@cortexkit/aft-opencode 0.39.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
@@ -7652,10 +7652,10 @@ var require_stringify = __commonJS((exports, module) => {
7652
7652
  replacer = null;
7653
7653
  indent = EMPTY;
7654
7654
  };
7655
- 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)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
7655
+ 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)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
7656
7656
  var join_content = (inside, value, gap) => {
7657
7657
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
7658
- return join9(comment, inside, gap);
7658
+ return join10(comment, inside, gap);
7659
7659
  };
7660
7660
  var stringify_string = (holder, key, value) => {
7661
7661
  const raw = get_raw_string_literal(holder, key);
@@ -7677,13 +7677,13 @@ var require_stringify = __commonJS((exports, module) => {
7677
7677
  if (i !== 0) {
7678
7678
  inside += COMMA;
7679
7679
  }
7680
- const before = join9(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
7680
+ const before = join10(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
7681
7681
  inside += before || LF + deeper_gap;
7682
7682
  inside += stringify(i, value, deeper_gap) || STR_NULL;
7683
7683
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
7684
7684
  after_comma = process_comments(value, AFTER(i), deeper_gap);
7685
7685
  }
7686
- inside += join9(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7686
+ inside += join10(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7687
7687
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
7688
7688
  };
7689
7689
  var object_stringify = (value, gap) => {
@@ -7704,13 +7704,13 @@ var require_stringify = __commonJS((exports, module) => {
7704
7704
  inside += COMMA;
7705
7705
  }
7706
7706
  first = false;
7707
- const before = join9(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
7707
+ const before = join10(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
7708
7708
  inside += before || LF + deeper_gap;
7709
7709
  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);
7710
7710
  after_comma = process_comments(value, AFTER(key), deeper_gap);
7711
7711
  };
7712
7712
  keys.forEach(iteratee);
7713
- inside += join9(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7713
+ inside += join10(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
7714
7714
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
7715
7715
  };
7716
7716
  function stringify(key, holder, gap) {
@@ -11593,7 +11593,45 @@ function error(message, meta) {
11593
11593
  console.error(`[aft-bridge] ERROR: ${message}`);
11594
11594
  }
11595
11595
  }
11596
+ // ../aft-bridge/dist/bash-format.js
11597
+ function appendPipeStripNote(output, note) {
11598
+ return note ? `${output}
11599
+
11600
+ ${note}` : output;
11601
+ }
11602
+ function formatSeconds(ms) {
11603
+ return `${Number((ms / 1000).toFixed(1))}s`;
11604
+ }
11605
+ function formatForegroundResult(data) {
11606
+ const output = data.output_preview ?? "";
11607
+ const outputPath = data.output_path;
11608
+ const truncated = data.output_truncated === true;
11609
+ const status = data.status;
11610
+ const exit = data.exit_code;
11611
+ let rendered = output;
11612
+ if (truncated && outputPath) {
11613
+ rendered += `
11614
+ [output truncated; full output at ${outputPath}]`;
11615
+ }
11616
+ if (status === "timed_out") {
11617
+ rendered += `
11618
+ [command timed out]`;
11619
+ }
11620
+ if (typeof exit === "number" && exit !== 0) {
11621
+ rendered += `
11622
+ [exit code: ${exit}]`;
11623
+ }
11624
+ return rendered;
11625
+ }
11626
+ function isTerminalStatus(status) {
11627
+ return status === "completed" || status === "failed" || status === "killed" || status === "timed_out";
11628
+ }
11629
+ function sleep(ms) {
11630
+ return new Promise((resolve) => setTimeout(resolve, ms));
11631
+ }
11596
11632
  // ../aft-bridge/dist/bash-hints.js
11633
+ import * as os from "node:os";
11634
+ import * as path from "node:path";
11597
11635
  var CONFLICT_HINT = `
11598
11636
 
11599
11637
  [Hint] Use aft_conflicts to see all conflict regions across files in a single call.`;
@@ -11623,18 +11661,87 @@ function commandInvokesCodeSearch(command) {
11623
11661
  }
11624
11662
  return false;
11625
11663
  }
11626
- function maybeAppendGrepSearchHint(output, command, aftSearchRegistered) {
11664
+ function maybeAppendGrepSearchHint(output, command, aftSearchRegistered, projectRoot) {
11627
11665
  if (output === "")
11628
11666
  return output;
11629
11667
  if (!commandInvokesCodeSearch(command))
11630
11668
  return output;
11631
11669
  if (output.includes(GREP_SEARCH_HINT_PREFIX))
11632
11670
  return output;
11671
+ if (shouldSuppressGrepSearchHint(command, projectRoot))
11672
+ return output;
11633
11673
  const hint = aftSearchRegistered ? GREP_SEARCH_AFT_SEARCH_HINT : GREP_SEARCH_GREP_HINT;
11634
11674
  return `${output}
11635
11675
 
11636
11676
  ${hint}`;
11637
11677
  }
11678
+ function shouldSuppressGrepSearchHint(command, projectRoot) {
11679
+ const root = projectRoot?.trim();
11680
+ if (!root)
11681
+ return false;
11682
+ const statements = splitTopLevelStatements(command);
11683
+ if (statements === null)
11684
+ return false;
11685
+ let sawCodeSearchStatement = false;
11686
+ for (const statement of statements) {
11687
+ const firstStage = firstPipelineStage(statement);
11688
+ if (firstStage === null)
11689
+ continue;
11690
+ const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
11691
+ if (firstToken === null)
11692
+ continue;
11693
+ if (firstToken.token !== "grep" && firstToken.token !== "rg")
11694
+ continue;
11695
+ sawCodeSearchStatement = true;
11696
+ const operands = collectPathOperands(firstStage, firstToken.end);
11697
+ if (operands.length === 0)
11698
+ return false;
11699
+ for (const operand of operands) {
11700
+ if (isPathInsideProject(root, operand))
11701
+ return false;
11702
+ }
11703
+ }
11704
+ return sawCodeSearchStatement;
11705
+ }
11706
+ function collectPathOperands(firstStage, startAfterCommand) {
11707
+ const operands = [];
11708
+ let index = skipSpaces(firstStage, startAfterCommand);
11709
+ while (index < firstStage.length) {
11710
+ const tokenResult = readShellToken(firstStage, index);
11711
+ if (tokenResult === null)
11712
+ break;
11713
+ const { token, end } = tokenResult;
11714
+ if (end <= index)
11715
+ break;
11716
+ index = skipSpaces(firstStage, end);
11717
+ if (token.startsWith("-"))
11718
+ continue;
11719
+ if (looksLikePathOperand(token))
11720
+ operands.push(token);
11721
+ }
11722
+ return operands;
11723
+ }
11724
+ function looksLikePathOperand(token) {
11725
+ return token.includes("/") || token.startsWith("~") || token.startsWith("./") || token.startsWith("../");
11726
+ }
11727
+ function expandTilde(target) {
11728
+ if (!target.startsWith("~"))
11729
+ return target;
11730
+ if (target === "~" || target.startsWith("~/")) {
11731
+ return path.join(os.homedir(), target.slice(1));
11732
+ }
11733
+ return target;
11734
+ }
11735
+ function resolvePathOperand(projectRoot, operand) {
11736
+ const expanded = expandTilde(operand);
11737
+ return path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(projectRoot, expanded);
11738
+ }
11739
+ function isPathInsideProject(projectRoot, operand) {
11740
+ const root = path.resolve(projectRoot);
11741
+ const resolved = resolvePathOperand(root, operand);
11742
+ const rel = path.relative(root, resolved);
11743
+ return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
11744
+ }
11638
11745
  function splitTopLevelStatements(command) {
11639
11746
  const statements = [];
11640
11747
  let start = 0;
@@ -11814,8 +11921,8 @@ function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
11814
11921
  }
11815
11922
  // ../aft-bridge/dist/bridge.js
11816
11923
  import { spawn } from "node:child_process";
11817
- import { homedir } from "node:os";
11818
- import { join } from "node:path";
11924
+ import { homedir as homedir2 } from "node:os";
11925
+ import { join as join2 } from "node:path";
11819
11926
  import { StringDecoder } from "node:string_decoder";
11820
11927
 
11821
11928
  // ../aft-bridge/dist/command-timeouts.js
@@ -12193,7 +12300,7 @@ class BinaryBridge {
12193
12300
  `;
12194
12301
  const keepBridgeOnTimeout = options?.keepBridgeOnTimeout === true;
12195
12302
  let requestSentAt = Date.now();
12196
- const response = await new Promise((resolve, reject) => {
12303
+ const response = await new Promise((resolve2, reject) => {
12197
12304
  const timer = setTimeout(() => {
12198
12305
  const entry = this.pending.get(id);
12199
12306
  if (!entry)
@@ -12228,7 +12335,7 @@ class BinaryBridge {
12228
12335
  entry.reject(new Error(`${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
12229
12336
  this.handleTimeout(requestSessionId);
12230
12337
  }, effectiveTimeoutMs);
12231
- this.pending.set(id, { resolve, reject, timer, onProgress: options?.onProgress, command });
12338
+ this.pending.set(id, { resolve: resolve2, reject, timer, onProgress: options?.onProgress, command });
12232
12339
  if (!this.process?.stdin?.writable) {
12233
12340
  this.pending.delete(id);
12234
12341
  clearTimeout(timer);
@@ -12326,15 +12433,15 @@ class BinaryBridge {
12326
12433
  if (this.process) {
12327
12434
  const proc = this.process;
12328
12435
  this.process = null;
12329
- return new Promise((resolve) => {
12436
+ return new Promise((resolve2) => {
12330
12437
  const forceKillTimer = setTimeout(() => {
12331
12438
  proc.kill("SIGKILL");
12332
- resolve();
12439
+ resolve2();
12333
12440
  }, 5000);
12334
12441
  proc.once("exit", () => {
12335
12442
  clearTimeout(forceKillTimer);
12336
12443
  this.logVia("Process exited during shutdown");
12337
- resolve();
12444
+ resolve2();
12338
12445
  });
12339
12446
  proc.kill("SIGTERM");
12340
12447
  });
@@ -12379,15 +12486,15 @@ class BinaryBridge {
12379
12486
  return;
12380
12487
  const proc = this.process;
12381
12488
  this.process = null;
12382
- await new Promise((resolve) => {
12489
+ await new Promise((resolve2) => {
12383
12490
  const forceKillTimer = setTimeout(() => {
12384
12491
  proc.kill("SIGKILL");
12385
- resolve();
12492
+ resolve2();
12386
12493
  }, 5000);
12387
12494
  proc.once("exit", () => {
12388
12495
  clearTimeout(forceKillTimer);
12389
12496
  this.logVia("Process exited during coordinated binary replacement");
12390
- resolve();
12497
+ resolve2();
12391
12498
  });
12392
12499
  proc.kill("SIGTERM");
12393
12500
  });
@@ -12414,7 +12521,7 @@ class BinaryBridge {
12414
12521
  })();
12415
12522
  const useFastembedBackend = semanticBackend === undefined || semanticBackend === "fastembed" || semanticBackend === "";
12416
12523
  const ortDir = typeof this.configOverrides._ort_dylib_dir === "string" && useFastembedBackend ? this.configOverrides._ort_dylib_dir : null;
12417
- const ortLibraryPath = ortDir == null ? null : join(ortDir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
12524
+ const ortLibraryPath = ortDir == null ? null : join2(ortDir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
12418
12525
  const envPath = process.platform === "win32" && ortDir ? `${ortDir};${process.env.PATH ?? ""}` : process.env.PATH;
12419
12526
  const env = {
12420
12527
  ...process.env,
@@ -12422,7 +12529,7 @@ class BinaryBridge {
12422
12529
  };
12423
12530
  this.logVia(`bridge.spawnProcess: useFastembedBackend=${useFastembedBackend}, ` + `parentORT=${process.env.ORT_DYLIB_PATH ?? "(unset)"}, ` + `ortLibraryPath=${ortLibraryPath ?? "(none)"}`);
12424
12531
  if (useFastembedBackend) {
12425
- 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"));
12532
+ 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"));
12426
12533
  if (process.env.ORT_DYLIB_PATH) {
12427
12534
  this.logVia(`ORT_DYLIB_PATH inherited from parent env: ${process.env.ORT_DYLIB_PATH}`);
12428
12535
  } else if (ortLibraryPath) {
@@ -12764,12 +12871,23 @@ function coerceStringArray(value) {
12764
12871
  }
12765
12872
  return [];
12766
12873
  }
12874
+ function isEmptyParam(value) {
12875
+ if (value === undefined || value === null)
12876
+ return true;
12877
+ if (typeof value === "string")
12878
+ return value.length === 0;
12879
+ if (Array.isArray(value))
12880
+ return value.length === 0;
12881
+ if (typeof value === "object")
12882
+ return Object.keys(value).length === 0;
12883
+ return false;
12884
+ }
12767
12885
  // ../aft-bridge/dist/downloader.js
12768
12886
  import { spawnSync } from "node:child_process";
12769
12887
  import { createHash, randomUUID } from "node:crypto";
12770
12888
  import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
12771
- import { homedir as homedir2 } from "node:os";
12772
- import { join as join2 } from "node:path";
12889
+ import { homedir as homedir3 } from "node:os";
12890
+ import { join as join3 } from "node:path";
12773
12891
  import { Readable } from "node:stream";
12774
12892
  import { pipeline } from "node:stream/promises";
12775
12893
 
@@ -12826,11 +12944,11 @@ function isExpectedCachedBinary(binaryPath, tag) {
12826
12944
  function getCacheDir() {
12827
12945
  if (process.platform === "win32") {
12828
12946
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
12829
- const base2 = localAppData || join2(homedir2(), "AppData", "Local");
12830
- return join2(base2, "aft", "bin");
12947
+ const base2 = localAppData || join3(homedir3(), "AppData", "Local");
12948
+ return join3(base2, "aft", "bin");
12831
12949
  }
12832
- const base = process.env.XDG_CACHE_HOME || join2(homedir2(), ".cache");
12833
- return join2(base, "aft", "bin");
12950
+ const base = process.env.XDG_CACHE_HOME || join3(homedir3(), ".cache");
12951
+ return join3(base, "aft", "bin");
12834
12952
  }
12835
12953
  function getBinaryName() {
12836
12954
  return process.platform === "win32" ? "aft.exe" : "aft";
@@ -12838,7 +12956,7 @@ function getBinaryName() {
12838
12956
  function getCachedBinaryPath(version) {
12839
12957
  if (!version)
12840
12958
  return null;
12841
- const binaryPath = join2(getCacheDir(), version, getBinaryName());
12959
+ const binaryPath = join3(getCacheDir(), version, getBinaryName());
12842
12960
  return existsSync(binaryPath) ? binaryPath : null;
12843
12961
  }
12844
12962
  async function downloadBinary(version) {
@@ -12855,16 +12973,16 @@ async function downloadBinary(version) {
12855
12973
  return null;
12856
12974
  }
12857
12975
  const tag = rawTag.startsWith("v") ? rawTag : `v${rawTag}`;
12858
- const versionedCacheDir = join2(getCacheDir(), tag);
12976
+ const versionedCacheDir = join3(getCacheDir(), tag);
12859
12977
  const binaryName = getBinaryName();
12860
- const binaryPath = join2(versionedCacheDir, binaryName);
12978
+ const binaryPath = join3(versionedCacheDir, binaryName);
12861
12979
  if (existsSync(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
12862
12980
  return binaryPath;
12863
12981
  }
12864
12982
  const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
12865
12983
  const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
12866
12984
  log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
12867
- const lockPath = join2(versionedCacheDir, ".download.lock");
12985
+ const lockPath = join3(versionedCacheDir, ".download.lock");
12868
12986
  let releaseLock = null;
12869
12987
  let binaryController = null;
12870
12988
  let checksumController = null;
@@ -13016,7 +13134,7 @@ async function acquireDownloadLock(lockPath) {
13016
13134
  if (Date.now() - startedAt > DOWNLOAD_LOCK_TIMEOUT_MS) {
13017
13135
  throw new Error(`Timed out waiting for download lock: ${lockPath}`);
13018
13136
  }
13019
- await new Promise((resolve) => setTimeout(resolve, 100));
13137
+ await new Promise((resolve2) => setTimeout(resolve2, 100));
13020
13138
  }
13021
13139
  }
13022
13140
  }
@@ -13102,18 +13220,18 @@ function stripJsoncSymbols(value) {
13102
13220
  // ../aft-bridge/dist/migration.js
13103
13221
  import { spawnSync as spawnSync2 } from "node:child_process";
13104
13222
  import { existsSync as existsSync4, mkdirSync as mkdirSync4 } from "node:fs";
13105
- import { homedir as homedir4, tmpdir } from "node:os";
13106
- import { dirname as dirname2, join as join5 } from "node:path";
13223
+ import { homedir as homedir5, tmpdir } from "node:os";
13224
+ import { dirname as dirname2, join as join6 } from "node:path";
13107
13225
 
13108
13226
  // ../aft-bridge/dist/paths.js
13109
13227
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync } from "node:fs";
13110
- import { dirname, join as join3 } from "node:path";
13228
+ import { dirname, join as join4 } from "node:path";
13111
13229
  function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
13112
- return join3(storageRoot, harness, ...segments);
13230
+ return join4(storageRoot, harness, ...segments);
13113
13231
  }
13114
13232
  function repairRootScopedStorageFile(storageRoot, harness, fileName) {
13115
13233
  const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
13116
- const rootPath = join3(storageRoot, fileName);
13234
+ const rootPath = join4(storageRoot, fileName);
13117
13235
  if (existsSync2(harnessPath) || !existsSync2(rootPath))
13118
13236
  return harnessPath;
13119
13237
  try {
@@ -13159,8 +13277,8 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
13159
13277
  import { execSync } from "node:child_process";
13160
13278
  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";
13161
13279
  import { createRequire as createRequire2 } from "node:module";
13162
- import { homedir as homedir3 } from "node:os";
13163
- import { join as join4 } from "node:path";
13280
+ import { homedir as homedir4 } from "node:os";
13281
+ import { join as join5 } from "node:path";
13164
13282
  var ensureBinaryForResolver = ensureBinary;
13165
13283
  function copyToVersionedCache(npmBinaryPath, knownVersion) {
13166
13284
  try {
@@ -13169,9 +13287,9 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
13169
13287
  return null;
13170
13288
  const tag = version.startsWith("v") ? version : `v${version}`;
13171
13289
  const cacheDir = getCacheDir();
13172
- const versionedDir = join4(cacheDir, tag);
13290
+ const versionedDir = join5(cacheDir, tag);
13173
13291
  const ext = process.platform === "win32" ? ".exe" : "";
13174
- const cachedPath = join4(versionedDir, `aft${ext}`);
13292
+ const cachedPath = join5(versionedDir, `aft${ext}`);
13175
13293
  if (existsSync3(cachedPath)) {
13176
13294
  const cachedVersion = readBinaryVersion(cachedPath);
13177
13295
  if (cachedVersion === version)
@@ -13201,18 +13319,18 @@ function normalizeBareVersion(version) {
13201
13319
  return version.startsWith("v") ? version.slice(1) : version;
13202
13320
  }
13203
13321
  function homeDirFromEnv(env) {
13204
- return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir3();
13322
+ return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir4();
13205
13323
  }
13206
13324
  function cacheDirFromEnv(env) {
13207
13325
  if (process.platform === "win32") {
13208
- const base2 = env.LOCALAPPDATA || env.APPDATA || join4(homeDirFromEnv(env), "AppData", "Local");
13209
- return join4(base2, "aft", "bin");
13326
+ const base2 = env.LOCALAPPDATA || env.APPDATA || join5(homeDirFromEnv(env), "AppData", "Local");
13327
+ return join5(base2, "aft", "bin");
13210
13328
  }
13211
- const base = env.XDG_CACHE_HOME || join4(homeDirFromEnv(env), ".cache");
13212
- return join4(base, "aft", "bin");
13329
+ const base = env.XDG_CACHE_HOME || join5(homeDirFromEnv(env), ".cache");
13330
+ return join5(base, "aft", "bin");
13213
13331
  }
13214
13332
  function cachedBinaryPathFromEnv(version, env, ext) {
13215
- const binaryPath = join4(cacheDirFromEnv(env), version, `aft${ext}`);
13333
+ const binaryPath = join5(cacheDirFromEnv(env), version, `aft${ext}`);
13216
13334
  return existsSync3(binaryPath) ? binaryPath : null;
13217
13335
  }
13218
13336
  function isExpectedCachedBinary2(binaryPath, expectedVersion) {
@@ -13331,7 +13449,7 @@ function findBinarySync(expectedVersion) {
13331
13449
  return usable;
13332
13450
  }
13333
13451
  } catch {}
13334
- const cargoPath = join4(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
13452
+ const cargoPath = join5(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
13335
13453
  if (existsSync3(cargoPath)) {
13336
13454
  const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
13337
13455
  if (usable)
@@ -13377,22 +13495,22 @@ function dataHome() {
13377
13495
  if (process.env.XDG_DATA_HOME)
13378
13496
  return process.env.XDG_DATA_HOME;
13379
13497
  if (process.platform === "win32") {
13380
- return process.env.LOCALAPPDATA || process.env.APPDATA || join5(homeDir(), "AppData", "Local");
13498
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join6(homeDir(), "AppData", "Local");
13381
13499
  }
13382
- return join5(homeDir(), ".local", "share");
13500
+ return join6(homeDir(), ".local", "share");
13383
13501
  }
13384
13502
  function homeDir() {
13385
13503
  if (process.platform === "win32")
13386
- return process.env.USERPROFILE || process.env.HOME || homedir4();
13387
- return process.env.HOME || homedir4();
13504
+ return process.env.USERPROFILE || process.env.HOME || homedir5();
13505
+ return process.env.HOME || homedir5();
13388
13506
  }
13389
13507
  function resolveLegacyStorageRoot(harness) {
13390
13508
  if (harness === "pi")
13391
- return join5(homeDir(), ".pi", "agent", "aft");
13392
- return join5(dataHome(), "opencode", "storage", "plugin", "aft");
13509
+ return join6(homeDir(), ".pi", "agent", "aft");
13510
+ return join6(dataHome(), "opencode", "storage", "plugin", "aft");
13393
13511
  }
13394
13512
  function resolveCortexKitStorageRoot() {
13395
- return join5(dataHome(), "cortexkit", "aft");
13513
+ return join6(dataHome(), "cortexkit", "aft");
13396
13514
  }
13397
13515
  function tail(value) {
13398
13516
  if (!value)
@@ -13406,12 +13524,12 @@ function spawnErrorLabel(error2) {
13406
13524
  return [code, error2.message].filter(Boolean).join(": ");
13407
13525
  }
13408
13526
  function migrationLogPath(newRoot, harness, logger) {
13409
- const desired = join5(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
13527
+ const desired = join6(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
13410
13528
  try {
13411
13529
  mkdirSync4(dirname2(desired), { recursive: true });
13412
13530
  return desired;
13413
13531
  } catch (err) {
13414
- const fallback = join5(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
13532
+ const fallback = join6(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
13415
13533
  logger?.warn?.(`Failed to create AFT migration log directory ${dirname2(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
13416
13534
  return fallback;
13417
13535
  }
@@ -13474,13 +13592,13 @@ async function ensureStorageMigrated(opts) {
13474
13592
  }
13475
13593
  // ../aft-bridge/dist/npm-resolver.js
13476
13594
  import { readdirSync, statSync as statSync2 } from "node:fs";
13477
- import { homedir as homedir5 } from "node:os";
13478
- import { delimiter, dirname as dirname3, isAbsolute, join as join6 } from "node:path";
13595
+ import { homedir as homedir6 } from "node:os";
13596
+ import { delimiter, dirname as dirname3, isAbsolute as isAbsolute2, join as join7 } from "node:path";
13479
13597
  function defaultDeps() {
13480
13598
  return {
13481
13599
  platform: process.platform,
13482
13600
  env: process.env,
13483
- home: homedir5(),
13601
+ home: homedir6(),
13484
13602
  execPath: process.execPath
13485
13603
  };
13486
13604
  }
@@ -13499,16 +13617,16 @@ function npmFromPath(deps) {
13499
13617
  const raw = deps.env.PATH ?? deps.env.Path ?? "";
13500
13618
  for (const entry of raw.split(delimiter)) {
13501
13619
  const dir = entry.trim().replace(/^"|"$/g, "");
13502
- if (!dir || !isAbsolute(dir))
13620
+ if (!dir || !isAbsolute2(dir))
13503
13621
  continue;
13504
- if (isFile(join6(dir, name)))
13622
+ if (isFile(join7(dir, name)))
13505
13623
  return dir;
13506
13624
  }
13507
13625
  return null;
13508
13626
  }
13509
13627
  function npmAdjacentToNode(deps) {
13510
13628
  const dir = dirname3(deps.execPath);
13511
- return isFile(join6(dir, npmBinaryName(deps.platform))) ? dir : null;
13629
+ return isFile(join7(dir, npmBinaryName(deps.platform))) ? dir : null;
13512
13630
  }
13513
13631
  function highestVersionedNodeBin(installsDir, name) {
13514
13632
  let entries;
@@ -13517,8 +13635,8 @@ function highestVersionedNodeBin(installsDir, name) {
13517
13635
  } catch {
13518
13636
  return null;
13519
13637
  }
13520
- const candidates = entries.filter((v) => isFile(join6(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
13521
- return candidates.length > 0 ? join6(installsDir, candidates[0], "bin") : null;
13638
+ const candidates = entries.filter((v) => isFile(join7(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
13639
+ return candidates.length > 0 ? join7(installsDir, candidates[0], "bin") : null;
13522
13640
  }
13523
13641
  function compareVersionsDesc(a, b) {
13524
13642
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -13543,22 +13661,22 @@ function wellKnownNpmDirs(deps) {
13543
13661
  const programFiles = env.ProgramFiles || "C:\\Program Files";
13544
13662
  const appData = env.APPDATA;
13545
13663
  const localAppData = env.LOCALAPPDATA;
13546
- push(join6(programFiles, "nodejs"));
13664
+ push(join7(programFiles, "nodejs"));
13547
13665
  if (appData)
13548
- push(join6(appData, "npm"));
13666
+ push(join7(appData, "npm"));
13549
13667
  if (localAppData)
13550
- push(join6(localAppData, "Volta", "bin"));
13668
+ push(join7(localAppData, "Volta", "bin"));
13551
13669
  if (env.NVM_SYMLINK)
13552
13670
  push(env.NVM_SYMLINK);
13553
13671
  } else {
13554
13672
  if (env.NVM_BIN)
13555
13673
  push(env.NVM_BIN);
13556
- push(highestVersionedNodeBin(join6(home, ".nvm", "versions", "node"), name));
13557
- push(highestVersionedNodeBin(join6(home, ".local", "share", "mise", "installs", "node"), name));
13558
- push(highestVersionedNodeBin(join6(home, ".asdf", "installs", "nodejs"), name));
13559
- push(join6(home, ".volta", "bin"));
13560
- push(join6(home, ".asdf", "shims"));
13561
- const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join6(home, ".local", "bin")]);
13674
+ push(highestVersionedNodeBin(join7(home, ".nvm", "versions", "node"), name));
13675
+ push(highestVersionedNodeBin(join7(home, ".local", "share", "mise", "installs", "node"), name));
13676
+ push(highestVersionedNodeBin(join7(home, ".asdf", "installs", "nodejs"), name));
13677
+ push(join7(home, ".volta", "bin"));
13678
+ push(join7(home, ".asdf", "shims"));
13679
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join7(home, ".local", "bin")]);
13562
13680
  for (const dir of systemDirs)
13563
13681
  push(dir);
13564
13682
  }
@@ -13568,12 +13686,12 @@ function resolveNpm(deps = defaultDeps()) {
13568
13686
  const name = npmBinaryName(deps.platform);
13569
13687
  const onPath = npmFromPath(deps);
13570
13688
  if (onPath)
13571
- return { command: join6(onPath, name), binDir: onPath };
13689
+ return { command: join7(onPath, name), binDir: onPath };
13572
13690
  const adjacent = npmAdjacentToNode(deps);
13573
13691
  if (adjacent)
13574
- return { command: join6(adjacent, name), binDir: adjacent };
13692
+ return { command: join7(adjacent, name), binDir: adjacent };
13575
13693
  for (const dir of wellKnownNpmDirs(deps)) {
13576
- const candidate = join6(dir, name);
13694
+ const candidate = join7(dir, name);
13577
13695
  if (isFile(candidate))
13578
13696
  return { command: candidate, binDir: dir };
13579
13697
  }
@@ -13593,7 +13711,7 @@ function isNpmAvailable(deps = defaultDeps()) {
13593
13711
  import { execFileSync } from "node:child_process";
13594
13712
  import { createHash as createHash2 } from "node:crypto";
13595
13713
  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";
13596
- import { basename, dirname as dirname4, isAbsolute as isAbsolute2, join as join7, relative, resolve, win32 } from "node:path";
13714
+ import { basename, dirname as dirname4, isAbsolute as isAbsolute3, join as join8, relative as relative2, resolve as resolve2, win32 } from "node:path";
13597
13715
  import { Readable as Readable2 } from "node:stream";
13598
13716
  import { pipeline as pipeline2 } from "node:stream/promises";
13599
13717
  var ORT_VERSION = "1.24.4";
@@ -13659,10 +13777,10 @@ function getManualInstallHint() {
13659
13777
  }
13660
13778
  async function ensureOnnxRuntime(storageDir) {
13661
13779
  const info = getPlatformInfo();
13662
- const ortVersionDir = join7(storageDir, "onnxruntime", ORT_VERSION);
13780
+ const ortVersionDir = join8(storageDir, "onnxruntime", ORT_VERSION);
13663
13781
  const libName = info?.libName ?? "libonnxruntime.dylib";
13664
13782
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
13665
- const libPath = join7(resolvedOrtDir, libName);
13783
+ const libPath = join8(resolvedOrtDir, libName);
13666
13784
  if (existsSync5(libPath)) {
13667
13785
  const meta = readOnnxInstalledMeta(ortVersionDir);
13668
13786
  if (meta?.sha256) {
@@ -13692,9 +13810,9 @@ async function ensureOnnxRuntime(storageDir) {
13692
13810
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
13693
13811
  return null;
13694
13812
  }
13695
- const onnxBaseDir = join7(storageDir, "onnxruntime");
13813
+ const onnxBaseDir = join8(storageDir, "onnxruntime");
13696
13814
  mkdirSync5(onnxBaseDir, { recursive: true });
13697
- const lockPath = join7(onnxBaseDir, ONNX_LOCK_FILE);
13815
+ const lockPath = join8(onnxBaseDir, ONNX_LOCK_FILE);
13698
13816
  cleanupAbandonedStagingDirs(onnxBaseDir);
13699
13817
  if (!acquireLock(lockPath)) {
13700
13818
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -13713,7 +13831,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
13713
13831
  for (const entry of entries) {
13714
13832
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
13715
13833
  continue;
13716
- const stagingDir = join7(onnxBaseDir, entry);
13834
+ const stagingDir = join8(onnxBaseDir, entry);
13717
13835
  const parts = entry.split(".");
13718
13836
  const pidStr = parts[parts.length - 2];
13719
13837
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -13750,7 +13868,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
13750
13868
  }
13751
13869
  function cleanupIncompleteTargetIfUnowned(ortDir) {
13752
13870
  try {
13753
- if (existsSync5(ortDir) && !existsSync5(join7(ortDir, ONNX_INSTALLED_META_FILE))) {
13871
+ if (existsSync5(ortDir) && !existsSync5(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
13754
13872
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
13755
13873
  rmSync2(ortDir, { recursive: true, force: true });
13756
13874
  }
@@ -13778,8 +13896,8 @@ function parseOnnxVersionFromDirectoryPath(value) {
13778
13896
  return null;
13779
13897
  }
13780
13898
  function isPathInsideRoot(root, candidate) {
13781
- const rel = relative(root, candidate);
13782
- return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute2(rel) && !win32.isAbsolute(rel);
13899
+ const rel = relative2(root, candidate);
13900
+ return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute3(rel) && !win32.isAbsolute(rel);
13783
13901
  }
13784
13902
  function detectOnnxVersion(libDir, libName) {
13785
13903
  try {
@@ -13794,7 +13912,7 @@ function detectOnnxVersion(libDir, libName) {
13794
13912
  if (version)
13795
13913
  return version;
13796
13914
  }
13797
- const base = join7(libDir, libName);
13915
+ const base = join8(libDir, libName);
13798
13916
  if (existsSync5(base)) {
13799
13917
  try {
13800
13918
  const real = realpathSync(base);
@@ -13830,7 +13948,7 @@ function pathEntriesForPlatform() {
13830
13948
  return pathEnvValue().split(delimiter2).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
13831
13949
  if (!entry || entry === "." || entry.includes("\x00"))
13832
13950
  return false;
13833
- return isAbsolute2(entry) || win32.isAbsolute(entry);
13951
+ return isAbsolute3(entry) || win32.isAbsolute(entry);
13834
13952
  });
13835
13953
  }
13836
13954
  function directoryContainsLibrary(dir, libName) {
@@ -13846,10 +13964,10 @@ function directoryContainsLibrary(dir, libName) {
13846
13964
  }
13847
13965
  }
13848
13966
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
13849
- if (existsSync5(join7(ortVersionDir, libName)))
13967
+ if (existsSync5(join8(ortVersionDir, libName)))
13850
13968
  return ortVersionDir;
13851
- const libSubdir = join7(ortVersionDir, "lib");
13852
- if (existsSync5(join7(libSubdir, libName)))
13969
+ const libSubdir = join8(ortVersionDir, "lib");
13970
+ if (existsSync5(join8(libSubdir, libName)))
13853
13971
  return libSubdir;
13854
13972
  return ortVersionDir;
13855
13973
  }
@@ -13864,12 +13982,12 @@ function findSystemOnnxRuntime(libName) {
13864
13982
  } else if (process.platform === "win32") {
13865
13983
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
13866
13984
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
13867
- searchPaths.push(join7(programFiles, "onnxruntime", "lib"), join7(programFiles, "Microsoft ONNX Runtime", "lib"), join7(programFiles, "Microsoft Machine Learning", "lib"), join7(programFilesX86, "onnxruntime", "lib"), ...(() => {
13985
+ searchPaths.push(join8(programFiles, "onnxruntime", "lib"), join8(programFiles, "Microsoft ONNX Runtime", "lib"), join8(programFiles, "Microsoft Machine Learning", "lib"), join8(programFilesX86, "onnxruntime", "lib"), ...(() => {
13868
13986
  const nugetPaths = [];
13869
13987
  const userProfile = process.env.USERPROFILE ?? "";
13870
13988
  if (!userProfile)
13871
13989
  return nugetPaths;
13872
- const nugetPackageDir = join7(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
13990
+ const nugetPackageDir = join8(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
13873
13991
  if (!existsSync5(nugetPackageDir))
13874
13992
  return nugetPaths;
13875
13993
  try {
@@ -13878,7 +13996,7 @@ function findSystemOnnxRuntime(libName) {
13878
13996
  continue;
13879
13997
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
13880
13998
  continue;
13881
- nugetPaths.push(join7(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join7(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
13999
+ nugetPaths.push(join8(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join8(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
13882
14000
  }
13883
14001
  } catch (err) {
13884
14002
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -13890,7 +14008,7 @@ function findSystemOnnxRuntime(libName) {
13890
14008
  const normalizeCase = process.platform === "win32" || process.platform === "darwin";
13891
14009
  const seen = new Set;
13892
14010
  const uniquePaths = searchPaths.filter((p) => {
13893
- let key = resolve(p).replace(/[/\\]+$/, "");
14011
+ let key = resolve2(p).replace(/[/\\]+$/, "");
13894
14012
  if (normalizeCase)
13895
14013
  key = key.toLowerCase();
13896
14014
  if (seen.has(key))
@@ -13900,7 +14018,7 @@ function findSystemOnnxRuntime(libName) {
13900
14018
  });
13901
14019
  const unknownVersionPaths = [];
13902
14020
  for (const dir of uniquePaths) {
13903
- const libPath = join7(dir, libName);
14021
+ const libPath = join8(dir, libName);
13904
14022
  if (process.platform === "win32") {
13905
14023
  if (!directoryContainsLibrary(dir, libName))
13906
14024
  continue;
@@ -13966,19 +14084,19 @@ function validateExtractedTree(stagingRoot) {
13966
14084
  const walk = (dir) => {
13967
14085
  const entries = readdirSync2(dir);
13968
14086
  for (const entry of entries) {
13969
- const fullPath = join7(dir, entry);
14087
+ const fullPath = join8(dir, entry);
13970
14088
  const lst = lstatSync(fullPath);
13971
14089
  if (lst.isSymbolicLink()) {
13972
14090
  const linkTarget = readlinkSync(fullPath);
13973
- const resolvedTarget = resolve(dirname4(fullPath), linkTarget);
13974
- const rel2 = relative(realRoot, resolvedTarget);
13975
- if (rel2.startsWith("..") || isAbsolute2(rel2) || win32.isAbsolute(rel2)) {
14091
+ const resolvedTarget = resolve2(dirname4(fullPath), linkTarget);
14092
+ const rel2 = relative2(realRoot, resolvedTarget);
14093
+ if (rel2.startsWith("..") || isAbsolute3(rel2) || win32.isAbsolute(rel2)) {
13976
14094
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
13977
14095
  }
13978
14096
  continue;
13979
14097
  }
13980
- const rel = relative(realRoot, fullPath);
13981
- if (rel.startsWith("..") || isAbsolute2(rel) || win32.isAbsolute(rel)) {
14098
+ const rel = relative2(realRoot, fullPath);
14099
+ if (rel.startsWith("..") || isAbsolute3(rel) || win32.isAbsolute(rel)) {
13982
14100
  throw new Error(`extracted entry ${fullPath} escapes staging root`);
13983
14101
  }
13984
14102
  if (lst.isDirectory()) {
@@ -14001,7 +14119,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14001
14119
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
14002
14120
  try {
14003
14121
  mkdirSync5(tmpDir, { recursive: true });
14004
- const archivePath = join7(tmpDir, `onnxruntime.${info.archiveType}`);
14122
+ const archivePath = join8(tmpDir, `onnxruntime.${info.archiveType}`);
14005
14123
  await downloadFileWithCap(url, archivePath);
14006
14124
  const archiveSha256 = sha256File(archivePath);
14007
14125
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
@@ -14017,7 +14135,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14017
14135
  unlinkSync3(archivePath);
14018
14136
  } catch {}
14019
14137
  validateExtractedTree(tmpDir);
14020
- const extractedDir = join7(tmpDir, info.assetName, "lib");
14138
+ const extractedDir = join8(tmpDir, info.assetName, "lib");
14021
14139
  if (!existsSync5(extractedDir)) {
14022
14140
  throw new Error(`Expected directory not found: ${extractedDir}`);
14023
14141
  }
@@ -14026,7 +14144,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14026
14144
  const realFiles = [];
14027
14145
  const symlinks = [];
14028
14146
  for (const libFile of libFiles) {
14029
- const src = join7(extractedDir, libFile);
14147
+ const src = join8(extractedDir, libFile);
14030
14148
  try {
14031
14149
  const stat = lstatSync(src);
14032
14150
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
@@ -14041,7 +14159,7 @@ async function downloadOnnxRuntime(info, targetDir) {
14041
14159
  }
14042
14160
  }
14043
14161
  copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
14044
- const libPath = join7(targetDir, info.libName);
14162
+ const libPath = join8(targetDir, info.libName);
14045
14163
  let libHash = null;
14046
14164
  try {
14047
14165
  libHash = sha256File(libPath);
@@ -14066,8 +14184,8 @@ async function downloadOnnxRuntime(info, targetDir) {
14066
14184
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
14067
14185
  const requiredLibs = new Set([info.libName]);
14068
14186
  for (const libFile of realFiles) {
14069
- const src = join7(extractedDir, libFile);
14070
- const dst = join7(targetDir, libFile);
14187
+ const src = join8(extractedDir, libFile);
14188
+ const dst = join8(targetDir, libFile);
14071
14189
  try {
14072
14190
  copyFile(src, dst);
14073
14191
  if (process.platform !== "win32") {
@@ -14083,12 +14201,12 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
14083
14201
  }
14084
14202
  const targetRoot = realpathSync(targetDir);
14085
14203
  for (const link of symlinks) {
14086
- const dst = join7(targetDir, link.name);
14204
+ const dst = join8(targetDir, link.name);
14087
14205
  try {
14088
14206
  unlinkSync3(dst);
14089
14207
  } catch {}
14090
- const dstForContainment = join7(targetRoot, link.name);
14091
- const resolvedTarget = resolve(dirname4(dstForContainment), link.target);
14208
+ const dstForContainment = join8(targetRoot, link.name);
14209
+ const resolvedTarget = resolve2(dirname4(dstForContainment), link.target);
14092
14210
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
14093
14211
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
14094
14212
  if (requiredLibs.has(link.name)) {
@@ -14108,7 +14226,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
14108
14226
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
14109
14227
  }
14110
14228
  }
14111
- const requiredPath = join7(targetDir, info.libName);
14229
+ const requiredPath = join8(targetDir, info.libName);
14112
14230
  if (!existsSync5(requiredPath)) {
14113
14231
  rmSync2(targetDir, { recursive: true, force: true });
14114
14232
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
@@ -14135,17 +14253,17 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
14135
14253
  ...sha256 ? { sha256 } : {},
14136
14254
  archiveSha256
14137
14255
  };
14138
- writeFileSync2(join7(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
14256
+ writeFileSync2(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
14139
14257
  } catch (err) {
14140
14258
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
14141
14259
  }
14142
14260
  }
14143
14261
  function readOnnxInstalledMeta(installDir) {
14144
- const path = join7(installDir, ONNX_INSTALLED_META_FILE);
14262
+ const path2 = join8(installDir, ONNX_INSTALLED_META_FILE);
14145
14263
  try {
14146
- if (!statSync3(path).isFile())
14264
+ if (!statSync3(path2).isFile())
14147
14265
  return null;
14148
- const raw = readFileSync3(path, "utf8");
14266
+ const raw = readFileSync3(path2, "utf8");
14149
14267
  const parsed = JSON.parse(raw);
14150
14268
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
14151
14269
  return null;
@@ -14159,9 +14277,9 @@ function readOnnxInstalledMeta(installDir) {
14159
14277
  return null;
14160
14278
  }
14161
14279
  }
14162
- function sha256File(path) {
14280
+ function sha256File(path2) {
14163
14281
  const hash = createHash2("sha256");
14164
- hash.update(readFileSync3(path));
14282
+ hash.update(readFileSync3(path2));
14165
14283
  return hash.digest("hex");
14166
14284
  }
14167
14285
  function acquireLock(lockPath) {
@@ -14997,6 +15115,91 @@ function normalizeKey(projectRoot) {
14997
15115
  return stripped;
14998
15116
  }
14999
15117
  }
15118
+ // ../aft-bridge/dist/tool-format.js
15119
+ function asPlainObject(value) {
15120
+ if (!value || typeof value !== "object" || Array.isArray(value))
15121
+ return;
15122
+ return value;
15123
+ }
15124
+ function candidateLocation(candidate) {
15125
+ const file = typeof candidate.file === "string" && candidate.file.length > 0 ? candidate.file : undefined;
15126
+ if (!file)
15127
+ return;
15128
+ const line = typeof candidate.line === "number" && Number.isFinite(candidate.line) ? candidate.line : undefined;
15129
+ return line === undefined ? file : `${file}:${line}`;
15130
+ }
15131
+ function stringifyData(data) {
15132
+ if (data === undefined)
15133
+ return;
15134
+ try {
15135
+ return JSON.stringify(data, null, 2);
15136
+ } catch {
15137
+ return String(data);
15138
+ }
15139
+ }
15140
+ function formatBridgeErrorMessage(command, response, params = {}) {
15141
+ const code = typeof response.code === "string" && response.code.length > 0 ? response.code : undefined;
15142
+ const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
15143
+ const data = asPlainObject(response.data);
15144
+ const rawCandidates = Array.isArray(response.candidates) ? response.candidates : Array.isArray(data?.candidates) ? data.candidates : undefined;
15145
+ const rawSymbol = typeof response.symbol === "string" && response.symbol.length > 0 ? response.symbol : typeof data?.symbol === "string" && data.symbol.length > 0 ? data.symbol : undefined;
15146
+ if (code === "ambiguous_target" || code === "target_symbol_not_in_file") {
15147
+ const candidates = (rawCandidates ?? []).map(asPlainObject).filter((candidate) => candidate !== undefined).map(candidateLocation).filter((candidate) => candidate !== undefined);
15148
+ if (candidates.length > 0) {
15149
+ const symbol = typeof params.toSymbol === "string" && params.toSymbol.length > 0 ? params.toSymbol : rawSymbol;
15150
+ const target = symbol ? `multiple symbols named "${symbol}"` : message.replace(/[.!?]+$/, "");
15151
+ const action = code === "ambiguous_target" ? "Pass toFile to disambiguate" : "Try one of these files for toFile";
15152
+ return `${command}: ${code} — ${target}. ${action}:
15153
+ ${candidates.map((candidate) => ` - ${candidate}`).join(`
15154
+ `)}`;
15155
+ }
15156
+ }
15157
+ if (!code)
15158
+ return message;
15159
+ const lines = [`${command}: ${code} — ${message}`];
15160
+ const extras = collectStructuredExtras(response);
15161
+ if (extras)
15162
+ lines.push(`data: ${extras}`);
15163
+ return lines.join(`
15164
+ `);
15165
+ }
15166
+ function collectStructuredExtras(response) {
15167
+ const reserved = new Set([
15168
+ "id",
15169
+ "success",
15170
+ "code",
15171
+ "message",
15172
+ "data",
15173
+ "status_bar",
15174
+ "bg_completions"
15175
+ ]);
15176
+ const extras = {};
15177
+ for (const [key, value] of Object.entries(response)) {
15178
+ if (reserved.has(key))
15179
+ continue;
15180
+ extras[key] = value;
15181
+ }
15182
+ if (Object.keys(extras).length === 0) {
15183
+ return stringifyData(response.data);
15184
+ }
15185
+ if (response.data !== undefined)
15186
+ extras.data = response.data;
15187
+ return stringifyData(extras);
15188
+ }
15189
+ function formatReadFooter(agentSpecifiedRange, data, options) {
15190
+ if (agentSpecifiedRange)
15191
+ return "";
15192
+ if (!data.truncated)
15193
+ return "";
15194
+ const startLine = data.start_line;
15195
+ const endLine = data.end_line;
15196
+ const totalLines = data.total_lines;
15197
+ if (startLine === undefined || endLine === undefined || totalLines === undefined) {
15198
+ return "";
15199
+ }
15200
+ return `
15201
+ (Showing lines ${startLine}-${endLine} of ${totalLines}. Use ${options.rangeHint} to read other sections.)`;
15202
+ }
15000
15203
  // ../aft-bridge/dist/zoom-format.js
15001
15204
  function formatZoomText(targetLabel, response) {
15002
15205
  const range = response.range;
@@ -15077,16 +15280,39 @@ function formatZoomMultiTargetResult(entries) {
15077
15280
 
15078
15281
  `) };
15079
15282
  }
15283
+ function isRustZoomBatchEnvelope(response) {
15284
+ if (!Array.isArray(response.symbols) || response.symbols.length === 0) {
15285
+ return false;
15286
+ }
15287
+ return response.symbols.every((entry) => {
15288
+ if (!entry || typeof entry !== "object")
15289
+ return false;
15290
+ const row = entry;
15291
+ return typeof row.name === "string" && row.response !== undefined && row.response !== null;
15292
+ });
15293
+ }
15294
+ function unwrapRustZoomBatchEnvelope(response) {
15295
+ if (!isRustZoomBatchEnvelope(response)) {
15296
+ return null;
15297
+ }
15298
+ const names = [];
15299
+ const responses = [];
15300
+ for (const entry of response.symbols) {
15301
+ names.push(entry.name);
15302
+ responses.push(entry.response);
15303
+ }
15304
+ return { names, responses };
15305
+ }
15080
15306
  // src/bg-notifications.ts
15081
15307
  import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
15082
15308
 
15083
15309
  // src/logger.ts
15084
15310
  import * as fs from "node:fs";
15085
- import * as os from "node:os";
15086
- import * as path from "node:path";
15311
+ import * as os2 from "node:os";
15312
+ import * as path2 from "node:path";
15087
15313
  var TAG = "[aft-plugin]";
15088
15314
  var isTestEnv = process.env.BUN_TEST === "1" || false;
15089
- var logFile = path.join(os.tmpdir(), isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
15315
+ var logFile = path2.join(os2.tmpdir(), isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
15090
15316
  var useStderr = process.env.AFT_LOG_STDERR === "1";
15091
15317
  var buffer = [];
15092
15318
  var flushTimer = null;
@@ -16030,8 +16256,8 @@ function formatDuration(completion) {
16030
16256
 
16031
16257
  // src/config.ts
16032
16258
  import { existsSync as existsSync6, readFileSync as readFileSync4, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
16033
- import { homedir as homedir6 } from "node:os";
16034
- import { join as join9 } from "node:path";
16259
+ import { homedir as homedir7 } from "node:os";
16260
+ import { join as join10 } from "node:path";
16035
16261
  var import_comment_json = __toESM(require_src2(), 1);
16036
16262
 
16037
16263
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
@@ -16799,10 +17025,10 @@ function mergeDefs(...defs) {
16799
17025
  function cloneDef(schema) {
16800
17026
  return mergeDefs(schema._zod.def);
16801
17027
  }
16802
- function getElementAtPath(obj, path2) {
16803
- if (!path2)
17028
+ function getElementAtPath(obj, path3) {
17029
+ if (!path3)
16804
17030
  return obj;
16805
- return path2.reduce((acc, key) => acc?.[key], obj);
17031
+ return path3.reduce((acc, key) => acc?.[key], obj);
16806
17032
  }
16807
17033
  function promiseAllObject(promisesObj) {
16808
17034
  const keys = Object.keys(promisesObj);
@@ -17183,11 +17409,11 @@ function aborted(x, startIndex = 0) {
17183
17409
  }
17184
17410
  return false;
17185
17411
  }
17186
- function prefixIssues(path2, issues) {
17412
+ function prefixIssues(path3, issues) {
17187
17413
  return issues.map((iss) => {
17188
17414
  var _a;
17189
17415
  (_a = iss).path ?? (_a.path = []);
17190
- iss.path.unshift(path2);
17416
+ iss.path.unshift(path3);
17191
17417
  return iss;
17192
17418
  });
17193
17419
  }
@@ -17370,7 +17596,7 @@ function formatError(error3, mapper = (issue2) => issue2.message) {
17370
17596
  }
17371
17597
  function treeifyError(error3, mapper = (issue2) => issue2.message) {
17372
17598
  const result = { errors: [] };
17373
- const processError = (error4, path2 = []) => {
17599
+ const processError = (error4, path3 = []) => {
17374
17600
  var _a, _b;
17375
17601
  for (const issue2 of error4.issues) {
17376
17602
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -17380,7 +17606,7 @@ function treeifyError(error3, mapper = (issue2) => issue2.message) {
17380
17606
  } else if (issue2.code === "invalid_element") {
17381
17607
  processError({ issues: issue2.issues }, issue2.path);
17382
17608
  } else {
17383
- const fullpath = [...path2, ...issue2.path];
17609
+ const fullpath = [...path3, ...issue2.path];
17384
17610
  if (fullpath.length === 0) {
17385
17611
  result.errors.push(mapper(issue2));
17386
17612
  continue;
@@ -17412,8 +17638,8 @@ function treeifyError(error3, mapper = (issue2) => issue2.message) {
17412
17638
  }
17413
17639
  function toDotPath(_path) {
17414
17640
  const segs = [];
17415
- const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
17416
- for (const seg of path2) {
17641
+ const path3 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
17642
+ for (const seg of path3) {
17417
17643
  if (typeof seg === "number")
17418
17644
  segs.push(`[${seg}]`);
17419
17645
  else if (typeof seg === "symbol")
@@ -29160,13 +29386,13 @@ function resolveRef(ref, ctx) {
29160
29386
  if (!ref.startsWith("#")) {
29161
29387
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
29162
29388
  }
29163
- const path2 = ref.slice(1).split("/").filter(Boolean);
29164
- if (path2.length === 0) {
29389
+ const path3 = ref.slice(1).split("/").filter(Boolean);
29390
+ if (path3.length === 0) {
29165
29391
  return ctx.rootSchema;
29166
29392
  }
29167
29393
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
29168
- if (path2[0] === defsKey) {
29169
- const key = path2[1];
29394
+ if (path3[0] === defsKey) {
29395
+ const key = path3[1];
29170
29396
  if (!key || !ctx.defs[key]) {
29171
29397
  throw new Error(`Reference not found: ${ref}`);
29172
29398
  }
@@ -29864,9 +30090,9 @@ function extractCommentsForPreservation(content) {
29864
30090
  }
29865
30091
  return comments;
29866
30092
  }
29867
- function ensureRecordAtPath(root, path2) {
30093
+ function ensureRecordAtPath(root, path3) {
29868
30094
  let current = root;
29869
- for (const segment of path2) {
30095
+ for (const segment of path3) {
29870
30096
  const existing = current[segment];
29871
30097
  if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
29872
30098
  current[segment] = {};
@@ -29875,9 +30101,9 @@ function ensureRecordAtPath(root, path2) {
29875
30101
  }
29876
30102
  return current;
29877
30103
  }
29878
- function hasPath(root, path2) {
30104
+ function hasPath(root, path3) {
29879
30105
  let current = root;
29880
- for (const segment of path2) {
30106
+ for (const segment of path3) {
29881
30107
  if (!current || typeof current !== "object" || Array.isArray(current))
29882
30108
  return false;
29883
30109
  const record2 = current;
@@ -29887,9 +30113,9 @@ function hasPath(root, path2) {
29887
30113
  }
29888
30114
  return true;
29889
30115
  }
29890
- function setPath(root, path2, value) {
29891
- const parent = ensureRecordAtPath(root, path2.slice(0, -1));
29892
- parent[path2[path2.length - 1]] = value;
30116
+ function setPath(root, path3, value) {
30117
+ const parent = ensureRecordAtPath(root, path3.slice(0, -1));
30118
+ parent[path3[path3.length - 1]] = value;
29893
30119
  }
29894
30120
  function migrateRawConfig(rawConfig, configPath, logger) {
29895
30121
  const oldKeys = [];
@@ -30226,17 +30452,17 @@ function getOpenCodeConfigDir() {
30226
30452
  if (envDir) {
30227
30453
  return envDir;
30228
30454
  }
30229
- const xdgConfig = process.env.XDG_CONFIG_HOME || join9(homedir6(), ".config");
30230
- return join9(xdgConfig, "opencode");
30455
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join10(homedir7(), ".config");
30456
+ return join10(xdgConfig, "opencode");
30231
30457
  }
30232
30458
  function loadAftConfig(projectDirectory) {
30233
30459
  const configDir = getOpenCodeConfigDir();
30234
- const userBasePath = join9(configDir, "aft");
30460
+ const userBasePath = join10(configDir, "aft");
30235
30461
  migrateAftConfigFile(`${userBasePath}.jsonc`);
30236
30462
  migrateAftConfigFile(`${userBasePath}.json`);
30237
30463
  const userDetected = detectConfigFile(userBasePath);
30238
30464
  const userConfigPath = userDetected.format !== "none" ? userDetected.path : `${userBasePath}.json`;
30239
- const projectBasePath = join9(projectDirectory, ".opencode", "aft");
30465
+ const projectBasePath = join10(projectDirectory, ".opencode", "aft");
30240
30466
  migrateAftConfigFile(`${projectBasePath}.jsonc`);
30241
30467
  migrateAftConfigFile(`${projectBasePath}.json`);
30242
30468
  const projectDetected = detectConfigFile(projectBasePath);
@@ -30262,8 +30488,8 @@ function loadAftConfig(projectDirectory) {
30262
30488
 
30263
30489
  // src/notifications.ts
30264
30490
  import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
30265
- import { homedir as homedir7, platform } from "node:os";
30266
- import { join as join10 } from "node:path";
30491
+ import { homedir as homedir8, platform } from "node:os";
30492
+ import { join as join11 } from "node:path";
30267
30493
  function isTuiMode() {
30268
30494
  return process.env.OPENCODE_CLIENT === "cli";
30269
30495
  }
@@ -30283,18 +30509,18 @@ var FEATURE_MARKER = `${AFT_MARKER} New in`;
30283
30509
  var WARNING_MARKER = `${AFT_MARKER} ⚠️`;
30284
30510
  var STATUS_MARKER = `${AFT_MARKER} ✅`;
30285
30511
  function getDesktopStatePath() {
30286
- const os2 = platform();
30287
- const home = homedir7();
30288
- if (os2 === "darwin") {
30289
- return join10(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
30512
+ const os3 = platform();
30513
+ const home = homedir8();
30514
+ if (os3 === "darwin") {
30515
+ return join11(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
30290
30516
  }
30291
- if (os2 === "linux") {
30292
- const xdgConfig = process.env.XDG_CONFIG_HOME || join10(home, ".config");
30293
- return join10(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
30517
+ if (os3 === "linux") {
30518
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join11(home, ".config");
30519
+ return join11(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
30294
30520
  }
30295
- if (os2 === "win32") {
30296
- const appData = process.env.APPDATA || join10(home, "AppData", "Roaming");
30297
- return join10(appData, "ai.opencode.desktop", "opencode.global.dat");
30521
+ if (os3 === "win32") {
30522
+ const appData = process.env.APPDATA || join11(home, "AppData", "Roaming");
30523
+ return join11(appData, "ai.opencode.desktop", "opencode.global.dat");
30298
30524
  }
30299
30525
  return null;
30300
30526
  }
@@ -30764,37 +30990,37 @@ import { dirname as dirname7 } from "node:path";
30764
30990
  import { spawn as spawn2 } from "node:child_process";
30765
30991
  import { cpSync, existsSync as existsSync9, mkdtempSync, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
30766
30992
  import { tmpdir as tmpdir3 } from "node:os";
30767
- import { basename as basename2, dirname as dirname6, join as join13 } from "node:path";
30993
+ import { basename as basename2, dirname as dirname6, join as join14 } from "node:path";
30768
30994
  var import_comment_json3 = __toESM(require_src2(), 1);
30769
30995
 
30770
30996
  // src/hooks/auto-update-checker/checker.ts
30771
30997
  var import_comment_json2 = __toESM(require_src2(), 1);
30772
30998
  import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
30773
- import { homedir as homedir9 } from "node:os";
30774
- import { dirname as dirname5, isAbsolute as isAbsolute3, join as join12, resolve as resolve2 } from "node:path";
30999
+ import { homedir as homedir10 } from "node:os";
31000
+ import { dirname as dirname5, isAbsolute as isAbsolute4, join as join13, resolve as resolve3 } from "node:path";
30775
31001
  import { fileURLToPath } from "node:url";
30776
31002
 
30777
31003
  // src/hooks/auto-update-checker/constants.ts
30778
- import { homedir as homedir8, platform as platform2 } from "node:os";
30779
- import { join as join11 } from "node:path";
31004
+ import { homedir as homedir9, platform as platform2 } from "node:os";
31005
+ import { join as join12 } from "node:path";
30780
31006
  var PACKAGE_NAME = "@cortexkit/aft-opencode";
30781
31007
  var NPM_REGISTRY_URL = "https://registry.npmjs.org";
30782
31008
  var NPM_FETCH_TIMEOUT = 1e4;
30783
31009
  function getOpenCodeCacheRoot() {
30784
31010
  if (platform2() === "win32") {
30785
- return join11(process.env.LOCALAPPDATA ?? homedir8(), "opencode");
31011
+ return join12(process.env.LOCALAPPDATA ?? homedir9(), "opencode");
30786
31012
  }
30787
- return join11(homedir8(), ".cache", "opencode");
31013
+ return join12(homedir9(), ".cache", "opencode");
30788
31014
  }
30789
31015
  function getOpenCodeConfigRoot() {
30790
31016
  if (platform2() === "win32") {
30791
- return join11(process.env.APPDATA ?? join11(homedir8(), "AppData", "Roaming"), "opencode");
31017
+ return join12(process.env.APPDATA ?? join12(homedir9(), "AppData", "Roaming"), "opencode");
30792
31018
  }
30793
- return join11(process.env.XDG_CONFIG_HOME ?? join11(homedir8(), ".config"), "opencode");
31019
+ return join12(process.env.XDG_CONFIG_HOME ?? join12(homedir9(), ".config"), "opencode");
30794
31020
  }
30795
- var CACHE_DIR = join11(getOpenCodeCacheRoot(), "packages");
30796
- var USER_OPENCODE_CONFIG = join11(getOpenCodeConfigRoot(), "opencode.json");
30797
- var USER_OPENCODE_CONFIG_JSONC = join11(getOpenCodeConfigRoot(), "opencode.jsonc");
31021
+ var CACHE_DIR = join12(getOpenCodeCacheRoot(), "packages");
31022
+ var USER_OPENCODE_CONFIG = join12(getOpenCodeConfigRoot(), "opencode.json");
31023
+ var USER_OPENCODE_CONFIG_JSONC = join12(getOpenCodeConfigRoot(), "opencode.jsonc");
30798
31024
 
30799
31025
  // src/hooks/auto-update-checker/types.ts
30800
31026
  var NpmPackageEnvelopeSchema = exports_external.object({
@@ -30852,8 +31078,8 @@ function extractChannel(version2) {
30852
31078
  }
30853
31079
  function getConfigPaths(directory) {
30854
31080
  return [
30855
- join12(directory, ".opencode", "opencode.json"),
30856
- join12(directory, ".opencode", "opencode.jsonc"),
31081
+ join13(directory, ".opencode", "opencode.json"),
31082
+ join13(directory, ".opencode", "opencode.jsonc"),
30857
31083
  USER_OPENCODE_CONFIG,
30858
31084
  USER_OPENCODE_CONFIG_JSONC
30859
31085
  ];
@@ -30866,9 +31092,9 @@ function resolvePathPluginSpec(spec, configPath) {
30866
31092
  return spec.replace(/^file:\/\//, "");
30867
31093
  }
30868
31094
  }
30869
- if (isAbsolute3(spec) || /^[A-Za-z]:[\\/]/.test(spec))
31095
+ if (isAbsolute4(spec) || /^[A-Za-z]:[\\/]/.test(spec))
30870
31096
  return spec;
30871
- return resolve2(dirname5(configPath), spec);
31097
+ return resolve3(dirname5(configPath), spec);
30872
31098
  }
30873
31099
  function getLocalDevPath(directory) {
30874
31100
  for (const configPath of getConfigPaths(directory)) {
@@ -30880,7 +31106,7 @@ function getLocalDevPath(directory) {
30880
31106
  for (const entry of plugins) {
30881
31107
  if (entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))
30882
31108
  continue;
30883
- if (entry.startsWith("file://") || entry.startsWith(".") || isAbsolute3(entry)) {
31109
+ if (entry.startsWith("file://") || entry.startsWith(".") || isAbsolute4(entry)) {
30884
31110
  const localPath = resolvePathPluginSpec(entry, configPath);
30885
31111
  const pkgPath = findPackageJsonUp(localPath);
30886
31112
  if (!pkgPath)
@@ -30899,7 +31125,7 @@ function findPackageJsonUp(startPath) {
30899
31125
  const stat = statSync4(startPath);
30900
31126
  let dir = stat.isDirectory() ? startPath : dirname5(startPath);
30901
31127
  for (let i = 0;i < 10; i++) {
30902
- const pkgPath = join12(dir, "package.json");
31128
+ const pkgPath = join13(dir, "package.json");
30903
31129
  if (existsSync8(pkgPath)) {
30904
31130
  try {
30905
31131
  const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync6(pkgPath, "utf-8")));
@@ -30960,7 +31186,7 @@ function findPluginEntry(directory) {
30960
31186
  }
30961
31187
  var cachedPackageVersion = null;
30962
31188
  function getSpecCachePackageJsonPath(spec) {
30963
- return join12(CACHE_DIR, spec, "node_modules", PACKAGE_NAME, "package.json");
31189
+ return join13(CACHE_DIR, spec, "node_modules", PACKAGE_NAME, "package.json");
30964
31190
  }
30965
31191
  function getCachedVersion(spec) {
30966
31192
  if (!spec && cachedPackageVersion)
@@ -30969,7 +31195,7 @@ function getCachedVersion(spec) {
30969
31195
  getCurrentRuntimePackageJsonPath(),
30970
31196
  spec ? getSpecCachePackageJsonPath(spec) : null,
30971
31197
  getSpecCachePackageJsonPath(`${PACKAGE_NAME}@latest`),
30972
- join12(homedir9(), ".cache", "opencode", "node_modules", PACKAGE_NAME, "package.json")
31198
+ join13(homedir10(), ".cache", "opencode", "node_modules", PACKAGE_NAME, "package.json")
30973
31199
  ].filter(isString);
30974
31200
  for (const packageJsonPath of candidates) {
30975
31201
  try {
@@ -31017,10 +31243,10 @@ async function getLatestVersion(channel = "latest", options = {}) {
31017
31243
  // src/hooks/auto-update-checker/cache.ts
31018
31244
  var pendingSnapshots = new Map;
31019
31245
  function createAutoUpdateSnapshot(installDir, packageJsonPath, packageName) {
31020
- const packageDir = join13(installDir, "node_modules", packageName);
31021
- const lockfilePath = join13(installDir, "package-lock.json");
31022
- const tempDir = mkdtempSync(join13(tmpdir3(), "aft-auto-update-"));
31023
- const stagedPackageDir = existsSync9(packageDir) ? join13(tempDir, "package") : null;
31246
+ const packageDir = join14(installDir, "node_modules", packageName);
31247
+ const lockfilePath = join14(installDir, "package-lock.json");
31248
+ const tempDir = mkdtempSync(join14(tmpdir3(), "aft-auto-update-"));
31249
+ const stagedPackageDir = existsSync9(packageDir) ? join14(tempDir, "package") : null;
31024
31250
  if (stagedPackageDir)
31025
31251
  cpSync(packageDir, stagedPackageDir, { recursive: true });
31026
31252
  return {
@@ -31061,7 +31287,7 @@ function stripPackageNameFromPath(pathValue, packageName) {
31061
31287
  return current;
31062
31288
  }
31063
31289
  function removeFromPackageLock(installDir, packageName) {
31064
- const lockPath = join13(installDir, "package-lock.json");
31290
+ const lockPath = join14(installDir, "package-lock.json");
31065
31291
  if (!existsSync9(lockPath))
31066
31292
  return false;
31067
31293
  try {
@@ -31110,7 +31336,7 @@ function ensureDependencyVersion(packageJsonPath, packageName, version2) {
31110
31336
  }
31111
31337
  }
31112
31338
  function removeInstalledPackage(installDir, packageName) {
31113
- const packageDir = join13(installDir, "node_modules", packageName);
31339
+ const packageDir = join14(installDir, "node_modules", packageName);
31114
31340
  if (!existsSync9(packageDir))
31115
31341
  return false;
31116
31342
  rmSync3(packageDir, { recursive: true, force: true });
@@ -31123,13 +31349,13 @@ function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackage
31123
31349
  const nodeModulesDir = stripPackageNameFromPath(packageDir, PACKAGE_NAME);
31124
31350
  if (nodeModulesDir && basename2(nodeModulesDir) === "node_modules") {
31125
31351
  const installDir = dirname6(nodeModulesDir);
31126
- const packageJsonPath = join13(installDir, "package.json");
31352
+ const packageJsonPath = join14(installDir, "package.json");
31127
31353
  if (existsSync9(packageJsonPath))
31128
31354
  return { installDir, packageJsonPath };
31129
31355
  }
31130
31356
  return null;
31131
31357
  }
31132
- const legacyPackageJsonPath = join13(dirname6(CACHE_DIR), "package.json");
31358
+ const legacyPackageJsonPath = join14(dirname6(CACHE_DIR), "package.json");
31133
31359
  if (existsSync9(legacyPackageJsonPath)) {
31134
31360
  return { installDir: dirname6(CACHE_DIR), packageJsonPath: legacyPackageJsonPath };
31135
31361
  }
@@ -31460,7 +31686,7 @@ import {
31460
31686
  statSync as statSync6,
31461
31687
  writeFileSync as writeFileSync8
31462
31688
  } from "node:fs";
31463
- import { join as join16 } from "node:path";
31689
+ import { join as join17 } from "node:path";
31464
31690
 
31465
31691
  // src/lsp-cache.ts
31466
31692
  import {
@@ -31472,36 +31698,36 @@ import {
31472
31698
  unlinkSync as unlinkSync5,
31473
31699
  writeFileSync as writeFileSync7
31474
31700
  } from "node:fs";
31475
- import { homedir as homedir10 } from "node:os";
31476
- import { join as join14 } from "node:path";
31701
+ import { homedir as homedir11 } from "node:os";
31702
+ import { join as join15 } from "node:path";
31477
31703
  function aftCacheBase() {
31478
31704
  const override = process.env.AFT_CACHE_DIR;
31479
31705
  if (override && override.length > 0)
31480
31706
  return override;
31481
31707
  if (process.platform === "win32") {
31482
31708
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
31483
- const base2 = localAppData || join14(homedir10(), "AppData", "Local");
31484
- return join14(base2, "aft");
31709
+ const base2 = localAppData || join15(homedir11(), "AppData", "Local");
31710
+ return join15(base2, "aft");
31485
31711
  }
31486
- const base = process.env.XDG_CACHE_HOME || join14(homedir10(), ".cache");
31487
- return join14(base, "aft");
31712
+ const base = process.env.XDG_CACHE_HOME || join15(homedir11(), ".cache");
31713
+ return join15(base, "aft");
31488
31714
  }
31489
31715
  function lspCacheRoot() {
31490
- return join14(aftCacheBase(), "lsp-packages");
31716
+ return join15(aftCacheBase(), "lsp-packages");
31491
31717
  }
31492
31718
  function lspPackageDir(npmPackage) {
31493
- return join14(lspCacheRoot(), encodeURIComponent(npmPackage));
31719
+ return join15(lspCacheRoot(), encodeURIComponent(npmPackage));
31494
31720
  }
31495
31721
  function lspBinaryPath(npmPackage, binary) {
31496
- return join14(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
31722
+ return join15(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
31497
31723
  }
31498
31724
  function lspBinDir(npmPackage) {
31499
- return join14(lspPackageDir(npmPackage), "node_modules", ".bin");
31725
+ return join15(lspPackageDir(npmPackage), "node_modules", ".bin");
31500
31726
  }
31501
31727
  function isInstalled(npmPackage, binary) {
31502
31728
  for (const candidate of lspBinaryCandidates(binary)) {
31503
31729
  try {
31504
- if (statSync5(join14(lspBinDir(npmPackage), candidate)).isFile())
31730
+ if (statSync5(join15(lspBinDir(npmPackage), candidate)).isFile())
31505
31731
  return true;
31506
31732
  } catch {}
31507
31733
  }
@@ -31521,17 +31747,17 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
31521
31747
  installedAt: new Date().toISOString(),
31522
31748
  ...sha256 ? { sha256 } : {}
31523
31749
  };
31524
- writeFileSync7(join14(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
31750
+ writeFileSync7(join15(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
31525
31751
  } catch (err) {
31526
31752
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
31527
31753
  }
31528
31754
  }
31529
31755
  function readInstalledMetaIn(installDir) {
31530
- const path2 = join14(installDir, INSTALLED_META_FILE);
31756
+ const path3 = join15(installDir, INSTALLED_META_FILE);
31531
31757
  try {
31532
- if (!statSync5(path2).isFile())
31758
+ if (!statSync5(path3).isFile())
31533
31759
  return null;
31534
- const raw = readFileSync9(path2, "utf8");
31760
+ const raw = readFileSync9(path3, "utf8");
31535
31761
  const parsed = JSON.parse(raw);
31536
31762
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
31537
31763
  return null;
@@ -31551,7 +31777,7 @@ function readInstalledMeta(packageKey) {
31551
31777
  return readInstalledMetaIn(lspPackageDir(packageKey));
31552
31778
  }
31553
31779
  function lockPath(npmPackage) {
31554
- return join14(lspPackageDir(npmPackage), ".aft-installing");
31780
+ return join15(lspPackageDir(npmPackage), ".aft-installing");
31555
31781
  }
31556
31782
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
31557
31783
  function acquireInstallLock(lockKey) {
@@ -31658,7 +31884,7 @@ async function withInstallLock(lockKey, task) {
31658
31884
  }
31659
31885
  var VERSION_CHECK_FILE = ".aft-version-check";
31660
31886
  function readVersionCheck(npmPackage) {
31661
- const file2 = join14(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31887
+ const file2 = join15(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31662
31888
  try {
31663
31889
  const raw = readFileSync9(file2, "utf8");
31664
31890
  const parsed = JSON.parse(raw);
@@ -31675,7 +31901,7 @@ function readVersionCheck(npmPackage) {
31675
31901
  }
31676
31902
  function writeVersionCheck(npmPackage, latest) {
31677
31903
  mkdirSync7(lspPackageDir(npmPackage), { recursive: true });
31678
- const file2 = join14(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31904
+ const file2 = join15(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31679
31905
  const record2 = {
31680
31906
  last_checked: new Date().toISOString(),
31681
31907
  latest_eligible: latest
@@ -31838,7 +32064,7 @@ var NPM_LSP_TABLE = [
31838
32064
 
31839
32065
  // src/lsp-project-relevance.ts
31840
32066
  import { existsSync as existsSync11, readdirSync as readdirSync3, readFileSync as readFileSync10 } from "node:fs";
31841
- import { join as join15 } from "node:path";
32067
+ import { join as join16 } from "node:path";
31842
32068
  var MAX_WALK_DIRS = 200;
31843
32069
  var MAX_WALK_DEPTH = 4;
31844
32070
  var NOISE_DIRS = new Set([
@@ -31855,7 +32081,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
31855
32081
  if (!rootMarkers)
31856
32082
  return false;
31857
32083
  for (const marker of rootMarkers) {
31858
- if (existsSync11(join15(projectRoot, marker)))
32084
+ if (existsSync11(join16(projectRoot, marker)))
31859
32085
  return true;
31860
32086
  }
31861
32087
  return false;
@@ -31879,7 +32105,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
31879
32105
  }
31880
32106
  function readPackageJson(projectRoot) {
31881
32107
  try {
31882
- const raw = readFileSync10(join15(projectRoot, "package.json"), "utf8");
32108
+ const raw = readFileSync10(join16(projectRoot, "package.json"), "utf8");
31883
32109
  const parsed = JSON.parse(raw);
31884
32110
  if (typeof parsed !== "object" || parsed === null)
31885
32111
  return null;
@@ -31909,7 +32135,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
31909
32135
  for (const entry of entries) {
31910
32136
  if (entry.isDirectory()) {
31911
32137
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
31912
- queue.push({ dir: join15(current.dir, entry.name), depth: current.depth + 1 });
32138
+ queue.push({ dir: join16(current.dir, entry.name), depth: current.depth + 1 });
31913
32139
  }
31914
32140
  continue;
31915
32141
  }
@@ -32036,7 +32262,7 @@ async function resolveTargetVersion(spec, config2, fetchImpl = fetch) {
32036
32262
  }
32037
32263
  function ensureInstallAnchor(cwd) {
32038
32264
  try {
32039
- const stub = join16(cwd, "package.json");
32265
+ const stub = join17(cwd, "package.json");
32040
32266
  if (!existsSync12(stub)) {
32041
32267
  writeFileSync8(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
32042
32268
  `);
@@ -32046,18 +32272,18 @@ function ensureInstallAnchor(cwd) {
32046
32272
  }
32047
32273
  }
32048
32274
  function runInstall(spec, version2, cwd, signal) {
32049
- return new Promise((resolve3) => {
32275
+ return new Promise((resolve4) => {
32050
32276
  const target = `${spec.npm}@${version2}`;
32051
32277
  log2(`[lsp] installing ${target} to ${cwd}`);
32052
32278
  if (signal?.aborted) {
32053
32279
  warn2(`[lsp] install ${target} aborted before spawn`);
32054
- resolve3(false);
32280
+ resolve4(false);
32055
32281
  return;
32056
32282
  }
32057
32283
  const npm = resolveNpm();
32058
32284
  if (!npm) {
32059
32285
  warn2(`[lsp] npm not found on PATH or known locations; cannot install ${target}`);
32060
- resolve3(false);
32286
+ resolve4(false);
32061
32287
  return;
32062
32288
  }
32063
32289
  ensureInstallAnchor(cwd);
@@ -32080,7 +32306,7 @@ function runInstall(spec, version2, cwd, signal) {
32080
32306
  return;
32081
32307
  settled = true;
32082
32308
  cleanup();
32083
- resolve3(ok);
32309
+ resolve4(ok);
32084
32310
  };
32085
32311
  const onAbort = () => {
32086
32312
  warn2(`[lsp] install ${target} aborted during shutdown`);
@@ -32181,7 +32407,7 @@ function cachedPackageDir(npmPackage) {
32181
32407
  return lspBinDir(npmPackage).replace(/[\\/]node_modules[\\/]\.bin[\\/]?$/, "");
32182
32408
  }
32183
32409
  function hashInstalledBinary(spec) {
32184
- return new Promise((resolve3, reject) => {
32410
+ return new Promise((resolve4, reject) => {
32185
32411
  const candidates = process.platform === "win32" ? [
32186
32412
  lspBinaryPath(spec.npm, spec.binary),
32187
32413
  lspBinaryPath(spec.npm, `${spec.binary}.cmd`),
@@ -32205,7 +32431,7 @@ function hashInstalledBinary(spec) {
32205
32431
  const stream = createReadStream(pathToHash);
32206
32432
  stream.on("error", reject);
32207
32433
  stream.on("data", (chunk) => hash2.update(chunk));
32208
- stream.on("end", () => resolve3(hash2.digest("hex")));
32434
+ stream.on("end", () => resolve4(hash2.digest("hex")));
32209
32435
  });
32210
32436
  }
32211
32437
  function installedBinaryPath(spec) {
@@ -32223,15 +32449,15 @@ function installedBinaryPath(spec) {
32223
32449
  }
32224
32450
  return null;
32225
32451
  }
32226
- function sha256OfFileSync(path2) {
32227
- return createHash4("sha256").update(readFileSync11(path2)).digest("hex");
32452
+ function sha256OfFileSync(path3) {
32453
+ return createHash4("sha256").update(readFileSync11(path3)).digest("hex");
32228
32454
  }
32229
32455
  function quarantineCachedNpmInstall(spec, reason) {
32230
32456
  const packageDir = lspPackageDir(spec.npm);
32231
- const dest = join16(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
32457
+ const dest = join17(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
32232
32458
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
32233
32459
  try {
32234
- mkdirSync8(join16(dest, ".."), { recursive: true });
32460
+ mkdirSync8(join17(dest, ".."), { recursive: true });
32235
32461
  rmSync5(dest, { recursive: true, force: true });
32236
32462
  renameSync6(packageDir, dest);
32237
32463
  } catch (err) {
@@ -32327,7 +32553,7 @@ import {
32327
32553
  unlinkSync as unlinkSync6,
32328
32554
  writeFileSync as writeFileSync9
32329
32555
  } from "node:fs";
32330
- import { dirname as dirname8, join as join17, relative as relative2, resolve as resolve3 } from "node:path";
32556
+ import { dirname as dirname8, join as join18, relative as relative3, resolve as resolve4 } from "node:path";
32331
32557
  import { Readable as Readable3 } from "node:stream";
32332
32558
  import { pipeline as pipeline3 } from "node:stream/promises";
32333
32559
 
@@ -32417,26 +32643,26 @@ function detectHostPlatform() {
32417
32643
 
32418
32644
  // src/lsp-github-install.ts
32419
32645
  function ghCacheRoot() {
32420
- return join17(aftCacheBase(), "lsp-binaries");
32646
+ return join18(aftCacheBase(), "lsp-binaries");
32421
32647
  }
32422
32648
  function ghPackageDir(spec) {
32423
- return join17(ghCacheRoot(), spec.id);
32649
+ return join18(ghCacheRoot(), spec.id);
32424
32650
  }
32425
32651
  function ghBinDir(spec) {
32426
- return join17(ghPackageDir(spec), "bin");
32652
+ return join18(ghPackageDir(spec), "bin");
32427
32653
  }
32428
32654
  function ghExtractDir(spec) {
32429
- return join17(ghPackageDir(spec), "extracted");
32655
+ return join18(ghPackageDir(spec), "extracted");
32430
32656
  }
32431
32657
  var INSTALLED_META_FILE2 = ".aft-installed";
32432
32658
  function ghBinaryPath(spec, platform3) {
32433
32659
  const ext = platform3 === "win32" ? ".exe" : "";
32434
- return join17(ghBinDir(spec), `${spec.binary}${ext}`);
32660
+ return join18(ghBinDir(spec), `${spec.binary}${ext}`);
32435
32661
  }
32436
32662
  function isGithubInstalled(spec, platform3) {
32437
32663
  for (const candidate of ghBinaryCandidates(spec, platform3)) {
32438
32664
  try {
32439
- if (statSync7(join17(ghBinDir(spec), candidate)).isFile())
32665
+ if (statSync7(join18(ghBinDir(spec), candidate)).isFile())
32440
32666
  return true;
32441
32667
  } catch {}
32442
32668
  }
@@ -32449,10 +32675,10 @@ function ghBinaryCandidates(spec, platform3) {
32449
32675
  }
32450
32676
  function readGithubInstalledMetaIn(installDir) {
32451
32677
  try {
32452
- const path2 = join17(installDir, INSTALLED_META_FILE2);
32453
- if (!statSync7(path2).isFile())
32678
+ const path3 = join18(installDir, INSTALLED_META_FILE2);
32679
+ if (!statSync7(path3).isFile())
32454
32680
  return null;
32455
- const parsed = JSON.parse(readFileSync12(path2, "utf8"));
32681
+ const parsed = JSON.parse(readFileSync12(path3, "utf8"));
32456
32682
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
32457
32683
  return null;
32458
32684
  return {
@@ -32476,24 +32702,24 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
32476
32702
  binarySha256,
32477
32703
  ...archiveSha256 ? { archiveSha256 } : {}
32478
32704
  };
32479
- writeFileSync9(join17(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
32705
+ writeFileSync9(join18(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
32480
32706
  } catch (err) {
32481
32707
  warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
32482
32708
  }
32483
32709
  }
32484
32710
  var MAX_DOWNLOAD_BYTES3 = 256 * 1024 * 1024;
32485
32711
  var MAX_EXTRACT_BYTES2 = 1024 * 1024 * 1024;
32486
- function sha256OfFile(path2) {
32487
- return new Promise((resolve4, reject) => {
32712
+ function sha256OfFile(path3) {
32713
+ return new Promise((resolve5, reject) => {
32488
32714
  const hash2 = createHash5("sha256");
32489
- const stream = createReadStream2(path2);
32715
+ const stream = createReadStream2(path3);
32490
32716
  stream.on("error", reject);
32491
32717
  stream.on("data", (chunk) => hash2.update(chunk));
32492
- stream.on("end", () => resolve4(hash2.digest("hex")));
32718
+ stream.on("end", () => resolve5(hash2.digest("hex")));
32493
32719
  });
32494
32720
  }
32495
- function sha256OfFileSync2(path2) {
32496
- return createHash5("sha256").update(readFileSync12(path2)).digest("hex");
32721
+ function sha256OfFileSync2(path3) {
32722
+ return createHash5("sha256").update(readFileSync12(path3)).digest("hex");
32497
32723
  }
32498
32724
  async function fetchReleaseByTag(githubRepo, tag, fetchImpl, signal) {
32499
32725
  const candidates = [];
@@ -32725,7 +32951,7 @@ function validateExtraction(stagingRoot) {
32725
32951
  throw new Error(`failed to read staging dir ${dir}: ${err}`);
32726
32952
  }
32727
32953
  for (const entry of entries) {
32728
- const full = join17(dir, entry);
32954
+ const full = join18(dir, entry);
32729
32955
  let lst;
32730
32956
  try {
32731
32957
  lst = lstatSync2(full);
@@ -32737,7 +32963,7 @@ function validateExtraction(stagingRoot) {
32737
32963
  try {
32738
32964
  target = readlinkSync2(full);
32739
32965
  } catch {}
32740
- throw new Error(`archive contains symlink ${relative2(realStagingRoot, full)} → ${target}; rejecting (zip-slip defense)`);
32966
+ throw new Error(`archive contains symlink ${relative3(realStagingRoot, full)} → ${target}; rejecting (zip-slip defense)`);
32741
32967
  }
32742
32968
  let realFull;
32743
32969
  try {
@@ -32745,8 +32971,8 @@ function validateExtraction(stagingRoot) {
32745
32971
  } catch (err) {
32746
32972
  throw new Error(`failed to realpath ${full}: ${err}`);
32747
32973
  }
32748
- const rel = relative2(realStagingRoot, realFull);
32749
- if (rel.startsWith("..") || resolve3(realStagingRoot, rel) !== realFull) {
32974
+ const rel = relative3(realStagingRoot, realFull);
32975
+ if (rel.startsWith("..") || resolve4(realStagingRoot, rel) !== realFull) {
32750
32976
  throw new Error(`archive entry escapes staging root: ${full} → ${realFull} (zip-slip defense)`);
32751
32977
  }
32752
32978
  if (lst.isDirectory()) {
@@ -32813,7 +33039,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
32813
33039
  }
32814
33040
  function quarantineCachedGithubInstall(spec, reason) {
32815
33041
  const packageDir = ghPackageDir(spec);
32816
- const dest = join17(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
33042
+ const dest = join18(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
32817
33043
  warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
32818
33044
  try {
32819
33045
  mkdirSync9(dirname8(dest), { recursive: true });
@@ -32826,7 +33052,7 @@ function quarantineCachedGithubInstall(spec, reason) {
32826
33052
  function validateCachedGithubInstall(spec, platform3) {
32827
33053
  const packageDir = ghPackageDir(spec);
32828
33054
  const meta3 = readGithubInstalledMetaIn(packageDir);
32829
- const binaryPath = ghBinaryCandidates(spec, platform3).map((candidate) => join17(ghBinDir(spec), candidate)).find((candidate) => {
33055
+ const binaryPath = ghBinaryCandidates(spec, platform3).map((candidate) => join18(ghBinDir(spec), candidate)).find((candidate) => {
32830
33056
  try {
32831
33057
  return statSync7(candidate).isFile();
32832
33058
  } catch {
@@ -32904,7 +33130,7 @@ async function downloadAndInstall(spec, tag, assets, platform3, arch, fetchImpl,
32904
33130
  }
32905
33131
  const pkgDir = ghPackageDir(spec);
32906
33132
  const extractDir = ghExtractDir(spec);
32907
- const archivePath = join17(pkgDir, expected.name);
33133
+ const archivePath = join18(pkgDir, expected.name);
32908
33134
  log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
32909
33135
  try {
32910
33136
  await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
@@ -32944,7 +33170,7 @@ async function downloadAndInstall(spec, tag, assets, platform3, arch, fetchImpl,
32944
33170
  unlinkSync6(archivePath);
32945
33171
  } catch {}
32946
33172
  }
32947
- const innerBinaryPath = join17(extractDir, spec.binaryPathInArchive(platform3, arch, version2));
33173
+ const innerBinaryPath = join18(extractDir, spec.binaryPathInArchive(platform3, arch, version2));
32948
33174
  if (!existsSync13(innerBinaryPath)) {
32949
33175
  error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
32950
33176
  return null;
@@ -33239,7 +33465,7 @@ function renderScreen(state, rows = state.rows, cols = state.cols) {
33239
33465
  `);
33240
33466
  }
33241
33467
  function writeTerminal(terminal, data) {
33242
- return new Promise((resolve4) => terminal.write(data, resolve4));
33468
+ return new Promise((resolve5) => terminal.write(data, resolve5));
33243
33469
  }
33244
33470
 
33245
33471
  // src/shared/rpc-server.ts
@@ -33254,18 +33480,18 @@ import {
33254
33480
  writeFileSync as writeFileSync10
33255
33481
  } from "node:fs";
33256
33482
  import { createServer } from "node:http";
33257
- import { dirname as dirname9, join as join19 } from "node:path";
33483
+ import { dirname as dirname9, join as join20 } from "node:path";
33258
33484
 
33259
33485
  // src/shared/rpc-utils.ts
33260
33486
  import { createHash as createHash6 } from "node:crypto";
33261
- import { join as join18 } from "node:path";
33487
+ import { join as join19 } from "node:path";
33262
33488
  function projectHash(directory) {
33263
33489
  const normalized = directory.replace(/\/+$/, "");
33264
33490
  return createHash6("sha256").update(normalized).digest("hex").slice(0, 16);
33265
33491
  }
33266
33492
  function rpcPortFileDir(storageDir, directory) {
33267
33493
  const hash2 = projectHash(directory);
33268
- return join18(storageDir, "rpc", hash2, "ports");
33494
+ return join19(storageDir, "rpc", hash2, "ports");
33269
33495
  }
33270
33496
  function isPidAlive(pid) {
33271
33497
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
@@ -33318,13 +33544,13 @@ class AftRpcServer {
33318
33544
  constructor(storageDir, directory) {
33319
33545
  this.portsDir = rpcPortFileDir(storageDir, directory);
33320
33546
  this.instanceId = randomBytes2(8).toString("hex");
33321
- this.portFilePath = join19(this.portsDir, `${this.instanceId}.json`);
33547
+ this.portFilePath = join20(this.portsDir, `${this.instanceId}.json`);
33322
33548
  }
33323
33549
  handle(method, handler) {
33324
33550
  this.handlers.set(method, handler);
33325
33551
  }
33326
33552
  async start() {
33327
- return new Promise((resolve4, reject) => {
33553
+ return new Promise((resolve5, reject) => {
33328
33554
  const server = createServer((req, res) => this.dispatch(req, res));
33329
33555
  server.on("error", (err) => {
33330
33556
  warn2(`RPC server error: ${err.message}`);
@@ -33357,7 +33583,7 @@ class AftRpcServer {
33357
33583
  } catch (err) {
33358
33584
  warn2(`Failed to write RPC port file: ${err}`);
33359
33585
  }
33360
- resolve4(this.port);
33586
+ resolve5(this.port);
33361
33587
  });
33362
33588
  server.unref();
33363
33589
  });
@@ -33372,7 +33598,7 @@ class AftRpcServer {
33372
33598
  for (const entry of entries) {
33373
33599
  if (!entry.endsWith(".json"))
33374
33600
  continue;
33375
- const filePath = join19(this.portsDir, entry);
33601
+ const filePath = join20(this.portsDir, entry);
33376
33602
  if (filePath === this.portFilePath)
33377
33603
  continue;
33378
33604
  try {
@@ -33777,20 +34003,20 @@ function formatStatusMarkdown(status) {
33777
34003
  // src/shared/tui-config.ts
33778
34004
  var import_comment_json4 = __toESM(require_src2(), 1);
33779
34005
  import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "node:fs";
33780
- import { dirname as dirname10, join as join21 } from "node:path";
34006
+ import { dirname as dirname10, join as join22 } from "node:path";
33781
34007
 
33782
34008
  // src/shared/opencode-config-dir.ts
33783
- import { homedir as homedir11 } from "node:os";
33784
- import { join as join20, resolve as resolve4 } from "node:path";
34009
+ import { homedir as homedir12 } from "node:os";
34010
+ import { join as join21, resolve as resolve5 } from "node:path";
33785
34011
  function getCliConfigDir() {
33786
34012
  const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
33787
34013
  if (envConfigDir) {
33788
- return resolve4(envConfigDir);
34014
+ return resolve5(envConfigDir);
33789
34015
  }
33790
34016
  if (process.platform === "win32") {
33791
- return join20(homedir11(), ".config", "opencode");
34017
+ return join21(homedir12(), ".config", "opencode");
33792
34018
  }
33793
- return join20(process.env.XDG_CONFIG_HOME || join20(homedir11(), ".config"), "opencode");
34019
+ return join21(process.env.XDG_CONFIG_HOME || join21(homedir12(), ".config"), "opencode");
33794
34020
  }
33795
34021
  function getOpenCodeConfigDir2(_options) {
33796
34022
  return getCliConfigDir();
@@ -33799,10 +34025,10 @@ function getOpenCodeConfigPaths(options) {
33799
34025
  const configDir = getOpenCodeConfigDir2(options);
33800
34026
  return {
33801
34027
  configDir,
33802
- configJson: join20(configDir, "opencode.json"),
33803
- configJsonc: join20(configDir, "opencode.jsonc"),
33804
- packageJson: join20(configDir, "package.json"),
33805
- omoConfig: join20(configDir, "magic-context.jsonc")
34028
+ configJson: join21(configDir, "opencode.json"),
34029
+ configJsonc: join21(configDir, "opencode.jsonc"),
34030
+ packageJson: join21(configDir, "package.json"),
34031
+ omoConfig: join21(configDir, "magic-context.jsonc")
33806
34032
  };
33807
34033
  }
33808
34034
 
@@ -33811,8 +34037,8 @@ var PLUGIN_NAME = "@cortexkit/aft-opencode";
33811
34037
  var PLUGIN_ENTRY = `${PLUGIN_NAME}@latest`;
33812
34038
  function resolveTuiConfigPath() {
33813
34039
  const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
33814
- const jsoncPath = join21(configDir, "tui.jsonc");
33815
- const jsonPath = join21(configDir, "tui.json");
34040
+ const jsoncPath = join22(configDir, "tui.jsonc");
34041
+ const jsonPath = join22(configDir, "tui.json");
33816
34042
  if (existsSync15(jsoncPath))
33817
34043
  return jsoncPath;
33818
34044
  if (existsSync15(jsonPath))
@@ -33901,8 +34127,8 @@ function installProcessHandlers() {
33901
34127
  }
33902
34128
  signalShutdownStarted = true;
33903
34129
  process.exitCode = SIGNAL_EXIT_CODES[sig];
33904
- const timeout = new Promise((resolve5) => {
33905
- setTimeout(resolve5, SIGNAL_CLEANUP_TIMEOUT_MS);
34130
+ const timeout = new Promise((resolve6) => {
34131
+ setTimeout(resolve6, SIGNAL_CLEANUP_TIMEOUT_MS);
33906
34132
  });
33907
34133
  Promise.race([runCleanups(sig), timeout]).finally(() => {
33908
34134
  process.exit(SIGNAL_EXIT_CODES[sig]);
@@ -34014,99 +34240,18 @@ import { tool as tool3 } from "@opencode-ai/plugin";
34014
34240
 
34015
34241
  // src/tools/_shared.ts
34016
34242
  import * as fs3 from "node:fs";
34017
- import * as os2 from "node:os";
34018
- import * as path2 from "node:path";
34243
+ import * as os3 from "node:os";
34244
+ import * as path3 from "node:path";
34019
34245
  import { tool as tool2 } from "@opencode-ai/plugin";
34020
34246
  var z2 = tool2.schema;
34021
34247
  var optionalInt = (min, max) => z2.number().int().min(min).max(max).optional();
34022
- function isEmptyParam(value) {
34023
- if (value === undefined || value === null)
34024
- return true;
34025
- if (typeof value === "string")
34026
- return value.length === 0;
34027
- if (Array.isArray(value))
34028
- return value.length === 0;
34029
- if (typeof value === "object")
34030
- return Object.keys(value).length === 0;
34031
- return false;
34032
- }
34033
34248
  var BASH_TRANSPORT_TIMEOUT_MS = 30000;
34034
- function asPlainObject(value) {
34035
- if (!value || typeof value !== "object" || Array.isArray(value))
34036
- return;
34037
- return value;
34038
- }
34039
- function candidateLocation(candidate) {
34040
- const file2 = typeof candidate.file === "string" && candidate.file.length > 0 ? candidate.file : undefined;
34041
- if (!file2)
34042
- return;
34043
- const line = typeof candidate.line === "number" && Number.isFinite(candidate.line) ? candidate.line : undefined;
34044
- return line === undefined ? file2 : `${file2}:${line}`;
34045
- }
34046
- function stringifyData(data) {
34047
- if (data === undefined)
34048
- return;
34049
- try {
34050
- return JSON.stringify(data, null, 2);
34051
- } catch {
34052
- return String(data);
34053
- }
34054
- }
34055
- function formatBridgeErrorMessage(command, response, params = {}) {
34056
- const code = typeof response.code === "string" && response.code.length > 0 ? response.code : undefined;
34057
- const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
34058
- const data = asPlainObject(response.data);
34059
- const rawCandidates = Array.isArray(response.candidates) ? response.candidates : Array.isArray(data?.candidates) ? data.candidates : undefined;
34060
- const rawSymbol = typeof response.symbol === "string" && response.symbol.length > 0 ? response.symbol : typeof data?.symbol === "string" && data.symbol.length > 0 ? data.symbol : undefined;
34061
- if (code === "ambiguous_target" || code === "target_symbol_not_in_file") {
34062
- const candidates = (rawCandidates ?? []).map(asPlainObject).filter((candidate) => candidate !== undefined).map(candidateLocation).filter((candidate) => candidate !== undefined);
34063
- if (candidates.length > 0) {
34064
- const symbol2 = typeof params.toSymbol === "string" && params.toSymbol.length > 0 ? params.toSymbol : rawSymbol;
34065
- const target = symbol2 ? `multiple symbols named "${symbol2}"` : message.replace(/[.!?]+$/, "");
34066
- const action = code === "ambiguous_target" ? "Pass toFile to disambiguate" : "Try one of these files for toFile";
34067
- return `${command}: ${code} — ${target}. ${action}:
34068
- ${candidates.map((candidate) => ` - ${candidate}`).join(`
34069
- `)}`;
34070
- }
34071
- }
34072
- if (!code)
34073
- return message;
34074
- const lines = [`${command}: ${code} — ${message}`];
34075
- const extras = collectStructuredExtras(response);
34076
- if (extras)
34077
- lines.push(`data: ${extras}`);
34078
- return lines.join(`
34079
- `);
34080
- }
34081
- function collectStructuredExtras(response) {
34082
- const reserved = new Set([
34083
- "id",
34084
- "success",
34085
- "code",
34086
- "message",
34087
- "data",
34088
- "status_bar",
34089
- "bg_completions"
34090
- ]);
34091
- const extras = {};
34092
- for (const [key, value] of Object.entries(response)) {
34093
- if (reserved.has(key))
34094
- continue;
34095
- extras[key] = value;
34096
- }
34097
- if (Object.keys(extras).length === 0) {
34098
- return stringifyData(response.data);
34099
- }
34100
- if (response.data !== undefined)
34101
- extras.data = response.data;
34102
- return stringifyData(extras);
34103
- }
34104
34249
  function canonicalizeDirectory(dir) {
34105
34250
  const trimmed = dir.replace(/[/\\]+$/, "");
34106
34251
  try {
34107
34252
  return fs3.realpathSync(trimmed);
34108
34253
  } catch {
34109
- return path2.resolve(trimmed);
34254
+ return path3.resolve(trimmed);
34110
34255
  }
34111
34256
  }
34112
34257
  function projectRootFor(runtime) {
@@ -34123,19 +34268,19 @@ async function resolveProjectRoot(ctx, runtime) {
34123
34268
  }
34124
34269
  return projectRootFor(runtime);
34125
34270
  }
34126
- function expandTilde(input) {
34271
+ function expandTilde2(input) {
34127
34272
  if (!input || !input.startsWith("~"))
34128
34273
  return input;
34129
34274
  if (input === "~")
34130
- return os2.homedir();
34131
- if (input.startsWith("~/") || input.startsWith(`~${path2.sep}`)) {
34132
- return path2.resolve(os2.homedir(), input.slice(2));
34275
+ return os3.homedir();
34276
+ if (input.startsWith("~/") || input.startsWith(`~${path3.sep}`)) {
34277
+ return path3.resolve(os3.homedir(), input.slice(2));
34133
34278
  }
34134
34279
  return input;
34135
34280
  }
34136
34281
  function resolvePathFromProjectRoot(projectRoot, target) {
34137
- const expanded = expandTilde(target);
34138
- return path2.isAbsolute(expanded) ? expanded : path2.resolve(projectRoot, expanded);
34282
+ const expanded = expandTilde2(target);
34283
+ return path3.isAbsolute(expanded) ? expanded : path3.resolve(projectRoot, expanded);
34139
34284
  }
34140
34285
  async function resolvePathArg(ctx, runtime, target) {
34141
34286
  return resolvePathFromProjectRoot(await resolveProjectRoot(ctx, runtime), target);
@@ -34177,19 +34322,19 @@ async function callBashBridge(ctx, runtime, command, params = {}, options) {
34177
34322
 
34178
34323
  // src/tools/permissions.ts
34179
34324
  import * as fs4 from "node:fs";
34180
- import * as path3 from "node:path";
34325
+ import * as path4 from "node:path";
34181
34326
  var UNSUPPORTED_ASK_HOST = "AFT requires OpenCode 1.15.5 or newer for permission asks; please upgrade OpenCode";
34182
34327
  async function runAsk(maybe) {
34183
34328
  await maybe;
34184
34329
  }
34185
34330
  function resolveAbsolutePath(context, target) {
34186
- return path3.isAbsolute(target) ? target : path3.resolve(projectRootFor(context), target);
34331
+ return path4.isAbsolute(target) ? target : path4.resolve(projectRootFor(context), target);
34187
34332
  }
34188
34333
  function resolveRelativePattern(context, target) {
34189
- return path3.relative(projectRootFor(context), resolveAbsolutePath(context, target)) || ".";
34334
+ return path4.relative(projectRootFor(context), resolveAbsolutePath(context, target)) || ".";
34190
34335
  }
34191
34336
  function resolveRelativePatternFromAbsolute(context, absolutePath) {
34192
- return path3.relative(projectRootFor(context), absolutePath) || ".";
34337
+ return path4.relative(projectRootFor(context), absolutePath) || ".";
34193
34338
  }
34194
34339
  function resolveRelativePatterns(context, targets) {
34195
34340
  const seen = new Set;
@@ -34229,8 +34374,8 @@ async function askEditPermission(context, patterns, metadata = {}) {
34229
34374
  function containsPath(parent, child) {
34230
34375
  if (!parent)
34231
34376
  return false;
34232
- const rel = path3.relative(parent, child);
34233
- return rel === "" || !rel.startsWith("..") && !path3.isAbsolute(rel);
34377
+ const rel = path4.relative(parent, child);
34378
+ return rel === "" || !rel.startsWith("..") && !path4.isAbsolute(rel);
34234
34379
  }
34235
34380
  function windowsPath(p) {
34236
34381
  if (process.platform !== "win32")
@@ -34240,7 +34385,7 @@ function windowsPath(p) {
34240
34385
  function normalizePath(p) {
34241
34386
  if (process.platform !== "win32")
34242
34387
  return p;
34243
- const resolved = path3.resolve(windowsPath(p));
34388
+ const resolved = path4.resolve(windowsPath(p));
34244
34389
  try {
34245
34390
  return fs4.realpathSync.native(resolved);
34246
34391
  } catch {
@@ -34256,7 +34401,7 @@ function normalizePathPattern(p) {
34256
34401
  if (!match)
34257
34402
  return normalizePath(p);
34258
34403
  const dir = /^[A-Za-z]:$/.test(match[1]) ? `${match[1]}\\` : match[1];
34259
- return path3.join(normalizePath(dir), match[2]);
34404
+ return path4.join(normalizePath(dir), match[2]);
34260
34405
  }
34261
34406
  async function assertExternalDirectoryPermission(context, target, options) {
34262
34407
  if (!target)
@@ -34275,8 +34420,8 @@ async function assertExternalDirectoryPermission(context, target, options) {
34275
34420
  return;
34276
34421
  }
34277
34422
  const kind = options?.kind ?? "file";
34278
- const parentDir = kind === "directory" ? absoluteTarget : path3.dirname(absoluteTarget);
34279
- const rawGlob = process.platform === "win32" ? normalizePathPattern(path3.join(parentDir, "*")) : path3.join(parentDir, "*").replaceAll("\\", "/");
34423
+ const parentDir = kind === "directory" ? absoluteTarget : path4.dirname(absoluteTarget);
34424
+ const rawGlob = process.platform === "win32" ? normalizePathPattern(path4.join(parentDir, "*")) : path4.join(parentDir, "*").replaceAll("\\", "/");
34280
34425
  try {
34281
34426
  await runAsk(context.ask({
34282
34427
  permission: "external_directory",
@@ -34350,6 +34495,20 @@ function extractHint(response) {
34350
34495
  const hint = response.hint;
34351
34496
  return typeof hint === "string" && hint.length > 0 ? hint : null;
34352
34497
  }
34498
+ function appendSkippedFiles(output, skippedFiles) {
34499
+ if (!skippedFiles || skippedFiles.length === 0)
34500
+ return output;
34501
+ const lines = skippedFiles.map((skipped) => {
34502
+ const file2 = skipped.file ?? "unknown";
34503
+ const reason = skipped.reason ?? "unknown reason";
34504
+ return ` ${file2}: ${reason}`;
34505
+ });
34506
+ return `${output}
34507
+
34508
+ Incomplete: skipped ${skippedFiles.length} file(s)
34509
+ ${lines.join(`
34510
+ `)}`;
34511
+ }
34353
34512
  async function resolveAstPaths(ctx, context, paths) {
34354
34513
  if (isEmptyParam(paths) || !Array.isArray(paths))
34355
34514
  return;
@@ -34374,17 +34533,18 @@ var SUPPORTED_LANGS = [
34374
34533
  "python",
34375
34534
  "rust",
34376
34535
  "go",
34377
- "pascal"
34536
+ "pascal",
34537
+ "r"
34378
34538
  ];
34379
34539
  function astTools(ctx) {
34380
34540
  const searchTool = {
34381
- description: `Search code patterns across filesystem using AST-aware matching. Supports 7 languages.
34541
+ description: `Search code patterns across filesystem using AST-aware matching. Supports 8 languages.
34382
34542
 
34383
34543
  ` + `Use meta-variables: $VAR matches a single AST node, $$$ matches multiple nodes (variadic).
34384
34544
  ` + `IMPORTANT: Patterns must be complete AST nodes (valid code fragments).
34385
34545
  ` + `For functions, include params and body: 'export async function $NAME($$$) { $$$ }' not just 'export async function $NAME'.
34386
34546
 
34387
- ` + "Examples: pattern='console.log($MSG)' lang='typescript', pattern='async function $NAME($$$) { $$$ }' lang='javascript', pattern='def $FUNC($$$): $$$' lang='python', pattern='Writeln($MSG);' lang='pascal'",
34547
+ ` + "Examples: pattern='console.log($MSG)' lang='typescript', pattern='async function $NAME($$$) { $$$ }' lang='javascript', pattern='def $FUNC($$$): $$$' lang='python', pattern='Writeln($MSG);' lang='pascal', pattern='$X <- $Y' lang='r'",
34388
34548
  args: {
34389
34549
  pattern: z3.string().describe("AST pattern with meta-variables ($VAR, $$$). Must be complete AST node."),
34390
34550
  lang: z3.enum(SUPPORTED_LANGS).describe("Target language"),
@@ -34465,6 +34625,9 @@ ${hint}`;
34465
34625
  }
34466
34626
  }
34467
34627
  }
34628
+ if (data.complete === false || (data.skipped_files?.length ?? 0) > 0) {
34629
+ output = appendSkippedFiles(output, data.skipped_files);
34630
+ }
34468
34631
  showOutputToUser(context, output);
34469
34632
  return output;
34470
34633
  }
@@ -34808,7 +34971,7 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
34808
34971
  throw new Error(status.message ?? "bash_status failed");
34809
34972
  }
34810
34973
  if (isTerminalStatus(status.status)) {
34811
- const rendered2 = maybeAppendGrepSearchHint(appendPipeStripNote(formatForegroundResult(status), pipeStrip.note), command, aftSearchRegistered);
34974
+ const rendered2 = maybeAppendGrepSearchHint(appendPipeStripNote(formatForegroundResult(status), pipeStrip.note), command, aftSearchRegistered, projectRootFor(context));
34812
34975
  const metadataPayload2 = foregroundMetadata(description, status, rendered2);
34813
34976
  metadata?.(metadataPayload2);
34814
34977
  return { output: rendered2, title: uiTitle, metadata: metadataPayload2 };
@@ -34872,11 +35035,6 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
34872
35035
  }
34873
35036
  };
34874
35037
  }
34875
- function appendPipeStripNote(output, note) {
34876
- return note ? `${output}
34877
-
34878
- ${note}` : output;
34879
- }
34880
35038
  function createBashStatusTool(ctx) {
34881
35039
  return {
34882
35040
  description: "Read-only snapshot of a background or PTY bash task's current state and output. Returns immediately. Never waits. Use bash_watch to block on or register for pattern matches and exit events.",
@@ -34981,9 +35139,6 @@ function ptyCacheKey(runtime, taskId) {
34981
35139
  function preview(output) {
34982
35140
  return output.length <= METADATA_PREVIEW_LIMIT ? output : output.slice(-METADATA_PREVIEW_LIMIT);
34983
35141
  }
34984
- function isTerminalStatus(status) {
34985
- return status === "completed" || status === "failed" || status === "killed" || status === "timed_out";
34986
- }
34987
35142
  function subagentGuidance(taskId) {
34988
35143
  return `
34989
35144
 
@@ -34999,30 +35154,6 @@ function formatPromotionMessage(taskId, timeout, waitWindowMs) {
34999
35154
  const waited = timeout !== undefined ? Math.min(timeout, waitWindowMs) : waitWindowMs;
35000
35155
  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({ taskId: "${taskId}" }) to inspect output or bash_kill({ taskId: "${taskId}" }) to terminate.`;
35001
35156
  }
35002
- function formatSeconds(ms) {
35003
- return `${Number((ms / 1000).toFixed(1))}s`;
35004
- }
35005
- function formatForegroundResult(data) {
35006
- const output = data.output_preview ?? "";
35007
- const outputPath = data.output_path;
35008
- const truncated = data.output_truncated === true;
35009
- const status = data.status;
35010
- const exit = data.exit_code;
35011
- let rendered = output;
35012
- if (truncated && outputPath) {
35013
- rendered += `
35014
- [output truncated; full output at ${outputPath}]`;
35015
- }
35016
- if (status === "timed_out") {
35017
- rendered += `
35018
- [command timed out]`;
35019
- }
35020
- if (typeof exit === "number" && exit !== 0) {
35021
- rendered += `
35022
- [exit code: ${exit}]`;
35023
- }
35024
- return rendered;
35025
- }
35026
35157
  function foregroundMetadata(description, data, rendered) {
35027
35158
  const outputPath = data.output_path;
35028
35159
  return {
@@ -35033,9 +35164,6 @@ function foregroundMetadata(description, data, rendered) {
35033
35164
  ...outputPath ? { outputPath } : {}
35034
35165
  };
35035
35166
  }
35036
- function sleep(ms) {
35037
- return new Promise((resolve7) => setTimeout(resolve7, ms));
35038
- }
35039
35167
  function getCallID(ctx) {
35040
35168
  const c = ctx;
35041
35169
  return c.callID ?? c.callId ?? c.call_id;
@@ -35058,7 +35186,7 @@ function conflictTools(ctx) {
35058
35186
  execute: async (args, context) => {
35059
35187
  const params = {};
35060
35188
  if (!isEmptyParam(args?.path)) {
35061
- const expanded = expandTilde(String(args.path));
35189
+ const expanded = expandTilde2(String(args.path));
35062
35190
  const projectRoot = await resolveProjectRoot(ctx, context);
35063
35191
  const resolved = resolvePathFromProjectRoot(projectRoot, expanded);
35064
35192
  const denied = await assertExternalDirectoryPermission(context, resolved, {
@@ -35080,7 +35208,7 @@ function conflictTools(ctx) {
35080
35208
 
35081
35209
  // src/tools/hoisted.ts
35082
35210
  import * as fs6 from "node:fs";
35083
- import * as path4 from "node:path";
35211
+ import * as path5 from "node:path";
35084
35212
  import { tool as tool8 } from "@opencode-ai/plugin";
35085
35213
 
35086
35214
  // src/patch-parser.ts
@@ -35520,13 +35648,16 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
35520
35648
  let scanText = "";
35521
35649
  let scanBaseOffset = 0;
35522
35650
  const bridgeOptions = {};
35651
+ if (waitFor?.kind === "regex") {
35652
+ await validateWaitRegex(ctx, runtime, waitFor);
35653
+ }
35523
35654
  clearSyncWatchAbort(runtime.sessionID);
35524
35655
  markTaskWaiting(runtime.sessionID, taskId);
35525
35656
  let sawTerminal = false;
35526
35657
  try {
35527
35658
  while (true) {
35528
35659
  const data = await bashStatusSnapshot2(ctx, runtime, taskId, outputMode, bridgeOptions);
35529
- const terminal = isTerminalStatus2(data.status);
35660
+ const terminal = isTerminalStatus(data.status);
35530
35661
  if (waitFor) {
35531
35662
  const scan = await readNewTaskOutput(runtime, taskId, data, spillCursor);
35532
35663
  if (scan) {
@@ -35534,7 +35665,12 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
35534
35665
  if (scanText.length === 0)
35535
35666
  scanBaseOffset = scan.baseOffset;
35536
35667
  scanText += scan.text;
35537
- const match = findWaitMatch(scanText, waitFor);
35668
+ if (waitFor.kind === "regex") {
35669
+ const trimmed = trimWaitScanBuffer(scanText, scanBaseOffset, waitFor);
35670
+ scanText = trimmed.text;
35671
+ scanBaseOffset = trimmed.baseOffset;
35672
+ }
35673
+ const match = await findWaitMatch(ctx, runtime, scanText, waitFor);
35538
35674
  if (match) {
35539
35675
  if (terminal) {
35540
35676
  sawTerminal = true;
@@ -35545,12 +35681,14 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
35545
35681
  reason: "matched",
35546
35682
  elapsed_ms: Date.now() - startedAt,
35547
35683
  match: match.text,
35548
- match_offset: scanBaseOffset + Buffer.byteLength(scanText.slice(0, match.index), "utf8")
35684
+ match_offset: scanBaseOffset + match.byteOffset
35549
35685
  });
35550
35686
  }
35551
- const trimmed = trimWaitScanBuffer(scanText, scanBaseOffset, waitFor);
35552
- scanText = trimmed.text;
35553
- scanBaseOffset = trimmed.baseOffset;
35687
+ if (waitFor.kind === "substring") {
35688
+ const trimmed = trimWaitScanBuffer(scanText, scanBaseOffset, waitFor);
35689
+ scanText = trimmed.text;
35690
+ scanBaseOffset = trimmed.baseOffset;
35691
+ }
35554
35692
  }
35555
35693
  }
35556
35694
  if (terminal) {
@@ -35565,7 +35703,7 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
35565
35703
  if (Date.now() >= deadline) {
35566
35704
  return withWaited(data, { reason: "timeout", elapsed_ms: Date.now() - startedAt });
35567
35705
  }
35568
- await sleep2(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())));
35706
+ await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())));
35569
35707
  }
35570
35708
  } finally {
35571
35709
  if (!sawTerminal)
@@ -35631,20 +35769,41 @@ function parseWaitPattern(value) {
35631
35769
  if (typeof value === "string")
35632
35770
  return { kind: "substring", value };
35633
35771
  if (isRegexWaitObject(value))
35634
- return { kind: "regex", value: new RegExp(value.regex), source: value.regex };
35772
+ return { kind: "regex", source: value.regex };
35635
35773
  return;
35636
35774
  }
35637
35775
  function isRegexWaitObject(value) {
35638
35776
  return typeof value === "object" && value !== null && "regex" in value && typeof value.regex === "string";
35639
35777
  }
35640
- function findWaitMatch(text, pattern) {
35778
+ async function validateWaitRegex(ctx, runtime, pattern) {
35779
+ await matchRegexWithBridge(ctx, runtime, pattern.source, "");
35780
+ }
35781
+ async function findWaitMatch(ctx, runtime, text, pattern) {
35641
35782
  if (pattern.kind === "substring") {
35642
35783
  const index = text.indexOf(pattern.value);
35643
- return index >= 0 ? { text: pattern.value, index } : undefined;
35784
+ return index >= 0 ? { text: pattern.value, byteOffset: Buffer.byteLength(text.slice(0, index), "utf8") } : undefined;
35644
35785
  }
35645
- pattern.value.lastIndex = 0;
35646
- const match = pattern.value.exec(text);
35647
- return match ? { text: match[0], index: match.index } : undefined;
35786
+ return await matchRegexWithBridge(ctx, runtime, pattern.source, text);
35787
+ }
35788
+ async function matchRegexWithBridge(ctx, runtime, pattern, text) {
35789
+ const result = await callBashBridge(ctx, runtime, "bash_regex_match", { pattern, text });
35790
+ if (result.success === false) {
35791
+ const code = String(result.code ?? "invalid_request");
35792
+ const message = String(result.message ?? "bash_regex_match failed");
35793
+ if (code === "invalid_regex")
35794
+ throw new Error(`invalid_request: invalid_regex: ${message}`);
35795
+ throw new Error(`${code}: ${message}`);
35796
+ }
35797
+ if (result.matched !== true)
35798
+ return;
35799
+ return {
35800
+ text: typeof result.match_text === "string" ? result.match_text : "",
35801
+ byteOffset: coerceMatchOffset(result.match_offset)
35802
+ };
35803
+ }
35804
+ function coerceMatchOffset(value) {
35805
+ const offset = typeof value === "number" ? value : Number(value ?? 0);
35806
+ return Number.isFinite(offset) && offset >= 0 ? offset : 0;
35648
35807
  }
35649
35808
  function trimWaitScanBuffer(text, baseOffset, pattern) {
35650
35809
  const keepFrom = pattern.kind === "substring" ? substringKeepStart(text, pattern.value) : regexKeepStart(text, REGEX_WAIT_SCAN_WINDOW_BYTES);
@@ -35677,18 +35836,12 @@ function regexKeepStart(text, maxBytes) {
35677
35836
  function withWaited(data, waited) {
35678
35837
  return { ...data, waited };
35679
35838
  }
35680
- function isTerminalStatus2(status) {
35681
- return status === "completed" || status === "failed" || status === "killed" || status === "timed_out";
35682
- }
35683
35839
  function ptyCacheKey2(runtime, taskId) {
35684
35840
  return `${projectRootFor(runtime)}::${runtime.sessionID ?? "__default__"}::${taskId}`;
35685
35841
  }
35686
35842
  function watchPtyCacheKey(runtime, taskId) {
35687
35843
  return `${ptyCacheKey2(runtime, taskId)}::watch`;
35688
35844
  }
35689
- function sleep2(ms) {
35690
- return new Promise((resolve7) => setTimeout(resolve7, ms));
35691
- }
35692
35845
 
35693
35846
  // src/tools/bash_write.ts
35694
35847
  import { tool as tool7 } from "@opencode-ai/plugin";
@@ -35723,21 +35876,10 @@ function createBashWriteTool(ctx) {
35723
35876
 
35724
35877
  // src/tools/hoisted.ts
35725
35878
  function relativeToWorktree(fp, worktree) {
35726
- return path4.relative(worktree, fp);
35879
+ return path5.relative(worktree, fp);
35727
35880
  }
35728
- function formatReadFooter(agentSpecifiedRange, data) {
35729
- if (agentSpecifiedRange)
35730
- return "";
35731
- if (!data.truncated)
35732
- return "";
35733
- const startLine = data.start_line;
35734
- const endLine = data.end_line;
35735
- const totalLines = data.total_lines;
35736
- if (startLine === undefined || endLine === undefined || totalLines === undefined) {
35737
- return "";
35738
- }
35739
- return `
35740
- (Showing lines ${startLine}-${endLine} of ${totalLines}. Use startLine/endLine to read other sections.)`;
35881
+ function formatReadFooter2(agentSpecifiedRange, data) {
35882
+ return formatReadFooter(agentSpecifiedRange, data, { rangeHint: "startLine/endLine" });
35741
35883
  }
35742
35884
  function buildUnifiedDiff(fp, before, after) {
35743
35885
  const beforeLines = before.split(`
@@ -36064,7 +36206,7 @@ function createReadTool(ctx) {
36064
36206
  return permissionDeniedResponse(error50.message);
36065
36207
  return permissionDeniedResponse("Permission denied.");
36066
36208
  }
36067
- const ext = path4.extname(filePath).toLowerCase();
36209
+ const ext = path5.extname(filePath).toLowerCase();
36068
36210
  const mimeMap = {
36069
36211
  ".png": "image/png",
36070
36212
  ".jpg": "image/jpeg",
@@ -36093,7 +36235,7 @@ function createReadTool(ctx) {
36093
36235
  const msg = `${label} read successfully`;
36094
36236
  return {
36095
36237
  output: `${msg} (${ext.slice(1).toUpperCase()}, ${sizeStr}). File: ${filePath}`,
36096
- title: path4.relative(projectRoot, filePath),
36238
+ title: path5.relative(projectRoot, filePath),
36097
36239
  metadata: {
36098
36240
  preview: msg,
36099
36241
  filepath: filePath,
@@ -36135,7 +36277,7 @@ function createReadTool(ctx) {
36135
36277
  }
36136
36278
  let output = data.content;
36137
36279
  const agentSpecifiedRange = args.startLine !== undefined || args.endLine !== undefined || args.offset !== undefined || args.limit !== undefined;
36138
- const footer = formatReadFooter(agentSpecifiedRange, data);
36280
+ const footer = formatReadFooter2(agentSpecifiedRange, data);
36139
36281
  if (footer)
36140
36282
  output += footer;
36141
36283
  return { output, title: dp, metadata: { title: dp } };
@@ -36157,7 +36299,7 @@ function createWriteTool(ctx, editToolName = "edit") {
36157
36299
  const content = args.content;
36158
36300
  const projectRoot = await resolveProjectRoot(ctx, context);
36159
36301
  const filePath = resolvePathFromProjectRoot(projectRoot, file2);
36160
- const relPath = path4.relative(projectRoot, filePath);
36302
+ const relPath = path5.relative(projectRoot, filePath);
36161
36303
  {
36162
36304
  const denial2 = await assertExternalDirectoryPermission(context, filePath);
36163
36305
  if (denial2)
@@ -36308,7 +36450,7 @@ function createEditTool(ctx, writeToolName = "write") {
36308
36450
  throw new Error("'filePath' parameter is required");
36309
36451
  const projectRoot = await resolveProjectRoot(ctx, context);
36310
36452
  const filePath = resolvePathFromProjectRoot(projectRoot, file2);
36311
- const relPath = path4.relative(projectRoot, filePath);
36453
+ const relPath = path5.relative(projectRoot, filePath);
36312
36454
  {
36313
36455
  const denial2 = await assertExternalDirectoryPermission(context, filePath);
36314
36456
  if (denial2)
@@ -36511,22 +36653,34 @@ function createApplyPatchTool(ctx) {
36511
36653
  }
36512
36654
  const projectRoot = await resolveProjectRoot(ctx, context);
36513
36655
  const affectedAbs = new Set;
36656
+ const initiallyExistsAbs = new Map;
36657
+ const rememberAffectedPath = (abs) => {
36658
+ affectedAbs.add(abs);
36659
+ if (!initiallyExistsAbs.has(abs)) {
36660
+ initiallyExistsAbs.set(abs, fs6.existsSync(abs));
36661
+ }
36662
+ };
36663
+ for (const h of hunks) {
36664
+ const srcAbs = resolvePathFromProjectRoot(projectRoot, h.path);
36665
+ rememberAffectedPath(srcAbs);
36666
+ if (h.type === "update" && h.move_path) {
36667
+ rememberAffectedPath(resolvePathFromProjectRoot(projectRoot, h.move_path));
36668
+ }
36669
+ }
36514
36670
  const newlyCreatedAbs = new Set;
36515
36671
  for (const h of hunks) {
36516
36672
  const srcAbs = resolvePathFromProjectRoot(projectRoot, h.path);
36517
- affectedAbs.add(srcAbs);
36518
- if (h.type === "add") {
36673
+ if (h.type === "add" && initiallyExistsAbs.get(srcAbs) === false) {
36519
36674
  newlyCreatedAbs.add(srcAbs);
36520
36675
  }
36521
36676
  if (h.type === "update" && h.move_path) {
36522
36677
  const dstAbs = resolvePathFromProjectRoot(projectRoot, h.move_path);
36523
- affectedAbs.add(dstAbs);
36524
- if (!fs6.existsSync(dstAbs)) {
36678
+ if (initiallyExistsAbs.get(dstAbs) === false) {
36525
36679
  newlyCreatedAbs.add(dstAbs);
36526
36680
  }
36527
36681
  }
36528
36682
  }
36529
- const relPaths = Array.from(affectedAbs).map((abs) => path4.relative(projectRoot, abs));
36683
+ const relPaths = Array.from(affectedAbs).map((abs) => path5.relative(projectRoot, abs));
36530
36684
  const multiFileWritePaths = Array.from(affectedAbs);
36531
36685
  {
36532
36686
  const asked = new Set;
@@ -36560,15 +36714,15 @@ function createApplyPatchTool(ctx) {
36560
36714
  }
36561
36715
  const results = [];
36562
36716
  const failures = [];
36563
- const perFileDiffs = [];
36564
- for (const hunk of hunks) {
36717
+ const appliedHunkResults = [];
36718
+ for (const [hunkIndex, hunk] of hunks.entries()) {
36565
36719
  const filePath = resolvePathFromProjectRoot(projectRoot, hunk.path);
36566
36720
  switch (hunk.type) {
36567
36721
  case "add": {
36568
36722
  if (fs6.existsSync(filePath)) {
36569
36723
  const msg = `Failed to create ${hunk.path}: file already exists. Use *** Update File: to modify, or *** Delete File: first if you want to replace it entirely.`;
36570
36724
  results.push(msg);
36571
- failures.push(hunk.path);
36725
+ failures.push({ index: hunkIndex, path: hunk.path });
36572
36726
  break;
36573
36727
  }
36574
36728
  try {
@@ -36590,10 +36744,13 @@ function createApplyPatchTool(ctx) {
36590
36744
  throw new Error("produced invalid syntax (rolled back)");
36591
36745
  }
36592
36746
  const wrDiff = writeResult.diff;
36593
- perFileDiffs.push({
36747
+ appliedHunkResults.push({
36748
+ index: hunkIndex,
36749
+ hunk,
36594
36750
  filePath,
36751
+ displayPath: filePath,
36595
36752
  before: "",
36596
- after: hunk.contents,
36753
+ after: content,
36597
36754
  additions: wrDiff?.additions ?? lineCount(content),
36598
36755
  deletions: wrDiff?.deletions ?? 0
36599
36756
  });
@@ -36601,7 +36758,7 @@ function createApplyPatchTool(ctx) {
36601
36758
  } catch (e) {
36602
36759
  const msg = `Failed to create ${hunk.path}: ${e instanceof Error ? e.message : e}`;
36603
36760
  results.push(msg);
36604
- failures.push(hunk.path);
36761
+ failures.push({ index: hunkIndex, path: hunk.path });
36605
36762
  const filePath2 = resolvePathFromProjectRoot(projectRoot, hunk.path);
36606
36763
  if (fs6.existsSync(filePath2)) {
36607
36764
  try {
@@ -36620,8 +36777,11 @@ function createApplyPatchTool(ctx) {
36620
36777
  if (deleteResult.success === false) {
36621
36778
  throw new Error(deleteResult.message ?? "delete failed");
36622
36779
  }
36623
- perFileDiffs.push({
36780
+ appliedHunkResults.push({
36781
+ index: hunkIndex,
36782
+ hunk,
36624
36783
  filePath,
36784
+ displayPath: filePath,
36625
36785
  before,
36626
36786
  after: "",
36627
36787
  additions: 0,
@@ -36630,7 +36790,7 @@ function createApplyPatchTool(ctx) {
36630
36790
  results.push(`Deleted ${hunk.path}`);
36631
36791
  } catch (e) {
36632
36792
  results.push(`Failed to delete ${hunk.path}: ${e instanceof Error ? e.message : e}`);
36633
- failures.push(hunk.path);
36793
+ failures.push({ index: hunkIndex, path: hunk.path });
36634
36794
  }
36635
36795
  break;
36636
36796
  }
@@ -36657,7 +36817,7 @@ function createApplyPatchTool(ctx) {
36657
36817
  if (diags && diags.length > 0) {
36658
36818
  const errors3 = diags.filter((d) => d.severity === "error");
36659
36819
  if (errors3.length > 0) {
36660
- const relPath = path4.relative(projectRoot, targetPath);
36820
+ const relPath = path5.relative(projectRoot, targetPath);
36661
36821
  const diagLines = errors3.map((d) => ` Line ${d.line}: ${d.message}`).join(`
36662
36822
  `);
36663
36823
  results.push(`
@@ -36671,13 +36831,17 @@ ${diagLines}`);
36671
36831
  additions: wrDiff.additions,
36672
36832
  deletions: wrDiff.deletions
36673
36833
  };
36674
- perFileDiffs.push({
36834
+ const appliedHunkResult = {
36835
+ index: hunkIndex,
36836
+ hunk,
36675
36837
  filePath,
36838
+ displayPath: targetPath,
36839
+ ...hunk.move_path ? { movePath: targetPath } : {},
36676
36840
  before: original,
36677
36841
  after: newContent,
36678
36842
  additions,
36679
36843
  deletions
36680
- });
36844
+ };
36681
36845
  if (hunk.move_path) {
36682
36846
  try {
36683
36847
  const deleteResult = await callBridge(ctx, context, "delete_file", {
@@ -36710,13 +36874,15 @@ ${diagLines}`);
36710
36874
  }
36711
36875
  throw new Error(`source delete failed after writing move destination; restored pre-patch checkpoint ${checkpointName}: ${formatError2(deleteError)}`);
36712
36876
  }
36877
+ appliedHunkResults.push(appliedHunkResult);
36713
36878
  results.push(`Updated and moved ${hunk.path} → ${hunk.move_path}`);
36714
36879
  } else {
36880
+ appliedHunkResults.push(appliedHunkResult);
36715
36881
  results.push(`Updated ${hunk.path}`);
36716
36882
  }
36717
36883
  } catch (e) {
36718
36884
  results.push(`Failed to update ${hunk.path}: ${e instanceof Error ? e.message : e}`);
36719
- failures.push(hunk.path);
36885
+ failures.push({ index: hunkIndex, path: hunk.path });
36720
36886
  break;
36721
36887
  }
36722
36888
  break;
@@ -36725,7 +36891,8 @@ ${diagLines}`);
36725
36891
  }
36726
36892
  if (failures.length > 0) {
36727
36893
  const partial2 = failures.length < hunks.length;
36728
- const summary = partial2 ? `Patch partially applied — ${hunks.length - failures.length} of ${hunks.length} hunk(s) succeeded. Failed: ${failures.join(", ")}. Successful changes are kept; use \`aft_safety\` to revert if you want to abort.` : `Patch failed — none of the ${hunks.length} hunk(s) applied: ${failures.join(", ")}.`;
36894
+ const failedList = failures.map((failure) => failure.path).join(", ");
36895
+ const summary = partial2 ? `Patch partially applied — ${hunks.length - failures.length} of ${hunks.length} hunk(s) succeeded. Failed: ${failedList}. Successful changes are kept; use \`aft_safety\` to revert if you want to abort.` : `Patch failed — none of the ${hunks.length} hunk(s) applied: ${failedList}.`;
36729
36896
  results.push(summary);
36730
36897
  if (!partial2) {
36731
36898
  throw new Error(results.join(`
@@ -36733,28 +36900,56 @@ ${diagLines}`);
36733
36900
  }
36734
36901
  }
36735
36902
  {
36736
- const diffByPath = new Map(perFileDiffs.map((d) => [d.filePath, d]));
36737
- const failedPaths = new Set(failures);
36738
- const appliedHunks = hunks.filter((h) => !failedPaths.has(h.path));
36739
- const files = appliedHunks.map((h) => {
36740
- const filePath = resolvePathFromProjectRoot(projectRoot, h.path);
36741
- const rawMovePath = h.type === "update" ? h.move_path : undefined;
36742
- const movePath = rawMovePath ? resolvePathFromProjectRoot(projectRoot, rawMovePath) : undefined;
36743
- const displayPath = movePath ?? filePath;
36744
- const relPath = path4.relative(projectRoot, displayPath);
36745
- const diffEntry = diffByPath.get(filePath);
36746
- const patch = diffEntry ? buildUnifiedDiff(displayPath, diffEntry.before, diffEntry.after) : "";
36747
- const additions = diffEntry?.additions ?? 0;
36748
- const deletions = diffEntry?.deletions ?? 0;
36749
- const uiType = h.type === "update" && rawMovePath ? "move" : h.type;
36903
+ const diffByReportKey = new Map;
36904
+ for (const applied of appliedHunkResults) {
36905
+ const reportKey = applied.movePath ? `${applied.filePath}\x00${applied.displayPath}` : applied.filePath;
36906
+ const existing = diffByReportKey.get(reportKey);
36907
+ if (!existing) {
36908
+ diffByReportKey.set(reportKey, {
36909
+ filePath: applied.filePath,
36910
+ displayPath: applied.displayPath,
36911
+ ...applied.movePath ? { movePath: applied.movePath } : {},
36912
+ lastHunk: applied.hunk,
36913
+ before: applied.before,
36914
+ after: applied.after,
36915
+ additions: applied.additions,
36916
+ deletions: applied.deletions,
36917
+ hunkCount: 1
36918
+ });
36919
+ continue;
36920
+ }
36921
+ existing.displayPath = applied.displayPath;
36922
+ existing.movePath = applied.movePath ?? existing.movePath;
36923
+ existing.lastHunk = applied.hunk;
36924
+ existing.after = applied.after;
36925
+ existing.hunkCount += 1;
36926
+ const netCounts = countDiffLines(existing.before, existing.after);
36927
+ existing.additions = netCounts.additions;
36928
+ existing.deletions = netCounts.deletions;
36929
+ }
36930
+ const files = Array.from(diffByReportKey.values()).map((entry) => {
36931
+ const relPath = path5.relative(projectRoot, entry.displayPath);
36932
+ const patch = buildUnifiedDiff(entry.displayPath, entry.before, entry.after);
36933
+ let uiType;
36934
+ if (entry.movePath) {
36935
+ uiType = "move";
36936
+ } else if (entry.hunkCount === 1) {
36937
+ uiType = entry.lastHunk.type;
36938
+ } else if (entry.before.length === 0 && entry.after.length > 0) {
36939
+ uiType = "add";
36940
+ } else if (entry.before.length > 0 && entry.after.length === 0) {
36941
+ uiType = "delete";
36942
+ } else {
36943
+ uiType = "update";
36944
+ }
36750
36945
  return {
36751
- filePath,
36946
+ filePath: entry.filePath,
36752
36947
  relativePath: relPath,
36753
36948
  type: uiType,
36754
36949
  patch,
36755
- additions,
36756
- deletions,
36757
- ...movePath ? { movePath } : {}
36950
+ additions: entry.additions,
36951
+ deletions: entry.deletions,
36952
+ ...entry.movePath ? { movePath: entry.movePath } : {}
36758
36953
  };
36759
36954
  });
36760
36955
  const fileList = files.map((f) => {
@@ -36762,7 +36957,7 @@ ${diagLines}`);
36762
36957
  return `${prefix} ${f.relativePath}`;
36763
36958
  }).join(`
36764
36959
  `);
36765
- const title = failures.length > 0 ? `Partially applied (${files.length} of ${hunks.length}). Updated:
36960
+ const title = failures.length > 0 ? `Partially applied (${hunks.length - failures.length} of ${hunks.length}). Updated:
36766
36961
  ${fileList}` : `Success. Updated the following files:
36767
36962
  ${fileList}`;
36768
36963
  const diffText = files.map((f) => f.patch).filter(Boolean).join(`
@@ -36915,7 +37110,7 @@ function aftPrefixedTools(ctx) {
36915
37110
  const file2 = normalizedArgs.filePath;
36916
37111
  const projectRoot = await resolveProjectRoot(ctx, context);
36917
37112
  const filePath = resolvePathFromProjectRoot(projectRoot, file2);
36918
- const relPath = path4.relative(projectRoot, filePath);
37113
+ const relPath = path5.relative(projectRoot, filePath);
36919
37114
  {
36920
37115
  const denial2 = await assertExternalDirectoryPermission(context, filePath);
36921
37116
  if (denial2)
@@ -37312,15 +37507,15 @@ function buildZoomTitle(args) {
37312
37507
  }
37313
37508
  return `${args.targets.filePath}#${args.targets.symbol}`;
37314
37509
  }
37315
- const path5 = args.filePath ?? args.url ?? "";
37510
+ const path6 = args.filePath ?? args.url ?? "";
37316
37511
  if (typeof args.symbols === "string")
37317
- return path5 ? `${path5}#${args.symbols}` : args.symbols;
37512
+ return path6 ? `${path6}#${args.symbols}` : args.symbols;
37318
37513
  if (Array.isArray(args.symbols) && args.symbols.length > 0) {
37319
37514
  if (args.symbols.length === 1)
37320
- return path5 ? `${path5}#${args.symbols[0]}` : args.symbols[0];
37321
- return path5 ? `${path5} (${args.symbols.length} symbols)` : `${args.symbols.length} symbols`;
37515
+ return path6 ? `${path6}#${args.symbols[0]}` : args.symbols[0];
37516
+ return path6 ? `${path6} (${args.symbols.length} symbols)` : `${args.symbols.length} symbols`;
37322
37517
  }
37323
- return path5 || "(no target)";
37518
+ return path6 || "(no target)";
37324
37519
  }
37325
37520
  function readingTools(ctx) {
37326
37521
  return {
@@ -37553,6 +37748,11 @@ function readingTools(ctx) {
37553
37748
  }));
37554
37749
  if (symbolsArray.length === 1) {
37555
37750
  const response = results[0] ?? { success: false, message: "missing zoom response" };
37751
+ const rustBatch = unwrapRustZoomBatchEnvelope(response);
37752
+ if (rustBatch) {
37753
+ const batch = formatZoomBatchResult(targetLabel, rustBatch.names, rustBatch.responses);
37754
+ return withMeta(batch.text);
37755
+ }
37556
37756
  if (response.success === false) {
37557
37757
  throw new Error(response.message || "zoom failed");
37558
37758
  }
@@ -37821,11 +38021,11 @@ function refactoringTools(ctx) {
37821
38021
  }
37822
38022
 
37823
38023
  // src/tools/safety.ts
37824
- import * as path5 from "node:path";
38024
+ import * as path6 from "node:path";
37825
38025
  import { tool as tool14 } from "@opencode-ai/plugin";
37826
38026
  var z14 = tool14.schema;
37827
38027
  function responsePaths(response) {
37828
- return Array.isArray(response.paths) ? response.paths.filter((path6) => typeof path6 === "string" && path6.length > 0) : [];
38028
+ return Array.isArray(response.paths) ? response.paths.filter((path7) => typeof path7 === "string" && path7.length > 0) : [];
37829
38029
  }
37830
38030
  function bridgeErrorMessage(response, fallback) {
37831
38031
  return typeof response.message === "string" && response.message.length > 0 ? response.message : fallback;
@@ -37902,9 +38102,9 @@ function safetyTools(ctx) {
37902
38102
  for (const rawFile of checkpointFiles) {
37903
38103
  if (typeof rawFile !== "string")
37904
38104
  continue;
37905
- const file2 = expandTilde(rawFile);
37906
- const abs = path5.isAbsolute(file2) ? file2 : path5.resolve(projectRoot, file2);
37907
- const parent = path5.dirname(abs);
38105
+ const file2 = expandTilde2(rawFile);
38106
+ const abs = path6.isAbsolute(file2) ? file2 : path6.resolve(projectRoot, file2);
38107
+ const parent = path6.dirname(abs);
37908
38108
  if (uniqueParents.has(parent))
37909
38109
  continue;
37910
38110
  uniqueParents.add(parent);
@@ -37942,8 +38142,8 @@ function safetyTools(ctx) {
37942
38142
  const params = {};
37943
38143
  if (args.name !== undefined)
37944
38144
  params.name = args.name;
37945
- const payloadFiles = coerceStringArray(args.files).map(expandTilde);
37946
- const filePathArg = typeof args.filePath === "string" ? expandTilde(args.filePath) : undefined;
38145
+ const payloadFiles = coerceStringArray(args.files).map(expandTilde2);
38146
+ const filePathArg = typeof args.filePath === "string" ? expandTilde2(args.filePath) : undefined;
37947
38147
  if (op === "checkpoint") {
37948
38148
  if (payloadFiles.length > 0) {
37949
38149
  params.files = payloadFiles;
@@ -37968,7 +38168,7 @@ function safetyTools(ctx) {
37968
38168
 
37969
38169
  // src/tools/search.ts
37970
38170
  import * as fs7 from "node:fs";
37971
- import * as path6 from "node:path";
38171
+ import * as path7 from "node:path";
37972
38172
  function arg2(schema) {
37973
38173
  return schema;
37974
38174
  }
@@ -38000,7 +38200,7 @@ function normalizeGlob(pattern) {
38000
38200
  return pattern;
38001
38201
  }
38002
38202
  function absoluteSearchPath(projectRoot, target) {
38003
- return resolvePathFromProjectRoot(projectRoot, expandTilde(target));
38203
+ return resolvePathFromProjectRoot(projectRoot, expandTilde2(target));
38004
38204
  }
38005
38205
  function searchPathExists(projectRoot, target) {
38006
38206
  return fs7.existsSync(absoluteSearchPath(projectRoot, target));
@@ -38077,7 +38277,7 @@ function searchTools(ctx) {
38077
38277
  const projectRoot = await resolveProjectRoot(ctx, context);
38078
38278
  const pattern = String(args.pattern);
38079
38279
  const includeArg = args.include ? String(args.include) : undefined;
38080
- const pathArg = args.path ? expandTilde(String(args.path)) : undefined;
38280
+ const pathArg = args.path ? expandTilde2(String(args.path)) : undefined;
38081
38281
  const bridgePath = pathArg ? absoluteSearchPath(projectRoot, pathArg) : undefined;
38082
38282
  const grepDenied = await askGrepPermission(context, pattern, {
38083
38283
  path: bridgePath,
@@ -38115,8 +38315,8 @@ function searchTools(ctx) {
38115
38315
  },
38116
38316
  execute: async (args, context) => {
38117
38317
  const projectRoot = await resolveProjectRoot(ctx, context);
38118
- let globPattern = expandTilde(String(args.pattern));
38119
- let globPath = args.path ? expandTilde(String(args.path)) : undefined;
38318
+ let globPattern = expandTilde2(String(args.pattern));
38319
+ let globPath = args.path ? expandTilde2(String(args.path)) : undefined;
38120
38320
  if (!globPath && globPattern.startsWith("/")) {
38121
38321
  const metaIdx = globPattern.search(/[*?{}[\]]/);
38122
38322
  if (metaIdx > 0) {
@@ -38126,8 +38326,8 @@ function searchTools(ctx) {
38126
38326
  globPattern = `**/${globPattern.slice(lastSlash + 1)}`;
38127
38327
  }
38128
38328
  } else if (metaIdx === -1) {
38129
- globPath = path6.dirname(globPattern);
38130
- globPattern = path6.basename(globPattern);
38329
+ globPath = path7.dirname(globPattern);
38330
+ globPattern = path7.basename(globPattern);
38131
38331
  }
38132
38332
  }
38133
38333
  const globDenied = await askGlobPermission(context, globPattern, { path: globPath });
@@ -38492,13 +38692,13 @@ ${lines}
38492
38692
  const upgradePromise = (async () => {
38493
38693
  warn2(`WARNING: aft binary v${binaryVersion} is older than plugin v${minVersion}. ` + "Some features may not work. Attempting to download a compatible binary...");
38494
38694
  try {
38495
- const path7 = await ensureBinary(`v${minVersion}`);
38496
- if (!path7) {
38695
+ const path8 = await ensureBinary(`v${minVersion}`);
38696
+ if (!path8) {
38497
38697
  warn2(`Could not find or download v${minVersion}. Continuing with v${binaryVersion}.`);
38498
38698
  return null;
38499
38699
  }
38500
- log2(`Found/downloaded compatible binary at ${path7}. Replacing running bridges...`);
38501
- const replaced = await pool.replaceBinary(path7);
38700
+ log2(`Found/downloaded compatible binary at ${path8}. Replacing running bridges...`);
38701
+ const replaced = await pool.replaceBinary(path8);
38502
38702
  log2("Binary replaced successfully. New bridges will use the updated binary.");
38503
38703
  return replaced;
38504
38704
  } catch (err) {