@wrongstack/tools 0.298.3 → 0.299.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/bash.js +14 -0
- package/dist/builtin.js +396 -0
- package/dist/codebase-index/background-indexer.d.ts +6 -1
- package/dist/codebase-index/codebase-incoming-calls-tool.d.ts +34 -0
- package/dist/codebase-index/codebase-outgoing-calls-tool.d.ts +34 -0
- package/dist/codebase-index/index-service.d.ts +24 -2
- package/dist/codebase-index/index.d.ts +4 -2
- package/dist/codebase-index/index.js +382 -0
- package/dist/codebase-index/project-server.js +177 -1
- package/dist/codebase-index/schema.d.ts +23 -0
- package/dist/codebase-index/worker-protocol.d.ts +14 -0
- package/dist/codebase-index/worker.js +164 -0
- package/dist/codebase-index/writer-graph-reader.d.ts +24 -1
- package/dist/codebase-index/writer.d.ts +21 -1
- package/dist/exec.js +4 -0
- package/dist/index.js +396 -0
- package/dist/pack.js +394 -0
- package/dist/ps-slash.js +4 -0
- package/dist/read.js +164 -0
- package/dist/tool-tier.js +396 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -7440,6 +7440,10 @@ async function acquireLock(lockfilePath, timeoutMs = 5e3) {
|
|
|
7440
7440
|
const start = Date.now();
|
|
7441
7441
|
const pidStr = String(process.pid);
|
|
7442
7442
|
const hostStr = os2.hostname();
|
|
7443
|
+
try {
|
|
7444
|
+
await fs6.mkdir(path9.dirname(lockfilePath), { recursive: true });
|
|
7445
|
+
} catch {
|
|
7446
|
+
}
|
|
7443
7447
|
while (Date.now() - start < timeoutMs) {
|
|
7444
7448
|
try {
|
|
7445
7449
|
await fs6.writeFile(lockfilePath, `${pidStr}:${hostStr}:${Date.now()}`, { flag: "wx" });
|
|
@@ -8111,6 +8115,16 @@ function parseKillCommand(command) {
|
|
|
8111
8115
|
if (pgrepMatch) {
|
|
8112
8116
|
return null;
|
|
8113
8117
|
}
|
|
8118
|
+
const posixScriptMatch = normalized.match(SCRIPT_KILL_RE_POSIX);
|
|
8119
|
+
if (posixScriptMatch) {
|
|
8120
|
+
return {
|
|
8121
|
+
name: "kill-script",
|
|
8122
|
+
signal: "FORCE",
|
|
8123
|
+
isGroupKill: false,
|
|
8124
|
+
isAllKill: false,
|
|
8125
|
+
originalCommand: command
|
|
8126
|
+
};
|
|
8127
|
+
}
|
|
8114
8128
|
return null;
|
|
8115
8129
|
}
|
|
8116
8130
|
async function getProtectedEntries() {
|
|
@@ -10908,6 +10922,136 @@ function mapWriterRefRow(row) {
|
|
|
10908
10922
|
}
|
|
10909
10923
|
|
|
10910
10924
|
// src/codebase-index/writer-graph-reader.ts
|
|
10925
|
+
var MAX_SQL_VARS = 900;
|
|
10926
|
+
function chunkedIdQuery(stmt, ids, buildSql, extraArgs = []) {
|
|
10927
|
+
const results = [];
|
|
10928
|
+
for (let start = 0; start < ids.length; start += MAX_SQL_VARS) {
|
|
10929
|
+
const chunk = ids.slice(start, start + MAX_SQL_VARS);
|
|
10930
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
10931
|
+
const sql = buildSql(placeholders);
|
|
10932
|
+
results.push(...stmt(sql).all(...chunk, ...extraArgs));
|
|
10933
|
+
}
|
|
10934
|
+
return results;
|
|
10935
|
+
}
|
|
10936
|
+
function chunkedIdScalar(stmt, ids, buildSql, extraArgs = []) {
|
|
10937
|
+
let total = 0;
|
|
10938
|
+
for (let start = 0; start < ids.length; start += MAX_SQL_VARS) {
|
|
10939
|
+
const chunk = ids.slice(start, start + MAX_SQL_VARS);
|
|
10940
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
10941
|
+
const sql = buildSql(placeholders);
|
|
10942
|
+
const rows = stmt(sql).all(...chunk, ...extraArgs);
|
|
10943
|
+
total += rows[0]?.n ?? 0;
|
|
10944
|
+
}
|
|
10945
|
+
return total;
|
|
10946
|
+
}
|
|
10947
|
+
function mapCallSiteRow(row) {
|
|
10948
|
+
return {
|
|
10949
|
+
symbol: {
|
|
10950
|
+
id: row.sym_id,
|
|
10951
|
+
name: row.sym_name,
|
|
10952
|
+
kind: row.sym_kind,
|
|
10953
|
+
lang: row.sym_lang,
|
|
10954
|
+
file: row.sym_file,
|
|
10955
|
+
line: row.sym_line,
|
|
10956
|
+
signature: row.sym_signature
|
|
10957
|
+
},
|
|
10958
|
+
callType: row.call_type,
|
|
10959
|
+
line: row.ref_line
|
|
10960
|
+
};
|
|
10961
|
+
}
|
|
10962
|
+
function resolveSymbolIds(stmt, symbolName, file) {
|
|
10963
|
+
const baseSql = file ? `SELECT id FROM symbols WHERE name = ? AND file = ? ORDER BY id` : `SELECT id FROM symbols WHERE name = ? ORDER BY id`;
|
|
10964
|
+
const args = file ? [symbolName, file] : [symbolName];
|
|
10965
|
+
const rows = stmt(baseSql).all(...args);
|
|
10966
|
+
return rows.map((r) => r.id);
|
|
10967
|
+
}
|
|
10968
|
+
function findIncomingCallsByName(stmt, symbolName, file, limit) {
|
|
10969
|
+
const targetIds = resolveSymbolIds(stmt, symbolName, file);
|
|
10970
|
+
if (targetIds.length === 0) return { calls: [], symbolFound: false, ambiguous: false, totalMatches: 0 };
|
|
10971
|
+
let matchIds = targetIds;
|
|
10972
|
+
let ambiguous = false;
|
|
10973
|
+
if (file !== void 0) {
|
|
10974
|
+
const allNamedIds = resolveSymbolIds(stmt, symbolName, void 0);
|
|
10975
|
+
if (allNamedIds.length > targetIds.length) {
|
|
10976
|
+
matchIds = allNamedIds;
|
|
10977
|
+
ambiguous = true;
|
|
10978
|
+
}
|
|
10979
|
+
}
|
|
10980
|
+
const useFallback = !file;
|
|
10981
|
+
const rows = chunkedIdQuery(
|
|
10982
|
+
stmt,
|
|
10983
|
+
matchIds,
|
|
10984
|
+
(ph) => `SELECT
|
|
10985
|
+
s.id AS sym_id,
|
|
10986
|
+
s.name AS sym_name,
|
|
10987
|
+
s.kind AS sym_kind,
|
|
10988
|
+
s.lang AS sym_lang,
|
|
10989
|
+
s.file AS sym_file,
|
|
10990
|
+
s.line AS sym_line,
|
|
10991
|
+
s.signature AS sym_signature,
|
|
10992
|
+
r.call_type,
|
|
10993
|
+
r.line AS ref_line
|
|
10994
|
+
FROM refs r
|
|
10995
|
+
JOIN symbols s ON s.id = r.from_id
|
|
10996
|
+
WHERE r.to_id IN (${ph})
|
|
10997
|
+
ORDER BY r.line, r.id`,
|
|
10998
|
+
[]
|
|
10999
|
+
);
|
|
11000
|
+
if (useFallback) {
|
|
11001
|
+
const fallbackRows = stmt(
|
|
11002
|
+
`SELECT
|
|
11003
|
+
s.id AS sym_id,
|
|
11004
|
+
s.name AS sym_name,
|
|
11005
|
+
s.kind AS sym_kind,
|
|
11006
|
+
s.lang AS sym_lang,
|
|
11007
|
+
s.file AS sym_file,
|
|
11008
|
+
s.line AS sym_line,
|
|
11009
|
+
s.signature AS sym_signature,
|
|
11010
|
+
r.call_type,
|
|
11011
|
+
r.line AS ref_line
|
|
11012
|
+
FROM refs r
|
|
11013
|
+
JOIN symbols s ON s.id = r.from_id
|
|
11014
|
+
WHERE r.to_id IS NULL AND r.to_name = ?
|
|
11015
|
+
ORDER BY r.line, r.id`
|
|
11016
|
+
).all(symbolName);
|
|
11017
|
+
rows.push(...fallbackRows);
|
|
11018
|
+
}
|
|
11019
|
+
rows.sort((a, b) => a.ref_line - b.ref_line || a.sym_id - b.sym_id);
|
|
11020
|
+
const allCalls = rows.map(mapCallSiteRow);
|
|
11021
|
+
return { calls: allCalls.slice(0, limit), symbolFound: true, ambiguous, totalMatches: allCalls.length };
|
|
11022
|
+
}
|
|
11023
|
+
function findOutgoingCallsByName(stmt, symbolName, file, limit) {
|
|
11024
|
+
const sourceIds = resolveSymbolIds(stmt, symbolName, file);
|
|
11025
|
+
if (sourceIds.length === 0) return { calls: [], symbolFound: false, unresolvedCount: 0, totalMatches: 0 };
|
|
11026
|
+
const unresolvedCount = chunkedIdScalar(
|
|
11027
|
+
stmt,
|
|
11028
|
+
sourceIds,
|
|
11029
|
+
(ph) => `SELECT COUNT(*) AS n FROM refs WHERE from_id IN (${ph}) AND to_id IS NULL`
|
|
11030
|
+
);
|
|
11031
|
+
const rows = chunkedIdQuery(
|
|
11032
|
+
stmt,
|
|
11033
|
+
sourceIds,
|
|
11034
|
+
(ph) => `SELECT
|
|
11035
|
+
s.id AS sym_id,
|
|
11036
|
+
s.name AS sym_name,
|
|
11037
|
+
s.kind AS sym_kind,
|
|
11038
|
+
s.lang AS sym_lang,
|
|
11039
|
+
s.file AS sym_file,
|
|
11040
|
+
s.line AS sym_line,
|
|
11041
|
+
s.signature AS sym_signature,
|
|
11042
|
+
r.call_type,
|
|
11043
|
+
r.line AS ref_line
|
|
11044
|
+
FROM refs r
|
|
11045
|
+
JOIN symbols s ON s.id = r.to_id
|
|
11046
|
+
WHERE r.from_id IN (${ph})
|
|
11047
|
+
AND r.to_id IS NOT NULL -- INNER JOIN already excludes NULL to_id; this is defensive belt-and-suspenders
|
|
11048
|
+
ORDER BY r.line, r.id`,
|
|
11049
|
+
[]
|
|
11050
|
+
);
|
|
11051
|
+
rows.sort((a, b) => a.ref_line - b.ref_line || a.sym_id - b.sym_id);
|
|
11052
|
+
const calls = rows.map(mapCallSiteRow).slice(0, limit);
|
|
11053
|
+
return { calls, symbolFound: true, unresolvedCount, totalMatches: rows.length };
|
|
11054
|
+
}
|
|
10911
11055
|
function findRefsToWithStatement(stmt, symbolId) {
|
|
10912
11056
|
return stmt(
|
|
10913
11057
|
"SELECT id, from_id, to_name, to_id, call_type, line FROM refs WHERE to_id = ? OR to_name = (SELECT name FROM symbols WHERE id = ?)"
|
|
@@ -12143,6 +12287,20 @@ var IndexStore = class _IndexStore {
|
|
|
12143
12287
|
return false;
|
|
12144
12288
|
}
|
|
12145
12289
|
}
|
|
12290
|
+
/**
|
|
12291
|
+
* Find all symbols that reference the named target symbol (incoming callers).
|
|
12292
|
+
* Accepts a name instead of an id so the agent doesn't need a prior lookup.
|
|
12293
|
+
*/
|
|
12294
|
+
findIncomingCallsByName(symbolName, file, limit = 100) {
|
|
12295
|
+
return findIncomingCallsByName((sql) => this.stmt(sql), symbolName, file, limit);
|
|
12296
|
+
}
|
|
12297
|
+
/**
|
|
12298
|
+
* Find all symbols that the named source symbol references (outgoing callees).
|
|
12299
|
+
* Accepts a name instead of an id so the agent doesn't need a prior lookup.
|
|
12300
|
+
*/
|
|
12301
|
+
findOutgoingCallsByName(symbolName, file, limit = 100) {
|
|
12302
|
+
return findOutgoingCallsByName((sql) => this.stmt(sql), symbolName, file, limit);
|
|
12303
|
+
}
|
|
12146
12304
|
/**
|
|
12147
12305
|
* Find all references TO a given symbol (who calls / uses this symbol?).
|
|
12148
12306
|
*/
|
|
@@ -13559,6 +13717,22 @@ function symbolGraphService(args) {
|
|
|
13559
13717
|
indexStorePool.release(store);
|
|
13560
13718
|
}
|
|
13561
13719
|
}
|
|
13720
|
+
function incomingCallsService(args) {
|
|
13721
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13722
|
+
try {
|
|
13723
|
+
return store.findIncomingCallsByName(args.symbol, args.file, args.limit ?? 100);
|
|
13724
|
+
} finally {
|
|
13725
|
+
indexStorePool.release(store);
|
|
13726
|
+
}
|
|
13727
|
+
}
|
|
13728
|
+
function outgoingCallsService(args) {
|
|
13729
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13730
|
+
try {
|
|
13731
|
+
return store.findOutgoingCallsByName(args.symbol, args.file, args.limit ?? 100);
|
|
13732
|
+
} finally {
|
|
13733
|
+
indexStorePool.release(store);
|
|
13734
|
+
}
|
|
13735
|
+
}
|
|
13562
13736
|
|
|
13563
13737
|
// src/codebase-index/background-indexer.ts
|
|
13564
13738
|
init_languages2();
|
|
@@ -13796,6 +13970,10 @@ async function callInline(op, args, opts) {
|
|
|
13796
13970
|
return fileGraphService(args);
|
|
13797
13971
|
case "symbolGraph":
|
|
13798
13972
|
return symbolGraphService(args);
|
|
13973
|
+
case "incomingCalls":
|
|
13974
|
+
return incomingCallsService(args);
|
|
13975
|
+
case "outgoingCalls":
|
|
13976
|
+
return outgoingCallsService(args);
|
|
13799
13977
|
default:
|
|
13800
13978
|
throw new Error(`unknown index op: ${String(op)}`);
|
|
13801
13979
|
}
|
|
@@ -13989,6 +14167,12 @@ async function fileGraphService2(args) {
|
|
|
13989
14167
|
async function symbolGraphService2(args) {
|
|
13990
14168
|
return callIndexOp("symbolGraph", args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });
|
|
13991
14169
|
}
|
|
14170
|
+
async function incomingCallsService2(args) {
|
|
14171
|
+
return callIndexOp("incomingCalls", args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });
|
|
14172
|
+
}
|
|
14173
|
+
async function outgoingCallsService2(args) {
|
|
14174
|
+
return callIndexOp("outgoingCalls", args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });
|
|
14175
|
+
}
|
|
13992
14176
|
function shutdownCodebaseIndexServer(projectRoot, indexDir, reason) {
|
|
13993
14177
|
return shutdownProjectIndexServer(projectRoot, indexDir, reason);
|
|
13994
14178
|
}
|
|
@@ -14072,6 +14256,214 @@ var codebaseIndexTool = {
|
|
|
14072
14256
|
}
|
|
14073
14257
|
};
|
|
14074
14258
|
|
|
14259
|
+
// src/codebase-index/codebase-incoming-calls-tool.ts
|
|
14260
|
+
var codebaseIncomingCallsTool = {
|
|
14261
|
+
name: "codebase-incoming-calls",
|
|
14262
|
+
category: "Project",
|
|
14263
|
+
icon: "index",
|
|
14264
|
+
description: "Find all callers of a function, method, or symbol \u2014 who invokes or references it. Uses the codebase index ref graph for instant, exact results. Always use this instead of grep when checking impact of a change.",
|
|
14265
|
+
usageHint: 'CALL THIS BEFORE REFACTORING OR CHANGING ANY FUNCTION:\n\n- NEVER use grep or manual line reading to check where a function is called.\n- ALWAYS call codebase-incoming-calls({ symbol: "funcName" }) first.\n- Returns exact files, line numbers, caller signatures, and call types in milliseconds.\n- Use `file` to disambiguate when multiple symbols share a name.\n- Combine with codebase-outgoing-calls to see what the symbol itself calls.\nIf the index is not built, run codebase-index first.',
|
|
14266
|
+
permission: "auto",
|
|
14267
|
+
mutating: false,
|
|
14268
|
+
capabilities: ["fs.read"],
|
|
14269
|
+
timeoutMs: 35e3,
|
|
14270
|
+
inputSchema: {
|
|
14271
|
+
type: "object",
|
|
14272
|
+
properties: {
|
|
14273
|
+
symbol: {
|
|
14274
|
+
type: "string",
|
|
14275
|
+
description: "The function/method/type name to find callers for"
|
|
14276
|
+
},
|
|
14277
|
+
file: {
|
|
14278
|
+
type: "string",
|
|
14279
|
+
description: "Scope to a specific file when multiple symbols share the same name"
|
|
14280
|
+
},
|
|
14281
|
+
limit: {
|
|
14282
|
+
type: "integer",
|
|
14283
|
+
description: "Maximum call sites to return (default 50, max 200)",
|
|
14284
|
+
minimum: 1,
|
|
14285
|
+
maximum: 200
|
|
14286
|
+
}
|
|
14287
|
+
},
|
|
14288
|
+
required: ["symbol"]
|
|
14289
|
+
},
|
|
14290
|
+
async execute(input, ctx) {
|
|
14291
|
+
const state = getIndexState();
|
|
14292
|
+
if (state.indexing && !state.ready) {
|
|
14293
|
+
return {
|
|
14294
|
+
symbol: input.symbol,
|
|
14295
|
+
calls: [],
|
|
14296
|
+
total: 0,
|
|
14297
|
+
indexStatus: `Indexing in progress (${state.currentFile}/${state.totalFiles} files) \u2014 retry in a moment.`
|
|
14298
|
+
};
|
|
14299
|
+
}
|
|
14300
|
+
if (state.lastError) {
|
|
14301
|
+
const circuit = state.circuit;
|
|
14302
|
+
const retryHint = circuit.state === "open" ? `Indexing is paused (circuit open, retry in ${Math.ceil(circuit.cooldownRemainingMs / 1e3)}s).` : "Try /codebase-reindex.";
|
|
14303
|
+
return {
|
|
14304
|
+
symbol: input.symbol,
|
|
14305
|
+
calls: [],
|
|
14306
|
+
total: 0,
|
|
14307
|
+
indexStatus: `Index build failed: ${state.lastError}. ${retryHint}`
|
|
14308
|
+
};
|
|
14309
|
+
}
|
|
14310
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 50), 200));
|
|
14311
|
+
const { calls, symbolFound, ambiguous, totalMatches } = await incomingCallsService2(
|
|
14312
|
+
{
|
|
14313
|
+
projectRoot: ctx.projectRoot,
|
|
14314
|
+
indexDir: codebaseIndexDirOverride(ctx),
|
|
14315
|
+
symbol: input.symbol,
|
|
14316
|
+
file: input.file,
|
|
14317
|
+
limit
|
|
14318
|
+
}
|
|
14319
|
+
);
|
|
14320
|
+
if (!symbolFound) {
|
|
14321
|
+
let hasPersistedIndex = state.ready;
|
|
14322
|
+
if (!hasPersistedIndex) {
|
|
14323
|
+
try {
|
|
14324
|
+
const stats = await codebaseIndexStats({
|
|
14325
|
+
projectRoot: ctx.projectRoot,
|
|
14326
|
+
indexDir: codebaseIndexDirOverride(ctx)
|
|
14327
|
+
});
|
|
14328
|
+
hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
|
|
14329
|
+
} catch {
|
|
14330
|
+
}
|
|
14331
|
+
}
|
|
14332
|
+
if (!hasPersistedIndex) {
|
|
14333
|
+
return {
|
|
14334
|
+
symbol: input.symbol,
|
|
14335
|
+
calls: [],
|
|
14336
|
+
total: 0,
|
|
14337
|
+
indexStatus: "No persisted index data found. Run codebase-index to build it."
|
|
14338
|
+
};
|
|
14339
|
+
}
|
|
14340
|
+
return {
|
|
14341
|
+
symbol: input.symbol,
|
|
14342
|
+
calls: [],
|
|
14343
|
+
total: 0,
|
|
14344
|
+
note: `Symbol "${input.symbol}" not found in the index. Use codebase-search to verify the name.`
|
|
14345
|
+
};
|
|
14346
|
+
}
|
|
14347
|
+
const notes = [];
|
|
14348
|
+
if (totalMatches > limit) {
|
|
14349
|
+
notes.push(`Results capped at ${limit} of ${totalMatches} call sites. Increase \`limit\` or use \`file\` to narrow.`);
|
|
14350
|
+
}
|
|
14351
|
+
if (ambiguous) {
|
|
14352
|
+
notes.push(`Symbol "${input.symbol}" exists in multiple files. Results include callers of all same-named symbols. Use codebase-search to find the exact file and pass it as \`file\`.`);
|
|
14353
|
+
}
|
|
14354
|
+
return {
|
|
14355
|
+
symbol: input.symbol,
|
|
14356
|
+
calls,
|
|
14357
|
+
total: calls.length,
|
|
14358
|
+
...notes.length > 0 ? { note: notes.join(" ") } : {}
|
|
14359
|
+
};
|
|
14360
|
+
}
|
|
14361
|
+
};
|
|
14362
|
+
|
|
14363
|
+
// src/codebase-index/codebase-outgoing-calls-tool.ts
|
|
14364
|
+
var codebaseOutgoingCallsTool = {
|
|
14365
|
+
name: "codebase-outgoing-calls",
|
|
14366
|
+
category: "Project",
|
|
14367
|
+
icon: "index",
|
|
14368
|
+
description: "Find all functions/methods/symbols that a given symbol calls or depends on \u2014 its callees. Uses the codebase index ref graph for instant, exact results. Use this to understand a function's dependencies before modifying it.",
|
|
14369
|
+
usageHint: 'USE THIS TO UNDERSTAND A FUNCTION\'S DEPENDENCIES:\n\n- Call codebase-outgoing-calls({ symbol: "funcName" }) to see everything it calls.\n- Returns exact files, line numbers, callee signatures, and call types in milliseconds.\n- Use `file` to disambiguate when multiple symbols share a name.\n- Pair with codebase-incoming-calls for a complete impact picture: incoming = who calls you, outgoing = what you call.\nIf the index is not built, run codebase-index first.',
|
|
14370
|
+
permission: "auto",
|
|
14371
|
+
mutating: false,
|
|
14372
|
+
capabilities: ["fs.read"],
|
|
14373
|
+
timeoutMs: 35e3,
|
|
14374
|
+
inputSchema: {
|
|
14375
|
+
type: "object",
|
|
14376
|
+
properties: {
|
|
14377
|
+
symbol: {
|
|
14378
|
+
type: "string",
|
|
14379
|
+
description: "The function/method/type name to find callees for"
|
|
14380
|
+
},
|
|
14381
|
+
file: {
|
|
14382
|
+
type: "string",
|
|
14383
|
+
description: "Scope to a specific file when multiple symbols share the same name"
|
|
14384
|
+
},
|
|
14385
|
+
limit: {
|
|
14386
|
+
type: "integer",
|
|
14387
|
+
description: "Maximum call sites to return (default 50, max 200)",
|
|
14388
|
+
minimum: 1,
|
|
14389
|
+
maximum: 200
|
|
14390
|
+
}
|
|
14391
|
+
},
|
|
14392
|
+
required: ["symbol"]
|
|
14393
|
+
},
|
|
14394
|
+
async execute(input, ctx) {
|
|
14395
|
+
const state = getIndexState();
|
|
14396
|
+
if (state.indexing && !state.ready) {
|
|
14397
|
+
return {
|
|
14398
|
+
symbol: input.symbol,
|
|
14399
|
+
calls: [],
|
|
14400
|
+
total: 0,
|
|
14401
|
+
indexStatus: `Indexing in progress (${state.currentFile}/${state.totalFiles} files) \u2014 retry in a moment.`
|
|
14402
|
+
};
|
|
14403
|
+
}
|
|
14404
|
+
if (state.lastError) {
|
|
14405
|
+
const circuit = state.circuit;
|
|
14406
|
+
const retryHint = circuit.state === "open" ? `Indexing is paused (circuit open, retry in ${Math.ceil(circuit.cooldownRemainingMs / 1e3)}s).` : "Try /codebase-reindex.";
|
|
14407
|
+
return {
|
|
14408
|
+
symbol: input.symbol,
|
|
14409
|
+
calls: [],
|
|
14410
|
+
total: 0,
|
|
14411
|
+
indexStatus: `Index build failed: ${state.lastError}. ${retryHint}`
|
|
14412
|
+
};
|
|
14413
|
+
}
|
|
14414
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 50), 200));
|
|
14415
|
+
const { calls, symbolFound, unresolvedCount, totalMatches } = await outgoingCallsService2(
|
|
14416
|
+
{
|
|
14417
|
+
projectRoot: ctx.projectRoot,
|
|
14418
|
+
indexDir: codebaseIndexDirOverride(ctx),
|
|
14419
|
+
symbol: input.symbol,
|
|
14420
|
+
file: input.file,
|
|
14421
|
+
limit
|
|
14422
|
+
}
|
|
14423
|
+
);
|
|
14424
|
+
if (!symbolFound) {
|
|
14425
|
+
let hasPersistedIndex = state.ready;
|
|
14426
|
+
if (!hasPersistedIndex) {
|
|
14427
|
+
try {
|
|
14428
|
+
const stats = await codebaseIndexStats({
|
|
14429
|
+
projectRoot: ctx.projectRoot,
|
|
14430
|
+
indexDir: codebaseIndexDirOverride(ctx)
|
|
14431
|
+
});
|
|
14432
|
+
hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
|
|
14433
|
+
} catch {
|
|
14434
|
+
}
|
|
14435
|
+
}
|
|
14436
|
+
if (!hasPersistedIndex) {
|
|
14437
|
+
return {
|
|
14438
|
+
symbol: input.symbol,
|
|
14439
|
+
calls: [],
|
|
14440
|
+
total: 0,
|
|
14441
|
+
indexStatus: "No persisted index data found. Run codebase-index to build it."
|
|
14442
|
+
};
|
|
14443
|
+
}
|
|
14444
|
+
return {
|
|
14445
|
+
symbol: input.symbol,
|
|
14446
|
+
calls: [],
|
|
14447
|
+
total: 0,
|
|
14448
|
+
note: `Symbol "${input.symbol}" not found in the index. Use codebase-search to verify the name.`
|
|
14449
|
+
};
|
|
14450
|
+
}
|
|
14451
|
+
const notes = [];
|
|
14452
|
+
if (totalMatches > limit) {
|
|
14453
|
+
notes.push(`Results capped at ${limit} of ${totalMatches} call sites. Increase \`limit\` or use \`file\` to narrow.`);
|
|
14454
|
+
}
|
|
14455
|
+
if (unresolvedCount > 0) {
|
|
14456
|
+
notes.push(`${unresolvedCount} unresolved reference(s) not shown \u2014 their targets could not be resolved during indexing.`);
|
|
14457
|
+
}
|
|
14458
|
+
return {
|
|
14459
|
+
symbol: input.symbol,
|
|
14460
|
+
calls,
|
|
14461
|
+
total: calls.length,
|
|
14462
|
+
...notes.length > 0 ? { note: notes.join(" ") } : {}
|
|
14463
|
+
};
|
|
14464
|
+
}
|
|
14465
|
+
};
|
|
14466
|
+
|
|
14075
14467
|
// src/codebase-index/codebase-search-tool.ts
|
|
14076
14468
|
var codebaseSearchTool = {
|
|
14077
14469
|
name: "codebase-search",
|
|
@@ -25561,6 +25953,8 @@ var TIER1_TOOLS = [
|
|
|
25561
25953
|
editTool,
|
|
25562
25954
|
codebaseStatsTool,
|
|
25563
25955
|
codebaseSearchTool,
|
|
25956
|
+
codebaseIncomingCallsTool,
|
|
25957
|
+
codebaseOutgoingCallsTool,
|
|
25564
25958
|
codebaseIndexTool,
|
|
25565
25959
|
bashTool,
|
|
25566
25960
|
grepTool,
|
|
@@ -25611,6 +26005,8 @@ var builtinTools = [
|
|
|
25611
26005
|
editTool,
|
|
25612
26006
|
codebaseStatsTool,
|
|
25613
26007
|
codebaseSearchTool,
|
|
26008
|
+
codebaseIncomingCallsTool,
|
|
26009
|
+
codebaseOutgoingCallsTool,
|
|
25614
26010
|
codebaseIndexTool,
|
|
25615
26011
|
deadCodeScanTool,
|
|
25616
26012
|
replaceTool,
|