@cortexkit/aft 0.59.0 → 0.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +436 -170
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -109,6 +109,29 @@ 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
+
113
+ // ../aft-bridge/dist/protocol.js
114
+ function isTerminalBashStatus(status, compatibilityAliases = false) {
115
+ return typeof status === "string" && (TERMINAL_BASH_STATUSES.has(status) || compatibilityAliases && (status === "cancelled" || status === "timeout"));
116
+ }
117
+ var TERMINAL_BG_TASK_STATUSES, TERMINAL_BASH_STATUSES;
118
+ var init_protocol = __esm(() => {
119
+ TERMINAL_BG_TASK_STATUSES = Object.freeze([
120
+ "completed",
121
+ "failed",
122
+ "killed",
123
+ "timed_out",
124
+ "fate_unknown"
125
+ ]);
126
+ TERMINAL_BASH_STATUSES = new Set(TERMINAL_BG_TASK_STATUSES);
127
+ });
128
+
129
+ // ../aft-bridge/dist/bash-format.js
130
+ var init_bash_format = __esm(() => {
131
+ init_protocol();
132
+ init_protocol();
133
+ });
134
+
112
135
  // ../aft-bridge/dist/path-display.js
113
136
  import { homedir } from "node:os";
114
137
  import { posix, win32 } from "node:path";
@@ -129,6 +152,7 @@ var init_path_display = () => {};
129
152
 
130
153
  // ../aft-bridge/dist/bash-hints.js
131
154
  var init_bash_hints = __esm(() => {
155
+ init_bash_format();
132
156
  init_path_display();
133
157
  });
134
158
 
@@ -609,15 +633,12 @@ var init_command_timeouts = __esm(() => {
609
633
  });
610
634
 
611
635
  // ../aft-bridge/dist/transport.js
612
- var WORKER_SESSION_FIELD = "worker_session";
636
+ var WORKER_SESSION_FIELD = "worker_session", HOST_TOOL_NAMES_FIELD = "host_tool_names";
613
637
 
614
638
  // ../aft-bridge/dist/bridge.js
615
639
  import { homedir as homedir4 } from "node:os";
616
640
  import { join as join3 } from "node:path";
617
641
  import { StringDecoder } from "node:string_decoder";
618
- function isTerminalBashStatus(status) {
619
- return typeof status === "string" && TERMINAL_BASH_STATUSES.has(status);
620
- }
621
642
  function bashTaskIdFrom(response) {
622
643
  const snakeCase = response.task_id;
623
644
  if (typeof snakeCase === "string" && snakeCase.length > 0)
@@ -646,44 +667,37 @@ function shouldSurfaceStderrLine(line) {
646
667
  return !(normalized === `Error in cpuinfo: ${BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE}` || normalized === BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE);
647
668
  }
648
669
  function compareSemver(a, b) {
649
- const [aMain, aPre] = a.split("-", 2);
650
- const [bMain, bPre] = b.split("-", 2);
651
- const aParts = aMain.split(".").map(Number);
652
- const bParts = bMain.split(".").map(Number);
670
+ const parse = (version) => {
671
+ const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(version);
672
+ const pre = match?.[4]?.split(".") ?? [];
673
+ if (!match || pre.some((id) => /^\d+$/.test(id) && id.length > 1 && id[0] === "0")) {
674
+ throw new Error(`Invalid semantic version: ${version}`);
675
+ }
676
+ return { core: match.slice(1, 4), pre };
677
+ };
678
+ const numeric = (a, b) => a.length !== b.length ? a.length - b.length : a === b ? 0 : a < b ? -1 : 1;
679
+ const left = parse(a);
680
+ const right = parse(b);
653
681
  for (let i = 0;i < 3; i++) {
654
- if (aParts[i] !== bParts[i])
655
- return (aParts[i] ?? 0) - (bParts[i] ?? 0);
682
+ const diff = numeric(left.core[i], right.core[i]);
683
+ if (diff !== 0)
684
+ return diff;
656
685
  }
657
- if (!aPre && !bPre)
658
- return 0;
659
- if (!aPre)
660
- return 1;
661
- if (!bPre)
662
- return -1;
663
- const aIds = aPre.split(".");
664
- const bIds = bPre.split(".");
665
- for (let i = 0;i < Math.max(aIds.length, bIds.length); i++) {
666
- const ai = aIds[i];
667
- const bi = bIds[i];
686
+ if (left.pre.length === 0 || right.pre.length === 0) {
687
+ return left.pre.length === right.pre.length ? 0 : left.pre.length === 0 ? 1 : -1;
688
+ }
689
+ for (let i = 0;i < Math.max(left.pre.length, right.pre.length); i++) {
690
+ const ai = left.pre[i];
691
+ const bi = right.pre[i];
668
692
  if (ai === undefined)
669
693
  return -1;
670
694
  if (bi === undefined)
671
695
  return 1;
672
696
  const aNum = /^\d+$/.test(ai);
673
697
  const bNum = /^\d+$/.test(bi);
674
- if (aNum && bNum) {
675
- const diff = Number.parseInt(ai, 10) - Number.parseInt(bi, 10);
676
- if (diff !== 0)
677
- return diff;
678
- } else if (aNum) {
679
- return -1;
680
- } else if (bNum) {
681
- return 1;
682
- } else {
683
- const cmp = ai.localeCompare(bi);
684
- if (cmp !== 0)
685
- return cmp;
686
- }
698
+ const diff = aNum && bNum ? numeric(ai, bi) : aNum !== bNum ? aNum ? -1 : 1 : ai === bi ? 0 : ai < bi ? -1 : 1;
699
+ if (diff !== 0)
700
+ return diff;
687
701
  }
688
702
  return 0;
689
703
  }
@@ -701,22 +715,27 @@ function coerceConfigureDroppedKeys(value) {
701
715
  }
702
716
  return dropped;
703
717
  }
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;
718
+ function shellOutcomeFromLateReply(response) {
719
+ const taskId = bashTaskIdFrom(response);
720
+ if (taskId)
721
+ return { kind: "task_started", taskId };
722
+ if (response.success === false) {
723
+ return {
724
+ kind: "not_started",
725
+ ...typeof response.code === "string" ? { code: response.code } : {},
726
+ ...typeof response.message === "string" ? { message: response.message } : {}
727
+ };
728
+ }
729
+ return { kind: "unknown" };
730
+ }
731
+ 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, binaryFingerprintReader, binaryFingerprintAsyncReader, BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE = "failed to parse processor information from /proc/cpuinfo", BridgeReplacedDuringVersionCheck, BridgeTransportTimeoutError, SHELL_TASK_COMMANDS, DEFAULT_LATE_SHELL_REPLY_GRACE_MS = 1e4, BridgeTransportUnavailableError, BridgeTransportUnknownOutcomeError, BinaryBridge;
705
732
  var init_bridge = __esm(() => {
706
733
  init_active_logger();
707
734
  init_binary_identity();
708
735
  init_child_process();
709
736
  init_command_timeouts();
737
+ init_protocol();
710
738
  MAX_STDOUT_BUFFER = 64 * 1024 * 1024;
711
- TERMINAL_BASH_STATUSES = new Set([
712
- "completed",
713
- "failed",
714
- "killed",
715
- "timed_out",
716
- "fate_unknown",
717
- "cancelled",
718
- "timeout"
719
- ]);
720
739
  binaryFingerprintReader = peekBinaryFingerprint;
721
740
  binaryFingerprintAsyncReader = binaryContentHash;
722
741
  BridgeReplacedDuringVersionCheck = class BridgeReplacedDuringVersionCheck extends Error {
@@ -731,13 +750,16 @@ var init_bridge = __esm(() => {
731
750
  command;
732
751
  timeoutMs;
733
752
  code = "transport_timeout";
734
- constructor(command, timeoutMs, message) {
753
+ shellOutcome;
754
+ constructor(command, timeoutMs, message, shellOutcome) {
735
755
  super(message);
736
756
  this.command = command;
737
757
  this.timeoutMs = timeoutMs;
738
758
  this.name = "BridgeTransportTimeoutError";
759
+ this.shellOutcome = shellOutcome;
739
760
  }
740
761
  };
762
+ SHELL_TASK_COMMANDS = new Set(["bash", "powershell"]);
741
763
  BridgeTransportUnavailableError = class BridgeTransportUnavailableError extends Error {
742
764
  code = "bridge_transport_unavailable";
743
765
  constructor(message, options) {
@@ -761,6 +783,8 @@ var init_bridge = __esm(() => {
761
783
  lastBinaryFingerprintCheckAt = 0;
762
784
  _retiringDueToBinaryChange = false;
763
785
  pending = new Map;
786
+ activeSendCalls = 0;
787
+ processLoopReferenced = true;
764
788
  outstandingBackgroundTaskIds = new Set;
765
789
  nextId = 1;
766
790
  processGeneration = 0;
@@ -776,6 +800,7 @@ var init_bridge = __esm(() => {
776
800
  _shuttingDown = false;
777
801
  timeoutMs;
778
802
  hangThreshold;
803
+ lateShellReplyGraceMs;
779
804
  maxRestarts;
780
805
  configured = false;
781
806
  _configurePromise = null;
@@ -792,6 +817,7 @@ var init_bridge = __esm(() => {
792
817
  cachedStatus = null;
793
818
  statusListeners = new Set;
794
819
  configureWarningClients = new Map;
820
+ restartTimer = null;
795
821
  restartResetTimer = null;
796
822
  lastChildActivityAt = 0;
797
823
  consecutiveRequestTimeouts = 0;
@@ -805,6 +831,7 @@ var init_bridge = __esm(() => {
805
831
  this.cwd = cwd;
806
832
  this.timeoutMs = options?.timeoutMs ?? DEFAULT_BRIDGE_TIMEOUT_MS;
807
833
  this.hangThreshold = options?.hangThreshold ?? BRIDGE_HANG_TIMEOUT_THRESHOLD;
834
+ this.lateShellReplyGraceMs = options?.lateShellReplyGraceMs ?? DEFAULT_LATE_SHELL_REPLY_GRACE_MS;
808
835
  this.maxRestarts = options?.maxRestarts ?? 3;
809
836
  this.errorPrefix = options?.errorPrefix ?? "[aft-bridge]";
810
837
  this.configOverrides = { ...configOverrides ?? {} };
@@ -992,6 +1019,32 @@ var init_bridge = __esm(() => {
992
1019
  this.sessionLogVia(sessionId, `hashline registration carrier transport=ndjson phase=${phase} edit_slot_survives=${editSlotSurvives}${repeated}`);
993
1020
  }
994
1021
  async send(command, params = {}, options) {
1022
+ this.activeSendCalls += 1;
1023
+ this.syncEventLoopHold();
1024
+ try {
1025
+ return await this.dispatchSend(command, params, options);
1026
+ } finally {
1027
+ this.activeSendCalls -= 1;
1028
+ this.syncEventLoopHold();
1029
+ }
1030
+ }
1031
+ syncEventLoopHold() {
1032
+ const child = this.process;
1033
+ if (!child)
1034
+ return;
1035
+ const hold = this.activeSendCalls > 0 || this.outstandingBackgroundTaskIds.size > 0;
1036
+ if (hold === this.processLoopReferenced)
1037
+ return;
1038
+ this.processLoopReferenced = hold;
1039
+ const handles = [child, child.stdin, child.stdout, child.stderr];
1040
+ for (const handle of handles) {
1041
+ if (hold)
1042
+ handle?.ref?.();
1043
+ else
1044
+ handle?.unref?.();
1045
+ }
1046
+ }
1047
+ async dispatchSend(command, params, options) {
995
1048
  let dispatchParams = params;
996
1049
  if (command === "configure") {
997
1050
  dispatchParams = { ...params };
@@ -1029,11 +1082,13 @@ var init_bridge = __esm(() => {
1029
1082
  params.edit_slot_survives = editSlotSurvives;
1030
1083
  this.logHashlineRegistrationCarrier("tool_call", sessionId, editSlotSurvives);
1031
1084
  }
1032
- const { preview, workerSession, ...sendOptions } = options ?? {};
1085
+ const { preview, workerSession, hostToolNames, ...sendOptions } = options ?? {};
1033
1086
  if (preview === true)
1034
1087
  params.preview = true;
1035
1088
  if (workerSession === true)
1036
1089
  params[WORKER_SESSION_FIELD] = true;
1090
+ if (hostToolNames)
1091
+ params[HOST_TOOL_NAMES_FIELD] = hostToolNames;
1037
1092
  return await this.send("tool_call", params, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
1038
1093
  }
1039
1094
  async sendWithVersionMismatchRetry(command, params, options, canRetryAfterVersionSwap) {
@@ -1049,9 +1104,6 @@ var init_bridge = __esm(() => {
1049
1104
  }
1050
1105
  const requestSessionId = typeof params.session_id === "string" && params.session_id.length > 0 ? params.session_id : undefined;
1051
1106
  this.ensureSpawned(requestSessionId);
1052
- if (requestSessionId && options?.configureWarningClient !== undefined) {
1053
- this.configureWarningClients.set(requestSessionId, options.configureWarningClient);
1054
- }
1055
1107
  const passive = isPassiveCommand(command);
1056
1108
  const resolvedTimeoutMs = options?.transportTimeoutMs ?? options?.timeoutMs ?? this.timeoutMs;
1057
1109
  const effectiveTimeoutMs = passive ? Math.min(resolvedTimeoutMs, PASSIVE_COMMAND_TIMEOUT_MS) : resolvedTimeoutMs;
@@ -1062,6 +1114,9 @@ var init_bridge = __esm(() => {
1062
1114
  if (!this.configured) {
1063
1115
  if (command !== "configure" && command !== "version") {
1064
1116
  if (!this._configurePromise) {
1117
+ if (this.onConfigureWarnings && requestSessionId && options?.configureWarningClient !== undefined) {
1118
+ this.configureWarningClients.set(requestSessionId, options.configureWarningClient);
1119
+ }
1065
1120
  const configuringChild = this.process;
1066
1121
  const requireConfiguringChild = () => {
1067
1122
  if (this.process !== configuringChild) {
@@ -1088,6 +1143,10 @@ var init_bridge = __esm(() => {
1088
1143
  throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
1089
1144
  }
1090
1145
  this.configured = true;
1146
+ } catch (error) {
1147
+ if (sessionIdForConfigure)
1148
+ this.configureWarningClients.delete(sessionIdForConfigure);
1149
+ throw error;
1091
1150
  } finally {
1092
1151
  this._configurePromise = null;
1093
1152
  }
@@ -1102,7 +1161,12 @@ var init_bridge = __esm(() => {
1102
1161
  if (command === "cancel_request" || Object.hasOwn(params, "command") || Object.hasOwn(params, "method")) {
1103
1162
  const nested = { ...params };
1104
1163
  const reserved = {};
1105
- for (const key of ["session_id", "lsp_hints", WORKER_SESSION_FIELD]) {
1164
+ for (const key of [
1165
+ "session_id",
1166
+ "lsp_hints",
1167
+ WORKER_SESSION_FIELD,
1168
+ HOST_TOOL_NAMES_FIELD
1169
+ ]) {
1106
1170
  if (Object.hasOwn(nested, key)) {
1107
1171
  reserved[key] = nested[key];
1108
1172
  delete nested[key];
@@ -1122,6 +1186,9 @@ var init_bridge = __esm(() => {
1122
1186
  const entry = this.pending.get(id);
1123
1187
  if (!entry)
1124
1188
  return;
1189
+ if (keepBridgeOnTimeout && this.holdForLateShellReply(id, entry, effectiveTimeoutMs, requestSessionId)) {
1190
+ return;
1191
+ }
1125
1192
  this.pending.delete(id);
1126
1193
  clearTimeout(entry.timer);
1127
1194
  entry.onSettled?.();
@@ -1216,52 +1283,48 @@ var init_bridge = __esm(() => {
1216
1283
  }
1217
1284
  }
1218
1285
  async deliverConfigureWarnings(configResult, params, options) {
1286
+ const sessionId = typeof params.session_id === "string" ? params.session_id : undefined;
1287
+ const client = options?.configureWarningClient ?? (sessionId ? this.configureWarningClients.get(sessionId) : undefined);
1288
+ if (sessionId && configResult.warnings_pending !== true)
1289
+ this.configureWarningClients.delete(sessionId);
1219
1290
  if (!this.onConfigureWarnings)
1220
1291
  return;
1221
1292
  const warnings = Array.isArray(configResult.warnings) ? configResult.warnings : [];
1222
1293
  const configDroppedKeys = coerceConfigureDroppedKeys(configResult.config_dropped_keys);
1223
1294
  if (warnings.length === 0 && configDroppedKeys.length === 0)
1224
1295
  return;
1225
- const sessionId = typeof params.session_id === "string" ? params.session_id : undefined;
1226
1296
  const context = {
1227
1297
  projectRoot: this.cwd,
1228
1298
  sessionId,
1229
- client: options?.configureWarningClient ?? (sessionId ? this.configureWarningClients.get(sessionId) : undefined),
1299
+ client,
1230
1300
  warnings
1231
1301
  };
1232
- if (configDroppedKeys.length > 0) {
1302
+ if (configDroppedKeys.length > 0)
1233
1303
  context.configDroppedKeys = configDroppedKeys;
1234
- }
1235
- try {
1236
- await this.onConfigureWarnings(context);
1237
- } catch (err) {
1238
- this.warnVia(`configure warning delivery failed: ${err instanceof Error ? err.message : String(err)}`);
1239
- } finally {
1240
- if (sessionId) {
1241
- this.configureWarningClients.delete(sessionId);
1242
- }
1243
- }
1304
+ this.dispatchHostCallback("configure warning", () => this.onConfigureWarnings?.(context));
1244
1305
  }
1245
1306
  async handleConfigureWarningsFrame(frame) {
1246
- if (!this.onConfigureWarnings)
1247
- return;
1248
- const warnings = frame.warnings;
1249
- if (!Array.isArray(warnings) || warnings.length === 0)
1307
+ const sessionId = typeof frame.session_id === "string" && frame.session_id.length > 0 ? frame.session_id : null;
1308
+ const client = sessionId ? this.configureWarningClients.get(sessionId) : undefined;
1309
+ if (sessionId)
1310
+ this.configureWarningClients.delete(sessionId);
1311
+ if (!this.onConfigureWarnings || !Array.isArray(frame.warnings) || frame.warnings.length === 0)
1250
1312
  return;
1251
- const projectRoot = typeof frame.project_root === "string" ? frame.project_root : this.cwd;
1252
- const rawSessionId = frame.session_id;
1253
- const sessionId = typeof rawSessionId === "string" && rawSessionId.length > 0 ? rawSessionId : null;
1313
+ this.dispatchHostCallback("configure warning", () => this.onConfigureWarnings?.({
1314
+ projectRoot: typeof frame.project_root === "string" ? frame.project_root : this.cwd,
1315
+ sessionId,
1316
+ client,
1317
+ warnings: frame.warnings
1318
+ }));
1319
+ }
1320
+ dispatchHostCallback(label, callback) {
1321
+ const failed = (error) => {
1322
+ this.warnVia(`${label} delivery failed: ${error instanceof Error ? error.message : String(error)}`);
1323
+ };
1254
1324
  try {
1255
- await this.onConfigureWarnings({
1256
- projectRoot,
1257
- sessionId,
1258
- client: sessionId ? this.configureWarningClients.get(sessionId) : undefined,
1259
- warnings
1260
- });
1261
- } finally {
1262
- if (sessionId) {
1263
- this.configureWarningClients.delete(sessionId);
1264
- }
1325
+ Promise.resolve(callback()).catch(failed);
1326
+ } catch (error) {
1327
+ failed(error);
1265
1328
  }
1266
1329
  }
1267
1330
  handleStatusChangedFrame(frame) {
@@ -1284,6 +1347,7 @@ var init_bridge = __esm(() => {
1284
1347
  this._shuttingDown = true;
1285
1348
  this.spawnedBinaryFingerprint = null;
1286
1349
  this.clearRestartResetTimer();
1350
+ this.clearRestartTimer();
1287
1351
  this.configureWarningClients.clear();
1288
1352
  this.rejectAllPending(new BridgeTransportUnknownOutcomeError(`${this.errorPrefix} Bridge shutting down`));
1289
1353
  if (this.process) {
@@ -1367,6 +1431,7 @@ var init_bridge = __esm(() => {
1367
1431
  this.spawnProcess(triggeringSessionId);
1368
1432
  }
1369
1433
  spawnProcess(triggeringSessionId) {
1434
+ this.clearRestartTimer();
1370
1435
  this._retiringDueToBinaryChange = false;
1371
1436
  if (triggeringSessionId) {
1372
1437
  this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
@@ -1417,6 +1482,11 @@ var init_bridge = __esm(() => {
1417
1482
  env: spawnEnv
1418
1483
  });
1419
1484
  const currentChild = child;
1485
+ child.stdin?.on("error", (cause) => {
1486
+ if (this.process !== currentChild)
1487
+ return;
1488
+ this.invalidateTransportProcess(new BridgeTransportUnknownOutcomeError(`${this.errorPrefix} Failed to write to stdin: ${cause.message}`, { cause }));
1489
+ });
1420
1490
  const stdoutDecoder = new StringDecoder("utf8");
1421
1491
  child.stdout?.on("data", (chunk) => {
1422
1492
  if (this.process !== currentChild)
@@ -1477,6 +1547,8 @@ var init_bridge = __esm(() => {
1477
1547
  this.lastChildActivityAt = 0;
1478
1548
  this.consecutiveRequestTimeouts = 0;
1479
1549
  this.stderrTail = [];
1550
+ this.processLoopReferenced = true;
1551
+ this.syncEventLoopHold();
1480
1552
  }
1481
1553
  pushStderrLine(line) {
1482
1554
  this.stderrTail.push(line);
@@ -1530,10 +1602,12 @@ var init_bridge = __esm(() => {
1530
1602
  ${tail}`;
1531
1603
  }
1532
1604
  onStdoutData(data) {
1533
- if (this.stdoutPendingLength + data.length > MAX_STDOUT_BUFFER) {
1605
+ const exceedsLimit = (fragment) => {
1606
+ if (this.stdoutPendingLength + Buffer.byteLength(fragment, "utf8") <= MAX_STDOUT_BUFFER)
1607
+ return false;
1534
1608
  this.handleCrash(new Error(`aft bridge stdout buffer exceeded ${MAX_STDOUT_BUFFER} bytes — killing bridge`));
1535
- return;
1536
- }
1609
+ return true;
1610
+ };
1537
1611
  this.stdoutScannedChars += data.length;
1538
1612
  const generation = this.processGeneration;
1539
1613
  let start = 0;
@@ -1541,6 +1615,8 @@ var init_bridge = __esm(() => {
1541
1615
  `);
1542
1616
  while (newlineIdx !== -1) {
1543
1617
  let line = data.slice(start, newlineIdx);
1618
+ if (exceedsLimit(line))
1619
+ return;
1544
1620
  if (this.stdoutPending.length > 0) {
1545
1621
  this.stdoutPending.push(line);
1546
1622
  line = this.stdoutPending.join("");
@@ -1559,8 +1635,10 @@ var init_bridge = __esm(() => {
1559
1635
  }
1560
1636
  if (start < data.length) {
1561
1637
  const rest = start === 0 ? data : data.slice(start);
1638
+ if (exceedsLimit(rest))
1639
+ return;
1562
1640
  this.stdoutPending.push(rest);
1563
- this.stdoutPendingLength += rest.length;
1641
+ this.stdoutPendingLength += Buffer.byteLength(rest, "utf8");
1564
1642
  }
1565
1643
  }
1566
1644
  flushStdoutBuffer() {
@@ -1603,15 +1681,16 @@ var init_bridge = __esm(() => {
1603
1681
  const taskId = bashTaskIdFrom(response);
1604
1682
  if (taskId)
1605
1683
  this.outstandingBackgroundTaskIds.delete(taskId);
1606
- this.onBashCompletion?.(response, this);
1684
+ this.syncEventLoopHold();
1685
+ this.dispatchHostCallback("bash completion", () => this.onBashCompletion?.(response, this));
1607
1686
  return;
1608
1687
  }
1609
1688
  if (response.type === "bash_long_running") {
1610
- this.onBashLongRunning?.(response, this);
1689
+ this.dispatchHostCallback("bash long-running", () => this.onBashLongRunning?.(response, this));
1611
1690
  return;
1612
1691
  }
1613
1692
  if (response.type === "bash_pattern_match") {
1614
- this.onBashPatternMatch?.(response, this);
1693
+ this.dispatchHostCallback("bash pattern-match", () => this.onBashPatternMatch?.(response, this));
1615
1694
  return;
1616
1695
  }
1617
1696
  if (response.type === "configure_warnings") {
@@ -1647,6 +1726,13 @@ var init_bridge = __esm(() => {
1647
1726
  this.scheduleRestartCountReset();
1648
1727
  this.accountForBashTaskResponse(entry.command, response);
1649
1728
  entry.resolve(response);
1729
+ } else if (id && typeof response.type !== "string") {
1730
+ const taskId = bashTaskIdFrom(response);
1731
+ if (taskId) {
1732
+ this.warnVia(`Dropped late reply for settled request id=${id} task_id=${taskId}`);
1733
+ } else {
1734
+ this.logVia(`Dropped late reply for settled request id=${id}`);
1735
+ }
1650
1736
  } else if (typeof response.type === "string") {
1651
1737
  this.logVia(`Ignoring unknown stdout push frame type: ${response.type}`);
1652
1738
  }
@@ -1655,11 +1741,38 @@ var init_bridge = __esm(() => {
1655
1741
  this.warnVia(`Failed to parse stdout line: ${quoted}`);
1656
1742
  }
1657
1743
  }
1744
+ holdForLateShellReply(id, entry, effectiveTimeoutMs, requestSessionId) {
1745
+ const graceMs = this.lateShellReplyGraceMs;
1746
+ if (!SHELL_TASK_COMMANDS.has(entry.command) || graceMs <= 0)
1747
+ return false;
1748
+ const timeoutMsg = `Request "${entry.command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms; waiting up to ${graceMs}ms for a late reply naming its task`;
1749
+ if (requestSessionId) {
1750
+ this.sessionWarnVia(requestSessionId, timeoutMsg);
1751
+ } else {
1752
+ this.warnVia(timeoutMsg);
1753
+ }
1754
+ const message = `${this.errorPrefix} Request "${entry.command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`;
1755
+ const rejectWith = entry.reject;
1756
+ const settle = (outcome) => {
1757
+ rejectWith(new BridgeTransportTimeoutError(entry.command, effectiveTimeoutMs, message, outcome));
1758
+ };
1759
+ entry.resolve = (response) => settle(shellOutcomeFromLateReply(response));
1760
+ clearTimeout(entry.timer);
1761
+ entry.timer = setTimeout(() => {
1762
+ if (this.pending.get(id) !== entry)
1763
+ return;
1764
+ this.pending.delete(id);
1765
+ entry.onSettled?.();
1766
+ this.warnVia(`Request "${entry.command}" (id=${id}) got no reply within ${graceMs}ms after its deadline`);
1767
+ settle({ kind: "unknown" });
1768
+ }, graceMs);
1769
+ return true;
1770
+ }
1658
1771
  accountForBashTaskResponse(command, response) {
1659
1772
  const taskId = bashTaskIdFrom(response);
1660
1773
  if (!taskId)
1661
1774
  return;
1662
- if (isTerminalBashStatus(response.status)) {
1775
+ if (isTerminalBashStatus(response.status, true)) {
1663
1776
  this.outstandingBackgroundTaskIds.delete(taskId);
1664
1777
  return;
1665
1778
  }
@@ -1694,6 +1807,7 @@ var init_bridge = __esm(() => {
1694
1807
  }
1695
1808
  }
1696
1809
  handleCrash(cause) {
1810
+ this.clearRestartTimer();
1697
1811
  const proc = this.process;
1698
1812
  this.process = null;
1699
1813
  this.spawnedBinaryFingerprint = null;
@@ -1716,7 +1830,8 @@ var init_bridge = __esm(() => {
1716
1830
  const delay = 100 * 2 ** this._restartCount;
1717
1831
  this._restartCount++;
1718
1832
  this.logVia(`Auto-restart #${this._restartCount} in ${delay}ms`);
1719
- setTimeout(() => {
1833
+ this.restartTimer = setTimeout(() => {
1834
+ this.restartTimer = null;
1720
1835
  if (!this._shuttingDown && !this.isAlive()) {
1721
1836
  try {
1722
1837
  this.spawnProcess();
@@ -1725,6 +1840,7 @@ var init_bridge = __esm(() => {
1725
1840
  }
1726
1841
  }
1727
1842
  }, delay);
1843
+ this.restartTimer.unref?.();
1728
1844
  this.scheduleRestartCountReset();
1729
1845
  } else {
1730
1846
  this.errorVia(`Max restarts (${this.maxRestarts}) reached, giving up. Logs: ${this.getLogFilePathVia()}${tail}`);
@@ -1732,6 +1848,7 @@ var init_bridge = __esm(() => {
1732
1848
  }
1733
1849
  }
1734
1850
  rejectAllPending(error) {
1851
+ this.configureWarningClients.clear();
1735
1852
  for (const [_id, entry] of this.pending) {
1736
1853
  clearTimeout(entry.timer);
1737
1854
  entry.onSettled?.();
@@ -1740,11 +1857,19 @@ var init_bridge = __esm(() => {
1740
1857
  this.pending.clear();
1741
1858
  }
1742
1859
  scheduleRestartCountReset() {
1860
+ if (this._restartCount === 0)
1861
+ return;
1743
1862
  this.clearRestartResetTimer();
1744
1863
  this.restartResetTimer = setTimeout(() => {
1745
1864
  this._restartCount = 0;
1746
1865
  this.restartResetTimer = null;
1747
1866
  }, BinaryBridge.RESTART_RESET_MS);
1867
+ this.restartResetTimer.unref?.();
1868
+ }
1869
+ clearRestartTimer() {
1870
+ if (this.restartTimer)
1871
+ clearTimeout(this.restartTimer);
1872
+ this.restartTimer = null;
1748
1873
  }
1749
1874
  clearRestartResetTimer() {
1750
1875
  if (this.restartResetTimer) {
@@ -2021,7 +2146,8 @@ async function downloadBinary(version) {
2021
2146
  const handleSigint = () => {
2022
2147
  cleanUpInterruptedDownload();
2023
2148
  process.off("SIGINT", handleSigint);
2024
- process.kill(process.pid, "SIGINT");
2149
+ if (process.listenerCount("SIGINT") === 0)
2150
+ process.kill(process.pid, "SIGINT");
2025
2151
  };
2026
2152
  const handleExit = () => cleanUpInterruptedDownload();
2027
2153
  process.once("SIGINT", handleSigint);
@@ -2396,7 +2522,7 @@ var init_durable_log = __esm(() => {
2396
2522
  init_storage_paths();
2397
2523
  DEFAULT_LOG_BYTES = 32 * 1024 * 1024;
2398
2524
  });
2399
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/envelope.js
2525
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/envelope.js
2400
2526
  var MAX_FRAME_BODY_LEN, FrameType, FRAME_TYPE_MAX, Priority, AdmissionClass;
2401
2527
  var init_envelope = __esm(() => {
2402
2528
  MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
@@ -2427,7 +2553,7 @@ var init_envelope = __esm(() => {
2427
2553
  })(AdmissionClass || (AdmissionClass = {}));
2428
2554
  });
2429
2555
 
2430
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/socket.js
2556
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/socket.js
2431
2557
  var WRITE_BORROWED, WRITE_TRACKED_BORROWED;
2432
2558
  var init_socket = __esm(() => {
2433
2559
  init_envelope();
@@ -2435,17 +2561,17 @@ var init_socket = __esm(() => {
2435
2561
  WRITE_TRACKED_BORROWED = Symbol("subc.socket.writeTrackedBorrowed");
2436
2562
  });
2437
2563
 
2438
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/auth.js
2564
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/auth.js
2439
2565
  var init_auth = __esm(() => {
2440
2566
  init_socket();
2441
2567
  });
2442
2568
 
2443
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/connection-file.js
2569
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/connection-file.js
2444
2570
  var init_connection_file = __esm(() => {
2445
2571
  init_envelope();
2446
2572
  });
2447
2573
 
2448
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/launch-nonce.js
2574
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/launch-nonce.js
2449
2575
  var PROCESS_CELL_KEY, U64_MAX, I32_MAX, RedactedLaunchNonce;
2450
2576
  var init_launch_nonce = __esm(() => {
2451
2577
  PROCESS_CELL_KEY = Symbol.for("@cortexkit/subc-client/launch-nonce/v1");
@@ -2471,16 +2597,16 @@ var init_launch_nonce = __esm(() => {
2471
2597
  };
2472
2598
  });
2473
2599
 
2474
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/route-handle.js
2600
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/route-handle.js
2475
2601
  var connectionToken, reverseRequests;
2476
2602
  var init_route_handle = __esm(() => {
2477
2603
  connectionToken = new WeakMap;
2478
2604
  reverseRequests = new WeakMap;
2479
2605
  });
2480
2606
 
2481
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/client.js
2607
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/client.js
2482
2608
  import { debuglog } from "node:util";
2483
- var debug, EMPTY_BODY, errorFrameFlags, ROUTE_OPEN_ADMISSION_PRESSURE_REASONS;
2609
+ var debug, EMPTY_BODY, errorFrameFlags, SCOPE_ROUTE_CLOSE_REASONS, ROUTE_OPEN_ADMISSION_PRESSURE_REASONS;
2484
2610
  var init_client = __esm(() => {
2485
2611
  init_auth();
2486
2612
  init_connection_file();
@@ -2492,10 +2618,16 @@ var init_client = __esm(() => {
2492
2618
  debug = debuglog("subc-client");
2493
2619
  EMPTY_BODY = new Uint8Array(0);
2494
2620
  errorFrameFlags = new WeakMap;
2621
+ SCOPE_ROUTE_CLOSE_REASONS = new Set([
2622
+ "scope_ended",
2623
+ "scope_carrier_removed",
2624
+ "scope_delegation_changed",
2625
+ "scope_parent_ended"
2626
+ ]);
2495
2627
  ROUTE_OPEN_ADMISSION_PRESSURE_REASONS = new Set(["open_admission_full", "target_binds_full"]);
2496
2628
  });
2497
2629
 
2498
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/provider.js
2630
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/provider.js
2499
2631
  var init_provider = __esm(() => {
2500
2632
  init_auth();
2501
2633
  init_client();
@@ -2506,7 +2638,7 @@ var init_provider = __esm(() => {
2506
2638
  init_socket();
2507
2639
  });
2508
2640
 
2509
- // ../../node_modules/.bun/@cortexkit+subc-client@0.20.0/node_modules/@cortexkit/subc-client/dist/index.js
2641
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/index.js
2510
2642
  var init_dist = __esm(() => {
2511
2643
  init_client();
2512
2644
  init_route_handle();
@@ -2941,6 +3073,7 @@ var CALL_DEADLINE_EXPIRED, LOCALLY_SATISFIED_COMMANDS, dispatchProbes;
2941
3073
  var init_subc_transport = __esm(() => {
2942
3074
  init_dist();
2943
3075
  init_active_logger();
3076
+ init_bash_format();
2944
3077
  init_error_contract();
2945
3078
  init_lifecycle_registry();
2946
3079
  init_project_identity();
@@ -3081,10 +3214,92 @@ function translateInspectLspPaths(map, prefix, out) {
3081
3214
  recordRetired(out, prefix, `inspect.${leaf}`);
3082
3215
  }
3083
3216
  }
3217
+ function translateExperimentalPaths(map, prefix, out) {
3218
+ for (const [oldKey, leaf] of [
3219
+ ["experimental_lsp_ty", "lsp_ty"],
3220
+ ["experimental_bash_rewrite", "rewrite"],
3221
+ ["experimental_bash_compress", "compress"],
3222
+ ["experimental_bash_background", "background"]
3223
+ ]) {
3224
+ if (!Object.hasOwn(map, oldKey))
3225
+ continue;
3226
+ recordRetired(out, prefix, oldKey);
3227
+ const value = map[oldKey];
3228
+ delete map[oldKey];
3229
+ if (!isRecord(map.experimental))
3230
+ map.experimental = {};
3231
+ const experimental = map.experimental;
3232
+ let destination = experimental;
3233
+ if (leaf !== "lsp_ty") {
3234
+ if (!isRecord(experimental.bash))
3235
+ experimental.bash = {};
3236
+ destination = experimental.bash;
3237
+ }
3238
+ if (Object.hasOwn(destination, leaf)) {
3239
+ superseded(out, oldKey, `${oldKey} is ignored because experimental.${leaf === "lsp_ty" ? leaf : `bash.${leaf}`} is already set`);
3240
+ } else {
3241
+ destination[leaf] = value;
3242
+ }
3243
+ }
3244
+ if (!isRecord(map.experimental) || !Object.hasOwn(map.experimental, "bash"))
3245
+ return;
3246
+ const experimental = map.experimental;
3247
+ const legacy = experimental.bash;
3248
+ if (isRecord(legacy)) {
3249
+ if (!["rewrite", "compress", "background"].some((leaf) => Object.hasOwn(legacy, leaf)))
3250
+ return;
3251
+ for (const leaf of Object.keys(legacy))
3252
+ recordRetired(out, prefix, `experimental.bash.${leaf}`);
3253
+ if (Object.hasOwn(map, "bash")) {
3254
+ superseded(out, "experimental.bash", 'experimental.bash is ignored because top-level "bash" is already set');
3255
+ } else {
3256
+ const bash = {
3257
+ rewrite: legacy.rewrite === true,
3258
+ compress: legacy.compress === true,
3259
+ background: legacy.background === true
3260
+ };
3261
+ for (const leaf of ["long_running_reminder_enabled", "long_running_reminder_interval_ms"]) {
3262
+ if (Object.hasOwn(legacy, leaf))
3263
+ bash[leaf] = legacy[leaf];
3264
+ }
3265
+ map.bash = bash;
3266
+ }
3267
+ } else {
3268
+ recordRetired(out, prefix, "experimental.bash");
3269
+ }
3270
+ delete experimental.bash;
3271
+ if (Object.keys(experimental).length === 0)
3272
+ delete map.experimental;
3273
+ }
3084
3274
  function translateBlock(map, userBase, blockLabel, out) {
3085
3275
  const prefix = blockLabel === "base" ? "" : `${blockLabel}.`;
3086
3276
  translateGithubAliases(map, prefix, out);
3087
3277
  translateInspectLspPaths(map, prefix, out);
3278
+ translateExperimentalPaths(map, prefix, out);
3279
+ if (isRecord(map.sandbox) && Object.hasOwn(map.sandbox, "enabled")) {
3280
+ const sandbox = map.sandbox;
3281
+ const enabled = sandbox.enabled;
3282
+ delete sandbox.enabled;
3283
+ recordRetired(out, prefix, "sandbox.enabled");
3284
+ if (typeof enabled === "boolean") {
3285
+ if (sandbox.profile === undefined)
3286
+ sandbox.profile = {};
3287
+ if (isRecord(sandbox.profile)) {
3288
+ const modes = { worker: enabled ? "strict" : "relaxed", head: enabled ? "strict" : "off" };
3289
+ for (const role of ["worker", "head"]) {
3290
+ if (sandbox.profile[role] !== undefined && sandbox.profile[role] !== modes[role]) {
3291
+ superseded(out, `${prefix}sandbox.enabled`, `sandbox.profile.${role} takes precedence over sandbox.enabled`);
3292
+ }
3293
+ sandbox.profile[role] ??= modes[role];
3294
+ }
3295
+ }
3296
+ } else
3297
+ out.warnings.push({
3298
+ code: "invalid_legacy_config",
3299
+ key: `${prefix}sandbox.enabled`,
3300
+ message: "Ignoring non-boolean sandbox.enabled; use sandbox.profile"
3301
+ });
3302
+ }
3088
3303
  let explicitList;
3089
3304
  const rawList = map.disabled_tools;
3090
3305
  if (Array.isArray(rawList) && rawList.every((entry) => typeof entry === "string")) {
@@ -3097,6 +3312,8 @@ function translateBlock(map, userBase, blockLabel, out) {
3097
3312
  });
3098
3313
  }
3099
3314
  for (const [path] of RETIRED_PATHS) {
3315
+ if (path === "experimental.bash")
3316
+ continue;
3100
3317
  if (hasPath(map, path))
3101
3318
  recordRetired(out, prefix, path);
3102
3319
  }
@@ -3312,6 +3529,7 @@ var init_feature_config = __esm(() => {
3312
3529
  aft_bash: "bash"
3313
3530
  };
3314
3531
  RETIRED_PATHS = [
3532
+ ["sandbox.enabled", "sandbox.profile"],
3315
3533
  ["tool_surface", "disabled_tools"],
3316
3534
  ["hoist_builtin_tools", "disabled_tools"],
3317
3535
  ["enabled", "disabled_tools"],
@@ -3320,7 +3538,12 @@ var init_feature_config = __esm(() => {
3320
3538
  ["semantic_search", "indexes.semantic"],
3321
3539
  ["experimental_semantic_search", "indexes.semantic"],
3322
3540
  ["callgraph_store", "indexes.callgraph"],
3323
- ["github.enabled", "github.read,github.write,github.shim"]
3541
+ ["github.enabled", "github.read,github.write,github.shim"],
3542
+ ["experimental_lsp_ty", "experimental.lsp_ty"],
3543
+ ["experimental_bash_rewrite", "bash.rewrite"],
3544
+ ["experimental_bash_compress", "bash.compress"],
3545
+ ["experimental_bash_background", "bash.background"],
3546
+ ["experimental.bash", "bash"]
3324
3547
  ];
3325
3548
  INDEX_INPUTS = [
3326
3549
  ["trigram", "search_index", "experimental_search_index"],
@@ -3334,6 +3557,7 @@ var DEFAULT_IDLE_TIMEOUT_MS, CLEANUP_INTERVAL_MS;
3334
3557
  var init_pool = __esm(() => {
3335
3558
  init_active_logger();
3336
3559
  init_bridge();
3560
+ init_lifecycle_registry();
3337
3561
  init_project_identity();
3338
3562
  DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
3339
3563
  CLEANUP_INTERVAL_MS = 60 * 1000;
@@ -3342,6 +3566,7 @@ var init_pool = __esm(() => {
3342
3566
  // ../aft-bridge/dist/revivable-transport.js
3343
3567
  var init_revivable_transport = __esm(() => {
3344
3568
  init_active_logger();
3569
+ init_lifecycle_registry();
3345
3570
  init_project_identity();
3346
3571
  });
3347
3572
 
@@ -3364,6 +3589,73 @@ var init_location_lifecycle = __esm(() => {
3364
3589
  RELEASE_LOCATION = Symbol.for("@cortexkit/aft-bridge/location-release/v1");
3365
3590
  });
3366
3591
 
3592
+ // ../aft-bridge/dist/lsp-github-probe.js
3593
+ var init_lsp_github_probe = __esm(() => {
3594
+ init_active_logger();
3595
+ });
3596
+
3597
+ // ../aft-bridge/dist/lsp-github-table.js
3598
+ var init_lsp_github_table = () => {};
3599
+
3600
+ // ../aft-bridge/dist/tar-executable.js
3601
+ import { existsSync as existsSync3 } from "node:fs";
3602
+ import { join as join8 } from "node:path";
3603
+ function windowsTarExecutable(options = {}) {
3604
+ const platform = options.platform ?? process.platform;
3605
+ if (platform !== "win32")
3606
+ return "tar";
3607
+ const env = options.env ?? process.env;
3608
+ const systemTar = join8(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
3609
+ return (options.exists ?? existsSync3)(systemTar) ? systemTar : "tar";
3610
+ }
3611
+ function extractionCommand(args, privateStorage) {
3612
+ const executable = windowsTarExecutable();
3613
+ if (privateStorage && process.platform !== "win32") {
3614
+ return {
3615
+ executable,
3616
+ file: "/bin/sh",
3617
+ args: [
3618
+ "-c",
3619
+ 'umask 077; exec "$@"',
3620
+ "aft-extract",
3621
+ executable,
3622
+ "--no-same-permissions",
3623
+ ...args.map((arg, index) => index === 0 && !arg.startsWith("-") ? `-${arg}` : arg)
3624
+ ]
3625
+ };
3626
+ }
3627
+ return { executable, file: executable, args };
3628
+ }
3629
+ function extractionError(executable, cause) {
3630
+ const detail = cause instanceof Error ? cause.message : String(cause);
3631
+ return new Error(`tar extraction failed using ${executable}: ${detail}`, { cause });
3632
+ }
3633
+ function execTarExtraction(args, timeout, privateStorage = false) {
3634
+ const command = extractionCommand(args, privateStorage);
3635
+ return new Promise((resolve, reject) => {
3636
+ execFile(command.file, command.args, { timeout }, (error) => {
3637
+ if (error)
3638
+ reject(extractionError(command.executable, error));
3639
+ else
3640
+ resolve();
3641
+ });
3642
+ });
3643
+ }
3644
+ var init_tar_executable = __esm(() => {
3645
+ init_child_process();
3646
+ });
3647
+
3648
+ // ../aft-bridge/dist/lsp-github-install.js
3649
+ var init_lsp_github_install = __esm(() => {
3650
+ init_binary_identity();
3651
+ init_cache_paths();
3652
+ init_child_process();
3653
+ init_lsp_github_probe();
3654
+ init_lsp_github_table();
3655
+ init_path_display();
3656
+ init_tar_executable();
3657
+ });
3658
+
3367
3659
  // ../aft-bridge/dist/message-detach.js
3368
3660
  var BASH_WAIT_DETACH_MAGIC_KEYWORD = "&detach", STANDALONE_DETACH_KEYWORD_SOURCE, STANDALONE_DETACH_KEYWORD_PATTERN, STANDALONE_DETACH_KEYWORDS_PATTERN;
3369
3661
  var init_message_detach = __esm(() => {
@@ -3374,7 +3666,7 @@ var init_message_detach = __esm(() => {
3374
3666
 
3375
3667
  // ../aft-bridge/dist/paths.js
3376
3668
  import { homedir as homedir7 } from "node:os";
3377
- import { dirname as dirname2, isAbsolute as isAbsolute4, join as join8, resolve as resolve5 } from "node:path";
3669
+ import { dirname as dirname2, isAbsolute as isAbsolute4, join as join9, resolve as resolve5 } from "node:path";
3378
3670
  function homeDir3() {
3379
3671
  if (process.platform === "win32")
3380
3672
  return process.env.USERPROFILE || process.env.HOME || homedir7();
@@ -3384,20 +3676,20 @@ function configHome() {
3384
3676
  const xdg = process.env.XDG_CONFIG_HOME;
3385
3677
  if (xdg && isAbsolute4(xdg))
3386
3678
  return xdg;
3387
- return join8(homeDir3(), ".config");
3679
+ return join9(homeDir3(), ".config");
3388
3680
  }
3389
3681
  function resolveCortexKitUserConfigPath() {
3390
- return join8(configHome(), "cortexkit", "aft.jsonc");
3682
+ return join9(configHome(), "cortexkit", "aft.jsonc");
3391
3683
  }
3392
3684
  function resolveCortexKitProjectConfigPath(projectDirectory) {
3393
- return join8(projectDirectory, ".cortexkit", "aft.jsonc");
3685
+ return join9(projectDirectory, ".cortexkit", "aft.jsonc");
3394
3686
  }
3395
3687
  var init_paths = __esm(() => {
3396
3688
  init_private_storage();
3397
3689
  });
3398
3690
 
3399
3691
  // ../aft-bridge/dist/resolver.js
3400
- import { closeSync as closeSync4, existsSync as existsSync3, promises as fsPromises, openSync as openSync4, readFileSync as readFileSync4, readSync as readSync3 } from "node:fs";
3692
+ import { closeSync as closeSync4, existsSync as existsSync4, promises as fsPromises, openSync as openSync4, readFileSync as readFileSync4, readSync as readSync3 } from "node:fs";
3401
3693
  function isNativeExecutable(binaryPath) {
3402
3694
  let fd = null;
3403
3695
  try {
@@ -3454,10 +3746,10 @@ var init_migration = __esm(() => {
3454
3746
  // ../aft-bridge/dist/migration-notices.js
3455
3747
  import { readFileSync as readFileSync5, renameSync as renameSync3, rmdirSync, statSync as statSync3, writeFileSync as writeFileSync2 } from "node:fs";
3456
3748
  import { homedir as homedir8 } from "node:os";
3457
- import { dirname as dirname3, join as join9, resolve as resolve6 } from "node:path";
3749
+ import { dirname as dirname3, join as join10, resolve as resolve6 } from "node:path";
3458
3750
  function migrationNoticeStorePath(env = process.env) {
3459
- const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join9(homedir8(), ".local", "state");
3460
- return join9(stateHome, "cortexkit", "aft", "migration-notices.json");
3751
+ const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join10(homedir8(), ".local", "state");
3752
+ return join10(stateHome, "cortexkit", "aft", "migration-notices.json");
3461
3753
  }
3462
3754
  function readRecords(storePath) {
3463
3755
  try {
@@ -3518,7 +3810,7 @@ var init_migration_notices = __esm(() => {
3518
3810
  // ../aft-bridge/dist/npm-resolver.js
3519
3811
  import { readdirSync as readdirSync2, statSync as statSync4 } from "node:fs";
3520
3812
  import { homedir as homedir9 } from "node:os";
3521
- import { dirname as dirname4, isAbsolute as isAbsolute5, join as join10 } from "node:path";
3813
+ import { dirname as dirname4, isAbsolute as isAbsolute5, join as join11 } from "node:path";
3522
3814
  function defaultDeps() {
3523
3815
  return {
3524
3816
  platform: process.platform,
@@ -3547,14 +3839,14 @@ function npmFromPath(deps) {
3547
3839
  const dir = entry.trim().replace(/^"|"$/g, "");
3548
3840
  if (!dir || !isAbsolute5(dir))
3549
3841
  continue;
3550
- if (isFile(join10(dir, name)))
3842
+ if (isFile(join11(dir, name)))
3551
3843
  return dir;
3552
3844
  }
3553
3845
  return null;
3554
3846
  }
3555
3847
  function npmAdjacentToNode(deps) {
3556
3848
  const dir = dirname4(deps.execPath);
3557
- return isFile(join10(dir, npmBinaryName(deps.platform))) ? dir : null;
3849
+ return isFile(join11(dir, npmBinaryName(deps.platform))) ? dir : null;
3558
3850
  }
3559
3851
  function highestVersionedNodeBin(installsDir, name) {
3560
3852
  let entries;
@@ -3563,8 +3855,8 @@ function highestVersionedNodeBin(installsDir, name) {
3563
3855
  } catch {
3564
3856
  return null;
3565
3857
  }
3566
- const candidates = entries.filter((v) => isFile(join10(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
3567
- return candidates.length > 0 ? join10(installsDir, candidates[0], "bin") : null;
3858
+ const candidates = entries.filter((v) => isFile(join11(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
3859
+ return candidates.length > 0 ? join11(installsDir, candidates[0], "bin") : null;
3568
3860
  }
3569
3861
  function compareVersionsDesc(a, b) {
3570
3862
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -3589,22 +3881,22 @@ function wellKnownNpmDirs(deps) {
3589
3881
  const programFiles = env.ProgramFiles || "C:\\Program Files";
3590
3882
  const appData = env.APPDATA;
3591
3883
  const localAppData = env.LOCALAPPDATA;
3592
- push(join10(programFiles, "nodejs"));
3884
+ push(join11(programFiles, "nodejs"));
3593
3885
  if (appData)
3594
- push(join10(appData, "npm"));
3886
+ push(join11(appData, "npm"));
3595
3887
  if (localAppData)
3596
- push(join10(localAppData, "Volta", "bin"));
3888
+ push(join11(localAppData, "Volta", "bin"));
3597
3889
  if (env.NVM_SYMLINK)
3598
3890
  push(env.NVM_SYMLINK);
3599
3891
  } else {
3600
3892
  if (env.NVM_BIN)
3601
3893
  push(env.NVM_BIN);
3602
- push(highestVersionedNodeBin(join10(home, ".nvm", "versions", "node"), name));
3603
- push(highestVersionedNodeBin(join10(home, ".local", "share", "mise", "installs", "node"), name));
3604
- push(highestVersionedNodeBin(join10(home, ".asdf", "installs", "nodejs"), name));
3605
- push(join10(home, ".volta", "bin"));
3606
- push(join10(home, ".asdf", "shims"));
3607
- const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join10(home, ".local", "bin")]);
3894
+ push(highestVersionedNodeBin(join11(home, ".nvm", "versions", "node"), name));
3895
+ push(highestVersionedNodeBin(join11(home, ".local", "share", "mise", "installs", "node"), name));
3896
+ push(highestVersionedNodeBin(join11(home, ".asdf", "installs", "nodejs"), name));
3897
+ push(join11(home, ".volta", "bin"));
3898
+ push(join11(home, ".asdf", "shims"));
3899
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join11(home, ".local", "bin")]);
3608
3900
  for (const dir of systemDirs)
3609
3901
  push(dir);
3610
3902
  }
@@ -3614,12 +3906,12 @@ function resolveNpm(deps = defaultDeps()) {
3614
3906
  const name = npmBinaryName(deps.platform);
3615
3907
  const onPath = npmFromPath(deps);
3616
3908
  if (onPath)
3617
- return { command: join10(onPath, name), binDir: onPath };
3909
+ return { command: join11(onPath, name), binDir: onPath };
3618
3910
  const adjacent = npmAdjacentToNode(deps);
3619
3911
  if (adjacent)
3620
- return { command: join10(adjacent, name), binDir: adjacent };
3912
+ return { command: join11(adjacent, name), binDir: adjacent };
3621
3913
  for (const dir of wellKnownNpmDirs(deps)) {
3622
- const candidate = join10(dir, name);
3914
+ const candidate = join11(dir, name);
3623
3915
  if (isFile(candidate))
3624
3916
  return { command: candidate, binDir: dir };
3625
3917
  }
@@ -3780,7 +4072,7 @@ function terminateNpmProcessTree(child, invocation, env = process.env, gracePeri
3780
4072
  };
3781
4073
  child.once("exit", onChildExit);
3782
4074
  const systemRoot = env.SystemRoot ?? env.SYSTEMROOT;
3783
- const taskkill = systemRoot ? join10(systemRoot, "System32", "taskkill.exe") : "taskkill.exe";
4075
+ const taskkill = systemRoot ? join11(systemRoot, "System32", "taskkill.exe") : "taskkill.exe";
3784
4076
  try {
3785
4077
  killer = spawn(taskkill, ["/pid", String(child.pid), "/t", "/f"], {
3786
4078
  stdio: "ignore",
@@ -3816,7 +4108,7 @@ var init_npm_resolver = __esm(() => {
3816
4108
  });
3817
4109
 
3818
4110
  // ../aft-bridge/dist/onnx-probe.js
3819
- import { closeSync as closeSync5, existsSync as existsSync4, openSync as openSync5, readSync as readSync4, realpathSync as realpathSync2 } from "node:fs";
4111
+ import { closeSync as closeSync5, existsSync as existsSync5, openSync as openSync5, readSync as readSync4, realpathSync as realpathSync2 } from "node:fs";
3820
4112
  function readAt(fd, offset, length) {
3821
4113
  const buffer = Buffer.alloc(length);
3822
4114
  const read = readSync4(fd, buffer, 0, length, offset);
@@ -3919,7 +4211,7 @@ function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
3919
4211
  for (const dependency of dylibs) {
3920
4212
  if (isUncheckableDependency(dependency))
3921
4213
  continue;
3922
- if (!existsSync4(dependency)) {
4214
+ if (!existsSync5(dependency)) {
3923
4215
  return { loadable: false, reason: `missing dependency ${dependency}` };
3924
4216
  }
3925
4217
  }
@@ -3936,41 +4228,6 @@ var init_onnx_probe = __esm(() => {
3936
4228
  UNCHECKED = { loadable: true, checked: false };
3937
4229
  });
3938
4230
 
3939
- // ../aft-bridge/dist/tar-executable.js
3940
- import { existsSync as existsSync5 } from "node:fs";
3941
- import { join as join11 } from "node:path";
3942
- function windowsTarExecutable(options = {}) {
3943
- const platform = options.platform ?? process.platform;
3944
- if (platform !== "win32")
3945
- return "tar";
3946
- const env = options.env ?? process.env;
3947
- const systemTar = join11(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
3948
- return (options.exists ?? existsSync5)(systemTar) ? systemTar : "tar";
3949
- }
3950
- function execTarExtractionSync(args, timeout, privateStorage = false) {
3951
- const executable = windowsTarExecutable();
3952
- try {
3953
- if (privateStorage && process.platform !== "win32") {
3954
- execFileSync("/bin/sh", [
3955
- "-c",
3956
- 'umask 077; exec "$@"',
3957
- "aft-extract",
3958
- executable,
3959
- "--no-same-permissions",
3960
- ...args.map((arg, index) => index === 0 && !arg.startsWith("-") ? `-${arg}` : arg)
3961
- ], { stdio: "pipe", timeout });
3962
- } else {
3963
- execFileSync(executable, args, { stdio: "pipe", timeout });
3964
- }
3965
- } catch (cause) {
3966
- const detail = cause instanceof Error ? cause.message : String(cause);
3967
- throw new Error(`tar extraction failed using ${executable}: ${detail}`, { cause });
3968
- }
3969
- }
3970
- var init_tar_executable = __esm(() => {
3971
- init_child_process();
3972
- });
3973
-
3974
4231
  // ../aft-bridge/dist/onnx-runtime.js
3975
4232
  import { randomBytes } from "node:crypto";
3976
4233
  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";
@@ -4428,7 +4685,7 @@ async function downloadOnnxRuntime(info, targetDir) {
4428
4685
  const archiveSha256 = await sha256File(archivePath);
4429
4686
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
4430
4687
  if (info.archiveType === "tgz") {
4431
- execTarExtractionSync(["xzf", archivePath, "-C", extractionRoot], 120000, true);
4688
+ await execTarExtraction(["xzf", archivePath, "-C", extractionRoot], 120000, true);
4432
4689
  } else {
4433
4690
  await extractZipArchive(archivePath, extractionRoot);
4434
4691
  }
@@ -4561,12 +4818,16 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
4561
4818
  }
4562
4819
  async function extractZipArchive(archivePath, destinationDir) {
4563
4820
  if (process.platform === "win32") {
4564
- execTarExtractionSync(["-xf", archivePath, "-C", destinationDir], 120000);
4821
+ await execTarExtraction(["-xf", archivePath, "-C", destinationDir], 120000);
4565
4822
  return;
4566
4823
  }
4567
- execFileSync("unzip", ["-q", archivePath, "-d", destinationDir], {
4568
- stdio: "pipe",
4569
- timeout: 120000
4824
+ await new Promise((resolve, reject) => {
4825
+ execFile("unzip", ["-q", archivePath, "-d", destinationDir], { timeout: 120000 }, (error) => {
4826
+ if (error)
4827
+ reject(error);
4828
+ else
4829
+ resolve();
4830
+ });
4570
4831
  });
4571
4832
  }
4572
4833
  function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
@@ -4841,6 +5102,7 @@ var init_semantic_status = __esm(() => {
4841
5102
  // ../aft-bridge/dist/index.js
4842
5103
  var init_dist2 = __esm(() => {
4843
5104
  init_active_logger();
5105
+ init_bash_format();
4844
5106
  init_bash_hints();
4845
5107
  init_bash_host_fallback();
4846
5108
  init_binary_identity();
@@ -4856,7 +5118,11 @@ var init_dist2 = __esm(() => {
4856
5118
  init_downloader();
4857
5119
  init_durable_log();
4858
5120
  init_error_contract();
5121
+ init_lifecycle_registry();
4859
5122
  init_location_lifecycle();
5123
+ init_lsp_github_install();
5124
+ init_lsp_github_probe();
5125
+ init_lsp_github_table();
4860
5126
  init_message_detach();
4861
5127
  init_migration();
4862
5128
  init_migration_notices();
@@ -13537,7 +13803,7 @@ function getSelfVersion() {
13537
13803
  var init_self_version = () => {};
13538
13804
 
13539
13805
  // ../../.github/opencode-version.txt
13540
- var opencode_version_default = `1.18.30
13806
+ var opencode_version_default = `1.19.3
13541
13807
  `;
13542
13808
  var init_opencode_version = () => {};
13543
13809
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/aft",
3
- "version": "0.59.0",
3
+ "version": "0.61.0",
4
4
  "type": "module",
5
5
  "description": "Unified CLI for Agent File Tools (AFT) — setup, one-shot index snapshots, doctor, and diagnostics across supported agent harnesses (OpenCode, Pi)",
6
6
  "license": "MIT",
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@clack/core": "^1.4.2",
27
27
  "@clack/prompts": "^1.6.0",
28
- "@cortexkit/aft-bridge": "0.59.0",
28
+ "@cortexkit/aft-bridge": "0.61.0",
29
29
  "comment-json": "^4.6.2"
30
30
  },
31
31
  "devDependencies": {