@wrongstack/tools 0.260.0 → 0.265.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 (88) hide show
  1. package/dist/audit.js +154 -10
  2. package/dist/audit.js.map +1 -1
  3. package/dist/bash.js +138 -2
  4. package/dist/bash.js.map +1 -1
  5. package/dist/batch-tool-use.js +1 -0
  6. package/dist/batch-tool-use.js.map +1 -1
  7. package/dist/builtin.d.ts +20 -1
  8. package/dist/builtin.js +674 -333
  9. package/dist/builtin.js.map +1 -1
  10. package/dist/circuit-breaker.d.ts +20 -0
  11. package/dist/circuit-breaker.js +40 -2
  12. package/dist/circuit-breaker.js.map +1 -1
  13. package/dist/codebase-index/index.d.ts +16 -0
  14. package/dist/codebase-index/index.js +62 -27
  15. package/dist/codebase-index/index.js.map +1 -1
  16. package/dist/codebase-index/worker.js +59 -27
  17. package/dist/codebase-index/worker.js.map +1 -1
  18. package/dist/diff.js +14 -6
  19. package/dist/diff.js.map +1 -1
  20. package/dist/document.js +18 -11
  21. package/dist/document.js.map +1 -1
  22. package/dist/edit.js +22 -14
  23. package/dist/edit.js.map +1 -1
  24. package/dist/exec.js +140 -3
  25. package/dist/exec.js.map +1 -1
  26. package/dist/fetch.d.ts +19 -1
  27. package/dist/fetch.js +2 -1
  28. package/dist/fetch.js.map +1 -1
  29. package/dist/format.js +153 -10
  30. package/dist/format.js.map +1 -1
  31. package/dist/git.js +1 -0
  32. package/dist/git.js.map +1 -1
  33. package/dist/glob.js +14 -6
  34. package/dist/glob.js.map +1 -1
  35. package/dist/grep.js +14 -6
  36. package/dist/grep.js.map +1 -1
  37. package/dist/index.d.ts +55 -3
  38. package/dist/index.js +833 -336
  39. package/dist/index.js.map +1 -1
  40. package/dist/install.js +154 -10
  41. package/dist/install.js.map +1 -1
  42. package/dist/json.js +2 -0
  43. package/dist/json.js.map +1 -1
  44. package/dist/lint.js +153 -10
  45. package/dist/lint.js.map +1 -1
  46. package/dist/logs.js +14 -6
  47. package/dist/logs.js.map +1 -1
  48. package/dist/memory.js +1 -0
  49. package/dist/memory.js.map +1 -1
  50. package/dist/mode.js +1 -0
  51. package/dist/mode.js.map +1 -1
  52. package/dist/outdated.js +16 -7
  53. package/dist/outdated.js.map +1 -1
  54. package/dist/pack.js +643 -332
  55. package/dist/pack.js.map +1 -1
  56. package/dist/patch.js +14 -6
  57. package/dist/patch.js.map +1 -1
  58. package/dist/process-registry.d.ts +56 -2
  59. package/dist/process-registry.js +138 -3
  60. package/dist/process-registry.js.map +1 -1
  61. package/dist/read.js +24 -18
  62. package/dist/read.js.map +1 -1
  63. package/dist/replace.js +14 -6
  64. package/dist/replace.js.map +1 -1
  65. package/dist/scaffold.js +14 -6
  66. package/dist/scaffold.js.map +1 -1
  67. package/dist/search.js +3 -3
  68. package/dist/search.js.map +1 -1
  69. package/dist/test.js +153 -10
  70. package/dist/test.js.map +1 -1
  71. package/dist/todo.js +1 -0
  72. package/dist/todo.js.map +1 -1
  73. package/dist/tool-help.js +1 -0
  74. package/dist/tool-help.js.map +1 -1
  75. package/dist/tool-icons.d.ts +20 -0
  76. package/dist/tool-icons.js +130 -0
  77. package/dist/tool-icons.js.map +1 -0
  78. package/dist/tool-search.js +1 -0
  79. package/dist/tool-search.js.map +1 -1
  80. package/dist/tool-use.js +1 -0
  81. package/dist/tool-use.js.map +1 -1
  82. package/dist/tree.js +14 -6
  83. package/dist/tree.js.map +1 -1
  84. package/dist/typecheck.js +153 -10
  85. package/dist/typecheck.js.map +1 -1
  86. package/dist/write.js +22 -14
  87. package/dist/write.js.map +1 -1
  88. package/package.json +6 -2
@@ -2,6 +2,7 @@ import { parentPort } from 'node:worker_threads';
2
2
  import { expectDefined, resolveWstackPaths, compileGlob, truncate } from '@wrongstack/core';
3
3
  import * as fs3 from 'node:fs/promises';
4
4
  import * as path4 from 'node:path';
5
+ import { toErrorMessage } from '@wrongstack/core/utils';
5
6
  import { createRequire } from 'node:module';
6
7
  import * as fs from 'node:fs';
7
8
  import { writeFileSync, mkdirSync } from 'node:fs';
@@ -235,7 +236,7 @@ function loadDatabaseSync() {
235
236
  DatabaseSyncCtor = req("node:sqlite").DatabaseSync;
236
237
  } catch (err) {
237
238
  throw new Error(
238
- `The codebase index needs Node's built-in SQLite (node:sqlite), available since Node 22.5. This runtime doesn't provide it: ${err instanceof Error ? err.message : String(err)}`
239
+ `The codebase index needs Node's built-in SQLite (node:sqlite), available since Node 22.5. This runtime doesn't provide it: ${toErrorMessage(err)}`
239
240
  );
240
241
  }
241
242
  return DatabaseSyncCtor;
@@ -681,39 +682,57 @@ var IndexStore = class {
681
682
  }
682
683
  });
683
684
  }
685
+ /**
686
+ * Bulk-insert refs for many source symbols in a single transaction.
687
+ *
688
+ * Unlike {@link insertRefs} this does NOT delete per source id — the caller
689
+ * (the indexer) has already cleared stale refs for the file via
690
+ * {@link deleteRefsForFile}, so the per-source DELETE would be redundant work
691
+ * repeated once per symbol. One transaction for the whole file instead of one
692
+ * per symbol turns an O(symbols) transaction count into O(1).
693
+ *
694
+ * Each ref's own {@link Ref.fromId} is used; pass an empty array to no-op.
695
+ */
696
+ insertRefsBatch(refs) {
697
+ if (refs.length === 0) return;
698
+ this.runWithRetry(() => {
699
+ const stmt = this.db.prepare(
700
+ `INSERT INTO refs(from_id, to_name, to_id, call_type, line)
701
+ VALUES (?, ?, ?, ?, ?)`
702
+ );
703
+ for (const ref of refs) {
704
+ stmt.run(ref.fromId, ref.toName, ref.toId ?? null, ref.callType, ref.line);
705
+ }
706
+ });
707
+ }
684
708
  /**
685
709
  * Delete all refs whose source symbols are in a given file.
686
710
  * Used when re-indexing a file to clear stale refs.
687
711
  */
688
712
  deleteRefsForFile(file) {
689
713
  this.runWithRetry(() => {
690
- const ids = this.db.prepare(
691
- "SELECT id FROM symbols WHERE file = ?"
692
- ).all(file);
693
- if (!ids.length) return;
694
- const placeholders = ids.map(() => "?").join(",");
695
- this.db.prepare(`DELETE FROM refs WHERE from_id IN (${placeholders})`).run(...ids.map((r) => r.id));
714
+ this.db.prepare(
715
+ "DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file = ?)"
716
+ ).run(file);
696
717
  });
697
718
  }
698
719
  /**
699
720
  * Resolve `to_name` → `to_id` for all refs that have a name but no id.
700
721
  * Call this after all symbols have been inserted to fill in cross-references.
722
+ *
723
+ * Single statement: the `to_name IN (SELECT name FROM symbols)` guard restricts
724
+ * the UPDATE to refs that will actually resolve, so `.changes` counts only refs
725
+ * that found a target — matching the previous per-row loop's return value.
701
726
  */
702
727
  resolveRefs() {
703
728
  return this.runWithRetry(() => {
704
- const unresolved = this.db.prepare(
705
- "SELECT id, to_name FROM refs WHERE to_id IS NULL AND to_name IS NOT NULL"
706
- ).all();
707
- let resolved = 0;
708
- for (const row of unresolved) {
709
- const target = this.db.prepare("SELECT id FROM symbols WHERE name = ? LIMIT 1").all(row.to_name);
710
- const first = target[0];
711
- if (first) {
712
- this.db.prepare("UPDATE refs SET to_id = ? WHERE id = ?").run(first.id, row.id);
713
- resolved++;
714
- }
715
- }
716
- return resolved;
729
+ const result = this.db.prepare(
730
+ `UPDATE refs SET to_id = (
731
+ SELECT id FROM symbols WHERE name = refs.to_name LIMIT 1
732
+ ) WHERE to_id IS NULL AND to_name IS NOT NULL
733
+ AND to_name IN (SELECT name FROM symbols)`
734
+ ).run();
735
+ return result.changes ?? 0;
717
736
  });
718
737
  }
719
738
  /**
@@ -820,7 +839,7 @@ function getSignature(node, sourceFile) {
820
839
  }
821
840
  function getJsDoc(node, sourceFile) {
822
841
  const fullText = sourceFile.getFullText();
823
- const nodePos = node.getFullWidth();
842
+ const nodePos = node.getFullStart();
824
843
  const comments = ts.getLeadingCommentRanges(fullText, nodePos);
825
844
  if (!comments) return "";
826
845
  for (const range of comments) {
@@ -2188,13 +2207,26 @@ async function runIndexerWithStore(store, opts) {
2188
2207
  symbolsIndexed += count;
2189
2208
  langStats[lang] = (langStats[lang] ?? 0) + count;
2190
2209
  if (parsed.refs && parsed.refs.length > 0) {
2191
- for (let i = 0; i < symbolsWithIds.length; i++) {
2192
- const sym = expectDefined(symbolsWithIds[i]);
2193
- const symRefs = parsed.refs.filter((r) => r.line === sym.line);
2194
- if (symRefs.length > 0) {
2195
- const refsWithFromId = symRefs.map((r) => ({ ...r, fromId: sym.id }));
2196
- store.insertRefs(sym.id, refsWithFromId);
2210
+ const refsByLine = /* @__PURE__ */ new Map();
2211
+ for (const r of parsed.refs) {
2212
+ let arr = refsByLine.get(r.line);
2213
+ if (!arr) {
2214
+ arr = [];
2215
+ refsByLine.set(r.line, arr);
2197
2216
  }
2217
+ arr.push(r);
2218
+ }
2219
+ const batch = [];
2220
+ for (const sym of symbolsWithIds) {
2221
+ const symRefs = refsByLine.get(sym.line);
2222
+ if (symRefs) {
2223
+ for (const r of symRefs) {
2224
+ batch.push({ ...r, fromId: sym.id });
2225
+ }
2226
+ }
2227
+ }
2228
+ if (batch.length > 0) {
2229
+ store.insertRefsBatch(batch);
2198
2230
  }
2199
2231
  }
2200
2232
  store.upsertFile({