@wrongstack/tools 0.307.0 → 0.307.1
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/builtin.js +564 -396
- package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +2 -0
- package/dist/codebase-index/index.js +134 -49
- package/dist/codebase-index/project-server.js +87 -43
- package/dist/codebase-index/worker.js +87 -43
- package/dist/codebase-index/writer-graph-helpers.d.ts +1 -1
- package/dist/codebase-index/writer-helpers.d.ts +12 -0
- package/dist/edit.js +87 -43
- package/dist/index.d.ts +1 -1
- package/dist/index.js +583 -412
- package/dist/pack.js +563 -396
- package/dist/patch.js +87 -43
- package/dist/read.js +91 -47
- package/dist/replace.js +87 -43
- package/dist/tool-tier.js +564 -396
- package/dist/write.js +87 -43
- package/package.json +4 -4
|
@@ -34,6 +34,8 @@ export interface ImpactAnalysisOutput {
|
|
|
34
34
|
affectedTestFiles: string[];
|
|
35
35
|
callSites: ImpactCallSite[];
|
|
36
36
|
recommendedActionPlan: string[];
|
|
37
|
+
/** False when the symbol could not be resolved in the index. */
|
|
38
|
+
symbolFound?: boolean;
|
|
37
39
|
error?: string | undefined;
|
|
38
40
|
}
|
|
39
41
|
export declare const codebaseImpactAnalysisTool: Tool<ImpactAnalysisInput, ImpactAnalysisOutput>;
|
|
@@ -3592,10 +3592,16 @@ function buildFileGraphNodeState(pkgSyms, localFiles, packageOf) {
|
|
|
3592
3592
|
}
|
|
3593
3593
|
return { fileNodes, symToFile, fileStats, ensureFileNode };
|
|
3594
3594
|
}
|
|
3595
|
-
function buildSymbolGraphNodes(symById, relatedIds,
|
|
3595
|
+
function buildSymbolGraphNodes(symById, relatedIds, localFiles, packageOf) {
|
|
3596
|
+
const local = new Set(
|
|
3597
|
+
[...typeof localFiles === "string" ? [localFiles] : localFiles].map(
|
|
3598
|
+
(file) => file.replace(/\\/g, "/")
|
|
3599
|
+
)
|
|
3600
|
+
);
|
|
3601
|
+
const isLocal = (file) => local.has(file.replace(/\\/g, "/"));
|
|
3596
3602
|
return [...relatedIds].map((id) => symById.get(id)).filter((symbol) => symbol !== void 0).sort((a, b) => {
|
|
3597
|
-
const aExternal = a.file
|
|
3598
|
-
const bExternal = b.file
|
|
3603
|
+
const aExternal = isLocal(a.file) ? 0 : 1;
|
|
3604
|
+
const bExternal = isLocal(b.file) ? 0 : 1;
|
|
3599
3605
|
return aExternal - bExternal || a.file.localeCompare(b.file) || a.line - b.line || a.id - b.id;
|
|
3600
3606
|
}).map((s) => ({
|
|
3601
3607
|
id: `sym:${s.id}`,
|
|
@@ -3609,7 +3615,7 @@ function buildSymbolGraphNodes(symById, relatedIds, fileFilter, packageOf) {
|
|
|
3609
3615
|
line: s.line,
|
|
3610
3616
|
signature: s.signature,
|
|
3611
3617
|
scope: s.scope,
|
|
3612
|
-
external: s.file
|
|
3618
|
+
external: !isLocal(s.file)
|
|
3613
3619
|
}));
|
|
3614
3620
|
}
|
|
3615
3621
|
function addWeightedEdge(edgeMap, source, target, callType, weight) {
|
|
@@ -3644,6 +3650,56 @@ function materializeWeightedEdges(edgeMap, idPrefix) {
|
|
|
3644
3650
|
return edges;
|
|
3645
3651
|
}
|
|
3646
3652
|
|
|
3653
|
+
// src/codebase-index/writer-helpers.ts
|
|
3654
|
+
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
3655
|
+
function escapeLike(value) {
|
|
3656
|
+
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
3657
|
+
}
|
|
3658
|
+
function posixIndexPath(file) {
|
|
3659
|
+
return file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
3660
|
+
}
|
|
3661
|
+
function indexedFileMatchSql(column = "file") {
|
|
3662
|
+
return `(${column} = ? OR replace(${column}, '\\', '/') = ? OR replace(${column}, '\\', '/') LIKE ? ESCAPE '\\')`;
|
|
3663
|
+
}
|
|
3664
|
+
function indexedFileMatchArgs(file) {
|
|
3665
|
+
const posix4 = posixIndexPath(file.trim());
|
|
3666
|
+
return [file, posix4, `%/${escapeLike(posix4)}`];
|
|
3667
|
+
}
|
|
3668
|
+
function matchesIndexedPackageFilter(storedFile, packageLabel, filter) {
|
|
3669
|
+
if (packageLabel === filter) return true;
|
|
3670
|
+
const posixFile = posixIndexPath(storedFile);
|
|
3671
|
+
const posixFilter = posixIndexPath(filter.trim());
|
|
3672
|
+
if (!posixFilter) return false;
|
|
3673
|
+
return posixFile === posixFilter || posixFile.endsWith(`/${posixFilter}`) || posixFile.includes(`/${posixFilter}/`);
|
|
3674
|
+
}
|
|
3675
|
+
function assignRefsToSymbols(refs, symbols) {
|
|
3676
|
+
if (refs.length === 0 || symbols.length === 0) return [];
|
|
3677
|
+
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
3678
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3679
|
+
const assigned = [];
|
|
3680
|
+
for (const ref of refs) {
|
|
3681
|
+
let owner;
|
|
3682
|
+
for (const symbol of ordered) {
|
|
3683
|
+
if (symbol.line > ref.line) break;
|
|
3684
|
+
owner = symbol;
|
|
3685
|
+
}
|
|
3686
|
+
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
3687
|
+
if (!owner || owner.id <= 0) continue;
|
|
3688
|
+
const key = `${owner.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
3689
|
+
if (seen.has(key)) continue;
|
|
3690
|
+
seen.add(key);
|
|
3691
|
+
assigned.push({ ...ref, fromId: owner.id });
|
|
3692
|
+
}
|
|
3693
|
+
return assigned;
|
|
3694
|
+
}
|
|
3695
|
+
function resolveIndexDir(projectRoot, override) {
|
|
3696
|
+
return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
|
|
3697
|
+
}
|
|
3698
|
+
function codebaseIndexDirOverride(ctx) {
|
|
3699
|
+
const v = ctx.meta?.["codebaseIndexDir"];
|
|
3700
|
+
return typeof v === "string" ? v : void 0;
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3647
3703
|
// src/codebase-index/writer-ref-mapper.ts
|
|
3648
3704
|
function mapWriterRefRow(row) {
|
|
3649
3705
|
return {
|
|
@@ -3699,10 +3755,23 @@ function mapCallSiteRow(row) {
|
|
|
3699
3755
|
line: row.ref_line
|
|
3700
3756
|
};
|
|
3701
3757
|
}
|
|
3758
|
+
function resolveIndexedFiles(stmt, file) {
|
|
3759
|
+
const rows = stmt(
|
|
3760
|
+
`SELECT DISTINCT file FROM symbols WHERE ${indexedFileMatchSql("file")} ORDER BY length(file), file`
|
|
3761
|
+
).all(...indexedFileMatchArgs(file));
|
|
3762
|
+
return rows.map((row) => row.file);
|
|
3763
|
+
}
|
|
3702
3764
|
function resolveSymbolIds(stmt, symbolName, file) {
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3765
|
+
if (!file) {
|
|
3766
|
+
const rows2 = stmt("SELECT id FROM symbols WHERE name = ? ORDER BY id").all(symbolName);
|
|
3767
|
+
return rows2.map((r) => r.id);
|
|
3768
|
+
}
|
|
3769
|
+
const indexedFiles = resolveIndexedFiles(stmt, file);
|
|
3770
|
+
if (indexedFiles.length === 0) return [];
|
|
3771
|
+
const placeholders = indexedFiles.map(() => "?").join(",");
|
|
3772
|
+
const rows = stmt(
|
|
3773
|
+
`SELECT id FROM symbols WHERE name = ? AND file IN (${placeholders}) ORDER BY id`
|
|
3774
|
+
).all(symbolName, ...indexedFiles);
|
|
3706
3775
|
return rows.map((r) => r.id);
|
|
3707
3776
|
}
|
|
3708
3777
|
function findIncomingCallsByName(stmt, symbolName, file, limit) {
|
|
@@ -4024,7 +4093,7 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
4024
4093
|
const allFiles = stmt("SELECT DISTINCT file FROM symbols").all();
|
|
4025
4094
|
const packageOf = readPackageLabeller(stmt);
|
|
4026
4095
|
const langOf = (file) => detectLang(file) ?? "other";
|
|
4027
|
-
const pkgFilePaths = allFiles.filter((f) => packageOf(f.file)
|
|
4096
|
+
const pkgFilePaths = allFiles.filter((f) => matchesIndexedPackageFilter(f.file, packageOf(f.file), packageFilter)).map((f) => f.file);
|
|
4028
4097
|
const localFiles = new Set(pkgFilePaths);
|
|
4029
4098
|
if (localFiles.size === 0) return { nodes: [], edges: [] };
|
|
4030
4099
|
const filePlaceholders = [...localFiles].map(() => "?").join(",");
|
|
@@ -4100,9 +4169,12 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
4100
4169
|
return { nodes: [...fileNodes.values()], edges };
|
|
4101
4170
|
}
|
|
4102
4171
|
function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
4172
|
+
const indexedFiles = resolveIndexedFiles(stmt, fileFilter);
|
|
4173
|
+
if (indexedFiles.length === 0) return { nodes: [], edges: [] };
|
|
4174
|
+
const filePlaceholders = indexedFiles.map(() => "?").join(",");
|
|
4103
4175
|
const syms = stmt(
|
|
4104
|
-
|
|
4105
|
-
).all(
|
|
4176
|
+
`SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY line, id`
|
|
4177
|
+
).all(...indexedFiles);
|
|
4106
4178
|
if (syms.length === 0) return { nodes: [], edges: [] };
|
|
4107
4179
|
const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));
|
|
4108
4180
|
const relatedIds = new Set(syms.map((symbol) => symbol.id));
|
|
@@ -4112,16 +4184,16 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
4112
4184
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
4113
4185
|
FROM refs r
|
|
4114
4186
|
JOIN symbols s ON s.id = r.from_id
|
|
4115
|
-
WHERE s.file
|
|
4187
|
+
WHERE s.file IN (${filePlaceholders})
|
|
4116
4188
|
UNION
|
|
4117
4189
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
4118
4190
|
FROM refs r
|
|
4119
4191
|
JOIN symbols s ON s.id = r.to_id
|
|
4120
|
-
WHERE s.file
|
|
4192
|
+
WHERE s.file IN (${filePlaceholders})
|
|
4121
4193
|
)
|
|
4122
4194
|
WHERE to_id IS NOT NULL
|
|
4123
4195
|
GROUP BY from_id, to_id, call_type`
|
|
4124
|
-
).all(
|
|
4196
|
+
).all(...indexedFiles, ...indexedFiles);
|
|
4125
4197
|
const edgeMap = /* @__PURE__ */ new Map();
|
|
4126
4198
|
for (const r of refRows) {
|
|
4127
4199
|
if (r.to_id == null) continue;
|
|
@@ -4140,43 +4212,15 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
4140
4212
|
).all(...missingIds);
|
|
4141
4213
|
for (const s of extras) symById.set(s.id, s);
|
|
4142
4214
|
}
|
|
4143
|
-
const nodes = buildSymbolGraphNodes(
|
|
4215
|
+
const nodes = buildSymbolGraphNodes(
|
|
4216
|
+
symById,
|
|
4217
|
+
relatedIds,
|
|
4218
|
+
new Set(syms.map((symbol) => symbol.file)),
|
|
4219
|
+
readPackageLabeller(stmt)
|
|
4220
|
+
);
|
|
4144
4221
|
return { nodes, edges };
|
|
4145
4222
|
}
|
|
4146
4223
|
|
|
4147
|
-
// src/codebase-index/writer-helpers.ts
|
|
4148
|
-
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
4149
|
-
function escapeLike(value) {
|
|
4150
|
-
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
4151
|
-
}
|
|
4152
|
-
function assignRefsToSymbols(refs, symbols) {
|
|
4153
|
-
if (refs.length === 0 || symbols.length === 0) return [];
|
|
4154
|
-
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
4155
|
-
const seen = /* @__PURE__ */ new Set();
|
|
4156
|
-
const assigned = [];
|
|
4157
|
-
for (const ref of refs) {
|
|
4158
|
-
let owner;
|
|
4159
|
-
for (const symbol of ordered) {
|
|
4160
|
-
if (symbol.line > ref.line) break;
|
|
4161
|
-
owner = symbol;
|
|
4162
|
-
}
|
|
4163
|
-
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
4164
|
-
if (!owner || owner.id <= 0) continue;
|
|
4165
|
-
const key = `${owner.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
4166
|
-
if (seen.has(key)) continue;
|
|
4167
|
-
seen.add(key);
|
|
4168
|
-
assigned.push({ ...ref, fromId: owner.id });
|
|
4169
|
-
}
|
|
4170
|
-
return assigned;
|
|
4171
|
-
}
|
|
4172
|
-
function resolveIndexDir(projectRoot, override) {
|
|
4173
|
-
return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
|
|
4174
|
-
}
|
|
4175
|
-
function codebaseIndexDirOverride(ctx) {
|
|
4176
|
-
const v = ctx.meta?.["codebaseIndexDir"];
|
|
4177
|
-
return typeof v === "string" ? v : void 0;
|
|
4178
|
-
}
|
|
4179
|
-
|
|
4180
4224
|
// src/codebase-index/vector-search.ts
|
|
4181
4225
|
var RRF_K = 60;
|
|
4182
4226
|
var VECTOR_DIMENSIONS = 384;
|
|
@@ -9265,6 +9309,9 @@ var codebaseImpactAnalysisTool = {
|
|
|
9265
9309
|
const limit = 200;
|
|
9266
9310
|
const transitive = input.transitive ?? true;
|
|
9267
9311
|
let rawSites = [];
|
|
9312
|
+
let symbolFound = true;
|
|
9313
|
+
let indexUnavailable = false;
|
|
9314
|
+
let indexError;
|
|
9268
9315
|
try {
|
|
9269
9316
|
const serviced = await incomingCallsService2({
|
|
9270
9317
|
projectRoot,
|
|
@@ -9275,7 +9322,43 @@ var codebaseImpactAnalysisTool = {
|
|
|
9275
9322
|
transitive
|
|
9276
9323
|
});
|
|
9277
9324
|
rawSites = serviced.calls;
|
|
9278
|
-
|
|
9325
|
+
symbolFound = serviced.symbolFound;
|
|
9326
|
+
} catch (err) {
|
|
9327
|
+
symbolFound = false;
|
|
9328
|
+
indexUnavailable = true;
|
|
9329
|
+
indexError = toErrorMessage4(err);
|
|
9330
|
+
}
|
|
9331
|
+
if (indexUnavailable) {
|
|
9332
|
+
const detail = indexError ? ` (${indexError})` : "";
|
|
9333
|
+
const reason = `Index query failed for '${input.symbol}'. Run codebase-index, then retry.${detail}`;
|
|
9334
|
+
return {
|
|
9335
|
+
status: "error",
|
|
9336
|
+
symbol: input.symbol,
|
|
9337
|
+
riskLevel: "low",
|
|
9338
|
+
summary: reason,
|
|
9339
|
+
totalCallSites: 0,
|
|
9340
|
+
affectedProductionFiles: [],
|
|
9341
|
+
affectedTestFiles: [],
|
|
9342
|
+
callSites: [],
|
|
9343
|
+
recommendedActionPlan: [reason],
|
|
9344
|
+
symbolFound: false,
|
|
9345
|
+
error: reason
|
|
9346
|
+
};
|
|
9347
|
+
}
|
|
9348
|
+
if (!symbolFound) {
|
|
9349
|
+
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.";
|
|
9350
|
+
return {
|
|
9351
|
+
status: "ok",
|
|
9352
|
+
symbol: input.symbol,
|
|
9353
|
+
riskLevel: "low",
|
|
9354
|
+
summary: reason,
|
|
9355
|
+
totalCallSites: 0,
|
|
9356
|
+
affectedProductionFiles: [],
|
|
9357
|
+
affectedTestFiles: [],
|
|
9358
|
+
callSites: [],
|
|
9359
|
+
recommendedActionPlan: [reason],
|
|
9360
|
+
symbolFound: false
|
|
9361
|
+
};
|
|
9279
9362
|
}
|
|
9280
9363
|
const prodFilesSet = /* @__PURE__ */ new Set();
|
|
9281
9364
|
const testFilesSet = /* @__PURE__ */ new Set();
|
|
@@ -9331,7 +9414,8 @@ var codebaseImpactAnalysisTool = {
|
|
|
9331
9414
|
affectedProductionFiles: prodFiles,
|
|
9332
9415
|
affectedTestFiles: testFiles,
|
|
9333
9416
|
callSites,
|
|
9334
|
-
recommendedActionPlan
|
|
9417
|
+
recommendedActionPlan,
|
|
9418
|
+
symbolFound: true
|
|
9335
9419
|
};
|
|
9336
9420
|
} catch (err) {
|
|
9337
9421
|
return {
|
|
@@ -9344,6 +9428,7 @@ var codebaseImpactAnalysisTool = {
|
|
|
9344
9428
|
affectedTestFiles: [],
|
|
9345
9429
|
callSites: [],
|
|
9346
9430
|
recommendedActionPlan: [],
|
|
9431
|
+
symbolFound: false,
|
|
9347
9432
|
error: toErrorMessage4(err)
|
|
9348
9433
|
};
|
|
9349
9434
|
}
|
|
@@ -4362,10 +4362,16 @@ function buildFileGraphNodeState(pkgSyms, localFiles, packageOf) {
|
|
|
4362
4362
|
}
|
|
4363
4363
|
return { fileNodes, symToFile, fileStats, ensureFileNode };
|
|
4364
4364
|
}
|
|
4365
|
-
function buildSymbolGraphNodes(symById, relatedIds,
|
|
4365
|
+
function buildSymbolGraphNodes(symById, relatedIds, localFiles, packageOf) {
|
|
4366
|
+
const local = new Set(
|
|
4367
|
+
[...typeof localFiles === "string" ? [localFiles] : localFiles].map(
|
|
4368
|
+
(file) => file.replace(/\\/g, "/")
|
|
4369
|
+
)
|
|
4370
|
+
);
|
|
4371
|
+
const isLocal = (file) => local.has(file.replace(/\\/g, "/"));
|
|
4366
4372
|
return [...relatedIds].map((id) => symById.get(id)).filter((symbol) => symbol !== void 0).sort((a, b) => {
|
|
4367
|
-
const aExternal = a.file
|
|
4368
|
-
const bExternal = b.file
|
|
4373
|
+
const aExternal = isLocal(a.file) ? 0 : 1;
|
|
4374
|
+
const bExternal = isLocal(b.file) ? 0 : 1;
|
|
4369
4375
|
return aExternal - bExternal || a.file.localeCompare(b.file) || a.line - b.line || a.id - b.id;
|
|
4370
4376
|
}).map((s) => ({
|
|
4371
4377
|
id: `sym:${s.id}`,
|
|
@@ -4379,7 +4385,7 @@ function buildSymbolGraphNodes(symById, relatedIds, fileFilter, packageOf) {
|
|
|
4379
4385
|
line: s.line,
|
|
4380
4386
|
signature: s.signature,
|
|
4381
4387
|
scope: s.scope,
|
|
4382
|
-
external: s.file
|
|
4388
|
+
external: !isLocal(s.file)
|
|
4383
4389
|
}));
|
|
4384
4390
|
}
|
|
4385
4391
|
function addWeightedEdge(edgeMap, source, target, callType, weight) {
|
|
@@ -4414,6 +4420,52 @@ function materializeWeightedEdges(edgeMap, idPrefix) {
|
|
|
4414
4420
|
return edges;
|
|
4415
4421
|
}
|
|
4416
4422
|
|
|
4423
|
+
// src/codebase-index/writer-helpers.ts
|
|
4424
|
+
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
4425
|
+
function escapeLike(value) {
|
|
4426
|
+
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
4427
|
+
}
|
|
4428
|
+
function posixIndexPath(file) {
|
|
4429
|
+
return file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
4430
|
+
}
|
|
4431
|
+
function indexedFileMatchSql(column = "file") {
|
|
4432
|
+
return `(${column} = ? OR replace(${column}, '\\', '/') = ? OR replace(${column}, '\\', '/') LIKE ? ESCAPE '\\')`;
|
|
4433
|
+
}
|
|
4434
|
+
function indexedFileMatchArgs(file) {
|
|
4435
|
+
const posix4 = posixIndexPath(file.trim());
|
|
4436
|
+
return [file, posix4, `%/${escapeLike(posix4)}`];
|
|
4437
|
+
}
|
|
4438
|
+
function matchesIndexedPackageFilter(storedFile, packageLabel, filter) {
|
|
4439
|
+
if (packageLabel === filter) return true;
|
|
4440
|
+
const posixFile = posixIndexPath(storedFile);
|
|
4441
|
+
const posixFilter = posixIndexPath(filter.trim());
|
|
4442
|
+
if (!posixFilter) return false;
|
|
4443
|
+
return posixFile === posixFilter || posixFile.endsWith(`/${posixFilter}`) || posixFile.includes(`/${posixFilter}/`);
|
|
4444
|
+
}
|
|
4445
|
+
function assignRefsToSymbols(refs, symbols) {
|
|
4446
|
+
if (refs.length === 0 || symbols.length === 0) return [];
|
|
4447
|
+
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
4448
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4449
|
+
const assigned = [];
|
|
4450
|
+
for (const ref of refs) {
|
|
4451
|
+
let owner;
|
|
4452
|
+
for (const symbol of ordered) {
|
|
4453
|
+
if (symbol.line > ref.line) break;
|
|
4454
|
+
owner = symbol;
|
|
4455
|
+
}
|
|
4456
|
+
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
4457
|
+
if (!owner || owner.id <= 0) continue;
|
|
4458
|
+
const key = `${owner.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
4459
|
+
if (seen.has(key)) continue;
|
|
4460
|
+
seen.add(key);
|
|
4461
|
+
assigned.push({ ...ref, fromId: owner.id });
|
|
4462
|
+
}
|
|
4463
|
+
return assigned;
|
|
4464
|
+
}
|
|
4465
|
+
function resolveIndexDir(projectRoot2, override) {
|
|
4466
|
+
return override ?? resolveWstackPaths({ projectRoot: projectRoot2 }).projectCodebaseIndex;
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4417
4469
|
// src/codebase-index/writer-ref-mapper.ts
|
|
4418
4470
|
function mapWriterRefRow(row) {
|
|
4419
4471
|
return {
|
|
@@ -4469,10 +4521,23 @@ function mapCallSiteRow(row) {
|
|
|
4469
4521
|
line: row.ref_line
|
|
4470
4522
|
};
|
|
4471
4523
|
}
|
|
4524
|
+
function resolveIndexedFiles(stmt, file) {
|
|
4525
|
+
const rows = stmt(
|
|
4526
|
+
`SELECT DISTINCT file FROM symbols WHERE ${indexedFileMatchSql("file")} ORDER BY length(file), file`
|
|
4527
|
+
).all(...indexedFileMatchArgs(file));
|
|
4528
|
+
return rows.map((row) => row.file);
|
|
4529
|
+
}
|
|
4472
4530
|
function resolveSymbolIds(stmt, symbolName, file) {
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4531
|
+
if (!file) {
|
|
4532
|
+
const rows2 = stmt("SELECT id FROM symbols WHERE name = ? ORDER BY id").all(symbolName);
|
|
4533
|
+
return rows2.map((r) => r.id);
|
|
4534
|
+
}
|
|
4535
|
+
const indexedFiles = resolveIndexedFiles(stmt, file);
|
|
4536
|
+
if (indexedFiles.length === 0) return [];
|
|
4537
|
+
const placeholders = indexedFiles.map(() => "?").join(",");
|
|
4538
|
+
const rows = stmt(
|
|
4539
|
+
`SELECT id FROM symbols WHERE name = ? AND file IN (${placeholders}) ORDER BY id`
|
|
4540
|
+
).all(symbolName, ...indexedFiles);
|
|
4476
4541
|
return rows.map((r) => r.id);
|
|
4477
4542
|
}
|
|
4478
4543
|
function findIncomingCallsByName(stmt, symbolName, file, limit) {
|
|
@@ -4794,7 +4859,7 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
4794
4859
|
const allFiles = stmt("SELECT DISTINCT file FROM symbols").all();
|
|
4795
4860
|
const packageOf = readPackageLabeller(stmt);
|
|
4796
4861
|
const langOf = (file) => detectLang(file) ?? "other";
|
|
4797
|
-
const pkgFilePaths = allFiles.filter((f) => packageOf(f.file)
|
|
4862
|
+
const pkgFilePaths = allFiles.filter((f) => matchesIndexedPackageFilter(f.file, packageOf(f.file), packageFilter)).map((f) => f.file);
|
|
4798
4863
|
const localFiles = new Set(pkgFilePaths);
|
|
4799
4864
|
if (localFiles.size === 0) return { nodes: [], edges: [] };
|
|
4800
4865
|
const filePlaceholders = [...localFiles].map(() => "?").join(",");
|
|
@@ -4870,9 +4935,12 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
4870
4935
|
return { nodes: [...fileNodes.values()], edges };
|
|
4871
4936
|
}
|
|
4872
4937
|
function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
4938
|
+
const indexedFiles = resolveIndexedFiles(stmt, fileFilter);
|
|
4939
|
+
if (indexedFiles.length === 0) return { nodes: [], edges: [] };
|
|
4940
|
+
const filePlaceholders = indexedFiles.map(() => "?").join(",");
|
|
4873
4941
|
const syms = stmt(
|
|
4874
|
-
|
|
4875
|
-
).all(
|
|
4942
|
+
`SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY line, id`
|
|
4943
|
+
).all(...indexedFiles);
|
|
4876
4944
|
if (syms.length === 0) return { nodes: [], edges: [] };
|
|
4877
4945
|
const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));
|
|
4878
4946
|
const relatedIds = new Set(syms.map((symbol) => symbol.id));
|
|
@@ -4882,16 +4950,16 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
4882
4950
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
4883
4951
|
FROM refs r
|
|
4884
4952
|
JOIN symbols s ON s.id = r.from_id
|
|
4885
|
-
WHERE s.file
|
|
4953
|
+
WHERE s.file IN (${filePlaceholders})
|
|
4886
4954
|
UNION
|
|
4887
4955
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
4888
4956
|
FROM refs r
|
|
4889
4957
|
JOIN symbols s ON s.id = r.to_id
|
|
4890
|
-
WHERE s.file
|
|
4958
|
+
WHERE s.file IN (${filePlaceholders})
|
|
4891
4959
|
)
|
|
4892
4960
|
WHERE to_id IS NOT NULL
|
|
4893
4961
|
GROUP BY from_id, to_id, call_type`
|
|
4894
|
-
).all(
|
|
4962
|
+
).all(...indexedFiles, ...indexedFiles);
|
|
4895
4963
|
const edgeMap = /* @__PURE__ */ new Map();
|
|
4896
4964
|
for (const r of refRows) {
|
|
4897
4965
|
if (r.to_id == null) continue;
|
|
@@ -4910,39 +4978,15 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
4910
4978
|
).all(...missingIds);
|
|
4911
4979
|
for (const s of extras) symById.set(s.id, s);
|
|
4912
4980
|
}
|
|
4913
|
-
const nodes = buildSymbolGraphNodes(
|
|
4981
|
+
const nodes = buildSymbolGraphNodes(
|
|
4982
|
+
symById,
|
|
4983
|
+
relatedIds,
|
|
4984
|
+
new Set(syms.map((symbol) => symbol.file)),
|
|
4985
|
+
readPackageLabeller(stmt)
|
|
4986
|
+
);
|
|
4914
4987
|
return { nodes, edges };
|
|
4915
4988
|
}
|
|
4916
4989
|
|
|
4917
|
-
// src/codebase-index/writer-helpers.ts
|
|
4918
|
-
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
4919
|
-
function escapeLike(value) {
|
|
4920
|
-
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
4921
|
-
}
|
|
4922
|
-
function assignRefsToSymbols(refs, symbols) {
|
|
4923
|
-
if (refs.length === 0 || symbols.length === 0) return [];
|
|
4924
|
-
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
4925
|
-
const seen = /* @__PURE__ */ new Set();
|
|
4926
|
-
const assigned = [];
|
|
4927
|
-
for (const ref of refs) {
|
|
4928
|
-
let owner;
|
|
4929
|
-
for (const symbol of ordered) {
|
|
4930
|
-
if (symbol.line > ref.line) break;
|
|
4931
|
-
owner = symbol;
|
|
4932
|
-
}
|
|
4933
|
-
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
4934
|
-
if (!owner || owner.id <= 0) continue;
|
|
4935
|
-
const key = `${owner.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
4936
|
-
if (seen.has(key)) continue;
|
|
4937
|
-
seen.add(key);
|
|
4938
|
-
assigned.push({ ...ref, fromId: owner.id });
|
|
4939
|
-
}
|
|
4940
|
-
return assigned;
|
|
4941
|
-
}
|
|
4942
|
-
function resolveIndexDir(projectRoot2, override) {
|
|
4943
|
-
return override ?? resolveWstackPaths({ projectRoot: projectRoot2 }).projectCodebaseIndex;
|
|
4944
|
-
}
|
|
4945
|
-
|
|
4946
4990
|
// src/codebase-index/vector-search.ts
|
|
4947
4991
|
var RRF_K = 60;
|
|
4948
4992
|
var VECTOR_DIMENSIONS = 384;
|
|
@@ -4347,10 +4347,16 @@ function buildFileGraphNodeState(pkgSyms, localFiles, packageOf) {
|
|
|
4347
4347
|
}
|
|
4348
4348
|
return { fileNodes, symToFile, fileStats, ensureFileNode };
|
|
4349
4349
|
}
|
|
4350
|
-
function buildSymbolGraphNodes(symById, relatedIds,
|
|
4350
|
+
function buildSymbolGraphNodes(symById, relatedIds, localFiles, packageOf) {
|
|
4351
|
+
const local = new Set(
|
|
4352
|
+
[...typeof localFiles === "string" ? [localFiles] : localFiles].map(
|
|
4353
|
+
(file) => file.replace(/\\/g, "/")
|
|
4354
|
+
)
|
|
4355
|
+
);
|
|
4356
|
+
const isLocal = (file) => local.has(file.replace(/\\/g, "/"));
|
|
4351
4357
|
return [...relatedIds].map((id) => symById.get(id)).filter((symbol) => symbol !== void 0).sort((a, b) => {
|
|
4352
|
-
const aExternal = a.file
|
|
4353
|
-
const bExternal = b.file
|
|
4358
|
+
const aExternal = isLocal(a.file) ? 0 : 1;
|
|
4359
|
+
const bExternal = isLocal(b.file) ? 0 : 1;
|
|
4354
4360
|
return aExternal - bExternal || a.file.localeCompare(b.file) || a.line - b.line || a.id - b.id;
|
|
4355
4361
|
}).map((s) => ({
|
|
4356
4362
|
id: `sym:${s.id}`,
|
|
@@ -4364,7 +4370,7 @@ function buildSymbolGraphNodes(symById, relatedIds, fileFilter, packageOf) {
|
|
|
4364
4370
|
line: s.line,
|
|
4365
4371
|
signature: s.signature,
|
|
4366
4372
|
scope: s.scope,
|
|
4367
|
-
external: s.file
|
|
4373
|
+
external: !isLocal(s.file)
|
|
4368
4374
|
}));
|
|
4369
4375
|
}
|
|
4370
4376
|
function addWeightedEdge(edgeMap, source, target, callType, weight) {
|
|
@@ -4399,6 +4405,52 @@ function materializeWeightedEdges(edgeMap, idPrefix) {
|
|
|
4399
4405
|
return edges;
|
|
4400
4406
|
}
|
|
4401
4407
|
|
|
4408
|
+
// src/codebase-index/writer-helpers.ts
|
|
4409
|
+
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
4410
|
+
function escapeLike(value) {
|
|
4411
|
+
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
4412
|
+
}
|
|
4413
|
+
function posixIndexPath(file) {
|
|
4414
|
+
return file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
4415
|
+
}
|
|
4416
|
+
function indexedFileMatchSql(column = "file") {
|
|
4417
|
+
return `(${column} = ? OR replace(${column}, '\\', '/') = ? OR replace(${column}, '\\', '/') LIKE ? ESCAPE '\\')`;
|
|
4418
|
+
}
|
|
4419
|
+
function indexedFileMatchArgs(file) {
|
|
4420
|
+
const posix4 = posixIndexPath(file.trim());
|
|
4421
|
+
return [file, posix4, `%/${escapeLike(posix4)}`];
|
|
4422
|
+
}
|
|
4423
|
+
function matchesIndexedPackageFilter(storedFile, packageLabel, filter) {
|
|
4424
|
+
if (packageLabel === filter) return true;
|
|
4425
|
+
const posixFile = posixIndexPath(storedFile);
|
|
4426
|
+
const posixFilter = posixIndexPath(filter.trim());
|
|
4427
|
+
if (!posixFilter) return false;
|
|
4428
|
+
return posixFile === posixFilter || posixFile.endsWith(`/${posixFilter}`) || posixFile.includes(`/${posixFilter}/`);
|
|
4429
|
+
}
|
|
4430
|
+
function assignRefsToSymbols(refs, symbols) {
|
|
4431
|
+
if (refs.length === 0 || symbols.length === 0) return [];
|
|
4432
|
+
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
4433
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4434
|
+
const assigned = [];
|
|
4435
|
+
for (const ref of refs) {
|
|
4436
|
+
let owner;
|
|
4437
|
+
for (const symbol of ordered) {
|
|
4438
|
+
if (symbol.line > ref.line) break;
|
|
4439
|
+
owner = symbol;
|
|
4440
|
+
}
|
|
4441
|
+
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
4442
|
+
if (!owner || owner.id <= 0) continue;
|
|
4443
|
+
const key = `${owner.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
4444
|
+
if (seen.has(key)) continue;
|
|
4445
|
+
seen.add(key);
|
|
4446
|
+
assigned.push({ ...ref, fromId: owner.id });
|
|
4447
|
+
}
|
|
4448
|
+
return assigned;
|
|
4449
|
+
}
|
|
4450
|
+
function resolveIndexDir(projectRoot, override) {
|
|
4451
|
+
return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
|
|
4452
|
+
}
|
|
4453
|
+
|
|
4402
4454
|
// src/codebase-index/writer-ref-mapper.ts
|
|
4403
4455
|
function mapWriterRefRow(row) {
|
|
4404
4456
|
return {
|
|
@@ -4454,10 +4506,23 @@ function mapCallSiteRow(row) {
|
|
|
4454
4506
|
line: row.ref_line
|
|
4455
4507
|
};
|
|
4456
4508
|
}
|
|
4509
|
+
function resolveIndexedFiles(stmt, file) {
|
|
4510
|
+
const rows = stmt(
|
|
4511
|
+
`SELECT DISTINCT file FROM symbols WHERE ${indexedFileMatchSql("file")} ORDER BY length(file), file`
|
|
4512
|
+
).all(...indexedFileMatchArgs(file));
|
|
4513
|
+
return rows.map((row) => row.file);
|
|
4514
|
+
}
|
|
4457
4515
|
function resolveSymbolIds(stmt, symbolName, file) {
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4516
|
+
if (!file) {
|
|
4517
|
+
const rows2 = stmt("SELECT id FROM symbols WHERE name = ? ORDER BY id").all(symbolName);
|
|
4518
|
+
return rows2.map((r) => r.id);
|
|
4519
|
+
}
|
|
4520
|
+
const indexedFiles = resolveIndexedFiles(stmt, file);
|
|
4521
|
+
if (indexedFiles.length === 0) return [];
|
|
4522
|
+
const placeholders = indexedFiles.map(() => "?").join(",");
|
|
4523
|
+
const rows = stmt(
|
|
4524
|
+
`SELECT id FROM symbols WHERE name = ? AND file IN (${placeholders}) ORDER BY id`
|
|
4525
|
+
).all(symbolName, ...indexedFiles);
|
|
4461
4526
|
return rows.map((r) => r.id);
|
|
4462
4527
|
}
|
|
4463
4528
|
function findIncomingCallsByName(stmt, symbolName, file, limit) {
|
|
@@ -4779,7 +4844,7 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
4779
4844
|
const allFiles = stmt("SELECT DISTINCT file FROM symbols").all();
|
|
4780
4845
|
const packageOf = readPackageLabeller(stmt);
|
|
4781
4846
|
const langOf = (file) => detectLang(file) ?? "other";
|
|
4782
|
-
const pkgFilePaths = allFiles.filter((f) => packageOf(f.file)
|
|
4847
|
+
const pkgFilePaths = allFiles.filter((f) => matchesIndexedPackageFilter(f.file, packageOf(f.file), packageFilter)).map((f) => f.file);
|
|
4783
4848
|
const localFiles = new Set(pkgFilePaths);
|
|
4784
4849
|
if (localFiles.size === 0) return { nodes: [], edges: [] };
|
|
4785
4850
|
const filePlaceholders = [...localFiles].map(() => "?").join(",");
|
|
@@ -4855,9 +4920,12 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
4855
4920
|
return { nodes: [...fileNodes.values()], edges };
|
|
4856
4921
|
}
|
|
4857
4922
|
function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
4923
|
+
const indexedFiles = resolveIndexedFiles(stmt, fileFilter);
|
|
4924
|
+
if (indexedFiles.length === 0) return { nodes: [], edges: [] };
|
|
4925
|
+
const filePlaceholders = indexedFiles.map(() => "?").join(",");
|
|
4858
4926
|
const syms = stmt(
|
|
4859
|
-
|
|
4860
|
-
).all(
|
|
4927
|
+
`SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY line, id`
|
|
4928
|
+
).all(...indexedFiles);
|
|
4861
4929
|
if (syms.length === 0) return { nodes: [], edges: [] };
|
|
4862
4930
|
const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));
|
|
4863
4931
|
const relatedIds = new Set(syms.map((symbol) => symbol.id));
|
|
@@ -4867,16 +4935,16 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
4867
4935
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
4868
4936
|
FROM refs r
|
|
4869
4937
|
JOIN symbols s ON s.id = r.from_id
|
|
4870
|
-
WHERE s.file
|
|
4938
|
+
WHERE s.file IN (${filePlaceholders})
|
|
4871
4939
|
UNION
|
|
4872
4940
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
4873
4941
|
FROM refs r
|
|
4874
4942
|
JOIN symbols s ON s.id = r.to_id
|
|
4875
|
-
WHERE s.file
|
|
4943
|
+
WHERE s.file IN (${filePlaceholders})
|
|
4876
4944
|
)
|
|
4877
4945
|
WHERE to_id IS NOT NULL
|
|
4878
4946
|
GROUP BY from_id, to_id, call_type`
|
|
4879
|
-
).all(
|
|
4947
|
+
).all(...indexedFiles, ...indexedFiles);
|
|
4880
4948
|
const edgeMap = /* @__PURE__ */ new Map();
|
|
4881
4949
|
for (const r of refRows) {
|
|
4882
4950
|
if (r.to_id == null) continue;
|
|
@@ -4895,39 +4963,15 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
4895
4963
|
).all(...missingIds);
|
|
4896
4964
|
for (const s of extras) symById.set(s.id, s);
|
|
4897
4965
|
}
|
|
4898
|
-
const nodes = buildSymbolGraphNodes(
|
|
4966
|
+
const nodes = buildSymbolGraphNodes(
|
|
4967
|
+
symById,
|
|
4968
|
+
relatedIds,
|
|
4969
|
+
new Set(syms.map((symbol) => symbol.file)),
|
|
4970
|
+
readPackageLabeller(stmt)
|
|
4971
|
+
);
|
|
4899
4972
|
return { nodes, edges };
|
|
4900
4973
|
}
|
|
4901
4974
|
|
|
4902
|
-
// src/codebase-index/writer-helpers.ts
|
|
4903
|
-
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
4904
|
-
function escapeLike(value) {
|
|
4905
|
-
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
4906
|
-
}
|
|
4907
|
-
function assignRefsToSymbols(refs, symbols) {
|
|
4908
|
-
if (refs.length === 0 || symbols.length === 0) return [];
|
|
4909
|
-
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
4910
|
-
const seen = /* @__PURE__ */ new Set();
|
|
4911
|
-
const assigned = [];
|
|
4912
|
-
for (const ref of refs) {
|
|
4913
|
-
let owner;
|
|
4914
|
-
for (const symbol of ordered) {
|
|
4915
|
-
if (symbol.line > ref.line) break;
|
|
4916
|
-
owner = symbol;
|
|
4917
|
-
}
|
|
4918
|
-
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
4919
|
-
if (!owner || owner.id <= 0) continue;
|
|
4920
|
-
const key = `${owner.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
4921
|
-
if (seen.has(key)) continue;
|
|
4922
|
-
seen.add(key);
|
|
4923
|
-
assigned.push({ ...ref, fromId: owner.id });
|
|
4924
|
-
}
|
|
4925
|
-
return assigned;
|
|
4926
|
-
}
|
|
4927
|
-
function resolveIndexDir(projectRoot, override) {
|
|
4928
|
-
return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
|
|
4929
|
-
}
|
|
4930
|
-
|
|
4931
4975
|
// src/codebase-index/vector-search.ts
|
|
4932
4976
|
var RRF_K = 60;
|
|
4933
4977
|
var VECTOR_DIMENSIONS = 384;
|