@cortexkit/aft-pi 0.64.0 → 0.65.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
@@ -8082,7 +8082,14 @@ var TERMINAL_BASH_STATUSES = new Set(TERMINAL_BG_TASK_STATUSES);
8082
8082
  function isTerminalBashStatus(status, compatibilityAliases = false) {
8083
8083
  return typeof status === "string" && (TERMINAL_BASH_STATUSES.has(status) || compatibilityAliases && (status === "cancelled" || status === "timeout"));
8084
8084
  }
8085
+
8085
8086
  // ../aft-bridge/dist/bash-format.js
8087
+ function formatUnknownPtyExit(taskId, data) {
8088
+ if (data.status !== "fate_unknown" || data.status_reason !== "AFT could not read how it ended") {
8089
+ return;
8090
+ }
8091
+ return `Task ${taskId}: exit status unknown (AFT could not read how it ended)`;
8092
+ }
8086
8093
  function isTerminalStatus(status) {
8087
8094
  return isTerminalBashStatus(status);
8088
8095
  }
@@ -8114,6 +8121,79 @@ function relativePathEscapesRoot(rel, platform = process.platform) {
8114
8121
  return rel === ".." || rel.startsWith("../") || platform === "win32" && rel.startsWith("..\\") || (platform === "win32" ? win32.isAbsolute(rel) : posix.isAbsolute(rel));
8115
8122
  }
8116
8123
 
8124
+ // ../aft-bridge/dist/wait-clock.js
8125
+ var SUSPEND_SKEW_MS = 1000;
8126
+ var RESUME_ALLOWANCE_MS = 1e4;
8127
+ var DEADLINE_POLL_MS = 250;
8128
+
8129
+ class WaitClock {
8130
+ wallNow;
8131
+ awakeNow;
8132
+ wall;
8133
+ awake;
8134
+ skew = 0;
8135
+ elapsed;
8136
+ suspendCount = 0;
8137
+ lastSuspendEnd = Number.NEGATIVE_INFINITY;
8138
+ constructor(wallNow = Date.now, awakeNow = () => performance.now()) {
8139
+ this.wallNow = wallNow;
8140
+ this.awakeNow = awakeNow;
8141
+ this.wall = wallNow();
8142
+ this.awake = awakeNow();
8143
+ this.elapsed = this.awake;
8144
+ }
8145
+ now() {
8146
+ const wall = this.wallNow();
8147
+ const awake = this.awakeNow();
8148
+ const active = Math.max(0, awake - this.awake);
8149
+ this.skew = Math.max(0, this.skew + wall - this.wall - active);
8150
+ this.elapsed += active;
8151
+ if (this.skew >= SUSPEND_SKEW_MS) {
8152
+ this.elapsed += this.skew;
8153
+ this.lastSuspendEnd = this.elapsed;
8154
+ this.skew = 0;
8155
+ this.suspendCount++;
8156
+ }
8157
+ this.wall = wall;
8158
+ this.awake = awake;
8159
+ return this.elapsed;
8160
+ }
8161
+ }
8162
+
8163
+ class RequestDeadline {
8164
+ clock;
8165
+ allowResume;
8166
+ deadline;
8167
+ suspendCount;
8168
+ resumed = false;
8169
+ constructor(clock, timeoutMs, allowResume = true) {
8170
+ this.clock = clock;
8171
+ this.allowResume = allowResume;
8172
+ this.deadline = clock.now() + timeoutMs;
8173
+ this.suspendCount = clock.suspendCount;
8174
+ }
8175
+ remaining() {
8176
+ const now = this.clock.now();
8177
+ if (now >= this.deadline && this.allowResume && !this.resumed && this.clock.suspendCount > this.suspendCount && this.clock.lastSuspendEnd >= this.deadline) {
8178
+ this.resumed = true;
8179
+ this.deadline = now + RESUME_ALLOWANCE_MS;
8180
+ }
8181
+ return Math.max(0, this.deadline - now);
8182
+ }
8183
+ }
8184
+ function deadlineTimer(scheduler, remaining, expired) {
8185
+ let timer;
8186
+ const check = () => {
8187
+ const left = remaining();
8188
+ if (left <= 0)
8189
+ expired();
8190
+ else
8191
+ timer = scheduler.setTimeout(check, Math.min(left, DEADLINE_POLL_MS));
8192
+ };
8193
+ check();
8194
+ return () => scheduler.clearTimeout(timer);
8195
+ }
8196
+
8117
8197
  // ../aft-bridge/dist/bash-hints.js
8118
8198
  var DEFAULT_PRIMARY_WATCH_TIMEOUT_MS = 30000;
8119
8199
  var MAX_WATCH_TIMEOUT_MS = 1800000;
@@ -8141,7 +8221,8 @@ function watchPollDelayMs(elapsedMs) {
8141
8221
  return 1000;
8142
8222
  }
8143
8223
  var watchClock = {
8144
- now: () => performance.now(),
8224
+ source: new WaitClock,
8225
+ now: () => watchClock.source.now(),
8145
8226
  sleep: abortableSleep
8146
8227
  };
8147
8228
  function abortableSleep(ms, signal) {
@@ -8287,6 +8368,7 @@ var GREP_SEARCH_AFT_SEARCH_HINT = "DO NOT search code by running grep/rg in bash
8287
8368
  var GREP_SEARCH_GREP_HINT = "DO NOT search code by running grep/rg in bash — it is unindexed, unranked, and serial. Use the `grep` tool instead (indexed and ranked).";
8288
8369
  var GREP_SEARCH_HINT_PREFIX = "DO NOT search code by running grep/rg in bash —";
8289
8370
  var GREP_SEARCH_FRESHNESS_WINDOW_MS = 60000;
8371
+ var MTIME_CLOCK_SLACK_MS = 1;
8290
8372
  function maybeAppendConflictsHint(output) {
8291
8373
  if (!output.includes("Automatic merge failed; fix conflicts"))
8292
8374
  return output;
@@ -8294,15 +8376,15 @@ function maybeAppendConflictsHint(output) {
8294
8376
  return output;
8295
8377
  return output + CONFLICT_HINT;
8296
8378
  }
8297
- function commandInvokesCodeSearch(command) {
8298
- const statements = splitTopLevelStatements(command);
8379
+ function commandInvokesCodeSearch(command, platform = process.platform) {
8380
+ const statements = splitTopLevelStatements(command, platform);
8299
8381
  if (statements === null)
8300
8382
  return false;
8301
8383
  for (const statement of statements) {
8302
- const firstStage = firstPipelineStage(statement);
8384
+ const firstStage = firstPipelineStage(statement, platform);
8303
8385
  if (firstStage === null)
8304
8386
  continue;
8305
- const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
8387
+ const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0), platform);
8306
8388
  if (firstToken === null)
8307
8389
  continue;
8308
8390
  if (firstToken.token === "grep" || firstToken.token === "rg")
@@ -8310,42 +8392,43 @@ function commandInvokesCodeSearch(command) {
8310
8392
  }
8311
8393
  return false;
8312
8394
  }
8313
- function maybeAppendGrepSearchHint(output, command, aftSearchRegistered, projectRoot) {
8395
+ function maybeAppendGrepSearchHint(output, command, aftSearchRegistered, projectRoot, platform = process.platform, workdir) {
8314
8396
  if (output === "")
8315
8397
  return output;
8316
- if (!commandInvokesCodeSearch(command))
8398
+ if (!commandInvokesCodeSearch(command, platform))
8317
8399
  return output;
8318
8400
  if (output.includes(GREP_SEARCH_HINT_PREFIX))
8319
8401
  return output;
8320
- if (shouldSuppressGrepSearchHint(command, projectRoot))
8402
+ if (shouldSuppressGrepSearchHint(command, projectRoot, platform, workdir))
8321
8403
  return output;
8322
8404
  const hint = aftSearchRegistered ? GREP_SEARCH_AFT_SEARCH_HINT : GREP_SEARCH_GREP_HINT;
8323
8405
  return `${output}
8324
8406
 
8325
8407
  ${hint}`;
8326
8408
  }
8327
- function shouldSuppressGrepSearchHint(command, projectRoot) {
8328
- const statements = splitTopLevelStatements(command);
8409
+ function shouldSuppressGrepSearchHint(command, projectRoot, platform, workdir) {
8410
+ const statements = splitTopLevelStatements(command, platform);
8329
8411
  if (statements === null)
8330
8412
  return false;
8331
- if (allSearchPathOperandsAreDynamic(statements))
8413
+ if (allSearchPathOperandsAreDynamic(statements, platform))
8332
8414
  return true;
8333
8415
  const root = projectRoot?.trim();
8334
8416
  if (!root)
8335
8417
  return false;
8336
- const resolvedRoot = path.resolve(root);
8337
- let effectiveCwd = resolvedRoot;
8418
+ const paths = platform === "win32" ? path.win32 : path.posix;
8419
+ const resolvedRoot = paths.resolve(root);
8420
+ let effectiveCwd = paths.resolve(resolvedRoot, workdir ?? ".");
8338
8421
  let sawCodeSearchStatement = false;
8339
8422
  for (const statement of statements) {
8340
- const firstStage = firstPipelineStage(statement);
8423
+ const firstStage = firstPipelineStage(statement, platform);
8341
8424
  if (firstStage === null)
8342
8425
  continue;
8343
- const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
8426
+ const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0), platform);
8344
8427
  if (firstToken === null)
8345
8428
  continue;
8346
8429
  const head = firstToken.token;
8347
8430
  if (head === "cd") {
8348
- effectiveCwd = nextCwdAfterCd(effectiveCwd, firstStage, firstToken.end);
8431
+ effectiveCwd = nextCwdAfterCd(effectiveCwd, firstStage, firstToken.end, platform);
8349
8432
  continue;
8350
8433
  }
8351
8434
  if (head !== "grep" && head !== "rg")
@@ -8353,20 +8436,23 @@ function shouldSuppressGrepSearchHint(command, projectRoot) {
8353
8436
  sawCodeSearchStatement = true;
8354
8437
  if (effectiveCwd === null)
8355
8438
  continue;
8356
- if (!isDirInsideProject(resolvedRoot, effectiveCwd))
8439
+ if (!isDirInsideProject(resolvedRoot, effectiveCwd, platform))
8357
8440
  continue;
8358
- const operands = collectPathOperands(firstStage, firstToken.end);
8441
+ const operands = collectPathOperands(firstStage, firstToken.end, platform);
8359
8442
  if (operands.length === 0)
8360
8443
  return false;
8361
8444
  let sawInProjectOperand = false;
8362
8445
  for (const operand of operands) {
8363
8446
  if (isDynamicPathOperand(operand))
8364
8447
  continue;
8365
- const resolvedOperand = resolvePathOperand(effectiveCwd, operand);
8366
- if (!isPathInsideProject(resolvedRoot, effectiveCwd, operand))
8448
+ const resolvedOperand = resolvePathOperand(effectiveCwd, operand, platform);
8449
+ if (!isPathInsideProject(resolvedRoot, effectiveCwd, operand, platform))
8450
+ continue;
8451
+ const suppress = shouldSuppressResolvedPath(resolvedOperand);
8452
+ if (suppress === undefined)
8367
8453
  continue;
8368
8454
  sawInProjectOperand = true;
8369
- if (shouldSuppressResolvedPath(resolvedOperand))
8455
+ if (suppress)
8370
8456
  return true;
8371
8457
  }
8372
8458
  if (sawInProjectOperand)
@@ -8374,19 +8460,19 @@ function shouldSuppressGrepSearchHint(command, projectRoot) {
8374
8460
  }
8375
8461
  return sawCodeSearchStatement;
8376
8462
  }
8377
- function allSearchPathOperandsAreDynamic(statements) {
8463
+ function allSearchPathOperandsAreDynamic(statements, platform) {
8378
8464
  let sawDynamicOnlySearch = false;
8379
8465
  for (const statement of statements) {
8380
- const firstStage = firstPipelineStage(statement);
8466
+ const firstStage = firstPipelineStage(statement, platform);
8381
8467
  if (firstStage === null)
8382
8468
  continue;
8383
- const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
8469
+ const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0), platform);
8384
8470
  if (firstToken === null)
8385
8471
  continue;
8386
8472
  const head = firstToken.token;
8387
8473
  if (head !== "grep" && head !== "rg")
8388
8474
  continue;
8389
- const operands = collectPathOperands(firstStage, firstToken.end);
8475
+ const operands = collectPathOperands(firstStage, firstToken.end, platform);
8390
8476
  if (operands.length === 0)
8391
8477
  return false;
8392
8478
  if (operands.some((operand) => !isDynamicPathOperand(operand)))
@@ -8395,11 +8481,12 @@ function allSearchPathOperandsAreDynamic(statements) {
8395
8481
  }
8396
8482
  return sawDynamicOnlySearch;
8397
8483
  }
8398
- function nextCwdAfterCd(currentCwd, firstStage, afterCd) {
8484
+ function nextCwdAfterCd(currentCwd, firstStage, afterCd, platform) {
8485
+ const paths = platform === "win32" ? path.win32 : path.posix;
8399
8486
  let index = skipSpaces(firstStage, afterCd);
8400
8487
  let target = null;
8401
8488
  while (index < firstStage.length) {
8402
- const tokenResult = readShellToken(firstStage, index);
8489
+ const tokenResult = readShellToken(firstStage, index, platform);
8403
8490
  if (tokenResult === null)
8404
8491
  break;
8405
8492
  const { token, end } = tokenResult;
@@ -8414,28 +8501,29 @@ function nextCwdAfterCd(currentCwd, firstStage, afterCd) {
8414
8501
  break;
8415
8502
  }
8416
8503
  if (target === null)
8417
- return path.resolve(os.homedir());
8504
+ return paths.resolve(os.homedir());
8418
8505
  if (target.includes("$") || target.includes("`"))
8419
8506
  return null;
8420
- const expanded = expandTilde(target);
8421
- if (path.isAbsolute(expanded))
8422
- return path.resolve(expanded);
8507
+ const expanded = expandTilde(target, platform);
8508
+ if (paths.isAbsolute(expanded))
8509
+ return paths.resolve(expanded);
8423
8510
  if (currentCwd === null)
8424
8511
  return null;
8425
- return path.resolve(currentCwd, expanded);
8512
+ return paths.resolve(currentCwd, expanded);
8426
8513
  }
8427
- function isDirInsideProject(resolvedRoot, dir) {
8428
- const rel = path.relative(resolvedRoot, path.resolve(dir));
8429
- return !relativePathEscapesRoot(rel);
8514
+ function isDirInsideProject(resolvedRoot, dir, platform) {
8515
+ const paths = platform === "win32" ? path.win32 : path.posix;
8516
+ const rel = paths.relative(resolvedRoot, paths.resolve(dir));
8517
+ return !relativePathEscapesRoot(rel, platform);
8430
8518
  }
8431
- function collectPathOperands(firstStage, startAfterCommand) {
8519
+ function collectPathOperands(firstStage, startAfterCommand, platform) {
8432
8520
  const operands = [];
8433
8521
  let index = skipSpaces(firstStage, startAfterCommand);
8434
8522
  let sawPattern = false;
8435
8523
  let optionsEnded = false;
8436
8524
  let optionValue;
8437
8525
  while (index < firstStage.length) {
8438
- const tokenResult = readShellToken(firstStage, index);
8526
+ const tokenResult = readShellToken(firstStage, index, platform);
8439
8527
  if (tokenResult === null)
8440
8528
  break;
8441
8529
  const { token, end } = tokenResult;
@@ -8494,22 +8582,25 @@ function collectPathOperands(firstStage, startAfterCommand) {
8494
8582
  function isDynamicPathOperand(token) {
8495
8583
  return token.startsWith("~") || token.includes("$") || token.includes("`");
8496
8584
  }
8497
- function expandTilde(target) {
8585
+ function expandTilde(target, platform) {
8498
8586
  if (!target.startsWith("~"))
8499
8587
  return target;
8500
8588
  if (target === "~" || target.startsWith("~/")) {
8501
- return path.join(os.homedir(), target.slice(1));
8589
+ const paths = platform === "win32" ? path.win32 : path.posix;
8590
+ return paths.join(os.homedir(), target.slice(1));
8502
8591
  }
8503
8592
  return target;
8504
8593
  }
8505
- function resolvePathOperand(projectRoot, operand) {
8506
- const expanded = expandTilde(operand);
8507
- return path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(projectRoot, expanded);
8594
+ function resolvePathOperand(projectRoot, operand, platform) {
8595
+ const paths = platform === "win32" ? path.win32 : path.posix;
8596
+ const expanded = expandTilde(operand, platform);
8597
+ return paths.isAbsolute(expanded) ? paths.resolve(expanded) : paths.resolve(projectRoot, expanded);
8508
8598
  }
8509
- function isPathInsideProject(resolvedRoot, baseCwd, operand) {
8510
- const resolved = resolvePathOperand(baseCwd, operand);
8511
- const rel = path.relative(resolvedRoot, resolved);
8512
- return !relativePathEscapesRoot(rel);
8599
+ function isPathInsideProject(resolvedRoot, baseCwd, operand, platform) {
8600
+ const paths = platform === "win32" ? path.win32 : path.posix;
8601
+ const resolved = resolvePathOperand(baseCwd, operand, platform);
8602
+ const rel = paths.relative(resolvedRoot, resolved);
8603
+ return !relativePathEscapesRoot(rel, platform);
8513
8604
  }
8514
8605
  function shouldSuppressResolvedPath(resolved) {
8515
8606
  try {
@@ -8517,12 +8608,12 @@ function shouldSuppressResolvedPath(resolved) {
8517
8608
  if (stats.isFile())
8518
8609
  return true;
8519
8610
  const ageMs = Date.now() - stats.mtimeMs;
8520
- return ageMs >= 0 && ageMs < GREP_SEARCH_FRESHNESS_WINDOW_MS;
8611
+ return ageMs > -MTIME_CLOCK_SLACK_MS && ageMs < GREP_SEARCH_FRESHNESS_WINDOW_MS;
8521
8612
  } catch {
8522
- return false;
8613
+ return;
8523
8614
  }
8524
8615
  }
8525
- function splitTopLevelStatements(command) {
8616
+ function splitTopLevelStatements(command, platform = process.platform) {
8526
8617
  const statements = [];
8527
8618
  let start = 0;
8528
8619
  let quote = "none";
@@ -8541,7 +8632,7 @@ function splitTopLevelStatements(command) {
8541
8632
  continue;
8542
8633
  }
8543
8634
  if (quote === "double") {
8544
- if (ch === "\\")
8635
+ if (ch === "\\" && backslashEscapesNext(command[index + 1], quote, platform))
8545
8636
  escaped = true;
8546
8637
  else if (ch === '"')
8547
8638
  quote = "none";
@@ -8552,7 +8643,7 @@ function splitTopLevelStatements(command) {
8552
8643
  inBacktick = false;
8553
8644
  continue;
8554
8645
  }
8555
- if (ch === "\\") {
8646
+ if (ch === "\\" && backslashEscapesNext(command[index + 1], quote, platform)) {
8556
8647
  escaped = true;
8557
8648
  continue;
8558
8649
  }
@@ -8595,7 +8686,7 @@ function splitTopLevelStatements(command) {
8595
8686
  statements.push(command.slice(start));
8596
8687
  return statements;
8597
8688
  }
8598
- function firstPipelineStage(command) {
8689
+ function firstPipelineStage(command, platform = process.platform) {
8599
8690
  let quote = "none";
8600
8691
  let firstPipeIndex;
8601
8692
  for (let index = 0;index < command.length; index++) {
@@ -8608,7 +8699,7 @@ function firstPipelineStage(command) {
8608
8699
  if (quote === "double") {
8609
8700
  if (ch === '"') {
8610
8701
  quote = "none";
8611
- } else if (ch === "\\") {
8702
+ } else if (ch === "\\" && backslashEscapesNext(command[index + 1], quote, platform)) {
8612
8703
  index++;
8613
8704
  } else if (ch === "`") {
8614
8705
  return null;
@@ -8619,7 +8710,7 @@ function firstPipelineStage(command) {
8619
8710
  quote = "single";
8620
8711
  } else if (ch === '"') {
8621
8712
  quote = "double";
8622
- } else if (ch === "\\") {
8713
+ } else if (ch === "\\" && backslashEscapesNext(command[index + 1], quote, platform)) {
8623
8714
  index++;
8624
8715
  } else if (ch === "`") {
8625
8716
  return null;
@@ -8635,7 +8726,7 @@ function firstPipelineStage(command) {
8635
8726
  return null;
8636
8727
  return command.slice(0, firstPipeIndex ?? command.length).trim();
8637
8728
  }
8638
- function readShellToken(command, start) {
8729
+ function readShellToken(command, start, platform = process.platform) {
8639
8730
  let quote = "none";
8640
8731
  let token = "";
8641
8732
  let index = start;
@@ -8652,9 +8743,11 @@ function readShellToken(command, start) {
8652
8743
  if (quote === "double") {
8653
8744
  if (ch === '"') {
8654
8745
  quote = "none";
8655
- } else if (ch === "\\") {
8746
+ } else if (ch === "\\" && backslashEscapesNext(command[index + 1], quote, platform)) {
8656
8747
  index++;
8657
- token += command[index] ?? "\\";
8748
+ if (command[index] !== `
8749
+ `)
8750
+ token += command[index];
8658
8751
  } else if (ch === "`") {
8659
8752
  return null;
8660
8753
  } else {
@@ -8670,7 +8763,7 @@ function readShellToken(command, start) {
8670
8763
  quote = "single";
8671
8764
  } else if (ch === '"') {
8672
8765
  quote = "double";
8673
- } else if (ch === "\\") {
8766
+ } else if (ch === "\\" && backslashEscapesNext(command[index + 1], quote, platform)) {
8674
8767
  index++;
8675
8768
  token += command[index] ?? "\\";
8676
8769
  } else if (ch === "`") {
@@ -8683,6 +8776,11 @@ function readShellToken(command, start) {
8683
8776
  return null;
8684
8777
  return { token, end: index };
8685
8778
  }
8779
+ function backslashEscapesNext(next, quote, platform) {
8780
+ if (quote === "double")
8781
+ return next !== undefined && '$`"\\\n'.includes(next);
8782
+ return platform !== "win32";
8783
+ }
8686
8784
  function isTokenBoundary(ch) {
8687
8785
  return ch === "|" || ch === ";" || ch === "&" || ch === "<" || ch === ">";
8688
8786
  }
@@ -8694,7 +8792,7 @@ function skipSpaces(input, start) {
8694
8792
  }
8695
8793
  // ../aft-bridge/dist/bash-host-fallback.js
8696
8794
  import { existsSync } from "node:fs";
8697
- import { join as join4 } from "node:path";
8795
+ import { join as join3 } from "node:path";
8698
8796
 
8699
8797
  // ../aft-bridge/dist/child-process.js
8700
8798
  import { execFile as nodeExecFile, execFileSync as nodeExecFileSync, execSync as nodeExecSync, spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
@@ -8702,7 +8800,7 @@ import { execFile as nodeExecFile, execFileSync as nodeExecFileSync, execSync as
8702
8800
  // ../aft-bridge/dist/test-child-environment.js
8703
8801
  import { mkdirSync, realpathSync } from "node:fs";
8704
8802
  import { homedir as homedir3, tmpdir } from "node:os";
8705
- import { dirname, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2 } from "node:path";
8803
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
8706
8804
  var DIRECTORIES = [
8707
8805
  "HOME",
8708
8806
  "USERPROFILE",
@@ -8722,8 +8820,8 @@ function toolchainHomes(inherited) {
8722
8820
  if (!global[TOOLCHAINS]) {
8723
8821
  const home = process.platform === "win32" ? inherited.USERPROFILE || inherited.HOME || homedir3() : inherited.HOME || homedir3();
8724
8822
  global[TOOLCHAINS] = {
8725
- RUSTUP_HOME: inherited.RUSTUP_HOME || join2(home, ".rustup"),
8726
- CARGO_HOME: inherited.CARGO_HOME || join2(home, ".cargo")
8823
+ RUSTUP_HOME: inherited.RUSTUP_HOME || join(home, ".rustup"),
8824
+ CARGO_HOME: inherited.CARGO_HOME || join(home, ".cargo")
8727
8825
  };
8728
8826
  }
8729
8827
  return global[TOOLCHAINS];
@@ -8750,31 +8848,31 @@ function isolatedAftEnvironment(root, inherited = process.env) {
8750
8848
  "aft-cache"
8751
8849
  ];
8752
8850
  for (const [index, key] of DIRECTORIES.entries()) {
8753
- env[key] = join2(root, names[index]);
8851
+ env[key] = join(root, names[index]);
8754
8852
  mkdirSync(env[key], { recursive: true });
8755
8853
  }
8756
8854
  delete env.AFT_ALLOW_PRODUCTION_MIGRATION;
8757
- createdRoots().add(resolve2(root));
8855
+ createdRoots().add(resolve(root));
8758
8856
  return env;
8759
8857
  }
8760
8858
  function canonical(path) {
8761
- let ancestor = resolve2(path);
8859
+ let ancestor = resolve(path);
8762
8860
  const tail = [];
8763
8861
  while (true) {
8764
8862
  try {
8765
- return join2(realpathSync(ancestor), ...tail);
8863
+ return join(realpathSync(ancestor), ...tail);
8766
8864
  } catch {
8767
8865
  const parent = dirname(ancestor);
8768
8866
  if (parent === ancestor)
8769
- return resolve2(path);
8770
- tail.unshift(relative2(parent, ancestor));
8867
+ return resolve(path);
8868
+ tail.unshift(relative(parent, ancestor));
8771
8869
  ancestor = parent;
8772
8870
  }
8773
8871
  }
8774
8872
  }
8775
8873
  function within(path, root) {
8776
- const tail = relative2(canonical(root), canonical(path));
8777
- return tail === "" || !tail.startsWith("..") && !isAbsolute2(tail);
8874
+ const tail = relative(canonical(root), canonical(path));
8875
+ return tail === "" || !tail.startsWith("..") && !isAbsolute(tail);
8778
8876
  }
8779
8877
  function testChildEnvironment(env) {
8780
8878
  const root = process.env.AFT_TEST_ISOLATION_ROOT;
@@ -8850,7 +8948,7 @@ function withPathPrepended(env, dir, platform = process.platform) {
8850
8948
 
8851
8949
  // ../aft-bridge/dist/storage-paths.js
8852
8950
  import { homedir as homedir4, tmpdir as tmpdir2 } from "node:os";
8853
- import { join as join3, resolve as resolve3 } from "node:path";
8951
+ import { join as join2, resolve as resolve2 } from "node:path";
8854
8952
  function environmentValue(context, name) {
8855
8953
  const value = (context.lookup ?? ((key) => process.env[key]))(name);
8856
8954
  return value !== undefined && value.length > 0 ? value : undefined;
@@ -8872,21 +8970,21 @@ function resolveDataHome(context = {}) {
8872
8970
  return localAppData;
8873
8971
  const userProfile = environmentValue(context, "USERPROFILE");
8874
8972
  if (userProfile)
8875
- return join3(userProfile, "AppData", "Local");
8973
+ return join2(userProfile, "AppData", "Local");
8876
8974
  }
8877
8975
  const home = environmentValue(context, "HOME");
8878
8976
  if (home)
8879
- return join3(home, ".local", "share");
8880
- return join3(".local", "share");
8977
+ return join2(home, ".local", "share");
8978
+ return join2(".local", "share");
8881
8979
  }
8882
8980
  function resolveStoragePath(raw, context = {}) {
8883
8981
  let expanded = raw;
8884
8982
  if (raw === "~") {
8885
8983
  expanded = homeDir(context);
8886
8984
  } else if (raw.startsWith("~/") || raw.startsWith("~\\")) {
8887
- expanded = join3(homeDir(context), raw.slice(2));
8985
+ expanded = join2(homeDir(context), raw.slice(2));
8888
8986
  }
8889
- return resolve3(context.currentDirectory ?? process.cwd(), expanded);
8987
+ return resolve2(context.currentDirectory ?? process.cwd(), expanded);
8890
8988
  }
8891
8989
  function resolveCortexKitStorageRoot(context = {}) {
8892
8990
  const override = environmentValue(context, "AFT_STORAGE_DIR");
@@ -8894,8 +8992,8 @@ function resolveCortexKitStorageRoot(context = {}) {
8894
8992
  return resolveStoragePath(override, context);
8895
8993
  const legacyCache = environmentValue(context, "AFT_CACHE_DIR");
8896
8994
  if (legacyCache)
8897
- return join3(resolveStoragePath(legacyCache, context), "aft");
8898
- return resolveStoragePath(join3(resolveDataHome(context), "cortexkit", "aft"), context);
8995
+ return join2(resolveStoragePath(legacyCache, context), "aft");
8996
+ return resolveStoragePath(join2(resolveDataHome(context), "cortexkit", "aft"), context);
8899
8997
  }
8900
8998
  function resolveAftStorageRoot(configuredRoot, context = {}) {
8901
8999
  if (environmentValue(context, "AFT_STORAGE_DIR")) {
@@ -8906,14 +9004,14 @@ function resolveAftStorageRoot(configuredRoot, context = {}) {
8906
9004
  return resolveCortexKitStorageRoot(context);
8907
9005
  }
8908
9006
  function resolveAftLogPath(filename, configuredRoot, context = {}) {
8909
- return join3(resolveAftStorageRoot(configuredRoot, context), "logs", filename);
9007
+ return join2(resolveAftStorageRoot(configuredRoot, context), "logs", filename);
8910
9008
  }
8911
9009
  function isTestEnvironment(context = {}) {
8912
9010
  return environmentValue(context, "BUN_TEST") === "1" || environmentValue(context, "NODE_ENV") === "test";
8913
9011
  }
8914
9012
  function resolvePluginLogPath(context = {}) {
8915
9013
  if (isTestEnvironment(context)) {
8916
- return join3(environmentValue(context, "TMPDIR") ?? tmpdir2(), `aft-plugin-tests-${process.pid}`, "logs", "aft-plugin-test.log");
9014
+ return join2(environmentValue(context, "TMPDIR") ?? tmpdir2(), `aft-plugin-tests-${process.pid}`, "logs", "aft-plugin-test.log");
8917
9015
  }
8918
9016
  return resolveAftLogPath("aft-plugin.log", undefined, context);
8919
9017
  }
@@ -8948,8 +9046,8 @@ function hostFallbackEnvWithShims(env, platform) {
8948
9046
  const pathKey = pathKeyForPlatform(normalized, platform);
8949
9047
  const inherited = pathKey === undefined ? undefined : normalized[pathKey];
8950
9048
  const storageRoot = normalized.AFT_STORAGE_DIR ? resolveStoragePath(normalized.AFT_STORAGE_DIR) : resolveCortexKitStorageRoot();
8951
- const shimsDir = join4(storageRoot, "shims");
8952
- if (!existsSync(join4(shimsDir, platform === "win32" ? "gh.cmd" : "gh")))
9049
+ const shimsDir = join3(storageRoot, "shims");
9050
+ if (!existsSync(join3(shimsDir, platform === "win32" ? "gh.cmd" : "gh")))
8953
9051
  return normalized;
8954
9052
  const separator = platform === "win32" ? ";" : ":";
8955
9053
  const entries = (inherited ?? "").split(separator).filter((entry) => entry.length > 0);
@@ -9708,7 +9806,7 @@ async function cachedFileSha256(path) {
9708
9806
  }
9709
9807
  // ../aft-bridge/dist/bridge.js
9710
9808
  import { homedir as homedir5 } from "node:os";
9711
- import { join as join5 } from "node:path";
9809
+ import { join as join4 } from "node:path";
9712
9810
  import { StringDecoder } from "node:string_decoder";
9713
9811
 
9714
9812
  // ../aft-bridge/dist/command-timeouts.js
@@ -9846,6 +9944,7 @@ function compareSemver(a, b) {
9846
9944
  }
9847
9945
  var SYSTEM_CLOCK = {
9848
9946
  now: () => Date.now(),
9947
+ awakeNow: () => performance.now(),
9849
9948
  setTimeout: (callback, ms) => setTimeout(callback, ms),
9850
9949
  clearTimeout: (timer) => clearTimeout(timer)
9851
9950
  };
@@ -9962,6 +10061,7 @@ class BinaryBridge {
9962
10061
  hangWindowMinMs;
9963
10062
  hangProbeTimeoutMs;
9964
10063
  clock;
10064
+ waitClock;
9965
10065
  lateShellReplyGraceMs;
9966
10066
  maxRestarts;
9967
10067
  configured = false;
@@ -9998,6 +10098,7 @@ class BinaryBridge {
9998
10098
  this.hangWindowMinMs = options?.hangWindowMinMs ?? DEFAULT_MIN_HANG_WINDOW_MS;
9999
10099
  this.hangProbeTimeoutMs = options?.hangProbeTimeoutMs ?? DEFAULT_HANG_PROBE_TIMEOUT_MS;
10000
10100
  this.clock = options?.clock ?? SYSTEM_CLOCK;
10101
+ this.waitClock = new WaitClock(() => this.clock.now(), () => this.clock.awakeNow?.() ?? this.clock.now());
10001
10102
  this.lateShellReplyGraceMs = options?.lateShellReplyGraceMs ?? DEFAULT_LATE_SHELL_REPLY_GRACE_MS;
10002
10103
  this.maxRestarts = options?.maxRestarts ?? 3;
10003
10104
  this.errorPrefix = options?.errorPrefix ?? "[aft-bridge]";
@@ -10364,11 +10465,17 @@ class BinaryBridge {
10364
10465
  const keepBridgeOnTimeout = passive || command === "bash_drain_completions" || options?.keepBridgeOnTimeout === true;
10365
10466
  const child = this.process;
10366
10467
  const response = await new Promise((resolve, reject) => {
10367
- const timer = this.clock.setTimeout(() => {
10468
+ const deadline = new RequestDeadline(this.waitClock, effectiveTimeoutMs);
10469
+ const expire = () => {
10368
10470
  const entry = this.pending.get(id);
10369
10471
  if (!entry)
10370
10472
  return;
10371
- if (keepBridgeOnTimeout && this.holdForLateShellReply(id, entry, effectiveTimeoutMs, requestSessionId)) {
10473
+ const remaining = deadline.remaining();
10474
+ if (remaining > 0) {
10475
+ entry.timer = this.clock.setTimeout(expire, Math.min(remaining, DEADLINE_POLL_MS));
10476
+ return;
10477
+ }
10478
+ if (keepBridgeOnTimeout && !deadline.resumed && this.holdForLateShellReply(id, entry, effectiveTimeoutMs, requestSessionId)) {
10372
10479
  return;
10373
10480
  }
10374
10481
  this.pending.delete(id);
@@ -10381,11 +10488,12 @@ class BinaryBridge {
10381
10488
  this.warnVia(timeoutMsg);
10382
10489
  }
10383
10490
  if (keepBridgeOnTimeout) {
10384
- entry.reject(new BridgeTransportTimeoutError(command, effectiveTimeoutMs, `${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
10491
+ entry.reject(new BridgeTransportTimeoutError(command, effectiveTimeoutMs, `${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`, deadline.resumed && SHELL_TASK_COMMANDS.has(command) ? { kind: "unknown" } : undefined));
10385
10492
  return;
10386
10493
  }
10387
10494
  entry.reject(new Error(`${this.errorPrefix} request "${command}" timed out after ${effectiveTimeoutMs}ms (bridge busy/under load); bridge kept warm — retry. A timed-out mutation may still complete; inspect before repeating it.`));
10388
- }, effectiveTimeoutMs);
10495
+ };
10496
+ const timer = this.clock.setTimeout(expire, Math.min(effectiveTimeoutMs, DEADLINE_POLL_MS));
10389
10497
  const entry = {
10390
10498
  resolve,
10391
10499
  reject,
@@ -10616,11 +10724,11 @@ class BinaryBridge {
10616
10724
  })();
10617
10725
  const useFastembedBackend = semanticBackend === undefined || semanticBackend === "fastembed" || semanticBackend === "";
10618
10726
  const ortDir = typeof this.configOverrides._ort_dylib_dir === "string" && useFastembedBackend ? this.configOverrides._ort_dylib_dir : null;
10619
- const ortLibraryPath = ortDir == null ? null : join5(ortDir, this.platform === "win32" ? "onnxruntime.dll" : this.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
10727
+ const ortLibraryPath = ortDir == null ? null : join4(ortDir, this.platform === "win32" ? "onnxruntime.dll" : this.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
10620
10728
  const env = { ...process.env };
10621
10729
  this.logVia(`bridge.spawnProcess: useFastembedBackend=${useFastembedBackend}, ` + `parentORT=${process.env.ORT_DYLIB_PATH ?? "(unset)"}, ` + `ortLibraryPath=${ortLibraryPath ?? "(none)"}`);
10622
10730
  if (useFastembedBackend) {
10623
- env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join5(this.configOverrides.storage_dir, "semantic", "models") : join5(homedir5() || "", ".cache", "fastembed"));
10731
+ env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join4(this.configOverrides.storage_dir, "semantic", "models") : join4(homedir5() || "", ".cache", "fastembed"));
10624
10732
  if (process.env.ORT_DYLIB_PATH) {
10625
10733
  this.logVia(`ORT_DYLIB_PATH inherited from parent env: ${process.env.ORT_DYLIB_PATH}`);
10626
10734
  } else if (ortLibraryPath) {
@@ -10941,14 +11049,21 @@ class BinaryBridge {
10941
11049
  };
10942
11050
  entry.resolve = (response) => settle(shellOutcomeFromLateReply(response));
10943
11051
  this.clock.clearTimeout(entry.timer);
10944
- entry.timer = this.clock.setTimeout(() => {
11052
+ const deadline = new RequestDeadline(this.waitClock, graceMs, false);
11053
+ const expire = () => {
10945
11054
  if (this.pending.get(id) !== entry)
10946
11055
  return;
11056
+ const remaining = deadline.remaining();
11057
+ if (remaining > 0) {
11058
+ entry.timer = this.clock.setTimeout(expire, Math.min(remaining, DEADLINE_POLL_MS));
11059
+ return;
11060
+ }
10947
11061
  this.pending.delete(id);
10948
11062
  entry.onSettled?.();
10949
11063
  this.warnVia(`Request "${entry.command}" (id=${id}) got no reply within ${graceMs}ms after its deadline`);
10950
11064
  settle({ kind: "unknown" });
10951
- }, graceMs);
11065
+ };
11066
+ entry.timer = this.clock.setTimeout(expire, Math.min(graceMs, DEADLINE_POLL_MS));
10952
11067
  return true;
10953
11068
  }
10954
11069
  accountForBashTaskResponse(command, response) {
@@ -11196,7 +11311,7 @@ class BinaryBridge {
11196
11311
  }
11197
11312
  // ../aft-bridge/dist/cache-paths.js
11198
11313
  import { homedir as homedir6 } from "node:os";
11199
- import { join as join6 } from "node:path";
11314
+ import { join as join5 } from "node:path";
11200
11315
  function homeDir2(env) {
11201
11316
  return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir6();
11202
11317
  }
@@ -11204,20 +11319,20 @@ function getAftCacheRoot(env = process.env) {
11204
11319
  if (env.AFT_CACHE_DIR)
11205
11320
  return env.AFT_CACHE_DIR;
11206
11321
  if (process.platform === "win32") {
11207
- const base = env.LOCALAPPDATA || env.APPDATA || join6(homeDir2(env), "AppData", "Local");
11208
- return join6(base, "aft");
11322
+ const base = env.LOCALAPPDATA || env.APPDATA || join5(homeDir2(env), "AppData", "Local");
11323
+ return join5(base, "aft");
11209
11324
  }
11210
- const base = env.XDG_CACHE_HOME || join6(homeDir2(env), ".cache");
11211
- return join6(base, "aft");
11325
+ const base = env.XDG_CACHE_HOME || join5(homeDir2(env), ".cache");
11326
+ return join5(base, "aft");
11212
11327
  }
11213
11328
  function getAftBinaryCacheDir(env = process.env) {
11214
- return join6(getAftCacheRoot(env), "bin");
11329
+ return join5(getAftCacheRoot(env), "bin");
11215
11330
  }
11216
11331
  function getAftLspPackagesDir(env = process.env) {
11217
- return join6(getAftCacheRoot(env), "lsp-packages");
11332
+ return join5(getAftCacheRoot(env), "lsp-packages");
11218
11333
  }
11219
11334
  function getAftLspBinariesDir(env = process.env) {
11220
- return join6(getAftCacheRoot(env), "lsp-binaries");
11335
+ return join5(getAftCacheRoot(env), "lsp-binaries");
11221
11336
  }
11222
11337
  // ../aft-bridge/dist/callgraph-format.js
11223
11338
  var UNRESOLVED_SUMMARY_NAME_LIMIT = 10;
@@ -11706,7 +11821,7 @@ function isFindReplaceOnlyEdit(args) {
11706
11821
  }
11707
11822
  // ../aft-bridge/dist/config-error.js
11708
11823
  import { homedir as homedir7 } from "node:os";
11709
- import { isAbsolute as isAbsolute3, join as join7 } from "node:path";
11824
+ import { isAbsolute as isAbsolute2, join as join6 } from "node:path";
11710
11825
  var CONFIG_ERROR_RESTART_NOTE = "AFT reads its config only at startup, so restart the host after fixing it.";
11711
11826
  function formatConfigErrorMessage(detail) {
11712
11827
  const trimmed = detail.trim();
@@ -11716,10 +11831,10 @@ function formatConfigErrorMessage(detail) {
11716
11831
  function resolveSubcConnectionFilePath(raw, home = homedir7()) {
11717
11832
  const trimmed = raw.trim();
11718
11833
  if (trimmed.startsWith("~"))
11719
- return join7(home, trimmed.slice(1).replace(/^[/\\]/, ""));
11720
- if (isAbsolute3(trimmed))
11834
+ return join6(home, trimmed.slice(1).replace(/^[/\\]/, ""));
11835
+ if (isAbsolute2(trimmed))
11721
11836
  return trimmed;
11722
- return join7(home, trimmed);
11837
+ return join6(home, trimmed);
11723
11838
  }
11724
11839
  function formatSubcConnectionMissingMessage(raw, resolved) {
11725
11840
  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.`;
@@ -11780,7 +11895,7 @@ function stripHarnessSpecificConfigKeys(value, keys) {
11780
11895
  }
11781
11896
  // ../aft-bridge/dist/config-tiers.js
11782
11897
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
11783
- import { resolve as resolve4 } from "node:path";
11898
+ import { resolve as resolve3 } from "node:path";
11784
11899
  function readConfigTiers(opts) {
11785
11900
  const tiers = [];
11786
11901
  try {
@@ -11788,7 +11903,7 @@ function readConfigTiers(opts) {
11788
11903
  const doc = readFileSync2(opts.userConfigPath, "utf-8");
11789
11904
  tiers.push({
11790
11905
  tier: "user",
11791
- source: resolve4(opts.userConfigPath),
11906
+ source: resolve3(opts.userConfigPath),
11792
11907
  doc
11793
11908
  });
11794
11909
  }
@@ -11798,7 +11913,7 @@ function readConfigTiers(opts) {
11798
11913
  const doc = readFileSync2(opts.projectConfigPath, "utf-8");
11799
11914
  tiers.push({
11800
11915
  tier: "project",
11801
- source: resolve4(opts.projectConfigPath),
11916
+ source: resolve3(opts.projectConfigPath),
11802
11917
  doc
11803
11918
  });
11804
11919
  }
@@ -11814,7 +11929,7 @@ function formatDroppedKeyWarnings(dropped) {
11814
11929
  // ../aft-bridge/dist/config-watch.js
11815
11930
  import { createHash as createHash2 } from "node:crypto";
11816
11931
  import { closeSync as closeSync2, fstatSync, openSync as openSync2, readFileSync as readFileSync3, readSync as readSync2, realpathSync as realpathSync2, statSync as statSync3, watch } from "node:fs";
11817
- import { basename, dirname as dirname2, resolve as resolve5 } from "node:path";
11932
+ import { basename, dirname as dirname2, resolve as resolve4 } from "node:path";
11818
11933
  var CONFIG_WATCH_DEBOUNCE_MS = 150;
11819
11934
  var CONFIG_LIVE_KEEP_NOTE = "AFT keeps using the last valid configuration until the file is fixed.";
11820
11935
  function pathKey(name) {
@@ -11869,6 +11984,7 @@ function aftLiveConfigKeys(resolveBash) {
11869
11984
  pathKey("revision_reads"),
11870
11985
  pathKey("inspect.diagnostics_timeout_ms"),
11871
11986
  pathKey("lsp.idle_minutes"),
11987
+ pathKey("lsp.max_servers"),
11872
11988
  ...[
11873
11989
  "diagnostics",
11874
11990
  "todos",
@@ -11981,7 +12097,7 @@ function canonicalDirectory(dir) {
11981
12097
  try {
11982
12098
  return realpathSync2(dir);
11983
12099
  } catch {
11984
- return resolve5(dir);
12100
+ return resolve4(dir);
11985
12101
  }
11986
12102
  }
11987
12103
  function watchAftConfigFiles(options) {
@@ -12001,6 +12117,7 @@ function watchAftConfigFiles(options) {
12001
12117
  const fallbackSeen = new Map;
12002
12118
  const watchImpl = options.watchImpl ?? watch;
12003
12119
  let rejectedRetries = 0;
12120
+ let recheckAfterArming = false;
12004
12121
  const check = () => {
12005
12122
  if (retryTimer)
12006
12123
  clearTimeout(retryTimer);
@@ -12009,7 +12126,8 @@ function watchAftConfigFiles(options) {
12009
12126
  firstPendingAt = null;
12010
12127
  if (stopped)
12011
12128
  return;
12012
- revalidate();
12129
+ if (revalidate())
12130
+ recheckAfterArming = true;
12013
12131
  const seen = new Map;
12014
12132
  for (const path of options.paths) {
12015
12133
  const text = readTextOrNull(path);
@@ -12067,7 +12185,7 @@ function watchAftConfigFiles(options) {
12067
12185
  for (const path of options.paths) {
12068
12186
  try {
12069
12187
  const resolved = realpathSync2(path);
12070
- const target = resolved === resolve5(path) ? undefined : resolved;
12188
+ const target = resolved === resolve4(path) ? undefined : resolved;
12071
12189
  if (targets.get(path) !== target) {
12072
12190
  if (target)
12073
12191
  targets.set(path, target);
@@ -12131,12 +12249,16 @@ function watchAftConfigFiles(options) {
12131
12249
  }
12132
12250
  return moved;
12133
12251
  }
12134
- revalidate();
12252
+ recheckAfterArming = revalidate();
12135
12253
  if (options.checkAtStart)
12136
12254
  check();
12137
12255
  const revalidateTimer = setInterval(() => {
12138
- if (!stopped && revalidate())
12256
+ if (stopped)
12257
+ return;
12258
+ const moved = revalidate();
12259
+ if (moved || recheckAfterArming)
12139
12260
  schedule();
12261
+ recheckAfterArming = moved;
12140
12262
  }, CONFIG_WATCH_REVALIDATE_MS);
12141
12263
  revalidateTimer.unref?.();
12142
12264
  return () => {
@@ -12179,6 +12301,10 @@ function aftLiveSecurityKeys(keys) {
12179
12301
  return minutes(next) > minutes(current);
12180
12302
  }
12181
12303
  },
12304
+ {
12305
+ key: pick("lsp.max_servers"),
12306
+ loosens: (current, next) => (typeof next === "number" ? next : 8) > (typeof current === "number" ? current : 8)
12307
+ },
12182
12308
  ...[
12183
12309
  "diagnostics",
12184
12310
  "todos",
@@ -12288,7 +12414,7 @@ function startLiveConfigReload(options) {
12288
12414
  import { createHash as createHash3, randomUUID } from "node:crypto";
12289
12415
  import { chmodSync, closeSync as closeSync3, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync as openSync3, readdirSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync4, unlinkSync as unlinkSync2, writeSync } from "node:fs";
12290
12416
  import { hostname } from "node:os";
12291
- import { join as join8 } from "node:path";
12417
+ import { join as join7 } from "node:path";
12292
12418
  import { Readable } from "node:stream";
12293
12419
  import { pipeline } from "node:stream/promises";
12294
12420
 
@@ -12404,7 +12530,7 @@ function getBinaryName() {
12404
12530
  function getCachedBinaryPath(version) {
12405
12531
  if (!version)
12406
12532
  return null;
12407
- const binaryPath = join8(getAftBinaryCacheDir(), version, getBinaryName());
12533
+ const binaryPath = join7(getAftBinaryCacheDir(), version, getBinaryName());
12408
12534
  return existsSync3(binaryPath) ? binaryPath : null;
12409
12535
  }
12410
12536
  async function downloadBinary(version) {
@@ -12421,16 +12547,16 @@ async function downloadBinary(version) {
12421
12547
  return null;
12422
12548
  }
12423
12549
  const tag = rawTag.startsWith("v") ? rawTag : `v${rawTag}`;
12424
- const versionedCacheDir = join8(getAftBinaryCacheDir(), tag);
12550
+ const versionedCacheDir = join7(getAftBinaryCacheDir(), tag);
12425
12551
  const binaryName = getBinaryName();
12426
- const binaryPath = join8(versionedCacheDir, binaryName);
12552
+ const binaryPath = join7(versionedCacheDir, binaryName);
12427
12553
  if (existsSync3(binaryPath) && await isExpectedCachedBinary(binaryPath, tag)) {
12428
12554
  return binaryPath;
12429
12555
  }
12430
12556
  const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
12431
12557
  const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
12432
12558
  log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
12433
- const lockPath = join8(versionedCacheDir, ".download.lock");
12559
+ const lockPath = join7(versionedCacheDir, ".download.lock");
12434
12560
  let releaseLock = null;
12435
12561
  let binaryController = null;
12436
12562
  let checksumController = null;
@@ -12656,7 +12782,7 @@ function sweepStaleDownloadTemps(versionedCacheDir, binaryName) {
12656
12782
  if (!entry.isFile() || !entry.name.startsWith(tempPrefix) || !entry.name.endsWith(".tmp")) {
12657
12783
  continue;
12658
12784
  }
12659
- const tempPath = join8(versionedCacheDir, entry.name);
12785
+ const tempPath = join7(versionedCacheDir, entry.name);
12660
12786
  const ageMs = Date.now() - statSync4(tempPath).mtimeMs;
12661
12787
  if (Math.abs(ageMs) > DOWNLOAD_LOCK_STALE_MS)
12662
12788
  unlinkSync2(tempPath);
@@ -12747,7 +12873,7 @@ import { dirname as dirname3 } from "node:path";
12747
12873
 
12748
12874
  // ../aft-bridge/dist/private-storage.js
12749
12875
  import { closeSync as closeSync4, constants, copyFileSync as copyFileSync2, fchmodSync, fstatSync as fstatSync2, lstatSync, mkdirSync as mkdirSync3, openSync as openSync4, readSync as readSync3, writeSync as writeSync2 } from "node:fs";
12750
- import { isAbsolute as isAbsolute4, join as join9, parse, relative as relative3, resolve as resolve6, sep } from "node:path";
12876
+ import { isAbsolute as isAbsolute3, join as join8, parse, relative as relative2, resolve as resolve5, sep } from "node:path";
12751
12877
  var PRIVATE_FILE_MODE = 384;
12752
12878
  var PRIVATE_DIRECTORY_MODE = 448;
12753
12879
  function privateMkdirSync(path, recursive = true) {
@@ -12782,19 +12908,19 @@ function privateCopyFileSync(source, destination) {
12782
12908
  }
12783
12909
  var warned = new Set;
12784
12910
  function openPrivateStorageDir(root, path = root) {
12785
- const base = resolve6(root);
12911
+ const base = resolve5(root);
12786
12912
  if (!root || base === parse(base).root) {
12787
12913
  throw new Error(`refusing filesystem root as private storage: ${base}`);
12788
12914
  }
12789
- const rel = relative3(base, resolve6(path));
12790
- if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute4(rel))
12915
+ const rel = relative2(base, resolve5(path));
12916
+ if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute3(rel))
12791
12917
  return;
12792
12918
  privateMkdirSync(path);
12793
12919
  if (process.platform === "win32")
12794
12920
  return;
12795
12921
  let current = base;
12796
12922
  for (const component of ["", ...rel.split(sep).filter(Boolean)]) {
12797
- current = join9(current, component);
12923
+ current = join8(current, component);
12798
12924
  let fd;
12799
12925
  try {
12800
12926
  if (lstatSync(current).isSymbolicLink())
@@ -13047,21 +13173,23 @@ ${reflowText}`;
13047
13173
  }
13048
13174
  return " Auto-formatted.";
13049
13175
  }
13050
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/client.js
13176
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/client.js
13051
13177
  import { promises as fs3 } from "node:fs";
13178
+ import { createHash as createHash4 } from "node:crypto";
13052
13179
  import { debuglog } from "node:util";
13053
13180
 
13054
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/auth.js
13181
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/auth.js
13055
13182
  import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
13056
13183
 
13057
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/socket.js
13184
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/socket.js
13058
13185
  import net from "node:net";
13059
13186
 
13060
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/envelope.js
13187
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/envelope.js
13061
13188
  var PROTOCOL_VERSION = 2;
13062
13189
  var HEADER_LEN = 21;
13063
13190
  var FROZEN_PREFIX_LEN = 5;
13064
13191
  var MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
13192
+ var MAX_DELIVERED_FRAME_LEN = 4 * 1024 * 1024;
13065
13193
  var FrameType;
13066
13194
  (function(FrameType) {
13067
13195
  FrameType[FrameType["Request"] = 0] = "Request";
@@ -13099,6 +13227,8 @@ var FLAG_PRIORITY_SHIFT = 1;
13099
13227
  var FLAG_LAST = 8;
13100
13228
  var FLAG_ADMISSION_MASK = 48;
13101
13229
  var FLAG_ADMISSION_SHIFT = 4;
13230
+ var DAEMON_ORIGIN_FLAG = 64;
13231
+ var SUBSCRIPTION_FLAG = 128;
13102
13232
  var FLAG_RESERVED_MASK = 0;
13103
13233
  function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Normal) {
13104
13234
  let flags = 0;
@@ -13233,7 +13363,7 @@ function encodeFrame(frame) {
13233
13363
  return output;
13234
13364
  }
13235
13365
 
13236
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/socket.js
13366
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/socket.js
13237
13367
  class SocketClosedError extends Error {
13238
13368
  }
13239
13369
 
@@ -13283,14 +13413,12 @@ class SubcSocket {
13283
13413
  sock.on("data", (chunk) => {
13284
13414
  this.chunks.push(chunk);
13285
13415
  this.buffered += chunk.length;
13286
- if (this.waiter) {
13416
+ if (this.waiter && this.waiter.extendOnProgress && this.buffered < this.waiter.need) {
13287
13417
  if (this.waiter.immediate) {
13288
13418
  clearImmediate(this.waiter.immediate);
13289
13419
  this.waiter.immediate = null;
13290
13420
  }
13291
- if (this.waiter.extendOnProgress && this.buffered < this.waiter.need) {
13292
- this.armWaiterTimer(this.waiter);
13293
- }
13421
+ this.armWaiterTimer(this.waiter);
13294
13422
  }
13295
13423
  this.tryServe();
13296
13424
  });
@@ -13307,12 +13435,18 @@ class SubcSocket {
13307
13435
  return this.sock.localPort ?? null;
13308
13436
  }
13309
13437
  static connect(host, port, deadlineMs) {
13438
+ return SubcSocket.connectTo({ host, port }, `${host}:${port}`, deadlineMs);
13439
+ }
13440
+ static connectLocal(path, deadlineMs) {
13441
+ return SubcSocket.connectTo({ path }, path, deadlineMs);
13442
+ }
13443
+ static connectTo(options, endpoint, deadlineMs) {
13310
13444
  return new Promise((resolve, reject) => {
13311
- const sock = net.connect({ host, port });
13445
+ const sock = net.connect(options);
13312
13446
  sock.setNoDelay(true);
13313
13447
  const timer = setTimeout(() => {
13314
13448
  sock.destroy();
13315
- reject(new SocketTimeoutError(`timed out connecting to ${host}:${port}`));
13449
+ reject(new SocketTimeoutError(`timed out connecting to ${endpoint}`));
13316
13450
  }, Math.max(0, deadlineMs - Date.now()));
13317
13451
  sock.once("connect", () => {
13318
13452
  clearTimeout(timer);
@@ -13529,7 +13663,7 @@ class SubcSocket {
13529
13663
  }
13530
13664
  }
13531
13665
 
13532
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/auth.js
13666
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/auth.js
13533
13667
  var NONCE_LEN = 32;
13534
13668
  var MAX_AUTH_MESSAGE_LEN = 4096;
13535
13669
  var SERVER_PROOF_DOMAIN = "subc-server-v1";
@@ -13603,7 +13737,7 @@ async function authenticateClient(sock, conn, deadlineMs) {
13603
13737
  await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
13604
13738
  }
13605
13739
 
13606
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/connection-file.js
13740
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/connection-file.js
13607
13741
  import { promises as fs2 } from "node:fs";
13608
13742
  var SCHEMA_VERSION = 1;
13609
13743
  var MIN_KEY_LEN = 32;
@@ -13650,7 +13784,10 @@ function verifyOwnerOnly(path, stat, expectedUid) {
13650
13784
  async function readConnectionFile(path) {
13651
13785
  return readConnectionFileForUid(path, process.geteuid?.());
13652
13786
  }
13653
- async function readConnectionFileForUid(path, expectedUid) {
13787
+ async function readConnectionFileWithLocalEndpoint(path) {
13788
+ return readConnectionFileForUid(path, process.geteuid?.(), true);
13789
+ }
13790
+ async function readConnectionFileForUid(path, expectedUid, includeLocalEndpoint = false) {
13654
13791
  const handle = await fs2.open(path, "r");
13655
13792
  let raw;
13656
13793
  try {
@@ -13689,13 +13826,26 @@ async function readConnectionFileForUid(path, expectedUid) {
13689
13826
  daemonVer: parsed.daemon_ver ?? ""
13690
13827
  };
13691
13828
  validate(info);
13829
+ if (includeLocalEndpoint && parsed.local_endpoint != null) {
13830
+ const endpoint = parsed.local_endpoint;
13831
+ if (endpoint.kind === "unix" && typeof endpoint.path === "string" && endpoint.path.length > 0) {
13832
+ info.localEndpoint = { kind: "unix", path: endpoint.path };
13833
+ } else if (endpoint.kind === "pipe" && typeof endpoint.name === "string" && endpoint.name.length > 0) {
13834
+ info.localEndpoint = { kind: "pipe", name: endpoint.name };
13835
+ } else {
13836
+ throw new ConnectionFileError("connection file local_endpoint must name a unix path or pipe name");
13837
+ }
13838
+ }
13692
13839
  return info;
13693
13840
  }
13694
13841
 
13695
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/launch-nonce.js
13842
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/launch-nonce.js
13696
13843
  import { closeSync as closeSync5, fstatSync as fstatSync3, readSync as readSync4 } from "node:fs";
13844
+ import { connect } from "node:net";
13697
13845
  var SUBC_LAUNCH_NONCE_ENV = "SUBC_LAUNCH_NONCE";
13698
13846
  var SUBC_LAUNCH_NONCE_FD_ENV = "SUBC_LAUNCH_NONCE_FD";
13847
+ var SUBC_LAUNCH_NONCE_PIPE_ENV = "SUBC_LAUNCH_NONCE_PIPE";
13848
+ var SUBC_LAUNCH_NONCE_PIPE_FALLBACK_ENV = "SUBC_LAUNCH_NONCE_PIPE_FALLBACK";
13699
13849
  class LaunchNonceError extends Error {
13700
13850
  name = "LaunchNonceError";
13701
13851
  kind;
@@ -13714,9 +13864,21 @@ class LaunchNonceError extends Error {
13714
13864
  this.foundInode = details.foundInode;
13715
13865
  }
13716
13866
  }
13717
- function launchNonceOrUndefined() {
13718
- const result = processCell().result();
13719
- return result.ok ? result.nonce ?? undefined : undefined;
13867
+ function isLaunchNonceError(error) {
13868
+ return error instanceof Error && error.name === "LaunchNonceError" && typeof error.kind === "string";
13869
+ }
13870
+ async function launchNonceAsync() {
13871
+ const cell = processCell();
13872
+ return unwrap(await (cell.resultAsync?.() ?? cell.result()));
13873
+ }
13874
+ async function launchNonceOrUndefinedAsync() {
13875
+ try {
13876
+ return await launchNonceAsync();
13877
+ } catch (error) {
13878
+ if (isLaunchNonceError(error))
13879
+ return;
13880
+ throw error;
13881
+ }
13720
13882
  }
13721
13883
  var PROCESS_CELL_KEY = Symbol.for("@cortexkit/subc-client/launch-nonce/v1");
13722
13884
  function processCell() {
@@ -13736,20 +13898,60 @@ function unwrap(result) {
13736
13898
 
13737
13899
  class LaunchNonceCell {
13738
13900
  cached;
13901
+ pending;
13739
13902
  descriptorReads = 0;
13740
13903
  lookup;
13741
13904
  platform;
13742
13905
  stat;
13743
- constructor(lookup, platform = process.platform, stat = (fd) => fstatSync3(fd, { bigint: true })) {
13906
+ pipeReader;
13907
+ constructor(lookup, platform = process.platform, stat = (fd) => fstatSync3(fd, { bigint: true }), pipeReader = readLaunchNoncePipe) {
13744
13908
  this.lookup = lookup;
13745
13909
  this.platform = platform;
13746
13910
  this.stat = stat;
13911
+ this.pipeReader = pipeReader;
13747
13912
  }
13748
13913
  result() {
13914
+ if (this.cached === undefined && this.platform === "win32" && this.lookup(SUBC_LAUNCH_NONCE_PIPE_ENV) !== undefined) {
13915
+ const fallback = this.permittedPipeFallback();
13916
+ if (fallback === undefined) {
13917
+ throw new LaunchNonceError("PipeNeedsAsync", "call launchNonceAsync() before the synchronous reader when SUBC_LAUNCH_NONCE_PIPE is set");
13918
+ }
13919
+ this.cached = { ok: true, nonce: fallback };
13920
+ }
13749
13921
  if (this.cached === undefined)
13750
13922
  this.cached = this.read();
13751
13923
  return this.cached;
13752
13924
  }
13925
+ async resultAsync() {
13926
+ if (this.cached !== undefined)
13927
+ return this.cached;
13928
+ if (this.pending !== undefined)
13929
+ return this.pending;
13930
+ const named = this.platform === "win32" ? this.lookup(SUBC_LAUNCH_NONCE_PIPE_ENV) : undefined;
13931
+ if (named === undefined)
13932
+ return this.result();
13933
+ const fallback = this.permittedPipeFallback();
13934
+ this.pending = this.pipeReader(named).then((nonce) => ({ ok: true, nonce: fallback !== undefined && nonce.value !== fallback.value ? fallback : nonce }), (error) => {
13935
+ if (fallback !== undefined)
13936
+ return { ok: true, nonce: fallback };
13937
+ if (!isLaunchNonceError(error))
13938
+ throw error;
13939
+ return { ok: false, error };
13940
+ }).then((result) => {
13941
+ this.cached ??= result;
13942
+ return this.cached;
13943
+ });
13944
+ return this.pending;
13945
+ }
13946
+ permittedPipeFallback() {
13947
+ if (this.lookup(SUBC_LAUNCH_NONCE_PIPE_FALLBACK_ENV) !== "env")
13948
+ return;
13949
+ const value = this.lookup(SUBC_LAUNCH_NONCE_ENV);
13950
+ return value ? makeLaunchNonce(value, "env") : undefined;
13951
+ }
13952
+ async getAsync() {
13953
+ return unwrap(await this.resultAsync());
13954
+ }
13753
13955
  get() {
13754
13956
  return unwrap(this.result());
13755
13957
  }
@@ -13880,8 +14082,198 @@ function closeQuietly(fd) {
13880
14082
  closeSync5(fd);
13881
14083
  } catch {}
13882
14084
  }
14085
+ async function readLaunchNoncePipe(name, connector = (path) => connect(path), openWindowMs = 500, readWindowMs = 2000) {
14086
+ const deadline = Date.now() + openWindowMs;
14087
+ for (;; ) {
14088
+ try {
14089
+ const bytes = await pipeAttempt(name, connector, Math.max(1, deadline - Date.now()), readWindowMs);
14090
+ if (bytes.length === 0)
14091
+ throw new LaunchNonceError("PipeEmpty", "the launch nonce named pipe is empty");
14092
+ let value;
14093
+ try {
14094
+ value = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
14095
+ } catch {
14096
+ throw new LaunchNonceError("PipeNotUtf8", "the launch nonce named pipe held bytes that are not UTF-8");
14097
+ }
14098
+ return makeLaunchNonce(value, "pipe");
14099
+ } catch (error) {
14100
+ if (isLaunchNonceError(error))
14101
+ throw error;
14102
+ const busy = error?.code === "EBUSY" || errnoOf(error) === 231;
14103
+ if (!busy || Date.now() >= deadline) {
14104
+ throw new LaunchNonceError("PipeNotOpen", "SUBC_LAUNCH_NONCE_PIPE names a pipe that could not be opened", { errno: errnoOf(error) });
14105
+ }
14106
+ await new Promise((resolve) => setTimeout(resolve, Math.min(10, Math.max(1, deadline - Date.now()))));
14107
+ }
14108
+ }
14109
+ }
14110
+ function pipeAttempt(name, connector, openWindowMs, readWindowMs) {
14111
+ return new Promise((resolve, reject) => {
14112
+ let socket;
14113
+ try {
14114
+ socket = connector(name);
14115
+ } catch (error) {
14116
+ reject(error);
14117
+ return;
14118
+ }
14119
+ let connected = false;
14120
+ let settled = false;
14121
+ let size = 0;
14122
+ const chunks = [];
14123
+ let timer = setTimeout(() => finish(new LaunchNonceError("PipeNotOpen", "launch nonce pipe open timed out")), openWindowMs);
14124
+ function finish(error) {
14125
+ if (settled)
14126
+ return;
14127
+ settled = true;
14128
+ clearTimeout(timer);
14129
+ socket.destroy();
14130
+ if (error !== undefined)
14131
+ reject(error);
14132
+ else
14133
+ resolve(Buffer.concat(chunks));
14134
+ }
14135
+ socket.once("connect", () => {
14136
+ connected = true;
14137
+ clearTimeout(timer);
14138
+ timer = setTimeout(() => finish(new LaunchNonceError("PipeUnreadable", "launch nonce pipe read timed out")), readWindowMs);
14139
+ });
14140
+ socket.on("data", (chunk) => {
14141
+ size += chunk.length;
14142
+ if (size > 4096) {
14143
+ finish(new LaunchNonceError("PipeUnreadable", "launch nonce pipe exceeded its byte limit"));
14144
+ return;
14145
+ }
14146
+ chunks.push(Buffer.from(chunk));
14147
+ });
14148
+ socket.once("end", () => finish());
14149
+ socket.once("error", (error) => finish(connected ? new LaunchNonceError("PipeUnreadable", "could not read the launch nonce from the named pipe", { errno: errnoOf(error) }) : error));
14150
+ socket.once("close", () => {
14151
+ if (!settled)
14152
+ finish(new LaunchNonceError("PipeUnreadable", "launch nonce pipe closed before EOF"));
14153
+ });
14154
+ });
14155
+ }
14156
+
14157
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/request-gate.js
14158
+ class Lane {
14159
+ limit;
14160
+ used = 0;
14161
+ waiters = [];
14162
+ failure;
14163
+ constructor(limit) {
14164
+ this.limit = limit;
14165
+ }
14166
+ acquire(timeoutMs, signal) {
14167
+ if (this.failure)
14168
+ return Promise.reject(this.failure);
14169
+ if (signal?.aborted)
14170
+ return Promise.reject(new Error("request cancelled before write"));
14171
+ if (timeoutMs !== undefined && timeoutMs <= 0)
14172
+ return Promise.reject(new Error("request deadline elapsed waiting for a slot"));
14173
+ if (this.used < this.limit && this.waiters.length === 0) {
14174
+ this.used++;
14175
+ return Promise.resolve(this.releaser());
14176
+ }
14177
+ return new Promise((resolve, reject) => {
14178
+ let timer;
14179
+ const clean = () => {
14180
+ if (timer !== undefined)
14181
+ clearTimeout(timer);
14182
+ signal?.removeEventListener("abort", abort);
14183
+ };
14184
+ const waiter = {
14185
+ grant: () => {
14186
+ clean();
14187
+ resolve(this.releaser());
14188
+ },
14189
+ fail: (error) => {
14190
+ clean();
14191
+ reject(error);
14192
+ }
14193
+ };
14194
+ const abort = () => {
14195
+ const index = this.waiters.indexOf(waiter);
14196
+ if (index < 0)
14197
+ return;
14198
+ this.waiters.splice(index, 1);
14199
+ waiter.fail(new Error("request cancelled before write"));
14200
+ };
14201
+ this.waiters.push(waiter);
14202
+ signal?.addEventListener("abort", abort, { once: true });
14203
+ if (timeoutMs !== undefined)
14204
+ timer = setTimeout(() => {
14205
+ const index = this.waiters.indexOf(waiter);
14206
+ if (index < 0)
14207
+ return;
14208
+ this.waiters.splice(index, 1);
14209
+ waiter.fail(new Error("request deadline elapsed waiting for a slot"));
14210
+ }, timeoutMs);
14211
+ });
14212
+ }
14213
+ close(error) {
14214
+ this.failure = error;
14215
+ for (const waiter of this.waiters.splice(0))
14216
+ waiter.fail(error);
14217
+ }
14218
+ releaser() {
14219
+ let released = false;
14220
+ return () => {
14221
+ if (released)
14222
+ return;
14223
+ released = true;
14224
+ const waiter = this.waiters.shift();
14225
+ if (waiter)
14226
+ waiter.grant();
14227
+ else
14228
+ this.used--;
14229
+ };
14230
+ }
14231
+ }
13883
14232
 
13884
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/route-handle.js
14233
+ class RequestGate {
14234
+ total;
14235
+ watches;
14236
+ slots = new Set;
14237
+ closed = new AbortController;
14238
+ get signal() {
14239
+ return this.closed.signal;
14240
+ }
14241
+ constructor(requestWindow, watchWindow) {
14242
+ this.total = new Lane(requestWindow);
14243
+ if (watchWindow !== undefined)
14244
+ this.watches = new Lane(watchWindow);
14245
+ }
14246
+ async acquire(watch, timeoutMs, signal) {
14247
+ const deadline = timeoutMs === undefined ? undefined : Date.now() + timeoutMs;
14248
+ const watchRelease = watch && this.watches ? await this.watches.acquire(timeoutMs, signal) : undefined;
14249
+ try {
14250
+ const totalRelease = await this.total.acquire(deadline === undefined ? undefined : deadline - Date.now(), signal);
14251
+ const slot = {
14252
+ inFlight: false,
14253
+ release: () => {
14254
+ if (!this.slots.delete(slot))
14255
+ return;
14256
+ totalRelease();
14257
+ watchRelease?.();
14258
+ }
14259
+ };
14260
+ this.slots.add(slot);
14261
+ return slot;
14262
+ } catch (error) {
14263
+ watchRelease?.();
14264
+ throw error;
14265
+ }
14266
+ }
14267
+ close(error) {
14268
+ this.total.close(error);
14269
+ this.watches?.close(error);
14270
+ this.closed.abort(error);
14271
+ for (const slot of this.slots)
14272
+ slot.release();
14273
+ }
14274
+ }
14275
+
14276
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/route-handle.js
13885
14277
  var connectionToken = new WeakMap;
13886
14278
  var reverseRequests = new WeakMap;
13887
14279
 
@@ -13974,10 +14366,13 @@ function sameRouteHandle(left, right) {
13974
14366
  return left === right;
13975
14367
  }
13976
14368
 
13977
- // ../../node_modules/.bun/@cortexkit+subc-client@0.21.2/node_modules/@cortexkit/subc-client/dist/client.js
14369
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.24.5/node_modules/@cortexkit/subc-client/dist/client.js
13978
14370
  var debug = debuglog("subc-client");
13979
14371
  var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
13980
14372
  var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
14373
+ var DEFAULT_SLEEP_GRACE_MS = 15000;
14374
+ var SLEEP_DETECTION_THRESHOLD_MS = 2000;
14375
+ var MIN_REQUEST_BUDGET_MS = 1;
13981
14376
  var TIMEOUT_ARBITRATION_GRACE_MS = 50;
13982
14377
  var LIVENESS_PROBE_WINDOW_MS = 2000;
13983
14378
  var REQUEST_DEADLINE_MARKER = "request_deadline";
@@ -14013,6 +14408,14 @@ class SubcCallError extends Error {
14013
14408
  }
14014
14409
  }
14015
14410
 
14411
+ class DaemonUnavailableError extends SubcCallError {
14412
+ recovery = "user_action_required";
14413
+ constructor(cause) {
14414
+ super("not_sent", "CortexKit's daemon is not running or can't be reached on this computer, so this tool call was not sent. Retrying won't start it. Stop calling CortexKit tools and ask the user to start the daemon (run `ck setup`, or restart the CortexKit service), then try again after they confirm it is running.", errorCode(cause), cause);
14415
+ this.name = "DaemonUnavailableError";
14416
+ }
14417
+ }
14418
+
14016
14419
  class SubcError extends Error {
14017
14420
  code;
14018
14421
  detail;
@@ -14137,6 +14540,14 @@ class SubcClient {
14137
14540
  reconnecting = null;
14138
14541
  generation = 1;
14139
14542
  routeOpenGateInstance;
14543
+ requestGates;
14544
+ wireSlots;
14545
+ get gates() {
14546
+ return this.requestGates ??= new Map;
14547
+ }
14548
+ get slots() {
14549
+ return this.wireSlots ??= new Map;
14550
+ }
14140
14551
  readerActive = false;
14141
14552
  constructor(sock, currentConn, opts) {
14142
14553
  this.sock = sock;
@@ -14152,8 +14563,15 @@ class SubcClient {
14152
14563
  }
14153
14564
  static async connect(opts) {
14154
14565
  const normalized = normalizeConnectOptions(opts);
14155
- const opened = await SubcClient.openConnection(normalized);
14156
- return new SubcClient(opened.sock, opened.conn, normalized);
14566
+ try {
14567
+ const opened = await SubcClient.openConnection(normalized);
14568
+ return new SubcClient(opened.sock, opened.conn, normalized);
14569
+ } catch (err) {
14570
+ if (errorCode(err) === "ENOENT" || errorCode(err) === "ECONNREFUSED") {
14571
+ throw new DaemonUnavailableError(err);
14572
+ }
14573
+ throw err;
14574
+ }
14157
14575
  }
14158
14576
  async catalogList(moduleId) {
14159
14577
  const body = this.encode(moduleId === undefined ? { op: "catalog.list" } : { op: "catalog.list", module_id: moduleId });
@@ -14189,17 +14607,23 @@ class SubcClient {
14189
14607
  }
14190
14608
  async sendRouteOpen(target, identity, opts = {}) {
14191
14609
  const scope = validatedRouteScope(opts.scope);
14192
- const consumerIdentity = routeOpenConsumerIdentity(opts);
14610
+ const consumerIdentity = await routeOpenConsumerIdentity(opts);
14193
14611
  const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry;
14194
14612
  reverseRequests.seal();
14195
14613
  const consumerCapabilities = reverseRequests.capabilities();
14196
14614
  const body = this.encode({
14197
14615
  op: "route.open",
14616
+ busy_refusals: true,
14198
14617
  target,
14199
14618
  identity,
14200
14619
  ...consumerIdentity ? { consumer_identity: consumerIdentity } : {},
14201
14620
  ...consumerCapabilities.length > 0 ? { consumer_capabilities: consumerCapabilities } : {},
14202
- ...scope ? { scope: { owner: scope.owner, ref: scope.ref, scope_epoch: scope.scopeEpoch } } : {}
14621
+ ...scope ? { scope: {
14622
+ owner: scope.owner,
14623
+ ref: scope.ref,
14624
+ scope_epoch: scope.scopeEpoch,
14625
+ ...scope.bindProof !== undefined ? { bind_proof: scope.bindProof } : {}
14626
+ } } : {}
14203
14627
  });
14204
14628
  let installed = null;
14205
14629
  const install = (frame) => {
@@ -14210,6 +14634,8 @@ class SubcClient {
14210
14634
  throw new SubcError(`route.open returned no route handle: ${JSON.stringify(parsed)}`);
14211
14635
  }
14212
14636
  installed = this.installRoute(parsed.route_channel, parsed.route_epoch, reverseRequests);
14637
+ if (parsed.request_window !== undefined)
14638
+ this.gates.set(installed, new RequestGate(parsed.request_window, parsed.watch_window));
14213
14639
  this.routeModules.set(parsed.route_channel, target.module_id);
14214
14640
  return true;
14215
14641
  };
@@ -14239,7 +14665,7 @@ class SubcClient {
14239
14665
  const bytes = binary ? requireBinaryBody(body) : body instanceof Uint8Array ? body : this.encode(body);
14240
14666
  const priority = opts.priority ?? Priority.Interactive;
14241
14667
  const admission = opts.admissionClass ?? AdmissionClass.Normal;
14242
- const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, undefined, undefined, binary, opts.signal);
14668
+ const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, undefined, undefined, binary, opts.signal, validatedSleepGraceMs(opts.sleepGraceMs ?? this.opts.sleepGraceMs ?? DEFAULT_SLEEP_GRACE_MS));
14243
14669
  return this.decodeReply(reply);
14244
14670
  }
14245
14671
  async call(moduleId, method, params, opts = {}) {
@@ -14255,10 +14681,12 @@ class SubcClient {
14255
14681
  }
14256
14682
  async managedCall(moduleId, body, opts) {
14257
14683
  let retriedUnknownChannel = false;
14684
+ const startedAt = opts.timeoutMs === undefined ? undefined : this.opts.now();
14685
+ let attemptOpts = opts;
14258
14686
  for (;; ) {
14259
- const routeHandle = await this.cachedRouteHandle(moduleId, opts);
14687
+ const routeHandle = await this.cachedRouteHandle(moduleId, attemptOpts);
14260
14688
  try {
14261
- return await this.managedRequest(routeHandle, body, opts);
14689
+ return await this.managedRequest(routeHandle, body, attemptOpts);
14262
14690
  } catch (err) {
14263
14691
  if (!(err instanceof SubcCallError))
14264
14692
  throw this.terminalCallError("managed call failed", err);
@@ -14268,6 +14696,15 @@ class SubcClient {
14268
14696
  this.evictRouteHandle(routeHandle);
14269
14697
  continue;
14270
14698
  }
14699
+ if (isDataPlaneDrainRefusal(err.code) && !retriedUnknownChannel && !this.closeStarted && !opts.signal?.aborted) {
14700
+ const remainingMs = opts.timeoutMs === undefined || startedAt === undefined ? undefined : opts.timeoutMs - (this.opts.now() - startedAt);
14701
+ if (remainingMs === undefined || remainingMs > 0) {
14702
+ retriedUnknownChannel = true;
14703
+ this.evictRouteHandle(routeHandle);
14704
+ attemptOpts = remainingMs === undefined ? opts : { ...opts, timeoutMs: remainingMs };
14705
+ continue;
14706
+ }
14707
+ }
14271
14708
  if (deadBindCode && retriedUnknownChannel) {
14272
14709
  this.evictRouteHandle(routeHandle);
14273
14710
  }
@@ -14297,6 +14734,8 @@ class SubcClient {
14297
14734
  }
14298
14735
  subscribe(handle, body, onEvent, opts = {}) {
14299
14736
  this.assertLiveHandle(handle);
14737
+ if (this.gates.has(handle))
14738
+ return this.subscribeGated(handle, body, onEvent, opts);
14300
14739
  const bytes = body instanceof Uint8Array ? body : this.encode(body);
14301
14740
  const priority = opts.priority ?? Priority.Interactive;
14302
14741
  const admission = opts.admissionClass ?? AdmissionClass.Normal;
@@ -14304,22 +14743,43 @@ class SubcClient {
14304
14743
  const key = pendingKey(handle, corr);
14305
14744
  let subscriptionPending = null;
14306
14745
  let resolveClosed = null;
14746
+ let resolveEnded;
14747
+ const ended = new Promise((resolve) => {
14748
+ resolveEnded = resolve;
14749
+ });
14750
+ const endFailure = (err, frame) => {
14751
+ if (frame?.header.ty === FrameType.Error) {
14752
+ const error = err;
14753
+ resolveEnded({ kind: "error", code: error.code, message: error.message, detail: error.detail });
14754
+ } else if (err instanceof SubcError && err.closeReason && err.closeReason !== "connection_lost") {
14755
+ resolveEnded({ kind: "route_closed", reason: err.closeReason });
14756
+ } else {
14757
+ resolveEnded({ kind: "connection_lost" });
14758
+ }
14759
+ };
14307
14760
  const closed = new Promise((resolve, reject) => {
14308
14761
  if (this.closedErr) {
14762
+ endFailure(this.closedErr);
14309
14763
  reject(this.closedErr);
14310
14764
  return;
14311
14765
  }
14312
14766
  resolveClosed = resolve;
14313
14767
  subscriptionPending = {
14314
14768
  handle,
14315
- resolve: () => resolve(),
14316
- reject,
14769
+ resolve: (frame) => {
14770
+ resolveEnded(frame.header.ty === FrameType.Response ? { kind: "response", body: frame.body } : { kind: "stream_end" });
14771
+ resolve();
14772
+ },
14773
+ reject: (err, frame) => {
14774
+ endFailure(err, frame);
14775
+ reject(err);
14776
+ },
14317
14777
  onProgress: onEvent,
14318
14778
  timer: null,
14319
14779
  subscription: true
14320
14780
  };
14321
14781
  this.pending.set(key, subscriptionPending);
14322
- const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), handle.channel, handle.epoch, corr, bytes);
14782
+ const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission) | SUBSCRIPTION_FLAG, handle.channel, handle.epoch, corr, bytes);
14323
14783
  writeBorrowed(this.sock, encodeFrame(frame), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch((err) => {
14324
14784
  const pending = this.pending.get(key);
14325
14785
  if (pending)
@@ -14332,11 +14792,14 @@ class SubcClient {
14332
14792
  return;
14333
14793
  cancelled = true;
14334
14794
  if (subscriptionPending && resolveClosed)
14335
- this.settle(key, subscriptionPending, resolveClosed);
14795
+ this.settle(key, subscriptionPending, () => {
14796
+ resolveEnded({ kind: "cancelled" });
14797
+ resolveClosed?.();
14798
+ });
14336
14799
  if (this.isLiveHandle(handle))
14337
14800
  this.cancel(handle, corr, priority);
14338
14801
  };
14339
- return { unsubscribe, closed };
14802
+ return { unsubscribe, closed, ended };
14340
14803
  }
14341
14804
  attachCancelSignal(signal, key, handle, corr, priority) {
14342
14805
  if (!handle)
@@ -14402,7 +14865,7 @@ class SubcClient {
14402
14865
  this.sendRouteGoodbye(handle);
14403
14866
  }
14404
14867
  async closeManagedRoute(target, identity, opts = {}) {
14405
- const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts), (opts.reverseRequests ?? new ReverseRequestRegistry).capabilities(), validatedRouteScope(opts.scope));
14868
+ const key = routeCacheKey(target, identity, await routeOpenConsumerIdentity(opts), (opts.reverseRequests ?? new ReverseRequestRegistry).capabilities(), validatedRouteScope(opts.scope));
14406
14869
  const cached = this.routes.get(key);
14407
14870
  if (!cached)
14408
14871
  return;
@@ -14455,10 +14918,21 @@ class SubcClient {
14455
14918
  });
14456
14919
  }
14457
14920
  static async openConnection(opts) {
14458
- const conn = await readConnectionFile(opts.connectionFile);
14921
+ const conn = opts.transport === "local" ? await readConnectionFileWithLocalEndpoint(opts.connectionFile) : await readConnectionFile(opts.connectionFile);
14459
14922
  const deadline = Date.now() + (opts.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS);
14460
14923
  const endpoint = conn.endpoints[0];
14461
- const sock = await SubcSocket.connect(endpoint.host, endpoint.port, deadline);
14924
+ let sock;
14925
+ if (opts.transport === "local") {
14926
+ const local = conn.localEndpoint;
14927
+ if (!local)
14928
+ throw new SubcError("connection file has no local_endpoint", "local_endpoint_absent");
14929
+ if (local.kind === "unix" !== (process.platform !== "win32")) {
14930
+ throw new SubcError("unsupported local endpoint kind on this platform", "local_endpoint_unsupported");
14931
+ }
14932
+ sock = await SubcSocket.connectLocal(local.kind === "unix" ? local.path : local.name, deadline);
14933
+ } else {
14934
+ sock = await SubcSocket.connect(endpoint.host, endpoint.port, deadline);
14935
+ }
14462
14936
  try {
14463
14937
  await authenticateClient(sock, conn, deadline);
14464
14938
  } catch (err) {
@@ -14470,7 +14944,125 @@ class SubcClient {
14470
14944
  async controlRpc(body, acceptFrame, onLateResponse) {
14471
14945
  return this.send(null, body, Priority.Interactive, AdmissionClass.Normal, undefined, undefined, acceptFrame, onLateResponse);
14472
14946
  }
14473
- send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse, binary = false, signal) {
14947
+ send(...args) {
14948
+ const [handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse, binary, signal, sleepGraceMs] = args;
14949
+ if (!handle || !this.gates.has(handle))
14950
+ return this.sendAttempt(...args);
14951
+ return this.gatedRequest(handle, false, timeoutMs, signal, (slot, remaining) => this.sendAttempt(handle, body, priority, admission, remaining, onProgress, acceptFrame, onLateResponse, binary, signal, sleepGraceMs, slot));
14952
+ }
14953
+ async gatedRequest(handle, watch, timeoutMs, signal, attempt) {
14954
+ const gate = this.gates.get(handle);
14955
+ const deadline = this.opts.now() + (timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS);
14956
+ let slot;
14957
+ try {
14958
+ slot = await gate.acquire(watch, deadline - this.opts.now(), signal);
14959
+ } catch (error) {
14960
+ throw this.notSentCallError("request was not sent while waiting for a route slot", error);
14961
+ }
14962
+ let delay = 25;
14963
+ let busyDeadlineError;
14964
+ try {
14965
+ for (;; ) {
14966
+ if (gate.signal.aborted)
14967
+ throw gate.signal.reason;
14968
+ if (signal?.aborted)
14969
+ throw this.notSentCallError("request cancelled before write", signal.reason);
14970
+ this.assertLiveHandle(handle);
14971
+ const budget = deadline - this.opts.now();
14972
+ if (budget < MIN_REQUEST_BUDGET_MS)
14973
+ throw busyDeadlineError ?? this.notSentCallError("request deadline elapsed before write", new Error("less than 1ms remains before the request deadline"));
14974
+ try {
14975
+ return await attempt(slot, budget);
14976
+ } catch (error) {
14977
+ const refusal = error instanceof SubcError ? error : error instanceof SubcCallError && error.cause instanceof SubcError ? error.cause : undefined;
14978
+ if (!refusal || !isRouteBusyRetryable(errorFrameFlags.get(refusal) ?? 0, refusal.code, this.gates.get(handle) === gate))
14979
+ throw error;
14980
+ const exhausted = () => new SubcCallError("not_sent", `daemon refused before forwarding: ${refusal.message}`, "route_busy", refusal);
14981
+ busyDeadlineError = exhausted();
14982
+ const remaining = deadline - this.opts.now();
14983
+ if (remaining <= 0 || signal?.aborted)
14984
+ throw exhausted();
14985
+ const ms = Math.min(remaining, delay * (0.5 + this.opts.random() * 0.5));
14986
+ delay = Math.min(1000, delay * 2);
14987
+ const proceed = await this.busySleep(ms, gate.signal, signal);
14988
+ if (gate.signal.aborted)
14989
+ throw gate.signal.reason;
14990
+ if (!proceed || this.opts.now() >= deadline)
14991
+ throw exhausted();
14992
+ }
14993
+ }
14994
+ } finally {
14995
+ if (!slot.inFlight)
14996
+ slot.release();
14997
+ }
14998
+ }
14999
+ async busySleep(ms, closed, signal) {
15000
+ if (closed.aborted || signal?.aborted)
15001
+ return false;
15002
+ let abort;
15003
+ const cancelled = new Promise((resolve) => {
15004
+ abort = () => resolve(false);
15005
+ });
15006
+ closed.addEventListener("abort", abort, { once: true });
15007
+ signal?.addEventListener("abort", abort, { once: true });
15008
+ try {
15009
+ return await Promise.race([this.opts.sleep(ms).then(() => true), cancelled]);
15010
+ } finally {
15011
+ closed.removeEventListener("abort", abort);
15012
+ signal?.removeEventListener("abort", abort);
15013
+ }
15014
+ }
15015
+ subscribeGated(handle, body, onEvent, opts) {
15016
+ const bytes = body instanceof Uint8Array ? body : this.encode(body);
15017
+ const priority = opts.priority ?? Priority.Interactive;
15018
+ const admission = opts.admissionClass ?? AdmissionClass.Normal;
15019
+ const abort = new AbortController;
15020
+ let current;
15021
+ let cancelled = false;
15022
+ let resolveClosed;
15023
+ let rejectClosed;
15024
+ let resolveEnded;
15025
+ const closed = new Promise((resolve, reject) => {
15026
+ resolveClosed = resolve;
15027
+ rejectClosed = reject;
15028
+ });
15029
+ const ended = new Promise((resolve) => {
15030
+ resolveEnded = resolve;
15031
+ });
15032
+ this.gatedRequest(handle, true, undefined, abort.signal, (slot, remaining) => this.sendAttempt(handle, bytes, priority, admission, remaining, onEvent, undefined, undefined, false, undefined, undefined, slot, true, (key, pending, corr) => {
15033
+ current = { key, pending, corr };
15034
+ })).then((frame) => {
15035
+ if (cancelled)
15036
+ return;
15037
+ resolveEnded(frame.header.ty === FrameType.Response ? { kind: "response", body: frame.body } : { kind: "stream_end" });
15038
+ resolveClosed();
15039
+ }, (error) => {
15040
+ if (cancelled)
15041
+ return;
15042
+ if (error instanceof SubcError && error.closeReason)
15043
+ resolveEnded(error.closeReason === "connection_lost" ? { kind: "connection_lost" } : { kind: "route_closed", reason: error.closeReason });
15044
+ else if (error instanceof SubcError || error instanceof SubcCallError)
15045
+ resolveEnded({ kind: "error", code: error.code, message: error.message, detail: error.detail });
15046
+ else
15047
+ resolveEnded({ kind: "connection_lost" });
15048
+ rejectClosed(error);
15049
+ });
15050
+ return { closed, ended, unsubscribe: () => {
15051
+ if (cancelled)
15052
+ return;
15053
+ cancelled = true;
15054
+ abort.abort();
15055
+ if (current && this.pending.get(current.key) === current.pending) {
15056
+ const { key, pending, corr } = current;
15057
+ this.settle(key, pending, () => pending.reject(new SubcError("subscription cancelled")));
15058
+ if (this.isLiveHandle(handle))
15059
+ this.cancel(handle, corr, priority);
15060
+ }
15061
+ resolveEnded({ kind: "cancelled" });
15062
+ resolveClosed();
15063
+ } };
15064
+ }
15065
+ sendAttempt(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse, binary = false, signal, sleepGraceMs = this.opts.sleepGraceMs ?? DEFAULT_SLEEP_GRACE_MS, slot, subscription = false, registered) {
14474
15066
  if (handle)
14475
15067
  this.assertLiveHandle(handle);
14476
15068
  if (this.closedErr)
@@ -14484,7 +15076,7 @@ class SubcClient {
14484
15076
  const key = pendingKey(handle, corr);
14485
15077
  const channel = handle?.channel ?? 0;
14486
15078
  const epoch = handle?.epoch ?? 0;
14487
- const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission), channel, epoch, corr, body);
15079
+ const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission) | (subscription ? SUBSCRIPTION_FLAG : 0), channel, epoch, corr, body);
14488
15080
  return new Promise((resolve, reject) => {
14489
15081
  const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
14490
15082
  const pending = {
@@ -14494,11 +15086,27 @@ class SubcClient {
14494
15086
  onProgress,
14495
15087
  timer: null,
14496
15088
  acceptFrame,
14497
- onLateResponse
15089
+ onLateResponse,
15090
+ slot,
15091
+ subscription
14498
15092
  };
14499
- pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
15093
+ if (!subscription)
15094
+ this.armRequestTimeout(key, pending, channel, corr, ms, sleepGraceMs);
14500
15095
  this.pending.set(key, pending);
14501
- writeBorrowed(this.sock, encodeFrame(frame), Date.now() + ms).catch((error) => {
15096
+ registered?.(key, pending, corr);
15097
+ if (slot && handle) {
15098
+ slot.inFlight = true;
15099
+ this.slots.set(key, { handle, slot });
15100
+ }
15101
+ const write = writeTrackedBorrowed(this.sock, encodeFrame(frame), Date.now() + ms);
15102
+ if (slot && !write.queued) {
15103
+ this.slots.delete(key);
15104
+ slot.inFlight = false;
15105
+ slot.release();
15106
+ }
15107
+ write.completed.catch((error) => {
15108
+ if (error instanceof SocketWriteNotQueuedError || error instanceof SocketWriteQueuedError)
15109
+ error = error.cause ?? error;
14502
15110
  const current = this.pending.get(key);
14503
15111
  if (current)
14504
15112
  this.rejectPending(key, current, error instanceof Error ? error : new SubcError(String(error)));
@@ -14507,10 +15115,16 @@ class SubcClient {
14507
15115
  this.attachCancelSignal(signal, key, handle, corr, priority);
14508
15116
  });
14509
15117
  }
15118
+ armRequestTimeout(key, pending, channel, corr, ms, sleepGraceMs) {
15119
+ pending.sleepGrace = { wallStartMs: Date.now(), awakeStartMs: performance.now(), ms: sleepGraceMs, used: false };
15120
+ pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
15121
+ }
14510
15122
  arbitrateTimeout(key, pending, channel, corr, ms) {
14511
15123
  const settleAsTimeout = () => {
14512
15124
  if (pending.onLateResponse)
14513
15125
  this.lateResponses.set(key, pending.onLateResponse);
15126
+ if (pending.slot?.inFlight && pending.handle && this.isLiveHandle(pending.handle))
15127
+ this.cancel(pending.handle, corr);
14514
15128
  this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms), REQUEST_DEADLINE_MARKER));
14515
15129
  };
14516
15130
  const graceDeadline = Date.now() + this.opts.timeoutArbitrationGraceMs;
@@ -14522,6 +15136,17 @@ class SubcClient {
14522
15136
  setImmediate(arbitrate);
14523
15137
  return;
14524
15138
  }
15139
+ const sleep = pending.sleepGrace;
15140
+ if (sleep && !sleep.used && sleep.ms > 0) {
15141
+ const wallElapsed = Date.now() - sleep.wallStartMs;
15142
+ const awakeElapsed = performance.now() - sleep.awakeStartMs;
15143
+ const sleptMs = wallElapsed - awakeElapsed;
15144
+ if (sleptMs > SLEEP_DETECTION_THRESHOLD_MS) {
15145
+ sleep.used = true;
15146
+ pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), sleep.ms);
15147
+ return;
15148
+ }
15149
+ }
14525
15150
  settleAsTimeout();
14526
15151
  };
14527
15152
  setImmediate(arbitrate);
@@ -14532,7 +15157,7 @@ class SubcClient {
14532
15157
  const priority = opts.priority ?? Priority.Interactive;
14533
15158
  const admission = opts.admissionClass ?? AdmissionClass.Normal;
14534
15159
  try {
14535
- const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, binary, opts.signal);
15160
+ const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, binary, opts.signal, validatedSleepGraceMs(opts.sleepGraceMs ?? this.opts.sleepGraceMs ?? DEFAULT_SLEEP_GRACE_MS));
14536
15161
  return this.decodeReply(reply);
14537
15162
  } catch (error) {
14538
15163
  if (error instanceof SubcCallError)
@@ -14540,7 +15165,13 @@ class SubcClient {
14540
15165
  throw this.terminalCallError("managed call failed", error);
14541
15166
  }
14542
15167
  }
14543
- sendManaged(handle, body, priority, admission, timeoutMs, onProgress, binary = false, signal) {
15168
+ sendManaged(...args) {
15169
+ const [handle, body, priority, admission, timeoutMs, onProgress, binary, signal, sleepGraceMs] = args;
15170
+ if (!this.gates.has(handle))
15171
+ return this.sendManagedAttempt(...args);
15172
+ return this.gatedRequest(handle, false, timeoutMs, signal, (slot, remaining) => this.sendManagedAttempt(handle, body, priority, admission, remaining, onProgress, binary, signal, sleepGraceMs, slot));
15173
+ }
15174
+ sendManagedAttempt(handle, body, priority, admission, timeoutMs, onProgress, binary = false, signal, sleepGraceMs = this.opts.sleepGraceMs ?? DEFAULT_SLEEP_GRACE_MS, slot) {
14544
15175
  try {
14545
15176
  this.assertLiveHandle(handle);
14546
15177
  } catch (error) {
@@ -14574,12 +15205,22 @@ class SubcClient {
14574
15205
  reject,
14575
15206
  onProgress,
14576
15207
  timer: null,
14577
- classifyFailure
15208
+ classifyFailure,
15209
+ slot
14578
15210
  };
14579
- pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, handle.channel, corr, ms), ms);
15211
+ this.armRequestTimeout(key, pending, handle.channel, corr, ms, sleepGraceMs);
14580
15212
  this.pending.set(key, pending);
15213
+ if (slot) {
15214
+ slot.inFlight = true;
15215
+ this.slots.set(key, { handle, slot });
15216
+ }
14581
15217
  const write = writeTrackedBorrowed(this.sock, encodeFrame(frame), Date.now() + ms);
14582
15218
  handedToSocket = write.queued;
15219
+ if (slot && !write.queued) {
15220
+ this.slots.delete(key);
15221
+ slot.inFlight = false;
15222
+ slot.release();
15223
+ }
14583
15224
  write.completed.catch((error) => {
14584
15225
  const current = this.pending.get(key);
14585
15226
  if (current)
@@ -14596,7 +15237,7 @@ class SubcClient {
14596
15237
  throw new SubcCallError("terminal", "managed call requires a BindIdentity in SubcClient.connect({ identity }) or call(..., { identity })", "missing_identity");
14597
15238
  }
14598
15239
  const target = { kind: opts.targetKind ?? this.opts.targetKind, module_id: moduleId };
14599
- const consumerIdentity = routeOpenConsumerIdentity(opts);
15240
+ const consumerIdentity = await routeOpenConsumerIdentity(opts);
14600
15241
  const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry;
14601
15242
  reverseRequests.seal();
14602
15243
  const key = routeCacheKey(target, identity, consumerIdentity, reverseRequests.capabilities(), scope);
@@ -14681,6 +15322,7 @@ class SubcClient {
14681
15322
  if ("handle" in outcome) {
14682
15323
  const { handle } = outcome;
14683
15324
  if (cached.closed) {
15325
+ this.failHandle(handle, new SubcError("route closed during route.open", "route_closed", undefined, "closed_by_caller"));
14684
15326
  this.liveRoutes.delete(handle.channel);
14685
15327
  this.sendRouteGoodbye(handle);
14686
15328
  throw this.routeClosedDuringOpen();
@@ -14804,6 +15446,9 @@ class SubcClient {
14804
15446
  return;
14805
15447
  } catch (err) {
14806
15448
  if (!isConsumerReconnectTransient(err) || attempt >= this.opts.reconnectBackoff.maxAttempts) {
15449
+ if (isConsumerReconnectTransient(err) && !(err instanceof AuthError)) {
15450
+ throw new DaemonUnavailableError(err);
15451
+ }
14807
15452
  if (err instanceof AuthError && attempt > 1) {
14808
15453
  throw new AuthError(`reconnect gave up after ${attempt} attempts: ${err.message} — the connection file and the daemon's key disagree persistently ` + `(daemon restarting in a loop, split connection-file paths, or a genuinely foreign daemon on this port); ` + `check the daemon, then restart this host app`);
14809
15454
  }
@@ -14926,6 +15571,16 @@ class SubcClient {
14926
15571
  }
14927
15572
  const key = pendingKey(handle, frame.header.corr);
14928
15573
  const pending = this.pending.get(key);
15574
+ if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error || frame.header.ty === FrameType.StreamEnd) {
15575
+ const record = this.slots.get(key);
15576
+ if (record) {
15577
+ this.slots.delete(key);
15578
+ record.slot.inFlight = false;
15579
+ const busy = frame.header.ty === FrameType.Error && pending?.slot === record.slot && isRouteBusyRetryable(frame.header.flags, this.errorFromFrame(frame).code, !!handle && this.gates.has(handle));
15580
+ if (!busy)
15581
+ record.slot.release();
15582
+ }
15583
+ }
14929
15584
  if (pending) {
14930
15585
  if (pending.acceptFrame && !pending.acceptFrame(frame))
14931
15586
  return;
@@ -14941,7 +15596,7 @@ class SubcClient {
14941
15596
  this.settle(key, pending, () => pending.resolve(frame));
14942
15597
  return;
14943
15598
  case FrameType.Error:
14944
- this.settle(key, pending, () => pending.reject(this.errorFromFrame(frame)));
15599
+ this.settle(key, pending, () => pending.reject(this.errorFromFrame(frame), frame));
14945
15600
  return;
14946
15601
  default:
14947
15602
  return;
@@ -15078,6 +15733,14 @@ class SubcClient {
15078
15733
  return this.legacyChannelReasons.get(channel) ?? "unknown";
15079
15734
  }
15080
15735
  failHandle(handle, error) {
15736
+ this.gates.get(handle)?.close(error);
15737
+ this.gates.delete(handle);
15738
+ for (const [key, record] of this.slots) {
15739
+ if (sameRouteHandle(record.handle, handle)) {
15740
+ record.slot.release();
15741
+ this.slots.delete(key);
15742
+ }
15743
+ }
15081
15744
  for (const [key, pending] of this.pending) {
15082
15745
  if (pending.handle && sameRouteHandle(pending.handle, handle))
15083
15746
  this.rejectPending(key, pending, error);
@@ -15087,6 +15750,10 @@ class SubcClient {
15087
15750
  const routeError = err instanceof SubcError && err.closeReason ? err : new SubcError(err.message, errorCode(err), undefined, this.closeStarted ? "closed_by_caller" : "connection_lost");
15088
15751
  if (!this.closedErr)
15089
15752
  this.closedErr = err;
15753
+ for (const gate of this.gates.values())
15754
+ gate.close(routeError);
15755
+ this.gates.clear();
15756
+ this.slots.clear();
15090
15757
  this.routeEndReasons.clear();
15091
15758
  this.legacyChannelReasons.clear();
15092
15759
  this.routeModules.clear();
@@ -15120,6 +15787,9 @@ class SubcClient {
15120
15787
  return this.ingressEpochDropCount;
15121
15788
  }
15122
15789
  installRoute(channel, epoch, reverseRequests = new ReverseRequestRegistry) {
15790
+ const previous = this.liveRoutes.get(channel);
15791
+ if (previous && this.gates.has(previous))
15792
+ this.failHandle(previous, new SubcError("route replaced", "route_closed", undefined, "closed_by_caller"));
15123
15793
  const handle = createRouteHandle(channel, epoch, this.connectionToken, reverseRequests);
15124
15794
  this.routeEndReasons.delete(channel);
15125
15795
  this.legacyChannelReasons.delete(channel);
@@ -15190,9 +15860,15 @@ function isRetryableRouteOpenCode(code) {
15190
15860
  return false;
15191
15861
  if (code === "target_flow_unsupported")
15192
15862
  return false;
15863
+ if (code === "target_federated_unsupported")
15864
+ return false;
15193
15865
  if (code === "target_agent_run_unsupported")
15194
15866
  return false;
15195
- return code === "module_reloading" || code === "module_warming" || code === "target_unavailable" || code === "module_timeout" || code === "scope_not_synced" || code === "scope_changed";
15867
+ if (code === "scope_bind_proof_required" || code === "scope_bind_proof_mismatch")
15868
+ return false;
15869
+ if (code === "scope_epoch_in_use")
15870
+ return false;
15871
+ return code === "module_reloading" || code === "module_warming" || code === "target_unavailable" || code === "module_timeout" || code === "scope_not_synced" || code === "scope_changed" || code === "session_address_unavailable" || code === "bind_busy";
15196
15872
  }
15197
15873
  function equalJitter(delayMs, random) {
15198
15874
  const half = delayMs / 2;
@@ -15229,6 +15905,12 @@ var STALE_ROUTE_EPOCH = "stale_route_epoch";
15229
15905
  function isEstablishedRouteDead(_flags, code) {
15230
15906
  return code === UNKNOWN_CHANNEL || code === STALE_ROUTE_EPOCH;
15231
15907
  }
15908
+ function isRouteBusyRetryable(flags, code, routeOptedIn) {
15909
+ return routeOptedIn && (flags & DAEMON_ORIGIN_FLAG) !== 0 && code === "route_busy";
15910
+ }
15911
+ function isDataPlaneDrainRefusal(code) {
15912
+ return code === "module_reloading";
15913
+ }
15232
15914
  async function connectionFileExists(path) {
15233
15915
  try {
15234
15916
  await fs3.access(path);
@@ -15240,6 +15922,7 @@ async function connectionFileExists(path) {
15240
15922
  function normalizeConnectOptions(opts) {
15241
15923
  return {
15242
15924
  connectionFile: opts.connectionFile,
15925
+ transport: opts.transport ?? "tcp",
15243
15926
  handshakeTimeoutMs: opts.handshakeTimeoutMs,
15244
15927
  identity: opts.identity,
15245
15928
  targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
@@ -15249,11 +15932,18 @@ function normalizeConnectOptions(opts) {
15249
15932
  random: opts.random ?? Math.random,
15250
15933
  routeOpenRetryDeadlineMs: opts.routeOpenRetryDeadlineMs ?? ROUTE_OPEN_RETRY_DEADLINE_MS,
15251
15934
  timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS,
15935
+ sleepGraceMs: validatedSleepGraceMs(opts.sleepGraceMs ?? DEFAULT_SLEEP_GRACE_MS),
15252
15936
  bodyReadTimeoutMs: opts.bodyReadTimeoutMs,
15253
15937
  livenessProbeWindowMs: opts.livenessProbeWindowMs ?? LIVENESS_PROBE_WINDOW_MS,
15254
15938
  onControlPush: opts.onControlPush
15255
15939
  };
15256
15940
  }
15941
+ function validatedSleepGraceMs(ms) {
15942
+ if (!Number.isFinite(ms) || ms < 0 || ms > 2147483647) {
15943
+ throw new RangeError("sleepGraceMs must be finite and in 0..2147483647 milliseconds");
15944
+ }
15945
+ return ms;
15946
+ }
15257
15947
  function isValidCapabilityIdentifier(identifier) {
15258
15948
  if (/\s/u.test(identifier))
15259
15949
  return false;
@@ -15276,7 +15966,13 @@ function isValidCapabilityIdentifier(identifier) {
15276
15966
  function routeCacheKey(target, identity, consumerIdentity, consumerCapabilities, scope) {
15277
15967
  const consumerPart = consumerIdentity ? `${consumerIdentity.module_id}\x00${consumerIdentity.launch_nonce}` : "";
15278
15968
  const capabilitiesPart = [...consumerCapabilities].sort().join("\x00");
15279
- const scopePart = scope ? JSON.stringify([scope.owner.kind, scope.owner.kind === "reserved" ? scope.owner.module_id : null, scope.ref, scope.scopeEpoch]) : "";
15969
+ const scopePart = scope ? JSON.stringify([
15970
+ scope.owner.kind,
15971
+ scope.owner.kind === "reserved" ? scope.owner.module_id : null,
15972
+ scope.ref,
15973
+ scope.scopeEpoch,
15974
+ scope.bindProof === undefined ? null : createHash4("sha256").update(scope.bindProof).digest("hex")
15975
+ ]) : "";
15280
15976
  return `${target.kind}\x00${target.module_id}\x00${identity.project_root}\x00${identity.harness}\x00${identity.session}\x00${consumerPart}\x00${capabilitiesPart}\x00${scopePart}`;
15281
15977
  }
15282
15978
  function validatedRouteScope(scope) {
@@ -15294,13 +15990,18 @@ function validatedRouteScope(scope) {
15294
15990
  if (!Number.isSafeInteger(scope.scopeEpoch) || scope.scopeEpoch < 0) {
15295
15991
  throw new SubcError("scope.scopeEpoch must be a safe non-negative integer", "invalid_scope");
15296
15992
  }
15297
- return { owner: { ...scope.owner }, ref: scope.ref, scopeEpoch: scope.scopeEpoch };
15993
+ return {
15994
+ owner: { ...scope.owner },
15995
+ ref: scope.ref,
15996
+ scopeEpoch: scope.scopeEpoch,
15997
+ ...scope.bindProof !== undefined ? { bindProof: scope.bindProof } : {}
15998
+ };
15298
15999
  }
15299
- function routeOpenConsumerIdentity(opts = {}) {
16000
+ async function routeOpenConsumerIdentity(opts = {}) {
15300
16001
  if (opts.consumerIdentity !== undefined)
15301
16002
  return opts.consumerIdentity ?? undefined;
15302
16003
  const moduleId = process.env[SUBC_MODULE_ID_ENV];
15303
- const launchNonce = launchNonceOrUndefined()?.value;
16004
+ const launchNonce = (await launchNonceOrUndefinedAsync())?.value;
15304
16005
  if (!moduleId || !launchNonce)
15305
16006
  return;
15306
16007
  return { module_id: moduleId, launch_nonce: launchNonce };
@@ -15753,19 +16454,19 @@ function getLifecycleRegistry() {
15753
16454
 
15754
16455
  // ../aft-bridge/dist/project-identity.js
15755
16456
  import { realpathSync as realpathSync3 } from "node:fs";
15756
- import { posix as posix2, resolve as resolve7, win32 as win322 } from "node:path";
16457
+ import { posix as posix3, resolve as resolve6, win32 as win323 } from "node:path";
15757
16458
  function canonicalizeProjectRoot(dir) {
15758
16459
  const trimmed = trimProjectRootSeparators(dir);
15759
16460
  let canonical;
15760
16461
  try {
15761
16462
  canonical = realpathSync3(trimmed);
15762
16463
  } catch {
15763
- canonical = resolve7(trimmed);
16464
+ canonical = resolve6(trimmed);
15764
16465
  }
15765
16466
  return normalizeWindowsRoot(canonical);
15766
16467
  }
15767
16468
  function trimProjectRootSeparators(dir, platform = process.platform) {
15768
- const root = (platform === "win32" ? win322 : posix2).parse(dir).root;
16469
+ const root = (platform === "win32" ? win323 : posix3).parse(dir).root;
15769
16470
  const trimmed = dir.replace(/[/\\]+$/, "");
15770
16471
  return trimmed.length < root.length ? root : trimmed;
15771
16472
  }
@@ -16564,6 +17265,8 @@ class SubcTransportPool {
16564
17265
  harness;
16565
17266
  connectionFile;
16566
17267
  handshakeTimeoutMs;
17268
+ clock;
17269
+ waitClock;
16567
17270
  consumerIdentity;
16568
17271
  hostScopes;
16569
17272
  hostScopeCache = new Map;
@@ -16606,6 +17309,13 @@ class SubcTransportPool {
16606
17309
  editSlotSurvives;
16607
17310
  editSlotSurvivesCaptured = false;
16608
17311
  constructor(options) {
17312
+ this.clock = options.clock ?? {
17313
+ now: () => Date.now(),
17314
+ awakeNow: () => performance.now(),
17315
+ setTimeout: (callback, ms) => setTimeout(callback, ms),
17316
+ clearTimeout: (timer) => clearTimeout(timer)
17317
+ };
17318
+ this.waitClock = new WaitClock(() => this.clock.now(), () => this.clock.awakeNow?.() ?? this.clock.now());
16609
17319
  this.connectionFile = options.connectionFile;
16610
17320
  this.harness = options.harness;
16611
17321
  this.handshakeTimeoutMs = options.handshakeTimeoutMs;
@@ -17232,11 +17942,12 @@ class SubcTransportPool {
17232
17942
  this.stopUnusedHostScopeRetry(record.identity.session);
17233
17943
  }
17234
17944
  async routeRequest(identity, body, timeoutMs, onProgress, expectedGeneration, abortSignal) {
17235
- const callStartedAt = performance.now();
17945
+ const callStartedAt = this.waitClock.now();
17236
17946
  const callDeadlineMs = timeoutMs ?? SUBC_DEFAULT_REQUEST_TIMEOUT_MS;
17947
+ const deadline = new RequestDeadline(this.waitClock, callDeadlineMs);
17237
17948
  let scheduledDelayMs = 0;
17238
- const spentMs = () => Math.max(performance.now() - callStartedAt, scheduledDelayMs);
17239
- const remainingMs = () => callDeadlineMs - spentMs();
17949
+ const spentMs = () => Math.max(this.waitClock.now() - callStartedAt, scheduledDelayMs);
17950
+ const remainingMs = () => deadline.remaining() - Math.max(0, scheduledDelayMs - (this.waitClock.now() - callStartedAt));
17240
17951
  const root = asCanonicalRootPath(identity.project_root);
17241
17952
  let generation = expectedGeneration;
17242
17953
  if (this.lifecycleEnabled()) {
@@ -17257,12 +17968,12 @@ class SubcTransportPool {
17257
17968
  const remaining = remainingMs();
17258
17969
  if (remaining <= 0)
17259
17970
  throw keyChanged ?? callDeadlinePassedError(undefined, callDeadlineMs);
17260
- let timer;
17971
+ let cancelTimer;
17261
17972
  try {
17262
17973
  const acquired = await Promise.race([
17263
17974
  this.ensureClient(),
17264
17975
  new Promise((resolve) => {
17265
- timer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), remaining);
17976
+ cancelTimer = deadlineTimer(this.clock, remainingMs, () => resolve(CALL_DEADLINE_EXPIRED));
17266
17977
  })
17267
17978
  ]);
17268
17979
  if (acquired === CALL_DEADLINE_EXPIRED) {
@@ -17277,22 +17988,22 @@ class SubcTransportPool {
17277
17988
  if (spentMs() + this.nextRouteReopenDelayMs() >= callDeadlineMs)
17278
17989
  throw error;
17279
17990
  } finally {
17280
- clearTimeout(timer);
17991
+ cancelTimer?.();
17281
17992
  }
17282
17993
  const { delayMs, wait } = this.waitForRouteReopenBackoff();
17283
17994
  scheduledDelayMs = spentMs() + delayMs;
17284
- let retryTimer;
17995
+ let cancelRetryTimer;
17285
17996
  try {
17286
17997
  const waited = await Promise.race([
17287
17998
  wait,
17288
17999
  new Promise((resolve) => {
17289
- retryTimer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), callDeadlineMs - (performance.now() - callStartedAt));
18000
+ cancelRetryTimer = deadlineTimer(this.clock, remainingMs, () => resolve(CALL_DEADLINE_EXPIRED));
17290
18001
  })
17291
18002
  ]);
17292
18003
  if (waited === CALL_DEADLINE_EXPIRED)
17293
18004
  throw keyChanged;
17294
18005
  } finally {
17295
- clearTimeout(retryTimer);
18006
+ cancelRetryTimer?.();
17296
18007
  }
17297
18008
  }
17298
18009
  this.assertRecordLive(record);
@@ -17335,9 +18046,9 @@ class SubcTransportPool {
17335
18046
  const remaining = remainingMs();
17336
18047
  if (remaining <= 0)
17337
18048
  throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
17338
- let timer;
18049
+ let cancelTimer;
17339
18050
  const expired = new Promise((resolve) => {
17340
- timer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), remaining);
18051
+ cancelTimer = deadlineTimer(this.clock, remainingMs, () => resolve(CALL_DEADLINE_EXPIRED));
17341
18052
  });
17342
18053
  try {
17343
18054
  const opened = await Promise.race([openRoute(), expired]);
@@ -17346,7 +18057,7 @@ class SubcTransportPool {
17346
18057
  }
17347
18058
  return opened;
17348
18059
  } finally {
17349
- clearTimeout(timer);
18060
+ cancelTimer?.();
17350
18061
  }
17351
18062
  };
17352
18063
  const openRouteAfterReloadWindow = async () => {
@@ -17425,6 +18136,7 @@ class SubcTransportPool {
17425
18136
  try {
17426
18137
  request = client.request(route, body, {
17427
18138
  timeoutMs: Math.ceil(requestTimeoutMs),
18139
+ ...deadline.resumed ? { sleepGraceMs: 0 } : {},
17428
18140
  onProgress
17429
18141
  });
17430
18142
  } catch (error) {
@@ -17552,6 +18264,7 @@ class SubcTransportPool {
17552
18264
  this.connecting = this.connectFn({
17553
18265
  connectionFile: this.connectionFile,
17554
18266
  handshakeTimeoutMs: this.handshakeTimeoutMs,
18267
+ sleepGraceMs: RESUME_ALLOWANCE_MS,
17555
18268
  onControlPush: (push) => {
17556
18269
  if (owner && this.client === owner)
17557
18270
  this.onScopeRouteClose(push);
@@ -18553,7 +19266,7 @@ function taskIdFromError(error) {
18553
19266
  return;
18554
19267
  }
18555
19268
  // ../aft-bridge/dist/feature-config.js
18556
- import { createHash as createHash4 } from "node:crypto";
19269
+ import { createHash as createHash5 } from "node:crypto";
18557
19270
  import { createRequire } from "node:module";
18558
19271
  var CANONICAL_TOOLS = [
18559
19272
  "aft_callgraph",
@@ -18614,12 +19327,7 @@ var RETIRED_IDLE_CHECKOUT_HOURS = [
18614
19327
  "idle.checkout_hours"
18615
19328
  ];
18616
19329
  var DATA_LAYER_KEYS_REFUSED_FROM = [0, 65];
18617
- var DATA_LAYER_RETIRED_PATHS = [
18618
- "views.callgraph_copies",
18619
- "views.enabled",
18620
- "views.idle_checkout_hours",
18621
- "worktree.ram_overlay"
18622
- ];
19330
+ var DATA_LAYER_RETIRED_PATHS = ["views.idle_checkout_hours"];
18623
19331
  var IDLE_CHECKOUT_HOURS_DEFAULT = 168;
18624
19332
  var IDLE_CHECKOUT_HOURS_MIN = 1;
18625
19333
  var IDLE_CHECKOUT_HOURS_MAX = 24 * 365;
@@ -18646,7 +19354,10 @@ function readRunningRelease() {
18646
19354
  return [0, 0];
18647
19355
  }
18648
19356
  var runningRelease;
19357
+ var runningReleaseOverrideForTest;
18649
19358
  function getRunningRelease() {
19359
+ if (runningReleaseOverrideForTest)
19360
+ return runningReleaseOverrideForTest;
18650
19361
  runningRelease ??= readRunningRelease();
18651
19362
  return runningRelease;
18652
19363
  }
@@ -18675,7 +19386,7 @@ function removedBlockKeyErrors(value, release, refuseRetired) {
18675
19386
  const paths = REMOVED_OPENCODE_PATHS.filter((path) => hasPath(value, path));
18676
19387
  if (refuseRetired)
18677
19388
  paths.push(...refusedRetiredNames(value));
18678
- if (releaseAtLeast(release, DATA_LAYER_KEYS_REFUSED_FROM))
19389
+ if (refuseRetired && releaseAtLeast(release, DATA_LAYER_KEYS_REFUSED_FROM))
18679
19390
  paths.push(...DATA_LAYER_RETIRED_PATHS.filter((path) => hasPath(value, path)));
18680
19391
  return paths.map((path) => `removed_config_key:${path}; run npx @cortexkit/aft doctor --fix`);
18681
19392
  }
@@ -18699,7 +19410,10 @@ var REFUSED_RETIRED_PATHS = [
18699
19410
  "experimental.bash",
18700
19411
  "idle.lsp_ttl_minutes",
18701
19412
  "inspect.tier2_soft_deadline_ms",
18702
- "inspect.max_drill_down_items"
19413
+ "inspect.max_drill_down_items",
19414
+ "views.callgraph_copies",
19415
+ "views.enabled",
19416
+ "worktree.ram_overlay"
18703
19417
  ];
18704
19418
  function refusedRetiredNames(block) {
18705
19419
  const names = REFUSED_RETIRED_PATHS.filter((path) => hasPath(block, path));
@@ -18897,8 +19611,9 @@ function translateDataLayerPaths(map, prefix, out) {
18897
19611
  }
18898
19612
  }
18899
19613
  for (const path of REMOVED_DATA_LAYER_PATHS) {
18900
- if (hasPath(map, path))
18901
- out.removedKeys.push(`${prefix}${path}`);
19614
+ const [container, leaf] = path.split(".");
19615
+ if (container && leaf && takeNested(map, container, leaf).found)
19616
+ recordRetired(out, prefix, path);
18902
19617
  }
18903
19618
  }
18904
19619
  function translateExperimentalPaths(map, prefix, out) {
@@ -19148,7 +19863,7 @@ var NO_EFFECT_RETIRED_NOTES = [
19148
19863
  ]
19149
19864
  ];
19150
19865
  function noEffectNote(key) {
19151
- return NO_EFFECT_RETIRED_NOTES.find(([path]) => namesPath(key, path))?.[1];
19866
+ return [...NO_EFFECT_RETIRED_NOTES, ...REMOVED_DATA_LAYER_NOTES].find(([path]) => namesPath(key, path))?.[1];
19152
19867
  }
19153
19868
  function namesPath(key, path) {
19154
19869
  return key === path || key.endsWith(`.${path}`);
@@ -19169,26 +19884,7 @@ var REMOVED_DATA_LAYER_NOTES = [
19169
19884
  ];
19170
19885
  function retiredIdleCheckoutHoursNote() {
19171
19886
  const [retired, replacement] = RETIRED_IDLE_CHECKOUT_HOURS;
19172
- return `${retired} is now ${replacement}; from ${refusedFromVersion()} AFT refuses a config file that still sets ${retired}.`;
19173
- }
19174
- function removedConfigKeysNoticeMessage(configPath, translation) {
19175
- const removed = translation.removedKeys ?? [];
19176
- if (removed.length === 0)
19177
- return "";
19178
- const parts = [
19179
- `${configPath} sets removed keys (${removed.join(", ")}); AFT ignores them, and from ${refusedFromVersion()} it refuses a config file that sets them. Run \`npx @cortexkit/aft doctor --fix\` to remove them.`
19180
- ];
19181
- for (const [path, note] of REMOVED_DATA_LAYER_NOTES) {
19182
- if (removed.some((key) => namesPath(key, path)))
19183
- parts.push(note);
19184
- }
19185
- return parts.join(" ");
19186
- }
19187
- function removedConfigKeysNoticeDigest(translation) {
19188
- return noticeDigest({
19189
- notice: "removed_data_layer_keys_v1",
19190
- keys: sortedUnique(translation.removedKeys)
19191
- });
19887
+ return `${retired} is now ${replacement}; from ${refusedFromVersion()} AFT refuses a user config file that still sets ${retired}.`;
19192
19888
  }
19193
19889
  function legacyConfigNoticeMessage(configPath, translation) {
19194
19890
  const equivalents = translation.retiredKeys.filter((key) => noEffectNote(key) === undefined);
@@ -19202,13 +19898,10 @@ function legacyConfigNoticeMessage(configPath, translation) {
19202
19898
  parts.push(retiredIdleCheckoutHoursNote());
19203
19899
  }
19204
19900
  }
19205
- for (const [, note] of NO_EFFECT_RETIRED_NOTES) {
19901
+ for (const [, note] of [...NO_EFFECT_RETIRED_NOTES, ...REMOVED_DATA_LAYER_NOTES]) {
19206
19902
  if (noEffect.has(note))
19207
19903
  parts.push(note);
19208
19904
  }
19209
- const removed = removedConfigKeysNoticeMessage(configPath, translation);
19210
- if (removed)
19211
- parts.push(removed);
19212
19905
  return parts.join(" ");
19213
19906
  }
19214
19907
  function translateConfigDocument(map, tier) {
@@ -19216,7 +19909,6 @@ function translateConfigDocument(map, tier) {
19216
19909
  warnings: [],
19217
19910
  legacyInput: false,
19218
19911
  retiredKeys: [],
19219
- removedKeys: [],
19220
19912
  retiredEnabledFalse: false
19221
19913
  };
19222
19914
  translateBlock(map, tier === "user", "base", out);
@@ -19227,7 +19919,6 @@ function translateConfigDocument(map, tier) {
19227
19919
  }
19228
19920
  }
19229
19921
  out.retiredKeys = sortedUnique(out.retiredKeys);
19230
- out.removedKeys = sortedUnique(out.removedKeys);
19231
19922
  return out;
19232
19923
  }
19233
19924
  function unknownDisabledTools(disabled) {
@@ -19266,7 +19957,8 @@ function projectBlock(block) {
19266
19957
  for (const path of [
19267
19958
  ...RETIRED_PATHS.map(([retired]) => retired),
19268
19959
  ...REMOVED_NO_EFFECT_PATHS,
19269
- ...DATA_LAYER_RETIRED_PATHS
19960
+ ...DATA_LAYER_RETIRED_PATHS,
19961
+ ...REMOVED_DATA_LAYER_PATHS
19270
19962
  ]) {
19271
19963
  const dot = path.indexOf(".");
19272
19964
  if (dot < 0) {
@@ -19346,7 +20038,7 @@ function canonicalJson(value) {
19346
20038
  return JSON.stringify(value);
19347
20039
  }
19348
20040
  function noticeDigest(projection) {
19349
- return createHash4("sha256").update(canonicalJson(projection), "utf8").digest("hex");
20041
+ return createHash5("sha256").update(canonicalJson(projection), "utf8").digest("hex");
19350
20042
  }
19351
20043
  var SEMANTIC_COST_NOTICE = "AFT indexes now default on; the local semantic backend may download an ONNX runtime and model and use CPU. Run npx @cortexkit/aft setup to change indexes.semantic.";
19352
20044
  var SEMANTIC_COST_NOTICE_DIGEST = noticeDigest({ notice: "semantic_default_cost_v1" });
@@ -20219,9 +20911,9 @@ async function createConcreteAftTransportPool(opts) {
20219
20911
  var LIFECYCLE_STATE = Symbol.for("@cortexkit/aft-bridge/location-lifecycle/v1");
20220
20912
  var RELEASE_LOCATION = Symbol.for("@cortexkit/aft-bridge/location-release/v1");
20221
20913
  // ../aft-bridge/dist/lsp-github-install.js
20222
- import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
20914
+ import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
20223
20915
  import { closeSync as closeSync6, copyFileSync as copyFileSync3, createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync as lstatSync2, mkdirSync as mkdirSync4, openSync as openSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, readlinkSync, readSync as readSync5, realpathSync as realpathSync4, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
20224
- import { dirname as dirname4, join as join11, relative as relative4, resolve as resolve8 } from "node:path";
20916
+ import { dirname as dirname4, join as join10, relative as relative3, resolve as resolve7 } from "node:path";
20225
20917
  import { Readable as Readable2 } from "node:stream";
20226
20918
  import { pipeline as pipeline2 } from "node:stream/promises";
20227
20919
 
@@ -20440,13 +21132,13 @@ function detectHostPlatform() {
20440
21132
 
20441
21133
  // ../aft-bridge/dist/tar-executable.js
20442
21134
  import { existsSync as existsSync5 } from "node:fs";
20443
- import { join as join10 } from "node:path";
21135
+ import { join as join9 } from "node:path";
20444
21136
  function windowsTarExecutable(options = {}) {
20445
21137
  const platform = options.platform ?? process.platform;
20446
21138
  if (platform !== "win32")
20447
21139
  return "tar";
20448
21140
  const env = options.env ?? process.env;
20449
- const systemTar = join10(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
21141
+ const systemTar = join9(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
20450
21142
  return (options.exists ?? existsSync5)(systemTar) ? systemTar : "tar";
20451
21143
  }
20452
21144
  function extractionCommand(args, privateStorage) {
@@ -20490,14 +21182,14 @@ function createGithubInstaller(services) {
20490
21182
  return getAftLspBinariesDir();
20491
21183
  }
20492
21184
  function ghPackageDir(spec) {
20493
- return join11(ghCacheRoot(), spec.id);
21185
+ return join10(ghCacheRoot(), spec.id);
20494
21186
  }
20495
21187
  function ghBinDir(spec) {
20496
21188
  const platform = detectHostPlatform()?.platform ?? "linux";
20497
21189
  return dirname4(ghBinaryPath(spec, platform));
20498
21190
  }
20499
21191
  function ghExtractDir(spec) {
20500
- return join11(ghPackageDir(spec), "extracted");
21192
+ return join10(ghPackageDir(spec), "extracted");
20501
21193
  }
20502
21194
  const INSTALLED_META_FILE = ".aft-installed";
20503
21195
  const INSTALL_FAILED_FILE = ".aft-install-failed.json";
@@ -20505,8 +21197,9 @@ function createGithubInstaller(services) {
20505
21197
  const INSTALL_LOCK_WAIT_MS = 10 * 60 * 1000;
20506
21198
  const INSTALL_LOCK_POLL_INTERVAL_MS = 1000;
20507
21199
  const INSTALL_LOCK_WAIT_TIMEOUT_REASON = "install lock held by another process for 10 minutes";
21200
+ const SMOKE_TIMEOUT_MS = 2000;
20508
21201
  function installFailureMarkerPath(spec) {
20509
- return join11(ghPackageDir(spec), INSTALL_FAILED_FILE);
21202
+ return join10(ghPackageDir(spec), INSTALL_FAILED_FILE);
20510
21203
  }
20511
21204
  function readInstallFailureMarker(spec) {
20512
21205
  try {
@@ -20550,15 +21243,15 @@ function createGithubInstaller(services) {
20550
21243
  const meta = readGithubInstalledMetaIn(ghPackageDir(spec));
20551
21244
  if (spec.layout === "distribution" && meta?.layout === "distribution" && isSafeVersion(meta.version)) {
20552
21245
  const arch = detectHostPlatform()?.arch ?? "x64";
20553
- return join11(ghExtractDir(spec), spec.binaryPathInArchive(platform, arch, stripTagV(meta.version)));
21246
+ return join10(ghExtractDir(spec), spec.binaryPathInArchive(platform, arch, stripTagV(meta.version)));
20554
21247
  }
20555
21248
  const ext = platform === "win32" ? ".exe" : "";
20556
- return join11(ghPackageDir(spec), "bin", `${spec.binary}${ext}`);
21249
+ return join10(ghPackageDir(spec), "bin", `${spec.binary}${ext}`);
20557
21250
  }
20558
21251
  function isGithubInstalled(spec, platform) {
20559
21252
  for (const candidate of ghBinaryCandidates(spec, platform)) {
20560
21253
  try {
20561
- if (statSync6(join11(ghBinDir(spec), candidate)).isFile())
21254
+ if (statSync6(join10(ghBinDir(spec), candidate)).isFile())
20562
21255
  return true;
20563
21256
  } catch {}
20564
21257
  }
@@ -20571,7 +21264,7 @@ function createGithubInstaller(services) {
20571
21264
  }
20572
21265
  function readGithubInstalledMetaIn(installDir) {
20573
21266
  try {
20574
- const path = join11(installDir, INSTALLED_META_FILE);
21267
+ const path = join10(installDir, INSTALLED_META_FILE);
20575
21268
  if (!statSync6(path).isFile())
20576
21269
  return null;
20577
21270
  const parsed = JSON.parse(readFileSync5(path, "utf8"));
@@ -20602,7 +21295,7 @@ function createGithubInstaller(services) {
20602
21295
  ...layout ? { layout } : {},
20603
21296
  ...smoke ? { smoke } : {}
20604
21297
  };
20605
- const path = join11(installDir, INSTALLED_META_FILE);
21298
+ const path = join10(installDir, INSTALLED_META_FILE);
20606
21299
  const tempPath = `${path}.tmp-${process.pid}-${randomBytes2(6).toString("hex")}`;
20607
21300
  try {
20608
21301
  writeFileSync2(tempPath, JSON.stringify(meta), { encoding: "utf8", flag: "wx" });
@@ -20618,7 +21311,7 @@ function createGithubInstaller(services) {
20618
21311
  const MAX_EXTRACT_BYTES = 1024 * 1024 * 1024;
20619
21312
  function sha256OfFile(path) {
20620
21313
  return new Promise((resolve, reject) => {
20621
- const hash = createHash5("sha256");
21314
+ const hash = createHash6("sha256");
20622
21315
  const stream = createReadStream2(path);
20623
21316
  stream.on("error", reject);
20624
21317
  stream.on("data", (chunk) => hash.update(chunk));
@@ -20626,7 +21319,7 @@ function createGithubInstaller(services) {
20626
21319
  });
20627
21320
  }
20628
21321
  function sha256OfFileSync(path) {
20629
- const hash = createHash5("sha256");
21322
+ const hash = createHash6("sha256");
20630
21323
  const fd = openSync5(path, "r");
20631
21324
  try {
20632
21325
  const buffer = Buffer.allocUnsafe(1024 * 1024);
@@ -20854,7 +21547,7 @@ function createGithubInstaller(services) {
20854
21547
  throw new Error(`failed to read staging dir ${dir}: ${err}`);
20855
21548
  }
20856
21549
  for (const entry of entries) {
20857
- const full = join11(dir, entry);
21550
+ const full = join10(dir, entry);
20858
21551
  let lst;
20859
21552
  try {
20860
21553
  lst = lstatSync2(full);
@@ -20866,7 +21559,7 @@ function createGithubInstaller(services) {
20866
21559
  try {
20867
21560
  target = readlinkSync(full);
20868
21561
  } catch {}
20869
- throw new Error(`archive contains symlink ${relative4(realStagingRoot, full)} → ${target}; rejecting (zip-slip defense)`);
21562
+ throw new Error(`archive contains symlink ${relative3(realStagingRoot, full)} → ${target}; rejecting (zip-slip defense)`);
20870
21563
  }
20871
21564
  let realFull;
20872
21565
  try {
@@ -20874,8 +21567,8 @@ function createGithubInstaller(services) {
20874
21567
  } catch (err) {
20875
21568
  throw new Error(`failed to realpath ${full}: ${err}`);
20876
21569
  }
20877
- const rel = relative4(realStagingRoot, realFull);
20878
- if (relativePathEscapesRoot(rel) || resolve8(realStagingRoot, rel) !== realFull) {
21570
+ const rel = relative3(realStagingRoot, realFull);
21571
+ if (relativePathEscapesRoot(rel) || resolve7(realStagingRoot, rel) !== realFull) {
20879
21572
  throw new Error(`archive entry escapes staging root: ${full} → ${realFull} (zip-slip defense)`);
20880
21573
  }
20881
21574
  if (lst.isDirectory()) {
@@ -21015,7 +21708,7 @@ function createGithubInstaller(services) {
21015
21708
  }
21016
21709
  function quarantineCachedGithubInstall(spec, reason) {
21017
21710
  const packageDir = ghPackageDir(spec);
21018
- const dest = join11(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
21711
+ const dest = join10(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
21019
21712
  warn(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
21020
21713
  try {
21021
21714
  mkdirSync4(dirname4(dest), { recursive: true });
@@ -21025,7 +21718,7 @@ function createGithubInstaller(services) {
21025
21718
  warn(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
21026
21719
  }
21027
21720
  }
21028
- async function smokeGithubBinary(spec, binaryPath) {
21721
+ async function smokeGithubBinary(spec, binaryPath, timeoutMs = SMOKE_TIMEOUT_MS) {
21029
21722
  return new Promise((resolveSmoke) => {
21030
21723
  let child;
21031
21724
  let settled = false;
@@ -21045,8 +21738,8 @@ function createGithubInstaller(services) {
21045
21738
  const timer = setTimeout(() => {
21046
21739
  child?.kill("SIGKILL");
21047
21740
  child?.unref();
21048
- finish("timeout", "exceeded 2000 ms; keeping install");
21049
- }, 2000);
21741
+ finish("timeout", `exceeded ${timeoutMs} ms; keeping install`);
21742
+ }, timeoutMs);
21050
21743
  const capture = (chunk) => {
21051
21744
  const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
21052
21745
  const available = 64 * 1024 - output.length;
@@ -21070,19 +21763,19 @@ function createGithubInstaller(services) {
21070
21763
  function hasRequiredRuntime(spec, extractDir, version) {
21071
21764
  return (spec.requiredRuntimePaths?.(stripTagV(version)) ?? []).every(({ path, kind }) => {
21072
21765
  try {
21073
- const info = statSync6(join11(extractDir, path));
21766
+ const info = statSync6(join10(extractDir, path));
21074
21767
  return kind === "file" ? info.isFile() : info.isDirectory();
21075
21768
  } catch {
21076
21769
  return false;
21077
21770
  }
21078
21771
  });
21079
21772
  }
21080
- function validateCachedGithubInstall(spec, platform) {
21773
+ function validateCachedGithubInstall(spec, platform, smokeTimeoutMs = SMOKE_TIMEOUT_MS) {
21081
21774
  const lease = acquireInstallLock(spec.githubRepo);
21082
21775
  if (!lease)
21083
21776
  return null;
21084
21777
  try {
21085
- const validation = validateCachedGithubInstallUnderLock(spec, platform);
21778
+ const validation = validateCachedGithubInstallUnderLock(spec, platform, smokeTimeoutMs);
21086
21779
  if (typeof validation !== "boolean")
21087
21780
  return validation.finally(() => lease.release());
21088
21781
  lease.release();
@@ -21092,10 +21785,10 @@ function createGithubInstaller(services) {
21092
21785
  throw err;
21093
21786
  }
21094
21787
  }
21095
- function validateCachedGithubInstallUnderLock(spec, platform) {
21788
+ function validateCachedGithubInstallUnderLock(spec, platform, smokeTimeoutMs = SMOKE_TIMEOUT_MS) {
21096
21789
  const packageDir = ghPackageDir(spec);
21097
21790
  const meta = readGithubInstalledMetaIn(packageDir);
21098
- const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join11(ghBinDir(spec), candidate)).find((candidate) => {
21791
+ const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join10(ghBinDir(spec), candidate)).find((candidate) => {
21099
21792
  try {
21100
21793
  return statSync6(candidate).isFile();
21101
21794
  } catch {
@@ -21125,7 +21818,7 @@ function createGithubInstaller(services) {
21125
21818
  quarantineCachedGithubInstall(spec, "missing required runtime files");
21126
21819
  return false;
21127
21820
  }
21128
- const verdict = await smokeGithubBinary(spec, binaryPath);
21821
+ const verdict = await smokeGithubBinary(spec, binaryPath, smokeTimeoutMs);
21129
21822
  if (verdict === "failed") {
21130
21823
  quarantineCachedGithubInstall(spec, "cached binary failed runtime smoke check");
21131
21824
  return false;
@@ -21171,7 +21864,7 @@ function createGithubInstaller(services) {
21171
21864
  }
21172
21865
  const pkgDir = ghPackageDir(spec);
21173
21866
  const extractDir = ghExtractDir(spec);
21174
- const archivePath = join11(pkgDir, expected.name);
21867
+ const archivePath = join10(pkgDir, expected.name);
21175
21868
  log(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
21176
21869
  try {
21177
21870
  await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
@@ -21207,7 +21900,7 @@ function createGithubInstaller(services) {
21207
21900
  const binaryRelativePath = spec.binaryPathInArchive(platform, arch, version);
21208
21901
  try {
21209
21902
  await extractArchiveSafely(archivePath, extractDir, expected.archive, async (stagingDir) => {
21210
- const stagedBinary = join11(stagingDir, binaryRelativePath);
21903
+ const stagedBinary = join10(stagingDir, binaryRelativePath);
21211
21904
  if (!existsSync6(stagedBinary) || !statSync6(stagedBinary).isFile()) {
21212
21905
  throw new Error(`extracted binary not found at ${stagedBinary}`);
21213
21906
  }
@@ -21237,7 +21930,7 @@ function createGithubInstaller(services) {
21237
21930
  unlinkSync3(archivePath);
21238
21931
  } catch {}
21239
21932
  }
21240
- const innerBinaryPath = join11(extractDir, binaryRelativePath);
21933
+ const innerBinaryPath = join10(extractDir, binaryRelativePath);
21241
21934
  const targetBinary = spec.layout === "distribution" ? innerBinaryPath : ghBinaryPath(spec, platform);
21242
21935
  mkdirSync4(dirname4(targetBinary), { recursive: true });
21243
21936
  try {
@@ -21364,6 +22057,7 @@ function createGithubInstaller(services) {
21364
22057
  let installsStarted = 0;
21365
22058
  const lockWaitTimeoutMs = Math.max(0, options.__lockWaitTimeoutMsForTests ?? INSTALL_LOCK_WAIT_MS);
21366
22059
  const lockPollIntervalMs = Math.max(1, options.__lockPollIntervalMsForTests ?? INSTALL_LOCK_POLL_INTERVAL_MS);
22060
+ const smokeTimeoutMs = Math.max(1, options.__smokeTimeoutMsForTests ?? SMOKE_TIMEOUT_MS);
21367
22061
  function notifyCachedBinDirsChanged(directory) {
21368
22062
  try {
21369
22063
  options.onCachedBinDirsChanged?.(directory);
@@ -21376,7 +22070,7 @@ function createGithubInstaller(services) {
21376
22070
  while (true) {
21377
22071
  if (signal.aborted)
21378
22072
  return null;
21379
- const validation = await withInstallLock(spec.githubRepo, async () => validateCachedGithubInstallUnderLock(spec, platform));
22073
+ const validation = await withInstallLock(spec.githubRepo, async () => validateCachedGithubInstallUnderLock(spec, platform, smokeTimeoutMs));
21380
22074
  if (validation !== null)
21381
22075
  return validation;
21382
22076
  if (signal.aborted)
@@ -21405,7 +22099,7 @@ function createGithubInstaller(services) {
21405
22099
  }
21406
22100
  for (const spec of GITHUB_LSP_TABLE) {
21407
22101
  const controller = new AbortController;
21408
- const validation = isGithubInstalled(spec, host.platform) ? validateCachedGithubInstall(spec, host.platform) : false;
22102
+ const validation = isGithubInstalled(spec, host.platform) ? validateCachedGithubInstall(spec, host.platform, smokeTimeoutMs) : false;
21409
22103
  if (validation === true)
21410
22104
  cachedBinDirs.push(ghBinDir(spec));
21411
22105
  const cacheReady = (validation === null ? retryBusyCacheValidation(spec, host.platform, controller.signal) : Promise.resolve(validation)).then((healthy) => {
@@ -21460,7 +22154,7 @@ function createGithubInstaller(services) {
21460
22154
  const currentHost = detectHostPlatform();
21461
22155
  if (!currentHost)
21462
22156
  return [];
21463
- const directories = await Promise.all(GITHUB_LSP_TABLE.map(async (spec) => isGithubInstalled(spec, currentHost.platform) && await validateCachedGithubInstall(spec, currentHost.platform) ? ghBinDir(spec) : null));
22157
+ const directories = await Promise.all(GITHUB_LSP_TABLE.map(async (spec) => isGithubInstalled(spec, currentHost.platform) && await validateCachedGithubInstall(spec, currentHost.platform, smokeTimeoutMs) ? ghBinDir(spec) : null));
21464
22158
  return directories.filter((directory) => directory !== null);
21465
22159
  }
21466
22160
  };
@@ -21531,7 +22225,7 @@ import { stat as stat2 } from "node:fs/promises";
21531
22225
  // ../aft-bridge/dist/npm-resolver.js
21532
22226
  import { readdirSync as readdirSync3, statSync as statSync7 } from "node:fs";
21533
22227
  import { homedir as homedir9 } from "node:os";
21534
- import { dirname as dirname5, isAbsolute as isAbsolute5, join as join12 } from "node:path";
22228
+ import { dirname as dirname5, isAbsolute as isAbsolute4, join as join11 } from "node:path";
21535
22229
  function defaultDeps() {
21536
22230
  return {
21537
22231
  platform: process.platform,
@@ -21558,16 +22252,16 @@ function npmFromPath(deps) {
21558
22252
  const separator = deps.platform === "win32" ? ";" : ":";
21559
22253
  for (const entry of raw.split(separator)) {
21560
22254
  const dir = entry.trim().replace(/^"|"$/g, "");
21561
- if (!dir || !isAbsolute5(dir))
22255
+ if (!dir || !isAbsolute4(dir))
21562
22256
  continue;
21563
- if (isFile(join12(dir, name)))
22257
+ if (isFile(join11(dir, name)))
21564
22258
  return dir;
21565
22259
  }
21566
22260
  return null;
21567
22261
  }
21568
22262
  function npmAdjacentToNode(deps) {
21569
22263
  const dir = dirname5(deps.execPath);
21570
- return isFile(join12(dir, npmBinaryName(deps.platform))) ? dir : null;
22264
+ return isFile(join11(dir, npmBinaryName(deps.platform))) ? dir : null;
21571
22265
  }
21572
22266
  function highestVersionedNodeBin(installsDir, name) {
21573
22267
  let entries;
@@ -21576,8 +22270,8 @@ function highestVersionedNodeBin(installsDir, name) {
21576
22270
  } catch {
21577
22271
  return null;
21578
22272
  }
21579
- const candidates = entries.filter((v) => isFile(join12(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
21580
- return candidates.length > 0 ? join12(installsDir, candidates[0], "bin") : null;
22273
+ const candidates = entries.filter((v) => isFile(join11(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
22274
+ return candidates.length > 0 ? join11(installsDir, candidates[0], "bin") : null;
21581
22275
  }
21582
22276
  function compareVersionsDesc(a, b) {
21583
22277
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -21602,22 +22296,22 @@ function wellKnownNpmDirs(deps) {
21602
22296
  const programFiles = env.ProgramFiles || "C:\\Program Files";
21603
22297
  const appData = env.APPDATA;
21604
22298
  const localAppData = env.LOCALAPPDATA;
21605
- push(join12(programFiles, "nodejs"));
22299
+ push(join11(programFiles, "nodejs"));
21606
22300
  if (appData)
21607
- push(join12(appData, "npm"));
22301
+ push(join11(appData, "npm"));
21608
22302
  if (localAppData)
21609
- push(join12(localAppData, "Volta", "bin"));
22303
+ push(join11(localAppData, "Volta", "bin"));
21610
22304
  if (env.NVM_SYMLINK)
21611
22305
  push(env.NVM_SYMLINK);
21612
22306
  } else {
21613
22307
  if (env.NVM_BIN)
21614
22308
  push(env.NVM_BIN);
21615
- push(highestVersionedNodeBin(join12(home, ".nvm", "versions", "node"), name));
21616
- push(highestVersionedNodeBin(join12(home, ".local", "share", "mise", "installs", "node"), name));
21617
- push(highestVersionedNodeBin(join12(home, ".asdf", "installs", "nodejs"), name));
21618
- push(join12(home, ".volta", "bin"));
21619
- push(join12(home, ".asdf", "shims"));
21620
- const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join12(home, ".local", "bin")]);
22309
+ push(highestVersionedNodeBin(join11(home, ".nvm", "versions", "node"), name));
22310
+ push(highestVersionedNodeBin(join11(home, ".local", "share", "mise", "installs", "node"), name));
22311
+ push(highestVersionedNodeBin(join11(home, ".asdf", "installs", "nodejs"), name));
22312
+ push(join11(home, ".volta", "bin"));
22313
+ push(join11(home, ".asdf", "shims"));
22314
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join11(home, ".local", "bin")]);
21621
22315
  for (const dir of systemDirs)
21622
22316
  push(dir);
21623
22317
  }
@@ -21627,12 +22321,12 @@ function resolveNpm(deps = defaultDeps()) {
21627
22321
  const name = npmBinaryName(deps.platform);
21628
22322
  const onPath = npmFromPath(deps);
21629
22323
  if (onPath)
21630
- return { command: join12(onPath, name), binDir: onPath };
22324
+ return { command: join11(onPath, name), binDir: onPath };
21631
22325
  const adjacent = npmAdjacentToNode(deps);
21632
22326
  if (adjacent)
21633
- return { command: join12(adjacent, name), binDir: adjacent };
22327
+ return { command: join11(adjacent, name), binDir: adjacent };
21634
22328
  for (const dir of wellKnownNpmDirs(deps)) {
21635
- const candidate = join12(dir, name);
22329
+ const candidate = join11(dir, name);
21636
22330
  if (isFile(candidate))
21637
22331
  return { command: candidate, binDir: dir };
21638
22332
  }
@@ -21641,15 +22335,15 @@ function resolveNpm(deps = defaultDeps()) {
21641
22335
  function npmCandidates(deps = defaultDeps()) {
21642
22336
  const name = npmBinaryName(deps.platform);
21643
22337
  const dirs = [
21644
- ...(deps.env.PATH ?? "").split(deps.platform === "win32" ? ";" : ":").filter(isAbsolute5),
22338
+ ...(deps.env.PATH ?? "").split(deps.platform === "win32" ? ";" : ":").filter(isAbsolute4),
21645
22339
  dirname5(deps.execPath),
21646
22340
  ...wellKnownNpmDirs(deps)
21647
22341
  ];
21648
22342
  return [...new Set(dirs)].flatMap((binDir) => {
21649
22343
  return [
21650
- join12(binDir, name),
21651
- join12(binDir, "node_modules", "npm", "bin", "npm-cli.js"),
21652
- join12(binDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
22344
+ join11(binDir, name),
22345
+ join11(binDir, "node_modules", "npm", "bin", "npm-cli.js"),
22346
+ join11(binDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
21653
22347
  ].filter(isFile).map((command) => ({ command, binDir }));
21654
22348
  });
21655
22349
  }
@@ -21818,7 +22512,7 @@ function terminateNpmProcessTree(child, invocation, env = process.env, gracePeri
21818
22512
  };
21819
22513
  child.once("exit", onChildExit);
21820
22514
  const systemRoot = env.SystemRoot ?? env.SYSTEMROOT;
21821
- const taskkill = systemRoot ? join12(systemRoot, "System32", "taskkill.exe") : "taskkill.exe";
22515
+ const taskkill = systemRoot ? join11(systemRoot, "System32", "taskkill.exe") : "taskkill.exe";
21822
22516
  try {
21823
22517
  killer = spawn(taskkill, ["/pid", String(child.pid), "/t", "/f"], {
21824
22518
  stdio: "ignore",
@@ -21949,7 +22643,7 @@ async function lspNpmInstallInvocation(npm, target, before, clock = SYSTEM_CLOCK
21949
22643
  }
21950
22644
  // ../aft-bridge/dist/lsp-npm-selection.js
21951
22645
  import { readFile, realpath, stat as stat3 } from "node:fs/promises";
21952
- import { dirname as dirname6, join as join13, resolve as resolve9 } from "node:path";
22646
+ import { dirname as dirname6, join as join12, resolve as resolve8 } from "node:path";
21953
22647
  var LSP_NPM_REFUSAL = "AFT can't install language servers with the npm at <path> (<reason>). Put a real npm 7 or newer first on PATH; pinning a server version won't help.";
21954
22648
  function lspNpmRefusal(path, reason) {
21955
22649
  return LSP_NPM_REFUSAL.replace("<path>", path).replace("<reason>", reason);
@@ -21964,13 +22658,13 @@ async function genuineNpm(candidate) {
21964
22658
  const windowsShim = /\.(?:cmd|bat)$/i.test(executable);
21965
22659
  let current = dirname6(executable);
21966
22660
  if (windowsShim)
21967
- current = join13(current, "node_modules", "npm");
22661
+ current = join12(current, "node_modules", "npm");
21968
22662
  for (;; ) {
21969
22663
  try {
21970
- const pkg = JSON.parse(await readFile(join13(current, "package.json"), "utf8"));
22664
+ const pkg = JSON.parse(await readFile(join12(current, "package.json"), "utf8"));
21971
22665
  const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.npm;
21972
22666
  if (pkg.name === "npm" && typeof bin === "string") {
21973
- const cli = await realpath(resolve9(current, bin));
22667
+ const cli = await realpath(resolve8(current, bin));
21974
22668
  if (!windowsShim && cli !== executable)
21975
22669
  return { reason: "not npm: command is not npm's declared CLI" };
21976
22670
  const major = /^(\d+)\.\d+\.\d+$/.exec(pkg.version)?.[1];
@@ -21979,7 +22673,7 @@ async function genuineNpm(candidate) {
21979
22673
  if (Number(major) < 7)
21980
22674
  return { reason: `old npm: ${pkg.version} (requires npm 7 or newer)` };
21981
22675
  if (windowsShim || process.platform === "win32" && /\.[cm]?js$/i.test(cli)) {
21982
- const node = join13(candidate.binDir ?? dirname6(executable), "node.exe");
22676
+ const node = join12(candidate.binDir ?? dirname6(executable), "node.exe");
21983
22677
  if (!(await stat3(node)).isFile())
21984
22678
  return { reason: "probe failed: adjacent Node is missing" };
21985
22679
  return { npm: { command: node, binDir: dirname6(node), cliPath: cli }, reason: "" };
@@ -22071,12 +22765,12 @@ function shouldInterruptWaitsForMessage(detachOnUserMessage, operatorText) {
22071
22765
  // ../aft-bridge/dist/migration.js
22072
22766
  import { closeSync as closeSync8, existsSync as existsSync9, mkdirSync as mkdirSync5, openSync as openSync7, readFileSync as readFileSync8, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync4 } from "node:fs";
22073
22767
  import { homedir as homedir12, tmpdir as tmpdir3 } from "node:os";
22074
- import { basename as basename2, dirname as dirname9, join as join16, resolve as resolve11 } from "node:path";
22768
+ import { basename as basename2, dirname as dirname9, join as join15, resolve as resolve10 } from "node:path";
22075
22769
 
22076
22770
  // ../aft-bridge/dist/paths.js
22077
22771
  import { existsSync as existsSync7, readFileSync as readFileSync6, realpathSync as realpathSync5, renameSync as renameSync4, writeFileSync as writeFileSync3 } from "node:fs";
22078
22772
  import { homedir as homedir10 } from "node:os";
22079
- import { dirname as dirname7, isAbsolute as isAbsolute6, join as join14, resolve as resolve10 } from "node:path";
22773
+ import { dirname as dirname7, isAbsolute as isAbsolute5, join as join13, resolve as resolve9 } from "node:path";
22080
22774
  function homeDir3() {
22081
22775
  if (process.platform === "win32")
22082
22776
  return process.env.USERPROFILE || process.env.HOME || homedir10();
@@ -22084,18 +22778,18 @@ function homeDir3() {
22084
22778
  }
22085
22779
  function configHome() {
22086
22780
  const xdg = process.env.XDG_CONFIG_HOME;
22087
- if (xdg && isAbsolute6(xdg))
22781
+ if (xdg && isAbsolute5(xdg))
22088
22782
  return xdg;
22089
- return join14(homeDir3(), ".config");
22783
+ return join13(homeDir3(), ".config");
22090
22784
  }
22091
22785
  function legacyOpenCodeConfigDir() {
22092
22786
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
22093
22787
  if (envDir)
22094
- return resolve10(envDir);
22095
- return join14(configHome(), "opencode");
22788
+ return resolve9(envDir);
22789
+ return join13(configHome(), "opencode");
22096
22790
  }
22097
22791
  function legacyPiAgentDir() {
22098
- return join14(homeDir3(), ".pi", "agent");
22792
+ return join13(homeDir3(), ".pi", "agent");
22099
22793
  }
22100
22794
  function legacySources(basePath, label, harness) {
22101
22795
  return [
@@ -22104,10 +22798,10 @@ function legacySources(basePath, label, harness) {
22104
22798
  ];
22105
22799
  }
22106
22800
  function resolveCortexKitUserConfigPath() {
22107
- return join14(configHome(), "cortexkit", "aft.jsonc");
22801
+ return join13(configHome(), "cortexkit", "aft.jsonc");
22108
22802
  }
22109
22803
  function resolveCortexKitProjectConfigPath(projectDirectory) {
22110
- return join14(projectDirectory, ".cortexkit", "aft.jsonc");
22804
+ return join13(projectDirectory, ".cortexkit", "aft.jsonc");
22111
22805
  }
22112
22806
  function resolveProjectConfigReadPath(projectDirectory, operatingHarness) {
22113
22807
  const canonical = resolveCortexKitProjectConfigPath(projectDirectory);
@@ -22134,14 +22828,14 @@ function resolveCortexKitConfigPaths(projectDirectory) {
22134
22828
  }
22135
22829
  function resolveLegacyAftConfigSources(projectDirectory) {
22136
22830
  const project = [
22137
- ...legacySources(join14(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
22138
- ...legacySources(join14(projectDirectory, ".pi", "aft"), "Pi project", "pi")
22831
+ ...legacySources(join13(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
22832
+ ...legacySources(join13(projectDirectory, ".pi", "aft"), "Pi project", "pi")
22139
22833
  ];
22140
22834
  const identity = (path) => {
22141
22835
  try {
22142
22836
  return realpathSync5(path);
22143
22837
  } catch {
22144
- return resolve10(path);
22838
+ return resolve9(path);
22145
22839
  }
22146
22840
  };
22147
22841
  const protectedPaths = new Set([
@@ -22150,18 +22844,18 @@ function resolveLegacyAftConfigSources(projectDirectory) {
22150
22844
  ].map(identity));
22151
22845
  return {
22152
22846
  user: [
22153
- ...legacySources(join14(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
22154
- ...legacySources(join14(legacyPiAgentDir(), "aft"), "Pi user", "pi")
22847
+ ...legacySources(join13(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
22848
+ ...legacySources(join13(legacyPiAgentDir(), "aft"), "Pi user", "pi")
22155
22849
  ].filter((source) => !protectedPaths.has(identity(source.path))),
22156
22850
  project
22157
22851
  };
22158
22852
  }
22159
22853
  function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
22160
- return join14(storageRoot, harness, ...segments);
22854
+ return join13(storageRoot, harness, ...segments);
22161
22855
  }
22162
22856
  function repairRootScopedStorageFile(storageRoot, harness, fileName) {
22163
22857
  const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
22164
- const rootPath = join14(storageRoot, fileName);
22858
+ const rootPath = join13(storageRoot, fileName);
22165
22859
  if (existsSync7(harnessPath) || !existsSync7(rootPath))
22166
22860
  return harnessPath;
22167
22861
  try {
@@ -22250,15 +22944,15 @@ function decodeFileUrl(target) {
22250
22944
  import { closeSync as closeSync7, existsSync as existsSync8, promises as fsPromises, openSync as openSync6, readFileSync as readFileSync7, readSync as readSync6 } from "node:fs";
22251
22945
  import { createRequire as createRequire2 } from "node:module";
22252
22946
  import { homedir as homedir11 } from "node:os";
22253
- import { delimiter, dirname as dirname8, isAbsolute as isAbsolute7, join as join15 } from "node:path";
22947
+ import { delimiter, dirname as dirname8, isAbsolute as isAbsolute6, join as join14 } from "node:path";
22254
22948
  var ensureBinaryForResolver = ensureBinary;
22255
22949
  var npmPlatformPackageReader = null;
22256
22950
  var cacheCopiesInFlight = new Map;
22257
22951
  function copyToVersionedCache(npmBinaryPath, version) {
22258
22952
  const tag = version.startsWith("v") ? version : `v${version}`;
22259
22953
  const ext = process.platform === "win32" ? ".exe" : "";
22260
- const versionedDir = join15(getAftBinaryCacheDir(), tag);
22261
- const cachedPath = join15(versionedDir, `aft${ext}`);
22954
+ const versionedDir = join14(getAftBinaryCacheDir(), tag);
22955
+ const cachedPath = join14(versionedDir, `aft${ext}`);
22262
22956
  if (existsSync8(cachedPath) && isTrustedCachedBinary(cachedPath, version))
22263
22957
  return { cachedPath };
22264
22958
  const existing = cacheCopiesInFlight.get(cachedPath);
@@ -22304,7 +22998,7 @@ function homeDirFromEnv(env) {
22304
22998
  return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir11();
22305
22999
  }
22306
23000
  function cachedBinaryPathFromEnv(version, env, ext) {
22307
- const binaryPath = join15(getAftBinaryCacheDir(env), version, `aft${ext}`);
23001
+ const binaryPath = join14(getAftBinaryCacheDir(env), version, `aft${ext}`);
22308
23002
  return existsSync8(binaryPath) ? binaryPath : null;
22309
23003
  }
22310
23004
  async function probeBinaryCandidateOffThread(binaryPath, source, expectedVersion) {
@@ -22324,9 +23018,9 @@ function pathCandidates(env, ext) {
22324
23018
  const seen = new Set;
22325
23019
  const candidates = [];
22326
23020
  for (const dir of rawPath.split(delimiter)) {
22327
- if (!dir || !isAbsolute7(dir))
23021
+ if (!dir || !isAbsolute6(dir))
22328
23022
  continue;
22329
- const candidate = join15(dir, `aft${ext}`);
23023
+ const candidate = join14(dir, `aft${ext}`);
22330
23024
  if (seen.has(candidate))
22331
23025
  continue;
22332
23026
  seen.add(candidate);
@@ -22404,7 +23098,7 @@ function npmPlatformPackage(ext) {
22404
23098
  const req = createRequire2(import.meta.url);
22405
23099
  const manifestPath = req.resolve(`@cortexkit/aft-${platformKey()}/package.json`);
22406
23100
  const manifest = JSON.parse(readFileSync7(manifestPath, "utf8"));
22407
- const binaryPath = join15(dirname8(manifestPath), "bin", `aft${ext}`);
23101
+ const binaryPath = join14(dirname8(manifestPath), "bin", `aft${ext}`);
22408
23102
  if (typeof manifest.version !== "string" || !existsSync8(binaryPath))
22409
23103
  return null;
22410
23104
  return { binaryPath, version: normalizeBareVersion(manifest.version) };
@@ -22471,7 +23165,7 @@ async function findProbedBinary(expectedVersion, env) {
22471
23165
  if (usable)
22472
23166
  return { path: usable, source: "PATH" };
22473
23167
  }
22474
- const cargoPath = join15(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
23168
+ const cargoPath = join14(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
22475
23169
  if (existsSync8(cargoPath)) {
22476
23170
  const usable = await probeBinaryCandidateOffThread(cargoPath, "cargo", pluginVersion);
22477
23171
  if (usable)
@@ -22570,9 +23264,9 @@ function dataHome() {
22570
23264
  if (process.env.XDG_DATA_HOME)
22571
23265
  return process.env.XDG_DATA_HOME;
22572
23266
  if (process.platform === "win32") {
22573
- return process.env.LOCALAPPDATA || process.env.APPDATA || join16(homeDir4(), "AppData", "Local");
23267
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join15(homeDir4(), "AppData", "Local");
22574
23268
  }
22575
- return join16(homeDir4(), ".local", "share");
23269
+ return join15(homeDir4(), ".local", "share");
22576
23270
  }
22577
23271
  function homeDir4() {
22578
23272
  if (process.platform === "win32")
@@ -22581,8 +23275,8 @@ function homeDir4() {
22581
23275
  }
22582
23276
  function resolveLegacyStorageRoot(harness) {
22583
23277
  if (harness === "pi")
22584
- return join16(homeDir4(), ".pi", "agent", "aft");
22585
- return join16(dataHome(), "opencode", "storage", "plugin", "aft");
23278
+ return join15(homeDir4(), ".pi", "agent", "aft");
23279
+ return join15(dataHome(), "opencode", "storage", "plugin", "aft");
22586
23280
  }
22587
23281
  function stripJsoncForParse(input) {
22588
23282
  let out = "";
@@ -22712,7 +23406,7 @@ function acquireConfigMigrationLock(lockDir) {
22712
23406
  }
22713
23407
  function atomicCopyConfigFile(sourcePath, targetPath) {
22714
23408
  mkdirSync5(dirname9(targetPath), { recursive: true });
22715
- const tmpPath = join16(dirname9(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
23409
+ const tmpPath = join15(dirname9(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
22716
23410
  let fd = null;
22717
23411
  try {
22718
23412
  fd = openSync7(tmpPath, "wx", 384);
@@ -22734,7 +23428,7 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
22734
23428
  }
22735
23429
  function atomicWriteConfigFile(targetPath, content) {
22736
23430
  mkdirSync5(dirname9(targetPath), { recursive: true });
22737
- const tmpPath = join16(dirname9(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
23431
+ const tmpPath = join15(dirname9(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
22738
23432
  let fd = null;
22739
23433
  try {
22740
23434
  fd = openSync7(tmpPath, "wx", 384);
@@ -22853,8 +23547,8 @@ function visibleConfigMigrationWarning(scope, targetPath, paths, reason) {
22853
23547
  }
22854
23548
  function migrateAftConfigFile(opts) {
22855
23549
  const warnings = [];
22856
- const resolvedTarget = resolve11(opts.targetPath);
22857
- const existingSources = opts.legacySources.filter((source) => existsSync9(source.path) && resolve11(source.path) !== resolvedTarget);
23550
+ const resolvedTarget = resolve10(opts.targetPath);
23551
+ const existingSources = opts.legacySources.filter((source) => existsSync9(source.path) && resolve10(source.path) !== resolvedTarget);
22858
23552
  const info = opts.logger?.info ?? opts.logger?.log;
22859
23553
  if (existingSources.length === 0) {
22860
23554
  return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
@@ -22916,12 +23610,12 @@ function spawnErrorLabel(error) {
22916
23610
  return [code, error.message].filter(Boolean).join(": ");
22917
23611
  }
22918
23612
  function migrationLogPath(newRoot, harness, logger) {
22919
- const desired = join16(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
23613
+ const desired = join15(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
22920
23614
  try {
22921
23615
  mkdirSync5(dirname9(desired), { recursive: true });
22922
23616
  return desired;
22923
23617
  } catch (err) {
22924
- const fallback = join16(tmpdir3(), `aft-migration-${harness}-${Date.now()}.jsonl`);
23618
+ const fallback = join15(tmpdir3(), `aft-migration-${harness}-${Date.now()}.jsonl`);
22925
23619
  logger?.warn?.(`Failed to create AFT migration log directory ${dirname9(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
22926
23620
  return fallback;
22927
23621
  }
@@ -22981,13 +23675,13 @@ async function ensureStorageMigrated(opts) {
22981
23675
  // ../aft-bridge/dist/migration-notices.js
22982
23676
  import { readFileSync as readFileSync9, renameSync as renameSync6, rmdirSync, statSync as statSync9, writeFileSync as writeFileSync5 } from "node:fs";
22983
23677
  import { homedir as homedir13 } from "node:os";
22984
- import { dirname as dirname10, join as join17, resolve as resolve12 } from "node:path";
23678
+ import { dirname as dirname10, join as join16, resolve as resolve11 } from "node:path";
22985
23679
  function migrationNoticeStorePath(env = process.env) {
22986
- const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join17(homedir13(), ".local", "state");
22987
- return join17(stateHome, "cortexkit", "aft", "migration-notices.json");
23680
+ const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join16(homedir13(), ".local", "state");
23681
+ return join16(stateHome, "cortexkit", "aft", "migration-notices.json");
22988
23682
  }
22989
23683
  function noticeKey(configPath, digest) {
22990
- return `${resolve12(configPath)}|${MIGRATION_POLICY_ID}|${digest}`;
23684
+ return `${resolve11(configPath)}|${MIGRATION_POLICY_ID}|${digest}`;
22991
23685
  }
22992
23686
  function readRecords(storePath) {
22993
23687
  try {
@@ -23181,7 +23875,7 @@ function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
23181
23875
  // ../aft-bridge/dist/onnx-runtime.js
23182
23876
  import { randomBytes as randomBytes3 } from "node:crypto";
23183
23877
  import { chmodSync as chmodSync2, closeSync as closeSync10, copyFileSync as copyFileSync4, createWriteStream as createWriteStream3, existsSync as existsSync11, lstatSync as lstatSync3, openSync as openSync9, readdirSync as readdirSync4, readFileSync as readFileSync10, readlinkSync as readlinkSync2, realpathSync as realpathSync7, renameSync as renameSync7, rmSync as rmSync4, statSync as statSync10, symlinkSync, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "node:fs";
23184
- import { basename as basename3, dirname as dirname11, isAbsolute as isAbsolute8, join as join18, relative as relative5, resolve as resolve13, win32 as win323 } from "node:path";
23878
+ import { basename as basename3, dirname as dirname11, isAbsolute as isAbsolute7, join as join17, relative as relative4, resolve as resolve12, win32 as win324 } from "node:path";
23185
23879
  import { Readable as Readable3 } from "node:stream";
23186
23880
  import { pipeline as pipeline3 } from "node:stream/promises";
23187
23881
  var ORT_VERSION = "1.24.4";
@@ -23269,7 +23963,7 @@ function resolveOnnxRuntime(storageDir, seams) {
23269
23963
  }
23270
23964
  async function findCachedOnnxRuntime(ortVersionDir, libName) {
23271
23965
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
23272
- const libPath = join18(resolvedOrtDir, libName);
23966
+ const libPath = join17(resolvedOrtDir, libName);
23273
23967
  if (existsSync11(libPath)) {
23274
23968
  const meta = readOnnxInstalledMeta(ortVersionDir);
23275
23969
  if (meta?.sha256) {
@@ -23294,7 +23988,7 @@ async function findCachedOnnxRuntime(ortVersionDir, libName) {
23294
23988
  }
23295
23989
  async function resolveOnnxRuntimeUncoalesced(storageDir, seams) {
23296
23990
  const info = seams.platformInfo !== undefined ? seams.platformInfo : getPlatformInfo();
23297
- const ortVersionDir = join18(storageDir, "onnxruntime", ORT_VERSION);
23991
+ const ortVersionDir = join17(storageDir, "onnxruntime", ORT_VERSION);
23298
23992
  const libName = info?.libName ?? "libonnxruntime.dylib";
23299
23993
  const cached = await findCachedOnnxRuntime(ortVersionDir, libName);
23300
23994
  if (cached)
@@ -23308,9 +24002,9 @@ async function resolveOnnxRuntimeUncoalesced(storageDir, seams) {
23308
24002
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
23309
24003
  return null;
23310
24004
  }
23311
- const onnxBaseDir = join18(storageDir, "onnxruntime");
24005
+ const onnxBaseDir = join17(storageDir, "onnxruntime");
23312
24006
  openPrivateStorageDir(storageDir, onnxBaseDir);
23313
- const lockPath = join18(onnxBaseDir, ONNX_LOCK_FILE);
24007
+ const lockPath = join17(onnxBaseDir, ONNX_LOCK_FILE);
23314
24008
  const pollMs = seams.lockPollMs ?? LOCK_POLL_MS;
23315
24009
  const deadline = Date.now() + LOCK_WAIT_MS;
23316
24010
  let announcedWait = false;
@@ -23355,7 +24049,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
23355
24049
  for (const entry of entries) {
23356
24050
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
23357
24051
  continue;
23358
- const stagingDir = join18(onnxBaseDir, entry);
24052
+ const stagingDir = join17(onnxBaseDir, entry);
23359
24053
  const parts = entry.split(".");
23360
24054
  const pidStr = parts[parts.length - 2];
23361
24055
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -23392,7 +24086,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
23392
24086
  }
23393
24087
  function cleanupIncompleteTargetIfUnowned(ortDir) {
23394
24088
  try {
23395
- if (existsSync11(ortDir) && !existsSync11(join18(ortDir, ONNX_INSTALLED_META_FILE))) {
24089
+ if (existsSync11(ortDir) && !existsSync11(join17(ortDir, ONNX_INSTALLED_META_FILE))) {
23396
24090
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
23397
24091
  rmSync4(ortDir, { recursive: true, force: true });
23398
24092
  }
@@ -23420,14 +24114,14 @@ function parseOnnxVersionFromDirectoryPath(value) {
23420
24114
  return null;
23421
24115
  }
23422
24116
  function isPathInsideRoot(root, candidate) {
23423
- const rel = relative5(root, candidate);
23424
- return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute8(rel) && !win323.isAbsolute(rel);
24117
+ const rel = relative4(root, candidate);
24118
+ return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute7(rel) && !win324.isAbsolute(rel);
23425
24119
  }
23426
24120
  function detectOnnxVersion(libDir, libName) {
23427
24121
  try {
23428
24122
  const entries = readdirSync4(libDir);
23429
24123
  try {
23430
- const resolved = parseOnnxVersionFromPath(realpathSync7(join18(libDir, libName)));
24124
+ const resolved = parseOnnxVersionFromPath(realpathSync7(join17(libDir, libName)));
23431
24125
  if (resolved && resolved !== INVALID_ORT_VERSION)
23432
24126
  return resolved;
23433
24127
  } catch {}
@@ -23441,7 +24135,7 @@ function detectOnnxVersion(libDir, libName) {
23441
24135
  if (version)
23442
24136
  return version;
23443
24137
  }
23444
- const base = join18(libDir, libName);
24138
+ const base = join17(libDir, libName);
23445
24139
  if (existsSync11(base)) {
23446
24140
  try {
23447
24141
  const real = realpathSync7(base);
@@ -23481,18 +24175,18 @@ function pathEntriesForPlatform() {
23481
24175
  return pathEnvValue().split(delimiter).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
23482
24176
  if (!entry || entry === "." || entry.includes("\x00"))
23483
24177
  return false;
23484
- return isAbsolute8(entry) || win323.isAbsolute(entry);
24178
+ return isAbsolute7(entry) || win324.isAbsolute(entry);
23485
24179
  });
23486
24180
  }
23487
24181
  function isWindowsSystem32Directory(dir) {
23488
24182
  if (process.platform !== "win32")
23489
24183
  return false;
23490
- const normalizedDir = win323.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
24184
+ const normalizedDir = win324.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
23491
24185
  const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
23492
24186
  return windowsRoots.some((root) => {
23493
24187
  if (!root)
23494
24188
  return false;
23495
- return normalizedDir === win323.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
24189
+ return normalizedDir === win324.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
23496
24190
  });
23497
24191
  }
23498
24192
  function directoryContainsLibrary(dir, libName) {
@@ -23508,10 +24202,10 @@ function directoryContainsLibrary(dir, libName) {
23508
24202
  }
23509
24203
  }
23510
24204
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
23511
- if (existsSync11(join18(ortVersionDir, libName)))
24205
+ if (existsSync11(join17(ortVersionDir, libName)))
23512
24206
  return ortVersionDir;
23513
- const libSubdir = join18(ortVersionDir, "lib");
23514
- if (existsSync11(join18(libSubdir, libName)))
24207
+ const libSubdir = join17(ortVersionDir, "lib");
24208
+ if (existsSync11(join17(libSubdir, libName)))
23515
24209
  return libSubdir;
23516
24210
  return ortVersionDir;
23517
24211
  }
@@ -23526,12 +24220,12 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23526
24220
  } else if (process.platform === "win32") {
23527
24221
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
23528
24222
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
23529
- searchPaths.push(join18(programFiles, "onnxruntime", "lib"), join18(programFiles, "Microsoft ONNX Runtime", "lib"), join18(programFiles, "Microsoft Machine Learning", "lib"), join18(programFilesX86, "onnxruntime", "lib"), ...(() => {
24223
+ searchPaths.push(join17(programFiles, "onnxruntime", "lib"), join17(programFiles, "Microsoft ONNX Runtime", "lib"), join17(programFiles, "Microsoft Machine Learning", "lib"), join17(programFilesX86, "onnxruntime", "lib"), ...(() => {
23530
24224
  const nugetPaths = [];
23531
24225
  const userProfile = process.env.USERPROFILE ?? "";
23532
24226
  if (!userProfile)
23533
24227
  return nugetPaths;
23534
- const nugetPackageDir = join18(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
24228
+ const nugetPackageDir = join17(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
23535
24229
  if (!existsSync11(nugetPackageDir))
23536
24230
  return nugetPaths;
23537
24231
  try {
@@ -23540,7 +24234,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23540
24234
  continue;
23541
24235
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
23542
24236
  continue;
23543
- nugetPaths.push(join18(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join18(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
24237
+ nugetPaths.push(join17(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join17(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
23544
24238
  }
23545
24239
  } catch (err) {
23546
24240
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -23552,7 +24246,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23552
24246
  const normalizeCase = process.platform === "win32" || process.platform === "darwin";
23553
24247
  const seen = new Set;
23554
24248
  const uniquePaths = searchPaths.filter((p) => {
23555
- let key = resolve13(p).replace(/[/\\]+$/, "");
24249
+ let key = resolve12(p).replace(/[/\\]+$/, "");
23556
24250
  if (normalizeCase)
23557
24251
  key = key.toLowerCase();
23558
24252
  if (seen.has(key))
@@ -23562,7 +24256,7 @@ function findSystemOnnxRuntime(libName, searchPathsOverride) {
23562
24256
  });
23563
24257
  const unknownVersionPaths = [];
23564
24258
  for (const dir of uniquePaths) {
23565
- const libPath = join18(dir, libName);
24259
+ const libPath = join17(dir, libName);
23566
24260
  if (process.platform === "win32") {
23567
24261
  if (!directoryContainsLibrary(dir, libName))
23568
24262
  continue;
@@ -23641,19 +24335,19 @@ function validateExtractedTree(stagingRoot) {
23641
24335
  const walk = (dir) => {
23642
24336
  const entries = readdirSync4(dir);
23643
24337
  for (const entry of entries) {
23644
- const fullPath = join18(dir, entry);
24338
+ const fullPath = join17(dir, entry);
23645
24339
  const lst = lstatSync3(fullPath);
23646
24340
  if (lst.isSymbolicLink()) {
23647
24341
  const linkTarget = readlinkSync2(fullPath);
23648
- const resolvedTarget = resolve13(dirname11(fullPath), linkTarget);
23649
- const rel = relative5(realRoot, resolvedTarget);
23650
- if (relativePathEscapesRoot(rel) || win323.isAbsolute(rel)) {
24342
+ const resolvedTarget = resolve12(dirname11(fullPath), linkTarget);
24343
+ const rel = relative4(realRoot, resolvedTarget);
24344
+ if (relativePathEscapesRoot(rel) || win324.isAbsolute(rel)) {
23651
24345
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
23652
24346
  }
23653
24347
  continue;
23654
24348
  }
23655
- const rel = relative5(realRoot, fullPath);
23656
- if (relativePathEscapesRoot(rel) || win323.isAbsolute(rel)) {
24349
+ const rel = relative4(realRoot, fullPath);
24350
+ if (relativePathEscapesRoot(rel) || win324.isAbsolute(rel)) {
23657
24351
  throw new Error(`extracted entry ${fullPath} escapes staging root`);
23658
24352
  }
23659
24353
  if (lst.isDirectory()) {
@@ -23678,11 +24372,11 @@ async function downloadOnnxRuntime(info, targetDir) {
23678
24372
  const url = `https://github.com/${ORT_REPO}/releases/download/v${ORT_VERSION}/${info.assetName}.${info.archiveType === "tgz" ? "tgz" : "zip"}`;
23679
24373
  log(`Downloading ONNX Runtime v${ORT_VERSION} for ${process.platform}/${process.arch}...`);
23680
24374
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}${randomBytes3(4).toString("hex")}`;
23681
- const extractionRoot = join18(tmpDir, "extract");
23682
- const stagedInstallDir = join18(tmpDir, "install");
24375
+ const extractionRoot = join17(tmpDir, "extract");
24376
+ const stagedInstallDir = join17(tmpDir, "install");
23683
24377
  try {
23684
24378
  privateMkdirSync(extractionRoot);
23685
- const archivePath = join18(tmpDir, `onnxruntime.${info.archiveType}`);
24379
+ const archivePath = join17(tmpDir, `onnxruntime.${info.archiveType}`);
23686
24380
  await downloadFileWithCap(url, archivePath);
23687
24381
  const archiveSha256 = await sha256File(archivePath);
23688
24382
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
@@ -23695,7 +24389,7 @@ async function downloadOnnxRuntime(info, targetDir) {
23695
24389
  unlinkSync5(archivePath);
23696
24390
  } catch {}
23697
24391
  validateExtractedTree(extractionRoot);
23698
- const extractedDir = join18(extractionRoot, info.assetName, "lib");
24392
+ const extractedDir = join17(extractionRoot, info.assetName, "lib");
23699
24393
  if (!existsSync11(extractedDir)) {
23700
24394
  throw new Error(`Expected directory not found: ${extractedDir}`);
23701
24395
  }
@@ -23703,7 +24397,7 @@ async function downloadOnnxRuntime(info, targetDir) {
23703
24397
  const realFiles = [];
23704
24398
  const symlinks = [];
23705
24399
  for (const libFile of libFiles) {
23706
- const src = join18(extractedDir, libFile);
24400
+ const src = join17(extractedDir, libFile);
23707
24401
  try {
23708
24402
  const stat = lstatSync3(src);
23709
24403
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
@@ -23718,14 +24412,14 @@ async function downloadOnnxRuntime(info, targetDir) {
23718
24412
  }
23719
24413
  }
23720
24414
  copyOnnxLibraries(info, extractedDir, stagedInstallDir, realFiles, symlinks);
23721
- const libPath = join18(stagedInstallDir, info.libName);
24415
+ const libPath = join17(stagedInstallDir, info.libName);
23722
24416
  const libHash = await sha256File(libPath);
23723
24417
  if (libHash !== info.librarySha256) {
23724
24418
  throw new Error(`onnx runtime library hash mismatch at ${libPath}: sha256 ${libHash}, ` + `expected the pinned ${info.librarySha256} for ${info.assetName}`);
23725
24419
  }
23726
24420
  writeOnnxInstalledMeta(stagedInstallDir, ORT_VERSION, libHash, archiveSha256);
23727
24421
  publishOnnxRuntime(stagedInstallDir, targetDir);
23728
- writeStampedFileDigest(join18(targetDir, info.libName), libHash);
24422
+ writeStampedFileDigest(join17(targetDir, info.libName), libHash);
23729
24423
  rmSync4(tmpDir, { recursive: true, force: true });
23730
24424
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
23731
24425
  return targetDir;
@@ -23767,8 +24461,8 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
23767
24461
  const requiredLibs = new Set([info.libName]);
23768
24462
  privateMkdirSync(targetDir);
23769
24463
  for (const libFile of realFiles) {
23770
- const src = join18(extractedDir, libFile);
23771
- const dst = join18(targetDir, libFile);
24464
+ const src = join17(extractedDir, libFile);
24465
+ const dst = join17(targetDir, libFile);
23772
24466
  try {
23773
24467
  if (copyFile === copyFileSync4)
23774
24468
  privateCopyFileSync(src, dst);
@@ -23787,12 +24481,12 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
23787
24481
  }
23788
24482
  const targetRoot = realpathSync7(targetDir);
23789
24483
  for (const link of symlinks) {
23790
- const dst = join18(targetDir, link.name);
24484
+ const dst = join17(targetDir, link.name);
23791
24485
  try {
23792
24486
  unlinkSync5(dst);
23793
24487
  } catch {}
23794
- const dstForContainment = join18(targetRoot, link.name);
23795
- const resolvedTarget = resolve13(dirname11(dstForContainment), link.target);
24488
+ const dstForContainment = join17(targetRoot, link.name);
24489
+ const resolvedTarget = resolve12(dirname11(dstForContainment), link.target);
23796
24490
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
23797
24491
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
23798
24492
  if (requiredLibs.has(link.name)) {
@@ -23812,7 +24506,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
23812
24506
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
23813
24507
  }
23814
24508
  }
23815
- const requiredPath = join18(targetDir, info.libName);
24509
+ const requiredPath = join17(targetDir, info.libName);
23816
24510
  if (!existsSync11(requiredPath)) {
23817
24511
  rmSync4(targetDir, { recursive: true, force: true });
23818
24512
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
@@ -23840,7 +24534,7 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
23840
24534
  ...sha256 ? { sha256 } : {},
23841
24535
  archiveSha256
23842
24536
  };
23843
- writeFileSync6(join18(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), {
24537
+ writeFileSync6(join17(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), {
23844
24538
  encoding: "utf8",
23845
24539
  mode: PRIVATE_FILE_MODE
23846
24540
  });
@@ -23849,7 +24543,7 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
23849
24543
  }
23850
24544
  }
23851
24545
  function readOnnxInstalledMeta(installDir) {
23852
- const path = join18(installDir, ONNX_INSTALLED_META_FILE);
24546
+ const path = join17(installDir, ONNX_INSTALLED_META_FILE);
23853
24547
  try {
23854
24548
  if (!statSync10(path).isFile())
23855
24549
  return null;
@@ -25705,7 +26399,7 @@ function isBgCompletion(value) {
25705
26399
  function formatCompletion(completion) {
25706
26400
  const status = formatStatus(completion);
25707
26401
  const duration = formatDuration(completion);
25708
- const header = `- task ${completion.task_id} (${status}${duration ? `, ${duration}` : ""})`;
26402
+ const header = formatUnknownPtyExit(completion.task_id, completion) ?? `- task ${completion.task_id} (${status}${duration ? `, ${duration}` : ""})`;
25709
26403
  const previewBlock = formatOutputPreview(completion);
25710
26404
  const descendantWarning = completion.live_descendants_summary ? ` ${completion.live_descendants_summary}` : "";
25711
26405
  const captureWarning = completion.output_incomplete || completion.status === "failed" && completion.status_reason ? ` [${completion.status_reason || "PTY output may be incomplete"}]` : "";
@@ -25772,9 +26466,9 @@ import {
25772
26466
  // package.json
25773
26467
  var package_default = {
25774
26468
  name: "@cortexkit/aft-pi",
25775
- version: "0.64.0",
26469
+ version: "0.65.0",
25776
26470
  type: "module",
25777
- description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
26471
+ description: "Pi coding agent extension for Agent Foundational Toolkit (AFT) — tree-sitter and LSP-powered code analysis",
25778
26472
  main: "dist/index.js",
25779
26473
  types: "dist/index.d.ts",
25780
26474
  license: "MIT",
@@ -25796,18 +26490,18 @@ var package_default = {
25796
26490
  "test:e2e": "bun test src/__tests__/e2e/"
25797
26491
  },
25798
26492
  dependencies: {
25799
- "@cortexkit/aft-bridge": "0.64.0",
26493
+ "@cortexkit/aft-bridge": "0.65.0",
25800
26494
  "comment-json": "^5.0.0",
25801
26495
  diff: "^8.0.4",
25802
26496
  zod: "^4.4.3"
25803
26497
  },
25804
26498
  optionalDependencies: {
25805
- "@cortexkit/aft-darwin-arm64": "0.64.0",
25806
- "@cortexkit/aft-darwin-x64": "0.64.0",
25807
- "@cortexkit/aft-linux-arm64": "0.64.0",
25808
- "@cortexkit/aft-linux-x64": "0.64.0",
25809
- "@cortexkit/aft-win32-arm64": "0.64.0",
25810
- "@cortexkit/aft-win32-x64": "0.64.0"
26499
+ "@cortexkit/aft-darwin-arm64": "0.65.0",
26500
+ "@cortexkit/aft-darwin-x64": "0.65.0",
26501
+ "@cortexkit/aft-linux-arm64": "0.65.0",
26502
+ "@cortexkit/aft-linux-x64": "0.65.0",
26503
+ "@cortexkit/aft-win32-arm64": "0.65.0",
26504
+ "@cortexkit/aft-win32-x64": "0.65.0"
25811
26505
  },
25812
26506
  devDependencies: {
25813
26507
  "@earendil-works/pi-coding-agent": "^0.80.2",
@@ -26010,11 +26704,11 @@ function coerceAftStatus(response) {
26010
26704
  warm_entries: readNumber(symbolCache.warm_entries)
26011
26705
  },
26012
26706
  storage_dir: readNullableString(response.storage_dir),
26013
- checkpoints_total: readNumber(response.checkpoints_total),
26707
+ checkpoints_total: readOptionalNumber(response.checkpoints_total),
26014
26708
  session: {
26015
26709
  id: readString(session.id, "__default__"),
26016
26710
  tracked_files: readNumber(session.tracked_files),
26017
- checkpoints: readNumber(session.checkpoints)
26711
+ checkpoints: readOptionalNumber(session.checkpoints)
26018
26712
  },
26019
26713
  compression: readCompression(response.compression),
26020
26714
  status_bar: readStatusBar(response.status_bar ?? response.status_bar_values)
@@ -26100,7 +26794,7 @@ import { Type } from "typebox";
26100
26794
  // src/config.ts
26101
26795
  import { existsSync as existsSync12, readFileSync as readFileSync11 } from "node:fs";
26102
26796
  import { homedir as homedir14 } from "node:os";
26103
- import { isAbsolute as isAbsolute9 } from "node:path";
26797
+ import { isAbsolute as isAbsolute8 } from "node:path";
26104
26798
  var import_comment_json = __toESM(require_src2(), 1);
26105
26799
 
26106
26800
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/core/core.js
@@ -30966,9 +31660,9 @@ var ConfigureWarningsDeliveryEnum = _enum(["toast", "log", "chat"]);
30966
31660
  var IndexKindSchema = _enum(["search", "semantic", "callgraph"]);
30967
31661
  function isSupportedAbsoluteIndexPath(path) {
30968
31662
  if (path === "~" || path.startsWith("~/") || path.startsWith("~\\")) {
30969
- return isAbsolute9(homedir14());
31663
+ return isAbsolute8(homedir14());
30970
31664
  }
30971
- return isAbsolute9(path);
31665
+ return isAbsolute8(path);
30972
31666
  }
30973
31667
  var IndexRootSchema = object({
30974
31668
  path: string2().refine(isSupportedAbsoluteIndexPath, {
@@ -31025,6 +31719,7 @@ var LspServerEntrySchema = object({
31025
31719
  initialization_options: unknown().optional()
31026
31720
  });
31027
31721
  var LspConfigSchema = object({
31722
+ max_servers: number2().int().nonnegative().optional(),
31028
31723
  idle_minutes: union([
31029
31724
  number2().int().transform((value) => Math.min(1440, Math.max(5, value))),
31030
31725
  literal("never")
@@ -31108,7 +31803,7 @@ var SubcConfigSchema = object({
31108
31803
  connection_file: string2().optional()
31109
31804
  });
31110
31805
  var GhShimConfigSchema = object({
31111
- binary_path: string2().trim().refine(isAbsolute9, "gh_shim.binary_path must be absolute").optional()
31806
+ binary_path: string2().trim().refine(isAbsolute8, "gh_shim.binary_path must be absolute").optional()
31112
31807
  });
31113
31808
  var RemoteExecConfigSchema = object({
31114
31809
  enabled: boolean2().optional(),
@@ -31159,13 +31854,6 @@ var IdleConfigSchema = object({
31159
31854
  root_ttl_minutes: number2().int().optional().transform((value) => value === undefined ? undefined : clampIdleRootTtlMinutes(value)),
31160
31855
  checkout_hours: number2().int().optional().transform((value) => value === undefined ? undefined : clampIdleCheckoutHours(value))
31161
31856
  });
31162
- var ViewsConfigSchema = object({
31163
- enabled: boolean2().optional(),
31164
- callgraph_copies: number2().int().optional()
31165
- });
31166
- var WorktreeConfigSchema = object({
31167
- ram_overlay: boolean2().optional()
31168
- });
31169
31857
  var BackupConfigSchema = object({
31170
31858
  enabled: boolean2().optional(),
31171
31859
  max_depth: number2().int().positive().optional(),
@@ -31186,12 +31874,10 @@ var AftConfigFieldsSchema = object({
31186
31874
  indexes: IndexesConfigSchema.optional(),
31187
31875
  index: IndexConfigSchema.optional(),
31188
31876
  storage: object({ cache_dir: string2().nullable().optional() }).optional(),
31189
- views: ViewsConfigSchema.optional(),
31190
31877
  callgraph_chunk_size: number2().optional(),
31191
31878
  inspect: InspectConfigSchema.optional(),
31192
31879
  idle: IdleConfigSchema.optional(),
31193
31880
  backup: BackupConfigSchema.optional(),
31194
- worktree: WorktreeConfigSchema.optional(),
31195
31881
  sandbox: SandboxConfigSchema.optional(),
31196
31882
  bash: BashConfigSchema.optional(),
31197
31883
  experimental: ExperimentalConfigSchema.optional(),
@@ -31347,6 +32033,9 @@ function loadConfigFromPath(configPath, tier) {
31347
32033
  throw new ConfigRejectedError(["invalid_config_document"], configPath);
31348
32034
  }
31349
32035
  const removed = removedConfigKeyErrors(cleanConfig, undefined, false);
32036
+ if (tier === "user") {
32037
+ removed.push(...removedConfigKeyErrors(cleanConfig).filter((error) => [...REMOVED_DATA_LAYER_PATHS, ...DATA_LAYER_RETIRED_PATHS].some((path) => error.endsWith(`${path}; run npx @cortexkit/aft doctor --fix`))));
32038
+ }
31350
32039
  if (removed.length) {
31351
32040
  throw new ConfigRejectedError(removed);
31352
32041
  }
@@ -31373,14 +32062,7 @@ function loadConfigFromPath(configPath, tier) {
31373
32062
  if (translation.legacyInput) {
31374
32063
  log2(`Config ${configPath} uses retired keys (${translation.retiredKeys.join(", ")}); applied their current equivalents in memory`);
31375
32064
  }
31376
- if (translation.removedKeys.length > 0) {
31377
- configLoadNotices.push({
31378
- configPath,
31379
- digest: removedConfigKeysNoticeDigest(translation),
31380
- message: removedConfigKeysNoticeMessage(configPath, translation)
31381
- });
31382
- }
31383
- } else if (translation.legacyInput || translation.removedKeys.length > 0) {
32065
+ } else if (translation.legacyInput) {
31384
32066
  configLoadNotices.push({
31385
32067
  configPath,
31386
32068
  digest: noticeDigest(projection),
@@ -31465,6 +32147,9 @@ function mergeSemanticConfig(base, override) {
31465
32147
  }
31466
32148
  function mergeLspConfig(base, override) {
31467
32149
  const projectSafe = {};
32150
+ if (override?.max_servers !== undefined && override.max_servers <= (base?.max_servers ?? 8)) {
32151
+ projectSafe.max_servers = override.max_servers;
32152
+ }
31468
32153
  if (override?.python !== undefined)
31469
32154
  projectSafe.python = override.python;
31470
32155
  if (override?.diagnostics_on_edit !== undefined) {
@@ -31485,15 +32170,6 @@ function mergeLspConfig(base, override) {
31485
32170
  return;
31486
32171
  return Object.fromEntries(Object.entries(lsp).filter(([, v]) => v !== undefined));
31487
32172
  }
31488
- function mergeWorktreeConfig(baseWorktree, overrideWorktree) {
31489
- if (baseWorktree === undefined && overrideWorktree === undefined)
31490
- return;
31491
- if (overrideWorktree === undefined)
31492
- return baseWorktree;
31493
- if (baseWorktree === undefined)
31494
- return overrideWorktree;
31495
- return { ...baseWorktree, ...overrideWorktree };
31496
- }
31497
32173
  function mergeIdleConfig(baseIdle, overrideIdle) {
31498
32174
  const merged = {
31499
32175
  root_ttl_minutes: overrideIdle?.root_ttl_minutes ?? baseIdle?.root_ttl_minutes,
@@ -31609,11 +32285,9 @@ var PROJECT_SAFE_TOP_LEVEL_FIELDS = new Set([
31609
32285
  "revision_reads",
31610
32286
  "validate_on_edit",
31611
32287
  "configure_warnings_delivery",
31612
- "views",
31613
32288
  "callgraph_chunk_size",
31614
32289
  "inspect",
31615
32290
  "idle",
31616
- "worktree",
31617
32291
  "git",
31618
32292
  "pi",
31619
32293
  "experimental",
@@ -31728,22 +32402,18 @@ function mergeConfigs(base, override) {
31728
32402
  bash.project_env = projectEnv;
31729
32403
  }
31730
32404
  const inspect = mergeInspectConfig(base.inspect, override.inspect);
31731
- const worktree = mergeWorktreeConfig(base.worktree, override.worktree);
31732
32405
  const idle = mergeIdleConfig(base.idle, override.idle);
31733
32406
  const sandbox = mergeSandboxConfig(base.sandbox, override.sandbox);
31734
32407
  const remoteExec = mergeRemoteExecConfig(base.remote_exec, override.remote_exec);
31735
32408
  const backup = mergeProjectBackupConfig(base.backup, override.backup);
31736
32409
  const pi = mergePiConfig(base.pi, override.pi);
31737
- const views = base.views !== undefined || override.views !== undefined ? { ...base.views, ...override.views } : undefined;
31738
32410
  const bridge = base.bridge;
31739
32411
  const safeOverride = pickProjectSafeFields(override);
31740
32412
  delete safeOverride.indexes;
31741
32413
  delete safeOverride.bash;
31742
32414
  delete safeOverride.inspect;
31743
- delete safeOverride.worktree;
31744
32415
  delete safeOverride.idle;
31745
32416
  delete safeOverride.pi;
31746
- delete safeOverride.views;
31747
32417
  return {
31748
32418
  ...base,
31749
32419
  ...safeOverride,
@@ -31752,13 +32422,11 @@ function mergeConfigs(base, override) {
31752
32422
  ...lsp ? { lsp } : {},
31753
32423
  ...bash !== undefined ? { bash } : {},
31754
32424
  ...inspect !== undefined ? { inspect } : {},
31755
- ...worktree !== undefined ? { worktree } : {},
31756
32425
  ...idle !== undefined ? { idle } : {},
31757
32426
  ...sandbox !== undefined ? { sandbox } : {},
31758
32427
  ...remoteExec !== undefined ? { remote_exec: remoteExec } : {},
31759
32428
  ...backup !== undefined ? { backup } : {},
31760
32429
  ...pi !== undefined ? { pi } : {},
31761
- ...views !== undefined ? { views } : {},
31762
32430
  experimental,
31763
32431
  semantic,
31764
32432
  search,
@@ -32076,7 +32744,7 @@ function detectPiHarness(api) {
32076
32744
  // src/omp-approval.ts
32077
32745
  import { realpathSync as realpathSync8 } from "node:fs";
32078
32746
  import { homedir as homedir15 } from "node:os";
32079
- import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute10, join as join19, relative as relative6, resolve as resolve14, sep as sep2 } from "node:path";
32747
+ import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute9, join as join18, relative as relative5, resolve as resolve13, sep as sep2 } from "node:path";
32080
32748
  var OMP_TOOL_TIERS = {
32081
32749
  read: "read",
32082
32750
  grep: "read",
@@ -32121,7 +32789,7 @@ function expandPath(value) {
32121
32789
  if (decoded === "~")
32122
32790
  return homedir15();
32123
32791
  if (decoded.startsWith("~/") || decoded.startsWith(`~${sep2}`))
32124
- return resolve14(homedir15(), decoded.slice(2));
32792
+ return resolve13(homedir15(), decoded.slice(2));
32125
32793
  return decoded;
32126
32794
  }
32127
32795
  function realLocation(path) {
@@ -32129,7 +32797,7 @@ function realLocation(path) {
32129
32797
  let current = path;
32130
32798
  for (;; ) {
32131
32799
  try {
32132
- return missing.length > 0 ? join19(realpathSync8(current), ...missing) : realpathSync8(current);
32800
+ return missing.length > 0 ? join18(realpathSync8(current), ...missing) : realpathSync8(current);
32133
32801
  } catch (error) {
32134
32802
  if (error.code !== "ENOENT")
32135
32803
  throw error;
@@ -32149,11 +32817,11 @@ function namesOutsidePath(root, value) {
32149
32817
  const expanded = expandPath(value);
32150
32818
  if (expanded.startsWith("file:"))
32151
32819
  return false;
32152
- const absolute = isAbsolute10(expanded) ? expanded : resolve14(root, expanded);
32153
- if (relativePathEscapesRoot(relative6(root, absolute)))
32820
+ const absolute = isAbsolute9(expanded) ? expanded : resolve13(root, expanded);
32821
+ if (relativePathEscapesRoot(relative5(root, absolute)))
32154
32822
  return true;
32155
32823
  try {
32156
- return relativePathEscapesRoot(relative6(realLocation(root), realLocation(absolute)));
32824
+ return relativePathEscapesRoot(relative5(realLocation(root), realLocation(absolute)));
32157
32825
  } catch {
32158
32826
  return true;
32159
32827
  }
@@ -32724,8 +33392,8 @@ function renderInner(s, error, theme, innerWidth) {
32724
33392
  left2.push(kv("symbol cache", `${formatCountShort(s.symbol_cache.local_entries)} local · ${formatCountShort(s.symbol_cache.warm_entries)} warm`, theme));
32725
33393
  right2.push(theme.fg("muted", "Current session"));
32726
33394
  right2.push(kv("tracked files", String(s.session.tracked_files), theme));
32727
- right2.push(kv("checkpoints", String(s.session.checkpoints), theme));
32728
- right2.push(kv("all-session", String(s.checkpoints_total), theme));
33395
+ right2.push(kv("checkpoints", s.session.checkpoints?.toString() ?? "—", theme));
33396
+ right2.push(kv("all-session", s.checkpoints_total?.toString() ?? "—", theme));
32729
33397
  for (const line of renderColumns(left2, right2, colWidth))
32730
33398
  lines.push(line);
32731
33399
  lines.push("");
@@ -32888,7 +33556,7 @@ function registerStatusCommand(pi, ctx) {
32888
33556
 
32889
33557
  // src/lsp-auto-install.ts
32890
33558
  import { existsSync as existsSync15, mkdirSync as mkdirSync7, renameSync as renameSync10, rmSync as rmSync7, statSync as statSync12, writeFileSync as writeFileSync9 } from "node:fs";
32891
- import { join as join22 } from "node:path";
33559
+ import { join as join21 } from "node:path";
32892
33560
 
32893
33561
  // src/lsp-cache.ts
32894
33562
  import { randomUUID as randomUUID3 } from "node:crypto";
@@ -32903,7 +33571,7 @@ import {
32903
33571
  unlinkSync as unlinkSync6,
32904
33572
  writeFileSync as writeFileSync8
32905
33573
  } from "node:fs";
32906
- import { join as join20 } from "node:path";
33574
+ import { join as join19 } from "node:path";
32907
33575
 
32908
33576
  // src/atomic-file.ts
32909
33577
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -32926,18 +33594,18 @@ function lspCacheRoot() {
32926
33594
  return getAftLspPackagesDir();
32927
33595
  }
32928
33596
  function lspPackageDir(npmPackage) {
32929
- return join20(lspCacheRoot(), encodeURIComponent(npmPackage));
33597
+ return join19(lspCacheRoot(), encodeURIComponent(npmPackage));
32930
33598
  }
32931
33599
  function lspBinaryPath(npmPackage, binary) {
32932
- return join20(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
33600
+ return join19(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
32933
33601
  }
32934
33602
  function lspBinDir(npmPackage) {
32935
- return join20(lspPackageDir(npmPackage), "node_modules", ".bin");
33603
+ return join19(lspPackageDir(npmPackage), "node_modules", ".bin");
32936
33604
  }
32937
33605
  function isInstalled(npmPackage, binary) {
32938
33606
  for (const candidate of lspBinaryCandidates(binary)) {
32939
33607
  try {
32940
- if (statSync11(join20(lspBinDir(npmPackage), candidate)).isFile())
33608
+ if (statSync11(join19(lspBinDir(npmPackage), candidate)).isFile())
32941
33609
  return true;
32942
33610
  } catch {}
32943
33611
  }
@@ -32957,13 +33625,13 @@ function writeInstalledMetaIn(installDir, version, sha256) {
32957
33625
  installedAt: new Date().toISOString(),
32958
33626
  ...sha256 ? { sha256 } : {}
32959
33627
  };
32960
- writeAtomicFile(join20(installDir, INSTALLED_META_FILE), JSON.stringify(meta));
33628
+ writeAtomicFile(join19(installDir, INSTALLED_META_FILE), JSON.stringify(meta));
32961
33629
  } catch (err) {
32962
33630
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
32963
33631
  }
32964
33632
  }
32965
33633
  function readInstalledMetaIn(installDir) {
32966
- const path = join20(installDir, INSTALLED_META_FILE);
33634
+ const path = join19(installDir, INSTALLED_META_FILE);
32967
33635
  try {
32968
33636
  if (!statSync11(path).isFile())
32969
33637
  return null;
@@ -32987,7 +33655,7 @@ function readInstalledMeta(packageKey) {
32987
33655
  return readInstalledMetaIn(lspPackageDir(packageKey));
32988
33656
  }
32989
33657
  function lockPath(npmPackage) {
32990
- return join20(lspPackageDir(npmPackage), ".aft-installing");
33658
+ return join19(lspPackageDir(npmPackage), ".aft-installing");
32991
33659
  }
32992
33660
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
32993
33661
  function acquireInstallLock(lockKey) {
@@ -33118,7 +33786,7 @@ var AUTO_INSTALL_STAMP_FILE = "last-lsp-autoinstall.json";
33118
33786
  var AUTO_INSTALL_WINDOW_MS = 60 * 1000;
33119
33787
  var AUTO_INSTALL_LOCK_STALE_MS = 30 * 60 * 1000;
33120
33788
  function autoInstallStampPath() {
33121
- return join20(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
33789
+ return join19(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
33122
33790
  }
33123
33791
  function hasRecentAutoInstallStamp(path) {
33124
33792
  try {
@@ -33219,7 +33887,7 @@ function claimLspAutoInstallPass() {
33219
33887
  }
33220
33888
  var VERSION_CHECK_FILE = ".aft-version-check";
33221
33889
  function readVersionCheck(npmPackage) {
33222
- const file = join20(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33890
+ const file = join19(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33223
33891
  try {
33224
33892
  const raw = readFileSync12(file, "utf8");
33225
33893
  const parsed = JSON.parse(raw);
@@ -33236,7 +33904,7 @@ function readVersionCheck(npmPackage) {
33236
33904
  }
33237
33905
  function writeVersionCheck(npmPackage, latest) {
33238
33906
  mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
33239
- const file = join20(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33907
+ const file = join19(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
33240
33908
  const record = {
33241
33909
  last_checked: new Date().toISOString(),
33242
33910
  latest_eligible: latest
@@ -33353,7 +34021,7 @@ function isVersionSupported(spec, version) {
33353
34021
 
33354
34022
  // src/lsp-project-relevance.ts
33355
34023
  import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync13 } from "node:fs";
33356
- import { join as join21 } from "node:path";
34024
+ import { join as join20 } from "node:path";
33357
34025
  var MAX_WALK_DIRS = 200;
33358
34026
  var MAX_WALK_DEPTH = 4;
33359
34027
  var NOISE_DIRS = new Set([
@@ -33370,7 +34038,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
33370
34038
  if (!rootMarkers)
33371
34039
  return false;
33372
34040
  for (const marker of rootMarkers) {
33373
- if (existsSync14(join21(projectRoot, marker)))
34041
+ if (existsSync14(join20(projectRoot, marker)))
33374
34042
  return true;
33375
34043
  }
33376
34044
  return false;
@@ -33394,7 +34062,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
33394
34062
  }
33395
34063
  function readPackageJson(projectRoot) {
33396
34064
  try {
33397
- const raw = readFileSync13(join21(projectRoot, "package.json"), "utf8");
34065
+ const raw = readFileSync13(join20(projectRoot, "package.json"), "utf8");
33398
34066
  const parsed = JSON.parse(raw);
33399
34067
  if (typeof parsed !== "object" || parsed === null)
33400
34068
  return null;
@@ -33424,7 +34092,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
33424
34092
  for (const entry of entries) {
33425
34093
  if (entry.isDirectory()) {
33426
34094
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
33427
- queue.push({ dir: join21(current.dir, entry.name), depth: current.depth + 1 });
34095
+ queue.push({ dir: join20(current.dir, entry.name), depth: current.depth + 1 });
33428
34096
  }
33429
34097
  continue;
33430
34098
  }
@@ -33557,7 +34225,7 @@ async function resolveTargetVersion(spec, config, fetchImpl = fetch) {
33557
34225
  }
33558
34226
  function ensureInstallAnchor(cwd) {
33559
34227
  try {
33560
- const stub = join22(cwd, "package.json");
34228
+ const stub = join21(cwd, "package.json");
33561
34229
  if (!existsSync15(stub)) {
33562
34230
  writeFileSync9(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
33563
34231
  `);
@@ -33784,10 +34452,10 @@ function sha256OfFileSync(path) {
33784
34452
  }
33785
34453
  function quarantineCachedNpmInstall(spec, reason) {
33786
34454
  const packageDir = lspPackageDir(spec.npm);
33787
- const dest = join22(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
34455
+ const dest = join21(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
33788
34456
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
33789
34457
  try {
33790
- mkdirSync7(join22(dest, ".."), { recursive: true });
34458
+ mkdirSync7(join21(dest, ".."), { recursive: true });
33791
34459
  rmSync7(dest, { recursive: true, force: true });
33792
34460
  renameSync10(packageDir, dest);
33793
34461
  } catch (err) {
@@ -34522,7 +35190,7 @@ import { Type as Type4 } from "typebox";
34522
35190
  // src/tools/hoisted.ts
34523
35191
  import { stat as stat4 } from "node:fs/promises";
34524
35192
  import { homedir as homedir16 } from "node:os";
34525
- import { isAbsolute as isAbsolute11, relative as relative7, resolve as resolve15, sep as sep3 } from "node:path";
35193
+ import { isAbsolute as isAbsolute10, relative as relative6, resolve as resolve14, sep as sep3 } from "node:path";
34526
35194
  import {
34527
35195
  renderDiff as renderDiff2
34528
35196
  } from "@earendil-works/pi-coding-agent";
@@ -34700,7 +35368,7 @@ function modelSupportsImages(extCtx) {
34700
35368
  }
34701
35369
  var NON_VISION_IMAGE_NOTE = "[Current model does not support images. The image will be omitted from this request.]";
34702
35370
  function containsPath(parent, child) {
34703
- const rel = relative7(parent, child);
35371
+ const rel = relative6(parent, child);
34704
35372
  return !relativePathEscapesRoot(rel);
34705
35373
  }
34706
35374
  function normalizePathInput(path) {
@@ -34710,13 +35378,13 @@ function normalizePathInput(path) {
34710
35378
  if (decoded === "~")
34711
35379
  return homedir16();
34712
35380
  if (decoded.startsWith(`~${sep3}`) || decoded.startsWith("~/")) {
34713
- return resolve15(homedir16(), decoded.slice(2));
35381
+ return resolve14(homedir16(), decoded.slice(2));
34714
35382
  }
34715
35383
  return decoded;
34716
35384
  }
34717
35385
  function absoluteSearchPath(cwd, target) {
34718
35386
  const expanded = normalizePathInput(target);
34719
- return isAbsolute11(expanded) ? expanded : resolve15(cwd, expanded);
35387
+ return isAbsolute10(expanded) ? expanded : resolve14(cwd, expanded);
34720
35388
  }
34721
35389
  async function searchPathExists(cwd, target) {
34722
35390
  try {
@@ -34772,7 +35440,7 @@ async function assertExternalDirectoryPermission(extCtx, target, options = {}) {
34772
35440
  if (!target)
34773
35441
  return;
34774
35442
  const expanded = normalizePathInput(target);
34775
- const absoluteTarget = isAbsolute11(expanded) ? expanded : resolve15(extCtx.cwd, expanded);
35443
+ const absoluteTarget = isAbsolute10(expanded) ? expanded : resolve14(extCtx.cwd, expanded);
34776
35444
  if (containsPath(extCtx.cwd, absoluteTarget))
34777
35445
  return;
34778
35446
  if (options.restrictToProjectRoot === false)
@@ -34781,7 +35449,7 @@ async function assertExternalDirectoryPermission(extCtx, target, options = {}) {
34781
35449
  }
34782
35450
  async function assertExternalReadPermission(ctx, extCtx, target, restrictToProjectRoot = ctx.config.restrict_to_project_root ?? false) {
34783
35451
  const expanded = normalizePathInput(target);
34784
- const absoluteTarget = isAbsolute11(expanded) ? expanded : resolve15(extCtx.cwd, expanded);
35452
+ const absoluteTarget = isAbsolute10(expanded) ? expanded : resolve14(extCtx.cwd, expanded);
34785
35453
  if (!restrictToProjectRoot || containsPath(extCtx.cwd, absoluteTarget))
34786
35454
  return;
34787
35455
  try {
@@ -36187,6 +36855,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
36187
36855
  }
36188
36856
  }
36189
36857
  const bridgeCommand = spawnContext.command;
36858
+ const workdir = spawnContext.cwd ?? params.workdir;
36190
36859
  let streamed = "";
36191
36860
  let usedHostFallback = false;
36192
36861
  let response;
@@ -36194,7 +36863,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
36194
36863
  response = await withOutsidePermissionOperation(() => callBashWithPermissionLoop(bridge, {
36195
36864
  command: bridgeCommand,
36196
36865
  timeout,
36197
- workdir: spawnContext.cwd ?? params.workdir,
36866
+ workdir,
36198
36867
  env: spawnContext.env,
36199
36868
  description: params.description,
36200
36869
  background: effectiveBackground,
@@ -36286,7 +36955,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
36286
36955
  task_id: taskId
36287
36956
  };
36288
36957
  const output = response.output ?? "";
36289
- return bashResult(usedHostFallback || isPowerShell ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
36958
+ return bashResult(usedHostFallback || isPowerShell ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd, workdir), details);
36290
36959
  },
36291
36960
  renderCall(args, theme, context) {
36292
36961
  return renderBashCall(asString2(args?.command), asString2(args?.description), theme, context);
@@ -36314,8 +36983,8 @@ function registerBashCompanionTools(pi, ctx, enabled = { bashStatus: true, bashW
36314
36983
  pi.registerTool(createBashKillTool(ctx));
36315
36984
  }
36316
36985
  }
36317
- function withBashHints(output, command, aftSearchRegistered, projectRoot) {
36318
- return maybeAppendGrepSearchHint(maybeAppendConflictsHint(output), command, aftSearchRegistered, projectRoot);
36986
+ function withBashHints(output, command, aftSearchRegistered, projectRoot, workdir) {
36987
+ return maybeAppendGrepSearchHint(maybeAppendConflictsHint(output), command, aftSearchRegistered, projectRoot, undefined, workdir);
36319
36988
  }
36320
36989
  function createBashStatusTool(ctx) {
36321
36990
  return {
@@ -36816,7 +37485,7 @@ function formatWaitSummary(taskId, waited, details, watchRole) {
36816
37485
  async function formatBashStatus(extCtx, taskId, details, requestedOutputMode, watchRole) {
36817
37486
  const exit = typeof details.exit_code === "number" ? ` (exit ${details.exit_code})` : "";
36818
37487
  const dur = typeof details.duration_ms === "number" ? ` ${Math.round(details.duration_ms / 1000)}s` : "";
36819
- let text = `Task ${taskId}: ${details.status}${exit}${dur}`;
37488
+ let text = formatUnknownPtyExit(taskId, details) ?? `Task ${taskId}: ${details.status}${exit}${dur}`;
36820
37489
  if (details.live_descendants_summary) {
36821
37490
  text += ` · ${details.live_descendants_summary}`;
36822
37491
  }
@@ -37122,7 +37791,7 @@ function registerFsTools(pi, ctx, surface) {
37122
37791
  recursive: coerceBoolean(params.recursive)
37123
37792
  }, extCtx);
37124
37793
  if (response.success === false) {
37125
- throw new Error(response.text || response.message || "delete failed");
37794
+ throw toolErrorFromResponse("delete", response);
37126
37795
  }
37127
37796
  const deletedEntries = response.deleted ?? [];
37128
37797
  const skipped = response.skipped_files ?? [];
@@ -38398,7 +39067,7 @@ function registerSafetyTool(pi, ctx) {
38398
39067
 
38399
39068
  // src/tools/semantic.ts
38400
39069
  import { homedir as homedir17 } from "node:os";
38401
- import { isAbsolute as isAbsolute12, resolve as resolve16 } from "node:path";
39070
+ import { isAbsolute as isAbsolute11, resolve as resolve15 } from "node:path";
38402
39071
  import { Type as Type13 } from "typebox";
38403
39072
  var FILESYSTEM_SCAN_STATUS = "answered by a filesystem scan";
38404
39073
  function semanticHonestyNote(response, theme) {
@@ -38421,8 +39090,8 @@ function selectedProjectRoot(cwd, pathArg) {
38421
39090
  const target = pathArg?.trim();
38422
39091
  if (!target)
38423
39092
  return canonicalizeProjectRoot(cwd);
38424
- const expanded = target === "~" ? homedir17() : /^~[/\\]/u.test(target) ? resolve16(homedir17(), target.slice(2)) : target;
38425
- return canonicalizeProjectRoot(isAbsolute12(expanded) ? expanded : resolve16(cwd, expanded));
39093
+ const expanded = target === "~" ? homedir17() : /^~[/\\]/u.test(target) ? resolve15(homedir17(), target.slice(2)) : target;
39094
+ return canonicalizeProjectRoot(isAbsolute11(expanded) ? expanded : resolve15(cwd, expanded));
38426
39095
  }
38427
39096
  function continuityKey(projectRoot, query, includeTests, topK) {
38428
39097
  return JSON.stringify([
@@ -39019,93 +39688,52 @@ function registerShutdownCleanup(fn) {
39019
39688
  }
39020
39689
 
39021
39690
  // src/workflow-hints.ts
39022
- var HEADING = "## IMPORTANT NOTICE about your tools";
39691
+ var HEADING = "# Agent Foundational Toolkit";
39023
39692
  function hashlineTagSourceHint(bashRewritesMintTags, isRegistered = () => true) {
39024
39693
  return `**Hashline edit tags**: ${hashlineTagSourceSentence(bashRewritesMintTags, isRegistered)}`;
39025
39694
  }
39026
39695
  var HASHLINE_TAG_SOURCE_HINT = hashlineTagSourceHint(true);
39027
39696
  function buildWorkflowHints(opts) {
39028
- const sections = [];
39029
- const grepName = "grep";
39030
- const bashName = "bash";
39031
- const hasOutline = !opts.absentTools.has("aft_outline");
39032
- const hasZoom = !opts.absentTools.has("aft_zoom");
39033
- const readName = "read";
39034
- const hasRead = !opts.absentTools.has(readName);
39035
- const hasGrep = !opts.absentTools.has(grepName);
39036
- const hasSearch = !opts.absentTools.has("aft_search");
39037
- const hasNavigate = !opts.absentTools.has("aft_callgraph");
39038
- const hasInspect = !opts.absentTools.has("aft_inspect");
39039
- const hasBash = !opts.absentTools.has(bashName);
39040
- const hasBgBash = opts.bashBackgroundEnabled && hasBash && !opts.absentTools.has("bash_status");
39041
- const hasWatch = !opts.absentTools.has("bash_watch");
39042
- const hasWrite = !opts.absentTools.has("bash_write");
39043
- if (hasBash && opts.bashCompressionEnabled) {
39044
- sections.push([
39045
- "**Test/build output**: bash output is auto-compressed for non-piped commands. Piped commands run verbatim and show the pipeline's output. For AFT's test/build summary, run the runner without filters:",
39046
- "- `bun test | grep fail` → run `bun test`",
39047
- "- `cargo test 2>&1 | tail -20` → run `cargo test`",
39048
- "- `npm run build | head -50` → run `npm run build`"
39049
- ].join(`
39050
- `));
39697
+ const has = (name) => !opts.absentTools.has(name);
39698
+ const hasBash = has("bash");
39699
+ const hasBackground = hasBash && opts.bashBackgroundEnabled && has("bash_watch") && has("bash_status");
39700
+ const finding = [];
39701
+ if (has("aft_search")) {
39702
+ finding.push("start with aft_search; it takes concepts, identifiers, regex and literals.");
39051
39703
  }
39052
- if (hasOutline && hasZoom) {
39053
- sections.push(`**Web/URL access**: \`aft_outline({ target: "<url>" })\` first for structure, then \`aft_zoom({ batch: [{ target: "<url>", symbols: "<heading>" }] })\` for the specific section.`);
39054
- }
39055
- if (hasOutline && (hasGrep || hasSearch) && (hasZoom || hasRead)) {
39056
- const searchName = hasSearch ? "aft_search" : grepName;
39057
- const locate = hasSearch ? "`aft_search` is the primary code-search tool: one call auto-routes concepts, identifiers, regex, error strings, and literals." : `\`${grepName}\` (the tool — indexed and ranked) locates code.`;
39058
- const zoomSteer = hasZoom ? ", or `aft_zoom`" : "";
39059
- const searchSteer = hasSearch ? `use \`aft_search\` (concepts, identifiers, regex, literals), \`${readName}\`, \`aft_outline\`${zoomSteer} instead` : `use the \`${grepName}\` tool, \`${readName}\`, \`aft_outline\`${zoomSteer} instead`;
39060
- const bashSteer = hasBash ? ` If you are about to run grep, rg, sed, awk, find, or cat through ${bashName} to locate or read code: STOP — ${searchSteer}.` : "";
39061
- sections.push([
39062
- `**Code exploration**: ${locate} Then \`aft_outline\` for structure → \`${hasZoom ? "aft_zoom" : readName}\` for symbol(s). DO NOT run \`grep\`/\`rg\`/\`find\`/\`sed\`/\`cat\` through \`bash\` to locate or read code — the bash path is unindexed, unranked, serial, and routinely surfaces the wrong hit. Keep \`bash\` for shell facts (git state, file metadata, processes).${bashSteer} Reflex translations:`,
39063
- `- \`grep -rn "handleAuth" src/\` in bash → \`${searchName}({ query: "handleAuth" })\``,
39064
- `- \`find . -name "*.ts" | xargs grep watcher\` in bash → \`${searchName}({ query: "watcher invalidation" })\` (concepts work too)`,
39065
- `- \`sed -n '100,160p' app.ts\` / \`cat app.ts\` in bash → \`${readName}({ path: "app.ts", startLine: 100, endLine: 160 })\``
39066
- ].join(`
39067
- `));
39704
+ if (has("aft_outline") && has("aft_zoom") && has("read")) {
39705
+ finding.push(`${finding.length ? "Then " : ""}aft_outline for structure, aft_zoom for named symbols, read for line ranges.`);
39068
39706
  }
39069
- if (hasInspect) {
39070
- sections.push("**Codebase health & diagnostics**: AFT does not surface compile/type errors automatically after edits — pull them with `aft_inspect`. Run it after a batch of edits and before you run tests or commit, when starting in unfamiliar code, or before a refactor/review. One call summarizes diagnostics (compile/type errors), TODOs, metrics, dead code, unused exports, and duplicates; pass `sections` for focused drill-down and `scope` to actively pull diagnostics for a specific file or directory. Its diagnostics are a fast checkpoint, not the authority — a clean `tsc` / `cargo check` / `pyright` run is the real gate. Dead code, unused exports, duplicates, cycles and complexity are computed only when you call aft_inspect, and the call waits until they are current; nothing refreshes them in the background, so run it again after further edits instead of polling.");
39071
- sections.push("**AFT status bar**: tool results may end with a one-line health bar `[AFT E<errors> W<warnings> | T<todos>]` — an IDE-style glance that appears when a count changes. `E`/`W` are live LSP diagnostics for files touched this session (your universal compile-error signal across every language with an LSP). Dead code, unused exports and duplicates are not on the bar; run `aft_inspect` for them. A `?` in place of a number means that count has no value yet (not zero). When `E>0`, you likely just introduced errors; investigate before moving on.");
39072
- }
39073
- if (hasNavigate) {
39074
- sections.push([
39075
- "Use `aft_callgraph` for code-relationship questions instead of grep + read chains:",
39076
- "- `callers` — find all call sites before changing a function signature",
39077
- "- `impact` — blast radius (which functions/files will need updates)",
39078
- "- `trace_to` — how execution reaches this code; each path runs back to a root labelled main, test, attribute, public API, or no caller found",
39079
- "- `trace_to_symbol` — shortest call path from one symbol to another",
39080
- "- `trace_data` — follow a value through assignments and parameters across files"
39081
- ].join(`
39082
- `));
39083
- }
39084
- if (hasBgBash && hasWatch) {
39085
- sections.push([
39086
- `**Long-running commands** (builds, installs, full test suites): run them in the FOREGROUND — use \`${bashName}({ command, wait: true })\` when you know it is long and need the result before anything else; if you send a new message, the wait detaches to background; otherwise omit \`wait\` so auto-promote can hand you a reminder while you work.`,
39087
- "- `background: true` is ONLY for when you have OTHER useful work to do while it runs: start it, do the other work, and the completion reminder delivers the result (or spawn a subagent for the side work). Do NOT background a command and then immediately `bash_watch` it — that spends a whole extra turn waiting for something foreground returns in one.",
39088
- "- `bash_watch` is for blocking on an ALREADY-backgrounded task once you've run out of parallel work (sync — the user can interrupt), or reacting to a specific early output line (async: background:true + pattern). Never loop `bash_status` to wait — it's a one-shot inspector."
39089
- ].join(`
39090
- `));
39707
+ if (hasBash) {
39708
+ finding.push("Don't find or read code with grep, find, sed or cat in bash.");
39091
39709
  }
39092
- if (hasBgBash && hasWrite) {
39093
- sections.push(`**PTY / interactive commands**: PTY mode is for interactive REPLs and terminal apps (python, node, bash itself, vim). Start with \`${bashName}({ command: "python", pty: true, background: true })\`, read the screen with \`bash_status({ task_id, output_mode: "screen" })\`, and send input with \`bash_write({ task_id, input: "..." })\`.`);
39710
+ const commands = [];
39711
+ if (hasBash && opts.bashCompressionEnabled) {
39712
+ commands.push("don't pipe test or build output into tail, grep or head; AFT already shortens it.");
39094
39713
  }
39095
- if (opts.hashlineEffective === true) {
39096
- sections.push(hashlineTagSourceHint(hasBash && opts.bashRewriteEnabled !== false, (name) => !opts.absentTools.has(name)));
39714
+ if (hasBackground) {
39715
+ commands.push("Pass wait: true when you need a long command's result before anything else; a new message from the user detaches the wait.", "Otherwise a long command moves to the background and a reminder brings its result.", "Block on it with bash_watch only when nothing else is left; bash_watch with background: true and a pattern tells you when a line appears.", "Never loop bash_status.");
39097
39716
  }
39098
- if (sections.length === 0) {
39717
+ const sections = [
39718
+ finding.length ? `**Finding code**: ${finding.join(" ")}` : "",
39719
+ has("aft_callgraph") ? "**Relationships**: aft_callgraph for callers, impact, and execution or data-flow traces." : "",
39720
+ has("aft_outline") && has("aft_zoom") ? "**Web pages**: aft_outline with a URL as target, then aft_zoom on a heading." : "",
39721
+ "",
39722
+ has("aft_inspect") ? "**After edits**: run aft_inspect for diagnostics; the project's typecheck and tests are the final check." : "",
39723
+ has("aft_inspect") ? "**Status bar**: `[AFT E.. W.. | T..]` appears when a count changes. E above 0 usually means your last edit broke something; `?` means unknown, not zero." : "",
39724
+ commands.length ? `**Commands**: ${commands.join(" ")}` : ""
39725
+ ];
39726
+ const hashline = opts.hashlineEffective === true ? hashlineTagSourceHint(hasBash && opts.bashRewriteEnabled !== false, has) : "";
39727
+ if (!sections.some(Boolean) && !hashline)
39099
39728
  return null;
39100
- }
39101
- sections.unshift(`You are equipped with a non-standard tool set: indexed code search, symbol-level reading, structural editing, and code analysis that are faster, more precise, and far cheaper in tokens than stitching together command-line utilities in bash. Always reach for these tools first.
39102
-
39103
- **Parallel tool calls**: when several read-only operations are independent, emit them in ONE response instead of serializing — file reads, structure and symbol lookups, code search, diagnostics, and git status/diff/log. Sequence only when a call depends on a prior result or when a command mutates state.`);
39104
- return `${HEADING}
39105
-
39106
- ${sections.join(`
39729
+ sections[3] = "**Parallel calls**: send independent read-only calls in one response.";
39730
+ const text = `${HEADING}
39107
39731
 
39732
+ ${sections.filter(Boolean).join(`
39108
39733
  `)}`;
39734
+ return hashline ? `${text}
39735
+
39736
+ ${hashline}` : text;
39109
39737
  }
39110
39738
  function buildHintsFromConfig(config, absentTools, hashlineEffective = false) {
39111
39739
  const bashCfg = resolveBashConfig(config);
@@ -39216,12 +39844,12 @@ var PLUGIN_VERSION = (() => {
39216
39844
  return "0.0.0";
39217
39845
  }
39218
39846
  })();
39219
- var ANNOUNCEMENT_VERSION = "0.64.0";
39847
+ var ANNOUNCEMENT_VERSION = "0.65.0";
39220
39848
  var ANNOUNCEMENT_FEATURES = [
39221
- "A new index store makes AFT much faster: call graphs build 26x faster, edits reach the call graph about 9x faster, dead-code checks run 4x faster, and the index takes 4x less disk and 3x less memory.",
39222
- "All worktrees of a repository share one index, so a new worktree is ready in under a second. `npx @cortexkit/aft cache prune-legacy` lists the old index folders and can remove them.",
39223
- "`trace_to` labels each root it reaches: main, test, attribute, public API, or no caller found.",
39224
- "Dead code, unused exports, duplicates, cycles and complexity run only when `aft_inspect` is called; the status bar shows errors, warnings and TODOs."
39849
+ "OpenCode 2: AFT's read-only tools also work inside Code Mode as `tools.aft.code.*`.",
39850
+ "TypeScript monorepos run one language server per TypeScript version instead of one per package; `lsp.max_servers` caps the total.",
39851
+ "Search and grep stay light on large growing files, and shell waits survive the computer going to sleep.",
39852
+ "`views.enabled`, `views.callgraph_copies` and `worktree.ram_overlay` are now refused in user config; `npx @cortexkit/aft doctor --fix` removes them."
39225
39853
  ];
39226
39854
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
39227
39855
  var pendingEagerWarnings = new Map;