@cortexkit/aft-opencode 0.56.2 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/bg-notifications.d.ts +1 -0
  2. package/dist/bg-notifications.d.ts.map +1 -1
  3. package/dist/entry/server.js +2650 -267
  4. package/dist/index.js +420 -228
  5. package/dist/lsp-github-install.d.ts.map +1 -1
  6. package/dist/permissions/v2-service.d.ts +30 -0
  7. package/dist/permissions/v2-service.d.ts.map +1 -0
  8. package/dist/permissions/v2.d.ts +121 -9
  9. package/dist/permissions/v2.d.ts.map +1 -1
  10. package/dist/shared/rpc-server.d.ts.map +1 -1
  11. package/dist/shared/status.d.ts +8 -1
  12. package/dist/shared/status.d.ts.map +1 -1
  13. package/dist/subc-tool-schemas.d.ts +11 -0
  14. package/dist/subc-tool-schemas.d.ts.map +1 -1
  15. package/dist/tool-registration.d.ts.map +1 -1
  16. package/dist/tools/definitions/v2.d.ts +6 -0
  17. package/dist/tools/definitions/v2.d.ts.map +1 -1
  18. package/dist/tools/hoisted/v2.d.ts +12 -2
  19. package/dist/tools/hoisted/v2.d.ts.map +1 -1
  20. package/dist/tools/hoisted.d.ts.map +1 -1
  21. package/dist/tools/semantic.d.ts.map +1 -1
  22. package/dist/tui/v2-status.d.ts +8 -0
  23. package/dist/tui/v2-status.d.ts.map +1 -1
  24. package/index.js +14 -0
  25. package/package.json +14 -10
  26. package/server.js +8 -0
  27. package/src/shared/rpc-server.ts +5 -0
  28. package/src/shared/status.ts +16 -9
  29. package/src/tui/index.tsx +1 -0
  30. package/src/tui/sidebar-view.tsx +722 -0
  31. package/src/tui/sidebar.tsx +42 -560
  32. package/src/tui/v2-status.ts +8 -1
  33. package/src/tui/v2.tsx +173 -30
  34. package/src/tui-compiled/index.tsx +1 -1
  35. package/src/tui-compiled/sidebar-view.tsx +815 -0
  36. package/src/tui-compiled/sidebar.tsx +45 -693
  37. package/src/tui-compiled/v2-status.ts +8 -1
  38. package/src/tui-compiled/v2.tsx +163 -54
  39. package/tui.js +7 -0
package/dist/index.js CHANGED
@@ -44,6 +44,17 @@ var __export = (target, all) => {
44
44
  set: __exportSetter.bind(all, name)
45
45
  });
46
46
  };
47
+ var __esm = (fn, res, err) => () => {
48
+ if (fn)
49
+ try {
50
+ res = fn(fn = 0);
51
+ } catch (e) {
52
+ err = [e];
53
+ }
54
+ if (err)
55
+ throw err[0];
56
+ return res;
57
+ };
47
58
 
48
59
  // ../../node_modules/.bun/esprima@4.0.1/node_modules/esprima/dist/esprima.js
49
60
  var require_esprima = __commonJS(function(exports, module) {
@@ -15543,12 +15554,36 @@ function isNpmAvailable(deps = defaultDeps()) {
15543
15554
  return resolveNpm(deps) !== null;
15544
15555
  }
15545
15556
  // ../aft-bridge/dist/onnx-runtime.js
15546
- import { execFileSync } from "node:child_process";
15557
+ import { execFileSync as execFileSync2 } from "node:child_process";
15547
15558
  import { createHash as createHash4 } from "node:crypto";
15548
- import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync9, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, rmSync as rmSync3, statSync as statSync6, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
15549
- import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute5, join as join12, relative as relative2, resolve as resolve7, win32 } from "node:path";
15559
+ import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync10, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync6, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
15560
+ import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute5, join as join13, relative as relative2, resolve as resolve7, win32 } from "node:path";
15550
15561
  import { Readable as Readable2 } from "node:stream";
15551
15562
  import { pipeline as pipeline2 } from "node:stream/promises";
15563
+
15564
+ // ../aft-bridge/dist/tar-executable.js
15565
+ import { execFileSync } from "node:child_process";
15566
+ import { existsSync as existsSync9 } from "node:fs";
15567
+ import { join as join12 } from "node:path";
15568
+ function windowsTarExecutable(options = {}) {
15569
+ const platform = options.platform ?? process.platform;
15570
+ if (platform !== "win32")
15571
+ return "tar";
15572
+ const env = options.env ?? process.env;
15573
+ const systemTar = join12(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
15574
+ return (options.exists ?? existsSync9)(systemTar) ? systemTar : "tar";
15575
+ }
15576
+ function execTarExtractionSync(args, timeout) {
15577
+ const executable = windowsTarExecutable();
15578
+ try {
15579
+ execFileSync(executable, args, { stdio: "pipe", timeout });
15580
+ } catch (cause) {
15581
+ const detail = cause instanceof Error ? cause.message : String(cause);
15582
+ throw new Error(`tar extraction failed using ${executable}: ${detail}`, { cause });
15583
+ }
15584
+ }
15585
+
15586
+ // ../aft-bridge/dist/onnx-runtime.js
15552
15587
  var ORT_VERSION = "1.24.4";
15553
15588
  var ORT_REPO = "microsoft/onnxruntime";
15554
15589
  var MAX_DOWNLOAD_BYTES2 = 256 * 1024 * 1024;
@@ -15612,11 +15647,11 @@ function getManualInstallHint() {
15612
15647
  }
15613
15648
  async function ensureOnnxRuntime(storageDir) {
15614
15649
  const info = getPlatformInfo();
15615
- const ortVersionDir = join12(storageDir, "onnxruntime", ORT_VERSION);
15650
+ const ortVersionDir = join13(storageDir, "onnxruntime", ORT_VERSION);
15616
15651
  const libName = info?.libName ?? "libonnxruntime.dylib";
15617
15652
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
15618
- const libPath = join12(resolvedOrtDir, libName);
15619
- if (existsSync9(libPath)) {
15653
+ const libPath = join13(resolvedOrtDir, libName);
15654
+ if (existsSync10(libPath)) {
15620
15655
  const meta = readOnnxInstalledMeta(ortVersionDir);
15621
15656
  if (meta?.sha256) {
15622
15657
  try {
@@ -15645,9 +15680,9 @@ async function ensureOnnxRuntime(storageDir) {
15645
15680
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
15646
15681
  return null;
15647
15682
  }
15648
- const onnxBaseDir = join12(storageDir, "onnxruntime");
15683
+ const onnxBaseDir = join13(storageDir, "onnxruntime");
15649
15684
  mkdirSync5(onnxBaseDir, { recursive: true });
15650
- const lockPath = join12(onnxBaseDir, ONNX_LOCK_FILE);
15685
+ const lockPath = join13(onnxBaseDir, ONNX_LOCK_FILE);
15651
15686
  cleanupAbandonedStagingDirs(onnxBaseDir);
15652
15687
  if (!acquireLock(lockPath)) {
15653
15688
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -15666,7 +15701,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
15666
15701
  for (const entry of entries) {
15667
15702
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
15668
15703
  continue;
15669
- const stagingDir = join12(onnxBaseDir, entry);
15704
+ const stagingDir = join13(onnxBaseDir, entry);
15670
15705
  const parts = entry.split(".");
15671
15706
  const pidStr = parts[parts.length - 2];
15672
15707
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -15703,7 +15738,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
15703
15738
  }
15704
15739
  function cleanupIncompleteTargetIfUnowned(ortDir) {
15705
15740
  try {
15706
- if (existsSync9(ortDir) && !existsSync9(join12(ortDir, ONNX_INSTALLED_META_FILE))) {
15741
+ if (existsSync10(ortDir) && !existsSync10(join13(ortDir, ONNX_INSTALLED_META_FILE))) {
15707
15742
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
15708
15743
  rmSync3(ortDir, { recursive: true, force: true });
15709
15744
  }
@@ -15747,8 +15782,8 @@ function detectOnnxVersion(libDir, libName) {
15747
15782
  if (version)
15748
15783
  return version;
15749
15784
  }
15750
- const base = join12(libDir, libName);
15751
- if (existsSync9(base)) {
15785
+ const base = join13(libDir, libName);
15786
+ if (existsSync10(base)) {
15752
15787
  try {
15753
15788
  const real = realpathSync2(base);
15754
15789
  const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
@@ -15814,10 +15849,10 @@ function directoryContainsLibrary(dir, libName) {
15814
15849
  }
15815
15850
  }
15816
15851
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
15817
- if (existsSync9(join12(ortVersionDir, libName)))
15852
+ if (existsSync10(join13(ortVersionDir, libName)))
15818
15853
  return ortVersionDir;
15819
- const libSubdir = join12(ortVersionDir, "lib");
15820
- if (existsSync9(join12(libSubdir, libName)))
15854
+ const libSubdir = join13(ortVersionDir, "lib");
15855
+ if (existsSync10(join13(libSubdir, libName)))
15821
15856
  return libSubdir;
15822
15857
  return ortVersionDir;
15823
15858
  }
@@ -15832,13 +15867,13 @@ function findSystemOnnxRuntime(libName) {
15832
15867
  } else if (process.platform === "win32") {
15833
15868
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
15834
15869
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
15835
- searchPaths.push(join12(programFiles, "onnxruntime", "lib"), join12(programFiles, "Microsoft ONNX Runtime", "lib"), join12(programFiles, "Microsoft Machine Learning", "lib"), join12(programFilesX86, "onnxruntime", "lib"), ...(() => {
15870
+ searchPaths.push(join13(programFiles, "onnxruntime", "lib"), join13(programFiles, "Microsoft ONNX Runtime", "lib"), join13(programFiles, "Microsoft Machine Learning", "lib"), join13(programFilesX86, "onnxruntime", "lib"), ...(() => {
15836
15871
  const nugetPaths = [];
15837
15872
  const userProfile = process.env.USERPROFILE ?? "";
15838
15873
  if (!userProfile)
15839
15874
  return nugetPaths;
15840
- const nugetPackageDir = join12(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
15841
- if (!existsSync9(nugetPackageDir))
15875
+ const nugetPackageDir = join13(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
15876
+ if (!existsSync10(nugetPackageDir))
15842
15877
  return nugetPaths;
15843
15878
  try {
15844
15879
  for (const entry of readdirSync3(nugetPackageDir, { withFileTypes: true })) {
@@ -15846,7 +15881,7 @@ function findSystemOnnxRuntime(libName) {
15846
15881
  continue;
15847
15882
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
15848
15883
  continue;
15849
- nugetPaths.push(join12(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join12(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
15884
+ nugetPaths.push(join13(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join13(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
15850
15885
  }
15851
15886
  } catch (err) {
15852
15887
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -15868,11 +15903,11 @@ function findSystemOnnxRuntime(libName) {
15868
15903
  });
15869
15904
  const unknownVersionPaths = [];
15870
15905
  for (const dir of uniquePaths) {
15871
- const libPath = join12(dir, libName);
15906
+ const libPath = join13(dir, libName);
15872
15907
  if (process.platform === "win32") {
15873
15908
  if (!directoryContainsLibrary(dir, libName))
15874
15909
  continue;
15875
- } else if (!existsSync9(libPath)) {
15910
+ } else if (!existsSync10(libPath)) {
15876
15911
  continue;
15877
15912
  }
15878
15913
  const version = detectOnnxVersion(dir, libName);
@@ -15938,7 +15973,7 @@ function validateExtractedTree(stagingRoot) {
15938
15973
  const walk = (dir) => {
15939
15974
  const entries = readdirSync3(dir);
15940
15975
  for (const entry of entries) {
15941
- const fullPath = join12(dir, entry);
15976
+ const fullPath = join13(dir, entry);
15942
15977
  const lst = lstatSync(fullPath);
15943
15978
  if (lst.isSymbolicLink()) {
15944
15979
  const linkTarget = readlinkSync(fullPath);
@@ -15971,34 +16006,32 @@ async function downloadOnnxRuntime(info, targetDir) {
15971
16006
  const url = `https://github.com/${ORT_REPO}/releases/download/v${ORT_VERSION}/${info.assetName}.${info.archiveType === "tgz" ? "tgz" : "zip"}`;
15972
16007
  log(`Downloading ONNX Runtime v${ORT_VERSION} for ${process.platform}/${process.arch}...`);
15973
16008
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
16009
+ const extractionRoot = join13(tmpDir, "extract");
16010
+ const stagedInstallDir = join13(tmpDir, "install");
15974
16011
  try {
15975
- mkdirSync5(tmpDir, { recursive: true });
15976
- const archivePath = join12(tmpDir, `onnxruntime.${info.archiveType}`);
16012
+ mkdirSync5(extractionRoot, { recursive: true });
16013
+ const archivePath = join13(tmpDir, `onnxruntime.${info.archiveType}`);
15977
16014
  await downloadFileWithCap(url, archivePath);
15978
16015
  const archiveSha256 = sha256File(archivePath);
15979
16016
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
15980
16017
  if (info.archiveType === "tgz") {
15981
- execFileSync("tar", ["xzf", archivePath, "-C", tmpDir], {
15982
- stdio: "pipe",
15983
- timeout: 120000
15984
- });
16018
+ execTarExtractionSync(["xzf", archivePath, "-C", extractionRoot], 120000);
15985
16019
  } else {
15986
- await extractZipArchive(archivePath, tmpDir);
16020
+ await extractZipArchive(archivePath, extractionRoot);
15987
16021
  }
15988
16022
  try {
15989
16023
  unlinkSync4(archivePath);
15990
16024
  } catch {}
15991
- validateExtractedTree(tmpDir);
15992
- const extractedDir = join12(tmpDir, info.assetName, "lib");
15993
- if (!existsSync9(extractedDir)) {
16025
+ validateExtractedTree(extractionRoot);
16026
+ const extractedDir = join13(extractionRoot, info.assetName, "lib");
16027
+ if (!existsSync10(extractedDir)) {
15994
16028
  throw new Error(`Expected directory not found: ${extractedDir}`);
15995
16029
  }
15996
- mkdirSync5(targetDir, { recursive: true });
15997
16030
  const libFiles = readdirSync3(extractedDir).filter((f) => f.startsWith("libonnxruntime") || f.startsWith("onnxruntime"));
15998
16031
  const realFiles = [];
15999
16032
  const symlinks = [];
16000
16033
  for (const libFile of libFiles) {
16001
- const src = join12(extractedDir, libFile);
16034
+ const src = join13(extractedDir, libFile);
16002
16035
  try {
16003
16036
  const stat = lstatSync(src);
16004
16037
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
@@ -16012,15 +16045,11 @@ async function downloadOnnxRuntime(info, targetDir) {
16012
16045
  realFiles.push(libFile);
16013
16046
  }
16014
16047
  }
16015
- copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
16016
- const libPath = join12(targetDir, info.libName);
16017
- let libHash = null;
16018
- try {
16019
- libHash = sha256File(libPath);
16020
- } catch (err) {
16021
- warn(`Could not hash newly-installed ONNX library at ${libPath}: ${err}`);
16022
- }
16023
- writeOnnxInstalledMeta(targetDir, ORT_VERSION, libHash, archiveSha256);
16048
+ copyOnnxLibraries(info, extractedDir, stagedInstallDir, realFiles, symlinks);
16049
+ const libPath = join13(stagedInstallDir, info.libName);
16050
+ const libHash = sha256File(libPath);
16051
+ writeOnnxInstalledMeta(stagedInstallDir, ORT_VERSION, libHash, archiveSha256);
16052
+ publishOnnxRuntime(stagedInstallDir, targetDir);
16024
16053
  rmSync3(tmpDir, { recursive: true, force: true });
16025
16054
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
16026
16055
  return targetDir;
@@ -16029,17 +16058,39 @@ async function downloadOnnxRuntime(info, targetDir) {
16029
16058
  try {
16030
16059
  rmSync3(tmpDir, { recursive: true, force: true });
16031
16060
  } catch {}
16032
- try {
16033
- rmSync3(targetDir, { recursive: true, force: true });
16034
- } catch {}
16035
16061
  return null;
16036
16062
  }
16037
16063
  }
16064
+ function publishOnnxRuntime(stagedInstallDir, targetDir) {
16065
+ const backupDir = `${targetDir}.backup.${process.pid}.${Date.now().toString(36)}`;
16066
+ const hadTarget = existsSync10(targetDir);
16067
+ if (hadTarget)
16068
+ renameSync5(targetDir, backupDir);
16069
+ try {
16070
+ renameSync5(stagedInstallDir, targetDir);
16071
+ } catch (installError) {
16072
+ if (hadTarget) {
16073
+ try {
16074
+ renameSync5(backupDir, targetDir);
16075
+ } catch (restoreError) {
16076
+ throw new Error(`ONNX Runtime replacement failed and the previous runtime could not be restored from ${backupDir}: ${restoreError}`, { cause: installError });
16077
+ }
16078
+ }
16079
+ throw installError;
16080
+ }
16081
+ if (hadTarget) {
16082
+ try {
16083
+ rmSync3(backupDir, { recursive: true, force: true });
16084
+ } catch (err) {
16085
+ warn(`Could not remove replaced ONNX Runtime backup at ${backupDir}: ${err}`);
16086
+ }
16087
+ }
16088
+ }
16038
16089
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
16039
16090
  const requiredLibs = new Set([info.libName]);
16040
16091
  for (const libFile of realFiles) {
16041
- const src = join12(extractedDir, libFile);
16042
- const dst = join12(targetDir, libFile);
16092
+ const src = join13(extractedDir, libFile);
16093
+ const dst = join13(targetDir, libFile);
16043
16094
  try {
16044
16095
  copyFile(src, dst);
16045
16096
  if (process.platform !== "win32") {
@@ -16055,11 +16106,11 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
16055
16106
  }
16056
16107
  const targetRoot = realpathSync2(targetDir);
16057
16108
  for (const link of symlinks) {
16058
- const dst = join12(targetDir, link.name);
16109
+ const dst = join13(targetDir, link.name);
16059
16110
  try {
16060
16111
  unlinkSync4(dst);
16061
16112
  } catch {}
16062
- const dstForContainment = join12(targetRoot, link.name);
16113
+ const dstForContainment = join13(targetRoot, link.name);
16063
16114
  const resolvedTarget = resolve7(dirname5(dstForContainment), link.target);
16064
16115
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
16065
16116
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
@@ -16080,21 +16131,18 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
16080
16131
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
16081
16132
  }
16082
16133
  }
16083
- const requiredPath = join12(targetDir, info.libName);
16084
- if (!existsSync9(requiredPath)) {
16134
+ const requiredPath = join13(targetDir, info.libName);
16135
+ if (!existsSync10(requiredPath)) {
16085
16136
  rmSync3(targetDir, { recursive: true, force: true });
16086
16137
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
16087
16138
  }
16088
16139
  }
16089
16140
  async function extractZipArchive(archivePath, destinationDir) {
16090
16141
  if (process.platform === "win32") {
16091
- execFileSync("tar.exe", ["-xf", archivePath, "-C", destinationDir], {
16092
- stdio: "pipe",
16093
- timeout: 120000
16094
- });
16142
+ execTarExtractionSync(["-xf", archivePath, "-C", destinationDir], 120000);
16095
16143
  return;
16096
16144
  }
16097
- execFileSync("unzip", ["-q", archivePath, "-d", destinationDir], {
16145
+ execFileSync2("unzip", ["-q", archivePath, "-d", destinationDir], {
16098
16146
  stdio: "pipe",
16099
16147
  timeout: 120000
16100
16148
  });
@@ -16107,13 +16155,13 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
16107
16155
  ...sha256 ? { sha256 } : {},
16108
16156
  archiveSha256
16109
16157
  };
16110
- writeFileSync3(join12(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
16158
+ writeFileSync3(join13(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
16111
16159
  } catch (err) {
16112
16160
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
16113
16161
  }
16114
16162
  }
16115
16163
  function readOnnxInstalledMeta(installDir) {
16116
- const path = join12(installDir, ONNX_INSTALLED_META_FILE);
16164
+ const path = join13(installDir, ONNX_INSTALLED_META_FILE);
16117
16165
  try {
16118
16166
  if (!statSync6(path).isFile())
16119
16167
  return null;
@@ -16225,7 +16273,7 @@ function isWindowsProcessAlive(pid) {
16225
16273
  if (!Number.isInteger(pid) || pid <= 0)
16226
16274
  return false;
16227
16275
  try {
16228
- const output = execFileSync("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
16276
+ const output = execFileSync2("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
16229
16277
  encoding: "utf8",
16230
16278
  timeout: 2000,
16231
16279
  windowsHide: true
@@ -16446,10 +16494,8 @@ function prepareCanonicalEditArguments(toolName, rawArguments) {
16446
16494
  if (unknownRootKeys.length > 0) {
16447
16495
  throw new InvalidRequestError(formatUnknownKeys(unknownRootKeys));
16448
16496
  }
16497
+ validateSymbolModePair(record);
16449
16498
  const modes = editModesPresent(record);
16450
- if (hasOrphanedSymbolContent(record)) {
16451
- throw new InvalidRequestError("edit: 'content' requires a non-empty string 'symbol' when symbol mode is selected");
16452
- }
16453
16499
  if (modes.length > 1) {
16454
16500
  throw new InvalidRequestError(`edit: conflicting modes: ${modes.join(", ")}. ${OMIT_OPTIONAL_FIELDS_STEERING}`);
16455
16501
  }
@@ -16469,7 +16515,7 @@ function prepareCanonicalEditArguments(toolName, rawArguments) {
16469
16515
  throw new InvalidRequestError("edit: 'symbol' must be a string when symbol mode is selected");
16470
16516
  }
16471
16517
  if (!hasOwn(record, "content") || typeof record.content !== "string") {
16472
- throw new InvalidRequestError("edit: symbol mode requires both 'symbol' and 'content' string properties");
16518
+ throw new InvalidRequestError("edit: incomplete symbol mode: property 'content' must be a string. " + "Retry with `symbol` + `content`, or use `edits[]`.");
16473
16519
  }
16474
16520
  } else {
16475
16521
  const item = {};
@@ -16522,6 +16568,29 @@ function validateEditPath(record) {
16522
16568
  function formatUnknownKeys(keys) {
16523
16569
  return `Unrecognized keys: ${keys.map((key) => `"${key}"`).join(", ")}`;
16524
16570
  }
16571
+ function validateSymbolModePair(record) {
16572
+ const completeShapes = "Retry with `symbol` + `content`, or use `edits[]`.";
16573
+ const hasSymbol = isNonEmptyString(record.symbol);
16574
+ const hasContent = isNonEmptyString(record.content);
16575
+ if (hasSymbol) {
16576
+ if (!hasOwn(record, "content")) {
16577
+ throw new InvalidRequestError(`edit: incomplete symbol mode: missing property 'content'. ${completeShapes}`);
16578
+ }
16579
+ if (record.content === null) {
16580
+ throw new InvalidRequestError(`edit: incomplete symbol mode: property 'content' is null. ${completeShapes}`);
16581
+ }
16582
+ return;
16583
+ }
16584
+ if (!hasContent)
16585
+ return;
16586
+ if (!hasOwn(record, "symbol")) {
16587
+ throw new InvalidRequestError(`edit: incomplete symbol mode: missing property 'symbol'. ${completeShapes}`);
16588
+ }
16589
+ if (record.symbol === null) {
16590
+ throw new InvalidRequestError(`edit: incomplete symbol mode: property 'symbol' is null. ${completeShapes}`);
16591
+ }
16592
+ throw new InvalidRequestError(`edit: incomplete symbol mode: property 'symbol' must be a non-empty string. ${completeShapes}`);
16593
+ }
16525
16594
  function editModesPresent(record) {
16526
16595
  const hasAppendContent = isNonEmptyString(record.appendContent);
16527
16596
  if (!hasAppendContent)
@@ -16607,9 +16676,6 @@ function normalizeEditArraySentinels(record) {
16607
16676
  return true;
16608
16677
  }
16609
16678
  }
16610
- function hasOrphanedSymbolContent(record) {
16611
- return isNonEmptyString(record.content) && !isNonEmptyString(record.symbol);
16612
- }
16613
16679
  function parseEditArray(value) {
16614
16680
  if (typeof value === "string") {
16615
16681
  let parsed;
@@ -16792,8 +16858,50 @@ function copyOwnProperties(source) {
16792
16858
  copy[key] = source[key];
16793
16859
  return copy;
16794
16860
  }
16861
+ // ../aft-bridge/dist/semantic-status.js
16862
+ var MISSING_ONNX_RUNTIME_MARKER = "ONNX Runtime not found.";
16863
+ var MISSING_ONNX_RUNTIME_LABEL = "unavailable — ONNX Runtime missing (npx @cortexkit/aft doctor --fix)";
16864
+ var REBUILDING_LABEL = "Rebuilding (model changed)";
16865
+ var SEMANTIC_PROGRESS_STATUSES = new Set(["building", "loading"]);
16866
+ var SEMANTIC_READY_STATUSES = new Set(["ready", "empty"]);
16867
+ var SEMANTIC_INACTIVE_STATUSES = new Set(["disabled", "busy"]);
16868
+ var SEMANTIC_FAILURE_LABELS = {
16869
+ backend_unavailable: "backend unavailable",
16870
+ degraded: "degraded",
16871
+ error: "error",
16872
+ failed: "failed",
16873
+ unavailable: "unavailable"
16874
+ };
16875
+ function semanticIndexStatusKind(status) {
16876
+ if (SEMANTIC_READY_STATUSES.has(status))
16877
+ return "ready";
16878
+ if (SEMANTIC_PROGRESS_STATUSES.has(status))
16879
+ return "progress";
16880
+ if (status in SEMANTIC_FAILURE_LABELS)
16881
+ return "failure";
16882
+ if (SEMANTIC_INACTIVE_STATUSES.has(status))
16883
+ return "inactive";
16884
+ return "unrecognized";
16885
+ }
16886
+ function mentionsMissingOnnxRuntime(...values) {
16887
+ return values.some((value) => typeof value === "string" && value.includes(MISSING_ONNX_RUNTIME_MARKER));
16888
+ }
16889
+ function semanticFailureLabel(status, stage, error) {
16890
+ if (mentionsMissingOnnxRuntime(error, stage))
16891
+ return MISSING_ONNX_RUNTIME_LABEL;
16892
+ return SEMANTIC_FAILURE_LABELS[status] ?? null;
16893
+ }
16894
+ function formatSemanticIndexStatus(status, stage, error) {
16895
+ const failure = semanticFailureLabel(status, stage, error);
16896
+ if (failure)
16897
+ return failure;
16898
+ if (semanticIndexStatusKind(status) === "progress" && stage === "fingerprint_change") {
16899
+ return REBUILDING_LABEL;
16900
+ }
16901
+ return status;
16902
+ }
16795
16903
  // src/config.ts
16796
- import { existsSync as existsSync10, readFileSync as readFileSync7, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
16904
+ import { existsSync as existsSync11, readFileSync as readFileSync7, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
16797
16905
  import { homedir as homedir10 } from "node:os";
16798
16906
  import { isAbsolute as isAbsolute6, parse as parsePath, resolve as resolvePath } from "node:path";
16799
16907
  var import_comment_json = __toESM(require_src2(), 1);
@@ -22024,7 +22132,7 @@ function migrateExperimentalBashBlock(rawConfig, configPath, logger) {
22024
22132
  return movedKeys;
22025
22133
  }
22026
22134
  function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 }) {
22027
- if (!existsSync10(configPath)) {
22135
+ if (!existsSync11(configPath)) {
22028
22136
  return { migrated: false, oldKeys: [] };
22029
22137
  }
22030
22138
  let tmpPath = null;
@@ -22048,7 +22156,7 @@ function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 })
22048
22156
  ${serialized}` : serialized;
22049
22157
  tmpPath = `${configPath}.tmp.${process.pid}`;
22050
22158
  writeFileSync4(tmpPath, nextContent, "utf-8");
22051
- renameSync5(tmpPath, configPath);
22159
+ renameSync6(tmpPath, configPath);
22052
22160
  logger.log(`Migrated config at ${configPath}: removed ${oldKeys.join(", ")}`);
22053
22161
  return { migrated: true, oldKeys };
22054
22162
  } catch (err) {
@@ -22109,7 +22217,7 @@ function recordConfigParseFailure(configPath, errorMessage) {
22109
22217
  }
22110
22218
  function loadConfigFromPath(configPath) {
22111
22219
  try {
22112
- if (!existsSync10(configPath)) {
22220
+ if (!existsSync11(configPath)) {
22113
22221
  return null;
22114
22222
  }
22115
22223
  const content = readFileSync7(configPath, "utf-8");
@@ -22449,7 +22557,7 @@ function loadAftConfig(projectDirectory) {
22449
22557
  }
22450
22558
 
22451
22559
  // src/tools/_shared.ts
22452
- import { existsSync as existsSync11 } from "node:fs";
22560
+ import { existsSync as existsSync12 } from "node:fs";
22453
22561
  import * as os2 from "node:os";
22454
22562
  import * as path2 from "node:path";
22455
22563
 
@@ -34862,6 +34970,7 @@ var DEBOUNCE_STEP_MS = 200;
34862
34970
  var DEBOUNCE_CAP_MS = 1000;
34863
34971
  var MAX_WAKE_SEND_ATTEMPTS = 5;
34864
34972
  var DEFAULT_WAKE_CONFIRMATION_WINDOW_MS = 5000;
34973
+ var BUSY_WAKE_DEFER_CEILING_MS = 60000;
34865
34974
  var UNKNOWN_COMPLETION_TTL_MS = 5000;
34866
34975
  var UNKNOWN_COMPLETION_CAP = 32;
34867
34976
  var DEFAULT_SESSION_ID2 = "__default__";
@@ -34893,10 +35002,12 @@ function logDroppedForeignSessionFrame(drainContext, droppedSessionId, liveSessi
34893
35002
  var DEFAULT_BG_HOP_TIMEOUT_MS = 15000;
34894
35003
  var bgHopTimeoutMs = DEFAULT_BG_HOP_TIMEOUT_MS;
34895
35004
  var wakeConfirmationWindowMs = DEFAULT_WAKE_CONFIRMATION_WINDOW_MS;
35005
+ var busyWakeDeferCeilingMs = BUSY_WAKE_DEFER_CEILING_MS;
34896
35006
  var lastWakeMessageTimestamp = 0;
34897
35007
  var wakeMessageCounter = 0;
34898
35008
  var subcNudgesInFlight = new Map;
34899
35009
  var subcNudgeLogState = new Map;
35010
+ var deferredBusyWakes = new Map;
34900
35011
  function consumeBgCompletion(sessionID, taskId) {
34901
35012
  const state = stateFor(sessionID);
34902
35013
  state.pendingCompletions = state.pendingCompletions.filter((c) => c.task_id !== taskId);
@@ -34911,6 +35022,9 @@ function consumeBgCompletion(sessionID, taskId) {
34911
35022
  }
34912
35023
  }
34913
35024
  clearWakeTimerIfNoPending(state);
35025
+ if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0 && state.pendingPatternMatches.length === 0) {
35026
+ clearDeferredBusyWake(sessionID || DEFAULT_SESSION_ID2);
35027
+ }
34914
35028
  }
34915
35029
  async function markBgCompletionDelivered(drainContext, taskId) {
34916
35030
  const state = stateFor(drainContext.sessionID);
@@ -35016,7 +35130,7 @@ async function handlePushedPatternMatch(drainContext, frame) {
35016
35130
  }
35017
35131
  const state = stateFor(drainContext.sessionID);
35018
35132
  queuePendingPatternMatch(state, { ...frame, ackCompletionOnDelivery: true });
35019
- await triggerWakeIfPending(drainContext, true);
35133
+ await triggerWakeIfPending(drainContext, true, true, false, true);
35020
35134
  }
35021
35135
  function ingestBgCompletions(sessionID, completions) {
35022
35136
  if (!Array.isArray(completions) || completions.length === 0)
@@ -35054,11 +35168,11 @@ function ingestBgCompletions(sessionID, completions) {
35054
35168
  }
35055
35169
  async function handlePushedBgCompletion(drainContext, completion) {
35056
35170
  ingestBgCompletions(drainContext.sessionID, [completion]);
35057
- await triggerWakeIfPending(drainContext, true, false);
35171
+ await triggerWakeIfPending(drainContext, true, false, false, true);
35058
35172
  }
35059
35173
  async function handlePushedBgLongRunning(drainContext, reminder) {
35060
35174
  stateFor(drainContext.sessionID).pendingLongRunning.push(reminder);
35061
- await triggerWakeIfPending(drainContext, true);
35175
+ await triggerWakeIfPending(drainContext, true, true, false, true);
35062
35176
  }
35063
35177
  async function appendInTurnBgCompletions(drainContext, output) {
35064
35178
  if (!output)
@@ -35103,6 +35217,7 @@ async function appendInTurnBgCompletions(drainContext, output) {
35103
35217
  if (inTurnAcked)
35104
35218
  confirmAcked(state, inTurnAckIds);
35105
35219
  clearWakeTimerIfNoPending(state);
35220
+ clearDeferredBusyWake(drainContext.sessionID);
35106
35221
  }
35107
35222
  async function handleIdleBgCompletions(drainContext) {
35108
35223
  stateFor(drainContext.sessionID).wakeDeferredTaskIds.clear();
@@ -35130,7 +35245,7 @@ async function handleSubcBgEventsNudgeOnce(drainContext) {
35130
35245
  const state = stateFor(drainContext.sessionID);
35131
35246
  state.wakeDeferredTaskIds.clear();
35132
35247
  rearmHardStoppedWake(state, drainContext);
35133
- await triggerWakeIfPending(drainContext, false, true, true);
35248
+ await triggerWakeIfPending(drainContext, false, true, true, true);
35134
35249
  }
35135
35250
  function logSubcNudgeLifecycle(drainContext, kind, message) {
35136
35251
  logDeliveryHop(drainContext, kind, message, {
@@ -35345,6 +35460,42 @@ function registerWakeAdmission(state, admission) {
35345
35460
  }, wakeConfirmationWindowMs);
35346
35461
  tracked.confirmationTimer.unref?.();
35347
35462
  }
35463
+ function clearDeferredBusyWake(sessionID) {
35464
+ const deferred = deferredBusyWakes.get(sessionID);
35465
+ if (!deferred)
35466
+ return;
35467
+ deferredBusyWakes.delete(sessionID);
35468
+ clearTimeout(deferred.timer);
35469
+ return deferred;
35470
+ }
35471
+ function deferBusyWake(drainContext) {
35472
+ const existing = deferredBusyWakes.get(drainContext.sessionID);
35473
+ if (existing) {
35474
+ existing.context = drainContext;
35475
+ return;
35476
+ }
35477
+ const deferredAt = Date.now();
35478
+ const deferred = {
35479
+ context: drainContext,
35480
+ deferredAt,
35481
+ timer: setTimeout(() => {
35482
+ if (deferredBusyWakes.get(drainContext.sessionID) !== deferred)
35483
+ return;
35484
+ deferredBusyWakes.delete(drainContext.sessionID);
35485
+ const waitMs = Math.max(0, Date.now() - deferredAt);
35486
+ sessionLog(drainContext.sessionID, `${LOG_PREFIX} busy wake defer ceiling reached`, {
35487
+ event: "bash_completion_wake_deferred_ceiling",
35488
+ wait_ms: waitMs,
35489
+ ceiling_ms: busyWakeDeferCeilingMs
35490
+ });
35491
+ triggerWakeIfPending(deferred.context, true).catch(() => {
35492
+ return;
35493
+ });
35494
+ }, busyWakeDeferCeilingMs)
35495
+ };
35496
+ deferred.timer.unref?.();
35497
+ deferredBusyWakes.set(drainContext.sessionID, deferred);
35498
+ }
35348
35499
  function observeOpenCodeBgNotificationEvent(event) {
35349
35500
  try {
35350
35501
  if (!event || typeof event !== "object")
@@ -35393,12 +35544,17 @@ function observeOpenCodeBgNotificationEvent(event) {
35393
35544
  return;
35394
35545
  }
35395
35546
  if (nextStatus === "idle") {
35547
+ const deferred = clearDeferredBusyWake(sessionID);
35548
+ if (deferred)
35549
+ triggerWakeIfPending(deferred.context, true).catch(() => {
35550
+ return;
35551
+ });
35396
35552
  for (const admission of state.wakeAdmissions.values())
35397
35553
  queueWakeRefire(state, admission);
35398
35554
  }
35399
35555
  } catch {}
35400
35556
  }
35401
- async function triggerWakeIfPending(drainContext, skipDrain, includeDeferredCompletions = true, forceDrain = false) {
35557
+ async function triggerWakeIfPending(drainContext, skipDrain, includeDeferredCompletions = true, forceDrain = false, deferWhileBusy = false) {
35402
35558
  const state = stateFor(drainContext.sessionID);
35403
35559
  if (!skipDrain && (forceDrain || state.outstandingTaskIds.size > 0 || !state.forcedDrainCompleted)) {
35404
35560
  await drainCompletions(drainContext);
@@ -35406,6 +35562,10 @@ async function triggerWakeIfPending(drainContext, skipDrain, includeDeferredComp
35406
35562
  routeExplicitControlCompletions(state);
35407
35563
  if (!hasWakeEligiblePending(state, includeDeferredCompletions))
35408
35564
  return;
35565
+ if (deferWhileBusy && state.hostStatus === "busy") {
35566
+ deferBusyWake(drainContext);
35567
+ return;
35568
+ }
35409
35569
  scheduleWake(state, async (reminder, deliveredCompletions, deliveredPatternMatches) => {
35410
35570
  const liveSession = getActiveSessionId() ?? drainContext.sessionID;
35411
35571
  if (liveSession && drainContext.sessionID && drainContext.sessionID !== liveSession) {
@@ -36247,7 +36407,7 @@ function bridgeFor(ctx, runtime) {
36247
36407
  if (ctx.isProjectEnabled?.(projectRoot) === false) {
36248
36408
  throw new Error(`AFT disabled by config for ${projectRoot}`);
36249
36409
  }
36250
- if (!existsSync11(projectRoot)) {
36410
+ if (!existsSync12(projectRoot)) {
36251
36411
  throw new Error(`project directory no longer exists: ${projectRoot} (stale restored session?)`);
36252
36412
  }
36253
36413
  return ctx.pool.getBridge(projectRoot);
@@ -36404,9 +36564,9 @@ async function signalBashWaitDetachForProject(pool, projectRoot, sessionID) {
36404
36564
  }
36405
36565
 
36406
36566
  // src/notifications.ts
36407
- import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
36567
+ import { existsSync as existsSync13, readFileSync as readFileSync8 } from "node:fs";
36408
36568
  import { homedir as homedir12, platform } from "node:os";
36409
- import { join as join13 } from "node:path";
36569
+ import { join as join14 } from "node:path";
36410
36570
  function isTuiMode() {
36411
36571
  return process.env.OPENCODE_CLIENT === "cli";
36412
36572
  }
@@ -36428,21 +36588,21 @@ function getDesktopStatePath() {
36428
36588
  const os = platform();
36429
36589
  const home = homedir12();
36430
36590
  if (os === "darwin") {
36431
- return join13(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
36591
+ return join14(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
36432
36592
  }
36433
36593
  if (os === "linux") {
36434
- const xdgConfig = process.env.XDG_CONFIG_HOME || join13(home, ".config");
36435
- return join13(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
36594
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join14(home, ".config");
36595
+ return join14(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
36436
36596
  }
36437
36597
  if (os === "win32") {
36438
- const appData = process.env.APPDATA || join13(home, "AppData", "Roaming");
36439
- return join13(appData, "ai.opencode.desktop", "opencode.global.dat");
36598
+ const appData = process.env.APPDATA || join14(home, "AppData", "Roaming");
36599
+ return join14(appData, "ai.opencode.desktop", "opencode.global.dat");
36440
36600
  }
36441
36601
  return null;
36442
36602
  }
36443
36603
  function readDesktopState() {
36444
36604
  const statePath = getDesktopStatePath();
36445
- if (!statePath || !existsSync12(statePath)) {
36605
+ if (!statePath || !existsSync13(statePath)) {
36446
36606
  return { serverUrl: null };
36447
36607
  }
36448
36608
  try {
@@ -36942,11 +37102,11 @@ async function flushConfigureWarningsOnIdle(sessionId) {
36942
37102
  // src/hooks/auto-update-checker/index.ts
36943
37103
  import {
36944
37104
  closeSync as closeSync5,
36945
- existsSync as existsSync15,
37105
+ existsSync as existsSync16,
36946
37106
  mkdirSync as mkdirSync6,
36947
37107
  openSync as openSync5,
36948
37108
  readFileSync as readFileSync11,
36949
- renameSync as renameSync6,
37109
+ renameSync as renameSync7,
36950
37110
  rmSync as rmSync5,
36951
37111
  statSync as statSync8,
36952
37112
  writeFileSync as writeFileSync7
@@ -36955,30 +37115,30 @@ import { dirname as dirname8 } from "node:path";
36955
37115
 
36956
37116
  // src/hooks/auto-update-checker/cache.ts
36957
37117
  import { spawn as spawn4 } from "node:child_process";
36958
- import { cpSync, existsSync as existsSync14, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
37118
+ import { cpSync, existsSync as existsSync15, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
36959
37119
  import { tmpdir as tmpdir2 } from "node:os";
36960
- import { basename as basename3, dirname as dirname7, join as join16 } from "node:path";
37120
+ import { basename as basename3, dirname as dirname7, join as join17 } from "node:path";
36961
37121
  var import_comment_json3 = __toESM(require_src2(), 1);
36962
37122
 
36963
37123
  // src/hooks/auto-update-checker/checker.ts
36964
- import { existsSync as existsSync13, readFileSync as readFileSync9, statSync as statSync7, writeFileSync as writeFileSync5 } from "node:fs";
36965
- import { dirname as dirname6, isAbsolute as isAbsolute8, join as join15, resolve as resolve9 } from "node:path";
37124
+ import { existsSync as existsSync14, readFileSync as readFileSync9, statSync as statSync7, writeFileSync as writeFileSync5 } from "node:fs";
37125
+ import { dirname as dirname6, isAbsolute as isAbsolute8, join as join16, resolve as resolve9 } from "node:path";
36966
37126
  import { fileURLToPath } from "node:url";
36967
37127
  var import_comment_json2 = __toESM(require_src2(), 1);
36968
37128
 
36969
37129
  // src/hooks/auto-update-checker/constants.ts
36970
- import { join as join14 } from "node:path";
37130
+ import { join as join15 } from "node:path";
36971
37131
  var PACKAGE_NAME = "@cortexkit/aft-opencode";
36972
37132
  var NPM_REGISTRY_URL = "https://registry.npmjs.org";
36973
37133
  var NPM_FETCH_TIMEOUT = 1e4;
36974
37134
  function cacheDir() {
36975
- return join14(getOpenCodeCacheRoot(), "packages");
37135
+ return join15(getOpenCodeCacheRoot(), "packages");
36976
37136
  }
36977
37137
  function userOpenCodeConfig() {
36978
- return join14(getOpenCodeConfigRoot(), "opencode.json");
37138
+ return join15(getOpenCodeConfigRoot(), "opencode.json");
36979
37139
  }
36980
37140
  function userOpenCodeConfigJsonc() {
36981
- return join14(getOpenCodeConfigRoot(), "opencode.jsonc");
37141
+ return join15(getOpenCodeConfigRoot(), "opencode.jsonc");
36982
37142
  }
36983
37143
 
36984
37144
  // src/hooks/auto-update-checker/types.ts
@@ -37037,8 +37197,8 @@ function extractChannel(version) {
37037
37197
  }
37038
37198
  function getConfigPaths(directory) {
37039
37199
  return [
37040
- join15(directory, ".opencode", "opencode.json"),
37041
- join15(directory, ".opencode", "opencode.jsonc"),
37200
+ join16(directory, ".opencode", "opencode.json"),
37201
+ join16(directory, ".opencode", "opencode.jsonc"),
37042
37202
  userOpenCodeConfig(),
37043
37203
  userOpenCodeConfigJsonc()
37044
37204
  ];
@@ -37058,7 +37218,7 @@ function resolvePathPluginSpec(spec, configPath) {
37058
37218
  function getLocalDevPath(directory) {
37059
37219
  for (const configPath of getConfigPaths(directory)) {
37060
37220
  try {
37061
- if (!existsSync13(configPath))
37221
+ if (!existsSync14(configPath))
37062
37222
  continue;
37063
37223
  const rawConfig = parseJsonConfig(readFileSync9(configPath, "utf-8"));
37064
37224
  const plugins = getPluginEntries(rawConfig);
@@ -37084,8 +37244,8 @@ function findPackageJsonUp(startPath) {
37084
37244
  const stat = statSync7(startPath);
37085
37245
  let dir = stat.isDirectory() ? startPath : dirname6(startPath);
37086
37246
  for (let i = 0;i < 10; i++) {
37087
- const pkgPath = join15(dir, "package.json");
37088
- if (existsSync13(pkgPath)) {
37247
+ const pkgPath = join16(dir, "package.json");
37248
+ if (existsSync14(pkgPath)) {
37089
37249
  try {
37090
37250
  const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync9(pkgPath, "utf-8")));
37091
37251
  if (pkg.success && pkg.data.name === PACKAGE_NAME)
@@ -37125,7 +37285,7 @@ function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
37125
37285
  function findPluginEntry(directory) {
37126
37286
  for (const configPath of getConfigPaths(directory)) {
37127
37287
  try {
37128
- if (!existsSync13(configPath))
37288
+ if (!existsSync14(configPath))
37129
37289
  continue;
37130
37290
  const rawConfig = parseJsonConfig(readFileSync9(configPath, "utf-8"));
37131
37291
  const plugins = getPluginEntries(rawConfig);
@@ -37145,7 +37305,7 @@ function findPluginEntry(directory) {
37145
37305
  }
37146
37306
  var cachedPackageVersion = null;
37147
37307
  function getSpecCachePackageJsonPath(spec) {
37148
- return join15(cacheDir(), spec, "node_modules", PACKAGE_NAME, "package.json");
37308
+ return join16(cacheDir(), spec, "node_modules", PACKAGE_NAME, "package.json");
37149
37309
  }
37150
37310
  function getCachedVersion(spec) {
37151
37311
  if (!spec && cachedPackageVersion)
@@ -37154,11 +37314,11 @@ function getCachedVersion(spec) {
37154
37314
  getCurrentRuntimePackageJsonPath(),
37155
37315
  spec ? getSpecCachePackageJsonPath(spec) : null,
37156
37316
  getSpecCachePackageJsonPath(`${PACKAGE_NAME}@latest`),
37157
- join15(getOpenCodeCacheRoot(), "node_modules", PACKAGE_NAME, "package.json")
37317
+ join16(getOpenCodeCacheRoot(), "node_modules", PACKAGE_NAME, "package.json")
37158
37318
  ].filter(isString);
37159
37319
  for (const packageJsonPath of candidates) {
37160
37320
  try {
37161
- if (!existsSync13(packageJsonPath))
37321
+ if (!existsSync14(packageJsonPath))
37162
37322
  continue;
37163
37323
  const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync9(packageJsonPath, "utf-8")));
37164
37324
  if (pkg.success && pkg.data.version) {
@@ -37203,17 +37363,17 @@ async function getLatestVersion(channel = "latest", options = {}) {
37203
37363
  var pendingSnapshots = new Map;
37204
37364
  var quarantinedInstallDirs = new Set;
37205
37365
  function createAutoUpdateSnapshot(installDir, packageJsonPath, packageName) {
37206
- const packageDir = join16(installDir, "node_modules", packageName);
37207
- const lockfilePath = join16(installDir, "package-lock.json");
37208
- const tempDir = mkdtempSync(join16(tmpdir2(), "aft-auto-update-"));
37209
- const stagedPackageDir = existsSync14(packageDir) ? join16(tempDir, "package") : null;
37366
+ const packageDir = join17(installDir, "node_modules", packageName);
37367
+ const lockfilePath = join17(installDir, "package-lock.json");
37368
+ const tempDir = mkdtempSync(join17(tmpdir2(), "aft-auto-update-"));
37369
+ const stagedPackageDir = existsSync15(packageDir) ? join17(tempDir, "package") : null;
37210
37370
  if (stagedPackageDir)
37211
37371
  cpSync(packageDir, stagedPackageDir, { recursive: true });
37212
37372
  return {
37213
37373
  packageJsonPath,
37214
- packageJson: existsSync14(packageJsonPath) ? readFileSync10(packageJsonPath, "utf-8") : null,
37374
+ packageJson: existsSync15(packageJsonPath) ? readFileSync10(packageJsonPath, "utf-8") : null,
37215
37375
  lockfilePath,
37216
- lockfile: existsSync14(lockfilePath) ? readFileSync10(lockfilePath, "utf-8") : null,
37376
+ lockfile: existsSync15(lockfilePath) ? readFileSync10(lockfilePath, "utf-8") : null,
37217
37377
  packageDir,
37218
37378
  stagedPackageDir,
37219
37379
  tempDir
@@ -37247,8 +37407,8 @@ function stripPackageNameFromPath(pathValue, packageName) {
37247
37407
  return current;
37248
37408
  }
37249
37409
  function removeFromPackageLock(installDir, packageName) {
37250
- const lockPath = join16(installDir, "package-lock.json");
37251
- if (!existsSync14(lockPath))
37410
+ const lockPath = join17(installDir, "package-lock.json");
37411
+ if (!existsSync15(lockPath))
37252
37412
  return false;
37253
37413
  try {
37254
37414
  const lock = import_comment_json3.parse(readFileSync10(lockPath, "utf-8"));
@@ -37274,7 +37434,7 @@ function removeFromPackageLock(installDir, packageName) {
37274
37434
  }
37275
37435
  }
37276
37436
  function ensureDependencyVersion(packageJsonPath, packageName, version) {
37277
- if (!existsSync14(packageJsonPath))
37437
+ if (!existsSync15(packageJsonPath))
37278
37438
  return false;
37279
37439
  try {
37280
37440
  const raw = import_comment_json3.parse(readFileSync10(packageJsonPath, "utf-8"));
@@ -37303,8 +37463,8 @@ function restorePendingSnapshot(installDir) {
37303
37463
  restoreAutoUpdateSnapshot(snapshot);
37304
37464
  }
37305
37465
  function removeInstalledPackage(installDir, packageName) {
37306
- const packageDir = join16(installDir, "node_modules", packageName);
37307
- if (!existsSync14(packageDir))
37466
+ const packageDir = join17(installDir, "node_modules", packageName);
37467
+ if (!existsSync15(packageDir))
37308
37468
  return false;
37309
37469
  rmSync4(packageDir, { recursive: true, force: true });
37310
37470
  log2(`[auto-update-checker] Package removed: ${packageDir}`);
@@ -37316,15 +37476,15 @@ function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackage
37316
37476
  const nodeModulesDir = stripPackageNameFromPath(packageDir, PACKAGE_NAME);
37317
37477
  if (nodeModulesDir && basename3(nodeModulesDir) === "node_modules") {
37318
37478
  const installDir = dirname7(nodeModulesDir);
37319
- const packageJsonPath = join16(installDir, "package.json");
37320
- if (existsSync14(packageJsonPath))
37479
+ const packageJsonPath = join17(installDir, "package.json");
37480
+ if (existsSync15(packageJsonPath))
37321
37481
  return { installDir, packageJsonPath };
37322
37482
  }
37323
37483
  return null;
37324
37484
  }
37325
37485
  const cacheRoot = dirname7(cacheDir());
37326
- const legacyPackageJsonPath = join16(cacheRoot, "package.json");
37327
- if (existsSync14(legacyPackageJsonPath)) {
37486
+ const legacyPackageJsonPath = join17(cacheRoot, "package.json");
37487
+ if (existsSync15(legacyPackageJsonPath)) {
37328
37488
  return { installDir: cacheRoot, packageJsonPath: legacyPackageJsonPath };
37329
37489
  }
37330
37490
  return null;
@@ -37547,7 +37707,7 @@ function claimCheckSlot(storageDir, intervalMs) {
37547
37707
  const replacementPath = `${lockPath}.tmp.${process.pid}`;
37548
37708
  writeFileSync7(replacementPath, JSON.stringify(owner), { encoding: "utf-8", mode: 384 });
37549
37709
  try {
37550
- renameSync6(replacementPath, lockPath);
37710
+ renameSync7(replacementPath, lockPath);
37551
37711
  } catch (replaceError) {
37552
37712
  rmSync5(replacementPath, { force: true });
37553
37713
  throw replaceError;
@@ -37615,7 +37775,7 @@ function checkLockIsOwnedBy(lockPath, owner) {
37615
37775
  }
37616
37776
  }
37617
37777
  function hasRecentCheckTimestamp(file, intervalMs) {
37618
- if (!existsSync15(file))
37778
+ if (!existsSync16(file))
37619
37779
  return false;
37620
37780
  try {
37621
37781
  const raw = JSON.parse(readFileSync11(file, "utf-8"));
@@ -37628,7 +37788,7 @@ function hasRecentCheckTimestamp(file, intervalMs) {
37628
37788
  function writeCheckTimestamp(file) {
37629
37789
  const tmp = `${file}.tmp.${process.pid}`;
37630
37790
  writeFileSync7(tmp, JSON.stringify({ lastCheckedMs: Date.now() }), "utf-8");
37631
- renameSync6(tmp, file);
37791
+ renameSync7(tmp, file);
37632
37792
  }
37633
37793
  async function runStartupCheck(ctx, options) {
37634
37794
  if (options.signal.aborted)
@@ -37725,15 +37885,15 @@ import { spawn as spawn5 } from "node:child_process";
37725
37885
  import { createHash as createHash6 } from "node:crypto";
37726
37886
  import {
37727
37887
  createReadStream,
37728
- existsSync as existsSync17,
37888
+ existsSync as existsSync18,
37729
37889
  mkdirSync as mkdirSync8,
37730
37890
  readFileSync as readFileSync14,
37731
- renameSync as renameSync8,
37891
+ renameSync as renameSync9,
37732
37892
  rmSync as rmSync7,
37733
37893
  statSync as statSync10,
37734
37894
  writeFileSync as writeFileSync9
37735
37895
  } from "node:fs";
37736
- import { join as join19 } from "node:path";
37896
+ import { join as join20 } from "node:path";
37737
37897
 
37738
37898
  // src/lsp-cache.ts
37739
37899
  import { randomUUID as randomUUID3 } from "node:crypto";
@@ -37742,13 +37902,13 @@ import {
37742
37902
  mkdirSync as mkdirSync7,
37743
37903
  openSync as openSync6,
37744
37904
  readFileSync as readFileSync12,
37745
- renameSync as renameSync7,
37905
+ renameSync as renameSync8,
37746
37906
  rmSync as rmSync6,
37747
37907
  statSync as statSync9,
37748
37908
  unlinkSync as unlinkSync6,
37749
37909
  writeFileSync as writeFileSync8
37750
37910
  } from "node:fs";
37751
- import { join as join17 } from "node:path";
37911
+ import { join as join18 } from "node:path";
37752
37912
  function aftCacheBase() {
37753
37913
  return getAftCacheRoot();
37754
37914
  }
@@ -37756,18 +37916,18 @@ function lspCacheRoot() {
37756
37916
  return getAftLspPackagesDir();
37757
37917
  }
37758
37918
  function lspPackageDir(npmPackage) {
37759
- return join17(lspCacheRoot(), encodeURIComponent(npmPackage));
37919
+ return join18(lspCacheRoot(), encodeURIComponent(npmPackage));
37760
37920
  }
37761
37921
  function lspBinaryPath(npmPackage, binary) {
37762
- return join17(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
37922
+ return join18(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
37763
37923
  }
37764
37924
  function lspBinDir(npmPackage) {
37765
- return join17(lspPackageDir(npmPackage), "node_modules", ".bin");
37925
+ return join18(lspPackageDir(npmPackage), "node_modules", ".bin");
37766
37926
  }
37767
37927
  function isInstalled(npmPackage, binary) {
37768
37928
  for (const candidate of lspBinaryCandidates(binary)) {
37769
37929
  try {
37770
- if (statSync9(join17(lspBinDir(npmPackage), candidate)).isFile())
37930
+ if (statSync9(join18(lspBinDir(npmPackage), candidate)).isFile())
37771
37931
  return true;
37772
37932
  } catch {}
37773
37933
  }
@@ -37787,13 +37947,13 @@ function writeInstalledMetaIn(installDir, version, sha256) {
37787
37947
  installedAt: new Date().toISOString(),
37788
37948
  ...sha256 ? { sha256 } : {}
37789
37949
  };
37790
- writeFileSync8(join17(installDir, INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
37950
+ writeFileSync8(join18(installDir, INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
37791
37951
  } catch (err) {
37792
37952
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
37793
37953
  }
37794
37954
  }
37795
37955
  function readInstalledMetaIn(installDir) {
37796
- const path = join17(installDir, INSTALLED_META_FILE);
37956
+ const path = join18(installDir, INSTALLED_META_FILE);
37797
37957
  try {
37798
37958
  if (!statSync9(path).isFile())
37799
37959
  return null;
@@ -37817,7 +37977,7 @@ function readInstalledMeta(packageKey) {
37817
37977
  return readInstalledMetaIn(lspPackageDir(packageKey));
37818
37978
  }
37819
37979
  function lockPath(npmPackage) {
37820
- return join17(lspPackageDir(npmPackage), ".aft-installing");
37980
+ return join18(lspPackageDir(npmPackage), ".aft-installing");
37821
37981
  }
37822
37982
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
37823
37983
  function acquireInstallLock(lockKey) {
@@ -37948,7 +38108,7 @@ var AUTO_INSTALL_STAMP_FILE = "last-lsp-autoinstall.json";
37948
38108
  var AUTO_INSTALL_WINDOW_MS = 60 * 1000;
37949
38109
  var AUTO_INSTALL_LOCK_STALE_MS = 30 * 60 * 1000;
37950
38110
  function autoInstallStampPath() {
37951
- return join17(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
38111
+ return join18(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
37952
38112
  }
37953
38113
  function hasRecentAutoInstallStamp(path) {
37954
38114
  try {
@@ -38034,7 +38194,7 @@ function claimLspAutoInstallPass() {
38034
38194
  encoding: "utf8",
38035
38195
  mode: 384
38036
38196
  });
38037
- renameSync7(tempPath, stampPath);
38197
+ renameSync8(tempPath, stampPath);
38038
38198
  return { release };
38039
38199
  } catch (err) {
38040
38200
  if (claimed) {
@@ -38049,7 +38209,7 @@ function claimLspAutoInstallPass() {
38049
38209
  }
38050
38210
  var VERSION_CHECK_FILE = ".aft-version-check";
38051
38211
  function readVersionCheck(npmPackage) {
38052
- const file = join17(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
38212
+ const file = join18(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
38053
38213
  try {
38054
38214
  const raw = readFileSync12(file, "utf8");
38055
38215
  const parsed = JSON.parse(raw);
@@ -38066,7 +38226,7 @@ function readVersionCheck(npmPackage) {
38066
38226
  }
38067
38227
  function writeVersionCheck(npmPackage, latest) {
38068
38228
  mkdirSync7(lspPackageDir(npmPackage), { recursive: true });
38069
- const file = join17(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
38229
+ const file = join18(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
38070
38230
  const record = {
38071
38231
  last_checked: new Date().toISOString(),
38072
38232
  latest_eligible: latest
@@ -38228,8 +38388,8 @@ var NPM_LSP_TABLE = [
38228
38388
  ];
38229
38389
 
38230
38390
  // src/lsp-project-relevance.ts
38231
- import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "node:fs";
38232
- import { join as join18 } from "node:path";
38391
+ import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "node:fs";
38392
+ import { join as join19 } from "node:path";
38233
38393
  var MAX_WALK_DIRS = 200;
38234
38394
  var MAX_WALK_DEPTH = 4;
38235
38395
  var NOISE_DIRS = new Set([
@@ -38246,7 +38406,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
38246
38406
  if (!rootMarkers)
38247
38407
  return false;
38248
38408
  for (const marker of rootMarkers) {
38249
- if (existsSync16(join18(projectRoot, marker)))
38409
+ if (existsSync17(join19(projectRoot, marker)))
38250
38410
  return true;
38251
38411
  }
38252
38412
  return false;
@@ -38270,7 +38430,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
38270
38430
  }
38271
38431
  function readPackageJson(projectRoot) {
38272
38432
  try {
38273
- const raw = readFileSync13(join18(projectRoot, "package.json"), "utf8");
38433
+ const raw = readFileSync13(join19(projectRoot, "package.json"), "utf8");
38274
38434
  const parsed = JSON.parse(raw);
38275
38435
  if (typeof parsed !== "object" || parsed === null)
38276
38436
  return null;
@@ -38300,7 +38460,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
38300
38460
  for (const entry of entries) {
38301
38461
  if (entry.isDirectory()) {
38302
38462
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
38303
- queue.push({ dir: join18(current.dir, entry.name), depth: current.depth + 1 });
38463
+ queue.push({ dir: join19(current.dir, entry.name), depth: current.depth + 1 });
38304
38464
  }
38305
38465
  continue;
38306
38466
  }
@@ -38428,8 +38588,8 @@ async function resolveTargetVersion(spec, config, fetchImpl = fetch) {
38428
38588
  }
38429
38589
  function ensureInstallAnchor(cwd) {
38430
38590
  try {
38431
- const stub = join19(cwd, "package.json");
38432
- if (!existsSync17(stub)) {
38591
+ const stub = join20(cwd, "package.json");
38592
+ if (!existsSync18(stub)) {
38433
38593
  writeFileSync9(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
38434
38594
  `);
38435
38595
  }
@@ -38655,12 +38815,12 @@ function sha256OfFileSync(path) {
38655
38815
  }
38656
38816
  function quarantineCachedNpmInstall(spec, reason) {
38657
38817
  const packageDir = lspPackageDir(spec.npm);
38658
- const dest = join19(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
38818
+ const dest = join20(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
38659
38819
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
38660
38820
  try {
38661
- mkdirSync8(join19(dest, ".."), { recursive: true });
38821
+ mkdirSync8(join20(dest, ".."), { recursive: true });
38662
38822
  rmSync7(dest, { recursive: true, force: true });
38663
- renameSync8(packageDir, dest);
38823
+ renameSync9(packageDir, dest);
38664
38824
  } catch (err) {
38665
38825
  warn2(`[lsp] tofu_mismatch ${spec.npm}: failed to quarantine cache entry: ${err}`);
38666
38826
  }
@@ -38741,26 +38901,26 @@ async function pushLspPathsAfterAutoInstall(pool, projectRoot, cachedBinDirs) {
38741
38901
  }
38742
38902
 
38743
38903
  // src/lsp-github-install.ts
38744
- import { execFileSync as execFileSync2 } from "node:child_process";
38904
+ import { execFileSync as execFileSync3 } from "node:child_process";
38745
38905
  import { createHash as createHash7, randomBytes as randomBytes3 } from "node:crypto";
38746
38906
  import {
38747
38907
  copyFileSync as copyFileSync4,
38748
38908
  createReadStream as createReadStream2,
38749
38909
  createWriteStream as createWriteStream3,
38750
- existsSync as existsSync18,
38910
+ existsSync as existsSync19,
38751
38911
  lstatSync as lstatSync2,
38752
38912
  mkdirSync as mkdirSync9,
38753
38913
  readdirSync as readdirSync5,
38754
38914
  readFileSync as readFileSync15,
38755
38915
  readlinkSync as readlinkSync2,
38756
38916
  realpathSync as realpathSync3,
38757
- renameSync as renameSync9,
38917
+ renameSync as renameSync10,
38758
38918
  rmSync as rmSync8,
38759
38919
  statSync as statSync11,
38760
38920
  unlinkSync as unlinkSync7,
38761
38921
  writeFileSync as writeFileSync10
38762
38922
  } from "node:fs";
38763
- import { dirname as dirname9, join as join20, relative as relative3, resolve as resolve10 } from "node:path";
38923
+ import { dirname as dirname9, join as join21, relative as relative3, resolve as resolve10 } from "node:path";
38764
38924
  import { Readable as Readable3 } from "node:stream";
38765
38925
  import { pipeline as pipeline3 } from "node:stream/promises";
38766
38926
 
@@ -38853,19 +39013,19 @@ function ghCacheRoot() {
38853
39013
  return getAftLspBinariesDir();
38854
39014
  }
38855
39015
  function ghPackageDir(spec) {
38856
- return join20(ghCacheRoot(), spec.id);
39016
+ return join21(ghCacheRoot(), spec.id);
38857
39017
  }
38858
39018
  function ghBinDir(spec) {
38859
- return join20(ghPackageDir(spec), "bin");
39019
+ return join21(ghPackageDir(spec), "bin");
38860
39020
  }
38861
39021
  function ghExtractDir(spec) {
38862
- return join20(ghPackageDir(spec), "extracted");
39022
+ return join21(ghPackageDir(spec), "extracted");
38863
39023
  }
38864
39024
  var INSTALLED_META_FILE2 = ".aft-installed";
38865
39025
  var INSTALL_FAILED_FILE = ".aft-install-failed.json";
38866
39026
  var INSTALL_FAILURE_BACKOFF_MS = 6 * 60 * 60 * 1000;
38867
39027
  function installFailureMarkerPath(spec) {
38868
- return join20(ghPackageDir(spec), INSTALL_FAILED_FILE);
39028
+ return join21(ghPackageDir(spec), INSTALL_FAILED_FILE);
38869
39029
  }
38870
39030
  function readInstallFailureMarker(spec) {
38871
39031
  try {
@@ -38886,7 +39046,7 @@ function writeInstallFailureMarker(spec, release, sha256, installError) {
38886
39046
  mkdirSync9(dirname9(path), { recursive: true });
38887
39047
  writeFileSync10(tempPath, `${JSON.stringify({ release, sha256, error: markerError, at: new Date().toISOString() })}
38888
39048
  `, { encoding: "utf8", mode: 384 });
38889
- renameSync9(tempPath, path);
39049
+ renameSync10(tempPath, path);
38890
39050
  } catch (err) {
38891
39051
  try {
38892
39052
  rmSync8(tempPath, { force: true });
@@ -38907,12 +39067,12 @@ function isFreshInstallFailure(marker) {
38907
39067
  }
38908
39068
  function ghBinaryPath(spec, platform) {
38909
39069
  const ext = platform === "win32" ? ".exe" : "";
38910
- return join20(ghBinDir(spec), `${spec.binary}${ext}`);
39070
+ return join21(ghBinDir(spec), `${spec.binary}${ext}`);
38911
39071
  }
38912
39072
  function isGithubInstalled(spec, platform) {
38913
39073
  for (const candidate of ghBinaryCandidates(spec, platform)) {
38914
39074
  try {
38915
- if (statSync11(join20(ghBinDir(spec), candidate)).isFile())
39075
+ if (statSync11(join21(ghBinDir(spec), candidate)).isFile())
38916
39076
  return true;
38917
39077
  } catch {}
38918
39078
  }
@@ -38925,7 +39085,7 @@ function ghBinaryCandidates(spec, platform) {
38925
39085
  }
38926
39086
  function readGithubInstalledMetaIn(installDir) {
38927
39087
  try {
38928
- const path = join20(installDir, INSTALLED_META_FILE2);
39088
+ const path = join21(installDir, INSTALLED_META_FILE2);
38929
39089
  if (!statSync11(path).isFile())
38930
39090
  return null;
38931
39091
  const parsed = JSON.parse(readFileSync15(path, "utf8"));
@@ -38952,7 +39112,7 @@ function writeGithubInstalledMetaIn(installDir, version, binarySha256, archiveSh
38952
39112
  binarySha256,
38953
39113
  ...archiveSha256 ? { archiveSha256 } : {}
38954
39114
  };
38955
- writeFileSync10(join20(installDir, INSTALLED_META_FILE2), JSON.stringify(meta), "utf8");
39115
+ writeFileSync10(join21(installDir, INSTALLED_META_FILE2), JSON.stringify(meta), "utf8");
38956
39116
  } catch (err) {
38957
39117
  warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
38958
39118
  }
@@ -39201,7 +39361,7 @@ function validateExtraction(stagingRoot) {
39201
39361
  throw new Error(`failed to read staging dir ${dir}: ${err}`);
39202
39362
  }
39203
39363
  for (const entry of entries) {
39204
- const full = join20(dir, entry);
39364
+ const full = join21(dir, entry);
39205
39365
  let lst;
39206
39366
  try {
39207
39367
  lst = lstatSync2(full);
@@ -39247,7 +39407,7 @@ function assertArchiveEntryPath(entry) {
39247
39407
  }
39248
39408
  function precheckWithTar(archivePath, command) {
39249
39409
  let totalBytes = 0;
39250
- const verbose = execFileSync2(command, ["-tvf", archivePath], { encoding: "utf8" });
39410
+ const verbose = execFileSync3(command, ["-tvf", archivePath], { encoding: "utf8" });
39251
39411
  for (const line of verbose.split(`
39252
39412
  `)) {
39253
39413
  if (line.startsWith("h")) {
@@ -39260,7 +39420,7 @@ function precheckWithTar(archivePath, command) {
39260
39420
  totalBytes += Math.max(...numeric);
39261
39421
  }
39262
39422
  }
39263
- const names = execFileSync2(command, ["-tf", archivePath], { encoding: "utf8" });
39423
+ const names = execFileSync3(command, ["-tf", archivePath], { encoding: "utf8" });
39264
39424
  for (const entry of names.split(`
39265
39425
  `)) {
39266
39426
  if (entry.length > 0)
@@ -39271,19 +39431,18 @@ function precheckWithTar(archivePath, command) {
39271
39431
  function precheckArchiveContents(archivePath, archiveType, zipListingMode = "platform") {
39272
39432
  let totalBytes = 0;
39273
39433
  if (archiveType === "zip" && zipListingMode === "platform" && process.platform !== "win32") {
39274
- const out = execFileSync2("unzip", ["-l", archivePath], { encoding: "utf8" });
39434
+ const out = execFileSync3("unzip", ["-l", archivePath], { encoding: "utf8" });
39275
39435
  const match = out.match(/^\s*(\d+)\s+\d+\s+files?\s*$/m);
39276
39436
  if (match)
39277
39437
  totalBytes = Number.parseInt(match[1] ?? "0", 10);
39278
- const names = execFileSync2("unzip", ["-Z1", archivePath], { encoding: "utf8" });
39438
+ const names = execFileSync3("unzip", ["-Z1", archivePath], { encoding: "utf8" });
39279
39439
  for (const entry of names.split(`
39280
39440
  `)) {
39281
39441
  if (entry.length > 0)
39282
39442
  assertArchiveEntryPath(entry);
39283
39443
  }
39284
39444
  } else {
39285
- const command = process.platform === "win32" ? "tar.exe" : "tar";
39286
- totalBytes = precheckWithTar(archivePath, command);
39445
+ totalBytes = precheckWithTar(archivePath, windowsTarExecutable());
39287
39446
  }
39288
39447
  if (totalBytes > MAX_EXTRACT_BYTES2) {
39289
39448
  throw new Error(`archive uncompressed size ${totalBytes} exceeds ${MAX_EXTRACT_BYTES2}`);
@@ -39303,7 +39462,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
39303
39462
  try {
39304
39463
  rmSync8(destDir, { recursive: true, force: true });
39305
39464
  } catch {}
39306
- renameSync9(stagingDir, destDir);
39465
+ renameSync10(stagingDir, destDir);
39307
39466
  } catch (err) {
39308
39467
  try {
39309
39468
  rmSync8(stagingDir, { recursive: true, force: true });
@@ -39313,12 +39472,12 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
39313
39472
  }
39314
39473
  function quarantineCachedGithubInstall(spec, reason) {
39315
39474
  const packageDir = ghPackageDir(spec);
39316
- const dest = join20(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
39475
+ const dest = join21(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
39317
39476
  warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
39318
39477
  try {
39319
39478
  mkdirSync9(dirname9(dest), { recursive: true });
39320
39479
  rmSync8(dest, { recursive: true, force: true });
39321
- renameSync9(packageDir, dest);
39480
+ renameSync10(packageDir, dest);
39322
39481
  } catch (err) {
39323
39482
  warn2(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
39324
39483
  }
@@ -39326,7 +39485,7 @@ function quarantineCachedGithubInstall(spec, reason) {
39326
39485
  function validateCachedGithubInstall(spec, platform) {
39327
39486
  const packageDir = ghPackageDir(spec);
39328
39487
  const meta = readGithubInstalledMetaIn(packageDir);
39329
- const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join20(ghBinDir(spec), candidate)).find((candidate) => {
39488
+ const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join21(ghBinDir(spec), candidate)).find((candidate) => {
39330
39489
  try {
39331
39490
  return statSync11(candidate).isFile();
39332
39491
  } catch {
@@ -39362,30 +39521,21 @@ function validateCachedGithubInstall(spec, platform) {
39362
39521
  function runPlatformExtractor(archivePath, destDir, archiveType) {
39363
39522
  if (archiveType === "zip") {
39364
39523
  if (process.platform === "win32") {
39365
- execFileSync2("tar.exe", ["-xf", archivePath, "-C", destDir], {
39366
- stdio: "pipe",
39367
- timeout: 180000
39368
- });
39524
+ execTarExtractionSync(["-xf", archivePath, "-C", destDir], 180000);
39369
39525
  return;
39370
39526
  }
39371
- execFileSync2("unzip", ["-q", "-o", archivePath, "-d", destDir], {
39527
+ execFileSync3("unzip", ["-q", "-o", archivePath, "-d", destDir], {
39372
39528
  stdio: "pipe",
39373
39529
  timeout: 180000
39374
39530
  });
39375
39531
  return;
39376
39532
  }
39377
39533
  if (archiveType === "tar.gz") {
39378
- execFileSync2("tar", ["-xzf", archivePath, "-C", destDir], {
39379
- stdio: "pipe",
39380
- timeout: 180000
39381
- });
39534
+ execTarExtractionSync(["-xzf", archivePath, "-C", destDir], 180000);
39382
39535
  return;
39383
39536
  }
39384
39537
  if (archiveType === "tar.xz") {
39385
- execFileSync2("tar", ["-xf", archivePath, "-C", destDir], {
39386
- stdio: "pipe",
39387
- timeout: 180000
39388
- });
39538
+ execTarExtractionSync(["-xf", archivePath, "-C", destDir], 180000);
39389
39539
  return;
39390
39540
  }
39391
39541
  throw new Error(`unsupported archive type: ${archiveType}`);
@@ -39406,7 +39556,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
39406
39556
  }
39407
39557
  const pkgDir = ghPackageDir(spec);
39408
39558
  const extractDir = ghExtractDir(spec);
39409
- const archivePath = join20(pkgDir, expected.name);
39559
+ const archivePath = join21(pkgDir, expected.name);
39410
39560
  log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
39411
39561
  try {
39412
39562
  await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
@@ -39448,8 +39598,8 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
39448
39598
  unlinkSync7(archivePath);
39449
39599
  } catch {}
39450
39600
  }
39451
- const innerBinaryPath = join20(extractDir, spec.binaryPathInArchive(platform, arch, version));
39452
- if (!existsSync18(innerBinaryPath)) {
39601
+ const innerBinaryPath = join21(extractDir, spec.binaryPathInArchive(platform, arch, version));
39602
+ if (!existsSync19(innerBinaryPath)) {
39453
39603
  const message = `extracted binary not found at ${innerBinaryPath}`;
39454
39604
  error2(`[lsp] ${spec.id}: ${message}`);
39455
39605
  return { ok: false, sha256: archiveSha256, error: message };
@@ -39554,7 +39704,7 @@ function runGithubAutoInstall(relevantServers, config, fetchImpl = fetch) {
39554
39704
  if (!host) {
39555
39705
  for (const spec of GITHUB_LSP_TABLE) {
39556
39706
  try {
39557
- if (existsSync18(ghBinDir(spec))) {
39707
+ if (existsSync19(ghBinDir(spec))) {
39558
39708
  cachedBinDirs.push(ghBinDir(spec));
39559
39709
  }
39560
39710
  } catch {}
@@ -39871,25 +40021,25 @@ function isTuiConnected(sessionId) {
39871
40021
  // src/shared/rpc-server.ts
39872
40022
  import { randomBytes as randomBytes4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
39873
40023
  import {
39874
- existsSync as existsSync19,
40024
+ existsSync as existsSync20,
39875
40025
  mkdirSync as mkdirSync10,
39876
40026
  readdirSync as readdirSync6,
39877
40027
  readFileSync as readFileSync16,
39878
- renameSync as renameSync10,
40028
+ renameSync as renameSync11,
39879
40029
  unlinkSync as unlinkSync8,
39880
40030
  writeFileSync as writeFileSync11
39881
40031
  } from "node:fs";
39882
40032
  import { createServer } from "node:http";
39883
- import { dirname as dirname10, join as join22 } from "node:path";
40033
+ import { dirname as dirname10, join as join23 } from "node:path";
39884
40034
 
39885
40035
  // src/shared/rpc-utils.ts
39886
- import { join as join21 } from "node:path";
40036
+ import { join as join22 } from "node:path";
39887
40037
  function projectHash(directory) {
39888
40038
  return projectRootKeyHash(directory);
39889
40039
  }
39890
40040
  function rpcPortFileDir(storageDir, directory) {
39891
40041
  const hash = projectHash(directory);
39892
- return join21(storageDir, "rpc", hash, "ports");
40042
+ return join22(storageDir, "rpc", hash, "ports");
39893
40043
  }
39894
40044
  function isPidAlive(pid) {
39895
40045
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
@@ -39963,7 +40113,7 @@ class AftRpcServer {
39963
40113
  constructor(storageDir, directory) {
39964
40114
  this.portsDir = rpcPortFileDir(storageDir, directory);
39965
40115
  this.instanceId = randomBytes4(8).toString("hex");
39966
- this.portFilePath = join22(this.portsDir, `${this.instanceId}.json`);
40116
+ this.portFilePath = join23(this.portsDir, `${this.instanceId}.json`);
39967
40117
  }
39968
40118
  handle(method, handler) {
39969
40119
  this.handlers.set(method, handler);
@@ -39993,6 +40143,7 @@ class AftRpcServer {
39993
40143
  });
39994
40144
  this.bunServer = server;
39995
40145
  this.port = server.port ?? 0;
40146
+ server.unref?.();
39996
40147
  this.afterServerStarted();
39997
40148
  return this.port;
39998
40149
  }
@@ -40038,7 +40189,7 @@ class AftRpcServer {
40038
40189
  pid: process.pid,
40039
40190
  started_at: Date.now()
40040
40191
  }), { encoding: "utf-8", mode: 384 });
40041
- renameSync10(tmpPath, this.portFilePath);
40192
+ renameSync11(tmpPath, this.portFilePath);
40042
40193
  }
40043
40194
  sweepDeadPortFiles() {
40044
40195
  let entries;
@@ -40050,7 +40201,7 @@ class AftRpcServer {
40050
40201
  for (const entry of entries) {
40051
40202
  if (!entry.endsWith(".json"))
40052
40203
  continue;
40053
- const filePath = join22(this.portsDir, entry);
40204
+ const filePath = join23(this.portsDir, entry);
40054
40205
  if (filePath === this.portFilePath)
40055
40206
  continue;
40056
40207
  try {
@@ -40069,7 +40220,7 @@ class AftRpcServer {
40069
40220
  if (!this.nodeServer && !this.bunServer || this.port <= 0)
40070
40221
  return;
40071
40222
  try {
40072
- if (existsSync19(this.portFilePath))
40223
+ if (existsSync20(this.portFilePath))
40073
40224
  return;
40074
40225
  this.writePortFile();
40075
40226
  log2(`RPC port file was missing; rewrote ${this.portFilePath}`);
@@ -40336,12 +40487,6 @@ function formatCacheRoleLabel(role) {
40336
40487
  }
40337
40488
  return role;
40338
40489
  }
40339
- function formatSemanticIndexStatus(status, stage) {
40340
- if ((status === "loading" || status === "building") && stage === "fingerprint_change") {
40341
- return "Rebuilding (model changed)";
40342
- }
40343
- return status;
40344
- }
40345
40490
  function formatSemanticRefreshing(refreshingCount) {
40346
40491
  if (!Number.isFinite(refreshingCount) || refreshingCount <= 0)
40347
40492
  return null;
@@ -40453,7 +40598,7 @@ function formatStatusMarkdown(status) {
40453
40598
  `- **Cache role:** \`${formatCacheRoleLabel(status.cache_role)}\``
40454
40599
  ];
40455
40600
  appendDegradedStatus(lines, status, true);
40456
- lines.push("", "### Enabled features", `- \`format_on_edit\`: ${formatFlag(status.features.format_on_edit)}`, `- \`search_index\`: ${formatFlag(status.features.search_index)}`, `- \`semantic_search\`: ${formatFlag(status.features.semantic_search)}`, `- \`callgraph_store\`: ${formatFlag(status.features.callgraph_store)}`, "", "### Search index", `- **Status:** \`${status.search_index.status}\``, `- **Files:** ${formatCount(status.search_index.files)}`, `- **Trigrams:** ${formatCount(status.search_index.trigrams)}`, "", "### Semantic index", `- **Status:** \`${formatSemanticIndexStatus(status.semantic_index.status, status.semantic_index.stage)}\``);
40601
+ lines.push("", "### Enabled features", `- \`format_on_edit\`: ${formatFlag(status.features.format_on_edit)}`, `- \`search_index\`: ${formatFlag(status.features.search_index)}`, `- \`semantic_search\`: ${formatFlag(status.features.semantic_search)}`, `- \`callgraph_store\`: ${formatFlag(status.features.callgraph_store)}`, "", "### Search index", `- **Status:** \`${status.search_index.status}\``, `- **Files:** ${formatCount(status.search_index.files)}`, `- **Trigrams:** ${formatCount(status.search_index.trigrams)}`, "", "### Semantic index", `- **Status:** \`${formatSemanticIndexStatus(status.semantic_index.status, status.semantic_index.stage, status.semantic_index.error)}\``);
40457
40602
  const refreshing = formatSemanticRefreshing(status.semantic_index.refreshing_count);
40458
40603
  if (refreshing) {
40459
40604
  lines.push(`- **Refresh:** ${refreshing}`);
@@ -40622,7 +40767,7 @@ function isSyncWatchAborted(sessionID) {
40622
40767
  }
40623
40768
 
40624
40769
  // src/tools/permissions.ts
40625
- import { execFileSync as execFileSync3 } from "node:child_process";
40770
+ import { execFileSync as execFileSync4 } from "node:child_process";
40626
40771
  import * as fs4 from "node:fs";
40627
40772
  import { tmpdir as tmpdir3 } from "node:os";
40628
40773
  import * as path3 from "node:path";
@@ -40877,7 +41022,7 @@ function gitRootForNearestExistingParent(resolved) {
40877
41022
  cwd = path3.dirname(nearest);
40878
41023
  } catch {}
40879
41024
  try {
40880
- const out = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
41025
+ const out = execFileSync4("git", ["rev-parse", "--show-toplevel"], {
40881
41026
  cwd,
40882
41027
  encoding: "utf8",
40883
41028
  stdio: ["ignore", "pipe", "ignore"]
@@ -41190,6 +41335,26 @@ function failure(error) {
41190
41335
  })();
41191
41336
  return new Error(`V2 tool execution rejected with a non-Error value: ${detail}`);
41192
41337
  }
41338
+ function isPlainObject3(value) {
41339
+ if (typeof value !== "object" || value === null)
41340
+ return false;
41341
+ const prototype = Object.getPrototypeOf(value);
41342
+ return prototype === Object.prototype || prototype === null;
41343
+ }
41344
+ function jsonSafeMetadata(value) {
41345
+ if (Array.isArray(value)) {
41346
+ return value.map((entry) => entry === undefined ? null : jsonSafeMetadata(entry));
41347
+ }
41348
+ if (!isPlainObject3(value))
41349
+ return value;
41350
+ const cleaned = {};
41351
+ for (const [key, entry] of Object.entries(value)) {
41352
+ if (entry === undefined)
41353
+ continue;
41354
+ cleaned[key] = jsonSafeMetadata(entry);
41355
+ }
41356
+ return cleaned;
41357
+ }
41193
41358
  function resultContent(result) {
41194
41359
  if (typeof result === "string")
41195
41360
  return { content: result };
@@ -41200,15 +41365,39 @@ function resultContent(result) {
41200
41365
  ...attachment.filename ? { name: attachment.filename } : {}
41201
41366
  }));
41202
41367
  const content = attachments.length ? [{ type: "text", text: result.output }, ...attachments] : result.output;
41203
- const metadata = {
41368
+ const metadata = jsonSafeMetadata({
41204
41369
  ...result.metadata ?? {},
41205
41370
  ...result.title ? { title: result.title } : {}
41206
- };
41371
+ });
41207
41372
  return {
41208
41373
  content,
41209
41374
  ...Object.keys(metadata).length ? { metadata } : {}
41210
41375
  };
41211
41376
  }
41377
+ function failureEnvelopeMessage(result) {
41378
+ const output = typeof result === "string" ? result : result.output;
41379
+ if (typeof output !== "string")
41380
+ return;
41381
+ const trimmed = output.trim();
41382
+ if (!trimmed.startsWith("{") || !trimmed.includes('"success"'))
41383
+ return;
41384
+ let parsed;
41385
+ try {
41386
+ parsed = JSON.parse(trimmed);
41387
+ } catch {
41388
+ return;
41389
+ }
41390
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
41391
+ return;
41392
+ const envelope = parsed;
41393
+ if (envelope.success !== false)
41394
+ return;
41395
+ for (const field of [envelope.message, envelope.error, envelope.code]) {
41396
+ if (typeof field === "string" && field.length > 0)
41397
+ return field;
41398
+ }
41399
+ return "The tool call failed.";
41400
+ }
41212
41401
  function bareToolName3(name) {
41213
41402
  return name.startsWith("aft_") ? name.slice(4) : name;
41214
41403
  }
@@ -41271,15 +41460,15 @@ function runtimeFor(location, context, signal, consumers) {
41271
41460
  abort: signal,
41272
41461
  effectAbort: signal,
41273
41462
  metadata: (update) => {
41274
- Effect.runPromise(context.progress({
41463
+ Effect.runPromise(context.progress(jsonSafeMetadata({
41275
41464
  ...update.metadata ?? {},
41276
41465
  ...update.title ? { title: update.title } : {}
41277
- }));
41466
+ })));
41278
41467
  },
41279
41468
  ask: (request) => {
41280
41469
  if (consumers.requestPermission)
41281
41470
  return consumers.requestPermission(request, context);
41282
- return Promise.reject(new Error(`The "${request.permission}" operation was refused because the OpenCode V2 host did not provide a permission request endpoint.`));
41471
+ return Promise.reject(new Error(`The "${request.permission}" operation was refused because this AFT runtime has no permission evaluator bound, so the host's permission rules for it could not be consulted.`));
41283
41472
  },
41284
41473
  progress: context.progress
41285
41474
  };
@@ -41308,6 +41497,9 @@ function projectV2Tool(name, definition, location, consumers = {}) {
41308
41497
  context: runtime,
41309
41498
  definition
41310
41499
  }) : await definition.execute(input, runtime);
41500
+ const refusal = failureEnvelopeMessage(result);
41501
+ if (refusal)
41502
+ throw new Error(refusal);
41311
41503
  return resultContent(result);
41312
41504
  },
41313
41505
  catch: failure
@@ -42402,7 +42594,7 @@ function createReadTool(ctx) {
42402
42594
  try {
42403
42595
  await runAsk(context.ask({
42404
42596
  permission: "read",
42405
- patterns: [filePath],
42597
+ patterns: [permissionPath(context, filePath)],
42406
42598
  always: ["*"],
42407
42599
  metadata: {}
42408
42600
  }));
@@ -42563,7 +42755,7 @@ function getEditDescription(ctx, writeToolName) {
42563
42755
 
42564
42756
  **Modes** (determined by which parameters you provide):
42565
42757
 
42566
- Provide exactly one mode per call: appendContent, edits[], or symbol plus content. Mixing modes or providing none is rejected — there is no implicit "write" fallback. To edit multiple files, make parallel \`edit\` calls in one response.
42758
+ Provide exactly one mode per call: appendContent, edits[], or symbol plus content. \`symbol\` and \`content\` are only meaningful together; a call carrying one without the other is incomplete. Mixing modes or providing none is rejected — there is no implicit "write" fallback. To edit multiple files, make parallel \`edit\` calls in one response.
42567
42759
 
42568
42760
  1. **Append** — pass \`path\` + \`appendContent\`
42569
42761
  Appends text to the end of a file, creating it if it does not exist.
@@ -42664,8 +42856,8 @@ function createEditTool(ctx, writeToolName = "write") {
42664
42856
  description: getEditDescription(ctx, writeToolName),
42665
42857
  args: {
42666
42858
  filePath: z7.string().describe("Path to the file to edit (absolute or relative to project root)"),
42667
- symbol: z7.string().optional().describe("Named symbol to replace (function, class, type)"),
42668
- content: z7.string().optional().describe("Replacement content for symbol mode. For whole-file writes, use the `write` tool."),
42859
+ symbol: z7.string().optional().describe("Named symbol to replace; only meaningful together with `content`. A call carrying one without the other is incomplete."),
42860
+ content: z7.string().optional().describe("Replacement content for symbol mode; only meaningful together with `symbol`. A call carrying one without the other is incomplete. For whole-file writes, use the `write` tool."),
42669
42861
  appendContent: z7.string().optional().describe("Text to append to the end of path; creates the file if needed"),
42670
42862
  edits: z7.array(z7.object({
42671
42863
  oldString: z7.string().optional().describe("Text to find for a batch find/replace edit"),
@@ -42907,7 +43099,7 @@ function createDeleteTool(ctx) {
42907
43099
  }
42908
43100
  await runAsk(context.ask({
42909
43101
  permission: "edit",
42910
- patterns: absolutePaths,
43102
+ patterns: resolveRelativePatterns(context, absolutePaths),
42911
43103
  always: ["*"],
42912
43104
  metadata: { action: "delete", count: absolutePaths.length }
42913
43105
  }));
@@ -42960,7 +43152,7 @@ function createMoveTool(ctx) {
42960
43152
  }
42961
43153
  await runAsk(context.ask({
42962
43154
  permission: "edit",
42963
- patterns: [filePath, destPath],
43155
+ patterns: resolveRelativePatterns(context, [filePath, destPath]),
42964
43156
  always: ["*"],
42965
43157
  metadata: { action: "move" }
42966
43158
  }));
@@ -43290,7 +43482,7 @@ function inspectTools(ctx) {
43290
43482
  ` + "Treat `dead_code` as a hint, not proof: reachability is call-based, so symbols reached only via method dispatch or referenced only in type position may be false positives — verify before deleting.\n\n" + "When a list is cut, the reply ends with `shown N of M <unit> (<reason>) · narrow: <knobs>`; absence of that line means the list is complete.",
43291
43483
  args: {
43292
43484
  sections: arg(z9.union([z9.string(), z9.array(z9.string())]).optional().describe("Categories to include in detailed drill-down (e.g. 'todos' or ['todos', 'dead_code', 'cycles']). Use 'all' for every active category. Omit for summary-only mode. `sections` changes detail, not the categories verified.")),
43293
- scope: arg(z9.union([z9.string(), z9.array(z9.string())]).optional().describe("Restrict returned results to paths under this scope (file or directory, absolute or relative to project root). `scope=` narrows results and limits Rust LSP startup to owning Cargo workspaces; it does not trigger per-file diagnostic collection. Scoped files no producer has authoritatively analyzed are reported as named gaps (complete: false), never as a clean empty result.")),
43485
+ scope: arg(z9.union([z9.string(), z9.array(z9.string())]).optional().describe("Restrict returned results to paths under this scope (one path, or an array of paths — not a space-separated list; file or directory; absolute or relative to project root). `scope=` narrows results and limits Rust LSP startup to owning Cargo workspaces; it does not trigger per-file diagnostic collection. Scoped files no producer has authoritatively analyzed are reported as named gaps (complete: false), never as a clean empty result.")),
43294
43486
  topK: arg(z9.number().int().positive().max(100).optional().describe("Max drill-down items per category. Default 20, max 100."))
43295
43487
  },
43296
43488
  execute: async (args, context) => {
@@ -43683,7 +43875,7 @@ function safetyTools(ctx) {
43683
43875
  ` + `- 'undo': Undo the entire last tool call when 'path' is omitted (typical), or undo the last edit to one file when 'path' is provided. Note: pops from the undo stack (irreversible, no redo). Use 'history' to inspect per-file history before undoing.
43684
43876
  ` + `- 'history': List all edit snapshots for a file. Requires 'path'.
43685
43877
  ` + `- 'checkpoint': Save a named snapshot. Explicit 'files' may be untracked or gitignored; omit them to snapshot backup-tracked files. Checkpoints are session-scoped and lost on bridge or daemon restart. Requires 'name'.
43686
- ` + `- 'restore': Restore files to a previously saved checkpoint. Requires 'name'.
43878
+ ` + `- 'restore': Restore files to a previously saved checkpoint. Optional 'path'/'files' scopes the restore; omitted scope restores the whole checkpoint. Requires 'name'.
43687
43879
  ` + `- 'list': List all available named checkpoints. No extra params needed.
43688
43880
 
43689
43881
  ` + `Each op requires specific parameters — see parameter descriptions for requirements.
@@ -43691,9 +43883,9 @@ function safetyTools(ctx) {
43691
43883
  ` + "Use checkpoint before risky multi-file changes. Use undo for quick single-file rollback.",
43692
43884
  args: {
43693
43885
  op: z12.enum(["undo", "history", "checkpoint", "restore", "list"]).describe("Safety operation"),
43694
- path: z12.string().optional().describe("File path (required for history, optional for undo). Absolute or relative to project root"),
43886
+ path: z12.string().optional().describe("File path (required for history, optional for undo, optional for restore — restores only that file). Absolute or relative to project root"),
43695
43887
  name: z12.string().optional().describe("Checkpoint name (required for checkpoint, restore)"),
43696
- files: z12.array(z12.string()).optional().describe("Specific files to include in checkpoint (optional, defaults to backup-tracked files; explicit files may be untracked or gitignored)")
43888
+ files: z12.array(z12.string()).optional().describe("Specific files to include in checkpoint, or to restore from a checkpoint (optional; restore without path/files restores the whole checkpoint; explicit checkpoint files may be untracked or gitignored)")
43697
43889
  },
43698
43890
  execute: async (args, context) => {
43699
43891
  const op = args.op;
@@ -44030,7 +44222,7 @@ function semanticTools(ctx) {
44030
44222
  const rawArgs = { query };
44031
44223
  const topK = coerceOptionalInt(args.topK, "topK", 1, 50);
44032
44224
  const offset = coerceOptionalInt(args.offset, "offset", 0, 1e5);
44033
- const includeTests = typeof args.includeTests === "boolean" ? args.includeTests : undefined;
44225
+ const includeTests = !isEmptyParam(args.includeTests) ? coerceBoolean(args.includeTests) : undefined;
44034
44226
  if (topK !== undefined)
44035
44227
  rawArgs.topK = topK;
44036
44228
  if (offset !== undefined)
@@ -44270,11 +44462,11 @@ function throwSentinel(command) {
44270
44462
  throw sentinel;
44271
44463
  }
44272
44464
  var PLUGIN_VERSION = resolvePluginVersion(import.meta.url);
44273
- var ANNOUNCEMENT_VERSION = "0.56.0";
44465
+ var ANNOUNCEMENT_VERSION = "0.57.0";
44274
44466
  var ANNOUNCEMENT_FEATURES = [
44275
- "Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
44276
- "aft_zoom handles real-world .jsonc: files with comment banners above the opening brace now resolve, and not-found errors point at the segment that actually failed (thanks @iceteaSA).",
44277
- "Disk hygiene: stale per-checkout inspect caches from old worktrees are now swept automatically — one machine reclaimed 21 GB."
44467
+ "OpenCode 2 is supported: tools, permission prompts, the sidebar and cancellation all work on the GA host, and an end-to-end matrix guards them.",
44468
+ "`doctor` configures a machine that has only OpenCode 2 installed, and `--fix` no longer skips unrelated repairs when it cannot decide the generation.",
44469
+ "A code-health scan no longer starts while the same project is still building its call graph, which cost about 90 MB of peak memory on large repositories."
44278
44470
  ];
44279
44471
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
44280
44472
  var plugin = async (input) => initializePluginForDirectory(input);