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