@cortexkit/aft-pi 0.38.0 → 0.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7728,10 +7728,10 @@ var require_stringify = __commonJS((exports, module) => {
7728
7728
  replacer = null;
7729
7729
  indent = EMPTY;
7730
7730
  };
7731
- var join9 = (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;
7731
+ var join10 = (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;
7732
7732
  var join_content = (inside, value, gap) => {
7733
7733
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
7734
- return join9(comment, inside, gap);
7734
+ return join10(comment, inside, gap);
7735
7735
  };
7736
7736
  var stringify_string = (holder, key, value) => {
7737
7737
  const raw = get_raw_string_literal(holder, key);
@@ -7753,13 +7753,13 @@ var require_stringify = __commonJS((exports, module) => {
7753
7753
  if (i !== 0) {
7754
7754
  inside += COMMA;
7755
7755
  }
7756
- const before = join9(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
7756
+ const before = join10(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
7757
7757
  inside += before || LF + deeper_gap;
7758
7758
  inside += stringify(i, value, deeper_gap) || STR_NULL;
7759
7759
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
7760
7760
  after_comma = process_comments(value, AFTER(i), deeper_gap);
7761
7761
  }
7762
- inside += join9(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7762
+ inside += join10(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7763
7763
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
7764
7764
  };
7765
7765
  var object_stringify = (value, gap) => {
@@ -7780,13 +7780,13 @@ var require_stringify = __commonJS((exports, module) => {
7780
7780
  inside += COMMA;
7781
7781
  }
7782
7782
  first = false;
7783
- const before = join9(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
7783
+ const before = join10(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
7784
7784
  inside += before || LF + deeper_gap;
7785
7785
  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);
7786
7786
  after_comma = process_comments(value, AFTER(key), deeper_gap);
7787
7787
  };
7788
7788
  keys.forEach(iteratee);
7789
- inside += join9(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7789
+ inside += join10(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7790
7790
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
7791
7791
  };
7792
7792
  function stringify(key, holder, gap) {
@@ -11674,7 +11674,45 @@ function error(message, meta) {
11674
11674
  console.error(`[aft-bridge] ERROR: ${message}`);
11675
11675
  }
11676
11676
  }
11677
+ // ../aft-bridge/dist/bash-format.js
11678
+ function appendPipeStripNote(output, note) {
11679
+ return note ? `${output}
11680
+
11681
+ ${note}` : output;
11682
+ }
11683
+ function formatSeconds(ms) {
11684
+ return `${Number((ms / 1000).toFixed(1))}s`;
11685
+ }
11686
+ function formatForegroundResult(data) {
11687
+ const output = data.output_preview ?? "";
11688
+ const outputPath = data.output_path;
11689
+ const truncated = data.output_truncated === true;
11690
+ const status = data.status;
11691
+ const exit = data.exit_code;
11692
+ let rendered = output;
11693
+ if (truncated && outputPath) {
11694
+ rendered += `
11695
+ [output truncated; full output at ${outputPath}]`;
11696
+ }
11697
+ if (status === "timed_out") {
11698
+ rendered += `
11699
+ [command timed out]`;
11700
+ }
11701
+ if (typeof exit === "number" && exit !== 0) {
11702
+ rendered += `
11703
+ [exit code: ${exit}]`;
11704
+ }
11705
+ return rendered;
11706
+ }
11707
+ function isTerminalStatus(status) {
11708
+ return status === "completed" || status === "failed" || status === "killed" || status === "timed_out";
11709
+ }
11710
+ function sleep(ms) {
11711
+ return new Promise((resolve) => setTimeout(resolve, ms));
11712
+ }
11677
11713
  // ../aft-bridge/dist/bash-hints.js
11714
+ import * as os from "node:os";
11715
+ import * as path from "node:path";
11678
11716
  var CONFLICT_HINT = `
11679
11717
 
11680
11718
  [Hint] Use aft_conflicts to see all conflict regions across files in a single call.`;
@@ -11688,48 +11726,175 @@ function maybeAppendConflictsHint(output) {
11688
11726
  return output;
11689
11727
  return output + CONFLICT_HINT;
11690
11728
  }
11691
- function commandLeadsWithCodeSearch(command) {
11692
- const trimmed = command.trim();
11693
- if (!trimmed)
11694
- return false;
11695
- const afterCd = peelLeadingCdAnd(trimmed);
11696
- if (afterCd === null)
11697
- return false;
11698
- const firstStage = firstPipelineStage(afterCd);
11699
- if (firstStage === null)
11729
+ function commandInvokesCodeSearch(command) {
11730
+ const statements = splitTopLevelStatements(command);
11731
+ if (statements === null)
11700
11732
  return false;
11701
- const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
11702
- if (firstToken === null)
11703
- return false;
11704
- return firstToken.token === "grep" || firstToken.token === "rg";
11733
+ for (const statement of statements) {
11734
+ const firstStage = firstPipelineStage(statement);
11735
+ if (firstStage === null)
11736
+ continue;
11737
+ const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
11738
+ if (firstToken === null)
11739
+ continue;
11740
+ if (firstToken.token === "grep" || firstToken.token === "rg")
11741
+ return true;
11742
+ }
11743
+ return false;
11705
11744
  }
11706
- function maybeAppendGrepSearchHint(output, command, aftSearchRegistered) {
11745
+ function maybeAppendGrepSearchHint(output, command, aftSearchRegistered, projectRoot) {
11707
11746
  if (output === "")
11708
11747
  return output;
11709
- if (!commandLeadsWithCodeSearch(command))
11748
+ if (!commandInvokesCodeSearch(command))
11710
11749
  return output;
11711
11750
  if (output.includes(GREP_SEARCH_HINT_PREFIX))
11712
11751
  return output;
11752
+ if (shouldSuppressGrepSearchHint(command, projectRoot))
11753
+ return output;
11713
11754
  const hint = aftSearchRegistered ? GREP_SEARCH_AFT_SEARCH_HINT : GREP_SEARCH_GREP_HINT;
11714
11755
  return `${output}
11715
11756
 
11716
11757
  ${hint}`;
11717
11758
  }
11718
- function peelLeadingCdAnd(command) {
11719
- const first = readShellToken(command, skipSpaces(command, 0));
11720
- if (first === null)
11721
- return null;
11722
- if (first.token !== "cd")
11723
- return command;
11724
- const dir = readShellToken(command, skipSpaces(command, first.end));
11725
- if (dir === null)
11759
+ function shouldSuppressGrepSearchHint(command, projectRoot) {
11760
+ const root = projectRoot?.trim();
11761
+ if (!root)
11762
+ return false;
11763
+ const statements = splitTopLevelStatements(command);
11764
+ if (statements === null)
11765
+ return false;
11766
+ let sawCodeSearchStatement = false;
11767
+ for (const statement of statements) {
11768
+ const firstStage = firstPipelineStage(statement);
11769
+ if (firstStage === null)
11770
+ continue;
11771
+ const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
11772
+ if (firstToken === null)
11773
+ continue;
11774
+ if (firstToken.token !== "grep" && firstToken.token !== "rg")
11775
+ continue;
11776
+ sawCodeSearchStatement = true;
11777
+ const operands = collectPathOperands(firstStage, firstToken.end);
11778
+ if (operands.length === 0)
11779
+ return false;
11780
+ for (const operand of operands) {
11781
+ if (isPathInsideProject(root, operand))
11782
+ return false;
11783
+ }
11784
+ }
11785
+ return sawCodeSearchStatement;
11786
+ }
11787
+ function collectPathOperands(firstStage, startAfterCommand) {
11788
+ const operands = [];
11789
+ let index = skipSpaces(firstStage, startAfterCommand);
11790
+ while (index < firstStage.length) {
11791
+ const tokenResult = readShellToken(firstStage, index);
11792
+ if (tokenResult === null)
11793
+ break;
11794
+ const { token, end } = tokenResult;
11795
+ if (end <= index)
11796
+ break;
11797
+ index = skipSpaces(firstStage, end);
11798
+ if (token.startsWith("-"))
11799
+ continue;
11800
+ if (looksLikePathOperand(token))
11801
+ operands.push(token);
11802
+ }
11803
+ return operands;
11804
+ }
11805
+ function looksLikePathOperand(token) {
11806
+ return token.includes("/") || token.startsWith("~") || token.startsWith("./") || token.startsWith("../");
11807
+ }
11808
+ function expandTilde(target) {
11809
+ if (!target.startsWith("~"))
11810
+ return target;
11811
+ if (target === "~" || target.startsWith("~/")) {
11812
+ return path.join(os.homedir(), target.slice(1));
11813
+ }
11814
+ return target;
11815
+ }
11816
+ function resolvePathOperand(projectRoot, operand) {
11817
+ const expanded = expandTilde(operand);
11818
+ return path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(projectRoot, expanded);
11819
+ }
11820
+ function isPathInsideProject(projectRoot, operand) {
11821
+ const root = path.resolve(projectRoot);
11822
+ const resolved = resolvePathOperand(root, operand);
11823
+ const rel = path.relative(root, resolved);
11824
+ return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
11825
+ }
11826
+ function splitTopLevelStatements(command) {
11827
+ const statements = [];
11828
+ let start = 0;
11829
+ let quote = "none";
11830
+ let escaped = false;
11831
+ let inBacktick = false;
11832
+ let parenDepth = 0;
11833
+ for (let index = 0;index < command.length; index++) {
11834
+ const ch = command[index];
11835
+ if (escaped) {
11836
+ escaped = false;
11837
+ continue;
11838
+ }
11839
+ if (quote === "single") {
11840
+ if (ch === "'")
11841
+ quote = "none";
11842
+ continue;
11843
+ }
11844
+ if (quote === "double") {
11845
+ if (ch === "\\")
11846
+ escaped = true;
11847
+ else if (ch === '"')
11848
+ quote = "none";
11849
+ continue;
11850
+ }
11851
+ if (inBacktick) {
11852
+ if (ch === "`")
11853
+ inBacktick = false;
11854
+ continue;
11855
+ }
11856
+ if (ch === "\\") {
11857
+ escaped = true;
11858
+ continue;
11859
+ }
11860
+ if (ch === "'") {
11861
+ quote = "single";
11862
+ continue;
11863
+ }
11864
+ if (ch === '"') {
11865
+ quote = "double";
11866
+ continue;
11867
+ }
11868
+ if (ch === "`") {
11869
+ inBacktick = true;
11870
+ continue;
11871
+ }
11872
+ if (ch === "(") {
11873
+ parenDepth++;
11874
+ continue;
11875
+ }
11876
+ if (ch === ")") {
11877
+ if (parenDepth > 0)
11878
+ parenDepth--;
11879
+ continue;
11880
+ }
11881
+ if (parenDepth > 0)
11882
+ continue;
11883
+ const next = command[index + 1];
11884
+ if (ch === "&" && next === "&" || ch === "|" && next === "|") {
11885
+ statements.push(command.slice(start, index));
11886
+ index++;
11887
+ start = index + 1;
11888
+ } else if (ch === ";" || ch === `
11889
+ ` || ch === "&") {
11890
+ statements.push(command.slice(start, index));
11891
+ start = index + 1;
11892
+ }
11893
+ }
11894
+ if (quote !== "none" || inBacktick || escaped)
11726
11895
  return null;
11727
- if (!dir.token)
11728
- return command;
11729
- const afterDir = skipSpaces(command, dir.end);
11730
- if (!command.startsWith("&&", afterDir))
11731
- return command;
11732
- return command.slice(afterDir + 2).trim();
11896
+ statements.push(command.slice(start));
11897
+ return statements;
11733
11898
  }
11734
11899
  function firstPipelineStage(command) {
11735
11900
  let quote = "none";
@@ -11837,8 +12002,8 @@ function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
11837
12002
  }
11838
12003
  // ../aft-bridge/dist/bridge.js
11839
12004
  import { spawn } from "node:child_process";
11840
- import { homedir } from "node:os";
11841
- import { join } from "node:path";
12005
+ import { homedir as homedir2 } from "node:os";
12006
+ import { join as join2 } from "node:path";
11842
12007
  import { StringDecoder } from "node:string_decoder";
11843
12008
 
11844
12009
  // ../aft-bridge/dist/command-timeouts.js
@@ -12211,7 +12376,7 @@ class BinaryBridge {
12211
12376
  `;
12212
12377
  const keepBridgeOnTimeout = options?.keepBridgeOnTimeout === true;
12213
12378
  let requestSentAt = Date.now();
12214
- const response = await new Promise((resolve, reject) => {
12379
+ const response = await new Promise((resolve2, reject) => {
12215
12380
  const timer = setTimeout(() => {
12216
12381
  const entry = this.pending.get(id);
12217
12382
  if (!entry)
@@ -12246,7 +12411,7 @@ class BinaryBridge {
12246
12411
  entry.reject(new Error(`${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
12247
12412
  this.handleTimeout(requestSessionId);
12248
12413
  }, effectiveTimeoutMs);
12249
- this.pending.set(id, { resolve, reject, timer, onProgress: options?.onProgress, command });
12414
+ this.pending.set(id, { resolve: resolve2, reject, timer, onProgress: options?.onProgress, command });
12250
12415
  if (!this.process?.stdin?.writable) {
12251
12416
  this.pending.delete(id);
12252
12417
  clearTimeout(timer);
@@ -12344,15 +12509,15 @@ class BinaryBridge {
12344
12509
  if (this.process) {
12345
12510
  const proc = this.process;
12346
12511
  this.process = null;
12347
- return new Promise((resolve) => {
12512
+ return new Promise((resolve2) => {
12348
12513
  const forceKillTimer = setTimeout(() => {
12349
12514
  proc.kill("SIGKILL");
12350
- resolve();
12515
+ resolve2();
12351
12516
  }, 5000);
12352
12517
  proc.once("exit", () => {
12353
12518
  clearTimeout(forceKillTimer);
12354
12519
  this.logVia("Process exited during shutdown");
12355
- resolve();
12520
+ resolve2();
12356
12521
  });
12357
12522
  proc.kill("SIGTERM");
12358
12523
  });
@@ -12397,15 +12562,15 @@ class BinaryBridge {
12397
12562
  return;
12398
12563
  const proc = this.process;
12399
12564
  this.process = null;
12400
- await new Promise((resolve) => {
12565
+ await new Promise((resolve2) => {
12401
12566
  const forceKillTimer = setTimeout(() => {
12402
12567
  proc.kill("SIGKILL");
12403
- resolve();
12568
+ resolve2();
12404
12569
  }, 5000);
12405
12570
  proc.once("exit", () => {
12406
12571
  clearTimeout(forceKillTimer);
12407
12572
  this.logVia("Process exited during coordinated binary replacement");
12408
- resolve();
12573
+ resolve2();
12409
12574
  });
12410
12575
  proc.kill("SIGTERM");
12411
12576
  });
@@ -12432,7 +12597,7 @@ class BinaryBridge {
12432
12597
  })();
12433
12598
  const useFastembedBackend = semanticBackend === undefined || semanticBackend === "fastembed" || semanticBackend === "";
12434
12599
  const ortDir = typeof this.configOverrides._ort_dylib_dir === "string" && useFastembedBackend ? this.configOverrides._ort_dylib_dir : null;
12435
- const ortLibraryPath = ortDir == null ? null : join(ortDir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
12600
+ const ortLibraryPath = ortDir == null ? null : join2(ortDir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
12436
12601
  const envPath = process.platform === "win32" && ortDir ? `${ortDir};${process.env.PATH ?? ""}` : process.env.PATH;
12437
12602
  const env = {
12438
12603
  ...process.env,
@@ -12440,7 +12605,7 @@ class BinaryBridge {
12440
12605
  };
12441
12606
  this.logVia(`bridge.spawnProcess: useFastembedBackend=${useFastembedBackend}, ` + `parentORT=${process.env.ORT_DYLIB_PATH ?? "(unset)"}, ` + `ortLibraryPath=${ortLibraryPath ?? "(none)"}`);
12442
12607
  if (useFastembedBackend) {
12443
- env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join(this.configOverrides.storage_dir, "semantic", "models") : join(homedir() || "", ".cache", "fastembed"));
12608
+ 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"));
12444
12609
  if (process.env.ORT_DYLIB_PATH) {
12445
12610
  this.logVia(`ORT_DYLIB_PATH inherited from parent env: ${process.env.ORT_DYLIB_PATH}`);
12446
12611
  } else if (ortLibraryPath) {
@@ -12782,12 +12947,37 @@ function coerceStringArray(value) {
12782
12947
  }
12783
12948
  return [];
12784
12949
  }
12950
+ function coerceOptionalInt(v, paramName, min, max) {
12951
+ if (v === undefined || v === null || v === "")
12952
+ return;
12953
+ if (typeof v === "number" && (!Number.isFinite(v) || v === 0 && min > 0))
12954
+ return;
12955
+ const n = typeof v === "string" ? Number(v) : v;
12956
+ if (typeof n !== "number" || !Number.isInteger(n)) {
12957
+ throw new Error(`${paramName} must be an integer between ${min} and ${max}`);
12958
+ }
12959
+ if (n < min || n > max) {
12960
+ throw new Error(`${paramName} must be between ${min} and ${max}`);
12961
+ }
12962
+ return n;
12963
+ }
12964
+ function isEmptyParam(value) {
12965
+ if (value === undefined || value === null)
12966
+ return true;
12967
+ if (typeof value === "string")
12968
+ return value.length === 0;
12969
+ if (Array.isArray(value))
12970
+ return value.length === 0;
12971
+ if (typeof value === "object")
12972
+ return Object.keys(value).length === 0;
12973
+ return false;
12974
+ }
12785
12975
  // ../aft-bridge/dist/downloader.js
12786
12976
  import { spawnSync } from "node:child_process";
12787
12977
  import { createHash, randomUUID } from "node:crypto";
12788
12978
  import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
12789
- import { homedir as homedir2 } from "node:os";
12790
- import { join as join2 } from "node:path";
12979
+ import { homedir as homedir3 } from "node:os";
12980
+ import { join as join3 } from "node:path";
12791
12981
  import { Readable } from "node:stream";
12792
12982
  import { pipeline } from "node:stream/promises";
12793
12983
 
@@ -12844,11 +13034,11 @@ function isExpectedCachedBinary(binaryPath, tag) {
12844
13034
  function getCacheDir() {
12845
13035
  if (process.platform === "win32") {
12846
13036
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
12847
- const base2 = localAppData || join2(homedir2(), "AppData", "Local");
12848
- return join2(base2, "aft", "bin");
13037
+ const base2 = localAppData || join3(homedir3(), "AppData", "Local");
13038
+ return join3(base2, "aft", "bin");
12849
13039
  }
12850
- const base = process.env.XDG_CACHE_HOME || join2(homedir2(), ".cache");
12851
- return join2(base, "aft", "bin");
13040
+ const base = process.env.XDG_CACHE_HOME || join3(homedir3(), ".cache");
13041
+ return join3(base, "aft", "bin");
12852
13042
  }
12853
13043
  function getBinaryName() {
12854
13044
  return process.platform === "win32" ? "aft.exe" : "aft";
@@ -12856,7 +13046,7 @@ function getBinaryName() {
12856
13046
  function getCachedBinaryPath(version) {
12857
13047
  if (!version)
12858
13048
  return null;
12859
- const binaryPath = join2(getCacheDir(), version, getBinaryName());
13049
+ const binaryPath = join3(getCacheDir(), version, getBinaryName());
12860
13050
  return existsSync(binaryPath) ? binaryPath : null;
12861
13051
  }
12862
13052
  async function downloadBinary(version) {
@@ -12873,16 +13063,16 @@ async function downloadBinary(version) {
12873
13063
  return null;
12874
13064
  }
12875
13065
  const tag = rawTag.startsWith("v") ? rawTag : `v${rawTag}`;
12876
- const versionedCacheDir = join2(getCacheDir(), tag);
13066
+ const versionedCacheDir = join3(getCacheDir(), tag);
12877
13067
  const binaryName = getBinaryName();
12878
- const binaryPath = join2(versionedCacheDir, binaryName);
13068
+ const binaryPath = join3(versionedCacheDir, binaryName);
12879
13069
  if (existsSync(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
12880
13070
  return binaryPath;
12881
13071
  }
12882
13072
  const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
12883
13073
  const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
12884
13074
  log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
12885
- const lockPath = join2(versionedCacheDir, ".download.lock");
13075
+ const lockPath = join3(versionedCacheDir, ".download.lock");
12886
13076
  let releaseLock = null;
12887
13077
  let binaryController = null;
12888
13078
  let checksumController = null;
@@ -13034,7 +13224,7 @@ async function acquireDownloadLock(lockPath) {
13034
13224
  if (Date.now() - startedAt > DOWNLOAD_LOCK_TIMEOUT_MS) {
13035
13225
  throw new Error(`Timed out waiting for download lock: ${lockPath}`);
13036
13226
  }
13037
- await new Promise((resolve) => setTimeout(resolve, 100));
13227
+ await new Promise((resolve2) => setTimeout(resolve2, 100));
13038
13228
  }
13039
13229
  }
13040
13230
  }
@@ -13127,18 +13317,18 @@ function stripJsoncSymbols(value) {
13127
13317
  // ../aft-bridge/dist/migration.js
13128
13318
  import { spawnSync as spawnSync2 } from "node:child_process";
13129
13319
  import { existsSync as existsSync4, mkdirSync as mkdirSync4 } from "node:fs";
13130
- import { homedir as homedir4, tmpdir } from "node:os";
13131
- import { dirname as dirname2, join as join5 } from "node:path";
13320
+ import { homedir as homedir5, tmpdir } from "node:os";
13321
+ import { dirname as dirname2, join as join6 } from "node:path";
13132
13322
 
13133
13323
  // ../aft-bridge/dist/paths.js
13134
13324
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync } from "node:fs";
13135
- import { dirname, join as join3 } from "node:path";
13325
+ import { dirname, join as join4 } from "node:path";
13136
13326
  function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
13137
- return join3(storageRoot, harness, ...segments);
13327
+ return join4(storageRoot, harness, ...segments);
13138
13328
  }
13139
13329
  function repairRootScopedStorageFile(storageRoot, harness, fileName) {
13140
13330
  const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
13141
- const rootPath = join3(storageRoot, fileName);
13331
+ const rootPath = join4(storageRoot, fileName);
13142
13332
  if (existsSync2(harnessPath) || !existsSync2(rootPath))
13143
13333
  return harnessPath;
13144
13334
  try {
@@ -13184,8 +13374,8 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
13184
13374
  import { execSync } from "node:child_process";
13185
13375
  import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
13186
13376
  import { createRequire as createRequire2 } from "node:module";
13187
- import { homedir as homedir3 } from "node:os";
13188
- import { join as join4 } from "node:path";
13377
+ import { homedir as homedir4 } from "node:os";
13378
+ import { join as join5 } from "node:path";
13189
13379
  var ensureBinaryForResolver = ensureBinary;
13190
13380
  function copyToVersionedCache(npmBinaryPath, knownVersion) {
13191
13381
  try {
@@ -13194,9 +13384,9 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
13194
13384
  return null;
13195
13385
  const tag = version.startsWith("v") ? version : `v${version}`;
13196
13386
  const cacheDir = getCacheDir();
13197
- const versionedDir = join4(cacheDir, tag);
13387
+ const versionedDir = join5(cacheDir, tag);
13198
13388
  const ext = process.platform === "win32" ? ".exe" : "";
13199
- const cachedPath = join4(versionedDir, `aft${ext}`);
13389
+ const cachedPath = join5(versionedDir, `aft${ext}`);
13200
13390
  if (existsSync3(cachedPath)) {
13201
13391
  const cachedVersion = readBinaryVersion(cachedPath);
13202
13392
  if (cachedVersion === version)
@@ -13226,18 +13416,18 @@ function normalizeBareVersion(version) {
13226
13416
  return version.startsWith("v") ? version.slice(1) : version;
13227
13417
  }
13228
13418
  function homeDirFromEnv(env) {
13229
- return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir3();
13419
+ return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir4();
13230
13420
  }
13231
13421
  function cacheDirFromEnv(env) {
13232
13422
  if (process.platform === "win32") {
13233
- const base2 = env.LOCALAPPDATA || env.APPDATA || join4(homeDirFromEnv(env), "AppData", "Local");
13234
- return join4(base2, "aft", "bin");
13423
+ const base2 = env.LOCALAPPDATA || env.APPDATA || join5(homeDirFromEnv(env), "AppData", "Local");
13424
+ return join5(base2, "aft", "bin");
13235
13425
  }
13236
- const base = env.XDG_CACHE_HOME || join4(homeDirFromEnv(env), ".cache");
13237
- return join4(base, "aft", "bin");
13426
+ const base = env.XDG_CACHE_HOME || join5(homeDirFromEnv(env), ".cache");
13427
+ return join5(base, "aft", "bin");
13238
13428
  }
13239
13429
  function cachedBinaryPathFromEnv(version, env, ext) {
13240
- const binaryPath = join4(cacheDirFromEnv(env), version, `aft${ext}`);
13430
+ const binaryPath = join5(cacheDirFromEnv(env), version, `aft${ext}`);
13241
13431
  return existsSync3(binaryPath) ? binaryPath : null;
13242
13432
  }
13243
13433
  function isExpectedCachedBinary2(binaryPath, expectedVersion) {
@@ -13356,7 +13546,7 @@ function findBinarySync(expectedVersion) {
13356
13546
  return usable;
13357
13547
  }
13358
13548
  } catch {}
13359
- const cargoPath = join4(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
13549
+ const cargoPath = join5(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
13360
13550
  if (existsSync3(cargoPath)) {
13361
13551
  const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
13362
13552
  if (usable)
@@ -13402,22 +13592,22 @@ function dataHome() {
13402
13592
  if (process.env.XDG_DATA_HOME)
13403
13593
  return process.env.XDG_DATA_HOME;
13404
13594
  if (process.platform === "win32") {
13405
- return process.env.LOCALAPPDATA || process.env.APPDATA || join5(homeDir(), "AppData", "Local");
13595
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join6(homeDir(), "AppData", "Local");
13406
13596
  }
13407
- return join5(homeDir(), ".local", "share");
13597
+ return join6(homeDir(), ".local", "share");
13408
13598
  }
13409
13599
  function homeDir() {
13410
13600
  if (process.platform === "win32")
13411
- return process.env.USERPROFILE || process.env.HOME || homedir4();
13412
- return process.env.HOME || homedir4();
13601
+ return process.env.USERPROFILE || process.env.HOME || homedir5();
13602
+ return process.env.HOME || homedir5();
13413
13603
  }
13414
13604
  function resolveLegacyStorageRoot(harness) {
13415
13605
  if (harness === "pi")
13416
- return join5(homeDir(), ".pi", "agent", "aft");
13417
- return join5(dataHome(), "opencode", "storage", "plugin", "aft");
13606
+ return join6(homeDir(), ".pi", "agent", "aft");
13607
+ return join6(dataHome(), "opencode", "storage", "plugin", "aft");
13418
13608
  }
13419
13609
  function resolveCortexKitStorageRoot() {
13420
- return join5(dataHome(), "cortexkit", "aft");
13610
+ return join6(dataHome(), "cortexkit", "aft");
13421
13611
  }
13422
13612
  function tail(value) {
13423
13613
  if (!value)
@@ -13431,12 +13621,12 @@ function spawnErrorLabel(error2) {
13431
13621
  return [code, error2.message].filter(Boolean).join(": ");
13432
13622
  }
13433
13623
  function migrationLogPath(newRoot, harness, logger) {
13434
- const desired = join5(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
13624
+ const desired = join6(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
13435
13625
  try {
13436
13626
  mkdirSync4(dirname2(desired), { recursive: true });
13437
13627
  return desired;
13438
13628
  } catch (err) {
13439
- const fallback = join5(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
13629
+ const fallback = join6(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
13440
13630
  logger?.warn?.(`Failed to create AFT migration log directory ${dirname2(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
13441
13631
  return fallback;
13442
13632
  }
@@ -13499,13 +13689,13 @@ async function ensureStorageMigrated(opts) {
13499
13689
  }
13500
13690
  // ../aft-bridge/dist/npm-resolver.js
13501
13691
  import { readdirSync, statSync as statSync2 } from "node:fs";
13502
- import { homedir as homedir5 } from "node:os";
13503
- import { delimiter, dirname as dirname3, isAbsolute, join as join6 } from "node:path";
13692
+ import { homedir as homedir6 } from "node:os";
13693
+ import { delimiter, dirname as dirname3, isAbsolute as isAbsolute2, join as join7 } from "node:path";
13504
13694
  function defaultDeps() {
13505
13695
  return {
13506
13696
  platform: process.platform,
13507
13697
  env: process.env,
13508
- home: homedir5(),
13698
+ home: homedir6(),
13509
13699
  execPath: process.execPath
13510
13700
  };
13511
13701
  }
@@ -13524,16 +13714,16 @@ function npmFromPath(deps) {
13524
13714
  const raw = deps.env.PATH ?? deps.env.Path ?? "";
13525
13715
  for (const entry of raw.split(delimiter)) {
13526
13716
  const dir = entry.trim().replace(/^"|"$/g, "");
13527
- if (!dir || !isAbsolute(dir))
13717
+ if (!dir || !isAbsolute2(dir))
13528
13718
  continue;
13529
- if (isFile(join6(dir, name)))
13719
+ if (isFile(join7(dir, name)))
13530
13720
  return dir;
13531
13721
  }
13532
13722
  return null;
13533
13723
  }
13534
13724
  function npmAdjacentToNode(deps) {
13535
13725
  const dir = dirname3(deps.execPath);
13536
- return isFile(join6(dir, npmBinaryName(deps.platform))) ? dir : null;
13726
+ return isFile(join7(dir, npmBinaryName(deps.platform))) ? dir : null;
13537
13727
  }
13538
13728
  function highestVersionedNodeBin(installsDir, name) {
13539
13729
  let entries;
@@ -13542,8 +13732,8 @@ function highestVersionedNodeBin(installsDir, name) {
13542
13732
  } catch {
13543
13733
  return null;
13544
13734
  }
13545
- const candidates = entries.filter((v) => isFile(join6(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
13546
- return candidates.length > 0 ? join6(installsDir, candidates[0], "bin") : null;
13735
+ const candidates = entries.filter((v) => isFile(join7(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
13736
+ return candidates.length > 0 ? join7(installsDir, candidates[0], "bin") : null;
13547
13737
  }
13548
13738
  function compareVersionsDesc(a, b) {
13549
13739
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -13568,22 +13758,22 @@ function wellKnownNpmDirs(deps) {
13568
13758
  const programFiles = env.ProgramFiles || "C:\\Program Files";
13569
13759
  const appData = env.APPDATA;
13570
13760
  const localAppData = env.LOCALAPPDATA;
13571
- push(join6(programFiles, "nodejs"));
13761
+ push(join7(programFiles, "nodejs"));
13572
13762
  if (appData)
13573
- push(join6(appData, "npm"));
13763
+ push(join7(appData, "npm"));
13574
13764
  if (localAppData)
13575
- push(join6(localAppData, "Volta", "bin"));
13765
+ push(join7(localAppData, "Volta", "bin"));
13576
13766
  if (env.NVM_SYMLINK)
13577
13767
  push(env.NVM_SYMLINK);
13578
13768
  } else {
13579
13769
  if (env.NVM_BIN)
13580
13770
  push(env.NVM_BIN);
13581
- push(highestVersionedNodeBin(join6(home, ".nvm", "versions", "node"), name));
13582
- push(highestVersionedNodeBin(join6(home, ".local", "share", "mise", "installs", "node"), name));
13583
- push(highestVersionedNodeBin(join6(home, ".asdf", "installs", "nodejs"), name));
13584
- push(join6(home, ".volta", "bin"));
13585
- push(join6(home, ".asdf", "shims"));
13586
- const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join6(home, ".local", "bin")]);
13771
+ push(highestVersionedNodeBin(join7(home, ".nvm", "versions", "node"), name));
13772
+ push(highestVersionedNodeBin(join7(home, ".local", "share", "mise", "installs", "node"), name));
13773
+ push(highestVersionedNodeBin(join7(home, ".asdf", "installs", "nodejs"), name));
13774
+ push(join7(home, ".volta", "bin"));
13775
+ push(join7(home, ".asdf", "shims"));
13776
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join7(home, ".local", "bin")]);
13587
13777
  for (const dir of systemDirs)
13588
13778
  push(dir);
13589
13779
  }
@@ -13593,12 +13783,12 @@ function resolveNpm(deps = defaultDeps()) {
13593
13783
  const name = npmBinaryName(deps.platform);
13594
13784
  const onPath = npmFromPath(deps);
13595
13785
  if (onPath)
13596
- return { command: join6(onPath, name), binDir: onPath };
13786
+ return { command: join7(onPath, name), binDir: onPath };
13597
13787
  const adjacent = npmAdjacentToNode(deps);
13598
13788
  if (adjacent)
13599
- return { command: join6(adjacent, name), binDir: adjacent };
13789
+ return { command: join7(adjacent, name), binDir: adjacent };
13600
13790
  for (const dir of wellKnownNpmDirs(deps)) {
13601
- const candidate = join6(dir, name);
13791
+ const candidate = join7(dir, name);
13602
13792
  if (isFile(candidate))
13603
13793
  return { command: candidate, binDir: dir };
13604
13794
  }
@@ -13615,7 +13805,7 @@ function npmSpawnEnv(resolved, baseEnv = process.env) {
13615
13805
  import { execFileSync } from "node:child_process";
13616
13806
  import { createHash as createHash2 } from "node:crypto";
13617
13807
  import { chmodSync as chmodSync3, closeSync as closeSync3, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync5, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync3, readlinkSync, realpathSync, rmSync as rmSync2, statSync as statSync3, symlinkSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
13618
- import { basename, dirname as dirname4, isAbsolute as isAbsolute2, join as join7, relative, resolve, win32 } from "node:path";
13808
+ import { basename, dirname as dirname4, isAbsolute as isAbsolute3, join as join8, relative as relative2, resolve as resolve2, win32 } from "node:path";
13619
13809
  import { Readable as Readable2 } from "node:stream";
13620
13810
  import { pipeline as pipeline2 } from "node:stream/promises";
13621
13811
  var ORT_VERSION = "1.24.4";
@@ -13678,10 +13868,10 @@ function getManualInstallHint() {
13678
13868
  }
13679
13869
  async function ensureOnnxRuntime(storageDir) {
13680
13870
  const info = getPlatformInfo();
13681
- const ortVersionDir = join7(storageDir, "onnxruntime", ORT_VERSION);
13871
+ const ortVersionDir = join8(storageDir, "onnxruntime", ORT_VERSION);
13682
13872
  const libName = info?.libName ?? "libonnxruntime.dylib";
13683
13873
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
13684
- const libPath = join7(resolvedOrtDir, libName);
13874
+ const libPath = join8(resolvedOrtDir, libName);
13685
13875
  if (existsSync5(libPath)) {
13686
13876
  const meta = readOnnxInstalledMeta(ortVersionDir);
13687
13877
  if (meta?.sha256) {
@@ -13711,9 +13901,9 @@ async function ensureOnnxRuntime(storageDir) {
13711
13901
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
13712
13902
  return null;
13713
13903
  }
13714
- const onnxBaseDir = join7(storageDir, "onnxruntime");
13904
+ const onnxBaseDir = join8(storageDir, "onnxruntime");
13715
13905
  mkdirSync5(onnxBaseDir, { recursive: true });
13716
- const lockPath = join7(onnxBaseDir, ONNX_LOCK_FILE);
13906
+ const lockPath = join8(onnxBaseDir, ONNX_LOCK_FILE);
13717
13907
  cleanupAbandonedStagingDirs(onnxBaseDir);
13718
13908
  if (!acquireLock(lockPath)) {
13719
13909
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -13732,7 +13922,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
13732
13922
  for (const entry of entries) {
13733
13923
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
13734
13924
  continue;
13735
- const stagingDir = join7(onnxBaseDir, entry);
13925
+ const stagingDir = join8(onnxBaseDir, entry);
13736
13926
  const parts = entry.split(".");
13737
13927
  const pidStr = parts[parts.length - 2];
13738
13928
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -13769,7 +13959,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
13769
13959
  }
13770
13960
  function cleanupIncompleteTargetIfUnowned(ortDir) {
13771
13961
  try {
13772
- if (existsSync5(ortDir) && !existsSync5(join7(ortDir, ONNX_INSTALLED_META_FILE))) {
13962
+ if (existsSync5(ortDir) && !existsSync5(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
13773
13963
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
13774
13964
  rmSync2(ortDir, { recursive: true, force: true });
13775
13965
  }
@@ -13797,8 +13987,8 @@ function parseOnnxVersionFromDirectoryPath(value) {
13797
13987
  return null;
13798
13988
  }
13799
13989
  function isPathInsideRoot(root, candidate) {
13800
- const rel = relative(root, candidate);
13801
- return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute2(rel) && !win32.isAbsolute(rel);
13990
+ const rel = relative2(root, candidate);
13991
+ return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute3(rel) && !win32.isAbsolute(rel);
13802
13992
  }
13803
13993
  function detectOnnxVersion(libDir, libName) {
13804
13994
  try {
@@ -13813,7 +14003,7 @@ function detectOnnxVersion(libDir, libName) {
13813
14003
  if (version)
13814
14004
  return version;
13815
14005
  }
13816
- const base = join7(libDir, libName);
14006
+ const base = join8(libDir, libName);
13817
14007
  if (existsSync5(base)) {
13818
14008
  try {
13819
14009
  const real = realpathSync(base);
@@ -13849,7 +14039,7 @@ function pathEntriesForPlatform() {
13849
14039
  return pathEnvValue().split(delimiter2).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
13850
14040
  if (!entry || entry === "." || entry.includes("\x00"))
13851
14041
  return false;
13852
- return isAbsolute2(entry) || win32.isAbsolute(entry);
14042
+ return isAbsolute3(entry) || win32.isAbsolute(entry);
13853
14043
  });
13854
14044
  }
13855
14045
  function directoryContainsLibrary(dir, libName) {
@@ -13865,10 +14055,10 @@ function directoryContainsLibrary(dir, libName) {
13865
14055
  }
13866
14056
  }
13867
14057
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
13868
- if (existsSync5(join7(ortVersionDir, libName)))
14058
+ if (existsSync5(join8(ortVersionDir, libName)))
13869
14059
  return ortVersionDir;
13870
- const libSubdir = join7(ortVersionDir, "lib");
13871
- if (existsSync5(join7(libSubdir, libName)))
14060
+ const libSubdir = join8(ortVersionDir, "lib");
14061
+ if (existsSync5(join8(libSubdir, libName)))
13872
14062
  return libSubdir;
13873
14063
  return ortVersionDir;
13874
14064
  }
@@ -13883,12 +14073,12 @@ function findSystemOnnxRuntime(libName) {
13883
14073
  } else if (process.platform === "win32") {
13884
14074
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
13885
14075
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
13886
- searchPaths.push(join7(programFiles, "onnxruntime", "lib"), join7(programFiles, "Microsoft ONNX Runtime", "lib"), join7(programFiles, "Microsoft Machine Learning", "lib"), join7(programFilesX86, "onnxruntime", "lib"), ...(() => {
14076
+ searchPaths.push(join8(programFiles, "onnxruntime", "lib"), join8(programFiles, "Microsoft ONNX Runtime", "lib"), join8(programFiles, "Microsoft Machine Learning", "lib"), join8(programFilesX86, "onnxruntime", "lib"), ...(() => {
13887
14077
  const nugetPaths = [];
13888
14078
  const userProfile = process.env.USERPROFILE ?? "";
13889
14079
  if (!userProfile)
13890
14080
  return nugetPaths;
13891
- const nugetPackageDir = join7(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
14081
+ const nugetPackageDir = join8(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
13892
14082
  if (!existsSync5(nugetPackageDir))
13893
14083
  return nugetPaths;
13894
14084
  try {
@@ -13897,7 +14087,7 @@ function findSystemOnnxRuntime(libName) {
13897
14087
  continue;
13898
14088
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
13899
14089
  continue;
13900
- nugetPaths.push(join7(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join7(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
14090
+ nugetPaths.push(join8(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join8(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
13901
14091
  }
13902
14092
  } catch (err) {
13903
14093
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -13909,7 +14099,7 @@ function findSystemOnnxRuntime(libName) {
13909
14099
  const normalizeCase = process.platform === "win32" || process.platform === "darwin";
13910
14100
  const seen = new Set;
13911
14101
  const uniquePaths = searchPaths.filter((p) => {
13912
- let key = resolve(p).replace(/[/\\]+$/, "");
14102
+ let key = resolve2(p).replace(/[/\\]+$/, "");
13913
14103
  if (normalizeCase)
13914
14104
  key = key.toLowerCase();
13915
14105
  if (seen.has(key))
@@ -13919,7 +14109,7 @@ function findSystemOnnxRuntime(libName) {
13919
14109
  });
13920
14110
  const unknownVersionPaths = [];
13921
14111
  for (const dir of uniquePaths) {
13922
- const libPath = join7(dir, libName);
14112
+ const libPath = join8(dir, libName);
13923
14113
  if (process.platform === "win32") {
13924
14114
  if (!directoryContainsLibrary(dir, libName))
13925
14115
  continue;
@@ -13985,19 +14175,19 @@ function validateExtractedTree(stagingRoot) {
13985
14175
  const walk = (dir) => {
13986
14176
  const entries = readdirSync2(dir);
13987
14177
  for (const entry of entries) {
13988
- const fullPath = join7(dir, entry);
14178
+ const fullPath = join8(dir, entry);
13989
14179
  const lst = lstatSync(fullPath);
13990
14180
  if (lst.isSymbolicLink()) {
13991
14181
  const linkTarget = readlinkSync(fullPath);
13992
- const resolvedTarget = resolve(dirname4(fullPath), linkTarget);
13993
- const rel2 = relative(realRoot, resolvedTarget);
13994
- if (rel2.startsWith("..") || isAbsolute2(rel2) || win32.isAbsolute(rel2)) {
14182
+ const resolvedTarget = resolve2(dirname4(fullPath), linkTarget);
14183
+ const rel2 = relative2(realRoot, resolvedTarget);
14184
+ if (rel2.startsWith("..") || isAbsolute3(rel2) || win32.isAbsolute(rel2)) {
13995
14185
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
13996
14186
  }
13997
14187
  continue;
13998
14188
  }
13999
- const rel = relative(realRoot, fullPath);
14000
- if (rel.startsWith("..") || isAbsolute2(rel) || win32.isAbsolute(rel)) {
14189
+ const rel = relative2(realRoot, fullPath);
14190
+ if (rel.startsWith("..") || isAbsolute3(rel) || win32.isAbsolute(rel)) {
14001
14191
  throw new Error(`extracted entry ${fullPath} escapes staging root`);
14002
14192
  }
14003
14193
  if (lst.isDirectory()) {
@@ -14020,7 +14210,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14020
14210
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
14021
14211
  try {
14022
14212
  mkdirSync5(tmpDir, { recursive: true });
14023
- const archivePath = join7(tmpDir, `onnxruntime.${info.archiveType}`);
14213
+ const archivePath = join8(tmpDir, `onnxruntime.${info.archiveType}`);
14024
14214
  await downloadFileWithCap(url, archivePath);
14025
14215
  const archiveSha256 = sha256File(archivePath);
14026
14216
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
@@ -14036,7 +14226,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14036
14226
  unlinkSync3(archivePath);
14037
14227
  } catch {}
14038
14228
  validateExtractedTree(tmpDir);
14039
- const extractedDir = join7(tmpDir, info.assetName, "lib");
14229
+ const extractedDir = join8(tmpDir, info.assetName, "lib");
14040
14230
  if (!existsSync5(extractedDir)) {
14041
14231
  throw new Error(`Expected directory not found: ${extractedDir}`);
14042
14232
  }
@@ -14045,7 +14235,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14045
14235
  const realFiles = [];
14046
14236
  const symlinks = [];
14047
14237
  for (const libFile of libFiles) {
14048
- const src = join7(extractedDir, libFile);
14238
+ const src = join8(extractedDir, libFile);
14049
14239
  try {
14050
14240
  const stat = lstatSync(src);
14051
14241
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
@@ -14060,7 +14250,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14060
14250
  }
14061
14251
  }
14062
14252
  copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
14063
- const libPath = join7(targetDir, info.libName);
14253
+ const libPath = join8(targetDir, info.libName);
14064
14254
  let libHash = null;
14065
14255
  try {
14066
14256
  libHash = sha256File(libPath);
@@ -14085,8 +14275,8 @@ async function downloadOnnxRuntime(info, targetDir) {
14085
14275
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
14086
14276
  const requiredLibs = new Set([info.libName]);
14087
14277
  for (const libFile of realFiles) {
14088
- const src = join7(extractedDir, libFile);
14089
- const dst = join7(targetDir, libFile);
14278
+ const src = join8(extractedDir, libFile);
14279
+ const dst = join8(targetDir, libFile);
14090
14280
  try {
14091
14281
  copyFile(src, dst);
14092
14282
  if (process.platform !== "win32") {
@@ -14102,12 +14292,12 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
14102
14292
  }
14103
14293
  const targetRoot = realpathSync(targetDir);
14104
14294
  for (const link of symlinks) {
14105
- const dst = join7(targetDir, link.name);
14295
+ const dst = join8(targetDir, link.name);
14106
14296
  try {
14107
14297
  unlinkSync3(dst);
14108
14298
  } catch {}
14109
- const dstForContainment = join7(targetRoot, link.name);
14110
- const resolvedTarget = resolve(dirname4(dstForContainment), link.target);
14299
+ const dstForContainment = join8(targetRoot, link.name);
14300
+ const resolvedTarget = resolve2(dirname4(dstForContainment), link.target);
14111
14301
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
14112
14302
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
14113
14303
  if (requiredLibs.has(link.name)) {
@@ -14127,7 +14317,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
14127
14317
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
14128
14318
  }
14129
14319
  }
14130
- const requiredPath = join7(targetDir, info.libName);
14320
+ const requiredPath = join8(targetDir, info.libName);
14131
14321
  if (!existsSync5(requiredPath)) {
14132
14322
  rmSync2(targetDir, { recursive: true, force: true });
14133
14323
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
@@ -14154,17 +14344,17 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
14154
14344
  ...sha256 ? { sha256 } : {},
14155
14345
  archiveSha256
14156
14346
  };
14157
- writeFileSync2(join7(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
14347
+ writeFileSync2(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
14158
14348
  } catch (err) {
14159
14349
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
14160
14350
  }
14161
14351
  }
14162
14352
  function readOnnxInstalledMeta(installDir) {
14163
- const path = join7(installDir, ONNX_INSTALLED_META_FILE);
14353
+ const path2 = join8(installDir, ONNX_INSTALLED_META_FILE);
14164
14354
  try {
14165
- if (!statSync3(path).isFile())
14355
+ if (!statSync3(path2).isFile())
14166
14356
  return null;
14167
- const raw = readFileSync3(path, "utf8");
14357
+ const raw = readFileSync3(path2, "utf8");
14168
14358
  const parsed = JSON.parse(raw);
14169
14359
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
14170
14360
  return null;
@@ -14178,9 +14368,9 @@ function readOnnxInstalledMeta(installDir) {
14178
14368
  return null;
14179
14369
  }
14180
14370
  }
14181
- function sha256File(path) {
14371
+ function sha256File(path2) {
14182
14372
  const hash = createHash2("sha256");
14183
- hash.update(readFileSync3(path));
14373
+ hash.update(readFileSync3(path2));
14184
14374
  return hash.digest("hex");
14185
14375
  }
14186
14376
  function acquireLock(lockPath) {
@@ -14840,13 +15030,13 @@ function tokenizeStage(stage) {
14840
15030
  }
14841
15031
  // ../aft-bridge/dist/pool.js
14842
15032
  import { realpathSync as realpathSync2 } from "node:fs";
14843
- import { homedir as homedir6 } from "node:os";
15033
+ import { homedir as homedir7 } from "node:os";
14844
15034
  var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
14845
15035
  var DEFAULT_MAX_POOL_SIZE = 8;
14846
15036
  var CLEANUP_INTERVAL_MS = 60 * 1000;
14847
15037
  function canonicalHomeDir() {
14848
15038
  try {
14849
- const home = homedir6();
15039
+ const home = homedir7();
14850
15040
  if (!home)
14851
15041
  return null;
14852
15042
  try {
@@ -15038,6 +15228,91 @@ function normalizeKey(projectRoot) {
15038
15228
  return stripped;
15039
15229
  }
15040
15230
  }
15231
+ // ../aft-bridge/dist/tool-format.js
15232
+ function asPlainObject(value) {
15233
+ if (!value || typeof value !== "object" || Array.isArray(value))
15234
+ return;
15235
+ return value;
15236
+ }
15237
+ function candidateLocation(candidate) {
15238
+ const file = typeof candidate.file === "string" && candidate.file.length > 0 ? candidate.file : undefined;
15239
+ if (!file)
15240
+ return;
15241
+ const line = typeof candidate.line === "number" && Number.isFinite(candidate.line) ? candidate.line : undefined;
15242
+ return line === undefined ? file : `${file}:${line}`;
15243
+ }
15244
+ function stringifyData(data) {
15245
+ if (data === undefined)
15246
+ return;
15247
+ try {
15248
+ return JSON.stringify(data, null, 2);
15249
+ } catch {
15250
+ return String(data);
15251
+ }
15252
+ }
15253
+ function formatBridgeErrorMessage(command, response, params = {}) {
15254
+ const code = typeof response.code === "string" && response.code.length > 0 ? response.code : undefined;
15255
+ const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
15256
+ const data = asPlainObject(response.data);
15257
+ const rawCandidates = Array.isArray(response.candidates) ? response.candidates : Array.isArray(data?.candidates) ? data.candidates : undefined;
15258
+ const rawSymbol = typeof response.symbol === "string" && response.symbol.length > 0 ? response.symbol : typeof data?.symbol === "string" && data.symbol.length > 0 ? data.symbol : undefined;
15259
+ if (code === "ambiguous_target" || code === "target_symbol_not_in_file") {
15260
+ const candidates = (rawCandidates ?? []).map(asPlainObject).filter((candidate) => candidate !== undefined).map(candidateLocation).filter((candidate) => candidate !== undefined);
15261
+ if (candidates.length > 0) {
15262
+ const symbol = typeof params.toSymbol === "string" && params.toSymbol.length > 0 ? params.toSymbol : rawSymbol;
15263
+ const target = symbol ? `multiple symbols named "${symbol}"` : message.replace(/[.!?]+$/, "");
15264
+ const action = code === "ambiguous_target" ? "Pass toFile to disambiguate" : "Try one of these files for toFile";
15265
+ return `${command}: ${code} — ${target}. ${action}:
15266
+ ${candidates.map((candidate) => ` - ${candidate}`).join(`
15267
+ `)}`;
15268
+ }
15269
+ }
15270
+ if (!code)
15271
+ return message;
15272
+ const lines = [`${command}: ${code} — ${message}`];
15273
+ const extras = collectStructuredExtras(response);
15274
+ if (extras)
15275
+ lines.push(`data: ${extras}`);
15276
+ return lines.join(`
15277
+ `);
15278
+ }
15279
+ function collectStructuredExtras(response) {
15280
+ const reserved = new Set([
15281
+ "id",
15282
+ "success",
15283
+ "code",
15284
+ "message",
15285
+ "data",
15286
+ "status_bar",
15287
+ "bg_completions"
15288
+ ]);
15289
+ const extras = {};
15290
+ for (const [key, value] of Object.entries(response)) {
15291
+ if (reserved.has(key))
15292
+ continue;
15293
+ extras[key] = value;
15294
+ }
15295
+ if (Object.keys(extras).length === 0) {
15296
+ return stringifyData(response.data);
15297
+ }
15298
+ if (response.data !== undefined)
15299
+ extras.data = response.data;
15300
+ return stringifyData(extras);
15301
+ }
15302
+ function formatReadFooter(agentSpecifiedRange, data, options) {
15303
+ if (agentSpecifiedRange)
15304
+ return "";
15305
+ if (!data.truncated)
15306
+ return "";
15307
+ const startLine = data.start_line;
15308
+ const endLine = data.end_line;
15309
+ const totalLines = data.total_lines;
15310
+ if (startLine === undefined || endLine === undefined || totalLines === undefined) {
15311
+ return "";
15312
+ }
15313
+ return `
15314
+ (Showing lines ${startLine}-${endLine} of ${totalLines}. Use ${options.rangeHint} to read other sections.)`;
15315
+ }
15041
15316
  // ../aft-bridge/dist/zoom-format.js
15042
15317
  function formatZoomText(targetLabel, response) {
15043
15318
  const range = response.range;
@@ -15118,13 +15393,36 @@ function formatZoomMultiTargetResult(entries) {
15118
15393
 
15119
15394
  `) };
15120
15395
  }
15396
+ function isRustZoomBatchEnvelope(response) {
15397
+ if (!Array.isArray(response.symbols) || response.symbols.length === 0) {
15398
+ return false;
15399
+ }
15400
+ return response.symbols.every((entry) => {
15401
+ if (!entry || typeof entry !== "object")
15402
+ return false;
15403
+ const row = entry;
15404
+ return typeof row.name === "string" && row.response !== undefined && row.response !== null;
15405
+ });
15406
+ }
15407
+ function unwrapRustZoomBatchEnvelope(response) {
15408
+ if (!isRustZoomBatchEnvelope(response)) {
15409
+ return null;
15410
+ }
15411
+ const names = [];
15412
+ const responses = [];
15413
+ for (const entry of response.symbols) {
15414
+ names.push(entry.name);
15415
+ responses.push(entry.response);
15416
+ }
15417
+ return { names, responses };
15418
+ }
15121
15419
  // src/logger.ts
15122
15420
  import * as fs from "node:fs";
15123
- import * as os from "node:os";
15124
- import * as path from "node:path";
15421
+ import * as os2 from "node:os";
15422
+ import * as path2 from "node:path";
15125
15423
  var TAG = "[aft-pi]";
15126
15424
  var isTestEnv = process.env.BUN_TEST === "1" || false;
15127
- var logFile = path.join(os.tmpdir(), isTestEnv ? "aft-pi-test.log" : "aft-pi.log");
15425
+ var logFile = path2.join(os2.tmpdir(), isTestEnv ? "aft-pi-test.log" : "aft-pi.log");
15128
15426
  var useStderr = process.env.AFT_LOG_STDERR === "1";
15129
15427
  var buffer = [];
15130
15428
  var flushTimer = null;
@@ -15760,7 +16058,7 @@ import {
15760
16058
  // package.json
15761
16059
  var package_default = {
15762
16060
  name: "@cortexkit/aft-pi",
15763
- version: "0.38.0",
16061
+ version: "0.39.1",
15764
16062
  type: "module",
15765
16063
  description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
15766
16064
  main: "dist/index.js",
@@ -15783,7 +16081,7 @@ var package_default = {
15783
16081
  "test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
15784
16082
  },
15785
16083
  dependencies: {
15786
- "@cortexkit/aft-bridge": "0.38.0",
16084
+ "@cortexkit/aft-bridge": "0.39.1",
15787
16085
  "@xterm/headless": "^5.5.0",
15788
16086
  "comment-json": "^5.0.0",
15789
16087
  diff: "^8.0.4",
@@ -15791,12 +16089,12 @@ var package_default = {
15791
16089
  zod: "^4.1.8"
15792
16090
  },
15793
16091
  optionalDependencies: {
15794
- "@cortexkit/aft-darwin-arm64": "0.38.0",
15795
- "@cortexkit/aft-darwin-x64": "0.38.0",
15796
- "@cortexkit/aft-linux-arm64": "0.38.0",
15797
- "@cortexkit/aft-linux-x64": "0.38.0",
15798
- "@cortexkit/aft-win32-arm64": "0.38.0",
15799
- "@cortexkit/aft-win32-x64": "0.38.0"
16092
+ "@cortexkit/aft-darwin-arm64": "0.39.1",
16093
+ "@cortexkit/aft-darwin-x64": "0.39.1",
16094
+ "@cortexkit/aft-linux-arm64": "0.39.1",
16095
+ "@cortexkit/aft-linux-x64": "0.39.1",
16096
+ "@cortexkit/aft-win32-arm64": "0.39.1",
16097
+ "@cortexkit/aft-win32-x64": "0.39.1"
15800
16098
  },
15801
16099
  devDependencies: {
15802
16100
  "@earendil-works/pi-coding-agent": "*",
@@ -16029,101 +16327,6 @@ function formatStatusDialogMessage(status) {
16029
16327
  // src/tools/_shared.ts
16030
16328
  import { Type } from "typebox";
16031
16329
  var optionalInt = (_min, _max) => Type.Optional(Type.Any({ description: "(integer)" }));
16032
- function coerceOptionalInt(v, paramName, min, max) {
16033
- if (v === undefined || v === null || v === "")
16034
- return;
16035
- if (typeof v === "number" && (!Number.isFinite(v) || v === 0 && min > 0))
16036
- return;
16037
- const n = typeof v === "string" ? Number(v) : v;
16038
- if (typeof n !== "number" || !Number.isInteger(n)) {
16039
- throw new Error(`${paramName} must be an integer between ${min} and ${max}`);
16040
- }
16041
- if (n < min || n > max) {
16042
- throw new Error(`${paramName} must be between ${min} and ${max}`);
16043
- }
16044
- return n;
16045
- }
16046
- function isEmptyParam(value) {
16047
- if (value === undefined || value === null)
16048
- return true;
16049
- if (typeof value === "string")
16050
- return value.length === 0;
16051
- if (Array.isArray(value))
16052
- return value.length === 0;
16053
- if (typeof value === "object")
16054
- return Object.keys(value).length === 0;
16055
- return false;
16056
- }
16057
- function asPlainObject(value) {
16058
- if (!value || typeof value !== "object" || Array.isArray(value))
16059
- return;
16060
- return value;
16061
- }
16062
- function candidateLocation(candidate) {
16063
- const file = typeof candidate.file === "string" && candidate.file.length > 0 ? candidate.file : undefined;
16064
- if (!file)
16065
- return;
16066
- const line = typeof candidate.line === "number" && Number.isFinite(candidate.line) ? candidate.line : undefined;
16067
- return line === undefined ? file : `${file}:${line}`;
16068
- }
16069
- function stringifyData(data) {
16070
- if (data === undefined)
16071
- return;
16072
- try {
16073
- return JSON.stringify(data, null, 2);
16074
- } catch {
16075
- return String(data);
16076
- }
16077
- }
16078
- function formatBridgeErrorMessage(command, response, params = {}) {
16079
- const code = typeof response.code === "string" && response.code.length > 0 ? response.code : undefined;
16080
- const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
16081
- const data = asPlainObject(response.data);
16082
- const rawCandidates = Array.isArray(response.candidates) ? response.candidates : Array.isArray(data?.candidates) ? data.candidates : undefined;
16083
- const rawSymbol = typeof response.symbol === "string" && response.symbol.length > 0 ? response.symbol : typeof data?.symbol === "string" && data.symbol.length > 0 ? data.symbol : undefined;
16084
- if (code === "ambiguous_target" || code === "target_symbol_not_in_file") {
16085
- const candidates = (rawCandidates ?? []).map(asPlainObject).filter((candidate) => candidate !== undefined).map(candidateLocation).filter((candidate) => candidate !== undefined);
16086
- if (candidates.length > 0) {
16087
- const symbol = typeof params.toSymbol === "string" && params.toSymbol.length > 0 ? params.toSymbol : rawSymbol;
16088
- const target = symbol ? `multiple symbols named "${symbol}"` : message.replace(/[.!?]+$/, "");
16089
- const action = code === "ambiguous_target" ? "Pass toFile to disambiguate" : "Try one of these files for toFile";
16090
- return `${command}: ${code} — ${target}. ${action}:
16091
- ${candidates.map((candidate) => ` - ${candidate}`).join(`
16092
- `)}`;
16093
- }
16094
- }
16095
- if (!code)
16096
- return message;
16097
- const lines = [`${command}: ${code} — ${message}`];
16098
- const extras = collectStructuredExtras(response);
16099
- if (extras)
16100
- lines.push(`data: ${extras}`);
16101
- return lines.join(`
16102
- `);
16103
- }
16104
- function collectStructuredExtras(response) {
16105
- const reserved = new Set([
16106
- "id",
16107
- "success",
16108
- "code",
16109
- "message",
16110
- "data",
16111
- "status_bar",
16112
- "bg_completions"
16113
- ]);
16114
- const extras = {};
16115
- for (const [key, value] of Object.entries(response)) {
16116
- if (reserved.has(key))
16117
- continue;
16118
- extras[key] = value;
16119
- }
16120
- if (Object.keys(extras).length === 0) {
16121
- return stringifyData(response.data);
16122
- }
16123
- if (response.data !== undefined)
16124
- extras.data = response.data;
16125
- return stringifyData(extras);
16126
- }
16127
16330
  function bridgeFor(ctx, cwd) {
16128
16331
  return ctx.pool.getBridge(cwd);
16129
16332
  }
@@ -16466,8 +16669,8 @@ function registerStatusCommand(pi, ctx) {
16466
16669
 
16467
16670
  // src/config.ts
16468
16671
  import { existsSync as existsSync6, readFileSync as readFileSync4, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
16469
- import { homedir as homedir7 } from "node:os";
16470
- import { join as join9 } from "node:path";
16672
+ import { homedir as homedir8 } from "node:os";
16673
+ import { join as join10 } from "node:path";
16471
16674
  var import_comment_json = __toESM(require_src2(), 1);
16472
16675
 
16473
16676
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
@@ -17235,10 +17438,10 @@ function mergeDefs(...defs) {
17235
17438
  function cloneDef(schema) {
17236
17439
  return mergeDefs(schema._zod.def);
17237
17440
  }
17238
- function getElementAtPath(obj, path2) {
17239
- if (!path2)
17441
+ function getElementAtPath(obj, path3) {
17442
+ if (!path3)
17240
17443
  return obj;
17241
- return path2.reduce((acc, key) => acc?.[key], obj);
17444
+ return path3.reduce((acc, key) => acc?.[key], obj);
17242
17445
  }
17243
17446
  function promiseAllObject(promisesObj) {
17244
17447
  const keys = Object.keys(promisesObj);
@@ -17619,11 +17822,11 @@ function aborted(x, startIndex = 0) {
17619
17822
  }
17620
17823
  return false;
17621
17824
  }
17622
- function prefixIssues(path2, issues) {
17825
+ function prefixIssues(path3, issues) {
17623
17826
  return issues.map((iss) => {
17624
17827
  var _a;
17625
17828
  (_a = iss).path ?? (_a.path = []);
17626
- iss.path.unshift(path2);
17829
+ iss.path.unshift(path3);
17627
17830
  return iss;
17628
17831
  });
17629
17832
  }
@@ -17806,7 +18009,7 @@ function formatError(error3, mapper = (issue2) => issue2.message) {
17806
18009
  }
17807
18010
  function treeifyError(error3, mapper = (issue2) => issue2.message) {
17808
18011
  const result = { errors: [] };
17809
- const processError = (error4, path2 = []) => {
18012
+ const processError = (error4, path3 = []) => {
17810
18013
  var _a, _b;
17811
18014
  for (const issue2 of error4.issues) {
17812
18015
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -17816,7 +18019,7 @@ function treeifyError(error3, mapper = (issue2) => issue2.message) {
17816
18019
  } else if (issue2.code === "invalid_element") {
17817
18020
  processError({ issues: issue2.issues }, issue2.path);
17818
18021
  } else {
17819
- const fullpath = [...path2, ...issue2.path];
18022
+ const fullpath = [...path3, ...issue2.path];
17820
18023
  if (fullpath.length === 0) {
17821
18024
  result.errors.push(mapper(issue2));
17822
18025
  continue;
@@ -17848,8 +18051,8 @@ function treeifyError(error3, mapper = (issue2) => issue2.message) {
17848
18051
  }
17849
18052
  function toDotPath(_path) {
17850
18053
  const segs = [];
17851
- const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
17852
- for (const seg of path2) {
18054
+ const path3 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
18055
+ for (const seg of path3) {
17853
18056
  if (typeof seg === "number")
17854
18057
  segs.push(`[${seg}]`);
17855
18058
  else if (typeof seg === "symbol")
@@ -29596,13 +29799,13 @@ function resolveRef(ref, ctx) {
29596
29799
  if (!ref.startsWith("#")) {
29597
29800
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
29598
29801
  }
29599
- const path2 = ref.slice(1).split("/").filter(Boolean);
29600
- if (path2.length === 0) {
29802
+ const path3 = ref.slice(1).split("/").filter(Boolean);
29803
+ if (path3.length === 0) {
29601
29804
  return ctx.rootSchema;
29602
29805
  }
29603
29806
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
29604
- if (path2[0] === defsKey) {
29605
- const key = path2[1];
29807
+ if (path3[0] === defsKey) {
29808
+ const key = path3[1];
29606
29809
  if (!key || !ctx.defs[key]) {
29607
29810
  throw new Error(`Reference not found: ${ref}`);
29608
29811
  }
@@ -30259,9 +30462,9 @@ function extractCommentsForPreservation(content) {
30259
30462
  }
30260
30463
  return comments;
30261
30464
  }
30262
- function ensureRecordAtPath(root, path2) {
30465
+ function ensureRecordAtPath(root, path3) {
30263
30466
  let current = root;
30264
- for (const segment of path2) {
30467
+ for (const segment of path3) {
30265
30468
  const existing = current[segment];
30266
30469
  if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
30267
30470
  current[segment] = {};
@@ -30270,9 +30473,9 @@ function ensureRecordAtPath(root, path2) {
30270
30473
  }
30271
30474
  return current;
30272
30475
  }
30273
- function hasPath(root, path2) {
30476
+ function hasPath(root, path3) {
30274
30477
  let current = root;
30275
- for (const segment of path2) {
30478
+ for (const segment of path3) {
30276
30479
  if (!current || typeof current !== "object" || Array.isArray(current))
30277
30480
  return false;
30278
30481
  const record2 = current;
@@ -30282,9 +30485,9 @@ function hasPath(root, path2) {
30282
30485
  }
30283
30486
  return true;
30284
30487
  }
30285
- function setPath(root, path2, value) {
30286
- const parent = ensureRecordAtPath(root, path2.slice(0, -1));
30287
- parent[path2[path2.length - 1]] = value;
30488
+ function setPath(root, path3, value) {
30489
+ const parent = ensureRecordAtPath(root, path3.slice(0, -1));
30490
+ parent[path3[path3.length - 1]] = value;
30288
30491
  }
30289
30492
  function migrateRawConfig(rawConfig, configPath, logger) {
30290
30493
  const oldKeys = [];
@@ -30601,15 +30804,15 @@ function mergeConfigs(base, override) {
30601
30804
  };
30602
30805
  }
30603
30806
  function getGlobalPiDir() {
30604
- return join9(homedir7(), ".pi", "agent");
30807
+ return join10(homedir8(), ".pi", "agent");
30605
30808
  }
30606
30809
  function loadAftConfig(projectDirectory) {
30607
- const userBasePath = join9(getGlobalPiDir(), "aft");
30810
+ const userBasePath = join10(getGlobalPiDir(), "aft");
30608
30811
  migrateAftConfigFile(`${userBasePath}.jsonc`);
30609
30812
  migrateAftConfigFile(`${userBasePath}.json`);
30610
30813
  const userDetected = detectConfigFile(userBasePath);
30611
30814
  const userConfigPath = userDetected.format !== "none" ? userDetected.path : `${userBasePath}.json`;
30612
- const projectBasePath = join9(projectDirectory, ".pi", "aft");
30815
+ const projectBasePath = join10(projectDirectory, ".pi", "aft");
30613
30816
  migrateAftConfigFile(`${projectBasePath}.jsonc`);
30614
30817
  migrateAftConfigFile(`${projectBasePath}.json`);
30615
30818
  const projectDetected = detectConfigFile(projectBasePath);
@@ -30646,7 +30849,7 @@ import {
30646
30849
  statSync as statSync5,
30647
30850
  writeFileSync as writeFileSync5
30648
30851
  } from "node:fs";
30649
- import { join as join12 } from "node:path";
30852
+ import { join as join13 } from "node:path";
30650
30853
 
30651
30854
  // src/lsp-cache.ts
30652
30855
  import {
@@ -30658,36 +30861,36 @@ import {
30658
30861
  unlinkSync as unlinkSync5,
30659
30862
  writeFileSync as writeFileSync4
30660
30863
  } from "node:fs";
30661
- import { homedir as homedir8 } from "node:os";
30662
- import { join as join10 } from "node:path";
30864
+ import { homedir as homedir9 } from "node:os";
30865
+ import { join as join11 } from "node:path";
30663
30866
  function aftCacheBase() {
30664
30867
  const override = process.env.AFT_CACHE_DIR;
30665
30868
  if (override && override.length > 0)
30666
30869
  return override;
30667
30870
  if (process.platform === "win32") {
30668
30871
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
30669
- const base2 = localAppData || join10(homedir8(), "AppData", "Local");
30670
- return join10(base2, "aft");
30872
+ const base2 = localAppData || join11(homedir9(), "AppData", "Local");
30873
+ return join11(base2, "aft");
30671
30874
  }
30672
- const base = process.env.XDG_CACHE_HOME || join10(homedir8(), ".cache");
30673
- return join10(base, "aft");
30875
+ const base = process.env.XDG_CACHE_HOME || join11(homedir9(), ".cache");
30876
+ return join11(base, "aft");
30674
30877
  }
30675
30878
  function lspCacheRoot() {
30676
- return join10(aftCacheBase(), "lsp-packages");
30879
+ return join11(aftCacheBase(), "lsp-packages");
30677
30880
  }
30678
30881
  function lspPackageDir(npmPackage) {
30679
- return join10(lspCacheRoot(), encodeURIComponent(npmPackage));
30882
+ return join11(lspCacheRoot(), encodeURIComponent(npmPackage));
30680
30883
  }
30681
30884
  function lspBinaryPath(npmPackage, binary) {
30682
- return join10(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
30885
+ return join11(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
30683
30886
  }
30684
30887
  function lspBinDir(npmPackage) {
30685
- return join10(lspPackageDir(npmPackage), "node_modules", ".bin");
30888
+ return join11(lspPackageDir(npmPackage), "node_modules", ".bin");
30686
30889
  }
30687
30890
  function isInstalled(npmPackage, binary) {
30688
30891
  for (const candidate of lspBinaryCandidates(binary)) {
30689
30892
  try {
30690
- if (statSync4(join10(lspBinDir(npmPackage), candidate)).isFile())
30893
+ if (statSync4(join11(lspBinDir(npmPackage), candidate)).isFile())
30691
30894
  return true;
30692
30895
  } catch {}
30693
30896
  }
@@ -30707,17 +30910,17 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
30707
30910
  installedAt: new Date().toISOString(),
30708
30911
  ...sha256 ? { sha256 } : {}
30709
30912
  };
30710
- writeFileSync4(join10(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
30913
+ writeFileSync4(join11(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
30711
30914
  } catch (err) {
30712
30915
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
30713
30916
  }
30714
30917
  }
30715
30918
  function readInstalledMetaIn(installDir) {
30716
- const path2 = join10(installDir, INSTALLED_META_FILE);
30919
+ const path3 = join11(installDir, INSTALLED_META_FILE);
30717
30920
  try {
30718
- if (!statSync4(path2).isFile())
30921
+ if (!statSync4(path3).isFile())
30719
30922
  return null;
30720
- const raw = readFileSync5(path2, "utf8");
30923
+ const raw = readFileSync5(path3, "utf8");
30721
30924
  const parsed = JSON.parse(raw);
30722
30925
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
30723
30926
  return null;
@@ -30737,7 +30940,7 @@ function readInstalledMeta(packageKey) {
30737
30940
  return readInstalledMetaIn(lspPackageDir(packageKey));
30738
30941
  }
30739
30942
  function lockPath(npmPackage) {
30740
- return join10(lspPackageDir(npmPackage), ".aft-installing");
30943
+ return join11(lspPackageDir(npmPackage), ".aft-installing");
30741
30944
  }
30742
30945
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
30743
30946
  function acquireInstallLock(lockKey) {
@@ -30844,7 +31047,7 @@ async function withInstallLock(lockKey, task) {
30844
31047
  }
30845
31048
  var VERSION_CHECK_FILE = ".aft-version-check";
30846
31049
  function readVersionCheck(npmPackage) {
30847
- const file2 = join10(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31050
+ const file2 = join11(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
30848
31051
  try {
30849
31052
  const raw = readFileSync5(file2, "utf8");
30850
31053
  const parsed = JSON.parse(raw);
@@ -30861,7 +31064,7 @@ function readVersionCheck(npmPackage) {
30861
31064
  }
30862
31065
  function writeVersionCheck(npmPackage, latest) {
30863
31066
  mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
30864
- const file2 = join10(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31067
+ const file2 = join11(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
30865
31068
  const record2 = {
30866
31069
  last_checked: new Date().toISOString(),
30867
31070
  latest_eligible: latest
@@ -31024,7 +31227,7 @@ var NPM_LSP_TABLE = [
31024
31227
 
31025
31228
  // src/lsp-project-relevance.ts
31026
31229
  import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync6 } from "node:fs";
31027
- import { join as join11 } from "node:path";
31230
+ import { join as join12 } from "node:path";
31028
31231
  var MAX_WALK_DIRS = 200;
31029
31232
  var MAX_WALK_DEPTH = 4;
31030
31233
  var NOISE_DIRS = new Set([
@@ -31041,7 +31244,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
31041
31244
  if (!rootMarkers)
31042
31245
  return false;
31043
31246
  for (const marker of rootMarkers) {
31044
- if (existsSync7(join11(projectRoot, marker)))
31247
+ if (existsSync7(join12(projectRoot, marker)))
31045
31248
  return true;
31046
31249
  }
31047
31250
  return false;
@@ -31065,7 +31268,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
31065
31268
  }
31066
31269
  function readPackageJson(projectRoot) {
31067
31270
  try {
31068
- const raw = readFileSync6(join11(projectRoot, "package.json"), "utf8");
31271
+ const raw = readFileSync6(join12(projectRoot, "package.json"), "utf8");
31069
31272
  const parsed = JSON.parse(raw);
31070
31273
  if (typeof parsed !== "object" || parsed === null)
31071
31274
  return null;
@@ -31095,7 +31298,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
31095
31298
  for (const entry of entries) {
31096
31299
  if (entry.isDirectory()) {
31097
31300
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
31098
- queue.push({ dir: join11(current.dir, entry.name), depth: current.depth + 1 });
31301
+ queue.push({ dir: join12(current.dir, entry.name), depth: current.depth + 1 });
31099
31302
  }
31100
31303
  continue;
31101
31304
  }
@@ -31222,7 +31425,7 @@ async function resolveTargetVersion(spec, config2, fetchImpl = fetch) {
31222
31425
  }
31223
31426
  function ensureInstallAnchor(cwd) {
31224
31427
  try {
31225
- const stub = join12(cwd, "package.json");
31428
+ const stub = join13(cwd, "package.json");
31226
31429
  if (!existsSync8(stub)) {
31227
31430
  writeFileSync5(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
31228
31431
  `);
@@ -31232,18 +31435,18 @@ function ensureInstallAnchor(cwd) {
31232
31435
  }
31233
31436
  }
31234
31437
  function runInstall(spec, version2, cwd, signal) {
31235
- return new Promise((resolve2) => {
31438
+ return new Promise((resolve3) => {
31236
31439
  const target = `${spec.npm}@${version2}`;
31237
31440
  log2(`[lsp] installing ${target} to ${cwd}`);
31238
31441
  if (signal?.aborted) {
31239
31442
  warn2(`[lsp] install ${target} aborted before spawn`);
31240
- resolve2(false);
31443
+ resolve3(false);
31241
31444
  return;
31242
31445
  }
31243
31446
  const npm = resolveNpm();
31244
31447
  if (!npm) {
31245
31448
  warn2(`[lsp] npm not found on PATH or known locations; cannot install ${target}`);
31246
- resolve2(false);
31449
+ resolve3(false);
31247
31450
  return;
31248
31451
  }
31249
31452
  ensureInstallAnchor(cwd);
@@ -31266,7 +31469,7 @@ function runInstall(spec, version2, cwd, signal) {
31266
31469
  return;
31267
31470
  settled = true;
31268
31471
  cleanup();
31269
- resolve2(ok);
31472
+ resolve3(ok);
31270
31473
  };
31271
31474
  const onAbort = () => {
31272
31475
  warn2(`[lsp] install ${target} aborted during shutdown`);
@@ -31367,7 +31570,7 @@ function cachedPackageDir(npmPackage) {
31367
31570
  return lspBinDir(npmPackage).replace(/[\\/]node_modules[\\/]\.bin[\\/]?$/, "");
31368
31571
  }
31369
31572
  function hashInstalledBinary(spec) {
31370
- return new Promise((resolve2, reject) => {
31573
+ return new Promise((resolve3, reject) => {
31371
31574
  const candidates = process.platform === "win32" ? [
31372
31575
  lspBinaryPath(spec.npm, spec.binary),
31373
31576
  lspBinaryPath(spec.npm, `${spec.binary}.cmd`),
@@ -31391,7 +31594,7 @@ function hashInstalledBinary(spec) {
31391
31594
  const stream = createReadStream(pathToHash);
31392
31595
  stream.on("error", reject);
31393
31596
  stream.on("data", (chunk) => hash2.update(chunk));
31394
- stream.on("end", () => resolve2(hash2.digest("hex")));
31597
+ stream.on("end", () => resolve3(hash2.digest("hex")));
31395
31598
  });
31396
31599
  }
31397
31600
  function installedBinaryPath(spec) {
@@ -31409,15 +31612,15 @@ function installedBinaryPath(spec) {
31409
31612
  }
31410
31613
  return null;
31411
31614
  }
31412
- function sha256OfFileSync(path2) {
31413
- return createHash3("sha256").update(readFileSync7(path2)).digest("hex");
31615
+ function sha256OfFileSync(path3) {
31616
+ return createHash3("sha256").update(readFileSync7(path3)).digest("hex");
31414
31617
  }
31415
31618
  function quarantineCachedNpmInstall(spec, reason) {
31416
31619
  const packageDir = lspPackageDir(spec.npm);
31417
- const dest = join12(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
31620
+ const dest = join13(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
31418
31621
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
31419
31622
  try {
31420
- mkdirSync7(join12(dest, ".."), { recursive: true });
31623
+ mkdirSync7(join13(dest, ".."), { recursive: true });
31421
31624
  rmSync3(dest, { recursive: true, force: true });
31422
31625
  renameSync5(packageDir, dest);
31423
31626
  } catch (err) {
@@ -31512,7 +31715,7 @@ import {
31512
31715
  unlinkSync as unlinkSync6,
31513
31716
  writeFileSync as writeFileSync6
31514
31717
  } from "node:fs";
31515
- import { dirname as dirname5, join as join13, relative as relative2, resolve as resolve2 } from "node:path";
31718
+ import { dirname as dirname5, join as join14, relative as relative3, resolve as resolve3 } from "node:path";
31516
31719
  import { Readable as Readable3 } from "node:stream";
31517
31720
  import { pipeline as pipeline3 } from "node:stream/promises";
31518
31721
 
@@ -31602,26 +31805,26 @@ function detectHostPlatform() {
31602
31805
 
31603
31806
  // src/lsp-github-install.ts
31604
31807
  function ghCacheRoot() {
31605
- return join13(aftCacheBase(), "lsp-binaries");
31808
+ return join14(aftCacheBase(), "lsp-binaries");
31606
31809
  }
31607
31810
  function ghPackageDir(spec) {
31608
- return join13(ghCacheRoot(), spec.id);
31811
+ return join14(ghCacheRoot(), spec.id);
31609
31812
  }
31610
31813
  function ghBinDir(spec) {
31611
- return join13(ghPackageDir(spec), "bin");
31814
+ return join14(ghPackageDir(spec), "bin");
31612
31815
  }
31613
31816
  function ghExtractDir(spec) {
31614
- return join13(ghPackageDir(spec), "extracted");
31817
+ return join14(ghPackageDir(spec), "extracted");
31615
31818
  }
31616
31819
  var INSTALLED_META_FILE2 = ".aft-installed";
31617
31820
  function ghBinaryPath(spec, platform) {
31618
31821
  const ext = platform === "win32" ? ".exe" : "";
31619
- return join13(ghBinDir(spec), `${spec.binary}${ext}`);
31822
+ return join14(ghBinDir(spec), `${spec.binary}${ext}`);
31620
31823
  }
31621
31824
  function isGithubInstalled(spec, platform) {
31622
31825
  for (const candidate of ghBinaryCandidates(spec, platform)) {
31623
31826
  try {
31624
- if (statSync6(join13(ghBinDir(spec), candidate)).isFile())
31827
+ if (statSync6(join14(ghBinDir(spec), candidate)).isFile())
31625
31828
  return true;
31626
31829
  } catch {}
31627
31830
  }
@@ -31634,10 +31837,10 @@ function ghBinaryCandidates(spec, platform) {
31634
31837
  }
31635
31838
  function readGithubInstalledMetaIn(installDir) {
31636
31839
  try {
31637
- const path2 = join13(installDir, INSTALLED_META_FILE2);
31638
- if (!statSync6(path2).isFile())
31840
+ const path3 = join14(installDir, INSTALLED_META_FILE2);
31841
+ if (!statSync6(path3).isFile())
31639
31842
  return null;
31640
- const parsed = JSON.parse(readFileSync8(path2, "utf8"));
31843
+ const parsed = JSON.parse(readFileSync8(path3, "utf8"));
31641
31844
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
31642
31845
  return null;
31643
31846
  return {
@@ -31661,24 +31864,24 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
31661
31864
  binarySha256,
31662
31865
  ...archiveSha256 ? { archiveSha256 } : {}
31663
31866
  };
31664
- writeFileSync6(join13(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
31867
+ writeFileSync6(join14(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
31665
31868
  } catch (err) {
31666
31869
  warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
31667
31870
  }
31668
31871
  }
31669
31872
  var MAX_DOWNLOAD_BYTES3 = 256 * 1024 * 1024;
31670
31873
  var MAX_EXTRACT_BYTES2 = 1024 * 1024 * 1024;
31671
- function sha256OfFile(path2) {
31672
- return new Promise((resolve3, reject) => {
31874
+ function sha256OfFile(path3) {
31875
+ return new Promise((resolve4, reject) => {
31673
31876
  const hash2 = createHash4("sha256");
31674
- const stream = createReadStream2(path2);
31877
+ const stream = createReadStream2(path3);
31675
31878
  stream.on("error", reject);
31676
31879
  stream.on("data", (chunk) => hash2.update(chunk));
31677
- stream.on("end", () => resolve3(hash2.digest("hex")));
31880
+ stream.on("end", () => resolve4(hash2.digest("hex")));
31678
31881
  });
31679
31882
  }
31680
- function sha256OfFileSync2(path2) {
31681
- return createHash4("sha256").update(readFileSync8(path2)).digest("hex");
31883
+ function sha256OfFileSync2(path3) {
31884
+ return createHash4("sha256").update(readFileSync8(path3)).digest("hex");
31682
31885
  }
31683
31886
  async function fetchReleaseByTag(githubRepo, tag, fetchImpl, signal) {
31684
31887
  const candidates = [];
@@ -31910,7 +32113,7 @@ function validateExtraction(stagingRoot) {
31910
32113
  throw new Error(`failed to read staging dir ${dir}: ${err}`);
31911
32114
  }
31912
32115
  for (const entry of entries) {
31913
- const full = join13(dir, entry);
32116
+ const full = join14(dir, entry);
31914
32117
  let lst;
31915
32118
  try {
31916
32119
  lst = lstatSync2(full);
@@ -31922,7 +32125,7 @@ function validateExtraction(stagingRoot) {
31922
32125
  try {
31923
32126
  target = readlinkSync2(full);
31924
32127
  } catch {}
31925
- throw new Error(`archive contains symlink ${relative2(realStagingRoot, full)} → ${target}; rejecting (zip-slip defense)`);
32128
+ throw new Error(`archive contains symlink ${relative3(realStagingRoot, full)} → ${target}; rejecting (zip-slip defense)`);
31926
32129
  }
31927
32130
  let realFull;
31928
32131
  try {
@@ -31930,8 +32133,8 @@ function validateExtraction(stagingRoot) {
31930
32133
  } catch (err) {
31931
32134
  throw new Error(`failed to realpath ${full}: ${err}`);
31932
32135
  }
31933
- const rel = relative2(realStagingRoot, realFull);
31934
- if (rel.startsWith("..") || resolve2(realStagingRoot, rel) !== realFull) {
32136
+ const rel = relative3(realStagingRoot, realFull);
32137
+ if (rel.startsWith("..") || resolve3(realStagingRoot, rel) !== realFull) {
31935
32138
  throw new Error(`archive entry escapes staging root: ${full} → ${realFull} (zip-slip defense)`);
31936
32139
  }
31937
32140
  if (lst.isDirectory()) {
@@ -31998,7 +32201,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
31998
32201
  }
31999
32202
  function quarantineCachedGithubInstall(spec, reason) {
32000
32203
  const packageDir = ghPackageDir(spec);
32001
- const dest = join13(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
32204
+ const dest = join14(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
32002
32205
  warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
32003
32206
  try {
32004
32207
  mkdirSync8(dirname5(dest), { recursive: true });
@@ -32011,7 +32214,7 @@ function quarantineCachedGithubInstall(spec, reason) {
32011
32214
  function validateCachedGithubInstall(spec, platform) {
32012
32215
  const packageDir = ghPackageDir(spec);
32013
32216
  const meta3 = readGithubInstalledMetaIn(packageDir);
32014
- const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join13(ghBinDir(spec), candidate)).find((candidate) => {
32217
+ const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join14(ghBinDir(spec), candidate)).find((candidate) => {
32015
32218
  try {
32016
32219
  return statSync6(candidate).isFile();
32017
32220
  } catch {
@@ -32089,7 +32292,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
32089
32292
  }
32090
32293
  const pkgDir = ghPackageDir(spec);
32091
32294
  const extractDir = ghExtractDir(spec);
32092
- const archivePath = join13(pkgDir, expected.name);
32295
+ const archivePath = join14(pkgDir, expected.name);
32093
32296
  log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
32094
32297
  try {
32095
32298
  await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
@@ -32129,7 +32332,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
32129
32332
  unlinkSync6(archivePath);
32130
32333
  } catch {}
32131
32334
  }
32132
- const innerBinaryPath = join13(extractDir, spec.binaryPathInArchive(platform, arch, version2));
32335
+ const innerBinaryPath = join14(extractDir, spec.binaryPathInArchive(platform, arch, version2));
32133
32336
  if (!existsSync9(innerBinaryPath)) {
32134
32337
  error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
32135
32338
  return null;
@@ -32527,7 +32730,7 @@ function renderScreen(state, rows = state.rows, cols = state.cols) {
32527
32730
  `);
32528
32731
  }
32529
32732
  function writeTerminal(terminal, data) {
32530
- return new Promise((resolve3) => terminal.write(data, resolve3));
32733
+ return new Promise((resolve4) => terminal.write(data, resolve4));
32531
32734
  }
32532
32735
 
32533
32736
  // src/shutdown-hooks.ts
@@ -32584,8 +32787,8 @@ function installProcessHandlers() {
32584
32787
  }
32585
32788
  signalShutdownStarted = true;
32586
32789
  process.exitCode = SIGNAL_EXIT_CODES[sig];
32587
- const timeout = new Promise((resolve3) => {
32588
- setTimeout(resolve3, SIGNAL_CLEANUP_TIMEOUT_MS);
32790
+ const timeout = new Promise((resolve4) => {
32791
+ setTimeout(resolve4, SIGNAL_CLEANUP_TIMEOUT_MS);
32589
32792
  });
32590
32793
  Promise.race([runCleanups(sig), timeout]).finally(() => {
32591
32794
  process.exit(SIGNAL_EXIT_CODES[sig]);
@@ -32627,8 +32830,8 @@ import { Type as Type3 } from "typebox";
32627
32830
 
32628
32831
  // src/tools/hoisted.ts
32629
32832
  import { stat } from "node:fs/promises";
32630
- import { homedir as homedir9 } from "node:os";
32631
- import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3, sep } from "node:path";
32833
+ import { homedir as homedir10 } from "node:os";
32834
+ import { isAbsolute as isAbsolute4, relative as relative4, resolve as resolve4, sep } from "node:path";
32632
32835
  import {
32633
32836
  renderDiff
32634
32837
  } from "@earendil-works/pi-coding-agent";
@@ -32742,18 +32945,18 @@ function diagnosticsOnEditDefault(ctx) {
32742
32945
  return ctx.config.lsp?.diagnostics_on_edit ?? false;
32743
32946
  }
32744
32947
  function containsPath(parent, child) {
32745
- const rel = relative3(parent, child);
32746
- return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
32948
+ const rel = relative4(parent, child);
32949
+ return rel === "" || !rel.startsWith("..") && !isAbsolute4(rel);
32747
32950
  }
32748
- function expandTilde(path2) {
32749
- if (!path2 || !path2.startsWith("~"))
32750
- return path2;
32751
- if (path2 === "~")
32752
- return homedir9();
32753
- if (path2.startsWith(`~${sep}`) || path2.startsWith("~/")) {
32754
- return resolve3(homedir9(), path2.slice(2));
32951
+ function expandTilde2(path3) {
32952
+ if (!path3 || !path3.startsWith("~"))
32953
+ return path3;
32954
+ if (path3 === "~")
32955
+ return homedir10();
32956
+ if (path3.startsWith(`~${sep}`) || path3.startsWith("~/")) {
32957
+ return resolve4(homedir10(), path3.slice(2));
32755
32958
  }
32756
- return path2;
32959
+ return path3;
32757
32960
  }
32758
32961
  function externalDirectoryPromptTimeoutMs() {
32759
32962
  const raw = process.env.AFT_PI_EXTERNAL_PROMPT_TIMEOUT_MS;
@@ -32765,8 +32968,8 @@ function externalDirectoryPromptTimeoutMs() {
32765
32968
  async function assertExternalDirectoryPermission(extCtx, target, action = "modify", options = {}) {
32766
32969
  if (!target)
32767
32970
  return;
32768
- const expanded = expandTilde(target);
32769
- const absoluteTarget = isAbsolute3(expanded) ? expanded : resolve3(extCtx.cwd, expanded);
32971
+ const expanded = expandTilde2(target);
32972
+ const absoluteTarget = isAbsolute4(expanded) ? expanded : resolve4(extCtx.cwd, expanded);
32770
32973
  if (containsPath(extCtx.cwd, absoluteTarget))
32771
32974
  return;
32772
32975
  if (options.restrictToProjectRoot === false)
@@ -32777,8 +32980,8 @@ async function assertExternalDirectoryPermission(extCtx, target, action = "modif
32777
32980
  }
32778
32981
  const timeoutMs = externalDirectoryPromptTimeoutMs();
32779
32982
  let timer;
32780
- const timeoutPromise = new Promise((resolve4) => {
32781
- timer = setTimeout(() => resolve4("timeout"), timeoutMs);
32983
+ const timeoutPromise = new Promise((resolve5) => {
32984
+ timer = setTimeout(() => resolve5("timeout"), timeoutMs);
32782
32985
  });
32783
32986
  try {
32784
32987
  const result = await Promise.race([
@@ -32842,8 +33045,12 @@ function registerHoistedTools(pi, ctx, surface) {
32842
33045
  const bridge = bridgeFor(ctx, extCtx.cwd);
32843
33046
  const offset = coerceOptionalInt(params.offset, "offset", 1, Number.MAX_SAFE_INTEGER);
32844
33047
  const limit = coerceOptionalInt(params.limit, "limit", 1, Number.MAX_SAFE_INTEGER);
33048
+ const filePath = await resolvePathArg(extCtx.cwd, params.path);
33049
+ await assertExternalDirectoryPermission(extCtx, filePath, "read", {
33050
+ restrictToProjectRoot: surface.restrictToProjectRoot
33051
+ });
32845
33052
  const req = {
32846
- file: await resolvePathArg(extCtx.cwd, params.path)
33053
+ file: filePath
32847
33054
  };
32848
33055
  if (offset !== undefined) {
32849
33056
  req.start_line = offset;
@@ -32860,7 +33067,7 @@ function registerHoistedTools(pi, ctx, surface) {
32860
33067
  }
32861
33068
  let text = response.content ?? "";
32862
33069
  const agentSpecifiedRange = offset !== undefined || limit !== undefined;
32863
- const footer = formatReadFooter(agentSpecifiedRange, response);
33070
+ const footer = formatReadFooter2(agentSpecifiedRange, response);
32864
33071
  if (footer)
32865
33072
  text += footer;
32866
33073
  return textResult(text);
@@ -33116,15 +33323,15 @@ ${summary}${suffix}`);
33116
33323
  container.addChild(new Text(renderDiff(diff), 1, 0));
33117
33324
  return container;
33118
33325
  }
33119
- function shortenPath(path2) {
33120
- const home = homedir9();
33121
- if (path2.startsWith(home))
33122
- return `~${path2.slice(home.length)}`;
33123
- return path2;
33326
+ function shortenPath(path3) {
33327
+ const home = homedir10();
33328
+ if (path3.startsWith(home))
33329
+ return `~${path3.slice(home.length)}`;
33330
+ return path3;
33124
33331
  }
33125
- async function resolvePathArg(cwd, path2) {
33126
- const expanded = expandTilde(path2);
33127
- const abs = isAbsolute3(expanded) ? expanded : resolve3(cwd, expanded);
33332
+ async function resolvePathArg(cwd, path3) {
33333
+ const expanded = expandTilde2(path3);
33334
+ const abs = isAbsolute4(expanded) ? expanded : resolve4(cwd, expanded);
33128
33335
  try {
33129
33336
  await stat(abs);
33130
33337
  return abs;
@@ -33162,23 +33369,12 @@ function splitIncludeGlobs(include) {
33162
33369
  out.push(tail2);
33163
33370
  return out;
33164
33371
  }
33165
- function formatReadFooter(agentSpecifiedRange, data) {
33166
- if (agentSpecifiedRange)
33167
- return "";
33168
- if (!data.truncated)
33169
- return "";
33170
- const startLine = data.start_line;
33171
- const endLine = data.end_line;
33172
- const totalLines = data.total_lines;
33173
- if (startLine === undefined || endLine === undefined || totalLines === undefined) {
33174
- return "";
33175
- }
33176
- return `
33177
- (Showing lines ${startLine}-${endLine} of ${totalLines}. Use offset/limit to read other sections.)`;
33372
+ function formatReadFooter2(agentSpecifiedRange, data) {
33373
+ return formatReadFooter(agentSpecifiedRange, data, { rangeHint: "offset/limit" });
33178
33374
  }
33179
33375
 
33180
33376
  // src/tools/render-helpers.ts
33181
- import { homedir as homedir10 } from "node:os";
33377
+ import { homedir as homedir11 } from "node:os";
33182
33378
  import { renderDiff as renderDiff2 } from "@earendil-works/pi-coding-agent";
33183
33379
  import { Container as Container2, Spacer as Spacer2, Text as Text2 } from "@earendil-works/pi-tui";
33184
33380
  function reuseText2(last) {
@@ -33187,11 +33383,11 @@ function reuseText2(last) {
33187
33383
  function reuseContainer2(last) {
33188
33384
  return last instanceof Container2 ? last : new Container2;
33189
33385
  }
33190
- function shortenPath2(path2) {
33191
- const home = homedir10();
33192
- if (path2.startsWith(home))
33193
- return `~${path2.slice(home.length)}`;
33194
- return path2;
33386
+ function shortenPath2(path3) {
33387
+ const home = homedir11();
33388
+ if (path3.startsWith(home))
33389
+ return `~${path3.slice(home.length)}`;
33390
+ return path3;
33195
33391
  }
33196
33392
  function renderToolCall(toolName, summary, theme, context) {
33197
33393
  const text = reuseText2(context.lastComponent);
@@ -33199,10 +33395,10 @@ function renderToolCall(toolName, summary, theme, context) {
33199
33395
  text.setText(`${theme.fg("toolTitle", theme.bold(toolName))}${suffix}`);
33200
33396
  return text;
33201
33397
  }
33202
- function accentPath(theme, path2) {
33203
- if (!path2)
33398
+ function accentPath(theme, path3) {
33399
+ if (!path3)
33204
33400
  return theme.fg("toolOutput", "...");
33205
- return theme.fg("accent", shortenPath2(path2));
33401
+ return theme.fg("accent", shortenPath2(path3));
33206
33402
  }
33207
33403
  function collectTextContent(result) {
33208
33404
  return result.content.filter((part) => part.type === "text").map((part) => part.text ?? "").join(`
@@ -33349,7 +33545,7 @@ function renderUnifiedDiff(unifiedDiff) {
33349
33545
  }
33350
33546
 
33351
33547
  // src/tools/ast.ts
33352
- var AstLang = StringEnum(["typescript", "tsx", "javascript", "python", "rust", "go", "pascal"], {
33548
+ var AstLang = StringEnum(["typescript", "tsx", "javascript", "python", "rust", "go", "pascal", "r"], {
33353
33549
  description: "Target language"
33354
33550
  });
33355
33551
  var SearchParams = Type3.Object({
@@ -33390,17 +33586,17 @@ ${warningStrings.map((w) => ` ${w}`).join(`
33390
33586
  async function resolveAstPaths(extCtx, paths) {
33391
33587
  if (isEmptyParam(paths) || !Array.isArray(paths))
33392
33588
  return;
33393
- return Promise.all(paths.filter((path2) => typeof path2 === "string").map((path2) => resolvePathArg(extCtx.cwd, path2)));
33589
+ return Promise.all(paths.filter((path3) => typeof path3 === "string").map((path3) => resolvePathArg(extCtx.cwd, path3)));
33394
33590
  }
33395
33591
  async function assertAstPathsPermission(extCtx, paths, action, restrictToProjectRoot) {
33396
33592
  if (paths === undefined || paths.length === 0)
33397
33593
  return;
33398
33594
  const checked = new Set;
33399
- for (const path2 of paths) {
33400
- if (checked.has(path2))
33595
+ for (const path3 of paths) {
33596
+ if (checked.has(path3))
33401
33597
  continue;
33402
- checked.add(path2);
33403
- await assertExternalDirectoryPermission(extCtx, path2, action, { restrictToProjectRoot });
33598
+ checked.add(path3);
33599
+ await assertExternalDirectoryPermission(extCtx, path3, action, { restrictToProjectRoot });
33404
33600
  }
33405
33601
  }
33406
33602
  function buildAstSearchSections(payload, theme) {
@@ -33583,6 +33779,7 @@ var FOREGROUND_POLL_INTERVAL_MS = 100;
33583
33779
  var BASH_WAIT_POLL_INTERVAL_MS = 100;
33584
33780
  var DEFAULT_BASH_STATUS_WAIT_TIMEOUT_MS = 30000;
33585
33781
  var MAX_BASH_STATUS_WAIT_TIMEOUT_MS = 300000;
33782
+ var REGEX_WAIT_SCAN_WINDOW_BYTES = 64 * 1024;
33586
33783
  function resolveForegroundWaitMs(configured) {
33587
33784
  const override = process.env.AFT_TEST_FOREGROUND_WAIT_MS;
33588
33785
  if (override !== undefined) {
@@ -33767,7 +33964,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
33767
33964
  throw new Error(status.message ?? "bash_status failed");
33768
33965
  }
33769
33966
  if (isTerminalStatus(status.status)) {
33770
- return bashResult(appendPipeStripNote(withBashHints(formatForegroundResult(status), bridgeCommand, aftSearchRegistered), pipeStrip.note), {
33967
+ return bashResult(appendPipeStripNote(withBashHints(formatForegroundResult(status), bridgeCommand, aftSearchRegistered, extCtx.cwd), pipeStrip.note), {
33771
33968
  exit_code: status.exit_code,
33772
33969
  duration_ms: status.duration_ms,
33773
33970
  truncated: status.output_truncated,
@@ -33794,7 +33991,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
33794
33991
  task_id: taskId
33795
33992
  };
33796
33993
  const output = response.output ?? "";
33797
- return bashResult(appendPipeStripNote(withBashHints(output, bridgeCommand, aftSearchRegistered), pipeStrip.note), details);
33994
+ return bashResult(appendPipeStripNote(withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), pipeStrip.note), details);
33798
33995
  },
33799
33996
  renderCall(args, theme, context) {
33800
33997
  return renderBashCall(args?.command, args?.description, theme, context);
@@ -33808,11 +34005,6 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
33808
34005
  pi.registerTool(createBashWriteTool(ctx));
33809
34006
  pi.registerTool(createBashKillTool(ctx));
33810
34007
  }
33811
- function appendPipeStripNote(output, note) {
33812
- return note ? `${output}
33813
-
33814
- ${note}` : output;
33815
- }
33816
34008
  function formatBackgroundLaunch(taskId, isPty) {
33817
34009
  if (isPty) {
33818
34010
  return `PTY task started: ${taskId}. Use bash_status({ task_id: "${taskId}", output_mode: "screen" }) to see the visible terminal, bash_write({ task_id: "${taskId}", input: ... }) to send keystrokes. A completion reminder fires automatically when the task exits.`;
@@ -33823,35 +34015,8 @@ function formatPromotionMessage(taskId, timeout, waitWindowMs) {
33823
34015
  const waited = timeout !== undefined ? Math.min(timeout, waitWindowMs) : waitWindowMs;
33824
34016
  return `Foreground bash didn't finish within ${formatSeconds(waited)} and was promoted to background: ${taskId}. A completion reminder will be delivered automatically; use bash_status({ task_id: "${taskId}" }) to inspect output or bash_kill({ task_id: "${taskId}" }) to terminate.`;
33825
34017
  }
33826
- function formatSeconds(ms) {
33827
- return `${Number((ms / 1000).toFixed(1))}s`;
33828
- }
33829
- function withBashHints(output, command, aftSearchRegistered) {
33830
- return maybeAppendGrepSearchHint(maybeAppendConflictsHint(output), command, aftSearchRegistered);
33831
- }
33832
- function formatForegroundResult(data) {
33833
- const output = data.output_preview ?? "";
33834
- const outputPath = data.output_path;
33835
- const truncated = data.output_truncated === true;
33836
- const status = data.status;
33837
- const exit = data.exit_code;
33838
- let rendered = output;
33839
- if (truncated && outputPath) {
33840
- rendered += `
33841
- [output truncated; full output at ${outputPath}]`;
33842
- }
33843
- if (status === "timed_out") {
33844
- rendered += `
33845
- [command timed out]`;
33846
- }
33847
- if (typeof exit === "number" && exit !== 0) {
33848
- rendered += `
33849
- [exit code: ${exit}]`;
33850
- }
33851
- return rendered;
33852
- }
33853
- function sleep(ms) {
33854
- return new Promise((resolve4) => setTimeout(resolve4, ms));
34018
+ function withBashHints(output, command, aftSearchRegistered, projectRoot) {
34019
+ return maybeAppendGrepSearchHint(maybeAppendConflictsHint(output), command, aftSearchRegistered, projectRoot);
33855
34020
  }
33856
34021
  function createBashStatusTool(ctx) {
33857
34022
  return {
@@ -34018,6 +34183,9 @@ async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFo
34018
34183
  keepBridgeOnTimeout: true,
34019
34184
  transportTimeoutMs: BASH_TRANSPORT_TIMEOUT_MS
34020
34185
  };
34186
+ if (waitFor?.kind === "regex") {
34187
+ await validateWaitRegex(bridge, extCtx, waitFor);
34188
+ }
34021
34189
  const sessionId = resolveSessionId(extCtx);
34022
34190
  clearSyncWatchAbort(sessionId);
34023
34191
  if (waitForExit)
@@ -34034,7 +34202,12 @@ async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFo
34034
34202
  if (scanText.length === 0)
34035
34203
  scanBaseOffset = scan.baseOffset;
34036
34204
  scanText += scan.text;
34037
- const match = findWaitMatch(scanText, waitFor);
34205
+ if (waitFor.kind === "regex") {
34206
+ const trimmed = trimWaitScanBuffer(scanText, scanBaseOffset, waitFor);
34207
+ scanText = trimmed.text;
34208
+ scanBaseOffset = trimmed.baseOffset;
34209
+ }
34210
+ const match = await findWaitMatch(bridge, extCtx, scanText, waitFor);
34038
34211
  if (match) {
34039
34212
  if (waitForExit && terminal) {
34040
34213
  sawTerminal = true;
@@ -34045,9 +34218,14 @@ async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFo
34045
34218
  reason: "matched",
34046
34219
  elapsed_ms: Date.now() - startedAt,
34047
34220
  match: match.text,
34048
- match_offset: scanBaseOffset + Buffer.byteLength(scanText.slice(0, match.index), "utf8")
34221
+ match_offset: scanBaseOffset + match.byteOffset
34049
34222
  });
34050
34223
  }
34224
+ if (waitFor.kind === "substring") {
34225
+ const trimmed = trimWaitScanBuffer(scanText, scanBaseOffset, waitFor);
34226
+ scanText = trimmed.text;
34227
+ scanBaseOffset = trimmed.baseOffset;
34228
+ }
34051
34229
  }
34052
34230
  }
34053
34231
  if (terminal) {
@@ -34133,20 +34311,69 @@ function parseWaitPattern(value) {
34133
34311
  if (typeof value === "string")
34134
34312
  return { kind: "substring", value };
34135
34313
  if (isRegexWaitObject(value))
34136
- return { kind: "regex", value: new RegExp(value.regex), source: value.regex };
34314
+ return { kind: "regex", source: value.regex };
34137
34315
  return;
34138
34316
  }
34139
34317
  function isRegexWaitObject(value) {
34140
34318
  return typeof value === "object" && value !== null && "regex" in value && typeof value.regex === "string";
34141
34319
  }
34142
- function findWaitMatch(text, pattern) {
34320
+ async function validateWaitRegex(bridge, extCtx, pattern) {
34321
+ await matchRegexWithBridge(bridge, extCtx, pattern.source, "");
34322
+ }
34323
+ async function findWaitMatch(bridge, extCtx, text, pattern) {
34143
34324
  if (pattern.kind === "substring") {
34144
34325
  const index = text.indexOf(pattern.value);
34145
- return index >= 0 ? { text: pattern.value, index } : undefined;
34326
+ return index >= 0 ? { text: pattern.value, byteOffset: Buffer.byteLength(text.slice(0, index), "utf8") } : undefined;
34327
+ }
34328
+ return await matchRegexWithBridge(bridge, extCtx, pattern.source, text);
34329
+ }
34330
+ async function matchRegexWithBridge(bridge, extCtx, pattern, text) {
34331
+ try {
34332
+ const result = await callBashBridge(bridge, "bash_regex_match", { pattern, text }, extCtx);
34333
+ if (result.matched !== true)
34334
+ return;
34335
+ return {
34336
+ text: typeof result.match_text === "string" ? result.match_text : "",
34337
+ byteOffset: coerceMatchOffset(result.match_offset)
34338
+ };
34339
+ } catch (err) {
34340
+ if (err instanceof BridgeError && err.code === "invalid_regex") {
34341
+ throw new Error(`invalid_request: invalid_regex: ${err.message}`);
34342
+ }
34343
+ throw err;
34146
34344
  }
34147
- pattern.value.lastIndex = 0;
34148
- const match = pattern.value.exec(text);
34149
- return match ? { text: match[0], index: match.index } : undefined;
34345
+ }
34346
+ function coerceMatchOffset(value) {
34347
+ const offset = typeof value === "number" ? value : Number(value ?? 0);
34348
+ return Number.isFinite(offset) && offset >= 0 ? offset : 0;
34349
+ }
34350
+ function trimWaitScanBuffer(text, baseOffset, pattern) {
34351
+ const keepFrom = pattern.kind === "substring" ? substringKeepStart(text, pattern.value) : regexKeepStart(text, REGEX_WAIT_SCAN_WINDOW_BYTES);
34352
+ if (keepFrom <= 0)
34353
+ return { text, baseOffset };
34354
+ return {
34355
+ text: text.slice(keepFrom),
34356
+ baseOffset: baseOffset + Buffer.byteLength(text.slice(0, keepFrom), "utf8")
34357
+ };
34358
+ }
34359
+ function substringKeepStart(text, pattern) {
34360
+ const keepChars = Math.max(0, pattern.length - 1);
34361
+ return text.length > keepChars ? text.length - keepChars : 0;
34362
+ }
34363
+ function regexKeepStart(text, maxBytes) {
34364
+ if (Buffer.byteLength(text, "utf8") <= maxBytes)
34365
+ return 0;
34366
+ let low = 0;
34367
+ let high = text.length;
34368
+ while (low < high) {
34369
+ const mid = Math.floor((low + high) / 2);
34370
+ if (Buffer.byteLength(text.slice(mid), "utf8") > maxBytes) {
34371
+ low = mid + 1;
34372
+ } else {
34373
+ high = mid;
34374
+ }
34375
+ }
34376
+ return low;
34150
34377
  }
34151
34378
  function withWaited(data, waited) {
34152
34379
  return { ...data, waited };
@@ -34222,9 +34449,6 @@ function ptyCacheKey(extCtx, taskId) {
34222
34449
  function watchPtyCacheKey(extCtx, taskId) {
34223
34450
  return `${ptyCacheKey(extCtx, taskId)}::watch`;
34224
34451
  }
34225
- function isTerminalStatus(status) {
34226
- return status === "completed" || status === "failed" || status === "killed" || status === "timed_out";
34227
- }
34228
34452
  function renderBashCall(command, description, theme, context) {
34229
34453
  const text = reuseText3(context.lastComponent);
34230
34454
  const display = description ?? (command ? shortenCommand(command) : "...");
@@ -34328,12 +34552,12 @@ function registerConflictsTool(pi, ctx) {
34328
34552
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
34329
34553
  const bridge = bridgeFor(ctx, extCtx.cwd);
34330
34554
  const reqParams = {};
34331
- const path2 = params?.path;
34332
- if (typeof path2 === "string" && path2.trim() !== "") {
34333
- await assertExternalDirectoryPermission(extCtx, path2, "inspect", {
34555
+ const path3 = params?.path;
34556
+ if (typeof path3 === "string" && path3.trim() !== "") {
34557
+ await assertExternalDirectoryPermission(extCtx, path3, "inspect", {
34334
34558
  restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
34335
34559
  });
34336
- reqParams.path = await resolvePathArg(extCtx.cwd, path2);
34560
+ reqParams.path = await resolvePathArg(extCtx.cwd, path3);
34337
34561
  }
34338
34562
  const response = await callBridge(bridge, "git_conflicts", reqParams, extCtx);
34339
34563
  return textResult(response.text ?? JSON.stringify(response, null, 2));
@@ -34732,8 +34956,8 @@ function tier2SummaryPart(summary, key, label) {
34732
34956
  return `${label} ${status ?? "unavailable"}`;
34733
34957
  }
34734
34958
  function shortDupOccurrence(entry) {
34735
- const [path2] = entry.split(":");
34736
- return path2?.split("/").pop() ?? entry;
34959
+ const [path3] = entry.split(":");
34960
+ return path3?.split("/").pop() ?? entry;
34737
34961
  }
34738
34962
  function tier2TopPreview(summary, theme) {
34739
34963
  const lines = [];
@@ -34942,9 +35166,9 @@ function depthWarning(response, theme, depthField = "depth_limited", truncatedFi
34942
35166
  const detail = truncated > 0 ? `, ${truncated} truncated` : "";
34943
35167
  return theme.fg("warning", `(depth limited${detail})`);
34944
35168
  }
34945
- function renderTracePath(path2, index, lines) {
35169
+ function renderTracePath(path3, index, lines) {
34946
35170
  lines.push(`Path ${index + 1}`);
34947
- asRecords(path2.hops).forEach((hop, hopIndex) => {
35171
+ asRecords(path3.hops).forEach((hop, hopIndex) => {
34948
35172
  const symbol2 = asString(hop.symbol) ?? "(unknown)";
34949
35173
  const file2 = shortenPath2(asString(hop.file) ?? "(unknown file)");
34950
35174
  const line = asNumber(hop.line);
@@ -34982,15 +35206,15 @@ function buildNavigateSections(args, payload, theme) {
34982
35206
  return sections2;
34983
35207
  }
34984
35208
  if (args.op === "trace_to_symbol") {
34985
- const path2 = asRecords(response.path);
35209
+ const path3 = asRecords(response.path);
34986
35210
  const complete = asBoolean(response.complete);
34987
35211
  const reason = asString(response.reason);
34988
- if (path2.length === 0) {
35212
+ if (path3.length === 0) {
34989
35213
  const prefix = complete === false ? theme.fg("warning", "No complete path") : theme.fg("muted", "No path");
34990
35214
  return [`${prefix}${reason ? ` (${reason})` : ""}`];
34991
35215
  }
34992
- const lines = [theme.fg("success", `${path2.length} hop${path2.length === 1 ? "" : "s"}`)];
34993
- path2.forEach((hop, index) => {
35216
+ const lines = [theme.fg("success", `${path3.length} hop${path3.length === 1 ? "" : "s"}`)];
35217
+ path3.forEach((hop, index) => {
34994
35218
  const symbol2 = asString(hop.symbol) ?? "(unknown)";
34995
35219
  const file2 = shortenPath2(asString(hop.file) ?? "(unknown file)");
34996
35220
  const line = asNumber(hop.line);
@@ -35006,9 +35230,9 @@ function buildNavigateSections(args, payload, theme) {
35006
35230
  ];
35007
35231
  if (paths.length === 0)
35008
35232
  sections2.push(theme.fg("muted", "No entry paths found."));
35009
- paths.forEach((path2, index) => {
35233
+ paths.forEach((path3, index) => {
35010
35234
  const lines = [];
35011
- renderTracePath(path2, index, lines);
35235
+ renderTracePath(path3, index, lines);
35012
35236
  sections2.push(lines.join(`
35013
35237
  `));
35014
35238
  });
@@ -35466,6 +35690,11 @@ Pass a single \`target\`:
35466
35690
  }));
35467
35691
  if (symbolsArray.length === 1) {
35468
35692
  const response2 = results[0] ?? { success: false, message: "missing zoom response" };
35693
+ const rustBatch = unwrapRustZoomBatchEnvelope(response2);
35694
+ if (rustBatch) {
35695
+ const batch2 = formatZoomBatchResult(targetLabel, rustBatch.names, rustBatch.responses);
35696
+ return textResult(batch2.text, batch2);
35697
+ }
35469
35698
  if (response2.success === false) {
35470
35699
  throw new Error(response2.message || "zoom failed");
35471
35700
  }
@@ -35701,7 +35930,7 @@ function registerRefactorTool(pi, ctx) {
35701
35930
  import { StringEnum as StringEnum5 } from "@earendil-works/pi-ai";
35702
35931
  import { Type as Type12 } from "typebox";
35703
35932
  function responsePaths(response) {
35704
- return Array.isArray(response.paths) ? response.paths.filter((path2) => typeof path2 === "string" && path2.length > 0) : [];
35933
+ return Array.isArray(response.paths) ? response.paths.filter((path3) => typeof path3 === "string" && path3.length > 0) : [];
35705
35934
  }
35706
35935
  var SafetyParams = Type12.Object({
35707
35936
  op: StringEnum5(["undo", "history", "checkpoint", "restore", "list"], {
@@ -36167,18 +36396,18 @@ function createVersionMismatchHandler(getPool, ensureCompatibleBinary = ensureBi
36167
36396
  const upgradePromise = (async () => {
36168
36397
  warn2(`WARNING: aft binary v${binaryVersion} is older than plugin v${minVersion}. ` + "Some features may not work. Attempting to download a compatible binary...");
36169
36398
  try {
36170
- const path2 = await ensureCompatibleBinary(`v${minVersion}`);
36171
- if (!path2) {
36399
+ const path3 = await ensureCompatibleBinary(`v${minVersion}`);
36400
+ if (!path3) {
36172
36401
  warn2(`Could not find or download v${minVersion}. Continuing with v${binaryVersion}.`);
36173
36402
  return null;
36174
36403
  }
36175
36404
  const pool = getPool();
36176
36405
  if (!pool) {
36177
- warn2(`Found/downloaded compatible binary at ${path2}, but bridge pool is not ready.`);
36406
+ warn2(`Found/downloaded compatible binary at ${path3}, but bridge pool is not ready.`);
36178
36407
  return null;
36179
36408
  }
36180
- log2(`Found/downloaded compatible binary at ${path2}. Replacing running bridges...`);
36181
- const replaced = await pool.replaceBinary(path2);
36409
+ log2(`Found/downloaded compatible binary at ${path3}. Replacing running bridges...`);
36410
+ const replaced = await pool.replaceBinary(path3);
36182
36411
  log2("Binary replaced successfully. New bridges will use the updated binary.");
36183
36412
  return replaced;
36184
36413
  } catch (err) {
@@ -36200,12 +36429,11 @@ var PLUGIN_VERSION = (() => {
36200
36429
  return "0.0.0";
36201
36430
  }
36202
36431
  })();
36203
- var ANNOUNCEMENT_VERSION = "0.38.0";
36432
+ var ANNOUNCEMENT_VERSION = "0.39.0";
36204
36433
  var ANNOUNCEMENT_FEATURES = [
36205
- "Code Health you can trust: dead code and unused exports are back in the status displays, rebuilt on a real TS/JS module-graph engine (oxc) barrel re-exports, entry points, and dynamic imports resolve correctly now.",
36206
- "Tools stay responsive during builds: filesystem events are processed off the request thread, so a cargo/webpack compile no longer queues your tool calls behind an event flood.",
36207
- "Pascal support in outline, zoom, and the AST tools.",
36208
- "Transient environment errors (schema fetch timeouts) no longer count as code errors in the status bar."
36434
+ "Accurate Rust dead code: constructors and associated functions reached through receiver-type inference are no longer mis-reported as dead.",
36435
+ "Code Health scans reparse only the file you changed instead of the whole project on every edit — a single-file edit dropped from ~3s of scan work to ~130ms on this repo, byte-identical results.",
36436
+ "R language support in outline, zoom, and the AST tools."
36209
36437
  ];
36210
36438
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
36211
36439
  var ALL_ONLY_TOOLS = new Set(["aft_callgraph", "aft_delete", "aft_move", "aft_refactor"]);
@@ -36504,7 +36732,7 @@ ${lines}
36504
36732
  if (onnxRuntimePromise) {
36505
36733
  await Promise.race([
36506
36734
  onnxRuntimePromise,
36507
- new Promise((resolve4) => setTimeout(() => resolve4(null), 60000))
36735
+ new Promise((resolve5) => setTimeout(() => resolve5(null), 60000))
36508
36736
  ]);
36509
36737
  }
36510
36738
  const bridge = pool.getBridge(cwd);