scip-query 0.3.4 → 0.4.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 (154) hide show
  1. package/README.md +2 -26
  2. package/dist/{chunk-FYYOWQXK.js → chunk-2F2WH5WQ.js} +19 -36
  3. package/dist/{chunk-C7H5WBTJ.js → chunk-2UISVZGQ.js} +2 -2
  4. package/dist/{chunk-HLKAFWWJ.js → chunk-4ZT7UGWW.js} +56 -91
  5. package/dist/chunk-5AJJGPZE.js +60 -0
  6. package/dist/chunk-5RKYZSQ6.js +75 -0
  7. package/dist/chunk-7YBLWIXY.js +115 -0
  8. package/dist/{chunk-O7Q7FDUJ.js → chunk-A4GWYETB.js} +2 -2
  9. package/dist/{chunk-CHDJXYBG.js → chunk-A5BGEBM7.js} +2 -2
  10. package/dist/{chunk-KKCHYLVI.js → chunk-A7YY7IDA.js} +2 -2
  11. package/dist/chunk-AS7N27JK.js +115 -0
  12. package/dist/{chunk-F7XU27LU.js → chunk-CQRYLK33.js} +26 -2
  13. package/dist/{chunk-NFS5W3PP.js → chunk-CQUNEJYM.js} +2 -2
  14. package/dist/chunk-D4I3ZMN5.js +38 -0
  15. package/dist/{chunk-J3JSOSUO.js → chunk-E7J7Q7UW.js} +2 -2
  16. package/dist/{chunk-GEXE2T6I.js → chunk-EOHPASDV.js} +22 -14
  17. package/dist/chunk-FVH3Y44U.js +1 -0
  18. package/dist/chunk-GIBETK3W.js +37 -0
  19. package/dist/{chunk-SMDCNPMK.js → chunk-H3FPW5YN.js} +2 -2
  20. package/dist/{chunk-GJDHTTR2.js → chunk-HNURMDF4.js} +32 -17
  21. package/dist/{chunk-7KIMF5PV.js → chunk-HRDPUTIQ.js} +2 -2
  22. package/dist/{chunk-OIDHN6GD.js → chunk-I2JM34UV.js} +146 -5
  23. package/dist/{chunk-EPWLXXBL.js → chunk-IV6NZ426.js} +27 -29
  24. package/dist/{chunk-VT4JBH6L.js → chunk-KDCQJTYW.js} +2 -2
  25. package/dist/{chunk-5OMVSV6E.js → chunk-LOVDB4C6.js} +2 -2
  26. package/dist/chunk-MA3B3IUT.js +75 -0
  27. package/dist/{chunk-26DOJ63W.js → chunk-N2LH3M2P.js} +13 -2
  28. package/dist/chunk-NWCJWA36.js +162 -0
  29. package/dist/{chunk-NG5F43OU.js → chunk-P3VCDYMJ.js} +70 -1
  30. package/dist/{chunk-P3E6L7KW.js → chunk-P42KQKJZ.js} +83 -3
  31. package/dist/{chunk-YDBXNPYU.js → chunk-PGHN5UTM.js} +2 -2
  32. package/dist/{chunk-UGQKAVCD.js → chunk-QCYR4S6T.js} +2 -2
  33. package/dist/chunk-QGCEAVJD.js +2529 -0
  34. package/dist/{chunk-KBOQX573.js → chunk-RIEA5DOB.js} +19 -2
  35. package/dist/{chunk-VIYSWZCO.js → chunk-SL674KAW.js} +31 -3
  36. package/dist/chunk-SRELHCMG.js +110 -0
  37. package/dist/chunk-UTRKBUCB.js +87 -0
  38. package/dist/{chunk-HJZUSUPU.js → chunk-VCOJRQPP.js} +5 -5
  39. package/dist/chunk-VISMEWYP.js +34 -0
  40. package/dist/{chunk-LFJQVJYJ.js → chunk-VU7FDTWV.js} +2 -2
  41. package/dist/{chunk-HLUS2HEB.js → chunk-VUBLUTMU.js} +5 -4
  42. package/dist/{chunk-WGAD3GNR.js → chunk-WNPF2I25.js} +5 -5
  43. package/dist/{chunk-YY4QGUQ5.js → chunk-X3J4VPWM.js} +2 -2
  44. package/dist/{chunk-GSH2FPKV.js → chunk-XH56HXLC.js} +2 -2
  45. package/dist/{chunk-DH7G3DDV.js → chunk-ZU2AQQB5.js} +2 -2
  46. package/dist/cli.js +2722 -1036
  47. package/dist/{db-ShvwGDKf.d.ts → db-C4rPbKkI.d.ts} +7 -14
  48. package/dist/index.d.ts +4 -5
  49. package/dist/index.js +378 -149
  50. package/dist/postinstall.js +9 -3
  51. package/dist/queries/affected.d.ts +1 -1
  52. package/dist/queries/affected.js +2 -2
  53. package/dist/queries/bottlenecks.d.ts +1 -1
  54. package/dist/queries/bottlenecks.js +2 -1
  55. package/dist/queries/by-kind.d.ts +1 -1
  56. package/dist/queries/by-kind.js +2 -1
  57. package/dist/queries/call-graph.d.ts +1 -1
  58. package/dist/queries/call-graph.js +2 -2
  59. package/dist/queries/change-surface.d.ts +1 -1
  60. package/dist/queries/change-surface.js +2 -2
  61. package/dist/queries/code.d.ts +1 -1
  62. package/dist/queries/code.js +2 -2
  63. package/dist/queries/complexity-hotspots.d.ts +1 -1
  64. package/dist/queries/complexity-hotspots.js +2 -2
  65. package/dist/queries/complexity.d.ts +1 -1
  66. package/dist/queries/complexity.js +2 -2
  67. package/dist/queries/convergence.d.ts +1 -1
  68. package/dist/queries/convergence.js +2 -2
  69. package/dist/queries/coupling.d.ts +1 -1
  70. package/dist/queries/coupling.js +2 -2
  71. package/dist/queries/cycles.d.ts +1 -1
  72. package/dist/queries/cycles.js +2 -2
  73. package/dist/queries/dataflow.d.ts +1 -1
  74. package/dist/queries/dataflow.js +2 -2
  75. package/dist/queries/dead.d.ts +1 -1
  76. package/dist/queries/dead.js +3 -3
  77. package/dist/queries/deep-chains.d.ts +1 -1
  78. package/dist/queries/deep-chains.js +2 -2
  79. package/dist/queries/deps.d.ts +1 -1
  80. package/dist/queries/deps.js +2 -2
  81. package/dist/queries/diff-impact.d.ts +1 -1
  82. package/dist/queries/drift.d.ts +1 -1
  83. package/dist/queries/drift.js +2 -2
  84. package/dist/queries/extract-candidates.d.ts +1 -1
  85. package/dist/queries/extract-candidates.js +2 -2
  86. package/dist/queries/fan.d.ts +1 -1
  87. package/dist/queries/fan.js +2 -2
  88. package/dist/queries/files.d.ts +1 -1
  89. package/dist/queries/health.d.ts +1 -1
  90. package/dist/queries/health.js +13 -13
  91. package/dist/queries/hierarchy.d.ts +1 -1
  92. package/dist/queries/hierarchy.js +2 -2
  93. package/dist/queries/hotspots.d.ts +1 -1
  94. package/dist/queries/hotspots.js +2 -1
  95. package/dist/queries/imports.d.ts +1 -1
  96. package/dist/queries/imports.js +2 -2
  97. package/dist/queries/index.d.ts +1 -2
  98. package/dist/queries/index.js +49 -53
  99. package/dist/queries/isolated.d.ts +3 -4
  100. package/dist/queries/isolated.js +3 -3
  101. package/dist/queries/members.d.ts +1 -1
  102. package/dist/queries/members.js +2 -2
  103. package/dist/queries/methods.d.ts +1 -1
  104. package/dist/queries/methods.js +2 -1
  105. package/dist/queries/outline.d.ts +1 -1
  106. package/dist/queries/outline.js +2 -2
  107. package/dist/queries/passthrough-candidates.d.ts +1 -1
  108. package/dist/queries/passthrough-candidates.js +2 -2
  109. package/dist/queries/redundant-reexports.d.ts +1 -1
  110. package/dist/queries/redundant-reexports.js +3 -3
  111. package/dist/queries/refs.d.ts +1 -1
  112. package/dist/queries/refs.js +2 -2
  113. package/dist/queries/similar-chains.d.ts +1 -1
  114. package/dist/queries/similar-chains.js +2 -2
  115. package/dist/queries/similar-files.d.ts +1 -1
  116. package/dist/queries/similar-files.js +2 -2
  117. package/dist/queries/similar-signatures.d.ts +5 -3
  118. package/dist/queries/similar-signatures.js +2 -1
  119. package/dist/queries/similar.d.ts +1 -1
  120. package/dist/queries/similar.js +2 -2
  121. package/dist/queries/slice.d.ts +1 -1
  122. package/dist/queries/slice.js +2 -2
  123. package/dist/queries/stale-abstractions.d.ts +1 -1
  124. package/dist/queries/stale-abstractions.js +2 -2
  125. package/dist/queries/stats.d.ts +1 -1
  126. package/dist/queries/surface.d.ts +1 -1
  127. package/dist/queries/surface.js +2 -2
  128. package/dist/queries/symbols.d.ts +1 -1
  129. package/dist/queries/symbols.js +2 -2
  130. package/dist/queries/system.d.ts +1 -1
  131. package/dist/queries/system.js +2 -2
  132. package/dist/queries/trace.d.ts +1 -1
  133. package/dist/queries/trace.js +2 -2
  134. package/dist/queries/wrapper-candidates.d.ts +1 -1
  135. package/dist/queries/wrapper-candidates.js +2 -2
  136. package/dist/reindex-worker.js +213 -62
  137. package/package.json +1 -1
  138. package/skills/scip-language-playbook/SKILL.md +371 -0
  139. package/dist/chunk-2UELLEBI.js +0 -1
  140. package/dist/chunk-4JCSOF2O.js +0 -97
  141. package/dist/chunk-AXQKUYKF.js +0 -1442
  142. package/dist/chunk-CPVAQJEC.js +0 -46
  143. package/dist/chunk-EOROMIFO.js +0 -41
  144. package/dist/chunk-GU2H5QRN.js +0 -28
  145. package/dist/chunk-LQJUPXQY.js +0 -109
  146. package/dist/chunk-MPGIHELS.js +0 -39
  147. package/dist/chunk-P4WO3BBW.js +0 -64
  148. package/dist/chunk-TOIEB3LG.js +0 -78
  149. package/dist/chunk-UQEQ6AHX.js +0 -60
  150. package/dist/chunk-VJJKSGIX.js +0 -121
  151. package/dist/chunk-YZ6L7GFO.js +0 -73
  152. package/dist/chunk-ZEUCXQBN.js +0 -71
  153. package/dist/queries/doc-coverage.d.ts +0 -14
  154. package/dist/queries/doc-coverage.js +0 -8
package/README.md CHANGED
@@ -19,6 +19,7 @@ For goal-oriented usage guides (not just command reference), see **[Agent Guide]
19
19
  ```bash
20
20
  # Install
21
21
  npm install -g scip-query
22
+ scip-query install-skills # installs built-in Codex/Claude skills, including scip-language-playbook
22
23
 
23
24
  # Index your project (auto-detects language)
24
25
  scip-query reindex
@@ -487,31 +488,6 @@ scip-query isolated --scope src/utils
487
488
 
488
489
  ---
489
490
 
490
- #### `doc-coverage`
491
-
492
- Check what percentage of symbols have documentation strings. Lists undocumented symbols.
493
-
494
- ```bash
495
- scip-query doc-coverage --min-loc 5
496
- # Documentation coverage: 78%
497
- # Total symbols: 122
498
- # Documented: 95
499
- # Undocumented: 27
500
- #
501
- # Undocumented:
502
- # src/utils/format.ts:15 formatCurrency
503
- # src/utils/format.ts:28 formatDate
504
- ```
505
-
506
- **Options:**
507
- - `-s, --scope <path>` — Limit to files matching path
508
- - `--min-loc <n>` — Minimum LOC to consider (default: 3)
509
- - `-n, --limit <n>` — Max undocumented symbols to show (default: 50)
510
-
511
- **Value:** Documentation health check. Focus efforts on the undocumented list.
512
-
513
- ---
514
-
515
491
  ### Codebase Metrics
516
492
 
517
493
  These commands measure structural properties of the codebase — hotspots, coupling, bottlenecks, fan-in/out.
@@ -1148,7 +1124,7 @@ scip-query similar-signatures --min-loc 5
1148
1124
 
1149
1125
  ## Programmatic API
1150
1126
 
1151
- All 50 commands are available as TypeScript functions:
1127
+ All 49 commands are available as TypeScript functions:
1152
1128
 
1153
1129
  ```typescript
1154
1130
  import {
@@ -1,39 +1,39 @@
1
- import {
2
- staleAbstractions
3
- } from "./chunk-P4WO3BBW.js";
4
1
  import {
5
2
  stats
6
3
  } from "./chunk-74RFWB5T.js";
7
4
  import {
8
5
  wrapperCandidates
9
- } from "./chunk-4JCSOF2O.js";
10
- import {
11
- passthroughCandidates
12
- } from "./chunk-ZEUCXQBN.js";
6
+ } from "./chunk-AS7N27JK.js";
13
7
  import {
14
8
  similarAll
15
- } from "./chunk-OIDHN6GD.js";
9
+ } from "./chunk-I2JM34UV.js";
10
+ import {
11
+ staleAbstractions
12
+ } from "./chunk-5RKYZSQ6.js";
16
13
  import {
17
14
  isolated
18
- } from "./chunk-UQEQ6AHX.js";
15
+ } from "./chunk-VISMEWYP.js";
16
+ import {
17
+ passthroughCandidates
18
+ } from "./chunk-5AJJGPZE.js";
19
19
  import {
20
20
  drift
21
- } from "./chunk-7KIMF5PV.js";
21
+ } from "./chunk-HRDPUTIQ.js";
22
22
  import {
23
23
  extractCandidates
24
- } from "./chunk-EPWLXXBL.js";
24
+ } from "./chunk-IV6NZ426.js";
25
25
  import {
26
26
  complexityHotspots
27
- } from "./chunk-VIYSWZCO.js";
27
+ } from "./chunk-SL674KAW.js";
28
28
  import {
29
29
  cycles
30
- } from "./chunk-LFJQVJYJ.js";
30
+ } from "./chunk-VU7FDTWV.js";
31
31
  import {
32
32
  dead
33
- } from "./chunk-LQJUPXQY.js";
33
+ } from "./chunk-SRELHCMG.js";
34
34
  import {
35
35
  isEntrySurface
36
- } from "./chunk-YY4QGUQ5.js";
36
+ } from "./chunk-X3J4VPWM.js";
37
37
 
38
38
  // src/queries/health.ts
39
39
  function health(db, opts = {}) {
@@ -57,20 +57,7 @@ function health(db, opts = {}) {
57
57
  const trueIsolatedCount = isolatedResult.filter(
58
58
  (s2) => !isEntrySurface(db, s2.relativePath)
59
59
  ).length;
60
- const filesWithFunctions = new Set(
61
- db.all(
62
- `SELECT DISTINCT d.relative_path
63
- FROM global_symbols gs
64
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
65
- JOIN documents d ON der.document_id = d.id
66
- WHERE gs.symbol LIKE '%().'
67
- ${db.pathExclusionsFor("d")}`
68
- ).map((r) => r.relative_path)
69
- );
70
- const trueStaleCount = staleResult.filter((s2) => {
71
- if (s2.consumers === 0 && filesWithFunctions.has(s2.file)) return false;
72
- return true;
73
- }).length;
60
+ const trueStaleCount = staleResult.length;
74
61
  const trueDriftCount = driftResult.results.length;
75
62
  const trueSimilarCount = similarResult.length;
76
63
  const actions = [];
@@ -145,11 +132,7 @@ function health(db, opts = {}) {
145
132
  });
146
133
  }
147
134
  if (trueStaleCount > 0) {
148
- const trueStaleSymbols = staleResult.filter((s2) => {
149
- if (s2.consumers === 0 && filesWithFunctions.has(s2.file)) return false;
150
- return true;
151
- });
152
- const unused = trueStaleSymbols.filter((s2) => s2.consumers === 0).length;
135
+ const unused = staleResult.filter((s2) => s2.consumers === 0).length;
153
136
  const singleUse = trueStaleCount - unused;
154
137
  const parts = [];
155
138
  if (unused > 0) parts.push(`${unused} unused`);
@@ -160,7 +143,7 @@ function health(db, opts = {}) {
160
143
  effort: "low",
161
144
  impact: "medium",
162
145
  count: trueStaleCount,
163
- locRecoverable: staleResult.filter((s2) => s2.consumers === 0 || !s2.file.includes("types")).reduce((sum, r) => sum + r.loc, 0)
146
+ locRecoverable: staleResult.reduce((sum, r) => sum + r.loc, 0)
164
147
  });
165
148
  }
166
149
  if (trueDriftCount > 0) {
@@ -235,4 +218,4 @@ function health(db, opts = {}) {
235
218
  export {
236
219
  health
237
220
  };
238
- //# sourceMappingURL=chunk-FYYOWQXK.js.map
221
+ //# sourceMappingURL=chunk-2F2WH5WQ.js.map
@@ -2,7 +2,7 @@ import {
2
2
  findFirstSymbolMatch,
3
3
  getCalleeRowsForSymbol,
4
4
  getCallerRowsForSymbol
5
- } from "./chunk-AXQKUYKF.js";
5
+ } from "./chunk-QGCEAVJD.js";
6
6
  import {
7
7
  shortenSymbol
8
8
  } from "./chunk-QIXNAB5K.js";
@@ -43,4 +43,4 @@ function uniqueRows(rows) {
43
43
  export {
44
44
  callGraph
45
45
  };
46
- //# sourceMappingURL=chunk-C7H5WBTJ.js.map
46
+ //# sourceMappingURL=chunk-2UISVZGQ.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ getAllDefinitions
3
+ } from "./chunk-QGCEAVJD.js";
1
4
  import {
2
5
  leafSuffix,
3
6
  parseSymbol,
@@ -115,102 +118,26 @@ function byKind(db, kindQuery, opts = {}) {
115
118
  if (kindNum === null) {
116
119
  return [];
117
120
  }
118
- const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
119
- const hasKinds = db.get(
120
- `SELECT COUNT(*) AS c FROM global_symbols WHERE kind IS NOT NULL`
121
- );
122
- if (!hasKinds || hasKinds.c === 0) {
123
- return inferByKind(db, kindNum, scope, limit);
124
- }
125
- const rows = db.all(
126
- `SELECT gs.symbol, gs.kind, d.relative_path, der.start_line, der.end_line
127
- FROM global_symbols gs
128
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
129
- JOIN documents d ON der.document_id = d.id
130
- WHERE gs.kind = ?
131
- ${db.pathExclusionsFor("d")}
132
- ${scopeFilter}
133
- ORDER BY d.relative_path, der.start_line
134
- LIMIT ?`,
135
- kindNum,
136
- limit
137
- );
138
- return rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
139
- symbol: r.symbol,
140
- shortName: shortenSymbol(r.symbol),
141
- kind: r.kind,
142
- kindName: KIND_NAMES[r.kind] ?? "Unknown",
143
- relativePath: r.relative_path,
144
- startLine: r.start_line,
145
- endLine: r.end_line
146
- }));
147
- }
148
- function kindCounts(db, opts = {}) {
149
- const scopeFilter = opts.scope ? `AND d.relative_path LIKE '%${opts.scope}%'` : "";
150
- const rows = db.all(
151
- `SELECT gs.kind, COUNT(*) AS cnt
152
- FROM global_symbols gs
153
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
154
- JOIN documents d ON der.document_id = d.id
155
- WHERE 1 = 1
156
- ${db.pathExclusionsFor("d")}
157
- AND gs.kind IS NOT NULL
158
- AND gs.kind != 0
159
- ${scopeFilter}
160
- GROUP BY gs.kind
161
- ORDER BY cnt DESC`
162
- );
163
- if (rows.length === 0) {
164
- return inferKindCounts(db, opts.scope);
165
- }
166
- return rows.map((r) => ({
167
- kind: r.kind,
168
- kindName: KIND_NAMES[r.kind] ?? "Unknown",
169
- count: r.cnt
170
- }));
171
- }
172
- function inferByKind(db, kindNum, scope, limit = 100) {
173
- const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
174
- const rows = db.all(
175
- `SELECT gs.symbol, d.relative_path, der.start_line, der.end_line, gs.documentation, gs.enclosing_symbol
176
- FROM global_symbols gs
177
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
178
- JOIN documents d ON der.document_id = d.id
179
- WHERE 1 = 1
180
- ${db.pathExclusionsFor("d")}
181
- ${scopeFilter}
182
- ORDER BY d.relative_path, der.start_line`
183
- );
184
- return rows.filter((row) => !db.isIgnored(row.relative_path)).map((row) => ({
121
+ const rows = loadKindRows(db, scope).map((row) => ({
185
122
  row,
186
- inferredKind: inferKindNumber(row.symbol, row.documentation, row.enclosing_symbol)
187
- })).filter((entry) => entry.inferredKind === kindNum).slice(0, limit).map(({ row, inferredKind }) => ({
123
+ resolvedKind: resolveKindNumber(row)
124
+ })).filter((entry) => entry.resolvedKind === kindNum).slice(0, limit);
125
+ return rows.map(({ row, resolvedKind }) => ({
188
126
  symbol: row.symbol,
189
127
  shortName: shortenSymbol(row.symbol),
190
- kind: inferredKind,
191
- kindName: KIND_NAMES[inferredKind] ?? "Unknown",
128
+ kind: resolvedKind,
129
+ kindName: KIND_NAMES[resolvedKind] ?? "Unknown",
192
130
  relativePath: row.relative_path,
193
131
  startLine: row.start_line,
194
132
  endLine: row.end_line
195
133
  }));
196
134
  }
197
- function inferKindCounts(db, scope) {
198
- const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
199
- const rows = db.all(
200
- `SELECT gs.symbol, gs.documentation, gs.enclosing_symbol, d.relative_path
201
- FROM global_symbols gs
202
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
203
- JOIN documents d ON der.document_id = d.id
204
- WHERE 1 = 1
205
- ${db.pathExclusionsFor("d")}
206
- ${scopeFilter}`
207
- );
135
+ function kindCounts(db, opts = {}) {
208
136
  const counts = /* @__PURE__ */ new Map();
209
- for (const row of rows) {
210
- if (db.isIgnored(row.relative_path)) continue;
211
- const inferred = inferKindNumber(row.symbol, row.documentation, row.enclosing_symbol);
212
- if (inferred === null || inferred === 0) continue;
213
- counts.set(inferred, (counts.get(inferred) ?? 0) + 1);
137
+ for (const row of loadKindRows(db, opts.scope)) {
138
+ const kind = resolveKindNumber(row);
139
+ if (kind === null || kind === 0) continue;
140
+ counts.set(kind, (counts.get(kind) ?? 0) + 1);
214
141
  }
215
142
  return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0] - b[0]).map(([kind, count]) => ({
216
143
  kind,
@@ -218,22 +145,60 @@ function inferKindCounts(db, scope) {
218
145
  count
219
146
  }));
220
147
  }
148
+ function loadKindRows(db, scope) {
149
+ return getAllDefinitions(db, { scope }).map(mapDefinitionToKindRow);
150
+ }
151
+ function mapDefinitionToKindRow(definition) {
152
+ return {
153
+ symbol: definition.symbol,
154
+ kind: definition.kind,
155
+ documentation: definition.documentation,
156
+ enclosing_symbol: definition.enclosingSymbol,
157
+ relative_path: definition.relativePath,
158
+ start_line: definition.startLine,
159
+ end_line: definition.endLine
160
+ };
161
+ }
162
+ function resolveKindNumber(row) {
163
+ if (row.kind !== null && row.kind !== 0) {
164
+ return normalizeIndexedKind(row.kind, row.symbol, row.documentation);
165
+ }
166
+ return inferKindNumber(row.symbol, row.documentation, row.enclosing_symbol);
167
+ }
168
+ function normalizeIndexedKind(kind, symbol, documentation) {
169
+ const signature = (documentation ?? "").toLowerCase();
170
+ const suffix = leafSuffix(symbol);
171
+ if (suffix === "type") {
172
+ if (signature.includes("type ")) return 76;
173
+ if (signature.includes("interface ")) return 27;
174
+ if (signature.includes("struct ")) return 68;
175
+ if (signature.includes("trait ")) return 73;
176
+ if (signature.includes("class ")) return 9;
177
+ }
178
+ return kind;
179
+ }
221
180
  function inferKindNumber(symbol, documentation, enclosingSymbol) {
222
181
  const parsed = parseSymbol(symbol);
223
182
  if ("kind" in parsed) {
224
183
  return null;
225
184
  }
226
185
  const descriptors = parsed.descriptors;
227
- const last = descriptors[descriptors.length - 1] ?? null;
228
186
  const parent = descriptors[descriptors.length - 2] ?? null;
229
187
  const suffix = leafSuffix(symbol);
230
- if (suffix === "type") return 9;
188
+ const signature = (documentation ?? "").toLowerCase();
189
+ if (suffix === "type") {
190
+ if (signature.includes("type ")) return 76;
191
+ if (signature.includes("interface ")) return 27;
192
+ if (signature.includes("struct ")) return 68;
193
+ if (signature.includes("trait ")) return 73;
194
+ if (signature.includes("class ")) return 9;
195
+ return 9;
196
+ }
231
197
  if (suffix === "method") {
232
198
  return parent?.suffix === "type" ? 33 : 23;
233
199
  }
234
200
  if (suffix === "namespace") return 39;
235
201
  if (suffix !== "term") return null;
236
- const signature = (documentation ?? "").toLowerCase();
237
202
  if (signature.includes("async def ") || signature.includes("def ")) {
238
203
  return 23;
239
204
  }
@@ -248,4 +213,4 @@ export {
248
213
  byKind,
249
214
  kindCounts
250
215
  };
251
- //# sourceMappingURL=chunk-HLKAFWWJ.js.map
216
+ //# sourceMappingURL=chunk-4ZT7UGWW.js.map
@@ -0,0 +1,60 @@
1
+ import {
2
+ getCalleeRowsForSymbol,
3
+ getDefinitionsForFile
4
+ } from "./chunk-QGCEAVJD.js";
5
+ import {
6
+ isFunctionLikeSymbol,
7
+ shortenSymbol
8
+ } from "./chunk-QIXNAB5K.js";
9
+
10
+ // src/queries/passthrough-candidates.ts
11
+ function passthroughCandidates(db, opts) {
12
+ const { scope, maxLoc = 15, limit = 30 } = opts ?? {};
13
+ const symbols = getScopedDefinitions(db, scope).filter((definition) => definitionLoc(definition) >= 3 && definitionLoc(definition) <= maxLoc);
14
+ const results = [];
15
+ for (const sym of symbols) {
16
+ if (db.isIgnored(sym.relativePath) || !isFunctionLikeSymbol(sym.symbol)) continue;
17
+ const rawCallees = getCalleeRowsForSymbol(db, sym);
18
+ const callees = rawCallees.some((callee2) => isFunctionLikeSymbol(callee2.symbol)) ? rawCallees.filter((callee2) => isFunctionLikeSymbol(callee2.symbol)) : rawCallees;
19
+ const uniqueCallees = /* @__PURE__ */ new Map();
20
+ for (const c of callees) {
21
+ if (!uniqueCallees.has(c.symbol)) {
22
+ uniqueCallees.set(c.symbol, { symbol: c.symbol, file: c.file });
23
+ }
24
+ }
25
+ if (uniqueCallees.size !== 1) continue;
26
+ const [, callee] = [...uniqueCallees.entries()][0];
27
+ results.push({
28
+ symbol: sym.symbol,
29
+ shortName: shortenSymbol(sym.symbol),
30
+ file: sym.relativePath,
31
+ startLine: sym.startLine,
32
+ endLine: sym.endLine,
33
+ loc: definitionLoc(sym),
34
+ forwardsTo: callee.symbol,
35
+ forwardsToShort: shortenSymbol(callee.symbol),
36
+ forwardsToFile: callee.file
37
+ });
38
+ }
39
+ results.sort((a, b) => a.loc - b.loc || a.file.localeCompare(b.file));
40
+ return results.slice(0, limit);
41
+ }
42
+ function getScopedDefinitions(db, scope) {
43
+ const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
44
+ return db.all(
45
+ `SELECT relative_path
46
+ FROM documents
47
+ WHERE 1 = 1
48
+ ${db.pathExclusionsFor("documents")}
49
+ ${scopeFilter}
50
+ ORDER BY relative_path`
51
+ ).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
52
+ }
53
+ function definitionLoc(definition) {
54
+ return definition.endLine - definition.startLine + 1;
55
+ }
56
+
57
+ export {
58
+ passthroughCandidates
59
+ };
60
+ //# sourceMappingURL=chunk-5AJJGPZE.js.map
@@ -0,0 +1,75 @@
1
+ import {
2
+ getDefinitionsForFile
3
+ } from "./chunk-QGCEAVJD.js";
4
+ import {
5
+ shortenSymbol
6
+ } from "./chunk-QIXNAB5K.js";
7
+
8
+ // src/queries/stale-abstractions.ts
9
+ function staleAbstractions(db, opts) {
10
+ const { scope, minLoc = 3, limit = 30 } = opts ?? {};
11
+ const rows = getScopedDefinitions(db, scope).filter((definition) => definition.isTypeLike && definitionLoc(definition) >= minLoc).map((definition) => ({
12
+ symbol: definition.symbol,
13
+ file: definition.relativePath,
14
+ start_line: definition.startLine,
15
+ end_line: definition.endLine,
16
+ loc: definitionLoc(definition),
17
+ consumers: countCrossFileConsumers(db, definition)
18
+ })).filter((row) => row.consumers <= 1).sort((left, right) => right.loc - left.loc || left.file.localeCompare(right.file) || left.start_line - right.start_line);
19
+ const filesWithFunctions = getFilesWithFunctions(db, scope);
20
+ return rows.filter((r) => !db.isIgnored(r.file)).filter((r) => isTrueStaleAbstraction(r, filesWithFunctions)).map((r) => ({
21
+ symbol: r.symbol,
22
+ shortName: shortenSymbol(r.symbol),
23
+ file: r.file,
24
+ startLine: r.start_line,
25
+ endLine: r.end_line,
26
+ loc: r.loc,
27
+ consumers: r.consumers
28
+ })).slice(0, limit);
29
+ }
30
+ function getFilesWithFunctions(db, scope) {
31
+ return new Set(getScopedDefinitions(db, scope).filter((definition) => definition.isFunctionLike).map((definition) => definition.relativePath));
32
+ }
33
+ function isTrueStaleAbstraction(row, filesWithFunctions) {
34
+ const basename = row.file.split("/").pop() ?? "";
35
+ const isTypeFile = basename.includes("types") || row.file.includes("/types/");
36
+ if (isTypeFile && row.consumers > 0) {
37
+ return false;
38
+ }
39
+ if (row.consumers === 0 && filesWithFunctions.has(row.file)) {
40
+ return false;
41
+ }
42
+ return true;
43
+ }
44
+ function getScopedDefinitions(db, scope) {
45
+ const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
46
+ return db.all(
47
+ `SELECT relative_path
48
+ FROM documents
49
+ WHERE 1 = 1
50
+ ${db.pathExclusionsFor("documents")}
51
+ ${scopeFilter}
52
+ ORDER BY relative_path`
53
+ ).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
54
+ }
55
+ function countCrossFileConsumers(db, definition) {
56
+ const callers = db.all(
57
+ `SELECT DISTINCT d.relative_path
58
+ FROM mentions m
59
+ JOIN chunks c ON m.chunk_id = c.id
60
+ JOIN documents d ON c.document_id = d.id
61
+ WHERE m.symbol_id = ?
62
+ AND m.role != 1
63
+ ${db.pathExclusionsFor("d")}`,
64
+ definition.symbolId
65
+ ).map((row) => row.relative_path).filter((relativePath) => relativePath !== definition.relativePath && !db.isIgnored(relativePath));
66
+ return new Set(callers).size;
67
+ }
68
+ function definitionLoc(definition) {
69
+ return definition.endLine - definition.startLine + 1;
70
+ }
71
+
72
+ export {
73
+ staleAbstractions
74
+ };
75
+ //# sourceMappingURL=chunk-5RKYZSQ6.js.map
@@ -0,0 +1,115 @@
1
+ import {
2
+ findFirstSymbolMatch,
3
+ getSourceReferenceSites,
4
+ getSourceText
5
+ } from "./chunk-QGCEAVJD.js";
6
+ import {
7
+ isFunctionLikeSymbol
8
+ } from "./chunk-QIXNAB5K.js";
9
+
10
+ // src/queries/refs.ts
11
+ function refs(db, symbolPattern) {
12
+ const match = findFirstSymbolMatch(db, symbolPattern);
13
+ if (match) {
14
+ const includeDefinitionSite = !isFunctionLikeSymbol(match.symbol);
15
+ const definitionRows = includeDefinitionSite ? [{
16
+ relativePath: match.relativePath,
17
+ line: match.startLine
18
+ }] : [];
19
+ const sourceSites = getSourceReferenceSites(db, match).filter((site) => !db.isIgnored(site.file)).map((site) => ({
20
+ relativePath: site.file,
21
+ line: site.line
22
+ }));
23
+ if (sourceSites.length > 0) {
24
+ const seen2 = /* @__PURE__ */ new Set();
25
+ const rows2 = [...definitionRows, ...sourceSites, ...getRubySemanticRefs(db, match)].filter((site) => {
26
+ const key = `${site.relativePath}:${site.line}`;
27
+ if (seen2.has(key)) return false;
28
+ seen2.add(key);
29
+ return true;
30
+ });
31
+ return rows2;
32
+ }
33
+ }
34
+ const rows = db.all(
35
+ `SELECT DISTINCT d.relative_path, c.start_line
36
+ FROM mentions m
37
+ JOIN chunks c ON m.chunk_id = c.id
38
+ JOIN documents d ON c.document_id = d.id
39
+ JOIN global_symbols gs ON m.symbol_id = gs.id
40
+ WHERE m.symbol_id = ?
41
+ AND ${db.localSymbolPredicate}
42
+ AND m.role != 1
43
+ ORDER BY d.relative_path, c.start_line`,
44
+ match?.symbolId ?? -1
45
+ );
46
+ const referenceRows = rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
47
+ relativePath: r.relative_path,
48
+ line: r.start_line
49
+ }));
50
+ if (!match || db.isIgnored(match.relativePath) || isFunctionLikeSymbol(match.symbol)) {
51
+ return referenceRows;
52
+ }
53
+ const seen = new Set(referenceRows.map((row) => `${row.relativePath}:${row.line}`));
54
+ if (!seen.has(`${match.relativePath}:${match.startLine}`)) {
55
+ referenceRows.unshift({
56
+ relativePath: match.relativePath,
57
+ line: match.startLine
58
+ });
59
+ }
60
+ for (const row of getRubySemanticRefs(db, match)) {
61
+ const key = `${row.relativePath}:${row.line}`;
62
+ if (seen.has(key)) continue;
63
+ seen.add(key);
64
+ referenceRows.push(row);
65
+ }
66
+ return referenceRows;
67
+ }
68
+ function getRubySemanticRefs(db, match) {
69
+ if (!match.relativePath.endsWith(".rb")) {
70
+ return [];
71
+ }
72
+ const tokens = rubyReferenceTokens(match.symbol);
73
+ if (tokens.length === 0) {
74
+ return [];
75
+ }
76
+ const rows = db.all(
77
+ `SELECT relative_path
78
+ FROM documents
79
+ WHERE relative_path LIKE '%.rb'
80
+ ${db.pathExclusionsFor("documents")}
81
+ ORDER BY relative_path`
82
+ );
83
+ const results = [];
84
+ for (const row of rows) {
85
+ if (db.isIgnored(row.relative_path)) continue;
86
+ const source = getSourceText(db, row.relative_path);
87
+ if (!source) continue;
88
+ const lines = source.split("\n");
89
+ for (let index = 0; index < lines.length; index++) {
90
+ const line = lines[index] ?? "";
91
+ if (tokens.some((token) => new RegExp(`@${token}\\b|\\b${token}:`).test(line))) {
92
+ results.push({
93
+ relativePath: row.relative_path,
94
+ line: index
95
+ });
96
+ }
97
+ }
98
+ }
99
+ return results;
100
+ }
101
+ function rubyReferenceTokens(rawSymbol) {
102
+ const leaf = rawSymbol.split(":").pop() ?? rawSymbol;
103
+ const snake = leaf.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9_]+/g, "_").toLowerCase().replace(/^_+|_+$/g, "");
104
+ const parts = snake.split("_").filter(Boolean);
105
+ const candidates = /* @__PURE__ */ new Set();
106
+ if (snake) candidates.add(snake);
107
+ if (parts.length >= 1) candidates.add(parts[parts.length - 1]);
108
+ if (parts.length >= 2) candidates.add(parts.slice(-2).join("_"));
109
+ return [...candidates];
110
+ }
111
+
112
+ export {
113
+ refs
114
+ };
115
+ //# sourceMappingURL=chunk-7YBLWIXY.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-4TYLS5XX.js";
4
4
  import {
5
5
  resolveIndexedPaths
6
- } from "./chunk-AXQKUYKF.js";
6
+ } from "./chunk-QGCEAVJD.js";
7
7
  import {
8
8
  shortenSymbol
9
9
  } from "./chunk-QIXNAB5K.js";
@@ -79,4 +79,4 @@ function system(db, modulePattern) {
79
79
  export {
80
80
  system
81
81
  };
82
- //# sourceMappingURL=chunk-O7Q7FDUJ.js.map
82
+ //# sourceMappingURL=chunk-A4GWYETB.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  findFirstSymbolMatch,
3
3
  getCalleeRowsForSymbol
4
- } from "./chunk-AXQKUYKF.js";
4
+ } from "./chunk-QGCEAVJD.js";
5
5
  import {
6
6
  shortenSymbol
7
7
  } from "./chunk-QIXNAB5K.js";
@@ -97,4 +97,4 @@ function forwardSlice(db, match) {
97
97
  export {
98
98
  slice
99
99
  };
100
- //# sourceMappingURL=chunk-CHDJXYBG.js.map
100
+ //# sourceMappingURL=chunk-A5BGEBM7.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveIndexedFile
3
- } from "./chunk-AXQKUYKF.js";
3
+ } from "./chunk-QGCEAVJD.js";
4
4
 
5
5
  // src/queries/coupling.ts
6
6
  function coupling(db, file1, file2) {
@@ -81,4 +81,4 @@ export {
81
81
  coupling,
82
82
  topCoupling
83
83
  };
84
- //# sourceMappingURL=chunk-KKCHYLVI.js.map
84
+ //# sourceMappingURL=chunk-A7YY7IDA.js.map