@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
package/dist/index.js
CHANGED
|
@@ -1034,8 +1034,8 @@ async function* spawnStream(opts) {
|
|
|
1034
1034
|
try {
|
|
1035
1035
|
for (; ; ) {
|
|
1036
1036
|
while (queue.length === 0) {
|
|
1037
|
-
await new Promise((
|
|
1038
|
-
waiter =
|
|
1037
|
+
await new Promise((resolve24) => {
|
|
1038
|
+
waiter = resolve24;
|
|
1039
1039
|
});
|
|
1040
1040
|
}
|
|
1041
1041
|
const chunk = queue.shift();
|
|
@@ -1138,9 +1138,9 @@ async function detectPackageManager(cwd, stopAt) {
|
|
|
1138
1138
|
return "npm";
|
|
1139
1139
|
}
|
|
1140
1140
|
async function detectPackageManagerInDir(dir) {
|
|
1141
|
-
const
|
|
1141
|
+
const fs44 = await import("node:fs/promises");
|
|
1142
1142
|
try {
|
|
1143
|
-
const raw = await
|
|
1143
|
+
const raw = await fs44.readFile(path3.join(dir, "package.json"), "utf8");
|
|
1144
1144
|
const declared = JSON.parse(raw).packageManager;
|
|
1145
1145
|
if (typeof declared === "string") {
|
|
1146
1146
|
const name = declared.split("@")[0] ?? "";
|
|
@@ -1159,7 +1159,7 @@ async function detectPackageManagerInDir(dir) {
|
|
|
1159
1159
|
];
|
|
1160
1160
|
for (const [file, manager] of lockfiles) {
|
|
1161
1161
|
try {
|
|
1162
|
-
await
|
|
1162
|
+
await fs44.stat(`${dir}/${file}`);
|
|
1163
1163
|
return manager;
|
|
1164
1164
|
} catch {
|
|
1165
1165
|
}
|
|
@@ -4140,15 +4140,15 @@ async function changedPaths(before, after, beforeSizes, afterSizes) {
|
|
|
4140
4140
|
const beforeSet = new Set(before);
|
|
4141
4141
|
const afterSet = new Set(after);
|
|
4142
4142
|
const changed = /* @__PURE__ */ new Set();
|
|
4143
|
-
for (const
|
|
4144
|
-
if (!beforeSet.has(
|
|
4143
|
+
for (const path50 of after) {
|
|
4144
|
+
if (!beforeSet.has(path50)) changed.add(path50);
|
|
4145
4145
|
}
|
|
4146
|
-
for (const
|
|
4147
|
-
if (!afterSet.has(
|
|
4146
|
+
for (const path50 of before) {
|
|
4147
|
+
if (!afterSet.has(path50)) changed.add(path50);
|
|
4148
4148
|
}
|
|
4149
4149
|
if (beforeSizes && afterSizes) {
|
|
4150
|
-
for (const
|
|
4151
|
-
if (beforeSizes.get(
|
|
4150
|
+
for (const path50 of after) {
|
|
4151
|
+
if (beforeSizes.get(path50) !== afterSizes.get(path50)) changed.add(path50);
|
|
4152
4152
|
}
|
|
4153
4153
|
}
|
|
4154
4154
|
return [...changed].sort();
|
|
@@ -5643,7 +5643,7 @@ async function syncGoParse(filePath, content, lang) {
|
|
|
5643
5643
|
}
|
|
5644
5644
|
const goBinary = resolveWin32Command("go");
|
|
5645
5645
|
const goResult = await new Promise(
|
|
5646
|
-
(
|
|
5646
|
+
(resolve24, reject) => {
|
|
5647
5647
|
let settled = false;
|
|
5648
5648
|
const proc = spawn5(goBinary, ["run", scriptPath], {
|
|
5649
5649
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -5672,7 +5672,7 @@ async function syncGoParse(filePath, content, lang) {
|
|
|
5672
5672
|
if (settled) return;
|
|
5673
5673
|
settled = true;
|
|
5674
5674
|
clearTimeout(timer);
|
|
5675
|
-
|
|
5675
|
+
resolve24({ code: code2, stdout: stdout2 });
|
|
5676
5676
|
});
|
|
5677
5677
|
}
|
|
5678
5678
|
);
|
|
@@ -6348,7 +6348,7 @@ async function resolvePython() {
|
|
|
6348
6348
|
return null;
|
|
6349
6349
|
}
|
|
6350
6350
|
function commandIsAvailable(command) {
|
|
6351
|
-
return new Promise((
|
|
6351
|
+
return new Promise((resolve24) => {
|
|
6352
6352
|
let settled = false;
|
|
6353
6353
|
const proc = spawn6(command, ["--version"], {
|
|
6354
6354
|
stdio: "ignore",
|
|
@@ -6358,7 +6358,7 @@ function commandIsAvailable(command) {
|
|
|
6358
6358
|
if (settled) return;
|
|
6359
6359
|
settled = true;
|
|
6360
6360
|
clearTimeout(timer);
|
|
6361
|
-
|
|
6361
|
+
resolve24(available);
|
|
6362
6362
|
};
|
|
6363
6363
|
const timer = setTimeout(() => {
|
|
6364
6364
|
proc.kill("SIGKILL");
|
|
@@ -6370,7 +6370,7 @@ function commandIsAvailable(command) {
|
|
|
6370
6370
|
});
|
|
6371
6371
|
}
|
|
6372
6372
|
function spawnPyParser(pyBinary, scriptPath, filePath, content) {
|
|
6373
|
-
return new Promise((
|
|
6373
|
+
return new Promise((resolve24, reject) => {
|
|
6374
6374
|
let settled = false;
|
|
6375
6375
|
const proc = spawn6(pyBinary, [scriptPath, filePath], {
|
|
6376
6376
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -6399,7 +6399,7 @@ function spawnPyParser(pyBinary, scriptPath, filePath, content) {
|
|
|
6399
6399
|
if (settled) return;
|
|
6400
6400
|
settled = true;
|
|
6401
6401
|
clearTimeout(timer);
|
|
6402
|
-
|
|
6402
|
+
resolve24({ code, stdout });
|
|
6403
6403
|
});
|
|
6404
6404
|
});
|
|
6405
6405
|
}
|
|
@@ -9615,10 +9615,10 @@ var bashTool = {
|
|
|
9615
9615
|
queue.push(c);
|
|
9616
9616
|
}
|
|
9617
9617
|
};
|
|
9618
|
-
const next = () => new Promise((
|
|
9618
|
+
const next = () => new Promise((resolve24) => {
|
|
9619
9619
|
const c = queue.shift();
|
|
9620
|
-
if (c)
|
|
9621
|
-
else resolveNext =
|
|
9620
|
+
if (c) resolve24(c);
|
|
9621
|
+
else resolveNext = resolve24;
|
|
9622
9622
|
});
|
|
9623
9623
|
let lastFlush = Date.now();
|
|
9624
9624
|
const flush = () => {
|
|
@@ -10071,11 +10071,11 @@ var BrowserArtifactStore = class {
|
|
|
10071
10071
|
};
|
|
10072
10072
|
async function hashFile(target) {
|
|
10073
10073
|
const hash = createHash3("sha256");
|
|
10074
|
-
await new Promise((
|
|
10074
|
+
await new Promise((resolve24, reject) => {
|
|
10075
10075
|
const stream = createReadStream(target);
|
|
10076
10076
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
10077
10077
|
stream.once("error", reject);
|
|
10078
|
-
stream.once("end",
|
|
10078
|
+
stream.once("end", resolve24);
|
|
10079
10079
|
});
|
|
10080
10080
|
return hash.digest("hex");
|
|
10081
10081
|
}
|
|
@@ -10230,7 +10230,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
10230
10230
|
async start() {
|
|
10231
10231
|
if (this.url) return this.url;
|
|
10232
10232
|
if (this.startPromise) return this.startPromise;
|
|
10233
|
-
this.startPromise = new Promise((
|
|
10233
|
+
this.startPromise = new Promise((resolve24, reject) => {
|
|
10234
10234
|
const onError = (error) => {
|
|
10235
10235
|
this.server.off("listening", onListening);
|
|
10236
10236
|
reject(error);
|
|
@@ -10243,7 +10243,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
10243
10243
|
return;
|
|
10244
10244
|
}
|
|
10245
10245
|
this.url = `http://127.0.0.1:${address.port}`;
|
|
10246
|
-
|
|
10246
|
+
resolve24(this.url);
|
|
10247
10247
|
};
|
|
10248
10248
|
this.server.once("error", onError);
|
|
10249
10249
|
this.server.once("listening", onListening);
|
|
@@ -10258,7 +10258,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
10258
10258
|
for (const socket of this.sockets) socket.destroy();
|
|
10259
10259
|
this.sockets.clear();
|
|
10260
10260
|
if (!this.server.listening) return;
|
|
10261
|
-
await new Promise((
|
|
10261
|
+
await new Promise((resolve24) => this.server.close(() => resolve24()));
|
|
10262
10262
|
}
|
|
10263
10263
|
async forwardHttp(request2, response) {
|
|
10264
10264
|
try {
|
|
@@ -10831,7 +10831,7 @@ function pushBounded(target, value, limit) {
|
|
|
10831
10831
|
}
|
|
10832
10832
|
async function abortable(signal, operation, onAbort) {
|
|
10833
10833
|
signal.throwIfAborted();
|
|
10834
|
-
return new Promise((
|
|
10834
|
+
return new Promise((resolve24, reject) => {
|
|
10835
10835
|
let settled = false;
|
|
10836
10836
|
let aborting = false;
|
|
10837
10837
|
const finish = (fn) => {
|
|
@@ -10849,7 +10849,7 @@ async function abortable(signal, operation, onAbort) {
|
|
|
10849
10849
|
signal.addEventListener("abort", abort, { once: true });
|
|
10850
10850
|
operation().then(
|
|
10851
10851
|
(value) => {
|
|
10852
|
-
if (!aborting) finish(() =>
|
|
10852
|
+
if (!aborting) finish(() => resolve24(value));
|
|
10853
10853
|
},
|
|
10854
10854
|
(err) => {
|
|
10855
10855
|
if (!aborting) finish(() => reject(err));
|
|
@@ -12116,10 +12116,16 @@ function buildFileGraphNodeState(pkgSyms, localFiles, packageOf) {
|
|
|
12116
12116
|
}
|
|
12117
12117
|
return { fileNodes, symToFile, fileStats, ensureFileNode };
|
|
12118
12118
|
}
|
|
12119
|
-
function buildSymbolGraphNodes(symById, relatedIds,
|
|
12119
|
+
function buildSymbolGraphNodes(symById, relatedIds, localFiles, packageOf) {
|
|
12120
|
+
const local = new Set(
|
|
12121
|
+
[...typeof localFiles === "string" ? [localFiles] : localFiles].map(
|
|
12122
|
+
(file) => file.replace(/\\/g, "/")
|
|
12123
|
+
)
|
|
12124
|
+
);
|
|
12125
|
+
const isLocal = (file) => local.has(file.replace(/\\/g, "/"));
|
|
12120
12126
|
return [...relatedIds].map((id) => symById.get(id)).filter((symbol) => symbol !== void 0).sort((a, b) => {
|
|
12121
|
-
const aExternal = a.file
|
|
12122
|
-
const bExternal = b.file
|
|
12127
|
+
const aExternal = isLocal(a.file) ? 0 : 1;
|
|
12128
|
+
const bExternal = isLocal(b.file) ? 0 : 1;
|
|
12123
12129
|
return aExternal - bExternal || a.file.localeCompare(b.file) || a.line - b.line || a.id - b.id;
|
|
12124
12130
|
}).map((s) => ({
|
|
12125
12131
|
id: `sym:${s.id}`,
|
|
@@ -12133,7 +12139,7 @@ function buildSymbolGraphNodes(symById, relatedIds, fileFilter, packageOf) {
|
|
|
12133
12139
|
line: s.line,
|
|
12134
12140
|
signature: s.signature,
|
|
12135
12141
|
scope: s.scope,
|
|
12136
|
-
external: s.file
|
|
12142
|
+
external: !isLocal(s.file)
|
|
12137
12143
|
}));
|
|
12138
12144
|
}
|
|
12139
12145
|
function addWeightedEdge(edgeMap, source, target, callType, weight) {
|
|
@@ -12168,6 +12174,56 @@ function materializeWeightedEdges(edgeMap, idPrefix) {
|
|
|
12168
12174
|
return edges;
|
|
12169
12175
|
}
|
|
12170
12176
|
|
|
12177
|
+
// src/codebase-index/writer-helpers.ts
|
|
12178
|
+
import { resolveWstackPaths as resolveWstackPaths2 } from "@wrongstack/core/utils";
|
|
12179
|
+
function escapeLike(value) {
|
|
12180
|
+
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
12181
|
+
}
|
|
12182
|
+
function posixIndexPath(file) {
|
|
12183
|
+
return file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
12184
|
+
}
|
|
12185
|
+
function indexedFileMatchSql(column = "file") {
|
|
12186
|
+
return `(${column} = ? OR replace(${column}, '\\', '/') = ? OR replace(${column}, '\\', '/') LIKE ? ESCAPE '\\')`;
|
|
12187
|
+
}
|
|
12188
|
+
function indexedFileMatchArgs(file) {
|
|
12189
|
+
const posix4 = posixIndexPath(file.trim());
|
|
12190
|
+
return [file, posix4, `%/${escapeLike(posix4)}`];
|
|
12191
|
+
}
|
|
12192
|
+
function matchesIndexedPackageFilter(storedFile, packageLabel, filter) {
|
|
12193
|
+
if (packageLabel === filter) return true;
|
|
12194
|
+
const posixFile = posixIndexPath(storedFile);
|
|
12195
|
+
const posixFilter = posixIndexPath(filter.trim());
|
|
12196
|
+
if (!posixFilter) return false;
|
|
12197
|
+
return posixFile === posixFilter || posixFile.endsWith(`/${posixFilter}`) || posixFile.includes(`/${posixFilter}/`);
|
|
12198
|
+
}
|
|
12199
|
+
function assignRefsToSymbols(refs, symbols) {
|
|
12200
|
+
if (refs.length === 0 || symbols.length === 0) return [];
|
|
12201
|
+
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
12202
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12203
|
+
const assigned = [];
|
|
12204
|
+
for (const ref of refs) {
|
|
12205
|
+
let owner2;
|
|
12206
|
+
for (const symbol of ordered) {
|
|
12207
|
+
if (symbol.line > ref.line) break;
|
|
12208
|
+
owner2 = symbol;
|
|
12209
|
+
}
|
|
12210
|
+
if (!owner2 && ref.callType === "import") owner2 = ordered[0];
|
|
12211
|
+
if (!owner2 || owner2.id <= 0) continue;
|
|
12212
|
+
const key = `${owner2.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
12213
|
+
if (seen.has(key)) continue;
|
|
12214
|
+
seen.add(key);
|
|
12215
|
+
assigned.push({ ...ref, fromId: owner2.id });
|
|
12216
|
+
}
|
|
12217
|
+
return assigned;
|
|
12218
|
+
}
|
|
12219
|
+
function resolveIndexDir(projectRoot, override) {
|
|
12220
|
+
return override ?? resolveWstackPaths2({ projectRoot }).projectCodebaseIndex;
|
|
12221
|
+
}
|
|
12222
|
+
function codebaseIndexDirOverride(ctx) {
|
|
12223
|
+
const v = ctx.meta?.["codebaseIndexDir"];
|
|
12224
|
+
return typeof v === "string" ? v : void 0;
|
|
12225
|
+
}
|
|
12226
|
+
|
|
12171
12227
|
// src/codebase-index/writer-ref-mapper.ts
|
|
12172
12228
|
function mapWriterRefRow(row) {
|
|
12173
12229
|
return {
|
|
@@ -12223,10 +12279,23 @@ function mapCallSiteRow(row) {
|
|
|
12223
12279
|
line: row.ref_line
|
|
12224
12280
|
};
|
|
12225
12281
|
}
|
|
12282
|
+
function resolveIndexedFiles(stmt, file) {
|
|
12283
|
+
const rows = stmt(
|
|
12284
|
+
`SELECT DISTINCT file FROM symbols WHERE ${indexedFileMatchSql("file")} ORDER BY length(file), file`
|
|
12285
|
+
).all(...indexedFileMatchArgs(file));
|
|
12286
|
+
return rows.map((row) => row.file);
|
|
12287
|
+
}
|
|
12226
12288
|
function resolveSymbolIds(stmt, symbolName, file) {
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12289
|
+
if (!file) {
|
|
12290
|
+
const rows2 = stmt("SELECT id FROM symbols WHERE name = ? ORDER BY id").all(symbolName);
|
|
12291
|
+
return rows2.map((r) => r.id);
|
|
12292
|
+
}
|
|
12293
|
+
const indexedFiles = resolveIndexedFiles(stmt, file);
|
|
12294
|
+
if (indexedFiles.length === 0) return [];
|
|
12295
|
+
const placeholders = indexedFiles.map(() => "?").join(",");
|
|
12296
|
+
const rows = stmt(
|
|
12297
|
+
`SELECT id FROM symbols WHERE name = ? AND file IN (${placeholders}) ORDER BY id`
|
|
12298
|
+
).all(symbolName, ...indexedFiles);
|
|
12230
12299
|
return rows.map((r) => r.id);
|
|
12231
12300
|
}
|
|
12232
12301
|
function findIncomingCallsByName(stmt, symbolName, file, limit) {
|
|
@@ -12548,7 +12617,7 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
12548
12617
|
const allFiles = stmt("SELECT DISTINCT file FROM symbols").all();
|
|
12549
12618
|
const packageOf = readPackageLabeller(stmt);
|
|
12550
12619
|
const langOf = (file) => detectLang(file) ?? "other";
|
|
12551
|
-
const pkgFilePaths = allFiles.filter((f) => packageOf(f.file)
|
|
12620
|
+
const pkgFilePaths = allFiles.filter((f) => matchesIndexedPackageFilter(f.file, packageOf(f.file), packageFilter)).map((f) => f.file);
|
|
12552
12621
|
const localFiles = new Set(pkgFilePaths);
|
|
12553
12622
|
if (localFiles.size === 0) return { nodes: [], edges: [] };
|
|
12554
12623
|
const filePlaceholders = [...localFiles].map(() => "?").join(",");
|
|
@@ -12624,9 +12693,12 @@ function getFileGraphWithStatement(stmt, packageFilter) {
|
|
|
12624
12693
|
return { nodes: [...fileNodes.values()], edges };
|
|
12625
12694
|
}
|
|
12626
12695
|
function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
12696
|
+
const indexedFiles = resolveIndexedFiles(stmt, fileFilter);
|
|
12697
|
+
if (indexedFiles.length === 0) return { nodes: [], edges: [] };
|
|
12698
|
+
const filePlaceholders = indexedFiles.map(() => "?").join(",");
|
|
12627
12699
|
const syms = stmt(
|
|
12628
|
-
|
|
12629
|
-
).all(
|
|
12700
|
+
`SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY line, id`
|
|
12701
|
+
).all(...indexedFiles);
|
|
12630
12702
|
if (syms.length === 0) return { nodes: [], edges: [] };
|
|
12631
12703
|
const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));
|
|
12632
12704
|
const relatedIds = new Set(syms.map((symbol) => symbol.id));
|
|
@@ -12636,16 +12708,16 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
12636
12708
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
12637
12709
|
FROM refs r
|
|
12638
12710
|
JOIN symbols s ON s.id = r.from_id
|
|
12639
|
-
WHERE s.file
|
|
12711
|
+
WHERE s.file IN (${filePlaceholders})
|
|
12640
12712
|
UNION
|
|
12641
12713
|
SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
|
|
12642
12714
|
FROM refs r
|
|
12643
12715
|
JOIN symbols s ON s.id = r.to_id
|
|
12644
|
-
WHERE s.file
|
|
12716
|
+
WHERE s.file IN (${filePlaceholders})
|
|
12645
12717
|
)
|
|
12646
12718
|
WHERE to_id IS NOT NULL
|
|
12647
12719
|
GROUP BY from_id, to_id, call_type`
|
|
12648
|
-
).all(
|
|
12720
|
+
).all(...indexedFiles, ...indexedFiles);
|
|
12649
12721
|
const edgeMap = /* @__PURE__ */ new Map();
|
|
12650
12722
|
for (const r of refRows) {
|
|
12651
12723
|
if (r.to_id == null) continue;
|
|
@@ -12664,43 +12736,15 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
12664
12736
|
).all(...missingIds);
|
|
12665
12737
|
for (const s of extras) symById.set(s.id, s);
|
|
12666
12738
|
}
|
|
12667
|
-
const nodes = buildSymbolGraphNodes(
|
|
12739
|
+
const nodes = buildSymbolGraphNodes(
|
|
12740
|
+
symById,
|
|
12741
|
+
relatedIds,
|
|
12742
|
+
new Set(syms.map((symbol) => symbol.file)),
|
|
12743
|
+
readPackageLabeller(stmt)
|
|
12744
|
+
);
|
|
12668
12745
|
return { nodes, edges };
|
|
12669
12746
|
}
|
|
12670
12747
|
|
|
12671
|
-
// src/codebase-index/writer-helpers.ts
|
|
12672
|
-
import { resolveWstackPaths as resolveWstackPaths2 } from "@wrongstack/core/utils";
|
|
12673
|
-
function escapeLike(value) {
|
|
12674
|
-
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
12675
|
-
}
|
|
12676
|
-
function assignRefsToSymbols(refs, symbols) {
|
|
12677
|
-
if (refs.length === 0 || symbols.length === 0) return [];
|
|
12678
|
-
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
12679
|
-
const seen = /* @__PURE__ */ new Set();
|
|
12680
|
-
const assigned = [];
|
|
12681
|
-
for (const ref of refs) {
|
|
12682
|
-
let owner2;
|
|
12683
|
-
for (const symbol of ordered) {
|
|
12684
|
-
if (symbol.line > ref.line) break;
|
|
12685
|
-
owner2 = symbol;
|
|
12686
|
-
}
|
|
12687
|
-
if (!owner2 && ref.callType === "import") owner2 = ordered[0];
|
|
12688
|
-
if (!owner2 || owner2.id <= 0) continue;
|
|
12689
|
-
const key = `${owner2.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
|
|
12690
|
-
if (seen.has(key)) continue;
|
|
12691
|
-
seen.add(key);
|
|
12692
|
-
assigned.push({ ...ref, fromId: owner2.id });
|
|
12693
|
-
}
|
|
12694
|
-
return assigned;
|
|
12695
|
-
}
|
|
12696
|
-
function resolveIndexDir(projectRoot, override) {
|
|
12697
|
-
return override ?? resolveWstackPaths2({ projectRoot }).projectCodebaseIndex;
|
|
12698
|
-
}
|
|
12699
|
-
function codebaseIndexDirOverride(ctx) {
|
|
12700
|
-
const v = ctx.meta?.["codebaseIndexDir"];
|
|
12701
|
-
return typeof v === "string" ? v : void 0;
|
|
12702
|
-
}
|
|
12703
|
-
|
|
12704
12748
|
// src/codebase-index/vector-search.ts
|
|
12705
12749
|
var RRF_K = 60;
|
|
12706
12750
|
var VECTOR_DIMENSIONS = 384;
|
|
@@ -14343,8 +14387,8 @@ function isProjectIndexServerHealth(value) {
|
|
|
14343
14387
|
return typeof health.checkedAt === "number" && typeof health.uptimeMs === "number" && typeof memory?.rss === "number" && typeof memory.heapUsed === "number" && typeof memory.heapTotal === "number" && typeof memory.external === "number" && typeof health.clients === "number" && typeof health.activeRequests === "number" && typeof health.activeWrites === "number" && typeof health.queuedWrites === "number" && typeof health.pendingExternalFiles === "number" && typeof health.watchingExternal === "boolean" && typeof activity?.indexing === "boolean" && typeof activity.currentFile === "number" && typeof activity.totalFiles === "number" && typeof activity.generation === "number";
|
|
14344
14388
|
}
|
|
14345
14389
|
function delay(ms) {
|
|
14346
|
-
return new Promise((
|
|
14347
|
-
const timer = setTimeout(
|
|
14390
|
+
return new Promise((resolve24) => {
|
|
14391
|
+
const timer = setTimeout(resolve24, ms);
|
|
14348
14392
|
timer.unref?.();
|
|
14349
14393
|
});
|
|
14350
14394
|
}
|
|
@@ -14550,7 +14594,7 @@ var ProjectServerConnection = class {
|
|
|
14550
14594
|
return Promise.reject(new Error("codebase-index server connection is not available"));
|
|
14551
14595
|
}
|
|
14552
14596
|
const id = this.nextId++;
|
|
14553
|
-
return new Promise((
|
|
14597
|
+
return new Promise((resolve24, reject) => {
|
|
14554
14598
|
const timer = setTimeout(() => {
|
|
14555
14599
|
const entry = this.pending.get(id);
|
|
14556
14600
|
if (!entry) return;
|
|
@@ -14573,7 +14617,7 @@ var ProjectServerConnection = class {
|
|
|
14573
14617
|
entry.reject(cancellationError(signal));
|
|
14574
14618
|
} : void 0;
|
|
14575
14619
|
this.pending.set(id, {
|
|
14576
|
-
resolve:
|
|
14620
|
+
resolve: resolve24,
|
|
14577
14621
|
reject,
|
|
14578
14622
|
timer,
|
|
14579
14623
|
signal,
|
|
@@ -14642,7 +14686,7 @@ var ProjectServerConnection = class {
|
|
|
14642
14686
|
this.binaryBuffer = [];
|
|
14643
14687
|
this.useBinary = false;
|
|
14644
14688
|
this.textDecoder = null;
|
|
14645
|
-
return new Promise((
|
|
14689
|
+
return new Promise((resolve24, reject) => {
|
|
14646
14690
|
const socket = net3.createConnection(this.endpoint);
|
|
14647
14691
|
this.socket = socket;
|
|
14648
14692
|
const timer = setTimeout(() => {
|
|
@@ -14654,7 +14698,7 @@ var ProjectServerConnection = class {
|
|
|
14654
14698
|
clearTimeout(timer);
|
|
14655
14699
|
this.connectResolve = null;
|
|
14656
14700
|
this.connectReject = null;
|
|
14657
|
-
|
|
14701
|
+
resolve24();
|
|
14658
14702
|
};
|
|
14659
14703
|
const finishReject = (error) => {
|
|
14660
14704
|
clearTimeout(timer);
|
|
@@ -15703,9 +15747,9 @@ var ParserWorkerPool = class {
|
|
|
15703
15747
|
for (let i = 0; i < files.length; i++) {
|
|
15704
15748
|
chunks[i % workerCount].push(files[i]);
|
|
15705
15749
|
}
|
|
15706
|
-
return new Promise((
|
|
15750
|
+
return new Promise((resolve24, reject) => {
|
|
15707
15751
|
this.pending.set(batchId, {
|
|
15708
|
-
resolve:
|
|
15752
|
+
resolve: resolve24,
|
|
15709
15753
|
reject,
|
|
15710
15754
|
accumulated: [],
|
|
15711
15755
|
expectedWorkers: workerCount,
|
|
@@ -15736,10 +15780,10 @@ var ParserWorkerPool = class {
|
|
|
15736
15780
|
await Promise.allSettled(
|
|
15737
15781
|
workers.map(
|
|
15738
15782
|
(w) => Promise.race([
|
|
15739
|
-
new Promise((
|
|
15740
|
-
w.once("exit", () =>
|
|
15783
|
+
new Promise((resolve24) => {
|
|
15784
|
+
w.once("exit", () => resolve24());
|
|
15741
15785
|
}),
|
|
15742
|
-
new Promise((
|
|
15786
|
+
new Promise((resolve24) => setTimeout(() => resolve24(), 2e3))
|
|
15743
15787
|
]).then(() => {
|
|
15744
15788
|
if (!w.threadId) return;
|
|
15745
15789
|
return w.terminate().catch(() => {
|
|
@@ -15800,7 +15844,7 @@ function shouldUseParserWorkerPool(candidateFileCount, parseBatchCount) {
|
|
|
15800
15844
|
return !isFrugalPerf() && candidateFileCount >= WORKER_POOL_THRESHOLD && parseBatchCount > 1;
|
|
15801
15845
|
}
|
|
15802
15846
|
function yieldEventLoop() {
|
|
15803
|
-
return new Promise((
|
|
15847
|
+
return new Promise((resolve24) => setImmediate(resolve24));
|
|
15804
15848
|
}
|
|
15805
15849
|
function throwIfAborted(signal) {
|
|
15806
15850
|
if (!signal?.aborted) return;
|
|
@@ -15832,7 +15876,7 @@ function normalizeComparablePath(value) {
|
|
|
15832
15876
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
15833
15877
|
}
|
|
15834
15878
|
function gitOutput(projectRoot, args) {
|
|
15835
|
-
return new Promise((
|
|
15879
|
+
return new Promise((resolve24, reject) => {
|
|
15836
15880
|
execFile(
|
|
15837
15881
|
"git",
|
|
15838
15882
|
["-C", projectRoot, ...args],
|
|
@@ -15843,7 +15887,7 @@ function gitOutput(projectRoot, args) {
|
|
|
15843
15887
|
},
|
|
15844
15888
|
(error, stdout) => {
|
|
15845
15889
|
if (error) reject(error);
|
|
15846
|
-
else
|
|
15890
|
+
else resolve24(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
|
|
15847
15891
|
}
|
|
15848
15892
|
);
|
|
15849
15893
|
});
|
|
@@ -16643,7 +16687,7 @@ function callIndexOp(op, args, opts) {
|
|
|
16643
16687
|
opts.signal.reason instanceof Error ? opts.signal.reason : new Error("Indexing cancelled")
|
|
16644
16688
|
);
|
|
16645
16689
|
}
|
|
16646
|
-
return new Promise((
|
|
16690
|
+
return new Promise((resolve24, reject) => {
|
|
16647
16691
|
const id = nextRpcId++;
|
|
16648
16692
|
const timer = setTimeout(() => {
|
|
16649
16693
|
pending.delete(id);
|
|
@@ -16665,7 +16709,7 @@ function callIndexOp(op, args, opts) {
|
|
|
16665
16709
|
pending.set(id, {
|
|
16666
16710
|
resolve: (v) => {
|
|
16667
16711
|
cleanup();
|
|
16668
|
-
|
|
16712
|
+
resolve24(v);
|
|
16669
16713
|
},
|
|
16670
16714
|
reject: (e) => {
|
|
16671
16715
|
cleanup();
|
|
@@ -17629,9 +17673,90 @@ var codebaseAstReplaceTool = {
|
|
|
17629
17673
|
}
|
|
17630
17674
|
};
|
|
17631
17675
|
|
|
17632
|
-
// src/codebase-index/codebase-
|
|
17676
|
+
// src/codebase-index/codebase-invariant-check-tool.ts
|
|
17677
|
+
import * as fs22 from "node:fs/promises";
|
|
17633
17678
|
import * as path27 from "node:path";
|
|
17634
17679
|
import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
|
|
17680
|
+
init_languages2();
|
|
17681
|
+
var codebaseInvariantCheckTool = {
|
|
17682
|
+
name: "codebase-invariant-check",
|
|
17683
|
+
category: "Inspect",
|
|
17684
|
+
icon: "index",
|
|
17685
|
+
permission: "auto",
|
|
17686
|
+
subjectKey: "file",
|
|
17687
|
+
mutating: false,
|
|
17688
|
+
capabilities: ["fs.read"],
|
|
17689
|
+
description: "Mathematically verify AST backward-compatibility invariants between original code and candidate mutations across TypeScript, Python, Go, Rust, Java, etc. Detects missing exports (INV-001), mandatory parameter additions (INV-002), interface breaking expansions (INV-003), and return type changes (INV-004) with zero hallucinations.",
|
|
17690
|
+
usageHint: "PRE-FLIGHT AST INVARIANT AUDIT:\n\n- Provide `file` and `modifiedCode` (or both `originalCode` and `modifiedCode`).\n- Returns `valid: true` if changes are strictly backward compatible.\n- Returns structured `violations[]` with exact rule IDs, offending symbol names, and fix instructions.",
|
|
17691
|
+
inputSchema: {
|
|
17692
|
+
type: "object",
|
|
17693
|
+
properties: {
|
|
17694
|
+
file: {
|
|
17695
|
+
type: "string",
|
|
17696
|
+
description: "Path to existing source file to compare against candidate modifications."
|
|
17697
|
+
},
|
|
17698
|
+
originalCode: {
|
|
17699
|
+
type: "string",
|
|
17700
|
+
description: "Original source code string (if not reading from an existing file)."
|
|
17701
|
+
},
|
|
17702
|
+
modifiedCode: {
|
|
17703
|
+
type: "string",
|
|
17704
|
+
description: "The candidate modified code string to validate."
|
|
17705
|
+
},
|
|
17706
|
+
lang: {
|
|
17707
|
+
type: "string",
|
|
17708
|
+
description: "Language hint (ts, py, go, rs, etc.). Inferred from file path if omitted."
|
|
17709
|
+
}
|
|
17710
|
+
},
|
|
17711
|
+
required: ["modifiedCode"],
|
|
17712
|
+
additionalProperties: false
|
|
17713
|
+
},
|
|
17714
|
+
async execute(input, ctx) {
|
|
17715
|
+
try {
|
|
17716
|
+
let originalCode = input.originalCode;
|
|
17717
|
+
let lang = input.lang;
|
|
17718
|
+
if (!originalCode && input.file) {
|
|
17719
|
+
const resolved = path27.isAbsolute(input.file) ? input.file : path27.resolve(ctx.projectRoot, input.file);
|
|
17720
|
+
originalCode = await fs22.readFile(resolved, "utf8");
|
|
17721
|
+
if (!lang) {
|
|
17722
|
+
lang = detectLang(resolved) ?? "ts";
|
|
17723
|
+
}
|
|
17724
|
+
}
|
|
17725
|
+
if (originalCode === void 0) {
|
|
17726
|
+
return {
|
|
17727
|
+
valid: false,
|
|
17728
|
+
violations: [],
|
|
17729
|
+
summary: "Neither originalCode nor file was provided for invariant comparison.",
|
|
17730
|
+
error: "Missing originalCode or file path."
|
|
17731
|
+
};
|
|
17732
|
+
}
|
|
17733
|
+
const res = await polyglotInvariantEngine.evaluate({
|
|
17734
|
+
originalCode,
|
|
17735
|
+
modifiedCode: input.modifiedCode,
|
|
17736
|
+
lang,
|
|
17737
|
+
filePath: input.file
|
|
17738
|
+
});
|
|
17739
|
+
const summary = res.valid ? "AST Invariants PASSED. Mutation is 100% backward compatible." : `AST Invariants FAILED with ${res.violations.length} violation(s):
|
|
17740
|
+
` + res.violations.map((v) => ` - [${v.ruleId}] ${v.symbolName}: ${v.message}`).join("\n");
|
|
17741
|
+
return {
|
|
17742
|
+
valid: res.valid,
|
|
17743
|
+
violations: res.violations,
|
|
17744
|
+
summary
|
|
17745
|
+
};
|
|
17746
|
+
} catch (err) {
|
|
17747
|
+
return {
|
|
17748
|
+
valid: false,
|
|
17749
|
+
violations: [],
|
|
17750
|
+
summary: `Error during invariant evaluation: ${toErrorMessage4(err)}`,
|
|
17751
|
+
error: toErrorMessage4(err)
|
|
17752
|
+
};
|
|
17753
|
+
}
|
|
17754
|
+
}
|
|
17755
|
+
};
|
|
17756
|
+
|
|
17757
|
+
// src/codebase-index/codebase-impact-analysis-tool.ts
|
|
17758
|
+
import * as path28 from "node:path";
|
|
17759
|
+
import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
|
|
17635
17760
|
var TEST_FILE_REGEX = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
|
|
17636
17761
|
var codebaseImpactAnalysisTool = {
|
|
17637
17762
|
name: "codebase-impact-analysis",
|
|
@@ -17668,6 +17793,9 @@ var codebaseImpactAnalysisTool = {
|
|
|
17668
17793
|
const limit = 200;
|
|
17669
17794
|
const transitive = input.transitive ?? true;
|
|
17670
17795
|
let rawSites = [];
|
|
17796
|
+
let symbolFound = true;
|
|
17797
|
+
let indexUnavailable = false;
|
|
17798
|
+
let indexError;
|
|
17671
17799
|
try {
|
|
17672
17800
|
const serviced = await incomingCallsService2({
|
|
17673
17801
|
projectRoot,
|
|
@@ -17678,13 +17806,49 @@ var codebaseImpactAnalysisTool = {
|
|
|
17678
17806
|
transitive
|
|
17679
17807
|
});
|
|
17680
17808
|
rawSites = serviced.calls;
|
|
17681
|
-
|
|
17809
|
+
symbolFound = serviced.symbolFound;
|
|
17810
|
+
} catch (err) {
|
|
17811
|
+
symbolFound = false;
|
|
17812
|
+
indexUnavailable = true;
|
|
17813
|
+
indexError = toErrorMessage5(err);
|
|
17814
|
+
}
|
|
17815
|
+
if (indexUnavailable) {
|
|
17816
|
+
const detail = indexError ? ` (${indexError})` : "";
|
|
17817
|
+
const reason = `Index query failed for '${input.symbol}'. Run codebase-index, then retry.${detail}`;
|
|
17818
|
+
return {
|
|
17819
|
+
status: "error",
|
|
17820
|
+
symbol: input.symbol,
|
|
17821
|
+
riskLevel: "low",
|
|
17822
|
+
summary: reason,
|
|
17823
|
+
totalCallSites: 0,
|
|
17824
|
+
affectedProductionFiles: [],
|
|
17825
|
+
affectedTestFiles: [],
|
|
17826
|
+
callSites: [],
|
|
17827
|
+
recommendedActionPlan: [reason],
|
|
17828
|
+
symbolFound: false,
|
|
17829
|
+
error: reason
|
|
17830
|
+
};
|
|
17831
|
+
}
|
|
17832
|
+
if (!symbolFound) {
|
|
17833
|
+
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.";
|
|
17834
|
+
return {
|
|
17835
|
+
status: "ok",
|
|
17836
|
+
symbol: input.symbol,
|
|
17837
|
+
riskLevel: "low",
|
|
17838
|
+
summary: reason,
|
|
17839
|
+
totalCallSites: 0,
|
|
17840
|
+
affectedProductionFiles: [],
|
|
17841
|
+
affectedTestFiles: [],
|
|
17842
|
+
callSites: [],
|
|
17843
|
+
recommendedActionPlan: [reason],
|
|
17844
|
+
symbolFound: false
|
|
17845
|
+
};
|
|
17682
17846
|
}
|
|
17683
17847
|
const prodFilesSet = /* @__PURE__ */ new Set();
|
|
17684
17848
|
const testFilesSet = /* @__PURE__ */ new Set();
|
|
17685
17849
|
const callSites = [];
|
|
17686
17850
|
for (const site of rawSites) {
|
|
17687
|
-
const relPath =
|
|
17851
|
+
const relPath = path28.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
|
|
17688
17852
|
const isTest = TEST_FILE_REGEX.test(relPath);
|
|
17689
17853
|
if (isTest) {
|
|
17690
17854
|
testFilesSet.add(relPath);
|
|
@@ -17734,7 +17898,8 @@ var codebaseImpactAnalysisTool = {
|
|
|
17734
17898
|
affectedProductionFiles: prodFiles,
|
|
17735
17899
|
affectedTestFiles: testFiles,
|
|
17736
17900
|
callSites,
|
|
17737
|
-
recommendedActionPlan
|
|
17901
|
+
recommendedActionPlan,
|
|
17902
|
+
symbolFound: true
|
|
17738
17903
|
};
|
|
17739
17904
|
} catch (err) {
|
|
17740
17905
|
return {
|
|
@@ -17747,14 +17912,15 @@ var codebaseImpactAnalysisTool = {
|
|
|
17747
17912
|
affectedTestFiles: [],
|
|
17748
17913
|
callSites: [],
|
|
17749
17914
|
recommendedActionPlan: [],
|
|
17750
|
-
|
|
17915
|
+
symbolFound: false,
|
|
17916
|
+
error: toErrorMessage5(err)
|
|
17751
17917
|
};
|
|
17752
17918
|
}
|
|
17753
17919
|
}
|
|
17754
17920
|
};
|
|
17755
17921
|
|
|
17756
17922
|
// src/codebase-index/codebase-incoming-calls-tool.ts
|
|
17757
|
-
import { toErrorMessage as
|
|
17923
|
+
import { toErrorMessage as toErrorMessage6 } from "@wrongstack/core/utils";
|
|
17758
17924
|
var codebaseIncomingCallsTool = {
|
|
17759
17925
|
name: "codebase-incoming-calls",
|
|
17760
17926
|
category: "Project",
|
|
@@ -17827,7 +17993,7 @@ var codebaseIncomingCallsTool = {
|
|
|
17827
17993
|
symbol: input.symbol,
|
|
17828
17994
|
calls: [],
|
|
17829
17995
|
total: 0,
|
|
17830
|
-
indexStatus: `Index query failed: ${
|
|
17996
|
+
indexStatus: `Index query failed: ${toErrorMessage6(err)}. Fall back to grep for this lookup.`
|
|
17831
17997
|
};
|
|
17832
17998
|
}
|
|
17833
17999
|
const { calls, symbolFound, ambiguous, totalMatches } = serviced;
|
|
@@ -17882,7 +18048,7 @@ var codebaseIncomingCallsTool = {
|
|
|
17882
18048
|
import { ToolValidationError } from "@wrongstack/core/types";
|
|
17883
18049
|
|
|
17884
18050
|
// src/codebase-index/codebase-search-tool.ts
|
|
17885
|
-
import { toErrorMessage as
|
|
18051
|
+
import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
|
|
17886
18052
|
var INDEXABLE_LANG_IDS = [
|
|
17887
18053
|
"ts",
|
|
17888
18054
|
"tsx",
|
|
@@ -18007,7 +18173,7 @@ var codebaseSearchTool = {
|
|
|
18007
18173
|
results: [],
|
|
18008
18174
|
total: 0,
|
|
18009
18175
|
query: input.query,
|
|
18010
|
-
indexStatus: `Index query failed: ${
|
|
18176
|
+
indexStatus: `Index query failed: ${toErrorMessage7(err)}. Fall back to grep/glob for this lookup.`
|
|
18011
18177
|
};
|
|
18012
18178
|
}
|
|
18013
18179
|
const { results, total } = searched;
|
|
@@ -18115,7 +18281,7 @@ var codebaseIndexTool = {
|
|
|
18115
18281
|
};
|
|
18116
18282
|
|
|
18117
18283
|
// src/codebase-index/codebase-outgoing-calls-tool.ts
|
|
18118
|
-
import { toErrorMessage as
|
|
18284
|
+
import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
|
|
18119
18285
|
var codebaseOutgoingCallsTool = {
|
|
18120
18286
|
name: "codebase-outgoing-calls",
|
|
18121
18287
|
category: "Project",
|
|
@@ -18188,7 +18354,7 @@ var codebaseOutgoingCallsTool = {
|
|
|
18188
18354
|
symbol: input.symbol,
|
|
18189
18355
|
calls: [],
|
|
18190
18356
|
total: 0,
|
|
18191
|
-
indexStatus: `Index query failed: ${
|
|
18357
|
+
indexStatus: `Index query failed: ${toErrorMessage8(err)}. Fall back to grep for this lookup.`
|
|
18192
18358
|
};
|
|
18193
18359
|
}
|
|
18194
18360
|
const { calls, symbolFound, unresolvedCount, totalMatches } = serviced;
|
|
@@ -18240,18 +18406,18 @@ var codebaseOutgoingCallsTool = {
|
|
|
18240
18406
|
};
|
|
18241
18407
|
|
|
18242
18408
|
// src/codebase-index/codebase-repo-map-tool.ts
|
|
18243
|
-
import { toErrorMessage as
|
|
18409
|
+
import { toErrorMessage as toErrorMessage9 } from "@wrongstack/core/utils";
|
|
18244
18410
|
|
|
18245
18411
|
// src/codebase-index/repo-map.ts
|
|
18246
18412
|
init_languages2();
|
|
18247
|
-
import * as
|
|
18248
|
-
import * as
|
|
18413
|
+
import * as fs24 from "node:fs/promises";
|
|
18414
|
+
import * as path30 from "node:path";
|
|
18249
18415
|
|
|
18250
18416
|
// src/codebase-index/skeleton-extractor.ts
|
|
18251
18417
|
init_languages2();
|
|
18252
18418
|
init_tree_sitter_parser();
|
|
18253
|
-
import * as
|
|
18254
|
-
import * as
|
|
18419
|
+
import * as fs23 from "node:fs/promises";
|
|
18420
|
+
import * as path29 from "node:path";
|
|
18255
18421
|
var tsModule3 = null;
|
|
18256
18422
|
async function loadTs3() {
|
|
18257
18423
|
if (!tsModule3) {
|
|
@@ -18579,7 +18745,7 @@ async function extractDirectorySkeleton(opts) {
|
|
|
18579
18745
|
if (filePaths.length >= maxFiles) return;
|
|
18580
18746
|
let entries;
|
|
18581
18747
|
try {
|
|
18582
|
-
entries = await
|
|
18748
|
+
entries = await fs23.readdir(dir, { withFileTypes: true });
|
|
18583
18749
|
} catch {
|
|
18584
18750
|
return;
|
|
18585
18751
|
}
|
|
@@ -18588,7 +18754,7 @@ async function extractDirectorySkeleton(opts) {
|
|
|
18588
18754
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build") {
|
|
18589
18755
|
continue;
|
|
18590
18756
|
}
|
|
18591
|
-
const fullPath =
|
|
18757
|
+
const fullPath = path29.join(dir, entry.name);
|
|
18592
18758
|
if (entry.isDirectory()) {
|
|
18593
18759
|
await scan(fullPath);
|
|
18594
18760
|
} else if (entry.isFile() && isIndexablePath(fullPath)) {
|
|
@@ -18605,7 +18771,7 @@ async function extractDirectorySkeleton(opts) {
|
|
|
18605
18771
|
const combinedParts = [];
|
|
18606
18772
|
for (const fp of filePaths) {
|
|
18607
18773
|
try {
|
|
18608
|
-
const content = await
|
|
18774
|
+
const content = await fs23.readFile(fp, "utf8");
|
|
18609
18775
|
const res = await extractFileSkeleton({
|
|
18610
18776
|
file: fp,
|
|
18611
18777
|
content,
|
|
@@ -18616,7 +18782,7 @@ async function extractDirectorySkeleton(opts) {
|
|
|
18616
18782
|
totalSkelChars += res.skeleton.length;
|
|
18617
18783
|
totalOrigLines += res.stats.originalLines;
|
|
18618
18784
|
totalSkelLines += res.stats.skeletonLines;
|
|
18619
|
-
const rel =
|
|
18785
|
+
const rel = path29.relative(opts.dirPath, fp).replace(/\\/g, "/");
|
|
18620
18786
|
combinedParts.push(
|
|
18621
18787
|
`// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ${rel} (${res.lang}) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
18622
18788
|
${res.skeleton}`
|
|
@@ -18653,13 +18819,13 @@ async function generateRepoMap(opts) {
|
|
|
18653
18819
|
const projectRoot = opts.projectRoot;
|
|
18654
18820
|
const maxTokens = opts.maxTokens ?? 1200;
|
|
18655
18821
|
const charBudget = maxTokens * 4;
|
|
18656
|
-
const focusSet = new Set((opts.focusFiles ?? []).map((f) =>
|
|
18822
|
+
const focusSet = new Set((opts.focusFiles ?? []).map((f) => path30.resolve(projectRoot, f)));
|
|
18657
18823
|
const allFiles = [];
|
|
18658
18824
|
async function scan(dir) {
|
|
18659
18825
|
if (allFiles.length > 500) return;
|
|
18660
18826
|
let entries;
|
|
18661
18827
|
try {
|
|
18662
|
-
entries = await
|
|
18828
|
+
entries = await fs24.readdir(dir, { withFileTypes: true });
|
|
18663
18829
|
} catch {
|
|
18664
18830
|
return;
|
|
18665
18831
|
}
|
|
@@ -18667,7 +18833,7 @@ async function generateRepoMap(opts) {
|
|
|
18667
18833
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
|
|
18668
18834
|
continue;
|
|
18669
18835
|
}
|
|
18670
|
-
const fullPath =
|
|
18836
|
+
const fullPath = path30.join(dir, entry.name);
|
|
18671
18837
|
if (entry.isDirectory()) {
|
|
18672
18838
|
await scan(fullPath);
|
|
18673
18839
|
} else if (entry.isFile() && isIndexablePath(fullPath)) {
|
|
@@ -18687,7 +18853,7 @@ async function generateRepoMap(opts) {
|
|
|
18687
18853
|
}
|
|
18688
18854
|
const scoredFiles = [];
|
|
18689
18855
|
for (const file of allFiles) {
|
|
18690
|
-
const relPath =
|
|
18856
|
+
const relPath = path30.relative(projectRoot, file).replace(/\\/g, "/");
|
|
18691
18857
|
let score = 10;
|
|
18692
18858
|
if (focusSet.has(file)) {
|
|
18693
18859
|
score += 100;
|
|
@@ -18702,7 +18868,7 @@ async function generateRepoMap(opts) {
|
|
|
18702
18868
|
for (const candidate of scoredFiles) {
|
|
18703
18869
|
if (currentChars >= charBudget) break;
|
|
18704
18870
|
try {
|
|
18705
|
-
const content = await
|
|
18871
|
+
const content = await fs24.readFile(candidate.file, "utf8");
|
|
18706
18872
|
if (content.length === 0) continue;
|
|
18707
18873
|
const skeletonResult = await extractFileSkeleton({
|
|
18708
18874
|
file: candidate.file,
|
|
@@ -18785,16 +18951,16 @@ var codebaseRepoMapTool = {
|
|
|
18785
18951
|
totalFilesScanned: 0,
|
|
18786
18952
|
estimatedTokens: 0,
|
|
18787
18953
|
rankedFiles: [],
|
|
18788
|
-
error:
|
|
18954
|
+
error: toErrorMessage9(err)
|
|
18789
18955
|
};
|
|
18790
18956
|
}
|
|
18791
18957
|
}
|
|
18792
18958
|
};
|
|
18793
18959
|
|
|
18794
18960
|
// src/codebase-index/codebase-skeleton-tool.ts
|
|
18795
|
-
import * as
|
|
18796
|
-
import * as
|
|
18797
|
-
import { toErrorMessage as
|
|
18961
|
+
import * as fs25 from "node:fs/promises";
|
|
18962
|
+
import * as path31 from "node:path";
|
|
18963
|
+
import { toErrorMessage as toErrorMessage10 } from "@wrongstack/core/utils";
|
|
18798
18964
|
var codebaseSkeletonTool = {
|
|
18799
18965
|
name: "codebase-skeleton",
|
|
18800
18966
|
category: "Project",
|
|
@@ -18833,13 +18999,13 @@ var codebaseSkeletonTool = {
|
|
|
18833
18999
|
additionalProperties: false
|
|
18834
19000
|
},
|
|
18835
19001
|
async execute(input, ctx) {
|
|
18836
|
-
const targetPath =
|
|
19002
|
+
const targetPath = path31.isAbsolute(input.path) ? input.path : path31.resolve(ctx.projectRoot ?? process.cwd(), input.path);
|
|
18837
19003
|
let stat22;
|
|
18838
19004
|
try {
|
|
18839
|
-
stat22 = await
|
|
19005
|
+
stat22 = await fs25.stat(targetPath);
|
|
18840
19006
|
} catch (err) {
|
|
18841
19007
|
throw new Error(
|
|
18842
|
-
`codebase-skeleton: file or directory not found at "${input.path}": ${
|
|
19008
|
+
`codebase-skeleton: file or directory not found at "${input.path}": ${toErrorMessage10(err)}`
|
|
18843
19009
|
);
|
|
18844
19010
|
}
|
|
18845
19011
|
const options = {
|
|
@@ -18872,7 +19038,7 @@ var codebaseSkeletonTool = {
|
|
|
18872
19038
|
files: dirResult.files
|
|
18873
19039
|
};
|
|
18874
19040
|
}
|
|
18875
|
-
const content = await
|
|
19041
|
+
const content = await fs25.readFile(targetPath, "utf8");
|
|
18876
19042
|
const fileResult = await extractFileSkeleton({
|
|
18877
19043
|
file: targetPath,
|
|
18878
19044
|
content,
|
|
@@ -18976,28 +19142,28 @@ var codebaseStatsTool = {
|
|
|
18976
19142
|
// src/codebase-index/codebase-targeted-test-tool.ts
|
|
18977
19143
|
init_spawn_stream();
|
|
18978
19144
|
init_util();
|
|
18979
|
-
import * as
|
|
18980
|
-
import * as
|
|
18981
|
-
import { toErrorMessage as
|
|
19145
|
+
import * as fs26 from "node:fs/promises";
|
|
19146
|
+
import * as path32 from "node:path";
|
|
19147
|
+
import { toErrorMessage as toErrorMessage11 } from "@wrongstack/core/utils";
|
|
18982
19148
|
var TEST_FILE_REGEX2 = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
|
|
18983
19149
|
async function findConventionTestFiles(projectRoot, sourceRelPath) {
|
|
18984
|
-
const parsed =
|
|
19150
|
+
const parsed = path32.parse(sourceRelPath);
|
|
18985
19151
|
const candidates = [
|
|
18986
|
-
|
|
18987
|
-
|
|
18988
|
-
|
|
18989
|
-
|
|
18990
|
-
|
|
18991
|
-
|
|
18992
|
-
|
|
18993
|
-
|
|
18994
|
-
|
|
19152
|
+
path32.join(parsed.dir, `${parsed.name}.test${parsed.ext}`),
|
|
19153
|
+
path32.join(parsed.dir, `${parsed.name}.spec${parsed.ext}`),
|
|
19154
|
+
path32.join(parsed.dir, `${parsed.name}_test${parsed.ext}`),
|
|
19155
|
+
path32.join(parsed.dir, `test_${parsed.name}${parsed.ext}`),
|
|
19156
|
+
path32.join("tests", `${parsed.name}.test${parsed.ext}`),
|
|
19157
|
+
path32.join("tests", `${parsed.name}.spec${parsed.ext}`),
|
|
19158
|
+
path32.join("test", `${parsed.name}.test${parsed.ext}`),
|
|
19159
|
+
path32.join(parsed.dir, "__tests__", `${parsed.name}.test${parsed.ext}`),
|
|
19160
|
+
path32.join(parsed.dir, "__tests__", `${parsed.name}${parsed.ext}`)
|
|
18995
19161
|
];
|
|
18996
19162
|
const found = [];
|
|
18997
19163
|
for (const cand of candidates) {
|
|
18998
|
-
const absPath =
|
|
19164
|
+
const absPath = path32.resolve(projectRoot, cand);
|
|
18999
19165
|
try {
|
|
19000
|
-
const st = await
|
|
19166
|
+
const st = await fs26.stat(absPath);
|
|
19001
19167
|
if (st.isFile()) {
|
|
19002
19168
|
found.push(cand.replace(/\\/g, "/"));
|
|
19003
19169
|
}
|
|
@@ -19054,7 +19220,7 @@ var codebaseTargetedTestTool = {
|
|
|
19054
19220
|
transitive: true
|
|
19055
19221
|
});
|
|
19056
19222
|
for (const site of serviced.calls) {
|
|
19057
|
-
const relPath =
|
|
19223
|
+
const relPath = path32.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
|
|
19058
19224
|
if (TEST_FILE_REGEX2.test(relPath)) {
|
|
19059
19225
|
suitesSet.add(relPath);
|
|
19060
19226
|
}
|
|
@@ -19131,7 +19297,7 @@ ${streamRes.stderr}`.trim(),
|
|
|
19131
19297
|
failed: 0,
|
|
19132
19298
|
durationMs: 0,
|
|
19133
19299
|
output: "",
|
|
19134
|
-
error:
|
|
19300
|
+
error: toErrorMessage11(err)
|
|
19135
19301
|
};
|
|
19136
19302
|
}
|
|
19137
19303
|
}
|
|
@@ -19139,8 +19305,8 @@ ${streamRes.stderr}`.trim(),
|
|
|
19139
19305
|
|
|
19140
19306
|
// src/codebase-index/dead-code-scan.ts
|
|
19141
19307
|
init_languages2();
|
|
19142
|
-
import * as
|
|
19143
|
-
import * as
|
|
19308
|
+
import * as fs27 from "node:fs";
|
|
19309
|
+
import * as path33 from "node:path";
|
|
19144
19310
|
var deadCodeScanTool = {
|
|
19145
19311
|
name: "dead-code-scan",
|
|
19146
19312
|
category: "Project",
|
|
@@ -19185,25 +19351,25 @@ var deadCodeScanTool = {
|
|
|
19185
19351
|
};
|
|
19186
19352
|
function tryReadJson(filePath) {
|
|
19187
19353
|
try {
|
|
19188
|
-
const raw =
|
|
19354
|
+
const raw = fs27.readFileSync(filePath, "utf8");
|
|
19189
19355
|
return JSON.parse(raw);
|
|
19190
19356
|
} catch {
|
|
19191
19357
|
return null;
|
|
19192
19358
|
}
|
|
19193
19359
|
}
|
|
19194
19360
|
function resolveAgainst(base, relative20) {
|
|
19195
|
-
if (
|
|
19196
|
-
return
|
|
19361
|
+
if (path33.isAbsolute(relative20)) return relative20;
|
|
19362
|
+
return path33.resolve(base, relative20);
|
|
19197
19363
|
}
|
|
19198
19364
|
function discoverEntryPoints(projectRoot, userEntryPoints) {
|
|
19199
19365
|
const entries = /* @__PURE__ */ new Set();
|
|
19200
19366
|
if (userEntryPoints) {
|
|
19201
19367
|
for (const ep of userEntryPoints) {
|
|
19202
19368
|
const resolved = resolveAgainst(projectRoot, ep);
|
|
19203
|
-
if (
|
|
19369
|
+
if (fs27.existsSync(resolved)) entries.add(resolved);
|
|
19204
19370
|
}
|
|
19205
19371
|
}
|
|
19206
|
-
const rootPkg = tryReadJson(
|
|
19372
|
+
const rootPkg = tryReadJson(path33.join(projectRoot, "package.json"));
|
|
19207
19373
|
if (rootPkg) {
|
|
19208
19374
|
addPkgJsonEntryPoints(projectRoot, rootPkg, entries);
|
|
19209
19375
|
}
|
|
@@ -19217,45 +19383,45 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
|
|
|
19217
19383
|
workspaces = [];
|
|
19218
19384
|
}
|
|
19219
19385
|
for (const wsDir of workspaces) {
|
|
19220
|
-
const pkgJsonPath =
|
|
19386
|
+
const pkgJsonPath = path33.join(wsDir, "package.json");
|
|
19221
19387
|
const pkg = tryReadJson(pkgJsonPath);
|
|
19222
19388
|
if (pkg) {
|
|
19223
19389
|
addPkgJsonEntryPoints(wsDir, pkg, entries);
|
|
19224
|
-
const convention1 =
|
|
19225
|
-
if (
|
|
19226
|
-
const convention2 =
|
|
19227
|
-
if (
|
|
19228
|
-
const convention3 =
|
|
19229
|
-
if (
|
|
19390
|
+
const convention1 = path33.join(wsDir, "src", "index.ts");
|
|
19391
|
+
if (fs27.existsSync(convention1)) entries.add(convention1);
|
|
19392
|
+
const convention2 = path33.join(wsDir, "src", "main.ts");
|
|
19393
|
+
if (fs27.existsSync(convention2)) entries.add(convention2);
|
|
19394
|
+
const convention3 = path33.join(wsDir, "index.ts");
|
|
19395
|
+
if (fs27.existsSync(convention3)) entries.add(convention3);
|
|
19230
19396
|
}
|
|
19231
19397
|
}
|
|
19232
19398
|
if (!rootPkg || !workspaces.length) {
|
|
19233
19399
|
for (const name of ["src/index.ts", "src/main.ts", "index.ts"]) {
|
|
19234
|
-
const convention =
|
|
19235
|
-
if (
|
|
19400
|
+
const convention = path33.join(projectRoot, name);
|
|
19401
|
+
if (fs27.existsSync(convention)) entries.add(convention);
|
|
19236
19402
|
}
|
|
19237
19403
|
}
|
|
19238
19404
|
return [...entries];
|
|
19239
19405
|
}
|
|
19240
19406
|
var BUILD_OUTPUT_DIRS = ["dist", "out", "build", "release"];
|
|
19241
|
-
var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${
|
|
19407
|
+
var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path33.sep}${d}${path33.sep}`);
|
|
19242
19408
|
function trySourceEquivalent(resolved) {
|
|
19243
|
-
resolved = resolved.replace(/[/\\]/g,
|
|
19409
|
+
resolved = resolved.replace(/[/\\]/g, path33.sep);
|
|
19244
19410
|
for (const marker of BUILD_OUTPUT_DIR_NAMES) {
|
|
19245
19411
|
const idx = resolved.indexOf(marker);
|
|
19246
19412
|
if (idx === -1) continue;
|
|
19247
|
-
const base = resolved.replace(marker, `${
|
|
19413
|
+
const base = resolved.replace(marker, `${path33.sep}src${path33.sep}`);
|
|
19248
19414
|
const candidate = base.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
19249
|
-
if (candidate !== base &&
|
|
19415
|
+
if (candidate !== base && fs27.existsSync(candidate)) {
|
|
19250
19416
|
return candidate;
|
|
19251
19417
|
}
|
|
19252
19418
|
const dtsStripped = base.replace(/\.d\.ts$/, "");
|
|
19253
19419
|
const candidateDts = dtsStripped + ".ts";
|
|
19254
|
-
if (candidateDts !== base && candidateDts !== candidate &&
|
|
19420
|
+
if (candidateDts !== base && candidateDts !== candidate && fs27.existsSync(candidateDts)) {
|
|
19255
19421
|
return candidateDts;
|
|
19256
19422
|
}
|
|
19257
19423
|
const candidateNoExt = base + ".ts";
|
|
19258
|
-
if (candidate !== candidateNoExt && candidateNoExt !== candidateDts &&
|
|
19424
|
+
if (candidate !== candidateNoExt && candidateNoExt !== candidateDts && fs27.existsSync(candidateNoExt)) {
|
|
19259
19425
|
return candidateNoExt;
|
|
19260
19426
|
}
|
|
19261
19427
|
}
|
|
@@ -19263,9 +19429,9 @@ function trySourceEquivalent(resolved) {
|
|
|
19263
19429
|
}
|
|
19264
19430
|
function tryAddEntryPath(pkgDir, rawPath, entries) {
|
|
19265
19431
|
const resolved = resolveAgainst(pkgDir, rawPath);
|
|
19266
|
-
if (
|
|
19432
|
+
if (fs27.existsSync(resolved)) entries.add(resolved);
|
|
19267
19433
|
const tsResolved = resolved.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
19268
|
-
if (tsResolved !== resolved &&
|
|
19434
|
+
if (tsResolved !== resolved && fs27.existsSync(tsResolved)) {
|
|
19269
19435
|
entries.add(tsResolved);
|
|
19270
19436
|
}
|
|
19271
19437
|
const srcAlt = trySourceEquivalent(resolved);
|
|
@@ -19309,18 +19475,18 @@ function expandGlobPattern(entry, projectRoot) {
|
|
|
19309
19475
|
const dirs = [];
|
|
19310
19476
|
if (entry.includes("*")) {
|
|
19311
19477
|
const base = entry.replace(/\/\*+$/, "");
|
|
19312
|
-
const baseDir =
|
|
19478
|
+
const baseDir = path33.resolve(projectRoot, base);
|
|
19313
19479
|
try {
|
|
19314
|
-
const children =
|
|
19480
|
+
const children = fs27.readdirSync(baseDir, { withFileTypes: true });
|
|
19315
19481
|
for (const child of children) {
|
|
19316
19482
|
if (child.isDirectory()) {
|
|
19317
|
-
dirs.push(
|
|
19483
|
+
dirs.push(path33.join(baseDir, child.name));
|
|
19318
19484
|
}
|
|
19319
19485
|
}
|
|
19320
19486
|
} catch {
|
|
19321
19487
|
}
|
|
19322
19488
|
} else {
|
|
19323
|
-
dirs.push(
|
|
19489
|
+
dirs.push(path33.resolve(projectRoot, entry));
|
|
19324
19490
|
}
|
|
19325
19491
|
return dirs;
|
|
19326
19492
|
}
|
|
@@ -19337,10 +19503,10 @@ function extractWorkspaceGlobs(pkg, projectRoot) {
|
|
|
19337
19503
|
return dirs;
|
|
19338
19504
|
}
|
|
19339
19505
|
function extractPnpmWorkspaceDirs(projectRoot) {
|
|
19340
|
-
const yamlPath =
|
|
19341
|
-
if (!
|
|
19506
|
+
const yamlPath = path33.join(projectRoot, "pnpm-workspace.yaml");
|
|
19507
|
+
if (!fs27.existsSync(yamlPath)) return [];
|
|
19342
19508
|
try {
|
|
19343
|
-
const content =
|
|
19509
|
+
const content = fs27.readFileSync(yamlPath, "utf8");
|
|
19344
19510
|
const dirs = [];
|
|
19345
19511
|
let inPackages = false;
|
|
19346
19512
|
const lines = content.split("\n");
|
|
@@ -19374,8 +19540,8 @@ function extractPnpmWorkspaceDirs(projectRoot) {
|
|
|
19374
19540
|
}
|
|
19375
19541
|
function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
|
|
19376
19542
|
if (!moduleSpecifier.startsWith(".")) return [];
|
|
19377
|
-
const dir =
|
|
19378
|
-
const base =
|
|
19543
|
+
const dir = path33.dirname(importerPath);
|
|
19544
|
+
const base = path33.resolve(dir, moduleSpecifier);
|
|
19379
19545
|
const results = [];
|
|
19380
19546
|
const stripped = base.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
19381
19547
|
const skipBase = stripped !== base && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(base);
|
|
@@ -19387,18 +19553,18 @@ function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
|
|
|
19387
19553
|
if (indexedFiles.has(candidate + ".jsx")) results.push(candidate + ".jsx");
|
|
19388
19554
|
if (indexedFiles.has(candidate + ".mjs")) results.push(candidate + ".mjs");
|
|
19389
19555
|
if (indexedFiles.has(candidate + ".cjs")) results.push(candidate + ".cjs");
|
|
19390
|
-
if (indexedFiles.has(
|
|
19391
|
-
results.push(
|
|
19392
|
-
if (indexedFiles.has(
|
|
19393
|
-
results.push(
|
|
19394
|
-
if (indexedFiles.has(
|
|
19395
|
-
results.push(
|
|
19396
|
-
if (indexedFiles.has(
|
|
19397
|
-
results.push(
|
|
19398
|
-
if (indexedFiles.has(
|
|
19399
|
-
results.push(
|
|
19400
|
-
if (indexedFiles.has(
|
|
19401
|
-
results.push(
|
|
19556
|
+
if (indexedFiles.has(path33.join(candidate, "index.ts")))
|
|
19557
|
+
results.push(path33.join(candidate, "index.ts"));
|
|
19558
|
+
if (indexedFiles.has(path33.join(candidate, "index.tsx")))
|
|
19559
|
+
results.push(path33.join(candidate, "index.tsx"));
|
|
19560
|
+
if (indexedFiles.has(path33.join(candidate, "index.js")))
|
|
19561
|
+
results.push(path33.join(candidate, "index.js"));
|
|
19562
|
+
if (indexedFiles.has(path33.join(candidate, "index.jsx")))
|
|
19563
|
+
results.push(path33.join(candidate, "index.jsx"));
|
|
19564
|
+
if (indexedFiles.has(path33.join(candidate, "index.mjs")))
|
|
19565
|
+
results.push(path33.join(candidate, "index.mjs"));
|
|
19566
|
+
if (indexedFiles.has(path33.join(candidate, "index.cjs")))
|
|
19567
|
+
results.push(path33.join(candidate, "index.cjs"));
|
|
19402
19568
|
}
|
|
19403
19569
|
return [...new Set(results)];
|
|
19404
19570
|
}
|
|
@@ -19430,7 +19596,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
19430
19596
|
symbolById.set(s.id, s);
|
|
19431
19597
|
}
|
|
19432
19598
|
const discoveredFiles = discoverEntryPoints(projectRoot, opts.userEntryPoints);
|
|
19433
|
-
const entryFileSet = new Set(discoveredFiles.map((f) =>
|
|
19599
|
+
const entryFileSet = new Set(discoveredFiles.map((f) => path33.resolve(f)));
|
|
19434
19600
|
const indexedFiles = /* @__PURE__ */ new Set();
|
|
19435
19601
|
for (const s of allSymbols) indexedFiles.add(s.file);
|
|
19436
19602
|
for (const fm of store.getAllFileMetas()) indexedFiles.add(fm.file);
|
|
@@ -19456,7 +19622,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
19456
19622
|
if (scannedBarrels.has(epFile)) continue;
|
|
19457
19623
|
scannedBarrels.add(epFile);
|
|
19458
19624
|
try {
|
|
19459
|
-
const content =
|
|
19625
|
+
const content = fs27.readFileSync(epFile, "utf8");
|
|
19460
19626
|
const strippedContent = content.replace(/\/\*[\s\S]*?\*\//g, (m) => " ".repeat(m.length)).replace(/\/\/[^\n]*/g, (m) => " ".repeat(m.length));
|
|
19461
19627
|
const reExportRe = /export\s+(?:(?:type\s+)?\{[\s\S]*?\}\s+from|\*\s+as\s+\w+\s+from|\*\s+from)\s+['"]([^'"]+)['"]/g;
|
|
19462
19628
|
for (; ; ) {
|
|
@@ -19546,7 +19712,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
19546
19712
|
const deadPackages = [];
|
|
19547
19713
|
const pkgEntries = findPackageEntries(projectRoot);
|
|
19548
19714
|
for (const [pkgName, pkgDir] of pkgEntries) {
|
|
19549
|
-
const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir +
|
|
19715
|
+
const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path33.sep));
|
|
19550
19716
|
if (pkgFiles.length === 0) continue;
|
|
19551
19717
|
const pkgUsed = pkgFiles.filter((s) => alive.has(s.id));
|
|
19552
19718
|
if (pkgUsed.length === 0) {
|
|
@@ -19582,7 +19748,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
19582
19748
|
}
|
|
19583
19749
|
function findPackageEntries(projectRoot) {
|
|
19584
19750
|
const pkgMap = /* @__PURE__ */ new Map();
|
|
19585
|
-
const rootPkg = tryReadJson(
|
|
19751
|
+
const rootPkg = tryReadJson(path33.join(projectRoot, "package.json"));
|
|
19586
19752
|
if (rootPkg && typeof rootPkg.name === "string") {
|
|
19587
19753
|
pkgMap.set(rootPkg.name, projectRoot);
|
|
19588
19754
|
}
|
|
@@ -19592,7 +19758,7 @@ function findPackageEntries(projectRoot) {
|
|
|
19592
19758
|
wsDirs = extractPnpmWorkspaceDirs(projectRoot);
|
|
19593
19759
|
}
|
|
19594
19760
|
for (const wsDir of wsDirs) {
|
|
19595
|
-
const wsPkg = tryReadJson(
|
|
19761
|
+
const wsPkg = tryReadJson(path33.join(wsDir, "package.json"));
|
|
19596
19762
|
if (wsPkg && typeof wsPkg.name === "string") {
|
|
19597
19763
|
pkgMap.set(wsPkg.name, wsDir);
|
|
19598
19764
|
}
|
|
@@ -19602,7 +19768,7 @@ function findPackageEntries(projectRoot) {
|
|
|
19602
19768
|
}
|
|
19603
19769
|
|
|
19604
19770
|
// src/clarify.ts
|
|
19605
|
-
import { toErrorMessage as
|
|
19771
|
+
import { toErrorMessage as toErrorMessage12 } from "@wrongstack/core/utils";
|
|
19606
19772
|
var clarifyTool = {
|
|
19607
19773
|
name: "clarify",
|
|
19608
19774
|
category: "Meta",
|
|
@@ -19675,15 +19841,15 @@ var clarifyTool = {
|
|
|
19675
19841
|
question: input.question ?? "",
|
|
19676
19842
|
selectedOptions: [],
|
|
19677
19843
|
decisionSummary: "",
|
|
19678
|
-
error:
|
|
19844
|
+
error: toErrorMessage12(err)
|
|
19679
19845
|
};
|
|
19680
19846
|
}
|
|
19681
19847
|
}
|
|
19682
19848
|
};
|
|
19683
19849
|
|
|
19684
19850
|
// src/design.ts
|
|
19685
|
-
import * as
|
|
19686
|
-
import * as
|
|
19851
|
+
import * as fs28 from "node:fs/promises";
|
|
19852
|
+
import * as path34 from "node:path";
|
|
19687
19853
|
import {
|
|
19688
19854
|
applyTokenOverrides,
|
|
19689
19855
|
getDesignKitLoader,
|
|
@@ -19698,17 +19864,17 @@ import {
|
|
|
19698
19864
|
setDesignOverrides
|
|
19699
19865
|
} from "@wrongstack/core/design";
|
|
19700
19866
|
async function resolveReal(p) {
|
|
19701
|
-
const resolved =
|
|
19867
|
+
const resolved = path34.resolve(p);
|
|
19702
19868
|
let probe = resolved;
|
|
19703
19869
|
const missing = [];
|
|
19704
19870
|
for (; ; ) {
|
|
19705
19871
|
try {
|
|
19706
|
-
return
|
|
19872
|
+
return path34.resolve(await fs28.realpath(probe), ...missing);
|
|
19707
19873
|
} catch (err) {
|
|
19708
19874
|
if (err.code === "ENOENT") {
|
|
19709
|
-
const parent =
|
|
19875
|
+
const parent = path34.dirname(probe);
|
|
19710
19876
|
if (parent === probe) return resolved;
|
|
19711
|
-
missing.unshift(
|
|
19877
|
+
missing.unshift(path34.basename(probe));
|
|
19712
19878
|
probe = parent;
|
|
19713
19879
|
continue;
|
|
19714
19880
|
}
|
|
@@ -19909,16 +20075,16 @@ Run \`design {action:"materialize"}\` to write the tuned tokens to your theme fi
|
|
|
19909
20075
|
outPath: input.out
|
|
19910
20076
|
});
|
|
19911
20077
|
const root = await resolveReal(ctx.projectRoot);
|
|
19912
|
-
const absResolved =
|
|
19913
|
-
const absParent = await resolveReal(
|
|
19914
|
-
const abs =
|
|
19915
|
-
const rel =
|
|
19916
|
-
if (rel.startsWith("..") ||
|
|
20078
|
+
const absResolved = path34.isAbsolute(result.path) ? path34.resolve(result.path) : path34.resolve(path34.join(ctx.projectRoot, result.path));
|
|
20079
|
+
const absParent = await resolveReal(path34.dirname(absResolved));
|
|
20080
|
+
const abs = path34.join(absParent, path34.basename(absResolved));
|
|
20081
|
+
const rel = path34.relative(root, abs);
|
|
20082
|
+
if (rel.startsWith("..") || path34.isAbsolute(rel)) {
|
|
19917
20083
|
throw new Error(`design: materialize path "${result.path}" would escape the project root`);
|
|
19918
20084
|
}
|
|
19919
20085
|
let exists = false;
|
|
19920
20086
|
try {
|
|
19921
|
-
await
|
|
20087
|
+
await fs28.access(abs);
|
|
19922
20088
|
exists = true;
|
|
19923
20089
|
} catch {
|
|
19924
20090
|
}
|
|
@@ -19935,8 +20101,8 @@ ${result.content}
|
|
|
19935
20101
|
\`\`\``
|
|
19936
20102
|
};
|
|
19937
20103
|
}
|
|
19938
|
-
await
|
|
19939
|
-
await
|
|
20104
|
+
await fs28.mkdir(path34.dirname(abs), { recursive: true });
|
|
20105
|
+
await fs28.writeFile(abs, result.content);
|
|
19940
20106
|
return {
|
|
19941
20107
|
action,
|
|
19942
20108
|
kit: active.kit,
|
|
@@ -19986,8 +20152,8 @@ Replace off-palette colors with kit tokens (or the materialized CSS vars / token
|
|
|
19986
20152
|
init_util();
|
|
19987
20153
|
import { spawn as spawn7 } from "node:child_process";
|
|
19988
20154
|
import { statSync as statSync3 } from "node:fs";
|
|
19989
|
-
import * as
|
|
19990
|
-
import * as
|
|
20155
|
+
import * as fs29 from "node:fs/promises";
|
|
20156
|
+
import * as path35 from "node:path";
|
|
19991
20157
|
import { buildChildEnv as buildChildEnv3 } from "@wrongstack/core/utils";
|
|
19992
20158
|
import { ToolValidationError as ToolValidationError2 } from "@wrongstack/core/types";
|
|
19993
20159
|
var MAX_FILE_DUMP_BYTES = 5 * 1024 * 1024;
|
|
@@ -20102,18 +20268,18 @@ function findGitDir(cwd) {
|
|
|
20102
20268
|
let dir = cwd;
|
|
20103
20269
|
for (let i = 0; i < 20; i++) {
|
|
20104
20270
|
try {
|
|
20105
|
-
const stat22 = statSync3(
|
|
20271
|
+
const stat22 = statSync3(path35.join(dir, ".git"));
|
|
20106
20272
|
if (stat22.isDirectory()) return dir;
|
|
20107
20273
|
} catch {
|
|
20108
20274
|
}
|
|
20109
|
-
const parent =
|
|
20275
|
+
const parent = path35.dirname(dir);
|
|
20110
20276
|
if (parent === dir) break;
|
|
20111
20277
|
dir = parent;
|
|
20112
20278
|
}
|
|
20113
20279
|
return null;
|
|
20114
20280
|
}
|
|
20115
20281
|
function runGit(args, cwd, signal) {
|
|
20116
|
-
return new Promise((
|
|
20282
|
+
return new Promise((resolve24) => {
|
|
20117
20283
|
let stdout = "";
|
|
20118
20284
|
let stderr = "";
|
|
20119
20285
|
const child = spawn7("git", args, {
|
|
@@ -20129,8 +20295,8 @@ function runGit(args, cwd, signal) {
|
|
|
20129
20295
|
child.stderr?.on("data", (c) => {
|
|
20130
20296
|
stderr += c.toString();
|
|
20131
20297
|
});
|
|
20132
|
-
child.on("close", (code) =>
|
|
20133
|
-
child.on("error", (e) =>
|
|
20298
|
+
child.on("close", (code) => resolve24({ stdout, stderr, exitCode: code ?? 0 }));
|
|
20299
|
+
child.on("error", (e) => resolve24({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
20134
20300
|
});
|
|
20135
20301
|
}
|
|
20136
20302
|
async function fileDiff(input, ctx, _signal) {
|
|
@@ -20148,7 +20314,7 @@ async function fileDiff(input, ctx, _signal) {
|
|
|
20148
20314
|
let truncated = false;
|
|
20149
20315
|
for (const file of files) {
|
|
20150
20316
|
const absPath = await safeResolveReal(file, ctx);
|
|
20151
|
-
const stat22 = await
|
|
20317
|
+
const stat22 = await fs29.stat(absPath).catch(() => null);
|
|
20152
20318
|
if (!stat22?.isFile()) continue;
|
|
20153
20319
|
if (stat22.size > MAX_FILE_DUMP_BYTES) {
|
|
20154
20320
|
truncated = true;
|
|
@@ -20157,7 +20323,7 @@ async function fileDiff(input, ctx, _signal) {
|
|
|
20157
20323
|
);
|
|
20158
20324
|
continue;
|
|
20159
20325
|
}
|
|
20160
|
-
const content = await
|
|
20326
|
+
const content = await fs29.readFile(absPath, "utf8");
|
|
20161
20327
|
const lines = content.split(/\r?\n/);
|
|
20162
20328
|
results.push(formatWithLineNumbers(file, lines));
|
|
20163
20329
|
}
|
|
@@ -20180,8 +20346,8 @@ ${numbered}`;
|
|
|
20180
20346
|
|
|
20181
20347
|
// src/document.ts
|
|
20182
20348
|
init_util();
|
|
20183
|
-
import * as
|
|
20184
|
-
import * as
|
|
20349
|
+
import * as fs30 from "node:fs/promises";
|
|
20350
|
+
import * as path36 from "node:path";
|
|
20185
20351
|
var documentTool = {
|
|
20186
20352
|
name: "document",
|
|
20187
20353
|
category: "Project",
|
|
@@ -20229,7 +20395,7 @@ var documentTool = {
|
|
|
20229
20395
|
) : input.path ? [await safeResolveReal(input.path, ctx)] : [];
|
|
20230
20396
|
for (const absPath of fileList) {
|
|
20231
20397
|
try {
|
|
20232
|
-
const content = await
|
|
20398
|
+
const content = await fs30.readFile(absPath, "utf8");
|
|
20233
20399
|
filesProcessed++;
|
|
20234
20400
|
const processed = processFile(
|
|
20235
20401
|
content,
|
|
@@ -20267,12 +20433,12 @@ async function resolveFiles(filesInput, cwd, ctx) {
|
|
|
20267
20433
|
if (!entry) continue;
|
|
20268
20434
|
let absPath;
|
|
20269
20435
|
try {
|
|
20270
|
-
absPath = ensureInsideRoot(
|
|
20436
|
+
absPath = ensureInsideRoot(path36.resolve(cwd, entry), ctx);
|
|
20271
20437
|
} catch {
|
|
20272
20438
|
continue;
|
|
20273
20439
|
}
|
|
20274
20440
|
try {
|
|
20275
|
-
const stat22 = await
|
|
20441
|
+
const stat22 = await fs30.stat(absPath);
|
|
20276
20442
|
if (stat22.isFile()) resolved.push(absPath);
|
|
20277
20443
|
} catch {
|
|
20278
20444
|
}
|
|
@@ -20343,7 +20509,7 @@ function processFile(content, absPath, _style, _overwrite, target) {
|
|
|
20343
20509
|
// src/e2e.ts
|
|
20344
20510
|
init_util();
|
|
20345
20511
|
import { open, readdir as readdir9 } from "node:fs/promises";
|
|
20346
|
-
import * as
|
|
20512
|
+
import * as path37 from "node:path";
|
|
20347
20513
|
async function readBoundedText(filePath, maxBytes) {
|
|
20348
20514
|
let handle;
|
|
20349
20515
|
try {
|
|
@@ -20393,8 +20559,8 @@ var MAX_PACKAGE_BYTES = 512 * 1024;
|
|
|
20393
20559
|
var MAX_CONFIG_BYTES = 512 * 1024;
|
|
20394
20560
|
var MAX_SPEC_SAMPLES = 20;
|
|
20395
20561
|
function relativePath(root, target) {
|
|
20396
|
-
const value =
|
|
20397
|
-
return value.split(
|
|
20562
|
+
const value = path37.relative(root, target) || ".";
|
|
20563
|
+
return value.split(path37.sep).join("/");
|
|
20398
20564
|
}
|
|
20399
20565
|
function escapeRegExp(value) {
|
|
20400
20566
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -20466,7 +20632,7 @@ async function scanWorkspace(root, maxDepth, signal) {
|
|
|
20466
20632
|
}
|
|
20467
20633
|
for (const entry of entries) {
|
|
20468
20634
|
signal.throwIfAborted();
|
|
20469
|
-
const absolutePath =
|
|
20635
|
+
const absolutePath = path37.join(current.directory, entry.name);
|
|
20470
20636
|
if (entry.isFile()) {
|
|
20471
20637
|
if (entry.name === "package.json") result.packageFiles.push(absolutePath);
|
|
20472
20638
|
const framework = CONFIG_NAMES.get(entry.name);
|
|
@@ -20527,9 +20693,9 @@ async function detectPackageManager3(projectRoot, scanRoot, declared) {
|
|
|
20527
20693
|
if (names.has("bun.lock") || names.has("bun.lockb")) return "bun";
|
|
20528
20694
|
if (names.has("package-lock.json") || names.has("npm-shrinkwrap.json")) return "npm";
|
|
20529
20695
|
if (directory === scanRoot) break;
|
|
20530
|
-
const parent =
|
|
20531
|
-
const relativeParent =
|
|
20532
|
-
if (parent === directory || relativeParent.startsWith("..") ||
|
|
20696
|
+
const parent = path37.dirname(directory);
|
|
20697
|
+
const relativeParent = path37.relative(scanRoot, parent);
|
|
20698
|
+
if (parent === directory || relativeParent.startsWith("..") || path37.isAbsolute(relativeParent)) {
|
|
20533
20699
|
break;
|
|
20534
20700
|
}
|
|
20535
20701
|
directory = parent;
|
|
@@ -20574,7 +20740,7 @@ function isSpec(framework, filename) {
|
|
|
20574
20740
|
return /\.(?:spec|test)\.(?:[cm]?[jt]sx?)$/i.test(filename);
|
|
20575
20741
|
}
|
|
20576
20742
|
async function collectSpecs(root, framework, testDirectory, signal) {
|
|
20577
|
-
const roots = testDirectory ? [
|
|
20743
|
+
const roots = testDirectory ? [path37.resolve(root, testDirectory)] : framework === "cypress" ? [path37.join(root, "cypress", "e2e"), path37.join(root, "cypress", "integration")] : [path37.join(root, "tests")];
|
|
20578
20744
|
const samples = [];
|
|
20579
20745
|
let count = 0;
|
|
20580
20746
|
let scanned = 0;
|
|
@@ -20593,7 +20759,7 @@ async function collectSpecs(root, framework, testDirectory, signal) {
|
|
|
20593
20759
|
}
|
|
20594
20760
|
for (const entry of entries) {
|
|
20595
20761
|
signal.throwIfAborted();
|
|
20596
|
-
const target =
|
|
20762
|
+
const target = path37.join(directory, entry.name);
|
|
20597
20763
|
if (entry.isDirectory() && !SKIP_DIRECTORIES.has(entry.name)) queue.push(target);
|
|
20598
20764
|
else if (entry.isFile() && isSpec(framework, entry.name)) {
|
|
20599
20765
|
count += 1;
|
|
@@ -20613,7 +20779,7 @@ function nearestPackage(projectRoot, packagesByDirectory, scanRoot) {
|
|
|
20613
20779
|
const found = packagesByDirectory.get(directory);
|
|
20614
20780
|
if (found) return found;
|
|
20615
20781
|
if (directory === scanRoot) return void 0;
|
|
20616
|
-
const parent =
|
|
20782
|
+
const parent = path37.dirname(directory);
|
|
20617
20783
|
if (parent === directory || relativePath(scanRoot, parent).startsWith("..")) return void 0;
|
|
20618
20784
|
directory = parent;
|
|
20619
20785
|
}
|
|
@@ -20624,13 +20790,13 @@ async function discoverE2EProjects(root, options) {
|
|
|
20624
20790
|
const packages = (await Promise.all(scan.packageFiles.map(readPackageInfo))).filter(
|
|
20625
20791
|
(info) => Boolean(info)
|
|
20626
20792
|
);
|
|
20627
|
-
const packagesByDirectory = new Map(packages.map((info) => [
|
|
20793
|
+
const packagesByDirectory = new Map(packages.map((info) => [path37.dirname(info.path), info]));
|
|
20628
20794
|
const candidates = /* @__PURE__ */ new Map();
|
|
20629
20795
|
for (const config of scan.configs) {
|
|
20630
20796
|
if (options.framework && options.framework !== "all" && config.framework !== options.framework) {
|
|
20631
20797
|
continue;
|
|
20632
20798
|
}
|
|
20633
|
-
const projectRoot =
|
|
20799
|
+
const projectRoot = path37.dirname(config.absolutePath);
|
|
20634
20800
|
candidates.set(`${config.framework}:${projectRoot}`, {
|
|
20635
20801
|
framework: config.framework,
|
|
20636
20802
|
root: projectRoot,
|
|
@@ -20638,7 +20804,7 @@ async function discoverE2EProjects(root, options) {
|
|
|
20638
20804
|
});
|
|
20639
20805
|
}
|
|
20640
20806
|
for (const info of packages) {
|
|
20641
|
-
const projectRoot =
|
|
20807
|
+
const projectRoot = path37.dirname(info.path);
|
|
20642
20808
|
for (const framework of frameworkFromPackage(info)) {
|
|
20643
20809
|
if (options.framework && options.framework !== "all" && framework !== options.framework)
|
|
20644
20810
|
continue;
|
|
@@ -20654,10 +20820,10 @@ async function discoverE2EProjects(root, options) {
|
|
|
20654
20820
|
const scripts = matchingScripts(info, candidate.framework);
|
|
20655
20821
|
const manager = await detectPackageManager3(candidate.root, root, info?.packageManager);
|
|
20656
20822
|
const testDirectory = candidate.framework === "playwright" ? staticString(source, "testDir") : void 0;
|
|
20657
|
-
const resolvedTestDirectory = testDirectory ?
|
|
20658
|
-
const relativeTestDirectory = resolvedTestDirectory ?
|
|
20823
|
+
const resolvedTestDirectory = testDirectory ? path37.resolve(candidate.root, testDirectory) : void 0;
|
|
20824
|
+
const relativeTestDirectory = resolvedTestDirectory ? path37.relative(root, resolvedTestDirectory) : void 0;
|
|
20659
20825
|
const unsafeTestDirectory = Boolean(
|
|
20660
|
-
relativeTestDirectory && (relativeTestDirectory.startsWith("..") ||
|
|
20826
|
+
relativeTestDirectory && (relativeTestDirectory.startsWith("..") || path37.isAbsolute(relativeTestDirectory))
|
|
20661
20827
|
);
|
|
20662
20828
|
const specs = options.includeSpecs === false || unsafeTestDirectory ? { count: 0, samples: [], truncated: false } : await collectSpecs(candidate.root, candidate.framework, testDirectory, options.signal);
|
|
20663
20829
|
const warnings = [];
|
|
@@ -20757,7 +20923,7 @@ var e2ePlanTool = {
|
|
|
20757
20923
|
};
|
|
20758
20924
|
|
|
20759
20925
|
// src/edit.ts
|
|
20760
|
-
import * as
|
|
20926
|
+
import * as fs31 from "node:fs/promises";
|
|
20761
20927
|
import {
|
|
20762
20928
|
atomicWrite as atomicWrite3,
|
|
20763
20929
|
detectNewlineStyle,
|
|
@@ -20981,7 +21147,7 @@ function prefixSimilarity(a, b) {
|
|
|
20981
21147
|
}
|
|
20982
21148
|
|
|
20983
21149
|
// src/_syntax-check.ts
|
|
20984
|
-
import * as
|
|
21150
|
+
import * as path38 from "node:path";
|
|
20985
21151
|
var TS_LIKE = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
20986
21152
|
var MAX_CHECK_CHARS = 15e5;
|
|
20987
21153
|
var MAX_ERRORS = 5;
|
|
@@ -21005,15 +21171,15 @@ async function checkSyntax(filePath, content, previousContent) {
|
|
|
21005
21171
|
return { errors, preExisting };
|
|
21006
21172
|
}
|
|
21007
21173
|
function isJsoncFile(filePath) {
|
|
21008
|
-
const base =
|
|
21174
|
+
const base = path38.basename(filePath).toLowerCase();
|
|
21009
21175
|
if (base.endsWith(".jsonc")) return true;
|
|
21010
21176
|
if (/^(tsconfig|jsconfig)([.-].*)?\.json$/.test(base)) return true;
|
|
21011
|
-
const dir =
|
|
21177
|
+
const dir = path38.basename(path38.dirname(filePath)).toLowerCase();
|
|
21012
21178
|
return dir === ".vscode";
|
|
21013
21179
|
}
|
|
21014
21180
|
async function parseErrors(filePath, content) {
|
|
21015
21181
|
if (content.length > MAX_CHECK_CHARS) return void 0;
|
|
21016
|
-
const ext =
|
|
21182
|
+
const ext = path38.extname(filePath).toLowerCase();
|
|
21017
21183
|
if (ext === ".json" || ext === ".jsonc") {
|
|
21018
21184
|
try {
|
|
21019
21185
|
JSON.parse(content);
|
|
@@ -21040,7 +21206,7 @@ async function parseErrors(filePath, content) {
|
|
|
21040
21206
|
ts2.ScriptKind.JSX
|
|
21041
21207
|
);
|
|
21042
21208
|
const sourceFile = ts2.createSourceFile(
|
|
21043
|
-
|
|
21209
|
+
path38.basename(filePath),
|
|
21044
21210
|
content,
|
|
21045
21211
|
ts2.ScriptTarget.Latest,
|
|
21046
21212
|
/* setParentNodes */
|
|
@@ -21131,7 +21297,7 @@ var editTool = {
|
|
|
21131
21297
|
});
|
|
21132
21298
|
}
|
|
21133
21299
|
const absPath = await safeResolveReal(input.path, ctx);
|
|
21134
|
-
const stat22 = await
|
|
21300
|
+
const stat22 = await fs31.stat(absPath).catch((err) => {
|
|
21135
21301
|
if (err.code === "ENOENT") {
|
|
21136
21302
|
throw new ToolValidationError3({
|
|
21137
21303
|
message: `edit: file "${input.path}" does not exist. Use \`write\` instead.`,
|
|
@@ -21148,8 +21314,8 @@ var editTool = {
|
|
|
21148
21314
|
});
|
|
21149
21315
|
}
|
|
21150
21316
|
const autoRead = !ctx.hasRead(absPath);
|
|
21151
|
-
const original = await
|
|
21152
|
-
const updated = await
|
|
21317
|
+
const original = await fs31.readFile(absPath, "utf8");
|
|
21318
|
+
const updated = await fs31.stat(absPath);
|
|
21153
21319
|
const mtimeTolerance = process.platform === "win32" ? 2e3 : 1;
|
|
21154
21320
|
const originalHash = sha256hex(original);
|
|
21155
21321
|
const lastReadHash = ctx.lastReadHash?.(absPath);
|
|
@@ -21257,7 +21423,7 @@ var editTool = {
|
|
|
21257
21423
|
enqueueReindex({ projectRoot: ctx.projectRoot, files: [absPath] });
|
|
21258
21424
|
} catch {
|
|
21259
21425
|
}
|
|
21260
|
-
const written = await
|
|
21426
|
+
const written = await fs31.stat(absPath);
|
|
21261
21427
|
ctx.recordRead(absPath, written.mtimeMs, "write", sha256hex(newFile));
|
|
21262
21428
|
ctx.session.recordFileChange({
|
|
21263
21429
|
path: absPath,
|
|
@@ -21307,14 +21473,14 @@ import {
|
|
|
21307
21473
|
emitProcessOutput as emitProcessOutput3,
|
|
21308
21474
|
emitProcessStarted as emitProcessStarted3
|
|
21309
21475
|
} from "@wrongstack/core/observability";
|
|
21310
|
-
import { toErrorMessage as
|
|
21476
|
+
import { toErrorMessage as toErrorMessage13 } from "@wrongstack/core/utils/error";
|
|
21311
21477
|
init_output_spool();
|
|
21312
21478
|
init_util();
|
|
21313
21479
|
init_win32_resolve();
|
|
21314
21480
|
|
|
21315
21481
|
// src/exec-kill-guard.ts
|
|
21316
21482
|
import * as os8 from "node:os";
|
|
21317
|
-
import * as
|
|
21483
|
+
import * as path39 from "node:path";
|
|
21318
21484
|
var isWin3 = os8.platform() === "win32";
|
|
21319
21485
|
async function checkExecKillCommand(cmd, args) {
|
|
21320
21486
|
if (!cmd) return { blocked: false };
|
|
@@ -21531,7 +21697,7 @@ async function checkKillTarget(target) {
|
|
|
21531
21697
|
reason: `Blocked: kill ${target.signal} '${target.name}' targets a WrongStack process name.`
|
|
21532
21698
|
};
|
|
21533
21699
|
}
|
|
21534
|
-
const currentImage =
|
|
21700
|
+
const currentImage = path39.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
|
|
21535
21701
|
const targetsNodeRuntime = nameLower === "node" || nameLower.startsWith("node");
|
|
21536
21702
|
if (targetsNodeRuntime && currentImage === "node") {
|
|
21537
21703
|
return {
|
|
@@ -22445,7 +22611,7 @@ var execTool = {
|
|
|
22445
22611
|
}
|
|
22446
22612
|
};
|
|
22447
22613
|
function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
|
|
22448
|
-
return new Promise((
|
|
22614
|
+
return new Promise((resolve24) => {
|
|
22449
22615
|
let stdout = "";
|
|
22450
22616
|
let stderr = "";
|
|
22451
22617
|
let killed = false;
|
|
@@ -22453,7 +22619,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
|
|
|
22453
22619
|
const finish = (result) => {
|
|
22454
22620
|
if (resolvedOnce.value) return;
|
|
22455
22621
|
resolvedOnce.value = true;
|
|
22456
|
-
|
|
22622
|
+
resolve24(result);
|
|
22457
22623
|
};
|
|
22458
22624
|
const startedAt = Date.now();
|
|
22459
22625
|
let stdoutBytes = 0;
|
|
@@ -22505,7 +22671,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
|
|
|
22505
22671
|
command: cmd,
|
|
22506
22672
|
args,
|
|
22507
22673
|
stdout: "",
|
|
22508
|
-
stderr: `spawn failed: ${
|
|
22674
|
+
stderr: `spawn failed: ${toErrorMessage13(err)}`,
|
|
22509
22675
|
exitCode: 1,
|
|
22510
22676
|
truncated: false,
|
|
22511
22677
|
allowed: true,
|
|
@@ -23129,10 +23295,10 @@ function parseFormatterCounts(fixer, output) {
|
|
|
23129
23295
|
};
|
|
23130
23296
|
}
|
|
23131
23297
|
async function detectFixer(cwd) {
|
|
23132
|
-
const
|
|
23298
|
+
const fs44 = await import("node:fs/promises");
|
|
23133
23299
|
const exists = async (file) => {
|
|
23134
23300
|
try {
|
|
23135
|
-
await
|
|
23301
|
+
await fs44.stat(`${cwd}/${file}`);
|
|
23136
23302
|
return true;
|
|
23137
23303
|
} catch {
|
|
23138
23304
|
return false;
|
|
@@ -23155,7 +23321,7 @@ async function detectFixer(cwd) {
|
|
|
23155
23321
|
if (await exists(cfg)) return "prettier";
|
|
23156
23322
|
}
|
|
23157
23323
|
try {
|
|
23158
|
-
const raw = await
|
|
23324
|
+
const raw = await fs44.readFile(`${cwd}/package.json`, "utf8");
|
|
23159
23325
|
const pkg = JSON.parse(raw);
|
|
23160
23326
|
if (pkg["prettier"] !== void 0) return "prettier";
|
|
23161
23327
|
} catch {
|
|
@@ -23167,7 +23333,7 @@ async function detectFixer(cwd) {
|
|
|
23167
23333
|
init_util();
|
|
23168
23334
|
import { spawn as spawn9 } from "node:child_process";
|
|
23169
23335
|
import { statSync as statSync4 } from "node:fs";
|
|
23170
|
-
import { dirname as dirname13, resolve as
|
|
23336
|
+
import { dirname as dirname13, resolve as resolve19, sep as sep6 } from "node:path";
|
|
23171
23337
|
import { assessCommitSafety } from "@wrongstack/core/coordination";
|
|
23172
23338
|
import { buildChildEnv as buildChildEnv4 } from "@wrongstack/core/utils";
|
|
23173
23339
|
var TIMEOUT_MS2 = 3e4;
|
|
@@ -23328,8 +23494,8 @@ function validateWorktreeInput(input, projectRoot) {
|
|
|
23328
23494
|
return reject(`unsafe worktree path: ${input.worktreePath}`);
|
|
23329
23495
|
}
|
|
23330
23496
|
if ((input.worktreeAction === "add" || input.worktreeAction === "remove") && input.worktreePath) {
|
|
23331
|
-
const root =
|
|
23332
|
-
const abs =
|
|
23497
|
+
const root = resolve19(projectRoot);
|
|
23498
|
+
const abs = resolve19(root, input.worktreePath);
|
|
23333
23499
|
if (abs !== root && !abs.startsWith(root + sep6)) {
|
|
23334
23500
|
return reject(`unsafe worktree path (escapes project root): ${input.worktreePath}`);
|
|
23335
23501
|
}
|
|
@@ -23423,7 +23589,7 @@ function buildArgs(input) {
|
|
|
23423
23589
|
}
|
|
23424
23590
|
}
|
|
23425
23591
|
function runGit2(args, cwd, signal) {
|
|
23426
|
-
return new Promise((
|
|
23592
|
+
return new Promise((resolve24) => {
|
|
23427
23593
|
let stdout = "";
|
|
23428
23594
|
let stderr = "";
|
|
23429
23595
|
const child = spawn9("git", args, {
|
|
@@ -23444,7 +23610,7 @@ function runGit2(args, cwd, signal) {
|
|
|
23444
23610
|
}
|
|
23445
23611
|
});
|
|
23446
23612
|
child.on("error", (err) => {
|
|
23447
|
-
|
|
23613
|
+
resolve24({
|
|
23448
23614
|
command: args[0],
|
|
23449
23615
|
stdout: normalizeCommandOutput(stdout),
|
|
23450
23616
|
stderr: err.message,
|
|
@@ -23453,7 +23619,7 @@ function runGit2(args, cwd, signal) {
|
|
|
23453
23619
|
});
|
|
23454
23620
|
});
|
|
23455
23621
|
child.on("close", (code) => {
|
|
23456
|
-
|
|
23622
|
+
resolve24({
|
|
23457
23623
|
command: args[0],
|
|
23458
23624
|
stdout: normalizeCommandOutput(stdout),
|
|
23459
23625
|
stderr: normalizeCommandOutput(stderr),
|
|
@@ -23465,8 +23631,8 @@ function runGit2(args, cwd, signal) {
|
|
|
23465
23631
|
}
|
|
23466
23632
|
|
|
23467
23633
|
// src/glob.ts
|
|
23468
|
-
import * as
|
|
23469
|
-
import * as
|
|
23634
|
+
import * as fs32 from "node:fs/promises";
|
|
23635
|
+
import * as path40 from "node:path";
|
|
23470
23636
|
import { compileGlob as compileGlob2, DEFAULT_WALK_IGNORE_DIRS as DEFAULT_WALK_IGNORE_DIRS2 } from "@wrongstack/core/utils";
|
|
23471
23637
|
import { ToolValidationError as ToolValidationError6 } from "@wrongstack/core/types";
|
|
23472
23638
|
|
|
@@ -23546,7 +23712,7 @@ var globTool = {
|
|
|
23546
23712
|
return;
|
|
23547
23713
|
}
|
|
23548
23714
|
try {
|
|
23549
|
-
const st = await
|
|
23715
|
+
const st = await fs32.stat(full);
|
|
23550
23716
|
if (truncated || results.length >= limit) {
|
|
23551
23717
|
truncated = true;
|
|
23552
23718
|
return;
|
|
@@ -23567,7 +23733,7 @@ var globTool = {
|
|
|
23567
23733
|
}
|
|
23568
23734
|
let entries;
|
|
23569
23735
|
try {
|
|
23570
|
-
entries = await
|
|
23736
|
+
entries = await fs32.readdir(dir, { withFileTypes: true });
|
|
23571
23737
|
} catch {
|
|
23572
23738
|
return;
|
|
23573
23739
|
}
|
|
@@ -23577,7 +23743,7 @@ var globTool = {
|
|
|
23577
23743
|
const name = e.name;
|
|
23578
23744
|
if (DEFAULT_IGNORE2.has(name)) continue;
|
|
23579
23745
|
const rel = relPrefix ? `${relPrefix}/${name}` : name;
|
|
23580
|
-
const full =
|
|
23746
|
+
const full = path40.join(dir, name);
|
|
23581
23747
|
if (e.isDirectory()) {
|
|
23582
23748
|
if (isGitIgnored(rel, true)) continue;
|
|
23583
23749
|
subdirs.push({ full, rel });
|
|
@@ -23592,15 +23758,15 @@ var globTool = {
|
|
|
23592
23758
|
}
|
|
23593
23759
|
} else if (e.isSymbolicLink()) {
|
|
23594
23760
|
try {
|
|
23595
|
-
const st = await
|
|
23761
|
+
const st = await fs32.stat(full);
|
|
23596
23762
|
if (st.isDirectory()) {
|
|
23597
23763
|
if (isGitIgnored(rel, true)) continue;
|
|
23598
|
-
const real = await
|
|
23764
|
+
const real = await fs32.realpath(full);
|
|
23599
23765
|
await assertRealInsideRoot(real, ctx);
|
|
23600
23766
|
subdirs.push({ full, rel });
|
|
23601
23767
|
} else if (st.isFile()) {
|
|
23602
23768
|
if (isGitIgnored(rel, false)) continue;
|
|
23603
|
-
const real = await
|
|
23769
|
+
const real = await fs32.realpath(full);
|
|
23604
23770
|
await assertRealInsideRoot(real, ctx);
|
|
23605
23771
|
re.lastIndex = 0;
|
|
23606
23772
|
const relMatch = re.test(rel);
|
|
@@ -23630,8 +23796,8 @@ var globTool = {
|
|
|
23630
23796
|
|
|
23631
23797
|
// src/grep.ts
|
|
23632
23798
|
import { spawn as spawn10 } from "node:child_process";
|
|
23633
|
-
import * as
|
|
23634
|
-
import * as
|
|
23799
|
+
import * as fs33 from "node:fs/promises";
|
|
23800
|
+
import * as path41 from "node:path";
|
|
23635
23801
|
import { ToolValidationError as ToolValidationError7 } from "@wrongstack/core/types";
|
|
23636
23802
|
import {
|
|
23637
23803
|
buildChildEnv as buildChildEnv5,
|
|
@@ -23866,7 +24032,7 @@ var grepTool = {
|
|
|
23866
24032
|
};
|
|
23867
24033
|
var rgAvailabilityCache;
|
|
23868
24034
|
function detectRg() {
|
|
23869
|
-
rgAvailabilityCache ??= new Promise((
|
|
24035
|
+
rgAvailabilityCache ??= new Promise((resolve24) => {
|
|
23870
24036
|
try {
|
|
23871
24037
|
const p = spawn10("rg", ["--version"], {
|
|
23872
24038
|
env: buildChildEnv5(),
|
|
@@ -23874,10 +24040,10 @@ function detectRg() {
|
|
|
23874
24040
|
signal: AbortSignal.timeout(1e4),
|
|
23875
24041
|
windowsHide: true
|
|
23876
24042
|
});
|
|
23877
|
-
p.on("error", () =>
|
|
23878
|
-
p.on("close", (code) =>
|
|
24043
|
+
p.on("error", () => resolve24(false));
|
|
24044
|
+
p.on("close", (code) => resolve24(code === 0));
|
|
23879
24045
|
} catch {
|
|
23880
|
-
|
|
24046
|
+
resolve24(false);
|
|
23881
24047
|
}
|
|
23882
24048
|
});
|
|
23883
24049
|
return rgAvailabilityCache;
|
|
@@ -23894,8 +24060,8 @@ async function* runRgStream(input, base, mode, limit, signal) {
|
|
|
23894
24060
|
for (const ignored of DEFAULT_IGNORE3) {
|
|
23895
24061
|
args.push("--glob", `!${ignored}/**`, "--glob", `!**/${ignored}/**`);
|
|
23896
24062
|
}
|
|
23897
|
-
const gitignorePath =
|
|
23898
|
-
if (await
|
|
24063
|
+
const gitignorePath = path41.join(base, ".gitignore");
|
|
24064
|
+
if (await fs33.access(gitignorePath).then(
|
|
23899
24065
|
() => true,
|
|
23900
24066
|
() => false
|
|
23901
24067
|
)) {
|
|
@@ -24085,9 +24251,9 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
24085
24251
|
if (globRe && !globRe.test(name) && !globRe.test(full)) return;
|
|
24086
24252
|
if (globRe) globRe.lastIndex = 0;
|
|
24087
24253
|
try {
|
|
24088
|
-
const stat22 = await
|
|
24254
|
+
const stat22 = await fs33.stat(full);
|
|
24089
24255
|
if (!stat22.isFile() || stat22.size > maxBytes || stopped || signal.aborted) return;
|
|
24090
|
-
const file = await
|
|
24256
|
+
const file = await fs33.open(full, "r");
|
|
24091
24257
|
try {
|
|
24092
24258
|
let bytesReadTotal = 0;
|
|
24093
24259
|
let lineNumber = 0;
|
|
@@ -24172,7 +24338,7 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
24172
24338
|
if (stopped || signal.aborted) return;
|
|
24173
24339
|
let entries;
|
|
24174
24340
|
try {
|
|
24175
|
-
entries = await
|
|
24341
|
+
entries = await fs33.readdir(dir, { withFileTypes: true });
|
|
24176
24342
|
} catch {
|
|
24177
24343
|
return;
|
|
24178
24344
|
}
|
|
@@ -24183,7 +24349,7 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
24183
24349
|
if (DEFAULT_IGNORE3.has(e.name)) continue;
|
|
24184
24350
|
if (e.isSymbolicLink()) continue;
|
|
24185
24351
|
const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
|
|
24186
|
-
const full =
|
|
24352
|
+
const full = path41.join(dir, e.name);
|
|
24187
24353
|
if (e.isDirectory()) {
|
|
24188
24354
|
if (isGitIgnored(rel, true)) continue;
|
|
24189
24355
|
subdirs.push({ full, rel });
|
|
@@ -24423,7 +24589,7 @@ function resolveManifestPath(cwd, pkgManager) {
|
|
|
24423
24589
|
}
|
|
24424
24590
|
|
|
24425
24591
|
// src/json.ts
|
|
24426
|
-
import * as
|
|
24592
|
+
import * as fs34 from "node:fs/promises";
|
|
24427
24593
|
import { deepMerge as deepMergeCore } from "@wrongstack/core/utils";
|
|
24428
24594
|
init_util();
|
|
24429
24595
|
var MAX_JSON_FILE_BYTES = 16 * 1024 * 1024;
|
|
@@ -24438,11 +24604,11 @@ var JsonFileTooLargeError = class extends Error {
|
|
|
24438
24604
|
};
|
|
24439
24605
|
async function readJsonFileBounded(filePath, ctx) {
|
|
24440
24606
|
const resolved = await safeResolveReal(filePath, ctx);
|
|
24441
|
-
const stat22 = await
|
|
24607
|
+
const stat22 = await fs34.stat(resolved);
|
|
24442
24608
|
if (stat22.size > MAX_JSON_FILE_BYTES) {
|
|
24443
24609
|
throw new JsonFileTooLargeError(filePath, stat22.size);
|
|
24444
24610
|
}
|
|
24445
|
-
return
|
|
24611
|
+
return fs34.readFile(resolved, "utf8");
|
|
24446
24612
|
}
|
|
24447
24613
|
var jsonTool = {
|
|
24448
24614
|
name: "json",
|
|
@@ -24919,60 +25085,60 @@ function jmespathSearch(data, query) {
|
|
|
24919
25085
|
}
|
|
24920
25086
|
function validateJsonSchema(data, schema) {
|
|
24921
25087
|
const errors = [];
|
|
24922
|
-
function check(value, s,
|
|
25088
|
+
function check(value, s, path50) {
|
|
24923
25089
|
if (s["type"]) {
|
|
24924
25090
|
const expectedType = s["type"];
|
|
24925
25091
|
const actualType = Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
|
|
24926
25092
|
if (expectedType === "integer") {
|
|
24927
|
-
if (!Number.isInteger(value)) errors.push(`${
|
|
25093
|
+
if (!Number.isInteger(value)) errors.push(`${path50}: expected integer, got ${actualType}`);
|
|
24928
25094
|
} else if (expectedType !== actualType) {
|
|
24929
|
-
errors.push(`${
|
|
25095
|
+
errors.push(`${path50}: expected ${expectedType}, got ${actualType}`);
|
|
24930
25096
|
}
|
|
24931
25097
|
}
|
|
24932
25098
|
if (typeof value === "string" && s["format"] === "uri" && value) {
|
|
24933
25099
|
try {
|
|
24934
25100
|
new URL(value);
|
|
24935
25101
|
} catch {
|
|
24936
|
-
errors.push(`${
|
|
25102
|
+
errors.push(`${path50}: not a valid URI`);
|
|
24937
25103
|
}
|
|
24938
25104
|
}
|
|
24939
25105
|
if (typeof value === "string" && s["pattern"]) {
|
|
24940
25106
|
const compiled = compileUserRegex(s["pattern"], "");
|
|
24941
25107
|
if (!compiled.ok) {
|
|
24942
|
-
errors.push(`${
|
|
25108
|
+
errors.push(`${path50}: invalid schema pattern \u2014 ${compiled.reason}`);
|
|
24943
25109
|
} else if (!compiled.regex.test(capSubject(value))) {
|
|
24944
|
-
errors.push(`${
|
|
25110
|
+
errors.push(`${path50}: does not match pattern ${s["pattern"]}`);
|
|
24945
25111
|
}
|
|
24946
25112
|
}
|
|
24947
25113
|
if (typeof value === "string" && s["minLength"] !== void 0 && value.length < s["minLength"]) {
|
|
24948
|
-
errors.push(`${
|
|
25114
|
+
errors.push(`${path50}: string too short (min ${s["minLength"]})`);
|
|
24949
25115
|
}
|
|
24950
25116
|
if (typeof value === "string" && s["maxLength"] !== void 0 && value.length > s["maxLength"]) {
|
|
24951
|
-
errors.push(`${
|
|
25117
|
+
errors.push(`${path50}: string too long (max ${s["maxLength"]})`);
|
|
24952
25118
|
}
|
|
24953
25119
|
if (typeof value === "number" && s["minimum"] !== void 0 && value < s["minimum"]) {
|
|
24954
|
-
errors.push(`${
|
|
25120
|
+
errors.push(`${path50}: below minimum ${s["minimum"]}`);
|
|
24955
25121
|
}
|
|
24956
25122
|
if (typeof value === "number" && s["maximum"] !== void 0 && value > s["maximum"]) {
|
|
24957
|
-
errors.push(`${
|
|
25123
|
+
errors.push(`${path50}: above maximum ${s["maximum"]}`);
|
|
24958
25124
|
}
|
|
24959
25125
|
if (Array.isArray(value) && s["items"] && Array.isArray(s["items"])) {
|
|
24960
25126
|
for (let i = 0; i < value.length; i++) {
|
|
24961
|
-
check(value[i], s["items"], `${
|
|
25127
|
+
check(value[i], s["items"], `${path50}[${i}]`);
|
|
24962
25128
|
}
|
|
24963
25129
|
}
|
|
24964
25130
|
if (typeof value === "object" && value !== null && !Array.isArray(value) && s["properties"]) {
|
|
24965
25131
|
const props = s["properties"];
|
|
24966
25132
|
for (const [k, propSchema] of Object.entries(props)) {
|
|
24967
|
-
check(value[k], propSchema, `${
|
|
25133
|
+
check(value[k], propSchema, `${path50}.${k}`);
|
|
24968
25134
|
}
|
|
24969
25135
|
}
|
|
24970
25136
|
}
|
|
24971
25137
|
check(data, schema, "$");
|
|
24972
25138
|
return { valid: errors.length === 0, errors };
|
|
24973
25139
|
}
|
|
24974
|
-
function simpleQuery(data,
|
|
24975
|
-
const parts =
|
|
25140
|
+
function simpleQuery(data, path50) {
|
|
25141
|
+
const parts = path50.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
24976
25142
|
let current = data;
|
|
24977
25143
|
for (const part of parts) {
|
|
24978
25144
|
if (current === null || current === void 0) return void 0;
|
|
@@ -28084,7 +28250,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
28084
28250
|
};
|
|
28085
28251
|
}
|
|
28086
28252
|
args.push("--timestamps", service);
|
|
28087
|
-
return new Promise((
|
|
28253
|
+
return new Promise((resolve24) => {
|
|
28088
28254
|
let stdout = "";
|
|
28089
28255
|
let stderr = "";
|
|
28090
28256
|
const MAX = 2e5;
|
|
@@ -28100,7 +28266,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
28100
28266
|
if (settled) return;
|
|
28101
28267
|
settled = true;
|
|
28102
28268
|
clearTimeout(timer);
|
|
28103
|
-
|
|
28269
|
+
resolve24(result);
|
|
28104
28270
|
};
|
|
28105
28271
|
const child = spawn11("docker", args, {
|
|
28106
28272
|
cwd,
|
|
@@ -28145,7 +28311,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
28145
28311
|
}
|
|
28146
28312
|
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
28147
28313
|
var MAX_TAIL_LINES = 1e5;
|
|
28148
|
-
async function fileLogs(
|
|
28314
|
+
async function fileLogs(path50, lines, filterRe) {
|
|
28149
28315
|
const { createInterface } = await import("node:readline");
|
|
28150
28316
|
const { createReadStream: createReadStream2 } = await import("node:fs");
|
|
28151
28317
|
const entries = [];
|
|
@@ -28154,7 +28320,7 @@ async function fileLogs(path49, lines, filterRe) {
|
|
|
28154
28320
|
let writeIdx = 0;
|
|
28155
28321
|
let totalLines = 0;
|
|
28156
28322
|
const rl = createInterface({
|
|
28157
|
-
input: createReadStream2(
|
|
28323
|
+
input: createReadStream2(path50),
|
|
28158
28324
|
crlfDelay: Number.POSITIVE_INFINITY
|
|
28159
28325
|
});
|
|
28160
28326
|
for await (const line of rl) {
|
|
@@ -28175,7 +28341,7 @@ async function fileLogs(path49, lines, filterRe) {
|
|
|
28175
28341
|
if (parsed) entries.push(parsed);
|
|
28176
28342
|
}
|
|
28177
28343
|
return {
|
|
28178
|
-
source:
|
|
28344
|
+
source: path50,
|
|
28179
28345
|
entries,
|
|
28180
28346
|
total: entries.length,
|
|
28181
28347
|
truncated: totalLines > effLines,
|
|
@@ -28317,7 +28483,7 @@ var outdatedTool = {
|
|
|
28317
28483
|
}
|
|
28318
28484
|
};
|
|
28319
28485
|
function runOutdated(manager, args, cwd, signal) {
|
|
28320
|
-
return new Promise((
|
|
28486
|
+
return new Promise((resolve24) => {
|
|
28321
28487
|
let stdout = "";
|
|
28322
28488
|
let stderr = "";
|
|
28323
28489
|
const MAX = 1e5;
|
|
@@ -28342,10 +28508,10 @@ function runOutdated(manager, args, cwd, signal) {
|
|
|
28342
28508
|
});
|
|
28343
28509
|
child.on("close", (code) => {
|
|
28344
28510
|
const result = parseOutdatedOutput(stdout, code ?? 0);
|
|
28345
|
-
|
|
28511
|
+
resolve24(result);
|
|
28346
28512
|
});
|
|
28347
28513
|
child.on("error", (e) => {
|
|
28348
|
-
|
|
28514
|
+
resolve24({
|
|
28349
28515
|
exit_code: 1,
|
|
28350
28516
|
packages: [],
|
|
28351
28517
|
total: 0,
|
|
@@ -28405,10 +28571,10 @@ Note: exit code 1 from \`outdated\` means outdated packages were found (expected
|
|
|
28405
28571
|
// src/patch.ts
|
|
28406
28572
|
init_util();
|
|
28407
28573
|
import { spawn as spawn13 } from "node:child_process";
|
|
28408
|
-
import * as
|
|
28574
|
+
import * as fs35 from "node:fs/promises";
|
|
28409
28575
|
import * as os9 from "node:os";
|
|
28410
|
-
import * as
|
|
28411
|
-
import { buildChildEnv as buildChildEnv8, toErrorMessage as
|
|
28576
|
+
import * as path42 from "node:path";
|
|
28577
|
+
import { buildChildEnv as buildChildEnv8, toErrorMessage as toErrorMessage14 } from "@wrongstack/core/utils";
|
|
28412
28578
|
var patchTool = {
|
|
28413
28579
|
name: "patch",
|
|
28414
28580
|
category: "Filesystem",
|
|
@@ -28452,26 +28618,26 @@ var patchTool = {
|
|
|
28452
28618
|
try {
|
|
28453
28619
|
dir = input.directory ? await safeResolveReal(input.directory, ctx) : ctx.cwd;
|
|
28454
28620
|
} catch (err) {
|
|
28455
|
-
return refuse(`patch refused: ${
|
|
28621
|
+
return refuse(`patch refused: ${toErrorMessage14(err)}`);
|
|
28456
28622
|
}
|
|
28457
|
-
const realRoot = await
|
|
28623
|
+
const realRoot = await fs35.realpath(ctx.projectRoot).catch(() => path42.resolve(ctx.projectRoot));
|
|
28458
28624
|
const targets = extractDiffTargets(input.patch);
|
|
28459
28625
|
const resolvedTargets = [];
|
|
28460
28626
|
for (const t of targets) {
|
|
28461
28627
|
const stripped = stripPathComponents(t.raw, strip);
|
|
28462
28628
|
if (!stripped) continue;
|
|
28463
|
-
if (
|
|
28629
|
+
if (path42.isAbsolute(stripped)) {
|
|
28464
28630
|
return refuse(`patch refused: target "${t.raw}" strips to absolute path`);
|
|
28465
28631
|
}
|
|
28466
|
-
const candidate =
|
|
28632
|
+
const candidate = path42.resolve(dir, stripped);
|
|
28467
28633
|
let real;
|
|
28468
28634
|
try {
|
|
28469
28635
|
real = await resolveRealInsideRoot(candidate, ctx);
|
|
28470
28636
|
} catch (err) {
|
|
28471
|
-
return refuse(`patch refused: target "${t.raw}" ${
|
|
28637
|
+
return refuse(`patch refused: target "${t.raw}" ${toErrorMessage14(err)}`);
|
|
28472
28638
|
}
|
|
28473
|
-
const rel =
|
|
28474
|
-
if (rel.startsWith("..") ||
|
|
28639
|
+
const rel = path42.relative(realRoot, real);
|
|
28640
|
+
if (rel.startsWith("..") || path42.isAbsolute(rel)) {
|
|
28475
28641
|
return refuse(`patch refused: target "${t.raw}" resolves outside project root`);
|
|
28476
28642
|
}
|
|
28477
28643
|
resolvedTargets.push({ raw: t.raw, deleted: t.deleted, abs: real });
|
|
@@ -28480,17 +28646,17 @@ var patchTool = {
|
|
|
28480
28646
|
const beforeExisted = /* @__PURE__ */ new Set();
|
|
28481
28647
|
if (!dryRun) {
|
|
28482
28648
|
for (const target of resolvedTargets) {
|
|
28483
|
-
const existed = (await
|
|
28649
|
+
const existed = (await fs35.stat(target.abs).catch(() => null))?.isFile() ?? false;
|
|
28484
28650
|
if (existed) beforeExisted.add(target.abs);
|
|
28485
28651
|
beforeContents.set(target.abs, await readTextForTracking(target.abs));
|
|
28486
28652
|
}
|
|
28487
28653
|
}
|
|
28488
|
-
const tmpDir = await
|
|
28654
|
+
const tmpDir = await fs35.mkdtemp(path42.join(os9.tmpdir(), ".wstack_patch_"));
|
|
28489
28655
|
try {
|
|
28490
|
-
await
|
|
28656
|
+
await fs35.chmod(tmpDir, 448).catch(() => {
|
|
28491
28657
|
});
|
|
28492
|
-
const patchFile =
|
|
28493
|
-
await
|
|
28658
|
+
const patchFile = path42.join(tmpDir, "in.diff");
|
|
28659
|
+
await fs35.writeFile(patchFile, input.patch, { mode: 384 });
|
|
28494
28660
|
const args = [`-p${strip}`, "--merge", ...dryRun ? ["--dry-run"] : [], "-i", patchFile];
|
|
28495
28661
|
const result = await runPatch(args, dir, opts.signal, {
|
|
28496
28662
|
patchFile,
|
|
@@ -28502,7 +28668,7 @@ var patchTool = {
|
|
|
28502
28668
|
for (const target of resolvedTargets) {
|
|
28503
28669
|
const abs = target.abs;
|
|
28504
28670
|
const before = beforeContents.get(abs) ?? null;
|
|
28505
|
-
const stat22 = await
|
|
28671
|
+
const stat22 = await fs35.stat(abs).catch(() => null);
|
|
28506
28672
|
if (!stat22?.isFile()) {
|
|
28507
28673
|
if (beforeExisted.has(abs)) {
|
|
28508
28674
|
touched.push(abs);
|
|
@@ -28535,7 +28701,7 @@ var patchTool = {
|
|
|
28535
28701
|
}
|
|
28536
28702
|
if (result.exitCode !== 0) {
|
|
28537
28703
|
if (!dryRun) {
|
|
28538
|
-
const partial = touched.length > 0 ? ` ${touched.length} file(s) were still modified on disk and have been recorded for rewind: ${touched.map((p) =>
|
|
28704
|
+
const partial = touched.length > 0 ? ` ${touched.length} file(s) were still modified on disk and have been recorded for rewind: ${touched.map((p) => path42.relative(realRoot, p) || p).join(", ")}.` : "";
|
|
28539
28705
|
return {
|
|
28540
28706
|
applied: touched.length,
|
|
28541
28707
|
rejected: 1,
|
|
@@ -28543,7 +28709,7 @@ var patchTool = {
|
|
|
28543
28709
|
// success path (which returns GNU patch's dir-relative names).
|
|
28544
28710
|
// `touched` entries are realpaths from resolveRealInsideRoot, and
|
|
28545
28711
|
// realRoot is also a realpath, so path.relative is like-for-like.
|
|
28546
|
-
files: touched.map((p) =>
|
|
28712
|
+
files: touched.map((p) => path42.relative(realRoot, p) || p),
|
|
28547
28713
|
dry_run: dryRun,
|
|
28548
28714
|
message: `patch failed: ${result.stderr || result.stdout}${partial}`
|
|
28549
28715
|
};
|
|
@@ -28559,7 +28725,7 @@ var patchTool = {
|
|
|
28559
28725
|
}
|
|
28560
28726
|
const patched = result.engine === "git" ? [
|
|
28561
28727
|
...new Set(
|
|
28562
|
-
resolvedTargets.map((target) =>
|
|
28728
|
+
resolvedTargets.map((target) => path42.relative(dir, target.abs) || target.abs)
|
|
28563
28729
|
)
|
|
28564
28730
|
] : extractPatchedFiles(result.stdout);
|
|
28565
28731
|
return {
|
|
@@ -28570,7 +28736,7 @@ var patchTool = {
|
|
|
28570
28736
|
message: result.stdout || "patch applied"
|
|
28571
28737
|
};
|
|
28572
28738
|
} finally {
|
|
28573
|
-
await
|
|
28739
|
+
await fs35.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
28574
28740
|
});
|
|
28575
28741
|
}
|
|
28576
28742
|
}
|
|
@@ -28578,9 +28744,9 @@ var patchTool = {
|
|
|
28578
28744
|
var MAX_TRACKING_BYTES = 5 * 1024 * 1024;
|
|
28579
28745
|
async function readTextForTracking(absPath) {
|
|
28580
28746
|
try {
|
|
28581
|
-
const stat22 = await
|
|
28747
|
+
const stat22 = await fs35.stat(absPath);
|
|
28582
28748
|
if (!stat22.isFile() || stat22.size > MAX_TRACKING_BYTES) return null;
|
|
28583
|
-
const buf = await
|
|
28749
|
+
const buf = await fs35.readFile(absPath);
|
|
28584
28750
|
if (buf.includes(0)) return null;
|
|
28585
28751
|
return buf.toString("utf8");
|
|
28586
28752
|
} catch {
|
|
@@ -28664,7 +28830,7 @@ function runPatch(args, cwd, signal, fallback) {
|
|
|
28664
28830
|
});
|
|
28665
28831
|
}
|
|
28666
28832
|
function runPatchProcess(command, args, cwd, signal) {
|
|
28667
|
-
return new Promise((
|
|
28833
|
+
return new Promise((resolve24) => {
|
|
28668
28834
|
let stdout = "";
|
|
28669
28835
|
let stderr = "";
|
|
28670
28836
|
const env = { ...buildChildEnv8(), LANG: "C", LC_ALL: "C" };
|
|
@@ -28683,11 +28849,11 @@ function runPatchProcess(command, args, cwd, signal) {
|
|
|
28683
28849
|
});
|
|
28684
28850
|
child.on(
|
|
28685
28851
|
"close",
|
|
28686
|
-
(code) =>
|
|
28852
|
+
(code) => resolve24({ exitCode: code ?? 1, stdout, stderr, unavailable: false })
|
|
28687
28853
|
);
|
|
28688
28854
|
child.on(
|
|
28689
28855
|
"error",
|
|
28690
|
-
(e) =>
|
|
28856
|
+
(e) => resolve24({
|
|
28691
28857
|
exitCode: 1,
|
|
28692
28858
|
stdout: "",
|
|
28693
28859
|
stderr: e.message,
|
|
@@ -29478,9 +29644,9 @@ function mkResult(plan, ok, message, todos) {
|
|
|
29478
29644
|
|
|
29479
29645
|
// src/read.ts
|
|
29480
29646
|
init_util();
|
|
29481
|
-
import * as
|
|
29647
|
+
import * as fs36 from "node:fs/promises";
|
|
29482
29648
|
import { FsError, ToolValidationError as ToolValidationError8 } from "@wrongstack/core/types";
|
|
29483
|
-
import { toErrorMessage as
|
|
29649
|
+
import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
|
|
29484
29650
|
var ADVANCED_MODE_META_KEY = "tools.read.advancedMode";
|
|
29485
29651
|
var MAX_BYTES2 = 5 * 1024 * 1024;
|
|
29486
29652
|
var readTool = {
|
|
@@ -29538,7 +29704,7 @@ var readTool = {
|
|
|
29538
29704
|
const shouldIncludeSymbols = input.includeSymbols === true || input.includeSymbols !== false && ctx.meta[ADVANCED_MODE_META_KEY] === true;
|
|
29539
29705
|
let stat22;
|
|
29540
29706
|
try {
|
|
29541
|
-
stat22 = await
|
|
29707
|
+
stat22 = await fs36.stat(absPath);
|
|
29542
29708
|
} catch (err) {
|
|
29543
29709
|
const code = err.code;
|
|
29544
29710
|
if (code === "ENOENT") {
|
|
@@ -29550,7 +29716,7 @@ var readTool = {
|
|
|
29550
29716
|
});
|
|
29551
29717
|
}
|
|
29552
29718
|
throw new FsError({
|
|
29553
|
-
message: `read: failed to stat "${input.path}": ${
|
|
29719
|
+
message: `read: failed to stat "${input.path}": ${toErrorMessage15(err)}`,
|
|
29554
29720
|
code: "FS_READ_FAILED",
|
|
29555
29721
|
path: absPath,
|
|
29556
29722
|
context: { errno: code },
|
|
@@ -29590,7 +29756,7 @@ var readTool = {
|
|
|
29590
29756
|
...symResult2?.symbols ? { symbols: symResult2.symbols } : {}
|
|
29591
29757
|
};
|
|
29592
29758
|
}
|
|
29593
|
-
const buf = await
|
|
29759
|
+
const buf = await fs36.readFile(absPath);
|
|
29594
29760
|
if (isBinaryBuffer(buf)) {
|
|
29595
29761
|
throw new FsError({
|
|
29596
29762
|
message: `read: "${input.path}" appears to be binary`,
|
|
@@ -29757,8 +29923,8 @@ ${interesting.join("\n")}` : "symbols/imports: (none detected)"
|
|
|
29757
29923
|
|
|
29758
29924
|
// src/replace.ts
|
|
29759
29925
|
import { spawn as spawn14 } from "node:child_process";
|
|
29760
|
-
import * as
|
|
29761
|
-
import * as
|
|
29926
|
+
import * as fs37 from "node:fs/promises";
|
|
29927
|
+
import * as path43 from "node:path";
|
|
29762
29928
|
import { ToolValidationError as ToolValidationError9 } from "@wrongstack/core/types";
|
|
29763
29929
|
import {
|
|
29764
29930
|
atomicWrite as atomicWrite4,
|
|
@@ -29841,14 +30007,14 @@ var replaceTool = {
|
|
|
29841
30007
|
const dryRun = input.dry_run ?? true;
|
|
29842
30008
|
const filesInput = Array.isArray(input.files) ? input.files.join(",") : input.files;
|
|
29843
30009
|
const fileList = await resolveFiles2(filesInput, ctx, globRe);
|
|
29844
|
-
const realRoot = await
|
|
30010
|
+
const realRoot = await fs37.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
29845
30011
|
const results = [];
|
|
29846
30012
|
let totalReplacements = 0;
|
|
29847
30013
|
let diffBytesUsed = 0;
|
|
29848
30014
|
let diffsOmitted = 0;
|
|
29849
30015
|
let diffsTruncated = 0;
|
|
29850
30016
|
for (const absPath of fileList) {
|
|
29851
|
-
const lstat2 = await
|
|
30017
|
+
const lstat2 = await fs37.lstat(absPath).catch((err) => {
|
|
29852
30018
|
if (err.code === "ENOENT") return null;
|
|
29853
30019
|
throw err;
|
|
29854
30020
|
});
|
|
@@ -29856,17 +30022,17 @@ var replaceTool = {
|
|
|
29856
30022
|
if (lstat2.isSymbolicLink()) continue;
|
|
29857
30023
|
let realPath;
|
|
29858
30024
|
try {
|
|
29859
|
-
realPath = await
|
|
30025
|
+
realPath = await fs37.realpath(absPath);
|
|
29860
30026
|
} catch {
|
|
29861
30027
|
continue;
|
|
29862
30028
|
}
|
|
29863
|
-
const rel =
|
|
29864
|
-
if (rel.startsWith("..") ||
|
|
29865
|
-
const stat22 = await
|
|
30029
|
+
const rel = path43.relative(realRoot, realPath);
|
|
30030
|
+
if (rel.startsWith("..") || path43.isAbsolute(rel)) continue;
|
|
30031
|
+
const stat22 = await fs37.stat(realPath).catch(() => null);
|
|
29866
30032
|
if (!stat22?.isFile()) continue;
|
|
29867
30033
|
let content;
|
|
29868
30034
|
try {
|
|
29869
|
-
const buf = await
|
|
30035
|
+
const buf = await fs37.readFile(realPath);
|
|
29870
30036
|
if (isBinaryBuffer(buf)) continue;
|
|
29871
30037
|
content = buf.toString("utf8");
|
|
29872
30038
|
} catch {
|
|
@@ -29889,7 +30055,7 @@ var replaceTool = {
|
|
|
29889
30055
|
if (!dryRun) {
|
|
29890
30056
|
const newContent = toStyle2(newContentLf, style);
|
|
29891
30057
|
await atomicWrite4(realPath, newContent, { mode: stat22.mode & 511 });
|
|
29892
|
-
const written = await
|
|
30058
|
+
const written = await fs37.stat(realPath).catch(() => null);
|
|
29893
30059
|
if (written) {
|
|
29894
30060
|
ctx.recordRead?.(realPath, written.mtimeMs, "write", sha256hex(newContent));
|
|
29895
30061
|
}
|
|
@@ -29989,8 +30155,8 @@ async function resolveFiles2(filesInput, ctx, extraGlob) {
|
|
|
29989
30155
|
const resolved = [];
|
|
29990
30156
|
for (const p of parts) {
|
|
29991
30157
|
const absPath = await safeResolveReal(p, ctx);
|
|
29992
|
-
if (extraGlob && !passesExtraGlob(extraGlob,
|
|
29993
|
-
const stat22 = await
|
|
30158
|
+
if (extraGlob && !passesExtraGlob(extraGlob, path43.basename(absPath), absPath)) continue;
|
|
30159
|
+
const stat22 = await fs37.stat(absPath).catch(() => null);
|
|
29994
30160
|
if (stat22?.isFile()) {
|
|
29995
30161
|
resolved.push(absPath);
|
|
29996
30162
|
}
|
|
@@ -30004,7 +30170,7 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
30004
30170
|
const { promise } = spawnRgFind(pattern, base);
|
|
30005
30171
|
const files = await promise;
|
|
30006
30172
|
if (extraGlob) {
|
|
30007
|
-
return files.filter((f) => passesExtraGlob(extraGlob,
|
|
30173
|
+
return files.filter((f) => passesExtraGlob(extraGlob, path43.basename(f), f));
|
|
30008
30174
|
}
|
|
30009
30175
|
return files;
|
|
30010
30176
|
} catch {
|
|
@@ -30014,17 +30180,17 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
30014
30180
|
}
|
|
30015
30181
|
var rgAvailabilityCache2;
|
|
30016
30182
|
function checkRg() {
|
|
30017
|
-
rgAvailabilityCache2 ??= new Promise((
|
|
30183
|
+
rgAvailabilityCache2 ??= new Promise((resolve24) => {
|
|
30018
30184
|
try {
|
|
30019
30185
|
const p = spawn14("rg", ["--version"], {
|
|
30020
30186
|
env: buildChildEnv9(),
|
|
30021
30187
|
stdio: "ignore",
|
|
30022
30188
|
windowsHide: true
|
|
30023
30189
|
});
|
|
30024
|
-
p.on("error", () =>
|
|
30025
|
-
p.on("close", (code) =>
|
|
30190
|
+
p.on("error", () => resolve24(false));
|
|
30191
|
+
p.on("close", (code) => resolve24(code === 0));
|
|
30026
30192
|
} catch {
|
|
30027
|
-
|
|
30193
|
+
resolve24(false);
|
|
30028
30194
|
}
|
|
30029
30195
|
});
|
|
30030
30196
|
return rgAvailabilityCache2;
|
|
@@ -30050,10 +30216,10 @@ function spawnRgFind(pattern, base) {
|
|
|
30050
30216
|
}
|
|
30051
30217
|
});
|
|
30052
30218
|
return {
|
|
30053
|
-
promise: new Promise((
|
|
30219
|
+
promise: new Promise((resolve24, reject) => {
|
|
30054
30220
|
child.on("error", reject);
|
|
30055
30221
|
child.on("close", () => {
|
|
30056
|
-
|
|
30222
|
+
resolve24(buf.split("\n").filter(Boolean));
|
|
30057
30223
|
});
|
|
30058
30224
|
})
|
|
30059
30225
|
};
|
|
@@ -30064,15 +30230,15 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
30064
30230
|
const walk2 = async (dir) => {
|
|
30065
30231
|
let entries;
|
|
30066
30232
|
try {
|
|
30067
|
-
entries = await
|
|
30233
|
+
entries = await fs37.readdir(dir, { withFileTypes: true });
|
|
30068
30234
|
} catch {
|
|
30069
30235
|
return;
|
|
30070
30236
|
}
|
|
30071
30237
|
for (const e of entries) {
|
|
30072
30238
|
if (DEFAULT_IGNORE4.includes(e.name)) continue;
|
|
30073
|
-
const full =
|
|
30239
|
+
const full = path43.join(dir, e.name);
|
|
30074
30240
|
try {
|
|
30075
|
-
const stat22 = await
|
|
30241
|
+
const stat22 = await fs37.lstat(full);
|
|
30076
30242
|
if (stat22.isSymbolicLink()) continue;
|
|
30077
30243
|
} catch {
|
|
30078
30244
|
continue;
|
|
@@ -30096,8 +30262,8 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
30096
30262
|
|
|
30097
30263
|
// src/scaffold.ts
|
|
30098
30264
|
init_util();
|
|
30099
|
-
import * as
|
|
30100
|
-
import * as
|
|
30265
|
+
import * as fs38 from "node:fs/promises";
|
|
30266
|
+
import * as path44 from "node:path";
|
|
30101
30267
|
import { atomicWrite as atomicWrite5 } from "@wrongstack/core/utils";
|
|
30102
30268
|
var BUILT_IN_TEMPLATES = {
|
|
30103
30269
|
"npm-package": {
|
|
@@ -30248,16 +30414,16 @@ async function handleBuiltIn(name, templateFiles, cwd, ctx, dryRun, vars) {
|
|
|
30248
30414
|
let filesCreated = 0;
|
|
30249
30415
|
for (const [filePath, content] of Object.entries(templateFiles)) {
|
|
30250
30416
|
const resolvedPath = substituteVars(filePath, name, vars);
|
|
30251
|
-
const joinedPath =
|
|
30252
|
-
const root =
|
|
30253
|
-
const target =
|
|
30254
|
-
const rel =
|
|
30255
|
-
if (rel.startsWith("..") ||
|
|
30417
|
+
const joinedPath = path44.join(cwd, resolvedPath);
|
|
30418
|
+
const root = path44.resolve(ctx.projectRoot);
|
|
30419
|
+
const target = path44.resolve(joinedPath);
|
|
30420
|
+
const rel = path44.relative(root, target);
|
|
30421
|
+
if (rel.startsWith("..") || path44.isAbsolute(rel)) {
|
|
30256
30422
|
throw new Error(`scaffold: generated path "${resolvedPath}" would escape project root`);
|
|
30257
30423
|
}
|
|
30258
30424
|
const fullPath = target;
|
|
30259
30425
|
if (!dryRun) {
|
|
30260
|
-
await
|
|
30426
|
+
await fs38.mkdir(path44.dirname(fullPath), { recursive: true });
|
|
30261
30427
|
await atomicWrite5(fullPath, substituteVars(content, name, vars));
|
|
30262
30428
|
}
|
|
30263
30429
|
files.push(resolvedPath);
|
|
@@ -30290,7 +30456,7 @@ function substituteVars(content, name, vars) {
|
|
|
30290
30456
|
// src/search.ts
|
|
30291
30457
|
import { FetchError as FetchError3, ToolValidationError as ToolValidationError10 } from "@wrongstack/core/types";
|
|
30292
30458
|
import { expectDefined as expectDefined9 } from "@wrongstack/core/utils";
|
|
30293
|
-
import { toErrorMessage as
|
|
30459
|
+
import { toErrorMessage as toErrorMessage16 } from "@wrongstack/core/utils";
|
|
30294
30460
|
var DEFAULT_NUM = 10;
|
|
30295
30461
|
var MAX_RESULTS = 50;
|
|
30296
30462
|
var MAX_SNIPPET_CHARS = 300;
|
|
@@ -30500,9 +30666,9 @@ async function duckduckgoSearch(query, signal) {
|
|
|
30500
30666
|
return { results: parseDuckDuckGo(html, MAX_RESULTS) };
|
|
30501
30667
|
} catch (err) {
|
|
30502
30668
|
console.log(
|
|
30503
|
-
JSON.stringify({ level: "debug", event: "search_failed", query, error:
|
|
30669
|
+
JSON.stringify({ level: "debug", event: "search_failed", query, error: toErrorMessage16(err) })
|
|
30504
30670
|
);
|
|
30505
|
-
return { results: [], error: `duckduckgo unreachable: ${
|
|
30671
|
+
return { results: [], error: `duckduckgo unreachable: ${toErrorMessage16(err)}` };
|
|
30506
30672
|
}
|
|
30507
30673
|
}
|
|
30508
30674
|
function takeFrom(iter, max) {
|
|
@@ -30568,7 +30734,7 @@ async function googleSearch(query, signal) {
|
|
|
30568
30734
|
const html = await fetchWithTimeout(url, signal, TIMEOUT_MS3).then((r) => r.text());
|
|
30569
30735
|
return { results: parseGoogleResults(html, MAX_RESULTS) };
|
|
30570
30736
|
} catch (err) {
|
|
30571
|
-
return { results: [], error: `google unreachable: ${
|
|
30737
|
+
return { results: [], error: `google unreachable: ${toErrorMessage16(err)}` };
|
|
30572
30738
|
}
|
|
30573
30739
|
}
|
|
30574
30740
|
function parseGoogleResults(html, num) {
|
|
@@ -30605,7 +30771,7 @@ async function bingSearch(query, signal) {
|
|
|
30605
30771
|
const html = await fetchWithTimeout(url, signal, TIMEOUT_MS3).then((r) => r.text());
|
|
30606
30772
|
return { results: parseBingResults(html, MAX_RESULTS) };
|
|
30607
30773
|
} catch (err) {
|
|
30608
|
-
return { results: [], error: `bing unreachable: ${
|
|
30774
|
+
return { results: [], error: `bing unreachable: ${toErrorMessage16(err)}` };
|
|
30609
30775
|
}
|
|
30610
30776
|
}
|
|
30611
30777
|
function parseBingResults(html, num) {
|
|
@@ -30703,9 +30869,9 @@ function decodeHtmlEntities(text) {
|
|
|
30703
30869
|
}
|
|
30704
30870
|
|
|
30705
30871
|
// src/security-ast-scan-tool.ts
|
|
30706
|
-
import * as
|
|
30707
|
-
import * as
|
|
30708
|
-
import { toErrorMessage as
|
|
30872
|
+
import * as fs39 from "node:fs/promises";
|
|
30873
|
+
import * as path45 from "node:path";
|
|
30874
|
+
import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
|
|
30709
30875
|
var SECRET_PATTERNS = [
|
|
30710
30876
|
{ name: "AWS Access Key", regex: /\b(AKIA[0-9A-Z]{16})\b/ },
|
|
30711
30877
|
{ name: "GitHub Token", regex: /\b(gh[pousr]_[A-Za-z0-9_]{36,255})\b/ },
|
|
@@ -30871,9 +31037,9 @@ var securityAstScanTool = {
|
|
|
30871
31037
|
let targetFile = input.file ?? "inline-code.ts";
|
|
30872
31038
|
let content = input.content;
|
|
30873
31039
|
if (!content && input.file) {
|
|
30874
|
-
const absPath =
|
|
30875
|
-
targetFile =
|
|
30876
|
-
content = await
|
|
31040
|
+
const absPath = path45.isAbsolute(input.file) ? input.file : path45.resolve(projectRoot, input.file);
|
|
31041
|
+
targetFile = path45.relative(projectRoot, absPath).replace(/\\/g, "/");
|
|
31042
|
+
content = await fs39.readFile(absPath, "utf8");
|
|
30877
31043
|
}
|
|
30878
31044
|
if (!content) {
|
|
30879
31045
|
return {
|
|
@@ -30914,15 +31080,15 @@ var securityAstScanTool = {
|
|
|
30914
31080
|
warningCount: 0,
|
|
30915
31081
|
findings: [],
|
|
30916
31082
|
summary: "",
|
|
30917
|
-
error:
|
|
31083
|
+
error: toErrorMessage17(err)
|
|
30918
31084
|
};
|
|
30919
31085
|
}
|
|
30920
31086
|
}
|
|
30921
31087
|
};
|
|
30922
31088
|
|
|
30923
31089
|
// src/set-working-dir.ts
|
|
30924
|
-
import * as
|
|
30925
|
-
import { toErrorMessage as
|
|
31090
|
+
import * as fs40 from "node:fs/promises";
|
|
31091
|
+
import { toErrorMessage as toErrorMessage18 } from "@wrongstack/core/utils";
|
|
30926
31092
|
var setWorkingDirTool = {
|
|
30927
31093
|
name: "set_working_dir",
|
|
30928
31094
|
category: "Context",
|
|
@@ -30956,12 +31122,12 @@ var setWorkingDirTool = {
|
|
|
30956
31122
|
} catch (err) {
|
|
30957
31123
|
return {
|
|
30958
31124
|
current: ctx.workingDir,
|
|
30959
|
-
error:
|
|
31125
|
+
error: toErrorMessage18(err)
|
|
30960
31126
|
};
|
|
30961
31127
|
}
|
|
30962
31128
|
let isDirectory = false;
|
|
30963
31129
|
try {
|
|
30964
|
-
isDirectory = (await
|
|
31130
|
+
isDirectory = (await fs40.stat(resolved)).isDirectory();
|
|
30965
31131
|
} catch {
|
|
30966
31132
|
isDirectory = false;
|
|
30967
31133
|
}
|
|
@@ -31496,7 +31662,7 @@ ${formatTaskList2(file.tasks)}` : file.tasks.length > 0 ? formatTaskList2(file.t
|
|
|
31496
31662
|
init_spawn_stream();
|
|
31497
31663
|
init_util();
|
|
31498
31664
|
init_legacy_bridge();
|
|
31499
|
-
import * as
|
|
31665
|
+
import * as path46 from "node:path";
|
|
31500
31666
|
var testTool = {
|
|
31501
31667
|
name: "test",
|
|
31502
31668
|
category: "Code Quality",
|
|
@@ -31603,7 +31769,7 @@ async function detectRunner(cwd) {
|
|
|
31603
31769
|
const candidates = ["vitest.config.ts", "jest.config.js", ".mocharc.json"];
|
|
31604
31770
|
for (const f of candidates) {
|
|
31605
31771
|
try {
|
|
31606
|
-
await stat22(
|
|
31772
|
+
await stat22(path46.join(cwd, f));
|
|
31607
31773
|
if (f.includes("vitest")) return "vitest";
|
|
31608
31774
|
if (f.includes("jest")) return "jest";
|
|
31609
31775
|
if (f.includes("mocha")) return "mocha";
|
|
@@ -31980,8 +32146,8 @@ var toolUseTool = {
|
|
|
31980
32146
|
|
|
31981
32147
|
// src/tree.ts
|
|
31982
32148
|
init_util();
|
|
31983
|
-
import * as
|
|
31984
|
-
import * as
|
|
32149
|
+
import * as fs41 from "node:fs/promises";
|
|
32150
|
+
import * as path47 from "node:path";
|
|
31985
32151
|
import { DEFAULT_WALK_IGNORE_DIRS as DEFAULT_WALK_IGNORE_DIRS4, expectDefined as expectDefined10 } from "@wrongstack/core/utils";
|
|
31986
32152
|
var DEFAULT_IGNORE5 = /* @__PURE__ */ new Set([
|
|
31987
32153
|
...DEFAULT_WALK_IGNORE_DIRS4,
|
|
@@ -32144,7 +32310,7 @@ var treeTool = {
|
|
|
32144
32310
|
async function walkDir(dir, depth, opts) {
|
|
32145
32311
|
opts.signal.throwIfAborted();
|
|
32146
32312
|
if (opts.retention.truncated) return;
|
|
32147
|
-
const entries = await
|
|
32313
|
+
const entries = await fs41.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
32148
32314
|
const filtered = entries.filter((e) => {
|
|
32149
32315
|
if (!opts.showHidden && e.name.startsWith(".")) return false;
|
|
32150
32316
|
if (opts.exclude.has(e.name)) return false;
|
|
@@ -32186,7 +32352,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
32186
32352
|
opts.retention.outputBytes += lineBytes;
|
|
32187
32353
|
if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {
|
|
32188
32354
|
const childPrefix = opts.prefix + connector;
|
|
32189
|
-
await walkDir(
|
|
32355
|
+
await walkDir(path47.join(dir, entry.name), depth + 1, {
|
|
32190
32356
|
...opts,
|
|
32191
32357
|
prefix: childPrefix,
|
|
32192
32358
|
isLast
|
|
@@ -32199,7 +32365,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
32199
32365
|
init_spawn_stream();
|
|
32200
32366
|
init_util();
|
|
32201
32367
|
init_legacy_bridge();
|
|
32202
|
-
import * as
|
|
32368
|
+
import * as path48 from "node:path";
|
|
32203
32369
|
var typecheckTool = {
|
|
32204
32370
|
name: "typecheck",
|
|
32205
32371
|
category: "Code Quality",
|
|
@@ -32311,8 +32477,8 @@ async function findTsConfig(cwd) {
|
|
|
32311
32477
|
const candidates = ["tsconfig.json", "tsconfig.base.json"];
|
|
32312
32478
|
for (const f of candidates) {
|
|
32313
32479
|
try {
|
|
32314
|
-
const s = await stat22(
|
|
32315
|
-
if (s.isFile()) return
|
|
32480
|
+
const s = await stat22(path48.join(cwd, f));
|
|
32481
|
+
if (s.isFile()) return path48.join(cwd, f);
|
|
32316
32482
|
} catch {
|
|
32317
32483
|
}
|
|
32318
32484
|
}
|
|
@@ -32320,7 +32486,7 @@ async function findTsConfig(cwd) {
|
|
|
32320
32486
|
}
|
|
32321
32487
|
|
|
32322
32488
|
// src/write.ts
|
|
32323
|
-
import * as
|
|
32489
|
+
import * as fs42 from "node:fs/promises";
|
|
32324
32490
|
import { ToolValidationError as ToolValidationError11 } from "@wrongstack/core/types";
|
|
32325
32491
|
import {
|
|
32326
32492
|
atomicWrite as atomicWrite6,
|
|
@@ -32397,14 +32563,14 @@ async function prepareWrite(input, ctx) {
|
|
|
32397
32563
|
let existed = false;
|
|
32398
32564
|
let prev = "";
|
|
32399
32565
|
try {
|
|
32400
|
-
const stat22 = await
|
|
32566
|
+
const stat22 = await fs42.stat(absPath);
|
|
32401
32567
|
existed = stat22.isFile();
|
|
32402
32568
|
if (existed) {
|
|
32403
32569
|
if (!ctx.hasRead(absPath)) {
|
|
32404
|
-
prev = await
|
|
32570
|
+
prev = await fs42.readFile(absPath, "utf8");
|
|
32405
32571
|
ctx.recordRead(absPath, stat22.mtimeMs, "write", sha256hex(prev));
|
|
32406
32572
|
} else {
|
|
32407
|
-
prev = await
|
|
32573
|
+
prev = await fs42.readFile(absPath, "utf8");
|
|
32408
32574
|
}
|
|
32409
32575
|
}
|
|
32410
32576
|
} catch (err) {
|
|
@@ -32425,7 +32591,7 @@ async function finishWrite(input, ctx, prepared, signal) {
|
|
|
32425
32591
|
const rawDiff = prepared.existed ? unifiedDiff3(prepared.prev, content, { fromFile: input.path, toFile: input.path }) : `+++ ${input.path}
|
|
32426
32592
|
+ (new file, ${content.split("\n").length} lines)`;
|
|
32427
32593
|
const { text: diff, truncated: diffTruncated } = truncateDiffPayload(rawDiff, MAX_DIFF_BYTES3);
|
|
32428
|
-
const stat22 = await
|
|
32594
|
+
const stat22 = await fs42.stat(prepared.absPath);
|
|
32429
32595
|
ctx.recordRead(prepared.absPath, stat22.mtimeMs, "write", sha256hex(content));
|
|
32430
32596
|
ctx.session.recordFileChange({
|
|
32431
32597
|
path: prepared.absPath,
|
|
@@ -32481,6 +32647,7 @@ var TIER1_TOOLS = [
|
|
|
32481
32647
|
editTool,
|
|
32482
32648
|
clarifyTool,
|
|
32483
32649
|
codebaseAstReplaceTool,
|
|
32650
|
+
codebaseInvariantCheckTool,
|
|
32484
32651
|
codebaseStatsTool,
|
|
32485
32652
|
codebaseSearchTool,
|
|
32486
32653
|
codebaseSkeletonTool,
|
|
@@ -32540,6 +32707,7 @@ var builtinTools = [
|
|
|
32540
32707
|
editTool,
|
|
32541
32708
|
clarifyTool,
|
|
32542
32709
|
codebaseAstReplaceTool,
|
|
32710
|
+
codebaseInvariantCheckTool,
|
|
32543
32711
|
codebaseStatsTool,
|
|
32544
32712
|
codebaseSearchTool,
|
|
32545
32713
|
codebaseSkeletonTool,
|
|
@@ -33596,8 +33764,8 @@ function createGlobalPsSlashCommand() {
|
|
|
33596
33764
|
}
|
|
33597
33765
|
|
|
33598
33766
|
// src/skill.ts
|
|
33599
|
-
import * as
|
|
33600
|
-
import * as
|
|
33767
|
+
import * as fs43 from "node:fs/promises";
|
|
33768
|
+
import * as path49 from "node:path";
|
|
33601
33769
|
import {
|
|
33602
33770
|
missingRequiredRuntimeTools,
|
|
33603
33771
|
missingRuntimeCapabilities,
|
|
@@ -33661,7 +33829,7 @@ function makeSkillTool(skillLoader) {
|
|
|
33661
33829
|
field: "name"
|
|
33662
33830
|
});
|
|
33663
33831
|
}
|
|
33664
|
-
const dir =
|
|
33832
|
+
const dir = path49.dirname(manifest.path);
|
|
33665
33833
|
let loadedResource;
|
|
33666
33834
|
if (input.resource?.trim()) {
|
|
33667
33835
|
loadedResource = await loadResource(dir, input.resource.trim());
|
|
@@ -33720,15 +33888,15 @@ ${listing}${warningLine}`;
|
|
|
33720
33888
|
}
|
|
33721
33889
|
async function loadResource(skillDir, rel) {
|
|
33722
33890
|
const norm = rel.replace(/\\/g, "/");
|
|
33723
|
-
if (
|
|
33891
|
+
if (path49.isAbsolute(rel) || norm.split("/").some((seg) => seg === "..")) {
|
|
33724
33892
|
throw new ToolValidationError13({
|
|
33725
33893
|
message: `skill: invalid resource path "${rel}"`,
|
|
33726
33894
|
field: "resource"
|
|
33727
33895
|
});
|
|
33728
33896
|
}
|
|
33729
|
-
const absPath =
|
|
33730
|
-
const root =
|
|
33731
|
-
if (absPath !== root && !absPath.startsWith(root +
|
|
33897
|
+
const absPath = path49.resolve(skillDir, rel);
|
|
33898
|
+
const root = path49.resolve(skillDir);
|
|
33899
|
+
if (absPath !== root && !absPath.startsWith(root + path49.sep)) {
|
|
33732
33900
|
throw new ToolValidationError13({
|
|
33733
33901
|
message: `skill: resource "${rel}" escapes the skill directory`,
|
|
33734
33902
|
field: "resource"
|
|
@@ -33737,15 +33905,15 @@ async function loadResource(skillDir, rel) {
|
|
|
33737
33905
|
let realPath;
|
|
33738
33906
|
let realRoot;
|
|
33739
33907
|
try {
|
|
33740
|
-
realRoot = await
|
|
33741
|
-
realPath = await
|
|
33908
|
+
realRoot = await fs43.realpath(root);
|
|
33909
|
+
realPath = await fs43.realpath(absPath);
|
|
33742
33910
|
} catch {
|
|
33743
33911
|
throw new ToolValidationError13({
|
|
33744
33912
|
message: `skill: resource "${rel}" not readable`,
|
|
33745
33913
|
field: "resource"
|
|
33746
33914
|
});
|
|
33747
33915
|
}
|
|
33748
|
-
if (realPath !== realRoot && !realPath.startsWith(realRoot +
|
|
33916
|
+
if (realPath !== realRoot && !realPath.startsWith(realRoot + path49.sep)) {
|
|
33749
33917
|
throw new ToolValidationError13({
|
|
33750
33918
|
message: `skill: resource "${rel}" resolves outside the skill directory`,
|
|
33751
33919
|
field: "resource"
|
|
@@ -33753,7 +33921,7 @@ async function loadResource(skillDir, rel) {
|
|
|
33753
33921
|
}
|
|
33754
33922
|
let buf;
|
|
33755
33923
|
try {
|
|
33756
|
-
buf = await
|
|
33924
|
+
buf = await fs43.readFile(realPath);
|
|
33757
33925
|
} catch {
|
|
33758
33926
|
throw new ToolValidationError13({
|
|
33759
33927
|
message: `skill: resource "${rel}" not readable`,
|
|
@@ -33782,17 +33950,17 @@ async function walk(root, dir, out) {
|
|
|
33782
33950
|
if (out.length >= MAX_LISTED_RESOURCES) return;
|
|
33783
33951
|
let entries;
|
|
33784
33952
|
try {
|
|
33785
|
-
entries = await
|
|
33953
|
+
entries = await fs43.readdir(dir, { withFileTypes: true });
|
|
33786
33954
|
} catch {
|
|
33787
33955
|
return;
|
|
33788
33956
|
}
|
|
33789
33957
|
for (const e of entries) {
|
|
33790
33958
|
if (out.length >= MAX_LISTED_RESOURCES) return;
|
|
33791
|
-
const fullPath =
|
|
33959
|
+
const fullPath = path49.join(dir, e.name);
|
|
33792
33960
|
let isDir = e.isDirectory();
|
|
33793
33961
|
if (e.isSymbolicLink()) {
|
|
33794
33962
|
try {
|
|
33795
|
-
isDir = (await
|
|
33963
|
+
isDir = (await fs43.stat(fullPath)).isDirectory();
|
|
33796
33964
|
} catch {
|
|
33797
33965
|
continue;
|
|
33798
33966
|
}
|
|
@@ -33803,8 +33971,8 @@ async function walk(root, dir, out) {
|
|
|
33803
33971
|
} else if (e.isFile()) {
|
|
33804
33972
|
if (e.name === "SKILL.md" || e.name === "SKILL.save.md") continue;
|
|
33805
33973
|
try {
|
|
33806
|
-
const stat22 = await
|
|
33807
|
-
const rel =
|
|
33974
|
+
const stat22 = await fs43.stat(fullPath);
|
|
33975
|
+
const rel = path49.relative(root, fullPath).split(path49.sep).join("/");
|
|
33808
33976
|
out.push({ path: rel, bytes: stat22.size });
|
|
33809
33977
|
} catch {
|
|
33810
33978
|
}
|
|
@@ -33900,12 +34068,14 @@ var TOOL_ICON_MAP = {
|
|
|
33900
34068
|
"codebase-stats": "index",
|
|
33901
34069
|
"codebase-incoming-calls": "index",
|
|
33902
34070
|
"codebase-outgoing-calls": "index",
|
|
34071
|
+
"codebase-invariant-check": "index",
|
|
33903
34072
|
"dead-code-scan": "index",
|
|
33904
34073
|
codebase_index: "index",
|
|
33905
34074
|
codebase_search: "index",
|
|
33906
34075
|
codebase_stats: "index",
|
|
33907
34076
|
codebase_incoming_calls: "index",
|
|
33908
34077
|
codebase_outgoing_calls: "index",
|
|
34078
|
+
codebase_invariant_check: "index",
|
|
33909
34079
|
dead_code_scan: "index",
|
|
33910
34080
|
// Data
|
|
33911
34081
|
json: "json",
|
|
@@ -34078,6 +34248,7 @@ export {
|
|
|
34078
34248
|
codebaseImpactAnalysisTool,
|
|
34079
34249
|
codebaseIndexStats,
|
|
34080
34250
|
codebaseIndexTool,
|
|
34251
|
+
codebaseInvariantCheckTool,
|
|
34081
34252
|
codebaseRepoMapTool,
|
|
34082
34253
|
codebaseSearchTool,
|
|
34083
34254
|
codebaseSkeletonTool,
|