@wrongstack/tools 0.87.0 → 0.89.3
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.
- package/dist/audit.js +1 -7
- package/dist/audit.js.map +1 -1
- package/dist/{background-indexer-DYm1FUxK.d.ts → background-indexer-C2014mH0.d.ts} +1 -1
- package/dist/bash.js +6 -18
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +59 -134
- package/dist/builtin.js.map +1 -1
- package/dist/circuit-breaker.js +1 -1
- package/dist/circuit-breaker.js.map +1 -1
- package/dist/codebase-index/index.d.ts +2 -21
- package/dist/codebase-index/index.js +25 -69
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/diff.js.map +1 -1
- package/dist/document.js +1 -1
- package/dist/document.js.map +1 -1
- package/dist/edit.js.map +1 -1
- package/dist/exec.js +3 -15
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +4 -16
- package/dist/format.js.map +1 -1
- package/dist/git.d.ts +2 -0
- package/dist/git.js +15 -8
- package/dist/git.js.map +1 -1
- package/dist/glob.js.map +1 -1
- package/dist/grep.js +1 -7
- package/dist/grep.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +173 -137
- package/dist/index.js.map +1 -1
- package/dist/install.js +4 -16
- package/dist/install.js.map +1 -1
- package/dist/lint.js +4 -16
- package/dist/lint.js.map +1 -1
- package/dist/logs.js.map +1 -1
- package/dist/memory.d.ts +29 -1
- package/dist/memory.js +115 -4
- package/dist/memory.js.map +1 -1
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +59 -134
- package/dist/pack.js.map +1 -1
- package/dist/patch.js.map +1 -1
- package/dist/process-registry.js +2 -7
- package/dist/process-registry.js.map +1 -1
- package/dist/read.js +1 -1
- package/dist/read.js.map +1 -1
- package/dist/replace.js +1 -7
- package/dist/replace.js.map +1 -1
- package/dist/scaffold.js.map +1 -1
- package/dist/search.js +2 -7
- package/dist/search.js.map +1 -1
- package/dist/test.js +4 -16
- package/dist/test.js.map +1 -1
- package/dist/tree.js +1 -7
- package/dist/tree.js.map +1 -1
- package/dist/typecheck.js +4 -16
- package/dist/typecheck.js.map +1 -1
- package/dist/write.js.map +1 -1
- package/package.json +2 -2
package/dist/circuit-breaker.js
CHANGED
|
@@ -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,
|
|
2
|
-
export {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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] ??
|
|
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 =
|
|
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 =
|
|
1434
|
-
const keyOffset = blockOffset +
|
|
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 =
|
|
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 =
|
|
1458
|
-
const keyOffset = blockOffset +
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2212
|
+
const c = expectDefined(candidates.find((c2) => c2.id === id));
|
|
2257
2213
|
const snippet = bm25.extractSnippet(id, qTokens);
|
|
2258
2214
|
return {
|
|
2259
2215
|
...c,
|