scip-query 0.7.2 → 0.8.1

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 (174) 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-doc-reconcile/SKILL.md +100 -0
  147. package/skills/scip-explore/SKILL.md +22 -9
  148. package/skills/scip-language-playbook/SKILL.md +4 -4
  149. package/skills/scip-maintainability/SKILL.md +264 -0
  150. package/skills/scip-verify/SKILL.md +2 -2
  151. package/dist/chunk-3X43EYFU.js +0 -3
  152. package/dist/chunk-4GPWGSOE.js +0 -40
  153. package/dist/chunk-5RGK4YA5.js +0 -63
  154. package/dist/chunk-5TT47UMX.js +0 -44
  155. package/dist/chunk-6QH2L26C.js +0 -71
  156. package/dist/chunk-6SR4UNWI.js +0 -2
  157. package/dist/chunk-6XEWA6FX.js +0 -2
  158. package/dist/chunk-7WHNTKSD.js +0 -2
  159. package/dist/chunk-BOVNTAKQ.js +0 -3
  160. package/dist/chunk-D62LLANH.js +0 -2
  161. package/dist/chunk-EDXML2HI.js +0 -4
  162. package/dist/chunk-EZQOVY3C.js +0 -2
  163. package/dist/chunk-IODTPF5H.js +0 -20
  164. package/dist/chunk-KJ6CW6EK.js +0 -2
  165. package/dist/chunk-NBUINPSH.js +0 -2
  166. package/dist/chunk-NHDPYW7O.js +0 -2
  167. package/dist/chunk-NKJKI6SE.js +0 -2
  168. package/dist/chunk-OPZQIJZU.js +0 -7
  169. package/dist/chunk-P3PVY6TX.js +0 -2
  170. package/dist/chunk-QE6MGGUY.js +0 -2
  171. package/dist/chunk-QVPYMZUJ.js +0 -6
  172. package/dist/chunk-RCJEFQOK.js +0 -4
  173. package/dist/chunk-UHMJYNTK.js +0 -2
  174. package/dist/health-x7B4Xu_6.d.ts +0 -119
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: scip-doc-reconcile
3
+ description: Reconcile standards docs and living documentation with the current code using scip-query doc-drift evidence. Updates descriptive claims, repairs broken file references, and escalates normative violations instead of silently blessing them. Ends with staleness driven to zero.
4
+ allowed-tools: [Bash, Read, Write, Edit, Glob, Agent, TaskCreate, TaskUpdate, TaskGet, TaskList]
5
+ keywords: [docs, standards, reconcile, doc-drift, stale-docs, agent-os, spec, documentation, drift, sync]
6
+ ---
7
+
8
+ # Doc Reconciliation with scip-query
9
+
10
+ Standards docs exist so agents implement consistently. When the code moves and
11
+ the doc doesn't, every agent that reads it implements against a dead spec.
12
+ This skill reconciles docs with reality — using evidence, not memory.
13
+
14
+ ## The One Rule That Matters
15
+
16
+ A doc contains two kinds of statements, and they drift differently:
17
+
18
+ - **Descriptive** ("the horses workflow lives in `workflows/horses.ts` and
19
+ exposes `listHorses`") — when code moved on, **update the doc**.
20
+ - **Normative** ("all routes MUST validate stable scope before querying") —
21
+ when code violates it, **do NOT rewrite the standard to bless the
22
+ violation**. Either fix the code to comply, or record the contradiction in
23
+ the report for a human decision. Silently weakening a standard to match
24
+ drifted code is worse than the drift.
25
+
26
+ When unsure which kind a statement is: MUST/SHOULD/NEVER language is
27
+ normative; file paths, symbol names, and behavior descriptions are
28
+ descriptive.
29
+
30
+ ## Workflow
31
+
32
+ ### 1. Build the evidence-backed worklist
33
+
34
+ ```bash
35
+ scip-query reindex
36
+ scip-query doc-drift # all living docs, ranked by staleness
37
+ scip-query doc-drift agent-os/standards # scoped to a standards tree
38
+ ```
39
+
40
+ Triage order:
41
+ 1. Docs with `BROKEN REFERENCE` lines (the spec cites deleted code — actively wrong)
42
+ 2. Highest staleness score
43
+ 3. Docs agents read most (AGENTS.md, CLAUDE.md, standards indexes)
44
+
45
+ Track each doc as a task. Archival docs (dated plans, ADRs, reports) are
46
+ excluded automatically — do not "reconcile" records of past decisions.
47
+
48
+ ### 2. Reconcile one doc at a time
49
+
50
+ For each doc, gather what actually changed:
51
+
52
+ ```bash
53
+ scip-query doc-drift <doc> # its subjects + changes since
54
+ git log --oneline -15 -- <subject-file> # WHY the subject changed
55
+ scip-query outline <subject-file> # what it looks like NOW
56
+ scip-query system <module> # current module shape
57
+ scip-query trace <symbol-the-doc-mentions> # does it still exist? who uses it?
58
+ ```
59
+
60
+ Then edit the doc:
61
+
62
+ - **Broken references**: find where the code went (`scip-query files <stem>`,
63
+ `git log --follow`) and update the citation — or delete the claim if the
64
+ capability is gone.
65
+ - **Stale descriptive claims**: re-read the subject files and rewrite the
66
+ claims to match current behavior. Every concrete claim you write must be
67
+ something you verified with a scip-query command this session — no claims
68
+ from memory.
69
+ - **Examples and snippets**: re-derive them from current code
70
+ (`scip-query code <symbol>`), don't patch them by eye.
71
+ - **Normative violations found while reading**: add them to the report under
72
+ "Standard vs code contradictions" with file:line evidence. Do not edit the
73
+ normative text.
74
+
75
+ ### 3. Verify, per doc and overall
76
+
77
+ ```bash
78
+ scip-query doc-drift <doc> # staleness must drop to 0, broken refs to none
79
+ scip-query diff-gate # your own doc edits gate clean before commit
80
+ ```
81
+
82
+ A doc still showing staleness after your edit means a subject changed in
83
+ ways you haven't reflected — go back.
84
+
85
+ ### 4. Report
86
+
87
+ - Per doc: staleness before → after, broken references fixed, claims updated.
88
+ - **Standard vs code contradictions** (normative): each with the standard's
89
+ requirement, the violating file:line, and a recommendation (fix code /
90
+ amend standard) — explicitly awaiting a human call.
91
+ - Docs recommended for deletion (describe removed capabilities entirely).
92
+
93
+ ## Hard Rules
94
+
95
+ 1. Every updated claim cites the scip-query command that verified it (in the
96
+ commit message or PR description).
97
+ 2. Never weaken normative language to match drifted code.
98
+ 3. Never reconcile archival docs (plans, ADRs, reports) — they are records.
99
+ 4. One commit per doc (or tight group) so review is per-standard.
100
+ 5. Re-run `scip-query doc-drift` at the end; the summary line is the result.
@@ -24,19 +24,21 @@ You are exploring a codebase to build a deep, accurate understanding of how a sy
24
24
 
25
25
  ## Hard Rules
26
26
 
27
- 1. **Every claim must come from scip-query.** If you say "function X calls function Y," you must have run `scip-query call-graph X` or `scip-query code X` to verify it. No memory. No assumptions.
27
+ 1. **Use a current index.** Before exploration, run `scip-query status` when available and check whether the index is missing, stale, or built for a different project root. If the codebase has changed, the status is uncertain, or the user asks for current facts, run `scip-query reindex` before trusting results. If reindexing fails, report that the index may be stale and mark affected claims as unverified.
28
28
 
29
- 2. **Read the code.** Don't describe what a function "probably does" run `scip-query code <symbol>` and describe what it actually does.
29
+ 2. **Every claim must come from scip-query.** If you say "function X calls function Y," you must have run `scip-query call-graph X` or `scip-query code X` to verify it. No memory. No assumptions.
30
30
 
31
- 3. **Follow the graph, not the folder structure.** File organization can be misleading. Use `scip-query deps`, `scip-query rdeps`, `scip-query call-graph`, and `scip-query dataflow` to trace actual execution paths.
31
+ 3. **Read the code.** Don't describe what a function "probably does" run `scip-query code <symbol>` and describe what it actually does.
32
32
 
33
- 4. **Start wide, then narrow.** Begin with `scip-query system` for the module map, then drill into specific symbols with `scip-query call-graph`, `scip-query code`, and `scip-query dataflow`.
33
+ 4. **Follow the graph, not the folder structure.** File organization can be misleading. Use `scip-query deps`, `scip-query rdeps`, `scip-query call-graph`, and `scip-query dataflow` to trace actual execution paths.
34
+
35
+ 5. **Start wide, then narrow.** Begin with `scip-query system` for the module map, then drill into specific symbols with `scip-query call-graph`, `scip-query code`, and `scip-query dataflow`.
34
36
 
35
37
  ---
36
38
 
37
39
  ## Symbol Lookup Tips
38
40
 
39
- scip-query accepts partial symbol names — you don't need the full SCIP symbol path. These all work:
41
+ `scip-query` accepts partial symbol names — you don't need the full SCIP symbol path. These all work:
40
42
 
41
43
  ```bash
42
44
  scip-query code processVegaMention # just the function name
@@ -63,7 +65,7 @@ scip-query code 'src/modules/chat/chat.service.ts:100-200'
63
65
 
64
66
  **If "Symbol not found":**
65
67
  1. Try a shorter/simpler name — `login` instead of `AuthService:login`
66
- 2. Try `scip-query symbols <file>` to see what symbols exist in the file
68
+ 2. Try `scip-query outline <file>` to see what symbols exist in the file
67
69
  3. Try `scip-query trace <name>` which uses a different lookup path
68
70
  4. Use the `file:line-line` syntax for `code` if you know the location
69
71
 
@@ -71,6 +73,17 @@ scip-query code 'src/modules/chat/chat.service.ts:100-200'
71
73
 
72
74
  ## Exploration Workflow
73
75
 
76
+ ### Step 0: Verify the index
77
+
78
+ Start by making sure the SCIP facts are current enough to trust:
79
+
80
+ ```bash
81
+ scip-query status # Check index location, freshness, and project root
82
+ scip-query reindex # Run when missing, stale, uncertain, or after code changes
83
+ ```
84
+
85
+ If `status` is unavailable or inconclusive, run `scip-query stats` and `scip-query reindex` when the repository has changed. Do not explore from an index you know is stale.
86
+
74
87
  ### Step 1: Orient — What are we looking at?
75
88
 
76
89
  Start with the high-level map. Run these first:
@@ -78,7 +91,7 @@ Start with the high-level map. Run these first:
78
91
  ```bash
79
92
  scip-query stats # How big is this codebase?
80
93
  scip-query system <module> # Full module map: files, symbols, deps
81
- scip-query symbols <entry-file> # What's in the entry point?
94
+ scip-query outline <entry-file> # What's in the entry point?
82
95
  ```
83
96
 
84
97
  **Output:** List all files in the module, the key symbols, what it depends on, and what depends on it. This is your map.
@@ -152,7 +165,7 @@ scip-query complexity X # How complex is it
152
165
 
153
166
  ### "What happens when a user does Y?"
154
167
 
155
- 1. Find the entry point: `scip-query files <handler-pattern>` or `scip-query symbols <route-file>`
168
+ 1. Find the entry point: `scip-query files <handler-pattern>` or `scip-query outline <route-file>`
156
169
  2. Read the handler: `scip-query code <handler>`
157
170
  3. Follow each call: `scip-query call-graph <callee>` → `scip-query code <callee>` → repeat
158
171
  4. Trace the data: `scip-query dataflow <key-variable>` at each step
@@ -207,7 +220,7 @@ Every file path, line number, and behavioral claim includes the scip-query comma
207
220
  | Purpose | Command |
208
221
  |---|---|
209
222
  | Read source code | `scip-query code <symbol> [-C N]` |
210
- | All symbols in a file | `scip-query symbols <file>` |
223
+ | All symbols in a file | `scip-query outline <file>` |
211
224
  | Find files | `scip-query files <pattern>` |
212
225
  | Full module map | `scip-query system <module>` |
213
226
  | True public API | `scip-query surface <module>` |
@@ -27,7 +27,7 @@ Run these in almost every codebase, regardless of language:
27
27
  ```bash
28
28
  scip-query stats
29
29
  scip-query files <feature-or-module-name>
30
- scip-query symbols <file>
30
+ scip-query outline <file>
31
31
  scip-query trace <symbol>
32
32
  scip-query code <symbol>
33
33
  ```
@@ -68,7 +68,7 @@ Vue note: `.vue` single-file components are handled by the same path. scip-query
68
68
 
69
69
  Use first:
70
70
  ```bash
71
- scip-query symbols <file>
71
+ scip-query outline <file>
72
72
  scip-query outline <file>
73
73
  scip-query system <module-or-file>
74
74
  scip-query imports <file>
@@ -209,7 +209,7 @@ Use first:
209
209
  scip-query trace <symbol>
210
210
  scip-query call-graph <symbol>
211
211
  scip-query refs <symbol>
212
- scip-query symbols <file>
212
+ scip-query outline <file>
213
213
  scip-query outline <file>
214
214
  ```
215
215
 
@@ -347,7 +347,7 @@ scip-query extract-candidates
347
347
 
348
348
  ```bash
349
349
  scip-query files <feature>
350
- scip-query symbols <file>
350
+ scip-query outline <file>
351
351
  scip-query trace <entry-symbol>
352
352
  scip-query call-graph <entry-symbol>
353
353
  scip-query code <entry-symbol>
@@ -0,0 +1,264 @@
1
+ ---
2
+ name: scip-maintainability
3
+ description: Principled maintainability review using scip-query. Finds hidden policies, scattered concepts, accidental variation, weak boundaries, and system-compression opportunities, then proposes or executes structural improvements without chasing health scores.
4
+ allowed-tools: [Bash, Write, Edit, Glob, Agent, TaskCreate, TaskUpdate, TaskGet, TaskList]
5
+ keywords: [maintainability, architecture, compression, simplify, principal, staff, smell, hidden-policy, concept-boundary, accidental-variation, refactor]
6
+ ---
7
+
8
+ # SCIP Maintainability Review
9
+
10
+ You are reviewing a codebase from the standpoint of a senior maintainer. The goal is not to maximize a metric. The goal is to make future changes easier to understand and safer to execute by tying every claim to `scip-query` evidence and by improving the structure that real maintainers must reason about.
11
+
12
+ A maintainability review is an architecture review over real code units such as files, symbols, commands, adapters, caches, public exports, tests, and docs. It identifies where one human concept is scattered across several mechanisms, where policy lives in caller folklore, and where accidental variation makes future edits harder than they need to be.
13
+
14
+ System compression belongs inside this review. A system compression is a maintainability improvement that replaces several mechanisms performing the same role, policy, lifecycle, or public-surface job with fewer named mechanisms that preserve behavior.
15
+
16
+ ---
17
+
18
+ ## When to Use This Skill
19
+
20
+ - "What would a principal engineer notice?"
21
+ - "What is gross here?"
22
+ - "Did this look vibe-coded?"
23
+ - "How should we simplify this architecture?"
24
+ - "Find deeper maintainability problems"
25
+ - "What hidden policies or concepts are scattered?"
26
+ - "Compress this system"
27
+ - "Find the refactor that actually makes this easier to maintain"
28
+
29
+ ---
30
+
31
+ ## Hard Rules
32
+
33
+ 1. **Evidence first.** Use `scip-query` to ground claims in files, symbols, references, call graphs, dependencies, surfaces, and blast radius. If the SCIP index is missing or stale, run `scip-query reindex` before trusting graph facts.
34
+
35
+ 2. **Do not chase health scores.** `scip-query health`, detector counts, and LOC estimates are diagnostic signals. They are not the objective. A change is valuable only when it reduces real maintenance burden while preserving behavior.
36
+
37
+ 3. **Name the referents before naming the smell.** A smell is not real until you can point to the concrete files, symbols, tests, or public surfaces that make the future-maintenance risk real.
38
+
39
+ 4. **Preserve essential variation.** Do not compress code merely because it looks similar. Different language grammars, runtime contracts, compatibility boundaries, public APIs, or domain rules may justify different code.
40
+
41
+ 5. **Reject false abstractions.** A new abstraction is justified only when it removes a hidden policy, names a lifecycle, enforces a rule callers were hand-maintaining, or reduces the concept count required for safe change.
42
+
43
+ 6. **Prefer small named mechanisms.** Delete, inline, merge, generate, or enforce before adding broad frameworks.
44
+
45
+ ---
46
+
47
+ ## Core Concepts
48
+
49
+ A code smell is an observable codebase fact that predicts avoidable future mistakes because the same knowledge must be rediscovered, synchronized, or defended in more than one place.
50
+
51
+ A concept boundary is the line around code units that exist for one reason to change. A weak boundary mixes unrelated reasons to change, such as parsing syntax, choosing fallback policy, caching data, and rendering output in one module.
52
+
53
+ A hidden policy is a rule for choosing behavior when several plausible behaviors exist, but the rule is implemented through local branches, repeated comments, naming conventions, or caller folklore instead of a named mechanism.
54
+
55
+ A lifecycle is a repeatable sequence of states or steps that makes a result valid, such as parse -> fallback -> emit, candidate -> evidence -> score -> report, or load -> augment -> write -> invalidate.
56
+
57
+ Accidental variation is difference in code shape that does not correspond to a difference in behavior, domain facts, runtime constraints, or external contracts.
58
+
59
+ Essential variation is difference that must remain because the real-world units differ, such as different language grammars, indexer capabilities, user-visible APIs, runtime environments, or compatibility boundaries.
60
+
61
+ Concept count is the number of distinct ideas a maintainer must keep active to make a safe change. Lowering concept count is valuable only when the new structure still explains all real variation.
62
+
63
+ ---
64
+
65
+ ## Workflow
66
+
67
+ ### 1. Bound the Review
68
+
69
+ Restate the question in concrete terms:
70
+
71
+ ```text
72
+ What future-maintenance mistakes does this structure invite, and what smaller named mechanisms would prevent them without hiding real variation?
73
+ ```
74
+
75
+ Identify the scope: whole repo, module, command family, query family, runtime surface, test fixture set, or one feature path.
76
+
77
+ ### 2. Refresh and Map Evidence
78
+
79
+ Start from current code intelligence:
80
+
81
+ ```bash
82
+ scip-query status
83
+ scip-query reindex # Run when missing, stale, uncertain, or after code changes
84
+ scip-query stats
85
+ scip-query system <scope>
86
+ scip-query surface <scope>
87
+ ```
88
+
89
+ Then map the concrete units:
90
+
91
+ ```bash
92
+ scip-query files <pattern>
93
+ scip-query outline <file>
94
+ scip-query outline <file>
95
+ scip-query deps <file>
96
+ scip-query rdeps <file>
97
+ scip-query trace <symbol>
98
+ scip-query call-graph <symbol>
99
+ scip-query affected <symbol>
100
+ scip-query change-surface <file>
101
+ ```
102
+
103
+ Use cleanup commands as probes, not verdicts:
104
+
105
+ ```bash
106
+ scip-query health --json
107
+ scip-query similar
108
+ scip-query similar-files
109
+ scip-query similar-chains
110
+ scip-query extract-candidates
111
+ scip-query wrapper-candidates
112
+ scip-query passthrough-candidates
113
+ scip-query stale-abstractions --include-low-confidence
114
+ scip-query drift
115
+ scip-query cycles
116
+ ```
117
+
118
+ ### 3. Build a Role Inventory
119
+
120
+ For each important cluster, record:
121
+
122
+ - concrete files and exported symbols
123
+ - callers and downstream public surfaces
124
+ - tests and fixtures that define behavior
125
+ - fallback paths, caches, registries, adapters, and command handlers
126
+ - generated artifacts or compatibility constraints
127
+ - the role each unit plays in the workflow
128
+
129
+ Ask:
130
+
131
+ - What one concept is being implemented in several places?
132
+ - What policy is hidden in branches, comments, argument conventions, or test fixtures?
133
+ - What lifecycle is present but unnamed?
134
+ - Which differences are essential, and which are accidental?
135
+ - What must a new maintainer know that the local interface does not admit?
136
+ - Would a smaller named mechanism remove a reason to change, or only move code around?
137
+
138
+ ### 4. Rank Maintainability Pressure
139
+
140
+ Prefer severe smells in this order:
141
+
142
+ 1. Hidden correctness or evidence policy spread across modules.
143
+ 2. Repeated lifecycle or pipeline with no named owner.
144
+ 3. Public surface that exposes accidental internals.
145
+ 4. Large module with multiple unrelated reasons to change.
146
+ 5. Tests that encode incident history without contract vocabulary.
147
+ 6. Adapter families with repeated capability or fallback shapes.
148
+ 7. Suppression comments that document architecture decisions instead of exceptions.
149
+ 8. Thin wrappers, pass-throughs, and helper layers that do not buy clarity.
150
+
151
+ Reject a target when:
152
+
153
+ - similar code reflects essential variation
154
+ - the new abstraction needs more concepts than it removes
155
+ - a compatibility boundary must stay explicit
156
+ - the smell is only aesthetic
157
+ - the behavior cannot be verified
158
+
159
+ ### 5. Choose a Compression Model
160
+
161
+ For substantial changes, compare at least two models:
162
+
163
+ - conservative: delete or inline local bloat without changing ownership
164
+ - shape-level: introduce one small mechanism that owns a repeated role or lifecycle
165
+ - radical: replace a scattered surface with metadata, generation, or an enforced policy
166
+
167
+ Evaluate each model by:
168
+
169
+ - behavior preserved
170
+ - concept count removed
171
+ - blast radius from `affected`, `change-surface`, `deps`, and `rdeps`
172
+ - deletion potential
173
+ - failure mode if the abstraction is false
174
+ - migration path and verification cost
175
+
176
+ Choose the model that removes a concept or policy duplication, not the model that merely extracts a helper.
177
+
178
+ ### 6. Produce a Register or Atlas
179
+
180
+ For broad review, create or update a register under `docs/plans/` unless the user asks not to edit files:
181
+
182
+ ```markdown
183
+ # SCIP Maintainability Register
184
+
185
+ ## Executive Read
186
+ ## Scope Map
187
+ ## Smell Ledger
188
+
189
+ | Priority | Smell | Evidence | Why it hurts | Better shape | Disposition |
190
+ | --- | --- | --- | --- | --- | --- |
191
+
192
+ ## Compression Opportunities
193
+ ## Deferred Boundaries
194
+ ## Verification Plan
195
+ ```
196
+
197
+ For implementation work, create an atlas before editing:
198
+
199
+ ```markdown
200
+ # <Scope> Maintainability Atlas
201
+
202
+ ## Scope Map
203
+ ## Role Inventory
204
+ ## Hidden Policies
205
+ ## Essential vs Accidental Variation
206
+ ## Opportunity Ledger
207
+ ## Dependency Order
208
+ ## Touch Map
209
+ ## Validation Plan
210
+ ```
211
+
212
+ Use dispositions:
213
+
214
+ - `merge`: combine mechanisms with the same role
215
+ - `delete`: remove proven unused or replaced code
216
+ - `inline`: remove a wrapper, adapter, or single-use abstraction
217
+ - `extract`: isolate a real shared role that multiple consumers need
218
+ - `generate`: derive a surface from metadata instead of maintaining it by hand
219
+ - `enforce`: centralize a policy or invariant so callers cannot drift
220
+ - `supersede`: absorb a local issue into a larger cluster
221
+ - `defer`: keep visible but out of scope because of a verified blocker
222
+ - `skip`: reject because the compression is false or net-negative
223
+
224
+ ### 7. Implement Conservatively
225
+
226
+ When asked to fix the smells:
227
+
228
+ - introduce the smallest named mechanism that matches the real concept
229
+ - keep essential variation close to the adapter or domain code that knows it
230
+ - move hidden policies behind interfaces that make the choice visible
231
+ - preserve behavior before broadening scope
232
+ - update registers or docs to record deferred boundaries and why
233
+
234
+ ### 8. Verify the Work
235
+
236
+ Run focused tests for touched code and repeat the structural probes that motivated the change:
237
+
238
+ ```bash
239
+ scip-query health --json
240
+ scip-query drift
241
+ scip-query stale-abstractions --include-low-confidence
242
+ scip-query wrapper-candidates
243
+ scip-query passthrough-candidates
244
+ scip-query similar-files
245
+ ```
246
+
247
+ Report:
248
+
249
+ - the named smell addressed
250
+ - the mechanism introduced, deleted, or simplified
251
+ - what was deliberately not compressed
252
+ - verification results
253
+ - commit hash, when committed
254
+
255
+ ---
256
+
257
+ ## Output Style
258
+
259
+ Be candid, specific, and evidence-grounded:
260
+
261
+ - "This module has three reasons to change."
262
+ - "This helper names a policy that was previously caller folklore."
263
+ - "This is false compression because the two adapters differ by runtime contract."
264
+ - "The health score changed, but that is a side effect, not the reason this was worth doing."
@@ -37,7 +37,7 @@ You are verifying that a code change was implemented correctly. Every check must
37
37
 
38
38
  ## Symbol Lookup Tips
39
39
 
40
- scip-query accepts partial symbol names — you don't need the full SCIP symbol path. These all work:
40
+ `scip-query` accepts partial symbol names — you don't need the full SCIP symbol path. These all work:
41
41
 
42
42
  ```bash
43
43
  scip-query code processVegaMention # just the function name
@@ -64,7 +64,7 @@ scip-query code 'src/modules/chat/chat.service.ts:100-200'
64
64
 
65
65
  **If "Symbol not found":**
66
66
  1. Try a shorter/simpler name — `login` instead of `AuthService:login`
67
- 2. Try `scip-query symbols <file>` to see what symbols exist in the file
67
+ 2. Try `scip-query outline <file>` to see what symbols exist in the file
68
68
  3. Try `scip-query trace <name>` which uses a different lookup path
69
69
  4. Use the `file:line-line` syntax for `code` if you know the location
70
70
 
@@ -1,3 +0,0 @@
1
- import{a as b}from"./chunk-RCJEFQOK.js";import{d as x}from"./chunk-4VYIZV3S.js";import{a as d,e as g,j as y}from"./chunk-5TT47UMX.js";import{a as u}from"./chunk-NHDPYW7O.js";var C=u("definition-consumer-file-usage");function I(e,t,n){return e.callerFileMap(t,{semantic:n.semantic,sourceFallback:n.sourceFallback})}function P(e,t,n){let i=[],r=0,s=0,p=x(t.symbol);for(let a of n)D(e,a,t.relativePath,p)?r++:S(e,a,p)?s++:i.push(a);return{realConsumers:i,barrelConsumers:r,importOnlyConsumers:s}}function S(e,t,n){if(!n)return!1;let i=g(t);if(!i)return!1;let r=C.get(e,t,()=>v(e,t,i));return r.importedLeaves.has(n)&&!r.usedLeaves.has(n)}function j(e){C.invalidateAll(e)}function v(e,t,n){let i=new Set,r=new Set,s=y(e,t);if(!s)return{importedLeaves:i,usedLeaves:r};let p=n==="rust"?new Set(["use_declaration"]):n==="python"?new Set(["import_statement","import_from_statement"]):new Set(["import_statement"]),a=(o,f)=>{let c=f||p.has(o.type);(o.type==="identifier"||o.type==="type_identifier"||o.type==="property_identifier"||o.type==="field_identifier")&&(c?i.add(o.text):r.add(o.text));for(let l of o.children)a(l,c)};return a(s.rootNode,!1),{importedLeaves:i,usedLeaves:r}}function D(e,t,n,i){if(!i)return!1;let r=d(e,t);if(!r)return!1;let s=b(e,t);if(s.length===0)return!1;let p=i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),a=new RegExp(`\\b${p}\\b`),o=r.split(`
2
- `),f=0;for(let c=0;c<o.length;c++){if(!a.test(o[c]??""))continue;if(f++,!s.find(m=>m.startLine<=c&&c<=m.endLine))return!1}return f>0}export{I as a,P as b,S as c,j as d};
3
- //# sourceMappingURL=chunk-3X43EYFU.js.map
@@ -1,40 +0,0 @@
1
- import{c as $}from"./chunk-5RGK4YA5.js";import{c as R}from"./chunk-EVXQF7DM.js";import{b as y}from"./chunk-RCJEFQOK.js";import{A as O,t as A,u as T}from"./chunk-BOVNTAKQ.js";import{c as L}from"./chunk-KJ6CW6EK.js";import{d,s as h,w as _}from"./chunk-4VYIZV3S.js";import{a as p,e as m,j as P}from"./chunk-5TT47UMX.js";import{a as S,b as k}from"./chunk-NHDPYW7O.js";var X=new Set(["identifier","type_identifier","field_identifier"]),q=new Set(["identifier"]),ee=new Set(["identifier","property_identifier","type_identifier"]),ne=new Set(["rust","python"]),te=/\{([^{}]*)\}/g,ie=/\b([A-Za-z_][\w]*)\b/g;function I(e,t,i,n={}){if(!i)return[];let r=p(e,t);if(!r)return[];if(r.indexOf(i)===-1)return[];if(m(t))return(D(e,t).get(i)??[]).filter(f=>!B(f,n));let o=T(e,t,r),s=new RegExp(`\\b${O(i)}\\b`),a=[];for(let c=0;c<o.length;c++)B(c,n)||s.test(o[c]??"")&&a.push(c);return a}function B(e,t){return typeof t.excludeStartLine=="number"&&typeof t.excludeEndLine=="number"&&e>=t.excludeStartLine&&e<=t.excludeEndLine}var x=S("file-identifiers");function H(e,t){return x.get(e,t,()=>new Set(D(e,t).keys()))}var N=S("file-ident-lines");function D(e,t){return N.get(e,t,()=>re(e,t))}var v=S("file-idents-by-line");function Se(e,t){return v.get(e,t,()=>{let i=D(e,t),n=0;for(let o of i.values()){let s=o[o.length-1];s!==void 0&&s>n&&(n=s)}let r=new Array(n+1);for(let o=0;o<=n;o+=1)r[o]=new Set;for(let[o,s]of i)for(let a of s)r[a].add(o);return r})}function ye(e){x.invalidateAll(e),N.invalidateAll(e),v.invalidateAll(e)}function he(e,t){x.invalidate(e,t),N.invalidate(e,t),v.invalidate(e,t)}function re(e,t){let i=new Map,n=(a,c)=>{let l=i.get(a);if(!l){i.set(a,[c]);return}l[l.length-1]!==c&&l.push(c)};if(m(t)){let a=P(e,t);if(a){let c=m(t),l=c==="rust"?X:c==="python"?q:ee,f=u=>{if(l.has(u.type)&&n(u.text,u.startPosition.row),c&&ne.has(c)&&u.type==="string_content"){let E=u.startPosition.row;for(let K of u.text.matchAll(te)){let V=K[1]??"";for(let F of V.matchAll(ie))F[1]&&n(F[1],E)}}for(let E of u.children)f(E)};return f(a.rootNode),i}}let r=p(e,t);if(!r)return i;let o=A(r).split(/\r?\n/),s=/\b([A-Za-z_$][\w$]*)\b/g;for(let a=0;a<o.length;a+=1){let c=o[a]??"";for(let l of c.matchAll(s))l[1]&&n(l[1],a)}return i}function j(e){return e.replace(/\\/g,"/").replace(/^\.\//,"")}function g(e,t){return j(e)===j(t)}function J(e,t){let i=new Map;for(let n of y(e,t)){if(!n.sourcePath)continue;let r=n.localName??n.importedName;if(r&&G(i,r,n.sourcePath),n.kind==="namespace")for(let o of n.usedMembers)G(i,o,n.sourcePath)}return i}function G(e,t,i){let n=e.get(t);n||(n=new Set,e.set(t,n)),n.add(i)}function Le(e,t){return C(e,t,i=>{let n=i?`AND m.symbol_id IN (${i.map(()=>"?").join(",")})`:"";return e.all(`SELECT
2
- m.symbol_id,
3
- d.relative_path,
4
- COUNT(*) AS ref_count
5
- FROM mentions m
6
- JOIN chunks c ON m.chunk_id = c.id
7
- JOIN documents d ON c.document_id = d.id
8
- WHERE m.role != 1
9
- ${n}
10
- ${e.pathExclusionsFor("d")}
11
- GROUP BY m.symbol_id, d.relative_path`,...i??[])})}function xe(e,t){return C(e,t,i=>{let n=i?`AND m.symbol_id IN (${i.map(()=>"?").join(",")})`:"";return e.all(`SELECT DISTINCT m.symbol_id, d.relative_path
12
- FROM mentions m
13
- JOIN chunks c ON m.chunk_id = c.id
14
- JOIN documents d ON c.document_id = d.id
15
- WHERE m.role != 1
16
- ${n}
17
- ${e.pathExclusionsFor("d")}`,...i??[])}).filter(i=>i.symbol_id!==null)}function Y(e,t){return C(e,t,i=>{let n=i?`AND m.symbol_id IN (${i.map(()=>"?").join(",")})`:"";return e.all(`SELECT DISTINCT m.symbol_id, d.relative_path, c.document_id,
18
- c.start_line AS chunk_start, c.end_line AS chunk_end
19
- FROM mentions m
20
- JOIN chunks c ON m.chunk_id = c.id
21
- JOIN documents d ON c.document_id = d.id
22
- WHERE m.role != 1
23
- ${n}
24
- ${e.pathExclusionsFor("d")}
25
- ORDER BY d.relative_path, c.start_line`,...i??[])})}function C(e,t,i){if(!t)return i();if(t.length===0)return[];let n=[];for(let r=0;r<t.length;r+=750)n.push(...i(t.slice(r,r+750)));return n}function Fe(e,t){let i=z(e);return i?t.filter(n=>z(n.file)===i):t}function ke(e,t,i,n){let r=i.find(o=>o.file===t);if(r)return r;if(n){let o=new Set(y(e,t).map(s=>s.sourcePath).filter(s=>!!s));for(let s of i)for(let a of o)if(g(a,s.file))return s;return null}return i.length===1?i[0]:null}function z(e){let t=m(e);return t?t==="typescript"||t==="tsx"||t==="javascript"?"javascript-family":t:null}var U=k("global-leaf-index");function w(e){return U.get(e,()=>{let t=e.all(`SELECT gs.id, gs.symbol,
26
- COALESCE(der_doc.relative_path, mention_doc.relative_path) AS relative_path
27
- FROM global_symbols gs
28
- LEFT JOIN defn_enclosing_ranges der ON der.symbol_id = gs.id
29
- LEFT JOIN documents der_doc ON der_doc.id = der.document_id
30
- LEFT JOIN (
31
- SELECT m.symbol_id, MIN(d.relative_path) AS relative_path
32
- FROM mentions m
33
- JOIN chunks c ON m.chunk_id = c.id
34
- JOIN documents d ON c.document_id = d.id
35
- WHERE m.role = 1
36
- GROUP BY m.symbol_id
37
- ) mention_doc ON mention_doc.symbol_id = gs.id
38
- WHERE 1 = 1
39
- ${e.symbolNoiseFor("gs")}`),i=new Map;for(let n of t){if(!n.relative_path||e.isIgnored(n.relative_path))continue;let r=d(n.symbol);if(!r)continue;let o=i.get(r);o||(o=[],i.set(r,o)),o.some(s=>s.symbolId===n.id)||o.push({symbol:n.symbol,symbolId:n.id,file:n.relative_path})}return i})}function Ae(e){U.invalidate(e)}function M(e,t,i){let n=w(e).get(i);if(!n||n.length===0)return[];if(n.length===1)return[b(n[0])];let r=n.filter(c=>c.file===t);if(r.length>0)return r.map(b);let o=J(e,t),s=o.get(i);if(s)for(let c of s){let l=n.filter(f=>g(c,f.file));if(l.length>0)return l.map(b)}let a=new Set;for(let c of o.values())for(let l of c)a.add(l);for(let c of a){let l=n.filter(f=>g(c,f.file));if(l.length>0&&l.length===n.length)return l.map(b)}return[]}function Ue(e,t,i){let n=M(e,t,i);if(n.length>0)return n;let r=w(e).get(i);return!r||r.length===0?[]:r.map(b)}function Z(e,t,i={}){let n=R(e,t);if(!n)return[];let r=d(n.symbol);if(!r)return[];if(i.semantic!==!1){let s=$(e,{...n,leaf:r,parentTypeName:null,isFunctionLike:!1,isTypeLike:!1,kind:null,documentation:null,enclosingSymbol:null});if(s.length>0){let a=new Map;for(let c of s){let l=a.get(c.file)??[];l.push(c.line),a.set(c.file,l)}return W(e,a)}}let o=new Map;for(let s of L(e)){let a=p(e,s);if(!a||a.indexOf(r)===-1||s!==n.relativePath&&!M(e,s,r).some(f=>f.symbolId===n.symbolId))continue;let c=I(e,s,r,s===n.relativePath?{excludeStartLine:n.startLine,excludeEndLine:n.endLine}:{});c.length>0&&o.set(s,c)}return W(e,o)}function We(e,t){let i=new Map;for(let o of t){if(!o.leaf)continue;let s=i.get(o.leaf)??[];s.push(o),i.set(o.leaf,s)}if(i.size===0)return new Map;let n=new Set(t.map(o=>o.symbolId)),r=new Map;for(let o of L(e)){let s=H(e,o);if(s.size!==0){for(let a of s)if(i.has(a))for(let c of M(e,o,a)){if(!n.has(c.symbolId)||o===c.relativePath)continue;let l=r.get(c.symbolId);l||(l=new Set,r.set(c.symbolId,l)),l.add(o)}}}return r}function b(e){return{symbolId:e.symbolId,symbol:e.symbol,relativePath:e.file}}function W(e,t){let i=[],n=new Set;for(let[r,o]of t){let s=h(e,r);for(let a of o){let c=_(s,a),l=`${r}|${a}|${c?.symbol??""}`;n.has(l)||(n.add(l),i.push({file:r,line:a,enclosingSymbol:c?.symbol??null}))}}return i}function oe(e,t){let i=ue(e,t);return i?me(e,ce(e,i.match,i.identifier)):[]}function nn(e,t,i={}){return se(e,t,i).map(n=>({file:n.file,line:n.line,enclosingSymbol:n.enclosingSymbol}))}function se(e,t,i={}){let n=Z(e,t,{semantic:i.semantic}),r=n.length>0?Q(n,"source-attribution"):Q(oe(e,t),"scip-reference-chunk");return i.includeIgnored===!0?r:r.filter(o=>!e.isIgnored(o.file))}function Q(e,t){return e.map(i=>({...i,provenance:t}))}function ce(e,t,i){let n=new Map;for(let[r,o]of ae(e,t.symbolId))n.set(r,le(e,r,o,t,i));return n}function ae(e,t){let i=new Map;for(let n of Y(e,[t])){if(e.isIgnored(n.relative_path))continue;let r=i.get(n.relative_path);r||(r=[],i.set(n.relative_path,r)),r.push({start_line:n.chunk_start,end_line:n.chunk_end})}return i}function le(e,t,i,n,r){let o=t===n.relativePath?{excludeStartLine:n.startLine,excludeEndLine:n.endLine}:{},s=r?I(e,t,r,o):[];return i.flatMap(a=>fe(s,a))}function fe(e,t){let i=e.filter(n=>n>=t.start_line&&n<=t.end_line);return i.length>0?i:[t.start_line]}function ue(e,t){let i=R(e,t);return i?{match:i,identifier:d(i.symbol)||null}:null}function me(e,t){let i=[],n=new Set;for(let[r,o]of t){let s=h(e,r);for(let a of o){let c=_(s,a),l=`${r}|${a}|${c?.symbol??""}`;n.has(l)||(n.add(l),i.push({file:r,line:a,enclosingSymbol:c?.symbol??null}))}}return i}export{D as a,Se as b,ye as c,he as d,Le as e,xe as f,Y as g,g as h,Fe as i,ke as j,w as k,Ae as l,J as m,M as n,Ue as o,We as p,oe as q,nn as r};
40
- //# sourceMappingURL=chunk-4GPWGSOE.js.map
@@ -1,63 +0,0 @@
1
- import{l as T}from"./chunk-BOVNTAKQ.js";import{d as N,s as k}from"./chunk-4VYIZV3S.js";import{a as x}from"./chunk-NN3O7TPH.js";function p(i,e,t){if(i.has(e))return i.get(e);let n=t();return i.set(e,n),n}import _ from"path";function oe(i,e){return i.getReferences().map(t=>{let n=t.getNode();return $(n,e)})}function se(i){let e=i;return typeof e.findReferences=="function"?e.findReferences():[]}function U(i,e,t,n){let r=[];for(let o of se(i))for(let s of oe(o,n))s.file===e.relativePath&&s.line>=e.startLine&&s.line<=e.endLine||r.push(s);for(let o of t)r.push(o);return E(r)}function W(i,e,t,n){let r=[],o=t?.getStart();for(let s of i.getReferences()){let a=s.getNode();y(n,a.getSourceFile().getFilePath())===e&&(o!==void 0&&a.getStart()===o||r.push({location:$(a,n),node:a}))}return r}function $(i,e){let t=i.getSourceFile(),n=t.getLineAndColumnAtPos(i.getStart());return{file:y(e,t.getFilePath())??t.getBaseName(),line:n.line-1,column:n.column-1}}function B(i,e,t){let n=i.getSourceFile(),r=g(n,i),o=i.getText(),s=new RegExp(`\\b${ae(o)}\\b`,"g"),a=n.getFullText().split(`
2
- `),l=[];for(let c=0;c<a.length;c++){if(c===r)continue;let f=a[c]??"";s.lastIndex=0;let u;for(;(u=s.exec(f))!==null;)l.push({file:e,line:c,column:u.index})}return E(l.filter(c=>y(t,_.join(t,c.file))===e))}function P(i){for(let e=i;e;e=e.getParent()){let t=e.getKindName();if(t.includes("Type")||t==="InterfaceDeclaration"||t==="TypeAliasDeclaration")return!0;if(t==="CallExpression"||t==="NewExpression"||t==="ExpressionStatement")return!1}return!1}function g(i,e){return i.getLineAndColumnAtPos(e.getStart()).line-1}function E(i){let e=new Set,t=[];for(let n of i){let r=`${n.file}:${n.line}:${n.column}`;e.has(r)||(e.add(r),t.push(n))}return t}function y(i,e){let t=_.relative(i||process.cwd(),e).replace(/\\/g,"/");return!t||t.startsWith("..")?null:t}function ae(i){return i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function H(i,e,t,n){let r=ce(e,n);return r.size===0?new Map:le(i,t,r)}function ce(i,e){let t=new Map;for(let n of k(i,e)){let r=N(n.symbol)??n.leaf;if(!r)continue;let o=t.get(r);o||(o=[],t.set(r,o)),o.push(n)}return t}function le(i,e,t){let n=new Map,r=new Map;return e.forEachDescendant(o=>{for(let s of de(i,o)){let a=t.get(s);if(!a)continue;let l=g(e,o);for(let c of a){if(l<c.startLine-1||l>c.endLine+1)continue;let f=Math.abs(l-c.startLine),u=r.get(c.symbolId);u!==void 0&&u<=f||(r.set(c.symbolId,f),n.set(c.symbolId,o))}}}),n}function de(i,e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};if("getNameNode"in e&&typeof e.getNameNode=="function"){let r=e.getNameNode();n(r?.getText())}if("getName"in e&&typeof e.getName=="function"){let r=e.getName();n(r)}return i.Node.isIdentifier(e)&&n(e.getText()),t}function J(i,e,t,n){return i.all(`SELECT
3
- gs.id AS symbolId,
4
- gs.symbol,
5
- d.relative_path AS relativePath,
6
- COALESCE(der.start_line, c.start_line) AS startLine,
7
- COALESCE(der.end_line, c.end_line) AS endLine,
8
- COALESCE(gs.display_name, '') AS leaf,
9
- NULL AS parentTypeName,
10
- CASE WHEN gs.kind IN (6, 12, 13) OR gs.symbol LIKE '%().' THEN 1 ELSE 0 END AS isFunctionLike,
11
- CASE WHEN gs.kind IN (5, 8, 11) THEN 1 ELSE 0 END AS isTypeLike,
12
- gs.kind AS kind,
13
- gs.documentation AS documentation,
14
- gs.enclosing_symbol AS enclosingSymbol
15
- FROM global_symbols gs
16
- LEFT JOIN defn_enclosing_ranges der ON der.symbol_id = gs.id
17
- LEFT JOIN chunks c ON c.document_id = der.document_id
18
- JOIN documents d ON d.id = der.document_id
19
- WHERE d.relative_path = ?
20
- AND COALESCE(gs.display_name, gs.symbol) LIKE ?
21
- ORDER BY ABS(COALESCE(der.start_line, c.start_line) - ?)
22
- LIMIT 5`,e,`%${n}%`,t)[0]??null}function V(i,e){let t=i.all(`SELECT
23
- d.id AS documentId,
24
- gs.id AS symbolId,
25
- gs.symbol,
26
- d.relative_path AS relativePath,
27
- der.start_line AS startLine,
28
- der.end_line AS endLine,
29
- COALESCE(gs.display_name, '') AS leaf,
30
- NULL AS parentTypeName,
31
- CASE WHEN gs.kind IN (6, 12, 13) OR gs.symbol LIKE '%().' THEN 1 ELSE 0 END AS isFunctionLike,
32
- CASE WHEN gs.kind IN (5, 8, 11) THEN 1 ELSE 0 END AS isTypeLike,
33
- gs.kind AS kind,
34
- gs.documentation AS documentation,
35
- gs.enclosing_symbol AS enclosingSymbol
36
- FROM global_symbols gs
37
- JOIN defn_enclosing_ranges der ON der.symbol_id = gs.id
38
- JOIN documents d ON d.id = der.document_id
39
- WHERE d.relative_path = ?
40
- UNION ALL
41
- SELECT
42
- d.id AS documentId,
43
- gs.id AS symbolId,
44
- gs.symbol,
45
- d.relative_path AS relativePath,
46
- MIN(c.start_line) AS startLine,
47
- MAX(c.end_line) AS endLine,
48
- COALESCE(gs.display_name, '') AS leaf,
49
- NULL AS parentTypeName,
50
- CASE WHEN gs.kind IN (6, 12, 13) OR gs.symbol LIKE '%().' THEN 1 ELSE 0 END AS isFunctionLike,
51
- CASE WHEN gs.kind IN (5, 8, 11) THEN 1 ELSE 0 END AS isTypeLike,
52
- gs.kind AS kind,
53
- gs.documentation AS documentation,
54
- gs.enclosing_symbol AS enclosingSymbol
55
- FROM global_symbols gs
56
- JOIN mentions m ON m.symbol_id = gs.id
57
- JOIN chunks c ON c.id = m.chunk_id
58
- JOIN documents d ON d.id = c.document_id
59
- WHERE d.relative_path = ?
60
- AND m.role = 1
61
- GROUP BY gs.id, gs.symbol, d.id, d.relative_path, gs.display_name, gs.kind, gs.documentation, gs.enclosing_symbol
62
- ORDER BY startLine, endLine`,e,e),n=new Set,r=new Map;for(let o of t){if(n.has(o.symbolId))continue;n.add(o.symbolId);let s=o.leaf||N(o.symbol);!s||r.has(s)||r.set(s,{...o,leaf:s})}return r}import pe from"path";var S=[".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"];function D(i){let e=i.toLowerCase();return S.some(t=>e.endsWith(t))}function K(i,e){let t=new Map,n=r=>D(r)?p(t,r,()=>{let o=pe.join(i.config.projectRoot,r);for(let{project:s}of e){let a=s.getSourceFile(o)??s.addSourceFileAtPathIfExists(o)??null;if(a)return{project:s,sourceFile:a}}return null}):null;return{sourceFile:r=>n(r)?.sourceFile??null,sourceFileMatch:n,indexedTypeScriptLikeDocuments:()=>x(i,{extensions:S})}}import m from"path";import{existsSync as M,readdirSync as fe,readFileSync as z}from"fs";function Y(i){let e=m.join(i,"package.json");if(!M(e))return[];let t;try{t=JSON.parse(z(e,"utf8"))}catch{return[]}return(Array.isArray(t.workspaces)?t.workspaces:t.workspaces?.packages??[]).flatMap(r=>ue(i,r)).flatMap(r=>me(i,r))}function ue(i,e){if(!e||e.startsWith("!")||e.includes("node_modules"))return[];if(!e.includes("*")){let s=m.join(i,e);return M(m.join(s,"package.json"))?[s]:[]}let t=e.indexOf("*"),n=e.slice(0,t).replace(/\/$/,""),r=e.slice(t+1).replace(/^\//,""),o=m.join(i,n||".");if(!M(o))return[];try{return fe(o).map(s=>m.join(o,s,r)).filter(s=>M(m.join(s,"package.json")))}catch{return[]}}function me(i,e){try{let t=JSON.parse(z(m.join(e,"package.json"),"utf8"));if(!t.name)return[];let n=m.relative(i,e).replace(/\\/g,"/");return[{name:t.name,rootRelative:n,sourceRootRelative:`${n}/src`}]}catch{return[]}}function X(i,e){for(let t of i)if(e===t.name||e.startsWith(`${t.name}/`))return t.name;return null}function q(i){return[`${i.sourceRootRelative}/index.ts`,`${i.sourceRootRelative}/index.tsx`,`${i.sourceRootRelative}/index.mts`,`${i.sourceRootRelative}/index.cts`]}import{existsSync as h,readFileSync as ge,readdirSync as ye,statSync as Se}from"fs";import d from"path";var R=["tsconfig.json","tsconfig.app.json","tsconfig.node.json","tsconfig.base.json"];function C(i,e){let n=e?d.dirname(d.join(i,e)):i,r=d.resolve(i);for(;n.startsWith(r);){for(let s of R){let a=d.join(n,s);if(h(a))return a}let o=d.dirname(n);if(o===n)break;n=o}for(let o of R){let s=d.join(i,o);if(h(s))return s}return null}function G(i){let e=i.config.projectRoot,t=new Set(he(e,i.config.semantic?.typescript?.tsconfigs)),n=x(i,{includeIgnored:!1,extensions:S});for(let r of n){let o=C(e,r);o&&t.add(d.resolve(o))}if(t.size===0){let r=C(e);r&&t.add(d.resolve(r))}return[...t].filter(r=>!Q(e,r)).sort((r,o)=>r.localeCompare(o))}function he(i,e=[]){let t=new Set;for(let n of e){let r=d.isAbsolute(n)?n:d.join(i,n);h(r)&&t.add(d.resolve(r))}for(let n of be(i))for(let r of R){let o=d.join(n,r);h(o)&&t.add(d.resolve(o))}if(t.size===0){let n=C(i);n&&t.add(d.resolve(n))}return[...t].filter(n=>!Q(i,n)).sort((n,r)=>n.localeCompare(r))}function be(i){let e=d.join(i,"package.json");if(!h(e))return[];let t;try{t=JSON.parse(ge(e,"utf8"))}catch{return[]}return(Array.isArray(t.workspaces)?t.workspaces:t.workspaces?.packages??[]).flatMap(r=>Ie(i,r))}function Ie(i,e){if(!e||e.startsWith("!")||e.includes("node_modules"))return[];if(!e.includes("*")){let s=d.join(i,e);return L(s)?[s]:[]}let t=e.indexOf("*"),n=e.slice(0,t).replace(/\/$/,""),r=e.slice(t+1).replace(/^\//,""),o=d.join(i,n||".");return L(o)?ye(o).map(s=>d.join(o,s,r)).filter(L):[]}function L(i){try{return Se(i).isDirectory()}catch{return!1}}function Q(i,e){let t=d.relative(i,e).replace(/\\/g,"/");return t.startsWith("..")||t.includes("/node_modules/")||t.startsWith("node_modules/")||t.includes("/dist/")||t.startsWith("dist/")}import{createRequire as xe}from"module";var Ne=xe(import.meta.url),b;function Z(){if(b!==void 0)return b;try{b=Ne("ts-morph")}catch{b=null}return b}function ee(i,e){return e.map(t=>({tsconfigPath:t,project:new i.Project({tsConfigFilePath:t,skipFileDependencyResolution:!1})}))}function F(i,e,t){return{language:"typescript",availability:()=>({available:!1,reason:i,tsconfigPath:e,tsconfigPaths:t}),importUsage:()=>[],referencesFor:()=>[],calleesFor:()=>[],signatureFor:()=>null}}function ie(i,e){let t=Z();if(!t)return F("ts-morph is not installed");let n=G(i);if(n.length===0)return F("no tsconfig found");try{let r=ee(t,n);return new A(i,t,r)}catch(r){return F(r instanceof Error?r.message:String(r),n[0],n)}}var A=class{constructor(e,t,n){this.db=e;this.tsMorph=t;this.projects=n;this.workspacePackages=Y(e.config.projectRoot),this.sourceFiles=K(e,n)}db;tsMorph;projects;language="typescript";importUsageCache=new Map;referencesCache=new Map;calleesCache=new Map;fileCalleesCache=new Map;signatureCache=new Map;definitionNodeCache=new Map;fileDefinitionNodeCache=new Map;indexedDefinitionLeafCache=new Map;packageImportReferenceIndex=null;packageExportIndex=null;workspacePackages;sourceFiles;availability(){return{available:!0,tsconfigPath:this.projects[0]?.tsconfigPath,tsconfigPaths:this.projects.map(e=>e.tsconfigPath)}}importUsage(e){return p(this.importUsageCache,e,()=>{let t=this.sourceFiles.sourceFile(e);if(!t)return[];let n=[];for(let r of t.getImportDeclarations())for(let o of this.importUsageForDeclaration(e,r))n.push(o);return n})}referencesFor(e){return p(this.referencesCache,e.symbolId,()=>{let t=this.nodeForDefinition(e),n=this.packageImportReferencesForDefinition(e);return t?U(t,e,n,this.db.config.projectRoot):n})}calleesFor(e){return p(this.calleesCache,e.symbolId,()=>p(this.fileCalleesCache,e.relativePath,()=>this.calleeMapForFile(e.relativePath)).get(e.symbolId)??[])}signatureFor(e){return p(this.signatureCache,e.symbolId,()=>{let t=this.nodeForDefinition(e);if(!t||!this.tsMorph.Node.isFunctionDeclaration(t)&&!this.tsMorph.Node.isMethodDeclaration(t)&&!this.tsMorph.Node.isArrowFunction(t)&&!this.tsMorph.Node.isFunctionExpression(t)&&!this.tsMorph.Node.isConstructorDeclaration(t))return null;let n=t.getType().getCallSignatures()[0];if(!n)return null;let r=n.getParameters().map(s=>{let a=s.getDeclarations()[0],l=a?s.getTypeAtLocation(a).getText(a):s.getValueDeclaration()?.getType().getText()??"unknown";return ne(l)}),o=n.getReturnType().getText(t);return`(${r.join(",")})=>${ne(o)}`})}importUsageForDeclaration(e,t){let n=T(this.db,e,t.getModuleSpecifierValue()),r=te(t);return t.getImportClause()?.isTypeOnly()?r.map(o=>ke(e,n,o)):r.map(o=>this.valueImportUsageForEntry(e,n,o))}valueImportUsageForEntry(e,t,n){let r=n.identifier?n.identifier.findReferences():[],o=[];for(let c of r)for(let f of W(c,e,n.identifier,this.db.config.projectRoot))o.push(f);let s=o.some(c=>!P(c.node)),a=o.some(c=>P(c.node)),l=n.isTypeOnly;return{importer:e,sourcePath:t,importedName:n.importedName,localName:n.localName,kind:n.kind,isTypeOnly:l,isUsed:l||o.length>0,isTypeUsed:l||a,isValueUsed:s,references:o.map(c=>c.location)}}packageImportReferencesForDefinition(e){return this.packageImportReferences().get(e.symbolId)??[]}packageImportReferences(){if(this.packageImportReferenceIndex)return this.packageImportReferenceIndex;let e=new Map,t=this.packageExports();for(let n of this.sourceFiles.indexedTypeScriptLikeDocuments())this.addPackageImportReferencesForDocument(e,t,n);for(let[n,r]of e)e.set(n,E(r));return this.packageImportReferenceIndex=e,e}addPackageImportReferencesForDocument(e,t,n){if(this.db.isIgnored(n))return;let r=this.sourceFiles.sourceFileMatch(n);if(r)for(let o of r.sourceFile.getImportDeclarations())this.addPackageImportReferencesForDeclaration(e,t,n,o)}addPackageImportReferencesForDeclaration(e,t,n,r){let o=X(this.workspacePackages,r.getModuleSpecifierValue());if(!o)return;let s=t.get(o);if(s)for(let a of te(r)){if(a.kind!=="named"||!a.identifier)continue;let l=s.get(a.importedName);if(!l||l.size===0)continue;let c=B(a.identifier,n,this.db.config.projectRoot);c.length>0&&Me(e,l,c)}}packageExports(){if(this.packageExportIndex)return this.packageExportIndex;let e=new Map;for(let t of this.workspacePackages){let n=new Map;for(let r of q(t))this.collectPackageExports(t,r,n,new Set);n.size>0&&e.set(t.name,n)}return this.packageExportIndex=e,e}collectPackageExports(e,t,n,r){if(r.has(t))return;r.add(t);let o=this.sourceFiles.sourceFile(t);if(o)for(let s of o.getExportDeclarations()){let a=s.getModuleSpecifierValue(),l=a?T(this.db,t,a):t;if(!l||!l.startsWith(`${e.sourceRootRelative}/`))continue;let c=s.getNamedExports();if(c.length===0){if(s.isNamespaceExport())continue;this.collectPackageExports(e,l,n,r);continue}for(let f of c){let u=f.getNameNode().getText(),w=f.getAliasNode()?.getText()??u,O=this.indexedDefinitionByLeaf(l,u);if(!O)continue;let I=n.get(w);I||(I=new Set,n.set(w,I)),I.add(O.symbolId)}}}indexedDefinitionByLeaf(e,t){return p(this.indexedDefinitionLeafCache,e,()=>V(this.db,e)).get(t)??null}nodeForDefinition(e){return p(this.definitionNodeCache,e.symbolId,()=>this.definitionNodesForFile(e.relativePath).get(e.symbolId)??null)}definitionNodesForFile(e){return p(this.fileDefinitionNodeCache,e,()=>{let t=this.sourceFiles.sourceFile(e);return t?H(this.tsMorph,this.db,t,e):new Map})}definitionFromSymbol(e){let t=e.getDeclarations();for(let n of t){let r=n.getSourceFile(),o=y(this.db.config.projectRoot,r.getFilePath());if(!o||this.db.isIgnored(o))continue;let s=g(r,n),a=J(this.db,o,s,e.getName());if(a)return{symbol:a.symbol,file:a.relativePath,line:a.startLine}}return null}calleeMapForFile(e){let t=this.sourceFiles.sourceFile(e);if(!t)return new Map;let n=k(this.db,e).sort((o,s)=>o.startLine-s.startLine||s.endLine-o.endLine);if(n.length===0)return new Map;let r=new Map;t.forEachDescendant(o=>{if(!this.tsMorph.Node.isCallExpression(o)&&!this.tsMorph.Node.isNewExpression(o))return;let s=this.semanticCalleeForCallNode(t,n,o);s&&Ee(r,s.callerId,s.target)});for(let[o,s]of r)r.set(o,Fe(s));return r}semanticCalleeForCallNode(e,t,n){let r=De(t,g(e,n));if(!r)return null;let o=n.getExpression(),s=o.getSymbol()??o.getType().getSymbol(),a=s?this.definitionFromSymbol(s):null;return a?{callerId:r.symbolId,target:{symbol:a.symbol,file:a.file,line:a.line}}:null}};function te(i){let e=[],t=i.getDefaultImport();t&&e.push({identifier:t,importedName:"default",localName:t.getText(),kind:"default",isTypeOnly:i.getImportClause()?.isTypeOnly()??!1});let n=i.getNamespaceImport();n&&e.push({identifier:n,importedName:"*",localName:n.getText(),kind:"namespace",isTypeOnly:i.getImportClause()?.isTypeOnly()??!1});for(let r of i.getNamedImports()){let o=r.getNameNode(),a=r.getAliasNode()??(o.getKindName()==="Identifier"?o:null);e.push({identifier:a,importedName:o.getText(),localName:a?.getText()??o.getText(),kind:"named",isTypeOnly:r.isTypeOnly()||(i.getImportClause()?.isTypeOnly()??!1)})}return e.length===0&&e.push({identifier:null,importedName:"*",localName:null,kind:"side-effect",isTypeOnly:!1}),e}function ke(i,e,t){return{importer:i,sourcePath:e,importedName:t.importedName,localName:t.localName,kind:t.kind,isTypeOnly:!0,isUsed:!0,isTypeUsed:!0,isValueUsed:!1,references:[]}}function Ee(i,e,t){let n=i.get(e);n||(n=[],i.set(e,n)),n.push(t)}function De(i,e){let t=null;for(let n of i)e<n.startLine||e>n.endLine||(!t||n.startLine>=t.startLine)&&(t=n);return t}function Me(i,e,t){for(let n of e){let r=i.get(n)??[];r.push(...t),i.set(n,r)}}function Fe(i){let e=new Set,t=[];for(let n of i){let r=`${n.symbol}|${n.file}|${n.line}`;e.has(r)||(e.add(r),t.push(n))}return t}function ne(i){return i.replace(/\s+/g," ").replace(/\bimport\("[^"]+"\)\./g,"").trim()}var j=new WeakMap;function re(i,e){let t=`${i.config.projectRoot}:typescript-workspace`,n=j.get(i);n||(n=new Map,j.set(i,n));let r=n.get(t);if(r)return r;let o=ie(i,e);return n.set(t,o),o}function ft(i){j.delete(i)}function yt(i,e){let t=v(i,e);return t?t.importUsage(e):[]}function ve(i,e){let t=v(i,e.relativePath);return t?t.referencesFor(e):[]}function St(i,e){let t=new Map;for(let n of e)for(let r of ve(i,n)){if(r.file===n.relativePath||i.isIgnored(r.file))continue;let o=t.get(n.symbolId);o||(o=new Set,t.set(n.symbolId,o)),o.add(r.file)}return t}function ht(i,e){let t=new Map;for(let n of e){let r=v(i,n.relativePath);if(!r)continue;let o=r.calleesFor(n);o.length>0&&t.set(n.symbolId,o)}return t}function bt(i,e){let t=v(i,e.relativePath);return t?t.signatureFor(e):null}function v(i,e){if(!D(e))return null;let t=re(i,e);return t.availability().available?t:null}export{ft as a,yt as b,ve as c,St as d,ht as e,bt as f};
63
- //# sourceMappingURL=chunk-5RGK4YA5.js.map