@wrongstack/tools 0.319.1 → 1.0.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 (203) hide show
  1. package/dist/_danger-detect.d.ts +8 -0
  2. package/dist/_syntax-check.d.ts +1 -2
  3. package/dist/audit.d.ts +4 -5
  4. package/dist/audit.js +8 -8
  5. package/dist/auto-proceed-loop-guard.js +9 -160
  6. package/dist/bash-kill-guard.d.ts +2 -3
  7. package/dist/bash.d.ts +2 -3
  8. package/dist/bash.js +6 -6
  9. package/dist/batch-tool-use.d.ts +2 -3
  10. package/dist/batch-tool-use.js +1 -1
  11. package/dist/browser/index.d.ts +1 -1
  12. package/dist/browser/index.js +1 -1
  13. package/dist/browser/tools.d.ts +56 -45
  14. package/dist/builtin.js +55 -55
  15. package/dist/{chunk-RJZQWEMS.js → chunk-24T5XIJU.js} +3 -2
  16. package/dist/{chunk-DTQ75VBC.js → chunk-2CTZW6JQ.js} +2 -2
  17. package/dist/chunk-37QKUQ2Z.js +171 -0
  18. package/dist/{chunk-LOBRWKCR.js → chunk-3D5DJWOE.js} +3 -3
  19. package/dist/{chunk-YOKD4GWJ.js → chunk-4ERMPDHV.js} +14 -8
  20. package/dist/{chunk-5EUJF3WC.js → chunk-4WPBS45A.js} +4 -5
  21. package/dist/{chunk-42BHI7TN.js → chunk-5ITQPCLC.js} +2 -2
  22. package/dist/{chunk-B4HTSV6Z.js → chunk-5KS24LTS.js} +11 -11
  23. package/dist/{chunk-QPNYDH5B.js → chunk-62OAECEQ.js} +29 -7
  24. package/dist/{chunk-IYKXK356.js → chunk-6GOZTS6F.js} +4 -4
  25. package/dist/{chunk-OG2BEUBY.js → chunk-7HL23T3T.js} +73 -16
  26. package/dist/{chunk-HFXSNKCV.js → chunk-7JJFC6CT.js} +1 -1
  27. package/dist/{chunk-TTZOK6IY.js → chunk-7N5U2RAU.js} +2 -2
  28. package/dist/{chunk-QBV725YG.js → chunk-7ODZTPCU.js} +2 -2
  29. package/dist/{chunk-OTINMOKK.js → chunk-AB2CAUOP.js} +66 -55
  30. package/dist/{chunk-6AAOT4PW.js → chunk-AQ5YBURX.js} +16 -4
  31. package/dist/{chunk-JDPQOR7C.js → chunk-ASEXQRA7.js} +19 -19
  32. package/dist/{chunk-FRN7TIAA.js → chunk-B3MGJBFI.js} +1 -1
  33. package/dist/{chunk-IWS56OY7.js → chunk-CGXTR34H.js} +63 -4
  34. package/dist/{chunk-IU4DV2PA.js → chunk-CHEK3ASV.js} +6 -3
  35. package/dist/{chunk-GOIZNNOA.js → chunk-DJYLI7EW.js} +1 -1
  36. package/dist/{chunk-CFLJFDYV.js → chunk-DK4J2WMH.js} +14 -11
  37. package/dist/{chunk-ZHH3BEWU.js → chunk-DRRY6SCM.js} +49 -22
  38. package/dist/{chunk-BK732J7I.js → chunk-FBUP524S.js} +4 -4
  39. package/dist/{chunk-WHIIIREL.js → chunk-FVM3O4JQ.js} +7 -3
  40. package/dist/chunk-FYDBUVQD.js +244 -0
  41. package/dist/{chunk-UDVKRX5R.js → chunk-GDDXX27P.js} +50 -50
  42. package/dist/{chunk-O44IMQCN.js → chunk-GKSG5CPH.js} +6 -6
  43. package/dist/{chunk-3PVYQFRQ.js → chunk-HDYUBRMF.js} +5 -3
  44. package/dist/{chunk-ELRRTWNP.js → chunk-IXIS7RSG.js} +2 -2
  45. package/dist/{chunk-X5FOFGXX.js → chunk-IYH4OHBP.js} +6 -6
  46. package/dist/{chunk-MNP3GE7H.js → chunk-JDOO4P6Z.js} +21 -16
  47. package/dist/{chunk-BSJSNVGA.js → chunk-KDEXUQY7.js} +24 -11
  48. package/dist/{chunk-V43EQ6VR.js → chunk-KE7A76VC.js} +3 -2
  49. package/dist/{chunk-2OXHS3KZ.js → chunk-KLJZ4WV4.js} +4 -3
  50. package/dist/{chunk-3M7LLN7W.js → chunk-LQSOU63Z.js} +12 -11
  51. package/dist/{chunk-DC4KMPJO.js → chunk-M6UV67BH.js} +2 -2
  52. package/dist/{chunk-C2DQKVLO.js → chunk-MJSJWXBF.js} +1 -1
  53. package/dist/{chunk-RNWUCZ2U.js → chunk-MK2JK35J.js} +29 -12
  54. package/dist/{chunk-FQZOHLG3.js → chunk-MSOAX3GC.js} +3 -2
  55. package/dist/{chunk-KY4PXYSO.js → chunk-N3K2SFEI.js} +534 -494
  56. package/dist/{chunk-EADULOZV.js → chunk-NJX2RXKJ.js} +50 -7
  57. package/dist/{chunk-AKHYMB4V.js → chunk-NN2SNP2R.js} +6 -6
  58. package/dist/{chunk-CMOUCKGC.js → chunk-NU2IZ72J.js} +6 -6
  59. package/dist/{chunk-RLMX75EM.js → chunk-O6BY43ZB.js} +29 -8
  60. package/dist/{chunk-NKNOBUBU.js → chunk-PVCB7RUZ.js} +2 -2
  61. package/dist/{chunk-UQQS3VNT.js → chunk-QA6IASYX.js} +8 -8
  62. package/dist/{chunk-VPALDFYM.js → chunk-RV7BVTDG.js} +1 -1
  63. package/dist/chunk-S57CDR2H.js +288 -0
  64. package/dist/{chunk-2VSZC6QM.js → chunk-SCMRM6NL.js} +6 -4
  65. package/dist/{chunk-W2CECGTG.js → chunk-SMARDKAC.js} +1 -1
  66. package/dist/{chunk-45JPRMC2.js → chunk-SOR7OCYP.js} +7 -3
  67. package/dist/{chunk-ATSKPZUK.js → chunk-T3SMFF5Q.js} +11 -5
  68. package/dist/{chunk-4BHUSMNL.js → chunk-UI3ZJIG3.js} +1 -1
  69. package/dist/{chunk-WXJY3BKV.js → chunk-VBF2YXUW.js} +2 -2
  70. package/dist/{chunk-FQNXYA6W.js → chunk-VU3QBYL4.js} +36 -5
  71. package/dist/{chunk-IIF5HIVF.js → chunk-VVZPQPTY.js} +2 -2
  72. package/dist/{chunk-VD2LV5WO.js → chunk-VZGPASGD.js} +37 -12
  73. package/dist/{chunk-64VIJPFV.js → chunk-WEEVSWQB.js} +17 -6
  74. package/dist/chunk-XXRMF2BC.js +186 -0
  75. package/dist/{chunk-RTZWBNTY.js → chunk-YEISRT4S.js} +7 -12
  76. package/dist/{chunk-Q5JPPCZC.js → chunk-YJTXRH5Y.js} +3 -2
  77. package/dist/{chunk-GMZYW52L.js → chunk-YULVUTK5.js} +6 -3
  78. package/dist/{chunk-NWZ6XGBJ.js → chunk-ZBMANLYH.js} +5 -3
  79. package/dist/{chunk-DP6CXMJZ.js → chunk-ZTCJCYLN.js} +3 -3
  80. package/dist/circuit-breaker.d.ts +1 -0
  81. package/dist/circuit-breaker.js +1 -1
  82. package/dist/clarify.d.ts +1 -0
  83. package/dist/codebase-index/codebase-ast-replace-tool.d.ts +2 -3
  84. package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +5 -4
  85. package/dist/codebase-index/codebase-incoming-calls-tool.d.ts +4 -3
  86. package/dist/codebase-index/codebase-index-tool.d.ts +2 -3
  87. package/dist/codebase-index/codebase-invariant-check-tool.d.ts +2 -3
  88. package/dist/codebase-index/codebase-outgoing-calls-tool.d.ts +4 -3
  89. package/dist/codebase-index/codebase-repo-map-tool.d.ts +2 -3
  90. package/dist/codebase-index/codebase-search-tool.d.ts +2 -3
  91. package/dist/codebase-index/codebase-skeleton-tool.d.ts +2 -3
  92. package/dist/codebase-index/codebase-stats-tool.d.ts +9 -3
  93. package/dist/codebase-index/codebase-targeted-test-tool.d.ts +4 -3
  94. package/dist/codebase-index/index.d.ts +11 -11
  95. package/dist/codebase-index/index.js +12 -12
  96. package/dist/codebase-index/parser-worker-script.js +3 -3
  97. package/dist/codebase-index/project-server-framing.d.ts +29 -0
  98. package/dist/codebase-index/project-server-lifecycle.d.ts +20 -0
  99. package/dist/codebase-index/project-server-operations.d.ts +37 -0
  100. package/dist/codebase-index/project-server-types.d.ts +30 -0
  101. package/dist/codebase-index/project-server-watcher.d.ts +25 -0
  102. package/dist/codebase-index/project-server.js +451 -394
  103. package/dist/codebase-index/worker.js +5 -5
  104. package/dist/codebase-index/writer-init.d.ts +13 -0
  105. package/dist/codebase-index/writer-maintenance.d.ts +14 -0
  106. package/dist/codebase-index/writer.d.ts +0 -15
  107. package/dist/design.d.ts +2 -2
  108. package/dist/design.js +1 -1
  109. package/dist/diff.d.ts +4 -4
  110. package/dist/diff.js +2 -2
  111. package/dist/document.d.ts +3 -4
  112. package/dist/document.js +1 -1
  113. package/dist/e2e.d.ts +1 -1
  114. package/dist/e2e.js +1 -1
  115. package/dist/edit.d.ts +3 -3
  116. package/dist/edit.js +9 -9
  117. package/dist/exec.d.ts +2 -3
  118. package/dist/exec.js +6 -6
  119. package/dist/fetch.d.ts +4 -3
  120. package/dist/fetch.js +1 -1
  121. package/dist/format.d.ts +17 -45
  122. package/dist/format.js +14 -10
  123. package/dist/git.d.ts +3 -3
  124. package/dist/git.js +1 -1
  125. package/dist/glob.d.ts +2 -3
  126. package/dist/glob.js +3 -3
  127. package/dist/{go-parser-IKHW67WE.js → go-parser-D7ELWQ7F.js} +2 -2
  128. package/dist/grep.d.ts +7 -5
  129. package/dist/grep.js +4 -4
  130. package/dist/index.d.ts +54 -45
  131. package/dist/index.js +122 -63
  132. package/dist/install.d.ts +7 -55
  133. package/dist/install.js +8 -8
  134. package/dist/{json-parser-2EOVP5MR.js → json-parser-34DHYCPW.js} +1 -18
  135. package/dist/json.d.ts +3 -4
  136. package/dist/json.js +2 -2
  137. package/dist/kanban-tool-types.d.ts +1 -2
  138. package/dist/kanban.d.ts +3 -19
  139. package/dist/kanban.js +1 -1
  140. package/dist/languages/execute-tool.d.ts +2 -3
  141. package/dist/languages/index.d.ts +2 -2
  142. package/dist/languages/index.js +6 -6
  143. package/dist/languages/tool.d.ts +3 -4
  144. package/dist/legacy-bridge-YXANP5QB.js +18 -0
  145. package/dist/lint.d.ts +5 -4
  146. package/dist/lint.js +8 -8
  147. package/dist/logs.d.ts +3 -4
  148. package/dist/logs.js +2 -2
  149. package/dist/memory.d.ts +7 -8
  150. package/dist/memory.js +1 -1
  151. package/dist/mode.d.ts +3 -4
  152. package/dist/mode.js +1 -1
  153. package/dist/next-steps-tool.d.ts +2 -3
  154. package/dist/next-steps.d.ts +11 -0
  155. package/dist/next-steps.js +10 -132
  156. package/dist/outdated.d.ts +5 -29
  157. package/dist/outdated.js +4 -4
  158. package/dist/pack.js +56 -56
  159. package/dist/{parser-dispatch-QGC4HSP5.js → parser-dispatch-BDVCJXTV.js} +4 -4
  160. package/dist/patch.d.ts +2 -3
  161. package/dist/patch.js +8 -8
  162. package/dist/plan.d.ts +4 -4
  163. package/dist/plan.js +3 -3
  164. package/dist/process-registry.js +2 -2
  165. package/dist/ps-slash.js +4 -4
  166. package/dist/pwsh.d.ts +1 -0
  167. package/dist/{py-parser-RFWG2HYI.js → py-parser-QC6MR4GB.js} +3 -3
  168. package/dist/read.d.ts +5 -5
  169. package/dist/read.js +8 -8
  170. package/dist/replace.d.ts +2 -3
  171. package/dist/replace.js +10 -10
  172. package/dist/scaffold.d.ts +7 -3
  173. package/dist/scaffold.js +3 -1
  174. package/dist/search.d.ts +17 -3
  175. package/dist/search.js +5 -1
  176. package/dist/set-working-dir.d.ts +2 -3
  177. package/dist/skill.d.ts +4 -5
  178. package/dist/skill.js +1 -1
  179. package/dist/task.d.ts +6 -6
  180. package/dist/task.js +3 -3
  181. package/dist/test.d.ts +5 -4
  182. package/dist/test.js +8 -8
  183. package/dist/todo.d.ts +8 -8
  184. package/dist/todo.js +2 -2
  185. package/dist/tool-diff.js +11 -230
  186. package/dist/tool-help.d.ts +2 -3
  187. package/dist/tool-help.js +1 -1
  188. package/dist/tool-search.d.ts +2 -3
  189. package/dist/tool-search.js +1 -1
  190. package/dist/tool-summary.js +5 -281
  191. package/dist/tool-tier.js +57 -57
  192. package/dist/tool-use.d.ts +2 -3
  193. package/dist/tool-use.js +1 -1
  194. package/dist/tree.d.ts +5 -3
  195. package/dist/tree.js +5 -1
  196. package/dist/typecheck.d.ts +3 -3
  197. package/dist/typecheck.js +8 -8
  198. package/dist/win32.js +1 -1
  199. package/dist/write.d.ts +2 -3
  200. package/dist/write.js +9 -9
  201. package/package.json +5 -5
  202. package/dist/legacy-bridge-3T7SR4SK.js +0 -18
  203. package/dist/spawn-background.d.ts +0 -80
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseFilesContent
3
- } from "./chunk-CMOUCKGC.js";
3
+ } from "./chunk-NU2IZ72J.js";
4
4
  import {
5
5
  INDEXABLE_EXTENSIONS,
6
6
  LANG_FAMILY_ENTRIES,
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-YOHO4DVT.js";
10
10
  import {
11
11
  loadGitignoreMatcher
12
- } from "./chunk-DTQ75VBC.js";
12
+ } from "./chunk-2CTZW6JQ.js";
13
13
 
14
14
  // src/codebase-index/circuit-breaker.ts
15
15
  var CircuitOpenError = class extends Error {
@@ -463,80 +463,6 @@ function runSqliteWithRetry(fn) {
463
463
  throw lastError;
464
464
  }
465
465
 
466
- // src/codebase-index/vector-search.ts
467
- var RRF_K = 60;
468
- function vectorEmbeddingEnabled() {
469
- return process.env["WRONGSTACK_INDEX_VECTORS"] === "1";
470
- }
471
- var VECTOR_DIMENSIONS = 384;
472
- var NGRAM_SIZE = 3;
473
- function embedText(text) {
474
- const vec = new Float32Array(VECTOR_DIMENSIONS);
475
- const normalized = text.toLowerCase().trim();
476
- if (normalized.length === 0) return vec;
477
- const target = normalized.length < NGRAM_SIZE ? ` ${normalized} `.slice(0, Math.max(NGRAM_SIZE, normalized.length + 2)) : normalized;
478
- for (let i = 0; i <= target.length - NGRAM_SIZE; i++) {
479
- const ngram = target.slice(i, i + NGRAM_SIZE);
480
- const bucket = hashNgram(ngram) % VECTOR_DIMENSIONS;
481
- vec[bucket] += 1;
482
- }
483
- let norm = 0;
484
- for (let i = 0; i < VECTOR_DIMENSIONS; i++) {
485
- norm += vec[i] * vec[i];
486
- }
487
- norm = Math.sqrt(norm);
488
- if (norm > 0) {
489
- for (let i = 0; i < VECTOR_DIMENSIONS; i++) {
490
- vec[i] /= norm;
491
- }
492
- }
493
- return vec;
494
- }
495
- function hashNgram(str) {
496
- let hash = 2166136261;
497
- for (let i = 0; i < str.length; i++) {
498
- hash ^= str.charCodeAt(i);
499
- hash = Math.imul(hash, 16777619);
500
- }
501
- return hash >>> 0;
502
- }
503
- function cosineSimilarity(a, b) {
504
- let dot = 0;
505
- const len = Math.min(a.length, b.length);
506
- for (let i = 0; i < len; i++) {
507
- dot += a[i] * b[i];
508
- }
509
- return dot;
510
- }
511
- function encodeVector(vec) {
512
- return Buffer.from(vec.buffer, vec.byteOffset, vec.byteLength);
513
- }
514
- function decodeVector(buf) {
515
- if (buf.byteLength === 0) return new Float32Array(0);
516
- if (buf.byteLength % 4 !== 0) {
517
- throw new Error(
518
- `decodeVector: invalid vector byteLength ${buf.byteLength} (must be a multiple of 4)`
519
- );
520
- }
521
- const copy = new Float32Array(buf.byteLength / 4);
522
- new Uint8Array(copy.buffer).set(buf);
523
- return copy;
524
- }
525
- function reciprocalRankFusion(bm25Ranks, vectorRanks, k = RRF_K) {
526
- const allIds = /* @__PURE__ */ new Set([...bm25Ranks.keys(), ...vectorRanks.keys()]);
527
- const scored = [];
528
- for (const id of allIds) {
529
- const bm25Rank = bm25Ranks.get(id);
530
- const vecRank = vectorRanks.get(id);
531
- let score = 0;
532
- if (bm25Rank !== void 0) score += 1 / (k + bm25Rank);
533
- if (vecRank !== void 0) score += 1 / (k + vecRank);
534
- scored.push([id, score]);
535
- }
536
- scored.sort((a, b) => b[1] - a[1]);
537
- return scored;
538
- }
539
-
540
466
  // src/codebase-index/writer-admin.ts
541
467
  import * as fs from "node:fs";
542
468
  import * as path from "node:path";
@@ -1698,129 +1624,78 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
1698
1624
  return { nodes, edges };
1699
1625
  }
1700
1626
 
1701
- // src/codebase-index/writer-mutations.ts
1702
- function commitBatchWithStatement(stmtFn, maxSqlVars, ftsAvailable, vectorsAvailable, allocateSymbolIds, invalidateIncomingRefsForFiles, resolveRefsForNamesUnsafe2, entries, options = {}) {
1703
- if (entries.length === 0 && (options.deleteForFiles?.length ?? 0) === 0) {
1704
- return [];
1627
+ // src/codebase-index/vector-search.ts
1628
+ var RRF_K = 60;
1629
+ function vectorEmbeddingEnabled() {
1630
+ return process.env["WRONGSTACK_INDEX_VECTORS"] === "1";
1631
+ }
1632
+ var VECTOR_DIMENSIONS = 384;
1633
+ var NGRAM_SIZE = 3;
1634
+ function embedText(text) {
1635
+ const vec = new Float32Array(VECTOR_DIMENSIONS);
1636
+ const normalized = text.toLowerCase().trim();
1637
+ if (normalized.length === 0) return vec;
1638
+ const target = normalized.length < NGRAM_SIZE ? ` ${normalized} `.slice(0, Math.max(NGRAM_SIZE, normalized.length + 2)) : normalized;
1639
+ for (let i = 0; i <= target.length - NGRAM_SIZE; i++) {
1640
+ const ngram = target.slice(i, i + NGRAM_SIZE);
1641
+ const bucket = hashNgram(ngram) % VECTOR_DIMENSIONS;
1642
+ vec[bucket] += 1;
1705
1643
  }
1706
- const affectedNames = /* @__PURE__ */ new Set();
1707
- for (const entry of entries) {
1708
- for (const symbol of entry.symbols) affectedNames.add(symbol.name);
1709
- for (const ref of entry.refs) affectedNames.add(ref.toName);
1644
+ let norm = 0;
1645
+ for (let i = 0; i < VECTOR_DIMENSIONS; i++) {
1646
+ norm += vec[i] * vec[i];
1710
1647
  }
1711
- if (options.deleteForFiles && options.deleteForFiles.length > 0) {
1712
- for (const name of invalidateIncomingRefsForFiles(options.deleteForFiles)) {
1713
- affectedNames.add(name);
1714
- }
1715
- let cursor = 0;
1716
- for (const take of inListChunks(options.deleteForFiles.length, Math.floor(maxSqlVars / 4))) {
1717
- const bucket = padToInBucket(options.deleteForFiles.slice(cursor, cursor + take));
1718
- cursor += take;
1719
- const ph = placeholders(bucket.length);
1720
- if (ftsAvailable) {
1721
- stmtFn(
1722
- `DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file IN (${ph}))`
1723
- ).run(...bucket);
1724
- }
1725
- if (vectorsAvailable) {
1726
- stmtFn(
1727
- `DELETE FROM symbol_vectors WHERE symbol_id IN (SELECT id FROM symbols WHERE file IN (${ph}))`
1728
- ).run(...bucket);
1729
- }
1730
- stmtFn(
1731
- `DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file IN (${ph}))`
1732
- ).run(...bucket);
1733
- stmtFn(`DELETE FROM symbols WHERE file IN (${ph})`).run(...bucket);
1648
+ norm = Math.sqrt(norm);
1649
+ if (norm > 0) {
1650
+ for (let i = 0; i < VECTOR_DIMENSIONS; i++) {
1651
+ vec[i] /= norm;
1734
1652
  }
1735
1653
  }
1736
- const totalSymbols = entries.reduce((n, e) => n + e.symbols.length, 0);
1737
- let nextId = allocateSymbolIds(totalSymbols);
1738
- const allInserted = [];
1739
- const refsToInsert = [];
1740
- const bulkSyms = [];
1741
- const ftsRows = [];
1742
- const vectorRows = [];
1743
- for (const entry of entries) {
1744
- const insertedForEntry = [];
1745
- for (const s of entry.symbols) {
1746
- const id = nextId++;
1747
- bulkSyms.push({
1748
- id,
1749
- lang: s.lang,
1750
- kind: s.kind,
1751
- name: s.name,
1752
- file: s.file,
1753
- line: s.line,
1754
- col: s.col,
1755
- signature: s.signature,
1756
- docComment: s.docComment,
1757
- scope: s.scope
1758
- });
1759
- if (ftsAvailable) {
1760
- ftsRows.push({
1761
- id,
1762
- text: buildIndexableText(s.name, s.signature, s.docComment)
1763
- });
1764
- }
1765
- if (vectorsAvailable) {
1766
- vectorRows.push({
1767
- id,
1768
- vector: encodeVector(embedText(buildIndexableText(s.name, s.signature, s.docComment)))
1769
- });
1770
- }
1771
- const inserted = { ...s, id };
1772
- allInserted.push(inserted);
1773
- insertedForEntry.push(inserted);
1774
- }
1775
- refsToInsert.push(...assignRefsToSymbols(entry.refs, insertedForEntry));
1654
+ return vec;
1655
+ }
1656
+ function hashNgram(str) {
1657
+ let hash = 2166136261;
1658
+ for (let i = 0; i < str.length; i++) {
1659
+ hash ^= str.charCodeAt(i);
1660
+ hash = Math.imul(hash, 16777619);
1776
1661
  }
1777
- bulkInsertSymbolsWithStatement((sql) => stmtFn(sql), maxSqlVars, bulkSyms);
1778
- bulkInsertFtsWithStatement((sql) => stmtFn(sql), maxSqlVars, ftsAvailable, ftsRows);
1779
- if (vectorsAvailable) {
1780
- bulkInsertVectorsWithStatement((sql) => stmtFn(sql), maxSqlVars, vectorRows);
1662
+ return hash >>> 0;
1663
+ }
1664
+ function cosineSimilarity(a, b) {
1665
+ let dot = 0;
1666
+ const len = Math.min(a.length, b.length);
1667
+ for (let i = 0; i < len; i++) {
1668
+ dot += a[i] * b[i];
1781
1669
  }
1782
- bulkInsertRefsWithStatement((sql) => stmtFn(sql), maxSqlVars, refsToInsert);
1783
- const upsertStmt = stmtFn(
1784
- `INSERT INTO files(file, lang, mtime_ms, content_hash, symbol_count, last_indexed)
1785
- VALUES (?, ?, ?, ?, ?, ?)
1786
- ON CONFLICT(file) DO UPDATE SET
1787
- lang = excluded.lang,
1788
- mtime_ms = excluded.mtime_ms,
1789
- content_hash = excluded.content_hash,
1790
- symbol_count = excluded.symbol_count,
1791
- last_indexed = excluded.last_indexed`
1792
- );
1793
- const now = Date.now();
1794
- for (const entry of entries) {
1795
- upsertStmt.run(
1796
- entry.file,
1797
- entry.lang,
1798
- entry.mtimeMs,
1799
- entry.contentHash ?? "",
1800
- entry.symbolCount,
1801
- now
1670
+ return dot;
1671
+ }
1672
+ function encodeVector(vec) {
1673
+ return Buffer.from(vec.buffer, vec.byteOffset, vec.byteLength);
1674
+ }
1675
+ function decodeVector(buf) {
1676
+ if (buf.byteLength === 0) return new Float32Array(0);
1677
+ if (buf.byteLength % 4 !== 0) {
1678
+ throw new Error(
1679
+ `decodeVector: invalid vector byteLength ${buf.byteLength} (must be a multiple of 4)`
1802
1680
  );
1803
1681
  }
1804
- resolveRefsForNamesUnsafe2(affectedNames);
1805
- return allInserted;
1682
+ const copy = new Float32Array(buf.byteLength / 4);
1683
+ new Uint8Array(copy.buffer).set(buf);
1684
+ return copy;
1806
1685
  }
1807
-
1808
- // src/codebase-index/writer-pragmas.ts
1809
- import { sqliteCachePragmas } from "@wrongstack/core/utils";
1810
- function applyIndexStorePragmas(db) {
1811
- try {
1812
- db.exec("PRAGMA journal_mode = WAL");
1813
- db.exec("PRAGMA synchronous = NORMAL");
1814
- db.exec("PRAGMA busy_timeout = 15000");
1815
- db.exec("PRAGMA temp_store = MEMORY");
1816
- const cache = sqliteCachePragmas();
1817
- db.exec(`PRAGMA cache_size = -${cache.cacheSizeKiB}`);
1818
- db.exec(`PRAGMA mmap_size = ${cache.mmapBytes}`);
1819
- db.exec("PRAGMA foreign_keys = ON");
1820
- db.exec("PRAGMA journal_size_limit = 67108864");
1821
- db.exec("PRAGMA wal_autocheckpoint = 1000");
1822
- } catch {
1686
+ function reciprocalRankFusion(bm25Ranks, vectorRanks, k = RRF_K) {
1687
+ const allIds = /* @__PURE__ */ new Set([...bm25Ranks.keys(), ...vectorRanks.keys()]);
1688
+ const scored = [];
1689
+ for (const id of allIds) {
1690
+ const bm25Rank = bm25Ranks.get(id);
1691
+ const vecRank = vectorRanks.get(id);
1692
+ let score = 0;
1693
+ if (bm25Rank !== void 0) score += 1 / (k + bm25Rank);
1694
+ if (vecRank !== void 0) score += 1 / (k + vecRank);
1695
+ scored.push([id, score]);
1823
1696
  }
1697
+ scored.sort((a, b) => b[1] - a[1]);
1698
+ return scored;
1824
1699
  }
1825
1700
 
1826
1701
  // src/codebase-index/writer-schema.ts
@@ -1914,15 +1789,431 @@ var SYMBOL_VECTORS_TABLE_SQL = `
1914
1789
  );
1915
1790
  `;
1916
1791
 
1917
- // src/codebase-index/writer-refs.ts
1918
- var FAMILY_MATCH_SQL = `(
1919
- sym.lang = refs.lang
1920
- OR refs.lang = ''
1921
- OR EXISTS (
1922
- SELECT 1 FROM lang_family lf1
1923
- JOIN lang_family lf2 ON lf1.family = lf2.family
1924
- WHERE lf1.lang = sym.lang AND lf2.lang = refs.lang
1925
- )
1792
+ // src/codebase-index/writer-init.ts
1793
+ var SYMBOLS_TEXT_DROPPED_KEY = "symbols_text_dropped";
1794
+ var NEXT_SYMBOL_ID_KEY = "next_symbol_id";
1795
+ function seedLangFamilies(stmt) {
1796
+ const insert = stmt("INSERT OR REPLACE INTO lang_family(lang, family) VALUES (?, ?)");
1797
+ for (const [lang, family] of LANG_FAMILY_ENTRIES) insert.run(lang, family);
1798
+ insert.run("", LANG_FAMILY_WILDCARD);
1799
+ }
1800
+ function repairMissingColumns(db) {
1801
+ const expected = [
1802
+ {
1803
+ table: "files",
1804
+ columns: [
1805
+ ["package", "TEXT NOT NULL DEFAULT ''"],
1806
+ ["content_hash", "TEXT NOT NULL DEFAULT ''"]
1807
+ ]
1808
+ },
1809
+ {
1810
+ table: "refs",
1811
+ columns: [
1812
+ ["lang", "TEXT NOT NULL DEFAULT ''"],
1813
+ ["module", "TEXT"],
1814
+ ["to_file", "TEXT"]
1815
+ ]
1816
+ }
1817
+ ];
1818
+ for (const { table, columns } of expected) {
1819
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
1820
+ const present = /* @__PURE__ */ new Set();
1821
+ for (const row of rows) {
1822
+ if (typeof row.name === "string") present.add(row.name);
1823
+ }
1824
+ if (present.size === 0) continue;
1825
+ for (const [name, type] of columns) {
1826
+ if (present.has(name)) continue;
1827
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${name} ${type}`);
1828
+ }
1829
+ }
1830
+ }
1831
+ function dropDeprecatedSymbolsColumns(db, getMetadata, setMetadata) {
1832
+ if (getMetadata(SYMBOLS_TEXT_DROPPED_KEY) !== void 0) return;
1833
+ const present = new Set(
1834
+ db.prepare("PRAGMA table_info(symbols)").all().flatMap(
1835
+ (row) => typeof row.name === "string" ? [row.name] : []
1836
+ )
1837
+ );
1838
+ if (present.size === 0) return;
1839
+ if (!present.has("text")) {
1840
+ setMetadata(SYMBOLS_TEXT_DROPPED_KEY, "1");
1841
+ return;
1842
+ }
1843
+ try {
1844
+ db.exec("ALTER TABLE symbols DROP COLUMN text");
1845
+ setMetadata(SYMBOLS_TEXT_DROPPED_KEY, "1");
1846
+ } catch {
1847
+ }
1848
+ }
1849
+ function initIndexSchema(db, stmt, getMetadata, setMetadata, maxSqlVars, invalidateBm25) {
1850
+ db.exec(METADATA_TABLE_SQL);
1851
+ const storedRows = stmt("SELECT value FROM metadata WHERE key = ?").all("version");
1852
+ const storedVersion = storedRows.length ? Number(storedRows[0]?.value) : null;
1853
+ if (storedVersion !== null && storedVersion !== SCHEMA_VERSION) {
1854
+ db.exec(`
1855
+ DROP TABLE IF EXISTS symbols;
1856
+ DROP TABLE IF EXISTS files;
1857
+ DROP TABLE IF EXISTS refs;
1858
+ DROP TABLE IF EXISTS symbol_vectors;
1859
+ `);
1860
+ db.exec("DROP TABLE IF EXISTS symbols_fts");
1861
+ stmt("UPDATE metadata SET value = ? WHERE key = ?").run(String(SCHEMA_VERSION), "version");
1862
+ } else if (storedVersion === null) {
1863
+ stmt("INSERT INTO metadata(key, value) VALUES (?, ?)").run("version", String(SCHEMA_VERSION));
1864
+ }
1865
+ db.exec(CORE_TABLES_SQL);
1866
+ db.exec(REFS_TABLE_SQL);
1867
+ repairMissingColumns(db);
1868
+ dropDeprecatedSymbolsColumns(db, getMetadata, setMetadata);
1869
+ for (const sql of FILE_INDEX_SQL) db.exec(sql);
1870
+ for (const sql of SYMBOL_INDEX_SQL) db.exec(sql);
1871
+ for (const sql of REFS_INDEX_SQL) db.exec(sql);
1872
+ db.exec(LANG_FAMILY_TABLE_SQL);
1873
+ seedLangFamilies(stmt);
1874
+ let ftsAvailable = false;
1875
+ try {
1876
+ const ftsSchema = stmt(
1877
+ "SELECT sql FROM sqlite_master WHERE type='table' AND name='symbols_fts'"
1878
+ ).get();
1879
+ if (ftsSchema?.sql?.includes("unicode61")) {
1880
+ db.exec("DROP TABLE IF EXISTS symbols_fts");
1881
+ }
1882
+ db.exec(SYMBOLS_FTS_SQL);
1883
+ ftsAvailable = true;
1884
+ const symbolCount = Number(
1885
+ stmt("SELECT COUNT(*) AS n FROM symbols").get()?.n ?? 0
1886
+ );
1887
+ const ftsCount = Number(
1888
+ stmt("SELECT COUNT(*) AS n FROM symbols_fts").get()?.n ?? 0
1889
+ );
1890
+ if (symbolCount !== ftsCount) {
1891
+ db.exec("DELETE FROM symbols_fts");
1892
+ if (vectorEmbeddingEnabled() && stmt("SELECT 1 FROM sqlite_master WHERE type='table' AND name='symbol_vectors'").get() !== void 0) {
1893
+ db.exec("DELETE FROM symbol_vectors");
1894
+ }
1895
+ const rows = stmt(
1896
+ "SELECT id, name, signature, doc_comment FROM symbols ORDER BY id"
1897
+ ).all();
1898
+ bulkInsertFtsWithStatement(
1899
+ stmt,
1900
+ maxSqlVars,
1901
+ ftsAvailable,
1902
+ rows.map((row) => ({
1903
+ id: row.id,
1904
+ text: buildIndexableText(row.name, row.signature, row.doc_comment)
1905
+ }))
1906
+ );
1907
+ invalidateBm25();
1908
+ }
1909
+ } catch {
1910
+ ftsAvailable = false;
1911
+ }
1912
+ let vectorsAvailable = false;
1913
+ try {
1914
+ if (vectorEmbeddingEnabled()) {
1915
+ db.exec(SYMBOL_VECTORS_TABLE_SQL);
1916
+ vectorsAvailable = true;
1917
+ } else {
1918
+ db.exec("DROP TABLE IF EXISTS symbol_vectors");
1919
+ vectorsAvailable = false;
1920
+ }
1921
+ } catch {
1922
+ vectorsAvailable = false;
1923
+ }
1924
+ ensureNextSymbolIdSeeded(stmt);
1925
+ return { ftsAvailable, vectorsAvailable };
1926
+ }
1927
+ function ensureNextSymbolIdSeeded(stmt) {
1928
+ const existing = stmt("SELECT value FROM metadata WHERE key = ?").get(NEXT_SYMBOL_ID_KEY);
1929
+ if (existing?.value !== void 0) return;
1930
+ const maxRows = stmt("SELECT MAX(id) AS m FROM symbols").all();
1931
+ const next = (maxRows[0]?.m ?? 0) + 1;
1932
+ stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)").run(
1933
+ NEXT_SYMBOL_ID_KEY,
1934
+ String(next)
1935
+ );
1936
+ }
1937
+ function allocateSymbolIds(stmt, count, getMaxSymbolId) {
1938
+ if (count <= 0) return getMaxSymbolId() + 1;
1939
+ ensureNextSymbolIdSeeded(stmt);
1940
+ const row = stmt("SELECT value FROM metadata WHERE key = ?").get(NEXT_SYMBOL_ID_KEY);
1941
+ const start = Math.max(1, Number(row?.value ?? 1) || 1);
1942
+ stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)").run(
1943
+ NEXT_SYMBOL_ID_KEY,
1944
+ String(start + count)
1945
+ );
1946
+ return start;
1947
+ }
1948
+
1949
+ // src/codebase-index/writer-maintenance.ts
1950
+ var FTS_CHURN_KEY = "fts_churn_since_maintain";
1951
+ function optimizeStore(db) {
1952
+ try {
1953
+ db.exec("PRAGMA optimize");
1954
+ } catch {
1955
+ }
1956
+ }
1957
+ function recordFtsChurn(ftsAvailable, getMetadata, setMetadata, rows) {
1958
+ if (rows <= 0 || !ftsAvailable) return;
1959
+ try {
1960
+ const current = Number(getMetadata(FTS_CHURN_KEY) ?? "0") || 0;
1961
+ setMetadata(FTS_CHURN_KEY, String(current + rows));
1962
+ } catch {
1963
+ }
1964
+ }
1965
+ function optimizeFtsIfNeeded(stmt, ftsAvailable, getMetadata, setMetadata, runWithRetry, options = {}) {
1966
+ if (!ftsAvailable) return false;
1967
+ try {
1968
+ const minChurnRatio = options.minChurnRatio ?? 0.1;
1969
+ const minChurnRows = options.minChurnRows ?? 5e3;
1970
+ const churn = Number(getMetadata(FTS_CHURN_KEY) ?? "0") || 0;
1971
+ const liveRows = Number(
1972
+ stmt("SELECT COUNT(*) AS n FROM symbols").get()?.n ?? 0
1973
+ );
1974
+ if (churn < Math.max(minChurnRows, liveRows * minChurnRatio)) return false;
1975
+ runWithRetry(() => {
1976
+ stmt(`INSERT INTO symbols_fts(symbols_fts) VALUES('optimize')`).run();
1977
+ });
1978
+ setMetadata(FTS_CHURN_KEY, "0");
1979
+ return true;
1980
+ } catch {
1981
+ return false;
1982
+ }
1983
+ }
1984
+ function checkpointWal(db) {
1985
+ try {
1986
+ const probe = db.prepare("PRAGMA wal_checkpoint(PASSIVE)").get();
1987
+ if (Number(probe?.busy ?? 1) !== 0) return false;
1988
+ const done = db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
1989
+ return Number(done?.busy ?? 1) === 0;
1990
+ } catch {
1991
+ return false;
1992
+ }
1993
+ }
1994
+ function compactIfNeeded(db, stmt, runWithRetry, options = {}) {
1995
+ const minBytes = options.minBytes ?? 256 * 1024 * 1024;
1996
+ const minFreeRatio = options.minFreeRatio ?? 0.35;
1997
+ try {
1998
+ const pageCount = Number(
1999
+ stmt("PRAGMA page_count").get()?.page_count ?? 0
2000
+ );
2001
+ const pageSize = Number(
2002
+ stmt("PRAGMA page_size").get()?.page_size ?? 0
2003
+ );
2004
+ const freePages = Number(
2005
+ stmt("PRAGMA freelist_count").get()?.freelist_count ?? 0
2006
+ );
2007
+ if (pageCount <= 0 || pageSize <= 0 || pageCount * pageSize < minBytes || freePages / pageCount < minFreeRatio) {
2008
+ return false;
2009
+ }
2010
+ runWithRetry(() => {
2011
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
2012
+ db.exec("VACUUM");
2013
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
2014
+ });
2015
+ return true;
2016
+ } catch {
2017
+ return false;
2018
+ }
2019
+ }
2020
+
2021
+ // src/codebase-index/writer-mutations.ts
2022
+ function commitBatchWithStatement(stmtFn, maxSqlVars, ftsAvailable, vectorsAvailable, allocateSymbolIds2, invalidateIncomingRefsForFiles, resolveRefsForNamesUnsafe2, entries, options = {}) {
2023
+ if (entries.length === 0 && (options.deleteForFiles?.length ?? 0) === 0) {
2024
+ return [];
2025
+ }
2026
+ const affectedNames = /* @__PURE__ */ new Set();
2027
+ for (const entry of entries) {
2028
+ for (const symbol of entry.symbols) affectedNames.add(symbol.name);
2029
+ for (const ref of entry.refs) affectedNames.add(ref.toName);
2030
+ }
2031
+ if (options.deleteForFiles && options.deleteForFiles.length > 0) {
2032
+ for (const name of invalidateIncomingRefsForFiles(options.deleteForFiles)) {
2033
+ affectedNames.add(name);
2034
+ }
2035
+ let cursor = 0;
2036
+ for (const take of inListChunks(options.deleteForFiles.length, Math.floor(maxSqlVars / 4))) {
2037
+ const bucket = padToInBucket(options.deleteForFiles.slice(cursor, cursor + take));
2038
+ cursor += take;
2039
+ const ph = placeholders(bucket.length);
2040
+ if (ftsAvailable) {
2041
+ stmtFn(
2042
+ `DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file IN (${ph}))`
2043
+ ).run(...bucket);
2044
+ }
2045
+ if (vectorsAvailable) {
2046
+ stmtFn(
2047
+ `DELETE FROM symbol_vectors WHERE symbol_id IN (SELECT id FROM symbols WHERE file IN (${ph}))`
2048
+ ).run(...bucket);
2049
+ }
2050
+ stmtFn(
2051
+ `DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file IN (${ph}))`
2052
+ ).run(...bucket);
2053
+ stmtFn(`DELETE FROM symbols WHERE file IN (${ph})`).run(...bucket);
2054
+ }
2055
+ }
2056
+ const totalSymbols = entries.reduce((n, e) => n + e.symbols.length, 0);
2057
+ let nextId = allocateSymbolIds2(totalSymbols);
2058
+ const allInserted = [];
2059
+ const refsToInsert = [];
2060
+ const bulkSyms = [];
2061
+ const ftsRows = [];
2062
+ const vectorRows = [];
2063
+ for (const entry of entries) {
2064
+ const insertedForEntry = [];
2065
+ for (const s of entry.symbols) {
2066
+ const id = nextId++;
2067
+ bulkSyms.push({
2068
+ id,
2069
+ lang: s.lang,
2070
+ kind: s.kind,
2071
+ name: s.name,
2072
+ file: s.file,
2073
+ line: s.line,
2074
+ col: s.col,
2075
+ signature: s.signature,
2076
+ docComment: s.docComment,
2077
+ scope: s.scope
2078
+ });
2079
+ if (ftsAvailable) {
2080
+ ftsRows.push({
2081
+ id,
2082
+ text: buildIndexableText(s.name, s.signature, s.docComment)
2083
+ });
2084
+ }
2085
+ if (vectorsAvailable) {
2086
+ vectorRows.push({
2087
+ id,
2088
+ vector: encodeVector(embedText(buildIndexableText(s.name, s.signature, s.docComment)))
2089
+ });
2090
+ }
2091
+ const inserted = { ...s, id };
2092
+ allInserted.push(inserted);
2093
+ insertedForEntry.push(inserted);
2094
+ }
2095
+ refsToInsert.push(...assignRefsToSymbols(entry.refs, insertedForEntry));
2096
+ }
2097
+ bulkInsertSymbolsWithStatement((sql) => stmtFn(sql), maxSqlVars, bulkSyms);
2098
+ bulkInsertFtsWithStatement((sql) => stmtFn(sql), maxSqlVars, ftsAvailable, ftsRows);
2099
+ if (vectorsAvailable) {
2100
+ bulkInsertVectorsWithStatement((sql) => stmtFn(sql), maxSqlVars, vectorRows);
2101
+ }
2102
+ bulkInsertRefsWithStatement((sql) => stmtFn(sql), maxSqlVars, refsToInsert);
2103
+ const upsertStmt = stmtFn(
2104
+ `INSERT INTO files(file, lang, mtime_ms, content_hash, symbol_count, last_indexed)
2105
+ VALUES (?, ?, ?, ?, ?, ?)
2106
+ ON CONFLICT(file) DO UPDATE SET
2107
+ lang = excluded.lang,
2108
+ mtime_ms = excluded.mtime_ms,
2109
+ content_hash = excluded.content_hash,
2110
+ symbol_count = excluded.symbol_count,
2111
+ last_indexed = excluded.last_indexed`
2112
+ );
2113
+ const now = Date.now();
2114
+ for (const entry of entries) {
2115
+ upsertStmt.run(
2116
+ entry.file,
2117
+ entry.lang,
2118
+ entry.mtimeMs,
2119
+ entry.contentHash ?? "",
2120
+ entry.symbolCount,
2121
+ now
2122
+ );
2123
+ }
2124
+ resolveRefsForNamesUnsafe2(affectedNames);
2125
+ return allInserted;
2126
+ }
2127
+ function insertSymbolsWithStatement(stmtFn, maxSqlVars, ftsAvailable, vectorsAvailable, allocateSymbolIds2, symbols) {
2128
+ let nextId = allocateSymbolIds2(symbols.length);
2129
+ const result = [];
2130
+ const bulk = [];
2131
+ const ftsRows = [];
2132
+ const vectorRows = [];
2133
+ for (const s of symbols) {
2134
+ const id = nextId++;
2135
+ bulk.push({
2136
+ id,
2137
+ lang: s.lang,
2138
+ kind: s.kind,
2139
+ name: s.name,
2140
+ file: s.file,
2141
+ line: s.line,
2142
+ col: s.col,
2143
+ signature: s.signature,
2144
+ docComment: s.docComment,
2145
+ scope: s.scope
2146
+ });
2147
+ if (ftsAvailable) {
2148
+ ftsRows.push({ id, text: buildIndexableText(s.name, s.signature, s.docComment) });
2149
+ }
2150
+ if (vectorsAvailable) {
2151
+ vectorRows.push({
2152
+ id,
2153
+ vector: encodeVector(embedText(buildIndexableText(s.name, s.signature, s.docComment)))
2154
+ });
2155
+ }
2156
+ result.push({ ...s, id });
2157
+ }
2158
+ bulkInsertSymbolsWithStatement((sql) => stmtFn(sql), maxSqlVars, bulk);
2159
+ bulkInsertFtsWithStatement((sql) => stmtFn(sql), maxSqlVars, ftsAvailable, ftsRows);
2160
+ if (vectorsAvailable) {
2161
+ bulkInsertVectorsWithStatement((sql) => stmtFn(sql), maxSqlVars, vectorRows);
2162
+ }
2163
+ return result;
2164
+ }
2165
+ function upsertFileWithStatement(stmtFn, meta) {
2166
+ stmtFn(
2167
+ `INSERT INTO files(file, lang, mtime_ms, content_hash, symbol_count, last_indexed)
2168
+ VALUES (?, ?, ?, ?, ?, ?)
2169
+ ON CONFLICT(file) DO UPDATE SET
2170
+ lang = excluded.lang,
2171
+ mtime_ms = excluded.mtime_ms,
2172
+ content_hash = excluded.content_hash,
2173
+ symbol_count = excluded.symbol_count,
2174
+ last_indexed = excluded.last_indexed`
2175
+ ).run(
2176
+ meta.file,
2177
+ meta.lang,
2178
+ meta.mtimeMs,
2179
+ meta.contentHash ?? "",
2180
+ meta.symbolCount,
2181
+ meta.lastIndexed
2182
+ );
2183
+ }
2184
+ function setFilePackagesWithStatement(stmtFn, entries) {
2185
+ if (entries.size === 0) return;
2186
+ const update = stmtFn("UPDATE files SET package = ? WHERE file = ?");
2187
+ for (const [file, label] of entries) update.run(label, file);
2188
+ }
2189
+
2190
+ // src/codebase-index/writer-pragmas.ts
2191
+ import { sqliteCachePragmas } from "@wrongstack/core/utils";
2192
+ function applyIndexStorePragmas(db) {
2193
+ try {
2194
+ db.exec("PRAGMA journal_mode = WAL");
2195
+ db.exec("PRAGMA synchronous = NORMAL");
2196
+ db.exec("PRAGMA busy_timeout = 15000");
2197
+ db.exec("PRAGMA temp_store = MEMORY");
2198
+ const cache = sqliteCachePragmas();
2199
+ db.exec(`PRAGMA cache_size = -${cache.cacheSizeKiB}`);
2200
+ db.exec(`PRAGMA mmap_size = ${cache.mmapBytes}`);
2201
+ db.exec("PRAGMA foreign_keys = ON");
2202
+ db.exec("PRAGMA journal_size_limit = 67108864");
2203
+ db.exec("PRAGMA wal_autocheckpoint = 1000");
2204
+ } catch {
2205
+ }
2206
+ }
2207
+
2208
+ // src/codebase-index/writer-refs.ts
2209
+ var FAMILY_MATCH_SQL = `(
2210
+ sym.lang = refs.lang
2211
+ OR refs.lang = ''
2212
+ OR EXISTS (
2213
+ SELECT 1 FROM lang_family lf1
2214
+ JOIN lang_family lf2 ON lf1.family = lf2.family
2215
+ WHERE lf1.lang = sym.lang AND lf2.lang = refs.lang
2216
+ )
1926
2217
  OR ? IN (
1927
2218
  SELECT family FROM lang_family WHERE lang = refs.lang
1928
2219
  )
@@ -2517,180 +2808,26 @@ var IndexStore = class _IndexStore {
2517
2808
  this.db.exec("ROLLBACK");
2518
2809
  }
2519
2810
  }
2520
- seedLangFamilies() {
2521
- const insert = this.stmt("INSERT OR REPLACE INTO lang_family(lang, family) VALUES (?, ?)");
2522
- for (const [lang, family] of LANG_FAMILY_ENTRIES) insert.run(lang, family);
2523
- insert.run("", LANG_FAMILY_WILDCARD);
2524
- }
2525
- repairMissingColumns() {
2526
- const expected = [
2527
- {
2528
- table: "files",
2529
- columns: [
2530
- ["package", "TEXT NOT NULL DEFAULT ''"],
2531
- ["content_hash", "TEXT NOT NULL DEFAULT ''"]
2532
- ]
2533
- },
2534
- {
2535
- table: "refs",
2536
- columns: [
2537
- ["lang", "TEXT NOT NULL DEFAULT ''"],
2538
- ["module", "TEXT"],
2539
- ["to_file", "TEXT"]
2540
- ]
2541
- }
2542
- ];
2543
- for (const { table, columns } of expected) {
2544
- const rows = this.db.prepare(`PRAGMA table_info(${table})`).all();
2545
- const present = /* @__PURE__ */ new Set();
2546
- for (const row of rows) {
2547
- if (typeof row.name === "string") present.add(row.name);
2548
- }
2549
- if (present.size === 0) continue;
2550
- for (const [name, type] of columns) {
2551
- if (present.has(name)) continue;
2552
- this.db.exec(`ALTER TABLE ${table} ADD COLUMN ${name} ${type}`);
2553
- }
2554
- }
2555
- }
2556
- /**
2557
- * P4: `symbols.text` duplicated name + signature + doc_comment (~19 MB on
2558
- * the live index) and is derived on demand now. In-place DROP COLUMN — no
2559
- * SCHEMA_VERSION bump, so no wipe-and-reparse. Best-effort: a busy or
2560
- * SQLite-without-DROP-COLUMN open leaves the column in place, where new
2561
- * inserts simply default it to '' and the next open retries.
2562
- */
2563
- dropDeprecatedSymbolsColumns() {
2564
- if (this.getMetadata(_IndexStore.SYMBOLS_TEXT_DROPPED_KEY) !== void 0) return;
2565
- const present = new Set(
2566
- this.db.prepare("PRAGMA table_info(symbols)").all().flatMap(
2567
- (row) => typeof row.name === "string" ? [row.name] : []
2568
- )
2569
- );
2570
- if (present.size === 0) return;
2571
- if (!present.has("text")) {
2572
- this.setMetadata(_IndexStore.SYMBOLS_TEXT_DROPPED_KEY, "1");
2573
- return;
2574
- }
2575
- try {
2576
- this.db.exec("ALTER TABLE symbols DROP COLUMN text");
2577
- this.setMetadata(_IndexStore.SYMBOLS_TEXT_DROPPED_KEY, "1");
2578
- } catch {
2579
- }
2580
- }
2581
2811
  initSchema() {
2582
- this.db.exec(METADATA_TABLE_SQL);
2583
- const storedRows = this.stmt("SELECT value FROM metadata WHERE key = ?").all("version");
2584
- const storedVersion = storedRows.length ? Number(storedRows[0]?.value) : null;
2585
- if (storedVersion !== null && storedVersion !== SCHEMA_VERSION) {
2586
- this.db.exec(`
2587
- DROP TABLE IF EXISTS symbols;
2588
- DROP TABLE IF EXISTS files;
2589
- DROP TABLE IF EXISTS refs;
2590
- DROP TABLE IF EXISTS symbol_vectors;
2591
- `);
2592
- this.db.exec("DROP TABLE IF EXISTS symbols_fts");
2593
- this.stmt("UPDATE metadata SET value = ? WHERE key = ?").run(
2594
- String(SCHEMA_VERSION),
2595
- "version"
2596
- );
2597
- } else if (storedVersion === null) {
2598
- this.stmt("INSERT INTO metadata(key, value) VALUES (?, ?)").run(
2599
- "version",
2600
- String(SCHEMA_VERSION)
2601
- );
2602
- }
2603
- this.db.exec(CORE_TABLES_SQL);
2604
- this.db.exec(REFS_TABLE_SQL);
2605
- this.repairMissingColumns();
2606
- this.dropDeprecatedSymbolsColumns();
2607
- for (const sql of FILE_INDEX_SQL) this.db.exec(sql);
2608
- for (const sql of SYMBOL_INDEX_SQL) this.db.exec(sql);
2609
- for (const sql of REFS_INDEX_SQL) this.db.exec(sql);
2610
- this.db.exec(LANG_FAMILY_TABLE_SQL);
2611
- this.seedLangFamilies();
2612
- try {
2613
- const ftsSchema = this.stmt(
2614
- "SELECT sql FROM sqlite_master WHERE type='table' AND name='symbols_fts'"
2615
- ).get();
2616
- if (ftsSchema?.sql?.includes("unicode61")) {
2617
- this.db.exec("DROP TABLE IF EXISTS symbols_fts");
2618
- }
2619
- this.db.exec(SYMBOLS_FTS_SQL);
2620
- this.ftsAvailable = true;
2621
- const symbolCount = Number(
2622
- this.stmt("SELECT COUNT(*) AS n FROM symbols").get()?.n ?? 0
2623
- );
2624
- const ftsCount = Number(
2625
- this.stmt("SELECT COUNT(*) AS n FROM symbols_fts").get()?.n ?? 0
2626
- );
2627
- if (symbolCount !== ftsCount) {
2628
- this.db.exec("DELETE FROM symbols_fts");
2629
- if (vectorEmbeddingEnabled() && this.stmt(
2630
- "SELECT 1 FROM sqlite_master WHERE type='table' AND name='symbol_vectors'"
2631
- ).get() !== void 0) {
2632
- this.db.exec("DELETE FROM symbol_vectors");
2633
- }
2634
- const rows = this.stmt(
2635
- "SELECT id, name, signature, doc_comment FROM symbols ORDER BY id"
2636
- ).all();
2637
- bulkInsertFtsWithStatement(
2638
- (sql) => this.stmt(sql),
2639
- _IndexStore.MAX_SQL_VARS,
2640
- this.ftsAvailable,
2641
- rows.map((row) => ({
2642
- id: row.id,
2643
- text: buildIndexableText(row.name, row.signature, row.doc_comment)
2644
- }))
2645
- );
2646
- this.invalidateBm25();
2647
- }
2648
- } catch {
2649
- this.ftsAvailable = false;
2650
- }
2651
- try {
2652
- if (vectorEmbeddingEnabled()) {
2653
- this.db.exec(SYMBOL_VECTORS_TABLE_SQL);
2654
- this.vectorsAvailable = true;
2655
- } else {
2656
- this.db.exec("DROP TABLE IF EXISTS symbol_vectors");
2657
- this.vectorsAvailable = false;
2658
- }
2659
- } catch {
2660
- this.vectorsAvailable = false;
2661
- }
2662
- this.ensureNextSymbolIdSeeded();
2663
- }
2664
- static NEXT_SYMBOL_ID_KEY = "next_symbol_id";
2665
- static MAX_SQL_VARS = 900;
2666
- /** P2: persisted FTS-mutation churn counter — see {@link optimizeFtsIfNeeded}. */
2667
- static FTS_CHURN_KEY = "fts_churn_since_maintain";
2668
- /** P4: one-shot marker that the deprecated symbols.text column is gone. */
2669
- static SYMBOLS_TEXT_DROPPED_KEY = "symbols_text_dropped";
2670
- ensureNextSymbolIdSeeded() {
2671
- const existing = this.stmt("SELECT value FROM metadata WHERE key = ?").get(
2672
- _IndexStore.NEXT_SYMBOL_ID_KEY
2673
- );
2674
- if (existing?.value !== void 0) return;
2675
- const maxRows = this.stmt("SELECT MAX(id) AS m FROM symbols").all();
2676
- const next = (maxRows[0]?.m ?? 0) + 1;
2677
- this.stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)").run(
2678
- _IndexStore.NEXT_SYMBOL_ID_KEY,
2679
- String(next)
2812
+ const { ftsAvailable, vectorsAvailable } = initIndexSchema(
2813
+ this.db,
2814
+ (sql) => this.stmt(sql),
2815
+ (key) => this.getMetadata(key),
2816
+ (key, value) => this.setMetadata(key, value),
2817
+ _IndexStore.MAX_SQL_VARS,
2818
+ () => this.invalidateBm25()
2680
2819
  );
2820
+ this.ftsAvailable = ftsAvailable;
2821
+ this.vectorsAvailable = vectorsAvailable;
2681
2822
  }
2823
+ static NEXT_SYMBOL_ID_KEY = NEXT_SYMBOL_ID_KEY;
2824
+ static MAX_SQL_VARS = 900;
2682
2825
  allocateSymbolIds(count) {
2683
- if (count <= 0) return this.getMaxSymbolId() + 1;
2684
- this.ensureNextSymbolIdSeeded();
2685
- const row = this.stmt("SELECT value FROM metadata WHERE key = ?").get(
2686
- _IndexStore.NEXT_SYMBOL_ID_KEY
2687
- );
2688
- const start = Math.max(1, Number(row?.value ?? 1) || 1);
2689
- this.stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)").run(
2690
- _IndexStore.NEXT_SYMBOL_ID_KEY,
2691
- String(start + count)
2826
+ return allocateSymbolIds(
2827
+ (sql) => this.stmt(sql),
2828
+ count,
2829
+ () => this.getMaxSymbolId()
2692
2830
  );
2693
- return start;
2694
2831
  }
2695
2832
  invalidateIncomingRefsForFiles(files) {
2696
2833
  if (files.length === 0) return /* @__PURE__ */ new Set();
@@ -2720,52 +2857,14 @@ var IndexStore = class _IndexStore {
2720
2857
  return this.runWithRetry(() => {
2721
2858
  const ownsTransaction = this.beginWriteTransaction();
2722
2859
  try {
2723
- let nextId = this.allocateSymbolIds(symbols.length);
2724
- const result = [];
2725
- const bulk = [];
2726
- const ftsRows = [];
2727
- const vectorRows = [];
2728
- for (const s of symbols) {
2729
- const id = nextId++;
2730
- bulk.push({
2731
- id,
2732
- lang: s.lang,
2733
- kind: s.kind,
2734
- name: s.name,
2735
- file: s.file,
2736
- line: s.line,
2737
- col: s.col,
2738
- signature: s.signature,
2739
- docComment: s.docComment,
2740
- scope: s.scope
2741
- });
2742
- if (this.ftsAvailable) {
2743
- ftsRows.push({ id, text: buildIndexableText(s.name, s.signature, s.docComment) });
2744
- }
2745
- if (this.vectorsAvailable) {
2746
- vectorRows.push({
2747
- id,
2748
- vector: encodeVector(
2749
- embedText(buildIndexableText(s.name, s.signature, s.docComment))
2750
- )
2751
- });
2752
- }
2753
- result.push({ ...s, id });
2754
- }
2755
- bulkInsertSymbolsWithStatement((sql) => this.stmt(sql), _IndexStore.MAX_SQL_VARS, bulk);
2756
- bulkInsertFtsWithStatement(
2860
+ const result = insertSymbolsWithStatement(
2757
2861
  (sql) => this.stmt(sql),
2758
2862
  _IndexStore.MAX_SQL_VARS,
2759
2863
  this.ftsAvailable,
2760
- ftsRows
2864
+ this.vectorsAvailable,
2865
+ this.allocateSymbolIds.bind(this),
2866
+ symbols
2761
2867
  );
2762
- if (this.vectorsAvailable) {
2763
- bulkInsertVectorsWithStatement(
2764
- (sql) => this.stmt(sql),
2765
- _IndexStore.MAX_SQL_VARS,
2766
- vectorRows
2767
- );
2768
- }
2769
2868
  this.recordFtsChurn(symbols.length);
2770
2869
  this.commitWriteTransaction(ownsTransaction);
2771
2870
  return result;
@@ -2836,25 +2935,7 @@ var IndexStore = class _IndexStore {
2836
2935
  });
2837
2936
  }
2838
2937
  upsertFile(meta) {
2839
- this.runWithRetry(() => {
2840
- this.stmt(
2841
- `INSERT INTO files(file, lang, mtime_ms, content_hash, symbol_count, last_indexed)
2842
- VALUES (?, ?, ?, ?, ?, ?)
2843
- ON CONFLICT(file) DO UPDATE SET
2844
- lang = excluded.lang,
2845
- mtime_ms = excluded.mtime_ms,
2846
- content_hash = excluded.content_hash,
2847
- symbol_count = excluded.symbol_count,
2848
- last_indexed = excluded.last_indexed`
2849
- ).run(
2850
- meta.file,
2851
- meta.lang,
2852
- meta.mtimeMs,
2853
- meta.contentHash ?? "",
2854
- meta.symbolCount,
2855
- meta.lastIndexed
2856
- );
2857
- });
2938
+ this.runWithRetry(() => upsertFileWithStatement((sql) => this.stmt(sql), meta));
2858
2939
  }
2859
2940
  getFileMeta(file) {
2860
2941
  return getFileMetaWithStatement((sql) => this.stmt(sql), file);
@@ -2863,11 +2944,7 @@ var IndexStore = class _IndexStore {
2863
2944
  return getAllFileMetasWithStatement((sql) => this.stmt(sql));
2864
2945
  }
2865
2946
  setFilePackages(entries) {
2866
- if (entries.size === 0) return;
2867
- this.runWithRetry(() => {
2868
- const update = this.stmt("UPDATE files SET package = ? WHERE file = ?");
2869
- for (const [file, label] of entries) update.run(label, file);
2870
- });
2947
+ this.runWithRetry(() => setFilePackagesWithStatement((sql) => this.stmt(sql), entries));
2871
2948
  }
2872
2949
  getNamespaceDeclarations() {
2873
2950
  return getNamespaceDeclarationsWithStatement((sql) => this.stmt(sql));
@@ -3089,10 +3166,7 @@ var IndexStore = class _IndexStore {
3089
3166
  });
3090
3167
  }
3091
3168
  optimize() {
3092
- try {
3093
- this.db.exec("PRAGMA optimize");
3094
- } catch {
3095
- }
3169
+ optimizeStore(this.db);
3096
3170
  }
3097
3171
  /**
3098
3172
  * P2: churn-gated FTS5 segment maintenance.
@@ -3110,23 +3184,14 @@ var IndexStore = class _IndexStore {
3110
3184
  * it ran, safe to call from the daemon's single-threaded idle path.
3111
3185
  */
3112
3186
  optimizeFtsIfNeeded(options = {}) {
3113
- if (!this.ftsAvailable) return false;
3114
- try {
3115
- const minChurnRatio = options.minChurnRatio ?? 0.1;
3116
- const minChurnRows = options.minChurnRows ?? 5e3;
3117
- const churn = Number(this.getMetadata(_IndexStore.FTS_CHURN_KEY) ?? "0") || 0;
3118
- const liveRows = Number(
3119
- this.stmt("SELECT COUNT(*) AS n FROM symbols").get()?.n ?? 0
3120
- );
3121
- if (churn < Math.max(minChurnRows, liveRows * minChurnRatio)) return false;
3122
- this.runWithRetry(() => {
3123
- this.stmt(`INSERT INTO symbols_fts(symbols_fts) VALUES('optimize')`).run();
3124
- });
3125
- this.setMetadata(_IndexStore.FTS_CHURN_KEY, "0");
3126
- return true;
3127
- } catch {
3128
- return false;
3129
- }
3187
+ return optimizeFtsIfNeeded(
3188
+ (sql) => this.stmt(sql),
3189
+ this.ftsAvailable,
3190
+ (key) => this.getMetadata(key),
3191
+ (key, value) => this.setMetadata(key, value),
3192
+ (fn) => this.runWithRetry(fn),
3193
+ options
3194
+ );
3130
3195
  }
3131
3196
  /**
3132
3197
  * Best-effort churn bookkeeping for {@link optimizeFtsIfNeeded}. Counts the
@@ -3135,12 +3200,12 @@ var IndexStore = class _IndexStore {
3135
3200
  * survives store open/close cycles in the daemon pool.
3136
3201
  */
3137
3202
  recordFtsChurn(rows) {
3138
- if (rows <= 0 || !this.ftsAvailable) return;
3139
- try {
3140
- const current = Number(this.getMetadata(_IndexStore.FTS_CHURN_KEY) ?? "0") || 0;
3141
- this.setMetadata(_IndexStore.FTS_CHURN_KEY, String(current + rows));
3142
- } catch {
3143
- }
3203
+ recordFtsChurn(
3204
+ this.ftsAvailable,
3205
+ (key) => this.getMetadata(key),
3206
+ (key, value) => this.setMetadata(key, value),
3207
+ rows
3208
+ );
3144
3209
  }
3145
3210
  /**
3146
3211
  * P4.14: best-effort WAL checkpoint for idle-time maintenance.
@@ -3154,40 +3219,15 @@ var IndexStore = class _IndexStore {
3154
3219
  * never wait on readers here: busy means "retry at the next idle window".
3155
3220
  */
3156
3221
  checkpointWal() {
3157
- try {
3158
- const probe = this.db.prepare("PRAGMA wal_checkpoint(PASSIVE)").get();
3159
- if (Number(probe?.busy ?? 1) !== 0) return false;
3160
- const done = this.db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
3161
- return Number(done?.busy ?? 1) === 0;
3162
- } catch {
3163
- return false;
3164
- }
3222
+ return checkpointWal(this.db);
3165
3223
  }
3166
3224
  compactIfNeeded(options = {}) {
3167
- const minBytes = options.minBytes ?? 256 * 1024 * 1024;
3168
- const minFreeRatio = options.minFreeRatio ?? 0.35;
3169
- try {
3170
- const pageCount = Number(
3171
- this.stmt("PRAGMA page_count").get()?.page_count ?? 0
3172
- );
3173
- const pageSize = Number(
3174
- this.stmt("PRAGMA page_size").get()?.page_size ?? 0
3175
- );
3176
- const freePages = Number(
3177
- this.stmt("PRAGMA freelist_count").get()?.freelist_count ?? 0
3178
- );
3179
- if (pageCount <= 0 || pageSize <= 0 || pageCount * pageSize < minBytes || freePages / pageCount < minFreeRatio) {
3180
- return false;
3181
- }
3182
- this.runWithRetry(() => {
3183
- this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
3184
- this.db.exec("VACUUM");
3185
- this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
3186
- });
3187
- return true;
3188
- } catch {
3189
- return false;
3190
- }
3225
+ return compactIfNeeded(
3226
+ this.db,
3227
+ (sql) => this.stmt(sql),
3228
+ (fn) => this.runWithRetry(fn),
3229
+ options
3230
+ );
3191
3231
  }
3192
3232
  findIncomingCallsByName(symbolName, file, limit = 100) {
3193
3233
  return findIncomingCallsByName((sql) => this.stmt(sql), symbolName, file, limit);
@@ -3819,7 +3859,7 @@ var ParserWorkerPool = class {
3819
3859
  */
3820
3860
  async reparseInline(batch, orphaned, workerId) {
3821
3861
  try {
3822
- const { parseFileContent } = await import("./parser-dispatch-QGC4HSP5.js");
3862
+ const { parseFileContent } = await import("./parser-dispatch-BDVCJXTV.js");
3823
3863
  for (const item of orphaned) {
3824
3864
  if (batch.settled) return;
3825
3865
  try {
@@ -4608,4 +4648,4 @@ export {
4608
4648
  incomingCallsService,
4609
4649
  outgoingCallsService
4610
4650
  };
4611
- //# sourceMappingURL=chunk-KY4PXYSO.js.map
4651
+ //# sourceMappingURL=chunk-N3K2SFEI.js.map