scip-query 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/README.md +179 -221
  2. package/dist/augment-vue-worker.js +1 -1
  3. package/dist/{chunk-OPWOX7NT.js → chunk-2EC4JTHC.js} +2 -2
  4. package/dist/{chunk-SVSLAUSJ.js → chunk-46ILZVMX.js} +2 -2
  5. package/dist/chunk-4A4JFNWG.js +2 -0
  6. package/dist/{chunk-QBXTQODK.js → chunk-4B7YLRXX.js} +2 -2
  7. package/dist/chunk-64UY7VTR.js +63 -0
  8. package/dist/chunk-66ORT3LS.js +2 -0
  9. package/dist/{chunk-VMS5YTBS.js → chunk-6G76D2YM.js} +2 -2
  10. package/dist/{chunk-PEU24CSY.js → chunk-6P5W4U6G.js} +2 -2
  11. package/dist/chunk-6ZFKI5EP.js +40 -0
  12. package/dist/{chunk-EVXQF7DM.js → chunk-7I6KNKE3.js} +2 -2
  13. package/dist/{chunk-EIGCLVKK.js → chunk-7TYJD45F.js} +2 -2
  14. package/dist/chunk-7UZWNW4E.js +2 -0
  15. package/dist/{chunk-GIRI7FHW.js → chunk-AGW2MVIO.js} +2 -2
  16. package/dist/chunk-APLCSDXL.js +4 -0
  17. package/dist/{chunk-JDFWJ7VK.js → chunk-BCFED24F.js} +2 -2
  18. package/dist/chunk-CVRXOP6M.js +3 -0
  19. package/dist/{chunk-2QNKEJ7R.js → chunk-D43L5PQF.js} +2 -2
  20. package/dist/chunk-DJTJ3DLZ.js +7 -0
  21. package/dist/chunk-EAU4RDFG.js +2 -0
  22. package/dist/{chunk-BI4F6GXI.js → chunk-EKP7XJ6L.js} +2 -2
  23. package/dist/{chunk-LLL7THVV.js → chunk-EM2PPDN7.js} +2 -2
  24. package/dist/{chunk-6QC7SCKV.js → chunk-FIPE5AQT.js} +2 -2
  25. package/dist/chunk-FTBT4RP2.js +7 -0
  26. package/dist/{chunk-TB2OYNRS.js → chunk-GD7XRHSV.js} +2 -2
  27. package/dist/{chunk-XDXZP3BE.js → chunk-GMEBYEMU.js} +2 -2
  28. package/dist/chunk-GTZAU7OL.js +2 -0
  29. package/dist/chunk-HVGNOUYP.js +2 -0
  30. package/dist/chunk-HVXIXDLV.js +2 -0
  31. package/dist/{chunk-5TB4N27G.js → chunk-I7OTKWNY.js} +2 -2
  32. package/dist/{chunk-RFCR2BRD.js → chunk-JAMU6FLN.js} +2 -2
  33. package/dist/chunk-JTCEWV7Q.js +2 -0
  34. package/dist/chunk-K4Z3FCUJ.js +6 -0
  35. package/dist/{chunk-WJQFABZN.js → chunk-K6YIGVL7.js} +2 -2
  36. package/dist/chunk-MKE7SEEX.js +2 -0
  37. package/dist/chunk-N5D5ZCBW.js +7 -0
  38. package/dist/{chunk-ROZNBWIF.js → chunk-NGLRXEWN.js} +2 -2
  39. package/dist/{chunk-IFGEPTH5.js → chunk-NK7TQQG4.js} +2 -2
  40. package/dist/chunk-NOVKLH2F.js +2 -0
  41. package/dist/chunk-OIMM7KMI.js +2 -0
  42. package/dist/chunk-OQSV6OS2.js +2 -0
  43. package/dist/chunk-PBGTMPJ7.js +2 -0
  44. package/dist/{chunk-YH6TTQEI.js → chunk-PCMVXWDC.js} +4 -4
  45. package/dist/{chunk-U75WH4XG.js → chunk-PE4EJOLN.js} +2 -2
  46. package/dist/chunk-PLFYFZX3.js +2 -0
  47. package/dist/{chunk-HTVLH3NL.js → chunk-QYQXPPDI.js} +2 -2
  48. package/dist/{chunk-P7UMQ7R7.js → chunk-RCRK4E7E.js} +2 -2
  49. package/dist/chunk-RIXOMSOR.js +20 -0
  50. package/dist/chunk-SB6I6O3P.js +2 -0
  51. package/dist/{chunk-X2JB54QF.js → chunk-SDGCKEB7.js} +2 -2
  52. package/dist/chunk-SLOIQKY7.js +2 -0
  53. package/dist/{chunk-4VYIZV3S.js → chunk-SOGLYIJ4.js} +4 -4
  54. package/dist/chunk-SSINY7HL.js +4 -0
  55. package/dist/{chunk-FU5WRWAN.js → chunk-TFO4OMJZ.js} +2 -2
  56. package/dist/chunk-TH4JVC34.js +71 -0
  57. package/dist/chunk-TQTVM27C.js +6 -0
  58. package/dist/{chunk-QP6FLI6D.js → chunk-TR5AU6A5.js} +2 -2
  59. package/dist/{chunk-4LKJMRT5.js → chunk-UQE3DSXY.js} +2 -2
  60. package/dist/{chunk-LXJTDFOV.js → chunk-UUDYI3FF.js} +2 -2
  61. package/dist/chunk-VDZL45XI.js +2 -0
  62. package/dist/{chunk-XANDY7N5.js → chunk-VN6B6HFB.js} +2 -2
  63. package/dist/{chunk-SDPP5KVQ.js → chunk-WC43FMAB.js} +2 -2
  64. package/dist/chunk-WEJYUS5O.js +2 -0
  65. package/dist/chunk-WQFOZIID.js +4 -0
  66. package/dist/chunk-XBFLIGWU.js +3 -0
  67. package/dist/{chunk-TGNL3ZKZ.js → chunk-XSZ5NC4O.js} +2 -2
  68. package/dist/{chunk-4T35WUCX.js → chunk-Z2AJQ7VA.js} +2 -2
  69. package/dist/{chunk-S5VMVNFM.js → chunk-ZIIQ55VK.js} +2 -2
  70. package/dist/chunk-ZJ737ZMD.js +2 -0
  71. package/dist/cli.js +171 -173
  72. package/dist/health-C6r2VgpA.d.ts +234 -0
  73. package/dist/index.d.ts +11 -18
  74. package/dist/index.js +1 -1
  75. package/dist/postinstall.js +4 -4
  76. package/dist/queries/affected.js +1 -1
  77. package/dist/queries/bottlenecks.js +1 -1
  78. package/dist/queries/by-kind.js +1 -1
  79. package/dist/queries/call-graph.js +1 -1
  80. package/dist/queries/change-surface.js +1 -1
  81. package/dist/queries/cleanup-plan.d.ts +66 -0
  82. package/dist/queries/cleanup-plan.js +2 -0
  83. package/dist/queries/co-change.d.ts +42 -0
  84. package/dist/queries/co-change.js +2 -0
  85. package/dist/queries/code.js +1 -1
  86. package/dist/queries/complexity-hotspots.js +1 -1
  87. package/dist/queries/complexity.js +1 -1
  88. package/dist/queries/convergence.js +1 -1
  89. package/dist/queries/coupling.js +1 -1
  90. package/dist/queries/cycles.js +1 -1
  91. package/dist/queries/dataflow.js +1 -1
  92. package/dist/queries/dead.js +1 -1
  93. package/dist/queries/deep-chains.js +1 -1
  94. package/dist/queries/deps.js +1 -1
  95. package/dist/queries/diff-gate.d.ts +52 -0
  96. package/dist/queries/diff-gate.js +2 -0
  97. package/dist/queries/diff-impact.js +1 -1
  98. package/dist/queries/doc-drift.d.ts +69 -0
  99. package/dist/queries/doc-drift.js +2 -0
  100. package/dist/queries/drift.js +1 -1
  101. package/dist/queries/extract-candidates.js +1 -1
  102. package/dist/queries/fan.js +1 -1
  103. package/dist/queries/health.d.ts +1 -1
  104. package/dist/queries/health.js +1 -1
  105. package/dist/queries/hierarchy.js +1 -1
  106. package/dist/queries/hotspots.js +1 -1
  107. package/dist/queries/imports.js +1 -1
  108. package/dist/queries/index.d.ts +38 -2
  109. package/dist/queries/index.js +1 -1
  110. package/dist/queries/isolated.js +1 -1
  111. package/dist/queries/members.js +1 -1
  112. package/dist/queries/methods.js +1 -1
  113. package/dist/queries/outline.d.ts +1 -0
  114. package/dist/queries/outline.js +1 -1
  115. package/dist/queries/passthrough-candidates.js +1 -1
  116. package/dist/queries/plan-context.d.ts +65 -0
  117. package/dist/queries/plan-context.js +2 -0
  118. package/dist/queries/recent-duplicates.d.ts +48 -0
  119. package/dist/queries/recent-duplicates.js +2 -0
  120. package/dist/queries/redundant-reexports.js +1 -1
  121. package/dist/queries/refs.js +1 -1
  122. package/dist/queries/self-audit.d.ts +58 -0
  123. package/dist/queries/self-audit.js +2 -0
  124. package/dist/queries/similar-chains.js +1 -1
  125. package/dist/queries/similar-files.d.ts +6 -0
  126. package/dist/queries/similar-files.js +1 -1
  127. package/dist/queries/similar-signatures.js +1 -1
  128. package/dist/queries/similar.js +1 -1
  129. package/dist/queries/slice.js +1 -1
  130. package/dist/queries/stale-abstractions.js +1 -1
  131. package/dist/queries/surface.js +1 -1
  132. package/dist/queries/symbols.js +1 -1
  133. package/dist/queries/system.js +1 -1
  134. package/dist/queries/trace.js +1 -1
  135. package/dist/queries/unused-params.d.ts +38 -0
  136. package/dist/queries/unused-params.js +2 -0
  137. package/dist/queries/wrapper-candidates.js +1 -1
  138. package/dist/reindex-worker.js +1 -1
  139. package/dist/reindex.js +1 -1
  140. package/dist/runtime.d.ts +3 -2
  141. package/dist/runtime.js +2 -2
  142. package/package.json +33 -1
  143. package/skills/concrete-plan/SKILL.md +37 -7
  144. package/skills/scip-ai-cleanup/SKILL.md +145 -0
  145. package/skills/scip-debloat/SKILL.md +37 -7
  146. package/skills/scip-explore/SKILL.md +22 -9
  147. package/skills/scip-language-playbook/SKILL.md +4 -4
  148. package/skills/scip-maintainability/SKILL.md +264 -0
  149. package/skills/scip-verify/SKILL.md +2 -2
  150. package/dist/chunk-3X43EYFU.js +0 -3
  151. package/dist/chunk-4GPWGSOE.js +0 -40
  152. package/dist/chunk-5RGK4YA5.js +0 -63
  153. package/dist/chunk-5TT47UMX.js +0 -44
  154. package/dist/chunk-6QH2L26C.js +0 -71
  155. package/dist/chunk-6SR4UNWI.js +0 -2
  156. package/dist/chunk-6XEWA6FX.js +0 -2
  157. package/dist/chunk-7WHNTKSD.js +0 -2
  158. package/dist/chunk-BOVNTAKQ.js +0 -3
  159. package/dist/chunk-D62LLANH.js +0 -2
  160. package/dist/chunk-EDXML2HI.js +0 -4
  161. package/dist/chunk-EZQOVY3C.js +0 -2
  162. package/dist/chunk-IODTPF5H.js +0 -20
  163. package/dist/chunk-KJ6CW6EK.js +0 -2
  164. package/dist/chunk-NBUINPSH.js +0 -2
  165. package/dist/chunk-NHDPYW7O.js +0 -2
  166. package/dist/chunk-NKJKI6SE.js +0 -2
  167. package/dist/chunk-OPZQIJZU.js +0 -7
  168. package/dist/chunk-P3PVY6TX.js +0 -2
  169. package/dist/chunk-QE6MGGUY.js +0 -2
  170. package/dist/chunk-QVPYMZUJ.js +0 -6
  171. package/dist/chunk-RCJEFQOK.js +0 -4
  172. package/dist/chunk-UHMJYNTK.js +0 -2
  173. package/dist/health-x7B4Xu_6.d.ts +0 -119
package/README.md CHANGED
@@ -1,107 +1,204 @@
1
- # scip-query
1
+ <p align="center">
2
+ <img src="docs/assets/scip-query-logo.png" alt="scip-query logo" width="120">
3
+ </p>
2
4
 
3
- Language-agnostic code intelligence CLI powered by [SCIP](https://github.com/sourcegraph/scip) indexes. Index a codebase once, then ask direct questions about symbols, references, dependencies, dead code, similarity, coupling, impact, and health without keeping an IDE or language server running.
5
+ <h1 align="center">scip-query</h1>
4
6
 
5
- Works with every language that has a SCIP indexer: TypeScript, JavaScript, Vue, Java, Scala, Kotlin, Rust, Python, Ruby, Go, C/C++, C#, Visual Basic, Dart, PHP.
7
+ <p align="center">
8
+ <strong>Structural code intelligence for AI agents and engineers.</strong>
9
+ </p>
6
10
 
7
- ## Purpose
11
+ <p align="center">
12
+ Ask compiler-backed questions about how a codebase is wired together, find what's rotting, and delete it with a compiler proof in hand.
13
+ </p>
8
14
 
9
- `scip-query` exists to make codebase understanding operational. A large codebase is a collection of source files, symbols, and dependency paths that people need to change without accidentally breaking users. This project turns compiler-produced code intelligence into terminal commands that answer the questions engineers and agents ask before they edit:
15
+ <p align="center">
16
+ <a href="https://www.npmjs.com/package/scip-query"><img alt="npm version" src="https://img.shields.io/npm/v/scip-query.svg"></a>
17
+ <a href="https://www.npmjs.com/package/scip-query"><img alt="npm downloads" src="https://img.shields.io/npm/dm/scip-query.svg"></a>
18
+ <a href="package.json"><img alt="Node version" src="https://img.shields.io/node/v/scip-query.svg"></a>
19
+ <a href="https://www.apache.org/licenses/LICENSE-2.0"><img alt="License" src="https://img.shields.io/npm/l/scip-query.svg"></a>
20
+ </p>
10
21
 
11
- - What is defined here?
12
- - Who uses this symbol?
13
- - What depends on this file?
14
- - What changes if I modify this API?
15
- - Which cleanup findings are backed by real reference evidence?
16
- - Where is the architecture drifting, duplicating work, or hiding complexity?
22
+ <p align="center">
23
+ <a href="https://www.npmjs.com/package/scip-query"><img alt="Install from npm" src="https://img.shields.io/badge/install-npm-cb3837?style=for-the-badge&logo=npm&logoColor=white"></a>
24
+ <a href="docs/AGENT_GUIDE.md"><img alt="Agent guide" src="https://img.shields.io/badge/agent-guide-2563eb?style=for-the-badge"></a>
25
+ <a href="docs/COMMAND_REFERENCE.md"><img alt="Command reference" src="https://img.shields.io/badge/command-reference-111827?style=for-the-badge"></a>
26
+ </p>
17
27
 
18
- The vision is a reliable code-intelligence layer for both humans and coding agents: fast enough to use during ordinary development, accurate enough to trust for planning, and explicit about confidence when an analysis moves beyond compiler-backed facts.
28
+ `scip-query` answers precise questions about how a codebase is wired together — where a symbol is defined, who references it, what calls it, what breaks if it changes — and turns those answers into something rarer: **cleanup you can trust**. Findings are ranked by evidence quality, validated against your repo's own git history, and (for deletions) proven safe by your own compiler before you touch anything.
19
29
 
20
- ## Problems It Solves
30
+ Works with every language that has a [SCIP](https://github.com/sourcegraph/scip) indexer: TypeScript, JavaScript, Vue, Java, Scala, Kotlin, Rust, Python, Ruby, Go, C/C++, C#, Visual Basic, Dart, PHP.
21
31
 
22
- - **Navigation without IDE state.** Query definitions, references, outlines, members, call graphs, and source snippets from a terminal or automation loop.
23
- - **Change planning.** Use `affected`, `change-surface`, and `diff-impact` to identify downstream consumers before and after a change.
24
- - **Architecture visibility.** Use `deps`, `rdeps`, `system`, `surface`, `coupling`, `cycles`, and `deep-chains` to see how modules actually relate.
25
- - **Codebase cleanup.** Use `dead`, `stale-abstractions`, `wrapper-candidates`, `passthrough-candidates`, `similar`, `similar-signatures`, `extract-candidates`, and `drift` to find removal or consolidation opportunities.
26
- - **Health reporting.** Use `health` to aggregate cleanup signals into one prioritized report instead of running dozens of commands by hand.
27
- - **Agent workflows.** Install the bundled Codex/Claude skills so agents can explore, plan, de-bloat, and verify changes with a consistent command vocabulary.
32
+ ## Install
28
33
 
29
- ## Accuracy Model
34
+ ```bash
35
+ npm install -g scip-query@latest
36
+ scip-query reindex # index the current project
37
+ scip-query health # see where you stand
38
+ ```
39
+
40
+ Or without a global install: `npx scip-query@latest reindex`.
30
41
 
31
- A SCIP index is a database-shaped record of code facts produced by language-aware indexers: the source files they read, the symbols they define, and the references they resolve. Because these facts come from compilers, type checkers, or language servers, direct definition and reference queries are much stronger evidence than text search.
42
+ ## The Problem
32
43
 
33
- `scip-query` separates three kinds of evidence:
44
+ Two problems, actually.
34
45
 
35
- - **Compiler-backed facts** come from the SCIP database. Commands like `symbols`, `refs`, `trace`, `deps`, `rdeps`, `surface`, and most symbol-level counts start here.
36
- - **Semantic augmentation** adds language-specific checks when available. TypeScript projects use `ts-morph` to verify references, import usage, callers, callees, and signatures when SCIP alone is incomplete.
37
- - **Source-backed heuristics** use parsed source text or ASTs to keep higher-level cleanup commands useful when an indexer omits call-site details. These findings are designed as investigation leads, not blind deletion instructions.
46
+ **Agents lose the thread.** A codebase is files connected by definitions, references, imports, calls, and dependency paths. Reading files gives local text, not verified structure. Search finds matching words, not real references. Before editing one unit you need to know what it is, who uses it, and what depends on it — with evidence, not vibes.
38
47
 
39
- The goal is not to replace compiler facts with regexes. The goal is to use the strongest available evidence first, fall back only when needed, and keep cleanup commands conservative enough that speed does not trade away accuracy.
48
+ **AI-generated code rots in specific ways.** Agents re-implement helpers they didn't know existed. They leave parallel half-wired implementations behind. They add parameters and options "for later" that never come. And the standards docs you write *for* them drift away from the code so the next agent implements against a dead spec. Generic linters don't see any of this, because none of it is visible in a single file.
40
49
 
41
- ## Workflows
50
+ `scip-query` attacks both: structural questions with evidence-backed answers, and rot detectors tuned to how code actually decays — each one validated, and each one honest about its own confidence.
42
51
 
43
- For goal-oriented usage guides (not just command reference), see **[Agent Guide](docs/AGENT_GUIDE.md)**:
52
+ ## Three Sources of Evidence
44
53
 
45
- - **[Understand a system](docs/AGENT_GUIDE.md#workflow-1-understand-a-system-before-making-changes)** map a module, trace symbols, check blast radius
46
- - **[Write an implementation plan](docs/AGENT_GUIDE.md#workflow-2-write-a-concrete-implementation-plan)** — identify contracts, map dependencies, find reusable code
47
- - **[De-bloat a codebase](docs/AGENT_GUIDE.md#workflow-3-clean-up-and-de-bloat-a-codebase)** — prioritized cleanup from dead code to pattern drift
48
- - **[Assess code quality](docs/AGENT_GUIDE.md#workflow-4-assess-code-quality-and-risk)** — health score, complexity hotspots, coupling risks
49
- - **[Verify change impact](docs/AGENT_GUIDE.md#workflow-5-understand-impact-after-making-changes)** — diff impact, transitive blast radius, consumer blast radius
54
+ Most code tools have one lens. `scip-query` has three, and tells you which one each answer came from:
50
55
 
51
- Historical implementation plans and completed cleanup notes live in [`docs/plans/`](docs/plans/).
56
+ ```mermaid
57
+ flowchart LR
58
+ A["Reference graph<br/>(SCIP: compilers & language servers)"] --> D["scip-query"]
59
+ B["Change graph<br/>(git history: co-change, churn, fix density)"] --> D
60
+ C["Verification oracles<br/>(tsc / cargo check / ts-morph)"] --> D
61
+ D --> E["Evidence-ranked answers<br/>graph-fact · change-graph · heuristic · compiler-verified"]
62
+ ```
52
63
 
53
- ## Install From npm
64
+ 1. **The reference graph** — who defines, references, calls, imports what. Built from SCIP indexes produced by real compilers and language servers, not text search.
65
+ 2. **The change graph** — what git history knows that no compiler can: files that always change together without any dependency edge (one concept scattered across artifacts), churn-weighted complexity (gnarly code nobody touches costs nothing), and whether flagged files actually attract fix commits.
66
+ 3. **Verification oracles** — your own toolchain as ground truth. Deletion plans are applied in a throwaway worktree and run through `tsc`/`cargo check` before being stamped `COMPILER-VERIFIED`. The tool even audits *itself*: `self-audit` scores its cheap evidence paths against the TypeScript compiler and reports precision/recall as a tracked number.
54
67
 
55
- Install the published CLI globally from npm:
68
+ ## At a Glance
69
+
70
+ | Ask this | Run this |
71
+ |---|---|
72
+ | What is in this module? | `scip-query system src/auth` |
73
+ | Who uses this symbol? | `scip-query trace login` |
74
+ | What might break if I change it? | `scip-query affected login` |
75
+ | Everything I need before editing this | `scip-query plan-context login` |
76
+ | What did my git diff affect? | `scip-query diff-impact` |
77
+ | How healthy is this codebase, really? | `scip-query health` |
78
+ | What can I delete — *prove it* | `scip-query cleanup-plan --verify` |
79
+ | What new code duplicates old code? | `scip-query recent-duplicates` |
80
+ | Which docs lie about the code now? | `scip-query doc-drift` |
81
+ | What changes together but isn't linked? | `scip-query co-change` |
82
+ | Gate an agent's diff before merging | `scip-query diff-gate` |
83
+ | Did the findings get worse? (CI gate) | `scip-query health --baseline` |
84
+
85
+ ## Cleaning Up AI-Generated Code
86
+
87
+ This is the workflow the tool is built around. Each detector targets a specific way AI-assisted development rots a codebase:
88
+
89
+ **1. Find the echoes.** Agents re-implement helpers they didn't know existed. `recent-duplicates` makes similarity *directional* using git file ages — which side is the established original, which is the recent echo:
56
90
 
57
- ```bash
58
- npm install -g scip-query@latest
59
- scip-query --version
91
+ ```
92
+ 91% ECHO src/components/ProjectCardVisual.tsx ProjectCardVisual() (added 62 commits ago)
93
+ duplicates established src/pages/HomePage.tsx RecentProjectRow()
94
+ 100% TWIN src/workflows/a.ts ensureAccessible() / src/workflows/b.ts ensureAccessible()
95
+ (both new — one agent session duplicated itself; consolidate before they diverge)
60
96
  ```
61
97
 
62
- You can also run it without a global install:
98
+ **2. Catch your standards docs lying.** If you keep in-repo standards for agents to read before implementing, a stale standard is worse than none. `doc-drift` reads every doc's file citations *and* its co-change history, then flags docs whose code moved on without them — including **broken references** to files that no longer exist:
99
+
100
+ ```
101
+ staleness 94 product/domain-model.md
102
+ BROKEN REFERENCE: cites src/api/servicePlans.ts — that file no longer exists
103
+ 22 change(s) since doc update src/workflows/serviceTasks.ts (referenced by doc)
104
+ ```
105
+
106
+ **3. Delete with proof.** `cleanup-plan` runs dead-code analysis to a *fixpoint* — deleting batch 0 makes batch 1 dead, and the plan shows the cascade. `--verify` applies each batch in a throwaway git worktree and runs your own compiler (differentially, so pre-existing errors don't drown the signal):
107
+
108
+ ```
109
+ ── Batch 0: deletable now (graph-fact, 67 LOC) ──
110
+ ── Batch 1: dead once batch 0 lands (cascade, 21 LOC) ──
111
+ Batch 0: COMPILER-VERIFIED
112
+ ```
113
+
114
+ When verification *fails*, the errors name the exact references the static evidence missed — that failure has caught real detector mistakes and stopped build-breaking deletions.
115
+
116
+ **4. Trim speculative generality.** `unused-params` finds trailing parameters no body ever uses (the classic "options for later"), scoped to removals that are type-safe by construction.
117
+
118
+ **5. Surface hidden coupling.** `co-change` finds file pairs that repeatedly change in the same commits with *no* dependency edge — schema ↔ generated inventory ↔ doc triangles, backend schemas ↔ frontend stores, `.env.example` ↔ its parser. The reference graph cannot see these; the change graph can.
119
+
120
+ **6. Gate every diff.** `diff-gate` runs the whole suite scoped to what a change *introduces* — echoes of established code, missing co-change partners, docs that cite the changed files, fresh unused params, new dead symbols, baseline regressions — in seconds, exit-code friendly, with a remediation per finding an agent can act on without human triage:
121
+
122
+ ```
123
+ [co-change-partner] schema.prisma changed, but scripts/scope-inventory.mjs did not — they change together 12x (86% of the time)
124
+ -> Update scripts/scope-inventory.mjs alongside this change, or confirm the coupling no longer holds.
125
+ ```
126
+
127
+ **7. Ratchet it in CI.** `health --write-baseline` snapshots finding identities into a committable file; `health --baseline` exits 1 on any *new* finding. "Don't get worse" is an objective gate that no score arithmetic can game.
128
+
129
+ Before any edit, `plan-context <target>` bundles the structural picture — definitions, references, call graph, blast radius — plus a HISTORY section: churn, fix-commit density, and the files that usually change together with the target ("editing this usually means editing these").
130
+
131
+ ## A Health Score You Can Argue With
132
+
133
+ `scip-query health` refuses to be a vanity number:
134
+
135
+ ```
136
+ Codebase Health Score: 95/100
137
+ Risk: 95/100 (validated predictors: graph facts + change graph)
138
+ Hygiene: 100/100 (tidiness candidates)
139
+
140
+ Score Breakdown (100 minus the following):
141
+ - 5 hidden-coupling: 5 co-changing pair(s) without a dependency edge
142
+
143
+ Axes:
144
+ Deletable: 1,027 LOC across 89 symbols
145
+ Change amplification: 5 files/commit median, 23 p90
146
+ Evidence quality: 5 graph-fact, 150 heuristic, 0 user-suppressed
147
+ Validation: flagged fix-density 0.12 vs baseline 0.20 (0.6x)
148
+ ```
149
+
150
+ - **Risk vs. Hygiene** are separate claims: risk components are empirically fix-predictive; hygiene components are tidiness. Blending them is how scores become meaningless.
151
+ - **Every deduction is itemized** — the scalar is auditable, not vibes.
152
+ - **The validation axis is a falsifiability loop**: it measures whether flagged files actually attract more fix commits than the rest *in your repo*, per detector. On some codebases passthrough findings predict fixes at 6× baseline; on others they're noise — the tool reports which, instead of assuming.
153
+ - **Suppressions are data**: every `// scip-query: ignore-*` comment is a precision label, counted and reported.
154
+
155
+ ## Accuracy Model
156
+
157
+ Evidence tiers are kept explicit, strongest first:
158
+
159
+ 1. **Compiler-backed facts** from the SCIP database (`trace`, `refs`, `deps`, `outline`, ...).
160
+ 2. **Semantic augmentation** via `ts-morph` for TypeScript — verified references, callers, callees when SCIP alone is incomplete.
161
+ 3. **Source-backed heuristics** (AST/text) for cleanup signals. Always labeled: *"these are candidates, not exact compiler facts."*
162
+ 4. **Compiler verification** for deletions — the only tier that earns the word "safe."
163
+
164
+ And because accuracy you don't measure is a feeling, `self-audit` samples symbols and scores the cheap paths against the TypeScript compiler:
63
165
 
64
- ```bash
65
- npx scip-query@latest --version
66
- npx scip-query@latest reindex
67
166
  ```
167
+ references precision 1.0 recall 0.9 (the cheap path doesn't fabricate; it occasionally misses)
168
+ ```
169
+
170
+ Heuristic detectors carry guardrails learned from real codebases: published `package.json` surfaces are exempt from "unused" advice, `contracts/` and `types/` modules are exempt from "definer never uses it," test files and component-sibling files don't count as hidden coupling, and changelogs-by-policy aren't drift.
171
+
172
+ ## Agent Skills
68
173
 
69
- The npm package is published at [`scip-query`](https://www.npmjs.com/package/scip-query). `@latest` should resolve to the newest published version.
174
+ `scip-query install-skills` symlinks ready-made skills into Claude Code, Codex, and shared agent roots — workflows for exploring (`scip-explore`), debloating (`scip-debloat`), maintainability review (`scip-maintainability`), claim verification (`scip-verify`), per-language guidance (`scip-language-playbook`), and grounded planning (`concrete-plan`).
70
175
 
71
176
  ## Quick Start
72
177
 
73
178
  ```bash
74
- # Install
75
- npm install -g scip-query@latest
76
- scip-query --version
77
- scip-query check-deps # verify optional indexers and parser support
78
- scip-query install-skills # install built-in Codex/Claude skills
79
-
80
- # Index your project (auto-detects language)
179
+ scip-query check-deps # verify indexers are runnable
180
+ scip-query install-skills # optional: agent skills
81
181
  scip-query reindex
82
182
 
83
- # Start querying
84
183
  scip-query stats
85
- scip-query health # full codebase health report
86
- scip-query symbols src/auth.service.ts
87
- scip-query refs login
88
- scip-query affected login # transitive blast radius
89
- scip-query dead --min-loc 10
90
- scip-query similar --min-similarity 0.5
91
- scip-query diff-impact # what did my changes affect?
184
+ scip-query system src/auth
185
+ scip-query plan-context login
186
+ scip-query health
187
+ scip-query cleanup-plan --verify
188
+ scip-query health --write-baseline # start the ratchet
92
189
  ```
93
190
 
94
191
  ## Prerequisites
95
192
 
96
- - **Node.js** >= 18
97
- - **scip** CLI - [Install from releases](https://github.com/sourcegraph/scip/releases) (converts index data to SQLite)
98
- - A language-specific SCIP indexer for your project:
193
+ - Node.js >= 18
194
+ - `scip` CLI, from [Sourcegraph SCIP releases](https://github.com/sourcegraph/scip/releases)
195
+ - A language-specific SCIP indexer for your project
99
196
 
100
197
  | Language | Indexer | Install |
101
198
  |---|---|---|
102
199
  | TypeScript / JavaScript / Vue | scip-typescript | `npm install -g @sourcegraph/scip-typescript` |
103
200
  | Java / Scala / Kotlin | scip-java | [releases](https://github.com/sourcegraph/scip-java/releases) |
104
- | Rust | rust-analyzer | Ships with rust-analyzer (`rust-analyzer scip`) |
201
+ | Rust | rust-analyzer | Ships with rust-analyzer: `rust-analyzer scip` |
105
202
  | Python | scip-python-plus | `npm install -g scip-python-plus` |
106
203
  | Go | scip-go | `go install github.com/sourcegraph/scip-go@latest` |
107
204
  | Ruby | scip-ruby | [releases](https://github.com/sourcegraph/scip-ruby/releases) |
@@ -110,23 +207,27 @@ scip-query diff-impact # what did my changes affect?
110
207
  | Dart | scip-dart | [releases](https://github.com/nicovince/scip-dart/releases) |
111
208
  | PHP | scip-php | [releases](https://github.com/nicovince/scip-php/releases) |
112
209
 
113
- For Python, the npm package is `scip-python-plus`. Depending on which version you installed, the executable on your `PATH` may be `scip-python`, `scip-python-plus`, or both. `scip-query` accepts either name.
210
+ For Python, the executable may be `scip-python`, `scip-python-plus`, or both. `scip-query` accepts either name.
114
211
 
115
- Vue single-file components (`.vue`) are handled by the JavaScript/TypeScript indexer. `scip-query` extracts the `<script>` block (or `<script setup>`, picking the language from the `lang=` attribute) and parses it as TS/JS so symbol, reference, and import queries cover Vue components alongside regular `.ts`/`.js` files.
212
+ Vue single-file components are handled through the JavaScript/TypeScript indexer. `scip-query` also extracts the `<script>` or `<script setup>` block so symbol, reference, and import queries cover Vue components alongside regular `.ts` and `.js` files.
116
213
 
117
214
  ## How It Works
118
215
 
119
- 1. A SCIP indexer analyzes your source code using the actual compiler/type checker and produces a `index.scip` protobuf file containing symbols, definitions, and references.
120
- 2. The `scip` CLI converts the protobuf to a SQLite database (`index.db`).
121
- 3. `scip-query` runs SQL queries and language-aware source augmentation against that database to answer questions about your codebase.
216
+ 1. A SCIP indexer analyzes source code with the actual compiler, type checker, or language server and produces `index.scip`.
217
+ 2. The `scip` CLI converts that protobuf file to a SQLite database: `index.db`.
218
+ 3. `scip-query` runs SQL queries, language-aware source augmentation, and git-history analysis against it.
122
219
 
123
- Because the index comes from real language tooling, direct symbol, definition, and reference queries are precise, not grep-based approximations. When a language index is missing enough call-site detail for higher-level analyses, `scip-query` can fall back to AST parsing, semantic providers, and identifier recovery so those commands stay useful while still reporting conservative results.
220
+ By default, indexes live in `~/.cache/scip-query/projects/<hash>/`, keeping project directories clean. Override paths with `.scipquery.json` or `SCIP_QUERY_*` environment variables.
124
221
 
125
222
  ## Configuration
126
223
 
127
- ### Per-project config
224
+ Run this in a project root:
128
225
 
129
- Run `scip-query init` to generate a `.scipquery.json` in your project root:
226
+ ```bash
227
+ scip-query init
228
+ ```
229
+
230
+ It creates `.scipquery.json`:
130
231
 
131
232
  ```json
132
233
  {
@@ -144,7 +245,7 @@ Run `scip-query init` to generate a `.scipquery.json` in your project root:
144
245
  }
145
246
  ```
146
247
 
147
- ### Environment variables
248
+ Useful environment variables:
148
249
 
149
250
  | Variable | Purpose |
150
251
  |---|---|
@@ -153,157 +254,14 @@ Run `scip-query init` to generate a `.scipquery.json` in your project root:
153
254
  | `SCIP_QUERY_INDEX_SCIP` | Override the SCIP protobuf path |
154
255
  | `SCIP_QUERY_CACHE_DIR` | Override the cache directory |
155
256
 
156
- ### Index storage
157
-
158
- By default, indexes are stored in `~/.cache/scip-query/projects/<hash>/` (following XDG conventions). This keeps your project directory clean. Override with the `dbPath` field in `.scipquery.json` or the `SCIP_QUERY_CACHE_DIR` environment variable.
159
-
160
- ### Gitignore integration
161
-
162
- All query results are filtered through your project's `.gitignore`. Build artifacts (`dist/`, `target/`, `__pycache__/`), dependency directories (`node_modules/`, `vendor/`), and virtual environments (`.venv/`) are automatically excluded. If no `.gitignore` exists, sensible defaults are applied.
163
-
164
- ---
165
-
166
- ## Command Reference
167
-
168
- <!-- BEGIN GENERATED COMMAND REFERENCE -->
257
+ Query results are filtered through the project's `.gitignore`. If none exists, common generated directories such as `dist/`, `target/`, `node_modules/`, and `.venv/` are excluded by default.
169
258
 
170
- This syntax summary is generated from the CLI command descriptors. Keep workflow guidance hand-authored, but keep command syntax, descriptions, and option flags descriptor-owned.
259
+ ## Documentation
171
260
 
172
- ### Indexing
173
-
174
- | Command | Description | Options |
175
- |---|---|---|
176
- | `reindex` | Index the codebase and convert to SQLite | `-l, --language <lang>`<br>`--pnpm-workspaces`<br>`--force`<br>`--allow-partial`<br>`--indexer-concurrency <n>` |
177
- | `augment-sources` | Add source files skipped by upstream SCIP indexers to the SQLite documents table | - |
178
- | `augment-vue` | Add compiler-resolved Vue SFC references to the SQLite index using Volar | `--project <tsconfig>` |
179
-
180
- ### Core
181
-
182
- | Command | Description | Options |
183
- |---|---|---|
184
- | `stats` | Show index statistics | - |
185
-
186
- ### Navigation
187
-
188
- | Command | Description | Options |
189
- |---|---|---|
190
- | `files <pattern>` | Find files matching a pattern | - |
191
- | `symbols <file>` | List symbols defined in a file (with line ranges + signatures) | - |
192
- | `methods <className>` | List methods of a class (with line ranges) | - |
193
- | `refs <symbol>` | Find all files referencing a symbol | `--full` |
194
- | `trace <symbol>` | Trace a symbol: definition + all references | `--full` |
195
- | `deps <file>` | Files this file depends on (internal) | - |
196
- | `rdeps <file>` | Files that depend on this file/module | - |
197
- | `system <module>` | Full module map: files, symbols, deps in/out | - |
198
- | `surface <module>` | What symbols consumers actually use from this module | - |
199
- | `imports <file>` | What symbols does this file import? | `--full` |
200
- | `imported-by <symbol>` | Which files import this symbol? | - |
201
- | `outline <file>` | Tree view of symbols in a file (using nesting hierarchy) | - |
202
- | `members <symbol>` | All children of a symbol (methods, fields, nested types) | - |
203
- | `by-kind <kind>` | Find symbols by SCIP kind (class, interface, enum, function, etc.) | `-s, --scope <path>`<br>`-n, --limit <n>` |
204
- | `kind-counts` | Histogram of symbol kinds in the codebase | `-s, --scope <path>` |
205
- | `hierarchy <symbol>` | Show a symbol's ancestry chain (method → class → module) | - |
206
- | `code <symbol>` | Read the source code for a symbol (bounded to its definition range) | `-C, --context <n>` |
207
- | `dataflow <symbol>` | Reference-level dataflow: definition sites, usage sites, producers, consumers | `--full` |
208
- | `slice <symbol>` | Reference-level program slice: what affects this (backward) or what this affects (forward) | `--forward`<br>`--depth <n>`<br>`--full` |
209
-
210
- ### Cleanup
211
-
212
- | Command | Description | Options |
213
- |---|---|---|
214
- | `dead [scope]` | Find dead code and file-internal symbols (no cross-file consumers) | `--min-loc <n>`<br>`--include-tests`<br>`--skip-barrels`<br>`--include-members`<br>`--only-dead`<br>`--only-internal`<br>`--full` |
215
- | `unused-imports <file>` | Find imports not referenced in the same file | `--full` |
216
- | `isolated` | Find completely orphaned symbols (no references at all) | `-s, --scope <path>`<br>`--min-loc <n>`<br>`--full` |
217
- | `similar [symbol]` | Find heuristic function similarity candidates from callee fingerprints | `--min-similarity <n>`<br>`-n, --limit <n>`<br>`-s, --scope <path>`<br>`--min-callees <n>`<br>`--cross-file-only`<br>`--full` |
218
- | `similar-files [file]` | Find heuristic similar-file candidates from dependency profiles | `--min-similarity <n>`<br>`-n, --limit <n>`<br>`-s, --scope <path>`<br>`--min-deps <n>` |
219
- | `similar-chains` | Find heuristic similar-chain candidates from dependency flows | `--min-similarity <n>`<br>`-n, --limit <n>`<br>`-s, --scope <path>`<br>`--min-length <n>`<br>`--max-length <n>` |
220
- | `extract-candidates` | Find heuristic extraction candidates from isolated callee clusters | `-s, --scope <path>`<br>`--min-loc <n>`<br>`--min-callees <n>`<br>`-n, --limit <n>`<br>`--full` |
221
- | `drift [module]` | Detect heuristic drift candidates: unused imports, layer violations, and pattern deviations | `--min-deviation <n>`<br>`--full` |
222
- | `wrapper-candidates` | Find heuristic wrapper candidates only called by one consumer | `-s, --scope <path>`<br>`--max-loc <n>`<br>`-n, --limit <n>`<br>`--full` |
223
- | `passthrough-candidates` | Find heuristic passthrough candidates that forward to one callee | `-s, --scope <path>`<br>`--max-loc <n>`<br>`-n, --limit <n>`<br>`--full` |
224
- | `stale-abstractions` | Find heuristic stale abstraction candidates with 0-1 consumers | `-s, --scope <path>`<br>`--min-loc <n>`<br>`-n, --limit <n>`<br>`--include-low-confidence`<br>`--full` |
225
- | `complexity-hotspots` | Find heuristic complexity hotspot candidates from LOC x fan-in x fan-out | `-s, --scope <path>`<br>`--min-loc <n>`<br>`-n, --limit <n>`<br>`--full` |
226
- | `convergence <symbol1> <symbol2>` | Show what a consolidated version of two similar functions would look like | `--full` |
227
- | `redundant-reexports` | Find barrel re-exports that nobody imports through | `-s, --scope <path>`<br>`-n, --limit <n>` |
228
- | `similar-signatures` | Find functions with near-identical type signatures (same shape) | `-s, --scope <path>`<br>`--min-loc <n>`<br>`-n, --limit <n>`<br>`--full` |
229
-
230
- ### Graph
231
-
232
- | Command | Description | Options |
233
- |---|---|---|
234
- | `hotspots` | Most-referenced symbols in the codebase (choke points) | `-n, --limit <n>`<br>`-s, --scope <path>` |
235
- | `fan-in [symbol]` | How many files reference a symbol (or top fan-in across codebase) | `-n, --limit <n>`<br>`-s, --scope <path>` |
236
- | `fan-out [file]` | How many external symbols a file uses (or top fan-out across codebase) | `-n, --limit <n>`<br>`-s, --scope <path>` |
237
- | `coupling [file1] [file2]` | Coupling between two files, or top coupled pairs in codebase | `-n, --limit <n>`<br>`-s, --scope <path>` |
238
- | `cycles` | Detect circular dependency chains between files | `-s, --scope <path>`<br>`--max-depth <n>` |
239
- | `bottlenecks` | Find coupling hubs: high fan-in AND high fan-out | `-n, --limit <n>`<br>`-s, --scope <path>`<br>`--min-fan-in <n>`<br>`--min-fan-out <n>`<br>`--full` |
240
- | `deep-chains` | Find the longest transitive dependency chains | `-n, --limit <n>`<br>`-s, --scope <path>`<br>`--min-depth <n>` |
241
- | `call-graph <symbol>` | Show incoming callers and outgoing callees for a symbol | `--full` |
242
-
243
- ### Impact
244
-
245
- | Command | Description | Options |
246
- |---|---|---|
247
- | `affected <symbol>` | Transitive closure of symbols that could break if this symbol changes | `--max-depth <n>`<br>`-s, --scope <path>` |
248
- | `change-surface <file>` | Pre-change briefing: exports, consumers, and blast-radius risk | `--full` |
249
- | `diff-impact` | Compute changed symbols and downstream consumers from current git diff | `--base <ref>` |
250
-
251
- ### Health
252
-
253
- | Command | Description | Options |
254
- |---|---|---|
255
- | `health` | Composite codebase health report with prioritized action list | `-s, --scope <path>`<br>`--full`<br>`--json` |
256
- | `complexity <symbol>` | Per-symbol complexity: branches, cyclomatic estimate, fan-in/out, callees | `--full` |
257
-
258
- ### Maintenance
259
-
260
- | Command | Description | Options |
261
- |---|---|---|
262
- | `install-skills` | Install skills (concrete-plan, scip-explore, scip-debloat, scip-verify, scip-language-playbook) into Claude Code and Codex | - |
263
- | `check-deps` | Check whether scip-query and the detected language indexers are actually runnable | - |
264
- | `init` | Create a .scipquery.json config file for this project | - |
265
- | `watch` | Watch for file changes and reindex automatically | `--debounce <ms>`<br>`--cooldown <ms>` |
266
- | `status` | Show index status for this project | - |
267
-
268
- <!-- END GENERATED COMMAND REFERENCE -->
269
-
270
-
271
- ## Programmatic API
272
-
273
- Every CLI command is also a TypeScript function. The `queries` namespace exports cover all of them — including the `top*` variants of `fan-in`, `fan-out`, and `coupling`, plus `similarAll` for the cross-codebase mode of `similar`:
274
-
275
- ```typescript
276
- import {
277
- ScipDatabase, createGitignoreFilter,
278
- } from 'scip-query';
279
- import {
280
- health, affected, changeSurface, diffImpact,
281
- hotspots, similar, dead, convergence,
282
- } from 'scip-query/queries';
283
-
284
- const filter = createGitignoreFilter('/path/to/project');
285
- const db = new ScipDatabase({
286
- dbPath: '/path/to/index.db',
287
- indexPath: '/path/to/index.scip',
288
- projectRoot: '/path/to/project',
289
- }, filter);
290
-
291
- // Full health report
292
- const report = health(db);
293
- console.log(`Score: ${report.score}/100`);
294
- console.log(`Actions: ${report.actions.length}`);
295
-
296
- // Impact analysis
297
- const blast = affected(db, 'login', { maxDepth: 3 });
298
- const brief = changeSurface(db, 'auth.service.ts');
299
- const impact = diffImpact(db, { base: 'main' });
300
-
301
- // Consolidation
302
- const pairs = similar(db, 'myFunction', { minSimilarity: 0.5 });
303
- const recipe = convergence(db, 'funcA', 'funcB');
304
-
305
- db.close();
306
- ```
261
+ - [Agent Guide](docs/AGENT_GUIDE.md): goal-oriented workflows for tracing, planning, cleanup, quality checks, and change verification.
262
+ - [Command Reference](docs/COMMAND_REFERENCE.md): generated command syntax, descriptions, and options.
263
+ - [Programmatic API](docs/API.md): using the query functions from TypeScript.
264
+ - [Historical plans](docs/plans/): implementation notes and completed cleanup plans.
307
265
 
308
266
  ## License
309
267
 
@@ -1,2 +1,2 @@
1
- import{c as t}from"./chunk-6QH2L26C.js";import{writeFileSync as o}from"fs";import{workerData as s}from"worker_threads";var e=s;try{let r=t({projectRoot:e.projectRoot,dbPath:e.dbPath,tsconfig:e.tsconfig,vueFiles:e.vueFiles,tasks:e.tasks});o(e.resultPath,JSON.stringify({ok:!0,result:r}))}catch(r){o(e.resultPath,JSON.stringify({ok:!1,error:r instanceof Error?r.message:String(r)}))}finally{let r=new Int32Array(e.sharedBuffer);Atomics.add(r,0,1),Atomics.notify(r,0)}
1
+ import{c as t}from"./chunk-TH4JVC34.js";import{writeFileSync as o}from"fs";import{workerData as s}from"worker_threads";var e=s;try{let r=t({projectRoot:e.projectRoot,dbPath:e.dbPath,tsconfig:e.tsconfig,vueFiles:e.vueFiles,tasks:e.tasks});o(e.resultPath,JSON.stringify({ok:!0,result:r}))}catch(r){o(e.resultPath,JSON.stringify({ok:!1,error:r instanceof Error?r.message:String(r)}))}finally{let r=new Int32Array(e.sharedBuffer);Atomics.add(r,0,1),Atomics.notify(r,0)}
2
2
  //# sourceMappingURL=augment-vue-worker.js.map
@@ -1,4 +1,4 @@
1
- import{a as m}from"./chunk-NBUINPSH.js";import{a as S}from"./chunk-NKJKI6SE.js";import{b as h}from"./chunk-5RGK4YA5.js";import{b as d}from"./chunk-RCJEFQOK.js";import{a as y}from"./chunk-NN3O7TPH.js";import f from"path";function l(e){let n=e.replace(/\\/g,"/").split("/").filter(Boolean);return n.length<=1?"(root)":n.length>=3&&["src","lib","app","server","client"].includes(n[0])?`${n[0]}/${n[1]}`:n[0]}function p(e,t){if(e===t)return"ok";let n=g(e),i=g(t);return n&&i?v(n,i)?"ok":"violation":w(e,t)}function D(e,t){let n=g(l(e)),i=g(l(t));return!!n&&!!i}function g(e){return/^src\/([^/]+)$/.exec(e)?.[1]??null}function v(e,t){return t==="domain"?!0:e==="domain"?!1:{analysis:new Set(["domain","source","storage","symbols"]),core:new Set(["analysis","domain","resolution","source","storage","symbols"]),"language-parsers":new Set(["domain","resolution","source","storage"]),queries:new Set(["analysis","core","domain","language-parsers","resolution","semantic","source","storage","symbols"]),reindex:new Set(["domain","language-parsers","resolution","runtime","semantic","source","storage","symbols"]),resolution:new Set(["domain","source","storage","symbols"]),runtime:new Set(["domain","queries","reindex","resolution","semantic","source","storage","symbols"]),semantic:new Set(["domain","resolution","storage","symbols"]),source:new Set(["domain","storage"]),storage:new Set(["domain","source"]),symbols:new Set(["analysis","domain","language-parsers","resolution","semantic","source","storage"])}[e]?.has(t)??!1}function w(e,t){if(t==="shared")return"ok";let n={app:new Set(["core","shared","ui"]),core:new Set(["shared"]),infra:new Set(["core","shared"]),ui:new Set(["core","shared"])};return n[e]?n[e].has(t)?"ok":"violation":null}function G(e,t){let{scope:n,minDeviation:i=5}=t??{},r=t?.semantic!==!1,c=new m(e).fileDependencyGraph(n),a=O(e,n);return _([...R(e,c,a,{semantic:r}),...k(c),...I(c,i)])}function R(e,t,n,i){let r=[];for(let[s,c]of t){if(u(s))continue;let a=n.get(s)??new Set;for(let o of c)if(!u(o)&&!a.has(o)){if(i.semantic&&L(e,s,o)||A(e,s,o)||T(e,s,o)||F(o)||j(e,s,o)||V(o))continue;r.push({file:s,kind:"unused-import",description:`Depends on ${o} but references none of its symbols`,dep:o})}}return r}function k(e){let t=[],n=$(e);for(let[i,r]of e){if(u(i))continue;let s=l(i);for(let c of r){if(u(c))continue;let a=l(c);if(s===a)continue;(p(s,a)??n.get(`${s}->${a}`))==="violation"&&t.push({file:i,kind:"layer-violation",description:`Imports from ${a}/ (${c}) \u2014 may cross architectural boundary`,dep:c,detail:`${s}/ should not depend on ${a}/`})}}return t}function I(e,t){let n=[];for(let[i,r]of M(e)){let s=r.filter(a=>!u(a));if(s.length<t)continue;let c=x(e,s);for(let a of s)for(let o of e.get(a)??[])u(o)||(c.get(o)??0)===1&&f.dirname(o)!==i&&f.dirname(o)!==f.dirname(i)&&(D(a,o)||n.push({file:a,kind:"pattern-deviation",description:`Only file in ${i}/ that depends on ${o}`,dep:o}))}return n}function _(e){return{results:e,unusedImports:e.filter(t=>t.kind==="unused-import").length,layerViolations:e.filter(t=>t.kind==="layer-violation").length,patternDeviations:e.filter(t=>t.kind==="pattern-deviation").length}}function M(e){let t=new Map;for(let n of e.keys()){let i=f.dirname(n),r=t.get(i);r||(r=[],t.set(i,r)),r.push(n)}return t}function x(e,t){let n=new Map;for(let i of t)for(let r of e.get(i)??[])u(r)||n.set(r,(n.get(r)??0)+1);return n}function O(e,t){let n=new Map;return E(e,n,t),P(e,n),n}function E(e,t,n){for(let i of N(e,n))b(e,t,i.from_file,i.to_file)}function N(e,t){let n=t?`AND d1.relative_path LIKE '%${t}%'`:"";return e.all(`SELECT DISTINCT d1.relative_path AS from_file, d2.relative_path AS to_file
1
+ import{a as m}from"./chunk-NOVKLH2F.js";import{a as S}from"./chunk-TQTVM27C.js";import{b as h}from"./chunk-64UY7VTR.js";import{b as d}from"./chunk-APLCSDXL.js";import{a as y}from"./chunk-NN3O7TPH.js";import f from"path";function l(e){let n=e.replace(/\\/g,"/").split("/").filter(Boolean);return n.length<=1?"(root)":n.length>=3&&["src","lib","app","server","client"].includes(n[0])?`${n[0]}/${n[1]}`:n[0]}function p(e,t){if(e===t)return"ok";let n=g(e),i=g(t);return n&&i?v(n,i)?"ok":"violation":w(e,t)}function D(e,t){let n=g(l(e)),i=g(l(t));return!!n&&!!i}function g(e){return/^src\/([^/]+)$/.exec(e)?.[1]??null}function v(e,t){return t==="domain"?!0:e==="domain"?!1:{analysis:new Set(["domain","source","storage","symbols"]),core:new Set(["analysis","domain","resolution","source","storage","symbols"]),"language-parsers":new Set(["domain","resolution","source","storage"]),queries:new Set(["analysis","core","domain","language-parsers","resolution","semantic","source","storage","symbols"]),reindex:new Set(["domain","language-parsers","resolution","runtime","semantic","source","storage","symbols"]),resolution:new Set(["domain","source","storage","symbols"]),runtime:new Set(["domain","queries","reindex","resolution","semantic","source","storage","symbols"]),semantic:new Set(["domain","resolution","storage","symbols"]),source:new Set(["domain","storage"]),storage:new Set(["domain","source"]),symbols:new Set(["analysis","domain","language-parsers","resolution","semantic","source","storage"])}[e]?.has(t)??!1}function w(e,t){if(t==="shared")return"ok";let n={app:new Set(["core","shared","ui"]),core:new Set(["shared"]),infra:new Set(["core","shared"]),ui:new Set(["core","shared"])};return n[e]?n[e].has(t)?"ok":"violation":null}function G(e,t){let{scope:n,minDeviation:i=5}=t??{},r=t?.semantic!==!1,c=new m(e).fileDependencyGraph(n),a=O(e,n);return _([...R(e,c,a,{semantic:r}),...k(c),...I(c,i)])}function R(e,t,n,i){let r=[];for(let[s,c]of t){if(u(s))continue;let a=n.get(s)??new Set;for(let o of c)if(!u(o)&&!a.has(o)){if(i.semantic&&L(e,s,o)||A(e,s,o)||T(e,s,o)||F(o)||j(e,s,o)||V(o))continue;r.push({file:s,kind:"unused-import",description:`Depends on ${o} but references none of its symbols`,dep:o})}}return r}function k(e){let t=[],n=$(e);for(let[i,r]of e){if(u(i))continue;let s=l(i);for(let c of r){if(u(c))continue;let a=l(c);if(s===a)continue;(p(s,a)??n.get(`${s}->${a}`))==="violation"&&t.push({file:i,kind:"layer-violation",description:`Imports from ${a}/ (${c}) \u2014 may cross architectural boundary`,dep:c,detail:`${s}/ should not depend on ${a}/`})}}return t}function I(e,t){let n=[];for(let[i,r]of M(e)){let s=r.filter(a=>!u(a));if(s.length<t)continue;let c=x(e,s);for(let a of s)for(let o of e.get(a)??[])u(o)||(c.get(o)??0)===1&&f.dirname(o)!==i&&f.dirname(o)!==f.dirname(i)&&(D(a,o)||n.push({file:a,kind:"pattern-deviation",description:`Only file in ${i}/ that depends on ${o}`,dep:o}))}return n}function _(e){return{results:e,unusedImports:e.filter(t=>t.kind==="unused-import").length,layerViolations:e.filter(t=>t.kind==="layer-violation").length,patternDeviations:e.filter(t=>t.kind==="pattern-deviation").length}}function M(e){let t=new Map;for(let n of e.keys()){let i=f.dirname(n),r=t.get(i);r||(r=[],t.set(i,r)),r.push(n)}return t}function x(e,t){let n=new Map;for(let i of t)for(let r of e.get(i)??[])u(r)||n.set(r,(n.get(r)??0)+1);return n}function O(e,t){let n=new Map;return E(e,n,t),P(e,n),n}function E(e,t,n){for(let i of N(e,n))b(e,t,i.from_file,i.to_file)}function N(e,t){let n=t?`AND d1.relative_path LIKE '%${t}%'`:"";return e.all(`SELECT DISTINCT d1.relative_path AS from_file, d2.relative_path AS to_file
2
2
  FROM mentions m
3
3
  JOIN chunks c ON m.chunk_id = c.id
4
4
  JOIN documents d1 ON c.document_id = d1.id
@@ -15,4 +15,4 @@ import{a as m}from"./chunk-NBUINPSH.js";import{a as S}from"./chunk-NKJKI6SE.js";
15
15
  AND m.role != 1
16
16
  ${e.pathExclusionsFor("d1","d2")}
17
17
  ${n}`)}function P(e,t){new m(e).scanSourceReferences({paths:y(e,{includeIgnored:!1}),includeRustAttributeNames:!0,identifierResolution:"permissive"},i=>{i.target.relativePath!==i.sourceFile&&(e.isIgnored(i.target.relativePath)||b(e,t,i.sourceFile,i.target.relativePath))})}function b(e,t,n,i){if(e.isIgnored(n)||e.isIgnored(i))return;let r=t.get(n);r||(r=new Set,t.set(n,r)),r.add(i)}function $(e){let t=new Map;for(let[i,r]of e){if(u(i))continue;let s=l(i);for(let c of r){if(u(c))continue;let a=l(c);if(s===a||p(s,a))continue;let o=`${s}->${a}`;t.set(o,(t.get(o)??0)+1)}}let n=new Map;for(let[i,r]of t)n.set(i,r<=2?"violation":"ok");return n}function F(e){return e.includes("types")||e.endsWith(".d.ts")}function L(e,t,n){let i=h(e,t).filter(r=>r.sourcePath===n);return i.length>0&&i.some(r=>r.isUsed)}function A(e,t,n){let i=d(e,t).filter(r=>r.sourcePath===n);return i.length>0&&i.some(r=>r.used)}function T(e,t,n){let i=d(e,t).filter(r=>r.sourcePath===n);return i.length>0&&i.every(r=>r.isTypeOnly===!0)}function V(e){return e.endsWith(".vue")}function j(e,t,n){let i=d(e,t).filter(r=>r.sourcePath===n);return i.length===0?!1:i.every(r=>r.kind==="side-effect"||r.kind==="namespace"&&r.usedMembers.length===0&&!r.used)}function u(e){let t=S(e);return!!(t==="entry"||t==="barrel"||t==="test"||t==="worker"||J(f.basename(e)))}function J(e){return!!(e==="index.ts"||e==="index.js"||e==="cli.ts"||e==="main.ts"||e==="main.rs"||e.includes("worker.")||e.includes("postinstall.")||e==="health.ts"||e==="health.js")}export{G as a};
18
- //# sourceMappingURL=chunk-OPWOX7NT.js.map
18
+ //# sourceMappingURL=chunk-2EC4JTHC.js.map
@@ -1,4 +1,4 @@
1
- import{a as t}from"./chunk-SDPP5KVQ.js";function r(e,n,o){let d=t(e,n)??n,s=t(e,o)??o,m=e.get(`SELECT COUNT(DISTINCT gs.id) AS shared
1
+ import{a as t}from"./chunk-WC43FMAB.js";function r(e,n,o){let d=t(e,n)??n,s=t(e,o)??o,m=e.get(`SELECT COUNT(DISTINCT gs.id) AS shared
2
2
  FROM global_symbols gs
3
3
  WHERE (
4
4
  -- Defined in file1, referenced in file2
@@ -53,4 +53,4 @@ import{a as t}from"./chunk-SDPP5KVQ.js";function r(e,n,o){let d=t(e,n)??n,s=t(e,
53
53
  GROUP BY def_d.id, ref_d.id
54
54
  ORDER BY shared DESC
55
55
  LIMIT ?`,o).filter(i=>!e.isIgnored(i.file1)&&!e.isIgnored(i.file2)).map(i=>({file1:i.file1,file2:i.file2,sharedSymbols:i.shared}))}export{r as a,c as b};
56
- //# sourceMappingURL=chunk-SVSLAUSJ.js.map
56
+ //# sourceMappingURL=chunk-46ILZVMX.js.map
@@ -0,0 +1,2 @@
1
+ import{a as p,f as h}from"./chunk-N5D5ZCBW.js";import{a as c}from"./chunk-TQTVM27C.js";import{a as d}from"./chunk-RIXOMSOR.js";import{existsSync as A}from"fs";import{join as S}from"path";function T(e){return m.test(e)}var m=/(?:^|\/)(?:package-lock\.json|pnpm-lock\.yaml|yarn\.lock|Cargo\.lock|CHANGELOG(?:\.[a-z]+)?|.*\.map)$|(?:^|\/)(?:dist|build|out|node_modules)\//i;function j(e,i,t={}){let{minTogether:o=4,minConfidence:r=.6,limit:a=30}=t,u=p(e),s=i!==void 0,f=h(e,{minTogether:s?Math.min(o,2):o,minConfidence:s?0:r});if(!u||!f)return{available:!1,commitsAnalyzed:0,findings:[]};let C=d(e),y=t.includeLinked===!0||s,l=[];for(let n of f){if(m.test(n.fileA)||m.test(n.fileB)||!b(e,n.fileA)||!b(e,n.fileB)||s&&!n.fileA.includes(i)&&!n.fileB.includes(i)||!s&&(c(n.fileA)==="test"||c(n.fileB)==="test"||k(n.fileA,n.fileB)))continue;let g=x(C,n.fileA,n.fileB);if(!(!y&&g)&&(l.push({...n,structurallyLinked:g}),l.length>=a))break}return{available:!0,commitsAnalyzed:u.commits.length,findings:l}}function b(e,i){return A(S(e.config.projectRoot,i))}function k(e,i){let t=e.lastIndexOf("/"),o=i.lastIndexOf("/");if(e.slice(0,t)!==i.slice(0,o))return!1;let r=e.slice(t+1).split(".")[0],a=i.slice(o+1).split(".")[0];return r!==""&&r===a}function x(e,i,t){return e.get(i)?.has(t)===!0||e.get(t)?.has(i)===!0}export{T as a,j as b};
2
+ //# sourceMappingURL=chunk-4A4JFNWG.js.map
@@ -1,4 +1,4 @@
1
- import{a as f}from"./chunk-SDPP5KVQ.js";import{a as d}from"./chunk-NBUINPSH.js";import{d as c}from"./chunk-5RGK4YA5.js";import{c as u}from"./chunk-4VYIZV3S.js";function L(e,n,i={}){let t=f(e,n);if(!t)return null;let r=h(e,t);if(!r||e.isIgnored(r.relative_path))return null;let s=[],m=0,l=g(e,r.relative_path),p=i.semantic===!1?new Map:c(e,l);for(let o of l){let a=S(e,r,o,p.get(o.symbolId)??new Set);m+=a,s.push({symbol:o.symbol,shortName:u(o.symbol),startLine:o.startLine,endLine:o.endLine,externalConsumers:a,riskLevel:b(a)})}return{file:r.relative_path,symbols:s,totalExternalConsumers:m}}function h(e,n){return e.get(`SELECT id, relative_path FROM documents
1
+ import{a as f}from"./chunk-WC43FMAB.js";import{a as d}from"./chunk-NOVKLH2F.js";import{d as c}from"./chunk-64UY7VTR.js";import{c as u}from"./chunk-SOGLYIJ4.js";function L(e,n,i={}){let t=f(e,n);if(!t)return null;let r=h(e,t);if(!r||e.isIgnored(r.relative_path))return null;let s=[],m=0,l=g(e,r.relative_path),p=i.semantic===!1?new Map:c(e,l);for(let o of l){let a=S(e,r,o,p.get(o.symbolId)??new Set);m+=a,s.push({symbol:o.symbol,shortName:u(o.symbol),startLine:o.startLine,endLine:o.endLine,externalConsumers:a,riskLevel:b(a)})}return{file:r.relative_path,symbols:s,totalExternalConsumers:m}}function h(e,n){return e.get(`SELECT id, relative_path FROM documents
2
2
  WHERE relative_path = ?
3
3
  ${e.pathExclusionsFor("documents")}
4
4
  LIMIT 1`,n)??null}function g(e,n){return new d(e).definitionsForFile(n).sort((i,t)=>i.startLine-t.startLine||i.endLine-t.endLine)}function S(e,n,i,t){let r=e.all(`SELECT DISTINCT consumer_d.relative_path
@@ -8,4 +8,4 @@ import{a as f}from"./chunk-SDPP5KVQ.js";import{a as d}from"./chunk-NBUINPSH.js";
8
8
  WHERE m.symbol_id = ?
9
9
  AND m.role != 1
10
10
  AND c.document_id != ?`,i.symbolId,n.id);return new Set([...r.map(s=>s.relative_path),...[...t].filter(s=>s!==n.relative_path)]).size}function b(e){return e>10?"high":e>0?"medium":"low"}export{L as a};
11
- //# sourceMappingURL=chunk-QBXTQODK.js.map
11
+ //# sourceMappingURL=chunk-4B7YLRXX.js.map