@cortexkit/aft 0.56.2 → 0.57.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
@@ -2717,11 +2717,34 @@ var init_npm_resolver = __esm(() => {
2717
2717
  };
2718
2718
  });
2719
2719
 
2720
- // ../aft-bridge/dist/onnx-runtime.js
2720
+ // ../aft-bridge/dist/tar-executable.js
2721
2721
  import { execFileSync } from "node:child_process";
2722
+ import { existsSync as existsSync4 } from "node:fs";
2723
+ import { join as join7 } from "node:path";
2724
+ function windowsTarExecutable(options = {}) {
2725
+ const platform = options.platform ?? process.platform;
2726
+ if (platform !== "win32")
2727
+ return "tar";
2728
+ const env = options.env ?? process.env;
2729
+ const systemTar = join7(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
2730
+ return (options.exists ?? existsSync4)(systemTar) ? systemTar : "tar";
2731
+ }
2732
+ function execTarExtractionSync(args, timeout) {
2733
+ const executable = windowsTarExecutable();
2734
+ try {
2735
+ execFileSync(executable, args, { stdio: "pipe", timeout });
2736
+ } catch (cause) {
2737
+ const detail = cause instanceof Error ? cause.message : String(cause);
2738
+ throw new Error(`tar extraction failed using ${executable}: ${detail}`, { cause });
2739
+ }
2740
+ }
2741
+ var init_tar_executable = () => {};
2742
+
2743
+ // ../aft-bridge/dist/onnx-runtime.js
2744
+ import { execFileSync as execFileSync2 } from "node:child_process";
2722
2745
  import { createHash as createHash3 } from "node:crypto";
2723
- import { chmodSync as chmodSync3, closeSync as closeSync3, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync3, openSync as openSync3, readdirSync as readdirSync3, readFileSync as readFileSync4, readlinkSync, realpathSync, rmSync as rmSync2, statSync as statSync3, symlinkSync, unlinkSync as unlinkSync3, writeFileSync } from "node:fs";
2724
- import { basename, dirname as dirname3, isAbsolute as isAbsolute3, join as join7, relative, resolve as resolve4, win32 } from "node:path";
2746
+ import { chmodSync as chmodSync3, closeSync as closeSync3, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync3, openSync as openSync3, readdirSync as readdirSync3, readFileSync as readFileSync4, readlinkSync, realpathSync, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync3, symlinkSync, unlinkSync as unlinkSync3, writeFileSync } from "node:fs";
2747
+ import { basename, dirname as dirname3, isAbsolute as isAbsolute3, join as join8, relative, resolve as resolve4, win32 } from "node:path";
2725
2748
  import { Readable as Readable2 } from "node:stream";
2726
2749
  import { pipeline as pipeline2 } from "node:stream/promises";
2727
2750
  function getPlatformInfo() {
@@ -2733,6 +2756,9 @@ function getPlatformInfo() {
2733
2756
  const ortArch = platformKey ? platformKey.split("-")[1] : process.arch;
2734
2757
  return platformMap[ortArch] || null;
2735
2758
  }
2759
+ function isOrtAutoDownloadSupported() {
2760
+ return getPlatformInfo() !== null;
2761
+ }
2736
2762
  function getManualInstallHint() {
2737
2763
  if (process.platform === "darwin" && process.arch === "x64") {
2738
2764
  return "brew install onnxruntime";
@@ -2744,11 +2770,11 @@ function getManualInstallHint() {
2744
2770
  }
2745
2771
  async function ensureOnnxRuntime(storageDir) {
2746
2772
  const info = getPlatformInfo();
2747
- const ortVersionDir = join7(storageDir, "onnxruntime", ORT_VERSION);
2773
+ const ortVersionDir = join8(storageDir, "onnxruntime", ORT_VERSION);
2748
2774
  const libName = info?.libName ?? "libonnxruntime.dylib";
2749
2775
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
2750
- const libPath = join7(resolvedOrtDir, libName);
2751
- if (existsSync4(libPath)) {
2776
+ const libPath = join8(resolvedOrtDir, libName);
2777
+ if (existsSync5(libPath)) {
2752
2778
  const meta = readOnnxInstalledMeta(ortVersionDir);
2753
2779
  if (meta?.sha256) {
2754
2780
  try {
@@ -2777,9 +2803,9 @@ async function ensureOnnxRuntime(storageDir) {
2777
2803
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
2778
2804
  return null;
2779
2805
  }
2780
- const onnxBaseDir = join7(storageDir, "onnxruntime");
2806
+ const onnxBaseDir = join8(storageDir, "onnxruntime");
2781
2807
  mkdirSync3(onnxBaseDir, { recursive: true });
2782
- const lockPath = join7(onnxBaseDir, ONNX_LOCK_FILE);
2808
+ const lockPath = join8(onnxBaseDir, ONNX_LOCK_FILE);
2783
2809
  cleanupAbandonedStagingDirs(onnxBaseDir);
2784
2810
  if (!acquireLock(lockPath)) {
2785
2811
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -2798,7 +2824,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
2798
2824
  for (const entry of entries) {
2799
2825
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
2800
2826
  continue;
2801
- const stagingDir = join7(onnxBaseDir, entry);
2827
+ const stagingDir = join8(onnxBaseDir, entry);
2802
2828
  const parts = entry.split(".");
2803
2829
  const pidStr = parts[parts.length - 2];
2804
2830
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -2835,7 +2861,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
2835
2861
  }
2836
2862
  function cleanupIncompleteTargetIfUnowned(ortDir) {
2837
2863
  try {
2838
- if (existsSync4(ortDir) && !existsSync4(join7(ortDir, ONNX_INSTALLED_META_FILE))) {
2864
+ if (existsSync5(ortDir) && !existsSync5(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
2839
2865
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
2840
2866
  rmSync2(ortDir, { recursive: true, force: true });
2841
2867
  }
@@ -2876,8 +2902,8 @@ function detectOnnxVersion(libDir, libName) {
2876
2902
  if (version)
2877
2903
  return version;
2878
2904
  }
2879
- const base = join7(libDir, libName);
2880
- if (existsSync4(base)) {
2905
+ const base = join8(libDir, libName);
2906
+ if (existsSync5(base)) {
2881
2907
  try {
2882
2908
  const real = realpathSync(base);
2883
2909
  const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
@@ -2943,10 +2969,10 @@ function directoryContainsLibrary(dir, libName) {
2943
2969
  }
2944
2970
  }
2945
2971
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
2946
- if (existsSync4(join7(ortVersionDir, libName)))
2972
+ if (existsSync5(join8(ortVersionDir, libName)))
2947
2973
  return ortVersionDir;
2948
- const libSubdir = join7(ortVersionDir, "lib");
2949
- if (existsSync4(join7(libSubdir, libName)))
2974
+ const libSubdir = join8(ortVersionDir, "lib");
2975
+ if (existsSync5(join8(libSubdir, libName)))
2950
2976
  return libSubdir;
2951
2977
  return ortVersionDir;
2952
2978
  }
@@ -2961,13 +2987,13 @@ function findSystemOnnxRuntime(libName) {
2961
2987
  } else if (process.platform === "win32") {
2962
2988
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
2963
2989
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
2964
- searchPaths.push(join7(programFiles, "onnxruntime", "lib"), join7(programFiles, "Microsoft ONNX Runtime", "lib"), join7(programFiles, "Microsoft Machine Learning", "lib"), join7(programFilesX86, "onnxruntime", "lib"), ...(() => {
2990
+ searchPaths.push(join8(programFiles, "onnxruntime", "lib"), join8(programFiles, "Microsoft ONNX Runtime", "lib"), join8(programFiles, "Microsoft Machine Learning", "lib"), join8(programFilesX86, "onnxruntime", "lib"), ...(() => {
2965
2991
  const nugetPaths = [];
2966
2992
  const userProfile = process.env.USERPROFILE ?? "";
2967
2993
  if (!userProfile)
2968
2994
  return nugetPaths;
2969
- const nugetPackageDir = join7(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
2970
- if (!existsSync4(nugetPackageDir))
2995
+ const nugetPackageDir = join8(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
2996
+ if (!existsSync5(nugetPackageDir))
2971
2997
  return nugetPaths;
2972
2998
  try {
2973
2999
  for (const entry of readdirSync3(nugetPackageDir, { withFileTypes: true })) {
@@ -2975,7 +3001,7 @@ function findSystemOnnxRuntime(libName) {
2975
3001
  continue;
2976
3002
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
2977
3003
  continue;
2978
- nugetPaths.push(join7(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join7(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
3004
+ nugetPaths.push(join8(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join8(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
2979
3005
  }
2980
3006
  } catch (err) {
2981
3007
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -2997,11 +3023,11 @@ function findSystemOnnxRuntime(libName) {
2997
3023
  });
2998
3024
  const unknownVersionPaths = [];
2999
3025
  for (const dir of uniquePaths) {
3000
- const libPath = join7(dir, libName);
3026
+ const libPath = join8(dir, libName);
3001
3027
  if (process.platform === "win32") {
3002
3028
  if (!directoryContainsLibrary(dir, libName))
3003
3029
  continue;
3004
- } else if (!existsSync4(libPath)) {
3030
+ } else if (!existsSync5(libPath)) {
3005
3031
  continue;
3006
3032
  }
3007
3033
  const version = detectOnnxVersion(dir, libName);
@@ -3067,7 +3093,7 @@ function validateExtractedTree(stagingRoot) {
3067
3093
  const walk = (dir) => {
3068
3094
  const entries = readdirSync3(dir);
3069
3095
  for (const entry of entries) {
3070
- const fullPath = join7(dir, entry);
3096
+ const fullPath = join8(dir, entry);
3071
3097
  const lst = lstatSync(fullPath);
3072
3098
  if (lst.isSymbolicLink()) {
3073
3099
  const linkTarget = readlinkSync(fullPath);
@@ -3100,34 +3126,32 @@ async function downloadOnnxRuntime(info, targetDir) {
3100
3126
  const url = `https://github.com/${ORT_REPO}/releases/download/v${ORT_VERSION}/${info.assetName}.${info.archiveType === "tgz" ? "tgz" : "zip"}`;
3101
3127
  log(`Downloading ONNX Runtime v${ORT_VERSION} for ${process.platform}/${process.arch}...`);
3102
3128
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
3129
+ const extractionRoot = join8(tmpDir, "extract");
3130
+ const stagedInstallDir = join8(tmpDir, "install");
3103
3131
  try {
3104
- mkdirSync3(tmpDir, { recursive: true });
3105
- const archivePath = join7(tmpDir, `onnxruntime.${info.archiveType}`);
3132
+ mkdirSync3(extractionRoot, { recursive: true });
3133
+ const archivePath = join8(tmpDir, `onnxruntime.${info.archiveType}`);
3106
3134
  await downloadFileWithCap(url, archivePath);
3107
3135
  const archiveSha256 = sha256File(archivePath);
3108
3136
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
3109
3137
  if (info.archiveType === "tgz") {
3110
- execFileSync("tar", ["xzf", archivePath, "-C", tmpDir], {
3111
- stdio: "pipe",
3112
- timeout: 120000
3113
- });
3138
+ execTarExtractionSync(["xzf", archivePath, "-C", extractionRoot], 120000);
3114
3139
  } else {
3115
- await extractZipArchive(archivePath, tmpDir);
3140
+ await extractZipArchive(archivePath, extractionRoot);
3116
3141
  }
3117
3142
  try {
3118
3143
  unlinkSync3(archivePath);
3119
3144
  } catch {}
3120
- validateExtractedTree(tmpDir);
3121
- const extractedDir = join7(tmpDir, info.assetName, "lib");
3122
- if (!existsSync4(extractedDir)) {
3145
+ validateExtractedTree(extractionRoot);
3146
+ const extractedDir = join8(extractionRoot, info.assetName, "lib");
3147
+ if (!existsSync5(extractedDir)) {
3123
3148
  throw new Error(`Expected directory not found: ${extractedDir}`);
3124
3149
  }
3125
- mkdirSync3(targetDir, { recursive: true });
3126
3150
  const libFiles = readdirSync3(extractedDir).filter((f) => f.startsWith("libonnxruntime") || f.startsWith("onnxruntime"));
3127
3151
  const realFiles = [];
3128
3152
  const symlinks = [];
3129
3153
  for (const libFile of libFiles) {
3130
- const src = join7(extractedDir, libFile);
3154
+ const src = join8(extractedDir, libFile);
3131
3155
  try {
3132
3156
  const stat = lstatSync(src);
3133
3157
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
@@ -3141,15 +3165,11 @@ async function downloadOnnxRuntime(info, targetDir) {
3141
3165
  realFiles.push(libFile);
3142
3166
  }
3143
3167
  }
3144
- copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
3145
- const libPath = join7(targetDir, info.libName);
3146
- let libHash = null;
3147
- try {
3148
- libHash = sha256File(libPath);
3149
- } catch (err) {
3150
- warn(`Could not hash newly-installed ONNX library at ${libPath}: ${err}`);
3151
- }
3152
- writeOnnxInstalledMeta(targetDir, ORT_VERSION, libHash, archiveSha256);
3168
+ copyOnnxLibraries(info, extractedDir, stagedInstallDir, realFiles, symlinks);
3169
+ const libPath = join8(stagedInstallDir, info.libName);
3170
+ const libHash = sha256File(libPath);
3171
+ writeOnnxInstalledMeta(stagedInstallDir, ORT_VERSION, libHash, archiveSha256);
3172
+ publishOnnxRuntime(stagedInstallDir, targetDir);
3153
3173
  rmSync2(tmpDir, { recursive: true, force: true });
3154
3174
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
3155
3175
  return targetDir;
@@ -3158,17 +3178,39 @@ async function downloadOnnxRuntime(info, targetDir) {
3158
3178
  try {
3159
3179
  rmSync2(tmpDir, { recursive: true, force: true });
3160
3180
  } catch {}
3161
- try {
3162
- rmSync2(targetDir, { recursive: true, force: true });
3163
- } catch {}
3164
3181
  return null;
3165
3182
  }
3166
3183
  }
3184
+ function publishOnnxRuntime(stagedInstallDir, targetDir) {
3185
+ const backupDir = `${targetDir}.backup.${process.pid}.${Date.now().toString(36)}`;
3186
+ const hadTarget = existsSync5(targetDir);
3187
+ if (hadTarget)
3188
+ renameSync3(targetDir, backupDir);
3189
+ try {
3190
+ renameSync3(stagedInstallDir, targetDir);
3191
+ } catch (installError) {
3192
+ if (hadTarget) {
3193
+ try {
3194
+ renameSync3(backupDir, targetDir);
3195
+ } catch (restoreError) {
3196
+ throw new Error(`ONNX Runtime replacement failed and the previous runtime could not be restored from ${backupDir}: ${restoreError}`, { cause: installError });
3197
+ }
3198
+ }
3199
+ throw installError;
3200
+ }
3201
+ if (hadTarget) {
3202
+ try {
3203
+ rmSync2(backupDir, { recursive: true, force: true });
3204
+ } catch (err) {
3205
+ warn(`Could not remove replaced ONNX Runtime backup at ${backupDir}: ${err}`);
3206
+ }
3207
+ }
3208
+ }
3167
3209
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
3168
3210
  const requiredLibs = new Set([info.libName]);
3169
3211
  for (const libFile of realFiles) {
3170
- const src = join7(extractedDir, libFile);
3171
- const dst = join7(targetDir, libFile);
3212
+ const src = join8(extractedDir, libFile);
3213
+ const dst = join8(targetDir, libFile);
3172
3214
  try {
3173
3215
  copyFile(src, dst);
3174
3216
  if (process.platform !== "win32") {
@@ -3184,11 +3226,11 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
3184
3226
  }
3185
3227
  const targetRoot = realpathSync(targetDir);
3186
3228
  for (const link of symlinks) {
3187
- const dst = join7(targetDir, link.name);
3229
+ const dst = join8(targetDir, link.name);
3188
3230
  try {
3189
3231
  unlinkSync3(dst);
3190
3232
  } catch {}
3191
- const dstForContainment = join7(targetRoot, link.name);
3233
+ const dstForContainment = join8(targetRoot, link.name);
3192
3234
  const resolvedTarget = resolve4(dirname3(dstForContainment), link.target);
3193
3235
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
3194
3236
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
@@ -3209,21 +3251,18 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
3209
3251
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
3210
3252
  }
3211
3253
  }
3212
- const requiredPath = join7(targetDir, info.libName);
3213
- if (!existsSync4(requiredPath)) {
3254
+ const requiredPath = join8(targetDir, info.libName);
3255
+ if (!existsSync5(requiredPath)) {
3214
3256
  rmSync2(targetDir, { recursive: true, force: true });
3215
3257
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
3216
3258
  }
3217
3259
  }
3218
3260
  async function extractZipArchive(archivePath, destinationDir) {
3219
3261
  if (process.platform === "win32") {
3220
- execFileSync("tar.exe", ["-xf", archivePath, "-C", destinationDir], {
3221
- stdio: "pipe",
3222
- timeout: 120000
3223
- });
3262
+ execTarExtractionSync(["-xf", archivePath, "-C", destinationDir], 120000);
3224
3263
  return;
3225
3264
  }
3226
- execFileSync("unzip", ["-q", archivePath, "-d", destinationDir], {
3265
+ execFileSync2("unzip", ["-q", archivePath, "-d", destinationDir], {
3227
3266
  stdio: "pipe",
3228
3267
  timeout: 120000
3229
3268
  });
@@ -3236,13 +3275,13 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
3236
3275
  ...sha256 ? { sha256 } : {},
3237
3276
  archiveSha256
3238
3277
  };
3239
- writeFileSync(join7(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
3278
+ writeFileSync(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
3240
3279
  } catch (err) {
3241
3280
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
3242
3281
  }
3243
3282
  }
3244
3283
  function readOnnxInstalledMeta(installDir) {
3245
- const path = join7(installDir, ONNX_INSTALLED_META_FILE);
3284
+ const path = join8(installDir, ONNX_INSTALLED_META_FILE);
3246
3285
  try {
3247
3286
  if (!statSync3(path).isFile())
3248
3287
  return null;
@@ -3354,7 +3393,7 @@ function isWindowsProcessAlive(pid) {
3354
3393
  if (!Number.isInteger(pid) || pid <= 0)
3355
3394
  return false;
3356
3395
  try {
3357
- const output = execFileSync("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
3396
+ const output = execFileSync2("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
3358
3397
  encoding: "utf8",
3359
3398
  timeout: 2000,
3360
3399
  windowsHide: true
@@ -3382,6 +3421,7 @@ var ORT_VERSION = "1.24.4", ORT_REPO = "microsoft/onnxruntime", MAX_DOWNLOAD_BYT
3382
3421
  var init_onnx_runtime = __esm(() => {
3383
3422
  init_active_logger();
3384
3423
  init_platform();
3424
+ init_tar_executable();
3385
3425
  MAX_DOWNLOAD_BYTES2 = 256 * 1024 * 1024;
3386
3426
  MAX_EXTRACT_BYTES = 1 * 1024 * 1024 * 1024;
3387
3427
  STALE_LOCK_MS = 5 * 60 * 1000;
@@ -3442,6 +3482,14 @@ var init_path_aliases = __esm(() => {
3442
3482
  ]);
3443
3483
  MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
3444
3484
  });
3485
+
3486
+ // ../aft-bridge/dist/semantic-status.js
3487
+ var SEMANTIC_PROGRESS_STATUSES, SEMANTIC_READY_STATUSES, SEMANTIC_INACTIVE_STATUSES;
3488
+ var init_semantic_status = __esm(() => {
3489
+ SEMANTIC_PROGRESS_STATUSES = new Set(["building", "loading"]);
3490
+ SEMANTIC_READY_STATUSES = new Set(["ready", "empty"]);
3491
+ SEMANTIC_INACTIVE_STATUSES = new Set(["disabled", "busy"]);
3492
+ });
3445
3493
  // ../aft-bridge/dist/index.js
3446
3494
  var init_dist2 = __esm(() => {
3447
3495
  init_active_logger();
@@ -3467,8 +3515,10 @@ var init_dist2 = __esm(() => {
3467
3515
  init_project_identity();
3468
3516
  init_resolver();
3469
3517
  init_revivable_transport();
3518
+ init_semantic_status();
3470
3519
  init_storage_paths();
3471
3520
  init_subc_transport();
3521
+ init_tar_executable();
3472
3522
  init_transport_factory();
3473
3523
  });
3474
3524
 
@@ -3485,10 +3535,10 @@ var init_paths2 = __esm(() => {
3485
3535
 
3486
3536
  // src/lib/binary-probe.ts
3487
3537
  import { execSync, spawnSync as spawnSync3 } from "node:child_process";
3488
- import { existsSync as existsSync5 } from "node:fs";
3538
+ import { existsSync as existsSync6, readdirSync as readdirSync4 } from "node:fs";
3489
3539
  import { createRequire } from "node:module";
3490
3540
  import { homedir as homedir6 } from "node:os";
3491
- import { join as join8 } from "node:path";
3541
+ import { join as join9 } from "node:path";
3492
3542
  async function loadPluginVersion() {
3493
3543
  try {
3494
3544
  const bridge = await Promise.resolve().then(() => (init_dist2(), {}));
@@ -3540,7 +3590,7 @@ function probeAftBinary(preferredVersion) {
3540
3590
  const candidates = [];
3541
3591
  for (const candidate of aftBinaryCandidates(preferredVersion)) {
3542
3592
  try {
3543
- if (!existsSync5(candidate))
3593
+ if (!existsSync6(candidate))
3544
3594
  continue;
3545
3595
  const result = spawnSync3(candidate, ["--version"], {
3546
3596
  stdio: ["ignore", "pipe", "pipe"],
@@ -3591,7 +3641,7 @@ function pushCandidate(candidates, candidate) {
3591
3641
  function firstExisting(candidates) {
3592
3642
  for (const candidate of candidates) {
3593
3643
  try {
3594
- if (!existsSync5(candidate))
3644
+ if (!existsSync6(candidate))
3595
3645
  continue;
3596
3646
  return candidate;
3597
3647
  } catch {}
@@ -3606,52 +3656,148 @@ function platformKey2(platform = process.platform, arch = process.arch) {
3606
3656
  };
3607
3657
  return table[platform]?.[arch] ?? null;
3608
3658
  }
3609
- function aftBinaryCandidates(preferredVersion) {
3610
- const candidates = [];
3659
+ function newestCachedBinary(cacheDir, binaryName) {
3660
+ let entries;
3661
+ try {
3662
+ entries = readdirSync4(cacheDir);
3663
+ } catch {
3664
+ return null;
3665
+ }
3666
+ let best = null;
3667
+ for (const entry of entries) {
3668
+ const version = entry.match(CACHE_VERSION_DIR)?.[1];
3669
+ if (!version)
3670
+ continue;
3671
+ const path = join9(cacheDir, entry, binaryName);
3672
+ try {
3673
+ if (!existsSync6(path))
3674
+ continue;
3675
+ } catch {
3676
+ continue;
3677
+ }
3678
+ if (!best || compareSemver(version, best.version) > 0)
3679
+ best = { version, path };
3680
+ }
3681
+ return best?.path ?? null;
3682
+ }
3683
+ function cacheLocation(preferredVersion) {
3684
+ const cacheDir = getAftBinaryCacheDir();
3685
+ const binaryName = getAftBinaryName();
3686
+ const label = "binary cache";
3687
+ const installedHere = "`aft doctor --fix` installs here";
3611
3688
  if (preferredVersion) {
3612
3689
  const tag = preferredVersion.startsWith("v") ? preferredVersion : `v${preferredVersion}`;
3613
- pushCandidate(candidates, join8(getAftBinaryCacheDir(), tag, getAftBinaryName()));
3690
+ return {
3691
+ label,
3692
+ paths: [join9(cacheDir, tag, binaryName)],
3693
+ emptyReason: `no ${tag}/${binaryName} under ${cacheDir} (${installedHere})`
3694
+ };
3614
3695
  }
3696
+ const newest = newestCachedBinary(cacheDir, binaryName);
3697
+ return {
3698
+ label,
3699
+ paths: newest ? [newest] : [],
3700
+ emptyReason: `no v<version>/${binaryName} under ${cacheDir} (${installedHere})`
3701
+ };
3702
+ }
3703
+ function platformPackageLocation() {
3704
+ const label = "npm platform package";
3615
3705
  const key = platformKey2();
3616
- if (key) {
3617
- try {
3618
- const require2 = createRequire(import.meta.url);
3619
- pushCandidate(candidates, require2.resolve(`@cortexkit/aft-${key}/bin/${getAftBinaryName()}`));
3620
- } catch {}
3706
+ if (!key) {
3707
+ return {
3708
+ label,
3709
+ paths: [],
3710
+ emptyReason: `no package published for ${process.platform}-${process.arch}`
3711
+ };
3621
3712
  }
3713
+ const packageName = `@cortexkit/aft-${key}`;
3714
+ try {
3715
+ const require2 = createRequire(import.meta.url);
3716
+ return {
3717
+ label,
3718
+ paths: [require2.resolve(`${packageName}/bin/${getAftBinaryName()}`)],
3719
+ emptyReason: `${packageName} not installed`
3720
+ };
3721
+ } catch {
3722
+ return { label, paths: [], emptyReason: `${packageName} not installed` };
3723
+ }
3724
+ }
3725
+ function pathLocation() {
3726
+ const lookup = process.platform === "win32" ? "where aft" : "which aft";
3727
+ const label = "PATH";
3728
+ let hits = [];
3622
3729
  try {
3623
- const lookup = process.platform === "win32" ? "where aft" : "which aft";
3624
3730
  const resolved = execSync(lookup, {
3625
3731
  stdio: "pipe",
3626
3732
  encoding: "utf-8",
3627
3733
  env: process.env
3628
3734
  }).trim();
3629
- for (const line of resolved.split(/\r?\n/)) {
3630
- const candidate = line.trim();
3631
- if (candidate && isNativeExecutable(candidate)) {
3632
- pushCandidate(candidates, candidate);
3633
- }
3634
- }
3735
+ hits = resolved.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
3635
3736
  } catch {}
3636
- pushCandidate(candidates, join8(homedir6(), ".cargo", "bin", getAftBinaryName()));
3737
+ const native = hits.filter((candidate) => isNativeExecutable(candidate));
3738
+ return {
3739
+ label,
3740
+ paths: native,
3741
+ emptyReason: hits.length > 0 ? `only non-native \`aft\` entries on PATH (${hits.join(", ")}), skipped because running them would re-enter this CLI` : `no \`aft\` on PATH (\`${lookup}\` found nothing)`
3742
+ };
3743
+ }
3744
+ function cargoLocation() {
3745
+ const path = join9(homedir6(), ".cargo", "bin", getAftBinaryName());
3746
+ return { label: "cargo install", paths: [path], emptyReason: `no ${path}` };
3747
+ }
3748
+ function aftBinarySearchLocations(preferredVersion) {
3749
+ return [
3750
+ cacheLocation(preferredVersion),
3751
+ platformPackageLocation(),
3752
+ pathLocation(),
3753
+ cargoLocation()
3754
+ ];
3755
+ }
3756
+ function aftBinaryCandidates(preferredVersion) {
3757
+ const candidates = [];
3758
+ for (const location of aftBinarySearchLocations(preferredVersion)) {
3759
+ for (const path of location.paths)
3760
+ pushCandidate(candidates, path);
3761
+ }
3637
3762
  return candidates;
3638
3763
  }
3764
+ function describeAftBinarySearch(preferredVersion) {
3765
+ return aftBinarySearchLocations(preferredVersion).map((location) => {
3766
+ const found = location.paths.filter((path) => {
3767
+ try {
3768
+ return existsSync6(path);
3769
+ } catch {
3770
+ return false;
3771
+ }
3772
+ });
3773
+ return `${location.label}: ${found.length > 0 ? found.join(", ") : location.emptyReason}`;
3774
+ });
3775
+ }
3776
+ function missingAftBinaryMessage(command, preferredVersion) {
3777
+ return [
3778
+ `${command} requires a native AFT binary and none was found. Searched:`,
3779
+ ...describeAftBinarySearch(preferredVersion).map((line) => ` - ${line}`),
3780
+ "`aft doctor --fix` installs into the binary cache directory named above; if it already reported success, that line is the directory this command searched — AFT_CACHE_DIR and XDG_CACHE_HOME change it."
3781
+ ].join(`
3782
+ `);
3783
+ }
3639
3784
  function findAftBinary(preferredVersion) {
3640
3785
  return firstExisting(aftBinaryCandidates(preferredVersion));
3641
3786
  }
3642
- var PLUGIN_VERSION, VERSION_LINE;
3787
+ var PLUGIN_VERSION, VERSION_LINE, CACHE_VERSION_DIR;
3643
3788
  var init_binary_probe = __esm(async () => {
3644
3789
  init_dist2();
3645
3790
  init_paths2();
3646
3791
  PLUGIN_VERSION = await loadPluginVersion();
3647
3792
  VERSION_LINE = /^(?:aft\s+)?v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/i;
3793
+ CACHE_VERSION_DIR = /^v(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/;
3648
3794
  });
3649
3795
 
3650
3796
  // src/lib/fs-util.ts
3651
- import { existsSync as existsSync6, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
3652
- import { join as join9 } from "node:path";
3797
+ import { existsSync as existsSync7, readdirSync as readdirSync5, statSync as statSync4 } from "node:fs";
3798
+ import { join as join10 } from "node:path";
3653
3799
  function dirSize(path) {
3654
- if (!existsSync6(path)) {
3800
+ if (!existsSync7(path)) {
3655
3801
  return 0;
3656
3802
  }
3657
3803
  const stat = statSync4(path);
@@ -3662,8 +3808,8 @@ function dirSize(path) {
3662
3808
  return 0;
3663
3809
  }
3664
3810
  let total = 0;
3665
- for (const entry of readdirSync4(path)) {
3666
- total += dirSize(join9(path, entry));
3811
+ for (const entry of readdirSync5(path)) {
3812
+ total += dirSize(join10(path, entry));
3667
3813
  }
3668
3814
  return total;
3669
3815
  }
@@ -3680,9 +3826,9 @@ function compareVersionLabels(a, b) {
3680
3826
  var init_fs_util = () => {};
3681
3827
 
3682
3828
  // src/lib/omp-paths.ts
3683
- import { existsSync as existsSync7 } from "node:fs";
3829
+ import { existsSync as existsSync8 } from "node:fs";
3684
3830
  import { homedir as homedir7 } from "node:os";
3685
- import { join as join10, resolve as resolve5 } from "node:path";
3831
+ import { join as join11, resolve as resolve5 } from "node:path";
3686
3832
  function envFirstHomeDir() {
3687
3833
  return process.env.HOME?.trim() || homedir7();
3688
3834
  }
@@ -3690,9 +3836,9 @@ function resolveOmpPaths() {
3690
3836
  const normalizedProfile = (process.env.OMP_PROFILE ?? process.env.PI_PROFILE)?.trim();
3691
3837
  const profile = normalizedProfile && normalizedProfile !== "default" && /^[a-z0-9][a-z0-9._-]{0,63}$/.test(normalizedProfile) ? normalizedProfile : undefined;
3692
3838
  const configDirName = process.env.PI_CONFIG_DIR?.trim() || ".omp";
3693
- const baseConfigRoot = join10(envFirstHomeDir(), configDirName);
3694
- const configRoot = profile ? join10(baseConfigRoot, "profiles", profile) : baseConfigRoot;
3695
- const defaultAgentDir = join10(configRoot, "agent");
3839
+ const baseConfigRoot = join11(envFirstHomeDir(), configDirName);
3840
+ const configRoot = profile ? join11(baseConfigRoot, "profiles", profile) : baseConfigRoot;
3841
+ const defaultAgentDir = join11(configRoot, "agent");
3696
3842
  const configuredAgentDir = profile ? undefined : process.env.PI_CODING_AGENT_DIR?.trim();
3697
3843
  const agentDir = configuredAgentDir ? resolve5(configuredAgentDir) : defaultAgentDir;
3698
3844
  const canUseXdg = (process.platform === "linux" || process.platform === "darwin") && agentDir === defaultAgentDir;
@@ -3700,9 +3846,9 @@ function resolveOmpPaths() {
3700
3846
  if (canUseXdg) {
3701
3847
  const xdgDataHome = process.env.XDG_DATA_HOME?.trim();
3702
3848
  if (xdgDataHome) {
3703
- const appRoot = join10(xdgDataHome, "omp");
3704
- const candidate = profile ? join10(appRoot, "profiles", profile) : appRoot;
3705
- if (existsSync7(candidate))
3849
+ const appRoot = join11(xdgDataHome, "omp");
3850
+ const candidate = profile ? join11(appRoot, "profiles", profile) : appRoot;
3851
+ if (existsSync8(candidate))
3706
3852
  dataRoot = candidate;
3707
3853
  }
3708
3854
  }
@@ -3712,8 +3858,8 @@ function resolveOmpPaths() {
3712
3858
  agentDir,
3713
3859
  dataRoot,
3714
3860
  dataAgentRoot,
3715
- pluginsDir: join10(dataRoot, "plugins"),
3716
- sessionsRoot: join10(dataAgentRoot, "sessions")
3861
+ pluginsDir: join11(dataRoot, "plugins"),
3862
+ sessionsRoot: join11(dataAgentRoot, "sessions")
3717
3863
  };
3718
3864
  }
3719
3865
  function getOmpAgentDir() {
@@ -3723,7 +3869,7 @@ function getOmpPluginsDir() {
3723
3869
  return resolveOmpPaths().pluginsDir;
3724
3870
  }
3725
3871
  function getOmpPluginsLockPath() {
3726
- return join10(getOmpPluginsDir(), "omp-plugins.lock.json");
3872
+ return join11(getOmpPluginsDir(), "omp-plugins.lock.json");
3727
3873
  }
3728
3874
  function getOmpSessionsRoot() {
3729
3875
  return resolveOmpPaths().sessionsRoot;
@@ -3743,12 +3889,12 @@ var init_omp_paths = () => {};
3743
3889
 
3744
3890
  // src/lib/omp-helpers.ts
3745
3891
  import { spawnSync as spawnSync4 } from "node:child_process";
3746
- import { accessSync, constants, existsSync as existsSync8, readFileSync as readFileSync5, statSync as statSync5 } from "node:fs";
3892
+ import { accessSync, constants, existsSync as existsSync9, readFileSync as readFileSync5, statSync as statSync5 } from "node:fs";
3747
3893
  import { homedir as homedir8 } from "node:os";
3748
- import { delimiter, extname, join as join11, resolve as resolve6 } from "node:path";
3894
+ import { delimiter, extname, join as join12, resolve as resolve6 } from "node:path";
3749
3895
  function isExecutableFile(path, platform = process.platform) {
3750
3896
  try {
3751
- if (!existsSync8(path) || !statSync5(path).isFile())
3897
+ if (!existsSync9(path) || !statSync5(path).isFile())
3752
3898
  return false;
3753
3899
  accessSync(path, platform === "win32" ? constants.F_OK : constants.X_OK);
3754
3900
  return true;
@@ -3777,11 +3923,11 @@ function detectOmpPackageCli() {
3777
3923
  if (!packageDir || !findOnPath("bun"))
3778
3924
  return null;
3779
3925
  try {
3780
- const manifest = JSON.parse(readFileSync5(join11(packageDir, "package.json"), "utf8"));
3926
+ const manifest = JSON.parse(readFileSync5(join12(packageDir, "package.json"), "utf8"));
3781
3927
  if (manifest.name !== OMP_HOST_PACKAGE)
3782
3928
  return null;
3783
- const cli = join11(packageDir, "dist", "cli.js");
3784
- return existsSync8(cli) ? cli : null;
3929
+ const cli = join12(packageDir, "dist", "cli.js");
3930
+ return existsSync9(cli) ? cli : null;
3785
3931
  } catch {
3786
3932
  return null;
3787
3933
  }
@@ -3801,13 +3947,13 @@ function getOmpCommandInvocation(ompPath, args) {
3801
3947
  }
3802
3948
  function getOmpFallbackCandidates(platform, home, appData) {
3803
3949
  if (platform !== "win32") {
3804
- return [join11(home, ".bun", "bin", "omp"), join11(home, ".local", "bin", "omp")];
3950
+ return [join12(home, ".bun", "bin", "omp"), join12(home, ".local", "bin", "omp")];
3805
3951
  }
3806
3952
  const npmRoot = appData?.trim();
3807
3953
  return [
3808
- ...npmRoot ? [join11(npmRoot, "npm", "omp.cmd"), join11(npmRoot, "npm", "omp.exe")] : [],
3809
- join11(home, ".bun", "bin", "omp.exe"),
3810
- join11(home, ".bun", "bin", "omp.cmd")
3954
+ ...npmRoot ? [join12(npmRoot, "npm", "omp.cmd"), join12(npmRoot, "npm", "omp.exe")] : [],
3955
+ join12(home, ".bun", "bin", "omp.exe"),
3956
+ join12(home, ".bun", "bin", "omp.cmd")
3811
3957
  ];
3812
3958
  }
3813
3959
  function detectOmpBinary() {
@@ -3888,8 +4034,8 @@ var init_omp_helpers = __esm(() => {
3888
4034
  });
3889
4035
 
3890
4036
  // src/adapters/omp.ts
3891
- import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
3892
- import { join as join12 } from "node:path";
4037
+ import { existsSync as existsSync10, readFileSync as readFileSync6 } from "node:fs";
4038
+ import { join as join13 } from "node:path";
3893
4039
 
3894
4040
  class OmpAdapter {
3895
4041
  kind = "omp";
@@ -3914,9 +4060,9 @@ class OmpAdapter {
3914
4060
  return {
3915
4061
  configDir,
3916
4062
  harnessConfig,
3917
- harnessConfigFormat: existsSync9(harnessConfig) ? "json" : "none",
4063
+ harnessConfigFormat: existsSync10(harnessConfig) ? "json" : "none",
3918
4064
  aftConfig,
3919
- aftConfigFormat: existsSync9(aftConfig) ? "jsonc" : "none"
4065
+ aftConfigFormat: existsSync10(aftConfig) ? "jsonc" : "none"
3920
4066
  };
3921
4067
  }
3922
4068
  hasPluginEntry() {
@@ -4007,7 +4153,7 @@ class OmpAdapter {
4007
4153
  path,
4008
4154
  cached: plugin?.version,
4009
4155
  latest: undefined,
4010
- exists: Boolean(plugin) || existsSync9(path)
4156
+ exists: Boolean(plugin) || existsSync10(path)
4011
4157
  };
4012
4158
  }
4013
4159
  getStorageDir() {
@@ -4031,12 +4177,12 @@ class OmpAdapter {
4031
4177
  describeStorageSubtrees() {
4032
4178
  const storage = this.getStorageDir();
4033
4179
  return {
4034
- index: dirSize(join12(storage, "index")),
4035
- semantic: dirSize(join12(storage, "semantic")),
4036
- backups: dirSize(join12(storage, "backups")),
4037
- url_cache: dirSize(join12(storage, "url_cache")),
4038
- onnxruntime: dirSize(join12(storage, "onnxruntime")),
4039
- logs: dirSize(join12(storage, "logs"))
4180
+ index: dirSize(join13(storage, "index")),
4181
+ semantic: dirSize(join13(storage, "semantic")),
4182
+ backups: dirSize(join13(storage, "backups")),
4183
+ url_cache: dirSize(join13(storage, "url_cache")),
4184
+ onnxruntime: dirSize(join13(storage, "onnxruntime")),
4185
+ logs: dirSize(join13(storage, "logs"))
4040
4186
  };
4041
4187
  }
4042
4188
  readRuntimeEnabled(configPath) {
@@ -11830,21 +11976,21 @@ var require_src2 = __commonJS(function(exports, module) {
11830
11976
  });
11831
11977
 
11832
11978
  // src/lib/jsonc.ts
11833
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "node:fs";
11979
+ import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "node:fs";
11834
11980
  import { dirname as dirname4 } from "node:path";
11835
11981
  function detectJsoncFile(configDir, baseName) {
11836
11982
  const jsoncPath = `${configDir}/${baseName}.jsonc`;
11837
11983
  const jsonPath = `${configDir}/${baseName}.json`;
11838
- if (existsSync10(jsoncPath)) {
11984
+ if (existsSync11(jsoncPath)) {
11839
11985
  return { path: jsoncPath, format: "jsonc" };
11840
11986
  }
11841
- if (existsSync10(jsonPath)) {
11987
+ if (existsSync11(jsonPath)) {
11842
11988
  return { path: jsonPath, format: "json" };
11843
11989
  }
11844
11990
  return { path: jsonPath, format: "none" };
11845
11991
  }
11846
11992
  function readJsoncFile(path) {
11847
- if (!existsSync10(path)) {
11993
+ if (!existsSync11(path)) {
11848
11994
  return { value: null };
11849
11995
  }
11850
11996
  try {
@@ -11865,7 +12011,7 @@ function writeJsoncFile(path, value, format = "json") {
11865
12011
  `);
11866
12012
  }
11867
12013
  function ensureAftSchemaUrl(path, format) {
11868
- const existed = existsSync10(path);
12014
+ const existed = existsSync11(path);
11869
12015
  if (!existed) {
11870
12016
  const writeFormat = format === "jsonc" ? "jsonc" : "json";
11871
12017
  writeJsoncFile(path, { $schema: AFT_SCHEMA_URL }, writeFormat);
@@ -11922,62 +12068,130 @@ var opencode_version_default = `1.18.30
11922
12068
  var init_opencode_version = () => {};
11923
12069
 
11924
12070
  // src/setup/opencode-config.ts
12071
+ function openCodePluginKey(generation) {
12072
+ return generation === "v2" ? "plugins" : "plugin";
12073
+ }
12074
+ function otherOpenCodePluginKey(key) {
12075
+ return key === "plugins" ? "plugin" : "plugins";
12076
+ }
12077
+ function openCodePluginReadKeys(generation) {
12078
+ if (generation === "v1")
12079
+ return ["plugin"];
12080
+ if (generation === "v2")
12081
+ return ["plugins"];
12082
+ return ["plugin", "plugins"];
12083
+ }
11925
12084
  function pinnedPluginEntry(version) {
11926
12085
  return `${AFT_OPENCODE_PACKAGE}@${version}`;
11927
12086
  }
11928
12087
  function isAftNpmEntry(entry) {
11929
12088
  return typeof entry === "string" && (entry === AFT_OPENCODE_PACKAGE || entry.startsWith(`${AFT_OPENCODE_PACKAGE}@`));
11930
12089
  }
11931
- function ensurePinnedPluginConfig(value, version, hasLocalAftEntry = () => false) {
12090
+ function isPackageObjectEntry(entry) {
12091
+ return typeof entry === "object" && entry !== null && !Array.isArray(entry) && typeof entry.package === "string";
12092
+ }
12093
+ function isPackageTupleEntry(entry) {
12094
+ return Array.isArray(entry) && typeof entry[0] === "string";
12095
+ }
12096
+ function pluginEntryPackage(entry) {
12097
+ if (typeof entry === "string")
12098
+ return entry;
12099
+ if (isPackageTupleEntry(entry))
12100
+ return entry[0];
12101
+ if (isPackageObjectEntry(entry))
12102
+ return entry.package;
12103
+ return null;
12104
+ }
12105
+ function pluginEntryOptions(entry) {
12106
+ if (isPackageTupleEntry(entry))
12107
+ return entry.length > 1 ? entry[1] : undefined;
12108
+ if (isPackageObjectEntry(entry))
12109
+ return entry.options;
12110
+ return;
12111
+ }
12112
+ function pluginEntryFitsKey(entry, key) {
12113
+ if (typeof entry === "string")
12114
+ return true;
12115
+ if (isPackageTupleEntry(entry))
12116
+ return key === "plugin";
12117
+ if (isPackageObjectEntry(entry))
12118
+ return key === "plugins";
12119
+ return false;
12120
+ }
12121
+ function shapePluginEntry(key, packageSpec, options) {
12122
+ if (options === undefined)
12123
+ return packageSpec;
12124
+ return key === "plugins" ? { package: packageSpec, options } : [packageSpec, options];
12125
+ }
12126
+ function sameEntry(left, right) {
12127
+ return JSON.stringify(left) === JSON.stringify(right);
12128
+ }
12129
+ function findLocalAftEntry(list, hasLocalAftEntry) {
12130
+ for (let index = 0;index < list.length; index += 1) {
12131
+ const packageSpec = pluginEntryPackage(list[index]);
12132
+ if (packageSpec === null || isAftNpmEntry(packageSpec))
12133
+ continue;
12134
+ if (hasLocalAftEntry(packageSpec)) {
12135
+ return { index, packageSpec, options: pluginEntryOptions(list[index]) };
12136
+ }
12137
+ }
12138
+ return null;
12139
+ }
12140
+ function ensurePinnedPluginConfig(value, version, hasLocalAftEntry = () => false, generation = "unknown") {
11932
12141
  const entry = pinnedPluginEntry(version);
11933
- const singular = Array.isArray(value.plugin) ? value.plugin : [];
11934
- const plural = Array.isArray(value.plugins) ? value.plugins : [];
11935
- const hadPluralKey = Object.hasOwn(value, "plugins");
11936
- if (!Array.isArray(value.plugin))
11937
- value.plugin = singular;
11938
- if (plural !== singular)
11939
- singular.push(...plural);
11940
- if (hadPluralKey)
11941
- delete value.plugins;
12142
+ const key = openCodePluginKey(generation);
12143
+ const hadKey = Array.isArray(value[key]);
12144
+ const list = hadKey ? value[key] : [];
12145
+ if (!hadKey)
12146
+ value[key] = list;
11942
12147
  const npmIndexes = [];
11943
- let hasLocalEntry = false;
11944
- for (let index = 0;index < singular.length; index += 1) {
11945
- const candidate = singular[index];
11946
- if (isAftNpmEntry(candidate))
12148
+ for (let index = 0;index < list.length; index += 1) {
12149
+ const packageSpec = pluginEntryPackage(list[index]);
12150
+ if (packageSpec !== null && isAftNpmEntry(packageSpec))
11947
12151
  npmIndexes.push(index);
11948
- else if (typeof candidate === "string" && hasLocalAftEntry(candidate))
11949
- hasLocalEntry = true;
11950
12152
  }
11951
12153
  if (npmIndexes.length > 0) {
11952
12154
  const firstIndex = npmIndexes[0];
11953
- const wasExact = singular[firstIndex] === entry;
11954
- singular[firstIndex] = entry;
12155
+ const shaped = shapePluginEntry(key, entry, pluginEntryOptions(list[firstIndex]));
12156
+ const wasExact = sameEntry(list[firstIndex], shaped);
12157
+ list[firstIndex] = shaped;
11955
12158
  for (let index = npmIndexes.length - 1;index >= 1; index -= 1) {
11956
- singular.splice(npmIndexes[index], 1);
11957
- }
11958
- const changed = hadPluralKey || !wasExact || npmIndexes.length > 1;
11959
- return { action: changed ? "updated" : "already_present", changed, entry };
11960
- }
11961
- if (hasLocalEntry) {
11962
- return {
11963
- action: hadPluralKey ? "updated" : "already_present",
11964
- changed: hadPluralKey,
11965
- entry
11966
- };
11967
- }
11968
- singular.push(entry);
11969
- return { action: "added", changed: true, entry };
11970
- }
11971
- function pluginConfigNeedsUpdate(value, version, hasLocalAftEntry = () => false) {
11972
- if (Object.hasOwn(value, "plugins"))
11973
- return true;
11974
- if (!Array.isArray(value.plugin))
12159
+ list.splice(npmIndexes[index], 1);
12160
+ }
12161
+ const changed = !wasExact || npmIndexes.length > 1;
12162
+ return { action: changed ? "updated" : "already_present", changed, entry, key };
12163
+ }
12164
+ const local = findLocalAftEntry(list, hasLocalAftEntry);
12165
+ if (local) {
12166
+ const shaped = shapePluginEntry(key, local.packageSpec, local.options);
12167
+ const changed = !sameEntry(list[local.index], shaped);
12168
+ list[local.index] = shaped;
12169
+ return { action: changed ? "updated" : "already_present", changed, entry, key };
12170
+ }
12171
+ const sibling = value[otherOpenCodePluginKey(key)];
12172
+ const siblingList = Array.isArray(sibling) ? sibling : null;
12173
+ const carried = siblingList ? findLocalAftEntry(siblingList, hasLocalAftEntry) : null;
12174
+ list.push(carried ? shapePluginEntry(key, carried.packageSpec, carried.options) : entry);
12175
+ if (carried && siblingList)
12176
+ siblingList.splice(carried.index, 1);
12177
+ return { action: "added", changed: true, entry, key };
12178
+ }
12179
+ function pluginConfigNeedsUpdate(value, version, hasLocalAftEntry = () => false, generation = "unknown") {
12180
+ const key = openCodePluginKey(generation);
12181
+ const list = value[key];
12182
+ if (!Array.isArray(list))
11975
12183
  return true;
11976
- const npmEntries = value.plugin.filter(isAftNpmEntry);
12184
+ const npmEntries = list.filter((candidate) => {
12185
+ const packageSpec = pluginEntryPackage(candidate);
12186
+ return packageSpec !== null && isAftNpmEntry(packageSpec);
12187
+ });
11977
12188
  if (npmEntries.length > 0) {
11978
- return npmEntries.length !== 1 || npmEntries[0] !== pinnedPluginEntry(version);
12189
+ return npmEntries.length !== 1 || pluginEntryPackage(npmEntries[0]) !== pinnedPluginEntry(version) || !pluginEntryFitsKey(npmEntries[0], key);
11979
12190
  }
11980
- return !value.plugin.some((entry) => typeof entry === "string" && hasLocalAftEntry(entry));
12191
+ const local = findLocalAftEntry(list, hasLocalAftEntry);
12192
+ if (local)
12193
+ return !pluginEntryFitsKey(list[local.index], key);
12194
+ return true;
11981
12195
  }
11982
12196
  var AFT_OPENCODE_PACKAGE = "@cortexkit/aft-opencode", MODERN_V1_VERSION;
11983
12197
  var init_opencode_config = __esm(() => {
@@ -11992,11 +12206,11 @@ import {
11992
12206
  accessSync as accessSync2,
11993
12207
  closeSync as closeSync4,
11994
12208
  constants as constants2,
11995
- existsSync as existsSync11,
12209
+ existsSync as existsSync12,
11996
12210
  mkdirSync as mkdirSync5,
11997
12211
  mkdtempSync,
11998
12212
  openSync as openSync4,
11999
- readdirSync as readdirSync5,
12213
+ readdirSync as readdirSync6,
12000
12214
  readFileSync as readFileSync8,
12001
12215
  readSync as readSync2,
12002
12216
  realpathSync as realpathSync2,
@@ -12004,7 +12218,7 @@ import {
12004
12218
  statSync as statSync6
12005
12219
  } from "node:fs";
12006
12220
  import { homedir as homedir9, tmpdir } from "node:os";
12007
- import { delimiter as delimiter2, dirname as dirname5, join as join13, parse, resolve as resolve7 } from "node:path";
12221
+ import { delimiter as delimiter2, dirname as dirname5, join as join14, parse, resolve as resolve7 } from "node:path";
12008
12222
  function executableNames2(name, platform) {
12009
12223
  if (platform !== "win32")
12010
12224
  return [name];
@@ -12042,7 +12256,7 @@ function packageMetadataNearExecutable(executable, expectedName) {
12042
12256
  current = dirname5(executable);
12043
12257
  }
12044
12258
  while (true) {
12045
- const direct = packageMetadataAt(join13(current, "package.json"), expectedName);
12259
+ const direct = packageMetadataAt(join14(current, "package.json"), expectedName);
12046
12260
  if (direct)
12047
12261
  return direct;
12048
12262
  const parent = dirname5(current);
@@ -12080,7 +12294,7 @@ function hashFileBytes(hash, path, size) {
12080
12294
  }
12081
12295
  }
12082
12296
  function snapshotTree(path) {
12083
- if (!existsSync11(path))
12297
+ if (!existsSync12(path))
12084
12298
  return "missing";
12085
12299
  const hash = createHash4("sha256");
12086
12300
  const visit = (current, relativePath) => {
@@ -12093,8 +12307,8 @@ function snapshotTree(path) {
12093
12307
  }
12094
12308
  hash.update(`${relativePath}\x00${info.mode}\x00${info.size}\x00${info.mtimeMs}\x00`);
12095
12309
  if (info.isDirectory()) {
12096
- for (const entry of readdirSync5(current).sort()) {
12097
- visit(join13(current, entry), join13(relativePath, entry));
12310
+ for (const entry of readdirSync6(current).sort()) {
12311
+ visit(join14(current, entry), join14(relativePath, entry));
12098
12312
  }
12099
12313
  return;
12100
12314
  }
@@ -12110,31 +12324,31 @@ function snapshotTree(path) {
12110
12324
  return hash.digest("hex");
12111
12325
  }
12112
12326
  function snapshotOperatorState(operatorHome) {
12113
- const database = join13(operatorHome, ".local", "share", "opencode", "opencode.db");
12327
+ const database = join14(operatorHome, ".local", "share", "opencode", "opencode.db");
12114
12328
  return JSON.stringify({
12115
12329
  database: snapshotTree(database),
12116
12330
  databaseWal: snapshotTree(`${database}-wal`),
12117
12331
  databaseShm: snapshotTree(`${database}-shm`),
12118
- logs: snapshotTree(join13(operatorHome, ".local", "share", "opencode", "log"))
12332
+ logs: snapshotTree(join14(operatorHome, ".local", "share", "opencode", "log"))
12119
12333
  });
12120
12334
  }
12121
12335
  function probeCreatedIsolatedState(dataRoot, stateRoot) {
12122
12336
  return [dataRoot, stateRoot].some((root) => {
12123
- const opencodeRoot = join13(root, "opencode");
12124
- const database = join13(opencodeRoot, "opencode.db");
12125
- return [database, `${database}-wal`, `${database}-shm`, join13(opencodeRoot, "log")].some(existsSync11);
12337
+ const opencodeRoot = join14(root, "opencode");
12338
+ const database = join14(opencodeRoot, "opencode.db");
12339
+ return [database, `${database}-wal`, `${database}-shm`, join14(opencodeRoot, "log")].some(existsSync12);
12126
12340
  });
12127
12341
  }
12128
12342
  function probeOpenCodeV1Version(executable, options = {}) {
12129
12343
  const operatorHome = options.operatorHome ?? homedir9();
12130
12344
  const before = snapshotOperatorState(operatorHome);
12131
- const root = mkdtempSync(join13(options.tempParent ?? tmpdir(), "aft-opencode-probe-"));
12132
- const home = join13(root, "home");
12133
- const config = join13(root, "config");
12134
- const data = join13(root, "data");
12135
- const state = join13(root, "state");
12136
- const cache = join13(root, "cache");
12137
- const project = join13(root, "project");
12345
+ const root = mkdtempSync(join14(options.tempParent ?? tmpdir(), "aft-opencode-probe-"));
12346
+ const home = join14(root, "home");
12347
+ const config = join14(root, "config");
12348
+ const data = join14(root, "data");
12349
+ const state = join14(root, "state");
12350
+ const cache = join14(root, "cache");
12351
+ const project = join14(root, "project");
12138
12352
  for (const directory of [home, config, data, state, cache, project]) {
12139
12353
  mkdirSync5(directory, { recursive: true });
12140
12354
  }
@@ -12145,7 +12359,7 @@ function probeOpenCodeV1Version(executable, options = {}) {
12145
12359
  XDG_DATA_HOME: data,
12146
12360
  XDG_STATE_HOME: state,
12147
12361
  XDG_CACHE_HOME: cache,
12148
- TMPDIR: join13(root, "tmp")
12362
+ TMPDIR: join14(root, "tmp")
12149
12363
  };
12150
12364
  mkdirSync5(env.TMPDIR, { recursive: true });
12151
12365
  delete env.OPENCODE_CONFIG;
@@ -12178,33 +12392,63 @@ function probeOpenCodeV1Version(executable, options = {}) {
12178
12392
  throw probeError;
12179
12393
  if (!result || result.error || result.status !== 0)
12180
12394
  return null;
12181
- const output = String(result.stdout ?? "").trim();
12182
- return output.length > 0 ? output : null;
12395
+ return parseHostVersion(String(result.stdout ?? ""));
12396
+ }
12397
+ function parseHostVersion(output) {
12398
+ if (!output)
12399
+ return null;
12400
+ const match = output.match(/(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z][0-9A-Za-z.-]*)?)/);
12401
+ return match ? match[1] : null;
12402
+ }
12403
+ function v2MetadataNearExecutable(executable) {
12404
+ for (const name of V2_PACKAGE_NAMES) {
12405
+ const metadata = packageMetadataNearExecutable(executable, name);
12406
+ if (metadata)
12407
+ return metadata;
12408
+ }
12409
+ return null;
12410
+ }
12411
+ function isV2Version(version) {
12412
+ const parsed = parseHostVersion(version);
12413
+ if (!parsed)
12414
+ return false;
12415
+ if (/^0\.0\.0-(?:beta|dev)-/.test(parsed))
12416
+ return true;
12417
+ const major = Number.parseInt(parsed, 10);
12418
+ return Number.isFinite(major) && major >= 2;
12419
+ }
12420
+ function resolvedPath(executable) {
12421
+ try {
12422
+ return realpathSync2(executable);
12423
+ } catch {
12424
+ return executable;
12425
+ }
12183
12426
  }
12184
12427
  function detectOpenCodeHostGeneration(dependencies = {}) {
12185
12428
  const findExecutable = dependencies.findExecutable ?? ((name) => findExecutableOnPath(name, dependencies.path, dependencies.platform));
12186
- const v1Executable = findExecutable("opencode");
12187
- const v2Executable = findExecutable("opencode2");
12429
+ const openCodeExecutable = findExecutable("opencode");
12430
+ const openCode2Executable = findExecutable("opencode2");
12188
12431
  const evidence = [];
12189
- if (v1Executable) {
12190
- const v1Metadata = packageMetadataNearExecutable(v1Executable, "opencode-ai");
12191
- const v2Metadata = packageMetadataNearExecutable(v1Executable, "@opencode-ai/cli");
12432
+ const sharedExecutable = openCodeExecutable !== null && openCode2Executable !== null && resolvedPath(openCodeExecutable) === resolvedPath(openCode2Executable);
12433
+ if (openCodeExecutable) {
12434
+ const v1Metadata = packageMetadataNearExecutable(openCodeExecutable, "opencode-ai");
12435
+ const v2Metadata = v2MetadataNearExecutable(openCodeExecutable);
12192
12436
  const metadataVersion = packageVersion(v2Metadata) ?? packageVersion(v1Metadata);
12193
- const version = metadataVersion ?? (dependencies.probeV1Version ?? probeOpenCodeV1Version)(v1Executable);
12194
- const isV2 = Boolean(v2Metadata) || /^0\.0\.0-(?:beta|dev)-/.test(version ?? "");
12437
+ const version = metadataVersion ?? (dependencies.probeV1Version ?? probeOpenCodeV1Version)(openCodeExecutable);
12438
+ const isV2 = Boolean(v2Metadata) || sharedExecutable || isV2Version(version);
12195
12439
  evidence.push({
12196
12440
  generation: isV2 ? "v2" : "v1",
12197
- executable: v1Executable,
12441
+ executable: openCodeExecutable,
12198
12442
  version,
12199
12443
  runtime: "bun",
12200
12444
  modernV1: !isV2 && version === MODERN_V1_VERSION
12201
12445
  });
12202
12446
  }
12203
- if (v2Executable) {
12204
- const version = packageVersion(packageMetadataNearExecutable(v2Executable, "@opencode-ai/cli"));
12447
+ if (openCode2Executable && !sharedExecutable) {
12448
+ const version = packageVersion(v2MetadataNearExecutable(openCode2Executable));
12205
12449
  evidence.push({
12206
12450
  generation: "v2",
12207
- executable: v2Executable,
12451
+ executable: openCode2Executable,
12208
12452
  version,
12209
12453
  runtime: "bun",
12210
12454
  modernV1: false
@@ -12228,17 +12472,18 @@ function formatHostGenerations(detection) {
12228
12472
  return "V2";
12229
12473
  return "unknown";
12230
12474
  }
12231
- var FULL_CONTENT_HASH_MAX_BYTES, PARTIAL_CONTENT_WINDOW_BYTES;
12475
+ var FULL_CONTENT_HASH_MAX_BYTES, PARTIAL_CONTENT_WINDOW_BYTES, V2_PACKAGE_NAMES;
12232
12476
  var init_host_generation = __esm(() => {
12233
12477
  init_opencode_config();
12234
12478
  FULL_CONTENT_HASH_MAX_BYTES = 64 * 1024 * 1024;
12235
12479
  PARTIAL_CONTENT_WINDOW_BYTES = 1024 * 1024;
12480
+ V2_PACKAGE_NAMES = ["@opencode/cli", "@opencode-ai/cli"];
12236
12481
  });
12237
12482
 
12238
12483
  // src/adapters/opencode.ts
12239
- import { existsSync as existsSync12, readFileSync as readFileSync9, rmSync as rmSync4, statSync as statSync7 } from "node:fs";
12484
+ import { existsSync as existsSync13, readFileSync as readFileSync9, rmSync as rmSync4, statSync as statSync7 } from "node:fs";
12240
12485
  import { homedir as homedir10 } from "node:os";
12241
- import { dirname as dirname6, join as join14, parse as parse2, resolve as resolve8 } from "node:path";
12486
+ import { dirname as dirname6, join as join15, parse as parse2, resolve as resolve8 } from "node:path";
12242
12487
  import { fileURLToPath } from "node:url";
12243
12488
  function getOpenCodeConfigDir() {
12244
12489
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
@@ -12249,13 +12494,13 @@ function getOpenCodeConfigDir() {
12249
12494
  function getLegacyOpenCodePluginCachePath(primaryPath) {
12250
12495
  if (process.platform !== "win32")
12251
12496
  return null;
12252
- const localAppData = process.env.LOCALAPPDATA ?? join14(homedir10(), "AppData", "Local");
12253
- const legacyPath = join14(localAppData, "opencode", "packages", LEGACY_PLUGIN_ENTRY);
12497
+ const localAppData = process.env.LOCALAPPDATA ?? join15(homedir10(), "AppData", "Local");
12498
+ const legacyPath = join15(localAppData, "opencode", "packages", LEGACY_PLUGIN_ENTRY);
12254
12499
  return resolve8(legacyPath) === resolve8(primaryPath) ? null : legacyPath;
12255
12500
  }
12256
12501
  function clearLegacyOpenCodePluginCache(primaryPath) {
12257
12502
  const legacyPath = getLegacyOpenCodePluginCachePath(primaryPath);
12258
- if (!legacyPath || !existsSync12(legacyPath))
12503
+ if (!legacyPath || !existsSync13(legacyPath))
12259
12504
  return { clearedPath: null };
12260
12505
  try {
12261
12506
  rmSync4(legacyPath, { recursive: true, force: true });
@@ -12273,16 +12518,16 @@ function hasOpenCodeCli() {
12273
12518
  function openCodeDesktopAppExists() {
12274
12519
  const candidates = [];
12275
12520
  if (process.platform === "darwin") {
12276
- candidates.push("/Applications/OpenCode.app", "/Applications/OpenCode Beta.app", join14(homedir10(), "Applications", "OpenCode.app"), join14(homedir10(), "Applications", "OpenCode Beta.app"));
12521
+ candidates.push("/Applications/OpenCode.app", "/Applications/OpenCode Beta.app", join15(homedir10(), "Applications", "OpenCode.app"), join15(homedir10(), "Applications", "OpenCode Beta.app"));
12277
12522
  } else if (process.platform === "win32") {
12278
- const localAppData = process.env.LOCALAPPDATA ?? join14(homedir10(), "AppData", "Local");
12279
- candidates.push(join14(localAppData, "Programs", "opencode"), join14(localAppData, "opencode"));
12523
+ const localAppData = process.env.LOCALAPPDATA ?? join15(homedir10(), "AppData", "Local");
12524
+ candidates.push(join15(localAppData, "Programs", "opencode"), join15(localAppData, "opencode"));
12280
12525
  } else {
12281
- candidates.push("/opt/OpenCode", "/usr/lib/opencode", join14(homedir10(), ".local", "share", "applications", "opencode.desktop"));
12526
+ candidates.push("/opt/OpenCode", "/usr/lib/opencode", join15(homedir10(), ".local", "share", "applications", "opencode.desktop"));
12282
12527
  }
12283
12528
  return candidates.some((p) => {
12284
12529
  try {
12285
- return existsSync12(p);
12530
+ return existsSync13(p);
12286
12531
  } catch {
12287
12532
  return false;
12288
12533
  }
@@ -12305,13 +12550,13 @@ function pathPointsToOurPlugin(entry) {
12305
12550
  if (!fsPath)
12306
12551
  return false;
12307
12552
  try {
12308
- if (!existsSync12(fsPath))
12553
+ if (!existsSync13(fsPath))
12309
12554
  return false;
12310
12555
  let searchDir = statSync7(fsPath).isDirectory() ? fsPath : dirname6(fsPath);
12311
12556
  let pkgJsonPath = null;
12312
12557
  while (true) {
12313
- const candidate = join14(searchDir, "package.json");
12314
- if (existsSync12(candidate)) {
12558
+ const candidate = join15(searchDir, "package.json");
12559
+ if (existsSync13(candidate)) {
12315
12560
  pkgJsonPath = candidate;
12316
12561
  break;
12317
12562
  }
@@ -12335,6 +12580,19 @@ function matchesPluginEntry(entry) {
12335
12580
  return true;
12336
12581
  return pathPointsToOurPlugin(entry);
12337
12582
  }
12583
+ function configRegistersAft(value, generation) {
12584
+ if (!value)
12585
+ return false;
12586
+ return openCodePluginReadKeys(generation).some((key) => {
12587
+ const list = value[key];
12588
+ if (!Array.isArray(list))
12589
+ return false;
12590
+ return list.some((entry) => {
12591
+ const packageSpec = pluginEntryPackage(entry);
12592
+ return packageSpec !== null && matchesPluginEntry(packageSpec);
12593
+ });
12594
+ });
12595
+ }
12338
12596
 
12339
12597
  class OpenCodeAdapter {
12340
12598
  kind = "opencode";
@@ -12343,7 +12601,7 @@ class OpenCodeAdapter {
12343
12601
  pluginEntryWithVersion = PLUGIN_ENTRY;
12344
12602
  hostDetection;
12345
12603
  isInstalled() {
12346
- if (existsSync12(getOpenCodeConfigDir()))
12604
+ if (existsSync13(getOpenCodeConfigDir()))
12347
12605
  return true;
12348
12606
  if (openCodeDesktopAppExists())
12349
12607
  return true;
@@ -12353,6 +12611,12 @@ class OpenCodeAdapter {
12353
12611
  this.hostDetection ??= detectOpenCodeHostGeneration();
12354
12612
  return this.hostDetection;
12355
12613
  }
12614
+ useHostDetection(detection) {
12615
+ this.hostDetection = detection;
12616
+ }
12617
+ configGeneration() {
12618
+ return this.hostDetection?.status ?? "unknown";
12619
+ }
12356
12620
  getHostVersion() {
12357
12621
  const versions = this.detectHostGeneration().evidence.map((item) => item.version).filter((version) => Boolean(version));
12358
12622
  return versions.length > 0 ? versions.join(" + ") : null;
@@ -12361,7 +12625,7 @@ class OpenCodeAdapter {
12361
12625
  const configDir = getOpenCodeConfigDir();
12362
12626
  const harness = detectJsoncFile(configDir, "opencode");
12363
12627
  const aftConfigPath = resolveCortexKitUserConfigPath();
12364
- const aftConfigExists = existsSync12(aftConfigPath);
12628
+ const aftConfigExists = existsSync13(aftConfigPath);
12365
12629
  const tui = detectJsoncFile(configDir, "tui");
12366
12630
  return {
12367
12631
  configDir,
@@ -12376,8 +12640,7 @@ class OpenCodeAdapter {
12376
12640
  hasPluginEntry() {
12377
12641
  const paths = this.detectConfigPaths();
12378
12642
  const { value } = readJsoncFile(paths.harnessConfig);
12379
- const plugins = Array.isArray(value?.plugin) ? value.plugin : [];
12380
- return plugins.some((entry) => typeof entry === "string" && matchesPluginEntry(entry));
12643
+ return configRegistersAft(value, this.configGeneration());
12381
12644
  }
12382
12645
  async ensurePluginEntry() {
12383
12646
  const paths = this.detectConfigPaths();
@@ -12392,8 +12655,7 @@ class OpenCodeAdapter {
12392
12655
  if (!paths.tuiConfig)
12393
12656
  return false;
12394
12657
  const { value } = readJsoncFile(paths.tuiConfig);
12395
- const plugins = Array.isArray(value?.plugin) ? value.plugin : [];
12396
- return plugins.some((entry) => typeof entry === "string" && matchesPluginEntry(entry));
12658
+ return configRegistersAft(value, this.configGeneration());
12397
12659
  }
12398
12660
  async ensureTuiPluginEntry() {
12399
12661
  const paths = this.detectConfigPaths();
@@ -12412,12 +12674,14 @@ class OpenCodeAdapter {
12412
12674
  return paths.tuiConfig ? this.configEntryNeedsUpdate(paths.tuiConfig, paths.tuiConfigFormat ?? "none") : true;
12413
12675
  }
12414
12676
  ensureConfigEntry(configPath, format, label) {
12677
+ const generation = this.configGeneration();
12678
+ const key = openCodePluginKey(generation);
12415
12679
  if (format === "none") {
12416
- writeJsoncFile(configPath, { plugin: [PLUGIN_ENTRY] }, "json");
12680
+ writeJsoncFile(configPath, { [key]: [PLUGIN_ENTRY] }, "json");
12417
12681
  return {
12418
12682
  ok: true,
12419
12683
  action: "added",
12420
- message: `Created ${configPath} and added ${PLUGIN_ENTRY} (${label})`,
12684
+ message: `Created ${configPath} and added ${PLUGIN_ENTRY} under \`${key}\` (${label})`,
12421
12685
  configPath
12422
12686
  };
12423
12687
  }
@@ -12430,12 +12694,12 @@ class OpenCodeAdapter {
12430
12694
  configPath
12431
12695
  };
12432
12696
  }
12433
- const update = ensurePinnedPluginConfig(value, getSelfVersion(), pathPointsToOurPlugin);
12697
+ const update = ensurePinnedPluginConfig(value, getSelfVersion(), pathPointsToOurPlugin, generation);
12434
12698
  if (!update.changed) {
12435
12699
  return {
12436
12700
  ok: true,
12437
12701
  action: "already_present",
12438
- message: `${PLUGIN_ENTRY} is already registered in ${configPath}`,
12702
+ message: `${PLUGIN_ENTRY} is already registered under \`${update.key}\` in ${configPath}`,
12439
12703
  configPath
12440
12704
  };
12441
12705
  }
@@ -12443,7 +12707,7 @@ class OpenCodeAdapter {
12443
12707
  return {
12444
12708
  ok: true,
12445
12709
  action: update.action,
12446
- message: `${update.action === "added" ? "Added" : "Updated"} ${PLUGIN_ENTRY} in ${configPath} (${label})`,
12710
+ message: `${update.action === "added" ? "Added" : "Updated"} ${PLUGIN_ENTRY} under \`${update.key}\` in ${configPath} (${label})`,
12447
12711
  configPath
12448
12712
  };
12449
12713
  }
@@ -12453,17 +12717,17 @@ class OpenCodeAdapter {
12453
12717
  const { value, error } = readJsoncFile(configPath);
12454
12718
  if (error || !value)
12455
12719
  return false;
12456
- return pluginConfigNeedsUpdate(value, getSelfVersion(), pathPointsToOurPlugin);
12720
+ return pluginConfigNeedsUpdate(value, getSelfVersion(), pathPointsToOurPlugin, this.configGeneration());
12457
12721
  }
12458
12722
  getPluginCacheInfo() {
12459
12723
  const configPath = this.detectConfigPaths().harnessConfig;
12460
12724
  const { value } = readJsoncFile(configPath);
12461
- const configuredEntry = Array.isArray(value?.plugin) ? value.plugin.find(isAftNpmEntry) : undefined;
12462
- const path = join14(getOpenCodeCacheDir(), "packages", configuredEntry ?? PLUGIN_ENTRY);
12725
+ const configuredEntry = openCodePluginReadKeys(this.configGeneration()).flatMap((key) => Array.isArray(value?.[key]) ? value[key] : []).map(pluginEntryPackage).find(isAftNpmEntry);
12726
+ const path = join15(getOpenCodeCacheDir(), "packages", configuredEntry ?? PLUGIN_ENTRY);
12463
12727
  let cached;
12464
12728
  try {
12465
- const installedPkgPath = join14(path, "node_modules", "@cortexkit", "aft-opencode", "package.json");
12466
- if (existsSync12(installedPkgPath)) {
12729
+ const installedPkgPath = join15(path, "node_modules", "@cortexkit", "aft-opencode", "package.json");
12730
+ if (existsSync13(installedPkgPath)) {
12467
12731
  const pkg = JSON.parse(readFileSync9(installedPkgPath, "utf-8"));
12468
12732
  cached = typeof pkg.version === "string" ? pkg.version : undefined;
12469
12733
  }
@@ -12474,7 +12738,7 @@ class OpenCodeAdapter {
12474
12738
  path,
12475
12739
  cached,
12476
12740
  latest: getSelfVersion(),
12477
- exists: existsSync12(path)
12741
+ exists: existsSync13(path)
12478
12742
  };
12479
12743
  }
12480
12744
  getStorageDir() {
@@ -12537,12 +12801,12 @@ class OpenCodeAdapter {
12537
12801
  describeStorageSubtrees() {
12538
12802
  const storage = this.getStorageDir();
12539
12803
  return {
12540
- index: dirSize(join14(storage, "index")),
12541
- semantic: dirSize(join14(storage, "semantic")),
12542
- backups: dirSize(join14(storage, "backups")),
12543
- url_cache: dirSize(join14(storage, "url_cache")),
12544
- onnxruntime: dirSize(join14(storage, "onnxruntime")),
12545
- logs: dirSize(join14(storage, "logs"))
12804
+ index: dirSize(join15(storage, "index")),
12805
+ semantic: dirSize(join15(storage, "semantic")),
12806
+ backups: dirSize(join15(storage, "backups")),
12807
+ url_cache: dirSize(join15(storage, "url_cache")),
12808
+ onnxruntime: dirSize(join15(storage, "onnxruntime")),
12809
+ logs: dirSize(join15(storage, "logs"))
12546
12810
  };
12547
12811
  }
12548
12812
  }
@@ -12562,20 +12826,20 @@ var init_opencode = __esm(() => {
12562
12826
 
12563
12827
  // src/adapters/pi.ts
12564
12828
  import { execSync as execSync2, spawnSync as spawnSync6 } from "node:child_process";
12565
- import { existsSync as existsSync13, readFileSync as readFileSync10 } from "node:fs";
12829
+ import { existsSync as existsSync14, readFileSync as readFileSync10 } from "node:fs";
12566
12830
  import { homedir as homedir11 } from "node:os";
12567
- import { join as join15, resolve as resolve9 } from "node:path";
12831
+ import { join as join16, resolve as resolve9 } from "node:path";
12568
12832
  function getPiAgentDir() {
12569
12833
  const configuredDir = process.env.PI_CODING_AGENT_DIR?.trim();
12570
12834
  if (configuredDir)
12571
12835
  return resolve9(configuredDir);
12572
12836
  const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
12573
12837
  const home = envHome && envHome.length > 0 ? envHome : homedir11();
12574
- return join15(home, ".pi", "agent");
12838
+ return join16(home, ".pi", "agent");
12575
12839
  }
12576
12840
  function readPiExtensionIndex() {
12577
- const settingsPath = join15(getPiAgentDir(), "settings.json");
12578
- if (existsSync13(settingsPath)) {
12841
+ const settingsPath = join16(getPiAgentDir(), "settings.json");
12842
+ if (existsSync14(settingsPath)) {
12579
12843
  try {
12580
12844
  const raw = readFileSync10(settingsPath, "utf-8");
12581
12845
  const trimmed = raw.replace(/^\uFEFF/, "");
@@ -12595,13 +12859,13 @@ function readPiExtensionIndex() {
12595
12859
  } catch {}
12596
12860
  }
12597
12861
  const candidates = [
12598
- join15(getPiAgentDir(), "extensions.json"),
12599
- join15(getPiAgentDir(), "extensions.jsonc"),
12600
- join15(getPiAgentDir(), "config.json"),
12601
- join15(getPiAgentDir(), "config.jsonc")
12862
+ join16(getPiAgentDir(), "extensions.json"),
12863
+ join16(getPiAgentDir(), "extensions.jsonc"),
12864
+ join16(getPiAgentDir(), "config.json"),
12865
+ join16(getPiAgentDir(), "config.jsonc")
12602
12866
  ];
12603
12867
  for (const path of candidates) {
12604
- if (!existsSync13(path))
12868
+ if (!existsSync14(path))
12605
12869
  continue;
12606
12870
  try {
12607
12871
  const { value } = readJsoncFile(path);
@@ -12634,15 +12898,15 @@ function piEntryMatchesAft(entry) {
12634
12898
  } else if (entry.startsWith("/")) {
12635
12899
  resolved = entry;
12636
12900
  } else if (entry.length > 0) {
12637
- resolved = join15(getPiAgentDir(), entry);
12901
+ resolved = join16(getPiAgentDir(), entry);
12638
12902
  }
12639
12903
  if (!resolved)
12640
12904
  return false;
12641
12905
  try {
12642
- if (!existsSync13(resolved))
12906
+ if (!existsSync14(resolved))
12643
12907
  return false;
12644
- const pkgPath = join15(resolved, "package.json");
12645
- if (!existsSync13(pkgPath))
12908
+ const pkgPath = join16(resolved, "package.json");
12909
+ if (!existsSync14(pkgPath))
12646
12910
  return false;
12647
12911
  const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
12648
12912
  return pkg.name === PLUGIN_NAME2;
@@ -12690,10 +12954,10 @@ class PiAdapter {
12690
12954
  const configDir = getPiAgentDir();
12691
12955
  const index = readPiExtensionIndex();
12692
12956
  const aftConfigPath = resolveCortexKitUserConfigPath();
12693
- const aftConfigExists = existsSync13(aftConfigPath);
12957
+ const aftConfigExists = existsSync14(aftConfigPath);
12694
12958
  return {
12695
12959
  configDir,
12696
- harnessConfig: index.path ?? join15(configDir, "extensions.json"),
12960
+ harnessConfig: index.path ?? join16(configDir, "extensions.json"),
12697
12961
  harnessConfigFormat: index.path ? "json" : "none",
12698
12962
  aftConfig: aftConfigPath,
12699
12963
  aftConfigFormat: aftConfigExists ? "jsonc" : "none"
@@ -12738,12 +13002,12 @@ class PiAdapter {
12738
13002
  }
12739
13003
  getPluginCacheInfo() {
12740
13004
  const candidates = [
12741
- join15(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
12742
- join15(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
12743
- join15(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
13005
+ join16(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
13006
+ join16(getPiAgentDir(), "node_modules", "@cortexkit", "aft-pi", "package.json"),
13007
+ join16(getPiAgentDir(), "extensions", "node_modules", "@cortexkit", "aft-pi", "package.json")
12744
13008
  ];
12745
13009
  for (const candidate of candidates) {
12746
- if (!existsSync13(candidate))
13010
+ if (!existsSync14(candidate))
12747
13011
  continue;
12748
13012
  try {
12749
13013
  const pkg = JSON.parse(readFileSync10(candidate, "utf-8"));
@@ -12757,7 +13021,7 @@ class PiAdapter {
12757
13021
  } catch {}
12758
13022
  }
12759
13023
  return {
12760
- path: join15(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
13024
+ path: join16(getPiAgentDir(), "npm", "node_modules", "@cortexkit", "aft-pi", "package.json"),
12761
13025
  exists: false
12762
13026
  };
12763
13027
  }
@@ -12779,12 +13043,12 @@ class PiAdapter {
12779
13043
  describeStorageSubtrees() {
12780
13044
  const storage = this.getStorageDir();
12781
13045
  return {
12782
- index: dirSize(join15(storage, "index")),
12783
- semantic: dirSize(join15(storage, "semantic")),
12784
- backups: dirSize(join15(storage, "backups")),
12785
- url_cache: dirSize(join15(storage, "url_cache")),
12786
- onnxruntime: dirSize(join15(storage, "onnxruntime")),
12787
- logs: dirSize(join15(storage, "logs"))
13046
+ index: dirSize(join16(storage, "index")),
13047
+ semantic: dirSize(join16(storage, "semantic")),
13048
+ backups: dirSize(join16(storage, "backups")),
13049
+ url_cache: dirSize(join16(storage, "url_cache")),
13050
+ onnxruntime: dirSize(join16(storage, "onnxruntime")),
13051
+ logs: dirSize(join16(storage, "logs"))
12788
13052
  };
12789
13053
  }
12790
13054
  }
@@ -14170,6 +14434,7 @@ async function runSetup(argv, options = {}) {
14170
14434
  }
14171
14435
  if (adapter instanceof OpenCodeAdapter) {
14172
14436
  const detection = options.detectOpenCodeHost ? options.detectOpenCodeHost() : adapter.detectHostGeneration();
14437
+ adapter.useHostDetection(detection);
14173
14438
  log2.info(`${adapter.displayName}: host generation ${formatHostGenerations(detection)}`);
14174
14439
  if (detection.status === "ambiguous") {
14175
14440
  log2.error(`${adapter.displayName}: both V1 and V2 hosts are installed; refusing to change either config until only one generation is selected on PATH.`);
@@ -14254,7 +14519,7 @@ import { spawnSync as spawnSync7 } from "node:child_process";
14254
14519
  function runIndex(argv) {
14255
14520
  const binary = findAftBinary();
14256
14521
  if (!binary) {
14257
- console.error("aft index requires a native AFT binary; run `aft doctor` to install or repair it.");
14522
+ console.error(missingAftBinaryMessage("aft index"));
14258
14523
  return 1;
14259
14524
  }
14260
14525
  const result = spawnSync7(binary, ["index", ...argv], {
@@ -14272,24 +14537,50 @@ var init_commands = __esm(async () => {
14272
14537
  });
14273
14538
 
14274
14539
  // src/doctor/opencode.ts
14275
- import { existsSync as existsSync14, readFileSync as readFileSync11 } from "node:fs";
14276
- import { dirname as dirname7, join as join16 } from "node:path";
14540
+ import { existsSync as existsSync15, readFileSync as readFileSync11 } from "node:fs";
14541
+ import { dirname as dirname7, join as join17 } from "node:path";
14277
14542
  import { fileURLToPath as fileURLToPath2 } from "node:url";
14278
14543
  function isLoadPath(value) {
14279
14544
  return OPENCODE_LOAD_PATHS.includes(value);
14280
14545
  }
14281
- function configuredAftEntry(value) {
14282
- if (!Array.isArray(value?.plugin))
14546
+ function aftEntryUnderKey(value, key) {
14547
+ const list = value?.[key];
14548
+ if (!Array.isArray(list))
14283
14549
  return null;
14284
- for (const entry of value.plugin) {
14285
- if (isAftNpmEntry(entry))
14286
- return entry;
14287
- const root = localPluginRoot(entry);
14550
+ for (const entry of list) {
14551
+ const packageSpec = pluginEntryPackage(entry);
14552
+ if (packageSpec === null)
14553
+ continue;
14554
+ if (isAftNpmEntry(packageSpec))
14555
+ return packageSpec;
14556
+ const root = localPluginRoot(packageSpec);
14288
14557
  if (root && manifestFromLocalPath(root))
14558
+ return packageSpec;
14559
+ }
14560
+ return null;
14561
+ }
14562
+ function configuredAftEntry(value, generation) {
14563
+ for (const key of openCodePluginReadKeys(generation)) {
14564
+ const entry = aftEntryUnderKey(value, key);
14565
+ if (entry)
14289
14566
  return entry;
14290
14567
  }
14291
14568
  return null;
14292
14569
  }
14570
+ function misshapenEntries(value, key) {
14571
+ const list = value?.[key];
14572
+ if (!Array.isArray(list))
14573
+ return [];
14574
+ const packages = [];
14575
+ for (const entry of list) {
14576
+ if (pluginEntryFitsKey(entry, key))
14577
+ continue;
14578
+ const packageSpec = pluginEntryPackage(entry);
14579
+ if (packageSpec !== null)
14580
+ packages.push(packageSpec);
14581
+ }
14582
+ return packages;
14583
+ }
14293
14584
  function localPluginRoot(entry) {
14294
14585
  if (typeof entry !== "string")
14295
14586
  return null;
@@ -14318,10 +14609,10 @@ function readManifest(path) {
14318
14609
  }
14319
14610
  function manifestFromLocalPath(path) {
14320
14611
  let current = path;
14321
- if (!existsSync14(join16(current, "package.json")))
14612
+ if (!existsSync15(join17(current, "package.json")))
14322
14613
  current = dirname7(current);
14323
14614
  while (true) {
14324
- const manifest = readManifest(join16(current, "package.json"));
14615
+ const manifest = readManifest(join17(current, "package.json"));
14325
14616
  if (manifest)
14326
14617
  return manifest;
14327
14618
  const parent = dirname7(current);
@@ -14334,14 +14625,14 @@ function pluginManifest(entry, cachePath) {
14334
14625
  const localRoot = localPluginRoot(entry);
14335
14626
  if (localRoot)
14336
14627
  return manifestFromLocalPath(localRoot);
14337
- return readManifest(join16(cachePath, "node_modules", "@cortexkit", "aft-opencode", "package.json"));
14628
+ return readManifest(join17(cachePath, "node_modules", "@cortexkit", "aft-opencode", "package.json"));
14338
14629
  }
14339
14630
  function hasExplicitSemver(entry) {
14340
14631
  const version = configuredVersion(entry);
14341
14632
  return Boolean(version && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.test(version));
14342
14633
  }
14343
14634
  function latestLoggedLoadPath(logPath) {
14344
- if (!existsSync14(logPath))
14635
+ if (!existsSync15(logPath))
14345
14636
  return null;
14346
14637
  try {
14347
14638
  const text = readFileSync11(logPath, "utf8");
@@ -14370,27 +14661,25 @@ function expectedOpenCodeLoadPath(detection) {
14370
14661
  }
14371
14662
  function diagnoseOpenCodeLoad(input) {
14372
14663
  const expectedLoadPath = expectedOpenCodeLoadPath(input.detection);
14664
+ const generation = input.detection.status;
14373
14665
  const config = readJsoncFile(input.configPath).value;
14374
- const entry = configuredAftEntry(config);
14666
+ const entry = configuredAftEntry(config, generation);
14375
14667
  const manifest = pluginManifest(entry, input.pluginCachePath);
14376
14668
  const logged = latestLoggedLoadPath(input.logPath);
14377
14669
  let takenLoadPath = logged;
14378
- if (!takenLoadPath && input.detection.status === "v1") {
14670
+ if (!takenLoadPath && generation === "v1") {
14379
14671
  takenLoadPath = "root-default";
14380
- } else if (!takenLoadPath && input.detection.status === "v2") {
14672
+ } else if (!takenLoadPath && generation === "v2") {
14381
14673
  takenLoadPath = expectedLoadPath;
14382
14674
  }
14383
14675
  const pluginVersion = (typeof manifest?.version === "string" ? manifest.version : null) ?? input.cachedPluginVersion ?? configuredVersion(entry) ?? null;
14384
- const problems = [];
14385
- if (config && Object.hasOwn(config, "plugins")) {
14386
- problems.push("config uses unsupported `plugins`; run doctor --fix to migrate it to `plugin`");
14387
- }
14676
+ const problems = [...describePluginKeyProblems(config, generation)];
14388
14677
  if (entry && isAftNpmEntry(entry) && input.expectedPluginEntry && entry !== input.expectedPluginEntry && !(input.acceptExplicitPluginVersion && hasExplicitSemver(entry))) {
14389
14678
  problems.push(`plugin entry ${entry} is not the required exact pin ${input.expectedPluginEntry}`);
14390
14679
  }
14391
- if (input.detection.status === "ambiguous") {
14392
- problems.push("both OpenCode V1 and V2 hosts were detected; refusing configuration writes");
14393
- } else if (input.detection.status === "unknown") {
14680
+ if (generation === "ambiguous") {
14681
+ problems.push("both OpenCode V1 and V2 hosts were detected; refusing configuration writes (a V1 host reads `plugin`, a V2 host reads `plugins`)");
14682
+ } else if (generation === "unknown") {
14394
14683
  problems.push("OpenCode host generation could not be detected");
14395
14684
  }
14396
14685
  if (expectedLoadPath && takenLoadPath && expectedLoadPath !== takenLoadPath) {
@@ -14398,6 +14687,22 @@ function diagnoseOpenCodeLoad(input) {
14398
14687
  }
14399
14688
  return { expectedLoadPath, takenLoadPath, pluginVersion, problems };
14400
14689
  }
14690
+ function describePluginKeyProblems(config, generation) {
14691
+ if (!config || generation === "ambiguous" || generation === "unknown")
14692
+ return [];
14693
+ const hostKey = openCodePluginKey(generation);
14694
+ const otherKey = otherOpenCodePluginKey(hostKey);
14695
+ const host = generation.toUpperCase();
14696
+ const problems = [];
14697
+ if (!aftEntryUnderKey(config, hostKey) && aftEntryUnderKey(config, otherKey)) {
14698
+ problems.push(`AFT is registered under \`${otherKey}\`, which a ${host} host does not read; run doctor --fix to register it under \`${hostKey}\``);
14699
+ }
14700
+ const aftEntry = aftEntryUnderKey(config, hostKey);
14701
+ for (const packageSpec of misshapenEntries(config, hostKey)) {
14702
+ problems.push(packageSpec === aftEntry ? `plugin entry ${packageSpec} under \`${hostKey}\` uses the ${host === "V1" ? "V2" : "V1"} entry shape; run doctor --fix to rewrite it` : `plugin entry ${packageSpec} under \`${hostKey}\` uses the ${host === "V1" ? "V2" : "V1"} entry shape, which a ${host} host cannot load; left unchanged because AFT did not register it`);
14703
+ }
14704
+ return problems;
14705
+ }
14401
14706
  var OPENCODE_LOAD_PATHS;
14402
14707
  var init_opencode2 = __esm(() => {
14403
14708
  init_jsonc();
@@ -14536,11 +14841,11 @@ var MAX_NOISE_LINES_IN_ERROR = 5;
14536
14841
  var init_aft_bridge = () => {};
14537
14842
 
14538
14843
  // src/lib/binary-cache.ts
14539
- import { existsSync as existsSync15, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
14540
- import { join as join17 } from "node:path";
14844
+ import { existsSync as existsSync16, readdirSync as readdirSync7, statSync as statSync8 } from "node:fs";
14845
+ import { join as join18 } from "node:path";
14541
14846
  function getBinaryCacheInfo(activeVersion) {
14542
14847
  const path = getAftBinaryCacheDir();
14543
- if (!existsSync15(path)) {
14848
+ if (!existsSync16(path)) {
14544
14849
  return {
14545
14850
  versions: [],
14546
14851
  activeVersion: null,
@@ -14548,9 +14853,9 @@ function getBinaryCacheInfo(activeVersion) {
14548
14853
  path
14549
14854
  };
14550
14855
  }
14551
- const versions = readdirSync6(path).filter((entry) => {
14856
+ const versions = readdirSync7(path).filter((entry) => {
14552
14857
  try {
14553
- return statSync8(join17(path, entry)).isDirectory();
14858
+ return statSync8(join18(path, entry)).isDirectory();
14554
14859
  } catch {
14555
14860
  return false;
14556
14861
  }
@@ -14648,13 +14953,13 @@ var init_sanitize = __esm(() => {
14648
14953
  });
14649
14954
 
14650
14955
  // src/lib/bridge-tool-failures.ts
14651
- import { closeSync as closeSync5, existsSync as existsSync16, openSync as openSync5, readSync as readSync3, statSync as statSync9 } from "node:fs";
14956
+ import { closeSync as closeSync5, existsSync as existsSync17, openSync as openSync5, readSync as readSync3, statSync as statSync9 } from "node:fs";
14652
14957
  function resolveBridgePluginLogPath() {
14653
14958
  const isTestEnv = process.env.BUN_TEST === "1" || false;
14654
14959
  return resolveAftLogPath(isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
14655
14960
  }
14656
14961
  function tailLogFileBytes(path, maxBytes) {
14657
- if (!existsSync16(path) || maxBytes <= 0)
14962
+ if (!existsSync17(path) || maxBytes <= 0)
14658
14963
  return "";
14659
14964
  let fd = null;
14660
14965
  try {
@@ -14790,9 +15095,9 @@ var init_bridge_tool_failures = __esm(() => {
14790
15095
  });
14791
15096
 
14792
15097
  // src/lib/build-breaker.ts
14793
- import { existsSync as existsSync17, readdirSync as readdirSync7 } from "node:fs";
15098
+ import { existsSync as existsSync18, readdirSync as readdirSync8 } from "node:fs";
14794
15099
  import { createRequire as createRequire3 } from "node:module";
14795
- import { join as join18 } from "node:path";
15100
+ import { join as join19 } from "node:path";
14796
15101
  function loadDatabaseSync() {
14797
15102
  const require2 = createRequire3(import.meta.url);
14798
15103
  try {
@@ -14806,11 +15111,11 @@ function loadDatabaseSync() {
14806
15111
  }
14807
15112
  }
14808
15113
  function buildBreakerDatabases(storageRoot) {
14809
- const callgraphRoot = join18(storageRoot, "callgraph");
14810
- if (!existsSync17(callgraphRoot))
15114
+ const callgraphRoot = join19(storageRoot, "callgraph");
15115
+ if (!existsSync18(callgraphRoot))
14811
15116
  return [];
14812
15117
  try {
14813
- return readdirSync7(callgraphRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join18(callgraphRoot, entry.name, "build-breaker.sqlite")).filter((path) => existsSync17(path));
15118
+ return readdirSync8(callgraphRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join19(callgraphRoot, entry.name, "build-breaker.sqlite")).filter((path) => existsSync18(path));
14814
15119
  } catch {
14815
15120
  return [];
14816
15121
  }
@@ -14886,20 +15191,20 @@ var init_build_breaker = __esm(() => {
14886
15191
  });
14887
15192
 
14888
15193
  // src/lib/legacy-storage.ts
14889
- import { existsSync as existsSync18, readdirSync as readdirSync8, statSync as statSync10 } from "node:fs";
14890
- import { join as join19 } from "node:path";
15194
+ import { existsSync as existsSync19, readdirSync as readdirSync9, statSync as statSync10 } from "node:fs";
15195
+ import { join as join20 } from "node:path";
14891
15196
  function summarizeLegacyPartitionDuplication(storageRoot) {
14892
- if (!existsSync18(storageRoot)) {
15197
+ if (!existsSync19(storageRoot)) {
14893
15198
  return { totalPartitions: 0, totalBytes: 0, byHarness: [] };
14894
15199
  }
14895
15200
  const byHarness = [];
14896
15201
  for (const harness of safeReadDir(storageRoot)) {
14897
- const harnessPath = join19(storageRoot, harness);
15202
+ const harnessPath = join20(storageRoot, harness);
14898
15203
  if (!isDirectory(harnessPath))
14899
15204
  continue;
14900
15205
  const partitions = new Map;
14901
- collectCallgraphPartitions(join19(harnessPath, "callgraph"), partitions);
14902
- collectInspectPartitions(join19(harnessPath, "inspect"), partitions);
15206
+ collectCallgraphPartitions(join20(harnessPath, "callgraph"), partitions);
15207
+ collectInspectPartitions(join20(harnessPath, "inspect"), partitions);
14903
15208
  if (partitions.size === 0)
14904
15209
  continue;
14905
15210
  let bytes = 0;
@@ -14918,7 +15223,7 @@ function collectCallgraphPartitions(domainPath, partitions) {
14918
15223
  if (!isDirectory(domainPath))
14919
15224
  return;
14920
15225
  for (const name of safeReadDir(domainPath)) {
14921
- const path = join19(domainPath, name);
15226
+ const path = join20(domainPath, name);
14922
15227
  if (isDirectory(path)) {
14923
15228
  if (!looksLikePartitionKey(name))
14924
15229
  continue;
@@ -14935,7 +15240,7 @@ function collectInspectPartitions(domainPath, partitions) {
14935
15240
  if (!isDirectory(domainPath))
14936
15241
  return;
14937
15242
  for (const name of safeReadDir(domainPath)) {
14938
- const path = join19(domainPath, name);
15243
+ const path = join20(domainPath, name);
14939
15244
  if (isDirectory(path)) {
14940
15245
  if (!looksLikePartitionKey(name))
14941
15246
  continue;
@@ -14984,7 +15289,7 @@ function looksLikePartitionKey(value) {
14984
15289
  }
14985
15290
  function safeReadDir(path) {
14986
15291
  try {
14987
- return readdirSync8(path).sort((left, right) => left.localeCompare(right));
15292
+ return readdirSync9(path).sort((left, right) => left.localeCompare(right));
14988
15293
  } catch {
14989
15294
  return [];
14990
15295
  }
@@ -15010,22 +15315,22 @@ var init_legacy_storage = __esm(() => {
15010
15315
  });
15011
15316
 
15012
15317
  // src/lib/lsp-cache.ts
15013
- import { existsSync as existsSync19, readdirSync as readdirSync9, rmSync as rmSync5, statSync as statSync11 } from "node:fs";
15014
- import { join as join20 } from "node:path";
15318
+ import { existsSync as existsSync20, readdirSync as readdirSync10, rmSync as rmSync5, statSync as statSync11 } from "node:fs";
15319
+ import { join as join21 } from "node:path";
15015
15320
  function inspectDir(path) {
15016
- if (!existsSync19(path)) {
15321
+ if (!existsSync20(path)) {
15017
15322
  return { entries: [], totalSize: 0 };
15018
15323
  }
15019
15324
  const entries = [];
15020
15325
  let totalSize = 0;
15021
15326
  let names;
15022
15327
  try {
15023
- names = readdirSync9(path);
15328
+ names = readdirSync10(path);
15024
15329
  } catch {
15025
15330
  return { entries: [], totalSize: 0 };
15026
15331
  }
15027
15332
  for (const name of names) {
15028
- const full = join20(path, name);
15333
+ const full = join21(path, name);
15029
15334
  try {
15030
15335
  if (!statSync11(full).isDirectory())
15031
15336
  continue;
@@ -15083,8 +15388,8 @@ var init_lsp_cache = __esm(() => {
15083
15388
  });
15084
15389
 
15085
15390
  // src/lib/onnx.ts
15086
- import { existsSync as existsSync20, readdirSync as readdirSync10, readlinkSync as readlinkSync2, realpathSync as realpathSync4 } from "node:fs";
15087
- import { basename as basename2, isAbsolute as isAbsolute4, join as join21, resolve as resolve10, win32 as win322 } from "node:path";
15391
+ import { existsSync as existsSync21, readdirSync as readdirSync11, readlinkSync as readlinkSync2, realpathSync as realpathSync4 } from "node:fs";
15392
+ import { basename as basename2, isAbsolute as isAbsolute4, join as join22, resolve as resolve10, win32 as win322 } from "node:path";
15088
15393
  function getOnnxLibraryName() {
15089
15394
  if (process.platform === "darwin")
15090
15395
  return "libonnxruntime.dylib";
@@ -15095,22 +15400,21 @@ function getOnnxLibraryName() {
15095
15400
  function getManualInstallHint2() {
15096
15401
  const p = process.platform;
15097
15402
  const a = process.arch;
15098
- if (p === "darwin") {
15099
- if (a === "arm64")
15100
- return "brew install onnxruntime (Apple Silicon)";
15101
- return "Intel Mac requires manual install — see docs";
15102
- }
15103
- if (p === "linux") {
15104
- if (a === "x64" || a === "arm64") {
15403
+ if (isOrtAutoDownloadSupported()) {
15404
+ if (p === "darwin")
15405
+ return "AFT auto-downloads ONNX Runtime on Apple Silicon";
15406
+ if (p === "linux")
15105
15407
  return "AFT auto-downloads ONNX Runtime on supported Linux (glibc)";
15106
- }
15107
- return "manual install required for this Linux arch";
15108
- }
15109
- if (p === "win32") {
15110
- if (a === "x64" || a === "arm64")
15408
+ if (p === "win32")
15111
15409
  return "AFT auto-downloads ONNX Runtime on Windows";
15112
- return "manual install required for this Windows arch";
15113
- }
15410
+ return `AFT auto-downloads ONNX Runtime on ${p}/${a}`;
15411
+ }
15412
+ if (p === "darwin")
15413
+ return "brew install onnxruntime (Intel Mac — no published build)";
15414
+ if (p === "linux")
15415
+ return `manual install required for this Linux arch (${a})`;
15416
+ if (p === "win32")
15417
+ return `manual install required for this Windows arch (${a})`;
15114
15418
  return "ONNX Runtime must be installed manually for this platform";
15115
15419
  }
15116
15420
  function pathEnvValue2() {
@@ -15137,7 +15441,7 @@ function isWindowsSystem32Directory2(dir) {
15137
15441
  }
15138
15442
  function directoryContainsLibrary2(dir, libName) {
15139
15443
  try {
15140
- const entries = readdirSync10(dir);
15444
+ const entries = readdirSync11(dir);
15141
15445
  if (process.platform === "win32") {
15142
15446
  const expected = libName.toLowerCase();
15143
15447
  return entries.some((entry) => entry.toLowerCase() === expected);
@@ -15155,7 +15459,7 @@ function findIgnoredWindowsSystemOnnxRuntime() {
15155
15459
  for (const root of windowsRoots) {
15156
15460
  if (!root)
15157
15461
  continue;
15158
- const systemDir = join21(root, "System32");
15462
+ const systemDir = join22(root, "System32");
15159
15463
  const key = win322.resolve(systemDir).toLowerCase();
15160
15464
  if (seen.has(key))
15161
15465
  continue;
@@ -15176,21 +15480,21 @@ function findSystemOnnxRuntime2() {
15176
15480
  searchPaths.push(...pathEntriesForPlatform2());
15177
15481
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
15178
15482
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
15179
- searchPaths.push(join21(programFiles, "onnxruntime", "lib"), join21(programFiles, "Microsoft ONNX Runtime", "lib"), join21(programFiles, "Microsoft Machine Learning", "lib"), join21(programFilesX86, "onnxruntime", "lib"), ...(() => {
15483
+ searchPaths.push(join22(programFiles, "onnxruntime", "lib"), join22(programFiles, "Microsoft ONNX Runtime", "lib"), join22(programFiles, "Microsoft Machine Learning", "lib"), join22(programFilesX86, "onnxruntime", "lib"), ...(() => {
15180
15484
  const nugetPaths = [];
15181
15485
  const userProfile = process.env.USERPROFILE ?? "";
15182
15486
  if (!userProfile)
15183
15487
  return nugetPaths;
15184
- const nugetPackageDir = join21(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
15185
- if (!existsSync20(nugetPackageDir))
15488
+ const nugetPackageDir = join22(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
15489
+ if (!existsSync21(nugetPackageDir))
15186
15490
  return nugetPaths;
15187
15491
  try {
15188
- for (const entry of readdirSync10(nugetPackageDir, { withFileTypes: true })) {
15492
+ for (const entry of readdirSync11(nugetPackageDir, { withFileTypes: true })) {
15189
15493
  if (!entry.isDirectory())
15190
15494
  continue;
15191
15495
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
15192
15496
  continue;
15193
- nugetPaths.push(join21(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join21(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
15497
+ nugetPaths.push(join22(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join22(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
15194
15498
  }
15195
15499
  } catch {}
15196
15500
  return nugetPaths;
@@ -15222,12 +15526,12 @@ function findSystemOnnxRuntime2() {
15222
15526
  return unknownVersionPaths[0] ?? null;
15223
15527
  }
15224
15528
  function findCachedOnnxRuntime(storageDir) {
15225
- const ortDir = join21(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
15529
+ const ortDir = join22(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
15226
15530
  const libName = getOnnxLibraryName();
15227
- if (existsSync20(join21(ortDir, libName)))
15531
+ if (existsSync21(join22(ortDir, libName)))
15228
15532
  return ortDir;
15229
- const libSubdir = join21(ortDir, "lib");
15230
- if (existsSync20(join21(libSubdir, libName)))
15533
+ const libSubdir = join22(ortDir, "lib");
15534
+ if (existsSync21(join22(libSubdir, libName)))
15231
15535
  return libSubdir;
15232
15536
  return null;
15233
15537
  }
@@ -15248,11 +15552,11 @@ function parseOrtVersionFromDirectoryPath(value) {
15248
15552
  return null;
15249
15553
  }
15250
15554
  function detectOrtVersion(libDir) {
15251
- if (!existsSync20(libDir))
15555
+ if (!existsSync21(libDir))
15252
15556
  return null;
15253
15557
  const libName = getOnnxLibraryName();
15254
15558
  try {
15255
- const entries = readdirSync10(libDir);
15559
+ const entries = readdirSync11(libDir);
15256
15560
  const barePrefix = libName.replace(/\.(so|dylib|dll)$/, "");
15257
15561
  const expectedPrefix = process.platform === "win32" ? barePrefix.toLowerCase() : barePrefix;
15258
15562
  for (const entry of entries) {
@@ -15263,8 +15567,8 @@ function detectOrtVersion(libDir) {
15263
15567
  if (version)
15264
15568
  return version;
15265
15569
  }
15266
- const base = join21(libDir, libName);
15267
- if (existsSync20(base)) {
15570
+ const base = join22(libDir, libName);
15571
+ if (existsSync21(base)) {
15268
15572
  try {
15269
15573
  const real = realpathSync4(base);
15270
15574
  const version = parseOrtVersionFromPath(real) ?? parseOrtVersionFromDirectoryPath(real);
@@ -15292,14 +15596,16 @@ function isOrtVersionCompatible(version) {
15292
15596
  return minor >= REQUIRED_ORT_MIN_MINOR2;
15293
15597
  }
15294
15598
  var ONNX_RUNTIME_VERSION = "1.24.4", INVALID_ORT_VERSION2 = "<invalid>", REQUIRED_ORT_MAJOR2 = 1, REQUIRED_ORT_MIN_MINOR2 = 20;
15295
- var init_onnx = () => {};
15599
+ var init_onnx = __esm(() => {
15600
+ init_dist2();
15601
+ });
15296
15602
 
15297
15603
  // src/lib/diagnostics.ts
15298
15604
  import {
15299
15605
  accessSync as accessSync3,
15300
15606
  closeSync as closeSync6,
15301
15607
  constants as constants3,
15302
- existsSync as existsSync21,
15608
+ existsSync as existsSync22,
15303
15609
  openSync as openSync6,
15304
15610
  readSync as readSync4,
15305
15611
  statSync as statSync12
@@ -15338,7 +15644,7 @@ async function diagnoseHarness(adapter) {
15338
15644
  const logPath = adapter.getLogFile();
15339
15645
  const pluginCache = adapter.getPluginCacheInfo();
15340
15646
  const storageAccessible = (() => {
15341
- if (!existsSync21(storage))
15647
+ if (!existsSync22(storage))
15342
15648
  return false;
15343
15649
  try {
15344
15650
  accessSync3(storage, constants3.R_OK | constants3.W_OK);
@@ -15363,7 +15669,7 @@ async function diagnoseHarness(adapter) {
15363
15669
  pluginRegistered: adapter.hasPluginEntry(),
15364
15670
  configPaths,
15365
15671
  aftConfig: {
15366
- exists: existsSync21(configPaths.aftConfig),
15672
+ exists: existsSync22(configPaths.aftConfig),
15367
15673
  ...aftConfigRead.error ? { parseError: aftConfigRead.error } : {},
15368
15674
  enabled: aftEnabled,
15369
15675
  ...aftEnabledSource ? { enabledSource: aftEnabledSource } : {},
@@ -15372,7 +15678,7 @@ async function diagnoseHarness(adapter) {
15372
15678
  pluginCache,
15373
15679
  storageDir: {
15374
15680
  path: storage,
15375
- exists: existsSync21(storage),
15681
+ exists: existsSync22(storage),
15376
15682
  accessible: storageAccessible,
15377
15683
  sizesByKey: describeStorage,
15378
15684
  ...legacyDuplication.totalPartitions > 0 ? { legacyDuplication } : {}
@@ -15389,12 +15695,13 @@ async function diagnoseHarness(adapter) {
15389
15695
  cachedCompatible: cachedVersion ? isOrtVersionCompatible(cachedVersion) : null,
15390
15696
  platform: `${process.platform}-${process.arch}`,
15391
15697
  installHint: getManualInstallHint2(),
15698
+ autoDownloadable: isOrtAutoDownloadSupported(),
15392
15699
  requirement: `>=${REQUIRED_ORT_MAJOR2}.${REQUIRED_ORT_MIN_MINOR2}`
15393
15700
  },
15394
15701
  logFile: {
15395
15702
  path: logPath,
15396
- exists: existsSync21(logPath),
15397
- sizeKb: existsSync21(logPath) ? Math.round(statSync12(logPath).size / 1024) : 0
15703
+ exists: existsSync22(logPath),
15704
+ sizeKb: existsSync22(logPath) ? Math.round(statSync12(logPath).size / 1024) : 0
15398
15705
  }
15399
15706
  };
15400
15707
  }
@@ -15551,7 +15858,7 @@ function collectDiagnosticIssues(report) {
15551
15858
  severity: "medium",
15552
15859
  scope: h.displayName,
15553
15860
  message: h.onnxRuntime.ignoredSystemPath ? `ONNX Runtime at ${h.onnxRuntime.ignoredSystemPath} has a ${h.onnxRuntime.ignoredSystemReason}; no compatible runtime was detected.` : "ONNX Runtime is required for semantic search but was not detected.",
15554
- remediation: `Run \`${CLI} doctor --fix\` or install ONNX Runtime manually (${h.onnxRuntime.installHint}).`
15861
+ remediation: h.onnxRuntime.autoDownloadable ? `Run \`${CLI} doctor --fix\` to download the AFT-managed ONNX Runtime.` : `Install ONNX Runtime manually (${h.onnxRuntime.installHint}); AFT has no ONNX Runtime download for ${h.onnxRuntime.platform}.`
15555
15862
  });
15556
15863
  }
15557
15864
  if (h.onnxRuntime.cachedCompatible === false) {
@@ -15591,7 +15898,7 @@ function formatDiagnosticIssuesSection(report) {
15591
15898
  return lines;
15592
15899
  }
15593
15900
  function tailLogFile(path, lines) {
15594
- if (!existsSync21(path))
15901
+ if (!existsSync22(path))
15595
15902
  return "";
15596
15903
  if (lines <= 0)
15597
15904
  return "";
@@ -15780,23 +16087,24 @@ var init_issue_body = __esm(() => {
15780
16087
  });
15781
16088
 
15782
16089
  // src/lib/onnx-fix.ts
15783
- import { existsSync as existsSync22, rmSync as rmSync6 } from "node:fs";
15784
- import { join as join22 } from "node:path";
16090
+ import { randomBytes } from "node:crypto";
16091
+ import { existsSync as existsSync23, mkdirSync as mkdirSync6, renameSync as renameSync4, rmSync as rmSync6 } from "node:fs";
16092
+ import { isAbsolute as isAbsolute5, join as join23, relative as relative2 } from "node:path";
15785
16093
  function findOnnxFixCandidates(report) {
15786
16094
  const candidates = [];
15787
16095
  for (const harness of report.harnesses) {
15788
16096
  if (!harness.onnxRuntime.required)
15789
16097
  continue;
15790
- const storageOnnxDir = join22(harness.storageDir.path, "onnxruntime");
16098
+ const storageOnnxDir = join23(harness.storageDir.path, "onnxruntime");
15791
16099
  const systemTooOld = harness.onnxRuntime.systemPath !== null && harness.onnxRuntime.systemCompatible === false;
15792
16100
  const cachedTooOld = harness.onnxRuntime.cachedPath !== null && harness.onnxRuntime.cachedCompatible === false;
15793
16101
  const hasCompatibleCached = harness.onnxRuntime.cachedCompatible === true;
15794
16102
  if (cachedTooOld) {
15795
16103
  candidates.push({
15796
16104
  harness,
15797
- 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.`,
16105
+ reason: `cached ONNX Runtime at ${harness.onnxRuntime.cachedPath} is v${harness.onnxRuntime.cachedVersion}, but AFT requires ${harness.onnxRuntime.requirement}. AFT will stage and verify a managed replacement before removing it.`,
15798
16106
  storageOnnxDir,
15799
- storageOnnxBytes: existsSync22(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
16107
+ storageOnnxBytes: existsSync23(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
15800
16108
  });
15801
16109
  continue;
15802
16110
  }
@@ -15805,7 +16113,7 @@ function findOnnxFixCandidates(report) {
15805
16113
  harness,
15806
16114
  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.`,
15807
16115
  storageOnnxDir,
15808
- storageOnnxBytes: existsSync22(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
16116
+ storageOnnxBytes: existsSync23(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
15809
16117
  });
15810
16118
  continue;
15811
16119
  }
@@ -15815,12 +16123,61 @@ function findOnnxFixCandidates(report) {
15815
16123
  harness,
15816
16124
  reason: `no compatible ONNX Runtime is installed.${ignoredCopy} AFT will download v1.24 into managed storage.`,
15817
16125
  storageOnnxDir,
15818
- storageOnnxBytes: existsSync22(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
16126
+ storageOnnxBytes: existsSync23(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
15819
16127
  });
15820
16128
  }
15821
16129
  }
15822
16130
  return candidates;
15823
16131
  }
16132
+ async function installManagedReplacement(candidate, ensureFn, rmFn) {
16133
+ const suffix = `${process.pid}.${Date.now().toString(36)}.${randomBytes(6).toString("hex")}`;
16134
+ const stagingStorageDir = `${candidate.harness.storageDir.path}.onnx-fix.tmp.${suffix}`;
16135
+ const stagedOnnxDir = join23(stagingStorageDir, "onnxruntime");
16136
+ const backupDir = `${candidate.storageOnnxDir}.backup.${suffix}`;
16137
+ try {
16138
+ const stagedInstalledPath = await ensureFn(stagingStorageDir);
16139
+ if (!stagedInstalledPath || !existsSync23(stagedInstalledPath)) {
16140
+ throw new Error("managed ONNX Runtime download was unavailable");
16141
+ }
16142
+ const installedRelativePath = relative2(stagedOnnxDir, stagedInstalledPath);
16143
+ if (isAbsolute5(installedRelativePath) || installedRelativePath === ".." || installedRelativePath.startsWith("../") || installedRelativePath.startsWith("..\\")) {
16144
+ throw new Error(`managed ONNX Runtime was installed outside staging: ${stagedInstalledPath}`);
16145
+ }
16146
+ mkdirSync6(candidate.harness.storageDir.path, { recursive: true });
16147
+ const hadPrevious = existsSync23(candidate.storageOnnxDir);
16148
+ if (hadPrevious)
16149
+ renameSync4(candidate.storageOnnxDir, backupDir);
16150
+ try {
16151
+ renameSync4(stagedOnnxDir, candidate.storageOnnxDir);
16152
+ } catch (installError) {
16153
+ if (hadPrevious) {
16154
+ try {
16155
+ renameSync4(backupDir, candidate.storageOnnxDir);
16156
+ } catch (restoreError) {
16157
+ throw new Error(`managed ONNX Runtime replacement failed and the previous runtime could not be restored from ${backupDir}: ${restoreError}`, { cause: installError });
16158
+ }
16159
+ }
16160
+ throw installError;
16161
+ }
16162
+ let cleanupError;
16163
+ if (hadPrevious) {
16164
+ try {
16165
+ rmFn(backupDir, { recursive: true, force: true });
16166
+ } catch (err) {
16167
+ cleanupError = err instanceof Error ? err.message : String(err);
16168
+ }
16169
+ }
16170
+ return {
16171
+ installedPath: join23(candidate.storageOnnxDir, installedRelativePath),
16172
+ clearedPrevious: hadPrevious && cleanupError === undefined,
16173
+ cleanupError
16174
+ };
16175
+ } finally {
16176
+ try {
16177
+ rmSync6(stagingStorageDir, { recursive: true, force: true });
16178
+ } catch {}
16179
+ }
16180
+ }
15824
16181
  async function runOnnxFix(adapters, report, options = {}) {
15825
16182
  const candidates = findOnnxFixCandidates(report);
15826
16183
  if (candidates.length === 0)
@@ -15829,12 +16186,12 @@ async function runOnnxFix(adapters, report, options = {}) {
15829
16186
  for (const candidate of candidates) {
15830
16187
  log2.info(` • ${candidate.harness.displayName}: ${candidate.reason}`);
15831
16188
  if (candidate.storageOnnxBytes > 0) {
15832
- log2.info(` will delete: ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)})`);
16189
+ log2.info(` will replace after a verified download: ${candidate.storageOnnxDir} (${formatBytes(candidate.storageOnnxBytes)})`);
15833
16190
  } else {
15834
16191
  log2.info(" no AFT-managed ONNX cache to delete");
15835
16192
  }
15836
16193
  }
15837
- 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");
16194
+ note("This NEVER touches system paths like /usr/lib or C:\\Windows\\System32. It downloads and verifies a replacement before swapping AFT's own ONNX cache.", "Safe operation");
15838
16195
  const confirmFn = options.confirmFn ?? confirm2;
15839
16196
  const proceed = options.yes ? true : await confirmFn("Proceed with the fixes above?", true);
15840
16197
  if (!proceed) {
@@ -15845,30 +16202,20 @@ async function runOnnxFix(adapters, report, options = {}) {
15845
16202
  const rmFn = options.rmFn ?? rmSync6;
15846
16203
  const ensureFn = options.ensureFn ?? ensureOnnxRuntime;
15847
16204
  for (const candidate of candidates) {
15848
- if (existsSync22(candidate.storageOnnxDir)) {
15849
- try {
15850
- rmFn(candidate.storageOnnxDir, { recursive: true, force: true });
16205
+ try {
16206
+ log2.info(`${candidate.harness.displayName}: downloading managed ONNX Runtime…`);
16207
+ const replacement = await installManagedReplacement(candidate, ensureFn, rmFn);
16208
+ if (replacement.clearedPrevious) {
15851
16209
  result.cleared += 1;
15852
16210
  result.bytesReclaimed += candidate.storageOnnxBytes;
15853
- log2.success(`${candidate.harness.displayName}: cleared ${candidate.storageOnnxDir} (reclaimed ${formatBytes(candidate.storageOnnxBytes)})`);
15854
- } catch (err) {
15855
- const message = err instanceof Error ? err.message : String(err);
15856
- log2.error(`${candidate.harness.displayName}: failed to clear ${candidate.storageOnnxDir}: ${message}`);
15857
- result.errors.push({ path: candidate.storageOnnxDir, error: message });
15858
- continue;
16211
+ log2.success(`${candidate.harness.displayName}: replaced ${candidate.storageOnnxDir} (reclaimed ${formatBytes(candidate.storageOnnxBytes)})`);
15859
16212
  }
15860
- }
15861
- try {
15862
- log2.info(`${candidate.harness.displayName}: downloading managed ONNX Runtime…`);
15863
- const installedPath = await ensureFn(candidate.harness.storageDir.path);
15864
- if (!installedPath) {
15865
- const message = "managed ONNX Runtime download was unavailable";
15866
- log2.error(`${candidate.harness.displayName}: ${message}`);
15867
- result.errors.push({ path: candidate.storageOnnxDir, error: message });
15868
- continue;
16213
+ if (replacement.cleanupError) {
16214
+ log2.warn(`${candidate.harness.displayName}: installed the replacement but could not remove the previous runtime backup: ${replacement.cleanupError}`);
16215
+ result.errors.push({ path: candidate.storageOnnxDir, error: replacement.cleanupError });
15869
16216
  }
15870
16217
  result.installed += 1;
15871
- log2.success(`${candidate.harness.displayName}: ONNX Runtime installed at ${installedPath}`);
16218
+ log2.success(`${candidate.harness.displayName}: ONNX Runtime installed at ${replacement.installedPath}`);
15872
16219
  } catch (err) {
15873
16220
  const message = err instanceof Error ? err.message : String(err);
15874
16221
  log2.error(`${candidate.harness.displayName}: ONNX Runtime download failed: ${message}`);
@@ -15887,10 +16234,10 @@ var init_onnx_fix = __esm(() => {
15887
16234
  });
15888
16235
 
15889
16236
  // src/lib/sessions.ts
15890
- import { existsSync as existsSync23, readdirSync as readdirSync11, readFileSync as readFileSync12, statSync as statSync13 } from "node:fs";
16237
+ import { existsSync as existsSync24, readdirSync as readdirSync12, readFileSync as readFileSync12, statSync as statSync13 } from "node:fs";
15891
16238
  import { createRequire as createRequire4 } from "node:module";
15892
16239
  import { homedir as homedir13 } from "node:os";
15893
- import { basename as basename3, join as join23 } from "node:path";
16240
+ import { basename as basename3, join as join24 } from "node:path";
15894
16241
  function listRecentSessions(adapter) {
15895
16242
  try {
15896
16243
  if (adapter.kind === "opencode")
@@ -15921,8 +16268,8 @@ function mapOpenCodeSessionRows(rows) {
15921
16268
  }).filter((session) => session !== null).sort((a, b) => b.lastActivity - a.lastActivity).slice(0, MAX_RECENT_SESSIONS);
15922
16269
  }
15923
16270
  function listRecentOpenCodeSessions() {
15924
- const dbPath = join23(getXdgDataHome(), "opencode", "opencode.db");
15925
- if (!existsSync23(dbPath))
16271
+ const dbPath = join24(getXdgDataHome(), "opencode", "opencode.db");
16272
+ if (!existsSync24(dbPath))
15926
16273
  return [];
15927
16274
  let db = null;
15928
16275
  try {
@@ -15941,10 +16288,10 @@ function listRecentOpenCodeSessions() {
15941
16288
  }
15942
16289
  function getXdgDataHome() {
15943
16290
  const xdgDataHome = process.env.XDG_DATA_HOME;
15944
- return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join23(homedir13(), ".local", "share");
16291
+ return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join24(homedir13(), ".local", "share");
15945
16292
  }
15946
16293
  function listRecentPiSessions() {
15947
- return listPiSessionsFromDir(join23(getHomeDir(), ".pi", "agent", "sessions"));
16294
+ return listPiSessionsFromDir(join24(getHomeDir(), ".pi", "agent", "sessions"));
15948
16295
  }
15949
16296
  function getHomeDir() {
15950
16297
  const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
@@ -15952,7 +16299,7 @@ function getHomeDir() {
15952
16299
  }
15953
16300
  function listPiSessionsFromDir(sessionsDir) {
15954
16301
  try {
15955
- if (!existsSync23(sessionsDir))
16302
+ if (!existsSync24(sessionsDir))
15956
16303
  return [];
15957
16304
  const files = collectJsonlFiles(sessionsDir).map((filePath) => {
15958
16305
  try {
@@ -15985,12 +16332,12 @@ function collectJsonlFiles(root) {
15985
16332
  continue;
15986
16333
  let entries;
15987
16334
  try {
15988
- entries = readdirSync11(dir, { withFileTypes: true });
16335
+ entries = readdirSync12(dir, { withFileTypes: true });
15989
16336
  } catch {
15990
16337
  continue;
15991
16338
  }
15992
16339
  for (const entry of entries) {
15993
- const path = join23(dir, entry.name);
16340
+ const path = join24(dir, entry.name);
15994
16341
  if (entry.isDirectory()) {
15995
16342
  stack.push(path);
15996
16343
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -16077,8 +16424,8 @@ var init_sessions = __esm(() => {
16077
16424
  import { spawn as spawn4, spawnSync as spawnSync9 } from "node:child_process";
16078
16425
  import {
16079
16426
  chmodSync as chmodSync4,
16080
- existsSync as existsSync24,
16081
- mkdirSync as mkdirSync6,
16427
+ existsSync as existsSync25,
16428
+ mkdirSync as mkdirSync7,
16082
16429
  mkdtempSync as mkdtempSync2,
16083
16430
  readFileSync as readFileSync13,
16084
16431
  realpathSync as realpathSync5,
@@ -16087,7 +16434,7 @@ import {
16087
16434
  writeFileSync as writeFileSync3
16088
16435
  } from "node:fs";
16089
16436
  import { tmpdir as tmpdir2 } from "node:os";
16090
- import { join as join24 } from "node:path";
16437
+ import { join as join25 } from "node:path";
16091
16438
  function openCodeAdapter(adapters) {
16092
16439
  return adapters.find((adapter) => adapter.kind === "opencode");
16093
16440
  }
@@ -16095,9 +16442,11 @@ function detectOpenCodeForCommand(adapters, override) {
16095
16442
  const adapter = openCodeAdapter(adapters);
16096
16443
  if (!adapter)
16097
16444
  return null;
16098
- if (override)
16099
- return override();
16100
- return adapter instanceof OpenCodeAdapter ? adapter.detectHostGeneration() : null;
16445
+ if (!(adapter instanceof OpenCodeAdapter))
16446
+ return override ? override() : null;
16447
+ const detection = override ? override() : adapter.detectHostGeneration();
16448
+ adapter.useHostDetection(detection);
16449
+ return detection;
16101
16450
  }
16102
16451
  function refuseAmbiguousOpenCodeWrites(detection) {
16103
16452
  if (detection?.status !== "ambiguous")
@@ -16122,7 +16471,7 @@ function buildDoctorProfileArgs(argv) {
16122
16471
  function runDoctorProfile(argv) {
16123
16472
  const binary = findAftBinary();
16124
16473
  if (!binary) {
16125
- console.error("aft doctor --profile requires a native AFT binary; run `aft doctor --fix` first.");
16474
+ console.error(missingAftBinaryMessage("aft doctor --profile"));
16126
16475
  return 1;
16127
16476
  }
16128
16477
  const result = spawnSync9(binary, buildDoctorProfileArgs(argv), {
@@ -16141,7 +16490,7 @@ async function runDoctor(options) {
16141
16490
  }
16142
16491
  intro(`${CLI} doctor`);
16143
16492
  if (options.fix) {
16144
- return runFixFlow(options.argv, options.detectOpenCodeHost, options.resolveAdapters, options.collectDiagnostics);
16493
+ return runFixFlow(options.argv, options.detectOpenCodeHost, options.resolveAdapters, options.collectDiagnostics, options.applyOnnxFix);
16145
16494
  }
16146
16495
  if (options.clear) {
16147
16496
  return runClearFlow(options.argv);
@@ -16448,7 +16797,7 @@ function clearOldBinaries() {
16448
16797
  errors: [],
16449
16798
  keptVersion: keepTag
16450
16799
  };
16451
- if (!existsSync24(info.path)) {
16800
+ if (!existsSync25(info.path)) {
16452
16801
  log2.info(`Binary cache: nothing to clear at ${info.path}`);
16453
16802
  return result;
16454
16803
  }
@@ -16458,7 +16807,7 @@ function clearOldBinaries() {
16458
16807
  return result;
16459
16808
  }
16460
16809
  for (const version of stale) {
16461
- const dir = join24(info.path, version);
16810
+ const dir = join25(info.path, version);
16462
16811
  let bytes = 0;
16463
16812
  try {
16464
16813
  bytes = statSync14(dir).isDirectory() ? dirSize(dir) : 0;
@@ -16748,15 +17097,16 @@ function logUnmatchedBinaryCandidates(expectedVersion) {
16748
17097
  log2.warn(` unmatched: ${candidate.path} reported v${candidate.version ?? "unknown"}`);
16749
17098
  }
16750
17099
  }
16751
- async function runFixFlow(argv, detectOpenCodeHost, resolveAdapters = resolveAdaptersForCommand, collect = collectDiagnostics) {
17100
+ async function runFixFlow(argv, detectOpenCodeHost, resolveAdapters = resolveAdaptersForCommand, collect = collectDiagnostics, applyOnnxFix = runOnnxFix) {
16752
17101
  const adapters = await resolveAdapters(argv, {
16753
17102
  allowMulti: false,
16754
17103
  verb: "auto-fix issues for"
16755
17104
  });
16756
17105
  const hostDetection = detectOpenCodeForCommand(adapters, detectOpenCodeHost);
16757
- if (refuseAmbiguousOpenCodeWrites(hostDetection)) {
16758
- outro("Done — no changes made.");
16759
- return 1;
17106
+ const configWritesRefused = refuseAmbiguousOpenCodeWrites(hostDetection);
17107
+ const skipped = [];
17108
+ if (configWritesRefused) {
17109
+ skipped.push("plugin registration in the OpenCode config (leave one OpenCode generation on PATH and re-run)");
16760
17110
  }
16761
17111
  if (hostDetection?.status === "unknown") {
16762
17112
  log2.warn("OpenCode: host generation is unavailable; applying only generation-independent exact-pin config fixes.");
@@ -16768,7 +17118,7 @@ async function runFixFlow(argv, detectOpenCodeHost, resolveAdapters = resolveAda
16768
17118
  if (!report.binaryVersion) {
16769
17119
  logUnmatchedBinaryCandidates(report.cliVersion);
16770
17120
  }
16771
- const plan = buildDoctorFixPlan(adapters, report);
17121
+ const plan = buildDoctorFixPlan(adapters, report).filter((item) => !(configWritesRefused && item.kind === "plugin"));
16772
17122
  if (plan.length > 0) {
16773
17123
  log2.warn("Planned changes:");
16774
17124
  for (const item of plan) {
@@ -16780,7 +17130,7 @@ async function runFixFlow(argv, detectOpenCodeHost, resolveAdapters = resolveAda
16780
17130
  return 0;
16781
17131
  }
16782
17132
  }
16783
- await fixPluginEntries(adapters);
17133
+ const pluginEntrySummary = configWritesRefused ? { changed: 0, errors: 0 } : await fixPluginEntries(adapters);
16784
17134
  const pluginUpdateSummary = await applyPluginUpdates(findPluginUpdateTargets(adapters, report));
16785
17135
  const storageSummary = ensureStorageDirsForRegisteredPlugins(adapters);
16786
17136
  const schemaSummary = applySchemaFixes(findSchemaFixTargets(adapters));
@@ -16791,6 +17141,7 @@ async function runFixFlow(argv, detectOpenCodeHost, resolveAdapters = resolveAda
16791
17141
  const shouldDownload = await confirmBinaryDownloadDespitePluginSkew(report, argv);
16792
17142
  if (!shouldDownload) {
16793
17143
  binaryDownloadSkipped = true;
17144
+ skipped.push("aft binary download (declined because the installed plugin would not use it)");
16794
17145
  } else {
16795
17146
  log2.info("AFT binary not found. Downloading…");
16796
17147
  try {
@@ -16810,20 +17161,37 @@ async function runFixFlow(argv, detectOpenCodeHost, resolveAdapters = resolveAda
16810
17161
  }
16811
17162
  }
16812
17163
  }
16813
- const onnxResult = await runOnnxFix(adapters, report, { yes: true });
16814
- if (onnxResult === null && !binaryDownloaded && !binaryDownloadSkipped && !binaryDownloadError && storageSummary.created === 0 && storageSummary.errors === 0 && schemaSummary.changed === 0 && schemaSummary.errors === 0 && pluginUpdateSummary.updated === 0 && pluginUpdateSummary.errors === 0) {
17164
+ const onnxResult = await applyOnnxFix(adapters, report, { yes: true });
17165
+ const applied = [];
17166
+ if (pluginEntrySummary.changed > 0)
17167
+ applied.push("plugin registration");
17168
+ if (pluginUpdateSummary.updated > 0)
17169
+ applied.push("plugin package update");
17170
+ if (storageSummary.created > 0)
17171
+ applied.push("AFT storage directory");
17172
+ if (schemaSummary.changed > 0)
17173
+ applied.push("AFT config $schema");
17174
+ if (binaryDownloaded)
17175
+ applied.push("aft binary download");
17176
+ if ((onnxResult?.installed ?? 0) > 0)
17177
+ applied.push("ONNX Runtime install");
17178
+ const nothingAttempted = onnxResult === null && !binaryDownloaded && !binaryDownloadSkipped && !binaryDownloadError && storageSummary.created === 0 && storageSummary.errors === 0 && schemaSummary.changed === 0 && schemaSummary.errors === 0 && pluginEntrySummary.changed === 0 && pluginEntrySummary.errors === 0 && pluginUpdateSummary.updated === 0 && pluginUpdateSummary.errors === 0;
17179
+ if (nothingAttempted && skipped.length === 0) {
16815
17180
  log2.info("No auto-fixable issues detected.");
16816
17181
  note(`If you're still seeing 'Semantic Index: failed' in the TUI sidebar, run \`${CLI} doctor\` (without --fix) for a full diagnostic dump.`, "Tip");
16817
- const afterReport = await collect(adapters);
16818
- const stillHasProblems = hasDoctorProblems(afterReport);
16819
- outro(stillHasProblems ? "Done — some issues remain." : "Done.");
16820
- return stillHasProblems ? 1 : 0;
17182
+ } else {
17183
+ logDoctorFixSummary(applied, skipped);
16821
17184
  }
16822
- const hadErrors = (onnxResult?.errors.length ?? 0) > 0 || binaryDownloadError !== null || storageSummary.errors > 0 || schemaSummary.errors > 0 || pluginUpdateSummary.errors > 0;
16823
- const afterReport = await collectDiagnostics(adapters);
17185
+ const hadErrors = (onnxResult?.errors.length ?? 0) > 0 || binaryDownloadError !== null || storageSummary.errors > 0 || schemaSummary.errors > 0 || pluginEntrySummary.errors > 0 || pluginUpdateSummary.errors > 0;
17186
+ const afterReport = await collect(adapters);
16824
17187
  const stillHasProblems = hasDoctorProblems(afterReport);
16825
- outro(hadErrors ? "Done — some fixes failed." : stillHasProblems ? "Done — some issues remain." : "Done.");
16826
- return hadErrors || stillHasProblems ? 1 : 0;
17188
+ outro(hadErrors ? "Done — some fixes failed." : skipped.length > 0 ? "Done — some fixes were skipped." : stillHasProblems ? "Done — some issues remain." : "Done.");
17189
+ return hadErrors || stillHasProblems || configWritesRefused ? 1 : 0;
17190
+ }
17191
+ function logDoctorFixSummary(applied, skipped) {
17192
+ log2.info(applied.length > 0 ? `Applied: ${applied.join(", ")}.` : "Applied: no changes.");
17193
+ if (skipped.length > 0)
17194
+ log2.warn(`Skipped: ${skipped.join("; ")}.`);
16827
17195
  }
16828
17196
  function logDoctorIssues(report) {
16829
17197
  const lines = formatDiagnosticIssuesSection(report);
@@ -16877,9 +17245,9 @@ function ensureStorageDirsForRegisteredPlugins(adapters) {
16877
17245
  if (!adapter.isInstalled() || !adapter.hasPluginEntry())
16878
17246
  continue;
16879
17247
  const storageDir = adapter.getStorageDir();
16880
- if (existsSync24(storageDir))
17248
+ if (existsSync25(storageDir))
16881
17249
  continue;
16882
- mkdirSync6(storageDir, { recursive: true });
17250
+ mkdirSync7(storageDir, { recursive: true });
16883
17251
  summary.created += 1;
16884
17252
  log2.success(`${adapter.displayName}: created AFT storage directory at ${storageDir}`);
16885
17253
  } catch (err) {
@@ -16926,19 +17294,27 @@ function reportLspCacheClear(cleanup) {
16926
17294
  }
16927
17295
  }
16928
17296
  async function fixPluginEntries(adapters) {
17297
+ const summary = { changed: 0, errors: 0 };
16929
17298
  for (const adapter of adapters) {
16930
- await maybeFixPlugin(adapter);
17299
+ const result = await maybeFixPlugin(adapter);
17300
+ summary.changed += result.changed;
17301
+ summary.errors += result.errors;
16931
17302
  }
17303
+ return summary;
16932
17304
  }
16933
17305
  async function maybeFixPlugin(adapter) {
17306
+ const summary = { changed: 0, errors: 0 };
16934
17307
  if (!adapter.isInstalled())
16935
- return;
17308
+ return summary;
16936
17309
  if (!adapter.hasPluginEntry() || adapterConfigNeedsUpdate(adapter)) {
16937
17310
  log2.info(`${adapter.displayName}: attempting to register or update plugin config…`);
16938
17311
  const result = await adapter.ensurePluginEntry();
16939
17312
  if (result.ok) {
17313
+ if (result.action === "added" || result.action === "updated")
17314
+ summary.changed += 1;
16940
17315
  log2.success(`${adapter.displayName}: ${result.message}`);
16941
17316
  } else {
17317
+ summary.errors += 1;
16942
17318
  log2.error(`${adapter.displayName}: ${result.message}`);
16943
17319
  }
16944
17320
  }
@@ -16947,12 +17323,15 @@ async function maybeFixPlugin(adapter) {
16947
17323
  if (!hasTuiEntry || adapterConfigNeedsUpdate(adapter, true)) {
16948
17324
  const result = await adapter.ensureTuiPluginEntry();
16949
17325
  if (result.ok && (result.action === "added" || result.action === "updated")) {
17326
+ summary.changed += 1;
16950
17327
  log2.success(`${adapter.displayName}: ${result.message}`);
16951
17328
  } else if (!result.ok) {
17329
+ summary.errors += 1;
16952
17330
  log2.error(`${adapter.displayName}: ${result.message}`);
16953
17331
  }
16954
17332
  }
16955
17333
  }
17334
+ return summary;
16956
17335
  }
16957
17336
  function describeAdapterInstallHint(kind) {
16958
17337
  if (kind === "opencode")
@@ -17027,11 +17406,11 @@ function deriveIssueTitleFromBody(body) {
17027
17406
  function writeIssueReviewFile(body) {
17028
17407
  let reviewDir = null;
17029
17408
  try {
17030
- reviewDir = mkdtempSync2(join24(tmpdir2(), "aft-issue-"));
17409
+ reviewDir = mkdtempSync2(join25(tmpdir2(), "aft-issue-"));
17031
17410
  if (process.platform !== "win32") {
17032
17411
  chmodSync4(reviewDir, 448);
17033
17412
  }
17034
- const outPath = join24(reviewDir, "issue.md");
17413
+ const outPath = join25(reviewDir, "issue.md");
17035
17414
  writeFileSync3(outPath, `${body}
17036
17415
  `, { encoding: "utf8", mode: 384, flag: "wx" });
17037
17416
  return { path: outPath, realPath: realpathSync5(outPath) };
@@ -17233,21 +17612,21 @@ var init_doctor = __esm(async () => {
17233
17612
  });
17234
17613
 
17235
17614
  // src/commands/lsp.ts
17236
- import { existsSync as existsSync25, readdirSync as readdirSync12, statSync as statSync15 } from "node:fs";
17615
+ import { existsSync as existsSync26, readdirSync as readdirSync13, statSync as statSync15 } from "node:fs";
17237
17616
  import { createRequire as createRequire5 } from "node:module";
17238
- import { dirname as dirname8, join as join25, resolve as resolve11 } from "node:path";
17617
+ import { dirname as dirname8, join as join26, resolve as resolve11 } from "node:path";
17239
17618
  function findProjectRootForFile(filePath, fallbackCwd = process.cwd()) {
17240
17619
  const resolvedFile = resolve11(fallbackCwd, filePath);
17241
17620
  let dir = dirname8(resolvedFile);
17242
17621
  try {
17243
- if (existsSync25(resolvedFile) && statSync15(resolvedFile).isDirectory()) {
17622
+ if (existsSync26(resolvedFile) && statSync15(resolvedFile).isDirectory()) {
17244
17623
  dir = resolvedFile;
17245
17624
  }
17246
17625
  } catch {
17247
17626
  dir = dirname8(resolvedFile);
17248
17627
  }
17249
17628
  while (true) {
17250
- if (PROJECT_ROOT_MARKERS.some((marker) => existsSync25(join25(dir, marker)))) {
17629
+ if (PROJECT_ROOT_MARKERS.some((marker) => existsSync26(join26(dir, marker)))) {
17251
17630
  return dir;
17252
17631
  }
17253
17632
  const parent = dirname8(dir);
@@ -17396,18 +17775,18 @@ function buildConfigureParams(adapter, projectRoot) {
17396
17775
  function inferLspPathsExtra(_lsp) {
17397
17776
  const paths = new Set;
17398
17777
  for (const entry of childDirs(getAftLspPackagesDir())) {
17399
- paths.add(join25(entry, "node_modules", ".bin"));
17778
+ paths.add(join26(entry, "node_modules", ".bin"));
17400
17779
  }
17401
17780
  for (const entry of childDirs(getAftLspBinariesDir())) {
17402
- paths.add(join25(entry, "bin"));
17781
+ paths.add(join26(entry, "bin"));
17403
17782
  }
17404
17783
  return [...paths];
17405
17784
  }
17406
17785
  function childDirs(path) {
17407
- if (!existsSync25(path))
17786
+ if (!existsSync26(path))
17408
17787
  return [];
17409
17788
  try {
17410
- return readdirSync12(path).map((entry) => join25(path, entry)).filter((entry) => {
17789
+ return readdirSync13(path).map((entry) => join26(path, entry)).filter((entry) => {
17411
17790
  try {
17412
17791
  return statSync15(entry).isDirectory();
17413
17792
  } catch {
@@ -17449,7 +17828,7 @@ function typescriptPackageWarning(response) {
17449
17828
  if (!typescriptServerSpawned || !response.project_root || diagnosticsCount > 0)
17450
17829
  return null;
17451
17830
  try {
17452
- createRequire5(join25(response.project_root, "package.json")).resolve("typescript");
17831
+ createRequire5(join26(response.project_root, "package.json")).resolve("typescript");
17453
17832
  return null;
17454
17833
  } catch {
17455
17834
  return "typescript package not resolvable from project — server will produce no diagnostics";
@@ -17489,9 +17868,9 @@ var init_lsp = __esm(async () => {
17489
17868
  });
17490
17869
 
17491
17870
  // src/commands/doctor-filters.ts
17492
- import { existsSync as existsSync26 } from "node:fs";
17871
+ import { existsSync as existsSync27 } from "node:fs";
17493
17872
  import { homedir as homedir14 } from "node:os";
17494
- import { relative as relative2, resolve as resolve12 } from "node:path";
17873
+ import { relative as relative3, resolve as resolve12 } from "node:path";
17495
17874
  function printDoctorFiltersHelp() {
17496
17875
  console.log(`Usage: ${CLI} doctor filters [--show <name>] [trust|untrust]`);
17497
17876
  console.log("");
@@ -17532,7 +17911,7 @@ async function runDoctorFilters(options) {
17532
17911
  log2.error(list.message ?? list.code ?? "list_filters failed");
17533
17912
  return 1;
17534
17913
  }
17535
- list.project_dir_exists = list.project_dir ? existsSync26(list.project_dir) : false;
17914
+ list.project_dir_exists = list.project_dir ? existsSync27(list.project_dir) : false;
17536
17915
  if (mode.kind === "list") {
17537
17916
  console.log(renderFilterList(list, projectRoot));
17538
17917
  return 0;
@@ -17714,7 +18093,7 @@ function formatHome(path) {
17714
18093
  function formatProjectPath(path, projectRoot) {
17715
18094
  if (!path)
17716
18095
  return "";
17717
- const rel = relative2(projectRoot, path);
18096
+ const rel = relative3(projectRoot, path);
17718
18097
  return rel.startsWith("..") || rel === "" ? path : `./${rel}`;
17719
18098
  }
17720
18099
  function formatSourcePath(path, projectRoot) {