@wrongstack/core 0.292.0 → 0.292.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1366,12 +1366,43 @@ async function backupConfigFile(filePath, paths) {
1366
1366
  }
1367
1367
  }
1368
1368
 
1369
+ // src/utils/connectivity.ts
1370
+ var DEFAULT_PROBE_URL = "https://1.1.1.1";
1371
+ var DEFAULT_TIMEOUT_MS = 5e3;
1372
+ var DEFAULT_TTL_MS = 3e4;
1373
+ var cached;
1374
+ async function checkConnectivity(opts) {
1375
+ const url = opts?.probeUrl ?? DEFAULT_PROBE_URL;
1376
+ const timeout = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1377
+ const ttl = opts?.ttlMs ?? DEFAULT_TTL_MS;
1378
+ if (cached && ttl > 0 && Date.now() - cached.at < ttl) {
1379
+ return cached.ok;
1380
+ }
1381
+ cached = { ok: await probe(url, timeout), at: Date.now() };
1382
+ return cached.ok;
1383
+ }
1384
+ async function probe(url, timeoutMs) {
1385
+ const controller = new AbortController();
1386
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1387
+ try {
1388
+ await fetch(url, { method: "HEAD", signal: controller.signal });
1389
+ return true;
1390
+ } catch {
1391
+ return false;
1392
+ } finally {
1393
+ clearTimeout(timer);
1394
+ }
1395
+ }
1396
+ function resetConnectivityCache() {
1397
+ cached = void 0;
1398
+ }
1399
+
1369
1400
  // src/utils/cache-key.ts
1370
1401
  import { createHash } from "node:crypto";
1371
1402
  var keyCache = /* @__PURE__ */ new WeakMap();
1372
1403
  function deriveCachePrefixKey(systemPrompt) {
1373
- const cached = keyCache.get(systemPrompt);
1374
- if (cached !== void 0) return cached;
1404
+ const cached2 = keyCache.get(systemPrompt);
1405
+ if (cached2 !== void 0) return cached2;
1375
1406
  const h = createHash("sha256");
1376
1407
  for (const block of systemPrompt) h.update(block.text).update("\0");
1377
1408
  const key = `ws-${h.digest("hex").slice(0, 32)}`;
@@ -3099,8 +3130,8 @@ ${agentList}`;
3099
3130
  modelCapabilities?.supportsVision ? 1 : 0,
3100
3131
  modelCapabilities?.supportsReasoning ? 1 : 0
3101
3132
  ].join("\0");
3102
- const cached = this.envCacheByRoot.get(cacheKey);
3103
- if (cached) return cached;
3133
+ const cached2 = this.envCacheByRoot.get(cacheKey);
3134
+ if (cached2) return cached2;
3104
3135
  const today = this.opts.todayIso ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3105
3136
  const platform4 = `${os2.platform()} ${os2.release()}`;
3106
3137
  const effShell = effectiveShell(os2.platform(), process.env["WRONGSTACK_SHELL"]);
@@ -3460,8 +3491,8 @@ var compactCache = /* @__PURE__ */ new WeakMap();
3460
3491
  function compactToolDefinitionForWire(tool, opts = {}) {
3461
3492
  const useDefaultOptions = opts.descriptionMaxChars === void 0 && opts.schemaDescriptionMaxChars === void 0;
3462
3493
  if (useDefaultOptions && typeof tool === "object" && tool !== null) {
3463
- const cached = compactCache.get(tool);
3464
- if (cached) return cached;
3494
+ const cached2 = compactCache.get(tool);
3495
+ if (cached2) return cached2;
3465
3496
  }
3466
3497
  const compact = {
3467
3498
  name: tool.name,
@@ -3649,8 +3680,8 @@ function realAnchoredInputTokens(messages, anchorTokens, anchorMsgCount) {
3649
3680
  return anchorTokens + delta;
3650
3681
  }
3651
3682
  function estimateToolDefTokens(tool) {
3652
- const cached = tool._estDefTokens;
3653
- if (typeof cached === "number" && cached > 0) return cached;
3683
+ const cached2 = tool._estDefTokens;
3684
+ if (typeof cached2 === "number" && cached2 > 0) return cached2;
3654
3685
  const compact = compactToolDefinitionForWire(tool);
3655
3686
  return RoughTokenEstimate(tool.name) + RoughTokenEstimate(compact.description) + RoughTokenEstimate(JSON.stringify(compact.inputSchema));
3656
3687
  }
@@ -3661,9 +3692,9 @@ function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = C
3661
3692
  } else if (Array.isArray(messages)) {
3662
3693
  for (const m of messages) {
3663
3694
  if (typeof m === "object" && m !== null && "content" in m) {
3664
- const cached = m._estTokens;
3665
- if (typeof cached === "number" && cached > 0) {
3666
- messagesTokens += cached;
3695
+ const cached2 = m._estTokens;
3696
+ if (typeof cached2 === "number" && cached2 > 0) {
3697
+ messagesTokens += cached2;
3667
3698
  continue;
3668
3699
  }
3669
3700
  const content = m.content;
@@ -4291,8 +4322,8 @@ var COMPILED_GLOB_CACHE = /* @__PURE__ */ new Map();
4291
4322
  var CACHE_MAX_SIZE = 2e3;
4292
4323
  var NEVER_MATCH = /[^\s\S]/;
4293
4324
  function getCachedGlob(pattern) {
4294
- const cached = COMPILED_GLOB_CACHE.get(pattern);
4295
- if (cached) return cached;
4325
+ const cached2 = COMPILED_GLOB_CACHE.get(pattern);
4326
+ if (cached2) return cached2;
4296
4327
  if (COMPILED_GLOB_CACHE.size >= CACHE_MAX_SIZE) {
4297
4328
  const keys = [...COMPILED_GLOB_CACHE.keys()];
4298
4329
  for (let i = 0; i < Math.floor(CACHE_MAX_SIZE / 4); i++) {
@@ -7978,9 +8009,9 @@ var DefaultConfigLoader = class _DefaultConfigLoader {
7978
8009
  try {
7979
8010
  const stat27 = await fs9.stat(file);
7980
8011
  mtimeMs = stat27.mtimeMs;
7981
- const cached = this.jsonCache.get(file);
7982
- if (cached && cached.mtimeMs === mtimeMs) {
7983
- return structuredClone(cached.value);
8012
+ const cached2 = this.jsonCache.get(file);
8013
+ if (cached2 && cached2.mtimeMs === mtimeMs) {
8014
+ return structuredClone(cached2.value);
7984
8015
  }
7985
8016
  } catch (err) {
7986
8017
  if (err.code === "ENOENT") {
@@ -11759,8 +11790,8 @@ var candidateCache = /* @__PURE__ */ new Map();
11759
11790
  function agentPrompt(id) {
11760
11791
  const envDir = process.env["WRONGSTACK_AGENT_INSTRUCTIONS_DIR"] ?? "";
11761
11792
  const cacheKey = `${envDir}\0${id}`;
11762
- const cached = promptCache.get(cacheKey);
11763
- if (cached !== void 0) return cached;
11793
+ const cached2 = promptCache.get(cacheKey);
11794
+ if (cached2 !== void 0) return cached2;
11764
11795
  const fileName = `${id}.md`;
11765
11796
  let resolved = "";
11766
11797
  for (const dir of agentPromptDirCandidates(envDir)) {
@@ -11776,8 +11807,8 @@ function agentPrompt(id) {
11776
11807
  function agentPromptDirCandidates(envDir) {
11777
11808
  const globalRoot = process.env["WRONGSTACK_HOME"] || path19.join(os6.homedir(), ".wrongstack");
11778
11809
  const candKey = `${envDir}\0${globalRoot}`;
11779
- const cached = candidateCache.get(candKey);
11780
- if (cached !== void 0) return cached;
11810
+ const cached2 = candidateCache.get(candKey);
11811
+ if (cached2 !== void 0) return cached2;
11781
11812
  const here = path19.dirname(fileURLToPath3(import.meta.url));
11782
11813
  const explicitDir = envDir || void 0;
11783
11814
  const candidates = [
@@ -15839,8 +15870,8 @@ import { fileURLToPath as fileURLToPath4 } from "node:url";
15839
15870
  var textCache = /* @__PURE__ */ new Map();
15840
15871
  var rootCandidates;
15841
15872
  function readBundledInstructionText(relativePath) {
15842
- const cached = textCache.get(relativePath);
15843
- if (cached !== void 0) return cached;
15873
+ const cached2 = textCache.get(relativePath);
15874
+ if (cached2 !== void 0) return cached2;
15844
15875
  let resolved = "";
15845
15876
  for (const root of instructionRootCandidates()) {
15846
15877
  try {
@@ -17815,7 +17846,8 @@ function effectiveInputTokens(usage) {
17815
17846
  }
17816
17847
  var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt is too long|too long|exceeds the context|\btokens\b.*exceed|too many tokens|reduce the length|resulted in \d+ tokens|input.{0,12}too (?:large|long)|context_length_exceeded/i;
17817
17848
  var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
17818
- var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit/i;
17849
+ var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit|usage[-_\s]*limit[-_\s]*(?:reached|exceeded)/i;
17850
+ var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
17819
17851
  function classifyProviderError(status, body, message) {
17820
17852
  const type = body?.type;
17821
17853
  const text2 = [message, body?.message, type, body?.raw].filter(Boolean).join("\n");
@@ -17823,6 +17855,9 @@ function classifyProviderError(status, body, message) {
17823
17855
  if (status === 408) return "timeout";
17824
17856
  if (status === 599) return "stream_hang";
17825
17857
  if (status === 402 || QUOTA_EXHAUSTED_RE.test(text2)) return "quota_exhausted";
17858
+ if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
17859
+ return "quota_exhausted";
17860
+ }
17826
17861
  if (type === "rate_limit_error" || status === 429) return "rate_limit";
17827
17862
  if (type === "overloaded_error" || status === 529) return "overloaded";
17828
17863
  if (status >= 500) return "server";
@@ -18545,6 +18580,12 @@ function createFallbackModelExtension(deps) {
18545
18580
  continue;
18546
18581
  const status = shouldFallback(lastErr);
18547
18582
  if (status === null) break;
18583
+ if (tracker && !tracker.isAvailable(entry.providerId, entry.model)) {
18584
+ deps.logger?.warn(
18585
+ `provider-status: "${entry.providerId}/${entry.model}" entered the waiting room since the chain was computed \u2014 skipping`
18586
+ );
18587
+ continue;
18588
+ }
18548
18589
  const targetProviderId = entry.providerId;
18549
18590
  const targetModel = entry.model;
18550
18591
  if (targetProviderId === ctx_.provider.id && targetModel === ctx_.model) continue;
@@ -19350,8 +19391,8 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
19350
19391
  async awaitTasks(taskIds) {
19351
19392
  return Promise.all(
19352
19393
  taskIds.map((id) => {
19353
- const cached = this.completedResults.find((r) => r.taskId === id);
19354
- if (cached) return cached;
19394
+ const cached2 = this.completedResults.find((r) => r.taskId === id);
19395
+ if (cached2) return cached2;
19355
19396
  return new Promise((resolve34, reject) => {
19356
19397
  const timeout = setTimeout(() => {
19357
19398
  this.off("task.completed", handler);
@@ -21318,8 +21359,8 @@ var Director = class _Director {
21318
21359
  awaitTasks(taskIds) {
21319
21360
  return Promise.all(
21320
21361
  taskIds.map((id) => {
21321
- const cached = this.completed.get(id);
21322
- if (cached) return cached;
21362
+ const cached2 = this.completed.get(id);
21363
+ if (cached2) return cached2;
21323
21364
  const existing = this.taskWaiters.get(id);
21324
21365
  if (existing) return existing.promise;
21325
21366
  let resolve34;
@@ -22815,17 +22856,17 @@ var SessionCheckpointCas = class {
22815
22856
  if (!normalized) throw new Error("invalid relative path");
22816
22857
  const output = path25.resolve(target, ...normalized.split("/"));
22817
22858
  if (!isInside(target, output)) throw new Error("path escapes checkpoint target");
22818
- let probe = output;
22859
+ let probe2 = output;
22819
22860
  for (; ; ) {
22820
22861
  try {
22821
- const real = await fsp9.realpath(probe);
22862
+ const real = await fsp9.realpath(probe2);
22822
22863
  if (!isInside(realTarget, real)) throw new Error("path resolves through a symlink outside checkpoint target");
22823
22864
  return output;
22824
22865
  } catch (err) {
22825
22866
  if (err.code !== "ENOENT") throw err;
22826
- const parent = path25.dirname(probe);
22827
- if (parent === probe) throw err;
22828
- probe = parent;
22867
+ const parent = path25.dirname(probe2);
22868
+ if (parent === probe2) throw err;
22869
+ probe2 = parent;
22829
22870
  }
22830
22871
  }
22831
22872
  }
@@ -23422,13 +23463,13 @@ var DefaultSessionStore = class _DefaultSessionStore {
23422
23463
  try {
23423
23464
  const s = await fsp11.stat(file);
23424
23465
  const stat27 = { mtimeMs: s.mtimeMs, size: s.size };
23425
- const cached = this._loadCache.get(id);
23426
- if (cached && cached.mtimeMs === stat27.mtimeMs && cached.size === stat27.size) {
23466
+ const cached2 = this._loadCache.get(id);
23467
+ if (cached2 && cached2.mtimeMs === stat27.mtimeMs && cached2.size === stat27.size) {
23427
23468
  cacheHit = true;
23428
23469
  this._loadCache.delete(id);
23429
- this._loadCache.set(id, cached);
23430
- if (mode.full) return cached.data;
23431
- return { ...cached.data, messages: [] };
23470
+ this._loadCache.set(id, cached2);
23471
+ if (mode.full) return cached2.data;
23472
+ return { ...cached2.data, messages: [] };
23432
23473
  }
23433
23474
  const events = [];
23434
23475
  let sessionStartEvent;
@@ -23959,8 +24000,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
23959
24000
  return shardKeys;
23960
24001
  }
23961
24002
  async readOrBuildShardManifest(shardKey) {
23962
- const cached = this.shardManifestCache.get(shardKey);
23963
- if (cached) return cached;
24003
+ const cached2 = this.shardManifestCache.get(shardKey);
24004
+ if (cached2) return cached2;
23964
24005
  const manifestPath = this.shardManifestPath(shardKey);
23965
24006
  try {
23966
24007
  const raw = await fsp11.readFile(manifestPath, "utf8");
@@ -28102,6 +28143,8 @@ import { timingSafeEqual } from "node:crypto";
28102
28143
  var MAILBOX_HTTP_MAX_BODY_BYTES = 256 * 1024;
28103
28144
  var MAILBOX_HTTP_RATE_LIMIT_PER_MINUTE = 120;
28104
28145
  var MAILBOX_HTTP_RATE_LIMIT_WINDOW_MS = 6e4;
28146
+ var MAILBOX_HTTP_DEFAULT_MAX_AGE_MS = 60 * 60 * 1e3;
28147
+ var MAILBOX_HTTP_MAX_AGE_CEILING_MS = 7 * 24 * 60 * 60 * 1e3;
28105
28148
  function authorizeMailboxBearerToken(request, expectedToken) {
28106
28149
  const header = request.headers.authorization;
28107
28150
  if (typeof header !== "string") return { allowed: false };
@@ -28145,6 +28188,7 @@ var MailboxHttpRateLimiter = class {
28145
28188
  };
28146
28189
  function createMailboxHttpRouter(options) {
28147
28190
  const maxBodyBytes = options.maxBodyBytes ?? MAILBOX_HTTP_MAX_BODY_BYTES;
28191
+ const defaultMaxAgeMs = options.defaultMaxAgeMs ?? void 0;
28148
28192
  const closeSseStreams = /* @__PURE__ */ new Set();
28149
28193
  return {
28150
28194
  async handle(request, response, routePath) {
@@ -28159,15 +28203,17 @@ function createMailboxHttpRouter(options) {
28159
28203
  if (!access10.allowed) {
28160
28204
  const forwardedFor = request.headers["x-forwarded-for"];
28161
28205
  const clientIp = (Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor)?.split(",")[0]?.trim() ?? request.socket?.remoteAddress ?? "unknown";
28162
- console.warn(JSON.stringify({
28163
- level: "warn",
28164
- event: "mailbox.http_auth_failure",
28165
- message: `Mailbox HTTP auth rejected for ${request.method ?? "?"} ${request.url ?? "?"} from ${clientIp}`,
28166
- method: request.method,
28167
- url: request.url,
28168
- clientIp,
28169
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
28170
- }));
28206
+ console.warn(
28207
+ JSON.stringify({
28208
+ level: "warn",
28209
+ event: "mailbox.http_auth_failure",
28210
+ message: `Mailbox HTTP auth rejected for ${request.method ?? "?"} ${request.url ?? "?"} from ${clientIp}`,
28211
+ method: request.method,
28212
+ url: request.url,
28213
+ clientIp,
28214
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
28215
+ })
28216
+ );
28171
28217
  writeJson(
28172
28218
  response,
28173
28219
  access10.status ?? 401,
@@ -28194,7 +28240,9 @@ function createMailboxHttpRouter(options) {
28194
28240
  method,
28195
28241
  url,
28196
28242
  maxBodyBytes,
28197
- closeSseStreams
28243
+ defaultMaxAgeMs,
28244
+ closeSseStreams,
28245
+ routePath
28198
28246
  );
28199
28247
  } catch (error2) {
28200
28248
  const code = error2 instanceof MailboxHttpValidationError ? "VALIDATION_ERROR" : "INTERNAL_ERROR";
@@ -28213,85 +28261,134 @@ function createMailboxHttpRouter(options) {
28213
28261
  }
28214
28262
  };
28215
28263
  }
28216
- async function dispatchMailboxRoute(mailbox, eventEmitter, request, response, method, url, maxBodyBytes, closeSseStreams) {
28217
- if (method === "POST" && url === "/mailbox/send") {
28264
+ async function dispatchMailboxRoute(mailbox, eventEmitter, request, response, method, url, maxBodyBytes, defaultMaxAgeMs, closeSseStreams, routePath) {
28265
+ if (routePath !== void 0 && routePath.indexOf("?") === 0) {
28266
+ throw validationError(`routePath must not start with '?' (got ${JSON.stringify(routePath)})`);
28267
+ }
28268
+ const queryIndex = url.indexOf("?");
28269
+ const path76 = queryIndex === -1 ? url : url.slice(0, queryIndex);
28270
+ if (method === "POST" && path76 === "/mailbox/send") {
28218
28271
  const input = validateSend(await readJsonBody(request, maxBodyBytes));
28219
28272
  writeJson(response, 201, await mailbox.send(input));
28220
28273
  return;
28221
28274
  }
28222
- if (method === "POST" && url === "/mailbox/query") {
28275
+ if (method === "POST" && path76 === "/mailbox/query") {
28276
+ const queryContext = parseSinceMs(url, defaultMaxAgeMs);
28277
+ if ("error" in queryContext) {
28278
+ writeJson(response, 400, { error: queryContext.error });
28279
+ return;
28280
+ }
28223
28281
  const messages = await mailbox.query(validateQuery(await readJsonBody(request, maxBodyBytes)));
28224
- writeJson(response, 200, { data: messages, count: messages.length });
28282
+ const filtered = filterMailboxMessagesByTimestamp(messages, queryContext.minTimestampIso);
28283
+ writeJson(response, 200, { data: filtered, count: filtered.length });
28225
28284
  return;
28226
28285
  }
28227
- if (method === "POST" && url === "/mailbox/check") {
28286
+ if (method === "POST" && path76 === "/mailbox/check") {
28287
+ const queryContext = parseSinceMs(url, defaultMaxAgeMs);
28288
+ if ("error" in queryContext) {
28289
+ writeJson(response, 400, { error: queryContext.error });
28290
+ return;
28291
+ }
28228
28292
  const result = await checkMailbox(
28229
28293
  mailbox,
28230
- validateCheck(await readJsonBody(request, maxBodyBytes))
28294
+ validateCheck(await readJsonBody(request, maxBodyBytes)),
28295
+ queryContext.minTimestampIso
28231
28296
  );
28232
28297
  writeJson(response, 200, result);
28233
28298
  return;
28234
28299
  }
28235
- if (method === "POST" && url === "/mailbox/ack") {
28300
+ if (method === "POST" && path76 === "/mailbox/ack") {
28236
28301
  const updated = await mailbox.ack(validateAck(await readJsonBody(request, maxBodyBytes)));
28237
28302
  writeJson(response, 200, { updated });
28238
28303
  return;
28239
28304
  }
28240
- if (method === "POST" && url === "/mailbox/ack-many") {
28305
+ if (method === "POST" && path76 === "/mailbox/ack-many") {
28241
28306
  const updated = await mailbox.ackMany(
28242
28307
  validateAckMany(await readJsonBody(request, maxBodyBytes))
28243
28308
  );
28244
28309
  writeJson(response, 200, { updated, count: updated.length });
28245
28310
  return;
28246
28311
  }
28247
- if (method === "POST" && url === "/mailbox/unread-count") {
28312
+ if (method === "POST" && path76 === "/mailbox/unread-count") {
28248
28313
  const body = await readJsonBody(request, maxBodyBytes);
28249
- writeJson(response, 200, { count: await mailbox.unreadCount(requireString(body, "forAgentId")) });
28314
+ writeJson(response, 200, {
28315
+ count: await mailbox.unreadCount(requireString(body, "forAgentId"))
28316
+ });
28250
28317
  return;
28251
28318
  }
28252
- if (method === "POST" && url === "/mailbox/agents/register") {
28253
- await mailbox.registerAgent(validateAgentRegistration(await readJsonBody(request, maxBodyBytes)));
28319
+ if (method === "POST" && path76 === "/mailbox/agents/register") {
28320
+ await mailbox.registerAgent(
28321
+ validateAgentRegistration(await readJsonBody(request, maxBodyBytes))
28322
+ );
28254
28323
  writeJson(response, 200, { ok: true });
28255
28324
  return;
28256
28325
  }
28257
- if (method === "POST" && url === "/mailbox/agents/heartbeat") {
28326
+ if (method === "POST" && path76 === "/mailbox/agents/heartbeat") {
28258
28327
  await mailbox.heartbeat(validateAgentHeartbeat(await readJsonBody(request, maxBodyBytes)));
28259
28328
  writeJson(response, 200, { ok: true });
28260
28329
  return;
28261
28330
  }
28262
- if (method === "POST" && url === "/mailbox/register-client") {
28263
- await mailbox.registerClient(validateClientRegistration(await readJsonBody(request, maxBodyBytes)));
28331
+ if (method === "POST" && path76 === "/mailbox/register-client") {
28332
+ await mailbox.registerClient(
28333
+ validateClientRegistration(await readJsonBody(request, maxBodyBytes))
28334
+ );
28264
28335
  writeJson(response, 200, { ok: true });
28265
28336
  return;
28266
28337
  }
28267
- if (method === "POST" && url === "/mailbox/heartbeat") {
28268
- await mailbox.clientHeartbeat(validateClientHeartbeat(await readJsonBody(request, maxBodyBytes)));
28338
+ if (method === "POST" && path76 === "/mailbox/heartbeat") {
28339
+ await mailbox.clientHeartbeat(
28340
+ validateClientHeartbeat(await readJsonBody(request, maxBodyBytes))
28341
+ );
28269
28342
  writeJson(response, 200, { ok: true });
28270
28343
  return;
28271
28344
  }
28272
- if (method === "POST" && url === "/mailbox/purge-clients") {
28345
+ if (method === "POST" && path76 === "/mailbox/purge-clients") {
28273
28346
  writeJson(response, 200, { ok: true, purged: await mailbox.purgeClients() });
28274
28347
  return;
28275
28348
  }
28276
- if (method === "GET" && url === "/mailbox/agents") {
28349
+ if (method === "GET" && path76 === "/mailbox/agents") {
28277
28350
  const agents = await mailbox.getAgentStatuses();
28278
28351
  writeJson(response, 200, { data: agents, count: agents.length });
28279
28352
  return;
28280
28353
  }
28281
- if (method === "GET" && url === "/mailbox/agents/online") {
28354
+ if (method === "GET" && path76 === "/mailbox/agents/online") {
28282
28355
  const agents = await mailbox.getOnlineAgents();
28283
28356
  writeJson(response, 200, { data: agents, count: agents.length });
28284
28357
  return;
28285
28358
  }
28286
- if (method === "GET" && url === "/mailbox/events" && eventEmitter) {
28287
- handleSse(request, response, eventEmitter, closeSseStreams);
28359
+ if (method === "GET" && path76 === "/mailbox/events" && eventEmitter) {
28360
+ const queryContext = parseSinceMs(url, defaultMaxAgeMs);
28361
+ if ("error" in queryContext) {
28362
+ writeJson(response, 400, { error: queryContext.error });
28363
+ return;
28364
+ }
28365
+ handleSse(request, response, eventEmitter, queryContext.minTimestampIso, closeSseStreams);
28288
28366
  return;
28289
28367
  }
28290
28368
  writeJson(response, 404, {
28291
28369
  error: { code: "NOT_FOUND", message: `no route for ${method} ${url}` }
28292
28370
  });
28293
28371
  }
28294
- function handleSse(request, response, eventEmitter, closeSseStreams) {
28372
+ function extractEventTimestamp(event) {
28373
+ if (event === null || typeof event !== "object") return void 0;
28374
+ const top = event.timestamp;
28375
+ if (typeof top === "string") return top;
28376
+ const nestedKeys = ["messageSent", "ackUpdated"];
28377
+ for (const key of nestedKeys) {
28378
+ const nested = event[key];
28379
+ if (nested !== null && typeof nested === "object") {
28380
+ const inner = nested.timestamp;
28381
+ if (typeof inner === "string") return inner;
28382
+ }
28383
+ }
28384
+ return void 0;
28385
+ }
28386
+ function isEventOlderThan(event, minTimestampIso) {
28387
+ const eventTimestamp = extractEventTimestamp(event);
28388
+ if (eventTimestamp === void 0) return false;
28389
+ return eventTimestamp < minTimestampIso;
28390
+ }
28391
+ function handleSse(request, response, eventEmitter, minTimestampIso, closeSseStreams) {
28295
28392
  response.writeHead(200, {
28296
28393
  "Content-Type": "text/event-stream",
28297
28394
  "Cache-Control": "no-store",
@@ -28301,6 +28398,9 @@ function handleSse(request, response, eventEmitter, closeSseStreams) {
28301
28398
  response.write(": connected\n\n");
28302
28399
  const unsubscribe2 = eventEmitter.subscribe((event) => {
28303
28400
  try {
28401
+ if (minTimestampIso !== void 0 && isEventOlderThan(event, minTimestampIso)) {
28402
+ return;
28403
+ }
28304
28404
  response.write(`data: ${JSON.stringify(event)}
28305
28405
 
28306
28406
  `);
@@ -28410,6 +28510,52 @@ function optionalNumber(object, key) {
28410
28510
  }
28411
28511
  return value;
28412
28512
  }
28513
+ function parseSinceMs(url, defaultMaxAgeMs) {
28514
+ const queryStart = url.indexOf("?");
28515
+ if (queryStart === -1) return resolveDefault(defaultMaxAgeMs, Date.now());
28516
+ const params = new URLSearchParams(url.slice(queryStart + 1));
28517
+ if (!params.has("sinceMs")) return resolveDefault(defaultMaxAgeMs, Date.now());
28518
+ const raw = params.get("sinceMs");
28519
+ if (raw === null || raw === void 0 || raw === "") {
28520
+ return {
28521
+ error: {
28522
+ code: "VALIDATION_ERROR",
28523
+ message: 'query parameter "sinceMs" is required (integer in milliseconds) when present'
28524
+ }
28525
+ };
28526
+ }
28527
+ if (!/^\d+$/.test(raw)) {
28528
+ return {
28529
+ error: {
28530
+ code: "VALIDATION_ERROR",
28531
+ message: 'query parameter "sinceMs" must be a non-negative integer (milliseconds)'
28532
+ }
28533
+ };
28534
+ }
28535
+ const requestedMs = Number(raw);
28536
+ if (!Number.isFinite(requestedMs) || requestedMs > Number.MAX_SAFE_INTEGER) {
28537
+ return {
28538
+ error: {
28539
+ code: "VALIDATION_ERROR",
28540
+ message: `query parameter "sinceMs" is out of range (max ${Number.MAX_SAFE_INTEGER})`
28541
+ }
28542
+ };
28543
+ }
28544
+ const now = Date.now();
28545
+ if (requestedMs === 0) return { minTimestampIso: void 0 };
28546
+ const effectiveMs = Math.min(requestedMs, MAILBOX_HTTP_MAX_AGE_CEILING_MS);
28547
+ return { minTimestampIso: new Date(now - effectiveMs).toISOString() };
28548
+ }
28549
+ function resolveDefault(defaultMaxAgeMs, now) {
28550
+ if (defaultMaxAgeMs === void 0 || !Number.isFinite(defaultMaxAgeMs) || defaultMaxAgeMs < 0 || defaultMaxAgeMs === 0) {
28551
+ return { minTimestampIso: void 0 };
28552
+ }
28553
+ return { minTimestampIso: new Date(now - defaultMaxAgeMs).toISOString() };
28554
+ }
28555
+ function filterMailboxMessagesByTimestamp(messages, minTimestampIso) {
28556
+ if (minTimestampIso === void 0) return messages.slice();
28557
+ return messages.filter((message) => message.timestamp >= minTimestampIso);
28558
+ }
28413
28559
  function optionalBoolean(object, key) {
28414
28560
  if (typeof object !== "object" || object === null) return void 0;
28415
28561
  const value = object[key];
@@ -28530,7 +28676,7 @@ function validateQuery(body) {
28530
28676
  if (incompleteOnly !== void 0) result.incompleteOnly = incompleteOnly;
28531
28677
  return result;
28532
28678
  }
28533
- async function checkMailbox(mailbox, input) {
28679
+ async function checkMailbox(mailbox, input, minTimestampIso) {
28534
28680
  const limit = input.limit ?? 20;
28535
28681
  const markRead = input.markRead ?? true;
28536
28682
  const completed = input.completed ?? false;
@@ -28538,8 +28684,9 @@ async function checkMailbox(mailbox, input) {
28538
28684
  const batches = await Promise.all(
28539
28685
  targets.map((to) => mailbox.query({ to, unreadBy: input.agentId, limit }))
28540
28686
  );
28687
+ const withinWindow = filterMailboxMessagesByTimestamp(batches.flat(), minTimestampIso);
28541
28688
  const seen = /* @__PURE__ */ new Set();
28542
- const messages = batches.flat().filter((message) => {
28689
+ const messages = withinWindow.filter((message) => {
28543
28690
  if (seen.has(message.id) || message.from === input.agentId) return false;
28544
28691
  seen.add(message.id);
28545
28692
  return true;
@@ -28913,11 +29060,11 @@ var DefaultMailbox = class {
28913
29060
  async query(q) {
28914
29061
  const queryType = q.type === void 0 ? void 0 : normalizeMailboxMessageType(q.type);
28915
29062
  const needFullScan = q.unreadBy !== void 0 || q.since !== void 0;
28916
- const cached = await this._readAllCached(false);
29063
+ const cached2 = await this._readAllCached(false);
28917
29064
  let candidates;
28918
- let candidatesComplete = !this._messageCacheTruncated || cached !== this._messageCache;
29065
+ let candidatesComplete = !this._messageCacheTruncated || cached2 !== this._messageCache;
28919
29066
  if (needFullScan) {
28920
- candidates = cached;
29067
+ candidates = cached2;
28921
29068
  } else {
28922
29069
  if (q.to !== void 0) {
28923
29070
  const direct = this._byTo.get(q.to);
@@ -28931,7 +29078,7 @@ var DefaultMailbox = class {
28931
29078
  candidates = Array.from(this._byFrom.get(q.from) ?? []);
28932
29079
  candidatesComplete = !this._messageCacheTruncated;
28933
29080
  } else {
28934
- candidates = cached;
29081
+ candidates = cached2;
28935
29082
  }
28936
29083
  }
28937
29084
  const limit = q.limit ?? 50;
@@ -30102,19 +30249,24 @@ var ProviderModelStatusTracker = class {
30102
30249
  let newState = s.state;
30103
30250
  let reason = "";
30104
30251
  const quotaExhausted = kind === "quota_exhausted" || isQuotaExhausted(kind, status, message);
30252
+ const endpointUnreachable = isEndpointUnreachable(kind, status, message);
30105
30253
  if (quotaExhausted) {
30106
30254
  newState = "blocked";
30107
30255
  reason = "quota_exhausted";
30108
30256
  s.stateExpiresAt = now + this.cfg.quotaBlockDurationMs;
30257
+ } else if (endpointUnreachable) {
30258
+ newState = "blocked";
30259
+ reason = "endpoint_unreachable";
30260
+ s.stateExpiresAt = now + this.cfg.quotaBlockDurationMs;
30109
30261
  }
30110
- if (!quotaExhausted && s.state === "healthy") {
30262
+ if (!quotaExhausted && !endpointUnreachable && s.state === "healthy") {
30111
30263
  if (s.consecutiveFailures >= this.cfg.degradedAfterFailures) {
30112
30264
  newState = "degraded";
30113
30265
  reason = `consecutive_failures_${s.consecutiveFailures}`;
30114
30266
  s.stateExpiresAt = now + this.cfg.degradedDurationMs;
30115
30267
  }
30116
30268
  }
30117
- if (!quotaExhausted && (s.state === "degraded" || s.state === "healthy")) {
30269
+ if (!quotaExhausted && !endpointUnreachable && (s.state === "degraded" || s.state === "healthy")) {
30118
30270
  if (s.rateLimitHits >= this.cfg.blockAfterRateLimitHits) {
30119
30271
  newState = "blocked";
30120
30272
  reason = `rate_limit_threshold_${this.cfg.blockAfterRateLimitHits}`;
@@ -30444,13 +30596,20 @@ function unpairKey(key) {
30444
30596
  if (idx === -1) return [key, ""];
30445
30597
  return [key.slice(0, idx), key.slice(idx + 1)];
30446
30598
  }
30447
- var QUOTA_EXHAUSTED_RE2 = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit/i;
30599
+ var QUOTA_EXHAUSTED_RE2 = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit|usage[-_\s]*limit[-_\s]*(?:reached|exceeded)|rate[-_\s]*limit[-_\s]*exceeded/i;
30448
30600
  function isQuotaExhausted(kind, status, message) {
30449
30601
  if (status === 402) return true;
30450
30602
  if (kind !== "rate_limit" && kind !== "quota_exhausted" && kind !== "invalid_request" && kind !== "auth")
30451
30603
  return false;
30452
30604
  return QUOTA_EXHAUSTED_RE2.test(message);
30453
30605
  }
30606
+ var ENDPOINT_UNREACHABLE_RE = /(?:upstream|origin|backend|endpoint)[-_\s]*(?:unreachable|refused|connect(?:ion)?[-_\s]*(?:refused|error|fail)|unavailable|down|timeout)|no[-_\s]*(?:healthy|valid)[-_\s]*upstream|cannot[-_\s]*connect|connection[-_\s]*(?:refused|reset|closed|timed?[-_\s]out)/i;
30607
+ function isEndpointUnreachable(kind, status, message) {
30608
+ if (status !== 502 && status !== 503 && status !== 0) return false;
30609
+ if (kind !== "server" && kind !== "network" && kind !== "overloaded" && kind !== "timeout")
30610
+ return false;
30611
+ return ENDPOINT_UNREACHABLE_RE.test(message);
30612
+ }
30454
30613
  function safeCount(value) {
30455
30614
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : 0;
30456
30615
  }
@@ -39578,8 +39737,8 @@ function eliseOldToolResults(messages, opts) {
39578
39737
  const preserveStart = findPreserveStart(messages, opts.preserveK);
39579
39738
  const tokenCache = /* @__PURE__ */ new Map();
39580
39739
  const tokensFor = (b) => {
39581
- const cached = tokenCache.get(b);
39582
- if (cached !== void 0) return cached;
39740
+ const cached2 = tokenCache.get(b);
39741
+ if (cached2 !== void 0) return cached2;
39583
39742
  const t2 = b.type === "tool_result" ? estimateToolResultTokens(b.content) : b.type === "tool_use" ? estimateToolInputTokens(b.input) : 0;
39584
39743
  tokenCache.set(b, t2);
39585
39744
  return t2;
@@ -41436,8 +41595,8 @@ var DefaultDesignKitLoader = class {
41436
41595
  }
41437
41596
  async readBody(id, stack) {
41438
41597
  const key = `${id.toLowerCase()}:${stack ?? "*"}`;
41439
- const cached = this.bodyCache.get(key);
41440
- if (cached !== void 0) return cached;
41598
+ const cached2 = this.bodyCache.get(key);
41599
+ if (cached2 !== void 0) return cached2;
41441
41600
  const m = await this.find(id);
41442
41601
  if (!m) throw new Error(`Design kit "${id}" not found`);
41443
41602
  const raw = await fs20.readFile(m.path, "utf8");
@@ -45305,8 +45464,8 @@ var DefaultSkillLoader = class {
45305
45464
  }
45306
45465
  async readBody(name) {
45307
45466
  const key = name.toLowerCase();
45308
- const cached = this.bodyCache.get(key);
45309
- if (cached !== void 0) return cached;
45467
+ const cached2 = this.bodyCache.get(key);
45468
+ if (cached2 !== void 0) return cached2;
45310
45469
  const m = await this.find(name);
45311
45470
  if (!m) throw new Error(`Skill "${name}" not found`);
45312
45471
  const body = await fs22.readFile(m.path, "utf8");
@@ -45315,8 +45474,8 @@ var DefaultSkillLoader = class {
45315
45474
  }
45316
45475
  async readSaveBody(name) {
45317
45476
  const key = `save:${name.toLowerCase()}`;
45318
- const cached = this.bodyCache.get(key);
45319
- if (cached !== void 0) return cached;
45477
+ const cached2 = this.bodyCache.get(key);
45478
+ if (cached2 !== void 0) return cached2;
45320
45479
  const m = await this.find(name);
45321
45480
  if (!m) throw new Error(`Skill "${name}" not found`);
45322
45481
  const savePath = path42.join(path42.dirname(m.path), "SKILL.save.md");
@@ -46059,19 +46218,19 @@ async function canonicalizeCandidatePath(candidate, ctx) {
46059
46218
  if (path45.isAbsolute(candidate)) return candidate;
46060
46219
  const absolute = path45.resolve(ctx.projectRoot, candidate);
46061
46220
  const canonicalRoot = await realpath3(ctx.projectRoot).catch(() => ctx.projectRoot);
46062
- let probe = absolute;
46221
+ let probe2 = absolute;
46063
46222
  const missingSegments = [];
46064
46223
  while (true) {
46065
46224
  try {
46066
- const canonical = path45.join(await realpath3(probe), ...missingSegments);
46225
+ const canonical = path45.join(await realpath3(probe2), ...missingSegments);
46067
46226
  return relativeToProject(canonical, canonicalRoot);
46068
46227
  } catch (cause) {
46069
46228
  const code = cause.code;
46070
46229
  if (code !== "ENOENT" && code !== "ENOTDIR") return absolute;
46071
- const parent = path45.dirname(probe);
46072
- if (parent === probe) return absolute;
46073
- missingSegments.unshift(path45.basename(probe));
46074
- probe = parent;
46230
+ const parent = path45.dirname(probe2);
46231
+ if (parent === probe2) return absolute;
46232
+ missingSegments.unshift(path45.basename(probe2));
46233
+ probe2 = parent;
46075
46234
  }
46076
46235
  }
46077
46236
  }
@@ -47993,23 +48152,23 @@ var DefaultModelsRegistry = class {
47993
48152
  */
47994
48153
  async loadBase(opts = {}, overlayAvailable = false) {
47995
48154
  if (!opts.force) {
47996
- const cached = await this.readCacheAt(this.cacheFile);
47997
- if (cached && this.isFresh(cached.fetchedAt)) {
47998
- this.fetchedAt = new Date(cached.fetchedAt);
47999
- return cached.payload;
48155
+ const cached2 = await this.readCacheAt(this.cacheFile);
48156
+ if (cached2 && this.isFresh(cached2.fetchedAt)) {
48157
+ this.fetchedAt = new Date(cached2.fetchedAt);
48158
+ return cached2.payload;
48000
48159
  }
48001
48160
  }
48002
48161
  try {
48003
48162
  return await this.refreshBase();
48004
48163
  } catch (err) {
48005
- const cached = await this.readCacheAt(this.cacheFile);
48006
- if (cached && this.isWithinMaxStaleAge(cached.fetchedAt)) {
48007
- this.fetchedAt = new Date(cached.fetchedAt);
48164
+ const cached2 = await this.readCacheAt(this.cacheFile);
48165
+ if (cached2 && this.isWithinMaxStaleAge(cached2.fetchedAt)) {
48166
+ this.fetchedAt = new Date(cached2.fetchedAt);
48008
48167
  const ageSeconds = Math.floor((Date.now() - this.fetchedAt.getTime()) / 1e3);
48009
48168
  console.warn(
48010
48169
  `ModelsRegistry: models.dev unavailable (${toErrorMessage(err)}); using stale cache from ${formatAge(ageSeconds)} ago. Run \`wstack models refresh\` to retry.`
48011
48170
  );
48012
- return cached.payload;
48171
+ return cached2.payload;
48013
48172
  }
48014
48173
  if (overlayAvailable) {
48015
48174
  console.warn(
@@ -48084,8 +48243,8 @@ var DefaultModelsRegistry = class {
48084
48243
  async loadOverlayFromUrl(opts) {
48085
48244
  if (!this.overlayUrl || !this.overlayCacheFile) return void 0;
48086
48245
  if (!opts.force) {
48087
- const cached = await this.readCacheAt(this.overlayCacheFile);
48088
- if (cached && this.isFresh(cached.fetchedAt)) return cached.payload;
48246
+ const cached2 = await this.readCacheAt(this.overlayCacheFile);
48247
+ if (cached2 && this.isFresh(cached2.fetchedAt)) return cached2.payload;
48089
48248
  }
48090
48249
  try {
48091
48250
  const res = await this.fetchImpl(this.overlayUrl, {
@@ -48108,13 +48267,13 @@ var DefaultModelsRegistry = class {
48108
48267
  });
48109
48268
  return json;
48110
48269
  } catch {
48111
- const cached = await this.readCacheAt(this.overlayCacheFile);
48112
- if (cached && this.isWithinMaxStaleAge(cached.fetchedAt)) {
48113
- const ageSeconds = Math.floor((Date.now() - new Date(cached.fetchedAt).getTime()) / 1e3);
48270
+ const cached2 = await this.readCacheAt(this.overlayCacheFile);
48271
+ if (cached2 && this.isWithinMaxStaleAge(cached2.fetchedAt)) {
48272
+ const ageSeconds = Math.floor((Date.now() - new Date(cached2.fetchedAt).getTime()) / 1e3);
48114
48273
  console.warn(
48115
48274
  `ModelsRegistry: overlay unavailable; using stale overlay from ${formatAge(ageSeconds)} ago.`
48116
48275
  );
48117
- return cached.payload;
48276
+ return cached2.payload;
48118
48277
  }
48119
48278
  return void 0;
48120
48279
  }
@@ -48175,9 +48334,9 @@ var DefaultModelsRegistry = class {
48175
48334
  }
48176
48335
  async ageSeconds() {
48177
48336
  if (!this.fetchedAt) {
48178
- const cached = await this.readCacheAt(this.cacheFile);
48179
- if (!cached) return Number.POSITIVE_INFINITY;
48180
- return (Date.now() - new Date(cached.fetchedAt).getTime()) / 1e3;
48337
+ const cached2 = await this.readCacheAt(this.cacheFile);
48338
+ if (!cached2) return Number.POSITIVE_INFINITY;
48339
+ return (Date.now() - new Date(cached2.fetchedAt).getTime()) / 1e3;
48181
48340
  }
48182
48341
  return (Date.now() - this.fetchedAt.getTime()) / 1e3;
48183
48342
  }
@@ -48716,7 +48875,7 @@ async function startMetricsServer(opts) {
48716
48875
 
48717
48876
  // src/observability/otlp-metrics.ts
48718
48877
  var DEFAULT_INTERVAL_MS = 3e4;
48719
- var DEFAULT_TIMEOUT_MS = 1e4;
48878
+ var DEFAULT_TIMEOUT_MS2 = 1e4;
48720
48879
  function joinEndpoint(base) {
48721
48880
  if (/\/v1\/metrics\/?$/.test(base)) return base;
48722
48881
  return base.replace(/\/$/, "") + "/v1/metrics";
@@ -48779,7 +48938,7 @@ function buildOtlpMetricsRequest(sink, opts = {}) {
48779
48938
  function startOtlpMetricsExporter(opts) {
48780
48939
  const url = joinEndpoint(opts.endpoint);
48781
48940
  const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
48782
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
48941
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
48783
48942
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
48784
48943
  const onError = opts.onError ?? (() => {
48785
48944
  });
@@ -48869,7 +49028,7 @@ var CapturingSpan = class {
48869
49028
  };
48870
49029
  var DEFAULT_INTERVAL_MS2 = 5e3;
48871
49030
  var DEFAULT_BUFFER_CAP = 2048;
48872
- var DEFAULT_TIMEOUT_MS2 = 1e4;
49031
+ var DEFAULT_TIMEOUT_MS3 = 1e4;
48873
49032
  function joinEndpoint2(base) {
48874
49033
  if (/\/v1\/traces\/?$/.test(base)) return base;
48875
49034
  return base.replace(/\/$/, "") + "/v1/traces";
@@ -48910,7 +49069,7 @@ function startOtlpTraceExporter(opts) {
48910
49069
  const url = joinEndpoint2(opts.endpoint);
48911
49070
  const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS2;
48912
49071
  const maxBuffered = opts.maxBufferedSpans ?? DEFAULT_BUFFER_CAP;
48913
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
49072
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
48914
49073
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
48915
49074
  const onError = opts.onError ?? (() => {
48916
49075
  });
@@ -49441,8 +49600,8 @@ var DefaultPermissionPolicy = class {
49441
49600
  const subject = subjectForToolInput(tool.name, input, tool.subjectKey);
49442
49601
  const cacheKey = `${tool.name}::${subject ?? tool.name}`;
49443
49602
  if (tool.name !== "write") {
49444
- const cached = this._evalCache.get(cacheKey);
49445
- if (cached !== void 0) return cached;
49603
+ const cached2 = this._evalCache.get(cacheKey);
49604
+ if (cached2 !== void 0) return cached2;
49446
49605
  }
49447
49606
  if (this.sessionDenied.has(cacheKey)) {
49448
49607
  this._logDeny(tool.name, subject, "session soft deny (user pressed no)");
@@ -53519,7 +53678,7 @@ function applyModelRuntime(req, opts) {
53519
53678
  }
53520
53679
 
53521
53680
  // src/execution/one-shot-llm.ts
53522
- var DEFAULT_TIMEOUT_MS3 = 3e4;
53681
+ var DEFAULT_TIMEOUT_MS4 = 3e4;
53523
53682
  var DEFAULT_MAX_TOKENS = 1024;
53524
53683
  var OneShotOrchestrator = class {
53525
53684
  opts;
@@ -53599,6 +53758,9 @@ var OneShotOrchestrator = class {
53599
53758
  for (const entry of usableChain) {
53600
53759
  if (!evaluateModelCalendar(config.modelAvailabilitySchedule, entry.providerId, entry.model).allowed)
53601
53760
  continue;
53761
+ if (tracker && !tracker.isAvailable(entry.providerId, entry.model)) {
53762
+ continue;
53763
+ }
53602
53764
  if (entry.providerId === provider.id && entry.model === target.model) continue;
53603
53765
  let fbProvider;
53604
53766
  try {
@@ -53682,7 +53844,7 @@ var OneShotOrchestrator = class {
53682
53844
  * timeout, composed with external cancellation when the caller supplies it.
53683
53845
  */
53684
53846
  resolveSignal(input) {
53685
- const timeoutSignal = AbortSignal.timeout(input.timeoutMs ?? DEFAULT_TIMEOUT_MS3);
53847
+ const timeoutSignal = AbortSignal.timeout(input.timeoutMs ?? DEFAULT_TIMEOUT_MS4);
53686
53848
  return input.signal ? AbortSignal.any([input.signal, timeoutSignal]) : timeoutSignal;
53687
53849
  }
53688
53850
  /**
@@ -55294,8 +55456,8 @@ var PhaseOrchestrator = class {
55294
55456
  });
55295
55457
  }
55296
55458
  getTrackerForPhase(phase) {
55297
- const cached = this.trackerCache.get(phase.id);
55298
- if (cached) return cached;
55459
+ const cached2 = this.trackerCache.get(phase.id);
55460
+ if (cached2) return cached2;
55299
55461
  const tracker = new TaskTracker({ store: new DefaultTaskStore() });
55300
55462
  tracker.setGraph(phase.taskGraph);
55301
55463
  this.trackerCache.set(phase.id, tracker);
@@ -56315,7 +56477,7 @@ var CheckpointManager = class {
56315
56477
 
56316
56478
  // src/hooks/shell-executor.ts
56317
56479
  import { spawn as spawn4 } from "node:child_process";
56318
- var DEFAULT_TIMEOUT_MS4 = 5e3;
56480
+ var DEFAULT_TIMEOUT_MS5 = 5e3;
56319
56481
  var MAX_OUTPUT_BYTES = 64 * 1024;
56320
56482
  var ALLOWED_SHELL_COMMANDS = /* @__PURE__ */ new Set([
56321
56483
  // POSIX shells + Windows shells
@@ -56441,7 +56603,7 @@ async function runShellHook(spec, input, logger) {
56441
56603
  return result.outcome;
56442
56604
  }
56443
56605
  async function runShellHookDetailed(spec, input, logger, options = {}) {
56444
- const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ?? DEFAULT_TIMEOUT_MS4, 10 * 6e4));
56606
+ const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ?? DEFAULT_TIMEOUT_MS5, 10 * 6e4));
56445
56607
  const argv = isCommandAllowed(spec.command);
56446
56608
  if (!argv) {
56447
56609
  logger?.warn?.(`hook rejected: command not in allowlist: ${spec.command}`);
@@ -56594,7 +56756,7 @@ function parseHookOutcome(stdout) {
56594
56756
  }
56595
56757
 
56596
56758
  // src/hooks/http-executor.ts
56597
- var DEFAULT_TIMEOUT_MS5 = 5e3;
56759
+ var DEFAULT_TIMEOUT_MS6 = 5e3;
56598
56760
  var MAX_OUTPUT_BYTES2 = 64 * 1024;
56599
56761
  function isAllowedUrl(raw) {
56600
56762
  try {
@@ -56616,7 +56778,7 @@ async function runHttpHookDetailed(spec, input, logger, options = {}) {
56616
56778
  }
56617
56779
  };
56618
56780
  }
56619
- const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ?? DEFAULT_TIMEOUT_MS5, 10 * 6e4));
56781
+ const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ?? DEFAULT_TIMEOUT_MS6, 10 * 6e4));
56620
56782
  const timeoutController = new AbortController();
56621
56783
  const timer = setTimeout(() => timeoutController.abort(new Error("hook timeout")), timeoutMs);
56622
56784
  timer.unref?.();
@@ -56821,7 +56983,7 @@ function hookMatcherMatches(matcher, toolName) {
56821
56983
  }
56822
56984
 
56823
56985
  // src/hooks/runner.ts
56824
- var DEFAULT_TIMEOUT_MS6 = 5e3;
56986
+ var DEFAULT_TIMEOUT_MS7 = 5e3;
56825
56987
  var MAX_TIMEOUT_MS = 10 * 6e4;
56826
56988
  function normalizePreToolOutcome(outcome) {
56827
56989
  if ("action" in outcome) return outcome;
@@ -57007,7 +57169,7 @@ var HookRunner = class {
57007
57169
  return this.failureOutcome(entry, payload, result.failure);
57008
57170
  }
57009
57171
  async invokeInProcess(entry, payload, env) {
57010
- const timeoutMs = Math.max(1, Math.min(entry.timeoutMs ?? DEFAULT_TIMEOUT_MS6, MAX_TIMEOUT_MS));
57172
+ const timeoutMs = Math.max(1, Math.min(entry.timeoutMs ?? DEFAULT_TIMEOUT_MS7, MAX_TIMEOUT_MS));
57011
57173
  const controller = new AbortController();
57012
57174
  let timedOut = false;
57013
57175
  const onParentAbort = () => controller.abort(env.signal?.reason);
@@ -59720,8 +59882,8 @@ function makePluginLLM(owner, hostLLM, providerRegistry, config, getLiveConfig,
59720
59882
  return { provider: liveProvider, providerName };
59721
59883
  }
59722
59884
  const cacheKey = `${providerName}|${model}`;
59723
- const cached = providerCache.get(cacheKey);
59724
- if (cached) return { provider: cached, providerName };
59885
+ const cached2 = providerCache.get(cacheKey);
59886
+ if (cached2) return { provider: cached2, providerName };
59725
59887
  let created;
59726
59888
  if (hostLLM.createProvider) {
59727
59889
  created = hostLLM.createProvider(providerName, model);
@@ -64102,9 +64264,9 @@ var ReplayProviderRunner = class {
64102
64264
  opts;
64103
64265
  async run(runOpts) {
64104
64266
  const hash4 = hashRequest(runOpts.request);
64105
- const cached = await this.opts.log.lookup(this.opts.sessionId, hash4);
64267
+ const cached2 = await this.opts.log.lookup(this.opts.sessionId, hash4);
64106
64268
  if (this.opts.mode === "replay") {
64107
- if (!cached) {
64269
+ if (!cached2) {
64108
64270
  this.opts.logger?.warn?.(
64109
64271
  `replay: no recorded response for hash ${hash4} (model ${runOpts.request.model})`
64110
64272
  );
@@ -64113,15 +64275,15 @@ var ReplayProviderRunner = class {
64113
64275
  );
64114
64276
  }
64115
64277
  this.opts.logger?.debug?.(
64116
- `replay: served cached response for hash ${hash4} (recorded ${cached.ts})`
64278
+ `replay: served cached response for hash ${hash4} (recorded ${cached2.ts})`
64117
64279
  );
64118
- return cached.response;
64280
+ return cached2.response;
64119
64281
  }
64120
- if (this.opts.mode === "auto" && cached) {
64282
+ if (this.opts.mode === "auto" && cached2) {
64121
64283
  this.opts.logger?.debug?.(
64122
64284
  `replay: auto-hit hash ${hash4}, served cached response`
64123
64285
  );
64124
- return cached.response;
64286
+ return cached2.response;
64125
64287
  }
64126
64288
  const response = await this.inner.run(runOpts);
64127
64289
  await this.opts.log.record({
@@ -64341,9 +64503,9 @@ var FileMemoryBackend = class {
64341
64503
  }
64342
64504
  async getIndex(file, scope) {
64343
64505
  const mtime = await this.getMtime(file);
64344
- const cached = this.indexCache.get(file);
64345
- if (cached && cached.mtimeMs === mtime) {
64346
- return cached;
64506
+ const cached2 = this.indexCache.get(file);
64507
+ if (cached2 && cached2.mtimeMs === mtime) {
64508
+ return cached2;
64347
64509
  }
64348
64510
  const entries = await this.loadEntries(file, scope, mtime);
64349
64511
  const index = buildInvertedIndex(entries);
@@ -70189,6 +70351,8 @@ export {
70189
70351
  MAILBOX_HEALTH_DEFAULT_FROM,
70190
70352
  MAILBOX_HEALTH_DEFAULT_INTERVAL_MS,
70191
70353
  MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS,
70354
+ MAILBOX_HTTP_DEFAULT_MAX_AGE_MS,
70355
+ MAILBOX_HTTP_MAX_AGE_CEILING_MS,
70192
70356
  MAILBOX_HTTP_MAX_BODY_BYTES,
70193
70357
  MAILBOX_HTTP_RATE_LIMIT_PER_MINUTE,
70194
70358
  MAILBOX_HTTP_RATE_LIMIT_WINDOW_MS,
@@ -70352,6 +70516,7 @@ export {
70352
70516
  buildTranscriptFromEvents,
70353
70517
  buildUserContentBlocks,
70354
70518
  canonicalProjectRoot,
70519
+ checkConnectivity,
70355
70520
  childChronicleContext,
70356
70521
  classifyFamily,
70357
70522
  classifyMailboxRecipient,
@@ -70728,6 +70893,7 @@ export {
70728
70893
  repairToolUseAdjacency,
70729
70894
  repeatedReadPressure,
70730
70895
  resetCalibration,
70896
+ resetConnectivityCache,
70731
70897
  resolveAuditLevel,
70732
70898
  resolveBrainConfigDefaults,
70733
70899
  resolveBundledDesignKitsDir,