PlunderStruck/scip-query

GitHub: PlunderStruck/scip-query

面向 AI 编程 Agent 的 TypeScript CLI 工具,利用 SCIP 索引和 Git 历史提供代码变更前后的结构化证据与验证把关。

Stars: 4 | Forks: 0

scip-query

面向 AI 编程 Agent 的证据与验证。

构建仓库映射。复用已有内容。完成重构。为 diff 设置把关。

npm version npm downloads Node version License

`scip-query` 是一个 TypeScript CLI 和 npm 包,它将 SCIP 索引、git 历史、具备语言感知能力的源码分析,以及代码仓库自身的检查机制,转化为 AI 编程 Agent 在代码变更前、变更中和变更后都可以调用的命令。 Agent 很擅长编辑眼前的代码,但在长任务中保持对整个仓库的全局模型时就不那么可靠了:它们会忽略已有的 helper,基于残缺的上下文制定计划,只迁移了部分调用点,忽视了仅存在历史关联的文件,并且当 diff 中仍然引入了重复代码、死代码或过时的文档时,就草草宣布完成。 `scip-query` 为它们提供了一个可重复的操作循环:构建目标及其影响范围的映射,基于仓库证据制定具体计划,在引入新概念之前检查是否可复用,检测未完成的迁移和隐藏的耦合,并对最终的 diff 进行把关。它不替代编译器、测试或代码审查;它只是让结构化的证据和仓库检查变得易于被 Agent 调用和报告。 ## Agent 循环 | 阶段 | Agent 需要确认的内容 | 命令 | |---|---|---| | 探索定向 | 已存在什么、定义在哪里、谁依赖它 | `system`, `trace`, `affected`, `plan-context` | | 计划规划 | 外部调用的接口、变更范围、影响范围以及历史伴生文件 | `surface`, `change-surface`, `co-change` | | 代码复用 | 对应的 helper、组件、hook 或 composable 是否已经存在 | `similar`, `recent-duplicates` | | 完成度检测 | 某次抽取或迁移是否覆盖了所有相关的位置 | `incomplete-migration`, `unused-params` | | 验证检查 | diff 影响了什么,受管覆盖的结构化检查是否发生回归 | `diff-impact`, `doc-drift`, `diff-gate`, `health --baseline` | | 代码清理 | 候选的移除项以及新暴露的死代码级联 | `cleanup-plan --verify` | React 和 Vue 仓库会获得额外的框架感知检查,用于发现重复的组件/模板结构、hook/composable 行为,以及过大组件或过大视图带来的压力。这些扩展了同样的复用和完成度工作流;核心的图、历史、规划、清理和 diff 把关命令并不局限于前端。 ## 安装 ``` npm install -g scip-query@latest scip-query check-deps scip-query reindex ``` 或者不进行全局安装:`npx scip-query@latest reindex`。 ## 从单次变更开始 ``` # 编辑前:建立 structure、consumers、history 和 blast radius scip-query plan-context # 创建 helper 或 abstraction 前:寻找现有的 concept scip-query similar # 执行 extraction 或 migration 后:查找仍然包含旧逻辑的站点 scip-query incomplete-migration # 宣布工作完成前:刷新 index 并 gate diff scip-query reindex && scip-query diff-gate ``` 对于全仓库范围的清理操作: ``` scip-query health scip-query recent-duplicates scip-query cleanup-plan --verify scip-query health --write-baseline ``` ## 证据与置信度 `scip-query` 保持每个答案的来源和强度可见: ``` flowchart LR A["SCIP graph facts"] --> F["evidence-ranked findings"] B["semantic augmentation"] --> F C["source-backed candidates"] --> F D["git-history signals"] --> F E["repository checks"] --> F ``` 1. 用于定义、引用、导入、调用和依赖关系的 **SCIP 图事实**。 2. 针对 TypeScript 的 **语义增强**(当 SCIP 索引需要更多细节时)。 3. 用于相似度、可维护性和清理检查的 **源码支撑候选集**。 4. 用于代码变动、共同变更、近期修改和文档漂移的 **Git 历史信号**。 5. 针对受支持的清理计划的 **仓库工具链验证**。 启发式的发现结果只是供检查的候选项,不能证明等价性或设计糟糕。运行 `scip-query capabilities` 以查看当前仓库和语言可用的证据和验证层。 ## 语言与框架覆盖范围 图导航通过受支持的 [SCIP](https://github.com/sourcegraph/scip) 索引器工作。高置信度的增强和验证因语言和项目工具链而异。TypeScript 目前拥有最丰富的语义增强。React 和 Vue 在核心工作流的基础上增加了内置的框架感知可维护性检查。 ## 清理 AI 生成的代码 这些检查专门针对 AI 辅助开发导致代码库腐化的特定方式。完整的目录以及每个检测器的预防配置详见 [docs/AI_FAILURE_MODES.md](docs/AI_FAILURE_MODES.md): **1. 寻找回声。** Agent 会重新实现它们不知道已经存在的 helper、hook、composable 和前端组件。`recent-duplicates` 使用 git 文件年龄使相似度具有 *方向性* —— 哪一方是既定的原始版本,哪一方是近期的回声(重复项): ``` 91% ECHO react-component src/components/ProjectCardVisual.tsx ProjectCardVisual (added 62 commits ago) duplicates established src/pages/HomePage.tsx RecentProjectRow() basis: jsx-structure shared: component:ProjectCard, prop:title, event:click 100% TWIN src/workflows/a.ts ensureAccessible() / src/workflows/b.ts ensureAccessible() (both new - one agent session duplicated itself; consolidate before they diverge) ``` **2. 完成未完成的抽取。** Agent 抽取了一个 helper,重新连接了一两个调用点,然后放弃了其余部分——被抽取的逻辑在它们错过的每个位置上仍然以内联方式存在。`incomplete-migration` 会找出在 diff 中新出现的 helper,确认它们已在某处被接入,并列出仍然包含该 helper 逻辑但从未调用它的既有位置(使用包含度评分,因为错过的位置包含该 helper 的逻辑 *加上* 其自身原有的逻辑): ``` src/utils/priceLabel.ts priceLabel() wired into: src/cards/price-summary-a.ts un-migrated: 100% buildReportB() (src/cards/price-summary-b.ts) un-migrated: 100% buildReportC() (src/cards/price-summary-c.ts) ``` **3. 揪出说谎的标准文档。** 如果你在仓库内存放了供 Agent 在实现前阅读的标准,那么过时的标准比没有标准更糟糕。`doc-drift` 会读取每个文档的文件引用 *以及* 它的共同变更历史,然后标记出代码已经演进但文档未同步更新的情况——包括指向已不存在文件的 **失效引用**: ``` staleness 94 product/domain-model.md BROKEN REFERENCE: cites src/api/servicePlans.ts — that file no longer exists 22 change(s) since doc update src/workflows/serviceTasks.ts (referenced by doc) ``` **4. 在项目检查中执行删除。** `cleanup-plan` 会将死代码分析运行到 *不动点* —— 删除第 0 批会使第 1 批变成死代码,该计划会展示这种级联反应。`--verify` 会在一次性的 git worktree 中应用每一批删除,并运行为你的项目检测到的受支持检查器(采用差分方式,因此预先存在的错误不会淹没信号): ``` ── Batch 0: deletable now (graph-fact, 67 LOC) ── ── Batch 1: dead once batch 0 lands (cascade, 21 LOC) ── Batch 0: COMPILER-VERIFIED ``` 当验证 *失败* 时,错误信息会明确指出静态证据遗漏的确切引用——这种失败机制已经捕捉到了真实的检测器错误,并阻止了会导致构建破坏的删除操作。 **5. 削减投机性的通用性。** `unused-params` 会查找没有任何实现体会使用的末尾参数(经典的“为以后留的选项”),并将范围限制在结构上类型安全的移除操作中。 **6. 保持前端复用的诚实性。** React 和 Vue 拥有专门的前端卫生检查:component-duplicate 命令比较 JSX/模板结构,hook/composable 命令比较状态/副作用/请求行为,而 large-component/view 命令会标记出集中了太多变更理由的文件。`health` 将这些作为卫生压力纳入指标,而 `incomplete-migration` 仍然是直接检查某个 hook/composable/helper 抽取是否已接入部分(而非全部)位置的手段。 **7. 揭示隐藏耦合。** `co-change` 查找在相同的 commit 中反复更改但 *没有* 依赖边的文件对 —— schema ↔ 生成的清单 ↔ 文档的三角关系,后端 schema ↔ 前端状态库,`.env.example` ↔ 其解析器。引用图无法看到这些;变更图可以。 **8. 为每个 diff 把关。** `diff-gate` 运行一组明确定义的检查,范围仅限于变更 *引入* 的内容 —— 既有代码的回声、未完成的迁移、缺失的共同变更伙伴、引用了被更改文件的文档、新出现的未使用参数、新增的死符号、基线回归 —— 并在发现每个问题时以非零状态码退出,附带修复文本说明: ``` [co-change-partner] schema.prisma changed, but scripts/scope-inventory.mjs did not — they change together 12x (86% of the time) -> Update scripts/scope-inventory.mjs alongside this change, or confirm the coupling no longer holds. ``` **9. 在 CI 中应用渐进收紧策略。** `health --write-baseline` 将发现的问题标识快照保存到一个可提交的文件中;`health --baseline` 遇到任何 *新* 发现的问题都会以状态码 1 退出。“不要变得更糟”是一个客观的关卡,任何分数算术都无法对其作弊。 已接受的问题发现可以被记录下来,而不会削弱其余的关卡: ``` scip-query suppress SQABC123DEF456 --check echo --reason "intentional compatibility shim" ``` 这会在 `.scipquery.json` 中追加一条附带理由的条目;`config-validate` 会拒绝没有标识和理由的抑制项,而 `diff-gate --json` 会报告处于活动状态和被抑制的发现结果。 在进行任何编辑之前,`plan-context ` 会打包结构化的图景 —— 定义、引用、调用图、影响范围 —— 外加一个 HISTORY 部分:代码变动、修复提交的密度,以及通常与目标一起更改的文件(“编辑这个通常意味着也要编辑这些”)。 ## 经得起推敲的健康度评分 `scip-query health` 拒绝成为一个虚荣的数字指标: ``` Codebase Health Score: 95/100 Risk: 95/100 (history-correlated signals: graph facts + change graph) Hygiene: 100/100 (tidiness candidates) Score Breakdown (100 minus the following): - 5 hidden-coupling: 5 co-changing pair(s) without a dependency edge Axes: Deletable: 1,027 LOC across 89 symbols Change amplification: 5 files/commit median, 23 p90 Evidence quality: 5 graph-fact, 150 heuristic, 0 user-suppressed Validation: flagged fix-density 0.12 vs baseline 0.20 (0.6x) ``` - **风险 vs. 卫生** 是两个独立的声明:风险组件与图事实和仓库历史信号挂钩;卫生组件代表整洁度。将它们混为一谈正是评分变得毫无意义的原因。 - **每一项扣分都有明细记录** —— 标量是可审计的,而不是凭感觉。 - **验证轴是一个可证伪性循环**:它测量 *在你的仓库中*,被标记的文件是否真的比其他文件吸引了更多的修复提交,并按每个检测器分别统计。在某些代码库中,某个检测器能追踪到反复出现的修复;在另一些代码库中,它主要是噪音 —— 该工具会报告具体是哪种情况,而不是妄加假设。 - **抑制项也是数据**:每个 `// scip-query: ignore-*` 注释都是一个精确的标签,会被统计和报告。 ## 准确度模型 证据层级保持明确,最强证据排在前面: 1. 来自 SCIP 数据库的 **编译器支撑的事实**(`trace`, `refs`, `deps`, `outline` 等)。 2. 通过 `ts-morph` 针对 TypeScript 的 **语义增强** —— 在 SCIP 单独使用不够完整时,提供经过验证的引用、调用方和被调用方。 3. 用于清理信号的 **源码支撑的启发式方法** (AST/文本)。始终带有标签:*“这些是候选项,而非确切的编译器事实。”* 4. 用于删除操作的 **编译器验证** —— 唯一配得上“安全”一词的层级。 因为你不去衡量的准确度只是一种感觉,`self-audit` 会对符号进行抽样,并根据 TypeScript 编译器对低成本路径进行评分: ``` references precision 1.0 recall 0.9 (the cheap path doesn't fabricate; it occasionally misses) ``` 启发式检测器内置了从真实代码库中学到的护栏:已发布的 `package.json` 对外接口豁免于“未使用”的建议,`contracts/` 和 `types/` 模块豁免于“定义者从不使用它”的检测,测试文件和组件的同级文件不计入隐藏耦合,而基于策略强制要求的 changelog 也不算作漂移。 ## Agent 技能 `scip-query install-skills` 会将现成的技能符号链接到 Claude Code、Codex 和共享的 Agent 根目录(`~/.agents/skills/`)—— 它们会随软件包自动更新。`scip-query` 路由技能在任何代码库工作时触发,并分派给合适的专家模块:探索(`scip-explore`)、瘦身去重(`scip-debloat`)、目录架构审查(`scip-directory-architecture`)、可维护性审查(`scip-maintainability`)、React 前端可维护性审查(`scip-react-maintainability`)、Vue 前端可维护性审查(`scip-vue-maintainability`)、变更后验证(`scip-verify`)、文档核对(`scip-doc-reconcile`)、AI 腐化清理(`scip-ai-cleanup`)、特定语言指导(`scip-language-playbook`)以及脚踏实地的规划(`concrete-plan`)。 然后,在每个项目中执行一次,`scip-query setup-agent` 会植入 `AGENTS.md` 指导块(外加一个 `CLAUDE.md` 导入垫片,因为 Claude Code 原生并不读取 AGENTS.md),而 `--git-hook` 会添加一个 pre-commit 的 diff 把关钩子,无论哪个 Agent —— 或是人类 —— 编写了变更代码,它都会被触发。 ## 快速开始 ``` scip-query check-deps # verify indexers are runnable scip-query install-skills # optional: agent skills scip-query reindex scip-query stats scip-query system src/auth scip-query plan-context login scip-query health scip-query cleanup-plan --verify scip-query health --write-baseline # start the ratchet ``` ## 前置条件 - Node.js >= 18 - `scip` CLI,来自 [Sourcegraph SCIP 发布版](https://github.com/sourcegraph/scip/releases) - 针对你的项目的特定语言的 SCIP 索引器 | 语言 | 索引器 | 安装 | |---|---|---| | TypeScript / JavaScript / Vue | scip-typescript | `npm install -g @sourcegraph/scip-typescript` | | Java / Scala / Kotlin | scip-java | [发布版](https://github.com/sourcegraph/scip-java/releases) | | Rust | rust-analyzer | 随 rust-analyzer 附带:`rust-analyzer scip` | | Python | scip-python-plus | `npm install -g scip-python-plus` | | Go | scip-go | `go install github.com/sourcegraph/scip-go@latest` | | Ruby | scip-ruby | [发布版](https://github.com/sourcegraph/scip-ruby/releases) | | C / C++ | scip-clang | [发布版](https://github.com/sourcegraph/scip-clang/releases) | | C# / VB | scip-dotnet | [版](https://github.com/sourcegraph/scip-dotnet/releases) | | Dart | scip-dart | [发布版](https://github.com/nicovince/scip-dart/releases) | | PHP | scip-php | [发布版](https://github.com/nicovince/scip-php/releases) | 对于 Python,可执行文件可能是 `scip-python`、`scip-python-plus` 或两者皆有。`scip-query` 接受这两种名称中的任何一个。 Vue 单文件组件通过 JavaScript/TypeScript 索引器进行处理。`scip-query` 还会提取 `