@cortexkit/aft 0.46.0 → 0.47.1

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,18 +2531,61 @@ 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
  }
2538
+ function decodeFileUrl(target) {
2539
+ if (!target.startsWith("file:"))
2540
+ return target;
2541
+ const rest = target.slice("file:".length);
2542
+ let pathPart;
2543
+ if (rest.startsWith("//")) {
2544
+ const after = rest.slice(2);
2545
+ const slash = after.indexOf("/");
2546
+ const authority = slash === -1 ? after : after.slice(0, slash);
2547
+ const p = slash === -1 ? "" : after.slice(slash);
2548
+ if (authority === "" || authority === "localhost")
2549
+ pathPart = p;
2550
+ else if (process.platform === "win32")
2551
+ pathPart = `//${authority}${p}`;
2552
+ else
2553
+ return target;
2554
+ } else if (rest.startsWith("/")) {
2555
+ pathPart = rest;
2556
+ } else {
2557
+ return target;
2558
+ }
2559
+ const bytes = [];
2560
+ for (let i = 0;i < pathPart.length; ) {
2561
+ if (pathPart[i] === "%" && i + 2 < pathPart.length) {
2562
+ const hex = pathPart.slice(i + 1, i + 3);
2563
+ if (/^[0-9a-fA-F]{2}$/.test(hex)) {
2564
+ bytes.push(Number.parseInt(hex, 16));
2565
+ i += 3;
2566
+ continue;
2567
+ }
2568
+ }
2569
+ const cp = pathPart.codePointAt(i);
2570
+ const ch = String.fromCodePoint(cp);
2571
+ for (const b of Buffer.from(ch, "utf8"))
2572
+ bytes.push(b);
2573
+ i += ch.length;
2574
+ }
2575
+ const decoded = Buffer.from(bytes).toString("utf8");
2576
+ if (process.platform === "win32" && /^\/[A-Za-z]:/.test(decoded)) {
2577
+ return decoded.slice(1);
2578
+ }
2579
+ return decoded;
2580
+ }
2409
2581
  var init_paths = () => {};
2410
2582
 
2411
2583
  // ../aft-bridge/dist/resolver.js
2412
2584
  import { execSync } from "node:child_process";
2413
2585
  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
2586
  import { createRequire } from "node:module";
2415
- import { homedir as homedir6 } from "node:os";
2416
- import { join as join5 } from "node:path";
2587
+ import { homedir as homedir7 } from "node:os";
2588
+ import { join as join6 } from "node:path";
2417
2589
  function copyToVersionedCache(npmBinaryPath, knownVersion) {
2418
2590
  try {
2419
2591
  const version = knownVersion ?? readBinaryVersion(npmBinaryPath);
@@ -2421,9 +2593,9 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
2421
2593
  return null;
2422
2594
  const tag = version.startsWith("v") ? version : `v${version}`;
2423
2595
  const cacheDir = getCacheDir();
2424
- const versionedDir = join5(cacheDir, tag);
2596
+ const versionedDir = join6(cacheDir, tag);
2425
2597
  const ext = process.platform === "win32" ? ".exe" : "";
2426
- const cachedPath = join5(versionedDir, `aft${ext}`);
2598
+ const cachedPath = join6(versionedDir, `aft${ext}`);
2427
2599
  if (existsSync4(cachedPath)) {
2428
2600
  const cachedVersion = readBinaryVersion(cachedPath);
2429
2601
  if (cachedVersion === version)
@@ -2453,18 +2625,18 @@ function normalizeBareVersion(version) {
2453
2625
  return version.startsWith("v") ? version.slice(1) : version;
2454
2626
  }
2455
2627
  function homeDirFromEnv(env) {
2456
- return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir6();
2628
+ return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir7();
2457
2629
  }
2458
2630
  function cacheDirFromEnv(env) {
2459
2631
  if (process.platform === "win32") {
2460
- const base2 = env.LOCALAPPDATA || env.APPDATA || join5(homeDirFromEnv(env), "AppData", "Local");
2461
- return join5(base2, "aft", "bin");
2632
+ const base2 = env.LOCALAPPDATA || env.APPDATA || join6(homeDirFromEnv(env), "AppData", "Local");
2633
+ return join6(base2, "aft", "bin");
2462
2634
  }
2463
- const base = env.XDG_CACHE_HOME || join5(homeDirFromEnv(env), ".cache");
2464
- return join5(base, "aft", "bin");
2635
+ const base = env.XDG_CACHE_HOME || join6(homeDirFromEnv(env), ".cache");
2636
+ return join6(base, "aft", "bin");
2465
2637
  }
2466
2638
  function cachedBinaryPathFromEnv(version, env, ext) {
2467
- const binaryPath = join5(cacheDirFromEnv(env), version, `aft${ext}`);
2639
+ const binaryPath = join6(cacheDirFromEnv(env), version, `aft${ext}`);
2468
2640
  return existsSync4(binaryPath) ? binaryPath : null;
2469
2641
  }
2470
2642
  function isExpectedCachedBinary2(binaryPath, expectedVersion) {
@@ -2583,7 +2755,7 @@ function findBinarySync(expectedVersion) {
2583
2755
  return usable;
2584
2756
  }
2585
2757
  } catch {}
2586
- const cargoPath = join5(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
2758
+ const cargoPath = join6(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
2587
2759
  if (existsSync4(cargoPath)) {
2588
2760
  const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
2589
2761
  if (usable)
@@ -2631,28 +2803,28 @@ var init_resolver = __esm(() => {
2631
2803
  // ../aft-bridge/dist/migration.js
2632
2804
  import { spawnSync as spawnSync2 } from "node:child_process";
2633
2805
  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() {
2806
+ import { homedir as homedir8, tmpdir } from "node:os";
2807
+ import { basename, dirname as dirname3, join as join7, resolve as resolve4 } from "node:path";
2808
+ function dataHome2() {
2637
2809
  if (process.env.XDG_DATA_HOME)
2638
2810
  return process.env.XDG_DATA_HOME;
2639
2811
  if (process.platform === "win32") {
2640
- return process.env.LOCALAPPDATA || process.env.APPDATA || join6(homeDir2(), "AppData", "Local");
2812
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join7(homeDir3(), "AppData", "Local");
2641
2813
  }
2642
- return join6(homeDir2(), ".local", "share");
2814
+ return join7(homeDir3(), ".local", "share");
2643
2815
  }
2644
- function homeDir2() {
2816
+ function homeDir3() {
2645
2817
  if (process.platform === "win32")
2646
- return process.env.USERPROFILE || process.env.HOME || homedir7();
2647
- return process.env.HOME || homedir7();
2818
+ return process.env.USERPROFILE || process.env.HOME || homedir8();
2819
+ return process.env.HOME || homedir8();
2648
2820
  }
2649
2821
  function resolveLegacyStorageRoot(harness) {
2650
2822
  if (harness === "pi")
2651
- return join6(homeDir2(), ".pi", "agent", "aft");
2652
- return join6(dataHome(), "opencode", "storage", "plugin", "aft");
2823
+ return join7(homeDir3(), ".pi", "agent", "aft");
2824
+ return join7(dataHome2(), "opencode", "storage", "plugin", "aft");
2653
2825
  }
2654
2826
  function resolveCortexKitStorageRoot() {
2655
- return join6(dataHome(), "cortexkit", "aft");
2827
+ return join7(dataHome2(), "cortexkit", "aft");
2656
2828
  }
2657
2829
  function stripJsoncForParse(input) {
2658
2830
  let out = "";
@@ -2781,8 +2953,8 @@ function acquireConfigMigrationLock(lockDir) {
2781
2953
  }
2782
2954
  }
2783
2955
  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`);
2956
+ mkdirSync4(dirname3(targetPath), { recursive: true });
2957
+ const tmpPath = join7(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
2786
2958
  let fd = null;
2787
2959
  try {
2788
2960
  fd = openSync3(tmpPath, "wx", 384);
@@ -2803,8 +2975,8 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
2803
2975
  }
2804
2976
  }
2805
2977
  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`);
2978
+ mkdirSync4(dirname3(targetPath), { recursive: true });
2979
+ const tmpPath = join7(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
2808
2980
  let fd = null;
2809
2981
  try {
2810
2982
  fd = openSync3(tmpPath, "wx", 384);
@@ -2927,7 +3099,7 @@ function migrateAftConfigFile(opts) {
2927
3099
  if (existingSources.length === 0) {
2928
3100
  return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
2929
3101
  }
2930
- mkdirSync4(dirname2(opts.targetPath), { recursive: true });
3102
+ mkdirSync4(dirname3(opts.targetPath), { recursive: true });
2931
3103
  const release = acquireConfigMigrationLock(`${opts.targetPath}.lock`);
2932
3104
  try {
2933
3105
  const sources = existingSources.map((source) => ({
@@ -2984,13 +3156,13 @@ function spawnErrorLabel(error2) {
2984
3156
  return [code, error2.message].filter(Boolean).join(": ");
2985
3157
  }
2986
3158
  function migrationLogPath(newRoot, harness, logger) {
2987
- const desired = join6(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
3159
+ const desired = join7(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
2988
3160
  try {
2989
- mkdirSync4(dirname2(desired), { recursive: true });
3161
+ mkdirSync4(dirname3(desired), { recursive: true });
2990
3162
  return desired;
2991
3163
  } 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}.`);
3164
+ const fallback = join7(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
3165
+ logger?.warn?.(`Failed to create AFT migration log directory ${dirname3(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
2994
3166
  return fallback;
2995
3167
  }
2996
3168
  }
@@ -3091,13 +3263,13 @@ var init_migration = __esm(() => {
3091
3263
  // ../aft-bridge/dist/npm-resolver.js
3092
3264
  import { execFileSync } from "node:child_process";
3093
3265
  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";
3266
+ import { homedir as homedir9 } from "node:os";
3267
+ import { delimiter, dirname as dirname4, isAbsolute as isAbsolute3, join as join8 } from "node:path";
3096
3268
  function defaultDeps() {
3097
3269
  return {
3098
3270
  platform: process.platform,
3099
3271
  env: process.env,
3100
- home: homedir8(),
3272
+ home: homedir9(),
3101
3273
  execPath: process.execPath
3102
3274
  };
3103
3275
  }
@@ -3118,14 +3290,14 @@ function npmFromPath(deps) {
3118
3290
  const dir = entry.trim().replace(/^"|"$/g, "");
3119
3291
  if (!dir || !isAbsolute3(dir))
3120
3292
  continue;
3121
- if (isFile(join7(dir, name)))
3293
+ if (isFile(join8(dir, name)))
3122
3294
  return dir;
3123
3295
  }
3124
3296
  return null;
3125
3297
  }
3126
3298
  function npmAdjacentToNode(deps) {
3127
- const dir = dirname3(deps.execPath);
3128
- return isFile(join7(dir, npmBinaryName(deps.platform))) ? dir : null;
3299
+ const dir = dirname4(deps.execPath);
3300
+ return isFile(join8(dir, npmBinaryName(deps.platform))) ? dir : null;
3129
3301
  }
3130
3302
  function highestVersionedNodeBin(installsDir, name) {
3131
3303
  let entries;
@@ -3134,8 +3306,8 @@ function highestVersionedNodeBin(installsDir, name) {
3134
3306
  } catch {
3135
3307
  return null;
3136
3308
  }
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;
3309
+ const candidates = entries.filter((v) => isFile(join8(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
3310
+ return candidates.length > 0 ? join8(installsDir, candidates[0], "bin") : null;
3139
3311
  }
3140
3312
  function compareVersionsDesc(a, b) {
3141
3313
  const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
@@ -3160,22 +3332,22 @@ function wellKnownNpmDirs(deps) {
3160
3332
  const programFiles = env.ProgramFiles || "C:\\Program Files";
3161
3333
  const appData = env.APPDATA;
3162
3334
  const localAppData = env.LOCALAPPDATA;
3163
- push(join7(programFiles, "nodejs"));
3335
+ push(join8(programFiles, "nodejs"));
3164
3336
  if (appData)
3165
- push(join7(appData, "npm"));
3337
+ push(join8(appData, "npm"));
3166
3338
  if (localAppData)
3167
- push(join7(localAppData, "Volta", "bin"));
3339
+ push(join8(localAppData, "Volta", "bin"));
3168
3340
  if (env.NVM_SYMLINK)
3169
3341
  push(env.NVM_SYMLINK);
3170
3342
  } else {
3171
3343
  if (env.NVM_BIN)
3172
3344
  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")]);
3345
+ push(highestVersionedNodeBin(join8(home, ".nvm", "versions", "node"), name));
3346
+ push(highestVersionedNodeBin(join8(home, ".local", "share", "mise", "installs", "node"), name));
3347
+ push(highestVersionedNodeBin(join8(home, ".asdf", "installs", "nodejs"), name));
3348
+ push(join8(home, ".volta", "bin"));
3349
+ push(join8(home, ".asdf", "shims"));
3350
+ const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join8(home, ".local", "bin")]);
3179
3351
  for (const dir of systemDirs)
3180
3352
  push(dir);
3181
3353
  }
@@ -3185,12 +3357,12 @@ function resolveNpm(deps = defaultDeps()) {
3185
3357
  const name = npmBinaryName(deps.platform);
3186
3358
  const onPath = npmFromPath(deps);
3187
3359
  if (onPath)
3188
- return { command: join7(onPath, name), binDir: onPath };
3360
+ return { command: join8(onPath, name), binDir: onPath };
3189
3361
  const adjacent = npmAdjacentToNode(deps);
3190
3362
  if (adjacent)
3191
- return { command: join7(adjacent, name), binDir: adjacent };
3363
+ return { command: join8(adjacent, name), binDir: adjacent };
3192
3364
  for (const dir of wellKnownNpmDirs(deps)) {
3193
- const candidate = join7(dir, name);
3365
+ const candidate = join8(dir, name);
3194
3366
  if (isFile(candidate))
3195
3367
  return { command: candidate, binDir: dir };
3196
3368
  }
@@ -3226,7 +3398,7 @@ var init_npm_resolver = () => {};
3226
3398
  import { execFileSync as execFileSync2 } from "node:child_process";
3227
3399
  import { createHash as createHash3 } from "node:crypto";
3228
3400
  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";
3401
+ import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute4, join as join9, relative as relative2, resolve as resolve5, win32 } from "node:path";
3230
3402
  import { Readable as Readable2 } from "node:stream";
3231
3403
  import { pipeline as pipeline2 } from "node:stream/promises";
3232
3404
  function getPlatformInfo() {
@@ -3252,10 +3424,10 @@ function getManualInstallHint() {
3252
3424
  }
3253
3425
  async function ensureOnnxRuntime(storageDir) {
3254
3426
  const info = getPlatformInfo();
3255
- const ortVersionDir = join8(storageDir, "onnxruntime", ORT_VERSION);
3427
+ const ortVersionDir = join9(storageDir, "onnxruntime", ORT_VERSION);
3256
3428
  const libName = info?.libName ?? "libonnxruntime.dylib";
3257
3429
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
3258
- const libPath = join8(resolvedOrtDir, libName);
3430
+ const libPath = join9(resolvedOrtDir, libName);
3259
3431
  if (existsSync6(libPath)) {
3260
3432
  const meta = readOnnxInstalledMeta(ortVersionDir);
3261
3433
  if (meta?.sha256) {
@@ -3285,9 +3457,9 @@ async function ensureOnnxRuntime(storageDir) {
3285
3457
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
3286
3458
  return null;
3287
3459
  }
3288
- const onnxBaseDir = join8(storageDir, "onnxruntime");
3460
+ const onnxBaseDir = join9(storageDir, "onnxruntime");
3289
3461
  mkdirSync5(onnxBaseDir, { recursive: true });
3290
- const lockPath = join8(onnxBaseDir, ONNX_LOCK_FILE);
3462
+ const lockPath = join9(onnxBaseDir, ONNX_LOCK_FILE);
3291
3463
  cleanupAbandonedStagingDirs(onnxBaseDir);
3292
3464
  if (!acquireLock(lockPath)) {
3293
3465
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -3306,7 +3478,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
3306
3478
  for (const entry of entries) {
3307
3479
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
3308
3480
  continue;
3309
- const stagingDir = join8(onnxBaseDir, entry);
3481
+ const stagingDir = join9(onnxBaseDir, entry);
3310
3482
  const parts = entry.split(".");
3311
3483
  const pidStr = parts[parts.length - 2];
3312
3484
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -3343,7 +3515,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
3343
3515
  }
3344
3516
  function cleanupIncompleteTargetIfUnowned(ortDir) {
3345
3517
  try {
3346
- if (existsSync6(ortDir) && !existsSync6(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
3518
+ if (existsSync6(ortDir) && !existsSync6(join9(ortDir, ONNX_INSTALLED_META_FILE))) {
3347
3519
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
3348
3520
  rmSync3(ortDir, { recursive: true, force: true });
3349
3521
  }
@@ -3388,7 +3560,7 @@ function detectOnnxVersion(libDir, libName) {
3388
3560
  if (version)
3389
3561
  return version;
3390
3562
  }
3391
- const base = join8(libDir, libName);
3563
+ const base = join9(libDir, libName);
3392
3564
  if (existsSync6(base)) {
3393
3565
  try {
3394
3566
  const real = realpathSync(base);
@@ -3427,6 +3599,17 @@ function pathEntriesForPlatform() {
3427
3599
  return isAbsolute4(entry) || win32.isAbsolute(entry);
3428
3600
  });
3429
3601
  }
3602
+ function isWindowsSystem32Directory(dir) {
3603
+ if (process.platform !== "win32")
3604
+ return false;
3605
+ const normalizedDir = win32.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
3606
+ const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
3607
+ return windowsRoots.some((root) => {
3608
+ if (!root)
3609
+ return false;
3610
+ return normalizedDir === win32.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
3611
+ });
3612
+ }
3430
3613
  function directoryContainsLibrary(dir, libName) {
3431
3614
  try {
3432
3615
  const entries = readdirSync2(dir);
@@ -3440,10 +3623,10 @@ function directoryContainsLibrary(dir, libName) {
3440
3623
  }
3441
3624
  }
3442
3625
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
3443
- if (existsSync6(join8(ortVersionDir, libName)))
3626
+ if (existsSync6(join9(ortVersionDir, libName)))
3444
3627
  return ortVersionDir;
3445
- const libSubdir = join8(ortVersionDir, "lib");
3446
- if (existsSync6(join8(libSubdir, libName)))
3628
+ const libSubdir = join9(ortVersionDir, "lib");
3629
+ if (existsSync6(join9(libSubdir, libName)))
3447
3630
  return libSubdir;
3448
3631
  return ortVersionDir;
3449
3632
  }
@@ -3458,12 +3641,12 @@ function findSystemOnnxRuntime(libName) {
3458
3641
  } else if (process.platform === "win32") {
3459
3642
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
3460
3643
  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"), ...(() => {
3644
+ searchPaths.push(join9(programFiles, "onnxruntime", "lib"), join9(programFiles, "Microsoft ONNX Runtime", "lib"), join9(programFiles, "Microsoft Machine Learning", "lib"), join9(programFilesX86, "onnxruntime", "lib"), ...(() => {
3462
3645
  const nugetPaths = [];
3463
3646
  const userProfile = process.env.USERPROFILE ?? "";
3464
3647
  if (!userProfile)
3465
3648
  return nugetPaths;
3466
- const nugetPackageDir = join8(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
3649
+ const nugetPackageDir = join9(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
3467
3650
  if (!existsSync6(nugetPackageDir))
3468
3651
  return nugetPaths;
3469
3652
  try {
@@ -3472,7 +3655,7 @@ function findSystemOnnxRuntime(libName) {
3472
3655
  continue;
3473
3656
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
3474
3657
  continue;
3475
- nugetPaths.push(join8(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join8(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
3658
+ nugetPaths.push(join9(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join9(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
3476
3659
  }
3477
3660
  } catch (err) {
3478
3661
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -3494,7 +3677,7 @@ function findSystemOnnxRuntime(libName) {
3494
3677
  });
3495
3678
  const unknownVersionPaths = [];
3496
3679
  for (const dir of uniquePaths) {
3497
- const libPath = join8(dir, libName);
3680
+ const libPath = join9(dir, libName);
3498
3681
  if (process.platform === "win32") {
3499
3682
  if (!directoryContainsLibrary(dir, libName))
3500
3683
  continue;
@@ -3503,6 +3686,10 @@ function findSystemOnnxRuntime(libName) {
3503
3686
  }
3504
3687
  const version = detectOnnxVersion(dir, libName);
3505
3688
  if (!version) {
3689
+ if (isWindowsSystem32Directory(dir)) {
3690
+ warn(`Skipping unversioned Windows system ONNX Runtime at ${dir}; falling through to AFT-managed download.`);
3691
+ continue;
3692
+ }
3506
3693
  unknownVersionPaths.push(dir);
3507
3694
  continue;
3508
3695
  }
@@ -3530,7 +3717,7 @@ async function downloadFileWithCap(url, destPath) {
3530
3717
  if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
3531
3718
  throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
3532
3719
  }
3533
- mkdirSync5(dirname4(destPath), { recursive: true });
3720
+ mkdirSync5(dirname5(destPath), { recursive: true });
3534
3721
  let bytesWritten = 0;
3535
3722
  const guard = new TransformStream({
3536
3723
  transform(chunk, transformController) {
@@ -3560,11 +3747,11 @@ function validateExtractedTree(stagingRoot) {
3560
3747
  const walk = (dir) => {
3561
3748
  const entries = readdirSync2(dir);
3562
3749
  for (const entry of entries) {
3563
- const fullPath = join8(dir, entry);
3750
+ const fullPath = join9(dir, entry);
3564
3751
  const lst = lstatSync(fullPath);
3565
3752
  if (lst.isSymbolicLink()) {
3566
3753
  const linkTarget = readlinkSync(fullPath);
3567
- const resolvedTarget = resolve5(dirname4(fullPath), linkTarget);
3754
+ const resolvedTarget = resolve5(dirname5(fullPath), linkTarget);
3568
3755
  const rel2 = relative2(realRoot, resolvedTarget);
3569
3756
  if (rel2.startsWith("..") || isAbsolute4(rel2) || win32.isAbsolute(rel2)) {
3570
3757
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
@@ -3595,7 +3782,7 @@ async function downloadOnnxRuntime(info, targetDir) {
3595
3782
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
3596
3783
  try {
3597
3784
  mkdirSync5(tmpDir, { recursive: true });
3598
- const archivePath = join8(tmpDir, `onnxruntime.${info.archiveType}`);
3785
+ const archivePath = join9(tmpDir, `onnxruntime.${info.archiveType}`);
3599
3786
  await downloadFileWithCap(url, archivePath);
3600
3787
  const archiveSha256 = sha256File(archivePath);
3601
3788
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
@@ -3611,7 +3798,7 @@ async function downloadOnnxRuntime(info, targetDir) {
3611
3798
  unlinkSync4(archivePath);
3612
3799
  } catch {}
3613
3800
  validateExtractedTree(tmpDir);
3614
- const extractedDir = join8(tmpDir, info.assetName, "lib");
3801
+ const extractedDir = join9(tmpDir, info.assetName, "lib");
3615
3802
  if (!existsSync6(extractedDir)) {
3616
3803
  throw new Error(`Expected directory not found: ${extractedDir}`);
3617
3804
  }
@@ -3620,11 +3807,11 @@ async function downloadOnnxRuntime(info, targetDir) {
3620
3807
  const realFiles = [];
3621
3808
  const symlinks = [];
3622
3809
  for (const libFile of libFiles) {
3623
- const src = join8(extractedDir, libFile);
3810
+ const src = join9(extractedDir, libFile);
3624
3811
  try {
3625
- const stat = lstatSync(src);
3626
- log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
3627
- if (stat.isSymbolicLink()) {
3812
+ const stat2 = lstatSync(src);
3813
+ log(`ORT extract: ${libFile} — isSymlink=${stat2.isSymbolicLink()}, isFile=${stat2.isFile()}, size=${stat2.size}`);
3814
+ if (stat2.isSymbolicLink()) {
3628
3815
  symlinks.push({ name: libFile, target: readlinkSync(src) });
3629
3816
  } else {
3630
3817
  realFiles.push(libFile);
@@ -3635,7 +3822,7 @@ async function downloadOnnxRuntime(info, targetDir) {
3635
3822
  }
3636
3823
  }
3637
3824
  copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
3638
- const libPath = join8(targetDir, info.libName);
3825
+ const libPath = join9(targetDir, info.libName);
3639
3826
  let libHash = null;
3640
3827
  try {
3641
3828
  libHash = sha256File(libPath);
@@ -3660,8 +3847,8 @@ async function downloadOnnxRuntime(info, targetDir) {
3660
3847
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
3661
3848
  const requiredLibs = new Set([info.libName]);
3662
3849
  for (const libFile of realFiles) {
3663
- const src = join8(extractedDir, libFile);
3664
- const dst = join8(targetDir, libFile);
3850
+ const src = join9(extractedDir, libFile);
3851
+ const dst = join9(targetDir, libFile);
3665
3852
  try {
3666
3853
  copyFile(src, dst);
3667
3854
  if (process.platform !== "win32") {
@@ -3677,12 +3864,12 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
3677
3864
  }
3678
3865
  const targetRoot = realpathSync(targetDir);
3679
3866
  for (const link of symlinks) {
3680
- const dst = join8(targetDir, link.name);
3867
+ const dst = join9(targetDir, link.name);
3681
3868
  try {
3682
3869
  unlinkSync4(dst);
3683
3870
  } catch {}
3684
- const dstForContainment = join8(targetRoot, link.name);
3685
- const resolvedTarget = resolve5(dirname4(dstForContainment), link.target);
3871
+ const dstForContainment = join9(targetRoot, link.name);
3872
+ const resolvedTarget = resolve5(dirname5(dstForContainment), link.target);
3686
3873
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
3687
3874
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
3688
3875
  if (requiredLibs.has(link.name)) {
@@ -3702,7 +3889,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
3702
3889
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
3703
3890
  }
3704
3891
  }
3705
- const requiredPath = join8(targetDir, info.libName);
3892
+ const requiredPath = join9(targetDir, info.libName);
3706
3893
  if (!existsSync6(requiredPath)) {
3707
3894
  rmSync3(targetDir, { recursive: true, force: true });
3708
3895
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
@@ -3729,13 +3916,13 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
3729
3916
  ...sha256 ? { sha256 } : {},
3730
3917
  archiveSha256
3731
3918
  };
3732
- writeFileSync3(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
3919
+ writeFileSync3(join9(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
3733
3920
  } catch (err) {
3734
3921
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
3735
3922
  }
3736
3923
  }
3737
3924
  function readOnnxInstalledMeta(installDir) {
3738
- const path2 = join8(installDir, ONNX_INSTALLED_META_FILE);
3925
+ const path2 = join9(installDir, ONNX_INSTALLED_META_FILE);
3739
3926
  try {
3740
3927
  if (!statSync4(path2).isFile())
3741
3928
  return null;
@@ -3873,7 +4060,7 @@ function isProcessAlive(pid) {
3873
4060
  }
3874
4061
  function cleanupOnnxRuntime(storageDir) {
3875
4062
  try {
3876
- const ortBase = join8(storageDir, "onnxruntime");
4063
+ const ortBase = join9(storageDir, "onnxruntime");
3877
4064
  if (existsSync6(ortBase)) {
3878
4065
  rmSync3(ortBase, { recursive: true, force: true });
3879
4066
  }
@@ -3975,10 +4162,10 @@ function projectRootKeyHash(dir) {
3975
4162
  var init_project_identity = () => {};
3976
4163
 
3977
4164
  // ../aft-bridge/dist/pool.js
3978
- import { homedir as homedir9 } from "node:os";
4165
+ import { homedir as homedir10 } from "node:os";
3979
4166
  function canonicalHomeDir() {
3980
4167
  try {
3981
- const home = homedir9();
4168
+ const home = homedir10();
3982
4169
  if (!home)
3983
4170
  return null;
3984
4171
  return canonicalizeProjectRoot(home);
@@ -4004,6 +4191,7 @@ class BridgePool {
4004
4191
  projectConfigLoader;
4005
4192
  logger;
4006
4193
  cleanupTimer = null;
4194
+ shutdownCalled = false;
4007
4195
  constructor(binaryPath, options = {}, configOverrides = {}) {
4008
4196
  this.binaryPath = binaryPath;
4009
4197
  this.maxPoolSize = options.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE;
@@ -4025,12 +4213,11 @@ class BridgePool {
4025
4213
  childEnv: options.childEnv
4026
4214
  };
4027
4215
  this.configOverrides = configOverrides;
4028
- if (Number.isFinite(this.idleTimeoutMs)) {
4029
- this.cleanupTimer = setInterval(() => this.cleanup(), CLEANUP_INTERVAL_MS);
4030
- this.cleanupTimer.unref();
4031
- }
4216
+ this.startCleanupTimer();
4032
4217
  }
4033
4218
  getActiveBridgeForRoot(projectRoot) {
4219
+ if (this.shutdownCalled)
4220
+ return null;
4034
4221
  const key = normalizeKey(projectRoot);
4035
4222
  const entry = this.bridges.get(key);
4036
4223
  if (!entry?.bridge.isAlive())
@@ -4038,7 +4225,21 @@ class BridgePool {
4038
4225
  entry.lastUsed = Date.now();
4039
4226
  return entry.bridge;
4040
4227
  }
4228
+ activeBridges() {
4229
+ if (this.shutdownCalled)
4230
+ return [];
4231
+ const alive = [];
4232
+ for (const entry of this.bridges.values()) {
4233
+ if (entry.bridge.isAlive())
4234
+ alive.push(entry.bridge);
4235
+ }
4236
+ return alive;
4237
+ }
4041
4238
  getBridge(projectRoot) {
4239
+ if (this.shutdownCalled) {
4240
+ this.shutdownCalled = false;
4241
+ this.startCleanupTimer();
4242
+ }
4042
4243
  const key = normalizeKey(projectRoot);
4043
4244
  const existing = this.bridges.get(key);
4044
4245
  if (existing) {
@@ -4048,15 +4249,7 @@ class BridgePool {
4048
4249
  if (this.bridges.size >= this.maxPoolSize) {
4049
4250
  this.evictLRU();
4050
4251
  }
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
- }
4252
+ const projectOverrides = this.loadProjectOverrides(key);
4060
4253
  const mergedOverrides = { ...this.configOverrides, ...projectOverrides };
4061
4254
  const bridge = new BinaryBridge(this.binaryPath, key, this.bridgeOptions, mergedOverrides);
4062
4255
  this.bridges.set(key, { bridge, lastUsed: Date.now() });
@@ -4106,6 +4299,7 @@ class BridgePool {
4106
4299
  }
4107
4300
  async closeSession(_projectRoot, _session) {}
4108
4301
  async shutdown() {
4302
+ this.shutdownCalled = true;
4109
4303
  if (this.cleanupTimer) {
4110
4304
  clearInterval(this.cleanupTimer);
4111
4305
  this.cleanupTimer = null;
@@ -4118,6 +4312,9 @@ class BridgePool {
4118
4312
  this.staleBridges.clear();
4119
4313
  await Promise.allSettled(shutdowns);
4120
4314
  }
4315
+ isShutdown() {
4316
+ return this.shutdownCalled;
4317
+ }
4121
4318
  async replaceBinary(newPath) {
4122
4319
  this.binaryPath = newPath;
4123
4320
  for (const entry of this.bridges.values()) {
@@ -4127,6 +4324,12 @@ class BridgePool {
4127
4324
  this.log(`Binary path updated to ${newPath}. Active bridges marked stale — next calls will use the new binary.`);
4128
4325
  return newPath;
4129
4326
  }
4327
+ startCleanupTimer() {
4328
+ if (!Number.isFinite(this.idleTimeoutMs) || this.cleanupTimer)
4329
+ return;
4330
+ this.cleanupTimer = setInterval(() => this.cleanup(), CLEANUP_INTERVAL_MS);
4331
+ this.cleanupTimer.unref();
4332
+ }
4130
4333
  log(message, meta) {
4131
4334
  const logger = this.logger ?? getActiveLogger();
4132
4335
  if (logger) {
@@ -4158,6 +4361,36 @@ class BridgePool {
4158
4361
  this.configOverrides[key] = value;
4159
4362
  }
4160
4363
  }
4364
+ async reconfigure(projectRoot, overrides) {
4365
+ const key = normalizeKey(projectRoot);
4366
+ for (const [name, value] of Object.entries(overrides)) {
4367
+ this.setConfigureOverride(name, value);
4368
+ }
4369
+ const bridge = this.getActiveBridgeForRoot(key);
4370
+ if (!bridge)
4371
+ return;
4372
+ const projectOverrides = this.loadProjectOverrides(key);
4373
+ const response = await bridge.send("configure", {
4374
+ project_root: key,
4375
+ ...this.configOverrides,
4376
+ ...projectOverrides,
4377
+ ...overrides
4378
+ });
4379
+ if (response.success === false) {
4380
+ throw new Error(`configure refresh failed for ${key}: ${String(response.message ?? "unknown error")}`);
4381
+ }
4382
+ }
4383
+ loadProjectOverrides(key) {
4384
+ if (!this.projectConfigLoader)
4385
+ return {};
4386
+ try {
4387
+ return this.projectConfigLoader(key) ?? {};
4388
+ } catch (err) {
4389
+ const message = err instanceof Error ? err.message : String(err);
4390
+ this.error(`projectConfigLoader failed; using global overrides only: ${message}`);
4391
+ return {};
4392
+ }
4393
+ }
4161
4394
  get size() {
4162
4395
  return this.bridges.size;
4163
4396
  }
@@ -4188,7 +4421,186 @@ var init_pool = __esm(() => {
4188
4421
  };
4189
4422
  });
4190
4423
 
4191
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/auth.js
4424
+ // ../aft-bridge/dist/revivable-transport.js
4425
+ class RevivableTransportPool {
4426
+ createPool;
4427
+ onBinaryReplaced;
4428
+ activePool;
4429
+ revival = null;
4430
+ transports = new Map;
4431
+ configureOverrides = new Map;
4432
+ constructor(initialPool, createPool, onBinaryReplaced) {
4433
+ this.createPool = createPool;
4434
+ this.onBinaryReplaced = onBinaryReplaced;
4435
+ this.activePool = initialPool;
4436
+ }
4437
+ getBridge(projectRoot) {
4438
+ const key = canonicalizeProjectRoot(projectRoot);
4439
+ let transport = this.transports.get(key);
4440
+ if (!transport) {
4441
+ transport = new RevivableProjectTransport(this, key);
4442
+ this.transports.set(key, transport);
4443
+ }
4444
+ return transport;
4445
+ }
4446
+ activeBridges() {
4447
+ return this.activePool.activeBridges();
4448
+ }
4449
+ getActiveBridgeForRoot(projectRoot) {
4450
+ const key = canonicalizeProjectRoot(projectRoot);
4451
+ const bridge = this.currentBridge(key);
4452
+ if (!bridge)
4453
+ return null;
4454
+ const transport = this.getBridge(key);
4455
+ transport.refreshStatusSubscription(bridge);
4456
+ return transport;
4457
+ }
4458
+ async toolCall(projectRoot, runtime, name, rawArgs = {}, options) {
4459
+ return this.getBridge(projectRoot).toolCall(runtime.sessionID, name, rawArgs, options);
4460
+ }
4461
+ setConfigureOverride(key, value) {
4462
+ if (value === undefined)
4463
+ this.configureOverrides.delete(key);
4464
+ else
4465
+ this.configureOverrides.set(key, value);
4466
+ this.activePool.setConfigureOverride(key, value);
4467
+ }
4468
+ async reconfigure(projectRoot, overrides) {
4469
+ for (const [key, value] of Object.entries(overrides)) {
4470
+ if (value === undefined)
4471
+ this.configureOverrides.delete(key);
4472
+ else
4473
+ this.configureOverrides.set(key, value);
4474
+ }
4475
+ const pool = await this.ensureActivePool();
4476
+ await pool.reconfigure(projectRoot, overrides);
4477
+ }
4478
+ async replaceBinary(path2) {
4479
+ const replaced = await this.activePool.replaceBinary(path2);
4480
+ this.onBinaryReplaced?.(replaced);
4481
+ return replaced;
4482
+ }
4483
+ closeSession(projectRoot, session) {
4484
+ return this.activePool.closeSession(projectRoot, session);
4485
+ }
4486
+ async shutdown() {
4487
+ const revival = this.revival;
4488
+ if (revival) {
4489
+ await Promise.allSettled([revival]);
4490
+ }
4491
+ await this.activePool.shutdown();
4492
+ for (const transport of this.transports.values()) {
4493
+ transport.refreshStatusSubscription(null);
4494
+ }
4495
+ }
4496
+ isShutdown() {
4497
+ return this.activePool.isShutdown();
4498
+ }
4499
+ async ensureActivePool() {
4500
+ if (!this.activePool.isShutdown())
4501
+ return this.activePool;
4502
+ if (this.revival)
4503
+ return this.revival;
4504
+ warn("transport was shut down but new demand arrived — reviving (host quit hook fired without process exit?)");
4505
+ const revival = this.createPool().then((pool) => {
4506
+ for (const [key, value] of this.configureOverrides) {
4507
+ pool.setConfigureOverride(key, value);
4508
+ }
4509
+ this.activePool = pool;
4510
+ for (const [root, transport] of this.transports) {
4511
+ transport.refreshStatusSubscription(pool.getActiveBridgeForRoot(root));
4512
+ }
4513
+ return pool;
4514
+ });
4515
+ this.revival = revival;
4516
+ revival.then(() => {
4517
+ if (this.revival === revival)
4518
+ this.revival = null;
4519
+ }, () => {
4520
+ if (this.revival === revival)
4521
+ this.revival = null;
4522
+ });
4523
+ return revival;
4524
+ }
4525
+ currentBridge(projectRoot) {
4526
+ return this.activePool.getActiveBridgeForRoot(projectRoot);
4527
+ }
4528
+ async send(projectRoot, command, params, options) {
4529
+ const pool = await this.ensureActivePool();
4530
+ const bridge = pool.getBridge(projectRoot);
4531
+ this.getBridge(projectRoot).refreshStatusSubscription(bridge);
4532
+ return bridge.send(command, params, options);
4533
+ }
4534
+ async toolCallOnProject(projectRoot, sessionId, name, rawArgs, options) {
4535
+ const pool = await this.ensureActivePool();
4536
+ const bridge = pool.getBridge(projectRoot);
4537
+ this.getBridge(projectRoot).refreshStatusSubscription(bridge);
4538
+ return bridge.toolCall(sessionId, name, rawArgs, options);
4539
+ }
4540
+ }
4541
+
4542
+ class RevivableProjectTransport {
4543
+ owner;
4544
+ projectRoot;
4545
+ statusListeners = new Map;
4546
+ statusBridges = new Map;
4547
+ constructor(owner, projectRoot) {
4548
+ this.owner = owner;
4549
+ this.projectRoot = projectRoot;
4550
+ }
4551
+ getCwd() {
4552
+ return this.projectRoot;
4553
+ }
4554
+ getStatusBar() {
4555
+ return this.owner.currentBridge(this.projectRoot)?.getStatusBar();
4556
+ }
4557
+ getCachedStatus() {
4558
+ return this.owner.currentBridge(this.projectRoot)?.getCachedStatus() ?? null;
4559
+ }
4560
+ cacheStatusSnapshot(snapshot) {
4561
+ this.owner.currentBridge(this.projectRoot)?.cacheStatusSnapshot(snapshot);
4562
+ }
4563
+ send(command, params, options) {
4564
+ return this.owner.send(this.projectRoot, command, params, options);
4565
+ }
4566
+ toolCall(sessionId, name, rawArgs, options) {
4567
+ return this.owner.toolCallOnProject(this.projectRoot, sessionId, name, rawArgs, options);
4568
+ }
4569
+ subscribeStatus(listener) {
4570
+ if (this.statusListeners.has(listener))
4571
+ return () => this.removeStatusListener(listener);
4572
+ this.statusListeners.set(listener, () => {});
4573
+ this.bindStatusListener(listener, this.owner.currentBridge(this.projectRoot));
4574
+ return () => this.removeStatusListener(listener);
4575
+ }
4576
+ refreshStatusSubscription(bridge) {
4577
+ for (const listener of this.statusListeners.keys()) {
4578
+ this.bindStatusListener(listener, bridge);
4579
+ }
4580
+ }
4581
+ bindStatusListener(listener, bridge) {
4582
+ if (this.statusBridges.get(listener) === bridge)
4583
+ return;
4584
+ const previousUnsubscribe = this.statusListeners.get(listener);
4585
+ previousUnsubscribe?.();
4586
+ const maybe = bridge;
4587
+ const unsubscribe = maybe && typeof maybe.subscribeStatus === "function" ? maybe.subscribeStatus(listener) : () => {};
4588
+ this.statusListeners.set(listener, unsubscribe);
4589
+ this.statusBridges.set(listener, bridge);
4590
+ }
4591
+ removeStatusListener(listener) {
4592
+ const unsubscribe = this.statusListeners.get(listener);
4593
+ this.statusListeners.delete(listener);
4594
+ this.statusBridges.delete(listener);
4595
+ unsubscribe?.();
4596
+ }
4597
+ }
4598
+ var init_revivable_transport = __esm(() => {
4599
+ init_active_logger();
4600
+ init_project_identity();
4601
+ });
4602
+
4603
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/auth.js
4192
4604
  import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
4193
4605
  function computeProof(key, domain, clientNonce, serverNonce, daemonId) {
4194
4606
  const mac = createHmac("sha256", Buffer.from(key));
@@ -4249,7 +4661,132 @@ var init_auth = __esm(() => {
4249
4661
  };
4250
4662
  });
4251
4663
 
4252
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/connection-file.js
4664
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/envelope.js
4665
+ function isPureHeader(ty) {
4666
+ return ty === FrameType.Cancel || ty === FrameType.Ping || ty === FrameType.Pong || ty === FrameType.Goodbye;
4667
+ }
4668
+ function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Normal) {
4669
+ let flags = 0;
4670
+ if (binary)
4671
+ flags |= FLAG_BINARY;
4672
+ flags |= priority << FLAG_PRIORITY_SHIFT;
4673
+ if (last)
4674
+ flags |= FLAG_LAST;
4675
+ flags |= admissionClass << FLAG_ADMISSION_SHIFT;
4676
+ return flags;
4677
+ }
4678
+ function encodeHeader(header) {
4679
+ const buffer = new Uint8Array(HEADER_LEN);
4680
+ const view = new DataView(buffer.buffer);
4681
+ view.setUint32(0, header.len, true);
4682
+ buffer[4] = header.ver;
4683
+ buffer[5] = header.ty;
4684
+ buffer[6] = header.flags;
4685
+ view.setUint16(7, header.channel, true);
4686
+ view.setUint32(9, header.epoch, true);
4687
+ view.setBigUint64(13, header.corr, true);
4688
+ return buffer;
4689
+ }
4690
+ function decodeHeader(bytes) {
4691
+ if (bytes.length < FROZEN_PREFIX_LEN) {
4692
+ throw new DecodeError(`header shorter than frozen prefix: have ${bytes.length} bytes`, "too_short_for_prefix");
4693
+ }
4694
+ const ver = bytes[4];
4695
+ if (ver !== PROTOCOL_VERSION)
4696
+ throw new DecodeError(`unsupported envelope version ${ver}`, "unsupported_version");
4697
+ if (bytes.length < HEADER_LEN) {
4698
+ throw new DecodeError(`header too short for version: have ${bytes.length} bytes, need ${HEADER_LEN}`, "too_short_for_header");
4699
+ }
4700
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
4701
+ const len = view.getUint32(0, true);
4702
+ const typeByte = bytes[5];
4703
+ if (typeByte > FRAME_TYPE_MAX)
4704
+ throw new DecodeError(`unknown frame type byte ${typeByte}`, "unknown_frame_type");
4705
+ const ty = typeByte;
4706
+ const flags = bytes[6];
4707
+ if ((flags & FLAG_RESERVED_MASK) !== 0) {
4708
+ throw new DecodeError(`reserved flag bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_flag_bits");
4709
+ }
4710
+ if ((flags & FLAG_PRIORITY_MASK) >> FLAG_PRIORITY_SHIFT === 3) {
4711
+ throw new DecodeError(`reserved priority bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_priority_bits");
4712
+ }
4713
+ const admission = (flags & FLAG_ADMISSION_MASK) >> FLAG_ADMISSION_SHIFT;
4714
+ if (admission === 3) {
4715
+ throw new DecodeError(`reserved admission class set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_admission_class");
4716
+ }
4717
+ if (admission === AdmissionClass.Sheddable && ty !== FrameType.Push && ty !== FrameType.StreamData) {
4718
+ throw new DecodeError(`SHEDDABLE admission class is illegal on ${FrameType[ty]} in flags 0b${flags.toString(2).padStart(8, "0")}`, "sheddable_illegal_frame_type");
4719
+ }
4720
+ const channel = view.getUint16(7, true);
4721
+ const epoch = view.getUint32(9, true);
4722
+ if (channel === 0 && epoch !== 0) {
4723
+ throw new DecodeError(`control channel carried nonzero epoch ${epoch}`, "nonzero_epoch_on_control_channel");
4724
+ }
4725
+ if (isPureHeader(ty) && len !== 0) {
4726
+ throw new DecodeError(`pure-header frame ${FrameType[ty]} declared non-zero body length ${len}`, "pure_header_frame_with_body");
4727
+ }
4728
+ return { len, ver, ty, flags, channel, epoch, corr: view.getBigUint64(13, true) };
4729
+ }
4730
+ function buildFrame(ty, flags, channel, epoch, corr, body) {
4731
+ return buildFrameWithVersion(PROTOCOL_VERSION, ty, flags, channel, epoch, corr, body);
4732
+ }
4733
+ function buildFrameWithVersion(ver, ty, flags, channel, epoch, corr, body) {
4734
+ if (body.length > MAX_FRAME_BODY_LEN) {
4735
+ throw new DecodeError(`frame body ${body.length} exceeds max ${MAX_FRAME_BODY_LEN}`, "frame_body_too_large");
4736
+ }
4737
+ const header = { len: body.length, ver, ty, flags, channel, epoch, corr };
4738
+ decodeHeader(encodeHeader(header));
4739
+ return { header, body };
4740
+ }
4741
+ function encodeFrame(frame) {
4742
+ if (frame.header.len !== frame.body.length) {
4743
+ throw new DecodeError(`frame header length ${frame.header.len} does not match body length ${frame.body.length}`, "frame_length_mismatch");
4744
+ }
4745
+ const header = encodeHeader(frame.header);
4746
+ const output = new Uint8Array(header.length + frame.body.length);
4747
+ output.set(header, 0);
4748
+ output.set(frame.body, header.length);
4749
+ return output;
4750
+ }
4751
+ 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;
4752
+ var init_envelope = __esm(() => {
4753
+ MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
4754
+ (function(FrameType2) {
4755
+ FrameType2[FrameType2["Request"] = 0] = "Request";
4756
+ FrameType2[FrameType2["Response"] = 1] = "Response";
4757
+ FrameType2[FrameType2["Push"] = 2] = "Push";
4758
+ FrameType2[FrameType2["StreamData"] = 3] = "StreamData";
4759
+ FrameType2[FrameType2["StreamEnd"] = 4] = "StreamEnd";
4760
+ FrameType2[FrameType2["Error"] = 5] = "Error";
4761
+ FrameType2[FrameType2["Cancel"] = 6] = "Cancel";
4762
+ FrameType2[FrameType2["Ping"] = 7] = "Ping";
4763
+ FrameType2[FrameType2["Pong"] = 8] = "Pong";
4764
+ FrameType2[FrameType2["Hello"] = 9] = "Hello";
4765
+ FrameType2[FrameType2["HelloAck"] = 10] = "HelloAck";
4766
+ FrameType2[FrameType2["Goodbye"] = 11] = "Goodbye";
4767
+ })(FrameType || (FrameType = {}));
4768
+ FRAME_TYPE_MAX = FrameType.Goodbye;
4769
+ (function(Priority2) {
4770
+ Priority2[Priority2["Passive"] = 0] = "Passive";
4771
+ Priority2[Priority2["Interactive"] = 1] = "Interactive";
4772
+ Priority2[Priority2["Background"] = 2] = "Background";
4773
+ })(Priority || (Priority = {}));
4774
+ (function(AdmissionClass2) {
4775
+ AdmissionClass2[AdmissionClass2["Normal"] = 0] = "Normal";
4776
+ AdmissionClass2[AdmissionClass2["Expedite"] = 1] = "Expedite";
4777
+ AdmissionClass2[AdmissionClass2["Sheddable"] = 2] = "Sheddable";
4778
+ })(AdmissionClass || (AdmissionClass = {}));
4779
+ DecodeError = class DecodeError extends Error {
4780
+ code;
4781
+ constructor(message, code) {
4782
+ super(message);
4783
+ this.code = code;
4784
+ this.name = "DecodeError";
4785
+ }
4786
+ };
4787
+ });
4788
+
4789
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/connection-file.js
4253
4790
  import { promises as fs } from "node:fs";
4254
4791
  function toBytes(value, field) {
4255
4792
  if (!Array.isArray(value) || value.some((n) => typeof n !== "number")) {
@@ -4274,8 +4811,8 @@ function validate(info) {
4274
4811
  async function verifyOwnerOnly(path2) {
4275
4812
  if (process.platform === "win32")
4276
4813
  return;
4277
- const stat = await fs.stat(path2);
4278
- const mode = stat.mode & 511;
4814
+ const stat2 = await fs.stat(path2);
4815
+ const mode = stat2.mode & 511;
4279
4816
  if ((mode & 63) !== 0) {
4280
4817
  throw new ConnectionFileError(`connection file ${path2} has insecure permissions 0o${mode.toString(8)}; expected owner-only 0600`);
4281
4818
  }
@@ -4289,6 +4826,10 @@ async function readConnectionFile(path2) {
4289
4826
  } catch (err) {
4290
4827
  throw new ConnectionFileError(`connection file JSON read failed for ${path2}: ${String(err)}`);
4291
4828
  }
4829
+ const wireVersion = parsed.wire_version;
4830
+ if (wireVersion !== undefined && wireVersion !== PROTOCOL_VERSION) {
4831
+ throw new ConnectionFileError(`connection file wire_version ${String(wireVersion)} but this client speaks ${PROTOCOL_VERSION}; the client library must be upgraded`);
4832
+ }
4292
4833
  const endpointsRaw = parsed.endpoints;
4293
4834
  if (!Array.isArray(endpointsRaw)) {
4294
4835
  throw new ConnectionFileError("connection file 'endpoints' must be an array");
@@ -4313,116 +4854,59 @@ async function readConnectionFile(path2) {
4313
4854
  }
4314
4855
  var SCHEMA_VERSION = 1, MIN_KEY_LEN = 32, DAEMON_ID_LEN = 16, ConnectionFileError;
4315
4856
  var init_connection_file = __esm(() => {
4857
+ init_envelope();
4316
4858
  ConnectionFileError = class ConnectionFileError extends Error {
4317
4859
  };
4318
4860
  });
4319
4861
 
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 {
4862
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/route-handle.js
4863
+ class RouteHandle {
4864
+ channel;
4865
+ epoch;
4866
+ constructor(channel, epoch, token) {
4867
+ if (!Number.isInteger(channel) || channel <= 0 || channel > 65535) {
4868
+ throw new RangeError(`route channel must be an integer in 1..65535, got ${channel}`);
4869
+ }
4870
+ if (!Number.isInteger(epoch) || epoch <= 0 || epoch > 4294967295) {
4871
+ throw new RangeError(`route epoch must be an integer in 1..4294967295, got ${epoch}`);
4872
+ }
4873
+ this.channel = channel;
4874
+ this.epoch = epoch;
4875
+ connectionToken.set(this, token);
4876
+ Object.freeze(this);
4877
+ }
4878
+ static create(channel, epoch, token) {
4879
+ return new RouteHandle(channel, epoch, token);
4880
+ }
4881
+ }
4882
+ function createRouteHandle(channel, epoch, token) {
4883
+ const factory = RouteHandle;
4884
+ return factory.create(channel, epoch, token);
4885
+ }
4886
+ function newConnectionToken() {
4887
+ return Object.freeze({});
4888
+ }
4889
+ function belongsToConnection(handle, token) {
4890
+ return connectionToken.get(handle) === token;
4891
+ }
4892
+ function sameRouteHandle(left, right) {
4893
+ return left === right;
4894
+ }
4895
+ var connectionToken, StaleRouteHandleError;
4896
+ var init_route_handle = __esm(() => {
4897
+ connectionToken = new WeakMap;
4898
+ StaleRouteHandleError = class StaleRouteHandleError extends Error {
4899
+ handle;
4900
+ code = "stale_route_handle";
4901
+ constructor(handle) {
4902
+ super(`route handle (${handle.channel}, ${handle.epoch}) is not live on the current connection`);
4903
+ this.handle = handle;
4904
+ this.name = "StaleRouteHandleError";
4905
+ }
4422
4906
  };
4423
4907
  });
4424
4908
 
4425
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/socket.js
4909
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/socket.js
4426
4910
  import net from "node:net";
4427
4911
 
4428
4912
  class SubcSocket {
@@ -4471,6 +4955,24 @@ class SubcSocket {
4471
4955
  });
4472
4956
  });
4473
4957
  }
4958
+ async readFrame(headerDeadlineMs, bodyDeadline, onHeader) {
4959
+ const prefix = await this.readExact(FROZEN_PREFIX_LEN, headerDeadlineMs);
4960
+ const version = prefix[4];
4961
+ if (version !== PROTOCOL_VERSION)
4962
+ throw new DecodeError(`unsupported envelope version ${version}`, "unsupported_version");
4963
+ const remainder = await this.readExact(HEADER_LEN - FROZEN_PREFIX_LEN, headerDeadlineMs);
4964
+ const headerBytes = new Uint8Array(HEADER_LEN);
4965
+ headerBytes.set(prefix);
4966
+ headerBytes.set(remainder, FROZEN_PREFIX_LEN);
4967
+ const header = decodeHeader(headerBytes);
4968
+ if (header.len > MAX_FRAME_BODY_LEN) {
4969
+ throw new DecodeError(`frame body ${header.len} exceeds max ${MAX_FRAME_BODY_LEN}`, "frame_body_too_large");
4970
+ }
4971
+ onHeader?.();
4972
+ const bodyDeadlineMs = typeof bodyDeadline === "number" ? bodyDeadline : Date.now() + bodyDeadline.afterHeaderMs;
4973
+ const body = header.len === 0 ? new Uint8Array(0) : await this.readExact(header.len, bodyDeadlineMs);
4974
+ return { header, body };
4975
+ }
4474
4976
  readExact(n, deadlineMs) {
4475
4977
  if (this.waiter) {
4476
4978
  return Promise.reject(new Error("concurrent readExact is not supported"));
@@ -4593,6 +5095,7 @@ class SubcSocket {
4593
5095
  }
4594
5096
  var SocketClosedError, SocketTimeoutError, SocketWriteNotQueuedError, SocketWriteQueuedError;
4595
5097
  var init_socket = __esm(() => {
5098
+ init_envelope();
4596
5099
  SocketClosedError = class SocketClosedError extends Error {
4597
5100
  };
4598
5101
  SocketTimeoutError = class SocketTimeoutError extends Error {
@@ -4613,7 +5116,7 @@ var init_socket = __esm(() => {
4613
5116
  };
4614
5117
  });
4615
5118
 
4616
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/client.js
5119
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/client.js
4617
5120
  import { promises as fs2 } from "node:fs";
4618
5121
  import { debuglog } from "node:util";
4619
5122
 
@@ -4623,7 +5126,11 @@ class SubcClient {
4623
5126
  opts;
4624
5127
  nextCorr = 1n;
4625
5128
  pending = new Map;
5129
+ lateResponses = new Map;
4626
5130
  routes = new Map;
5131
+ liveRoutes = new Map;
5132
+ connectionToken = newConnectionToken();
5133
+ ingressEpochDropCount = 0;
4627
5134
  closedErr = null;
4628
5135
  closeStarted = false;
4629
5136
  reconnecting = null;
@@ -4651,40 +5158,71 @@ class SubcClient {
4651
5158
  }
4652
5159
  async routeOpen(target, identity, opts = {}) {
4653
5160
  const consumerIdentity = routeOpenConsumerIdentity(opts);
5161
+ const consumerCapabilities = opts.consumerCapabilities;
4654
5162
  const body = this.encode({
4655
5163
  op: "route.open",
4656
5164
  target,
4657
5165
  identity,
4658
- ...consumerIdentity ? { consumer_identity: consumerIdentity } : {}
5166
+ ...consumerIdentity ? { consumer_identity: consumerIdentity } : {},
5167
+ ...consumerCapabilities !== undefined ? { consumer_capabilities: consumerCapabilities } : {}
4659
5168
  });
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;
5169
+ let installed = null;
5170
+ const install = (frame) => {
5171
+ if (frame.header.ty !== FrameType.Response)
5172
+ return true;
5173
+ const parsed = this.parseJson(frame);
5174
+ if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number") {
5175
+ throw new SubcError(`route.open returned no route handle: ${JSON.stringify(parsed)}`);
5176
+ }
5177
+ installed = this.installRoute(parsed.route_channel, parsed.route_epoch);
5178
+ return true;
5179
+ };
5180
+ const closeLateRoute = (frame) => {
5181
+ if (frame.header.ty !== FrameType.Response)
5182
+ return;
5183
+ try {
5184
+ const parsed = this.parseJson(frame);
5185
+ if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number")
5186
+ return;
5187
+ const lateHandle = this.installRoute(parsed.route_channel, parsed.route_epoch);
5188
+ this.failHandle(lateHandle, new SubcError("late route.open was closed", "route_closed"));
5189
+ this.liveRoutes.delete(lateHandle.channel);
5190
+ this.sendRouteGoodbye(lateHandle, true);
5191
+ } catch {
5192
+ this.closeConnectionAfterCleanupFailure();
5193
+ }
5194
+ };
5195
+ await this.controlRpc(body, install, closeLateRoute);
5196
+ if (!installed)
5197
+ throw new SubcError("route.open response was not installed");
5198
+ return installed;
4666
5199
  }
4667
- async request(routeChannel, body, opts = {}) {
5200
+ async request(handle, body, opts = {}) {
5201
+ this.assertLiveHandle(handle);
4668
5202
  const bytes = body instanceof Uint8Array ? body : this.encode(body);
4669
5203
  const priority = opts.priority ?? Priority.Interactive;
4670
- const reply = await this.send(routeChannel, bytes, priority, opts.timeoutMs, opts.onProgress);
5204
+ const admission = opts.admissionClass ?? AdmissionClass.Normal;
5205
+ const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
4671
5206
  return this.parseJson(reply);
4672
5207
  }
4673
5208
  async call(moduleId, method, params, opts = {}) {
4674
5209
  const body = params === undefined ? { method } : { method, params };
4675
5210
  let retriedUnknownChannel = false;
4676
5211
  for (;; ) {
4677
- const routeChannel = await this.cachedRouteChannel(moduleId, opts);
5212
+ const routeHandle = await this.cachedRouteHandle(moduleId, opts);
4678
5213
  try {
4679
- return await this.managedRequest(routeChannel, body, opts);
5214
+ return await this.managedRequest(routeHandle, body, opts);
4680
5215
  } catch (err) {
4681
5216
  if (!(err instanceof SubcCallError))
4682
5217
  throw this.terminalCallError("managed call failed", err);
4683
5218
  if (err.code === "unknown_channel" && !retriedUnknownChannel && !this.closeStarted) {
4684
5219
  retriedUnknownChannel = true;
4685
- this.evictRouteChannel(routeChannel);
5220
+ this.evictRouteHandle(routeHandle);
4686
5221
  continue;
4687
5222
  }
5223
+ if (err.code === "unknown_channel" && retriedUnknownChannel) {
5224
+ this.evictRouteHandle(routeHandle);
5225
+ }
4688
5226
  if (err.kind === "not_sent") {
4689
5227
  try {
4690
5228
  await this.reconnectAfterDrop(err);
@@ -4700,29 +5238,31 @@ class SubcClient {
4700
5238
  }
4701
5239
  }
4702
5240
  }
4703
- subscribe(routeChannel, body, onEvent, opts = {}) {
5241
+ subscribe(handle, body, onEvent, opts = {}) {
5242
+ this.assertLiveHandle(handle);
4704
5243
  const bytes = body instanceof Uint8Array ? body : this.encode(body);
4705
5244
  const priority = opts.priority ?? Priority.Interactive;
4706
- const corr = this.nextCorr++;
4707
- const key = `${routeChannel}:${corr}`;
5245
+ const admission = opts.admissionClass ?? AdmissionClass.Normal;
5246
+ const corr = this.allocateCorr();
5247
+ const key = pendingKey(handle, corr);
4708
5248
  const closed = new Promise((resolve7, reject) => {
4709
5249
  if (this.closedErr) {
4710
5250
  reject(this.closedErr);
4711
5251
  return;
4712
5252
  }
4713
5253
  this.pending.set(key, {
4714
- channel: routeChannel,
5254
+ handle,
4715
5255
  resolve: () => resolve7(),
4716
5256
  reject,
4717
5257
  onProgress: onEvent,
4718
5258
  timer: null,
4719
5259
  subscription: true
4720
5260
  });
4721
- const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), routeChannel, corr, bytes);
5261
+ const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), handle.channel, handle.epoch, corr, bytes);
4722
5262
  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)));
5263
+ const pending = this.pending.get(key);
5264
+ if (pending)
5265
+ this.rejectPending(key, pending, err instanceof Error ? err : new SubcError(String(err)));
4726
5266
  });
4727
5267
  });
4728
5268
  let cancelled = false;
@@ -4730,45 +5270,77 @@ class SubcClient {
4730
5270
  if (cancelled)
4731
5271
  return;
4732
5272
  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(() => {});
5273
+ this.cancel(handle, corr, priority);
4735
5274
  };
4736
5275
  return { unsubscribe, closed };
4737
5276
  }
4738
- async closeRoute(target, identity, opts = {}) {
5277
+ cancel(handle, corr, priority = Priority.Interactive) {
5278
+ this.assertLiveHandle(handle);
5279
+ const cancel = buildFrame(FrameType.Cancel, buildFlags(false, priority, false), handle.channel, handle.epoch, corr, EMPTY_BODY);
5280
+ this.sock.write(encodeFrame(cancel), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch(() => {
5281
+ return;
5282
+ });
5283
+ }
5284
+ async routePoll(handle, kind) {
5285
+ this.assertLiveHandle(handle);
5286
+ const body = this.encode({
5287
+ op: "route.poll",
5288
+ route_channel: handle.channel,
5289
+ route_epoch: handle.epoch,
5290
+ kind
5291
+ });
5292
+ const reply = await this.controlRpc(body, (frame) => {
5293
+ if (frame.header.ty !== FrameType.Response)
5294
+ return true;
5295
+ const parsed = this.parseJson(frame);
5296
+ return parsed.route_channel === handle.channel && parsed.route_epoch === handle.epoch;
5297
+ });
5298
+ return this.parseJson(reply);
5299
+ }
5300
+ async closeRoute(handle, opts = {}) {
5301
+ this.assertLiveHandle(handle);
5302
+ for (const [key, cached] of this.routes) {
5303
+ if (cached.handle && sameRouteHandle(cached.handle, handle)) {
5304
+ cached.closed = true;
5305
+ cached.handle = null;
5306
+ this.routes.delete(key);
5307
+ }
5308
+ }
5309
+ if (opts.drain)
5310
+ await this.drainUnaryOnHandle(handle);
5311
+ this.failHandle(handle, new SubcError("route closed by closeRoute", "route_closed"));
5312
+ if (this.liveRoutes.get(handle.channel) === handle)
5313
+ this.liveRoutes.delete(handle.channel);
5314
+ this.sendRouteGoodbye(handle);
5315
+ }
5316
+ async closeManagedRoute(target, identity, opts = {}) {
4739
5317
  const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts));
4740
5318
  const cached = this.routes.get(key);
4741
5319
  if (!cached)
4742
5320
  return;
4743
5321
  cached.closed = true;
4744
5322
  this.routes.delete(key);
4745
- const channel = cached.channel;
4746
- cached.channel = null;
4747
- if (channel !== null)
4748
- await this.closeRouteChannel(channel, opts);
5323
+ const handle = cached.handle;
5324
+ cached.handle = null;
5325
+ if (handle)
5326
+ await this.closeRoute(handle, opts);
4749
5327
  }
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);
5328
+ async closeRouteChannel(handle, opts = {}) {
5329
+ await this.closeRoute(handle, opts);
4758
5330
  }
4759
5331
  close() {
4760
5332
  this.closeStarted = true;
4761
5333
  this.fail(new SubcError("client closed"));
4762
5334
  this.sock.close();
4763
5335
  }
4764
- drainUnaryOnChannel(channel) {
5336
+ drainUnaryOnHandle(handle) {
4765
5337
  const waiters = [];
4766
5338
  for (const pending of this.pending.values()) {
4767
- if (pending.channel === channel && !pending.subscription) {
5339
+ if (pending.handle === handle && !pending.subscription) {
4768
5340
  waiters.push(new Promise((resolve7) => {
4769
- const prev = pending.onSettle;
5341
+ const previous = pending.onSettle;
4770
5342
  pending.onSettle = () => {
4771
- prev?.();
5343
+ previous?.();
4772
5344
  resolve7();
4773
5345
  };
4774
5346
  }));
@@ -4778,11 +5350,21 @@ class SubcClient {
4778
5350
  return;
4779
5351
  });
4780
5352
  }
4781
- sendRouteGoodbye(channel) {
4782
- if (this.closedErr)
5353
+ sendRouteGoodbye(handle, closeOnQueueFailure = false) {
5354
+ this.assertLiveConnection(handle);
5355
+ if (this.closedErr) {
5356
+ if (closeOnQueueFailure)
5357
+ this.closeConnectionAfterCleanupFailure();
4783
5358
  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(() => {});
5359
+ }
5360
+ const goodbye = buildFrame(FrameType.Goodbye, buildFlags(false, Priority.Interactive, false), handle.channel, handle.epoch, 0n, EMPTY_BODY);
5361
+ const write = this.sock.writeTracked(encodeFrame(goodbye), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS);
5362
+ if (!write.queued && closeOnQueueFailure)
5363
+ this.closeConnectionAfterCleanupFailure();
5364
+ write.completed.catch(() => {
5365
+ if (closeOnQueueFailure && !write.queued)
5366
+ this.closeConnectionAfterCleanupFailure();
5367
+ });
4786
5368
  }
4787
5369
  static async openConnection(opts) {
4788
5370
  const conn = await readConnectionFile(opts.connectionFile);
@@ -4797,37 +5379,48 @@ class SubcClient {
4797
5379
  }
4798
5380
  return { sock, conn };
4799
5381
  }
4800
- async controlRpc(body) {
4801
- return this.send(0, body, Priority.Interactive, undefined, undefined);
5382
+ async controlRpc(body, acceptFrame, onLateResponse) {
5383
+ return this.send(null, body, Priority.Interactive, AdmissionClass.Normal, undefined, undefined, acceptFrame, onLateResponse);
4802
5384
  }
4803
- send(channel, body, priority, timeoutMs, onProgress) {
5385
+ send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse) {
5386
+ if (handle)
5387
+ this.assertLiveHandle(handle);
4804
5388
  if (this.closedErr)
4805
5389
  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);
5390
+ let corr;
5391
+ try {
5392
+ corr = this.allocateCorr();
5393
+ } catch (error2) {
5394
+ return Promise.reject(error2);
5395
+ }
5396
+ const key = pendingKey(handle, corr);
5397
+ const channel = handle?.channel ?? 0;
5398
+ const epoch = handle?.epoch ?? 0;
5399
+ const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), channel, epoch, corr, body);
4809
5400
  return new Promise((resolve7, reject) => {
4810
5401
  const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
4811
5402
  const pending = {
4812
- channel,
5403
+ handle,
4813
5404
  resolve: resolve7,
4814
5405
  reject,
4815
5406
  onProgress,
4816
- timer: null
5407
+ timer: null,
5408
+ acceptFrame,
5409
+ onLateResponse
4817
5410
  };
4818
- pending.timer = setTimeout(() => {
4819
- this.arbitrateTimeout(key, pending, channel, corr, ms);
4820
- }, ms);
5411
+ pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
4821
5412
  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)));
5413
+ this.sock.write(encodeFrame(frame), Date.now() + ms).catch((error2) => {
5414
+ const current = this.pending.get(key);
5415
+ if (current)
5416
+ this.rejectPending(key, current, error2 instanceof Error ? error2 : new SubcError(String(error2)));
4826
5417
  });
4827
5418
  });
4828
5419
  }
4829
5420
  arbitrateTimeout(key, pending, channel, corr, ms) {
4830
5421
  const settleAsTimeout = () => {
5422
+ if (pending.onLateResponse)
5423
+ this.lateResponses.set(key, pending.onLateResponse);
4831
5424
  this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms), REQUEST_DEADLINE_MARKER));
4832
5425
  };
4833
5426
  const graceDeadline = Date.now() + this.opts.timeoutArbitrationGraceMs;
@@ -4843,59 +5436,67 @@ class SubcClient {
4843
5436
  };
4844
5437
  setImmediate(arbitrate);
4845
5438
  }
4846
- async managedRequest(routeChannel, body, opts) {
5439
+ async managedRequest(handle, body, opts) {
4847
5440
  const bytes = body instanceof Uint8Array ? body : this.encode(body);
4848
5441
  const priority = opts.priority ?? Priority.Interactive;
5442
+ const admission = opts.admissionClass ?? AdmissionClass.Normal;
4849
5443
  try {
4850
- const reply = await this.sendManaged(routeChannel, bytes, priority, opts.timeoutMs, opts.onProgress);
5444
+ const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
4851
5445
  return this.parseJson(reply);
4852
- } catch (err) {
4853
- if (err instanceof SubcCallError)
4854
- throw err;
4855
- throw this.terminalCallError("managed call failed", err);
5446
+ } catch (error2) {
5447
+ if (error2 instanceof SubcCallError)
5448
+ throw error2;
5449
+ throw this.terminalCallError("managed call failed", error2);
4856
5450
  }
4857
5451
  }
4858
- sendManaged(channel, body, priority, timeoutMs, onProgress) {
5452
+ sendManaged(handle, body, priority, admission, timeoutMs, onProgress) {
5453
+ try {
5454
+ this.assertLiveHandle(handle);
5455
+ } catch (error2) {
5456
+ return Promise.reject(this.notSentCallError("request used a stale route handle", error2));
5457
+ }
4859
5458
  if (this.closedErr) {
4860
5459
  return Promise.reject(this.notSentCallError("request was not sent because the subc connection was already closed", this.closedErr));
4861
5460
  }
4862
- const corr = this.nextCorr++;
4863
- const key = `${channel}:${corr}`;
4864
- const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), channel, corr, body);
5461
+ let corr;
5462
+ try {
5463
+ corr = this.allocateCorr();
5464
+ } catch (error2) {
5465
+ return Promise.reject(this.notSentCallError("request correlation allocator was exhausted", error2));
5466
+ }
5467
+ const key = pendingKey(handle, corr);
5468
+ const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), handle.channel, handle.epoch, corr, body);
4865
5469
  let handedToSocket = false;
4866
- const classifyFailure = (err) => {
4867
- if (!handedToSocket) {
4868
- return this.notSentCallError("request bytes were not queued to the subc socket", err);
5470
+ const classifyFailure = (error2) => {
5471
+ if (!handedToSocket)
5472
+ return this.notSentCallError("request bytes were not queued to the subc socket", error2);
5473
+ if (error2 instanceof SubcError && error2.code === REQUEST_DEADLINE_MARKER) {
5474
+ 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);
4869
5475
  }
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);
4872
- }
4873
- return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", err);
5476
+ return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", error2);
4874
5477
  };
4875
5478
  return new Promise((resolve7, reject) => {
4876
5479
  const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
4877
5480
  const pending = {
4878
- channel,
5481
+ handle,
4879
5482
  resolve: resolve7,
4880
5483
  reject,
4881
5484
  onProgress,
4882
5485
  timer: null,
4883
5486
  classifyFailure
4884
5487
  };
4885
- pending.timer = setTimeout(() => {
4886
- this.arbitrateTimeout(key, pending, channel, corr, ms);
4887
- }, ms);
5488
+ pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, handle.channel, corr, ms), ms);
4888
5489
  this.pending.set(key, pending);
4889
5490
  const write = this.sock.writeTracked(encodeFrame(frame), Date.now() + ms);
4890
5491
  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)));
5492
+ write.completed.catch((error2) => {
5493
+ const current = this.pending.get(key);
5494
+ if (current)
5495
+ this.rejectPending(key, current, error2 instanceof Error ? error2 : new SubcError(String(error2)));
4895
5496
  });
4896
5497
  });
4897
5498
  }
4898
- async cachedRouteChannel(moduleId, opts) {
5499
+ async cachedRouteHandle(moduleId, opts) {
4899
5500
  const identity = opts.identity ?? this.opts.identity;
4900
5501
  if (!identity) {
4901
5502
  throw new SubcCallError("terminal", "managed call requires a BindIdentity in SubcClient.connect({ identity }) or call(..., { identity })", "missing_identity");
@@ -4911,15 +5512,13 @@ class SubcClient {
4911
5512
  target,
4912
5513
  identity,
4913
5514
  consumerIdentity,
4914
- channel: null,
4915
- generation: 0,
5515
+ handle: null,
4916
5516
  opening: null
4917
5517
  };
4918
5518
  this.routes.set(key, cached);
4919
5519
  }
4920
- if (cached.channel !== null && cached.generation === this.generation && !this.closedErr) {
4921
- return cached.channel;
4922
- }
5520
+ if (cached.handle && this.isLiveHandle(cached.handle))
5521
+ return cached.handle;
4923
5522
  if (!cached.opening) {
4924
5523
  cached.opening = this.openCachedRoute(cached).finally(() => {
4925
5524
  cached.opening = null;
@@ -4936,44 +5535,43 @@ class SubcClient {
4936
5535
  throw this.routeClosedDuringOpen();
4937
5536
  try {
4938
5537
  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;
5538
+ } catch (error2) {
5539
+ throw this.notSentRecoveryError("route.open could not run because reconnect failed", error2);
4944
5540
  }
5541
+ if (cached.handle && this.isLiveHandle(cached.handle))
5542
+ return cached.handle;
4945
5543
  try {
4946
- const channel = await this.routeOpen(cached.target, cached.identity, {
5544
+ const handle = await this.routeOpen(cached.target, cached.identity, {
4947
5545
  consumerIdentity: cached.consumerIdentity ?? null
4948
5546
  });
4949
5547
  if (cached.closed) {
4950
- this.sendRouteGoodbye(channel);
5548
+ this.liveRoutes.delete(handle.channel);
5549
+ this.sendRouteGoodbye(handle);
4951
5550
  throw this.routeClosedDuringOpen();
4952
5551
  }
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)) {
5552
+ cached.handle = handle;
5553
+ return handle;
5554
+ } catch (error2) {
5555
+ if (error2 instanceof SubcCallError && error2.code === "route_closed")
5556
+ throw error2;
5557
+ if (!this.closeStarted && isConsumerReconnectTransient(error2)) {
4960
5558
  try {
4961
- await this.reconnectAfterDrop(err);
4962
- } catch (reconnectErr) {
4963
- throw this.notSentRecoveryError("route.open was not sent and reconnect failed", reconnectErr);
5559
+ await this.reconnectAfterDrop(error2);
5560
+ } catch (reconnectError) {
5561
+ throw this.notSentRecoveryError("route.open was not sent and reconnect failed", reconnectError);
4964
5562
  }
4965
5563
  continue;
4966
5564
  }
4967
- if (!this.closeStarted && err instanceof SubcError && isRetryableRouteOpenCode(err.code)) {
5565
+ if (!this.closeStarted && error2 instanceof SubcError && isRetryableRouteOpenCode(error2.code)) {
4968
5566
  routeRetryAttempt += 1;
4969
5567
  if (routeRetryAttempt < this.opts.reconnectBackoff.maxAttempts && Date.now() < routeRetryDeadline) {
4970
5568
  await this.opts.sleep(routeRetryDelay);
4971
5569
  routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
4972
5570
  continue;
4973
5571
  }
4974
- throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${err.code} (retry budget exhausted)`, err);
5572
+ throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error2.code} (retry budget exhausted)`, error2);
4975
5573
  }
4976
- throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, err);
5574
+ throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, error2);
4977
5575
  }
4978
5576
  }
4979
5577
  }
@@ -5036,25 +5634,27 @@ class SubcClient {
5036
5634
  this.currentConn = opened.conn;
5037
5635
  this.closedErr = null;
5038
5636
  this.generation += 1;
5637
+ this.connectionToken = newConnectionToken();
5638
+ this.liveRoutes.clear();
5639
+ this.lateResponses.clear();
5640
+ this.nextCorr = 1n;
5039
5641
  this.readLoop(opened.sock, this.generation);
5040
5642
  }
5041
5643
  async reopenCachedRoutes() {
5042
- for (const cached of this.routes.values()) {
5043
- cached.channel = null;
5044
- cached.generation = 0;
5045
- }
5644
+ for (const cached of this.routes.values())
5645
+ cached.handle = null;
5046
5646
  for (const cached of this.routes.values()) {
5047
5647
  if (cached.closed)
5048
5648
  continue;
5049
- const channel = await this.routeOpen(cached.target, cached.identity, {
5649
+ const handle = await this.routeOpen(cached.target, cached.identity, {
5050
5650
  consumerIdentity: cached.consumerIdentity ?? null
5051
5651
  });
5052
5652
  if (cached.closed) {
5053
- this.sendRouteGoodbye(channel);
5653
+ this.liveRoutes.delete(handle.channel);
5654
+ this.sendRouteGoodbye(handle);
5054
5655
  continue;
5055
5656
  }
5056
- cached.channel = channel;
5057
- cached.generation = this.generation;
5657
+ cached.handle = handle;
5058
5658
  }
5059
5659
  }
5060
5660
  timeoutMessage(channel, corr, ms) {
@@ -5068,28 +5668,37 @@ class SubcClient {
5068
5668
  async readLoop(sock, generation) {
5069
5669
  try {
5070
5670
  for (;; ) {
5071
- const headerBytes = await sock.readExact(HEADER_LEN, Number.POSITIVE_INFINITY);
5072
- this.readerActive = true;
5671
+ this.readerActive = false;
5672
+ const frame = await sock.readFrame(Number.POSITIVE_INFINITY, { afterHeaderMs: BODY_READ_TIMEOUT_MS }, () => {
5673
+ this.readerActive = true;
5674
+ });
5073
5675
  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
- }
5676
+ if (this.sock === sock && this.generation === generation)
5677
+ this.dispatch(frame);
5079
5678
  } finally {
5080
5679
  this.readerActive = false;
5081
5680
  }
5082
5681
  }
5083
- } catch (err) {
5682
+ } catch (error2) {
5084
5683
  if (this.sock === sock && this.generation === generation) {
5085
- this.fail(err instanceof Error ? err : new SubcError(String(err)));
5684
+ this.fail(error2 instanceof Error ? error2 : new SubcError(String(error2)));
5685
+ }
5686
+ }
5687
+ }
5688
+ dispatch(frame) {
5689
+ let handle = null;
5690
+ if (frame.header.channel !== 0) {
5691
+ handle = this.liveRoutes.get(frame.header.channel) ?? null;
5692
+ if (!handle || handle.epoch !== frame.header.epoch) {
5693
+ this.ingressEpochDropCount += 1;
5694
+ return;
5086
5695
  }
5087
5696
  }
5088
- }
5089
- dispatch(frame) {
5090
- const key = `${frame.header.channel}:${frame.header.corr}`;
5697
+ const key = pendingKey(handle, frame.header.corr);
5091
5698
  const pending = this.pending.get(key);
5092
5699
  if (pending) {
5700
+ if (pending.acceptFrame && !pending.acceptFrame(frame))
5701
+ return;
5093
5702
  switch (frame.header.ty) {
5094
5703
  case FrameType.Push:
5095
5704
  case FrameType.StreamData:
@@ -5106,15 +5715,22 @@ class SubcClient {
5106
5715
  return;
5107
5716
  }
5108
5717
  }
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);
5718
+ const late = this.lateResponses.get(key);
5719
+ if (late && (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error)) {
5720
+ this.lateResponses.delete(key);
5721
+ late(frame);
5112
5722
  return;
5113
5723
  }
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() ?? "?");
5724
+ if (frame.header.ty === FrameType.Goodbye && handle) {
5725
+ this.failHandle(handle, new SubcError("route closed by subc (GOODBYE)"));
5726
+ if (this.liveRoutes.get(handle.channel) === handle)
5727
+ this.liveRoutes.delete(handle.channel);
5728
+ this.evictRouteHandle(handle);
5116
5729
  return;
5117
5730
  }
5731
+ if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error || frame.header.ty === FrameType.StreamEnd) {
5732
+ 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() ?? "?");
5733
+ }
5118
5734
  }
5119
5735
  settle(key, pending, run) {
5120
5736
  if (this.pending.get(key) !== pending)
@@ -5137,18 +5753,16 @@ class SubcClient {
5137
5753
  return new SubcError(Buffer.from(frame.body).toString("utf8") || "subc error");
5138
5754
  }
5139
5755
  }
5140
- evictRouteChannel(channel) {
5756
+ evictRouteHandle(handle) {
5141
5757
  for (const cached of this.routes.values()) {
5142
- if (cached.channel === channel && cached.generation === this.generation) {
5143
- cached.channel = null;
5144
- }
5758
+ if (cached.handle && sameRouteHandle(cached.handle, handle))
5759
+ cached.handle = null;
5145
5760
  }
5146
5761
  }
5147
- failChannel(channel, err) {
5762
+ failHandle(handle, error2) {
5148
5763
  for (const [key, pending] of this.pending) {
5149
- if (pending.channel === channel) {
5150
- this.rejectPending(key, pending, err);
5151
- }
5764
+ if (pending.handle && sameRouteHandle(pending.handle, handle))
5765
+ this.rejectPending(key, pending, error2);
5152
5766
  }
5153
5767
  }
5154
5768
  fail(err) {
@@ -5176,6 +5790,44 @@ class SubcClient {
5176
5790
  return this.notSentCallError(message, cause);
5177
5791
  return this.terminalCallError(message, cause);
5178
5792
  }
5793
+ get droppedIngressFrames() {
5794
+ return this.ingressEpochDropCount;
5795
+ }
5796
+ installRoute(channel, epoch) {
5797
+ const handle = createRouteHandle(channel, epoch, this.connectionToken);
5798
+ this.liveRoutes.set(channel, handle);
5799
+ return handle;
5800
+ }
5801
+ isLiveHandle(handle) {
5802
+ return belongsToConnection(handle, this.connectionToken) && this.liveRoutes.get(handle.channel) === handle;
5803
+ }
5804
+ assertLiveConnection(handle) {
5805
+ if (!belongsToConnection(handle, this.connectionToken))
5806
+ throw new StaleRouteHandleError(handle);
5807
+ }
5808
+ assertLiveHandle(handle) {
5809
+ if (!this.isLiveHandle(handle))
5810
+ throw new StaleRouteHandleError(handle);
5811
+ }
5812
+ allocateCorr() {
5813
+ const maximum = 0xffffffffffffffffn;
5814
+ if (this.nextCorr > maximum) {
5815
+ const error2 = new SubcError("channel-0 correlation id allocator exhausted", "corr_exhausted");
5816
+ this.fail(error2);
5817
+ this.sock.close();
5818
+ this.scheduleReconnectAfterDrop(error2);
5819
+ throw error2;
5820
+ }
5821
+ const corr = this.nextCorr;
5822
+ this.nextCorr += 1n;
5823
+ return corr;
5824
+ }
5825
+ closeConnectionAfterCleanupFailure() {
5826
+ const error2 = new SubcError("late route cleanup could not be queued", "late_route_cleanup_failed");
5827
+ this.fail(error2);
5828
+ this.sock.close();
5829
+ this.scheduleReconnectAfterDrop(error2);
5830
+ }
5179
5831
  encode(value) {
5180
5832
  return new Uint8Array(Buffer.from(JSON.stringify(value), "utf8"));
5181
5833
  }
@@ -5245,11 +5897,15 @@ function causeMessage(cause) {
5245
5897
  return "";
5246
5898
  return `: ${cause instanceof Error ? cause.message : String(cause)}`;
5247
5899
  }
5900
+ function pendingKey(handle, corr) {
5901
+ return handle ? `${handle.channel}:${handle.epoch}:${corr}` : `0:0:${corr}`;
5902
+ }
5248
5903
  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
5904
  var init_client = __esm(() => {
5250
5905
  init_auth();
5251
5906
  init_connection_file();
5252
5907
  init_envelope();
5908
+ init_route_handle();
5253
5909
  init_socket();
5254
5910
  debug = debuglog("subc-client");
5255
5911
  EMPTY_BODY = new Uint8Array(0);
@@ -5279,7 +5935,7 @@ var init_client = __esm(() => {
5279
5935
  };
5280
5936
  });
5281
5937
 
5282
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/provider.js
5938
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/provider.js
5283
5939
  import { Buffer as Buffer2 } from "node:buffer";
5284
5940
 
5285
5941
  class AsyncPermitPool {
@@ -5328,6 +5984,11 @@ class SubcProvider {
5328
5984
  closeStarted = false;
5329
5985
  closedErr = null;
5330
5986
  inflight = new Map;
5987
+ pending = new Map;
5988
+ liveRoutes = new Map;
5989
+ connectionToken = newConnectionToken();
5990
+ nextCorr = 1n;
5991
+ ingressEpochDropCount = 0;
5331
5992
  requestGate = new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY);
5332
5993
  reconnecting = null;
5333
5994
  generation = 1;
@@ -5347,12 +6008,55 @@ class SubcProvider {
5347
6008
  this.readLoop(sock, this.generation);
5348
6009
  this.enqueueConnectionState({ state: "connected", epoch: this.connectionEpoch });
5349
6010
  }
6011
+ get droppedIngressFrames() {
6012
+ return this.ingressEpochDropCount;
6013
+ }
5350
6014
  get conn() {
5351
6015
  return this.currentConn;
5352
6016
  }
5353
6017
  currentEpoch() {
5354
6018
  return this.connectionEpoch;
5355
6019
  }
6020
+ async request(handle, body, opts = {}) {
6021
+ this.assertLiveHandle(handle);
6022
+ const corr = this.allocateCorr();
6023
+ const key = routeKey(handle, corr);
6024
+ const timeoutMs = opts.timeoutMs ?? WRITE_TIMEOUT_MS;
6025
+ const frame = buildFrame(FrameType.Request, buildFlags(false, opts.priority ?? Priority.Interactive, false, opts.admissionClass ?? AdmissionClass.Normal), handle.channel, handle.epoch, corr, body);
6026
+ return await new Promise((resolve7, reject) => {
6027
+ const timer = setTimeout(() => {
6028
+ if (this.pending.delete(key))
6029
+ reject(new SubcProviderError("reverse request timed out", "request_timeout"));
6030
+ }, timeoutMs);
6031
+ this.pending.set(key, {
6032
+ resolve: (response) => resolve7(response.body),
6033
+ reject,
6034
+ timer
6035
+ });
6036
+ this.sendOn(this.sock, this.generation, frame).catch((error2) => {
6037
+ const pending = this.pending.get(key);
6038
+ if (!pending)
6039
+ return;
6040
+ this.pending.delete(key);
6041
+ clearTimeout(pending.timer);
6042
+ reject(error2 instanceof Error ? error2 : new SubcProviderError(String(error2)));
6043
+ });
6044
+ });
6045
+ }
6046
+ async push(handle, body, opts = {}) {
6047
+ this.assertLiveHandle(handle);
6048
+ 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));
6049
+ }
6050
+ cancel(handle, corr) {
6051
+ this.assertLiveHandle(handle);
6052
+ this.sendOn(this.sock, this.generation, buildFrame(FrameType.Cancel, controlFlags(), handle.channel, handle.epoch, corr, new Uint8Array(0)));
6053
+ }
6054
+ closeRoute(handle) {
6055
+ this.assertLiveHandle(handle);
6056
+ this.liveRoutes.delete(handle.channel);
6057
+ this.abortHandle(handle);
6058
+ this.sendOn(this.sock, this.generation, buildFrame(FrameType.Goodbye, controlFlags(), handle.channel, handle.epoch, 0n, new Uint8Array(0)));
6059
+ }
5356
6060
  static async connect(opts) {
5357
6061
  if (opts.manifest.protocol_ver !== PROTOCOL_VERSION) {
5358
6062
  throw new SubcProviderError(`manifest protocol_ver ${opts.manifest.protocol_ver} does not match client protocol ${PROTOCOL_VERSION}`, "invalid_manifest");
@@ -5367,7 +6071,7 @@ class SubcProvider {
5367
6071
  this.cancelRestoredDebounce();
5368
6072
  const sock = this.sock;
5369
6073
  try {
5370
- await sendFrame(sock, buildFrame(FrameType.Goodbye, controlFlags(), 0, 0n, new Uint8Array(0)));
6074
+ await sendFrame(sock, buildFrame(FrameType.Goodbye, controlFlags(), 0, 0, 0n, new Uint8Array(0)));
5371
6075
  } catch {} finally {
5372
6076
  sock.close();
5373
6077
  this.finishClosed();
@@ -5375,12 +6079,13 @@ class SubcProvider {
5375
6079
  }
5376
6080
  await this.closed;
5377
6081
  }
5378
- static async openConnection(opts) {
6082
+ static async openConnection(opts, onSocket) {
5379
6083
  const conn = await readConnectionFile(opts.connectionFile);
5380
6084
  const deadline = Date.now() + (opts.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS2);
5381
6085
  const endpoint = conn.endpoints[0];
5382
6086
  const sock = await SubcSocket.connect(endpoint.host, endpoint.port, deadline);
5383
6087
  try {
6088
+ onSocket?.(sock);
5384
6089
  await authenticateClient(sock, conn, deadline);
5385
6090
  await sendFrame(sock, buildHelloFrame(opts));
5386
6091
  const ack = await expectHelloAck(sock, deadline);
@@ -5393,19 +6098,17 @@ class SubcProvider {
5393
6098
  async readLoop(sock, generation) {
5394
6099
  try {
5395
6100
  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);
6101
+ const frame = await sock.readFrame(Number.POSITIVE_INFINITY, { afterHeaderMs: BODY_READ_TIMEOUT_MS2 });
6102
+ const keepGoing = await this.dispatch(frame, sock, generation);
5400
6103
  if (!keepGoing) {
5401
6104
  if (this.sock === sock && this.generation === generation)
5402
6105
  this.closeStarted = true;
5403
6106
  break;
5404
6107
  }
5405
6108
  }
5406
- } catch (err) {
6109
+ } catch (error2) {
5407
6110
  if (this.sock === sock && this.generation === generation && !this.closeStarted) {
5408
- this.handleUnexpectedDrop(sock, generation, err instanceof Error ? err : new SubcProviderError(String(err)));
6111
+ this.handleUnexpectedDrop(sock, generation, error2 instanceof Error ? error2 : new SubcProviderError(String(error2)));
5409
6112
  return;
5410
6113
  }
5411
6114
  } finally {
@@ -5417,28 +6120,58 @@ class SubcProvider {
5417
6120
  }
5418
6121
  }
5419
6122
  async dispatch(frame, sock, generation) {
6123
+ let handle = null;
6124
+ if (frame.header.channel !== 0) {
6125
+ handle = this.liveRoutes.get(frame.header.channel) ?? null;
6126
+ if (!handle || handle.epoch !== frame.header.epoch) {
6127
+ this.ingressEpochDropCount += 1;
6128
+ return true;
6129
+ }
6130
+ }
6131
+ if (handle) {
6132
+ const pendingKey2 = routeKey(handle, frame.header.corr);
6133
+ const pending = this.pending.get(pendingKey2);
6134
+ if (pending) {
6135
+ if (frame.header.ty === FrameType.Push || frame.header.ty === FrameType.StreamData)
6136
+ return true;
6137
+ if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.StreamEnd) {
6138
+ this.pending.delete(pendingKey2);
6139
+ clearTimeout(pending.timer);
6140
+ pending.resolve(frame);
6141
+ return true;
6142
+ }
6143
+ if (frame.header.ty === FrameType.Error) {
6144
+ this.pending.delete(pendingKey2);
6145
+ clearTimeout(pending.timer);
6146
+ pending.reject(providerErrorFromFrame(frame));
6147
+ return true;
6148
+ }
6149
+ }
6150
+ }
5420
6151
  switch (frame.header.ty) {
5421
6152
  case FrameType.Ping:
5422
6153
  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)));
6154
+ await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Pong, frame.header.flags, 0, 0, frame.header.corr, new Uint8Array(0)));
5424
6155
  }
5425
6156
  return true;
5426
6157
  case FrameType.Goodbye:
5427
- if (frame.header.channel === 0)
6158
+ if (!handle)
5428
6159
  return false;
5429
- this.abortChannel(generation, frame.header.channel);
5430
- await this.opts.onRouteGone?.(frame.header.channel);
6160
+ this.liveRoutes.delete(handle.channel);
6161
+ this.abortHandle(handle);
6162
+ await this.opts.onRouteGone?.(handle);
5431
6163
  return true;
5432
6164
  case FrameType.Cancel:
5433
- this.inflight.get(routeKey(generation, frame.header.channel, frame.header.corr))?.abort();
6165
+ if (handle)
6166
+ this.inflight.get(routeKey(handle, frame.header.corr))?.abort();
5434
6167
  return true;
5435
6168
  case FrameType.Request:
5436
6169
  if (frame.header.channel === 0) {
5437
6170
  await this.handleControlRequest(frame, sock, generation);
5438
- } else {
5439
- this.handleDataRequest(frame, sock, generation).catch((err) => {
6171
+ } else if (handle) {
6172
+ this.handleDataRequest(frame, handle, sock, generation).catch((error2) => {
5440
6173
  if (!this.closeStarted && this.sock === sock && this.generation === generation) {
5441
- console.warn("SubcProvider handler failed after its request was dispatched", err);
6174
+ console.warn("SubcProvider handler failed after its request was dispatched", error2);
5442
6175
  }
5443
6176
  });
5444
6177
  }
@@ -5447,19 +6180,28 @@ class SubcProvider {
5447
6180
  return true;
5448
6181
  }
5449
6182
  }
5450
- abortChannel(generation, channel) {
5451
- const prefix = `${generation}:${channel}:`;
6183
+ abortHandle(handle) {
6184
+ const prefix = `${handle.channel}:${handle.epoch}:`;
5452
6185
  for (const [key, controller] of this.inflight) {
5453
6186
  if (key.startsWith(prefix))
5454
6187
  controller.abort();
5455
6188
  }
6189
+ for (const [key, pending] of this.pending) {
6190
+ if (!key.startsWith(prefix))
6191
+ continue;
6192
+ this.pending.delete(key);
6193
+ clearTimeout(pending.timer);
6194
+ pending.reject(new StaleRouteHandleError(handle));
6195
+ }
5456
6196
  }
5457
- abortGeneration(generation) {
5458
- const prefix = `${generation}:`;
5459
- for (const [key, controller] of this.inflight) {
5460
- if (key.startsWith(prefix))
5461
- controller.abort();
6197
+ abortGeneration(_generation) {
6198
+ this.abortAllInflight();
6199
+ for (const [key, pending] of this.pending) {
6200
+ this.pending.delete(key);
6201
+ clearTimeout(pending.timer);
6202
+ pending.reject(new SubcProviderError("provider connection dropped", "connection_dropped"));
5462
6203
  }
6204
+ this.liveRoutes.clear();
5463
6205
  }
5464
6206
  abortAllInflight() {
5465
6207
  for (const controller of this.inflight.values())
@@ -5468,9 +6210,9 @@ class SubcProvider {
5468
6210
  async handleControlRequest(frame, sock, generation) {
5469
6211
  const request = parseJson(frame.body);
5470
6212
  if (request.op === HEALTH_CHECK_OP) {
5471
- this.handleHealthRequest(frame, sock, generation).catch((err) => {
6213
+ this.handleHealthRequest(frame, sock, generation).catch((error2) => {
5472
6214
  if (!this.closeStarted && this.sock === sock && this.generation === generation) {
5473
- console.warn("SubcProvider health handler failed after its request was dispatched", err);
6215
+ console.warn("SubcProvider health handler failed after its request was dispatched", error2);
5474
6216
  }
5475
6217
  });
5476
6218
  return;
@@ -5478,47 +6220,93 @@ class SubcProvider {
5478
6220
  if (request.op !== "route.bind") {
5479
6221
  throw new SubcProviderError(`unsupported module control request ${request.op ?? "<missing op>"}`);
5480
6222
  }
6223
+ const boundChannel = numberField(request.route_channel, "route_channel");
6224
+ const boundEpoch = numberField(request.epoch, "epoch");
6225
+ const stale = this.liveRoutes.get(boundChannel);
6226
+ if (stale) {
6227
+ if (boundEpoch <= stale.epoch) {
6228
+ await this.sendError(frame, "route_rejected", `route.bind epoch ${boundEpoch} does not supersede installed epoch ${stale.epoch} on channel ${boundChannel}`, controlFlags(), sock, generation);
6229
+ return;
6230
+ }
6231
+ this.liveRoutes.delete(stale.channel);
6232
+ this.abortHandle(stale);
6233
+ await this.opts.onRouteGone?.(stale);
6234
+ }
6235
+ const tentative = createRouteHandle(boundChannel, boundEpoch, this.connectionToken);
5481
6236
  const bindRequest = {
5482
- route_channel: numberField(request.route_channel, "route_channel"),
6237
+ handle: tentative,
5483
6238
  target: request.target,
5484
6239
  identity: request.identity,
5485
- principal: request.principal
6240
+ principal: request.principal,
6241
+ consumer_capabilities: request.consumer_capabilities
5486
6242
  };
5487
- const decision = await this.opts.onBind?.(bindRequest);
6243
+ let decision;
6244
+ try {
6245
+ decision = await this.opts.onBind?.(bindRequest);
6246
+ } catch (error2) {
6247
+ try {
6248
+ await this.sendError(frame, "route_rejected", error2 instanceof Error ? error2.message : String(error2), controlFlags(), sock, generation);
6249
+ } finally {
6250
+ await this.opts.onRouteGone?.(tentative);
6251
+ }
6252
+ return;
6253
+ }
5488
6254
  const rejection = bindRejection(decision);
5489
6255
  if (rejection) {
5490
- await this.sendError(frame, rejection.code, rejection.message, controlFlags(), sock, generation);
6256
+ try {
6257
+ await this.sendError(frame, rejection.code, rejection.message, controlFlags(), sock, generation);
6258
+ } finally {
6259
+ await this.opts.onRouteGone?.(tentative);
6260
+ }
6261
+ return;
6262
+ }
6263
+ try {
6264
+ await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Response, controlFlags(), 0, 0, frame.header.corr, encodeJson({ op: "route.bind" })));
6265
+ } catch (error2) {
6266
+ await this.opts.onRouteGone?.(tentative);
6267
+ throw error2;
6268
+ }
6269
+ if (this.sock !== sock || this.generation !== generation || this.closeStarted || this.closedErr) {
6270
+ await this.opts.onRouteGone?.(tentative);
5491
6271
  return;
5492
6272
  }
5493
- await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Response, controlFlags(), 0, frame.header.corr, encodeJson({ op: "route.bind" })));
6273
+ this.liveRoutes.set(tentative.channel, tentative);
6274
+ await this.opts.onBound?.(tentative);
5494
6275
  }
5495
- async handleDataRequest(frame, sock, generation) {
5496
- const { channel, corr, ver } = frame.header;
5497
- const key = routeKey(generation, channel, corr);
6276
+ async handleDataRequest(frame, handle, sock, generation) {
6277
+ const { corr, ver } = frame.header;
6278
+ const key = routeKey(handle, corr);
5498
6279
  const controller = new AbortController;
5499
6280
  this.inflight.set(key, controller);
5500
- const dataFlags = buildFlags(false, Priority.Interactive, false);
5501
- const ctx = {
6281
+ const context = {
6282
+ handle,
5502
6283
  signal: controller.signal,
5503
6284
  currentEpoch: () => this.connectionEpoch,
5504
- emit: async (eventBody) => {
6285
+ emit: async (eventBody, options = {}) => {
6286
+ this.assertLiveHandle(handle);
5505
6287
  if (controller.signal.aborted)
5506
6288
  return;
5507
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamData, dataFlags, channel, corr, eventBody));
6289
+ 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
6290
  }
5509
6291
  };
5510
6292
  const releasePermit = await (this.requestGate ?? new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY)).acquire();
6293
+ const dataFlags = buildFlags(false, Priority.Interactive, false);
5511
6294
  try {
5512
- const body = await this.opts.handler(channel, frame.body, ctx);
6295
+ const body = await this.opts.handler(handle, frame.body, context);
6296
+ if (controller.signal.aborted)
6297
+ return;
6298
+ this.assertLiveHandle(handle);
5513
6299
  if (body === undefined) {
5514
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamEnd, dataFlags, channel, corr, new Uint8Array(0)));
6300
+ await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamEnd, dataFlags, handle.channel, handle.epoch, corr, new Uint8Array(0)));
5515
6301
  } else if (body instanceof Uint8Array) {
5516
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, dataFlags, channel, corr, body));
6302
+ await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, dataFlags, handle.channel, handle.epoch, corr, body));
5517
6303
  } else {
5518
6304
  throw new SubcProviderError("provider handler must return a Uint8Array or void", "invalid_handler_response");
5519
6305
  }
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);
6306
+ } catch (error2) {
6307
+ if (error2 instanceof StaleRouteHandleError || controller.signal.aborted)
6308
+ return;
6309
+ await this.sendError(frame, error2 instanceof SubcProviderError && error2.code ? error2.code : "handler_error", error2 instanceof Error ? error2.message : String(error2), dataFlags, sock, generation);
5522
6310
  } finally {
5523
6311
  releasePermit();
5524
6312
  if (this.inflight.get(key) === controller)
@@ -5526,8 +6314,8 @@ class SubcProvider {
5526
6314
  }
5527
6315
  }
5528
6316
  async handleHealthRequest(frame, sock, generation) {
5529
- const { channel, corr, ver } = frame.header;
5530
- const key = routeKey(generation, channel, corr);
6317
+ const { corr, ver } = frame.header;
6318
+ const key = `control:${generation}:${corr}`;
5531
6319
  const controller = new AbortController;
5532
6320
  this.inflight.set(key, controller);
5533
6321
  const releasePermit = await (this.requestGate ?? new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY)).acquire();
@@ -5535,14 +6323,14 @@ class SubcProvider {
5535
6323
  if (controller.signal.aborted)
5536
6324
  return;
5537
6325
  const report = await this.opts.health();
5538
- await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, controlFlags(), channel, corr, encodeJson({
6326
+ await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, controlFlags(), 0, 0, corr, encodeJson({
5539
6327
  op: HEALTH_CHECK_OP,
5540
6328
  status: report.status,
5541
6329
  ...report.detail === undefined ? {} : { detail: report.detail },
5542
6330
  ...report.metrics === undefined ? {} : { metrics: report.metrics }
5543
6331
  })));
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);
6332
+ } catch (error2) {
6333
+ await this.sendError(frame, error2 instanceof SubcProviderError && error2.code ? error2.code : "health_error", error2 instanceof Error ? error2.message : String(error2), controlFlags(), sock, generation);
5546
6334
  } finally {
5547
6335
  releasePermit();
5548
6336
  if (this.inflight.get(key) === controller)
@@ -5550,7 +6338,7 @@ class SubcProvider {
5550
6338
  }
5551
6339
  }
5552
6340
  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 })));
6341
+ 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
6342
  }
5555
6343
  async sendOn(sock, generation, frame) {
5556
6344
  if (this.sock !== sock || this.generation !== generation || this.closeStarted || this.closedErr)
@@ -5558,42 +6346,79 @@ class SubcProvider {
5558
6346
  await sendFrame(sock, frame);
5559
6347
  }
5560
6348
  handleUnexpectedDrop(sock, generation, cause) {
6349
+ if (this.closeStarted || this.sock !== sock || this.generation !== generation)
6350
+ return;
5561
6351
  this.cancelRestoredDebounce();
5562
6352
  this.abortGeneration(generation);
5563
6353
  this.generation += 1;
5564
6354
  sock.close();
5565
- this.enqueueConnectionState({ state: "down", cause });
5566
- this.scheduleReconnectAfterDrop(cause);
6355
+ this.scheduleReconnectAfterDrop(cause, this.generation, sock);
5567
6356
  }
5568
- scheduleReconnectAfterDrop(trigger) {
5569
- if (this.closeStarted || this.reconnecting)
6357
+ scheduleReconnectAfterDrop(cause, generation, droppedSocket) {
6358
+ if (this.closeStarted)
5570
6359
  return;
5571
- const promise = this.reconnectWithRetry(trigger).catch((err) => {
5572
- if (!this.closeStarted)
6360
+ const previous = this.reconnecting;
6361
+ if (previous) {
6362
+ if (!this.shouldSupersedeReconnect(previous, generation, droppedSocket))
6363
+ return;
6364
+ previous.superseded = true;
6365
+ previous.socket?.close();
6366
+ }
6367
+ const cycle = {
6368
+ generation,
6369
+ socket: null,
6370
+ socketDied: false,
6371
+ superseded: false
6372
+ };
6373
+ this.reconnecting = cycle;
6374
+ this.enqueueConnectionState({ state: "down", cause });
6375
+ this.reconnectWithRetry(cycle).catch((err) => {
6376
+ if (this.isCurrentReconnect(cycle) && !this.closeStarted) {
5573
6377
  this.failFatal(err instanceof Error ? err : new SubcProviderError(String(err)));
6378
+ }
5574
6379
  }).finally(() => {
5575
- if (this.reconnecting === promise)
6380
+ if (this.isCurrentReconnect(cycle))
5576
6381
  this.reconnecting = null;
5577
6382
  });
5578
- this.reconnecting = promise;
5579
6383
  }
5580
- async reconnectWithRetry(_trigger) {
6384
+ async reconnectWithRetry(cycle) {
5581
6385
  let attempt = 0;
5582
6386
  let delay = this.opts.reconnectBackoff.baseMs;
5583
6387
  for (;; ) {
6388
+ if (!this.isCurrentReconnect(cycle))
6389
+ return;
5584
6390
  if (this.closeStarted)
5585
6391
  throw new SubcProviderError("provider closed");
6392
+ cycle.socket = null;
6393
+ cycle.socketDied = false;
5586
6394
  attempt += 1;
5587
- this.enqueueConnectionState({ state: "reconnecting", attempt });
6395
+ this.enqueueReconnectState(cycle, attempt);
5588
6396
  try {
5589
- const opened = await SubcProvider.openConnection(this.opts);
5590
- if (this.closeStarted) {
6397
+ const opened = await SubcProvider.openConnection(this.opts, (sock) => {
6398
+ if (!this.isCurrentReconnect(cycle)) {
6399
+ sock.close();
6400
+ return;
6401
+ }
6402
+ cycle.socket = sock;
6403
+ });
6404
+ if (!this.isCurrentReconnect(cycle) || this.closeStarted) {
5591
6405
  opened.sock.close();
5592
- throw new SubcProviderError("provider closed");
6406
+ if (this.closeStarted)
6407
+ throw new SubcProviderError("provider closed");
6408
+ return;
5593
6409
  }
5594
- this.replaceConnection(opened);
6410
+ const epoch = this.replaceConnection(opened, cycle.generation);
6411
+ this.reconnecting = null;
6412
+ if (this.reconnecting !== null) {
6413
+ throw new SubcProviderError("reconnect state must clear before restored", "reconnect_state");
6414
+ }
6415
+ this.scheduleRestored(cycle.generation, epoch);
5595
6416
  return;
5596
6417
  } catch (err) {
6418
+ if (!this.isCurrentReconnect(cycle))
6419
+ return;
6420
+ if (cycle.socket)
6421
+ cycle.socketDied = true;
5597
6422
  if (this.closeStarted)
5598
6423
  throw err;
5599
6424
  if (!isProviderReconnectTransient(err))
@@ -5603,16 +6428,29 @@ class SubcProvider {
5603
6428
  }
5604
6429
  }
5605
6430
  }
5606
- replaceConnection(opened) {
6431
+ isCurrentReconnect(cycle) {
6432
+ return !cycle.superseded && this.reconnecting === cycle && this.generation === cycle.generation;
6433
+ }
6434
+ shouldSupersedeReconnect(cycle, generation, droppedSocket) {
6435
+ return cycle.generation < generation || cycle.socketDied || cycle.socket === droppedSocket;
6436
+ }
6437
+ enqueueReconnectState(cycle, attempt) {
6438
+ if (!this.isCurrentReconnect(cycle))
6439
+ return;
6440
+ this.enqueueConnectionState({ state: "reconnecting", attempt }, cycle.generation, cycle);
6441
+ }
6442
+ replaceConnection(opened, generation) {
5607
6443
  this.sock.close();
5608
6444
  this.sock = opened.sock;
5609
6445
  this.currentConn = opened.conn;
5610
6446
  this.storage = opened.ack.storage;
5611
6447
  this.closedErr = null;
5612
6448
  this.connectionEpoch += 1;
5613
- const generation = this.generation;
6449
+ this.connectionToken = newConnectionToken();
6450
+ this.liveRoutes.clear();
6451
+ this.nextCorr = 1n;
5614
6452
  this.readLoop(opened.sock, generation);
5615
- this.scheduleRestored(generation, this.connectionEpoch);
6453
+ return this.connectionEpoch;
5616
6454
  }
5617
6455
  scheduleRestored(generation, epoch) {
5618
6456
  if (!this.opts.onConnectionState)
@@ -5620,7 +6458,7 @@ class SubcProvider {
5620
6458
  const token = ++this.restoredDebounceToken;
5621
6459
  this.opts.sleep(this.opts.restoredDebounceMs).then(() => {
5622
6460
  if (token === this.restoredDebounceToken && !this.closeStarted && this.sock && this.generation === generation && this.connectionEpoch === epoch) {
5623
- this.enqueueConnectionState({ state: "restored", epoch });
6461
+ this.enqueueConnectionState({ state: "restored", epoch }, generation);
5624
6462
  }
5625
6463
  }).catch((err) => {
5626
6464
  if (token === this.restoredDebounceToken && !this.closeStarted) {
@@ -5631,10 +6469,10 @@ class SubcProvider {
5631
6469
  cancelRestoredDebounce() {
5632
6470
  this.restoredDebounceToken += 1;
5633
6471
  }
5634
- enqueueConnectionState(event) {
6472
+ enqueueConnectionState(event, generation, reconnect) {
5635
6473
  if (!this.opts.onConnectionState)
5636
6474
  return;
5637
- this.stateQueue.push(event);
6475
+ this.stateQueue.push({ event, generation, reconnect });
5638
6476
  if (!this.drainingStateQueue)
5639
6477
  this.drainConnectionStateQueue();
5640
6478
  }
@@ -5644,7 +6482,12 @@ class SubcProvider {
5644
6482
  this.drainingStateQueue = true;
5645
6483
  try {
5646
6484
  while (this.stateQueue.length > 0) {
5647
- const event = this.stateQueue[0];
6485
+ const queued = this.stateQueue[0];
6486
+ if (this.closeStarted || queued.generation !== undefined && queued.generation !== this.generation || queued.reconnect?.superseded) {
6487
+ this.stateQueue.shift();
6488
+ continue;
6489
+ }
6490
+ const { event } = queued;
5648
6491
  try {
5649
6492
  await this.opts.onConnectionState?.(event);
5650
6493
  this.stateQueue.shift();
@@ -5664,6 +6507,24 @@ class SubcProvider {
5664
6507
  this.drainConnectionStateQueue();
5665
6508
  }
5666
6509
  }
6510
+ isLiveHandle(handle) {
6511
+ return belongsToConnection(handle, this.connectionToken) && this.liveRoutes.get(handle.channel) === handle;
6512
+ }
6513
+ assertLiveHandle(handle) {
6514
+ if (!this.isLiveHandle(handle))
6515
+ throw new StaleRouteHandleError(handle);
6516
+ }
6517
+ allocateCorr() {
6518
+ const maximum = 0xffffffffffffffffn;
6519
+ if (this.nextCorr > maximum) {
6520
+ const error2 = new SubcProviderError("channel-0 correlation id allocator exhausted", "corr_exhausted");
6521
+ this.handleUnexpectedDrop(this.sock, this.generation, error2);
6522
+ throw error2;
6523
+ }
6524
+ const corr = this.nextCorr;
6525
+ this.nextCorr += 1n;
6526
+ return corr;
6527
+ }
5667
6528
  failFatal(err) {
5668
6529
  if (!this.closedErr)
5669
6530
  this.closedErr = err;
@@ -5677,8 +6538,16 @@ class SubcProvider {
5677
6538
  this.resolveClosed();
5678
6539
  }
5679
6540
  }
5680
- function routeKey(generation, channel, corr) {
5681
- return `${generation}:${channel}:${corr}`;
6541
+ function routeKey(handle, corr) {
6542
+ return `${handle.channel}:${handle.epoch}:${corr}`;
6543
+ }
6544
+ function providerErrorFromFrame(frame) {
6545
+ try {
6546
+ const body = parseJson(frame.body);
6547
+ return new SubcProviderError(body.message ?? "subc error", body.code);
6548
+ } catch {
6549
+ return new SubcProviderError(Buffer2.from(frame.body).toString("utf8") || "subc error");
6550
+ }
5682
6551
  }
5683
6552
  function launchNonce(opts) {
5684
6553
  const nonce = opts.launchNonce ?? process.env[SUBC_LAUNCH_NONCE_ENV2];
@@ -5693,6 +6562,7 @@ function normalizeProviderConnectOptions(opts) {
5693
6562
  handshakeTimeoutMs: opts.handshakeTimeoutMs,
5694
6563
  controlOps: opts.controlOps,
5695
6564
  onBind: opts.onBind,
6565
+ onBound: opts.onBound,
5696
6566
  onRouteGone: opts.onRouteGone,
5697
6567
  reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
5698
6568
  sleep: opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))),
@@ -5710,7 +6580,7 @@ function normalizedControlOps(controlOps) {
5710
6580
  }
5711
6581
  function buildHelloFrame(opts) {
5712
6582
  const nonce = launchNonce(opts);
5713
- return buildFrame(FrameType.Hello, controlFlags(), 0, HELLO_CORR, encodeJson({
6583
+ return buildFrame(FrameType.Hello, controlFlags(), 0, 0, HELLO_CORR, encodeJson({
5714
6584
  manifest: normalizeManifest(opts.manifest),
5715
6585
  protocol_ver: PROTOCOL_VERSION,
5716
6586
  control_ops: normalizedControlOps(opts.controlOps),
@@ -5749,14 +6619,17 @@ async function sendFrame(sock, frame) {
5749
6619
  await sock.write(encodeFrame(frame), Date.now() + WRITE_TIMEOUT_MS);
5750
6620
  }
5751
6621
  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);
6622
+ const frame = await sock.readFrame(deadline, deadline);
6623
+ switch (frame.header.ty) {
6624
+ case FrameType.HelloAck: {
6625
+ const ack = parseJson(frame.body);
6626
+ if (ack.negotiated_ver !== PROTOCOL_VERSION) {
6627
+ throw new SubcProviderError(`subc negotiated protocol ${ack.negotiated_ver}; expected exactly ${PROTOCOL_VERSION}`, "unsupported_version");
6628
+ }
6629
+ return ack;
6630
+ }
5758
6631
  case FrameType.Error: {
5759
- const error2 = parseJson(body);
6632
+ const error2 = parseJson(frame.body);
5760
6633
  throw new SubcProviderError(`subc rejected HELLO: ${error2.code ?? "unknown"} — ${error2.message ?? "subc error"}`, error2.code);
5761
6634
  }
5762
6635
  default:
@@ -5903,6 +6776,7 @@ var init_provider = __esm(() => {
5903
6776
  init_client();
5904
6777
  init_connection_file();
5905
6778
  init_envelope();
6779
+ init_route_handle();
5906
6780
  init_socket();
5907
6781
  SubcProviderError = class SubcProviderError extends Error {
5908
6782
  code;
@@ -5913,9 +6787,10 @@ var init_provider = __esm(() => {
5913
6787
  };
5914
6788
  });
5915
6789
 
5916
- // ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/index.js
6790
+ // ../../node_modules/.bun/@cortexkit+subc-client@0.5.0/node_modules/@cortexkit/subc-client/dist/index.js
5917
6791
  var init_dist = __esm(() => {
5918
6792
  init_client();
6793
+ init_route_handle();
5919
6794
  init_connection_file();
5920
6795
  init_envelope();
5921
6796
  init_auth();
@@ -5932,15 +6807,17 @@ class BgSubscription {
5932
6807
  identity;
5933
6808
  acquireClient;
5934
6809
  dropClient;
6810
+ consumerIdentity;
5935
6811
  onNudge;
5936
6812
  sleep;
5937
6813
  stopped = false;
5938
6814
  current = null;
5939
6815
  loop;
5940
- constructor(identity, acquireClient, dropClient, onNudge, sleep2) {
6816
+ constructor(identity, acquireClient, dropClient, consumerIdentity, onNudge, sleep2) {
5941
6817
  this.identity = identity;
5942
6818
  this.acquireClient = acquireClient;
5943
6819
  this.dropClient = dropClient;
6820
+ this.consumerIdentity = consumerIdentity;
5944
6821
  this.onNudge = onNudge;
5945
6822
  this.sleep = sleep2;
5946
6823
  this.loop = this.run();
@@ -5969,9 +6846,9 @@ class BgSubscription {
5969
6846
  }
5970
6847
  if (this.stopped)
5971
6848
  return;
5972
- let channel;
6849
+ let route;
5973
6850
  try {
5974
- channel = await client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, this.identity);
6851
+ route = await client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, this.identity, { consumerIdentity: this.consumerIdentity });
5975
6852
  } catch (err) {
5976
6853
  if (isConsumerReconnectTransient(err))
5977
6854
  this.dropClient(client);
@@ -5979,12 +6856,12 @@ class BgSubscription {
5979
6856
  continue;
5980
6857
  }
5981
6858
  if (this.stopped) {
5982
- safeCloseRoute(client, channel);
6859
+ safeCloseRoute(client, route);
5983
6860
  return;
5984
6861
  }
5985
6862
  const subscribedAt = Date.now();
5986
6863
  try {
5987
- const sub = client.subscribe(channel, { op: "bg_events" }, () => {
6864
+ const sub = client.subscribe(route, { op: "bg_events" }, () => {
5988
6865
  if (!this.stopped)
5989
6866
  this.onNudge();
5990
6867
  });
@@ -6004,7 +6881,7 @@ class BgSubscription {
6004
6881
  attempt = 0;
6005
6882
  } finally {
6006
6883
  this.current = null;
6007
- safeCloseRoute(client, channel);
6884
+ safeCloseRoute(client, route);
6008
6885
  }
6009
6886
  await this.backoff(attempt++);
6010
6887
  }
@@ -6017,12 +6894,12 @@ class BgSubscription {
6017
6894
  function isRecord(value) {
6018
6895
  return typeof value === "object" && value !== null && !Array.isArray(value);
6019
6896
  }
6020
- function isUnknownChannelError(err) {
6021
- return err instanceof SubcError && err.code === "unknown_channel";
6897
+ function isRouteProvenAbsentError(err) {
6898
+ return err instanceof SubcError && err.code === "unknown_channel" || err instanceof StaleRouteHandleError;
6022
6899
  }
6023
- function safeCloseRoute(client, channel) {
6900
+ function safeCloseRoute(client, route) {
6024
6901
  try {
6025
- client.closeRouteChannel(channel).catch(() => {
6902
+ client.closeRouteChannel(route).catch(() => {
6026
6903
  return;
6027
6904
  });
6028
6905
  } catch {}
@@ -6106,6 +6983,7 @@ class SubcTransportPool {
6106
6983
  harness;
6107
6984
  connectionFile;
6108
6985
  handshakeTimeoutMs;
6986
+ consumerIdentity;
6109
6987
  connectFn;
6110
6988
  onBgEventsNudge;
6111
6989
  bgBackoffSleep;
@@ -6119,6 +6997,7 @@ class SubcTransportPool {
6119
6997
  this.connectionFile = options.connectionFile;
6120
6998
  this.harness = options.harness;
6121
6999
  this.handshakeTimeoutMs = options.handshakeTimeoutMs;
7000
+ this.consumerIdentity = options.consumerIdentity;
6122
7001
  this.connectFn = options.connect ?? ((opts) => SubcClient.connect(opts));
6123
7002
  this.onBgEventsNudge = options.onBgEventsNudge;
6124
7003
  this.bgBackoffSleep = options.bgBackoffSleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
@@ -6141,6 +7020,11 @@ class SubcTransportPool {
6141
7020
  return null;
6142
7021
  return this.transports.get(key) ?? null;
6143
7022
  }
7023
+ activeBridges() {
7024
+ if (!this.client || this.shuttingDown)
7025
+ return [];
7026
+ return [...this.transports.values()];
7027
+ }
6144
7028
  async toolCall(projectRoot, runtime, name, rawArgs = {}, options) {
6145
7029
  return this.getBridge(projectRoot).toolCall(runtime.sessionID, name, rawArgs, options);
6146
7030
  }
@@ -6171,7 +7055,7 @@ class SubcTransportPool {
6171
7055
  throw new RouteTornDownError("subc session closed");
6172
7056
  }
6173
7057
  try {
6174
- const opened = await this.routeChannel(client, identity, record);
7058
+ const opened = await this.routeHandle(client, identity, record);
6175
7059
  if (!this.isCurrentSession(key, record)) {
6176
7060
  throw new RouteTornDownError("subc session closed");
6177
7061
  }
@@ -6197,29 +7081,29 @@ class SubcTransportPool {
6197
7081
  if (isConsumerReconnectTransient(err)) {
6198
7082
  this.transportFailures = 0;
6199
7083
  this.dropClient(client);
6200
- } else if (!isUnknownChannelError(err) && ++this.transportFailures >= MAX_CONSECUTIVE_TRANSPORT_FAILURES) {
7084
+ } else if (!isRouteProvenAbsentError(err) && ++this.transportFailures >= MAX_CONSECUTIVE_TRANSPORT_FAILURES) {
6201
7085
  this.transportFailures = 0;
6202
7086
  this.dropClient(client);
6203
7087
  }
6204
7088
  }
6205
7089
  };
6206
- const requestOnRoute = async (channel2) => {
6207
- const reply = await client.request(channel2, body, { timeoutMs, onProgress });
7090
+ const requestOnRoute = async (route2) => {
7091
+ const reply = await client.request(route2, body, { timeoutMs, onProgress });
6208
7092
  if (this.isCurrentSession(key, record) && this.client === client) {
6209
7093
  this.transportFailures = 0;
6210
7094
  }
6211
7095
  this.ensureBgSubscription(identity, record);
6212
7096
  return reply;
6213
7097
  };
6214
- let { channel, entry } = await openRoute();
7098
+ let { route, entry } = await openRoute();
6215
7099
  try {
6216
- return await requestOnRoute(channel);
7100
+ return await requestOnRoute(route);
6217
7101
  } catch (err) {
6218
- if (isUnknownChannelError(err) && this.isCurrentSession(key, record) && this.client === client) {
7102
+ if (isRouteProvenAbsentError(err) && this.isCurrentSession(key, record) && this.client === client) {
6219
7103
  clearRouteEntry(entry);
6220
- ({ channel, entry } = await openRoute());
7104
+ ({ route, entry } = await openRoute());
6221
7105
  try {
6222
- return await requestOnRoute(channel);
7106
+ return await requestOnRoute(route);
6223
7107
  } catch (retryErr) {
6224
7108
  handleRequestFailure(retryErr, entry);
6225
7109
  throw retryErr;
@@ -6261,24 +7145,26 @@ class SubcTransportPool {
6261
7145
  });
6262
7146
  return this.connecting;
6263
7147
  }
6264
- async routeChannel(client, identity, record) {
7148
+ async routeHandle(client, identity, record) {
6265
7149
  const key = identityKey(identity);
6266
7150
  const existing = record.routeEntry;
6267
- if (existing?.channel != null)
6268
- return { channel: existing.channel, entry: existing };
7151
+ if (existing?.handle != null)
7152
+ return { route: existing.handle, entry: existing };
6269
7153
  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) => {
7154
+ return { route: await existing.opening, entry: existing };
7155
+ const entry = { client, opening: null, handle: null, closed: false };
7156
+ const opening = client.routeOpen({ kind: "tool_provider", module_id: AFT_MODULE_ID }, identity, {
7157
+ consumerIdentity: this.consumerIdentity
7158
+ }).then((route) => {
6273
7159
  if (!this.isCurrentSession(key, record) || record.routeEntry !== entry || entry.closed || this.client !== client) {
6274
- safeCloseRoute(client, channel);
7160
+ safeCloseRoute(client, route);
6275
7161
  if (record.routeEntry === entry)
6276
7162
  record.routeEntry = null;
6277
7163
  throw new RouteTornDownError("subc route opened after teardown");
6278
7164
  }
6279
- entry.channel = channel;
7165
+ entry.handle = route;
6280
7166
  entry.opening = null;
6281
- return channel;
7167
+ return route;
6282
7168
  }).catch((err) => {
6283
7169
  const current = this.isCurrentSession(key, record);
6284
7170
  if (record.routeEntry === entry) {
@@ -6292,7 +7178,7 @@ class SubcTransportPool {
6292
7178
  });
6293
7179
  entry.opening = opening;
6294
7180
  record.routeEntry = entry;
6295
- return { channel: await opening, entry };
7181
+ return { route: await opening, entry };
6296
7182
  }
6297
7183
  ensureBgSubscription(identity, record) {
6298
7184
  if (this.shuttingDown || !this.onBgEventsNudge)
@@ -6303,7 +7189,7 @@ class SubcTransportPool {
6303
7189
  if (record.bgSub)
6304
7190
  return;
6305
7191
  const onNudge = () => this.onBgEventsNudge?.(identity.project_root, identity.session);
6306
- const sub = new BgSubscription(identity, () => this.ensureClient(), (client) => this.dropClient(client), onNudge, this.bgBackoffSleep);
7192
+ const sub = new BgSubscription(identity, () => this.ensureClient(), (client) => this.dropClient(client), this.consumerIdentity, onNudge, this.bgBackoffSleep);
6307
7193
  record.bgSub = sub;
6308
7194
  }
6309
7195
  dropClient(client) {
@@ -6324,9 +7210,13 @@ class SubcTransportPool {
6324
7210
  }
6325
7211
  }
6326
7212
  setConfigureOverride(_key, _value) {}
7213
+ async reconfigure(_projectRoot, _overrides) {}
6327
7214
  async replaceBinary(path2) {
6328
7215
  return path2;
6329
7216
  }
7217
+ isShutdown() {
7218
+ return this.shuttingDown;
7219
+ }
6330
7220
  async shutdown() {
6331
7221
  this.shuttingDown = true;
6332
7222
  const subs = [];
@@ -6350,10 +7240,10 @@ class SubcTransportPool {
6350
7240
  this.transports.clear();
6351
7241
  await Promise.allSettled(subs.map((sub) => sub.stop()));
6352
7242
  await Promise.allSettled(entries.map(async (entry) => {
6353
- if (entry.channel == null)
7243
+ if (entry.handle == null)
6354
7244
  return;
6355
7245
  try {
6356
- await entry.client.closeRouteChannel(entry.channel);
7246
+ await entry.client.closeRouteChannel(entry.handle);
6357
7247
  } catch {}
6358
7248
  }));
6359
7249
  if (client) {
@@ -6382,9 +7272,9 @@ class SubcTransportPool {
6382
7272
  entry.closed = true;
6383
7273
  if (sub)
6384
7274
  await sub.stop();
6385
- if (entry?.channel != null) {
7275
+ if (entry?.handle != null) {
6386
7276
  try {
6387
- await entry.client.closeRouteChannel(entry.channel);
7277
+ await entry.client.closeRouteChannel(entry.handle);
6388
7278
  } catch {}
6389
7279
  }
6390
7280
  }
@@ -6485,18 +7375,25 @@ function formatReadFooter(agentSpecifiedRange, data, options) {
6485
7375
  }
6486
7376
 
6487
7377
  // ../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";
7378
+ import { homedir as homedir11 } from "node:os";
7379
+ import { isAbsolute as isAbsolute5, join as join10 } from "node:path";
6490
7380
  function resolveConnectionFilePath(raw) {
6491
7381
  const trimmed = raw.trim();
6492
7382
  if (trimmed.startsWith("~")) {
6493
- return join9(homedir10(), trimmed.slice(1).replace(/^[/\\]/, ""));
7383
+ return join10(homedir11(), trimmed.slice(1).replace(/^[/\\]/, ""));
6494
7384
  }
6495
7385
  if (isAbsolute5(trimmed))
6496
7386
  return trimmed;
6497
- return join9(homedir10(), trimmed);
7387
+ return join10(homedir11(), trimmed);
6498
7388
  }
6499
7389
  async function createAftTransportPool(opts) {
7390
+ let binaryPath = opts.binaryPath;
7391
+ const createPool = () => createConcreteAftTransportPool({ ...opts, binaryPath });
7392
+ return new RevivableTransportPool(await createPool(), createPool, (path2) => {
7393
+ binaryPath = path2;
7394
+ });
7395
+ }
7396
+ async function createConcreteAftTransportPool(opts) {
6500
7397
  const raw = opts.subcConnectionFile?.trim();
6501
7398
  if (raw && raw.length > 0) {
6502
7399
  const connectionFile = resolveConnectionFilePath(raw);
@@ -6507,6 +7404,7 @@ async function createAftTransportPool(opts) {
6507
7404
  return new SubcTransportPool({
6508
7405
  connectionFile,
6509
7406
  harness: opts.harness,
7407
+ consumerIdentity: opts.subcConsumerIdentity,
6510
7408
  onBgEventsNudge: opts.onBgEventsNudge
6511
7409
  });
6512
7410
  }
@@ -6514,6 +7412,7 @@ async function createAftTransportPool(opts) {
6514
7412
  }
6515
7413
  var init_transport_factory = __esm(() => {
6516
7414
  init_pool();
7415
+ init_revivable_transport();
6517
7416
  init_subc_transport();
6518
7417
  });
6519
7418
 
@@ -6631,6 +7530,7 @@ __export(exports_dist, {
6631
7530
  timeoutForCommand: () => timeoutForCommand,
6632
7531
  tagStderrLine: () => tagStderrLine,
6633
7532
  stripJsoncSymbols: () => stripJsoncSymbols,
7533
+ stripHarnessSpecificConfigKeys: () => stripHarnessSpecificConfigKeys,
6634
7534
  statusBarLine: () => statusBarLine,
6635
7535
  sleep: () => sleep,
6636
7536
  shouldShowAnnouncement: () => shouldShowAnnouncement,
@@ -6645,6 +7545,8 @@ __export(exports_dist, {
6645
7545
  resolveCortexKitProjectConfigPath: () => resolveCortexKitProjectConfigPath,
6646
7546
  resolveCortexKitConfigPaths: () => resolveCortexKitConfigPaths,
6647
7547
  resolveBashKillTimeout: () => resolveBashKillTimeout,
7548
+ resolveAftStorageRoot: () => resolveAftStorageRoot,
7549
+ resolveAftLogPath: () => resolveAftLogPath,
6648
7550
  repairRootScopedStorageFile: () => repairRootScopedStorageFile,
6649
7551
  readConfigTiers: () => readConfigTiers,
6650
7552
  projectRootKeyHash: () => projectRootKeyHash,
@@ -6687,6 +7589,7 @@ __export(exports_dist, {
6687
7589
  ensureOnnxRuntime: () => ensureOnnxRuntime,
6688
7590
  ensureBinary: () => ensureBinary,
6689
7591
  downloadBinary: () => downloadBinary,
7592
+ decodeFileUrl: () => decodeFileUrl,
6690
7593
  createStatusBarEmitState: () => createStatusBarEmitState,
6691
7594
  createAftTransportPool: () => createAftTransportPool,
6692
7595
  compressionSavingsPercent: () => compressionSavingsPercent,
@@ -6702,11 +7605,17 @@ __export(exports_dist, {
6702
7605
  __onnxTest__: () => __test__,
6703
7606
  SubcTransportPool: () => SubcTransportPool,
6704
7607
  STATUS_BAR_HEARTBEAT_CALLS: () => STATUS_BAR_HEARTBEAT_CALLS,
7608
+ RotatingLogSink: () => RotatingLogSink,
7609
+ RevivableTransportPool: () => RevivableTransportPool,
6705
7610
  PLATFORM_ASSET_MAP: () => PLATFORM_ASSET_MAP,
6706
7611
  PLATFORM_ARCH_MAP: () => PLATFORM_ARCH_MAP,
6707
7612
  PLAIN_CALLGRAPH_THEME: () => PLAIN_CALLGRAPH_THEME,
7613
+ PI_ONLY_KEYS: () => PI_ONLY_KEYS,
7614
+ OPENCODE_ONLY_KEYS: () => OPENCODE_ONLY_KEYS,
6708
7615
  LONG_RUNNING_COMMAND_TIMEOUT_MS: () => LONG_RUNNING_COMMAND_TIMEOUT_MS,
6709
7616
  HomeProjectRootError: () => HomeProjectRootError,
7617
+ DEFAULT_LOG_GENERATIONS: () => DEFAULT_LOG_GENERATIONS,
7618
+ DEFAULT_LOG_BYTES: () => DEFAULT_LOG_BYTES,
6710
7619
  BridgeTransportTimeoutError: () => BridgeTransportTimeoutError,
6711
7620
  BridgePool: () => BridgePool,
6712
7621
  BinaryBridge: () => BinaryBridge
@@ -6717,8 +7626,10 @@ var init_dist2 = __esm(() => {
6717
7626
  init_bridge();
6718
7627
  init_callgraph_format();
6719
7628
  init_command_timeouts();
7629
+ init_config_keys();
6720
7630
  init_config_tiers();
6721
7631
  init_downloader();
7632
+ init_durable_log();
6722
7633
  init_migration();
6723
7634
  init_npm_resolver();
6724
7635
  init_onnx_runtime();
@@ -6727,70 +7638,70 @@ var init_dist2 = __esm(() => {
6727
7638
  init_pool();
6728
7639
  init_project_identity();
6729
7640
  init_resolver();
7641
+ init_revivable_transport();
6730
7642
  init_subc_transport();
6731
7643
  init_transport_factory();
6732
7644
  });
6733
7645
 
6734
7646
  // src/lib/paths.ts
6735
- import { homedir as homedir11, tmpdir as tmpdir2 } from "node:os";
6736
- import { join as join10 } from "node:path";
7647
+ import { homedir as homedir12 } from "node:os";
7648
+ import { join as join11 } from "node:path";
6737
7649
  function getAftBinaryCacheDir() {
6738
7650
  if (process.env.AFT_CACHE_DIR) {
6739
- return join10(process.env.AFT_CACHE_DIR, "bin");
7651
+ return join11(process.env.AFT_CACHE_DIR, "bin");
6740
7652
  }
6741
7653
  if (process.platform === "win32") {
6742
7654
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
6743
- const base2 = localAppData || join10(homedir11(), "AppData", "Local");
6744
- return join10(base2, "aft", "bin");
7655
+ const base2 = localAppData || join11(homedir12(), "AppData", "Local");
7656
+ return join11(base2, "aft", "bin");
6745
7657
  }
6746
- const base = process.env.XDG_CACHE_HOME || join10(homedir11(), ".cache");
6747
- return join10(base, "aft", "bin");
7658
+ const base = process.env.XDG_CACHE_HOME || join11(homedir12(), ".cache");
7659
+ return join11(base, "aft", "bin");
6748
7660
  }
6749
7661
  function getAftBinaryName() {
6750
7662
  return process.platform === "win32" ? "aft.exe" : "aft";
6751
7663
  }
6752
7664
  function getAftLspPackagesDir() {
6753
7665
  if (process.env.AFT_CACHE_DIR) {
6754
- return join10(process.env.AFT_CACHE_DIR, "lsp-packages");
7666
+ return join11(process.env.AFT_CACHE_DIR, "lsp-packages");
6755
7667
  }
6756
7668
  if (process.platform === "win32") {
6757
7669
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
6758
- const base2 = localAppData || join10(homedir11(), "AppData", "Local");
6759
- return join10(base2, "aft", "lsp-packages");
7670
+ const base2 = localAppData || join11(homedir12(), "AppData", "Local");
7671
+ return join11(base2, "aft", "lsp-packages");
6760
7672
  }
6761
- const base = process.env.XDG_CACHE_HOME || join10(homedir11(), ".cache");
6762
- return join10(base, "aft", "lsp-packages");
7673
+ const base = process.env.XDG_CACHE_HOME || join11(homedir12(), ".cache");
7674
+ return join11(base, "aft", "lsp-packages");
6763
7675
  }
6764
7676
  function getAftLspBinariesDir() {
6765
7677
  if (process.env.AFT_CACHE_DIR) {
6766
- return join10(process.env.AFT_CACHE_DIR, "lsp-binaries");
7678
+ return join11(process.env.AFT_CACHE_DIR, "lsp-binaries");
6767
7679
  }
6768
7680
  if (process.platform === "win32") {
6769
7681
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
6770
- const base2 = localAppData || join10(homedir11(), "AppData", "Local");
6771
- return join10(base2, "aft", "lsp-binaries");
7682
+ const base2 = localAppData || join11(homedir12(), "AppData", "Local");
7683
+ return join11(base2, "aft", "lsp-binaries");
6772
7684
  }
6773
- const base = process.env.XDG_CACHE_HOME || join10(homedir11(), ".cache");
6774
- return join10(base, "aft", "lsp-binaries");
7685
+ const base = process.env.XDG_CACHE_HOME || join11(homedir12(), ".cache");
7686
+ return join11(base, "aft", "lsp-binaries");
6775
7687
  }
6776
- function homeDir3() {
7688
+ function homeDir4() {
6777
7689
  if (process.platform === "win32")
6778
- return process.env.USERPROFILE || process.env.HOME || homedir11();
6779
- return process.env.HOME || homedir11();
7690
+ return process.env.USERPROFILE || process.env.HOME || homedir12();
7691
+ return process.env.HOME || homedir12();
6780
7692
  }
6781
- function dataHome2() {
7693
+ function dataHome3() {
6782
7694
  if (process.env.XDG_DATA_HOME)
6783
7695
  return process.env.XDG_DATA_HOME;
6784
7696
  if (process.platform === "win32") {
6785
- return process.env.LOCALAPPDATA || process.env.APPDATA || join10(homeDir3(), "AppData", "Local");
7697
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join11(homeDir4(), "AppData", "Local");
6786
7698
  }
6787
- return join10(homeDir3(), ".local", "share");
7699
+ return join11(homeDir4(), ".local", "share");
6788
7700
  }
6789
7701
  function getCortexKitStorageRoot() {
6790
- return join10(dataHome2(), "cortexkit", "aft");
6791
- }
6792
- function getTmpLogPath(filename) {
6793
- return join10(tmpdir2(), filename);
7702
+ if (process.env.AFT_CACHE_DIR)
7703
+ return join11(process.env.AFT_CACHE_DIR, "aft");
7704
+ return join11(dataHome3(), "cortexkit", "aft");
6794
7705
  }
6795
7706
  var init_paths2 = () => {};
6796
7707
 
@@ -6798,8 +7709,8 @@ var init_paths2 = () => {};
6798
7709
  import { execSync as execSync2, spawnSync as spawnSync3 } from "node:child_process";
6799
7710
  import { existsSync as existsSync7 } from "node:fs";
6800
7711
  import { createRequire as createRequire2 } from "node:module";
6801
- import { homedir as homedir12 } from "node:os";
6802
- import { join as join11 } from "node:path";
7712
+ import { homedir as homedir13 } from "node:os";
7713
+ import { join as join12 } from "node:path";
6803
7714
  async function loadPluginVersion() {
6804
7715
  try {
6805
7716
  const bridge = await Promise.resolve().then(() => (init_dist2(), exports_dist));
@@ -6921,7 +7832,7 @@ function aftBinaryCandidates(preferredVersion) {
6921
7832
  const candidates = [];
6922
7833
  if (preferredVersion) {
6923
7834
  const tag = preferredVersion.startsWith("v") ? preferredVersion : `v${preferredVersion}`;
6924
- pushCandidate(candidates, join11(getAftBinaryCacheDir(), tag, getAftBinaryName()));
7835
+ pushCandidate(candidates, join12(getAftBinaryCacheDir(), tag, getAftBinaryName()));
6925
7836
  }
6926
7837
  const key = platformKey2();
6927
7838
  if (key) {
@@ -6944,7 +7855,7 @@ function aftBinaryCandidates(preferredVersion) {
6944
7855
  }
6945
7856
  }
6946
7857
  } catch {}
6947
- pushCandidate(candidates, join11(homedir12(), ".cargo", "bin", getAftBinaryName()));
7858
+ pushCandidate(candidates, join12(homedir13(), ".cargo", "bin", getAftBinaryName()));
6948
7859
  return candidates;
6949
7860
  }
6950
7861
  function findAftBinary(preferredVersion) {
@@ -6960,21 +7871,21 @@ var init_binary_probe = __esm(async () => {
6960
7871
 
6961
7872
  // src/lib/fs-util.ts
6962
7873
  import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync5 } from "node:fs";
6963
- import { join as join12 } from "node:path";
7874
+ import { join as join13 } from "node:path";
6964
7875
  function dirSize(path2) {
6965
7876
  if (!existsSync8(path2)) {
6966
7877
  return 0;
6967
7878
  }
6968
- const stat = statSync5(path2);
6969
- if (stat.isFile()) {
6970
- return stat.size;
7879
+ const stat2 = statSync5(path2);
7880
+ if (stat2.isFile()) {
7881
+ return stat2.size;
6971
7882
  }
6972
- if (!stat.isDirectory()) {
7883
+ if (!stat2.isDirectory()) {
6973
7884
  return 0;
6974
7885
  }
6975
7886
  let total = 0;
6976
7887
  for (const entry of readdirSync3(path2)) {
6977
- total += dirSize(join12(path2, entry));
7888
+ total += dirSize(join13(path2, entry));
6978
7889
  }
6979
7890
  return total;
6980
7891
  }
@@ -14597,10 +15508,10 @@ var require_stringify = __commonJS((exports, module) => {
14597
15508
  replacer = null;
14598
15509
  indent = EMPTY;
14599
15510
  };
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;
15511
+ 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
15512
  var join_content = (inside, value, gap) => {
14602
15513
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
14603
- return join13(comment, inside, gap);
15514
+ return join14(comment, inside, gap);
14604
15515
  };
14605
15516
  var stringify_string = (holder, key, value) => {
14606
15517
  const raw = get_raw_string_literal(holder, key);
@@ -14622,13 +15533,13 @@ var require_stringify = __commonJS((exports, module) => {
14622
15533
  if (i !== 0) {
14623
15534
  inside += COMMA;
14624
15535
  }
14625
- const before = join13(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
15536
+ const before = join14(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
14626
15537
  inside += before || LF + deeper_gap;
14627
15538
  inside += stringify(i, value, deeper_gap) || STR_NULL;
14628
15539
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
14629
15540
  after_comma = process_comments(value, AFTER(i), deeper_gap);
14630
15541
  }
14631
- inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
15542
+ inside += join14(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
14632
15543
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
14633
15544
  };
14634
15545
  var object_stringify = (value, gap) => {
@@ -14649,13 +15560,13 @@ var require_stringify = __commonJS((exports, module) => {
14649
15560
  inside += COMMA;
14650
15561
  }
14651
15562
  first = false;
14652
- const before = join13(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
15563
+ const before = join14(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
14653
15564
  inside += before || LF + deeper_gap;
14654
15565
  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
15566
  after_comma = process_comments(value, AFTER(key), deeper_gap);
14656
15567
  };
14657
15568
  keys.forEach(iteratee);
14658
- inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
15569
+ inside += join14(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
14659
15570
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
14660
15571
  };
14661
15572
  function stringify(key, holder, gap) {
@@ -14749,7 +15660,7 @@ var require_src2 = __commonJS((exports, module) => {
14749
15660
 
14750
15661
  // src/lib/jsonc.ts
14751
15662
  import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
14752
- import { dirname as dirname5 } from "node:path";
15663
+ import { dirname as dirname6 } from "node:path";
14753
15664
  function detectJsoncFile(configDir, baseName) {
14754
15665
  const jsoncPath = `${configDir}/${baseName}.jsonc`;
14755
15666
  const jsonPath = `${configDir}/${baseName}.json`;
@@ -14777,7 +15688,7 @@ function readJsoncFile(path2) {
14777
15688
  }
14778
15689
  }
14779
15690
  function writeJsoncFile(path2, value, format = "json") {
14780
- mkdirSync6(dirname5(path2), { recursive: true });
15691
+ mkdirSync6(dirname6(path2), { recursive: true });
14781
15692
  const serialized = format === "jsonc" ? import_comment_json.stringify(value, null, 2) : JSON.stringify(value, null, 2);
14782
15693
  writeFileSync4(path2, `${serialized}
14783
15694
  `);
@@ -14837,25 +15748,25 @@ var init_self_version = () => {};
14837
15748
  // src/adapters/opencode.ts
14838
15749
  import { execSync as execSync3 } from "node:child_process";
14839
15750
  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";
15751
+ import { homedir as homedir14 } from "node:os";
15752
+ import { dirname as dirname7, join as join14, parse, resolve as resolve7 } from "node:path";
14842
15753
  import { fileURLToPath } from "node:url";
14843
15754
  function getOpenCodeConfigDir() {
14844
15755
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
14845
15756
  if (envDir)
14846
15757
  return resolve7(envDir);
14847
- const xdg = process.env.XDG_CONFIG_HOME || join13(homedir13(), ".config");
14848
- return join13(xdg, "opencode");
15758
+ const xdg = process.env.XDG_CONFIG_HOME || join14(homedir14(), ".config");
15759
+ return join14(xdg, "opencode");
14849
15760
  }
14850
15761
  function getOpenCodeCacheDir() {
14851
15762
  const xdg = process.env.XDG_CACHE_HOME;
14852
15763
  if (xdg)
14853
- return join13(xdg, "opencode");
15764
+ return join14(xdg, "opencode");
14854
15765
  if (process.platform === "win32") {
14855
- const localAppData = process.env.LOCALAPPDATA ?? join13(homedir13(), "AppData", "Local");
14856
- return join13(localAppData, "opencode");
15766
+ const localAppData = process.env.LOCALAPPDATA ?? join14(homedir14(), "AppData", "Local");
15767
+ return join14(localAppData, "opencode");
14857
15768
  }
14858
- return join13(homedir13(), ".cache", "opencode");
15769
+ return join14(homedir14(), ".cache", "opencode");
14859
15770
  }
14860
15771
  function hasOpenCodeCli() {
14861
15772
  try {
@@ -14868,12 +15779,12 @@ function hasOpenCodeCli() {
14868
15779
  function openCodeDesktopAppExists() {
14869
15780
  const candidates = [];
14870
15781
  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"));
15782
+ candidates.push("/Applications/OpenCode.app", "/Applications/OpenCode Beta.app", join14(homedir14(), "Applications", "OpenCode.app"), join14(homedir14(), "Applications", "OpenCode Beta.app"));
14872
15783
  } 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"));
15784
+ const localAppData = process.env.LOCALAPPDATA ?? join14(homedir14(), "AppData", "Local");
15785
+ candidates.push(join14(localAppData, "Programs", "opencode"), join14(localAppData, "opencode"));
14875
15786
  } else {
14876
- candidates.push("/opt/OpenCode", "/usr/lib/opencode", join13(homedir13(), ".local", "share", "applications", "opencode.desktop"));
15787
+ candidates.push("/opt/OpenCode", "/usr/lib/opencode", join14(homedir14(), ".local", "share", "applications", "opencode.desktop"));
14877
15788
  }
14878
15789
  return candidates.some((p) => {
14879
15790
  try {
@@ -14902,15 +15813,15 @@ function pathPointsToOurPlugin(entry) {
14902
15813
  try {
14903
15814
  if (!existsSync10(fsPath))
14904
15815
  return false;
14905
- let searchDir = statSync6(fsPath).isDirectory() ? fsPath : dirname6(fsPath);
15816
+ let searchDir = statSync6(fsPath).isDirectory() ? fsPath : dirname7(fsPath);
14906
15817
  let pkgJsonPath = null;
14907
15818
  while (true) {
14908
- const candidate = join13(searchDir, "package.json");
15819
+ const candidate = join14(searchDir, "package.json");
14909
15820
  if (existsSync10(candidate)) {
14910
15821
  pkgJsonPath = candidate;
14911
15822
  break;
14912
15823
  }
14913
- const parent = dirname6(searchDir);
15824
+ const parent = dirname7(searchDir);
14914
15825
  if (parent === searchDir || searchDir === parse(searchDir).root)
14915
15826
  break;
14916
15827
  searchDir = parent;
@@ -15076,10 +15987,10 @@ class OpenCodeAdapter {
15076
15987
  };
15077
15988
  }
15078
15989
  getPluginCacheInfo() {
15079
- const path2 = join13(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY);
15990
+ const path2 = join14(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY);
15080
15991
  let cached;
15081
15992
  try {
15082
- const installedPkgPath = join13(path2, "node_modules", "@cortexkit", "aft-opencode", "package.json");
15993
+ const installedPkgPath = join14(path2, "node_modules", "@cortexkit", "aft-opencode", "package.json");
15083
15994
  if (existsSync10(installedPkgPath)) {
15084
15995
  const pkg = JSON.parse(readFileSync8(installedPkgPath, "utf-8"));
15085
15996
  cached = typeof pkg.version === "string" ? pkg.version : undefined;
@@ -15098,7 +16009,7 @@ class OpenCodeAdapter {
15098
16009
  return getCortexKitStorageRoot();
15099
16010
  }
15100
16011
  getLogFile() {
15101
- return getTmpLogPath("aft-plugin.log");
16012
+ return resolveAftLogPath("aft-plugin.log");
15102
16013
  }
15103
16014
  getInstallHint() {
15104
16015
  return "Install OpenCode: https://opencode.ai/docs/install";
@@ -15140,11 +16051,11 @@ class OpenCodeAdapter {
15140
16051
  describeStorageSubtrees() {
15141
16052
  const storage = this.getStorageDir();
15142
16053
  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"))
16054
+ index: dirSize(join14(storage, "index")),
16055
+ semantic: dirSize(join14(storage, "semantic")),
16056
+ backups: dirSize(join14(storage, "backups")),
16057
+ url_cache: dirSize(join14(storage, "url_cache")),
16058
+ onnxruntime: dirSize(join14(storage, "onnxruntime"))
15148
16059
  };
15149
16060
  }
15150
16061
  }
@@ -15161,15 +16072,15 @@ var init_opencode = __esm(() => {
15161
16072
  // src/adapters/pi.ts
15162
16073
  import { execSync as execSync4, spawnSync as spawnSync4 } from "node:child_process";
15163
16074
  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";
16075
+ import { homedir as homedir15 } from "node:os";
16076
+ import { join as join15 } from "node:path";
15166
16077
  function getPiAgentDir() {
15167
16078
  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");
16079
+ const home = envHome && envHome.length > 0 ? envHome : homedir15();
16080
+ return join15(home, ".pi", "agent");
15170
16081
  }
15171
16082
  function readPiExtensionIndex() {
15172
- const settingsPath = join14(getPiAgentDir(), "settings.json");
16083
+ const settingsPath = join15(getPiAgentDir(), "settings.json");
15173
16084
  if (existsSync11(settingsPath)) {
15174
16085
  try {
15175
16086
  const raw = readFileSync9(settingsPath, "utf-8");
@@ -15183,10 +16094,10 @@ function readPiExtensionIndex() {
15183
16094
  } catch {}
15184
16095
  }
15185
16096
  const candidates = [
15186
- join14(getPiAgentDir(), "extensions.json"),
15187
- join14(getPiAgentDir(), "extensions.jsonc"),
15188
- join14(getPiAgentDir(), "config.json"),
15189
- join14(getPiAgentDir(), "config.jsonc")
16097
+ join15(getPiAgentDir(), "extensions.json"),
16098
+ join15(getPiAgentDir(), "extensions.jsonc"),
16099
+ join15(getPiAgentDir(), "config.json"),
16100
+ join15(getPiAgentDir(), "config.jsonc")
15190
16101
  ];
15191
16102
  for (const path2 of candidates) {
15192
16103
  if (!existsSync11(path2))
@@ -15222,14 +16133,14 @@ function piEntryMatchesAft(entry) {
15222
16133
  } else if (entry.startsWith("/")) {
15223
16134
  resolved = entry;
15224
16135
  } else if (entry.length > 0) {
15225
- resolved = join14(getPiAgentDir(), entry);
16136
+ resolved = join15(getPiAgentDir(), entry);
15226
16137
  }
15227
16138
  if (!resolved)
15228
16139
  return false;
15229
16140
  try {
15230
16141
  if (!existsSync11(resolved))
15231
16142
  return false;
15232
- const pkgPath = join14(resolved, "package.json");
16143
+ const pkgPath = join15(resolved, "package.json");
15233
16144
  if (!existsSync11(pkgPath))
15234
16145
  return false;
15235
16146
  const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
@@ -15281,7 +16192,7 @@ class PiAdapter {
15281
16192
  const aftConfigExists = existsSync11(aftConfigPath);
15282
16193
  return {
15283
16194
  configDir,
15284
- harnessConfig: index.path ?? join14(configDir, "extensions.json"),
16195
+ harnessConfig: index.path ?? join15(configDir, "extensions.json"),
15285
16196
  harnessConfigFormat: index.path ? "json" : "none",
15286
16197
  aftConfig: aftConfigPath,
15287
16198
  aftConfigFormat: aftConfigExists ? "jsonc" : "none"
@@ -15326,8 +16237,8 @@ class PiAdapter {
15326
16237
  }
15327
16238
  getPluginCacheInfo() {
15328
16239
  const candidates = [
15329
- join14(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
15330
- join14(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
16240
+ join15(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
16241
+ join15(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
15331
16242
  ];
15332
16243
  for (const candidate of candidates) {
15333
16244
  if (!existsSync11(candidate))
@@ -15344,7 +16255,7 @@ class PiAdapter {
15344
16255
  } catch {}
15345
16256
  }
15346
16257
  return {
15347
- path: join14(getPiAgentDir(), "extensions"),
16258
+ path: join15(getPiAgentDir(), "extensions"),
15348
16259
  exists: false
15349
16260
  };
15350
16261
  }
@@ -15352,7 +16263,7 @@ class PiAdapter {
15352
16263
  return getCortexKitStorageRoot();
15353
16264
  }
15354
16265
  getLogFile() {
15355
- return getTmpLogPath("aft-pi.log");
16266
+ return resolveAftLogPath("aft-plugin.log");
15356
16267
  }
15357
16268
  getInstallHint() {
15358
16269
  return "Install Pi: https://github.com/badlogic/pi-mono";
@@ -15366,11 +16277,11 @@ class PiAdapter {
15366
16277
  describeStorageSubtrees() {
15367
16278
  const storage = this.getStorageDir();
15368
16279
  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"))
16280
+ index: dirSize(join15(storage, "index")),
16281
+ semantic: dirSize(join15(storage, "semantic")),
16282
+ backups: dirSize(join15(storage, "backups")),
16283
+ url_cache: dirSize(join15(storage, "url_cache")),
16284
+ onnxruntime: dirSize(join15(storage, "onnxruntime"))
15374
16285
  };
15375
16286
  }
15376
16287
  }
@@ -17394,28 +18305,30 @@ var init_aft_bridge = () => {};
17394
18305
  // src/commands/lsp.ts
17395
18306
  var exports_lsp = {};
17396
18307
  __export(exports_lsp, {
18308
+ typescriptPackageWarning: () => typescriptPackageWarning,
17397
18309
  runLspDoctor: () => runLspDoctor,
17398
18310
  renderLspInspection: () => renderLspInspection,
17399
18311
  printLspDoctorHelp: () => printLspDoctorHelp,
17400
18312
  findProjectRootForFile: () => findProjectRootForFile
17401
18313
  });
17402
18314
  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";
18315
+ import { createRequire as createRequire4 } from "node:module";
18316
+ import { dirname as dirname8, join as join16, resolve as resolve8 } from "node:path";
17404
18317
  function findProjectRootForFile(filePath, fallbackCwd = process.cwd()) {
17405
18318
  const resolvedFile = resolve8(fallbackCwd, filePath);
17406
- let dir = dirname7(resolvedFile);
18319
+ let dir = dirname8(resolvedFile);
17407
18320
  try {
17408
18321
  if (existsSync12(resolvedFile) && statSync7(resolvedFile).isDirectory()) {
17409
18322
  dir = resolvedFile;
17410
18323
  }
17411
18324
  } catch {
17412
- dir = dirname7(resolvedFile);
18325
+ dir = dirname8(resolvedFile);
17413
18326
  }
17414
18327
  while (true) {
17415
- if (PROJECT_ROOT_MARKERS.some((marker) => existsSync12(join15(dir, marker)))) {
18328
+ if (PROJECT_ROOT_MARKERS.some((marker) => existsSync12(join16(dir, marker)))) {
17416
18329
  return dir;
17417
18330
  }
17418
- const parent = dirname7(dir);
18331
+ const parent = dirname8(dir);
17419
18332
  if (parent === dir)
17420
18333
  return resolve8(fallbackCwd);
17421
18334
  dir = parent;
@@ -17471,7 +18384,12 @@ async function runLspDoctor(options) {
17471
18384
  log2.error(inspect.message ?? inspect.code ?? "lsp_inspect failed");
17472
18385
  return 1;
17473
18386
  }
17474
- console.log(renderLspInspection(file, inspect));
18387
+ const inspection = inspect;
18388
+ const typescriptWarning = typescriptPackageWarning(inspection);
18389
+ console.log(renderLspInspection(file, {
18390
+ ...inspection,
18391
+ ...typescriptWarning ? { typescript_package_warning: typescriptWarning } : {}
18392
+ }));
17475
18393
  return 0;
17476
18394
  }
17477
18395
  function renderLspInspection(inputFile, response) {
@@ -17507,6 +18425,10 @@ function renderLspInspection(inputFile, response) {
17507
18425
  lines.push(` Action: ${installHint(server.binary_name)}`);
17508
18426
  }
17509
18427
  }
18428
+ if (response.typescript_package_warning) {
18429
+ lines.push("");
18430
+ lines.push(`Warning: ${response.typescript_package_warning}`);
18431
+ }
17510
18432
  const diagnostics = response.diagnostics ?? [];
17511
18433
  lines.push("");
17512
18434
  lines.push(`Diagnostics (${response.diagnostics_count ?? diagnostics.length} found):`);
@@ -17535,8 +18457,8 @@ function parseFileArg(argv) {
17535
18457
  function buildConfigureParams(adapter, projectRoot) {
17536
18458
  const userConfigPath = adapter.detectConfigPaths().aftConfig;
17537
18459
  const dir = adapter.kind === "pi" ? ".pi" : ".opencode";
17538
- const projectJsonc = join15(projectRoot, dir, "aft.jsonc");
17539
- const projectJson = join15(projectRoot, dir, "aft.json");
18460
+ const projectJsonc = join16(projectRoot, dir, "aft.jsonc");
18461
+ const projectJson = join16(projectRoot, dir, "aft.json");
17540
18462
  const projectConfigPath = existsSync12(projectJsonc) ? projectJsonc : projectJson;
17541
18463
  return {
17542
18464
  id: "doctor-lsp-configure",
@@ -17550,10 +18472,10 @@ function buildConfigureParams(adapter, projectRoot) {
17550
18472
  function inferLspPathsExtra(_lsp) {
17551
18473
  const paths = new Set;
17552
18474
  for (const entry of childDirs(getAftLspPackagesDir())) {
17553
- paths.add(join15(entry, "node_modules", ".bin"));
18475
+ paths.add(join16(entry, "node_modules", ".bin"));
17554
18476
  }
17555
18477
  for (const entry of childDirs(getAftLspBinariesDir())) {
17556
- paths.add(join15(entry, "bin"));
18478
+ paths.add(join16(entry, "bin"));
17557
18479
  }
17558
18480
  return [...paths];
17559
18481
  }
@@ -17561,7 +18483,7 @@ function childDirs(path2) {
17561
18483
  if (!existsSync12(path2))
17562
18484
  return [];
17563
18485
  try {
17564
- return readdirSync4(path2).map((entry) => join15(path2, entry)).filter((entry) => {
18486
+ return readdirSync4(path2).map((entry) => join16(path2, entry)).filter((entry) => {
17565
18487
  try {
17566
18488
  return statSync7(entry).isDirectory();
17567
18489
  } catch {
@@ -17596,6 +18518,18 @@ function formatSpawnStatus(server) {
17596
18518
  function formatList(values) {
17597
18519
  return values.length === 0 ? "(none)" : values.join(", ");
17598
18520
  }
18521
+ function typescriptPackageWarning(response) {
18522
+ const typescriptServerSpawned = response.matching_servers?.some((server) => server.id === "typescript" && server.spawn_status === "ok");
18523
+ const diagnosticsCount = response.diagnostics_count ?? response.diagnostics?.length ?? 0;
18524
+ if (!typescriptServerSpawned || !response.project_root || diagnosticsCount > 0)
18525
+ return null;
18526
+ try {
18527
+ createRequire4(join16(response.project_root, "package.json")).resolve("typescript");
18528
+ return null;
18529
+ } catch {
18530
+ return "typescript package not resolvable from project — server will produce no diagnostics";
18531
+ }
18532
+ }
17599
18533
  function installHint(binaryName) {
17600
18534
  if (binaryName === "ty")
17601
18535
  return "Install with `uv tool install ty` or `pip install ty`.";
@@ -17639,7 +18573,7 @@ __export(exports_doctor_filters, {
17639
18573
  printDoctorFiltersHelp: () => printDoctorFiltersHelp
17640
18574
  });
17641
18575
  import { existsSync as existsSync13 } from "node:fs";
17642
- import { homedir as homedir15 } from "node:os";
18576
+ import { homedir as homedir16 } from "node:os";
17643
18577
  import { relative as relative3, resolve as resolve9 } from "node:path";
17644
18578
  function printDoctorFiltersHelp() {
17645
18579
  console.log("Usage: aft doctor filters [--show <name>] [trust|untrust]");
@@ -17857,7 +18791,7 @@ function truncate(value) {
17857
18791
  return value.length <= 80 ? value : `${value.slice(0, 77)}…`;
17858
18792
  }
17859
18793
  function formatHome(path2) {
17860
- const home = homedir15();
18794
+ const home = homedir16();
17861
18795
  return path2.startsWith(home) ? `~${path2.slice(home.length)}` : path2;
17862
18796
  }
17863
18797
  function formatProjectPath(path2, projectRoot) {
@@ -17881,7 +18815,7 @@ var init_doctor_filters = __esm(async () => {
17881
18815
 
17882
18816
  // src/lib/binary-cache.ts
17883
18817
  import { existsSync as existsSync14, readdirSync as readdirSync5, statSync as statSync8 } from "node:fs";
17884
- import { join as join16 } from "node:path";
18818
+ import { join as join17 } from "node:path";
17885
18819
  function getBinaryCacheInfo(activeVersion) {
17886
18820
  const path2 = getAftBinaryCacheDir();
17887
18821
  if (!existsSync14(path2)) {
@@ -17894,7 +18828,7 @@ function getBinaryCacheInfo(activeVersion) {
17894
18828
  }
17895
18829
  const versions = readdirSync5(path2).filter((entry) => {
17896
18830
  try {
17897
- return statSync8(join16(path2, entry)).isDirectory();
18831
+ return statSync8(join17(path2, entry)).isDirectory();
17898
18832
  } catch {
17899
18833
  return false;
17900
18834
  }
@@ -17915,7 +18849,7 @@ var init_binary_cache = __esm(() => {
17915
18849
 
17916
18850
  // src/lib/sanitize.ts
17917
18851
  import { realpathSync as realpathSync3 } from "node:fs";
17918
- import { homedir as homedir16, userInfo } from "node:os";
18852
+ import { homedir as homedir17, userInfo } from "node:os";
17919
18853
  function escapeRegex(value) {
17920
18854
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17921
18855
  }
@@ -17946,7 +18880,7 @@ function redactSecrets(content) {
17946
18880
  }
17947
18881
  function sanitizeContent(content) {
17948
18882
  const username = userInfo().username;
17949
- const home = homedir16();
18883
+ const home = homedir17();
17950
18884
  let sanitized = redactSecrets(content);
17951
18885
  const cwd = process.cwd();
17952
18886
  for (const candidate of new Set([cwd, safeRealpath(cwd)])) {
@@ -17993,11 +18927,9 @@ var init_sanitize = __esm(() => {
17993
18927
 
17994
18928
  // src/lib/bridge-tool-failures.ts
17995
18929
  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
18930
  function resolveBridgePluginLogPath() {
17999
18931
  const isTestEnv = process.env.BUN_TEST === "1" || false;
18000
- return join17(tmpdir3(), isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
18932
+ return resolveAftLogPath(isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
18001
18933
  }
18002
18934
  function tailLogFileBytes(path2, maxBytes) {
18003
18935
  if (!existsSync15(path2) || maxBytes <= 0)
@@ -18128,31 +19060,156 @@ function buildRecentAftToolFailuresSectionFromLog(logPath = resolveBridgePluginL
18128
19060
  }
18129
19061
  var BRIDGE_LOG_TAIL_BYTES, MAX_TOOL_FAILURE_CLASSES = 30, SESSION_TAG_PATTERN, STRUCTURED_CODE_PATTERN;
18130
19062
  var init_bridge_tool_failures = __esm(() => {
19063
+ init_dist2();
18131
19064
  init_sanitize();
18132
19065
  BRIDGE_LOG_TAIL_BYTES = 2 * 1024 * 1024;
18133
19066
  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
19067
  STRUCTURED_CODE_PATTERN = /"code"\s*:\s*"([^"]+)"/;
18135
19068
  });
18136
19069
 
18137
- // src/lib/lsp-cache.ts
18138
- import { existsSync as existsSync16, readdirSync as readdirSync6, rmSync as rmSync5, statSync as statSync10 } from "node:fs";
19070
+ // src/lib/legacy-storage.ts
19071
+ import { existsSync as existsSync16, readdirSync as readdirSync6, statSync as statSync10 } from "node:fs";
18139
19072
  import { join as join18 } from "node:path";
19073
+ function summarizeLegacyPartitionDuplication(storageRoot) {
19074
+ if (!existsSync16(storageRoot)) {
19075
+ return { totalPartitions: 0, totalBytes: 0, byHarness: [] };
19076
+ }
19077
+ const byHarness = [];
19078
+ for (const harness of safeReadDir(storageRoot)) {
19079
+ const harnessPath = join18(storageRoot, harness);
19080
+ if (!isDirectory(harnessPath))
19081
+ continue;
19082
+ const partitions = new Map;
19083
+ collectCallgraphPartitions(join18(harnessPath, "callgraph"), partitions);
19084
+ collectInspectPartitions(join18(harnessPath, "inspect"), partitions);
19085
+ if (partitions.size === 0)
19086
+ continue;
19087
+ let bytes = 0;
19088
+ for (const size of partitions.values())
19089
+ bytes += size;
19090
+ byHarness.push({ harness, partitions: partitions.size, bytes });
19091
+ }
19092
+ byHarness.sort((left, right) => left.harness.localeCompare(right.harness));
19093
+ return {
19094
+ totalPartitions: byHarness.reduce((sum, item) => sum + item.partitions, 0),
19095
+ totalBytes: byHarness.reduce((sum, item) => sum + item.bytes, 0),
19096
+ byHarness
19097
+ };
19098
+ }
19099
+ function collectCallgraphPartitions(domainPath, partitions) {
19100
+ if (!isDirectory(domainPath))
19101
+ return;
19102
+ for (const name of safeReadDir(domainPath)) {
19103
+ const path2 = join18(domainPath, name);
19104
+ if (isDirectory(path2)) {
19105
+ if (!looksLikePartitionKey(name))
19106
+ continue;
19107
+ addPartitionBytes(partitions, `callgraph:${name}`, dirSize(path2));
19108
+ continue;
19109
+ }
19110
+ const key = callgraphPartitionKeyFromName(name);
19111
+ if (!key)
19112
+ continue;
19113
+ addPartitionBytes(partitions, `callgraph:${key}`, safeFileSize(path2));
19114
+ }
19115
+ }
19116
+ function collectInspectPartitions(domainPath, partitions) {
19117
+ if (!isDirectory(domainPath))
19118
+ return;
19119
+ for (const name of safeReadDir(domainPath)) {
19120
+ const path2 = join18(domainPath, name);
19121
+ if (isDirectory(path2)) {
19122
+ if (!looksLikePartitionKey(name))
19123
+ continue;
19124
+ addPartitionBytes(partitions, `inspect:${name}`, dirSize(path2));
19125
+ continue;
19126
+ }
19127
+ const key = inspectPartitionKeyFromName(name);
19128
+ if (!key)
19129
+ continue;
19130
+ addPartitionBytes(partitions, `inspect:${key}`, safeFileSize(path2));
19131
+ }
19132
+ }
19133
+ function addPartitionBytes(partitions, key, bytes) {
19134
+ partitions.set(key, (partitions.get(key) ?? 0) + bytes);
19135
+ }
19136
+ function callgraphPartitionKeyFromName(name) {
19137
+ if (name.includes(".tmp."))
19138
+ return null;
19139
+ if (name.endsWith(".current")) {
19140
+ const key2 = name.slice(0, -".current".length);
19141
+ return looksLikePartitionKey(key2) ? key2 : null;
19142
+ }
19143
+ const base = sqliteishBaseName(name);
19144
+ if (!base)
19145
+ return null;
19146
+ const split = base.indexOf(".g");
19147
+ const key = split === -1 ? base : base.slice(0, split);
19148
+ return looksLikePartitionKey(key) ? key : null;
19149
+ }
19150
+ function inspectPartitionKeyFromName(name) {
19151
+ if (name.includes(".tmp."))
19152
+ return null;
19153
+ const base = sqliteishBaseName(name);
19154
+ return base && looksLikePartitionKey(base) ? base : null;
19155
+ }
19156
+ function sqliteishBaseName(name) {
19157
+ for (const suffix of SQLITE_SUFFIXES) {
19158
+ if (name.endsWith(suffix)) {
19159
+ return name.slice(0, -suffix.length);
19160
+ }
19161
+ }
19162
+ return null;
19163
+ }
19164
+ function looksLikePartitionKey(value) {
19165
+ return /^[0-9a-fA-F]{16}$/.test(value);
19166
+ }
19167
+ function safeReadDir(path2) {
19168
+ try {
19169
+ return readdirSync6(path2).sort((left, right) => left.localeCompare(right));
19170
+ } catch {
19171
+ return [];
19172
+ }
19173
+ }
19174
+ function isDirectory(path2) {
19175
+ try {
19176
+ return statSync10(path2).isDirectory();
19177
+ } catch {
19178
+ return false;
19179
+ }
19180
+ }
19181
+ function safeFileSize(path2) {
19182
+ try {
19183
+ return statSync10(path2).isFile() ? statSync10(path2).size : 0;
19184
+ } catch {
19185
+ return 0;
19186
+ }
19187
+ }
19188
+ var SQLITE_SUFFIXES;
19189
+ var init_legacy_storage = __esm(() => {
19190
+ init_fs_util();
19191
+ SQLITE_SUFFIXES = [".sqlite-wal", ".sqlite-shm", ".sqlite-journal", ".sqlite"];
19192
+ });
19193
+
19194
+ // src/lib/lsp-cache.ts
19195
+ import { existsSync as existsSync17, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync11 } from "node:fs";
19196
+ import { join as join19 } from "node:path";
18140
19197
  function inspectDir(path2) {
18141
- if (!existsSync16(path2)) {
19198
+ if (!existsSync17(path2)) {
18142
19199
  return { entries: [], totalSize: 0 };
18143
19200
  }
18144
19201
  const entries = [];
18145
19202
  let totalSize = 0;
18146
19203
  let names;
18147
19204
  try {
18148
- names = readdirSync6(path2);
19205
+ names = readdirSync7(path2);
18149
19206
  } catch {
18150
19207
  return { entries: [], totalSize: 0 };
18151
19208
  }
18152
19209
  for (const name of names) {
18153
- const full = join18(path2, name);
19210
+ const full = join19(path2, name);
18154
19211
  try {
18155
- if (!statSync10(full).isDirectory())
19212
+ if (!statSync11(full).isDirectory())
18156
19213
  continue;
18157
19214
  const size = dirSize(full);
18158
19215
  entries.push({
@@ -18208,8 +19265,8 @@ var init_lsp_cache = __esm(() => {
18208
19265
  });
18209
19266
 
18210
19267
  // 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";
19268
+ import { existsSync as existsSync18, readdirSync as readdirSync8, readlinkSync as readlinkSync2, realpathSync as realpathSync4 } from "node:fs";
19269
+ import { basename as basename3, isAbsolute as isAbsolute6, join as join20, resolve as resolve10, win32 as win322 } from "node:path";
18213
19270
  function getOnnxLibraryName() {
18214
19271
  if (process.platform === "darwin")
18215
19272
  return "libonnxruntime.dylib";
@@ -18249,9 +19306,20 @@ function pathEntriesForPlatform2() {
18249
19306
  return isAbsolute6(entry) || win322.isAbsolute(entry);
18250
19307
  });
18251
19308
  }
19309
+ function isWindowsSystem32Directory2(dir) {
19310
+ if (process.platform !== "win32")
19311
+ return false;
19312
+ const normalizedDir = win322.resolve(dir).replace(/[\\/]+$/, "").toLowerCase();
19313
+ const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
19314
+ return windowsRoots.some((root) => {
19315
+ if (!root)
19316
+ return false;
19317
+ return normalizedDir === win322.resolve(root, "System32").replace(/[\\/]+$/, "").toLowerCase();
19318
+ });
19319
+ }
18252
19320
  function directoryContainsLibrary2(dir, libName) {
18253
19321
  try {
18254
- const entries = readdirSync7(dir);
19322
+ const entries = readdirSync8(dir);
18255
19323
  if (process.platform === "win32") {
18256
19324
  const expected = libName.toLowerCase();
18257
19325
  return entries.some((entry) => entry.toLowerCase() === expected);
@@ -18261,6 +19329,24 @@ function directoryContainsLibrary2(dir, libName) {
18261
19329
  return false;
18262
19330
  }
18263
19331
  }
19332
+ function findIgnoredWindowsSystemOnnxRuntime() {
19333
+ if (process.platform !== "win32")
19334
+ return null;
19335
+ const windowsRoots = [process.env.SystemRoot, process.env.windir, "C:\\Windows"];
19336
+ const seen = new Set;
19337
+ for (const root of windowsRoots) {
19338
+ if (!root)
19339
+ continue;
19340
+ const systemDir = join20(root, "System32");
19341
+ const key = win322.resolve(systemDir).toLowerCase();
19342
+ if (seen.has(key))
19343
+ continue;
19344
+ seen.add(key);
19345
+ if (directoryContainsLibrary2(systemDir, getOnnxLibraryName()))
19346
+ return systemDir;
19347
+ }
19348
+ return null;
19349
+ }
18264
19350
  function findSystemOnnxRuntime2() {
18265
19351
  const libName = getOnnxLibraryName();
18266
19352
  const searchPaths = [];
@@ -18272,21 +19358,21 @@ function findSystemOnnxRuntime2() {
18272
19358
  searchPaths.push(...pathEntriesForPlatform2());
18273
19359
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
18274
19360
  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"), ...(() => {
19361
+ searchPaths.push(join20(programFiles, "onnxruntime", "lib"), join20(programFiles, "Microsoft ONNX Runtime", "lib"), join20(programFiles, "Microsoft Machine Learning", "lib"), join20(programFilesX86, "onnxruntime", "lib"), ...(() => {
18276
19362
  const nugetPaths = [];
18277
19363
  const userProfile = process.env.USERPROFILE ?? "";
18278
19364
  if (!userProfile)
18279
19365
  return nugetPaths;
18280
- const nugetPackageDir = join19(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
18281
- if (!existsSync17(nugetPackageDir))
19366
+ const nugetPackageDir = join20(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
19367
+ if (!existsSync18(nugetPackageDir))
18282
19368
  return nugetPaths;
18283
19369
  try {
18284
- for (const entry of readdirSync7(nugetPackageDir, { withFileTypes: true })) {
19370
+ for (const entry of readdirSync8(nugetPackageDir, { withFileTypes: true })) {
18285
19371
  if (!entry.isDirectory())
18286
19372
  continue;
18287
19373
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
18288
19374
  continue;
18289
- nugetPaths.push(join19(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join19(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
19375
+ nugetPaths.push(join20(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join20(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
18290
19376
  }
18291
19377
  } catch {}
18292
19378
  return nugetPaths;
@@ -18306,6 +19392,8 @@ function findSystemOnnxRuntime2() {
18306
19392
  continue;
18307
19393
  const version = detectOrtVersion(dir);
18308
19394
  if (!version) {
19395
+ if (isWindowsSystem32Directory2(dir))
19396
+ continue;
18309
19397
  unknownVersionPaths.push(dir);
18310
19398
  continue;
18311
19399
  }
@@ -18316,12 +19404,12 @@ function findSystemOnnxRuntime2() {
18316
19404
  return unknownVersionPaths[0] ?? null;
18317
19405
  }
18318
19406
  function findCachedOnnxRuntime(storageDir) {
18319
- const ortDir = join19(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
19407
+ const ortDir = join20(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
18320
19408
  const libName = getOnnxLibraryName();
18321
- if (existsSync17(join19(ortDir, libName)))
19409
+ if (existsSync18(join20(ortDir, libName)))
18322
19410
  return ortDir;
18323
- const libSubdir = join19(ortDir, "lib");
18324
- if (existsSync17(join19(libSubdir, libName)))
19411
+ const libSubdir = join20(ortDir, "lib");
19412
+ if (existsSync18(join20(libSubdir, libName)))
18325
19413
  return libSubdir;
18326
19414
  return null;
18327
19415
  }
@@ -18342,11 +19430,11 @@ function parseOrtVersionFromDirectoryPath(value) {
18342
19430
  return null;
18343
19431
  }
18344
19432
  function detectOrtVersion(libDir) {
18345
- if (!existsSync17(libDir))
19433
+ if (!existsSync18(libDir))
18346
19434
  return null;
18347
19435
  const libName = getOnnxLibraryName();
18348
19436
  try {
18349
- const entries = readdirSync7(libDir);
19437
+ const entries = readdirSync8(libDir);
18350
19438
  const barePrefix = libName.replace(/\.(so|dylib|dll)$/, "");
18351
19439
  const expectedPrefix = process.platform === "win32" ? barePrefix.toLowerCase() : barePrefix;
18352
19440
  for (const entry of entries) {
@@ -18357,8 +19445,8 @@ function detectOrtVersion(libDir) {
18357
19445
  if (version)
18358
19446
  return version;
18359
19447
  }
18360
- const base = join19(libDir, libName);
18361
- if (existsSync17(base)) {
19448
+ const base = join20(libDir, libName);
19449
+ if (existsSync18(base)) {
18362
19450
  try {
18363
19451
  const real = realpathSync4(base);
18364
19452
  const version = parseOrtVersionFromPath(real) ?? parseOrtVersionFromDirectoryPath(real);
@@ -18393,10 +19481,10 @@ import {
18393
19481
  accessSync,
18394
19482
  closeSync as closeSync6,
18395
19483
  constants,
18396
- existsSync as existsSync18,
19484
+ existsSync as existsSync19,
18397
19485
  openSync as openSync6,
18398
19486
  readSync as readSync3,
18399
- statSync as statSync11
19487
+ statSync as statSync12
18400
19488
  } from "node:fs";
18401
19489
  async function collectDiagnostics(adapters) {
18402
19490
  const cliVersion = getSelfVersion();
@@ -18431,7 +19519,7 @@ async function diagnoseHarness(adapter) {
18431
19519
  const logPath = adapter.getLogFile();
18432
19520
  const pluginCache = adapter.getPluginCacheInfo();
18433
19521
  const storageAccessible = (() => {
18434
- if (!existsSync18(storage))
19522
+ if (!existsSync19(storage))
18435
19523
  return false;
18436
19524
  try {
18437
19525
  accessSync(storage, constants.R_OK | constants.W_OK);
@@ -18441,8 +19529,10 @@ async function diagnoseHarness(adapter) {
18441
19529
  }
18442
19530
  })();
18443
19531
  const describeStorage = "describeStorageSubtrees" in adapter && typeof adapter.describeStorageSubtrees === "function" ? adapter.describeStorageSubtrees() : {};
19532
+ const legacyDuplication = summarizeLegacyPartitionDuplication(storage);
18444
19533
  const semanticEnabled = aftEnabled && (aftConfigRead.value?.semantic_search === true || aftConfigRead.value?.experimental_semantic_search === true);
18445
19534
  const systemOrtDir = findSystemOnnxRuntime2();
19535
+ const ignoredSystemOrtDir = systemOrtDir ? null : findIgnoredWindowsSystemOnnxRuntime();
18446
19536
  const cachedOrtDir = findCachedOnnxRuntime(storage);
18447
19537
  const systemVersion = systemOrtDir ? detectOrtVersion(systemOrtDir) : null;
18448
19538
  const cachedVersion = cachedOrtDir ? detectOrtVersion(cachedOrtDir) : null;
@@ -18454,7 +19544,7 @@ async function diagnoseHarness(adapter) {
18454
19544
  pluginRegistered: adapter.hasPluginEntry(),
18455
19545
  configPaths,
18456
19546
  aftConfig: {
18457
- exists: existsSync18(configPaths.aftConfig),
19547
+ exists: existsSync19(configPaths.aftConfig),
18458
19548
  ...aftConfigRead.error ? { parseError: aftConfigRead.error } : {},
18459
19549
  enabled: aftEnabled,
18460
19550
  ...aftEnabledSource ? { enabledSource: aftEnabledSource } : {},
@@ -18463,15 +19553,18 @@ async function diagnoseHarness(adapter) {
18463
19553
  pluginCache,
18464
19554
  storageDir: {
18465
19555
  path: storage,
18466
- exists: existsSync18(storage),
19556
+ exists: existsSync19(storage),
18467
19557
  accessible: storageAccessible,
18468
- sizesByKey: describeStorage
19558
+ sizesByKey: describeStorage,
19559
+ ...legacyDuplication.totalPartitions > 0 ? { legacyDuplication } : {}
18469
19560
  },
18470
19561
  onnxRuntime: {
18471
19562
  required: semanticEnabled,
18472
19563
  systemPath: systemOrtDir,
18473
19564
  systemVersion,
18474
19565
  systemCompatible: systemVersion ? isOrtVersionCompatible(systemVersion) : null,
19566
+ ignoredSystemPath: ignoredSystemOrtDir,
19567
+ ignoredSystemReason: ignoredSystemOrtDir ? "version unreadable (Windows system copy) — ignored" : null,
18475
19568
  cachedPath: cachedOrtDir,
18476
19569
  cachedVersion,
18477
19570
  cachedCompatible: cachedVersion ? isOrtVersionCompatible(cachedVersion) : null,
@@ -18481,8 +19574,8 @@ async function diagnoseHarness(adapter) {
18481
19574
  },
18482
19575
  logFile: {
18483
19576
  path: logPath,
18484
- exists: existsSync18(logPath),
18485
- sizeKb: existsSync18(logPath) ? Math.round(statSync11(logPath).size / 1024) : 0
19577
+ exists: existsSync19(logPath),
19578
+ sizeKb: existsSync19(logPath) ? Math.round(statSync12(logPath).size / 1024) : 0
18486
19579
  }
18487
19580
  };
18488
19581
  }
@@ -18637,7 +19730,7 @@ function collectDiagnosticIssues(report) {
18637
19730
  code: "onnx_missing",
18638
19731
  severity: "medium",
18639
19732
  scope: h2.displayName,
18640
- message: "ONNX Runtime is required for semantic search but was not detected.",
19733
+ 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
19734
  remediation: `Run \`aft doctor --fix\` or install ONNX Runtime manually (${h2.onnxRuntime.installHint}).`
18642
19735
  });
18643
19736
  }
@@ -18678,14 +19771,14 @@ function formatDiagnosticIssuesSection(report) {
18678
19771
  return lines;
18679
19772
  }
18680
19773
  function tailLogFile(path2, lines) {
18681
- if (!existsSync18(path2))
19774
+ if (!existsSync19(path2))
18682
19775
  return "";
18683
19776
  if (lines <= 0)
18684
19777
  return "";
18685
19778
  const chunkSize = 64 * 1024;
18686
19779
  let fd = null;
18687
19780
  try {
18688
- const size = statSync11(path2).size;
19781
+ const size = statSync12(path2).size;
18689
19782
  fd = openSync6(path2, "r");
18690
19783
  const chunks = [];
18691
19784
  let position = size;
@@ -18718,6 +19811,7 @@ var init_diagnostics = __esm(async () => {
18718
19811
  init_dist2();
18719
19812
  init_binary_cache();
18720
19813
  init_jsonc();
19814
+ init_legacy_storage();
18721
19815
  init_lsp_cache();
18722
19816
  init_onnx();
18723
19817
  init_sanitize();
@@ -18865,34 +19959,42 @@ var init_issue_body = __esm(() => {
18865
19959
  });
18866
19960
 
18867
19961
  // src/lib/onnx-fix.ts
18868
- import { existsSync as existsSync19, rmSync as rmSync6 } from "node:fs";
18869
- import { join as join20 } from "node:path";
19962
+ import { existsSync as existsSync20, rmSync as rmSync6 } from "node:fs";
19963
+ import { join as join21 } from "node:path";
18870
19964
  function findOnnxFixCandidates(report) {
18871
19965
  const candidates = [];
18872
19966
  for (const harness of report.harnesses) {
18873
19967
  if (!harness.onnxRuntime.required)
18874
19968
  continue;
18875
- if (!harness.storageDir.exists)
18876
- continue;
18877
- const storageOnnxDir = join20(harness.storageDir.path, "onnxruntime");
19969
+ const storageOnnxDir = join21(harness.storageDir.path, "onnxruntime");
18878
19970
  const systemTooOld = harness.onnxRuntime.systemPath !== null && harness.onnxRuntime.systemCompatible === false;
18879
19971
  const cachedTooOld = harness.onnxRuntime.cachedPath !== null && harness.onnxRuntime.cachedCompatible === false;
18880
19972
  const hasCompatibleCached = harness.onnxRuntime.cachedCompatible === true;
18881
19973
  if (cachedTooOld) {
18882
19974
  candidates.push({
18883
19975
  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.`,
19976
+ 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
19977
  storageOnnxDir,
18886
- storageOnnxBytes: existsSync19(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
19978
+ storageOnnxBytes: existsSync20(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
18887
19979
  });
18888
19980
  continue;
18889
19981
  }
18890
19982
  if (systemTooOld && !hasCompatibleCached) {
18891
19983
  candidates.push({
18892
19984
  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.`,
19985
+ 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.`,
19986
+ storageOnnxDir,
19987
+ storageOnnxBytes: existsSync20(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
19988
+ });
19989
+ continue;
19990
+ }
19991
+ if (!harness.onnxRuntime.systemPath && !harness.onnxRuntime.cachedPath) {
19992
+ const ignoredCopy = harness.onnxRuntime.ignoredSystemPath ? ` The Windows system copy at ${harness.onnxRuntime.ignoredSystemPath} was ignored because its version is unreadable.` : "";
19993
+ candidates.push({
19994
+ harness,
19995
+ reason: `no compatible ONNX Runtime is installed.${ignoredCopy} AFT will download v1.24 into managed storage.`,
18894
19996
  storageOnnxDir,
18895
- storageOnnxBytes: existsSync19(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
19997
+ storageOnnxBytes: existsSync20(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
18896
19998
  });
18897
19999
  }
18898
20000
  }
@@ -18900,58 +20002,74 @@ function findOnnxFixCandidates(report) {
18900
20002
  }
18901
20003
  async function runOnnxFix(adapters, report, options = {}) {
18902
20004
  const candidates = findOnnxFixCandidates(report);
18903
- if (candidates.length === 0) {
20005
+ if (candidates.length === 0)
18904
20006
  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)})`);
20007
+ log2.warn(`Found ${candidates.length} ONNX Runtime issue(s) that --fix can repair with an AFT-managed runtime:`);
20008
+ for (const candidate of candidates) {
20009
+ log2.info(` ${candidate.harness.displayName}: ${candidate.reason}`);
20010
+ if (candidate.storageOnnxBytes > 0) {
20011
+ log2.info(` will delete: ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)})`);
18911
20012
  } else {
18912
- log2.info(` no AFT-managed ONNX cache to delete; nothing to reclaim`);
20013
+ log2.info(" no AFT-managed ONNX cache to delete");
18913
20014
  }
18914
20015
  }
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");
20016
+ 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
20017
  const confirmFn = options.confirmFn ?? confirm2;
18917
20018
  const proceed = options.yes ? true : await confirmFn("Proceed with the fixes above?", true);
18918
20019
  if (!proceed) {
18919
20020
  log2.info("Skipped — no changes made.");
18920
20021
  return null;
18921
20022
  }
18922
- const result = { cleared: 0, bytesReclaimed: 0, errors: [] };
20023
+ const result = { cleared: 0, installed: 0, bytesReclaimed: 0, errors: [] };
18923
20024
  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;
20025
+ const ensureFn = options.ensureFn ?? ensureOnnxRuntime;
20026
+ for (const candidate of candidates) {
20027
+ if (existsSync20(candidate.storageOnnxDir)) {
20028
+ try {
20029
+ rmFn(candidate.storageOnnxDir, { recursive: true, force: true });
20030
+ result.cleared += 1;
20031
+ result.bytesReclaimed += candidate.storageOnnxBytes;
20032
+ log2.success(`${candidate.harness.displayName}: cleared ${candidate.storageOnnxDir} (reclaimed ${formatBytes(candidate.storageOnnxBytes)})`);
20033
+ } catch (err) {
20034
+ const message = err instanceof Error ? err.message : String(err);
20035
+ log2.error(`${candidate.harness.displayName}: failed to clear ${candidate.storageOnnxDir}: ${message}`);
20036
+ result.errors.push({ path: candidate.storageOnnxDir, error: message });
20037
+ continue;
20038
+ }
18928
20039
  }
18929
20040
  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)})`);
20041
+ log2.info(`${candidate.harness.displayName}: downloading managed ONNX Runtime…`);
20042
+ const installedPath = await ensureFn(candidate.harness.storageDir.path);
20043
+ if (!installedPath) {
20044
+ const message = "managed ONNX Runtime download was unavailable";
20045
+ log2.error(`${candidate.harness.displayName}: ${message}`);
20046
+ result.errors.push({ path: candidate.storageOnnxDir, error: message });
20047
+ continue;
20048
+ }
20049
+ result.installed += 1;
20050
+ log2.success(`${candidate.harness.displayName}: ONNX Runtime installed at ${installedPath}`);
18934
20051
  } 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 });
20052
+ const message = err instanceof Error ? err.message : String(err);
20053
+ log2.error(`${candidate.harness.displayName}: ONNX Runtime download failed: ${message}`);
20054
+ result.errors.push({ path: candidate.storageOnnxDir, error: message });
18938
20055
  }
18939
20056
  }
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");
20057
+ if (result.installed > 0) {
20058
+ note("Restart your AFT-using harness (OpenCode / Pi) so semantic indexing uses the newly installed managed runtime.", "Next step");
18942
20059
  }
18943
20060
  return result;
18944
20061
  }
18945
20062
  var init_onnx_fix = __esm(() => {
20063
+ init_dist2();
18946
20064
  init_fs_util();
18947
20065
  init_prompts();
18948
20066
  });
18949
20067
 
18950
20068
  // 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";
20069
+ import { existsSync as existsSync21, readdirSync as readdirSync9, readFileSync as readFileSync10, statSync as statSync13 } from "node:fs";
20070
+ import { createRequire as createRequire5 } from "node:module";
20071
+ import { homedir as homedir18 } from "node:os";
20072
+ import { basename as basename4, join as join22 } from "node:path";
18955
20073
  function listRecentSessions(adapter) {
18956
20074
  try {
18957
20075
  if (adapter.kind === "opencode")
@@ -18980,12 +20098,12 @@ function mapOpenCodeSessionRows(rows) {
18980
20098
  }).filter((session) => session !== null).sort((a3, b2) => b2.lastActivity - a3.lastActivity).slice(0, MAX_RECENT_SESSIONS);
18981
20099
  }
18982
20100
  function listRecentOpenCodeSessions() {
18983
- const dbPath = join21(getXdgDataHome(), "opencode", "opencode.db");
18984
- if (!existsSync20(dbPath))
20101
+ const dbPath = join22(getXdgDataHome(), "opencode", "opencode.db");
20102
+ if (!existsSync21(dbPath))
18985
20103
  return [];
18986
20104
  let db = null;
18987
20105
  try {
18988
- const require2 = createRequire4(import.meta.url);
20106
+ const require2 = createRequire5(import.meta.url);
18989
20107
  const sqlite = require2("node:sqlite");
18990
20108
  db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
18991
20109
  const rows = db.prepare("SELECT id, title, time_updated FROM session ORDER BY time_updated DESC LIMIT 5").all();
@@ -19000,22 +20118,22 @@ function listRecentOpenCodeSessions() {
19000
20118
  }
19001
20119
  function getXdgDataHome() {
19002
20120
  const xdgDataHome = process.env.XDG_DATA_HOME;
19003
- return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join21(homedir17(), ".local", "share");
20121
+ return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join22(homedir18(), ".local", "share");
19004
20122
  }
19005
20123
  function listRecentPiSessions() {
19006
- return listPiSessionsFromDir(join21(getHomeDir(), ".pi", "agent", "sessions"));
20124
+ return listPiSessionsFromDir(join22(getHomeDir(), ".pi", "agent", "sessions"));
19007
20125
  }
19008
20126
  function getHomeDir() {
19009
20127
  const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
19010
- return envHome && envHome.length > 0 ? envHome : homedir17();
20128
+ return envHome && envHome.length > 0 ? envHome : homedir18();
19011
20129
  }
19012
20130
  function listPiSessionsFromDir(sessionsDir) {
19013
20131
  try {
19014
- if (!existsSync20(sessionsDir))
20132
+ if (!existsSync21(sessionsDir))
19015
20133
  return [];
19016
20134
  const files = collectJsonlFiles(sessionsDir).map((filePath) => {
19017
20135
  try {
19018
- const stats = statSync12(filePath);
20136
+ const stats = statSync13(filePath);
19019
20137
  return { filePath, mtimeMs: stats.mtimeMs };
19020
20138
  } catch {
19021
20139
  return null;
@@ -19044,12 +20162,12 @@ function collectJsonlFiles(root) {
19044
20162
  continue;
19045
20163
  let entries;
19046
20164
  try {
19047
- entries = readdirSync8(dir, { withFileTypes: true });
20165
+ entries = readdirSync9(dir, { withFileTypes: true });
19048
20166
  } catch {
19049
20167
  continue;
19050
20168
  }
19051
20169
  for (const entry of entries) {
19052
- const path2 = join21(dir, entry.name);
20170
+ const path2 = join22(dir, entry.name);
19053
20171
  if (entry.isDirectory()) {
19054
20172
  stack.push(path2);
19055
20173
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -19149,17 +20267,17 @@ __export(exports_doctor, {
19149
20267
  import { execFileSync as execFileSync3 } from "node:child_process";
19150
20268
  import {
19151
20269
  chmodSync as chmodSync4,
19152
- existsSync as existsSync21,
20270
+ existsSync as existsSync22,
19153
20271
  mkdirSync as mkdirSync7,
19154
20272
  mkdtempSync,
19155
20273
  readFileSync as readFileSync11,
19156
20274
  realpathSync as realpathSync5,
19157
20275
  rmSync as rmSync7,
19158
- statSync as statSync13,
20276
+ statSync as statSync14,
19159
20277
  writeFileSync as writeFileSync5
19160
20278
  } from "node:fs";
19161
- import { tmpdir as tmpdir4 } from "node:os";
19162
- import { join as join22 } from "node:path";
20279
+ import { tmpdir as tmpdir2 } from "node:os";
20280
+ import { join as join23 } from "node:path";
19163
20281
  async function runDoctor(options) {
19164
20282
  if (options.issue) {
19165
20283
  return runIssueFlow(options.argv);
@@ -19228,6 +20346,8 @@ async function runDoctor(options) {
19228
20346
  }
19229
20347
  if (h2.onnxRuntime.systemPath) {
19230
20348
  parts.push(`system: ${h2.onnxRuntime.systemVersion ?? "unknown"}${h2.onnxRuntime.systemCompatible === false ? " (incompatible)" : ""}`);
20349
+ } else if (h2.onnxRuntime.ignoredSystemPath) {
20350
+ parts.push(`system: ${h2.onnxRuntime.ignoredSystemReason} at ${h2.onnxRuntime.ignoredSystemPath}`);
19231
20351
  }
19232
20352
  if (!h2.onnxRuntime.cachedPath && !h2.onnxRuntime.systemPath) {
19233
20353
  parts.push(`not installed — ${h2.onnxRuntime.installHint}`);
@@ -19324,7 +20444,7 @@ function clearOldBinaries() {
19324
20444
  errors: [],
19325
20445
  keptVersion: keepTag
19326
20446
  };
19327
- if (!existsSync21(info.path)) {
20447
+ if (!existsSync22(info.path)) {
19328
20448
  log2.info(`Binary cache: nothing to clear at ${info.path}`);
19329
20449
  return result;
19330
20450
  }
@@ -19334,10 +20454,10 @@ function clearOldBinaries() {
19334
20454
  return result;
19335
20455
  }
19336
20456
  for (const version of stale) {
19337
- const dir = join22(info.path, version);
20457
+ const dir = join23(info.path, version);
19338
20458
  let bytes = 0;
19339
20459
  try {
19340
- bytes = statSync13(dir).isDirectory() ? dirSize(dir) : 0;
20460
+ bytes = statSync14(dir).isDirectory() ? dirSize(dir) : 0;
19341
20461
  } catch {
19342
20462
  bytes = 0;
19343
20463
  }
@@ -19511,12 +20631,12 @@ function buildDoctorFixPlan(adapters, report) {
19511
20631
  if (candidate.storageOnnxBytes > 0) {
19512
20632
  items.push({
19513
20633
  kind: "onnx",
19514
- message: `Will delete AFT-managed ONNX cache at ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)})`
20634
+ message: `Will replace AFT-managed ONNX cache at ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)}) and download a compatible runtime`
19515
20635
  });
19516
20636
  } else {
19517
20637
  items.push({
19518
20638
  kind: "onnx",
19519
- message: `Will leave system ONNX untouched and refresh AFT-managed ONNX state for ${candidate.harness.displayName} on next start`
20639
+ message: `Will leave system ONNX untouched and download a compatible AFT-managed runtime for ${candidate.harness.displayName}`
19520
20640
  });
19521
20641
  }
19522
20642
  }
@@ -19648,7 +20768,8 @@ function logDoctorIssues(report) {
19648
20768
  }
19649
20769
  function formatDoctorStorageStatus(h2) {
19650
20770
  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)})`;
20771
+ const legacyDuplication = formatLegacyDuplication(h2.storageDir.legacyDuplication);
20772
+ return `${state} (${[formatStorageSizes(h2.storageDir.sizesByKey), legacyDuplication].filter((part) => Boolean(part)).join("; ")})`;
19652
20773
  }
19653
20774
  async function confirmBinaryDownloadDespitePluginSkew(report, argv) {
19654
20775
  const skews = findPluginCliVersionSkews(report);
@@ -19678,7 +20799,7 @@ function ensureStorageDirsForRegisteredPlugins(adapters) {
19678
20799
  if (!adapter.isInstalled() || !adapter.hasPluginEntry())
19679
20800
  continue;
19680
20801
  const storageDir = adapter.getStorageDir();
19681
- if (existsSync21(storageDir))
20802
+ if (existsSync22(storageDir))
19682
20803
  continue;
19683
20804
  mkdirSync7(storageDir, { recursive: true });
19684
20805
  summary.created += 1;
@@ -19760,6 +20881,12 @@ function formatStorageSizes(sizes) {
19760
20881
  const parts = Object.entries(sizes).filter(([, size]) => size > 0).map(([key, size]) => `${key}: ${formatBytes(size)}`);
19761
20882
  return parts.length > 0 ? parts.join(", ") : "empty";
19762
20883
  }
20884
+ function formatLegacyDuplication(summary) {
20885
+ if (!summary || summary.totalPartitions === 0)
20886
+ return null;
20887
+ const byHarness = summary.byHarness.map((entry) => `${entry.harness}: ${entry.partitions} partition(s) / ${formatBytes(entry.bytes)}`).join("; ");
20888
+ return `legacy duplication: ${summary.totalPartitions} partition(s), ${formatBytes(summary.totalBytes)} total [${byHarness}]`;
20889
+ }
19763
20890
  function isInteractiveTerminal() {
19764
20891
  return process.stdin.isTTY === true && process.stdout.isTTY === true;
19765
20892
  }
@@ -19791,11 +20918,11 @@ function deriveIssueTitleFromBody(body) {
19791
20918
  function writeIssueReviewFile(body) {
19792
20919
  let reviewDir = null;
19793
20920
  try {
19794
- reviewDir = mkdtempSync(join22(tmpdir4(), "aft-issue-"));
20921
+ reviewDir = mkdtempSync(join23(tmpdir2(), "aft-issue-"));
19795
20922
  if (process.platform !== "win32") {
19796
20923
  chmodSync4(reviewDir, 448);
19797
20924
  }
19798
- const outPath = join22(reviewDir, "issue.md");
20925
+ const outPath = join23(reviewDir, "issue.md");
19799
20926
  writeFileSync5(outPath, `${body}
19800
20927
  `, { encoding: "utf8", mode: 384, flag: "wx" });
19801
20928
  return { path: outPath, realPath: realpathSync5(outPath) };