@wrongstack/tools 0.308.0 → 0.308.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bash-kill-guard.d.ts +1 -0
- package/dist/bash.js +15 -1
- package/dist/builtin.js +625 -146
- package/dist/exec.js +34 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +653 -174
- package/dist/pack.js +624 -146
- package/dist/plan.js +13 -3
- package/dist/pwsh.d.ts +22 -0
- package/dist/session-kanban-sync.d.ts +4 -1
- package/dist/session-kanban.js +9 -3
- package/dist/task.js +13 -3
- package/dist/todo.js +13 -3
- package/dist/tool-tier.js +625 -146
- package/package.json +5 -4
package/dist/pack.js
CHANGED
|
@@ -1031,8 +1031,8 @@ async function* spawnStream(opts) {
|
|
|
1031
1031
|
try {
|
|
1032
1032
|
for (; ; ) {
|
|
1033
1033
|
while (queue.length === 0) {
|
|
1034
|
-
await new Promise((
|
|
1035
|
-
waiter =
|
|
1034
|
+
await new Promise((resolve24) => {
|
|
1035
|
+
waiter = resolve24;
|
|
1036
1036
|
});
|
|
1037
1037
|
}
|
|
1038
1038
|
const chunk = queue.shift();
|
|
@@ -1135,9 +1135,9 @@ async function detectPackageManager(cwd, stopAt) {
|
|
|
1135
1135
|
return "npm";
|
|
1136
1136
|
}
|
|
1137
1137
|
async function detectPackageManagerInDir(dir) {
|
|
1138
|
-
const
|
|
1138
|
+
const fs44 = await import("node:fs/promises");
|
|
1139
1139
|
try {
|
|
1140
|
-
const raw = await
|
|
1140
|
+
const raw = await fs44.readFile(path3.join(dir, "package.json"), "utf8");
|
|
1141
1141
|
const declared = JSON.parse(raw).packageManager;
|
|
1142
1142
|
if (typeof declared === "string") {
|
|
1143
1143
|
const name = declared.split("@")[0] ?? "";
|
|
@@ -1156,7 +1156,7 @@ async function detectPackageManagerInDir(dir) {
|
|
|
1156
1156
|
];
|
|
1157
1157
|
for (const [file, manager] of lockfiles) {
|
|
1158
1158
|
try {
|
|
1159
|
-
await
|
|
1159
|
+
await fs44.stat(`${dir}/${file}`);
|
|
1160
1160
|
return manager;
|
|
1161
1161
|
} catch {
|
|
1162
1162
|
}
|
|
@@ -4137,15 +4137,15 @@ async function changedPaths(before, after, beforeSizes, afterSizes) {
|
|
|
4137
4137
|
const beforeSet = new Set(before);
|
|
4138
4138
|
const afterSet = new Set(after);
|
|
4139
4139
|
const changed = /* @__PURE__ */ new Set();
|
|
4140
|
-
for (const
|
|
4141
|
-
if (!beforeSet.has(
|
|
4140
|
+
for (const path50 of after) {
|
|
4141
|
+
if (!beforeSet.has(path50)) changed.add(path50);
|
|
4142
4142
|
}
|
|
4143
|
-
for (const
|
|
4144
|
-
if (!afterSet.has(
|
|
4143
|
+
for (const path50 of before) {
|
|
4144
|
+
if (!afterSet.has(path50)) changed.add(path50);
|
|
4145
4145
|
}
|
|
4146
4146
|
if (beforeSizes && afterSizes) {
|
|
4147
|
-
for (const
|
|
4148
|
-
if (beforeSizes.get(
|
|
4147
|
+
for (const path50 of after) {
|
|
4148
|
+
if (beforeSizes.get(path50) !== afterSizes.get(path50)) changed.add(path50);
|
|
4149
4149
|
}
|
|
4150
4150
|
}
|
|
4151
4151
|
return [...changed].sort();
|
|
@@ -5640,7 +5640,7 @@ async function syncGoParse(filePath, content, lang) {
|
|
|
5640
5640
|
}
|
|
5641
5641
|
const goBinary = resolveWin32Command("go");
|
|
5642
5642
|
const goResult = await new Promise(
|
|
5643
|
-
(
|
|
5643
|
+
(resolve24, reject) => {
|
|
5644
5644
|
let settled = false;
|
|
5645
5645
|
const proc = spawn5(goBinary, ["run", scriptPath], {
|
|
5646
5646
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -5669,7 +5669,7 @@ async function syncGoParse(filePath, content, lang) {
|
|
|
5669
5669
|
if (settled) return;
|
|
5670
5670
|
settled = true;
|
|
5671
5671
|
clearTimeout(timer);
|
|
5672
|
-
|
|
5672
|
+
resolve24({ code: code2, stdout: stdout2 });
|
|
5673
5673
|
});
|
|
5674
5674
|
}
|
|
5675
5675
|
);
|
|
@@ -6345,7 +6345,7 @@ async function resolvePython() {
|
|
|
6345
6345
|
return null;
|
|
6346
6346
|
}
|
|
6347
6347
|
function commandIsAvailable(command) {
|
|
6348
|
-
return new Promise((
|
|
6348
|
+
return new Promise((resolve24) => {
|
|
6349
6349
|
let settled = false;
|
|
6350
6350
|
const proc = spawn6(command, ["--version"], {
|
|
6351
6351
|
stdio: "ignore",
|
|
@@ -6355,7 +6355,7 @@ function commandIsAvailable(command) {
|
|
|
6355
6355
|
if (settled) return;
|
|
6356
6356
|
settled = true;
|
|
6357
6357
|
clearTimeout(timer);
|
|
6358
|
-
|
|
6358
|
+
resolve24(available);
|
|
6359
6359
|
};
|
|
6360
6360
|
const timer = setTimeout(() => {
|
|
6361
6361
|
proc.kill("SIGKILL");
|
|
@@ -6367,7 +6367,7 @@ function commandIsAvailable(command) {
|
|
|
6367
6367
|
});
|
|
6368
6368
|
}
|
|
6369
6369
|
function spawnPyParser(pyBinary, scriptPath, filePath, content) {
|
|
6370
|
-
return new Promise((
|
|
6370
|
+
return new Promise((resolve24, reject) => {
|
|
6371
6371
|
let settled = false;
|
|
6372
6372
|
const proc = spawn6(pyBinary, [scriptPath, filePath], {
|
|
6373
6373
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -6396,7 +6396,7 @@ function spawnPyParser(pyBinary, scriptPath, filePath, content) {
|
|
|
6396
6396
|
if (settled) return;
|
|
6397
6397
|
settled = true;
|
|
6398
6398
|
clearTimeout(timer);
|
|
6399
|
-
|
|
6399
|
+
resolve24({ code, stdout });
|
|
6400
6400
|
});
|
|
6401
6401
|
});
|
|
6402
6402
|
}
|
|
@@ -8604,6 +8604,18 @@ function parseKillCommand(command) {
|
|
|
8604
8604
|
originalCommand: command
|
|
8605
8605
|
};
|
|
8606
8606
|
}
|
|
8607
|
+
const wmicPidMatch = normalized.match(
|
|
8608
|
+
/^wmic\s+process\s+where\s+['"]?processid\s*=\s*['"]?(\d+)/i
|
|
8609
|
+
);
|
|
8610
|
+
if (wmicPidMatch?.[1]) {
|
|
8611
|
+
return {
|
|
8612
|
+
pid: parseInt(wmicPidMatch[1], 10),
|
|
8613
|
+
signal: "FORCE",
|
|
8614
|
+
isGroupKill: false,
|
|
8615
|
+
isAllKill: false,
|
|
8616
|
+
originalCommand: command
|
|
8617
|
+
};
|
|
8618
|
+
}
|
|
8607
8619
|
const killScriptMatch = normalized.match(SCRIPT_KILL_RE);
|
|
8608
8620
|
if (killScriptMatch) {
|
|
8609
8621
|
return {
|
|
@@ -8723,7 +8735,9 @@ async function isKillProtected(kill) {
|
|
|
8723
8735
|
return protectedPids.length > 0;
|
|
8724
8736
|
}
|
|
8725
8737
|
if (kill.pid !== void 0) {
|
|
8726
|
-
|
|
8738
|
+
if (await registry.shouldBlockKill(kill.pid)) return true;
|
|
8739
|
+
if (kill.pid === process.pid || kill.pid === process.ppid) return true;
|
|
8740
|
+
return false;
|
|
8727
8741
|
}
|
|
8728
8742
|
return false;
|
|
8729
8743
|
}
|
|
@@ -8770,8 +8784,8 @@ async function checkAndBlockKillCommand(command) {
|
|
|
8770
8784
|
|
|
8771
8785
|
// src/_shell-pick.ts
|
|
8772
8786
|
var POSIX_DEFAULT = "cmd";
|
|
8773
|
-
function pickShell(
|
|
8774
|
-
if (
|
|
8787
|
+
function pickShell(platform6, command, env) {
|
|
8788
|
+
if (platform6 !== "win32") return POSIX_DEFAULT;
|
|
8775
8789
|
const override = env.get("WRONGSTACK_SHELL")?.trim().toLowerCase();
|
|
8776
8790
|
if (override === "cmd" || override === "cmd.exe") return "cmd";
|
|
8777
8791
|
if (override === "powershell" || override === "powershell.exe") return "powershell";
|
|
@@ -9230,10 +9244,10 @@ var bashTool = {
|
|
|
9230
9244
|
queue.push(c);
|
|
9231
9245
|
}
|
|
9232
9246
|
};
|
|
9233
|
-
const next = () => new Promise((
|
|
9247
|
+
const next = () => new Promise((resolve24) => {
|
|
9234
9248
|
const c = queue.shift();
|
|
9235
|
-
if (c)
|
|
9236
|
-
else resolveNext =
|
|
9249
|
+
if (c) resolve24(c);
|
|
9250
|
+
else resolveNext = resolve24;
|
|
9237
9251
|
});
|
|
9238
9252
|
let lastFlush = Date.now();
|
|
9239
9253
|
const flush = () => {
|
|
@@ -9696,11 +9710,11 @@ var BrowserArtifactStore = class {
|
|
|
9696
9710
|
};
|
|
9697
9711
|
async function hashFile(target) {
|
|
9698
9712
|
const hash = createHash3("sha256");
|
|
9699
|
-
await new Promise((
|
|
9713
|
+
await new Promise((resolve24, reject) => {
|
|
9700
9714
|
const stream = createReadStream(target);
|
|
9701
9715
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
9702
9716
|
stream.once("error", reject);
|
|
9703
|
-
stream.once("end",
|
|
9717
|
+
stream.once("end", resolve24);
|
|
9704
9718
|
});
|
|
9705
9719
|
return hash.digest("hex");
|
|
9706
9720
|
}
|
|
@@ -9850,7 +9864,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
9850
9864
|
async start() {
|
|
9851
9865
|
if (this.url) return this.url;
|
|
9852
9866
|
if (this.startPromise) return this.startPromise;
|
|
9853
|
-
this.startPromise = new Promise((
|
|
9867
|
+
this.startPromise = new Promise((resolve24, reject) => {
|
|
9854
9868
|
const onError = (error) => {
|
|
9855
9869
|
this.server.off("listening", onListening);
|
|
9856
9870
|
reject(error);
|
|
@@ -9863,7 +9877,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
9863
9877
|
return;
|
|
9864
9878
|
}
|
|
9865
9879
|
this.url = `http://127.0.0.1:${address.port}`;
|
|
9866
|
-
|
|
9880
|
+
resolve24(this.url);
|
|
9867
9881
|
};
|
|
9868
9882
|
this.server.once("error", onError);
|
|
9869
9883
|
this.server.once("listening", onListening);
|
|
@@ -9878,7 +9892,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
9878
9892
|
for (const socket of this.sockets) socket.destroy();
|
|
9879
9893
|
this.sockets.clear();
|
|
9880
9894
|
if (!this.server.listening) return;
|
|
9881
|
-
await new Promise((
|
|
9895
|
+
await new Promise((resolve24) => this.server.close(() => resolve24()));
|
|
9882
9896
|
}
|
|
9883
9897
|
async forwardHttp(request2, response) {
|
|
9884
9898
|
try {
|
|
@@ -10451,7 +10465,7 @@ function pushBounded(target, value, limit) {
|
|
|
10451
10465
|
}
|
|
10452
10466
|
async function abortable(signal, operation, onAbort) {
|
|
10453
10467
|
signal.throwIfAborted();
|
|
10454
|
-
return new Promise((
|
|
10468
|
+
return new Promise((resolve24, reject) => {
|
|
10455
10469
|
let settled = false;
|
|
10456
10470
|
let aborting = false;
|
|
10457
10471
|
const finish = (fn) => {
|
|
@@ -10469,7 +10483,7 @@ async function abortable(signal, operation, onAbort) {
|
|
|
10469
10483
|
signal.addEventListener("abort", abort, { once: true });
|
|
10470
10484
|
operation().then(
|
|
10471
10485
|
(value) => {
|
|
10472
|
-
if (!aborting) finish(() =>
|
|
10486
|
+
if (!aborting) finish(() => resolve24(value));
|
|
10473
10487
|
},
|
|
10474
10488
|
(err) => {
|
|
10475
10489
|
if (!aborting) finish(() => reject(err));
|
|
@@ -13996,8 +14010,8 @@ function isProjectIndexServerHealth(value) {
|
|
|
13996
14010
|
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";
|
|
13997
14011
|
}
|
|
13998
14012
|
function delay(ms) {
|
|
13999
|
-
return new Promise((
|
|
14000
|
-
const timer = setTimeout(
|
|
14013
|
+
return new Promise((resolve24) => {
|
|
14014
|
+
const timer = setTimeout(resolve24, ms);
|
|
14001
14015
|
timer.unref?.();
|
|
14002
14016
|
});
|
|
14003
14017
|
}
|
|
@@ -14203,7 +14217,7 @@ var ProjectServerConnection = class {
|
|
|
14203
14217
|
return Promise.reject(new Error("codebase-index server connection is not available"));
|
|
14204
14218
|
}
|
|
14205
14219
|
const id = this.nextId++;
|
|
14206
|
-
return new Promise((
|
|
14220
|
+
return new Promise((resolve24, reject) => {
|
|
14207
14221
|
const timer = setTimeout(() => {
|
|
14208
14222
|
const entry = this.pending.get(id);
|
|
14209
14223
|
if (!entry) return;
|
|
@@ -14226,7 +14240,7 @@ var ProjectServerConnection = class {
|
|
|
14226
14240
|
entry.reject(cancellationError(signal));
|
|
14227
14241
|
} : void 0;
|
|
14228
14242
|
this.pending.set(id, {
|
|
14229
|
-
resolve:
|
|
14243
|
+
resolve: resolve24,
|
|
14230
14244
|
reject,
|
|
14231
14245
|
timer,
|
|
14232
14246
|
signal,
|
|
@@ -14295,7 +14309,7 @@ var ProjectServerConnection = class {
|
|
|
14295
14309
|
this.binaryBuffer = [];
|
|
14296
14310
|
this.useBinary = false;
|
|
14297
14311
|
this.textDecoder = null;
|
|
14298
|
-
return new Promise((
|
|
14312
|
+
return new Promise((resolve24, reject) => {
|
|
14299
14313
|
const socket = net3.createConnection(this.endpoint);
|
|
14300
14314
|
this.socket = socket;
|
|
14301
14315
|
const timer = setTimeout(() => {
|
|
@@ -14307,7 +14321,7 @@ var ProjectServerConnection = class {
|
|
|
14307
14321
|
clearTimeout(timer);
|
|
14308
14322
|
this.connectResolve = null;
|
|
14309
14323
|
this.connectReject = null;
|
|
14310
|
-
|
|
14324
|
+
resolve24();
|
|
14311
14325
|
};
|
|
14312
14326
|
const finishReject = (error) => {
|
|
14313
14327
|
clearTimeout(timer);
|
|
@@ -15321,9 +15335,9 @@ var ParserWorkerPool = class {
|
|
|
15321
15335
|
for (let i = 0; i < files.length; i++) {
|
|
15322
15336
|
chunks[i % workerCount].push(files[i]);
|
|
15323
15337
|
}
|
|
15324
|
-
return new Promise((
|
|
15338
|
+
return new Promise((resolve24, reject) => {
|
|
15325
15339
|
this.pending.set(batchId, {
|
|
15326
|
-
resolve:
|
|
15340
|
+
resolve: resolve24,
|
|
15327
15341
|
reject,
|
|
15328
15342
|
accumulated: [],
|
|
15329
15343
|
expectedWorkers: workerCount,
|
|
@@ -15354,10 +15368,10 @@ var ParserWorkerPool = class {
|
|
|
15354
15368
|
await Promise.allSettled(
|
|
15355
15369
|
workers.map(
|
|
15356
15370
|
(w) => Promise.race([
|
|
15357
|
-
new Promise((
|
|
15358
|
-
w.once("exit", () =>
|
|
15371
|
+
new Promise((resolve24) => {
|
|
15372
|
+
w.once("exit", () => resolve24());
|
|
15359
15373
|
}),
|
|
15360
|
-
new Promise((
|
|
15374
|
+
new Promise((resolve24) => setTimeout(() => resolve24(), 2e3))
|
|
15361
15375
|
]).then(() => {
|
|
15362
15376
|
if (!w.threadId) return;
|
|
15363
15377
|
return w.terminate().catch(() => {
|
|
@@ -15418,7 +15432,7 @@ function shouldUseParserWorkerPool(candidateFileCount, parseBatchCount) {
|
|
|
15418
15432
|
return !isFrugalPerf() && candidateFileCount >= WORKER_POOL_THRESHOLD && parseBatchCount > 1;
|
|
15419
15433
|
}
|
|
15420
15434
|
function yieldEventLoop() {
|
|
15421
|
-
return new Promise((
|
|
15435
|
+
return new Promise((resolve24) => setImmediate(resolve24));
|
|
15422
15436
|
}
|
|
15423
15437
|
function throwIfAborted(signal) {
|
|
15424
15438
|
if (!signal?.aborted) return;
|
|
@@ -15450,7 +15464,7 @@ function normalizeComparablePath(value) {
|
|
|
15450
15464
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
15451
15465
|
}
|
|
15452
15466
|
function gitOutput(projectRoot, args) {
|
|
15453
|
-
return new Promise((
|
|
15467
|
+
return new Promise((resolve24, reject) => {
|
|
15454
15468
|
execFile(
|
|
15455
15469
|
"git",
|
|
15456
15470
|
["-C", projectRoot, ...args],
|
|
@@ -15461,7 +15475,7 @@ function gitOutput(projectRoot, args) {
|
|
|
15461
15475
|
},
|
|
15462
15476
|
(error, stdout) => {
|
|
15463
15477
|
if (error) reject(error);
|
|
15464
|
-
else
|
|
15478
|
+
else resolve24(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
|
|
15465
15479
|
}
|
|
15466
15480
|
);
|
|
15467
15481
|
});
|
|
@@ -16237,7 +16251,7 @@ function callIndexOp(op, args, opts) {
|
|
|
16237
16251
|
opts.signal.reason instanceof Error ? opts.signal.reason : new Error("Indexing cancelled")
|
|
16238
16252
|
);
|
|
16239
16253
|
}
|
|
16240
|
-
return new Promise((
|
|
16254
|
+
return new Promise((resolve24, reject) => {
|
|
16241
16255
|
const id = nextRpcId++;
|
|
16242
16256
|
const timer = setTimeout(() => {
|
|
16243
16257
|
pending.delete(id);
|
|
@@ -16259,7 +16273,7 @@ function callIndexOp(op, args, opts) {
|
|
|
16259
16273
|
pending.set(id, {
|
|
16260
16274
|
resolve: (v) => {
|
|
16261
16275
|
cleanup();
|
|
16262
|
-
|
|
16276
|
+
resolve24(v);
|
|
16263
16277
|
},
|
|
16264
16278
|
reject: (e) => {
|
|
16265
16279
|
cleanup();
|
|
@@ -19792,7 +19806,7 @@ function findGitDir(cwd) {
|
|
|
19792
19806
|
return null;
|
|
19793
19807
|
}
|
|
19794
19808
|
function runGit(args, cwd, signal) {
|
|
19795
|
-
return new Promise((
|
|
19809
|
+
return new Promise((resolve24) => {
|
|
19796
19810
|
let stdout = "";
|
|
19797
19811
|
let stderr = "";
|
|
19798
19812
|
const child = spawn7("git", args, {
|
|
@@ -19808,8 +19822,8 @@ function runGit(args, cwd, signal) {
|
|
|
19808
19822
|
child.stderr?.on("data", (c) => {
|
|
19809
19823
|
stderr += c.toString();
|
|
19810
19824
|
});
|
|
19811
|
-
child.on("close", (code) =>
|
|
19812
|
-
child.on("error", (e) =>
|
|
19825
|
+
child.on("close", (code) => resolve24({ stdout, stderr, exitCode: code ?? 0 }));
|
|
19826
|
+
child.on("error", (e) => resolve24({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
19813
19827
|
});
|
|
19814
19828
|
}
|
|
19815
19829
|
async function fileDiff(input, ctx, _signal) {
|
|
@@ -21024,6 +21038,40 @@ var RULES = [
|
|
|
21024
21038
|
},
|
|
21025
21039
|
reason: "Remove-Item with -Recurse -Force"
|
|
21026
21040
|
},
|
|
21041
|
+
// ----- Windows PowerShell Disk & Volume destruction -----
|
|
21042
|
+
{
|
|
21043
|
+
id: "powershell-disk-volume-destroy",
|
|
21044
|
+
level: "destructive",
|
|
21045
|
+
test: (cmd, args) => {
|
|
21046
|
+
if (cmd !== "powershell" && cmd !== "pwsh") return false;
|
|
21047
|
+
return args.some(
|
|
21048
|
+
(a) => /^(?:Format-Volume|Clear-Disk|Initialize-Disk|Remove-Partition|Clear-Volume)(?:\s|$)/i.test(a)
|
|
21049
|
+
);
|
|
21050
|
+
},
|
|
21051
|
+
reason: "PowerShell disk/volume partition destruction"
|
|
21052
|
+
},
|
|
21053
|
+
// ----- Windows PowerShell System Restart / Shutdown -----
|
|
21054
|
+
{
|
|
21055
|
+
id: "powershell-stop-restart-computer",
|
|
21056
|
+
level: "destructive",
|
|
21057
|
+
test: (cmd, args) => {
|
|
21058
|
+
if (cmd !== "powershell" && cmd !== "pwsh") return false;
|
|
21059
|
+
return args.some((a) => /^(?:Stop-Computer|Restart-Computer)(?:\s|$)/i.test(a));
|
|
21060
|
+
},
|
|
21061
|
+
reason: "PowerShell system shutdown or restart"
|
|
21062
|
+
},
|
|
21063
|
+
// ----- Windows PowerShell ExecutionPolicy / Payload evasion -----
|
|
21064
|
+
{
|
|
21065
|
+
id: "powershell-execution-policy-bypass",
|
|
21066
|
+
level: "caution",
|
|
21067
|
+
test: (cmd, args) => {
|
|
21068
|
+
if (cmd !== "powershell" && cmd !== "pwsh") return false;
|
|
21069
|
+
return args.some(
|
|
21070
|
+
(a) => /Set-ExecutionPolicy\s+(?:Bypass|Unrestricted)|-(?:EncodedCommand|enc)\b/i.test(a)
|
|
21071
|
+
);
|
|
21072
|
+
},
|
|
21073
|
+
reason: "PowerShell execution policy bypass or encoded command"
|
|
21074
|
+
},
|
|
21027
21075
|
// ----- find -exec / -ok / -execdir -----
|
|
21028
21076
|
{
|
|
21029
21077
|
id: "find-exec",
|
|
@@ -22444,7 +22492,7 @@ var execTool = {
|
|
|
22444
22492
|
}
|
|
22445
22493
|
};
|
|
22446
22494
|
function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
|
|
22447
|
-
return new Promise((
|
|
22495
|
+
return new Promise((resolve24) => {
|
|
22448
22496
|
let stdout = "";
|
|
22449
22497
|
let stderr = "";
|
|
22450
22498
|
let killed = false;
|
|
@@ -22452,7 +22500,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
|
|
|
22452
22500
|
const finish = (result) => {
|
|
22453
22501
|
if (resolvedOnce.value) return;
|
|
22454
22502
|
resolvedOnce.value = true;
|
|
22455
|
-
|
|
22503
|
+
resolve24(result);
|
|
22456
22504
|
};
|
|
22457
22505
|
const startedAt = Date.now();
|
|
22458
22506
|
let stdoutBytes = 0;
|
|
@@ -23128,10 +23176,10 @@ function parseFormatterCounts(fixer, output) {
|
|
|
23128
23176
|
};
|
|
23129
23177
|
}
|
|
23130
23178
|
async function detectFixer(cwd) {
|
|
23131
|
-
const
|
|
23179
|
+
const fs44 = await import("node:fs/promises");
|
|
23132
23180
|
const exists = async (file) => {
|
|
23133
23181
|
try {
|
|
23134
|
-
await
|
|
23182
|
+
await fs44.stat(`${cwd}/${file}`);
|
|
23135
23183
|
return true;
|
|
23136
23184
|
} catch {
|
|
23137
23185
|
return false;
|
|
@@ -23154,7 +23202,7 @@ async function detectFixer(cwd) {
|
|
|
23154
23202
|
if (await exists(cfg)) return "prettier";
|
|
23155
23203
|
}
|
|
23156
23204
|
try {
|
|
23157
|
-
const raw = await
|
|
23205
|
+
const raw = await fs44.readFile(`${cwd}/package.json`, "utf8");
|
|
23158
23206
|
const pkg = JSON.parse(raw);
|
|
23159
23207
|
if (pkg["prettier"] !== void 0) return "prettier";
|
|
23160
23208
|
} catch {
|
|
@@ -23422,7 +23470,7 @@ function buildArgs(input) {
|
|
|
23422
23470
|
}
|
|
23423
23471
|
}
|
|
23424
23472
|
function runGit2(args, cwd, signal) {
|
|
23425
|
-
return new Promise((
|
|
23473
|
+
return new Promise((resolve24) => {
|
|
23426
23474
|
let stdout = "";
|
|
23427
23475
|
let stderr = "";
|
|
23428
23476
|
const child = spawn9("git", args, {
|
|
@@ -23443,7 +23491,7 @@ function runGit2(args, cwd, signal) {
|
|
|
23443
23491
|
}
|
|
23444
23492
|
});
|
|
23445
23493
|
child.on("error", (err) => {
|
|
23446
|
-
|
|
23494
|
+
resolve24({
|
|
23447
23495
|
command: args[0],
|
|
23448
23496
|
stdout: normalizeCommandOutput(stdout),
|
|
23449
23497
|
stderr: err.message,
|
|
@@ -23452,7 +23500,7 @@ function runGit2(args, cwd, signal) {
|
|
|
23452
23500
|
});
|
|
23453
23501
|
});
|
|
23454
23502
|
child.on("close", (code) => {
|
|
23455
|
-
|
|
23503
|
+
resolve24({
|
|
23456
23504
|
command: args[0],
|
|
23457
23505
|
stdout: normalizeCommandOutput(stdout),
|
|
23458
23506
|
stderr: normalizeCommandOutput(stderr),
|
|
@@ -23865,7 +23913,7 @@ var grepTool = {
|
|
|
23865
23913
|
};
|
|
23866
23914
|
var rgAvailabilityCache;
|
|
23867
23915
|
function detectRg() {
|
|
23868
|
-
rgAvailabilityCache ??= new Promise((
|
|
23916
|
+
rgAvailabilityCache ??= new Promise((resolve24) => {
|
|
23869
23917
|
try {
|
|
23870
23918
|
const p = spawn10("rg", ["--version"], {
|
|
23871
23919
|
env: buildChildEnv5(),
|
|
@@ -23873,10 +23921,10 @@ function detectRg() {
|
|
|
23873
23921
|
signal: AbortSignal.timeout(1e4),
|
|
23874
23922
|
windowsHide: true
|
|
23875
23923
|
});
|
|
23876
|
-
p.on("error", () =>
|
|
23877
|
-
p.on("close", (code) =>
|
|
23924
|
+
p.on("error", () => resolve24(false));
|
|
23925
|
+
p.on("close", (code) => resolve24(code === 0));
|
|
23878
23926
|
} catch {
|
|
23879
|
-
|
|
23927
|
+
resolve24(false);
|
|
23880
23928
|
}
|
|
23881
23929
|
});
|
|
23882
23930
|
return rgAvailabilityCache;
|
|
@@ -24918,60 +24966,60 @@ function jmespathSearch(data, query) {
|
|
|
24918
24966
|
}
|
|
24919
24967
|
function validateJsonSchema(data, schema) {
|
|
24920
24968
|
const errors = [];
|
|
24921
|
-
function check(value, s,
|
|
24969
|
+
function check(value, s, path50) {
|
|
24922
24970
|
if (s["type"]) {
|
|
24923
24971
|
const expectedType = s["type"];
|
|
24924
24972
|
const actualType = Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
|
|
24925
24973
|
if (expectedType === "integer") {
|
|
24926
|
-
if (!Number.isInteger(value)) errors.push(`${
|
|
24974
|
+
if (!Number.isInteger(value)) errors.push(`${path50}: expected integer, got ${actualType}`);
|
|
24927
24975
|
} else if (expectedType !== actualType) {
|
|
24928
|
-
errors.push(`${
|
|
24976
|
+
errors.push(`${path50}: expected ${expectedType}, got ${actualType}`);
|
|
24929
24977
|
}
|
|
24930
24978
|
}
|
|
24931
24979
|
if (typeof value === "string" && s["format"] === "uri" && value) {
|
|
24932
24980
|
try {
|
|
24933
24981
|
new URL(value);
|
|
24934
24982
|
} catch {
|
|
24935
|
-
errors.push(`${
|
|
24983
|
+
errors.push(`${path50}: not a valid URI`);
|
|
24936
24984
|
}
|
|
24937
24985
|
}
|
|
24938
24986
|
if (typeof value === "string" && s["pattern"]) {
|
|
24939
24987
|
const compiled = compileUserRegex(s["pattern"], "");
|
|
24940
24988
|
if (!compiled.ok) {
|
|
24941
|
-
errors.push(`${
|
|
24989
|
+
errors.push(`${path50}: invalid schema pattern \u2014 ${compiled.reason}`);
|
|
24942
24990
|
} else if (!compiled.regex.test(capSubject(value))) {
|
|
24943
|
-
errors.push(`${
|
|
24991
|
+
errors.push(`${path50}: does not match pattern ${s["pattern"]}`);
|
|
24944
24992
|
}
|
|
24945
24993
|
}
|
|
24946
24994
|
if (typeof value === "string" && s["minLength"] !== void 0 && value.length < s["minLength"]) {
|
|
24947
|
-
errors.push(`${
|
|
24995
|
+
errors.push(`${path50}: string too short (min ${s["minLength"]})`);
|
|
24948
24996
|
}
|
|
24949
24997
|
if (typeof value === "string" && s["maxLength"] !== void 0 && value.length > s["maxLength"]) {
|
|
24950
|
-
errors.push(`${
|
|
24998
|
+
errors.push(`${path50}: string too long (max ${s["maxLength"]})`);
|
|
24951
24999
|
}
|
|
24952
25000
|
if (typeof value === "number" && s["minimum"] !== void 0 && value < s["minimum"]) {
|
|
24953
|
-
errors.push(`${
|
|
25001
|
+
errors.push(`${path50}: below minimum ${s["minimum"]}`);
|
|
24954
25002
|
}
|
|
24955
25003
|
if (typeof value === "number" && s["maximum"] !== void 0 && value > s["maximum"]) {
|
|
24956
|
-
errors.push(`${
|
|
25004
|
+
errors.push(`${path50}: above maximum ${s["maximum"]}`);
|
|
24957
25005
|
}
|
|
24958
25006
|
if (Array.isArray(value) && s["items"] && Array.isArray(s["items"])) {
|
|
24959
25007
|
for (let i = 0; i < value.length; i++) {
|
|
24960
|
-
check(value[i], s["items"], `${
|
|
25008
|
+
check(value[i], s["items"], `${path50}[${i}]`);
|
|
24961
25009
|
}
|
|
24962
25010
|
}
|
|
24963
25011
|
if (typeof value === "object" && value !== null && !Array.isArray(value) && s["properties"]) {
|
|
24964
25012
|
const props = s["properties"];
|
|
24965
25013
|
for (const [k, propSchema] of Object.entries(props)) {
|
|
24966
|
-
check(value[k], propSchema, `${
|
|
25014
|
+
check(value[k], propSchema, `${path50}.${k}`);
|
|
24967
25015
|
}
|
|
24968
25016
|
}
|
|
24969
25017
|
}
|
|
24970
25018
|
check(data, schema, "$");
|
|
24971
25019
|
return { valid: errors.length === 0, errors };
|
|
24972
25020
|
}
|
|
24973
|
-
function simpleQuery(data,
|
|
24974
|
-
const parts =
|
|
25021
|
+
function simpleQuery(data, path50) {
|
|
25022
|
+
const parts = path50.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
24975
25023
|
let current = data;
|
|
24976
25024
|
for (const part of parts) {
|
|
24977
25025
|
if (current === null || current === void 0) return void 0;
|
|
@@ -25374,7 +25422,7 @@ function broadcastTodoUpdate(context, todos) {
|
|
|
25374
25422
|
const mailbox = getSharedProjectMailbox(projectDir);
|
|
25375
25423
|
void mailbox.send({
|
|
25376
25424
|
from: context.agentId,
|
|
25377
|
-
to:
|
|
25425
|
+
to: `@session:${sessionId}`,
|
|
25378
25426
|
type: "status",
|
|
25379
25427
|
subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
|
|
25380
25428
|
body: JSON.stringify({
|
|
@@ -25403,13 +25451,17 @@ Reassess your current plan before continuing; do not rely on the initial todo sn
|
|
|
25403
25451
|
state.appendMessage({ role: "user", content: [{ type: "text", text }] });
|
|
25404
25452
|
}
|
|
25405
25453
|
}
|
|
25406
|
-
function applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors2) {
|
|
25454
|
+
function applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors2, options = {}) {
|
|
25407
25455
|
const metaKanban = context.meta["kanban"];
|
|
25408
25456
|
const metaBoardId = metaKanban && typeof metaKanban === "object" ? metaKanban["boardId"] : void 0;
|
|
25409
25457
|
const activeBoardId2 = context.currentKanbanBoardId ?? (typeof metaBoardId === "string" ? metaBoardId : void 0);
|
|
25410
25458
|
if (!activeBoardId2 || board.id !== activeBoardId2 || board.lifecycle?.mode !== "managed") {
|
|
25411
25459
|
return [...context.todos];
|
|
25412
25460
|
}
|
|
25461
|
+
const ownerSessionId = options.sessionOwnerFromTags?.(board.tags);
|
|
25462
|
+
if (ownerSessionId && ownerSessionId !== (context.session?.id ?? "")) {
|
|
25463
|
+
return [...context.todos];
|
|
25464
|
+
}
|
|
25413
25465
|
const projectedTodos = orderTasksForTodos(
|
|
25414
25466
|
board,
|
|
25415
25467
|
board.tasks.filter(
|
|
@@ -25483,6 +25535,10 @@ function sessionBoardTitle(sessionId) {
|
|
|
25483
25535
|
function sessionBoardTags(sessionId) {
|
|
25484
25536
|
return ["session", SESSION_BOARD_TAG, sessionTag(sessionId)];
|
|
25485
25537
|
}
|
|
25538
|
+
function sessionIdFromTags(tags) {
|
|
25539
|
+
const tag = tags?.find((candidate) => candidate.startsWith("session:"));
|
|
25540
|
+
return tag?.slice("session:".length) || null;
|
|
25541
|
+
}
|
|
25486
25542
|
function sameColumns(columns) {
|
|
25487
25543
|
return columns.length === SESSION_KANBAN_COLUMNS.length && columns.every((column, index) => column.id === SESSION_KANBAN_COLUMNS[index]?.id);
|
|
25488
25544
|
}
|
|
@@ -25670,7 +25726,9 @@ function mirrorSessionTasksToKanban(projectRoot, tasks, sessionId) {
|
|
|
25670
25726
|
);
|
|
25671
25727
|
}
|
|
25672
25728
|
function applyManagedKanbanBoardToTodos2(context, board) {
|
|
25673
|
-
return applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors
|
|
25729
|
+
return applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors, {
|
|
25730
|
+
sessionOwnerFromTags: sessionIdFromTags
|
|
25731
|
+
});
|
|
25674
25732
|
}
|
|
25675
25733
|
|
|
25676
25734
|
// src/kanban-board-actions.ts
|
|
@@ -27643,7 +27701,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
27643
27701
|
};
|
|
27644
27702
|
}
|
|
27645
27703
|
args.push("--timestamps", service);
|
|
27646
|
-
return new Promise((
|
|
27704
|
+
return new Promise((resolve24) => {
|
|
27647
27705
|
let stdout = "";
|
|
27648
27706
|
let stderr = "";
|
|
27649
27707
|
const MAX = 2e5;
|
|
@@ -27659,7 +27717,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
27659
27717
|
if (settled) return;
|
|
27660
27718
|
settled = true;
|
|
27661
27719
|
clearTimeout(timer);
|
|
27662
|
-
|
|
27720
|
+
resolve24(result);
|
|
27663
27721
|
};
|
|
27664
27722
|
const child = spawn11("docker", args, {
|
|
27665
27723
|
cwd,
|
|
@@ -27704,7 +27762,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
27704
27762
|
}
|
|
27705
27763
|
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
27706
27764
|
var MAX_TAIL_LINES = 1e5;
|
|
27707
|
-
async function fileLogs(
|
|
27765
|
+
async function fileLogs(path50, lines, filterRe) {
|
|
27708
27766
|
const { createInterface } = await import("node:readline");
|
|
27709
27767
|
const { createReadStream: createReadStream2 } = await import("node:fs");
|
|
27710
27768
|
const entries = [];
|
|
@@ -27713,7 +27771,7 @@ async function fileLogs(path49, lines, filterRe) {
|
|
|
27713
27771
|
let writeIdx = 0;
|
|
27714
27772
|
let totalLines = 0;
|
|
27715
27773
|
const rl = createInterface({
|
|
27716
|
-
input: createReadStream2(
|
|
27774
|
+
input: createReadStream2(path50),
|
|
27717
27775
|
crlfDelay: Number.POSITIVE_INFINITY
|
|
27718
27776
|
});
|
|
27719
27777
|
for await (const line of rl) {
|
|
@@ -27734,7 +27792,7 @@ async function fileLogs(path49, lines, filterRe) {
|
|
|
27734
27792
|
if (parsed) entries.push(parsed);
|
|
27735
27793
|
}
|
|
27736
27794
|
return {
|
|
27737
|
-
source:
|
|
27795
|
+
source: path50,
|
|
27738
27796
|
entries,
|
|
27739
27797
|
total: entries.length,
|
|
27740
27798
|
truncated: totalLines > effLines,
|
|
@@ -27876,7 +27934,7 @@ var outdatedTool = {
|
|
|
27876
27934
|
}
|
|
27877
27935
|
};
|
|
27878
27936
|
function runOutdated(manager, args, cwd, signal) {
|
|
27879
|
-
return new Promise((
|
|
27937
|
+
return new Promise((resolve24) => {
|
|
27880
27938
|
let stdout = "";
|
|
27881
27939
|
let stderr = "";
|
|
27882
27940
|
const MAX = 1e5;
|
|
@@ -27901,10 +27959,10 @@ function runOutdated(manager, args, cwd, signal) {
|
|
|
27901
27959
|
});
|
|
27902
27960
|
child.on("close", (code) => {
|
|
27903
27961
|
const result = parseOutdatedOutput(stdout, code ?? 0);
|
|
27904
|
-
|
|
27962
|
+
resolve24(result);
|
|
27905
27963
|
});
|
|
27906
27964
|
child.on("error", (e) => {
|
|
27907
|
-
|
|
27965
|
+
resolve24({
|
|
27908
27966
|
exit_code: 1,
|
|
27909
27967
|
packages: [],
|
|
27910
27968
|
total: 0,
|
|
@@ -28223,7 +28281,7 @@ function runPatch(args, cwd, signal, fallback) {
|
|
|
28223
28281
|
});
|
|
28224
28282
|
}
|
|
28225
28283
|
function runPatchProcess(command, args, cwd, signal) {
|
|
28226
|
-
return new Promise((
|
|
28284
|
+
return new Promise((resolve24) => {
|
|
28227
28285
|
let stdout = "";
|
|
28228
28286
|
let stderr = "";
|
|
28229
28287
|
const env = { ...buildChildEnv8(), LANG: "C", LC_ALL: "C" };
|
|
@@ -28242,11 +28300,11 @@ function runPatchProcess(command, args, cwd, signal) {
|
|
|
28242
28300
|
});
|
|
28243
28301
|
child.on(
|
|
28244
28302
|
"close",
|
|
28245
|
-
(code) =>
|
|
28303
|
+
(code) => resolve24({ exitCode: code ?? 1, stdout, stderr, unavailable: false })
|
|
28246
28304
|
);
|
|
28247
28305
|
child.on(
|
|
28248
28306
|
"error",
|
|
28249
|
-
(e) =>
|
|
28307
|
+
(e) => resolve24({
|
|
28250
28308
|
exitCode: 1,
|
|
28251
28309
|
stdout: "",
|
|
28252
28310
|
stderr: e.message,
|
|
@@ -29035,9 +29093,428 @@ function mkResult(plan, ok, message, todos) {
|
|
|
29035
29093
|
return result;
|
|
29036
29094
|
}
|
|
29037
29095
|
|
|
29096
|
+
// src/pwsh.ts
|
|
29097
|
+
import { spawn as spawn14 } from "node:child_process";
|
|
29098
|
+
import * as fs36 from "node:fs";
|
|
29099
|
+
import * as os10 from "node:os";
|
|
29100
|
+
import * as path43 from "node:path";
|
|
29101
|
+
import { StringDecoder as StringDecoder3 } from "node:string_decoder";
|
|
29102
|
+
import {
|
|
29103
|
+
emitProcessCompleted as emitProcessCompleted4,
|
|
29104
|
+
emitProcessOutput as emitProcessOutput4,
|
|
29105
|
+
emitProcessStarted as emitProcessStarted4
|
|
29106
|
+
} from "@wrongstack/core/observability";
|
|
29107
|
+
init_output_spool();
|
|
29108
|
+
init_util();
|
|
29109
|
+
init_process_registry();
|
|
29110
|
+
init_win32_resolve();
|
|
29111
|
+
var MAX_OUTPUT4 = 32768;
|
|
29112
|
+
var DEFAULT_TIMEOUT_MS4 = 3e5;
|
|
29113
|
+
var STREAM_FLUSH_INTERVAL_MS2 = 200;
|
|
29114
|
+
var STREAM_FLUSH_BYTES2 = 4 * 1024;
|
|
29115
|
+
var MAX_QUEUE_CHUNKS2 = 500;
|
|
29116
|
+
var PWSH_TOOL_DESCRIPTION = "Execute a PowerShell command (`pwsh -Command`) in a fresh process on Windows and return its stdout/stderr. Stateless per call: pass `workdir` instead of using `cd`.";
|
|
29117
|
+
var PWSH_TOOL_USAGE_HINT = "Best practices & sandbox protocol for pwsh:\n- **Stateless**: No cwd, variables, or functions persist between calls. Use `workdir` to set the directory.\n- **Paths & Environs**: Use native Windows paths (`C:\\...`) and read env vars via `$env:NAME` (and `$env:DSH_*`).\n- **Exit Codes**: Non-zero exits are reported as `[exit code: N]`. On Windows, a force-killed command settles as exit code 1 (interruption).\n- **Background**: Set `run_in_background: true` for long-running processes (returns job id; manage via job_output/job_kill).\n- **Sandboxing**: Under read-only sandbox, pwsh runs in `ConstrainedLanguage` mode (prefer cmdlets, basic types; .NET reflection and COM fail). Workspace-write runs in `FullLanguage`.\n- **Escalation**: If denied by policy (`[sandbox: file access denied]`), retry once with `sandbox_permissions` plus a one-sentence `justification`.";
|
|
29118
|
+
function wrapPwshCommand(command) {
|
|
29119
|
+
const bootstrap = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;$ProgressPreference = 'SilentlyContinue';$ConfirmPreference = 'None';$WhatIfPreference = $false";
|
|
29120
|
+
return `${bootstrap}
|
|
29121
|
+
$ErrorActionPreference = 'Stop'
|
|
29122
|
+
${command}
|
|
29123
|
+
if ($LASTEXITCODE -is [int]) { exit $LASTEXITCODE }`;
|
|
29124
|
+
}
|
|
29125
|
+
var pwshTool = {
|
|
29126
|
+
name: "pwsh",
|
|
29127
|
+
category: "Shell",
|
|
29128
|
+
description: PWSH_TOOL_DESCRIPTION,
|
|
29129
|
+
usageHint: PWSH_TOOL_USAGE_HINT,
|
|
29130
|
+
selection: {
|
|
29131
|
+
doNotUseWhen: "the command is an allowlisted single binary (node, git, pnpm, tsc) needing no shell expansion or pipelines.",
|
|
29132
|
+
useInstead: ["exec"]
|
|
29133
|
+
},
|
|
29134
|
+
permission: "confirm",
|
|
29135
|
+
mutating: true,
|
|
29136
|
+
riskTier: "destructive",
|
|
29137
|
+
icon: "terminal",
|
|
29138
|
+
subjectKey: "command",
|
|
29139
|
+
capabilities: ["shell.arbitrary"],
|
|
29140
|
+
timeoutMs: 61e4,
|
|
29141
|
+
maxOutputBytes: MAX_OUTPUT4,
|
|
29142
|
+
estimatedDurationMs: 3e4,
|
|
29143
|
+
inputSchema: {
|
|
29144
|
+
type: "object",
|
|
29145
|
+
properties: {
|
|
29146
|
+
command: {
|
|
29147
|
+
type: "string",
|
|
29148
|
+
description: "The exact PowerShell command or script block to run."
|
|
29149
|
+
},
|
|
29150
|
+
workdir: {
|
|
29151
|
+
type: "string",
|
|
29152
|
+
description: "Absolute or project-relative path to the working directory for this command. Defaults to session working directory."
|
|
29153
|
+
},
|
|
29154
|
+
timeout_ms: {
|
|
29155
|
+
type: "integer",
|
|
29156
|
+
description: "Optional timeout for this specific command in milliseconds (default 300000, max 600000)."
|
|
29157
|
+
},
|
|
29158
|
+
run_in_background: {
|
|
29159
|
+
type: "boolean",
|
|
29160
|
+
description: "If true, launch the process in the background and return the job ID / PID immediately."
|
|
29161
|
+
},
|
|
29162
|
+
background: {
|
|
29163
|
+
type: "boolean",
|
|
29164
|
+
description: "Alias for run_in_background."
|
|
29165
|
+
},
|
|
29166
|
+
sandbox_permissions: {
|
|
29167
|
+
type: "string",
|
|
29168
|
+
description: "Escalation mode if retrying a sandbox-denied command (e.g., workspace-write)."
|
|
29169
|
+
},
|
|
29170
|
+
justification: {
|
|
29171
|
+
type: "string",
|
|
29172
|
+
description: "One-sentence justification when retrying a denied command with sandbox_permissions."
|
|
29173
|
+
}
|
|
29174
|
+
},
|
|
29175
|
+
required: ["command"]
|
|
29176
|
+
},
|
|
29177
|
+
async execute(input, ctx, opts) {
|
|
29178
|
+
let final;
|
|
29179
|
+
const executeStream = pwshTool.executeStream;
|
|
29180
|
+
if (!executeStream) throw new Error("pwshTool: stream execution unavailable");
|
|
29181
|
+
for await (const ev of executeStream(input, ctx, opts)) {
|
|
29182
|
+
if (ev.type === "final") final = ev.output;
|
|
29183
|
+
}
|
|
29184
|
+
if (!final) throw new Error("pwsh: stream ended without final event");
|
|
29185
|
+
return final;
|
|
29186
|
+
},
|
|
29187
|
+
async *executeStream(input, ctx, opts) {
|
|
29188
|
+
if (!input?.command) throw new Error("pwsh: command is required");
|
|
29189
|
+
const isBackground = !!(input.run_in_background || input.background);
|
|
29190
|
+
const registry = getProcessRegistry();
|
|
29191
|
+
if (!registry.beforeCall(isBackground)) {
|
|
29192
|
+
yield {
|
|
29193
|
+
type: "final",
|
|
29194
|
+
output: {
|
|
29195
|
+
output: "",
|
|
29196
|
+
exit_code: 1,
|
|
29197
|
+
timed_out: false,
|
|
29198
|
+
pid: null,
|
|
29199
|
+
error: "pwsh: circuit breaker open \u2014 too many consecutive failures or slow calls. Use /kill to inspect or /kill reset to recover."
|
|
29200
|
+
}
|
|
29201
|
+
};
|
|
29202
|
+
return;
|
|
29203
|
+
}
|
|
29204
|
+
const killCheck = await checkAndBlockKillCommand(input.command);
|
|
29205
|
+
if (killCheck.blocked) {
|
|
29206
|
+
yield {
|
|
29207
|
+
type: "final",
|
|
29208
|
+
output: {
|
|
29209
|
+
output: "",
|
|
29210
|
+
exit_code: 1,
|
|
29211
|
+
timed_out: false,
|
|
29212
|
+
pid: null,
|
|
29213
|
+
error: `pwsh: ${killCheck.reason}`
|
|
29214
|
+
}
|
|
29215
|
+
};
|
|
29216
|
+
return;
|
|
29217
|
+
}
|
|
29218
|
+
const isWin5 = os10.platform() === "win32";
|
|
29219
|
+
const bin = isWin5 ? resolvePowerShell("pwsh.exe") : "pwsh";
|
|
29220
|
+
const args = shellArgs("pwsh");
|
|
29221
|
+
const stdinBody = wrapPwshCommand(input.command);
|
|
29222
|
+
const env = buildChildEnv2(ctx.session?.id);
|
|
29223
|
+
let targetCwd = ctx.workingDir ?? ctx.projectRoot;
|
|
29224
|
+
if (input.workdir) {
|
|
29225
|
+
const resolved = path43.isAbsolute(input.workdir) ? input.workdir : path43.resolve(ctx.projectRoot, input.workdir);
|
|
29226
|
+
if (fs36.existsSync(resolved)) {
|
|
29227
|
+
targetCwd = resolved;
|
|
29228
|
+
}
|
|
29229
|
+
}
|
|
29230
|
+
const startedAt = Date.now();
|
|
29231
|
+
const detached = !isWin5;
|
|
29232
|
+
if (isBackground) {
|
|
29233
|
+
const child2 = spawn14(bin, args, {
|
|
29234
|
+
cwd: targetCwd,
|
|
29235
|
+
env,
|
|
29236
|
+
detached,
|
|
29237
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
29238
|
+
windowsHide: true
|
|
29239
|
+
});
|
|
29240
|
+
if (child2.stdin) {
|
|
29241
|
+
child2.stdin.write(stdinBody);
|
|
29242
|
+
child2.stdin.end();
|
|
29243
|
+
}
|
|
29244
|
+
const pid2 = child2.pid;
|
|
29245
|
+
if (typeof pid2 === "number") {
|
|
29246
|
+
registry.register({
|
|
29247
|
+
pid: pid2,
|
|
29248
|
+
name: "pwsh",
|
|
29249
|
+
command: redactCommand(input.command),
|
|
29250
|
+
startedAt: Date.now(),
|
|
29251
|
+
sessionId: ctx.session?.id,
|
|
29252
|
+
child: child2,
|
|
29253
|
+
processGroupLeader: detached && child2.pid === pid2,
|
|
29254
|
+
background: true
|
|
29255
|
+
});
|
|
29256
|
+
child2.on("close", () => registry.unregister(pid2));
|
|
29257
|
+
child2.on("error", () => {
|
|
29258
|
+
registry.unregister(pid2);
|
|
29259
|
+
registry.afterCall(Date.now() - startedAt, true, isBackground);
|
|
29260
|
+
});
|
|
29261
|
+
child2.unref();
|
|
29262
|
+
const jobId = `job_${pid2}`;
|
|
29263
|
+
ctx.recordSideEffect?.({
|
|
29264
|
+
toolUseId: `pwsh-bg-${Date.now()}`,
|
|
29265
|
+
toolName: "pwsh",
|
|
29266
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29267
|
+
input: { command: redactCommand(input.command), background: true },
|
|
29268
|
+
outcome: `started background job ${jobId} (PID: ${pid2})`,
|
|
29269
|
+
risk: "shell"
|
|
29270
|
+
});
|
|
29271
|
+
yield {
|
|
29272
|
+
type: "final",
|
|
29273
|
+
output: {
|
|
29274
|
+
output: `Background job started: ${jobId} (PID: ${pid2})
|
|
29275
|
+
Working directory: ${targetCwd}`,
|
|
29276
|
+
exit_code: null,
|
|
29277
|
+
timed_out: false,
|
|
29278
|
+
pid: pid2,
|
|
29279
|
+
job_id: jobId
|
|
29280
|
+
}
|
|
29281
|
+
};
|
|
29282
|
+
return;
|
|
29283
|
+
}
|
|
29284
|
+
yield {
|
|
29285
|
+
type: "final",
|
|
29286
|
+
output: {
|
|
29287
|
+
output: "",
|
|
29288
|
+
exit_code: 1,
|
|
29289
|
+
timed_out: false,
|
|
29290
|
+
pid: null,
|
|
29291
|
+
error: "pwsh: failed to obtain PID for background process"
|
|
29292
|
+
}
|
|
29293
|
+
};
|
|
29294
|
+
return;
|
|
29295
|
+
}
|
|
29296
|
+
const spool = createOutputSpool({ tool: "pwsh", thresholdBytes: MAX_OUTPUT4 });
|
|
29297
|
+
const child = spawn14(bin, args, {
|
|
29298
|
+
cwd: targetCwd,
|
|
29299
|
+
env,
|
|
29300
|
+
detached,
|
|
29301
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
29302
|
+
windowsHide: true
|
|
29303
|
+
});
|
|
29304
|
+
const pid = child.pid;
|
|
29305
|
+
let stdoutBytes = 0;
|
|
29306
|
+
let stderrBytes = 0;
|
|
29307
|
+
let telemetryCompleted = false;
|
|
29308
|
+
emitProcessStarted4({
|
|
29309
|
+
...pid !== void 0 ? { pid } : {},
|
|
29310
|
+
parentPid: process.pid,
|
|
29311
|
+
command: redactCommand(`${bin} ${args.join(" ")}`),
|
|
29312
|
+
args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
|
|
29313
|
+
cwd: targetCwd,
|
|
29314
|
+
background: false,
|
|
29315
|
+
startedAt: new Date(startedAt).toISOString()
|
|
29316
|
+
});
|
|
29317
|
+
const completeForeground = (exitCode, sig) => {
|
|
29318
|
+
if (telemetryCompleted) return;
|
|
29319
|
+
telemetryCompleted = true;
|
|
29320
|
+
emitProcessCompleted4({
|
|
29321
|
+
...pid !== void 0 ? { pid } : {},
|
|
29322
|
+
exitCode,
|
|
29323
|
+
...sig ? { signal: sig } : {},
|
|
29324
|
+
durationMs: Date.now() - startedAt,
|
|
29325
|
+
stdoutBytes,
|
|
29326
|
+
stderrBytes,
|
|
29327
|
+
timedOut,
|
|
29328
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29329
|
+
});
|
|
29330
|
+
};
|
|
29331
|
+
if (typeof pid === "number") {
|
|
29332
|
+
registry.register({
|
|
29333
|
+
pid,
|
|
29334
|
+
name: "pwsh",
|
|
29335
|
+
command: redactCommand(input.command),
|
|
29336
|
+
startedAt: Date.now(),
|
|
29337
|
+
sessionId: ctx.session?.id,
|
|
29338
|
+
child,
|
|
29339
|
+
processGroupLeader: detached && child.pid === pid
|
|
29340
|
+
});
|
|
29341
|
+
}
|
|
29342
|
+
if (child.stdin) {
|
|
29343
|
+
child.stdin.write(stdinBody);
|
|
29344
|
+
child.stdin.end();
|
|
29345
|
+
}
|
|
29346
|
+
const timeoutMs = Math.min(
|
|
29347
|
+
Math.max(1e3, input.timeout_ms ?? DEFAULT_TIMEOUT_MS4),
|
|
29348
|
+
6e5
|
|
29349
|
+
);
|
|
29350
|
+
let timedOut = false;
|
|
29351
|
+
const timers = [];
|
|
29352
|
+
const killWithTimeout = (timeout) => {
|
|
29353
|
+
if (isWin5) {
|
|
29354
|
+
if (typeof child.pid === "number" && child.exitCode === null) {
|
|
29355
|
+
const attempted = registry.kill(child.pid, { force: true, graceMs: timeout });
|
|
29356
|
+
if (!attempted) {
|
|
29357
|
+
try {
|
|
29358
|
+
child.kill();
|
|
29359
|
+
} catch {
|
|
29360
|
+
}
|
|
29361
|
+
}
|
|
29362
|
+
}
|
|
29363
|
+
return;
|
|
29364
|
+
}
|
|
29365
|
+
if (typeof child.pid === "number") {
|
|
29366
|
+
registry.kill(child.pid, { graceMs: timeout });
|
|
29367
|
+
} else {
|
|
29368
|
+
try {
|
|
29369
|
+
child.kill("SIGTERM");
|
|
29370
|
+
} catch {
|
|
29371
|
+
}
|
|
29372
|
+
}
|
|
29373
|
+
};
|
|
29374
|
+
const timer = setTimeout(() => {
|
|
29375
|
+
timedOut = true;
|
|
29376
|
+
killWithTimeout(2e3);
|
|
29377
|
+
}, timeoutMs);
|
|
29378
|
+
timers.push(timer);
|
|
29379
|
+
const onAbort = () => killWithTimeout(2e3);
|
|
29380
|
+
if (opts.signal.aborted) onAbort();
|
|
29381
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
29382
|
+
const queue = [];
|
|
29383
|
+
let resolveNext = null;
|
|
29384
|
+
const push = (c) => {
|
|
29385
|
+
if (resolveNext) {
|
|
29386
|
+
const r = resolveNext;
|
|
29387
|
+
resolveNext = null;
|
|
29388
|
+
r(c);
|
|
29389
|
+
} else {
|
|
29390
|
+
queue.push(c);
|
|
29391
|
+
}
|
|
29392
|
+
};
|
|
29393
|
+
const next = () => new Promise((resolve24) => {
|
|
29394
|
+
const c = queue.shift();
|
|
29395
|
+
if (c) resolve24(c);
|
|
29396
|
+
else resolveNext = resolve24;
|
|
29397
|
+
});
|
|
29398
|
+
let buf = "";
|
|
29399
|
+
let pending2 = "";
|
|
29400
|
+
let lastFlush = Date.now();
|
|
29401
|
+
const flush = () => {
|
|
29402
|
+
if (pending2.length === 0) return null;
|
|
29403
|
+
const text = pending2;
|
|
29404
|
+
pending2 = "";
|
|
29405
|
+
lastFlush = Date.now();
|
|
29406
|
+
return text;
|
|
29407
|
+
};
|
|
29408
|
+
let paused = false;
|
|
29409
|
+
const pauseIfFlooded = () => {
|
|
29410
|
+
if (!paused && queue.length >= MAX_QUEUE_CHUNKS2) {
|
|
29411
|
+
paused = true;
|
|
29412
|
+
child.stdout?.pause();
|
|
29413
|
+
child.stderr?.pause();
|
|
29414
|
+
}
|
|
29415
|
+
};
|
|
29416
|
+
const resumeIfDrained = () => {
|
|
29417
|
+
if (paused && queue.length < MAX_QUEUE_CHUNKS2) {
|
|
29418
|
+
paused = false;
|
|
29419
|
+
child.stdout?.resume();
|
|
29420
|
+
child.stderr?.resume();
|
|
29421
|
+
}
|
|
29422
|
+
};
|
|
29423
|
+
const stdoutDecoder = new StringDecoder3("utf8");
|
|
29424
|
+
const stderrDecoder = new StringDecoder3("utf8");
|
|
29425
|
+
const onData = (chunk, stream) => {
|
|
29426
|
+
const text = (stream === "stdout" ? stdoutDecoder : stderrDecoder).write(chunk);
|
|
29427
|
+
if (stream === "stdout") stdoutBytes += chunk.byteLength;
|
|
29428
|
+
else stderrBytes += chunk.byteLength;
|
|
29429
|
+
emitProcessOutput4({ pid: pid ?? 0, stream, chunk });
|
|
29430
|
+
if (buf.length < MAX_OUTPUT4) {
|
|
29431
|
+
buf += text.slice(0, MAX_OUTPUT4 - buf.length);
|
|
29432
|
+
}
|
|
29433
|
+
spool.write(text);
|
|
29434
|
+
pending2 += text;
|
|
29435
|
+
push({ kind: "data", text });
|
|
29436
|
+
pauseIfFlooded();
|
|
29437
|
+
};
|
|
29438
|
+
child.stdout?.on("data", (chunk) => onData(chunk, "stdout"));
|
|
29439
|
+
child.stderr?.on("data", (chunk) => onData(chunk, "stderr"));
|
|
29440
|
+
child.on("error", (err) => {
|
|
29441
|
+
for (const t of timers) clearTimeout(t);
|
|
29442
|
+
registry.afterCall(Date.now() - startedAt, true);
|
|
29443
|
+
completeForeground(1);
|
|
29444
|
+
push({ kind: "error", err });
|
|
29445
|
+
});
|
|
29446
|
+
child.on("close", (code, signal) => {
|
|
29447
|
+
for (const t of timers) clearTimeout(t);
|
|
29448
|
+
if (typeof pid === "number") registry.unregister(pid);
|
|
29449
|
+
registry.afterCall(Date.now() - startedAt, code !== 0 && code !== null);
|
|
29450
|
+
completeForeground(timedOut ? 124 : code ?? (signal ? 1 : 0), signal ?? void 0);
|
|
29451
|
+
const tail = stdoutDecoder.end() + stderrDecoder.end();
|
|
29452
|
+
if (tail) {
|
|
29453
|
+
if (buf.length < MAX_OUTPUT4) buf += tail.slice(0, MAX_OUTPUT4 - buf.length);
|
|
29454
|
+
spool.write(tail);
|
|
29455
|
+
pending2 += tail;
|
|
29456
|
+
}
|
|
29457
|
+
push({ kind: "end", code });
|
|
29458
|
+
});
|
|
29459
|
+
try {
|
|
29460
|
+
while (true) {
|
|
29461
|
+
const c = await next();
|
|
29462
|
+
resumeIfDrained();
|
|
29463
|
+
if (c.kind === "error") throw c.err;
|
|
29464
|
+
if (c.kind === "end") {
|
|
29465
|
+
const remainder = flush();
|
|
29466
|
+
if (remainder !== null) {
|
|
29467
|
+
yield { type: "partial_output", text: remainder };
|
|
29468
|
+
}
|
|
29469
|
+
const spooled = spool.finalize();
|
|
29470
|
+
let formattedOutput = normalizeCommandOutput(buf);
|
|
29471
|
+
if (c.code !== null && c.code !== 0 && !timedOut) {
|
|
29472
|
+
if (!formattedOutput.includes(`[exit code: ${c.code}]`)) {
|
|
29473
|
+
formattedOutput = formattedOutput ? `${formattedOutput}
|
|
29474
|
+
[exit code: ${c.code}]` : `[exit code: ${c.code}]`;
|
|
29475
|
+
}
|
|
29476
|
+
}
|
|
29477
|
+
const hint = !timedOut && typeof c.code === "number" && c.code !== 0 ? diagnoseBashism(input.command, "pwsh") : void 0;
|
|
29478
|
+
const danger = detectDanger("pwsh", [input.command]);
|
|
29479
|
+
const cautionText = danger.level === "caution" && danger.reasons.length > 0 ? `
|
|
29480
|
+
[caution: ${danger.reasons.join("; ")}]` : "";
|
|
29481
|
+
const finalResultText = formattedOutput + (spooled ? spoolNote(spooled) : "") + (hint ? `
|
|
29482
|
+
|
|
29483
|
+
${hint}` : "") + cautionText;
|
|
29484
|
+
ctx.recordSideEffect?.({
|
|
29485
|
+
toolUseId: `pwsh-${Date.now()}`,
|
|
29486
|
+
toolName: "pwsh",
|
|
29487
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29488
|
+
input: { command: redactCommand(input.command) },
|
|
29489
|
+
outcome: timedOut ? `timed out (exit ${c.code})` : `exit ${c.code}`,
|
|
29490
|
+
risk: "shell"
|
|
29491
|
+
});
|
|
29492
|
+
yield {
|
|
29493
|
+
type: "final",
|
|
29494
|
+
output: {
|
|
29495
|
+
output: finalResultText,
|
|
29496
|
+
exit_code: timedOut ? 1 : c.code,
|
|
29497
|
+
timed_out: timedOut,
|
|
29498
|
+
pid
|
|
29499
|
+
}
|
|
29500
|
+
};
|
|
29501
|
+
return;
|
|
29502
|
+
}
|
|
29503
|
+
const now = Date.now();
|
|
29504
|
+
if (pending2.length >= STREAM_FLUSH_BYTES2 || now - lastFlush >= STREAM_FLUSH_INTERVAL_MS2) {
|
|
29505
|
+
const text = flush();
|
|
29506
|
+
if (text) yield { type: "partial_output", text };
|
|
29507
|
+
}
|
|
29508
|
+
}
|
|
29509
|
+
} finally {
|
|
29510
|
+
for (const t of timers) clearTimeout(t);
|
|
29511
|
+
}
|
|
29512
|
+
}
|
|
29513
|
+
};
|
|
29514
|
+
|
|
29038
29515
|
// src/read.ts
|
|
29039
29516
|
init_util();
|
|
29040
|
-
import * as
|
|
29517
|
+
import * as fs37 from "node:fs/promises";
|
|
29041
29518
|
import { FsError, ToolValidationError as ToolValidationError8 } from "@wrongstack/core/types";
|
|
29042
29519
|
import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
|
|
29043
29520
|
var ADVANCED_MODE_META_KEY = "tools.read.advancedMode";
|
|
@@ -29097,7 +29574,7 @@ var readTool = {
|
|
|
29097
29574
|
const shouldIncludeSymbols = input.includeSymbols === true || input.includeSymbols !== false && ctx.meta[ADVANCED_MODE_META_KEY] === true;
|
|
29098
29575
|
let stat21;
|
|
29099
29576
|
try {
|
|
29100
|
-
stat21 = await
|
|
29577
|
+
stat21 = await fs37.stat(absPath);
|
|
29101
29578
|
} catch (err) {
|
|
29102
29579
|
const code = err.code;
|
|
29103
29580
|
if (code === "ENOENT") {
|
|
@@ -29149,7 +29626,7 @@ var readTool = {
|
|
|
29149
29626
|
...symResult2?.symbols ? { symbols: symResult2.symbols } : {}
|
|
29150
29627
|
};
|
|
29151
29628
|
}
|
|
29152
|
-
const buf = await
|
|
29629
|
+
const buf = await fs37.readFile(absPath);
|
|
29153
29630
|
if (isBinaryBuffer(buf)) {
|
|
29154
29631
|
throw new FsError({
|
|
29155
29632
|
message: `read: "${input.path}" appears to be binary`,
|
|
@@ -29315,9 +29792,9 @@ ${interesting.join("\n")}` : "symbols/imports: (none detected)"
|
|
|
29315
29792
|
}
|
|
29316
29793
|
|
|
29317
29794
|
// src/replace.ts
|
|
29318
|
-
import { spawn as
|
|
29319
|
-
import * as
|
|
29320
|
-
import * as
|
|
29795
|
+
import { spawn as spawn15 } from "node:child_process";
|
|
29796
|
+
import * as fs38 from "node:fs/promises";
|
|
29797
|
+
import * as path44 from "node:path";
|
|
29321
29798
|
import { ToolValidationError as ToolValidationError9 } from "@wrongstack/core/types";
|
|
29322
29799
|
import {
|
|
29323
29800
|
atomicWrite as atomicWrite4,
|
|
@@ -29400,14 +29877,14 @@ var replaceTool = {
|
|
|
29400
29877
|
const dryRun = input.dry_run ?? true;
|
|
29401
29878
|
const filesInput = Array.isArray(input.files) ? input.files.join(",") : input.files;
|
|
29402
29879
|
const fileList = await resolveFiles2(filesInput, ctx, globRe);
|
|
29403
|
-
const realRoot = await
|
|
29880
|
+
const realRoot = await fs38.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
29404
29881
|
const results = [];
|
|
29405
29882
|
let totalReplacements = 0;
|
|
29406
29883
|
let diffBytesUsed = 0;
|
|
29407
29884
|
let diffsOmitted = 0;
|
|
29408
29885
|
let diffsTruncated = 0;
|
|
29409
29886
|
for (const absPath of fileList) {
|
|
29410
|
-
const lstat2 = await
|
|
29887
|
+
const lstat2 = await fs38.lstat(absPath).catch((err) => {
|
|
29411
29888
|
if (err.code === "ENOENT") return null;
|
|
29412
29889
|
throw err;
|
|
29413
29890
|
});
|
|
@@ -29415,17 +29892,17 @@ var replaceTool = {
|
|
|
29415
29892
|
if (lstat2.isSymbolicLink()) continue;
|
|
29416
29893
|
let realPath;
|
|
29417
29894
|
try {
|
|
29418
|
-
realPath = await
|
|
29895
|
+
realPath = await fs38.realpath(absPath);
|
|
29419
29896
|
} catch {
|
|
29420
29897
|
continue;
|
|
29421
29898
|
}
|
|
29422
|
-
const rel =
|
|
29423
|
-
if (rel.startsWith("..") ||
|
|
29424
|
-
const stat21 = await
|
|
29899
|
+
const rel = path44.relative(realRoot, realPath);
|
|
29900
|
+
if (rel.startsWith("..") || path44.isAbsolute(rel)) continue;
|
|
29901
|
+
const stat21 = await fs38.stat(realPath).catch(() => null);
|
|
29425
29902
|
if (!stat21?.isFile()) continue;
|
|
29426
29903
|
let content;
|
|
29427
29904
|
try {
|
|
29428
|
-
const buf = await
|
|
29905
|
+
const buf = await fs38.readFile(realPath);
|
|
29429
29906
|
if (isBinaryBuffer(buf)) continue;
|
|
29430
29907
|
content = buf.toString("utf8");
|
|
29431
29908
|
} catch {
|
|
@@ -29448,7 +29925,7 @@ var replaceTool = {
|
|
|
29448
29925
|
if (!dryRun) {
|
|
29449
29926
|
const newContent = toStyle2(newContentLf, style);
|
|
29450
29927
|
await atomicWrite4(realPath, newContent, { mode: stat21.mode & 511 });
|
|
29451
|
-
const written = await
|
|
29928
|
+
const written = await fs38.stat(realPath).catch(() => null);
|
|
29452
29929
|
if (written) {
|
|
29453
29930
|
ctx.recordRead?.(realPath, written.mtimeMs, "write", sha256hex(newContent));
|
|
29454
29931
|
}
|
|
@@ -29548,8 +30025,8 @@ async function resolveFiles2(filesInput, ctx, extraGlob) {
|
|
|
29548
30025
|
const resolved = [];
|
|
29549
30026
|
for (const p of parts) {
|
|
29550
30027
|
const absPath = await safeResolveReal(p, ctx);
|
|
29551
|
-
if (extraGlob && !passesExtraGlob(extraGlob,
|
|
29552
|
-
const stat21 = await
|
|
30028
|
+
if (extraGlob && !passesExtraGlob(extraGlob, path44.basename(absPath), absPath)) continue;
|
|
30029
|
+
const stat21 = await fs38.stat(absPath).catch(() => null);
|
|
29553
30030
|
if (stat21?.isFile()) {
|
|
29554
30031
|
resolved.push(absPath);
|
|
29555
30032
|
}
|
|
@@ -29563,7 +30040,7 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
29563
30040
|
const { promise } = spawnRgFind(pattern, base);
|
|
29564
30041
|
const files = await promise;
|
|
29565
30042
|
if (extraGlob) {
|
|
29566
|
-
return files.filter((f) => passesExtraGlob(extraGlob,
|
|
30043
|
+
return files.filter((f) => passesExtraGlob(extraGlob, path44.basename(f), f));
|
|
29567
30044
|
}
|
|
29568
30045
|
return files;
|
|
29569
30046
|
} catch {
|
|
@@ -29573,24 +30050,24 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
29573
30050
|
}
|
|
29574
30051
|
var rgAvailabilityCache2;
|
|
29575
30052
|
function checkRg() {
|
|
29576
|
-
rgAvailabilityCache2 ??= new Promise((
|
|
30053
|
+
rgAvailabilityCache2 ??= new Promise((resolve24) => {
|
|
29577
30054
|
try {
|
|
29578
|
-
const p =
|
|
30055
|
+
const p = spawn15("rg", ["--version"], {
|
|
29579
30056
|
env: buildChildEnv9(),
|
|
29580
30057
|
stdio: "ignore",
|
|
29581
30058
|
windowsHide: true
|
|
29582
30059
|
});
|
|
29583
|
-
p.on("error", () =>
|
|
29584
|
-
p.on("close", (code) =>
|
|
30060
|
+
p.on("error", () => resolve24(false));
|
|
30061
|
+
p.on("close", (code) => resolve24(code === 0));
|
|
29585
30062
|
} catch {
|
|
29586
|
-
|
|
30063
|
+
resolve24(false);
|
|
29587
30064
|
}
|
|
29588
30065
|
});
|
|
29589
30066
|
return rgAvailabilityCache2;
|
|
29590
30067
|
}
|
|
29591
30068
|
function spawnRgFind(pattern, base) {
|
|
29592
30069
|
const args = ["--files", "--glob", pattern, base];
|
|
29593
|
-
const child =
|
|
30070
|
+
const child = spawn15("rg", args, {
|
|
29594
30071
|
signal: AbortSignal.timeout(3e4),
|
|
29595
30072
|
env: buildChildEnv9(),
|
|
29596
30073
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -29609,10 +30086,10 @@ function spawnRgFind(pattern, base) {
|
|
|
29609
30086
|
}
|
|
29610
30087
|
});
|
|
29611
30088
|
return {
|
|
29612
|
-
promise: new Promise((
|
|
30089
|
+
promise: new Promise((resolve24, reject) => {
|
|
29613
30090
|
child.on("error", reject);
|
|
29614
30091
|
child.on("close", () => {
|
|
29615
|
-
|
|
30092
|
+
resolve24(buf.split("\n").filter(Boolean));
|
|
29616
30093
|
});
|
|
29617
30094
|
})
|
|
29618
30095
|
};
|
|
@@ -29623,15 +30100,15 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
29623
30100
|
const walk = async (dir) => {
|
|
29624
30101
|
let entries;
|
|
29625
30102
|
try {
|
|
29626
|
-
entries = await
|
|
30103
|
+
entries = await fs38.readdir(dir, { withFileTypes: true });
|
|
29627
30104
|
} catch {
|
|
29628
30105
|
return;
|
|
29629
30106
|
}
|
|
29630
30107
|
for (const e of entries) {
|
|
29631
30108
|
if (DEFAULT_IGNORE4.includes(e.name)) continue;
|
|
29632
|
-
const full =
|
|
30109
|
+
const full = path44.join(dir, e.name);
|
|
29633
30110
|
try {
|
|
29634
|
-
const stat21 = await
|
|
30111
|
+
const stat21 = await fs38.lstat(full);
|
|
29635
30112
|
if (stat21.isSymbolicLink()) continue;
|
|
29636
30113
|
} catch {
|
|
29637
30114
|
continue;
|
|
@@ -29655,8 +30132,8 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
29655
30132
|
|
|
29656
30133
|
// src/scaffold.ts
|
|
29657
30134
|
init_util();
|
|
29658
|
-
import * as
|
|
29659
|
-
import * as
|
|
30135
|
+
import * as fs39 from "node:fs/promises";
|
|
30136
|
+
import * as path45 from "node:path";
|
|
29660
30137
|
import { atomicWrite as atomicWrite5 } from "@wrongstack/core/utils";
|
|
29661
30138
|
var BUILT_IN_TEMPLATES = {
|
|
29662
30139
|
"npm-package": {
|
|
@@ -29807,16 +30284,16 @@ async function handleBuiltIn(name, templateFiles, cwd, ctx, dryRun, vars) {
|
|
|
29807
30284
|
let filesCreated = 0;
|
|
29808
30285
|
for (const [filePath, content] of Object.entries(templateFiles)) {
|
|
29809
30286
|
const resolvedPath = substituteVars(filePath, name, vars);
|
|
29810
|
-
const joinedPath =
|
|
29811
|
-
const root =
|
|
29812
|
-
const target =
|
|
29813
|
-
const rel =
|
|
29814
|
-
if (rel.startsWith("..") ||
|
|
30287
|
+
const joinedPath = path45.join(cwd, resolvedPath);
|
|
30288
|
+
const root = path45.resolve(ctx.projectRoot);
|
|
30289
|
+
const target = path45.resolve(joinedPath);
|
|
30290
|
+
const rel = path45.relative(root, target);
|
|
30291
|
+
if (rel.startsWith("..") || path45.isAbsolute(rel)) {
|
|
29815
30292
|
throw new Error(`scaffold: generated path "${resolvedPath}" would escape project root`);
|
|
29816
30293
|
}
|
|
29817
30294
|
const fullPath = target;
|
|
29818
30295
|
if (!dryRun) {
|
|
29819
|
-
await
|
|
30296
|
+
await fs39.mkdir(path45.dirname(fullPath), { recursive: true });
|
|
29820
30297
|
await atomicWrite5(fullPath, substituteVars(content, name, vars));
|
|
29821
30298
|
}
|
|
29822
30299
|
files.push(resolvedPath);
|
|
@@ -30262,8 +30739,8 @@ function decodeHtmlEntities(text) {
|
|
|
30262
30739
|
}
|
|
30263
30740
|
|
|
30264
30741
|
// src/security-ast-scan-tool.ts
|
|
30265
|
-
import * as
|
|
30266
|
-
import * as
|
|
30742
|
+
import * as fs40 from "node:fs/promises";
|
|
30743
|
+
import * as path46 from "node:path";
|
|
30267
30744
|
import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
|
|
30268
30745
|
var SECRET_PATTERNS = [
|
|
30269
30746
|
{ name: "AWS Access Key", regex: /\b(AKIA[0-9A-Z]{16})\b/ },
|
|
@@ -30430,9 +30907,9 @@ var securityAstScanTool = {
|
|
|
30430
30907
|
let targetFile = input.file ?? "inline-code.ts";
|
|
30431
30908
|
let content = input.content;
|
|
30432
30909
|
if (!content && input.file) {
|
|
30433
|
-
const absPath =
|
|
30434
|
-
targetFile =
|
|
30435
|
-
content = await
|
|
30910
|
+
const absPath = path46.isAbsolute(input.file) ? input.file : path46.resolve(projectRoot, input.file);
|
|
30911
|
+
targetFile = path46.relative(projectRoot, absPath).replace(/\\/g, "/");
|
|
30912
|
+
content = await fs40.readFile(absPath, "utf8");
|
|
30436
30913
|
}
|
|
30437
30914
|
if (!content) {
|
|
30438
30915
|
return {
|
|
@@ -30480,7 +30957,7 @@ var securityAstScanTool = {
|
|
|
30480
30957
|
};
|
|
30481
30958
|
|
|
30482
30959
|
// src/set-working-dir.ts
|
|
30483
|
-
import * as
|
|
30960
|
+
import * as fs41 from "node:fs/promises";
|
|
30484
30961
|
import { toErrorMessage as toErrorMessage18 } from "@wrongstack/core/utils";
|
|
30485
30962
|
var setWorkingDirTool = {
|
|
30486
30963
|
name: "set_working_dir",
|
|
@@ -30520,7 +30997,7 @@ var setWorkingDirTool = {
|
|
|
30520
30997
|
}
|
|
30521
30998
|
let isDirectory = false;
|
|
30522
30999
|
try {
|
|
30523
|
-
isDirectory = (await
|
|
31000
|
+
isDirectory = (await fs41.stat(resolved)).isDirectory();
|
|
30524
31001
|
} catch {
|
|
30525
31002
|
isDirectory = false;
|
|
30526
31003
|
}
|
|
@@ -31055,7 +31532,7 @@ ${formatTaskList2(file.tasks)}` : file.tasks.length > 0 ? formatTaskList2(file.t
|
|
|
31055
31532
|
init_spawn_stream();
|
|
31056
31533
|
init_util();
|
|
31057
31534
|
init_legacy_bridge();
|
|
31058
|
-
import * as
|
|
31535
|
+
import * as path47 from "node:path";
|
|
31059
31536
|
var testTool = {
|
|
31060
31537
|
name: "test",
|
|
31061
31538
|
category: "Code Quality",
|
|
@@ -31162,7 +31639,7 @@ async function detectRunner(cwd) {
|
|
|
31162
31639
|
const candidates = ["vitest.config.ts", "jest.config.js", ".mocharc.json"];
|
|
31163
31640
|
for (const f of candidates) {
|
|
31164
31641
|
try {
|
|
31165
|
-
await stat21(
|
|
31642
|
+
await stat21(path47.join(cwd, f));
|
|
31166
31643
|
if (f.includes("vitest")) return "vitest";
|
|
31167
31644
|
if (f.includes("jest")) return "jest";
|
|
31168
31645
|
if (f.includes("mocha")) return "mocha";
|
|
@@ -31539,8 +32016,8 @@ var toolUseTool = {
|
|
|
31539
32016
|
|
|
31540
32017
|
// src/tree.ts
|
|
31541
32018
|
init_util();
|
|
31542
|
-
import * as
|
|
31543
|
-
import * as
|
|
32019
|
+
import * as fs42 from "node:fs/promises";
|
|
32020
|
+
import * as path48 from "node:path";
|
|
31544
32021
|
import { DEFAULT_WALK_IGNORE_DIRS as DEFAULT_WALK_IGNORE_DIRS4, expectDefined as expectDefined10 } from "@wrongstack/core/utils";
|
|
31545
32022
|
var DEFAULT_IGNORE5 = /* @__PURE__ */ new Set([
|
|
31546
32023
|
...DEFAULT_WALK_IGNORE_DIRS4,
|
|
@@ -31703,7 +32180,7 @@ var treeTool = {
|
|
|
31703
32180
|
async function walkDir(dir, depth, opts) {
|
|
31704
32181
|
opts.signal.throwIfAborted();
|
|
31705
32182
|
if (opts.retention.truncated) return;
|
|
31706
|
-
const entries = await
|
|
32183
|
+
const entries = await fs42.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
31707
32184
|
const filtered = entries.filter((e) => {
|
|
31708
32185
|
if (!opts.showHidden && e.name.startsWith(".")) return false;
|
|
31709
32186
|
if (opts.exclude.has(e.name)) return false;
|
|
@@ -31745,7 +32222,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
31745
32222
|
opts.retention.outputBytes += lineBytes;
|
|
31746
32223
|
if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {
|
|
31747
32224
|
const childPrefix = opts.prefix + connector;
|
|
31748
|
-
await walkDir(
|
|
32225
|
+
await walkDir(path48.join(dir, entry.name), depth + 1, {
|
|
31749
32226
|
...opts,
|
|
31750
32227
|
prefix: childPrefix,
|
|
31751
32228
|
isLast
|
|
@@ -31758,7 +32235,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
31758
32235
|
init_spawn_stream();
|
|
31759
32236
|
init_util();
|
|
31760
32237
|
init_legacy_bridge();
|
|
31761
|
-
import * as
|
|
32238
|
+
import * as path49 from "node:path";
|
|
31762
32239
|
var typecheckTool = {
|
|
31763
32240
|
name: "typecheck",
|
|
31764
32241
|
category: "Code Quality",
|
|
@@ -31870,8 +32347,8 @@ async function findTsConfig(cwd) {
|
|
|
31870
32347
|
const candidates = ["tsconfig.json", "tsconfig.base.json"];
|
|
31871
32348
|
for (const f of candidates) {
|
|
31872
32349
|
try {
|
|
31873
|
-
const s = await stat21(
|
|
31874
|
-
if (s.isFile()) return
|
|
32350
|
+
const s = await stat21(path49.join(cwd, f));
|
|
32351
|
+
if (s.isFile()) return path49.join(cwd, f);
|
|
31875
32352
|
} catch {
|
|
31876
32353
|
}
|
|
31877
32354
|
}
|
|
@@ -31879,7 +32356,7 @@ async function findTsConfig(cwd) {
|
|
|
31879
32356
|
}
|
|
31880
32357
|
|
|
31881
32358
|
// src/write.ts
|
|
31882
|
-
import * as
|
|
32359
|
+
import * as fs43 from "node:fs/promises";
|
|
31883
32360
|
import { ToolValidationError as ToolValidationError11 } from "@wrongstack/core/types";
|
|
31884
32361
|
import {
|
|
31885
32362
|
atomicWrite as atomicWrite6,
|
|
@@ -31956,14 +32433,14 @@ async function prepareWrite(input, ctx) {
|
|
|
31956
32433
|
let existed = false;
|
|
31957
32434
|
let prev = "";
|
|
31958
32435
|
try {
|
|
31959
|
-
const stat21 = await
|
|
32436
|
+
const stat21 = await fs43.stat(absPath);
|
|
31960
32437
|
existed = stat21.isFile();
|
|
31961
32438
|
if (existed) {
|
|
31962
32439
|
if (!ctx.hasRead(absPath)) {
|
|
31963
|
-
prev = await
|
|
32440
|
+
prev = await fs43.readFile(absPath, "utf8");
|
|
31964
32441
|
ctx.recordRead(absPath, stat21.mtimeMs, "write", sha256hex(prev));
|
|
31965
32442
|
} else {
|
|
31966
|
-
prev = await
|
|
32443
|
+
prev = await fs43.readFile(absPath, "utf8");
|
|
31967
32444
|
}
|
|
31968
32445
|
}
|
|
31969
32446
|
} catch (err) {
|
|
@@ -31984,7 +32461,7 @@ async function finishWrite(input, ctx, prepared, signal) {
|
|
|
31984
32461
|
const rawDiff = prepared.existed ? unifiedDiff3(prepared.prev, content, { fromFile: input.path, toFile: input.path }) : `+++ ${input.path}
|
|
31985
32462
|
+ (new file, ${content.split("\n").length} lines)`;
|
|
31986
32463
|
const { text: diff, truncated: diffTruncated } = truncateDiffPayload(rawDiff, MAX_DIFF_BYTES3);
|
|
31987
|
-
const stat21 = await
|
|
32464
|
+
const stat21 = await fs43.stat(prepared.absPath);
|
|
31988
32465
|
ctx.recordRead(prepared.absPath, stat21.mtimeMs, "write", sha256hex(content));
|
|
31989
32466
|
ctx.session.recordFileChange({
|
|
31990
32467
|
path: prepared.absPath,
|
|
@@ -32059,6 +32536,7 @@ var builtinTools = [
|
|
|
32059
32536
|
grepTool,
|
|
32060
32537
|
bashTool,
|
|
32061
32538
|
execTool,
|
|
32539
|
+
pwshTool,
|
|
32062
32540
|
fetchTool,
|
|
32063
32541
|
searchTool,
|
|
32064
32542
|
todoTool,
|