@cortexkit/aft-opencode 0.58.0 → 0.58.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9574,6 +9574,9 @@ function isTerminalStatus(status) {
9574
9574
  function sleep(ms) {
9575
9575
  return new Promise((resolve) => setTimeout(resolve, ms));
9576
9576
  }
9577
+ function monotonicNowMs() {
9578
+ return performance.now();
9579
+ }
9577
9580
  // ../aft-bridge/dist/bash-hints.js
9578
9581
  import * as fs from "node:fs";
9579
9582
  import * as os from "node:os";
@@ -9584,6 +9587,10 @@ function resolveWatchTimeoutMs(requestedMs, role, capMs) {
9584
9587
  const fallback = role === "worker" ? capMs : DEFAULT_PRIMARY_WATCH_TIMEOUT_MS;
9585
9588
  return Math.min(requestedMs ?? fallback, capMs);
9586
9589
  }
9590
+ function formatWatchWaited(elapsedMs, limitMs, capMs) {
9591
+ const limit = limitMs >= capMs ? `limit ${limitMs}ms, the bash.watch_sync_max_ms cap` : `limit ${limitMs}ms`;
9592
+ return `Waited ${Math.round(elapsedMs)}ms (${limit})`;
9593
+ }
9587
9594
  function watchTimeoutSteer(role, capMs, timeoutParam = "timeoutMs") {
9588
9595
  if (role === "worker") {
9589
9596
  return `The command is still running; this is not a failure. Watch again (${timeoutParam} up to ${capMs}) and don't report a result until it finishes.`;
@@ -9970,7 +9977,7 @@ import { existsSync } from "node:fs";
9970
9977
  import { join as join3 } from "node:path";
9971
9978
 
9972
9979
  // ../aft-bridge/dist/child-process.js
9973
- import { execFileSync as nodeExecFileSync, execSync as nodeExecSync, spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
9980
+ import { execFile as nodeExecFile, execFileSync as nodeExecFileSync, execSync as nodeExecSync, spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
9974
9981
  var HIDDEN = { windowsHide: true };
9975
9982
  function withWindowsHidden(args, takesArgv) {
9976
9983
  const out = [...args];
@@ -9992,6 +9999,7 @@ function hidden(resolve, takesArgv) {
9992
9999
  }
9993
10000
  var spawn = hidden(() => nodeSpawn, true);
9994
10001
  var spawnSync = hidden(() => nodeSpawnSync, true);
10002
+ var execFile = hidden(() => nodeExecFile, true);
9995
10003
  var execFileSync = hidden(() => nodeExecFileSync, true);
9996
10004
  var execSync = hidden(() => nodeExecSync, false);
9997
10005
 
@@ -11318,17 +11326,30 @@ class BinaryBridge {
11318
11326
  }
11319
11327
  }
11320
11328
  onStderrData(data) {
11321
- this.stderrBuffer += data;
11322
- let newlineIdx;
11323
- while ((newlineIdx = this.stderrBuffer.indexOf(`
11324
- `)) !== -1) {
11325
- const line = this.stderrBuffer.slice(0, newlineIdx).replace(/\r$/, "");
11326
- this.stderrBuffer = this.stderrBuffer.slice(newlineIdx + 1);
11327
- if (!line || !shouldSurfaceStderrLine(line))
11328
- continue;
11329
- const tagged = tagStderrLine(line);
11330
- this.logVia(tagged);
11331
- this.pushStderrLine(tagged);
11329
+ const partialLimit = 64 * 1024;
11330
+ let offset = 0;
11331
+ while (offset < data.length) {
11332
+ const newline = data.indexOf(`
11333
+ `, offset);
11334
+ const end = newline < 0 ? data.length : newline;
11335
+ while (offset < end) {
11336
+ const count = Math.min(partialLimit - this.stderrBuffer.length, end - offset);
11337
+ this.stderrBuffer += data.slice(offset, offset + count);
11338
+ offset += count;
11339
+ if (this.stderrBuffer.length === partialLimit) {
11340
+ const last = this.stderrBuffer.charCodeAt(this.stderrBuffer.length - 1);
11341
+ const carry = last >= 55296 && last <= 56319 ? this.stderrBuffer.slice(-1) : "";
11342
+ const fragment = carry ? this.stderrBuffer.slice(0, -1) : this.stderrBuffer;
11343
+ const tagged = tagStderrLine(`${fragment} [stderr record truncated into bounded fragments; ${Buffer.byteLength(fragment)} bytes shown, continuation follows]`);
11344
+ this.stderrBuffer = carry;
11345
+ this.logVia(tagged);
11346
+ this.pushStderrLine(tagged);
11347
+ }
11348
+ }
11349
+ if (newline < 0)
11350
+ break;
11351
+ this.flushStderrBuffer();
11352
+ offset = newline + 1;
11332
11353
  }
11333
11354
  }
11334
11355
  flushStderrBuffer() {
@@ -11817,9 +11838,366 @@ function formatDroppedKeyWarnings(dropped) {
11817
11838
  }
11818
11839
  return dropped.map((item) => `Ignoring ${item.key} from ${item.tier} config (${item.reason})`);
11819
11840
  }
11841
+ // ../aft-bridge/dist/config-watch.js
11842
+ import { readFileSync as readFileSync3, statSync as statSync3, watch } from "node:fs";
11843
+ import { basename, dirname } from "node:path";
11844
+ var CONFIG_WATCH_DEBOUNCE_MS = 150;
11845
+ var CONFIG_LIVE_KEEP_NOTE = "AFT keeps using the last valid configuration until the file is fixed.";
11846
+ function pathKey(name) {
11847
+ const segments = name.split(".");
11848
+ return {
11849
+ name,
11850
+ read(config) {
11851
+ let value = config;
11852
+ for (const segment of segments) {
11853
+ if (value === null || typeof value !== "object")
11854
+ return;
11855
+ value = value[segment];
11856
+ }
11857
+ return value;
11858
+ },
11859
+ write(config, value) {
11860
+ const set = (target, index) => {
11861
+ const copy = target !== null && typeof target === "object" && !Array.isArray(target) ? { ...target } : {};
11862
+ const segment = segments[index];
11863
+ if (index === segments.length - 1) {
11864
+ if (value === undefined)
11865
+ delete copy[segment];
11866
+ else
11867
+ copy[segment] = value;
11868
+ } else {
11869
+ copy[segment] = set(copy[segment], index + 1);
11870
+ }
11871
+ return copy;
11872
+ };
11873
+ return set(config, 0);
11874
+ }
11875
+ };
11876
+ }
11877
+ function bashKey(name, resolveBash) {
11878
+ return {
11879
+ name: `bash.${name}`,
11880
+ read: (config) => resolveBash(config)[name],
11881
+ write(config, value) {
11882
+ const resolved = { ...resolveBash(config), [name]: value };
11883
+ for (const key of Object.keys(resolved)) {
11884
+ if (resolved[key] === undefined)
11885
+ delete resolved[key];
11886
+ }
11887
+ return { ...config, bash: resolved };
11888
+ }
11889
+ };
11890
+ }
11891
+ function aftLiveConfigKeys(resolveBash) {
11892
+ return [
11893
+ pathKey("configure_warnings_delivery"),
11894
+ pathKey("restrict_to_project_root"),
11895
+ pathKey("inspect.diagnostics_timeout_ms"),
11896
+ pathKey("inspect.tier2_idle_minutes"),
11897
+ bashKey("foreground_wait_window_ms", resolveBash),
11898
+ bashKey("host_fallback", resolveBash),
11899
+ bashKey("subagent_background", resolveBash),
11900
+ bashKey("watch_sync_max_ms", resolveBash)
11901
+ ];
11902
+ }
11903
+ function sameValue(a, b) {
11904
+ return JSON.stringify(a) === JSON.stringify(b);
11905
+ }
11906
+ function flattenLeaves(value, prefix, out) {
11907
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
11908
+ const entries = Object.entries(value);
11909
+ if (entries.length === 0 && prefix)
11910
+ out.set(prefix, "{}");
11911
+ for (const [key, child] of entries) {
11912
+ flattenLeaves(child, prefix ? `${prefix}.${key}` : key, out);
11913
+ }
11914
+ return;
11915
+ }
11916
+ if (prefix)
11917
+ out.set(prefix, JSON.stringify(value));
11918
+ }
11919
+ function applyLiveConfigKeys(current, next, keys, baseline = current) {
11920
+ let config = current;
11921
+ const applied = [];
11922
+ for (const key of keys) {
11923
+ const value = key.read(next);
11924
+ if (sameValue(key.read(current), value))
11925
+ continue;
11926
+ config = key.write(config, value);
11927
+ applied.push(key.name);
11928
+ }
11929
+ const before = new Map;
11930
+ const after = new Map;
11931
+ flattenLeaves(baseline, "", before);
11932
+ flattenLeaves(next, "", after);
11933
+ const liveNames = keys.map((key) => key.name);
11934
+ const isLive = (leaf) => liveNames.some((name) => leaf === name || leaf.startsWith(`${name}.`));
11935
+ const deferred = new Set;
11936
+ for (const leaf of new Set([...before.keys(), ...after.keys()])) {
11937
+ if (before.get(leaf) === after.get(leaf) || isLive(leaf))
11938
+ continue;
11939
+ deferred.add(leaf);
11940
+ }
11941
+ return { config, applied, deferred: [...deferred].sort() };
11942
+ }
11943
+ function readTextOrNull(path) {
11944
+ try {
11945
+ return readFileSync3(path, "utf8");
11946
+ } catch {
11947
+ return null;
11948
+ }
11949
+ }
11950
+ var CONFIG_WATCH_REVALIDATE_MS = 2000;
11951
+ var CONFIG_WATCH_REJECTED_RETRIES = 3;
11952
+ var CONFIG_WATCH_MAX_DELAY_MS = 1000;
11953
+ function identityOf(dir) {
11954
+ try {
11955
+ const stat = statSync3(dir, { bigint: true });
11956
+ const base = `${stat.dev}:${stat.ino}`;
11957
+ return process.platform === "win32" ? base : `${base}:${stat.birthtimeNs}`;
11958
+ } catch {
11959
+ return null;
11960
+ }
11961
+ }
11962
+ function watchDirFor(file) {
11963
+ let dir = dirname(file);
11964
+ while (dir !== dirname(dir) && identityOf(dir) === null)
11965
+ dir = dirname(dir);
11966
+ return dir;
11967
+ }
11968
+ function watchAftConfigFiles(options) {
11969
+ const debounceMs = options.debounceMs ?? CONFIG_WATCH_DEBOUNCE_MS;
11970
+ const lastSeen = new Map;
11971
+ for (const path of options.paths) {
11972
+ if (options.initialTexts)
11973
+ lastSeen.set(path, options.initialTexts[path] ?? null);
11974
+ else
11975
+ lastSeen.set(path, options.checkAtStart ? undefined : readTextOrNull(path));
11976
+ }
11977
+ let timer = null;
11978
+ let firstPendingAt = null;
11979
+ let stopped = false;
11980
+ const watchers = new Map;
11981
+ const watchImpl = options.watchImpl ?? watch;
11982
+ let rejectedRetries = 0;
11983
+ const check = () => {
11984
+ timer = null;
11985
+ firstPendingAt = null;
11986
+ if (stopped)
11987
+ return;
11988
+ revalidate();
11989
+ const seen = new Map;
11990
+ for (const path of options.paths) {
11991
+ const text = readTextOrNull(path);
11992
+ if (text !== lastSeen.get(path))
11993
+ seen.set(path, text);
11994
+ }
11995
+ if (seen.size === 0)
11996
+ return;
11997
+ const outcome = options.onChange();
11998
+ if (outcome === false) {
11999
+ if (rejectedRetries < CONFIG_WATCH_REJECTED_RETRIES) {
12000
+ rejectedRetries += 1;
12001
+ retryTimer = setTimeout(check, CONFIG_WATCH_MAX_DELAY_MS);
12002
+ retryTimer.unref?.();
12003
+ }
12004
+ return;
12005
+ }
12006
+ rejectedRetries = 0;
12007
+ if (outcome instanceof Map) {
12008
+ for (const path of options.paths)
12009
+ lastSeen.set(path, outcome.get(path) ?? null);
12010
+ } else {
12011
+ for (const [path, text] of seen)
12012
+ lastSeen.set(path, text);
12013
+ }
12014
+ };
12015
+ let retryTimer = null;
12016
+ const schedule = () => {
12017
+ if (stopped)
12018
+ return;
12019
+ const now = Date.now();
12020
+ firstPendingAt ??= now;
12021
+ if (timer)
12022
+ clearTimeout(timer);
12023
+ const delay = Math.max(0, Math.min(debounceMs, firstPendingAt + CONFIG_WATCH_MAX_DELAY_MS - now));
12024
+ timer = setTimeout(check, delay);
12025
+ timer.unref?.();
12026
+ };
12027
+ function revalidate() {
12028
+ const wanted = new Set(options.paths.map(watchDirFor));
12029
+ let moved = false;
12030
+ for (const [dir, entry] of watchers) {
12031
+ if (!wanted.has(dir) || entry.stale || identityOf(dir) !== entry.identity) {
12032
+ entry.watcher.close();
12033
+ watchers.delete(dir);
12034
+ moved = true;
12035
+ }
12036
+ }
12037
+ for (const dir of wanted) {
12038
+ if (watchers.has(dir))
12039
+ continue;
12040
+ try {
12041
+ const identity = identityOf(dir);
12042
+ options.beforeWatchForTest?.(dir);
12043
+ const name = basename(dir);
12044
+ const watcher = watchImpl(dir, { persistent: false }, (event, filename) => {
12045
+ if (event === "rename" && filename === name) {
12046
+ const current = watchers.get(dir);
12047
+ if (current && current.watcher === watcher)
12048
+ current.stale = true;
12049
+ }
12050
+ schedule();
12051
+ });
12052
+ if (identityOf(dir) !== identity) {
12053
+ watcher.close();
12054
+ moved = true;
12055
+ continue;
12056
+ }
12057
+ const entry = { watcher, identity, stale: false };
12058
+ entry.watcher.on("error", () => {
12059
+ entry.watcher.close();
12060
+ if (watchers.get(dir) === entry)
12061
+ watchers.delete(dir);
12062
+ schedule();
12063
+ });
12064
+ watchers.set(dir, entry);
12065
+ moved = true;
12066
+ } catch {}
12067
+ }
12068
+ return moved;
12069
+ }
12070
+ revalidate();
12071
+ if (options.checkAtStart)
12072
+ check();
12073
+ const revalidateTimer = setInterval(() => {
12074
+ if (!stopped && revalidate())
12075
+ schedule();
12076
+ }, CONFIG_WATCH_REVALIDATE_MS);
12077
+ revalidateTimer.unref?.();
12078
+ return () => {
12079
+ stopped = true;
12080
+ if (timer)
12081
+ clearTimeout(timer);
12082
+ if (retryTimer)
12083
+ clearTimeout(retryTimer);
12084
+ clearInterval(revalidateTimer);
12085
+ for (const entry of watchers.values())
12086
+ entry.watcher.close();
12087
+ watchers.clear();
12088
+ };
12089
+ }
12090
+ function aftLiveSecurityKeys(keys) {
12091
+ const byName = new Map(keys.map((key) => [key.name, key]));
12092
+ const pick = (name) => {
12093
+ const key = byName.get(name);
12094
+ if (!key)
12095
+ throw new Error(`unknown live config key ${name}`);
12096
+ return key;
12097
+ };
12098
+ return [
12099
+ {
12100
+ key: pick("restrict_to_project_root"),
12101
+ loosens: (current, next) => current === true && next !== true
12102
+ },
12103
+ {
12104
+ key: pick("bash.host_fallback"),
12105
+ loosens: (current, next) => current !== true && next === true
12106
+ }
12107
+ ];
12108
+ }
12109
+ function liveConfigReloadLogLine(applied, deferred) {
12110
+ let line = "config reload";
12111
+ if (applied.length > 0)
12112
+ line += ` applied=[${applied.join(",")}]`;
12113
+ if (deferred.length > 0) {
12114
+ line += ` deferred=[${deferred.join(",")}] (deferred keys apply on next connect/restart)`;
12115
+ }
12116
+ return line;
12117
+ }
12118
+ function startLiveConfigReload(options) {
12119
+ const baseline = options.getConfig();
12120
+ let lastError = null;
12121
+ let acceptedSources = new Set(options.initialSources);
12122
+ let acceptedProjectText = options.initialProjectText ?? null;
12123
+ let acceptedTexts;
12124
+ const reload = () => {
12125
+ let loaded = options.load();
12126
+ if (loaded.ok) {
12127
+ const read = new Set(loaded.sources);
12128
+ const deleted = [...acceptedSources].find((path) => !read.has(path));
12129
+ if (deleted !== undefined) {
12130
+ loaded = { ok: false, message: `AFT config at ${deleted} was deleted` };
12131
+ } else {
12132
+ acceptedSources = read;
12133
+ }
12134
+ }
12135
+ if (!loaded.ok) {
12136
+ const message = `${loaded.message.trim().replace(/[.!?]?$/, ".")} ${CONFIG_LIVE_KEEP_NOTE}`;
12137
+ if (message !== lastError) {
12138
+ lastError = message;
12139
+ options.reportError(message);
12140
+ }
12141
+ return null;
12142
+ }
12143
+ lastError = null;
12144
+ acceptedTexts = loaded.texts;
12145
+ const current = options.getConfig();
12146
+ let next = loaded.config;
12147
+ const held = [];
12148
+ const projectText = loaded.projectText ?? null;
12149
+ if (loaded.projectText !== undefined && projectText !== acceptedProjectText) {
12150
+ for (const security of options.securityKeys ?? []) {
12151
+ const now = security.key.read(current);
12152
+ if (security.loosens(now, security.key.read(next))) {
12153
+ next = security.key.write(next, now);
12154
+ held.push(security.key.name);
12155
+ }
12156
+ }
12157
+ if (held.length === 0)
12158
+ acceptedProjectText = projectText;
12159
+ }
12160
+ const result = applyLiveConfigKeys(current, next, options.keys, baseline);
12161
+ if (result.applied.length > 0)
12162
+ options.setConfig(result.config);
12163
+ if (result.applied.length > 0 || result.deferred.length > 0 || held.length > 0) {
12164
+ let line = liveConfigReloadLogLine(result.applied, result.deferred);
12165
+ if (held.length > 0) {
12166
+ line += ` held=[${held.join(",")}] (not loosened while the project file differs from the one the published values came from; the next restart applies them)`;
12167
+ }
12168
+ options.log(line);
12169
+ }
12170
+ return { ...result, held };
12171
+ };
12172
+ const safeReload = () => {
12173
+ try {
12174
+ acceptedTexts = undefined;
12175
+ if (reload() === null)
12176
+ return false;
12177
+ const texts = acceptedTexts;
12178
+ if (!texts)
12179
+ return true;
12180
+ return new Map(options.paths.map((path) => [path, texts[path] ?? null]));
12181
+ } catch (err) {
12182
+ options.reportError(`AFT config reload failed: ${err instanceof Error ? err.message : String(err)}`);
12183
+ return false;
12184
+ }
12185
+ };
12186
+ if (options.watch === false) {
12187
+ return { reload, stop: () => {} };
12188
+ }
12189
+ const stop = watchAftConfigFiles({
12190
+ paths: options.paths,
12191
+ debounceMs: options.debounceMs,
12192
+ onChange: safeReload,
12193
+ initialTexts: options.initialTexts,
12194
+ checkAtStart: true
12195
+ });
12196
+ return { reload, stop };
12197
+ }
11820
12198
  // ../aft-bridge/dist/downloader.js
11821
12199
  import { createHash as createHash2, randomUUID } from "node:crypto";
11822
- import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync, openSync, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, rmSync, statSync as statSync3, unlinkSync as unlinkSync2, writeSync } from "node:fs";
12200
+ import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync, openSync, readdirSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync4, unlinkSync as unlinkSync2, writeSync } from "node:fs";
11823
12201
  import { hostname } from "node:os";
11824
12202
  import { join as join7 } from "node:path";
11825
12203
  import { Readable } from "node:stream";
@@ -12171,7 +12549,7 @@ function isReclaimableDownloadLock(owner, ageMs, staleMs) {
12171
12549
  }
12172
12550
  function reclaimDownloadLock(lockPath, expectedOwner) {
12173
12551
  try {
12174
- if (readFileSync3(lockPath, "utf-8") !== expectedOwner)
12552
+ if (readFileSync4(lockPath, "utf-8") !== expectedOwner)
12175
12553
  return false;
12176
12554
  rmSync(lockPath, { force: true });
12177
12555
  return true;
@@ -12189,7 +12567,7 @@ function sweepStaleDownloadTemps(versionedCacheDir, binaryName) {
12189
12567
  continue;
12190
12568
  }
12191
12569
  const tempPath = join7(versionedCacheDir, entry.name);
12192
- const ageMs = Date.now() - statSync3(tempPath).mtimeMs;
12570
+ const ageMs = Date.now() - statSync4(tempPath).mtimeMs;
12193
12571
  if (Math.abs(ageMs) > DOWNLOAD_LOCK_STALE_MS)
12194
12572
  unlinkSync2(tempPath);
12195
12573
  }
@@ -12211,7 +12589,7 @@ async function acquireDownloadLock(lockPath, timing = {}) {
12211
12589
  }
12212
12590
  return () => {
12213
12591
  try {
12214
- if (readFileSync3(lockPath, "utf-8") === owner) {
12592
+ if (readFileSync4(lockPath, "utf-8") === owner) {
12215
12593
  rmSync(lockPath, { force: true });
12216
12594
  }
12217
12595
  } catch {}
@@ -12223,8 +12601,8 @@ async function acquireDownloadLock(lockPath, timing = {}) {
12223
12601
  let existingOwner;
12224
12602
  let ageMs;
12225
12603
  try {
12226
- existingOwner = readFileSync3(lockPath, "utf-8");
12227
- ageMs = Date.now() - statSync3(lockPath).mtimeMs;
12604
+ existingOwner = readFileSync4(lockPath, "utf-8");
12605
+ ageMs = Date.now() - statSync4(lockPath).mtimeMs;
12228
12606
  } catch (readErr) {
12229
12607
  if (readErr.code === "ENOENT")
12230
12608
  continue;
@@ -12274,7 +12652,7 @@ async function fetchLatestTag() {
12274
12652
  }
12275
12653
  // ../aft-bridge/dist/durable-log.js
12276
12654
  import { appendFile, chmod, mkdir, rename, rm, stat } from "node:fs/promises";
12277
- import { dirname } from "node:path";
12655
+ import { dirname as dirname2 } from "node:path";
12278
12656
  var DEFAULT_LOG_BYTES = 32 * 1024 * 1024;
12279
12657
  var DEFAULT_LOG_GENERATIONS = 1;
12280
12658
  var LOG_DIR_MODE = 448;
@@ -12287,6 +12665,10 @@ class RotatingLogSink {
12287
12665
  queue = Promise.resolve();
12288
12666
  disabled = false;
12289
12667
  failureReported = false;
12668
+ queuedBytes = 0;
12669
+ queuedRecords = 0;
12670
+ droppedBytes = 0;
12671
+ overflowQueued = false;
12290
12672
  constructor(path, options = {}) {
12291
12673
  this.path = path;
12292
12674
  this.maxBytes = options.maxBytes ?? DEFAULT_LOG_BYTES;
@@ -12295,7 +12677,34 @@ class RotatingLogSink {
12295
12677
  append(data) {
12296
12678
  if (this.disabled || data.length === 0)
12297
12679
  return;
12298
- this.queue = this.queue.then(() => this.write(data)).catch((error) => {
12680
+ const bytes = Buffer.byteLength(data);
12681
+ const overflow = this.queuedBytes + bytes > 1024 * 1024 || this.queuedRecords >= 4096;
12682
+ if (overflow) {
12683
+ this.droppedBytes += bytes;
12684
+ if (this.overflowQueued)
12685
+ return;
12686
+ this.overflowQueued = true;
12687
+ data = "";
12688
+ } else {
12689
+ this.queuedBytes += bytes;
12690
+ this.queuedRecords += 1;
12691
+ }
12692
+ this.queue = this.queue.then(async () => {
12693
+ if (overflow) {
12694
+ const dropped = this.droppedBytes;
12695
+ this.droppedBytes = 0;
12696
+ this.overflowQueued = false;
12697
+ await this.write(`[aft-plugin] durable log queue overflow: dropped ${dropped} bytes (1MiB/4096-record pending limit); reduce diagnostic volume.
12698
+ `);
12699
+ } else {
12700
+ try {
12701
+ await this.write(data);
12702
+ } finally {
12703
+ this.queuedBytes -= bytes;
12704
+ this.queuedRecords -= 1;
12705
+ }
12706
+ }
12707
+ }).catch((error) => {
12299
12708
  this.disabled = true;
12300
12709
  if (!this.failureReported) {
12301
12710
  this.failureReported = true;
@@ -12310,8 +12719,8 @@ class RotatingLogSink {
12310
12719
  await this.queue;
12311
12720
  }
12312
12721
  async write(data) {
12313
- const dir = dirname(this.path);
12314
- await mkdir(dirname(dir), { recursive: true });
12722
+ const dir = dirname2(this.path);
12723
+ await mkdir(dirname2(dir), { recursive: true });
12315
12724
  try {
12316
12725
  await mkdir(dir, { mode: LOG_DIR_MODE });
12317
12726
  } catch (error) {
@@ -14099,7 +14508,7 @@ function reverseRequestMethod(body) {
14099
14508
  }
14100
14509
  }
14101
14510
  // ../aft-bridge/dist/subc-transport.js
14102
- import { existsSync as existsSync4, statSync as statSync4 } from "node:fs";
14511
+ import { existsSync as existsSync4, statSync as statSync5 } from "node:fs";
14103
14512
 
14104
14513
  // ../aft-bridge/dist/lifecycle-registry.js
14105
14514
  import { lstat } from "node:fs/promises";
@@ -14626,6 +15035,7 @@ var RECONNECT_RETRY_FLOOR_MS = 100;
14626
15035
  var RECONNECT_RETRY_CAP_MS = 2000;
14627
15036
  var SUBC_DEFAULT_REQUEST_TIMEOUT_MS = 30000;
14628
15037
  var ROUTE_OPEN_RELOAD_WAIT_CEILING_MS = 45000;
15038
+ var CALL_DEADLINE_EXPIRED = Symbol("call deadline expired");
14629
15039
  function reloadWaitExhaustedSuffix(callDeadlineMs) {
14630
15040
  if (callDeadlineMs > ROUTE_OPEN_RELOAD_WAIT_CEILING_MS) {
14631
15041
  const ceilingSeconds = ROUTE_OPEN_RELOAD_WAIT_CEILING_MS / 1000;
@@ -14978,7 +15388,16 @@ function absentRootError(root) {
14978
15388
  return new SubcError(`invalid route project root: project root does not exist: ${root}`, "config_divergence");
14979
15389
  }
14980
15390
  function reloadWindowExhaustedError(error, callDeadlineMs) {
14981
- const suffix = reloadWaitExhaustedSuffix(callDeadlineMs);
15391
+ return withDeadlineSuffix(error, reloadWaitExhaustedSuffix(callDeadlineMs));
15392
+ }
15393
+ function callDeadlinePassedError(lastError, callDeadlineMs) {
15394
+ const seconds = Math.round(callDeadlineMs / 100) / 10;
15395
+ const suffix = ` The AFT daemon module did not return within this call's ${seconds}s deadline.`;
15396
+ if (lastError !== undefined)
15397
+ return withDeadlineSuffix(lastError, suffix);
15398
+ return new SubcError(`route to module '${AFT_MODULE_ID}' was not ready before the call ran out of time.${suffix}`, REQUEST_DEADLINE_CODE);
15399
+ }
15400
+ function withDeadlineSuffix(error, suffix) {
14982
15401
  if (error instanceof Error) {
14983
15402
  try {
14984
15403
  error.message += suffix;
@@ -15217,7 +15636,7 @@ class SubcTransportPool {
15217
15636
  rootCanAttach(root) {
15218
15637
  let directoryExists = false;
15219
15638
  try {
15220
- directoryExists = statSync4(root).isDirectory();
15639
+ directoryExists = statSync5(root).isDirectory();
15221
15640
  } catch {}
15222
15641
  if (directoryExists) {
15223
15642
  this.dormantRoots.delete(root);
@@ -15557,6 +15976,7 @@ class SubcTransportPool {
15557
15976
  return this.rootReapedError(record);
15558
15977
  }
15559
15978
  async routeRequest(identity, body, timeoutMs, onProgress, expectedGeneration, abortSignal) {
15979
+ const callStartedAt = performance.now();
15560
15980
  const root = asCanonicalRootPath(identity.project_root);
15561
15981
  let generation = expectedGeneration;
15562
15982
  if (this.lifecycleEnabled()) {
@@ -15609,19 +16029,41 @@ class SubcTransportPool {
15609
16029
  };
15610
16030
  const callDeadlineMs = timeoutMs ?? SUBC_DEFAULT_REQUEST_TIMEOUT_MS;
15611
16031
  const reloadWaitBudgetMs = Math.min(callDeadlineMs, ROUTE_OPEN_RELOAD_WAIT_CEILING_MS);
15612
- let reloadWaitedMs = 0;
16032
+ let scheduledDelayMs = 0;
16033
+ let lastRefusal;
16034
+ const spentMs = () => Math.max(performance.now() - callStartedAt, scheduledDelayMs);
16035
+ const remainingMs = () => callDeadlineMs - spentMs();
16036
+ const openRouteWithinDeadline = async () => {
16037
+ const remaining = remainingMs();
16038
+ if (remaining <= 0)
16039
+ throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
16040
+ let timer;
16041
+ const expired = new Promise((resolve) => {
16042
+ timer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), remaining);
16043
+ });
16044
+ try {
16045
+ const opened = await Promise.race([openRoute(), expired]);
16046
+ if (opened === CALL_DEADLINE_EXPIRED) {
16047
+ throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
16048
+ }
16049
+ return opened;
16050
+ } finally {
16051
+ clearTimeout(timer);
16052
+ }
16053
+ };
15613
16054
  const openRouteAfterReloadWindow = async () => {
15614
16055
  while (true) {
15615
16056
  try {
15616
- return await openRoute();
16057
+ return await openRouteWithinDeadline();
15617
16058
  } catch (error) {
15618
16059
  if (!isRouteOpenReloadWindowError(error))
15619
16060
  throw error;
15620
- if (reloadWaitedMs + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
16061
+ lastRefusal = error;
16062
+ if (spentMs() + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
15621
16063
  throw reloadWindowExhaustedError(error, callDeadlineMs);
15622
16064
  }
15623
16065
  const { delayMs, wait } = this.waitForRouteReopenBackoff();
15624
- reloadWaitedMs += delayMs;
16066
+ scheduledDelayMs = spentMs() + delayMs;
15625
16067
  await wait;
15626
16068
  }
15627
16069
  }
@@ -15657,7 +16099,7 @@ class SubcTransportPool {
15657
16099
  route: routeLabel(entry.handle)
15658
16100
  });
15659
16101
  };
15660
- const requestOnRoute = async (route, entry) => {
16102
+ const requestOnRoute = async (route, entry, requestTimeoutMs) => {
15661
16103
  this.assertRecordLive(record);
15662
16104
  if (abortSignal?.aborted) {
15663
16105
  clearRouteEntry(entry);
@@ -15673,8 +16115,10 @@ class SubcTransportPool {
15673
16115
  };
15674
16116
  abortSignal?.addEventListener("abort", onAbort, { once: true });
15675
16117
  try {
15676
- const requestTimeoutMs = reloadWaitedMs > 0 ? callDeadlineMs - reloadWaitedMs : timeoutMs;
15677
- const request = client.request(route, body, { timeoutMs: requestTimeoutMs, onProgress });
16118
+ const request = client.request(route, body, {
16119
+ timeoutMs: Math.ceil(requestTimeoutMs),
16120
+ onProgress
16121
+ });
15678
16122
  const reply = abortSignal ? await Promise.race([request, aborted]) : await request;
15679
16123
  if (!this.isCurrentSession(key, record)) {
15680
16124
  if (this.isReapInduced(record))
@@ -15695,8 +16139,11 @@ class SubcTransportPool {
15695
16139
  let reopened = false;
15696
16140
  let retriedAbsentRoute = false;
15697
16141
  while (true) {
16142
+ const requestTimeoutMs = remainingMs();
16143
+ if (requestTimeoutMs <= 0)
16144
+ throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
15698
16145
  try {
15699
- const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry);
16146
+ const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry, requestTimeoutMs);
15700
16147
  if (reopened)
15701
16148
  this.resetRouteReopenBackoff();
15702
16149
  return reply;
@@ -15706,11 +16153,12 @@ class SubcTransportPool {
15706
16153
  const ownsRoute = this.isCurrentSession(key, record) && this.client === client;
15707
16154
  if (ownsRoute && isRouteRequestReloadRefusal(error)) {
15708
16155
  clearRouteEntry(routeAndEntry.entry);
15709
- if (reloadWaitedMs + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
16156
+ lastRefusal = error;
16157
+ if (spentMs() + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
15710
16158
  throw reloadWindowExhaustedError(error, callDeadlineMs);
15711
16159
  }
15712
16160
  const { delayMs, wait } = this.waitForRouteReopenBackoff();
15713
- reloadWaitedMs += delayMs;
16161
+ scheduledDelayMs = spentMs() + delayMs;
15714
16162
  await wait;
15715
16163
  routeAndEntry = await openRouteAfterReloadWindow();
15716
16164
  reopened = true;
@@ -15719,7 +16167,12 @@ class SubcTransportPool {
15719
16167
  if (ownsRoute && !retriedAbsentRoute && isRouteProvenAbsentError(error)) {
15720
16168
  retriedAbsentRoute = true;
15721
16169
  clearRouteEntry(routeAndEntry.entry);
15722
- await this.waitForRouteReopenBackoff().wait;
16170
+ if (spentMs() + this.nextRouteReopenDelayMs() >= callDeadlineMs) {
16171
+ throw callDeadlinePassedError(error, callDeadlineMs);
16172
+ }
16173
+ const { delayMs, wait } = this.waitForRouteReopenBackoff();
16174
+ scheduledDelayMs = spentMs() + delayMs;
16175
+ await wait;
15723
16176
  routeAndEntry = await openRouteAfterReloadWindow();
15724
16177
  reopened = true;
15725
16178
  continue;
@@ -17542,14 +17995,14 @@ function shouldInterruptWaitsForMessage(detachOnUserMessage, operatorText) {
17542
17995
  return detachOnUserMessage || containsStandaloneDetachKeyword(operatorText);
17543
17996
  }
17544
17997
  // ../aft-bridge/dist/migration.js
17545
- import { closeSync as closeSync3, existsSync as existsSync8, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync6, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
17998
+ import { closeSync as closeSync3, existsSync as existsSync8, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync7, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
17546
17999
  import { homedir as homedir8, tmpdir as tmpdir2 } from "node:os";
17547
- import { basename, dirname as dirname4, join as join10, resolve as resolve6 } from "node:path";
18000
+ import { basename as basename2, dirname as dirname5, join as join10, resolve as resolve6 } from "node:path";
17548
18001
 
17549
18002
  // ../aft-bridge/dist/paths.js
17550
- import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync3, writeFileSync as writeFileSync2 } from "node:fs";
18003
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync2 } from "node:fs";
17551
18004
  import { homedir as homedir6 } from "node:os";
17552
- import { dirname as dirname2, isAbsolute as isAbsolute3, join as join8, resolve as resolve5 } from "node:path";
18005
+ import { dirname as dirname3, isAbsolute as isAbsolute3, join as join8, resolve as resolve5 } from "node:path";
17553
18006
  function homeDir3() {
17554
18007
  if (process.platform === "win32")
17555
18008
  return process.env.USERPROFILE || process.env.HOME || homedir6();
@@ -17609,7 +18062,7 @@ function repairRootScopedStorageFile(storageRoot, harness, fileName) {
17609
18062
  if (existsSync6(harnessPath) || !existsSync6(rootPath))
17610
18063
  return harnessPath;
17611
18064
  try {
17612
- mkdirSync2(dirname2(harnessPath), { recursive: true });
18065
+ mkdirSync2(dirname3(harnessPath), { recursive: true });
17613
18066
  renameSync3(rootPath, harnessPath);
17614
18067
  } catch {}
17615
18068
  return harnessPath;
@@ -17621,7 +18074,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
17621
18074
  let lastVersion = "";
17622
18075
  try {
17623
18076
  if (existsSync6(versionFile)) {
17624
- lastVersion = readFileSync4(versionFile, "utf-8").trim();
18077
+ lastVersion = readFileSync5(versionFile, "utf-8").trim();
17625
18078
  }
17626
18079
  } catch {
17627
18080
  return false;
@@ -17630,7 +18083,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
17630
18083
  return false;
17631
18084
  if (!lastVersion) {
17632
18085
  try {
17633
- mkdirSync2(dirname2(versionFile), { recursive: true });
18086
+ mkdirSync2(dirname3(versionFile), { recursive: true });
17634
18087
  writeFileSync2(versionFile, currentVersion);
17635
18088
  } catch {}
17636
18089
  return false;
@@ -17642,7 +18095,7 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
17642
18095
  return;
17643
18096
  const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
17644
18097
  try {
17645
- mkdirSync2(dirname2(versionFile), { recursive: true });
18098
+ mkdirSync2(dirname3(versionFile), { recursive: true });
17646
18099
  writeFileSync2(versionFile, currentVersion);
17647
18100
  } catch {}
17648
18101
  }
@@ -17691,10 +18144,10 @@ function decodeFileUrl(target) {
17691
18144
  }
17692
18145
 
17693
18146
  // ../aft-bridge/dist/resolver.js
17694
- import { closeSync as closeSync2, existsSync as existsSync7, promises as fsPromises, openSync as openSync2, readFileSync as readFileSync5, readSync } from "node:fs";
18147
+ import { closeSync as closeSync2, existsSync as existsSync7, promises as fsPromises, openSync as openSync2, readFileSync as readFileSync6, readSync } from "node:fs";
17695
18148
  import { createRequire } from "node:module";
17696
18149
  import { homedir as homedir7 } from "node:os";
17697
- import { delimiter, dirname as dirname3, isAbsolute as isAbsolute4, join as join9 } from "node:path";
18150
+ import { delimiter, dirname as dirname4, isAbsolute as isAbsolute4, join as join9 } from "node:path";
17698
18151
  var ensureBinaryForResolver = ensureBinary;
17699
18152
  var npmPlatformPackageReader = null;
17700
18153
  var cacheCopiesInFlight = new Map;
@@ -17847,8 +18300,8 @@ function npmPlatformPackage(ext) {
17847
18300
  try {
17848
18301
  const req = createRequire(import.meta.url);
17849
18302
  const manifestPath = req.resolve(`@cortexkit/aft-${platformKey()}/package.json`);
17850
- const manifest = JSON.parse(readFileSync5(manifestPath, "utf8"));
17851
- const binaryPath = join9(dirname3(manifestPath), "bin", `aft${ext}`);
18303
+ const manifest = JSON.parse(readFileSync6(manifestPath, "utf8"));
18304
+ const binaryPath = join9(dirname4(manifestPath), "bin", `aft${ext}`);
17852
18305
  if (typeof manifest.version !== "string" || !existsSync7(binaryPath))
17853
18306
  return null;
17854
18307
  return { binaryPath, version: normalizeBareVersion(manifest.version) };
@@ -18102,7 +18555,7 @@ function acquireConfigMigrationLock(lockDir) {
18102
18555
  if (code !== "EEXIST")
18103
18556
  throw err;
18104
18557
  try {
18105
- const ageMs = Date.now() - statSync5(lockDir).mtimeMs;
18558
+ const ageMs = Date.now() - statSync6(lockDir).mtimeMs;
18106
18559
  if (ageMs > 60000) {
18107
18560
  rmSync2(lockDir, { recursive: true, force: true });
18108
18561
  continue;
@@ -18116,12 +18569,12 @@ function acquireConfigMigrationLock(lockDir) {
18116
18569
  }
18117
18570
  }
18118
18571
  function atomicCopyConfigFile(sourcePath, targetPath) {
18119
- mkdirSync3(dirname4(targetPath), { recursive: true });
18120
- const tmpPath = join10(dirname4(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
18572
+ mkdirSync3(dirname5(targetPath), { recursive: true });
18573
+ const tmpPath = join10(dirname5(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
18121
18574
  let fd = null;
18122
18575
  try {
18123
18576
  fd = openSync3(tmpPath, "wx", 384);
18124
- writeFileSync3(fd, readFileSync6(sourcePath));
18577
+ writeFileSync3(fd, readFileSync7(sourcePath));
18125
18578
  closeSync3(fd);
18126
18579
  fd = null;
18127
18580
  renameSync4(tmpPath, targetPath);
@@ -18138,8 +18591,8 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
18138
18591
  }
18139
18592
  }
18140
18593
  function atomicWriteConfigFile(targetPath, content) {
18141
- mkdirSync3(dirname4(targetPath), { recursive: true });
18142
- const tmpPath = join10(dirname4(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
18594
+ mkdirSync3(dirname5(targetPath), { recursive: true });
18595
+ const tmpPath = join10(dirname5(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
18143
18596
  let fd = null;
18144
18597
  try {
18145
18598
  fd = openSync3(tmpPath, "wx", 384);
@@ -18200,11 +18653,11 @@ function markLegacySourcesMovedAside(sources, targetPath, logger) {
18200
18653
  const desiredMarkerPath = `${source.path}${MOVED_MARKER_SUFFIX}`;
18201
18654
  const markerPath = nonClobberingSidecarPath(desiredMarkerPath);
18202
18655
  try {
18203
- const original = readFileSync6(source.path, "utf-8");
18656
+ const original = readFileSync7(source.path, "utf-8");
18204
18657
  if (markerPath !== desiredMarkerPath) {
18205
18658
  logger?.warn?.(`Preserving existing legacy AFT marker ${desiredMarkerPath}; writing new marker to ${markerPath}`);
18206
18659
  }
18207
- atomicWriteConfigFile(markerPath, movedMarkerContent(targetPath, basename(source.path), original));
18660
+ atomicWriteConfigFile(markerPath, movedMarkerContent(targetPath, basename2(source.path), original));
18208
18661
  unlinkSync3(source.path);
18209
18662
  info?.(`Moved legacy AFT config ${source.path} aside to ${markerPath}; AFT now reads ${targetPath}`);
18210
18663
  } catch (err) {
@@ -18264,15 +18717,15 @@ function migrateAftConfigFile(opts) {
18264
18717
  if (existingSources.length === 0) {
18265
18718
  return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
18266
18719
  }
18267
- mkdirSync3(dirname4(opts.targetPath), { recursive: true });
18720
+ mkdirSync3(dirname5(opts.targetPath), { recursive: true });
18268
18721
  const release = acquireConfigMigrationLock(`${opts.targetPath}.lock`);
18269
18722
  try {
18270
18723
  const sources = existingSources.map((source) => ({
18271
18724
  ...source,
18272
- content: readFileSync6(source.path, "utf-8")
18725
+ content: readFileSync7(source.path, "utf-8")
18273
18726
  }));
18274
18727
  if (existsSync8(opts.targetPath)) {
18275
- const targetContent = readFileSync6(opts.targetPath, "utf-8");
18728
+ const targetContent = readFileSync7(opts.targetPath, "utf-8");
18276
18729
  for (const source of sources) {
18277
18730
  if (fileSemanticsMatch(source.content, targetContent))
18278
18731
  continue;
@@ -18323,11 +18776,11 @@ function spawnErrorLabel(error) {
18323
18776
  function migrationLogPath(newRoot, harness, logger) {
18324
18777
  const desired = join10(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
18325
18778
  try {
18326
- mkdirSync3(dirname4(desired), { recursive: true });
18779
+ mkdirSync3(dirname5(desired), { recursive: true });
18327
18780
  return desired;
18328
18781
  } catch (err) {
18329
18782
  const fallback = join10(tmpdir2(), `aft-migration-${harness}-${Date.now()}.jsonl`);
18330
- logger?.warn?.(`Failed to create AFT migration log directory ${dirname4(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
18783
+ logger?.warn?.(`Failed to create AFT migration log directory ${dirname5(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
18331
18784
  return fallback;
18332
18785
  }
18333
18786
  }
@@ -18388,9 +18841,9 @@ async function ensureStorageMigrated(opts) {
18388
18841
  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}` : ""));
18389
18842
  }
18390
18843
  // ../aft-bridge/dist/migration-notices.js
18391
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync5, rmdirSync, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
18844
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync as renameSync5, rmdirSync, statSync as statSync7, writeFileSync as writeFileSync4 } from "node:fs";
18392
18845
  import { homedir as homedir9 } from "node:os";
18393
- import { dirname as dirname5, join as join11, resolve as resolve7 } from "node:path";
18846
+ import { dirname as dirname6, join as join11, resolve as resolve7 } from "node:path";
18394
18847
  function migrationNoticeStorePath(env = process.env) {
18395
18848
  const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join11(homedir9(), ".local", "state");
18396
18849
  return join11(stateHome, "cortexkit", "aft", "migration-notices.json");
@@ -18400,7 +18853,7 @@ function noticeKey(configPath, digest) {
18400
18853
  }
18401
18854
  function readRecords(storePath) {
18402
18855
  try {
18403
- const parsed = JSON.parse(readFileSync7(storePath, "utf8"));
18856
+ const parsed = JSON.parse(readFileSync8(storePath, "utf8"));
18404
18857
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
18405
18858
  } catch {
18406
18859
  return {};
@@ -18409,7 +18862,7 @@ function readRecords(storePath) {
18409
18862
  var LOCK_STALE_MS = 1e4;
18410
18863
  function withStoreLock(storePath, action) {
18411
18864
  const lockPath = `${storePath}.lock`;
18412
- mkdirSync4(dirname5(storePath), { recursive: true });
18865
+ mkdirSync4(dirname6(storePath), { recursive: true });
18413
18866
  const deadline = Date.now() + 2000;
18414
18867
  for (;; ) {
18415
18868
  try {
@@ -18419,7 +18872,7 @@ function withStoreLock(storePath, action) {
18419
18872
  if (error.code !== "EEXIST")
18420
18873
  throw error;
18421
18874
  try {
18422
- if (Date.now() - statSync6(lockPath).mtimeMs > LOCK_STALE_MS)
18875
+ if (Date.now() - statSync7(lockPath).mtimeMs > LOCK_STALE_MS)
18423
18876
  rmdirSync(lockPath);
18424
18877
  } catch {}
18425
18878
  if (Date.now() > deadline)
@@ -18460,9 +18913,9 @@ function deliverMigrationNoticeOnce(options) {
18460
18913
  }
18461
18914
  }
18462
18915
  // ../aft-bridge/dist/npm-resolver.js
18463
- import { readdirSync as readdirSync2, statSync as statSync7 } from "node:fs";
18916
+ import { readdirSync as readdirSync2, statSync as statSync8 } from "node:fs";
18464
18917
  import { homedir as homedir10 } from "node:os";
18465
- import { dirname as dirname6, isAbsolute as isAbsolute5, join as join12 } from "node:path";
18918
+ import { dirname as dirname7, isAbsolute as isAbsolute5, join as join12 } from "node:path";
18466
18919
  function defaultDeps() {
18467
18920
  return {
18468
18921
  platform: process.platform,
@@ -18476,7 +18929,7 @@ function npmBinaryName(platform) {
18476
18929
  }
18477
18930
  function isFile(p) {
18478
18931
  try {
18479
- return statSync7(p).isFile();
18932
+ return statSync8(p).isFile();
18480
18933
  } catch {
18481
18934
  return false;
18482
18935
  }
@@ -18497,7 +18950,7 @@ function npmFromPath(deps) {
18497
18950
  return null;
18498
18951
  }
18499
18952
  function npmAdjacentToNode(deps) {
18500
- const dir = dirname6(deps.execPath);
18953
+ const dir = dirname7(deps.execPath);
18501
18954
  return isFile(join12(dir, npmBinaryName(deps.platform))) ? dir : null;
18502
18955
  }
18503
18956
  function highestVersionedNodeBin(installsDir, name) {
@@ -18885,8 +19338,8 @@ function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
18885
19338
  }
18886
19339
  // ../aft-bridge/dist/onnx-runtime.js
18887
19340
  import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
18888
- import { chmodSync as chmodSync2, closeSync as closeSync5, copyFileSync as copyFileSync2, createWriteStream as createWriteStream2, existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync5, openSync as openSync5, readdirSync as readdirSync3, readFileSync as readFileSync8, readlinkSync, realpathSync as realpathSync3, renameSync as renameSync6, rmSync as rmSync3, statSync as statSync8, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "node:fs";
18889
- import { basename as basename2, dirname as dirname7, isAbsolute as isAbsolute6, join as join14, relative as relative2, resolve as resolve8, win32 } from "node:path";
19341
+ import { chmodSync as chmodSync2, closeSync as closeSync5, copyFileSync as copyFileSync2, createWriteStream as createWriteStream2, existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync5, openSync as openSync5, readdirSync as readdirSync3, readFileSync as readFileSync9, readlinkSync, realpathSync as realpathSync3, renameSync as renameSync6, rmSync as rmSync3, statSync as statSync9, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "node:fs";
19342
+ import { basename as basename3, dirname as dirname8, isAbsolute as isAbsolute6, join as join14, relative as relative2, resolve as resolve8, win32 } from "node:path";
18890
19343
  import { Readable as Readable2 } from "node:stream";
18891
19344
  import { pipeline as pipeline2 } from "node:stream/promises";
18892
19345
 
@@ -19093,7 +19546,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
19093
19546
  abandoned = true;
19094
19547
  } else {
19095
19548
  try {
19096
- const ageMs = Date.now() - statSync8(stagingDir).mtimeMs;
19549
+ const ageMs = Date.now() - statSync9(stagingDir).mtimeMs;
19097
19550
  abandoned = ageMs > STALE_LOCK_MS;
19098
19551
  } catch {
19099
19552
  abandoned = true;
@@ -19130,7 +19583,7 @@ var REQUIRED_ORT_MAJOR = 1;
19130
19583
  var REQUIRED_ORT_MIN_MINOR = 20;
19131
19584
  var INVALID_ORT_VERSION = "<invalid>";
19132
19585
  function parseOnnxVersionFromPath(value) {
19133
- const name = basename2(value);
19586
+ const name = basename3(value);
19134
19587
  const semverish = name.match(/(?:^|[._-])(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?)(?:\.(?:dylib|dll))?$/);
19135
19588
  if (semverish)
19136
19589
  return semverish[1].split(/[-+]/, 1)[0];
@@ -19335,7 +19788,7 @@ async function downloadFileWithCap(url, destPath) {
19335
19788
  if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
19336
19789
  throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
19337
19790
  }
19338
- mkdirSync5(dirname7(destPath), { recursive: true });
19791
+ mkdirSync5(dirname8(destPath), { recursive: true });
19339
19792
  let bytesWritten = 0;
19340
19793
  const guard = new TransformStream({
19341
19794
  transform(chunk, transformController) {
@@ -19369,7 +19822,7 @@ function validateExtractedTree(stagingRoot) {
19369
19822
  const lst = lstatSync(fullPath);
19370
19823
  if (lst.isSymbolicLink()) {
19371
19824
  const linkTarget = readlinkSync(fullPath);
19372
- const resolvedTarget = resolve8(dirname7(fullPath), linkTarget);
19825
+ const resolvedTarget = resolve8(dirname8(fullPath), linkTarget);
19373
19826
  const rel = relative2(realRoot, resolvedTarget);
19374
19827
  if (rel.startsWith("..") || isAbsolute6(rel) || win32.isAbsolute(rel)) {
19375
19828
  throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
@@ -19505,7 +19958,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
19505
19958
  unlinkSync4(dst);
19506
19959
  } catch {}
19507
19960
  const dstForContainment = join14(targetRoot, link.name);
19508
- const resolvedTarget = resolve8(dirname7(dstForContainment), link.target);
19961
+ const resolvedTarget = resolve8(dirname8(dstForContainment), link.target);
19509
19962
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
19510
19963
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
19511
19964
  if (requiredLibs.has(link.name)) {
@@ -19557,9 +20010,9 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
19557
20010
  function readOnnxInstalledMeta(installDir) {
19558
20011
  const path = join14(installDir, ONNX_INSTALLED_META_FILE);
19559
20012
  try {
19560
- if (!statSync8(path).isFile())
20013
+ if (!statSync9(path).isFile())
19561
20014
  return null;
19562
- const raw = readFileSync8(path, "utf8");
20015
+ const raw = readFileSync9(path, "utf8");
19563
20016
  const parsed = JSON.parse(raw);
19564
20017
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
19565
20018
  return null;
@@ -19575,7 +20028,7 @@ function readOnnxInstalledMeta(installDir) {
19575
20028
  }
19576
20029
  function sha256File2(path) {
19577
20030
  const hash = createHash5("sha256");
19578
- hash.update(readFileSync8(path));
20031
+ hash.update(readFileSync9(path));
19579
20032
  return hash.digest("hex");
19580
20033
  }
19581
20034
  function acquireLock(lockPath) {
@@ -19603,12 +20056,12 @@ ${new Date().toISOString()}
19603
20056
  let owningPid = null;
19604
20057
  let lockMtimeMs = 0;
19605
20058
  try {
19606
- const raw = readFileSync8(lockPath, "utf8");
20059
+ const raw = readFileSync9(lockPath, "utf8");
19607
20060
  const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
19608
20061
  const parsed = Number.parseInt(firstLine, 10);
19609
20062
  if (Number.isFinite(parsed) && parsed > 0)
19610
20063
  owningPid = parsed;
19611
- lockMtimeMs = statSync8(lockPath).mtimeMs;
20064
+ lockMtimeMs = statSync9(lockPath).mtimeMs;
19612
20065
  } catch {
19613
20066
  return tryClaim();
19614
20067
  }
@@ -19628,7 +20081,7 @@ function releaseLock(lockPath) {
19628
20081
  try {
19629
20082
  let owningPid = null;
19630
20083
  try {
19631
- const raw = readFileSync8(lockPath, "utf8");
20084
+ const raw = readFileSync9(lockPath, "utf8");
19632
20085
  const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
19633
20086
  const parsed = Number.parseInt(firstLine, 10);
19634
20087
  if (Number.isFinite(parsed) && parsed > 0)
@@ -20319,7 +20772,7 @@ function formatSemanticIndexStatus(status, stage, error, backend) {
20319
20772
  return status;
20320
20773
  }
20321
20774
  // src/config.ts
20322
- import { existsSync as existsSync12, readFileSync as readFileSync9, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "node:fs";
20775
+ import { existsSync as existsSync12, readFileSync as readFileSync10, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "node:fs";
20323
20776
  import { homedir as homedir11 } from "node:os";
20324
20777
  import { isAbsolute as isAbsolute7, parse as parsePath, resolve as resolvePath } from "node:path";
20325
20778
  var import_comment_json = __toESM(require_src2(), 1);
@@ -25162,6 +25615,17 @@ var SemanticConfigSchema = object({
25162
25615
  max_input_tokens: number2().int().positive().optional(),
25163
25616
  max_files: number2().int().positive().optional()
25164
25617
  });
25618
+ var RerankConfigSchema = object({
25619
+ backend: _enum(["off", "onnx", "remote", "synapse"]).optional(),
25620
+ model: string2().trim().min(1).optional(),
25621
+ endpoint: string2().trim().min(1).optional(),
25622
+ api_key_env: string2().trim().min(1).optional(),
25623
+ top_n: number2().int().positive().optional(),
25624
+ timeout_ms: number2().int().positive().optional()
25625
+ });
25626
+ var SearchConfigSchema = object({
25627
+ rerank: RerankConfigSchema.optional()
25628
+ });
25165
25629
  var LspExtensionSchema = string2().trim().min(1).refine((value) => value.replace(/^\.+/, "").length > 0, {
25166
25630
  message: "Extension must include characters other than leading dots"
25167
25631
  });
@@ -25307,6 +25771,7 @@ var AftConfigFieldsSchema = object({
25307
25771
  lsp: LspConfigSchema.optional(),
25308
25772
  url_fetch_allow_private: boolean2().optional(),
25309
25773
  semantic: SemanticConfigSchema.optional(),
25774
+ search: SearchConfigSchema.optional(),
25310
25775
  auto_update: boolean2().optional(),
25311
25776
  bridge: BridgeConfigSchema.optional(),
25312
25777
  subc: SubcConfigSchema.optional(),
@@ -25551,7 +26016,7 @@ function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 })
25551
26016
  let tmpPath = null;
25552
26017
  let oldKeys = [];
25553
26018
  try {
25554
- const content = readFileSync9(configPath, "utf-8");
26019
+ const content = readFileSync10(configPath, "utf-8");
25555
26020
  const rawConfig = import_comment_json.parse(content);
25556
26021
  if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
25557
26022
  return { migrated: false, oldKeys: [] };
@@ -25618,6 +26083,18 @@ function parseConfigPartially(rawConfig) {
25618
26083
  return partialConfig;
25619
26084
  }
25620
26085
  var configLoadErrors = [];
26086
+ var configValidationErrors = [];
26087
+ var configLoadSources = [];
26088
+ var configLoadTexts = new Map;
26089
+ function getConfigLoadSources() {
26090
+ return configLoadSources;
26091
+ }
26092
+ function getConfigLoadTexts() {
26093
+ return configLoadTexts;
26094
+ }
26095
+ function getConfigValidationErrors() {
26096
+ return configValidationErrors;
26097
+ }
25621
26098
  function getConfigLoadErrors() {
25622
26099
  return configLoadErrors;
25623
26100
  }
@@ -25650,7 +26127,9 @@ function loadConfigFromPath(configPath, tier) {
25650
26127
  if (!existsSync12(configPath)) {
25651
26128
  return null;
25652
26129
  }
25653
- const content = readFileSync9(configPath, "utf-8");
26130
+ const content = readFileSync10(configPath, "utf-8");
26131
+ configLoadSources.push(configPath);
26132
+ configLoadTexts.set(configPath, content);
25654
26133
  const rawConfig = import_comment_json.parse(content);
25655
26134
  migrateRawConfig(rawConfig, configPath, { log: log2, warn: warn2 });
25656
26135
  cleanConfig = stripJsoncSymbols(rawConfig);
@@ -25695,6 +26174,7 @@ function loadConfigFromPath(configPath, tier) {
25695
26174
  } else {
25696
26175
  const errorMsg = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
25697
26176
  warn2(`Config validation error in ${configPath}: ${errorMsg}`);
26177
+ configValidationErrors.push({ path: configPath, message: errorMsg });
25698
26178
  parsed = parseConfigPartially(cleanConfig);
25699
26179
  }
25700
26180
  if (!parsed)
@@ -25891,14 +26371,33 @@ function getStrippedTopLevelKeys(override) {
25891
26371
  for (const tool of partitionProjectDisables(override.disabled_tools).ignored) {
25892
26372
  stripped.push(`disabled_tools.${tool}`);
25893
26373
  }
26374
+ stripped.push(...projectRerankStrippedKeys(override.search?.rerank));
26375
+ return stripped;
26376
+ }
26377
+ function projectRerankStrippedKeys(rerank) {
26378
+ if (rerank === undefined)
26379
+ return [];
26380
+ const stripped = [];
26381
+ if (rerank.backend !== undefined && rerank.backend !== "off")
26382
+ stripped.push("search.rerank.backend");
26383
+ for (const key of ["model", "endpoint", "api_key_env", "top_n", "timeout_ms"]) {
26384
+ if (rerank[key] !== undefined)
26385
+ stripped.push(`search.rerank.${key}`);
26386
+ }
25894
26387
  return stripped;
25895
26388
  }
26389
+ function mergeProjectSearchConfig(base, project) {
26390
+ if (project?.rerank?.backend !== "off")
26391
+ return base;
26392
+ return { ...base, rerank: { ...base?.rerank, backend: "off" } };
26393
+ }
25896
26394
  function mergeConfigs(base, override) {
25897
26395
  const disabledTools = unionDisabledTools(base.disabled_tools, partitionProjectDisables(override.disabled_tools).accepted);
25898
26396
  const indexes = mergeIndexes(base.indexes, override.indexes, true);
25899
26397
  const formatter = { ...base.formatter, ...override.formatter };
25900
26398
  const checker = { ...base.checker, ...override.checker };
25901
26399
  const semantic = mergeSemanticConfig(base.semantic, override.semantic);
26400
+ const search = mergeProjectSearchConfig(base.search, override.search);
25902
26401
  const lsp = mergeLspConfig(base.lsp, override.lsp);
25903
26402
  const experimental = mergeExperimentalConfig(base.experimental, override.experimental);
25904
26403
  const bash = mergeBashConfig(base.bash, override.bash);
@@ -25928,6 +26427,7 @@ function mergeConfigs(base, override) {
25928
26427
  ...pi !== undefined ? { pi } : {},
25929
26428
  experimental,
25930
26429
  semantic,
26430
+ search,
25931
26431
  ...bridge !== undefined ? { bridge } : {},
25932
26432
  ...indexes !== undefined ? { indexes } : {},
25933
26433
  ...disabledTools !== undefined ? { disabled_tools: disabledTools } : {}
@@ -25992,6 +26492,9 @@ function buildConfigTierConfigureParams(projectDirectory, processState = {}) {
25992
26492
  }
25993
26493
  function loadAftConfig(projectDirectory) {
25994
26494
  configLoadErrors = [];
26495
+ configValidationErrors = [];
26496
+ configLoadSources = [];
26497
+ configLoadTexts = new Map;
25995
26498
  configLoadNotices = [];
25996
26499
  semanticInputSupplied = false;
25997
26500
  const { userConfigPath, projectConfigPath } = resolveAftConfigPaths(projectDirectory);
@@ -39824,16 +40327,29 @@ function markBridgeEnd() {
39824
40327
  slot.bridgeEnd = performance.now();
39825
40328
  }
39826
40329
  }
40330
+ async function measurePreStage(stage, operation) {
40331
+ const start = performance.now();
40332
+ try {
40333
+ return await operation();
40334
+ } finally {
40335
+ const slot = perfStore.getStore();
40336
+ if (slot) {
40337
+ slot.stages ??= {};
40338
+ slot.stages[stage] = (slot.stages[stage] ?? 0) + performance.now() - start;
40339
+ }
40340
+ }
40341
+ }
39827
40342
  function emit(slot) {
40343
+ const stages = slot.stages ? ` directory=${Math.round(slot.stages.directory ?? 0)}ms permission=${Math.round(slot.stages.permission ?? 0)}ms capability=${Math.round(slot.stages.capability ?? 0)}ms` : "";
39828
40344
  const t3 = performance.now();
39829
40345
  const total = Math.round(t3 - slot.t0);
39830
40346
  if (slot.bridgeStart !== undefined && slot.bridgeEnd !== undefined) {
39831
40347
  const pre = Math.round(slot.bridgeStart - slot.t0);
39832
40348
  const bridge = Math.round(slot.bridgeEnd - slot.bridgeStart);
39833
40349
  const post = Math.round(t3 - slot.bridgeEnd);
39834
- sessionLog(slot.sessionID, `perf tool=${slot.tool} total=${total}ms pre=${pre}ms bridge=${bridge}ms post=${post}ms`);
40350
+ sessionLog(slot.sessionID, `perf tool=${slot.tool} total=${total}ms pre=${pre}ms bridge=${bridge}ms post=${post}ms${stages}`);
39835
40351
  } else {
39836
- sessionLog(slot.sessionID, `perf tool=${slot.tool} total=${total}ms (no bridge call)`);
40352
+ sessionLog(slot.sessionID, `perf tool=${slot.tool} total=${total}ms (no bridge call)${stages}`);
39837
40353
  }
39838
40354
  }
39839
40355
  function instrumentToolMap(tools) {
@@ -40063,10 +40579,10 @@ import {
40063
40579
  createReadStream as createReadStream2,
40064
40580
  existsSync as existsSync15,
40065
40581
  mkdirSync as mkdirSync7,
40066
- readFileSync as readFileSync12,
40582
+ readFileSync as readFileSync13,
40067
40583
  renameSync as renameSync9,
40068
40584
  rmSync as rmSync5,
40069
- statSync as statSync10,
40585
+ statSync as statSync11,
40070
40586
  writeFileSync as writeFileSync8
40071
40587
  } from "node:fs";
40072
40588
  import { join as join17 } from "node:path";
@@ -40077,10 +40593,10 @@ import {
40077
40593
  closeSync as closeSync6,
40078
40594
  mkdirSync as mkdirSync6,
40079
40595
  openSync as openSync6,
40080
- readFileSync as readFileSync10,
40596
+ readFileSync as readFileSync11,
40081
40597
  renameSync as renameSync8,
40082
40598
  rmSync as rmSync4,
40083
- statSync as statSync9,
40599
+ statSync as statSync10,
40084
40600
  unlinkSync as unlinkSync6,
40085
40601
  writeFileSync as writeFileSync7
40086
40602
  } from "node:fs";
@@ -40103,7 +40619,7 @@ function lspBinDir(npmPackage) {
40103
40619
  function isInstalled(npmPackage, binary) {
40104
40620
  for (const candidate of lspBinaryCandidates(binary)) {
40105
40621
  try {
40106
- if (statSync9(join15(lspBinDir(npmPackage), candidate)).isFile())
40622
+ if (statSync10(join15(lspBinDir(npmPackage), candidate)).isFile())
40107
40623
  return true;
40108
40624
  } catch {}
40109
40625
  }
@@ -40131,9 +40647,9 @@ function writeInstalledMetaIn(installDir, version, sha256) {
40131
40647
  function readInstalledMetaIn(installDir) {
40132
40648
  const path = join15(installDir, INSTALLED_META_FILE);
40133
40649
  try {
40134
- if (!statSync9(path).isFile())
40650
+ if (!statSync10(path).isFile())
40135
40651
  return null;
40136
- const raw = readFileSync10(path, "utf8");
40652
+ const raw = readFileSync11(path, "utf8");
40137
40653
  const parsed = JSON.parse(raw);
40138
40654
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
40139
40655
  return null;
@@ -40202,12 +40718,12 @@ ${token}
40202
40718
  let owningPid = null;
40203
40719
  let lockMtimeMs = 0;
40204
40720
  try {
40205
- const raw = readFileSync10(lock, "utf8");
40721
+ const raw = readFileSync11(lock, "utf8");
40206
40722
  const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
40207
40723
  const parsed = Number.parseInt(firstLine, 10);
40208
40724
  if (Number.isFinite(parsed) && parsed > 0)
40209
40725
  owningPid = parsed;
40210
- lockMtimeMs = statSync9(lock).mtimeMs;
40726
+ lockMtimeMs = statSync10(lock).mtimeMs;
40211
40727
  } catch {
40212
40728
  return tryClaim();
40213
40729
  }
@@ -40241,7 +40757,7 @@ function releaseInstallLock(lockKey, acquisitionToken) {
40241
40757
  let owningPid = null;
40242
40758
  let owningToken = "";
40243
40759
  try {
40244
- const raw = readFileSync10(lock, "utf8");
40760
+ const raw = readFileSync11(lock, "utf8");
40245
40761
  const lines = raw.split(/\r?\n/);
40246
40762
  const parsed = Number.parseInt(lines[0]?.trim() ?? "", 10);
40247
40763
  if (Number.isFinite(parsed) && parsed > 0)
@@ -40288,7 +40804,7 @@ function autoInstallStampPath() {
40288
40804
  }
40289
40805
  function hasRecentAutoInstallStamp(path) {
40290
40806
  try {
40291
- const parsed = JSON.parse(readFileSync10(path, "utf8"));
40807
+ const parsed = JSON.parse(readFileSync11(path, "utf8"));
40292
40808
  return typeof parsed.lastRunMs === "number" && Number.isFinite(parsed.lastRunMs) && Math.abs(Date.now() - parsed.lastRunMs) < AUTO_INSTALL_WINDOW_MS;
40293
40809
  } catch {
40294
40810
  return false;
@@ -40296,7 +40812,7 @@ function hasRecentAutoInstallStamp(path) {
40296
40812
  }
40297
40813
  function readAutoInstallLockOwner(path) {
40298
40814
  try {
40299
- const parsed = JSON.parse(readFileSync10(path, "utf8"));
40815
+ const parsed = JSON.parse(readFileSync11(path, "utf8"));
40300
40816
  if (typeof parsed.pid !== "number" || typeof parsed.startedMs !== "number" || typeof parsed.token !== "string") {
40301
40817
  return null;
40302
40818
  }
@@ -40309,7 +40825,7 @@ function autoInstallLockIsStale(path) {
40309
40825
  const owner = readAutoInstallLockOwner(path);
40310
40826
  let age = Number.POSITIVE_INFINITY;
40311
40827
  try {
40312
- age = Math.abs(Date.now() - statSync9(path).mtimeMs);
40828
+ age = Math.abs(Date.now() - statSync10(path).mtimeMs);
40313
40829
  } catch {
40314
40830
  return true;
40315
40831
  }
@@ -40387,7 +40903,7 @@ var VERSION_CHECK_FILE = ".aft-version-check";
40387
40903
  function readVersionCheck(npmPackage) {
40388
40904
  const file = join15(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
40389
40905
  try {
40390
- const raw = readFileSync10(file, "utf8");
40906
+ const raw = readFileSync11(file, "utf8");
40391
40907
  const parsed = JSON.parse(raw);
40392
40908
  if (typeof parsed.last_checked === "string") {
40393
40909
  return {
@@ -40490,6 +41006,13 @@ var NPM_LSP_TABLE = [
40490
41006
  extensions: ["ts", "tsx", "js", "jsx", "mjs", "cjs", "mts", "cts"],
40491
41007
  rootMarkers: ["tsconfig.json", "jsconfig.json", "package.json"]
40492
41008
  },
41009
+ {
41010
+ id: "typescript-sdk",
41011
+ npm: "typescript",
41012
+ binary: "tsserver",
41013
+ extensions: ["ts", "tsx", "js", "jsx", "mjs", "cjs", "mts", "cts"],
41014
+ rootMarkers: ["tsconfig.json", "jsconfig.json", "package.json"]
41015
+ },
40493
41016
  {
40494
41017
  id: "python",
40495
41018
  npm: "pyright",
@@ -40564,7 +41087,7 @@ var NPM_LSP_TABLE = [
40564
41087
  ];
40565
41088
 
40566
41089
  // src/lsp-project-relevance.ts
40567
- import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync11 } from "node:fs";
41090
+ import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "node:fs";
40568
41091
  import { join as join16 } from "node:path";
40569
41092
  var MAX_WALK_DIRS = 200;
40570
41093
  var MAX_WALK_DEPTH = 4;
@@ -40606,7 +41129,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
40606
41129
  }
40607
41130
  function readPackageJson(projectRoot) {
40608
41131
  try {
40609
- const raw = readFileSync11(join16(projectRoot, "package.json"), "utf8");
41132
+ const raw = readFileSync12(join16(projectRoot, "package.json"), "utf8");
40610
41133
  const parsed = JSON.parse(raw);
40611
41134
  if (typeof parsed !== "object" || parsed === null)
40612
41135
  return null;
@@ -40954,7 +41477,7 @@ function hashInstalledBinary(spec) {
40954
41477
  let pathToHash = null;
40955
41478
  for (const p of candidates) {
40956
41479
  try {
40957
- if (statSync10(p).isFile()) {
41480
+ if (statSync11(p).isFile()) {
40958
41481
  pathToHash = p;
40959
41482
  break;
40960
41483
  }
@@ -40980,14 +41503,14 @@ function installedBinaryPath(spec) {
40980
41503
  ] : [lspBinaryPath(spec.npm, spec.binary)];
40981
41504
  for (const candidate of candidates) {
40982
41505
  try {
40983
- if (statSync10(candidate).isFile())
41506
+ if (statSync11(candidate).isFile())
40984
41507
  return candidate;
40985
41508
  } catch {}
40986
41509
  }
40987
41510
  return null;
40988
41511
  }
40989
41512
  function sha256OfFileSync(path) {
40990
- return createHash7("sha256").update(readFileSync12(path)).digest("hex");
41513
+ return createHash7("sha256").update(readFileSync13(path)).digest("hex");
40991
41514
  }
40992
41515
  function quarantineCachedNpmInstall(spec, reason) {
40993
41516
  const packageDir = lspPackageDir(spec.npm);
@@ -41030,7 +41553,7 @@ function runAutoInstall(projectRoot, config, fetchImpl = fetch) {
41030
41553
  if (isInstalled(spec.npm, spec.binary) && validateCachedNpmInstall(spec)) {
41031
41554
  cachedBinDirs.push(lspBinDir(spec.npm));
41032
41555
  }
41033
- if (config.disabled.has(spec.id)) {
41556
+ if (config.disabled.has(spec.id) || spec.id === "typescript-sdk" && config.disabled.has("typescript")) {
41034
41557
  skipped.push({ id: spec.id, reason: "disabled by config" });
41035
41558
  continue;
41036
41559
  }
@@ -41086,16 +41609,16 @@ import {
41086
41609
  lstatSync as lstatSync2,
41087
41610
  mkdirSync as mkdirSync8,
41088
41611
  readdirSync as readdirSync5,
41089
- readFileSync as readFileSync13,
41612
+ readFileSync as readFileSync14,
41090
41613
  readlinkSync as readlinkSync2,
41091
41614
  realpathSync as realpathSync4,
41092
41615
  renameSync as renameSync10,
41093
41616
  rmSync as rmSync6,
41094
- statSync as statSync11,
41617
+ statSync as statSync12,
41095
41618
  unlinkSync as unlinkSync7,
41096
41619
  writeFileSync as writeFileSync9
41097
41620
  } from "node:fs";
41098
- import { dirname as dirname8, join as join18, relative as relative3, resolve as resolve10 } from "node:path";
41621
+ import { dirname as dirname9, join as join18, relative as relative3, resolve as resolve10 } from "node:path";
41099
41622
  import { Readable as Readable3 } from "node:stream";
41100
41623
  import { pipeline as pipeline3 } from "node:stream/promises";
41101
41624
 
@@ -41204,7 +41727,7 @@ function installFailureMarkerPath(spec) {
41204
41727
  }
41205
41728
  function readInstallFailureMarker(spec) {
41206
41729
  try {
41207
- const marker = JSON.parse(readFileSync13(installFailureMarkerPath(spec), "utf8"));
41730
+ const marker = JSON.parse(readFileSync14(installFailureMarkerPath(spec), "utf8"));
41208
41731
  if (typeof marker.release !== "string" || typeof marker.sha256 !== "string" || typeof marker.error !== "string" || typeof marker.at !== "string" || !Number.isFinite(Date.parse(marker.at))) {
41209
41732
  return null;
41210
41733
  }
@@ -41218,7 +41741,7 @@ function writeInstallFailureMarker(spec, release, sha256, installError) {
41218
41741
  const markerError = installError.replace(/\s+/g, " ").trim();
41219
41742
  const tempPath = `${path}.tmp-${process.pid}-${randomBytes4(6).toString("hex")}`;
41220
41743
  try {
41221
- mkdirSync8(dirname8(path), { recursive: true });
41744
+ mkdirSync8(dirname9(path), { recursive: true });
41222
41745
  writeFileSync9(tempPath, `${JSON.stringify({ release, sha256, error: markerError, at: new Date().toISOString() })}
41223
41746
  `, { encoding: "utf8", mode: 384 });
41224
41747
  renameSync10(tempPath, path);
@@ -41247,7 +41770,7 @@ function ghBinaryPath(spec, platform) {
41247
41770
  function isGithubInstalled(spec, platform) {
41248
41771
  for (const candidate of ghBinaryCandidates(spec, platform)) {
41249
41772
  try {
41250
- if (statSync11(join18(ghBinDir(spec), candidate)).isFile())
41773
+ if (statSync12(join18(ghBinDir(spec), candidate)).isFile())
41251
41774
  return true;
41252
41775
  } catch {}
41253
41776
  }
@@ -41261,9 +41784,9 @@ function ghBinaryCandidates(spec, platform) {
41261
41784
  function readGithubInstalledMetaIn(installDir) {
41262
41785
  try {
41263
41786
  const path = join18(installDir, INSTALLED_META_FILE2);
41264
- if (!statSync11(path).isFile())
41787
+ if (!statSync12(path).isFile())
41265
41788
  return null;
41266
- const parsed = JSON.parse(readFileSync13(path, "utf8"));
41789
+ const parsed = JSON.parse(readFileSync14(path, "utf8"));
41267
41790
  if (typeof parsed.version !== "string" || parsed.version.length === 0)
41268
41791
  return null;
41269
41792
  return {
@@ -41304,7 +41827,7 @@ function sha256OfFile(path) {
41304
41827
  });
41305
41828
  }
41306
41829
  function sha256OfFileSync2(path) {
41307
- return createHash8("sha256").update(readFileSync13(path)).digest("hex");
41830
+ return createHash8("sha256").update(readFileSync14(path)).digest("hex");
41308
41831
  }
41309
41832
  async function fetchReleaseByTag(githubRepo, tag, fetchImpl, signal) {
41310
41833
  const candidates = [];
@@ -41480,7 +42003,7 @@ async function downloadFile(url, destPath, fetchImpl, assetSize, signal) {
41480
42003
  if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES3) {
41481
42004
  throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES3}`);
41482
42005
  }
41483
- mkdirSync8(dirname8(destPath), { recursive: true });
42006
+ mkdirSync8(dirname9(destPath), { recursive: true });
41484
42007
  let bytesWritten = 0;
41485
42008
  const guard = new TransformStream({
41486
42009
  transform(chunk, controller) {
@@ -41650,7 +42173,7 @@ function quarantineCachedGithubInstall(spec, reason) {
41650
42173
  const dest = join18(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
41651
42174
  warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
41652
42175
  try {
41653
- mkdirSync8(dirname8(dest), { recursive: true });
42176
+ mkdirSync8(dirname9(dest), { recursive: true });
41654
42177
  rmSync6(dest, { recursive: true, force: true });
41655
42178
  renameSync10(packageDir, dest);
41656
42179
  } catch (err) {
@@ -41662,7 +42185,7 @@ function validateCachedGithubInstall(spec, platform) {
41662
42185
  const meta = readGithubInstalledMetaIn(packageDir);
41663
42186
  const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join18(ghBinDir(spec), candidate)).find((candidate) => {
41664
42187
  try {
41665
- return statSync11(candidate).isFile();
42188
+ return statSync12(candidate).isFile();
41666
42189
  } catch {
41667
42190
  return false;
41668
42191
  }
@@ -41780,7 +42303,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
41780
42303
  return { ok: false, sha256: archiveSha256, error: message };
41781
42304
  }
41782
42305
  const targetBinary = ghBinaryPath(spec, platform);
41783
- mkdirSync8(dirname8(targetBinary), { recursive: true });
42306
+ mkdirSync8(dirname9(targetBinary), { recursive: true });
41784
42307
  try {
41785
42308
  copyFileSync3(innerBinaryPath, targetBinary);
41786
42309
  if (platform !== "win32") {
@@ -42309,14 +42832,16 @@ async function assertExternalDirectoryPermission(ctx, context, target, options)
42309
42832
  const directory = root ? normalizePath(root) : root;
42310
42833
  const rawWorktree = context.worktree;
42311
42834
  const worktree = rawWorktree && rawWorktree !== "/" ? normalizePath(rawWorktree) : rawWorktree;
42835
+ const restrictToProjectRoot = ctx.config.restrict_to_project_root === true;
42312
42836
  if (directory && containsPath(directory, absoluteTarget))
42313
42837
  return;
42314
- if (worktree && worktree !== "/" && worktree !== directory && containsPath(worktree, absoluteTarget)) {
42838
+ if (!restrictToProjectRoot && worktree && worktree !== "/" && worktree !== directory && containsPath(worktree, absoluteTarget)) {
42315
42839
  return;
42316
42840
  }
42317
- if (ctx.config.restrict_to_project_root === true) {
42318
- if (options?.serverValidatedRead === true)
42841
+ if (restrictToProjectRoot) {
42842
+ if (options?.serverValidatedRead === true && await isSessionOwnedBashArtifact(ctx, context, absoluteTarget)) {
42319
42843
  return;
42844
+ }
42320
42845
  notifyRestrictBlocked(ctx, context, absoluteTarget);
42321
42846
  return restrictDenialMessage(absoluteTarget);
42322
42847
  }
@@ -42846,8 +43371,87 @@ function projectV2Tool(name, definition, location, consumers = {}) {
42846
43371
  }
42847
43372
 
42848
43373
  // src/tools/hoisted.ts
43374
+ import { stat as stat2 } from "node:fs/promises";
42849
43375
  import * as path4 from "node:path";
42850
43376
 
43377
+ // src/shared/read-vision.ts
43378
+ var VISION_HOST_TIMEOUT_MS = 1500;
43379
+ var states = new WeakMap;
43380
+ function stateFor2(client) {
43381
+ let state = states.get(client);
43382
+ if (!state) {
43383
+ state = { models: new Map, history: new Map, capabilities: new Map };
43384
+ states.set(client, state);
43385
+ }
43386
+ return state;
43387
+ }
43388
+ function rememberReadModel(client, sessionID, model) {
43389
+ stateFor2(client).models.set(sessionID, model);
43390
+ }
43391
+ async function bounded(call) {
43392
+ let timer;
43393
+ try {
43394
+ return await Promise.race([
43395
+ Promise.resolve().then(call),
43396
+ new Promise((resolve) => {
43397
+ timer = setTimeout(() => resolve(undefined), VISION_HOST_TIMEOUT_MS);
43398
+ })
43399
+ ]);
43400
+ } catch {
43401
+ return;
43402
+ } finally {
43403
+ clearTimeout(timer);
43404
+ }
43405
+ }
43406
+ function record3(value) {
43407
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
43408
+ }
43409
+ async function currentSessionVisionCapability(client, sessionID) {
43410
+ if (!sessionID)
43411
+ return;
43412
+ const state = stateFor2(client);
43413
+ let model = state.models.get(sessionID);
43414
+ if (!model) {
43415
+ let pending = state.history.get(sessionID);
43416
+ if (!pending) {
43417
+ pending = bounded(() => resolvePromptContext(client, sessionID)).then((context) => context?.model);
43418
+ state.history.set(sessionID, pending);
43419
+ pending.finally(() => state.history.delete(sessionID));
43420
+ }
43421
+ const historical = await pending;
43422
+ model = state.models.get(sessionID) ?? historical;
43423
+ }
43424
+ if (!model)
43425
+ return;
43426
+ const currentModel = model;
43427
+ const key = JSON.stringify([model.providerID, model.modelID]);
43428
+ let capability = state.capabilities.get(key);
43429
+ if (!capability) {
43430
+ capability = (async () => {
43431
+ const api = client.provider;
43432
+ if (!api?.list)
43433
+ return;
43434
+ const list = api.list.bind(api);
43435
+ const listed = record3(await bounded(list));
43436
+ const catalog = record3(listed?.data) ?? listed;
43437
+ const providers = catalog?.all ?? catalog?.providers;
43438
+ if (!Array.isArray(providers))
43439
+ return;
43440
+ const provider = providers.map(record3).find((entry) => entry?.id === currentModel.providerID);
43441
+ const models = provider?.models;
43442
+ const entry = record3(Array.isArray(models) ? models.find((entry) => record3(entry)?.id === currentModel.modelID) : record3(models)?.[currentModel.modelID]);
43443
+ const inputs = record3(entry?.modalities)?.input;
43444
+ return Array.isArray(inputs) ? inputs.includes("image") : typeof entry?.attachment === "boolean" ? entry.attachment : undefined;
43445
+ })();
43446
+ state.capabilities.set(key, capability);
43447
+ capability.then((value) => {
43448
+ if (value === undefined)
43449
+ state.capabilities.delete(key);
43450
+ });
43451
+ }
43452
+ return capability;
43453
+ }
43454
+
42851
43455
  // src/shared/subagent-detect.ts
42852
43456
  import { Effect as Effect2 } from "effect";
42853
43457
  var CACHE_MAX_ENTRIES2 = 200;
@@ -43434,7 +44038,7 @@ A notification will fire when the pattern matches or the task exits.`;
43434
44038
  const data = await waitForBashStatus(ctx, context, taskId, undefined, waitFor, effectiveWaitMs);
43435
44039
  const waited = data.waited;
43436
44040
  if (waited?.reason === "user_message") {
43437
- const convertedText = await convertToAsyncWatchOnAbort(ctx, context, taskId, waitFor, coerceBoolean(args.once, true));
44041
+ const convertedText = await convertToAsyncWatchOnAbort(ctx, context, taskId, waitFor, coerceBoolean(args.once, true), waited.elapsed_ms);
43438
44042
  const metadata = context.metadata;
43439
44043
  metadata?.({ taskId, status: data.status, waited, convertedToAsync: true });
43440
44044
  return convertedText;
@@ -43446,9 +44050,10 @@ A notification will fire when the pattern matches or the task exits.`;
43446
44050
  }
43447
44051
  };
43448
44052
  }
43449
- async function convertToAsyncWatchOnAbort(ctx, context, taskId, waitFor, once) {
44053
+ async function convertToAsyncWatchOnAbort(ctx, context, taskId, waitFor, once, elapsedMs) {
44054
+ const interrupted = `Sync watch for task ${taskId} was interrupted because you sent a message after ${elapsedMs}ms of waiting. `;
43450
44055
  if (!waitFor) {
43451
- return `Sync watch for task ${taskId} was interrupted because you sent a message. ` + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits; don't poll bash_status.`;
44056
+ return interrupted + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits; don't poll bash_status.`;
43452
44057
  }
43453
44058
  const notifyParams = {
43454
44059
  task_id: taskId,
@@ -43463,12 +44068,12 @@ async function convertToAsyncWatchOnAbort(ctx, context, taskId, waitFor, once) {
43463
44068
  const registered = await callBashBridge(ctx, context, "bash_notify", notifyParams);
43464
44069
  if (registered.success === false) {
43465
44070
  unmarkExplicitControl(context.sessionID, taskId);
43466
- return `Sync watch for task ${taskId} was interrupted because you sent a message. ` + `Auto-registering an async watch failed (${String(registered.message ?? "unknown error")}). ` + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits.`;
44071
+ return interrupted + `Auto-registering an async watch failed (${String(registered.message ?? "unknown error")}). ` + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits.`;
43467
44072
  }
43468
- return `Sync watch for task ${taskId} was interrupted because you sent a message. ` + `The wait has been converted to an async watch (${registered.watch_id}). ` + `A notification will fire when the pattern matches or the task exits.`;
44073
+ return interrupted + `The wait has been converted to an async watch (${registered.watch_id}). ` + `A notification will fire when the pattern matches or the task exits.`;
43469
44074
  } catch (err) {
43470
44075
  unmarkExplicitControl(context.sessionID, taskId);
43471
- return `Sync watch for task ${taskId} was interrupted because you sent a message. ` + `Auto-registering an async watch failed (${err instanceof Error ? err.message : String(err)}). ` + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits.`;
44076
+ return interrupted + `Auto-registering an async watch failed (${err instanceof Error ? err.message : String(err)}). ` + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits.`;
43472
44077
  }
43473
44078
  }
43474
44079
  function formatWatchResultText(taskId, data, waited, role, syncWaitCap) {
@@ -43477,21 +44082,22 @@ function formatWatchResultText(taskId, data, waited, role, syncWaitCap) {
43477
44082
  const dur = typeof data.duration_ms === "number" ? ` ${Math.round(data.duration_ms / 1000)}s` : "";
43478
44083
  let text = `Task ${taskId}: ${status}${exit}${dur}`;
43479
44084
  if (waited) {
44085
+ const waitedText = formatWatchWaited(waited.elapsed_ms, waited.limit_ms, syncWaitCap);
43480
44086
  if (waited.reason === "matched") {
43481
44087
  const stream = waited.match_stream ? ` in ${waited.match_stream}` : "";
43482
44088
  text += `
43483
- Waited ${waited.elapsed_ms}ms; matched ${JSON.stringify(waited.match ?? "")}${stream} at offset ${waited.match_offset ?? 0}.`;
44089
+ ${waitedText}; matched ${JSON.stringify(waited.match ?? "")}${stream} at offset ${waited.match_offset ?? 0}.`;
43484
44090
  } else if (waited.reason === "timeout") {
43485
44091
  text += `
43486
- Waited ${waited.elapsed_ms}ms; timeout reached without match. ${watchTimeoutSteer(role, syncWaitCap)}`;
44092
+ ${waitedText}; timeout reached without match. ${watchTimeoutSteer(role, syncWaitCap)}`;
43487
44093
  } else if (waited.reason === "unavailable") {
43488
44094
  text += `
43489
- Waited ${waited.elapsed_ms}ms; the bridge was busy, so task state is unknown. Do not poll; let the task's completion notification wake the session, or use one bash_status snapshot on the next normal tool call.`;
44095
+ ${waitedText}; the bridge was busy, so task state is unknown. Do not poll; let the task's completion notification wake the session, or use one bash_status snapshot on the next normal tool call.`;
43490
44096
  } else {
43491
44097
  const stat = String(data.status ?? "unknown");
43492
44098
  const e = typeof data.exit_code === "number" ? `, exit ${data.exit_code}` : "";
43493
44099
  text += `
43494
- Waited ${waited.elapsed_ms}ms; task exited (${stat}${e}).`;
44100
+ ${waitedText}; task exited (${stat}${e}).`;
43495
44101
  }
43496
44102
  }
43497
44103
  const preview = data.output_preview;
@@ -43513,8 +44119,9 @@ async function bashStatusSnapshot2(ctx, runtime, taskId, outputMode, cursor, opt
43513
44119
  return data;
43514
44120
  }
43515
44121
  async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effectiveWaitMs) {
43516
- const startedAt = Date.now();
44122
+ const startedAt = monotonicNowMs();
43517
44123
  const deadline = startedAt + effectiveWaitMs;
44124
+ const elapsedMs = () => Math.round(monotonicNowMs() - startedAt);
43518
44125
  let spillCursor = { output: 0, stderr: 0 };
43519
44126
  const scanState = {
43520
44127
  output: { text: "", baseOffset: 0 },
@@ -43539,16 +44146,18 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
43539
44146
  if (isSyncWatchAborted(runtime.sessionID)) {
43540
44147
  return withWaited(lastData ?? unavailableSnapshot(), {
43541
44148
  reason: "user_message",
43542
- elapsed_ms: Date.now() - startedAt
44149
+ elapsed_ms: elapsedMs(),
44150
+ limit_ms: effectiveWaitMs
43543
44151
  });
43544
44152
  }
43545
- if (Date.now() >= deadline) {
44153
+ if (monotonicNowMs() >= deadline) {
43546
44154
  return withWaited(lastData ?? unavailableSnapshot(), {
43547
44155
  reason: "unavailable",
43548
- elapsed_ms: Date.now() - startedAt
44156
+ elapsed_ms: elapsedMs(),
44157
+ limit_ms: effectiveWaitMs
43549
44158
  });
43550
44159
  }
43551
- await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())));
44160
+ await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - monotonicNowMs())));
43552
44161
  continue;
43553
44162
  }
43554
44163
  lastData = data;
@@ -43577,7 +44186,8 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
43577
44186
  const matchStream = data.mode === "pty" ? undefined : chunk.stream === "output" ? "stdout" : "stderr";
43578
44187
  return withWaited(data, {
43579
44188
  reason: "matched",
43580
- elapsed_ms: Date.now() - startedAt,
44189
+ elapsed_ms: elapsedMs(),
44190
+ limit_ms: effectiveWaitMs,
43581
44191
  match: match.text,
43582
44192
  match_offset: state.baseOffset + match.byteOffset,
43583
44193
  match_stream: matchStream
@@ -43595,15 +44205,27 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
43595
44205
  sawTerminal = true;
43596
44206
  consumeBgCompletion(runtime.sessionID, taskId);
43597
44207
  await markBgCompletionDelivered({ ctx, directory: projectRootFor(runtime), sessionID: runtime.sessionID }, taskId);
43598
- return withWaited(data, { reason: "exited", elapsed_ms: Date.now() - startedAt });
44208
+ return withWaited(data, {
44209
+ reason: "exited",
44210
+ elapsed_ms: elapsedMs(),
44211
+ limit_ms: effectiveWaitMs
44212
+ });
43599
44213
  }
43600
44214
  if (isSyncWatchAborted(runtime.sessionID)) {
43601
- return withWaited(data, { reason: "user_message", elapsed_ms: Date.now() - startedAt });
44215
+ return withWaited(data, {
44216
+ reason: "user_message",
44217
+ elapsed_ms: elapsedMs(),
44218
+ limit_ms: effectiveWaitMs
44219
+ });
43602
44220
  }
43603
- if (Date.now() >= deadline) {
43604
- return withWaited(data, { reason: "timeout", elapsed_ms: Date.now() - startedAt });
44221
+ if (monotonicNowMs() >= deadline) {
44222
+ return withWaited(data, {
44223
+ reason: "timeout",
44224
+ elapsed_ms: elapsedMs(),
44225
+ limit_ms: effectiveWaitMs
44226
+ });
43605
44227
  }
43606
- await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())));
44228
+ await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - monotonicNowMs())));
43607
44229
  }
43608
44230
  } finally {
43609
44231
  if (!sawTerminal)
@@ -43751,47 +44373,6 @@ var ISSUE_AND_PR_READ_DESCRIPTION = "GitHub issues and pull requests can be read
43751
44373
  function whenGhReadEnabled(enabled, description) {
43752
44374
  return enabled ? description : "";
43753
44375
  }
43754
- function asRecord(value) {
43755
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
43756
- }
43757
- function visionCapabilityForOpenCodeModel(model) {
43758
- const entry = model;
43759
- if (Array.isArray(entry?.modalities?.input)) {
43760
- return entry.modalities.input.includes("image");
43761
- }
43762
- return typeof entry?.attachment === "boolean" ? entry.attachment : undefined;
43763
- }
43764
- function modelFromOpenCodeProvider(provider, modelID) {
43765
- const models = provider.models;
43766
- if (Array.isArray(models)) {
43767
- return models.find((model) => asRecord(model)?.id === modelID);
43768
- }
43769
- return asRecord(models)?.[modelID];
43770
- }
43771
- async function currentSessionVisionCapability(client, sessionID) {
43772
- if (!sessionID)
43773
- return;
43774
- const promptContext = await resolvePromptContext(client, sessionID);
43775
- const currentModel = promptContext?.model;
43776
- if (!currentModel)
43777
- return;
43778
- const providerApi = client.provider;
43779
- if (typeof providerApi?.list !== "function")
43780
- return;
43781
- let listed;
43782
- try {
43783
- listed = await providerApi.list();
43784
- } catch {
43785
- return;
43786
- }
43787
- const result = asRecord(listed);
43788
- const catalog = asRecord(result?.data) ?? result;
43789
- const providers = Array.isArray(catalog?.all) ? catalog.all : Array.isArray(catalog?.providers) ? catalog.providers : [];
43790
- const provider = providers.map(asRecord).find((entry) => entry?.id === currentModel.providerID);
43791
- if (!provider)
43792
- return;
43793
- return visionCapabilityForOpenCodeModel(modelFromOpenCodeProvider(provider, currentModel.modelID));
43794
- }
43795
44376
  function persistFilePathAlias(args, context) {
43796
44377
  if (typeof args.path === "string" && !Object.hasOwn(args, "filePath")) {
43797
44378
  args.filePath = args.path;
@@ -43963,7 +44544,7 @@ function inferBeforeStart(ops, from, beforeLen) {
43963
44544
  var z7 = tool.schema;
43964
44545
  var READ_DESCRIPTION = `Read file contents or list directory entries.
43965
44546
 
43966
- Use either startLine/endLine OR offset/limit to read a section of a file.
44547
+ Use either startLine/endLine OR offset/limit to read a section of a file or sorted directory listing.
43967
44548
 
43968
44549
  Behavior:
43969
44550
  - Returns line-numbered content (e.g., "1: const x = 1")
@@ -43971,7 +44552,7 @@ Behavior:
43971
44552
  - Output capped at 50KB
43972
44553
  - Binary files are auto-detected and return a size-only message
43973
44554
  - Supported images (PNG, JPEG, GIF, WebP) and PDFs are returned as tool attachments; range arguments are ignored for media
43974
- - Directories return sorted entries with trailing / for subdirectories
44555
+ - Directories return sorted entries with trailing / for subdirectories; offset is 1-based, limit defaults to and is capped at 1000 entries. Enumeration stops at 10,000 entries; partial listings carry a shown/total trailer.
43975
44556
 
43976
44557
  Examples:
43977
44558
  Read full file: { "path": "src/app.ts" }
@@ -43995,30 +44576,30 @@ function createReadTool(ctx) {
43995
44576
  description: readDescription(resolveGithubConfig(ctx.config).read),
43996
44577
  args: {
43997
44578
  filePath: z7.string().describe("Path to file or directory (absolute or relative to project root)"),
43998
- startLine: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("1-based line to start reading from"),
43999
- endLine: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("1-based line to stop reading at (inclusive)"),
44000
- limit: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("Max lines to return (default: 2000)"),
44001
- offset: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("1-based line number to start reading from (use with limit). Ignored if startLine is provided")
44579
+ startLine: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("1-based line or directory entry to start reading from"),
44580
+ endLine: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("1-based line or directory entry to stop reading at (inclusive)"),
44581
+ limit: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("Max lines (default: 2000) or directory entries (default and cap: 1000) to return"),
44582
+ offset: optionalInt(1, Number.MAX_SAFE_INTEGER).describe("1-based line or directory entry to start reading from (use with limit). Ignored if startLine is provided")
44002
44583
  },
44003
44584
  execute: async (args, context) => {
44004
44585
  const file = args.path;
44005
- const projectRoot = await resolveProjectRoot(ctx, context);
44586
+ const projectRoot = await measurePreStage("directory", () => resolveProjectRoot(ctx, context));
44006
44587
  const filePath = resolvePathFromProjectRoot(projectRoot, file);
44007
44588
  persistFilePathAlias(args, context);
44008
44589
  {
44009
- const denial = await assertExternalDirectoryPermission(ctx, context, filePath, {
44590
+ const denial = await measurePreStage("permission", () => assertExternalDirectoryPermission(ctx, context, filePath, {
44010
44591
  serverValidatedRead: true
44011
- });
44592
+ }));
44012
44593
  if (denial)
44013
44594
  return permissionDeniedResponse(denial);
44014
44595
  }
44015
44596
  try {
44016
- await runAsk(context.ask({
44597
+ await measurePreStage("permission", () => runAsk(context.ask({
44017
44598
  permission: "read",
44018
44599
  patterns: [permissionPath(context, filePath)],
44019
44600
  always: ["*"],
44020
44601
  metadata: {}
44021
- }));
44602
+ })));
44022
44603
  } catch (error) {
44023
44604
  const failure = classifyPermissionError(error);
44024
44605
  return permissionDeniedResponse(failure.kind === "rule_denied" ? permissionRuleDenial("read") : failure.message);
@@ -44042,7 +44623,8 @@ function createReadTool(ctx) {
44042
44623
  rawArgs.endLine = endLine;
44043
44624
  if (rawLimit !== undefined && rawOffset === undefined)
44044
44625
  rawArgs.limit = rawLimit;
44045
- const visionCapability = await currentSessionVisionCapability(ctx.client, context.sessionID);
44626
+ const mediaCandidate = isGithubResourcePath(file) || /\.(png|jpe?g|gif|webp|pdf)$/i.test(filePath) && await stat2(filePath).then((info) => info.isFile(), () => false);
44627
+ const visionCapability = mediaCandidate ? await measurePreStage("capability", () => currentSessionVisionCapability(ctx.client, context.sessionID)) : undefined;
44046
44628
  if (visionCapability !== undefined)
44047
44629
  rawArgs.vision_capability = visionCapability;
44048
44630
  const response = await callToolCall(ctx, context, "read", rawArgs);
@@ -44486,7 +45068,7 @@ function createApplyPatchTool(ctx) {
44486
45068
  };
44487
45069
  }
44488
45070
  function deleteDescription(ctx) {
44489
- const backupText = ctx.config.backup?.enabled === false ? "Backup capture is disabled by user config, so this tool does not create undo snapshots. " : "Each file is backed up before deletion — use aft_safety undo to recover any of them. For directories, every file inside is individually backed up before the tree is removed. The deleted file's contents stay in the undo store until its retention expires. A recursive delete whose backup would copy more than 2,000 files or 100 MiB in one call is refused before anything is deleted; delete such a tree in smaller pieces, or use bash `rm -rf` when no undo is needed. ";
45071
+ const backupText = ctx.config.backup?.enabled === false ? "Backup capture is disabled by user config, so this tool does not create undo snapshots. A directory tree containing a mount point of another filesystem is still refused. " : "Each file is backed up before deletion — use aft_safety undo to recover any of them. A recursive delete backs up the whole tree: directories (empty ones too, with their permissions), file contents, hard links (relinked by undo) and symlinks (the link itself, never its target; restored exactly, even when dangling). Sockets are deleted but undo does not restore them, and a file hard-linked to paths outside the tree comes back as an independent copy; both are reported as warnings. Refused before anything is deleted: mount points of another filesystem, named pipes, device nodes, and symlinks undo cannot recreate exactly (non-UTF-8 target, or on Windows). Paths under the system temp directory are never backed up, so only mount points are refused there. The deleted file's contents stay in the undo store until its retention expires. A recursive delete whose backup would record more than 2,000 entries (files, directories and links) or copy 100 MiB in one call is refused before anything is deleted; delete such a tree in smaller pieces, or use bash `rm -rf` when no undo is needed. ";
44490
45072
  return `Delete one or more files (or directories).
44491
45073
 
44492
45074
  ` + backupText + `Directory deletion requires recursive: true. Without it, passing a directory returns an error.
@@ -44702,7 +45284,7 @@ async function resolveAndGateScope(ctx, context, scope) {
44702
45284
  }
44703
45285
  return { scope: Array.isArray(scope) ? resolved : resolved[0] };
44704
45286
  }
44705
- function asRecord2(value) {
45287
+ function asRecord(value) {
44706
45288
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : undefined;
44707
45289
  }
44708
45290
  function asString(value) {
@@ -44710,7 +45292,7 @@ function asString(value) {
44710
45292
  }
44711
45293
  function firstRecord(...values) {
44712
45294
  for (const value of values) {
44713
- const record = asRecord2(value);
45295
+ const record = asRecord(value);
44714
45296
  if (record)
44715
45297
  return record;
44716
45298
  }
@@ -44745,7 +45327,7 @@ function parseInspectPhaseEntries(value) {
44745
45327
  if (!Array.isArray(value))
44746
45328
  return [];
44747
45329
  return value.flatMap((candidate) => {
44748
- const entry = asRecord2(candidate);
45330
+ const entry = asRecord(candidate);
44749
45331
  const id = asString(entry?.id);
44750
45332
  if (!id)
44751
45333
  return [];
@@ -44761,7 +45343,7 @@ function parseInspectPhaseEntries(value) {
44761
45343
  });
44762
45344
  }
44763
45345
  function parseInspectTerminal(payload) {
44764
- const response = asRecord2(payload);
45346
+ const response = asRecord(payload);
44765
45347
  if (!response)
44766
45348
  return;
44767
45349
  const kind = terminalKind(response);
@@ -44776,7 +45358,7 @@ function parseInspectTerminal(payload) {
44776
45358
  waitStampText: kind === "FRESH" ? firstString(waitStamp?.text, waitStamp?.human_text) : undefined
44777
45359
  };
44778
45360
  }
44779
- const failedPhaseRecord = asRecord2(response.failed_phase);
45361
+ const failedPhaseRecord = asRecord(response.failed_phase);
44780
45362
  const failedPhaseId = firstString(failedPhaseRecord?.id, response.failed_phase);
44781
45363
  const failedPhase = failedPhaseId ? parseInspectPhaseEntries([
44782
45364
  {
@@ -45549,7 +46131,7 @@ function hasMeaningfulProjectSearchFallback(query, pathArg, externalRoot) {
45549
46131
  return trimmedQuery.length > 0 && trimmedQuery !== pathArg && trimmedQuery !== externalRoot;
45550
46132
  }
45551
46133
  var GENERATION_CHANGED_DISCLOSURE = "index changed - order re-derived";
45552
- function asRecord3(value) {
46134
+ function asRecord2(value) {
45553
46135
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
45554
46136
  }
45555
46137
  function normalizeContinuityQuery(query) {
@@ -45564,14 +46146,14 @@ function continuityKey(projectRoot, query, includeTests, topK) {
45564
46146
  ]);
45565
46147
  }
45566
46148
  function responseGeneration(response) {
45567
- const envelope = asRecord3(response);
45568
- const structured = asRecord3(envelope?.structuredContent) ?? asRecord3(envelope?.structured_content);
45569
- const plan = asRecord3(envelope?.plan) ?? asRecord3(structured?.plan);
46149
+ const envelope = asRecord2(response);
46150
+ const structured = asRecord2(envelope?.structuredContent) ?? asRecord2(envelope?.structured_content);
46151
+ const plan = asRecord2(envelope?.plan) ?? asRecord2(structured?.plan);
45570
46152
  const generation = plan?.snapshot_generation ?? envelope?.snapshot_generation;
45571
46153
  return typeof generation === "string" ? generation : undefined;
45572
46154
  }
45573
46155
  function surfaceSearchText(response, continuity, sessionId, key) {
45574
- const envelope = asRecord3(response);
46156
+ const envelope = asRecord2(response);
45575
46157
  const text = typeof envelope?.text === "string" ? envelope.text : "";
45576
46158
  const generation = responseGeneration(response);
45577
46159
  if (generation === undefined)
@@ -45849,6 +46431,8 @@ var defaultBridgeBootstrapDependencies = {
45849
46431
  loadConfig: loadAftConfig,
45850
46432
  deliverLoadNotices: (notify) => deliverConfigLoadNotices(notify, getConfigLoadNotices()),
45851
46433
  configLoadErrors: getConfigLoadErrors,
46434
+ configLoadSources: getConfigLoadSources,
46435
+ configLoadTexts: getConfigLoadTexts,
45852
46436
  subcConnectionFileError,
45853
46437
  migrateConfigLocations: (directory) => migrateAftConfigLocations(directory, bridgeLogger).flatMap((result) => result.warnings),
45854
46438
  resolveBinary: resolveBinaryWithWarmup,
@@ -45890,8 +46474,12 @@ function loadBootstrapConfig(directory, notify, dependencies = defaultBridgeBoot
45890
46474
  const failure = parseFailure(dependencies);
45891
46475
  if (failure)
45892
46476
  return configErrorState(failure, notify);
46477
+ const provenance = dependencies.configLoadSources ? {
46478
+ sources: [...dependencies.configLoadSources()],
46479
+ sourceTexts: Object.fromEntries(dependencies.configLoadTexts?.() ?? [])
46480
+ } : {};
45893
46481
  dependencies.deliverLoadNotices?.(notify);
45894
- return { ok: true, config };
46482
+ return { ok: true, config, ...provenance };
45895
46483
  } catch (err) {
45896
46484
  return configErrorState(err instanceof Error ? err.message : String(err), notify);
45897
46485
  }
@@ -46083,8 +46671,60 @@ function buildConfigErrorToolMap(config, message, client, buildToolMap = buildAf
46083
46671
  return failEveryToolCall(buildToolMap(ctx, config), message);
46084
46672
  }
46085
46673
 
46674
+ // src/config-live-reload.ts
46675
+ var OPENCODE_LIVE_CONFIG_KEYS = aftLiveConfigKeys((config) => resolveBashConfig(config));
46676
+ function projectTextOf(directory) {
46677
+ const { projectConfigPath } = resolveCortexKitConfigPaths(directory);
46678
+ return getConfigLoadTexts().get(projectConfigPath) ?? null;
46679
+ }
46680
+ function loadOpenCodeConfigForLiveReload(directory) {
46681
+ try {
46682
+ const config = loadAftConfig(directory);
46683
+ const [failure] = getConfigLoadErrors();
46684
+ if (failure) {
46685
+ return { ok: false, message: formatConfigParseErrorMessage(failure.path, failure.message) };
46686
+ }
46687
+ const [invalid] = getConfigValidationErrors();
46688
+ if (invalid) {
46689
+ return {
46690
+ ok: false,
46691
+ message: `AFT config at ${invalid.path} has an invalid setting: ${invalid.message}`
46692
+ };
46693
+ }
46694
+ return {
46695
+ ok: true,
46696
+ config,
46697
+ sources: [...getConfigLoadSources()],
46698
+ projectText: projectTextOf(directory),
46699
+ texts: Object.fromEntries(getConfigLoadTexts())
46700
+ };
46701
+ } catch (err) {
46702
+ return { ok: false, message: err instanceof Error ? err.message : String(err) };
46703
+ }
46704
+ }
46705
+ function startOpenCodeLiveConfigReload(options) {
46706
+ const { userConfigPath, projectConfigPath } = resolveCortexKitConfigPaths(options.directory);
46707
+ return startLiveConfigReload({
46708
+ paths: [userConfigPath, projectConfigPath],
46709
+ load: () => loadOpenCodeConfigForLiveReload(options.directory),
46710
+ initialSources: options.initialSources,
46711
+ initialProjectText: options.initialSourceTexts?.[projectConfigPath] ?? null,
46712
+ initialTexts: options.initialSourceTexts,
46713
+ securityKeys: aftLiveSecurityKeys(OPENCODE_LIVE_CONFIG_KEYS),
46714
+ keys: OPENCODE_LIVE_CONFIG_KEYS,
46715
+ getConfig: options.getConfig,
46716
+ setConfig: options.setConfig,
46717
+ log: (message) => log2(`${message} (${options.directory})`),
46718
+ reportError: (message) => {
46719
+ error2(message);
46720
+ options.notify(message);
46721
+ },
46722
+ watch: options.watch
46723
+ });
46724
+ }
46725
+
46086
46726
  // src/notifications.ts
46087
- import { existsSync as existsSync18, readFileSync as readFileSync14 } from "node:fs";
46727
+ import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
46088
46728
  import { homedir as homedir13, platform } from "node:os";
46089
46729
  import { join as join20 } from "node:path";
46090
46730
  function isTuiMode() {
@@ -46126,7 +46766,7 @@ function readDesktopState() {
46126
46766
  return { serverUrl: null };
46127
46767
  }
46128
46768
  try {
46129
- const raw = readFileSync14(statePath, "utf-8");
46769
+ const raw = readFileSync15(statePath, "utf-8");
46130
46770
  const state = JSON.parse(raw);
46131
46771
  let serverUrl = null;
46132
46772
  const serverStr = state.server;
@@ -46625,23 +47265,25 @@ import {
46625
47265
  existsSync as existsSync21,
46626
47266
  mkdirSync as mkdirSync9,
46627
47267
  openSync as openSync7,
46628
- readFileSync as readFileSync17,
47268
+ readFileSync as readFileSync18,
46629
47269
  renameSync as renameSync11,
46630
47270
  rmSync as rmSync8,
46631
- statSync as statSync14,
47271
+ statSync as statSync15,
46632
47272
  writeFileSync as writeFileSync12
46633
47273
  } from "node:fs";
46634
- import { dirname as dirname14 } from "node:path";
47274
+ import { dirname as dirname15 } from "node:path";
46635
47275
 
46636
47276
  // src/hooks/auto-update-checker/cache.ts
46637
- import { cpSync, existsSync as existsSync20, mkdtempSync, readFileSync as readFileSync16, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
47277
+ import { cpSync, existsSync as existsSync20, mkdtempSync, readFileSync as readFileSync17, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
46638
47278
  import { tmpdir as tmpdir4 } from "node:os";
46639
- import { basename as basename5, dirname as dirname13, join as join23 } from "node:path";
47279
+ import { basename as basename6, dirname as dirname14, join as join23 } from "node:path";
46640
47280
  var import_comment_json3 = __toESM(require_src2(), 1);
46641
47281
 
46642
47282
  // src/hooks/auto-update-checker/checker.ts
46643
- import { existsSync as existsSync19, readFileSync as readFileSync15, statSync as statSync13, writeFileSync as writeFileSync10 } from "node:fs";
46644
- import { dirname as dirname12, isAbsolute as isAbsolute11, join as join22, resolve as resolve13 } from "node:path";
47283
+ import { existsSync as existsSync19, readFileSync as readFileSync16, statSync as statSync14, writeFileSync as writeFileSync10 } from "node:fs";
47284
+ import { readFile } from "node:fs/promises";
47285
+ import { homedir as homedir14 } from "node:os";
47286
+ import { dirname as dirname13, isAbsolute as isAbsolute11, join as join22, resolve as resolve13 } from "node:path";
46645
47287
  import { fileURLToPath } from "node:url";
46646
47288
  var import_comment_json2 = __toESM(require_src2(), 1);
46647
47289
 
@@ -46732,14 +47374,14 @@ function resolvePathPluginSpec(spec, configPath) {
46732
47374
  }
46733
47375
  if (isAbsolute11(spec) || /^[A-Za-z]:[\\/]/.test(spec))
46734
47376
  return spec;
46735
- return resolve13(dirname12(configPath), spec);
47377
+ return resolve13(dirname13(configPath), spec);
46736
47378
  }
46737
47379
  function getLocalDevPath(directory) {
46738
47380
  for (const configPath of getConfigPaths(directory)) {
46739
47381
  try {
46740
47382
  if (!existsSync19(configPath))
46741
47383
  continue;
46742
- const rawConfig = parseJsonConfig(readFileSync15(configPath, "utf-8"));
47384
+ const rawConfig = parseJsonConfig(readFileSync16(configPath, "utf-8"));
46743
47385
  const plugins = getPluginEntries(rawConfig);
46744
47386
  for (const entry of plugins) {
46745
47387
  if (entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))
@@ -46749,7 +47391,7 @@ function getLocalDevPath(directory) {
46749
47391
  const pkgPath = findPackageJsonUp(localPath);
46750
47392
  if (!pkgPath)
46751
47393
  continue;
46752
- const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync15(pkgPath, "utf-8")));
47394
+ const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync16(pkgPath, "utf-8")));
46753
47395
  if (pkg.success && pkg.data.name === PACKAGE_NAME)
46754
47396
  return localPath;
46755
47397
  }
@@ -46760,18 +47402,18 @@ function getLocalDevPath(directory) {
46760
47402
  }
46761
47403
  function findPackageJsonUp(startPath) {
46762
47404
  try {
46763
- const stat = statSync13(startPath);
46764
- let dir = stat.isDirectory() ? startPath : dirname12(startPath);
47405
+ const stat = statSync14(startPath);
47406
+ let dir = stat.isDirectory() ? startPath : dirname13(startPath);
46765
47407
  for (let i = 0;i < 10; i++) {
46766
47408
  const pkgPath = join22(dir, "package.json");
46767
47409
  if (existsSync19(pkgPath)) {
46768
47410
  try {
46769
- const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync15(pkgPath, "utf-8")));
47411
+ const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync16(pkgPath, "utf-8")));
46770
47412
  if (pkg.success && pkg.data.name === PACKAGE_NAME)
46771
47413
  return pkgPath;
46772
47414
  } catch {}
46773
47415
  }
46774
- const parent = dirname12(dir);
47416
+ const parent = dirname13(dir);
46775
47417
  if (parent === dir)
46776
47418
  break;
46777
47419
  dir = parent;
@@ -46787,7 +47429,7 @@ function getLocalDevVersion(directory) {
46787
47429
  const pkgPath = findPackageJsonUp(localPath);
46788
47430
  if (!pkgPath)
46789
47431
  return null;
46790
- const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync15(pkgPath, "utf-8")));
47432
+ const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync16(pkgPath, "utf-8")));
46791
47433
  return pkg.success ? pkg.data.version ?? null : null;
46792
47434
  } catch {
46793
47435
  return null;
@@ -46795,7 +47437,7 @@ function getLocalDevVersion(directory) {
46795
47437
  }
46796
47438
  function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
46797
47439
  try {
46798
- return findPackageJsonUp(dirname12(fileURLToPath(currentModuleUrl)));
47440
+ return findPackageJsonUp(dirname13(fileURLToPath(currentModuleUrl)));
46799
47441
  } catch (err) {
46800
47442
  warn2(`[auto-update-checker] Failed to resolve runtime package path: ${String(err)}`);
46801
47443
  return null;
@@ -46806,7 +47448,7 @@ function findPluginEntry(directory) {
46806
47448
  try {
46807
47449
  if (!existsSync19(configPath))
46808
47450
  continue;
46809
- const rawConfig = parseJsonConfig(readFileSync15(configPath, "utf-8"));
47451
+ const rawConfig = parseJsonConfig(readFileSync16(configPath, "utf-8"));
46810
47452
  const plugins = getPluginEntries(rawConfig);
46811
47453
  for (const entry of plugins) {
46812
47454
  if (entry === PACKAGE_NAME) {
@@ -46839,7 +47481,7 @@ function getCachedVersion(spec) {
46839
47481
  try {
46840
47482
  if (!existsSync19(packageJsonPath))
46841
47483
  continue;
46842
- const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync15(packageJsonPath, "utf-8")));
47484
+ const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync16(packageJsonPath, "utf-8")));
46843
47485
  if (pkg.success && pkg.data.version) {
46844
47486
  if (!spec)
46845
47487
  cachedPackageVersion = pkg.data.version;
@@ -46849,6 +47491,117 @@ function getCachedVersion(spec) {
46849
47491
  }
46850
47492
  return null;
46851
47493
  }
47494
+ var registryCache = new Map;
47495
+ function npmConfigGet(key, directory) {
47496
+ return new Promise((resolve, reject) => {
47497
+ execFile(process.platform === "win32" ? "npm.cmd" : "npm", ["config", "get", key], {
47498
+ cwd: directory,
47499
+ timeout: NPM_FETCH_TIMEOUT,
47500
+ windowsHide: true,
47501
+ shell: process.platform === "win32"
47502
+ }, (error, stdout) => {
47503
+ if (error)
47504
+ reject(error);
47505
+ else
47506
+ resolve(stdout.trim());
47507
+ });
47508
+ });
47509
+ }
47510
+ function configuredRegistry(value) {
47511
+ return value && value !== "undefined" && value !== "null" ? value : undefined;
47512
+ }
47513
+ async function readRegistrySettings(path, required = false) {
47514
+ let text;
47515
+ try {
47516
+ text = await readFile(path, "utf8");
47517
+ } catch (error) {
47518
+ if (!required && error.code === "ENOENT")
47519
+ return {};
47520
+ throw error;
47521
+ }
47522
+ const settings = {};
47523
+ for (const line of text.split(/\r?\n/)) {
47524
+ const trimmed = line.trim();
47525
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith(";"))
47526
+ continue;
47527
+ const separator = trimmed.indexOf("=");
47528
+ if (separator < 0)
47529
+ continue;
47530
+ const key = trimmed.slice(0, separator).trim();
47531
+ if (key === "registry" || key === "@cortexkit:registry") {
47532
+ settings[key] = configuredRegistry(trimmed.slice(separator + 1).trim());
47533
+ }
47534
+ }
47535
+ return settings;
47536
+ }
47537
+ function registryEnvironment(key) {
47538
+ const variable = `npm_config_${key}`;
47539
+ const value = process.env[variable] ?? Object.entries(process.env).find(([name]) => name.toLowerCase() === variable)?.[1];
47540
+ return configuredRegistry(value ?? "");
47541
+ }
47542
+ async function registryWithoutNpm(directory) {
47543
+ let scoped = registryEnvironment("@cortexkit:registry");
47544
+ let registry = registryEnvironment("registry");
47545
+ const visited = new Set;
47546
+ for (let current = directory;; current = dirname13(current)) {
47547
+ if (scoped)
47548
+ break;
47549
+ const path = join22(current, ".npmrc");
47550
+ visited.add(path);
47551
+ const settings = await readRegistrySettings(path);
47552
+ scoped ??= settings["@cortexkit:registry"];
47553
+ registry ??= settings.registry;
47554
+ if (dirname13(current) === current)
47555
+ break;
47556
+ }
47557
+ const explicitUserConfig = process.env.npm_config_userconfig ?? process.env.NPM_CONFIG_USERCONFIG;
47558
+ const home = (process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME) ?? homedir14();
47559
+ const userConfig = explicitUserConfig ?? join22(home, ".npmrc");
47560
+ if (!scoped && !visited.has(userConfig)) {
47561
+ const settings = await readRegistrySettings(userConfig, explicitUserConfig !== undefined);
47562
+ scoped = settings["@cortexkit:registry"];
47563
+ registry ??= settings.registry;
47564
+ }
47565
+ const selected = scoped ?? registry ?? NPM_REGISTRY_URL;
47566
+ return selected.replace(/\$\{([^}]+)\}/g, (_match, name) => {
47567
+ const value = process.env[name];
47568
+ if (value === undefined)
47569
+ throw new Error("Unresolved registry environment variable");
47570
+ return value;
47571
+ });
47572
+ }
47573
+ function validateRegistry(registry) {
47574
+ const url = new URL(registry);
47575
+ if (url.protocol !== "https:" && url.protocol !== "http:")
47576
+ throw new Error("Unsupported registry protocol");
47577
+ return registry;
47578
+ }
47579
+ var reportedRegistryFailures = new Set;
47580
+ function reportRegistryFailure(directory) {
47581
+ const key = resolve13(directory);
47582
+ if (reportedRegistryFailures.has(key))
47583
+ return;
47584
+ reportedRegistryFailures.add(key);
47585
+ debug2("[auto-update-checker] Configured npm registry could not be resolved or used; skipping update check.");
47586
+ }
47587
+ function resolveRegistry(directory) {
47588
+ const key = resolve13(directory);
47589
+ let pending = registryCache.get(key);
47590
+ if (!pending) {
47591
+ pending = (async () => {
47592
+ let registry;
47593
+ try {
47594
+ const scoped = configuredRegistry(await npmConfigGet("@cortexkit:registry", key));
47595
+ registry = scoped ?? configuredRegistry(await npmConfigGet("registry", key)) ?? NPM_REGISTRY_URL;
47596
+ } catch {
47597
+ registry = await registryWithoutNpm(key);
47598
+ }
47599
+ return validateRegistry(registry);
47600
+ })();
47601
+ registryCache.set(key, pending);
47602
+ }
47603
+ return pending;
47604
+ }
46852
47605
  function buildRegistryUrl(registryUrl) {
46853
47606
  return `${registryUrl.replace(/\/+$/, "")}/${encodeURIComponent(PACKAGE_NAME).replace("%2F", "/")}`;
46854
47607
  }
@@ -46860,17 +47613,24 @@ async function getLatestVersion(channel = "latest", options = {}) {
46860
47613
  try {
46861
47614
  if (options.signal?.aborted)
46862
47615
  return null;
46863
- const response = await fetch(buildRegistryUrl(options.registryUrl ?? NPM_REGISTRY_URL), {
47616
+ const registry = validateRegistry(options.registryUrl ?? await resolveRegistry(options.directory ?? process.cwd()));
47617
+ if (controller.signal.aborted)
47618
+ return null;
47619
+ const response = await fetch(buildRegistryUrl(registry), {
46864
47620
  signal: controller.signal,
46865
47621
  headers: { Accept: "application/json" }
46866
47622
  });
46867
- if (!response.ok)
47623
+ if (!response.ok) {
47624
+ reportRegistryFailure(options.directory ?? process.cwd());
46868
47625
  return null;
47626
+ }
46869
47627
  const data = NpmPackageEnvelopeSchema.safeParse(await response.json());
46870
47628
  if (!data.success)
46871
47629
  return null;
46872
47630
  return data.data["dist-tags"][channel] ?? data.data["dist-tags"].latest ?? null;
46873
47631
  } catch {
47632
+ if (!controller.signal.aborted)
47633
+ reportRegistryFailure(options.directory ?? process.cwd());
46874
47634
  return null;
46875
47635
  } finally {
46876
47636
  options.signal?.removeEventListener("abort", abortHandler);
@@ -46890,9 +47650,9 @@ function createAutoUpdateSnapshot(installDir, packageJsonPath, packageName) {
46890
47650
  cpSync(packageDir, stagedPackageDir, { recursive: true });
46891
47651
  return {
46892
47652
  packageJsonPath,
46893
- packageJson: existsSync20(packageJsonPath) ? readFileSync16(packageJsonPath, "utf-8") : null,
47653
+ packageJson: existsSync20(packageJsonPath) ? readFileSync17(packageJsonPath, "utf-8") : null,
46894
47654
  lockfilePath,
46895
- lockfile: existsSync20(lockfilePath) ? readFileSync16(lockfilePath, "utf-8") : null,
47655
+ lockfile: existsSync20(lockfilePath) ? readFileSync17(lockfilePath, "utf-8") : null,
46896
47656
  packageDir,
46897
47657
  stagedPackageDir,
46898
47658
  tempDir
@@ -46919,9 +47679,9 @@ function restoreAutoUpdateSnapshot(snapshot) {
46919
47679
  function stripPackageNameFromPath(pathValue, packageName) {
46920
47680
  let current = pathValue;
46921
47681
  for (const segment of [...packageName.split("/")].reverse()) {
46922
- if (basename5(current) !== segment)
47682
+ if (basename6(current) !== segment)
46923
47683
  return null;
46924
- current = dirname13(current);
47684
+ current = dirname14(current);
46925
47685
  }
46926
47686
  return current;
46927
47687
  }
@@ -46930,7 +47690,7 @@ function removeFromPackageLock(installDir, packageName) {
46930
47690
  if (!existsSync20(lockPath))
46931
47691
  return false;
46932
47692
  try {
46933
- const lock = import_comment_json3.parse(readFileSync16(lockPath, "utf-8"));
47693
+ const lock = import_comment_json3.parse(readFileSync17(lockPath, "utf-8"));
46934
47694
  let modified = false;
46935
47695
  if (lock.packages) {
46936
47696
  const key = `node_modules/${packageName}`;
@@ -46956,7 +47716,7 @@ function ensureDependencyVersion(packageJsonPath, packageName, version) {
46956
47716
  if (!existsSync20(packageJsonPath))
46957
47717
  return false;
46958
47718
  try {
46959
- const raw = import_comment_json3.parse(readFileSync16(packageJsonPath, "utf-8"));
47719
+ const raw = import_comment_json3.parse(readFileSync17(packageJsonPath, "utf-8"));
46960
47720
  const pkgJson = PackageJsonSchema.safeParse(raw);
46961
47721
  if (!pkgJson.success)
46962
47722
  return false;
@@ -46991,17 +47751,17 @@ function removeInstalledPackage(installDir, packageName) {
46991
47751
  }
46992
47752
  function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
46993
47753
  if (runtimePackageJsonPath) {
46994
- const packageDir = dirname13(runtimePackageJsonPath);
47754
+ const packageDir = dirname14(runtimePackageJsonPath);
46995
47755
  const nodeModulesDir = stripPackageNameFromPath(packageDir, PACKAGE_NAME);
46996
- if (nodeModulesDir && basename5(nodeModulesDir) === "node_modules") {
46997
- const installDir = dirname13(nodeModulesDir);
47756
+ if (nodeModulesDir && basename6(nodeModulesDir) === "node_modules") {
47757
+ const installDir = dirname14(nodeModulesDir);
46998
47758
  const packageJsonPath = join23(installDir, "package.json");
46999
47759
  if (existsSync20(packageJsonPath))
47000
47760
  return { installDir, packageJsonPath };
47001
47761
  }
47002
47762
  return null;
47003
47763
  }
47004
- const cacheRoot = dirname13(cacheDir());
47764
+ const cacheRoot = dirname14(cacheDir());
47005
47765
  const legacyPackageJsonPath = join23(cacheRoot, "package.json");
47006
47766
  if (existsSync20(legacyPackageJsonPath)) {
47007
47767
  return { installDir: cacheRoot, packageJsonPath: legacyPackageJsonPath };
@@ -47204,7 +47964,7 @@ function claimCheckSlot(storageDir, intervalMs) {
47204
47964
  try {
47205
47965
  if (hasRecentCheckTimestamp(file, intervalMs))
47206
47966
  return null;
47207
- mkdirSync9(dirname14(file), { recursive: true });
47967
+ mkdirSync9(dirname15(file), { recursive: true });
47208
47968
  const lockPath = `${file}.lock`;
47209
47969
  const owner = { pid: process.pid, startedMs: Date.now() };
47210
47970
  let lockFd = null;
@@ -47275,9 +48035,9 @@ function isOrphanedCheckLock(lockPath) {
47275
48035
  }
47276
48036
  }
47277
48037
  function readCheckLockState(lockPath) {
47278
- const fallbackStartedMs = statSync14(lockPath).mtimeMs;
48038
+ const fallbackStartedMs = statSync15(lockPath).mtimeMs;
47279
48039
  try {
47280
- const parsed = JSON.parse(readFileSync17(lockPath, "utf-8"));
48040
+ const parsed = JSON.parse(readFileSync18(lockPath, "utf-8"));
47281
48041
  const pid = Number.isSafeInteger(parsed.pid) && (parsed.pid ?? 0) > 0 ? parsed.pid ?? null : null;
47282
48042
  const startedMs = typeof parsed.startedMs === "number" && Number.isFinite(parsed.startedMs) ? parsed.startedMs : fallbackStartedMs;
47283
48043
  return { pid, startedMs };
@@ -47287,7 +48047,7 @@ function readCheckLockState(lockPath) {
47287
48047
  }
47288
48048
  function checkLockIsOwnedBy(lockPath, owner) {
47289
48049
  try {
47290
- const parsed = JSON.parse(readFileSync17(lockPath, "utf-8"));
48050
+ const parsed = JSON.parse(readFileSync18(lockPath, "utf-8"));
47291
48051
  return parsed.pid === owner.pid && parsed.startedMs === owner.startedMs;
47292
48052
  } catch {
47293
48053
  return false;
@@ -47297,7 +48057,7 @@ function hasRecentCheckTimestamp(file, intervalMs) {
47297
48057
  if (!existsSync21(file))
47298
48058
  return false;
47299
48059
  try {
47300
- const raw = JSON.parse(readFileSync17(file, "utf-8"));
48060
+ const raw = JSON.parse(readFileSync18(file, "utf-8"));
47301
48061
  const last = typeof raw.lastCheckedMs === "number" ? raw.lastCheckedMs : 0;
47302
48062
  return Number.isFinite(last) && Date.now() - last < intervalMs;
47303
48063
  } catch {
@@ -47353,6 +48113,7 @@ async function runBackgroundUpdateCheck(ctx, options) {
47353
48113
  const channel = extractChannel(pluginInfo.pinnedVersion ?? currentVersion);
47354
48114
  const latestVersion = await getLatestVersion(channel, {
47355
48115
  registryUrl: options.npmRegistryUrl,
48116
+ directory: ctx.directory,
47356
48117
  timeoutMs: options.fetchTimeoutMs,
47357
48118
  signal: options.signal
47358
48119
  });
@@ -47493,13 +48254,13 @@ import {
47493
48254
  existsSync as existsSync22,
47494
48255
  mkdirSync as mkdirSync10,
47495
48256
  readdirSync as readdirSync6,
47496
- readFileSync as readFileSync18,
48257
+ readFileSync as readFileSync19,
47497
48258
  renameSync as renameSync12,
47498
48259
  unlinkSync as unlinkSync8,
47499
48260
  writeFileSync as writeFileSync13
47500
48261
  } from "node:fs";
47501
48262
  import { createServer } from "node:http";
47502
- import { dirname as dirname15, join as join25 } from "node:path";
48263
+ import { dirname as dirname16, join as join25 } from "node:path";
47503
48264
 
47504
48265
  // src/shared/rpc-utils.ts
47505
48266
  import { join as join24 } from "node:path";
@@ -47649,7 +48410,7 @@ class AftRpcServer {
47649
48410
  }
47650
48411
  }
47651
48412
  writePortFile() {
47652
- const dir = dirname15(this.portFilePath);
48413
+ const dir = dirname16(this.portFilePath);
47653
48414
  mkdirSync10(dir, { recursive: true, mode: 448 });
47654
48415
  const tmpPath = `${this.portFilePath}.tmp`;
47655
48416
  writeFileSync13(tmpPath, JSON.stringify({
@@ -47674,7 +48435,7 @@ class AftRpcServer {
47674
48435
  if (filePath === this.portFilePath)
47675
48436
  continue;
47676
48437
  try {
47677
- const record = parseRpcPortRecord(readFileSync18(filePath, "utf-8"));
48438
+ const record = parseRpcPortRecord(readFileSync19(filePath, "utf-8"));
47678
48439
  if (record === null) {
47679
48440
  unlinkSync8(filePath);
47680
48441
  continue;
@@ -47889,7 +48650,7 @@ function formatSemanticIndexLabel(semantic) {
47889
48650
  backendUrl: semantic.backend_url
47890
48651
  });
47891
48652
  }
47892
- function asRecord4(value) {
48653
+ function asRecord3(value) {
47893
48654
  return typeof value === "object" && value !== null ? value : {};
47894
48655
  }
47895
48656
  function readString(value, fallback = "") {
@@ -47908,7 +48669,7 @@ function readOptionalNumber(value) {
47908
48669
  return typeof value === "number" && Number.isFinite(value) ? value : null;
47909
48670
  }
47910
48671
  function readCompressionAggregate(value) {
47911
- const aggregate = asRecord4(value);
48672
+ const aggregate = asRecord3(value);
47912
48673
  return {
47913
48674
  events: readNumber(aggregate.events),
47914
48675
  original_tokens: readNumber(aggregate.original_tokens),
@@ -47919,7 +48680,7 @@ function readCompressionAggregate(value) {
47919
48680
  function readCompression(value) {
47920
48681
  if (typeof value !== "object" || value === null)
47921
48682
  return;
47922
- const compression = asRecord4(value);
48683
+ const compression = asRecord3(value);
47923
48684
  return {
47924
48685
  project: readCompressionAggregate(compression.project),
47925
48686
  session: readCompressionAggregate(compression.session)
@@ -47928,7 +48689,7 @@ function readCompression(value) {
47928
48689
  function readStatusBar(value) {
47929
48690
  if (typeof value !== "object" || value === null)
47930
48691
  return;
47931
- const bar = asRecord4(value);
48692
+ const bar = asRecord3(value);
47932
48693
  const errors = readOptionalNumber(bar.errors);
47933
48694
  const warnings = readOptionalNumber(bar.warnings);
47934
48695
  const deadCode = readOptionalNumber(bar.dead_code);
@@ -47986,17 +48747,17 @@ function formatBytes(bytes) {
47986
48747
  return `${value.toFixed(decimals)} ${units[unitIndex]}`;
47987
48748
  }
47988
48749
  function coerceAftStatus(response) {
47989
- const features = asRecord4(response.features);
47990
- const searchIndex = asRecord4(response.search_index);
47991
- const semanticIndex = asRecord4(response.semantic_index);
48750
+ const features = asRecord3(response.features);
48751
+ const searchIndex = asRecord3(response.search_index);
48752
+ const semanticIndex = asRecord3(response.semantic_index);
47992
48753
  const semanticConfig = {
47993
- ...asRecord4(response.semantic),
47994
- ...asRecord4(response.semantic_config)
48754
+ ...asRecord3(response.semantic),
48755
+ ...asRecord3(response.semantic_config)
47995
48756
  };
47996
- const disk = asRecord4(response.disk);
47997
- const symbolCache = asRecord4(response.symbol_cache);
47998
- const runtime = asRecord4(response.runtime);
47999
- const session = asRecord4(response.session);
48757
+ const disk = asRecord3(response.disk);
48758
+ const symbolCache = asRecord3(response.symbol_cache);
48759
+ const runtime = asRecord3(response.runtime);
48760
+ const session = asRecord3(response.session);
48000
48761
  return {
48001
48762
  version: readString(response.version, "unknown"),
48002
48763
  project_root: readNullableString(response.project_root),
@@ -48537,6 +49298,16 @@ async function initializePluginForDirectory(input) {
48537
49298
  storageDir: configOverrides.storage_dir,
48538
49299
  isProjectEnabled
48539
49300
  };
49301
+ const liveConfigReload = startOpenCodeLiveConfigReload({
49302
+ directory: registrationRoot,
49303
+ initialSources: bootstrap.sources ?? [],
49304
+ initialSourceTexts: bootstrap.sourceTexts,
49305
+ getConfig: () => ctx.config,
49306
+ setConfig: (config) => {
49307
+ ctx.config = config;
49308
+ },
49309
+ notify: (message) => deliverConfigMigrationWarnings(registrationRoot, [message])
49310
+ });
48540
49311
  const statusSubscribedBridges = new WeakSet;
48541
49312
  const statusUnsubscribes = new Set;
48542
49313
  const subscribeBridgeStatus = (bridge) => {
@@ -48574,6 +49345,7 @@ async function initializePluginForDirectory(input) {
48574
49345
  let clearInspectTier2Idle = () => {};
48575
49346
  const shutdownCleanup = registerShutdownCleanup(async (reason) => {
48576
49347
  autoUpdateAbort.abort();
49348
+ liveConfigReload.stop();
48577
49349
  clearInspectTier2Idle();
48578
49350
  for (const unsubscribe of statusUnsubscribes) {
48579
49351
  try {
@@ -48732,7 +49504,7 @@ Install: ${getManualInstallHint()}`);
48732
49504
  }
48733
49505
  const inspectTier2Idle = createInspectTier2IdleScheduler({
48734
49506
  isEnabled: () => registeredTools.has("aft_inspect"),
48735
- idleMinutes: () => aftConfig.inspect?.tier2_idle_minutes,
49507
+ idleMinutes: () => ctx.config.inspect?.tier2_idle_minutes,
48736
49508
  warn: warn2,
48737
49509
  run: async (sessionID) => {
48738
49510
  const sessionDir = await getSessionDirectory(input.client, sessionID, input.directory) ?? input.directory;
@@ -48790,11 +49562,17 @@ Install: ${getManualInstallHint()}`);
48790
49562
  storageDir: configOverrides.storage_dir,
48791
49563
  pluginVersion: PLUGIN_VERSION,
48792
49564
  serverUrl: input.serverUrl?.toString(),
48793
- delivery: aftConfig.configure_warnings_delivery ?? "toast"
49565
+ delivery: ctx.config.configure_warnings_delivery ?? "toast"
48794
49566
  });
48795
49567
  }
48796
49568
  await flushConfigureWarningsOnIdle(sessionID);
48797
49569
  },
49570
+ "chat.params": async (params) => {
49571
+ rememberReadModel(input.client, params.sessionID, {
49572
+ providerID: params.model.providerID,
49573
+ modelID: params.model.id
49574
+ });
49575
+ },
48798
49576
  "chat.message": async (messageInput, messageOutput) => {
48799
49577
  const sid = messageInput.sessionID ?? messageInput.sessionId ?? messageInput.id;
48800
49578
  warmSessionDirectory(input.client, sid, input.directory);
@@ -48904,7 +49682,7 @@ var AftRpc = Rpc.define({
48904
49682
  }
48905
49683
  });
48906
49684
  // src/rpc/register.ts
48907
- function asRecord5(value) {
49685
+ function asRecord4(value) {
48908
49686
  return typeof value === "object" && value !== null ? value : undefined;
48909
49687
  }
48910
49688
  function finiteNumber(value) {
@@ -48914,12 +49692,12 @@ function nonEmptyString(value) {
48914
49692
  return typeof value === "string" && value.length > 0 ? value : undefined;
48915
49693
  }
48916
49694
  function sessionFromSnapshot(snapshot) {
48917
- return nonEmptyString(asRecord5(snapshot.session)?.id);
49695
+ return nonEmptyString(asRecord4(snapshot.session)?.id);
48918
49696
  }
48919
49697
  function indexProgressFromStatus(snapshot) {
48920
49698
  const sessionID = sessionFromSnapshot(snapshot);
48921
49699
  const progress = [];
48922
- const search = asRecord5(snapshot.search_index);
49700
+ const search = asRecord4(snapshot.search_index);
48923
49701
  if (search && typeof search.status === "string") {
48924
49702
  progress.push({
48925
49703
  index: "search",
@@ -48928,7 +49706,7 @@ function indexProgressFromStatus(snapshot) {
48928
49706
  ...finiteNumber(search.files) === undefined ? {} : { completed: finiteNumber(search.files) }
48929
49707
  });
48930
49708
  }
48931
- const semantic = asRecord5(snapshot.semantic_index);
49709
+ const semantic = asRecord4(snapshot.semantic_index);
48932
49710
  if (semantic && typeof semantic.status === "string") {
48933
49711
  const stage = semantic.stage === null ? null : nonEmptyString(semantic.stage);
48934
49712
  const completed = finiteNumber(semantic.entries_done);
@@ -49428,7 +50206,7 @@ function matchesVersion2(version, options) {
49428
50206
 
49429
50207
  // ../../node_modules/.bun/@opencode+client@2.0.11+bdc4bbd92cece36b/node_modules/@opencode/client/dist/chunks/service-rg0h87gt.js
49430
50208
  init_service_9rqn6x4v();
49431
- import { readFile, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
50209
+ import { readFile as readFile2, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
49432
50210
  var exports_pty_handoff = {};
49433
50211
  __export2(exports_pty_handoff, {
49434
50212
  PtyHandoff: () => exports_pty_handoff,
@@ -49485,7 +50263,7 @@ async function publish(file, info, handoff) {
49485
50263
  }
49486
50264
  async function environment2(file, env) {
49487
50265
  const record = await read(file);
49488
- const current = await readFile(file, "utf8").then((text) => JSON.parse(text)).catch(() => {
50266
+ const current = await readFile2(file, "utf8").then((text) => JSON.parse(text)).catch(() => {
49489
50267
  return;
49490
50268
  });
49491
50269
  const handoff = record !== undefined && record.expiresAt > Date.now() && (current === undefined || same(record.source, current)) ? record.handoff : undefined;
@@ -49500,7 +50278,7 @@ async function clear2(file) {
49500
50278
  await rm2(file + ".pty-handoff", { force: true });
49501
50279
  }
49502
50280
  async function read(file) {
49503
- const value = await readFile(file + ".pty-handoff", "utf8").then((text) => JSON.parse(text)).catch(() => {
50281
+ const value = await readFile2(file + ".pty-handoff", "utf8").then((text) => JSON.parse(text)).catch(() => {
49504
50282
  return;
49505
50283
  });
49506
50284
  if (typeof value !== "object" || value === null || !("source" in value) || !("handoff" in value))
@@ -49534,8 +50312,8 @@ function isHandoff(value) {
49534
50312
  return typeof value === "object" && value !== null && "directory" in value && typeof value.directory === "string" && "instanceID" in value && typeof value.instanceID === "string" && "ticket" in value && typeof value.ticket === "string" && "expiresAt" in value && typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt);
49535
50313
  }
49536
50314
  // ../../node_modules/.bun/@opencode+client@2.0.11+bdc4bbd92cece36b/node_modules/@opencode/client/dist/promise/service.js
49537
- import { readFile as readFile2, rm as rm3 } from "node:fs/promises";
49538
- import { homedir as homedir14 } from "node:os";
50315
+ import { readFile as readFile3, rm as rm3 } from "node:fs/promises";
50316
+ import { homedir as homedir15 } from "node:os";
49539
50317
  import { join as join26 } from "node:path";
49540
50318
  async function discover(options = {}) {
49541
50319
  const found = (await registered(options.file)).service;
@@ -49548,7 +50326,7 @@ async function discover(options = {}) {
49548
50326
  return found.endpoint;
49549
50327
  }
49550
50328
  function fallback() {
49551
- return join26(process.env["XDG_STATE_HOME"] ?? join26(homedir14(), ".local", "state"), "opencode", "service.json");
50329
+ return join26(process.env["XDG_STATE_HOME"] ?? join26(homedir15(), ".local", "state"), "opencode", "service.json");
49552
50330
  }
49553
50331
  function headers(endpoint) {
49554
50332
  if (endpoint.auth === undefined)
@@ -49558,7 +50336,7 @@ function headers(endpoint) {
49558
50336
  };
49559
50337
  }
49560
50338
  async function read2(file) {
49561
- const text = await readFile2(file ?? fallback(), "utf8").catch(() => {
50339
+ const text = await readFile3(file ?? fallback(), "utf8").catch(() => {
49562
50340
  return;
49563
50341
  });
49564
50342
  if (text === undefined)
@@ -49867,6 +50645,7 @@ var defaults = {
49867
50645
  }),
49868
50646
  acquireBridge,
49869
50647
  releaseBridge,
50648
+ startLiveConfigReload: startOpenCodeLiveConfigReload,
49870
50649
  resolvePoolOptions: resolveBridgePoolTransportOptions,
49871
50650
  resolveVersion: () => resolvePluginVersion(import.meta.url)
49872
50651
  };
@@ -49920,7 +50699,17 @@ async function bootLocation(context, location, dependencies) {
49920
50699
  const { hashlineEditRegistered } = applyToolSurfaceOverrides(pool, config, registeredTools);
49921
50700
  reportHashlineDowngrade(config, registeredTools, notify);
49922
50701
  toolContext.hashlineEffective = hashlineEditRegistered;
49923
- return { consumers, pool, tools };
50702
+ const liveConfigReload = dependencies.startLiveConfigReload({
50703
+ directory,
50704
+ initialSources: bootstrap.sources ?? [],
50705
+ initialSourceTexts: bootstrap.sourceTexts,
50706
+ getConfig: () => toolContext.config,
50707
+ setConfig: (next) => {
50708
+ toolContext.config = next;
50709
+ },
50710
+ notify
50711
+ });
50712
+ return { consumers, pool, tools, liveConfigReload };
49924
50713
  }
49925
50714
  var runningByDirectory = new Map;
49926
50715
  var startsInProcess = 0;
@@ -49962,6 +50751,7 @@ function makeServerEffect(overrides = {}) {
49962
50751
  return;
49963
50752
  }
49964
50753
  yield* Effect7.addFinalizer(() => Effect7.promise(async () => {
50754
+ runtime.liveConfigReload?.stop();
49965
50755
  runtime.consumers.dispose?.();
49966
50756
  await dependencies.releaseBridge(runtime.pool);
49967
50757
  }));