svamp-cli 0.2.328 → 0.2.330

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +27 -6
  2. package/dist/{adminCommands-DotiO7jx.mjs → adminCommands-CeAsjKoA.mjs} +1 -1
  3. package/dist/{agentCommands-DefL1pIo.mjs → agentCommands-CDj6yTgX.mjs} +5 -5
  4. package/dist/{auth-DLK3tc_f.mjs → auth-CtiKOzhL.mjs} +1 -1
  5. package/dist/{cli-BCN1uAze.mjs → cli-CZ4D7AII.mjs} +79 -78
  6. package/dist/cli.mjs +2 -2
  7. package/dist/{commands-xhA5FWM8.mjs → commands-71PkPL_M.mjs} +10 -2
  8. package/dist/{commands-DH2WCdPH.mjs → commands-BFkBvM5j.mjs} +3 -3
  9. package/dist/{commands-DEZLlXJ3.mjs → commands-BOBRaVaF.mjs} +34 -27
  10. package/dist/{commands-gO42Ijz3.mjs → commands-BRTTViag.mjs} +3 -3
  11. package/dist/{commands-uN_gulw0.mjs → commands-BXjej1wP.mjs} +12 -4
  12. package/dist/{commands-BD6Qfv3u.mjs → commands-DiBOzYv7.mjs} +11 -11
  13. package/dist/{commands-BFlfbiey.mjs → commands-DkIbjVr6.mjs} +1 -1
  14. package/dist/{commands-BEnXz1U_.mjs → commands-WJbeIMNx.mjs} +2 -2
  15. package/dist/{fleet-CbKnESdR.mjs → fleet-DmTm6tsY.mjs} +8 -4
  16. package/dist/{headlessCli-2wTVI-Kj.mjs → headlessCli-DqlYDREf.mjs} +2 -2
  17. package/dist/index.mjs +1 -1
  18. package/dist/{notifyCommands--tpDRdrL.mjs → notifyCommands-WZDIxM_h.mjs} +1 -1
  19. package/dist/package-CT65p79F.mjs +64 -0
  20. package/dist/{rpc-CZqCc9Pr.mjs → rpc-CFb-c-Nu.mjs} +1 -1
  21. package/dist/{rpc-BCLZpI5H.mjs → rpc-tO-T8OWN.mjs} +2 -1
  22. package/dist/{run-BAYXQ4-N.mjs → run-CA3J4pGr.mjs} +1 -1
  23. package/dist/{run-CSV6OgQ8.mjs → run-ON_xcuFF.mjs} +195 -23
  24. package/dist/{scheduler-s_j089nA.mjs → scheduler-DtzofW-S.mjs} +1 -1
  25. package/dist/{serveCommands-C4779W5n.mjs → serveCommands-DBz696oe.mjs} +10 -10
  26. package/dist/{sideband-B7sDP61Z.mjs → sideband-CDQJ24BM.mjs} +1 -1
  27. package/package.json +3 -3
  28. package/dist/package-BORyBEey.mjs +0 -64
@@ -3350,7 +3350,11 @@ class ServeManager {
3350
3350
  if (access === "owner" && !spec.ownerEmail) {
3351
3351
  this.log(`\u26A0 Mount '${spec.name}': access='owner' but no owner email could be resolved \u2014 NO ONE will be able to sign in. Use an explicit email allowlist instead, e.g. access: ["you@example.com"].`);
3352
3352
  }
3353
- const reusableToken = replaced && access === "link" && replaced.linkToken && !spec.regenerateUrl && !crossSessionTakeover ? replaced.linkToken : void 0;
3353
+ const sameTarget = !!replaced && replaced.directory === resolvedDir && JSON.stringify(replaced.process ?? null) === JSON.stringify(spec.process ?? null);
3354
+ const reusableToken = replaced && access === "link" && replaced.linkToken && !spec.regenerateUrl && !crossSessionTakeover && sameTarget ? replaced.linkToken : void 0;
3355
+ if (replaced && access === "link" && replaced.linkToken && !sameTarget && !spec.regenerateUrl && !crossSessionTakeover) {
3356
+ this.log(`Mount '${spec.name}': target changed \u2014 minting a NEW capability URL. The previously shared link no longer resolves (it would otherwise have followed the mount to its new target).`);
3357
+ }
3354
3358
  const mount = {
3355
3359
  name: spec.name,
3356
3360
  directory: resolvedDir,
@@ -4718,6 +4722,7 @@ var claudeAuth = /*#__PURE__*/Object.freeze({
4718
4722
  MANAGED_ENV_KEYS: MANAGED_ENV_KEYS,
4719
4723
  applyClaudeProxyEnv: applyClaudeProxyEnv,
4720
4724
  getClaudeAuthStatus: getClaudeAuthStatus,
4725
+ normalizeProxyUrl: normalizeProxyUrl,
4721
4726
  resolveHyphaProxyUrl: resolveHyphaProxyUrl,
4722
4727
  setClaudeAuthCustom: setClaudeAuthCustom,
4723
4728
  setClaudeAuthHyphaProxy: setClaudeAuthHyphaProxy,
@@ -4988,7 +4993,8 @@ function resolveAccountEnv(account, env = process.env, svampHome) {
4988
4993
  };
4989
4994
  }
4990
4995
  case "hypha-proxy": {
4991
- const url = account.baseUrl ? stripV1(account.baseUrl) : resolveHyphaProxyUrl();
4996
+ const envProxyUrl = (env.SVAMP_HYPHA_PROXY_URL || "").trim();
4997
+ const url = account.baseUrl ? stripV1(account.baseUrl) : envProxyUrl ? normalizeProxyUrl(envProxyUrl) : resolveHyphaProxyUrl();
4992
4998
  const token = env.HYPHA_TOKEN;
4993
4999
  if (!url) throw new Error("hypha-proxy account has no URL (set SVAMP_HYPHA_PROXY_URL or an account base URL)");
4994
5000
  if (!token) throw new Error("hypha-proxy account requires HYPHA_TOKEN on the machine");
@@ -5377,7 +5383,25 @@ function cancelFlow(flowId) {
5377
5383
  flows.delete(flowId);
5378
5384
  }
5379
5385
 
5380
- const FIELD_RANGES = [[0, 59], [0, 23], [1, 31], [1, 12], [0, 6]];
5386
+ const FIELD_RANGES = [[0, 59], [0, 23], [1, 31], [1, 12], [0, 7]];
5387
+ const MONTH_NAMES = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
5388
+ const DOW_NAMES = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
5389
+ function substituteNames(token, fieldIndex) {
5390
+ const names = fieldIndex === 3 ? MONTH_NAMES : fieldIndex === 4 ? DOW_NAMES : null;
5391
+ if (!names) return token;
5392
+ return token.replace(/[A-Za-z]+/g, (word) => {
5393
+ const i = names.indexOf(word.toUpperCase());
5394
+ if (i < 0) return word;
5395
+ return String(fieldIndex === 3 ? i + 1 : i);
5396
+ });
5397
+ }
5398
+ function normalizeDow(set) {
5399
+ if (!set.has(7)) return set;
5400
+ const out = new Set(set);
5401
+ out.delete(7);
5402
+ out.add(0);
5403
+ return out;
5404
+ }
5381
5405
  function parseField(token, [min, max]) {
5382
5406
  const set = /* @__PURE__ */ new Set();
5383
5407
  for (const part of token.split(",")) {
@@ -5406,8 +5430,11 @@ function parseField(token, [min, max]) {
5406
5430
  function parseCron(expr) {
5407
5431
  const fields = String(expr).trim().split(/\s+/);
5408
5432
  if (fields.length !== 5) throw new Error(`cron must have 5 fields, got ${fields.length}: "${expr}"`);
5409
- const [minute, hour, dom, month, dow] = fields.map((f, i) => parseField(f, FIELD_RANGES[i]));
5410
- return { minute, hour, dom, month, dow, domRestricted: fields[2] !== "*", dowRestricted: fields[4] !== "*" };
5433
+ const [minute, hour, dom, month, dow] = fields.map((f, i) => parseField(substituteNames(f, i), FIELD_RANGES[i]));
5434
+ return { minute, hour, dom, month, dow: normalizeDow(dow), domRestricted: fields[2] !== "*", dowRestricted: fields[4] !== "*" };
5435
+ }
5436
+ function validateCronExpr(expr) {
5437
+ parseCron(expr);
5411
5438
  }
5412
5439
  function cronMatches(expr, date) {
5413
5440
  const c = typeof expr === "string" ? parseCron(expr) : expr;
@@ -8305,7 +8332,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
8305
8332
  }
8306
8333
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
8307
8334
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
8308
- const { toolsForRole } = await import('./sideband-B7sDP61Z.mjs');
8335
+ const { toolsForRole } = await import('./sideband-CDQJ24BM.mjs');
8309
8336
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
8310
8337
  return fmt(r2);
8311
8338
  }
@@ -8410,18 +8437,21 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
8410
8437
  return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
8411
8438
  }
8412
8439
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
8413
- const { queryCore } = await import('./commands-DEZLlXJ3.mjs');
8440
+ const { queryCore } = await import('./commands-BOBRaVaF.mjs');
8414
8441
  const timeout = c.reply?.timeout_sec || 120;
8415
8442
  let result;
8443
+ let thrownSessionId;
8416
8444
  try {
8417
8445
  result = await queryCore(selfMachine, dir, rendered, { permissionMode: "bypassPermissions", tag: "svamp-channel", timeout });
8418
8446
  } catch (e) {
8447
+ thrownSessionId = e?.sessionId || void 0;
8419
8448
  return { ok: false, call_id: callId, status: "error", error: e?.message || String(e) };
8420
8449
  } finally {
8421
8450
  statelessLimiter.release(senderKey);
8422
- if (result?.sessionId) {
8451
+ const ephemeralId = result?.sessionId || thrownSessionId;
8452
+ if (ephemeralId) {
8423
8453
  try {
8424
- handlers.deleteSession?.(result.sessionId);
8454
+ handlers.deleteSession?.(ephemeralId);
8425
8455
  } catch {
8426
8456
  }
8427
8457
  }
@@ -16941,12 +16971,13 @@ function addIssue(projectRoot, fields) {
16941
16971
  function issueLockPath(projectRoot, id) {
16942
16972
  return join$1(issuesDir(projectRoot), `${normalizeIssueRef(id)}.lock`);
16943
16973
  }
16974
+ const ISSUE_LOCK_DEADLINE_MS = 3e3;
16944
16975
  function withIssueLock(projectRoot, id, fn) {
16945
16976
  try {
16946
16977
  mkdirSync$1(issuesDir(projectRoot), { recursive: true });
16947
16978
  } catch {
16948
16979
  }
16949
- return withFileLock(issueLockPath(projectRoot, id), fn);
16980
+ return withFileLock(issueLockPath(projectRoot, id), fn, { deadlineMs: ISSUE_LOCK_DEADLINE_MS });
16950
16981
  }
16951
16982
  function _updateIssueUnlocked(projectRoot, id, patch) {
16952
16983
  const cur = getIssue(projectRoot, id);
@@ -18189,6 +18220,49 @@ function resolveContextWindow(opts) {
18189
18220
  return candidate;
18190
18221
  }
18191
18222
 
18223
+ const DEFAULT_AUTO_COMPACT_RATIO = 0.85;
18224
+ const MIN_WINDOW_FOR_BACKSTOP = 5e4;
18225
+ const MIN_RATIO = 0.5;
18226
+ const MAX_RATIO = 0.97;
18227
+ function resolveAutoCompactEnabled(env = process.env) {
18228
+ const v = (env.SVAMP_AUTO_COMPACT ?? "").trim().toLowerCase();
18229
+ if (v === "0" || v === "false" || v === "off" || v === "no") return false;
18230
+ return true;
18231
+ }
18232
+ function resolveAutoCompactRatio(env = process.env) {
18233
+ const raw = (env.SVAMP_AUTO_COMPACT_RATIO ?? "").trim();
18234
+ if (!raw) return DEFAULT_AUTO_COMPACT_RATIO;
18235
+ const n = Number(raw);
18236
+ if (!Number.isFinite(n)) return DEFAULT_AUTO_COMPACT_RATIO;
18237
+ if (n < MIN_RATIO) return MIN_RATIO;
18238
+ if (n > MAX_RATIO) return MAX_RATIO;
18239
+ return n;
18240
+ }
18241
+ function decideProactiveCompaction(opts) {
18242
+ const { observed, window, ratio, enabled } = opts;
18243
+ const pct = window > 0 ? observed / window : 0;
18244
+ if (!enabled) return { shouldCompact: false, window, pct, reason: "disabled" };
18245
+ if (!(window >= MIN_WINDOW_FOR_BACKSTOP)) return { shouldCompact: false, window, pct, reason: "window-too-small" };
18246
+ if (!(observed > 0)) return { shouldCompact: false, window, pct, reason: "no-observed" };
18247
+ if (pct >= ratio) return { shouldCompact: true, window, pct, reason: "threshold" };
18248
+ return { shouldCompact: false, window, pct, reason: "below-threshold" };
18249
+ }
18250
+ function fmtK(n) {
18251
+ return `${Math.round((n || 0) / 1e3)}K`;
18252
+ }
18253
+ function describeAutoCompact(observed, window, pct) {
18254
+ return `Context at ${Math.round(pct * 100)}% of the ${fmtK(window)} window (${fmtK(observed)} tokens) \u2014 compacting automatically to stay under the model's limit.`;
18255
+ }
18256
+ function isContextTooLongError(text) {
18257
+ if (!text) return false;
18258
+ const t = text.toLowerCase();
18259
+ if (t.includes("prompt is too long")) return true;
18260
+ if (/tokens\s*>\s*[\d,]+\s*maximum/.test(t)) return true;
18261
+ if (t.includes("input length and") && t.includes("max_tokens") && t.includes("context")) return true;
18262
+ if (t.includes("context") && t.includes("exceed") && t.includes("limit") && !t.includes("subscription")) return true;
18263
+ return false;
18264
+ }
18265
+
18192
18266
  function fmtTokens(n) {
18193
18267
  return Math.max(0, Math.round(n)).toLocaleString("en-US");
18194
18268
  }
@@ -18220,9 +18294,17 @@ function nextFailuresAfterZombieProbeFailure(consecutiveHeartbeatFailures) {
18220
18294
  function shouldRunServiceProbe(args) {
18221
18295
  return !args.inGrace && !args.zombieProbeRan;
18222
18296
  }
18297
+ const MAX_DISCONNECT_RESPAWNS = 3;
18298
+ const DISCONNECT_RESPAWN_WINDOW_MS = 30 * 6e4;
18299
+ function pruneRespawnTimestamps(timestamps, now, windowMs = DISCONNECT_RESPAWN_WINDOW_MS) {
18300
+ return (timestamps || []).filter((t) => Number.isFinite(t) && now - t < windowMs);
18301
+ }
18223
18302
  function decideDisconnectRecovery(args) {
18224
18303
  if (args.shutdownRequested) return "stay";
18225
- return args.supervised ? "exit-for-respawn" : "stay";
18304
+ if (!args.supervised) return "stay";
18305
+ const cap = args.maxRespawns ?? MAX_DISCONNECT_RESPAWNS;
18306
+ if ((args.respawnsInWindow ?? 0) >= cap) return "stay";
18307
+ return "exit-for-respawn";
18226
18308
  }
18227
18309
  function shouldForceReconnect(consecutiveHeartbeatFailures) {
18228
18310
  if (consecutiveHeartbeatFailures < 2) return false;
@@ -18700,6 +18782,9 @@ function dedupeLines(lines) {
18700
18782
  function buildClaudeErrorHint(text, apiErrorStatus) {
18701
18783
  const lower = (text || "").toLowerCase();
18702
18784
  const isOverload = apiErrorStatus === 529 || lower.includes("529") || lower.includes("overload");
18785
+ if (isContextTooLongError(text)) {
18786
+ return "\n\nThe conversation exceeded the model's context window (the prompt is too long). The daemon is compacting the history automatically to recover \u2014 resend your message. If it keeps overflowing, start a fresh session, or raise the auto-compaction headroom with a lower `SVAMP_AUTO_COMPACT_RATIO` (e.g. 0.75) on the machine running the daemon.";
18787
+ }
18703
18788
  const isResumeIssue = lower.includes("tool_use.name") || lower.includes("invalid_request") || lower.includes("messages.");
18704
18789
  const isBillingIssue = lower.includes("credit") || lower.includes("balance") || lower.includes("billing") || lower.includes("quota") || lower.includes("subscription") || lower.includes("payment") || lower.includes("1m-context") || lower.includes("1m context");
18705
18790
  const isLoginIssue = lower.includes("login") || lower.includes("logged in") || lower.includes("auth") || lower.includes("api key") || lower.includes("unauthorized");
@@ -20018,6 +20103,25 @@ function writeDaemonStateFile(state) {
20018
20103
  writeFileSync(tmpPath, JSON.stringify(state, null, 2), "utf-8");
20019
20104
  renameSync$1(tmpPath, DAEMON_STATE_FILE);
20020
20105
  }
20106
+ const DISCONNECT_RESPAWN_FILE = join(SVAMP_HOME, "disconnect-respawns.json");
20107
+ function readDisconnectRespawns() {
20108
+ try {
20109
+ if (!existsSync$1(DISCONNECT_RESPAWN_FILE)) return [];
20110
+ const parsed = JSON.parse(readFileSync$1(DISCONNECT_RESPAWN_FILE, "utf-8"));
20111
+ return Array.isArray(parsed) ? parsed.filter((n) => typeof n === "number") : [];
20112
+ } catch {
20113
+ return [];
20114
+ }
20115
+ }
20116
+ function writeDisconnectRespawns(timestamps) {
20117
+ try {
20118
+ ensureHomeDir();
20119
+ const tmpPath = DISCONNECT_RESPAWN_FILE + ".tmp";
20120
+ writeFileSync(tmpPath, JSON.stringify(timestamps), "utf-8");
20121
+ renameSync$1(tmpPath, DISCONNECT_RESPAWN_FILE);
20122
+ } catch {
20123
+ }
20124
+ }
20021
20125
  function readDaemonStateFile() {
20022
20126
  try {
20023
20127
  if (!existsSync$1(DAEMON_STATE_FILE)) return null;
@@ -20271,7 +20375,7 @@ async function startDaemon(options) {
20271
20375
  try {
20272
20376
  const dir = loadSessionIndex()[sessionId]?.directory;
20273
20377
  if (!dir) return;
20274
- const { reconcileServiceLinks } = await import('./agentCommands-DefL1pIo.mjs');
20378
+ const { reconcileServiceLinks } = await import('./agentCommands-CDj6yTgX.mjs');
20275
20379
  const configPath = getSvampConfigPath(dir, sessionId);
20276
20380
  const config = readSvampConfig(configPath);
20277
20381
  const entries = Array.from(urls.entries());
@@ -20293,7 +20397,7 @@ async function startDaemon(options) {
20293
20397
  try {
20294
20398
  const dir = loadSessionIndex()[sessionId]?.directory;
20295
20399
  if (!dir) return;
20296
- const { reconcileServiceLinks } = await import('./agentCommands-DefL1pIo.mjs');
20400
+ const { reconcileServiceLinks } = await import('./agentCommands-CDj6yTgX.mjs');
20297
20401
  const configPath = getSvampConfigPath(dir, sessionId);
20298
20402
  const config = readSvampConfig(configPath);
20299
20403
  const incoming = [{
@@ -20314,7 +20418,7 @@ async function startDaemon(options) {
20314
20418
  try {
20315
20419
  const dir = loadSessionIndex()[sessionId]?.directory;
20316
20420
  if (!dir) return;
20317
- const { dropServiceLinks } = await import('./agentCommands-DefL1pIo.mjs');
20421
+ const { dropServiceLinks } = await import('./agentCommands-CDj6yTgX.mjs');
20318
20422
  const configPath = getSvampConfigPath(dir, sessionId);
20319
20423
  const config = readSvampConfig(configPath);
20320
20424
  if (dropServiceLinks(config, "serve", mountName)) {
@@ -20389,12 +20493,16 @@ async function startDaemon(options) {
20389
20493
  });
20390
20494
  server.on("disconnected", (reason) => {
20391
20495
  const supervised2 = process.env.SVAMP_SUPERVISED === "1";
20392
- const recovery = decideDisconnectRecovery({ supervised: supervised2, shutdownRequested });
20496
+ const nowMs = Date.now();
20497
+ const respawnHistory = pruneRespawnTimestamps(readDisconnectRespawns(), nowMs);
20498
+ const recovery = decideDisconnectRecovery({ supervised: supervised2, shutdownRequested, respawnsInWindow: respawnHistory.length });
20393
20499
  if (recovery === "exit-for-respawn") {
20500
+ writeDisconnectRespawns([...respawnHistory, nowMs]);
20394
20501
  logger.log(`Hypha connection permanently lost: ${reason}. Exiting for a clean supervised respawn (sessions restore via --resume).`);
20395
20502
  setTimeout(() => process.exit(1), 250);
20396
20503
  } else {
20397
- logger.log(`Hypha connection permanently lost: ${reason}. Daemon continues running (unsupervised) \u2014 restart manually to reconnect.`);
20504
+ const capped = supervised2 && !shutdownRequested && respawnHistory.length >= MAX_DISCONNECT_RESPAWNS;
20505
+ logger.log(capped ? `Hypha connection permanently lost: ${reason}. Already respawned ${respawnHistory.length}x in the last 30 min \u2014 the far end looks down, so STAYING UP (local sessions keep running). Will retry after the window clears.` : `Hypha connection permanently lost: ${reason}. Daemon continues running (unsupervised) \u2014 restart manually to reconnect.`);
20398
20506
  }
20399
20507
  });
20400
20508
  const pidToTrackedSession = /* @__PURE__ */ new Map();
@@ -21281,6 +21389,11 @@ ${parts.join("\n")}`);
21281
21389
  let consecutiveOverloadRetries = 0;
21282
21390
  let overloadBailedThisTurn = false;
21283
21391
  let pendingCompactTurn = false;
21392
+ const autoCompactEnabled = resolveAutoCompactEnabled();
21393
+ const autoCompactRatio = resolveAutoCompactRatio();
21394
+ let autoCompactWasAutoInjected = false;
21395
+ let autoCompactDisabled = false;
21396
+ let autoCompactRecoveryTried = false;
21284
21397
  let noIsolationWarned = false;
21285
21398
  const RATELIMIT_CFG = getRateLimitRetryConfig();
21286
21399
  let currentTurnMessage;
@@ -21644,6 +21757,23 @@ ${parts.join("\n")}`);
21644
21757
  } else if (isRetryableRateLimit(resultText, msg.api_error_status) && scheduleRateLimitRetry2()) {
21645
21758
  rateLimitRetryScheduled = true;
21646
21759
  lastErrorMessagePushed = true;
21760
+ } else if (isContextTooLongError(resultText) && autoCompactEnabled && !autoCompactDisabled && !autoCompactRecoveryTried) {
21761
+ autoCompactRecoveryTried = true;
21762
+ logger.log(`[Session ${sessionId}] Context-overflow 400 \u2014 injecting one automatic /compact recovery`);
21763
+ sessionService.pushMessage(
21764
+ { type: "message", message: "The conversation exceeded the model's context window. Compacting automatically to recover \u2014 resend your message once it finishes. If this repeats, start a fresh session.", level: "warning" },
21765
+ "event"
21766
+ );
21767
+ const existingQueue = sessionMetadata.messageQueue || [];
21768
+ sessionMetadata = {
21769
+ ...sessionMetadata,
21770
+ messageQueue: [
21771
+ { id: randomUUID(), text: "/compact", displayText: "\u{1F5DC}\uFE0F Auto-compacting to recover from context overflow", createdAt: Date.now(), alreadyStored: true, autoCompact: true },
21772
+ ...existingQueue
21773
+ ]
21774
+ };
21775
+ sessionService.updateMetadata(sessionMetadata);
21776
+ lastErrorMessagePushed = true;
21647
21777
  } else {
21648
21778
  const lower = resultText.toLowerCase();
21649
21779
  const isLoginIssue = lower.includes("login") || lower.includes("logged in") || lower.includes("auth") || lower.includes("api key") || lower.includes("unauthorized");
@@ -21707,13 +21837,22 @@ ${parts.join("\n")}`);
21707
21837
  }
21708
21838
  if (pendingCompactTurn) {
21709
21839
  pendingCompactTurn = false;
21840
+ const wasAuto = autoCompactWasAutoInjected;
21841
+ autoCompactWasAutoInjected = false;
21842
+ if (wasAuto) {
21843
+ autoCompactDisabled = true;
21844
+ logger.log(`[Session ${sessionId}] Auto /compact unsupported by this Claude Code \u2014 disabling the auto-compaction backstop for this session`);
21845
+ }
21710
21846
  logger.log(`[Session ${sessionId}] /compact produced no compaction boundary \u2014 Claude Code likely too old to handle it in stream-json mode`);
21711
21847
  sessionService.pushMessage(
21712
21848
  { type: "message", message: compactUnsupportedWarning(), level: "warning" },
21713
21849
  "event"
21714
21850
  );
21715
21851
  }
21716
- if (!msg.is_error) resetRateLimitStreak();
21852
+ if (!msg.is_error) {
21853
+ resetRateLimitStreak();
21854
+ autoCompactRecoveryTried = false;
21855
+ }
21717
21856
  if (msg.session_id) {
21718
21857
  claudeResumeId = msg.session_id;
21719
21858
  if (sessionMetadata.claudeSessionId !== msg.session_id) {
@@ -21799,6 +21938,35 @@ ${parts.join("\n")}`);
21799
21938
  logger.log(`[Session ${sessionId}] ${taskInfo}`);
21800
21939
  sessionService.pushMessage({ type: "session_event", message: taskInfo }, "session");
21801
21940
  }
21941
+ if (!msg.is_error && !pendingCompactTurn && !autoCompactDisabled && autoCompactEnabled) {
21942
+ try {
21943
+ const observed = computeObservedContext(msg.usage);
21944
+ const decision = decideProactiveCompaction({
21945
+ observed,
21946
+ window: resolvedWindow > 0 ? resolvedWindow : sessionMetadata.contextWindow || 0,
21947
+ ratio: autoCompactRatio,
21948
+ enabled: autoCompactEnabled
21949
+ });
21950
+ if (decision.shouldCompact) {
21951
+ logger.log(`[Session ${sessionId}] Auto-compaction backstop firing at ${Math.round(decision.pct * 100)}% of ${decision.window} window (${observed} tokens) \u2014 injecting /compact`);
21952
+ sessionService.pushMessage(
21953
+ { type: "message", message: describeAutoCompact(observed, decision.window, decision.pct), level: "warning" },
21954
+ "event"
21955
+ );
21956
+ const existingQueue = sessionMetadata.messageQueue || [];
21957
+ sessionMetadata = {
21958
+ ...sessionMetadata,
21959
+ messageQueue: [
21960
+ { id: randomUUID(), text: "/compact", displayText: "\u{1F5DC}\uFE0F Auto-compacting context", createdAt: Date.now(), alreadyStored: true, autoCompact: true },
21961
+ ...existingQueue
21962
+ ]
21963
+ };
21964
+ sessionService.updateMetadata(sessionMetadata);
21965
+ }
21966
+ } catch (e) {
21967
+ logger.log(`[Session ${sessionId}] Auto-compaction backstop check failed: ${e?.message}`);
21968
+ }
21969
+ }
21802
21970
  const queueLen = sessionMetadata.messageQueue?.length ?? 0;
21803
21971
  if (queueLen > 0 && claudeResumeId && !trackedSession.stopped) {
21804
21972
  setTimeout(() => processMessageQueueRef?.(), 200);
@@ -21885,6 +22053,8 @@ ${parts.join("\n")}`);
21885
22053
  sessionService.pushMessage(msg, "session");
21886
22054
  } else if (msg.type === "system" && msg.subtype === "compact_boundary") {
21887
22055
  pendingCompactTurn = false;
22056
+ autoCompactWasAutoInjected = false;
22057
+ autoCompactRecoveryTried = false;
21888
22058
  const compactLine = describeCompaction(msg.compact_metadata);
21889
22059
  logger.log(`[Session ${sessionId}] ${compactLine}`);
21890
22060
  sessionService.pushMessage(
@@ -22697,11 +22867,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
22697
22867
  });
22698
22868
  },
22699
22869
  onIssue: async (params) => {
22700
- const { issueRpc } = await import('./rpc-CZqCc9Pr.mjs');
22870
+ const { issueRpc } = await import('./rpc-CFb-c-Nu.mjs');
22701
22871
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
22702
22872
  },
22703
22873
  onWorkflow: async (params) => {
22704
- const { workflowRpc } = await import('./rpc-BCLZpI5H.mjs');
22874
+ const { workflowRpc } = await import('./rpc-tO-T8OWN.mjs');
22705
22875
  return workflowRpc(params?.cwd || directory, params || {});
22706
22876
  },
22707
22877
  onRipgrep: async (args, cwd) => {
@@ -22840,6 +23010,8 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
22840
23010
  userMessagePending = true;
22841
23011
  turnInitiatedByUser = true;
22842
23012
  currentTurnMessage = next.text;
23013
+ pendingCompactTurn = isCompactCommand(next.text);
23014
+ autoCompactWasAutoInjected = pendingCompactTurn && !!next.autoCompact;
22843
23015
  resetRateLimitStreak();
22844
23016
  if (rateLimitRetryTimer) {
22845
23017
  clearTimeout(rateLimitRetryTimer);
@@ -23407,11 +23579,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
23407
23579
  });
23408
23580
  },
23409
23581
  onIssue: async (params) => {
23410
- const { issueRpc } = await import('./rpc-CZqCc9Pr.mjs');
23582
+ const { issueRpc } = await import('./rpc-CFb-c-Nu.mjs');
23411
23583
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
23412
23584
  },
23413
23585
  onWorkflow: async (params) => {
23414
- const { workflowRpc } = await import('./rpc-BCLZpI5H.mjs');
23586
+ const { workflowRpc } = await import('./rpc-tO-T8OWN.mjs');
23415
23587
  return workflowRpc(params?.cwd || directory, params || {});
23416
23588
  },
23417
23589
  onRipgrep: async (args, cwd) => {
@@ -24764,7 +24936,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
24764
24936
  const PING_TIMEOUT_MS = 15e3;
24765
24937
  const POST_RECONNECT_GRACE_MS = 2e4;
24766
24938
  const RECONNECT_JITTER_MS = 2500;
24767
- const { WorkflowScheduler } = await import('./scheduler-s_j089nA.mjs');
24939
+ const { WorkflowScheduler } = await import('./scheduler-DtzofW-S.mjs');
24768
24940
  const workflowProjectRoots = () => {
24769
24941
  const dirs = /* @__PURE__ */ new Set();
24770
24942
  for (const s of pidToTrackedSession.values()) {
@@ -25399,4 +25571,4 @@ var run = /*#__PURE__*/Object.freeze({
25399
25571
  writeStopMarker: writeStopMarker
25400
25572
  });
25401
25573
 
25402
- export { listSkillFiles as $, saveWorkflow as A, rawWorkflow as B, listWorkflows as C, isWorkflowEnabled as D, workflowSchedules as E, inZone as F, cronMatches as G, summarize as H, workflowSteps as I, parseJwtEmail as J, computeCollectionConfigUpdate as K, SYSTEM_COLLECTION_CONFIG as L, loadMachineContext as M, buildMachineInstructions as N, machineToolsForRole as O, buildMachineTools as P, parseFrontmatter as Q, READ_ONLY_TOOLS as R, SharingNotificationSync as S, getSkillsServer as T, getSkillsWorkspaceName as U, getSkillsCollectionName as V, fetchWithTimeout as W, searchSkills as X, SKILLS_DIR as Y, getSkillInfo as Z, downloadSkillFile as _, createSessionStore as a, resolveModel as a0, formatHandle as a1, normalizeAllowedUser as a2, loadSecurityContextConfig as a3, resolveSecurityContext as a4, buildSecurityContextFromFlags as a5, mergeSecurityContexts as a6, buildSessionShareUrl as a7, computeOutboundHop as a8, registerAwaitingReply as a9, kimiSetup as aA, api as aB, supervisorLock as aC, run as aD, buildMachineShareUrl as aa, parseHandle as ab, handleMatchesMetadata as ac, PINNED_CODEX_VERSION as ad, clearStopMarker as ae, stopMarkerExists as af, withFileLock as ag, describeMisconfiguration as ah, buildMachineDeps as ai, applyClaudeProxyEnv as aj, composeSessionId as ak, generateFriendlyName as al, generateHookSettings as am, instanceConfig as an, frpc as ao, staticFileServer as ap, claudeAuth as aq, codexProvider as ar, projectInfo as as, DefaultTransport$1 as at, acpBackend as au, acpAgentConfig as av, codexAppServerBackend as aw, GeminiTransport$1 as ax, KimiTransport$1 as ay, kimiProvider as az, stopDaemon as b, connectToHypha as c, daemonStatus as d, shortId as e, resolveProjectRoot as f, getHyphaServerUrl$1 as g, getIssue as h, resumeIssue as i, addComment as j, addIssue as k, listIssues as l, isPendingIssue as m, searchIssues as n, isVisibleTo as o, pauseIssue as p, getRun as q, registerMachineService as r, startDaemon as s, listRuns as t, updateIssue as u, getWorkflow as v, runWorkflow as w, setWorkflowEnabled as x, removeWorkflow as y, validateWorkflowName as z };
25574
+ export { downloadSkillFile as $, validateWorkflowName as A, saveWorkflow as B, rawWorkflow as C, listWorkflows as D, isWorkflowEnabled as E, workflowSchedules as F, inZone as G, cronMatches as H, summarize as I, workflowSteps as J, parseJwtEmail as K, computeCollectionConfigUpdate as L, SYSTEM_COLLECTION_CONFIG as M, loadMachineContext as N, buildMachineInstructions as O, machineToolsForRole as P, buildMachineTools as Q, READ_ONLY_TOOLS as R, SharingNotificationSync as S, parseFrontmatter as T, getSkillsServer as U, getSkillsWorkspaceName as V, getSkillsCollectionName as W, fetchWithTimeout as X, searchSkills as Y, SKILLS_DIR as Z, getSkillInfo as _, createSessionStore as a, listSkillFiles as a0, resolveModel as a1, formatHandle as a2, normalizeAllowedUser as a3, loadSecurityContextConfig as a4, resolveSecurityContext as a5, buildSecurityContextFromFlags as a6, mergeSecurityContexts as a7, buildSessionShareUrl as a8, computeOutboundHop as a9, kimiProvider as aA, kimiSetup as aB, api as aC, supervisorLock as aD, run as aE, registerAwaitingReply as aa, buildMachineShareUrl as ab, parseHandle as ac, handleMatchesMetadata as ad, PINNED_CODEX_VERSION as ae, clearStopMarker as af, stopMarkerExists as ag, withFileLock as ah, describeMisconfiguration as ai, buildMachineDeps as aj, applyClaudeProxyEnv as ak, composeSessionId as al, generateFriendlyName as am, generateHookSettings as an, instanceConfig as ao, frpc as ap, staticFileServer as aq, claudeAuth as ar, codexProvider as as, projectInfo as at, DefaultTransport$1 as au, acpBackend as av, acpAgentConfig as aw, codexAppServerBackend as ax, GeminiTransport$1 as ay, KimiTransport$1 as az, stopDaemon as b, connectToHypha as c, daemonStatus as d, shortId as e, resolveProjectRoot as f, getHyphaServerUrl$1 as g, getIssue as h, resumeIssue as i, addComment as j, addIssue as k, listIssues as l, isPendingIssue as m, searchIssues as n, isVisibleTo as o, pauseIssue as p, getRun as q, registerMachineService as r, startDaemon as s, listRuns as t, updateIssue as u, getWorkflow as v, runWorkflow as w, setWorkflowEnabled as x, removeWorkflow as y, validateCronExpr as z };
@@ -1,4 +1,4 @@
1
- import { f as resolveProjectRoot, C as listWorkflows, D as isWorkflowEnabled, E as workflowSchedules, F as inZone, w as runWorkflow, G as cronMatches } from './run-CSV6OgQ8.mjs';
1
+ import { f as resolveProjectRoot, D as listWorkflows, E as isWorkflowEnabled, F as workflowSchedules, G as inZone, w as runWorkflow, H as cronMatches } from './run-ON_xcuFF.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -1,6 +1,6 @@
1
1
  import * as path from 'path';
2
- import { w as wantsHelp } from './cli-BCN1uAze.mjs';
3
- import './run-CSV6OgQ8.mjs';
2
+ import { w as wantsHelp } from './cli-CZ4D7AII.mjs';
3
+ import './run-ON_xcuFF.mjs';
4
4
  import 'os';
5
5
  import 'fs/promises';
6
6
  import 'fs';
@@ -77,7 +77,7 @@ async function handleServeCommand() {
77
77
  }
78
78
  }
79
79
  async function serveAdd(args, machineId) {
80
- const { connectAndGetMachine } = await import('./commands-DEZLlXJ3.mjs');
80
+ const { connectAndGetMachine } = await import('./commands-BOBRaVaF.mjs');
81
81
  const pos = positionalArgs(args);
82
82
  const name = pos[0];
83
83
  if (!name) {
@@ -110,7 +110,7 @@ async function serveAdd(args, machineId) {
110
110
  }
111
111
  if (sessionId && result?.url) {
112
112
  try {
113
- const { autoAddSessionLink } = await import('./agentCommands-DefL1pIo.mjs');
113
+ const { autoAddSessionLink } = await import('./agentCommands-CDj6yTgX.mjs');
114
114
  autoAddSessionLink(String(result.url), name, void 0, { kind: "serve", name });
115
115
  } catch {
116
116
  }
@@ -124,7 +124,7 @@ async function serveAdd(args, machineId) {
124
124
  }
125
125
  }
126
126
  async function serveApply(args, machineId) {
127
- const { connectAndGetMachine } = await import('./commands-DEZLlXJ3.mjs');
127
+ const { connectAndGetMachine } = await import('./commands-BOBRaVaF.mjs');
128
128
  const fs = await import('fs');
129
129
  const yaml = await import('yaml');
130
130
  const file = positionalArgs(args)[0];
@@ -209,7 +209,7 @@ async function serveApply(args, machineId) {
209
209
  console.log(`URL: ${result.url}`);
210
210
  if (params.sessionId && result?.url) {
211
211
  try {
212
- const { autoAddSessionLink } = await import('./agentCommands-DefL1pIo.mjs');
212
+ const { autoAddSessionLink } = await import('./agentCommands-CDj6yTgX.mjs');
213
213
  const prevSession = process.env.SVAMP_SESSION_ID;
214
214
  process.env.SVAMP_SESSION_ID = String(params.sessionId);
215
215
  try {
@@ -230,7 +230,7 @@ async function serveApply(args, machineId) {
230
230
  }
231
231
  }
232
232
  async function serveRemove(args, machineId) {
233
- const { connectAndGetMachine } = await import('./commands-DEZLlXJ3.mjs');
233
+ const { connectAndGetMachine } = await import('./commands-BOBRaVaF.mjs');
234
234
  const pos = positionalArgs(args);
235
235
  const name = pos[0];
236
236
  if (!name) {
@@ -240,7 +240,7 @@ async function serveRemove(args, machineId) {
240
240
  const { machine, server } = await connectAndGetMachine(machineId);
241
241
  try {
242
242
  await machine.serveRemove({ name });
243
- const { removeSessionLinkByService } = await import('./agentCommands-DefL1pIo.mjs');
243
+ const { removeSessionLinkByService } = await import('./agentCommands-CDj6yTgX.mjs');
244
244
  removeSessionLinkByService("serve", name);
245
245
  console.log(`Mount '${name}' removed.`);
246
246
  } catch (err) {
@@ -252,7 +252,7 @@ async function serveRemove(args, machineId) {
252
252
  }
253
253
  }
254
254
  async function serveList(args, machineId) {
255
- const { connectAndGetMachine } = await import('./commands-DEZLlXJ3.mjs');
255
+ const { connectAndGetMachine } = await import('./commands-BOBRaVaF.mjs');
256
256
  const all = hasFlag(args, "--all", "-a");
257
257
  const json = hasFlag(args, "--json");
258
258
  const sessionId = getFlag(args, "--session");
@@ -286,7 +286,7 @@ async function serveList(args, machineId) {
286
286
  }
287
287
  }
288
288
  async function serveInfo(machineId) {
289
- const { connectAndGetMachine } = await import('./commands-DEZLlXJ3.mjs');
289
+ const { connectAndGetMachine } = await import('./commands-BOBRaVaF.mjs');
290
290
  const { machine, server } = await connectAndGetMachine(machineId);
291
291
  try {
292
292
  const info = await machine.serveInfo();
@@ -1,4 +1,4 @@
1
- import { R as READ_ONLY_TOOLS, M as loadMachineContext, N as buildMachineInstructions, O as machineToolsForRole, P as buildMachineTools } from './run-CSV6OgQ8.mjs';
1
+ import { R as READ_ONLY_TOOLS, N as loadMachineContext, O as buildMachineInstructions, P as machineToolsForRole, Q as buildMachineTools } from './run-ON_xcuFF.mjs';
2
2
  import 'node:child_process';
3
3
  import 'os';
4
4
  import 'fs/promises';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.328",
3
+ "version": "0.2.330",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -20,13 +20,13 @@
20
20
  "scripts": {
21
21
  "build": "rm -rf dist bin/skills bin/commands && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && cp -r ../../skills/crew bin/skills/crew && cp -r ../../commands bin/commands && tsc --noEmit && pkgroll",
22
22
  "typecheck": "tsc --noEmit",
23
- "test": "node test/with-timeout.mjs 420 npx tsx test/test-context-window.mjs && node test/with-timeout.mjs 420 npx tsx test/test-ratelimit-retry.mjs && node test/with-timeout.mjs 420 npx tsx test/test-completed-requests.mjs && node test/with-timeout.mjs 420 npx tsx test/test-reconnect-health.mjs &&node test/with-timeout.mjs 420 npx tsx test/test-instance-config.mjs && node test/with-timeout.mjs 420 npx tsx test/test-authorize.mjs && node test/with-timeout.mjs 420 npx tsx test/test-normalize-allowed-user.mjs && node test/with-timeout.mjs 420 npx tsx test/test-share-url.mjs && node test/with-timeout.mjs 420 npx tsx test/test-update-sharing-normalization.mjs && node test/with-timeout.mjs 420 npx tsx test/test-sharing-notify-sync.mjs && node test/with-timeout.mjs 420 npx tsx test/test-sharing-notify-resolve.mjs && node test/with-timeout.mjs 420 npx tsx test/test-staged-homes-sweep.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-helpers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-cli-routing.mjs && node test/with-timeout.mjs 420 npx tsx test/test-security-context.mjs && node test/with-timeout.mjs 420 npx tsx test/test-isolation-decision.mjs && node test/with-timeout.mjs 420 npx tsx test/test-message-helpers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-stdin-delivery.mjs && node test/with-timeout.mjs 420 npx tsx test/test-agent-config.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wrap-command.mjs && node test/with-timeout.mjs 420 npx tsx test/test-credential-staging.mjs && node test/with-timeout.mjs 420 npx tsx test/test-claude-auth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-backend-accounts.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-force-model.mjs && node test/with-timeout.mjs 420 npx tsx test/test-backend-oauth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-btw-proxy-env.mjs && node test/with-timeout.mjs 420 npx tsx test/test-output-formatters.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-guard.mjs && node test/with-timeout.mjs 420 npx tsx test/test-user-events.mjs && node test/with-timeout.mjs 420 npx tsx test/test-migrate-children.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-install.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-setup.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-pairing.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-coordinator.mjs && node test/with-timeout.mjs 420 npx tsx test/e2e-outpost-transport.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-reconcile.mjs && node test/with-timeout.mjs 420 npx tsx test/test-auto-topic.mjs && node test/with-timeout.mjs 420 npx tsx test/test-project-info.mjs && node test/with-timeout.mjs 420 npx tsx test/test-agent-types.mjs && node test/with-timeout.mjs 420 npx tsx test/test-transport.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-update-handlers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-scanner.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hypha-client.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hook-settings.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-service-logic.mjs && node test/with-timeout.mjs 420 npx tsx test/test-daemon-persistence.mjs && node test/with-timeout.mjs 420 npx tsx test/test-detect-isolation.mjs && node test/with-timeout.mjs 420 npx tsx test/test-isolation-disable.mjs && node test/with-timeout.mjs 420 npx tsx test/test-machine-service-logic.mjs && node test/with-timeout.mjs 420 npx tsx test/test-machine-session-visibility.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-access-fallback.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-rpc-role-map.mjs && node test/with-timeout.mjs 420 npx tsx test/test-interactive-helpers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-pinned-codex.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-request-timeout.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-app-server.mjs && node test/with-timeout.mjs 420 npx tsx test/test-kimi-provider.mjs && node test/with-timeout.mjs 420 npx tsx test/test-acp-backend.mjs && node test/with-timeout.mjs 420 npx tsx test/test-acp-bridge.mjs && node test/with-timeout.mjs 420 npx tsx test/test-listener-backoff.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-identity-env.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hook-server.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-commands.mjs && node test/with-timeout.mjs 420 npx tsx test/test-interactive-console.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-messages.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-send-query.mjs && node test/with-timeout.mjs 420 npx tsx test/test-skills.mjs && node test/with-timeout.mjs 420 npx tsx test/test-agent-grouping.mjs && node test/with-timeout.mjs 420 npx tsx test/test-machine-list-directory.mjs && node test/with-timeout.mjs 420 npx tsx test/test-service-commands.mjs && node test/with-timeout.mjs 420 npx tsx test/test-supervisor.mjs && node test/with-timeout.mjs 420 npx tsx test/test-supervisor-lock.mjs && node test/with-timeout.mjs 420 node test/test-supervisor-restart.mjs && node test/with-timeout.mjs 420 npx tsx test/test-clear-detection.mjs && node test/with-timeout.mjs 420 npx tsx test/test-compact-detect.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-consolidation.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-store.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-cross-machine.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-store.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-store-lock.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-close-gate.mjs && node test/with-timeout.mjs 420 npx tsx test/test-loop-verify.mjs && node test/with-timeout.mjs 420 npx tsx test/test-restore-decision.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-rpc.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-pause.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-store.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-rpc.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-scheduler.mjs && node test/with-timeout.mjs 420 npx tsx test/test-cron.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-runs.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-runs-lock.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-idle.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-reconcile.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-link-subdomain.mjs && node test/with-timeout.mjs 420 npx tsx test/test-short-id.mjs && node test/with-timeout.mjs 420 npx tsx test/test-transcript-edit.mjs && node test/with-timeout.mjs 420 npx tsx test/test-edit-history.mjs && node test/with-timeout.mjs 420 npx tsx test/test-friendly-name.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-rpc-dispatch.mjs && node test/with-timeout.mjs 420 npx tsx test/test-sandbox-cli.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-manager.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-files-gateway.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-ws-upgrade.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-auth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-static-file-server.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-stability.mjs && node test/with-timeout.mjs 420 npx tsx test/test-frpc-e2e.mjs --unit-only && node test/with-timeout.mjs 420 npx tsx test/test-frpc-status.mjs && node test/with-timeout.mjs 420 npx tsx test/test-frpc-orphan-reap.mjs && node test/with-timeout.mjs 420 node test/pinnedClaudeCode.test.mjs && node test/with-timeout.mjs 420 node test/fleet.test.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-file.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-rpc.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-agent.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-agent.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channels-service.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hotreload-seam.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hot-reload.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hot-reload-live.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-core.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-async-reply.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outbox-reload.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-binding.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-store-lock.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-identity.mjs && node test/with-timeout.mjs 420 npx tsx test/test-stateless-dispatch-limiter.mjs && node test/with-timeout.mjs 420 npx tsx test/test-shared-session-identity.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-agent-auth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-http.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-upload.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-file-access.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-voice.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-headless.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-machine.mjs && node test/with-timeout.mjs 420 npx tsx test/test-crew-merge.mjs && node test/with-timeout.mjs 420 npx tsx test/test-crew-verdict-routing.mjs && node test/with-timeout.mjs 420 npx tsx test/test-crew-standalone.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-links.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-loop-pause-guard.mjs && node test/with-timeout.mjs 420 npx tsx test/test-artifact-guard.mjs && node test/with-timeout.mjs 420 npx tsx test/test-artifact-sync-pagination.mjs && node test/with-timeout.mjs 420 npx tsx test/test-graceful-restart.mjs && node test/with-timeout.mjs 420 npx tsx test/test-flush-exit.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-skills.mjs && node test/with-timeout.mjs 420 npx tsx test/test-nightly-0807-fixes.mjs && node test/with-timeout.mjs 420 npx tsx test/test-nightly-0814-fixes.mjs && node test/with-timeout.mjs 420 npx tsx test/test-log-prune.mjs && node test/with-timeout.mjs 420 node test/test-message-count-cache.mjs && node test/with-timeout.mjs 420 node test/test-serve-link-gate.mjs && node test/with-timeout.mjs 420 node test/test-security-context-unenforceable.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-id-resolution.mjs && node test/with-timeout.mjs 420 npx tsx test/test-help-flag-never-acts.mjs && node test/with-timeout.mjs 420 npx tsx test/test-with-timeout.mjs && node test/with-timeout.mjs 420 npx tsx test/test-message-queue-cap.mjs",
23
+ "test": "node test/with-timeout.mjs 420 npx tsx test/test-context-window.mjs && node test/with-timeout.mjs 420 npx tsx test/test-ratelimit-retry.mjs && node test/with-timeout.mjs 420 npx tsx test/test-completed-requests.mjs && node test/with-timeout.mjs 420 npx tsx test/test-reconnect-health.mjs &&node test/with-timeout.mjs 420 npx tsx test/test-fleet-version-parse.mjs &&node test/with-timeout.mjs 420 npx tsx test/test-instance-config.mjs && node test/with-timeout.mjs 420 npx tsx test/test-authorize.mjs && node test/with-timeout.mjs 420 npx tsx test/test-normalize-allowed-user.mjs && node test/with-timeout.mjs 420 npx tsx test/test-share-url.mjs && node test/with-timeout.mjs 420 npx tsx test/test-update-sharing-normalization.mjs && node test/with-timeout.mjs 420 npx tsx test/test-sharing-notify-sync.mjs && node test/with-timeout.mjs 420 npx tsx test/test-sharing-notify-resolve.mjs && node test/with-timeout.mjs 420 npx tsx test/test-staged-homes-sweep.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-helpers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-cli-routing.mjs && node test/with-timeout.mjs 420 npx tsx test/test-security-context.mjs && node test/with-timeout.mjs 420 npx tsx test/test-isolation-decision.mjs && node test/with-timeout.mjs 420 npx tsx test/test-message-helpers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-stdin-delivery.mjs && node test/with-timeout.mjs 420 npx tsx test/test-agent-config.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wrap-command.mjs && node test/with-timeout.mjs 420 npx tsx test/test-credential-staging.mjs && node test/with-timeout.mjs 420 npx tsx test/test-claude-auth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-backend-accounts.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-force-model.mjs && node test/with-timeout.mjs 420 npx tsx test/test-backend-oauth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-btw-proxy-env.mjs && node test/with-timeout.mjs 420 npx tsx test/test-output-formatters.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-guard.mjs && node test/with-timeout.mjs 420 npx tsx test/test-user-events.mjs && node test/with-timeout.mjs 420 npx tsx test/test-migrate-children.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-install.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-setup.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-pairing.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outpost-coordinator.mjs && node test/with-timeout.mjs 420 npx tsx test/e2e-outpost-transport.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-reconcile.mjs && node test/with-timeout.mjs 420 npx tsx test/test-auto-topic.mjs && node test/with-timeout.mjs 420 npx tsx test/test-project-info.mjs && node test/with-timeout.mjs 420 npx tsx test/test-agent-types.mjs && node test/with-timeout.mjs 420 npx tsx test/test-transport.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-update-handlers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-scanner.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hypha-client.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hook-settings.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-service-logic.mjs && node test/with-timeout.mjs 420 npx tsx test/test-daemon-persistence.mjs && node test/with-timeout.mjs 420 npx tsx test/test-detect-isolation.mjs && node test/with-timeout.mjs 420 npx tsx test/test-isolation-disable.mjs && node test/with-timeout.mjs 420 npx tsx test/test-machine-service-logic.mjs && node test/with-timeout.mjs 420 npx tsx test/test-machine-session-visibility.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-access-fallback.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-rpc-role-map.mjs && node test/with-timeout.mjs 420 npx tsx test/test-interactive-helpers.mjs && node test/with-timeout.mjs 420 npx tsx test/test-pinned-codex.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-request-timeout.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-app-server.mjs && node test/with-timeout.mjs 420 npx tsx test/test-kimi-provider.mjs && node test/with-timeout.mjs 420 npx tsx test/test-acp-backend.mjs && node test/with-timeout.mjs 420 npx tsx test/test-acp-bridge.mjs && node test/with-timeout.mjs 420 npx tsx test/test-listener-backoff.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-identity-env.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hook-server.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-commands.mjs && node test/with-timeout.mjs 420 npx tsx test/test-interactive-console.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-messages.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-send-query.mjs && node test/with-timeout.mjs 420 npx tsx test/test-skills.mjs && node test/with-timeout.mjs 420 npx tsx test/test-agent-grouping.mjs && node test/with-timeout.mjs 420 npx tsx test/test-machine-list-directory.mjs && node test/with-timeout.mjs 420 npx tsx test/test-service-commands.mjs && node test/with-timeout.mjs 420 npx tsx test/test-supervisor.mjs && node test/with-timeout.mjs 420 npx tsx test/test-supervisor-lock.mjs && node test/with-timeout.mjs 420 node test/test-supervisor-restart.mjs && node test/with-timeout.mjs 420 npx tsx test/test-clear-detection.mjs && node test/with-timeout.mjs 420 npx tsx test/test-compact-detect.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-consolidation.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-store.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox.mjs && node test/with-timeout.mjs 420 npx tsx test/test-inbox-cross-machine.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-store.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-store-lock.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-close-gate.mjs && node test/with-timeout.mjs 420 npx tsx test/test-loop-verify.mjs && node test/with-timeout.mjs 420 npx tsx test/test-restore-decision.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-rpc.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-pause.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-store.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-rpc.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-scheduler.mjs && node test/with-timeout.mjs 420 npx tsx test/test-cron.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-runs.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-runs-lock.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-idle.mjs && node test/with-timeout.mjs 420 npx tsx test/test-workflow-reconcile.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-link-subdomain.mjs && node test/with-timeout.mjs 420 npx tsx test/test-short-id.mjs && node test/with-timeout.mjs 420 npx tsx test/test-transcript-edit.mjs && node test/with-timeout.mjs 420 npx tsx test/test-edit-history.mjs && node test/with-timeout.mjs 420 npx tsx test/test-friendly-name.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-rpc-dispatch.mjs && node test/with-timeout.mjs 420 npx tsx test/test-sandbox-cli.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-manager.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-files-gateway.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-ws-upgrade.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-auth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-static-file-server.mjs && node test/with-timeout.mjs 420 npx tsx test/test-serve-stability.mjs && node test/with-timeout.mjs 420 npx tsx test/test-frpc-e2e.mjs --unit-only && node test/with-timeout.mjs 420 npx tsx test/test-frpc-status.mjs && node test/with-timeout.mjs 420 npx tsx test/test-frpc-orphan-reap.mjs && node test/with-timeout.mjs 420 node test/pinnedClaudeCode.test.mjs && node test/with-timeout.mjs 420 node test/fleet.test.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-file.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-rpc.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-agent.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-agent.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channels-service.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hotreload-seam.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hot-reload.mjs && node test/with-timeout.mjs 420 npx tsx test/test-hot-reload-live.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-core.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-async-reply.mjs && node test/with-timeout.mjs 420 npx tsx test/test-outbox-reload.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-binding.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-store-lock.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-identity.mjs && node test/with-timeout.mjs 420 npx tsx test/test-stateless-dispatch-limiter.mjs && node test/with-timeout.mjs 420 npx tsx test/test-shared-session-identity.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-agent-auth.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-http.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-upload.mjs && node test/with-timeout.mjs 420 npx tsx test/test-channel-file-access.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-voice.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-headless.mjs && node test/with-timeout.mjs 420 npx tsx test/test-wise-machine.mjs && node test/with-timeout.mjs 420 npx tsx test/test-crew-merge.mjs && node test/with-timeout.mjs 420 npx tsx test/test-crew-verdict-routing.mjs && node test/with-timeout.mjs 420 npx tsx test/test-crew-standalone.mjs && node test/with-timeout.mjs 420 npx tsx test/test-session-links.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-loop-pause-guard.mjs && node test/with-timeout.mjs 420 npx tsx test/test-artifact-guard.mjs && node test/with-timeout.mjs 420 npx tsx test/test-artifact-sync-pagination.mjs && node test/with-timeout.mjs 420 npx tsx test/test-graceful-restart.mjs && node test/with-timeout.mjs 420 npx tsx test/test-flush-exit.mjs && node test/with-timeout.mjs 420 npx tsx test/test-codex-skills.mjs && node test/with-timeout.mjs 420 npx tsx test/test-nightly-0807-fixes.mjs && node test/with-timeout.mjs 420 npx tsx test/test-nightly-0814-fixes.mjs && node test/with-timeout.mjs 420 npx tsx test/test-log-prune.mjs && node test/with-timeout.mjs 420 node test/test-message-count-cache.mjs && node test/with-timeout.mjs 420 node test/test-serve-link-gate.mjs && node test/with-timeout.mjs 420 node test/test-security-context-unenforceable.mjs && node test/with-timeout.mjs 420 npx tsx test/test-issue-id-resolution.mjs && node test/with-timeout.mjs 420 npx tsx test/test-help-flag-never-acts.mjs && node test/with-timeout.mjs 420 npx tsx test/test-with-timeout.mjs && node test/with-timeout.mjs 420 npx tsx test/test-message-queue-cap.mjs && node test/with-timeout.mjs 420 npx tsx test/test-compaction-backstop.mjs",
24
24
  "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
25
25
  "dev": "tsx src/cli.ts",
26
26
  "dev:daemon": "tsx src/cli.ts daemon start-sync",
27
27
  "test:e2e": "node --no-warnings test/e2e-session-tests.mjs && npx tsx test/e2e-codex-midturn-steer.mjs && npx tsx test/e2e-serve-iframe-login.mjs && npx tsx test/test-archive-preserves-claude-file.mjs && npx tsx test/test-daemon-e2e.mjs && npx tsx test/test-hypha-service.mjs && npx tsx test/test-permission-e2e.mjs && npx tsx test/test-serve-e2e.mjs && npx tsx test/test-session-archive-resume.mjs && npx tsx test/test-session-rpc-e2e.mjs && npx tsx test/test-skills-integration.mjs && npx tsx test/test-wm-refresh.mjs && npx tsx test/e2e-session-files-gateway.mjs && npx tsx test/e2e-dns-production-hosts.mjs",
28
28
  "test:frpc": "npx tsx test/test-frpc-e2e.mjs",
29
- "prepublishOnly": "node ../../scripts/bump-cli-version.mjs --check && yarn build"
29
+ "prepublishOnly": "node ../../scripts/bump-cli-version.mjs --check && yarn build && yarn test"
30
30
  },
31
31
  "dependencies": {
32
32
  "@agentclientprotocol/sdk": "^0.14.1",