@wrongstack/tools 0.89.1 → 0.104.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 (58) hide show
  1. package/dist/audit.js +1 -7
  2. package/dist/audit.js.map +1 -1
  3. package/dist/{background-indexer-DYm1FUxK.d.ts → background-indexer-C2014mH0.d.ts} +1 -1
  4. package/dist/bash.js +6 -18
  5. package/dist/bash.js.map +1 -1
  6. package/dist/builtin.js +187 -133
  7. package/dist/builtin.js.map +1 -1
  8. package/dist/circuit-breaker.js +1 -1
  9. package/dist/circuit-breaker.js.map +1 -1
  10. package/dist/codebase-index/index.d.ts +2 -21
  11. package/dist/codebase-index/index.js +25 -69
  12. package/dist/codebase-index/index.js.map +1 -1
  13. package/dist/diff.js.map +1 -1
  14. package/dist/document.js +1 -1
  15. package/dist/document.js.map +1 -1
  16. package/dist/edit.js.map +1 -1
  17. package/dist/exec.js +3 -15
  18. package/dist/exec.js.map +1 -1
  19. package/dist/fetch.js.map +1 -1
  20. package/dist/format.js +4 -16
  21. package/dist/format.js.map +1 -1
  22. package/dist/git.js +1 -7
  23. package/dist/git.js.map +1 -1
  24. package/dist/glob.js.map +1 -1
  25. package/dist/grep.js +1 -7
  26. package/dist/grep.js.map +1 -1
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +301 -136
  29. package/dist/index.js.map +1 -1
  30. package/dist/install.js +4 -16
  31. package/dist/install.js.map +1 -1
  32. package/dist/lint.js +4 -16
  33. package/dist/lint.js.map +1 -1
  34. package/dist/logs.js.map +1 -1
  35. package/dist/memory.d.ts +29 -1
  36. package/dist/memory.js +115 -4
  37. package/dist/memory.js.map +1 -1
  38. package/dist/outdated.js.map +1 -1
  39. package/dist/pack.js +187 -133
  40. package/dist/pack.js.map +1 -1
  41. package/dist/patch.js.map +1 -1
  42. package/dist/process-registry.js +2 -7
  43. package/dist/process-registry.js.map +1 -1
  44. package/dist/read.js +1 -1
  45. package/dist/read.js.map +1 -1
  46. package/dist/replace.js +1 -7
  47. package/dist/replace.js.map +1 -1
  48. package/dist/scaffold.js.map +1 -1
  49. package/dist/search.js +2 -7
  50. package/dist/search.js.map +1 -1
  51. package/dist/test.js +4 -16
  52. package/dist/test.js.map +1 -1
  53. package/dist/tree.js +1 -7
  54. package/dist/tree.js.map +1 -1
  55. package/dist/typecheck.js +4 -16
  56. package/dist/typecheck.js.map +1 -1
  57. package/dist/write.js.map +1 -1
  58. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  // src/circuit-breaker.ts
2
2
  var DEFAULT_MAX_CONSECUTIVE_FAILURES = 5;
3
- var DEFAULT_SLOW_CALL_THRESHOLD_MS = 6e4;
3
+ var DEFAULT_SLOW_CALL_THRESHOLD_MS = 18e4;
4
4
  var DEFAULT_MAX_SLOW_CALLS = 3;
5
5
  var DEFAULT_WINDOW_MS = 6e4;
6
6
  var DEFAULT_MAX_CALLS_PER_WINDOW = 30;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"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","file":"circuit-breaker.js","sourcesContent":["/**\n * CircuitBreaker — prevents runaway bash/exec tool chains by:\n *\n * - Tripping on consecutive failures (models that keep repeating the\n * same failing command, e.g. `npm install` with wrong args in a loop)\n * - Tripping on slow call ratio (too many long-running commands suggest\n * a hung subprocess that the model doesn't know how to kill)\n * - Rate-limiting bursts (rapid succession of commands without reading\n * output suggests the model isn't processing results)\n * - Auto-recovering after a cooldown period so a fixed model can resume\n *\n * The breaker is owned by the ProcessRegistry so any tool that registers\n * a process participates in the same circuit. \"Per-tool\" isolation is\n * intentionally NOT implemented — the model treats bash/exec as one\n * resource pool; isolating them would let the model route around the\n * breaker by alternating which tool it uses.\n */\n\nexport interface CircuitBreakerConfig {\n /**\n * Consecutive failures before trip. Default: 5.\n * A single success resets this counter to 0.\n */\n maxConsecutiveFailures?: number | undefined;\n /**\n * Slow-call threshold in ms. A call that runs longer than this is\n * counted as \"slow\". Default: 60_000 (1 minute).\n */\n slowCallThresholdMs?: number | undefined;\n /**\n * Max slow calls before trip (within the sliding window). Default: 3.\n */\n maxSlowCalls?: number | undefined;\n /**\n * Sliding window for rate-limit and slow-call counting, in ms.\n * Default: 60_000 (1 minute).\n */\n windowMs?: number | undefined;\n /**\n * Max calls within the sliding window. Default: 30.\n * Burst exceeding this trips the breaker immediately.\n */\n maxCallsPerWindow?: number | undefined;\n /**\n * Cooldown before auto-recovery attempt, in ms. Default: 30_000 (30s).\n * After this the breaker enters \"half-open\" state and allows one call\n * through to test whether the problem is resolved.\n */\n cooldownMs?: number | undefined;\n}\n\ninterface CallRecord {\n at: number;\n /** True if the call threw or returned an is_error result. */\n failed: boolean;\n /** True if elapsed time exceeded slowCallThresholdMs. */\n slow: boolean;\n}\n\ntype BreakerState = 'closed' | 'open' | 'half-open';\n\nconst DEFAULT_MAX_CONSECUTIVE_FAILURES = 5;\nconst DEFAULT_SLOW_CALL_THRESHOLD_MS = 60_000;\nconst DEFAULT_MAX_SLOW_CALLS = 3;\nconst DEFAULT_WINDOW_MS = 60_000;\nconst DEFAULT_MAX_CALLS_PER_WINDOW = 30;\nconst DEFAULT_COOLDOWN_MS = 30_000;\n\nexport interface CircuitBreakerSnapshot {\n state: 'closed' | 'open' | 'half-open';\n consecutiveFailures: number;\n slowCallsInWindow: number;\n callsInWindow: number;\n windowMs: number;\n cooldownRemainingMs: number | null;\n lastFailureAt: number | null;\n lastSlowAt: number | null;\n}\n\nexport class CircuitBreaker {\n private readonly maxConsecutiveFailures: number;\n private readonly slowCallThresholdMs: number;\n private readonly maxSlowCalls: number;\n private readonly windowMs: number;\n private readonly maxCallsPerWindow: number;\n private readonly cooldownMs: number;\n\n private state: BreakerState = 'closed';\n private consecutiveFailures = 0;\n private window: CallRecord[] = [];\n private lastFailureAt: number | null = null;\n private lastSlowAt: number | null = null;\n /** Timestamp when the breaker was opened (for cooldown calculation). */\n private openedAt: number | null = null;\n\n constructor(config: CircuitBreakerConfig = {}) {\n this.maxConsecutiveFailures = config.maxConsecutiveFailures ?? DEFAULT_MAX_CONSECUTIVE_FAILURES;\n this.slowCallThresholdMs = config.slowCallThresholdMs ?? DEFAULT_SLOW_CALL_THRESHOLD_MS;\n this.maxSlowCalls = config.maxSlowCalls ?? DEFAULT_MAX_SLOW_CALLS;\n this.windowMs = config.windowMs ?? DEFAULT_WINDOW_MS;\n this.maxCallsPerWindow = config.maxCallsPerWindow ?? DEFAULT_MAX_CALLS_PER_WINDOW;\n this.cooldownMs = config.cooldownMs ?? DEFAULT_COOLDOWN_MS;\n }\n\n /**\n * Returns true if the circuit allows a new call to proceed.\n * When false, callers should abort the tool call and return a\n * circuit-breaker error instead of spawning a process.\n */\n get canProceed(): boolean {\n this._checkStateTransition();\n return this.state !== 'open';\n }\n\n /**\n * Snapshot of the current breaker state for observability (`/kill`).\n */\n snapshot(): CircuitBreakerSnapshot {\n this._checkStateTransition();\n const now = Date.now();\n let cooldownRemaining: number | null = null;\n if (this.openedAt !== null && this.state === 'open') {\n const elapsed = now - this.openedAt;\n cooldownRemaining = Math.max(0, this.cooldownMs - elapsed);\n }\n return {\n state: this.state,\n consecutiveFailures: this.consecutiveFailures,\n slowCallsInWindow: this.window.filter((c) => c.slow).length,\n callsInWindow: this.window.length,\n windowMs: this.windowMs,\n cooldownRemainingMs: cooldownRemaining,\n lastFailureAt: this.lastFailureAt,\n lastSlowAt: this.lastSlowAt,\n };\n }\n\n /**\n * Call this BEFORE spawning a bash/exec process.\n * Returns true if the call is allowed; false if the breaker is open.\n * When false, callers MUST NOT spawn a process.\n */\n beforeCall(): boolean {\n this._checkStateTransition();\n if (this.state === 'open') return false;\n return true;\n }\n\n /**\n * Call this AFTER a bash/exec process finishes (success or failure).\n * `durationMs` is the wall-clock time the process ran.\n * `failed` is true when the process returned a non-zero exit code or\n * threw an exception before spawning.\n */\n afterCall(durationMs: number, failed: boolean): void {\n const now = Date.now();\n\n if (this.state === 'half-open') {\n // First call through after cooldown — if it failed, go back to open.\n if (failed) {\n this._trip();\n return;\n }\n // Success in half-open → reset to closed.\n this._reset();\n return;\n }\n\n // Prune old records outside the sliding window.\n this._pruneWindow(now);\n\n const slow = durationMs >= this.slowCallThresholdMs;\n this.window.push({ at: now, failed, slow });\n\n if (failed) {\n this.consecutiveFailures++;\n this.lastFailureAt = now;\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n this._trip();\n }\n return;\n }\n\n // Success: reset consecutive failure counter.\n this.consecutiveFailures = 0;\n\n if (slow) {\n this.lastSlowAt = now;\n const slowCount = this.window.filter((c) => c.slow).length;\n if (slowCount >= this.maxSlowCalls) {\n this._trip();\n }\n }\n\n const callCount = this.window.length;\n if (callCount >= this.maxCallsPerWindow) {\n // Rate limit exceeded. This is a soft trip — we reset the window\n // and let the next call try immediately (the caller will still see\n // canProceed=false until the window drains naturally).\n this._trip();\n }\n }\n\n /** Force the breaker open. Used by /kill force and Ctrl+C. */\n forceOpen(): void {\n this._trip();\n }\n\n /** Force a reset to closed. Used by tests and /kill reset. */\n forceReset(): void {\n this._reset();\n }\n\n private _trip(): void {\n if (this.state === 'open') return; // already open\n this.state = 'open';\n this.openedAt = Date.now();\n }\n\n private _reset(): void {\n this.state = 'closed';\n this.consecutiveFailures = 0;\n this.window = [];\n this.openedAt = null;\n }\n\n /** Transition from open → half-open when cooldown elapses. */\n private _checkStateTransition(): void {\n if (this.state !== 'open' || this.openedAt === null) return;\n const elapsed = Date.now() - this.openedAt;\n if (elapsed >= this.cooldownMs) {\n this.state = 'half-open';\n this.openedAt = null;\n }\n }\n\n private _pruneWindow(now: number): void {\n const cutoff = now - this.windowMs;\n this.window = this.window.filter((c) => c.at >= cutoff);\n }\n}"]}
1
+ {"version":3,"sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"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","file":"circuit-breaker.js","sourcesContent":["/**\n * CircuitBreaker — prevents runaway bash/exec tool chains by:\n *\n * - Tripping on consecutive failures (models that keep repeating the\n * same failing command, e.g. `npm install` with wrong args in a loop)\n * - Tripping on slow call ratio (too many long-running commands suggest\n * a hung subprocess that the model doesn't know how to kill)\n * - Rate-limiting bursts (rapid succession of commands without reading\n * output suggests the model isn't processing results)\n * - Auto-recovering after a cooldown period so a fixed model can resume\n *\n * The breaker is owned by the ProcessRegistry so any tool that registers\n * a process participates in the same circuit. \"Per-tool\" isolation is\n * intentionally NOT implemented — the model treats bash/exec as one\n * resource pool; isolating them would let the model route around the\n * breaker by alternating which tool it uses.\n */\n\nexport interface CircuitBreakerConfig {\n /**\n * Consecutive failures before trip. Default: 5.\n * A single success resets this counter to 0.\n */\n maxConsecutiveFailures?: number | undefined;\n /**\n * Slow-call threshold in ms. A call that runs longer than this is\n * counted as \"slow\". Default: 60_000 (1 minute).\n */\n slowCallThresholdMs?: number | undefined;\n /**\n * Max slow calls before trip (within the sliding window). Default: 3.\n */\n maxSlowCalls?: number | undefined;\n /**\n * Sliding window for rate-limit and slow-call counting, in ms.\n * Default: 60_000 (1 minute).\n */\n windowMs?: number | undefined;\n /**\n * Max calls within the sliding window. Default: 30.\n * Burst exceeding this trips the breaker immediately.\n */\n maxCallsPerWindow?: number | undefined;\n /**\n * Cooldown before auto-recovery attempt, in ms. Default: 30_000 (30s).\n * After this the breaker enters \"half-open\" state and allows one call\n * through to test whether the problem is resolved.\n */\n cooldownMs?: number | undefined;\n}\n\ninterface CallRecord {\n at: number;\n /** True if the call threw or returned an is_error result. */\n failed: boolean;\n /** True if elapsed time exceeded slowCallThresholdMs. */\n slow: boolean;\n}\n\ntype BreakerState = 'closed' | 'open' | 'half-open';\n\nconst DEFAULT_MAX_CONSECUTIVE_FAILURES = 5;\nconst DEFAULT_SLOW_CALL_THRESHOLD_MS = 180_000;\n// 3 minutes — balanced against the 5-minute bash timeout. Commands\n// running <3min are normal; 3-5min are \"slow\" and count toward the\n// breaker. 3 consecutive slow calls trip the circuit.\nconst DEFAULT_MAX_SLOW_CALLS = 3;\nconst DEFAULT_WINDOW_MS = 60_000;\nconst DEFAULT_MAX_CALLS_PER_WINDOW = 30;\nconst DEFAULT_COOLDOWN_MS = 30_000;\n\nexport interface CircuitBreakerSnapshot {\n state: 'closed' | 'open' | 'half-open';\n consecutiveFailures: number;\n slowCallsInWindow: number;\n callsInWindow: number;\n windowMs: number;\n cooldownRemainingMs: number | null;\n lastFailureAt: number | null;\n lastSlowAt: number | null;\n}\n\nexport class CircuitBreaker {\n private readonly maxConsecutiveFailures: number;\n private readonly slowCallThresholdMs: number;\n private readonly maxSlowCalls: number;\n private readonly windowMs: number;\n private readonly maxCallsPerWindow: number;\n private readonly cooldownMs: number;\n\n private state: BreakerState = 'closed';\n private consecutiveFailures = 0;\n private window: CallRecord[] = [];\n private lastFailureAt: number | null = null;\n private lastSlowAt: number | null = null;\n /** Timestamp when the breaker was opened (for cooldown calculation). */\n private openedAt: number | null = null;\n\n constructor(config: CircuitBreakerConfig = {}) {\n this.maxConsecutiveFailures = config.maxConsecutiveFailures ?? DEFAULT_MAX_CONSECUTIVE_FAILURES;\n this.slowCallThresholdMs = config.slowCallThresholdMs ?? DEFAULT_SLOW_CALL_THRESHOLD_MS;\n this.maxSlowCalls = config.maxSlowCalls ?? DEFAULT_MAX_SLOW_CALLS;\n this.windowMs = config.windowMs ?? DEFAULT_WINDOW_MS;\n this.maxCallsPerWindow = config.maxCallsPerWindow ?? DEFAULT_MAX_CALLS_PER_WINDOW;\n this.cooldownMs = config.cooldownMs ?? DEFAULT_COOLDOWN_MS;\n }\n\n /**\n * Returns true if the circuit allows a new call to proceed.\n * When false, callers should abort the tool call and return a\n * circuit-breaker error instead of spawning a process.\n */\n get canProceed(): boolean {\n this._checkStateTransition();\n return this.state !== 'open';\n }\n\n /**\n * Snapshot of the current breaker state for observability (`/kill`).\n */\n snapshot(): CircuitBreakerSnapshot {\n this._checkStateTransition();\n const now = Date.now();\n let cooldownRemaining: number | null = null;\n if (this.openedAt !== null && this.state === 'open') {\n const elapsed = now - this.openedAt;\n cooldownRemaining = Math.max(0, this.cooldownMs - elapsed);\n }\n return {\n state: this.state,\n consecutiveFailures: this.consecutiveFailures,\n slowCallsInWindow: this.window.filter((c) => c.slow).length,\n callsInWindow: this.window.length,\n windowMs: this.windowMs,\n cooldownRemainingMs: cooldownRemaining,\n lastFailureAt: this.lastFailureAt,\n lastSlowAt: this.lastSlowAt,\n };\n }\n\n /**\n * Call this BEFORE spawning a bash/exec process.\n * Returns true if the call is allowed; false if the breaker is open.\n * When false, callers MUST NOT spawn a process.\n */\n beforeCall(): boolean {\n this._checkStateTransition();\n if (this.state === 'open') return false;\n return true;\n }\n\n /**\n * Call this AFTER a bash/exec process finishes (success or failure).\n * `durationMs` is the wall-clock time the process ran.\n * `failed` is true when the process returned a non-zero exit code or\n * threw an exception before spawning.\n */\n afterCall(durationMs: number, failed: boolean): void {\n const now = Date.now();\n\n if (this.state === 'half-open') {\n // First call through after cooldown — if it failed, go back to open.\n if (failed) {\n this._trip();\n return;\n }\n // Success in half-open → reset to closed.\n this._reset();\n return;\n }\n\n // Prune old records outside the sliding window.\n this._pruneWindow(now);\n\n const slow = durationMs >= this.slowCallThresholdMs;\n this.window.push({ at: now, failed, slow });\n\n if (failed) {\n this.consecutiveFailures++;\n this.lastFailureAt = now;\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n this._trip();\n }\n return;\n }\n\n // Success: reset consecutive failure counter.\n this.consecutiveFailures = 0;\n\n if (slow) {\n this.lastSlowAt = now;\n const slowCount = this.window.filter((c) => c.slow).length;\n if (slowCount >= this.maxSlowCalls) {\n this._trip();\n }\n }\n\n const callCount = this.window.length;\n if (callCount >= this.maxCallsPerWindow) {\n // Rate limit exceeded. This is a soft trip — we reset the window\n // and let the next call try immediately (the caller will still see\n // canProceed=false until the window drains naturally).\n this._trip();\n }\n }\n\n /** Force the breaker open. Used by /kill force and Ctrl+C. */\n forceOpen(): void {\n this._trip();\n }\n\n /** Force a reset to closed. Used by tests and /kill reset. */\n forceReset(): void {\n this._reset();\n }\n\n private _trip(): void {\n if (this.state === 'open') return; // already open\n this.state = 'open';\n this.openedAt = Date.now();\n }\n\n private _reset(): void {\n this.state = 'closed';\n this.consecutiveFailures = 0;\n this.window = [];\n this.openedAt = null;\n }\n\n /** Transition from open → half-open when cooldown elapses. */\n private _checkStateTransition(): void {\n if (this.state !== 'open' || this.openedAt === null) return;\n const elapsed = Date.now() - this.openedAt;\n if (elapsed >= this.cooldownMs) {\n this.state = 'half-open';\n this.openedAt = null;\n }\n }\n\n private _pruneWindow(now: number): void {\n const cutoff = now - this.windowMs;\n this.window = this.window.filter((c) => c.at >= cutoff);\n }\n}"]}
@@ -1,18 +1,7 @@
1
- import { I as IndexResult, d as Symbol, F as FileMeta, e as SymbolKind, f as SymbolLang, c as SearchResult, b as IndexStats, R as Ref } from '../background-indexer-DYm1FUxK.js';
2
- export { a as FileSymbols, S as SCHEMA_VERSION, g as cancelPendingReindexes, h as codebaseIndexTool, i as codebaseSearchTool, j as codebaseStatsTool, k as enqueueReindex, l as getIndexState, m as isIndexReady, n as isIndexableFile, o as isIndexing, p as onIndexStateChange, r as runStartupIndex } from '../background-indexer-DYm1FUxK.js';
1
+ import { I as IndexResult, S as Symbol, F as FileMeta, a as SymbolKind, b as SymbolLang, c as SearchResult, d as IndexStats, R as Ref } from '../background-indexer-C2014mH0.js';
2
+ export { e as FileSymbols, f as SCHEMA_VERSION, g as cancelPendingReindexes, h as codebaseIndexTool, i as codebaseSearchTool, j as codebaseStatsTool, k as enqueueReindex, l as getIndexState, m as isIndexReady, n as isIndexableFile, o as isIndexing, p as onIndexStateChange, r as runStartupIndex } from '../background-indexer-C2014mH0.js';
3
3
  import { Context } from '@wrongstack/core';
4
4
 
5
- /**
6
- * Main indexing orchestrator.
7
- *
8
- * Given a project root and a list of files:
9
- * 1. Parse each file with the appropriate parser (TS, Go, Python, Rust, JSON, YAML)
10
- * 2. Delete old symbols for changed/deleted files
11
- * 3. Insert new symbols
12
- * 4. Update file metadata
13
- * 5. Return index statistics
14
- */
15
-
16
5
  interface IndexerOptions {
17
6
  projectRoot: string;
18
7
  files?: string[] | undefined;
@@ -25,14 +14,6 @@ interface IndexerOptions {
25
14
  /** Run a full or incremental index and return statistics. */
26
15
  declare function runIndexer(_ctx: Context, opts: IndexerOptions): Promise<IndexResult>;
27
16
 
28
- /**
29
- * SQLite storage layer for the codebase index.
30
- *
31
- * Uses `node:sqlite` (synchronous API — DatabaseSync class).
32
- * Database file: ~/.wrongstack/projects/<hash>/codebase-index/index.db — kept
33
- * out of the repo so it never clutters the working tree or needs gitignoring.
34
- */
35
-
36
17
  /**
37
18
  * Resolve the per-project index directory. By default it lives under the
38
19
  * global project dir (`~/.wrongstack/projects/<hash>/codebase-index`),
@@ -1,19 +1,14 @@
1
+ import { resolveWstackPaths, expectDefined, compileGlob } from '@wrongstack/core';
1
2
  import * as fs3 from 'node:fs/promises';
2
3
  import * as path4 from 'node:path';
3
- import { resolveWstackPaths, compileGlob } from '@wrongstack/core';
4
4
  import { createRequire } from 'node:module';
5
5
  import * as fs from 'node:fs';
6
- import { mkdirSync, writeFileSync } from 'node:fs';
6
+ import { writeFileSync, mkdirSync } from 'node:fs';
7
7
  import * as ts from 'typescript';
8
8
  import { execFileSync, spawnSync } from 'node:child_process';
9
9
  import * as os from 'node:os';
10
10
 
11
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
12
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
13
- }) : x)(function(x) {
14
- if (typeof require !== "undefined") return require.apply(this, arguments);
15
- throw Error('Dynamic require of "' + x + '" is not supported');
16
- });
11
+ // src/codebase-index/indexer.ts
17
12
 
18
13
  // src/codebase-index/schema.ts
19
14
  var SCHEMA_VERSION = 1;
@@ -81,12 +76,6 @@ function internalKindToLspKind(k) {
81
76
  }
82
77
 
83
78
  // src/codebase-index/writer.ts
84
- function expectDefined(value) {
85
- if (value === null || value === void 0) {
86
- throw new Error("Expected value to be defined");
87
- }
88
- return value;
89
- }
90
79
  var DB_FILE = "index.db";
91
80
  function resolveIndexDir(projectRoot, override) {
92
81
  return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
@@ -1144,12 +1133,6 @@ function syncPyParse(filePath, lang) {
1144
1133
  return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
1145
1134
  }
1146
1135
  }
1147
- function expectDefined2(value) {
1148
- if (value === null || value === void 0) {
1149
- throw new Error("Expected value to be defined");
1150
- }
1151
- return value;
1152
- }
1153
1136
  function parseSymbols4(opts) {
1154
1137
  const { file, content, lang } = opts;
1155
1138
  const nativeAvailable = checkNativeParser();
@@ -1189,8 +1172,7 @@ function tryNativeParse(file, content) {
1189
1172
  const toolsDir = path4.join(process.cwd(), "tools");
1190
1173
  const crateDir = path4.join(toolsDir, "syn-parser");
1191
1174
  const tmpFile = path4.join(crateDir, "src", "input.rs");
1192
- const { writeFileSync: writeFileSync3 } = __require("node:fs");
1193
- writeFileSync3(tmpFile, content, "utf8");
1175
+ writeFileSync(tmpFile, content, "utf8");
1194
1176
  const result = spawnSync(
1195
1177
  "cargo",
1196
1178
  ["run", "--manifest-path", path4.join(toolsDir, "Cargo.toml")],
@@ -1238,7 +1220,7 @@ function regexParse(opts) {
1238
1220
  let hi = lineOffsets.length - 1;
1239
1221
  while (lo < hi) {
1240
1222
  const mid = lo + hi + 1 >>> 1;
1241
- if (expectDefined2(lineOffsets[mid]) <= offset) lo = mid;
1223
+ if (expectDefined(lineOffsets[mid]) <= offset) lo = mid;
1242
1224
  else hi = mid - 1;
1243
1225
  }
1244
1226
  return lo + 1;
@@ -1250,7 +1232,7 @@ function regexParse(opts) {
1250
1232
  for (const pattern of RS_PATTERNS) {
1251
1233
  pattern.regex.lastIndex = 0;
1252
1234
  for (let match = pattern.regex.exec(content); match !== null; match = pattern.regex.exec(content)) {
1253
- const name = expectDefined2(match[1]);
1235
+ const name = expectDefined(match[1]);
1254
1236
  const offset = match.index ?? 0;
1255
1237
  const line = lineFromOffset(offset);
1256
1238
  const col = offset - (lineOffsets[line - 1] ?? 0);
@@ -1280,12 +1262,6 @@ function regexParse(opts) {
1280
1262
  });
1281
1263
  return { file, lang, symbols: deduped, mtimeMs: Date.now() };
1282
1264
  }
1283
- function expectDefined3(value) {
1284
- if (value === null || value === void 0) {
1285
- throw new Error("Expected value to be defined");
1286
- }
1287
- return value;
1288
- }
1289
1265
  function parseSymbols5(opts) {
1290
1266
  const { file, content, lang } = opts;
1291
1267
  try {
@@ -1312,14 +1288,14 @@ function regexParse2(opts) {
1312
1288
  let hi = lineOffsets.length - 1;
1313
1289
  while (lo < hi) {
1314
1290
  const mid = lo + hi + 1 >>> 1;
1315
- if (expectDefined3(lineOffsets[mid]) <= offset) lo = mid;
1291
+ if (expectDefined(lineOffsets[mid]) <= offset) lo = mid;
1316
1292
  else hi = mid - 1;
1317
1293
  }
1318
1294
  return lo + 1;
1319
1295
  }
1320
1296
  const rootMatch = content.match(/^\s*\{/m);
1321
1297
  if (rootMatch) {
1322
- const offset = expectDefined3(rootMatch.index);
1298
+ const offset = expectDefined(rootMatch.index);
1323
1299
  const line = lineFromOffset(offset);
1324
1300
  symbols.push(
1325
1301
  makeSymbol({
@@ -1335,7 +1311,7 @@ function regexParse2(opts) {
1335
1311
  }
1336
1312
  const topLevelKeyRegex = /^\s*"([^"]+)"\s*:/gm;
1337
1313
  for (let match = topLevelKeyRegex.exec(content); match !== null; match = topLevelKeyRegex.exec(content)) {
1338
- const key = expectDefined3(match[1]);
1314
+ const key = expectDefined(match[1]);
1339
1315
  const offset = match.index ?? 0;
1340
1316
  const line = lineFromOffset(offset);
1341
1317
  const col = offset - (lineOffsets[line - 1] ?? 0);
@@ -1382,7 +1358,7 @@ function regexParse2(opts) {
1382
1358
  const defsRegex = /"\$defs"\s*:|"\$defs"\s*:/g;
1383
1359
  const defsMatch = defsRegex.exec(content);
1384
1360
  if (defsMatch !== null) {
1385
- const offset = expectDefined3(defsMatch.index);
1361
+ const offset = expectDefined(defsMatch.index);
1386
1362
  const line = lineFromOffset(offset);
1387
1363
  symbols.push(
1388
1364
  makeSymbol({
@@ -1407,7 +1383,7 @@ function regexParse2(opts) {
1407
1383
  for (let match = pat.exec(content); match !== null; match = pat.exec(content)) {
1408
1384
  const offset = match.index ?? 0;
1409
1385
  const line = lineFromOffset(offset);
1410
- const key = match[0]?.match(/"([^"]+)"/)?.[1] ?? expectDefined3(match[0]);
1386
+ const key = match[0]?.match(/"([^"]+)"/)?.[1] ?? expectDefined(match[0]);
1411
1387
  symbols.push(
1412
1388
  makeSymbol({
1413
1389
  name: key,
@@ -1426,12 +1402,12 @@ function regexParse2(opts) {
1426
1402
  function extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFromOffset) {
1427
1403
  const scriptsBlockRegex = /"scripts"\s*:\s*\{([^}]+)\}/g;
1428
1404
  for (let match = scriptsBlockRegex.exec(content); match !== null; match = scriptsBlockRegex.exec(content)) {
1429
- const blockContent = expectDefined3(match[0]);
1405
+ const blockContent = expectDefined(match[0]);
1430
1406
  const blockOffset = match.index ?? 0;
1431
1407
  const scriptKeyRegex = /"(\w[\w-]*)"\s*:/g;
1432
1408
  for (let scriptMatch = scriptKeyRegex.exec(blockContent); scriptMatch !== null; scriptMatch = scriptKeyRegex.exec(blockContent)) {
1433
- const key = expectDefined3(scriptMatch[1]);
1434
- const keyOffset = blockOffset + expectDefined3(scriptMatch.index);
1409
+ const key = expectDefined(scriptMatch[1]);
1410
+ const keyOffset = blockOffset + expectDefined(scriptMatch.index);
1435
1411
  const line = lineFromOffset(keyOffset);
1436
1412
  symbols.push(
1437
1413
  makeSymbol({
@@ -1450,12 +1426,12 @@ function extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFr
1450
1426
  function extractCompilerOptions(content, symbols, file, lang, lineOffsets, parentLine, lineFromOffset) {
1451
1427
  const optsBlockRegex = /"compilerOptions"\s*:\s*\{([^}]+)\}/g;
1452
1428
  for (let match = optsBlockRegex.exec(content); match !== null; match = optsBlockRegex.exec(content)) {
1453
- const blockContent = expectDefined3(match[0]);
1429
+ const blockContent = expectDefined(match[0]);
1454
1430
  const blockOffset = match.index ?? 0;
1455
1431
  const optKeyRegex = /"(\w[\w]*)"\s*:/g;
1456
1432
  for (let optMatch = optKeyRegex.exec(blockContent); optMatch !== null; optMatch = optKeyRegex.exec(blockContent)) {
1457
- const key = expectDefined3(optMatch[1]);
1458
- const keyOffset = blockOffset + expectDefined3(optMatch.index);
1433
+ const key = expectDefined(optMatch[1]);
1434
+ const keyOffset = blockOffset + expectDefined(optMatch.index);
1459
1435
  const line = lineFromOffset(keyOffset);
1460
1436
  if (line <= parentLine) continue;
1461
1437
  symbols.push(
@@ -1487,14 +1463,6 @@ function makeSymbol(opts) {
1487
1463
  text: `${opts.name} ${opts.signature}`.trim()
1488
1464
  };
1489
1465
  }
1490
-
1491
- // src/codebase-index/yaml-parser.ts
1492
- function expectDefined4(value) {
1493
- if (value === null || value === void 0) {
1494
- throw new Error("Expected value to be defined");
1495
- }
1496
- return value;
1497
- }
1498
1466
  function parseSymbols6(opts) {
1499
1467
  const { file, content, lang } = opts;
1500
1468
  try {
@@ -1516,14 +1484,14 @@ function regexParse3(opts) {
1516
1484
  let hi = lineOffsets.length - 1;
1517
1485
  while (lo < hi) {
1518
1486
  const mid = lo + hi + 1 >>> 1;
1519
- if (expectDefined4(lineOffsets[mid]) <= offset) lo = mid;
1487
+ if (expectDefined(lineOffsets[mid]) <= offset) lo = mid;
1520
1488
  else hi = mid - 1;
1521
1489
  }
1522
1490
  return lo + 1;
1523
1491
  }
1524
1492
  const anchorRegex = /&(\w[\w-]*)/g;
1525
1493
  for (let match = anchorRegex.exec(content); match !== null; match = anchorRegex.exec(content)) {
1526
- const name = expectDefined4(match[1]);
1494
+ const name = expectDefined(match[1]);
1527
1495
  const offset = match.index ?? 0;
1528
1496
  const line = lineFromOffset(offset);
1529
1497
  const col = offset - (lineOffsets[line - 1] ?? 0);
@@ -1541,7 +1509,7 @@ function regexParse3(opts) {
1541
1509
  }
1542
1510
  const aliasRegex = /\*(\w[\w-]*)/g;
1543
1511
  for (let match = aliasRegex.exec(content); match !== null; match = aliasRegex.exec(content)) {
1544
- const name = expectDefined4(match[1]);
1512
+ const name = expectDefined(match[1]);
1545
1513
  const offset = match.index ?? 0;
1546
1514
  const line = lineFromOffset(offset);
1547
1515
  const col = offset - (lineOffsets[line - 1] ?? 0);
@@ -1576,7 +1544,7 @@ function regexParse3(opts) {
1576
1544
  }
1577
1545
  const listItemRegex = /^-(\s+)([^:#\s][^:#\s]*)\s*:/gm;
1578
1546
  for (let match = listItemRegex.exec(content); match !== null; match = listItemRegex.exec(content)) {
1579
- const key = expectDefined4(match[2]);
1547
+ const key = expectDefined(match[2]);
1580
1548
  const offset = match.index ?? 0;
1581
1549
  const line = lineFromOffset(offset);
1582
1550
  const col = offset - (lineOffsets[line - 1] ?? 0);
@@ -1596,7 +1564,7 @@ function regexParse3(opts) {
1596
1564
  }
1597
1565
  const blockScalarRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:\s*[|>](\s|$)/gm;
1598
1566
  for (let match = blockScalarRegex.exec(content); match !== null; match = blockScalarRegex.exec(content)) {
1599
- const key = expectDefined4(match[2]);
1567
+ const key = expectDefined(match[2]);
1600
1568
  const offset = match.index ?? 0;
1601
1569
  const line = lineFromOffset(offset);
1602
1570
  const col = offset - (lineOffsets[line - 1] ?? 0);
@@ -1816,12 +1784,6 @@ function cancelPendingReindexes() {
1816
1784
  }
1817
1785
 
1818
1786
  // src/codebase-index/indexer.ts
1819
- function expectDefined5(value) {
1820
- if (value === null || value === void 0) {
1821
- throw new Error("Expected value to be defined");
1822
- }
1823
- return value;
1824
- }
1825
1787
  var YIELD_EVERY_N = 50;
1826
1788
  function yieldEventLoop() {
1827
1789
  return new Promise((resolve2) => setImmediate(resolve2));
@@ -1930,7 +1892,7 @@ async function runIndexer(_ctx, opts) {
1930
1892
  for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
1931
1893
  }
1932
1894
  for (let fi = 0; fi < files.length; fi++) {
1933
- const file = expectDefined5(files[fi]);
1895
+ const file = expectDefined(files[fi]);
1934
1896
  _setIndexProgress(fi + 1, files.length);
1935
1897
  if (fi > 0 && fi % YIELD_EVERY_N === 0) {
1936
1898
  await yieldEventLoop();
@@ -1987,7 +1949,7 @@ async function runIndexer(_ctx, opts) {
1987
1949
  langStats[lang] = (langStats[lang] ?? 0) + count;
1988
1950
  if (parsed.refs && parsed.refs.length > 0) {
1989
1951
  for (let i = 0; i < symbolsWithIds.length; i++) {
1990
- const sym = expectDefined5(symbolsWithIds[i]);
1952
+ const sym = expectDefined(symbolsWithIds[i]);
1991
1953
  const symRefs = parsed.refs.filter((r) => r.line === sym.line);
1992
1954
  if (symRefs.length > 0) {
1993
1955
  const refsWithFromId = symRefs.map((r) => ({ ...r, fromId: sym.id }));
@@ -2158,12 +2120,6 @@ var Bm25Index = class {
2158
2120
  };
2159
2121
 
2160
2122
  // src/codebase-index/codebase-search-tool.ts
2161
- function expectDefined6(value) {
2162
- if (value === null || value === void 0) {
2163
- throw new Error("Expected value to be defined");
2164
- }
2165
- return value;
2166
- }
2167
2123
  var codebaseSearchTool = {
2168
2124
  name: "codebase-search",
2169
2125
  category: "Project",
@@ -2253,7 +2209,7 @@ var codebaseSearchTool = {
2253
2209
  const top = scored.slice(0, limit);
2254
2210
  const qTokens = tokenise(input.query);
2255
2211
  const results = top.map(({ id, score }) => {
2256
- const c = expectDefined6(candidates.find((c2) => c2.id === id));
2212
+ const c = expectDefined(candidates.find((c2) => c2.id === id));
2257
2213
  const snippet = bm25.extractSnippet(id, qTokens);
2258
2214
  return {
2259
2215
  ...c,