@cortexkit/aft 0.46.0 → 0.47.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
@@ -1895,6 +1895,21 @@ function isEmptyParam(value) {
1895
1895
  return false;
1896
1896
  }
1897
1897
 
1898
+ // ../aft-bridge/dist/config-keys.js
1899
+ function stripHarnessSpecificConfigKeys(value, keys) {
1900
+ if (!value || typeof value !== "object" || Array.isArray(value))
1901
+ return value;
1902
+ const stripped = { ...value };
1903
+ for (const key of keys)
1904
+ delete stripped[key];
1905
+ return stripped;
1906
+ }
1907
+ var OPENCODE_ONLY_KEYS, PI_ONLY_KEYS;
1908
+ var init_config_keys = __esm(() => {
1909
+ OPENCODE_ONLY_KEYS = ["hoist_builtin_tools", "auto_update"];
1910
+ PI_ONLY_KEYS = [];
1911
+ });
1912
+
1898
1913
  // ../aft-bridge/dist/config-tiers.js
1899
1914
  import { existsSync, readFileSync as readFileSync2 } from "node:fs";
1900
1915
  import { resolve as resolve2 } from "node:path";
@@ -2223,6 +2238,120 @@ var init_downloader = __esm(() => {
2223
2238
  DOWNLOAD_LOCK_STALE_MS = 10 * 60000;
2224
2239
  });
2225
2240
 
2241
+ // ../aft-bridge/dist/durable-log.js
2242
+ import { appendFile, mkdir, rename, rm, stat } from "node:fs/promises";
2243
+ import { homedir as homedir5 } from "node:os";
2244
+ import { dirname, join as join4 } from "node:path";
2245
+ function homeDir() {
2246
+ if (process.platform === "win32")
2247
+ return process.env.USERPROFILE || process.env.HOME || homedir5();
2248
+ return process.env.HOME || homedir5();
2249
+ }
2250
+ function dataHome() {
2251
+ if (process.env.XDG_DATA_HOME)
2252
+ return process.env.XDG_DATA_HOME;
2253
+ if (process.platform === "win32") {
2254
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join4(homeDir(), "AppData", "Local");
2255
+ }
2256
+ return join4(homeDir(), ".local", "share");
2257
+ }
2258
+ function resolveAftStorageRoot(configuredRoot) {
2259
+ if (configuredRoot)
2260
+ return configuredRoot;
2261
+ if (process.env.AFT_CACHE_DIR)
2262
+ return join4(process.env.AFT_CACHE_DIR, "aft");
2263
+ return join4(dataHome(), "cortexkit", "aft");
2264
+ }
2265
+ function resolveAftLogPath(filename, configuredRoot) {
2266
+ return join4(resolveAftStorageRoot(configuredRoot), "logs", filename);
2267
+ }
2268
+
2269
+ class RotatingLogSink {
2270
+ path;
2271
+ maxBytes;
2272
+ generations;
2273
+ estimatedBytes = null;
2274
+ queue = Promise.resolve();
2275
+ disabled = false;
2276
+ failureReported = false;
2277
+ constructor(path2, options = {}) {
2278
+ this.path = path2;
2279
+ this.maxBytes = options.maxBytes ?? DEFAULT_LOG_BYTES;
2280
+ this.generations = options.generations ?? DEFAULT_LOG_GENERATIONS;
2281
+ }
2282
+ append(data) {
2283
+ if (this.disabled || data.length === 0)
2284
+ return;
2285
+ this.queue = this.queue.then(() => this.write(data)).catch((error2) => {
2286
+ this.disabled = true;
2287
+ if (!this.failureReported) {
2288
+ this.failureReported = true;
2289
+ try {
2290
+ process.stderr.write(`[aft-plugin] durable log disabled for ${this.path}: ${error2 instanceof Error ? error2.message : String(error2)}
2291
+ `);
2292
+ } catch {}
2293
+ }
2294
+ });
2295
+ }
2296
+ async drain() {
2297
+ await this.queue;
2298
+ }
2299
+ async write(data) {
2300
+ await mkdir(dirname(this.path), { recursive: true });
2301
+ if (this.estimatedBytes === null) {
2302
+ try {
2303
+ this.estimatedBytes = (await stat(this.path)).size;
2304
+ } catch (error2) {
2305
+ if (!isMissing(error2))
2306
+ throw error2;
2307
+ this.estimatedBytes = 0;
2308
+ }
2309
+ }
2310
+ const bytes = Buffer.byteLength(data);
2311
+ if (this.estimatedBytes > 0 && this.estimatedBytes + bytes > this.maxBytes) {
2312
+ await this.rotate();
2313
+ }
2314
+ await appendFile(this.path, data, "utf8");
2315
+ this.estimatedBytes = (this.estimatedBytes ?? 0) + bytes;
2316
+ }
2317
+ async rotate() {
2318
+ if (this.generations <= 0) {
2319
+ await removeIfPresent(this.path);
2320
+ this.estimatedBytes = 0;
2321
+ return;
2322
+ }
2323
+ await removeIfPresent(`${this.path}.${this.generations}`);
2324
+ for (let generation = this.generations - 1;generation >= 1; generation -= 1) {
2325
+ await renameIfPresent(`${this.path}.${generation}`, `${this.path}.${generation + 1}`);
2326
+ }
2327
+ await renameIfPresent(this.path, `${this.path}.1`);
2328
+ this.estimatedBytes = 0;
2329
+ }
2330
+ }
2331
+ function isMissing(error2) {
2332
+ return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
2333
+ }
2334
+ async function removeIfPresent(path2) {
2335
+ try {
2336
+ await rm(path2, { force: true });
2337
+ } catch (error2) {
2338
+ if (!isMissing(error2))
2339
+ throw error2;
2340
+ }
2341
+ }
2342
+ async function renameIfPresent(from, to) {
2343
+ try {
2344
+ await rename(from, to);
2345
+ } catch (error2) {
2346
+ if (!isMissing(error2))
2347
+ throw error2;
2348
+ }
2349
+ }
2350
+ var DEFAULT_LOG_BYTES, DEFAULT_LOG_GENERATIONS = 5;
2351
+ var init_durable_log = __esm(() => {
2352
+ DEFAULT_LOG_BYTES = 20 * 1024 * 1024;
2353
+ });
2354
+
2226
2355
  // ../aft-bridge/dist/edit-summary.js
2227
2356
  function formatEditSummary(data) {
2228
2357
  if (data.rolled_back === true) {
@@ -2308,27 +2437,27 @@ function stripJsoncSymbols(value) {
2308
2437
 
2309
2438
  // ../aft-bridge/dist/paths.js
2310
2439
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync } from "node:fs";
2311
- import { homedir as homedir5 } from "node:os";
2312
- import { dirname, isAbsolute as isAbsolute2, join as join4, resolve as resolve3 } from "node:path";
2313
- function homeDir() {
2440
+ import { homedir as homedir6 } from "node:os";
2441
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join5, resolve as resolve3 } from "node:path";
2442
+ function homeDir2() {
2314
2443
  if (process.platform === "win32")
2315
- return process.env.USERPROFILE || process.env.HOME || homedir5();
2316
- return process.env.HOME || homedir5();
2444
+ return process.env.USERPROFILE || process.env.HOME || homedir6();
2445
+ return process.env.HOME || homedir6();
2317
2446
  }
2318
2447
  function configHome() {
2319
2448
  const xdg = process.env.XDG_CONFIG_HOME;
2320
2449
  if (xdg && isAbsolute2(xdg))
2321
2450
  return xdg;
2322
- return join4(homeDir(), ".config");
2451
+ return join5(homeDir2(), ".config");
2323
2452
  }
2324
2453
  function legacyOpenCodeConfigDir() {
2325
2454
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
2326
2455
  if (envDir)
2327
2456
  return resolve3(envDir);
2328
- return join4(configHome(), "opencode");
2457
+ return join5(configHome(), "opencode");
2329
2458
  }
2330
2459
  function legacyPiAgentDir() {
2331
- return join4(homeDir(), ".pi", "agent");
2460
+ return join5(homeDir2(), ".pi", "agent");
2332
2461
  }
2333
2462
  function legacySources(basePath, label, harness) {
2334
2463
  return [
@@ -2337,10 +2466,10 @@ function legacySources(basePath, label, harness) {
2337
2466
  ];
2338
2467
  }
2339
2468
  function resolveCortexKitUserConfigPath() {
2340
- return join4(configHome(), "cortexkit", "aft.jsonc");
2469
+ return join5(configHome(), "cortexkit", "aft.jsonc");
2341
2470
  }
2342
2471
  function resolveCortexKitProjectConfigPath(projectDirectory) {
2343
- return join4(projectDirectory, ".cortexkit", "aft.jsonc");
2472
+ return join5(projectDirectory, ".cortexkit", "aft.jsonc");
2344
2473
  }
2345
2474
  function resolveCortexKitConfigPaths(projectDirectory) {
2346
2475
  return {
@@ -2351,25 +2480,25 @@ function resolveCortexKitConfigPaths(projectDirectory) {
2351
2480
  function resolveLegacyAftConfigSources(projectDirectory) {
2352
2481
  return {
2353
2482
  user: [
2354
- ...legacySources(join4(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
2355
- ...legacySources(join4(legacyPiAgentDir(), "aft"), "Pi user", "pi")
2483
+ ...legacySources(join5(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
2484
+ ...legacySources(join5(legacyPiAgentDir(), "aft"), "Pi user", "pi")
2356
2485
  ],
2357
2486
  project: [
2358
- ...legacySources(join4(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
2359
- ...legacySources(join4(projectDirectory, ".pi", "aft"), "Pi project", "pi")
2487
+ ...legacySources(join5(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
2488
+ ...legacySources(join5(projectDirectory, ".pi", "aft"), "Pi project", "pi")
2360
2489
  ]
2361
2490
  };
2362
2491
  }
2363
2492
  function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
2364
- return join4(storageRoot, harness, ...segments);
2493
+ return join5(storageRoot, harness, ...segments);
2365
2494
  }
2366
2495
  function repairRootScopedStorageFile(storageRoot, harness, fileName) {
2367
2496
  const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
2368
- const rootPath = join4(storageRoot, fileName);
2497
+ const rootPath = join5(storageRoot, fileName);
2369
2498
  if (existsSync3(harnessPath) || !existsSync3(rootPath))
2370
2499
  return harnessPath;
2371
2500
  try {
2372
- mkdirSync2(dirname(harnessPath), { recursive: true });
2501
+ mkdirSync2(dirname2(harnessPath), { recursive: true });
2373
2502
  renameSync2(rootPath, harnessPath);
2374
2503
  } catch {}
2375
2504
  return harnessPath;
@@ -2390,7 +2519,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
2390
2519
  return false;
2391
2520
  if (!lastVersion) {
2392
2521
  try {
2393
- mkdirSync2(dirname(versionFile), { recursive: true });
2522
+ mkdirSync2(dirname2(versionFile), { recursive: true });
2394
2523
  writeFileSync(versionFile, currentVersion);
2395
2524
  } catch {}
2396
2525
  return false;
@@ -2402,7 +2531,7 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
2402
2531
  return;
2403
2532
  const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
2404
2533
  try {
2405
- mkdirSync2(dirname(versionFile), { recursive: true });
2534
+ mkdirSync2(dirname2(versionFile), { recursive: true });
2406
2535
  writeFileSync(versionFile, currentVersion);
2407
2536
  } catch {}
2408
2537
  }
@@ -2412,8 +2541,8 @@ var init_paths = () => {};
2412
2541
  import { execSync } from "node:child_process";
2413
2542
  import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
2414
2543
  import { createRequire } from "node:module";
2415
- import { homedir as homedir6 } from "node:os";
2416
- import { join as join5 } from "node:path";
2544
+ import { homedir as homedir7 } from "node:os";
2545
+ import { join as join6 } from "node:path";
2417
2546
  function copyToVersionedCache(npmBinaryPath, knownVersion) {
2418
2547
  try {
2419
2548
  const version = knownVersion ?? readBinaryVersion(npmBinaryPath);
@@ -2421,9 +2550,9 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
2421
2550
  return null;
2422
2551
  const tag = version.startsWith("v") ? version : `v${version}`;
2423
2552
  const cacheDir = getCacheDir();
2424
- const versionedDir = join5(cacheDir, tag);
2553
+ const versionedDir = join6(cacheDir, tag);
2425
2554
  const ext = process.platform === "win32" ? ".exe" : "";
2426
- const cachedPath = join5(versionedDir, `aft${ext}`);
2555
+ const cachedPath = join6(versionedDir, `aft${ext}`);
2427
2556
  if (existsSync4(cachedPath)) {
2428
2557
  const cachedVersion = readBinaryVersion(cachedPath);
2429
2558
  if (cachedVersion === version)
@@ -2453,18 +2582,18 @@ function normalizeBareVersion(version) {
2453
2582
  return version.startsWith("v") ? version.slice(1) : version;
2454
2583
  }
2455
2584
  function homeDirFromEnv(env) {
2456
- return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir6();
2585
+ return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir7();
2457
2586
  }
2458
2587
  function cacheDirFromEnv(env) {
2459
2588
  if (process.platform === "win32") {
2460
- const base2 = env.LOCALAPPDATA || env.APPDATA || join5(homeDirFromEnv(env), "AppData", "Local");
2461
- return join5(base2, "aft", "bin");
2589
+ const base2 = env.LOCALAPPDATA || env.APPDATA || join6(homeDirFromEnv(env), "AppData", "Local");
2590
+ return join6(base2, "aft", "bin");
2462
2591
  }
2463
- const base = env.XDG_CACHE_HOME || join5(homeDirFromEnv(env), ".cache");
2464
- return join5(base, "aft", "bin");
2592
+ const base = env.XDG_CACHE_HOME || join6(homeDirFromEnv(env), ".cache");
2593
+ return join6(base, "aft", "bin");
2465
2594
  }
2466
2595
  function cachedBinaryPathFromEnv(version, env, ext) {
2467
- const binaryPath = join5(cacheDirFromEnv(env), version, `aft${ext}`);
2596
+ const binaryPath = join6(cacheDirFromEnv(env), version, `aft${ext}`);
2468
2597
  return existsSync4(binaryPath) ? binaryPath : null;
2469
2598
  }
2470
2599
  function isExpectedCachedBinary2(binaryPath, expectedVersion) {
@@ -2583,7 +2712,7 @@ function findBinarySync(expectedVersion) {
2583
2712
  return usable;
2584
2713
  }
2585
2714
  } catch {}
2586
- const cargoPath = join5(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
2715
+ const cargoPath = join6(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
2587
2716
  if (existsSync4(cargoPath)) {
2588
2717
  const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
2589
2718
  if (usable)
@@ -2631,28 +2760,28 @@ var init_resolver = __esm(() => {
2631
2760
  // ../aft-bridge/dist/migration.js
2632
2761
  import { spawnSync as spawnSync2 } from "node:child_process";
2633
2762
  import { closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
2634
- import { homedir as homedir7, tmpdir } from "node:os";
2635
- import { basename, dirname as dirname2, join as join6, resolve as resolve4 } from "node:path";
2636
- function dataHome() {
2763
+ import { homedir as homedir8, tmpdir } from "node:os";
2764
+ import { basename, dirname as dirname3, join as join7, resolve as resolve4 } from "node:path";
2765
+ function dataHome2() {
2637
2766
  if (process.env.XDG_DATA_HOME)
2638
2767
  return process.env.XDG_DATA_HOME;
2639
2768
  if (process.platform === "win32") {
2640
- return process.env.LOCALAPPDATA || process.env.APPDATA || join6(homeDir2(), "AppData", "Local");
2769
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join7(homeDir3(), "AppData", "Local");
2641
2770
  }
2642
- return join6(homeDir2(), ".local", "share");
2771
+ return join7(homeDir3(), ".local", "share");
2643
2772
  }
2644
- function homeDir2() {
2773
+ function homeDir3() {
2645
2774
  if (process.platform === "win32")
2646
- return process.env.USERPROFILE || process.env.HOME || homedir7();
2647
- return process.env.HOME || homedir7();
2775
+ return process.env.USERPROFILE || process.env.HOME || homedir8();
2776
+ return process.env.HOME || homedir8();
2648
2777
  }
2649
2778
  function resolveLegacyStorageRoot(harness) {
2650
2779
  if (harness === "pi")
2651
- return join6(homeDir2(), ".pi", "agent", "aft");
2652
- return join6(dataHome(), "opencode", "storage", "plugin", "aft");
2780
+ return join7(homeDir3(), ".pi", "agent", "aft");
2781
+ return join7(dataHome2(), "opencode", "storage", "plugin", "aft");
2653
2782
  }
2654
2783
  function resolveCortexKitStorageRoot() {
2655
- return join6(dataHome(), "cortexkit", "aft");
2784
+ return join7(dataHome2(), "cortexkit", "aft");
2656
2785
  }
2657
2786
  function stripJsoncForParse(input) {
2658
2787
  let out = "";
@@ -2781,8 +2910,8 @@ function acquireConfigMigrationLock(lockDir) {
2781
2910
  }
2782
2911
  }
2783
2912
  function atomicCopyConfigFile(sourcePath, targetPath) {
2784
- mkdirSync4(dirname2(targetPath), { recursive: true });
2785
- const tmpPath = join6(dirname2(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
2913
+ mkdirSync4(dirname3(targetPath), { recursive: true });
2914
+ const tmpPath = join7(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
2786
2915
  let fd = null;
2787
2916
  try {
2788
2917
  fd = openSync3(tmpPath, "wx", 384);
@@ -2803,8 +2932,8 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
2803
2932
  }
2804
2933
  }
2805
2934
  function atomicWriteConfigFile(targetPath, content) {
2806
- mkdirSync4(dirname2(targetPath), { recursive: true });
2807
- const tmpPath = join6(dirname2(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
2935
+ mkdirSync4(dirname3(targetPath), { recursive: true });
2936
+ const tmpPath = join7(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
2808
2937
  let fd = null;
2809
2938
  try {
2810
2939
  fd = openSync3(tmpPath, "wx", 384);
@@ -2927,7 +3056,7 @@ function migrateAftConfigFile(opts) {
2927
3056
  if (existingSources.length === 0) {
2928
3057
  return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
2929
3058
  }
2930
- mkdirSync4(dirname2(opts.targetPath), { recursive: true });
3059
+ mkdirSync4(dirname3(opts.targetPath), { recursive: true });
2931
3060
  const release = acquireConfigMigrationLock(`${opts.targetPath}.lock`);
2932
3061
  try {
2933
3062
  const sources = existingSources.map((source) => ({
@@ -2984,13 +3113,13 @@ function spawnErrorLabel(error2) {
2984
3113
  return [code, error2.message].filter(Boolean).join(": ");
2985
3114
  }
2986
3115
  function migrationLogPath(newRoot, harness, logger) {
2987
- const desired = join6(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
3116
+ const desired = join7(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
2988
3117
  try {
2989
- mkdirSync4(dirname2(desired), { recursive: true });
3118
+ mkdirSync4(dirname3(desired), { recursive: true });
2990
3119
  return desired;
2991
3120
  } catch (err) {
2992
- const fallback = join6(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
2993
- logger?.warn?.(`Failed to create AFT migration log directory ${dirname2(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
3121
+ const fallback = join7(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
3122
+ logger?.warn?.(`Failed to create AFT migration log directory ${dirname3(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
2994
3123
  return fallback;
2995
3124
  }
2996
3125
  }
@@ -3091,13 +3220,13 @@ var init_migration = __esm(() => {
3091
3220
  // ../aft-bridge/dist/npm-resolver.js
3092
3221
  import { execFileSync } from "node:child_process";
3093
3222
  import { readdirSync, statSync as statSync3 } from "node:fs";
3094
- import { homedir as homedir8 } from "node:os";
3095
- import { delimiter, dirname as dirname3, isAbsolute as isAbsolute3, join as join7 } from "node:path";
3223
+ import { homedir as homedir9 } from "node:os";
3224
+ import { delimiter, dirname as dirname4, isAbsolute as isAbsolute3, join as join8 } from "node:path";
3096
3225
  function defaultDeps() {
3097
3226
  return {
3098
3227
  platform: process.platform,
3099
3228
  env: process.env,
3100
- home: homedir8(),
3229
+ home: homedir9(),
3101
3230
  execPath: process.execPath
3102
3231
  };
3103
3232
  }
@@ -3118,14 +3247,14 @@ function npmFromPath(deps) {
3118
3247
  const dir = entry.trim().replace(/^"|"$/g, "");
3119
3248
  if (!dir || !isAbsolute3(dir))
3120
3249
  continue;
3121
- if (isFile(join7(dir, name)))
3250
+ if (isFile(join8(dir, name)))
3122
3251
  return dir;
3123
3252
  }
3124
3253
  return null;
3125
3254
  }
3126
3255
  function npmAdjacentToNode(deps) {
3127
- const dir = dirname3(deps.execPath);
3128
- return isFile(join7(dir, npmBinaryName(deps.platform))) ? dir : null;
3256
+ const dir = dirname4(deps.execPath);
3257
+ return isFile(join8(dir, npmBinaryName(deps.platform))) ? dir : null;
3129
3258
  }
3130
3259
  function highestVersionedNodeBin(installsDir, name) {
3131
3260
  let entries;
@@ -3134,8 +3263,8 @@ function highestVersionedNodeBin(installsDir, name) {
3134
3263
  } catch {
3135
3264
  return null;
3136
3265
  }
3137
- const candidates = entries.filter((v) => isFile(join7(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
3138
- return candidates.length > 0 ? join7(installsDir, candidates[0], "bin") : null;
3266
+ const candidates = entries.filter((v) => isFile(join8(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
3267
+ return candidates.length > 0 ? join8(installsDir, candidates[0], "bin") : null;
3139
3268
  }
3140
3269
  function compareVersionsDesc(a, b) {
3141
3270
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -3160,22 +3289,22 @@ function wellKnownNpmDirs(deps) {
3160
3289
  const programFiles = env.ProgramFiles || "C:\\Program Files";
3161
3290
  const appData = env.APPDATA;
3162
3291
  const localAppData = env.LOCALAPPDATA;
3163
- push(join7(programFiles, "nodejs"));
3292
+ push(join8(programFiles, "nodejs"));
3164
3293
  if (appData)
3165
- push(join7(appData, "npm"));
3294
+ push(join8(appData, "npm"));
3166
3295
  if (localAppData)
3167
- push(join7(localAppData, "Volta", "bin"));
3296
+ push(join8(localAppData, "Volta", "bin"));
3168
3297
  if (env.NVM_SYMLINK)
3169
3298
  push(env.NVM_SYMLINK);
3170
3299
  } else {
3171
3300
  if (env.NVM_BIN)
3172
3301
  push(env.NVM_BIN);
3173
- push(highestVersionedNodeBin(join7(home, ".nvm", "versions", "node"), name));
3174
- push(highestVersionedNodeBin(join7(home, ".local", "share", "mise", "installs", "node"), name));
3175
- push(highestVersionedNodeBin(join7(home, ".asdf", "installs", "nodejs"), name));
3176
- push(join7(home, ".volta", "bin"));
3177
- push(join7(home, ".asdf", "shims"));
3178
- const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join7(home, ".local", "bin")]);
3302
+ push(highestVersionedNodeBin(join8(home, ".nvm", "versions", "node"), name));
3303
+ push(highestVersionedNodeBin(join8(home, ".local", "share", "mise", "installs", "node"), name));
3304
+ push(highestVersionedNodeBin(join8(home, ".asdf", "installs", "nodejs"), name));
3305
+ push(join8(home, ".volta", "bin"));
3306
+ push(join8(home, ".asdf", "shims"));
3307
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join8(home, ".local", "bin")]);
3179
3308
  for (const dir of systemDirs)
3180
3309
  push(dir);
3181
3310
  }
@@ -3185,12 +3314,12 @@ function resolveNpm(deps = defaultDeps()) {
3185
3314
  const name = npmBinaryName(deps.platform);
3186
3315
  const onPath = npmFromPath(deps);
3187
3316
  if (onPath)
3188
- return { command: join7(onPath, name), binDir: onPath };
3317
+ return { command: join8(onPath, name), binDir: onPath };
3189
3318
  const adjacent = npmAdjacentToNode(deps);
3190
3319
  if (adjacent)
3191
- return { command: join7(adjacent, name), binDir: adjacent };
3320
+ return { command: join8(adjacent, name), binDir: adjacent };
3192
3321
  for (const dir of wellKnownNpmDirs(deps)) {
3193
- const candidate = join7(dir, name);
3322
+ const candidate = join8(dir, name);
3194
3323
  if (isFile(candidate))
3195
3324
  return { command: candidate, binDir: dir };
3196
3325
  }
@@ -3226,7 +3355,7 @@ var init_npm_resolver = () => {};
3226
3355
  import { execFileSync as execFileSync2 } from "node:child_process";
3227
3356
  import { createHash as createHash3 } from "node:crypto";
3228
3357
  import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync2, readFileSync as readFileSync6, readlinkSync, realpathSync, rmSync as rmSync3, statSync as statSync4, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
3229
- import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join8, relative as relative2, resolve as resolve5, win32 } from "node:path";
3358
+ import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute4, join as join9, relative as relative2, resolve as resolve5, win32 } from "node:path";
3230
3359
  import { Readable as Readable2 } from "node:stream";
3231
3360
  import { pipeline as pipeline2 } from "node:stream/promises";
3232
3361
  function getPlatformInfo() {
@@ -3252,10 +3381,10 @@ function getManualInstallHint() {
3252
3381
  }
3253
3382
  async function ensureOnnxRuntime(storageDir) {
3254
3383
  const info = getPlatformInfo();
3255
- const ortVersionDir = join8(storageDir, "onnxruntime", ORT_VERSION);
3384
+ const ortVersionDir = join9(storageDir, "onnxruntime", ORT_VERSION);
3256
3385
  const libName = info?.libName ?? "libonnxruntime.dylib";
3257
3386
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
3258
- const libPath = join8(resolvedOrtDir, libName);
3387
+ const libPath = join9(resolvedOrtDir, libName);
3259
3388
  if (existsSync6(libPath)) {
3260
3389
  const meta = readOnnxInstalledMeta(ortVersionDir);
3261
3390
  if (meta?.sha256) {
@@ -3285,9 +3414,9 @@ async function ensureOnnxRuntime(storageDir) {
3285
3414
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
3286
3415
  return null;
3287
3416
  }
3288
- const onnxBaseDir = join8(storageDir, "onnxruntime");
3417
+ const onnxBaseDir = join9(storageDir, "onnxruntime");
3289
3418
  mkdirSync5(onnxBaseDir, { recursive: true });
3290
- const lockPath = join8(onnxBaseDir, ONNX_LOCK_FILE);
3419
+ const lockPath = join9(onnxBaseDir, ONNX_LOCK_FILE);
3291
3420
  cleanupAbandonedStagingDirs(onnxBaseDir);
3292
3421
  if (!acquireLock(lockPath)) {
3293
3422
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -3306,7 +3435,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
3306
3435
  for (const entry of entries) {
3307
3436
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
3308
3437
  continue;
3309
- const stagingDir = join8(onnxBaseDir, entry);
3438
+ const stagingDir = join9(onnxBaseDir, entry);
3310
3439
  const parts = entry.split(".");
3311
3440
  const pidStr = parts[parts.length - 2];
3312
3441
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -3343,7 +3472,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
3343
3472
  }
3344
3473
  function cleanupIncompleteTargetIfUnowned(ortDir) {
3345
3474
  try {
3346
- if (existsSync6(ortDir) && !existsSync6(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
3475
+ if (existsSync6(ortDir) && !existsSync6(join9(ortDir, ONNX_INSTALLED_META_FILE))) {
3347
3476
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
3348
3477
  rmSync3(ortDir, { recursive: true, force: true });
3349
3478
  }
@@ -3388,7 +3517,7 @@ function detectOnnxVersion(libDir, libName) {
3388
3517
  if (version)
3389
3518
  return version;
3390
3519
  }
3391
- const base = join8(libDir, libName);
3520
+ const base = join9(libDir, libName);
3392
3521
  if (existsSync6(base)) {
3393
3522
  try {
3394
3523
  const real = realpathSync(base);
@@ -3427,6 +3556,17 @@ function pathEntriesForPlatform() {
3427
3556
  return isAbsolute4(entry) || win32.isAbsolute(entry);
3428
3557
  });
3429
3558
  }
3559
+ function isWindowsSystem32Directory(dir) {
3560
+ if (process.platform !== "win32")
3561
+ return false;
3562
+ const normalizedDir = win32.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
3563
+ const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
3564
+ return windowsRoots.some((root) => {
3565
+ if (!root)
3566
+ return false;
3567
+ return normalizedDir === win32.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
3568
+ });
3569
+ }
3430
3570
  function directoryContainsLibrary(dir, libName) {
3431
3571
  try {
3432
3572
  const entries = readdirSync2(dir);
@@ -3440,10 +3580,10 @@ function directoryContainsLibrary(dir, libName) {
3440
3580
  }
3441
3581
  }
3442
3582
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
3443
- if (existsSync6(join8(ortVersionDir, libName)))
3583
+ if (existsSync6(join9(ortVersionDir, libName)))
3444
3584
  return ortVersionDir;
3445
- const libSubdir = join8(ortVersionDir, "lib");
3446
- if (existsSync6(join8(libSubdir, libName)))
3585
+ const libSubdir = join9(ortVersionDir, "lib");
3586
+ if (existsSync6(join9(libSubdir, libName)))
3447
3587
  return libSubdir;
3448
3588
  return ortVersionDir;
3449
3589
  }
@@ -3458,12 +3598,12 @@ function findSystemOnnxRuntime(libName) {
3458
3598
  } else if (process.platform === "win32") {
3459
3599
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
3460
3600
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
3461
- searchPaths.push(join8(programFiles, "onnxruntime", "lib"), join8(programFiles, "Microsoft ONNX Runtime", "lib"), join8(programFiles, "Microsoft Machine Learning", "lib"), join8(programFilesX86, "onnxruntime", "lib"), ...(() => {
3601
+ searchPaths.push(join9(programFiles, "onnxruntime", "lib"), join9(programFiles, "Microsoft ONNX Runtime", "lib"), join9(programFiles, "Microsoft Machine Learning", "lib"), join9(programFilesX86, "onnxruntime", "lib"), ...(() => {
3462
3602
  const nugetPaths = [];
3463
3603
  const userProfile = process.env.USERPROFILE ?? "";
3464
3604
  if (!userProfile)
3465
3605
  return nugetPaths;
3466
- const nugetPackageDir = join8(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
3606
+ const nugetPackageDir = join9(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
3467
3607
  if (!existsSync6(nugetPackageDir))
3468
3608
  return nugetPaths;
3469
3609
  try {
@@ -3472,7 +3612,7 @@ function findSystemOnnxRuntime(libName) {
3472
3612
  continue;
3473
3613
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
3474
3614
  continue;
3475
- nugetPaths.push(join8(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join8(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
3615
+ nugetPaths.push(join9(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join9(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
3476
3616
  }
3477
3617
  } catch (err) {
3478
3618
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -3494,7 +3634,7 @@ function findSystemOnnxRuntime(libName) {
3494
3634
  });
3495
3635
  const unknownVersionPaths = [];
3496
3636
  for (const dir of uniquePaths) {
3497
- const libPath = join8(dir, libName);
3637
+ const libPath = join9(dir, libName);
3498
3638
  if (process.platform === "win32") {
3499
3639
  if (!directoryContainsLibrary(dir, libName))
3500
3640
  continue;
@@ -3503,6 +3643,10 @@ function findSystemOnnxRuntime(libName) {
3503
3643
  }
3504
3644
  const version = detectOnnxVersion(dir, libName);
3505
3645
  if (!version) {
3646
+ if (isWindowsSystem32Directory(dir)) {
3647
+ warn(`Skipping unversioned Windows system ONNX Runtime at ${dir}; falling through to AFT-managed download.`);
3648
+ continue;
3649
+ }
3506
3650
  unknownVersionPaths.push(dir);
3507
3651
  continue;
3508
3652
  }
@@ -3530,7 +3674,7 @@ async function downloadFileWithCap(url, destPath) {
3530
3674
  if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
3531
3675
  throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
3532
3676
  }
3533
- mkdirSync5(dirname4(destPath), { recursive: true });
3677
+ mkdirSync5(dirname5(destPath), { recursive: true });
3534
3678
  let bytesWritten = 0;
3535
3679
  const guard = new TransformStream({
3536
3680
  transform(chunk, transformController) {
@@ -3560,11 +3704,11 @@ function validateExtractedTree(stagingRoot) {
3560
3704
  const walk = (dir) => {
3561
3705
  const entries = readdirSync2(dir);
3562
3706
  for (const entry of entries) {
3563
- const fullPath = join8(dir, entry);
3707
+ const fullPath = join9(dir, entry);
3564
3708
  const lst = lstatSync(fullPath);
3565
3709
  if (lst.isSymbolicLink()) {
3566
3710
  const linkTarget = readlinkSync(fullPath);
3567
- const resolvedTarget = resolve5(dirname4(fullPath), linkTarget);
3711
+ const resolvedTarget = resolve5(dirname5(fullPath), linkTarget);
3568
3712
  const rel2 = relative2(realRoot, resolvedTarget);
3569
3713
  if (rel2.startsWith("..") || isAbsolute4(rel2) || win32.isAbsolute(rel2)) {
3570
3714
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
@@ -3595,7 +3739,7 @@ async function downloadOnnxRuntime(info, targetDir) {
3595
3739
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
3596
3740
  try {
3597
3741
  mkdirSync5(tmpDir, { recursive: true });
3598
- const archivePath = join8(tmpDir, `onnxruntime.${info.archiveType}`);
3742
+ const archivePath = join9(tmpDir, `onnxruntime.${info.archiveType}`);
3599
3743
  await downloadFileWithCap(url, archivePath);
3600
3744
  const archiveSha256 = sha256File(archivePath);
3601
3745
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
@@ -3611,7 +3755,7 @@ async function downloadOnnxRuntime(info, targetDir) {
3611
3755
  unlinkSync4(archivePath);
3612
3756
  } catch {}
3613
3757
  validateExtractedTree(tmpDir);
3614
- const extractedDir = join8(tmpDir, info.assetName, "lib");
3758
+ const extractedDir = join9(tmpDir, info.assetName, "lib");
3615
3759
  if (!existsSync6(extractedDir)) {
3616
3760
  throw new Error(`Expected directory not found: ${extractedDir}`);
3617
3761
  }
@@ -3620,11 +3764,11 @@ async function downloadOnnxRuntime(info, targetDir) {
3620
3764
  const realFiles = [];
3621
3765
  const symlinks = [];
3622
3766
  for (const libFile of libFiles) {
3623
- const src = join8(extractedDir, libFile);
3767
+ const src = join9(extractedDir, libFile);
3624
3768
  try {
3625
- const stat = lstatSync(src);
3626
- log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
3627
- if (stat.isSymbolicLink()) {
3769
+ const stat2 = lstatSync(src);
3770
+ log(`ORT extract: ${libFile} — isSymlink=${stat2.isSymbolicLink()}, isFile=${stat2.isFile()}, size=${stat2.size}`);
3771
+ if (stat2.isSymbolicLink()) {
3628
3772
  symlinks.push({ name: libFile, target: readlinkSync(src) });
3629
3773
  } else {
3630
3774
  realFiles.push(libFile);
@@ -3635,7 +3779,7 @@ async function downloadOnnxRuntime(info, targetDir) {
3635
3779
  }
3636
3780
  }
3637
3781
  copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
3638
- const libPath = join8(targetDir, info.libName);
3782
+ const libPath = join9(targetDir, info.libName);
3639
3783
  let libHash = null;
3640
3784
  try {
3641
3785
  libHash = sha256File(libPath);
@@ -3660,8 +3804,8 @@ async function downloadOnnxRuntime(info, targetDir) {
3660
3804
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
3661
3805
  const requiredLibs = new Set([info.libName]);
3662
3806
  for (const libFile of realFiles) {
3663
- const src = join8(extractedDir, libFile);
3664
- const dst = join8(targetDir, libFile);
3807
+ const src = join9(extractedDir, libFile);
3808
+ const dst = join9(targetDir, libFile);
3665
3809
  try {
3666
3810
  copyFile(src, dst);
3667
3811
  if (process.platform !== "win32") {
@@ -3677,12 +3821,12 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
3677
3821
  }
3678
3822
  const targetRoot = realpathSync(targetDir);
3679
3823
  for (const link of symlinks) {
3680
- const dst = join8(targetDir, link.name);
3824
+ const dst = join9(targetDir, link.name);
3681
3825
  try {
3682
3826
  unlinkSync4(dst);
3683
3827
  } catch {}
3684
- const dstForContainment = join8(targetRoot, link.name);
3685
- const resolvedTarget = resolve5(dirname4(dstForContainment), link.target);
3828
+ const dstForContainment = join9(targetRoot, link.name);
3829
+ const resolvedTarget = resolve5(dirname5(dstForContainment), link.target);
3686
3830
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
3687
3831
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
3688
3832
  if (requiredLibs.has(link.name)) {
@@ -3702,7 +3846,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
3702
3846
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
3703
3847
  }
3704
3848
  }
3705
- const requiredPath = join8(targetDir, info.libName);
3849
+ const requiredPath = join9(targetDir, info.libName);
3706
3850
  if (!existsSync6(requiredPath)) {
3707
3851
  rmSync3(targetDir, { recursive: true, force: true });
3708
3852
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
@@ -3729,13 +3873,13 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
3729
3873
  ...sha256 ? { sha256 } : {},
3730
3874
  archiveSha256
3731
3875
  };
3732
- writeFileSync3(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
3876
+ writeFileSync3(join9(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
3733
3877
  } catch (err) {
3734
3878
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
3735
3879
  }
3736
3880
  }
3737
3881
  function readOnnxInstalledMeta(installDir) {
3738
- const path2 = join8(installDir, ONNX_INSTALLED_META_FILE);
3882
+ const path2 = join9(installDir, ONNX_INSTALLED_META_FILE);
3739
3883
  try {
3740
3884
  if (!statSync4(path2).isFile())
3741
3885
  return null;
@@ -3873,7 +4017,7 @@ function isProcessAlive(pid) {
3873
4017
  }
3874
4018
  function cleanupOnnxRuntime(storageDir) {
3875
4019
  try {
3876
- const ortBase = join8(storageDir, "onnxruntime");
4020
+ const ortBase = join9(storageDir, "onnxruntime");
3877
4021
  if (existsSync6(ortBase)) {
3878
4022
  rmSync3(ortBase, { recursive: true, force: true });
3879
4023
  }
@@ -3975,10 +4119,10 @@ function projectRootKeyHash(dir) {
3975
4119
  var init_project_identity = () => {};
3976
4120
 
3977
4121
  // ../aft-bridge/dist/pool.js
3978
- import { homedir as homedir9 } from "node:os";
4122
+ import { homedir as homedir10 } from "node:os";
3979
4123
  function canonicalHomeDir() {
3980
4124
  try {
3981
- const home = homedir9();
4125
+ const home = homedir10();
3982
4126
  if (!home)
3983
4127
  return null;
3984
4128
  return canonicalizeProjectRoot(home);
@@ -4004,6 +4148,7 @@ class BridgePool {
4004
4148
  projectConfigLoader;
4005
4149
  logger;
4006
4150
  cleanupTimer = null;
4151
+ shutdownCalled = false;
4007
4152
  constructor(binaryPath, options = {}, configOverrides = {}) {
4008
4153
  this.binaryPath = binaryPath;
4009
4154
  this.maxPoolSize = options.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE;
@@ -4025,12 +4170,11 @@ class BridgePool {
4025
4170
  childEnv: options.childEnv
4026
4171
  };
4027
4172
  this.configOverrides = configOverrides;
4028
- if (Number.isFinite(this.idleTimeoutMs)) {
4029
- this.cleanupTimer = setInterval(() => this.cleanup(), CLEANUP_INTERVAL_MS);
4030
- this.cleanupTimer.unref();
4031
- }
4173
+ this.startCleanupTimer();
4032
4174
  }
4033
4175
  getActiveBridgeForRoot(projectRoot) {
4176
+ if (this.shutdownCalled)
4177
+ return null;
4034
4178
  const key = normalizeKey(projectRoot);
4035
4179
  const entry = this.bridges.get(key);
4036
4180
  if (!entry?.bridge.isAlive())
@@ -4038,7 +4182,21 @@ class BridgePool {
4038
4182
  entry.lastUsed = Date.now();
4039
4183
  return entry.bridge;
4040
4184
  }
4185
+ activeBridges() {
4186
+ if (this.shutdownCalled)
4187
+ return [];
4188
+ const alive = [];
4189
+ for (const entry of this.bridges.values()) {
4190
+ if (entry.bridge.isAlive())
4191
+ alive.push(entry.bridge);
4192
+ }
4193
+ return alive;
4194
+ }
4041
4195
  getBridge(projectRoot) {
4196
+ if (this.shutdownCalled) {
4197
+ this.shutdownCalled = false;
4198
+ this.startCleanupTimer();
4199
+ }
4042
4200
  const key = normalizeKey(projectRoot);
4043
4201
  const existing = this.bridges.get(key);
4044
4202
  if (existing) {
@@ -4048,15 +4206,7 @@ class BridgePool {
4048
4206
  if (this.bridges.size >= this.maxPoolSize) {
4049
4207
  this.evictLRU();
4050
4208
  }
4051
- let projectOverrides = {};
4052
- if (this.projectConfigLoader) {
4053
- try {
4054
- projectOverrides = this.projectConfigLoader(key) ?? {};
4055
- } catch (err) {
4056
- const message = err instanceof Error ? err.message : String(err);
4057
- this.error(`projectConfigLoader failed; using global overrides only: ${message}`);
4058
- }
4059
- }
4209
+ const projectOverrides = this.loadProjectOverrides(key);
4060
4210
  const mergedOverrides = { ...this.configOverrides, ...projectOverrides };
4061
4211
  const bridge = new BinaryBridge(this.binaryPath, key, this.bridgeOptions, mergedOverrides);
4062
4212
  this.bridges.set(key, { bridge, lastUsed: Date.now() });
@@ -4106,6 +4256,7 @@ class BridgePool {
4106
4256
  }
4107
4257
  async closeSession(_projectRoot, _session) {}
4108
4258
  async shutdown() {
4259
+ this.shutdownCalled = true;
4109
4260
  if (this.cleanupTimer) {
4110
4261
  clearInterval(this.cleanupTimer);
4111
4262
  this.cleanupTimer = null;
@@ -4118,6 +4269,9 @@ class BridgePool {
4118
4269
  this.staleBridges.clear();
4119
4270
  await Promise.allSettled(shutdowns);
4120
4271
  }
4272
+ isShutdown() {
4273
+ return this.shutdownCalled;
4274
+ }
4121
4275
  async replaceBinary(newPath) {
4122
4276
  this.binaryPath = newPath;
4123
4277
  for (const entry of this.bridges.values()) {
@@ -4127,6 +4281,12 @@ class BridgePool {
4127
4281
  this.log(`Binary path updated to ${newPath}. Active bridges marked stale — next calls will use the new binary.`);
4128
4282
  return newPath;
4129
4283
  }
4284
+ startCleanupTimer() {
4285
+ if (!Number.isFinite(this.idleTimeoutMs) || this.cleanupTimer)
4286
+ return;
4287
+ this.cleanupTimer = setInterval(() => this.cleanup(), CLEANUP_INTERVAL_MS);
4288
+ this.cleanupTimer.unref();
4289
+ }
4130
4290
  log(message, meta) {
4131
4291
  const logger = this.logger ?? getActiveLogger();
4132
4292
  if (logger) {
@@ -4158,6 +4318,36 @@ class BridgePool {
4158
4318
  this.configOverrides[key] = value;
4159
4319
  }
4160
4320
  }
4321
+ async reconfigure(projectRoot, overrides) {
4322
+ const key = normalizeKey(projectRoot);
4323
+ for (const [name, value] of Object.entries(overrides)) {
4324
+ this.setConfigureOverride(name, value);
4325
+ }
4326
+ const bridge = this.getActiveBridgeForRoot(key);
4327
+ if (!bridge)
4328
+ return;
4329
+ const projectOverrides = this.loadProjectOverrides(key);
4330
+ const response = await bridge.send("configure", {
4331
+ project_root: key,
4332
+ ...this.configOverrides,
4333
+ ...projectOverrides,
4334
+ ...overrides
4335
+ });
4336
+ if (response.success === false) {
4337
+ throw new Error(`configure refresh failed for ${key}: ${String(response.message ?? "unknown error")}`);
4338
+ }
4339
+ }
4340
+ loadProjectOverrides(key) {
4341
+ if (!this.projectConfigLoader)
4342
+ return {};
4343
+ try {
4344
+ return this.projectConfigLoader(key) ?? {};
4345
+ } catch (err) {
4346
+ const message = err instanceof Error ? err.message : String(err);
4347
+ this.error(`projectConfigLoader failed; using global overrides only: ${message}`);
4348
+ return {};
4349
+ }
4350
+ }
4161
4351
  get size() {
4162
4352
  return this.bridges.size;
4163
4353
  }
@@ -4188,7 +4378,186 @@ var init_pool = __esm(() => {
4188
4378
  };
4189
4379
  });
4190
4380
 
4191
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/auth.js
4381
+ // ../aft-bridge/dist/revivable-transport.js
4382
+ class RevivableTransportPool {
4383
+ createPool;
4384
+ onBinaryReplaced;
4385
+ activePool;
4386
+ revival = null;
4387
+ transports = new Map;
4388
+ configureOverrides = new Map;
4389
+ constructor(initialPool, createPool, onBinaryReplaced) {
4390
+ this.createPool = createPool;
4391
+ this.onBinaryReplaced = onBinaryReplaced;
4392
+ this.activePool = initialPool;
4393
+ }
4394
+ getBridge(projectRoot) {
4395
+ const key = canonicalizeProjectRoot(projectRoot);
4396
+ let transport = this.transports.get(key);
4397
+ if (!transport) {
4398
+ transport = new RevivableProjectTransport(this, key);
4399
+ this.transports.set(key, transport);
4400
+ }
4401
+ return transport;
4402
+ }
4403
+ activeBridges() {
4404
+ return this.activePool.activeBridges();
4405
+ }
4406
+ getActiveBridgeForRoot(projectRoot) {
4407
+ const key = canonicalizeProjectRoot(projectRoot);
4408
+ const bridge = this.currentBridge(key);
4409
+ if (!bridge)
4410
+ return null;
4411
+ const transport = this.getBridge(key);
4412
+ transport.refreshStatusSubscription(bridge);
4413
+ return transport;
4414
+ }
4415
+ async toolCall(projectRoot, runtime, name, rawArgs = {}, options) {
4416
+ return this.getBridge(projectRoot).toolCall(runtime.sessionID, name, rawArgs, options);
4417
+ }
4418
+ setConfigureOverride(key, value) {
4419
+ if (value === undefined)
4420
+ this.configureOverrides.delete(key);
4421
+ else
4422
+ this.configureOverrides.set(key, value);
4423
+ this.activePool.setConfigureOverride(key, value);
4424
+ }
4425
+ async reconfigure(projectRoot, overrides) {
4426
+ for (const [key, value] of Object.entries(overrides)) {
4427
+ if (value === undefined)
4428
+ this.configureOverrides.delete(key);
4429
+ else
4430
+ this.configureOverrides.set(key, value);
4431
+ }
4432
+ const pool = await this.ensureActivePool();
4433
+ await pool.reconfigure(projectRoot, overrides);
4434
+ }
4435
+ async replaceBinary(path2) {
4436
+ const replaced = await this.activePool.replaceBinary(path2);
4437
+ this.onBinaryReplaced?.(replaced);
4438
+ return replaced;
4439
+ }
4440
+ closeSession(projectRoot, session) {
4441
+ return this.activePool.closeSession(projectRoot, session);
4442
+ }
4443
+ async shutdown() {
4444
+ const revival = this.revival;
4445
+ if (revival) {
4446
+ await Promise.allSettled([revival]);
4447
+ }
4448
+ await this.activePool.shutdown();
4449
+ for (const transport of this.transports.values()) {
4450
+ transport.refreshStatusSubscription(null);
4451
+ }
4452
+ }
4453
+ isShutdown() {
4454
+ return this.activePool.isShutdown();
4455
+ }
4456
+ async ensureActivePool() {
4457
+ if (!this.activePool.isShutdown())
4458
+ return this.activePool;
4459
+ if (this.revival)
4460
+ return this.revival;
4461
+ warn("transport was shut down but new demand arrived — reviving (host quit hook fired without process exit?)");
4462
+ const revival = this.createPool().then((pool) => {
4463
+ for (const [key, value] of this.configureOverrides) {
4464
+ pool.setConfigureOverride(key, value);
4465
+ }
4466
+ this.activePool = pool;
4467
+ for (const [root, transport] of this.transports) {
4468
+ transport.refreshStatusSubscription(pool.getActiveBridgeForRoot(root));
4469
+ }
4470
+ return pool;
4471
+ });
4472
+ this.revival = revival;
4473
+ revival.then(() => {
4474
+ if (this.revival === revival)
4475
+ this.revival = null;
4476
+ }, () => {
4477
+ if (this.revival === revival)
4478
+ this.revival = null;
4479
+ });
4480
+ return revival;
4481
+ }
4482
+ currentBridge(projectRoot) {
4483
+ return this.activePool.getActiveBridgeForRoot(projectRoot);
4484
+ }
4485
+ async send(projectRoot, command, params, options) {
4486
+ const pool = await this.ensureActivePool();
4487
+ const bridge = pool.getBridge(projectRoot);
4488
+ this.getBridge(projectRoot).refreshStatusSubscription(bridge);
4489
+ return bridge.send(command, params, options);
4490
+ }
4491
+ async toolCallOnProject(projectRoot, sessionId, name, rawArgs, options) {
4492
+ const pool = await this.ensureActivePool();
4493
+ const bridge = pool.getBridge(projectRoot);
4494
+ this.getBridge(projectRoot).refreshStatusSubscription(bridge);
4495
+ return bridge.toolCall(sessionId, name, rawArgs, options);
4496
+ }
4497
+ }
4498
+
4499
+ class RevivableProjectTransport {
4500
+ owner;
4501
+ projectRoot;
4502
+ statusListeners = new Map;
4503
+ statusBridges = new Map;
4504
+ constructor(owner, projectRoot) {
4505
+ this.owner = owner;
4506
+ this.projectRoot = projectRoot;
4507
+ }
4508
+ getCwd() {
4509
+ return this.projectRoot;
4510
+ }
4511
+ getStatusBar() {
4512
+ return this.owner.currentBridge(this.projectRoot)?.getStatusBar();
4513
+ }
4514
+ getCachedStatus() {
4515
+ return this.owner.currentBridge(this.projectRoot)?.getCachedStatus() ?? null;
4516
+ }
4517
+ cacheStatusSnapshot(snapshot) {
4518
+ this.owner.currentBridge(this.projectRoot)?.cacheStatusSnapshot(snapshot);
4519
+ }
4520
+ send(command, params, options) {
4521
+ return this.owner.send(this.projectRoot, command, params, options);
4522
+ }
4523
+ toolCall(sessionId, name, rawArgs, options) {
4524
+ return this.owner.toolCallOnProject(this.projectRoot, sessionId, name, rawArgs, options);
4525
+ }
4526
+ subscribeStatus(listener) {
4527
+ if (this.statusListeners.has(listener))
4528
+ return () => this.removeStatusListener(listener);
4529
+ this.statusListeners.set(listener, () => {});
4530
+ this.bindStatusListener(listener, this.owner.currentBridge(this.projectRoot));
4531
+ return () => this.removeStatusListener(listener);
4532
+ }
4533
+ refreshStatusSubscription(bridge) {
4534
+ for (const listener of this.statusListeners.keys()) {
4535
+ this.bindStatusListener(listener, bridge);
4536
+ }
4537
+ }
4538
+ bindStatusListener(listener, bridge) {
4539
+ if (this.statusBridges.get(listener) === bridge)
4540
+ return;
4541
+ const previousUnsubscribe = this.statusListeners.get(listener);
4542
+ previousUnsubscribe?.();
4543
+ const maybe = bridge;
4544
+ const unsubscribe = maybe && typeof maybe.subscribeStatus === "function" ? maybe.subscribeStatus(listener) : () => {};
4545
+ this.statusListeners.set(listener, unsubscribe);
4546
+ this.statusBridges.set(listener, bridge);
4547
+ }
4548
+ removeStatusListener(listener) {
4549
+ const unsubscribe = this.statusListeners.get(listener);
4550
+ this.statusListeners.delete(listener);
4551
+ this.statusBridges.delete(listener);
4552
+ unsubscribe?.();
4553
+ }
4554
+ }
4555
+ var init_revivable_transport = __esm(() => {
4556
+ init_active_logger();
4557
+ init_project_identity();
4558
+ });
4559
+
4560
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/auth.js
4192
4561
  import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
4193
4562
  function computeProof(key, domain, clientNonce, serverNonce, daemonId) {
4194
4563
  const mac = createHmac("sha256", Buffer.from(key));
@@ -4249,7 +4618,132 @@ var init_auth = __esm(() => {
4249
4618
  };
4250
4619
  });
4251
4620
 
4252
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/connection-file.js
4621
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/envelope.js
4622
+ function isPureHeader(ty) {
4623
+ return ty === FrameType.Cancel || ty === FrameType.Ping || ty === FrameType.Pong || ty === FrameType.Goodbye;
4624
+ }
4625
+ function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Normal) {
4626
+ let flags = 0;
4627
+ if (binary)
4628
+ flags |= FLAG_BINARY;
4629
+ flags |= priority << FLAG_PRIORITY_SHIFT;
4630
+ if (last)
4631
+ flags |= FLAG_LAST;
4632
+ flags |= admissionClass << FLAG_ADMISSION_SHIFT;
4633
+ return flags;
4634
+ }
4635
+ function encodeHeader(header) {
4636
+ const buffer = new Uint8Array(HEADER_LEN);
4637
+ const view = new DataView(buffer.buffer);
4638
+ view.setUint32(0, header.len, true);
4639
+ buffer[4] = header.ver;
4640
+ buffer[5] = header.ty;
4641
+ buffer[6] = header.flags;
4642
+ view.setUint16(7, header.channel, true);
4643
+ view.setUint32(9, header.epoch, true);
4644
+ view.setBigUint64(13, header.corr, true);
4645
+ return buffer;
4646
+ }
4647
+ function decodeHeader(bytes) {
4648
+ if (bytes.length < FROZEN_PREFIX_LEN) {
4649
+ throw new DecodeError(`header shorter than frozen prefix: have ${bytes.length} bytes`, "too_short_for_prefix");
4650
+ }
4651
+ const ver = bytes[4];
4652
+ if (ver !== PROTOCOL_VERSION)
4653
+ throw new DecodeError(`unsupported envelope version ${ver}`, "unsupported_version");
4654
+ if (bytes.length < HEADER_LEN) {
4655
+ throw new DecodeError(`header too short for version: have ${bytes.length} bytes, need ${HEADER_LEN}`, "too_short_for_header");
4656
+ }
4657
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
4658
+ const len = view.getUint32(0, true);
4659
+ const typeByte = bytes[5];
4660
+ if (typeByte > FRAME_TYPE_MAX)
4661
+ throw new DecodeError(`unknown frame type byte ${typeByte}`, "unknown_frame_type");
4662
+ const ty = typeByte;
4663
+ const flags = bytes[6];
4664
+ if ((flags & FLAG_RESERVED_MASK) !== 0) {
4665
+ throw new DecodeError(`reserved flag bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_flag_bits");
4666
+ }
4667
+ if ((flags & FLAG_PRIORITY_MASK) >> FLAG_PRIORITY_SHIFT === 3) {
4668
+ throw new DecodeError(`reserved priority bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_priority_bits");
4669
+ }
4670
+ const admission = (flags & FLAG_ADMISSION_MASK) >> FLAG_ADMISSION_SHIFT;
4671
+ if (admission === 3) {
4672
+ throw new DecodeError(`reserved admission class set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_admission_class");
4673
+ }
4674
+ if (admission === AdmissionClass.Sheddable && ty !== FrameType.Push && ty !== FrameType.StreamData) {
4675
+ throw new DecodeError(`SHEDDABLE admission class is illegal on ${FrameType[ty]} in flags 0b${flags.toString(2).padStart(8, "0")}`, "sheddable_illegal_frame_type");
4676
+ }
4677
+ const channel = view.getUint16(7, true);
4678
+ const epoch = view.getUint32(9, true);
4679
+ if (channel === 0 && epoch !== 0) {
4680
+ throw new DecodeError(`control channel carried nonzero epoch ${epoch}`, "nonzero_epoch_on_control_channel");
4681
+ }
4682
+ if (isPureHeader(ty) && len !== 0) {
4683
+ throw new DecodeError(`pure-header frame ${FrameType[ty]} declared non-zero body length ${len}`, "pure_header_frame_with_body");
4684
+ }
4685
+ return { len, ver, ty, flags, channel, epoch, corr: view.getBigUint64(13, true) };
4686
+ }
4687
+ function buildFrame(ty, flags, channel, epoch, corr, body) {
4688
+ return buildFrameWithVersion(PROTOCOL_VERSION, ty, flags, channel, epoch, corr, body);
4689
+ }
4690
+ function buildFrameWithVersion(ver, ty, flags, channel, epoch, corr, body) {
4691
+ if (body.length > MAX_FRAME_BODY_LEN) {
4692
+ throw new DecodeError(`frame body ${body.length} exceeds max ${MAX_FRAME_BODY_LEN}`, "frame_body_too_large");
4693
+ }
4694
+ const header = { len: body.length, ver, ty, flags, channel, epoch, corr };
4695
+ decodeHeader(encodeHeader(header));
4696
+ return { header, body };
4697
+ }
4698
+ function encodeFrame(frame) {
4699
+ if (frame.header.len !== frame.body.length) {
4700
+ throw new DecodeError(`frame header length ${frame.header.len} does not match body length ${frame.body.length}`, "frame_length_mismatch");
4701
+ }
4702
+ const header = encodeHeader(frame.header);
4703
+ const output = new Uint8Array(header.length + frame.body.length);
4704
+ output.set(header, 0);
4705
+ output.set(frame.body, header.length);
4706
+ return output;
4707
+ }
4708
+ var PROTOCOL_VERSION = 2, HEADER_LEN = 21, FROZEN_PREFIX_LEN = 5, MAX_FRAME_BODY_LEN, FrameType, FRAME_TYPE_MAX, Priority, AdmissionClass, FLAG_BINARY = 1, FLAG_PRIORITY_MASK = 6, FLAG_PRIORITY_SHIFT = 1, FLAG_LAST = 8, FLAG_ADMISSION_MASK = 48, FLAG_ADMISSION_SHIFT = 4, FLAG_RESERVED_MASK = 192, DecodeError;
4709
+ var init_envelope = __esm(() => {
4710
+ MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
4711
+ (function(FrameType2) {
4712
+ FrameType2[FrameType2["Request"] = 0] = "Request";
4713
+ FrameType2[FrameType2["Response"] = 1] = "Response";
4714
+ FrameType2[FrameType2["Push"] = 2] = "Push";
4715
+ FrameType2[FrameType2["StreamData"] = 3] = "StreamData";
4716
+ FrameType2[FrameType2["StreamEnd"] = 4] = "StreamEnd";
4717
+ FrameType2[FrameType2["Error"] = 5] = "Error";
4718
+ FrameType2[FrameType2["Cancel"] = 6] = "Cancel";
4719
+ FrameType2[FrameType2["Ping"] = 7] = "Ping";
4720
+ FrameType2[FrameType2["Pong"] = 8] = "Pong";
4721
+ FrameType2[FrameType2["Hello"] = 9] = "Hello";
4722
+ FrameType2[FrameType2["HelloAck"] = 10] = "HelloAck";
4723
+ FrameType2[FrameType2["Goodbye"] = 11] = "Goodbye";
4724
+ })(FrameType || (FrameType = {}));
4725
+ FRAME_TYPE_MAX = FrameType.Goodbye;
4726
+ (function(Priority2) {
4727
+ Priority2[Priority2["Passive"] = 0] = "Passive";
4728
+ Priority2[Priority2["Interactive"] = 1] = "Interactive";
4729
+ Priority2[Priority2["Background"] = 2] = "Background";
4730
+ })(Priority || (Priority = {}));
4731
+ (function(AdmissionClass2) {
4732
+ AdmissionClass2[AdmissionClass2["Normal"] = 0] = "Normal";
4733
+ AdmissionClass2[AdmissionClass2["Expedite"] = 1] = "Expedite";
4734
+ AdmissionClass2[AdmissionClass2["Sheddable"] = 2] = "Sheddable";
4735
+ })(AdmissionClass || (AdmissionClass = {}));
4736
+ DecodeError = class DecodeError extends Error {
4737
+ code;
4738
+ constructor(message, code) {
4739
+ super(message);
4740
+ this.code = code;
4741
+ this.name = "DecodeError";
4742
+ }
4743
+ };
4744
+ });
4745
+
4746
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/connection-file.js
4253
4747
  import { promises as fs } from "node:fs";
4254
4748
  function toBytes(value, field) {
4255
4749
  if (!Array.isArray(value) || value.some((n) => typeof n !== "number")) {
@@ -4274,8 +4768,8 @@ function validate(info) {
4274
4768
  async function verifyOwnerOnly(path2) {
4275
4769
  if (process.platform === "win32")
4276
4770
  return;
4277
- const stat = await fs.stat(path2);
4278
- const mode = stat.mode & 511;
4771
+ const stat2 = await fs.stat(path2);
4772
+ const mode = stat2.mode & 511;
4279
4773
  if ((mode & 63) !== 0) {
4280
4774
  throw new ConnectionFileError(`connection file ${path2} has insecure permissions 0o${mode.toString(8)}; expected owner-only 0600`);
4281
4775
  }
@@ -4289,6 +4783,10 @@ async function readConnectionFile(path2) {
4289
4783
  } catch (err) {
4290
4784
  throw new ConnectionFileError(`connection file JSON read failed for ${path2}: ${String(err)}`);
4291
4785
  }
4786
+ const wireVersion = parsed.wire_version;
4787
+ if (wireVersion !== undefined && wireVersion !== PROTOCOL_VERSION) {
4788
+ throw new ConnectionFileError(`connection file wire_version ${String(wireVersion)} but this client speaks ${PROTOCOL_VERSION}; the client library must be upgraded`);
4789
+ }
4292
4790
  const endpointsRaw = parsed.endpoints;
4293
4791
  if (!Array.isArray(endpointsRaw)) {
4294
4792
  throw new ConnectionFileError("connection file 'endpoints' must be an array");
@@ -4313,116 +4811,59 @@ async function readConnectionFile(path2) {
4313
4811
  }
4314
4812
  var SCHEMA_VERSION = 1, MIN_KEY_LEN = 32, DAEMON_ID_LEN = 16, ConnectionFileError;
4315
4813
  var init_connection_file = __esm(() => {
4814
+ init_envelope();
4316
4815
  ConnectionFileError = class ConnectionFileError extends Error {
4317
4816
  };
4318
4817
  });
4319
4818
 
4320
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/envelope.js
4321
- function isPureHeader(ty) {
4322
- return ty === FrameType.Cancel || ty === FrameType.Ping || ty === FrameType.Pong || ty === FrameType.Goodbye;
4323
- }
4324
- function buildFlags(binary, priority, last) {
4325
- let b = 0;
4326
- if (binary)
4327
- b |= FLAG_BINARY;
4328
- b |= priority << FLAG_PRIORITY_SHIFT;
4329
- if (last)
4330
- b |= FLAG_LAST;
4331
- return b;
4332
- }
4333
- function encodeHeader(h) {
4334
- const buf = new Uint8Array(HEADER_LEN);
4335
- const view = new DataView(buf.buffer);
4336
- view.setUint32(0, h.len, true);
4337
- buf[4] = h.ver;
4338
- buf[5] = h.ty;
4339
- buf[6] = h.flags;
4340
- view.setUint16(7, h.channel, true);
4341
- view.setBigUint64(9, h.corr, true);
4342
- return buf;
4343
- }
4344
- function decodeHeader(bytes) {
4345
- if (bytes.length < FROZEN_PREFIX_LEN) {
4346
- throw new DecodeError(`header shorter than frozen prefix: have ${bytes.length} bytes`);
4347
- }
4348
- const ver = bytes[4];
4349
- if (ver !== PROTOCOL_VERSION) {
4350
- throw new DecodeError(`unsupported envelope version ${ver}`);
4351
- }
4352
- if (bytes.length < HEADER_LEN) {
4353
- throw new DecodeError(`header too short for version: have ${bytes.length} bytes, need ${HEADER_LEN}`);
4354
- }
4355
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
4356
- const len = view.getUint32(0, true);
4357
- const tyByte = bytes[5];
4358
- if (tyByte > FRAME_TYPE_MAX) {
4359
- throw new DecodeError(`unknown frame type byte ${tyByte}`);
4360
- }
4361
- const ty = tyByte;
4362
- const flags = bytes[6];
4363
- if ((flags & FLAG_RESERVED_MASK) !== 0) {
4364
- throw new DecodeError(`reserved flag bits set in flags 0b${flags.toString(2)}`);
4365
- }
4366
- if ((flags & FLAG_PRIORITY_MASK) >> FLAG_PRIORITY_SHIFT === 3) {
4367
- throw new DecodeError(`reserved priority bits set in flags 0b${flags.toString(2)}`);
4368
- }
4369
- if (isPureHeader(ty) && len !== 0) {
4370
- throw new DecodeError(`pure-header frame ${FrameType[ty]} declared non-zero body length ${len}`);
4371
- }
4372
- const channel = view.getUint16(7, true);
4373
- const corr = view.getBigUint64(9, true);
4374
- return { len, ver, ty, flags, channel, corr };
4375
- }
4376
- function buildFrame(ty, flags, channel, corr, body) {
4377
- return buildFrameWithVersion(PROTOCOL_VERSION, ty, flags, channel, corr, body);
4378
- }
4379
- function buildFrameWithVersion(ver, ty, flags, channel, corr, body) {
4380
- if (body.length > MAX_FRAME_BODY_LEN) {
4381
- throw new DecodeError(`frame body ${body.length} exceeds max ${MAX_FRAME_BODY_LEN}`);
4382
- }
4383
- if (isPureHeader(ty) && body.length !== 0) {
4384
- throw new DecodeError(`pure-header frame ${FrameType[ty]} cannot carry a body`);
4385
- }
4386
- return {
4387
- header: { len: body.length, ver, ty, flags, channel, corr },
4388
- body
4389
- };
4390
- }
4391
- function encodeFrame(frame) {
4392
- const header = encodeHeader(frame.header);
4393
- const out = new Uint8Array(header.length + frame.body.length);
4394
- out.set(header, 0);
4395
- out.set(frame.body, header.length);
4396
- return out;
4397
- }
4398
- var PROTOCOL_VERSION = 1, HEADER_LEN = 17, FROZEN_PREFIX_LEN = 5, MAX_FRAME_BODY_LEN, FrameType, FRAME_TYPE_MAX, Priority, FLAG_BINARY = 1, FLAG_PRIORITY_MASK = 6, FLAG_PRIORITY_SHIFT = 1, FLAG_LAST = 8, FLAG_RESERVED_MASK = 240, DecodeError;
4399
- var init_envelope = __esm(() => {
4400
- MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
4401
- (function(FrameType2) {
4402
- FrameType2[FrameType2["Request"] = 0] = "Request";
4403
- FrameType2[FrameType2["Response"] = 1] = "Response";
4404
- FrameType2[FrameType2["Push"] = 2] = "Push";
4405
- FrameType2[FrameType2["StreamData"] = 3] = "StreamData";
4406
- FrameType2[FrameType2["StreamEnd"] = 4] = "StreamEnd";
4407
- FrameType2[FrameType2["Error"] = 5] = "Error";
4408
- FrameType2[FrameType2["Cancel"] = 6] = "Cancel";
4409
- FrameType2[FrameType2["Ping"] = 7] = "Ping";
4410
- FrameType2[FrameType2["Pong"] = 8] = "Pong";
4411
- FrameType2[FrameType2["Hello"] = 9] = "Hello";
4412
- FrameType2[FrameType2["HelloAck"] = 10] = "HelloAck";
4413
- FrameType2[FrameType2["Goodbye"] = 11] = "Goodbye";
4414
- })(FrameType || (FrameType = {}));
4415
- FRAME_TYPE_MAX = FrameType.Goodbye;
4416
- (function(Priority2) {
4417
- Priority2[Priority2["Passive"] = 0] = "Passive";
4418
- Priority2[Priority2["Interactive"] = 1] = "Interactive";
4419
- Priority2[Priority2["Background"] = 2] = "Background";
4420
- })(Priority || (Priority = {}));
4421
- DecodeError = class DecodeError extends Error {
4819
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/route-handle.js
4820
+ class RouteHandle {
4821
+ channel;
4822
+ epoch;
4823
+ constructor(channel, epoch, token) {
4824
+ if (!Number.isInteger(channel) || channel <= 0 || channel > 65535) {
4825
+ throw new RangeError(`route channel must be an integer in 1..65535, got ${channel}`);
4826
+ }
4827
+ if (!Number.isInteger(epoch) || epoch <= 0 || epoch > 4294967295) {
4828
+ throw new RangeError(`route epoch must be an integer in 1..4294967295, got ${epoch}`);
4829
+ }
4830
+ this.channel = channel;
4831
+ this.epoch = epoch;
4832
+ connectionToken.set(this, token);
4833
+ Object.freeze(this);
4834
+ }
4835
+ static create(channel, epoch, token) {
4836
+ return new RouteHandle(channel, epoch, token);
4837
+ }
4838
+ }
4839
+ function createRouteHandle(channel, epoch, token) {
4840
+ const factory = RouteHandle;
4841
+ return factory.create(channel, epoch, token);
4842
+ }
4843
+ function newConnectionToken() {
4844
+ return Object.freeze({});
4845
+ }
4846
+ function belongsToConnection(handle, token) {
4847
+ return connectionToken.get(handle) === token;
4848
+ }
4849
+ function sameRouteHandle(left, right) {
4850
+ return left === right;
4851
+ }
4852
+ var connectionToken, StaleRouteHandleError;
4853
+ var init_route_handle = __esm(() => {
4854
+ connectionToken = new WeakMap;
4855
+ StaleRouteHandleError = class StaleRouteHandleError extends Error {
4856
+ handle;
4857
+ code = "stale_route_handle";
4858
+ constructor(handle) {
4859
+ super(`route handle (${handle.channel}, ${handle.epoch}) is not live on the current connection`);
4860
+ this.handle = handle;
4861
+ this.name = "StaleRouteHandleError";
4862
+ }
4422
4863
  };
4423
4864
  });
4424
4865
 
4425
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/socket.js
4866
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/socket.js
4426
4867
  import net from "node:net";
4427
4868
 
4428
4869
  class SubcSocket {
@@ -4471,6 +4912,24 @@ class SubcSocket {
4471
4912
  });
4472
4913
  });
4473
4914
  }
4915
+ async readFrame(headerDeadlineMs, bodyDeadline, onHeader) {
4916
+ const prefix = await this.readExact(FROZEN_PREFIX_LEN, headerDeadlineMs);
4917
+ const version = prefix[4];
4918
+ if (version !== PROTOCOL_VERSION)
4919
+ throw new DecodeError(`unsupported envelope version ${version}`, "unsupported_version");
4920
+ const remainder = await this.readExact(HEADER_LEN - FROZEN_PREFIX_LEN, headerDeadlineMs);
4921
+ const headerBytes = new Uint8Array(HEADER_LEN);
4922
+ headerBytes.set(prefix);
4923
+ headerBytes.set(remainder, FROZEN_PREFIX_LEN);
4924
+ const header = decodeHeader(headerBytes);
4925
+ if (header.len > MAX_FRAME_BODY_LEN) {
4926
+ throw new DecodeError(`frame body ${header.len} exceeds max ${MAX_FRAME_BODY_LEN}`, "frame_body_too_large");
4927
+ }
4928
+ onHeader?.();
4929
+ const bodyDeadlineMs = typeof bodyDeadline === "number" ? bodyDeadline : Date.now() + bodyDeadline.afterHeaderMs;
4930
+ const body = header.len === 0 ? new Uint8Array(0) : await this.readExact(header.len, bodyDeadlineMs);
4931
+ return { header, body };
4932
+ }
4474
4933
  readExact(n, deadlineMs) {
4475
4934
  if (this.waiter) {
4476
4935
  return Promise.reject(new Error("concurrent readExact is not supported"));
@@ -4593,6 +5052,7 @@ class SubcSocket {
4593
5052
  }
4594
5053
  var SocketClosedError, SocketTimeoutError, SocketWriteNotQueuedError, SocketWriteQueuedError;
4595
5054
  var init_socket = __esm(() => {
5055
+ init_envelope();
4596
5056
  SocketClosedError = class SocketClosedError extends Error {
4597
5057
  };
4598
5058
  SocketTimeoutError = class SocketTimeoutError extends Error {
@@ -4613,7 +5073,7 @@ var init_socket = __esm(() => {
4613
5073
  };
4614
5074
  });
4615
5075
 
4616
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/client.js
5076
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/client.js
4617
5077
  import { promises as fs2 } from "node:fs";
4618
5078
  import { debuglog } from "node:util";
4619
5079
 
@@ -4623,7 +5083,11 @@ class SubcClient {
4623
5083
  opts;
4624
5084
  nextCorr = 1n;
4625
5085
  pending = new Map;
5086
+ lateResponses = new Map;
4626
5087
  routes = new Map;
5088
+ liveRoutes = new Map;
5089
+ connectionToken = newConnectionToken();
5090
+ ingressEpochDropCount = 0;
4627
5091
  closedErr = null;
4628
5092
  closeStarted = false;
4629
5093
  reconnecting = null;
@@ -4651,40 +5115,71 @@ class SubcClient {
4651
5115
  }
4652
5116
  async routeOpen(target, identity, opts = {}) {
4653
5117
  const consumerIdentity = routeOpenConsumerIdentity(opts);
5118
+ const consumerCapabilities = opts.consumerCapabilities;
4654
5119
  const body = this.encode({
4655
5120
  op: "route.open",
4656
5121
  target,
4657
5122
  identity,
4658
- ...consumerIdentity ? { consumer_identity: consumerIdentity } : {}
5123
+ ...consumerIdentity ? { consumer_identity: consumerIdentity } : {},
5124
+ ...consumerCapabilities !== undefined ? { consumer_capabilities: consumerCapabilities } : {}
4659
5125
  });
4660
- const reply = await this.controlRpc(body);
4661
- const parsed = this.parseJson(reply);
4662
- if (typeof parsed.route_channel !== "number") {
4663
- throw new SubcError(`route.open returned no route_channel: ${JSON.stringify(parsed)}`);
4664
- }
4665
- return parsed.route_channel;
5126
+ let installed = null;
5127
+ const install = (frame) => {
5128
+ if (frame.header.ty !== FrameType.Response)
5129
+ return true;
5130
+ const parsed = this.parseJson(frame);
5131
+ if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number") {
5132
+ throw new SubcError(`route.open returned no route handle: ${JSON.stringify(parsed)}`);
5133
+ }
5134
+ installed = this.installRoute(parsed.route_channel, parsed.route_epoch);
5135
+ return true;
5136
+ };
5137
+ const closeLateRoute = (frame) => {
5138
+ if (frame.header.ty !== FrameType.Response)
5139
+ return;
5140
+ try {
5141
+ const parsed = this.parseJson(frame);
5142
+ if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number")
5143
+ return;
5144
+ const lateHandle = this.installRoute(parsed.route_channel, parsed.route_epoch);
5145
+ this.failHandle(lateHandle, new SubcError("late route.open was closed", "route_closed"));
5146
+ this.liveRoutes.delete(lateHandle.channel);
5147
+ this.sendRouteGoodbye(lateHandle, true);
5148
+ } catch {
5149
+ this.closeConnectionAfterCleanupFailure();
5150
+ }
5151
+ };
5152
+ await this.controlRpc(body, install, closeLateRoute);
5153
+ if (!installed)
5154
+ throw new SubcError("route.open response was not installed");
5155
+ return installed;
4666
5156
  }
4667
- async request(routeChannel, body, opts = {}) {
5157
+ async request(handle, body, opts = {}) {
5158
+ this.assertLiveHandle(handle);
4668
5159
  const bytes = body instanceof Uint8Array ? body : this.encode(body);
4669
5160
  const priority = opts.priority ?? Priority.Interactive;
4670
- const reply = await this.send(routeChannel, bytes, priority, opts.timeoutMs, opts.onProgress);
5161
+ const admission = opts.admissionClass ?? AdmissionClass.Normal;
5162
+ const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
4671
5163
  return this.parseJson(reply);
4672
5164
  }
4673
5165
  async call(moduleId, method, params, opts = {}) {
4674
5166
  const body = params === undefined ? { method } : { method, params };
4675
5167
  let retriedUnknownChannel = false;
4676
5168
  for (;; ) {
4677
- const routeChannel = await this.cachedRouteChannel(moduleId, opts);
5169
+ const routeHandle = await this.cachedRouteHandle(moduleId, opts);
4678
5170
  try {
4679
- return await this.managedRequest(routeChannel, body, opts);
5171
+ return await this.managedRequest(routeHandle, body, opts);
4680
5172
  } catch (err) {
4681
5173
  if (!(err instanceof SubcCallError))
4682
5174
  throw this.terminalCallError("managed call failed", err);
4683
5175
  if (err.code === "unknown_channel" && !retriedUnknownChannel && !this.closeStarted) {
4684
5176
  retriedUnknownChannel = true;
4685
- this.evictRouteChannel(routeChannel);
5177
+ this.evictRouteHandle(routeHandle);
4686
5178
  continue;
4687
5179
  }
5180
+ if (err.code === "unknown_channel" && retriedUnknownChannel) {
5181
+ this.evictRouteHandle(routeHandle);
5182
+ }
4688
5183
  if (err.kind === "not_sent") {
4689
5184
  try {
4690
5185
  await this.reconnectAfterDrop(err);
@@ -4700,29 +5195,31 @@ class SubcClient {
4700
5195
  }
4701
5196
  }
4702
5197
  }
4703
- subscribe(routeChannel, body, onEvent, opts = {}) {
5198
+ subscribe(handle, body, onEvent, opts = {}) {
5199
+ this.assertLiveHandle(handle);
4704
5200
  const bytes = body instanceof Uint8Array ? body : this.encode(body);
4705
5201
  const priority = opts.priority ?? Priority.Interactive;
4706
- const corr = this.nextCorr++;
4707
- const key = `${routeChannel}:${corr}`;
5202
+ const admission = opts.admissionClass ?? AdmissionClass.Normal;
5203
+ const corr = this.allocateCorr();
5204
+ const key = pendingKey(handle, corr);
4708
5205
  const closed = new Promise((resolve7, reject) => {
4709
5206
  if (this.closedErr) {
4710
5207
  reject(this.closedErr);
4711
5208
  return;
4712
5209
  }
4713
5210
  this.pending.set(key, {
4714
- channel: routeChannel,
5211
+ handle,
4715
5212
  resolve: () => resolve7(),
4716
5213
  reject,
4717
5214
  onProgress: onEvent,
4718
5215
  timer: null,
4719
5216
  subscription: true
4720
5217
  });
4721
- const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), routeChannel, corr, bytes);
5218
+ const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), handle.channel, handle.epoch, corr, bytes);
4722
5219
  this.sock.write(encodeFrame(frame), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch((err) => {
4723
- const p = this.pending.get(key);
4724
- if (p)
4725
- this.rejectPending(key, p, err instanceof Error ? err : new SubcError(String(err)));
5220
+ const pending = this.pending.get(key);
5221
+ if (pending)
5222
+ this.rejectPending(key, pending, err instanceof Error ? err : new SubcError(String(err)));
4726
5223
  });
4727
5224
  });
4728
5225
  let cancelled = false;
@@ -4730,45 +5227,77 @@ class SubcClient {
4730
5227
  if (cancelled)
4731
5228
  return;
4732
5229
  cancelled = true;
4733
- const cancel = buildFrame(FrameType.Cancel, buildFlags(false, priority, false), routeChannel, corr, EMPTY_BODY);
4734
- this.sock.write(encodeFrame(cancel), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch(() => {});
5230
+ this.cancel(handle, corr, priority);
4735
5231
  };
4736
5232
  return { unsubscribe, closed };
4737
5233
  }
4738
- async closeRoute(target, identity, opts = {}) {
5234
+ cancel(handle, corr, priority = Priority.Interactive) {
5235
+ this.assertLiveHandle(handle);
5236
+ const cancel = buildFrame(FrameType.Cancel, buildFlags(false, priority, false), handle.channel, handle.epoch, corr, EMPTY_BODY);
5237
+ this.sock.write(encodeFrame(cancel), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch(() => {
5238
+ return;
5239
+ });
5240
+ }
5241
+ async routePoll(handle, kind) {
5242
+ this.assertLiveHandle(handle);
5243
+ const body = this.encode({
5244
+ op: "route.poll",
5245
+ route_channel: handle.channel,
5246
+ route_epoch: handle.epoch,
5247
+ kind
5248
+ });
5249
+ const reply = await this.controlRpc(body, (frame) => {
5250
+ if (frame.header.ty !== FrameType.Response)
5251
+ return true;
5252
+ const parsed = this.parseJson(frame);
5253
+ return parsed.route_channel === handle.channel && parsed.route_epoch === handle.epoch;
5254
+ });
5255
+ return this.parseJson(reply);
5256
+ }
5257
+ async closeRoute(handle, opts = {}) {
5258
+ this.assertLiveHandle(handle);
5259
+ for (const [key, cached] of this.routes) {
5260
+ if (cached.handle && sameRouteHandle(cached.handle, handle)) {
5261
+ cached.closed = true;
5262
+ cached.handle = null;
5263
+ this.routes.delete(key);
5264
+ }
5265
+ }
5266
+ if (opts.drain)
5267
+ await this.drainUnaryOnHandle(handle);
5268
+ this.failHandle(handle, new SubcError("route closed by closeRoute", "route_closed"));
5269
+ if (this.liveRoutes.get(handle.channel) === handle)
5270
+ this.liveRoutes.delete(handle.channel);
5271
+ this.sendRouteGoodbye(handle);
5272
+ }
5273
+ async closeManagedRoute(target, identity, opts = {}) {
4739
5274
  const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts));
4740
5275
  const cached = this.routes.get(key);
4741
5276
  if (!cached)
4742
5277
  return;
4743
5278
  cached.closed = true;
4744
5279
  this.routes.delete(key);
4745
- const channel = cached.channel;
4746
- cached.channel = null;
4747
- if (channel !== null)
4748
- await this.closeRouteChannel(channel, opts);
5280
+ const handle = cached.handle;
5281
+ cached.handle = null;
5282
+ if (handle)
5283
+ await this.closeRoute(handle, opts);
4749
5284
  }
4750
- async closeRouteChannel(channel, opts = {}) {
4751
- if (channel === 0)
4752
- return;
4753
- if (opts.drain) {
4754
- await this.drainUnaryOnChannel(channel);
4755
- }
4756
- this.failChannel(channel, new SubcError("route closed by closeRoute", "route_closed"));
4757
- this.sendRouteGoodbye(channel);
5285
+ async closeRouteChannel(handle, opts = {}) {
5286
+ await this.closeRoute(handle, opts);
4758
5287
  }
4759
5288
  close() {
4760
5289
  this.closeStarted = true;
4761
5290
  this.fail(new SubcError("client closed"));
4762
5291
  this.sock.close();
4763
5292
  }
4764
- drainUnaryOnChannel(channel) {
5293
+ drainUnaryOnHandle(handle) {
4765
5294
  const waiters = [];
4766
5295
  for (const pending of this.pending.values()) {
4767
- if (pending.channel === channel && !pending.subscription) {
5296
+ if (pending.handle === handle && !pending.subscription) {
4768
5297
  waiters.push(new Promise((resolve7) => {
4769
- const prev = pending.onSettle;
5298
+ const previous = pending.onSettle;
4770
5299
  pending.onSettle = () => {
4771
- prev?.();
5300
+ previous?.();
4772
5301
  resolve7();
4773
5302
  };
4774
5303
  }));
@@ -4778,11 +5307,21 @@ class SubcClient {
4778
5307
  return;
4779
5308
  });
4780
5309
  }
4781
- sendRouteGoodbye(channel) {
4782
- if (this.closedErr)
5310
+ sendRouteGoodbye(handle, closeOnQueueFailure = false) {
5311
+ this.assertLiveConnection(handle);
5312
+ if (this.closedErr) {
5313
+ if (closeOnQueueFailure)
5314
+ this.closeConnectionAfterCleanupFailure();
4783
5315
  return;
4784
- const goodbye = buildFrame(FrameType.Goodbye, buildFlags(false, Priority.Interactive, false), channel, 0n, EMPTY_BODY);
4785
- this.sock.write(encodeFrame(goodbye), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch(() => {});
5316
+ }
5317
+ const goodbye = buildFrame(FrameType.Goodbye, buildFlags(false, Priority.Interactive, false), handle.channel, handle.epoch, 0n, EMPTY_BODY);
5318
+ const write = this.sock.writeTracked(encodeFrame(goodbye), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS);
5319
+ if (!write.queued && closeOnQueueFailure)
5320
+ this.closeConnectionAfterCleanupFailure();
5321
+ write.completed.catch(() => {
5322
+ if (closeOnQueueFailure && !write.queued)
5323
+ this.closeConnectionAfterCleanupFailure();
5324
+ });
4786
5325
  }
4787
5326
  static async openConnection(opts) {
4788
5327
  const conn = await readConnectionFile(opts.connectionFile);
@@ -4797,37 +5336,48 @@ class SubcClient {
4797
5336
  }
4798
5337
  return { sock, conn };
4799
5338
  }
4800
- async controlRpc(body) {
4801
- return this.send(0, body, Priority.Interactive, undefined, undefined);
5339
+ async controlRpc(body, acceptFrame, onLateResponse) {
5340
+ return this.send(null, body, Priority.Interactive, AdmissionClass.Normal, undefined, undefined, acceptFrame, onLateResponse);
4802
5341
  }
4803
- send(channel, body, priority, timeoutMs, onProgress) {
5342
+ send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse) {
5343
+ if (handle)
5344
+ this.assertLiveHandle(handle);
4804
5345
  if (this.closedErr)
4805
5346
  return Promise.reject(this.closedErr);
4806
- const corr = this.nextCorr++;
4807
- const key = `${channel}:${corr}`;
4808
- const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), channel, corr, body);
5347
+ let corr;
5348
+ try {
5349
+ corr = this.allocateCorr();
5350
+ } catch (error2) {
5351
+ return Promise.reject(error2);
5352
+ }
5353
+ const key = pendingKey(handle, corr);
5354
+ const channel = handle?.channel ?? 0;
5355
+ const epoch = handle?.epoch ?? 0;
5356
+ const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), channel, epoch, corr, body);
4809
5357
  return new Promise((resolve7, reject) => {
4810
5358
  const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
4811
5359
  const pending = {
4812
- channel,
5360
+ handle,
4813
5361
  resolve: resolve7,
4814
5362
  reject,
4815
5363
  onProgress,
4816
- timer: null
5364
+ timer: null,
5365
+ acceptFrame,
5366
+ onLateResponse
4817
5367
  };
4818
- pending.timer = setTimeout(() => {
4819
- this.arbitrateTimeout(key, pending, channel, corr, ms);
4820
- }, ms);
5368
+ pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
4821
5369
  this.pending.set(key, pending);
4822
- this.sock.write(encodeFrame(frame), Date.now() + ms).catch((err) => {
4823
- const p = this.pending.get(key);
4824
- if (p)
4825
- this.rejectPending(key, p, err instanceof Error ? err : new SubcError(String(err)));
5370
+ this.sock.write(encodeFrame(frame), Date.now() + ms).catch((error2) => {
5371
+ const current = this.pending.get(key);
5372
+ if (current)
5373
+ this.rejectPending(key, current, error2 instanceof Error ? error2 : new SubcError(String(error2)));
4826
5374
  });
4827
5375
  });
4828
5376
  }
4829
5377
  arbitrateTimeout(key, pending, channel, corr, ms) {
4830
5378
  const settleAsTimeout = () => {
5379
+ if (pending.onLateResponse)
5380
+ this.lateResponses.set(key, pending.onLateResponse);
4831
5381
  this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms), REQUEST_DEADLINE_MARKER));
4832
5382
  };
4833
5383
  const graceDeadline = Date.now() + this.opts.timeoutArbitrationGraceMs;
@@ -4843,59 +5393,67 @@ class SubcClient {
4843
5393
  };
4844
5394
  setImmediate(arbitrate);
4845
5395
  }
4846
- async managedRequest(routeChannel, body, opts) {
5396
+ async managedRequest(handle, body, opts) {
4847
5397
  const bytes = body instanceof Uint8Array ? body : this.encode(body);
4848
5398
  const priority = opts.priority ?? Priority.Interactive;
5399
+ const admission = opts.admissionClass ?? AdmissionClass.Normal;
4849
5400
  try {
4850
- const reply = await this.sendManaged(routeChannel, bytes, priority, opts.timeoutMs, opts.onProgress);
5401
+ const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
4851
5402
  return this.parseJson(reply);
4852
- } catch (err) {
4853
- if (err instanceof SubcCallError)
4854
- throw err;
4855
- throw this.terminalCallError("managed call failed", err);
5403
+ } catch (error2) {
5404
+ if (error2 instanceof SubcCallError)
5405
+ throw error2;
5406
+ throw this.terminalCallError("managed call failed", error2);
4856
5407
  }
4857
5408
  }
4858
- sendManaged(channel, body, priority, timeoutMs, onProgress) {
5409
+ sendManaged(handle, body, priority, admission, timeoutMs, onProgress) {
5410
+ try {
5411
+ this.assertLiveHandle(handle);
5412
+ } catch (error2) {
5413
+ return Promise.reject(this.notSentCallError("request used a stale route handle", error2));
5414
+ }
4859
5415
  if (this.closedErr) {
4860
5416
  return Promise.reject(this.notSentCallError("request was not sent because the subc connection was already closed", this.closedErr));
4861
5417
  }
4862
- const corr = this.nextCorr++;
4863
- const key = `${channel}:${corr}`;
4864
- const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), channel, corr, body);
5418
+ let corr;
5419
+ try {
5420
+ corr = this.allocateCorr();
5421
+ } catch (error2) {
5422
+ return Promise.reject(this.notSentCallError("request correlation allocator was exhausted", error2));
5423
+ }
5424
+ const key = pendingKey(handle, corr);
5425
+ const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), handle.channel, handle.epoch, corr, body);
4865
5426
  let handedToSocket = false;
4866
- const classifyFailure = (err) => {
4867
- if (!handedToSocket) {
4868
- return this.notSentCallError("request bytes were not queued to the subc socket", err);
4869
- }
4870
- if (err instanceof SubcError && err.code === REQUEST_DEADLINE_MARKER) {
4871
- return new SubcCallError("outcome_unknown", `managed call deadline exceeded after request bytes were queued to the local socket; no terminal response was observed; outcome unknown${causeMessage(err)}`, DEADLINE_NO_DROP_CODE, err);
5427
+ const classifyFailure = (error2) => {
5428
+ if (!handedToSocket)
5429
+ return this.notSentCallError("request bytes were not queued to the subc socket", error2);
5430
+ if (error2 instanceof SubcError && error2.code === REQUEST_DEADLINE_MARKER) {
5431
+ return new SubcCallError("outcome_unknown", `managed call deadline exceeded after request bytes were queued to the local socket; no terminal response was observed; outcome unknown${causeMessage(error2)}`, DEADLINE_NO_DROP_CODE, error2);
4872
5432
  }
4873
- return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", err);
5433
+ return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", error2);
4874
5434
  };
4875
5435
  return new Promise((resolve7, reject) => {
4876
5436
  const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
4877
5437
  const pending = {
4878
- channel,
5438
+ handle,
4879
5439
  resolve: resolve7,
4880
5440
  reject,
4881
5441
  onProgress,
4882
5442
  timer: null,
4883
5443
  classifyFailure
4884
5444
  };
4885
- pending.timer = setTimeout(() => {
4886
- this.arbitrateTimeout(key, pending, channel, corr, ms);
4887
- }, ms);
5445
+ pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, handle.channel, corr, ms), ms);
4888
5446
  this.pending.set(key, pending);
4889
5447
  const write = this.sock.writeTracked(encodeFrame(frame), Date.now() + ms);
4890
5448
  handedToSocket = write.queued;
4891
- write.completed.catch((err) => {
4892
- const p = this.pending.get(key);
4893
- if (p)
4894
- this.rejectPending(key, p, err instanceof Error ? err : new SubcError(String(err)));
5449
+ write.completed.catch((error2) => {
5450
+ const current = this.pending.get(key);
5451
+ if (current)
5452
+ this.rejectPending(key, current, error2 instanceof Error ? error2 : new SubcError(String(error2)));
4895
5453
  });
4896
5454
  });
4897
5455
  }
4898
- async cachedRouteChannel(moduleId, opts) {
5456
+ async cachedRouteHandle(moduleId, opts) {
4899
5457
  const identity = opts.identity ?? this.opts.identity;
4900
5458
  if (!identity) {
4901
5459
  throw new SubcCallError("terminal", "managed call requires a BindIdentity in SubcClient.connect({ identity }) or call(..., { identity })", "missing_identity");
@@ -4911,15 +5469,13 @@ class SubcClient {
4911
5469
  target,
4912
5470
  identity,
4913
5471
  consumerIdentity,
4914
- channel: null,
4915
- generation: 0,
5472
+ handle: null,
4916
5473
  opening: null
4917
5474
  };
4918
5475
  this.routes.set(key, cached);
4919
5476
  }
4920
- if (cached.channel !== null && cached.generation === this.generation && !this.closedErr) {
4921
- return cached.channel;
4922
- }
5477
+ if (cached.handle && this.isLiveHandle(cached.handle))
5478
+ return cached.handle;
4923
5479
  if (!cached.opening) {
4924
5480
  cached.opening = this.openCachedRoute(cached).finally(() => {
4925
5481
  cached.opening = null;
@@ -4936,44 +5492,43 @@ class SubcClient {
4936
5492
  throw this.routeClosedDuringOpen();
4937
5493
  try {
4938
5494
  await this.ensureConnectedForManaged();
4939
- } catch (err) {
4940
- throw this.notSentRecoveryError("route.open could not run because reconnect failed", err);
4941
- }
4942
- if (cached.channel !== null && cached.generation === this.generation && !this.closedErr) {
4943
- return cached.channel;
5495
+ } catch (error2) {
5496
+ throw this.notSentRecoveryError("route.open could not run because reconnect failed", error2);
4944
5497
  }
5498
+ if (cached.handle && this.isLiveHandle(cached.handle))
5499
+ return cached.handle;
4945
5500
  try {
4946
- const channel = await this.routeOpen(cached.target, cached.identity, {
5501
+ const handle = await this.routeOpen(cached.target, cached.identity, {
4947
5502
  consumerIdentity: cached.consumerIdentity ?? null
4948
5503
  });
4949
5504
  if (cached.closed) {
4950
- this.sendRouteGoodbye(channel);
5505
+ this.liveRoutes.delete(handle.channel);
5506
+ this.sendRouteGoodbye(handle);
4951
5507
  throw this.routeClosedDuringOpen();
4952
5508
  }
4953
- cached.channel = channel;
4954
- cached.generation = this.generation;
4955
- return channel;
4956
- } catch (err) {
4957
- if (err instanceof SubcCallError && err.code === "route_closed")
4958
- throw err;
4959
- if (!this.closeStarted && isConsumerReconnectTransient(err)) {
5509
+ cached.handle = handle;
5510
+ return handle;
5511
+ } catch (error2) {
5512
+ if (error2 instanceof SubcCallError && error2.code === "route_closed")
5513
+ throw error2;
5514
+ if (!this.closeStarted && isConsumerReconnectTransient(error2)) {
4960
5515
  try {
4961
- await this.reconnectAfterDrop(err);
4962
- } catch (reconnectErr) {
4963
- throw this.notSentRecoveryError("route.open was not sent and reconnect failed", reconnectErr);
5516
+ await this.reconnectAfterDrop(error2);
5517
+ } catch (reconnectError) {
5518
+ throw this.notSentRecoveryError("route.open was not sent and reconnect failed", reconnectError);
4964
5519
  }
4965
5520
  continue;
4966
5521
  }
4967
- if (!this.closeStarted && err instanceof SubcError && isRetryableRouteOpenCode(err.code)) {
5522
+ if (!this.closeStarted && error2 instanceof SubcError && isRetryableRouteOpenCode(error2.code)) {
4968
5523
  routeRetryAttempt += 1;
4969
5524
  if (routeRetryAttempt < this.opts.reconnectBackoff.maxAttempts && Date.now() < routeRetryDeadline) {
4970
5525
  await this.opts.sleep(routeRetryDelay);
4971
5526
  routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
4972
5527
  continue;
4973
5528
  }
4974
- throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${err.code} (retry budget exhausted)`, err);
5529
+ throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error2.code} (retry budget exhausted)`, error2);
4975
5530
  }
4976
- throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, err);
5531
+ throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, error2);
4977
5532
  }
4978
5533
  }
4979
5534
  }
@@ -5036,25 +5591,27 @@ class SubcClient {
5036
5591
  this.currentConn = opened.conn;
5037
5592
  this.closedErr = null;
5038
5593
  this.generation += 1;
5594
+ this.connectionToken = newConnectionToken();
5595
+ this.liveRoutes.clear();
5596
+ this.lateResponses.clear();
5597
+ this.nextCorr = 1n;
5039
5598
  this.readLoop(opened.sock, this.generation);
5040
5599
  }
5041
5600
  async reopenCachedRoutes() {
5042
- for (const cached of this.routes.values()) {
5043
- cached.channel = null;
5044
- cached.generation = 0;
5045
- }
5601
+ for (const cached of this.routes.values())
5602
+ cached.handle = null;
5046
5603
  for (const cached of this.routes.values()) {
5047
5604
  if (cached.closed)
5048
5605
  continue;
5049
- const channel = await this.routeOpen(cached.target, cached.identity, {
5606
+ const handle = await this.routeOpen(cached.target, cached.identity, {
5050
5607
  consumerIdentity: cached.consumerIdentity ?? null
5051
5608
  });
5052
5609
  if (cached.closed) {
5053
- this.sendRouteGoodbye(channel);
5610
+ this.liveRoutes.delete(handle.channel);
5611
+ this.sendRouteGoodbye(handle);
5054
5612
  continue;
5055
5613
  }
5056
- cached.channel = channel;
5057
- cached.generation = this.generation;
5614
+ cached.handle = handle;
5058
5615
  }
5059
5616
  }
5060
5617
  timeoutMessage(channel, corr, ms) {
@@ -5068,28 +5625,37 @@ class SubcClient {
5068
5625
  async readLoop(sock, generation) {
5069
5626
  try {
5070
5627
  for (;; ) {
5071
- const headerBytes = await sock.readExact(HEADER_LEN, Number.POSITIVE_INFINITY);
5072
- this.readerActive = true;
5628
+ this.readerActive = false;
5629
+ const frame = await sock.readFrame(Number.POSITIVE_INFINITY, { afterHeaderMs: BODY_READ_TIMEOUT_MS }, () => {
5630
+ this.readerActive = true;
5631
+ });
5073
5632
  try {
5074
- const header = decodeHeader(headerBytes);
5075
- const body = header.len === 0 ? new Uint8Array(0) : await sock.readExact(header.len, Date.now() + BODY_READ_TIMEOUT_MS);
5076
- if (this.sock === sock && this.generation === generation) {
5077
- this.dispatch({ header, body });
5078
- }
5633
+ if (this.sock === sock && this.generation === generation)
5634
+ this.dispatch(frame);
5079
5635
  } finally {
5080
5636
  this.readerActive = false;
5081
5637
  }
5082
5638
  }
5083
- } catch (err) {
5639
+ } catch (error2) {
5084
5640
  if (this.sock === sock && this.generation === generation) {
5085
- this.fail(err instanceof Error ? err : new SubcError(String(err)));
5641
+ this.fail(error2 instanceof Error ? error2 : new SubcError(String(error2)));
5642
+ }
5643
+ }
5644
+ }
5645
+ dispatch(frame) {
5646
+ let handle = null;
5647
+ if (frame.header.channel !== 0) {
5648
+ handle = this.liveRoutes.get(frame.header.channel) ?? null;
5649
+ if (!handle || handle.epoch !== frame.header.epoch) {
5650
+ this.ingressEpochDropCount += 1;
5651
+ return;
5086
5652
  }
5087
5653
  }
5088
- }
5089
- dispatch(frame) {
5090
- const key = `${frame.header.channel}:${frame.header.corr}`;
5654
+ const key = pendingKey(handle, frame.header.corr);
5091
5655
  const pending = this.pending.get(key);
5092
5656
  if (pending) {
5657
+ if (pending.acceptFrame && !pending.acceptFrame(frame))
5658
+ return;
5093
5659
  switch (frame.header.ty) {
5094
5660
  case FrameType.Push:
5095
5661
  case FrameType.StreamData:
@@ -5106,15 +5672,22 @@ class SubcClient {
5106
5672
  return;
5107
5673
  }
5108
5674
  }
5109
- if (frame.header.ty === FrameType.Goodbye) {
5110
- this.failChannel(frame.header.channel, new SubcError("route closed by subc (GOODBYE)"));
5111
- this.evictRouteChannel(frame.header.channel);
5675
+ const late = this.lateResponses.get(key);
5676
+ if (late && (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error)) {
5677
+ this.lateResponses.delete(key);
5678
+ late(frame);
5112
5679
  return;
5113
5680
  }
5114
- if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error || frame.header.ty === FrameType.StreamEnd) {
5115
- debug("dropped terminal frame with no waiter: type=%d channel=%d corr=%s port=%s", frame.header.ty, frame.header.channel, frame.header.corr, this.sock.localPort() ?? "?");
5681
+ if (frame.header.ty === FrameType.Goodbye && handle) {
5682
+ this.failHandle(handle, new SubcError("route closed by subc (GOODBYE)"));
5683
+ if (this.liveRoutes.get(handle.channel) === handle)
5684
+ this.liveRoutes.delete(handle.channel);
5685
+ this.evictRouteHandle(handle);
5116
5686
  return;
5117
5687
  }
5688
+ if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error || frame.header.ty === FrameType.StreamEnd) {
5689
+ debug("dropped terminal frame with no waiter: type=%d channel=%d epoch=%d corr=%s port=%s", frame.header.ty, frame.header.channel, frame.header.epoch, frame.header.corr, this.sock.localPort() ?? "?");
5690
+ }
5118
5691
  }
5119
5692
  settle(key, pending, run) {
5120
5693
  if (this.pending.get(key) !== pending)
@@ -5137,18 +5710,16 @@ class SubcClient {
5137
5710
  return new SubcError(Buffer.from(frame.body).toString("utf8") || "subc error");
5138
5711
  }
5139
5712
  }
5140
- evictRouteChannel(channel) {
5713
+ evictRouteHandle(handle) {
5141
5714
  for (const cached of this.routes.values()) {
5142
- if (cached.channel === channel && cached.generation === this.generation) {
5143
- cached.channel = null;
5144
- }
5715
+ if (cached.handle && sameRouteHandle(cached.handle, handle))
5716
+ cached.handle = null;
5145
5717
  }
5146
5718
  }
5147
- failChannel(channel, err) {
5719
+ failHandle(handle, error2) {
5148
5720
  for (const [key, pending] of this.pending) {
5149
- if (pending.channel === channel) {
5150
- this.rejectPending(key, pending, err);
5151
- }
5721
+ if (pending.handle && sameRouteHandle(pending.handle, handle))
5722
+ this.rejectPending(key, pending, error2);
5152
5723
  }
5153
5724
  }
5154
5725
  fail(err) {
@@ -5176,6 +5747,44 @@ class SubcClient {
5176
5747
  return this.notSentCallError(message, cause);
5177
5748
  return this.terminalCallError(message, cause);
5178
5749
  }
5750
+ get droppedIngressFrames() {
5751
+ return this.ingressEpochDropCount;
5752
+ }
5753
+ installRoute(channel, epoch) {
5754
+ const handle = createRouteHandle(channel, epoch, this.connectionToken);
5755
+ this.liveRoutes.set(channel, handle);
5756
+ return handle;
5757
+ }
5758
+ isLiveHandle(handle) {
5759
+ return belongsToConnection(handle, this.connectionToken) && this.liveRoutes.get(handle.channel) === handle;
5760
+ }
5761
+ assertLiveConnection(handle) {
5762
+ if (!belongsToConnection(handle, this.connectionToken))
5763
+ throw new StaleRouteHandleError(handle);
5764
+ }
5765
+ assertLiveHandle(handle) {
5766
+ if (!this.isLiveHandle(handle))
5767
+ throw new StaleRouteHandleError(handle);
5768
+ }
5769
+ allocateCorr() {
5770
+ const maximum = 0xffffffffffffffffn;
5771
+ if (this.nextCorr > maximum) {
5772
+ const error2 = new SubcError("channel-0 correlation id allocator exhausted", "corr_exhausted");
5773
+ this.fail(error2);
5774
+ this.sock.close();
5775
+ this.scheduleReconnectAfterDrop(error2);
5776
+ throw error2;
5777
+ }
5778
+ const corr = this.nextCorr;
5779
+ this.nextCorr += 1n;
5780
+ return corr;
5781
+ }
5782
+ closeConnectionAfterCleanupFailure() {
5783
+ const error2 = new SubcError("late route cleanup could not be queued", "late_route_cleanup_failed");
5784
+ this.fail(error2);
5785
+ this.sock.close();
5786
+ this.scheduleReconnectAfterDrop(error2);
5787
+ }
5179
5788
  encode(value) {
5180
5789
  return new Uint8Array(Buffer.from(JSON.stringify(value), "utf8"));
5181
5790
  }
@@ -5245,11 +5854,15 @@ function causeMessage(cause) {
5245
5854
  return "";
5246
5855
  return `: ${cause instanceof Error ? cause.message : String(cause)}`;
5247
5856
  }
5857
+ function pendingKey(handle, corr) {
5858
+ return handle ? `${handle.channel}:${handle.epoch}:${corr}` : `0:0:${corr}`;
5859
+ }
5248
5860
  var debug, DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4, DEFAULT_REQUEST_TIMEOUT_MS = 30000, TIMEOUT_ARBITRATION_GRACE_MS = 50, REQUEST_DEADLINE_MARKER = "request_deadline", DEADLINE_NO_DROP_CODE = "deadline_exceeded_no_drop_observed", ROUTE_OPEN_RETRY_DEADLINE_MS = 30000, BODY_READ_TIMEOUT_MS = 30000, EMPTY_BODY, DEFAULT_MANAGED_TARGET_KIND = "management_surface", SUBC_MODULE_ID_ENV = "SUBC_MODULE_ID", SUBC_LAUNCH_NONCE_ENV = "SUBC_LAUNCH_NONCE", DEFAULT_RECONNECT_BACKOFF, SubcCallError, SubcError;
5249
5861
  var init_client = __esm(() => {
5250
5862
  init_auth();
5251
5863
  init_connection_file();
5252
5864
  init_envelope();
5865
+ init_route_handle();
5253
5866
  init_socket();
5254
5867
  debug = debuglog("subc-client");
5255
5868
  EMPTY_BODY = new Uint8Array(0);
@@ -5279,7 +5892,7 @@ var init_client = __esm(() => {
5279
5892
  };
5280
5893
  });
5281
5894
 
5282
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/provider.js
5895
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/provider.js
5283
5896
  import { Buffer as Buffer2 } from "node:buffer";
5284
5897
 
5285
5898
  class AsyncPermitPool {
@@ -5328,6 +5941,11 @@ class SubcProvider {
5328
5941
  closeStarted = false;
5329
5942
  closedErr = null;
5330
5943
  inflight = new Map;
5944
+ pending = new Map;
5945
+ liveRoutes = new Map;
5946
+ connectionToken = newConnectionToken();
5947
+ nextCorr = 1n;
5948
+ ingressEpochDropCount = 0;
5331
5949
  requestGate = new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY);
5332
5950
  reconnecting = null;
5333
5951
  generation = 1;
@@ -5347,12 +5965,55 @@ class SubcProvider {
5347
5965
  this.readLoop(sock, this.generation);
5348
5966
  this.enqueueConnectionState({ state: "connected", epoch: this.connectionEpoch });
5349
5967
  }
5968
+ get droppedIngressFrames() {
5969
+ return this.ingressEpochDropCount;
5970
+ }
5350
5971
  get conn() {
5351
5972
  return this.currentConn;
5352
5973
  }
5353
5974
  currentEpoch() {
5354
5975
  return this.connectionEpoch;
5355
5976
  }
5977
+ async request(handle, body, opts = {}) {
5978
+ this.assertLiveHandle(handle);
5979
+ const corr = this.allocateCorr();
5980
+ const key = routeKey(handle, corr);
5981
+ const timeoutMs = opts.timeoutMs ?? WRITE_TIMEOUT_MS;
5982
+ const frame = buildFrame(FrameType.Request, buildFlags(false, opts.priority ?? Priority.Interactive, false, opts.admissionClass ?? AdmissionClass.Normal), handle.channel, handle.epoch, corr, body);
5983
+ return await new Promise((resolve7, reject) => {
5984
+ const timer = setTimeout(() => {
5985
+ if (this.pending.delete(key))
5986
+ reject(new SubcProviderError("reverse request timed out", "request_timeout"));
5987
+ }, timeoutMs);
5988
+ this.pending.set(key, {
5989
+ resolve: (response) => resolve7(response.body),
5990
+ reject,
5991
+ timer
5992
+ });
5993
+ this.sendOn(this.sock, this.generation, frame).catch((error2) => {
5994
+ const pending = this.pending.get(key);
5995
+ if (!pending)
5996
+ return;
5997
+ this.pending.delete(key);
5998
+ clearTimeout(pending.timer);
5999
+ reject(error2 instanceof Error ? error2 : new SubcProviderError(String(error2)));
6000
+ });
6001
+ });
6002
+ }
6003
+ async push(handle, body, opts = {}) {
6004
+ this.assertLiveHandle(handle);
6005
+ await this.sendOn(this.sock, this.generation, buildFrame(FrameType.Push, buildFlags(false, opts.priority ?? Priority.Interactive, false, opts.admissionClass ?? AdmissionClass.Normal), handle.channel, handle.epoch, 0n, body));
6006
+ }
6007
+ cancel(handle, corr) {
6008
+ this.assertLiveHandle(handle);
6009
+ this.sendOn(this.sock, this.generation, buildFrame(FrameType.Cancel, controlFlags(), handle.channel, handle.epoch, corr, new Uint8Array(0)));
6010
+ }
6011
+ closeRoute(handle) {
6012
+ this.assertLiveHandle(handle);
6013
+ this.liveRoutes.delete(handle.channel);
6014
+ this.abortHandle(handle);
6015
+ this.sendOn(this.sock, this.generation, buildFrame(FrameType.Goodbye, controlFlags(), handle.channel, handle.epoch, 0n, new Uint8Array(0)));
6016
+ }
5356
6017
  static async connect(opts) {
5357
6018
  if (opts.manifest.protocol_ver !== PROTOCOL_VERSION) {
5358
6019
  throw new SubcProviderError(`manifest protocol_ver ${opts.manifest.protocol_ver} does not match client protocol ${PROTOCOL_VERSION}`, "invalid_manifest");
@@ -5367,7 +6028,7 @@ class SubcProvider {
5367
6028
  this.cancelRestoredDebounce();
5368
6029
  const sock = this.sock;
5369
6030
  try {
5370
- await sendFrame(sock, buildFrame(FrameType.Goodbye, controlFlags(), 0, 0n, new Uint8Array(0)));
6031
+ await sendFrame(sock, buildFrame(FrameType.Goodbye, controlFlags(), 0, 0, 0n, new Uint8Array(0)));
5371
6032
  } catch {} finally {
5372
6033
  sock.close();
5373
6034
  this.finishClosed();
@@ -5375,12 +6036,13 @@ class SubcProvider {
5375
6036
  }
5376
6037
  await this.closed;
5377
6038
  }
5378
- static async openConnection(opts) {
6039
+ static async openConnection(opts, onSocket) {
5379
6040
  const conn = await readConnectionFile(opts.connectionFile);
5380
6041
  const deadline = Date.now() + (opts.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS2);
5381
6042
  const endpoint = conn.endpoints[0];
5382
6043
  const sock = await SubcSocket.connect(endpoint.host, endpoint.port, deadline);
5383
6044
  try {
6045
+ onSocket?.(sock);
5384
6046
  await authenticateClient(sock, conn, deadline);
5385
6047
  await sendFrame(sock, buildHelloFrame(opts));
5386
6048
  const ack = await expectHelloAck(sock, deadline);
@@ -5393,19 +6055,17 @@ class SubcProvider {
5393
6055
  async readLoop(sock, generation) {
5394
6056
  try {
5395
6057
  for (;; ) {
5396
- const headerBytes = await sock.readExact(HEADER_LEN, Number.POSITIVE_INFINITY);
5397
- const header = decodeHeader(headerBytes);
5398
- const body = header.len === 0 ? new Uint8Array(0) : await sock.readExact(header.len, Date.now() + BODY_READ_TIMEOUT_MS2);
5399
- const keepGoing = await this.dispatch({ header, body }, sock, generation);
6058
+ const frame = await sock.readFrame(Number.POSITIVE_INFINITY, { afterHeaderMs: BODY_READ_TIMEOUT_MS2 });
6059
+ const keepGoing = await this.dispatch(frame, sock, generation);
5400
6060
  if (!keepGoing) {
5401
6061
  if (this.sock === sock && this.generation === generation)
5402
6062
  this.closeStarted = true;
5403
6063
  break;
5404
6064
  }
5405
6065
  }
5406
- } catch (err) {
6066
+ } catch (error2) {
5407
6067
  if (this.sock === sock && this.generation === generation && !this.closeStarted) {
5408
- this.handleUnexpectedDrop(sock, generation, err instanceof Error ? err : new SubcProviderError(String(err)));
6068
+ this.handleUnexpectedDrop(sock, generation, error2 instanceof Error ? error2 : new SubcProviderError(String(error2)));
5409
6069
  return;
5410
6070
  }
5411
6071
  } finally {
@@ -5417,28 +6077,58 @@ class SubcProvider {
5417
6077
  }
5418
6078
  }
5419
6079
  async dispatch(frame, sock, generation) {
6080
+ let handle = null;
6081
+ if (frame.header.channel !== 0) {
6082
+ handle = this.liveRoutes.get(frame.header.channel) ?? null;
6083
+ if (!handle || handle.epoch !== frame.header.epoch) {
6084
+ this.ingressEpochDropCount += 1;
6085
+ return true;
6086
+ }
6087
+ }
6088
+ if (handle) {
6089
+ const pendingKey2 = routeKey(handle, frame.header.corr);
6090
+ const pending = this.pending.get(pendingKey2);
6091
+ if (pending) {
6092
+ if (frame.header.ty === FrameType.Push || frame.header.ty === FrameType.StreamData)
6093
+ return true;
6094
+ if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.StreamEnd) {
6095
+ this.pending.delete(pendingKey2);
6096
+ clearTimeout(pending.timer);
6097
+ pending.resolve(frame);
6098
+ return true;
6099
+ }
6100
+ if (frame.header.ty === FrameType.Error) {
6101
+ this.pending.delete(pendingKey2);
6102
+ clearTimeout(pending.timer);
6103
+ pending.reject(providerErrorFromFrame(frame));
6104
+ return true;
6105
+ }
6106
+ }
6107
+ }
5420
6108
  switch (frame.header.ty) {
5421
6109
  case FrameType.Ping:
5422
6110
  if (frame.header.channel === 0) {
5423
- await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Pong, frame.header.flags, 0, frame.header.corr, new Uint8Array(0)));
6111
+ await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Pong, frame.header.flags, 0, 0, frame.header.corr, new Uint8Array(0)));
5424
6112
  }
5425
6113
  return true;
5426
6114
  case FrameType.Goodbye:
5427
- if (frame.header.channel === 0)
6115
+ if (!handle)
5428
6116
  return false;
5429
- this.abortChannel(generation, frame.header.channel);
5430
- await this.opts.onRouteGone?.(frame.header.channel);
6117
+ this.liveRoutes.delete(handle.channel);
6118
+ this.abortHandle(handle);
6119
+ await this.opts.onRouteGone?.(handle);
5431
6120
  return true;
5432
6121
  case FrameType.Cancel:
5433
- this.inflight.get(routeKey(generation, frame.header.channel, frame.header.corr))?.abort();
6122
+ if (handle)
6123
+ this.inflight.get(routeKey(handle, frame.header.corr))?.abort();
5434
6124
  return true;
5435
6125
  case FrameType.Request:
5436
6126
  if (frame.header.channel === 0) {
5437
6127
  await this.handleControlRequest(frame, sock, generation);
5438
- } else {
5439
- this.handleDataRequest(frame, sock, generation).catch((err) => {
6128
+ } else if (handle) {
6129
+ this.handleDataRequest(frame, handle, sock, generation).catch((error2) => {
5440
6130
  if (!this.closeStarted && this.sock === sock && this.generation === generation) {
5441
- console.warn("SubcProvider handler failed after its request was dispatched", err);
6131
+ console.warn("SubcProvider handler failed after its request was dispatched", error2);
5442
6132
  }
5443
6133
  });
5444
6134
  }
@@ -5447,19 +6137,28 @@ class SubcProvider {
5447
6137
  return true;
5448
6138
  }
5449
6139
  }
5450
- abortChannel(generation, channel) {
5451
- const prefix = `${generation}:${channel}:`;
6140
+ abortHandle(handle) {
6141
+ const prefix = `${handle.channel}:${handle.epoch}:`;
5452
6142
  for (const [key, controller] of this.inflight) {
5453
6143
  if (key.startsWith(prefix))
5454
6144
  controller.abort();
5455
6145
  }
6146
+ for (const [key, pending] of this.pending) {
6147
+ if (!key.startsWith(prefix))
6148
+ continue;
6149
+ this.pending.delete(key);
6150
+ clearTimeout(pending.timer);
6151
+ pending.reject(new StaleRouteHandleError(handle));
6152
+ }
5456
6153
  }
5457
- abortGeneration(generation) {
5458
- const prefix = `${generation}:`;
5459
- for (const [key, controller] of this.inflight) {
5460
- if (key.startsWith(prefix))
5461
- controller.abort();
6154
+ abortGeneration(_generation) {
6155
+ this.abortAllInflight();
6156
+ for (const [key, pending] of this.pending) {
6157
+ this.pending.delete(key);
6158
+ clearTimeout(pending.timer);
6159
+ pending.reject(new SubcProviderError("provider connection dropped", "connection_dropped"));
5462
6160
  }
6161
+ this.liveRoutes.clear();
5463
6162
  }
5464
6163
  abortAllInflight() {
5465
6164
  for (const controller of this.inflight.values())
@@ -5468,9 +6167,9 @@ class SubcProvider {
5468
6167
  async handleControlRequest(frame, sock, generation) {
5469
6168
  const request = parseJson(frame.body);
5470
6169
  if (request.op === HEALTH_CHECK_OP) {
5471
- this.handleHealthRequest(frame, sock, generation).catch((err) => {
6170
+ this.handleHealthRequest(frame, sock, generation).catch((error2) => {
5472
6171
  if (!this.closeStarted && this.sock === sock && this.generation === generation) {
5473
- console.warn("SubcProvider health handler failed after its request was dispatched", err);
6172
+ console.warn("SubcProvider health handler failed after its request was dispatched", error2);
5474
6173
  }
5475
6174
  });
5476
6175
  return;
@@ -5478,47 +6177,93 @@ class SubcProvider {
5478
6177
  if (request.op !== "route.bind") {
5479
6178
  throw new SubcProviderError(`unsupported module control request ${request.op ?? "<missing op>"}`);
5480
6179
  }
6180
+ const boundChannel = numberField(request.route_channel, "route_channel");
6181
+ const boundEpoch = numberField(request.epoch, "epoch");
6182
+ const stale = this.liveRoutes.get(boundChannel);
6183
+ if (stale) {
6184
+ if (boundEpoch <= stale.epoch) {
6185
+ await this.sendError(frame, "route_rejected", `route.bind epoch ${boundEpoch} does not supersede installed epoch ${stale.epoch} on channel ${boundChannel}`, controlFlags(), sock, generation);
6186
+ return;
6187
+ }
6188
+ this.liveRoutes.delete(stale.channel);
6189
+ this.abortHandle(stale);
6190
+ await this.opts.onRouteGone?.(stale);
6191
+ }
6192
+ const tentative = createRouteHandle(boundChannel, boundEpoch, this.connectionToken);
5481
6193
  const bindRequest = {
5482
- route_channel: numberField(request.route_channel, "route_channel"),
6194
+ handle: tentative,
5483
6195
  target: request.target,
5484
6196
  identity: request.identity,
5485
- principal: request.principal
6197
+ principal: request.principal,
6198
+ consumer_capabilities: request.consumer_capabilities
5486
6199
  };
5487
- const decision = await this.opts.onBind?.(bindRequest);
6200
+ let decision;
6201
+ try {
6202
+ decision = await this.opts.onBind?.(bindRequest);
6203
+ } catch (error2) {
6204
+ try {
6205
+ await this.sendError(frame, "route_rejected", error2 instanceof Error ? error2.message : String(error2), controlFlags(), sock, generation);
6206
+ } finally {
6207
+ await this.opts.onRouteGone?.(tentative);
6208
+ }
6209
+ return;
6210
+ }
5488
6211
  const rejection = bindRejection(decision);
5489
6212
  if (rejection) {
5490
- await this.sendError(frame, rejection.code, rejection.message, controlFlags(), sock, generation);
6213
+ try {
6214
+ await this.sendError(frame, rejection.code, rejection.message, controlFlags(), sock, generation);
6215
+ } finally {
6216
+ await this.opts.onRouteGone?.(tentative);
6217
+ }
6218
+ return;
6219
+ }
6220
+ try {
6221
+ await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Response, controlFlags(), 0, 0, frame.header.corr, encodeJson({ op: "route.bind" })));
6222
+ } catch (error2) {
6223
+ await this.opts.onRouteGone?.(tentative);
6224
+ throw error2;
6225
+ }
6226
+ if (this.sock !== sock || this.generation !== generation || this.closeStarted || this.closedErr) {
6227
+ await this.opts.onRouteGone?.(tentative);
5491
6228
  return;
5492
6229
  }
5493
- await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Response, controlFlags(), 0, frame.header.corr, encodeJson({ op: "route.bind" })));
6230
+ this.liveRoutes.set(tentative.channel, tentative);
6231
+ await this.opts.onBound?.(tentative);
5494
6232
  }
5495
- async handleDataRequest(frame, sock, generation) {
5496
- const { channel, corr, ver } = frame.header;
5497
- const key = routeKey(generation, channel, corr);
6233
+ async handleDataRequest(frame, handle, sock, generation) {
6234
+ const { corr, ver } = frame.header;
6235
+ const key = routeKey(handle, corr);
5498
6236
  const controller = new AbortController;
5499
6237
  this.inflight.set(key, controller);
5500
- const dataFlags = buildFlags(false, Priority.Interactive, false);
5501
- const ctx = {
6238
+ const context = {
6239
+ handle,
5502
6240
  signal: controller.signal,
5503
6241
  currentEpoch: () => this.connectionEpoch,
5504
- emit: async (eventBody) => {
6242
+ emit: async (eventBody, options = {}) => {
6243
+ this.assertLiveHandle(handle);
5505
6244
  if (controller.signal.aborted)
5506
6245
  return;
5507
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamData, dataFlags, channel, corr, eventBody));
6246
+ await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamData, buildFlags(false, options.priority ?? Priority.Interactive, false, options.admissionClass ?? AdmissionClass.Normal), handle.channel, handle.epoch, corr, eventBody));
5508
6247
  }
5509
6248
  };
5510
6249
  const releasePermit = await (this.requestGate ?? new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY)).acquire();
6250
+ const dataFlags = buildFlags(false, Priority.Interactive, false);
5511
6251
  try {
5512
- const body = await this.opts.handler(channel, frame.body, ctx);
6252
+ const body = await this.opts.handler(handle, frame.body, context);
6253
+ if (controller.signal.aborted)
6254
+ return;
6255
+ this.assertLiveHandle(handle);
5513
6256
  if (body === undefined) {
5514
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamEnd, dataFlags, channel, corr, new Uint8Array(0)));
6257
+ await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamEnd, dataFlags, handle.channel, handle.epoch, corr, new Uint8Array(0)));
5515
6258
  } else if (body instanceof Uint8Array) {
5516
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, dataFlags, channel, corr, body));
6259
+ await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, dataFlags, handle.channel, handle.epoch, corr, body));
5517
6260
  } else {
5518
6261
  throw new SubcProviderError("provider handler must return a Uint8Array or void", "invalid_handler_response");
5519
6262
  }
5520
- } catch (err) {
5521
- await this.sendError(frame, err instanceof SubcProviderError && err.code ? err.code : "handler_error", err instanceof Error ? err.message : String(err), dataFlags, sock, generation);
6263
+ } catch (error2) {
6264
+ if (error2 instanceof StaleRouteHandleError || controller.signal.aborted)
6265
+ return;
6266
+ await this.sendError(frame, error2 instanceof SubcProviderError && error2.code ? error2.code : "handler_error", error2 instanceof Error ? error2.message : String(error2), dataFlags, sock, generation);
5522
6267
  } finally {
5523
6268
  releasePermit();
5524
6269
  if (this.inflight.get(key) === controller)
@@ -5526,8 +6271,8 @@ class SubcProvider {
5526
6271
  }
5527
6272
  }
5528
6273
  async handleHealthRequest(frame, sock, generation) {
5529
- const { channel, corr, ver } = frame.header;
5530
- const key = routeKey(generation, channel, corr);
6274
+ const { corr, ver } = frame.header;
6275
+ const key = `control:${generation}:${corr}`;
5531
6276
  const controller = new AbortController;
5532
6277
  this.inflight.set(key, controller);
5533
6278
  const releasePermit = await (this.requestGate ?? new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY)).acquire();
@@ -5535,14 +6280,14 @@ class SubcProvider {
5535
6280
  if (controller.signal.aborted)
5536
6281
  return;
5537
6282
  const report = await this.opts.health();
5538
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, controlFlags(), channel, corr, encodeJson({
6283
+ await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, controlFlags(), 0, 0, corr, encodeJson({
5539
6284
  op: HEALTH_CHECK_OP,
5540
6285
  status: report.status,
5541
6286
  ...report.detail === undefined ? {} : { detail: report.detail },
5542
6287
  ...report.metrics === undefined ? {} : { metrics: report.metrics }
5543
6288
  })));
5544
- } catch (err) {
5545
- await this.sendError(frame, err instanceof SubcProviderError && err.code ? err.code : "health_error", err instanceof Error ? err.message : String(err), controlFlags(), sock, generation);
6289
+ } catch (error2) {
6290
+ await this.sendError(frame, error2 instanceof SubcProviderError && error2.code ? error2.code : "health_error", error2 instanceof Error ? error2.message : String(error2), controlFlags(), sock, generation);
5546
6291
  } finally {
5547
6292
  releasePermit();
5548
6293
  if (this.inflight.get(key) === controller)
@@ -5550,7 +6295,7 @@ class SubcProvider {
5550
6295
  }
5551
6296
  }
5552
6297
  async sendError(frame, code, message, flags, sock, generation) {
5553
- await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Error, flags, frame.header.channel, frame.header.corr, encodeJson({ code, message })));
6298
+ await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Error, flags, frame.header.channel, frame.header.epoch, frame.header.corr, encodeJson({ code, message })));
5554
6299
  }
5555
6300
  async sendOn(sock, generation, frame) {
5556
6301
  if (this.sock !== sock || this.generation !== generation || this.closeStarted || this.closedErr)
@@ -5558,42 +6303,79 @@ class SubcProvider {
5558
6303
  await sendFrame(sock, frame);
5559
6304
  }
5560
6305
  handleUnexpectedDrop(sock, generation, cause) {
6306
+ if (this.closeStarted || this.sock !== sock || this.generation !== generation)
6307
+ return;
5561
6308
  this.cancelRestoredDebounce();
5562
6309
  this.abortGeneration(generation);
5563
6310
  this.generation += 1;
5564
6311
  sock.close();
5565
- this.enqueueConnectionState({ state: "down", cause });
5566
- this.scheduleReconnectAfterDrop(cause);
6312
+ this.scheduleReconnectAfterDrop(cause, this.generation, sock);
5567
6313
  }
5568
- scheduleReconnectAfterDrop(trigger) {
5569
- if (this.closeStarted || this.reconnecting)
6314
+ scheduleReconnectAfterDrop(cause, generation, droppedSocket) {
6315
+ if (this.closeStarted)
5570
6316
  return;
5571
- const promise = this.reconnectWithRetry(trigger).catch((err) => {
5572
- if (!this.closeStarted)
6317
+ const previous = this.reconnecting;
6318
+ if (previous) {
6319
+ if (!this.shouldSupersedeReconnect(previous, generation, droppedSocket))
6320
+ return;
6321
+ previous.superseded = true;
6322
+ previous.socket?.close();
6323
+ }
6324
+ const cycle = {
6325
+ generation,
6326
+ socket: null,
6327
+ socketDied: false,
6328
+ superseded: false
6329
+ };
6330
+ this.reconnecting = cycle;
6331
+ this.enqueueConnectionState({ state: "down", cause });
6332
+ this.reconnectWithRetry(cycle).catch((err) => {
6333
+ if (this.isCurrentReconnect(cycle) && !this.closeStarted) {
5573
6334
  this.failFatal(err instanceof Error ? err : new SubcProviderError(String(err)));
6335
+ }
5574
6336
  }).finally(() => {
5575
- if (this.reconnecting === promise)
6337
+ if (this.isCurrentReconnect(cycle))
5576
6338
  this.reconnecting = null;
5577
6339
  });
5578
- this.reconnecting = promise;
5579
6340
  }
5580
- async reconnectWithRetry(_trigger) {
6341
+ async reconnectWithRetry(cycle) {
5581
6342
  let attempt = 0;
5582
6343
  let delay = this.opts.reconnectBackoff.baseMs;
5583
6344
  for (;; ) {
6345
+ if (!this.isCurrentReconnect(cycle))
6346
+ return;
5584
6347
  if (this.closeStarted)
5585
6348
  throw new SubcProviderError("provider closed");
6349
+ cycle.socket = null;
6350
+ cycle.socketDied = false;
5586
6351
  attempt += 1;
5587
- this.enqueueConnectionState({ state: "reconnecting", attempt });
6352
+ this.enqueueReconnectState(cycle, attempt);
5588
6353
  try {
5589
- const opened = await SubcProvider.openConnection(this.opts);
5590
- if (this.closeStarted) {
6354
+ const opened = await SubcProvider.openConnection(this.opts, (sock) => {
6355
+ if (!this.isCurrentReconnect(cycle)) {
6356
+ sock.close();
6357
+ return;
6358
+ }
6359
+ cycle.socket = sock;
6360
+ });
6361
+ if (!this.isCurrentReconnect(cycle) || this.closeStarted) {
5591
6362
  opened.sock.close();
5592
- throw new SubcProviderError("provider closed");
6363
+ if (this.closeStarted)
6364
+ throw new SubcProviderError("provider closed");
6365
+ return;
5593
6366
  }
5594
- this.replaceConnection(opened);
6367
+ const epoch = this.replaceConnection(opened, cycle.generation);
6368
+ this.reconnecting = null;
6369
+ if (this.reconnecting !== null) {
6370
+ throw new SubcProviderError("reconnect state must clear before restored", "reconnect_state");
6371
+ }
6372
+ this.scheduleRestored(cycle.generation, epoch);
5595
6373
  return;
5596
6374
  } catch (err) {
6375
+ if (!this.isCurrentReconnect(cycle))
6376
+ return;
6377
+ if (cycle.socket)
6378
+ cycle.socketDied = true;
5597
6379
  if (this.closeStarted)
5598
6380
  throw err;
5599
6381
  if (!isProviderReconnectTransient(err))
@@ -5603,16 +6385,29 @@ class SubcProvider {
5603
6385
  }
5604
6386
  }
5605
6387
  }
5606
- replaceConnection(opened) {
6388
+ isCurrentReconnect(cycle) {
6389
+ return !cycle.superseded && this.reconnecting === cycle && this.generation === cycle.generation;
6390
+ }
6391
+ shouldSupersedeReconnect(cycle, generation, droppedSocket) {
6392
+ return cycle.generation < generation || cycle.socketDied || cycle.socket === droppedSocket;
6393
+ }
6394
+ enqueueReconnectState(cycle, attempt) {
6395
+ if (!this.isCurrentReconnect(cycle))
6396
+ return;
6397
+ this.enqueueConnectionState({ state: "reconnecting", attempt }, cycle.generation, cycle);
6398
+ }
6399
+ replaceConnection(opened, generation) {
5607
6400
  this.sock.close();
5608
6401
  this.sock = opened.sock;
5609
6402
  this.currentConn = opened.conn;
5610
6403
  this.storage = opened.ack.storage;
5611
6404
  this.closedErr = null;
5612
6405
  this.connectionEpoch += 1;
5613
- const generation = this.generation;
6406
+ this.connectionToken = newConnectionToken();
6407
+ this.liveRoutes.clear();
6408
+ this.nextCorr = 1n;
5614
6409
  this.readLoop(opened.sock, generation);
5615
- this.scheduleRestored(generation, this.connectionEpoch);
6410
+ return this.connectionEpoch;
5616
6411
  }
5617
6412
  scheduleRestored(generation, epoch) {
5618
6413
  if (!this.opts.onConnectionState)
@@ -5620,7 +6415,7 @@ class SubcProvider {
5620
6415
  const token = ++this.restoredDebounceToken;
5621
6416
  this.opts.sleep(this.opts.restoredDebounceMs).then(() => {
5622
6417
  if (token === this.restoredDebounceToken && !this.closeStarted && this.sock && this.generation === generation && this.connectionEpoch === epoch) {
5623
- this.enqueueConnectionState({ state: "restored", epoch });
6418
+ this.enqueueConnectionState({ state: "restored", epoch }, generation);
5624
6419
  }
5625
6420
  }).catch((err) => {
5626
6421
  if (token === this.restoredDebounceToken && !this.closeStarted) {
@@ -5631,10 +6426,10 @@ class SubcProvider {
5631
6426
  cancelRestoredDebounce() {
5632
6427
  this.restoredDebounceToken += 1;
5633
6428
  }
5634
- enqueueConnectionState(event) {
6429
+ enqueueConnectionState(event, generation, reconnect) {
5635
6430
  if (!this.opts.onConnectionState)
5636
6431
  return;
5637
- this.stateQueue.push(event);
6432
+ this.stateQueue.push({ event, generation, reconnect });
5638
6433
  if (!this.drainingStateQueue)
5639
6434
  this.drainConnectionStateQueue();
5640
6435
  }
@@ -5644,7 +6439,12 @@ class SubcProvider {
5644
6439
  this.drainingStateQueue = true;
5645
6440
  try {
5646
6441
  while (this.stateQueue.length > 0) {
5647
- const event = this.stateQueue[0];
6442
+ const queued = this.stateQueue[0];
6443
+ if (this.closeStarted || queued.generation !== undefined && queued.generation !== this.generation || queued.reconnect?.superseded) {
6444
+ this.stateQueue.shift();
6445
+ continue;
6446
+ }
6447
+ const { event } = queued;
5648
6448
  try {
5649
6449
  await this.opts.onConnectionState?.(event);
5650
6450
  this.stateQueue.shift();
@@ -5664,6 +6464,24 @@ class SubcProvider {
5664
6464
  this.drainConnectionStateQueue();
5665
6465
  }
5666
6466
  }
6467
+ isLiveHandle(handle) {
6468
+ return belongsToConnection(handle, this.connectionToken) && this.liveRoutes.get(handle.channel) === handle;
6469
+ }
6470
+ assertLiveHandle(handle) {
6471
+ if (!this.isLiveHandle(handle))
6472
+ throw new StaleRouteHandleError(handle);
6473
+ }
6474
+ allocateCorr() {
6475
+ const maximum = 0xffffffffffffffffn;
6476
+ if (this.nextCorr > maximum) {
6477
+ const error2 = new SubcProviderError("channel-0 correlation id allocator exhausted", "corr_exhausted");
6478
+ this.handleUnexpectedDrop(this.sock, this.generation, error2);
6479
+ throw error2;
6480
+ }
6481
+ const corr = this.nextCorr;
6482
+ this.nextCorr += 1n;
6483
+ return corr;
6484
+ }
5667
6485
  failFatal(err) {
5668
6486
  if (!this.closedErr)
5669
6487
  this.closedErr = err;
@@ -5677,8 +6495,16 @@ class SubcProvider {
5677
6495
  this.resolveClosed();
5678
6496
  }
5679
6497
  }
5680
- function routeKey(generation, channel, corr) {
5681
- return `${generation}:${channel}:${corr}`;
6498
+ function routeKey(handle, corr) {
6499
+ return `${handle.channel}:${handle.epoch}:${corr}`;
6500
+ }
6501
+ function providerErrorFromFrame(frame) {
6502
+ try {
6503
+ const body = parseJson(frame.body);
6504
+ return new SubcProviderError(body.message ?? "subc error", body.code);
6505
+ } catch {
6506
+ return new SubcProviderError(Buffer2.from(frame.body).toString("utf8") || "subc error");
6507
+ }
5682
6508
  }
5683
6509
  function launchNonce(opts) {
5684
6510
  const nonce = opts.launchNonce ?? process.env[SUBC_LAUNCH_NONCE_ENV2];
@@ -5693,6 +6519,7 @@ function normalizeProviderConnectOptions(opts) {
5693
6519
  handshakeTimeoutMs: opts.handshakeTimeoutMs,
5694
6520
  controlOps: opts.controlOps,
5695
6521
  onBind: opts.onBind,
6522
+ onBound: opts.onBound,
5696
6523
  onRouteGone: opts.onRouteGone,
5697
6524
  reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
5698
6525
  sleep: opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))),
@@ -5710,7 +6537,7 @@ function normalizedControlOps(controlOps) {
5710
6537
  }
5711
6538
  function buildHelloFrame(opts) {
5712
6539
  const nonce = launchNonce(opts);
5713
- return buildFrame(FrameType.Hello, controlFlags(), 0, HELLO_CORR, encodeJson({
6540
+ return buildFrame(FrameType.Hello, controlFlags(), 0, 0, HELLO_CORR, encodeJson({
5714
6541
  manifest: normalizeManifest(opts.manifest),
5715
6542
  protocol_ver: PROTOCOL_VERSION,
5716
6543
  control_ops: normalizedControlOps(opts.controlOps),
@@ -5749,14 +6576,17 @@ async function sendFrame(sock, frame) {
5749
6576
  await sock.write(encodeFrame(frame), Date.now() + WRITE_TIMEOUT_MS);
5750
6577
  }
5751
6578
  async function expectHelloAck(sock, deadline) {
5752
- const header = decodeHeader(await sock.readExact(HEADER_LEN, deadline));
5753
- const body = header.len === 0 ? new Uint8Array(0) : await sock.readExact(header.len, deadline);
5754
- const frame = { header, body };
5755
- switch (header.ty) {
5756
- case FrameType.HelloAck:
5757
- return parseJson(body);
6579
+ const frame = await sock.readFrame(deadline, deadline);
6580
+ switch (frame.header.ty) {
6581
+ case FrameType.HelloAck: {
6582
+ const ack = parseJson(frame.body);
6583
+ if (ack.negotiated_ver !== PROTOCOL_VERSION) {
6584
+ throw new SubcProviderError(`subc negotiated protocol ${ack.negotiated_ver}; expected exactly ${PROTOCOL_VERSION}`, "unsupported_version");
6585
+ }
6586
+ return ack;
6587
+ }
5758
6588
  case FrameType.Error: {
5759
- const error2 = parseJson(body);
6589
+ const error2 = parseJson(frame.body);
5760
6590
  throw new SubcProviderError(`subc rejected HELLO: ${error2.code ?? "unknown"} — ${error2.message ?? "subc error"}`, error2.code);
5761
6591
  }
5762
6592
  default:
@@ -5903,6 +6733,7 @@ var init_provider = __esm(() => {
5903
6733
  init_client();
5904
6734
  init_connection_file();
5905
6735
  init_envelope();
6736
+ init_route_handle();
5906
6737
  init_socket();
5907
6738
  SubcProviderError = class SubcProviderError extends Error {
5908
6739
  code;
@@ -5913,9 +6744,10 @@ var init_provider = __esm(() => {
5913
6744
  };
5914
6745
  });
5915
6746
 
5916
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/index.js
6747
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/index.js
5917
6748
  var init_dist = __esm(() => {
5918
6749
  init_client();
6750
+ init_route_handle();
5919
6751
  init_connection_file();
5920
6752
  init_envelope();
5921
6753
  init_auth();
@@ -5932,15 +6764,17 @@ class BgSubscription {
5932
6764
  identity;
5933
6765
  acquireClient;
5934
6766
  dropClient;
6767
+ consumerIdentity;
5935
6768
  onNudge;
5936
6769
  sleep;
5937
6770
  stopped = false;
5938
6771
  current = null;
5939
6772
  loop;
5940
- constructor(identity, acquireClient, dropClient, onNudge, sleep2) {
6773
+ constructor(identity, acquireClient, dropClient, consumerIdentity, onNudge, sleep2) {
5941
6774
  this.identity = identity;
5942
6775
  this.acquireClient = acquireClient;
5943
6776
  this.dropClient = dropClient;
6777
+ this.consumerIdentity = consumerIdentity;
5944
6778
  this.onNudge = onNudge;
5945
6779
  this.sleep = sleep2;
5946
6780
  this.loop = this.run();
@@ -5969,9 +6803,9 @@ class BgSubscription {
5969
6803
  }
5970
6804
  if (this.stopped)
5971
6805
  return;
5972
- let channel;
6806
+ let route;
5973
6807
  try {
5974
- channel = await client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, this.identity);
6808
+ route = await client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, this.identity, { consumerIdentity: this.consumerIdentity });
5975
6809
  } catch (err) {
5976
6810
  if (isConsumerReconnectTransient(err))
5977
6811
  this.dropClient(client);
@@ -5979,12 +6813,12 @@ class BgSubscription {
5979
6813
  continue;
5980
6814
  }
5981
6815
  if (this.stopped) {
5982
- safeCloseRoute(client, channel);
6816
+ safeCloseRoute(client, route);
5983
6817
  return;
5984
6818
  }
5985
6819
  const subscribedAt = Date.now();
5986
6820
  try {
5987
- const sub = client.subscribe(channel, { op: "bg_events" }, () => {
6821
+ const sub = client.subscribe(route, { op: "bg_events" }, () => {
5988
6822
  if (!this.stopped)
5989
6823
  this.onNudge();
5990
6824
  });
@@ -6004,7 +6838,7 @@ class BgSubscription {
6004
6838
  attempt = 0;
6005
6839
  } finally {
6006
6840
  this.current = null;
6007
- safeCloseRoute(client, channel);
6841
+ safeCloseRoute(client, route);
6008
6842
  }
6009
6843
  await this.backoff(attempt++);
6010
6844
  }
@@ -6017,12 +6851,12 @@ class BgSubscription {
6017
6851
  function isRecord(value) {
6018
6852
  return typeof value === "object" && value !== null && !Array.isArray(value);
6019
6853
  }
6020
- function isUnknownChannelError(err) {
6021
- return err instanceof SubcError && err.code === "unknown_channel";
6854
+ function isRouteProvenAbsentError(err) {
6855
+ return err instanceof SubcError && err.code === "unknown_channel" || err instanceof StaleRouteHandleError;
6022
6856
  }
6023
- function safeCloseRoute(client, channel) {
6857
+ function safeCloseRoute(client, route) {
6024
6858
  try {
6025
- client.closeRouteChannel(channel).catch(() => {
6859
+ client.closeRouteChannel(route).catch(() => {
6026
6860
  return;
6027
6861
  });
6028
6862
  } catch {}
@@ -6106,6 +6940,7 @@ class SubcTransportPool {
6106
6940
  harness;
6107
6941
  connectionFile;
6108
6942
  handshakeTimeoutMs;
6943
+ consumerIdentity;
6109
6944
  connectFn;
6110
6945
  onBgEventsNudge;
6111
6946
  bgBackoffSleep;
@@ -6119,6 +6954,7 @@ class SubcTransportPool {
6119
6954
  this.connectionFile = options.connectionFile;
6120
6955
  this.harness = options.harness;
6121
6956
  this.handshakeTimeoutMs = options.handshakeTimeoutMs;
6957
+ this.consumerIdentity = options.consumerIdentity;
6122
6958
  this.connectFn = options.connect ?? ((opts) => SubcClient.connect(opts));
6123
6959
  this.onBgEventsNudge = options.onBgEventsNudge;
6124
6960
  this.bgBackoffSleep = options.bgBackoffSleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
@@ -6141,6 +6977,11 @@ class SubcTransportPool {
6141
6977
  return null;
6142
6978
  return this.transports.get(key) ?? null;
6143
6979
  }
6980
+ activeBridges() {
6981
+ if (!this.client || this.shuttingDown)
6982
+ return [];
6983
+ return [...this.transports.values()];
6984
+ }
6144
6985
  async toolCall(projectRoot, runtime, name, rawArgs = {}, options) {
6145
6986
  return this.getBridge(projectRoot).toolCall(runtime.sessionID, name, rawArgs, options);
6146
6987
  }
@@ -6171,7 +7012,7 @@ class SubcTransportPool {
6171
7012
  throw new RouteTornDownError("subc session closed");
6172
7013
  }
6173
7014
  try {
6174
- const opened = await this.routeChannel(client, identity, record);
7015
+ const opened = await this.routeHandle(client, identity, record);
6175
7016
  if (!this.isCurrentSession(key, record)) {
6176
7017
  throw new RouteTornDownError("subc session closed");
6177
7018
  }
@@ -6197,29 +7038,29 @@ class SubcTransportPool {
6197
7038
  if (isConsumerReconnectTransient(err)) {
6198
7039
  this.transportFailures = 0;
6199
7040
  this.dropClient(client);
6200
- } else if (!isUnknownChannelError(err) && ++this.transportFailures >= MAX_CONSECUTIVE_TRANSPORT_FAILURES) {
7041
+ } else if (!isRouteProvenAbsentError(err) && ++this.transportFailures >= MAX_CONSECUTIVE_TRANSPORT_FAILURES) {
6201
7042
  this.transportFailures = 0;
6202
7043
  this.dropClient(client);
6203
7044
  }
6204
7045
  }
6205
7046
  };
6206
- const requestOnRoute = async (channel2) => {
6207
- const reply = await client.request(channel2, body, { timeoutMs, onProgress });
7047
+ const requestOnRoute = async (route2) => {
7048
+ const reply = await client.request(route2, body, { timeoutMs, onProgress });
6208
7049
  if (this.isCurrentSession(key, record) && this.client === client) {
6209
7050
  this.transportFailures = 0;
6210
7051
  }
6211
7052
  this.ensureBgSubscription(identity, record);
6212
7053
  return reply;
6213
7054
  };
6214
- let { channel, entry } = await openRoute();
7055
+ let { route, entry } = await openRoute();
6215
7056
  try {
6216
- return await requestOnRoute(channel);
7057
+ return await requestOnRoute(route);
6217
7058
  } catch (err) {
6218
- if (isUnknownChannelError(err) && this.isCurrentSession(key, record) && this.client === client) {
7059
+ if (isRouteProvenAbsentError(err) && this.isCurrentSession(key, record) && this.client === client) {
6219
7060
  clearRouteEntry(entry);
6220
- ({ channel, entry } = await openRoute());
7061
+ ({ route, entry } = await openRoute());
6221
7062
  try {
6222
- return await requestOnRoute(channel);
7063
+ return await requestOnRoute(route);
6223
7064
  } catch (retryErr) {
6224
7065
  handleRequestFailure(retryErr, entry);
6225
7066
  throw retryErr;
@@ -6261,24 +7102,26 @@ class SubcTransportPool {
6261
7102
  });
6262
7103
  return this.connecting;
6263
7104
  }
6264
- async routeChannel(client, identity, record) {
7105
+ async routeHandle(client, identity, record) {
6265
7106
  const key = identityKey(identity);
6266
7107
  const existing = record.routeEntry;
6267
- if (existing?.channel != null)
6268
- return { channel: existing.channel, entry: existing };
7108
+ if (existing?.handle != null)
7109
+ return { route: existing.handle, entry: existing };
6269
7110
  if (existing?.opening)
6270
- return { channel: await existing.opening, entry: existing };
6271
- const entry = { client, opening: null, channel: null, closed: false };
6272
- const opening = client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, identity).then((channel) => {
7111
+ return { route: await existing.opening, entry: existing };
7112
+ const entry = { client, opening: null, handle: null, closed: false };
7113
+ const opening = client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, identity, {
7114
+ consumerIdentity: this.consumerIdentity
7115
+ }).then((route) => {
6273
7116
  if (!this.isCurrentSession(key, record) || record.routeEntry !== entry || entry.closed || this.client !== client) {
6274
- safeCloseRoute(client, channel);
7117
+ safeCloseRoute(client, route);
6275
7118
  if (record.routeEntry === entry)
6276
7119
  record.routeEntry = null;
6277
7120
  throw new RouteTornDownError("subc route opened after teardown");
6278
7121
  }
6279
- entry.channel = channel;
7122
+ entry.handle = route;
6280
7123
  entry.opening = null;
6281
- return channel;
7124
+ return route;
6282
7125
  }).catch((err) => {
6283
7126
  const current = this.isCurrentSession(key, record);
6284
7127
  if (record.routeEntry === entry) {
@@ -6292,7 +7135,7 @@ class SubcTransportPool {
6292
7135
  });
6293
7136
  entry.opening = opening;
6294
7137
  record.routeEntry = entry;
6295
- return { channel: await opening, entry };
7138
+ return { route: await opening, entry };
6296
7139
  }
6297
7140
  ensureBgSubscription(identity, record) {
6298
7141
  if (this.shuttingDown || !this.onBgEventsNudge)
@@ -6303,7 +7146,7 @@ class SubcTransportPool {
6303
7146
  if (record.bgSub)
6304
7147
  return;
6305
7148
  const onNudge = () => this.onBgEventsNudge?.(identity.project_root, identity.session);
6306
- const sub = new BgSubscription(identity, () => this.ensureClient(), (client) => this.dropClient(client), onNudge, this.bgBackoffSleep);
7149
+ const sub = new BgSubscription(identity, () => this.ensureClient(), (client) => this.dropClient(client), this.consumerIdentity, onNudge, this.bgBackoffSleep);
6307
7150
  record.bgSub = sub;
6308
7151
  }
6309
7152
  dropClient(client) {
@@ -6324,9 +7167,13 @@ class SubcTransportPool {
6324
7167
  }
6325
7168
  }
6326
7169
  setConfigureOverride(_key, _value) {}
7170
+ async reconfigure(_projectRoot, _overrides) {}
6327
7171
  async replaceBinary(path2) {
6328
7172
  return path2;
6329
7173
  }
7174
+ isShutdown() {
7175
+ return this.shuttingDown;
7176
+ }
6330
7177
  async shutdown() {
6331
7178
  this.shuttingDown = true;
6332
7179
  const subs = [];
@@ -6350,10 +7197,10 @@ class SubcTransportPool {
6350
7197
  this.transports.clear();
6351
7198
  await Promise.allSettled(subs.map((sub) => sub.stop()));
6352
7199
  await Promise.allSettled(entries.map(async (entry) => {
6353
- if (entry.channel == null)
7200
+ if (entry.handle == null)
6354
7201
  return;
6355
7202
  try {
6356
- await entry.client.closeRouteChannel(entry.channel);
7203
+ await entry.client.closeRouteChannel(entry.handle);
6357
7204
  } catch {}
6358
7205
  }));
6359
7206
  if (client) {
@@ -6382,9 +7229,9 @@ class SubcTransportPool {
6382
7229
  entry.closed = true;
6383
7230
  if (sub)
6384
7231
  await sub.stop();
6385
- if (entry?.channel != null) {
7232
+ if (entry?.handle != null) {
6386
7233
  try {
6387
- await entry.client.closeRouteChannel(entry.channel);
7234
+ await entry.client.closeRouteChannel(entry.handle);
6388
7235
  } catch {}
6389
7236
  }
6390
7237
  }
@@ -6485,18 +7332,25 @@ function formatReadFooter(agentSpecifiedRange, data, options) {
6485
7332
  }
6486
7333
 
6487
7334
  // ../aft-bridge/dist/transport-factory.js
6488
- import { homedir as homedir10 } from "node:os";
6489
- import { isAbsolute as isAbsolute5, join as join9 } from "node:path";
7335
+ import { homedir as homedir11 } from "node:os";
7336
+ import { isAbsolute as isAbsolute5, join as join10 } from "node:path";
6490
7337
  function resolveConnectionFilePath(raw) {
6491
7338
  const trimmed = raw.trim();
6492
7339
  if (trimmed.startsWith("~")) {
6493
- return join9(homedir10(), trimmed.slice(1).replace(/^[/\\]/, ""));
7340
+ return join10(homedir11(), trimmed.slice(1).replace(/^[/\\]/, ""));
6494
7341
  }
6495
7342
  if (isAbsolute5(trimmed))
6496
7343
  return trimmed;
6497
- return join9(homedir10(), trimmed);
7344
+ return join10(homedir11(), trimmed);
6498
7345
  }
6499
7346
  async function createAftTransportPool(opts) {
7347
+ let binaryPath = opts.binaryPath;
7348
+ const createPool = () => createConcreteAftTransportPool({ ...opts, binaryPath });
7349
+ return new RevivableTransportPool(await createPool(), createPool, (path2) => {
7350
+ binaryPath = path2;
7351
+ });
7352
+ }
7353
+ async function createConcreteAftTransportPool(opts) {
6500
7354
  const raw = opts.subcConnectionFile?.trim();
6501
7355
  if (raw && raw.length > 0) {
6502
7356
  const connectionFile = resolveConnectionFilePath(raw);
@@ -6507,6 +7361,7 @@ async function createAftTransportPool(opts) {
6507
7361
  return new SubcTransportPool({
6508
7362
  connectionFile,
6509
7363
  harness: opts.harness,
7364
+ consumerIdentity: opts.subcConsumerIdentity,
6510
7365
  onBgEventsNudge: opts.onBgEventsNudge
6511
7366
  });
6512
7367
  }
@@ -6514,6 +7369,7 @@ async function createAftTransportPool(opts) {
6514
7369
  }
6515
7370
  var init_transport_factory = __esm(() => {
6516
7371
  init_pool();
7372
+ init_revivable_transport();
6517
7373
  init_subc_transport();
6518
7374
  });
6519
7375
 
@@ -6631,6 +7487,7 @@ __export(exports_dist, {
6631
7487
  timeoutForCommand: () => timeoutForCommand,
6632
7488
  tagStderrLine: () => tagStderrLine,
6633
7489
  stripJsoncSymbols: () => stripJsoncSymbols,
7490
+ stripHarnessSpecificConfigKeys: () => stripHarnessSpecificConfigKeys,
6634
7491
  statusBarLine: () => statusBarLine,
6635
7492
  sleep: () => sleep,
6636
7493
  shouldShowAnnouncement: () => shouldShowAnnouncement,
@@ -6645,6 +7502,8 @@ __export(exports_dist, {
6645
7502
  resolveCortexKitProjectConfigPath: () => resolveCortexKitProjectConfigPath,
6646
7503
  resolveCortexKitConfigPaths: () => resolveCortexKitConfigPaths,
6647
7504
  resolveBashKillTimeout: () => resolveBashKillTimeout,
7505
+ resolveAftStorageRoot: () => resolveAftStorageRoot,
7506
+ resolveAftLogPath: () => resolveAftLogPath,
6648
7507
  repairRootScopedStorageFile: () => repairRootScopedStorageFile,
6649
7508
  readConfigTiers: () => readConfigTiers,
6650
7509
  projectRootKeyHash: () => projectRootKeyHash,
@@ -6702,11 +7561,17 @@ __export(exports_dist, {
6702
7561
  __onnxTest__: () => __test__,
6703
7562
  SubcTransportPool: () => SubcTransportPool,
6704
7563
  STATUS_BAR_HEARTBEAT_CALLS: () => STATUS_BAR_HEARTBEAT_CALLS,
7564
+ RotatingLogSink: () => RotatingLogSink,
7565
+ RevivableTransportPool: () => RevivableTransportPool,
6705
7566
  PLATFORM_ASSET_MAP: () => PLATFORM_ASSET_MAP,
6706
7567
  PLATFORM_ARCH_MAP: () => PLATFORM_ARCH_MAP,
6707
7568
  PLAIN_CALLGRAPH_THEME: () => PLAIN_CALLGRAPH_THEME,
7569
+ PI_ONLY_KEYS: () => PI_ONLY_KEYS,
7570
+ OPENCODE_ONLY_KEYS: () => OPENCODE_ONLY_KEYS,
6708
7571
  LONG_RUNNING_COMMAND_TIMEOUT_MS: () => LONG_RUNNING_COMMAND_TIMEOUT_MS,
6709
7572
  HomeProjectRootError: () => HomeProjectRootError,
7573
+ DEFAULT_LOG_GENERATIONS: () => DEFAULT_LOG_GENERATIONS,
7574
+ DEFAULT_LOG_BYTES: () => DEFAULT_LOG_BYTES,
6710
7575
  BridgeTransportTimeoutError: () => BridgeTransportTimeoutError,
6711
7576
  BridgePool: () => BridgePool,
6712
7577
  BinaryBridge: () => BinaryBridge
@@ -6717,8 +7582,10 @@ var init_dist2 = __esm(() => {
6717
7582
  init_bridge();
6718
7583
  init_callgraph_format();
6719
7584
  init_command_timeouts();
7585
+ init_config_keys();
6720
7586
  init_config_tiers();
6721
7587
  init_downloader();
7588
+ init_durable_log();
6722
7589
  init_migration();
6723
7590
  init_npm_resolver();
6724
7591
  init_onnx_runtime();
@@ -6727,70 +7594,70 @@ var init_dist2 = __esm(() => {
6727
7594
  init_pool();
6728
7595
  init_project_identity();
6729
7596
  init_resolver();
7597
+ init_revivable_transport();
6730
7598
  init_subc_transport();
6731
7599
  init_transport_factory();
6732
7600
  });
6733
7601
 
6734
7602
  // src/lib/paths.ts
6735
- import { homedir as homedir11, tmpdir as tmpdir2 } from "node:os";
6736
- import { join as join10 } from "node:path";
7603
+ import { homedir as homedir12 } from "node:os";
7604
+ import { join as join11 } from "node:path";
6737
7605
  function getAftBinaryCacheDir() {
6738
7606
  if (process.env.AFT_CACHE_DIR) {
6739
- return join10(process.env.AFT_CACHE_DIR, "bin");
7607
+ return join11(process.env.AFT_CACHE_DIR, "bin");
6740
7608
  }
6741
7609
  if (process.platform === "win32") {
6742
7610
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
6743
- const base2 = localAppData || join10(homedir11(), "AppData", "Local");
6744
- return join10(base2, "aft", "bin");
7611
+ const base2 = localAppData || join11(homedir12(), "AppData", "Local");
7612
+ return join11(base2, "aft", "bin");
6745
7613
  }
6746
- const base = process.env.XDG_CACHE_HOME || join10(homedir11(), ".cache");
6747
- return join10(base, "aft", "bin");
7614
+ const base = process.env.XDG_CACHE_HOME || join11(homedir12(), ".cache");
7615
+ return join11(base, "aft", "bin");
6748
7616
  }
6749
7617
  function getAftBinaryName() {
6750
7618
  return process.platform === "win32" ? "aft.exe" : "aft";
6751
7619
  }
6752
7620
  function getAftLspPackagesDir() {
6753
7621
  if (process.env.AFT_CACHE_DIR) {
6754
- return join10(process.env.AFT_CACHE_DIR, "lsp-packages");
7622
+ return join11(process.env.AFT_CACHE_DIR, "lsp-packages");
6755
7623
  }
6756
7624
  if (process.platform === "win32") {
6757
7625
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
6758
- const base2 = localAppData || join10(homedir11(), "AppData", "Local");
6759
- return join10(base2, "aft", "lsp-packages");
7626
+ const base2 = localAppData || join11(homedir12(), "AppData", "Local");
7627
+ return join11(base2, "aft", "lsp-packages");
6760
7628
  }
6761
- const base = process.env.XDG_CACHE_HOME || join10(homedir11(), ".cache");
6762
- return join10(base, "aft", "lsp-packages");
7629
+ const base = process.env.XDG_CACHE_HOME || join11(homedir12(), ".cache");
7630
+ return join11(base, "aft", "lsp-packages");
6763
7631
  }
6764
7632
  function getAftLspBinariesDir() {
6765
7633
  if (process.env.AFT_CACHE_DIR) {
6766
- return join10(process.env.AFT_CACHE_DIR, "lsp-binaries");
7634
+ return join11(process.env.AFT_CACHE_DIR, "lsp-binaries");
6767
7635
  }
6768
7636
  if (process.platform === "win32") {
6769
7637
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
6770
- const base2 = localAppData || join10(homedir11(), "AppData", "Local");
6771
- return join10(base2, "aft", "lsp-binaries");
7638
+ const base2 = localAppData || join11(homedir12(), "AppData", "Local");
7639
+ return join11(base2, "aft", "lsp-binaries");
6772
7640
  }
6773
- const base = process.env.XDG_CACHE_HOME || join10(homedir11(), ".cache");
6774
- return join10(base, "aft", "lsp-binaries");
7641
+ const base = process.env.XDG_CACHE_HOME || join11(homedir12(), ".cache");
7642
+ return join11(base, "aft", "lsp-binaries");
6775
7643
  }
6776
- function homeDir3() {
7644
+ function homeDir4() {
6777
7645
  if (process.platform === "win32")
6778
- return process.env.USERPROFILE || process.env.HOME || homedir11();
6779
- return process.env.HOME || homedir11();
7646
+ return process.env.USERPROFILE || process.env.HOME || homedir12();
7647
+ return process.env.HOME || homedir12();
6780
7648
  }
6781
- function dataHome2() {
7649
+ function dataHome3() {
6782
7650
  if (process.env.XDG_DATA_HOME)
6783
7651
  return process.env.XDG_DATA_HOME;
6784
7652
  if (process.platform === "win32") {
6785
- return process.env.LOCALAPPDATA || process.env.APPDATA || join10(homeDir3(), "AppData", "Local");
7653
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join11(homeDir4(), "AppData", "Local");
6786
7654
  }
6787
- return join10(homeDir3(), ".local", "share");
7655
+ return join11(homeDir4(), ".local", "share");
6788
7656
  }
6789
7657
  function getCortexKitStorageRoot() {
6790
- return join10(dataHome2(), "cortexkit", "aft");
6791
- }
6792
- function getTmpLogPath(filename) {
6793
- return join10(tmpdir2(), filename);
7658
+ if (process.env.AFT_CACHE_DIR)
7659
+ return join11(process.env.AFT_CACHE_DIR, "aft");
7660
+ return join11(dataHome3(), "cortexkit", "aft");
6794
7661
  }
6795
7662
  var init_paths2 = () => {};
6796
7663
 
@@ -6798,8 +7665,8 @@ var init_paths2 = () => {};
6798
7665
  import { execSync as execSync2, spawnSync as spawnSync3 } from "node:child_process";
6799
7666
  import { existsSync as existsSync7 } from "node:fs";
6800
7667
  import { createRequire as createRequire2 } from "node:module";
6801
- import { homedir as homedir12 } from "node:os";
6802
- import { join as join11 } from "node:path";
7668
+ import { homedir as homedir13 } from "node:os";
7669
+ import { join as join12 } from "node:path";
6803
7670
  async function loadPluginVersion() {
6804
7671
  try {
6805
7672
  const bridge = await Promise.resolve().then(() => (init_dist2(), exports_dist));
@@ -6921,7 +7788,7 @@ function aftBinaryCandidates(preferredVersion) {
6921
7788
  const candidates = [];
6922
7789
  if (preferredVersion) {
6923
7790
  const tag = preferredVersion.startsWith("v") ? preferredVersion : `v${preferredVersion}`;
6924
- pushCandidate(candidates, join11(getAftBinaryCacheDir(), tag, getAftBinaryName()));
7791
+ pushCandidate(candidates, join12(getAftBinaryCacheDir(), tag, getAftBinaryName()));
6925
7792
  }
6926
7793
  const key = platformKey2();
6927
7794
  if (key) {
@@ -6944,7 +7811,7 @@ function aftBinaryCandidates(preferredVersion) {
6944
7811
  }
6945
7812
  }
6946
7813
  } catch {}
6947
- pushCandidate(candidates, join11(homedir12(), ".cargo", "bin", getAftBinaryName()));
7814
+ pushCandidate(candidates, join12(homedir13(), ".cargo", "bin", getAftBinaryName()));
6948
7815
  return candidates;
6949
7816
  }
6950
7817
  function findAftBinary(preferredVersion) {
@@ -6960,21 +7827,21 @@ var init_binary_probe = __esm(async () => {
6960
7827
 
6961
7828
  // src/lib/fs-util.ts
6962
7829
  import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync5 } from "node:fs";
6963
- import { join as join12 } from "node:path";
7830
+ import { join as join13 } from "node:path";
6964
7831
  function dirSize(path2) {
6965
7832
  if (!existsSync8(path2)) {
6966
7833
  return 0;
6967
7834
  }
6968
- const stat = statSync5(path2);
6969
- if (stat.isFile()) {
6970
- return stat.size;
7835
+ const stat2 = statSync5(path2);
7836
+ if (stat2.isFile()) {
7837
+ return stat2.size;
6971
7838
  }
6972
- if (!stat.isDirectory()) {
7839
+ if (!stat2.isDirectory()) {
6973
7840
  return 0;
6974
7841
  }
6975
7842
  let total = 0;
6976
7843
  for (const entry of readdirSync3(path2)) {
6977
- total += dirSize(join12(path2, entry));
7844
+ total += dirSize(join13(path2, entry));
6978
7845
  }
6979
7846
  return total;
6980
7847
  }
@@ -14597,10 +15464,10 @@ var require_stringify = __commonJS((exports, module) => {
14597
15464
  replacer = null;
14598
15465
  indent = EMPTY;
14599
15466
  };
14600
- var join13 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
15467
+ var join14 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
14601
15468
  var join_content = (inside, value, gap) => {
14602
15469
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
14603
- return join13(comment, inside, gap);
15470
+ return join14(comment, inside, gap);
14604
15471
  };
14605
15472
  var stringify_string = (holder, key, value) => {
14606
15473
  const raw = get_raw_string_literal(holder, key);
@@ -14622,13 +15489,13 @@ var require_stringify = __commonJS((exports, module) => {
14622
15489
  if (i !== 0) {
14623
15490
  inside += COMMA;
14624
15491
  }
14625
- const before = join13(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
15492
+ const before = join14(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
14626
15493
  inside += before || LF + deeper_gap;
14627
15494
  inside += stringify(i, value, deeper_gap) || STR_NULL;
14628
15495
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
14629
15496
  after_comma = process_comments(value, AFTER(i), deeper_gap);
14630
15497
  }
14631
- inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
15498
+ inside += join14(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
14632
15499
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
14633
15500
  };
14634
15501
  var object_stringify = (value, gap) => {
@@ -14649,13 +15516,13 @@ var require_stringify = __commonJS((exports, module) => {
14649
15516
  inside += COMMA;
14650
15517
  }
14651
15518
  first = false;
14652
- const before = join13(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
15519
+ const before = join14(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
14653
15520
  inside += before || LF + deeper_gap;
14654
15521
  inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
14655
15522
  after_comma = process_comments(value, AFTER(key), deeper_gap);
14656
15523
  };
14657
15524
  keys.forEach(iteratee);
14658
- inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
15525
+ inside += join14(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
14659
15526
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
14660
15527
  };
14661
15528
  function stringify(key, holder, gap) {
@@ -14749,7 +15616,7 @@ var require_src2 = __commonJS((exports, module) => {
14749
15616
 
14750
15617
  // src/lib/jsonc.ts
14751
15618
  import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
14752
- import { dirname as dirname5 } from "node:path";
15619
+ import { dirname as dirname6 } from "node:path";
14753
15620
  function detectJsoncFile(configDir, baseName) {
14754
15621
  const jsoncPath = `${configDir}/${baseName}.jsonc`;
14755
15622
  const jsonPath = `${configDir}/${baseName}.json`;
@@ -14777,7 +15644,7 @@ function readJsoncFile(path2) {
14777
15644
  }
14778
15645
  }
14779
15646
  function writeJsoncFile(path2, value, format = "json") {
14780
- mkdirSync6(dirname5(path2), { recursive: true });
15647
+ mkdirSync6(dirname6(path2), { recursive: true });
14781
15648
  const serialized = format === "jsonc" ? import_comment_json.stringify(value, null, 2) : JSON.stringify(value, null, 2);
14782
15649
  writeFileSync4(path2, `${serialized}
14783
15650
  `);
@@ -14837,25 +15704,25 @@ var init_self_version = () => {};
14837
15704
  // src/adapters/opencode.ts
14838
15705
  import { execSync as execSync3 } from "node:child_process";
14839
15706
  import { existsSync as existsSync10, readFileSync as readFileSync8, rmSync as rmSync4, statSync as statSync6 } from "node:fs";
14840
- import { homedir as homedir13 } from "node:os";
14841
- import { dirname as dirname6, join as join13, parse, resolve as resolve7 } from "node:path";
15707
+ import { homedir as homedir14 } from "node:os";
15708
+ import { dirname as dirname7, join as join14, parse, resolve as resolve7 } from "node:path";
14842
15709
  import { fileURLToPath } from "node:url";
14843
15710
  function getOpenCodeConfigDir() {
14844
15711
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
14845
15712
  if (envDir)
14846
15713
  return resolve7(envDir);
14847
- const xdg = process.env.XDG_CONFIG_HOME || join13(homedir13(), ".config");
14848
- return join13(xdg, "opencode");
15714
+ const xdg = process.env.XDG_CONFIG_HOME || join14(homedir14(), ".config");
15715
+ return join14(xdg, "opencode");
14849
15716
  }
14850
15717
  function getOpenCodeCacheDir() {
14851
15718
  const xdg = process.env.XDG_CACHE_HOME;
14852
15719
  if (xdg)
14853
- return join13(xdg, "opencode");
15720
+ return join14(xdg, "opencode");
14854
15721
  if (process.platform === "win32") {
14855
- const localAppData = process.env.LOCALAPPDATA ?? join13(homedir13(), "AppData", "Local");
14856
- return join13(localAppData, "opencode");
15722
+ const localAppData = process.env.LOCALAPPDATA ?? join14(homedir14(), "AppData", "Local");
15723
+ return join14(localAppData, "opencode");
14857
15724
  }
14858
- return join13(homedir13(), ".cache", "opencode");
15725
+ return join14(homedir14(), ".cache", "opencode");
14859
15726
  }
14860
15727
  function hasOpenCodeCli() {
14861
15728
  try {
@@ -14868,12 +15735,12 @@ function hasOpenCodeCli() {
14868
15735
  function openCodeDesktopAppExists() {
14869
15736
  const candidates = [];
14870
15737
  if (process.platform === "darwin") {
14871
- candidates.push("/Applications/OpenCode.app", "/Applications/OpenCode Beta.app", join13(homedir13(), "Applications", "OpenCode.app"), join13(homedir13(), "Applications", "OpenCode Beta.app"));
15738
+ candidates.push("/Applications/OpenCode.app", "/Applications/OpenCode Beta.app", join14(homedir14(), "Applications", "OpenCode.app"), join14(homedir14(), "Applications", "OpenCode Beta.app"));
14872
15739
  } else if (process.platform === "win32") {
14873
- const localAppData = process.env.LOCALAPPDATA ?? join13(homedir13(), "AppData", "Local");
14874
- candidates.push(join13(localAppData, "Programs", "opencode"), join13(localAppData, "opencode"));
15740
+ const localAppData = process.env.LOCALAPPDATA ?? join14(homedir14(), "AppData", "Local");
15741
+ candidates.push(join14(localAppData, "Programs", "opencode"), join14(localAppData, "opencode"));
14875
15742
  } else {
14876
- candidates.push("/opt/OpenCode", "/usr/lib/opencode", join13(homedir13(), ".local", "share", "applications", "opencode.desktop"));
15743
+ candidates.push("/opt/OpenCode", "/usr/lib/opencode", join14(homedir14(), ".local", "share", "applications", "opencode.desktop"));
14877
15744
  }
14878
15745
  return candidates.some((p) => {
14879
15746
  try {
@@ -14902,15 +15769,15 @@ function pathPointsToOurPlugin(entry) {
14902
15769
  try {
14903
15770
  if (!existsSync10(fsPath))
14904
15771
  return false;
14905
- let searchDir = statSync6(fsPath).isDirectory() ? fsPath : dirname6(fsPath);
15772
+ let searchDir = statSync6(fsPath).isDirectory() ? fsPath : dirname7(fsPath);
14906
15773
  let pkgJsonPath = null;
14907
15774
  while (true) {
14908
- const candidate = join13(searchDir, "package.json");
15775
+ const candidate = join14(searchDir, "package.json");
14909
15776
  if (existsSync10(candidate)) {
14910
15777
  pkgJsonPath = candidate;
14911
15778
  break;
14912
15779
  }
14913
- const parent = dirname6(searchDir);
15780
+ const parent = dirname7(searchDir);
14914
15781
  if (parent === searchDir || searchDir === parse(searchDir).root)
14915
15782
  break;
14916
15783
  searchDir = parent;
@@ -15076,10 +15943,10 @@ class OpenCodeAdapter {
15076
15943
  };
15077
15944
  }
15078
15945
  getPluginCacheInfo() {
15079
- const path2 = join13(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY);
15946
+ const path2 = join14(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY);
15080
15947
  let cached;
15081
15948
  try {
15082
- const installedPkgPath = join13(path2, "node_modules", "@cortexkit", "aft-opencode", "package.json");
15949
+ const installedPkgPath = join14(path2, "node_modules", "@cortexkit", "aft-opencode", "package.json");
15083
15950
  if (existsSync10(installedPkgPath)) {
15084
15951
  const pkg = JSON.parse(readFileSync8(installedPkgPath, "utf-8"));
15085
15952
  cached = typeof pkg.version === "string" ? pkg.version : undefined;
@@ -15098,7 +15965,7 @@ class OpenCodeAdapter {
15098
15965
  return getCortexKitStorageRoot();
15099
15966
  }
15100
15967
  getLogFile() {
15101
- return getTmpLogPath("aft-plugin.log");
15968
+ return resolveAftLogPath("aft-plugin.log");
15102
15969
  }
15103
15970
  getInstallHint() {
15104
15971
  return "Install OpenCode: https://opencode.ai/docs/install";
@@ -15140,11 +16007,11 @@ class OpenCodeAdapter {
15140
16007
  describeStorageSubtrees() {
15141
16008
  const storage = this.getStorageDir();
15142
16009
  return {
15143
- index: dirSize(join13(storage, "index")),
15144
- semantic: dirSize(join13(storage, "semantic")),
15145
- backups: dirSize(join13(storage, "backups")),
15146
- url_cache: dirSize(join13(storage, "url_cache")),
15147
- onnxruntime: dirSize(join13(storage, "onnxruntime"))
16010
+ index: dirSize(join14(storage, "index")),
16011
+ semantic: dirSize(join14(storage, "semantic")),
16012
+ backups: dirSize(join14(storage, "backups")),
16013
+ url_cache: dirSize(join14(storage, "url_cache")),
16014
+ onnxruntime: dirSize(join14(storage, "onnxruntime"))
15148
16015
  };
15149
16016
  }
15150
16017
  }
@@ -15161,15 +16028,15 @@ var init_opencode = __esm(() => {
15161
16028
  // src/adapters/pi.ts
15162
16029
  import { execSync as execSync4, spawnSync as spawnSync4 } from "node:child_process";
15163
16030
  import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
15164
- import { homedir as homedir14 } from "node:os";
15165
- import { join as join14 } from "node:path";
16031
+ import { homedir as homedir15 } from "node:os";
16032
+ import { join as join15 } from "node:path";
15166
16033
  function getPiAgentDir() {
15167
16034
  const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
15168
- const home = envHome && envHome.length > 0 ? envHome : homedir14();
15169
- return join14(home, ".pi", "agent");
16035
+ const home = envHome && envHome.length > 0 ? envHome : homedir15();
16036
+ return join15(home, ".pi", "agent");
15170
16037
  }
15171
16038
  function readPiExtensionIndex() {
15172
- const settingsPath = join14(getPiAgentDir(), "settings.json");
16039
+ const settingsPath = join15(getPiAgentDir(), "settings.json");
15173
16040
  if (existsSync11(settingsPath)) {
15174
16041
  try {
15175
16042
  const raw = readFileSync9(settingsPath, "utf-8");
@@ -15183,10 +16050,10 @@ function readPiExtensionIndex() {
15183
16050
  } catch {}
15184
16051
  }
15185
16052
  const candidates = [
15186
- join14(getPiAgentDir(), "extensions.json"),
15187
- join14(getPiAgentDir(), "extensions.jsonc"),
15188
- join14(getPiAgentDir(), "config.json"),
15189
- join14(getPiAgentDir(), "config.jsonc")
16053
+ join15(getPiAgentDir(), "extensions.json"),
16054
+ join15(getPiAgentDir(), "extensions.jsonc"),
16055
+ join15(getPiAgentDir(), "config.json"),
16056
+ join15(getPiAgentDir(), "config.jsonc")
15190
16057
  ];
15191
16058
  for (const path2 of candidates) {
15192
16059
  if (!existsSync11(path2))
@@ -15222,14 +16089,14 @@ function piEntryMatchesAft(entry) {
15222
16089
  } else if (entry.startsWith("/")) {
15223
16090
  resolved = entry;
15224
16091
  } else if (entry.length > 0) {
15225
- resolved = join14(getPiAgentDir(), entry);
16092
+ resolved = join15(getPiAgentDir(), entry);
15226
16093
  }
15227
16094
  if (!resolved)
15228
16095
  return false;
15229
16096
  try {
15230
16097
  if (!existsSync11(resolved))
15231
16098
  return false;
15232
- const pkgPath = join14(resolved, "package.json");
16099
+ const pkgPath = join15(resolved, "package.json");
15233
16100
  if (!existsSync11(pkgPath))
15234
16101
  return false;
15235
16102
  const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
@@ -15281,7 +16148,7 @@ class PiAdapter {
15281
16148
  const aftConfigExists = existsSync11(aftConfigPath);
15282
16149
  return {
15283
16150
  configDir,
15284
- harnessConfig: index.path ?? join14(configDir, "extensions.json"),
16151
+ harnessConfig: index.path ?? join15(configDir, "extensions.json"),
15285
16152
  harnessConfigFormat: index.path ? "json" : "none",
15286
16153
  aftConfig: aftConfigPath,
15287
16154
  aftConfigFormat: aftConfigExists ? "jsonc" : "none"
@@ -15326,8 +16193,8 @@ class PiAdapter {
15326
16193
  }
15327
16194
  getPluginCacheInfo() {
15328
16195
  const candidates = [
15329
- join14(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
15330
- join14(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
16196
+ join15(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
16197
+ join15(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
15331
16198
  ];
15332
16199
  for (const candidate of candidates) {
15333
16200
  if (!existsSync11(candidate))
@@ -15344,7 +16211,7 @@ class PiAdapter {
15344
16211
  } catch {}
15345
16212
  }
15346
16213
  return {
15347
- path: join14(getPiAgentDir(), "extensions"),
16214
+ path: join15(getPiAgentDir(), "extensions"),
15348
16215
  exists: false
15349
16216
  };
15350
16217
  }
@@ -15352,7 +16219,7 @@ class PiAdapter {
15352
16219
  return getCortexKitStorageRoot();
15353
16220
  }
15354
16221
  getLogFile() {
15355
- return getTmpLogPath("aft-pi.log");
16222
+ return resolveAftLogPath("aft-plugin.log");
15356
16223
  }
15357
16224
  getInstallHint() {
15358
16225
  return "Install Pi: https://github.com/badlogic/pi-mono";
@@ -15366,11 +16233,11 @@ class PiAdapter {
15366
16233
  describeStorageSubtrees() {
15367
16234
  const storage = this.getStorageDir();
15368
16235
  return {
15369
- index: dirSize(join14(storage, "index")),
15370
- semantic: dirSize(join14(storage, "semantic")),
15371
- backups: dirSize(join14(storage, "backups")),
15372
- url_cache: dirSize(join14(storage, "url_cache")),
15373
- onnxruntime: dirSize(join14(storage, "onnxruntime"))
16236
+ index: dirSize(join15(storage, "index")),
16237
+ semantic: dirSize(join15(storage, "semantic")),
16238
+ backups: dirSize(join15(storage, "backups")),
16239
+ url_cache: dirSize(join15(storage, "url_cache")),
16240
+ onnxruntime: dirSize(join15(storage, "onnxruntime"))
15374
16241
  };
15375
16242
  }
15376
16243
  }
@@ -17394,28 +18261,30 @@ var init_aft_bridge = () => {};
17394
18261
  // src/commands/lsp.ts
17395
18262
  var exports_lsp = {};
17396
18263
  __export(exports_lsp, {
18264
+ typescriptPackageWarning: () => typescriptPackageWarning,
17397
18265
  runLspDoctor: () => runLspDoctor,
17398
18266
  renderLspInspection: () => renderLspInspection,
17399
18267
  printLspDoctorHelp: () => printLspDoctorHelp,
17400
18268
  findProjectRootForFile: () => findProjectRootForFile
17401
18269
  });
17402
18270
  import { existsSync as existsSync12, readdirSync as readdirSync4, statSync as statSync7 } from "node:fs";
17403
- import { dirname as dirname7, join as join15, resolve as resolve8 } from "node:path";
18271
+ import { createRequire as createRequire4 } from "node:module";
18272
+ import { dirname as dirname8, join as join16, resolve as resolve8 } from "node:path";
17404
18273
  function findProjectRootForFile(filePath, fallbackCwd = process.cwd()) {
17405
18274
  const resolvedFile = resolve8(fallbackCwd, filePath);
17406
- let dir = dirname7(resolvedFile);
18275
+ let dir = dirname8(resolvedFile);
17407
18276
  try {
17408
18277
  if (existsSync12(resolvedFile) && statSync7(resolvedFile).isDirectory()) {
17409
18278
  dir = resolvedFile;
17410
18279
  }
17411
18280
  } catch {
17412
- dir = dirname7(resolvedFile);
18281
+ dir = dirname8(resolvedFile);
17413
18282
  }
17414
18283
  while (true) {
17415
- if (PROJECT_ROOT_MARKERS.some((marker) => existsSync12(join15(dir, marker)))) {
18284
+ if (PROJECT_ROOT_MARKERS.some((marker) => existsSync12(join16(dir, marker)))) {
17416
18285
  return dir;
17417
18286
  }
17418
- const parent = dirname7(dir);
18287
+ const parent = dirname8(dir);
17419
18288
  if (parent === dir)
17420
18289
  return resolve8(fallbackCwd);
17421
18290
  dir = parent;
@@ -17471,7 +18340,12 @@ async function runLspDoctor(options) {
17471
18340
  log2.error(inspect.message ?? inspect.code ?? "lsp_inspect failed");
17472
18341
  return 1;
17473
18342
  }
17474
- console.log(renderLspInspection(file, inspect));
18343
+ const inspection = inspect;
18344
+ const typescriptWarning = typescriptPackageWarning(inspection);
18345
+ console.log(renderLspInspection(file, {
18346
+ ...inspection,
18347
+ ...typescriptWarning ? { typescript_package_warning: typescriptWarning } : {}
18348
+ }));
17475
18349
  return 0;
17476
18350
  }
17477
18351
  function renderLspInspection(inputFile, response) {
@@ -17507,6 +18381,10 @@ function renderLspInspection(inputFile, response) {
17507
18381
  lines.push(` Action: ${installHint(server.binary_name)}`);
17508
18382
  }
17509
18383
  }
18384
+ if (response.typescript_package_warning) {
18385
+ lines.push("");
18386
+ lines.push(`Warning: ${response.typescript_package_warning}`);
18387
+ }
17510
18388
  const diagnostics = response.diagnostics ?? [];
17511
18389
  lines.push("");
17512
18390
  lines.push(`Diagnostics (${response.diagnostics_count ?? diagnostics.length} found):`);
@@ -17535,8 +18413,8 @@ function parseFileArg(argv) {
17535
18413
  function buildConfigureParams(adapter, projectRoot) {
17536
18414
  const userConfigPath = adapter.detectConfigPaths().aftConfig;
17537
18415
  const dir = adapter.kind === "pi" ? ".pi" : ".opencode";
17538
- const projectJsonc = join15(projectRoot, dir, "aft.jsonc");
17539
- const projectJson = join15(projectRoot, dir, "aft.json");
18416
+ const projectJsonc = join16(projectRoot, dir, "aft.jsonc");
18417
+ const projectJson = join16(projectRoot, dir, "aft.json");
17540
18418
  const projectConfigPath = existsSync12(projectJsonc) ? projectJsonc : projectJson;
17541
18419
  return {
17542
18420
  id: "doctor-lsp-configure",
@@ -17550,10 +18428,10 @@ function buildConfigureParams(adapter, projectRoot) {
17550
18428
  function inferLspPathsExtra(_lsp) {
17551
18429
  const paths = new Set;
17552
18430
  for (const entry of childDirs(getAftLspPackagesDir())) {
17553
- paths.add(join15(entry, "node_modules", ".bin"));
18431
+ paths.add(join16(entry, "node_modules", ".bin"));
17554
18432
  }
17555
18433
  for (const entry of childDirs(getAftLspBinariesDir())) {
17556
- paths.add(join15(entry, "bin"));
18434
+ paths.add(join16(entry, "bin"));
17557
18435
  }
17558
18436
  return [...paths];
17559
18437
  }
@@ -17561,7 +18439,7 @@ function childDirs(path2) {
17561
18439
  if (!existsSync12(path2))
17562
18440
  return [];
17563
18441
  try {
17564
- return readdirSync4(path2).map((entry) => join15(path2, entry)).filter((entry) => {
18442
+ return readdirSync4(path2).map((entry) => join16(path2, entry)).filter((entry) => {
17565
18443
  try {
17566
18444
  return statSync7(entry).isDirectory();
17567
18445
  } catch {
@@ -17596,6 +18474,18 @@ function formatSpawnStatus(server) {
17596
18474
  function formatList(values) {
17597
18475
  return values.length === 0 ? "(none)" : values.join(", ");
17598
18476
  }
18477
+ function typescriptPackageWarning(response) {
18478
+ const typescriptServerSpawned = response.matching_servers?.some((server) => server.id === "typescript" && server.spawn_status === "ok");
18479
+ const diagnosticsCount = response.diagnostics_count ?? response.diagnostics?.length ?? 0;
18480
+ if (!typescriptServerSpawned || !response.project_root || diagnosticsCount > 0)
18481
+ return null;
18482
+ try {
18483
+ createRequire4(join16(response.project_root, "package.json")).resolve("typescript");
18484
+ return null;
18485
+ } catch {
18486
+ return "typescript package not resolvable from project — server will produce no diagnostics";
18487
+ }
18488
+ }
17599
18489
  function installHint(binaryName) {
17600
18490
  if (binaryName === "ty")
17601
18491
  return "Install with `uv tool install ty` or `pip install ty`.";
@@ -17639,7 +18529,7 @@ __export(exports_doctor_filters, {
17639
18529
  printDoctorFiltersHelp: () => printDoctorFiltersHelp
17640
18530
  });
17641
18531
  import { existsSync as existsSync13 } from "node:fs";
17642
- import { homedir as homedir15 } from "node:os";
18532
+ import { homedir as homedir16 } from "node:os";
17643
18533
  import { relative as relative3, resolve as resolve9 } from "node:path";
17644
18534
  function printDoctorFiltersHelp() {
17645
18535
  console.log("Usage: aft doctor filters [--show <name>] [trust|untrust]");
@@ -17857,7 +18747,7 @@ function truncate(value) {
17857
18747
  return value.length <= 80 ? value : `${value.slice(0, 77)}…`;
17858
18748
  }
17859
18749
  function formatHome(path2) {
17860
- const home = homedir15();
18750
+ const home = homedir16();
17861
18751
  return path2.startsWith(home) ? `~${path2.slice(home.length)}` : path2;
17862
18752
  }
17863
18753
  function formatProjectPath(path2, projectRoot) {
@@ -17881,7 +18771,7 @@ var init_doctor_filters = __esm(async () => {
17881
18771
 
17882
18772
  // src/lib/binary-cache.ts
17883
18773
  import { existsSync as existsSync14, readdirSync as readdirSync5, statSync as statSync8 } from "node:fs";
17884
- import { join as join16 } from "node:path";
18774
+ import { join as join17 } from "node:path";
17885
18775
  function getBinaryCacheInfo(activeVersion) {
17886
18776
  const path2 = getAftBinaryCacheDir();
17887
18777
  if (!existsSync14(path2)) {
@@ -17894,7 +18784,7 @@ function getBinaryCacheInfo(activeVersion) {
17894
18784
  }
17895
18785
  const versions = readdirSync5(path2).filter((entry) => {
17896
18786
  try {
17897
- return statSync8(join16(path2, entry)).isDirectory();
18787
+ return statSync8(join17(path2, entry)).isDirectory();
17898
18788
  } catch {
17899
18789
  return false;
17900
18790
  }
@@ -17915,7 +18805,7 @@ var init_binary_cache = __esm(() => {
17915
18805
 
17916
18806
  // src/lib/sanitize.ts
17917
18807
  import { realpathSync as realpathSync3 } from "node:fs";
17918
- import { homedir as homedir16, userInfo } from "node:os";
18808
+ import { homedir as homedir17, userInfo } from "node:os";
17919
18809
  function escapeRegex(value) {
17920
18810
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17921
18811
  }
@@ -17946,7 +18836,7 @@ function redactSecrets(content) {
17946
18836
  }
17947
18837
  function sanitizeContent(content) {
17948
18838
  const username = userInfo().username;
17949
- const home = homedir16();
18839
+ const home = homedir17();
17950
18840
  let sanitized = redactSecrets(content);
17951
18841
  const cwd = process.cwd();
17952
18842
  for (const candidate of new Set([cwd, safeRealpath(cwd)])) {
@@ -17993,11 +18883,9 @@ var init_sanitize = __esm(() => {
17993
18883
 
17994
18884
  // src/lib/bridge-tool-failures.ts
17995
18885
  import { closeSync as closeSync5, existsSync as existsSync15, openSync as openSync5, readSync as readSync2, statSync as statSync9 } from "node:fs";
17996
- import { tmpdir as tmpdir3 } from "node:os";
17997
- import { join as join17 } from "node:path";
17998
18886
  function resolveBridgePluginLogPath() {
17999
18887
  const isTestEnv = process.env.BUN_TEST === "1" || false;
18000
- return join17(tmpdir3(), isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
18888
+ return resolveAftLogPath(isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
18001
18889
  }
18002
18890
  function tailLogFileBytes(path2, maxBytes) {
18003
18891
  if (!existsSync15(path2) || maxBytes <= 0)
@@ -18128,31 +19016,156 @@ function buildRecentAftToolFailuresSectionFromLog(logPath = resolveBridgePluginL
18128
19016
  }
18129
19017
  var BRIDGE_LOG_TAIL_BYTES, MAX_TOOL_FAILURE_CLASSES = 30, SESSION_TAG_PATTERN, STRUCTURED_CODE_PATTERN;
18130
19018
  var init_bridge_tool_failures = __esm(() => {
19019
+ init_dist2();
18131
19020
  init_sanitize();
18132
19021
  BRIDGE_LOG_TAIL_BYTES = 2 * 1024 * 1024;
18133
19022
  SESSION_TAG_PATTERN = /\[ses_[^\]\s]+\]|\[[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\]/g;
18134
19023
  STRUCTURED_CODE_PATTERN = /"code"\s*:\s*"([^"]+)"/;
18135
19024
  });
18136
19025
 
18137
- // src/lib/lsp-cache.ts
18138
- import { existsSync as existsSync16, readdirSync as readdirSync6, rmSync as rmSync5, statSync as statSync10 } from "node:fs";
19026
+ // src/lib/legacy-storage.ts
19027
+ import { existsSync as existsSync16, readdirSync as readdirSync6, statSync as statSync10 } from "node:fs";
18139
19028
  import { join as join18 } from "node:path";
19029
+ function summarizeLegacyPartitionDuplication(storageRoot) {
19030
+ if (!existsSync16(storageRoot)) {
19031
+ return { totalPartitions: 0, totalBytes: 0, byHarness: [] };
19032
+ }
19033
+ const byHarness = [];
19034
+ for (const harness of safeReadDir(storageRoot)) {
19035
+ const harnessPath = join18(storageRoot, harness);
19036
+ if (!isDirectory(harnessPath))
19037
+ continue;
19038
+ const partitions = new Map;
19039
+ collectCallgraphPartitions(join18(harnessPath, "callgraph"), partitions);
19040
+ collectInspectPartitions(join18(harnessPath, "inspect"), partitions);
19041
+ if (partitions.size === 0)
19042
+ continue;
19043
+ let bytes = 0;
19044
+ for (const size of partitions.values())
19045
+ bytes += size;
19046
+ byHarness.push({ harness, partitions: partitions.size, bytes });
19047
+ }
19048
+ byHarness.sort((left, right) => left.harness.localeCompare(right.harness));
19049
+ return {
19050
+ totalPartitions: byHarness.reduce((sum, item) => sum + item.partitions, 0),
19051
+ totalBytes: byHarness.reduce((sum, item) => sum + item.bytes, 0),
19052
+ byHarness
19053
+ };
19054
+ }
19055
+ function collectCallgraphPartitions(domainPath, partitions) {
19056
+ if (!isDirectory(domainPath))
19057
+ return;
19058
+ for (const name of safeReadDir(domainPath)) {
19059
+ const path2 = join18(domainPath, name);
19060
+ if (isDirectory(path2)) {
19061
+ if (!looksLikePartitionKey(name))
19062
+ continue;
19063
+ addPartitionBytes(partitions, `callgraph:${name}`, dirSize(path2));
19064
+ continue;
19065
+ }
19066
+ const key = callgraphPartitionKeyFromName(name);
19067
+ if (!key)
19068
+ continue;
19069
+ addPartitionBytes(partitions, `callgraph:${key}`, safeFileSize(path2));
19070
+ }
19071
+ }
19072
+ function collectInspectPartitions(domainPath, partitions) {
19073
+ if (!isDirectory(domainPath))
19074
+ return;
19075
+ for (const name of safeReadDir(domainPath)) {
19076
+ const path2 = join18(domainPath, name);
19077
+ if (isDirectory(path2)) {
19078
+ if (!looksLikePartitionKey(name))
19079
+ continue;
19080
+ addPartitionBytes(partitions, `inspect:${name}`, dirSize(path2));
19081
+ continue;
19082
+ }
19083
+ const key = inspectPartitionKeyFromName(name);
19084
+ if (!key)
19085
+ continue;
19086
+ addPartitionBytes(partitions, `inspect:${key}`, safeFileSize(path2));
19087
+ }
19088
+ }
19089
+ function addPartitionBytes(partitions, key, bytes) {
19090
+ partitions.set(key, (partitions.get(key) ?? 0) + bytes);
19091
+ }
19092
+ function callgraphPartitionKeyFromName(name) {
19093
+ if (name.includes(".tmp."))
19094
+ return null;
19095
+ if (name.endsWith(".current")) {
19096
+ const key2 = name.slice(0, -".current".length);
19097
+ return looksLikePartitionKey(key2) ? key2 : null;
19098
+ }
19099
+ const base = sqliteishBaseName(name);
19100
+ if (!base)
19101
+ return null;
19102
+ const split = base.indexOf(".g");
19103
+ const key = split === -1 ? base : base.slice(0, split);
19104
+ return looksLikePartitionKey(key) ? key : null;
19105
+ }
19106
+ function inspectPartitionKeyFromName(name) {
19107
+ if (name.includes(".tmp."))
19108
+ return null;
19109
+ const base = sqliteishBaseName(name);
19110
+ return base && looksLikePartitionKey(base) ? base : null;
19111
+ }
19112
+ function sqliteishBaseName(name) {
19113
+ for (const suffix of SQLITE_SUFFIXES) {
19114
+ if (name.endsWith(suffix)) {
19115
+ return name.slice(0, -suffix.length);
19116
+ }
19117
+ }
19118
+ return null;
19119
+ }
19120
+ function looksLikePartitionKey(value) {
19121
+ return /^[0-9a-fA-F]{16}$/.test(value);
19122
+ }
19123
+ function safeReadDir(path2) {
19124
+ try {
19125
+ return readdirSync6(path2).sort((left, right) => left.localeCompare(right));
19126
+ } catch {
19127
+ return [];
19128
+ }
19129
+ }
19130
+ function isDirectory(path2) {
19131
+ try {
19132
+ return statSync10(path2).isDirectory();
19133
+ } catch {
19134
+ return false;
19135
+ }
19136
+ }
19137
+ function safeFileSize(path2) {
19138
+ try {
19139
+ return statSync10(path2).isFile() ? statSync10(path2).size : 0;
19140
+ } catch {
19141
+ return 0;
19142
+ }
19143
+ }
19144
+ var SQLITE_SUFFIXES;
19145
+ var init_legacy_storage = __esm(() => {
19146
+ init_fs_util();
19147
+ SQLITE_SUFFIXES = [".sqlite-wal", ".sqlite-shm", ".sqlite-journal", ".sqlite"];
19148
+ });
19149
+
19150
+ // src/lib/lsp-cache.ts
19151
+ import { existsSync as existsSync17, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync11 } from "node:fs";
19152
+ import { join as join19 } from "node:path";
18140
19153
  function inspectDir(path2) {
18141
- if (!existsSync16(path2)) {
19154
+ if (!existsSync17(path2)) {
18142
19155
  return { entries: [], totalSize: 0 };
18143
19156
  }
18144
19157
  const entries = [];
18145
19158
  let totalSize = 0;
18146
19159
  let names;
18147
19160
  try {
18148
- names = readdirSync6(path2);
19161
+ names = readdirSync7(path2);
18149
19162
  } catch {
18150
19163
  return { entries: [], totalSize: 0 };
18151
19164
  }
18152
19165
  for (const name of names) {
18153
- const full = join18(path2, name);
19166
+ const full = join19(path2, name);
18154
19167
  try {
18155
- if (!statSync10(full).isDirectory())
19168
+ if (!statSync11(full).isDirectory())
18156
19169
  continue;
18157
19170
  const size = dirSize(full);
18158
19171
  entries.push({
@@ -18208,8 +19221,8 @@ var init_lsp_cache = __esm(() => {
18208
19221
  });
18209
19222
 
18210
19223
  // src/lib/onnx.ts
18211
- import { existsSync as existsSync17, readdirSync as readdirSync7, readlinkSync as readlinkSync2, realpathSync as realpathSync4 } from "node:fs";
18212
- import { basename as basename3, isAbsolute as isAbsolute6, join as join19, resolve as resolve10, win32 as win322 } from "node:path";
19224
+ import { existsSync as existsSync18, readdirSync as readdirSync8, readlinkSync as readlinkSync2, realpathSync as realpathSync4 } from "node:fs";
19225
+ import { basename as basename3, isAbsolute as isAbsolute6, join as join20, resolve as resolve10, win32 as win322 } from "node:path";
18213
19226
  function getOnnxLibraryName() {
18214
19227
  if (process.platform === "darwin")
18215
19228
  return "libonnxruntime.dylib";
@@ -18249,9 +19262,20 @@ function pathEntriesForPlatform2() {
18249
19262
  return isAbsolute6(entry) || win322.isAbsolute(entry);
18250
19263
  });
18251
19264
  }
19265
+ function isWindowsSystem32Directory2(dir) {
19266
+ if (process.platform !== "win32")
19267
+ return false;
19268
+ const normalizedDir = win322.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
19269
+ const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
19270
+ return windowsRoots.some((root) => {
19271
+ if (!root)
19272
+ return false;
19273
+ return normalizedDir === win322.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
19274
+ });
19275
+ }
18252
19276
  function directoryContainsLibrary2(dir, libName) {
18253
19277
  try {
18254
- const entries = readdirSync7(dir);
19278
+ const entries = readdirSync8(dir);
18255
19279
  if (process.platform === "win32") {
18256
19280
  const expected = libName.toLowerCase();
18257
19281
  return entries.some((entry) => entry.toLowerCase() === expected);
@@ -18261,6 +19285,24 @@ function directoryContainsLibrary2(dir, libName) {
18261
19285
  return false;
18262
19286
  }
18263
19287
  }
19288
+ function findIgnoredWindowsSystemOnnxRuntime() {
19289
+ if (process.platform !== "win32")
19290
+ return null;
19291
+ const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
19292
+ const seen = new Set;
19293
+ for (const root of windowsRoots) {
19294
+ if (!root)
19295
+ continue;
19296
+ const systemDir = join20(root, "System32");
19297
+ const key = win322.resolve(systemDir).toLowerCase();
19298
+ if (seen.has(key))
19299
+ continue;
19300
+ seen.add(key);
19301
+ if (directoryContainsLibrary2(systemDir, getOnnxLibraryName()))
19302
+ return systemDir;
19303
+ }
19304
+ return null;
19305
+ }
18264
19306
  function findSystemOnnxRuntime2() {
18265
19307
  const libName = getOnnxLibraryName();
18266
19308
  const searchPaths = [];
@@ -18272,21 +19314,21 @@ function findSystemOnnxRuntime2() {
18272
19314
  searchPaths.push(...pathEntriesForPlatform2());
18273
19315
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
18274
19316
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
18275
- searchPaths.push(join19(programFiles, "onnxruntime", "lib"), join19(programFiles, "Microsoft ONNX Runtime", "lib"), join19(programFiles, "Microsoft Machine Learning", "lib"), join19(programFilesX86, "onnxruntime", "lib"), ...(() => {
19317
+ searchPaths.push(join20(programFiles, "onnxruntime", "lib"), join20(programFiles, "Microsoft ONNX Runtime", "lib"), join20(programFiles, "Microsoft Machine Learning", "lib"), join20(programFilesX86, "onnxruntime", "lib"), ...(() => {
18276
19318
  const nugetPaths = [];
18277
19319
  const userProfile = process.env.USERPROFILE ?? "";
18278
19320
  if (!userProfile)
18279
19321
  return nugetPaths;
18280
- const nugetPackageDir = join19(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
18281
- if (!existsSync17(nugetPackageDir))
19322
+ const nugetPackageDir = join20(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
19323
+ if (!existsSync18(nugetPackageDir))
18282
19324
  return nugetPaths;
18283
19325
  try {
18284
- for (const entry of readdirSync7(nugetPackageDir, { withFileTypes: true })) {
19326
+ for (const entry of readdirSync8(nugetPackageDir, { withFileTypes: true })) {
18285
19327
  if (!entry.isDirectory())
18286
19328
  continue;
18287
19329
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
18288
19330
  continue;
18289
- nugetPaths.push(join19(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join19(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
19331
+ nugetPaths.push(join20(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join20(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
18290
19332
  }
18291
19333
  } catch {}
18292
19334
  return nugetPaths;
@@ -18306,6 +19348,8 @@ function findSystemOnnxRuntime2() {
18306
19348
  continue;
18307
19349
  const version = detectOrtVersion(dir);
18308
19350
  if (!version) {
19351
+ if (isWindowsSystem32Directory2(dir))
19352
+ continue;
18309
19353
  unknownVersionPaths.push(dir);
18310
19354
  continue;
18311
19355
  }
@@ -18316,12 +19360,12 @@ function findSystemOnnxRuntime2() {
18316
19360
  return unknownVersionPaths[0] ?? null;
18317
19361
  }
18318
19362
  function findCachedOnnxRuntime(storageDir) {
18319
- const ortDir = join19(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
19363
+ const ortDir = join20(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
18320
19364
  const libName = getOnnxLibraryName();
18321
- if (existsSync17(join19(ortDir, libName)))
19365
+ if (existsSync18(join20(ortDir, libName)))
18322
19366
  return ortDir;
18323
- const libSubdir = join19(ortDir, "lib");
18324
- if (existsSync17(join19(libSubdir, libName)))
19367
+ const libSubdir = join20(ortDir, "lib");
19368
+ if (existsSync18(join20(libSubdir, libName)))
18325
19369
  return libSubdir;
18326
19370
  return null;
18327
19371
  }
@@ -18342,11 +19386,11 @@ function parseOrtVersionFromDirectoryPath(value) {
18342
19386
  return null;
18343
19387
  }
18344
19388
  function detectOrtVersion(libDir) {
18345
- if (!existsSync17(libDir))
19389
+ if (!existsSync18(libDir))
18346
19390
  return null;
18347
19391
  const libName = getOnnxLibraryName();
18348
19392
  try {
18349
- const entries = readdirSync7(libDir);
19393
+ const entries = readdirSync8(libDir);
18350
19394
  const barePrefix = libName.replace(/\.(so|dylib|dll)$/, "");
18351
19395
  const expectedPrefix = process.platform === "win32" ? barePrefix.toLowerCase() : barePrefix;
18352
19396
  for (const entry of entries) {
@@ -18357,8 +19401,8 @@ function detectOrtVersion(libDir) {
18357
19401
  if (version)
18358
19402
  return version;
18359
19403
  }
18360
- const base = join19(libDir, libName);
18361
- if (existsSync17(base)) {
19404
+ const base = join20(libDir, libName);
19405
+ if (existsSync18(base)) {
18362
19406
  try {
18363
19407
  const real = realpathSync4(base);
18364
19408
  const version = parseOrtVersionFromPath(real) ?? parseOrtVersionFromDirectoryPath(real);
@@ -18393,10 +19437,10 @@ import {
18393
19437
  accessSync,
18394
19438
  closeSync as closeSync6,
18395
19439
  constants,
18396
- existsSync as existsSync18,
19440
+ existsSync as existsSync19,
18397
19441
  openSync as openSync6,
18398
19442
  readSync as readSync3,
18399
- statSync as statSync11
19443
+ statSync as statSync12
18400
19444
  } from "node:fs";
18401
19445
  async function collectDiagnostics(adapters) {
18402
19446
  const cliVersion = getSelfVersion();
@@ -18431,7 +19475,7 @@ async function diagnoseHarness(adapter) {
18431
19475
  const logPath = adapter.getLogFile();
18432
19476
  const pluginCache = adapter.getPluginCacheInfo();
18433
19477
  const storageAccessible = (() => {
18434
- if (!existsSync18(storage))
19478
+ if (!existsSync19(storage))
18435
19479
  return false;
18436
19480
  try {
18437
19481
  accessSync(storage, constants.R_OK | constants.W_OK);
@@ -18441,8 +19485,10 @@ async function diagnoseHarness(adapter) {
18441
19485
  }
18442
19486
  })();
18443
19487
  const describeStorage = "describeStorageSubtrees" in adapter && typeof adapter.describeStorageSubtrees === "function" ? adapter.describeStorageSubtrees() : {};
19488
+ const legacyDuplication = summarizeLegacyPartitionDuplication(storage);
18444
19489
  const semanticEnabled = aftEnabled && (aftConfigRead.value?.semantic_search === true || aftConfigRead.value?.experimental_semantic_search === true);
18445
19490
  const systemOrtDir = findSystemOnnxRuntime2();
19491
+ const ignoredSystemOrtDir = systemOrtDir ? null : findIgnoredWindowsSystemOnnxRuntime();
18446
19492
  const cachedOrtDir = findCachedOnnxRuntime(storage);
18447
19493
  const systemVersion = systemOrtDir ? detectOrtVersion(systemOrtDir) : null;
18448
19494
  const cachedVersion = cachedOrtDir ? detectOrtVersion(cachedOrtDir) : null;
@@ -18454,7 +19500,7 @@ async function diagnoseHarness(adapter) {
18454
19500
  pluginRegistered: adapter.hasPluginEntry(),
18455
19501
  configPaths,
18456
19502
  aftConfig: {
18457
- exists: existsSync18(configPaths.aftConfig),
19503
+ exists: existsSync19(configPaths.aftConfig),
18458
19504
  ...aftConfigRead.error ? { parseError: aftConfigRead.error } : {},
18459
19505
  enabled: aftEnabled,
18460
19506
  ...aftEnabledSource ? { enabledSource: aftEnabledSource } : {},
@@ -18463,15 +19509,18 @@ async function diagnoseHarness(adapter) {
18463
19509
  pluginCache,
18464
19510
  storageDir: {
18465
19511
  path: storage,
18466
- exists: existsSync18(storage),
19512
+ exists: existsSync19(storage),
18467
19513
  accessible: storageAccessible,
18468
- sizesByKey: describeStorage
19514
+ sizesByKey: describeStorage,
19515
+ ...legacyDuplication.totalPartitions > 0 ? { legacyDuplication } : {}
18469
19516
  },
18470
19517
  onnxRuntime: {
18471
19518
  required: semanticEnabled,
18472
19519
  systemPath: systemOrtDir,
18473
19520
  systemVersion,
18474
19521
  systemCompatible: systemVersion ? isOrtVersionCompatible(systemVersion) : null,
19522
+ ignoredSystemPath: ignoredSystemOrtDir,
19523
+ ignoredSystemReason: ignoredSystemOrtDir ? "version unreadable (Windows system copy) — ignored" : null,
18475
19524
  cachedPath: cachedOrtDir,
18476
19525
  cachedVersion,
18477
19526
  cachedCompatible: cachedVersion ? isOrtVersionCompatible(cachedVersion) : null,
@@ -18481,8 +19530,8 @@ async function diagnoseHarness(adapter) {
18481
19530
  },
18482
19531
  logFile: {
18483
19532
  path: logPath,
18484
- exists: existsSync18(logPath),
18485
- sizeKb: existsSync18(logPath) ? Math.round(statSync11(logPath).size / 1024) : 0
19533
+ exists: existsSync19(logPath),
19534
+ sizeKb: existsSync19(logPath) ? Math.round(statSync12(logPath).size / 1024) : 0
18486
19535
  }
18487
19536
  };
18488
19537
  }
@@ -18637,7 +19686,7 @@ function collectDiagnosticIssues(report) {
18637
19686
  code: "onnx_missing",
18638
19687
  severity: "medium",
18639
19688
  scope: h2.displayName,
18640
- message: "ONNX Runtime is required for semantic search but was not detected.",
19689
+ message: h2.onnxRuntime.ignoredSystemPath ? `ONNX Runtime at ${h2.onnxRuntime.ignoredSystemPath} has a ${h2.onnxRuntime.ignoredSystemReason}; no compatible runtime was detected.` : "ONNX Runtime is required for semantic search but was not detected.",
18641
19690
  remediation: `Run \`aft doctor --fix\` or install ONNX Runtime manually (${h2.onnxRuntime.installHint}).`
18642
19691
  });
18643
19692
  }
@@ -18678,14 +19727,14 @@ function formatDiagnosticIssuesSection(report) {
18678
19727
  return lines;
18679
19728
  }
18680
19729
  function tailLogFile(path2, lines) {
18681
- if (!existsSync18(path2))
19730
+ if (!existsSync19(path2))
18682
19731
  return "";
18683
19732
  if (lines <= 0)
18684
19733
  return "";
18685
19734
  const chunkSize = 64 * 1024;
18686
19735
  let fd = null;
18687
19736
  try {
18688
- const size = statSync11(path2).size;
19737
+ const size = statSync12(path2).size;
18689
19738
  fd = openSync6(path2, "r");
18690
19739
  const chunks = [];
18691
19740
  let position = size;
@@ -18718,6 +19767,7 @@ var init_diagnostics = __esm(async () => {
18718
19767
  init_dist2();
18719
19768
  init_binary_cache();
18720
19769
  init_jsonc();
19770
+ init_legacy_storage();
18721
19771
  init_lsp_cache();
18722
19772
  init_onnx();
18723
19773
  init_sanitize();
@@ -18865,34 +19915,42 @@ var init_issue_body = __esm(() => {
18865
19915
  });
18866
19916
 
18867
19917
  // src/lib/onnx-fix.ts
18868
- import { existsSync as existsSync19, rmSync as rmSync6 } from "node:fs";
18869
- import { join as join20 } from "node:path";
19918
+ import { existsSync as existsSync20, rmSync as rmSync6 } from "node:fs";
19919
+ import { join as join21 } from "node:path";
18870
19920
  function findOnnxFixCandidates(report) {
18871
19921
  const candidates = [];
18872
19922
  for (const harness of report.harnesses) {
18873
19923
  if (!harness.onnxRuntime.required)
18874
19924
  continue;
18875
- if (!harness.storageDir.exists)
18876
- continue;
18877
- const storageOnnxDir = join20(harness.storageDir.path, "onnxruntime");
19925
+ const storageOnnxDir = join21(harness.storageDir.path, "onnxruntime");
18878
19926
  const systemTooOld = harness.onnxRuntime.systemPath !== null && harness.onnxRuntime.systemCompatible === false;
18879
19927
  const cachedTooOld = harness.onnxRuntime.cachedPath !== null && harness.onnxRuntime.cachedCompatible === false;
18880
19928
  const hasCompatibleCached = harness.onnxRuntime.cachedCompatible === true;
18881
19929
  if (cachedTooOld) {
18882
19930
  candidates.push({
18883
19931
  harness,
18884
- reason: `cached ONNX Runtime at ${harness.onnxRuntime.cachedPath} is v${harness.onnxRuntime.cachedVersion}, but AFT requires ${harness.onnxRuntime.requirement}. Clearing forces a fresh download on next start.`,
19932
+ reason: `cached ONNX Runtime at ${harness.onnxRuntime.cachedPath} is v${harness.onnxRuntime.cachedVersion}, but AFT requires ${harness.onnxRuntime.requirement}. Clearing it allows an immediate managed download.`,
18885
19933
  storageOnnxDir,
18886
- storageOnnxBytes: existsSync19(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
19934
+ storageOnnxBytes: existsSync20(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
18887
19935
  });
18888
19936
  continue;
18889
19937
  }
18890
19938
  if (systemTooOld && !hasCompatibleCached) {
18891
19939
  candidates.push({
18892
19940
  harness,
18893
- reason: `system ONNX Runtime at ${harness.onnxRuntime.systemPath} is v${harness.onnxRuntime.systemVersion}, but AFT requires ${harness.onnxRuntime.requirement}, and no AFT-managed install is present. AFT v0.19.5+ skips incompatible system installs and auto-downloads v1.24 on next start; clearing any stale state here ensures a clean slate.`,
19941
+ reason: `system ONNX Runtime at ${harness.onnxRuntime.systemPath} is v${harness.onnxRuntime.systemVersion}, but AFT requires ${harness.onnxRuntime.requirement}, and no AFT-managed install is present. AFT will leave the system copy untouched and download v1.24 into managed storage.`,
19942
+ storageOnnxDir,
19943
+ storageOnnxBytes: existsSync20(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
19944
+ });
19945
+ continue;
19946
+ }
19947
+ if (!harness.onnxRuntime.systemPath && !harness.onnxRuntime.cachedPath) {
19948
+ const ignoredCopy = harness.onnxRuntime.ignoredSystemPath ? ` The Windows system copy at ${harness.onnxRuntime.ignoredSystemPath} was ignored because its version is unreadable.` : "";
19949
+ candidates.push({
19950
+ harness,
19951
+ reason: `no compatible ONNX Runtime is installed.${ignoredCopy} AFT will download v1.24 into managed storage.`,
18894
19952
  storageOnnxDir,
18895
- storageOnnxBytes: existsSync19(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
19953
+ storageOnnxBytes: existsSync20(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
18896
19954
  });
18897
19955
  }
18898
19956
  }
@@ -18900,58 +19958,74 @@ function findOnnxFixCandidates(report) {
18900
19958
  }
18901
19959
  async function runOnnxFix(adapters, report, options = {}) {
18902
19960
  const candidates = findOnnxFixCandidates(report);
18903
- if (candidates.length === 0) {
19961
+ if (candidates.length === 0)
18904
19962
  return null;
18905
- }
18906
- log2.warn(`Found ${candidates.length} ONNX Runtime issue(s) that --fix can address by clearing AFT-managed cache:`);
18907
- for (const c3 of candidates) {
18908
- log2.info(` • ${c3.harness.displayName}: ${c3.reason}`);
18909
- if (c3.storageOnnxBytes > 0) {
18910
- log2.info(` will delete: ${c3.storageOnnxDir} (${formatBytes(c3.storageOnnxBytes)})`);
19963
+ log2.warn(`Found ${candidates.length} ONNX Runtime issue(s) that --fix can repair with an AFT-managed runtime:`);
19964
+ for (const candidate of candidates) {
19965
+ log2.info(` ${candidate.harness.displayName}: ${candidate.reason}`);
19966
+ if (candidate.storageOnnxBytes > 0) {
19967
+ log2.info(` will delete: ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)})`);
18911
19968
  } else {
18912
- log2.info(` no AFT-managed ONNX cache to delete; nothing to reclaim`);
19969
+ log2.info(" no AFT-managed ONNX cache to delete");
18913
19970
  }
18914
19971
  }
18915
- note("This NEVER touches system paths like /usr/lib. It only deletes AFT's own ONNX download cache. " + "On next bridge start, AFT will re-download ONNX Runtime v1.24 and use that instead of the " + "incompatible system library.", "Safe operation");
19972
+ note("This NEVER touches system paths like /usr/lib or C:\\Windows\\System32. It only replaces AFT's own ONNX cache, then downloads the compatible managed runtime.", "Safe operation");
18916
19973
  const confirmFn = options.confirmFn ?? confirm2;
18917
19974
  const proceed = options.yes ? true : await confirmFn("Proceed with the fixes above?", true);
18918
19975
  if (!proceed) {
18919
19976
  log2.info("Skipped — no changes made.");
18920
19977
  return null;
18921
19978
  }
18922
- const result = { cleared: 0, bytesReclaimed: 0, errors: [] };
19979
+ const result = { cleared: 0, installed: 0, bytesReclaimed: 0, errors: [] };
18923
19980
  const rmFn = options.rmFn ?? rmSync6;
18924
- for (const c3 of candidates) {
18925
- if (!existsSync19(c3.storageOnnxDir)) {
18926
- log2.success(`${c3.harness.displayName}: no cached state to clear; restart your harness to trigger a fresh ONNX download`);
18927
- continue;
19981
+ const ensureFn = options.ensureFn ?? ensureOnnxRuntime;
19982
+ for (const candidate of candidates) {
19983
+ if (existsSync20(candidate.storageOnnxDir)) {
19984
+ try {
19985
+ rmFn(candidate.storageOnnxDir, { recursive: true, force: true });
19986
+ result.cleared += 1;
19987
+ result.bytesReclaimed += candidate.storageOnnxBytes;
19988
+ log2.success(`${candidate.harness.displayName}: cleared ${candidate.storageOnnxDir} (reclaimed ${formatBytes(candidate.storageOnnxBytes)})`);
19989
+ } catch (err) {
19990
+ const message = err instanceof Error ? err.message : String(err);
19991
+ log2.error(`${candidate.harness.displayName}: failed to clear ${candidate.storageOnnxDir}: ${message}`);
19992
+ result.errors.push({ path: candidate.storageOnnxDir, error: message });
19993
+ continue;
19994
+ }
18928
19995
  }
18929
19996
  try {
18930
- rmFn(c3.storageOnnxDir, { recursive: true, force: true });
18931
- result.cleared += 1;
18932
- result.bytesReclaimed += c3.storageOnnxBytes;
18933
- log2.success(`${c3.harness.displayName}: cleared ${c3.storageOnnxDir} (reclaimed ${formatBytes(c3.storageOnnxBytes)})`);
19997
+ log2.info(`${candidate.harness.displayName}: downloading managed ONNX Runtime…`);
19998
+ const installedPath = await ensureFn(candidate.harness.storageDir.path);
19999
+ if (!installedPath) {
20000
+ const message = "managed ONNX Runtime download was unavailable";
20001
+ log2.error(`${candidate.harness.displayName}: ${message}`);
20002
+ result.errors.push({ path: candidate.storageOnnxDir, error: message });
20003
+ continue;
20004
+ }
20005
+ result.installed += 1;
20006
+ log2.success(`${candidate.harness.displayName}: ONNX Runtime installed at ${installedPath}`);
18934
20007
  } catch (err) {
18935
- const message = err.message ?? "unknown error";
18936
- log2.error(`${c3.harness.displayName}: failed to clear ${c3.storageOnnxDir}: ${message}`);
18937
- result.errors.push({ path: c3.storageOnnxDir, error: message });
20008
+ const message = err instanceof Error ? err.message : String(err);
20009
+ log2.error(`${candidate.harness.displayName}: ONNX Runtime download failed: ${message}`);
20010
+ result.errors.push({ path: candidate.storageOnnxDir, error: message });
18938
20011
  }
18939
20012
  }
18940
- if (result.cleared > 0 || candidates.some((c3) => c3.storageOnnxBytes === 0)) {
18941
- note("Restart your AFT-using harness (OpenCode / Pi) to trigger a fresh ONNX Runtime download. " + "Watch the TUI sidebar the Semantic Index status should move from 'failed' → 'building' → 'ready'.", "Next step");
20013
+ if (result.installed > 0) {
20014
+ note("Restart your AFT-using harness (OpenCode / Pi) so semantic indexing uses the newly installed managed runtime.", "Next step");
18942
20015
  }
18943
20016
  return result;
18944
20017
  }
18945
20018
  var init_onnx_fix = __esm(() => {
20019
+ init_dist2();
18946
20020
  init_fs_util();
18947
20021
  init_prompts();
18948
20022
  });
18949
20023
 
18950
20024
  // src/lib/sessions.ts
18951
- import { existsSync as existsSync20, readdirSync as readdirSync8, readFileSync as readFileSync10, statSync as statSync12 } from "node:fs";
18952
- import { createRequire as createRequire4 } from "node:module";
18953
- import { homedir as homedir17 } from "node:os";
18954
- import { basename as basename4, join as join21 } from "node:path";
20025
+ import { existsSync as existsSync21, readdirSync as readdirSync9, readFileSync as readFileSync10, statSync as statSync13 } from "node:fs";
20026
+ import { createRequire as createRequire5 } from "node:module";
20027
+ import { homedir as homedir18 } from "node:os";
20028
+ import { basename as basename4, join as join22 } from "node:path";
18955
20029
  function listRecentSessions(adapter) {
18956
20030
  try {
18957
20031
  if (adapter.kind === "opencode")
@@ -18980,12 +20054,12 @@ function mapOpenCodeSessionRows(rows) {
18980
20054
  }).filter((session) => session !== null).sort((a3, b2) => b2.lastActivity - a3.lastActivity).slice(0, MAX_RECENT_SESSIONS);
18981
20055
  }
18982
20056
  function listRecentOpenCodeSessions() {
18983
- const dbPath = join21(getXdgDataHome(), "opencode", "opencode.db");
18984
- if (!existsSync20(dbPath))
20057
+ const dbPath = join22(getXdgDataHome(), "opencode", "opencode.db");
20058
+ if (!existsSync21(dbPath))
18985
20059
  return [];
18986
20060
  let db = null;
18987
20061
  try {
18988
- const require2 = createRequire4(import.meta.url);
20062
+ const require2 = createRequire5(import.meta.url);
18989
20063
  const sqlite = require2("node:sqlite");
18990
20064
  db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
18991
20065
  const rows = db.prepare("SELECT id, title, time_updated FROM session ORDER BY time_updated DESC LIMIT 5").all();
@@ -19000,22 +20074,22 @@ function listRecentOpenCodeSessions() {
19000
20074
  }
19001
20075
  function getXdgDataHome() {
19002
20076
  const xdgDataHome = process.env.XDG_DATA_HOME;
19003
- return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join21(homedir17(), ".local", "share");
20077
+ return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join22(homedir18(), ".local", "share");
19004
20078
  }
19005
20079
  function listRecentPiSessions() {
19006
- return listPiSessionsFromDir(join21(getHomeDir(), ".pi", "agent", "sessions"));
20080
+ return listPiSessionsFromDir(join22(getHomeDir(), ".pi", "agent", "sessions"));
19007
20081
  }
19008
20082
  function getHomeDir() {
19009
20083
  const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
19010
- return envHome && envHome.length > 0 ? envHome : homedir17();
20084
+ return envHome && envHome.length > 0 ? envHome : homedir18();
19011
20085
  }
19012
20086
  function listPiSessionsFromDir(sessionsDir) {
19013
20087
  try {
19014
- if (!existsSync20(sessionsDir))
20088
+ if (!existsSync21(sessionsDir))
19015
20089
  return [];
19016
20090
  const files = collectJsonlFiles(sessionsDir).map((filePath) => {
19017
20091
  try {
19018
- const stats = statSync12(filePath);
20092
+ const stats = statSync13(filePath);
19019
20093
  return { filePath, mtimeMs: stats.mtimeMs };
19020
20094
  } catch {
19021
20095
  return null;
@@ -19044,12 +20118,12 @@ function collectJsonlFiles(root) {
19044
20118
  continue;
19045
20119
  let entries;
19046
20120
  try {
19047
- entries = readdirSync8(dir, { withFileTypes: true });
20121
+ entries = readdirSync9(dir, { withFileTypes: true });
19048
20122
  } catch {
19049
20123
  continue;
19050
20124
  }
19051
20125
  for (const entry of entries) {
19052
- const path2 = join21(dir, entry.name);
20126
+ const path2 = join22(dir, entry.name);
19053
20127
  if (entry.isDirectory()) {
19054
20128
  stack.push(path2);
19055
20129
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -19149,17 +20223,17 @@ __export(exports_doctor, {
19149
20223
  import { execFileSync as execFileSync3 } from "node:child_process";
19150
20224
  import {
19151
20225
  chmodSync as chmodSync4,
19152
- existsSync as existsSync21,
20226
+ existsSync as existsSync22,
19153
20227
  mkdirSync as mkdirSync7,
19154
20228
  mkdtempSync,
19155
20229
  readFileSync as readFileSync11,
19156
20230
  realpathSync as realpathSync5,
19157
20231
  rmSync as rmSync7,
19158
- statSync as statSync13,
20232
+ statSync as statSync14,
19159
20233
  writeFileSync as writeFileSync5
19160
20234
  } from "node:fs";
19161
- import { tmpdir as tmpdir4 } from "node:os";
19162
- import { join as join22 } from "node:path";
20235
+ import { tmpdir as tmpdir2 } from "node:os";
20236
+ import { join as join23 } from "node:path";
19163
20237
  async function runDoctor(options) {
19164
20238
  if (options.issue) {
19165
20239
  return runIssueFlow(options.argv);
@@ -19228,6 +20302,8 @@ async function runDoctor(options) {
19228
20302
  }
19229
20303
  if (h2.onnxRuntime.systemPath) {
19230
20304
  parts.push(`system: ${h2.onnxRuntime.systemVersion ?? "unknown"}${h2.onnxRuntime.systemCompatible === false ? " (incompatible)" : ""}`);
20305
+ } else if (h2.onnxRuntime.ignoredSystemPath) {
20306
+ parts.push(`system: ${h2.onnxRuntime.ignoredSystemReason} at ${h2.onnxRuntime.ignoredSystemPath}`);
19231
20307
  }
19232
20308
  if (!h2.onnxRuntime.cachedPath && !h2.onnxRuntime.systemPath) {
19233
20309
  parts.push(`not installed — ${h2.onnxRuntime.installHint}`);
@@ -19324,7 +20400,7 @@ function clearOldBinaries() {
19324
20400
  errors: [],
19325
20401
  keptVersion: keepTag
19326
20402
  };
19327
- if (!existsSync21(info.path)) {
20403
+ if (!existsSync22(info.path)) {
19328
20404
  log2.info(`Binary cache: nothing to clear at ${info.path}`);
19329
20405
  return result;
19330
20406
  }
@@ -19334,10 +20410,10 @@ function clearOldBinaries() {
19334
20410
  return result;
19335
20411
  }
19336
20412
  for (const version of stale) {
19337
- const dir = join22(info.path, version);
20413
+ const dir = join23(info.path, version);
19338
20414
  let bytes = 0;
19339
20415
  try {
19340
- bytes = statSync13(dir).isDirectory() ? dirSize(dir) : 0;
20416
+ bytes = statSync14(dir).isDirectory() ? dirSize(dir) : 0;
19341
20417
  } catch {
19342
20418
  bytes = 0;
19343
20419
  }
@@ -19511,12 +20587,12 @@ function buildDoctorFixPlan(adapters, report) {
19511
20587
  if (candidate.storageOnnxBytes > 0) {
19512
20588
  items.push({
19513
20589
  kind: "onnx",
19514
- message: `Will delete AFT-managed ONNX cache at ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)})`
20590
+ message: `Will replace AFT-managed ONNX cache at ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)}) and download a compatible runtime`
19515
20591
  });
19516
20592
  } else {
19517
20593
  items.push({
19518
20594
  kind: "onnx",
19519
- message: `Will leave system ONNX untouched and refresh AFT-managed ONNX state for ${candidate.harness.displayName} on next start`
20595
+ message: `Will leave system ONNX untouched and download a compatible AFT-managed runtime for ${candidate.harness.displayName}`
19520
20596
  });
19521
20597
  }
19522
20598
  }
@@ -19648,7 +20724,8 @@ function logDoctorIssues(report) {
19648
20724
  }
19649
20725
  function formatDoctorStorageStatus(h2) {
19650
20726
  const state = h2.storageDir.exists ? h2.storageDir.path : `${h2.storageDir.path} (${h2.pluginRegistered ? "not yet created (lazy — created on first tool call)" : "not created"})`;
19651
- return `${state} (${formatStorageSizes(h2.storageDir.sizesByKey)})`;
20727
+ const legacyDuplication = formatLegacyDuplication(h2.storageDir.legacyDuplication);
20728
+ return `${state} (${[formatStorageSizes(h2.storageDir.sizesByKey), legacyDuplication].filter((part) => Boolean(part)).join("; ")})`;
19652
20729
  }
19653
20730
  async function confirmBinaryDownloadDespitePluginSkew(report, argv) {
19654
20731
  const skews = findPluginCliVersionSkews(report);
@@ -19678,7 +20755,7 @@ function ensureStorageDirsForRegisteredPlugins(adapters) {
19678
20755
  if (!adapter.isInstalled() || !adapter.hasPluginEntry())
19679
20756
  continue;
19680
20757
  const storageDir = adapter.getStorageDir();
19681
- if (existsSync21(storageDir))
20758
+ if (existsSync22(storageDir))
19682
20759
  continue;
19683
20760
  mkdirSync7(storageDir, { recursive: true });
19684
20761
  summary.created += 1;
@@ -19760,6 +20837,12 @@ function formatStorageSizes(sizes) {
19760
20837
  const parts = Object.entries(sizes).filter(([, size]) => size > 0).map(([key, size]) => `${key}: ${formatBytes(size)}`);
19761
20838
  return parts.length > 0 ? parts.join(", ") : "empty";
19762
20839
  }
20840
+ function formatLegacyDuplication(summary) {
20841
+ if (!summary || summary.totalPartitions === 0)
20842
+ return null;
20843
+ const byHarness = summary.byHarness.map((entry) => `${entry.harness}: ${entry.partitions} partition(s) / ${formatBytes(entry.bytes)}`).join("; ");
20844
+ return `legacy duplication: ${summary.totalPartitions} partition(s), ${formatBytes(summary.totalBytes)} total [${byHarness}]`;
20845
+ }
19763
20846
  function isInteractiveTerminal() {
19764
20847
  return process.stdin.isTTY === true && process.stdout.isTTY === true;
19765
20848
  }
@@ -19791,11 +20874,11 @@ function deriveIssueTitleFromBody(body) {
19791
20874
  function writeIssueReviewFile(body) {
19792
20875
  let reviewDir = null;
19793
20876
  try {
19794
- reviewDir = mkdtempSync(join22(tmpdir4(), "aft-issue-"));
20877
+ reviewDir = mkdtempSync(join23(tmpdir2(), "aft-issue-"));
19795
20878
  if (process.platform !== "win32") {
19796
20879
  chmodSync4(reviewDir, 448);
19797
20880
  }
19798
- const outPath = join22(reviewDir, "issue.md");
20881
+ const outPath = join23(reviewDir, "issue.md");
19799
20882
  writeFileSync5(outPath, `${body}
19800
20883
  `, { encoding: "utf8", mode: 384, flag: "wx" });
19801
20884
  return { path: outPath, realPath: realpathSync5(outPath) };