@cortexkit/aft 0.58.2 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -109,8 +109,124 @@ var ACTIVE_LOGGER_SYMBOL;
109
109
  var init_active_logger = __esm(() => {
110
110
  ACTIVE_LOGGER_SYMBOL = Symbol.for("aft-bridge-active-logger");
111
111
  });
112
+ // ../aft-bridge/dist/path-display.js
113
+ import { homedir } from "node:os";
114
+ import { posix, win32 } from "node:path";
115
+ function shortenHomePath(path, home = homedir(), platform = process.platform) {
116
+ if (!home)
117
+ return path;
118
+ const normalize = (value) => platform === "win32" ? value.replace(/\\/g, "/").toLowerCase() : value;
119
+ const base = normalize(home).replace(/\/+$/, "");
120
+ const target = normalize(path);
121
+ if (target === normalize(home) || target === base)
122
+ return "~";
123
+ return target.startsWith(`${base}/`) ? `~${path.slice(base.length)}` : path;
124
+ }
125
+ function relativePathEscapesRoot(rel, platform = process.platform) {
126
+ return rel === ".." || rel.startsWith("../") || platform === "win32" && rel.startsWith("..\\") || (platform === "win32" ? win32.isAbsolute(rel) : posix.isAbsolute(rel));
127
+ }
128
+ var init_path_display = () => {};
129
+
112
130
  // ../aft-bridge/dist/bash-hints.js
113
- var init_bash_hints = () => {};
131
+ var init_bash_hints = __esm(() => {
132
+ init_path_display();
133
+ });
134
+
135
+ // ../aft-bridge/dist/test-child-environment.js
136
+ import { mkdirSync, realpathSync } from "node:fs";
137
+ import { homedir as homedir2, tmpdir } from "node:os";
138
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
139
+ function toolchainHomes(inherited) {
140
+ const global = globalThis;
141
+ if (!global[TOOLCHAINS]) {
142
+ const home = process.platform === "win32" ? inherited.USERPROFILE || inherited.HOME || homedir2() : inherited.HOME || homedir2();
143
+ global[TOOLCHAINS] = {
144
+ RUSTUP_HOME: inherited.RUSTUP_HOME || join(home, ".rustup"),
145
+ CARGO_HOME: inherited.CARGO_HOME || join(home, ".cargo")
146
+ };
147
+ }
148
+ return global[TOOLCHAINS];
149
+ }
150
+ function createdRoots() {
151
+ const global = globalThis;
152
+ return global[ROOTS] ??= new Set;
153
+ }
154
+ function isolatedAftEnvironment(root, inherited = process.env) {
155
+ const env = { ...inherited };
156
+ const toolchains = toolchainHomes(inherited);
157
+ env.RUSTUP_HOME ||= toolchains.RUSTUP_HOME;
158
+ env.CARGO_HOME ||= toolchains.CARGO_HOME;
159
+ const names = [
160
+ "home",
161
+ "home",
162
+ "local",
163
+ "config",
164
+ "data",
165
+ "state",
166
+ "cache",
167
+ "runtime",
168
+ "storage",
169
+ "aft-cache"
170
+ ];
171
+ for (const [index, key] of DIRECTORIES.entries()) {
172
+ env[key] = join(root, names[index]);
173
+ mkdirSync(env[key], { recursive: true });
174
+ }
175
+ delete env.AFT_ALLOW_PRODUCTION_MIGRATION;
176
+ createdRoots().add(resolve(root));
177
+ return env;
178
+ }
179
+ function canonical(path) {
180
+ let ancestor = resolve(path);
181
+ const tail = [];
182
+ while (true) {
183
+ try {
184
+ return join(realpathSync(ancestor), ...tail);
185
+ } catch {
186
+ const parent = dirname(ancestor);
187
+ if (parent === ancestor)
188
+ return resolve(path);
189
+ tail.unshift(relative(parent, ancestor));
190
+ ancestor = parent;
191
+ }
192
+ }
193
+ }
194
+ function within(path, root) {
195
+ const tail = relative(canonical(root), canonical(path));
196
+ return tail === "" || !tail.startsWith("..") && !isAbsolute(tail);
197
+ }
198
+ function testChildEnvironment(env) {
199
+ const root = process.env.AFT_TEST_ISOLATION_ROOT;
200
+ if (!root)
201
+ return env;
202
+ const fallback = isolatedAftEnvironment(root, env);
203
+ for (const key of DIRECTORIES) {
204
+ const value = env[key];
205
+ if (value && ([...createdRoots()].some((created) => within(value, created)) || within(value, tmpdir()))) {
206
+ mkdirSync(value, { recursive: true });
207
+ fallback[key] = value;
208
+ }
209
+ }
210
+ fallback.AFT_TEST_ISOLATION_ROOT = root;
211
+ return fallback;
212
+ }
213
+ var DIRECTORIES, ROOTS, TOOLCHAINS;
214
+ var init_test_child_environment = __esm(() => {
215
+ DIRECTORIES = [
216
+ "HOME",
217
+ "USERPROFILE",
218
+ "LOCALAPPDATA",
219
+ "XDG_CONFIG_HOME",
220
+ "XDG_DATA_HOME",
221
+ "XDG_STATE_HOME",
222
+ "XDG_CACHE_HOME",
223
+ "XDG_RUNTIME_DIR",
224
+ "AFT_STORAGE_DIR",
225
+ "AFT_CACHE_DIR"
226
+ ];
227
+ ROOTS = Symbol.for("cortexkit.aft.created-test-child-roots");
228
+ TOOLCHAINS = Symbol.for("cortexkit.aft.test-child-toolchain-homes");
229
+ });
114
230
 
115
231
  // ../aft-bridge/dist/child-process.js
116
232
  import { execFile as nodeExecFile, execFileSync as nodeExecFileSync, execSync as nodeExecSync, spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
@@ -130,10 +246,19 @@ function withWindowsHidden(args, takesArgv) {
130
246
  return out;
131
247
  }
132
248
  function hidden(resolve, takesArgv) {
133
- return (...args) => resolve()(...withWindowsHidden(args, takesArgv));
249
+ return (...args) => {
250
+ const out = withWindowsHidden(args, takesArgv);
251
+ if (process.env.AFT_TEST_ISOLATION_ROOT) {
252
+ const index = takesArgv && (Array.isArray(out[1]) || out[1] == null && out.length > 2) ? 2 : 1;
253
+ const options = out[index];
254
+ options.env = testChildEnvironment(options.env ?? process.env);
255
+ }
256
+ return resolve()(...out);
257
+ };
134
258
  }
135
259
  var HIDDEN, spawn, spawnSync, execFile, execFileSync, execSync;
136
260
  var init_child_process = __esm(() => {
261
+ init_test_child_environment();
137
262
  HIDDEN = { windowsHide: true };
138
263
  spawn = hidden(() => nodeSpawn, true);
139
264
  spawnSync = hidden(() => nodeSpawnSync, true);
@@ -165,8 +290,8 @@ function withPathPrepended(env, dir, platform = process.platform) {
165
290
  }
166
291
 
167
292
  // ../aft-bridge/dist/storage-paths.js
168
- import { homedir, tmpdir } from "node:os";
169
- import { join, resolve } from "node:path";
293
+ import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
294
+ import { join as join2, resolve as resolve2 } from "node:path";
170
295
  function environmentValue(context, name) {
171
296
  const value = (context.lookup ?? ((key) => process.env[key]))(name);
172
297
  return value !== undefined && value.length > 0 ? value : undefined;
@@ -176,7 +301,7 @@ function storagePlatform(context) {
176
301
  }
177
302
  function homeDir(context) {
178
303
  const configured = storagePlatform(context) === "windows" ? environmentValue(context, "USERPROFILE") ?? environmentValue(context, "HOME") : environmentValue(context, "HOME") ?? environmentValue(context, "USERPROFILE");
179
- return configured ?? context.fallbackHome ?? homedir();
304
+ return configured ?? context.fallbackHome ?? homedir3();
180
305
  }
181
306
  function resolveDataHome(context = {}) {
182
307
  const xdg = environmentValue(context, "XDG_DATA_HOME");
@@ -188,21 +313,21 @@ function resolveDataHome(context = {}) {
188
313
  return localAppData;
189
314
  const userProfile = environmentValue(context, "USERPROFILE");
190
315
  if (userProfile)
191
- return join(userProfile, "AppData", "Local");
316
+ return join2(userProfile, "AppData", "Local");
192
317
  }
193
318
  const home = environmentValue(context, "HOME");
194
319
  if (home)
195
- return join(home, ".local", "share");
196
- return join(".local", "share");
320
+ return join2(home, ".local", "share");
321
+ return join2(".local", "share");
197
322
  }
198
323
  function resolveStoragePath(raw, context = {}) {
199
324
  let expanded = raw;
200
325
  if (raw === "~") {
201
326
  expanded = homeDir(context);
202
327
  } else if (raw.startsWith("~/") || raw.startsWith("~\\")) {
203
- expanded = join(homeDir(context), raw.slice(2));
328
+ expanded = join2(homeDir(context), raw.slice(2));
204
329
  }
205
- return resolve(context.currentDirectory ?? process.cwd(), expanded);
330
+ return resolve2(context.currentDirectory ?? process.cwd(), expanded);
206
331
  }
207
332
  function resolveCortexKitStorageRoot(context = {}) {
208
333
  const override = environmentValue(context, "AFT_STORAGE_DIR");
@@ -210,8 +335,8 @@ function resolveCortexKitStorageRoot(context = {}) {
210
335
  return resolveStoragePath(override, context);
211
336
  const legacyCache = environmentValue(context, "AFT_CACHE_DIR");
212
337
  if (legacyCache)
213
- return join(resolveStoragePath(legacyCache, context), "aft");
214
- return resolveStoragePath(join(resolveDataHome(context), "cortexkit", "aft"), context);
338
+ return join2(resolveStoragePath(legacyCache, context), "aft");
339
+ return resolveStoragePath(join2(resolveDataHome(context), "cortexkit", "aft"), context);
215
340
  }
216
341
  function resolveAftStorageRoot(configuredRoot, context = {}) {
217
342
  if (environmentValue(context, "AFT_STORAGE_DIR")) {
@@ -222,14 +347,14 @@ function resolveAftStorageRoot(configuredRoot, context = {}) {
222
347
  return resolveCortexKitStorageRoot(context);
223
348
  }
224
349
  function resolveAftLogPath(filename, configuredRoot, context = {}) {
225
- return join(resolveAftStorageRoot(configuredRoot, context), "logs", filename);
350
+ return join2(resolveAftStorageRoot(configuredRoot, context), "logs", filename);
226
351
  }
227
352
  function isTestEnvironment(context = {}) {
228
353
  return environmentValue(context, "BUN_TEST") === "1" || environmentValue(context, "NODE_ENV") === "test";
229
354
  }
230
355
  function resolvePluginLogPath(context = {}) {
231
356
  if (isTestEnvironment(context)) {
232
- return join(environmentValue(context, "TMPDIR") ?? tmpdir(), "aft-plugin-test.log");
357
+ return join2(environmentValue(context, "TMPDIR") ?? tmpdir2(), `aft-plugin-tests-${process.pid}`, "logs", "aft-plugin-test.log");
233
358
  }
234
359
  return resolveAftLogPath("aft-plugin.log", undefined, context);
235
360
  }
@@ -246,7 +371,7 @@ var init_bash_host_fallback = __esm(() => {
246
371
 
247
372
  // ../aft-bridge/dist/binary-identity.js
248
373
  import { createHash } from "node:crypto";
249
- import { createReadStream, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
374
+ import { closeSync, createReadStream, openSync, readFileSync, readSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
250
375
  function bareVersion(version) {
251
376
  return version.startsWith("v") ? version.slice(1) : version;
252
377
  }
@@ -311,7 +436,7 @@ function writeSidecarAtomically(binaryPath, identity) {
311
436
  const tmp = `${sidecar}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
312
437
  try {
313
438
  writeFileSync(tmp, `${JSON.stringify(identity)}
314
- `, "utf8");
439
+ `, { encoding: "utf8", mode: 384 });
315
440
  if (process.platform === "win32") {
316
441
  try {
317
442
  unlinkSync(sidecar);
@@ -428,12 +553,50 @@ function peekBinaryContentHash(binaryPath) {
428
553
  binaryContentHash(binaryPath);
429
554
  return null;
430
555
  }
431
- var SIDECAR_SCHEMA = 1, pendingIdentityWrites, contentHashCache, contentHashInFlight;
556
+ function digestStamp(path) {
557
+ const s = statSync(path, { bigint: true });
558
+ return `${s.dev}:${s.ino}:${s.size}:${s.mtimeNs}:${s.ctimeNs}`;
559
+ }
560
+ function readStampedFileDigest(path) {
561
+ try {
562
+ const value = JSON.parse(readFileSync(`${path}.digest.json`, "utf8"));
563
+ return value.schema === 1 && value.stamp === digestStamp(path) && typeof value.sha256 === "string" && /^[a-f0-9]{64}$/.test(value.sha256) ? value.sha256 : null;
564
+ } catch {
565
+ return null;
566
+ }
567
+ }
568
+ function writeStampedFileDigest(path, sha256, verifiedStamp) {
569
+ const sidecar = `${path}.digest.json`;
570
+ const tmp = `${sidecar}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
571
+ try {
572
+ writeFileSync(tmp, JSON.stringify({ schema: 1, stamp: verifiedStamp ?? digestStamp(path), sha256 }), { mode: 384 });
573
+ renameSync(tmp, sidecar);
574
+ } catch {} finally {
575
+ try {
576
+ unlinkSync(tmp);
577
+ } catch {}
578
+ }
579
+ }
580
+ async function cachedFileSha256(path) {
581
+ const known = readStampedFileDigest(path);
582
+ if (known)
583
+ return known;
584
+ const before = digestStamp(path);
585
+ digestWork.asyncHashes += 1;
586
+ digestWork.bytesHashed += Number(statSync(path).size);
587
+ const digest = await sha256File(path);
588
+ if (digestStamp(path) !== before)
589
+ throw new Error(`File changed while hashing: ${path}`);
590
+ writeStampedFileDigest(path, digest, before);
591
+ return digest;
592
+ }
593
+ var SIDECAR_SCHEMA = 1, pendingIdentityWrites, contentHashCache, contentHashInFlight, digestWork;
432
594
  var init_binary_identity = __esm(() => {
433
595
  init_active_logger();
434
596
  pendingIdentityWrites = new Set;
435
597
  contentHashCache = new Map;
436
598
  contentHashInFlight = new Map;
599
+ digestWork = { syncHashes: 0, asyncHashes: 0, bytesHashed: 0 };
437
600
  });
438
601
 
439
602
  // ../aft-bridge/dist/command-timeouts.js
@@ -446,11 +609,11 @@ var init_command_timeouts = __esm(() => {
446
609
  });
447
610
 
448
611
  // ../aft-bridge/dist/transport.js
449
- var WORKER_SESSION_FIELD = "worker_session";
612
+ var WORKER_SESSION_FIELD = "worker_session", HOST_TOOL_NAMES_FIELD = "host_tool_names";
450
613
 
451
614
  // ../aft-bridge/dist/bridge.js
452
- import { homedir as homedir2 } from "node:os";
453
- import { join as join2 } from "node:path";
615
+ import { homedir as homedir4 } from "node:os";
616
+ import { join as join3 } from "node:path";
454
617
  import { StringDecoder } from "node:string_decoder";
455
618
  function isTerminalBashStatus(status) {
456
619
  return typeof status === "string" && TERMINAL_BASH_STATUSES.has(status);
@@ -538,14 +701,13 @@ function coerceConfigureDroppedKeys(value) {
538
701
  }
539
702
  return dropped;
540
703
  }
541
- var DEFAULT_BRIDGE_TIMEOUT_MS = 30000, BRIDGE_HANG_TIMEOUT_THRESHOLD = 2, MAX_STDOUT_BUFFER, STDOUT_BUFFER_COMPACT_THRESHOLD, HASHLINE_REGISTRATION_LOG_INTERVAL_MS = 60000, HASHLINE_REGISTRATION_LOG_STATE_LIMIT = 256, TERMINAL_BASH_STATUSES, binaryFingerprintReader, binaryFingerprintAsyncReader, BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE = "failed to parse processor information from /proc/cpuinfo", BridgeReplacedDuringVersionCheck, BridgeTransportTimeoutError, BridgeTransportUnavailableError, BridgeTransportUnknownOutcomeError, BinaryBridge;
704
+ var DEFAULT_BRIDGE_TIMEOUT_MS = 30000, BRIDGE_HANG_TIMEOUT_THRESHOLD = 2, MAX_STDOUT_BUFFER, MALFORMED_STDOUT_LOG_CHARS = 512, HASHLINE_REGISTRATION_LOG_INTERVAL_MS = 60000, HASHLINE_REGISTRATION_LOG_STATE_LIMIT = 256, TERMINAL_BASH_STATUSES, binaryFingerprintReader, binaryFingerprintAsyncReader, BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE = "failed to parse processor information from /proc/cpuinfo", BridgeReplacedDuringVersionCheck, BridgeTransportTimeoutError, BridgeTransportUnavailableError, BridgeTransportUnknownOutcomeError, BinaryBridge;
542
705
  var init_bridge = __esm(() => {
543
706
  init_active_logger();
544
707
  init_binary_identity();
545
708
  init_child_process();
546
709
  init_command_timeouts();
547
710
  MAX_STDOUT_BUFFER = 64 * 1024 * 1024;
548
- STDOUT_BUFFER_COMPACT_THRESHOLD = 64 * 1024;
549
711
  TERMINAL_BASH_STATUSES = new Set([
550
712
  "completed",
551
713
  "failed",
@@ -599,11 +761,17 @@ var init_bridge = __esm(() => {
599
761
  lastBinaryFingerprintCheckAt = 0;
600
762
  _retiringDueToBinaryChange = false;
601
763
  pending = new Map;
764
+ activeSendCalls = 0;
765
+ processLoopReferenced = true;
602
766
  outstandingBackgroundTaskIds = new Set;
603
767
  nextId = 1;
604
768
  processGeneration = 0;
605
- stdoutBuffer = "";
606
- stdoutReadOffset = 0;
769
+ stdoutPending = [];
770
+ stdoutPendingLength = 0;
771
+ stdoutScannedChars = 0;
772
+ __stdoutScannedCharsForTests() {
773
+ return this.stdoutScannedChars;
774
+ }
607
775
  stderrBuffer = "";
608
776
  stderrTail = [];
609
777
  _restartCount = 0;
@@ -629,6 +797,7 @@ var init_bridge = __esm(() => {
629
797
  restartResetTimer = null;
630
798
  lastChildActivityAt = 0;
631
799
  consecutiveRequestTimeouts = 0;
800
+ timeoutRestartAwaitingRecovery = false;
632
801
  errorPrefix;
633
802
  logger;
634
803
  childEnv;
@@ -825,6 +994,32 @@ var init_bridge = __esm(() => {
825
994
  this.sessionLogVia(sessionId, `hashline registration carrier transport=ndjson phase=${phase} edit_slot_survives=${editSlotSurvives}${repeated}`);
826
995
  }
827
996
  async send(command, params = {}, options) {
997
+ this.activeSendCalls += 1;
998
+ this.syncEventLoopHold();
999
+ try {
1000
+ return await this.dispatchSend(command, params, options);
1001
+ } finally {
1002
+ this.activeSendCalls -= 1;
1003
+ this.syncEventLoopHold();
1004
+ }
1005
+ }
1006
+ syncEventLoopHold() {
1007
+ const child = this.process;
1008
+ if (!child)
1009
+ return;
1010
+ const hold = this.activeSendCalls > 0 || this.outstandingBackgroundTaskIds.size > 0;
1011
+ if (hold === this.processLoopReferenced)
1012
+ return;
1013
+ this.processLoopReferenced = hold;
1014
+ const handles = [child, child.stdin, child.stdout, child.stderr];
1015
+ for (const handle of handles) {
1016
+ if (hold)
1017
+ handle?.ref?.();
1018
+ else
1019
+ handle?.unref?.();
1020
+ }
1021
+ }
1022
+ async dispatchSend(command, params, options) {
828
1023
  let dispatchParams = params;
829
1024
  if (command === "configure") {
830
1025
  dispatchParams = { ...params };
@@ -862,17 +1057,19 @@ var init_bridge = __esm(() => {
862
1057
  params.edit_slot_survives = editSlotSurvives;
863
1058
  this.logHashlineRegistrationCarrier("tool_call", sessionId, editSlotSurvives);
864
1059
  }
865
- const { preview, workerSession, ...sendOptions } = options ?? {};
1060
+ const { preview, workerSession, hostToolNames, ...sendOptions } = options ?? {};
866
1061
  if (preview === true)
867
1062
  params.preview = true;
868
1063
  if (workerSession === true)
869
1064
  params[WORKER_SESSION_FIELD] = true;
1065
+ if (hostToolNames)
1066
+ params[HOST_TOOL_NAMES_FIELD] = hostToolNames;
870
1067
  return await this.send("tool_call", params, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
871
1068
  }
872
1069
  async sendWithVersionMismatchRetry(command, params, options, canRetryAfterVersionSwap) {
873
1070
  try {
874
1071
  if (this._retiringDueToBinaryChange) {
875
- throw new Error(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
1072
+ throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
876
1073
  }
877
1074
  if (this._shuttingDown) {
878
1075
  throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
@@ -935,7 +1132,12 @@ var init_bridge = __esm(() => {
935
1132
  if (command === "cancel_request" || Object.hasOwn(params, "command") || Object.hasOwn(params, "method")) {
936
1133
  const nested = { ...params };
937
1134
  const reserved = {};
938
- for (const key of ["session_id", "lsp_hints", WORKER_SESSION_FIELD]) {
1135
+ for (const key of [
1136
+ "session_id",
1137
+ "lsp_hints",
1138
+ WORKER_SESSION_FIELD,
1139
+ HOST_TOOL_NAMES_FIELD
1140
+ ]) {
939
1141
  if (Object.hasOwn(nested, key)) {
940
1142
  reserved[key] = nested[key];
941
1143
  delete nested[key];
@@ -947,7 +1149,7 @@ var init_bridge = __esm(() => {
947
1149
  }
948
1150
  const line = `${JSON.stringify(request)}
949
1151
  `;
950
- const keepBridgeOnTimeout = passive || options?.keepBridgeOnTimeout === true;
1152
+ const keepBridgeOnTimeout = passive || command === "bash_drain_completions" || options?.keepBridgeOnTimeout === true;
951
1153
  let requestSentAt = Date.now();
952
1154
  const child = this.process;
953
1155
  const response = await new Promise((resolve, reject) => {
@@ -971,7 +1173,8 @@ var init_bridge = __esm(() => {
971
1173
  const childActiveSinceRequest = this.lastChildActivityAt > requestSentAt;
972
1174
  const consecutiveTimeouts = this.consecutiveRequestTimeouts + 1;
973
1175
  this.consecutiveRequestTimeouts = consecutiveTimeouts;
974
- const keepWarm = childActiveSinceRequest || consecutiveTimeouts < this.hangThreshold;
1176
+ const restartSuppressed = this.timeoutRestartAwaitingRecovery;
1177
+ const keepWarm = restartSuppressed || childActiveSinceRequest || consecutiveTimeouts < this.hangThreshold;
975
1178
  const restartSuffix = keepWarm ? " — bridge kept warm" : " — restarting bridge";
976
1179
  const timeoutMsg = `Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms${restartSuffix}`;
977
1180
  if (requestSessionId) {
@@ -980,7 +1183,7 @@ var init_bridge = __esm(() => {
980
1183
  this.warnVia(timeoutMsg);
981
1184
  }
982
1185
  if (keepWarm) {
983
- entry.reject(new Error(`${this.errorPrefix} request "${command}" timed out after ${effectiveTimeoutMs}ms (bridge busy/under load); bridge kept warm — retry`));
1186
+ entry.reject(new Error(restartSuppressed ? `${this.errorPrefix} request "${command}" timed out after ${effectiveTimeoutMs}ms; automatic timeout restart already attempted; bridge kept warm to finish startup. Retry later or restart the host explicitly if it remains unresponsive. A timed-out mutation may still complete; inspect before repeating it.` : `${this.errorPrefix} request "${command}" timed out after ${effectiveTimeoutMs}ms (bridge busy/under load); bridge kept warm — retry`));
984
1187
  return;
985
1188
  }
986
1189
  entry.reject(new Error(`${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
@@ -1117,7 +1320,7 @@ var init_bridge = __esm(() => {
1117
1320
  this.spawnedBinaryFingerprint = null;
1118
1321
  this.clearRestartResetTimer();
1119
1322
  this.configureWarningClients.clear();
1120
- this.rejectAllPending(new Error(`${this.errorPrefix} Bridge shutting down`));
1323
+ this.rejectAllPending(new BridgeTransportUnknownOutcomeError(`${this.errorPrefix} Bridge shutting down`));
1121
1324
  if (this.process) {
1122
1325
  const proc = this.process;
1123
1326
  this.process = null;
@@ -1172,7 +1375,7 @@ var init_bridge = __esm(() => {
1172
1375
  this.lastBinaryFingerprintCheckAt = 0;
1173
1376
  this._retiringDueToBinaryChange = false;
1174
1377
  this.clearRestartResetTimer();
1175
- this.rejectAllPending(new Error(`${this.errorPrefix} Bridge restarting with updated binary: ${newBinaryPath}`));
1378
+ this.rejectAllPending(new BridgeTransportUnknownOutcomeError(`${this.errorPrefix} Bridge restarting with updated binary: ${newBinaryPath}`));
1176
1379
  if (!this.process)
1177
1380
  return;
1178
1381
  const proc = this.process;
@@ -1215,11 +1418,11 @@ var init_bridge = __esm(() => {
1215
1418
  })();
1216
1419
  const useFastembedBackend = semanticBackend === undefined || semanticBackend === "fastembed" || semanticBackend === "";
1217
1420
  const ortDir = typeof this.configOverrides._ort_dylib_dir === "string" && useFastembedBackend ? this.configOverrides._ort_dylib_dir : null;
1218
- const ortLibraryPath = ortDir == null ? null : join2(ortDir, this.platform === "win32" ? "onnxruntime.dll" : this.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
1421
+ const ortLibraryPath = ortDir == null ? null : join3(ortDir, this.platform === "win32" ? "onnxruntime.dll" : this.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
1219
1422
  const env = { ...process.env };
1220
1423
  this.logVia(`bridge.spawnProcess: useFastembedBackend=${useFastembedBackend}, ` + `parentORT=${process.env.ORT_DYLIB_PATH ?? "(unset)"}, ` + `ortLibraryPath=${ortLibraryPath ?? "(none)"}`);
1221
1424
  if (useFastembedBackend) {
1222
- env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join2(this.configOverrides.storage_dir, "semantic", "models") : join2(homedir2() || "", ".cache", "fastembed"));
1425
+ env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join3(this.configOverrides.storage_dir, "semantic", "models") : join3(homedir4() || "", ".cache", "fastembed"));
1223
1426
  if (process.env.ORT_DYLIB_PATH) {
1224
1427
  this.logVia(`ORT_DYLIB_PATH inherited from parent env: ${process.env.ORT_DYLIB_PATH}`);
1225
1428
  } else if (ortLibraryPath) {
@@ -1303,12 +1506,14 @@ var init_bridge = __esm(() => {
1303
1506
  this.processGeneration += 1;
1304
1507
  this.recordSpawnedBinaryFingerprint();
1305
1508
  this.lastBinaryFingerprintCheckAt = Date.now();
1306
- this.stdoutBuffer = "";
1307
- this.stdoutReadOffset = 0;
1509
+ this.stdoutPending = [];
1510
+ this.stdoutPendingLength = 0;
1308
1511
  this.stderrBuffer = "";
1309
1512
  this.lastChildActivityAt = 0;
1310
1513
  this.consecutiveRequestTimeouts = 0;
1311
1514
  this.stderrTail = [];
1515
+ this.processLoopReferenced = true;
1516
+ this.syncEventLoopHold();
1312
1517
  }
1313
1518
  pushStderrLine(line) {
1314
1519
  this.stderrTail.push(line);
@@ -1362,41 +1567,43 @@ var init_bridge = __esm(() => {
1362
1567
  ${tail}`;
1363
1568
  }
1364
1569
  onStdoutData(data) {
1365
- if (this.stdoutReadOffset > STDOUT_BUFFER_COMPACT_THRESHOLD) {
1366
- this.compactStdoutBuffer();
1367
- }
1368
- this.stdoutBuffer += data;
1369
- if (this.stdoutBuffer.length - this.stdoutReadOffset > MAX_STDOUT_BUFFER) {
1570
+ if (this.stdoutPendingLength + data.length > MAX_STDOUT_BUFFER) {
1370
1571
  this.handleCrash(new Error(`aft bridge stdout buffer exceeded ${MAX_STDOUT_BUFFER} bytes — killing bridge`));
1371
1572
  return;
1372
1573
  }
1373
- let newlineIdx;
1374
- while ((newlineIdx = this.stdoutBuffer.indexOf(`
1375
- `, this.stdoutReadOffset)) !== -1) {
1376
- const line = this.stdoutBuffer.slice(this.stdoutReadOffset, newlineIdx).trim();
1377
- this.stdoutReadOffset = newlineIdx + 1;
1574
+ this.stdoutScannedChars += data.length;
1575
+ const generation = this.processGeneration;
1576
+ let start = 0;
1577
+ let newlineIdx = data.indexOf(`
1578
+ `);
1579
+ while (newlineIdx !== -1) {
1580
+ let line = data.slice(start, newlineIdx);
1581
+ if (this.stdoutPending.length > 0) {
1582
+ this.stdoutPending.push(line);
1583
+ line = this.stdoutPending.join("");
1584
+ this.stdoutPending = [];
1585
+ this.stdoutPendingLength = 0;
1586
+ }
1587
+ start = newlineIdx + 1;
1588
+ line = line.trim();
1378
1589
  if (line) {
1379
1590
  this.processStdoutLine(line);
1591
+ if (this.processGeneration !== generation)
1592
+ return;
1380
1593
  }
1381
- if (this.stdoutReadOffset > STDOUT_BUFFER_COMPACT_THRESHOLD && this.stdoutReadOffset > this.stdoutBuffer.length / 2) {
1382
- this.compactStdoutBuffer();
1383
- }
1594
+ newlineIdx = data.indexOf(`
1595
+ `, start);
1384
1596
  }
1385
- if (this.stdoutReadOffset === this.stdoutBuffer.length) {
1386
- this.stdoutBuffer = "";
1387
- this.stdoutReadOffset = 0;
1597
+ if (start < data.length) {
1598
+ const rest = start === 0 ? data : data.slice(start);
1599
+ this.stdoutPending.push(rest);
1600
+ this.stdoutPendingLength += rest.length;
1388
1601
  }
1389
1602
  }
1390
- compactStdoutBuffer() {
1391
- if (this.stdoutReadOffset === 0)
1392
- return;
1393
- this.stdoutBuffer = this.stdoutBuffer.slice(this.stdoutReadOffset);
1394
- this.stdoutReadOffset = 0;
1395
- }
1396
1603
  flushStdoutBuffer() {
1397
- const line = this.stdoutBuffer.slice(this.stdoutReadOffset).trim();
1398
- this.stdoutBuffer = "";
1399
- this.stdoutReadOffset = 0;
1604
+ const line = this.stdoutPending.join("").trim();
1605
+ this.stdoutPending = [];
1606
+ this.stdoutPendingLength = 0;
1400
1607
  if (!line)
1401
1608
  return;
1402
1609
  this.processStdoutLine(line);
@@ -1433,6 +1640,7 @@ var init_bridge = __esm(() => {
1433
1640
  const taskId = bashTaskIdFrom(response);
1434
1641
  if (taskId)
1435
1642
  this.outstandingBackgroundTaskIds.delete(taskId);
1643
+ this.syncEventLoopHold();
1436
1644
  this.onBashCompletion?.(response, this);
1437
1645
  return;
1438
1646
  }
@@ -1463,6 +1671,17 @@ var init_bridge = __esm(() => {
1463
1671
  clearTimeout(entry.timer);
1464
1672
  entry.onSettled?.();
1465
1673
  this.consecutiveRequestTimeouts = 0;
1674
+ if (response.success !== false && ![
1675
+ "configure",
1676
+ "version",
1677
+ "status",
1678
+ "ping",
1679
+ "bash_drain_completions",
1680
+ "bash_ack_completions",
1681
+ "cancel_request"
1682
+ ].includes(entry.command)) {
1683
+ this.timeoutRestartAwaitingRecovery = false;
1684
+ }
1466
1685
  this.scheduleRestartCountReset();
1467
1686
  this.accountForBashTaskResponse(entry.command, response);
1468
1687
  entry.resolve(response);
@@ -1470,7 +1689,8 @@ var init_bridge = __esm(() => {
1470
1689
  this.logVia(`Ignoring unknown stdout push frame type: ${response.type}`);
1471
1690
  }
1472
1691
  } catch (_err) {
1473
- this.warnVia(`Failed to parse stdout line: ${line}`);
1692
+ const quoted = line.length > MALFORMED_STDOUT_LOG_CHARS ? `${line.slice(0, MALFORMED_STDOUT_LOG_CHARS)}… (${line.length} chars)` : line;
1693
+ this.warnVia(`Failed to parse stdout line: ${quoted}`);
1474
1694
  }
1475
1695
  }
1476
1696
  accountForBashTaskResponse(command, response) {
@@ -1487,6 +1707,7 @@ var init_bridge = __esm(() => {
1487
1707
  }
1488
1708
  handleTimeout(trigger, triggeringSessionId) {
1489
1709
  this.consecutiveRequestTimeouts = 0;
1710
+ this.timeoutRestartAwaitingRecovery = true;
1490
1711
  this.spawnedBinaryFingerprint = null;
1491
1712
  const abortedSiblings = Array.from(this.pending, ([requestId, entry]) => ({
1492
1713
  request_id: requestId,
@@ -1533,7 +1754,7 @@ var init_bridge = __esm(() => {
1533
1754
  const delay = 100 * 2 ** this._restartCount;
1534
1755
  this._restartCount++;
1535
1756
  this.logVia(`Auto-restart #${this._restartCount} in ${delay}ms`);
1536
- setTimeout(() => {
1757
+ const restartTimer = setTimeout(() => {
1537
1758
  if (!this._shuttingDown && !this.isAlive()) {
1538
1759
  try {
1539
1760
  this.spawnProcess();
@@ -1542,6 +1763,7 @@ var init_bridge = __esm(() => {
1542
1763
  }
1543
1764
  }
1544
1765
  }, delay);
1766
+ restartTimer.unref?.();
1545
1767
  this.scheduleRestartCountReset();
1546
1768
  } else {
1547
1769
  this.errorVia(`Max restarts (${this.maxRestarts}) reached, giving up. Logs: ${this.getLogFilePathVia()}${tail}`);
@@ -1562,6 +1784,7 @@ var init_bridge = __esm(() => {
1562
1784
  this._restartCount = 0;
1563
1785
  this.restartResetTimer = null;
1564
1786
  }, BinaryBridge.RESTART_RESET_MS);
1787
+ this.restartResetTimer.unref?.();
1565
1788
  }
1566
1789
  clearRestartResetTimer() {
1567
1790
  if (this.restartResetTimer) {
@@ -1573,55 +1796,57 @@ var init_bridge = __esm(() => {
1573
1796
  });
1574
1797
 
1575
1798
  // ../aft-bridge/dist/cache-paths.js
1576
- import { homedir as homedir3 } from "node:os";
1577
- import { join as join3 } from "node:path";
1799
+ import { homedir as homedir5 } from "node:os";
1800
+ import { join as join4 } from "node:path";
1578
1801
  function homeDir2(env) {
1579
- return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir3();
1802
+ return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir5();
1580
1803
  }
1581
- function getOpenCodeCacheRoot(env = process.env, home = homedir3()) {
1582
- return join3(env.XDG_CACHE_HOME || join3(home, ".cache"), "opencode");
1804
+ function getOpenCodeCacheRoot(env = process.env, home = homedir5()) {
1805
+ return join4(env.XDG_CACHE_HOME || join4(home, ".cache"), "opencode");
1583
1806
  }
1584
- function getOpenCodeConfigRoot(env = process.env, home = homedir3()) {
1585
- return join3(env.XDG_CONFIG_HOME || join3(home, ".config"), "opencode");
1807
+ function getOpenCodeConfigRoot(env = process.env, home = homedir5()) {
1808
+ return join4(env.XDG_CONFIG_HOME || join4(home, ".config"), "opencode");
1586
1809
  }
1587
1810
  function getAftCacheRoot(env = process.env) {
1588
1811
  if (env.AFT_CACHE_DIR)
1589
1812
  return env.AFT_CACHE_DIR;
1590
1813
  if (process.platform === "win32") {
1591
- const base = env.LOCALAPPDATA || env.APPDATA || join3(homeDir2(env), "AppData", "Local");
1592
- return join3(base, "aft");
1814
+ const base = env.LOCALAPPDATA || env.APPDATA || join4(homeDir2(env), "AppData", "Local");
1815
+ return join4(base, "aft");
1593
1816
  }
1594
- const base = env.XDG_CACHE_HOME || join3(homeDir2(env), ".cache");
1595
- return join3(base, "aft");
1817
+ const base = env.XDG_CACHE_HOME || join4(homeDir2(env), ".cache");
1818
+ return join4(base, "aft");
1596
1819
  }
1597
1820
  function getAftBinaryCacheDir(env = process.env) {
1598
- return join3(getAftCacheRoot(env), "bin");
1821
+ return join4(getAftCacheRoot(env), "bin");
1599
1822
  }
1600
1823
  function getAftLspPackagesDir(env = process.env) {
1601
- return join3(getAftCacheRoot(env), "lsp-packages");
1824
+ return join4(getAftCacheRoot(env), "lsp-packages");
1602
1825
  }
1603
1826
  function getAftLspBinariesDir(env = process.env) {
1604
- return join3(getAftCacheRoot(env), "lsp-binaries");
1827
+ return join4(getAftCacheRoot(env), "lsp-binaries");
1605
1828
  }
1606
1829
  var init_cache_paths = () => {};
1607
1830
 
1608
1831
  // ../aft-bridge/dist/callgraph-format.js
1609
- var init_callgraph_format = () => {};
1832
+ var init_callgraph_format = __esm(() => {
1833
+ init_path_display();
1834
+ });
1610
1835
  // ../aft-bridge/dist/config-error.js
1611
- import { homedir as homedir4 } from "node:os";
1612
- import { isAbsolute, join as join4 } from "node:path";
1836
+ import { homedir as homedir6 } from "node:os";
1837
+ import { isAbsolute as isAbsolute2, join as join5 } from "node:path";
1613
1838
  function formatConfigErrorMessage(detail) {
1614
1839
  const trimmed = detail.trim();
1615
1840
  const sentence = /[.!?]$/.test(trimmed) ? trimmed : `${trimmed}.`;
1616
1841
  return `${sentence} ${CONFIG_ERROR_RESTART_NOTE}`;
1617
1842
  }
1618
- function resolveSubcConnectionFilePath(raw, home = homedir4()) {
1843
+ function resolveSubcConnectionFilePath(raw, home = homedir6()) {
1619
1844
  const trimmed = raw.trim();
1620
1845
  if (trimmed.startsWith("~"))
1621
- return join4(home, trimmed.slice(1).replace(/^[/\\]/, ""));
1622
- if (isAbsolute(trimmed))
1846
+ return join5(home, trimmed.slice(1).replace(/^[/\\]/, ""));
1847
+ if (isAbsolute2(trimmed))
1623
1848
  return trimmed;
1624
- return join4(home, trimmed);
1849
+ return join5(home, trimmed);
1625
1850
  }
1626
1851
  function formatSubcConnectionMissingMessage(raw, resolved) {
1627
1852
  return `subc.connection_file is set to "${raw.trim()}" (resolved: ${resolved}) but no subc ` + `connection file exists there. Start the Subconscious daemon, correct the path, ` + `or remove subc.connection_file from your user config to use the standalone bridge.`;
@@ -1637,7 +1862,7 @@ var init_config_keys = () => {};
1637
1862
 
1638
1863
  // ../aft-bridge/dist/config-tiers.js
1639
1864
  import { existsSync, readFileSync as readFileSync2 } from "node:fs";
1640
- import { resolve as resolve2 } from "node:path";
1865
+ import { resolve as resolve3 } from "node:path";
1641
1866
  function readConfigTiers(opts) {
1642
1867
  const tiers = [];
1643
1868
  try {
@@ -1645,7 +1870,7 @@ function readConfigTiers(opts) {
1645
1870
  const doc = readFileSync2(opts.userConfigPath, "utf-8");
1646
1871
  tiers.push({
1647
1872
  tier: "user",
1648
- source: resolve2(opts.userConfigPath),
1873
+ source: resolve3(opts.userConfigPath),
1649
1874
  doc
1650
1875
  });
1651
1876
  }
@@ -1655,7 +1880,7 @@ function readConfigTiers(opts) {
1655
1880
  const doc = readFileSync2(opts.projectConfigPath, "utf-8");
1656
1881
  tiers.push({
1657
1882
  tier: "project",
1658
- source: resolve2(opts.projectConfigPath),
1883
+ source: resolve3(opts.projectConfigPath),
1659
1884
  doc
1660
1885
  });
1661
1886
  }
@@ -1757,9 +1982,9 @@ var init_version_probe = __esm(() => {
1757
1982
 
1758
1983
  // ../aft-bridge/dist/downloader.js
1759
1984
  import { createHash as createHash2, randomUUID } from "node:crypto";
1760
- import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync2, mkdirSync, openSync, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, rmSync, statSync as statSync2, unlinkSync as unlinkSync2, writeSync } from "node:fs";
1985
+ import { chmodSync, closeSync as closeSync2, copyFileSync, createWriteStream, existsSync as existsSync2, mkdirSync as mkdirSync2, openSync as openSync2, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, rmSync, statSync as statSync2, unlinkSync as unlinkSync2, writeSync } from "node:fs";
1761
1986
  import { hostname } from "node:os";
1762
- import { join as join5 } from "node:path";
1987
+ import { join as join6 } from "node:path";
1763
1988
  import { Readable } from "node:stream";
1764
1989
  import { pipeline } from "node:stream/promises";
1765
1990
  function expectedVersionFromTag(tag) {
@@ -1783,7 +2008,7 @@ function getBinaryName() {
1783
2008
  function getCachedBinaryPath(version) {
1784
2009
  if (!version)
1785
2010
  return null;
1786
- const binaryPath = join5(getAftBinaryCacheDir(), version, getBinaryName());
2011
+ const binaryPath = join6(getAftBinaryCacheDir(), version, getBinaryName());
1787
2012
  return existsSync2(binaryPath) ? binaryPath : null;
1788
2013
  }
1789
2014
  async function downloadBinary(version) {
@@ -1800,16 +2025,16 @@ async function downloadBinary(version) {
1800
2025
  return null;
1801
2026
  }
1802
2027
  const tag = rawTag.startsWith("v") ? rawTag : `v${rawTag}`;
1803
- const versionedCacheDir = join5(getAftBinaryCacheDir(), tag);
2028
+ const versionedCacheDir = join6(getAftBinaryCacheDir(), tag);
1804
2029
  const binaryName = getBinaryName();
1805
- const binaryPath = join5(versionedCacheDir, binaryName);
2030
+ const binaryPath = join6(versionedCacheDir, binaryName);
1806
2031
  if (existsSync2(binaryPath) && await isExpectedCachedBinary(binaryPath, tag)) {
1807
2032
  return binaryPath;
1808
2033
  }
1809
2034
  const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
1810
2035
  const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
1811
2036
  log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
1812
- const lockPath = join5(versionedCacheDir, ".download.lock");
2037
+ const lockPath = join6(versionedCacheDir, ".download.lock");
1813
2038
  let releaseLock = null;
1814
2039
  let binaryController = null;
1815
2040
  let checksumController = null;
@@ -1843,7 +2068,7 @@ async function downloadBinary(version) {
1843
2068
  process.once("exit", handleExit);
1844
2069
  try {
1845
2070
  if (!existsSync2(versionedCacheDir)) {
1846
- mkdirSync(versionedCacheDir, { recursive: true });
2071
+ mkdirSync2(versionedCacheDir, { recursive: true });
1847
2072
  }
1848
2073
  releaseLock = await acquireDownloadLock(lockPath);
1849
2074
  sweepStaleDownloadTemps(versionedCacheDir, binaryName);
@@ -2033,7 +2258,7 @@ function sweepStaleDownloadTemps(versionedCacheDir, binaryName) {
2033
2258
  if (!entry.isFile() || !entry.name.startsWith(tempPrefix) || !entry.name.endsWith(".tmp")) {
2034
2259
  continue;
2035
2260
  }
2036
- const tempPath = join5(versionedCacheDir, entry.name);
2261
+ const tempPath = join6(versionedCacheDir, entry.name);
2037
2262
  const ageMs = Date.now() - statSync2(tempPath).mtimeMs;
2038
2263
  if (Math.abs(ageMs) > DOWNLOAD_LOCK_STALE_MS)
2039
2264
  unlinkSync2(tempPath);
@@ -2048,11 +2273,11 @@ async function acquireDownloadLock(lockPath, timing = {}) {
2048
2273
  while (true) {
2049
2274
  try {
2050
2275
  const owner = createDownloadLockOwner();
2051
- const fd = openSync(lockPath, "wx");
2276
+ const fd = openSync2(lockPath, "wx");
2052
2277
  try {
2053
2278
  writeSync(fd, owner);
2054
2279
  } finally {
2055
- closeSync(fd);
2280
+ closeSync2(fd);
2056
2281
  }
2057
2282
  return () => {
2058
2283
  try {
@@ -2132,13 +2357,86 @@ var init_downloader = __esm(() => {
2132
2357
  ensureBinaryInFlight = new Map;
2133
2358
  });
2134
2359
 
2360
+ // ../aft-bridge/dist/private-storage.js
2361
+ 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";
2362
+ import { isAbsolute as isAbsolute3, join as join7, parse, relative as relative2, resolve as resolve4, sep } from "node:path";
2363
+ function privateMkdirSync(path, recursive = true) {
2364
+ mkdirSync3(path, {
2365
+ recursive,
2366
+ ...process.platform === "win32" ? {} : { mode: PRIVATE_DIRECTORY_MODE }
2367
+ });
2368
+ }
2369
+ function privateCopyFileSync(source, destination) {
2370
+ if (process.platform === "win32") {
2371
+ copyFileSync2(source, destination);
2372
+ return;
2373
+ }
2374
+ const input = openSync3(source, "r");
2375
+ let output;
2376
+ try {
2377
+ output = openSync3(destination, "wx", PRIVATE_FILE_MODE);
2378
+ const buffer = Buffer.allocUnsafe(64 * 1024);
2379
+ for (;; ) {
2380
+ const bytes = readSync2(input, buffer);
2381
+ if (bytes === 0)
2382
+ break;
2383
+ let offset = 0;
2384
+ while (offset < bytes)
2385
+ offset += writeSync2(output, buffer, offset, bytes - offset);
2386
+ }
2387
+ } finally {
2388
+ closeSync3(input);
2389
+ if (output !== undefined)
2390
+ closeSync3(output);
2391
+ }
2392
+ }
2393
+ function openPrivateStorageDir(root, path = root) {
2394
+ const base = resolve4(root);
2395
+ if (!root || base === parse(base).root) {
2396
+ throw new Error(`refusing filesystem root as private storage: ${base}`);
2397
+ }
2398
+ const rel = relative2(base, resolve4(path));
2399
+ if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute3(rel))
2400
+ return;
2401
+ privateMkdirSync(path);
2402
+ if (process.platform === "win32")
2403
+ return;
2404
+ let current = base;
2405
+ for (const component of ["", ...rel.split(sep).filter(Boolean)]) {
2406
+ current = join7(current, component);
2407
+ let fd;
2408
+ try {
2409
+ if (lstatSync(current).isSymbolicLink())
2410
+ return;
2411
+ fd = openSync3(current, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
2412
+ if ((fstatSync(fd).mode & 63) !== 0)
2413
+ fchmodSync(fd, PRIVATE_DIRECTORY_MODE);
2414
+ } catch (error) {
2415
+ if (!warned.has(current)) {
2416
+ warned.add(current);
2417
+ process.stderr.write(`[aft] could not tighten private storage ${current}: ${String(error)}; continuing
2418
+ `);
2419
+ }
2420
+ return;
2421
+ } finally {
2422
+ if (fd !== undefined)
2423
+ closeSync3(fd);
2424
+ }
2425
+ }
2426
+ }
2427
+ var PRIVATE_FILE_MODE = 384, PRIVATE_DIRECTORY_MODE = 448, warned;
2428
+ var init_private_storage = __esm(() => {
2429
+ warned = new Set;
2430
+ });
2431
+
2135
2432
  // ../aft-bridge/dist/durable-log.js
2136
2433
  var DEFAULT_LOG_BYTES;
2137
2434
  var init_durable_log = __esm(() => {
2435
+ init_private_storage();
2138
2436
  init_storage_paths();
2139
2437
  DEFAULT_LOG_BYTES = 32 * 1024 * 1024;
2140
2438
  });
2141
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/envelope.js
2439
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/envelope.js
2142
2440
  var MAX_FRAME_BODY_LEN, FrameType, FRAME_TYPE_MAX, Priority, AdmissionClass;
2143
2441
  var init_envelope = __esm(() => {
2144
2442
  MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
@@ -2169,7 +2467,7 @@ var init_envelope = __esm(() => {
2169
2467
  })(AdmissionClass || (AdmissionClass = {}));
2170
2468
  });
2171
2469
 
2172
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/socket.js
2470
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/socket.js
2173
2471
  var WRITE_BORROWED, WRITE_TRACKED_BORROWED;
2174
2472
  var init_socket = __esm(() => {
2175
2473
  init_envelope();
@@ -2177,47 +2475,84 @@ var init_socket = __esm(() => {
2177
2475
  WRITE_TRACKED_BORROWED = Symbol("subc.socket.writeTrackedBorrowed");
2178
2476
  });
2179
2477
 
2180
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/auth.js
2478
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/auth.js
2181
2479
  var init_auth = __esm(() => {
2182
2480
  init_socket();
2183
2481
  });
2184
2482
 
2185
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/connection-file.js
2483
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/connection-file.js
2186
2484
  var init_connection_file = __esm(() => {
2187
2485
  init_envelope();
2188
2486
  });
2189
2487
 
2190
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/route-handle.js
2488
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/launch-nonce.js
2489
+ var PROCESS_CELL_KEY, U64_MAX, I32_MAX, RedactedLaunchNonce;
2490
+ var init_launch_nonce = __esm(() => {
2491
+ PROCESS_CELL_KEY = Symbol.for("@cortexkit/subc-client/launch-nonce/v1");
2492
+ U64_MAX = (1n << 64n) - 1n;
2493
+ I32_MAX = 2 ** 31 - 1;
2494
+ RedactedLaunchNonce = class RedactedLaunchNonce {
2495
+ source;
2496
+ #value;
2497
+ constructor(value, source) {
2498
+ this.#value = value;
2499
+ this.source = source;
2500
+ Object.freeze(this);
2501
+ }
2502
+ get value() {
2503
+ return this.#value;
2504
+ }
2505
+ toJSON() {
2506
+ return { source: this.source };
2507
+ }
2508
+ [Symbol.for("nodejs.util.inspect.custom")]() {
2509
+ return `LaunchNonce { value: <${this.#value.length} bytes redacted>, source: "${this.source}" }`;
2510
+ }
2511
+ };
2512
+ });
2513
+
2514
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/route-handle.js
2191
2515
  var connectionToken, reverseRequests;
2192
2516
  var init_route_handle = __esm(() => {
2193
2517
  connectionToken = new WeakMap;
2194
2518
  reverseRequests = new WeakMap;
2195
2519
  });
2196
2520
 
2197
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/client.js
2521
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/client.js
2198
2522
  import { debuglog } from "node:util";
2199
- var debug, EMPTY_BODY;
2523
+ var debug, EMPTY_BODY, errorFrameFlags, SCOPE_ROUTE_CLOSE_REASONS, ROUTE_OPEN_ADMISSION_PRESSURE_REASONS;
2200
2524
  var init_client = __esm(() => {
2201
2525
  init_auth();
2202
2526
  init_connection_file();
2203
2527
  init_envelope();
2528
+ init_launch_nonce();
2204
2529
  init_route_handle();
2205
2530
  init_socket();
2531
+ init_launch_nonce();
2206
2532
  debug = debuglog("subc-client");
2207
2533
  EMPTY_BODY = new Uint8Array(0);
2534
+ errorFrameFlags = new WeakMap;
2535
+ SCOPE_ROUTE_CLOSE_REASONS = new Set([
2536
+ "scope_ended",
2537
+ "scope_carrier_removed",
2538
+ "scope_delegation_changed",
2539
+ "scope_parent_ended"
2540
+ ]);
2541
+ ROUTE_OPEN_ADMISSION_PRESSURE_REASONS = new Set(["open_admission_full", "target_binds_full"]);
2208
2542
  });
2209
2543
 
2210
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/provider.js
2544
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/provider.js
2211
2545
  var init_provider = __esm(() => {
2212
2546
  init_auth();
2213
2547
  init_client();
2214
2548
  init_connection_file();
2215
2549
  init_envelope();
2550
+ init_launch_nonce();
2216
2551
  init_route_handle();
2217
2552
  init_socket();
2218
2553
  });
2219
2554
 
2220
- // ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/index.js
2555
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/index.js
2221
2556
  var init_dist = __esm(() => {
2222
2557
  init_client();
2223
2558
  init_route_handle();
@@ -2225,6 +2560,7 @@ var init_dist = __esm(() => {
2225
2560
  init_envelope();
2226
2561
  init_auth();
2227
2562
  init_socket();
2563
+ init_launch_nonce();
2228
2564
  init_provider();
2229
2565
  });
2230
2566
 
@@ -2647,7 +2983,7 @@ var init_lifecycle_registry = __esm(() => {
2647
2983
  var init_project_identity = () => {};
2648
2984
 
2649
2985
  // ../aft-bridge/dist/subc-transport.js
2650
- var CALL_DEADLINE_EXPIRED, LOCALLY_SATISFIED_COMMANDS;
2986
+ var CALL_DEADLINE_EXPIRED, LOCALLY_SATISFIED_COMMANDS, dispatchProbes;
2651
2987
  var init_subc_transport = __esm(() => {
2652
2988
  init_dist();
2653
2989
  init_active_logger();
@@ -2656,6 +2992,7 @@ var init_subc_transport = __esm(() => {
2656
2992
  init_project_identity();
2657
2993
  CALL_DEADLINE_EXPIRED = Symbol("call deadline expired");
2658
2994
  LOCALLY_SATISFIED_COMMANDS = new Set(["configure"]);
2995
+ dispatchProbes = new Map;
2659
2996
  });
2660
2997
 
2661
2998
  // ../aft-bridge/dist/error-contract.js
@@ -2686,26 +3023,9 @@ function surfaceDisables(surface) {
2686
3023
  return;
2687
3024
  }
2688
3025
  }
2689
- function parseMinor(version) {
2690
- const match = /^v?(\d+)\.(\d+)/.exec(version.trim());
2691
- if (!match)
2692
- return;
2693
- return [Number(match[1]), Number(match[2])];
2694
- }
2695
- function policyPhaseForVersion(version) {
2696
- const minor = parseMinor(version);
2697
- if (!minor)
2698
- return "window";
2699
- const [major, min] = minor;
2700
- const [rejectMajor, rejectMinor] = POLICY_REJECT_FROM_MINOR;
2701
- return major > rejectMajor || major === rejectMajor && min >= rejectMinor ? "rejecting" : "window";
2702
- }
2703
3026
  function isRecord(value) {
2704
3027
  return typeof value === "object" && value !== null && !Array.isArray(value);
2705
3028
  }
2706
- function removed(old, replacement) {
2707
- return `removed_config_key:${old}:use:${replacement}`;
2708
- }
2709
3029
  function hasPath(map, path) {
2710
3030
  const dot = path.indexOf(".");
2711
3031
  if (dot < 0)
@@ -2728,12 +3048,147 @@ function falseRuntimeGates(map) {
2728
3048
  function sortedUnique(names) {
2729
3049
  return [...new Set(names)].sort();
2730
3050
  }
2731
- function translateBlock(map, userBase, phase, blockLabel, out) {
2732
- if (Object.hasOwn(map, "gh_read"))
2733
- out.errors.push(removed("gh_read", "github.read"));
2734
- if (isRecord(map.gh_shim) && Object.hasOwn(map.gh_shim, "enabled")) {
2735
- out.errors.push(removed("gh_shim", "github.shim"));
3051
+ function recordRetired(out, prefix, key) {
3052
+ out.legacyInput = true;
3053
+ out.retiredKeys.push(`${prefix}${key}`);
3054
+ }
3055
+ function superseded(out, key, message) {
3056
+ out.warnings.push({ code: "superseded_legacy_config", key, message });
3057
+ }
3058
+ function nestedBool(map, container, leaf) {
3059
+ const inner = map[container];
3060
+ return isRecord(inner) && typeof inner[leaf] === "boolean" ? inner[leaf] : undefined;
3061
+ }
3062
+ function translateGithubAliases(map, prefix, out) {
3063
+ const masterOff = nestedBool(map, "github", "enabled") === false;
3064
+ for (const [alias, leaf, retiredKey] of [
3065
+ ["gh_read", "read", "gh_read"],
3066
+ ["gh_shim", "shim", "gh_shim.enabled"]
3067
+ ]) {
3068
+ const aliasBlock = map[alias];
3069
+ const supplied = alias === "gh_read" ? Object.hasOwn(map, alias) : isRecord(aliasBlock) && Object.hasOwn(aliasBlock, "enabled");
3070
+ if (!supplied)
3071
+ continue;
3072
+ recordRetired(out, prefix, retiredKey);
3073
+ const aliasValue = isRecord(aliasBlock) && typeof aliasBlock.enabled === "boolean" ? aliasBlock.enabled : undefined;
3074
+ if (aliasValue !== undefined) {
3075
+ const canonical = nestedBool(map, "github", leaf);
3076
+ if (canonical !== undefined) {
3077
+ if (canonical !== aliasValue) {
3078
+ superseded(out, `${prefix}${retiredKey}`, `${alias}.enabled=${aliasValue} is ignored because github.${leaf}=${canonical} is set`);
3079
+ }
3080
+ } else if (masterOff) {
3081
+ if (aliasValue) {
3082
+ superseded(out, `${prefix}${retiredKey}`, `${alias}.enabled=true is ignored because github.enabled=false switches github.${leaf} off`);
3083
+ }
3084
+ } else {
3085
+ if (!Object.hasOwn(map, "github"))
3086
+ map.github = {};
3087
+ if (isRecord(map.github))
3088
+ map.github[leaf] = aliasValue;
3089
+ }
3090
+ }
3091
+ if (alias === "gh_read") {
3092
+ delete map.gh_read;
3093
+ } else if (isRecord(aliasBlock)) {
3094
+ delete aliasBlock.enabled;
3095
+ if (Object.keys(aliasBlock).length === 0)
3096
+ delete map.gh_shim;
3097
+ }
3098
+ }
3099
+ }
3100
+ function takeNested(map, container, leaf) {
3101
+ const inner = map[container];
3102
+ if (!isRecord(inner) || !Object.hasOwn(inner, leaf))
3103
+ return { found: false };
3104
+ const value = inner[leaf];
3105
+ delete inner[leaf];
3106
+ if (Object.keys(inner).length === 0)
3107
+ delete map[container];
3108
+ return { found: true, value };
3109
+ }
3110
+ function translateInspectLspPaths(map, prefix, out) {
3111
+ const ttl = takeNested(map, "idle", "lsp_ttl_minutes");
3112
+ if (ttl.found) {
3113
+ recordRetired(out, prefix, "idle.lsp_ttl_minutes");
3114
+ if (isRecord(map.lsp) && map.lsp.idle_minutes !== undefined) {
3115
+ superseded(out, `${prefix}idle.lsp_ttl_minutes`, "idle.lsp_ttl_minutes is ignored because lsp.idle_minutes is set");
3116
+ } else {
3117
+ const raw = typeof ttl.value === "number" && Number.isSafeInteger(ttl.value) ? ttl.value : LSP_IDLE_MINUTES_DEFAULT;
3118
+ const minutes = Math.min(LSP_IDLE_MINUTES_MAX, Math.max(LSP_IDLE_MINUTES_MIN, raw));
3119
+ if (!Object.hasOwn(map, "lsp"))
3120
+ map.lsp = {};
3121
+ if (isRecord(map.lsp))
3122
+ map.lsp.idle_minutes = minutes;
3123
+ }
2736
3124
  }
3125
+ for (const leaf of ["tier2_soft_deadline_ms", "max_drill_down_items"]) {
3126
+ if (takeNested(map, "inspect", leaf).found)
3127
+ recordRetired(out, prefix, `inspect.${leaf}`);
3128
+ }
3129
+ }
3130
+ function translateExperimentalPaths(map, prefix, out) {
3131
+ for (const [oldKey, leaf] of [
3132
+ ["experimental_lsp_ty", "lsp_ty"],
3133
+ ["experimental_bash_rewrite", "rewrite"],
3134
+ ["experimental_bash_compress", "compress"],
3135
+ ["experimental_bash_background", "background"]
3136
+ ]) {
3137
+ if (!Object.hasOwn(map, oldKey))
3138
+ continue;
3139
+ recordRetired(out, prefix, oldKey);
3140
+ const value = map[oldKey];
3141
+ delete map[oldKey];
3142
+ if (!isRecord(map.experimental))
3143
+ map.experimental = {};
3144
+ const experimental = map.experimental;
3145
+ let destination = experimental;
3146
+ if (leaf !== "lsp_ty") {
3147
+ if (!isRecord(experimental.bash))
3148
+ experimental.bash = {};
3149
+ destination = experimental.bash;
3150
+ }
3151
+ if (Object.hasOwn(destination, leaf)) {
3152
+ superseded(out, oldKey, `${oldKey} is ignored because experimental.${leaf === "lsp_ty" ? leaf : `bash.${leaf}`} is already set`);
3153
+ } else {
3154
+ destination[leaf] = value;
3155
+ }
3156
+ }
3157
+ if (!isRecord(map.experimental) || !Object.hasOwn(map.experimental, "bash"))
3158
+ return;
3159
+ const experimental = map.experimental;
3160
+ const legacy = experimental.bash;
3161
+ if (isRecord(legacy)) {
3162
+ if (!["rewrite", "compress", "background"].some((leaf) => Object.hasOwn(legacy, leaf)))
3163
+ return;
3164
+ for (const leaf of Object.keys(legacy))
3165
+ recordRetired(out, prefix, `experimental.bash.${leaf}`);
3166
+ if (Object.hasOwn(map, "bash")) {
3167
+ superseded(out, "experimental.bash", 'experimental.bash is ignored because top-level "bash" is already set');
3168
+ } else {
3169
+ const bash = {
3170
+ rewrite: legacy.rewrite === true,
3171
+ compress: legacy.compress === true,
3172
+ background: legacy.background === true
3173
+ };
3174
+ for (const leaf of ["long_running_reminder_enabled", "long_running_reminder_interval_ms"]) {
3175
+ if (Object.hasOwn(legacy, leaf))
3176
+ bash[leaf] = legacy[leaf];
3177
+ }
3178
+ map.bash = bash;
3179
+ }
3180
+ } else {
3181
+ recordRetired(out, prefix, "experimental.bash");
3182
+ }
3183
+ delete experimental.bash;
3184
+ if (Object.keys(experimental).length === 0)
3185
+ delete map.experimental;
3186
+ }
3187
+ function translateBlock(map, userBase, blockLabel, out) {
3188
+ const prefix = blockLabel === "base" ? "" : `${blockLabel}.`;
3189
+ translateGithubAliases(map, prefix, out);
3190
+ translateInspectLspPaths(map, prefix, out);
3191
+ translateExperimentalPaths(map, prefix, out);
2737
3192
  let explicitList;
2738
3193
  const rawList = map.disabled_tools;
2739
3194
  if (Array.isArray(rawList) && rawList.every((entry) => typeof entry === "string")) {
@@ -2741,30 +3196,17 @@ function translateBlock(map, userBase, phase, blockLabel, out) {
2741
3196
  const host = LEGACY_TOOL_ALIASES[name];
2742
3197
  if (host === undefined)
2743
3198
  return name;
2744
- out.legacyInput = true;
2745
- if (phase === "rejecting")
2746
- out.errors.push(removed(name, host));
3199
+ recordRetired(out, prefix, name);
2747
3200
  return host;
2748
3201
  });
2749
3202
  }
2750
- const suppliedPaths = RETIRED_PATHS.map(([path]) => path).filter((path) => hasPath(map, path));
2751
- if (suppliedPaths.length > 0)
2752
- out.legacyInput = true;
2753
- const gates = falseRuntimeGates(map);
2754
- if (phase === "rejecting") {
2755
- for (const path of suppliedPaths) {
2756
- const replacement = RETIRED_PATHS.find(([old]) => old === path)?.[1] ?? "disabled_tools";
2757
- out.errors.push(removed(path, replacement));
2758
- }
2759
- if (gates.length > 0 && explicitList === undefined) {
2760
- out.warnings.push({
2761
- code: "legacy_runtime_gate_runtime_only",
2762
- key: blockLabel,
2763
- message: `${gates.join(", ")} now restricts runtime behavior only and no longer removes tool registrations; list tools in disabled_tools to unregister them`
2764
- });
2765
- }
2766
- return;
3203
+ for (const [path] of RETIRED_PATHS) {
3204
+ if (path === "experimental.bash")
3205
+ continue;
3206
+ if (hasPath(map, path))
3207
+ recordRetired(out, prefix, path);
2767
3208
  }
3209
+ const gates = falseRuntimeGates(map);
2768
3210
  if (explicitList !== undefined)
2769
3211
  map.disabled_tools = explicitList;
2770
3212
  for (const [leaf, legacy, experimental] of INDEX_INPUTS) {
@@ -2791,19 +3233,11 @@ function translateBlock(map, userBase, phase, blockLabel, out) {
2791
3233
  }
2792
3234
  if (canonical !== undefined) {
2793
3235
  if (canonical !== value) {
2794
- out.warnings.push({
2795
- code: "superseded_legacy_config",
2796
- key,
2797
- message: `${key}=${value} is ignored because indexes.${leaf}=${canonical} is set`
2798
- });
3236
+ superseded(out, key, `${key}=${value} is ignored because indexes.${leaf}=${canonical} is set`);
2799
3237
  }
2800
3238
  } else if (chosen !== undefined) {
2801
3239
  if (chosen !== value) {
2802
- out.warnings.push({
2803
- code: "superseded_legacy_config",
2804
- key,
2805
- message: `${key}=${value} is ignored because ${legacy}=${chosen} takes precedence`
2806
- });
3240
+ superseded(out, key, `${key}=${value} is ignored because ${legacy}=${chosen} takes precedence`);
2807
3241
  }
2808
3242
  } else {
2809
3243
  chosen = value;
@@ -2825,11 +3259,7 @@ function translateBlock(map, userBase, phase, blockLabel, out) {
2825
3259
  if (!Object.hasOwn(github, leaf))
2826
3260
  github[leaf] = false;
2827
3261
  else if (github[leaf] === true) {
2828
- out.warnings.push({
2829
- code: "superseded_legacy_config",
2830
- key: "github.enabled",
2831
- message: `github.enabled=false is ignored for github.${leaf} because github.${leaf}=true is set`
2832
- });
3262
+ superseded(out, "github.enabled", `github.enabled=false is ignored for github.${leaf} because github.${leaf}=true is set`);
2833
3263
  }
2834
3264
  }
2835
3265
  }
@@ -2870,21 +3300,19 @@ function translateBlock(map, userBase, phase, blockLabel, out) {
2870
3300
  message: RETIRED_ENABLED_FALSE_INDEXES_NOTE
2871
3301
  });
2872
3302
  }
2873
- for (const gate of gates) {
2874
- if (gate === "backup.enabled")
2875
- generated.add("aft_safety");
2876
- else if (gate === "inspect.enabled")
2877
- generated.add("aft_inspect");
2878
- else
2879
- for (const name of BASH_GATE_DISABLES)
2880
- generated.add(name);
3303
+ if (gates.length > 0 && explicitList === undefined) {
3304
+ out.warnings.push({
3305
+ code: "legacy_runtime_gate_runtime_only",
3306
+ key: blockLabel,
3307
+ message: `${gates.join(", ")} now restricts runtime behavior only and no longer removes tool registrations; list tools in disabled_tools to unregister them`
3308
+ });
2881
3309
  }
2882
3310
  if (explicitList !== undefined) {
2883
3311
  if (explicitSurface || generated.size > 0) {
2884
3312
  out.warnings.push({
2885
3313
  code: "superseded_legacy_config",
2886
3314
  key: blockLabel,
2887
- message: "disabled_tools is set explicitly, so legacy tool_surface/hoist_builtin_tools/enabled and runtime gates do not change registration",
3315
+ message: "disabled_tools is set explicitly, so legacy tool_surface/hoist_builtin_tools/enabled do not change registration",
2888
3316
  once: true
2889
3317
  });
2890
3318
  }
@@ -2901,29 +3329,22 @@ function translateBlock(map, userBase, phase, blockLabel, out) {
2901
3329
  }
2902
3330
  if (list !== undefined)
2903
3331
  map.disabled_tools = list;
2904
- if (gates.length > 0) {
2905
- out.warnings.push({
2906
- code: "legacy_runtime_gate_requires_fix",
2907
- key: blockLabel,
2908
- message: `${gates.join(", ")} still removes tool registrations during this release only; run \`npx @cortexkit/aft doctor --fix\` to record the choice in disabled_tools`
2909
- });
2910
- }
2911
3332
  }
2912
- function translateConfigDocument(map, phase, tier) {
3333
+ function translateConfigDocument(map, tier) {
2913
3334
  const out = {
2914
- errors: [],
2915
3335
  warnings: [],
2916
3336
  legacyInput: false,
3337
+ retiredKeys: [],
2917
3338
  retiredEnabledFalse: false
2918
3339
  };
2919
- translateBlock(map, tier === "user", phase, "base", out);
3340
+ translateBlock(map, tier === "user", "base", out);
2920
3341
  if (isRecord(map.harnesses)) {
2921
3342
  for (const [name, block] of Object.entries(map.harnesses)) {
2922
3343
  if (isRecord(block))
2923
- translateBlock(block, false, phase, `harnesses.${name}`, out);
3344
+ translateBlock(block, false, `harnesses.${name}`, out);
2924
3345
  }
2925
3346
  }
2926
- out.errors = sortedUnique(out.errors);
3347
+ out.retiredKeys = sortedUnique(out.retiredKeys);
2927
3348
  return out;
2928
3349
  }
2929
3350
  function canonicalJson(value) {
@@ -2950,7 +3371,7 @@ function mergeIndexes(base, override, restricted) {
2950
3371
  }
2951
3372
  return merged;
2952
3373
  }
2953
- var CANONICAL_TOOLS, HOST_TOOL_NAMES, DEFAULT_DISABLED_TOOLS, LEGACY_TOOL_ALIASES, BASH_GATE_DISABLES, POLICY_REJECT_FROM_MINOR, RETIRED_PATHS, INDEX_INPUTS, RETIRED_ENABLED_FALSE_INDEXES_NOTE = "enabled: false no longer turns AFT off: it is translated to disabling every tool, but the trigram, semantic and callgraph indexes still build. To keep AFT from indexing this repository, also set indexes.trigram, indexes.semantic and indexes.callgraph to false.", SEMANTIC_COST_NOTICE_DIGEST, ConfigRejectedError;
3374
+ var CANONICAL_TOOLS, HOST_TOOL_NAMES, DEFAULT_DISABLED_TOOLS, LEGACY_TOOL_ALIASES, RETIRED_PATHS, INDEX_INPUTS, LSP_IDLE_MINUTES_DEFAULT = 60, LSP_IDLE_MINUTES_MIN = 5, LSP_IDLE_MINUTES_MAX = 1440, RETIRED_ENABLED_FALSE_INDEXES_NOTE = "enabled: false no longer turns AFT off: it is translated to disabling every tool, but the trigram, semantic and callgraph indexes still build. To keep AFT from indexing this repository, also set indexes.trigram, indexes.semantic and indexes.callgraph to false.", SEMANTIC_COST_NOTICE_DIGEST;
2954
3375
  var init_feature_config = __esm(() => {
2955
3376
  CANONICAL_TOOLS = [
2956
3377
  "aft_callgraph",
@@ -2996,14 +3417,6 @@ var init_feature_config = __esm(() => {
2996
3417
  aft_glob: "glob",
2997
3418
  aft_bash: "bash"
2998
3419
  };
2999
- BASH_GATE_DISABLES = [
3000
- "bash",
3001
- "bash_kill",
3002
- "bash_status",
3003
- "bash_watch",
3004
- "bash_write"
3005
- ];
3006
- POLICY_REJECT_FROM_MINOR = [0, 59];
3007
3420
  RETIRED_PATHS = [
3008
3421
  ["tool_surface", "disabled_tools"],
3009
3422
  ["hoist_builtin_tools", "disabled_tools"],
@@ -3013,7 +3426,12 @@ var init_feature_config = __esm(() => {
3013
3426
  ["semantic_search", "indexes.semantic"],
3014
3427
  ["experimental_semantic_search", "indexes.semantic"],
3015
3428
  ["callgraph_store", "indexes.callgraph"],
3016
- ["github.enabled", "github.read,github.write,github.shim"]
3429
+ ["github.enabled", "github.read,github.write,github.shim"],
3430
+ ["experimental_lsp_ty", "experimental.lsp_ty"],
3431
+ ["experimental_bash_rewrite", "bash.rewrite"],
3432
+ ["experimental_bash_compress", "bash.compress"],
3433
+ ["experimental_bash_background", "bash.background"],
3434
+ ["experimental.bash", "bash"]
3017
3435
  ];
3018
3436
  INDEX_INPUTS = [
3019
3437
  ["trigram", "search_index", "experimental_search_index"],
@@ -3021,20 +3439,13 @@ var init_feature_config = __esm(() => {
3021
3439
  ["callgraph", "callgraph_store", undefined]
3022
3440
  ];
3023
3441
  SEMANTIC_COST_NOTICE_DIGEST = noticeDigest({ notice: "semantic_default_cost_v1" });
3024
- ConfigRejectedError = class ConfigRejectedError extends Error {
3025
- errors;
3026
- constructor(errors, source) {
3027
- super(`AFT configuration${source ? ` at ${source}` : ""} was rejected: ${errors.join(", ")}. ` + "Run `npx @cortexkit/aft doctor --fix` to migrate removed keys.");
3028
- this.name = "ConfigRejectedError";
3029
- this.errors = errors;
3030
- }
3031
- };
3032
3442
  });
3033
3443
  // ../aft-bridge/dist/pool.js
3034
3444
  var DEFAULT_IDLE_TIMEOUT_MS, CLEANUP_INTERVAL_MS;
3035
3445
  var init_pool = __esm(() => {
3036
3446
  init_active_logger();
3037
3447
  init_bridge();
3448
+ init_lifecycle_registry();
3038
3449
  init_project_identity();
3039
3450
  DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
3040
3451
  CLEANUP_INTERVAL_MS = 60 * 1000;
@@ -3043,6 +3454,7 @@ var init_pool = __esm(() => {
3043
3454
  // ../aft-bridge/dist/revivable-transport.js
3044
3455
  var init_revivable_transport = __esm(() => {
3045
3456
  init_active_logger();
3457
+ init_lifecycle_registry();
3046
3458
  init_project_identity();
3047
3459
  });
3048
3460
 
@@ -3058,6 +3470,7 @@ var init_transport_factory = __esm(() => {
3058
3470
  // ../aft-bridge/dist/location-lifecycle.js
3059
3471
  var LIFECYCLE_STATE, RELEASE_LOCATION;
3060
3472
  var init_location_lifecycle = __esm(() => {
3473
+ init_bridge();
3061
3474
  init_project_identity();
3062
3475
  init_transport_factory();
3063
3476
  LIFECYCLE_STATE = Symbol.for("@cortexkit/aft-bridge/location-lifecycle/v1");
@@ -3073,35 +3486,37 @@ var init_message_detach = __esm(() => {
3073
3486
  });
3074
3487
 
3075
3488
  // ../aft-bridge/dist/paths.js
3076
- import { homedir as homedir5 } from "node:os";
3077
- import { dirname, isAbsolute as isAbsolute2, join as join6, resolve as resolve3 } from "node:path";
3489
+ import { homedir as homedir7 } from "node:os";
3490
+ import { dirname as dirname2, isAbsolute as isAbsolute4, join as join8, resolve as resolve5 } from "node:path";
3078
3491
  function homeDir3() {
3079
3492
  if (process.platform === "win32")
3080
- return process.env.USERPROFILE || process.env.HOME || homedir5();
3081
- return process.env.HOME || homedir5();
3493
+ return process.env.USERPROFILE || process.env.HOME || homedir7();
3494
+ return process.env.HOME || homedir7();
3082
3495
  }
3083
3496
  function configHome() {
3084
3497
  const xdg = process.env.XDG_CONFIG_HOME;
3085
- if (xdg && isAbsolute2(xdg))
3498
+ if (xdg && isAbsolute4(xdg))
3086
3499
  return xdg;
3087
- return join6(homeDir3(), ".config");
3500
+ return join8(homeDir3(), ".config");
3088
3501
  }
3089
3502
  function resolveCortexKitUserConfigPath() {
3090
- return join6(configHome(), "cortexkit", "aft.jsonc");
3503
+ return join8(configHome(), "cortexkit", "aft.jsonc");
3091
3504
  }
3092
3505
  function resolveCortexKitProjectConfigPath(projectDirectory) {
3093
- return join6(projectDirectory, ".cortexkit", "aft.jsonc");
3506
+ return join8(projectDirectory, ".cortexkit", "aft.jsonc");
3094
3507
  }
3095
- var init_paths = () => {};
3508
+ var init_paths = __esm(() => {
3509
+ init_private_storage();
3510
+ });
3096
3511
 
3097
3512
  // ../aft-bridge/dist/resolver.js
3098
- import { closeSync as closeSync2, existsSync as existsSync3, promises as fsPromises, openSync as openSync2, readFileSync as readFileSync4, readSync } from "node:fs";
3513
+ import { closeSync as closeSync4, existsSync as existsSync3, promises as fsPromises, openSync as openSync4, readFileSync as readFileSync4, readSync as readSync3 } from "node:fs";
3099
3514
  function isNativeExecutable(binaryPath) {
3100
3515
  let fd = null;
3101
3516
  try {
3102
- fd = openSync2(binaryPath, "r");
3517
+ fd = openSync4(binaryPath, "r");
3103
3518
  const buf = Buffer.alloc(4);
3104
- const read = readSync(fd, buf, 0, 4, 0);
3519
+ const read = readSync3(fd, buf, 0, 4, 0);
3105
3520
  if (read < 2)
3106
3521
  return false;
3107
3522
  const b0 = buf[0];
@@ -3122,7 +3537,7 @@ function isNativeExecutable(binaryPath) {
3122
3537
  } finally {
3123
3538
  if (fd !== null) {
3124
3539
  try {
3125
- closeSync2(fd);
3540
+ closeSync4(fd);
3126
3541
  } catch {}
3127
3542
  }
3128
3543
  }
@@ -3150,12 +3565,12 @@ var init_migration = __esm(() => {
3150
3565
  });
3151
3566
 
3152
3567
  // ../aft-bridge/dist/migration-notices.js
3153
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, renameSync as renameSync3, rmdirSync, statSync as statSync3, writeFileSync as writeFileSync2 } from "node:fs";
3154
- import { homedir as homedir6 } from "node:os";
3155
- import { dirname as dirname2, join as join7, resolve as resolve4 } from "node:path";
3568
+ import { readFileSync as readFileSync5, renameSync as renameSync3, rmdirSync, statSync as statSync3, writeFileSync as writeFileSync2 } from "node:fs";
3569
+ import { homedir as homedir8 } from "node:os";
3570
+ import { dirname as dirname3, join as join9, resolve as resolve6 } from "node:path";
3156
3571
  function migrationNoticeStorePath(env = process.env) {
3157
- const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join7(homedir6(), ".local", "state");
3158
- return join7(stateHome, "cortexkit", "aft", "migration-notices.json");
3572
+ const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join9(homedir8(), ".local", "state");
3573
+ return join9(stateHome, "cortexkit", "aft", "migration-notices.json");
3159
3574
  }
3160
3575
  function readRecords(storePath) {
3161
3576
  try {
@@ -3167,11 +3582,11 @@ function readRecords(storePath) {
3167
3582
  }
3168
3583
  function withStoreLock(storePath, action) {
3169
3584
  const lockPath = `${storePath}.lock`;
3170
- mkdirSync2(dirname2(storePath), { recursive: true });
3585
+ openPrivateStorageDir(dirname3(storePath));
3171
3586
  const deadline = Date.now() + 2000;
3172
3587
  for (;; ) {
3173
3588
  try {
3174
- mkdirSync2(lockPath);
3589
+ privateMkdirSync(lockPath, false);
3175
3590
  break;
3176
3591
  } catch (error) {
3177
3592
  if (error.code !== "EEXIST")
@@ -3194,30 +3609,34 @@ function withStoreLock(storePath, action) {
3194
3609
  }
3195
3610
  }
3196
3611
  function clearMigrationNotices(configPath, storePath = migrationNoticeStorePath()) {
3197
- const prefix = `${resolve4(configPath)}|`;
3612
+ const prefix = `${resolve6(configPath)}|`;
3198
3613
  withStoreLock(storePath, () => {
3199
3614
  const records = readRecords(storePath);
3200
3615
  for (const key of Object.keys(records))
3201
3616
  if (key.startsWith(prefix))
3202
3617
  delete records[key];
3203
3618
  writeFileSync2(storePath, `${JSON.stringify(records, null, 2)}
3204
- `, "utf8");
3619
+ `, {
3620
+ encoding: "utf8",
3621
+ mode: PRIVATE_FILE_MODE
3622
+ });
3205
3623
  });
3206
3624
  }
3207
3625
  var LOCK_STALE_MS = 1e4;
3208
3626
  var init_migration_notices = __esm(() => {
3209
3627
  init_feature_config();
3628
+ init_private_storage();
3210
3629
  });
3211
3630
 
3212
3631
  // ../aft-bridge/dist/npm-resolver.js
3213
3632
  import { readdirSync as readdirSync2, statSync as statSync4 } from "node:fs";
3214
- import { homedir as homedir7 } from "node:os";
3215
- import { dirname as dirname3, isAbsolute as isAbsolute3, join as join8 } from "node:path";
3633
+ import { homedir as homedir9 } from "node:os";
3634
+ import { dirname as dirname4, isAbsolute as isAbsolute5, join as join10 } from "node:path";
3216
3635
  function defaultDeps() {
3217
3636
  return {
3218
3637
  platform: process.platform,
3219
3638
  env: process.env,
3220
- home: homedir7(),
3639
+ home: homedir9(),
3221
3640
  execPath: process.execPath
3222
3641
  };
3223
3642
  }
@@ -3239,16 +3658,16 @@ function npmFromPath(deps) {
3239
3658
  const separator = deps.platform === "win32" ? ";" : ":";
3240
3659
  for (const entry of raw.split(separator)) {
3241
3660
  const dir = entry.trim().replace(/^"|"$/g, "");
3242
- if (!dir || !isAbsolute3(dir))
3661
+ if (!dir || !isAbsolute5(dir))
3243
3662
  continue;
3244
- if (isFile(join8(dir, name)))
3663
+ if (isFile(join10(dir, name)))
3245
3664
  return dir;
3246
3665
  }
3247
3666
  return null;
3248
3667
  }
3249
3668
  function npmAdjacentToNode(deps) {
3250
- const dir = dirname3(deps.execPath);
3251
- return isFile(join8(dir, npmBinaryName(deps.platform))) ? dir : null;
3669
+ const dir = dirname4(deps.execPath);
3670
+ return isFile(join10(dir, npmBinaryName(deps.platform))) ? dir : null;
3252
3671
  }
3253
3672
  function highestVersionedNodeBin(installsDir, name) {
3254
3673
  let entries;
@@ -3257,8 +3676,8 @@ function highestVersionedNodeBin(installsDir, name) {
3257
3676
  } catch {
3258
3677
  return null;
3259
3678
  }
3260
- const candidates = entries.filter((v) => isFile(join8(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
3261
- return candidates.length > 0 ? join8(installsDir, candidates[0], "bin") : null;
3679
+ const candidates = entries.filter((v) => isFile(join10(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
3680
+ return candidates.length > 0 ? join10(installsDir, candidates[0], "bin") : null;
3262
3681
  }
3263
3682
  function compareVersionsDesc(a, b) {
3264
3683
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -3283,22 +3702,22 @@ function wellKnownNpmDirs(deps) {
3283
3702
  const programFiles = env.ProgramFiles || "C:\\Program Files";
3284
3703
  const appData = env.APPDATA;
3285
3704
  const localAppData = env.LOCALAPPDATA;
3286
- push(join8(programFiles, "nodejs"));
3705
+ push(join10(programFiles, "nodejs"));
3287
3706
  if (appData)
3288
- push(join8(appData, "npm"));
3707
+ push(join10(appData, "npm"));
3289
3708
  if (localAppData)
3290
- push(join8(localAppData, "Volta", "bin"));
3709
+ push(join10(localAppData, "Volta", "bin"));
3291
3710
  if (env.NVM_SYMLINK)
3292
3711
  push(env.NVM_SYMLINK);
3293
3712
  } else {
3294
3713
  if (env.NVM_BIN)
3295
3714
  push(env.NVM_BIN);
3296
- push(highestVersionedNodeBin(join8(home, ".nvm", "versions", "node"), name));
3297
- push(highestVersionedNodeBin(join8(home, ".local", "share", "mise", "installs", "node"), name));
3298
- push(highestVersionedNodeBin(join8(home, ".asdf", "installs", "nodejs"), name));
3299
- push(join8(home, ".volta", "bin"));
3300
- push(join8(home, ".asdf", "shims"));
3301
- const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join8(home, ".local", "bin")]);
3715
+ push(highestVersionedNodeBin(join10(home, ".nvm", "versions", "node"), name));
3716
+ push(highestVersionedNodeBin(join10(home, ".local", "share", "mise", "installs", "node"), name));
3717
+ push(highestVersionedNodeBin(join10(home, ".asdf", "installs", "nodejs"), name));
3718
+ push(join10(home, ".volta", "bin"));
3719
+ push(join10(home, ".asdf", "shims"));
3720
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join10(home, ".local", "bin")]);
3302
3721
  for (const dir of systemDirs)
3303
3722
  push(dir);
3304
3723
  }
@@ -3308,12 +3727,12 @@ function resolveNpm(deps = defaultDeps()) {
3308
3727
  const name = npmBinaryName(deps.platform);
3309
3728
  const onPath = npmFromPath(deps);
3310
3729
  if (onPath)
3311
- return { command: join8(onPath, name), binDir: onPath };
3730
+ return { command: join10(onPath, name), binDir: onPath };
3312
3731
  const adjacent = npmAdjacentToNode(deps);
3313
3732
  if (adjacent)
3314
- return { command: join8(adjacent, name), binDir: adjacent };
3733
+ return { command: join10(adjacent, name), binDir: adjacent };
3315
3734
  for (const dir of wellKnownNpmDirs(deps)) {
3316
- const candidate = join8(dir, name);
3735
+ const candidate = join10(dir, name);
3317
3736
  if (isFile(candidate))
3318
3737
  return { command: candidate, binDir: dir };
3319
3738
  }
@@ -3474,7 +3893,7 @@ function terminateNpmProcessTree(child, invocation, env = process.env, gracePeri
3474
3893
  };
3475
3894
  child.once("exit", onChildExit);
3476
3895
  const systemRoot = env.SystemRoot ?? env.SYSTEMROOT;
3477
- const taskkill = systemRoot ? join8(systemRoot, "System32", "taskkill.exe") : "taskkill.exe";
3896
+ const taskkill = systemRoot ? join10(systemRoot, "System32", "taskkill.exe") : "taskkill.exe";
3478
3897
  try {
3479
3898
  killer = spawn(taskkill, ["/pid", String(child.pid), "/t", "/f"], {
3480
3899
  stdio: "ignore",
@@ -3510,10 +3929,10 @@ var init_npm_resolver = __esm(() => {
3510
3929
  });
3511
3930
 
3512
3931
  // ../aft-bridge/dist/onnx-probe.js
3513
- import { closeSync as closeSync3, existsSync as existsSync4, openSync as openSync3, readSync as readSync2, realpathSync } from "node:fs";
3932
+ import { closeSync as closeSync5, existsSync as existsSync4, openSync as openSync5, readSync as readSync4, realpathSync as realpathSync2 } from "node:fs";
3514
3933
  function readAt(fd, offset, length) {
3515
3934
  const buffer = Buffer.alloc(length);
3516
- const read = readSync2(fd, buffer, 0, length, offset);
3935
+ const read = readSync4(fd, buffer, 0, length, offset);
3517
3936
  return buffer.subarray(0, read);
3518
3937
  }
3519
3938
  function cpuTypeForArch(arch) {
@@ -3587,7 +4006,7 @@ function isUncheckableDependency(path) {
3587
4006
  function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
3588
4007
  let fd;
3589
4008
  try {
3590
- fd = openSync3(realpathSync(libPath), "r");
4009
+ fd = openSync5(realpathSync2(libPath), "r");
3591
4010
  } catch (err) {
3592
4011
  return {
3593
4012
  loadable: false,
@@ -3621,7 +4040,7 @@ function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
3621
4040
  } catch {
3622
4041
  return UNCHECKED;
3623
4042
  } finally {
3624
- closeSync3(fd);
4043
+ closeSync5(fd);
3625
4044
  }
3626
4045
  }
3627
4046
  var MH_MAGIC = 4277009102, MH_MAGIC_64 = 4277009103, FAT_MAGIC = 3405691582, LC_LOAD_DYLIB = 12, LC_REEXPORT_DYLIB = 2147483679, LC_LOAD_UPWARD_DYLIB = 2147483683, CPU_TYPE_X86_64 = 16777223, CPU_TYPE_ARM64 = 16777228, MAX_HEADER_BYTES, UNCHECKED;
@@ -3632,19 +4051,30 @@ var init_onnx_probe = __esm(() => {
3632
4051
 
3633
4052
  // ../aft-bridge/dist/tar-executable.js
3634
4053
  import { existsSync as existsSync5 } from "node:fs";
3635
- import { join as join9 } from "node:path";
4054
+ import { join as join11 } from "node:path";
3636
4055
  function windowsTarExecutable(options = {}) {
3637
4056
  const platform = options.platform ?? process.platform;
3638
4057
  if (platform !== "win32")
3639
4058
  return "tar";
3640
4059
  const env = options.env ?? process.env;
3641
- const systemTar = join9(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
4060
+ const systemTar = join11(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
3642
4061
  return (options.exists ?? existsSync5)(systemTar) ? systemTar : "tar";
3643
4062
  }
3644
- function execTarExtractionSync(args, timeout) {
4063
+ function execTarExtractionSync(args, timeout, privateStorage = false) {
3645
4064
  const executable = windowsTarExecutable();
3646
4065
  try {
3647
- execFileSync(executable, args, { stdio: "pipe", timeout });
4066
+ if (privateStorage && process.platform !== "win32") {
4067
+ execFileSync("/bin/sh", [
4068
+ "-c",
4069
+ 'umask 077; exec "$@"',
4070
+ "aft-extract",
4071
+ executable,
4072
+ "--no-same-permissions",
4073
+ ...args.map((arg, index) => index === 0 && !arg.startsWith("-") ? `-${arg}` : arg)
4074
+ ], { stdio: "pipe", timeout });
4075
+ } else {
4076
+ execFileSync(executable, args, { stdio: "pipe", timeout });
4077
+ }
3648
4078
  } catch (cause) {
3649
4079
  const detail = cause instanceof Error ? cause.message : String(cause);
3650
4080
  throw new Error(`tar extraction failed using ${executable}: ${detail}`, { cause });
@@ -3655,9 +4085,9 @@ var init_tar_executable = __esm(() => {
3655
4085
  });
3656
4086
 
3657
4087
  // ../aft-bridge/dist/onnx-runtime.js
3658
- import { createHash as createHash4, randomBytes } from "node:crypto";
3659
- import { chmodSync as chmodSync2, closeSync as closeSync4, copyFileSync as copyFileSync2, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync3, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync5, symlinkSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
3660
- import { basename, dirname as dirname4, isAbsolute as isAbsolute4, join as join10, relative, resolve as resolve5, win32 } from "node:path";
4088
+ import { randomBytes } from "node:crypto";
4089
+ import { chmodSync as chmodSync2, closeSync as closeSync6, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync as lstatSync2, openSync as openSync6, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync5, symlinkSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
4090
+ import { basename, dirname as dirname5, isAbsolute as isAbsolute6, join as join12, relative as relative3, resolve as resolve7, win32 as win322 } from "node:path";
3661
4091
  import { Readable as Readable2 } from "node:stream";
3662
4092
  import { pipeline as pipeline2 } from "node:stream/promises";
3663
4093
  function getPlatformInfo() {
@@ -3694,14 +4124,14 @@ function resolveOnnxRuntime(storageDir, seams) {
3694
4124
  inflightResolutions.set(storageDir, resolution);
3695
4125
  return resolution;
3696
4126
  }
3697
- function findCachedOnnxRuntime(ortVersionDir, libName) {
4127
+ async function findCachedOnnxRuntime(ortVersionDir, libName) {
3698
4128
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
3699
- const libPath = join10(resolvedOrtDir, libName);
4129
+ const libPath = join12(resolvedOrtDir, libName);
3700
4130
  if (existsSync6(libPath)) {
3701
4131
  const meta = readOnnxInstalledMeta(ortVersionDir);
3702
4132
  if (meta?.sha256) {
3703
4133
  try {
3704
- const currentHash = sha256File2(libPath);
4134
+ const currentHash = await cachedFileSha256(libPath);
3705
4135
  if (currentHash !== meta.sha256) {
3706
4136
  error(`ONNX Runtime at ${resolvedOrtDir}: TOFU sha256 mismatch — refusing to use ` + `tampered binary. Recorded ${meta.sha256}, current ${currentHash}. ` + `Run \`npx @cortexkit/aft doctor --clear\` to re-download from scratch.`);
3707
4137
  } else {
@@ -3721,9 +4151,9 @@ function findCachedOnnxRuntime(ortVersionDir, libName) {
3721
4151
  }
3722
4152
  async function resolveOnnxRuntimeUncoalesced(storageDir, seams) {
3723
4153
  const info = seams.platformInfo !== undefined ? seams.platformInfo : getPlatformInfo();
3724
- const ortVersionDir = join10(storageDir, "onnxruntime", ORT_VERSION);
4154
+ const ortVersionDir = join12(storageDir, "onnxruntime", ORT_VERSION);
3725
4155
  const libName = info?.libName ?? "libonnxruntime.dylib";
3726
- const cached = findCachedOnnxRuntime(ortVersionDir, libName);
4156
+ const cached = await findCachedOnnxRuntime(ortVersionDir, libName);
3727
4157
  if (cached)
3728
4158
  return cached;
3729
4159
  const systemPath = findSystemOnnxRuntime(info?.libName, seams.systemSearchPaths);
@@ -3735,9 +4165,9 @@ async function resolveOnnxRuntimeUncoalesced(storageDir, seams) {
3735
4165
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
3736
4166
  return null;
3737
4167
  }
3738
- const onnxBaseDir = join10(storageDir, "onnxruntime");
3739
- mkdirSync3(onnxBaseDir, { recursive: true });
3740
- const lockPath = join10(onnxBaseDir, ONNX_LOCK_FILE);
4168
+ const onnxBaseDir = join12(storageDir, "onnxruntime");
4169
+ openPrivateStorageDir(storageDir, onnxBaseDir);
4170
+ const lockPath = join12(onnxBaseDir, ONNX_LOCK_FILE);
3741
4171
  const pollMs = seams.lockPollMs ?? LOCK_POLL_MS;
3742
4172
  const deadline = Date.now() + LOCK_WAIT_MS;
3743
4173
  let announcedWait = false;
@@ -3752,14 +4182,14 @@ async function resolveOnnxRuntimeUncoalesced(storageDir, seams) {
3752
4182
  return null;
3753
4183
  }
3754
4184
  await new Promise((done) => setTimeout(done, pollMs));
3755
- const published = findCachedOnnxRuntime(ortVersionDir, libName);
4185
+ const published = await findCachedOnnxRuntime(ortVersionDir, libName);
3756
4186
  if (published) {
3757
4187
  lastInstallFailure = null;
3758
4188
  return published;
3759
4189
  }
3760
4190
  }
3761
4191
  try {
3762
- const published = findCachedOnnxRuntime(ortVersionDir, libName);
4192
+ const published = await findCachedOnnxRuntime(ortVersionDir, libName);
3763
4193
  if (published) {
3764
4194
  lastInstallFailure = null;
3765
4195
  return published;
@@ -3782,7 +4212,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
3782
4212
  for (const entry of entries) {
3783
4213
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
3784
4214
  continue;
3785
- const stagingDir = join10(onnxBaseDir, entry);
4215
+ const stagingDir = join12(onnxBaseDir, entry);
3786
4216
  const parts = entry.split(".");
3787
4217
  const pidStr = parts[parts.length - 2];
3788
4218
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -3819,7 +4249,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
3819
4249
  }
3820
4250
  function cleanupIncompleteTargetIfUnowned(ortDir) {
3821
4251
  try {
3822
- if (existsSync6(ortDir) && !existsSync6(join10(ortDir, ONNX_INSTALLED_META_FILE))) {
4252
+ if (existsSync6(ortDir) && !existsSync6(join12(ortDir, ONNX_INSTALLED_META_FILE))) {
3823
4253
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
3824
4254
  rmSync2(ortDir, { recursive: true, force: true });
3825
4255
  }
@@ -3844,14 +4274,14 @@ function parseOnnxVersionFromDirectoryPath(value) {
3844
4274
  return null;
3845
4275
  }
3846
4276
  function isPathInsideRoot(root, candidate) {
3847
- const rel = relative(root, candidate);
3848
- return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute4(rel) && !win32.isAbsolute(rel);
4277
+ const rel = relative3(root, candidate);
4278
+ return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute6(rel) && !win322.isAbsolute(rel);
3849
4279
  }
3850
4280
  function detectOnnxVersion(libDir, libName) {
3851
4281
  try {
3852
4282
  const entries = readdirSync3(libDir);
3853
4283
  try {
3854
- const resolved = parseOnnxVersionFromPath(realpathSync2(join10(libDir, libName)));
4284
+ const resolved = parseOnnxVersionFromPath(realpathSync3(join12(libDir, libName)));
3855
4285
  if (resolved && resolved !== INVALID_ORT_VERSION)
3856
4286
  return resolved;
3857
4287
  } catch {}
@@ -3865,10 +4295,10 @@ function detectOnnxVersion(libDir, libName) {
3865
4295
  if (version)
3866
4296
  return version;
3867
4297
  }
3868
- const base = join10(libDir, libName);
4298
+ const base = join12(libDir, libName);
3869
4299
  if (existsSync6(base)) {
3870
4300
  try {
3871
- const real = realpathSync2(base);
4301
+ const real = realpathSync3(base);
3872
4302
  const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
3873
4303
  if (version)
3874
4304
  return version;
@@ -3905,18 +4335,18 @@ function pathEntriesForPlatform() {
3905
4335
  return pathEnvValue().split(delimiter).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
3906
4336
  if (!entry || entry === "." || entry.includes("\x00"))
3907
4337
  return false;
3908
- return isAbsolute4(entry) || win32.isAbsolute(entry);
4338
+ return isAbsolute6(entry) || win322.isAbsolute(entry);
3909
4339
  });
3910
4340
  }
3911
4341
  function isWindowsSystem32Directory(dir) {
3912
4342
  if (process.platform !== "win32")
3913
4343
  return false;
3914
- const normalizedDir = win32.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
4344
+ const normalizedDir = win322.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
3915
4345
  const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
3916
4346
  return windowsRoots.some((root) => {
3917
4347
  if (!root)
3918
4348
  return false;
3919
- return normalizedDir === win32.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
4349
+ return normalizedDir === win322.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
3920
4350
  });
3921
4351
  }
3922
4352
  function directoryContainsLibrary(dir, libName) {
@@ -3932,10 +4362,10 @@ function directoryContainsLibrary(dir, libName) {
3932
4362
  }
3933
4363
  }
3934
4364
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
3935
- if (existsSync6(join10(ortVersionDir, libName)))
4365
+ if (existsSync6(join12(ortVersionDir, libName)))
3936
4366
  return ortVersionDir;
3937
- const libSubdir = join10(ortVersionDir, "lib");
3938
- if (existsSync6(join10(libSubdir, libName)))
4367
+ const libSubdir = join12(ortVersionDir, "lib");
4368
+ if (existsSync6(join12(libSubdir, libName)))
3939
4369
  return libSubdir;
3940
4370
  return ortVersionDir;
3941
4371
  }
@@ -3950,12 +4380,12 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
3950
4380
  } else if (process.platform === "win32") {
3951
4381
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
3952
4382
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
3953
- searchPaths.push(join10(programFiles, "onnxruntime", "lib"), join10(programFiles, "Microsoft ONNX Runtime", "lib"), join10(programFiles, "Microsoft Machine Learning", "lib"), join10(programFilesX86, "onnxruntime", "lib"), ...(() => {
4383
+ searchPaths.push(join12(programFiles, "onnxruntime", "lib"), join12(programFiles, "Microsoft ONNX Runtime", "lib"), join12(programFiles, "Microsoft Machine Learning", "lib"), join12(programFilesX86, "onnxruntime", "lib"), ...(() => {
3954
4384
  const nugetPaths = [];
3955
4385
  const userProfile = process.env.USERPROFILE ?? "";
3956
4386
  if (!userProfile)
3957
4387
  return nugetPaths;
3958
- const nugetPackageDir = join10(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
4388
+ const nugetPackageDir = join12(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
3959
4389
  if (!existsSync6(nugetPackageDir))
3960
4390
  return nugetPaths;
3961
4391
  try {
@@ -3964,7 +4394,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
3964
4394
  continue;
3965
4395
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
3966
4396
  continue;
3967
- nugetPaths.push(join10(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join10(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
4397
+ nugetPaths.push(join12(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join12(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
3968
4398
  }
3969
4399
  } catch (err) {
3970
4400
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -3976,7 +4406,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
3976
4406
  const normalizeCase = process.platform === "win32" || process.platform === "darwin";
3977
4407
  const seen = new Set;
3978
4408
  const uniquePaths = searchPaths.filter((p) => {
3979
- let key = resolve5(p).replace(/[/\\]+$/, "");
4409
+ let key = resolve7(p).replace(/[/\\]+$/, "");
3980
4410
  if (normalizeCase)
3981
4411
  key = key.toLowerCase();
3982
4412
  if (seen.has(key))
@@ -3986,7 +4416,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
3986
4416
  });
3987
4417
  const unknownVersionPaths = [];
3988
4418
  for (const dir of uniquePaths) {
3989
- const libPath = join10(dir, libName);
4419
+ const libPath = join12(dir, libName);
3990
4420
  if (process.platform === "win32") {
3991
4421
  if (!directoryContainsLibrary(dir, libName))
3992
4422
  continue;
@@ -4033,7 +4463,7 @@ async function downloadFileWithCap(url, destPath) {
4033
4463
  if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
4034
4464
  throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
4035
4465
  }
4036
- mkdirSync3(dirname4(destPath), { recursive: true });
4466
+ privateMkdirSync(dirname5(destPath));
4037
4467
  let bytesWritten = 0;
4038
4468
  const guard = new TransformStream({
4039
4469
  transform(chunk, transformController) {
@@ -4047,7 +4477,9 @@ async function downloadFileWithCap(url, destPath) {
4047
4477
  });
4048
4478
  const guarded = res.body.pipeThrough(guard);
4049
4479
  const nodeStream = Readable2.fromWeb(guarded);
4050
- await pipeline2(nodeStream, createWriteStream2(destPath), { signal: controller.signal });
4480
+ await pipeline2(nodeStream, createWriteStream2(destPath, { mode: PRIVATE_FILE_MODE }), {
4481
+ signal: controller.signal
4482
+ });
4051
4483
  } catch (err) {
4052
4484
  try {
4053
4485
  unlinkSync3(destPath);
@@ -4058,31 +4490,35 @@ async function downloadFileWithCap(url, destPath) {
4058
4490
  }
4059
4491
  }
4060
4492
  function validateExtractedTree(stagingRoot) {
4061
- const realRoot = realpathSync2(stagingRoot);
4493
+ const realRoot = realpathSync3(stagingRoot);
4062
4494
  let totalBytes = 0;
4063
4495
  const walk = (dir) => {
4064
4496
  const entries = readdirSync3(dir);
4065
4497
  for (const entry of entries) {
4066
- const fullPath = join10(dir, entry);
4067
- const lst = lstatSync(fullPath);
4498
+ const fullPath = join12(dir, entry);
4499
+ const lst = lstatSync2(fullPath);
4068
4500
  if (lst.isSymbolicLink()) {
4069
4501
  const linkTarget = readlinkSync(fullPath);
4070
- const resolvedTarget = resolve5(dirname4(fullPath), linkTarget);
4071
- const rel = relative(realRoot, resolvedTarget);
4072
- if (rel.startsWith("..") || isAbsolute4(rel) || win32.isAbsolute(rel)) {
4502
+ const resolvedTarget = resolve7(dirname5(fullPath), linkTarget);
4503
+ const rel = relative3(realRoot, resolvedTarget);
4504
+ if (relativePathEscapesRoot(rel) || win322.isAbsolute(rel)) {
4073
4505
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
4074
4506
  }
4075
4507
  continue;
4076
4508
  }
4077
- const rel = relative(realRoot, fullPath);
4078
- if (rel.startsWith("..") || isAbsolute4(rel) || win32.isAbsolute(rel)) {
4509
+ const rel = relative3(realRoot, fullPath);
4510
+ if (relativePathEscapesRoot(rel) || win322.isAbsolute(rel)) {
4079
4511
  throw new Error(`extracted entry ${fullPath} escapes staging root`);
4080
4512
  }
4081
4513
  if (lst.isDirectory()) {
4514
+ if (process.platform !== "win32")
4515
+ chmodSync2(fullPath, PRIVATE_DIRECTORY_MODE);
4082
4516
  walk(fullPath);
4083
4517
  continue;
4084
4518
  }
4085
4519
  if (lst.isFile()) {
4520
+ if (process.platform !== "win32")
4521
+ chmodSync2(fullPath, PRIVATE_FILE_MODE);
4086
4522
  totalBytes += lst.size;
4087
4523
  if (totalBytes > MAX_EXTRACT_BYTES) {
4088
4524
  throw new Error(`extracted size ${totalBytes} exceeds max ${MAX_EXTRACT_BYTES} (decompression bomb defense)`);
@@ -4096,16 +4532,16 @@ async function downloadOnnxRuntime(info, targetDir) {
4096
4532
  const url = `https://github.com/${ORT_REPO}/releases/download/v${ORT_VERSION}/${info.assetName}.${info.archiveType === "tgz" ? "tgz" : "zip"}`;
4097
4533
  log(`Downloading ONNX Runtime v${ORT_VERSION} for ${process.platform}/${process.arch}...`);
4098
4534
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}${randomBytes(4).toString("hex")}`;
4099
- const extractionRoot = join10(tmpDir, "extract");
4100
- const stagedInstallDir = join10(tmpDir, "install");
4535
+ const extractionRoot = join12(tmpDir, "extract");
4536
+ const stagedInstallDir = join12(tmpDir, "install");
4101
4537
  try {
4102
- mkdirSync3(extractionRoot, { recursive: true });
4103
- const archivePath = join10(tmpDir, `onnxruntime.${info.archiveType}`);
4538
+ privateMkdirSync(extractionRoot);
4539
+ const archivePath = join12(tmpDir, `onnxruntime.${info.archiveType}`);
4104
4540
  await downloadFileWithCap(url, archivePath);
4105
- const archiveSha256 = sha256File2(archivePath);
4541
+ const archiveSha256 = await sha256File(archivePath);
4106
4542
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
4107
4543
  if (info.archiveType === "tgz") {
4108
- execTarExtractionSync(["xzf", archivePath, "-C", extractionRoot], 120000);
4544
+ execTarExtractionSync(["xzf", archivePath, "-C", extractionRoot], 120000, true);
4109
4545
  } else {
4110
4546
  await extractZipArchive(archivePath, extractionRoot);
4111
4547
  }
@@ -4113,7 +4549,7 @@ async function downloadOnnxRuntime(info, targetDir) {
4113
4549
  unlinkSync3(archivePath);
4114
4550
  } catch {}
4115
4551
  validateExtractedTree(extractionRoot);
4116
- const extractedDir = join10(extractionRoot, info.assetName, "lib");
4552
+ const extractedDir = join12(extractionRoot, info.assetName, "lib");
4117
4553
  if (!existsSync6(extractedDir)) {
4118
4554
  throw new Error(`Expected directory not found: ${extractedDir}`);
4119
4555
  }
@@ -4121,9 +4557,9 @@ async function downloadOnnxRuntime(info, targetDir) {
4121
4557
  const realFiles = [];
4122
4558
  const symlinks = [];
4123
4559
  for (const libFile of libFiles) {
4124
- const src = join10(extractedDir, libFile);
4560
+ const src = join12(extractedDir, libFile);
4125
4561
  try {
4126
- const stat = lstatSync(src);
4562
+ const stat = lstatSync2(src);
4127
4563
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
4128
4564
  if (stat.isSymbolicLink()) {
4129
4565
  symlinks.push({ name: libFile, target: readlinkSync(src) });
@@ -4136,13 +4572,14 @@ async function downloadOnnxRuntime(info, targetDir) {
4136
4572
  }
4137
4573
  }
4138
4574
  copyOnnxLibraries(info, extractedDir, stagedInstallDir, realFiles, symlinks);
4139
- const libPath = join10(stagedInstallDir, info.libName);
4140
- const libHash = sha256File2(libPath);
4575
+ const libPath = join12(stagedInstallDir, info.libName);
4576
+ const libHash = await sha256File(libPath);
4141
4577
  if (libHash !== info.librarySha256) {
4142
4578
  throw new Error(`onnx runtime library hash mismatch at ${libPath}: sha256 ${libHash}, ` + `expected the pinned ${info.librarySha256} for ${info.assetName}`);
4143
4579
  }
4144
4580
  writeOnnxInstalledMeta(stagedInstallDir, ORT_VERSION, libHash, archiveSha256);
4145
4581
  publishOnnxRuntime(stagedInstallDir, targetDir);
4582
+ writeStampedFileDigest(join12(targetDir, info.libName), libHash);
4146
4583
  rmSync2(tmpDir, { recursive: true, force: true });
4147
4584
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
4148
4585
  return targetDir;
@@ -4180,16 +4617,19 @@ function publishOnnxRuntime(stagedInstallDir, targetDir) {
4180
4617
  }
4181
4618
  }
4182
4619
  }
4183
- function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync2) {
4620
+ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
4184
4621
  const requiredLibs = new Set([info.libName]);
4185
- mkdirSync3(targetDir, { recursive: true });
4622
+ privateMkdirSync(targetDir);
4186
4623
  for (const libFile of realFiles) {
4187
- const src = join10(extractedDir, libFile);
4188
- const dst = join10(targetDir, libFile);
4624
+ const src = join12(extractedDir, libFile);
4625
+ const dst = join12(targetDir, libFile);
4189
4626
  try {
4190
- copyFile(src, dst);
4627
+ if (copyFile === copyFileSync3)
4628
+ privateCopyFileSync(src, dst);
4629
+ else
4630
+ copyFile(src, dst);
4191
4631
  if (process.platform !== "win32") {
4192
- chmodSync2(dst, 493);
4632
+ chmodSync2(dst, PRIVATE_FILE_MODE);
4193
4633
  }
4194
4634
  } catch (copyErr) {
4195
4635
  if (requiredLibs.has(libFile)) {
@@ -4199,14 +4639,14 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
4199
4639
  log(`ORT extract: failed to copy optional ${libFile}: ${copyErr}`);
4200
4640
  }
4201
4641
  }
4202
- const targetRoot = realpathSync2(targetDir);
4642
+ const targetRoot = realpathSync3(targetDir);
4203
4643
  for (const link of symlinks) {
4204
- const dst = join10(targetDir, link.name);
4644
+ const dst = join12(targetDir, link.name);
4205
4645
  try {
4206
4646
  unlinkSync3(dst);
4207
4647
  } catch {}
4208
- const dstForContainment = join10(targetRoot, link.name);
4209
- const resolvedTarget = resolve5(dirname4(dstForContainment), link.target);
4648
+ const dstForContainment = join12(targetRoot, link.name);
4649
+ const resolvedTarget = resolve7(dirname5(dstForContainment), link.target);
4210
4650
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
4211
4651
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
4212
4652
  if (requiredLibs.has(link.name)) {
@@ -4226,7 +4666,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
4226
4666
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
4227
4667
  }
4228
4668
  }
4229
- const requiredPath = join10(targetDir, info.libName);
4669
+ const requiredPath = join12(targetDir, info.libName);
4230
4670
  if (!existsSync6(requiredPath)) {
4231
4671
  rmSync2(targetDir, { recursive: true, force: true });
4232
4672
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
@@ -4250,13 +4690,16 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
4250
4690
  ...sha256 ? { sha256 } : {},
4251
4691
  archiveSha256
4252
4692
  };
4253
- writeFileSync3(join10(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
4693
+ writeFileSync3(join12(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), {
4694
+ encoding: "utf8",
4695
+ mode: PRIVATE_FILE_MODE
4696
+ });
4254
4697
  } catch (err) {
4255
4698
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
4256
4699
  }
4257
4700
  }
4258
4701
  function readOnnxInstalledMeta(installDir) {
4259
- const path = join10(installDir, ONNX_INSTALLED_META_FILE);
4702
+ const path = join12(installDir, ONNX_INSTALLED_META_FILE);
4260
4703
  try {
4261
4704
  if (!statSync5(path).isFile())
4262
4705
  return null;
@@ -4274,21 +4717,16 @@ function readOnnxInstalledMeta(installDir) {
4274
4717
  return null;
4275
4718
  }
4276
4719
  }
4277
- function sha256File2(path) {
4278
- const hash = createHash4("sha256");
4279
- hash.update(readFileSync6(path));
4280
- return hash.digest("hex");
4281
- }
4282
4720
  function acquireLock(lockPath) {
4283
4721
  const tryClaim = () => {
4284
4722
  try {
4285
- const fd = openSync4(lockPath, "wx");
4723
+ const fd = openSync6(lockPath, "wx", PRIVATE_FILE_MODE);
4286
4724
  try {
4287
4725
  writeFileSync3(fd, `${process.pid}
4288
4726
  ${new Date().toISOString()}
4289
4727
  `);
4290
4728
  } finally {
4291
- closeSync4(fd);
4729
+ closeSync6(fd);
4292
4730
  }
4293
4731
  return true;
4294
4732
  } catch (err) {
@@ -4395,9 +4833,12 @@ function isProcessAlive2(pid) {
4395
4833
  var ORT_VERSION = "1.24.4", ORT_REPO = "microsoft/onnxruntime", MAX_DOWNLOAD_BYTES2, MAX_EXTRACT_BYTES, ONNX_LOCK_FILE = ".aft-onnx-installing", ONNX_INSTALLED_META_FILE = ".aft-onnx-installed", STALE_LOCK_MS, LOCK_WAIT_MS, LOCK_POLL_MS = 1000, ORT_PLATFORM_MAP, lastInstallFailure = null, inflightResolutions, REQUIRED_ORT_MAJOR = 1, REQUIRED_ORT_MIN_MINOR = 20, INVALID_ORT_VERSION = "<invalid>";
4396
4834
  var init_onnx_runtime = __esm(() => {
4397
4835
  init_active_logger();
4836
+ init_binary_identity();
4398
4837
  init_child_process();
4399
4838
  init_onnx_probe();
4839
+ init_path_display();
4400
4840
  init_platform();
4841
+ init_private_storage();
4401
4842
  init_tar_executable();
4402
4843
  MAX_DOWNLOAD_BYTES2 = 256 * 1024 * 1024;
4403
4844
  MAX_EXTRACT_BYTES = 1 * 1024 * 1024 * 1024;
@@ -4468,8 +4909,8 @@ var init_path_aliases = __esm(() => {
4468
4909
  });
4469
4910
 
4470
4911
  // ../aft-bridge/dist/path-lookup.js
4471
- import { accessSync, constants, statSync as statSync6 } from "node:fs";
4472
- import { delimiter, resolve as resolve6 } from "node:path";
4912
+ import { accessSync, constants as constants2, statSync as statSync6 } from "node:fs";
4913
+ import { delimiter, resolve as resolve8 } from "node:path";
4473
4914
  function executableNames(name, platform) {
4474
4915
  if (platform !== "win32")
4475
4916
  return [name];
@@ -4485,12 +4926,12 @@ function findExecutablesOnPath(name, options = {}) {
4485
4926
  if (!directory)
4486
4927
  continue;
4487
4928
  for (const candidateName of executableNames(name, platform)) {
4488
- const candidate = resolve6(directory, candidateName);
4929
+ const candidate = resolve8(directory, candidateName);
4489
4930
  if (seen.has(candidate))
4490
4931
  continue;
4491
4932
  seen.add(candidate);
4492
4933
  try {
4493
- accessSync(candidate, platform === "win32" ? constants.F_OK : constants.X_OK);
4934
+ accessSync(candidate, platform === "win32" ? constants2.F_OK : constants2.X_OK);
4494
4935
  if (statSync6(candidate).isFile())
4495
4936
  hits.push(candidate);
4496
4937
  } catch {}
@@ -4528,6 +4969,7 @@ var init_dist2 = __esm(() => {
4528
4969
  init_downloader();
4529
4970
  init_durable_log();
4530
4971
  init_error_contract();
4972
+ init_lifecycle_registry();
4531
4973
  init_location_lifecycle();
4532
4974
  init_message_detach();
4533
4975
  init_migration();
@@ -4536,6 +4978,7 @@ var init_dist2 = __esm(() => {
4536
4978
  init_onnx_probe();
4537
4979
  init_onnx_runtime();
4538
4980
  init_path_aliases();
4981
+ init_path_display();
4539
4982
  init_path_lookup();
4540
4983
  init_paths();
4541
4984
  init_platform();
@@ -4566,8 +5009,8 @@ var init_paths2 = __esm(() => {
4566
5009
  // src/lib/binary-probe.ts
4567
5010
  import { existsSync as existsSync7, readdirSync as readdirSync4 } from "node:fs";
4568
5011
  import { createRequire } from "node:module";
4569
- import { homedir as homedir8 } from "node:os";
4570
- import { join as join11 } from "node:path";
5012
+ import { homedir as homedir10 } from "node:os";
5013
+ import { join as join13 } from "node:path";
4571
5014
  async function loadPluginVersion() {
4572
5015
  try {
4573
5016
  const bridge = await Promise.resolve().then(() => (init_dist2(), {}));
@@ -4697,7 +5140,7 @@ function newestCachedBinary(cacheDir, binaryName) {
4697
5140
  const version = entry.match(CACHE_VERSION_DIR)?.[1];
4698
5141
  if (!version)
4699
5142
  continue;
4700
- const path = join11(cacheDir, entry, binaryName);
5143
+ const path = join13(cacheDir, entry, binaryName);
4701
5144
  try {
4702
5145
  if (!existsSync7(path))
4703
5146
  continue;
@@ -4718,7 +5161,7 @@ function cacheLocation(preferredVersion) {
4718
5161
  const tag = preferredVersion.startsWith("v") ? preferredVersion : `v${preferredVersion}`;
4719
5162
  return {
4720
5163
  label,
4721
- paths: [join11(cacheDir, tag, binaryName)],
5164
+ paths: [join13(cacheDir, tag, binaryName)],
4722
5165
  emptyReason: `no ${tag}/${binaryName} under ${cacheDir} (${installedHere})`
4723
5166
  };
4724
5167
  }
@@ -4762,7 +5205,7 @@ function pathLocation() {
4762
5205
  };
4763
5206
  }
4764
5207
  function cargoLocation() {
4765
- const path = join11(homedir8(), ".cargo", "bin", getAftBinaryName());
5208
+ const path = join13(homedir10(), ".cargo", "bin", getAftBinaryName());
4766
5209
  return { label: "cargo install", paths: [path], emptyReason: `no ${path}` };
4767
5210
  }
4768
5211
  function aftBinarySearchLocations(preferredVersion) {
@@ -4815,7 +5258,7 @@ var init_binary_probe = __esm(async () => {
4815
5258
 
4816
5259
  // src/lib/fs-util.ts
4817
5260
  import { existsSync as existsSync8, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
4818
- import { join as join12 } from "node:path";
5261
+ import { join as join14 } from "node:path";
4819
5262
  function dirSize(path) {
4820
5263
  if (!existsSync8(path)) {
4821
5264
  return 0;
@@ -4829,7 +5272,7 @@ function dirSize(path) {
4829
5272
  }
4830
5273
  let total = 0;
4831
5274
  for (const entry of readdirSync5(path)) {
4832
- total += dirSize(join12(path, entry));
5275
+ total += dirSize(join14(path, entry));
4833
5276
  }
4834
5277
  return total;
4835
5278
  }
@@ -4847,27 +5290,27 @@ var init_fs_util = () => {};
4847
5290
 
4848
5291
  // src/lib/omp-paths.ts
4849
5292
  import { existsSync as existsSync9 } from "node:fs";
4850
- import { homedir as homedir9 } from "node:os";
4851
- import { join as join13, resolve as resolve7 } from "node:path";
5293
+ import { homedir as homedir11 } from "node:os";
5294
+ import { join as join15, resolve as resolve9 } from "node:path";
4852
5295
  function envFirstHomeDir() {
4853
- return process.env.HOME?.trim() || homedir9();
5296
+ return process.env.HOME?.trim() || homedir11();
4854
5297
  }
4855
5298
  function resolveOmpPaths() {
4856
5299
  const normalizedProfile = (process.env.OMP_PROFILE ?? process.env.PI_PROFILE)?.trim();
4857
5300
  const profile = normalizedProfile && normalizedProfile !== "default" && /^[a-z0-9][a-z0-9._-]{0,63}$/.test(normalizedProfile) ? normalizedProfile : undefined;
4858
5301
  const configDirName = process.env.PI_CONFIG_DIR?.trim() || ".omp";
4859
- const baseConfigRoot = join13(envFirstHomeDir(), configDirName);
4860
- const configRoot = profile ? join13(baseConfigRoot, "profiles", profile) : baseConfigRoot;
4861
- const defaultAgentDir = join13(configRoot, "agent");
5302
+ const baseConfigRoot = join15(envFirstHomeDir(), configDirName);
5303
+ const configRoot = profile ? join15(baseConfigRoot, "profiles", profile) : baseConfigRoot;
5304
+ const defaultAgentDir = join15(configRoot, "agent");
4862
5305
  const configuredAgentDir = profile ? undefined : process.env.PI_CODING_AGENT_DIR?.trim();
4863
- const agentDir = configuredAgentDir ? resolve7(configuredAgentDir) : defaultAgentDir;
5306
+ const agentDir = configuredAgentDir ? resolve9(configuredAgentDir) : defaultAgentDir;
4864
5307
  const canUseXdg = (process.platform === "linux" || process.platform === "darwin") && agentDir === defaultAgentDir;
4865
5308
  let dataRoot = configRoot;
4866
5309
  if (canUseXdg) {
4867
5310
  const xdgDataHome = process.env.XDG_DATA_HOME?.trim();
4868
5311
  if (xdgDataHome) {
4869
- const appRoot = join13(xdgDataHome, "omp");
4870
- const candidate = profile ? join13(appRoot, "profiles", profile) : appRoot;
5312
+ const appRoot = join15(xdgDataHome, "omp");
5313
+ const candidate = profile ? join15(appRoot, "profiles", profile) : appRoot;
4871
5314
  if (existsSync9(candidate))
4872
5315
  dataRoot = candidate;
4873
5316
  }
@@ -4878,8 +5321,8 @@ function resolveOmpPaths() {
4878
5321
  agentDir,
4879
5322
  dataRoot,
4880
5323
  dataAgentRoot,
4881
- pluginsDir: join13(dataRoot, "plugins"),
4882
- sessionsRoot: join13(dataAgentRoot, "sessions")
5324
+ pluginsDir: join15(dataRoot, "plugins"),
5325
+ sessionsRoot: join15(dataAgentRoot, "sessions")
4883
5326
  };
4884
5327
  }
4885
5328
  function getOmpAgentDir() {
@@ -4889,7 +5332,7 @@ function getOmpPluginsDir() {
4889
5332
  return resolveOmpPaths().pluginsDir;
4890
5333
  }
4891
5334
  function getOmpPluginsLockPath() {
4892
- return join13(getOmpPluginsDir(), "omp-plugins.lock.json");
5335
+ return join15(getOmpPluginsDir(), "omp-plugins.lock.json");
4893
5336
  }
4894
5337
  function getOmpSessionsRoot() {
4895
5338
  return resolveOmpPaths().sessionsRoot;
@@ -4901,21 +5344,21 @@ function getOmpPackageDir() {
4901
5344
  if (value === "~")
4902
5345
  return envFirstHomeDir();
4903
5346
  if (value.startsWith("~/") || value.startsWith("~\\")) {
4904
- return resolve7(envFirstHomeDir(), value.slice(2));
5347
+ return resolve9(envFirstHomeDir(), value.slice(2));
4905
5348
  }
4906
- return resolve7(value);
5349
+ return resolve9(value);
4907
5350
  }
4908
5351
  var init_omp_paths = () => {};
4909
5352
 
4910
5353
  // src/lib/omp-helpers.ts
4911
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync10, readFileSync as readFileSync7, statSync as statSync8 } from "node:fs";
4912
- import { homedir as homedir10 } from "node:os";
4913
- import { delimiter as delimiter2, extname, join as join14, resolve as resolve8 } from "node:path";
5354
+ import { accessSync as accessSync2, constants as constants3, existsSync as existsSync10, readFileSync as readFileSync7, statSync as statSync8 } from "node:fs";
5355
+ import { homedir as homedir12 } from "node:os";
5356
+ import { delimiter as delimiter2, extname, join as join16, resolve as resolve10 } from "node:path";
4914
5357
  function isExecutableFile(path, platform = process.platform) {
4915
5358
  try {
4916
5359
  if (!existsSync10(path) || !statSync8(path).isFile())
4917
5360
  return false;
4918
- accessSync2(path, platform === "win32" ? constants2.F_OK : constants2.X_OK);
5361
+ accessSync2(path, platform === "win32" ? constants3.F_OK : constants3.X_OK);
4919
5362
  return true;
4920
5363
  } catch {
4921
5364
  return false;
@@ -4930,7 +5373,7 @@ function findOnPath(name, pathValue = process.env.PATH ?? "", platform = process
4930
5373
  if (!directory)
4931
5374
  continue;
4932
5375
  for (const candidateName of executableNames2(name, platform)) {
4933
- const candidate = resolve8(directory, candidateName);
5376
+ const candidate = resolve10(directory, candidateName);
4934
5377
  if (isExecutableFile(candidate, platform))
4935
5378
  return candidate;
4936
5379
  }
@@ -4942,10 +5385,10 @@ function detectOmpPackageCli() {
4942
5385
  if (!packageDir || !findOnPath("bun"))
4943
5386
  return null;
4944
5387
  try {
4945
- const manifest = JSON.parse(readFileSync7(join14(packageDir, "package.json"), "utf8"));
5388
+ const manifest = JSON.parse(readFileSync7(join16(packageDir, "package.json"), "utf8"));
4946
5389
  if (manifest.name !== OMP_HOST_PACKAGE)
4947
5390
  return null;
4948
- const cli = join14(packageDir, "dist", "cli.js");
5391
+ const cli = join16(packageDir, "dist", "cli.js");
4949
5392
  return existsSync10(cli) ? cli : null;
4950
5393
  } catch {
4951
5394
  return null;
@@ -4966,13 +5409,13 @@ function getOmpCommandInvocation(ompPath, args) {
4966
5409
  }
4967
5410
  function getOmpFallbackCandidates(platform, home, appData) {
4968
5411
  if (platform !== "win32") {
4969
- return [join14(home, ".bun", "bin", "omp"), join14(home, ".local", "bin", "omp")];
5412
+ return [join16(home, ".bun", "bin", "omp"), join16(home, ".local", "bin", "omp")];
4970
5413
  }
4971
5414
  const npmRoot = appData?.trim();
4972
5415
  return [
4973
- ...npmRoot ? [join14(npmRoot, "npm", "omp.cmd"), join14(npmRoot, "npm", "omp.exe")] : [],
4974
- join14(home, ".bun", "bin", "omp.exe"),
4975
- join14(home, ".bun", "bin", "omp.cmd")
5416
+ ...npmRoot ? [join16(npmRoot, "npm", "omp.cmd"), join16(npmRoot, "npm", "omp.exe")] : [],
5417
+ join16(home, ".bun", "bin", "omp.exe"),
5418
+ join16(home, ".bun", "bin", "omp.cmd")
4976
5419
  ];
4977
5420
  }
4978
5421
  function detectOmpBinary() {
@@ -4982,7 +5425,7 @@ function detectOmpBinary() {
4982
5425
  const fromPackage = detectOmpPackageCli();
4983
5426
  if (fromPackage)
4984
5427
  return { path: fromPackage, source: "package" };
4985
- const home = process.env.HOME?.trim() || homedir10();
5428
+ const home = process.env.HOME?.trim() || homedir12();
4986
5429
  const candidate = getOmpFallbackCandidates(process.platform, home, process.env.APPDATA).find((path) => isExecutableFile(path));
4987
5430
  return candidate ? { path: candidate, source: "home" } : null;
4988
5431
  }
@@ -5055,7 +5498,7 @@ var init_omp_helpers = __esm(() => {
5055
5498
 
5056
5499
  // src/adapters/omp.ts
5057
5500
  import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
5058
- import { join as join15 } from "node:path";
5501
+ import { join as join17 } from "node:path";
5059
5502
 
5060
5503
  class OmpAdapter {
5061
5504
  kind = "omp";
@@ -5197,12 +5640,12 @@ class OmpAdapter {
5197
5640
  describeStorageSubtrees() {
5198
5641
  const storage = this.getStorageDir();
5199
5642
  return {
5200
- index: dirSize(join15(storage, "index")),
5201
- semantic: dirSize(join15(storage, "semantic")),
5202
- backups: dirSize(join15(storage, "backups")),
5203
- url_cache: dirSize(join15(storage, "url_cache")),
5204
- onnxruntime: dirSize(join15(storage, "onnxruntime")),
5205
- logs: dirSize(join15(storage, "logs"))
5643
+ index: dirSize(join17(storage, "index")),
5644
+ semantic: dirSize(join17(storage, "semantic")),
5645
+ backups: dirSize(join17(storage, "backups")),
5646
+ url_cache: dirSize(join17(storage, "url_cache")),
5647
+ onnxruntime: dirSize(join17(storage, "onnxruntime")),
5648
+ logs: dirSize(join17(storage, "logs"))
5206
5649
  };
5207
5650
  }
5208
5651
  readRuntimeEnabled(configPath) {
@@ -5240,8 +5683,8 @@ var init_omp = __esm(() => {
5240
5683
 
5241
5684
  // src/lib/fs-errors.ts
5242
5685
  import { existsSync as existsSync12, statSync as statSync9 } from "node:fs";
5243
- import { homedir as homedir11 } from "node:os";
5244
- import { dirname as dirname5, resolve as resolve9, sep } from "node:path";
5686
+ import { homedir as homedir13 } from "node:os";
5687
+ import { dirname as dirname6, resolve as resolve11, sep as sep2 } from "node:path";
5245
5688
  function errorCode(error) {
5246
5689
  if (typeof error === "object" && error !== null && "code" in error) {
5247
5690
  const code = error.code;
@@ -5271,10 +5714,8 @@ function errorPath(error) {
5271
5714
  const native = message.match(/\b(?:write|update|create|open|read|mkdir|rename)\s+((?:[A-Za-z]:)?[\\/][^:\n]+?):\s/i);
5272
5715
  return native?.[1] ?? null;
5273
5716
  }
5274
- function tildePath(path, home = homedir11()) {
5275
- if (path === home)
5276
- return "~";
5277
- return path.startsWith(home + sep) ? `~${path.slice(home.length)}` : path;
5717
+ function tildePath(path, home = homedir13()) {
5718
+ return shortenHomePath(path, home);
5278
5719
  }
5279
5720
  function shellPath(path) {
5280
5721
  if (/^[\w@%+=:,./~-]+$/.test(path))
@@ -5284,10 +5725,10 @@ function shellPath(path) {
5284
5725
  return `'${path.replace(/'/g, "'\\''")}'`;
5285
5726
  }
5286
5727
  function describePermissionProblem(target, facts = defaultFacts) {
5287
- const home = resolve9(facts.home());
5288
- let existing = resolve9(target);
5289
- while (!facts.exists(existing) && dirname5(existing) !== existing)
5290
- existing = dirname5(existing);
5728
+ const home = resolve11(facts.home());
5729
+ let existing = resolve11(target);
5730
+ while (!facts.exists(existing) && dirname6(existing) !== existing)
5731
+ existing = dirname6(existing);
5291
5732
  const ownerUid = facts.ownerUid(existing);
5292
5733
  const me = facts.currentUid();
5293
5734
  const shownTarget = tildePath(target, home);
@@ -5301,8 +5742,8 @@ function describePermissionProblem(target, facts = defaultFacts) {
5301
5742
  }
5302
5743
  let widest = existing;
5303
5744
  while (true) {
5304
- const parent = dirname5(widest);
5305
- if (parent === widest || parent === home || !parent.startsWith(home + sep))
5745
+ const parent = dirname6(widest);
5746
+ if (parent === widest || parent === home || !parent.startsWith(home + sep2))
5306
5747
  break;
5307
5748
  if (facts.ownerUid(parent) !== ownerUid)
5308
5749
  break;
@@ -5352,7 +5793,7 @@ var init_fs_errors = __esm(() => {
5352
5793
  return false;
5353
5794
  }
5354
5795
  },
5355
- home: () => homedir11()
5796
+ home: () => homedir13()
5356
5797
  };
5357
5798
  });
5358
5799
 
@@ -13115,7 +13556,7 @@ var require_src2 = __commonJS(function(exports, module) {
13115
13556
 
13116
13557
  // src/lib/jsonc.ts
13117
13558
  import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
13118
- import { dirname as dirname6 } from "node:path";
13559
+ import { dirname as dirname7 } from "node:path";
13119
13560
  function detectJsoncFile(configDir, baseName) {
13120
13561
  const jsoncPath = `${configDir}/${baseName}.jsonc`;
13121
13562
  const jsonPath = `${configDir}/${baseName}.json`;
@@ -13143,7 +13584,7 @@ function readJsoncFile(path) {
13143
13584
  }
13144
13585
  }
13145
13586
  function writeJsoncFile(path, value, format = "json") {
13146
- mkdirSync4(dirname6(path), { recursive: true });
13587
+ mkdirSync4(dirname7(path), { recursive: true });
13147
13588
  const serialized = format === "jsonc" ? import_comment_json.stringify(value, null, 2) : JSON.stringify(value, null, 2);
13148
13589
  writeFileSync4(path, `${serialized}
13149
13590
  `);
@@ -13359,15 +13800,16 @@ function pluginConfigNeedsUpdate(value, version, hasLocalAftEntry = () => false,
13359
13800
  return !pluginEntryFitsKey(list[local.index], key);
13360
13801
  return true;
13361
13802
  }
13362
- function hostShellPluginDisabled(value) {
13803
+ function hostToolPluginDisabled(value, hostTool) {
13363
13804
  const list = value?.plugins;
13364
- return Array.isArray(list) && list.includes(OPENCODE_HOST_SHELL_DISABLE_ENTRY);
13805
+ return Array.isArray(list) && list.includes(OPENCODE_HOST_TOOLS[hostTool].disableEntry);
13365
13806
  }
13366
- function setHostShellPluginDisabled(value, disabled) {
13807
+ function setHostToolPluginDisabled(value, hostTool, disabled) {
13808
+ const entry = OPENCODE_HOST_TOOLS[hostTool].disableEntry;
13367
13809
  const existing = Array.isArray(value.plugins) ? value.plugins : null;
13368
13810
  const indexes = [];
13369
13811
  existing?.forEach((entry, index) => {
13370
- if (entry === OPENCODE_HOST_SHELL_DISABLE_ENTRY)
13812
+ if (entry === OPENCODE_HOST_TOOLS[hostTool].disableEntry)
13371
13813
  indexes.push(index);
13372
13814
  });
13373
13815
  if (disabled ? indexes.length === 1 : indexes.length === 0)
@@ -13380,17 +13822,19 @@ function setHostShellPluginDisabled(value, disabled) {
13380
13822
  list.splice(remove[index], 1);
13381
13823
  }
13382
13824
  if (disabled && indexes.length === 0)
13383
- list.push(OPENCODE_HOST_SHELL_DISABLE_ENTRY);
13825
+ list.push(entry);
13384
13826
  return { changed: true };
13385
13827
  }
13386
- function aftBashEnabled(userConfig) {
13828
+ function aftHostReplacementEnabled(userConfig, hostTool) {
13387
13829
  if (!userConfig)
13388
13830
  return true;
13389
13831
  if (userConfig.enabled === false)
13390
13832
  return false;
13391
13833
  const disabled = userConfig.disabled_tools;
13392
- if (Array.isArray(disabled) && disabled.includes("bash"))
13834
+ if (Array.isArray(disabled) && disabled.includes(OPENCODE_HOST_TOOLS[hostTool].aftTool))
13393
13835
  return false;
13836
+ if (hostTool !== "shell")
13837
+ return true;
13394
13838
  const bash = userConfig.bash;
13395
13839
  if (bash === false)
13396
13840
  return false;
@@ -13399,30 +13843,35 @@ function aftBashEnabled(userConfig) {
13399
13843
  }
13400
13844
  return true;
13401
13845
  }
13402
- var AFT_OPENCODE_PACKAGE = "@cortexkit/aft-opencode", MODERN_V1_VERSION, EXACT_VERSION, OPENCODE_HOST_SHELL_DISABLE_ENTRY = "-opencode.tool.shell";
13846
+ var AFT_OPENCODE_PACKAGE = "@cortexkit/aft-opencode", MODERN_V1_VERSION, EXACT_VERSION, OPENCODE_HOST_SHELL_DISABLE_ENTRY = "-opencode.tool.shell", OPENCODE_HOST_PATCH_DISABLE_ENTRY = "-opencode.tool.patch", OPENCODE_HOST_TOOLS, OPENCODE_HOST_TOOL_NAMES;
13403
13847
  var init_opencode_config = __esm(() => {
13404
13848
  init_opencode_version();
13405
13849
  MODERN_V1_VERSION = opencode_version_default.trim();
13406
13850
  EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
13851
+ OPENCODE_HOST_TOOLS = {
13852
+ shell: { aftTool: "bash", disableEntry: OPENCODE_HOST_SHELL_DISABLE_ENTRY },
13853
+ patch: { aftTool: "apply_patch", disableEntry: OPENCODE_HOST_PATCH_DISABLE_ENTRY }
13854
+ };
13855
+ OPENCODE_HOST_TOOL_NAMES = Object.keys(OPENCODE_HOST_TOOLS);
13407
13856
  });
13408
13857
 
13409
13858
  // src/setup/host-generation.ts
13410
- import { createHash as createHash5 } from "node:crypto";
13859
+ import { createHash as createHash4 } from "node:crypto";
13411
13860
  import {
13412
- closeSync as closeSync5,
13861
+ closeSync as closeSync7,
13413
13862
  existsSync as existsSync14,
13414
13863
  mkdirSync as mkdirSync5,
13415
13864
  mkdtempSync,
13416
- openSync as openSync5,
13865
+ openSync as openSync7,
13417
13866
  readdirSync as readdirSync6,
13418
13867
  readFileSync as readFileSync10,
13419
- readSync as readSync3,
13420
- realpathSync as realpathSync3,
13868
+ readSync as readSync5,
13869
+ realpathSync as realpathSync4,
13421
13870
  rmSync as rmSync3,
13422
13871
  statSync as statSync10
13423
13872
  } from "node:fs";
13424
- import { homedir as homedir12, tmpdir as tmpdir2 } from "node:os";
13425
- import { dirname as dirname7, join as join16, parse } from "node:path";
13873
+ import { homedir as homedir14, tmpdir as tmpdir3 } from "node:os";
13874
+ import { dirname as dirname8, join as join18, parse as parse2 } from "node:path";
13426
13875
  function findExecutableOnPath2(name, pathValue = process.env.PATH ?? "", platform = process.platform) {
13427
13876
  return findExecutableOnPath(name, { pathValue, platform });
13428
13877
  }
@@ -13437,31 +13886,63 @@ function packageMetadataAt(path, expectedName) {
13437
13886
  function packageMetadataNearExecutable(executable, expectedName) {
13438
13887
  let current;
13439
13888
  try {
13440
- current = dirname7(realpathSync3(executable));
13889
+ current = dirname8(realpathSync4(executable));
13441
13890
  } catch {
13442
- current = dirname7(executable);
13891
+ current = dirname8(executable);
13443
13892
  }
13444
13893
  while (true) {
13445
- const direct = packageMetadataAt(join16(current, "package.json"), expectedName);
13894
+ const direct = packageMetadataAt(join18(current, "package.json"), expectedName);
13446
13895
  if (direct)
13447
13896
  return direct;
13448
- const parent = dirname7(current);
13449
- if (parent === current || current === parse(current).root)
13897
+ const parent = dirname8(current);
13898
+ if (parent === current || current === parse2(current).root)
13450
13899
  return null;
13451
13900
  current = parent;
13452
13901
  }
13453
13902
  }
13903
+ function npmLauncherTarget(launcher) {
13904
+ let source;
13905
+ try {
13906
+ if (statSync10(launcher).size > LAUNCHER_MAX_BYTES)
13907
+ return null;
13908
+ source = readFileSync10(launcher, "utf8");
13909
+ } catch {
13910
+ return null;
13911
+ }
13912
+ const operands = [...source.matchAll(CMD_LAUNCHER_PATH)];
13913
+ if (operands.length === 0)
13914
+ operands.push(...source.matchAll(SH_LAUNCHER_PATH));
13915
+ const relativeTarget = operands.at(-1)?.[1];
13916
+ if (!relativeTarget)
13917
+ return null;
13918
+ const target = join18(dirname8(launcher), ...relativeTarget.split(/[\\/]+/).filter(Boolean));
13919
+ try {
13920
+ return statSync10(target).isFile() ? target : null;
13921
+ } catch {
13922
+ return null;
13923
+ }
13924
+ }
13925
+ function hostLaunchPath(executable, platform) {
13926
+ const isBatch = BATCH_FILE.test(executable);
13927
+ const isScript = isBatch || platform === "win32" && !/\.(?:exe|com)$/i.test(executable);
13928
+ if (!isScript)
13929
+ return executable;
13930
+ const target = npmLauncherTarget(executable);
13931
+ if (target)
13932
+ return target;
13933
+ return isBatch ? null : executable;
13934
+ }
13454
13935
  function packageVersion(metadata) {
13455
13936
  return typeof metadata?.version === "string" && metadata.version.length > 0 ? metadata.version : null;
13456
13937
  }
13457
13938
  function hashFileBytes(hash, path, size) {
13458
13939
  const buffer = Buffer.allocUnsafe(Math.min(Math.max(size, 1), PARTIAL_CONTENT_WINDOW_BYTES));
13459
- const descriptor = openSync5(path, "r");
13940
+ const descriptor = openSync7(path, "r");
13460
13941
  try {
13461
13942
  if (size <= FULL_CONTENT_HASH_MAX_BYTES) {
13462
13943
  let position = 0;
13463
13944
  while (position < size) {
13464
- const read = readSync3(descriptor, buffer, 0, buffer.length, position);
13945
+ const read = readSync5(descriptor, buffer, 0, buffer.length, position);
13465
13946
  if (read <= 0)
13466
13947
  break;
13467
13948
  hash.update(buffer.subarray(0, read));
@@ -13470,19 +13951,19 @@ function hashFileBytes(hash, path, size) {
13470
13951
  return;
13471
13952
  }
13472
13953
  hash.update("partial\x00");
13473
- const head = readSync3(descriptor, buffer, 0, buffer.length, 0);
13954
+ const head = readSync5(descriptor, buffer, 0, buffer.length, 0);
13474
13955
  hash.update(buffer.subarray(0, Math.max(head, 0)));
13475
13956
  const tailStart = Math.max(size - PARTIAL_CONTENT_WINDOW_BYTES, 0);
13476
- const tail = readSync3(descriptor, buffer, 0, buffer.length, tailStart);
13957
+ const tail = readSync5(descriptor, buffer, 0, buffer.length, tailStart);
13477
13958
  hash.update(buffer.subarray(0, Math.max(tail, 0)));
13478
13959
  } finally {
13479
- closeSync5(descriptor);
13960
+ closeSync7(descriptor);
13480
13961
  }
13481
13962
  }
13482
13963
  function snapshotTree(path) {
13483
13964
  if (!existsSync14(path))
13484
13965
  return "missing";
13485
- const hash = createHash5("sha256");
13966
+ const hash = createHash4("sha256");
13486
13967
  const visit = (current, relativePath) => {
13487
13968
  let info;
13488
13969
  try {
@@ -13494,7 +13975,7 @@ function snapshotTree(path) {
13494
13975
  hash.update(`${relativePath}\x00${info.mode}\x00${info.size}\x00${info.mtimeMs}\x00`);
13495
13976
  if (info.isDirectory()) {
13496
13977
  for (const entry of readdirSync6(current).sort()) {
13497
- visit(join16(current, entry), join16(relativePath, entry));
13978
+ visit(join18(current, entry), join18(relativePath, entry));
13498
13979
  }
13499
13980
  return;
13500
13981
  }
@@ -13510,31 +13991,34 @@ function snapshotTree(path) {
13510
13991
  return hash.digest("hex");
13511
13992
  }
13512
13993
  function snapshotOperatorState(operatorHome) {
13513
- const database = join16(operatorHome, ".local", "share", "opencode", "opencode.db");
13994
+ const database = join18(operatorHome, ".local", "share", "opencode", "opencode.db");
13514
13995
  return JSON.stringify({
13515
13996
  database: snapshotTree(database),
13516
13997
  databaseWal: snapshotTree(`${database}-wal`),
13517
13998
  databaseShm: snapshotTree(`${database}-shm`),
13518
- logs: snapshotTree(join16(operatorHome, ".local", "share", "opencode", "log"))
13999
+ logs: snapshotTree(join18(operatorHome, ".local", "share", "opencode", "log"))
13519
14000
  });
13520
14001
  }
13521
14002
  function probeCreatedIsolatedState(dataRoot, stateRoot) {
13522
14003
  return [dataRoot, stateRoot].some((root) => {
13523
- const opencodeRoot = join16(root, "opencode");
13524
- const database = join16(opencodeRoot, "opencode.db");
13525
- return [database, `${database}-wal`, `${database}-shm`, join16(opencodeRoot, "log")].some(existsSync14);
14004
+ const opencodeRoot = join18(root, "opencode");
14005
+ const database = join18(opencodeRoot, "opencode.db");
14006
+ return [database, `${database}-wal`, `${database}-shm`, join18(opencodeRoot, "log")].some(existsSync14);
13526
14007
  });
13527
14008
  }
13528
14009
  function probeOpenCodeV1Version(executable, options = {}) {
13529
- const operatorHome = options.operatorHome ?? homedir12();
14010
+ const launchPath = hostLaunchPath(executable, options.platform ?? process.platform);
14011
+ if (launchPath === null)
14012
+ return null;
14013
+ const operatorHome = options.operatorHome ?? homedir14();
13530
14014
  const before = snapshotOperatorState(operatorHome);
13531
- const root = mkdtempSync(join16(options.tempParent ?? tmpdir2(), "aft-opencode-probe-"));
13532
- const home = join16(root, "home");
13533
- const config = join16(root, "config");
13534
- const data = join16(root, "data");
13535
- const state = join16(root, "state");
13536
- const cache = join16(root, "cache");
13537
- const project = join16(root, "project");
14015
+ const root = mkdtempSync(join18(options.tempParent ?? tmpdir3(), "aft-opencode-probe-"));
14016
+ const home = join18(root, "home");
14017
+ const config = join18(root, "config");
14018
+ const data = join18(root, "data");
14019
+ const state = join18(root, "state");
14020
+ const cache = join18(root, "cache");
14021
+ const project = join18(root, "project");
13538
14022
  for (const directory of [home, config, data, state, cache, project]) {
13539
14023
  mkdirSync5(directory, { recursive: true });
13540
14024
  }
@@ -13545,7 +14029,7 @@ function probeOpenCodeV1Version(executable, options = {}) {
13545
14029
  XDG_DATA_HOME: data,
13546
14030
  XDG_STATE_HOME: state,
13547
14031
  XDG_CACHE_HOME: cache,
13548
- TMPDIR: join16(root, "tmp")
14032
+ TMPDIR: join18(root, "tmp")
13549
14033
  };
13550
14034
  mkdirSync5(env.TMPDIR, { recursive: true });
13551
14035
  delete env.OPENCODE_CONFIG;
@@ -13555,7 +14039,7 @@ function probeOpenCodeV1Version(executable, options = {}) {
13555
14039
  let result;
13556
14040
  let probeError;
13557
14041
  try {
13558
- result = (options.spawn ?? spawnSync)(executable, ["--standalone", "--version"], {
14042
+ result = (options.spawn ?? spawnSync)(launchPath, ["--standalone", "--version"], {
13559
14043
  cwd: project,
13560
14044
  encoding: "utf8",
13561
14045
  env,
@@ -13605,7 +14089,7 @@ function isV2Version(version) {
13605
14089
  }
13606
14090
  function resolvedPath(executable) {
13607
14091
  try {
13608
- return realpathSync3(executable);
14092
+ return realpathSync4(executable);
13609
14093
  } catch {
13610
14094
  return executable;
13611
14095
  }
@@ -13614,13 +14098,18 @@ function detectOpenCodeHostGeneration(dependencies = {}) {
13614
14098
  const findExecutable = dependencies.findExecutable ?? ((name) => findExecutableOnPath2(name, dependencies.path, dependencies.platform));
13615
14099
  const openCodeExecutable = findExecutable("opencode");
13616
14100
  const openCode2Executable = findExecutable("opencode2");
14101
+ const platform = dependencies.platform ?? process.platform;
14102
+ const hostOf = (executable) => executable === null ? null : hostLaunchPath(executable, platform) ?? executable;
14103
+ const openCodeHost = hostOf(openCodeExecutable);
14104
+ const openCode2Host = hostOf(openCode2Executable);
13617
14105
  const evidence = [];
13618
- const sharedExecutable = openCodeExecutable !== null && openCode2Executable !== null && resolvedPath(openCodeExecutable) === resolvedPath(openCode2Executable);
13619
- if (openCodeExecutable) {
13620
- const v1Metadata = packageMetadataNearExecutable(openCodeExecutable, "opencode-ai");
13621
- const v2Metadata = v2MetadataNearExecutable(openCodeExecutable);
14106
+ const sharedExecutable = openCodeHost !== null && openCode2Host !== null && resolvedPath(openCodeHost) === resolvedPath(openCode2Host);
14107
+ if (openCodeExecutable !== null && openCodeHost !== null) {
14108
+ const v1Metadata = packageMetadataNearExecutable(openCodeHost, "opencode-ai");
14109
+ const v2Metadata = v2MetadataNearExecutable(openCodeHost);
13622
14110
  const metadataVersion = packageVersion(v2Metadata) ?? packageVersion(v1Metadata);
13623
- const version = metadataVersion ?? (dependencies.probeV1Version ?? probeOpenCodeV1Version)(openCodeExecutable);
14111
+ const probeVersion = dependencies.probeV1Version ?? ((executable) => probeOpenCodeV1Version(executable, { platform }));
14112
+ const version = metadataVersion ?? probeVersion(openCodeExecutable);
13624
14113
  const isV2 = Boolean(v2Metadata) || sharedExecutable || isV2Version(version);
13625
14114
  evidence.push({
13626
14115
  generation: isV2 ? "v2" : "v1",
@@ -13630,8 +14119,8 @@ function detectOpenCodeHostGeneration(dependencies = {}) {
13630
14119
  modernV1: !isV2 && version === MODERN_V1_VERSION
13631
14120
  });
13632
14121
  }
13633
- if (openCode2Executable && !sharedExecutable) {
13634
- const version = packageVersion(v2MetadataNearExecutable(openCode2Executable));
14122
+ if (openCode2Executable !== null && openCode2Host !== null && !sharedExecutable) {
14123
+ const version = packageVersion(v2MetadataNearExecutable(openCode2Host));
13635
14124
  evidence.push({
13636
14125
  generation: "v2",
13637
14126
  executable: openCode2Executable,
@@ -13667,10 +14156,14 @@ function formatHostGenerations(detection) {
13667
14156
  return "V2";
13668
14157
  return "unknown";
13669
14158
  }
13670
- var FULL_CONTENT_HASH_MAX_BYTES, PARTIAL_CONTENT_WINDOW_BYTES, V2_PACKAGE_NAMES;
14159
+ var LAUNCHER_MAX_BYTES, CMD_LAUNCHER_PATH, SH_LAUNCHER_PATH, BATCH_FILE, FULL_CONTENT_HASH_MAX_BYTES, PARTIAL_CONTENT_WINDOW_BYTES, V2_PACKAGE_NAMES;
13671
14160
  var init_host_generation = __esm(() => {
13672
14161
  init_dist2();
13673
14162
  init_opencode_config();
14163
+ LAUNCHER_MAX_BYTES = 64 * 1024;
14164
+ CMD_LAUNCHER_PATH = /"%~?dp0%?\\([^"%\r\n]+)"/g;
14165
+ SH_LAUNCHER_PATH = /"\$basedir\/([^"$\r\n]+)"/g;
14166
+ BATCH_FILE = /\.(?:cmd|bat)$/i;
13674
14167
  FULL_CONTENT_HASH_MAX_BYTES = 64 * 1024 * 1024;
13675
14168
  PARTIAL_CONTENT_WINDOW_BYTES = 1024 * 1024;
13676
14169
  V2_PACKAGE_NAMES = ["@opencode/cli", "@opencode-ai/cli"];
@@ -13678,21 +14171,21 @@ var init_host_generation = __esm(() => {
13678
14171
 
13679
14172
  // src/adapters/opencode.ts
13680
14173
  import { existsSync as existsSync15, readFileSync as readFileSync11, rmSync as rmSync4, statSync as statSync11 } from "node:fs";
13681
- import { homedir as homedir13 } from "node:os";
13682
- import { dirname as dirname8, join as join17, parse as parse2, resolve as resolve10 } from "node:path";
14174
+ import { homedir as homedir15 } from "node:os";
14175
+ import { dirname as dirname9, join as join19, parse as parse3, resolve as resolve12 } from "node:path";
13683
14176
  import { fileURLToPath } from "node:url";
13684
14177
  function getOpenCodeConfigDir() {
13685
14178
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
13686
14179
  if (envDir)
13687
- return resolve10(envDir);
14180
+ return resolve12(envDir);
13688
14181
  return getOpenCodeConfigRoot();
13689
14182
  }
13690
14183
  function getLegacyOpenCodePluginCachePath(primaryPath) {
13691
14184
  if (process.platform !== "win32")
13692
14185
  return null;
13693
- const localAppData = process.env.LOCALAPPDATA ?? join17(homedir13(), "AppData", "Local");
13694
- const legacyPath = join17(localAppData, "opencode", "packages", LEGACY_PLUGIN_ENTRY);
13695
- return resolve10(legacyPath) === resolve10(primaryPath) ? null : legacyPath;
14186
+ const localAppData = process.env.LOCALAPPDATA ?? join19(homedir15(), "AppData", "Local");
14187
+ const legacyPath = join19(localAppData, "opencode", "packages", LEGACY_PLUGIN_ENTRY);
14188
+ return resolve12(legacyPath) === resolve12(primaryPath) ? null : legacyPath;
13696
14189
  }
13697
14190
  function clearLegacyOpenCodePluginCache(primaryPath) {
13698
14191
  const legacyPath = getLegacyOpenCodePluginCachePath(primaryPath);
@@ -13714,12 +14207,12 @@ function hasOpenCodeCli() {
13714
14207
  function openCodeDesktopAppExists() {
13715
14208
  const candidates = [];
13716
14209
  if (process.platform === "darwin") {
13717
- candidates.push("/Applications/OpenCode.app", "/Applications/OpenCode Beta.app", join17(homedir13(), "Applications", "OpenCode.app"), join17(homedir13(), "Applications", "OpenCode Beta.app"));
14210
+ candidates.push("/Applications/OpenCode.app", "/Applications/OpenCode Beta.app", join19(homedir15(), "Applications", "OpenCode.app"), join19(homedir15(), "Applications", "OpenCode Beta.app"));
13718
14211
  } else if (process.platform === "win32") {
13719
- const localAppData = process.env.LOCALAPPDATA ?? join17(homedir13(), "AppData", "Local");
13720
- candidates.push(join17(localAppData, "Programs", "opencode"), join17(localAppData, "opencode"));
14212
+ const localAppData = process.env.LOCALAPPDATA ?? join19(homedir15(), "AppData", "Local");
14213
+ candidates.push(join19(localAppData, "Programs", "opencode"), join19(localAppData, "opencode"));
13721
14214
  } else {
13722
- candidates.push("/opt/OpenCode", "/usr/lib/opencode", join17(homedir13(), ".local", "share", "applications", "opencode.desktop"));
14215
+ candidates.push("/opt/OpenCode", "/usr/lib/opencode", join19(homedir15(), ".local", "share", "applications", "opencode.desktop"));
13723
14216
  }
13724
14217
  return candidates.some((p) => {
13725
14218
  try {
@@ -13748,16 +14241,16 @@ function pathPointsToOurPlugin(entry) {
13748
14241
  try {
13749
14242
  if (!existsSync15(fsPath))
13750
14243
  return false;
13751
- let searchDir = statSync11(fsPath).isDirectory() ? fsPath : dirname8(fsPath);
14244
+ let searchDir = statSync11(fsPath).isDirectory() ? fsPath : dirname9(fsPath);
13752
14245
  let pkgJsonPath = null;
13753
14246
  while (true) {
13754
- const candidate = join17(searchDir, "package.json");
14247
+ const candidate = join19(searchDir, "package.json");
13755
14248
  if (existsSync15(candidate)) {
13756
14249
  pkgJsonPath = candidate;
13757
14250
  break;
13758
14251
  }
13759
- const parent = dirname8(searchDir);
13760
- if (parent === searchDir || searchDir === parse2(searchDir).root)
14252
+ const parent = dirname9(searchDir);
14253
+ if (parent === searchDir || searchDir === parse3(searchDir).root)
13761
14254
  break;
13762
14255
  searchDir = parent;
13763
14256
  }
@@ -13925,23 +14418,33 @@ class OpenCodeAdapter {
13925
14418
  };
13926
14419
  }
13927
14420
  hostShellState() {
14421
+ return this.hostToolState("shell");
14422
+ }
14423
+ hostToolState(hostTool) {
13928
14424
  if (this.configGeneration() !== "v2")
13929
14425
  return "not_applicable";
13930
14426
  const { value } = readJsoncFile(this.detectConfigPaths().harnessConfig);
13931
- return hostShellPluginDisabled(value) ? "disabled" : "enabled";
14427
+ return hostToolPluginDisabled(value, hostTool) ? "disabled" : "enabled";
13932
14428
  }
13933
14429
  aftBashEnabled() {
14430
+ return this.aftHostReplacementEnabled("shell");
14431
+ }
14432
+ aftHostReplacementEnabled(hostTool) {
13934
14433
  const { value } = readJsoncFile(this.detectConfigPaths().aftConfig);
13935
- return aftBashEnabled(value);
14434
+ return aftHostReplacementEnabled(value, hostTool);
13936
14435
  }
13937
14436
  setHostShellDisabled(disabled) {
14437
+ return this.setHostToolDisabled("shell", disabled);
14438
+ }
14439
+ setHostToolDisabled(hostTool, disabled) {
14440
+ const { disableEntry, aftTool } = OPENCODE_HOST_TOOLS[hostTool];
13938
14441
  const configPath = this.detectConfigPaths().harnessConfig;
13939
14442
  const format = this.detectConfigPaths().harnessConfigFormat;
13940
14443
  if (this.configGeneration() !== "v2") {
13941
14444
  return {
13942
14445
  ok: false,
13943
14446
  action: "error",
13944
- message: "only OpenCode 2 has a built-in shell tool plugin to disable",
14447
+ message: `only OpenCode 2 has a built-in ${hostTool} tool plugin to disable`,
13945
14448
  configPath
13946
14449
  };
13947
14450
  }
@@ -13949,13 +14452,13 @@ class OpenCodeAdapter {
13949
14452
  if (!disabled) {
13950
14453
  return { ok: true, action: "already_present", message: "no config to change", configPath };
13951
14454
  }
13952
- const failed = this.tryWrite(configPath, () => writeJsoncFile(configPath, { plugins: [OPENCODE_HOST_SHELL_DISABLE_ENTRY] }, "json"));
14455
+ const failed = this.tryWrite(configPath, () => writeJsoncFile(configPath, { plugins: [disableEntry] }, "json"));
13953
14456
  if (failed)
13954
14457
  return failed;
13955
14458
  return {
13956
14459
  ok: true,
13957
14460
  action: "added",
13958
- message: `Created ${configPath} with ${OPENCODE_HOST_SHELL_DISABLE_ENTRY} under \`plugins\``,
14461
+ message: `Created ${configPath} with ${disableEntry} under \`plugins\``,
13959
14462
  configPath
13960
14463
  };
13961
14464
  }
@@ -13968,12 +14471,12 @@ class OpenCodeAdapter {
13968
14471
  configPath
13969
14472
  };
13970
14473
  }
13971
- const { changed } = setHostShellPluginDisabled(value, disabled);
14474
+ const { changed } = setHostToolPluginDisabled(value, hostTool, disabled);
13972
14475
  if (!changed) {
13973
14476
  return {
13974
14477
  ok: true,
13975
14478
  action: "already_present",
13976
- message: disabled ? `${OPENCODE_HOST_SHELL_DISABLE_ENTRY} is already set in ${configPath}` : `${OPENCODE_HOST_SHELL_DISABLE_ENTRY} is not set in ${configPath}`,
14479
+ message: disabled ? `${disableEntry} is already set in ${configPath}` : `${disableEntry} is not set in ${configPath}`,
13977
14480
  configPath
13978
14481
  };
13979
14482
  }
@@ -13983,7 +14486,7 @@ class OpenCodeAdapter {
13983
14486
  return {
13984
14487
  ok: true,
13985
14488
  action: disabled ? "added" : "updated",
13986
- message: disabled ? `Added ${OPENCODE_HOST_SHELL_DISABLE_ENTRY} under \`plugins\` in ${configPath}: OpenCode's own shell tool is disabled, so agents use AFT's bash` : `Removed ${OPENCODE_HOST_SHELL_DISABLE_ENTRY} from ${configPath}: OpenCode's own shell tool is enabled again`,
14489
+ message: disabled ? `Added ${disableEntry} under \`plugins\` in ${configPath}: OpenCode's own ${hostTool} tool is disabled, so agents use AFT's ${aftTool}` : `Removed ${disableEntry} from ${configPath}: OpenCode's own ${hostTool} tool is enabled again`,
13987
14490
  configPath
13988
14491
  };
13989
14492
  }
@@ -14007,10 +14510,10 @@ class OpenCodeAdapter {
14007
14510
  const configPath = this.detectConfigPaths().harnessConfig;
14008
14511
  const { value } = readJsoncFile(configPath);
14009
14512
  const configuredEntry = openCodePluginReadKeys(this.configGeneration()).flatMap((key) => Array.isArray(value?.[key]) ? value[key] : []).map(pluginEntryPackage).find(isAftNpmEntry);
14010
- const path = join17(getOpenCodeCacheDir(), "packages", configuredEntry ?? PLUGIN_ENTRY);
14513
+ const path = join19(getOpenCodeCacheDir(), "packages", configuredEntry ?? PLUGIN_ENTRY);
14011
14514
  let cached;
14012
14515
  try {
14013
- const installedPkgPath = join17(path, "node_modules", "@cortexkit", "aft-opencode", "package.json");
14516
+ const installedPkgPath = join19(path, "node_modules", "@cortexkit", "aft-opencode", "package.json");
14014
14517
  if (existsSync15(installedPkgPath)) {
14015
14518
  const pkg = JSON.parse(readFileSync11(installedPkgPath, "utf-8"));
14016
14519
  cached = typeof pkg.version === "string" ? pkg.version : undefined;
@@ -14086,12 +14589,12 @@ class OpenCodeAdapter {
14086
14589
  describeStorageSubtrees() {
14087
14590
  const storage = this.getStorageDir();
14088
14591
  return {
14089
- index: dirSize(join17(storage, "index")),
14090
- semantic: dirSize(join17(storage, "semantic")),
14091
- backups: dirSize(join17(storage, "backups")),
14092
- url_cache: dirSize(join17(storage, "url_cache")),
14093
- onnxruntime: dirSize(join17(storage, "onnxruntime")),
14094
- logs: dirSize(join17(storage, "logs"))
14592
+ index: dirSize(join19(storage, "index")),
14593
+ semantic: dirSize(join19(storage, "semantic")),
14594
+ backups: dirSize(join19(storage, "backups")),
14595
+ url_cache: dirSize(join19(storage, "url_cache")),
14596
+ onnxruntime: dirSize(join19(storage, "onnxruntime")),
14597
+ logs: dirSize(join19(storage, "logs"))
14095
14598
  };
14096
14599
  }
14097
14600
  }
@@ -14112,18 +14615,18 @@ var init_opencode = __esm(() => {
14112
14615
 
14113
14616
  // src/adapters/pi.ts
14114
14617
  import { existsSync as existsSync16, readFileSync as readFileSync12 } from "node:fs";
14115
- import { homedir as homedir14 } from "node:os";
14116
- import { join as join18, resolve as resolve11 } from "node:path";
14618
+ import { homedir as homedir16 } from "node:os";
14619
+ import { join as join20, resolve as resolve13 } from "node:path";
14117
14620
  function getPiAgentDir() {
14118
14621
  const configuredDir = process.env.PI_CODING_AGENT_DIR?.trim();
14119
14622
  if (configuredDir)
14120
- return resolve11(configuredDir);
14623
+ return resolve13(configuredDir);
14121
14624
  const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
14122
- const home = envHome && envHome.length > 0 ? envHome : homedir14();
14123
- return join18(home, ".pi", "agent");
14625
+ const home = envHome && envHome.length > 0 ? envHome : homedir16();
14626
+ return join20(home, ".pi", "agent");
14124
14627
  }
14125
14628
  function readPiExtensionIndex() {
14126
- const settingsPath = join18(getPiAgentDir(), "settings.json");
14629
+ const settingsPath = join20(getPiAgentDir(), "settings.json");
14127
14630
  if (existsSync16(settingsPath)) {
14128
14631
  try {
14129
14632
  const raw = readFileSync12(settingsPath, "utf-8");
@@ -14144,10 +14647,10 @@ function readPiExtensionIndex() {
14144
14647
  } catch {}
14145
14648
  }
14146
14649
  const candidates = [
14147
- join18(getPiAgentDir(), "extensions.json"),
14148
- join18(getPiAgentDir(), "extensions.jsonc"),
14149
- join18(getPiAgentDir(), "config.json"),
14150
- join18(getPiAgentDir(), "config.jsonc")
14650
+ join20(getPiAgentDir(), "extensions.json"),
14651
+ join20(getPiAgentDir(), "extensions.jsonc"),
14652
+ join20(getPiAgentDir(), "config.json"),
14653
+ join20(getPiAgentDir(), "config.jsonc")
14151
14654
  ];
14152
14655
  for (const path of candidates) {
14153
14656
  if (!existsSync16(path))
@@ -14183,14 +14686,14 @@ function piEntryMatchesAft(entry) {
14183
14686
  } else if (entry.startsWith("/")) {
14184
14687
  resolved = entry;
14185
14688
  } else if (entry.length > 0) {
14186
- resolved = join18(getPiAgentDir(), entry);
14689
+ resolved = join20(getPiAgentDir(), entry);
14187
14690
  }
14188
14691
  if (!resolved)
14189
14692
  return false;
14190
14693
  try {
14191
14694
  if (!existsSync16(resolved))
14192
14695
  return false;
14193
- const pkgPath = join18(resolved, "package.json");
14696
+ const pkgPath = join20(resolved, "package.json");
14194
14697
  if (!existsSync16(pkgPath))
14195
14698
  return false;
14196
14699
  const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
@@ -14242,7 +14745,7 @@ class PiAdapter {
14242
14745
  const aftConfigExists = existsSync16(aftConfigPath);
14243
14746
  return {
14244
14747
  configDir,
14245
- harnessConfig: index.path ?? join18(configDir, "extensions.json"),
14748
+ harnessConfig: index.path ?? join20(configDir, "extensions.json"),
14246
14749
  harnessConfigFormat: index.path ? "json" : "none",
14247
14750
  aftConfig: aftConfigPath,
14248
14751
  aftConfigFormat: aftConfigExists ? "jsonc" : "none"
@@ -14287,9 +14790,9 @@ class PiAdapter {
14287
14790
  }
14288
14791
  getPluginCacheInfo() {
14289
14792
  const candidates = [
14290
- join18(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
14291
- join18(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
14292
- join18(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
14793
+ join20(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
14794
+ join20(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
14795
+ join20(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
14293
14796
  ];
14294
14797
  for (const candidate of candidates) {
14295
14798
  if (!existsSync16(candidate))
@@ -14306,7 +14809,7 @@ class PiAdapter {
14306
14809
  } catch {}
14307
14810
  }
14308
14811
  return {
14309
- path: join18(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
14812
+ path: join20(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
14310
14813
  exists: false
14311
14814
  };
14312
14815
  }
@@ -14328,12 +14831,12 @@ class PiAdapter {
14328
14831
  describeStorageSubtrees() {
14329
14832
  const storage = this.getStorageDir();
14330
14833
  return {
14331
- index: dirSize(join18(storage, "index")),
14332
- semantic: dirSize(join18(storage, "semantic")),
14333
- backups: dirSize(join18(storage, "backups")),
14334
- url_cache: dirSize(join18(storage, "url_cache")),
14335
- onnxruntime: dirSize(join18(storage, "onnxruntime")),
14336
- logs: dirSize(join18(storage, "logs"))
14834
+ index: dirSize(join20(storage, "index")),
14835
+ semantic: dirSize(join20(storage, "semantic")),
14836
+ backups: dirSize(join20(storage, "backups")),
14837
+ url_cache: dirSize(join20(storage, "url_cache")),
14838
+ onnxruntime: dirSize(join20(storage, "onnxruntime")),
14839
+ logs: dirSize(join20(storage, "logs"))
14337
14840
  };
14338
14841
  }
14339
14842
  }
@@ -15754,11 +16257,11 @@ var init_version = __esm(async () => {
15754
16257
 
15755
16258
  // src/lib/cli-logger.ts
15756
16259
  import { appendFileSync, mkdirSync as mkdirSync6 } from "node:fs";
15757
- import { tmpdir as tmpdir3 } from "node:os";
15758
- import { dirname as dirname9, join as join19 } from "node:path";
16260
+ import { tmpdir as tmpdir4 } from "node:os";
16261
+ import { dirname as dirname10, join as join21 } from "node:path";
15759
16262
  function cliLogPath() {
15760
16263
  if (isTestEnvironment())
15761
- return join19(tmpdir3(), "aft-cli-test.log");
16264
+ return join21(tmpdir4(), "aft-cli-test.log");
15762
16265
  return resolveAftLogPath("aft-cli.log");
15763
16266
  }
15764
16267
  function write(level, message) {
@@ -15773,7 +16276,7 @@ function write(level, message) {
15773
16276
  }
15774
16277
  try {
15775
16278
  const path = cliLogPath();
15776
- mkdirSync6(dirname9(path), { recursive: true });
16279
+ mkdirSync6(dirname10(path), { recursive: true });
15777
16280
  appendFileSync(path, `${new Date().toISOString()} ${level.toUpperCase()} ${message}
15778
16281
  `);
15779
16282
  } catch {}
@@ -15811,10 +16314,10 @@ var init_cli_logger = __esm(() => {
15811
16314
 
15812
16315
  // src/lib/binary-install.ts
15813
16316
  import { existsSync as existsSync17 } from "node:fs";
15814
- import { join as join20 } from "node:path";
16317
+ import { join as join22 } from "node:path";
15815
16318
  function cachedBinaryFor(version) {
15816
16319
  const tag = version.startsWith("v") ? version : `v${version}`;
15817
- const path = join20(getAftBinaryCacheDir(), tag, getAftBinaryName());
16320
+ const path = join22(getAftBinaryCacheDir(), tag, getAftBinaryName());
15818
16321
  try {
15819
16322
  return existsSync17(path) ? path : null;
15820
16323
  } catch {
@@ -15948,7 +16451,7 @@ function loadFeaturePlan(harness, run = runNative) {
15948
16451
  return {
15949
16452
  ok: false,
15950
16453
  error: withCliCommands(error),
15951
- configRejected: result.status === 1 && error.includes("aft doctor --fix"),
16454
+ configRejected: result.status === 1 && error.includes("AFT cannot load this configuration"),
15952
16455
  missingBinary: result.missingBinary === true
15953
16456
  };
15954
16457
  }
@@ -16430,8 +16933,10 @@ async function runSetup(argv, options = {}) {
16430
16933
  for (const adapter of nextSteps) {
16431
16934
  if (!(adapter instanceof OpenCodeAdapter))
16432
16935
  continue;
16433
- if (await offerHostShellDisable(adapter, argv, options) === "failed")
16434
- anyFailure = true;
16936
+ for (const hostTool of OPENCODE_HOST_TOOL_NAMES) {
16937
+ if (await offerHostToolDisable(adapter, hostTool, argv, options) === "failed")
16938
+ anyFailure = true;
16939
+ }
16435
16940
  }
16436
16941
  for (const adapter of nextSteps)
16437
16942
  printNextSteps(adapter);
@@ -16501,19 +17006,20 @@ async function configureAdapter(adapter, options) {
16501
17006
  }
16502
17007
  return failed ? "failed" : "ok";
16503
17008
  }
16504
- async function offerHostShellDisable(adapter, argv, options = {}) {
16505
- if (adapter.hostShellState() === "not_applicable")
17009
+ async function offerHostToolDisable(adapter, hostTool, argv, options = {}) {
17010
+ if (adapter.hostToolState(hostTool) === "not_applicable")
16506
17011
  return "skipped";
16507
- const bashOn = adapter.aftBashEnabled();
17012
+ const { aftTool } = OPENCODE_HOST_TOOLS[hostTool];
17013
+ const replacementOn = adapter.aftHostReplacementEnabled(hostTool);
16508
17014
  const interactive = !argv.includes("--yes") && !argv.includes("-y") && (options.interactive ?? Boolean(process.stdin.isTTY));
16509
- const disable = interactive ? await (options.confirmHostShell ?? confirm2)(HOST_SHELL_QUESTION, bashOn) : bashOn;
16510
- const result = adapter.setHostShellDisabled(disable);
17015
+ const disable = interactive ? await (options.confirmHostTool ?? (hostTool === "shell" ? options.confirmHostShell : undefined) ?? confirm2)(hostTool === "shell" ? HOST_SHELL_QUESTION : `OpenCode's own ${hostTool} tool: disable it so agents use AFT's ${aftTool}?`, replacementOn) : replacementOn;
17016
+ const result = adapter.setHostToolDisabled(hostTool, disable);
16511
17017
  if (!result.ok) {
16512
17018
  log2.error(`${adapter.displayName}: ${result.message}`);
16513
17019
  return "failed";
16514
17020
  }
16515
17021
  if (result.action === "already_present") {
16516
- log2.info(`${adapter.displayName}: OpenCode's own shell tool is ${disable ? "already disabled" : "enabled"}${disable ? "; agents use AFT's bash" : bashOn ? "" : " (AFT's bash is disabled)"}`);
17022
+ log2.info(`${adapter.displayName}: OpenCode's own ${hostTool} tool is ${disable ? "already disabled" : "enabled"}${disable ? `; agents use AFT's ${aftTool}` : replacementOn ? "" : ` (AFT's ${aftTool} is disabled)`}`);
16517
17023
  } else {
16518
17024
  log2.success(`${adapter.displayName}: ${result.message}`);
16519
17025
  }
@@ -16569,6 +17075,7 @@ var init_setup = __esm(async () => {
16569
17075
  init_prompts();
16570
17076
  init_self_version();
16571
17077
  init_host_generation();
17078
+ init_opencode_config();
16572
17079
  await __promiseAll([
16573
17080
  init_binary_probe(),
16574
17081
  init_feature_plan(),
@@ -16620,6 +17127,28 @@ var init_backups = __esm(async () => {
16620
17127
  await init_binary_probe();
16621
17128
  });
16622
17129
 
17130
+ // src/commands/cache.ts
17131
+ function runCache(argv) {
17132
+ const binary = findAftBinary();
17133
+ if (!binary) {
17134
+ console.error(missingAftBinaryMessage(`${CLI} cache`));
17135
+ return 1;
17136
+ }
17137
+ const result = spawnSync(binary, ["cache", ...argv], {
17138
+ stdio: "inherit",
17139
+ env: process.env
17140
+ });
17141
+ if (result.error) {
17142
+ console.error(`aft cache failed to start ${binary}: ${result.error.message}`);
17143
+ return 1;
17144
+ }
17145
+ return result.status ?? 1;
17146
+ }
17147
+ var init_cache = __esm(async () => {
17148
+ init_dist2();
17149
+ await init_binary_probe();
17150
+ });
17151
+
16623
17152
  // src/doctor/features.ts
16624
17153
  function isOn(feature) {
16625
17154
  return feature.effective !== "off";
@@ -16729,7 +17258,7 @@ var init_features = __esm(() => {
16729
17258
 
16730
17259
  // src/doctor/opencode.ts
16731
17260
  import { existsSync as existsSync18, readFileSync as readFileSync13 } from "node:fs";
16732
- import { dirname as dirname10, join as join21 } from "node:path";
17261
+ import { dirname as dirname11, join as join23 } from "node:path";
16733
17262
  import { fileURLToPath as fileURLToPath2 } from "node:url";
16734
17263
  function isLoadPath(value) {
16735
17264
  return OPENCODE_LOAD_PATHS.includes(value);
@@ -16800,13 +17329,13 @@ function readManifest(path) {
16800
17329
  }
16801
17330
  function manifestFromLocalPath(path) {
16802
17331
  let current = path;
16803
- if (!existsSync18(join21(current, "package.json")))
16804
- current = dirname10(current);
17332
+ if (!existsSync18(join23(current, "package.json")))
17333
+ current = dirname11(current);
16805
17334
  while (true) {
16806
- const manifest = readManifest(join21(current, "package.json"));
17335
+ const manifest = readManifest(join23(current, "package.json"));
16807
17336
  if (manifest)
16808
17337
  return manifest;
16809
- const parent = dirname10(current);
17338
+ const parent = dirname11(current);
16810
17339
  if (parent === current)
16811
17340
  return null;
16812
17341
  current = parent;
@@ -16816,7 +17345,7 @@ function pluginManifest(entry, cachePath) {
16816
17345
  const localRoot = localPluginRoot(entry);
16817
17346
  if (localRoot)
16818
17347
  return manifestFromLocalPath(localRoot);
16819
- return readManifest(join21(cachePath, "node_modules", "@cortexkit", "aft-opencode", "package.json"));
17348
+ return readManifest(join23(cachePath, "node_modules", "@cortexkit", "aft-opencode", "package.json"));
16820
17349
  }
16821
17350
  function pinProblem(entry, pinned) {
16822
17351
  return `the plugin entry ${entry} ${describePluginEntry(entry)}; run \`${CLI} doctor --fix\` to pin it to ${pinned}`;
@@ -16916,6 +17445,36 @@ function isResponseForRequest(parsed, expectedIds) {
16916
17445
  return false;
16917
17446
  return expectedIds.has(id);
16918
17447
  }
17448
+ function createNdjsonLineSplitter(onLine) {
17449
+ let pending = [];
17450
+ let scannedChars = 0;
17451
+ return {
17452
+ push(chunk) {
17453
+ scannedChars += chunk.length;
17454
+ let start = 0;
17455
+ let newline = chunk.indexOf(`
17456
+ `);
17457
+ while (newline !== -1) {
17458
+ let line = chunk.slice(start, newline);
17459
+ if (pending.length > 0) {
17460
+ pending.push(line);
17461
+ line = pending.join("");
17462
+ pending = [];
17463
+ }
17464
+ start = newline + 1;
17465
+ if (onLine(line.trim()) === true)
17466
+ return;
17467
+ newline = chunk.indexOf(`
17468
+ `, start);
17469
+ }
17470
+ if (start < chunk.length)
17471
+ pending.push(start === 0 ? chunk : chunk.slice(start));
17472
+ },
17473
+ get scannedChars() {
17474
+ return scannedChars;
17475
+ }
17476
+ };
17477
+ }
16919
17478
  async function sendAftRequest(binaryPath, request) {
16920
17479
  const responses = await sendAftRequests(binaryPath, [request]);
16921
17480
  const response = responses[0];
@@ -16930,7 +17489,7 @@ async function sendAftRequests(binaryPath, requests) {
16930
17489
  });
16931
17490
  const responses = [];
16932
17491
  const noiseLines = [];
16933
- let stdout = "";
17492
+ let noiseLineCount = 0;
16934
17493
  let stderr = "";
16935
17494
  let settled = false;
16936
17495
  const finish = (fn) => {
@@ -16941,18 +17500,23 @@ async function sendAftRequests(binaryPath, requests) {
16941
17500
  fn();
16942
17501
  };
16943
17502
  const expectedIds = new Set(requests.map((req) => req.id));
17503
+ const recordNoise = (line) => {
17504
+ noiseLineCount += 1;
17505
+ if (noiseLines.length < MAX_NOISE_LINES_IN_ERROR)
17506
+ noiseLines.push(line);
17507
+ };
16944
17508
  const handleLine = (line) => {
16945
17509
  if (!line)
16946
17510
  return;
16947
17511
  if (!line.startsWith("{")) {
16948
- noiseLines.push(line);
17512
+ recordNoise(line);
16949
17513
  return;
16950
17514
  }
16951
17515
  let parsed;
16952
17516
  try {
16953
17517
  parsed = JSON.parse(line);
16954
17518
  } catch {
16955
- noiseLines.push(line);
17519
+ recordNoise(line);
16956
17520
  return;
16957
17521
  }
16958
17522
  if (!isResponseForRequest(parsed, expectedIds)) {
@@ -16964,20 +17528,15 @@ async function sendAftRequests(binaryPath, requests) {
16964
17528
  finish(() => resolve(responses));
16965
17529
  }
16966
17530
  };
17531
+ const stdoutLines = createNdjsonLineSplitter((line) => {
17532
+ handleLine(line);
17533
+ return settled;
17534
+ });
16967
17535
  child.stdout.setEncoding("utf-8");
16968
17536
  child.stdout.on("data", (chunk) => {
16969
- stdout += chunk;
16970
- while (true) {
16971
- const newline = stdout.indexOf(`
16972
- `);
16973
- if (newline === -1)
16974
- break;
16975
- const line = stdout.slice(0, newline).trim();
16976
- stdout = stdout.slice(newline + 1);
16977
- handleLine(line);
16978
- if (settled)
16979
- break;
16980
- }
17537
+ if (settled)
17538
+ return;
17539
+ stdoutLines.push(chunk);
16981
17540
  });
16982
17541
  child.stderr.setEncoding("utf-8");
16983
17542
  child.stderr.on("data", (chunk) => {
@@ -16989,7 +17548,7 @@ async function sendAftRequests(binaryPath, requests) {
16989
17548
  child.on("close", (code) => {
16990
17549
  if (settled)
16991
17550
  return;
16992
- finish(() => reject(buildBridgeError({ binaryPath, code, stderr, noiseLines, responses })));
17551
+ finish(() => reject(buildBridgeError({ binaryPath, code, stderr, noiseLines, noiseLineCount, responses })));
16993
17552
  });
16994
17553
  child.stdin.on("error", () => {});
16995
17554
  try {
@@ -17007,14 +17566,14 @@ function buildBridgeError(ctx) {
17007
17566
  if (ctx.responses.length > 0) {
17008
17567
  parts.push(`Got ${ctx.responses.length} valid response(s) before exit.`);
17009
17568
  }
17010
- if (ctx.noiseLines.length > 0) {
17569
+ if (ctx.noiseLineCount > 0) {
17011
17570
  parts.push(`
17012
- The binary printed ${ctx.noiseLines.length} non-JSON line(s) to stdout — this usually means ` + "the resolved binary isn't an AFT release binary (wrapper script, panic output, or unrelated tool):");
17571
+ The binary printed ${ctx.noiseLineCount} non-JSON line(s) to stdout — this usually means ` + "the resolved binary isn't an AFT release binary (wrapper script, panic output, or unrelated tool):");
17013
17572
  const sample = ctx.noiseLines.slice(0, MAX_NOISE_LINES_IN_ERROR).map((line) => ` | ${line}`);
17014
17573
  parts.push(sample.join(`
17015
17574
  `));
17016
- if (ctx.noiseLines.length > MAX_NOISE_LINES_IN_ERROR) {
17017
- parts.push(` | (… ${ctx.noiseLines.length - MAX_NOISE_LINES_IN_ERROR} more line(s) omitted)`);
17575
+ if (ctx.noiseLineCount > MAX_NOISE_LINES_IN_ERROR) {
17576
+ parts.push(` | (… ${ctx.noiseLineCount - MAX_NOISE_LINES_IN_ERROR} more line(s) omitted)`);
17018
17577
  }
17019
17578
  parts.push(`
17020
17579
  Try: ${CLI} doctor (full diagnostics) or check ~/.cache/aft/bin/ for the right binary.`);
@@ -17035,7 +17594,7 @@ var init_aft_bridge = __esm(() => {
17035
17594
 
17036
17595
  // src/lib/binary-cache.ts
17037
17596
  import { existsSync as existsSync19, readdirSync as readdirSync7, statSync as statSync12 } from "node:fs";
17038
- import { join as join22 } from "node:path";
17597
+ import { join as join24 } from "node:path";
17039
17598
  function getBinaryCacheInfo(activeVersion) {
17040
17599
  const path = getAftBinaryCacheDir();
17041
17600
  if (!existsSync19(path)) {
@@ -17048,7 +17607,7 @@ function getBinaryCacheInfo(activeVersion) {
17048
17607
  }
17049
17608
  const versions = readdirSync7(path).filter((entry) => {
17050
17609
  try {
17051
- return statSync12(join22(path, entry)).isDirectory();
17610
+ return statSync12(join24(path, entry)).isDirectory();
17052
17611
  } catch {
17053
17612
  return false;
17054
17613
  }
@@ -17068,14 +17627,14 @@ var init_binary_cache = __esm(() => {
17068
17627
  });
17069
17628
 
17070
17629
  // src/lib/sanitize.ts
17071
- import { realpathSync as realpathSync4 } from "node:fs";
17072
- import { homedir as homedir15, userInfo } from "node:os";
17630
+ import { realpathSync as realpathSync5 } from "node:fs";
17631
+ import { homedir as homedir17, userInfo } from "node:os";
17073
17632
  function escapeRegex(value) {
17074
17633
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17075
17634
  }
17076
17635
  function safeRealpath(p) {
17077
17636
  try {
17078
- return realpathSync4(p);
17637
+ return realpathSync5(p);
17079
17638
  } catch {
17080
17639
  return null;
17081
17640
  }
@@ -17105,7 +17664,7 @@ function redactSecrets(content) {
17105
17664
  }
17106
17665
  function sanitizeContent(content) {
17107
17666
  const username = userInfo().username;
17108
- const home = homedir15();
17667
+ const home = homedir17();
17109
17668
  let sanitized = redactSecrets(content);
17110
17669
  const cwd = process.cwd();
17111
17670
  for (const candidate of new Set([cwd, safeRealpath(cwd)])) {
@@ -17122,7 +17681,7 @@ function sanitizeContent(content) {
17122
17681
  sanitized = sanitized.replace(/([A-Za-z]:\\Users\\)[^\\"'\s]+/g, "$1<USER>");
17123
17682
  sanitized = sanitized.replace(/([A-Za-z]:\/Users\/)[^/\s"']+/g, "$1<USER>");
17124
17683
  if (username) {
17125
- sanitized = sanitized.replace(new RegExp(escapeRegex(username), "g"), "<USER>");
17684
+ sanitized = redactUsername(sanitized, username);
17126
17685
  }
17127
17686
  return sanitized;
17128
17687
  }
@@ -17138,6 +17697,11 @@ function sanitizeValue(value) {
17138
17697
  }
17139
17698
  return value;
17140
17699
  }
17700
+ function redactUsername(content, username) {
17701
+ if (!username)
17702
+ return content;
17703
+ return content.replace(new RegExp(`(?<![\\p{L}\\p{N}_])${escapeRegex(username)}(?![\\p{L}\\p{N}_])`, "gu"), "<USER>");
17704
+ }
17141
17705
  var SECRET_PLACEHOLDER = "<REDACTED_SECRET>", URL_CREDENTIAL_PLACEHOLDER = "***", KEY_NAME = "[A-Za-z_][A-Za-z0-9_.-]*", SENSITIVE_KEY_WORD, SEGMENTED_KEY_WORD, CAMEL_CASE_KEY_WORD, JWT_PATTERN, AWS_ACCESS_KEY_ID_PATTERN, CREDENTIAL_QUERY_PATTERN, KEY_QUERY_PATTERN, quotedSensitiveKeyValuePattern, unquotedSensitiveKeyValuePattern, bareSensitiveKeyValuePattern;
17142
17706
  var init_sanitize = __esm(() => {
17143
17707
  SENSITIVE_KEY_WORD = /(?:token|password|secret|api[_-]?key|passwd|pwd|credential)/i;
@@ -17153,7 +17717,7 @@ var init_sanitize = __esm(() => {
17153
17717
  });
17154
17718
 
17155
17719
  // src/lib/bridge-tool-failures.ts
17156
- import { closeSync as closeSync6, existsSync as existsSync20, openSync as openSync6, readSync as readSync4, statSync as statSync13 } from "node:fs";
17720
+ import { closeSync as closeSync8, existsSync as existsSync20, openSync as openSync8, readSync as readSync6, statSync as statSync13 } from "node:fs";
17157
17721
  function resolveBridgePluginLogPath() {
17158
17722
  return resolvePluginLogPath();
17159
17723
  }
@@ -17167,16 +17731,16 @@ function tailLogFileBytes(path, maxBytes) {
17167
17731
  return "";
17168
17732
  const readLength = Math.min(size, maxBytes);
17169
17733
  const position = size - readLength;
17170
- fd = openSync6(path, "r");
17734
+ fd = openSync8(path, "r");
17171
17735
  const buffer = Buffer.allocUnsafe(readLength);
17172
- const bytesRead = readSync4(fd, buffer, 0, readLength, position);
17736
+ const bytesRead = readSync6(fd, buffer, 0, readLength, position);
17173
17737
  return buffer.subarray(0, bytesRead).toString("utf-8").trim();
17174
17738
  } catch {
17175
17739
  return "";
17176
17740
  } finally {
17177
17741
  if (fd !== null) {
17178
17742
  try {
17179
- closeSync6(fd);
17743
+ closeSync8(fd);
17180
17744
  } catch {}
17181
17745
  }
17182
17746
  }
@@ -17296,7 +17860,7 @@ var init_bridge_tool_failures = __esm(() => {
17296
17860
  // src/lib/build-breaker.ts
17297
17861
  import { existsSync as existsSync21, readdirSync as readdirSync8 } from "node:fs";
17298
17862
  import { createRequire as createRequire3 } from "node:module";
17299
- import { join as join23 } from "node:path";
17863
+ import { join as join25 } from "node:path";
17300
17864
  function loadDatabaseSync() {
17301
17865
  const require2 = createRequire3(import.meta.url);
17302
17866
  try {
@@ -17310,11 +17874,11 @@ function loadDatabaseSync() {
17310
17874
  }
17311
17875
  }
17312
17876
  function buildBreakerDatabases(storageRoot) {
17313
- const callgraphRoot = join23(storageRoot, "callgraph");
17877
+ const callgraphRoot = join25(storageRoot, "callgraph");
17314
17878
  if (!existsSync21(callgraphRoot))
17315
17879
  return [];
17316
17880
  try {
17317
- return readdirSync8(callgraphRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join23(callgraphRoot, entry.name, "build-breaker.sqlite")).filter((path) => existsSync21(path));
17881
+ return readdirSync8(callgraphRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join25(callgraphRoot, entry.name, "build-breaker.sqlite")).filter((path) => existsSync21(path));
17318
17882
  } catch {
17319
17883
  return [];
17320
17884
  }
@@ -17450,21 +18014,10 @@ function previewConfigMigration(targets) {
17450
18014
  if (!raw)
17451
18015
  continue;
17452
18016
  const translated = structuredClone(raw);
17453
- const translation = translateConfigDocument(translated, "window", target.tier);
17454
- const retiredGithub = Object.hasOwn(raw, "gh_read") || isRecord2(raw.gh_shim) && "enabled" in raw.gh_shim;
17455
- if (!translation.legacyInput && translation.errors.length === 0 && !retiredGithub)
18017
+ const translation = translateConfigDocument(translated, target.tier);
18018
+ if (!translation.legacyInput)
17456
18019
  continue;
17457
18020
  const changes = diffConfig(raw, translated);
17458
- for (const code of translation.errors) {
17459
- const match = /^removed_config_key:([^:]+):use:(.+)$/.exec(code);
17460
- if (match)
17461
- changes.push({
17462
- kind: "changed",
17463
- key: match[1],
17464
- before: undefined,
17465
- after: `→ ${match[2]}`
17466
- });
17467
- }
17468
18021
  previews.push({ ...target, changes });
17469
18022
  }
17470
18023
  return previews;
@@ -17477,9 +18030,6 @@ function describeConfigChange(change) {
17477
18030
  return `removed ${change.key} (was ${show(change.before)})`;
17478
18031
  if (change.kind === "added")
17479
18032
  return `added ${change.key}: ${show(change.after)}`;
17480
- if (change.before === undefined && typeof change.after === "string" && change.after.startsWith("→ ")) {
17481
- return `replaced ${change.key} with ${change.after.slice(2)}`;
17482
- }
17483
18033
  return `changed ${change.key}: ${show(change.before)} → ${show(change.after)}`;
17484
18034
  }
17485
18035
  var import_comment_json2;
@@ -17490,19 +18040,19 @@ var init_config_migration = __esm(() => {
17490
18040
 
17491
18041
  // src/lib/legacy-storage.ts
17492
18042
  import { existsSync as existsSync23, readdirSync as readdirSync9, statSync as statSync14 } from "node:fs";
17493
- import { join as join24 } from "node:path";
18043
+ import { join as join26 } from "node:path";
17494
18044
  function summarizeLegacyPartitionDuplication(storageRoot) {
17495
18045
  if (!existsSync23(storageRoot)) {
17496
18046
  return { totalPartitions: 0, totalBytes: 0, byHarness: [] };
17497
18047
  }
17498
18048
  const byHarness = [];
17499
18049
  for (const harness of safeReadDir(storageRoot)) {
17500
- const harnessPath = join24(storageRoot, harness);
18050
+ const harnessPath = join26(storageRoot, harness);
17501
18051
  if (!isDirectory(harnessPath))
17502
18052
  continue;
17503
18053
  const partitions = new Map;
17504
- collectCallgraphPartitions(join24(harnessPath, "callgraph"), partitions);
17505
- collectInspectPartitions(join24(harnessPath, "inspect"), partitions);
18054
+ collectCallgraphPartitions(join26(harnessPath, "callgraph"), partitions);
18055
+ collectInspectPartitions(join26(harnessPath, "inspect"), partitions);
17506
18056
  if (partitions.size === 0)
17507
18057
  continue;
17508
18058
  let bytes = 0;
@@ -17521,7 +18071,7 @@ function collectCallgraphPartitions(domainPath, partitions) {
17521
18071
  if (!isDirectory(domainPath))
17522
18072
  return;
17523
18073
  for (const name of safeReadDir(domainPath)) {
17524
- const path = join24(domainPath, name);
18074
+ const path = join26(domainPath, name);
17525
18075
  if (isDirectory(path)) {
17526
18076
  if (!looksLikePartitionKey(name))
17527
18077
  continue;
@@ -17538,7 +18088,7 @@ function collectInspectPartitions(domainPath, partitions) {
17538
18088
  if (!isDirectory(domainPath))
17539
18089
  return;
17540
18090
  for (const name of safeReadDir(domainPath)) {
17541
- const path = join24(domainPath, name);
18091
+ const path = join26(domainPath, name);
17542
18092
  if (isDirectory(path)) {
17543
18093
  if (!looksLikePartitionKey(name))
17544
18094
  continue;
@@ -17614,7 +18164,7 @@ var init_legacy_storage = __esm(() => {
17614
18164
 
17615
18165
  // src/lib/lsp-cache.ts
17616
18166
  import { existsSync as existsSync24, readdirSync as readdirSync10, rmSync as rmSync5, statSync as statSync15 } from "node:fs";
17617
- import { join as join25 } from "node:path";
18167
+ import { join as join27 } from "node:path";
17618
18168
  function inspectDir(path) {
17619
18169
  if (!existsSync24(path)) {
17620
18170
  return { entries: [], totalSize: 0 };
@@ -17628,7 +18178,7 @@ function inspectDir(path) {
17628
18178
  return { entries: [], totalSize: 0 };
17629
18179
  }
17630
18180
  for (const name of names) {
17631
- const full = join25(path, name);
18181
+ const full = join27(path, name);
17632
18182
  try {
17633
18183
  if (!statSync15(full).isDirectory())
17634
18184
  continue;
@@ -17686,8 +18236,8 @@ var init_lsp_cache = __esm(() => {
17686
18236
  });
17687
18237
 
17688
18238
  // src/lib/onnx.ts
17689
- import { existsSync as existsSync25, readdirSync as readdirSync11, readlinkSync as readlinkSync2, realpathSync as realpathSync5 } from "node:fs";
17690
- import { basename as basename2, isAbsolute as isAbsolute5, join as join26, resolve as resolve12, win32 as win322 } from "node:path";
18239
+ import { existsSync as existsSync25, readdirSync as readdirSync11, readlinkSync as readlinkSync2, realpathSync as realpathSync6 } from "node:fs";
18240
+ import { basename as basename2, isAbsolute as isAbsolute7, join as join28, resolve as resolve14, win32 as win323 } from "node:path";
17691
18241
  function getOnnxLibraryName() {
17692
18242
  if (process.platform === "darwin")
17693
18243
  return "libonnxruntime.dylib";
@@ -17723,18 +18273,18 @@ function pathEntriesForPlatform2() {
17723
18273
  return pathEnvValue2().split(delimiter).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
17724
18274
  if (!entry || entry === "." || entry.includes("\x00"))
17725
18275
  return false;
17726
- return isAbsolute5(entry) || win322.isAbsolute(entry);
18276
+ return isAbsolute7(entry) || win323.isAbsolute(entry);
17727
18277
  });
17728
18278
  }
17729
18279
  function isWindowsSystem32Directory2(dir) {
17730
18280
  if (process.platform !== "win32")
17731
18281
  return false;
17732
- const normalizedDir = win322.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
18282
+ const normalizedDir = win323.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
17733
18283
  const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
17734
18284
  return windowsRoots.some((root) => {
17735
18285
  if (!root)
17736
18286
  return false;
17737
- return normalizedDir === win322.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
18287
+ return normalizedDir === win323.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
17738
18288
  });
17739
18289
  }
17740
18290
  function directoryContainsLibrary2(dir, libName) {
@@ -17757,8 +18307,8 @@ function findIgnoredWindowsSystemOnnxRuntime() {
17757
18307
  for (const root of windowsRoots) {
17758
18308
  if (!root)
17759
18309
  continue;
17760
- const systemDir = join26(root, "System32");
17761
- const key = win322.resolve(systemDir).toLowerCase();
18310
+ const systemDir = join28(root, "System32");
18311
+ const key = win323.resolve(systemDir).toLowerCase();
17762
18312
  if (seen.has(key))
17763
18313
  continue;
17764
18314
  seen.add(key);
@@ -17779,12 +18329,12 @@ function inspectSystemOnnxRuntime(searchPathsOverride) {
17779
18329
  searchPaths.push(...pathEntriesForPlatform2());
17780
18330
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
17781
18331
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
17782
- searchPaths.push(join26(programFiles, "onnxruntime", "lib"), join26(programFiles, "Microsoft ONNX Runtime", "lib"), join26(programFiles, "Microsoft Machine Learning", "lib"), join26(programFilesX86, "onnxruntime", "lib"), ...(() => {
18332
+ searchPaths.push(join28(programFiles, "onnxruntime", "lib"), join28(programFiles, "Microsoft ONNX Runtime", "lib"), join28(programFiles, "Microsoft Machine Learning", "lib"), join28(programFilesX86, "onnxruntime", "lib"), ...(() => {
17783
18333
  const nugetPaths = [];
17784
18334
  const userProfile = process.env.USERPROFILE ?? "";
17785
18335
  if (!userProfile)
17786
18336
  return nugetPaths;
17787
- const nugetPackageDir = join26(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
18337
+ const nugetPackageDir = join28(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
17788
18338
  if (!existsSync25(nugetPackageDir))
17789
18339
  return nugetPaths;
17790
18340
  try {
@@ -17793,7 +18343,7 @@ function inspectSystemOnnxRuntime(searchPathsOverride) {
17793
18343
  continue;
17794
18344
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
17795
18345
  continue;
17796
- nugetPaths.push(join26(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join26(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
18346
+ nugetPaths.push(join28(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join28(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
17797
18347
  }
17798
18348
  } catch {}
17799
18349
  return nugetPaths;
@@ -17803,7 +18353,7 @@ function inspectSystemOnnxRuntime(searchPathsOverride) {
17803
18353
  const seen = new Set;
17804
18354
  const unknownVersionPaths = [];
17805
18355
  for (const dir of searchPaths) {
17806
- let key = resolve12(dir).replace(/[/\\]+$/, "");
18356
+ let key = resolve14(dir).replace(/[/\\]+$/, "");
17807
18357
  if (normalizeCase)
17808
18358
  key = key.toLowerCase();
17809
18359
  if (seen.has(key))
@@ -17812,7 +18362,7 @@ function inspectSystemOnnxRuntime(searchPathsOverride) {
17812
18362
  if (!directoryContainsLibrary2(dir, libName))
17813
18363
  continue;
17814
18364
  if (process.platform !== "win32") {
17815
- const probe = probeOnnxRuntimeLoadable(join26(dir, libName));
18365
+ const probe = probeOnnxRuntimeLoadable(join28(dir, libName));
17816
18366
  if (!probe.loadable) {
17817
18367
  ignored ??= { path: dir, reason: `unloadable: ${probe.reason} — ignored` };
17818
18368
  continue;
@@ -17832,12 +18382,12 @@ function inspectSystemOnnxRuntime(searchPathsOverride) {
17832
18382
  return { path: unknownVersionPaths[0] ?? null, ignored };
17833
18383
  }
17834
18384
  function findCachedOnnxRuntime2(storageDir) {
17835
- const ortDir = join26(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
18385
+ const ortDir = join28(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
17836
18386
  const libName = getOnnxLibraryName();
17837
- if (existsSync25(join26(ortDir, libName)))
18387
+ if (existsSync25(join28(ortDir, libName)))
17838
18388
  return ortDir;
17839
- const libSubdir = join26(ortDir, "lib");
17840
- if (existsSync25(join26(libSubdir, libName)))
18389
+ const libSubdir = join28(ortDir, "lib");
18390
+ if (existsSync25(join28(libSubdir, libName)))
17841
18391
  return libSubdir;
17842
18392
  return null;
17843
18393
  }
@@ -17862,7 +18412,7 @@ function detectOrtVersion(libDir) {
17862
18412
  return null;
17863
18413
  const libName = getOnnxLibraryName();
17864
18414
  try {
17865
- const resolved = parseOrtVersionFromPath(realpathSync5(join26(libDir, libName)));
18415
+ const resolved = parseOrtVersionFromPath(realpathSync6(join28(libDir, libName)));
17866
18416
  if (resolved && resolved !== INVALID_ORT_VERSION2)
17867
18417
  return resolved;
17868
18418
  } catch {}
@@ -17878,10 +18428,10 @@ function detectOrtVersion(libDir) {
17878
18428
  if (version)
17879
18429
  return version;
17880
18430
  }
17881
- const base = join26(libDir, libName);
18431
+ const base = join28(libDir, libName);
17882
18432
  if (existsSync25(base)) {
17883
18433
  try {
17884
- const real = realpathSync5(base);
18434
+ const real = realpathSync6(base);
17885
18435
  const version = parseOrtVersionFromPath(real) ?? parseOrtVersionFromDirectoryPath(real);
17886
18436
  if (version)
17887
18437
  return version;
@@ -17942,7 +18492,6 @@ function indexesOf(block) {
17942
18492
  }
17943
18493
  function evaluatePluginLoad(input) {
17944
18494
  const blockers = [];
17945
- const phase = policyPhaseForVersion(input.pluginVersion);
17946
18495
  const tiers = [
17947
18496
  { path: input.userConfigPath, tier: "user" }
17948
18497
  ];
@@ -17970,20 +18519,7 @@ function evaluatePluginLoad(input) {
17970
18519
  if (!value)
17971
18520
  continue;
17972
18521
  const translated = structuredClone(value);
17973
- const translation = translateConfigDocument(translated, phase, tier);
17974
- if (translation.errors.length > 0) {
17975
- const removed = translation.errors.map((code) => code.replace(/^removed_config_key:([^:]+):use:(.+)$/, "$1 → $2")).join(", ");
17976
- const scope = tier === "project" ? " in this project" : "";
17977
- const toolCallError = formatConfigErrorMessage(new ConfigRejectedError(translation.errors, path).message);
17978
- blockers.push({
17979
- code: "config_rejected",
17980
- path,
17981
- message: `${failsEveryToolCall(toolCallError, scope)} (removed keys: ${removed})`,
17982
- toolCallError,
17983
- remediation: `Run \`${CLI} doctor --fix\` to migrate the file, then restart the host.`,
17984
- fixable: true
17985
- });
17986
- }
18522
+ translateConfigDocument(translated, tier);
17987
18523
  loaded[tier] = withHarness(translated, input.harness);
17988
18524
  }
17989
18525
  const subc = loaded.user && isRecord3(loaded.user.subc) ? loaded.user.subc : null;
@@ -18022,11 +18558,11 @@ var init_plugin_load = __esm(() => {
18022
18558
  // src/lib/diagnostics.ts
18023
18559
  import {
18024
18560
  accessSync as accessSync3,
18025
- closeSync as closeSync7,
18026
- constants as constants3,
18561
+ closeSync as closeSync9,
18562
+ constants as constants4,
18027
18563
  existsSync as existsSync27,
18028
- openSync as openSync7,
18029
- readSync as readSync5,
18564
+ openSync as openSync9,
18565
+ readSync as readSync7,
18030
18566
  statSync as statSync16
18031
18567
  } from "node:fs";
18032
18568
  async function collectDiagnostics(adapters) {
@@ -18066,7 +18602,7 @@ async function diagnoseHarness(adapter) {
18066
18602
  if (!existsSync27(storage))
18067
18603
  return false;
18068
18604
  try {
18069
- accessSync3(storage, constants3.R_OK | constants3.W_OK);
18605
+ accessSync3(storage, constants4.R_OK | constants4.W_OK);
18070
18606
  return true;
18071
18607
  } catch {
18072
18608
  return false;
@@ -18077,8 +18613,7 @@ async function diagnoseHarness(adapter) {
18077
18613
  const pluginLoad = evaluatePluginLoad({
18078
18614
  userConfigPath: configPaths.aftConfig,
18079
18615
  projectDirectory: process.cwd(),
18080
- harness: adapter.kind === "opencode" ? "opencode" : "pi",
18081
- pluginVersion: pluginCache.cached ?? getSelfVersion()
18616
+ harness: adapter.kind === "opencode" ? "opencode" : "pi"
18082
18617
  });
18083
18618
  const semanticEnabled = aftEnabled && pluginLoad.onnxRequired;
18084
18619
  const systemInspection = inspectSystemOnnxRuntime();
@@ -18370,7 +18905,7 @@ function tailLogFile(path, lines) {
18370
18905
  let fd = null;
18371
18906
  try {
18372
18907
  const size = statSync16(path).size;
18373
- fd = openSync7(path, "r");
18908
+ fd = openSync9(path, "r");
18374
18909
  const chunks = [];
18375
18910
  let position = size;
18376
18911
  let newlineCount = 0;
@@ -18378,7 +18913,7 @@ function tailLogFile(path, lines) {
18378
18913
  const readLength = Math.min(chunkSize, position);
18379
18914
  position -= readLength;
18380
18915
  const buffer = Buffer.allocUnsafe(readLength);
18381
- const bytesRead = readSync5(fd, buffer, 0, readLength, position);
18916
+ const bytesRead = readSync7(fd, buffer, 0, readLength, position);
18382
18917
  const chunk = bytesRead === readLength ? buffer : buffer.subarray(0, bytesRead);
18383
18918
  chunks.unshift(chunk);
18384
18919
  for (let i = chunk.length - 1;i >= 0; i -= 1) {
@@ -18393,7 +18928,7 @@ function tailLogFile(path, lines) {
18393
18928
  } finally {
18394
18929
  if (fd !== null) {
18395
18930
  try {
18396
- closeSync7(fd);
18931
+ closeSync9(fd);
18397
18932
  } catch {}
18398
18933
  }
18399
18934
  }
@@ -18490,29 +19025,44 @@ function capBodyToGithubLimit(body, maxBytes = MAX_GITHUB_BODY_BYTES) {
18490
19025
  const head = body.slice(0, logBlockStart);
18491
19026
  const log = body.slice(logBlockStart, logBlockEnd);
18492
19027
  const tail = body.slice(logBlockEnd);
18493
- const overheadBytes = Buffer.byteLength(head, "utf8") + Buffer.byteLength(tail, "utf8");
18494
19028
  const truncationMarker = `[truncated for GitHub 64KB limit — older log lines dropped]
18495
19029
  `;
18496
- const markerBytes = Buffer.byteLength(truncationMarker, "utf8");
18497
- const logBudget = maxBytes - overheadBytes - markerBytes;
18498
- if (logBudget <= 0) {
18499
- return `${head}${truncationMarker}${tail}`;
18500
- }
18501
19030
  const lines = log.split(`
18502
19031
  `);
18503
- let keepLines = lines;
18504
- let kept = keepLines.join(`
18505
- `);
18506
- while (Buffer.byteLength(kept, "utf8") > logBudget && keepLines.length > 1) {
18507
- const dropCount = Math.max(1, Math.floor(keepLines.length * 0.05));
18508
- keepLines = keepLines.slice(dropCount);
18509
- kept = keepLines.join(`
18510
- `);
18511
- }
18512
- if (Buffer.byteLength(kept, "utf8") > logBudget) {
18513
- kept = truncateToByteBudget(kept, logBudget);
19032
+ let inFence = false;
19033
+ let fence = "";
19034
+ const payload = [];
19035
+ for (let i = 0;i < lines.length; i++) {
19036
+ const delimiter = lines[i].match(/^\s*(`{3,}|~{3,})/);
19037
+ if (delimiter) {
19038
+ if (!inFence) {
19039
+ inFence = true;
19040
+ fence = delimiter[1];
19041
+ } else if (delimiter[1][0] === fence[0] && delimiter[1].length >= fence.length)
19042
+ inFence = false;
19043
+ } else if (inFence || lines[i] && !/^#{1,6} /.test(lines[i])) {
19044
+ payload.push(i);
19045
+ }
19046
+ }
19047
+ const removed = new Set;
19048
+ const render = () => `${head}${truncationMarker}${lines.filter((_, i) => !removed.has(i)).join(`
19049
+ `)}${tail}`;
19050
+ let size = Buffer.byteLength(render(), "utf8");
19051
+ for (const index of payload) {
19052
+ if (size <= maxBytes)
19053
+ break;
19054
+ const excess = size - maxBytes;
19055
+ const bytes = Buffer.byteLength(lines[index], "utf8");
19056
+ if (index === payload.at(-1) && bytes > excess) {
19057
+ const kept = truncateToByteBudget(lines[index], bytes - excess);
19058
+ size -= bytes - Buffer.byteLength(kept, "utf8");
19059
+ lines[index] = kept;
19060
+ } else {
19061
+ removed.add(index);
19062
+ size -= bytes + 1;
19063
+ }
18514
19064
  }
18515
- return `${head}${truncationMarker}${kept}${tail}`;
19065
+ return render();
18516
19066
  }
18517
19067
  function findNextTopLevelHeading(body, startIdx) {
18518
19068
  const idx = body.indexOf(`
@@ -18548,13 +19098,13 @@ var init_issue_body = __esm(() => {
18548
19098
  // src/lib/onnx-fix.ts
18549
19099
  import { randomBytes as randomBytes2 } from "node:crypto";
18550
19100
  import { existsSync as existsSync28, mkdirSync as mkdirSync7, renameSync as renameSync5, rmSync as rmSync6 } from "node:fs";
18551
- import { isAbsolute as isAbsolute6, join as join27, relative as relative2 } from "node:path";
19101
+ import { isAbsolute as isAbsolute8, join as join29, relative as relative4 } from "node:path";
18552
19102
  function findOnnxFixCandidates(report) {
18553
19103
  const candidates = [];
18554
19104
  for (const harness of report.harnesses) {
18555
19105
  if (!harness.onnxRuntime.required)
18556
19106
  continue;
18557
- const storageOnnxDir = join27(harness.storageDir.path, "onnxruntime");
19107
+ const storageOnnxDir = join29(harness.storageDir.path, "onnxruntime");
18558
19108
  const systemTooOld = harness.onnxRuntime.systemPath !== null && harness.onnxRuntime.systemCompatible === false;
18559
19109
  const cachedTooOld = harness.onnxRuntime.cachedPath !== null && harness.onnxRuntime.cachedCompatible === false;
18560
19110
  const hasCompatibleCached = harness.onnxRuntime.cachedCompatible === true;
@@ -18593,15 +19143,15 @@ function findOnnxFixCandidates(report) {
18593
19143
  async function installManagedReplacement(candidate, ensureFn, rmFn) {
18594
19144
  const suffix = `${process.pid}.${Date.now().toString(36)}.${randomBytes2(6).toString("hex")}`;
18595
19145
  const stagingStorageDir = `${candidate.harness.storageDir.path}.onnx-fix.tmp.${suffix}`;
18596
- const stagedOnnxDir = join27(stagingStorageDir, "onnxruntime");
19146
+ const stagedOnnxDir = join29(stagingStorageDir, "onnxruntime");
18597
19147
  const backupDir = `${candidate.storageOnnxDir}.backup.${suffix}`;
18598
19148
  try {
18599
19149
  const stagedInstalledPath = await ensureFn(stagingStorageDir);
18600
19150
  if (!stagedInstalledPath || !existsSync28(stagedInstalledPath)) {
18601
19151
  throw new Error("managed ONNX Runtime download was unavailable");
18602
19152
  }
18603
- const installedRelativePath = relative2(stagedOnnxDir, stagedInstalledPath);
18604
- if (isAbsolute6(installedRelativePath) || installedRelativePath === ".." || installedRelativePath.startsWith("../") || installedRelativePath.startsWith("..\\")) {
19153
+ const installedRelativePath = relative4(stagedOnnxDir, stagedInstalledPath);
19154
+ if (isAbsolute8(installedRelativePath) || installedRelativePath === ".." || installedRelativePath.startsWith("../") || installedRelativePath.startsWith("..\\")) {
18605
19155
  throw new Error(`managed ONNX Runtime was installed outside staging: ${stagedInstalledPath}`);
18606
19156
  }
18607
19157
  mkdirSync7(candidate.harness.storageDir.path, { recursive: true });
@@ -18629,7 +19179,7 @@ async function installManagedReplacement(candidate, ensureFn, rmFn) {
18629
19179
  }
18630
19180
  }
18631
19181
  return {
18632
- installedPath: join27(candidate.storageOnnxDir, installedRelativePath),
19182
+ installedPath: join29(candidate.storageOnnxDir, installedRelativePath),
18633
19183
  clearedPrevious: hadPrevious && cleanupError === undefined,
18634
19184
  cleanupError
18635
19185
  };
@@ -18696,7 +19246,7 @@ var init_onnx_fix = __esm(() => {
18696
19246
  });
18697
19247
 
18698
19248
  // src/lib/session-log.ts
18699
- import { closeSync as closeSync8, openSync as openSync8, readSync as readSync6, statSync as statSync17 } from "node:fs";
19249
+ import { closeSync as closeSync10, openSync as openSync10, readSync as readSync8, statSync as statSync17 } from "node:fs";
18700
19250
  function readSessionLog(path, session, maxBytes = MAX_SCAN_BYTES) {
18701
19251
  const lines = [];
18702
19252
  const errors = [];
@@ -18734,7 +19284,7 @@ function readSessionLog(path, session, maxBytes = MAX_SCAN_BYTES) {
18734
19284
  break;
18735
19285
  let fd;
18736
19286
  try {
18737
- fd = openSync8(file, "r");
19287
+ fd = openSync10(file, "r");
18738
19288
  let position = statSync17(file).size;
18739
19289
  let suffix = Buffer.alloc(0);
18740
19290
  while (position > 0 && remaining > 0 && (lines.length < 200 || errors.length < 20)) {
@@ -18742,7 +19292,7 @@ function readSessionLog(path, session, maxBytes = MAX_SCAN_BYTES) {
18742
19292
  position -= length;
18743
19293
  remaining -= length;
18744
19294
  const chunk = Buffer.allocUnsafe(length);
18745
- const count = readSync6(fd, chunk, 0, length, position);
19295
+ const count = readSync8(fd, chunk, 0, length, position);
18746
19296
  const bytes = Buffer.concat([chunk.subarray(0, count), suffix]);
18747
19297
  let end = bytes.length;
18748
19298
  for (let i = bytes.length - 1;i >= 0; i -= 1) {
@@ -18761,7 +19311,7 @@ function readSessionLog(path, session, maxBytes = MAX_SCAN_BYTES) {
18761
19311
  boundHit = true;
18762
19312
  } catch {} finally {
18763
19313
  if (fd !== undefined)
18764
- closeSync8(fd);
19314
+ closeSync10(fd);
18765
19315
  }
18766
19316
  }
18767
19317
  return { lines: lines.reverse(), errors: errors.reverse(), boundHit };
@@ -18777,8 +19327,8 @@ var init_session_log = __esm(() => {
18777
19327
  // src/lib/sessions.ts
18778
19328
  import { existsSync as existsSync29, readdirSync as readdirSync12, readFileSync as readFileSync16, statSync as statSync18 } from "node:fs";
18779
19329
  import { createRequire as createRequire4 } from "node:module";
18780
- import { homedir as homedir16 } from "node:os";
18781
- import { basename as basename3, join as join28 } from "node:path";
19330
+ import { homedir as homedir18 } from "node:os";
19331
+ import { basename as basename3, join as join30 } from "node:path";
18782
19332
  function listRecentSessions(adapter) {
18783
19333
  try {
18784
19334
  if (adapter.kind === "opencode")
@@ -18812,7 +19362,7 @@ function mapOpenCodeSessionRows(rows) {
18812
19362
  }).filter((session) => session !== null).sort((a, b) => b.lastActivity - a.lastActivity).slice(0, MAX_RECENT_SESSIONS);
18813
19363
  }
18814
19364
  function listRecentOpenCodeSessions() {
18815
- const dbPath = join28(getXdgDataHome(), "opencode", "opencode.db");
19365
+ const dbPath = join30(getXdgDataHome(), "opencode", "opencode.db");
18816
19366
  if (!existsSync29(dbPath))
18817
19367
  return [];
18818
19368
  let db = null;
@@ -18832,14 +19382,14 @@ function listRecentOpenCodeSessions() {
18832
19382
  }
18833
19383
  function getXdgDataHome() {
18834
19384
  const xdgDataHome = process.env.XDG_DATA_HOME;
18835
- return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join28(homedir16(), ".local", "share");
19385
+ return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join30(homedir18(), ".local", "share");
18836
19386
  }
18837
19387
  function listRecentPiSessions() {
18838
- return listPiSessionsFromDir(join28(getHomeDir(), ".pi", "agent", "sessions"));
19388
+ return listPiSessionsFromDir(join30(getHomeDir(), ".pi", "agent", "sessions"));
18839
19389
  }
18840
19390
  function getHomeDir() {
18841
19391
  const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
18842
- return envHome && envHome.length > 0 ? envHome : homedir16();
19392
+ return envHome && envHome.length > 0 ? envHome : homedir18();
18843
19393
  }
18844
19394
  function listPiSessionsFromDir(sessionsDir) {
18845
19395
  try {
@@ -18881,7 +19431,7 @@ function collectJsonlFiles(root) {
18881
19431
  continue;
18882
19432
  }
18883
19433
  for (const entry of entries) {
18884
- const path = join28(dir, entry.name);
19434
+ const path = join30(dir, entry.name);
18885
19435
  if (entry.isDirectory()) {
18886
19436
  stack.push(path);
18887
19437
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -18986,13 +19536,13 @@ import {
18986
19536
  mkdirSync as mkdirSync8,
18987
19537
  mkdtempSync as mkdtempSync2,
18988
19538
  readFileSync as readFileSync17,
18989
- realpathSync as realpathSync6,
19539
+ realpathSync as realpathSync7,
18990
19540
  rmSync as rmSync7,
18991
19541
  statSync as statSync19,
18992
19542
  writeFileSync as writeFileSync5
18993
19543
  } from "node:fs";
18994
- import { tmpdir as tmpdir4 } from "node:os";
18995
- import { join as join29 } from "node:path";
19544
+ import { tmpdir as tmpdir5 } from "node:os";
19545
+ import { join as join31 } from "node:path";
18996
19546
  function openCodeAdapter(adapters) {
18997
19547
  return adapters.find((adapter) => adapter.kind === "opencode");
18998
19548
  }
@@ -19132,9 +19682,11 @@ async function runDoctor(options) {
19132
19682
  }
19133
19683
  if (opencodeSkew)
19134
19684
  log2.error(` ${opencodeSkew.message} ${opencodeSkew.remediation}`);
19135
- const hostShell = hostShellDoctorLine(opencodeAdapter);
19136
- if (hostShell)
19137
- log2[hostShell.level](` ${hostShell.text}`);
19685
+ for (const hostTool of OPENCODE_HOST_TOOL_NAMES) {
19686
+ const line = hostToolDoctorLine(opencodeAdapter, hostTool);
19687
+ if (line)
19688
+ log2[line.level](` ${line.text}`);
19689
+ }
19138
19690
  }
19139
19691
  const blockers = h.pluginLoad?.blockers ?? [];
19140
19692
  if (h.pluginRegistered && blockers.length > 0) {
@@ -19411,7 +19963,7 @@ function clearOldBinaries() {
19411
19963
  return result;
19412
19964
  }
19413
19965
  for (const version of stale) {
19414
- const dir = join29(info.path, version);
19966
+ const dir = join31(info.path, version);
19415
19967
  let bytes = 0;
19416
19968
  try {
19417
19969
  bytes = statSync19(dir).isDirectory() ? dirSize(dir) : 0;
@@ -19434,34 +19986,35 @@ function clearOldBinaries() {
19434
19986
  }
19435
19987
  return result;
19436
19988
  }
19437
- function hostShellDoctorLine(adapter) {
19989
+ function hostToolDoctorLine(adapter, hostTool) {
19438
19990
  if (!(adapter instanceof OpenCodeAdapter))
19439
19991
  return null;
19440
- const state = adapter.hostShellState();
19992
+ const { disableEntry, aftTool } = OPENCODE_HOST_TOOLS[hostTool];
19993
+ const state = adapter.hostToolState(hostTool);
19441
19994
  if (state === "not_applicable")
19442
19995
  return null;
19443
19996
  if (state === "disabled") {
19444
19997
  return {
19445
19998
  level: "info",
19446
- text: `OpenCode's own shell tool: disabled (${OPENCODE_HOST_SHELL_DISABLE_ENTRY} is set); agents use AFT's bash`
19999
+ text: `OpenCode's own ${hostTool} tool: disabled (${disableEntry} is set); agents use AFT's ${aftTool}`
19447
20000
  };
19448
20001
  }
19449
- if (!adapter.aftBashEnabled()) {
20002
+ if (!adapter.aftHostReplacementEnabled(hostTool)) {
19450
20003
  return {
19451
20004
  level: "info",
19452
- text: "OpenCode's own shell tool: enabled (AFT's bash is disabled, so it stays)"
20005
+ text: `OpenCode's own ${hostTool} tool: enabled (AFT's ${aftTool} is disabled, so it stays)`
19453
20006
  };
19454
20007
  }
19455
20008
  return {
19456
20009
  level: "warn",
19457
- text: `OpenCode's own shell tool: enabled beside AFT's bash — run \`${CLI} doctor --fix\` or \`${CLI} setup\` to disable it (${OPENCODE_HOST_SHELL_DISABLE_ENTRY})`
20010
+ text: `OpenCode's own ${hostTool} tool: enabled beside AFT's ${aftTool} — run \`${CLI} doctor --fix\` or \`${CLI} setup\` to disable it (${disableEntry})`
19458
20011
  };
19459
20012
  }
19460
- function hostShellFixTarget(adapters) {
20013
+ function hostToolFixTargets(adapters) {
19461
20014
  const adapter = openCodeAdapter(adapters);
19462
20015
  if (!(adapter instanceof OpenCodeAdapter))
19463
- return null;
19464
- return adapter.hostShellState() === "enabled" && adapter.aftBashEnabled() ? adapter : null;
20016
+ return [];
20017
+ return OPENCODE_HOST_TOOL_NAMES.filter((hostTool) => adapter.hostToolState(hostTool) === "enabled" && adapter.aftHostReplacementEnabled(hostTool)).map((hostTool) => ({ adapter, hostTool }));
19465
20018
  }
19466
20019
  function findPluginUpdateTargets(adapters, report) {
19467
20020
  const adaptersByKind = new Map(adapters.map((a) => [a.kind, a]));
@@ -19570,7 +20123,7 @@ async function runDoctorNpmInstall(npm, installDir) {
19570
20123
  });
19571
20124
  }
19572
20125
  function installedPluginVersion(installDir) {
19573
- const manifest = join29(installDir, "node_modules", ...AFT_OPENCODE_PACKAGE.split("/"), "package.json");
20126
+ const manifest = join31(installDir, "node_modules", ...AFT_OPENCODE_PACKAGE.split("/"), "package.json");
19574
20127
  try {
19575
20128
  const pkg = JSON.parse(readFileSync17(manifest, "utf-8"));
19576
20129
  return typeof pkg.version === "string" ? pkg.version : null;
@@ -19692,11 +20245,11 @@ function buildDoctorFixPlan(adapters, report) {
19692
20245
  message: `Will ${hasTuiEntry ? "update" : "add"} ${adapter.pluginEntryWithVersion} ${hasTuiEntry ? "in" : "to"} ${harness.configPaths.tuiConfig} (TUI sidebar)`
19693
20246
  });
19694
20247
  }
19695
- const hostShellTarget = hostShellFixTarget(adapters);
19696
- if (hostShellTarget) {
20248
+ for (const { adapter, hostTool } of hostToolFixTargets(adapters)) {
20249
+ const { disableEntry, aftTool } = OPENCODE_HOST_TOOLS[hostTool];
19697
20250
  items.push({
19698
20251
  kind: "plugin",
19699
- message: `Will add ${OPENCODE_HOST_SHELL_DISABLE_ENTRY} to ${hostShellTarget.detectConfigPaths().harnessConfig} so agents use AFT's bash instead of OpenCode's own shell tool`
20252
+ message: `Will add ${disableEntry} to ${adapter.detectConfigPaths().harnessConfig} so agents use AFT's ${aftTool} instead of OpenCode's own ${hostTool} tool`
19700
20253
  });
19701
20254
  }
19702
20255
  for (const target of findPluginUpdateTargets(adapters, report)) {
@@ -19844,9 +20397,8 @@ async function runFixFlow(argv, detectOpenCodeHost, resolveAdapters = resolveAda
19844
20397
  }
19845
20398
  }
19846
20399
  const pluginEntrySummary = configWritesRefused ? { changed: 0, errors: 0 } : await fixPluginEntries(adapters);
19847
- const hostShellTarget = configWritesRefused ? null : hostShellFixTarget(adapters);
19848
- if (hostShellTarget) {
19849
- const result = hostShellTarget.setHostShellDisabled(true);
20400
+ for (const { adapter, hostTool } of configWritesRefused ? [] : hostToolFixTargets(adapters)) {
20401
+ const result = adapter.setHostToolDisabled(hostTool, true);
19850
20402
  if (result.ok) {
19851
20403
  if (result.action !== "already_present")
19852
20404
  log2.success(`OpenCode: ${result.message}`);
@@ -20205,14 +20757,14 @@ function deriveIssueTitleFromBody(body) {
20205
20757
  function writeIssueReviewFile(body) {
20206
20758
  let reviewDir = null;
20207
20759
  try {
20208
- reviewDir = mkdtempSync2(join29(tmpdir4(), "aft-issue-"));
20760
+ reviewDir = mkdtempSync2(join31(tmpdir5(), "aft-issue-"));
20209
20761
  if (process.platform !== "win32") {
20210
20762
  chmodSync3(reviewDir, 448);
20211
20763
  }
20212
- const outPath = join29(reviewDir, "issue.md");
20764
+ const outPath = join31(reviewDir, "issue.md");
20213
20765
  writeFileSync5(outPath, `${body}
20214
20766
  `, { encoding: "utf8", mode: 384, flag: "wx" });
20215
- return { path: outPath, realPath: realpathSync6(outPath) };
20767
+ return { path: outPath, realPath: realpathSync7(outPath) };
20216
20768
  } catch (err) {
20217
20769
  if (reviewDir) {
20218
20770
  try {
@@ -20225,7 +20777,7 @@ function writeIssueReviewFile(body) {
20225
20777
  }
20226
20778
  function readReviewedIssueFile(reviewFile) {
20227
20779
  try {
20228
- const realPath = realpathSync6(reviewFile.path);
20780
+ const realPath = realpathSync7(reviewFile.path);
20229
20781
  if (realPath !== reviewFile.realPath) {
20230
20782
  log2.error(`Review file path changed before filing; refusing to read ${reviewFile.path}.`);
20231
20783
  return null;
@@ -20438,24 +20990,24 @@ var init_doctor = __esm(async () => {
20438
20990
  // src/commands/lsp.ts
20439
20991
  import { existsSync as existsSync31, readdirSync as readdirSync13, statSync as statSync20 } from "node:fs";
20440
20992
  import { createRequire as createRequire5 } from "node:module";
20441
- import { dirname as dirname11, join as join30, resolve as resolve13 } from "node:path";
20993
+ import { dirname as dirname12, join as join32, resolve as resolve15 } from "node:path";
20442
20994
  function findProjectRootForFile(filePath, fallbackCwd = process.cwd()) {
20443
- const resolvedFile = resolve13(fallbackCwd, filePath);
20444
- let dir = dirname11(resolvedFile);
20995
+ const resolvedFile = resolve15(fallbackCwd, filePath);
20996
+ let dir = dirname12(resolvedFile);
20445
20997
  try {
20446
20998
  if (existsSync31(resolvedFile) && statSync20(resolvedFile).isDirectory()) {
20447
20999
  dir = resolvedFile;
20448
21000
  }
20449
21001
  } catch {
20450
- dir = dirname11(resolvedFile);
21002
+ dir = dirname12(resolvedFile);
20451
21003
  }
20452
21004
  while (true) {
20453
- if (PROJECT_ROOT_MARKERS.some((marker) => existsSync31(join30(dir, marker)))) {
21005
+ if (PROJECT_ROOT_MARKERS.some((marker) => existsSync31(join32(dir, marker)))) {
20454
21006
  return dir;
20455
21007
  }
20456
- const parent = dirname11(dir);
21008
+ const parent = dirname12(dir);
20457
21009
  if (parent === dir)
20458
- return resolve13(fallbackCwd);
21010
+ return resolve15(fallbackCwd);
20459
21011
  dir = parent;
20460
21012
  }
20461
21013
  }
@@ -20486,7 +21038,7 @@ async function runLspDoctor(options) {
20486
21038
  log2.error("Could not find the aft binary in the cache, platform package, PATH, or ~/.cargo/bin.");
20487
21039
  return 1;
20488
21040
  }
20489
- const resolvedFile = resolve13(file);
21041
+ const resolvedFile = resolve15(file);
20490
21042
  const projectRoot = findProjectRootForFile(resolvedFile);
20491
21043
  const config = buildConfigureParams(adapter, projectRoot);
20492
21044
  const inspectRequest = {
@@ -20599,10 +21151,10 @@ function buildConfigureParams(adapter, projectRoot) {
20599
21151
  function inferLspPathsExtra(_lsp) {
20600
21152
  const paths = new Set;
20601
21153
  for (const entry of childDirs(getAftLspPackagesDir())) {
20602
- paths.add(join30(entry, "node_modules", ".bin"));
21154
+ paths.add(join32(entry, "node_modules", ".bin"));
20603
21155
  }
20604
21156
  for (const entry of childDirs(getAftLspBinariesDir())) {
20605
- paths.add(join30(entry, "bin"));
21157
+ paths.add(join32(entry, "bin"));
20606
21158
  }
20607
21159
  return [...paths];
20608
21160
  }
@@ -20610,7 +21162,7 @@ function childDirs(path) {
20610
21162
  if (!existsSync31(path))
20611
21163
  return [];
20612
21164
  try {
20613
- return readdirSync13(path).map((entry) => join30(path, entry)).filter((entry) => {
21165
+ return readdirSync13(path).map((entry) => join32(path, entry)).filter((entry) => {
20614
21166
  try {
20615
21167
  return statSync20(entry).isDirectory();
20616
21168
  } catch {
@@ -20622,11 +21174,13 @@ function childDirs(path) {
20622
21174
  }
20623
21175
  }
20624
21176
  function formatBinary(server) {
21177
+ const names = server.binary_names?.length ? server.binary_names : [server.binary_name];
21178
+ const alternatives = names.length > 1 ? `; candidates: ${names.join(" or ")}` : "";
20625
21179
  if (!server.binary_path) {
20626
21180
  const locations = server.kind === "python" || server.kind === "ty" ? "workspace virtualenv, node_modules/.bin, lsp_paths_extra, or PATH" : "node_modules/.bin, lsp_paths_extra, or PATH";
20627
- return `${server.binary_name} (NOT FOUND in ${locations})`;
21181
+ return `${names.join(" or ")} (NOT FOUND in ${locations})`;
20628
21182
  }
20629
- return `${server.binary_path} (found via ${server.binary_source})`;
21183
+ return `${server.binary_path} (found via ${server.binary_source}${alternatives})`;
20630
21184
  }
20631
21185
  function formatWorkspaceRoot(server) {
20632
21186
  if (!server.workspace_root) {
@@ -20652,7 +21206,7 @@ function typescriptPackageWarning(response) {
20652
21206
  if (!typescriptServerSpawned || !response.project_root || diagnosticsCount > 0)
20653
21207
  return null;
20654
21208
  try {
20655
- createRequire5(join30(response.project_root, "package.json")).resolve("typescript");
21209
+ createRequire5(join32(response.project_root, "package.json")).resolve("typescript");
20656
21210
  return null;
20657
21211
  } catch {
20658
21212
  return "typescript package not resolvable from project — server will produce no diagnostics";
@@ -20693,8 +21247,7 @@ var init_lsp = __esm(async () => {
20693
21247
 
20694
21248
  // src/commands/doctor-filters.ts
20695
21249
  import { existsSync as existsSync32 } from "node:fs";
20696
- import { homedir as homedir17 } from "node:os";
20697
- import { relative as relative3, resolve as resolve14 } from "node:path";
21250
+ import { relative as relative5, resolve as resolve16 } from "node:path";
20698
21251
  function printDoctorFiltersHelp() {
20699
21252
  console.log(`Usage: ${CLI} doctor filters [--show <name>] [trust|untrust]`);
20700
21253
  console.log("");
@@ -20729,7 +21282,7 @@ async function runDoctorFilters(options) {
20729
21282
  log2.error("Could not find the aft binary in the cache, platform package, PATH, or ~/.cargo/bin.");
20730
21283
  return 1;
20731
21284
  }
20732
- const projectRoot = resolve14(process.cwd());
21285
+ const projectRoot = resolve16(process.cwd());
20733
21286
  const list = await listFilters(binary, adapter, projectRoot, options.sendRequests ?? sendAftRequests);
20734
21287
  if (!list.success) {
20735
21288
  log2.error(list.message ?? list.code ?? "list_filters failed");
@@ -20911,14 +21464,13 @@ function truncate(value) {
20911
21464
  return value.length <= 80 ? value : `${value.slice(0, 77)}…`;
20912
21465
  }
20913
21466
  function formatHome(path) {
20914
- const home = homedir17();
20915
- return path.startsWith(home) ? `~${path.slice(home.length)}` : path;
21467
+ return shortenHomePath(path);
20916
21468
  }
20917
21469
  function formatProjectPath(path, projectRoot) {
20918
21470
  if (!path)
20919
21471
  return "";
20920
- const rel = relative3(projectRoot, path);
20921
- return rel.startsWith("..") || rel === "" ? path : `./${rel}`;
21472
+ const rel = relative5(projectRoot, path);
21473
+ return relativePathEscapesRoot(rel) || rel === "" ? path : `./${rel}`;
20922
21474
  }
20923
21475
  function formatSourcePath(path, projectRoot) {
20924
21476
  if (!path)
@@ -20926,6 +21478,7 @@ function formatSourcePath(path, projectRoot) {
20926
21478
  return formatProjectPath(path, projectRoot);
20927
21479
  }
20928
21480
  var init_doctor_filters = __esm(async () => {
21481
+ init_dist2();
20929
21482
  init_aft_bridge();
20930
21483
  init_harness_select();
20931
21484
  init_prompts();
@@ -20949,6 +21502,7 @@ function printHelp() {
20949
21502
  console.log(" setup --answers <file> Save feature choices from an answers file");
20950
21503
  console.log(" index Build one configured index snapshot (no scheduler)");
20951
21504
  console.log(" backups purge Remove undo backups by --path and/or --session (dry run unless --yes)");
21505
+ console.log(" cache prune-legacy Delete legacy index caches past their rollback window (dry run unless --yes)");
20952
21506
  console.log(" doctor Check and fix configuration issues");
20953
21507
  console.log(" doctor --profile [seconds] Profile a running AFT daemon");
20954
21508
  console.log(" doctor lsp <file> Inspect LSP setup for one file");
@@ -20969,6 +21523,7 @@ function printHelp() {
20969
21523
  console.log(` ${CLI} setup`);
20970
21524
  console.log(` ${CLI} index`);
20971
21525
  console.log(` ${CLI} backups purge --path ./build --yes`);
21526
+ console.log(` ${CLI} cache prune-legacy`);
20972
21527
  console.log(` ${CLI} doctor`);
20973
21528
  console.log(` ${CLI} doctor --profile 4`);
20974
21529
  console.log(` ${CLI} doctor lsp ./src/main.py`);
@@ -20994,6 +21549,10 @@ async function main() {
20994
21549
  await init_backups();
20995
21550
  return runBackups(args);
20996
21551
  }
21552
+ if (command === "cache") {
21553
+ await init_cache();
21554
+ return runCache(args);
21555
+ }
20997
21556
  if (command === "doctor") {
20998
21557
  if (args.includes("--profile")) {
20999
21558
  await init_doctor();