@cortexkit/aft-pi 0.53.0 → 0.54.0

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
@@ -7711,9 +7711,9 @@ var require_stringify = __commonJS(function(exports, module) {
7711
7711
  value
7712
7712
  } = comment;
7713
7713
  const line_breaks_before = blank_lines > 0 ? blank_lines + (inline ? 0 : 1) : null;
7714
- const delimiter2 = line_breaks_before > 0 ? repeat_line_breaks(line_breaks_before, deeper_gap) : inline ? SPACE : i === 0 && symbol_tag === PREFIX_BEFORE_ALL && deeper_gap === EMPTY ? EMPTY : LF + deeper_gap;
7714
+ const delimiter3 = line_breaks_before > 0 ? repeat_line_breaks(line_breaks_before, deeper_gap) : inline ? SPACE : i === 0 && symbol_tag === PREFIX_BEFORE_ALL && deeper_gap === EMPTY ? EMPTY : LF + deeper_gap;
7715
7715
  const is_line_comment = type === "LineComment";
7716
- str += delimiter2 + comment_stringify(value, is_line_comment);
7716
+ str += delimiter3 + comment_stringify(value, is_line_comment);
7717
7717
  blank_lines = 0;
7718
7718
  last_comment = comment;
7719
7719
  });
@@ -7730,10 +7730,10 @@ var require_stringify = __commonJS(function(exports, module) {
7730
7730
  replacer = null;
7731
7731
  indent = EMPTY;
7732
7732
  };
7733
- var join12 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two)), gap) : EMPTY;
7733
+ var join13 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two)), gap) : EMPTY;
7734
7734
  var join_content = (inside, value, gap) => {
7735
7735
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
7736
- return join12(comment, inside, gap);
7736
+ return join13(comment, inside, gap);
7737
7737
  };
7738
7738
  var stringify_string = (holder, key, value) => {
7739
7739
  const raw = get_raw_string_literal(holder, key);
@@ -7755,13 +7755,13 @@ var require_stringify = __commonJS(function(exports, module) {
7755
7755
  if (i !== 0) {
7756
7756
  inside += COMMA;
7757
7757
  }
7758
- const before = join12(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
7758
+ const before = join13(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
7759
7759
  inside += before || LF + deeper_gap;
7760
7760
  inside += stringify(i, value, deeper_gap) || STR_NULL;
7761
7761
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
7762
7762
  after_comma = process_comments(value, AFTER(i), deeper_gap);
7763
7763
  }
7764
- inside += join12(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7764
+ inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7765
7765
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
7766
7766
  };
7767
7767
  var object_stringify = (value, gap) => {
@@ -7782,13 +7782,13 @@ var require_stringify = __commonJS(function(exports, module) {
7782
7782
  inside += COMMA;
7783
7783
  }
7784
7784
  first = false;
7785
- const before = join12(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
7785
+ const before = join13(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
7786
7786
  inside += before || LF + deeper_gap;
7787
7787
  inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
7788
7788
  after_comma = process_comments(value, AFTER(key), deeper_gap);
7789
7789
  };
7790
7790
  keys.forEach(iteratee);
7791
- inside += join12(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7791
+ inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7792
7792
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
7793
7793
  };
7794
7794
  function stringify(key, holder, gap) {
@@ -8329,10 +8329,68 @@ function skipSpaces(input, start) {
8329
8329
  }
8330
8330
  // ../aft-bridge/dist/bash-host-fallback.js
8331
8331
  import { spawn } from "node:child_process";
8332
+ import { existsSync } from "node:fs";
8333
+ import { delimiter, join as join3 } from "node:path";
8334
+
8335
+ // ../aft-bridge/dist/storage-paths.js
8336
+ import { homedir as homedir2 } from "node:os";
8337
+ import { join as join2, resolve as resolve2 } from "node:path";
8338
+ function homeDir() {
8339
+ if (process.platform === "win32")
8340
+ return process.env.USERPROFILE || process.env.HOME || homedir2();
8341
+ return process.env.HOME || homedir2();
8342
+ }
8343
+ function dataHome() {
8344
+ const xdg = process.env.XDG_DATA_HOME;
8345
+ if (xdg)
8346
+ return xdg;
8347
+ if (process.platform === "win32") {
8348
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join2(homeDir(), "AppData", "Local");
8349
+ }
8350
+ return join2(homeDir(), ".local", "share");
8351
+ }
8352
+ function resolveStoragePath(raw) {
8353
+ let expanded = raw;
8354
+ if (raw === "~") {
8355
+ expanded = homeDir();
8356
+ } else if (raw.startsWith("~/") || raw.startsWith("~\\")) {
8357
+ expanded = join2(homeDir(), raw.slice(2));
8358
+ }
8359
+ return resolve2(expanded);
8360
+ }
8361
+ function resolveCortexKitStorageRoot() {
8362
+ const override = process.env.AFT_STORAGE_DIR;
8363
+ if (override)
8364
+ return resolveStoragePath(override);
8365
+ return resolveStoragePath(join2(dataHome(), "cortexkit", "aft"));
8366
+ }
8367
+ function resolveAftStorageRoot(configuredRoot) {
8368
+ if (process.env.AFT_STORAGE_DIR)
8369
+ return resolveCortexKitStorageRoot();
8370
+ if (configuredRoot)
8371
+ return configuredRoot;
8372
+ return resolveCortexKitStorageRoot();
8373
+ }
8374
+ function resolveAftLogPath(filename, configuredRoot) {
8375
+ return join2(resolveAftStorageRoot(configuredRoot), "logs", filename);
8376
+ }
8377
+
8378
+ // ../aft-bridge/dist/bash-host-fallback.js
8332
8379
  var BASH_HOST_FALLBACK_BANNER = "[AFT host fallback - module transport down; no rewrites/compression/background]";
8333
8380
  var BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES = 100 * 1024;
8334
8381
  var BASH_HOST_FALLBACK_MAX_TIMEOUT_MS = 10 * 60 * 1000;
8335
8382
  var BASH_HOST_FALLBACK_REFUSAL = "AFT transport is down; only foreground execution is available in host fallback";
8383
+ function hostFallbackPathWithShims(env) {
8384
+ const storageRoot = env.AFT_STORAGE_DIR ? resolveStoragePath(env.AFT_STORAGE_DIR) : resolveCortexKitStorageRoot();
8385
+ const shimsDir = join3(storageRoot, "shims");
8386
+ if (!existsSync(join3(shimsDir, "gh")))
8387
+ return env.PATH;
8388
+ const inherited = env.PATH ?? "";
8389
+ const entries = inherited.split(delimiter).filter((entry) => entry.length > 0);
8390
+ if (entries[0] === shimsDir)
8391
+ return inherited;
8392
+ return [shimsDir, ...entries.filter((entry) => entry !== shimsDir)].join(delimiter);
8393
+ }
8336
8394
  function bashHostFallbackAskPattern(command, cwd) {
8337
8395
  return `AFT UNAVAILABLE - host fallback execution:
8338
8396
 
@@ -8365,11 +8423,17 @@ async function runBashHostFallback(options) {
8365
8423
  if (options.signal?.aborted) {
8366
8424
  throw new DOMException("The host fallback command was aborted", "AbortError");
8367
8425
  }
8368
- return await new Promise((resolve2, reject) => {
8426
+ return await new Promise((resolve3, reject) => {
8369
8427
  const child = spawn(options.command, {
8370
8428
  cwd: options.projectRoot,
8371
8429
  shell: true,
8372
- env: { ...process.env, ...options.env },
8430
+ env: (() => {
8431
+ const merged = { ...process.env, ...options.env };
8432
+ const path2 = hostFallbackPathWithShims(merged);
8433
+ if (path2 !== undefined)
8434
+ merged.PATH = path2;
8435
+ return merged;
8436
+ })(),
8373
8437
  stdio: ["ignore", "pipe", "pipe"],
8374
8438
  detached: process.platform !== "win32",
8375
8439
  windowsHide: true
@@ -8432,7 +8496,7 @@ async function runBashHostFallback(options) {
8432
8496
  return;
8433
8497
  }
8434
8498
  const exitCode = timedOut ? 124 : code ?? 1;
8435
- resolve2({
8499
+ resolve3({
8436
8500
  success: true,
8437
8501
  output: renderOutput(Buffer.concat(chunks), exitCode),
8438
8502
  exit_code: exitCode,
@@ -8452,8 +8516,8 @@ function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
8452
8516
  import { spawn as spawn2 } from "node:child_process";
8453
8517
  import { createHash } from "node:crypto";
8454
8518
  import { readFileSync } from "node:fs";
8455
- import { homedir as homedir2 } from "node:os";
8456
- import { join as join2 } from "node:path";
8519
+ import { homedir as homedir3 } from "node:os";
8520
+ import { join as join4 } from "node:path";
8457
8521
  import { StringDecoder } from "node:string_decoder";
8458
8522
 
8459
8523
  // ../aft-bridge/dist/command-timeouts.js
@@ -8953,7 +9017,7 @@ class BinaryBridge {
8953
9017
  const keepBridgeOnTimeout = passive || options?.keepBridgeOnTimeout === true;
8954
9018
  let requestSentAt = Date.now();
8955
9019
  const child = this.process;
8956
- const response = await new Promise((resolve2, reject) => {
9020
+ const response = await new Promise((resolve3, reject) => {
8957
9021
  const timer = setTimeout(() => {
8958
9022
  const entry = this.pending.get(id);
8959
9023
  if (!entry)
@@ -8988,7 +9052,7 @@ class BinaryBridge {
8988
9052
  entry.reject(new Error(`${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
8989
9053
  this.handleTimeout(requestSessionId);
8990
9054
  }, effectiveTimeoutMs);
8991
- this.pending.set(id, { resolve: resolve2, reject, timer, onProgress: options?.onProgress, command });
9055
+ this.pending.set(id, { resolve: resolve3, reject, timer, onProgress: options?.onProgress, command });
8992
9056
  if (!child?.stdin?.writable) {
8993
9057
  this.pending.delete(id);
8994
9058
  clearTimeout(timer);
@@ -9106,15 +9170,15 @@ class BinaryBridge {
9106
9170
  if (this.process) {
9107
9171
  const proc = this.process;
9108
9172
  this.process = null;
9109
- return new Promise((resolve2) => {
9173
+ return new Promise((resolve3) => {
9110
9174
  const forceKillTimer = setTimeout(() => {
9111
9175
  proc.kill("SIGKILL");
9112
- resolve2();
9176
+ resolve3();
9113
9177
  }, 5000);
9114
9178
  proc.once("exit", () => {
9115
9179
  clearTimeout(forceKillTimer);
9116
9180
  this.logVia("Process exited during shutdown");
9117
- resolve2();
9181
+ resolve3();
9118
9182
  });
9119
9183
  proc.kill("SIGTERM");
9120
9184
  });
@@ -9162,15 +9226,15 @@ class BinaryBridge {
9162
9226
  return;
9163
9227
  const proc = this.process;
9164
9228
  this.process = null;
9165
- await new Promise((resolve2) => {
9229
+ await new Promise((resolve3) => {
9166
9230
  const forceKillTimer = setTimeout(() => {
9167
9231
  proc.kill("SIGKILL");
9168
- resolve2();
9232
+ resolve3();
9169
9233
  }, 5000);
9170
9234
  proc.once("exit", () => {
9171
9235
  clearTimeout(forceKillTimer);
9172
9236
  this.logVia("Process exited during coordinated binary replacement");
9173
- resolve2();
9237
+ resolve3();
9174
9238
  });
9175
9239
  proc.kill("SIGTERM");
9176
9240
  });
@@ -9200,7 +9264,7 @@ class BinaryBridge {
9200
9264
  })();
9201
9265
  const useFastembedBackend = semanticBackend === undefined || semanticBackend === "fastembed" || semanticBackend === "";
9202
9266
  const ortDir = typeof this.configOverrides._ort_dylib_dir === "string" && useFastembedBackend ? this.configOverrides._ort_dylib_dir : null;
9203
- const ortLibraryPath = ortDir == null ? null : join2(ortDir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
9267
+ const ortLibraryPath = ortDir == null ? null : join4(ortDir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
9204
9268
  const envPath = process.platform === "win32" && ortDir ? `${ortDir};${process.env.PATH ?? ""}` : process.env.PATH;
9205
9269
  const env = {
9206
9270
  ...process.env,
@@ -9208,7 +9272,7 @@ class BinaryBridge {
9208
9272
  };
9209
9273
  this.logVia(`bridge.spawnProcess: useFastembedBackend=${useFastembedBackend}, ` + `parentORT=${process.env.ORT_DYLIB_PATH ?? "(unset)"}, ` + `ortLibraryPath=${ortLibraryPath ?? "(none)"}`);
9210
9274
  if (useFastembedBackend) {
9211
- env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join2(this.configOverrides.storage_dir, "semantic", "models") : join2(homedir2() || "", ".cache", "fastembed"));
9275
+ env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join4(this.configOverrides.storage_dir, "semantic", "models") : join4(homedir3() || "", ".cache", "fastembed"));
9212
9276
  if (process.env.ORT_DYLIB_PATH) {
9213
9277
  this.logVia(`ORT_DYLIB_PATH inherited from parent env: ${process.env.ORT_DYLIB_PATH}`);
9214
9278
  } else if (ortLibraryPath) {
@@ -9537,32 +9601,32 @@ class BinaryBridge {
9537
9601
  }
9538
9602
  }
9539
9603
  // ../aft-bridge/dist/cache-paths.js
9540
- import { homedir as homedir3 } from "node:os";
9541
- import { join as join3 } from "node:path";
9542
- function homeDir(env) {
9543
- return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir3();
9604
+ import { homedir as homedir4 } from "node:os";
9605
+ import { join as join5 } from "node:path";
9606
+ function homeDir2(env) {
9607
+ return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir4();
9544
9608
  }
9545
9609
  function getAftCacheRoot(env = process.env) {
9546
9610
  if (env.AFT_CACHE_DIR)
9547
9611
  return env.AFT_CACHE_DIR;
9548
9612
  if (process.platform === "win32") {
9549
- const base2 = env.LOCALAPPDATA || env.APPDATA || join3(homeDir(env), "AppData", "Local");
9550
- return join3(base2, "aft");
9613
+ const base2 = env.LOCALAPPDATA || env.APPDATA || join5(homeDir2(env), "AppData", "Local");
9614
+ return join5(base2, "aft");
9551
9615
  }
9552
- const base = env.XDG_CACHE_HOME || join3(homeDir(env), ".cache");
9553
- return join3(base, "aft");
9616
+ const base = env.XDG_CACHE_HOME || join5(homeDir2(env), ".cache");
9617
+ return join5(base, "aft");
9554
9618
  }
9555
9619
  function getAftBinaryCacheDir(env = process.env) {
9556
- return join3(getAftCacheRoot(env), "bin");
9620
+ return join5(getAftCacheRoot(env), "bin");
9557
9621
  }
9558
9622
  function getAftLspPackagesDir(env = process.env) {
9559
- return join3(getAftCacheRoot(env), "lsp-packages");
9623
+ return join5(getAftCacheRoot(env), "lsp-packages");
9560
9624
  }
9561
9625
  function getAftLspBinariesDir(env = process.env) {
9562
- return join3(getAftCacheRoot(env), "lsp-binaries");
9626
+ return join5(getAftCacheRoot(env), "lsp-binaries");
9563
9627
  }
9564
9628
  // ../aft-bridge/dist/callgraph-format.js
9565
- import { homedir as homedir4 } from "node:os";
9629
+ import { homedir as homedir5 } from "node:os";
9566
9630
  var UNRESOLVED_SUMMARY_NAME_LIMIT = 10;
9567
9631
  var PLAIN_CALLGRAPH_THEME = {
9568
9632
  fg: (_role, text) => text
@@ -9585,7 +9649,7 @@ function asBoolean(value) {
9585
9649
  return typeof value === "boolean" ? value : undefined;
9586
9650
  }
9587
9651
  function shortenPath(path2) {
9588
- const home = homedir4();
9652
+ const home = homedir5();
9589
9653
  if (path2.startsWith(home))
9590
9654
  return `~${path2.slice(home.length)}`;
9591
9655
  return path2;
@@ -9932,26 +9996,26 @@ function stripHarnessSpecificConfigKeys(value, keys) {
9932
9996
  return stripped;
9933
9997
  }
9934
9998
  // ../aft-bridge/dist/config-tiers.js
9935
- import { existsSync, readFileSync as readFileSync2 } from "node:fs";
9936
- import { resolve as resolve2 } from "node:path";
9999
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
10000
+ import { resolve as resolve3 } from "node:path";
9937
10001
  function readConfigTiers(opts) {
9938
10002
  const tiers = [];
9939
10003
  try {
9940
- if (existsSync(opts.userConfigPath)) {
10004
+ if (existsSync2(opts.userConfigPath)) {
9941
10005
  const doc = readFileSync2(opts.userConfigPath, "utf-8");
9942
10006
  tiers.push({
9943
10007
  tier: "user",
9944
- source: resolve2(opts.userConfigPath),
10008
+ source: resolve3(opts.userConfigPath),
9945
10009
  doc
9946
10010
  });
9947
10011
  }
9948
10012
  } catch {}
9949
10013
  try {
9950
- if (existsSync(opts.projectConfigPath)) {
10014
+ if (existsSync2(opts.projectConfigPath)) {
9951
10015
  const doc = readFileSync2(opts.projectConfigPath, "utf-8");
9952
10016
  tiers.push({
9953
10017
  tier: "project",
9954
- source: resolve2(opts.projectConfigPath),
10018
+ source: resolve3(opts.projectConfigPath),
9955
10019
  doc
9956
10020
  });
9957
10021
  }
@@ -9967,9 +10031,9 @@ function formatDroppedKeyWarnings(dropped) {
9967
10031
  // ../aft-bridge/dist/downloader.js
9968
10032
  import { spawnSync } from "node:child_process";
9969
10033
  import { createHash as createHash2, randomUUID } from "node:crypto";
9970
- import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync2, mkdirSync, openSync, readdirSync, readFileSync as readFileSync3, renameSync, rmSync, statSync as statSync2, unlinkSync, writeSync } from "node:fs";
10034
+ import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync, openSync, readdirSync, readFileSync as readFileSync3, renameSync, rmSync, statSync as statSync2, unlinkSync, writeSync } from "node:fs";
9971
10035
  import { hostname } from "node:os";
9972
- import { join as join4 } from "node:path";
10036
+ import { join as join6 } from "node:path";
9973
10037
  import { Readable } from "node:stream";
9974
10038
  import { pipeline } from "node:stream/promises";
9975
10039
 
@@ -10029,8 +10093,8 @@ function getBinaryName() {
10029
10093
  function getCachedBinaryPath(version) {
10030
10094
  if (!version)
10031
10095
  return null;
10032
- const binaryPath = join4(getAftBinaryCacheDir(), version, getBinaryName());
10033
- return existsSync2(binaryPath) ? binaryPath : null;
10096
+ const binaryPath = join6(getAftBinaryCacheDir(), version, getBinaryName());
10097
+ return existsSync3(binaryPath) ? binaryPath : null;
10034
10098
  }
10035
10099
  async function downloadBinary(version) {
10036
10100
  const archMap = PLATFORM_ARCH_MAP[process.platform] ?? {};
@@ -10046,16 +10110,16 @@ async function downloadBinary(version) {
10046
10110
  return null;
10047
10111
  }
10048
10112
  const tag = rawTag.startsWith("v") ? rawTag : `v${rawTag}`;
10049
- const versionedCacheDir = join4(getAftBinaryCacheDir(), tag);
10113
+ const versionedCacheDir = join6(getAftBinaryCacheDir(), tag);
10050
10114
  const binaryName = getBinaryName();
10051
- const binaryPath = join4(versionedCacheDir, binaryName);
10052
- if (existsSync2(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
10115
+ const binaryPath = join6(versionedCacheDir, binaryName);
10116
+ if (existsSync3(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
10053
10117
  return binaryPath;
10054
10118
  }
10055
10119
  const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
10056
10120
  const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
10057
10121
  log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
10058
- const lockPath = join4(versionedCacheDir, ".download.lock");
10122
+ const lockPath = join6(versionedCacheDir, ".download.lock");
10059
10123
  let releaseLock = null;
10060
10124
  let binaryController = null;
10061
10125
  let checksumController = null;
@@ -10064,7 +10128,7 @@ async function downloadBinary(version) {
10064
10128
  const tmpPath = `${binaryPath}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
10065
10129
  const cleanUpPartialDownload = () => {
10066
10130
  try {
10067
- if (existsSync2(tmpPath))
10131
+ if (existsSync3(tmpPath))
10068
10132
  unlinkSync(tmpPath);
10069
10133
  } catch {}
10070
10134
  };
@@ -10088,12 +10152,12 @@ async function downloadBinary(version) {
10088
10152
  process.once("SIGINT", handleSigint);
10089
10153
  process.once("exit", handleExit);
10090
10154
  try {
10091
- if (!existsSync2(versionedCacheDir)) {
10155
+ if (!existsSync3(versionedCacheDir)) {
10092
10156
  mkdirSync(versionedCacheDir, { recursive: true });
10093
10157
  }
10094
10158
  releaseLock = await acquireDownloadLock(lockPath);
10095
10159
  sweepStaleDownloadTemps(versionedCacheDir, binaryName);
10096
- if (existsSync2(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
10160
+ if (existsSync3(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
10097
10161
  return binaryPath;
10098
10162
  }
10099
10163
  binaryController = new AbortController;
@@ -10158,7 +10222,7 @@ async function downloadBinary(version) {
10158
10222
  renameSync(tmpPath, binaryPath);
10159
10223
  }
10160
10224
  try {
10161
- if (existsSync2(tmpPath))
10225
+ if (existsSync3(tmpPath))
10162
10226
  unlinkSync(tmpPath);
10163
10227
  } catch {
10164
10228
  warn(`Could not clean up temporary download file ${tmpPath} — it can be removed manually.`);
@@ -10274,7 +10338,7 @@ function sweepStaleDownloadTemps(versionedCacheDir, binaryName) {
10274
10338
  if (!entry.isFile() || !entry.name.startsWith(tempPrefix) || !entry.name.endsWith(".tmp")) {
10275
10339
  continue;
10276
10340
  }
10277
- const tempPath = join4(versionedCacheDir, entry.name);
10341
+ const tempPath = join6(versionedCacheDir, entry.name);
10278
10342
  const ageMs = Date.now() - statSync2(tempPath).mtimeMs;
10279
10343
  if (Math.abs(ageMs) > DOWNLOAD_LOCK_STALE_MS)
10280
10344
  unlinkSync(tempPath);
@@ -10323,7 +10387,7 @@ async function acquireDownloadLock(lockPath, timing = {}) {
10323
10387
  if (Date.now() - startedAt > timeoutMs) {
10324
10388
  throw new Error(`Timed out waiting for download lock: ${lockPath}`);
10325
10389
  }
10326
- await new Promise((resolve3) => setTimeout(resolve3, pollIntervalMs));
10390
+ await new Promise((resolve4) => setTimeout(resolve4, pollIntervalMs));
10327
10391
  }
10328
10392
  }
10329
10393
  }
@@ -10361,51 +10425,6 @@ async function fetchLatestTag() {
10361
10425
  // ../aft-bridge/dist/durable-log.js
10362
10426
  import { appendFile, mkdir, rename, rm, stat } from "node:fs/promises";
10363
10427
  import { dirname } from "node:path";
10364
-
10365
- // ../aft-bridge/dist/storage-paths.js
10366
- import { homedir as homedir5 } from "node:os";
10367
- import { join as join5, resolve as resolve3 } from "node:path";
10368
- function homeDir2() {
10369
- if (process.platform === "win32")
10370
- return process.env.USERPROFILE || process.env.HOME || homedir5();
10371
- return process.env.HOME || homedir5();
10372
- }
10373
- function dataHome() {
10374
- const xdg = process.env.XDG_DATA_HOME;
10375
- if (xdg)
10376
- return xdg;
10377
- if (process.platform === "win32") {
10378
- return process.env.LOCALAPPDATA || process.env.APPDATA || join5(homeDir2(), "AppData", "Local");
10379
- }
10380
- return join5(homeDir2(), ".local", "share");
10381
- }
10382
- function resolveStoragePath(raw) {
10383
- let expanded = raw;
10384
- if (raw === "~") {
10385
- expanded = homeDir2();
10386
- } else if (raw.startsWith("~/") || raw.startsWith("~\\")) {
10387
- expanded = join5(homeDir2(), raw.slice(2));
10388
- }
10389
- return resolve3(expanded);
10390
- }
10391
- function resolveCortexKitStorageRoot() {
10392
- const override = process.env.AFT_STORAGE_DIR;
10393
- if (override)
10394
- return resolveStoragePath(override);
10395
- return resolveStoragePath(join5(dataHome(), "cortexkit", "aft"));
10396
- }
10397
- function resolveAftStorageRoot(configuredRoot) {
10398
- if (process.env.AFT_STORAGE_DIR)
10399
- return resolveCortexKitStorageRoot();
10400
- if (configuredRoot)
10401
- return configuredRoot;
10402
- return resolveCortexKitStorageRoot();
10403
- }
10404
- function resolveAftLogPath(filename, configuredRoot) {
10405
- return join5(resolveAftStorageRoot(configuredRoot), "logs", filename);
10406
- }
10407
-
10408
- // ../aft-bridge/dist/durable-log.js
10409
10428
  var DEFAULT_LOG_BYTES = 32 * 1024 * 1024;
10410
10429
  var DEFAULT_LOG_GENERATIONS = 1;
10411
10430
  class RotatingLogSink {
@@ -12040,7 +12059,7 @@ function pendingKey(handle, corr) {
12040
12059
  return handle ? `${handle.channel}:${handle.epoch}:${corr}` : `0:0:${corr}`;
12041
12060
  }
12042
12061
  // ../aft-bridge/dist/subc-transport.js
12043
- import { existsSync as existsSync3, statSync as statSync3 } from "node:fs";
12062
+ import { existsSync as existsSync4, statSync as statSync3 } from "node:fs";
12044
12063
 
12045
12064
  // ../aft-bridge/dist/lifecycle-registry.js
12046
12065
  import { lstat } from "node:fs/promises";
@@ -13049,7 +13068,7 @@ class SubcTransportPool {
13049
13068
  this.dormantRoots.delete(root);
13050
13069
  return true;
13051
13070
  }
13052
- const reclaimedMarkerPresent = existsSync3(`${root}.reclaimed`);
13071
+ const reclaimedMarkerPresent = existsSync4(`${root}.reclaimed`);
13053
13072
  if (reclaimedMarkerPresent) {
13054
13073
  this.markRootDormant(root);
13055
13074
  return false;
@@ -13881,14 +13900,14 @@ function stripJsoncSymbols(value) {
13881
13900
  }
13882
13901
  // ../aft-bridge/dist/migration.js
13883
13902
  import { spawnSync as spawnSync2 } from "node:child_process";
13884
- import { closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
13903
+ import { closeSync as closeSync3, existsSync as existsSync7, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
13885
13904
  import { homedir as homedir8, tmpdir } from "node:os";
13886
- import { basename, dirname as dirname3, join as join8, resolve as resolve6 } from "node:path";
13905
+ import { basename, dirname as dirname3, join as join9, resolve as resolve6 } from "node:path";
13887
13906
 
13888
13907
  // ../aft-bridge/dist/paths.js
13889
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync } from "node:fs";
13908
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync } from "node:fs";
13890
13909
  import { homedir as homedir6 } from "node:os";
13891
- import { dirname as dirname2, isAbsolute as isAbsolute2, join as join6, resolve as resolve5 } from "node:path";
13910
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join7, resolve as resolve5 } from "node:path";
13892
13911
  function homeDir3() {
13893
13912
  if (process.platform === "win32")
13894
13913
  return process.env.USERPROFILE || process.env.HOME || homedir6();
@@ -13898,16 +13917,16 @@ function configHome() {
13898
13917
  const xdg = process.env.XDG_CONFIG_HOME;
13899
13918
  if (xdg && isAbsolute2(xdg))
13900
13919
  return xdg;
13901
- return join6(homeDir3(), ".config");
13920
+ return join7(homeDir3(), ".config");
13902
13921
  }
13903
13922
  function legacyOpenCodeConfigDir() {
13904
13923
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
13905
13924
  if (envDir)
13906
13925
  return resolve5(envDir);
13907
- return join6(configHome(), "opencode");
13926
+ return join7(configHome(), "opencode");
13908
13927
  }
13909
13928
  function legacyPiAgentDir() {
13910
- return join6(homeDir3(), ".pi", "agent");
13929
+ return join7(homeDir3(), ".pi", "agent");
13911
13930
  }
13912
13931
  function legacySources(basePath, label, harness) {
13913
13932
  return [
@@ -13916,10 +13935,10 @@ function legacySources(basePath, label, harness) {
13916
13935
  ];
13917
13936
  }
13918
13937
  function resolveCortexKitUserConfigPath() {
13919
- return join6(configHome(), "cortexkit", "aft.jsonc");
13938
+ return join7(configHome(), "cortexkit", "aft.jsonc");
13920
13939
  }
13921
13940
  function resolveCortexKitProjectConfigPath(projectDirectory) {
13922
- return join6(projectDirectory, ".cortexkit", "aft.jsonc");
13941
+ return join7(projectDirectory, ".cortexkit", "aft.jsonc");
13923
13942
  }
13924
13943
  function resolveCortexKitConfigPaths(projectDirectory) {
13925
13944
  return {
@@ -13930,22 +13949,22 @@ function resolveCortexKitConfigPaths(projectDirectory) {
13930
13949
  function resolveLegacyAftConfigSources(projectDirectory) {
13931
13950
  return {
13932
13951
  user: [
13933
- ...legacySources(join6(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
13934
- ...legacySources(join6(legacyPiAgentDir(), "aft"), "Pi user", "pi")
13952
+ ...legacySources(join7(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
13953
+ ...legacySources(join7(legacyPiAgentDir(), "aft"), "Pi user", "pi")
13935
13954
  ],
13936
13955
  project: [
13937
- ...legacySources(join6(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
13938
- ...legacySources(join6(projectDirectory, ".pi", "aft"), "Pi project", "pi")
13956
+ ...legacySources(join7(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
13957
+ ...legacySources(join7(projectDirectory, ".pi", "aft"), "Pi project", "pi")
13939
13958
  ]
13940
13959
  };
13941
13960
  }
13942
13961
  function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
13943
- return join6(storageRoot, harness, ...segments);
13962
+ return join7(storageRoot, harness, ...segments);
13944
13963
  }
13945
13964
  function repairRootScopedStorageFile(storageRoot, harness, fileName) {
13946
13965
  const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
13947
- const rootPath = join6(storageRoot, fileName);
13948
- if (existsSync4(harnessPath) || !existsSync4(rootPath))
13966
+ const rootPath = join7(storageRoot, fileName);
13967
+ if (existsSync5(harnessPath) || !existsSync5(rootPath))
13949
13968
  return harnessPath;
13950
13969
  try {
13951
13970
  mkdirSync2(dirname2(harnessPath), { recursive: true });
@@ -13959,7 +13978,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
13959
13978
  const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
13960
13979
  let lastVersion = "";
13961
13980
  try {
13962
- if (existsSync4(versionFile)) {
13981
+ if (existsSync5(versionFile)) {
13963
13982
  lastVersion = readFileSync4(versionFile, "utf-8").trim();
13964
13983
  }
13965
13984
  } catch {
@@ -14031,10 +14050,10 @@ function decodeFileUrl(target) {
14031
14050
 
14032
14051
  // ../aft-bridge/dist/resolver.js
14033
14052
  import { execSync } from "node:child_process";
14034
- import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
14053
+ import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
14035
14054
  import { createRequire as createRequire2 } from "node:module";
14036
14055
  import { homedir as homedir7 } from "node:os";
14037
- import { join as join7 } from "node:path";
14056
+ import { join as join8 } from "node:path";
14038
14057
  var ensureBinaryForResolver = ensureBinary;
14039
14058
  function copyToVersionedCache(npmBinaryPath, knownVersion) {
14040
14059
  try {
@@ -14043,10 +14062,10 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
14043
14062
  return null;
14044
14063
  const tag = version.startsWith("v") ? version : `v${version}`;
14045
14064
  const cacheDir = getAftBinaryCacheDir();
14046
- const versionedDir = join7(cacheDir, tag);
14065
+ const versionedDir = join8(cacheDir, tag);
14047
14066
  const ext = process.platform === "win32" ? ".exe" : "";
14048
- const cachedPath = join7(versionedDir, `aft${ext}`);
14049
- if (existsSync5(cachedPath)) {
14067
+ const cachedPath = join8(versionedDir, `aft${ext}`);
14068
+ if (existsSync6(cachedPath)) {
14050
14069
  const cachedVersion = readBinaryVersion(cachedPath);
14051
14070
  if (cachedVersion === version)
14052
14071
  return cachedPath;
@@ -14058,7 +14077,7 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
14058
14077
  if (process.platform !== "win32") {
14059
14078
  chmodSync2(tmpPath, 493);
14060
14079
  }
14061
- if (process.platform === "win32" && existsSync5(cachedPath)) {
14080
+ if (process.platform === "win32" && existsSync6(cachedPath)) {
14062
14081
  try {
14063
14082
  unlinkSync2(cachedPath);
14064
14083
  } catch {}
@@ -14078,8 +14097,8 @@ function homeDirFromEnv(env) {
14078
14097
  return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir7();
14079
14098
  }
14080
14099
  function cachedBinaryPathFromEnv(version, env, ext) {
14081
- const binaryPath = join7(getAftBinaryCacheDir(env), version, `aft${ext}`);
14082
- return existsSync5(binaryPath) ? binaryPath : null;
14100
+ const binaryPath = join8(getAftBinaryCacheDir(env), version, `aft${ext}`);
14101
+ return existsSync6(binaryPath) ? binaryPath : null;
14083
14102
  }
14084
14103
  function isExpectedCachedBinary2(binaryPath, expectedVersion) {
14085
14104
  const expected = normalizeBareVersion(expectedVersion);
@@ -14178,7 +14197,7 @@ function findBinarySyncInner(expectedVersion) {
14178
14197
  const packageBin = `@cortexkit/aft-${key}/bin/aft${ext}`;
14179
14198
  const req = createRequire2(import.meta.url);
14180
14199
  const resolved = req.resolve(packageBin);
14181
- if (existsSync5(resolved)) {
14200
+ if (existsSync6(resolved)) {
14182
14201
  const npmVersion = readBinaryVersion(resolved);
14183
14202
  if (npmVersion === null) {
14184
14203
  warn(`npm platform package binary at ${resolved} did not report a version; skipping (continuing to PATH lookup)`);
@@ -14207,8 +14226,8 @@ function findBinarySyncInner(expectedVersion) {
14207
14226
  return { path: usable, source: "PATH" };
14208
14227
  }
14209
14228
  } catch {}
14210
- const cargoPath = join7(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
14211
- if (existsSync5(cargoPath)) {
14229
+ const cargoPath = join8(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
14230
+ if (existsSync6(cargoPath)) {
14212
14231
  const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
14213
14232
  if (usable)
14214
14233
  return { path: usable, source: "cargo" };
@@ -14254,9 +14273,9 @@ function dataHome2() {
14254
14273
  if (process.env.XDG_DATA_HOME)
14255
14274
  return process.env.XDG_DATA_HOME;
14256
14275
  if (process.platform === "win32") {
14257
- return process.env.LOCALAPPDATA || process.env.APPDATA || join8(homeDir4(), "AppData", "Local");
14276
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join9(homeDir4(), "AppData", "Local");
14258
14277
  }
14259
- return join8(homeDir4(), ".local", "share");
14278
+ return join9(homeDir4(), ".local", "share");
14260
14279
  }
14261
14280
  function homeDir4() {
14262
14281
  if (process.platform === "win32")
@@ -14265,8 +14284,8 @@ function homeDir4() {
14265
14284
  }
14266
14285
  function resolveLegacyStorageRoot(harness) {
14267
14286
  if (harness === "pi")
14268
- return join8(homeDir4(), ".pi", "agent", "aft");
14269
- return join8(dataHome2(), "opencode", "storage", "plugin", "aft");
14287
+ return join9(homeDir4(), ".pi", "agent", "aft");
14288
+ return join9(dataHome2(), "opencode", "storage", "plugin", "aft");
14270
14289
  }
14271
14290
  function stripJsoncForParse(input) {
14272
14291
  let out = "";
@@ -14396,7 +14415,7 @@ function acquireConfigMigrationLock(lockDir) {
14396
14415
  }
14397
14416
  function atomicCopyConfigFile(sourcePath, targetPath) {
14398
14417
  mkdirSync4(dirname3(targetPath), { recursive: true });
14399
- const tmpPath = join8(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
14418
+ const tmpPath = join9(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
14400
14419
  let fd = null;
14401
14420
  try {
14402
14421
  fd = openSync3(tmpPath, "wx", 384);
@@ -14418,7 +14437,7 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
14418
14437
  }
14419
14438
  function atomicWriteConfigFile(targetPath, content) {
14420
14439
  mkdirSync4(dirname3(targetPath), { recursive: true });
14421
- const tmpPath = join8(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
14440
+ const tmpPath = join9(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
14422
14441
  let fd = null;
14423
14442
  try {
14424
14443
  fd = openSync3(tmpPath, "wx", 384);
@@ -14440,11 +14459,11 @@ function atomicWriteConfigFile(targetPath, content) {
14440
14459
  }
14441
14460
  var MOVED_MARKER_SUFFIX = ".MOVED_READPLEASE";
14442
14461
  function nonClobberingSidecarPath(desiredPath) {
14443
- if (!existsSync6(desiredPath))
14462
+ if (!existsSync7(desiredPath))
14444
14463
  return desiredPath;
14445
14464
  for (let index = 1;index < Number.MAX_SAFE_INTEGER; index++) {
14446
14465
  const candidate = `${desiredPath}.${index}`;
14447
- if (!existsSync6(candidate))
14466
+ if (!existsSync7(candidate))
14448
14467
  return candidate;
14449
14468
  }
14450
14469
  throw new Error(`could not find available preservation sidecar path for ${desiredPath}`);
@@ -14538,7 +14557,7 @@ function visibleConfigMigrationWarning(scope, targetPath, paths, reason) {
14538
14557
  function migrateAftConfigFile(opts) {
14539
14558
  const warnings = [];
14540
14559
  const resolvedTarget = resolve6(opts.targetPath);
14541
- const existingSources = opts.legacySources.filter((source) => existsSync6(source.path) && resolve6(source.path) !== resolvedTarget);
14560
+ const existingSources = opts.legacySources.filter((source) => existsSync7(source.path) && resolve6(source.path) !== resolvedTarget);
14542
14561
  const info = opts.logger?.info ?? opts.logger?.log;
14543
14562
  if (existingSources.length === 0) {
14544
14563
  return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
@@ -14550,7 +14569,7 @@ function migrateAftConfigFile(opts) {
14550
14569
  ...source,
14551
14570
  content: readFileSync5(source.path, "utf-8")
14552
14571
  }));
14553
- if (existsSync6(opts.targetPath)) {
14572
+ if (existsSync7(opts.targetPath)) {
14554
14573
  const targetContent = readFileSync5(opts.targetPath, "utf-8");
14555
14574
  for (const source of sources) {
14556
14575
  if (fileSemanticsMatch(source.content, targetContent))
@@ -14600,12 +14619,12 @@ function spawnErrorLabel(error2) {
14600
14619
  return [code, error2.message].filter(Boolean).join(": ");
14601
14620
  }
14602
14621
  function migrationLogPath(newRoot, harness, logger) {
14603
- const desired = join8(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
14622
+ const desired = join9(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
14604
14623
  try {
14605
14624
  mkdirSync4(dirname3(desired), { recursive: true });
14606
14625
  return desired;
14607
14626
  } catch (err) {
14608
- const fallback = join8(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
14627
+ const fallback = join9(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
14609
14628
  logger?.warn?.(`Failed to create AFT migration log directory ${dirname3(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
14610
14629
  return fallback;
14611
14630
  }
@@ -14615,11 +14634,11 @@ async function ensureStorageMigrated(opts) {
14615
14634
  const newRoot = resolveCortexKitStorageRoot();
14616
14635
  const targetMarker = resolveHarnessStoragePath(newRoot, opts.harness, TARGET_MARKER);
14617
14636
  const info = opts.logger?.info ?? opts.logger?.log;
14618
- if (existsSync6(targetMarker)) {
14637
+ if (existsSync7(targetMarker)) {
14619
14638
  info?.(`AFT storage already migrated for ${opts.harness}; using ${newRoot}`);
14620
14639
  return;
14621
14640
  }
14622
- if (!existsSync6(legacyRoot)) {
14641
+ if (!existsSync7(legacyRoot)) {
14623
14642
  info?.(`AFT storage migration skipped for ${opts.harness}: no legacy data at ${legacyRoot}; ` + `using ${newRoot} for fresh install`);
14624
14643
  return;
14625
14644
  }
@@ -14669,7 +14688,7 @@ async function ensureStorageMigrated(opts) {
14669
14688
  // ../aft-bridge/dist/npm-resolver.js
14670
14689
  import { readdirSync as readdirSync2, statSync as statSync5 } from "node:fs";
14671
14690
  import { homedir as homedir9 } from "node:os";
14672
- import { delimiter, dirname as dirname4, isAbsolute as isAbsolute3, join as join9 } from "node:path";
14691
+ import { delimiter as delimiter2, dirname as dirname4, isAbsolute as isAbsolute3, join as join10 } from "node:path";
14673
14692
  function defaultDeps() {
14674
14693
  return {
14675
14694
  platform: process.platform,
@@ -14691,18 +14710,18 @@ function isFile(p) {
14691
14710
  function npmFromPath(deps) {
14692
14711
  const name = npmBinaryName(deps.platform);
14693
14712
  const raw = deps.env.PATH ?? deps.env.Path ?? "";
14694
- for (const entry of raw.split(delimiter)) {
14713
+ for (const entry of raw.split(delimiter2)) {
14695
14714
  const dir = entry.trim().replace(/^"|"$/g, "");
14696
14715
  if (!dir || !isAbsolute3(dir))
14697
14716
  continue;
14698
- if (isFile(join9(dir, name)))
14717
+ if (isFile(join10(dir, name)))
14699
14718
  return dir;
14700
14719
  }
14701
14720
  return null;
14702
14721
  }
14703
14722
  function npmAdjacentToNode(deps) {
14704
14723
  const dir = dirname4(deps.execPath);
14705
- return isFile(join9(dir, npmBinaryName(deps.platform))) ? dir : null;
14724
+ return isFile(join10(dir, npmBinaryName(deps.platform))) ? dir : null;
14706
14725
  }
14707
14726
  function highestVersionedNodeBin(installsDir, name) {
14708
14727
  let entries;
@@ -14711,8 +14730,8 @@ function highestVersionedNodeBin(installsDir, name) {
14711
14730
  } catch {
14712
14731
  return null;
14713
14732
  }
14714
- const candidates = entries.filter((v) => isFile(join9(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
14715
- return candidates.length > 0 ? join9(installsDir, candidates[0], "bin") : null;
14733
+ const candidates = entries.filter((v) => isFile(join10(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
14734
+ return candidates.length > 0 ? join10(installsDir, candidates[0], "bin") : null;
14716
14735
  }
14717
14736
  function compareVersionsDesc(a, b) {
14718
14737
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -14737,22 +14756,22 @@ function wellKnownNpmDirs(deps) {
14737
14756
  const programFiles = env.ProgramFiles || "C:\\Program Files";
14738
14757
  const appData = env.APPDATA;
14739
14758
  const localAppData = env.LOCALAPPDATA;
14740
- push(join9(programFiles, "nodejs"));
14759
+ push(join10(programFiles, "nodejs"));
14741
14760
  if (appData)
14742
- push(join9(appData, "npm"));
14761
+ push(join10(appData, "npm"));
14743
14762
  if (localAppData)
14744
- push(join9(localAppData, "Volta", "bin"));
14763
+ push(join10(localAppData, "Volta", "bin"));
14745
14764
  if (env.NVM_SYMLINK)
14746
14765
  push(env.NVM_SYMLINK);
14747
14766
  } else {
14748
14767
  if (env.NVM_BIN)
14749
14768
  push(env.NVM_BIN);
14750
- push(highestVersionedNodeBin(join9(home, ".nvm", "versions", "node"), name));
14751
- push(highestVersionedNodeBin(join9(home, ".local", "share", "mise", "installs", "node"), name));
14752
- push(highestVersionedNodeBin(join9(home, ".asdf", "installs", "nodejs"), name));
14753
- push(join9(home, ".volta", "bin"));
14754
- push(join9(home, ".asdf", "shims"));
14755
- const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join9(home, ".local", "bin")]);
14769
+ push(highestVersionedNodeBin(join10(home, ".nvm", "versions", "node"), name));
14770
+ push(highestVersionedNodeBin(join10(home, ".local", "share", "mise", "installs", "node"), name));
14771
+ push(highestVersionedNodeBin(join10(home, ".asdf", "installs", "nodejs"), name));
14772
+ push(join10(home, ".volta", "bin"));
14773
+ push(join10(home, ".asdf", "shims"));
14774
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join10(home, ".local", "bin")]);
14756
14775
  for (const dir of systemDirs)
14757
14776
  push(dir);
14758
14777
  }
@@ -14762,12 +14781,12 @@ function resolveNpm(deps = defaultDeps()) {
14762
14781
  const name = npmBinaryName(deps.platform);
14763
14782
  const onPath = npmFromPath(deps);
14764
14783
  if (onPath)
14765
- return { command: join9(onPath, name), binDir: onPath };
14784
+ return { command: join10(onPath, name), binDir: onPath };
14766
14785
  const adjacent = npmAdjacentToNode(deps);
14767
14786
  if (adjacent)
14768
- return { command: join9(adjacent, name), binDir: adjacent };
14787
+ return { command: join10(adjacent, name), binDir: adjacent };
14769
14788
  for (const dir of wellKnownNpmDirs(deps)) {
14770
- const candidate = join9(dir, name);
14789
+ const candidate = join10(dir, name);
14771
14790
  if (isFile(candidate))
14772
14791
  return { command: candidate, binDir: dir };
14773
14792
  }
@@ -14777,14 +14796,14 @@ function npmSpawnEnv(resolved, baseEnv = process.env) {
14777
14796
  if (!resolved.binDir)
14778
14797
  return { ...baseEnv };
14779
14798
  const existing = baseEnv.PATH ?? baseEnv.Path ?? "";
14780
- const next = existing ? `${resolved.binDir}${delimiter}${existing}` : resolved.binDir;
14799
+ const next = existing ? `${resolved.binDir}${delimiter2}${existing}` : resolved.binDir;
14781
14800
  return { ...baseEnv, PATH: next };
14782
14801
  }
14783
14802
  // ../aft-bridge/dist/onnx-runtime.js
14784
14803
  import { execFileSync } from "node:child_process";
14785
14804
  import { createHash as createHash3 } from "node:crypto";
14786
- import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync7, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, rmSync as rmSync3, statSync as statSync6, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
14787
- import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute4, join as join10, relative as relative2, resolve as resolve7, win32 } from "node:path";
14805
+ import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync8, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, rmSync as rmSync3, statSync as statSync6, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
14806
+ import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute4, join as join11, relative as relative2, resolve as resolve7, win32 } from "node:path";
14788
14807
  import { Readable as Readable2 } from "node:stream";
14789
14808
  import { pipeline as pipeline2 } from "node:stream/promises";
14790
14809
  var ORT_VERSION = "1.24.4";
@@ -14847,11 +14866,11 @@ function getManualInstallHint() {
14847
14866
  }
14848
14867
  async function ensureOnnxRuntime(storageDir) {
14849
14868
  const info = getPlatformInfo();
14850
- const ortVersionDir = join10(storageDir, "onnxruntime", ORT_VERSION);
14869
+ const ortVersionDir = join11(storageDir, "onnxruntime", ORT_VERSION);
14851
14870
  const libName = info?.libName ?? "libonnxruntime.dylib";
14852
14871
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
14853
- const libPath = join10(resolvedOrtDir, libName);
14854
- if (existsSync7(libPath)) {
14872
+ const libPath = join11(resolvedOrtDir, libName);
14873
+ if (existsSync8(libPath)) {
14855
14874
  const meta = readOnnxInstalledMeta(ortVersionDir);
14856
14875
  if (meta?.sha256) {
14857
14876
  try {
@@ -14880,9 +14899,9 @@ async function ensureOnnxRuntime(storageDir) {
14880
14899
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
14881
14900
  return null;
14882
14901
  }
14883
- const onnxBaseDir = join10(storageDir, "onnxruntime");
14902
+ const onnxBaseDir = join11(storageDir, "onnxruntime");
14884
14903
  mkdirSync5(onnxBaseDir, { recursive: true });
14885
- const lockPath = join10(onnxBaseDir, ONNX_LOCK_FILE);
14904
+ const lockPath = join11(onnxBaseDir, ONNX_LOCK_FILE);
14886
14905
  cleanupAbandonedStagingDirs(onnxBaseDir);
14887
14906
  if (!acquireLock(lockPath)) {
14888
14907
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -14901,7 +14920,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
14901
14920
  for (const entry of entries) {
14902
14921
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
14903
14922
  continue;
14904
- const stagingDir = join10(onnxBaseDir, entry);
14923
+ const stagingDir = join11(onnxBaseDir, entry);
14905
14924
  const parts = entry.split(".");
14906
14925
  const pidStr = parts[parts.length - 2];
14907
14926
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -14938,7 +14957,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
14938
14957
  }
14939
14958
  function cleanupIncompleteTargetIfUnowned(ortDir) {
14940
14959
  try {
14941
- if (existsSync7(ortDir) && !existsSync7(join10(ortDir, ONNX_INSTALLED_META_FILE))) {
14960
+ if (existsSync8(ortDir) && !existsSync8(join11(ortDir, ONNX_INSTALLED_META_FILE))) {
14942
14961
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
14943
14962
  rmSync3(ortDir, { recursive: true, force: true });
14944
14963
  }
@@ -14982,8 +15001,8 @@ function detectOnnxVersion(libDir, libName) {
14982
15001
  if (version)
14983
15002
  return version;
14984
15003
  }
14985
- const base = join10(libDir, libName);
14986
- if (existsSync7(base)) {
15004
+ const base = join11(libDir, libName);
15005
+ if (existsSync8(base)) {
14987
15006
  try {
14988
15007
  const real = realpathSync2(base);
14989
15008
  const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
@@ -15014,8 +15033,8 @@ function pathEnvValue() {
15014
15033
  return process.env.PATH ?? process.env.Path ?? process.env.path ?? "";
15015
15034
  }
15016
15035
  function pathEntriesForPlatform() {
15017
- const delimiter2 = process.platform === "win32" ? ";" : ":";
15018
- return pathEnvValue().split(delimiter2).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
15036
+ const delimiter3 = process.platform === "win32" ? ";" : ":";
15037
+ return pathEnvValue().split(delimiter3).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
15019
15038
  if (!entry || entry === "." || entry.includes("\x00"))
15020
15039
  return false;
15021
15040
  return isAbsolute4(entry) || win32.isAbsolute(entry);
@@ -15045,10 +15064,10 @@ function directoryContainsLibrary(dir, libName) {
15045
15064
  }
15046
15065
  }
15047
15066
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
15048
- if (existsSync7(join10(ortVersionDir, libName)))
15067
+ if (existsSync8(join11(ortVersionDir, libName)))
15049
15068
  return ortVersionDir;
15050
- const libSubdir = join10(ortVersionDir, "lib");
15051
- if (existsSync7(join10(libSubdir, libName)))
15069
+ const libSubdir = join11(ortVersionDir, "lib");
15070
+ if (existsSync8(join11(libSubdir, libName)))
15052
15071
  return libSubdir;
15053
15072
  return ortVersionDir;
15054
15073
  }
@@ -15063,13 +15082,13 @@ function findSystemOnnxRuntime(libName) {
15063
15082
  } else if (process.platform === "win32") {
15064
15083
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
15065
15084
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
15066
- searchPaths.push(join10(programFiles, "onnxruntime", "lib"), join10(programFiles, "Microsoft ONNX Runtime", "lib"), join10(programFiles, "Microsoft Machine Learning", "lib"), join10(programFilesX86, "onnxruntime", "lib"), ...(() => {
15085
+ searchPaths.push(join11(programFiles, "onnxruntime", "lib"), join11(programFiles, "Microsoft ONNX Runtime", "lib"), join11(programFiles, "Microsoft Machine Learning", "lib"), join11(programFilesX86, "onnxruntime", "lib"), ...(() => {
15067
15086
  const nugetPaths = [];
15068
15087
  const userProfile = process.env.USERPROFILE ?? "";
15069
15088
  if (!userProfile)
15070
15089
  return nugetPaths;
15071
- const nugetPackageDir = join10(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
15072
- if (!existsSync7(nugetPackageDir))
15090
+ const nugetPackageDir = join11(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
15091
+ if (!existsSync8(nugetPackageDir))
15073
15092
  return nugetPaths;
15074
15093
  try {
15075
15094
  for (const entry of readdirSync3(nugetPackageDir, { withFileTypes: true })) {
@@ -15077,7 +15096,7 @@ function findSystemOnnxRuntime(libName) {
15077
15096
  continue;
15078
15097
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
15079
15098
  continue;
15080
- nugetPaths.push(join10(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join10(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
15099
+ nugetPaths.push(join11(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join11(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
15081
15100
  }
15082
15101
  } catch (err) {
15083
15102
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -15099,11 +15118,11 @@ function findSystemOnnxRuntime(libName) {
15099
15118
  });
15100
15119
  const unknownVersionPaths = [];
15101
15120
  for (const dir of uniquePaths) {
15102
- const libPath = join10(dir, libName);
15121
+ const libPath = join11(dir, libName);
15103
15122
  if (process.platform === "win32") {
15104
15123
  if (!directoryContainsLibrary(dir, libName))
15105
15124
  continue;
15106
- } else if (!existsSync7(libPath)) {
15125
+ } else if (!existsSync8(libPath)) {
15107
15126
  continue;
15108
15127
  }
15109
15128
  const version = detectOnnxVersion(dir, libName);
@@ -15169,7 +15188,7 @@ function validateExtractedTree(stagingRoot) {
15169
15188
  const walk = (dir) => {
15170
15189
  const entries = readdirSync3(dir);
15171
15190
  for (const entry of entries) {
15172
- const fullPath = join10(dir, entry);
15191
+ const fullPath = join11(dir, entry);
15173
15192
  const lst = lstatSync(fullPath);
15174
15193
  if (lst.isSymbolicLink()) {
15175
15194
  const linkTarget = readlinkSync(fullPath);
@@ -15204,7 +15223,7 @@ async function downloadOnnxRuntime(info, targetDir) {
15204
15223
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
15205
15224
  try {
15206
15225
  mkdirSync5(tmpDir, { recursive: true });
15207
- const archivePath = join10(tmpDir, `onnxruntime.${info.archiveType}`);
15226
+ const archivePath = join11(tmpDir, `onnxruntime.${info.archiveType}`);
15208
15227
  await downloadFileWithCap(url, archivePath);
15209
15228
  const archiveSha256 = sha256File(archivePath);
15210
15229
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
@@ -15220,8 +15239,8 @@ async function downloadOnnxRuntime(info, targetDir) {
15220
15239
  unlinkSync4(archivePath);
15221
15240
  } catch {}
15222
15241
  validateExtractedTree(tmpDir);
15223
- const extractedDir = join10(tmpDir, info.assetName, "lib");
15224
- if (!existsSync7(extractedDir)) {
15242
+ const extractedDir = join11(tmpDir, info.assetName, "lib");
15243
+ if (!existsSync8(extractedDir)) {
15225
15244
  throw new Error(`Expected directory not found: ${extractedDir}`);
15226
15245
  }
15227
15246
  mkdirSync5(targetDir, { recursive: true });
@@ -15229,7 +15248,7 @@ async function downloadOnnxRuntime(info, targetDir) {
15229
15248
  const realFiles = [];
15230
15249
  const symlinks = [];
15231
15250
  for (const libFile of libFiles) {
15232
- const src = join10(extractedDir, libFile);
15251
+ const src = join11(extractedDir, libFile);
15233
15252
  try {
15234
15253
  const stat2 = lstatSync(src);
15235
15254
  log(`ORT extract: ${libFile} — isSymlink=${stat2.isSymbolicLink()}, isFile=${stat2.isFile()}, size=${stat2.size}`);
@@ -15244,7 +15263,7 @@ async function downloadOnnxRuntime(info, targetDir) {
15244
15263
  }
15245
15264
  }
15246
15265
  copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
15247
- const libPath = join10(targetDir, info.libName);
15266
+ const libPath = join11(targetDir, info.libName);
15248
15267
  let libHash = null;
15249
15268
  try {
15250
15269
  libHash = sha256File(libPath);
@@ -15269,8 +15288,8 @@ async function downloadOnnxRuntime(info, targetDir) {
15269
15288
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
15270
15289
  const requiredLibs = new Set([info.libName]);
15271
15290
  for (const libFile of realFiles) {
15272
- const src = join10(extractedDir, libFile);
15273
- const dst = join10(targetDir, libFile);
15291
+ const src = join11(extractedDir, libFile);
15292
+ const dst = join11(targetDir, libFile);
15274
15293
  try {
15275
15294
  copyFile(src, dst);
15276
15295
  if (process.platform !== "win32") {
@@ -15286,11 +15305,11 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
15286
15305
  }
15287
15306
  const targetRoot = realpathSync2(targetDir);
15288
15307
  for (const link of symlinks) {
15289
- const dst = join10(targetDir, link.name);
15308
+ const dst = join11(targetDir, link.name);
15290
15309
  try {
15291
15310
  unlinkSync4(dst);
15292
15311
  } catch {}
15293
- const dstForContainment = join10(targetRoot, link.name);
15312
+ const dstForContainment = join11(targetRoot, link.name);
15294
15313
  const resolvedTarget = resolve7(dirname5(dstForContainment), link.target);
15295
15314
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
15296
15315
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
@@ -15311,8 +15330,8 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
15311
15330
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
15312
15331
  }
15313
15332
  }
15314
- const requiredPath = join10(targetDir, info.libName);
15315
- if (!existsSync7(requiredPath)) {
15333
+ const requiredPath = join11(targetDir, info.libName);
15334
+ if (!existsSync8(requiredPath)) {
15316
15335
  rmSync3(targetDir, { recursive: true, force: true });
15317
15336
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
15318
15337
  }
@@ -15338,13 +15357,13 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
15338
15357
  ...sha256 ? { sha256 } : {},
15339
15358
  archiveSha256
15340
15359
  };
15341
- writeFileSync3(join10(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
15360
+ writeFileSync3(join11(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
15342
15361
  } catch (err) {
15343
15362
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
15344
15363
  }
15345
15364
  }
15346
15365
  function readOnnxInstalledMeta(installDir) {
15347
- const path2 = join10(installDir, ONNX_INSTALLED_META_FILE);
15366
+ const path2 = join11(installDir, ONNX_INSTALLED_META_FILE);
15348
15367
  try {
15349
15368
  if (!statSync6(path2).isFile())
15350
15369
  return null;
@@ -15750,7 +15769,7 @@ function editModesPresent(record) {
15750
15769
  const hasSymbol = isNonEmptyString(record.symbol);
15751
15770
  if (!hasSymbol) {
15752
15771
  delete record.symbol;
15753
- if (record.content === null || record.content === "")
15772
+ if (isNullOrEmptyString(record.content))
15754
15773
  delete record.content;
15755
15774
  } else if (record.content === null) {
15756
15775
  delete record.content;
@@ -15779,17 +15798,24 @@ function editModesPresent(record) {
15779
15798
  function isNonEmptyString(value) {
15780
15799
  return typeof value === "string" && value.length > 0;
15781
15800
  }
15801
+ function isNullOrEmptyString(value) {
15802
+ return value === null || value === "";
15803
+ }
15782
15804
  var OMIT_OPTIONAL_FIELDS_STEERING = "Omit unused optional fields entirely; do not send empty strings or empty arrays for them.";
15783
15805
  function isEditSentinelItem(item) {
15784
15806
  if (!item || typeof item !== "object" || Array.isArray(item))
15785
15807
  return false;
15786
15808
  const record = item;
15787
- if (record.oldString !== "")
15809
+ const oldStringEmpty = hasOwn(record, "oldString") && isNullOrEmptyString(record.oldString);
15810
+ if (!oldStringEmpty)
15788
15811
  return false;
15789
- const newStringEmpty = !hasOwn(record, "newString") || record.newString === "" || record.newString === null;
15812
+ if (record.oldString === null && ["startLine", "endLine"].some((key) => hasOwn(record, key) && record[key] !== null)) {
15813
+ return false;
15814
+ }
15815
+ const newStringEmpty = !hasOwn(record, "newString") || isNullOrEmptyString(record.newString);
15790
15816
  if (!newStringEmpty)
15791
15817
  return false;
15792
- return !hasOwn(record, "content") || record.content === "" || record.content === null;
15818
+ return !hasOwn(record, "content") || isNullOrEmptyString(record.content);
15793
15819
  }
15794
15820
  function normalizeEditArraySentinels(record) {
15795
15821
  const value = record.edits;
@@ -15844,6 +15870,18 @@ function parseEditArray(value) {
15844
15870
  }
15845
15871
  function stripLineRangeSentinels(item) {
15846
15872
  const hasRangeField = ["startLine", "endLine", "content"].some((key) => hasOwn(item, key));
15873
+ for (const key of [
15874
+ "oldString",
15875
+ "newString",
15876
+ "replaceAll",
15877
+ "occurrence",
15878
+ "startLine",
15879
+ "endLine",
15880
+ "content"
15881
+ ]) {
15882
+ if (item[key] === null)
15883
+ delete item[key];
15884
+ }
15847
15885
  if (!hasRangeField)
15848
15886
  return;
15849
15887
  if (item.oldString === "")
@@ -16556,17 +16594,17 @@ function collectStructuredExtras(response) {
16556
16594
  return stringifyData(extras);
16557
16595
  }
16558
16596
  // ../aft-bridge/dist/transport-factory.js
16559
- import { existsSync as existsSync8 } from "node:fs";
16597
+ import { existsSync as existsSync9 } from "node:fs";
16560
16598
  import { homedir as homedir11 } from "node:os";
16561
- import { isAbsolute as isAbsolute5, join as join11 } from "node:path";
16599
+ import { isAbsolute as isAbsolute5, join as join12 } from "node:path";
16562
16600
  function resolveConnectionFilePath(raw) {
16563
16601
  const trimmed = raw.trim();
16564
16602
  if (trimmed.startsWith("~")) {
16565
- return join11(homedir11(), trimmed.slice(1).replace(/^[/\\]/, ""));
16603
+ return join12(homedir11(), trimmed.slice(1).replace(/^[/\\]/, ""));
16566
16604
  }
16567
16605
  if (isAbsolute5(trimmed))
16568
16606
  return trimmed;
16569
- return join11(homedir11(), trimmed);
16607
+ return join12(homedir11(), trimmed);
16570
16608
  }
16571
16609
  var SUBC_CLIENT_REAPER_PROCESS_KEY = "subc_client_reaper";
16572
16610
  function booleanOption(value) {
@@ -16640,7 +16678,7 @@ async function createConcreteAftTransportPool(opts) {
16640
16678
  consumerIdentity: opts.subcConsumerIdentity,
16641
16679
  onBgEventsNudge: opts.onBgEventsNudge,
16642
16680
  onBgEventsNudgeRef: opts.onBgEventsNudgeRef,
16643
- lifecycleDemandCheck: opts.subcLifecycleDemandCheck ?? ((root) => existsSync8(root))
16681
+ lifecycleDemandCheck: opts.subcLifecycleDemandCheck ?? ((root) => existsSync9(root))
16644
16682
  });
16645
16683
  }
16646
16684
  return new BridgePool(opts.binaryPath, opts.poolOptions, opts.configOverrides);
@@ -17461,7 +17499,7 @@ import {
17461
17499
  // package.json
17462
17500
  var package_default = {
17463
17501
  name: "@cortexkit/aft-pi",
17464
- version: "0.53.0",
17502
+ version: "0.54.0",
17465
17503
  type: "module",
17466
17504
  description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
17467
17505
  main: "dist/index.js",
@@ -17484,19 +17522,19 @@ var package_default = {
17484
17522
  "test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
17485
17523
  },
17486
17524
  dependencies: {
17487
- "@cortexkit/aft-bridge": "0.53.0",
17525
+ "@cortexkit/aft-bridge": "0.54.0",
17488
17526
  "comment-json": "^5.0.0",
17489
17527
  diff: "^8.0.4",
17490
17528
  typebox: "1.1.38",
17491
17529
  zod: "^4.4.3"
17492
17530
  },
17493
17531
  optionalDependencies: {
17494
- "@cortexkit/aft-darwin-arm64": "0.53.0",
17495
- "@cortexkit/aft-darwin-x64": "0.53.0",
17496
- "@cortexkit/aft-linux-arm64": "0.53.0",
17497
- "@cortexkit/aft-linux-x64": "0.53.0",
17498
- "@cortexkit/aft-win32-arm64": "0.53.0",
17499
- "@cortexkit/aft-win32-x64": "0.53.0"
17532
+ "@cortexkit/aft-darwin-arm64": "0.54.0",
17533
+ "@cortexkit/aft-darwin-x64": "0.54.0",
17534
+ "@cortexkit/aft-linux-arm64": "0.54.0",
17535
+ "@cortexkit/aft-linux-x64": "0.54.0",
17536
+ "@cortexkit/aft-win32-arm64": "0.54.0",
17537
+ "@cortexkit/aft-win32-x64": "0.54.0"
17500
17538
  },
17501
17539
  devDependencies: {
17502
17540
  "@earendil-works/pi-coding-agent": "^0.80.2",
@@ -17764,7 +17802,7 @@ function appendDegradedStatus(lines, status, markdown) {
17764
17802
  }
17765
17803
 
17766
17804
  // src/tools/_shared.ts
17767
- import { existsSync as existsSync9 } from "node:fs";
17805
+ import { existsSync as existsSync10 } from "node:fs";
17768
17806
  import { Type } from "typebox";
17769
17807
  var optionalInt = (min, max, description = "(integer)") => Type.Optional(Type.Union([Type.Integer({ minimum: min, maximum: max }), Type.String()], {
17770
17808
  description
@@ -17785,7 +17823,7 @@ function withPathAliasPreparation(tool) {
17785
17823
  };
17786
17824
  }
17787
17825
  function bridgeFor(ctx, cwd) {
17788
- if (!existsSync9(cwd)) {
17826
+ if (!existsSync10(cwd)) {
17789
17827
  throw new Error(`project directory no longer exists: ${cwd} (stale restored session?)`);
17790
17828
  }
17791
17829
  return ctx.pool.getBridge(cwd);
@@ -17833,8 +17871,10 @@ async function callBridge(bridge, command, params = {}, extCtx, options) {
17833
17871
  return response;
17834
17872
  }
17835
17873
  async function callToolCall(bridge, name, rawArgs = {}, extCtx, options) {
17874
+ return callToolCallForSession(bridge, name, rawArgs, extCtx ? resolveSessionId(extCtx) : undefined, extCtx, options);
17875
+ }
17876
+ async function callToolCallForSession(bridge, name, rawArgs, sessionId, extCtx, options) {
17836
17877
  const timeoutMs = timeoutForCommand(name);
17837
- const sessionId = extCtx ? resolveSessionId(extCtx) : undefined;
17838
17878
  const sendOptions = {
17839
17879
  ...timeoutMs !== undefined ? { timeoutMs } : {},
17840
17880
  configureWarningClient: extCtx,
@@ -18157,7 +18197,7 @@ function registerStatusCommand(pi, ctx) {
18157
18197
  }
18158
18198
 
18159
18199
  // src/config.ts
18160
- import { existsSync as existsSync10, readFileSync as readFileSync7, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
18200
+ import { existsSync as existsSync11, readFileSync as readFileSync7, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
18161
18201
  import { homedir as homedir12 } from "node:os";
18162
18202
  import { isAbsolute as isAbsolute6 } from "node:path";
18163
18203
  var import_comment_json = __toESM(require_src2(), 1);
@@ -19773,8 +19813,8 @@ function emoji() {
19773
19813
  }
19774
19814
  var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
19775
19815
  var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
19776
- var mac = (delimiter2) => {
19777
- const escapedDelim = escapeRegex(delimiter2 ?? ":");
19816
+ var mac = (delimiter3) => {
19817
+ const escapedDelim = escapeRegex(delimiter3 ?? ":");
19778
19818
  return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
19779
19819
  };
19780
19820
  var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
@@ -32439,6 +32479,26 @@ function date4(params) {
32439
32479
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
32440
32480
  config(en_default());
32441
32481
  // src/config.ts
32482
+ var ACTIVE_HARNESS = "pi";
32483
+ function isConfigRecord(value) {
32484
+ return value !== null && typeof value === "object" && !Array.isArray(value);
32485
+ }
32486
+ function normalizeConfigForActiveHarness(value) {
32487
+ const config2 = stripHarnessSpecificConfigKeys(value, OPENCODE_ONLY_KEYS);
32488
+ if (!isConfigRecord(config2) || !isConfigRecord(config2.harnesses))
32489
+ return config2;
32490
+ const override = config2.harnesses[ACTIVE_HARNESS];
32491
+ return {
32492
+ ...config2,
32493
+ harnesses: override === undefined ? {} : { [ACTIVE_HARNESS]: stripHarnessSpecificConfigKeys(override, OPENCODE_ONLY_KEYS) }
32494
+ };
32495
+ }
32496
+ function warnIgnoredNestedHarnesses(rawConfig, configPath) {
32497
+ const override = isConfigRecord(rawConfig.harnesses) ? rawConfig.harnesses[ACTIVE_HARNESS] : undefined;
32498
+ if (isConfigRecord(override) && Object.hasOwn(override, "harnesses")) {
32499
+ warn2(`Ignoring nested harnesses in harnesses.${ACTIVE_HARNESS} from ${configPath}; harness overrides cannot recurse`);
32500
+ }
32501
+ }
32442
32502
  var DEFAULT_INSPECT_DIAGNOSTICS_TIMEOUT_MS = 120000;
32443
32503
  var MIN_INSPECT_DIAGNOSTICS_TIMEOUT_MS = 1e4;
32444
32504
  var MAX_INSPECT_DIAGNOSTICS_TIMEOUT_MS = 600000;
@@ -32457,6 +32517,7 @@ function resolveBashConfig(config2) {
32457
32517
  const surfaceDefaultEnabled = surface !== "minimal";
32458
32518
  const reminderEnabled = (typeof top === "object" && top !== null ? top.long_running_reminder_enabled : undefined) ?? legacy?.long_running_reminder_enabled;
32459
32519
  const reminderInterval = (typeof top === "object" && top !== null ? top.long_running_reminder_interval_ms : undefined) ?? legacy?.long_running_reminder_interval_ms;
32520
+ const topDetachOnUserMessage = typeof top === "object" && top !== null ? top.detach_on_user_message ?? true : true;
32460
32521
  const rawForegroundWait = typeof top === "object" && top !== null ? top.foreground_wait_window_ms : undefined;
32461
32522
  const foregroundWaitWindowMs = Math.max(FOREGROUND_WAIT_WINDOW_MIN_MS, rawForegroundWait ?? FOREGROUND_WAIT_WINDOW_DEFAULT_MS);
32462
32523
  const base = {
@@ -32465,9 +32526,11 @@ function resolveBashConfig(config2) {
32465
32526
  compress: false,
32466
32527
  background: false,
32467
32528
  host_fallback: false,
32529
+ detach_on_user_message: true,
32468
32530
  long_running_reminder_enabled: reminderEnabled,
32469
32531
  long_running_reminder_interval_ms: reminderInterval,
32470
- foreground_wait_window_ms: foregroundWaitWindowMs
32532
+ foreground_wait_window_ms: foregroundWaitWindowMs,
32533
+ powershell_tool: typeof top === "object" && top !== null ? top.powershell_tool ?? false : false
32471
32534
  };
32472
32535
  if (top === false)
32473
32536
  return base;
@@ -32481,7 +32544,8 @@ function resolveBashConfig(config2) {
32481
32544
  rewrite: top.rewrite ?? true,
32482
32545
  compress: top.compress ?? true,
32483
32546
  background: top.background ?? true,
32484
- host_fallback: top.host_fallback ?? false
32547
+ host_fallback: top.host_fallback ?? false,
32548
+ detach_on_user_message: topDetachOnUserMessage
32485
32549
  };
32486
32550
  }
32487
32551
  const hasLegacyFeatureFlag = legacy && (legacy.rewrite !== undefined || legacy.compress !== undefined || legacy.background !== undefined);
@@ -32595,9 +32659,11 @@ var BashFeaturesSchema = exports_external.object({
32595
32659
  compress: exports_external.boolean().optional(),
32596
32660
  background: exports_external.boolean().optional(),
32597
32661
  host_fallback: exports_external.boolean().optional(),
32662
+ detach_on_user_message: exports_external.boolean().optional(),
32598
32663
  long_running_reminder_enabled: exports_external.boolean().optional(),
32599
32664
  long_running_reminder_interval_ms: exports_external.number().int().positive().optional(),
32600
- foreground_wait_window_ms: exports_external.number().int().positive().optional()
32665
+ foreground_wait_window_ms: exports_external.number().int().positive().optional(),
32666
+ powershell_tool: exports_external.boolean().optional()
32601
32667
  });
32602
32668
  var BashConfigSchema = exports_external.union([exports_external.boolean(), BashFeaturesSchema]);
32603
32669
  var SandboxConfigSchema = exports_external.object({
@@ -32640,7 +32706,7 @@ var BackupConfigSchema = exports_external.object({
32640
32706
  max_depth: exports_external.number().int().positive().optional(),
32641
32707
  max_file_size: exports_external.number().int().positive().optional()
32642
32708
  });
32643
- var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecificConfigKeys(value, OPENCODE_ONLY_KEYS), exports_external.object({
32709
+ var AftConfigFieldsSchema = exports_external.object({
32644
32710
  $schema: exports_external.string().optional(),
32645
32711
  enabled: exports_external.boolean().optional(),
32646
32712
  edit_mode: exports_external.enum(["default", "hashline"]).optional(),
@@ -32672,7 +32738,20 @@ var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecifi
32672
32738
  subc: SubcConfigSchema.optional(),
32673
32739
  gh_shim: GhShimConfigSchema.optional(),
32674
32740
  git: GitConfigSchema.optional()
32741
+ });
32742
+ var HarnessOverrideSchema = exports_external.preprocess((value) => {
32743
+ if (!isConfigRecord(value) || !Object.hasOwn(value, "harnesses"))
32744
+ return value;
32745
+ const { harnesses: _nestedHarnesses, ...override } = value;
32746
+ return override;
32747
+ }, AftConfigFieldsSchema.strict());
32748
+ var AftConfigSchema = exports_external.preprocess(normalizeConfigForActiveHarness, AftConfigFieldsSchema.extend({
32749
+ harnesses: exports_external.record(exports_external.string(), HarnessOverrideSchema).optional()
32675
32750
  }).strict());
32751
+ function applyActiveHarnessOverride(config2) {
32752
+ const { harnesses: _harnesses, ...base } = config2;
32753
+ return { ...base, ...config2.harnesses?.[ACTIVE_HARNESS] };
32754
+ }
32676
32755
  var CONFIG_MIGRATIONS = [
32677
32756
  { oldKey: "experimental_search_index", newPath: ["search_index"] },
32678
32757
  { oldKey: "experimental_semantic_search", newPath: ["semantic_search"] },
@@ -32783,7 +32862,7 @@ function migrateExperimentalBashBlock(rawConfig, configPath, logger) {
32783
32862
  return movedKeys;
32784
32863
  }
32785
32864
  function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 }) {
32786
- if (!existsSync10(configPath)) {
32865
+ if (!existsSync11(configPath)) {
32787
32866
  return { migrated: false, oldKeys: [] };
32788
32867
  }
32789
32868
  let tmpPath = null;
@@ -32842,7 +32921,7 @@ function warnIgnoredHarnessSpecificConfigKeys(config2, configPath) {
32842
32921
  }
32843
32922
  function loadConfigFromPath(configPath) {
32844
32923
  try {
32845
- if (!existsSync10(configPath))
32924
+ if (!existsSync11(configPath))
32846
32925
  return null;
32847
32926
  const content = readFileSync7(configPath, "utf-8");
32848
32927
  const rawConfig = import_comment_json.parse(content);
@@ -32853,14 +32932,15 @@ function loadConfigFromPath(configPath) {
32853
32932
  migrateRawConfig(rawConfig, configPath, { log: log2, warn: warn2 });
32854
32933
  const cleanConfig = stripJsoncSymbols(rawConfig);
32855
32934
  warnIgnoredHarnessSpecificConfigKeys(cleanConfig, configPath);
32935
+ warnIgnoredNestedHarnesses(cleanConfig, configPath);
32856
32936
  const result = AftConfigSchema.safeParse(cleanConfig);
32857
32937
  if (result.success) {
32858
32938
  log2(`Config loaded from ${configPath}`);
32859
- return result.data;
32939
+ return applyActiveHarnessOverride(result.data);
32860
32940
  }
32861
32941
  const errorMsg = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
32862
32942
  warn2(`Config validation error in ${configPath}: ${errorMsg}`);
32863
- return parseConfigPartially(cleanConfig);
32943
+ return applyActiveHarnessOverride(parseConfigPartially(cleanConfig));
32864
32944
  } catch (err) {
32865
32945
  const errorMsg = err instanceof Error ? err.message : String(err);
32866
32946
  error2(`Error loading config from ${configPath}: ${errorMsg}`);
@@ -33176,7 +33256,7 @@ import { spawn as spawn3 } from "node:child_process";
33176
33256
  import { createHash as createHash4 } from "node:crypto";
33177
33257
  import {
33178
33258
  createReadStream,
33179
- existsSync as existsSync12,
33259
+ existsSync as existsSync13,
33180
33260
  mkdirSync as mkdirSync7,
33181
33261
  readFileSync as readFileSync10,
33182
33262
  renameSync as renameSync6,
@@ -33184,7 +33264,7 @@ import {
33184
33264
  statSync as statSync8,
33185
33265
  writeFileSync as writeFileSync6
33186
33266
  } from "node:fs";
33187
- import { join as join14 } from "node:path";
33267
+ import { join as join15 } from "node:path";
33188
33268
 
33189
33269
  // src/lsp-cache.ts
33190
33270
  import {
@@ -33196,23 +33276,23 @@ import {
33196
33276
  unlinkSync as unlinkSync6,
33197
33277
  writeFileSync as writeFileSync5
33198
33278
  } from "node:fs";
33199
- import { join as join12 } from "node:path";
33279
+ import { join as join13 } from "node:path";
33200
33280
  function lspCacheRoot() {
33201
33281
  return getAftLspPackagesDir();
33202
33282
  }
33203
33283
  function lspPackageDir(npmPackage) {
33204
- return join12(lspCacheRoot(), encodeURIComponent(npmPackage));
33284
+ return join13(lspCacheRoot(), encodeURIComponent(npmPackage));
33205
33285
  }
33206
33286
  function lspBinaryPath(npmPackage, binary) {
33207
- return join12(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
33287
+ return join13(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
33208
33288
  }
33209
33289
  function lspBinDir(npmPackage) {
33210
- return join12(lspPackageDir(npmPackage), "node_modules", ".bin");
33290
+ return join13(lspPackageDir(npmPackage), "node_modules", ".bin");
33211
33291
  }
33212
33292
  function isInstalled(npmPackage, binary) {
33213
33293
  for (const candidate of lspBinaryCandidates(binary)) {
33214
33294
  try {
33215
- if (statSync7(join12(lspBinDir(npmPackage), candidate)).isFile())
33295
+ if (statSync7(join13(lspBinDir(npmPackage), candidate)).isFile())
33216
33296
  return true;
33217
33297
  } catch {}
33218
33298
  }
@@ -33232,13 +33312,13 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
33232
33312
  installedAt: new Date().toISOString(),
33233
33313
  ...sha256 ? { sha256 } : {}
33234
33314
  };
33235
- writeFileSync5(join12(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
33315
+ writeFileSync5(join13(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
33236
33316
  } catch (err) {
33237
33317
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
33238
33318
  }
33239
33319
  }
33240
33320
  function readInstalledMetaIn(installDir) {
33241
- const path2 = join12(installDir, INSTALLED_META_FILE);
33321
+ const path2 = join13(installDir, INSTALLED_META_FILE);
33242
33322
  try {
33243
33323
  if (!statSync7(path2).isFile())
33244
33324
  return null;
@@ -33262,7 +33342,7 @@ function readInstalledMeta(packageKey) {
33262
33342
  return readInstalledMetaIn(lspPackageDir(packageKey));
33263
33343
  }
33264
33344
  function lockPath(npmPackage) {
33265
- return join12(lspPackageDir(npmPackage), ".aft-installing");
33345
+ return join13(lspPackageDir(npmPackage), ".aft-installing");
33266
33346
  }
33267
33347
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
33268
33348
  function acquireInstallLock(lockKey) {
@@ -33369,7 +33449,7 @@ async function withInstallLock(lockKey, task) {
33369
33449
  }
33370
33450
  var VERSION_CHECK_FILE = ".aft-version-check";
33371
33451
  function readVersionCheck(npmPackage) {
33372
- const file2 = join12(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33452
+ const file2 = join13(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33373
33453
  try {
33374
33454
  const raw = readFileSync8(file2, "utf8");
33375
33455
  const parsed = JSON.parse(raw);
@@ -33386,7 +33466,7 @@ function readVersionCheck(npmPackage) {
33386
33466
  }
33387
33467
  function writeVersionCheck(npmPackage, latest) {
33388
33468
  mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
33389
- const file2 = join12(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33469
+ const file2 = join13(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33390
33470
  const record2 = {
33391
33471
  last_checked: new Date().toISOString(),
33392
33472
  latest_eligible: latest
@@ -33548,8 +33628,8 @@ var NPM_LSP_TABLE = [
33548
33628
  ];
33549
33629
 
33550
33630
  // src/lsp-project-relevance.ts
33551
- import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "node:fs";
33552
- import { join as join13 } from "node:path";
33631
+ import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "node:fs";
33632
+ import { join as join14 } from "node:path";
33553
33633
  var MAX_WALK_DIRS = 200;
33554
33634
  var MAX_WALK_DEPTH = 4;
33555
33635
  var NOISE_DIRS = new Set([
@@ -33566,7 +33646,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
33566
33646
  if (!rootMarkers)
33567
33647
  return false;
33568
33648
  for (const marker of rootMarkers) {
33569
- if (existsSync11(join13(projectRoot, marker)))
33649
+ if (existsSync12(join14(projectRoot, marker)))
33570
33650
  return true;
33571
33651
  }
33572
33652
  return false;
@@ -33590,7 +33670,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
33590
33670
  }
33591
33671
  function readPackageJson(projectRoot) {
33592
33672
  try {
33593
- const raw = readFileSync9(join13(projectRoot, "package.json"), "utf8");
33673
+ const raw = readFileSync9(join14(projectRoot, "package.json"), "utf8");
33594
33674
  const parsed = JSON.parse(raw);
33595
33675
  if (typeof parsed !== "object" || parsed === null)
33596
33676
  return null;
@@ -33620,7 +33700,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
33620
33700
  for (const entry of entries) {
33621
33701
  if (entry.isDirectory()) {
33622
33702
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
33623
- queue.push({ dir: join13(current.dir, entry.name), depth: current.depth + 1 });
33703
+ queue.push({ dir: join14(current.dir, entry.name), depth: current.depth + 1 });
33624
33704
  }
33625
33705
  continue;
33626
33706
  }
@@ -33747,8 +33827,8 @@ async function resolveTargetVersion(spec, config2, fetchImpl = fetch) {
33747
33827
  }
33748
33828
  function ensureInstallAnchor(cwd) {
33749
33829
  try {
33750
- const stub = join14(cwd, "package.json");
33751
- if (!existsSync12(stub)) {
33830
+ const stub = join15(cwd, "package.json");
33831
+ if (!existsSync13(stub)) {
33752
33832
  writeFileSync6(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
33753
33833
  `);
33754
33834
  }
@@ -33939,10 +34019,10 @@ function sha256OfFileSync(path2) {
33939
34019
  }
33940
34020
  function quarantineCachedNpmInstall(spec, reason) {
33941
34021
  const packageDir = lspPackageDir(spec.npm);
33942
- const dest = join14(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
34022
+ const dest = join15(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
33943
34023
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
33944
34024
  try {
33945
- mkdirSync7(join14(dest, ".."), { recursive: true });
34025
+ mkdirSync7(join15(dest, ".."), { recursive: true });
33946
34026
  rmSync4(dest, { recursive: true, force: true });
33947
34027
  renameSync6(packageDir, dest);
33948
34028
  } catch (err) {
@@ -34030,7 +34110,7 @@ import {
34030
34110
  copyFileSync as copyFileSync4,
34031
34111
  createReadStream as createReadStream2,
34032
34112
  createWriteStream as createWriteStream3,
34033
- existsSync as existsSync13,
34113
+ existsSync as existsSync14,
34034
34114
  lstatSync as lstatSync2,
34035
34115
  mkdirSync as mkdirSync8,
34036
34116
  readdirSync as readdirSync5,
@@ -34043,7 +34123,7 @@ import {
34043
34123
  unlinkSync as unlinkSync7,
34044
34124
  writeFileSync as writeFileSync7
34045
34125
  } from "node:fs";
34046
- import { dirname as dirname6, join as join15, relative as relative3, resolve as resolve8 } from "node:path";
34126
+ import { dirname as dirname6, join as join16, relative as relative3, resolve as resolve8 } from "node:path";
34047
34127
  import { Readable as Readable3 } from "node:stream";
34048
34128
  import { pipeline as pipeline3 } from "node:stream/promises";
34049
34129
 
@@ -34136,23 +34216,23 @@ function ghCacheRoot() {
34136
34216
  return getAftLspBinariesDir();
34137
34217
  }
34138
34218
  function ghPackageDir(spec) {
34139
- return join15(ghCacheRoot(), spec.id);
34219
+ return join16(ghCacheRoot(), spec.id);
34140
34220
  }
34141
34221
  function ghBinDir(spec) {
34142
- return join15(ghPackageDir(spec), "bin");
34222
+ return join16(ghPackageDir(spec), "bin");
34143
34223
  }
34144
34224
  function ghExtractDir(spec) {
34145
- return join15(ghPackageDir(spec), "extracted");
34225
+ return join16(ghPackageDir(spec), "extracted");
34146
34226
  }
34147
34227
  var INSTALLED_META_FILE2 = ".aft-installed";
34148
34228
  function ghBinaryPath(spec, platform) {
34149
34229
  const ext = platform === "win32" ? ".exe" : "";
34150
- return join15(ghBinDir(spec), `${spec.binary}${ext}`);
34230
+ return join16(ghBinDir(spec), `${spec.binary}${ext}`);
34151
34231
  }
34152
34232
  function isGithubInstalled(spec, platform) {
34153
34233
  for (const candidate of ghBinaryCandidates(spec, platform)) {
34154
34234
  try {
34155
- if (statSync9(join15(ghBinDir(spec), candidate)).isFile())
34235
+ if (statSync9(join16(ghBinDir(spec), candidate)).isFile())
34156
34236
  return true;
34157
34237
  } catch {}
34158
34238
  }
@@ -34165,7 +34245,7 @@ function ghBinaryCandidates(spec, platform) {
34165
34245
  }
34166
34246
  function readGithubInstalledMetaIn(installDir) {
34167
34247
  try {
34168
- const path2 = join15(installDir, INSTALLED_META_FILE2);
34248
+ const path2 = join16(installDir, INSTALLED_META_FILE2);
34169
34249
  if (!statSync9(path2).isFile())
34170
34250
  return null;
34171
34251
  const parsed = JSON.parse(readFileSync11(path2, "utf8"));
@@ -34192,7 +34272,7 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
34192
34272
  binarySha256,
34193
34273
  ...archiveSha256 ? { archiveSha256 } : {}
34194
34274
  };
34195
- writeFileSync7(join15(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
34275
+ writeFileSync7(join16(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
34196
34276
  } catch (err) {
34197
34277
  warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
34198
34278
  }
@@ -34441,7 +34521,7 @@ function validateExtraction(stagingRoot) {
34441
34521
  throw new Error(`failed to read staging dir ${dir}: ${err}`);
34442
34522
  }
34443
34523
  for (const entry of entries) {
34444
- const full = join15(dir, entry);
34524
+ const full = join16(dir, entry);
34445
34525
  let lst;
34446
34526
  try {
34447
34527
  lst = lstatSync2(full);
@@ -34529,7 +34609,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
34529
34609
  }
34530
34610
  function quarantineCachedGithubInstall(spec, reason) {
34531
34611
  const packageDir = ghPackageDir(spec);
34532
- const dest = join15(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
34612
+ const dest = join16(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
34533
34613
  warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
34534
34614
  try {
34535
34615
  mkdirSync8(dirname6(dest), { recursive: true });
@@ -34542,7 +34622,7 @@ function quarantineCachedGithubInstall(spec, reason) {
34542
34622
  function validateCachedGithubInstall(spec, platform) {
34543
34623
  const packageDir = ghPackageDir(spec);
34544
34624
  const meta3 = readGithubInstalledMetaIn(packageDir);
34545
- const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join15(ghBinDir(spec), candidate)).find((candidate) => {
34625
+ const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join16(ghBinDir(spec), candidate)).find((candidate) => {
34546
34626
  try {
34547
34627
  return statSync9(candidate).isFile();
34548
34628
  } catch {
@@ -34620,7 +34700,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
34620
34700
  }
34621
34701
  const pkgDir = ghPackageDir(spec);
34622
34702
  const extractDir = ghExtractDir(spec);
34623
- const archivePath = join15(pkgDir, expected.name);
34703
+ const archivePath = join16(pkgDir, expected.name);
34624
34704
  log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
34625
34705
  try {
34626
34706
  await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
@@ -34660,8 +34740,8 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
34660
34740
  unlinkSync7(archivePath);
34661
34741
  } catch {}
34662
34742
  }
34663
- const innerBinaryPath = join15(extractDir, spec.binaryPathInArchive(platform, arch, version2));
34664
- if (!existsSync13(innerBinaryPath)) {
34743
+ const innerBinaryPath = join16(extractDir, spec.binaryPathInArchive(platform, arch, version2));
34744
+ if (!existsSync14(innerBinaryPath)) {
34665
34745
  error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
34666
34746
  return null;
34667
34747
  }
@@ -34745,7 +34825,7 @@ function runGithubAutoInstall(relevantServers, config2, fetchImpl = fetch) {
34745
34825
  if (!host) {
34746
34826
  for (const spec of GITHUB_LSP_TABLE) {
34747
34827
  try {
34748
- if (existsSync13(ghBinDir(spec))) {
34828
+ if (existsSync14(ghBinDir(spec))) {
34749
34829
  cachedBinDirs.push(ghBinDir(spec));
34750
34830
  }
34751
34831
  } catch {}
@@ -34972,6 +35052,17 @@ function sendFeatureAnnouncement(version2, features, footer, storageDir) {
34972
35052
 
34973
35053
  // src/bash-wait-detach.ts
34974
35054
  var BASH_TRANSPORT_TIMEOUT_MS = 30000;
35055
+ var BASH_WAIT_DETACH_MAGIC_KEYWORD = "&detach";
35056
+ var EMPTY_DETACH_MESSAGE = "(requested background detach)";
35057
+ function stripUserMessageDetachKeyword(messageText) {
35058
+ if (!messageText.includes(BASH_WAIT_DETACH_MAGIC_KEYWORD))
35059
+ return messageText;
35060
+ const stripped = messageText.replaceAll(BASH_WAIT_DETACH_MAGIC_KEYWORD, "").replace(/[ \t]{2,}/g, " ");
35061
+ return stripped.trim() === "" ? EMPTY_DETACH_MESSAGE : stripped;
35062
+ }
35063
+ function shouldDetachBashWaitOnUserMessage(config2, messageText) {
35064
+ return resolveBashConfig(config2).detach_on_user_message || messageText.includes(BASH_WAIT_DETACH_MAGIC_KEYWORD);
35065
+ }
34975
35066
  async function sendBashWaitDetach(bridge, sessionID) {
34976
35067
  const response = await bridge.send("bash_wait_detach", { session_id: sessionID }, { keepBridgeOnTimeout: true, transportTimeoutMs: BASH_TRANSPORT_TIMEOUT_MS });
34977
35068
  if (response.success === false) {
@@ -35763,8 +35854,9 @@ PDFs aren't supported on the Pi harness yet.`, response);
35763
35854
  parameters: HashlineEditParams,
35764
35855
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
35765
35856
  const bridge = bridgeFor(ctx, extCtx.cwd);
35857
+ const sessionId = resolveSessionId(extCtx);
35766
35858
  const rawArgs = { patch: params.patch };
35767
- const preflight = await callToolCall(bridge, "hashline_preflight", rawArgs, extCtx);
35859
+ const preflight = await callToolCallForSession(bridge, "hashline_preflight", rawArgs, sessionId, extCtx);
35768
35860
  if (preflight.success === false)
35769
35861
  throw toolErrorFromResponse("edit", preflight);
35770
35862
  for (const target of [
@@ -35775,10 +35867,12 @@ PDFs aren't supported on the Pi harness yet.`, response);
35775
35867
  restrictToProjectRoot: surface.restrictToProjectRoot
35776
35868
  });
35777
35869
  }
35778
- const preview = await callToolCall(bridge, "edit", rawArgs, extCtx, { preview: true });
35870
+ const preview = await callToolCallForSession(bridge, "edit", rawArgs, sessionId, extCtx, {
35871
+ preview: true
35872
+ });
35779
35873
  if (preview.success === false)
35780
35874
  throw toolErrorFromResponse("edit", preview);
35781
- const response = await callToolCall(bridge, "edit", rawArgs, extCtx);
35875
+ const response = await callToolCallForSession(bridge, "edit", rawArgs, sessionId, extCtx);
35782
35876
  if (response.success === false)
35783
35877
  throw toolErrorFromResponse("edit", response);
35784
35878
  return buildMutationResult(response);
@@ -36328,7 +36422,7 @@ var BashBaseParams = {
36328
36422
  description: "Human-readable description shown in UI logs. Helps users understand what the command does without reading shell syntax."
36329
36423
  })),
36330
36424
  wait: Type4.Optional(Type4.Boolean({
36331
- description: "When true, run in the foreground without auto-promoting and wait until the command finishes or reaches its timeout; if you send a new message, the wait detaches to background. Use only when you know the result is required before doing anything else."
36425
+ description: "When true, run in the foreground without auto-promoting and wait until the command finishes or reaches its timeout; a new user message detaches by default, while `bash.detach_on_user_message: false` keeps it blocking unless the message contains the literal `&detach`. The token is stripped before delivery; the rest of the message is preserved, and a token-only message becomes `(requested background detach)`. Use only when you know the result is required before doing anything else."
36332
36426
  })),
36333
36427
  sandbox: Type4.Optional(Type4.Literal("host", {
36334
36428
  description: "Request one-command approval to run unsandboxed on the host; use only when native sandboxing blocks required work, and note that it is a no-op when sandboxing is disabled."
@@ -36423,11 +36517,17 @@ ${ask.command ?? ""}
36423
36517
  Working directory:
36424
36518
  ${ask.cwd ?? ""}`;
36425
36519
  }
36426
- async function callBashWithPermissionLoop(bridge, params, extCtx, options) {
36520
+ function piPowerShellAskText(command) {
36521
+ return `PowerShell commands are conservatively approved one at a time because AFT's POSIX shell scanner cannot safely interpret PowerShell syntax.
36522
+
36523
+ Exact command:
36524
+ ${command}`;
36525
+ }
36526
+ async function callBashWithPermissionLoop(bridge, params, extCtx, options, bridgeCommand = "bash") {
36427
36527
  const granted = Array.isArray(params.permissions_granted) ? params.permissions_granted.filter((value) => typeof value === "string") : [];
36428
36528
  for (let round = 0;round < 8; round++) {
36429
36529
  try {
36430
- return await callBashBridge(bridge, "bash", { ...params, ...granted.length > 0 ? { permissions_granted: granted } : {} }, extCtx, options);
36530
+ return await callBashBridge(bridge, bridgeCommand, { ...params, ...granted.length > 0 ? { permissions_granted: granted } : {} }, extCtx, options);
36431
36531
  } catch (error53) {
36432
36532
  if (!(error53 instanceof BridgeError)) {
36433
36533
  if (error53 instanceof Error && error53.message.includes("permission_required")) {
@@ -36438,19 +36538,30 @@ async function callBashWithPermissionLoop(bridge, params, extCtx, options) {
36438
36538
  if (error53.code !== "permission_required")
36439
36539
  throw error53;
36440
36540
  const asks = Array.isArray(error53.response?.asks) ? error53.response.asks : [];
36441
- if (asks.length === 0 || asks.some((ask) => ask.kind !== "escalation")) {
36442
- throw new Error("Permission ask reached Pi adapter without a host escalation grant — this is a bug.");
36443
- }
36444
- if (!extCtx.hasUI || typeof extCtx.ui?.confirm !== "function") {
36445
- throw new BridgeError("Permission denied: host escalation approval requires an interactive UI.", "permission_denied");
36541
+ if (asks.length === 0 || !extCtx.hasUI || typeof extCtx.ui?.confirm !== "function") {
36542
+ throw new BridgeError("Permission denied: command approval requires an interactive UI.", "permission_denied");
36446
36543
  }
36447
36544
  for (const ask of asks) {
36448
- const approved = await extCtx.ui.confirm("Run command unsandboxed on host?", piEscalationAskText(ask), { signal: extCtx.signal });
36545
+ if (ask.kind === "escalation") {
36546
+ const approved2 = await extCtx.ui.confirm("Run command unsandboxed on host?", piEscalationAskText(ask), { signal: extCtx.signal });
36547
+ if (!approved2) {
36548
+ throw new BridgeError("Permission denied: unsandboxed host execution was denied.", "permission_denied");
36549
+ }
36550
+ if (ask.grant_id && !granted.includes(ask.grant_id))
36551
+ granted.push(ask.grant_id);
36552
+ continue;
36553
+ }
36554
+ if (bridgeCommand !== "powershell") {
36555
+ throw new Error("Permission ask reached Pi adapter without a host escalation grant — this is a bug.");
36556
+ }
36557
+ const approved = await extCtx.ui.confirm("Allow PowerShell command?", piPowerShellAskText(String(params.command ?? "")), { signal: extCtx.signal });
36449
36558
  if (!approved) {
36450
- throw new BridgeError("Permission denied: unsandboxed host execution was denied.", "permission_denied");
36559
+ throw new BridgeError("Permission denied: PowerShell command was denied.", "permission_denied");
36560
+ }
36561
+ for (const grant of [...ask.always ?? [], ...ask.patterns ?? []]) {
36562
+ if (!granted.includes(grant))
36563
+ granted.push(grant);
36451
36564
  }
36452
- if (ask.grant_id && !granted.includes(ask.grant_id))
36453
- granted.push(ask.grant_id);
36454
36565
  }
36455
36566
  }
36456
36567
  }
@@ -36477,23 +36588,27 @@ function getBashSpawnHook(pi) {
36477
36588
  }
36478
36589
  return api2.hooks?.bashSpawn;
36479
36590
  }
36480
- function registerBashTool(pi, ctx, aftSearchRegistered = false, registeredName = "bash", registerCompanions = true) {
36481
- const spawnHook = getBashSpawnHook(pi);
36591
+ function registerBashTool(pi, ctx, aftSearchRegistered = false, registeredName = "bash", registerCompanions = true, shell = "bash") {
36592
+ const isPowerShell = shell === "powershell";
36593
+ const spawnHook = isPowerShell ? undefined : getBashSpawnHook(pi);
36482
36594
  const readToolName = registeredName === "bash" ? "read" : "aft_read";
36483
36595
  const grepToolName = registeredName === "bash" ? "grep" : "aft_grep";
36484
36596
  const searchSteer = aftSearchRegistered ? `use \`aft_search\` (concepts, identifiers, regex, literals), \`${readToolName}\`, \`aft_outline\`, or \`aft_zoom\` instead` : `use the \`${grepToolName}\` tool, \`${readToolName}\`, \`aft_outline\`, or \`aft_zoom\` instead`;
36485
36597
  const bashCfg = resolveBashConfig(ctx.config);
36486
36598
  let hostFallbackActive = false;
36487
36599
  const compressionSentence = bashCfg.compress ? " Output is compressed by default; pass `compressed: false` for raw output. Piped commands run verbatim and show the pipeline's output; for AFT's test/build summary, run the runner without `| head`, `| tail`, or `| grep`." : "";
36488
- const tasksSentence = bashCfg.background ? ' Commands run in the foreground and return inline; `wait: true` blocks until a long command finishes instead of auto-promoting, but detaches to background if you send a new message — use it when you need the result before doing anything else; keep it off otherwise so auto-promote can remind you while you work. Use `background: true` yourself ONLY when you have other useful work to do while it runs; then `bash_watch` waits on the task (sync blocks until exit/pattern, async notifies) and `bash_status` peeks at it — never background a command and immediately `bash_watch` it (that wastes a turn for what foreground returns in one), and never loop `bash_status` to wait. `pty: true` runs interactive programs (REPLs, TUIs), implies background, and is driven with `bash_status({ output_mode: "screen" })` plus `bash_write`.' : " Commands run in the foreground to completion; `timeout` is the hard kill cap (default 30 minutes).";
36600
+ const detachSentence = bashCfg.detach_on_user_message ? "A new user message detaches this wait. Set `bash.detach_on_user_message: false` to keep it blocking; even then, a message containing the literal `&detach` forces detachment, and the token is stripped before delivery; the rest of the message is preserved, while a token-only message becomes `(requested background detach)`." : "Because `bash.detach_on_user_message` is false, a new user message leaves this wait blocking; include the literal `&detach` anywhere to force detachment, and the token is stripped before delivery; the rest of the message is preserved, while a token-only message becomes `(requested background detach)`.";
36601
+ const tasksSentence = bashCfg.background ? ` Commands run in the foreground and return inline; \`wait: true\` blocks until a long command finishes instead of auto-promoting; ${detachSentence} Use it when you need the result before doing anything else; keep it off otherwise so auto-promote can remind you while you work. Use \`background: true\` yourself ONLY when you have other useful work to do while it runs; then \`bash_watch\` waits on the task (sync blocks until exit/pattern, async notifies) and \`bash_status\` peeks at it — never background a command and immediately \`bash_watch\` it (that wastes a turn for what foreground returns in one), and never loop \`bash_status\` to wait. \`pty: true\` runs interactive programs (REPLs, TUIs), implies background, and is driven with \`bash_status({ output_mode: "screen" })\` plus \`bash_write\`.` : " Commands run in the foreground to completion; `timeout` is the hard kill cap (default 30 minutes).";
36489
36602
  pi.registerTool({
36490
36603
  name: registeredName,
36491
36604
  label: registeredName,
36492
- description: `Execute shell commands.${compressionSentence}${tasksSentence}
36605
+ description: isPowerShell ? `Execute PowerShell commands through AFT.${compressionSentence}${tasksSentence}
36606
+
36607
+ PowerShell syntax is not analyzed as POSIX shell. Each command requires explicit approval so syntax AFT cannot safely interpret is never auto-allowed.` : `Execute shell commands.${compressionSentence}${tasksSentence}
36493
36608
 
36494
36609
  DO NOT use bash for code search or code exploration. If you are about to run grep, rg, sed, awk, find, or cat through bash to locate or read code: STOP — ${searchSteer}.`,
36495
- promptSnippet: bashCfg.background ? "Run shell commands (timeout in milliseconds; supports workdir, background tasks, compressed output, PTY mode)" : "Run shell commands (timeout in milliseconds; supports workdir and compressed output)",
36496
- promptGuidelines: [
36610
+ promptSnippet: isPowerShell ? "Run PowerShell commands (timeout in milliseconds; supports workdir, background tasks, compressed output, PTY mode)" : bashCfg.background ? "Run shell commands (timeout in milliseconds; supports workdir, background tasks, compressed output, PTY mode)" : "Run shell commands (timeout in milliseconds; supports workdir and compressed output)",
36611
+ promptGuidelines: isPowerShell ? ["Use PowerShell syntax. Every command requires explicit approval."] : [
36497
36612
  `DO NOT use bash for code search or exploration — ${searchSteer}.`,
36498
36613
  "Set compressed: false when you need ANSI color codes in the output.",
36499
36614
  "Piped commands run verbatim and show the pipeline's output; run test/build tools without pipes when you need AFT's summary."
@@ -36552,7 +36667,8 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
36552
36667
  foreground_orchestrate: true,
36553
36668
  block_to_completion: blockToCompletion,
36554
36669
  wait: requestedWait,
36555
- sandbox: params.sandbox
36670
+ sandbox: params.sandbox,
36671
+ ...isPowerShell ? { shell: "powershell" } : {}
36556
36672
  }, extCtx, {
36557
36673
  transportTimeoutMs: orchestratedTransportTimeoutMs(blockToCompletion, requestedWait, effectiveTimeout, foregroundWaitMs),
36558
36674
  onProgress: ({ text }) => {
@@ -36560,9 +36676,9 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
36560
36676
  const displayText = truncateToVisualLines(streamed, 100);
36561
36677
  onUpdate?.(bashResult(displayText, { streaming: true }));
36562
36678
  }
36563
- });
36679
+ }, isPowerShell ? "powershell" : "bash");
36564
36680
  } catch (error53) {
36565
- if (!bashCfg2.host_fallback || !isBashTransportDeadError(error53))
36681
+ if (isPowerShell || !bashCfg2.host_fallback || !isBashTransportDeadError(error53))
36566
36682
  throw error53;
36567
36683
  if (rawRequestedBackground) {
36568
36684
  throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; background:true is unsupported.`);
@@ -36609,7 +36725,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
36609
36725
  task_id: taskId
36610
36726
  };
36611
36727
  const output = response.output ?? "";
36612
- return bashResult(usedHostFallback ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
36728
+ return bashResult(usedHostFallback || isPowerShell ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
36613
36729
  },
36614
36730
  renderCall(args, theme, context) {
36615
36731
  return renderBashCall(args?.command, args?.description, theme, context);
@@ -37622,25 +37738,39 @@ function formatPhase(entry) {
37622
37738
  return details.length > 0 ? `${entry.id} (${details.join("; ")})` : entry.id;
37623
37739
  }
37624
37740
  function renderInspectTerminal(terminal, serverText) {
37625
- const lines = [terminal.kind];
37626
37741
  if (terminal.kind === "FRESH") {
37627
- lines.push(`wait-stamp: ${terminal.waitStampText ?? "not supplied"}`);
37742
+ const lines = [
37743
+ terminal.kind,
37744
+ `wait-stamp: ${terminal.waitStampText ?? "not supplied"}`
37745
+ ];
37746
+ lines.push(terminal.phases.length > 0 ? `completed phases:
37747
+ ${terminal.phases.map((phase) => `- ${formatPhase(phase)}`).join(`
37748
+ `)}` : "completed phases: none");
37749
+ if (serverText?.trim())
37750
+ lines.push(serverText);
37751
+ return lines.join(`
37752
+ `);
37628
37753
  }
37629
37754
  if (terminal.kind === "PHASE-FAILED") {
37630
- if (terminal.failedPhase)
37631
- lines.push(`failed phase: ${formatPhase(terminal.failedPhase)}`);
37632
- lines.push(`failure reason: ${terminal.failureReason ?? "not supplied"}`);
37633
- if (terminal.failureDetail)
37634
- lines.push(`failure detail: ${terminal.failureDetail}`);
37755
+ const detail = compactTerminalField(terminal.failureDetail, "not supplied");
37756
+ const reason = compactTerminalField(terminal.failureReason, "not supplied");
37757
+ return [
37758
+ `inspect could not complete: ${detail} (${reason}).`,
37759
+ `Completed phases: ${terminal.phases.length}. Retry, or narrow with sections=...`
37760
+ ].join(`
37761
+ `);
37635
37762
  }
37636
- lines.push(terminal.phases.length > 0 ? `completed phases:
37637
- ${terminal.phases.map((phase) => `- ${formatPhase(phase)}`).join(`
37638
- `)}` : "completed phases: none");
37639
- if (serverText?.trim())
37640
- lines.push(serverText);
37641
- return lines.join(`
37763
+ const phaseLabel = terminal.phases.length === 1 ? "phase" : "phases";
37764
+ return [
37765
+ `inspect was interrupted before it could complete (after ${terminal.phases.length} completed ${phaseLabel}); no fresh snapshot was produced.`,
37766
+ "Retry is safe; retry inspect, or narrow with sections=..."
37767
+ ].join(`
37642
37768
  `);
37643
37769
  }
37770
+ function compactTerminalField(value, fallback) {
37771
+ const compact = value?.trim().replace(/\s+/g, " ");
37772
+ return compact || fallback;
37773
+ }
37644
37774
  function diagnosticsSummaryPart(summary) {
37645
37775
  const section = asRecord3(summary?.diagnostics);
37646
37776
  if (!section)
@@ -37762,9 +37892,19 @@ function renderInspectCall(args, theme, context) {
37762
37892
  function renderInspectResult(result, theme, context, options = { expanded: true }) {
37763
37893
  const payload = extractStructuredPayload(result);
37764
37894
  const terminal = parseInspectTerminal(payload);
37895
+ if (terminal) {
37896
+ const sections2 = [renderInspectTerminal(terminal, asString2(asRecord3(payload)?.text))];
37897
+ return collapsibleResult({
37898
+ summary: sections2[0]?.split(`
37899
+ `)[0] ?? "inspect",
37900
+ full: renderSections(sections2, context),
37901
+ expanded: options.expanded,
37902
+ context
37903
+ });
37904
+ }
37765
37905
  if (context.isError)
37766
37906
  return renderErrorResult(result, "inspect failed", theme, context);
37767
- const sections = terminal ? [renderInspectTerminal(terminal, asString2(asRecord3(payload)?.text))] : buildInspectSections(payload, theme);
37907
+ const sections = buildInspectSections(payload, theme);
37768
37908
  return collapsibleResult({
37769
37909
  summary: sections[0] ?? "inspect completed",
37770
37910
  full: renderSections(sections, context),
@@ -38429,7 +38569,7 @@ var SafetyParams = Type12.Object({
38429
38569
  })),
38430
38570
  name: Type12.Optional(Type12.String({ description: "Checkpoint name (required for checkpoint, restore)" })),
38431
38571
  files: Type12.Optional(Type12.Array(Type12.String(), {
38432
- description: "Specific files for checkpoint (optional, defaults to all tracked)"
38572
+ description: "Specific files for checkpoint (optional, defaults to all backup-tracked files; explicit files may be untracked or gitignored)"
38433
38573
  }))
38434
38574
  });
38435
38575
  function buildSafetySections(args, payload, theme) {
@@ -38474,14 +38614,16 @@ function buildSafetySections(args, payload, theme) {
38474
38614
  `${theme.fg("muted", "files")} ${asNumber2(response.file_count) ?? 0}`,
38475
38615
  skipped.length > 0 ? `${theme.fg("warning", "skipped")}
38476
38616
  ${skipped.map((entry) => ` ↳ ${shortenPath2(asString2(entry.file) ?? "(file)")}: ${asString2(entry.error) ?? "unknown error"}`).join(`
38477
- `)}` : theme.fg("muted", "No skipped files.")
38478
- ];
38617
+ `)}` : theme.fg("muted", "No skipped files."),
38618
+ asString2(response.durability)
38619
+ ].filter((section) => Boolean(section));
38479
38620
  }
38480
38621
  if (args.op === "restore") {
38481
38622
  return [
38482
38623
  `${theme.fg("success", "checkpoint restored")} ${theme.fg("accent", asString2(response.name) ?? args.name ?? "(checkpoint)")}`,
38483
- `${theme.fg("muted", "files")} ${asNumber2(response.file_count) ?? 0}`
38484
- ];
38624
+ `${theme.fg("muted", "files")} ${asNumber2(response.file_count) ?? 0}`,
38625
+ asString2(response.durability)
38626
+ ].filter((section) => Boolean(section));
38485
38627
  }
38486
38628
  const checkpoints = asRecords2(response.checkpoints);
38487
38629
  const sections = [
@@ -38489,6 +38631,9 @@ ${skipped.map((entry) => ` ↳ ${shortenPath2(asString2(entry.file) ?? "(file)"
38489
38631
  ];
38490
38632
  if (checkpoints.length === 0) {
38491
38633
  sections.push(theme.fg("muted", "No checkpoints saved."));
38634
+ const durability2 = asString2(response.durability);
38635
+ if (durability2)
38636
+ sections.push(theme.fg("muted", durability2));
38492
38637
  return sections;
38493
38638
  }
38494
38639
  sections.push(checkpoints.map((checkpoint, index) => {
@@ -38498,6 +38643,9 @@ ${skipped.map((entry) => ` ↳ ${shortenPath2(asString2(entry.file) ?? "(file)"
38498
38643
  return `${index + 1}. ${name} ${theme.fg("muted", `${count} file${count === 1 ? "" : "s"} · ${created}`)}`;
38499
38644
  }).join(`
38500
38645
  `));
38646
+ const durability = asString2(response.durability);
38647
+ if (durability)
38648
+ sections.push(theme.fg("muted", durability));
38501
38649
  return sections;
38502
38650
  }
38503
38651
  function renderSafetyCall(args, theme, context) {
@@ -38747,7 +38895,25 @@ function registerSemanticTool(pi, ctx) {
38747
38895
 
38748
38896
  // src/tool-registration.ts
38749
38897
  var ALL_ONLY_TOOLS = new Set(["aft_callgraph", "aft_delete", "aft_move", "aft_refactor"]);
38750
- function resolvePiToolSurface(config2) {
38898
+ function resolvePiPowerShellFallback(config2) {
38899
+ return resolveBashConfig(config2).powershell_tool;
38900
+ }
38901
+ function piPowerShellEnabledFromHost(pi) {
38902
+ const api2 = pi;
38903
+ if (typeof api2.getActiveTools !== "function" || typeof api2.getAllTools !== "function") {
38904
+ return;
38905
+ }
38906
+ try {
38907
+ const tool = api2.getAllTools().find((candidate) => candidate.name === "powershell");
38908
+ const source = tool?.sourceInfo?.source ?? tool?.source;
38909
+ if (!tool || source === undefined)
38910
+ return;
38911
+ return source === "builtin" && api2.getActiveTools().some((active) => (typeof active === "string" ? active : active.name) === "powershell");
38912
+ } catch {
38913
+ return;
38914
+ }
38915
+ }
38916
+ function resolvePiToolSurface(config2, pi) {
38751
38917
  const surface = config2.tool_surface ?? "recommended";
38752
38918
  const disabled = new Set(config2.disabled_tools ?? []);
38753
38919
  const hoistBuiltinTools = config2.hoist_builtin_tools !== false;
@@ -38755,10 +38921,12 @@ function resolvePiToolSurface(config2) {
38755
38921
  const builtinToolEnabled = (bareName) => ok(hoistBuiltinTools ? bareName : `aft_${bareName}`);
38756
38922
  const allOnly = (name) => ALL_ONLY_TOOLS.has(name) && ok(name);
38757
38923
  const restrictToProjectRoot = config2.restrict_to_project_root ?? false;
38924
+ const powershellEnabled = (pi ? piPowerShellEnabledFromHost(pi) : undefined) ?? resolvePiPowerShellFallback(config2);
38758
38925
  if (surface === "minimal") {
38759
38926
  return {
38760
38927
  hoistBuiltinTools,
38761
38928
  hoistBash: builtinToolEnabled("bash"),
38929
+ hoistPowershell: powershellEnabled && builtinToolEnabled("powershell"),
38762
38930
  hoistRead: false,
38763
38931
  hoistWrite: false,
38764
38932
  hoistEdit: false,
@@ -38782,6 +38950,7 @@ function resolvePiToolSurface(config2) {
38782
38950
  const base = {
38783
38951
  hoistBuiltinTools,
38784
38952
  hoistBash: builtinToolEnabled("bash"),
38953
+ hoistPowershell: powershellEnabled && builtinToolEnabled("powershell"),
38785
38954
  hoistRead: builtinToolEnabled("read"),
38786
38955
  hoistWrite: builtinToolEnabled("write"),
38787
38956
  hoistEdit: builtinToolEnabled("edit"),
@@ -38813,14 +38982,20 @@ function resolvePiToolSurface(config2) {
38813
38982
  return base;
38814
38983
  }
38815
38984
  function registerPiToolSurface(pi, ctx, surface) {
38816
- if (surface.hoistBash && resolveBashConfig(ctx.config).enabled) {
38985
+ const bashCfg = resolveBashConfig(ctx.config);
38986
+ const bashRegistered = surface.hoistBash && bashCfg.enabled;
38987
+ const powershellRegistered = surface.hoistPowershell && bashCfg.enabled;
38988
+ if (bashRegistered) {
38817
38989
  registerBashTool(pi, ctx, surface.semantic, surface.hoistBuiltinTools ? "bash" : "aft_bash", false);
38818
- registerBashCompanionTools(pi, ctx);
38819
38990
  }
38991
+ if (powershellRegistered) {
38992
+ registerBashTool(pi, ctx, surface.semantic, surface.hoistBuiltinTools ? "powershell" : "aft_powershell", false, "powershell");
38993
+ }
38994
+ if (bashRegistered || powershellRegistered)
38995
+ registerBashCompanionTools(pi, ctx);
38820
38996
  registerHoistedTools(pi, ctx, surface);
38821
- if (surface.outline || surface.zoom) {
38997
+ if (surface.outline || surface.zoom)
38822
38998
  registerReadingTools(pi, ctx, surface);
38823
- }
38824
38999
  if (surface.semantic)
38825
39000
  registerSemanticTool(pi, ctx);
38826
39001
  if (surface.inspect)
@@ -39003,7 +39178,7 @@ var PLUGIN_VERSION = (() => {
39003
39178
  return "0.0.0";
39004
39179
  }
39005
39180
  })();
39006
- var ANNOUNCEMENT_VERSION = "0.53.0";
39181
+ var ANNOUNCEMENT_VERSION = "0.54.0";
39007
39182
  var ANNOUNCEMENT_FEATURES = [
39008
39183
  "Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
39009
39184
  "aft_zoom handles real-world .jsonc: files with comment banners above the opening brace now resolve, and not-found errors point at the segment that actually failed (thanks @iceteaSA).",
@@ -39322,7 +39497,7 @@ ${lines}
39322
39497
  });
39323
39498
  }
39324
39499
  pool.setConfigureOverride("harness", "pi");
39325
- const surface = resolvePiToolSurface(config2);
39500
+ const surface = resolvePiToolSurface(config2, pi);
39326
39501
  const hashlineEditRegistered = config2.edit_mode === "hashline" && surface.hoistEdit;
39327
39502
  pool.setConfigureOverride("edit_slot_survives", hashlineEditRegistered);
39328
39503
  pool.setConfigureOverride("aft_search_registered", surface.semantic);
@@ -39370,6 +39545,17 @@ ${lines}
39370
39545
  sendFeatureAnnouncement(ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER, storageDir);
39371
39546
  }
39372
39547
  registerPiToolSurface(pi, ctx, surface);
39548
+ let powershellRegistered = surface.hoistPowershell && resolveBashConfig(config2).enabled;
39549
+ pi.on("session_start", () => {
39550
+ if (powershellRegistered)
39551
+ return;
39552
+ const liveSurface = resolvePiToolSurface(config2, pi);
39553
+ if (!liveSurface.hoistPowershell || !resolveBashConfig(config2).enabled)
39554
+ return;
39555
+ registerBashTool(pi, ctx, liveSurface.semantic, liveSurface.hoistBuiltinTools ? "powershell" : "aft_powershell", false, "powershell");
39556
+ registerBashCompanionTools(pi, ctx);
39557
+ powershellRegistered = true;
39558
+ });
39373
39559
  registerWorkflowHints(pi, config2, surface);
39374
39560
  registerStatusCommand(pi, ctx);
39375
39561
  pi.on("tool_result", async (event, extCtx) => {
@@ -39401,10 +39587,18 @@ ${lines}
39401
39587
  });
39402
39588
  }
39403
39589
  });
39404
- pi.on("input", (_event, extCtx) => {
39590
+ pi.on("input", (event, extCtx) => {
39405
39591
  const sessionId = resolveSessionId(extCtx);
39406
39592
  signalSyncWatchAbort(sessionId);
39407
- signalBashWaitDetachForProject(pool, extCtx.cwd, sessionId);
39593
+ const originalText = event.text;
39594
+ const transformedText = stripUserMessageDetachKeyword(originalText);
39595
+ const shouldDetach = shouldDetachBashWaitOnUserMessage(config2, originalText);
39596
+ if (shouldDetach) {
39597
+ signalBashWaitDetachForProject(pool, extCtx.cwd, sessionId);
39598
+ }
39599
+ if (transformedText !== originalText) {
39600
+ return { action: "transform", text: transformedText };
39601
+ }
39408
39602
  });
39409
39603
  const unregisterShutdownCleanup = registerShutdownCleanup(async () => {
39410
39604
  try {