very-happy-cli 0.2.90 → 0.2.92

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 (31) hide show
  1. package/dist/{AcpBackend-CnYZFdd0.cjs → AcpBackend-BP7id8L6.cjs} +1 -1
  2. package/dist/{AcpBackend-BV4wSnJ3.mjs → AcpBackend-DDEsgc1c.mjs} +1 -1
  3. package/dist/{AcpSessionManager-Cyne6Rmg.mjs → AcpSessionManager-C29t6wb_.mjs} +1 -1
  4. package/dist/{AcpSessionManager-BPBdrrME.cjs → AcpSessionManager-Cys1Hsb8.cjs} +1 -1
  5. package/dist/{config-CgXitj0f.cjs → config-B77vhdwT.cjs} +2 -2
  6. package/dist/{config-BEdyyciP.mjs → config-CJQw0z1o.mjs} +2 -2
  7. package/dist/{index-an09rejO.mjs → index-8LDXVYWi.mjs} +409 -51
  8. package/dist/{index-4YmVbx7j.cjs → index-B63Vjt4W.cjs} +425 -67
  9. package/dist/{index-Dfu5uvjk.mjs → index-BP9pfzdZ.mjs} +5 -5
  10. package/dist/{index-B1wTVXjt.cjs → index-L3o5Gz-2.cjs} +4 -4
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/{installTerminalHooks-DDpVxk8-.cjs → installTerminalHooks-BBc2nij4.cjs} +2 -2
  14. package/dist/{installTerminalHooks-C-OgZr5k.mjs → installTerminalHooks-DDRrUG_n.mjs} +2 -2
  15. package/dist/lib.cjs +1 -1
  16. package/dist/lib.d.cts +103 -3
  17. package/dist/lib.d.mts +103 -3
  18. package/dist/lib.mjs +1 -1
  19. package/dist/{mcp-Du-N0qlK.mjs → mcp-CYJAl5pk.mjs} +2 -2
  20. package/dist/{mcp-B6Nq-RUL.cjs → mcp-DbYXyw1U.cjs} +2 -2
  21. package/dist/{runGemini-ChG7cGMC.cjs → runGemini-BDSWSID6.cjs} +4 -4
  22. package/dist/{runGemini-DBr_TiTL.mjs → runGemini-DHYs_Beq.mjs} +4 -4
  23. package/dist/{runOpenClaw-D2jtVgpC.cjs → runOpenClaw-DC9gb1bd.cjs} +3 -3
  24. package/dist/{runOpenClaw-Cbde8t92.mjs → runOpenClaw-DTaXxvNd.mjs} +3 -3
  25. package/dist/{send-Bjen1TUE.cjs → send-BEdGwmA-.cjs} +2 -2
  26. package/dist/{send-BHliX59m.mjs → send-BQSaVz9r.mjs} +2 -2
  27. package/dist/{spawn-CH1Rq-LW.cjs → spawn-CK1ma_qc.cjs} +2 -2
  28. package/dist/{spawn-JxaPHAoP.mjs → spawn-DS-Uz_Hw.mjs} +2 -2
  29. package/dist/{types-DS3i_5LV.mjs → types-B_8X_rZk.mjs} +572 -93
  30. package/dist/{types-BNGeiP1C.cjs → types-CjlB_fKT.cjs} +573 -93
  31. package/package.json +7 -7
@@ -1,7 +1,7 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
2
  import os, { homedir } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
4
- import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, v as ensurePrivateDirectory, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, x as hardenPrivateFile, f as packageJson, i as readSettings, y as readCredentials, z as credentialRelayProblem, B as deriveLocalCliUpdateSummary, j as encodeBase64, C as updateSettings, D as encodeBase64Url, E as decodeBase64, F as writeCredentialsLegacy, G as writeCredentialsDataKey, H as readCredentialsForConfiguredRelay, J as encrypt, r as readPersistedSessions, K as getLocalHappyAgentCredentialPath, L as readLocalHappyAgentCredentials, N as decryptWithDataKey, O as decryptLegacy, P as extractCompleteLines, Q as decideBackfill, S as parseTerminalHookPayload, T as tmuxArgs, U as scrubTmuxClientEnv, V as decideMirrorBinding, W as persistSession, X as MIRROR_BACKFILL_LINES_DEFAULT, Y as mirrorLineKey, Z as mirrorLocalId, _ as detectResumeSupport, $ as detectCLIAvailability, a0 as acquireDaemonLock, a1 as summarizeSpawnSessionForLog, a2 as deletePersistedSessions, a3 as decrypt, a4 as writeDaemonState, A as ApiClient, a5 as fetchCliUpdateState, a6 as resolveCliUpdateCheckInterval, a7 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a8 as releaseDaemonLock, a9 as isValidSessionId, aa as listVhTerminals, ab as isValidTerminalId, ac as readVhTerminal, ad as sendToVhTerminal, h as connectionState, ae as startOfflineReconnection, af as clearCredentials, ag as clearMachineId, k as ensurePrivateDirectorySync, w as writePrivateFileSync, ah as SandboxConfigSchema, b as createEnvelope, ai as CodexAppServerClient, aj as getLatestDaemonLog } from './types-DS3i_5LV.mjs';
4
+ import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, v as ensurePrivateDirectory, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, x as hardenPrivateFile, f as packageJson, i as readSettings, y as readCredentials, z as credentialRelayProblem, B as deriveLocalCliUpdateSummary, j as encodeBase64, C as updateSettings, D as encodeBase64Url, E as decodeBase64, F as writeCredentialsLegacy, G as writeCredentialsDataKey, H as readCredentialsForConfiguredRelay, J as encrypt, r as readPersistedSessions, K as isClaudeSessionId, L as getLocalHappyAgentCredentialPath, N as readLocalHappyAgentCredentials, O as decryptWithDataKey, P as decryptLegacy, Q as extractCompleteLines, S as decideBackfill, T as parseTerminalHookPayload, U as tmuxArgs, V as scrubTmuxClientEnv, W as decideMirrorBinding, X as persistSession, Y as MIRROR_BACKFILL_LINES_DEFAULT, Z as mirrorLineKey, _ as mirrorLocalId, $ as detectResumeSupport, a0 as detectCLIAvailability, a1 as acquireDaemonLock, a2 as summarizeSpawnSessionForLog, a3 as deletePersistedSessions, a4 as decrypt, a5 as writeDaemonState, A as ApiClient, a6 as fetchCliUpdateState, a7 as resolveCliUpdateCheckInterval, a8 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a9 as releaseDaemonLock, aa as isValidSessionId, ab as listVhTerminals, ac as isValidTerminalId, ad as readVhTerminal, ae as sendToVhTerminal, h as connectionState, af as startOfflineReconnection, ag as clearCredentials, ah as clearMachineId, k as ensurePrivateDirectorySync, w as writePrivateFileSync, ai as SandboxConfigSchema, b as createEnvelope, aj as CodexAppServerClient, ak as getLatestDaemonLog } from './types-B_8X_rZk.mjs';
5
5
  import spawn$1, { spawn } from 'cross-spawn';
6
6
  import path, { join, resolve, basename, isAbsolute, normalize, sep, dirname } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
@@ -42,6 +42,56 @@ import inquirer from 'inquirer';
42
42
  import { fileURLToPath } from 'node:url';
43
43
  import { createInterface as createInterface$1 } from 'node:readline/promises';
44
44
 
45
+ const PROCESS_IDENTITY_FIELDS = [
46
+ "hostPid",
47
+ "version",
48
+ "startedBy",
49
+ "startedFromDaemon",
50
+ "happyHomeDir",
51
+ "happyLibDir",
52
+ "happyToolsDir",
53
+ "capabilities",
54
+ "attachmentKinds",
55
+ "queueCancellation",
56
+ "sandbox",
57
+ "dangerouslySkipPermissions",
58
+ "os",
59
+ "host",
60
+ "homeDir",
61
+ "permissionMode"
62
+ ];
63
+ function processIdentityFields(local) {
64
+ const out = {};
65
+ for (const key of PROCESS_IDENTITY_FIELDS) {
66
+ const value = local[key];
67
+ if (value !== void 0) out[key] = value;
68
+ }
69
+ return out;
70
+ }
71
+ function mergeReconnectMetadata(server, local, now) {
72
+ return {
73
+ ...server,
74
+ ...processIdentityFields(local),
75
+ lifecycleState: "running",
76
+ lifecycleStateSince: now,
77
+ archivedBy: void 0,
78
+ archiveReason: void 0
79
+ };
80
+ }
81
+ function applyServerSnapshot(response, snapshot) {
82
+ return {
83
+ ...response,
84
+ seq: snapshot.seq,
85
+ metadata: snapshot.metadata,
86
+ metadataVersion: snapshot.metadataVersion,
87
+ agentState: snapshot.agentState,
88
+ agentStateVersion: snapshot.agentStateVersion
89
+ };
90
+ }
91
+ function withoutServerSnapshot(response) {
92
+ return { ...response, metadataVersion: 0, agentStateVersion: 0 };
93
+ }
94
+
45
95
  function daemonControlHeaders(controlToken) {
46
96
  return {
47
97
  "Content-Type": "application/json",
@@ -1548,6 +1598,9 @@ function query(params) {
1548
1598
  if (opts?.mcpServers && Object.keys(opts.mcpServers).length > 0) {
1549
1599
  ensureLocalProxyBypass(env);
1550
1600
  }
1601
+ if (sdkOptions.allowDangerouslySkipPermissions && typeof process.getuid === "function" && process.getuid() === 0 && env.IS_SANDBOX === void 0) {
1602
+ env.IS_SANDBOX = "1";
1603
+ }
1551
1604
  sdkOptions.env = env;
1552
1605
  if (opts?.canCallTool) {
1553
1606
  const callback = opts.canCallTool;
@@ -1633,6 +1686,12 @@ function resolveRemoteClaudePermissionMode(currentMode, incomingMode, sandboxEna
1633
1686
  }
1634
1687
  return nextMode;
1635
1688
  }
1689
+ function reconcilePublishedPermissionMode(input) {
1690
+ if (!input.effective) return null;
1691
+ const mismatch = input.effective !== input.intent;
1692
+ if (input.effective === input.published) return mismatch ? { publish: input.effective, mismatch } : null;
1693
+ return { publish: input.effective, mismatch };
1694
+ }
1636
1695
 
1637
1696
  function parseCompact(message) {
1638
1697
  const trimmed = message.trim();
@@ -1962,7 +2021,12 @@ async function claudeRemote(opts) {
1962
2021
  mcpServers: systemInit.mcp_servers?.map((s) => ({ name: s.name, status: s.status })),
1963
2022
  skills: systemInit.skills,
1964
2023
  model: systemInit.model,
1965
- modelIsDefault: initial.mode.model == null
2024
+ modelIsDefault: initial.mode.model == null,
2025
+ // The SDK's own verdict on the mode it will enforce —
2026
+ // settings (permissions.deny/ask/defaultMode/
2027
+ // disableBypassPermissionsMode) can override what we
2028
+ // asked for. runClaude publishes THIS, not our intent.
2029
+ permissionMode: systemInit.permissionMode
1966
2030
  });
1967
2031
  }
1968
2032
  if (systemInit.session_id) {
@@ -1980,6 +2044,10 @@ async function claudeRemote(opts) {
1980
2044
  if (message.type === "result") {
1981
2045
  updateThinking(false);
1982
2046
  logger.debug("[claudeRemote] Result received");
2047
+ const denials = message.permission_denials;
2048
+ if (denials && denials.length > 0) {
2049
+ logger.warn(`[claudeRemote] ${denials.length} tool call(s) auto-denied by Claude Code policy: ${denials.map((d) => d.tool_name ?? "?").join(", ")}`);
2050
+ }
1983
2051
  if (isCompactCommand) {
1984
2052
  const compactSucceeded = message.subtype === "success";
1985
2053
  logger.debug(`[claudeRemote] Compaction ${compactSucceeded ? "completed" : "failed"}`);
@@ -2190,16 +2258,9 @@ class PermissionHandler {
2190
2258
  }
2191
2259
  } else {
2192
2260
  if (response.approved && response.mode) {
2193
- try {
2194
- if (!this.setPermissionModeCallback) throw new Error("permission mode updater unavailable");
2195
- await this.setPermissionModeCallback(response.mode);
2196
- this.permissionMode = response.mode;
2197
- this.onModeChangedCallback?.(response.mode);
2198
- } catch (err) {
2199
- const reason = `Failed to switch permission mode: ${err instanceof Error ? err.message : String(err)}`;
2200
- pending.resolve({ behavior: "deny", message: reason });
2201
- return { ...response, approved: false, reason };
2202
- }
2261
+ this.permissionMode = response.mode;
2262
+ this.deferredPermissionMode = response.mode;
2263
+ this.onModeChangedCallback?.(response.mode);
2203
2264
  }
2204
2265
  if (response.approved && !pending.suggestions?.length && response.allowTools?.length) {
2205
2266
  response.allowTools.forEach((tool) => {
@@ -2540,6 +2601,17 @@ class PermissionHandler {
2540
2601
  }
2541
2602
  }
2542
2603
 
2604
+ function rewriteQueuedPermissionMode(queue, hasher, permissionMode) {
2605
+ let rewritten = 0;
2606
+ for (const item of queue) {
2607
+ if (item.mode.permissionMode === permissionMode) continue;
2608
+ item.mode = { ...item.mode, permissionMode };
2609
+ item.modeHash = hasher(item.mode);
2610
+ rewritten += 1;
2611
+ }
2612
+ return rewritten;
2613
+ }
2614
+
2543
2615
  function formatClaudeMessageForInk(message, messageBuffer, onAssistantResult) {
2544
2616
  logger.debugLargeJson("[CLAUDE INK] Message from remote mode:", message);
2545
2617
  switch (message.type) {
@@ -2794,7 +2866,13 @@ class SDKToLogConverter {
2794
2866
  type: "user",
2795
2867
  message: userMsg.message,
2796
2868
  ...userMsg.parent_tool_use_id ? { parent_tool_use_id: userMsg.parent_tool_use_id } : {},
2797
- ...meta ? { isMeta: true } : {}
2869
+ ...meta ? { isMeta: true } : {},
2870
+ // B-260-P2: structured tool output (Agent/Task final report +
2871
+ // run totals, or the `async_launched` stub marker) and the
2872
+ // message origin (task-notification). Both are consumed by
2873
+ // sessionProtocolMapper; the raw-line schema is passthrough.
2874
+ ...userMsg.tool_use_result !== void 0 ? { tool_use_result: userMsg.tool_use_result } : {},
2875
+ ...userMsg.origin ? { origin: userMsg.origin } : {}
2798
2876
  };
2799
2877
  if (Array.isArray(userMsg.message.content)) {
2800
2878
  for (const content of userMsg.message.content) {
@@ -3305,7 +3383,7 @@ function createTurnSteeringController() {
3305
3383
  };
3306
3384
  }
3307
3385
 
3308
- async function claudeRemoteLauncher(session, onPermissionModeChange) {
3386
+ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffectivePermissionMode) {
3309
3387
  logger.debug("[claudeRemoteLauncher] Starting remote launcher");
3310
3388
  const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
3311
3389
  logger.debug(`[claudeRemoteLauncher] TTY available: ${hasTTY}`);
@@ -3539,6 +3617,10 @@ async function claudeRemoteLauncher(session, onPermissionModeChange) {
3539
3617
  mode = { ...mode, permissionMode: nextMode };
3540
3618
  modeHash = session.queue.modeHasher(mode);
3541
3619
  }
3620
+ rewriteQueuedPermissionMode(session.queue.queue, session.queue.modeHasher, nextMode);
3621
+ if (pending) {
3622
+ pending = { ...pending, mode: { ...pending.mode, permissionMode: nextMode } };
3623
+ }
3542
3624
  onPermissionModeChange?.(nextMode);
3543
3625
  return nextMode;
3544
3626
  };
@@ -3611,6 +3693,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange) {
3611
3693
  skillCount: metadata.skills?.length ?? 0
3612
3694
  });
3613
3695
  session.client.updateMetadata((currentMetadata) => applyClaudeSdkMetadata(currentMetadata, metadata));
3696
+ if (metadata.permissionMode) onEffectivePermissionMode?.(metadata.permissionMode);
3614
3697
  },
3615
3698
  onQueryReady: (q) => {
3616
3699
  turnSteering.setInterrupt(q.interrupt);
@@ -3788,7 +3871,7 @@ async function loop(opts) {
3788
3871
  break;
3789
3872
  }
3790
3873
  case "remote": {
3791
- const reason = await claudeRemoteLauncher(session, opts.onPermissionModeChange);
3874
+ const reason = await claudeRemoteLauncher(session, opts.onPermissionModeChange, opts.onEffectivePermissionMode);
3792
3875
  switch (reason) {
3793
3876
  case "exit":
3794
3877
  return 0;
@@ -5263,6 +5346,45 @@ function sanitizeSpawnPermissionMode(value) {
5263
5346
  return ALLOWED_SPAWN_PERMISSION_MODES.includes(value) ? value : null;
5264
5347
  }
5265
5348
 
5349
+ function resumePrecheck(metadata, fs) {
5350
+ const flavor = metadata.flavor ?? "claude";
5351
+ if (flavor !== "claude" && flavor !== "codex") {
5352
+ return { ok: false, reason: "unsupported-flavor", detail: `flavor "${flavor}" cannot be resumed` };
5353
+ }
5354
+ if (!metadata.path || !fs.cwdExists(metadata.path)) {
5355
+ return { ok: false, reason: "missing-cwd", detail: `working directory ${metadata.path ?? "(none)"} does not exist` };
5356
+ }
5357
+ if (flavor === "codex") {
5358
+ if (!metadata.codexThreadId) return { ok: false, reason: "no-backend-id", detail: "session has no Codex thread id" };
5359
+ return { ok: true };
5360
+ }
5361
+ if (!isClaudeSessionId(metadata.claudeSessionId)) {
5362
+ return { ok: false, reason: "no-backend-id", detail: "session has no Claude session id" };
5363
+ }
5364
+ if (!fs.conversationExists(metadata.path, metadata.claudeSessionId)) {
5365
+ return { ok: false, reason: "conversation-missing", detail: `conversation ${metadata.claudeSessionId} is not on disk` };
5366
+ }
5367
+ return { ok: true };
5368
+ }
5369
+ function sanitizeResumeModel(value) {
5370
+ if (typeof value !== "string") return null;
5371
+ return /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(value) ? value : null;
5372
+ }
5373
+
5374
+ const DEFAULT_MAX_RESTARTS = 3;
5375
+ function decideRestart(priorAttempts, max = DEFAULT_MAX_RESTARTS) {
5376
+ if (priorAttempts >= max) {
5377
+ return {
5378
+ allowed: false,
5379
+ reason: `restart-limit: this session has already been restarted ${priorAttempts} time(s) this daemon session (max ${max}). Start a new session instead.`
5380
+ };
5381
+ }
5382
+ return { allowed: true, attempt: priorAttempts + 1 };
5383
+ }
5384
+ function recordRestartAttempt(priorAttempts) {
5385
+ return priorAttempts + 1;
5386
+ }
5387
+
5266
5388
  const CONTROL_TOKEN_BYTES = 32;
5267
5389
  function createDaemonControlToken() {
5268
5390
  return randomBytes(CONTROL_TOKEN_BYTES).toString("base64url");
@@ -7080,6 +7202,7 @@ async function startDaemon() {
7080
7202
  tracked.pid = livePid;
7081
7203
  tracked.startedBy = "recovered after daemon restart";
7082
7204
  pidToTrackedSession.set(livePid, tracked);
7205
+ persistSession(id, { ...s, savedAt: Date.now() });
7083
7206
  } else {
7084
7207
  sessionIdToFinishedSession.set(id, tracked);
7085
7208
  }
@@ -7508,6 +7631,13 @@ async function startDaemon() {
7508
7631
  const timeout = setTimeout(() => {
7509
7632
  pidToAwaiter.delete(happyProcess.pid);
7510
7633
  logger.debug(`[DAEMON RUN] Session webhook timeout for PID ${happyProcess.pid}`);
7634
+ if (happyProcess.pid) {
7635
+ try {
7636
+ terminateProcess(happyProcess.pid, () => {
7637
+ });
7638
+ } catch {
7639
+ }
7640
+ }
7511
7641
  resolve({
7512
7642
  type: "error",
7513
7643
  errorMessage: `Session webhook timeout for PID ${happyProcess.pid}`
@@ -7530,6 +7660,19 @@ async function startDaemon() {
7530
7660
  return sessionIdToFinishedSession.get(happySessionId);
7531
7661
  };
7532
7662
  const fetchServerSessionMetadata = async (sessionId, encryptionKey, encryptionVariant) => {
7663
+ try {
7664
+ const byId = await axios.get(`${configuration.serverUrl}/v1/sessions/${encodeURIComponent(sessionId)}`, {
7665
+ headers: { Authorization: `Bearer ${credentials.token}` },
7666
+ timeout: 1e4,
7667
+ validateStatus: (status) => status >= 200 && status < 300 || status === 404
7668
+ });
7669
+ if (byId.status !== 404) {
7670
+ const row = byId.data.session;
7671
+ if (row?.metadata) return decrypt(encryptionKey, encryptionVariant, decodeBase64(row.metadata));
7672
+ }
7673
+ } catch (error) {
7674
+ logger.debug(`[DAEMON RUN] by-id session metadata fetch failed, falling back to list: ${error instanceof Error ? error.message : error}`);
7675
+ }
7533
7676
  try {
7534
7677
  const response = await axios.get(`${configuration.serverUrl}/v1/sessions`, {
7535
7678
  headers: { Authorization: `Bearer ${credentials.token}` },
@@ -7545,17 +7688,38 @@ async function startDaemon() {
7545
7688
  return null;
7546
7689
  }
7547
7690
  };
7691
+ const resumeGates = /* @__PURE__ */ new Map();
7548
7692
  const resumeSession = async (happySessionId, options) => {
7693
+ let gate = resumeGates.get(happySessionId);
7694
+ if (!gate) {
7695
+ gate = createSpawnGate();
7696
+ resumeGates.set(happySessionId, gate);
7697
+ }
7698
+ try {
7699
+ return await gate.join(() => resumeSessionImpl(happySessionId, options));
7700
+ } finally {
7701
+ if (!gate.inFlight()) resumeGates.delete(happySessionId);
7702
+ }
7703
+ };
7704
+ const resumeSessionImpl = async (happySessionId, options) => {
7549
7705
  try {
7706
+ for (const [pid, live] of pidToTrackedSession.entries()) {
7707
+ if (live.happySessionId !== happySessionId) continue;
7708
+ if (isPidAlive(pid)) {
7709
+ logger.debug(`[DAEMON RUN] resume ${happySessionId}: process ${pid} already alive \u2014 idempotent success`);
7710
+ return { type: "success", sessionId: happySessionId };
7711
+ }
7712
+ onChildExited(pid);
7713
+ }
7550
7714
  const tracked = findTrackedSessionById(happySessionId);
7551
7715
  if (!tracked) {
7552
- return { type: "error", errorMessage: `Session ${happySessionId} is not tracked by this daemon. It may have been started before the daemon or on another machine.` };
7716
+ return { type: "error", errorMessage: `resume-precheck:not-tracked: Session ${happySessionId} is not tracked by this daemon. It may have been started before the daemon, more than 14 days ago, or on another machine.` };
7553
7717
  }
7554
7718
  if (!tracked.happySessionMetadataFromLocalWebhook) {
7555
- return { type: "error", errorMessage: `Session ${happySessionId} has no metadata. Cannot resume.` };
7719
+ return { type: "error", errorMessage: `resume-precheck:no-metadata: Session ${happySessionId} has no metadata. Cannot resume.` };
7556
7720
  }
7557
7721
  if (!tracked.encryption) {
7558
- return { type: "error", errorMessage: `Session ${happySessionId} has no stored encryption data. It was likely started before this feature was available. Restart the daemon and start a new session to enable resume.` };
7722
+ return { type: "error", errorMessage: `resume-precheck:no-encryption: Session ${happySessionId} has no stored encryption data. It was likely started before this feature was available. Restart the daemon and start a new session to enable resume.` };
7559
7723
  }
7560
7724
  let metadata = tracked.happySessionMetadataFromLocalWebhook;
7561
7725
  const needsFetch = !metadata.claudeSessionId && (!metadata.flavor || metadata.flavor === "claude") || !metadata.codexThreadId && metadata.flavor === "codex";
@@ -7567,18 +7731,24 @@ async function startDaemon() {
7567
7731
  tracked.happySessionMetadataFromLocalWebhook = serverMetadata;
7568
7732
  }
7569
7733
  }
7734
+ const precheck = resumePrecheck(metadata, {
7735
+ cwdExists: (p) => existsSync$1(p),
7736
+ conversationExists: (cwd, claudeSessionId) => existsSync$1(join$1(getProjectPath(cwd), `${claudeSessionId}.jsonl`))
7737
+ });
7738
+ if (!precheck.ok) {
7739
+ return { type: "error", errorMessage: `resume-precheck:${precheck.reason}: ${precheck.detail}` };
7740
+ }
7570
7741
  const launch = buildResumeLaunch(
7571
7742
  { id: happySessionId, active: true, metadata },
7572
7743
  { startedBy: "daemon", claudeStartingMode: "remote" }
7573
7744
  );
7574
- if (options?.model) {
7575
- launch.args.push("--model", options.model);
7576
- }
7577
- if (options?.permissionMode) {
7578
- launch.args.push("--permission-mode", options.permissionMode);
7579
- }
7580
- await fs.access(launch.cwd);
7581
- return spawnTrackedHappyProcess({
7745
+ const model = sanitizeResumeModel(options?.model);
7746
+ if (model) launch.args.push("--model", model);
7747
+ else if (options?.model !== void 0) logger.debug(`[DAEMON RUN] resume: ignoring invalid model ${JSON.stringify(options.model)}`);
7748
+ const permissionMode = sanitizeSpawnPermissionMode(options?.permissionMode);
7749
+ if (permissionMode) launch.args.push("--permission-mode", permissionMode);
7750
+ else if (options?.permissionMode !== void 0) logger.debug(`[DAEMON RUN] resume: ignoring invalid permission mode ${JSON.stringify(options.permissionMode)}`);
7751
+ const result = await spawnTrackedHappyProcess({
7582
7752
  args: launch.args,
7583
7753
  cwd: launch.cwd,
7584
7754
  env: {
@@ -7591,6 +7761,18 @@ async function startDaemon() {
7591
7761
  HAPPY_RECONNECT_AGENT_STATE_VERSION: String(tracked.encryption.agentStateVersion)
7592
7762
  }
7593
7763
  });
7764
+ if (result.type === "success") {
7765
+ persistSession(happySessionId, {
7766
+ encryptionKey: encodeBase64(tracked.encryption.encryptionKey),
7767
+ encryptionVariant: tracked.encryption.encryptionVariant,
7768
+ seq: tracked.encryption.seq,
7769
+ metadataVersion: tracked.encryption.metadataVersion,
7770
+ agentStateVersion: tracked.encryption.agentStateVersion,
7771
+ metadata,
7772
+ savedAt: Date.now()
7773
+ });
7774
+ }
7775
+ return result;
7594
7776
  } catch (error) {
7595
7777
  const errorMessage = error instanceof Error ? error.message : error && typeof error === "object" ? JSON.stringify(error) : String(error);
7596
7778
  logger.debug(`[DAEMON RUN] Failed to resume session: ${errorMessage}`, error instanceof Error ? error.stack : void 0);
@@ -7600,6 +7782,136 @@ async function startDaemon() {
7600
7782
  };
7601
7783
  }
7602
7784
  };
7785
+ const restartCounts = /* @__PURE__ */ new Map();
7786
+ const stopSessionAndWait = (happySessionId, timeoutMs = 8e3) => {
7787
+ let targetPid = null;
7788
+ for (const [pid2, s] of pidToTrackedSession.entries()) {
7789
+ if (s.happySessionId === happySessionId && isPidAlive(pid2)) {
7790
+ targetPid = pid2;
7791
+ break;
7792
+ }
7793
+ }
7794
+ if (targetPid === null) return Promise.resolve();
7795
+ const pid = targetPid;
7796
+ return new Promise((resolve) => {
7797
+ let settled = false;
7798
+ const done = () => {
7799
+ if (!settled) {
7800
+ settled = true;
7801
+ resolve();
7802
+ }
7803
+ };
7804
+ const requested = terminateProcess(pid, () => {
7805
+ const tracked = pidToTrackedSession.get(pid);
7806
+ if (tracked) {
7807
+ if (tracked.happySessionId && tracked.encryption) {
7808
+ sessionIdToFinishedSession.set(tracked.happySessionId, tracked);
7809
+ }
7810
+ pidToTrackedSession.delete(pid);
7811
+ }
7812
+ done();
7813
+ });
7814
+ if (!requested) done();
7815
+ setTimeout(done, timeoutMs).unref?.();
7816
+ });
7817
+ };
7818
+ const restartSession = async (happySessionId, options) => {
7819
+ let gate = resumeGates.get(happySessionId);
7820
+ if (!gate) {
7821
+ gate = createSpawnGate();
7822
+ resumeGates.set(happySessionId, gate);
7823
+ }
7824
+ try {
7825
+ return await gate.replace(() => restartSessionImpl(happySessionId, options));
7826
+ } finally {
7827
+ if (!gate.inFlight()) resumeGates.delete(happySessionId);
7828
+ }
7829
+ };
7830
+ const restartSessionImpl = async (happySessionId, options) => {
7831
+ try {
7832
+ const prior = restartCounts.get(happySessionId) ?? 0;
7833
+ const decision = decideRestart(prior, DEFAULT_MAX_RESTARTS);
7834
+ if (!decision.allowed) {
7835
+ return { type: "error", errorMessage: `restart:${decision.reason}` };
7836
+ }
7837
+ await stopSessionAndWait(happySessionId);
7838
+ const tracked = findTrackedSessionById(happySessionId);
7839
+ if (!tracked) {
7840
+ return { type: "error", errorMessage: `restart-precheck:not-tracked: Session ${happySessionId} is not tracked by this daemon.` };
7841
+ }
7842
+ if (!tracked.happySessionMetadataFromLocalWebhook) {
7843
+ return { type: "error", errorMessage: `restart-precheck:no-metadata: Session ${happySessionId} has no metadata. Cannot restart.` };
7844
+ }
7845
+ if (!tracked.encryption) {
7846
+ return { type: "error", errorMessage: `restart-precheck:no-encryption: Session ${happySessionId} has no stored encryption data. Restart the daemon and start a new session.` };
7847
+ }
7848
+ let metadata = tracked.happySessionMetadataFromLocalWebhook;
7849
+ const needsFetch = !metadata.claudeSessionId && (!metadata.flavor || metadata.flavor === "claude") || !metadata.codexThreadId && metadata.flavor === "codex";
7850
+ if (needsFetch) {
7851
+ const serverMetadata = await fetchServerSessionMetadata(happySessionId, tracked.encryption.encryptionKey, tracked.encryption.encryptionVariant);
7852
+ if (serverMetadata) {
7853
+ metadata = serverMetadata;
7854
+ tracked.happySessionMetadataFromLocalWebhook = serverMetadata;
7855
+ }
7856
+ }
7857
+ const precheck = resumePrecheck(metadata, {
7858
+ cwdExists: (p) => existsSync$1(p),
7859
+ conversationExists: (cwd2, claudeSessionId) => existsSync$1(join$1(getProjectPath(cwd2), `${claudeSessionId}.jsonl`))
7860
+ });
7861
+ let args;
7862
+ let cwd;
7863
+ if (precheck.ok) {
7864
+ const launch = buildResumeLaunch(
7865
+ { id: happySessionId, active: true, metadata },
7866
+ { startedBy: "daemon", claudeStartingMode: "remote" }
7867
+ );
7868
+ args = launch.args;
7869
+ cwd = launch.cwd;
7870
+ } else if ((metadata.flavor ?? "claude") === "claude" && typeof metadata.path === "string" && metadata.path.length > 0) {
7871
+ cwd = metadata.path;
7872
+ if (!existsSync$1(cwd)) {
7873
+ return { type: "error", errorMessage: `restart-precheck:cwd-missing: ${cwd}` };
7874
+ }
7875
+ args = ["claude", "--happy-starting-mode", "remote", "--started-by", "daemon"];
7876
+ } else {
7877
+ return { type: "error", errorMessage: `restart-precheck:${precheck.ok ? "unknown" : precheck.reason}: ${precheck.ok ? "" : precheck.detail}` };
7878
+ }
7879
+ const model = sanitizeResumeModel(options?.model);
7880
+ if (model) args.push("--model", model);
7881
+ const permissionMode = sanitizeSpawnPermissionMode(options?.permissionMode);
7882
+ if (permissionMode) args.push("--permission-mode", permissionMode);
7883
+ restartCounts.set(happySessionId, recordRestartAttempt(prior));
7884
+ const result = await spawnTrackedHappyProcess({
7885
+ args,
7886
+ cwd,
7887
+ env: {
7888
+ ...process.env,
7889
+ HAPPY_RECONNECT_SESSION_ID: happySessionId,
7890
+ HAPPY_RECONNECT_ENCRYPTION_KEY: encodeBase64(tracked.encryption.encryptionKey),
7891
+ HAPPY_RECONNECT_ENCRYPTION_VARIANT: tracked.encryption.encryptionVariant,
7892
+ HAPPY_RECONNECT_SEQ: String(tracked.encryption.seq),
7893
+ HAPPY_RECONNECT_METADATA_VERSION: String(tracked.encryption.metadataVersion),
7894
+ HAPPY_RECONNECT_AGENT_STATE_VERSION: String(tracked.encryption.agentStateVersion)
7895
+ }
7896
+ });
7897
+ if (result.type === "success") {
7898
+ persistSession(happySessionId, {
7899
+ encryptionKey: encodeBase64(tracked.encryption.encryptionKey),
7900
+ encryptionVariant: tracked.encryption.encryptionVariant,
7901
+ seq: tracked.encryption.seq,
7902
+ metadataVersion: tracked.encryption.metadataVersion,
7903
+ agentStateVersion: tracked.encryption.agentStateVersion,
7904
+ metadata,
7905
+ savedAt: Date.now()
7906
+ });
7907
+ }
7908
+ return result;
7909
+ } catch (error) {
7910
+ const errorMessage = error instanceof Error ? error.message : String(error);
7911
+ logger.debug(`[DAEMON RUN] Failed to restart session: ${errorMessage}`, error instanceof Error ? error.stack : void 0);
7912
+ return { type: "error", errorMessage: `Failed to restart session: ${errorMessage}` };
7913
+ }
7914
+ };
7603
7915
  const stopSession = (sessionId) => {
7604
7916
  logger.debug(`[DAEMON RUN] Attempting to stop session ${sessionId}`);
7605
7917
  for (const [pid, session] of pidToTrackedSession.entries()) {
@@ -7770,6 +8082,7 @@ async function startDaemon() {
7770
8082
  apiMachine.setRPCHandlers({
7771
8083
  spawnSession,
7772
8084
  resumeSession,
8085
+ restartSession,
7773
8086
  stopSession,
7774
8087
  listTrackedSessionIds: () => [...pidToTrackedSession.values()].map((session) => session.happySessionId).filter((sessionId) => typeof sessionId === "string"),
7775
8088
  requestShutdown: () => requestShutdown("happy-app")
@@ -9361,6 +9674,18 @@ async function runClaude(credentials, options = {}) {
9361
9674
  if (reconnectSessionId && !await api.reactivateSession(response.id)) {
9362
9675
  throw new Error(`Failed to reactivate archived session ${response.id}`);
9363
9676
  }
9677
+ let reconnectSeeded = false;
9678
+ if (reconnectSessionId) {
9679
+ const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
9680
+ if (snapshot.ok) {
9681
+ response = applyServerSnapshot(response, snapshot.session);
9682
+ reconnectSeeded = true;
9683
+ logger.debug(`[START] Reconnect seeded from server: seq=${snapshot.session.seq} metadataVersion=${snapshot.session.metadataVersion}`);
9684
+ } else {
9685
+ response = withoutServerSnapshot(response);
9686
+ logger.debug(`[START] Reconnect without server snapshot (${snapshot.reason}); skipping existing messages`);
9687
+ }
9688
+ }
9364
9689
  try {
9365
9690
  logger.debug(`[START] Reporting session ${response.id} to daemon`);
9366
9691
  const result = await notifyDaemonSessionStarted(response.id, metadata, {
@@ -9378,15 +9703,17 @@ async function runClaude(credentials, options = {}) {
9378
9703
  } catch (error) {
9379
9704
  logger.debug("[START] Failed to report to daemon (may not be running):", error);
9380
9705
  }
9381
- const session = api.sessionSyncClient(response);
9706
+ const session = api.sessionSyncClient(response, reconnectSeeded ? { initialSeq: response.seq } : void 0);
9382
9707
  if (reconnectSessionId) {
9383
9708
  session.suppressNextArchiveSignal();
9384
- session.skipExistingMessages();
9709
+ if (!reconnectSeeded) session.skipExistingMessages();
9385
9710
  session.updateMetadata((meta) => ({
9386
- ...meta,
9387
- lifecycleState: "running",
9388
- archivedBy: void 0,
9389
- queueCancellation: true
9711
+ ...mergeReconnectMetadata(meta, metadata, Date.now()),
9712
+ queueCancellation: true,
9713
+ // B-262 batch 2 (B5): a reconnected process re-publishes the mode
9714
+ // IT enforces; the server copy may still carry the previous
9715
+ // process's value.
9716
+ permissionMode: mapToClaudeMode(initialPermissionMode ?? "default")
9390
9717
  }));
9391
9718
  }
9392
9719
  const forkClaudeSessionId = process.env.HAPPY_FORK_CLAUDE_SESSION_ID;
@@ -9526,6 +9853,22 @@ async function runClaude(credentials, options = {}) {
9526
9853
  publishedPermissionMode = published;
9527
9854
  session.updateMetadata((meta) => ({ ...meta, permissionMode: published }));
9528
9855
  };
9856
+ const publishEffectivePermissionMode = (effective) => {
9857
+ const decision = reconcilePublishedPermissionMode({
9858
+ intent: mapToClaudeMode(currentPermissionMode ?? "default"),
9859
+ published: publishedPermissionMode,
9860
+ effective
9861
+ });
9862
+ if (!decision) return;
9863
+ if (decision.mismatch) {
9864
+ logger.warn(`[loop] Claude Code enforces permission mode '${effective}' but this process asked for '${mapToClaudeMode(currentPermissionMode ?? "default")}' \u2014 check ~/.claude settings (permissions.deny/ask/defaultMode/disableBypassPermissionsMode). Publishing the effective mode.`);
9865
+ }
9866
+ if (decision.publish !== publishedPermissionMode) {
9867
+ publishedPermissionMode = decision.publish;
9868
+ session.updateMetadata((meta) => ({ ...meta, permissionMode: decision.publish }));
9869
+ }
9870
+ };
9871
+ let lastExplicitModeSwitchAt = 0;
9529
9872
  let currentModel = options.model ?? DEFAULT_CLAUDE_MODEL;
9530
9873
  let currentFallbackModel = void 0;
9531
9874
  let currentCustomSystemPrompt = void 0;
@@ -9570,7 +9913,11 @@ async function runClaude(credentials, options = {}) {
9570
9913
  }
9571
9914
  const attachmentsForThisMessage = await session.drainAttachmentsForUserMessage();
9572
9915
  let messagePermissionMode = currentPermissionMode;
9573
- if (message.meta?.permissionMode) {
9916
+ const messageCreatedAt = message.createdAt;
9917
+ const staleModeSnapshot = message.meta?.permissionMode !== void 0 && typeof messageCreatedAt === "number" && messageCreatedAt < lastExplicitModeSwitchAt;
9918
+ if (staleModeSnapshot) {
9919
+ logger.debug(`[loop] Ignoring stale meta.permissionMode=${message.meta?.permissionMode} (message ${messageCreatedAt} predates explicit switch ${lastExplicitModeSwitchAt}); keeping ${currentPermissionMode}`);
9920
+ } else if (message.meta?.permissionMode) {
9574
9921
  const previousPermissionMode = currentPermissionMode;
9575
9922
  messagePermissionMode = resolveRemoteClaudePermissionMode(
9576
9923
  currentPermissionMode,
@@ -9834,9 +10181,11 @@ async function runClaude(credentials, options = {}) {
9834
10181
  },
9835
10182
  onAbort: resetCurrentModeDefaults,
9836
10183
  onPermissionModeChange: (mode) => {
10184
+ lastExplicitModeSwitchAt = Date.now();
9837
10185
  publishPermissionMode(mode);
9838
10186
  logger.debug(`[loop] Permission mode updated from session RPC / approval to: ${mode}`);
9839
10187
  },
10188
+ onEffectivePermissionMode: (mode) => publishEffectivePermissionMode(mode),
9840
10189
  mcpServers: {
9841
10190
  "happy": {
9842
10191
  type: "http",
@@ -12070,7 +12419,7 @@ function setupOfflineReconnection(opts) {
12070
12419
  });
12071
12420
  return { session, reconnectionHandle, isOffline: true };
12072
12421
  } else {
12073
- session = api.sessionSyncClient(response);
12422
+ session = api.sessionSyncClient(response, opts.sessionClientOptions);
12074
12423
  return { session, reconnectionHandle: null, isOffline: false };
12075
12424
  }
12076
12425
  }
@@ -12839,6 +13188,18 @@ async function runCodex(opts) {
12839
13188
  if (reconnectSessionId && response && !await api.reactivateSession(response.id)) {
12840
13189
  throw new Error(`Failed to reactivate archived session ${response.id}`);
12841
13190
  }
13191
+ let reconnectSeeded = false;
13192
+ if (reconnectSessionId && response) {
13193
+ const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
13194
+ if (snapshot.ok) {
13195
+ response = applyServerSnapshot(response, snapshot.session);
13196
+ reconnectSeeded = true;
13197
+ logger.debug(`[START] Reconnect seeded from server: seq=${snapshot.session.seq} metadataVersion=${snapshot.session.metadataVersion}`);
13198
+ } else {
13199
+ response = withoutServerSnapshot(response);
13200
+ logger.debug(`[START] Reconnect without server snapshot (${snapshot.reason}); skipping existing messages`);
13201
+ }
13202
+ }
12842
13203
  let session;
12843
13204
  let permissionHandler;
12844
13205
  let client;
@@ -12850,6 +13211,7 @@ async function runCodex(opts) {
12850
13211
  metadata,
12851
13212
  state,
12852
13213
  response,
13214
+ sessionClientOptions: reconnectSeeded && response ? { initialSeq: response.seq } : void 0,
12853
13215
  onSessionSwap: (newSession) => {
12854
13216
  session = newSession;
12855
13217
  if (permissionHandler) {
@@ -12860,12 +13222,8 @@ async function runCodex(opts) {
12860
13222
  session = initialSession;
12861
13223
  if (reconnectSessionId) {
12862
13224
  session.suppressNextArchiveSignal();
12863
- session.skipExistingMessages();
12864
- session.updateMetadata((meta) => ({
12865
- ...meta,
12866
- lifecycleState: "running",
12867
- archivedBy: void 0
12868
- }));
13225
+ if (!reconnectSeeded) session.skipExistingMessages();
13226
+ session.updateMetadata((meta) => mergeReconnectMetadata(meta, metadata, Date.now()));
12869
13227
  }
12870
13228
  if (response) {
12871
13229
  try {
@@ -13593,7 +13951,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13593
13951
  process.exit(0);
13594
13952
  } else if (subcommand === "install-terminal-hooks") {
13595
13953
  try {
13596
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-C-OgZr5k.mjs');
13954
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-DDRrUG_n.mjs');
13597
13955
  const command = parseTerminalHooksArgs(args.slice(1));
13598
13956
  if (command.action === "help") {
13599
13957
  console.log(TERMINAL_HOOKS_HELP);
@@ -13610,7 +13968,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13610
13968
  }
13611
13969
  } else if (subcommand === "spawn") {
13612
13970
  try {
13613
- const { handleSpawnCommand } = await import('./spawn-JxaPHAoP.mjs');
13971
+ const { handleSpawnCommand } = await import('./spawn-DS-Uz_Hw.mjs');
13614
13972
  await handleSpawnCommand(args.slice(1));
13615
13973
  } catch (error) {
13616
13974
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13622,7 +13980,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13622
13980
  return;
13623
13981
  } else if (subcommand === "send") {
13624
13982
  try {
13625
- const { handleSendCommand } = await import('./send-BHliX59m.mjs');
13983
+ const { handleSendCommand } = await import('./send-BQSaVz9r.mjs');
13626
13984
  await handleSendCommand(args.slice(1));
13627
13985
  } catch (error) {
13628
13986
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13728,9 +14086,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13728
14086
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
13729
14087
  const projectId = args[3];
13730
14088
  try {
13731
- const { saveGoogleCloudProjectToConfig } = await import('./config-BEdyyciP.mjs');
13732
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-DS3i_5LV.mjs').then(function (n) { return n.ak; });
13733
- const { ApiClient: ApiClient2 } = await import('./types-DS3i_5LV.mjs').then(function (n) { return n.al; });
14089
+ const { saveGoogleCloudProjectToConfig } = await import('./config-CJQw0z1o.mjs');
14090
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-B_8X_rZk.mjs').then(function (n) { return n.al; });
14091
+ const { ApiClient: ApiClient2 } = await import('./types-B_8X_rZk.mjs').then(function (n) { return n.am; });
13734
14092
  let userEmail = void 0;
13735
14093
  try {
13736
14094
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -13761,7 +14119,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13761
14119
  }
13762
14120
  if (geminiSubcommand === "project" && args[2] === "get") {
13763
14121
  try {
13764
- const { readGeminiLocalConfig } = await import('./config-BEdyyciP.mjs');
14122
+ const { readGeminiLocalConfig } = await import('./config-CJQw0z1o.mjs');
13765
14123
  const config = readGeminiLocalConfig();
13766
14124
  if (config.googleCloudProject) {
13767
14125
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -13801,7 +14159,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13801
14159
  process.exit(0);
13802
14160
  }
13803
14161
  try {
13804
- const { runGemini } = await import('./runGemini-DBr_TiTL.mjs');
14162
+ const { runGemini } = await import('./runGemini-DHYs_Beq.mjs');
13805
14163
  let startedBy = void 0;
13806
14164
  for (let i = 1; i < args.length; i++) {
13807
14165
  if (args[i] === "--started-by") {
@@ -13823,7 +14181,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13823
14181
  return;
13824
14182
  } else if (subcommand === "acp") {
13825
14183
  try {
13826
- const { runAcp, resolveAcpAgentConfig } = await import('./index-Dfu5uvjk.mjs');
14184
+ const { runAcp, resolveAcpAgentConfig } = await import('./index-BP9pfzdZ.mjs');
13827
14185
  let startedBy = void 0;
13828
14186
  let verbose = false;
13829
14187
  const acpArgs = [];
@@ -13863,7 +14221,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13863
14221
  return;
13864
14222
  } else if (subcommand === "openclaw") {
13865
14223
  try {
13866
- const { runOpenClaw } = await import('./runOpenClaw-Cbde8t92.mjs');
14224
+ const { runOpenClaw } = await import('./runOpenClaw-DTaXxvNd.mjs');
13867
14225
  let startedBy = void 0;
13868
14226
  let verbose = false;
13869
14227
  let gatewayUrl;
@@ -13914,7 +14272,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13914
14272
  return;
13915
14273
  } else if (subcommand === "mcp" && args.length === 1) {
13916
14274
  try {
13917
- const { handleMcpCommand } = await import('./mcp-Du-N0qlK.mjs');
14275
+ const { handleMcpCommand } = await import('./mcp-CYJAl5pk.mjs');
13918
14276
  await handleMcpCommand();
13919
14277
  } catch (error) {
13920
14278
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}