@cortexkit/aft-pi 0.39.4 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11675,11 +11675,6 @@ function error(message, meta) {
11675
11675
  }
11676
11676
  }
11677
11677
  // ../aft-bridge/dist/bash-format.js
11678
- function appendPipeStripNote(output, note) {
11679
- return note ? `${output}
11680
-
11681
- ${note}` : output;
11682
- }
11683
11678
  function formatSeconds(ms) {
11684
11679
  return `${Number((ms / 1000).toFixed(1))}s`;
11685
11680
  }
@@ -11757,12 +11752,16 @@ function maybeAppendGrepSearchHint(output, command, aftSearchRegistered, project
11757
11752
  ${hint}`;
11758
11753
  }
11759
11754
  function shouldSuppressGrepSearchHint(command, projectRoot) {
11760
- const root = projectRoot?.trim();
11761
- if (!root)
11762
- return false;
11763
11755
  const statements = splitTopLevelStatements(command);
11764
11756
  if (statements === null)
11765
11757
  return false;
11758
+ if (allSearchPathOperandsAreDynamic(statements))
11759
+ return true;
11760
+ const root = projectRoot?.trim();
11761
+ if (!root)
11762
+ return false;
11763
+ const resolvedRoot = path.resolve(root);
11764
+ let effectiveCwd = resolvedRoot;
11766
11765
  let sawCodeSearchStatement = false;
11767
11766
  for (const statement of statements) {
11768
11767
  const firstStage = firstPipelineStage(statement);
@@ -11771,19 +11770,84 @@ function shouldSuppressGrepSearchHint(command, projectRoot) {
11771
11770
  const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
11772
11771
  if (firstToken === null)
11773
11772
  continue;
11774
- if (firstToken.token !== "grep" && firstToken.token !== "rg")
11773
+ const head = firstToken.token;
11774
+ if (head === "cd") {
11775
+ effectiveCwd = nextCwdAfterCd(effectiveCwd, firstStage, firstToken.end);
11776
+ continue;
11777
+ }
11778
+ if (head !== "grep" && head !== "rg")
11775
11779
  continue;
11776
11780
  sawCodeSearchStatement = true;
11781
+ if (effectiveCwd === null)
11782
+ continue;
11783
+ if (!isDirInsideProject(resolvedRoot, effectiveCwd))
11784
+ continue;
11777
11785
  const operands = collectPathOperands(firstStage, firstToken.end);
11778
11786
  if (operands.length === 0)
11779
11787
  return false;
11780
11788
  for (const operand of operands) {
11781
- if (isPathInsideProject(root, operand))
11789
+ if (isDynamicPathOperand(operand))
11790
+ continue;
11791
+ if (isPathInsideProject(resolvedRoot, effectiveCwd, operand))
11782
11792
  return false;
11783
11793
  }
11784
11794
  }
11785
11795
  return sawCodeSearchStatement;
11786
11796
  }
11797
+ function allSearchPathOperandsAreDynamic(statements) {
11798
+ let sawDynamicOnlySearch = false;
11799
+ for (const statement of statements) {
11800
+ const firstStage = firstPipelineStage(statement);
11801
+ if (firstStage === null)
11802
+ continue;
11803
+ const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
11804
+ if (firstToken === null)
11805
+ continue;
11806
+ const head = firstToken.token;
11807
+ if (head !== "grep" && head !== "rg")
11808
+ continue;
11809
+ const operands = collectPathOperands(firstStage, firstToken.end);
11810
+ if (operands.length === 0)
11811
+ return false;
11812
+ if (operands.some((operand) => !isDynamicPathOperand(operand)))
11813
+ return false;
11814
+ sawDynamicOnlySearch = true;
11815
+ }
11816
+ return sawDynamicOnlySearch;
11817
+ }
11818
+ function nextCwdAfterCd(currentCwd, firstStage, afterCd) {
11819
+ let index = skipSpaces(firstStage, afterCd);
11820
+ let target = null;
11821
+ while (index < firstStage.length) {
11822
+ const tokenResult = readShellToken(firstStage, index);
11823
+ if (tokenResult === null)
11824
+ break;
11825
+ const { token, end } = tokenResult;
11826
+ if (end <= index)
11827
+ break;
11828
+ index = skipSpaces(firstStage, end);
11829
+ if (token === "-")
11830
+ return null;
11831
+ if (token.length > 1 && token.startsWith("-"))
11832
+ continue;
11833
+ target = token;
11834
+ break;
11835
+ }
11836
+ if (target === null)
11837
+ return path.resolve(os.homedir());
11838
+ if (target.includes("$") || target.includes("`"))
11839
+ return null;
11840
+ const expanded = expandTilde(target);
11841
+ if (path.isAbsolute(expanded))
11842
+ return path.resolve(expanded);
11843
+ if (currentCwd === null)
11844
+ return null;
11845
+ return path.resolve(currentCwd, expanded);
11846
+ }
11847
+ function isDirInsideProject(resolvedRoot, dir) {
11848
+ const rel = path.relative(resolvedRoot, path.resolve(dir));
11849
+ return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
11850
+ }
11787
11851
  function collectPathOperands(firstStage, startAfterCommand) {
11788
11852
  const operands = [];
11789
11853
  let index = skipSpaces(firstStage, startAfterCommand);
@@ -11805,6 +11869,9 @@ function collectPathOperands(firstStage, startAfterCommand) {
11805
11869
  function looksLikePathOperand(token) {
11806
11870
  return token.includes("/") || token.startsWith("~") || token.startsWith("./") || token.startsWith("../");
11807
11871
  }
11872
+ function isDynamicPathOperand(token) {
11873
+ return token.startsWith("~") || token.includes("$") || token.includes("`");
11874
+ }
11808
11875
  function expandTilde(target) {
11809
11876
  if (!target.startsWith("~"))
11810
11877
  return target;
@@ -11817,10 +11884,9 @@ function resolvePathOperand(projectRoot, operand) {
11817
11884
  const expanded = expandTilde(operand);
11818
11885
  return path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(projectRoot, expanded);
11819
11886
  }
11820
- function isPathInsideProject(projectRoot, operand) {
11821
- const root = path.resolve(projectRoot);
11822
- const resolved = resolvePathOperand(root, operand);
11823
- const rel = path.relative(root, resolved);
11887
+ function isPathInsideProject(resolvedRoot, baseCwd, operand) {
11888
+ const resolved = resolvePathOperand(baseCwd, operand);
11889
+ const rel = path.relative(resolvedRoot, resolved);
11824
11890
  return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
11825
11891
  }
11826
11892
  function splitTopLevelStatements(command) {
@@ -12013,6 +12079,7 @@ var LONG_RUNNING_COMMAND_TIMEOUT_MS = {
12013
12079
  trace_to_symbol: 60000,
12014
12080
  trace_data: 60000,
12015
12081
  impact: 60000,
12082
+ inspect: 60000,
12016
12083
  grep: 60000,
12017
12084
  glob: 60000,
12018
12085
  semantic_search: 60000
@@ -12071,7 +12138,6 @@ function formatStatusBar(counts) {
12071
12138
  // ../aft-bridge/dist/bridge.js
12072
12139
  var DEFAULT_BRIDGE_TIMEOUT_MS = 30000;
12073
12140
  var BRIDGE_HANG_TIMEOUT_THRESHOLD = 2;
12074
- var SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS = 5000;
12075
12141
  var MAX_STDOUT_BUFFER = 64 * 1024 * 1024;
12076
12142
  var STDOUT_BUFFER_COMPACT_THRESHOLD = 64 * 1024;
12077
12143
  var TERMINAL_BASH_STATUSES = new Set([
@@ -12144,28 +12210,19 @@ function compareSemver(a, b) {
12144
12210
  }
12145
12211
  return 0;
12146
12212
  }
12147
- function clampSemanticTimeout(configOverrides, bridgeTimeoutMs) {
12148
- const semantic = configOverrides.semantic;
12149
- if (!semantic || typeof semantic !== "object" || Array.isArray(semantic)) {
12150
- return configOverrides;
12151
- }
12152
- const timeoutMs = semantic.timeout_ms;
12153
- if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs)) {
12154
- return configOverrides;
12155
- }
12156
- const semanticTransportBudgetMs = Math.max(bridgeTimeoutMs, LONG_RUNNING_COMMAND_TIMEOUT_MS.semantic_search ?? 0);
12157
- const maxSemanticTimeoutMs = semanticTransportBudgetMs > SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS ? semanticTransportBudgetMs - SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS : Math.max(1, semanticTransportBudgetMs - 1);
12158
- if (timeoutMs <= maxSemanticTimeoutMs) {
12159
- return configOverrides;
12160
- }
12161
- warn(`semantic.timeout_ms=${timeoutMs} exceeds the semantic transport budget; clamping to ${maxSemanticTimeoutMs}ms (budget: ${semanticTransportBudgetMs}ms)`);
12162
- return {
12163
- ...configOverrides,
12164
- semantic: {
12165
- ...semantic,
12166
- timeout_ms: maxSemanticTimeoutMs
12213
+ function coerceConfigureDroppedKeys(value) {
12214
+ if (!Array.isArray(value))
12215
+ return [];
12216
+ const dropped = [];
12217
+ for (const item of value) {
12218
+ if (!item || typeof item !== "object" || Array.isArray(item))
12219
+ continue;
12220
+ const record = item;
12221
+ if (typeof record.key === "string" && typeof record.tier === "string" && typeof record.reason === "string") {
12222
+ dropped.push({ key: record.key, tier: record.tier, reason: record.reason });
12167
12223
  }
12168
- };
12224
+ }
12225
+ return dropped;
12169
12226
  }
12170
12227
 
12171
12228
  class BridgeReplacedDuringVersionCheck extends Error {
@@ -12235,7 +12292,7 @@ class BinaryBridge {
12235
12292
  this.timeoutMs = options?.timeoutMs ?? DEFAULT_BRIDGE_TIMEOUT_MS;
12236
12293
  this.hangThreshold = options?.hangThreshold ?? BRIDGE_HANG_TIMEOUT_THRESHOLD;
12237
12294
  this.maxRestarts = options?.maxRestarts ?? 3;
12238
- this.configOverrides = clampSemanticTimeout(configOverrides ?? {}, this.timeoutMs);
12295
+ this.configOverrides = configOverrides ?? {};
12239
12296
  this.minVersion = options?.minVersion;
12240
12297
  this.onVersionMismatch = options?.onVersionMismatch;
12241
12298
  this.onConfigureWarnings = options?.onConfigureWarnings;
@@ -12472,18 +12529,24 @@ class BinaryBridge {
12472
12529
  }
12473
12530
  }
12474
12531
  async deliverConfigureWarnings(configResult, params, options) {
12475
- if (!this.onConfigureWarnings || !Array.isArray(configResult.warnings))
12532
+ if (!this.onConfigureWarnings)
12476
12533
  return;
12477
- if (configResult.warnings.length === 0)
12534
+ const warnings = Array.isArray(configResult.warnings) ? configResult.warnings : [];
12535
+ const configDroppedKeys = coerceConfigureDroppedKeys(configResult.config_dropped_keys);
12536
+ if (warnings.length === 0 && configDroppedKeys.length === 0)
12478
12537
  return;
12479
12538
  const sessionId = typeof params.session_id === "string" ? params.session_id : undefined;
12539
+ const context = {
12540
+ projectRoot: this.cwd,
12541
+ sessionId,
12542
+ client: options?.configureWarningClient ?? (sessionId ? this.configureWarningClients.get(sessionId) : undefined),
12543
+ warnings
12544
+ };
12545
+ if (configDroppedKeys.length > 0) {
12546
+ context.configDroppedKeys = configDroppedKeys;
12547
+ }
12480
12548
  try {
12481
- await this.onConfigureWarnings({
12482
- projectRoot: this.cwd,
12483
- sessionId,
12484
- client: options?.configureWarningClient ?? (sessionId ? this.configureWarningClients.get(sessionId) : undefined),
12485
- warnings: configResult.warnings
12486
- });
12549
+ await this.onConfigureWarnings(context);
12487
12550
  } catch (err) {
12488
12551
  this.warnVia(`configure warning delivery failed: ${err instanceof Error ? err.message : String(err)}`);
12489
12552
  } finally {
@@ -13190,6 +13253,48 @@ function coerceStringArray(value) {
13190
13253
  }
13191
13254
  return [];
13192
13255
  }
13256
+ function coerceTargetParam(value) {
13257
+ if (Array.isArray(value)) {
13258
+ return value.filter((entry) => typeof entry === "string" && entry.length > 0);
13259
+ }
13260
+ if (typeof value === "string") {
13261
+ const trimmed = value.trim();
13262
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
13263
+ try {
13264
+ const parsed = JSON.parse(trimmed);
13265
+ if (Array.isArray(parsed)) {
13266
+ return parsed.filter((entry) => typeof entry === "string" && entry.length > 0);
13267
+ }
13268
+ } catch {}
13269
+ }
13270
+ return value;
13271
+ }
13272
+ return value;
13273
+ }
13274
+ function coerceBoolean(value, defaultValue = false) {
13275
+ if (defaultValue) {
13276
+ if (value === undefined)
13277
+ return true;
13278
+ if (typeof value === "boolean")
13279
+ return value;
13280
+ if (typeof value === "number")
13281
+ return value !== 0;
13282
+ if (typeof value === "string") {
13283
+ const normalized = value.trim().toLowerCase();
13284
+ return normalized !== "false" && normalized !== "0";
13285
+ }
13286
+ return true;
13287
+ }
13288
+ if (typeof value === "boolean")
13289
+ return value;
13290
+ if (typeof value === "number")
13291
+ return value === 1;
13292
+ if (typeof value === "string") {
13293
+ const normalized = value.trim().toLowerCase();
13294
+ return normalized === "true" || normalized === "1";
13295
+ }
13296
+ return false;
13297
+ }
13193
13298
  function coerceOptionalInt(v, paramName, min, max) {
13194
13299
  if (v === undefined || v === null || v === "")
13195
13300
  return;
@@ -13215,10 +13320,43 @@ function isEmptyParam(value) {
13215
13320
  return Object.keys(value).length === 0;
13216
13321
  return false;
13217
13322
  }
13323
+ // ../aft-bridge/dist/config-tiers.js
13324
+ import { existsSync, readFileSync } from "node:fs";
13325
+ import { resolve as resolve2 } from "node:path";
13326
+ function readConfigTiers(opts) {
13327
+ const tiers = [];
13328
+ try {
13329
+ if (existsSync(opts.userConfigPath)) {
13330
+ const doc = readFileSync(opts.userConfigPath, "utf-8");
13331
+ tiers.push({
13332
+ tier: "user",
13333
+ source: resolve2(opts.userConfigPath),
13334
+ doc
13335
+ });
13336
+ }
13337
+ } catch {}
13338
+ try {
13339
+ if (existsSync(opts.projectConfigPath)) {
13340
+ const doc = readFileSync(opts.projectConfigPath, "utf-8");
13341
+ tiers.push({
13342
+ tier: "project",
13343
+ source: resolve2(opts.projectConfigPath),
13344
+ doc
13345
+ });
13346
+ }
13347
+ } catch {}
13348
+ return tiers;
13349
+ }
13350
+ function formatDroppedKeyWarnings(dropped) {
13351
+ if (!dropped || !Array.isArray(dropped)) {
13352
+ return [];
13353
+ }
13354
+ return dropped.map((item) => `Ignoring ${item.key} from ${item.tier} config (${item.reason})`);
13355
+ }
13218
13356
  // ../aft-bridge/dist/downloader.js
13219
13357
  import { spawnSync } from "node:child_process";
13220
13358
  import { createHash, randomUUID } from "node:crypto";
13221
- import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
13359
+ import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync2, mkdirSync, openSync, readFileSync as readFileSync2, renameSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
13222
13360
  import { homedir as homedir4 } from "node:os";
13223
13361
  import { join as join3 } from "node:path";
13224
13362
  import { Readable } from "node:stream";
@@ -13290,7 +13428,7 @@ function getCachedBinaryPath(version) {
13290
13428
  if (!version)
13291
13429
  return null;
13292
13430
  const binaryPath = join3(getCacheDir(), version, getBinaryName());
13293
- return existsSync(binaryPath) ? binaryPath : null;
13431
+ return existsSync2(binaryPath) ? binaryPath : null;
13294
13432
  }
13295
13433
  async function downloadBinary(version) {
13296
13434
  const archMap = PLATFORM_ARCH_MAP[process.platform] ?? {};
@@ -13309,7 +13447,7 @@ async function downloadBinary(version) {
13309
13447
  const versionedCacheDir = join3(getCacheDir(), tag);
13310
13448
  const binaryName = getBinaryName();
13311
13449
  const binaryPath = join3(versionedCacheDir, binaryName);
13312
- if (existsSync(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
13450
+ if (existsSync2(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
13313
13451
  return binaryPath;
13314
13452
  }
13315
13453
  const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
@@ -13323,11 +13461,11 @@ async function downloadBinary(version) {
13323
13461
  let checksumTimeout = null;
13324
13462
  const tmpPath = `${binaryPath}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
13325
13463
  try {
13326
- if (!existsSync(versionedCacheDir)) {
13464
+ if (!existsSync2(versionedCacheDir)) {
13327
13465
  mkdirSync(versionedCacheDir, { recursive: true });
13328
13466
  }
13329
13467
  releaseLock = await acquireDownloadLock(lockPath);
13330
- if (existsSync(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
13468
+ if (existsSync2(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
13331
13469
  return binaryPath;
13332
13470
  }
13333
13471
  binaryController = new AbortController;
@@ -13392,7 +13530,7 @@ async function downloadBinary(version) {
13392
13530
  renameSync(tmpPath, binaryPath);
13393
13531
  }
13394
13532
  try {
13395
- if (existsSync(tmpPath))
13533
+ if (existsSync2(tmpPath))
13396
13534
  unlinkSync(tmpPath);
13397
13535
  } catch {
13398
13536
  warn(`Could not clean up temporary download file ${tmpPath} — it can be removed manually.`);
@@ -13402,7 +13540,7 @@ async function downloadBinary(version) {
13402
13540
  } catch (err) {
13403
13541
  const msg = err instanceof Error ? err.message : String(err);
13404
13542
  error(`Failed to download AFT binary: ${msg}`);
13405
- if (existsSync(tmpPath)) {
13543
+ if (existsSync2(tmpPath)) {
13406
13544
  try {
13407
13545
  unlinkSync(tmpPath);
13408
13546
  } catch {}
@@ -13446,7 +13584,7 @@ async function acquireDownloadLock(lockPath) {
13446
13584
  closeSync(fd);
13447
13585
  } catch {}
13448
13586
  try {
13449
- if (readFileSync(lockPath, "utf-8") === owner) {
13587
+ if (readFileSync2(lockPath, "utf-8") === owner) {
13450
13588
  rmSync(lockPath, { force: true });
13451
13589
  }
13452
13590
  } catch {}
@@ -13467,7 +13605,7 @@ async function acquireDownloadLock(lockPath) {
13467
13605
  if (Date.now() - startedAt > DOWNLOAD_LOCK_TIMEOUT_MS) {
13468
13606
  throw new Error(`Timed out waiting for download lock: ${lockPath}`);
13469
13607
  }
13470
- await new Promise((resolve2) => setTimeout(resolve2, 100));
13608
+ await new Promise((resolve3) => setTimeout(resolve3, 100));
13471
13609
  }
13472
13610
  }
13473
13611
  }
@@ -13571,20 +13709,71 @@ function stripJsoncSymbols(value) {
13571
13709
  }
13572
13710
  // ../aft-bridge/dist/migration.js
13573
13711
  import { spawnSync as spawnSync2 } from "node:child_process";
13574
- import { existsSync as existsSync4, mkdirSync as mkdirSync4 } from "node:fs";
13575
- import { homedir as homedir6, tmpdir } from "node:os";
13576
- import { dirname as dirname2, join as join6 } from "node:path";
13712
+ import { closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync4, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
13713
+ import { homedir as homedir7, tmpdir } from "node:os";
13714
+ import { basename, dirname as dirname2, join as join6, resolve as resolve4 } from "node:path";
13577
13715
 
13578
13716
  // ../aft-bridge/dist/paths.js
13579
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync } from "node:fs";
13580
- import { dirname, join as join4 } from "node:path";
13717
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync } from "node:fs";
13718
+ import { homedir as homedir5 } from "node:os";
13719
+ import { dirname, isAbsolute as isAbsolute2, join as join4, resolve as resolve3 } from "node:path";
13720
+ function homeDir() {
13721
+ if (process.platform === "win32")
13722
+ return process.env.USERPROFILE || process.env.HOME || homedir5();
13723
+ return process.env.HOME || homedir5();
13724
+ }
13725
+ function configHome() {
13726
+ const xdg = process.env.XDG_CONFIG_HOME;
13727
+ if (xdg && isAbsolute2(xdg))
13728
+ return xdg;
13729
+ return join4(homeDir(), ".config");
13730
+ }
13731
+ function legacyOpenCodeConfigDir() {
13732
+ const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
13733
+ if (envDir)
13734
+ return resolve3(envDir);
13735
+ return join4(configHome(), "opencode");
13736
+ }
13737
+ function legacyPiAgentDir() {
13738
+ return join4(homeDir(), ".pi", "agent");
13739
+ }
13740
+ function legacySources(basePath, label, harness) {
13741
+ return [
13742
+ { path: `${basePath}.jsonc`, label: `${label} aft.jsonc`, harness },
13743
+ { path: `${basePath}.json`, label: `${label} aft.json`, harness }
13744
+ ];
13745
+ }
13746
+ function resolveCortexKitUserConfigPath() {
13747
+ return join4(configHome(), "cortexkit", "aft.jsonc");
13748
+ }
13749
+ function resolveCortexKitProjectConfigPath(projectDirectory) {
13750
+ return join4(projectDirectory, ".cortexkit", "aft.jsonc");
13751
+ }
13752
+ function resolveCortexKitConfigPaths(projectDirectory) {
13753
+ return {
13754
+ userConfigPath: resolveCortexKitUserConfigPath(),
13755
+ projectConfigPath: resolveCortexKitProjectConfigPath(projectDirectory)
13756
+ };
13757
+ }
13758
+ function resolveLegacyAftConfigSources(projectDirectory) {
13759
+ return {
13760
+ user: [
13761
+ ...legacySources(join4(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
13762
+ ...legacySources(join4(legacyPiAgentDir(), "aft"), "Pi user", "pi")
13763
+ ],
13764
+ project: [
13765
+ ...legacySources(join4(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
13766
+ ...legacySources(join4(projectDirectory, ".pi", "aft"), "Pi project", "pi")
13767
+ ]
13768
+ };
13769
+ }
13581
13770
  function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
13582
13771
  return join4(storageRoot, harness, ...segments);
13583
13772
  }
13584
13773
  function repairRootScopedStorageFile(storageRoot, harness, fileName) {
13585
13774
  const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
13586
13775
  const rootPath = join4(storageRoot, fileName);
13587
- if (existsSync2(harnessPath) || !existsSync2(rootPath))
13776
+ if (existsSync3(harnessPath) || !existsSync3(rootPath))
13588
13777
  return harnessPath;
13589
13778
  try {
13590
13779
  mkdirSync2(dirname(harnessPath), { recursive: true });
@@ -13598,8 +13787,8 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
13598
13787
  const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
13599
13788
  let lastVersion = "";
13600
13789
  try {
13601
- if (existsSync2(versionFile)) {
13602
- lastVersion = readFileSync2(versionFile, "utf-8").trim();
13790
+ if (existsSync3(versionFile)) {
13791
+ lastVersion = readFileSync3(versionFile, "utf-8").trim();
13603
13792
  }
13604
13793
  } catch {
13605
13794
  return false;
@@ -13627,9 +13816,9 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
13627
13816
 
13628
13817
  // ../aft-bridge/dist/resolver.js
13629
13818
  import { execSync } from "node:child_process";
13630
- import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
13819
+ import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
13631
13820
  import { createRequire as createRequire2 } from "node:module";
13632
- import { homedir as homedir5 } from "node:os";
13821
+ import { homedir as homedir6 } from "node:os";
13633
13822
  import { join as join5 } from "node:path";
13634
13823
  var ensureBinaryForResolver = ensureBinary;
13635
13824
  function copyToVersionedCache(npmBinaryPath, knownVersion) {
@@ -13642,7 +13831,7 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
13642
13831
  const versionedDir = join5(cacheDir, tag);
13643
13832
  const ext = process.platform === "win32" ? ".exe" : "";
13644
13833
  const cachedPath = join5(versionedDir, `aft${ext}`);
13645
- if (existsSync3(cachedPath)) {
13834
+ if (existsSync4(cachedPath)) {
13646
13835
  const cachedVersion = readBinaryVersion(cachedPath);
13647
13836
  if (cachedVersion === version)
13648
13837
  return cachedPath;
@@ -13654,7 +13843,7 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
13654
13843
  if (process.platform !== "win32") {
13655
13844
  chmodSync2(tmpPath, 493);
13656
13845
  }
13657
- if (process.platform === "win32" && existsSync3(cachedPath)) {
13846
+ if (process.platform === "win32" && existsSync4(cachedPath)) {
13658
13847
  try {
13659
13848
  unlinkSync2(cachedPath);
13660
13849
  } catch {}
@@ -13671,7 +13860,7 @@ function normalizeBareVersion(version) {
13671
13860
  return version.startsWith("v") ? version.slice(1) : version;
13672
13861
  }
13673
13862
  function homeDirFromEnv(env) {
13674
- return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir5();
13863
+ return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir6();
13675
13864
  }
13676
13865
  function cacheDirFromEnv(env) {
13677
13866
  if (process.platform === "win32") {
@@ -13683,7 +13872,7 @@ function cacheDirFromEnv(env) {
13683
13872
  }
13684
13873
  function cachedBinaryPathFromEnv(version, env, ext) {
13685
13874
  const binaryPath = join5(cacheDirFromEnv(env), version, `aft${ext}`);
13686
- return existsSync3(binaryPath) ? binaryPath : null;
13875
+ return existsSync4(binaryPath) ? binaryPath : null;
13687
13876
  }
13688
13877
  function isExpectedCachedBinary2(binaryPath, expectedVersion) {
13689
13878
  const expected = normalizeBareVersion(expectedVersion);
@@ -13772,7 +13961,7 @@ function findBinarySync(expectedVersion) {
13772
13961
  const packageBin = `@cortexkit/aft-${key}/bin/aft${ext}`;
13773
13962
  const req = createRequire2(import.meta.url);
13774
13963
  const resolved = req.resolve(packageBin);
13775
- if (existsSync3(resolved)) {
13964
+ if (existsSync4(resolved)) {
13776
13965
  const npmVersion = readBinaryVersion(resolved);
13777
13966
  if (npmVersion === null) {
13778
13967
  warn(`npm platform package binary at ${resolved} did not report a version; skipping (continuing to PATH lookup)`);
@@ -13802,7 +13991,7 @@ function findBinarySync(expectedVersion) {
13802
13991
  }
13803
13992
  } catch {}
13804
13993
  const cargoPath = join5(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
13805
- if (existsSync3(cargoPath)) {
13994
+ if (existsSync4(cargoPath)) {
13806
13995
  const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
13807
13996
  if (usable)
13808
13997
  return usable;
@@ -13847,23 +14036,343 @@ function dataHome() {
13847
14036
  if (process.env.XDG_DATA_HOME)
13848
14037
  return process.env.XDG_DATA_HOME;
13849
14038
  if (process.platform === "win32") {
13850
- return process.env.LOCALAPPDATA || process.env.APPDATA || join6(homeDir(), "AppData", "Local");
14039
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join6(homeDir2(), "AppData", "Local");
13851
14040
  }
13852
- return join6(homeDir(), ".local", "share");
14041
+ return join6(homeDir2(), ".local", "share");
13853
14042
  }
13854
- function homeDir() {
14043
+ function homeDir2() {
13855
14044
  if (process.platform === "win32")
13856
- return process.env.USERPROFILE || process.env.HOME || homedir6();
13857
- return process.env.HOME || homedir6();
14045
+ return process.env.USERPROFILE || process.env.HOME || homedir7();
14046
+ return process.env.HOME || homedir7();
13858
14047
  }
13859
14048
  function resolveLegacyStorageRoot(harness) {
13860
14049
  if (harness === "pi")
13861
- return join6(homeDir(), ".pi", "agent", "aft");
14050
+ return join6(homeDir2(), ".pi", "agent", "aft");
13862
14051
  return join6(dataHome(), "opencode", "storage", "plugin", "aft");
13863
14052
  }
13864
14053
  function resolveCortexKitStorageRoot() {
13865
14054
  return join6(dataHome(), "cortexkit", "aft");
13866
14055
  }
14056
+ function stripJsoncForParse(input) {
14057
+ let out = "";
14058
+ let inString = false;
14059
+ let escaped = false;
14060
+ for (let i = 0;i < input.length; i++) {
14061
+ const ch = input[i];
14062
+ const next = input[i + 1];
14063
+ if (inString) {
14064
+ out += ch;
14065
+ if (escaped) {
14066
+ escaped = false;
14067
+ } else if (ch === "\\") {
14068
+ escaped = true;
14069
+ } else if (ch === '"') {
14070
+ inString = false;
14071
+ }
14072
+ continue;
14073
+ }
14074
+ if (ch === '"') {
14075
+ inString = true;
14076
+ out += ch;
14077
+ continue;
14078
+ }
14079
+ if (ch === "/" && next === "/") {
14080
+ while (i < input.length && input[i] !== `
14081
+ `)
14082
+ i++;
14083
+ out += `
14084
+ `;
14085
+ continue;
14086
+ }
14087
+ if (ch === "/" && next === "*") {
14088
+ i += 2;
14089
+ while (i < input.length && !(input[i] === "*" && input[i + 1] === "/"))
14090
+ i++;
14091
+ i++;
14092
+ out += " ";
14093
+ continue;
14094
+ }
14095
+ out += ch;
14096
+ }
14097
+ let withoutTrailingCommas = "";
14098
+ inString = false;
14099
+ escaped = false;
14100
+ for (let i = 0;i < out.length; i++) {
14101
+ const ch = out[i];
14102
+ if (inString) {
14103
+ withoutTrailingCommas += ch;
14104
+ if (escaped) {
14105
+ escaped = false;
14106
+ } else if (ch === "\\") {
14107
+ escaped = true;
14108
+ } else if (ch === '"') {
14109
+ inString = false;
14110
+ }
14111
+ continue;
14112
+ }
14113
+ if (ch === '"') {
14114
+ inString = true;
14115
+ withoutTrailingCommas += ch;
14116
+ continue;
14117
+ }
14118
+ if (ch === ",") {
14119
+ let j = i + 1;
14120
+ while (j < out.length && /\s/.test(out[j]))
14121
+ j++;
14122
+ if (out[j] === "}" || out[j] === "]")
14123
+ continue;
14124
+ }
14125
+ withoutTrailingCommas += ch;
14126
+ }
14127
+ return withoutTrailingCommas;
14128
+ }
14129
+ function sortJson(value) {
14130
+ if (Array.isArray(value))
14131
+ return value.map(sortJson);
14132
+ if (value && typeof value === "object") {
14133
+ const sorted = {};
14134
+ for (const key of Object.keys(value).sort()) {
14135
+ sorted[key] = sortJson(value[key]);
14136
+ }
14137
+ return sorted;
14138
+ }
14139
+ return value;
14140
+ }
14141
+ function normalizedJsoncSemantics(content) {
14142
+ return JSON.stringify(sortJson(JSON.parse(stripJsoncForParse(content))));
14143
+ }
14144
+ function fileSemanticsMatch(a, b) {
14145
+ try {
14146
+ return normalizedJsoncSemantics(a) === normalizedJsoncSemantics(b);
14147
+ } catch {
14148
+ return a === b;
14149
+ }
14150
+ }
14151
+ function sleepSync(ms) {
14152
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
14153
+ }
14154
+ function acquireConfigMigrationLock(lockDir) {
14155
+ const deadline = Date.now() + 30000;
14156
+ while (true) {
14157
+ try {
14158
+ mkdirSync4(lockDir, { recursive: false });
14159
+ return () => {
14160
+ try {
14161
+ rmSync2(lockDir, { recursive: true, force: true });
14162
+ } catch {}
14163
+ };
14164
+ } catch (err) {
14165
+ const code = err?.code;
14166
+ if (code !== "EEXIST")
14167
+ throw err;
14168
+ try {
14169
+ const ageMs = Date.now() - statSync2(lockDir).mtimeMs;
14170
+ if (ageMs > 60000) {
14171
+ rmSync2(lockDir, { recursive: true, force: true });
14172
+ continue;
14173
+ }
14174
+ } catch {}
14175
+ if (Date.now() >= deadline) {
14176
+ throw new Error(`timed out waiting for config migration lock ${lockDir}`);
14177
+ }
14178
+ sleepSync(25);
14179
+ }
14180
+ }
14181
+ }
14182
+ function atomicCopyConfigFile(sourcePath, targetPath) {
14183
+ mkdirSync4(dirname2(targetPath), { recursive: true });
14184
+ const tmpPath = join6(dirname2(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
14185
+ let fd = null;
14186
+ try {
14187
+ fd = openSync3(tmpPath, "wx", 384);
14188
+ writeFileSync2(fd, readFileSync4(sourcePath));
14189
+ closeSync3(fd);
14190
+ fd = null;
14191
+ renameSync4(tmpPath, targetPath);
14192
+ } catch (err) {
14193
+ if (fd !== null) {
14194
+ try {
14195
+ closeSync3(fd);
14196
+ } catch {}
14197
+ }
14198
+ try {
14199
+ unlinkSync3(tmpPath);
14200
+ } catch {}
14201
+ throw err;
14202
+ }
14203
+ }
14204
+ function atomicWriteConfigFile(targetPath, content) {
14205
+ mkdirSync4(dirname2(targetPath), { recursive: true });
14206
+ const tmpPath = join6(dirname2(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
14207
+ let fd = null;
14208
+ try {
14209
+ fd = openSync3(tmpPath, "wx", 384);
14210
+ writeFileSync2(fd, content);
14211
+ closeSync3(fd);
14212
+ fd = null;
14213
+ renameSync4(tmpPath, targetPath);
14214
+ } catch (err) {
14215
+ if (fd !== null) {
14216
+ try {
14217
+ closeSync3(fd);
14218
+ } catch {}
14219
+ }
14220
+ try {
14221
+ unlinkSync3(tmpPath);
14222
+ } catch {}
14223
+ throw err;
14224
+ }
14225
+ }
14226
+ var MOVED_MARKER_SUFFIX = ".MOVED_READPLEASE";
14227
+ function nonClobberingSidecarPath(desiredPath) {
14228
+ if (!existsSync5(desiredPath))
14229
+ return desiredPath;
14230
+ for (let index = 1;index < Number.MAX_SAFE_INTEGER; index++) {
14231
+ const candidate = `${desiredPath}.${index}`;
14232
+ if (!existsSync5(candidate))
14233
+ return candidate;
14234
+ }
14235
+ throw new Error(`could not find available preservation sidecar path for ${desiredPath}`);
14236
+ }
14237
+ function movedMarkerContent(targetPath, originalName, originalContent) {
14238
+ const header = [
14239
+ "// AFT configuration moved.",
14240
+ "//",
14241
+ "// AFT now reads its configuration from one shared CortexKit location",
14242
+ "// instead of a per-agent path. The settings that were in this file have",
14243
+ "// been moved to:",
14244
+ "//",
14245
+ `// ${targetPath}`,
14246
+ "//",
14247
+ "// Edit that file to change AFT settings. This location is no longer read",
14248
+ "// by AFT.",
14249
+ "//",
14250
+ `// To undo, rename this file back to "${originalName}" (and remove the`,
14251
+ "// CortexKit copy above if you want this location to take precedence).",
14252
+ "//",
14253
+ "// Your original settings are preserved below for reference.",
14254
+ "",
14255
+ ""
14256
+ ].join(`
14257
+ `);
14258
+ return `${header}${originalContent}`;
14259
+ }
14260
+ function markLegacySourcesMovedAside(sources, targetPath, logger) {
14261
+ const warnings = [];
14262
+ const info = logger?.info ?? logger?.log;
14263
+ for (const source of sources) {
14264
+ const desiredMarkerPath = `${source.path}${MOVED_MARKER_SUFFIX}`;
14265
+ const markerPath = nonClobberingSidecarPath(desiredMarkerPath);
14266
+ try {
14267
+ const original = readFileSync4(source.path, "utf-8");
14268
+ if (markerPath !== desiredMarkerPath) {
14269
+ logger?.warn?.(`Preserving existing legacy AFT marker ${desiredMarkerPath}; writing new marker to ${markerPath}`);
14270
+ }
14271
+ atomicWriteConfigFile(markerPath, movedMarkerContent(targetPath, basename(source.path), original));
14272
+ unlinkSync3(source.path);
14273
+ info?.(`Moved legacy AFT config ${source.path} aside to ${markerPath}; AFT now reads ${targetPath}`);
14274
+ } catch (err) {
14275
+ const msg = err instanceof Error ? err.message : String(err);
14276
+ warnings.push(`AFT could not move legacy config ${source.path} aside (${msg}); it is now stale and ignored. Delete it manually — AFT reads ${targetPath}.`);
14277
+ logger?.warn?.(`Could not move legacy AFT config ${source.path} aside (${msg}); AFT reads ${targetPath}`);
14278
+ }
14279
+ }
14280
+ return warnings;
14281
+ }
14282
+ var PRESERVED_OLD_SUFFIX = "_OLD";
14283
+ function preservedOldContent(losingHarness, winningHarness, targetPath, originalContent) {
14284
+ const winnerLine = winningHarness ? `// configs differed, so ${winningHarness}'s config won (first harness to run the` : "// configs differed, so the config that was migrated first won and is the";
14285
+ const header = [
14286
+ `// AFT config from ${losingHarness} — preserved, NOT read.`,
14287
+ "//",
14288
+ "// AFT now reads one shared config for all harnesses. Your OpenCode and Pi",
14289
+ winnerLine,
14290
+ winningHarness ? "// migration) and is now the active config at:" : "// active config at:",
14291
+ "//",
14292
+ `// ${targetPath}`,
14293
+ "//",
14294
+ `// This file holds ${losingHarness}'s previous settings. Merge anything you`,
14295
+ "// want to keep into the active config above, then delete this file. AFT does",
14296
+ "// not read this path.",
14297
+ "",
14298
+ ""
14299
+ ].join(`
14300
+ `);
14301
+ return `${header}${originalContent}`;
14302
+ }
14303
+ function preserveDifferingSourceAsOld(source, winningHarness, targetPath, logger) {
14304
+ const losingHarness = source.harness ?? "pi";
14305
+ const desiredOldPath = `${targetPath}.${losingHarness}${PRESERVED_OLD_SUFFIX}`;
14306
+ const oldPath = nonClobberingSidecarPath(desiredOldPath);
14307
+ try {
14308
+ if (oldPath !== desiredOldPath) {
14309
+ logger?.warn?.(`Preserving existing ${losingHarness} config sidecar ${desiredOldPath}; writing new preserved config to ${oldPath}`);
14310
+ }
14311
+ atomicWriteConfigFile(oldPath, preservedOldContent(losingHarness, winningHarness, targetPath, source.content));
14312
+ } catch (err) {
14313
+ const msg = err instanceof Error ? err.message : String(err);
14314
+ logger?.warn?.(`Could not preserve ${losingHarness} config as ${oldPath} (${msg})`);
14315
+ }
14316
+ const usingDesc = winningHarness ? `${winningHarness}'s config` : "the existing shared config";
14317
+ return `AFT found different OpenCode and Pi configs during config unification. ` + `Using ${usingDesc} at ${targetPath}; preserved ${losingHarness}'s previous ` + `config at ${oldPath} — merge any settings you want to keep, then delete it.`;
14318
+ }
14319
+ function visibleConfigMigrationWarning(scope, targetPath, paths, reason) {
14320
+ const uniquePaths = [...new Set([targetPath, ...paths])];
14321
+ return `AFT ${scope} config migration refused: ${reason}. ` + `Legacy and CortexKit config paths collapse to one file, but AFT will not overwrite or merge them automatically. ` + `Please consolidate manually into ${targetPath}. Paths: ${uniquePaths.join(" ; ")}`;
14322
+ }
14323
+ function migrateAftConfigFile(opts) {
14324
+ const warnings = [];
14325
+ const resolvedTarget = resolve4(opts.targetPath);
14326
+ const existingSources = opts.legacySources.filter((source) => existsSync5(source.path) && resolve4(source.path) !== resolvedTarget);
14327
+ const info = opts.logger?.info ?? opts.logger?.log;
14328
+ if (existingSources.length === 0) {
14329
+ return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
14330
+ }
14331
+ mkdirSync4(dirname2(opts.targetPath), { recursive: true });
14332
+ const release = acquireConfigMigrationLock(`${opts.targetPath}.lock`);
14333
+ try {
14334
+ const sources = existingSources.map((source) => ({
14335
+ ...source,
14336
+ content: readFileSync4(source.path, "utf-8")
14337
+ }));
14338
+ if (existsSync5(opts.targetPath)) {
14339
+ const targetContent = readFileSync4(opts.targetPath, "utf-8");
14340
+ for (const source of sources) {
14341
+ if (fileSemanticsMatch(source.content, targetContent))
14342
+ continue;
14343
+ warnings.push(preserveDifferingSourceAsOld(source, undefined, opts.targetPath, opts.logger));
14344
+ }
14345
+ info?.(`AFT ${opts.scope} config already present at ${opts.targetPath}; reconciled ${sources.length} legacy source(s)`);
14346
+ warnings.push(...markLegacySourcesMovedAside(sources, opts.targetPath, opts.logger));
14347
+ return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
14348
+ }
14349
+ const winner = (opts.operatingHarness ? sources.find((source) => source.harness === opts.operatingHarness) : undefined) ?? sources[0];
14350
+ atomicCopyConfigFile(winner.path, opts.targetPath);
14351
+ info?.(`Migrated AFT ${opts.scope} config from ${winner.path} to ${opts.targetPath}`);
14352
+ for (const source of sources) {
14353
+ if (source.path === winner.path)
14354
+ continue;
14355
+ if (fileSemanticsMatch(source.content, winner.content))
14356
+ continue;
14357
+ warnings.push(preserveDifferingSourceAsOld(source, winner.harness, opts.targetPath, opts.logger));
14358
+ }
14359
+ warnings.push(...markLegacySourcesMovedAside(sources, opts.targetPath, opts.logger));
14360
+ return {
14361
+ migrated: true,
14362
+ conflict: false,
14363
+ sourcePath: winner.path,
14364
+ targetPath: opts.targetPath,
14365
+ warnings
14366
+ };
14367
+ } catch (err) {
14368
+ const message = visibleConfigMigrationWarning(opts.scope, opts.targetPath, existingSources.map((source) => source.path), `migration failed (${err instanceof Error ? err.message : String(err)})`);
14369
+ warnings.push(message);
14370
+ opts.logger?.warn?.(message);
14371
+ return { migrated: false, conflict: true, targetPath: opts.targetPath, warnings };
14372
+ } finally {
14373
+ release();
14374
+ }
14375
+ }
13867
14376
  function tail(value) {
13868
14377
  if (!value)
13869
14378
  return "";
@@ -13891,11 +14400,11 @@ async function ensureStorageMigrated(opts) {
13891
14400
  const newRoot = resolveCortexKitStorageRoot();
13892
14401
  const targetMarker = resolveHarnessStoragePath(newRoot, opts.harness, TARGET_MARKER);
13893
14402
  const info = opts.logger?.info ?? opts.logger?.log;
13894
- if (existsSync4(targetMarker)) {
14403
+ if (existsSync5(targetMarker)) {
13895
14404
  info?.(`AFT storage already migrated for ${opts.harness}; using ${newRoot}`);
13896
14405
  return;
13897
14406
  }
13898
- if (!existsSync4(legacyRoot)) {
14407
+ if (!existsSync5(legacyRoot)) {
13899
14408
  info?.(`AFT storage migration skipped for ${opts.harness}: no legacy data at ${legacyRoot}; ` + `using ${newRoot} for fresh install`);
13900
14409
  return;
13901
14410
  }
@@ -13943,14 +14452,14 @@ async function ensureStorageMigrated(opts) {
13943
14452
  throw new Error(`AFT storage migration failed (${detail}). ` + `Harness: ${opts.harness}. Legacy: ${legacyRoot}. Target: ${newRoot}. ` + `See log: ${logPath}. ` + `Plugin load aborted to prevent legacy/new state divergence.` + (stderrTail ? ` Stderr tail: ${stderrTail}` : "") + (stdoutTail ? ` Stdout tail: ${stdoutTail}` : ""));
13944
14453
  }
13945
14454
  // ../aft-bridge/dist/npm-resolver.js
13946
- import { readdirSync, statSync as statSync2 } from "node:fs";
13947
- import { homedir as homedir7 } from "node:os";
13948
- import { delimiter, dirname as dirname3, isAbsolute as isAbsolute2, join as join7 } from "node:path";
14455
+ import { readdirSync, statSync as statSync3 } from "node:fs";
14456
+ import { homedir as homedir8 } from "node:os";
14457
+ import { delimiter, dirname as dirname3, isAbsolute as isAbsolute3, join as join7 } from "node:path";
13949
14458
  function defaultDeps() {
13950
14459
  return {
13951
14460
  platform: process.platform,
13952
14461
  env: process.env,
13953
- home: homedir7(),
14462
+ home: homedir8(),
13954
14463
  execPath: process.execPath
13955
14464
  };
13956
14465
  }
@@ -13959,7 +14468,7 @@ function npmBinaryName(platform) {
13959
14468
  }
13960
14469
  function isFile(p) {
13961
14470
  try {
13962
- return statSync2(p).isFile();
14471
+ return statSync3(p).isFile();
13963
14472
  } catch {
13964
14473
  return false;
13965
14474
  }
@@ -13969,7 +14478,7 @@ function npmFromPath(deps) {
13969
14478
  const raw = deps.env.PATH ?? deps.env.Path ?? "";
13970
14479
  for (const entry of raw.split(delimiter)) {
13971
14480
  const dir = entry.trim().replace(/^"|"$/g, "");
13972
- if (!dir || !isAbsolute2(dir))
14481
+ if (!dir || !isAbsolute3(dir))
13973
14482
  continue;
13974
14483
  if (isFile(join7(dir, name)))
13975
14484
  return dir;
@@ -14059,8 +14568,8 @@ function npmSpawnEnv(resolved, baseEnv = process.env) {
14059
14568
  // ../aft-bridge/dist/onnx-runtime.js
14060
14569
  import { execFileSync } from "node:child_process";
14061
14570
  import { createHash as createHash2 } from "node:crypto";
14062
- import { chmodSync as chmodSync3, closeSync as closeSync3, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync5, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync3, readlinkSync, realpathSync, rmSync as rmSync2, statSync as statSync3, symlinkSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
14063
- import { basename, dirname as dirname4, isAbsolute as isAbsolute3, join as join8, relative as relative2, resolve as resolve2, win32 } from "node:path";
14571
+ import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync2, readFileSync as readFileSync5, readlinkSync, realpathSync, rmSync as rmSync3, statSync as statSync4, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
14572
+ import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join8, relative as relative2, resolve as resolve5, win32 } from "node:path";
14064
14573
  import { Readable as Readable2 } from "node:stream";
14065
14574
  import { pipeline as pipeline2 } from "node:stream/promises";
14066
14575
  var ORT_VERSION = "1.24.4";
@@ -14127,7 +14636,7 @@ async function ensureOnnxRuntime(storageDir) {
14127
14636
  const libName = info?.libName ?? "libonnxruntime.dylib";
14128
14637
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
14129
14638
  const libPath = join8(resolvedOrtDir, libName);
14130
- if (existsSync5(libPath)) {
14639
+ if (existsSync6(libPath)) {
14131
14640
  const meta = readOnnxInstalledMeta(ortVersionDir);
14132
14641
  if (meta?.sha256) {
14133
14642
  try {
@@ -14189,7 +14698,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
14189
14698
  abandoned = true;
14190
14699
  } else {
14191
14700
  try {
14192
- const ageMs = Date.now() - statSync3(stagingDir).mtimeMs;
14701
+ const ageMs = Date.now() - statSync4(stagingDir).mtimeMs;
14193
14702
  abandoned = ageMs > STALE_LOCK_MS;
14194
14703
  } catch {
14195
14704
  abandoned = true;
@@ -14204,7 +14713,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
14204
14713
  if (abandoned) {
14205
14714
  log(`[onnx] removing abandoned staging dir ${stagingDir}`);
14206
14715
  try {
14207
- rmSync2(stagingDir, { recursive: true, force: true });
14716
+ rmSync3(stagingDir, { recursive: true, force: true });
14208
14717
  } catch (err) {
14209
14718
  warn(`[onnx] failed to remove ${stagingDir}: ${err}`);
14210
14719
  }
@@ -14214,9 +14723,9 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
14214
14723
  }
14215
14724
  function cleanupIncompleteTargetIfUnowned(ortDir) {
14216
14725
  try {
14217
- if (existsSync5(ortDir) && !existsSync5(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
14726
+ if (existsSync6(ortDir) && !existsSync6(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
14218
14727
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
14219
- rmSync2(ortDir, { recursive: true, force: true });
14728
+ rmSync3(ortDir, { recursive: true, force: true });
14220
14729
  }
14221
14730
  } catch (err) {
14222
14731
  warn(`[onnx] failed to sweep ${ortDir}: ${err}`);
@@ -14226,7 +14735,7 @@ var REQUIRED_ORT_MAJOR = 1;
14226
14735
  var REQUIRED_ORT_MIN_MINOR = 20;
14227
14736
  var INVALID_ORT_VERSION = "<invalid>";
14228
14737
  function parseOnnxVersionFromPath(value) {
14229
- const name = basename(value);
14738
+ const name = basename2(value);
14230
14739
  const semverish = name.match(/(?:^|[._-])(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?)(?:\.(?:dylib|dll))?$/);
14231
14740
  if (semverish)
14232
14741
  return semverish[1].split(/[-+]/, 1)[0];
@@ -14243,7 +14752,7 @@ function parseOnnxVersionFromDirectoryPath(value) {
14243
14752
  }
14244
14753
  function isPathInsideRoot(root, candidate) {
14245
14754
  const rel = relative2(root, candidate);
14246
- return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute3(rel) && !win32.isAbsolute(rel);
14755
+ return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute4(rel) && !win32.isAbsolute(rel);
14247
14756
  }
14248
14757
  function detectOnnxVersion(libDir, libName) {
14249
14758
  try {
@@ -14259,7 +14768,7 @@ function detectOnnxVersion(libDir, libName) {
14259
14768
  return version;
14260
14769
  }
14261
14770
  const base = join8(libDir, libName);
14262
- if (existsSync5(base)) {
14771
+ if (existsSync6(base)) {
14263
14772
  try {
14264
14773
  const real = realpathSync(base);
14265
14774
  const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
@@ -14294,7 +14803,7 @@ function pathEntriesForPlatform() {
14294
14803
  return pathEnvValue().split(delimiter2).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
14295
14804
  if (!entry || entry === "." || entry.includes("\x00"))
14296
14805
  return false;
14297
- return isAbsolute3(entry) || win32.isAbsolute(entry);
14806
+ return isAbsolute4(entry) || win32.isAbsolute(entry);
14298
14807
  });
14299
14808
  }
14300
14809
  function directoryContainsLibrary(dir, libName) {
@@ -14310,10 +14819,10 @@ function directoryContainsLibrary(dir, libName) {
14310
14819
  }
14311
14820
  }
14312
14821
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
14313
- if (existsSync5(join8(ortVersionDir, libName)))
14822
+ if (existsSync6(join8(ortVersionDir, libName)))
14314
14823
  return ortVersionDir;
14315
14824
  const libSubdir = join8(ortVersionDir, "lib");
14316
- if (existsSync5(join8(libSubdir, libName)))
14825
+ if (existsSync6(join8(libSubdir, libName)))
14317
14826
  return libSubdir;
14318
14827
  return ortVersionDir;
14319
14828
  }
@@ -14334,7 +14843,7 @@ function findSystemOnnxRuntime(libName) {
14334
14843
  if (!userProfile)
14335
14844
  return nugetPaths;
14336
14845
  const nugetPackageDir = join8(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
14337
- if (!existsSync5(nugetPackageDir))
14846
+ if (!existsSync6(nugetPackageDir))
14338
14847
  return nugetPaths;
14339
14848
  try {
14340
14849
  for (const entry of readdirSync2(nugetPackageDir, { withFileTypes: true })) {
@@ -14354,7 +14863,7 @@ function findSystemOnnxRuntime(libName) {
14354
14863
  const normalizeCase = process.platform === "win32" || process.platform === "darwin";
14355
14864
  const seen = new Set;
14356
14865
  const uniquePaths = searchPaths.filter((p) => {
14357
- let key = resolve2(p).replace(/[/\\]+$/, "");
14866
+ let key = resolve5(p).replace(/[/\\]+$/, "");
14358
14867
  if (normalizeCase)
14359
14868
  key = key.toLowerCase();
14360
14869
  if (seen.has(key))
@@ -14368,7 +14877,7 @@ function findSystemOnnxRuntime(libName) {
14368
14877
  if (process.platform === "win32") {
14369
14878
  if (!directoryContainsLibrary(dir, libName))
14370
14879
  continue;
14371
- } else if (!existsSync5(libPath)) {
14880
+ } else if (!existsSync6(libPath)) {
14372
14881
  continue;
14373
14882
  }
14374
14883
  const version = detectOnnxVersion(dir, libName);
@@ -14417,7 +14926,7 @@ async function downloadFileWithCap(url, destPath) {
14417
14926
  await pipeline2(nodeStream, createWriteStream2(destPath), { signal: controller.signal });
14418
14927
  } catch (err) {
14419
14928
  try {
14420
- unlinkSync3(destPath);
14929
+ unlinkSync4(destPath);
14421
14930
  } catch {}
14422
14931
  throw err;
14423
14932
  } finally {
@@ -14434,15 +14943,15 @@ function validateExtractedTree(stagingRoot) {
14434
14943
  const lst = lstatSync(fullPath);
14435
14944
  if (lst.isSymbolicLink()) {
14436
14945
  const linkTarget = readlinkSync(fullPath);
14437
- const resolvedTarget = resolve2(dirname4(fullPath), linkTarget);
14946
+ const resolvedTarget = resolve5(dirname4(fullPath), linkTarget);
14438
14947
  const rel2 = relative2(realRoot, resolvedTarget);
14439
- if (rel2.startsWith("..") || isAbsolute3(rel2) || win32.isAbsolute(rel2)) {
14948
+ if (rel2.startsWith("..") || isAbsolute4(rel2) || win32.isAbsolute(rel2)) {
14440
14949
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
14441
14950
  }
14442
14951
  continue;
14443
14952
  }
14444
14953
  const rel = relative2(realRoot, fullPath);
14445
- if (rel.startsWith("..") || isAbsolute3(rel) || win32.isAbsolute(rel)) {
14954
+ if (rel.startsWith("..") || isAbsolute4(rel) || win32.isAbsolute(rel)) {
14446
14955
  throw new Error(`extracted entry ${fullPath} escapes staging root`);
14447
14956
  }
14448
14957
  if (lst.isDirectory()) {
@@ -14478,11 +14987,11 @@ async function downloadOnnxRuntime(info, targetDir) {
14478
14987
  await extractZipArchive(archivePath, tmpDir);
14479
14988
  }
14480
14989
  try {
14481
- unlinkSync3(archivePath);
14990
+ unlinkSync4(archivePath);
14482
14991
  } catch {}
14483
14992
  validateExtractedTree(tmpDir);
14484
14993
  const extractedDir = join8(tmpDir, info.assetName, "lib");
14485
- if (!existsSync5(extractedDir)) {
14994
+ if (!existsSync6(extractedDir)) {
14486
14995
  throw new Error(`Expected directory not found: ${extractedDir}`);
14487
14996
  }
14488
14997
  mkdirSync5(targetDir, { recursive: true });
@@ -14513,16 +15022,16 @@ async function downloadOnnxRuntime(info, targetDir) {
14513
15022
  warn(`Could not hash newly-installed ONNX library at ${libPath}: ${err}`);
14514
15023
  }
14515
15024
  writeOnnxInstalledMeta(targetDir, ORT_VERSION, libHash, archiveSha256);
14516
- rmSync2(tmpDir, { recursive: true, force: true });
15025
+ rmSync3(tmpDir, { recursive: true, force: true });
14517
15026
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
14518
15027
  return targetDir;
14519
15028
  } catch (err) {
14520
15029
  error(`Failed to download ONNX Runtime: ${err}`);
14521
15030
  try {
14522
- rmSync2(tmpDir, { recursive: true, force: true });
15031
+ rmSync3(tmpDir, { recursive: true, force: true });
14523
15032
  } catch {}
14524
15033
  try {
14525
- rmSync2(targetDir, { recursive: true, force: true });
15034
+ rmSync3(targetDir, { recursive: true, force: true });
14526
15035
  } catch {}
14527
15036
  return null;
14528
15037
  }
@@ -14539,7 +15048,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
14539
15048
  }
14540
15049
  } catch (copyErr) {
14541
15050
  if (requiredLibs.has(libFile)) {
14542
- rmSync2(targetDir, { recursive: true, force: true });
15051
+ rmSync3(targetDir, { recursive: true, force: true });
14543
15052
  throw copyErr;
14544
15053
  }
14545
15054
  log(`ORT extract: failed to copy optional ${libFile}: ${copyErr}`);
@@ -14549,14 +15058,14 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
14549
15058
  for (const link of symlinks) {
14550
15059
  const dst = join8(targetDir, link.name);
14551
15060
  try {
14552
- unlinkSync3(dst);
15061
+ unlinkSync4(dst);
14553
15062
  } catch {}
14554
15063
  const dstForContainment = join8(targetRoot, link.name);
14555
- const resolvedTarget = resolve2(dirname4(dstForContainment), link.target);
15064
+ const resolvedTarget = resolve5(dirname4(dstForContainment), link.target);
14556
15065
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
14557
15066
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
14558
15067
  if (requiredLibs.has(link.name)) {
14559
- rmSync2(targetDir, { recursive: true, force: true });
15068
+ rmSync3(targetDir, { recursive: true, force: true });
14560
15069
  throw new Error(message);
14561
15070
  }
14562
15071
  log(`ORT extract: skipping optional symlink ${link.name}: ${message}`);
@@ -14566,15 +15075,15 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
14566
15075
  symlinkSync(link.target, dst);
14567
15076
  } catch (symlinkErr) {
14568
15077
  if (requiredLibs.has(link.name)) {
14569
- rmSync2(targetDir, { recursive: true, force: true });
15078
+ rmSync3(targetDir, { recursive: true, force: true });
14570
15079
  throw symlinkErr;
14571
15080
  }
14572
15081
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
14573
15082
  }
14574
15083
  }
14575
15084
  const requiredPath = join8(targetDir, info.libName);
14576
- if (!existsSync5(requiredPath)) {
14577
- rmSync2(targetDir, { recursive: true, force: true });
15085
+ if (!existsSync6(requiredPath)) {
15086
+ rmSync3(targetDir, { recursive: true, force: true });
14578
15087
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
14579
15088
  }
14580
15089
  }
@@ -14599,7 +15108,7 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
14599
15108
  ...sha256 ? { sha256 } : {},
14600
15109
  archiveSha256
14601
15110
  };
14602
- writeFileSync2(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
15111
+ writeFileSync3(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
14603
15112
  } catch (err) {
14604
15113
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
14605
15114
  }
@@ -14607,9 +15116,9 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
14607
15116
  function readOnnxInstalledMeta(installDir) {
14608
15117
  const path2 = join8(installDir, ONNX_INSTALLED_META_FILE);
14609
15118
  try {
14610
- if (!statSync3(path2).isFile())
15119
+ if (!statSync4(path2).isFile())
14611
15120
  return null;
14612
- const raw = readFileSync3(path2, "utf8");
15121
+ const raw = readFileSync5(path2, "utf8");
14613
15122
  const parsed = JSON.parse(raw);
14614
15123
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
14615
15124
  return null;
@@ -14625,680 +15134,166 @@ function readOnnxInstalledMeta(installDir) {
14625
15134
  }
14626
15135
  function sha256File(path2) {
14627
15136
  const hash = createHash2("sha256");
14628
- hash.update(readFileSync3(path2));
15137
+ hash.update(readFileSync5(path2));
14629
15138
  return hash.digest("hex");
14630
15139
  }
14631
15140
  function acquireLock(lockPath) {
14632
15141
  const tryClaim = () => {
14633
15142
  try {
14634
- const fd = openSync3(lockPath, "wx");
15143
+ const fd = openSync4(lockPath, "wx");
14635
15144
  try {
14636
- writeFileSync2(fd, `${process.pid}
15145
+ writeFileSync3(fd, `${process.pid}
14637
15146
  ${new Date().toISOString()}
14638
15147
  `);
14639
15148
  } finally {
14640
- closeSync3(fd);
15149
+ closeSync4(fd);
14641
15150
  }
14642
15151
  return true;
14643
15152
  } catch (err) {
14644
15153
  const code = err.code;
14645
15154
  if (code === "EEXIST")
14646
- return false;
14647
- warn(`[onnx] unexpected error acquiring lock ${lockPath}: ${err}`);
14648
- return false;
14649
- }
14650
- };
14651
- if (tryClaim())
14652
- return true;
14653
- let owningPid = null;
14654
- let lockMtimeMs = 0;
14655
- try {
14656
- const raw = readFileSync3(lockPath, "utf8");
14657
- const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
14658
- const parsed = Number.parseInt(firstLine, 10);
14659
- if (Number.isFinite(parsed) && parsed > 0)
14660
- owningPid = parsed;
14661
- lockMtimeMs = statSync3(lockPath).mtimeMs;
14662
- } catch {
14663
- return tryClaim();
14664
- }
14665
- const age = Date.now() - lockMtimeMs;
14666
- const ageWithinFresh = Math.abs(age) < STALE_LOCK_MS;
14667
- const ownerAlive = owningPid !== null && isProcessAlive(owningPid);
14668
- if (ownerAlive && ageWithinFresh) {
14669
- return false;
14670
- }
14671
- log(`[onnx] reclaiming install lock (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
14672
- try {
14673
- unlinkSync3(lockPath);
14674
- } catch {}
14675
- return tryClaim();
14676
- }
14677
- function releaseLock(lockPath) {
14678
- try {
14679
- let owningPid = null;
14680
- try {
14681
- const raw = readFileSync3(lockPath, "utf8");
14682
- const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
14683
- const parsed = Number.parseInt(firstLine, 10);
14684
- if (Number.isFinite(parsed) && parsed > 0)
14685
- owningPid = parsed;
14686
- } catch (readErr) {
14687
- const code = readErr.code;
14688
- if (code === "ENOENT")
14689
- return;
14690
- warn(`[onnx] could not read lock ${lockPath} during release: ${readErr}`);
14691
- return;
14692
- }
14693
- if (owningPid !== process.pid) {
14694
- log(`[onnx] not releasing lock ${lockPath}: owned by pid ${owningPid ?? "unknown"} (we are ${process.pid})`);
14695
- return;
14696
- }
14697
- try {
14698
- unlinkSync3(lockPath);
14699
- } catch (unlinkErr) {
14700
- const code = unlinkErr.code;
14701
- if (code !== "ENOENT") {
14702
- warn(`[onnx] failed to release lock ${lockPath}: ${unlinkErr}`);
14703
- }
14704
- }
14705
- } catch (err) {
14706
- warn(`[onnx] unexpected error releasing lock ${lockPath}: ${err}`);
14707
- }
14708
- }
14709
- function tasklistPidFromCsvLine(line) {
14710
- const quoted = line.match(/"([^"]*)"/g);
14711
- if (quoted && quoted.length >= 2)
14712
- return quoted[1].slice(1, -1);
14713
- const cells = line.split(",").map((cell) => cell.trim().replace(/^"|"$/g, ""));
14714
- return cells[1] ?? null;
14715
- }
14716
- function isWindowsProcessAlive(pid) {
14717
- if (!Number.isInteger(pid) || pid <= 0)
14718
- return false;
14719
- try {
14720
- const output = execFileSync("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
14721
- encoding: "utf8",
14722
- timeout: 2000,
14723
- windowsHide: true
14724
- });
14725
- const expected = String(pid);
14726
- return output.split(/\r?\n/).some((line) => tasklistPidFromCsvLine(line) === expected);
14727
- } catch {
14728
- return false;
14729
- }
14730
- }
14731
- function isProcessAlive(pid) {
14732
- if (process.platform === "win32")
14733
- return isWindowsProcessAlive(pid);
14734
- try {
14735
- process.kill(pid, 0);
14736
- return true;
14737
- } catch (err) {
14738
- const code = err.code;
14739
- if (code === "ESRCH")
14740
- return false;
14741
- return true;
14742
- }
14743
- }
14744
- // ../aft-bridge/dist/pipe-strip.js
14745
- var NOISE_FILTERS = new Set([
14746
- "grep",
14747
- "rg",
14748
- "head",
14749
- "tail",
14750
- "cat",
14751
- "less",
14752
- "more",
14753
- "sed",
14754
- "awk",
14755
- "cut",
14756
- "sort",
14757
- "uniq",
14758
- "tr",
14759
- "column",
14760
- "fold"
14761
- ]);
14762
- var GREP_GUARD_FLAGS = new Set([
14763
- "c",
14764
- "count",
14765
- "q",
14766
- "quiet",
14767
- "o",
14768
- "only-matching",
14769
- "l",
14770
- "files-with-matches"
14771
- ]);
14772
- function maybeStripCompressorPipe(command, compressionEnabled) {
14773
- if (!compressionEnabled)
14774
- return { command, stripped: false };
14775
- const chain = splitTopLevelCommandChain(command);
14776
- if (chain === null)
14777
- return { command, stripped: false };
14778
- let stripped = false;
14779
- const droppedFilterChains = [];
14780
- const rebuilt = chain.map(({ segment, separator }) => {
14781
- const result = stripSinglePipelineSegment(segment);
14782
- if (result.stripped) {
14783
- stripped = true;
14784
- droppedFilterChains.push(result.filters);
14785
- }
14786
- return `${result.segment}${separator}`;
14787
- }).join("");
14788
- if (!stripped)
14789
- return { command, stripped: false };
14790
- return {
14791
- command: rebuilt,
14792
- stripped: true,
14793
- note: formatStripNote(droppedFilterChains)
14794
- };
14795
- }
14796
- function stripSinglePipelineSegment(segment) {
14797
- const leading = /^\s*/.exec(segment)?.[0] ?? "";
14798
- const trailing = /\s*$/.exec(segment)?.[0] ?? "";
14799
- const coreStart = leading.length;
14800
- const coreEnd = segment.length - trailing.length;
14801
- if (coreEnd <= coreStart)
14802
- return { segment, stripped: false };
14803
- const core = segment.slice(coreStart, coreEnd);
14804
- if (containsUnsplittableConstruct(core))
14805
- return { segment, stripped: false };
14806
- if (hasUnquotedBackground(core))
14807
- return { segment, stripped: false };
14808
- const stages = splitTopLevelPipeline(core);
14809
- if (stages.length < 2)
14810
- return { segment, stripped: false };
14811
- const firstStage = stages[0]?.trim() ?? "";
14812
- if (!isCompressorHandledRunner(firstStage))
14813
- return { segment, stripped: false };
14814
- const filterStages = stages.slice(1).map((stage) => stage.trim());
14815
- for (const stage of filterStages) {
14816
- if (!filterStageIsSafeToDrop(stage))
14817
- return { segment, stripped: false };
14818
- }
14819
- return {
14820
- segment: `${leading}${firstStage}${trailing}`,
14821
- stripped: true,
14822
- filters: filterStages.join(" | ")
14823
- };
14824
- }
14825
- function formatStripNote(droppedFilterChains) {
14826
- const filters = droppedFilterChains.map((filter) => `\`| ${filter}\``).join(", ");
14827
- return `[AFT dropped ${filters} (compressed:false to keep)]`;
14828
- }
14829
- function splitTopLevelCommandChain(command) {
14830
- const segments = [];
14831
- let start = 0;
14832
- let quote = null;
14833
- let escaped = false;
14834
- let inBacktick = false;
14835
- let parenDepth = 0;
14836
- for (let index = 0;index < command.length; index++) {
14837
- const char = command[index];
14838
- const next = command[index + 1];
14839
- if (escaped) {
14840
- escaped = false;
14841
- continue;
14842
- }
14843
- if (inBacktick) {
14844
- if (char === "\\")
14845
- escaped = true;
14846
- else if (char === "`")
14847
- inBacktick = false;
14848
- continue;
14849
- }
14850
- if (char === "\\" && quote !== "'") {
14851
- escaped = true;
14852
- continue;
14853
- }
14854
- if (quote) {
14855
- if (char === quote)
14856
- quote = null;
14857
- continue;
14858
- }
14859
- if (char === "'" || char === '"') {
14860
- quote = char;
14861
- continue;
14862
- }
14863
- if (char === "`") {
14864
- inBacktick = true;
14865
- continue;
14866
- }
14867
- if (char === "(") {
14868
- parenDepth++;
14869
- continue;
14870
- }
14871
- if (char === ")") {
14872
- if (parenDepth === 0)
14873
- return null;
14874
- parenDepth--;
14875
- continue;
14876
- }
14877
- if (parenDepth > 0)
14878
- continue;
14879
- if (char === `
14880
- ` || char === "\r")
14881
- return null;
14882
- if (char === "#" && (index === 0 || command[index - 1] === " " || command[index - 1] === "\t"))
14883
- return null;
14884
- if (char === "&" && next === "&") {
14885
- segments.push({ segment: command.slice(start, index), separator: "&&" });
14886
- start = index + 2;
14887
- index++;
14888
- continue;
14889
- }
14890
- if (char === "|" && next === "|") {
14891
- segments.push({ segment: command.slice(start, index), separator: "||" });
14892
- start = index + 2;
14893
- index++;
14894
- continue;
14895
- }
14896
- if (char === ";") {
14897
- segments.push({ segment: command.slice(start, index), separator: ";" });
14898
- start = index + 1;
14899
- }
14900
- }
14901
- if (escaped || quote || inBacktick || parenDepth !== 0)
14902
- return null;
14903
- segments.push({ segment: command.slice(start), separator: "" });
14904
- return segments;
14905
- }
14906
- function splitTopLevelPipeline(command) {
14907
- const stages = [];
14908
- let start = 0;
14909
- let quote = null;
14910
- let escaped = false;
14911
- for (let index = 0;index < command.length; index++) {
14912
- const char = command[index];
14913
- const next = command[index + 1];
14914
- const previous = command[index - 1];
14915
- if (escaped) {
14916
- escaped = false;
14917
- continue;
14918
- }
14919
- if (char === "\\" && quote !== "'") {
14920
- escaped = true;
14921
- continue;
14922
- }
14923
- if (quote) {
14924
- if (char === quote)
14925
- quote = null;
14926
- continue;
14927
- }
14928
- if (char === "'" || char === '"') {
14929
- quote = char;
14930
- continue;
14931
- }
14932
- if (char === "|" && previous !== "|" && next !== "|") {
14933
- stages.push(command.slice(start, index));
14934
- start = index + 1;
14935
- }
14936
- }
14937
- stages.push(command.slice(start));
14938
- return stages;
14939
- }
14940
- function isCompressorHandledRunner(stage) {
14941
- const tokens = tokenizeStage(stage);
14942
- if (tokens.length === 0)
14943
- return false;
14944
- if (tokens.some((token) => token === "&&" || token === "||" || token.includes(";"))) {
14945
- return false;
14946
- }
14947
- let tokenOffset = 0;
14948
- while (tokenOffset < tokens.length && isEnvAssignment(tokens[tokenOffset])) {
14949
- tokenOffset++;
14950
- }
14951
- const first = runnerName(tokens[tokenOffset]);
14952
- const runnerArgs = tokens.slice(tokenOffset + 1);
14953
- const second = runnerArgs[0];
14954
- const third = runnerArgs[1];
14955
- const rest = runnerArgs;
14956
- if (!first)
14957
- return false;
14958
- if (first === "bun") {
14959
- let args = rest;
14960
- if (args[0] === "--cwd")
14961
- args = args.slice(2);
14962
- else if (args[0]?.startsWith("--cwd="))
14963
- args = args.slice(1);
14964
- const sub = args[0];
14965
- const subNext = args[1];
14966
- return sub === "test" || sub === "run" && isJsVerificationScript(subNext);
14967
- }
14968
- if (first === "npm" || first === "pnpm") {
14969
- return second === "test" || second === "run" && isJsVerificationScript(third);
14970
- }
14971
- if (first === "yarn") {
14972
- return isJsVerificationScript(second) || second === "run" && isJsVerificationScript(third);
14973
- }
14974
- if (first === "deno")
14975
- return ["test", "lint", "check", "bench"].includes(second ?? "");
14976
- if (first === "npx") {
14977
- return ["tsc", "eslint", "vitest", "jest", "playwright", "biome"].includes(second ?? "");
14978
- }
14979
- if (first === "playwright")
14980
- return second === "test";
14981
- if (first === "cargo") {
14982
- return ["test", "build", "check", "clippy", "nextest"].includes(second ?? "");
14983
- }
14984
- if (first === "go")
14985
- return ["test", "build", "vet"].includes(second ?? "");
14986
- if (first === "gradle" || first === "gradlew") {
14987
- return hasBuildTask(rest, ["test", "check", "build", "assemble", "clean"]);
14988
- }
14989
- if (first === "mvn" || first === "mvnw") {
14990
- return hasBuildTask(rest, ["test", "verify", "package", "install", "clean"]);
14991
- }
14992
- if (first === "dotnet")
14993
- return ["test", "build"].includes(second ?? "");
14994
- if (first === "rspec")
14995
- return true;
14996
- if (first === "rake") {
14997
- const positionals = rest.filter((a) => !a.startsWith("-"));
14998
- if (positionals.length === 0)
14999
- return false;
15000
- if (positionals.some((a) => a.includes("/") || a.includes(".") || a.includes("=")))
15001
- return false;
15002
- return positionals.some((a) => a === "test" || a === "spec");
15003
- }
15004
- if (first === "phpunit" || first === "pest")
15005
- return true;
15006
- if (first === "xcodebuild")
15007
- return xcodebuildHasBuildAction(rest);
15008
- if (first === "swift")
15009
- return second === "test" || second === "build";
15010
- if (first === "make" || first === "gmake") {
15011
- return hasBuildTask(rest, ["test", "check", "lint", "clean"]);
15012
- }
15013
- return [
15014
- "vitest",
15015
- "jest",
15016
- "pytest",
15017
- "tsc",
15018
- "eslint",
15019
- "biome",
15020
- "ruff",
15021
- "mypy",
15022
- "tox",
15023
- "nox"
15024
- ].includes(first);
15025
- }
15026
- function isEnvAssignment(token) {
15027
- if (!token)
15028
- return false;
15029
- return /^[a-zA-Z_][a-zA-Z0-9_]*=/.test(token);
15030
- }
15031
- function runnerName(token) {
15032
- if (!token)
15033
- return "";
15034
- const slash = token.lastIndexOf("/");
15035
- return slash === -1 ? token : token.slice(slash + 1);
15036
- }
15037
- function hasBuildTask(args, tasks) {
15038
- const isAllowedTask = (arg) => tasks.some((task) => arg === task || arg.endsWith(`:${task}`));
15039
- const isFlagOrProperty = (arg) => arg.startsWith("-") || arg.includes("=");
15040
- let sawAllowed = false;
15041
- for (const arg of args) {
15042
- if (isFlagOrProperty(arg))
15043
- continue;
15044
- if (!isAllowedTask(arg))
15155
+ return false;
15156
+ warn(`[onnx] unexpected error acquiring lock ${lockPath}: ${err}`);
15045
15157
  return false;
15046
- sawAllowed = true;
15158
+ }
15159
+ };
15160
+ if (tryClaim())
15161
+ return true;
15162
+ let owningPid = null;
15163
+ let lockMtimeMs = 0;
15164
+ try {
15165
+ const raw = readFileSync5(lockPath, "utf8");
15166
+ const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
15167
+ const parsed = Number.parseInt(firstLine, 10);
15168
+ if (Number.isFinite(parsed) && parsed > 0)
15169
+ owningPid = parsed;
15170
+ lockMtimeMs = statSync4(lockPath).mtimeMs;
15171
+ } catch {
15172
+ return tryClaim();
15047
15173
  }
15048
- return sawAllowed;
15049
- }
15050
- function isJsVerificationScript(token) {
15051
- if (!token)
15174
+ const age = Date.now() - lockMtimeMs;
15175
+ const ageWithinFresh = Math.abs(age) < STALE_LOCK_MS;
15176
+ const ownerAlive = owningPid !== null && isProcessAlive(owningPid);
15177
+ if (ownerAlive && ageWithinFresh) {
15052
15178
  return false;
15053
- return token.startsWith("test") || token === "typecheck" || token.startsWith("typecheck:");
15054
- }
15055
- var XCODEBUILD_VALUE_FLAGS = new Set([
15056
- "-scheme",
15057
- "-target",
15058
- "-project",
15059
- "-workspace",
15060
- "-configuration",
15061
- "-sdk",
15062
- "-destination",
15063
- "-arch",
15064
- "-derivedDataPath",
15065
- "-resultBundlePath",
15066
- "-xcconfig",
15067
- "-toolchain"
15068
- ]);
15069
- var XCODEBUILD_BUILD_ACTIONS = new Set([
15070
- "build",
15071
- "test",
15072
- "build-for-testing",
15073
- "test-without-building",
15074
- "analyze"
15075
- ]);
15076
- function xcodebuildHasBuildAction(args) {
15077
- for (let i = 0;i < args.length; i++) {
15078
- const arg = args[i];
15079
- if (arg.startsWith("-")) {
15080
- if (XCODEBUILD_VALUE_FLAGS.has(arg))
15081
- i++;
15082
- continue;
15083
- }
15084
- if (XCODEBUILD_BUILD_ACTIONS.has(arg))
15085
- return true;
15086
15179
  }
15087
- return false;
15180
+ log(`[onnx] reclaiming install lock (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
15181
+ try {
15182
+ unlinkSync4(lockPath);
15183
+ } catch {}
15184
+ return tryClaim();
15088
15185
  }
15089
- function containsUnsplittableConstruct(command) {
15090
- let quote = null;
15091
- let escaped = false;
15092
- for (let i = 0;i < command.length; i++) {
15093
- const char = command[i];
15094
- if (escaped) {
15095
- escaped = false;
15096
- continue;
15097
- }
15098
- if (char === "\\" && quote !== "'") {
15099
- escaped = true;
15100
- continue;
15101
- }
15102
- if (quote === "'") {
15103
- if (char === "'")
15104
- quote = null;
15105
- continue;
15186
+ function releaseLock(lockPath) {
15187
+ try {
15188
+ let owningPid = null;
15189
+ try {
15190
+ const raw = readFileSync5(lockPath, "utf8");
15191
+ const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
15192
+ const parsed = Number.parseInt(firstLine, 10);
15193
+ if (Number.isFinite(parsed) && parsed > 0)
15194
+ owningPid = parsed;
15195
+ } catch (readErr) {
15196
+ const code = readErr.code;
15197
+ if (code === "ENOENT")
15198
+ return;
15199
+ warn(`[onnx] could not read lock ${lockPath} during release: ${readErr}`);
15200
+ return;
15106
15201
  }
15107
- if (quote === '"') {
15108
- if (char === '"')
15109
- quote = null;
15110
- else if (char === "`")
15111
- return true;
15112
- else if (char === "$" && command[i + 1] === "(")
15113
- return true;
15114
- continue;
15202
+ if (owningPid !== process.pid) {
15203
+ log(`[onnx] not releasing lock ${lockPath}: owned by pid ${owningPid ?? "unknown"} (we are ${process.pid})`);
15204
+ return;
15115
15205
  }
15116
- if (char === "'" || char === '"') {
15117
- quote = char;
15118
- continue;
15206
+ try {
15207
+ unlinkSync4(lockPath);
15208
+ } catch (unlinkErr) {
15209
+ const code = unlinkErr.code;
15210
+ if (code !== "ENOENT") {
15211
+ warn(`[onnx] failed to release lock ${lockPath}: ${unlinkErr}`);
15212
+ }
15119
15213
  }
15120
- if (char === "`")
15121
- return true;
15122
- if (char === "(" || char === ")")
15123
- return true;
15214
+ } catch (err) {
15215
+ warn(`[onnx] unexpected error releasing lock ${lockPath}: ${err}`);
15124
15216
  }
15125
- return false;
15126
15217
  }
15127
- var READS_FILE_OPERAND = new Set(["cat", "tac", "nl", "less", "more"]);
15128
- function filterStageIsSafeToDrop(stage) {
15129
- const head = tokenizeStage(stage)[0];
15130
- if (!head)
15131
- return false;
15132
- if (head === "wc")
15133
- return false;
15134
- if (!NOISE_FILTERS.has(head))
15135
- return false;
15136
- if (/[<>]/.test(stage))
15218
+ function tasklistPidFromCsvLine(line) {
15219
+ const quoted = line.match(/"([^"]*)"/g);
15220
+ if (quoted && quoted.length >= 2)
15221
+ return quoted[1].slice(1, -1);
15222
+ const cells = line.split(",").map((cell) => cell.trim().replace(/^"|"$/g, ""));
15223
+ return cells[1] ?? null;
15224
+ }
15225
+ function isWindowsProcessAlive(pid) {
15226
+ if (!Number.isInteger(pid) || pid <= 0)
15137
15227
  return false;
15138
- if (hasUnquotedBackground(stage))
15228
+ try {
15229
+ const output = execFileSync("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
15230
+ encoding: "utf8",
15231
+ timeout: 2000,
15232
+ windowsHide: true
15233
+ });
15234
+ const expected = String(pid);
15235
+ return output.split(/\r?\n/).some((line) => tasklistPidFromCsvLine(line) === expected);
15236
+ } catch {
15139
15237
  return false;
15140
- const args = tokenizeStage(stage).slice(1);
15141
- const hasFlag = (...names) => args.some((a) => names.some((n) => a === n || a.startsWith(`${n}=`)));
15142
- if (head === "grep" || head === "rg") {
15143
- if (hasIntentChangingGrepFlag(args))
15144
- return false;
15145
- if (countBareOperands(args) > 1)
15146
- return false;
15147
- return true;
15148
- }
15149
- if (head === "head" || head === "tail") {
15150
- if (bareOperands(args).some((op) => !/^\d+$/.test(op)))
15151
- return false;
15152
- return true;
15153
15238
  }
15154
- if (READS_FILE_OPERAND.has(head)) {
15155
- if (countBareOperands(args) > 0)
15156
- return false;
15157
- return true;
15158
- }
15159
- if (head === "sed") {
15160
- if (hasFlag("-i", "--in-place"))
15161
- return false;
15162
- if (countBareOperands(args) > 1)
15163
- return false;
15239
+ }
15240
+ function isProcessAlive(pid) {
15241
+ if (process.platform === "win32")
15242
+ return isWindowsProcessAlive(pid);
15243
+ try {
15244
+ process.kill(pid, 0);
15164
15245
  return true;
15165
- }
15166
- if (head === "awk") {
15167
- if (countBareOperands(args) > 1)
15246
+ } catch (err) {
15247
+ const code = err.code;
15248
+ if (code === "ESRCH")
15168
15249
  return false;
15169
15250
  return true;
15170
15251
  }
15171
- if (head === "sort" && hasFlag("-o", "--output"))
15172
- return false;
15173
- if (bareOperands(args).some((op) => op.includes("/") || op.includes(".")))
15174
- return false;
15175
- return true;
15176
- }
15177
- function bareOperands(args) {
15178
- const out = [];
15179
- let afterDoubleDash = false;
15180
- for (const arg of args) {
15181
- if (!afterDoubleDash && arg === "--") {
15182
- afterDoubleDash = true;
15183
- continue;
15184
- }
15185
- if (!afterDoubleDash && arg.startsWith("-") && arg !== "-")
15186
- continue;
15187
- out.push(arg);
15188
- }
15189
- return out;
15190
- }
15191
- function countBareOperands(args) {
15192
- return bareOperands(args).length;
15193
15252
  }
15194
- function hasUnquotedBackground(stage) {
15195
- let quote = null;
15196
- let escaped = false;
15197
- for (let i = 0;i < stage.length; i++) {
15198
- const char = stage[i];
15199
- if (escaped) {
15200
- escaped = false;
15201
- continue;
15202
- }
15203
- if (char === "\\" && quote !== "'") {
15204
- escaped = true;
15205
- continue;
15206
- }
15207
- if (quote) {
15208
- if (char === quote)
15209
- quote = null;
15210
- continue;
15211
- }
15212
- if (char === "'" || char === '"') {
15213
- quote = char;
15214
- continue;
15215
- }
15216
- if (char === "&") {
15217
- const prev = stage[i - 1];
15218
- const next = stage[i + 1];
15219
- if (prev === "&" || next === "&" || prev === ">" || next === ">")
15220
- continue;
15221
- return true;
15222
- }
15253
+ // ../aft-bridge/dist/pool.js
15254
+ import { homedir as homedir9 } from "node:os";
15255
+
15256
+ // ../aft-bridge/dist/project-identity.js
15257
+ import { realpathSync as realpathSync2 } from "node:fs";
15258
+ import { resolve as resolve6 } from "node:path";
15259
+ function canonicalizeProjectRoot(dir) {
15260
+ const trimmed = dir.replace(/[/\\]+$/, "");
15261
+ let canonical;
15262
+ try {
15263
+ canonical = realpathSync2(trimmed);
15264
+ } catch {
15265
+ canonical = resolve6(trimmed);
15223
15266
  }
15224
- return false;
15267
+ return normalizeWindowsRoot(canonical);
15225
15268
  }
15226
- function hasIntentChangingGrepFlag(args) {
15227
- for (const arg of args) {
15228
- if (arg === "--")
15229
- return false;
15230
- if (!arg.startsWith("-") || arg === "-")
15231
- continue;
15232
- if (arg.startsWith("--")) {
15233
- const flag = arg.slice(2).split("=", 1)[0];
15234
- if (GREP_GUARD_FLAGS.has(flag))
15235
- return true;
15236
- continue;
15237
- }
15238
- for (const flag of arg.slice(1)) {
15239
- if (GREP_GUARD_FLAGS.has(flag))
15240
- return true;
15241
- }
15269
+ function normalizeWindowsRoot(p) {
15270
+ if (process.platform !== "win32")
15271
+ return p;
15272
+ let s = p;
15273
+ if (s.startsWith("\\\\?\\UNC\\")) {
15274
+ s = `\\\\${s.slice("\\\\?\\UNC\\".length)}`;
15275
+ } else if (s.startsWith("\\\\?\\")) {
15276
+ s = s.slice("\\\\?\\".length);
15242
15277
  }
15243
- return false;
15244
- }
15245
- function tokenizeStage(stage) {
15246
- const tokens = [];
15247
- let current = "";
15248
- let quote = null;
15249
- let escaped = false;
15250
- for (let index = 0;index < stage.length; index++) {
15251
- const char = stage[index];
15252
- if (escaped) {
15253
- current += char;
15254
- escaped = false;
15255
- continue;
15256
- }
15257
- if (char === "\\" && quote !== "'") {
15258
- escaped = true;
15259
- continue;
15260
- }
15261
- if (quote) {
15262
- if (char === quote) {
15263
- quote = null;
15264
- } else {
15265
- current += char;
15266
- }
15267
- continue;
15268
- }
15269
- if (char === "'" || char === '"') {
15270
- quote = char;
15271
- continue;
15272
- }
15273
- if (/\s/.test(char)) {
15274
- if (current.length > 0) {
15275
- tokens.push(current);
15276
- current = "";
15277
- }
15278
- continue;
15278
+ if (s.length >= 2 && s[1] === ":") {
15279
+ const drive = s.charCodeAt(0);
15280
+ if (drive >= 97 && drive <= 122) {
15281
+ s = s[0].toUpperCase() + s.slice(1);
15279
15282
  }
15280
- current += char;
15281
15283
  }
15282
- if (current.length > 0)
15283
- tokens.push(current);
15284
- return tokens;
15284
+ return s;
15285
15285
  }
15286
+
15286
15287
  // ../aft-bridge/dist/pool.js
15287
- import { realpathSync as realpathSync2 } from "node:fs";
15288
- import { homedir as homedir8 } from "node:os";
15289
15288
  var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
15290
15289
  var DEFAULT_MAX_POOL_SIZE = 8;
15291
15290
  var CLEANUP_INTERVAL_MS = 60 * 1000;
15292
15291
  function canonicalHomeDir() {
15293
15292
  try {
15294
- const home = homedir8();
15293
+ const home = homedir9();
15295
15294
  if (!home)
15296
15295
  return null;
15297
- try {
15298
- return realpathSync2(home);
15299
- } catch {
15300
- return home.replace(/[/\\]+$/, "");
15301
- }
15296
+ return canonicalizeProjectRoot(home);
15302
15297
  } catch {
15303
15298
  return null;
15304
15299
  }
@@ -15477,12 +15472,7 @@ class BridgePool {
15477
15472
  }
15478
15473
  }
15479
15474
  function normalizeKey(projectRoot) {
15480
- const stripped = projectRoot.replace(/[/\\]+$/, "");
15481
- try {
15482
- return realpathSync2(stripped);
15483
- } catch {
15484
- return stripped;
15485
- }
15475
+ return canonicalizeProjectRoot(projectRoot);
15486
15476
  }
15487
15477
  // ../aft-bridge/dist/tool-format.js
15488
15478
  function asPlainObject(value) {
@@ -16314,7 +16304,7 @@ import {
16314
16304
  // package.json
16315
16305
  var package_default = {
16316
16306
  name: "@cortexkit/aft-pi",
16317
- version: "0.39.4",
16307
+ version: "0.40.0",
16318
16308
  type: "module",
16319
16309
  description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
16320
16310
  main: "dist/index.js",
@@ -16337,7 +16327,7 @@ var package_default = {
16337
16327
  "test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
16338
16328
  },
16339
16329
  dependencies: {
16340
- "@cortexkit/aft-bridge": "0.39.4",
16330
+ "@cortexkit/aft-bridge": "0.40.0",
16341
16331
  "@xterm/headless": "^5.5.0",
16342
16332
  "comment-json": "^5.0.0",
16343
16333
  diff: "^8.0.4",
@@ -16345,12 +16335,12 @@ var package_default = {
16345
16335
  zod: "^4.1.8"
16346
16336
  },
16347
16337
  optionalDependencies: {
16348
- "@cortexkit/aft-darwin-arm64": "0.39.4",
16349
- "@cortexkit/aft-darwin-x64": "0.39.4",
16350
- "@cortexkit/aft-linux-arm64": "0.39.4",
16351
- "@cortexkit/aft-linux-x64": "0.39.4",
16352
- "@cortexkit/aft-win32-arm64": "0.39.4",
16353
- "@cortexkit/aft-win32-x64": "0.39.4"
16338
+ "@cortexkit/aft-darwin-arm64": "0.40.0",
16339
+ "@cortexkit/aft-darwin-x64": "0.40.0",
16340
+ "@cortexkit/aft-linux-arm64": "0.40.0",
16341
+ "@cortexkit/aft-linux-x64": "0.40.0",
16342
+ "@cortexkit/aft-win32-arm64": "0.40.0",
16343
+ "@cortexkit/aft-win32-x64": "0.40.0"
16354
16344
  },
16355
16345
  devDependencies: {
16356
16346
  "@earendil-works/pi-coding-agent": "*",
@@ -16924,9 +16914,7 @@ function registerStatusCommand(pi, ctx) {
16924
16914
  }
16925
16915
 
16926
16916
  // src/config.ts
16927
- import { existsSync as existsSync6, readFileSync as readFileSync4, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
16928
- import { homedir as homedir9 } from "node:os";
16929
- import { join as join10 } from "node:path";
16917
+ import { existsSync as existsSync7, readFileSync as readFileSync6, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
16930
16918
  var import_comment_json = __toESM(require_src2(), 1);
16931
16919
 
16932
16920
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
@@ -30462,7 +30450,7 @@ function date4(params) {
30462
30450
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
30463
30451
  config(en_default());
30464
30452
  // src/config.ts
30465
- var FOREGROUND_WAIT_WINDOW_DEFAULT_MS = 8000;
30453
+ var FOREGROUND_WAIT_WINDOW_DEFAULT_MS = 15000;
30466
30454
  var FOREGROUND_WAIT_WINDOW_MIN_MS = 5000;
30467
30455
  function resolveBashConfig(config2) {
30468
30456
  const top = config2.bash;
@@ -30633,105 +30621,6 @@ var AftConfigSchema = exports_external.object({
30633
30621
  max_callgraph_files: exports_external.number().int().positive().optional(),
30634
30622
  bridge: BridgeConfigSchema.optional()
30635
30623
  }).strict();
30636
- function normalizeLspExtension(extension) {
30637
- return extension.trim().replace(/^\.+/, "");
30638
- }
30639
- function resolveLspConfigForConfigure(config2) {
30640
- const overrides = {};
30641
- const disabled = new Set(config2.lsp?.disabled ?? []);
30642
- let experimentalTy = config2.experimental?.lsp_ty;
30643
- switch (config2.lsp?.python ?? "auto") {
30644
- case "ty":
30645
- experimentalTy = true;
30646
- disabled.add("python");
30647
- break;
30648
- case "pyright":
30649
- experimentalTy = false;
30650
- disabled.add("ty");
30651
- break;
30652
- case "auto":
30653
- break;
30654
- }
30655
- if (experimentalTy !== undefined) {
30656
- overrides.experimental_lsp_ty = experimentalTy;
30657
- }
30658
- const servers = Object.entries(config2.lsp?.servers ?? {}).map(([id, server]) => {
30659
- const entry = {
30660
- id,
30661
- args: server.args,
30662
- root_markers: server.root_markers,
30663
- disabled: server.disabled
30664
- };
30665
- if (server.extensions && server.extensions.length > 0) {
30666
- entry.extensions = server.extensions.map(normalizeLspExtension);
30667
- }
30668
- if (server.binary) {
30669
- entry.binary = server.binary;
30670
- }
30671
- if (server.env && Object.keys(server.env).length > 0) {
30672
- entry.env = server.env;
30673
- }
30674
- if (server.initialization_options !== undefined) {
30675
- entry.initialization_options = server.initialization_options;
30676
- }
30677
- return entry;
30678
- });
30679
- if (servers.length > 0) {
30680
- overrides.lsp_servers = servers;
30681
- }
30682
- if (disabled.size > 0) {
30683
- overrides.disabled_lsp = [...disabled];
30684
- }
30685
- return overrides;
30686
- }
30687
- function resolveProjectOverridesForConfigure(config2) {
30688
- const overrides = {};
30689
- if (config2.format_on_edit !== undefined)
30690
- overrides.format_on_edit = config2.format_on_edit;
30691
- if (config2.formatter_timeout_secs !== undefined)
30692
- overrides.formatter_timeout_secs = config2.formatter_timeout_secs;
30693
- if (config2.validate_on_edit !== undefined)
30694
- overrides.validate_on_edit = config2.validate_on_edit;
30695
- if (config2.formatter !== undefined)
30696
- overrides.formatter = config2.formatter;
30697
- if (config2.checker !== undefined)
30698
- overrides.checker = config2.checker;
30699
- overrides.restrict_to_project_root = config2.restrict_to_project_root ?? false;
30700
- if (config2.search_index !== undefined)
30701
- overrides.search_index = config2.search_index;
30702
- if (config2.semantic_search !== undefined)
30703
- overrides.semantic_search = config2.semantic_search;
30704
- if (config2.callgraph_store !== undefined)
30705
- overrides.callgraph_store = config2.callgraph_store;
30706
- if (config2.callgraph_chunk_size !== undefined)
30707
- overrides.callgraph_chunk_size = config2.callgraph_chunk_size;
30708
- Object.assign(overrides, resolveExperimentalConfigForConfigure(config2));
30709
- Object.assign(overrides, resolveLspConfigForConfigure(config2));
30710
- if (config2.semantic !== undefined)
30711
- overrides.semantic = config2.semantic;
30712
- if (config2.inspect !== undefined)
30713
- overrides.inspect = config2.inspect;
30714
- if (config2.max_callgraph_files !== undefined)
30715
- overrides.max_callgraph_files = config2.max_callgraph_files;
30716
- return overrides;
30717
- }
30718
- function resolveExperimentalConfigForConfigure(config2) {
30719
- const overrides = {};
30720
- const bash = resolveBashConfig(config2);
30721
- overrides.experimental_bash_rewrite = bash.rewrite;
30722
- overrides.experimental_bash_compress = bash.compress;
30723
- overrides.experimental_bash_background = bash.background;
30724
- if (bash.long_running_reminder_enabled !== undefined) {
30725
- overrides.bash_long_running_reminder_enabled = bash.long_running_reminder_enabled;
30726
- }
30727
- if (bash.long_running_reminder_interval_ms !== undefined) {
30728
- overrides.bash_long_running_reminder_interval_ms = bash.long_running_reminder_interval_ms;
30729
- }
30730
- if (config2.experimental?.lsp_ty !== undefined) {
30731
- overrides.experimental_lsp_ty = config2.experimental.lsp_ty;
30732
- }
30733
- return overrides;
30734
- }
30735
30624
  var CONFIG_MIGRATIONS = [
30736
30625
  { oldKey: "experimental_search_index", newPath: ["search_index"] },
30737
30626
  { oldKey: "experimental_semantic_search", newPath: ["semantic_search"] },
@@ -30841,14 +30730,14 @@ function migrateExperimentalBashBlock(rawConfig, configPath, logger) {
30841
30730
  }
30842
30731
  return movedKeys;
30843
30732
  }
30844
- function migrateAftConfigFile(configPath, logger = { log: log2, warn: warn2 }) {
30845
- if (!existsSync6(configPath)) {
30733
+ function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 }) {
30734
+ if (!existsSync7(configPath)) {
30846
30735
  return { migrated: false, oldKeys: [] };
30847
30736
  }
30848
30737
  let tmpPath = null;
30849
30738
  let oldKeys = [];
30850
30739
  try {
30851
- const content = readFileSync4(configPath, "utf-8");
30740
+ const content = readFileSync6(configPath, "utf-8");
30852
30741
  const rawConfig = import_comment_json.parse(content);
30853
30742
  if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
30854
30743
  return { migrated: false, oldKeys: [] };
@@ -30864,14 +30753,14 @@ function migrateAftConfigFile(configPath, logger = { log: log2, warn: warn2 }) {
30864
30753
  `)}
30865
30754
  ${serialized}` : serialized;
30866
30755
  tmpPath = `${configPath}.tmp.${process.pid}`;
30867
- writeFileSync3(tmpPath, nextContent, "utf-8");
30868
- renameSync4(tmpPath, configPath);
30756
+ writeFileSync4(tmpPath, nextContent, "utf-8");
30757
+ renameSync5(tmpPath, configPath);
30869
30758
  logger.log(`Migrated config at ${configPath}: removed ${oldKeys.join(", ")}`);
30870
30759
  return { migrated: true, oldKeys };
30871
30760
  } catch (err) {
30872
30761
  if (tmpPath) {
30873
30762
  try {
30874
- unlinkSync4(tmpPath);
30763
+ unlinkSync5(tmpPath);
30875
30764
  } catch {}
30876
30765
  }
30877
30766
  if (isWritableMigrationError(err)) {
@@ -30882,15 +30771,6 @@ ${serialized}` : serialized;
30882
30771
  return { migrated: false, oldKeys: [] };
30883
30772
  }
30884
30773
  }
30885
- function detectConfigFile(basePath) {
30886
- const jsoncPath = `${basePath}.jsonc`;
30887
- const jsonPath = `${basePath}.json`;
30888
- if (existsSync6(jsoncPath))
30889
- return { format: "jsonc", path: jsoncPath };
30890
- if (existsSync6(jsonPath))
30891
- return { format: "json", path: jsonPath };
30892
- return { format: "none", path: jsonPath };
30893
- }
30894
30774
  var configLoadErrors = [];
30895
30775
  function getConfigLoadErrors() {
30896
30776
  return configLoadErrors;
@@ -30904,9 +30784,9 @@ function recordConfigParseFailure(configPath, errorMessage) {
30904
30784
  }
30905
30785
  function loadConfigFromPath(configPath) {
30906
30786
  try {
30907
- if (!existsSync6(configPath))
30787
+ if (!existsSync7(configPath))
30908
30788
  return null;
30909
- const content = readFileSync4(configPath, "utf-8");
30789
+ const content = readFileSync6(configPath, "utf-8");
30910
30790
  const rawConfig = import_comment_json.parse(content);
30911
30791
  if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
30912
30792
  recordConfigParseFailure(configPath, "root must be an object");
@@ -31123,21 +31003,43 @@ function resolveBridgePoolTransportOptions(config2) {
31123
31003
  hangThreshold: config2.bridge?.hang_threshold ?? DEFAULT_BRIDGE_HANG_THRESHOLD
31124
31004
  };
31125
31005
  }
31126
- function getGlobalPiDir() {
31127
- return join10(homedir9(), ".pi", "agent");
31006
+ function migrateAftConfigLocations(projectDirectory, logger = { log: log2, warn: warn2 }) {
31007
+ const paths = resolveCortexKitConfigPaths(projectDirectory);
31008
+ const legacy = resolveLegacyAftConfigSources(projectDirectory);
31009
+ return [
31010
+ migrateAftConfigFile({
31011
+ scope: "user",
31012
+ targetPath: paths.userConfigPath,
31013
+ legacySources: legacy.user,
31014
+ operatingHarness: "pi",
31015
+ logger
31016
+ }),
31017
+ migrateAftConfigFile({
31018
+ scope: "project",
31019
+ targetPath: paths.projectConfigPath,
31020
+ legacySources: legacy.project,
31021
+ operatingHarness: "pi",
31022
+ logger
31023
+ })
31024
+ ];
31025
+ }
31026
+ function resolveAftConfigPaths(projectDirectory) {
31027
+ const paths = resolveCortexKitConfigPaths(projectDirectory);
31028
+ migrateAftConfigFile2(paths.userConfigPath);
31029
+ migrateAftConfigFile2(paths.projectConfigPath);
31030
+ return paths;
31031
+ }
31032
+ function buildConfigTierConfigureParams(projectDirectory, processState = {}) {
31033
+ const paths = resolveAftConfigPaths(projectDirectory);
31034
+ return {
31035
+ ...processState,
31036
+ cortexkit_user_config_path: paths.userConfigPath,
31037
+ config: readConfigTiers(paths)
31038
+ };
31128
31039
  }
31129
31040
  function loadAftConfig(projectDirectory) {
31130
31041
  configLoadErrors = [];
31131
- const userBasePath = join10(getGlobalPiDir(), "aft");
31132
- migrateAftConfigFile(`${userBasePath}.jsonc`);
31133
- migrateAftConfigFile(`${userBasePath}.json`);
31134
- const userDetected = detectConfigFile(userBasePath);
31135
- const userConfigPath = userDetected.format !== "none" ? userDetected.path : `${userBasePath}.json`;
31136
- const projectBasePath = join10(projectDirectory, ".pi", "aft");
31137
- migrateAftConfigFile(`${projectBasePath}.jsonc`);
31138
- migrateAftConfigFile(`${projectBasePath}.json`);
31139
- const projectDetected = detectConfigFile(projectBasePath);
31140
- const projectConfigPath = projectDetected.format !== "none" ? projectDetected.path : `${projectBasePath}.json`;
31042
+ const { userConfigPath, projectConfigPath } = resolveAftConfigPaths(projectDirectory);
31141
31043
  let config2 = loadConfigFromPath(userConfigPath) ?? {};
31142
31044
  const projectConfig = loadConfigFromPath(projectConfigPath);
31143
31045
  if (projectConfig) {
@@ -31162,56 +31064,56 @@ import { spawn as spawn2 } from "node:child_process";
31162
31064
  import { createHash as createHash3 } from "node:crypto";
31163
31065
  import {
31164
31066
  createReadStream,
31165
- existsSync as existsSync8,
31067
+ existsSync as existsSync9,
31166
31068
  mkdirSync as mkdirSync7,
31167
- readFileSync as readFileSync7,
31168
- renameSync as renameSync5,
31169
- rmSync as rmSync3,
31170
- statSync as statSync5,
31171
- writeFileSync as writeFileSync5
31069
+ readFileSync as readFileSync9,
31070
+ renameSync as renameSync6,
31071
+ rmSync as rmSync4,
31072
+ statSync as statSync6,
31073
+ writeFileSync as writeFileSync6
31172
31074
  } from "node:fs";
31173
- import { join as join13 } from "node:path";
31075
+ import { join as join12 } from "node:path";
31174
31076
 
31175
31077
  // src/lsp-cache.ts
31176
31078
  import {
31177
- closeSync as closeSync4,
31079
+ closeSync as closeSync5,
31178
31080
  mkdirSync as mkdirSync6,
31179
- openSync as openSync4,
31180
- readFileSync as readFileSync5,
31181
- statSync as statSync4,
31182
- unlinkSync as unlinkSync5,
31183
- writeFileSync as writeFileSync4
31081
+ openSync as openSync5,
31082
+ readFileSync as readFileSync7,
31083
+ statSync as statSync5,
31084
+ unlinkSync as unlinkSync6,
31085
+ writeFileSync as writeFileSync5
31184
31086
  } from "node:fs";
31185
31087
  import { homedir as homedir10 } from "node:os";
31186
- import { join as join11 } from "node:path";
31088
+ import { join as join10 } from "node:path";
31187
31089
  function aftCacheBase() {
31188
31090
  const override = process.env.AFT_CACHE_DIR;
31189
31091
  if (override && override.length > 0)
31190
31092
  return override;
31191
31093
  if (process.platform === "win32") {
31192
31094
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
31193
- const base2 = localAppData || join11(homedir10(), "AppData", "Local");
31194
- return join11(base2, "aft");
31095
+ const base2 = localAppData || join10(homedir10(), "AppData", "Local");
31096
+ return join10(base2, "aft");
31195
31097
  }
31196
- const base = process.env.XDG_CACHE_HOME || join11(homedir10(), ".cache");
31197
- return join11(base, "aft");
31098
+ const base = process.env.XDG_CACHE_HOME || join10(homedir10(), ".cache");
31099
+ return join10(base, "aft");
31198
31100
  }
31199
31101
  function lspCacheRoot() {
31200
- return join11(aftCacheBase(), "lsp-packages");
31102
+ return join10(aftCacheBase(), "lsp-packages");
31201
31103
  }
31202
31104
  function lspPackageDir(npmPackage) {
31203
- return join11(lspCacheRoot(), encodeURIComponent(npmPackage));
31105
+ return join10(lspCacheRoot(), encodeURIComponent(npmPackage));
31204
31106
  }
31205
31107
  function lspBinaryPath(npmPackage, binary) {
31206
- return join11(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
31108
+ return join10(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
31207
31109
  }
31208
31110
  function lspBinDir(npmPackage) {
31209
- return join11(lspPackageDir(npmPackage), "node_modules", ".bin");
31111
+ return join10(lspPackageDir(npmPackage), "node_modules", ".bin");
31210
31112
  }
31211
31113
  function isInstalled(npmPackage, binary) {
31212
31114
  for (const candidate of lspBinaryCandidates(binary)) {
31213
31115
  try {
31214
- if (statSync4(join11(lspBinDir(npmPackage), candidate)).isFile())
31116
+ if (statSync5(join10(lspBinDir(npmPackage), candidate)).isFile())
31215
31117
  return true;
31216
31118
  } catch {}
31217
31119
  }
@@ -31231,17 +31133,17 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
31231
31133
  installedAt: new Date().toISOString(),
31232
31134
  ...sha256 ? { sha256 } : {}
31233
31135
  };
31234
- writeFileSync4(join11(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
31136
+ writeFileSync5(join10(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
31235
31137
  } catch (err) {
31236
31138
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
31237
31139
  }
31238
31140
  }
31239
31141
  function readInstalledMetaIn(installDir) {
31240
- const path3 = join11(installDir, INSTALLED_META_FILE);
31142
+ const path3 = join10(installDir, INSTALLED_META_FILE);
31241
31143
  try {
31242
- if (!statSync4(path3).isFile())
31144
+ if (!statSync5(path3).isFile())
31243
31145
  return null;
31244
- const raw = readFileSync5(path3, "utf8");
31146
+ const raw = readFileSync7(path3, "utf8");
31245
31147
  const parsed = JSON.parse(raw);
31246
31148
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
31247
31149
  return null;
@@ -31261,7 +31163,7 @@ function readInstalledMeta(packageKey) {
31261
31163
  return readInstalledMetaIn(lspPackageDir(packageKey));
31262
31164
  }
31263
31165
  function lockPath(npmPackage) {
31264
- return join11(lspPackageDir(npmPackage), ".aft-installing");
31166
+ return join10(lspPackageDir(npmPackage), ".aft-installing");
31265
31167
  }
31266
31168
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
31267
31169
  function acquireInstallLock(lockKey) {
@@ -31269,13 +31171,13 @@ function acquireInstallLock(lockKey) {
31269
31171
  const lock = lockPath(lockKey);
31270
31172
  const tryClaim = () => {
31271
31173
  try {
31272
- const fd = openSync4(lock, "wx");
31174
+ const fd = openSync5(lock, "wx");
31273
31175
  try {
31274
- writeFileSync4(fd, `${process.pid}
31176
+ writeFileSync5(fd, `${process.pid}
31275
31177
  ${new Date().toISOString()}
31276
31178
  `);
31277
31179
  } finally {
31278
- closeSync4(fd);
31180
+ closeSync5(fd);
31279
31181
  }
31280
31182
  return true;
31281
31183
  } catch (err) {
@@ -31291,12 +31193,12 @@ ${new Date().toISOString()}
31291
31193
  let owningPid = null;
31292
31194
  let lockMtimeMs = 0;
31293
31195
  try {
31294
- const raw = readFileSync5(lock, "utf8");
31196
+ const raw = readFileSync7(lock, "utf8");
31295
31197
  const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
31296
31198
  const parsed = Number.parseInt(firstLine, 10);
31297
31199
  if (Number.isFinite(parsed) && parsed > 0)
31298
31200
  owningPid = parsed;
31299
- lockMtimeMs = statSync4(lock).mtimeMs;
31201
+ lockMtimeMs = statSync5(lock).mtimeMs;
31300
31202
  } catch {
31301
31203
  return tryClaim();
31302
31204
  }
@@ -31309,7 +31211,7 @@ ${new Date().toISOString()}
31309
31211
  }
31310
31212
  log2(`[lsp] reclaiming install lock for ${lockKey} (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
31311
31213
  try {
31312
- unlinkSync5(lock);
31214
+ unlinkSync6(lock);
31313
31215
  } catch {}
31314
31216
  return tryClaim();
31315
31217
  }
@@ -31329,7 +31231,7 @@ function releaseInstallLock(lockKey) {
31329
31231
  try {
31330
31232
  let owningPid = null;
31331
31233
  try {
31332
- const raw = readFileSync5(lock, "utf8");
31234
+ const raw = readFileSync7(lock, "utf8");
31333
31235
  const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
31334
31236
  const parsed = Number.parseInt(firstLine, 10);
31335
31237
  if (Number.isFinite(parsed) && parsed > 0)
@@ -31346,7 +31248,7 @@ function releaseInstallLock(lockKey) {
31346
31248
  return;
31347
31249
  }
31348
31250
  try {
31349
- unlinkSync5(lock);
31251
+ unlinkSync6(lock);
31350
31252
  } catch (unlinkErr) {
31351
31253
  const code = unlinkErr.code;
31352
31254
  if (code !== "ENOENT") {
@@ -31368,9 +31270,9 @@ async function withInstallLock(lockKey, task) {
31368
31270
  }
31369
31271
  var VERSION_CHECK_FILE = ".aft-version-check";
31370
31272
  function readVersionCheck(npmPackage) {
31371
- const file2 = join11(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31273
+ const file2 = join10(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31372
31274
  try {
31373
- const raw = readFileSync5(file2, "utf8");
31275
+ const raw = readFileSync7(file2, "utf8");
31374
31276
  const parsed = JSON.parse(raw);
31375
31277
  if (typeof parsed.last_checked === "string") {
31376
31278
  return {
@@ -31385,12 +31287,12 @@ function readVersionCheck(npmPackage) {
31385
31287
  }
31386
31288
  function writeVersionCheck(npmPackage, latest) {
31387
31289
  mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
31388
- const file2 = join11(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31290
+ const file2 = join10(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
31389
31291
  const record2 = {
31390
31292
  last_checked: new Date().toISOString(),
31391
31293
  latest_eligible: latest
31392
31294
  };
31393
- writeFileSync4(file2, JSON.stringify(record2, null, 2));
31295
+ writeFileSync5(file2, JSON.stringify(record2, null, 2));
31394
31296
  }
31395
31297
  function shouldRecheckVersion(record2, weeklyCheckIntervalMs = 7 * 24 * 60 * 60 * 1000) {
31396
31298
  if (!record2)
@@ -31547,8 +31449,8 @@ var NPM_LSP_TABLE = [
31547
31449
  ];
31548
31450
 
31549
31451
  // src/lsp-project-relevance.ts
31550
- import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync6 } from "node:fs";
31551
- import { join as join12 } from "node:path";
31452
+ import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "node:fs";
31453
+ import { join as join11 } from "node:path";
31552
31454
  var MAX_WALK_DIRS = 200;
31553
31455
  var MAX_WALK_DEPTH = 4;
31554
31456
  var NOISE_DIRS = new Set([
@@ -31565,7 +31467,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
31565
31467
  if (!rootMarkers)
31566
31468
  return false;
31567
31469
  for (const marker of rootMarkers) {
31568
- if (existsSync7(join12(projectRoot, marker)))
31470
+ if (existsSync8(join11(projectRoot, marker)))
31569
31471
  return true;
31570
31472
  }
31571
31473
  return false;
@@ -31589,7 +31491,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
31589
31491
  }
31590
31492
  function readPackageJson(projectRoot) {
31591
31493
  try {
31592
- const raw = readFileSync6(join12(projectRoot, "package.json"), "utf8");
31494
+ const raw = readFileSync8(join11(projectRoot, "package.json"), "utf8");
31593
31495
  const parsed = JSON.parse(raw);
31594
31496
  if (typeof parsed !== "object" || parsed === null)
31595
31497
  return null;
@@ -31619,7 +31521,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
31619
31521
  for (const entry of entries) {
31620
31522
  if (entry.isDirectory()) {
31621
31523
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
31622
- queue.push({ dir: join12(current.dir, entry.name), depth: current.depth + 1 });
31524
+ queue.push({ dir: join11(current.dir, entry.name), depth: current.depth + 1 });
31623
31525
  }
31624
31526
  continue;
31625
31527
  }
@@ -31746,9 +31648,9 @@ async function resolveTargetVersion(spec, config2, fetchImpl = fetch) {
31746
31648
  }
31747
31649
  function ensureInstallAnchor(cwd) {
31748
31650
  try {
31749
- const stub = join13(cwd, "package.json");
31750
- if (!existsSync8(stub)) {
31751
- writeFileSync5(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
31651
+ const stub = join12(cwd, "package.json");
31652
+ if (!existsSync9(stub)) {
31653
+ writeFileSync6(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
31752
31654
  `);
31753
31655
  }
31754
31656
  } catch (err) {
@@ -31756,18 +31658,18 @@ function ensureInstallAnchor(cwd) {
31756
31658
  }
31757
31659
  }
31758
31660
  function runInstall(spec, version2, cwd, signal) {
31759
- return new Promise((resolve3) => {
31661
+ return new Promise((resolve7) => {
31760
31662
  const target = `${spec.npm}@${version2}`;
31761
31663
  log2(`[lsp] installing ${target} to ${cwd}`);
31762
31664
  if (signal?.aborted) {
31763
31665
  warn2(`[lsp] install ${target} aborted before spawn`);
31764
- resolve3(false);
31666
+ resolve7(false);
31765
31667
  return;
31766
31668
  }
31767
31669
  const npm = resolveNpm();
31768
31670
  if (!npm) {
31769
31671
  warn2(`[lsp] npm not found on PATH or known locations; cannot install ${target}`);
31770
- resolve3(false);
31672
+ resolve7(false);
31771
31673
  return;
31772
31674
  }
31773
31675
  ensureInstallAnchor(cwd);
@@ -31790,7 +31692,7 @@ function runInstall(spec, version2, cwd, signal) {
31790
31692
  return;
31791
31693
  settled = true;
31792
31694
  cleanup();
31793
- resolve3(ok);
31695
+ resolve7(ok);
31794
31696
  };
31795
31697
  const onAbort = () => {
31796
31698
  warn2(`[lsp] install ${target} aborted during shutdown`);
@@ -31891,7 +31793,7 @@ function cachedPackageDir(npmPackage) {
31891
31793
  return lspBinDir(npmPackage).replace(/[\\/]node_modules[\\/]\.bin[\\/]?$/, "");
31892
31794
  }
31893
31795
  function hashInstalledBinary(spec) {
31894
- return new Promise((resolve3, reject) => {
31796
+ return new Promise((resolve7, reject) => {
31895
31797
  const candidates = process.platform === "win32" ? [
31896
31798
  lspBinaryPath(spec.npm, spec.binary),
31897
31799
  lspBinaryPath(spec.npm, `${spec.binary}.cmd`),
@@ -31901,7 +31803,7 @@ function hashInstalledBinary(spec) {
31901
31803
  let pathToHash = null;
31902
31804
  for (const p of candidates) {
31903
31805
  try {
31904
- if (statSync5(p).isFile()) {
31806
+ if (statSync6(p).isFile()) {
31905
31807
  pathToHash = p;
31906
31808
  break;
31907
31809
  }
@@ -31915,7 +31817,7 @@ function hashInstalledBinary(spec) {
31915
31817
  const stream = createReadStream(pathToHash);
31916
31818
  stream.on("error", reject);
31917
31819
  stream.on("data", (chunk) => hash2.update(chunk));
31918
- stream.on("end", () => resolve3(hash2.digest("hex")));
31820
+ stream.on("end", () => resolve7(hash2.digest("hex")));
31919
31821
  });
31920
31822
  }
31921
31823
  function installedBinaryPath(spec) {
@@ -31927,23 +31829,23 @@ function installedBinaryPath(spec) {
31927
31829
  ] : [lspBinaryPath(spec.npm, spec.binary)];
31928
31830
  for (const candidate of candidates) {
31929
31831
  try {
31930
- if (statSync5(candidate).isFile())
31832
+ if (statSync6(candidate).isFile())
31931
31833
  return candidate;
31932
31834
  } catch {}
31933
31835
  }
31934
31836
  return null;
31935
31837
  }
31936
31838
  function sha256OfFileSync(path3) {
31937
- return createHash3("sha256").update(readFileSync7(path3)).digest("hex");
31839
+ return createHash3("sha256").update(readFileSync9(path3)).digest("hex");
31938
31840
  }
31939
31841
  function quarantineCachedNpmInstall(spec, reason) {
31940
31842
  const packageDir = lspPackageDir(spec.npm);
31941
- const dest = join13(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
31843
+ const dest = join12(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
31942
31844
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
31943
31845
  try {
31944
- mkdirSync7(join13(dest, ".."), { recursive: true });
31945
- rmSync3(dest, { recursive: true, force: true });
31946
- renameSync5(packageDir, dest);
31846
+ mkdirSync7(join12(dest, ".."), { recursive: true });
31847
+ rmSync4(dest, { recursive: true, force: true });
31848
+ renameSync6(packageDir, dest);
31947
31849
  } catch (err) {
31948
31850
  warn2(`[lsp] tofu_mismatch ${spec.npm}: failed to quarantine cache entry: ${err}`);
31949
31851
  }
@@ -32023,20 +31925,20 @@ import {
32023
31925
  copyFileSync as copyFileSync4,
32024
31926
  createReadStream as createReadStream2,
32025
31927
  createWriteStream as createWriteStream3,
32026
- existsSync as existsSync9,
31928
+ existsSync as existsSync10,
32027
31929
  lstatSync as lstatSync2,
32028
31930
  mkdirSync as mkdirSync8,
32029
31931
  readdirSync as readdirSync4,
32030
- readFileSync as readFileSync8,
31932
+ readFileSync as readFileSync10,
32031
31933
  readlinkSync as readlinkSync2,
32032
31934
  realpathSync as realpathSync3,
32033
- renameSync as renameSync6,
32034
- rmSync as rmSync4,
32035
- statSync as statSync6,
32036
- unlinkSync as unlinkSync6,
32037
- writeFileSync as writeFileSync6
31935
+ renameSync as renameSync7,
31936
+ rmSync as rmSync5,
31937
+ statSync as statSync7,
31938
+ unlinkSync as unlinkSync7,
31939
+ writeFileSync as writeFileSync7
32038
31940
  } from "node:fs";
32039
- import { dirname as dirname5, join as join14, relative as relative3, resolve as resolve3 } from "node:path";
31941
+ import { dirname as dirname5, join as join13, relative as relative3, resolve as resolve7 } from "node:path";
32040
31942
  import { Readable as Readable3 } from "node:stream";
32041
31943
  import { pipeline as pipeline3 } from "node:stream/promises";
32042
31944
 
@@ -32126,26 +32028,26 @@ function detectHostPlatform() {
32126
32028
 
32127
32029
  // src/lsp-github-install.ts
32128
32030
  function ghCacheRoot() {
32129
- return join14(aftCacheBase(), "lsp-binaries");
32031
+ return join13(aftCacheBase(), "lsp-binaries");
32130
32032
  }
32131
32033
  function ghPackageDir(spec) {
32132
- return join14(ghCacheRoot(), spec.id);
32034
+ return join13(ghCacheRoot(), spec.id);
32133
32035
  }
32134
32036
  function ghBinDir(spec) {
32135
- return join14(ghPackageDir(spec), "bin");
32037
+ return join13(ghPackageDir(spec), "bin");
32136
32038
  }
32137
32039
  function ghExtractDir(spec) {
32138
- return join14(ghPackageDir(spec), "extracted");
32040
+ return join13(ghPackageDir(spec), "extracted");
32139
32041
  }
32140
32042
  var INSTALLED_META_FILE2 = ".aft-installed";
32141
32043
  function ghBinaryPath(spec, platform) {
32142
32044
  const ext = platform === "win32" ? ".exe" : "";
32143
- return join14(ghBinDir(spec), `${spec.binary}${ext}`);
32045
+ return join13(ghBinDir(spec), `${spec.binary}${ext}`);
32144
32046
  }
32145
32047
  function isGithubInstalled(spec, platform) {
32146
32048
  for (const candidate of ghBinaryCandidates(spec, platform)) {
32147
32049
  try {
32148
- if (statSync6(join14(ghBinDir(spec), candidate)).isFile())
32050
+ if (statSync7(join13(ghBinDir(spec), candidate)).isFile())
32149
32051
  return true;
32150
32052
  } catch {}
32151
32053
  }
@@ -32158,10 +32060,10 @@ function ghBinaryCandidates(spec, platform) {
32158
32060
  }
32159
32061
  function readGithubInstalledMetaIn(installDir) {
32160
32062
  try {
32161
- const path3 = join14(installDir, INSTALLED_META_FILE2);
32162
- if (!statSync6(path3).isFile())
32063
+ const path3 = join13(installDir, INSTALLED_META_FILE2);
32064
+ if (!statSync7(path3).isFile())
32163
32065
  return null;
32164
- const parsed = JSON.parse(readFileSync8(path3, "utf8"));
32066
+ const parsed = JSON.parse(readFileSync10(path3, "utf8"));
32165
32067
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
32166
32068
  return null;
32167
32069
  return {
@@ -32185,7 +32087,7 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
32185
32087
  binarySha256,
32186
32088
  ...archiveSha256 ? { archiveSha256 } : {}
32187
32089
  };
32188
- writeFileSync6(join14(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
32090
+ writeFileSync7(join13(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
32189
32091
  } catch (err) {
32190
32092
  warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
32191
32093
  }
@@ -32193,16 +32095,16 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
32193
32095
  var MAX_DOWNLOAD_BYTES3 = 256 * 1024 * 1024;
32194
32096
  var MAX_EXTRACT_BYTES2 = 1024 * 1024 * 1024;
32195
32097
  function sha256OfFile(path3) {
32196
- return new Promise((resolve4, reject) => {
32098
+ return new Promise((resolve8, reject) => {
32197
32099
  const hash2 = createHash4("sha256");
32198
32100
  const stream = createReadStream2(path3);
32199
32101
  stream.on("error", reject);
32200
32102
  stream.on("data", (chunk) => hash2.update(chunk));
32201
- stream.on("end", () => resolve4(hash2.digest("hex")));
32103
+ stream.on("end", () => resolve8(hash2.digest("hex")));
32202
32104
  });
32203
32105
  }
32204
32106
  function sha256OfFileSync2(path3) {
32205
- return createHash4("sha256").update(readFileSync8(path3)).digest("hex");
32107
+ return createHash4("sha256").update(readFileSync10(path3)).digest("hex");
32206
32108
  }
32207
32109
  async function fetchReleaseByTag(githubRepo, tag, fetchImpl, signal) {
32208
32110
  const candidates = [];
@@ -32395,7 +32297,7 @@ async function downloadFile(url2, destPath, fetchImpl, assetSize, signal) {
32395
32297
  await pipeline3(nodeStream, createWriteStream3(destPath), { signal: timeout.signal });
32396
32298
  } catch (err) {
32397
32299
  try {
32398
- unlinkSync6(destPath);
32300
+ unlinkSync7(destPath);
32399
32301
  } catch {}
32400
32302
  throw err;
32401
32303
  } finally {
@@ -32434,7 +32336,7 @@ function validateExtraction(stagingRoot) {
32434
32336
  throw new Error(`failed to read staging dir ${dir}: ${err}`);
32435
32337
  }
32436
32338
  for (const entry of entries) {
32437
- const full = join14(dir, entry);
32339
+ const full = join13(dir, entry);
32438
32340
  let lst;
32439
32341
  try {
32440
32342
  lst = lstatSync2(full);
@@ -32455,7 +32357,7 @@ function validateExtraction(stagingRoot) {
32455
32357
  throw new Error(`failed to realpath ${full}: ${err}`);
32456
32358
  }
32457
32359
  const rel = relative3(realStagingRoot, realFull);
32458
- if (rel.startsWith("..") || resolve3(realStagingRoot, rel) !== realFull) {
32360
+ if (rel.startsWith("..") || resolve7(realStagingRoot, rel) !== realFull) {
32459
32361
  throw new Error(`archive entry escapes staging root: ${full} → ${realFull} (zip-slip defense)`);
32460
32362
  }
32461
32363
  if (lst.isDirectory()) {
@@ -32502,7 +32404,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
32502
32404
  const suffix = randomBytes(8).toString("hex");
32503
32405
  const stagingDir = `${destDir}.staging-${suffix}`;
32504
32406
  try {
32505
- rmSync4(stagingDir, { recursive: true, force: true });
32407
+ rmSync5(stagingDir, { recursive: true, force: true });
32506
32408
  } catch {}
32507
32409
  mkdirSync8(stagingDir, { recursive: true });
32508
32410
  try {
@@ -32510,24 +32412,24 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
32510
32412
  runPlatformExtractor(archivePath, stagingDir, archiveType);
32511
32413
  validateExtraction(stagingDir);
32512
32414
  try {
32513
- rmSync4(destDir, { recursive: true, force: true });
32415
+ rmSync5(destDir, { recursive: true, force: true });
32514
32416
  } catch {}
32515
- renameSync6(stagingDir, destDir);
32417
+ renameSync7(stagingDir, destDir);
32516
32418
  } catch (err) {
32517
32419
  try {
32518
- rmSync4(stagingDir, { recursive: true, force: true });
32420
+ rmSync5(stagingDir, { recursive: true, force: true });
32519
32421
  } catch {}
32520
32422
  throw err;
32521
32423
  }
32522
32424
  }
32523
32425
  function quarantineCachedGithubInstall(spec, reason) {
32524
32426
  const packageDir = ghPackageDir(spec);
32525
- const dest = join14(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
32427
+ const dest = join13(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
32526
32428
  warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
32527
32429
  try {
32528
32430
  mkdirSync8(dirname5(dest), { recursive: true });
32529
- rmSync4(dest, { recursive: true, force: true });
32530
- renameSync6(packageDir, dest);
32431
+ rmSync5(dest, { recursive: true, force: true });
32432
+ renameSync7(packageDir, dest);
32531
32433
  } catch (err) {
32532
32434
  warn2(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
32533
32435
  }
@@ -32535,9 +32437,9 @@ function quarantineCachedGithubInstall(spec, reason) {
32535
32437
  function validateCachedGithubInstall(spec, platform) {
32536
32438
  const packageDir = ghPackageDir(spec);
32537
32439
  const meta3 = readGithubInstalledMetaIn(packageDir);
32538
- const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join14(ghBinDir(spec), candidate)).find((candidate) => {
32440
+ const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join13(ghBinDir(spec), candidate)).find((candidate) => {
32539
32441
  try {
32540
- return statSync6(candidate).isFile();
32442
+ return statSync7(candidate).isFile();
32541
32443
  } catch {
32542
32444
  return false;
32543
32445
  }
@@ -32613,7 +32515,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
32613
32515
  }
32614
32516
  const pkgDir = ghPackageDir(spec);
32615
32517
  const extractDir = ghExtractDir(spec);
32616
- const archivePath = join14(pkgDir, expected.name);
32518
+ const archivePath = join13(pkgDir, expected.name);
32617
32519
  log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
32618
32520
  try {
32619
32521
  await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
@@ -32627,7 +32529,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
32627
32529
  } catch (err) {
32628
32530
  error2(`[lsp] hash ${spec.id} failed: ${err}`);
32629
32531
  try {
32630
- unlinkSync6(archivePath);
32532
+ unlinkSync7(archivePath);
32631
32533
  } catch {}
32632
32534
  return null;
32633
32535
  }
@@ -32638,7 +32540,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
32638
32540
  if (previousArchiveSha256 !== archiveSha256) {
32639
32541
  error2(`[lsp] ${spec.id} ${tag}: TOFU sha256 mismatch — refusing install. ` + `Previously installed archive sha256=${previousArchiveSha256}, downloaded sha256=${archiveSha256}. ` + `This means the published release for tag ${tag} changed. Investigate before proceeding.`);
32640
32542
  try {
32641
- unlinkSync6(archivePath);
32543
+ unlinkSync7(archivePath);
32642
32544
  } catch {}
32643
32545
  return null;
32644
32546
  }
@@ -32650,11 +32552,11 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
32650
32552
  return null;
32651
32553
  } finally {
32652
32554
  try {
32653
- unlinkSync6(archivePath);
32555
+ unlinkSync7(archivePath);
32654
32556
  } catch {}
32655
32557
  }
32656
- const innerBinaryPath = join14(extractDir, spec.binaryPathInArchive(platform, arch, version2));
32657
- if (!existsSync9(innerBinaryPath)) {
32558
+ const innerBinaryPath = join13(extractDir, spec.binaryPathInArchive(platform, arch, version2));
32559
+ if (!existsSync10(innerBinaryPath)) {
32658
32560
  error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
32659
32561
  return null;
32660
32562
  }
@@ -32738,7 +32640,7 @@ function runGithubAutoInstall(relevantServers, config2, fetchImpl = fetch) {
32738
32640
  if (!host) {
32739
32641
  for (const spec of GITHUB_LSP_TABLE) {
32740
32642
  try {
32741
- if (existsSync9(ghBinDir(spec))) {
32643
+ if (existsSync10(ghBinDir(spec))) {
32742
32644
  cachedBinDirs.push(ghBinDir(spec));
32743
32645
  }
32744
32646
  } catch {}
@@ -32908,9 +32810,13 @@ function warningTitle(warning) {
32908
32810
  return "LSP binary is missing";
32909
32811
  case "config_parse_failed":
32910
32812
  return "Config failed to parse";
32813
+ case "config_key_dropped":
32814
+ return "Config key ignored";
32911
32815
  }
32912
32816
  }
32913
32817
  function formatConfigureWarning(warning) {
32818
+ if (warning.kind === "config_key_dropped")
32819
+ return `${WARNING_MARKER} ${warning.hint}`;
32914
32820
  const details = [];
32915
32821
  if (warning.language)
32916
32822
  details.push(`language: ${warning.language}`);
@@ -33053,7 +32959,7 @@ function renderScreen(state, rows = state.rows, cols = state.cols) {
33053
32959
  `);
33054
32960
  }
33055
32961
  function writeTerminal(terminal, data) {
33056
- return new Promise((resolve4) => terminal.write(data, resolve4));
32962
+ return new Promise((resolve8) => terminal.write(data, resolve8));
33057
32963
  }
33058
32964
 
33059
32965
  // src/shutdown-hooks.ts
@@ -33110,8 +33016,8 @@ function installProcessHandlers() {
33110
33016
  }
33111
33017
  signalShutdownStarted = true;
33112
33018
  process.exitCode = SIGNAL_EXIT_CODES[sig];
33113
- const timeout = new Promise((resolve4) => {
33114
- setTimeout(resolve4, SIGNAL_CLEANUP_TIMEOUT_MS);
33019
+ const timeout = new Promise((resolve8) => {
33020
+ setTimeout(resolve8, SIGNAL_CLEANUP_TIMEOUT_MS);
33115
33021
  });
33116
33022
  Promise.race([runCleanups(sig), timeout]).finally(() => {
33117
33023
  process.exit(SIGNAL_EXIT_CODES[sig]);
@@ -33154,7 +33060,7 @@ import { Type as Type3 } from "typebox";
33154
33060
  // src/tools/hoisted.ts
33155
33061
  import { stat } from "node:fs/promises";
33156
33062
  import { homedir as homedir11 } from "node:os";
33157
- import { isAbsolute as isAbsolute4, relative as relative4, resolve as resolve4, sep } from "node:path";
33063
+ import { isAbsolute as isAbsolute5, relative as relative4, resolve as resolve8, sep } from "node:path";
33158
33064
  import {
33159
33065
  renderDiff
33160
33066
  } from "@earendil-works/pi-coding-agent";
@@ -33269,7 +33175,7 @@ function diagnosticsOnEditDefault(ctx) {
33269
33175
  }
33270
33176
  function containsPath(parent, child) {
33271
33177
  const rel = relative4(parent, child);
33272
- return rel === "" || !rel.startsWith("..") && !isAbsolute4(rel);
33178
+ return rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
33273
33179
  }
33274
33180
  function expandTilde2(path3) {
33275
33181
  if (!path3 || !path3.startsWith("~"))
@@ -33277,13 +33183,13 @@ function expandTilde2(path3) {
33277
33183
  if (path3 === "~")
33278
33184
  return homedir11();
33279
33185
  if (path3.startsWith(`~${sep}`) || path3.startsWith("~/")) {
33280
- return resolve4(homedir11(), path3.slice(2));
33186
+ return resolve8(homedir11(), path3.slice(2));
33281
33187
  }
33282
33188
  return path3;
33283
33189
  }
33284
33190
  function absoluteSearchPath(cwd, target) {
33285
33191
  const expanded = expandTilde2(target);
33286
- return isAbsolute4(expanded) ? expanded : resolve4(cwd, expanded);
33192
+ return isAbsolute5(expanded) ? expanded : resolve8(cwd, expanded);
33287
33193
  }
33288
33194
  async function searchPathExists(cwd, target) {
33289
33195
  try {
@@ -33339,7 +33245,7 @@ async function assertExternalDirectoryPermission(extCtx, target, options = {}) {
33339
33245
  if (!target)
33340
33246
  return;
33341
33247
  const expanded = expandTilde2(target);
33342
- const absoluteTarget = isAbsolute4(expanded) ? expanded : resolve4(extCtx.cwd, expanded);
33248
+ const absoluteTarget = isAbsolute5(expanded) ? expanded : resolve8(extCtx.cwd, expanded);
33343
33249
  if (containsPath(extCtx.cwd, absoluteTarget))
33344
33250
  return;
33345
33251
  if (options.restrictToProjectRoot === false)
@@ -33487,7 +33393,7 @@ function registerHoistedTools(pi, ctx, surface) {
33487
33393
  diagnostics: diagnosticsOnEditDefault(ctx),
33488
33394
  include_diff_content: true
33489
33395
  };
33490
- if (params.replaceAll === true)
33396
+ if (coerceBoolean(params.replaceAll))
33491
33397
  req.replace_all = true;
33492
33398
  const occurrence = coerceOptionalInt(params.occurrence, "occurrence", 0, Number.MAX_SAFE_INTEGER);
33493
33399
  if (occurrence !== undefined)
@@ -34108,7 +34014,7 @@ function registerAstTools(pi, ctx, surface) {
34108
34014
  req.paths = paths;
34109
34015
  if (!isEmptyParam(params.globs))
34110
34016
  req.globs = params.globs;
34111
- req.dry_run = params.dryRun === true;
34017
+ req.dry_run = coerceBoolean(params.dryRun);
34112
34018
  const response = await callBridge(bridge, "ast_replace", req, extCtx);
34113
34019
  return textResult(response.text ?? JSON.stringify(response));
34114
34020
  },
@@ -34259,8 +34165,8 @@ function registerBashTool(pi, ctx, aftSearchRegistered = false) {
34259
34165
  const spawnHook = getBashSpawnHook(pi);
34260
34166
  const searchSteer = aftSearchRegistered ? "use `aft_search` (concepts, identifiers, regex, literals), `read`, `aft_outline`, or `aft_zoom` instead" : "use the `grep` tool, `read`, `aft_outline`, or `aft_zoom` instead";
34261
34167
  const bashCfg = resolveBashConfig(ctx.config);
34262
- const compressionSentence = bashCfg.compress ? " Output is compressed by default; pass `compressed: false` for raw output." : "";
34263
- const tasksSentence = bashCfg.background ? ' Pass `background: true` to run in the background and get a task_id for `bash_status`/`bash_watch`/`bash_kill`. Pass `pty: true` for interactive programs (REPLs, TUIs) and drive them with `bash_status({ output_mode: "screen" })` plus `bash_write`. Use `bash_watch` to wait for exit or output patterns (sync blocks, async notifies). Do not loop `bash_status` to wait.' : " Commands run in the foreground to completion; `timeout` is the hard kill cap (default 30 minutes).";
34168
+ const compressionSentence = bashCfg.compress ? " Output is compressed by default; pass `compressed: false` for raw output. Piped commands run verbatim and show the pipeline's output; for AFT's test/build summary, run the runner without `| head`, `| tail`, or `| grep`." : "";
34169
+ const tasksSentence = bashCfg.background ? ' Commands run in the foreground and return inline; a long-running one auto-promotes to background and delivers a completion reminder when it finishes — so for the common "I am waiting on this result" case, just run it and wait, no flags needed. Use `background: true` yourself ONLY when you have other useful work to do while it runs; then `bash_watch` waits on the task (sync blocks until exit/pattern, async notifies) and `bash_status` peeks at it — never background a command and immediately `bash_watch` it (that wastes a turn for what foreground returns in one), and never loop `bash_status` to wait. `pty: true` runs interactive programs (REPLs, TUIs), implies background, and is driven with `bash_status({ output_mode: "screen" })` plus `bash_write`.' : " Commands run in the foreground to completion; `timeout` is the hard kill cap (default 30 minutes).";
34264
34170
  pi.registerTool({
34265
34171
  name: "bash",
34266
34172
  label: "bash",
@@ -34270,7 +34176,8 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34270
34176
  promptSnippet: bashCfg.background ? "Run shell commands (timeout in milliseconds; supports workdir, background tasks, compressed output, PTY mode)" : "Run shell commands (timeout in milliseconds; supports workdir and compressed output)",
34271
34177
  promptGuidelines: [
34272
34178
  `DO NOT use bash for code search or exploration — ${searchSteer}.`,
34273
- "Set compressed: false when you need ANSI color codes in the output."
34179
+ "Set compressed: false when you need ANSI color codes in the output.",
34180
+ "Piped commands run verbatim and show the pipeline's output; run test/build tools without pipes when you need AFT's summary."
34274
34181
  ],
34275
34182
  parameters: bashParamsForConfig(bashCfg.background),
34276
34183
  async execute(_toolCallId, params, _signal, onUpdate, extCtx) {
@@ -34281,8 +34188,9 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34281
34188
  const timeout = coerceOptionalInt(params.timeout, "timeout", 1, Number.MAX_SAFE_INTEGER);
34282
34189
  const ptyRows = backgroundDisabled ? undefined : coerceOptionalInt(params.ptyRows, "ptyRows", 1, 60);
34283
34190
  const ptyCols = backgroundDisabled ? undefined : coerceOptionalInt(params.ptyCols, "ptyCols", 1, 140);
34284
- const requestedPty = !backgroundDisabled && params.pty === true;
34285
- const effectiveBackground = !backgroundDisabled && (params.background === true || requestedPty);
34191
+ const compressed = coerceBoolean(params.compressed, true);
34192
+ const requestedPty = !backgroundDisabled && coerceBoolean(params.pty);
34193
+ const effectiveBackground = !backgroundDisabled && (coerceBoolean(params.background) || requestedPty);
34286
34194
  const effectiveTimeout = effectiveBackground || backgroundDisabled ? timeout : resolveBashKillTimeout(timeout, foregroundWaitMs);
34287
34195
  let spawnContext = {
34288
34196
  command: params.command,
@@ -34295,9 +34203,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34295
34203
  throw new Error(`BashSpawnHook failed: ${hookErr instanceof Error ? hookErr.message : String(hookErr)}`);
34296
34204
  }
34297
34205
  }
34298
- const compressionEnabled = bashCfg2.compress && params.compressed !== false;
34299
- const pipeStrip = maybeStripCompressorPipe(spawnContext.command, compressionEnabled);
34300
- const bridgeCommand = pipeStrip.command;
34206
+ const bridgeCommand = spawnContext.command;
34301
34207
  let streamed = "";
34302
34208
  const response = await callBashBridge(bridge, "bash", {
34303
34209
  command: bridgeCommand,
@@ -34307,7 +34213,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34307
34213
  description: params.description,
34308
34214
  background: effectiveBackground,
34309
34215
  notify_on_completion: effectiveBackground,
34310
- compressed: params.compressed,
34216
+ compressed,
34311
34217
  pty: requestedPty,
34312
34218
  pty_rows: ptyRows,
34313
34219
  pty_cols: ptyCols
@@ -34330,7 +34236,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34330
34236
  if (response.status === "running" && taskId) {
34331
34237
  if (effectiveBackground) {
34332
34238
  trackBgTask(resolveSessionId(extCtx), taskId);
34333
- return bashResult(appendPipeStripNote(formatBackgroundLaunch(taskId, requestedPty), pipeStrip.note), { task_id: taskId });
34239
+ return bashResult(formatBackgroundLaunch(taskId, requestedPty), { task_id: taskId });
34334
34240
  }
34335
34241
  const waitTimeoutMs = backgroundDisabled ? effectiveTimeout ?? DEFAULT_HARD_TIMEOUT_MS : effectiveTimeout !== undefined ? Math.min(effectiveTimeout, foregroundWaitMs) : foregroundWaitMs;
34336
34242
  const startedAt = Date.now();
@@ -34340,7 +34246,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34340
34246
  throw new Error(status.message ?? "bash_status failed");
34341
34247
  }
34342
34248
  if (isTerminalStatus(status.status)) {
34343
- return bashResult(appendPipeStripNote(withBashHints(formatForegroundResult(status), bridgeCommand, aftSearchRegistered, extCtx.cwd), pipeStrip.note), {
34249
+ return bashResult(withBashHints(formatForegroundResult(status), bridgeCommand, aftSearchRegistered, extCtx.cwd), {
34344
34250
  exit_code: status.exit_code,
34345
34251
  duration_ms: status.duration_ms,
34346
34252
  truncated: status.output_truncated,
@@ -34358,7 +34264,9 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34358
34264
  throw new Error(promoted.message ?? "bash_promote failed");
34359
34265
  }
34360
34266
  trackBgTask(resolveSessionId(extCtx), taskId);
34361
- return bashResult(appendPipeStripNote(formatPromotionMessage(taskId, effectiveTimeout, foregroundWaitMs), pipeStrip.note), { task_id: taskId });
34267
+ return bashResult(formatPromotionMessage(taskId, effectiveTimeout, foregroundWaitMs), {
34268
+ task_id: taskId
34269
+ });
34362
34270
  }
34363
34271
  await sleep(FOREGROUND_POLL_INTERVAL_MS);
34364
34272
  }
@@ -34371,7 +34279,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
34371
34279
  task_id: taskId
34372
34280
  };
34373
34281
  const output = response.output ?? "";
34374
- return bashResult(appendPipeStripNote(withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), pipeStrip.note), details);
34282
+ return bashResult(withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
34375
34283
  },
34376
34284
  renderCall(args, theme, context) {
34377
34285
  return renderBashCall(args?.command, args?.description, theme, context);
@@ -34425,13 +34333,13 @@ function createBashWatchTool(ctx) {
34425
34333
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
34426
34334
  const bridge = bridgeFor(ctx, extCtx.cwd);
34427
34335
  const waitFor = parseWaitPattern(params.pattern);
34428
- if (params.background === true) {
34336
+ if (coerceBoolean(params.background)) {
34429
34337
  if (!waitFor) {
34430
34338
  throw new Error("invalid_request: Use auto-reminder; bash_watch without pattern in async mode is redundant");
34431
34339
  }
34432
34340
  const notifyParams = {
34433
34341
  task_id: params.task_id,
34434
- once: params.once !== false
34342
+ once: coerceBoolean(params.once, true)
34435
34343
  };
34436
34344
  if (waitFor.kind === "regex")
34437
34345
  notifyParams.regex = waitFor.source;
@@ -34457,7 +34365,7 @@ A notification will fire when the pattern matches or the task exits.`, watchDeta
34457
34365
  }
34458
34366
  const data = await waitForBashStatus(ctx, bridge, extCtx, params.task_id, undefined, waitFor, true, Math.min(coerceOptionalInt(params.timeout_ms, "timeout_ms", 1, MAX_BASH_STATUS_WAIT_TIMEOUT_MS) ?? DEFAULT_BASH_STATUS_WAIT_TIMEOUT_MS, MAX_BASH_STATUS_WAIT_TIMEOUT_MS));
34459
34367
  if (data.waited?.reason === "user_message") {
34460
- const convertedText = await convertToAsyncWatchOnAbort(bridge, extCtx, params.task_id, waitFor, params.once !== false);
34368
+ const convertedText = await convertToAsyncWatchOnAbort(bridge, extCtx, params.task_id, waitFor, coerceBoolean(params.once, true));
34461
34369
  return textResult(convertedText, { waited: data.waited });
34462
34370
  }
34463
34371
  const text = await formatBashStatus(extCtx, params.task_id, data, undefined);
@@ -35059,7 +34967,7 @@ function registerFsTools(pi, ctx, surface) {
35059
34967
  const bridge = bridgeFor(ctx, extCtx.cwd);
35060
34968
  const response = await callBridge(bridge, "delete_file", {
35061
34969
  files,
35062
- recursive: params.recursive === true
34970
+ recursive: coerceBoolean(params.recursive)
35063
34971
  }, extCtx);
35064
34972
  const deletedEntries = response.deleted ?? [];
35065
34973
  const skipped = response.skipped_files ?? [];
@@ -35500,7 +35408,7 @@ function registerInspectTool(pi, ctx) {
35500
35408
  pi.registerTool({
35501
35409
  name: "aft_inspect",
35502
35410
  label: "inspect",
35503
- description: "Codebase health snapshot. One call returns summary stats for: TODOs, diagnostics, file/symbol metrics, dead code, unused exports, code duplicates. Pass `sections` for per-category drill-down details.\n\n" + "Categories run in tiers — Tier 1 (todos, metrics) return synchronously from cache. Tier 2 (dead_code, unused_exports, duplicates) run asynchronously on demand: when a call sees cold `pending_categories: [...]` or stale `stale_categories: [...]`, Pi quietly starts a background Tier 2 warmup (deduped while in-flight and rate-limited per category to at most once every 4 minutes, matching OpenCode's default idle window). The current call may still return pending results while the cache warms; a later call can use cached data.\n\n" + `Use when: starting work on unfamiliar code, after multi-edit batches to check diagnostics, before a refactor, before review, or to verify cleanup completeness.
35411
+ description: "Codebase health snapshot. One call returns summary stats for: TODOs, diagnostics, file/symbol metrics, dead code, unused exports, code duplicates. Pass `sections` for per-category drill-down details.\n\n" + "Categories run in tiers — Tier 1 (todos, metrics) return synchronously from cache. Tier 2 (dead_code, unused_exports, duplicates) waits for a fresh reuse scan up to a short deadline; if a category is still scanning the response reports `complete: false` with `pending_categories: [...]` rather than a fabricated clean count. Pi may still trigger a deduped background warmup for categories that remain pending.\n\n" + `Use when: starting work on unfamiliar code, after multi-edit batches to check diagnostics, before a refactor, before review, or to verify cleanup completeness.
35504
35412
 
35505
35413
  ` + "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.",
35506
35414
  parameters: InspectParams,
@@ -35509,7 +35417,9 @@ function registerInspectTool(pi, ctx) {
35509
35417
  const sections = normalizeStringOrArray(params.sections);
35510
35418
  const scope = await resolveAndGateScope(extCtx, ctx, normalizeStringOrArray(params.scope));
35511
35419
  const topK = validateOptionalTopK(params.topK);
35512
- const response = await callBridge(bridge, "inspect", { sections, scope, topK }, extCtx);
35420
+ const response = await callBridge(bridge, "inspect", { sections, scope, topK }, extCtx, {
35421
+ keepBridgeOnTimeout: true
35422
+ });
35513
35423
  runPendingTier2Categories(bridge, tier2RefreshCategories(response), extCtx);
35514
35424
  const body = response.text;
35515
35425
  if (typeof body === "string") {
@@ -35809,8 +35719,8 @@ Pass a single \`target\`:
35809
35719
  parameters: OutlineParams,
35810
35720
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
35811
35721
  const bridge = bridgeFor(ctx, extCtx.cwd);
35812
- const target = params.target;
35813
- const filesMode = params.files === true;
35722
+ const target = coerceTargetParam(params.target);
35723
+ const filesMode = coerceBoolean(params.files);
35814
35724
  const isArray = Array.isArray(target) && target.length > 0;
35815
35725
  if (filesMode) {
35816
35726
  if (Array.isArray(target)) {
@@ -35908,7 +35818,7 @@ Pass a single \`target\`:
35908
35818
  const hasUrl = !isEmptyParam(params.url);
35909
35819
  const hasTargets = hasTargetsProvided(params.targets);
35910
35820
  const hasSymbols = !isEmptyParam(params.symbols);
35911
- const wantCallgraph = params.callgraph === true;
35821
+ const wantCallgraph = coerceBoolean(params.callgraph);
35912
35822
  if (hasTargets) {
35913
35823
  if (hasFilePath || hasUrl || hasSymbols) {
35914
35824
  throw new Error("'targets' is mutually exclusive with 'filePath', 'url', and 'symbols'");
@@ -36430,6 +36340,10 @@ var SearchParams2 = Type13.Object({
36430
36340
  Type13.Literal("auto")
36431
36341
  ], {
36432
36342
  description: "Optional routing hint. Defaults to 'auto'."
36343
+ })),
36344
+ includeTests: Type13.Optional(Type13.Boolean({
36345
+ default: false,
36346
+ description: "Include test files (*.test.*, *_test.rs, __tests__/, …) plus test-support, fixture, mock, snapshot, and corpus files. Defaults to false."
36433
36347
  }))
36434
36348
  });
36435
36349
  function buildSemanticSections(args, payload, theme) {
@@ -36535,6 +36449,8 @@ function registerSemanticTool(pi, ctx) {
36535
36449
  req.top_k = params.topK;
36536
36450
  if (params.hint !== undefined)
36537
36451
  req.hint = params.hint;
36452
+ if (params.includeTests !== undefined)
36453
+ req.include_tests = params.includeTests;
36538
36454
  const response = await callBridge(bridge, "semantic_search", req, extCtx);
36539
36455
  let agentText = response.text ?? "No results.";
36540
36456
  const extra = extraAgentHonestyNote(response);
@@ -36568,7 +36484,7 @@ function buildWorkflowHints(opts) {
36568
36484
  const hasBgBash = opts.bashBackgroundEnabled && hasBash && !opts.absentTools.has("bash_status");
36569
36485
  if (hasBash && opts.bashCompressionEnabled) {
36570
36486
  sections.push([
36571
- "**Test/build output**: bash output is auto-compressed failures and the summary are always kept. DO NOT pipe test/build commands through filters to summarize; that hides failures:",
36487
+ "**Test/build output**: bash output is auto-compressed for non-piped commands. Piped commands run verbatim and show the pipeline's output. For AFT's test/build summary, run the runner without filters:",
36572
36488
  "- `bun test | grep fail` → run `bun test`",
36573
36489
  "- `cargo test 2>&1 | tail -20` → run `cargo test`",
36574
36490
  "- `npm run build | head -50` → run `npm run build`"
@@ -36607,11 +36523,9 @@ function buildWorkflowHints(opts) {
36607
36523
  }
36608
36524
  if (hasBgBash) {
36609
36525
  sections.push([
36610
- `**Long-running commands** (builds, installs, full test suites): \`${bashName}({ background: true })\` returns a \`task_id\` immediately.`,
36611
- "1. Nothing else useful to do (a build/test/validation whose result is the next thing you need) sync `bash_watch` to block until it exits (pass a longer timeout_ms for long commands; the user can interrupt).",
36612
- "2. Useful parallel work available end your turn; the completion reminder delivers the result. (Or spawn a subagent for the side work.)",
36613
- "3. Want to react to a specific early output line → async `bash_watch` (background:true + pattern).",
36614
- "Never loop `bash_status` to wait — it's a one-shot inspector, not a wait primitive."
36526
+ `**Long-running commands** (builds, installs, full test suites): run them in the FOREGROUND — \`${bashName}({ command })\` waits and returns the result in ONE step, and if it outlives the short wait window it auto-promotes to background and delivers a completion reminder when it finishes. Don't reach for \`background: true\` for the common "I'm waiting on this result" case — that costs an extra turn.`,
36527
+ "- `background: true` is ONLY for when you have OTHER useful work to do while it runs: start it, do the other work, and the completion reminder delivers the result (or spawn a subagent for the side work). Do NOT background a command and then immediately `bash_watch` it that spends a whole extra turn waiting for something foreground returns in one.",
36528
+ "- `bash_watch` is for blocking on an ALREADY-backgrounded task once you've run out of parallel work (sync the user can interrupt), or reacting to a specific early output line (async: background:true + pattern). Never loop `bash_status` to wait — it's a one-shot inspector."
36615
36529
  ].join(`
36616
36530
  `));
36617
36531
  sections.push(`**PTY / interactive commands**: PTY mode is for interactive REPLs and terminal apps (python, node, bash itself, vim). Start with \`${bashName}({ command: "python", pty: true, background: true })\`, read the screen with \`bash_status({ task_id, output_mode: "screen" })\`, and send input with \`bash_write({ task_id, input: "..." })\`.`);
@@ -36713,11 +36627,12 @@ var PLUGIN_VERSION = (() => {
36713
36627
  return "0.0.0";
36714
36628
  }
36715
36629
  })();
36716
- var ANNOUNCEMENT_VERSION = "0.39.0";
36630
+ var ANNOUNCEMENT_VERSION = "0.40.0";
36717
36631
  var ANNOUNCEMENT_FEATURES = [
36718
- "Accurate Rust dead code: constructors and associated functions reached through receiver-type inference are no longer mis-reported as dead.",
36719
- "Code Health scans reparse only the file you changed instead of the whole project on every edit a single-file edit dropped from ~3s of scan work to ~130ms on this repo, byte-identical results.",
36720
- "R language support in outline, zoom, and the AST tools."
36632
+ "Groundwork for Subconscious, the CortexKit daemon: configuration now lives in one place under ~/.config/cortexkit/ and <project>/.cortexkit/ (auto-migrated). The daemon integration is dormant nothing changes in how you run AFT today.",
36633
+ "Bash output never hides a failure: piped commands run exactly as written with their real exit status, cancelled tasks report as failed, and a failing run is never compressed to a clean-looking summary.",
36634
+ "The top aft_search result is now the complete, ready-to-edit symbol (no re-read needed); test files are hidden from results by default.",
36635
+ "format_on_edit is now off by default, and bash commands default to the foreground."
36721
36636
  ];
36722
36637
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
36723
36638
  var ALL_ONLY_TOOLS = new Set(["aft_callgraph", "aft_delete", "aft_move", "aft_refactor"]);
@@ -36726,11 +36641,25 @@ function isConfigureWarning(value) {
36726
36641
  if (!value || typeof value !== "object" || Array.isArray(value))
36727
36642
  return false;
36728
36643
  const warning = value;
36729
- return (warning.kind === "formatter_not_installed" || warning.kind === "checker_not_installed" || warning.kind === "lsp_binary_missing" || warning.kind === "config_parse_failed") && typeof warning.hint === "string";
36644
+ return (warning.kind === "formatter_not_installed" || warning.kind === "checker_not_installed" || warning.kind === "lsp_binary_missing" || warning.kind === "config_parse_failed" || warning.kind === "config_key_dropped") && typeof warning.hint === "string";
36730
36645
  }
36731
36646
  function coerceConfigureWarnings(warnings) {
36732
36647
  return warnings.filter(isConfigureWarning);
36733
36648
  }
36649
+ function isDroppedConfigKey(value) {
36650
+ if (!value || typeof value !== "object" || Array.isArray(value))
36651
+ return false;
36652
+ const dropped = value;
36653
+ return typeof dropped.key === "string" && typeof dropped.tier === "string" && typeof dropped.reason === "string";
36654
+ }
36655
+ function coerceDroppedKeyWarnings(droppedKeys) {
36656
+ if (!Array.isArray(droppedKeys))
36657
+ return [];
36658
+ return formatDroppedKeyWarnings(droppedKeys.filter(isDroppedConfigKey)).map((hint) => ({
36659
+ kind: "config_key_dropped",
36660
+ hint
36661
+ }));
36662
+ }
36734
36663
  function drainPendingEagerWarnings(projectRoot) {
36735
36664
  const pending = pendingEagerWarnings.get(projectRoot) ?? [];
36736
36665
  pendingEagerWarnings.delete(projectRoot);
@@ -36757,7 +36686,10 @@ function bridgeDirectoryFromCallback(bridge, fallback) {
36757
36686
  return typeof cwd === "string" && cwd.length > 0 ? cwd : fallback;
36758
36687
  }
36759
36688
  async function handleConfigureWarningsForSession(context) {
36760
- const validWarnings = coerceConfigureWarnings(context.warnings);
36689
+ const validWarnings = [
36690
+ ...coerceConfigureWarnings(context.warnings),
36691
+ ...coerceDroppedKeyWarnings(context.configDroppedKeys)
36692
+ ];
36761
36693
  if (!context.sessionId) {
36762
36694
  if (validWarnings.length === 0)
36763
36695
  return;
@@ -36855,6 +36787,25 @@ async function src_default(pi) {
36855
36787
  return;
36856
36788
  }
36857
36789
  await ensureStorageMigrated({ harness: "pi", binaryPath, logger: bridgeLogger });
36790
+ const deliverConfigMigrationWarnings = (messages) => {
36791
+ for (const message of messages) {
36792
+ const notify = pi.ui?.notify;
36793
+ if (typeof notify === "function") {
36794
+ try {
36795
+ notify(message, "warning");
36796
+ continue;
36797
+ } catch (err) {
36798
+ warn2(`[config] failed to deliver migration notification: ${err}`);
36799
+ }
36800
+ }
36801
+ try {
36802
+ process.stderr.write(`
36803
+ [AFT] ${message}
36804
+ `);
36805
+ } catch {}
36806
+ }
36807
+ };
36808
+ deliverConfigMigrationWarnings(migrateAftConfigLocations(process.cwd(), bridgeLogger).flatMap((result) => result.warnings));
36858
36809
  const config2 = loadAftConfig(process.cwd());
36859
36810
  enqueueConfigParseWarnings(process.cwd(), getConfigLoadErrors());
36860
36811
  const storageDir = resolveCortexKitStorageRoot();
@@ -36865,10 +36816,9 @@ async function src_default(pi) {
36865
36816
  return null;
36866
36817
  });
36867
36818
  }
36868
- const configOverrides = resolveProjectOverridesForConfigure(config2);
36869
- if (config2.url_fetch_allow_private !== undefined)
36870
- configOverrides.url_fetch_allow_private = config2.url_fetch_allow_private;
36871
- configOverrides.storage_dir = storageDir;
36819
+ const configOverrides = buildConfigTierConfigureParams(process.cwd(), {
36820
+ storage_dir: storageDir
36821
+ });
36872
36822
  try {
36873
36823
  const lspAutoInstall = config2.lsp?.auto_install ?? true;
36874
36824
  const lspGraceDays = config2.lsp?.grace_days ?? 7;
@@ -36936,7 +36886,7 @@ ${lines}
36936
36886
  errorPrefix: "[aft-pi]",
36937
36887
  minVersion: PLUGIN_VERSION,
36938
36888
  onVersionMismatch: createVersionMismatchHandler(() => pool),
36939
- onConfigureWarnings: ({ projectRoot, sessionId, client, warnings }) => {
36889
+ onConfigureWarnings: ({ projectRoot, sessionId, client, warnings, configDroppedKeys }) => {
36940
36890
  const bridge = pool.getActiveBridgeForRoot(projectRoot);
36941
36891
  if (!bridge)
36942
36892
  return;
@@ -36948,6 +36898,7 @@ ${lines}
36948
36898
  client,
36949
36899
  bridge,
36950
36900
  warnings: [...pendingWarnings, ...warnings],
36901
+ configDroppedKeys,
36951
36902
  storageDir,
36952
36903
  pluginVersion: PLUGIN_VERSION
36953
36904
  });
@@ -37007,7 +36958,7 @@ ${lines}
37007
36958
  if (onnxRuntimePromise) {
37008
36959
  await Promise.race([
37009
36960
  onnxRuntimePromise,
37010
- new Promise((resolve5) => setTimeout(() => resolve5(null), 60000))
36961
+ new Promise((resolve9) => setTimeout(() => resolve9(null), 60000))
37011
36962
  ]);
37012
36963
  }
37013
36964
  const bridge = pool.getBridge(cwd);