@wrongstack/tools 0.307.1 → 0.308.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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((resolve24) => {
1038
- waiter = resolve24;
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 fs44 = await import("node:fs/promises");
1141
+ const fs45 = await import("node:fs/promises");
1142
1142
  try {
1143
- const raw = await fs44.readFile(path3.join(dir, "package.json"), "utf8");
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 fs44.stat(`${dir}/${file}`);
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 path50 of after) {
4144
- if (!beforeSet.has(path50)) changed.add(path50);
4143
+ for (const path51 of after) {
4144
+ if (!beforeSet.has(path51)) changed.add(path51);
4145
4145
  }
4146
- for (const path50 of before) {
4147
- if (!afterSet.has(path50)) changed.add(path50);
4146
+ for (const path51 of before) {
4147
+ if (!afterSet.has(path51)) changed.add(path51);
4148
4148
  }
4149
4149
  if (beforeSizes && afterSizes) {
4150
- for (const path50 of after) {
4151
- if (beforeSizes.get(path50) !== afterSizes.get(path50)) changed.add(path50);
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
- (resolve24, reject) => {
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
- resolve24({ code: code2, stdout: stdout2 });
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((resolve24) => {
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
- resolve24(available);
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((resolve24, reject) => {
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
- resolve24({ code, stdout });
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(platform6, env, deps = {}) {
8112
- if (platform6 !== "win32") return void 0;
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 platform6 = opts.platform ?? process.platform;
8123
- if (platform6 !== "win32") return void 0;
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(platform6, { get: (k) => env[k] }, { hasBinary: opts.hasBinary }) ?? "cmd";
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
- return registry.shouldBlockKill(kill.pid);
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(platform6, command, env) {
9159
- if (platform6 !== "win32") return POSIX_DEFAULT;
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((resolve24) => {
9666
+ const next = () => new Promise((resolve25) => {
9619
9667
  const c = queue.shift();
9620
- if (c) resolve24(c);
9621
- else resolveNext = resolve24;
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((resolve24, reject) => {
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", resolve24);
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((resolve24, reject) => {
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
- resolve24(this.url);
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((resolve24) => this.server.close(() => resolve24()));
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((resolve24, reject) => {
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(() => resolve24(value));
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((resolve24) => {
14391
- const timer = setTimeout(resolve24, ms);
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((resolve24, reject) => {
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: resolve24,
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((resolve24, reject) => {
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
- resolve24();
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((resolve24, reject) => {
15798
+ return new Promise((resolve25, reject) => {
15751
15799
  this.pending.set(batchId, {
15752
- resolve: resolve24,
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((resolve24) => {
15784
- w.once("exit", () => resolve24());
15831
+ new Promise((resolve25) => {
15832
+ w.once("exit", () => resolve25());
15785
15833
  }),
15786
- new Promise((resolve24) => setTimeout(() => resolve24(), 2e3))
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((resolve24) => setImmediate(resolve24));
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((resolve24, reject) => {
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 resolve24(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
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((resolve24, reject) => {
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
- resolve24(v);
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((resolve24) => {
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) => resolve24({ stdout, stderr, exitCode: code ?? 0 }));
20299
- child.on("error", (e) => resolve24({ stdout: "", stderr: e.message, exitCode: 1 }));
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((resolve24) => {
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
- resolve24(result);
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 fs44 = await import("node:fs/promises");
23346
+ const fs45 = await import("node:fs/promises");
23299
23347
  const exists = async (file) => {
23300
23348
  try {
23301
- await fs44.stat(`${cwd}/${file}`);
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 fs44.readFile(`${cwd}/package.json`, "utf8");
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((resolve24) => {
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
- resolve24({
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
- resolve24({
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((resolve24) => {
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", () => resolve24(false));
24044
- p.on("close", (code) => resolve24(code === 0));
24091
+ p.on("error", () => resolve25(false));
24092
+ p.on("close", (code) => resolve25(code === 0));
24045
24093
  } catch {
24046
- resolve24(false);
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, path50) {
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(`${path50}: expected integer, got ${actualType}`);
25141
+ if (!Number.isInteger(value)) errors.push(`${path51}: expected integer, got ${actualType}`);
25094
25142
  } else if (expectedType !== actualType) {
25095
- errors.push(`${path50}: expected ${expectedType}, got ${actualType}`);
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(`${path50}: not a valid URI`);
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(`${path50}: invalid schema pattern \u2014 ${compiled.reason}`);
25156
+ errors.push(`${path51}: invalid schema pattern \u2014 ${compiled.reason}`);
25109
25157
  } else if (!compiled.regex.test(capSubject(value))) {
25110
- errors.push(`${path50}: does not match pattern ${s["pattern"]}`);
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(`${path50}: string too short (min ${s["minLength"]})`);
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(`${path50}: string too long (max ${s["maxLength"]})`);
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(`${path50}: below minimum ${s["minimum"]}`);
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(`${path50}: above maximum ${s["maximum"]}`);
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"], `${path50}[${i}]`);
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, `${path50}.${k}`);
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, path50) {
25141
- const parts = path50.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
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;
@@ -28250,7 +28298,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
28250
28298
  };
28251
28299
  }
28252
28300
  args.push("--timestamps", service);
28253
- return new Promise((resolve24) => {
28301
+ return new Promise((resolve25) => {
28254
28302
  let stdout = "";
28255
28303
  let stderr = "";
28256
28304
  const MAX = 2e5;
@@ -28266,7 +28314,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
28266
28314
  if (settled) return;
28267
28315
  settled = true;
28268
28316
  clearTimeout(timer);
28269
- resolve24(result);
28317
+ resolve25(result);
28270
28318
  };
28271
28319
  const child = spawn11("docker", args, {
28272
28320
  cwd,
@@ -28311,7 +28359,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
28311
28359
  }
28312
28360
  var DOCKER_LOGS_TIMEOUT_MS = 3e3;
28313
28361
  var MAX_TAIL_LINES = 1e5;
28314
- async function fileLogs(path50, lines, filterRe) {
28362
+ async function fileLogs(path51, lines, filterRe) {
28315
28363
  const { createInterface } = await import("node:readline");
28316
28364
  const { createReadStream: createReadStream2 } = await import("node:fs");
28317
28365
  const entries = [];
@@ -28320,7 +28368,7 @@ async function fileLogs(path50, lines, filterRe) {
28320
28368
  let writeIdx = 0;
28321
28369
  let totalLines = 0;
28322
28370
  const rl = createInterface({
28323
- input: createReadStream2(path50),
28371
+ input: createReadStream2(path51),
28324
28372
  crlfDelay: Number.POSITIVE_INFINITY
28325
28373
  });
28326
28374
  for await (const line of rl) {
@@ -28341,7 +28389,7 @@ async function fileLogs(path50, lines, filterRe) {
28341
28389
  if (parsed) entries.push(parsed);
28342
28390
  }
28343
28391
  return {
28344
- source: path50,
28392
+ source: path51,
28345
28393
  entries,
28346
28394
  total: entries.length,
28347
28395
  truncated: totalLines > effLines,
@@ -28483,7 +28531,7 @@ var outdatedTool = {
28483
28531
  }
28484
28532
  };
28485
28533
  function runOutdated(manager, args, cwd, signal) {
28486
- return new Promise((resolve24) => {
28534
+ return new Promise((resolve25) => {
28487
28535
  let stdout = "";
28488
28536
  let stderr = "";
28489
28537
  const MAX = 1e5;
@@ -28508,10 +28556,10 @@ function runOutdated(manager, args, cwd, signal) {
28508
28556
  });
28509
28557
  child.on("close", (code) => {
28510
28558
  const result = parseOutdatedOutput(stdout, code ?? 0);
28511
- resolve24(result);
28559
+ resolve25(result);
28512
28560
  });
28513
28561
  child.on("error", (e) => {
28514
- resolve24({
28562
+ resolve25({
28515
28563
  exit_code: 1,
28516
28564
  packages: [],
28517
28565
  total: 0,
@@ -28830,7 +28878,7 @@ function runPatch(args, cwd, signal, fallback) {
28830
28878
  });
28831
28879
  }
28832
28880
  function runPatchProcess(command, args, cwd, signal) {
28833
- return new Promise((resolve24) => {
28881
+ return new Promise((resolve25) => {
28834
28882
  let stdout = "";
28835
28883
  let stderr = "";
28836
28884
  const env = { ...buildChildEnv8(), LANG: "C", LC_ALL: "C" };
@@ -28849,11 +28897,11 @@ function runPatchProcess(command, args, cwd, signal) {
28849
28897
  });
28850
28898
  child.on(
28851
28899
  "close",
28852
- (code) => resolve24({ exitCode: code ?? 1, stdout, stderr, unavailable: false })
28900
+ (code) => resolve25({ exitCode: code ?? 1, stdout, stderr, unavailable: false })
28853
28901
  );
28854
28902
  child.on(
28855
28903
  "error",
28856
- (e) => resolve24({
28904
+ (e) => resolve25({
28857
28905
  exitCode: 1,
28858
28906
  stdout: "",
28859
28907
  stderr: e.message,
@@ -29642,9 +29690,428 @@ function mkResult(plan, ok, message, todos) {
29642
29690
  return result;
29643
29691
  }
29644
29692
 
29693
+ // src/pwsh.ts
29694
+ import { spawn as spawn14 } from "node:child_process";
29695
+ import * as fs36 from "node:fs";
29696
+ import * as os10 from "node:os";
29697
+ import * as path43 from "node:path";
29698
+ import { StringDecoder as StringDecoder3 } from "node:string_decoder";
29699
+ import {
29700
+ emitProcessCompleted as emitProcessCompleted4,
29701
+ emitProcessOutput as emitProcessOutput4,
29702
+ emitProcessStarted as emitProcessStarted4
29703
+ } from "@wrongstack/core/observability";
29704
+ init_output_spool();
29705
+ init_util();
29706
+ init_process_registry();
29707
+ init_win32_resolve();
29708
+ var MAX_OUTPUT4 = 32768;
29709
+ var DEFAULT_TIMEOUT_MS4 = 3e5;
29710
+ var STREAM_FLUSH_INTERVAL_MS2 = 200;
29711
+ var STREAM_FLUSH_BYTES2 = 4 * 1024;
29712
+ var MAX_QUEUE_CHUNKS2 = 500;
29713
+ 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`.";
29714
+ 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`.";
29715
+ function wrapPwshCommand(command) {
29716
+ const bootstrap = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;$ProgressPreference = 'SilentlyContinue';$ConfirmPreference = 'None';$WhatIfPreference = $false";
29717
+ return `${bootstrap}
29718
+ $ErrorActionPreference = 'Stop'
29719
+ ${command}
29720
+ if ($LASTEXITCODE -is [int]) { exit $LASTEXITCODE }`;
29721
+ }
29722
+ var pwshTool = {
29723
+ name: "pwsh",
29724
+ category: "Shell",
29725
+ description: PWSH_TOOL_DESCRIPTION,
29726
+ usageHint: PWSH_TOOL_USAGE_HINT,
29727
+ selection: {
29728
+ doNotUseWhen: "the command is an allowlisted single binary (node, git, pnpm, tsc) needing no shell expansion or pipelines.",
29729
+ useInstead: ["exec"]
29730
+ },
29731
+ permission: "confirm",
29732
+ mutating: true,
29733
+ riskTier: "destructive",
29734
+ icon: "terminal",
29735
+ subjectKey: "command",
29736
+ capabilities: ["shell.arbitrary"],
29737
+ timeoutMs: 61e4,
29738
+ maxOutputBytes: MAX_OUTPUT4,
29739
+ estimatedDurationMs: 3e4,
29740
+ inputSchema: {
29741
+ type: "object",
29742
+ properties: {
29743
+ command: {
29744
+ type: "string",
29745
+ description: "The exact PowerShell command or script block to run."
29746
+ },
29747
+ workdir: {
29748
+ type: "string",
29749
+ description: "Absolute or project-relative path to the working directory for this command. Defaults to session working directory."
29750
+ },
29751
+ timeout_ms: {
29752
+ type: "integer",
29753
+ description: "Optional timeout for this specific command in milliseconds (default 300000, max 600000)."
29754
+ },
29755
+ run_in_background: {
29756
+ type: "boolean",
29757
+ description: "If true, launch the process in the background and return the job ID / PID immediately."
29758
+ },
29759
+ background: {
29760
+ type: "boolean",
29761
+ description: "Alias for run_in_background."
29762
+ },
29763
+ sandbox_permissions: {
29764
+ type: "string",
29765
+ description: "Escalation mode if retrying a sandbox-denied command (e.g., workspace-write)."
29766
+ },
29767
+ justification: {
29768
+ type: "string",
29769
+ description: "One-sentence justification when retrying a denied command with sandbox_permissions."
29770
+ }
29771
+ },
29772
+ required: ["command"]
29773
+ },
29774
+ async execute(input, ctx, opts) {
29775
+ let final;
29776
+ const executeStream = pwshTool.executeStream;
29777
+ if (!executeStream) throw new Error("pwshTool: stream execution unavailable");
29778
+ for await (const ev of executeStream(input, ctx, opts)) {
29779
+ if (ev.type === "final") final = ev.output;
29780
+ }
29781
+ if (!final) throw new Error("pwsh: stream ended without final event");
29782
+ return final;
29783
+ },
29784
+ async *executeStream(input, ctx, opts) {
29785
+ if (!input?.command) throw new Error("pwsh: command is required");
29786
+ const isBackground = !!(input.run_in_background || input.background);
29787
+ const registry = getProcessRegistry();
29788
+ if (!registry.beforeCall(isBackground)) {
29789
+ yield {
29790
+ type: "final",
29791
+ output: {
29792
+ output: "",
29793
+ exit_code: 1,
29794
+ timed_out: false,
29795
+ pid: null,
29796
+ error: "pwsh: circuit breaker open \u2014 too many consecutive failures or slow calls. Use /kill to inspect or /kill reset to recover."
29797
+ }
29798
+ };
29799
+ return;
29800
+ }
29801
+ const killCheck = await checkAndBlockKillCommand(input.command);
29802
+ if (killCheck.blocked) {
29803
+ yield {
29804
+ type: "final",
29805
+ output: {
29806
+ output: "",
29807
+ exit_code: 1,
29808
+ timed_out: false,
29809
+ pid: null,
29810
+ error: `pwsh: ${killCheck.reason}`
29811
+ }
29812
+ };
29813
+ return;
29814
+ }
29815
+ const isWin5 = os10.platform() === "win32";
29816
+ const bin = isWin5 ? resolvePowerShell("pwsh.exe") : "pwsh";
29817
+ const args = shellArgs("pwsh");
29818
+ const stdinBody = wrapPwshCommand(input.command);
29819
+ const env = buildChildEnv2(ctx.session?.id);
29820
+ let targetCwd = ctx.workingDir ?? ctx.projectRoot;
29821
+ if (input.workdir) {
29822
+ const resolved = path43.isAbsolute(input.workdir) ? input.workdir : path43.resolve(ctx.projectRoot, input.workdir);
29823
+ if (fs36.existsSync(resolved)) {
29824
+ targetCwd = resolved;
29825
+ }
29826
+ }
29827
+ const startedAt = Date.now();
29828
+ const detached = !isWin5;
29829
+ if (isBackground) {
29830
+ const child2 = spawn14(bin, args, {
29831
+ cwd: targetCwd,
29832
+ env,
29833
+ detached,
29834
+ stdio: ["pipe", "ignore", "ignore"],
29835
+ windowsHide: true
29836
+ });
29837
+ if (child2.stdin) {
29838
+ child2.stdin.write(stdinBody);
29839
+ child2.stdin.end();
29840
+ }
29841
+ const pid2 = child2.pid;
29842
+ if (typeof pid2 === "number") {
29843
+ registry.register({
29844
+ pid: pid2,
29845
+ name: "pwsh",
29846
+ command: redactCommand(input.command),
29847
+ startedAt: Date.now(),
29848
+ sessionId: ctx.session?.id,
29849
+ child: child2,
29850
+ processGroupLeader: detached && child2.pid === pid2,
29851
+ background: true
29852
+ });
29853
+ child2.on("close", () => registry.unregister(pid2));
29854
+ child2.on("error", () => {
29855
+ registry.unregister(pid2);
29856
+ registry.afterCall(Date.now() - startedAt, true, isBackground);
29857
+ });
29858
+ child2.unref();
29859
+ const jobId = `job_${pid2}`;
29860
+ ctx.recordSideEffect?.({
29861
+ toolUseId: `pwsh-bg-${Date.now()}`,
29862
+ toolName: "pwsh",
29863
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
29864
+ input: { command: redactCommand(input.command), background: true },
29865
+ outcome: `started background job ${jobId} (PID: ${pid2})`,
29866
+ risk: "shell"
29867
+ });
29868
+ yield {
29869
+ type: "final",
29870
+ output: {
29871
+ output: `Background job started: ${jobId} (PID: ${pid2})
29872
+ Working directory: ${targetCwd}`,
29873
+ exit_code: null,
29874
+ timed_out: false,
29875
+ pid: pid2,
29876
+ job_id: jobId
29877
+ }
29878
+ };
29879
+ return;
29880
+ }
29881
+ yield {
29882
+ type: "final",
29883
+ output: {
29884
+ output: "",
29885
+ exit_code: 1,
29886
+ timed_out: false,
29887
+ pid: null,
29888
+ error: "pwsh: failed to obtain PID for background process"
29889
+ }
29890
+ };
29891
+ return;
29892
+ }
29893
+ const spool = createOutputSpool({ tool: "pwsh", thresholdBytes: MAX_OUTPUT4 });
29894
+ const child = spawn14(bin, args, {
29895
+ cwd: targetCwd,
29896
+ env,
29897
+ detached,
29898
+ stdio: ["pipe", "pipe", "pipe"],
29899
+ windowsHide: true
29900
+ });
29901
+ const pid = child.pid;
29902
+ let stdoutBytes = 0;
29903
+ let stderrBytes = 0;
29904
+ let telemetryCompleted = false;
29905
+ emitProcessStarted4({
29906
+ ...pid !== void 0 ? { pid } : {},
29907
+ parentPid: process.pid,
29908
+ command: redactCommand(`${bin} ${args.join(" ")}`),
29909
+ args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
29910
+ cwd: targetCwd,
29911
+ background: false,
29912
+ startedAt: new Date(startedAt).toISOString()
29913
+ });
29914
+ const completeForeground = (exitCode, sig) => {
29915
+ if (telemetryCompleted) return;
29916
+ telemetryCompleted = true;
29917
+ emitProcessCompleted4({
29918
+ ...pid !== void 0 ? { pid } : {},
29919
+ exitCode,
29920
+ ...sig ? { signal: sig } : {},
29921
+ durationMs: Date.now() - startedAt,
29922
+ stdoutBytes,
29923
+ stderrBytes,
29924
+ timedOut,
29925
+ endedAt: (/* @__PURE__ */ new Date()).toISOString()
29926
+ });
29927
+ };
29928
+ if (typeof pid === "number") {
29929
+ registry.register({
29930
+ pid,
29931
+ name: "pwsh",
29932
+ command: redactCommand(input.command),
29933
+ startedAt: Date.now(),
29934
+ sessionId: ctx.session?.id,
29935
+ child,
29936
+ processGroupLeader: detached && child.pid === pid
29937
+ });
29938
+ }
29939
+ if (child.stdin) {
29940
+ child.stdin.write(stdinBody);
29941
+ child.stdin.end();
29942
+ }
29943
+ const timeoutMs = Math.min(
29944
+ Math.max(1e3, input.timeout_ms ?? DEFAULT_TIMEOUT_MS4),
29945
+ 6e5
29946
+ );
29947
+ let timedOut = false;
29948
+ const timers = [];
29949
+ const killWithTimeout = (timeout) => {
29950
+ if (isWin5) {
29951
+ if (typeof child.pid === "number" && child.exitCode === null) {
29952
+ const attempted = registry.kill(child.pid, { force: true, graceMs: timeout });
29953
+ if (!attempted) {
29954
+ try {
29955
+ child.kill();
29956
+ } catch {
29957
+ }
29958
+ }
29959
+ }
29960
+ return;
29961
+ }
29962
+ if (typeof child.pid === "number") {
29963
+ registry.kill(child.pid, { graceMs: timeout });
29964
+ } else {
29965
+ try {
29966
+ child.kill("SIGTERM");
29967
+ } catch {
29968
+ }
29969
+ }
29970
+ };
29971
+ const timer = setTimeout(() => {
29972
+ timedOut = true;
29973
+ killWithTimeout(2e3);
29974
+ }, timeoutMs);
29975
+ timers.push(timer);
29976
+ const onAbort = () => killWithTimeout(2e3);
29977
+ if (opts.signal.aborted) onAbort();
29978
+ else opts.signal.addEventListener("abort", onAbort, { once: true });
29979
+ const queue = [];
29980
+ let resolveNext = null;
29981
+ const push = (c) => {
29982
+ if (resolveNext) {
29983
+ const r = resolveNext;
29984
+ resolveNext = null;
29985
+ r(c);
29986
+ } else {
29987
+ queue.push(c);
29988
+ }
29989
+ };
29990
+ const next = () => new Promise((resolve25) => {
29991
+ const c = queue.shift();
29992
+ if (c) resolve25(c);
29993
+ else resolveNext = resolve25;
29994
+ });
29995
+ let buf = "";
29996
+ let pending2 = "";
29997
+ let lastFlush = Date.now();
29998
+ const flush = () => {
29999
+ if (pending2.length === 0) return null;
30000
+ const text = pending2;
30001
+ pending2 = "";
30002
+ lastFlush = Date.now();
30003
+ return text;
30004
+ };
30005
+ let paused = false;
30006
+ const pauseIfFlooded = () => {
30007
+ if (!paused && queue.length >= MAX_QUEUE_CHUNKS2) {
30008
+ paused = true;
30009
+ child.stdout?.pause();
30010
+ child.stderr?.pause();
30011
+ }
30012
+ };
30013
+ const resumeIfDrained = () => {
30014
+ if (paused && queue.length < MAX_QUEUE_CHUNKS2) {
30015
+ paused = false;
30016
+ child.stdout?.resume();
30017
+ child.stderr?.resume();
30018
+ }
30019
+ };
30020
+ const stdoutDecoder = new StringDecoder3("utf8");
30021
+ const stderrDecoder = new StringDecoder3("utf8");
30022
+ const onData = (chunk, stream) => {
30023
+ const text = (stream === "stdout" ? stdoutDecoder : stderrDecoder).write(chunk);
30024
+ if (stream === "stdout") stdoutBytes += chunk.byteLength;
30025
+ else stderrBytes += chunk.byteLength;
30026
+ emitProcessOutput4({ pid: pid ?? 0, stream, chunk });
30027
+ if (buf.length < MAX_OUTPUT4) {
30028
+ buf += text.slice(0, MAX_OUTPUT4 - buf.length);
30029
+ }
30030
+ spool.write(text);
30031
+ pending2 += text;
30032
+ push({ kind: "data", text });
30033
+ pauseIfFlooded();
30034
+ };
30035
+ child.stdout?.on("data", (chunk) => onData(chunk, "stdout"));
30036
+ child.stderr?.on("data", (chunk) => onData(chunk, "stderr"));
30037
+ child.on("error", (err) => {
30038
+ for (const t of timers) clearTimeout(t);
30039
+ registry.afterCall(Date.now() - startedAt, true);
30040
+ completeForeground(1);
30041
+ push({ kind: "error", err });
30042
+ });
30043
+ child.on("close", (code, signal) => {
30044
+ for (const t of timers) clearTimeout(t);
30045
+ if (typeof pid === "number") registry.unregister(pid);
30046
+ registry.afterCall(Date.now() - startedAt, code !== 0 && code !== null);
30047
+ completeForeground(timedOut ? 124 : code ?? (signal ? 1 : 0), signal ?? void 0);
30048
+ const tail = stdoutDecoder.end() + stderrDecoder.end();
30049
+ if (tail) {
30050
+ if (buf.length < MAX_OUTPUT4) buf += tail.slice(0, MAX_OUTPUT4 - buf.length);
30051
+ spool.write(tail);
30052
+ pending2 += tail;
30053
+ }
30054
+ push({ kind: "end", code });
30055
+ });
30056
+ try {
30057
+ while (true) {
30058
+ const c = await next();
30059
+ resumeIfDrained();
30060
+ if (c.kind === "error") throw c.err;
30061
+ if (c.kind === "end") {
30062
+ const remainder = flush();
30063
+ if (remainder !== null) {
30064
+ yield { type: "partial_output", text: remainder };
30065
+ }
30066
+ const spooled = spool.finalize();
30067
+ let formattedOutput = normalizeCommandOutput(buf);
30068
+ if (c.code !== null && c.code !== 0 && !timedOut) {
30069
+ if (!formattedOutput.includes(`[exit code: ${c.code}]`)) {
30070
+ formattedOutput = formattedOutput ? `${formattedOutput}
30071
+ [exit code: ${c.code}]` : `[exit code: ${c.code}]`;
30072
+ }
30073
+ }
30074
+ const hint = !timedOut && typeof c.code === "number" && c.code !== 0 ? diagnoseBashism(input.command, "pwsh") : void 0;
30075
+ const danger = detectDanger("pwsh", [input.command]);
30076
+ const cautionText = danger.level === "caution" && danger.reasons.length > 0 ? `
30077
+ [caution: ${danger.reasons.join("; ")}]` : "";
30078
+ const finalResultText = formattedOutput + (spooled ? spoolNote(spooled) : "") + (hint ? `
30079
+
30080
+ ${hint}` : "") + cautionText;
30081
+ ctx.recordSideEffect?.({
30082
+ toolUseId: `pwsh-${Date.now()}`,
30083
+ toolName: "pwsh",
30084
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
30085
+ input: { command: redactCommand(input.command) },
30086
+ outcome: timedOut ? `timed out (exit ${c.code})` : `exit ${c.code}`,
30087
+ risk: "shell"
30088
+ });
30089
+ yield {
30090
+ type: "final",
30091
+ output: {
30092
+ output: finalResultText,
30093
+ exit_code: timedOut ? 1 : c.code,
30094
+ timed_out: timedOut,
30095
+ pid
30096
+ }
30097
+ };
30098
+ return;
30099
+ }
30100
+ const now2 = Date.now();
30101
+ if (pending2.length >= STREAM_FLUSH_BYTES2 || now2 - lastFlush >= STREAM_FLUSH_INTERVAL_MS2) {
30102
+ const text = flush();
30103
+ if (text) yield { type: "partial_output", text };
30104
+ }
30105
+ }
30106
+ } finally {
30107
+ for (const t of timers) clearTimeout(t);
30108
+ }
30109
+ }
30110
+ };
30111
+
29645
30112
  // src/read.ts
29646
30113
  init_util();
29647
- import * as fs36 from "node:fs/promises";
30114
+ import * as fs37 from "node:fs/promises";
29648
30115
  import { FsError, ToolValidationError as ToolValidationError8 } from "@wrongstack/core/types";
29649
30116
  import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
29650
30117
  var ADVANCED_MODE_META_KEY = "tools.read.advancedMode";
@@ -29704,7 +30171,7 @@ var readTool = {
29704
30171
  const shouldIncludeSymbols = input.includeSymbols === true || input.includeSymbols !== false && ctx.meta[ADVANCED_MODE_META_KEY] === true;
29705
30172
  let stat22;
29706
30173
  try {
29707
- stat22 = await fs36.stat(absPath);
30174
+ stat22 = await fs37.stat(absPath);
29708
30175
  } catch (err) {
29709
30176
  const code = err.code;
29710
30177
  if (code === "ENOENT") {
@@ -29756,7 +30223,7 @@ var readTool = {
29756
30223
  ...symResult2?.symbols ? { symbols: symResult2.symbols } : {}
29757
30224
  };
29758
30225
  }
29759
- const buf = await fs36.readFile(absPath);
30226
+ const buf = await fs37.readFile(absPath);
29760
30227
  if (isBinaryBuffer(buf)) {
29761
30228
  throw new FsError({
29762
30229
  message: `read: "${input.path}" appears to be binary`,
@@ -29922,9 +30389,9 @@ ${interesting.join("\n")}` : "symbols/imports: (none detected)"
29922
30389
  }
29923
30390
 
29924
30391
  // src/replace.ts
29925
- import { spawn as spawn14 } from "node:child_process";
29926
- import * as fs37 from "node:fs/promises";
29927
- import * as path43 from "node:path";
30392
+ import { spawn as spawn15 } from "node:child_process";
30393
+ import * as fs38 from "node:fs/promises";
30394
+ import * as path44 from "node:path";
29928
30395
  import { ToolValidationError as ToolValidationError9 } from "@wrongstack/core/types";
29929
30396
  import {
29930
30397
  atomicWrite as atomicWrite4,
@@ -30007,14 +30474,14 @@ var replaceTool = {
30007
30474
  const dryRun = input.dry_run ?? true;
30008
30475
  const filesInput = Array.isArray(input.files) ? input.files.join(",") : input.files;
30009
30476
  const fileList = await resolveFiles2(filesInput, ctx, globRe);
30010
- const realRoot = await fs37.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
30477
+ const realRoot = await fs38.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
30011
30478
  const results = [];
30012
30479
  let totalReplacements = 0;
30013
30480
  let diffBytesUsed = 0;
30014
30481
  let diffsOmitted = 0;
30015
30482
  let diffsTruncated = 0;
30016
30483
  for (const absPath of fileList) {
30017
- const lstat2 = await fs37.lstat(absPath).catch((err) => {
30484
+ const lstat2 = await fs38.lstat(absPath).catch((err) => {
30018
30485
  if (err.code === "ENOENT") return null;
30019
30486
  throw err;
30020
30487
  });
@@ -30022,17 +30489,17 @@ var replaceTool = {
30022
30489
  if (lstat2.isSymbolicLink()) continue;
30023
30490
  let realPath;
30024
30491
  try {
30025
- realPath = await fs37.realpath(absPath);
30492
+ realPath = await fs38.realpath(absPath);
30026
30493
  } catch {
30027
30494
  continue;
30028
30495
  }
30029
- const rel = path43.relative(realRoot, realPath);
30030
- if (rel.startsWith("..") || path43.isAbsolute(rel)) continue;
30031
- const stat22 = await fs37.stat(realPath).catch(() => null);
30496
+ const rel = path44.relative(realRoot, realPath);
30497
+ if (rel.startsWith("..") || path44.isAbsolute(rel)) continue;
30498
+ const stat22 = await fs38.stat(realPath).catch(() => null);
30032
30499
  if (!stat22?.isFile()) continue;
30033
30500
  let content;
30034
30501
  try {
30035
- const buf = await fs37.readFile(realPath);
30502
+ const buf = await fs38.readFile(realPath);
30036
30503
  if (isBinaryBuffer(buf)) continue;
30037
30504
  content = buf.toString("utf8");
30038
30505
  } catch {
@@ -30055,7 +30522,7 @@ var replaceTool = {
30055
30522
  if (!dryRun) {
30056
30523
  const newContent = toStyle2(newContentLf, style);
30057
30524
  await atomicWrite4(realPath, newContent, { mode: stat22.mode & 511 });
30058
- const written = await fs37.stat(realPath).catch(() => null);
30525
+ const written = await fs38.stat(realPath).catch(() => null);
30059
30526
  if (written) {
30060
30527
  ctx.recordRead?.(realPath, written.mtimeMs, "write", sha256hex(newContent));
30061
30528
  }
@@ -30155,8 +30622,8 @@ async function resolveFiles2(filesInput, ctx, extraGlob) {
30155
30622
  const resolved = [];
30156
30623
  for (const p of parts) {
30157
30624
  const absPath = await safeResolveReal(p, ctx);
30158
- if (extraGlob && !passesExtraGlob(extraGlob, path43.basename(absPath), absPath)) continue;
30159
- const stat22 = await fs37.stat(absPath).catch(() => null);
30625
+ if (extraGlob && !passesExtraGlob(extraGlob, path44.basename(absPath), absPath)) continue;
30626
+ const stat22 = await fs38.stat(absPath).catch(() => null);
30160
30627
  if (stat22?.isFile()) {
30161
30628
  resolved.push(absPath);
30162
30629
  }
@@ -30170,7 +30637,7 @@ async function globFiles(pattern, base, extraGlob) {
30170
30637
  const { promise } = spawnRgFind(pattern, base);
30171
30638
  const files = await promise;
30172
30639
  if (extraGlob) {
30173
- return files.filter((f) => passesExtraGlob(extraGlob, path43.basename(f), f));
30640
+ return files.filter((f) => passesExtraGlob(extraGlob, path44.basename(f), f));
30174
30641
  }
30175
30642
  return files;
30176
30643
  } catch {
@@ -30180,24 +30647,24 @@ async function globFiles(pattern, base, extraGlob) {
30180
30647
  }
30181
30648
  var rgAvailabilityCache2;
30182
30649
  function checkRg() {
30183
- rgAvailabilityCache2 ??= new Promise((resolve24) => {
30650
+ rgAvailabilityCache2 ??= new Promise((resolve25) => {
30184
30651
  try {
30185
- const p = spawn14("rg", ["--version"], {
30652
+ const p = spawn15("rg", ["--version"], {
30186
30653
  env: buildChildEnv9(),
30187
30654
  stdio: "ignore",
30188
30655
  windowsHide: true
30189
30656
  });
30190
- p.on("error", () => resolve24(false));
30191
- p.on("close", (code) => resolve24(code === 0));
30657
+ p.on("error", () => resolve25(false));
30658
+ p.on("close", (code) => resolve25(code === 0));
30192
30659
  } catch {
30193
- resolve24(false);
30660
+ resolve25(false);
30194
30661
  }
30195
30662
  });
30196
30663
  return rgAvailabilityCache2;
30197
30664
  }
30198
30665
  function spawnRgFind(pattern, base) {
30199
30666
  const args = ["--files", "--glob", pattern, base];
30200
- const child = spawn14("rg", args, {
30667
+ const child = spawn15("rg", args, {
30201
30668
  signal: AbortSignal.timeout(3e4),
30202
30669
  env: buildChildEnv9(),
30203
30670
  stdio: ["ignore", "pipe", "pipe"],
@@ -30216,10 +30683,10 @@ function spawnRgFind(pattern, base) {
30216
30683
  }
30217
30684
  });
30218
30685
  return {
30219
- promise: new Promise((resolve24, reject) => {
30686
+ promise: new Promise((resolve25, reject) => {
30220
30687
  child.on("error", reject);
30221
30688
  child.on("close", () => {
30222
- resolve24(buf.split("\n").filter(Boolean));
30689
+ resolve25(buf.split("\n").filter(Boolean));
30223
30690
  });
30224
30691
  })
30225
30692
  };
@@ -30230,15 +30697,15 @@ async function globNative(pattern, base, extraGlob) {
30230
30697
  const walk2 = async (dir) => {
30231
30698
  let entries;
30232
30699
  try {
30233
- entries = await fs37.readdir(dir, { withFileTypes: true });
30700
+ entries = await fs38.readdir(dir, { withFileTypes: true });
30234
30701
  } catch {
30235
30702
  return;
30236
30703
  }
30237
30704
  for (const e of entries) {
30238
30705
  if (DEFAULT_IGNORE4.includes(e.name)) continue;
30239
- const full = path43.join(dir, e.name);
30706
+ const full = path44.join(dir, e.name);
30240
30707
  try {
30241
- const stat22 = await fs37.lstat(full);
30708
+ const stat22 = await fs38.lstat(full);
30242
30709
  if (stat22.isSymbolicLink()) continue;
30243
30710
  } catch {
30244
30711
  continue;
@@ -30262,8 +30729,8 @@ async function globNative(pattern, base, extraGlob) {
30262
30729
 
30263
30730
  // src/scaffold.ts
30264
30731
  init_util();
30265
- import * as fs38 from "node:fs/promises";
30266
- import * as path44 from "node:path";
30732
+ import * as fs39 from "node:fs/promises";
30733
+ import * as path45 from "node:path";
30267
30734
  import { atomicWrite as atomicWrite5 } from "@wrongstack/core/utils";
30268
30735
  var BUILT_IN_TEMPLATES = {
30269
30736
  "npm-package": {
@@ -30414,16 +30881,16 @@ async function handleBuiltIn(name, templateFiles, cwd, ctx, dryRun, vars) {
30414
30881
  let filesCreated = 0;
30415
30882
  for (const [filePath, content] of Object.entries(templateFiles)) {
30416
30883
  const resolvedPath = substituteVars(filePath, name, vars);
30417
- const joinedPath = path44.join(cwd, resolvedPath);
30418
- const root = path44.resolve(ctx.projectRoot);
30419
- const target = path44.resolve(joinedPath);
30420
- const rel = path44.relative(root, target);
30421
- if (rel.startsWith("..") || path44.isAbsolute(rel)) {
30884
+ const joinedPath = path45.join(cwd, resolvedPath);
30885
+ const root = path45.resolve(ctx.projectRoot);
30886
+ const target = path45.resolve(joinedPath);
30887
+ const rel = path45.relative(root, target);
30888
+ if (rel.startsWith("..") || path45.isAbsolute(rel)) {
30422
30889
  throw new Error(`scaffold: generated path "${resolvedPath}" would escape project root`);
30423
30890
  }
30424
30891
  const fullPath = target;
30425
30892
  if (!dryRun) {
30426
- await fs38.mkdir(path44.dirname(fullPath), { recursive: true });
30893
+ await fs39.mkdir(path45.dirname(fullPath), { recursive: true });
30427
30894
  await atomicWrite5(fullPath, substituteVars(content, name, vars));
30428
30895
  }
30429
30896
  files.push(resolvedPath);
@@ -30869,8 +31336,8 @@ function decodeHtmlEntities(text) {
30869
31336
  }
30870
31337
 
30871
31338
  // src/security-ast-scan-tool.ts
30872
- import * as fs39 from "node:fs/promises";
30873
- import * as path45 from "node:path";
31339
+ import * as fs40 from "node:fs/promises";
31340
+ import * as path46 from "node:path";
30874
31341
  import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
30875
31342
  var SECRET_PATTERNS = [
30876
31343
  { name: "AWS Access Key", regex: /\b(AKIA[0-9A-Z]{16})\b/ },
@@ -31037,9 +31504,9 @@ var securityAstScanTool = {
31037
31504
  let targetFile = input.file ?? "inline-code.ts";
31038
31505
  let content = input.content;
31039
31506
  if (!content && input.file) {
31040
- const absPath = path45.isAbsolute(input.file) ? input.file : path45.resolve(projectRoot, input.file);
31041
- targetFile = path45.relative(projectRoot, absPath).replace(/\\/g, "/");
31042
- content = await fs39.readFile(absPath, "utf8");
31507
+ const absPath = path46.isAbsolute(input.file) ? input.file : path46.resolve(projectRoot, input.file);
31508
+ targetFile = path46.relative(projectRoot, absPath).replace(/\\/g, "/");
31509
+ content = await fs40.readFile(absPath, "utf8");
31043
31510
  }
31044
31511
  if (!content) {
31045
31512
  return {
@@ -31087,7 +31554,7 @@ var securityAstScanTool = {
31087
31554
  };
31088
31555
 
31089
31556
  // src/set-working-dir.ts
31090
- import * as fs40 from "node:fs/promises";
31557
+ import * as fs41 from "node:fs/promises";
31091
31558
  import { toErrorMessage as toErrorMessage18 } from "@wrongstack/core/utils";
31092
31559
  var setWorkingDirTool = {
31093
31560
  name: "set_working_dir",
@@ -31127,7 +31594,7 @@ var setWorkingDirTool = {
31127
31594
  }
31128
31595
  let isDirectory = false;
31129
31596
  try {
31130
- isDirectory = (await fs40.stat(resolved)).isDirectory();
31597
+ isDirectory = (await fs41.stat(resolved)).isDirectory();
31131
31598
  } catch {
31132
31599
  isDirectory = false;
31133
31600
  }
@@ -31662,7 +32129,7 @@ ${formatTaskList2(file.tasks)}` : file.tasks.length > 0 ? formatTaskList2(file.t
31662
32129
  init_spawn_stream();
31663
32130
  init_util();
31664
32131
  init_legacy_bridge();
31665
- import * as path46 from "node:path";
32132
+ import * as path47 from "node:path";
31666
32133
  var testTool = {
31667
32134
  name: "test",
31668
32135
  category: "Code Quality",
@@ -31769,7 +32236,7 @@ async function detectRunner(cwd) {
31769
32236
  const candidates = ["vitest.config.ts", "jest.config.js", ".mocharc.json"];
31770
32237
  for (const f of candidates) {
31771
32238
  try {
31772
- await stat22(path46.join(cwd, f));
32239
+ await stat22(path47.join(cwd, f));
31773
32240
  if (f.includes("vitest")) return "vitest";
31774
32241
  if (f.includes("jest")) return "jest";
31775
32242
  if (f.includes("mocha")) return "mocha";
@@ -32146,8 +32613,8 @@ var toolUseTool = {
32146
32613
 
32147
32614
  // src/tree.ts
32148
32615
  init_util();
32149
- import * as fs41 from "node:fs/promises";
32150
- import * as path47 from "node:path";
32616
+ import * as fs42 from "node:fs/promises";
32617
+ import * as path48 from "node:path";
32151
32618
  import { DEFAULT_WALK_IGNORE_DIRS as DEFAULT_WALK_IGNORE_DIRS4, expectDefined as expectDefined10 } from "@wrongstack/core/utils";
32152
32619
  var DEFAULT_IGNORE5 = /* @__PURE__ */ new Set([
32153
32620
  ...DEFAULT_WALK_IGNORE_DIRS4,
@@ -32310,7 +32777,7 @@ var treeTool = {
32310
32777
  async function walkDir(dir, depth, opts) {
32311
32778
  opts.signal.throwIfAborted();
32312
32779
  if (opts.retention.truncated) return;
32313
- const entries = await fs41.readdir(dir, { withFileTypes: true }).catch(() => []);
32780
+ const entries = await fs42.readdir(dir, { withFileTypes: true }).catch(() => []);
32314
32781
  const filtered = entries.filter((e) => {
32315
32782
  if (!opts.showHidden && e.name.startsWith(".")) return false;
32316
32783
  if (opts.exclude.has(e.name)) return false;
@@ -32352,7 +32819,7 @@ async function walkDir(dir, depth, opts) {
32352
32819
  opts.retention.outputBytes += lineBytes;
32353
32820
  if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {
32354
32821
  const childPrefix = opts.prefix + connector;
32355
- await walkDir(path47.join(dir, entry.name), depth + 1, {
32822
+ await walkDir(path48.join(dir, entry.name), depth + 1, {
32356
32823
  ...opts,
32357
32824
  prefix: childPrefix,
32358
32825
  isLast
@@ -32365,7 +32832,7 @@ async function walkDir(dir, depth, opts) {
32365
32832
  init_spawn_stream();
32366
32833
  init_util();
32367
32834
  init_legacy_bridge();
32368
- import * as path48 from "node:path";
32835
+ import * as path49 from "node:path";
32369
32836
  var typecheckTool = {
32370
32837
  name: "typecheck",
32371
32838
  category: "Code Quality",
@@ -32477,8 +32944,8 @@ async function findTsConfig(cwd) {
32477
32944
  const candidates = ["tsconfig.json", "tsconfig.base.json"];
32478
32945
  for (const f of candidates) {
32479
32946
  try {
32480
- const s = await stat22(path48.join(cwd, f));
32481
- if (s.isFile()) return path48.join(cwd, f);
32947
+ const s = await stat22(path49.join(cwd, f));
32948
+ if (s.isFile()) return path49.join(cwd, f);
32482
32949
  } catch {
32483
32950
  }
32484
32951
  }
@@ -32486,7 +32953,7 @@ async function findTsConfig(cwd) {
32486
32953
  }
32487
32954
 
32488
32955
  // src/write.ts
32489
- import * as fs42 from "node:fs/promises";
32956
+ import * as fs43 from "node:fs/promises";
32490
32957
  import { ToolValidationError as ToolValidationError11 } from "@wrongstack/core/types";
32491
32958
  import {
32492
32959
  atomicWrite as atomicWrite6,
@@ -32563,14 +33030,14 @@ async function prepareWrite(input, ctx) {
32563
33030
  let existed = false;
32564
33031
  let prev = "";
32565
33032
  try {
32566
- const stat22 = await fs42.stat(absPath);
33033
+ const stat22 = await fs43.stat(absPath);
32567
33034
  existed = stat22.isFile();
32568
33035
  if (existed) {
32569
33036
  if (!ctx.hasRead(absPath)) {
32570
- prev = await fs42.readFile(absPath, "utf8");
33037
+ prev = await fs43.readFile(absPath, "utf8");
32571
33038
  ctx.recordRead(absPath, stat22.mtimeMs, "write", sha256hex(prev));
32572
33039
  } else {
32573
- prev = await fs42.readFile(absPath, "utf8");
33040
+ prev = await fs43.readFile(absPath, "utf8");
32574
33041
  }
32575
33042
  }
32576
33043
  } catch (err) {
@@ -32591,7 +33058,7 @@ async function finishWrite(input, ctx, prepared, signal) {
32591
33058
  const rawDiff = prepared.existed ? unifiedDiff3(prepared.prev, content, { fromFile: input.path, toFile: input.path }) : `+++ ${input.path}
32592
33059
  + (new file, ${content.split("\n").length} lines)`;
32593
33060
  const { text: diff, truncated: diffTruncated } = truncateDiffPayload(rawDiff, MAX_DIFF_BYTES3);
32594
- const stat22 = await fs42.stat(prepared.absPath);
33061
+ const stat22 = await fs43.stat(prepared.absPath);
32595
33062
  ctx.recordRead(prepared.absPath, stat22.mtimeMs, "write", sha256hex(content));
32596
33063
  ctx.session.recordFileChange({
32597
33064
  path: prepared.absPath,
@@ -32669,6 +33136,7 @@ var TIER1_TOOLS = [
32669
33136
  var TIER2_TOOLS = [
32670
33137
  replaceTool,
32671
33138
  execTool,
33139
+ pwshTool,
32672
33140
  fetchTool,
32673
33141
  gitTool,
32674
33142
  treeTool,
@@ -32724,6 +33192,7 @@ var builtinTools = [
32724
33192
  grepTool,
32725
33193
  bashTool,
32726
33194
  execTool,
33195
+ pwshTool,
32727
33196
  fetchTool,
32728
33197
  searchTool,
32729
33198
  todoTool,
@@ -33140,7 +33609,7 @@ var builtinToolsPack = {
33140
33609
  };
33141
33610
 
33142
33611
  // src/process-guardian.ts
33143
- import * as os10 from "node:os";
33612
+ import * as os11 from "node:os";
33144
33613
  var ProcessGuardian = class {
33145
33614
  registry;
33146
33615
  config;
@@ -33276,7 +33745,7 @@ var ProcessGuardian = class {
33276
33745
  event: "process_guardian.started",
33277
33746
  instanceId: this.instanceId,
33278
33747
  mainPid: process.pid,
33279
- hostname: os10.hostname(),
33748
+ hostname: os11.hostname(),
33280
33749
  platform: process.platform
33281
33750
  })
33282
33751
  );
@@ -33410,8 +33879,8 @@ var ProcessGuardian = class {
33410
33879
  instanceId: this.instanceId,
33411
33880
  mainPid: process.pid,
33412
33881
  protectedCount: this.protectedProcesses.size,
33413
- platform: os10.platform(),
33414
- hostname: os10.hostname(),
33882
+ platform: os11.platform(),
33883
+ hostname: os11.hostname(),
33415
33884
  uptime: process.uptime()
33416
33885
  };
33417
33886
  }
@@ -33441,7 +33910,7 @@ function stopProcessGuardian() {
33441
33910
  init_process_registry();
33442
33911
 
33443
33912
  // src/ps-slash.ts
33444
- import * as os11 from "node:os";
33913
+ import * as os12 from "node:os";
33445
33914
  var IDLE_THRESHOLD_MS = 2 * 6e4;
33446
33915
  var STALE_THRESHOLD_MS2 = 5 * 6e4;
33447
33916
  function now() {
@@ -33482,7 +33951,7 @@ async function listInstances(options = {}) {
33482
33951
  const mainProc = processes.find((p) => p.spawnMode === "main");
33483
33952
  const firstProc = processes.at(0);
33484
33953
  const mainPid = mainProc?.pid ?? firstProc?.pid ?? 0;
33485
- const hostname_ = firstProc?.hostname ?? os11.hostname();
33954
+ const hostname_ = firstProc?.hostname ?? os12.hostname();
33486
33955
  const startedAt = Math.min(...processes.map((p) => p.startedAt));
33487
33956
  const lastActivity = Math.max(...processes.map((p) => p.lastHeartbeat));
33488
33957
  const age = timestamp - lastActivity;
@@ -33570,7 +34039,7 @@ async function getGlobalProcessStatus() {
33570
34039
  mainPid: process.pid,
33571
34040
  protectedCount: 0,
33572
34041
  platform: process.platform,
33573
- hostname: os11.hostname(),
34042
+ hostname: os12.hostname(),
33574
34043
  uptime: 0
33575
34044
  },
33576
34045
  allInstances: instances.map((inst) => ({
@@ -33764,8 +34233,8 @@ function createGlobalPsSlashCommand() {
33764
34233
  }
33765
34234
 
33766
34235
  // src/skill.ts
33767
- import * as fs43 from "node:fs/promises";
33768
- import * as path49 from "node:path";
34236
+ import * as fs44 from "node:fs/promises";
34237
+ import * as path50 from "node:path";
33769
34238
  import {
33770
34239
  missingRequiredRuntimeTools,
33771
34240
  missingRuntimeCapabilities,
@@ -33829,7 +34298,7 @@ function makeSkillTool(skillLoader) {
33829
34298
  field: "name"
33830
34299
  });
33831
34300
  }
33832
- const dir = path49.dirname(manifest.path);
34301
+ const dir = path50.dirname(manifest.path);
33833
34302
  let loadedResource;
33834
34303
  if (input.resource?.trim()) {
33835
34304
  loadedResource = await loadResource(dir, input.resource.trim());
@@ -33888,15 +34357,15 @@ ${listing}${warningLine}`;
33888
34357
  }
33889
34358
  async function loadResource(skillDir, rel) {
33890
34359
  const norm = rel.replace(/\\/g, "/");
33891
- if (path49.isAbsolute(rel) || norm.split("/").some((seg) => seg === "..")) {
34360
+ if (path50.isAbsolute(rel) || norm.split("/").some((seg) => seg === "..")) {
33892
34361
  throw new ToolValidationError13({
33893
34362
  message: `skill: invalid resource path "${rel}"`,
33894
34363
  field: "resource"
33895
34364
  });
33896
34365
  }
33897
- const absPath = path49.resolve(skillDir, rel);
33898
- const root = path49.resolve(skillDir);
33899
- if (absPath !== root && !absPath.startsWith(root + path49.sep)) {
34366
+ const absPath = path50.resolve(skillDir, rel);
34367
+ const root = path50.resolve(skillDir);
34368
+ if (absPath !== root && !absPath.startsWith(root + path50.sep)) {
33900
34369
  throw new ToolValidationError13({
33901
34370
  message: `skill: resource "${rel}" escapes the skill directory`,
33902
34371
  field: "resource"
@@ -33905,15 +34374,15 @@ async function loadResource(skillDir, rel) {
33905
34374
  let realPath;
33906
34375
  let realRoot;
33907
34376
  try {
33908
- realRoot = await fs43.realpath(root);
33909
- realPath = await fs43.realpath(absPath);
34377
+ realRoot = await fs44.realpath(root);
34378
+ realPath = await fs44.realpath(absPath);
33910
34379
  } catch {
33911
34380
  throw new ToolValidationError13({
33912
34381
  message: `skill: resource "${rel}" not readable`,
33913
34382
  field: "resource"
33914
34383
  });
33915
34384
  }
33916
- if (realPath !== realRoot && !realPath.startsWith(realRoot + path49.sep)) {
34385
+ if (realPath !== realRoot && !realPath.startsWith(realRoot + path50.sep)) {
33917
34386
  throw new ToolValidationError13({
33918
34387
  message: `skill: resource "${rel}" resolves outside the skill directory`,
33919
34388
  field: "resource"
@@ -33921,7 +34390,7 @@ async function loadResource(skillDir, rel) {
33921
34390
  }
33922
34391
  let buf;
33923
34392
  try {
33924
- buf = await fs43.readFile(realPath);
34393
+ buf = await fs44.readFile(realPath);
33925
34394
  } catch {
33926
34395
  throw new ToolValidationError13({
33927
34396
  message: `skill: resource "${rel}" not readable`,
@@ -33950,17 +34419,17 @@ async function walk(root, dir, out) {
33950
34419
  if (out.length >= MAX_LISTED_RESOURCES) return;
33951
34420
  let entries;
33952
34421
  try {
33953
- entries = await fs43.readdir(dir, { withFileTypes: true });
34422
+ entries = await fs44.readdir(dir, { withFileTypes: true });
33954
34423
  } catch {
33955
34424
  return;
33956
34425
  }
33957
34426
  for (const e of entries) {
33958
34427
  if (out.length >= MAX_LISTED_RESOURCES) return;
33959
- const fullPath = path49.join(dir, e.name);
34428
+ const fullPath = path50.join(dir, e.name);
33960
34429
  let isDir = e.isDirectory();
33961
34430
  if (e.isSymbolicLink()) {
33962
34431
  try {
33963
- isDir = (await fs43.stat(fullPath)).isDirectory();
34432
+ isDir = (await fs44.stat(fullPath)).isDirectory();
33964
34433
  } catch {
33965
34434
  continue;
33966
34435
  }
@@ -33971,8 +34440,8 @@ async function walk(root, dir, out) {
33971
34440
  } else if (e.isFile()) {
33972
34441
  if (e.name === "SKILL.md" || e.name === "SKILL.save.md") continue;
33973
34442
  try {
33974
- const stat22 = await fs43.stat(fullPath);
33975
- const rel = path49.relative(root, fullPath).split(path49.sep).join("/");
34443
+ const stat22 = await fs44.stat(fullPath);
34444
+ const rel = path50.relative(root, fullPath).split(path50.sep).join("/");
33976
34445
  out.push({ path: rel, bytes: stat22.size });
33977
34446
  } catch {
33978
34447
  }
@@ -33998,6 +34467,8 @@ var TOOL_ICON_MAP = {
33998
34467
  // Shell/command execution
33999
34468
  bash: "terminal",
34000
34469
  exec: "terminal",
34470
+ pwsh: "terminal",
34471
+ powershell: "terminal",
34001
34472
  run: "terminal",
34002
34473
  command: "terminal",
34003
34474
  shell: "terminal",
@@ -34205,6 +34676,7 @@ export {
34205
34676
  OFF_ONLY_TOOLS,
34206
34677
  OPTIONAL_TOOLS,
34207
34678
  PRIMARY_LANGUAGE_PROFILES,
34679
+ PWSH_TOOL_DESCRIPTION,
34208
34680
  SESSION_KANBAN_COLUMNS,
34209
34681
  TIER1_TOOLS,
34210
34682
  TIER2_TOOLS,
@@ -34332,6 +34804,7 @@ export {
34332
34804
  projectSessionPlanToKanban,
34333
34805
  projectSessionTasksToKanban,
34334
34806
  projectSessionTodosToKanban,
34807
+ pwshTool,
34335
34808
  readTool,
34336
34809
  rebindSessionKanbanTask,
34337
34810
  recordKanbanVerificationEvidence,