@wrongstack/tools 0.284.0 → 0.285.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.
- package/dist/_concurrency.d.ts +16 -0
- package/dist/_concurrency.d.ts.map +1 -0
- package/dist/_danger-detect.d.ts +54 -0
- package/dist/_danger-detect.d.ts.map +1 -0
- package/dist/_edit-match.d.ts +86 -0
- package/dist/_edit-match.d.ts.map +1 -0
- package/dist/_env.d.ts +6 -0
- package/dist/_env.d.ts.map +1 -0
- package/dist/_fetch-guard.d.ts +31 -0
- package/dist/_fetch-guard.d.ts.map +1 -0
- package/dist/_output-spool.d.ts +38 -0
- package/dist/_output-spool.d.ts.map +1 -0
- package/dist/_redact-command.d.ts +6 -0
- package/dist/_redact-command.d.ts.map +1 -0
- package/dist/_regex.d.ts +39 -0
- package/dist/_regex.d.ts.map +1 -0
- package/dist/_session-shell.d.ts +73 -0
- package/dist/_session-shell.d.ts.map +1 -0
- package/dist/_shell-pick.d.ts +158 -0
- package/dist/_shell-pick.d.ts.map +1 -0
- package/dist/_spawn-stream.d.ts +32 -0
- package/dist/_spawn-stream.d.ts.map +1 -0
- package/dist/_syntax-check.d.ts +16 -0
- package/dist/_syntax-check.d.ts.map +1 -0
- package/dist/_util.d.ts +68 -0
- package/dist/_util.d.ts.map +1 -0
- package/dist/_win32-resolve.d.ts +42 -0
- package/dist/_win32-resolve.d.ts.map +1 -0
- package/dist/audit.d.ts +4 -5
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +2743 -28
- package/dist/audit.js.map +7 -1
- package/dist/bash-kill-guard.d.ts +62 -0
- package/dist/bash-kill-guard.d.ts.map +1 -0
- package/dist/bash.d.ts +4 -5
- package/dist/bash.d.ts.map +1 -0
- package/dist/bash.js +59 -30
- package/dist/bash.js.map +7 -1
- package/dist/batch-tool-use.d.ts +4 -5
- package/dist/batch-tool-use.d.ts.map +1 -0
- package/dist/batch-tool-use.js +3 -3
- package/dist/batch-tool-use.js.map +7 -1
- package/dist/builtin.d.ts +7 -9
- package/dist/builtin.d.ts.map +1 -0
- package/dist/builtin.js +5282 -1019
- package/dist/builtin.js.map +7 -1
- package/dist/circuit-breaker.d.ts +4 -5
- package/dist/circuit-breaker.d.ts.map +1 -0
- package/dist/circuit-breaker.js +3 -3
- package/dist/circuit-breaker.js.map +7 -1
- package/dist/codebase-index/background-indexer.d.ts +116 -0
- package/dist/codebase-index/background-indexer.d.ts.map +1 -0
- package/dist/codebase-index/bm25.d.ts +40 -0
- package/dist/codebase-index/bm25.d.ts.map +1 -0
- package/dist/codebase-index/circuit-breaker.d.ts +94 -0
- package/dist/codebase-index/circuit-breaker.d.ts.map +1 -0
- package/dist/codebase-index/codebase-index-tool.d.ts +17 -0
- package/dist/codebase-index/codebase-index-tool.d.ts.map +1 -0
- package/dist/codebase-index/codebase-search-tool.d.ts +43 -0
- package/dist/codebase-index/codebase-search-tool.d.ts.map +1 -0
- package/dist/codebase-index/codebase-stats-tool.d.ts +23 -0
- package/dist/codebase-index/codebase-stats-tool.d.ts.map +1 -0
- package/dist/codebase-index/gitignore.d.ts +22 -0
- package/dist/codebase-index/gitignore.d.ts.map +1 -0
- package/dist/codebase-index/go-parser.d.ts +16 -0
- package/dist/codebase-index/go-parser.d.ts.map +1 -0
- package/dist/codebase-index/index-service.d.ts +25 -0
- package/dist/codebase-index/index-service.d.ts.map +1 -0
- package/dist/codebase-index/index.d.ts +23 -271
- package/dist/codebase-index/index.d.ts.map +1 -0
- package/dist/codebase-index/index.js +136 -68
- package/dist/codebase-index/index.js.map +7 -1
- package/dist/codebase-index/indexer.d.ts +28 -0
- package/dist/codebase-index/indexer.d.ts.map +1 -0
- package/dist/codebase-index/json-parser.d.ts +8 -0
- package/dist/codebase-index/json-parser.d.ts.map +1 -0
- package/dist/codebase-index/lsp-kind.d.ts +53 -0
- package/dist/codebase-index/lsp-kind.d.ts.map +1 -0
- package/dist/codebase-index/py-parser.d.ts +16 -0
- package/dist/codebase-index/py-parser.d.ts.map +1 -0
- package/dist/codebase-index/refs-extractor.d.ts +25 -0
- package/dist/codebase-index/refs-extractor.d.ts.map +1 -0
- package/dist/codebase-index/rs-parser.d.ts +8 -0
- package/dist/codebase-index/rs-parser.d.ts.map +1 -0
- package/dist/codebase-index/schema.d.ts +82 -0
- package/dist/codebase-index/schema.d.ts.map +1 -0
- package/dist/codebase-index/ts-parser.d.ts +30 -0
- package/dist/codebase-index/ts-parser.d.ts.map +1 -0
- package/dist/codebase-index/worker-protocol.d.ts +77 -0
- package/dist/codebase-index/worker-protocol.d.ts.map +1 -0
- package/dist/codebase-index/worker.d.ts +16 -2
- package/dist/codebase-index/worker.d.ts.map +1 -0
- package/dist/codebase-index/worker.js +103 -65
- package/dist/codebase-index/worker.js.map +7 -1
- package/dist/codebase-index/writer.d.ts +189 -0
- package/dist/codebase-index/writer.d.ts.map +1 -0
- package/dist/codebase-index/yaml-parser.d.ts +8 -0
- package/dist/codebase-index/yaml-parser.d.ts.map +1 -0
- package/dist/design.d.ts +38 -0
- package/dist/design.d.ts.map +1 -0
- package/dist/design.js +270 -0
- package/dist/design.js.map +7 -0
- package/dist/diff.d.ts +4 -5
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +14 -12
- package/dist/diff.js.map +7 -1
- package/dist/document.d.ts +4 -5
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +8 -7
- package/dist/document.js.map +7 -1
- package/dist/edit.d.ts +5 -36
- package/dist/edit.d.ts.map +1 -0
- package/dist/edit.js +28 -16
- package/dist/edit.js.map +7 -1
- package/dist/exec.d.ts +67 -2
- package/dist/exec.d.ts.map +1 -0
- package/dist/exec.js +50 -25
- package/dist/exec.js.map +7 -1
- package/dist/fetch.d.ts +4 -32
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +89 -77
- package/dist/fetch.js.map +7 -1
- package/dist/format.d.ts +4 -5
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +2415 -28
- package/dist/format.js.map +7 -1
- package/dist/git.d.ts +4 -5
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +10 -9
- package/dist/git.js.map +7 -1
- package/dist/glob.d.ts +4 -5
- package/dist/glob.d.ts.map +1 -0
- package/dist/glob.js +15 -12
- package/dist/glob.js.map +7 -1
- package/dist/grep.d.ts +4 -5
- package/dist/grep.d.ts.map +1 -0
- package/dist/grep.js +13 -10
- package/dist/grep.js.map +7 -1
- package/dist/index.d.ts +19 -724
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6088 -1690
- package/dist/index.js.map +7 -1
- package/dist/install.d.ts +4 -5
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +2680 -31
- package/dist/install.js.map +7 -1
- package/dist/json.d.ts +4 -5
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +13 -11
- package/dist/json.js.map +7 -1
- package/dist/kanban.d.ts +107 -0
- package/dist/kanban.d.ts.map +1 -0
- package/dist/kanban.js +845 -0
- package/dist/kanban.js.map +7 -0
- package/dist/languages/detect.d.ts +3 -0
- package/dist/languages/detect.d.ts.map +1 -0
- package/dist/languages/diagnostics.d.ts +15 -0
- package/dist/languages/diagnostics.d.ts.map +1 -0
- package/dist/languages/execute-tool.d.ts +34 -0
- package/dist/languages/execute-tool.d.ts.map +1 -0
- package/dist/languages/execute.d.ts +18 -0
- package/dist/languages/execute.d.ts.map +1 -0
- package/dist/languages/index.d.ts +12 -0
- package/dist/languages/index.d.ts.map +1 -0
- package/dist/languages/index.js +4457 -0
- package/dist/languages/index.js.map +7 -0
- package/dist/languages/legacy-bridge.d.ts +29 -0
- package/dist/languages/legacy-bridge.d.ts.map +1 -0
- package/dist/languages/package-tool.d.ts +29 -0
- package/dist/languages/package-tool.d.ts.map +1 -0
- package/dist/languages/plan.d.ts +4 -0
- package/dist/languages/plan.d.ts.map +1 -0
- package/dist/languages/profile-helpers.d.ts +14 -0
- package/dist/languages/profile-helpers.d.ts.map +1 -0
- package/dist/languages/profiles/additional.d.ts +3 -0
- package/dist/languages/profiles/additional.d.ts.map +1 -0
- package/dist/languages/profiles/primary.d.ts +3 -0
- package/dist/languages/profiles/primary.d.ts.map +1 -0
- package/dist/languages/registry.d.ts +11 -0
- package/dist/languages/registry.d.ts.map +1 -0
- package/dist/languages/tool.d.ts +32 -0
- package/dist/languages/tool.d.ts.map +1 -0
- package/dist/languages/types.d.ts +207 -0
- package/dist/languages/types.d.ts.map +1 -0
- package/dist/lint.d.ts +4 -5
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +2415 -27
- package/dist/lint.js.map +7 -1
- package/dist/logs.d.ts +4 -5
- package/dist/logs.d.ts.map +1 -0
- package/dist/logs.js +16 -10
- package/dist/logs.js.map +7 -1
- package/dist/memory.d.ts +7 -8
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +7 -5
- package/dist/memory.js.map +7 -1
- package/dist/mode.d.ts +4 -5
- package/dist/mode.d.ts.map +1 -0
- package/dist/mode.js +3 -3
- package/dist/mode.js.map +7 -1
- package/dist/next-steps.d.ts +5 -6
- package/dist/next-steps.d.ts.map +1 -0
- package/dist/next-steps.js +5 -4
- package/dist/next-steps.js.map +7 -1
- package/dist/outdated.d.ts +4 -5
- package/dist/outdated.d.ts.map +1 -0
- package/dist/outdated.js +4777 -68
- package/dist/outdated.js.map +7 -1
- package/dist/pack.d.ts +3 -6
- package/dist/pack.d.ts.map +1 -0
- package/dist/pack.js +5275 -1019
- package/dist/pack.js.map +7 -1
- package/dist/patch.d.ts +4 -5
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +18 -16
- package/dist/patch.js.map +7 -1
- package/dist/plan.d.ts +55 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +280 -0
- package/dist/plan.js.map +7 -0
- package/dist/process-guardian.d.ts +100 -0
- package/dist/process-guardian.d.ts.map +1 -0
- package/dist/process-registry-persistent.d.ts +121 -0
- package/dist/process-registry-persistent.d.ts.map +1 -0
- package/dist/process-registry.d.ts +13 -17
- package/dist/process-registry.d.ts.map +1 -0
- package/dist/process-registry.js +15 -9
- package/dist/process-registry.js.map +7 -1
- package/dist/ps-slash.d.ts +106 -0
- package/dist/ps-slash.d.ts.map +1 -0
- package/dist/ps-slash.js +1291 -0
- package/dist/ps-slash.js.map +7 -0
- package/dist/read.d.ts +4 -5
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +13 -11
- package/dist/read.js.map +7 -1
- package/dist/replace.d.ts +4 -5
- package/dist/replace.d.ts.map +1 -0
- package/dist/replace.js +26 -13
- package/dist/replace.js.map +7 -1
- package/dist/scaffold.d.ts +4 -5
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +16 -14
- package/dist/scaffold.js.map +7 -1
- package/dist/search.d.ts +5 -6
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +24 -25
- package/dist/search.js.map +7 -1
- package/dist/set-working-dir.d.ts +18 -0
- package/dist/set-working-dir.d.ts.map +1 -0
- package/dist/shim/node-sqlite.d.ts +3 -0
- package/dist/shim/node-sqlite.d.ts.map +1 -0
- package/dist/skill.d.ts +45 -0
- package/dist/skill.d.ts.map +1 -0
- package/dist/skill.js +175 -0
- package/dist/skill.js.map +7 -0
- package/dist/spawn-background.d.ts +80 -0
- package/dist/spawn-background.d.ts.map +1 -0
- package/dist/task.d.ts +35 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +380 -0
- package/dist/task.js.map +7 -0
- package/dist/test.d.ts +4 -5
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +2419 -27
- package/dist/test.js.map +7 -1
- package/dist/todo.d.ts +4 -5
- package/dist/todo.d.ts.map +1 -0
- package/dist/todo.js +5 -5
- package/dist/todo.js.map +7 -1
- package/dist/tool-diff.d.ts +16 -17
- package/dist/tool-diff.d.ts.map +1 -0
- package/dist/tool-diff.js +11 -3
- package/dist/tool-diff.js.map +7 -1
- package/dist/tool-help.d.ts +4 -5
- package/dist/tool-help.d.ts.map +1 -0
- package/dist/tool-help.js +3 -3
- package/dist/tool-help.js.map +7 -1
- package/dist/tool-icon-map.d.ts +45 -0
- package/dist/tool-icon-map.d.ts.map +1 -0
- package/dist/tool-icons.d.ts +5 -6
- package/dist/tool-icons.d.ts.map +1 -0
- package/dist/tool-icons.js +16 -4
- package/dist/tool-icons.js.map +7 -1
- package/dist/tool-search.d.ts +4 -5
- package/dist/tool-search.d.ts.map +1 -0
- package/dist/tool-search.js +3 -3
- package/dist/tool-search.js.map +7 -1
- package/dist/tool-summary.d.ts +4 -5
- package/dist/tool-summary.d.ts.map +1 -0
- package/dist/tool-summary.js +5 -3
- package/dist/tool-summary.js.map +7 -1
- package/dist/tool-use.d.ts +4 -5
- package/dist/tool-use.d.ts.map +1 -0
- package/dist/tool-use.js +3 -3
- package/dist/tool-use.js.map +7 -1
- package/dist/tree.d.ts +4 -5
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +11 -9
- package/dist/tree.js.map +7 -1
- package/dist/typecheck.d.ts +4 -5
- package/dist/typecheck.d.ts.map +1 -0
- package/dist/typecheck.js +2416 -28
- package/dist/typecheck.js.map +7 -1
- package/dist/write.d.ts +4 -5
- package/dist/write.d.ts.map +1 -0
- package/dist/write.js +21 -16
- package/dist/write.js.map +7 -1
- package/package.json +34 -6
- package/dist/background-indexer-BeDBxfSh.d.ts +0 -371
- package/dist/exec-2OKoT6tk.d.ts +0 -121
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* resource pool; isolating them would let the model route around the
|
|
16
16
|
* breaker by alternating which tool it uses.
|
|
17
17
|
*/
|
|
18
|
-
interface CircuitBreakerConfig {
|
|
18
|
+
export interface CircuitBreakerConfig {
|
|
19
19
|
/**
|
|
20
20
|
* Consecutive failures before trip. Default: 5.
|
|
21
21
|
* A single success resets this counter to 0.
|
|
@@ -47,7 +47,7 @@ interface CircuitBreakerConfig {
|
|
|
47
47
|
*/
|
|
48
48
|
cooldownMs?: number | undefined;
|
|
49
49
|
}
|
|
50
|
-
interface CircuitBreakerSnapshot {
|
|
50
|
+
export interface CircuitBreakerSnapshot {
|
|
51
51
|
state: 'closed' | 'open' | 'half-open';
|
|
52
52
|
consecutiveFailures: number;
|
|
53
53
|
slowCallsInWindow: number;
|
|
@@ -57,7 +57,7 @@ interface CircuitBreakerSnapshot {
|
|
|
57
57
|
lastFailureAt: number | null;
|
|
58
58
|
lastSlowAt: number | null;
|
|
59
59
|
}
|
|
60
|
-
declare class CircuitBreaker {
|
|
60
|
+
export declare class CircuitBreaker {
|
|
61
61
|
private readonly maxConsecutiveFailures;
|
|
62
62
|
private readonly slowCallThresholdMs;
|
|
63
63
|
private readonly maxSlowCalls;
|
|
@@ -132,5 +132,4 @@ declare class CircuitBreaker {
|
|
|
132
132
|
private _checkStateTransition;
|
|
133
133
|
private _pruneWindow;
|
|
134
134
|
}
|
|
135
|
-
|
|
136
|
-
export { CircuitBreaker, type CircuitBreakerConfig, type CircuitBreakerSnapshot };
|
|
135
|
+
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAsBD,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACvC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,UAAU,CAAuB;IACzC,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAuB;IAEvC;;;;;OAKG;IACH,OAAO,CAAC,OAAO,CAAQ;IAEvB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAEnC,YAAY,MAAM,GAAE,oBAAyB,EAO5C;IAED,4EAA4E;IAC5E,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIjC;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;;OAIG;IACH,IAAI,UAAU,IAAI,OAAO,CAIxB;IAED;;OAEG;IACH,QAAQ,IAAI,sBAAsB,CAkBjC;IAED;;;;;;;;OAQG;IACH,UAAU,CAAC,MAAM,UAAQ,GAAG,OAAO,CAKlC;IAED;;;;;;;;OAQG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAQ,GAAG,IAAI,CAiDnE;IAED,8DAA8D;IAC9D,SAAS,IAAI,IAAI,CAEhB;IAED,8DAA8D;IAC9D,UAAU,IAAI,IAAI,CAEjB;IAED,OAAO,CAAC,KAAK;IAmBb,OAAO,CAAC,MAAM;IAiBd,8DAA8D;IAC9D,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,YAAY;CAIrB"}
|
package/dist/circuit-breaker.js
CHANGED
|
@@ -189,7 +189,7 @@ var CircuitBreaker = class {
|
|
|
189
189
|
this.window = this.window.filter((c) => c.at >= cutoff);
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
export {
|
|
193
|
+
CircuitBreaker
|
|
194
|
+
};
|
|
194
195
|
//# sourceMappingURL=circuit-breaker.js.map
|
|
195
|
-
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -1 +1,7 @@
|
|
|
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 /**\n * Master enable flag. When false the breaker is bypassed: `beforeCall`\n * always returns true and `afterCall` records nothing. The class itself\n * defaults to enabled (so the standalone unit tests exercise tripping); the\n * ProcessRegistry flips this off until the user opts in via `/settings`.\n */\n private enabled = true;\n\n /**\n * Fired (best-effort) when the breaker transitions into the `open` state.\n * The registry uses this to arm its auto kill/reset countdown.\n */\n onTrip?: (() => void) | undefined;\n /**\n * Fired (best-effort) when the breaker returns to `closed` after having been\n * open/half-open. The registry uses this to cancel a pending kill/reset.\n */\n onReset?: (() => void) | undefined;\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 /** Toggle the master enable. Disabling resets to a clean `closed` state. */\n setEnabled(enabled: boolean): void {\n if (this.enabled === enabled) return;\n this.enabled = enabled;\n if (!enabled) this._reset();\n }\n\n get isEnabled(): boolean {\n return this.enabled;\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 if (!this.enabled) return true;\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 * @param bypass - If true, skip the circuit breaker check entirely.\n * Use for background/fire-and-forget processes that should\n * not affect breaker state.\n */\n beforeCall(bypass = false): boolean {\n if (bypass || !this.enabled) return true;\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 * @param bypass - If true, do not update breaker state.\n * Use for background/fire-and-forget processes.\n */\n afterCall(durationMs: number, failed: boolean, bypass = false): void {\n if (bypass || !this.enabled) return;\n\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 // P3 #23 (before-release.md): clear the window on trip. Old records are\n // irrelevant once tripped — the breaker starts fresh after cooldown\n // (half-open → closed resets the counters). Without this the window array\n // holds onto CallRecord entries for its lifetime if no new afterCall()\n // arrives (which is the case when the breaker stays open and no new calls\n // are attempted).\n this.window = [];\n // Best-effort: never let a listener failure corrupt breaker state.\n try {\n this.onTrip?.();\n } catch {\n /* ignored — observability hook only */\n }\n }\n\n private _reset(): void {\n const wasRecovering = this.state !== 'closed';\n this.state = 'closed';\n this.consecutiveFailures = 0;\n this.window = [];\n this.openedAt = null;\n // Only notify on a real recovery (open/half-open → closed), not on the\n // initial closed state or an idempotent re-reset.\n if (wasRecovering) {\n try {\n this.onReset?.();\n } catch {\n /* ignored — observability hook only */\n }\n }\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
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/circuit-breaker.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * CircuitBreaker \u2014 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 \u2014 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 \u2014 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 /**\n * Master enable flag. When false the breaker is bypassed: `beforeCall`\n * always returns true and `afterCall` records nothing. The class itself\n * defaults to enabled (so the standalone unit tests exercise tripping); the\n * ProcessRegistry flips this off until the user opts in via `/settings`.\n */\n private enabled = true;\n\n /**\n * Fired (best-effort) when the breaker transitions into the `open` state.\n * The registry uses this to arm its auto kill/reset countdown.\n */\n onTrip?: (() => void) | undefined;\n /**\n * Fired (best-effort) when the breaker returns to `closed` after having been\n * open/half-open. The registry uses this to cancel a pending kill/reset.\n */\n onReset?: (() => void) | undefined;\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 /** Toggle the master enable. Disabling resets to a clean `closed` state. */\n setEnabled(enabled: boolean): void {\n if (this.enabled === enabled) return;\n this.enabled = enabled;\n if (!enabled) this._reset();\n }\n\n get isEnabled(): boolean {\n return this.enabled;\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 if (!this.enabled) return true;\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 * @param bypass - If true, skip the circuit breaker check entirely.\n * Use for background/fire-and-forget processes that should\n * not affect breaker state.\n */\n beforeCall(bypass = false): boolean {\n if (bypass || !this.enabled) return true;\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 * @param bypass - If true, do not update breaker state.\n * Use for background/fire-and-forget processes.\n */\n afterCall(durationMs: number, failed: boolean, bypass = false): void {\n if (bypass || !this.enabled) return;\n\n const now = Date.now();\n\n if (this.state === 'half-open') {\n // First call through after cooldown \u2014 if it failed, go back to open.\n if (failed) {\n this._trip();\n return;\n }\n // Success in half-open \u2192 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 \u2014 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 // P3 #23 (before-release.md): clear the window on trip. Old records are\n // irrelevant once tripped \u2014 the breaker starts fresh after cooldown\n // (half-open \u2192 closed resets the counters). Without this the window array\n // holds onto CallRecord entries for its lifetime if no new afterCall()\n // arrives (which is the case when the breaker stays open and no new calls\n // are attempted).\n this.window = [];\n // Best-effort: never let a listener failure corrupt breaker state.\n try {\n this.onTrip?.();\n } catch {\n /* ignored \u2014 observability hook only */\n }\n }\n\n private _reset(): void {\n const wasRecovering = this.state !== 'closed';\n this.state = 'closed';\n this.consecutiveFailures = 0;\n this.window = [];\n this.openedAt = null;\n // Only notify on a real recovery (open/half-open \u2192 closed), not on the\n // initial closed state or an idempotent re-reset.\n if (wasRecovering) {\n try {\n this.onReset?.();\n } catch {\n /* ignored \u2014 observability hook only */\n }\n }\n }\n\n /** Transition from open \u2192 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}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index host — the main-thread coordinator for all codebase-index operations.
|
|
3
|
+
*
|
|
4
|
+
* Production mode runs every operation (full scans, per-file reindexes,
|
|
5
|
+
* searches, stats) in a dedicated worker thread (`worker.ts`), so the
|
|
6
|
+
* synchronous `node:sqlite` calls and the TypeScript parser can never block
|
|
7
|
+
* the main event loop — the failure mode that used to freeze terminals is
|
|
8
|
+
* structurally impossible. When the built worker file is not present (tests
|
|
9
|
+
* run from source, exotic runtimes) or `WRONGSTACK_INDEX_INLINE=1` is set,
|
|
10
|
+
* operations fall back to running inline through the same service layer.
|
|
11
|
+
*
|
|
12
|
+
* Concerns owned here, in front of either execution mode:
|
|
13
|
+
*
|
|
14
|
+
* 1. **Serialization** — every write run (startup scan, per-edit incremental,
|
|
15
|
+
* external file-watch, manual reindex) goes through one process-wide
|
|
16
|
+
* promise-chain mutex so two runs never race the same `index.db` writer.
|
|
17
|
+
* 2. **Debounce** — rapid successive edits to the same file coalesce into a
|
|
18
|
+
* single reindex, keyed per `(indexDir, file)`.
|
|
19
|
+
* 3. **Watchdog** — every operation is raced against a timeout. In worker
|
|
20
|
+
* mode a timeout hard-terminates the worker (it respawns lazily on the
|
|
21
|
+
* next request); inline it aborts the run's signal. Either way the mutex
|
|
22
|
+
* chain always advances and the promise always settles.
|
|
23
|
+
* 4. **Circuit breaker** — repeated failures/timeouts pause indexing instead
|
|
24
|
+
* of queuing more work behind a wedged pipeline. See circuit-breaker.ts.
|
|
25
|
+
* 5. **State tracking** — ready/indexing/progress flags + change listeners
|
|
26
|
+
* for the TUI status chip and the search/stats tools' gating.
|
|
27
|
+
*/
|
|
28
|
+
import { type CircuitSnapshot } from './circuit-breaker.js';
|
|
29
|
+
import type { IndexResult, IndexStats } from './schema.js';
|
|
30
|
+
import type { SearchOpArgs, SearchOpResult, StatsOpArgs } from './worker-protocol.js';
|
|
31
|
+
/** True once the first full-project index has completed (success or failure). */
|
|
32
|
+
export declare function isIndexReady(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Mark the index as ready so downstream tools (codebase-search, codebase-stats)
|
|
35
|
+
* don't gate on a startup index that never ran.
|
|
36
|
+
*/
|
|
37
|
+
export declare function setIndexReady(): void;
|
|
38
|
+
/** True while an index build is actively running. */
|
|
39
|
+
export declare function isIndexing(): boolean;
|
|
40
|
+
/** Current indexing progress: { currentFile, totalFiles, ready, indexing, circuit }. */
|
|
41
|
+
export declare function getIndexState(): {
|
|
42
|
+
ready: boolean;
|
|
43
|
+
indexing: boolean;
|
|
44
|
+
currentFile: number;
|
|
45
|
+
totalFiles: number;
|
|
46
|
+
lastError: string | null;
|
|
47
|
+
/** Circuit-breaker state — `open` means indexing is paused after repeated failures. */
|
|
48
|
+
circuit: CircuitSnapshot;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Optional callback fired on every lifecycle transition (started, progress,
|
|
52
|
+
* completed, failed). Plug into the event bus or a TUI dispatcher to surface
|
|
53
|
+
* the indexing state in real time.
|
|
54
|
+
*/
|
|
55
|
+
type IndexStateListener = (state: ReturnType<typeof getIndexState>) => void;
|
|
56
|
+
export declare function onIndexStateChange(listener: IndexStateListener): () => void;
|
|
57
|
+
/**
|
|
58
|
+
* Tear down the index host (worker + pending debounces). Call on process
|
|
59
|
+
* shutdown; safe to call when nothing is running.
|
|
60
|
+
*/
|
|
61
|
+
export declare function shutdownCodebaseIndexHost(): void;
|
|
62
|
+
/** True when the file's extension maps to a language the indexer can parse. */
|
|
63
|
+
export declare function isIndexableFile(filePath: string): boolean;
|
|
64
|
+
export declare function runStartupIndex(opts: {
|
|
65
|
+
projectRoot: string;
|
|
66
|
+
indexDir?: string | undefined;
|
|
67
|
+
force?: boolean | undefined;
|
|
68
|
+
langs?: string[] | undefined;
|
|
69
|
+
signal?: AbortSignal | undefined;
|
|
70
|
+
/** Watchdog timeout for the whole run. Default: 120s. */
|
|
71
|
+
timeoutMs?: number | undefined;
|
|
72
|
+
}): Promise<IndexResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Debounced, fire-and-forget incremental reindex of specific files. Used by the
|
|
75
|
+
* per-edit toolCall middleware and the external file watcher. Non-indexable
|
|
76
|
+
* paths are dropped. Errors are reported via the optional `onError` callback and
|
|
77
|
+
* never thrown to the caller (background work must not crash a turn).
|
|
78
|
+
*/
|
|
79
|
+
export declare function enqueueReindex(opts: {
|
|
80
|
+
projectRoot: string;
|
|
81
|
+
files: string[];
|
|
82
|
+
indexDir?: string | undefined;
|
|
83
|
+
debounceMs?: number | undefined;
|
|
84
|
+
/** Watchdog timeout per file. Default: 30s. */
|
|
85
|
+
timeoutMs?: number | undefined;
|
|
86
|
+
onError?: ((err: unknown) => void) | undefined;
|
|
87
|
+
}): void;
|
|
88
|
+
/** Cancel all pending debounced reindexes. For teardown / tests. */
|
|
89
|
+
export declare function cancelPendingReindexes(): void;
|
|
90
|
+
/**
|
|
91
|
+
* Ranked symbol search against the index. The query runs in the index worker
|
|
92
|
+
* (or inline in fallback mode) — the main thread never opens SQLite. Reads
|
|
93
|
+
* don't take the write mutex (WAL readers don't block the writer) and don't
|
|
94
|
+
* feed the circuit breaker; a wedged read still trips the watchdog, which
|
|
95
|
+
* recycles the worker.
|
|
96
|
+
*/
|
|
97
|
+
export declare function searchCodebaseIndex(args: SearchOpArgs, opts?: {
|
|
98
|
+
timeoutMs?: number | undefined;
|
|
99
|
+
signal?: AbortSignal | undefined;
|
|
100
|
+
}): Promise<SearchOpResult>;
|
|
101
|
+
/** Index health/statistics, fetched off the main thread like searches. */
|
|
102
|
+
export declare function codebaseIndexStats(args: StatsOpArgs, opts?: {
|
|
103
|
+
timeoutMs?: number | undefined;
|
|
104
|
+
signal?: AbortSignal | undefined;
|
|
105
|
+
}): Promise<IndexStats>;
|
|
106
|
+
/**
|
|
107
|
+
* Reset all process-global indexing state for test isolation.
|
|
108
|
+
*
|
|
109
|
+
* Vitest runs test files in parallel within the same process, so module-level
|
|
110
|
+
* state (`_indexing`, `_ready`, `chain`, `indexCircuitBreaker`) leaks between
|
|
111
|
+
* tests. Call this in `beforeEach` to ensure each test starts with a clean
|
|
112
|
+
* slate. Production code should NEVER call this.
|
|
113
|
+
*/
|
|
114
|
+
export declare function resetIndexStateForTesting(): void;
|
|
115
|
+
export {};
|
|
116
|
+
//# sourceMappingURL=background-indexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background-indexer.d.ts","sourceRoot":"","sources":["../../src/codebase-index/background-indexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,EAEL,KAAK,eAAe,EAGrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,KAAK,EAKV,YAAY,EACZ,cAAc,EACd,WAAW,EAEZ,MAAM,sBAAsB,CAAC;AA2B9B,iFAAiF;AACjF,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,qDAAqD;AACrD,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wFAAwF;AACxF,wBAAgB,aAAa,IAAI;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uFAAuF;IACvF,OAAO,EAAE,eAAe,CAAC;CAC1B,CASA;AAED;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,KAAK,IAAI,CAAC;AAG5E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAK3E;AAoGD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAIhD;AAuJD,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAmBD,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,GAAG,OAAO,CAAC,WAAW,CAAC,CA2DvB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAChD,GAAG,IAAI,CAmCP;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAAO,GAC9E,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED,0EAA0E;AAC1E,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,WAAW,EACjB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAAO,GAC9E,OAAO,CAAC,UAAU,CAAC,CAKrB;AAID;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAchD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BM25 ranking implementation — no external dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm: Okapi BM25 with standard parameters (k1=1.5, b=0.75).
|
|
5
|
+
*/
|
|
6
|
+
interface Bm25Doc {
|
|
7
|
+
id: number;
|
|
8
|
+
tokens: string[];
|
|
9
|
+
raw: string;
|
|
10
|
+
len: number;
|
|
11
|
+
}
|
|
12
|
+
/** Tokenise a string into lowercase word tokens. */
|
|
13
|
+
export declare function tokenise(text: string): string[];
|
|
14
|
+
export interface IndexableDoc {
|
|
15
|
+
id: number;
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Build indexable text for BM25 from a symbol's fields.
|
|
20
|
+
* The name is split into camelCase/SnakeCase words so that queries
|
|
21
|
+
* like "complex" match "complexOperation". The verbatim name is
|
|
22
|
+
* also included for exact-match queries.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildIndexableText(name: string, signature: string, docComment: string): string;
|
|
25
|
+
export declare function buildBm25Index(docs: IndexableDoc[]): Bm25Index;
|
|
26
|
+
export declare class Bm25Index {
|
|
27
|
+
private documents;
|
|
28
|
+
private df;
|
|
29
|
+
private N;
|
|
30
|
+
private readonly safeAvgLen;
|
|
31
|
+
constructor(documents: Bm25Doc[], df: Record<string, number>, N: number, avgLen: number);
|
|
32
|
+
score(query: string, filter?: (id: number) => boolean): Array<{
|
|
33
|
+
id: number;
|
|
34
|
+
score: number;
|
|
35
|
+
}>;
|
|
36
|
+
getDoc(id: number): Bm25Doc | undefined;
|
|
37
|
+
extractSnippet(docId: number, queryTokens: string[], radius?: number): string;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=bm25.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bm25.d.ts","sourceRoot":"","sources":["../../src/codebase-index/bm25.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,oDAAoD;AACpD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAI/C;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAgBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,SAAS,CAsB9D;AAED,qBAAa,SAAS;IAIlB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,CAAC;IALX,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,YACU,SAAS,EAAE,OAAO,EAAE,EACpB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,CAAC,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EAGf;IAED,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CA+B3F;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAEtC;IAED,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,MAAM,SAAK,GAAG,MAAM,CAexE;CACF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit breaker for the codebase indexer.
|
|
3
|
+
*
|
|
4
|
+
* The indexer can wedge: a hung filesystem, a parser pathology, or another
|
|
5
|
+
* wstack process holding the SQLite write lock (several surfaces — TUI, WebUI,
|
|
6
|
+
* parallel terminals — share one per-project `index.db`). Without protection,
|
|
7
|
+
* every queued reindex piles up behind the process-wide mutex, `isIndexing()`
|
|
8
|
+
* stays true forever, and anything that awaits an index run (the startup scan,
|
|
9
|
+
* `/codebase-reindex`) locks its terminal.
|
|
10
|
+
*
|
|
11
|
+
* Standard three-state breaker:
|
|
12
|
+
*
|
|
13
|
+
* closed — normal operation; consecutive failures are counted.
|
|
14
|
+
* open — after `failureThreshold` consecutive failures, every request
|
|
15
|
+
* is rejected fast ({@link CircuitOpenError}) for `cooldownMs`.
|
|
16
|
+
* half-open — after the cooldown exactly one probe run is admitted;
|
|
17
|
+
* success closes the circuit, failure re-opens it.
|
|
18
|
+
*
|
|
19
|
+
* Watchdog timeouts ({@link IndexTimeoutError}) count as failures;
|
|
20
|
+
* caller-initiated aborts (session teardown) do not — the background indexer
|
|
21
|
+
* makes that distinction before recording.
|
|
22
|
+
*
|
|
23
|
+
* Lock conflicts ({@link LockError}) do NOT count as failures — they are expected
|
|
24
|
+
* transient conditions when multiple wstack surfaces share the same `index.db`.
|
|
25
|
+
* The index store retries automatically; a LockError only reaches the circuit
|
|
26
|
+
* breaker when all retries are exhausted.
|
|
27
|
+
*/
|
|
28
|
+
export type CircuitState = 'closed' | 'open' | 'half-open';
|
|
29
|
+
export interface CircuitSnapshot {
|
|
30
|
+
state: CircuitState;
|
|
31
|
+
consecutiveFailures: number;
|
|
32
|
+
lastFailure: string | null;
|
|
33
|
+
/** ms until an open circuit admits a half-open probe (0 unless open). */
|
|
34
|
+
cooldownRemainingMs: number;
|
|
35
|
+
}
|
|
36
|
+
/** Thrown when a run is rejected because the circuit is open. */
|
|
37
|
+
export declare class CircuitOpenError extends Error {
|
|
38
|
+
readonly name = "CircuitOpenError";
|
|
39
|
+
}
|
|
40
|
+
/** Thrown by the background indexer's watchdog when a run exceeds its timeout. */
|
|
41
|
+
export declare class IndexTimeoutError extends Error {
|
|
42
|
+
readonly name = "IndexTimeoutError";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Thrown when an SQLite operation fails with a lock conflict (SQLITE_BUSY or
|
|
46
|
+
* SQLITE_LOCKED) even after all retry attempts are exhausted.
|
|
47
|
+
*
|
|
48
|
+
* The circuit breaker does **not** count `LockError` as a failure — a lock
|
|
49
|
+
* conflict means another writer is active, not that this indexer is broken.
|
|
50
|
+
* The caller should treat it as a transient failure and retry later.
|
|
51
|
+
*/
|
|
52
|
+
export declare class LockError extends Error {
|
|
53
|
+
readonly name = "LockError";
|
|
54
|
+
}
|
|
55
|
+
export interface CircuitBreakerOptions {
|
|
56
|
+
/** Consecutive failures before the circuit opens. Default: 3. */
|
|
57
|
+
failureThreshold?: number | undefined;
|
|
58
|
+
/** How long an open circuit rejects requests before allowing a probe. Default: 60s. */
|
|
59
|
+
cooldownMs?: number | undefined;
|
|
60
|
+
/** Injectable clock for tests. Default: Date.now. */
|
|
61
|
+
now?: (() => number) | undefined;
|
|
62
|
+
}
|
|
63
|
+
export declare class IndexCircuitBreaker {
|
|
64
|
+
private readonly failureThreshold;
|
|
65
|
+
private readonly cooldownMs;
|
|
66
|
+
private readonly now;
|
|
67
|
+
private state;
|
|
68
|
+
private consecutiveFailures;
|
|
69
|
+
private openedAt;
|
|
70
|
+
private lastFailure;
|
|
71
|
+
private probeInFlight;
|
|
72
|
+
constructor(opts?: CircuitBreakerOptions);
|
|
73
|
+
/**
|
|
74
|
+
* True when a run may proceed. An open circuit transitions to half-open once
|
|
75
|
+
* the cooldown has elapsed, admitting exactly one probe; further requests
|
|
76
|
+
* are rejected until that probe settles via recordSuccess/recordFailure.
|
|
77
|
+
*/
|
|
78
|
+
allowRequest(): boolean;
|
|
79
|
+
recordSuccess(): void;
|
|
80
|
+
recordFailure(err: unknown): void;
|
|
81
|
+
/** Force-close the circuit (manual recovery: `/codebase-reindex`). */
|
|
82
|
+
reset(): void;
|
|
83
|
+
snapshot(): CircuitSnapshot;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Process-wide breaker shared by every index path (startup scan, per-edit
|
|
87
|
+
* incremental, external watcher, the `codebase-index` tool). Module-level for
|
|
88
|
+
* the same reason the mutex is: there is one `index.db` per project and one
|
|
89
|
+
* indexing pipeline per process.
|
|
90
|
+
*/
|
|
91
|
+
export declare const indexCircuitBreaker: IndexCircuitBreaker;
|
|
92
|
+
/** Reset the shared breaker — used by `/codebase-reindex` and tests. */
|
|
93
|
+
export declare function resetIndexCircuitBreaker(): void;
|
|
94
|
+
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../src/codebase-index/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,yEAAyE;IACzE,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,iEAAiE;AACjE,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAkB,IAAI,sBAAsB;CAC7C;AAED,kFAAkF;AAClF,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,SAAkB,IAAI,uBAAuB;CAC9C;AAED;;;;;;;GAOG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAkB,IAAI,eAAe;CACtC;AAED,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,qDAAqD;IACrD,GAAG,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;CAClC;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,aAAa,CAAS;IAE9B,YAAY,IAAI,GAAE,qBAA0B,EAI3C;IAED;;;;OAIG;IACH,YAAY,IAAI,OAAO,CAYtB;IAED,aAAa,IAAI,IAAI,CAKpB;IAED,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAehC;IAED,sEAAsE;IACtE,KAAK,IAAI,IAAI,CAMZ;IAED,QAAQ,IAAI,eAAe,CAQ1B;CACF;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAC;AAE7D,wEAAwE;AACxE,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Tool } from '@wrongstack/core';
|
|
2
|
+
export declare const codebaseIndexTool: Tool<CodebaseIndexInput, CodebaseIndexOutput>;
|
|
3
|
+
interface CodebaseIndexInput {
|
|
4
|
+
force?: boolean | undefined;
|
|
5
|
+
langs?: string[] | undefined;
|
|
6
|
+
}
|
|
7
|
+
interface CodebaseIndexOutput {
|
|
8
|
+
filesIndexed: number;
|
|
9
|
+
symbolsIndexed: number;
|
|
10
|
+
langStats: Record<string, number>;
|
|
11
|
+
durationMs: number;
|
|
12
|
+
errors: string[];
|
|
13
|
+
/** Advisory note when the indexer was skipped (e.g. another index in progress). */
|
|
14
|
+
note?: string | undefined;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=codebase-index-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codebase-index-tool.d.ts","sourceRoot":"","sources":["../../src/codebase-index/codebase-index-tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAK7C,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,mBAAmB,CAyE3E,CAAC;AAIF,UAAU,kBAAkB;IAC1B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAC9B;AAED,UAAU,mBAAmB;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `codebase-search` tool — search the symbol index with BM25 ranking.
|
|
3
|
+
*
|
|
4
|
+
* Usage: codebase-search({
|
|
5
|
+
* query: string, // search terms
|
|
6
|
+
* kind?: string, // class|function|interface|method|const|...
|
|
7
|
+
* lang?: string, // ts|tsx|js|jsx|go|py|rs
|
|
8
|
+
* file?: string, // filter to a specific file path (substring match)
|
|
9
|
+
* limit?: number, // max results (default 20, max 100)
|
|
10
|
+
* })
|
|
11
|
+
*
|
|
12
|
+
* Returns: [{ name, kind, lang, file, line, signature, snippet, score }, ...]
|
|
13
|
+
*
|
|
14
|
+
* The query executes in the index worker via FTS5 (`MATCH` + native `bm25()`)
|
|
15
|
+
* — the main thread never opens SQLite, so a contended or wedged index can
|
|
16
|
+
* slow this tool down but can never freeze the terminal.
|
|
17
|
+
*/
|
|
18
|
+
import type { Tool } from '@wrongstack/core';
|
|
19
|
+
import type { SearchResult } from './schema.js';
|
|
20
|
+
export declare const codebaseSearchTool: Tool<CodebaseSearchInput, CodebaseSearchOutput>;
|
|
21
|
+
interface CodebaseSearchInput {
|
|
22
|
+
query: string;
|
|
23
|
+
kind?: string | undefined;
|
|
24
|
+
lang?: string | undefined;
|
|
25
|
+
file?: string | undefined;
|
|
26
|
+
limit?: number | undefined;
|
|
27
|
+
lspKind?: number | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* When true, hints that LSP-based search should be preferred over the index.
|
|
30
|
+
* The built-in tool ignores this (index-only), but when the LSP plugin is
|
|
31
|
+
* active it intercepts the tool and provides live LSP workspaceSymbol results.
|
|
32
|
+
*/
|
|
33
|
+
preferLsp?: boolean | undefined;
|
|
34
|
+
}
|
|
35
|
+
interface CodebaseSearchOutput {
|
|
36
|
+
results: SearchResult[];
|
|
37
|
+
total: number;
|
|
38
|
+
query: string;
|
|
39
|
+
/** Non-empty when the index blocked the search (not ready, indexing, failed). */
|
|
40
|
+
indexStatus?: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=codebase-search-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codebase-search-tool.d.ts","sourceRoot":"","sources":["../../src/codebase-index/codebase-search-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,kBAAkB,EAAE,IAAI,CAAC,mBAAmB,EAAE,oBAAoB,CA8G9E,CAAC;AAIF,UAAU,mBAAmB;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAED,UAAU,oBAAoB;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `codebase-stats` tool — report index health and statistics.
|
|
3
|
+
*
|
|
4
|
+
* Usage: codebase-stats({})
|
|
5
|
+
*
|
|
6
|
+
* Returns: { totalSymbols, totalFiles, byLang, byKind, lastIndexed, sizeBytes, version }
|
|
7
|
+
*/
|
|
8
|
+
import type { Tool } from '@wrongstack/core';
|
|
9
|
+
export declare const codebaseStatsTool: Tool<Record<string, never>, CodebaseStatsOutput>;
|
|
10
|
+
interface CodebaseStatsOutput {
|
|
11
|
+
totalSymbols: number;
|
|
12
|
+
totalFiles: number;
|
|
13
|
+
byLang: Record<string, number>;
|
|
14
|
+
byKind: Record<string, number>;
|
|
15
|
+
lastIndexed: number | null;
|
|
16
|
+
sizeBytes: number;
|
|
17
|
+
indexPath: string;
|
|
18
|
+
version: number;
|
|
19
|
+
/** Non-empty when the index is not ready or is still building. */
|
|
20
|
+
indexStatus?: string | undefined;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=codebase-stats-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codebase-stats-tool.d.ts","sourceRoot":"","sources":["../../src/codebase-index/codebase-stats-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAK7C,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,mBAAmB,CAwE9E,CAAC;AAEF,UAAU,mBAAmB;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal but faithful `.gitignore` matcher for the indexer.
|
|
3
|
+
*
|
|
4
|
+
* Supports the parts of the gitignore spec that matter for skipping source
|
|
5
|
+
* files: comments / blanks, `!` negation (last match wins), trailing-slash
|
|
6
|
+
* directory-only rules, leading-slash / embedded-slash anchoring, and the
|
|
7
|
+
* `*` / `**` / `?` / `[...]` globs (via core's {@link compileGlob}).
|
|
8
|
+
*
|
|
9
|
+
* Only the project-root `.gitignore` is read. Nested `.gitignore` files are not
|
|
10
|
+
* walked — the common build/dependency dirs that would live deeper are already
|
|
11
|
+
* covered by the indexer's always-on `DEFAULT_IGNORE`.
|
|
12
|
+
*
|
|
13
|
+
* Known limitation: a `!negated` file inside an ignored directory will not be
|
|
14
|
+
* re-included, because the indexer prunes ignored directories before descending
|
|
15
|
+
* (a large performance win). This matches most lightweight implementations.
|
|
16
|
+
*/
|
|
17
|
+
export type IgnoreMatcher = (relPath: string, isDir: boolean) => boolean;
|
|
18
|
+
/** Compile a list of raw `.gitignore` lines into a matcher. */
|
|
19
|
+
export declare function compileGitignore(lines: string[]): IgnoreMatcher;
|
|
20
|
+
/** Read `<projectRoot>/.gitignore` and compile it. Missing file → matches nothing. */
|
|
21
|
+
export declare function loadGitignoreMatcher(projectRoot: string): Promise<IgnoreMatcher>;
|
|
22
|
+
//# sourceMappingURL=gitignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/codebase-index/gitignore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAgBzE,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,aAAa,CAgD/D;AAED,sFAAsF;AACtF,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAStF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Go source symbol extraction using `go/parser`.
|
|
3
|
+
*
|
|
4
|
+
* Spawns a `go run -` child process that parses the file with go/ast and
|
|
5
|
+
* emits JSON. Falls back to empty results on any error.
|
|
6
|
+
*
|
|
7
|
+
* Extracts: package, func, type, const, var
|
|
8
|
+
*/
|
|
9
|
+
import type { FileSymbols, SymbolLang } from './schema.js';
|
|
10
|
+
export declare function parseSymbols(opts: {
|
|
11
|
+
file: string;
|
|
12
|
+
content: string;
|
|
13
|
+
lang: SymbolLang;
|
|
14
|
+
}): Promise<FileSymbols>;
|
|
15
|
+
export { detectLang } from './ts-parser.js';
|
|
16
|
+
//# sourceMappingURL=go-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"go-parser.d.ts","sourceRoot":"","sources":["../../src/codebase-index/go-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAyB,UAAU,EAAE,MAAM,aAAa,CAAC;AAIlF,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,CAAC;CAClB,GAAG,OAAO,CAAC,WAAW,CAAC,CAavB;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution-location-agnostic index operations.
|
|
3
|
+
*
|
|
4
|
+
* One implementation, two callers: the index worker thread (production —
|
|
5
|
+
* synchronous SQLite and the TypeScript parser can never block the main
|
|
6
|
+
* thread / terminal UI there) and the inline fallback inside the host (tests,
|
|
7
|
+
* `WRONGSTACK_INDEX_INLINE=1`, or runtimes where the worker file is missing).
|
|
8
|
+
*
|
|
9
|
+
* Every operation opens its own short-lived IndexStore, exactly like the old
|
|
10
|
+
* per-call code paths did — there is no connection state to share, which keeps
|
|
11
|
+
* multi-project usage trivially correct and crash recovery simple.
|
|
12
|
+
*/
|
|
13
|
+
import type { IndexResult, IndexStats } from './schema.js';
|
|
14
|
+
import type { IndexOpArgs, SearchOpArgs, SearchOpResult, StatsOpArgs } from './worker-protocol.js';
|
|
15
|
+
export interface ServiceHooks {
|
|
16
|
+
signal?: AbortSignal | undefined;
|
|
17
|
+
onProgress?: ((current: number, total: number) => void) | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Full or per-file index run. */
|
|
20
|
+
export declare function indexService(args: IndexOpArgs, hooks?: ServiceHooks): Promise<IndexResult>;
|
|
21
|
+
/** Ranked symbol search (FTS5 inside SQLite; BM25 fallback without FTS5). */
|
|
22
|
+
export declare function searchService(args: SearchOpArgs): SearchOpResult;
|
|
23
|
+
/** Index health and statistics. */
|
|
24
|
+
export declare function statsService(args: StatsOpArgs): IndexStats;
|
|
25
|
+
//# sourceMappingURL=index-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-service.d.ts","sourceRoot":"","sources":["../../src/codebase-index/index-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAA0B,MAAM,aAAa,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAenG,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACrE;AAED,kCAAkC;AAClC,wBAAsB,YAAY,CAChC,IAAI,EAAE,WAAW,EACjB,KAAK,GAAE,YAAiB,GACvB,OAAO,CAAC,WAAW,CAAC,CAWtB;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CAgBhE;AAED,mCAAmC;AACnC,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,CAO1D"}
|