@wrongstack/tools 1.0.8 → 1.0.9
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/_win32-resolve.d.ts +5 -0
- package/dist/audit.js +5 -5
- package/dist/bash.js +2 -2
- package/dist/browser/index.js +1 -1
- package/dist/builtin.js +41 -41
- package/dist/{chunk-N3OTTQNC.js → chunk-2OCAAFAT.js} +44 -25
- package/dist/{chunk-5MP76C72.js → chunk-2UVAIS5O.js} +24 -29
- package/dist/{chunk-SIIOHBNY.js → chunk-3RRK33YM.js} +2 -2
- package/dist/{chunk-M2W36JT7.js → chunk-4CE3RKEP.js} +6 -3
- package/dist/{chunk-QJARSK2G.js → chunk-4SUGLJLO.js} +11 -3
- package/dist/{chunk-AH7J5HWL.js → chunk-5RBUYFRV.js} +15 -7
- package/dist/{chunk-WKLUOXR4.js → chunk-7GOE2ZTZ.js} +2 -2
- package/dist/{chunk-O6AGFJBO.js → chunk-7V33PHT6.js} +49 -77
- package/dist/{chunk-CAF4L6KN.js → chunk-C3WP6ZOT.js} +36 -48
- package/dist/{chunk-KMXPP32M.js → chunk-C6ZOXNXV.js} +13 -3
- package/dist/{chunk-EGT5QLCB.js → chunk-D6RQZMZS.js} +123 -255
- package/dist/{chunk-S6CGSFLX.js → chunk-DBG7UQGK.js} +10 -3
- package/dist/{chunk-FI6SOIVE.js → chunk-DLZCOEVG.js} +21 -3
- package/dist/{chunk-NL45OWEO.js → chunk-DOAHONOS.js} +7 -12
- package/dist/{chunk-3LQJXJDM.js → chunk-E7A4SLKR.js} +2 -2
- package/dist/{chunk-JB5JLY7V.js → chunk-ENE22I5W.js} +387 -394
- package/dist/{chunk-SEONDNLN.js → chunk-G7CYW5EP.js} +2 -2
- package/dist/{chunk-MF6ZUBI7.js → chunk-HV7RWDCL.js} +3 -3
- package/dist/{chunk-TU6UVATU.js → chunk-HYHE4VNA.js} +3 -3
- package/dist/{chunk-HIRVCXLP.js → chunk-IE4KDAOB.js} +3 -3
- package/dist/{chunk-YA2ZYCJY.js → chunk-JPK2HHBK.js} +1 -1
- package/dist/{chunk-7E55DAFW.js → chunk-KHUCKLOR.js} +12 -7
- package/dist/{chunk-R3HIZVFS.js → chunk-KPDCKSN5.js} +23 -3
- package/dist/{chunk-B3MGJBFI.js → chunk-KS2OEZWV.js} +23 -47
- package/dist/{chunk-UI3ZJIG3.js → chunk-LKLIQUCW.js} +14 -8
- package/dist/{chunk-62OAECEQ.js → chunk-LLSFOUZF.js} +8 -8
- package/dist/{chunk-YZQSUL5G.js → chunk-M4ZHHCCW.js} +14 -6
- package/dist/{chunk-IXIS7RSG.js → chunk-MRXWOOOR.js} +29 -47
- package/dist/{chunk-C4DSQBTT.js → chunk-NEYUPZL6.js} +3 -3
- package/dist/{chunk-6XYFYLN7.js → chunk-O2MHULBO.js} +13 -8
- package/dist/{chunk-B62LKMWQ.js → chunk-OKZJJDOG.js} +86 -188
- package/dist/{chunk-HOFVYIPI.js → chunk-ON6ET5ER.js} +16 -1
- package/dist/{chunk-KF7GMVNU.js → chunk-OUERRFEM.js} +32 -11
- package/dist/{chunk-GNLHBDFO.js → chunk-OXO773CW.js} +127 -196
- package/dist/{chunk-GF4JHLCO.js → chunk-PWZUHZP7.js} +2 -2
- package/dist/{chunk-5KRKL3WD.js → chunk-QA37PFYL.js} +28 -67
- package/dist/{chunk-OGQMPX3J.js → chunk-QAWI3RSK.js} +37 -81
- package/dist/{chunk-ZMCV3XOV.js → chunk-SPNXDTCJ.js} +29 -63
- package/dist/{chunk-H2VB7GCR.js → chunk-ULI2J6TX.js} +27 -14
- package/dist/{chunk-EMA2XENR.js → chunk-UVYRQKPZ.js} +4 -3
- package/dist/{chunk-2NTHMZV3.js → chunk-VMJY6FYJ.js} +693 -276
- package/dist/{chunk-YUK3WLHJ.js → chunk-WEUEU53R.js} +2 -2
- package/dist/{chunk-ZOUG3KKS.js → chunk-XPVYZ2S6.js} +2 -2
- package/dist/{chunk-5U5ULQX2.js → chunk-XZLVJD56.js} +5 -1
- package/dist/{chunk-HCPSVK7J.js → chunk-YKSOSI2N.js} +47 -31
- package/dist/codebase-index/codebase-ast-replace-tool.d.ts +5 -6
- package/dist/codebase-index/codebase-context-tool.d.ts +4 -6
- package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +1 -2
- package/dist/codebase-index/codebase-incoming-calls-tool.d.ts +0 -2
- package/dist/codebase-index/codebase-index-tool.d.ts +0 -2
- package/dist/codebase-index/codebase-invariant-check-tool.d.ts +1 -2
- package/dist/codebase-index/codebase-outgoing-calls-tool.d.ts +0 -2
- package/dist/codebase-index/codebase-repo-map-tool.d.ts +1 -2
- package/dist/codebase-index/codebase-search-tool.d.ts +1 -1
- package/dist/codebase-index/codebase-targeted-test-tool.d.ts +1 -2
- package/dist/codebase-index/index.js +8 -8
- package/dist/codebase-index/parser-worker-script.js +3 -3
- package/dist/codebase-index/project-server.js +5 -5
- package/dist/codebase-index/worker.js +4 -4
- package/dist/design.js +1 -1
- package/dist/diff.js +1 -1
- package/dist/edit.js +7 -7
- package/dist/exec.d.ts +7 -7
- package/dist/exec.js +2 -2
- package/dist/format.js +5 -5
- package/dist/git.js +1 -1
- package/dist/glob.js +1 -1
- package/dist/{go-parser-VDPRQEGM.js → go-parser-Z4H6SR3R.js} +6 -3
- package/dist/grep.js +1 -1
- package/dist/index.js +45 -45
- package/dist/install.js +5 -5
- package/dist/json.d.ts +0 -1
- package/dist/json.js +1 -1
- package/dist/kanban-presence.d.ts +6 -0
- package/dist/kanban-serializer.d.ts +9 -1
- package/dist/kanban-split-task-handler.d.ts +1 -1
- package/dist/kanban-tool-results.d.ts +57 -2
- package/dist/kanban-tool-types.d.ts +16 -5
- package/dist/kanban.d.ts +14 -0
- package/dist/kanban.js +9 -1
- package/dist/languages/index.js +3 -3
- package/dist/{legacy-bridge-4T4OTSQP.js → legacy-bridge-BPT2S2F4.js} +5 -5
- package/dist/lint.js +5 -5
- package/dist/logs.js +1 -1
- package/dist/mode.d.ts +3 -2
- package/dist/mode.js +1 -1
- package/dist/outdated.js +2 -2
- package/dist/pack.js +42 -42
- package/dist/{parser-dispatch-4E2SDQUO.js → parser-dispatch-WG4DNBHH.js} +4 -4
- package/dist/patch.js +7 -7
- package/dist/plan.d.ts +2 -1
- package/dist/plan.js +3 -3
- package/dist/{py-parser-MAW6DHFE.js → py-parser-4PFZYAJ7.js} +3 -3
- package/dist/read.js +7 -7
- package/dist/replace.js +7 -7
- package/dist/search.d.ts +0 -6
- package/dist/search.js +1 -1
- package/dist/security-ast-scan-tool.d.ts +1 -2
- package/dist/session-shell.js +2 -2
- package/dist/task.d.ts +2 -1
- package/dist/task.js +3 -3
- package/dist/test.d.ts +8 -1
- package/dist/test.js +5 -5
- package/dist/todo.js +2 -2
- package/dist/tool-search.d.ts +2 -0
- package/dist/tool-search.js +1 -1
- package/dist/tool-tier.js +43 -43
- package/dist/tool-use.d.ts +2 -2
- package/dist/tool-use.js +1 -1
- package/dist/tree.js +1 -1
- package/dist/typecheck.js +5 -5
- package/dist/wasm/bash/tree-sitter-bash.wasm +0 -0
- package/dist/wasm/c/tree-sitter-c.wasm +0 -0
- package/dist/wasm/c_sharp/tree-sitter-c_sharp.wasm +0 -0
- package/dist/wasm/checksums.json +16 -0
- package/dist/wasm/cpp/tree-sitter-cpp.wasm +0 -0
- package/dist/wasm/elixir/tree-sitter-elixir.wasm +0 -0
- package/dist/wasm/go/tree-sitter-go.wasm +0 -0
- package/dist/wasm/java/tree-sitter-java.wasm +0 -0
- package/dist/wasm/kotlin/tree-sitter-kotlin.wasm +0 -0
- package/dist/wasm/php/tree-sitter-php.wasm +0 -0
- package/dist/wasm/python/tree-sitter-python.wasm +0 -0
- package/dist/wasm/ruby/tree-sitter-ruby.wasm +0 -0
- package/dist/wasm/rust/tree-sitter-rust.wasm +0 -0
- package/dist/wasm/swift/tree-sitter-swift.wasm +0 -0
- package/dist/wasm/tree-sitter-runtime.wasm +0 -0
- package/dist/win32.d.ts +1 -1
- package/dist/win32.js +3 -1
- package/dist/write.js +7 -7
- package/package.json +10 -10
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-XRNN44QY.js";
|
|
4
4
|
import {
|
|
5
5
|
spawnStream
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UVYRQKPZ.js";
|
|
7
7
|
import {
|
|
8
8
|
codebaseContext,
|
|
9
9
|
codebaseIndexStats,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
outgoingCallsService,
|
|
16
16
|
runStartupIndex,
|
|
17
17
|
searchCodebaseIndex
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-HYHE4VNA.js";
|
|
19
19
|
import {
|
|
20
20
|
IndexTimeoutError,
|
|
21
21
|
SCHEMA_VERSION,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
posixIndexPath,
|
|
27
27
|
resolveIndexDir,
|
|
28
28
|
xxhash64String
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-NEYUPZL6.js";
|
|
30
30
|
import {
|
|
31
31
|
EXT_TO_LANG,
|
|
32
32
|
detectLang,
|
|
@@ -477,6 +477,16 @@ async function loadTs2() {
|
|
|
477
477
|
}
|
|
478
478
|
return tsModule2;
|
|
479
479
|
}
|
|
480
|
+
function indentAt(content, pos) {
|
|
481
|
+
const lineStart = content.lastIndexOf("\n", pos - 1) + 1;
|
|
482
|
+
return /^[ \t]*/.exec(content.slice(lineStart, pos))?.[0] ?? "";
|
|
483
|
+
}
|
|
484
|
+
function reindent(text, indent) {
|
|
485
|
+
const lines = text.replace(/^\s*\n/, "").trimEnd().split("\n");
|
|
486
|
+
const widths = lines.filter((l) => l.trim()).map((l) => /^[ \t]*/.exec(l)?.[0].length ?? 0);
|
|
487
|
+
const common = widths.length > 0 ? Math.min(...widths) : 0;
|
|
488
|
+
return lines.map((l) => l.trim() ? `${indent}${l.slice(common)}` : "").join("\n");
|
|
489
|
+
}
|
|
480
490
|
async function mutateTsSymbol(content, lang, symbolName, newBody, target = "body") {
|
|
481
491
|
const ts = await loadTs2();
|
|
482
492
|
const scriptKind = lang === "tsx" ? ts.ScriptKind.TSX : lang === "jsx" ? ts.ScriptKind.JSX : lang === "js" ? ts.ScriptKind.JS : ts.ScriptKind.TS;
|
|
@@ -487,49 +497,88 @@ async function mutateTsSymbol(content, lang, symbolName, newBody, target = "body
|
|
|
487
497
|
true,
|
|
488
498
|
scriptKind
|
|
489
499
|
);
|
|
490
|
-
|
|
491
|
-
|
|
500
|
+
const nameOf = (node) => {
|
|
501
|
+
const n = node.name;
|
|
502
|
+
if (!n) return void 0;
|
|
503
|
+
return ts.isIdentifier(n) || ts.isPrivateIdentifier(n) || ts.isStringLiteral(n) ? n.text : void 0;
|
|
504
|
+
};
|
|
505
|
+
const matches = [];
|
|
506
|
+
const scope = [];
|
|
492
507
|
function visit(node) {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
} else if (ts.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
508
|
+
let declared;
|
|
509
|
+
let body = null;
|
|
510
|
+
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node)) {
|
|
511
|
+
declared = nameOf(node);
|
|
512
|
+
body = node.body ?? null;
|
|
513
|
+
} else if (ts.isConstructorDeclaration(node)) {
|
|
514
|
+
declared = "constructor";
|
|
515
|
+
body = node.body ?? null;
|
|
516
|
+
} else if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isEnumDeclaration(node) || ts.isModuleDeclaration(node)) {
|
|
517
|
+
declared = nameOf(node);
|
|
518
|
+
} else if (ts.isTypeAliasDeclaration(node)) {
|
|
519
|
+
declared = nameOf(node);
|
|
520
|
+
body = node.type;
|
|
521
|
+
} else if (ts.isVariableDeclaration(node) || ts.isPropertyDeclaration(node)) {
|
|
522
|
+
declared = nameOf(node);
|
|
523
|
+
const init = node.initializer;
|
|
524
|
+
if (init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
|
|
525
|
+
body = init.body;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (declared === void 0) {
|
|
529
|
+
ts.forEachChild(node, visit);
|
|
530
|
+
return;
|
|
516
531
|
}
|
|
532
|
+
matches.push({
|
|
533
|
+
node,
|
|
534
|
+
body,
|
|
535
|
+
qualified: [...scope, declared].join("."),
|
|
536
|
+
line: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1
|
|
537
|
+
});
|
|
538
|
+
scope.push(declared);
|
|
517
539
|
ts.forEachChild(node, visit);
|
|
540
|
+
scope.pop();
|
|
518
541
|
}
|
|
519
542
|
ts.forEachChild(sourceFile, visit);
|
|
520
|
-
|
|
521
|
-
|
|
543
|
+
let candidates = matches.filter(
|
|
544
|
+
(m) => m.qualified === symbolName || m.qualified.endsWith(`.${symbolName}`)
|
|
545
|
+
);
|
|
546
|
+
if (candidates.length === 0) return null;
|
|
547
|
+
if (candidates.length > 1) {
|
|
548
|
+
const first = candidates[0]?.qualified;
|
|
549
|
+
const overloadable = candidates.every(
|
|
550
|
+
(m) => m.qualified === first && (ts.isFunctionDeclaration(m.node) || ts.isMethodDeclaration(m.node) || ts.isConstructorDeclaration(m.node))
|
|
551
|
+
);
|
|
552
|
+
const implemented = candidates.filter((m) => m.body !== null);
|
|
553
|
+
if (overloadable && implemented.length === 1) candidates = implemented;
|
|
554
|
+
}
|
|
555
|
+
if (candidates.length > 1) {
|
|
556
|
+
const listed = candidates.map((m) => `${m.qualified} (L${m.line})`).join(", ");
|
|
557
|
+
const example = candidates.find((m) => m.qualified.includes("."))?.qualified;
|
|
558
|
+
throw new Error(
|
|
559
|
+
`Symbol '${symbolName}' is ambiguous: ${candidates.length} declarations match \u2014 ${listed}. ` + (example ? `Pass a qualified name, e.g. symbol: "${example}".` : "Rename-free disambiguation is impossible here; use the edit tool.")
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
const match = candidates[0];
|
|
563
|
+
let fullNode = match.node;
|
|
564
|
+
if (ts.isVariableDeclaration(match.node)) {
|
|
565
|
+
const list = match.node.parent;
|
|
566
|
+
const stmt = list?.parent;
|
|
567
|
+
if (list && ts.isVariableDeclarationList(list) && list.declarations.length === 1 && stmt && ts.isVariableStatement(stmt)) {
|
|
568
|
+
fullNode = stmt;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const replaceTarget = target === "full" || !match.body ? fullNode : match.body;
|
|
522
572
|
const startPos = replaceTarget.getStart(sourceFile);
|
|
523
573
|
const endPos = replaceTarget.getEnd();
|
|
524
574
|
const startLine = sourceFile.getLineAndCharacterOfPosition(startPos).line + 1;
|
|
525
575
|
const endLine = sourceFile.getLineAndCharacterOfPosition(endPos).line + 1;
|
|
526
576
|
let formattedReplacement = newBody.trim();
|
|
527
|
-
if (target === "body" &&
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}`;
|
|
532
|
-
}
|
|
577
|
+
if (target === "body" && match.body && ts.isBlock(match.body) && !formattedReplacement.startsWith("{")) {
|
|
578
|
+
const baseIndent = indentAt(content, fullNode.getStart(sourceFile));
|
|
579
|
+
formattedReplacement = `{
|
|
580
|
+
${reindent(newBody, `${baseIndent} `)}
|
|
581
|
+
${baseIndent}}`;
|
|
533
582
|
}
|
|
534
583
|
const updatedContent = content.slice(0, startPos) + formattedReplacement + content.slice(endPos);
|
|
535
584
|
const newEndLine = startLine + formattedReplacement.split("\n").length - 1;
|
|
@@ -599,6 +648,21 @@ async function mutateTreeSitterSymbol(content, lang, symbolName, newBody, target
|
|
|
599
648
|
parser.delete();
|
|
600
649
|
}
|
|
601
650
|
}
|
|
651
|
+
var TEST_CALLEES = String.raw`(?:it|test|describe|suite|bench|context|specify)`;
|
|
652
|
+
function notFoundMessage(symbol, relPath, content) {
|
|
653
|
+
const base = `Symbol '${symbol}' could not be located in AST of '${relPath}'`;
|
|
654
|
+
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
655
|
+
const testCall = new RegExp(
|
|
656
|
+
String.raw`\b${TEST_CALLEES}(?:\.\w+)*\s*\(\s*(['"\x60])${escaped}\1`
|
|
657
|
+
);
|
|
658
|
+
if (testCall.test(content)) {
|
|
659
|
+
return `${base}: that is a test-case title, not a declaration. codebase-ast-replace only resolves named declarations (function, method, class, interface, type, enum, variable); use the edit tool to change a test case.`;
|
|
660
|
+
}
|
|
661
|
+
if (!/^[\p{L}_$#][\p{L}\p{N}_$]*(?:\.[\p{L}_$#][\p{L}\p{N}_$]*)*$/u.test(symbol)) {
|
|
662
|
+
return `${base}: '${symbol}' is not a declaration name. Pass an identifier such as "calculateTotal", or a qualified "ClassName.method" for a nested member.`;
|
|
663
|
+
}
|
|
664
|
+
return `${base}. Check the name with codebase-search, or qualify a nested member as "Outer.inner".`;
|
|
665
|
+
}
|
|
602
666
|
async function replaceSymbolInFile(opts, projectRoot) {
|
|
603
667
|
const resolved = path.isAbsolute(opts.file) ? opts.file : path.resolve(projectRoot, opts.file);
|
|
604
668
|
const content = await fs.readFile(resolved, "utf8");
|
|
@@ -610,9 +674,7 @@ async function replaceSymbolInFile(opts, projectRoot) {
|
|
|
610
674
|
result = await mutateTreeSitterSymbol(content, lang, opts.symbol, opts.newBody, opts.target);
|
|
611
675
|
}
|
|
612
676
|
if (!result) {
|
|
613
|
-
throw new Error(
|
|
614
|
-
`Symbol '${opts.symbol}' could not be located in AST of '${path.relative(projectRoot, resolved)}'`
|
|
615
|
-
);
|
|
677
|
+
throw new Error(notFoundMessage(opts.symbol, path.relative(projectRoot, resolved), content));
|
|
616
678
|
}
|
|
617
679
|
result.file = resolved;
|
|
618
680
|
if (opts.checkInvariants !== false) {
|
|
@@ -642,7 +704,6 @@ Pass allowBreakingChanges: true if this breaking change is intended.`
|
|
|
642
704
|
|
|
643
705
|
// src/codebase-index/codebase-ast-replace-tool.ts
|
|
644
706
|
import * as path2 from "node:path";
|
|
645
|
-
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
646
707
|
var codebaseAstReplaceTool = {
|
|
647
708
|
name: "codebase-ast-replace",
|
|
648
709
|
category: "Edit",
|
|
@@ -651,7 +712,7 @@ var codebaseAstReplaceTool = {
|
|
|
651
712
|
subjectKey: "file",
|
|
652
713
|
mutating: true,
|
|
653
714
|
capabilities: ["fs.write", "fs.read"],
|
|
654
|
-
description: "Surgically replace the implementation body or full definition of a function, method, class,
|
|
715
|
+
description: "Surgically replace the implementation body or full definition of a named declaration (function, method, class, interface, type alias, enum, variable) using AST parsing. Test cases (`it(...)`/`test(...)` titles) are call arguments, not declarations \u2014 use the edit tool for those. Guarantees zero string-matching errors, regex escape bugs, or whitespace indentation mismatches. Automatically verifies AST backward-compatibility invariants (no mandatory param addition, no export deletion, no interface breaking).",
|
|
655
716
|
usageHint: 'SURGICAL AST-BASED CODE EDITING:\n\n- Use when updating an existing function, method, or class without worrying about context lines.\n- Pass `symbol: "calculateTotal"` and `newBody: "return items.reduce(...);"`.\n- Default `target: "body"` replaces only the inner `{ ... }` block while preserving the signature and JSDoc.\n- Use `target: "full"` if you also need to modify the function parameters or return type.\n- Setting `allowBreakingChanges: true` bypasses the invariant engine if breaking changes are deliberate.',
|
|
656
717
|
inputSchema: {
|
|
657
718
|
type: "object",
|
|
@@ -662,7 +723,7 @@ var codebaseAstReplaceTool = {
|
|
|
662
723
|
},
|
|
663
724
|
symbol: {
|
|
664
725
|
type: "string",
|
|
665
|
-
description:
|
|
726
|
+
description: 'Declaration name (function, method, class, interface, type, enum, variable). Qualify nested members as "ClassName.method" when the bare name is ambiguous. Not a test-case title.'
|
|
666
727
|
},
|
|
667
728
|
newBody: {
|
|
668
729
|
type: "string",
|
|
@@ -685,33 +746,27 @@ var codebaseAstReplaceTool = {
|
|
|
685
746
|
required: ["file", "symbol", "newBody"],
|
|
686
747
|
additionalProperties: false
|
|
687
748
|
},
|
|
749
|
+
// Failures THROW. A returned `{ status: 'error' }` is a successful tool call
|
|
750
|
+
// to the executor (is_error:false) — the UI showed "ok", the audit log and
|
|
751
|
+
// spans recorded success, and only a model reading the payload noticed.
|
|
688
752
|
async execute(input, ctx) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
};
|
|
701
|
-
} catch (err) {
|
|
702
|
-
return {
|
|
703
|
-
status: "error",
|
|
704
|
-
file: input.file,
|
|
705
|
-
symbol: input.symbol,
|
|
706
|
-
error: toErrorMessage(err)
|
|
707
|
-
};
|
|
708
|
-
}
|
|
753
|
+
const projectRoot = ctx.projectRoot ?? ctx.cwd ?? process.cwd();
|
|
754
|
+
const file = await safeResolveProjectPath(input.file, ctx);
|
|
755
|
+
const result = await replaceSymbolInFile({ ...input, file }, projectRoot);
|
|
756
|
+
return {
|
|
757
|
+
status: "ok",
|
|
758
|
+
file: path2.relative(projectRoot, result.file).replace(/\\/g, "/"),
|
|
759
|
+
symbol: result.symbol,
|
|
760
|
+
originalRange: result.originalRange,
|
|
761
|
+
newRange: result.newRange,
|
|
762
|
+
violations: result.violations?.map((v) => `[${v.ruleId}] ${v.message}`)
|
|
763
|
+
};
|
|
709
764
|
}
|
|
710
765
|
};
|
|
711
766
|
|
|
712
767
|
// src/codebase-index/codebase-impact-analysis-tool.ts
|
|
713
768
|
import * as path3 from "node:path";
|
|
714
|
-
import { toErrorMessage
|
|
769
|
+
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
715
770
|
var TEST_FILE_REGEX = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
|
|
716
771
|
var codebaseImpactAnalysisTool = {
|
|
717
772
|
name: "codebase-impact-analysis",
|
|
@@ -742,141 +797,114 @@ var codebaseImpactAnalysisTool = {
|
|
|
742
797
|
additionalProperties: false
|
|
743
798
|
},
|
|
744
799
|
async execute(input, ctx) {
|
|
800
|
+
const projectRoot = ctx.projectRoot ?? ctx.cwd ?? process.cwd();
|
|
801
|
+
const indexDir = codebaseIndexDirOverride(ctx);
|
|
802
|
+
const limit = 200;
|
|
803
|
+
const transitive = input.transitive ?? true;
|
|
804
|
+
let rawSites = [];
|
|
805
|
+
let symbolFound = true;
|
|
806
|
+
let indexUnavailable = false;
|
|
807
|
+
let indexError;
|
|
745
808
|
try {
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
const transitive = input.transitive ?? true;
|
|
750
|
-
let rawSites = [];
|
|
751
|
-
let symbolFound = true;
|
|
752
|
-
let indexUnavailable = false;
|
|
753
|
-
let indexError;
|
|
754
|
-
try {
|
|
755
|
-
const serviced = await incomingCallsService({
|
|
756
|
-
projectRoot,
|
|
757
|
-
indexDir,
|
|
758
|
-
symbol: input.symbol,
|
|
759
|
-
file: input.file,
|
|
760
|
-
limit,
|
|
761
|
-
transitive
|
|
762
|
-
});
|
|
763
|
-
rawSites = serviced.calls;
|
|
764
|
-
symbolFound = serviced.symbolFound;
|
|
765
|
-
} catch (err) {
|
|
766
|
-
symbolFound = false;
|
|
767
|
-
indexUnavailable = true;
|
|
768
|
-
indexError = toErrorMessage2(err);
|
|
769
|
-
}
|
|
770
|
-
if (indexUnavailable) {
|
|
771
|
-
const detail = indexError ? ` (${indexError})` : "";
|
|
772
|
-
const reason = `Index query failed for '${input.symbol}'. Run codebase-index, then retry.${detail}`;
|
|
773
|
-
return {
|
|
774
|
-
status: "error",
|
|
775
|
-
symbol: input.symbol,
|
|
776
|
-
riskLevel: "low",
|
|
777
|
-
summary: reason,
|
|
778
|
-
totalCallSites: 0,
|
|
779
|
-
affectedProductionFiles: [],
|
|
780
|
-
affectedTestFiles: [],
|
|
781
|
-
callSites: [],
|
|
782
|
-
recommendedActionPlan: [reason],
|
|
783
|
-
symbolFound: false,
|
|
784
|
-
error: reason
|
|
785
|
-
};
|
|
786
|
-
}
|
|
787
|
-
if (!symbolFound) {
|
|
788
|
-
const reason = `Symbol '${input.symbol}' was not found in the index` + (input.file ? ` for file filter '${input.file}'` : "") + ". Use codebase-search to verify the name.";
|
|
789
|
-
return {
|
|
790
|
-
status: "ok",
|
|
791
|
-
symbol: input.symbol,
|
|
792
|
-
riskLevel: "low",
|
|
793
|
-
summary: reason,
|
|
794
|
-
totalCallSites: 0,
|
|
795
|
-
affectedProductionFiles: [],
|
|
796
|
-
affectedTestFiles: [],
|
|
797
|
-
callSites: [],
|
|
798
|
-
recommendedActionPlan: [reason],
|
|
799
|
-
symbolFound: false
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
const prodFilesSet = /* @__PURE__ */ new Set();
|
|
803
|
-
const testFilesSet = /* @__PURE__ */ new Set();
|
|
804
|
-
const callSites = [];
|
|
805
|
-
for (const site of rawSites) {
|
|
806
|
-
const relPath = path3.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
|
|
807
|
-
const isTest = TEST_FILE_REGEX.test(relPath);
|
|
808
|
-
if (isTest) {
|
|
809
|
-
testFilesSet.add(relPath);
|
|
810
|
-
} else {
|
|
811
|
-
prodFilesSet.add(relPath);
|
|
812
|
-
}
|
|
813
|
-
callSites.push({
|
|
814
|
-
file: relPath,
|
|
815
|
-
line: site.line,
|
|
816
|
-
callerName: site.symbol.name,
|
|
817
|
-
callerKind: site.symbol.kind,
|
|
818
|
-
callType: site.callType,
|
|
819
|
-
isTest
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
const prodFiles = [...prodFilesSet];
|
|
823
|
-
const testFiles = [...testFilesSet];
|
|
824
|
-
const totalCallSites = callSites.length;
|
|
825
|
-
let riskLevel = "low";
|
|
826
|
-
if (prodFiles.length > 5 || totalCallSites > 10) {
|
|
827
|
-
riskLevel = "high";
|
|
828
|
-
} else if (prodFiles.length > 1 || totalCallSites > 3) {
|
|
829
|
-
riskLevel = "medium";
|
|
830
|
-
}
|
|
831
|
-
const recommendedActionPlan = [];
|
|
832
|
-
if (prodFiles.length > 0) {
|
|
833
|
-
recommendedActionPlan.push(
|
|
834
|
-
`Update ${totalCallSites} call site(s) across ${prodFiles.length} production file(s): ${prodFiles.slice(0, 3).join(", ")}${prodFiles.length > 3 ? ` +${prodFiles.length - 3} more` : ""}`
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
|
-
if (testFiles.length > 0) {
|
|
838
|
-
recommendedActionPlan.push(
|
|
839
|
-
`Run targeted tests in ${testFiles.length} test suite(s): ${testFiles.join(", ")}`
|
|
840
|
-
);
|
|
841
|
-
} else {
|
|
842
|
-
recommendedActionPlan.push(
|
|
843
|
-
`No existing test files directly cover '${input.symbol}'. Consider adding a test suite.`
|
|
844
|
-
);
|
|
845
|
-
}
|
|
846
|
-
const summary = `Blast Radius for '${input.symbol}': ${riskLevel.toUpperCase()} RISK (${totalCallSites} call sites in ${prodFiles.length} prod files, ${testFiles.length} test suites).`;
|
|
847
|
-
return {
|
|
848
|
-
status: "ok",
|
|
809
|
+
const serviced = await incomingCallsService({
|
|
810
|
+
projectRoot,
|
|
811
|
+
indexDir,
|
|
849
812
|
symbol: input.symbol,
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
recommendedActionPlan,
|
|
857
|
-
symbolFound: true
|
|
858
|
-
};
|
|
813
|
+
file: input.file,
|
|
814
|
+
limit,
|
|
815
|
+
transitive
|
|
816
|
+
});
|
|
817
|
+
rawSites = serviced.calls;
|
|
818
|
+
symbolFound = serviced.symbolFound;
|
|
859
819
|
} catch (err) {
|
|
820
|
+
symbolFound = false;
|
|
821
|
+
indexUnavailable = true;
|
|
822
|
+
indexError = toErrorMessage(err);
|
|
823
|
+
}
|
|
824
|
+
if (indexUnavailable) {
|
|
825
|
+
const detail = indexError ? ` (${indexError})` : "";
|
|
826
|
+
throw new Error(
|
|
827
|
+
`Index query failed for '${input.symbol}'. Run codebase-index, then retry.${detail}`
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
if (!symbolFound) {
|
|
831
|
+
const reason = `Symbol '${input.symbol}' was not found in the index` + (input.file ? ` for file filter '${input.file}'` : "") + ". Use codebase-search to verify the name.";
|
|
860
832
|
return {
|
|
861
|
-
status: "
|
|
833
|
+
status: "ok",
|
|
862
834
|
symbol: input.symbol,
|
|
863
835
|
riskLevel: "low",
|
|
864
|
-
summary:
|
|
836
|
+
summary: reason,
|
|
865
837
|
totalCallSites: 0,
|
|
866
838
|
affectedProductionFiles: [],
|
|
867
839
|
affectedTestFiles: [],
|
|
868
840
|
callSites: [],
|
|
869
|
-
recommendedActionPlan: [],
|
|
870
|
-
symbolFound: false
|
|
871
|
-
error: toErrorMessage2(err)
|
|
841
|
+
recommendedActionPlan: [reason],
|
|
842
|
+
symbolFound: false
|
|
872
843
|
};
|
|
873
844
|
}
|
|
845
|
+
const prodFilesSet = /* @__PURE__ */ new Set();
|
|
846
|
+
const testFilesSet = /* @__PURE__ */ new Set();
|
|
847
|
+
const callSites = [];
|
|
848
|
+
for (const site of rawSites) {
|
|
849
|
+
const relPath = path3.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
|
|
850
|
+
const isTest = TEST_FILE_REGEX.test(relPath);
|
|
851
|
+
if (isTest) {
|
|
852
|
+
testFilesSet.add(relPath);
|
|
853
|
+
} else {
|
|
854
|
+
prodFilesSet.add(relPath);
|
|
855
|
+
}
|
|
856
|
+
callSites.push({
|
|
857
|
+
file: relPath,
|
|
858
|
+
line: site.line,
|
|
859
|
+
callerName: site.symbol.name,
|
|
860
|
+
callerKind: site.symbol.kind,
|
|
861
|
+
callType: site.callType,
|
|
862
|
+
isTest
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
const prodFiles = [...prodFilesSet];
|
|
866
|
+
const testFiles = [...testFilesSet];
|
|
867
|
+
const totalCallSites = callSites.length;
|
|
868
|
+
let riskLevel = "low";
|
|
869
|
+
if (prodFiles.length > 5 || totalCallSites > 10) {
|
|
870
|
+
riskLevel = "high";
|
|
871
|
+
} else if (prodFiles.length > 1 || totalCallSites > 3) {
|
|
872
|
+
riskLevel = "medium";
|
|
873
|
+
}
|
|
874
|
+
const recommendedActionPlan = [];
|
|
875
|
+
if (prodFiles.length > 0) {
|
|
876
|
+
recommendedActionPlan.push(
|
|
877
|
+
`Update ${totalCallSites} call site(s) across ${prodFiles.length} production file(s): ${prodFiles.slice(0, 3).join(", ")}${prodFiles.length > 3 ? ` +${prodFiles.length - 3} more` : ""}`
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
if (testFiles.length > 0) {
|
|
881
|
+
recommendedActionPlan.push(
|
|
882
|
+
`Run targeted tests in ${testFiles.length} test suite(s): ${testFiles.join(", ")}`
|
|
883
|
+
);
|
|
884
|
+
} else {
|
|
885
|
+
recommendedActionPlan.push(
|
|
886
|
+
`No existing test files directly cover '${input.symbol}'. Consider adding a test suite.`
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
const summary = `Blast Radius for '${input.symbol}': ${riskLevel.toUpperCase()} RISK (${totalCallSites} call sites in ${prodFiles.length} prod files, ${testFiles.length} test suites).`;
|
|
890
|
+
return {
|
|
891
|
+
status: "ok",
|
|
892
|
+
symbol: input.symbol,
|
|
893
|
+
riskLevel,
|
|
894
|
+
summary,
|
|
895
|
+
totalCallSites,
|
|
896
|
+
affectedProductionFiles: prodFiles,
|
|
897
|
+
affectedTestFiles: testFiles,
|
|
898
|
+
callSites,
|
|
899
|
+
recommendedActionPlan,
|
|
900
|
+
symbolFound: true
|
|
901
|
+
};
|
|
874
902
|
}
|
|
875
903
|
};
|
|
876
904
|
|
|
877
905
|
// src/codebase-index/codebase-incoming-calls-tool.ts
|
|
878
906
|
import { ToolValidationError } from "@wrongstack/core/types";
|
|
879
|
-
import { toErrorMessage as
|
|
907
|
+
import { toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
|
|
880
908
|
var codebaseIncomingCallsTool = {
|
|
881
909
|
name: "codebase-incoming-calls",
|
|
882
910
|
category: "Project",
|
|
@@ -923,12 +951,7 @@ var codebaseIncomingCallsTool = {
|
|
|
923
951
|
if (state.lastError) {
|
|
924
952
|
const circuit = state.circuit;
|
|
925
953
|
const retryHint = circuit.state === "open" ? `Indexing is paused (circuit open, retry in ${Math.ceil(circuit.cooldownRemainingMs / 1e3)}s).` : "Try /codebase-reindex.";
|
|
926
|
-
|
|
927
|
-
symbol: input.symbol,
|
|
928
|
-
calls: [],
|
|
929
|
-
total: 0,
|
|
930
|
-
indexStatus: `Index build failed: ${state.lastError}. ${retryHint}`
|
|
931
|
-
};
|
|
954
|
+
throw new Error(`Index build failed: ${state.lastError}. ${retryHint}`);
|
|
932
955
|
}
|
|
933
956
|
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 50), 200));
|
|
934
957
|
const transitive = input.transitive === true;
|
|
@@ -945,19 +968,15 @@ var codebaseIncomingCallsTool = {
|
|
|
945
968
|
});
|
|
946
969
|
} catch (err) {
|
|
947
970
|
if (err.name === "IndexRefreshInProgressError") {
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
indexStatus: `Index refresh in progress (${state.currentFile}/${state.totalFiles} files); this symbol has no cached answer yet \u2014 retry after the completed generation is published.`
|
|
953
|
-
};
|
|
971
|
+
throw new Error(
|
|
972
|
+
`Index refresh in progress (${state.currentFile}/${state.totalFiles} files); this symbol has no cached answer yet \u2014 retry after the completed generation is published.`,
|
|
973
|
+
{ cause: err }
|
|
974
|
+
);
|
|
954
975
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
indexStatus: `Index query failed: ${toErrorMessage3(err)}. Fall back to grep for this lookup.`
|
|
960
|
-
};
|
|
976
|
+
throw new Error(
|
|
977
|
+
`Index query failed: ${toErrorMessage2(err)}. Fall back to grep for this lookup.`,
|
|
978
|
+
{ cause: err }
|
|
979
|
+
);
|
|
961
980
|
}
|
|
962
981
|
const { calls, symbolFound, ambiguous, totalMatches, stale } = serviced;
|
|
963
982
|
if (!symbolFound) {
|
|
@@ -969,16 +988,17 @@ var codebaseIncomingCallsTool = {
|
|
|
969
988
|
indexDir: codebaseIndexDirOverride(ctx)
|
|
970
989
|
});
|
|
971
990
|
hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
|
|
972
|
-
} catch {
|
|
991
|
+
} catch (err) {
|
|
992
|
+
throw new Error(
|
|
993
|
+
`Symbol "${input.symbol}" was not found and the persisted index could not be verified: ${toErrorMessage2(err)}. Try /codebase-reindex or fall back to grep.`,
|
|
994
|
+
{ cause: err }
|
|
995
|
+
);
|
|
973
996
|
}
|
|
974
997
|
}
|
|
975
998
|
if (!hasPersistedIndex) {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
total: 0,
|
|
980
|
-
indexStatus: "No persisted index data found. Run codebase-index to build it."
|
|
981
|
-
};
|
|
999
|
+
throw new Error(
|
|
1000
|
+
"No persisted index data found. Run codebase-index to build it, then retry."
|
|
1001
|
+
);
|
|
982
1002
|
}
|
|
983
1003
|
return {
|
|
984
1004
|
symbol: input.symbol,
|
|
@@ -1018,7 +1038,7 @@ import { ToolValidationError as ToolValidationError3 } from "@wrongstack/core/ty
|
|
|
1018
1038
|
|
|
1019
1039
|
// src/codebase-index/codebase-search-tool.ts
|
|
1020
1040
|
import { ToolValidationError as ToolValidationError2 } from "@wrongstack/core/types";
|
|
1021
|
-
import { toErrorMessage as
|
|
1041
|
+
import { toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
|
|
1022
1042
|
var INDEXABLE_LANG_IDS = [
|
|
1023
1043
|
...new Set(Object.values(EXT_TO_LANG))
|
|
1024
1044
|
].sort();
|
|
@@ -1112,12 +1132,7 @@ var codebaseSearchTool = {
|
|
|
1112
1132
|
if (state.lastError) {
|
|
1113
1133
|
const circuit = state.circuit;
|
|
1114
1134
|
const retryHint = circuit.state === "open" ? `Indexing is paused (circuit open, retry in ${Math.ceil(circuit.cooldownRemainingMs / 1e3)}s); the user can run /codebase-reindex to retry now.` : "Try /codebase-reindex.";
|
|
1115
|
-
|
|
1116
|
-
results: [],
|
|
1117
|
-
total: 0,
|
|
1118
|
-
query: input.query,
|
|
1119
|
-
indexStatus: `Index build failed: ${state.lastError}. ${retryHint}`
|
|
1120
|
-
};
|
|
1135
|
+
throw new Error(`Index build failed: ${state.lastError}. ${retryHint}`);
|
|
1121
1136
|
}
|
|
1122
1137
|
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 20), 100));
|
|
1123
1138
|
let searched;
|
|
@@ -1140,19 +1155,15 @@ var codebaseSearchTool = {
|
|
|
1140
1155
|
signal.throwIfAborted();
|
|
1141
1156
|
}
|
|
1142
1157
|
if (err.name === "IndexRefreshInProgressError") {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
indexStatus: `Index refresh in progress (${state.currentFile}/${state.totalFiles} files); this query has no cached answer yet \u2014 retry after the completed generation is published.`
|
|
1148
|
-
};
|
|
1158
|
+
throw new Error(
|
|
1159
|
+
`Index refresh in progress (${state.currentFile}/${state.totalFiles} files); this query has no cached answer yet \u2014 retry after the completed generation is published.`,
|
|
1160
|
+
{ cause: err }
|
|
1161
|
+
);
|
|
1149
1162
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
indexStatus: `Index query failed: ${toErrorMessage4(err)}. Fall back to grep/glob for this lookup.`
|
|
1155
|
-
};
|
|
1163
|
+
throw new Error(
|
|
1164
|
+
`Index query failed: ${toErrorMessage3(err)}. Fall back to grep/glob for this lookup.`,
|
|
1165
|
+
{ cause: err }
|
|
1166
|
+
);
|
|
1156
1167
|
}
|
|
1157
1168
|
const { results, total, stale, indexSummary } = searched;
|
|
1158
1169
|
let hasPersistedIndex = state.ready || total > 0;
|
|
@@ -1166,9 +1177,19 @@ var codebaseSearchTool = {
|
|
|
1166
1177
|
{ signal }
|
|
1167
1178
|
);
|
|
1168
1179
|
hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
|
|
1169
|
-
} catch {
|
|
1180
|
+
} catch (err) {
|
|
1181
|
+
if (signal?.aborted) signal.throwIfAborted();
|
|
1182
|
+
throw new Error(
|
|
1183
|
+
`codebase-search found no results and could not verify the persisted index: ${toErrorMessage3(err)}. Try /codebase-reindex or fall back to grep/glob.`,
|
|
1184
|
+
{ cause: err }
|
|
1185
|
+
);
|
|
1170
1186
|
}
|
|
1171
1187
|
}
|
|
1188
|
+
if (!hasPersistedIndex) {
|
|
1189
|
+
throw new Error(
|
|
1190
|
+
"No persisted index data found. Run codebase-index to build it, then retry codebase-search."
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1172
1193
|
return {
|
|
1173
1194
|
results,
|
|
1174
1195
|
total,
|
|
@@ -1176,8 +1197,7 @@ var codebaseSearchTool = {
|
|
|
1176
1197
|
...stale ? {
|
|
1177
1198
|
stale: true,
|
|
1178
1199
|
indexStatus: `Index refresh in progress (${state.currentFile}/${state.totalFiles} files); results served from the previous generation \u2014 symbols from files being indexed may lag.`
|
|
1179
|
-
} : {}
|
|
1180
|
-
...hasPersistedIndex ? {} : { indexStatus: "No persisted index data found. Run codebase-index to build it." }
|
|
1200
|
+
} : {}
|
|
1181
1201
|
};
|
|
1182
1202
|
}
|
|
1183
1203
|
};
|
|
@@ -1235,28 +1255,18 @@ var codebaseIndexTool = {
|
|
|
1235
1255
|
}
|
|
1236
1256
|
}
|
|
1237
1257
|
if (isIndexing()) {
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
langStats: {},
|
|
1242
|
-
durationMs: 0,
|
|
1243
|
-
errors: [],
|
|
1244
|
-
note: "A full index is already in progress. Retry codebase-index after it completes (check codebase-stats)."
|
|
1245
|
-
};
|
|
1258
|
+
throw new Error(
|
|
1259
|
+
"A full index is already in progress. Retry codebase-index after it completes (check codebase-stats)."
|
|
1260
|
+
);
|
|
1246
1261
|
}
|
|
1247
1262
|
if (input.force) {
|
|
1248
1263
|
indexCircuitBreaker.reset();
|
|
1249
1264
|
} else {
|
|
1250
1265
|
const circuit = indexCircuitBreaker.snapshot();
|
|
1251
1266
|
if (circuit.state === "open" && circuit.cooldownRemainingMs > 0) {
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
langStats: {},
|
|
1256
|
-
durationMs: 0,
|
|
1257
|
-
errors: [],
|
|
1258
|
-
note: `Codebase indexing is paused after repeated failures (last: ${circuit.lastFailure ?? "unknown"}). Auto-retry possible in ${Math.max(1, Math.ceil(circuit.cooldownRemainingMs / 1e3))}s; use force: true or run /codebase-reindex to retry immediately.`
|
|
1259
|
-
};
|
|
1267
|
+
throw new Error(
|
|
1268
|
+
`Codebase indexing is paused after repeated failures (last: ${circuit.lastFailure ?? "unknown"}). Auto-retry possible in ${Math.max(1, Math.ceil(circuit.cooldownRemainingMs / 1e3))}s; use force: true or run /codebase-reindex to retry immediately.`
|
|
1269
|
+
);
|
|
1260
1270
|
}
|
|
1261
1271
|
}
|
|
1262
1272
|
const result = await runStartupIndex({
|
|
@@ -1279,7 +1289,7 @@ var codebaseIndexTool = {
|
|
|
1279
1289
|
|
|
1280
1290
|
// src/codebase-index/codebase-invariant-check-tool.ts
|
|
1281
1291
|
import * as fs2 from "node:fs/promises";
|
|
1282
|
-
import {
|
|
1292
|
+
import { ToolValidationError as ToolValidationError4 } from "@wrongstack/core/types";
|
|
1283
1293
|
var codebaseInvariantCheckTool = {
|
|
1284
1294
|
name: "codebase-invariant-check",
|
|
1285
1295
|
category: "Inspect",
|
|
@@ -1313,52 +1323,44 @@ var codebaseInvariantCheckTool = {
|
|
|
1313
1323
|
required: ["modifiedCode"],
|
|
1314
1324
|
additionalProperties: false
|
|
1315
1325
|
},
|
|
1326
|
+
// Failures THROW. The old catch returned `valid: false` — a successful call
|
|
1327
|
+
// (is_error:false) whose payload was indistinguishable from "this change
|
|
1328
|
+
// breaks compatibility", so an unreadable file read as a real violation.
|
|
1316
1329
|
async execute(input, ctx) {
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
lang = detectLang(resolved) ?? "ts";
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
if (originalCode === void 0) {
|
|
1328
|
-
return {
|
|
1329
|
-
valid: false,
|
|
1330
|
-
violations: [],
|
|
1331
|
-
summary: "Neither originalCode nor file was provided for invariant comparison.",
|
|
1332
|
-
error: "Missing originalCode or file path."
|
|
1333
|
-
};
|
|
1330
|
+
let originalCode = input.originalCode;
|
|
1331
|
+
let lang = input.lang;
|
|
1332
|
+
if (!originalCode && input.file) {
|
|
1333
|
+
const resolved = await safeResolveProjectPath(input.file, ctx);
|
|
1334
|
+
originalCode = await fs2.readFile(resolved, "utf8");
|
|
1335
|
+
if (!lang) {
|
|
1336
|
+
lang = detectLang(resolved) ?? "ts";
|
|
1334
1337
|
}
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1338
|
+
}
|
|
1339
|
+
if (originalCode === void 0) {
|
|
1340
|
+
throw new ToolValidationError4({
|
|
1341
|
+
message: "Neither originalCode nor file was provided for invariant comparison.",
|
|
1342
|
+
field: "originalCode"
|
|
1340
1343
|
});
|
|
1341
|
-
const summary = res.valid ? "AST Invariants PASSED. Mutation is 100% backward compatible." : `AST Invariants FAILED with ${res.violations.length} violation(s):
|
|
1342
|
-
` + res.violations.map((v) => ` - [${v.ruleId}] ${v.symbolName}: ${v.message}`).join("\n");
|
|
1343
|
-
return {
|
|
1344
|
-
valid: res.valid,
|
|
1345
|
-
violations: res.violations,
|
|
1346
|
-
summary
|
|
1347
|
-
};
|
|
1348
|
-
} catch (err) {
|
|
1349
|
-
return {
|
|
1350
|
-
valid: false,
|
|
1351
|
-
violations: [],
|
|
1352
|
-
summary: `Error during invariant evaluation: ${toErrorMessage5(err)}`,
|
|
1353
|
-
error: toErrorMessage5(err)
|
|
1354
|
-
};
|
|
1355
1344
|
}
|
|
1345
|
+
const res = await polyglotInvariantEngine.evaluate({
|
|
1346
|
+
originalCode,
|
|
1347
|
+
modifiedCode: input.modifiedCode,
|
|
1348
|
+
lang,
|
|
1349
|
+
filePath: input.file
|
|
1350
|
+
});
|
|
1351
|
+
const summary = res.valid ? "AST Invariants PASSED. Mutation is 100% backward compatible." : `AST Invariants FAILED with ${res.violations.length} violation(s):
|
|
1352
|
+
` + res.violations.map((v) => ` - [${v.ruleId}] ${v.symbolName}: ${v.message}`).join("\n");
|
|
1353
|
+
return {
|
|
1354
|
+
valid: res.valid,
|
|
1355
|
+
violations: res.violations,
|
|
1356
|
+
summary
|
|
1357
|
+
};
|
|
1356
1358
|
}
|
|
1357
1359
|
};
|
|
1358
1360
|
|
|
1359
1361
|
// src/codebase-index/codebase-outgoing-calls-tool.ts
|
|
1360
|
-
import { ToolValidationError as
|
|
1361
|
-
import { toErrorMessage as
|
|
1362
|
+
import { ToolValidationError as ToolValidationError5 } from "@wrongstack/core/types";
|
|
1363
|
+
import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
|
|
1362
1364
|
var codebaseOutgoingCallsTool = {
|
|
1363
1365
|
name: "codebase-outgoing-calls",
|
|
1364
1366
|
category: "Project",
|
|
@@ -1396,7 +1398,7 @@ var codebaseOutgoingCallsTool = {
|
|
|
1396
1398
|
},
|
|
1397
1399
|
async execute(input, ctx) {
|
|
1398
1400
|
if (!input?.symbol || typeof input.symbol !== "string" || !input.symbol.trim()) {
|
|
1399
|
-
throw new
|
|
1401
|
+
throw new ToolValidationError5({
|
|
1400
1402
|
message: "codebase-outgoing-calls: symbol is required and cannot be empty",
|
|
1401
1403
|
field: "symbol"
|
|
1402
1404
|
});
|
|
@@ -1405,12 +1407,7 @@ var codebaseOutgoingCallsTool = {
|
|
|
1405
1407
|
if (state.lastError) {
|
|
1406
1408
|
const circuit = state.circuit;
|
|
1407
1409
|
const retryHint = circuit.state === "open" ? `Indexing is paused (circuit open, retry in ${Math.ceil(circuit.cooldownRemainingMs / 1e3)}s).` : "Try /codebase-reindex.";
|
|
1408
|
-
|
|
1409
|
-
symbol: input.symbol,
|
|
1410
|
-
calls: [],
|
|
1411
|
-
total: 0,
|
|
1412
|
-
indexStatus: `Index build failed: ${state.lastError}. ${retryHint}`
|
|
1413
|
-
};
|
|
1410
|
+
throw new Error(`Index build failed: ${state.lastError}. ${retryHint}`);
|
|
1414
1411
|
}
|
|
1415
1412
|
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 50), 200));
|
|
1416
1413
|
const transitive = input.transitive === true;
|
|
@@ -1427,19 +1424,15 @@ var codebaseOutgoingCallsTool = {
|
|
|
1427
1424
|
});
|
|
1428
1425
|
} catch (err) {
|
|
1429
1426
|
if (err.name === "IndexRefreshInProgressError") {
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
indexStatus: `Index refresh in progress (${state.currentFile}/${state.totalFiles} files); this symbol has no cached answer yet \u2014 retry after the completed generation is published.`
|
|
1435
|
-
};
|
|
1427
|
+
throw new Error(
|
|
1428
|
+
`Index refresh in progress (${state.currentFile}/${state.totalFiles} files); this symbol has no cached answer yet \u2014 retry after the completed generation is published.`,
|
|
1429
|
+
{ cause: err }
|
|
1430
|
+
);
|
|
1436
1431
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
indexStatus: `Index query failed: ${toErrorMessage6(err)}. Fall back to grep for this lookup.`
|
|
1442
|
-
};
|
|
1432
|
+
throw new Error(
|
|
1433
|
+
`Index query failed: ${toErrorMessage4(err)}. Fall back to grep for this lookup.`,
|
|
1434
|
+
{ cause: err }
|
|
1435
|
+
);
|
|
1443
1436
|
}
|
|
1444
1437
|
const { calls, symbolFound, unresolvedCount, totalMatches, stale } = serviced;
|
|
1445
1438
|
if (!symbolFound) {
|
|
@@ -1451,16 +1444,17 @@ var codebaseOutgoingCallsTool = {
|
|
|
1451
1444
|
indexDir: codebaseIndexDirOverride(ctx)
|
|
1452
1445
|
});
|
|
1453
1446
|
hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
|
|
1454
|
-
} catch {
|
|
1447
|
+
} catch (err) {
|
|
1448
|
+
throw new Error(
|
|
1449
|
+
`Symbol "${input.symbol}" was not found and the persisted index could not be verified: ${toErrorMessage4(err)}. Try /codebase-reindex or fall back to grep.`,
|
|
1450
|
+
{ cause: err }
|
|
1451
|
+
);
|
|
1455
1452
|
}
|
|
1456
1453
|
}
|
|
1457
1454
|
if (!hasPersistedIndex) {
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
total: 0,
|
|
1462
|
-
indexStatus: "No persisted index data found. Run codebase-index to build it."
|
|
1463
|
-
};
|
|
1455
|
+
throw new Error(
|
|
1456
|
+
"No persisted index data found. Run codebase-index to build it, then retry."
|
|
1457
|
+
);
|
|
1464
1458
|
}
|
|
1465
1459
|
return {
|
|
1466
1460
|
symbol: input.symbol,
|
|
@@ -1495,9 +1489,6 @@ var codebaseOutgoingCallsTool = {
|
|
|
1495
1489
|
}
|
|
1496
1490
|
};
|
|
1497
1491
|
|
|
1498
|
-
// src/codebase-index/codebase-repo-map-tool.ts
|
|
1499
|
-
import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
|
|
1500
|
-
|
|
1501
1492
|
// src/codebase-index/repo-map.ts
|
|
1502
1493
|
import { existsSync } from "node:fs";
|
|
1503
1494
|
import * as path6 from "node:path";
|
|
@@ -2171,38 +2162,28 @@ var codebaseRepoMapTool = {
|
|
|
2171
2162
|
},
|
|
2172
2163
|
additionalProperties: false
|
|
2173
2164
|
},
|
|
2165
|
+
// Failures THROW so the executor marks the call is_error (a returned
|
|
2166
|
+
// `status: 'error'` payload was recorded as a successful call).
|
|
2174
2167
|
async execute(input, ctx) {
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
};
|
|
2189
|
-
} catch (err) {
|
|
2190
|
-
return {
|
|
2191
|
-
status: "error",
|
|
2192
|
-
map: "",
|
|
2193
|
-
filesCount: 0,
|
|
2194
|
-
totalFilesScanned: 0,
|
|
2195
|
-
estimatedTokens: 0,
|
|
2196
|
-
rankedFiles: [],
|
|
2197
|
-
error: toErrorMessage7(err)
|
|
2198
|
-
};
|
|
2199
|
-
}
|
|
2168
|
+
const projectRoot = ctx.projectRoot ?? ctx.cwd ?? process.cwd();
|
|
2169
|
+
const result = await generateRepoMap({
|
|
2170
|
+
projectRoot,
|
|
2171
|
+
maxTokens: input.maxTokens,
|
|
2172
|
+
focusFiles: input.focusFiles,
|
|
2173
|
+
// Honour a caller-supplied index location so the map reads the same
|
|
2174
|
+
// index the other codebase-* tools do.
|
|
2175
|
+
indexDir: codebaseIndexDirOverride(ctx)
|
|
2176
|
+
});
|
|
2177
|
+
return {
|
|
2178
|
+
status: "ok",
|
|
2179
|
+
...result
|
|
2180
|
+
};
|
|
2200
2181
|
}
|
|
2201
2182
|
};
|
|
2202
2183
|
|
|
2203
2184
|
// src/codebase-index/codebase-skeleton-tool.ts
|
|
2204
2185
|
import * as fs6 from "node:fs/promises";
|
|
2205
|
-
import { toErrorMessage as
|
|
2186
|
+
import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
|
|
2206
2187
|
var codebaseSkeletonTool = {
|
|
2207
2188
|
name: "codebase-skeleton",
|
|
2208
2189
|
category: "Project",
|
|
@@ -2249,7 +2230,7 @@ var codebaseSkeletonTool = {
|
|
|
2249
2230
|
stat3 = await fs6.stat(targetPath);
|
|
2250
2231
|
} catch (err) {
|
|
2251
2232
|
throw new Error(
|
|
2252
|
-
`codebase-skeleton: file or directory not found at "${input.path}": ${
|
|
2233
|
+
`codebase-skeleton: file or directory not found at "${input.path}": ${toErrorMessage5(err)}`
|
|
2253
2234
|
);
|
|
2254
2235
|
}
|
|
2255
2236
|
const options = {
|
|
@@ -2298,7 +2279,7 @@ var codebaseSkeletonTool = {
|
|
|
2298
2279
|
};
|
|
2299
2280
|
|
|
2300
2281
|
// src/codebase-index/codebase-stats-tool.ts
|
|
2301
|
-
import { toErrorMessage as
|
|
2282
|
+
import { toErrorMessage as toErrorMessage6 } from "@wrongstack/core/utils";
|
|
2302
2283
|
var codebaseStatsTool = {
|
|
2303
2284
|
name: "codebase-stats",
|
|
2304
2285
|
category: "Project",
|
|
@@ -2350,18 +2331,10 @@ var codebaseStatsTool = {
|
|
|
2350
2331
|
if (signal?.aborted) {
|
|
2351
2332
|
signal.throwIfAborted();
|
|
2352
2333
|
}
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
byKind: {},
|
|
2358
|
-
lastIndexed: null,
|
|
2359
|
-
sizeBytes: 0,
|
|
2360
|
-
indexPath,
|
|
2361
|
-
version: SCHEMA_VERSION,
|
|
2362
|
-
statsAvailable: false,
|
|
2363
|
-
indexStatus: err instanceof IndexTimeoutError || err?.name === "IndexTimeoutError" ? "Index statistics timed out. Do not repeatedly retry stats; try codebase-search directly or use the appropriate grep/glob/tree fallback." : `Index statistics query failed: ${toErrorMessage9(err)}. The index may be corrupted or inaccessible; try /codebase-reindex.`
|
|
2364
|
-
};
|
|
2334
|
+
throw new Error(
|
|
2335
|
+
err instanceof IndexTimeoutError || err?.name === "IndexTimeoutError" ? "Index statistics timed out. Do not repeatedly retry stats; try codebase-search directly or use the appropriate grep/glob/tree fallback." : `Index statistics query failed: ${toErrorMessage6(err)}. The index may be corrupted or inaccessible; try /codebase-reindex.`,
|
|
2336
|
+
{ cause: err }
|
|
2337
|
+
);
|
|
2365
2338
|
}
|
|
2366
2339
|
const circuit = idxState.circuit;
|
|
2367
2340
|
const hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
|
|
@@ -2390,7 +2363,7 @@ var codebaseStatsTool = {
|
|
|
2390
2363
|
// src/codebase-index/codebase-targeted-test-tool.ts
|
|
2391
2364
|
import * as fs7 from "node:fs/promises";
|
|
2392
2365
|
import * as path7 from "node:path";
|
|
2393
|
-
import { toErrorMessage as
|
|
2366
|
+
import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
|
|
2394
2367
|
var TEST_FILE_REGEX2 = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
|
|
2395
2368
|
async function findConventionTestFiles(projectRoot, sourceRelPath) {
|
|
2396
2369
|
const parsed = path7.parse(sourceRelPath);
|
|
@@ -2535,16 +2508,10 @@ ${streamRes.stderr}`.trim(),
|
|
|
2535
2508
|
output: combinedOutput
|
|
2536
2509
|
};
|
|
2537
2510
|
} catch (err) {
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
passed: 0,
|
|
2543
|
-
failed: 0,
|
|
2544
|
-
durationMs: 0,
|
|
2545
|
-
output: "",
|
|
2546
|
-
error: toErrorMessage10(err)
|
|
2547
|
-
};
|
|
2511
|
+
const suites = suitesSet.size > 0 ? ` (discovered suites: ${[...suitesSet].join(", ")})` : "";
|
|
2512
|
+
throw new Error(`Targeted test run failed to execute: ${toErrorMessage7(err)}${suites}`, {
|
|
2513
|
+
cause: err
|
|
2514
|
+
});
|
|
2548
2515
|
}
|
|
2549
2516
|
}
|
|
2550
2517
|
};
|
|
@@ -2552,6 +2519,7 @@ ${streamRes.stderr}`.trim(),
|
|
|
2552
2519
|
// src/codebase-index/dead-code-scan.ts
|
|
2553
2520
|
import * as fs8 from "node:fs";
|
|
2554
2521
|
import * as path8 from "node:path";
|
|
2522
|
+
import { ToolValidationError as ToolValidationError6 } from "@wrongstack/core/types";
|
|
2555
2523
|
var deadCodeScanTool = {
|
|
2556
2524
|
name: "dead-code-scan",
|
|
2557
2525
|
category: "Project",
|
|
@@ -2582,12 +2550,36 @@ var deadCodeScanTool = {
|
|
|
2582
2550
|
},
|
|
2583
2551
|
async execute(input, ctx, _execOpts) {
|
|
2584
2552
|
const startMs = Date.now();
|
|
2585
|
-
const projectRoot = input.projectRoot
|
|
2553
|
+
const projectRoot = input.projectRoot !== void 0 ? await safeResolveProjectPath(input.projectRoot, ctx) : ctx.projectRoot ?? ctx.cwd ?? process.cwd();
|
|
2586
2554
|
const indexDir = input.indexDir ?? codebaseIndexDirOverride(ctx) ?? void 0;
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
userEntryPoints
|
|
2590
|
-
|
|
2555
|
+
let userEntryPoints;
|
|
2556
|
+
if (input.entryPoints) {
|
|
2557
|
+
userEntryPoints = [];
|
|
2558
|
+
for (const ep of input.entryPoints) {
|
|
2559
|
+
const resolved = await safeResolveProjectPath(
|
|
2560
|
+
path8.isAbsolute(ep) ? ep : path8.resolve(projectRoot, ep),
|
|
2561
|
+
ctx
|
|
2562
|
+
);
|
|
2563
|
+
if (!fs8.existsSync(resolved)) {
|
|
2564
|
+
throw new ToolValidationError6({
|
|
2565
|
+
message: `dead-code-scan: entry point not found: "${ep}"`,
|
|
2566
|
+
field: "entryPoints"
|
|
2567
|
+
});
|
|
2568
|
+
}
|
|
2569
|
+
userEntryPoints.push(resolved);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
const result = runDeadCodeScan(projectRoot, { indexDir, userEntryPoints });
|
|
2573
|
+
if (result.stats.totalSymbols === 0) {
|
|
2574
|
+
throw new Error(
|
|
2575
|
+
`dead-code-scan: the codebase index for "${projectRoot}" has no symbols. Run codebase-index, then retry.`
|
|
2576
|
+
);
|
|
2577
|
+
}
|
|
2578
|
+
if (result.stats.alive === 0) {
|
|
2579
|
+
throw new Error(
|
|
2580
|
+
`dead-code-scan: no indexed entry point was found under "${projectRoot}" (package.json main/bin/exports/types or src/index.ts), so reachability cannot be computed. Pass \`entryPoints\`.`
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2591
2583
|
return {
|
|
2592
2584
|
...result,
|
|
2593
2585
|
stats: { ...result.stats, durationMs: Date.now() - startMs }
|
|
@@ -3568,8 +3560,8 @@ async function buildProjectAtlasBrief(projectRoot, opts = {}) {
|
|
|
3568
3560
|
}
|
|
3569
3561
|
|
|
3570
3562
|
// src/codebase-index/codebase-context-tool.ts
|
|
3571
|
-
import { ToolValidationError as
|
|
3572
|
-
import { toErrorMessage as
|
|
3563
|
+
import { ToolValidationError as ToolValidationError7 } from "@wrongstack/core/types";
|
|
3564
|
+
import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
|
|
3573
3565
|
var TOOL_TIMEOUT_MS = 35e3;
|
|
3574
3566
|
var VECTOR_HIT_LIMIT = 12;
|
|
3575
3567
|
var VECTOR_MIN_SCORE = 0.25;
|
|
@@ -3604,7 +3596,7 @@ var codebaseContextTool = {
|
|
|
3604
3596
|
capabilities: ["fs.read"],
|
|
3605
3597
|
timeoutMs: TOOL_TIMEOUT_MS,
|
|
3606
3598
|
description: "Find the files and declarations a task touches, from a plain-language description. Combines ranked symbol search with a personalised walk over the reference graph, so results include not just what matched by name but what those matches are structurally attached to \u2014 the interface behind a handler, the store behind a route, the module every match imports. Returns ranked files with the relevant declarations, their signatures and line numbers.",
|
|
3607
|
-
usageHint: 'START HERE FOR ANY TASK THAT SPANS MORE THAN ONE FILE:\n\n- Describe the task, not a symbol name: `codebase-context({ query: "retry a provider request after a 429" })`.\n- Prefer this over `codebase-search` when you do not already know the symbol you want; prefer `codebase-search` when you do.\n- Use the returned `file` + `line` to `read` only the parts you need, instead of reading whole files.\n- `matched: true` means the file matched the query directly; the rest were reached through the graph.\n- `relevance` is relative to this answer only (top result is always 1.0) \u2014 never compare it across queries.\n- Narrow with `pathPrefix: "packages/core"` when you already know the area.\n-
|
|
3599
|
+
usageHint: 'START HERE FOR ANY TASK THAT SPANS MORE THAN ONE FILE:\n\n- Describe the task, not a symbol name: `codebase-context({ query: "retry a provider request after a 429" })`.\n- Prefer this over `codebase-search` when you do not already know the symbol you want; prefer `codebase-search` when you do.\n- Use the returned `file` + `line` to `read` only the parts you need, instead of reading whole files.\n- `matched: true` means the file matched the query directly; the rest were reached through the graph.\n- `relevance` is relative to this answer only (top result is always 1.0) \u2014 never compare it across queries.\n- Narrow with `pathPrefix: "packages/core"` when you already know the area.\n- If the call fails because no index exists, run `/codebase-reindex` (or `codebase-index`) first.',
|
|
3608
3600
|
inputSchema: {
|
|
3609
3601
|
type: "object",
|
|
3610
3602
|
properties: {
|
|
@@ -3631,19 +3623,20 @@ var codebaseContextTool = {
|
|
|
3631
3623
|
async execute(input, ctx, execOpts) {
|
|
3632
3624
|
const query = typeof input.query === "string" ? input.query.trim() : "";
|
|
3633
3625
|
if (query.length === 0) {
|
|
3634
|
-
throw new
|
|
3626
|
+
throw new ToolValidationError7({
|
|
3635
3627
|
message: "codebase-context requires a non-empty `query`.",
|
|
3636
3628
|
field: "query"
|
|
3637
3629
|
});
|
|
3638
3630
|
}
|
|
3639
3631
|
const signal = execOpts?.signal ?? ctx.signal;
|
|
3640
3632
|
const projectRoot = ctx.projectRoot ?? ctx.cwd ?? process.cwd();
|
|
3633
|
+
signal?.throwIfAborted();
|
|
3634
|
+
const indexDir = codebaseIndexDirOverride(ctx);
|
|
3635
|
+
let result;
|
|
3641
3636
|
try {
|
|
3642
|
-
signal?.throwIfAborted();
|
|
3643
|
-
const indexDir = codebaseIndexDirOverride(ctx);
|
|
3644
3637
|
const vectorFiles = await semanticSeeds(projectRoot, indexDir, query);
|
|
3645
3638
|
signal?.throwIfAborted();
|
|
3646
|
-
|
|
3639
|
+
result = await codebaseContext({
|
|
3647
3640
|
projectRoot,
|
|
3648
3641
|
indexDir,
|
|
3649
3642
|
query,
|
|
@@ -3652,28 +3645,28 @@ var codebaseContextTool = {
|
|
|
3652
3645
|
symbolsPerFile: input.symbolsPerFile,
|
|
3653
3646
|
pathPrefix: input.pathPrefix
|
|
3654
3647
|
});
|
|
3655
|
-
return {
|
|
3656
|
-
query: result.query,
|
|
3657
|
-
entries: result.entries,
|
|
3658
|
-
seedCount: result.seedCount,
|
|
3659
|
-
semanticSeedCount: result.semanticSeedCount,
|
|
3660
|
-
totalCandidates: result.totalCandidates,
|
|
3661
|
-
indexStatus: result.indexStatus,
|
|
3662
|
-
..."stale" in result && result.stale === true ? { stale: true } : {}
|
|
3663
|
-
};
|
|
3664
3648
|
} catch (err) {
|
|
3665
3649
|
if (signal?.aborted) throw err;
|
|
3666
3650
|
const refreshing = err instanceof Error && err.name === "IndexRefreshInProgressError";
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3651
|
+
throw new Error(
|
|
3652
|
+
refreshing ? "Codebase index is refreshing; retry once the current generation is published." : `codebase-context lookup failed: ${toErrorMessage8(err)}`,
|
|
3653
|
+
{ cause: err }
|
|
3654
|
+
);
|
|
3655
|
+
}
|
|
3656
|
+
if (result.indexStatus === "no-index") {
|
|
3657
|
+
throw new Error(
|
|
3658
|
+
"No codebase index data found. Run /codebase-reindex (or codebase-index), then retry codebase-context."
|
|
3659
|
+
);
|
|
3676
3660
|
}
|
|
3661
|
+
return {
|
|
3662
|
+
query: result.query,
|
|
3663
|
+
entries: result.entries,
|
|
3664
|
+
seedCount: result.seedCount,
|
|
3665
|
+
semanticSeedCount: result.semanticSeedCount,
|
|
3666
|
+
totalCandidates: result.totalCandidates,
|
|
3667
|
+
indexStatus: result.indexStatus,
|
|
3668
|
+
..."stale" in result && result.stale === true ? { stale: true } : {}
|
|
3669
|
+
};
|
|
3677
3670
|
}
|
|
3678
3671
|
};
|
|
3679
3672
|
|
|
@@ -4047,4 +4040,4 @@ export {
|
|
|
4047
4040
|
embedFiles,
|
|
4048
4041
|
embedProjectFiles
|
|
4049
4042
|
};
|
|
4050
|
-
//# sourceMappingURL=chunk-
|
|
4043
|
+
//# sourceMappingURL=chunk-ENE22I5W.js.map
|