@cortexkit/aft-opencode 0.63.5 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/config-live-reload.d.ts +4 -16
  2. package/dist/config-live-reload.d.ts.map +1 -1
  3. package/dist/config.d.ts +11 -28
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/entry/server.js +774 -410
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +774 -410
  8. package/dist/lsp-auto-install.d.ts.map +1 -1
  9. package/dist/shared/session-directory.d.ts +4 -2
  10. package/dist/shared/session-directory.d.ts.map +1 -1
  11. package/dist/shared/status.d.ts +0 -4
  12. package/dist/shared/status.d.ts.map +1 -1
  13. package/dist/subc-tool-schemas.d.ts +4 -3
  14. package/dist/subc-tool-schemas.d.ts.map +1 -1
  15. package/dist/tools/_shared.d.ts +11 -17
  16. package/dist/tools/_shared.d.ts.map +1 -1
  17. package/dist/tools/bash_watch.d.ts +6 -3
  18. package/dist/tools/bash_watch.d.ts.map +1 -1
  19. package/dist/tools/definitions/v2.d.ts +25 -0
  20. package/dist/tools/definitions/v2.d.ts.map +1 -1
  21. package/dist/tools/inspect.d.ts +0 -15
  22. package/dist/tools/inspect.d.ts.map +1 -1
  23. package/dist/tui/preferences.d.ts +1 -1
  24. package/dist/tui/v2-status.d.ts +3 -2
  25. package/dist/tui/v2-status.d.ts.map +1 -1
  26. package/dist/v2-session-lifecycle.d.ts.map +1 -1
  27. package/package.json +8 -8
  28. package/src/shared/session-directory.ts +10 -5
  29. package/src/shared/status.ts +2 -22
  30. package/src/tui/index.tsx +1 -25
  31. package/src/tui/preferences.ts +1 -1
  32. package/src/tui/sidebar-view.tsx +2 -39
  33. package/src/tui/v2-status.ts +5 -14
  34. package/src/tui-compiled/index.tsx +2 -41
  35. package/src/tui-compiled/preferences.ts +1 -1
  36. package/src/tui-compiled/sidebar-view.tsx +34 -72
  37. package/src/tui-compiled/v2-status.ts +5 -14
@@ -9542,9 +9542,10 @@ var BASH_HOST_FALLBACK_BANNER = "[AFT host fallback - module transport down; no
9542
9542
  var BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES = 100 * 1024;
9543
9543
  var BASH_HOST_FALLBACK_MAX_TIMEOUT_MS = 10 * 60 * 1000;
9544
9544
  var BASH_HOST_FALLBACK_REFUSAL = "AFT module connection is down";
9545
- var BASH_RUNON_DESCRIPTION = 'Run on a remote build server: `linux` (2 vCPUs), or `linux,Nc` for N vCPUs such as `linux,8c`; add ",net" for outbound internet (offline by default). `windows` runs the command in Git Bash on a Windows build machine (no vCPU or network options). `macos` sends the command to a macOS machine for builds and tests that need macOS (no vCPU or network options).';
9546
- var BASH_RETURN_PATHS_DESCRIPTION = "With runon: up to 64 files to copy back from the build server after the command, as paths relative to workdir inside the project (10 MiB in total). Each verified file replaces the local file at the same path; the result lists every path as returned or not returned, with the reason.";
9547
- var BASH_RUNON_GUIDANCE = 'When remote runs are available, put `runon: "linux"` on build and test lines (cargo, bun test), including chains and pipes. Keep git, gh, interactive and file-editing commands local, and keep a line local if it needs this machine\'s own operating system or hardware (its sandbox, code signing, service manager, permission prompts or GUI frameworks) or runs a binary that already exists on this machine; a build or test that needs only macOS (its sandbox, code signing or file watching) can use runon: "macos" instead; building and testing still go remote, and a remote build leaves no binaries or target/ output in the local worktree. Add `,Nc` to request N vCPUs (`linux,4c`); without it the job gets 2 vCPUs. The job sees exactly the CPUs it gets, so ask for what the command uses: 2c (the default) for a single test binary or script, 4c for `cargo check`/clippy on one crate, 8c for a workspace test suite, and 16c for a large release build.';
9545
+ var BASH_RUNON_MEMORY_DESCRIPTION = "On Linux, add `,Ngb` to ask for N GiB of memory, for example `linux,2c,16gb` for a Rust build.";
9546
+ var BASH_RUNON_DESCRIPTION = 'Run on a remote build server: `linux` (2 vCPUs), or `linux,Nc` for N vCPUs such as `linux,8c`; add ",net" for outbound internet (offline by default). `windows` runs the command in Git Bash on a Windows build machine (no vCPU or network options). `macos` sends the command to a macOS machine for builds and tests that need macOS (no vCPU or network options).' + ` ${BASH_RUNON_MEMORY_DESCRIPTION}`;
9547
+ var BASH_RETURN_PATHS_DESCRIPTION = "With runon: up to 64 files to copy back from the build server after the command, as paths relative to workdir inside the project (up to 128 MiB in total). Each verified file replaces the local file at the same path; the result lists every path as returned or not returned, with the reason.";
9548
+ var BASH_RUNON_GUIDANCE = 'When remote runs are available, put `runon: "linux"` on build and test lines (cargo, bun test), including chains and pipes. A runon job\'s file changes are not copied back; only output, the exit code and return_paths files return. Edit locally first; name a file in return_paths to regenerate it remotely. Keep git, gh, interactive and file-editing commands local, and keep a line local if it needs this machine\'s own operating system or hardware (its sandbox, code signing, service manager, permission prompts or GUI frameworks) or runs a binary that already exists on this machine; a build or test that needs only macOS (its sandbox, code signing or file watching) can use runon: "macos" instead; building and testing still go remote, and a remote build leaves no binaries or target/ output in the local worktree. Add `,Nc` to request N vCPUs (`linux,4c`); without it the job gets 2 vCPUs. The job sees exactly the CPUs it gets, so ask for what the command uses: 2c (the default) for a single test binary or script, 4c for `cargo check`/clippy on one crate, 8c for a workspace test suite, and 16c for a large release build.';
9548
9549
  function pathKeyForPlatform(env, platform) {
9549
9550
  return platform === "win32" ? Object.keys(env).find((key) => key.toLowerCase() === "path") : "PATH";
9550
9551
  }
@@ -9799,6 +9800,7 @@ function bashAcksConfirmed(response, targets) {
9799
9800
  }
9800
9801
  // ../aft-bridge/dist/bash-permissions.js
9801
9802
  var BASH_PERMISSION_NOT_SETTLED = "bash permission not settled after {rounds} rounds: still asking for {kind} {path} (operation: {operation}; granted already: {granted})";
9803
+ var BASH_PERMISSION_DENIED = "Permission denied for this shell command: {parts} ({host reason}). The parts are checked together, so one denied part denies the whole command; run the allowed parts in a separate call.";
9802
9804
 
9803
9805
  class BashPermissionLoopError extends Error {
9804
9806
  }
@@ -9833,6 +9835,10 @@ ${ask.command ?? ""}
9833
9835
  Working directory:
9834
9836
  ${ask.cwd ?? ""}`;
9835
9837
  }
9838
+ function permissionAskPath(ask) {
9839
+ const paths = ask.patterns?.length ? ask.patterns : bashPermissionRetryGrants(ask);
9840
+ return ask.kind === "escalation" && ask.command ? `${ask.command}${ask.cwd ? ` @ ${ask.cwd}` : ""}` : paths.length ? paths.join(", ") : "<no asks returned>";
9841
+ }
9836
9842
  async function withBashPermissionLoop(options) {
9837
9843
  const granted = new Set;
9838
9844
  const alreadyGranted = (ask) => {
@@ -9854,20 +9860,22 @@ async function withBashPermissionLoop(options) {
9854
9860
  already_granted: alreadyGranted(ask)
9855
9861
  }))
9856
9862
  });
9857
- const unsettled = (cause) => {
9863
+ const unsettled = () => {
9858
9864
  const message = (asks.length ? asks : [{}]).map((ask) => {
9859
- const paths = ask.patterns?.length ? ask.patterns : bashPermissionRetryGrants(ask);
9860
- const path = ask.kind === "escalation" && ask.command ? `${ask.command}${ask.cwd ? ` @ ${ask.cwd}` : ""}` : paths.length ? paths.join(", ") : "<no asks returned>";
9861
- return BASH_PERMISSION_NOT_SETTLED.replace("{rounds}", String(round)).replace("{kind}", ask.kind ?? "unknown").replace("{operation}", ask.operation ?? options.operation ?? "bash").replace("{granted}", alreadyGranted(ask) ? "yes" : "no").replace("{path}", () => path);
9865
+ return BASH_PERMISSION_NOT_SETTLED.replace("{rounds}", String(round)).replace("{kind}", ask.kind ?? "unknown").replace("{operation}", ask.operation ?? options.operation ?? "bash").replace("{granted}", alreadyGranted(ask) ? "yes" : "no").replace("{path}", () => permissionAskPath(ask));
9862
9866
  }).join("; ");
9863
- return new BashPermissionLoopError(cause instanceof Error ? `${message}: ${cause.message}` : message, { cause });
9867
+ return new BashPermissionLoopError(message);
9864
9868
  };
9865
9869
  if (asks.length === 0 || asks.every(alreadyGranted) || round >= 8)
9866
9870
  throw unsettled();
9871
+ const pendingAsks = asks.filter((ask) => !alreadyGranted(ask));
9867
9872
  try {
9868
- await options.approve(asks.filter((ask) => !alreadyGranted(ask)));
9873
+ await options.approve(pendingAsks);
9869
9874
  } catch (error) {
9870
- throw unsettled(error);
9875
+ const parts = pendingAsks.map(permissionAskPath).join(", ");
9876
+ const reason = error instanceof Error && error.message ? error.message.trim().replace(/\.$/, "") : "";
9877
+ const message = reason ? BASH_PERMISSION_DENIED.replace("{host reason}", () => reason) : BASH_PERMISSION_DENIED.replace(" ({host reason})", "");
9878
+ throw new BashPermissionLoopError(message.replace("{parts}", () => parts), { cause: error });
9871
9879
  }
9872
9880
  for (const ask of asks) {
9873
9881
  for (const grant of bashPermissionRetryGrants(ask))
@@ -12111,8 +12119,9 @@ function formatDroppedKeyWarnings(dropped) {
12111
12119
  return dropped.map((item) => `Ignoring ${item.key} from ${item.tier} config (${item.reason})`);
12112
12120
  }
12113
12121
  // ../aft-bridge/dist/config-watch.js
12114
- import { readFileSync as readFileSync3, statSync as statSync3, watch } from "node:fs";
12115
- import { basename, dirname as dirname2 } from "node:path";
12122
+ import { createHash as createHash2 } from "node:crypto";
12123
+ import { closeSync as closeSync2, fstatSync, openSync as openSync2, readFileSync as readFileSync3, readSync as readSync2, realpathSync as realpathSync2, statSync as statSync3, watch } from "node:fs";
12124
+ import { basename, dirname as dirname2, resolve as resolve5 } from "node:path";
12116
12125
  var CONFIG_WATCH_DEBOUNCE_MS = 150;
12117
12126
  var CONFIG_LIVE_KEEP_NOTE = "AFT keeps using the last valid configuration until the file is fixed.";
12118
12127
  function pathKey(name) {
@@ -12166,7 +12175,6 @@ function aftLiveConfigKeys(resolveBash) {
12166
12175
  pathKey("restrict_to_project_root"),
12167
12176
  pathKey("revision_reads"),
12168
12177
  pathKey("inspect.diagnostics_timeout_ms"),
12169
- pathKey("inspect.tier2_idle_minutes"),
12170
12178
  pathKey("lsp.idle_minutes"),
12171
12179
  ...[
12172
12180
  "diagnostics",
@@ -12238,6 +12246,29 @@ function readTextOrNull(path) {
12238
12246
  var CONFIG_WATCH_REVALIDATE_MS = 2000;
12239
12247
  var CONFIG_WATCH_REJECTED_RETRIES = 3;
12240
12248
  var CONFIG_WATCH_MAX_DELAY_MS = 1000;
12249
+ var CONFIG_READ_LIMIT = 1024 * 1024;
12250
+ function contentFingerprint(path) {
12251
+ let fd;
12252
+ try {
12253
+ fd = openSync2(path, "r");
12254
+ const metadata = fstatSync(fd, { bigint: true });
12255
+ const bytes = Buffer.alloc(Math.min(Number(metadata.size), CONFIG_READ_LIMIT));
12256
+ let offset = 0;
12257
+ while (offset < bytes.length) {
12258
+ const read = readSync2(fd, bytes, offset, bytes.length - offset, null);
12259
+ if (read === 0)
12260
+ break;
12261
+ offset += read;
12262
+ }
12263
+ const hash = createHash2("sha256").update(bytes.subarray(0, offset)).digest("hex");
12264
+ return `${metadata.size}:${metadata.mtimeNs}:${hash}`;
12265
+ } catch {
12266
+ return null;
12267
+ } finally {
12268
+ if (fd !== undefined)
12269
+ closeSync2(fd);
12270
+ }
12271
+ }
12241
12272
  function identityOf(dir) {
12242
12273
  try {
12243
12274
  const stat = statSync3(dir, { bigint: true });
@@ -12253,6 +12284,13 @@ function watchDirFor(file) {
12253
12284
  dir = dirname2(dir);
12254
12285
  return dir;
12255
12286
  }
12287
+ function canonicalDirectory(dir) {
12288
+ try {
12289
+ return realpathSync2(dir);
12290
+ } catch {
12291
+ return resolve5(dir);
12292
+ }
12293
+ }
12256
12294
  function watchAftConfigFiles(options) {
12257
12295
  const debounceMs = options.debounceMs ?? CONFIG_WATCH_DEBOUNCE_MS;
12258
12296
  const lastSeen = new Map;
@@ -12266,6 +12304,8 @@ function watchAftConfigFiles(options) {
12266
12304
  let firstPendingAt = null;
12267
12305
  let stopped = false;
12268
12306
  const watchers = new Map;
12307
+ const targets = new Map;
12308
+ const fallbackSeen = new Map;
12269
12309
  const watchImpl = options.watchImpl ?? watch;
12270
12310
  let rejectedRetries = 0;
12271
12311
  const check = () => {
@@ -12319,8 +12359,34 @@ function watchAftConfigFiles(options) {
12319
12359
  timer.unref?.();
12320
12360
  };
12321
12361
  function revalidate() {
12322
- const wanted = new Set(options.paths.map(watchDirFor));
12362
+ const wanted = new Set;
12363
+ const wantedCanonical = new Set;
12364
+ const wantDirectory = (dir) => {
12365
+ const canonical = canonicalDirectory(dir);
12366
+ if (wantedCanonical.has(canonical))
12367
+ return;
12368
+ wantedCanonical.add(canonical);
12369
+ wanted.add(dir);
12370
+ };
12371
+ for (const path of options.paths)
12372
+ wantDirectory(watchDirFor(path));
12323
12373
  let moved = false;
12374
+ for (const path of options.paths) {
12375
+ try {
12376
+ const resolved = realpathSync2(path);
12377
+ const target = resolved === resolve5(path) ? undefined : resolved;
12378
+ if (targets.get(path) !== target) {
12379
+ if (target)
12380
+ targets.set(path, target);
12381
+ else
12382
+ targets.delete(path);
12383
+ fallbackSeen.delete(path);
12384
+ moved = true;
12385
+ }
12386
+ } catch {}
12387
+ }
12388
+ for (const target of targets.values())
12389
+ wantDirectory(watchDirFor(target));
12324
12390
  for (const [dir, entry] of watchers) {
12325
12391
  if (!wanted.has(dir) || entry.stale || identityOf(dir) !== entry.identity) {
12326
12392
  entry.watcher.close();
@@ -12359,6 +12425,17 @@ function watchAftConfigFiles(options) {
12359
12425
  moved = true;
12360
12426
  } catch {}
12361
12427
  }
12428
+ const watchedCanonical = new Set(Array.from(watchers.keys(), canonicalDirectory));
12429
+ for (const [path, target] of targets) {
12430
+ if (watchedCanonical.has(canonicalDirectory(dirname2(target)))) {
12431
+ fallbackSeen.delete(path);
12432
+ continue;
12433
+ }
12434
+ const fingerprint = contentFingerprint(path);
12435
+ if (!fallbackSeen.has(path) || fallbackSeen.get(path) !== fingerprint)
12436
+ moved = true;
12437
+ fallbackSeen.set(path, fingerprint);
12438
+ }
12362
12439
  return moved;
12363
12440
  }
12364
12441
  revalidate();
@@ -12515,8 +12592,8 @@ function startLiveConfigReload(options) {
12515
12592
  return { reload, stop };
12516
12593
  }
12517
12594
  // ../aft-bridge/dist/downloader.js
12518
- import { createHash as createHash2, randomUUID } from "node:crypto";
12519
- import { chmodSync, closeSync as closeSync2, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync as openSync2, readdirSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync4, unlinkSync as unlinkSync2, writeSync } from "node:fs";
12595
+ import { createHash as createHash3, randomUUID } from "node:crypto";
12596
+ import { chmodSync, closeSync as closeSync3, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync as openSync3, readdirSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync4, unlinkSync as unlinkSync2, writeSync } from "node:fs";
12520
12597
  import { hostname } from "node:os";
12521
12598
  import { join as join8 } from "node:path";
12522
12599
  import { Readable } from "node:stream";
@@ -12734,7 +12811,7 @@ async function downloadBinary(version) {
12734
12811
  warn(`Checksum verification failed: checksums.sha256 found but no entry for ${assetName}. ` + "Binary download aborted for security reasons.");
12735
12812
  return null;
12736
12813
  }
12737
- const hash = createHash2("sha256");
12814
+ const hash = createHash3("sha256");
12738
12815
  let bytesWritten = 0;
12739
12816
  const guard = new TransformStream({
12740
12817
  transform(chunk, controller) {
@@ -12901,11 +12978,11 @@ async function acquireDownloadLock(lockPath, timing = {}) {
12901
12978
  while (true) {
12902
12979
  try {
12903
12980
  const owner = createDownloadLockOwner();
12904
- const fd = openSync2(lockPath, "wx");
12981
+ const fd = openSync3(lockPath, "wx");
12905
12982
  try {
12906
12983
  writeSync(fd, owner);
12907
12984
  } finally {
12908
- closeSync2(fd);
12985
+ closeSync3(fd);
12909
12986
  }
12910
12987
  return () => {
12911
12988
  try {
@@ -12976,8 +13053,8 @@ import { appendFile, lstat, mkdir, open, rename, rm, stat } from "node:fs/promis
12976
13053
  import { dirname as dirname3 } from "node:path";
12977
13054
 
12978
13055
  // ../aft-bridge/dist/private-storage.js
12979
- import { closeSync as closeSync3, constants, copyFileSync as copyFileSync2, fchmodSync, fstatSync, lstatSync, mkdirSync as mkdirSync3, openSync as openSync3, readSync as readSync2, writeSync as writeSync2 } from "node:fs";
12980
- import { isAbsolute as isAbsolute4, join as join9, parse, relative as relative3, resolve as resolve5, sep } from "node:path";
13056
+ import { closeSync as closeSync4, constants, copyFileSync as copyFileSync2, fchmodSync, fstatSync as fstatSync2, lstatSync, mkdirSync as mkdirSync3, openSync as openSync4, readSync as readSync3, writeSync as writeSync2 } from "node:fs";
13057
+ import { isAbsolute as isAbsolute4, join as join9, parse, relative as relative3, resolve as resolve6, sep } from "node:path";
12981
13058
  var PRIVATE_FILE_MODE = 384;
12982
13059
  var PRIVATE_DIRECTORY_MODE = 448;
12983
13060
  function privateMkdirSync(path, recursive = true) {
@@ -12991,13 +13068,13 @@ function privateCopyFileSync(source, destination) {
12991
13068
  copyFileSync2(source, destination);
12992
13069
  return;
12993
13070
  }
12994
- const input = openSync3(source, "r");
13071
+ const input = openSync4(source, "r");
12995
13072
  let output;
12996
13073
  try {
12997
- output = openSync3(destination, "wx", PRIVATE_FILE_MODE);
13074
+ output = openSync4(destination, "wx", PRIVATE_FILE_MODE);
12998
13075
  const buffer = Buffer.allocUnsafe(64 * 1024);
12999
13076
  for (;; ) {
13000
- const bytes = readSync2(input, buffer);
13077
+ const bytes = readSync3(input, buffer);
13001
13078
  if (bytes === 0)
13002
13079
  break;
13003
13080
  let offset = 0;
@@ -13005,18 +13082,18 @@ function privateCopyFileSync(source, destination) {
13005
13082
  offset += writeSync2(output, buffer, offset, bytes - offset);
13006
13083
  }
13007
13084
  } finally {
13008
- closeSync3(input);
13085
+ closeSync4(input);
13009
13086
  if (output !== undefined)
13010
- closeSync3(output);
13087
+ closeSync4(output);
13011
13088
  }
13012
13089
  }
13013
13090
  var warned = new Set;
13014
13091
  function openPrivateStorageDir(root, path = root) {
13015
- const base = resolve5(root);
13092
+ const base = resolve6(root);
13016
13093
  if (!root || base === parse(base).root) {
13017
13094
  throw new Error(`refusing filesystem root as private storage: ${base}`);
13018
13095
  }
13019
- const rel = relative3(base, resolve5(path));
13096
+ const rel = relative3(base, resolve6(path));
13020
13097
  if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute4(rel))
13021
13098
  return;
13022
13099
  privateMkdirSync(path);
@@ -13029,8 +13106,8 @@ function openPrivateStorageDir(root, path = root) {
13029
13106
  try {
13030
13107
  if (lstatSync(current).isSymbolicLink())
13031
13108
  return;
13032
- fd = openSync3(current, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
13033
- if ((fstatSync(fd).mode & 63) !== 0)
13109
+ fd = openSync4(current, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
13110
+ if ((fstatSync2(fd).mode & 63) !== 0)
13034
13111
  fchmodSync(fd, PRIVATE_DIRECTORY_MODE);
13035
13112
  } catch (error) {
13036
13113
  if (!warned.has(current)) {
@@ -13041,7 +13118,7 @@ function openPrivateStorageDir(root, path = root) {
13041
13118
  return;
13042
13119
  } finally {
13043
13120
  if (fd !== undefined)
13044
- closeSync3(fd);
13121
+ closeSync4(fd);
13045
13122
  }
13046
13123
  }
13047
13124
  }
@@ -13864,7 +13941,7 @@ async function readConnectionFileForUid(path, expectedUid) {
13864
13941
  }
13865
13942
 
13866
13943
  // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/launch-nonce.js
13867
- import { closeSync as closeSync4, fstatSync as fstatSync2, readSync as readSync3 } from "node:fs";
13944
+ import { closeSync as closeSync5, fstatSync as fstatSync3, readSync as readSync4 } from "node:fs";
13868
13945
  var SUBC_LAUNCH_NONCE_ENV = "SUBC_LAUNCH_NONCE";
13869
13946
  var SUBC_LAUNCH_NONCE_FD_ENV = "SUBC_LAUNCH_NONCE_FD";
13870
13947
  class LaunchNonceError extends Error {
@@ -13911,7 +13988,7 @@ class LaunchNonceCell {
13911
13988
  lookup;
13912
13989
  platform;
13913
13990
  stat;
13914
- constructor(lookup, platform = process.platform, stat = (fd) => fstatSync2(fd, { bigint: true })) {
13991
+ constructor(lookup, platform = process.platform, stat = (fd) => fstatSync3(fd, { bigint: true })) {
13915
13992
  this.lookup = lookup;
13916
13993
  this.platform = platform;
13917
13994
  this.stat = stat;
@@ -13959,7 +14036,7 @@ class LaunchNonceCell {
13959
14036
  const chunk = Buffer.alloc(256);
13960
14037
  let got;
13961
14038
  try {
13962
- got = readSync3(fd, chunk, 0, chunk.length, null);
14039
+ got = readSync4(fd, chunk, 0, chunk.length, null);
13963
14040
  } catch (error) {
13964
14041
  if (isWouldBlock(error))
13965
14042
  throw emptyError(fd);
@@ -13971,7 +14048,7 @@ class LaunchNonceCell {
13971
14048
  const parts = [Buffer.from(chunk.subarray(0, got))];
13972
14049
  try {
13973
14050
  for (;; ) {
13974
- const n = readSync3(fd, chunk, 0, chunk.length, null);
14051
+ const n = readSync4(fd, chunk, 0, chunk.length, null);
13975
14052
  if (n === 0)
13976
14053
  break;
13977
14054
  parts.push(Buffer.from(chunk.subarray(0, n)));
@@ -14048,7 +14125,7 @@ function errnoOf(error) {
14048
14125
  }
14049
14126
  function closeQuietly(fd) {
14050
14127
  try {
14051
- closeSync4(fd);
14128
+ closeSync5(fd);
14052
14129
  } catch {}
14053
14130
  }
14054
14131
 
@@ -15923,16 +16000,16 @@ function getLifecycleRegistry() {
15923
16000
  }
15924
16001
 
15925
16002
  // ../aft-bridge/dist/project-identity.js
15926
- import { createHash as createHash3 } from "node:crypto";
15927
- import { realpathSync as realpathSync2 } from "node:fs";
15928
- import { posix as posix2, resolve as resolve6, win32 as win322 } from "node:path";
16003
+ import { createHash as createHash4 } from "node:crypto";
16004
+ import { realpathSync as realpathSync3 } from "node:fs";
16005
+ import { posix as posix2, resolve as resolve7, win32 as win322 } from "node:path";
15929
16006
  function canonicalizeProjectRoot(dir) {
15930
16007
  const trimmed = trimProjectRootSeparators(dir);
15931
16008
  let canonical;
15932
16009
  try {
15933
- canonical = realpathSync2(trimmed);
16010
+ canonical = realpathSync3(trimmed);
15934
16011
  } catch {
15935
- canonical = resolve6(trimmed);
16012
+ canonical = resolve7(trimmed);
15936
16013
  }
15937
16014
  return normalizeWindowsRoot(canonical);
15938
16015
  }
@@ -15972,7 +16049,7 @@ function hasDotComponent(path) {
15972
16049
  return path.split(/[\\/]/).some((component) => component === "." || component === "..");
15973
16050
  }
15974
16051
  function projectRootKeyHash(dir) {
15975
- return createHash3("sha256").update(canonicalizeProjectRoot(dir)).digest("hex").slice(0, 16);
16052
+ return createHash4("sha256").update(canonicalizeProjectRoot(dir)).digest("hex").slice(0, 16);
15976
16053
  }
15977
16054
 
15978
16055
  // ../aft-bridge/dist/subc-transport.js
@@ -17915,7 +17992,9 @@ class SubcTransportPool {
17915
17992
  });
17916
17993
  retry = state.bindPending;
17917
17994
  } else {
17918
- retry = this.hostScope(client, record.identity);
17995
+ retry = this.hostScope(client, record.identity).finally(() => {
17996
+ this.scheduleHostScopeRetry(session, state);
17997
+ });
17919
17998
  }
17920
17999
  retry.catch((error) => {
17921
18000
  warn(`subc head scope: session=${session} background retry failed code=${error instanceof Error ? error.name : "Error"}`);
@@ -18083,12 +18162,18 @@ class SubcTransportPool {
18083
18162
  }
18084
18163
  return this.openScopedHostToolRoute(client, identity, record, entry, channel);
18085
18164
  }
18086
- bindHostToolRoute(client, identity, channel, reason, scope) {
18165
+ async bindHostToolRoute(client, identity, channel, reason, scope) {
18087
18166
  log(`subc head scope: session=${identity.session} bind=${scope ? "scoped" : "unscoped"} channel=${channel} root=${identity.project_root} reason=${reason}` + (scope ? ` ref=${scope.ref.slice(0, 8)} epoch=${scope.scopeEpoch}` : ""));
18088
- return client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, identity, {
18167
+ const route = await client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, identity, {
18089
18168
  consumerIdentity: this.consumerIdentity,
18090
18169
  ...scope ? { scope } : {}
18091
18170
  });
18171
+ const state = this.hostScopeCache.get(identity.session);
18172
+ if (scope && state?.unscopedReason && state.answer?.result === "scope" && state.answer.scope === scope) {
18173
+ log(`subc head scope: session=${identity.session} route=upgraded from=unscoped ref=${scope.ref.slice(0, 8)} epoch=${scope.scopeEpoch}`);
18174
+ state.unscopedReason = undefined;
18175
+ }
18176
+ return route;
18092
18177
  }
18093
18178
  async openScopedHostToolRoute(client, identity, record, entry, channel = "tool") {
18094
18179
  const decision = await this.hostScope(client, identity);
@@ -18720,7 +18805,8 @@ function taskIdFromError(error) {
18720
18805
  return;
18721
18806
  }
18722
18807
  // ../aft-bridge/dist/feature-config.js
18723
- import { createHash as createHash4 } from "node:crypto";
18808
+ import { createHash as createHash5 } from "node:crypto";
18809
+ import { createRequire } from "node:module";
18724
18810
  var CANONICAL_TOOLS = [
18725
18811
  "aft_callgraph",
18726
18812
  "aft_conflicts",
@@ -18770,23 +18856,114 @@ var REMOVED_OPENCODE_PATHS = [
18770
18856
  "opencode.server_url",
18771
18857
  "opencode.server_password_env"
18772
18858
  ];
18773
- function removedConfigKeyErrors(value) {
18859
+ var REMOVED_DATA_LAYER_PATHS = [
18860
+ "views.callgraph_copies",
18861
+ "views.enabled",
18862
+ "worktree.ram_overlay"
18863
+ ];
18864
+ var RETIRED_IDLE_CHECKOUT_HOURS = [
18865
+ "views.idle_checkout_hours",
18866
+ "idle.checkout_hours"
18867
+ ];
18868
+ var DATA_LAYER_KEYS_REFUSED_FROM = [0, 65];
18869
+ var DATA_LAYER_RETIRED_PATHS = [
18870
+ "views.callgraph_copies",
18871
+ "views.enabled",
18872
+ "views.idle_checkout_hours",
18873
+ "worktree.ram_overlay"
18874
+ ];
18875
+ var IDLE_CHECKOUT_HOURS_DEFAULT = 168;
18876
+ var IDLE_CHECKOUT_HOURS_MIN = 1;
18877
+ var IDLE_CHECKOUT_HOURS_MAX = 24 * 365;
18878
+ function parseRelease(version) {
18879
+ const match = /^(\d+)\.(\d+)(?:\.|$)/.exec(version);
18880
+ return match ? [Number(match[1]), Number(match[2])] : undefined;
18881
+ }
18882
+ var AFT_PACKAGE_NAMES = new Set([
18883
+ "@cortexkit/aft-bridge",
18884
+ "@cortexkit/aft-opencode",
18885
+ "@cortexkit/aft-pi",
18886
+ "@cortexkit/aft"
18887
+ ]);
18888
+ function readRunningRelease() {
18889
+ const req = createRequire(import.meta.url);
18890
+ for (const candidate of ["../package.json", "../../package.json", "../../../package.json"]) {
18891
+ try {
18892
+ const manifest = req(candidate);
18893
+ if (manifest.name && AFT_PACKAGE_NAMES.has(manifest.name) && manifest.version) {
18894
+ return parseRelease(manifest.version) ?? [0, 0];
18895
+ }
18896
+ } catch {}
18897
+ }
18898
+ return [0, 0];
18899
+ }
18900
+ var runningRelease;
18901
+ function getRunningRelease() {
18902
+ runningRelease ??= readRunningRelease();
18903
+ return runningRelease;
18904
+ }
18905
+ function releaseAtLeast(release, floor) {
18906
+ return release[0] !== floor[0] ? release[0] > floor[0] : release[1] >= floor[1];
18907
+ }
18908
+ function refusedFromVersion() {
18909
+ return `${DATA_LAYER_KEYS_REFUSED_FROM[0]}.${DATA_LAYER_KEYS_REFUSED_FROM[1]}.0`;
18910
+ }
18911
+ function removedConfigKeyErrors(value, release = getRunningRelease(), refuseRetired = true) {
18774
18912
  if (!isRecord2(value))
18775
18913
  return [];
18776
- const errors = removedOpencodeKeyErrors(value);
18914
+ const errors = removedBlockKeyErrors(value, release, refuseRetired);
18777
18915
  if (isRecord2(value.harnesses)) {
18778
18916
  for (const [name, block] of Object.entries(value.harnesses)) {
18779
18917
  if (!isRecord2(block))
18780
18918
  continue;
18781
- for (const error of removedOpencodeKeyErrors(block)) {
18919
+ for (const error of removedBlockKeyErrors(block, release, refuseRetired)) {
18782
18920
  errors.push(error.replace("removed_config_key:", `removed_config_key:harnesses.${name}.`));
18783
18921
  }
18784
18922
  }
18785
18923
  }
18786
18924
  return errors;
18787
18925
  }
18788
- function removedOpencodeKeyErrors(value) {
18789
- return REMOVED_OPENCODE_PATHS.filter((path) => hasPath(value, path)).map((path) => `removed_config_key:${path}; run aft doctor --fix`);
18926
+ function removedBlockKeyErrors(value, release, refuseRetired) {
18927
+ const paths = REMOVED_OPENCODE_PATHS.filter((path) => hasPath(value, path));
18928
+ if (refuseRetired)
18929
+ paths.push(...refusedRetiredNames(value));
18930
+ if (releaseAtLeast(release, DATA_LAYER_KEYS_REFUSED_FROM))
18931
+ paths.push(...DATA_LAYER_RETIRED_PATHS.filter((path) => hasPath(value, path)));
18932
+ return paths.map((path) => `removed_config_key:${path}; run npx @cortexkit/aft doctor --fix`);
18933
+ }
18934
+ var REFUSED_RETIRED_PATHS = [
18935
+ "sandbox.enabled",
18936
+ "tool_surface",
18937
+ "hoist_builtin_tools",
18938
+ "enabled",
18939
+ "search_index",
18940
+ "experimental_search_index",
18941
+ "semantic_search",
18942
+ "experimental_semantic_search",
18943
+ "callgraph_store",
18944
+ "github.enabled",
18945
+ "gh_read",
18946
+ "gh_shim.enabled",
18947
+ "experimental_lsp_ty",
18948
+ "experimental_bash_rewrite",
18949
+ "experimental_bash_compress",
18950
+ "experimental_bash_background",
18951
+ "experimental.bash",
18952
+ "idle.lsp_ttl_minutes",
18953
+ "inspect.tier2_soft_deadline_ms",
18954
+ "inspect.max_drill_down_items"
18955
+ ];
18956
+ function refusedRetiredNames(block) {
18957
+ const names = REFUSED_RETIRED_PATHS.filter((path) => hasPath(block, path));
18958
+ if (Array.isArray(block.disabled_tools)) {
18959
+ for (const name of block.disabled_tools) {
18960
+ if (typeof name !== "string" || !Object.hasOwn(LEGACY_TOOL_ALIASES, name))
18961
+ continue;
18962
+ if (!names.includes(name))
18963
+ names.push(name);
18964
+ }
18965
+ }
18966
+ return names;
18790
18967
  }
18791
18968
  var RETIRED_PATHS = [
18792
18969
  ["sandbox.enabled", "sandbox.profile"],
@@ -18935,7 +19112,10 @@ function translateInspectLspPaths(map, prefix, out) {
18935
19112
  recordRetired(out, prefix, `inspect.${leaf}`);
18936
19113
  }
18937
19114
  }
18938
- var REMOVED_NO_EFFECT_PATHS = ["bridge.hang_threshold"];
19115
+ var REMOVED_NO_EFFECT_PATHS = [
19116
+ "bridge.hang_threshold",
19117
+ "inspect.tier2_idle_minutes"
19118
+ ];
18939
19119
  function dropNoEffectPaths(map, prefix, out) {
18940
19120
  for (const path of REMOVED_NO_EFFECT_PATHS) {
18941
19121
  const [container, leaf] = path.split(".");
@@ -18944,6 +19124,29 @@ function dropNoEffectPaths(map, prefix, out) {
18944
19124
  }
18945
19125
  }
18946
19126
  }
19127
+ function retiredIdleCheckoutHours(value) {
19128
+ const raw = typeof value === "number" && Number.isSafeInteger(value) ? value : IDLE_CHECKOUT_HOURS_DEFAULT;
19129
+ return Math.min(IDLE_CHECKOUT_HOURS_MAX, Math.max(IDLE_CHECKOUT_HOURS_MIN, raw));
19130
+ }
19131
+ function translateDataLayerPaths(map, prefix, out) {
19132
+ const [retired, replacement] = RETIRED_IDLE_CHECKOUT_HOURS;
19133
+ const hours = takeNested(map, "views", "idle_checkout_hours");
19134
+ if (hours.found) {
19135
+ recordRetired(out, prefix, retired);
19136
+ if (isRecord2(map.idle) && map.idle.checkout_hours !== undefined) {
19137
+ superseded(out, `${prefix}${retired}`, `${retired} is ignored because ${replacement} is set`);
19138
+ } else {
19139
+ if (!Object.hasOwn(map, "idle"))
19140
+ map.idle = {};
19141
+ if (isRecord2(map.idle))
19142
+ map.idle.checkout_hours = retiredIdleCheckoutHours(hours.value);
19143
+ }
19144
+ }
19145
+ for (const path of REMOVED_DATA_LAYER_PATHS) {
19146
+ if (hasPath(map, path))
19147
+ out.removedKeys.push(`${prefix}${path}`);
19148
+ }
19149
+ }
18947
19150
  function translateExperimentalPaths(map, prefix, out) {
18948
19151
  for (const [oldKey, leaf] of [
18949
19152
  ["experimental_lsp_ty", "lsp_ty"],
@@ -18976,23 +19179,25 @@ function translateExperimentalPaths(map, prefix, out) {
18976
19179
  const experimental = map.experimental;
18977
19180
  const legacy = experimental.bash;
18978
19181
  if (isRecord2(legacy)) {
18979
- if (!["rewrite", "compress", "background"].some((leaf) => Object.hasOwn(legacy, leaf)))
18980
- return;
19182
+ if (Object.keys(legacy).length === 0)
19183
+ recordRetired(out, prefix, "experimental.bash");
18981
19184
  for (const leaf of Object.keys(legacy))
18982
19185
  recordRetired(out, prefix, `experimental.bash.${leaf}`);
18983
19186
  if (Object.hasOwn(map, "bash")) {
18984
19187
  superseded(out, "experimental.bash", 'experimental.bash is ignored because top-level "bash" is already set');
18985
19188
  } else {
18986
- const bash = {
18987
- rewrite: legacy.rewrite === true,
18988
- compress: legacy.compress === true,
18989
- background: legacy.background === true
18990
- };
19189
+ const bash = {};
19190
+ if (["rewrite", "compress", "background"].some((leaf) => Object.hasOwn(legacy, leaf))) {
19191
+ bash.rewrite = legacy.rewrite === true;
19192
+ bash.compress = legacy.compress === true;
19193
+ bash.background = legacy.background === true;
19194
+ }
18991
19195
  for (const leaf of ["long_running_reminder_enabled", "long_running_reminder_interval_ms"]) {
18992
19196
  if (Object.hasOwn(legacy, leaf))
18993
19197
  bash[leaf] = legacy[leaf];
18994
19198
  }
18995
- map.bash = bash;
19199
+ if (Object.keys(bash).length > 0)
19200
+ map.bash = bash;
18996
19201
  }
18997
19202
  } else {
18998
19203
  recordRetired(out, prefix, "experimental.bash");
@@ -19005,6 +19210,7 @@ function translateBlock(map, userBase, blockLabel, out) {
19005
19210
  const prefix = blockLabel === "base" ? "" : `${blockLabel}.`;
19006
19211
  translateGithubAliases(map, prefix, out);
19007
19212
  translateInspectLspPaths(map, prefix, out);
19213
+ translateDataLayerPaths(map, prefix, out);
19008
19214
  dropNoEffectPaths(map, prefix, out);
19009
19215
  translateExperimentalPaths(map, prefix, out);
19010
19216
  if (isRecord2(map.sandbox) && Object.hasOwn(map.sandbox, "enabled")) {
@@ -19043,8 +19249,6 @@ function translateBlock(map, userBase, blockLabel, out) {
19043
19249
  });
19044
19250
  }
19045
19251
  for (const [path] of RETIRED_PATHS) {
19046
- if (path === "experimental.bash")
19047
- continue;
19048
19252
  if (hasPath(map, path))
19049
19253
  recordRetired(out, prefix, path);
19050
19254
  }
@@ -19180,13 +19384,57 @@ var NO_EFFECT_RETIRED_NOTES = [
19180
19384
  "inspect.max_drill_down_items",
19181
19385
  "inspect.max_drill_down_items never had an effect, so the setting can be removed."
19182
19386
  ],
19387
+ [
19388
+ "inspect.tier2_idle_minutes",
19389
+ "inspect.tier2_idle_minutes no longer does anything: AFT runs whole-repository analyses only when aft_inspect is called, so the setting can be removed."
19390
+ ],
19183
19391
  [
19184
19392
  "inspect.tier2_soft_deadline_ms",
19185
19393
  "inspect.tier2_soft_deadline_ms never had an effect, so the setting can be removed."
19186
19394
  ]
19187
19395
  ];
19188
19396
  function noEffectNote(key) {
19189
- return NO_EFFECT_RETIRED_NOTES.find(([path]) => key === path || key.endsWith(`.${path}`))?.[1];
19397
+ return NO_EFFECT_RETIRED_NOTES.find(([path]) => namesPath(key, path))?.[1];
19398
+ }
19399
+ function namesPath(key, path) {
19400
+ return key === path || key.endsWith(`.${path}`);
19401
+ }
19402
+ var REMOVED_DATA_LAYER_NOTES = [
19403
+ [
19404
+ "views.callgraph_copies",
19405
+ "views.callgraph_copies is gone because no checkout borrows another checkout's call graph any more."
19406
+ ],
19407
+ [
19408
+ "views.enabled",
19409
+ "views.enabled is gone because AFT now keeps one index store per repository and always uses it."
19410
+ ],
19411
+ [
19412
+ "worktree.ram_overlay",
19413
+ "worktree.ram_overlay is gone because every worktree now has its own index state, so there is no borrowed index to patch in memory."
19414
+ ]
19415
+ ];
19416
+ function retiredIdleCheckoutHoursNote() {
19417
+ const [retired, replacement] = RETIRED_IDLE_CHECKOUT_HOURS;
19418
+ return `${retired} is now ${replacement}; from ${refusedFromVersion()} AFT refuses a config file that still sets ${retired}.`;
19419
+ }
19420
+ function removedConfigKeysNoticeMessage(configPath, translation) {
19421
+ const removed = translation.removedKeys ?? [];
19422
+ if (removed.length === 0)
19423
+ return "";
19424
+ const parts = [
19425
+ `${configPath} sets removed keys (${removed.join(", ")}); AFT ignores them, and from ${refusedFromVersion()} it refuses a config file that sets them. Run \`npx @cortexkit/aft doctor --fix\` to remove them.`
19426
+ ];
19427
+ for (const [path, note] of REMOVED_DATA_LAYER_NOTES) {
19428
+ if (removed.some((key) => namesPath(key, path)))
19429
+ parts.push(note);
19430
+ }
19431
+ return parts.join(" ");
19432
+ }
19433
+ function removedConfigKeysNoticeDigest(translation) {
19434
+ return noticeDigest({
19435
+ notice: "removed_data_layer_keys_v1",
19436
+ keys: sortedUnique(translation.removedKeys)
19437
+ });
19190
19438
  }
19191
19439
  function legacyConfigNoticeMessage(configPath, translation) {
19192
19440
  const equivalents = translation.retiredKeys.filter((key) => noEffectNote(key) === undefined);
@@ -19196,11 +19444,17 @@ function legacyConfigNoticeMessage(configPath, translation) {
19196
19444
  parts.push(`${configPath} uses retired keys (${equivalents.join(", ")}); AFT applied their current equivalents, with the same limits a project config has for those keys. Run \`npx @cortexkit/aft doctor --fix\` to update the file.`);
19197
19445
  if (translation.retiredEnabledFalse)
19198
19446
  parts.push(RETIRED_ENABLED_FALSE_INDEXES_NOTE);
19447
+ if (equivalents.some((key) => namesPath(key, RETIRED_IDLE_CHECKOUT_HOURS[0]))) {
19448
+ parts.push(retiredIdleCheckoutHoursNote());
19449
+ }
19199
19450
  }
19200
19451
  for (const [, note] of NO_EFFECT_RETIRED_NOTES) {
19201
19452
  if (noEffect.has(note))
19202
19453
  parts.push(note);
19203
19454
  }
19455
+ const removed = removedConfigKeysNoticeMessage(configPath, translation);
19456
+ if (removed)
19457
+ parts.push(removed);
19204
19458
  return parts.join(" ");
19205
19459
  }
19206
19460
  function translateConfigDocument(map, tier) {
@@ -19208,6 +19462,7 @@ function translateConfigDocument(map, tier) {
19208
19462
  warnings: [],
19209
19463
  legacyInput: false,
19210
19464
  retiredKeys: [],
19465
+ removedKeys: [],
19211
19466
  retiredEnabledFalse: false
19212
19467
  };
19213
19468
  translateBlock(map, tier === "user", "base", out);
@@ -19218,6 +19473,7 @@ function translateConfigDocument(map, tier) {
19218
19473
  }
19219
19474
  }
19220
19475
  out.retiredKeys = sortedUnique(out.retiredKeys);
19476
+ out.removedKeys = sortedUnique(out.removedKeys);
19221
19477
  return out;
19222
19478
  }
19223
19479
  function unknownDisabledTools(disabled) {
@@ -19253,7 +19509,11 @@ function validateResolvedConfig(value) {
19253
19509
  var ABSENT = { absent: true };
19254
19510
  function projectBlock(block) {
19255
19511
  const legacyPaths = {};
19256
- for (const path of [...RETIRED_PATHS.map(([retired]) => retired), ...REMOVED_NO_EFFECT_PATHS]) {
19512
+ for (const path of [
19513
+ ...RETIRED_PATHS.map(([retired]) => retired),
19514
+ ...REMOVED_NO_EFFECT_PATHS,
19515
+ ...DATA_LAYER_RETIRED_PATHS
19516
+ ]) {
19257
19517
  const dot = path.indexOf(".");
19258
19518
  if (dot < 0) {
19259
19519
  if (Object.hasOwn(block, path))
@@ -19332,7 +19592,7 @@ function canonicalJson(value) {
19332
19592
  return JSON.stringify(value);
19333
19593
  }
19334
19594
  function noticeDigest(projection) {
19335
- return createHash4("sha256").update(canonicalJson(projection), "utf8").digest("hex");
19595
+ return createHash5("sha256").update(canonicalJson(projection), "utf8").digest("hex");
19336
19596
  }
19337
19597
  var SEMANTIC_COST_NOTICE = "AFT indexes now default on; the local semantic backend may download an ONNX runtime and model and use CPU. Run npx @cortexkit/aft setup to change indexes.semantic.";
19338
19598
  var SEMANTIC_COST_NOTICE_DIGEST = noticeDigest({ notice: "semantic_default_cost_v1" });
@@ -20370,9 +20630,9 @@ async function releaseBridge(pool) {
20370
20630
  await pool.shutdown();
20371
20631
  }
20372
20632
  // ../aft-bridge/dist/lsp-github-install.js
20373
- import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
20374
- import { closeSync as closeSync5, copyFileSync as copyFileSync3, createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync as lstatSync2, mkdirSync as mkdirSync4, openSync as openSync4, readdirSync as readdirSync2, readFileSync as readFileSync5, readlinkSync, readSync as readSync4, realpathSync as realpathSync3, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
20375
- import { dirname as dirname4, join as join11, relative as relative4, resolve as resolve7 } from "node:path";
20633
+ import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
20634
+ import { closeSync as closeSync6, copyFileSync as copyFileSync3, createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync as lstatSync2, mkdirSync as mkdirSync4, openSync as openSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, readlinkSync, readSync as readSync5, realpathSync as realpathSync4, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
20635
+ import { dirname as dirname4, join as join11, relative as relative4, resolve as resolve8 } from "node:path";
20376
20636
  import { Readable as Readable2 } from "node:stream";
20377
20637
  import { pipeline as pipeline2 } from "node:stream/promises";
20378
20638
 
@@ -20769,7 +21029,7 @@ function createGithubInstaller(services) {
20769
21029
  const MAX_EXTRACT_BYTES = 1024 * 1024 * 1024;
20770
21030
  function sha256OfFile(path) {
20771
21031
  return new Promise((resolve, reject) => {
20772
- const hash = createHash5("sha256");
21032
+ const hash = createHash6("sha256");
20773
21033
  const stream = createReadStream2(path);
20774
21034
  stream.on("error", reject);
20775
21035
  stream.on("data", (chunk) => hash.update(chunk));
@@ -20777,17 +21037,17 @@ function createGithubInstaller(services) {
20777
21037
  });
20778
21038
  }
20779
21039
  function sha256OfFileSync(path) {
20780
- const hash = createHash5("sha256");
20781
- const fd = openSync4(path, "r");
21040
+ const hash = createHash6("sha256");
21041
+ const fd = openSync5(path, "r");
20782
21042
  try {
20783
21043
  const buffer = Buffer.allocUnsafe(1024 * 1024);
20784
- let read = readSync4(fd, buffer, 0, buffer.length, null);
21044
+ let read = readSync5(fd, buffer, 0, buffer.length, null);
20785
21045
  while (read > 0) {
20786
21046
  hash.update(buffer.subarray(0, read));
20787
- read = readSync4(fd, buffer, 0, buffer.length, null);
21047
+ read = readSync5(fd, buffer, 0, buffer.length, null);
20788
21048
  }
20789
21049
  } finally {
20790
- closeSync5(fd);
21050
+ closeSync6(fd);
20791
21051
  }
20792
21052
  return hash.digest("hex");
20793
21053
  }
@@ -20995,7 +21255,7 @@ function createGithubInstaller(services) {
20995
21255
  throw new Error(`too many redirects (>${maxRedirects})`);
20996
21256
  }
20997
21257
  function validateExtraction(stagingRoot) {
20998
- const realStagingRoot = realpathSync3(stagingRoot);
21258
+ const realStagingRoot = realpathSync4(stagingRoot);
20999
21259
  let totalBytes = 0;
21000
21260
  const walk = (dir) => {
21001
21261
  let entries;
@@ -21021,12 +21281,12 @@ function createGithubInstaller(services) {
21021
21281
  }
21022
21282
  let realFull;
21023
21283
  try {
21024
- realFull = realpathSync3(full);
21284
+ realFull = realpathSync4(full);
21025
21285
  } catch (err) {
21026
21286
  throw new Error(`failed to realpath ${full}: ${err}`);
21027
21287
  }
21028
21288
  const rel = relative4(realStagingRoot, realFull);
21029
- if (relativePathEscapesRoot(rel) || resolve7(realStagingRoot, rel) !== realFull) {
21289
+ if (relativePathEscapesRoot(rel) || resolve8(realStagingRoot, rel) !== realFull) {
21030
21290
  throw new Error(`archive entry escapes staging root: ${full} → ${realFull} (zip-slip defense)`);
21031
21291
  }
21032
21292
  if (lst.isDirectory()) {
@@ -21789,6 +22049,21 @@ function resolveNpm(deps = defaultDeps()) {
21789
22049
  }
21790
22050
  return null;
21791
22051
  }
22052
+ function npmCandidates(deps = defaultDeps()) {
22053
+ const name = npmBinaryName(deps.platform);
22054
+ const dirs = [
22055
+ ...(deps.env.PATH ?? "").split(deps.platform === "win32" ? ";" : ":").filter(isAbsolute5),
22056
+ dirname5(deps.execPath),
22057
+ ...wellKnownNpmDirs(deps)
22058
+ ];
22059
+ return [...new Set(dirs)].flatMap((binDir) => {
22060
+ return [
22061
+ join12(binDir, name),
22062
+ join12(binDir, "node_modules", "npm", "bin", "npm-cli.js"),
22063
+ join12(binDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
22064
+ ].filter(isFile).map((command) => ({ command, binDir }));
22065
+ });
22066
+ }
21792
22067
  function quoteCmdArgument(value) {
21793
22068
  if (/[\0\r\n"%]/.test(value)) {
21794
22069
  throw new Error(`npm argument cannot be represented safely for cmd.exe: ${JSON.stringify(value)}`);
@@ -21796,6 +22071,8 @@ function quoteCmdArgument(value) {
21796
22071
  return `"${value}"`;
21797
22072
  }
21798
22073
  function npmInvocation(resolved, npmArgs, platform = process.platform, env = process.env) {
22074
+ if (resolved.cliPath)
22075
+ return { command: resolved.command, args: [resolved.cliPath, ...npmArgs] };
21799
22076
  if (platform !== "win32" || !/\.(?:cmd|bat)$/i.test(resolved.command)) {
21800
22077
  return { command: resolved.command, args: [...npmArgs] };
21801
22078
  }
@@ -22051,10 +22328,11 @@ function probeNpmCutoffSupport(npm, clock) {
22051
22328
  });
22052
22329
  }
22053
22330
  async function npmSupportsCutoff(npm, clock) {
22054
- const identity = await stat2(npm.command).then(({ size, mtimeMs }) => ({ size, mtimeMs })).catch(() => {
22331
+ const key = npm.cliPath ? `${npm.command}\x00${npm.cliPath}` : npm.command;
22332
+ const identity = await stat2(npm.cliPath ?? npm.command).then(({ size, mtimeMs }) => ({ size, mtimeMs })).catch(() => {
22055
22333
  return;
22056
22334
  });
22057
- const existing = npmCutoffSupport.get(npm.command);
22335
+ const existing = npmCutoffSupport.get(key);
22058
22336
  const sameIdentity = existing && existing.identity?.size === identity?.size && existing.identity?.mtimeMs === identity?.mtimeMs;
22059
22337
  if (existing && sameIdentity) {
22060
22338
  if (!existing.settled || identity !== undefined && existing.settled.outcome !== "transient" || clock.now() < existing.settled.retryAt)
@@ -22065,7 +22343,7 @@ async function npmSupportsCutoff(npm, clock) {
22065
22343
  return outcome;
22066
22344
  });
22067
22345
  const entry = { identity, pending };
22068
- npmCutoffSupport.set(npm.command, entry);
22346
+ npmCutoffSupport.set(key, entry);
22069
22347
  return pending;
22070
22348
  }
22071
22349
  function lspPublicationCutoff(graceDays, pinned, now = Date.now()) {
@@ -22083,6 +22361,79 @@ async function lspNpmInstallInvocation(npm, target, before, clock = SYSTEM_CLOCK
22083
22361
  target
22084
22362
  ]);
22085
22363
  }
22364
+ // ../aft-bridge/dist/lsp-npm-selection.js
22365
+ import { readFile, realpath, stat as stat3 } from "node:fs/promises";
22366
+ import { dirname as dirname6, join as join13, resolve as resolve9 } from "node:path";
22367
+ var LSP_NPM_REFUSAL = "AFT can't install language servers with the npm at <path> (<reason>). Put a real npm 7 or newer first on PATH; pinning a server version won't help.";
22368
+ function lspNpmRefusal(path, reason) {
22369
+ return LSP_NPM_REFUSAL.replace("<path>", path).replace("<reason>", reason);
22370
+ }
22371
+ async function genuineNpm(candidate) {
22372
+ let executable;
22373
+ try {
22374
+ executable = await realpath(candidate.command);
22375
+ } catch (error) {
22376
+ return { reason: `probe failed: ${String(error)}` };
22377
+ }
22378
+ const windowsShim = /\.(?:cmd|bat)$/i.test(executable);
22379
+ let current = dirname6(executable);
22380
+ if (windowsShim)
22381
+ current = join13(current, "node_modules", "npm");
22382
+ for (;; ) {
22383
+ try {
22384
+ const pkg = JSON.parse(await readFile(join13(current, "package.json"), "utf8"));
22385
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.npm;
22386
+ if (pkg.name === "npm" && typeof bin === "string") {
22387
+ const cli = await realpath(resolve9(current, bin));
22388
+ if (!windowsShim && cli !== executable)
22389
+ return { reason: "not npm: command is not npm's declared CLI" };
22390
+ const major = /^(\d+)\.\d+\.\d+$/.exec(pkg.version)?.[1];
22391
+ if (!major)
22392
+ return { reason: "probe failed: npm manifest has an unknown version" };
22393
+ if (Number(major) < 7)
22394
+ return { reason: `old npm: ${pkg.version} (requires npm 7 or newer)` };
22395
+ if (windowsShim || process.platform === "win32" && /\.[cm]?js$/i.test(cli)) {
22396
+ const node = join13(candidate.binDir ?? dirname6(executable), "node.exe");
22397
+ if (!(await stat3(node)).isFile())
22398
+ return { reason: "probe failed: adjacent Node is missing" };
22399
+ return { npm: { command: node, binDir: dirname6(node), cliPath: cli }, reason: "" };
22400
+ }
22401
+ return { npm: { command: cli, binDir: candidate.binDir }, reason: "" };
22402
+ }
22403
+ } catch {}
22404
+ const parent = dirname6(current);
22405
+ if (parent === current || windowsShim)
22406
+ break;
22407
+ current = parent;
22408
+ }
22409
+ return { reason: "not npm: no matching npm package manifest and CLI" };
22410
+ }
22411
+ async function selectLspNpm(preferred, candidates, signal) {
22412
+ const aborted = () => ({
22413
+ refusal: lspNpmRefusal(preferred.command, "probe failed: installation aborted")
22414
+ });
22415
+ if (signal?.aborted)
22416
+ return aborted();
22417
+ const first = await genuineNpm(preferred);
22418
+ if (signal?.aborted)
22419
+ return aborted();
22420
+ if (first.npm)
22421
+ return { npm: first.npm };
22422
+ const seen = new Set([preferred.command]);
22423
+ for (const candidate of candidates ?? npmCandidates()) {
22424
+ if (signal?.aborted)
22425
+ return aborted();
22426
+ if (seen.has(candidate.command))
22427
+ continue;
22428
+ seen.add(candidate.command);
22429
+ const result = await genuineNpm(candidate);
22430
+ if (signal?.aborted)
22431
+ return aborted();
22432
+ if (result.npm)
22433
+ return { npm: result.npm };
22434
+ }
22435
+ return { refusal: lspNpmRefusal(preferred.command, first.reason) };
22436
+ }
22086
22437
  // ../aft-bridge/dist/message-detach.js
22087
22438
  var BASH_WAIT_DETACH_MAGIC_KEYWORD = "&detach";
22088
22439
  var STANDALONE_DETACH_KEYWORD_SOURCE = `(^|[^\\p{L}\\p{N}_])${BASH_WAIT_DETACH_MAGIC_KEYWORD}(?![\\p{L}\\p{N}_])`;
@@ -22132,14 +22483,14 @@ function shouldInterruptWaitsForMessage(detachOnUserMessage, operatorText) {
22132
22483
  return detachOnUserMessage || containsStandaloneDetachKeyword(operatorText);
22133
22484
  }
22134
22485
  // ../aft-bridge/dist/migration.js
22135
- import { closeSync as closeSync7, existsSync as existsSync9, mkdirSync as mkdirSync5, openSync as openSync6, readFileSync as readFileSync8, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync4 } from "node:fs";
22486
+ import { closeSync as closeSync8, existsSync as existsSync9, mkdirSync as mkdirSync5, openSync as openSync7, readFileSync as readFileSync8, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync4 } from "node:fs";
22136
22487
  import { homedir as homedir10, tmpdir as tmpdir3 } from "node:os";
22137
- import { basename as basename2, dirname as dirname8, join as join15, resolve as resolve9 } from "node:path";
22488
+ import { basename as basename2, dirname as dirname9, join as join16, resolve as resolve11 } from "node:path";
22138
22489
 
22139
22490
  // ../aft-bridge/dist/paths.js
22140
- import { existsSync as existsSync7, readFileSync as readFileSync6, realpathSync as realpathSync4, renameSync as renameSync4, writeFileSync as writeFileSync3 } from "node:fs";
22491
+ import { existsSync as existsSync7, readFileSync as readFileSync6, realpathSync as realpathSync5, renameSync as renameSync4, writeFileSync as writeFileSync3 } from "node:fs";
22141
22492
  import { homedir as homedir8 } from "node:os";
22142
- import { dirname as dirname6, isAbsolute as isAbsolute6, join as join13, resolve as resolve8 } from "node:path";
22493
+ import { dirname as dirname7, isAbsolute as isAbsolute6, join as join14, resolve as resolve10 } from "node:path";
22143
22494
  function homeDir3() {
22144
22495
  if (process.platform === "win32")
22145
22496
  return process.env.USERPROFILE || process.env.HOME || homedir8();
@@ -22149,16 +22500,16 @@ function configHome() {
22149
22500
  const xdg = process.env.XDG_CONFIG_HOME;
22150
22501
  if (xdg && isAbsolute6(xdg))
22151
22502
  return xdg;
22152
- return join13(homeDir3(), ".config");
22503
+ return join14(homeDir3(), ".config");
22153
22504
  }
22154
22505
  function legacyOpenCodeConfigDir() {
22155
22506
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
22156
22507
  if (envDir)
22157
- return resolve8(envDir);
22158
- return join13(configHome(), "opencode");
22508
+ return resolve10(envDir);
22509
+ return join14(configHome(), "opencode");
22159
22510
  }
22160
22511
  function legacyPiAgentDir() {
22161
- return join13(homeDir3(), ".pi", "agent");
22512
+ return join14(homeDir3(), ".pi", "agent");
22162
22513
  }
22163
22514
  function legacySources(basePath, label, harness) {
22164
22515
  return [
@@ -22167,10 +22518,10 @@ function legacySources(basePath, label, harness) {
22167
22518
  ];
22168
22519
  }
22169
22520
  function resolveCortexKitUserConfigPath() {
22170
- return join13(configHome(), "cortexkit", "aft.jsonc");
22521
+ return join14(configHome(), "cortexkit", "aft.jsonc");
22171
22522
  }
22172
22523
  function resolveCortexKitProjectConfigPath(projectDirectory) {
22173
- return join13(projectDirectory, ".cortexkit", "aft.jsonc");
22524
+ return join14(projectDirectory, ".cortexkit", "aft.jsonc");
22174
22525
  }
22175
22526
  function resolveProjectConfigReadPath(projectDirectory, operatingHarness) {
22176
22527
  const canonical = resolveCortexKitProjectConfigPath(projectDirectory);
@@ -22197,14 +22548,14 @@ function resolveCortexKitConfigPaths(projectDirectory) {
22197
22548
  }
22198
22549
  function resolveLegacyAftConfigSources(projectDirectory) {
22199
22550
  const project = [
22200
- ...legacySources(join13(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
22201
- ...legacySources(join13(projectDirectory, ".pi", "aft"), "Pi project", "pi")
22551
+ ...legacySources(join14(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
22552
+ ...legacySources(join14(projectDirectory, ".pi", "aft"), "Pi project", "pi")
22202
22553
  ];
22203
22554
  const identity = (path) => {
22204
22555
  try {
22205
- return realpathSync4(path);
22556
+ return realpathSync5(path);
22206
22557
  } catch {
22207
- return resolve8(path);
22558
+ return resolve10(path);
22208
22559
  }
22209
22560
  };
22210
22561
  const protectedPaths = new Set([
@@ -22213,22 +22564,22 @@ function resolveLegacyAftConfigSources(projectDirectory) {
22213
22564
  ].map(identity));
22214
22565
  return {
22215
22566
  user: [
22216
- ...legacySources(join13(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
22217
- ...legacySources(join13(legacyPiAgentDir(), "aft"), "Pi user", "pi")
22567
+ ...legacySources(join14(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
22568
+ ...legacySources(join14(legacyPiAgentDir(), "aft"), "Pi user", "pi")
22218
22569
  ].filter((source) => !protectedPaths.has(identity(source.path))),
22219
22570
  project
22220
22571
  };
22221
22572
  }
22222
22573
  function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
22223
- return join13(storageRoot, harness, ...segments);
22574
+ return join14(storageRoot, harness, ...segments);
22224
22575
  }
22225
22576
  function repairRootScopedStorageFile(storageRoot, harness, fileName) {
22226
22577
  const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
22227
- const rootPath = join13(storageRoot, fileName);
22578
+ const rootPath = join14(storageRoot, fileName);
22228
22579
  if (existsSync7(harnessPath) || !existsSync7(rootPath))
22229
22580
  return harnessPath;
22230
22581
  try {
22231
- openPrivateStorageDir(storageRoot, dirname6(harnessPath));
22582
+ openPrivateStorageDir(storageRoot, dirname7(harnessPath));
22232
22583
  renameSync4(rootPath, harnessPath);
22233
22584
  } catch {}
22234
22585
  return harnessPath;
@@ -22249,7 +22600,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
22249
22600
  return false;
22250
22601
  if (!lastVersion) {
22251
22602
  try {
22252
- openPrivateStorageDir(storageRoot, dirname6(versionFile));
22603
+ openPrivateStorageDir(storageRoot, dirname7(versionFile));
22253
22604
  writeFileSync3(versionFile, currentVersion, { mode: PRIVATE_FILE_MODE });
22254
22605
  } catch {}
22255
22606
  return false;
@@ -22261,7 +22612,7 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
22261
22612
  return;
22262
22613
  const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
22263
22614
  try {
22264
- openPrivateStorageDir(storageRoot, dirname6(versionFile));
22615
+ openPrivateStorageDir(storageRoot, dirname7(versionFile));
22265
22616
  writeFileSync3(versionFile, currentVersion, { mode: PRIVATE_FILE_MODE });
22266
22617
  } catch {}
22267
22618
  }
@@ -22310,18 +22661,18 @@ function decodeFileUrl(target) {
22310
22661
  }
22311
22662
 
22312
22663
  // ../aft-bridge/dist/resolver.js
22313
- import { closeSync as closeSync6, existsSync as existsSync8, promises as fsPromises, openSync as openSync5, readFileSync as readFileSync7, readSync as readSync5 } from "node:fs";
22314
- import { createRequire } from "node:module";
22664
+ import { closeSync as closeSync7, existsSync as existsSync8, promises as fsPromises, openSync as openSync6, readFileSync as readFileSync7, readSync as readSync6 } from "node:fs";
22665
+ import { createRequire as createRequire2 } from "node:module";
22315
22666
  import { homedir as homedir9 } from "node:os";
22316
- import { delimiter, dirname as dirname7, isAbsolute as isAbsolute7, join as join14 } from "node:path";
22667
+ import { delimiter, dirname as dirname8, isAbsolute as isAbsolute7, join as join15 } from "node:path";
22317
22668
  var ensureBinaryForResolver = ensureBinary;
22318
22669
  var npmPlatformPackageReader = null;
22319
22670
  var cacheCopiesInFlight = new Map;
22320
22671
  function copyToVersionedCache(npmBinaryPath, version) {
22321
22672
  const tag = version.startsWith("v") ? version : `v${version}`;
22322
22673
  const ext = process.platform === "win32" ? ".exe" : "";
22323
- const versionedDir = join14(getAftBinaryCacheDir(), tag);
22324
- const cachedPath = join14(versionedDir, `aft${ext}`);
22674
+ const versionedDir = join15(getAftBinaryCacheDir(), tag);
22675
+ const cachedPath = join15(versionedDir, `aft${ext}`);
22325
22676
  if (existsSync8(cachedPath) && isTrustedCachedBinary(cachedPath, version))
22326
22677
  return { cachedPath };
22327
22678
  const existing = cacheCopiesInFlight.get(cachedPath);
@@ -22367,7 +22718,7 @@ function homeDirFromEnv(env) {
22367
22718
  return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir9();
22368
22719
  }
22369
22720
  function cachedBinaryPathFromEnv(version, env, ext) {
22370
- const binaryPath = join14(getAftBinaryCacheDir(env), version, `aft${ext}`);
22721
+ const binaryPath = join15(getAftBinaryCacheDir(env), version, `aft${ext}`);
22371
22722
  return existsSync8(binaryPath) ? binaryPath : null;
22372
22723
  }
22373
22724
  async function probeBinaryCandidateOffThread(binaryPath, source, expectedVersion) {
@@ -22389,7 +22740,7 @@ function pathCandidates(env, ext) {
22389
22740
  for (const dir of rawPath.split(delimiter)) {
22390
22741
  if (!dir || !isAbsolute7(dir))
22391
22742
  continue;
22392
- const candidate = join14(dir, `aft${ext}`);
22743
+ const candidate = join15(dir, `aft${ext}`);
22393
22744
  if (seen.has(candidate))
22394
22745
  continue;
22395
22746
  seen.add(candidate);
@@ -22401,9 +22752,9 @@ function pathCandidates(env, ext) {
22401
22752
  function isNativeExecutable(binaryPath) {
22402
22753
  let fd = null;
22403
22754
  try {
22404
- fd = openSync5(binaryPath, "r");
22755
+ fd = openSync6(binaryPath, "r");
22405
22756
  const buf = Buffer.alloc(4);
22406
- const read = readSync5(fd, buf, 0, 4, 0);
22757
+ const read = readSync6(fd, buf, 0, 4, 0);
22407
22758
  if (read < 2)
22408
22759
  return false;
22409
22760
  const b0 = buf[0];
@@ -22424,7 +22775,7 @@ function isNativeExecutable(binaryPath) {
22424
22775
  } finally {
22425
22776
  if (fd !== null) {
22426
22777
  try {
22427
- closeSync6(fd);
22778
+ closeSync7(fd);
22428
22779
  } catch {}
22429
22780
  }
22430
22781
  }
@@ -22454,7 +22805,7 @@ function explicitBinaryOverride(env) {
22454
22805
  }
22455
22806
  function ownPackageVersion() {
22456
22807
  try {
22457
- const req = createRequire(import.meta.url);
22808
+ const req = createRequire2(import.meta.url);
22458
22809
  return req("../package.json").version;
22459
22810
  } catch {
22460
22811
  return null;
@@ -22464,10 +22815,10 @@ function npmPlatformPackage(ext) {
22464
22815
  if (npmPlatformPackageReader)
22465
22816
  return npmPlatformPackageReader(ext);
22466
22817
  try {
22467
- const req = createRequire(import.meta.url);
22818
+ const req = createRequire2(import.meta.url);
22468
22819
  const manifestPath = req.resolve(`@cortexkit/aft-${platformKey()}/package.json`);
22469
22820
  const manifest = JSON.parse(readFileSync7(manifestPath, "utf8"));
22470
- const binaryPath = join14(dirname7(manifestPath), "bin", `aft${ext}`);
22821
+ const binaryPath = join15(dirname8(manifestPath), "bin", `aft${ext}`);
22471
22822
  if (typeof manifest.version !== "string" || !existsSync8(binaryPath))
22472
22823
  return null;
22473
22824
  return { binaryPath, version: normalizeBareVersion(manifest.version) };
@@ -22534,7 +22885,7 @@ async function findProbedBinary(expectedVersion, env) {
22534
22885
  if (usable)
22535
22886
  return { path: usable, source: "PATH" };
22536
22887
  }
22537
- const cargoPath = join14(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
22888
+ const cargoPath = join15(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
22538
22889
  if (existsSync8(cargoPath)) {
22539
22890
  const usable = await probeBinaryCandidateOffThread(cargoPath, "cargo", pluginVersion);
22540
22891
  if (usable)
@@ -22633,9 +22984,9 @@ function dataHome() {
22633
22984
  if (process.env.XDG_DATA_HOME)
22634
22985
  return process.env.XDG_DATA_HOME;
22635
22986
  if (process.platform === "win32") {
22636
- return process.env.LOCALAPPDATA || process.env.APPDATA || join15(homeDir4(), "AppData", "Local");
22987
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join16(homeDir4(), "AppData", "Local");
22637
22988
  }
22638
- return join15(homeDir4(), ".local", "share");
22989
+ return join16(homeDir4(), ".local", "share");
22639
22990
  }
22640
22991
  function homeDir4() {
22641
22992
  if (process.platform === "win32")
@@ -22644,8 +22995,8 @@ function homeDir4() {
22644
22995
  }
22645
22996
  function resolveLegacyStorageRoot(harness) {
22646
22997
  if (harness === "pi")
22647
- return join15(homeDir4(), ".pi", "agent", "aft");
22648
- return join15(dataHome(), "opencode", "storage", "plugin", "aft");
22998
+ return join16(homeDir4(), ".pi", "agent", "aft");
22999
+ return join16(dataHome(), "opencode", "storage", "plugin", "aft");
22649
23000
  }
22650
23001
  function stripJsoncForParse(input) {
22651
23002
  let out = "";
@@ -22774,19 +23125,19 @@ function acquireConfigMigrationLock(lockDir) {
22774
23125
  }
22775
23126
  }
22776
23127
  function atomicCopyConfigFile(sourcePath, targetPath) {
22777
- mkdirSync5(dirname8(targetPath), { recursive: true });
22778
- const tmpPath = join15(dirname8(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
23128
+ mkdirSync5(dirname9(targetPath), { recursive: true });
23129
+ const tmpPath = join16(dirname9(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
22779
23130
  let fd = null;
22780
23131
  try {
22781
- fd = openSync6(tmpPath, "wx", 384);
23132
+ fd = openSync7(tmpPath, "wx", 384);
22782
23133
  writeFileSync4(fd, readFileSync8(sourcePath));
22783
- closeSync7(fd);
23134
+ closeSync8(fd);
22784
23135
  fd = null;
22785
23136
  renameSync5(tmpPath, targetPath);
22786
23137
  } catch (err) {
22787
23138
  if (fd !== null) {
22788
23139
  try {
22789
- closeSync7(fd);
23140
+ closeSync8(fd);
22790
23141
  } catch {}
22791
23142
  }
22792
23143
  try {
@@ -22796,19 +23147,19 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
22796
23147
  }
22797
23148
  }
22798
23149
  function atomicWriteConfigFile(targetPath, content) {
22799
- mkdirSync5(dirname8(targetPath), { recursive: true });
22800
- const tmpPath = join15(dirname8(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
23150
+ mkdirSync5(dirname9(targetPath), { recursive: true });
23151
+ const tmpPath = join16(dirname9(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
22801
23152
  let fd = null;
22802
23153
  try {
22803
- fd = openSync6(tmpPath, "wx", 384);
23154
+ fd = openSync7(tmpPath, "wx", 384);
22804
23155
  writeFileSync4(fd, content);
22805
- closeSync7(fd);
23156
+ closeSync8(fd);
22806
23157
  fd = null;
22807
23158
  renameSync5(tmpPath, targetPath);
22808
23159
  } catch (err) {
22809
23160
  if (fd !== null) {
22810
23161
  try {
22811
- closeSync7(fd);
23162
+ closeSync8(fd);
22812
23163
  } catch {}
22813
23164
  }
22814
23165
  try {
@@ -22916,13 +23267,13 @@ function visibleConfigMigrationWarning(scope, targetPath, paths, reason) {
22916
23267
  }
22917
23268
  function migrateAftConfigFile(opts) {
22918
23269
  const warnings = [];
22919
- const resolvedTarget = resolve9(opts.targetPath);
22920
- const existingSources = opts.legacySources.filter((source) => existsSync9(source.path) && resolve9(source.path) !== resolvedTarget);
23270
+ const resolvedTarget = resolve11(opts.targetPath);
23271
+ const existingSources = opts.legacySources.filter((source) => existsSync9(source.path) && resolve11(source.path) !== resolvedTarget);
22921
23272
  const info = opts.logger?.info ?? opts.logger?.log;
22922
23273
  if (existingSources.length === 0) {
22923
23274
  return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
22924
23275
  }
22925
- mkdirSync5(dirname8(opts.targetPath), { recursive: true });
23276
+ mkdirSync5(dirname9(opts.targetPath), { recursive: true });
22926
23277
  const release = acquireConfigMigrationLock(`${opts.targetPath}.lock`);
22927
23278
  try {
22928
23279
  const sources = existingSources.map((source) => ({
@@ -22979,13 +23330,13 @@ function spawnErrorLabel(error) {
22979
23330
  return [code, error.message].filter(Boolean).join(": ");
22980
23331
  }
22981
23332
  function migrationLogPath(newRoot, harness, logger) {
22982
- const desired = join15(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
23333
+ const desired = join16(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
22983
23334
  try {
22984
- mkdirSync5(dirname8(desired), { recursive: true });
23335
+ mkdirSync5(dirname9(desired), { recursive: true });
22985
23336
  return desired;
22986
23337
  } catch (err) {
22987
- const fallback = join15(tmpdir3(), `aft-migration-${harness}-${Date.now()}.jsonl`);
22988
- logger?.warn?.(`Failed to create AFT migration log directory ${dirname8(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
23338
+ const fallback = join16(tmpdir3(), `aft-migration-${harness}-${Date.now()}.jsonl`);
23339
+ logger?.warn?.(`Failed to create AFT migration log directory ${dirname9(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
22989
23340
  return fallback;
22990
23341
  }
22991
23342
  }
@@ -23044,13 +23395,13 @@ async function ensureStorageMigrated(opts) {
23044
23395
  // ../aft-bridge/dist/migration-notices.js
23045
23396
  import { readFileSync as readFileSync9, renameSync as renameSync6, rmdirSync, statSync as statSync9, writeFileSync as writeFileSync5 } from "node:fs";
23046
23397
  import { homedir as homedir11 } from "node:os";
23047
- import { dirname as dirname9, join as join16, resolve as resolve10 } from "node:path";
23398
+ import { dirname as dirname10, join as join17, resolve as resolve12 } from "node:path";
23048
23399
  function migrationNoticeStorePath(env = process.env) {
23049
- const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join16(homedir11(), ".local", "state");
23050
- return join16(stateHome, "cortexkit", "aft", "migration-notices.json");
23400
+ const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join17(homedir11(), ".local", "state");
23401
+ return join17(stateHome, "cortexkit", "aft", "migration-notices.json");
23051
23402
  }
23052
23403
  function noticeKey(configPath, digest) {
23053
- return `${resolve10(configPath)}|${MIGRATION_POLICY_ID}|${digest}`;
23404
+ return `${resolve12(configPath)}|${MIGRATION_POLICY_ID}|${digest}`;
23054
23405
  }
23055
23406
  function readRecords(storePath) {
23056
23407
  try {
@@ -23063,7 +23414,7 @@ function readRecords(storePath) {
23063
23414
  var LOCK_STALE_MS = 1e4;
23064
23415
  function withStoreLock(storePath, action) {
23065
23416
  const lockPath = `${storePath}.lock`;
23066
- openPrivateStorageDir(dirname9(storePath));
23417
+ openPrivateStorageDir(dirname10(storePath));
23067
23418
  const deadline = Date.now() + 2000;
23068
23419
  for (;; ) {
23069
23420
  try {
@@ -23117,7 +23468,7 @@ function deliverMigrationNoticeOnce(options) {
23117
23468
  }
23118
23469
  }
23119
23470
  // ../aft-bridge/dist/onnx-probe.js
23120
- import { closeSync as closeSync8, existsSync as existsSync10, openSync as openSync7, readSync as readSync6, realpathSync as realpathSync5 } from "node:fs";
23471
+ import { closeSync as closeSync9, existsSync as existsSync10, openSync as openSync8, readSync as readSync7, realpathSync as realpathSync6 } from "node:fs";
23121
23472
  var MH_MAGIC = 4277009102;
23122
23473
  var MH_MAGIC_64 = 4277009103;
23123
23474
  var FAT_MAGIC = 3405691582;
@@ -23130,7 +23481,7 @@ var MAX_HEADER_BYTES = 4 * 1024 * 1024;
23130
23481
  var UNCHECKED = { loadable: true, checked: false };
23131
23482
  function readAt(fd, offset, length) {
23132
23483
  const buffer = Buffer.alloc(length);
23133
- const read = readSync6(fd, buffer, 0, length, offset);
23484
+ const read = readSync7(fd, buffer, 0, length, offset);
23134
23485
  return buffer.subarray(0, read);
23135
23486
  }
23136
23487
  function cpuTypeForArch(arch) {
@@ -23204,7 +23555,7 @@ function isUncheckableDependency(path) {
23204
23555
  function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
23205
23556
  let fd;
23206
23557
  try {
23207
- fd = openSync7(realpathSync5(libPath), "r");
23558
+ fd = openSync8(realpathSync6(libPath), "r");
23208
23559
  } catch (err) {
23209
23560
  return {
23210
23561
  loadable: false,
@@ -23238,13 +23589,13 @@ function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
23238
23589
  } catch {
23239
23590
  return UNCHECKED;
23240
23591
  } finally {
23241
- closeSync8(fd);
23592
+ closeSync9(fd);
23242
23593
  }
23243
23594
  }
23244
23595
  // ../aft-bridge/dist/onnx-runtime.js
23245
23596
  import { randomBytes as randomBytes3 } from "node:crypto";
23246
- import { chmodSync as chmodSync2, closeSync as closeSync9, copyFileSync as copyFileSync4, createWriteStream as createWriteStream3, existsSync as existsSync11, lstatSync as lstatSync3, openSync as openSync8, readdirSync as readdirSync4, readFileSync as readFileSync10, readlinkSync as readlinkSync2, realpathSync as realpathSync6, renameSync as renameSync7, rmSync as rmSync4, statSync as statSync10, symlinkSync, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "node:fs";
23247
- import { basename as basename3, dirname as dirname10, isAbsolute as isAbsolute8, join as join17, relative as relative5, resolve as resolve11, win32 as win323 } from "node:path";
23597
+ import { chmodSync as chmodSync2, closeSync as closeSync10, copyFileSync as copyFileSync4, createWriteStream as createWriteStream3, existsSync as existsSync11, lstatSync as lstatSync3, openSync as openSync9, readdirSync as readdirSync4, readFileSync as readFileSync10, readlinkSync as readlinkSync2, realpathSync as realpathSync7, renameSync as renameSync7, rmSync as rmSync4, statSync as statSync10, symlinkSync, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "node:fs";
23598
+ import { basename as basename3, dirname as dirname11, isAbsolute as isAbsolute8, join as join18, relative as relative5, resolve as resolve13, win32 as win323 } from "node:path";
23248
23599
  import { Readable as Readable3 } from "node:stream";
23249
23600
  import { pipeline as pipeline3 } from "node:stream/promises";
23250
23601
  var ORT_VERSION = "1.24.4";
@@ -23335,7 +23686,7 @@ function resolveOnnxRuntime(storageDir, seams) {
23335
23686
  }
23336
23687
  async function findCachedOnnxRuntime(ortVersionDir, libName) {
23337
23688
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
23338
- const libPath = join17(resolvedOrtDir, libName);
23689
+ const libPath = join18(resolvedOrtDir, libName);
23339
23690
  if (existsSync11(libPath)) {
23340
23691
  const meta = readOnnxInstalledMeta(ortVersionDir);
23341
23692
  if (meta?.sha256) {
@@ -23360,7 +23711,7 @@ async function findCachedOnnxRuntime(ortVersionDir, libName) {
23360
23711
  }
23361
23712
  async function resolveOnnxRuntimeUncoalesced(storageDir, seams) {
23362
23713
  const info = seams.platformInfo !== undefined ? seams.platformInfo : getPlatformInfo();
23363
- const ortVersionDir = join17(storageDir, "onnxruntime", ORT_VERSION);
23714
+ const ortVersionDir = join18(storageDir, "onnxruntime", ORT_VERSION);
23364
23715
  const libName = info?.libName ?? "libonnxruntime.dylib";
23365
23716
  const cached = await findCachedOnnxRuntime(ortVersionDir, libName);
23366
23717
  if (cached)
@@ -23374,9 +23725,9 @@ async function resolveOnnxRuntimeUncoalesced(storageDir, seams) {
23374
23725
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
23375
23726
  return null;
23376
23727
  }
23377
- const onnxBaseDir = join17(storageDir, "onnxruntime");
23728
+ const onnxBaseDir = join18(storageDir, "onnxruntime");
23378
23729
  openPrivateStorageDir(storageDir, onnxBaseDir);
23379
- const lockPath = join17(onnxBaseDir, ONNX_LOCK_FILE);
23730
+ const lockPath = join18(onnxBaseDir, ONNX_LOCK_FILE);
23380
23731
  const pollMs = seams.lockPollMs ?? LOCK_POLL_MS;
23381
23732
  const deadline = Date.now() + LOCK_WAIT_MS;
23382
23733
  let announcedWait = false;
@@ -23421,7 +23772,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
23421
23772
  for (const entry of entries) {
23422
23773
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
23423
23774
  continue;
23424
- const stagingDir = join17(onnxBaseDir, entry);
23775
+ const stagingDir = join18(onnxBaseDir, entry);
23425
23776
  const parts = entry.split(".");
23426
23777
  const pidStr = parts[parts.length - 2];
23427
23778
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -23458,7 +23809,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
23458
23809
  }
23459
23810
  function cleanupIncompleteTargetIfUnowned(ortDir) {
23460
23811
  try {
23461
- if (existsSync11(ortDir) && !existsSync11(join17(ortDir, ONNX_INSTALLED_META_FILE))) {
23812
+ if (existsSync11(ortDir) && !existsSync11(join18(ortDir, ONNX_INSTALLED_META_FILE))) {
23462
23813
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
23463
23814
  rmSync4(ortDir, { recursive: true, force: true });
23464
23815
  }
@@ -23493,7 +23844,7 @@ function detectOnnxVersion(libDir, libName) {
23493
23844
  try {
23494
23845
  const entries = readdirSync4(libDir);
23495
23846
  try {
23496
- const resolved = parseOnnxVersionFromPath(realpathSync6(join17(libDir, libName)));
23847
+ const resolved = parseOnnxVersionFromPath(realpathSync7(join18(libDir, libName)));
23497
23848
  if (resolved && resolved !== INVALID_ORT_VERSION)
23498
23849
  return resolved;
23499
23850
  } catch {}
@@ -23507,10 +23858,10 @@ function detectOnnxVersion(libDir, libName) {
23507
23858
  if (version)
23508
23859
  return version;
23509
23860
  }
23510
- const base = join17(libDir, libName);
23861
+ const base = join18(libDir, libName);
23511
23862
  if (existsSync11(base)) {
23512
23863
  try {
23513
- const real = realpathSync6(base);
23864
+ const real = realpathSync7(base);
23514
23865
  const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
23515
23866
  if (version)
23516
23867
  return version;
@@ -23574,10 +23925,10 @@ function directoryContainsLibrary(dir, libName) {
23574
23925
  }
23575
23926
  }
23576
23927
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
23577
- if (existsSync11(join17(ortVersionDir, libName)))
23928
+ if (existsSync11(join18(ortVersionDir, libName)))
23578
23929
  return ortVersionDir;
23579
- const libSubdir = join17(ortVersionDir, "lib");
23580
- if (existsSync11(join17(libSubdir, libName)))
23930
+ const libSubdir = join18(ortVersionDir, "lib");
23931
+ if (existsSync11(join18(libSubdir, libName)))
23581
23932
  return libSubdir;
23582
23933
  return ortVersionDir;
23583
23934
  }
@@ -23592,12 +23943,12 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23592
23943
  } else if (process.platform === "win32") {
23593
23944
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
23594
23945
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
23595
- searchPaths.push(join17(programFiles, "onnxruntime", "lib"), join17(programFiles, "Microsoft ONNX Runtime", "lib"), join17(programFiles, "Microsoft Machine Learning", "lib"), join17(programFilesX86, "onnxruntime", "lib"), ...(() => {
23946
+ searchPaths.push(join18(programFiles, "onnxruntime", "lib"), join18(programFiles, "Microsoft ONNX Runtime", "lib"), join18(programFiles, "Microsoft Machine Learning", "lib"), join18(programFilesX86, "onnxruntime", "lib"), ...(() => {
23596
23947
  const nugetPaths = [];
23597
23948
  const userProfile = process.env.USERPROFILE ?? "";
23598
23949
  if (!userProfile)
23599
23950
  return nugetPaths;
23600
- const nugetPackageDir = join17(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
23951
+ const nugetPackageDir = join18(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
23601
23952
  if (!existsSync11(nugetPackageDir))
23602
23953
  return nugetPaths;
23603
23954
  try {
@@ -23606,7 +23957,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23606
23957
  continue;
23607
23958
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
23608
23959
  continue;
23609
- nugetPaths.push(join17(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join17(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
23960
+ nugetPaths.push(join18(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join18(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
23610
23961
  }
23611
23962
  } catch (err) {
23612
23963
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -23618,7 +23969,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23618
23969
  const normalizeCase = process.platform === "win32" || process.platform === "darwin";
23619
23970
  const seen = new Set;
23620
23971
  const uniquePaths = searchPaths.filter((p) => {
23621
- let key = resolve11(p).replace(/[/\\]+$/, "");
23972
+ let key = resolve13(p).replace(/[/\\]+$/, "");
23622
23973
  if (normalizeCase)
23623
23974
  key = key.toLowerCase();
23624
23975
  if (seen.has(key))
@@ -23628,7 +23979,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23628
23979
  });
23629
23980
  const unknownVersionPaths = [];
23630
23981
  for (const dir of uniquePaths) {
23631
- const libPath = join17(dir, libName);
23982
+ const libPath = join18(dir, libName);
23632
23983
  if (process.platform === "win32") {
23633
23984
  if (!directoryContainsLibrary(dir, libName))
23634
23985
  continue;
@@ -23675,7 +24026,7 @@ async function downloadFileWithCap(url, destPath) {
23675
24026
  if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
23676
24027
  throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
23677
24028
  }
23678
- privateMkdirSync(dirname10(destPath));
24029
+ privateMkdirSync(dirname11(destPath));
23679
24030
  let bytesWritten = 0;
23680
24031
  const guard = new TransformStream({
23681
24032
  transform(chunk, transformController) {
@@ -23702,16 +24053,16 @@ async function downloadFileWithCap(url, destPath) {
23702
24053
  }
23703
24054
  }
23704
24055
  function validateExtractedTree(stagingRoot) {
23705
- const realRoot = realpathSync6(stagingRoot);
24056
+ const realRoot = realpathSync7(stagingRoot);
23706
24057
  let totalBytes = 0;
23707
24058
  const walk = (dir) => {
23708
24059
  const entries = readdirSync4(dir);
23709
24060
  for (const entry of entries) {
23710
- const fullPath = join17(dir, entry);
24061
+ const fullPath = join18(dir, entry);
23711
24062
  const lst = lstatSync3(fullPath);
23712
24063
  if (lst.isSymbolicLink()) {
23713
24064
  const linkTarget = readlinkSync2(fullPath);
23714
- const resolvedTarget = resolve11(dirname10(fullPath), linkTarget);
24065
+ const resolvedTarget = resolve13(dirname11(fullPath), linkTarget);
23715
24066
  const rel = relative5(realRoot, resolvedTarget);
23716
24067
  if (relativePathEscapesRoot(rel) || win323.isAbsolute(rel)) {
23717
24068
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
@@ -23744,11 +24095,11 @@ async function downloadOnnxRuntime(info, targetDir) {
23744
24095
  const url = `https://github.com/${ORT_REPO}/releases/download/v${ORT_VERSION}/${info.assetName}.${info.archiveType === "tgz" ? "tgz" : "zip"}`;
23745
24096
  log(`Downloading ONNX Runtime v${ORT_VERSION} for ${process.platform}/${process.arch}...`);
23746
24097
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}${randomBytes3(4).toString("hex")}`;
23747
- const extractionRoot = join17(tmpDir, "extract");
23748
- const stagedInstallDir = join17(tmpDir, "install");
24098
+ const extractionRoot = join18(tmpDir, "extract");
24099
+ const stagedInstallDir = join18(tmpDir, "install");
23749
24100
  try {
23750
24101
  privateMkdirSync(extractionRoot);
23751
- const archivePath = join17(tmpDir, `onnxruntime.${info.archiveType}`);
24102
+ const archivePath = join18(tmpDir, `onnxruntime.${info.archiveType}`);
23752
24103
  await downloadFileWithCap(url, archivePath);
23753
24104
  const archiveSha256 = await sha256File(archivePath);
23754
24105
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
@@ -23761,7 +24112,7 @@ async function downloadOnnxRuntime(info, targetDir) {
23761
24112
  unlinkSync5(archivePath);
23762
24113
  } catch {}
23763
24114
  validateExtractedTree(extractionRoot);
23764
- const extractedDir = join17(extractionRoot, info.assetName, "lib");
24115
+ const extractedDir = join18(extractionRoot, info.assetName, "lib");
23765
24116
  if (!existsSync11(extractedDir)) {
23766
24117
  throw new Error(`Expected directory not found: ${extractedDir}`);
23767
24118
  }
@@ -23769,7 +24120,7 @@ async function downloadOnnxRuntime(info, targetDir) {
23769
24120
  const realFiles = [];
23770
24121
  const symlinks = [];
23771
24122
  for (const libFile of libFiles) {
23772
- const src = join17(extractedDir, libFile);
24123
+ const src = join18(extractedDir, libFile);
23773
24124
  try {
23774
24125
  const stat = lstatSync3(src);
23775
24126
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
@@ -23784,14 +24135,14 @@ async function downloadOnnxRuntime(info, targetDir) {
23784
24135
  }
23785
24136
  }
23786
24137
  copyOnnxLibraries(info, extractedDir, stagedInstallDir, realFiles, symlinks);
23787
- const libPath = join17(stagedInstallDir, info.libName);
24138
+ const libPath = join18(stagedInstallDir, info.libName);
23788
24139
  const libHash = await sha256File(libPath);
23789
24140
  if (libHash !== info.librarySha256) {
23790
24141
  throw new Error(`onnx runtime library hash mismatch at ${libPath}: sha256 ${libHash}, ` + `expected the pinned ${info.librarySha256} for ${info.assetName}`);
23791
24142
  }
23792
24143
  writeOnnxInstalledMeta(stagedInstallDir, ORT_VERSION, libHash, archiveSha256);
23793
24144
  publishOnnxRuntime(stagedInstallDir, targetDir);
23794
- writeStampedFileDigest(join17(targetDir, info.libName), libHash);
24145
+ writeStampedFileDigest(join18(targetDir, info.libName), libHash);
23795
24146
  rmSync4(tmpDir, { recursive: true, force: true });
23796
24147
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
23797
24148
  return targetDir;
@@ -23833,8 +24184,8 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
23833
24184
  const requiredLibs = new Set([info.libName]);
23834
24185
  privateMkdirSync(targetDir);
23835
24186
  for (const libFile of realFiles) {
23836
- const src = join17(extractedDir, libFile);
23837
- const dst = join17(targetDir, libFile);
24187
+ const src = join18(extractedDir, libFile);
24188
+ const dst = join18(targetDir, libFile);
23838
24189
  try {
23839
24190
  if (copyFile === copyFileSync4)
23840
24191
  privateCopyFileSync(src, dst);
@@ -23851,14 +24202,14 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
23851
24202
  log(`ORT extract: failed to copy optional ${libFile}: ${copyErr}`);
23852
24203
  }
23853
24204
  }
23854
- const targetRoot = realpathSync6(targetDir);
24205
+ const targetRoot = realpathSync7(targetDir);
23855
24206
  for (const link of symlinks) {
23856
- const dst = join17(targetDir, link.name);
24207
+ const dst = join18(targetDir, link.name);
23857
24208
  try {
23858
24209
  unlinkSync5(dst);
23859
24210
  } catch {}
23860
- const dstForContainment = join17(targetRoot, link.name);
23861
- const resolvedTarget = resolve11(dirname10(dstForContainment), link.target);
24211
+ const dstForContainment = join18(targetRoot, link.name);
24212
+ const resolvedTarget = resolve13(dirname11(dstForContainment), link.target);
23862
24213
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
23863
24214
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
23864
24215
  if (requiredLibs.has(link.name)) {
@@ -23878,7 +24229,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
23878
24229
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
23879
24230
  }
23880
24231
  }
23881
- const requiredPath = join17(targetDir, info.libName);
24232
+ const requiredPath = join18(targetDir, info.libName);
23882
24233
  if (!existsSync11(requiredPath)) {
23883
24234
  rmSync4(targetDir, { recursive: true, force: true });
23884
24235
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
@@ -23906,7 +24257,7 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
23906
24257
  ...sha256 ? { sha256 } : {},
23907
24258
  archiveSha256
23908
24259
  };
23909
- writeFileSync6(join17(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), {
24260
+ writeFileSync6(join18(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), {
23910
24261
  encoding: "utf8",
23911
24262
  mode: PRIVATE_FILE_MODE
23912
24263
  });
@@ -23915,7 +24266,7 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
23915
24266
  }
23916
24267
  }
23917
24268
  function readOnnxInstalledMeta(installDir) {
23918
- const path = join17(installDir, ONNX_INSTALLED_META_FILE);
24269
+ const path = join18(installDir, ONNX_INSTALLED_META_FILE);
23919
24270
  try {
23920
24271
  if (!statSync10(path).isFile())
23921
24272
  return null;
@@ -23936,13 +24287,13 @@ function readOnnxInstalledMeta(installDir) {
23936
24287
  function acquireLock(lockPath) {
23937
24288
  const tryClaim = () => {
23938
24289
  try {
23939
- const fd = openSync8(lockPath, "wx", PRIVATE_FILE_MODE);
24290
+ const fd = openSync9(lockPath, "wx", PRIVATE_FILE_MODE);
23940
24291
  try {
23941
24292
  writeFileSync6(fd, `${process.pid}
23942
24293
  ${new Date().toISOString()}
23943
24294
  `);
23944
24295
  } finally {
23945
- closeSync9(fd);
24296
+ closeSync10(fd);
23946
24297
  }
23947
24298
  return true;
23948
24299
  } catch (err) {
@@ -29678,13 +30029,6 @@ var LspConfigSchema = object({
29678
30029
  versions: record(string2().trim().min(1), string2().trim().min(1)).optional()
29679
30030
  });
29680
30031
  var ExperimentalConfigSchema = object({
29681
- bash: object({
29682
- rewrite: boolean2().optional(),
29683
- compress: boolean2().optional(),
29684
- background: boolean2().optional(),
29685
- long_running_reminder_enabled: boolean2().optional(),
29686
- long_running_reminder_interval_ms: number2().int().positive().optional()
29687
- }).optional(),
29688
30032
  lsp_ty: boolean2().optional()
29689
30033
  });
29690
30034
  var BashEnvSchema = record(string2(), string2()).superRefine((env, context) => {
@@ -29784,7 +30128,6 @@ function clampInspectDiagnosticsTimeoutMs(value) {
29784
30128
  var InspectConfigSchema = object({
29785
30129
  enabled: boolean2().optional(),
29786
30130
  diagnostics_timeout_ms: number2().int().positive().optional().transform((value) => value === undefined ? undefined : clampInspectDiagnosticsTimeoutMs(value)),
29787
- tier2_idle_minutes: number2().min(0).optional(),
29788
30131
  tier2_pass_timeout_ms: number2().int().positive().optional(),
29789
30132
  categories: object({
29790
30133
  diagnostics: boolean2().optional(),
@@ -29802,11 +30145,16 @@ var InspectConfigSchema = object({
29802
30145
  function clampIdleRootTtlMinutes(value) {
29803
30146
  return Math.min(30, Math.max(5, value));
29804
30147
  }
30148
+ function clampIdleCheckoutHours(value) {
30149
+ return Math.min(IDLE_CHECKOUT_HOURS_MAX, Math.max(IDLE_CHECKOUT_HOURS_MIN, value));
30150
+ }
29805
30151
  var IdleConfigSchema = object({
29806
- root_ttl_minutes: number2().int().optional().transform((value) => value === undefined ? undefined : clampIdleRootTtlMinutes(value))
30152
+ root_ttl_minutes: number2().int().optional().transform((value) => value === undefined ? undefined : clampIdleRootTtlMinutes(value)),
30153
+ checkout_hours: number2().int().optional().transform((value) => value === undefined ? undefined : clampIdleCheckoutHours(value))
29807
30154
  });
29808
30155
  var ViewsConfigSchema = object({
29809
- enabled: boolean2().optional()
30156
+ enabled: boolean2().optional(),
30157
+ callgraph_copies: number2().int().optional()
29810
30158
  });
29811
30159
  var WorktreeConfigSchema = object({
29812
30160
  ram_overlay: boolean2().optional()
@@ -29910,6 +30258,11 @@ function applyActiveHarnessOverride(config, trusted) {
29910
30258
  delete merged.indexes;
29911
30259
  else
29912
30260
  merged.indexes = indexes;
30261
+ const idle = mergeIdleConfig(base.idle, override.idle);
30262
+ if (idle === undefined)
30263
+ delete merged.idle;
30264
+ else
30265
+ merged.idle = idle;
29913
30266
  merged.sandbox = mergeSandboxConfig(base.sandbox, override.sandbox, true);
29914
30267
  if (!trusted && override.sandbox?.write_allow !== undefined) {
29915
30268
  merged.sandbox = { ...merged.sandbox, write_allow: override.sandbox.write_allow };
@@ -29934,9 +30287,8 @@ function clampBashWatchSyncMaxMs(value) {
29934
30287
  }
29935
30288
  function resolveBashConfig(config) {
29936
30289
  const top = config.bash;
29937
- const legacy = config.experimental?.bash;
29938
- const reminderEnabled = (typeof top === "object" && top !== null ? top.long_running_reminder_enabled : undefined) ?? legacy?.long_running_reminder_enabled;
29939
- const reminderInterval = (typeof top === "object" && top !== null ? top.long_running_reminder_interval_ms : undefined) ?? legacy?.long_running_reminder_interval_ms;
30290
+ const reminderEnabled = typeof top === "object" && top !== null ? top.long_running_reminder_enabled : undefined;
30291
+ const reminderInterval = typeof top === "object" && top !== null ? top.long_running_reminder_interval_ms : undefined;
29940
30292
  const topSubagentBg = typeof top === "object" && top !== null ? top.subagent_background !== false : true;
29941
30293
  const topDetachOnUserMessage = typeof top === "object" && top !== null ? top.detach_on_user_message ?? true : true;
29942
30294
  const rawForegroundWait = typeof top === "object" && top !== null ? top.foreground_wait_window_ms : undefined;
@@ -29983,19 +30335,6 @@ function resolveBashConfig(config) {
29983
30335
  powershell_tool: top.powershell_tool ?? false
29984
30336
  };
29985
30337
  }
29986
- const hasLegacyFeatureFlag = legacy && (legacy.rewrite !== undefined || legacy.compress !== undefined || legacy.background !== undefined);
29987
- if (hasLegacyFeatureFlag) {
29988
- const rewrite = legacy.rewrite === true;
29989
- const compress = legacy.compress === true;
29990
- const background = legacy.background === true;
29991
- return {
29992
- ...base,
29993
- enabled: true,
29994
- rewrite,
29995
- compress,
29996
- background
29997
- };
29998
- }
29999
30338
  return { ...base, enabled: true, rewrite: true, compress: true, background: true };
30000
30339
  }
30001
30340
  function parseConfigPartially(rawConfig) {
@@ -30132,7 +30471,7 @@ function loadConfigFromPath(configPath, tier) {
30132
30471
  recordConfigParseFailure(configPath, errorMsg);
30133
30472
  throw new ConfigRejectedError(["invalid_config_document"], configPath);
30134
30473
  }
30135
- const removed = removedConfigKeyErrors(cleanConfig);
30474
+ const removed = removedConfigKeyErrors(cleanConfig, undefined, false);
30136
30475
  if (removed.length) {
30137
30476
  throw new ConfigRejectedError(removed);
30138
30477
  }
@@ -30155,9 +30494,18 @@ function loadConfigFromPath(configPath, tier) {
30155
30494
  warn2(text);
30156
30495
  }
30157
30496
  }
30158
- if (translation.legacyInput && tier === "user") {
30159
- log2(`Config ${configPath} uses retired keys (${translation.retiredKeys.join(", ")}); applied their current equivalents in memory`);
30160
- } else if (translation.legacyInput) {
30497
+ if (tier === "user") {
30498
+ if (translation.legacyInput) {
30499
+ log2(`Config ${configPath} uses retired keys (${translation.retiredKeys.join(", ")}); applied their current equivalents in memory`);
30500
+ }
30501
+ if (translation.removedKeys.length > 0) {
30502
+ configLoadNotices.push({
30503
+ configPath,
30504
+ digest: removedConfigKeysNoticeDigest(translation),
30505
+ message: removedConfigKeysNoticeMessage(configPath, translation)
30506
+ });
30507
+ }
30508
+ } else if (translation.legacyInput || translation.removedKeys.length > 0) {
30161
30509
  configLoadNotices.push({
30162
30510
  configPath,
30163
30511
  digest: noticeDigest(projection),
@@ -30242,6 +30590,13 @@ function mergeWorktreeConfig(baseWorktree, overrideWorktree) {
30242
30590
  return overrideWorktree;
30243
30591
  return { ...baseWorktree, ...overrideWorktree };
30244
30592
  }
30593
+ function mergeIdleConfig(baseIdle, overrideIdle) {
30594
+ const merged = {
30595
+ root_ttl_minutes: overrideIdle?.root_ttl_minutes ?? baseIdle?.root_ttl_minutes,
30596
+ checkout_hours: overrideIdle?.checkout_hours ?? baseIdle?.checkout_hours
30597
+ };
30598
+ return merged.root_ttl_minutes === undefined && merged.checkout_hours === undefined ? undefined : merged;
30599
+ }
30245
30600
  function mergeInspectConfig(baseInspect, overrideInspect) {
30246
30601
  const diagnosticsTimeoutConfigured = baseInspect?.diagnostics_timeout_ms !== undefined || overrideInspect?.diagnostics_timeout_ms !== undefined;
30247
30602
  const diagnosticsTimeoutMs = Math.max(clampInspectDiagnosticsTimeoutMs(baseInspect?.diagnostics_timeout_ms ?? DEFAULT_INSPECT_DIAGNOSTICS_TIMEOUT_MS), clampInspectDiagnosticsTimeoutMs(overrideInspect?.diagnostics_timeout_ms ?? DEFAULT_INSPECT_DIAGNOSTICS_TIMEOUT_MS));
@@ -30339,19 +30694,10 @@ function mergeBashEnvMaps(base, override) {
30339
30694
  return Object.fromEntries(merged.values());
30340
30695
  }
30341
30696
  function mergeExperimentalConfig(baseExperimental, overrideExperimental) {
30342
- const bash = {
30343
- ...baseExperimental?.bash,
30344
- ...overrideExperimental?.bash
30345
- };
30346
30697
  const experimental = {
30347
30698
  ...baseExperimental,
30348
30699
  ...overrideExperimental
30349
30700
  };
30350
- if (Object.values(bash).some((value) => value !== undefined)) {
30351
- experimental.bash = bash;
30352
- } else {
30353
- delete experimental.bash;
30354
- }
30355
30701
  if (Object.values(experimental).every((value) => value === undefined)) {
30356
30702
  return;
30357
30703
  }
@@ -30502,17 +30848,21 @@ function mergeConfigs(base, override) {
30502
30848
  }
30503
30849
  const inspect = mergeInspectConfig(base.inspect, override.inspect);
30504
30850
  const worktree = mergeWorktreeConfig(base.worktree, override.worktree);
30851
+ const idle = mergeIdleConfig(base.idle, override.idle);
30505
30852
  const sandbox = mergeSandboxConfig(base.sandbox, override.sandbox);
30506
30853
  const remoteExec = mergeRemoteExecConfig(base.remote_exec, override.remote_exec);
30507
30854
  const backup = mergeProjectBackupConfig(base.backup, override.backup);
30508
30855
  const pi = mergePiConfig(base.pi, override.pi);
30856
+ const views = base.views !== undefined || override.views !== undefined ? { ...base.views, ...override.views } : undefined;
30509
30857
  const bridge = base.bridge;
30510
30858
  const safeOverride = pickProjectSafeFields(override);
30511
30859
  delete safeOverride.indexes;
30512
30860
  delete safeOverride.bash;
30513
30861
  delete safeOverride.inspect;
30514
30862
  delete safeOverride.worktree;
30863
+ delete safeOverride.idle;
30515
30864
  delete safeOverride.pi;
30865
+ delete safeOverride.views;
30516
30866
  return {
30517
30867
  ...base,
30518
30868
  ...safeOverride,
@@ -30522,10 +30872,12 @@ function mergeConfigs(base, override) {
30522
30872
  ...bash !== undefined ? { bash } : {},
30523
30873
  ...inspect !== undefined ? { inspect } : {},
30524
30874
  ...worktree !== undefined ? { worktree } : {},
30875
+ ...idle !== undefined ? { idle } : {},
30525
30876
  ...sandbox !== undefined ? { sandbox } : {},
30526
30877
  ...remoteExec !== undefined ? { remote_exec: remoteExec } : {},
30527
30878
  ...backup !== undefined ? { backup } : {},
30528
30879
  ...pi !== undefined ? { pi } : {},
30880
+ ...views !== undefined ? { views } : {},
30529
30881
  experimental,
30530
30882
  semantic,
30531
30883
  search,
@@ -30929,7 +31281,7 @@ async function signalActiveBridges(pool, projectRoot, sessionID, request) {
30929
31281
  }
30930
31282
 
30931
31283
  // src/bg-notifications.ts
30932
- import { createHash as createHash6, randomBytes as randomBytes4, randomUUID as randomUUID2 } from "node:crypto";
31284
+ import { createHash as createHash7, randomBytes as randomBytes4, randomUUID as randomUUID2 } from "node:crypto";
30933
31285
 
30934
31286
  // src/shared/last-assistant-model.ts
30935
31287
  function isRecord3(value) {
@@ -31253,7 +31605,7 @@ async function awaitWakeAdmission(options) {
31253
31605
 
31254
31606
  // src/bg-notifications.ts
31255
31607
  function hashReminder(text) {
31256
- return createHash6("sha256").update(text).digest("hex").slice(0, 16);
31608
+ return createHash7("sha256").update(text).digest("hex").slice(0, 16);
31257
31609
  }
31258
31610
  var CONSUMED_TASKIDS_CAP = 256;
31259
31611
  var DELIVERED_AWAITING_ACK_CAP = 4096;
@@ -32809,14 +33161,14 @@ async function runDetachedBgHandler(work, onError) {
32809
33161
 
32810
33162
  // src/lsp-auto-install.ts
32811
33163
  import { existsSync as existsSync14, mkdirSync as mkdirSync7, renameSync as renameSync9, rmSync as rmSync6, statSync as statSync13, writeFileSync as writeFileSync8 } from "node:fs";
32812
- import { join as join20 } from "node:path";
33164
+ import { join as join21 } from "node:path";
32813
33165
 
32814
33166
  // src/lsp-cache.ts
32815
33167
  import { randomUUID as randomUUID3 } from "node:crypto";
32816
33168
  import {
32817
- closeSync as closeSync10,
33169
+ closeSync as closeSync11,
32818
33170
  mkdirSync as mkdirSync6,
32819
- openSync as openSync9,
33171
+ openSync as openSync10,
32820
33172
  readFileSync as readFileSync12,
32821
33173
  renameSync as renameSync8,
32822
33174
  rmSync as rmSync5,
@@ -32824,7 +33176,7 @@ import {
32824
33176
  unlinkSync as unlinkSync6,
32825
33177
  writeFileSync as writeFileSync7
32826
33178
  } from "node:fs";
32827
- import { join as join18 } from "node:path";
33179
+ import { join as join19 } from "node:path";
32828
33180
  function aftCacheBase() {
32829
33181
  return getAftCacheRoot();
32830
33182
  }
@@ -32832,18 +33184,18 @@ function lspCacheRoot() {
32832
33184
  return getAftLspPackagesDir();
32833
33185
  }
32834
33186
  function lspPackageDir(npmPackage) {
32835
- return join18(lspCacheRoot(), encodeURIComponent(npmPackage));
33187
+ return join19(lspCacheRoot(), encodeURIComponent(npmPackage));
32836
33188
  }
32837
33189
  function lspBinaryPath(npmPackage, binary) {
32838
- return join18(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
33190
+ return join19(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
32839
33191
  }
32840
33192
  function lspBinDir(npmPackage) {
32841
- return join18(lspPackageDir(npmPackage), "node_modules", ".bin");
33193
+ return join19(lspPackageDir(npmPackage), "node_modules", ".bin");
32842
33194
  }
32843
33195
  function isInstalled(npmPackage, binary) {
32844
33196
  for (const candidate of lspBinaryCandidates(binary)) {
32845
33197
  try {
32846
- if (statSync12(join18(lspBinDir(npmPackage), candidate)).isFile())
33198
+ if (statSync12(join19(lspBinDir(npmPackage), candidate)).isFile())
32847
33199
  return true;
32848
33200
  } catch {}
32849
33201
  }
@@ -32863,13 +33215,13 @@ function writeInstalledMetaIn(installDir, version, sha256) {
32863
33215
  installedAt: new Date().toISOString(),
32864
33216
  ...sha256 ? { sha256 } : {}
32865
33217
  };
32866
- writeFileSync7(join18(installDir, INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
33218
+ writeFileSync7(join19(installDir, INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
32867
33219
  } catch (err) {
32868
33220
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
32869
33221
  }
32870
33222
  }
32871
33223
  function readInstalledMetaIn(installDir) {
32872
- const path = join18(installDir, INSTALLED_META_FILE);
33224
+ const path = join19(installDir, INSTALLED_META_FILE);
32873
33225
  try {
32874
33226
  if (!statSync12(path).isFile())
32875
33227
  return null;
@@ -32893,7 +33245,7 @@ function readInstalledMeta(packageKey) {
32893
33245
  return readInstalledMetaIn(lspPackageDir(packageKey));
32894
33246
  }
32895
33247
  function lockPath(npmPackage) {
32896
- return join18(lspPackageDir(npmPackage), ".aft-installing");
33248
+ return join19(lspPackageDir(npmPackage), ".aft-installing");
32897
33249
  }
32898
33250
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
32899
33251
  function acquireInstallLock(lockKey) {
@@ -32902,14 +33254,14 @@ function acquireInstallLock(lockKey) {
32902
33254
  const token = randomUUID3();
32903
33255
  const tryClaim = () => {
32904
33256
  try {
32905
- const fd = openSync9(lock, "wx");
33257
+ const fd = openSync10(lock, "wx");
32906
33258
  try {
32907
33259
  writeFileSync7(fd, `${process.pid}
32908
33260
  ${new Date().toISOString()}
32909
33261
  ${token}
32910
33262
  `);
32911
33263
  } finally {
32912
- closeSync10(fd);
33264
+ closeSync11(fd);
32913
33265
  }
32914
33266
  let retained = false;
32915
33267
  let released = false;
@@ -33024,7 +33376,7 @@ var AUTO_INSTALL_STAMP_FILE = "last-lsp-autoinstall.json";
33024
33376
  var AUTO_INSTALL_WINDOW_MS = 60 * 1000;
33025
33377
  var AUTO_INSTALL_LOCK_STALE_MS = 30 * 60 * 1000;
33026
33378
  function autoInstallStampPath() {
33027
- return join18(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
33379
+ return join19(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
33028
33380
  }
33029
33381
  function hasRecentAutoInstallStamp(path) {
33030
33382
  try {
@@ -33072,11 +33424,11 @@ function claimLspAutoInstallPass() {
33072
33424
  };
33073
33425
  const tryClaim = () => {
33074
33426
  try {
33075
- const fd = openSync9(lock, "wx");
33427
+ const fd = openSync10(lock, "wx");
33076
33428
  try {
33077
33429
  writeFileSync7(fd, JSON.stringify(owner));
33078
33430
  } finally {
33079
- closeSync10(fd);
33431
+ closeSync11(fd);
33080
33432
  }
33081
33433
  return true;
33082
33434
  } catch (err) {
@@ -33125,7 +33477,7 @@ function claimLspAutoInstallPass() {
33125
33477
  }
33126
33478
  var VERSION_CHECK_FILE = ".aft-version-check";
33127
33479
  function readVersionCheck(npmPackage) {
33128
- const file = join18(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33480
+ const file = join19(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33129
33481
  try {
33130
33482
  const raw = readFileSync12(file, "utf8");
33131
33483
  const parsed = JSON.parse(raw);
@@ -33142,7 +33494,7 @@ function readVersionCheck(npmPackage) {
33142
33494
  }
33143
33495
  function writeVersionCheck(npmPackage, latest) {
33144
33496
  mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
33145
- const file = join18(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33497
+ const file = join19(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33146
33498
  const record = {
33147
33499
  last_checked: new Date().toISOString(),
33148
33500
  latest_eligible: latest
@@ -33259,7 +33611,7 @@ function isVersionSupported(spec, version) {
33259
33611
 
33260
33612
  // src/lsp-project-relevance.ts
33261
33613
  import { existsSync as existsSync13, readdirSync as readdirSync5, readFileSync as readFileSync13 } from "node:fs";
33262
- import { join as join19 } from "node:path";
33614
+ import { join as join20 } from "node:path";
33263
33615
  var MAX_WALK_DIRS = 200;
33264
33616
  var MAX_WALK_DEPTH = 4;
33265
33617
  var NOISE_DIRS = new Set([
@@ -33276,7 +33628,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
33276
33628
  if (!rootMarkers)
33277
33629
  return false;
33278
33630
  for (const marker of rootMarkers) {
33279
- if (existsSync13(join19(projectRoot, marker)))
33631
+ if (existsSync13(join20(projectRoot, marker)))
33280
33632
  return true;
33281
33633
  }
33282
33634
  return false;
@@ -33300,7 +33652,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
33300
33652
  }
33301
33653
  function readPackageJson(projectRoot) {
33302
33654
  try {
33303
- const raw = readFileSync13(join19(projectRoot, "package.json"), "utf8");
33655
+ const raw = readFileSync13(join20(projectRoot, "package.json"), "utf8");
33304
33656
  const parsed = JSON.parse(raw);
33305
33657
  if (typeof parsed !== "object" || parsed === null)
33306
33658
  return null;
@@ -33330,7 +33682,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
33330
33682
  for (const entry of entries) {
33331
33683
  if (entry.isDirectory()) {
33332
33684
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
33333
- queue.push({ dir: join19(current.dir, entry.name), depth: current.depth + 1 });
33685
+ queue.push({ dir: join20(current.dir, entry.name), depth: current.depth + 1 });
33334
33686
  }
33335
33687
  continue;
33336
33688
  }
@@ -33463,7 +33815,7 @@ async function resolveTargetVersion(spec, config, fetchImpl = fetch) {
33463
33815
  }
33464
33816
  function ensureInstallAnchor(cwd) {
33465
33817
  try {
33466
- const stub = join20(cwd, "package.json");
33818
+ const stub = join21(cwd, "package.json");
33467
33819
  if (!existsSync14(stub)) {
33468
33820
  writeFileSync8(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
33469
33821
  `);
@@ -33479,18 +33831,26 @@ async function runInstall(spec, version, cwd, installLock, before, signal) {
33479
33831
  warn2(`[lsp] install ${target} aborted before spawn`);
33480
33832
  return false;
33481
33833
  }
33482
- const npm = resolveNpm();
33483
- if (!npm) {
33834
+ const preferredNpm = resolveNpm();
33835
+ if (!preferredNpm) {
33484
33836
  warn2(`[lsp] npm not found on PATH or known locations; cannot install ${target}`);
33485
33837
  return false;
33486
33838
  }
33839
+ const selected = await selectLspNpm(preferredNpm, undefined, signal);
33840
+ if (signal?.aborted)
33841
+ return false;
33842
+ if (!selected.npm) {
33843
+ warn2(`[lsp] ${selected.refusal}`);
33844
+ return false;
33845
+ }
33846
+ const npm = selected.npm;
33487
33847
  const invocation = await lspNpmInstallInvocation(npm, target, before);
33488
33848
  if (signal?.aborted) {
33489
33849
  warn2(`[lsp] install ${target} aborted during npm capability probe`);
33490
33850
  return false;
33491
33851
  }
33492
33852
  if (!invocation) {
33493
- warn2(`[lsp] npm cannot enforce the publication cutoff; cannot install ${target}`);
33853
+ warn2(`[lsp] ${lspNpmRefusal(npm.command, "probe failed: cannot verify publication-cutoff support")}`);
33494
33854
  return false;
33495
33855
  }
33496
33856
  ensureInstallAnchor(cwd);
@@ -33567,6 +33927,9 @@ async function runInstall(spec, version, cwd, installLock, before, signal) {
33567
33927
  log2(`[lsp] installed ${target}`);
33568
33928
  finish(true);
33569
33929
  } else {
33930
+ const rejectedOption = /--(?:no-save|before|ignore-scripts)\b/.exec(stderrBuf)?.[0];
33931
+ if (rejectedOption)
33932
+ warn2(`[lsp] ${lspNpmRefusal(npm.command, `rejected option: ${rejectedOption}`)}`);
33570
33933
  error2(`[lsp] install ${target} exited with code ${code}; last stderr:
33571
33934
  ${stderrBuf.trim()}`);
33572
33935
  finish(false);
@@ -33673,10 +34036,10 @@ function sha256OfFileSync(path) {
33673
34036
  }
33674
34037
  function quarantineCachedNpmInstall(spec, reason) {
33675
34038
  const packageDir = lspPackageDir(spec.npm);
33676
- const dest = join20(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
34039
+ const dest = join21(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
33677
34040
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
33678
34041
  try {
33679
- mkdirSync7(join20(dest, ".."), { recursive: true });
34042
+ mkdirSync7(join21(dest, ".."), { recursive: true });
33680
34043
  rmSync6(dest, { recursive: true, force: true });
33681
34044
  renameSync9(packageDir, dest);
33682
34045
  } catch (err) {
@@ -45690,13 +46053,16 @@ async function boundedVerification(client, sessionId) {
45690
46053
  setCache(sessionId, dir);
45691
46054
  return dir;
45692
46055
  }
46056
+ function clearSessionDirectory(sessionId) {
46057
+ cache.delete(sessionId);
46058
+ lookupGenerations.delete(sessionId);
46059
+ verifyCache.delete(sessionId);
46060
+ }
45693
46061
  async function closeDeletedSessionRoutes(pool, sessionId, fallbackDirectory) {
45694
46062
  const roots = new Set(pool.activeBridges().map((bridge) => bridge.getCwd()));
45695
46063
  roots.add(getSessionDirectoryCached(sessionId) ?? fallbackDirectory);
45696
46064
  await Promise.allSettled([...roots].map((root) => pool.closeSession(root, sessionId)));
45697
- cache.delete(sessionId);
45698
- lookupGenerations.delete(sessionId);
45699
- verifyCache.delete(sessionId);
46065
+ clearSessionDirectory(sessionId);
45700
46066
  }
45701
46067
 
45702
46068
  // src/shared/subagent-detect.ts
@@ -46515,6 +46881,9 @@ function canonicalizeDirectory(dir) {
46515
46881
  return canonicalizeProjectRoot(dir);
46516
46882
  }
46517
46883
  function projectRootFor(runtime) {
46884
+ if (runtime.directoryIsSessionRoot && runtime.directory) {
46885
+ return canonicalizeDirectory(runtime.directory);
46886
+ }
46518
46887
  const cached = getSessionDirectoryCached(runtime.sessionID);
46519
46888
  if (typeof cached === "string" && cached.length > 0) {
46520
46889
  return canonicalizeDirectory(cached);
@@ -46965,6 +47334,10 @@ function registerV2SessionLifecycle(context, ctx) {
46965
47334
  const sessionID = event.data.sessionID;
46966
47335
  if (!sessionID)
46967
47336
  return;
47337
+ if (event.type === "session.moved") {
47338
+ clearSessionDirectory(sessionID);
47339
+ return;
47340
+ }
46968
47341
  if (event.type === "session.deleted") {
46969
47342
  const state = sessions.get(sessionID);
46970
47343
  const kills = killStoppedBackgroundTasks(context, sessionID, ctx);
@@ -47162,7 +47535,7 @@ function backgroundWaitDescription(watchToolRegistered, statusRegistered, role =
47162
47535
  }
47163
47536
  if (watchToolRegistered) {
47164
47537
  const noPolling = statusRegistered ? ", and never loop bash_status to wait" : "";
47165
- return `then bash_watch handles only a short remaining wait (in a main session a watch defaults to 30s, max bash.watch_sync_max_ms, 120s by default; in a delegated session a watch without a timeout waits up to the worker wait limit, bash.worker_wait_max_ms, 30 minutes by default, then reports it is still running; watch again to keep waiting); for anything longer end the turn and let the completion reminder wake you, or use bash({wait:true}) when the result is needed before anything else — never background a command and immediately bash_watch it (that wastes a turn for what foreground returns in one)${noPolling}.`;
47538
+ return `then bash_watch handles only a short remaining wait (in a main session a watch defaults to 30s, max bash.watch_sync_max_ms, 120s by default; in a delegated session a watch without a timeout waits up to the worker wait limit, bash.worker_wait_max_ms, 30 minutes by default, then reports it is still running; watch again to keep waiting); for anything longer, first do the work that doesn't need this result, end the turn only when everything left needs it, and let the completion reminder wake you, or use bash({wait:true}) when the result is needed before anything else — never background a command and immediately bash_watch it (that wastes a turn for what foreground returns in one)${noPolling}.`;
47166
47539
  }
47167
47540
  return statusRegistered ? "the task keeps running after the call returns, a completion reminder arrives when it exits, and bash_status reports its state and output. Use bash({wait:true}) instead when the result is needed before anything else." : "the task keeps running after the call returns and a completion reminder arrives when it exits. Use bash({wait:true}) instead when the result is needed before anything else.";
47168
47541
  }
@@ -47189,7 +47562,7 @@ function bashToolDescription(aftSearchRegistered, compressionOn, backgroundOn, d
47189
47562
  ].join(", ");
47190
47563
  const searchSteer = `use ${steerTools}${zoomEnabled ? ", or aft_zoom" : ""} instead`;
47191
47564
  const compression = compressionOn ? " Output is compressed by default; pass compressed: false for raw output. Piped commands run verbatim and show the pipeline's output; for AFT's test/build summary, run the runner without | head, | tail, or | grep. Pipeline-failure notes cover single top-level pipelines only; multi-statement commands (`a; b | c; d`) are not instrumented, so masked failures inside them still need explicit exit-code checks." : "";
47192
- const tasks = backgroundOn ? ` Commands run in the foreground and return inline; wait: true blocks until a long command finishes instead of auto-promoting (it blocks up to bash.worker_wait_max_ms, 30 minutes by default, then reports the command is still running; watch again to keep waiting); ${userMessageDetachDescription(detachOnUserMessage)} Use it when you need the result before doing anything else; ${autoPromote}. Use background: true yourself ONLY when you have other useful work to do while it runs; ${backgroundWaitDescription(watchToolRegistered, status, role)} Do not change or delete files a background command uses until it finishes. A \`nohup … &\` launch still holds the call if the child keeps stdout/stderr; redirect both or use background:true. pty: true runs interactive programs (REPLs, TUIs), implies background${ptyDriveClause(status, write)}.` : " Commands run in the foreground to completion; timeout is the hard kill cap (default 30 minutes).";
47565
+ const tasks = backgroundOn ? ` Commands run in the foreground and return inline; wait: true blocks until a long command finishes instead of auto-promoting (it blocks up to bash.worker_wait_max_ms, 30 minutes by default, then reports the command is still running; watch again to keep waiting); ${userMessageDetachDescription(detachOnUserMessage)} Use it when you need the result before doing anything else; ${autoPromote}. Use background: true yourself ONLY when you have other work to do while it runs, and any work that doesn't need this command's result counts; ${backgroundWaitDescription(watchToolRegistered, status, role)} Do not change or delete files a background command uses until it finishes. A \`nohup … &\` launch still holds the call if the child keeps stdout/stderr; redirect both or use background:true. pty: true runs interactive programs (REPLs, TUIs), implies background${ptyDriveClause(status, write)}.` : " Commands run in the foreground to completion; timeout is the hard kill cap (default 30 minutes).";
47193
47566
  const outputRules = backgroundOn ? " Finished output expires after the task is 24 hours old and its completion has been delivered; under project-root restrictions, only the starting session can read output outside the project—copy cited lines into your report." : "";
47194
47567
  const timeoutRules = " `timeout` starts after spawn and kills the Unix process group (exit 124; Windows uses taskkill /T /F); processes that leave the group survive.";
47195
47568
  const remoteRuns = surface.remoteRuns ? ` ${BASH_RUNON_GUIDANCE}` : "";
@@ -47665,6 +48038,55 @@ function failure(error) {
47665
48038
  })();
47666
48039
  return new Error(`V2 tool execution rejected with a non-Error value: ${detail}`);
47667
48040
  }
48041
+ function tagOf(value) {
48042
+ return typeof value === "object" && value !== null ? value._tag : undefined;
48043
+ }
48044
+ function hostPermissionRefusal(error) {
48045
+ if (!(error instanceof BashPermissionLoopError) || !error.message)
48046
+ return error;
48047
+ const hostError = error.cause;
48048
+ if (!(hostError instanceof Error) || tagOf(hostError) !== "Tool.Error")
48049
+ return error;
48050
+ const inner = hostError.error;
48051
+ if (!(inner instanceof Error))
48052
+ return error;
48053
+ const text = error.message;
48054
+ try {
48055
+ const InnerClass = inner.constructor;
48056
+ let rebuilt;
48057
+ let shown;
48058
+ switch (tagOf(inner)) {
48059
+ case "Permission.BlockedError": {
48060
+ const { rules, permission, resources } = inner;
48061
+ rebuilt = new InnerClass({ rules, permission, resources, reason: text });
48062
+ shown = rebuilt.message;
48063
+ break;
48064
+ }
48065
+ case "Permission.CorrectedError":
48066
+ rebuilt = new InnerClass({ feedback: text });
48067
+ shown = rebuilt.feedback;
48068
+ break;
48069
+ default:
48070
+ return error;
48071
+ }
48072
+ if (!(rebuilt instanceof InnerClass) || tagOf(rebuilt) !== tagOf(inner) || shown !== text) {
48073
+ return error;
48074
+ }
48075
+ const ToolErrorClass = hostError.constructor;
48076
+ const metadata = hostError.metadata;
48077
+ const refusal = new ToolErrorClass({
48078
+ message: text,
48079
+ error: rebuilt,
48080
+ ...metadata === undefined ? {} : { metadata }
48081
+ });
48082
+ if (!(refusal instanceof ToolErrorClass) || tagOf(refusal) !== "Tool.Error" || refusal.message !== text || refusal.error !== rebuilt) {
48083
+ return error;
48084
+ }
48085
+ return refusal;
48086
+ } catch {
48087
+ return error;
48088
+ }
48089
+ }
47668
48090
  function isPlainObject3(value) {
47669
48091
  if (typeof value !== "object" || value === null)
47670
48092
  return false;
@@ -47875,7 +48297,7 @@ function projectV2Tool(name, definition, location, consumers = {}) {
47875
48297
  } catch (error) {
47876
48298
  if (stepAbort)
47877
48299
  throw new PermissionStepAbort(stepAbort.error);
47878
- throw error;
48300
+ throw hostPermissionRefusal(error);
47879
48301
  } finally {
47880
48302
  signal.removeEventListener("abort", onAbort);
47881
48303
  }
@@ -47886,7 +48308,7 @@ function projectV2Tool(name, definition, location, consumers = {}) {
47886
48308
  }
47887
48309
 
47888
48310
  // src/tools/hoisted.ts
47889
- import { stat as stat3 } from "node:fs/promises";
48311
+ import { stat as stat4 } from "node:fs/promises";
47890
48312
  import * as path4 from "node:path";
47891
48313
 
47892
48314
  // src/hashline-tag-sources.ts
@@ -48005,19 +48427,22 @@ function coerceConfiguredWatchTimeout(value, role, cap) {
48005
48427
  throw new Error(`${message} (bash.watch_sync_max_ms)`);
48006
48428
  }
48007
48429
  }
48008
- function bashWatchDescription(role, statusRegistered) {
48430
+ var PRIMARY_ASYNC_WATCH_SENTENCES = " The user can interrupt anytime; the wait auto-converts to an async notification. Async (background:true, requires pattern) registers a non-blocking notification and returns immediately — use when you have parallel work or want to end your turn.";
48431
+ function bashWatchDescription(role, statusRegistered, asyncWatches = true) {
48009
48432
  const noPolling = statusRegistered ? " Never loop bash_status to wait." : "";
48010
48433
  if (role === "worker") {
48011
48434
  return `Watch a background bash task and wait until it exits or prints a pattern. ${WATCH_SYNC_DEFAULTS_DESCRIPTION}. A background task never wakes you, so wait on it before you report a result. ${WORKER_KEEP_WAITING}${noPolling}`;
48012
48435
  }
48013
- return `Watch a background bash task. ${WATCH_SYNC_DEFAULTS_DESCRIPTION}. In a main session sync waits are for a short remaining wait on a task; for anything longer end the turn on \`bash({background:true})\` and let the completion reminder wake you, or use \`bash({wait:true})\` when the result is needed before anything else. The user can interrupt anytime; the wait auto-converts to an async notification. Async (background:true, requires pattern) registers a non-blocking notification and returns immediately — use when you have parallel work or want to end your turn.${noPolling}`;
48436
+ const asyncSentences = asyncWatches ? PRIMARY_ASYNC_WATCH_SENTENCES : "";
48437
+ return `Watch a background bash task. ${WATCH_SYNC_DEFAULTS_DESCRIPTION}. In a main session sync waits are for a short remaining wait on a task; for anything longer, first do the work that doesn't need the result, end the turn only when everything left needs it, and let the completion reminder wake you, or use \`bash({wait:true})\` when the result is needed before anything else.${asyncSentences}${noPolling}`;
48014
48438
  }
48439
+ var WATCH_PATTERN_MODES_SENTENCE = " Optional in sync mode; required with background:true.";
48015
48440
  function createBashWatchTool(ctx) {
48016
48441
  return {
48017
48442
  description: bashWatchDescription("primary", bashCompanionRegistered(ctx.config, "bash_status")),
48018
48443
  args: {
48019
48444
  taskId: z5.string().describe("Background task ID returned by bash({ background: true })."),
48020
- pattern: z5.union([z5.string(), z5.object({ regex: z5.string() })]).optional().describe("Substring or regex pattern. Optional in sync mode; required with background:true. Sync substring watches keep only the overlap tail needed for boundary matches; sync regex watches use a 64 KB rolling output window."),
48445
+ pattern: z5.union([z5.string(), z5.object({ regex: z5.string() })]).optional().describe(`Substring or regex pattern.${WATCH_PATTERN_MODES_SENTENCE} Sync substring watches keep only the overlap tail needed for boundary matches; sync regex watches use a 64 KB rolling output window.`),
48021
48446
  background: z5.boolean().optional().describe("When true, register an async watch and return immediately. Defaults to false (sync wait)."),
48022
48447
  timeoutMs: optionalInt(1, 1800000).describe(WATCH_TIMEOUT_PARAM_DESCRIPTION),
48023
48448
  deliver: z5.literal("each_line").optional().describe("Async-only: batch every matching complete line, fold consecutive duplicates, and report cap drops with byte offsets."),
@@ -48900,7 +49325,7 @@ function createReadTool(ctx) {
48900
49325
  const ref = revisionRefArg(args.ref);
48901
49326
  if (ref !== undefined)
48902
49327
  rawArgs.ref = ref;
48903
- const mediaCandidate = isGithubResourcePath(file) || /\.(png|jpe?g|gif|webp|pdf)$/i.test(filePath) && await stat3(filePath).then((info) => info.isFile(), () => false);
49328
+ const mediaCandidate = isGithubResourcePath(file) || /\.(png|jpe?g|gif|webp|pdf)$/i.test(filePath) && await stat4(filePath).then((info) => info.isFile(), () => false);
48904
49329
  const visionCapability = mediaCandidate ? await measurePreStage("capability", () => currentSessionVisionCapability(ctx.client, context.sessionID)) : undefined;
48905
49330
  if (visionCapability !== undefined)
48906
49331
  rawArgs.vision_capability = visionCapability;
@@ -49571,7 +49996,7 @@ function importTools(ctx) {
49571
49996
  }
49572
49997
 
49573
49998
  // src/tools/inspect.ts
49574
- import { stat as stat4 } from "node:fs/promises";
49999
+ import { stat as stat5 } from "node:fs/promises";
49575
50000
  var z9 = tool.schema;
49576
50001
  var INSPECT_TRANSPORT_HEADROOM_MS = 30000;
49577
50002
  function arg(schema) {
@@ -49595,7 +50020,7 @@ async function resolveAndGateScope(ctx, context, scope) {
49595
50020
  });
49596
50021
  if (denial)
49597
50022
  return { scope: undefined, denial };
49598
- if (!await stat4(target).then((entry) => entry.isDirectory(), () => false)) {
50023
+ if (!await stat5(target).then((entry) => entry.isDirectory(), () => false)) {
49599
50024
  const readDenial = await assertV2ReadPermission(context, target);
49600
50025
  if (readDenial)
49601
50026
  return { scope: undefined, denial: readDenial };
@@ -49732,39 +50157,6 @@ function compactTerminalField(value, fallback) {
49732
50157
  compact = compact?.replaceAll(internal, plain);
49733
50158
  return compact || fallback;
49734
50159
  }
49735
- function createInspectTier2IdleScheduler(options) {
49736
- const timers = new Map;
49737
- const setTimer = options.setTimer ?? ((callback, delayMs) => setTimeout(callback, delayMs));
49738
- const clearTimer = options.clearTimer ?? ((timer) => clearTimeout(timer));
49739
- const clear = (sessionID) => {
49740
- const timer = timers.get(sessionID);
49741
- if (!timer)
49742
- return;
49743
- clearTimer(timer);
49744
- timers.delete(sessionID);
49745
- };
49746
- const clearAll = () => {
49747
- for (const timer of timers.values())
49748
- clearTimer(timer);
49749
- timers.clear();
49750
- };
49751
- const schedule = (sessionID) => {
49752
- if (!options.isEnabled())
49753
- return;
49754
- clear(sessionID);
49755
- const idleMinutes = options.idleMinutes() ?? 4;
49756
- const delayMs = Math.max(0, idleMinutes * 60 * 1000);
49757
- const timer = setTimer(() => {
49758
- timers.delete(sessionID);
49759
- options.run(sessionID).catch((err) => {
49760
- options.warn?.(`inspect_tier2_run failed: ${err instanceof Error ? err.message : String(err)}`);
49761
- });
49762
- }, delayMs);
49763
- timer.unref?.();
49764
- timers.set(sessionID, timer);
49765
- };
49766
- return { schedule, clear, clearAll };
49767
- }
49768
50160
  function inspectTools(ctx) {
49769
50161
  const inspectTool = {
49770
50162
  description: "Codebase health inspection that waits for current analysis. FRESH means the reported analysis is current. PARTIAL means some diagnostics are unknown; the header names the analyzer, reason, and retry guidance. INTERRUPTED means the request stopped without a fresh snapshot; retry aft_inspect. PHASE-FAILED means inspection could not finish; address the reported reason and retry, or narrow the scope. `sections` selects drill-down detail. Scoped requests collect diagnostics when sections is omitted or includes 'diagnostics' or 'all'; sections that leave diagnostics out skip diagnostics work. Unscoped requests keep warm diagnostics. Categories switched off in `inspect.categories` are not computed or refreshed, render as off, and never make the header PARTIAL.\n\n" + "Use `scope=` to narrow all findings, counts, and examples to those paths. Cross-boundary duplicates are labeled as groups touching the scope. Scope also limits Rust analyzer startup to the Cargo workspaces owning those paths when diagnostics are requested. Files without an authoritative diagnostic report remain named gaps (complete: false), not a clean result.\n\n" + `Use when: starting work on unfamiliar code, after multi-edit batches to check diagnostics, before a refactor, before review, or to verify cleanup completeness.
@@ -49819,7 +50211,7 @@ function navigationTools(ctx) {
49819
50211
  ` + `- 'callers': Find all call sites of a symbol. Use before renaming or changing a function's signature.
49820
50212
  ` + `- 'impact': What breaks if a symbol changes — affected callers with signatures and entry-point status (blast radius). Use before a risky edit.
49821
50213
  ` + `- 'call_tree': What a function calls (forward traversal). Use to understand a function's dependencies before modifying it.
49822
- ` + `- 'trace_to': How execution reaches a function from entry points (routes, exports, main). Use to understand context around deeply-nested code.
50214
+ ` + `- 'trace_to': How execution reaches a function: each path of callers runs back to a root, labelled main, test, attribute, public API, or no caller found. Use to understand context around deeply-nested code.
49823
50215
  ` + `- 'trace_to_symbol': Shortest call path from one symbol to another. Requires 'toSymbol'. If multiple targets match, the error returns candidate files; retry with 'toPath' to disambiguate.
49824
50216
  ` + `- 'trace_data': Follow a value through variable assignments and function parameters across files. Requires 'symbol' (scope to trace from) and 'expression'.
49825
50217
 
@@ -51280,7 +51672,7 @@ function startOpenCodeLiveConfigReload(options) {
51280
51672
  // src/notifications.ts
51281
51673
  import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
51282
51674
  import { homedir as homedir14, platform } from "node:os";
51283
- import { join as join23 } from "node:path";
51675
+ import { join as join24 } from "node:path";
51284
51676
  function isTuiMode() {
51285
51677
  return process.env.OPENCODE_CLIENT === "cli";
51286
51678
  }
@@ -51302,15 +51694,15 @@ function getDesktopStatePath() {
51302
51694
  const os = platform();
51303
51695
  const home = homedir14();
51304
51696
  if (os === "darwin") {
51305
- return join23(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
51697
+ return join24(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
51306
51698
  }
51307
51699
  if (os === "linux") {
51308
- const xdgConfig = process.env.XDG_CONFIG_HOME || join23(home, ".config");
51309
- return join23(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
51700
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join24(home, ".config");
51701
+ return join24(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
51310
51702
  }
51311
51703
  if (os === "win32") {
51312
- const appData = process.env.APPDATA || join23(home, "AppData", "Roaming");
51313
- return join23(appData, "ai.opencode.desktop", "opencode.global.dat");
51704
+ const appData = process.env.APPDATA || join24(home, "AppData", "Roaming");
51705
+ return join24(appData, "ai.opencode.desktop", "opencode.global.dat");
51314
51706
  }
51315
51707
  return null;
51316
51708
  }
@@ -51822,47 +52214,47 @@ async function flushConfigureWarningsOnIdle(sessionId) {
51822
52214
  // src/hooks/auto-update-checker/index.ts
51823
52215
  import { randomUUID as randomUUID4 } from "node:crypto";
51824
52216
  import {
51825
- closeSync as closeSync12,
52217
+ closeSync as closeSync13,
51826
52218
  existsSync as existsSync20,
51827
- fstatSync as fstatSync3,
52219
+ fstatSync as fstatSync4,
51828
52220
  linkSync,
51829
52221
  mkdirSync as mkdirSync8,
51830
- openSync as openSync11,
52222
+ openSync as openSync12,
51831
52223
  readFileSync as readFileSync17,
51832
52224
  renameSync as renameSync10,
51833
52225
  rmSync as rmSync8,
51834
52226
  statSync as statSync17,
51835
52227
  writeFileSync as writeFileSync11
51836
52228
  } from "node:fs";
51837
- import { dirname as dirname15 } from "node:path";
52229
+ import { dirname as dirname16 } from "node:path";
51838
52230
 
51839
52231
  // src/hooks/auto-update-checker/cache.ts
51840
52232
  import { cpSync, existsSync as existsSync19, mkdtempSync, readFileSync as readFileSync16, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "node:fs";
51841
52233
  import { tmpdir as tmpdir4 } from "node:os";
51842
- import { basename as basename5, dirname as dirname14, join as join26 } from "node:path";
52234
+ import { basename as basename5, dirname as dirname15, join as join27 } from "node:path";
51843
52235
  var import_comment_json3 = __toESM(require_src2(), 1);
51844
52236
 
51845
52237
  // src/hooks/auto-update-checker/checker.ts
51846
52238
  import { existsSync as existsSync18, readFileSync as readFileSync15, statSync as statSync16, writeFileSync as writeFileSync9 } from "node:fs";
51847
- import { readFile } from "node:fs/promises";
52239
+ import { readFile as readFile2 } from "node:fs/promises";
51848
52240
  import { homedir as homedir15 } from "node:os";
51849
- import { dirname as dirname13, isAbsolute as isAbsolute14, join as join25, resolve as resolve15 } from "node:path";
52241
+ import { dirname as dirname14, isAbsolute as isAbsolute14, join as join26, resolve as resolve17 } from "node:path";
51850
52242
  import { fileURLToPath } from "node:url";
51851
52243
  var import_comment_json2 = __toESM(require_src2(), 1);
51852
52244
 
51853
52245
  // src/hooks/auto-update-checker/constants.ts
51854
- import { join as join24 } from "node:path";
52246
+ import { join as join25 } from "node:path";
51855
52247
  var PACKAGE_NAME = "@cortexkit/aft-opencode";
51856
52248
  var NPM_REGISTRY_URL = "https://registry.npmjs.org";
51857
52249
  var NPM_FETCH_TIMEOUT = 1e4;
51858
52250
  function cacheDir() {
51859
- return join24(getOpenCodeCacheRoot(), "packages");
52251
+ return join25(getOpenCodeCacheRoot(), "packages");
51860
52252
  }
51861
52253
  function userOpenCodeConfig() {
51862
- return join24(getOpenCodeConfigRoot(), "opencode.json");
52254
+ return join25(getOpenCodeConfigRoot(), "opencode.json");
51863
52255
  }
51864
52256
  function userOpenCodeConfigJsonc() {
51865
- return join24(getOpenCodeConfigRoot(), "opencode.jsonc");
52257
+ return join25(getOpenCodeConfigRoot(), "opencode.jsonc");
51866
52258
  }
51867
52259
 
51868
52260
  // src/hooks/auto-update-checker/types.ts
@@ -51921,8 +52313,8 @@ function extractChannel(version) {
51921
52313
  }
51922
52314
  function getConfigPaths(directory) {
51923
52315
  return [
51924
- join25(directory, ".opencode", "opencode.json"),
51925
- join25(directory, ".opencode", "opencode.jsonc"),
52316
+ join26(directory, ".opencode", "opencode.json"),
52317
+ join26(directory, ".opencode", "opencode.jsonc"),
51926
52318
  userOpenCodeConfig(),
51927
52319
  userOpenCodeConfigJsonc()
51928
52320
  ];
@@ -51937,7 +52329,7 @@ function resolvePathPluginSpec(spec, configPath) {
51937
52329
  }
51938
52330
  if (isAbsolute14(spec) || /^[A-Za-z]:[\\/]/.test(spec))
51939
52331
  return spec;
51940
- return resolve15(dirname13(configPath), spec);
52332
+ return resolve17(dirname14(configPath), spec);
51941
52333
  }
51942
52334
  function getLocalDevPath(directory) {
51943
52335
  for (const configPath of getConfigPaths(directory)) {
@@ -51966,9 +52358,9 @@ function getLocalDevPath(directory) {
51966
52358
  function findPackageJsonUp(startPath) {
51967
52359
  try {
51968
52360
  const stat = statSync16(startPath);
51969
- let dir = stat.isDirectory() ? startPath : dirname13(startPath);
52361
+ let dir = stat.isDirectory() ? startPath : dirname14(startPath);
51970
52362
  for (let i = 0;i < 10; i++) {
51971
- const pkgPath = join25(dir, "package.json");
52363
+ const pkgPath = join26(dir, "package.json");
51972
52364
  if (existsSync18(pkgPath)) {
51973
52365
  try {
51974
52366
  const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync15(pkgPath, "utf-8")));
@@ -51976,7 +52368,7 @@ function findPackageJsonUp(startPath) {
51976
52368
  return pkgPath;
51977
52369
  } catch {}
51978
52370
  }
51979
- const parent = dirname13(dir);
52371
+ const parent = dirname14(dir);
51980
52372
  if (parent === dir)
51981
52373
  break;
51982
52374
  dir = parent;
@@ -52000,7 +52392,7 @@ function getLocalDevVersion(directory) {
52000
52392
  }
52001
52393
  function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
52002
52394
  try {
52003
- return findPackageJsonUp(dirname13(fileURLToPath(currentModuleUrl)));
52395
+ return findPackageJsonUp(dirname14(fileURLToPath(currentModuleUrl)));
52004
52396
  } catch (err) {
52005
52397
  warn2(`[auto-update-checker] Failed to resolve runtime package path: ${String(err)}`);
52006
52398
  return null;
@@ -52034,7 +52426,7 @@ function findPluginEntry(directory) {
52034
52426
  }
52035
52427
  var cachedPackageVersion = null;
52036
52428
  function getSpecCachePackageJsonPath(spec) {
52037
- return join25(cacheDir(), spec, "node_modules", PACKAGE_NAME, "package.json");
52429
+ return join26(cacheDir(), spec, "node_modules", PACKAGE_NAME, "package.json");
52038
52430
  }
52039
52431
  function getCachedVersion(spec) {
52040
52432
  if (!spec && cachedPackageVersion)
@@ -52043,7 +52435,7 @@ function getCachedVersion(spec) {
52043
52435
  getCurrentRuntimePackageJsonPath(),
52044
52436
  spec ? getSpecCachePackageJsonPath(spec) : null,
52045
52437
  getSpecCachePackageJsonPath(`${PACKAGE_NAME}@latest`),
52046
- join25(getOpenCodeCacheRoot(), "node_modules", PACKAGE_NAME, "package.json")
52438
+ join26(getOpenCodeCacheRoot(), "node_modules", PACKAGE_NAME, "package.json")
52047
52439
  ].filter(isString);
52048
52440
  for (const packageJsonPath of candidates) {
52049
52441
  try {
@@ -52081,7 +52473,7 @@ function configuredRegistry(value) {
52081
52473
  async function readRegistrySettings(path, required = false) {
52082
52474
  let text;
52083
52475
  try {
52084
- text = await readFile(path, "utf8");
52476
+ text = await readFile2(path, "utf8");
52085
52477
  } catch (error) {
52086
52478
  if (!required && error.code === "ENOENT")
52087
52479
  return {};
@@ -52111,20 +52503,20 @@ async function registryWithoutNpm(directory) {
52111
52503
  let scoped = registryEnvironment("@cortexkit:registry");
52112
52504
  let registry = registryEnvironment("registry");
52113
52505
  const visited = new Set;
52114
- for (let current = directory;; current = dirname13(current)) {
52506
+ for (let current = directory;; current = dirname14(current)) {
52115
52507
  if (scoped)
52116
52508
  break;
52117
- const path = join25(current, ".npmrc");
52509
+ const path = join26(current, ".npmrc");
52118
52510
  visited.add(path);
52119
52511
  const settings = await readRegistrySettings(path);
52120
52512
  scoped ??= settings["@cortexkit:registry"];
52121
52513
  registry ??= settings.registry;
52122
- if (dirname13(current) === current)
52514
+ if (dirname14(current) === current)
52123
52515
  break;
52124
52516
  }
52125
52517
  const explicitUserConfig = process.env.npm_config_userconfig ?? process.env.NPM_CONFIG_USERCONFIG;
52126
52518
  const home = (process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME) ?? homedir15();
52127
- const userConfig = explicitUserConfig ?? join25(home, ".npmrc");
52519
+ const userConfig = explicitUserConfig ?? join26(home, ".npmrc");
52128
52520
  if (!scoped && !visited.has(userConfig)) {
52129
52521
  const settings = await readRegistrySettings(userConfig, explicitUserConfig !== undefined);
52130
52522
  scoped = settings["@cortexkit:registry"];
@@ -52146,14 +52538,14 @@ function validateRegistry(registry) {
52146
52538
  }
52147
52539
  var reportedRegistryFailures = new Set;
52148
52540
  function reportRegistryFailure(directory) {
52149
- const key = resolve15(directory);
52541
+ const key = resolve17(directory);
52150
52542
  if (reportedRegistryFailures.has(key))
52151
52543
  return;
52152
52544
  reportedRegistryFailures.add(key);
52153
52545
  debug2("[auto-update-checker] Configured npm registry could not be resolved or used; skipping update check.");
52154
52546
  }
52155
52547
  function resolveRegistry(directory) {
52156
- const key = resolve15(directory);
52548
+ const key = resolve17(directory);
52157
52549
  let pending = registryCache.get(key);
52158
52550
  if (!pending) {
52159
52551
  pending = (async () => {
@@ -52210,10 +52602,10 @@ async function getLatestVersion(channel = "latest", options = {}) {
52210
52602
  var pendingSnapshots = new Map;
52211
52603
  var quarantinedInstallDirs = new Set;
52212
52604
  function createAutoUpdateSnapshot(installDir, packageJsonPath, packageName) {
52213
- const packageDir = join26(installDir, "node_modules", packageName);
52214
- const lockfilePath = join26(installDir, "package-lock.json");
52215
- const tempDir = mkdtempSync(join26(tmpdir4(), "aft-auto-update-"));
52216
- const stagedPackageDir = existsSync19(packageDir) ? join26(tempDir, "package") : null;
52605
+ const packageDir = join27(installDir, "node_modules", packageName);
52606
+ const lockfilePath = join27(installDir, "package-lock.json");
52607
+ const tempDir = mkdtempSync(join27(tmpdir4(), "aft-auto-update-"));
52608
+ const stagedPackageDir = existsSync19(packageDir) ? join27(tempDir, "package") : null;
52217
52609
  if (stagedPackageDir)
52218
52610
  cpSync(packageDir, stagedPackageDir, { recursive: true });
52219
52611
  return {
@@ -52249,12 +52641,12 @@ function stripPackageNameFromPath(pathValue, packageName) {
52249
52641
  for (const segment of [...packageName.split("/")].reverse()) {
52250
52642
  if (basename5(current) !== segment)
52251
52643
  return null;
52252
- current = dirname14(current);
52644
+ current = dirname15(current);
52253
52645
  }
52254
52646
  return current;
52255
52647
  }
52256
52648
  function removeFromPackageLock(installDir, packageName) {
52257
- const lockPath = join26(installDir, "package-lock.json");
52649
+ const lockPath = join27(installDir, "package-lock.json");
52258
52650
  if (!existsSync19(lockPath))
52259
52651
  return false;
52260
52652
  try {
@@ -52310,7 +52702,7 @@ function restorePendingSnapshot(installDir) {
52310
52702
  restoreAutoUpdateSnapshot(snapshot);
52311
52703
  }
52312
52704
  function removeInstalledPackage(installDir, packageName) {
52313
- const packageDir = join26(installDir, "node_modules", packageName);
52705
+ const packageDir = join27(installDir, "node_modules", packageName);
52314
52706
  if (!existsSync19(packageDir))
52315
52707
  return false;
52316
52708
  rmSync7(packageDir, { recursive: true, force: true });
@@ -52319,18 +52711,18 @@ function removeInstalledPackage(installDir, packageName) {
52319
52711
  }
52320
52712
  function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
52321
52713
  if (runtimePackageJsonPath) {
52322
- const packageDir = dirname14(runtimePackageJsonPath);
52714
+ const packageDir = dirname15(runtimePackageJsonPath);
52323
52715
  const nodeModulesDir = stripPackageNameFromPath(packageDir, PACKAGE_NAME);
52324
52716
  if (nodeModulesDir && basename5(nodeModulesDir) === "node_modules") {
52325
- const installDir = dirname14(nodeModulesDir);
52326
- const packageJsonPath = join26(installDir, "package.json");
52717
+ const installDir = dirname15(nodeModulesDir);
52718
+ const packageJsonPath = join27(installDir, "package.json");
52327
52719
  if (existsSync19(packageJsonPath))
52328
52720
  return { installDir, packageJsonPath };
52329
52721
  }
52330
52722
  return null;
52331
52723
  }
52332
- const cacheRoot = dirname14(cacheDir());
52333
- const legacyPackageJsonPath = join26(cacheRoot, "package.json");
52724
+ const cacheRoot = dirname15(cacheDir());
52725
+ const legacyPackageJsonPath = join27(cacheRoot, "package.json");
52334
52726
  if (existsSync19(legacyPackageJsonPath)) {
52335
52727
  return { installDir: cacheRoot, packageJsonPath: legacyPackageJsonPath };
52336
52728
  }
@@ -52532,19 +52924,19 @@ function claimCheckSlot(storageDir, intervalMs, testHooks = {}) {
52532
52924
  try {
52533
52925
  if (hasRecentCheckTimestamp(file, intervalMs))
52534
52926
  return null;
52535
- mkdirSync8(dirname15(file), { recursive: true });
52927
+ mkdirSync8(dirname16(file), { recursive: true });
52536
52928
  const lockPath = `${file}.lock`;
52537
52929
  const owner = { pid: process.pid, startedMs: Date.now(), token: randomUUID4() };
52538
52930
  let lockFd = null;
52539
52931
  try {
52540
- lockFd = openSync11(lockPath, "wx");
52932
+ lockFd = openSync12(lockPath, "wx");
52541
52933
  writeFileSync11(lockFd, JSON.stringify(owner));
52542
- closeSync12(lockFd);
52934
+ closeSync13(lockFd);
52543
52935
  lockFd = null;
52544
52936
  } catch (err) {
52545
52937
  if (lockFd !== null) {
52546
52938
  try {
52547
- closeSync12(lockFd);
52939
+ closeSync13(lockFd);
52548
52940
  } catch {}
52549
52941
  }
52550
52942
  if (err.code !== "EEXIST")
@@ -52562,7 +52954,7 @@ function claimCheckSlot(storageDir, intervalMs, testHooks = {}) {
52562
52954
  return null;
52563
52955
  }
52564
52956
  try {
52565
- lockFd = openSync11(lockPath, "wx");
52957
+ lockFd = openSync12(lockPath, "wx");
52566
52958
  } catch (claimError) {
52567
52959
  if (claimError.code === "EEXIST")
52568
52960
  return null;
@@ -52571,11 +52963,11 @@ function claimCheckSlot(storageDir, intervalMs, testHooks = {}) {
52571
52963
  try {
52572
52964
  writeFileSync11(lockFd, JSON.stringify(owner));
52573
52965
  } finally {
52574
- closeSync12(lockFd);
52966
+ closeSync13(lockFd);
52575
52967
  lockFd = null;
52576
52968
  }
52577
52969
  } finally {
52578
- closeSync12(reclaimFd);
52970
+ closeSync13(reclaimFd);
52579
52971
  releaseCheckLock(reclaimPath, owner);
52580
52972
  }
52581
52973
  }
@@ -52658,12 +53050,12 @@ function claimObservedCheckLock(lockPath, observed, testHooks = {}) {
52658
53050
  return true;
52659
53051
  }
52660
53052
  function writeReclaimGuard(reclaimPath, owner) {
52661
- const fd = openSync11(reclaimPath, "wx");
53053
+ const fd = openSync12(reclaimPath, "wx");
52662
53054
  try {
52663
53055
  writeFileSync11(fd, JSON.stringify(owner));
52664
53056
  return fd;
52665
53057
  } catch (error) {
52666
- closeSync12(fd);
53058
+ closeSync13(fd);
52667
53059
  throw error;
52668
53060
  }
52669
53061
  }
@@ -52690,14 +53082,14 @@ function readCheckLockState(lockPath) {
52690
53082
  let content;
52691
53083
  try {
52692
53084
  const observed = statSync17(lockPath, { bigint: true });
52693
- const fd = openSync11(lockPath, "r");
53085
+ const fd = openSync12(lockPath, "r");
52694
53086
  try {
52695
- info = fstatSync3(fd, { bigint: true });
53087
+ info = fstatSync4(fd, { bigint: true });
52696
53088
  if (info.dev !== observed.dev || info.ino !== observed.ino)
52697
53089
  return null;
52698
53090
  content = readFileSync17(fd, "utf-8");
52699
53091
  } finally {
52700
- closeSync12(fd);
53092
+ closeSync13(fd);
52701
53093
  }
52702
53094
  } catch (error) {
52703
53095
  if (error.code === "ENOENT")
@@ -52847,10 +53239,10 @@ function showToast(ctx, title, message, variant = "info", duration = 3000) {
52847
53239
  }
52848
53240
 
52849
53241
  // src/plugin-version.ts
52850
- import { createRequire as createRequire2 } from "node:module";
53242
+ import { createRequire as createRequire3 } from "node:module";
52851
53243
  var PLUGIN_PACKAGE_NAME = "@cortexkit/aft-opencode";
52852
53244
  function resolvePluginVersion(importMetaUrl) {
52853
- const req = createRequire2(importMetaUrl);
53245
+ const req = createRequire3(importMetaUrl);
52854
53246
  for (const candidate of ["../package.json", "../../package.json", "../../../package.json"]) {
52855
53247
  try {
52856
53248
  const manifest = req(candidate);
@@ -52956,16 +53348,16 @@ import {
52956
53348
  writeFileSync as writeFileSync12
52957
53349
  } from "node:fs";
52958
53350
  import { createServer } from "node:http";
52959
- import { dirname as dirname16, join as join28 } from "node:path";
53351
+ import { dirname as dirname17, join as join29 } from "node:path";
52960
53352
 
52961
53353
  // src/shared/rpc-utils.ts
52962
- import { join as join27 } from "node:path";
53354
+ import { join as join28 } from "node:path";
52963
53355
  function projectHash(directory) {
52964
53356
  return projectRootKeyHash(directory);
52965
53357
  }
52966
53358
  function rpcPortFileDir(storageDir, directory) {
52967
53359
  const hash = projectHash(directory);
52968
- return join27(storageDir, "rpc", hash, "ports");
53360
+ return join28(storageDir, "rpc", hash, "ports");
52969
53361
  }
52970
53362
  function isPidAlive(pid) {
52971
53363
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
@@ -53042,7 +53434,7 @@ class AftRpcServer {
53042
53434
  constructor(storageDir, directory) {
53043
53435
  this.portsDir = rpcPortFileDir(storageDir, directory);
53044
53436
  this.instanceId = randomBytes5(8).toString("hex");
53045
- this.portFilePath = join28(this.portsDir, `${this.instanceId}.json`);
53437
+ this.portFilePath = join29(this.portsDir, `${this.instanceId}.json`);
53046
53438
  }
53047
53439
  handle(method, handler) {
53048
53440
  this.handlers.set(method, handler);
@@ -53119,7 +53511,7 @@ class AftRpcServer {
53119
53511
  }
53120
53512
  }
53121
53513
  writePortFile() {
53122
- const dir = dirname16(this.portFilePath);
53514
+ const dir = dirname17(this.portFilePath);
53123
53515
  mkdirSync9(dir, { recursive: true, mode: 448 });
53124
53516
  const tmpPath = `${this.portFilePath}.tmp`;
53125
53517
  writeFileSync12(tmpPath, JSON.stringify({
@@ -53141,13 +53533,13 @@ class AftRpcServer {
53141
53533
  const temporary = entry.endsWith(".json.tmp");
53142
53534
  if (!temporary && !entry.endsWith(".json"))
53143
53535
  continue;
53144
- const filePath = join28(this.portsDir, entry);
53536
+ const filePath = join29(this.portsDir, entry);
53145
53537
  if (filePath === this.portFilePath)
53146
53538
  continue;
53147
53539
  try {
53148
53540
  const record = parseRpcPortRecord(readFileSync18(filePath, "utf-8"));
53149
53541
  if (record === null) {
53150
- if (!temporary || Date.now() - statSync18(join28(this.portsDir, entry)).mtimeMs >= UNREADABLE_TMP_MAX_AGE_MS) {
53542
+ if (!temporary || Date.now() - statSync18(join29(this.portsDir, entry)).mtimeMs >= UNREADABLE_TMP_MAX_AGE_MS) {
53151
53543
  unlinkSync7(filePath);
53152
53544
  }
53153
53545
  continue;
@@ -53455,9 +53847,6 @@ function readStatusBar(value) {
53455
53847
  const disabled = Array.isArray(bar.disabled_categories) ? bar.disabled_categories.filter((key) => typeof key === "string") : [];
53456
53848
  const errors = readOptionalNumber(bar.errors);
53457
53849
  const warnings = readOptionalNumber(bar.warnings);
53458
- const deadCode = readOptionalNumber(bar.dead_code);
53459
- const unusedExports = readOptionalNumber(bar.unused_exports);
53460
- const duplicates = readOptionalNumber(bar.duplicates);
53461
53850
  const todos = readOptionalNumber(bar.todos);
53462
53851
  const noLanguageServer = bar.diagnostics === "no_language_server";
53463
53852
  const producerMissing = bar.diagnostics === "producer_missing";
@@ -53466,18 +53855,14 @@ function readStatusBar(value) {
53466
53855
  producer: gap.producer,
53467
53856
  root: gap.root
53468
53857
  })) : [];
53469
- if (errors === null && warnings === null && deadCode === null && unusedExports === null && duplicates === null && todos === null && !noLanguageServer && !producerMissing && disabled.length === 0) {
53858
+ if (errors === null && warnings === null && todos === null && !noLanguageServer && !producerMissing && disabled.length === 0) {
53470
53859
  return;
53471
53860
  }
53472
53861
  return {
53473
53862
  ...disabled.length > 0 ? { disabled_categories: disabled } : {},
53474
53863
  ...errors !== null ? { errors } : {},
53475
53864
  ...warnings !== null ? { warnings } : {},
53476
- ...deadCode !== null ? { dead_code: deadCode } : {},
53477
- ...unusedExports !== null ? { unused_exports: unusedExports } : {},
53478
- ...duplicates !== null ? { duplicates } : {},
53479
53865
  ...todos !== null ? { todos } : {},
53480
- ...bar.tier2_stale === true ? { tier2_stale: true } : {},
53481
53866
  ...noLanguageServer ? { diagnostics: "no_language_server" } : {},
53482
53867
  ...producerMissing ? { diagnostics: "producer_missing", diagnostics_gaps: diagnosticsGaps } : {}
53483
53868
  };
@@ -53671,13 +54056,10 @@ function formatStatusMarkdown(status) {
53671
54056
  const rows = [
53672
54057
  ["Errors", sb.errors],
53673
54058
  ["Warnings", sb.warnings],
53674
- ["Dead code", sb.dead_code],
53675
- ["Unused exports", sb.unused_exports],
53676
- ["Duplicates", sb.duplicates],
53677
54059
  ["TODOs", sb.todos]
53678
54060
  ].filter((row) => typeof row[1] === "number");
53679
54061
  if (rows.length > 0) {
53680
- lines.push("", `### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`);
54062
+ lines.push("", "### Code Health");
53681
54063
  for (const [label, value] of rows)
53682
54064
  lines.push(`- **${label}:** ${formatCount(value)}`);
53683
54065
  }
@@ -53848,15 +54230,15 @@ function buildWorkflowHints(opts) {
53848
54230
  `));
53849
54231
  }
53850
54232
  if (hasInspect) {
53851
- sections.push("**Codebase health & diagnostics**: AFT does not surface compile/type errors automatically after edits — pull them with `aft_inspect`. Run it after a batch of edits and before you run tests or commit, when starting in unfamiliar code, or before a refactor/review. One call summarizes diagnostics (compile/type errors), TODOs, metrics, dead code, unused exports, and duplicates; pass `sections` for focused drill-down and `scope` to actively pull diagnostics for a specific file or directory. Its diagnostics are a fast checkpoint, not the authority — a clean `tsc` / `cargo check` / `pyright` run is the real gate. Treat stale_categories/pending_categories as stale or incomplete cache state. AFT schedules a Tier-2 refresh after its next idle or inspect-triggered background run; use one later normal aft_inspect after that refresh, not a polling loop.");
53852
- sections.push("**AFT status bar**: tool results may end with a one-line health bar `[AFT E<errors> W<warnings> | D<dead-code> U<unused-exports> C<clone/dup-groups> | T<todos>]` — an IDE-style glance that appears when a count changes. `E`/`W` are live LSP diagnostics for files touched this session (your universal compile-error signal across every language with an LSP). A `~` before `D` means the dead-code/unused/dup counts predate your latest edit — run `aft_inspect` for current numbers and detail. A `?` in place of a number means that count has no value yet (not zero). When `E>0`, you likely just introduced errors; investigate before moving on.");
54233
+ sections.push("**Codebase health & diagnostics**: AFT does not surface compile/type errors automatically after edits — pull them with `aft_inspect`. Run it after a batch of edits and before you run tests or commit, when starting in unfamiliar code, or before a refactor/review. One call summarizes diagnostics (compile/type errors), TODOs, metrics, dead code, unused exports, and duplicates; pass `sections` for focused drill-down and `scope` to actively pull diagnostics for a specific file or directory. Its diagnostics are a fast checkpoint, not the authority — a clean `tsc` / `cargo check` / `pyright` run is the real gate. Dead code, unused exports, duplicates, cycles and complexity are computed only when you call aft_inspect, and the call waits until they are current; nothing refreshes them in the background, so run it again after further edits instead of polling.");
54234
+ sections.push("**AFT status bar**: tool results may end with a one-line health bar `[AFT E<errors> W<warnings> | T<todos>]` — an IDE-style glance that appears when a count changes. `E`/`W` are live LSP diagnostics for files touched this session (your universal compile-error signal across every language with an LSP). Dead code, unused exports and duplicates are not on the bar; run `aft_inspect` for them. A `?` in place of a number means that count has no value yet (not zero). When `E>0`, you likely just introduced errors; investigate before moving on.");
53853
54235
  }
53854
54236
  if (hasNavigate) {
53855
54237
  sections.push([
53856
54238
  "Use `aft_callgraph` for code-relationship questions instead of grep + read chains:",
53857
54239
  "- `callers` — find all call sites before changing a function signature",
53858
54240
  "- `impact` — blast radius (which functions/files will need updates)",
53859
- "- `trace_to` — how execution reaches this code from entry points (routes, exports, main)",
54241
+ "- `trace_to` — how execution reaches this code; each path runs back to a root labelled main, test, attribute, public API, or no caller found",
53860
54242
  "- `trace_to_symbol` — shortest call path from one symbol to another",
53861
54243
  "- `trace_data` — follow a value through assignments and parameters across files"
53862
54244
  ].join(`
@@ -53948,12 +54330,12 @@ function throwSentinel(command) {
53948
54330
  throw sentinel;
53949
54331
  }
53950
54332
  var PLUGIN_VERSION = resolvePluginVersion(import.meta.url);
53951
- var ANNOUNCEMENT_VERSION = "0.63.0";
54333
+ var ANNOUNCEMENT_VERSION = "0.64.0";
53952
54334
  var ANNOUNCEMENT_FEATURES = [
53953
- "Cap a shell command's total memory, background and terminal commands included, with `bash.memory_limit_mib`.",
53954
- "Shell results can list or diff the files a command changed: set `bash.changed_files` to `list` or `diff`.",
53955
- "Put rebuildable caches on another disk with `storage.cache_dir`.",
53956
- "Call graphs mark callback references and link constructors, Python edits keep their indentation, and many reported issues are fixed."
54335
+ "A new index store makes AFT much faster: call graphs build 26x faster, edits reach the call graph about 9x faster, dead-code checks run 4x faster, and the index takes 4x less disk and 3x less memory.",
54336
+ "All worktrees of a repository share one index, so a new worktree is ready in under a second. `npx @cortexkit/aft cache prune-legacy` lists the old index folders and can remove them.",
54337
+ "`trace_to` labels each root it reaches: main, test, attribute, public API, or no caller found.",
54338
+ "Dead code, unused exports, duplicates, cycles and complexity run only when `aft_inspect` is called; the status bar shows errors, warnings and TODOs."
53957
54339
  ];
53958
54340
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
53959
54341
  var plugin = async (input) => initializePluginForDirectory(input);
@@ -54164,13 +54546,11 @@ async function initializePluginForDirectory(input) {
54164
54546
  return result;
54165
54547
  };
54166
54548
  const rpcServer = new AftRpcServer(configOverrides.storage_dir, input.directory);
54167
- let clearInspectTier2Idle = () => {};
54168
54549
  let clearAnnouncementTimer = () => {};
54169
54550
  const shutdownCleanup = registerShutdownCleanup(async (reason) => {
54170
54551
  cancelPendingWakesForContext(ctx);
54171
54552
  autoUpdateAbort.abort();
54172
54553
  liveConfigReload.stop();
54173
- clearInspectTier2Idle();
54174
54554
  clearAnnouncementTimer();
54175
54555
  for (const unsubscribe of statusUnsubscribes) {
54176
54556
  try {
@@ -54304,22 +54684,6 @@ Install: ${getManualInstallHint()}`);
54304
54684
  if (hintsBlock) {
54305
54685
  log2(`Workflow hints injected (${hintsBlock.length} chars)`);
54306
54686
  }
54307
- const inspectTier2Idle = createInspectTier2IdleScheduler({
54308
- isEnabled: () => registeredTools.has("aft_inspect"),
54309
- idleMinutes: () => ctx.config.inspect?.tier2_idle_minutes,
54310
- warn: warn2,
54311
- run: async (sessionID) => {
54312
- const sessionDir = await getSessionDirectory(input.client, sessionID, input.directory) ?? input.directory;
54313
- if (!isProjectEnabled(sessionDir))
54314
- return;
54315
- const bridge = ctx.pool.getActiveBridgeForRoot(sessionDir) ?? ctx.pool.getBridge(sessionDir);
54316
- const response = await bridge.send("inspect_tier2_run", { session_id: sessionID });
54317
- if (response.success === false) {
54318
- warn2(response.message || "inspect_tier2_run failed");
54319
- }
54320
- }
54321
- });
54322
- clearInspectTier2Idle = () => inspectTier2Idle.clearAll();
54323
54687
  return {
54324
54688
  tool: allTools,
54325
54689
  "experimental.chat.system.transform": async (systemInput, output) => {
@@ -54343,13 +54707,16 @@ Install: ${getManualInstallHint()}`);
54343
54707
  const eventType = eventInput.event.type;
54344
54708
  observeOpenCodeBgNotificationEvent(eventInput.event);
54345
54709
  const sessionID = extractSessionID(eventInput.event.properties);
54710
+ if (eventType === "session.moved" && sessionID) {
54711
+ clearSessionDirectory(sessionID);
54712
+ return;
54713
+ }
54346
54714
  if (eventType === "session.created" && sessionID) {
54347
54715
  const sessionDir = await getSessionDirectory(input.client, sessionID, input.directory) ?? input.directory;
54348
54716
  observeFreshSessionStart(pool, sessionDir, sessionID, "new");
54349
54717
  }
54350
54718
  if (eventType === "session.deleted" && sessionID) {
54351
54719
  releaseSessionState(sessionID);
54352
- inspectTier2Idle.clear(sessionID);
54353
54720
  closeDeletedSessionRoutes(pool, sessionID, input.worktree ?? input.directory).catch(() => {});
54354
54721
  return;
54355
54722
  }
@@ -54357,7 +54724,6 @@ Install: ${getManualInstallHint()}`);
54357
54724
  return;
54358
54725
  if (!sessionID)
54359
54726
  return;
54360
- inspectTier2Idle.schedule(sessionID);
54361
54727
  const sessionDir = await getSessionDirectory(input.client, sessionID, input.directory) ?? input.directory;
54362
54728
  if (!isProjectEnabled(sessionDir))
54363
54729
  return;
@@ -54405,8 +54771,6 @@ Install: ${getManualInstallHint()}`);
54405
54771
  output.args = prepareOpenCodeArguments(toolInput.tool, output.args, {
54406
54772
  hashlineEffective: ctx.hashlineEffective
54407
54773
  });
54408
- if (toolInput.sessionID)
54409
- inspectTier2Idle.clear(toolInput.sessionID);
54410
54774
  },
54411
54775
  "command.execute.before": async (commandInput, _output) => {
54412
54776
  if (commandInput.command !== STATUS_COMMAND) {