@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/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((resolve25) => {
|
|
1038
|
+
waiter = resolve25;
|
|
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 fs45 = await import("node:fs/promises");
|
|
1142
1142
|
try {
|
|
1143
|
-
const raw = await
|
|
1143
|
+
const raw = await fs45.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 fs45.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 path51 of after) {
|
|
4144
|
+
if (!beforeSet.has(path51)) changed.add(path51);
|
|
4145
4145
|
}
|
|
4146
|
-
for (const
|
|
4147
|
-
if (!afterSet.has(
|
|
4146
|
+
for (const path51 of before) {
|
|
4147
|
+
if (!afterSet.has(path51)) changed.add(path51);
|
|
4148
4148
|
}
|
|
4149
4149
|
if (beforeSizes && afterSizes) {
|
|
4150
|
-
for (const
|
|
4151
|
-
if (beforeSizes.get(
|
|
4150
|
+
for (const path51 of after) {
|
|
4151
|
+
if (beforeSizes.get(path51) !== afterSizes.get(path51)) changed.add(path51);
|
|
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
|
+
(resolve25, 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
|
+
resolve25({ 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((resolve25) => {
|
|
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
|
+
resolve25(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((resolve25, 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
|
+
resolve25({ code, stdout });
|
|
6403
6403
|
});
|
|
6404
6404
|
});
|
|
6405
6405
|
}
|
|
@@ -7788,6 +7788,40 @@ var RULES = [
|
|
|
7788
7788
|
},
|
|
7789
7789
|
reason: "Remove-Item with -Recurse -Force"
|
|
7790
7790
|
},
|
|
7791
|
+
// ----- Windows PowerShell Disk & Volume destruction -----
|
|
7792
|
+
{
|
|
7793
|
+
id: "powershell-disk-volume-destroy",
|
|
7794
|
+
level: "destructive",
|
|
7795
|
+
test: (cmd, args) => {
|
|
7796
|
+
if (cmd !== "powershell" && cmd !== "pwsh") return false;
|
|
7797
|
+
return args.some(
|
|
7798
|
+
(a) => /^(?:Format-Volume|Clear-Disk|Initialize-Disk|Remove-Partition|Clear-Volume)(?:\s|$)/i.test(a)
|
|
7799
|
+
);
|
|
7800
|
+
},
|
|
7801
|
+
reason: "PowerShell disk/volume partition destruction"
|
|
7802
|
+
},
|
|
7803
|
+
// ----- Windows PowerShell System Restart / Shutdown -----
|
|
7804
|
+
{
|
|
7805
|
+
id: "powershell-stop-restart-computer",
|
|
7806
|
+
level: "destructive",
|
|
7807
|
+
test: (cmd, args) => {
|
|
7808
|
+
if (cmd !== "powershell" && cmd !== "pwsh") return false;
|
|
7809
|
+
return args.some((a) => /^(?:Stop-Computer|Restart-Computer)(?:\s|$)/i.test(a));
|
|
7810
|
+
},
|
|
7811
|
+
reason: "PowerShell system shutdown or restart"
|
|
7812
|
+
},
|
|
7813
|
+
// ----- Windows PowerShell ExecutionPolicy / Payload evasion -----
|
|
7814
|
+
{
|
|
7815
|
+
id: "powershell-execution-policy-bypass",
|
|
7816
|
+
level: "caution",
|
|
7817
|
+
test: (cmd, args) => {
|
|
7818
|
+
if (cmd !== "powershell" && cmd !== "pwsh") return false;
|
|
7819
|
+
return args.some(
|
|
7820
|
+
(a) => /Set-ExecutionPolicy\s+(?:Bypass|Unrestricted)|-(?:EncodedCommand|enc)\b/i.test(a)
|
|
7821
|
+
);
|
|
7822
|
+
},
|
|
7823
|
+
reason: "PowerShell execution policy bypass or encoded command"
|
|
7824
|
+
},
|
|
7791
7825
|
// ----- find -exec / -ok / -execdir -----
|
|
7792
7826
|
{
|
|
7793
7827
|
id: "find-exec",
|
|
@@ -8108,8 +8142,8 @@ function normalizeShell(value) {
|
|
|
8108
8142
|
if (v === "pwsh" || v === "pwsh.exe") return "pwsh";
|
|
8109
8143
|
return void 0;
|
|
8110
8144
|
}
|
|
8111
|
-
function resolveSessionShell(
|
|
8112
|
-
if (
|
|
8145
|
+
function resolveSessionShell(platform7, env, deps = {}) {
|
|
8146
|
+
if (platform7 !== "win32") return void 0;
|
|
8113
8147
|
const override = normalizeShell(env.get("WRONGSTACK_SHELL"));
|
|
8114
8148
|
if (override) return override;
|
|
8115
8149
|
const hasBinary = deps.hasBinary ?? ((bin) => resolveWin32Command(bin) !== bin);
|
|
@@ -8119,11 +8153,11 @@ function resolveSessionShell(platform6, env, deps = {}) {
|
|
|
8119
8153
|
}
|
|
8120
8154
|
function ensureSessionShell(opts = {}) {
|
|
8121
8155
|
const env = opts.env ?? process.env;
|
|
8122
|
-
const
|
|
8123
|
-
if (
|
|
8156
|
+
const platform7 = opts.platform ?? process.platform;
|
|
8157
|
+
if (platform7 !== "win32") return void 0;
|
|
8124
8158
|
const existing = normalizeShell(env["WRONGSTACK_SHELL"]);
|
|
8125
8159
|
if (existing) return existing;
|
|
8126
|
-
const chosen = resolveSessionShell(
|
|
8160
|
+
const chosen = resolveSessionShell(platform7, { get: (k) => env[k] }, { hasBinary: opts.hasBinary }) ?? "cmd";
|
|
8127
8161
|
env["WRONGSTACK_SHELL"] = chosen;
|
|
8128
8162
|
return chosen;
|
|
8129
8163
|
}
|
|
@@ -8989,6 +9023,18 @@ function parseKillCommand(command) {
|
|
|
8989
9023
|
originalCommand: command
|
|
8990
9024
|
};
|
|
8991
9025
|
}
|
|
9026
|
+
const wmicPidMatch = normalized.match(
|
|
9027
|
+
/^wmic\s+process\s+where\s+['"]?processid\s*=\s*['"]?(\d+)/i
|
|
9028
|
+
);
|
|
9029
|
+
if (wmicPidMatch?.[1]) {
|
|
9030
|
+
return {
|
|
9031
|
+
pid: parseInt(wmicPidMatch[1], 10),
|
|
9032
|
+
signal: "FORCE",
|
|
9033
|
+
isGroupKill: false,
|
|
9034
|
+
isAllKill: false,
|
|
9035
|
+
originalCommand: command
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
8992
9038
|
const killScriptMatch = normalized.match(SCRIPT_KILL_RE);
|
|
8993
9039
|
if (killScriptMatch) {
|
|
8994
9040
|
return {
|
|
@@ -9108,7 +9154,9 @@ async function isKillProtected(kill) {
|
|
|
9108
9154
|
return protectedPids.length > 0;
|
|
9109
9155
|
}
|
|
9110
9156
|
if (kill.pid !== void 0) {
|
|
9111
|
-
|
|
9157
|
+
if (await registry.shouldBlockKill(kill.pid)) return true;
|
|
9158
|
+
if (kill.pid === process.pid || kill.pid === process.ppid) return true;
|
|
9159
|
+
return false;
|
|
9112
9160
|
}
|
|
9113
9161
|
return false;
|
|
9114
9162
|
}
|
|
@@ -9155,8 +9203,8 @@ async function checkAndBlockKillCommand(command) {
|
|
|
9155
9203
|
|
|
9156
9204
|
// src/_shell-pick.ts
|
|
9157
9205
|
var POSIX_DEFAULT = "cmd";
|
|
9158
|
-
function pickShell(
|
|
9159
|
-
if (
|
|
9206
|
+
function pickShell(platform7, command, env) {
|
|
9207
|
+
if (platform7 !== "win32") return POSIX_DEFAULT;
|
|
9160
9208
|
const override = env.get("WRONGSTACK_SHELL")?.trim().toLowerCase();
|
|
9161
9209
|
if (override === "cmd" || override === "cmd.exe") return "cmd";
|
|
9162
9210
|
if (override === "powershell" || override === "powershell.exe") return "powershell";
|
|
@@ -9615,10 +9663,10 @@ var bashTool = {
|
|
|
9615
9663
|
queue.push(c);
|
|
9616
9664
|
}
|
|
9617
9665
|
};
|
|
9618
|
-
const next = () => new Promise((
|
|
9666
|
+
const next = () => new Promise((resolve25) => {
|
|
9619
9667
|
const c = queue.shift();
|
|
9620
|
-
if (c)
|
|
9621
|
-
else resolveNext =
|
|
9668
|
+
if (c) resolve25(c);
|
|
9669
|
+
else resolveNext = resolve25;
|
|
9622
9670
|
});
|
|
9623
9671
|
let lastFlush = Date.now();
|
|
9624
9672
|
const flush = () => {
|
|
@@ -10071,11 +10119,11 @@ var BrowserArtifactStore = class {
|
|
|
10071
10119
|
};
|
|
10072
10120
|
async function hashFile(target) {
|
|
10073
10121
|
const hash = createHash3("sha256");
|
|
10074
|
-
await new Promise((
|
|
10122
|
+
await new Promise((resolve25, reject) => {
|
|
10075
10123
|
const stream = createReadStream(target);
|
|
10076
10124
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
10077
10125
|
stream.once("error", reject);
|
|
10078
|
-
stream.once("end",
|
|
10126
|
+
stream.once("end", resolve25);
|
|
10079
10127
|
});
|
|
10080
10128
|
return hash.digest("hex");
|
|
10081
10129
|
}
|
|
@@ -10230,7 +10278,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
10230
10278
|
async start() {
|
|
10231
10279
|
if (this.url) return this.url;
|
|
10232
10280
|
if (this.startPromise) return this.startPromise;
|
|
10233
|
-
this.startPromise = new Promise((
|
|
10281
|
+
this.startPromise = new Promise((resolve25, reject) => {
|
|
10234
10282
|
const onError = (error) => {
|
|
10235
10283
|
this.server.off("listening", onListening);
|
|
10236
10284
|
reject(error);
|
|
@@ -10243,7 +10291,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
10243
10291
|
return;
|
|
10244
10292
|
}
|
|
10245
10293
|
this.url = `http://127.0.0.1:${address.port}`;
|
|
10246
|
-
|
|
10294
|
+
resolve25(this.url);
|
|
10247
10295
|
};
|
|
10248
10296
|
this.server.once("error", onError);
|
|
10249
10297
|
this.server.once("listening", onListening);
|
|
@@ -10258,7 +10306,7 @@ var BrowserNetworkGuardProxy = class {
|
|
|
10258
10306
|
for (const socket of this.sockets) socket.destroy();
|
|
10259
10307
|
this.sockets.clear();
|
|
10260
10308
|
if (!this.server.listening) return;
|
|
10261
|
-
await new Promise((
|
|
10309
|
+
await new Promise((resolve25) => this.server.close(() => resolve25()));
|
|
10262
10310
|
}
|
|
10263
10311
|
async forwardHttp(request2, response) {
|
|
10264
10312
|
try {
|
|
@@ -10831,7 +10879,7 @@ function pushBounded(target, value, limit) {
|
|
|
10831
10879
|
}
|
|
10832
10880
|
async function abortable(signal, operation, onAbort) {
|
|
10833
10881
|
signal.throwIfAborted();
|
|
10834
|
-
return new Promise((
|
|
10882
|
+
return new Promise((resolve25, reject) => {
|
|
10835
10883
|
let settled = false;
|
|
10836
10884
|
let aborting = false;
|
|
10837
10885
|
const finish = (fn) => {
|
|
@@ -10849,7 +10897,7 @@ async function abortable(signal, operation, onAbort) {
|
|
|
10849
10897
|
signal.addEventListener("abort", abort, { once: true });
|
|
10850
10898
|
operation().then(
|
|
10851
10899
|
(value) => {
|
|
10852
|
-
if (!aborting) finish(() =>
|
|
10900
|
+
if (!aborting) finish(() => resolve25(value));
|
|
10853
10901
|
},
|
|
10854
10902
|
(err) => {
|
|
10855
10903
|
if (!aborting) finish(() => reject(err));
|
|
@@ -14387,8 +14435,8 @@ function isProjectIndexServerHealth(value) {
|
|
|
14387
14435
|
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";
|
|
14388
14436
|
}
|
|
14389
14437
|
function delay(ms) {
|
|
14390
|
-
return new Promise((
|
|
14391
|
-
const timer = setTimeout(
|
|
14438
|
+
return new Promise((resolve25) => {
|
|
14439
|
+
const timer = setTimeout(resolve25, ms);
|
|
14392
14440
|
timer.unref?.();
|
|
14393
14441
|
});
|
|
14394
14442
|
}
|
|
@@ -14594,7 +14642,7 @@ var ProjectServerConnection = class {
|
|
|
14594
14642
|
return Promise.reject(new Error("codebase-index server connection is not available"));
|
|
14595
14643
|
}
|
|
14596
14644
|
const id = this.nextId++;
|
|
14597
|
-
return new Promise((
|
|
14645
|
+
return new Promise((resolve25, reject) => {
|
|
14598
14646
|
const timer = setTimeout(() => {
|
|
14599
14647
|
const entry = this.pending.get(id);
|
|
14600
14648
|
if (!entry) return;
|
|
@@ -14617,7 +14665,7 @@ var ProjectServerConnection = class {
|
|
|
14617
14665
|
entry.reject(cancellationError(signal));
|
|
14618
14666
|
} : void 0;
|
|
14619
14667
|
this.pending.set(id, {
|
|
14620
|
-
resolve:
|
|
14668
|
+
resolve: resolve25,
|
|
14621
14669
|
reject,
|
|
14622
14670
|
timer,
|
|
14623
14671
|
signal,
|
|
@@ -14686,7 +14734,7 @@ var ProjectServerConnection = class {
|
|
|
14686
14734
|
this.binaryBuffer = [];
|
|
14687
14735
|
this.useBinary = false;
|
|
14688
14736
|
this.textDecoder = null;
|
|
14689
|
-
return new Promise((
|
|
14737
|
+
return new Promise((resolve25, reject) => {
|
|
14690
14738
|
const socket = net3.createConnection(this.endpoint);
|
|
14691
14739
|
this.socket = socket;
|
|
14692
14740
|
const timer = setTimeout(() => {
|
|
@@ -14698,7 +14746,7 @@ var ProjectServerConnection = class {
|
|
|
14698
14746
|
clearTimeout(timer);
|
|
14699
14747
|
this.connectResolve = null;
|
|
14700
14748
|
this.connectReject = null;
|
|
14701
|
-
|
|
14749
|
+
resolve25();
|
|
14702
14750
|
};
|
|
14703
14751
|
const finishReject = (error) => {
|
|
14704
14752
|
clearTimeout(timer);
|
|
@@ -15747,9 +15795,9 @@ var ParserWorkerPool = class {
|
|
|
15747
15795
|
for (let i = 0; i < files.length; i++) {
|
|
15748
15796
|
chunks[i % workerCount].push(files[i]);
|
|
15749
15797
|
}
|
|
15750
|
-
return new Promise((
|
|
15798
|
+
return new Promise((resolve25, reject) => {
|
|
15751
15799
|
this.pending.set(batchId, {
|
|
15752
|
-
resolve:
|
|
15800
|
+
resolve: resolve25,
|
|
15753
15801
|
reject,
|
|
15754
15802
|
accumulated: [],
|
|
15755
15803
|
expectedWorkers: workerCount,
|
|
@@ -15780,10 +15828,10 @@ var ParserWorkerPool = class {
|
|
|
15780
15828
|
await Promise.allSettled(
|
|
15781
15829
|
workers.map(
|
|
15782
15830
|
(w) => Promise.race([
|
|
15783
|
-
new Promise((
|
|
15784
|
-
w.once("exit", () =>
|
|
15831
|
+
new Promise((resolve25) => {
|
|
15832
|
+
w.once("exit", () => resolve25());
|
|
15785
15833
|
}),
|
|
15786
|
-
new Promise((
|
|
15834
|
+
new Promise((resolve25) => setTimeout(() => resolve25(), 2e3))
|
|
15787
15835
|
]).then(() => {
|
|
15788
15836
|
if (!w.threadId) return;
|
|
15789
15837
|
return w.terminate().catch(() => {
|
|
@@ -15844,7 +15892,7 @@ function shouldUseParserWorkerPool(candidateFileCount, parseBatchCount) {
|
|
|
15844
15892
|
return !isFrugalPerf() && candidateFileCount >= WORKER_POOL_THRESHOLD && parseBatchCount > 1;
|
|
15845
15893
|
}
|
|
15846
15894
|
function yieldEventLoop() {
|
|
15847
|
-
return new Promise((
|
|
15895
|
+
return new Promise((resolve25) => setImmediate(resolve25));
|
|
15848
15896
|
}
|
|
15849
15897
|
function throwIfAborted(signal) {
|
|
15850
15898
|
if (!signal?.aborted) return;
|
|
@@ -15876,7 +15924,7 @@ function normalizeComparablePath(value) {
|
|
|
15876
15924
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
15877
15925
|
}
|
|
15878
15926
|
function gitOutput(projectRoot, args) {
|
|
15879
|
-
return new Promise((
|
|
15927
|
+
return new Promise((resolve25, reject) => {
|
|
15880
15928
|
execFile(
|
|
15881
15929
|
"git",
|
|
15882
15930
|
["-C", projectRoot, ...args],
|
|
@@ -15887,7 +15935,7 @@ function gitOutput(projectRoot, args) {
|
|
|
15887
15935
|
},
|
|
15888
15936
|
(error, stdout) => {
|
|
15889
15937
|
if (error) reject(error);
|
|
15890
|
-
else
|
|
15938
|
+
else resolve25(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
|
|
15891
15939
|
}
|
|
15892
15940
|
);
|
|
15893
15941
|
});
|
|
@@ -16687,7 +16735,7 @@ function callIndexOp(op, args, opts) {
|
|
|
16687
16735
|
opts.signal.reason instanceof Error ? opts.signal.reason : new Error("Indexing cancelled")
|
|
16688
16736
|
);
|
|
16689
16737
|
}
|
|
16690
|
-
return new Promise((
|
|
16738
|
+
return new Promise((resolve25, reject) => {
|
|
16691
16739
|
const id = nextRpcId++;
|
|
16692
16740
|
const timer = setTimeout(() => {
|
|
16693
16741
|
pending.delete(id);
|
|
@@ -16709,7 +16757,7 @@ function callIndexOp(op, args, opts) {
|
|
|
16709
16757
|
pending.set(id, {
|
|
16710
16758
|
resolve: (v) => {
|
|
16711
16759
|
cleanup();
|
|
16712
|
-
|
|
16760
|
+
resolve25(v);
|
|
16713
16761
|
},
|
|
16714
16762
|
reject: (e) => {
|
|
16715
16763
|
cleanup();
|
|
@@ -20279,7 +20327,7 @@ function findGitDir(cwd) {
|
|
|
20279
20327
|
return null;
|
|
20280
20328
|
}
|
|
20281
20329
|
function runGit(args, cwd, signal) {
|
|
20282
|
-
return new Promise((
|
|
20330
|
+
return new Promise((resolve25) => {
|
|
20283
20331
|
let stdout = "";
|
|
20284
20332
|
let stderr = "";
|
|
20285
20333
|
const child = spawn7("git", args, {
|
|
@@ -20295,8 +20343,8 @@ function runGit(args, cwd, signal) {
|
|
|
20295
20343
|
child.stderr?.on("data", (c) => {
|
|
20296
20344
|
stderr += c.toString();
|
|
20297
20345
|
});
|
|
20298
|
-
child.on("close", (code) =>
|
|
20299
|
-
child.on("error", (e) =>
|
|
20346
|
+
child.on("close", (code) => resolve25({ stdout, stderr, exitCode: code ?? 0 }));
|
|
20347
|
+
child.on("error", (e) => resolve25({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
20300
20348
|
});
|
|
20301
20349
|
}
|
|
20302
20350
|
async function fileDiff(input, ctx, _signal) {
|
|
@@ -22611,7 +22659,7 @@ var execTool = {
|
|
|
22611
22659
|
}
|
|
22612
22660
|
};
|
|
22613
22661
|
function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
|
|
22614
|
-
return new Promise((
|
|
22662
|
+
return new Promise((resolve25) => {
|
|
22615
22663
|
let stdout = "";
|
|
22616
22664
|
let stderr = "";
|
|
22617
22665
|
let killed = false;
|
|
@@ -22619,7 +22667,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
|
|
|
22619
22667
|
const finish = (result) => {
|
|
22620
22668
|
if (resolvedOnce.value) return;
|
|
22621
22669
|
resolvedOnce.value = true;
|
|
22622
|
-
|
|
22670
|
+
resolve25(result);
|
|
22623
22671
|
};
|
|
22624
22672
|
const startedAt = Date.now();
|
|
22625
22673
|
let stdoutBytes = 0;
|
|
@@ -23295,10 +23343,10 @@ function parseFormatterCounts(fixer, output) {
|
|
|
23295
23343
|
};
|
|
23296
23344
|
}
|
|
23297
23345
|
async function detectFixer(cwd) {
|
|
23298
|
-
const
|
|
23346
|
+
const fs45 = await import("node:fs/promises");
|
|
23299
23347
|
const exists = async (file) => {
|
|
23300
23348
|
try {
|
|
23301
|
-
await
|
|
23349
|
+
await fs45.stat(`${cwd}/${file}`);
|
|
23302
23350
|
return true;
|
|
23303
23351
|
} catch {
|
|
23304
23352
|
return false;
|
|
@@ -23321,7 +23369,7 @@ async function detectFixer(cwd) {
|
|
|
23321
23369
|
if (await exists(cfg)) return "prettier";
|
|
23322
23370
|
}
|
|
23323
23371
|
try {
|
|
23324
|
-
const raw = await
|
|
23372
|
+
const raw = await fs45.readFile(`${cwd}/package.json`, "utf8");
|
|
23325
23373
|
const pkg = JSON.parse(raw);
|
|
23326
23374
|
if (pkg["prettier"] !== void 0) return "prettier";
|
|
23327
23375
|
} catch {
|
|
@@ -23589,7 +23637,7 @@ function buildArgs(input) {
|
|
|
23589
23637
|
}
|
|
23590
23638
|
}
|
|
23591
23639
|
function runGit2(args, cwd, signal) {
|
|
23592
|
-
return new Promise((
|
|
23640
|
+
return new Promise((resolve25) => {
|
|
23593
23641
|
let stdout = "";
|
|
23594
23642
|
let stderr = "";
|
|
23595
23643
|
const child = spawn9("git", args, {
|
|
@@ -23610,7 +23658,7 @@ function runGit2(args, cwd, signal) {
|
|
|
23610
23658
|
}
|
|
23611
23659
|
});
|
|
23612
23660
|
child.on("error", (err) => {
|
|
23613
|
-
|
|
23661
|
+
resolve25({
|
|
23614
23662
|
command: args[0],
|
|
23615
23663
|
stdout: normalizeCommandOutput(stdout),
|
|
23616
23664
|
stderr: err.message,
|
|
@@ -23619,7 +23667,7 @@ function runGit2(args, cwd, signal) {
|
|
|
23619
23667
|
});
|
|
23620
23668
|
});
|
|
23621
23669
|
child.on("close", (code) => {
|
|
23622
|
-
|
|
23670
|
+
resolve25({
|
|
23623
23671
|
command: args[0],
|
|
23624
23672
|
stdout: normalizeCommandOutput(stdout),
|
|
23625
23673
|
stderr: normalizeCommandOutput(stderr),
|
|
@@ -24032,7 +24080,7 @@ var grepTool = {
|
|
|
24032
24080
|
};
|
|
24033
24081
|
var rgAvailabilityCache;
|
|
24034
24082
|
function detectRg() {
|
|
24035
|
-
rgAvailabilityCache ??= new Promise((
|
|
24083
|
+
rgAvailabilityCache ??= new Promise((resolve25) => {
|
|
24036
24084
|
try {
|
|
24037
24085
|
const p = spawn10("rg", ["--version"], {
|
|
24038
24086
|
env: buildChildEnv5(),
|
|
@@ -24040,10 +24088,10 @@ function detectRg() {
|
|
|
24040
24088
|
signal: AbortSignal.timeout(1e4),
|
|
24041
24089
|
windowsHide: true
|
|
24042
24090
|
});
|
|
24043
|
-
p.on("error", () =>
|
|
24044
|
-
p.on("close", (code) =>
|
|
24091
|
+
p.on("error", () => resolve25(false));
|
|
24092
|
+
p.on("close", (code) => resolve25(code === 0));
|
|
24045
24093
|
} catch {
|
|
24046
|
-
|
|
24094
|
+
resolve25(false);
|
|
24047
24095
|
}
|
|
24048
24096
|
});
|
|
24049
24097
|
return rgAvailabilityCache;
|
|
@@ -25085,60 +25133,60 @@ function jmespathSearch(data, query) {
|
|
|
25085
25133
|
}
|
|
25086
25134
|
function validateJsonSchema(data, schema) {
|
|
25087
25135
|
const errors = [];
|
|
25088
|
-
function check(value, s,
|
|
25136
|
+
function check(value, s, path51) {
|
|
25089
25137
|
if (s["type"]) {
|
|
25090
25138
|
const expectedType = s["type"];
|
|
25091
25139
|
const actualType = Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
|
|
25092
25140
|
if (expectedType === "integer") {
|
|
25093
|
-
if (!Number.isInteger(value)) errors.push(`${
|
|
25141
|
+
if (!Number.isInteger(value)) errors.push(`${path51}: expected integer, got ${actualType}`);
|
|
25094
25142
|
} else if (expectedType !== actualType) {
|
|
25095
|
-
errors.push(`${
|
|
25143
|
+
errors.push(`${path51}: expected ${expectedType}, got ${actualType}`);
|
|
25096
25144
|
}
|
|
25097
25145
|
}
|
|
25098
25146
|
if (typeof value === "string" && s["format"] === "uri" && value) {
|
|
25099
25147
|
try {
|
|
25100
25148
|
new URL(value);
|
|
25101
25149
|
} catch {
|
|
25102
|
-
errors.push(`${
|
|
25150
|
+
errors.push(`${path51}: not a valid URI`);
|
|
25103
25151
|
}
|
|
25104
25152
|
}
|
|
25105
25153
|
if (typeof value === "string" && s["pattern"]) {
|
|
25106
25154
|
const compiled = compileUserRegex(s["pattern"], "");
|
|
25107
25155
|
if (!compiled.ok) {
|
|
25108
|
-
errors.push(`${
|
|
25156
|
+
errors.push(`${path51}: invalid schema pattern \u2014 ${compiled.reason}`);
|
|
25109
25157
|
} else if (!compiled.regex.test(capSubject(value))) {
|
|
25110
|
-
errors.push(`${
|
|
25158
|
+
errors.push(`${path51}: does not match pattern ${s["pattern"]}`);
|
|
25111
25159
|
}
|
|
25112
25160
|
}
|
|
25113
25161
|
if (typeof value === "string" && s["minLength"] !== void 0 && value.length < s["minLength"]) {
|
|
25114
|
-
errors.push(`${
|
|
25162
|
+
errors.push(`${path51}: string too short (min ${s["minLength"]})`);
|
|
25115
25163
|
}
|
|
25116
25164
|
if (typeof value === "string" && s["maxLength"] !== void 0 && value.length > s["maxLength"]) {
|
|
25117
|
-
errors.push(`${
|
|
25165
|
+
errors.push(`${path51}: string too long (max ${s["maxLength"]})`);
|
|
25118
25166
|
}
|
|
25119
25167
|
if (typeof value === "number" && s["minimum"] !== void 0 && value < s["minimum"]) {
|
|
25120
|
-
errors.push(`${
|
|
25168
|
+
errors.push(`${path51}: below minimum ${s["minimum"]}`);
|
|
25121
25169
|
}
|
|
25122
25170
|
if (typeof value === "number" && s["maximum"] !== void 0 && value > s["maximum"]) {
|
|
25123
|
-
errors.push(`${
|
|
25171
|
+
errors.push(`${path51}: above maximum ${s["maximum"]}`);
|
|
25124
25172
|
}
|
|
25125
25173
|
if (Array.isArray(value) && s["items"] && Array.isArray(s["items"])) {
|
|
25126
25174
|
for (let i = 0; i < value.length; i++) {
|
|
25127
|
-
check(value[i], s["items"], `${
|
|
25175
|
+
check(value[i], s["items"], `${path51}[${i}]`);
|
|
25128
25176
|
}
|
|
25129
25177
|
}
|
|
25130
25178
|
if (typeof value === "object" && value !== null && !Array.isArray(value) && s["properties"]) {
|
|
25131
25179
|
const props = s["properties"];
|
|
25132
25180
|
for (const [k, propSchema] of Object.entries(props)) {
|
|
25133
|
-
check(value[k], propSchema, `${
|
|
25181
|
+
check(value[k], propSchema, `${path51}.${k}`);
|
|
25134
25182
|
}
|
|
25135
25183
|
}
|
|
25136
25184
|
}
|
|
25137
25185
|
check(data, schema, "$");
|
|
25138
25186
|
return { valid: errors.length === 0, errors };
|
|
25139
25187
|
}
|
|
25140
|
-
function simpleQuery(data,
|
|
25141
|
-
const parts =
|
|
25188
|
+
function simpleQuery(data, path51) {
|
|
25189
|
+
const parts = path51.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
25142
25190
|
let current = data;
|
|
25143
25191
|
for (const part of parts) {
|
|
25144
25192
|
if (current === null || current === void 0) return void 0;
|
|
@@ -25543,7 +25591,7 @@ function broadcastTodoUpdate(context, todos) {
|
|
|
25543
25591
|
const mailbox = getSharedProjectMailbox(projectDir);
|
|
25544
25592
|
void mailbox.send({
|
|
25545
25593
|
from: context.agentId,
|
|
25546
|
-
to:
|
|
25594
|
+
to: `@session:${sessionId}`,
|
|
25547
25595
|
type: "status",
|
|
25548
25596
|
subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
|
|
25549
25597
|
body: JSON.stringify({
|
|
@@ -25601,13 +25649,17 @@ function applySessionKanbanBoardToTodos(context, board, options) {
|
|
|
25601
25649
|
broadcastTodoUpdate(context, context.todos);
|
|
25602
25650
|
return [...context.todos];
|
|
25603
25651
|
}
|
|
25604
|
-
function applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors2) {
|
|
25652
|
+
function applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors2, options = {}) {
|
|
25605
25653
|
const metaKanban = context.meta["kanban"];
|
|
25606
25654
|
const metaBoardId = metaKanban && typeof metaKanban === "object" ? metaKanban["boardId"] : void 0;
|
|
25607
25655
|
const activeBoardId2 = context.currentKanbanBoardId ?? (typeof metaBoardId === "string" ? metaBoardId : void 0);
|
|
25608
25656
|
if (!activeBoardId2 || board.id !== activeBoardId2 || board.lifecycle?.mode !== "managed") {
|
|
25609
25657
|
return [...context.todos];
|
|
25610
25658
|
}
|
|
25659
|
+
const ownerSessionId = options.sessionOwnerFromTags?.(board.tags);
|
|
25660
|
+
if (ownerSessionId && ownerSessionId !== (context.session?.id ?? "")) {
|
|
25661
|
+
return [...context.todos];
|
|
25662
|
+
}
|
|
25611
25663
|
const projectedTodos = orderTasksForTodos(
|
|
25612
25664
|
board,
|
|
25613
25665
|
board.tasks.filter(
|
|
@@ -26274,7 +26326,9 @@ function applySessionKanbanBoardToTodos2(context, board) {
|
|
|
26274
26326
|
});
|
|
26275
26327
|
}
|
|
26276
26328
|
function applyManagedKanbanBoardToTodos2(context, board) {
|
|
26277
|
-
return applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors
|
|
26329
|
+
return applyManagedKanbanBoardToTodos(context, board, suppressedTodoMirrors, {
|
|
26330
|
+
sessionOwnerFromTags: sessionIdFromTags
|
|
26331
|
+
});
|
|
26278
26332
|
}
|
|
26279
26333
|
function applySessionKanbanTaskToSource2(context, task, options = {}) {
|
|
26280
26334
|
return applySessionKanbanTaskToSource(context, task, suppressedTodoMirrors, options);
|
|
@@ -28250,7 +28304,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
28250
28304
|
};
|
|
28251
28305
|
}
|
|
28252
28306
|
args.push("--timestamps", service);
|
|
28253
|
-
return new Promise((
|
|
28307
|
+
return new Promise((resolve25) => {
|
|
28254
28308
|
let stdout = "";
|
|
28255
28309
|
let stderr = "";
|
|
28256
28310
|
const MAX = 2e5;
|
|
@@ -28266,7 +28320,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
28266
28320
|
if (settled) return;
|
|
28267
28321
|
settled = true;
|
|
28268
28322
|
clearTimeout(timer);
|
|
28269
|
-
|
|
28323
|
+
resolve25(result);
|
|
28270
28324
|
};
|
|
28271
28325
|
const child = spawn11("docker", args, {
|
|
28272
28326
|
cwd,
|
|
@@ -28311,7 +28365,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
28311
28365
|
}
|
|
28312
28366
|
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
28313
28367
|
var MAX_TAIL_LINES = 1e5;
|
|
28314
|
-
async function fileLogs(
|
|
28368
|
+
async function fileLogs(path51, lines, filterRe) {
|
|
28315
28369
|
const { createInterface } = await import("node:readline");
|
|
28316
28370
|
const { createReadStream: createReadStream2 } = await import("node:fs");
|
|
28317
28371
|
const entries = [];
|
|
@@ -28320,7 +28374,7 @@ async function fileLogs(path50, lines, filterRe) {
|
|
|
28320
28374
|
let writeIdx = 0;
|
|
28321
28375
|
let totalLines = 0;
|
|
28322
28376
|
const rl = createInterface({
|
|
28323
|
-
input: createReadStream2(
|
|
28377
|
+
input: createReadStream2(path51),
|
|
28324
28378
|
crlfDelay: Number.POSITIVE_INFINITY
|
|
28325
28379
|
});
|
|
28326
28380
|
for await (const line of rl) {
|
|
@@ -28341,7 +28395,7 @@ async function fileLogs(path50, lines, filterRe) {
|
|
|
28341
28395
|
if (parsed) entries.push(parsed);
|
|
28342
28396
|
}
|
|
28343
28397
|
return {
|
|
28344
|
-
source:
|
|
28398
|
+
source: path51,
|
|
28345
28399
|
entries,
|
|
28346
28400
|
total: entries.length,
|
|
28347
28401
|
truncated: totalLines > effLines,
|
|
@@ -28483,7 +28537,7 @@ var outdatedTool = {
|
|
|
28483
28537
|
}
|
|
28484
28538
|
};
|
|
28485
28539
|
function runOutdated(manager, args, cwd, signal) {
|
|
28486
|
-
return new Promise((
|
|
28540
|
+
return new Promise((resolve25) => {
|
|
28487
28541
|
let stdout = "";
|
|
28488
28542
|
let stderr = "";
|
|
28489
28543
|
const MAX = 1e5;
|
|
@@ -28508,10 +28562,10 @@ function runOutdated(manager, args, cwd, signal) {
|
|
|
28508
28562
|
});
|
|
28509
28563
|
child.on("close", (code) => {
|
|
28510
28564
|
const result = parseOutdatedOutput(stdout, code ?? 0);
|
|
28511
|
-
|
|
28565
|
+
resolve25(result);
|
|
28512
28566
|
});
|
|
28513
28567
|
child.on("error", (e) => {
|
|
28514
|
-
|
|
28568
|
+
resolve25({
|
|
28515
28569
|
exit_code: 1,
|
|
28516
28570
|
packages: [],
|
|
28517
28571
|
total: 0,
|
|
@@ -28830,7 +28884,7 @@ function runPatch(args, cwd, signal, fallback) {
|
|
|
28830
28884
|
});
|
|
28831
28885
|
}
|
|
28832
28886
|
function runPatchProcess(command, args, cwd, signal) {
|
|
28833
|
-
return new Promise((
|
|
28887
|
+
return new Promise((resolve25) => {
|
|
28834
28888
|
let stdout = "";
|
|
28835
28889
|
let stderr = "";
|
|
28836
28890
|
const env = { ...buildChildEnv8(), LANG: "C", LC_ALL: "C" };
|
|
@@ -28849,11 +28903,11 @@ function runPatchProcess(command, args, cwd, signal) {
|
|
|
28849
28903
|
});
|
|
28850
28904
|
child.on(
|
|
28851
28905
|
"close",
|
|
28852
|
-
(code) =>
|
|
28906
|
+
(code) => resolve25({ exitCode: code ?? 1, stdout, stderr, unavailable: false })
|
|
28853
28907
|
);
|
|
28854
28908
|
child.on(
|
|
28855
28909
|
"error",
|
|
28856
|
-
(e) =>
|
|
28910
|
+
(e) => resolve25({
|
|
28857
28911
|
exitCode: 1,
|
|
28858
28912
|
stdout: "",
|
|
28859
28913
|
stderr: e.message,
|
|
@@ -29642,9 +29696,428 @@ function mkResult(plan, ok, message, todos) {
|
|
|
29642
29696
|
return result;
|
|
29643
29697
|
}
|
|
29644
29698
|
|
|
29699
|
+
// src/pwsh.ts
|
|
29700
|
+
import { spawn as spawn14 } from "node:child_process";
|
|
29701
|
+
import * as fs36 from "node:fs";
|
|
29702
|
+
import * as os10 from "node:os";
|
|
29703
|
+
import * as path43 from "node:path";
|
|
29704
|
+
import { StringDecoder as StringDecoder3 } from "node:string_decoder";
|
|
29705
|
+
import {
|
|
29706
|
+
emitProcessCompleted as emitProcessCompleted4,
|
|
29707
|
+
emitProcessOutput as emitProcessOutput4,
|
|
29708
|
+
emitProcessStarted as emitProcessStarted4
|
|
29709
|
+
} from "@wrongstack/core/observability";
|
|
29710
|
+
init_output_spool();
|
|
29711
|
+
init_util();
|
|
29712
|
+
init_process_registry();
|
|
29713
|
+
init_win32_resolve();
|
|
29714
|
+
var MAX_OUTPUT4 = 32768;
|
|
29715
|
+
var DEFAULT_TIMEOUT_MS4 = 3e5;
|
|
29716
|
+
var STREAM_FLUSH_INTERVAL_MS2 = 200;
|
|
29717
|
+
var STREAM_FLUSH_BYTES2 = 4 * 1024;
|
|
29718
|
+
var MAX_QUEUE_CHUNKS2 = 500;
|
|
29719
|
+
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`.";
|
|
29720
|
+
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`.";
|
|
29721
|
+
function wrapPwshCommand(command) {
|
|
29722
|
+
const bootstrap = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;$ProgressPreference = 'SilentlyContinue';$ConfirmPreference = 'None';$WhatIfPreference = $false";
|
|
29723
|
+
return `${bootstrap}
|
|
29724
|
+
$ErrorActionPreference = 'Stop'
|
|
29725
|
+
${command}
|
|
29726
|
+
if ($LASTEXITCODE -is [int]) { exit $LASTEXITCODE }`;
|
|
29727
|
+
}
|
|
29728
|
+
var pwshTool = {
|
|
29729
|
+
name: "pwsh",
|
|
29730
|
+
category: "Shell",
|
|
29731
|
+
description: PWSH_TOOL_DESCRIPTION,
|
|
29732
|
+
usageHint: PWSH_TOOL_USAGE_HINT,
|
|
29733
|
+
selection: {
|
|
29734
|
+
doNotUseWhen: "the command is an allowlisted single binary (node, git, pnpm, tsc) needing no shell expansion or pipelines.",
|
|
29735
|
+
useInstead: ["exec"]
|
|
29736
|
+
},
|
|
29737
|
+
permission: "confirm",
|
|
29738
|
+
mutating: true,
|
|
29739
|
+
riskTier: "destructive",
|
|
29740
|
+
icon: "terminal",
|
|
29741
|
+
subjectKey: "command",
|
|
29742
|
+
capabilities: ["shell.arbitrary"],
|
|
29743
|
+
timeoutMs: 61e4,
|
|
29744
|
+
maxOutputBytes: MAX_OUTPUT4,
|
|
29745
|
+
estimatedDurationMs: 3e4,
|
|
29746
|
+
inputSchema: {
|
|
29747
|
+
type: "object",
|
|
29748
|
+
properties: {
|
|
29749
|
+
command: {
|
|
29750
|
+
type: "string",
|
|
29751
|
+
description: "The exact PowerShell command or script block to run."
|
|
29752
|
+
},
|
|
29753
|
+
workdir: {
|
|
29754
|
+
type: "string",
|
|
29755
|
+
description: "Absolute or project-relative path to the working directory for this command. Defaults to session working directory."
|
|
29756
|
+
},
|
|
29757
|
+
timeout_ms: {
|
|
29758
|
+
type: "integer",
|
|
29759
|
+
description: "Optional timeout for this specific command in milliseconds (default 300000, max 600000)."
|
|
29760
|
+
},
|
|
29761
|
+
run_in_background: {
|
|
29762
|
+
type: "boolean",
|
|
29763
|
+
description: "If true, launch the process in the background and return the job ID / PID immediately."
|
|
29764
|
+
},
|
|
29765
|
+
background: {
|
|
29766
|
+
type: "boolean",
|
|
29767
|
+
description: "Alias for run_in_background."
|
|
29768
|
+
},
|
|
29769
|
+
sandbox_permissions: {
|
|
29770
|
+
type: "string",
|
|
29771
|
+
description: "Escalation mode if retrying a sandbox-denied command (e.g., workspace-write)."
|
|
29772
|
+
},
|
|
29773
|
+
justification: {
|
|
29774
|
+
type: "string",
|
|
29775
|
+
description: "One-sentence justification when retrying a denied command with sandbox_permissions."
|
|
29776
|
+
}
|
|
29777
|
+
},
|
|
29778
|
+
required: ["command"]
|
|
29779
|
+
},
|
|
29780
|
+
async execute(input, ctx, opts) {
|
|
29781
|
+
let final;
|
|
29782
|
+
const executeStream = pwshTool.executeStream;
|
|
29783
|
+
if (!executeStream) throw new Error("pwshTool: stream execution unavailable");
|
|
29784
|
+
for await (const ev of executeStream(input, ctx, opts)) {
|
|
29785
|
+
if (ev.type === "final") final = ev.output;
|
|
29786
|
+
}
|
|
29787
|
+
if (!final) throw new Error("pwsh: stream ended without final event");
|
|
29788
|
+
return final;
|
|
29789
|
+
},
|
|
29790
|
+
async *executeStream(input, ctx, opts) {
|
|
29791
|
+
if (!input?.command) throw new Error("pwsh: command is required");
|
|
29792
|
+
const isBackground = !!(input.run_in_background || input.background);
|
|
29793
|
+
const registry = getProcessRegistry();
|
|
29794
|
+
if (!registry.beforeCall(isBackground)) {
|
|
29795
|
+
yield {
|
|
29796
|
+
type: "final",
|
|
29797
|
+
output: {
|
|
29798
|
+
output: "",
|
|
29799
|
+
exit_code: 1,
|
|
29800
|
+
timed_out: false,
|
|
29801
|
+
pid: null,
|
|
29802
|
+
error: "pwsh: circuit breaker open \u2014 too many consecutive failures or slow calls. Use /kill to inspect or /kill reset to recover."
|
|
29803
|
+
}
|
|
29804
|
+
};
|
|
29805
|
+
return;
|
|
29806
|
+
}
|
|
29807
|
+
const killCheck = await checkAndBlockKillCommand(input.command);
|
|
29808
|
+
if (killCheck.blocked) {
|
|
29809
|
+
yield {
|
|
29810
|
+
type: "final",
|
|
29811
|
+
output: {
|
|
29812
|
+
output: "",
|
|
29813
|
+
exit_code: 1,
|
|
29814
|
+
timed_out: false,
|
|
29815
|
+
pid: null,
|
|
29816
|
+
error: `pwsh: ${killCheck.reason}`
|
|
29817
|
+
}
|
|
29818
|
+
};
|
|
29819
|
+
return;
|
|
29820
|
+
}
|
|
29821
|
+
const isWin5 = os10.platform() === "win32";
|
|
29822
|
+
const bin = isWin5 ? resolvePowerShell("pwsh.exe") : "pwsh";
|
|
29823
|
+
const args = shellArgs("pwsh");
|
|
29824
|
+
const stdinBody = wrapPwshCommand(input.command);
|
|
29825
|
+
const env = buildChildEnv2(ctx.session?.id);
|
|
29826
|
+
let targetCwd = ctx.workingDir ?? ctx.projectRoot;
|
|
29827
|
+
if (input.workdir) {
|
|
29828
|
+
const resolved = path43.isAbsolute(input.workdir) ? input.workdir : path43.resolve(ctx.projectRoot, input.workdir);
|
|
29829
|
+
if (fs36.existsSync(resolved)) {
|
|
29830
|
+
targetCwd = resolved;
|
|
29831
|
+
}
|
|
29832
|
+
}
|
|
29833
|
+
const startedAt = Date.now();
|
|
29834
|
+
const detached = !isWin5;
|
|
29835
|
+
if (isBackground) {
|
|
29836
|
+
const child2 = spawn14(bin, args, {
|
|
29837
|
+
cwd: targetCwd,
|
|
29838
|
+
env,
|
|
29839
|
+
detached,
|
|
29840
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
29841
|
+
windowsHide: true
|
|
29842
|
+
});
|
|
29843
|
+
if (child2.stdin) {
|
|
29844
|
+
child2.stdin.write(stdinBody);
|
|
29845
|
+
child2.stdin.end();
|
|
29846
|
+
}
|
|
29847
|
+
const pid2 = child2.pid;
|
|
29848
|
+
if (typeof pid2 === "number") {
|
|
29849
|
+
registry.register({
|
|
29850
|
+
pid: pid2,
|
|
29851
|
+
name: "pwsh",
|
|
29852
|
+
command: redactCommand(input.command),
|
|
29853
|
+
startedAt: Date.now(),
|
|
29854
|
+
sessionId: ctx.session?.id,
|
|
29855
|
+
child: child2,
|
|
29856
|
+
processGroupLeader: detached && child2.pid === pid2,
|
|
29857
|
+
background: true
|
|
29858
|
+
});
|
|
29859
|
+
child2.on("close", () => registry.unregister(pid2));
|
|
29860
|
+
child2.on("error", () => {
|
|
29861
|
+
registry.unregister(pid2);
|
|
29862
|
+
registry.afterCall(Date.now() - startedAt, true, isBackground);
|
|
29863
|
+
});
|
|
29864
|
+
child2.unref();
|
|
29865
|
+
const jobId = `job_${pid2}`;
|
|
29866
|
+
ctx.recordSideEffect?.({
|
|
29867
|
+
toolUseId: `pwsh-bg-${Date.now()}`,
|
|
29868
|
+
toolName: "pwsh",
|
|
29869
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29870
|
+
input: { command: redactCommand(input.command), background: true },
|
|
29871
|
+
outcome: `started background job ${jobId} (PID: ${pid2})`,
|
|
29872
|
+
risk: "shell"
|
|
29873
|
+
});
|
|
29874
|
+
yield {
|
|
29875
|
+
type: "final",
|
|
29876
|
+
output: {
|
|
29877
|
+
output: `Background job started: ${jobId} (PID: ${pid2})
|
|
29878
|
+
Working directory: ${targetCwd}`,
|
|
29879
|
+
exit_code: null,
|
|
29880
|
+
timed_out: false,
|
|
29881
|
+
pid: pid2,
|
|
29882
|
+
job_id: jobId
|
|
29883
|
+
}
|
|
29884
|
+
};
|
|
29885
|
+
return;
|
|
29886
|
+
}
|
|
29887
|
+
yield {
|
|
29888
|
+
type: "final",
|
|
29889
|
+
output: {
|
|
29890
|
+
output: "",
|
|
29891
|
+
exit_code: 1,
|
|
29892
|
+
timed_out: false,
|
|
29893
|
+
pid: null,
|
|
29894
|
+
error: "pwsh: failed to obtain PID for background process"
|
|
29895
|
+
}
|
|
29896
|
+
};
|
|
29897
|
+
return;
|
|
29898
|
+
}
|
|
29899
|
+
const spool = createOutputSpool({ tool: "pwsh", thresholdBytes: MAX_OUTPUT4 });
|
|
29900
|
+
const child = spawn14(bin, args, {
|
|
29901
|
+
cwd: targetCwd,
|
|
29902
|
+
env,
|
|
29903
|
+
detached,
|
|
29904
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
29905
|
+
windowsHide: true
|
|
29906
|
+
});
|
|
29907
|
+
const pid = child.pid;
|
|
29908
|
+
let stdoutBytes = 0;
|
|
29909
|
+
let stderrBytes = 0;
|
|
29910
|
+
let telemetryCompleted = false;
|
|
29911
|
+
emitProcessStarted4({
|
|
29912
|
+
...pid !== void 0 ? { pid } : {},
|
|
29913
|
+
parentPid: process.pid,
|
|
29914
|
+
command: redactCommand(`${bin} ${args.join(" ")}`),
|
|
29915
|
+
args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
|
|
29916
|
+
cwd: targetCwd,
|
|
29917
|
+
background: false,
|
|
29918
|
+
startedAt: new Date(startedAt).toISOString()
|
|
29919
|
+
});
|
|
29920
|
+
const completeForeground = (exitCode, sig) => {
|
|
29921
|
+
if (telemetryCompleted) return;
|
|
29922
|
+
telemetryCompleted = true;
|
|
29923
|
+
emitProcessCompleted4({
|
|
29924
|
+
...pid !== void 0 ? { pid } : {},
|
|
29925
|
+
exitCode,
|
|
29926
|
+
...sig ? { signal: sig } : {},
|
|
29927
|
+
durationMs: Date.now() - startedAt,
|
|
29928
|
+
stdoutBytes,
|
|
29929
|
+
stderrBytes,
|
|
29930
|
+
timedOut,
|
|
29931
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29932
|
+
});
|
|
29933
|
+
};
|
|
29934
|
+
if (typeof pid === "number") {
|
|
29935
|
+
registry.register({
|
|
29936
|
+
pid,
|
|
29937
|
+
name: "pwsh",
|
|
29938
|
+
command: redactCommand(input.command),
|
|
29939
|
+
startedAt: Date.now(),
|
|
29940
|
+
sessionId: ctx.session?.id,
|
|
29941
|
+
child,
|
|
29942
|
+
processGroupLeader: detached && child.pid === pid
|
|
29943
|
+
});
|
|
29944
|
+
}
|
|
29945
|
+
if (child.stdin) {
|
|
29946
|
+
child.stdin.write(stdinBody);
|
|
29947
|
+
child.stdin.end();
|
|
29948
|
+
}
|
|
29949
|
+
const timeoutMs = Math.min(
|
|
29950
|
+
Math.max(1e3, input.timeout_ms ?? DEFAULT_TIMEOUT_MS4),
|
|
29951
|
+
6e5
|
|
29952
|
+
);
|
|
29953
|
+
let timedOut = false;
|
|
29954
|
+
const timers = [];
|
|
29955
|
+
const killWithTimeout = (timeout) => {
|
|
29956
|
+
if (isWin5) {
|
|
29957
|
+
if (typeof child.pid === "number" && child.exitCode === null) {
|
|
29958
|
+
const attempted = registry.kill(child.pid, { force: true, graceMs: timeout });
|
|
29959
|
+
if (!attempted) {
|
|
29960
|
+
try {
|
|
29961
|
+
child.kill();
|
|
29962
|
+
} catch {
|
|
29963
|
+
}
|
|
29964
|
+
}
|
|
29965
|
+
}
|
|
29966
|
+
return;
|
|
29967
|
+
}
|
|
29968
|
+
if (typeof child.pid === "number") {
|
|
29969
|
+
registry.kill(child.pid, { graceMs: timeout });
|
|
29970
|
+
} else {
|
|
29971
|
+
try {
|
|
29972
|
+
child.kill("SIGTERM");
|
|
29973
|
+
} catch {
|
|
29974
|
+
}
|
|
29975
|
+
}
|
|
29976
|
+
};
|
|
29977
|
+
const timer = setTimeout(() => {
|
|
29978
|
+
timedOut = true;
|
|
29979
|
+
killWithTimeout(2e3);
|
|
29980
|
+
}, timeoutMs);
|
|
29981
|
+
timers.push(timer);
|
|
29982
|
+
const onAbort = () => killWithTimeout(2e3);
|
|
29983
|
+
if (opts.signal.aborted) onAbort();
|
|
29984
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
29985
|
+
const queue = [];
|
|
29986
|
+
let resolveNext = null;
|
|
29987
|
+
const push = (c) => {
|
|
29988
|
+
if (resolveNext) {
|
|
29989
|
+
const r = resolveNext;
|
|
29990
|
+
resolveNext = null;
|
|
29991
|
+
r(c);
|
|
29992
|
+
} else {
|
|
29993
|
+
queue.push(c);
|
|
29994
|
+
}
|
|
29995
|
+
};
|
|
29996
|
+
const next = () => new Promise((resolve25) => {
|
|
29997
|
+
const c = queue.shift();
|
|
29998
|
+
if (c) resolve25(c);
|
|
29999
|
+
else resolveNext = resolve25;
|
|
30000
|
+
});
|
|
30001
|
+
let buf = "";
|
|
30002
|
+
let pending2 = "";
|
|
30003
|
+
let lastFlush = Date.now();
|
|
30004
|
+
const flush = () => {
|
|
30005
|
+
if (pending2.length === 0) return null;
|
|
30006
|
+
const text = pending2;
|
|
30007
|
+
pending2 = "";
|
|
30008
|
+
lastFlush = Date.now();
|
|
30009
|
+
return text;
|
|
30010
|
+
};
|
|
30011
|
+
let paused = false;
|
|
30012
|
+
const pauseIfFlooded = () => {
|
|
30013
|
+
if (!paused && queue.length >= MAX_QUEUE_CHUNKS2) {
|
|
30014
|
+
paused = true;
|
|
30015
|
+
child.stdout?.pause();
|
|
30016
|
+
child.stderr?.pause();
|
|
30017
|
+
}
|
|
30018
|
+
};
|
|
30019
|
+
const resumeIfDrained = () => {
|
|
30020
|
+
if (paused && queue.length < MAX_QUEUE_CHUNKS2) {
|
|
30021
|
+
paused = false;
|
|
30022
|
+
child.stdout?.resume();
|
|
30023
|
+
child.stderr?.resume();
|
|
30024
|
+
}
|
|
30025
|
+
};
|
|
30026
|
+
const stdoutDecoder = new StringDecoder3("utf8");
|
|
30027
|
+
const stderrDecoder = new StringDecoder3("utf8");
|
|
30028
|
+
const onData = (chunk, stream) => {
|
|
30029
|
+
const text = (stream === "stdout" ? stdoutDecoder : stderrDecoder).write(chunk);
|
|
30030
|
+
if (stream === "stdout") stdoutBytes += chunk.byteLength;
|
|
30031
|
+
else stderrBytes += chunk.byteLength;
|
|
30032
|
+
emitProcessOutput4({ pid: pid ?? 0, stream, chunk });
|
|
30033
|
+
if (buf.length < MAX_OUTPUT4) {
|
|
30034
|
+
buf += text.slice(0, MAX_OUTPUT4 - buf.length);
|
|
30035
|
+
}
|
|
30036
|
+
spool.write(text);
|
|
30037
|
+
pending2 += text;
|
|
30038
|
+
push({ kind: "data", text });
|
|
30039
|
+
pauseIfFlooded();
|
|
30040
|
+
};
|
|
30041
|
+
child.stdout?.on("data", (chunk) => onData(chunk, "stdout"));
|
|
30042
|
+
child.stderr?.on("data", (chunk) => onData(chunk, "stderr"));
|
|
30043
|
+
child.on("error", (err) => {
|
|
30044
|
+
for (const t of timers) clearTimeout(t);
|
|
30045
|
+
registry.afterCall(Date.now() - startedAt, true);
|
|
30046
|
+
completeForeground(1);
|
|
30047
|
+
push({ kind: "error", err });
|
|
30048
|
+
});
|
|
30049
|
+
child.on("close", (code, signal) => {
|
|
30050
|
+
for (const t of timers) clearTimeout(t);
|
|
30051
|
+
if (typeof pid === "number") registry.unregister(pid);
|
|
30052
|
+
registry.afterCall(Date.now() - startedAt, code !== 0 && code !== null);
|
|
30053
|
+
completeForeground(timedOut ? 124 : code ?? (signal ? 1 : 0), signal ?? void 0);
|
|
30054
|
+
const tail = stdoutDecoder.end() + stderrDecoder.end();
|
|
30055
|
+
if (tail) {
|
|
30056
|
+
if (buf.length < MAX_OUTPUT4) buf += tail.slice(0, MAX_OUTPUT4 - buf.length);
|
|
30057
|
+
spool.write(tail);
|
|
30058
|
+
pending2 += tail;
|
|
30059
|
+
}
|
|
30060
|
+
push({ kind: "end", code });
|
|
30061
|
+
});
|
|
30062
|
+
try {
|
|
30063
|
+
while (true) {
|
|
30064
|
+
const c = await next();
|
|
30065
|
+
resumeIfDrained();
|
|
30066
|
+
if (c.kind === "error") throw c.err;
|
|
30067
|
+
if (c.kind === "end") {
|
|
30068
|
+
const remainder = flush();
|
|
30069
|
+
if (remainder !== null) {
|
|
30070
|
+
yield { type: "partial_output", text: remainder };
|
|
30071
|
+
}
|
|
30072
|
+
const spooled = spool.finalize();
|
|
30073
|
+
let formattedOutput = normalizeCommandOutput(buf);
|
|
30074
|
+
if (c.code !== null && c.code !== 0 && !timedOut) {
|
|
30075
|
+
if (!formattedOutput.includes(`[exit code: ${c.code}]`)) {
|
|
30076
|
+
formattedOutput = formattedOutput ? `${formattedOutput}
|
|
30077
|
+
[exit code: ${c.code}]` : `[exit code: ${c.code}]`;
|
|
30078
|
+
}
|
|
30079
|
+
}
|
|
30080
|
+
const hint = !timedOut && typeof c.code === "number" && c.code !== 0 ? diagnoseBashism(input.command, "pwsh") : void 0;
|
|
30081
|
+
const danger = detectDanger("pwsh", [input.command]);
|
|
30082
|
+
const cautionText = danger.level === "caution" && danger.reasons.length > 0 ? `
|
|
30083
|
+
[caution: ${danger.reasons.join("; ")}]` : "";
|
|
30084
|
+
const finalResultText = formattedOutput + (spooled ? spoolNote(spooled) : "") + (hint ? `
|
|
30085
|
+
|
|
30086
|
+
${hint}` : "") + cautionText;
|
|
30087
|
+
ctx.recordSideEffect?.({
|
|
30088
|
+
toolUseId: `pwsh-${Date.now()}`,
|
|
30089
|
+
toolName: "pwsh",
|
|
30090
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30091
|
+
input: { command: redactCommand(input.command) },
|
|
30092
|
+
outcome: timedOut ? `timed out (exit ${c.code})` : `exit ${c.code}`,
|
|
30093
|
+
risk: "shell"
|
|
30094
|
+
});
|
|
30095
|
+
yield {
|
|
30096
|
+
type: "final",
|
|
30097
|
+
output: {
|
|
30098
|
+
output: finalResultText,
|
|
30099
|
+
exit_code: timedOut ? 1 : c.code,
|
|
30100
|
+
timed_out: timedOut,
|
|
30101
|
+
pid
|
|
30102
|
+
}
|
|
30103
|
+
};
|
|
30104
|
+
return;
|
|
30105
|
+
}
|
|
30106
|
+
const now2 = Date.now();
|
|
30107
|
+
if (pending2.length >= STREAM_FLUSH_BYTES2 || now2 - lastFlush >= STREAM_FLUSH_INTERVAL_MS2) {
|
|
30108
|
+
const text = flush();
|
|
30109
|
+
if (text) yield { type: "partial_output", text };
|
|
30110
|
+
}
|
|
30111
|
+
}
|
|
30112
|
+
} finally {
|
|
30113
|
+
for (const t of timers) clearTimeout(t);
|
|
30114
|
+
}
|
|
30115
|
+
}
|
|
30116
|
+
};
|
|
30117
|
+
|
|
29645
30118
|
// src/read.ts
|
|
29646
30119
|
init_util();
|
|
29647
|
-
import * as
|
|
30120
|
+
import * as fs37 from "node:fs/promises";
|
|
29648
30121
|
import { FsError, ToolValidationError as ToolValidationError8 } from "@wrongstack/core/types";
|
|
29649
30122
|
import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
|
|
29650
30123
|
var ADVANCED_MODE_META_KEY = "tools.read.advancedMode";
|
|
@@ -29704,7 +30177,7 @@ var readTool = {
|
|
|
29704
30177
|
const shouldIncludeSymbols = input.includeSymbols === true || input.includeSymbols !== false && ctx.meta[ADVANCED_MODE_META_KEY] === true;
|
|
29705
30178
|
let stat22;
|
|
29706
30179
|
try {
|
|
29707
|
-
stat22 = await
|
|
30180
|
+
stat22 = await fs37.stat(absPath);
|
|
29708
30181
|
} catch (err) {
|
|
29709
30182
|
const code = err.code;
|
|
29710
30183
|
if (code === "ENOENT") {
|
|
@@ -29756,7 +30229,7 @@ var readTool = {
|
|
|
29756
30229
|
...symResult2?.symbols ? { symbols: symResult2.symbols } : {}
|
|
29757
30230
|
};
|
|
29758
30231
|
}
|
|
29759
|
-
const buf = await
|
|
30232
|
+
const buf = await fs37.readFile(absPath);
|
|
29760
30233
|
if (isBinaryBuffer(buf)) {
|
|
29761
30234
|
throw new FsError({
|
|
29762
30235
|
message: `read: "${input.path}" appears to be binary`,
|
|
@@ -29922,9 +30395,9 @@ ${interesting.join("\n")}` : "symbols/imports: (none detected)"
|
|
|
29922
30395
|
}
|
|
29923
30396
|
|
|
29924
30397
|
// src/replace.ts
|
|
29925
|
-
import { spawn as
|
|
29926
|
-
import * as
|
|
29927
|
-
import * as
|
|
30398
|
+
import { spawn as spawn15 } from "node:child_process";
|
|
30399
|
+
import * as fs38 from "node:fs/promises";
|
|
30400
|
+
import * as path44 from "node:path";
|
|
29928
30401
|
import { ToolValidationError as ToolValidationError9 } from "@wrongstack/core/types";
|
|
29929
30402
|
import {
|
|
29930
30403
|
atomicWrite as atomicWrite4,
|
|
@@ -30007,14 +30480,14 @@ var replaceTool = {
|
|
|
30007
30480
|
const dryRun = input.dry_run ?? true;
|
|
30008
30481
|
const filesInput = Array.isArray(input.files) ? input.files.join(",") : input.files;
|
|
30009
30482
|
const fileList = await resolveFiles2(filesInput, ctx, globRe);
|
|
30010
|
-
const realRoot = await
|
|
30483
|
+
const realRoot = await fs38.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
30011
30484
|
const results = [];
|
|
30012
30485
|
let totalReplacements = 0;
|
|
30013
30486
|
let diffBytesUsed = 0;
|
|
30014
30487
|
let diffsOmitted = 0;
|
|
30015
30488
|
let diffsTruncated = 0;
|
|
30016
30489
|
for (const absPath of fileList) {
|
|
30017
|
-
const lstat2 = await
|
|
30490
|
+
const lstat2 = await fs38.lstat(absPath).catch((err) => {
|
|
30018
30491
|
if (err.code === "ENOENT") return null;
|
|
30019
30492
|
throw err;
|
|
30020
30493
|
});
|
|
@@ -30022,17 +30495,17 @@ var replaceTool = {
|
|
|
30022
30495
|
if (lstat2.isSymbolicLink()) continue;
|
|
30023
30496
|
let realPath;
|
|
30024
30497
|
try {
|
|
30025
|
-
realPath = await
|
|
30498
|
+
realPath = await fs38.realpath(absPath);
|
|
30026
30499
|
} catch {
|
|
30027
30500
|
continue;
|
|
30028
30501
|
}
|
|
30029
|
-
const rel =
|
|
30030
|
-
if (rel.startsWith("..") ||
|
|
30031
|
-
const stat22 = await
|
|
30502
|
+
const rel = path44.relative(realRoot, realPath);
|
|
30503
|
+
if (rel.startsWith("..") || path44.isAbsolute(rel)) continue;
|
|
30504
|
+
const stat22 = await fs38.stat(realPath).catch(() => null);
|
|
30032
30505
|
if (!stat22?.isFile()) continue;
|
|
30033
30506
|
let content;
|
|
30034
30507
|
try {
|
|
30035
|
-
const buf = await
|
|
30508
|
+
const buf = await fs38.readFile(realPath);
|
|
30036
30509
|
if (isBinaryBuffer(buf)) continue;
|
|
30037
30510
|
content = buf.toString("utf8");
|
|
30038
30511
|
} catch {
|
|
@@ -30055,7 +30528,7 @@ var replaceTool = {
|
|
|
30055
30528
|
if (!dryRun) {
|
|
30056
30529
|
const newContent = toStyle2(newContentLf, style);
|
|
30057
30530
|
await atomicWrite4(realPath, newContent, { mode: stat22.mode & 511 });
|
|
30058
|
-
const written = await
|
|
30531
|
+
const written = await fs38.stat(realPath).catch(() => null);
|
|
30059
30532
|
if (written) {
|
|
30060
30533
|
ctx.recordRead?.(realPath, written.mtimeMs, "write", sha256hex(newContent));
|
|
30061
30534
|
}
|
|
@@ -30155,8 +30628,8 @@ async function resolveFiles2(filesInput, ctx, extraGlob) {
|
|
|
30155
30628
|
const resolved = [];
|
|
30156
30629
|
for (const p of parts) {
|
|
30157
30630
|
const absPath = await safeResolveReal(p, ctx);
|
|
30158
|
-
if (extraGlob && !passesExtraGlob(extraGlob,
|
|
30159
|
-
const stat22 = await
|
|
30631
|
+
if (extraGlob && !passesExtraGlob(extraGlob, path44.basename(absPath), absPath)) continue;
|
|
30632
|
+
const stat22 = await fs38.stat(absPath).catch(() => null);
|
|
30160
30633
|
if (stat22?.isFile()) {
|
|
30161
30634
|
resolved.push(absPath);
|
|
30162
30635
|
}
|
|
@@ -30170,7 +30643,7 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
30170
30643
|
const { promise } = spawnRgFind(pattern, base);
|
|
30171
30644
|
const files = await promise;
|
|
30172
30645
|
if (extraGlob) {
|
|
30173
|
-
return files.filter((f) => passesExtraGlob(extraGlob,
|
|
30646
|
+
return files.filter((f) => passesExtraGlob(extraGlob, path44.basename(f), f));
|
|
30174
30647
|
}
|
|
30175
30648
|
return files;
|
|
30176
30649
|
} catch {
|
|
@@ -30180,24 +30653,24 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
30180
30653
|
}
|
|
30181
30654
|
var rgAvailabilityCache2;
|
|
30182
30655
|
function checkRg() {
|
|
30183
|
-
rgAvailabilityCache2 ??= new Promise((
|
|
30656
|
+
rgAvailabilityCache2 ??= new Promise((resolve25) => {
|
|
30184
30657
|
try {
|
|
30185
|
-
const p =
|
|
30658
|
+
const p = spawn15("rg", ["--version"], {
|
|
30186
30659
|
env: buildChildEnv9(),
|
|
30187
30660
|
stdio: "ignore",
|
|
30188
30661
|
windowsHide: true
|
|
30189
30662
|
});
|
|
30190
|
-
p.on("error", () =>
|
|
30191
|
-
p.on("close", (code) =>
|
|
30663
|
+
p.on("error", () => resolve25(false));
|
|
30664
|
+
p.on("close", (code) => resolve25(code === 0));
|
|
30192
30665
|
} catch {
|
|
30193
|
-
|
|
30666
|
+
resolve25(false);
|
|
30194
30667
|
}
|
|
30195
30668
|
});
|
|
30196
30669
|
return rgAvailabilityCache2;
|
|
30197
30670
|
}
|
|
30198
30671
|
function spawnRgFind(pattern, base) {
|
|
30199
30672
|
const args = ["--files", "--glob", pattern, base];
|
|
30200
|
-
const child =
|
|
30673
|
+
const child = spawn15("rg", args, {
|
|
30201
30674
|
signal: AbortSignal.timeout(3e4),
|
|
30202
30675
|
env: buildChildEnv9(),
|
|
30203
30676
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -30216,10 +30689,10 @@ function spawnRgFind(pattern, base) {
|
|
|
30216
30689
|
}
|
|
30217
30690
|
});
|
|
30218
30691
|
return {
|
|
30219
|
-
promise: new Promise((
|
|
30692
|
+
promise: new Promise((resolve25, reject) => {
|
|
30220
30693
|
child.on("error", reject);
|
|
30221
30694
|
child.on("close", () => {
|
|
30222
|
-
|
|
30695
|
+
resolve25(buf.split("\n").filter(Boolean));
|
|
30223
30696
|
});
|
|
30224
30697
|
})
|
|
30225
30698
|
};
|
|
@@ -30230,15 +30703,15 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
30230
30703
|
const walk2 = async (dir) => {
|
|
30231
30704
|
let entries;
|
|
30232
30705
|
try {
|
|
30233
|
-
entries = await
|
|
30706
|
+
entries = await fs38.readdir(dir, { withFileTypes: true });
|
|
30234
30707
|
} catch {
|
|
30235
30708
|
return;
|
|
30236
30709
|
}
|
|
30237
30710
|
for (const e of entries) {
|
|
30238
30711
|
if (DEFAULT_IGNORE4.includes(e.name)) continue;
|
|
30239
|
-
const full =
|
|
30712
|
+
const full = path44.join(dir, e.name);
|
|
30240
30713
|
try {
|
|
30241
|
-
const stat22 = await
|
|
30714
|
+
const stat22 = await fs38.lstat(full);
|
|
30242
30715
|
if (stat22.isSymbolicLink()) continue;
|
|
30243
30716
|
} catch {
|
|
30244
30717
|
continue;
|
|
@@ -30262,8 +30735,8 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
30262
30735
|
|
|
30263
30736
|
// src/scaffold.ts
|
|
30264
30737
|
init_util();
|
|
30265
|
-
import * as
|
|
30266
|
-
import * as
|
|
30738
|
+
import * as fs39 from "node:fs/promises";
|
|
30739
|
+
import * as path45 from "node:path";
|
|
30267
30740
|
import { atomicWrite as atomicWrite5 } from "@wrongstack/core/utils";
|
|
30268
30741
|
var BUILT_IN_TEMPLATES = {
|
|
30269
30742
|
"npm-package": {
|
|
@@ -30414,16 +30887,16 @@ async function handleBuiltIn(name, templateFiles, cwd, ctx, dryRun, vars) {
|
|
|
30414
30887
|
let filesCreated = 0;
|
|
30415
30888
|
for (const [filePath, content] of Object.entries(templateFiles)) {
|
|
30416
30889
|
const resolvedPath = substituteVars(filePath, name, vars);
|
|
30417
|
-
const joinedPath =
|
|
30418
|
-
const root =
|
|
30419
|
-
const target =
|
|
30420
|
-
const rel =
|
|
30421
|
-
if (rel.startsWith("..") ||
|
|
30890
|
+
const joinedPath = path45.join(cwd, resolvedPath);
|
|
30891
|
+
const root = path45.resolve(ctx.projectRoot);
|
|
30892
|
+
const target = path45.resolve(joinedPath);
|
|
30893
|
+
const rel = path45.relative(root, target);
|
|
30894
|
+
if (rel.startsWith("..") || path45.isAbsolute(rel)) {
|
|
30422
30895
|
throw new Error(`scaffold: generated path "${resolvedPath}" would escape project root`);
|
|
30423
30896
|
}
|
|
30424
30897
|
const fullPath = target;
|
|
30425
30898
|
if (!dryRun) {
|
|
30426
|
-
await
|
|
30899
|
+
await fs39.mkdir(path45.dirname(fullPath), { recursive: true });
|
|
30427
30900
|
await atomicWrite5(fullPath, substituteVars(content, name, vars));
|
|
30428
30901
|
}
|
|
30429
30902
|
files.push(resolvedPath);
|
|
@@ -30869,8 +31342,8 @@ function decodeHtmlEntities(text) {
|
|
|
30869
31342
|
}
|
|
30870
31343
|
|
|
30871
31344
|
// src/security-ast-scan-tool.ts
|
|
30872
|
-
import * as
|
|
30873
|
-
import * as
|
|
31345
|
+
import * as fs40 from "node:fs/promises";
|
|
31346
|
+
import * as path46 from "node:path";
|
|
30874
31347
|
import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
|
|
30875
31348
|
var SECRET_PATTERNS = [
|
|
30876
31349
|
{ name: "AWS Access Key", regex: /\b(AKIA[0-9A-Z]{16})\b/ },
|
|
@@ -31037,9 +31510,9 @@ var securityAstScanTool = {
|
|
|
31037
31510
|
let targetFile = input.file ?? "inline-code.ts";
|
|
31038
31511
|
let content = input.content;
|
|
31039
31512
|
if (!content && input.file) {
|
|
31040
|
-
const absPath =
|
|
31041
|
-
targetFile =
|
|
31042
|
-
content = await
|
|
31513
|
+
const absPath = path46.isAbsolute(input.file) ? input.file : path46.resolve(projectRoot, input.file);
|
|
31514
|
+
targetFile = path46.relative(projectRoot, absPath).replace(/\\/g, "/");
|
|
31515
|
+
content = await fs40.readFile(absPath, "utf8");
|
|
31043
31516
|
}
|
|
31044
31517
|
if (!content) {
|
|
31045
31518
|
return {
|
|
@@ -31087,7 +31560,7 @@ var securityAstScanTool = {
|
|
|
31087
31560
|
};
|
|
31088
31561
|
|
|
31089
31562
|
// src/set-working-dir.ts
|
|
31090
|
-
import * as
|
|
31563
|
+
import * as fs41 from "node:fs/promises";
|
|
31091
31564
|
import { toErrorMessage as toErrorMessage18 } from "@wrongstack/core/utils";
|
|
31092
31565
|
var setWorkingDirTool = {
|
|
31093
31566
|
name: "set_working_dir",
|
|
@@ -31127,7 +31600,7 @@ var setWorkingDirTool = {
|
|
|
31127
31600
|
}
|
|
31128
31601
|
let isDirectory = false;
|
|
31129
31602
|
try {
|
|
31130
|
-
isDirectory = (await
|
|
31603
|
+
isDirectory = (await fs41.stat(resolved)).isDirectory();
|
|
31131
31604
|
} catch {
|
|
31132
31605
|
isDirectory = false;
|
|
31133
31606
|
}
|
|
@@ -31662,7 +32135,7 @@ ${formatTaskList2(file.tasks)}` : file.tasks.length > 0 ? formatTaskList2(file.t
|
|
|
31662
32135
|
init_spawn_stream();
|
|
31663
32136
|
init_util();
|
|
31664
32137
|
init_legacy_bridge();
|
|
31665
|
-
import * as
|
|
32138
|
+
import * as path47 from "node:path";
|
|
31666
32139
|
var testTool = {
|
|
31667
32140
|
name: "test",
|
|
31668
32141
|
category: "Code Quality",
|
|
@@ -31769,7 +32242,7 @@ async function detectRunner(cwd) {
|
|
|
31769
32242
|
const candidates = ["vitest.config.ts", "jest.config.js", ".mocharc.json"];
|
|
31770
32243
|
for (const f of candidates) {
|
|
31771
32244
|
try {
|
|
31772
|
-
await stat22(
|
|
32245
|
+
await stat22(path47.join(cwd, f));
|
|
31773
32246
|
if (f.includes("vitest")) return "vitest";
|
|
31774
32247
|
if (f.includes("jest")) return "jest";
|
|
31775
32248
|
if (f.includes("mocha")) return "mocha";
|
|
@@ -32146,8 +32619,8 @@ var toolUseTool = {
|
|
|
32146
32619
|
|
|
32147
32620
|
// src/tree.ts
|
|
32148
32621
|
init_util();
|
|
32149
|
-
import * as
|
|
32150
|
-
import * as
|
|
32622
|
+
import * as fs42 from "node:fs/promises";
|
|
32623
|
+
import * as path48 from "node:path";
|
|
32151
32624
|
import { DEFAULT_WALK_IGNORE_DIRS as DEFAULT_WALK_IGNORE_DIRS4, expectDefined as expectDefined10 } from "@wrongstack/core/utils";
|
|
32152
32625
|
var DEFAULT_IGNORE5 = /* @__PURE__ */ new Set([
|
|
32153
32626
|
...DEFAULT_WALK_IGNORE_DIRS4,
|
|
@@ -32310,7 +32783,7 @@ var treeTool = {
|
|
|
32310
32783
|
async function walkDir(dir, depth, opts) {
|
|
32311
32784
|
opts.signal.throwIfAborted();
|
|
32312
32785
|
if (opts.retention.truncated) return;
|
|
32313
|
-
const entries = await
|
|
32786
|
+
const entries = await fs42.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
32314
32787
|
const filtered = entries.filter((e) => {
|
|
32315
32788
|
if (!opts.showHidden && e.name.startsWith(".")) return false;
|
|
32316
32789
|
if (opts.exclude.has(e.name)) return false;
|
|
@@ -32352,7 +32825,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
32352
32825
|
opts.retention.outputBytes += lineBytes;
|
|
32353
32826
|
if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {
|
|
32354
32827
|
const childPrefix = opts.prefix + connector;
|
|
32355
|
-
await walkDir(
|
|
32828
|
+
await walkDir(path48.join(dir, entry.name), depth + 1, {
|
|
32356
32829
|
...opts,
|
|
32357
32830
|
prefix: childPrefix,
|
|
32358
32831
|
isLast
|
|
@@ -32365,7 +32838,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
32365
32838
|
init_spawn_stream();
|
|
32366
32839
|
init_util();
|
|
32367
32840
|
init_legacy_bridge();
|
|
32368
|
-
import * as
|
|
32841
|
+
import * as path49 from "node:path";
|
|
32369
32842
|
var typecheckTool = {
|
|
32370
32843
|
name: "typecheck",
|
|
32371
32844
|
category: "Code Quality",
|
|
@@ -32477,8 +32950,8 @@ async function findTsConfig(cwd) {
|
|
|
32477
32950
|
const candidates = ["tsconfig.json", "tsconfig.base.json"];
|
|
32478
32951
|
for (const f of candidates) {
|
|
32479
32952
|
try {
|
|
32480
|
-
const s = await stat22(
|
|
32481
|
-
if (s.isFile()) return
|
|
32953
|
+
const s = await stat22(path49.join(cwd, f));
|
|
32954
|
+
if (s.isFile()) return path49.join(cwd, f);
|
|
32482
32955
|
} catch {
|
|
32483
32956
|
}
|
|
32484
32957
|
}
|
|
@@ -32486,7 +32959,7 @@ async function findTsConfig(cwd) {
|
|
|
32486
32959
|
}
|
|
32487
32960
|
|
|
32488
32961
|
// src/write.ts
|
|
32489
|
-
import * as
|
|
32962
|
+
import * as fs43 from "node:fs/promises";
|
|
32490
32963
|
import { ToolValidationError as ToolValidationError11 } from "@wrongstack/core/types";
|
|
32491
32964
|
import {
|
|
32492
32965
|
atomicWrite as atomicWrite6,
|
|
@@ -32563,14 +33036,14 @@ async function prepareWrite(input, ctx) {
|
|
|
32563
33036
|
let existed = false;
|
|
32564
33037
|
let prev = "";
|
|
32565
33038
|
try {
|
|
32566
|
-
const stat22 = await
|
|
33039
|
+
const stat22 = await fs43.stat(absPath);
|
|
32567
33040
|
existed = stat22.isFile();
|
|
32568
33041
|
if (existed) {
|
|
32569
33042
|
if (!ctx.hasRead(absPath)) {
|
|
32570
|
-
prev = await
|
|
33043
|
+
prev = await fs43.readFile(absPath, "utf8");
|
|
32571
33044
|
ctx.recordRead(absPath, stat22.mtimeMs, "write", sha256hex(prev));
|
|
32572
33045
|
} else {
|
|
32573
|
-
prev = await
|
|
33046
|
+
prev = await fs43.readFile(absPath, "utf8");
|
|
32574
33047
|
}
|
|
32575
33048
|
}
|
|
32576
33049
|
} catch (err) {
|
|
@@ -32591,7 +33064,7 @@ async function finishWrite(input, ctx, prepared, signal) {
|
|
|
32591
33064
|
const rawDiff = prepared.existed ? unifiedDiff3(prepared.prev, content, { fromFile: input.path, toFile: input.path }) : `+++ ${input.path}
|
|
32592
33065
|
+ (new file, ${content.split("\n").length} lines)`;
|
|
32593
33066
|
const { text: diff, truncated: diffTruncated } = truncateDiffPayload(rawDiff, MAX_DIFF_BYTES3);
|
|
32594
|
-
const stat22 = await
|
|
33067
|
+
const stat22 = await fs43.stat(prepared.absPath);
|
|
32595
33068
|
ctx.recordRead(prepared.absPath, stat22.mtimeMs, "write", sha256hex(content));
|
|
32596
33069
|
ctx.session.recordFileChange({
|
|
32597
33070
|
path: prepared.absPath,
|
|
@@ -32669,6 +33142,7 @@ var TIER1_TOOLS = [
|
|
|
32669
33142
|
var TIER2_TOOLS = [
|
|
32670
33143
|
replaceTool,
|
|
32671
33144
|
execTool,
|
|
33145
|
+
pwshTool,
|
|
32672
33146
|
fetchTool,
|
|
32673
33147
|
gitTool,
|
|
32674
33148
|
treeTool,
|
|
@@ -32724,6 +33198,7 @@ var builtinTools = [
|
|
|
32724
33198
|
grepTool,
|
|
32725
33199
|
bashTool,
|
|
32726
33200
|
execTool,
|
|
33201
|
+
pwshTool,
|
|
32727
33202
|
fetchTool,
|
|
32728
33203
|
searchTool,
|
|
32729
33204
|
todoTool,
|
|
@@ -33140,7 +33615,7 @@ var builtinToolsPack = {
|
|
|
33140
33615
|
};
|
|
33141
33616
|
|
|
33142
33617
|
// src/process-guardian.ts
|
|
33143
|
-
import * as
|
|
33618
|
+
import * as os11 from "node:os";
|
|
33144
33619
|
var ProcessGuardian = class {
|
|
33145
33620
|
registry;
|
|
33146
33621
|
config;
|
|
@@ -33276,7 +33751,7 @@ var ProcessGuardian = class {
|
|
|
33276
33751
|
event: "process_guardian.started",
|
|
33277
33752
|
instanceId: this.instanceId,
|
|
33278
33753
|
mainPid: process.pid,
|
|
33279
|
-
hostname:
|
|
33754
|
+
hostname: os11.hostname(),
|
|
33280
33755
|
platform: process.platform
|
|
33281
33756
|
})
|
|
33282
33757
|
);
|
|
@@ -33410,8 +33885,8 @@ var ProcessGuardian = class {
|
|
|
33410
33885
|
instanceId: this.instanceId,
|
|
33411
33886
|
mainPid: process.pid,
|
|
33412
33887
|
protectedCount: this.protectedProcesses.size,
|
|
33413
|
-
platform:
|
|
33414
|
-
hostname:
|
|
33888
|
+
platform: os11.platform(),
|
|
33889
|
+
hostname: os11.hostname(),
|
|
33415
33890
|
uptime: process.uptime()
|
|
33416
33891
|
};
|
|
33417
33892
|
}
|
|
@@ -33441,7 +33916,7 @@ function stopProcessGuardian() {
|
|
|
33441
33916
|
init_process_registry();
|
|
33442
33917
|
|
|
33443
33918
|
// src/ps-slash.ts
|
|
33444
|
-
import * as
|
|
33919
|
+
import * as os12 from "node:os";
|
|
33445
33920
|
var IDLE_THRESHOLD_MS = 2 * 6e4;
|
|
33446
33921
|
var STALE_THRESHOLD_MS2 = 5 * 6e4;
|
|
33447
33922
|
function now() {
|
|
@@ -33482,7 +33957,7 @@ async function listInstances(options = {}) {
|
|
|
33482
33957
|
const mainProc = processes.find((p) => p.spawnMode === "main");
|
|
33483
33958
|
const firstProc = processes.at(0);
|
|
33484
33959
|
const mainPid = mainProc?.pid ?? firstProc?.pid ?? 0;
|
|
33485
|
-
const hostname_ = firstProc?.hostname ??
|
|
33960
|
+
const hostname_ = firstProc?.hostname ?? os12.hostname();
|
|
33486
33961
|
const startedAt = Math.min(...processes.map((p) => p.startedAt));
|
|
33487
33962
|
const lastActivity = Math.max(...processes.map((p) => p.lastHeartbeat));
|
|
33488
33963
|
const age = timestamp - lastActivity;
|
|
@@ -33570,7 +34045,7 @@ async function getGlobalProcessStatus() {
|
|
|
33570
34045
|
mainPid: process.pid,
|
|
33571
34046
|
protectedCount: 0,
|
|
33572
34047
|
platform: process.platform,
|
|
33573
|
-
hostname:
|
|
34048
|
+
hostname: os12.hostname(),
|
|
33574
34049
|
uptime: 0
|
|
33575
34050
|
},
|
|
33576
34051
|
allInstances: instances.map((inst) => ({
|
|
@@ -33764,8 +34239,8 @@ function createGlobalPsSlashCommand() {
|
|
|
33764
34239
|
}
|
|
33765
34240
|
|
|
33766
34241
|
// src/skill.ts
|
|
33767
|
-
import * as
|
|
33768
|
-
import * as
|
|
34242
|
+
import * as fs44 from "node:fs/promises";
|
|
34243
|
+
import * as path50 from "node:path";
|
|
33769
34244
|
import {
|
|
33770
34245
|
missingRequiredRuntimeTools,
|
|
33771
34246
|
missingRuntimeCapabilities,
|
|
@@ -33829,7 +34304,7 @@ function makeSkillTool(skillLoader) {
|
|
|
33829
34304
|
field: "name"
|
|
33830
34305
|
});
|
|
33831
34306
|
}
|
|
33832
|
-
const dir =
|
|
34307
|
+
const dir = path50.dirname(manifest.path);
|
|
33833
34308
|
let loadedResource;
|
|
33834
34309
|
if (input.resource?.trim()) {
|
|
33835
34310
|
loadedResource = await loadResource(dir, input.resource.trim());
|
|
@@ -33888,15 +34363,15 @@ ${listing}${warningLine}`;
|
|
|
33888
34363
|
}
|
|
33889
34364
|
async function loadResource(skillDir, rel) {
|
|
33890
34365
|
const norm = rel.replace(/\\/g, "/");
|
|
33891
|
-
if (
|
|
34366
|
+
if (path50.isAbsolute(rel) || norm.split("/").some((seg) => seg === "..")) {
|
|
33892
34367
|
throw new ToolValidationError13({
|
|
33893
34368
|
message: `skill: invalid resource path "${rel}"`,
|
|
33894
34369
|
field: "resource"
|
|
33895
34370
|
});
|
|
33896
34371
|
}
|
|
33897
|
-
const absPath =
|
|
33898
|
-
const root =
|
|
33899
|
-
if (absPath !== root && !absPath.startsWith(root +
|
|
34372
|
+
const absPath = path50.resolve(skillDir, rel);
|
|
34373
|
+
const root = path50.resolve(skillDir);
|
|
34374
|
+
if (absPath !== root && !absPath.startsWith(root + path50.sep)) {
|
|
33900
34375
|
throw new ToolValidationError13({
|
|
33901
34376
|
message: `skill: resource "${rel}" escapes the skill directory`,
|
|
33902
34377
|
field: "resource"
|
|
@@ -33905,15 +34380,15 @@ async function loadResource(skillDir, rel) {
|
|
|
33905
34380
|
let realPath;
|
|
33906
34381
|
let realRoot;
|
|
33907
34382
|
try {
|
|
33908
|
-
realRoot = await
|
|
33909
|
-
realPath = await
|
|
34383
|
+
realRoot = await fs44.realpath(root);
|
|
34384
|
+
realPath = await fs44.realpath(absPath);
|
|
33910
34385
|
} catch {
|
|
33911
34386
|
throw new ToolValidationError13({
|
|
33912
34387
|
message: `skill: resource "${rel}" not readable`,
|
|
33913
34388
|
field: "resource"
|
|
33914
34389
|
});
|
|
33915
34390
|
}
|
|
33916
|
-
if (realPath !== realRoot && !realPath.startsWith(realRoot +
|
|
34391
|
+
if (realPath !== realRoot && !realPath.startsWith(realRoot + path50.sep)) {
|
|
33917
34392
|
throw new ToolValidationError13({
|
|
33918
34393
|
message: `skill: resource "${rel}" resolves outside the skill directory`,
|
|
33919
34394
|
field: "resource"
|
|
@@ -33921,7 +34396,7 @@ async function loadResource(skillDir, rel) {
|
|
|
33921
34396
|
}
|
|
33922
34397
|
let buf;
|
|
33923
34398
|
try {
|
|
33924
|
-
buf = await
|
|
34399
|
+
buf = await fs44.readFile(realPath);
|
|
33925
34400
|
} catch {
|
|
33926
34401
|
throw new ToolValidationError13({
|
|
33927
34402
|
message: `skill: resource "${rel}" not readable`,
|
|
@@ -33950,17 +34425,17 @@ async function walk(root, dir, out) {
|
|
|
33950
34425
|
if (out.length >= MAX_LISTED_RESOURCES) return;
|
|
33951
34426
|
let entries;
|
|
33952
34427
|
try {
|
|
33953
|
-
entries = await
|
|
34428
|
+
entries = await fs44.readdir(dir, { withFileTypes: true });
|
|
33954
34429
|
} catch {
|
|
33955
34430
|
return;
|
|
33956
34431
|
}
|
|
33957
34432
|
for (const e of entries) {
|
|
33958
34433
|
if (out.length >= MAX_LISTED_RESOURCES) return;
|
|
33959
|
-
const fullPath =
|
|
34434
|
+
const fullPath = path50.join(dir, e.name);
|
|
33960
34435
|
let isDir = e.isDirectory();
|
|
33961
34436
|
if (e.isSymbolicLink()) {
|
|
33962
34437
|
try {
|
|
33963
|
-
isDir = (await
|
|
34438
|
+
isDir = (await fs44.stat(fullPath)).isDirectory();
|
|
33964
34439
|
} catch {
|
|
33965
34440
|
continue;
|
|
33966
34441
|
}
|
|
@@ -33971,8 +34446,8 @@ async function walk(root, dir, out) {
|
|
|
33971
34446
|
} else if (e.isFile()) {
|
|
33972
34447
|
if (e.name === "SKILL.md" || e.name === "SKILL.save.md") continue;
|
|
33973
34448
|
try {
|
|
33974
|
-
const stat22 = await
|
|
33975
|
-
const rel =
|
|
34449
|
+
const stat22 = await fs44.stat(fullPath);
|
|
34450
|
+
const rel = path50.relative(root, fullPath).split(path50.sep).join("/");
|
|
33976
34451
|
out.push({ path: rel, bytes: stat22.size });
|
|
33977
34452
|
} catch {
|
|
33978
34453
|
}
|
|
@@ -33998,6 +34473,8 @@ var TOOL_ICON_MAP = {
|
|
|
33998
34473
|
// Shell/command execution
|
|
33999
34474
|
bash: "terminal",
|
|
34000
34475
|
exec: "terminal",
|
|
34476
|
+
pwsh: "terminal",
|
|
34477
|
+
powershell: "terminal",
|
|
34001
34478
|
run: "terminal",
|
|
34002
34479
|
command: "terminal",
|
|
34003
34480
|
shell: "terminal",
|
|
@@ -34205,6 +34682,7 @@ export {
|
|
|
34205
34682
|
OFF_ONLY_TOOLS,
|
|
34206
34683
|
OPTIONAL_TOOLS,
|
|
34207
34684
|
PRIMARY_LANGUAGE_PROFILES,
|
|
34685
|
+
PWSH_TOOL_DESCRIPTION,
|
|
34208
34686
|
SESSION_KANBAN_COLUMNS,
|
|
34209
34687
|
TIER1_TOOLS,
|
|
34210
34688
|
TIER2_TOOLS,
|
|
@@ -34332,6 +34810,7 @@ export {
|
|
|
34332
34810
|
projectSessionPlanToKanban,
|
|
34333
34811
|
projectSessionTasksToKanban,
|
|
34334
34812
|
projectSessionTodosToKanban,
|
|
34813
|
+
pwshTool,
|
|
34335
34814
|
readTool,
|
|
34336
34815
|
rebindSessionKanbanTask,
|
|
34337
34816
|
recordKanbanVerificationEvidence,
|