very-happy-cli 0.2.142 → 0.2.144

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 (49) hide show
  1. package/dist/{AcpBackend-D2LqY2to.mjs → AcpBackend-DLsPpWnc.mjs} +2 -2
  2. package/dist/{AcpBackend-DJsqfgjD.cjs → AcpBackend-DssrjZDS.cjs} +30 -30
  3. package/dist/{AcpSessionManager-CdeM5KD9.mjs → AcpSessionManager-1pAH8SdV.mjs} +1 -1
  4. package/dist/{AcpSessionManager-CTfDxziP.cjs → AcpSessionManager-DkBV80Rr.cjs} +9 -9
  5. package/dist/{agentGuidance-Cz8QVcX3.mjs → agentGuidance-CupQ9Lve.mjs} +1 -1
  6. package/dist/{agentGuidance-Bi8iBjy3.cjs → agentGuidance-D1PDVswF.cjs} +1 -1
  7. package/dist/agentHome-BaSxP7lQ.mjs +107 -0
  8. package/dist/agentHome-uf1zs2Fi.cjs +113 -0
  9. package/dist/codex/happyMcpStdioBridge.cjs +2 -2
  10. package/dist/codex/happyMcpStdioBridge.mjs +2 -2
  11. package/dist/{config-ZsBeq10u.mjs → config-CxHoQo52.mjs} +4 -4
  12. package/dist/{config-BIbYBmTd.cjs → config-kx4y9oAI.cjs} +4 -4
  13. package/dist/{index-Bom8mTuS.cjs → index-DIoSNgtt.cjs} +4 -4
  14. package/dist/{index-CYFendNf.mjs → index-Diu81aSC.mjs} +77 -28
  15. package/dist/{index-CSQZhQ0C.cjs → index-Dn0JMM8l.cjs} +250 -201
  16. package/dist/{index-BPTPrjhL.cjs → index-Dox9iD5R.cjs} +31 -31
  17. package/dist/{index-CNARLBax.mjs → index-DxEaiVzX.mjs} +4 -4
  18. package/dist/{index-CY0zmhIp.mjs → index-J6a8OHS6.mjs} +8 -8
  19. package/dist/index.cjs +4 -4
  20. package/dist/index.mjs +4 -4
  21. package/dist/{installTerminalHooks-BPJu2WVz.mjs → installTerminalHooks-BBMGk3q5.mjs} +4 -4
  22. package/dist/{installTerminalHooks-DA7SyFYW.cjs → installTerminalHooks-De7_iOOC.cjs} +4 -4
  23. package/dist/lib.cjs +5 -5
  24. package/dist/lib.mjs +2 -2
  25. package/dist/{limits-B3hngubn.cjs → limits-C_Sklt--.cjs} +7 -7
  26. package/dist/{limits-CHsz3Ba-.mjs → limits-DxArdmkZ.mjs} +8 -8
  27. package/dist/{mcp-BkWBRWFe.mjs → mcp-C1oNnlw5.mjs} +4 -4
  28. package/dist/{mcp-ySrfNOYl.cjs → mcp-xyb8dYIQ.cjs} +9 -9
  29. package/dist/{piRuntime-uX0WHVr4.cjs → piRuntime-3Vbdgv6X.cjs} +2 -2
  30. package/dist/{piRuntime-DBLUyXFr.mjs → piRuntime-CzJdE4z4.mjs} +2 -2
  31. package/dist/{piTerminal-DNr3hkzY.cjs → piTerminal-BFpwVGWr.cjs} +6 -6
  32. package/dist/{piTerminal-Bc3jSCnY.mjs → piTerminal-Do2GiKMN.mjs} +6 -6
  33. package/dist/{runGemini-eJ08cXk7.cjs → runGemini-CCdGxTF2.cjs} +24 -24
  34. package/dist/{runGemini-rgFHTnG7.mjs → runGemini-De5NRMT9.mjs} +6 -6
  35. package/dist/{runOpenClaw-GjLWwjas.mjs → runOpenClaw-C2t4DRyi.mjs} +5 -5
  36. package/dist/{runOpenClaw-D0LVzxqM.cjs → runOpenClaw-CRMUfrWk.cjs} +26 -26
  37. package/dist/{send-Bg2oqt7f.cjs → send-BA1Dgpgn.cjs} +4 -4
  38. package/dist/{send-DV8liaRN.mjs → send-l6Rj09c0.mjs} +4 -4
  39. package/dist/{sessions-DPimBZ8H.cjs → sessions-CtVcoXvG.cjs} +5 -5
  40. package/dist/{sessions-JiL4aJkC.mjs → sessions-MWLDqQk-.mjs} +4 -4
  41. package/dist/{spawn-COOcUwkG.cjs → spawn-Be4nsNuQ.cjs} +6 -6
  42. package/dist/{spawn-CnMk3LFG.mjs → spawn-DKWR-6Qc.mjs} +4 -4
  43. package/dist/{teams-DSQgHBLE.cjs → teams-CcjjNLi8.cjs} +4 -4
  44. package/dist/{teams-uHZcdX9j.mjs → teams-DMf9GNGE.mjs} +4 -4
  45. package/dist/{todo-oHWNpEx_.mjs → todo-BEXZRm1A.mjs} +3 -3
  46. package/dist/{todo-DeauuUd6.cjs → todo-EffYAnre.cjs} +5 -5
  47. package/dist/{types-Dnoxgb7G.mjs → types-D6YKR7wo.mjs} +372 -15
  48. package/dist/{types-Xd_LJRJN.cjs → types-DZ5c-9f3.cjs} +379 -13
  49. package/package.json +7 -7
@@ -3,14 +3,14 @@
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
5
  var node_crypto = require('node:crypto');
6
- var api = require('./types-Xd_LJRJN.cjs');
7
- var persistence = require('./limits-B3hngubn.cjs');
6
+ var index = require('./types-DZ5c-9f3.cjs');
7
+ var persistence = require('./limits-C_Sklt--.cjs');
8
8
  var spawn = require('cross-spawn');
9
9
  var path = require('node:path');
10
10
  var node_readline = require('node:readline');
11
11
  var node_fs = require('node:fs');
12
12
  var projectPath = require('./projectPath-ChLhdOyt.cjs');
13
- var agentGuidance = require('./agentGuidance-Bi8iBjy3.cjs');
13
+ var agentGuidance = require('./agentGuidance-D1PDVswF.cjs');
14
14
  var promises = require('node:fs/promises');
15
15
  var fs = require('fs/promises');
16
16
  var ink = require('ink');
@@ -288,7 +288,7 @@ class Session {
288
288
  reportEventToDaemon = (event) => {
289
289
  const spawnedBy = process.env.HAPPY_SPAWNED_BY;
290
290
  if (!spawnedBy) return;
291
- void api.notifyDaemonSessionEvent(this.client.sessionId, event, spawnedBy).catch((error) => persistence.logger.debug("[Session] Failed to report session event to daemon:", error));
291
+ void index.notifyDaemonSessionEvent(this.client.sessionId, event, spawnedBy).catch((error) => persistence.logger.debug("[Session] Failed to report session event to daemon:", error));
292
292
  };
293
293
  /** Produce an `error` notification for an unexpected session failure. */
294
294
  onSessionError = (message) => {
@@ -398,7 +398,7 @@ function pinSmallFastModel(env) {
398
398
  }
399
399
 
400
400
  function claudeCheckSession(sessionId, path$1) {
401
- const projectDir = api.getProjectPath(path$1);
401
+ const projectDir = index.getProjectPath(path$1);
402
402
  const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);
403
403
  const sessionExists = node_fs.existsSync(sessionFile);
404
404
  if (!sessionExists) {
@@ -424,7 +424,7 @@ function claudeCheckSession(sessionId, path$1) {
424
424
 
425
425
  function claudeFindLastSession(workingDirectory) {
426
426
  try {
427
- const projectDir = api.getProjectPath(workingDirectory);
427
+ const projectDir = index.getProjectPath(workingDirectory);
428
428
  const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
429
429
  const files = node_fs.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
430
430
  const sessionId = f.replace(".jsonl", "");
@@ -478,7 +478,7 @@ function shouldIncludeCoAuthoredBy() {
478
478
 
479
479
  const BASE_SYSTEM_PROMPT = (() => agentGuidance.trimIdent(`
480
480
  ALWAYS when you start a new chat - you must call a tool "mcp__happy__change_title" to set a chat title. When you think chat title is not relevant anymore - call the tool again to change it. When chat name is too generic and you have a change to make it more specific - call the tool again to change it. This title is needed to easily find the chat in the future. Help human.
481
- `))() + "\n\n" + agentGuidance.AGENT_GUIDANCE + "\n\n" + api.BUILTIN_TODO_DISCOVERY;
481
+ `))() + "\n\n" + agentGuidance.AGENT_GUIDANCE + "\n\n" + index.BUILTIN_TODO_DISCOVERY;
482
482
  const CO_AUTHORED_CREDITS = (() => agentGuidance.trimIdent(`
483
483
  When making commit messages, instead of just giving co-credit to Claude, also give credit to Happy like so:
484
484
 
@@ -511,7 +511,7 @@ function quoteShellArg(value) {
511
511
  return `'${value.replace(/'/g, `'\\''`)}'`;
512
512
  }
513
513
  async function claudeLocal(opts) {
514
- const projectDir = api.getProjectPath(opts.path);
514
+ const projectDir = index.getProjectPath(opts.path);
515
515
  node_fs.mkdirSync(projectDir, { recursive: true });
516
516
  const hasContinueFlag = opts.claudeArgs?.includes("--continue");
517
517
  const hasResumeFlag = opts.claudeArgs?.includes("--resume");
@@ -667,7 +667,7 @@ async function claudeLocal(opts) {
667
667
  persistence.logger.warn("[ClaudeLocal] Sandbox is not supported on Windows; continuing without sandbox.");
668
668
  } else {
669
669
  try {
670
- cleanupSandbox = await api.initializeSandbox(opts.sandboxConfig, opts.path);
670
+ cleanupSandbox = await index.initializeSandbox(opts.sandboxConfig, opts.path);
671
671
  if (!spawnArgs.includes("--dangerously-skip-permissions")) {
672
672
  spawnArgs = [...spawnArgs, "--dangerously-skip-permissions"];
673
673
  }
@@ -675,7 +675,7 @@ async function claudeLocal(opts) {
675
675
  "node",
676
676
  ...spawnArgs.map((arg) => quoteShellArg(arg))
677
677
  ].join(" ");
678
- spawnCommand = await api.wrapCommand(fullCommand);
678
+ spawnCommand = await index.wrapCommand(fullCommand);
679
679
  spawnWithShell = true;
680
680
  persistence.logger.info(
681
681
  `[ClaudeLocal] Sandbox enabled: workspace=${opts.sandboxConfig.workspaceRoot ?? opts.path}, network=${opts.sandboxConfig.networkMode}`
@@ -738,7 +738,7 @@ async function claudeLocal(opts) {
738
738
  persistence.logger.debug(`[ClaudeLocal] Unknown message type: ${message.type}`);
739
739
  }
740
740
  } catch (e) {
741
- persistence.logger.debug("[ClaudeLocal] Non-JSON line from fd3:", api.contentLogMetadata(line));
741
+ persistence.logger.debug("[ClaudeLocal] Non-JSON line from fd3:", index.contentLogMetadata(line));
742
742
  }
743
743
  });
744
744
  rl.on("error", (err) => {
@@ -876,7 +876,7 @@ const INTERNAL_CLAUDE_EVENT_TYPES$1 = /* @__PURE__ */ new Set([
876
876
  "queue-operation"
877
877
  ]);
878
878
  async function createSessionScanner(opts) {
879
- const projectDir = api.getProjectPath(opts.workingDirectory);
879
+ const projectDir = index.getProjectPath(opts.workingDirectory);
880
880
  let finishedSessions = /* @__PURE__ */ new Set();
881
881
  let pendingSessions = /* @__PURE__ */ new Set();
882
882
  let currentSessionId = null;
@@ -891,7 +891,7 @@ async function createSessionScanner(opts) {
891
891
  }
892
892
  currentSessionId = opts.sessionId;
893
893
  }
894
- const sync = new api.InvalidateSync(async () => {
894
+ const sync = new index.InvalidateSync(async () => {
895
895
  let sessions = [];
896
896
  for (let p of pendingSessions) {
897
897
  if (!deadSessions.has(p)) {
@@ -1033,7 +1033,7 @@ async function readSessionLog(projectDir, sessionId) {
1033
1033
  if (message.type && INTERNAL_CLAUDE_EVENT_TYPES$1.has(message.type)) {
1034
1034
  continue;
1035
1035
  }
1036
- let parsed = api.RawJSONLinesSchema.safeParse(message);
1036
+ let parsed = index.RawJSONLinesSchema.safeParse(message);
1037
1037
  if (!parsed.success) {
1038
1038
  continue;
1039
1039
  }
@@ -1912,7 +1912,7 @@ async function awaitFileExist(file, timeout = 1e4) {
1912
1912
  await fs.access(file);
1913
1913
  return true;
1914
1914
  } catch (e) {
1915
- await api.delay(1e3);
1915
+ await index.delay(1e3);
1916
1916
  }
1917
1917
  }
1918
1918
  return false;
@@ -2107,7 +2107,7 @@ async function claudeRemote(opts) {
2107
2107
  }
2108
2108
  continue;
2109
2109
  }
2110
- persistence.logger.debug(`[claudeRemote] Message ${message.type}`, api.contentLogMetadata(message));
2110
+ persistence.logger.debug(`[claudeRemote] Message ${message.type}`, index.contentLogMetadata(message));
2111
2111
  if (message.type === "assistant" && message.error) {
2112
2112
  lastAssistantError = message.error;
2113
2113
  }
@@ -2147,7 +2147,7 @@ async function claudeRemote(opts) {
2147
2147
  }
2148
2148
  if (systemInit.session_id) {
2149
2149
  persistence.logger.debug(`[claudeRemote] Waiting for session file to be written to disk: ${systemInit.session_id}`);
2150
- const projectDir = api.getProjectPath(opts.path);
2150
+ const projectDir = index.getProjectPath(opts.path);
2151
2151
  const found = await awaitFileExist(path.join(projectDir, `${systemInit.session_id}.jsonl`), 3e4);
2152
2152
  persistence.logger.debug(`[claudeRemote] Session file found: ${systemInit.session_id} ${found}`);
2153
2153
  if (!found) {
@@ -2378,9 +2378,9 @@ class PermissionHandler {
2378
2378
  persistence.logger.debug("Plan mode result received", {
2379
2379
  approved: response.approved,
2380
2380
  mode: response.mode,
2381
- reason: api.contentLogMetadata(response.reason),
2381
+ reason: index.contentLogMetadata(response.reason),
2382
2382
  allowToolCount: response.allowTools?.length ?? 0,
2383
- updatedInput: api.contentLogMetadata(response.updatedInput)
2383
+ updatedInput: index.contentLogMetadata(response.updatedInput)
2384
2384
  });
2385
2385
  if (response.approved) {
2386
2386
  const newMode = response.mode && ["default", "acceptEdits", "bypassPermissions"].includes(response.mode) ? response.mode : "bypassPermissions";
@@ -2704,9 +2704,9 @@ class PermissionHandler {
2704
2704
  id: message.id,
2705
2705
  approved: message.approved,
2706
2706
  mode: message.mode,
2707
- reason: api.contentLogMetadata(message.reason),
2707
+ reason: index.contentLogMetadata(message.reason),
2708
2708
  allowToolCount: message.allowTools?.length ?? 0,
2709
- updatedInput: api.contentLogMetadata(message.updatedInput)
2709
+ updatedInput: index.contentLogMetadata(message.updatedInput)
2710
2710
  });
2711
2711
  const id = message.id;
2712
2712
  const pending = this.pendingRequests.get(id);
@@ -3191,7 +3191,7 @@ class OutgoingMessageQueue {
3191
3191
  }
3192
3192
  queue = [];
3193
3193
  nextId = 1;
3194
- lock = new api.AsyncLock();
3194
+ lock = new index.AsyncLock();
3195
3195
  processTimer;
3196
3196
  delayTimers = /* @__PURE__ */ new Map();
3197
3197
  /**
@@ -3483,7 +3483,7 @@ class StreamRelay {
3483
3483
  }
3484
3484
  this.pending.text += text;
3485
3485
  this.pending.bytes += Buffer.byteLength(text, "utf8");
3486
- if (this.pending.bytes >= STREAM_FLUSH_MAX_BYTES || this.pending.text.length >= api.STREAM_DELTA_MAX_CHARS) {
3486
+ if (this.pending.bytes >= STREAM_FLUSH_MAX_BYTES || this.pending.text.length >= index.STREAM_DELTA_MAX_CHARS) {
3487
3487
  this.flushPending();
3488
3488
  return;
3489
3489
  }
@@ -3663,8 +3663,8 @@ async function stageClaudeAttachments(attachments, options) {
3663
3663
  await persistence.ensurePrivateDirectory(sessionDir);
3664
3664
  const staged = [];
3665
3665
  for (const attachment of attachments) {
3666
- if (attachment.data.length > api.MAX_CHAT_ATTACHMENT_SOURCE_BYTES) {
3667
- throw new Error(`Attachment exceeds the ${api.MAX_CHAT_ATTACHMENT_SOURCE_BYTES / 1024 / 1024} MB limit`);
3666
+ if (attachment.data.length > index.MAX_CHAT_ATTACHMENT_SOURCE_BYTES) {
3667
+ throw new Error(`Attachment exceeds the ${index.MAX_CHAT_ATTACHMENT_SOURCE_BYTES / 1024 / 1024} MB limit`);
3668
3668
  }
3669
3669
  const name = safeFileName(attachment.name || "file");
3670
3670
  const targetPath = path.join(sessionDir, uniqueFileName(name));
@@ -4265,12 +4265,12 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
4265
4265
  claudeArgs: session.claudeArgs,
4266
4266
  onMessage,
4267
4267
  onCompletionEvent: (message) => {
4268
- persistence.logger.debug("[remote]: Completion event received:", api.contentLogMetadata(message));
4268
+ persistence.logger.debug("[remote]: Completion event received:", index.contentLogMetadata(message));
4269
4269
  session.client.sendSessionEvent({ type: "message", message });
4270
4270
  },
4271
4271
  onAuthFailure: (reason) => {
4272
4272
  session.client.sendSessionEvent({ type: "message", message: `Claude Code auth: ${reason}`, kind: "claude-auth-failed" });
4273
- void api.notifyDaemonClaudeAuthFailed(session.client.sessionId).catch((error) => persistence.logger.debug("[remote]: auth_failed report to daemon failed:", error));
4273
+ void index.notifyDaemonClaudeAuthFailed(session.client.sessionId).catch((error) => persistence.logger.debug("[remote]: auth_failed report to daemon failed:", error));
4274
4274
  },
4275
4275
  onSessionReset: () => {
4276
4276
  persistence.logger.debug("[remote]: Session reset");
@@ -5062,7 +5062,7 @@ function daemonReadiness(authenticated, running, hasState) {
5062
5062
  message: "\u26A0\uFE0F Daemon is not running \u2014 run `very-happy daemon start`"
5063
5063
  };
5064
5064
  }
5065
- function collectRuntimeReadiness(run = node_child_process.spawnSync, currentNodeVersion = process.version, onPath = api.commandOnPath) {
5065
+ function collectRuntimeReadiness(run = node_child_process.spawnSync, currentNodeVersion = process.version, onPath = index.commandOnPath) {
5066
5066
  const tmux = probe("tmux", run);
5067
5067
  return {
5068
5068
  node: {
@@ -5111,7 +5111,7 @@ function shareSafeEnvironmentInfo(env = process.env, runtime = process) {
5111
5111
  function printCliUpdateStatus(state) {
5112
5112
  const installed = persistence.configuration.currentCliVersion;
5113
5113
  const running = state?.startedWithCliVersion ?? null;
5114
- const summary = api.deriveLocalCliUpdateSummary(installed, running, state?.cliUpdate);
5114
+ const summary = index.deriveLocalCliUpdateSummary(installed, running, state?.cliUpdate);
5115
5115
  console.log(` Installed CLI: ${installed}`);
5116
5116
  console.log(` Running daemon: ${running ?? "not running"}`);
5117
5117
  if (state?.cliUpdate?.recommendedVersion) console.log(` Recommended: ${state.cliUpdate.recommendedVersion}`);
@@ -5146,7 +5146,7 @@ function getLogFiles(logDir) {
5146
5146
  async function runDoctorDaemon() {
5147
5147
  console.log(chalk.bold("\n\u{1F916} Daemon Status"));
5148
5148
  try {
5149
- const isRunning = await api.checkIfDaemonRunningAndCleanupStaleState();
5149
+ const isRunning = await index.checkIfDaemonRunningAndCleanupStaleState();
5150
5150
  const state = await persistence.readDaemonState();
5151
5151
  if (isRunning && state) {
5152
5152
  console.log(chalk.green("\u2713 Daemon is running"));
@@ -5316,6 +5316,16 @@ ${typeLabels[type] || type}:`));
5316
5316
  console.log(chalk.gray(" OS-keychain credentials cannot be verified here; see /docs/configuration#claude-credentials."));
5317
5317
  }
5318
5318
  console.log(chalk.gray(" An external claude command is only needed for native terminal/mirror use."));
5319
+ try {
5320
+ const { resolveAgentHomesForCli } = await Promise.resolve().then(function () { return require('./agentHome-uf1zs2Fi.cjs'); });
5321
+ const { describeAgentHome } = await Promise.resolve().then(function () { return require('./types-DZ5c-9f3.cjs'); }).then(function (n) { return n.index; });
5322
+ const homes = await resolveAgentHomesForCli();
5323
+ console.log(chalk.green(`\u2713 Claude config dir: ${describeAgentHome(homes.claudeConfigDir)}`));
5324
+ console.log(chalk.green(`\u2713 Codex home: ${describeAgentHome(homes.codexHome)}`));
5325
+ console.log(chalk.gray(" Resolved from settings.json, then your login shell, then the daemon environment; pin with `very-happy agent-home`."));
5326
+ } catch {
5327
+ console.log(chalk.yellow("\u25CB Could not resolve the Claude/Codex home directories"));
5328
+ }
5319
5329
  if (availableAgents.length === 0) {
5320
5330
  console.log(chalk.yellow("\u25CB No external agent command found on this daemon PATH"));
5321
5331
  console.log(chalk.gray(" Codex, Gemini, OpenCode, OpenClaw, and native Claude terminal paths need their local command or gateway."));
@@ -5349,7 +5359,7 @@ ${typeLabels[type] || type}:`));
5349
5359
  }
5350
5360
  console.log(chalk.bold("\n\u{1F916} Daemon Status"));
5351
5361
  try {
5352
- const isRunning = await api.checkIfDaemonRunningAndCleanupStaleState();
5362
+ const isRunning = await index.checkIfDaemonRunningAndCleanupStaleState();
5353
5363
  const state = await persistence.readDaemonState();
5354
5364
  const summary = daemonReadiness(authenticated, isRunning, Boolean(state));
5355
5365
  if (summary.level === "ready" && state) {
@@ -5419,7 +5429,7 @@ async function registryVersion(name) {
5419
5429
  return typeof data.version === "string" ? stableVersion(data.version) : null;
5420
5430
  }
5421
5431
  async function detectAgentVersions(deps = { probe: probeAgentVersion, registryVersion }, now = Date.now()) {
5422
- const agents = await Promise.all(api.AGENT_VERSION_SOURCES.map(async (source) => {
5432
+ const agents = await Promise.all(index.AGENT_VERSION_SOURCES.map(async (source) => {
5423
5433
  const local = source.command ? await deps.probe(source.command).catch(() => ({ version: null, missing: false })) : { version: stableVersion(persistence.packageJson.dependencies["@anthropic-ai/claude-agent-sdk"]), missing: false };
5424
5434
  if (local.missing) return { id: source.id, installed: null, latest: null, status: "not-installed" };
5425
5435
  const latest = await deps.registryVersion(source.package).catch(() => null);
@@ -5678,7 +5688,7 @@ async function waitForAuthentication(keypair, claimSecret) {
5678
5688
  }
5679
5689
  process.stdout.write("\rWaiting for authentication" + ".".repeat(dots % 3 + 1) + " ");
5680
5690
  dots++;
5681
- await api.delay(1e3);
5691
+ await index.delay(1e3);
5682
5692
  }
5683
5693
  } finally {
5684
5694
  process.off("SIGINT", handleInterrupt);
@@ -6003,7 +6013,7 @@ async function waitForSessionKey(sessionId, timeoutMs) {
6003
6013
  `Session ${sessionId} has no encryption key in ${persistence.configuration.sessionsFile}. Either it was not spawned by this machine's daemon, or the daemon is too old to persist session keys.`
6004
6014
  );
6005
6015
  }
6006
- await api.delay(200);
6016
+ await index.delay(200);
6007
6017
  }
6008
6018
  }
6009
6019
  async function sendUserMessage(sessionId, persisted, text, client, options = {}) {
@@ -6065,7 +6075,7 @@ function resumePrecheck(metadata, fs) {
6065
6075
  if (!metadata.codexThreadId) return { ok: false, reason: "no-backend-id", detail: "session has no Codex thread id" };
6066
6076
  return { ok: true };
6067
6077
  }
6068
- if (!api.isClaudeSessionId(metadata.claudeSessionId)) {
6078
+ if (!index.isClaudeSessionId(metadata.claudeSessionId)) {
6069
6079
  return { ok: false, reason: "no-backend-id", detail: "session has no Claude session id" };
6070
6080
  }
6071
6081
  if (!fs.conversationExists(metadata.path, metadata.claudeSessionId)) {
@@ -7377,8 +7387,8 @@ function decryptBoxBundle(bundle, recipientSecretKey) {
7377
7387
  return decrypted ? new Uint8Array(decrypted) : null;
7378
7388
  }
7379
7389
  function readAgentCredentials() {
7380
- const credentialPath = api.getLocalHappyAgentCredentialPath();
7381
- const credentials = api.readLocalHappyAgentCredentials();
7390
+ const credentialPath = index.getLocalHappyAgentCredentialPath();
7391
+ const credentials = index.readLocalHappyAgentCredentials();
7382
7392
  if (!credentials) {
7383
7393
  throw new Error(
7384
7394
  `Cannot use the legacy CLI resume path without ${credentialPath}. This credential is produced only by the source-only internal control-plane prototype; do not install the unrelated npm package named happy-agent. Use the Web session controls instead.`
@@ -7678,7 +7688,7 @@ function ownedCliLink(link, target, packageDir) {
7678
7688
  return resolved.startsWith(path.join(packageDir, "bin") + path.sep);
7679
7689
  }
7680
7690
  async function installCliSafely(version, deps = defaults) {
7681
- const parsed = api.parseExactVersion(version);
7691
+ const parsed = index.parseExactVersion(version);
7682
7692
  if (!parsed) throw new Error("Invalid exact CLI version");
7683
7693
  const args = autoUpdateInstallArgs(parsed.exact);
7684
7694
  if (deps.platform === "win32") {
@@ -7769,7 +7779,7 @@ function createUpdateController(deps) {
7769
7779
  let lastPublished = "";
7770
7780
  const now = deps.now ?? Date.now;
7771
7781
  function validManualTarget(next, version) {
7772
- return version === next.recommendedVersion && Number.isFinite(next.checkedAt) && now() - next.checkedAt <= 65 * 6e4 && next.checkedAt <= now() + 6e4 && api.compareExactVersions(next.currentVersion, version) === -1 && (!next.minimumVersion || [0, 1].includes(api.compareExactVersions(version, next.minimumVersion) ?? -1));
7782
+ return version === next.recommendedVersion && Number.isFinite(next.checkedAt) && now() - next.checkedAt <= 65 * 6e4 && next.checkedAt <= now() + 6e4 && index.compareExactVersions(next.currentVersion, version) === -1 && (!next.minimumVersion || [0, 1].includes(index.compareExactVersions(version, next.minimumVersion) ?? -1));
7773
7783
  }
7774
7784
  function publish(state, version, detail) {
7775
7785
  if (!policy) return;
@@ -7807,7 +7817,7 @@ function createUpdateController(deps) {
7807
7817
  publish("unapproved", null);
7808
7818
  return;
7809
7819
  }
7810
- const order = api.compareExactVersions(policy.currentVersion, target);
7820
+ const order = index.compareExactVersions(policy.currentVersion, target);
7811
7821
  if (order !== -1) {
7812
7822
  publish(order === null ? "policy_stale" : "current", target);
7813
7823
  return;
@@ -7988,7 +7998,7 @@ function parseJsonObject(text) {
7988
7998
  return null;
7989
7999
  }
7990
8000
  }
7991
- function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-CSQZhQ0C.cjs', document.baseURI).href))).resolve(s)) {
8001
+ function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Dn0JMM8l.cjs', document.baseURI).href))).resolve(s)) {
7992
8002
  const platformArch = `${platform}-${arch}`;
7993
8003
  const candidates = [
7994
8004
  `@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
@@ -8378,7 +8388,7 @@ function parseLines(lines) {
8378
8388
  try {
8379
8389
  const parsed = JSON.parse(line);
8380
8390
  if (parsed?.type && INTERNAL_CLAUDE_EVENT_TYPES.has(parsed.type)) continue;
8381
- const result = api.RawJSONLinesSchema.safeParse(parsed);
8391
+ const result = index.RawJSONLinesSchema.safeParse(parsed);
8382
8392
  if (!result.success) continue;
8383
8393
  out.push(result.data);
8384
8394
  } catch {
@@ -8422,19 +8432,19 @@ function createMirrorScanner(opts) {
8422
8432
  } finally {
8423
8433
  await handle.close();
8424
8434
  }
8425
- const { lines, consumedBytes } = api.extractCompleteLines(buf);
8435
+ const { lines, consumedBytes } = index.extractCompleteLines(buf);
8426
8436
  tail.offset += consumedBytes;
8427
8437
  if (lines.length === 0) return;
8428
8438
  let messages = parseLines(lines);
8429
8439
  if (isFirstBackfillRead) {
8430
- const decision = api.decideBackfill(messages, opts.backfillLines);
8440
+ const decision = index.decideBackfill(messages, opts.backfillLines);
8431
8441
  messages = decision.replay;
8432
8442
  if (decision.truncated) opts.events.onBackfillTruncated?.();
8433
8443
  tail.mode = "from-eof";
8434
8444
  }
8435
8445
  if (messages.length > 0) opts.events.onMessages(messages);
8436
8446
  };
8437
- const sync = new api.InvalidateSync(async () => {
8447
+ const sync = new index.InvalidateSync(async () => {
8438
8448
  for (const tail of files.values()) {
8439
8449
  try {
8440
8450
  await readTail(tail);
@@ -8518,7 +8528,7 @@ function pendingCreateSupersededBy(pending, event) {
8518
8528
  const TERMINAL_MIRROR_FLAVOR = "terminal-mirror";
8519
8529
  const RECONCILE_HYSTERESIS_MS = 2e4;
8520
8530
  function createMirrorManager(deps) {
8521
- const backfillLines = deps.backfillLines ?? api.MIRROR_BACKFILL_LINES_DEFAULT;
8531
+ const backfillLines = deps.backfillLines ?? index.MIRROR_BACKFILL_LINES_DEFAULT;
8522
8532
  const bindings = /* @__PURE__ */ new Map();
8523
8533
  const lastEndedAt = /* @__PURE__ */ new Map();
8524
8534
  const pendingCreates = /* @__PURE__ */ new Map();
@@ -8533,7 +8543,7 @@ function createMirrorManager(deps) {
8533
8543
  };
8534
8544
  const isTerminalAlive = deps.isTerminalAlive ?? ((terminalId) => {
8535
8545
  try {
8536
- return node_child_process.spawnSync("tmux", api.tmuxArgs(["has-session", "-t", `=vh-${terminalId}:`]), { stdio: "ignore", timeout: 3e3, env: api.scrubTmuxClientEnv({ ...process.env }) }).status === 0;
8546
+ return node_child_process.spawnSync("tmux", index.tmuxArgs(["has-session", "-t", `=vh-${terminalId}:`]), { stdio: "ignore", timeout: 3e3, env: index.scrubTmuxClientEnv({ ...process.env }) }).status === 0;
8537
8547
  } catch {
8538
8548
  return false;
8539
8549
  }
@@ -8541,7 +8551,7 @@ function createMirrorManager(deps) {
8541
8551
  const transcriptPathFor = (event) => {
8542
8552
  if (event.transcriptPath) return event.transcriptPath;
8543
8553
  if (!event.cwd) return null;
8544
- return path.join(api.getProjectPath(event.cwd), `${event.claudeSessionId}.jsonl`);
8554
+ return path.join(index.getProjectPath(event.cwd), `${event.claudeSessionId}.jsonl`);
8545
8555
  };
8546
8556
  const persistBinding = (binding) => {
8547
8557
  persistence.persistSession(binding.happySessionId, {
@@ -8557,8 +8567,8 @@ function createMirrorManager(deps) {
8557
8567
  };
8558
8568
  const sendMessages = (binding, messages) => {
8559
8569
  for (const message of messages) {
8560
- const key = api.mirrorLineKey(message);
8561
- binding.client.sendClaudeSessionMessage(message, key ? { localIdFor: (envelopeIndex) => api.mirrorLocalId(key, envelopeIndex) } : void 0);
8570
+ const key = index.mirrorLineKey(message);
8571
+ binding.client.sendClaudeSessionMessage(message, key ? { localIdFor: (envelopeIndex) => index.mirrorLocalId(key, envelopeIndex) } : void 0);
8562
8572
  }
8563
8573
  };
8564
8574
  const attachScanner = (binding, opts) => {
@@ -8662,7 +8672,7 @@ function createMirrorManager(deps) {
8662
8672
  archiveReason: void 0
8663
8673
  });
8664
8674
  const scanner = attachScanner(binding, { withTruncationNotice: false });
8665
- scanner.addFile(path.join(api.getProjectPath(meta.path), `${meta.claudeSessionId}.jsonl`), "backfill-tail");
8675
+ scanner.addFile(path.join(index.getProjectPath(meta.path), `${meta.claudeSessionId}.jsonl`), "backfill-tail");
8666
8676
  persistence.logger.debug(`[MIRROR] reconcile adopted terminal ${terminalId} \u2192 ${sessionId}`);
8667
8677
  deps.onBindingsChanged?.();
8668
8678
  };
@@ -8677,7 +8687,7 @@ function createMirrorManager(deps) {
8677
8687
  archiveReason: void 0
8678
8688
  });
8679
8689
  const scanner = binding.scanner ?? attachScanner(binding, { withTruncationNotice: false });
8680
- scanner.addFile(path.join(api.getProjectPath(binding.metadata.path), `${binding.claudeSessionId}.jsonl`), "backfill-tail");
8690
+ scanner.addFile(path.join(index.getProjectPath(binding.metadata.path), `${binding.claudeSessionId}.jsonl`), "backfill-tail");
8681
8691
  persistence.logger.debug(`[MIRROR] reconcile reactivated (in place) terminal ${binding.terminalId}`);
8682
8692
  deps.onBindingsChanged?.();
8683
8693
  };
@@ -8780,7 +8790,7 @@ function createMirrorManager(deps) {
8780
8790
  const parked = pendingCreates.get(event.terminalId);
8781
8791
  if (parked && pendingCreateSupersededBy(parked, event)) pendingCreates.delete(event.terminalId);
8782
8792
  const binding = bindings.get(event.terminalId) ?? null;
8783
- const decision = api.decideMirrorBinding(
8793
+ const decision = index.decideMirrorBinding(
8784
8794
  event,
8785
8795
  binding ? { status: binding.status, claudeSessionId: binding.claudeSessionId } : null
8786
8796
  );
@@ -8801,7 +8811,7 @@ function createMirrorManager(deps) {
8801
8811
  };
8802
8812
  return {
8803
8813
  handleHookPayload(body) {
8804
- const event = api.parseTerminalHookPayload(body);
8814
+ const event = index.parseTerminalHookPayload(body);
8805
8815
  if (!event) {
8806
8816
  persistence.logger.debug("[MIRROR] unparseable /terminal-hook payload dropped");
8807
8817
  return;
@@ -8929,7 +8939,7 @@ function createMirrorManager(deps) {
8929
8939
  };
8930
8940
  bindings.set(terminalId, binding);
8931
8941
  const scanner = attachScanner(binding, { withTruncationNotice: false });
8932
- scanner.addFile(path.join(api.getProjectPath(meta.path), `${meta.claudeSessionId}.jsonl`), "backfill-tail");
8942
+ scanner.addFile(path.join(index.getProjectPath(meta.path), `${meta.claudeSessionId}.jsonl`), "backfill-tail");
8933
8943
  persistence.logger.debug(`[MIRROR] restored binding terminal ${terminalId} \u2192 ${sessionId}`);
8934
8944
  deps.onBindingsChanged?.();
8935
8945
  }
@@ -9608,7 +9618,7 @@ function toSummary(id, persisted, extra) {
9608
9618
  };
9609
9619
  }
9610
9620
  async function listSessions(options = {}) {
9611
- const live = await api.listDaemonSessions();
9621
+ const live = await index.listDaemonSessions();
9612
9622
  return mergeSessionSummaries(live, persistence.readPersistedSessions(), options);
9613
9623
  }
9614
9624
  function summarizeAccountSession(row, persisted, liveIds, now) {
@@ -9678,7 +9688,7 @@ async function listAccountSessions(options = {}) {
9678
9688
  });
9679
9689
  const rows = Array.isArray(response.data?.sessions) ? response.data.sessions : [];
9680
9690
  const persisted = persistence.readPersistedSessions();
9681
- const live = await api.listDaemonSessions();
9691
+ const live = await index.listDaemonSessions();
9682
9692
  const liveIds = new Set(live.map((child) => child.happySessionId).filter((id) => typeof id === "string"));
9683
9693
  const now = Date.now();
9684
9694
  const summaries = rows.filter((row) => typeof row?.id === "string").map((row) => summarizeAccountSession(row, persisted[row.id], liveIds, now)).filter((summary) => options.includeArchived || !summary.archived);
@@ -9712,7 +9722,7 @@ async function readSessionTranscript(sessionId, limit) {
9712
9722
  const messages = Array.isArray(response.data?.messages) ? response.data.messages : [];
9713
9723
  messages.reverse();
9714
9724
  const key = persistence.decodeBase64(persisted.encryptionKey);
9715
- const live = await api.listDaemonSessions();
9725
+ const live = await index.listDaemonSessions();
9716
9726
  const bodies = messages.map((message) => {
9717
9727
  if (message.content?.t !== "encrypted") return null;
9718
9728
  try {
@@ -9728,7 +9738,7 @@ async function readSessionTranscript(sessionId, limit) {
9728
9738
  };
9729
9739
  }
9730
9740
  async function stopSession(sessionId) {
9731
- return await api.stopDaemonSession(sessionId);
9741
+ return await index.stopDaemonSession(sessionId);
9732
9742
  }
9733
9743
  async function archiveSession(sessionId) {
9734
9744
  const token = await bearerToken();
@@ -10038,6 +10048,10 @@ Use the teams tools to inspect current task state before acting. This message is
10038
10048
  } };
10039
10049
  }
10040
10050
 
10051
+ function daemonExitCode(source) {
10052
+ return source === "exception" ? 1 : 0;
10053
+ }
10054
+
10041
10055
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
10042
10056
  function sanitizeImportTitle(value) {
10043
10057
  if (typeof value !== "string") return null;
@@ -10046,7 +10060,7 @@ function sanitizeImportTitle(value) {
10046
10060
  return collapsed.length > 200 ? `${collapsed.slice(0, 199)}\u2026` : collapsed;
10047
10061
  }
10048
10062
  const hostSuffix = process.env.HAPPY_VARIANT === "dev" ? "-dev" : "";
10049
- const startupCliAvailability = api.detectCLIAvailability();
10063
+ const startupCliAvailability = index.detectCLIAvailability();
10050
10064
  const initialMachineMetadata = {
10051
10065
  teamsVersion: 1,
10052
10066
  teamLaunchVersion: 1,
@@ -10057,7 +10071,7 @@ const initialMachineMetadata = {
10057
10071
  happyHomeDir: persistence.configuration.happyHomeDir,
10058
10072
  happyLibDir: projectPath.projectPath(),
10059
10073
  cliAvailability: startupCliAvailability,
10060
- resumeSupport: { ...api.detectResumeSupport(), rpcAvailable: true }
10074
+ resumeSupport: { ...index.detectResumeSupport(), rpcAvailable: true }
10061
10075
  };
10062
10076
  async function preflightNewBundle(bundlePath) {
10063
10077
  const home = fs$1.mkdtempSync(path$1.join(os.tmpdir(), "vh-preflight-"));
@@ -10112,14 +10126,20 @@ async function startDaemon() {
10112
10126
  let cliUpdateStateRef = null;
10113
10127
  let lastHandoverHold = null;
10114
10128
  let claudeCredentialStoreSetting = (await persistence.readSettings()).claudeCredentialStore === "file" ? "file" : "auto";
10129
+ try {
10130
+ const homes = await index.refreshAgentHomes();
10131
+ persistence.logger.debug(`[DAEMON RUN] Claude config dir: ${index.describeAgentHome(homes.claudeConfigDir)}; Codex home: ${index.describeAgentHome(homes.codexHome)}`);
10132
+ } catch (error) {
10133
+ persistence.logger.debug("[DAEMON RUN] agent home resolution failed; using the daemon environment as-is", error);
10134
+ }
10115
10135
  let requestShutdown;
10116
10136
  let resolvesWhenShutdownRequested = new Promise((resolve) => {
10117
10137
  requestShutdown = (source, errorMessage) => {
10118
10138
  persistence.logger.debug(`[DAEMON RUN] Requesting shutdown (source: ${source}, errorMessage: ${errorMessage})`);
10119
10139
  setTimeout(async () => {
10120
- persistence.logger.debug("[DAEMON RUN] Startup malfunctioned, forcing exit with code 1");
10140
+ persistence.logger.debug(`[DAEMON RUN] Shutdown did not complete in time, forcing exit with code ${daemonExitCode(source)}`);
10121
10141
  await new Promise((resolve2) => setTimeout(resolve2, 100));
10122
- process.exit(1);
10142
+ process.exit(daemonExitCode(source));
10123
10143
  }, 1e3);
10124
10144
  resolve({ source, errorMessage });
10125
10145
  };
@@ -10156,7 +10176,7 @@ async function startDaemon() {
10156
10176
  });
10157
10177
  persistence.logger.debug("[DAEMON RUN] Starting daemon process...");
10158
10178
  persistence.logger.debugLargeJson("[DAEMON RUN] Environment", getEnvironmentInfo());
10159
- const runningDaemonVersionMatches = await api.isDaemonRunningCurrentlyInstalledHappyVersion();
10179
+ const runningDaemonVersionMatches = await index.isDaemonRunningCurrentlyInstalledHappyVersion();
10160
10180
  const runningDaemonState = await persistence.readDaemonState();
10161
10181
  const runningDaemonEndpointsMatch = Boolean(runningDaemonState) && daemonEndpointsMatch(
10162
10182
  runningDaemonState?.serverUrl,
@@ -10166,7 +10186,7 @@ async function startDaemon() {
10166
10186
  );
10167
10187
  if (!runningDaemonVersionMatches || !runningDaemonEndpointsMatch) {
10168
10188
  persistence.logger.debug("[DAEMON RUN] Daemon version or endpoint mismatch detected, restarting daemon");
10169
- await api.stopDaemon();
10189
+ await index.stopDaemon();
10170
10190
  } else {
10171
10191
  persistence.logger.debug("[DAEMON RUN] Daemon version matches, keeping existing daemon");
10172
10192
  console.log("Daemon already running with matching version");
@@ -10185,7 +10205,7 @@ async function startDaemon() {
10185
10205
  const { credentials, machineId } = await authAndSetupMachineIfNeeded();
10186
10206
  persistence.logger.debug("[DAEMON RUN] Auth and machine setup complete");
10187
10207
  const pidToTrackedSession = /* @__PURE__ */ new Map();
10188
- const turnActivity = new api.TurnActivityTracker();
10208
+ const turnActivity = new index.TurnActivityTracker();
10189
10209
  const sessionIdToFinishedSession = /* @__PURE__ */ new Map();
10190
10210
  let teamWorker;
10191
10211
  const persisted = persistence.readPersistedSessions();
@@ -10277,7 +10297,8 @@ async function startDaemon() {
10277
10297
  }
10278
10298
  };
10279
10299
  const assistantSpawnGate = createSpawnGate();
10280
- const spawnSession = (options) => {
10300
+ const spawnSession = async (options) => {
10301
+ await index.refreshAgentHomes();
10281
10302
  if (assistantSpawnMode(options) !== "claude-singleton") {
10282
10303
  return spawnSessionImpl(options);
10283
10304
  }
@@ -10285,7 +10306,7 @@ async function startDaemon() {
10285
10306
  };
10286
10307
  const currentCliAvailability = () => apiMachineRef?.getCLIAvailability() ?? startupCliAvailability;
10287
10308
  const spawnSessionImpl = async (options) => {
10288
- persistence.logger.debugLargeJson("[DAEMON RUN] Spawning session", api.summarizeSpawnSessionForLog(options));
10309
+ persistence.logger.debugLargeJson("[DAEMON RUN] Spawning session", index.summarizeSpawnSessionForLog(options));
10289
10310
  const spawnModel = options.agent === "pi" ? sanitizeSpawnModel(options.model) : null;
10290
10311
  const spawnPermissionMode = sanitizeSpawnPermissionMode(options.permissionMode);
10291
10312
  if (options.permissionMode !== void 0 && spawnPermissionMode === null) {
@@ -10350,7 +10371,7 @@ async function startDaemon() {
10350
10371
  s.encryptionVariant
10351
10372
  );
10352
10373
  const claudeSessionId = resolveAssistantClaudeSessionId(s.metadata, serverMetadata);
10353
- const canResumeClaude = !!claudeSessionId && fs$1.existsSync(path$1.join(api.getProjectPath(assistantHome()), `${claudeSessionId}.jsonl`));
10374
+ const canResumeClaude = !!claudeSessionId && index.locateClaudeConversation(assistantHome(), claudeSessionId) !== null;
10354
10375
  return spawnTrackedHappyProcess({
10355
10376
  args: [
10356
10377
  "claude",
@@ -10369,6 +10390,8 @@ async function startDaemon() {
10369
10390
  // B-297: see the resume/restart paths — every spawn carries the
10370
10391
  // credentialStore=file shim, not just fresh sessions (B-276 D8).
10371
10392
  ...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {},
10393
+ // B-478: point Claude at the directory the transcript was found in.
10394
+ ...canResumeClaude ? index.agentHomeSpawnEnv({ workingDirectory: assistantHome(), claudeSessionId }) : {},
10372
10395
  HAPPY_SESSION_VARIANT: "assistant",
10373
10396
  HAPPY_RECONNECT_SESSION_ID: assistantSessionId,
10374
10397
  HAPPY_RECONNECT_ENCRYPTION_KEY: s.encryptionKey,
@@ -10512,9 +10535,9 @@ async function startDaemon() {
10512
10535
  };
10513
10536
  }
10514
10537
  const resumeId = agent === "claude" ? options.resumeClaudeSessionId : agent === "codex" ? options.resumeCodexThreadId : void 0;
10515
- const resumeFragment = resumeId ? ` --resume ${api.shellescape(resumeId)}` : "";
10516
- const permissionModeFragment = spawnPermissionMode ? ` --permission-mode ${api.shellescape(spawnPermissionMode)}` : "";
10517
- const modelFragment = spawnModel ? ` --model ${api.shellescape(spawnModel)}` : "";
10538
+ const resumeFragment = resumeId ? ` --resume ${index.shellescape(resumeId)}` : "";
10539
+ const permissionModeFragment = spawnPermissionMode ? ` --permission-mode ${index.shellescape(spawnPermissionMode)}` : "";
10540
+ const modelFragment = spawnModel ? ` --model ${index.shellescape(spawnModel)}` : "";
10518
10541
  const fullCommand = `node --no-warnings --no-deprecation ${cliPath} ${agent} --happy-starting-mode remote --started-by daemon${resumeFragment}${permissionModeFragment}${modelFragment}`;
10519
10542
  const windowName = `happy-${Date.now()}-${agent}`;
10520
10543
  const tmuxEnv = {};
@@ -10523,6 +10546,7 @@ async function startDaemon() {
10523
10546
  tmuxEnv[key] = value;
10524
10547
  }
10525
10548
  }
10549
+ Object.assign(tmuxEnv, index.agentHomeSpawnEnv({ workingDirectory: directory, claudeSessionId: options.resumeClaudeSessionId, codexThreadId: options.resumeCodexThreadId }));
10526
10550
  Object.assign(tmuxEnv, extraEnv);
10527
10551
  const tmuxResult = await tmux.spawnInTmux([fullCommand], {
10528
10552
  sessionName: tmuxSessionName,
@@ -10617,6 +10641,9 @@ async function startDaemon() {
10617
10641
  cwd: directory,
10618
10642
  env: {
10619
10643
  ...process.env,
10644
+ // B-478: a fork/duplicate resumes a transcript that may live in
10645
+ // a moved config dir. Explicit environmentVariables still win.
10646
+ ...index.agentHomeSpawnEnv({ workingDirectory: directory, claudeSessionId: options.resumeClaudeSessionId, codexThreadId: options.resumeCodexThreadId }),
10620
10647
  ...extraEnv
10621
10648
  },
10622
10649
  directoryCreated,
@@ -10767,6 +10794,7 @@ async function startDaemon() {
10767
10794
  gate = createSpawnGate();
10768
10795
  resumeGates.set(happySessionId, gate);
10769
10796
  }
10797
+ await index.refreshAgentHomes();
10770
10798
  try {
10771
10799
  return await gate.join(() => resumeSessionImpl(happySessionId, options));
10772
10800
  } finally {
@@ -10813,7 +10841,9 @@ async function startDaemon() {
10813
10841
  }
10814
10842
  const precheck = resumePrecheck(metadata, {
10815
10843
  cwdExists: (p) => fs$1.existsSync(p),
10816
- conversationExists: (cwd, claudeSessionId) => fs$1.existsSync(path$1.join(api.getProjectPath(cwd), `${claudeSessionId}.jsonl`))
10844
+ // B-478: also looks in every other Claude config dir the user's shell
10845
+ // or settings point at, not just the one the daemon was started with.
10846
+ conversationExists: (cwd, claudeSessionId) => index.locateClaudeConversation(cwd, claudeSessionId) !== null
10817
10847
  });
10818
10848
  let freshConversation = false;
10819
10849
  if (!precheck.ok) {
@@ -10844,6 +10874,9 @@ async function startDaemon() {
10844
10874
  // fell back to `auto` reads a different credential store than the
10845
10875
  // fresh one next to it (B-276 D8).
10846
10876
  ...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {},
10877
+ // B-478: if the transcript lives in a Claude/Codex home other than
10878
+ // the resolved one, this spawn is pointed there.
10879
+ ...freshConversation ? {} : index.agentHomeSpawnEnv({ workingDirectory: launch.cwd, claudeSessionId: metadata.claudeSessionId, codexThreadId: metadata.codexThreadId }),
10847
10880
  HAPPY_RECONNECT_SESSION_ID: happySessionId,
10848
10881
  HAPPY_RECONNECT_ENCRYPTION_KEY: persistence.encodeBase64(tracked.encryption.encryptionKey),
10849
10882
  HAPPY_RECONNECT_ENCRYPTION_VARIANT: tracked.encryption.encryptionVariant,
@@ -10905,6 +10938,7 @@ async function startDaemon() {
10905
10938
  gate = createSpawnGate();
10906
10939
  resumeGates.set(happySessionId, gate);
10907
10940
  }
10941
+ await index.refreshAgentHomes();
10908
10942
  try {
10909
10943
  return await gate.replace(() => restartSessionImpl(happySessionId, options));
10910
10944
  } finally {
@@ -10940,7 +10974,9 @@ async function startDaemon() {
10940
10974
  }
10941
10975
  const precheck = resumePrecheck(metadata, {
10942
10976
  cwdExists: (p) => fs$1.existsSync(p),
10943
- conversationExists: (cwd2, claudeSessionId) => fs$1.existsSync(path$1.join(api.getProjectPath(cwd2), `${claudeSessionId}.jsonl`))
10977
+ // B-478: also looks in every other Claude config dir the user's shell
10978
+ // or settings point at, not just the one the daemon was started with.
10979
+ conversationExists: (cwd2, claudeSessionId) => index.locateClaudeConversation(cwd2, claudeSessionId) !== null
10944
10980
  });
10945
10981
  let args;
10946
10982
  let cwd;
@@ -10975,6 +11011,8 @@ async function startDaemon() {
10975
11011
  // fell back to `auto` reads a different credential store than the
10976
11012
  // fresh one next to it (B-276 D8).
10977
11013
  ...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {},
11014
+ // B-478: see resumeSession.
11015
+ ...precheck.ok ? index.agentHomeSpawnEnv({ workingDirectory: cwd, claudeSessionId: metadata.claudeSessionId, codexThreadId: metadata.codexThreadId }) : {},
10978
11016
  HAPPY_RECONNECT_SESSION_ID: happySessionId,
10979
11017
  HAPPY_RECONNECT_ENCRYPTION_KEY: persistence.encodeBase64(tracked.encryption.encryptionKey),
10980
11018
  HAPPY_RECONNECT_ENCRYPTION_VARIANT: tracked.encryption.encryptionVariant,
@@ -11152,8 +11190,8 @@ async function startDaemon() {
11152
11190
  httpPort: controlPort,
11153
11191
  startedAt: Date.now()
11154
11192
  };
11155
- const api$1 = await api.ApiClient.create(credentials);
11156
- const machine = await api$1.getOrCreateMachine({
11193
+ const api = await index.ApiClient.create(credentials);
11194
+ const machine = await api.getOrCreateMachine({
11157
11195
  machineId,
11158
11196
  metadata: initialMachineMetadata,
11159
11197
  daemonState: initialDaemonState
@@ -11167,10 +11205,10 @@ async function startDaemon() {
11167
11205
  if (identityConflict) {
11168
11206
  persistence.logger.warn(`[DAEMON RUN] machine identity conflict (${identityConflict.confidence}): ${describeMachineIdentityConflict(identityConflict)}`);
11169
11207
  }
11170
- const apiMachine = api$1.machineSyncClient(machine);
11208
+ const apiMachine = api.machineSyncClient(machine);
11171
11209
  apiMachineRef = apiMachine;
11172
11210
  const mirrorManager = createMirrorManager({
11173
- api: api$1,
11211
+ api,
11174
11212
  machineId,
11175
11213
  onBindingsChanged: () => apiMachine.requestTerminalListRefresh()
11176
11214
  });
@@ -11221,7 +11259,7 @@ async function startDaemon() {
11221
11259
  }
11222
11260
  let lastUpdateLog = "";
11223
11261
  const updateController = createUpdateController({
11224
- policy: () => api.fetchCliUpdateState(persistence.configuration.serverUrl, persistence.packageJson.version),
11262
+ policy: () => index.fetchCliUpdateState(persistence.configuration.serverUrl, persistence.packageJson.version),
11225
11263
  enabled: async () => ((await persistence.readSettings()).cliAutoUpdate ?? "idle") !== "off",
11226
11264
  // B-466: "idle" = no agent turn in flight. Idle wrappers survive a
11227
11265
  // handover (they talk to the server themselves) and web terminals live
@@ -11248,9 +11286,9 @@ async function startDaemon() {
11248
11286
  persistence.logger.debug("[DAEMON RUN] CLI update policy check failed:", error);
11249
11287
  });
11250
11288
  void refreshCliUpdate();
11251
- const cliUpdateIntervalMs = api.resolveCliUpdateCheckInterval(process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL);
11252
- if (process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL && cliUpdateIntervalMs === api.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS && process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL.trim() !== String(api.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS)) {
11253
- persistence.logger.warn(`[DAEMON RUN] Ignoring invalid HAPPY_CLI_UPDATE_CHECK_INTERVAL; using ${api.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS}ms`);
11289
+ const cliUpdateIntervalMs = index.resolveCliUpdateCheckInterval(process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL);
11290
+ if (process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL && cliUpdateIntervalMs === index.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS && process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL.trim() !== String(index.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS)) {
11291
+ persistence.logger.warn(`[DAEMON RUN] Ignoring invalid HAPPY_CLI_UPDATE_CHECK_INTERVAL; using ${index.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS}ms`);
11254
11292
  }
11255
11293
  const cliUpdateInterval = setInterval(() => void refreshCliUpdate(), cliUpdateIntervalMs);
11256
11294
  const stopAgentVersionChecks = startAgentVersionChecks(
@@ -11301,7 +11339,7 @@ async function startDaemon() {
11301
11339
  claudeAuthService.stop();
11302
11340
  apiMachine.shutdown();
11303
11341
  await stopControlServer();
11304
- await api.cleanupDaemonState();
11342
+ await index.cleanupDaemonState();
11305
11343
  await persistence.releaseDaemonLock(daemonLockHandle);
11306
11344
  await stopCaffeinate();
11307
11345
  try {
@@ -11374,11 +11412,11 @@ async function startDaemon() {
11374
11412
  }
11375
11413
  apiMachine.shutdown();
11376
11414
  await stopControlServer();
11377
- await api.cleanupDaemonState();
11415
+ await index.cleanupDaemonState();
11378
11416
  await stopCaffeinate();
11379
11417
  await persistence.releaseDaemonLock(daemonLockHandle);
11380
- persistence.logger.debug("[DAEMON RUN] Cleanup completed, exiting process");
11381
- process.exit(0);
11418
+ persistence.logger.debug(`[DAEMON RUN] Cleanup completed, exiting process with code ${daemonExitCode(source)}`);
11419
+ process.exit(daemonExitCode(source));
11382
11420
  };
11383
11421
  persistence.logger.debug("[DAEMON RUN] Daemon started successfully, waiting for shutdown request");
11384
11422
  const shutdownRequest = await resolvesWhenShutdownRequested;
@@ -11641,7 +11679,7 @@ ${sessions.map(describeSummary).join("\n")}`);
11641
11679
  limit: z.z.number().optional().describe("How many recent messages to fetch (default 20, max 100)")
11642
11680
  }
11643
11681
  }, async (args) => {
11644
- if (!api.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11682
+ if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11645
11683
  try {
11646
11684
  const result = await readSessionTranscript(args.sessionId, args.limit ?? 20);
11647
11685
  const body = result.transcript.length > 0 ? result.transcript : "(no readable conversation content in this range)";
@@ -11660,7 +11698,7 @@ ${body}`);
11660
11698
  text: z.z.string().describe("The message text to send")
11661
11699
  }
11662
11700
  }, async (args) => {
11663
- if (!api.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11701
+ if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11664
11702
  if (typeof args.text !== "string" || args.text.trim().length === 0) return fail("text must be non-empty");
11665
11703
  try {
11666
11704
  const persisted = await waitForSessionKey(args.sessionId, 0);
@@ -11682,7 +11720,7 @@ ${body}`);
11682
11720
  if (!normalized.ok) return fail(normalized.error);
11683
11721
  const directory = normalized.directory;
11684
11722
  try {
11685
- const result = await api.spawnDaemonSession(directory, void 0, { spawnedBy: "assistant" });
11723
+ const result = await index.spawnDaemonSession(directory, void 0, { spawnedBy: "assistant" });
11686
11724
  if (result?.error || !result?.sessionId) {
11687
11725
  return fail(`Failed to spawn session: ${result?.error ?? "daemon returned no session id"}`);
11688
11726
  }
@@ -11709,7 +11747,7 @@ ${body}`);
11709
11747
  sessionId: z.z.string().describe("The Happy session id to stop")
11710
11748
  }
11711
11749
  }, async (args) => {
11712
- if (!api.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11750
+ if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11713
11751
  try {
11714
11752
  const persisted = persistence.readPersistedSessions()[args.sessionId];
11715
11753
  const success = await stopSession(args.sessionId);
@@ -11726,7 +11764,7 @@ ${body}`);
11726
11764
  sessionId: z.z.string().describe("The Happy session id to archive")
11727
11765
  }
11728
11766
  }, async (args) => {
11729
- if (!api.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11767
+ if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
11730
11768
  try {
11731
11769
  await archiveSession(args.sessionId);
11732
11770
  const persisted = persistence.readPersistedSessions()[args.sessionId];
@@ -11742,7 +11780,7 @@ function registerAssistantMachineTools(mcp) {
11742
11780
  title: "List Terminals",
11743
11781
  inputSchema: {}
11744
11782
  }, async () => {
11745
- const r = api.listVhTerminals();
11783
+ const r = index.listVhTerminals();
11746
11784
  if (!r.ok) return fail(`Failed to list terminals: ${r.error}`);
11747
11785
  if (r.terminals.length === 0) return ok("No web terminals are open on this machine.");
11748
11786
  const lines = r.terminals.map((t) => {
@@ -11762,8 +11800,8 @@ ${lines.join("\n")}`);
11762
11800
  lines: z.z.number().optional().describe("How many history lines to read (default 80, max 2000)")
11763
11801
  }
11764
11802
  }, async (args) => {
11765
- if (!api.isValidTerminalId(args.terminalId)) return fail("Invalid terminalId");
11766
- const r = api.readVhTerminal(args.terminalId, args.lines ?? 80);
11803
+ if (!index.isValidTerminalId(args.terminalId)) return fail("Invalid terminalId");
11804
+ const r = index.readVhTerminal(args.terminalId, args.lines ?? 80);
11767
11805
  if (!r.ok) return fail(`Failed to read terminal ${args.terminalId}: ${r.error}`);
11768
11806
  return ok(`terminal ${args.terminalId} \u2014 last output:
11769
11807
  ${r.text}`);
@@ -11777,10 +11815,10 @@ ${r.text}`);
11777
11815
  submit: z.z.boolean().optional().describe("Also press Enter after pasting (default false)")
11778
11816
  }
11779
11817
  }, async (args) => {
11780
- if (!api.isValidTerminalId(args.terminalId)) return fail("Invalid terminalId");
11818
+ if (!index.isValidTerminalId(args.terminalId)) return fail("Invalid terminalId");
11781
11819
  if (typeof args.text !== "string" || args.text.length === 0) return fail("text must be non-empty");
11782
11820
  const submit = args.submit === true;
11783
- const r = api.sendToVhTerminal(args.terminalId, args.text, submit);
11821
+ const r = index.sendToVhTerminal(args.terminalId, args.text, submit);
11784
11822
  if (!r.ok) return fail(`Failed to send to terminal ${args.terminalId}: ${r.error}`);
11785
11823
  return ok(submit ? `Pasted and submitted (Enter sent) in terminal ${args.terminalId}.` : `Pasted into terminal ${args.terminalId} WITHOUT pressing Enter \u2014 the user (or a follow-up terminal_send with submit=true) decides whether it runs.`);
11786
11824
  });
@@ -12052,7 +12090,7 @@ async function startHappyServer(client, options) {
12052
12090
  return;
12053
12091
  }
12054
12092
  }
12055
- const usage = api.ContextUsageSchema.parse({ ...JSON.parse(body), updatedAt: Date.now() });
12093
+ const usage = index.ContextUsageSchema.parse({ ...JSON.parse(body), updatedAt: Date.now() });
12056
12094
  options.onContextUsage(usage);
12057
12095
  res.writeHead(204).end();
12058
12096
  } catch {
@@ -12372,7 +12410,7 @@ function registerSideQuestionHandler(rpc, deps) {
12372
12410
  const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
12373
12411
  const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
12374
12412
  const run = deps.run ?? (async (input) => {
12375
- const { query } = await Promise.resolve().then(function () { return require('./index-Bom8mTuS.cjs'); });
12413
+ const { query } = await Promise.resolve().then(function () { return require('./index-DIoSNgtt.cjs'); });
12376
12414
  return runSideQuestion(query, input);
12377
12415
  });
12378
12416
  const slots = /* @__PURE__ */ new Map();
@@ -12474,7 +12512,7 @@ const MAX_TITLE_CHARS = 60;
12474
12512
  const GENERATION_TIMEOUT_MS = 3e4;
12475
12513
  function resolveClaudeBinary() {
12476
12514
  try {
12477
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-CSQZhQ0C.cjs', document.baseURI).href)));
12515
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Dn0JMM8l.cjs', document.baseURI).href)));
12478
12516
  const utilsPath = path.resolve(path.join(projectPath.projectPath(), "scripts", "claude_version_utils.cjs"));
12479
12517
  const { getClaudeCliPath } = require$1(utilsPath);
12480
12518
  const path$1 = getClaudeCliPath();
@@ -12486,7 +12524,7 @@ function resolveClaudeBinary() {
12486
12524
  }
12487
12525
  function buildPrompt(firstUserMessage) {
12488
12526
  const sample = firstUserMessage.slice(0, MAX_PROMPT_SAMPLE_CHARS);
12489
- return `${api.TITLE_PROMPT_PREFIX} (match the message's language). Be concrete \u2014 name the actual task/subject. Do NOT output generic placeholders like "\u65B0\u5BF9\u8BDD"/"New chat"/"Conversation"/"Untitled". No quotes, no trailing punctuation. Reply with ONLY the title.
12527
+ return `${index.TITLE_PROMPT_PREFIX} (match the message's language). Be concrete \u2014 name the actual task/subject. Do NOT output generic placeholders like "\u65B0\u5BF9\u8BDD"/"New chat"/"Conversation"/"Untitled". No quotes, no trailing punctuation. Reply with ONLY the title.
12490
12528
 
12491
12529
  Message: "${sample}"`;
12492
12530
  }
@@ -12682,7 +12720,7 @@ function buildBoardPrompt(input) {
12682
12720
  const taskLines = tasks.length > 0 ? tasks.map((t) => `- ${t.id}: ${t.title}`).join("\n") : "(no tasks defined)";
12683
12721
  const todoBlock = input.todos.length > 0 ? input.todos.join("\n") : "(none)";
12684
12722
  return [
12685
- `${api.BOARD_ANALYZER_PROMPT_PREFIX} Analyze this session snapshot and reply with ONLY a strict JSON object, no markdown, no explanations:`,
12723
+ `${index.BOARD_ANALYZER_PROMPT_PREFIX} Analyze this session snapshot and reply with ONLY a strict JSON object, no markdown, no explanations:`,
12686
12724
  '{"taskId": string|null, "attention": "none"|"review"|"blocked", "progress": string}',
12687
12725
  "",
12688
12726
  "Rules:",
@@ -12886,8 +12924,8 @@ async function runClaude(credentials, options = {}) {
12886
12924
  if (options.startedBy === "daemon" && options.startingMode === "local") {
12887
12925
  throw new Error("Daemon-spawned sessions cannot use local/interactive mode. Use --happy-starting-mode remote or spawn sessions directly from terminal.");
12888
12926
  }
12889
- api.connectionState.setBackend("Claude");
12890
- const api$1 = await api.ApiClient.create(credentials);
12927
+ index.connectionState.setBackend("Claude");
12928
+ const api = await index.ApiClient.create(credentials);
12891
12929
  let state = {};
12892
12930
  const settings = await persistence.readSettings();
12893
12931
  let machineId = settings?.machineId;
@@ -12904,7 +12942,7 @@ async function runClaude(credentials, options = {}) {
12904
12942
  }
12905
12943
  persistence.logger.debug(`Using machineId: ${machineId}`);
12906
12944
  const sessionTag = node_crypto.randomUUID();
12907
- await api$1.getOrCreateMachine({
12945
+ await api.getOrCreateMachine({
12908
12946
  machineId,
12909
12947
  metadata: initialMachineMetadata
12910
12948
  });
@@ -12974,16 +13012,16 @@ async function runClaude(credentials, options = {}) {
12974
13012
  agentStateVersion: parseInt(reconnectAgentStateVersion || "0", 10)
12975
13013
  };
12976
13014
  } else {
12977
- response = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
13015
+ response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
12978
13016
  }
12979
13017
  if (!response) {
12980
13018
  let offlineSessionId = null;
12981
- const reconnection = api.startOfflineReconnection({
13019
+ const reconnection = index.startOfflineReconnection({
12982
13020
  serverUrl: persistence.configuration.serverUrl,
12983
13021
  onReconnected: async () => {
12984
- const resp = await api$1.getOrCreateSession({ tag: node_crypto.randomUUID(), metadata, state });
13022
+ const resp = await api.getOrCreateSession({ tag: node_crypto.randomUUID(), metadata, state });
12985
13023
  if (!resp) throw new Error("Server unavailable");
12986
- const session2 = api$1.sessionSyncClient(resp);
13024
+ const session2 = api.sessionSyncClient(resp);
12987
13025
  const scanner = await createSessionScanner({
12988
13026
  sessionId: null,
12989
13027
  workingDirectory,
@@ -13019,12 +13057,12 @@ async function runClaude(credentials, options = {}) {
13019
13057
  }
13020
13058
  persistence.logger.debug(`Session created: ${response.id}`);
13021
13059
  await claimSessionOrExit(response.id, { takeover: !!reconnectSessionId, flavor: "claude" });
13022
- if (reconnectSessionId && !await api$1.reactivateSession(response.id)) {
13060
+ if (reconnectSessionId && !await api.reactivateSession(response.id)) {
13023
13061
  throw new Error(`Failed to reactivate archived session ${response.id}`);
13024
13062
  }
13025
13063
  let reconnectSeeded = false;
13026
13064
  if (reconnectSessionId) {
13027
- const snapshot = await api$1.getSession(response.id, response.encryptionKey, response.encryptionVariant);
13065
+ const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
13028
13066
  if (snapshot.ok) {
13029
13067
  response = applyServerSnapshot(response, snapshot.session);
13030
13068
  reconnectSeeded = true;
@@ -13036,7 +13074,7 @@ async function runClaude(credentials, options = {}) {
13036
13074
  }
13037
13075
  try {
13038
13076
  persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
13039
- const result = await api.notifyDaemonSessionStarted(response.id, metadata, {
13077
+ const result = await index.notifyDaemonSessionStarted(response.id, metadata, {
13040
13078
  encryptionKey: persistence.encodeBase64(response.encryptionKey),
13041
13079
  encryptionVariant: response.encryptionVariant,
13042
13080
  seq: response.seq,
@@ -13051,7 +13089,7 @@ async function runClaude(credentials, options = {}) {
13051
13089
  } catch (error) {
13052
13090
  persistence.logger.debug("[START] Failed to report to daemon (may not be running):", error);
13053
13091
  }
13054
- const session = api$1.sessionSyncClient(response, reconnectSeeded ? { initialSeq: response.seq } : void 0);
13092
+ const session = api.sessionSyncClient(response, reconnectSeeded ? { initialSeq: response.seq } : void 0);
13055
13093
  if (reconnectSessionId) {
13056
13094
  session.suppressNextArchiveSignal();
13057
13095
  if (!reconnectSeeded) session.skipExistingMessages();
@@ -13067,7 +13105,7 @@ async function runClaude(credentials, options = {}) {
13067
13105
  }
13068
13106
  const forkClaudeSessionId = process.env.HAPPY_FORK_CLAUDE_SESSION_ID;
13069
13107
  if (!reconnectSessionId && forkClaudeSessionId) {
13070
- const jsonlPath = path.join(api.getProjectPath(workingDirectory), `${forkClaudeSessionId}.jsonl`);
13108
+ const jsonlPath = path.join(index.getProjectPath(workingDirectory), `${forkClaudeSessionId}.jsonl`);
13071
13109
  try {
13072
13110
  const file = await promises.readFile(jsonlPath, "utf-8");
13073
13111
  const lines = file.split("\n");
@@ -13080,7 +13118,7 @@ async function runClaude(credentials, options = {}) {
13080
13118
  } catch {
13081
13119
  continue;
13082
13120
  }
13083
- const result = api.RawJSONLinesSchema.safeParse(parsed);
13121
+ const result = index.RawJSONLinesSchema.safeParse(parsed);
13084
13122
  if (!result.success) continue;
13085
13123
  session.sendClaudeSessionMessage(result.data);
13086
13124
  backfilled += 1;
@@ -13122,7 +13160,7 @@ async function runClaude(credentials, options = {}) {
13122
13160
  enabled: settings?.boardLlm === true,
13123
13161
  selfReportState: boardSelfReport,
13124
13162
  fetchTasks: async () => {
13125
- const item = await api$1.kvGet("vh.board-tasks.v1");
13163
+ const item = await api.kvGet("vh.board-tasks.v1");
13126
13164
  if (!item) return null;
13127
13165
  try {
13128
13166
  const parsed = JSON.parse(Buffer.from(item.value, "base64").toString("utf8"));
@@ -13158,7 +13196,7 @@ async function runClaude(credentials, options = {}) {
13158
13196
  let currentSession = null;
13159
13197
  const hookServer = await startHookServer({
13160
13198
  onSessionHook: (sessionId, data) => {
13161
- persistence.logger.debug(`[START] Session hook received: ${sessionId}`, api.contentLogMetadata(data));
13199
+ persistence.logger.debug(`[START] Session hook received: ${sessionId}`, index.contentLogMetadata(data));
13162
13200
  remoteScanner.onNewSession(sessionId, { treatExistingAsProcessed: true });
13163
13201
  if (currentSession) {
13164
13202
  const previousSessionId = currentSession.sessionId;
@@ -13376,7 +13414,7 @@ async function runClaude(credentials, options = {}) {
13376
13414
  };
13377
13415
  messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
13378
13416
  persistence.logger.debug("[start] /compact command pushed to queue:", {
13379
- ...api.contentLogMetadata(message.content.text),
13417
+ ...index.contentLogMetadata(message.content.text),
13380
13418
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
13381
13419
  hasMetadata: Boolean(message.meta)
13382
13420
  });
@@ -13396,7 +13434,7 @@ async function runClaude(credentials, options = {}) {
13396
13434
  };
13397
13435
  messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
13398
13436
  persistence.logger.debug("[start] /clear command pushed to queue:", {
13399
- ...api.contentLogMetadata(message.content.text),
13437
+ ...index.contentLogMetadata(message.content.text),
13400
13438
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
13401
13439
  hasMetadata: Boolean(message.meta)
13402
13440
  });
@@ -13458,7 +13496,7 @@ async function runClaude(credentials, options = {}) {
13458
13496
  }) === true;
13459
13497
  if (accepted) {
13460
13498
  persistence.logger.debug("User message steered into current turn:", {
13461
- ...api.contentLogMetadata(message.content.text),
13499
+ ...index.contentLogMetadata(message.content.text),
13462
13500
  attachmentCount: attachmentsForThisMessage?.length ?? 0
13463
13501
  });
13464
13502
  return;
@@ -13467,7 +13505,7 @@ async function runClaude(credentials, options = {}) {
13467
13505
  }
13468
13506
  messageQueue.push(message.content.text, enhancedMode, attachmentsForThisMessage, message.localKey);
13469
13507
  persistence.logger.debug("User message pushed to queue:", {
13470
- ...api.contentLogMetadata(message.content.text),
13508
+ ...index.contentLogMetadata(message.content.text),
13471
13509
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
13472
13510
  hasMetadata: Boolean(message.meta)
13473
13511
  });
@@ -13488,7 +13526,7 @@ async function runClaude(credentials, options = {}) {
13488
13526
  currentSession?.cleanup();
13489
13527
  session.sendSessionDeath();
13490
13528
  try {
13491
- await api$1.deactivateSession(session.sessionId);
13529
+ await api.deactivateSession(session.sessionId);
13492
13530
  } catch (err) {
13493
13531
  persistence.logger.debug("[START] deactivateSession during cleanup failed:", err);
13494
13532
  }
@@ -13535,7 +13573,7 @@ async function runClaude(credentials, options = {}) {
13535
13573
  permissionMode: initialPermissionMode,
13536
13574
  startingMode: options.startingMode,
13537
13575
  messageQueue,
13538
- api: api$1,
13576
+ api,
13539
13577
  allowedTools: happyServer.toolNames.map((toolName) => `mcp__happy__${toolName}`),
13540
13578
  onModeChange: (newMode) => {
13541
13579
  currentRunMode = newMode;
@@ -13764,7 +13802,7 @@ async function handleAuthLogin(args) {
13764
13802
  console.log(chalk.gray(" \u2022 Re-authenticate and register machine\n"));
13765
13803
  try {
13766
13804
  persistence.logger.debug("Stopping daemon for force auth...");
13767
- await api.stopDaemon();
13805
+ await index.stopDaemon();
13768
13806
  console.log(chalk.gray("\u2713 Stopped daemon"));
13769
13807
  } catch (error) {
13770
13808
  persistence.logger.debug("Daemon was not running or failed to stop:", error);
@@ -13829,7 +13867,7 @@ async function handleAuthLogout() {
13829
13867
  if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
13830
13868
  try {
13831
13869
  try {
13832
- await api.stopDaemon();
13870
+ await index.stopDaemon();
13833
13871
  console.log(chalk.gray("Stopped daemon"));
13834
13872
  } catch {
13835
13873
  }
@@ -13874,7 +13912,7 @@ async function handleAuthStatus() {
13874
13912
  console.log(chalk.gray(`
13875
13913
  Data directory: ${persistence.configuration.happyHomeDir}`));
13876
13914
  try {
13877
- const running = await api.checkIfDaemonRunningAndCleanupStaleState();
13915
+ const running = await index.checkIfDaemonRunningAndCleanupStaleState();
13878
13916
  if (running) {
13879
13917
  console.log(chalk.green("\u2713 Daemon running"));
13880
13918
  } else {
@@ -14436,23 +14474,23 @@ async function handleConnectVendor(vendor, displayName) {
14436
14474
  console.log(chalk.gray(' Please run "very-happy auth login" first'));
14437
14475
  process.exit(1);
14438
14476
  }
14439
- const api$1 = await api.ApiClient.create(credentials);
14477
+ const api = await index.ApiClient.create(credentials);
14440
14478
  if (vendor === "codex") {
14441
14479
  console.log("\u{1F680} Registering Codex token with server");
14442
14480
  const codexAuthTokens = await authenticateCodex();
14443
- await api$1.registerVendorToken("openai", { oauth: codexAuthTokens });
14481
+ await api.registerVendorToken("openai", { oauth: codexAuthTokens });
14444
14482
  console.log("\u2705 Codex token registered with server");
14445
14483
  process.exit(0);
14446
14484
  } else if (vendor === "claude") {
14447
14485
  console.log("\u{1F680} Registering Anthropic token with server");
14448
14486
  const anthropicAuthTokens = await authenticateClaude();
14449
- await api$1.registerVendorToken("anthropic", { oauth: anthropicAuthTokens });
14487
+ await api.registerVendorToken("anthropic", { oauth: anthropicAuthTokens });
14450
14488
  console.log("\u2705 Anthropic token registered with server");
14451
14489
  process.exit(0);
14452
14490
  } else if (vendor === "gemini") {
14453
14491
  console.log("\u{1F680} Registering Gemini token with server");
14454
14492
  const geminiAuthTokens = await authenticateGemini();
14455
- await api$1.registerVendorToken("gemini", { oauth: geminiAuthTokens });
14493
+ await api.registerVendorToken("gemini", { oauth: geminiAuthTokens });
14456
14494
  console.log("\u2705 Gemini token registered with server");
14457
14495
  updateLocalGeminiCredentials(geminiAuthTokens);
14458
14496
  process.exit(0);
@@ -14468,7 +14506,7 @@ async function handleConnectStatus() {
14468
14506
  console.log(chalk.gray(' Please run "very-happy auth login" first'));
14469
14507
  process.exit(1);
14470
14508
  }
14471
- const api$1 = await api.ApiClient.create(credentials);
14509
+ const api = await index.ApiClient.create(credentials);
14472
14510
  const vendors = [
14473
14511
  { key: "gemini", name: "Gemini", display: "Google Gemini" },
14474
14512
  { key: "openai", name: "Codex", display: "OpenAI Codex" },
@@ -14476,7 +14514,7 @@ async function handleConnectStatus() {
14476
14514
  ];
14477
14515
  for (const vendor of vendors) {
14478
14516
  try {
14479
- const token = await api$1.getVendorToken(vendor.key);
14517
+ const token = await api.getVendorToken(vendor.key);
14480
14518
  if (token?.oauth) {
14481
14519
  let userInfo = "";
14482
14520
  if (token.oauth.id_token) {
@@ -14700,9 +14738,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
14700
14738
  };
14701
14739
  }
14702
14740
 
14703
- const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-CSQZhQ0C.cjs', document.baseURI).href)));
14741
+ const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Dn0JMM8l.cjs', document.baseURI).href)));
14704
14742
  const __dirname$1 = path.dirname(__filename$1);
14705
- const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-CSQZhQ0C.cjs', document.baseURI).href)));
14743
+ const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Dn0JMM8l.cjs', document.baseURI).href)));
14706
14744
  const PRISMA_QUERY_ENGINE_FILES = {
14707
14745
  "arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
14708
14746
  "x64-darwin": "libquery_engine-darwin.dylib.node",
@@ -15091,7 +15129,7 @@ const DAEMON_READY_TIMEOUT_MS = 5e3;
15091
15129
  const DAEMON_READY_POLL_INTERVAL_MS = 100;
15092
15130
  async function ensureDaemonRunning() {
15093
15131
  persistence.logger.debug("Ensuring Happy background service is running & matches our version...");
15094
- const versionMatches = await api.isDaemonRunningCurrentlyInstalledHappyVersion();
15132
+ const versionMatches = await index.isDaemonRunningCurrentlyInstalledHappyVersion();
15095
15133
  const state = await persistence.readDaemonState();
15096
15134
  const endpointsMatch = Boolean(state) && daemonEndpointsMatch(
15097
15135
  state?.serverUrl,
@@ -15102,9 +15140,9 @@ async function ensureDaemonRunning() {
15102
15140
  if (versionMatches && endpointsMatch) {
15103
15141
  return;
15104
15142
  }
15105
- if (await api.checkIfDaemonRunningAndCleanupStaleState()) {
15143
+ if (await index.checkIfDaemonRunningAndCleanupStaleState()) {
15106
15144
  persistence.logger.debug("Stopping daemon whose version or configured relay no longer matches...");
15107
- await api.stopDaemon();
15145
+ await index.stopDaemon();
15108
15146
  }
15109
15147
  persistence.logger.debug("Starting Happy background service...");
15110
15148
  const daemonProcess = spawnHappyCLI(["daemon", "start-sync"], {
@@ -15115,7 +15153,7 @@ async function ensureDaemonRunning() {
15115
15153
  daemonProcess.unref();
15116
15154
  const deadline = Date.now() + DAEMON_READY_TIMEOUT_MS;
15117
15155
  while (Date.now() < deadline) {
15118
- if (await api.checkIfDaemonRunningAndCleanupStaleState()) {
15156
+ if (await index.checkIfDaemonRunningAndCleanupStaleState()) {
15119
15157
  persistence.logger.debug("Happy background service is ready");
15120
15158
  return;
15121
15159
  }
@@ -15137,14 +15175,14 @@ function maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagent
15137
15175
  if (!subagent || startedSubagents.has(subagent)) {
15138
15176
  return;
15139
15177
  }
15140
- envelopes.push(api.createEnvelope("agent", { t: "start" }, { ...opts, subagent }));
15178
+ envelopes.push(index.createEnvelope("agent", { t: "start" }, { ...opts, subagent }));
15141
15179
  startedSubagents.add(subagent);
15142
15180
  activeSubagents.add(subagent);
15143
15181
  }
15144
15182
  function emitSubagentStops(opts, startedSubagents, activeSubagents) {
15145
15183
  const envelopes = [];
15146
15184
  for (const subagent of activeSubagents) {
15147
- envelopes.push(api.createEnvelope("agent", { t: "stop" }, { ...opts, subagent }));
15185
+ envelopes.push(index.createEnvelope("agent", { t: "stop" }, { ...opts, subagent }));
15148
15186
  }
15149
15187
  activeSubagents.clear();
15150
15188
  startedSubagents.clear();
@@ -15240,7 +15278,7 @@ function turnStatus(turn) {
15240
15278
  function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output) {
15241
15279
  const time = turnTimestampMs(turn);
15242
15280
  const opts = { turn: turn.id, time, codexItemId: item.id };
15243
- envelopes.push(api.createEnvelope("agent", {
15281
+ envelopes.push(index.createEnvelope("agent", {
15244
15282
  t: "tool-call-start",
15245
15283
  call: item.id,
15246
15284
  name,
@@ -15252,7 +15290,7 @@ function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output
15252
15290
  id: `${item.id}:start`
15253
15291
  }));
15254
15292
  if (output && output.trim().length > 0) {
15255
- envelopes.push(api.createEnvelope("agent", {
15293
+ envelopes.push(index.createEnvelope("agent", {
15256
15294
  t: "text",
15257
15295
  text: output,
15258
15296
  thinking: true
@@ -15262,7 +15300,7 @@ function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output
15262
15300
  }));
15263
15301
  }
15264
15302
  if ("status" in item && (item.status === "inProgress" || item.status === "running")) return;
15265
- envelopes.push(api.createEnvelope("agent", {
15303
+ envelopes.push(index.createEnvelope("agent", {
15266
15304
  t: "tool-call-end",
15267
15305
  call: item.id
15268
15306
  }, {
@@ -15284,7 +15322,7 @@ function mapCodexCollaborationItem(item, opts = {}, source = "history") {
15284
15322
  agentsStates: item.agentsStates ?? {}
15285
15323
  };
15286
15324
  const startId = source === "live" ? `${item.id}:${item.status ?? "unknown"}:start` : `${item.id}:start`;
15287
- const envelopes = [api.createEnvelope("agent", {
15325
+ const envelopes = [index.createEnvelope("agent", {
15288
15326
  t: "tool-call-start",
15289
15327
  call: item.id,
15290
15328
  name: "CodexCollaboration",
@@ -15293,7 +15331,7 @@ function mapCodexCollaborationItem(item, opts = {}, source = "history") {
15293
15331
  args
15294
15332
  }, { ...opts, id: startId })];
15295
15333
  if (item.status === "completed" || item.status === "failed" || item.status === "interrupted") {
15296
- envelopes.push(api.createEnvelope("agent", {
15334
+ envelopes.push(index.createEnvelope("agent", {
15297
15335
  t: "tool-call-end",
15298
15336
  call: item.id,
15299
15337
  result: { text: JSON.stringify(args, null, 2), isError: item.status !== "completed" }
@@ -15306,7 +15344,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
15306
15344
  for (const turn of thread.turns ?? []) {
15307
15345
  const startedAt = turnTimestampMs(turn);
15308
15346
  const completedAt = completedTimestampMs(turn);
15309
- envelopes.push(api.createEnvelope("agent", { t: "turn-start" }, {
15347
+ envelopes.push(index.createEnvelope("agent", { t: "turn-start" }, {
15310
15348
  id: `${turn.id}:start`,
15311
15349
  turn: turn.id,
15312
15350
  time: startedAt
@@ -15321,7 +15359,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
15321
15359
  case "userMessage": {
15322
15360
  const text = textFromInputItems(item.content);
15323
15361
  if (text) {
15324
- envelopes.push(api.createEnvelope("user", { t: "text", text }, {
15362
+ envelopes.push(index.createEnvelope("user", { t: "text", text }, {
15325
15363
  id: item.id,
15326
15364
  time: startedAt,
15327
15365
  codexItemId: item.id
@@ -15332,7 +15370,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
15332
15370
  case "agentMessage": {
15333
15371
  const text = typeof item.text === "string" ? item.text.trim() : "";
15334
15372
  if (text.length > 0) {
15335
- envelopes.push(api.createEnvelope("agent", { t: "text", text }, {
15373
+ envelopes.push(index.createEnvelope("agent", { t: "text", text }, {
15336
15374
  id: item.id,
15337
15375
  turn: turn.id,
15338
15376
  time: completedAt,
@@ -15344,7 +15382,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
15344
15382
  case "reasoning": {
15345
15383
  const text = reasoningText(item);
15346
15384
  if (text) {
15347
- envelopes.push(api.createEnvelope("agent", { t: "text", text, thinking: true }, {
15385
+ envelopes.push(index.createEnvelope("agent", { t: "text", text, thinking: true }, {
15348
15386
  id: item.id,
15349
15387
  turn: turn.id,
15350
15388
  time: startedAt,
@@ -15399,7 +15437,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
15399
15437
  }
15400
15438
  }
15401
15439
  }
15402
- envelopes.push(api.createEnvelope("agent", { t: "turn-end", status: turnStatus(turn) }, {
15440
+ envelopes.push(index.createEnvelope("agent", { t: "turn-end", status: turnStatus(turn) }, {
15403
15441
  id: `${turn.id}:end`,
15404
15442
  turn: turn.id,
15405
15443
  time: completedAt
@@ -15454,7 +15492,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15454
15492
  }
15455
15493
  if (type === "task_started") {
15456
15494
  const turnId = cuid2.createId();
15457
- const turnStart = api.createEnvelope("agent", { t: "turn-start" }, { turn: turnId });
15495
+ const turnStart = index.createEnvelope("agent", { t: "turn-start" }, { turn: turnId });
15458
15496
  startedSubagents.clear();
15459
15497
  activeSubagents.clear();
15460
15498
  providerSubagentToSessionSubagent.clear();
@@ -15485,7 +15523,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15485
15523
  providerSubagentToSessionSubagent,
15486
15524
  envelopes: [
15487
15525
  ...emitSubagentStops(lifecycleOpts, startedSubagents, activeSubagents),
15488
- api.createEnvelope("agent", {
15526
+ index.createEnvelope("agent", {
15489
15527
  t: "turn-end",
15490
15528
  status: pickTurnEndStatus(message, type)
15491
15529
  }, lifecycleOpts)
@@ -15515,7 +15553,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15515
15553
  }
15516
15554
  const envelopes = [];
15517
15555
  maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
15518
- envelopes.push(api.createEnvelope("agent", { t: "text", text: message.message }, opts));
15556
+ envelopes.push(index.createEnvelope("agent", { t: "text", text: message.message }, opts));
15519
15557
  return {
15520
15558
  currentTurnId: state.currentTurnId,
15521
15559
  startedSubagents,
@@ -15537,7 +15575,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15537
15575
  }
15538
15576
  const envelopes = [];
15539
15577
  maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
15540
- envelopes.push(api.createEnvelope("agent", { t: "text", text, thinking: true }, opts));
15578
+ envelopes.push(index.createEnvelope("agent", { t: "text", text, thinking: true }, opts));
15541
15579
  return {
15542
15580
  currentTurnId: state.currentTurnId,
15543
15581
  startedSubagents,
@@ -15554,7 +15592,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15554
15592
  const envelopes = [];
15555
15593
  maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
15556
15594
  envelopes.push(
15557
- api.createEnvelope("agent", {
15595
+ index.createEnvelope("agent", {
15558
15596
  t: "tool-call-start",
15559
15597
  call,
15560
15598
  name: "CodexBash",
@@ -15575,7 +15613,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15575
15613
  const call = pickCallId(message);
15576
15614
  const envelopes = [];
15577
15615
  maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
15578
- envelopes.push(api.createEnvelope("agent", { t: "tool-call-end", call }, opts));
15616
+ envelopes.push(index.createEnvelope("agent", { t: "tool-call-end", call }, opts));
15579
15617
  return {
15580
15618
  currentTurnId: state.currentTurnId,
15581
15619
  startedSubagents,
@@ -15591,7 +15629,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15591
15629
  const envelopes = [];
15592
15630
  maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
15593
15631
  envelopes.push(
15594
- api.createEnvelope("agent", {
15632
+ index.createEnvelope("agent", {
15595
15633
  t: "tool-call-start",
15596
15634
  call,
15597
15635
  name: "CodexPatch",
@@ -15615,7 +15653,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
15615
15653
  const call = pickCallId(message);
15616
15654
  const envelopes = [];
15617
15655
  maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
15618
- envelopes.push(api.createEnvelope("agent", { t: "tool-call-end", call }, opts));
15656
+ envelopes.push(index.createEnvelope("agent", { t: "tool-call-end", call }, opts));
15619
15657
  return {
15620
15658
  currentTurnId: state.currentTurnId,
15621
15659
  startedSubagents,
@@ -15636,7 +15674,7 @@ function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
15636
15674
  const toolLikeMessage = message;
15637
15675
  const opts = buildEnvelopeOptions(state.currentTurnId);
15638
15676
  if (message.type === "reasoning") {
15639
- return [api.createEnvelope("agent", {
15677
+ return [index.createEnvelope("agent", {
15640
15678
  t: "text",
15641
15679
  text: message.message,
15642
15680
  thinking: true
@@ -15644,7 +15682,7 @@ function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
15644
15682
  }
15645
15683
  if (message.type === "tool-call") {
15646
15684
  const title = typeof toolLikeMessage.input?.title === "string" ? toolLikeMessage.input.title : `${toolLikeMessage.name || "Tool"} call`;
15647
- return [api.createEnvelope("agent", {
15685
+ return [index.createEnvelope("agent", {
15648
15686
  t: "tool-call-start",
15649
15687
  call: toolLikeMessage.callId,
15650
15688
  name: toolLikeMessage.name || "unknown",
@@ -15657,13 +15695,13 @@ function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
15657
15695
  const envelopes = [];
15658
15696
  const content = toolLikeMessage.output?.content;
15659
15697
  if (typeof content === "string" && content.trim().length > 0) {
15660
- envelopes.push(api.createEnvelope("agent", {
15698
+ envelopes.push(index.createEnvelope("agent", {
15661
15699
  t: "text",
15662
15700
  text: content,
15663
15701
  thinking: true
15664
15702
  }, opts));
15665
15703
  }
15666
- envelopes.push(api.createEnvelope("agent", {
15704
+ envelopes.push(index.createEnvelope("agent", {
15667
15705
  t: "tool-call-end",
15668
15706
  call: toolLikeMessage.callId
15669
15707
  }, opts));
@@ -16352,17 +16390,17 @@ function createOfflineSessionStub(sessionTag) {
16352
16390
  }
16353
16391
 
16354
16392
  function setupOfflineReconnection(opts) {
16355
- const { api: api$1, sessionTag, metadata, state, response, onSessionSwap } = opts;
16393
+ const { api, sessionTag, metadata, state, response, onSessionSwap } = opts;
16356
16394
  let session;
16357
16395
  let reconnectionHandle = null;
16358
16396
  if (!response) {
16359
16397
  session = createOfflineSessionStub(sessionTag);
16360
- reconnectionHandle = api.startOfflineReconnection({
16398
+ reconnectionHandle = index.startOfflineReconnection({
16361
16399
  serverUrl: persistence.configuration.serverUrl,
16362
16400
  onReconnected: async () => {
16363
- const resp = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
16401
+ const resp = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
16364
16402
  if (!resp) throw new Error("Server unavailable");
16365
- const realSession = api$1.sessionSyncClient(resp);
16403
+ const realSession = api.sessionSyncClient(resp);
16366
16404
  onSessionSwap(realSession);
16367
16405
  return realSession;
16368
16406
  },
@@ -16372,7 +16410,7 @@ function setupOfflineReconnection(opts) {
16372
16410
  });
16373
16411
  return { session, reconnectionHandle, isOffline: true };
16374
16412
  } else {
16375
- session = api$1.sessionSyncClient(response, opts.sessionClientOptions);
16413
+ session = api.sessionSyncClient(response, opts.sessionClientOptions);
16376
16414
  return { session, reconnectionHandle: null, isOffline: false };
16377
16415
  }
16378
16416
  }
@@ -16622,7 +16660,7 @@ function buildCodexTurnPrompt(opts) {
16622
16660
  parts.push(opts.message);
16623
16661
  if (opts.includeTitleInstruction) {
16624
16662
  parts.push(CHANGE_TITLE_INSTRUCTION);
16625
- parts.push(api.BUILTIN_TODO_DISCOVERY);
16663
+ parts.push(index.BUILTIN_TODO_DISCOVERY);
16626
16664
  }
16627
16665
  return parts.join("\n\n");
16628
16666
  }
@@ -16690,8 +16728,8 @@ async function runCodex(opts) {
16690
16728
  process.exit(1);
16691
16729
  }
16692
16730
  const sessionTag = node_crypto.randomUUID();
16693
- api.connectionState.setBackend("Codex");
16694
- const api$1 = await api.ApiClient.create(opts.credentials);
16731
+ index.connectionState.setBackend("Codex");
16732
+ const api = await index.ApiClient.create(opts.credentials);
16695
16733
  persistence.logger.debug(`[codex] Starting with options: startedBy=${opts.startedBy || "terminal"}`);
16696
16734
  const settings = await persistence.readSettings();
16697
16735
  let machineId = settings?.machineId;
@@ -16701,7 +16739,7 @@ async function runCodex(opts) {
16701
16739
  process.exit(1);
16702
16740
  }
16703
16741
  persistence.logger.debug(`Using machineId: ${machineId}`);
16704
- await api$1.getOrCreateMachine({
16742
+ await api.getOrCreateMachine({
16705
16743
  machineId,
16706
16744
  metadata: initialMachineMetadata
16707
16745
  });
@@ -16745,17 +16783,17 @@ async function runCodex(opts) {
16745
16783
  agentStateVersion: parseInt(reconnectAgentStateVersion || "0", 10)
16746
16784
  };
16747
16785
  } else {
16748
- response = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
16786
+ response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
16749
16787
  }
16750
16788
  if (response) {
16751
16789
  await claimSessionOrExit(response.id, { takeover: !!reconnectSessionId, flavor: "codex" });
16752
16790
  }
16753
- if (reconnectSessionId && response && !await api$1.reactivateSession(response.id)) {
16791
+ if (reconnectSessionId && response && !await api.reactivateSession(response.id)) {
16754
16792
  throw new Error(`Failed to reactivate archived session ${response.id}`);
16755
16793
  }
16756
16794
  let reconnectSeeded = false;
16757
16795
  if (reconnectSessionId && response) {
16758
- const snapshot = await api$1.getSession(response.id, response.encryptionKey, response.encryptionVariant);
16796
+ const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
16759
16797
  if (snapshot.ok) {
16760
16798
  response = applyServerSnapshot(response, snapshot.session);
16761
16799
  reconnectSeeded = true;
@@ -16772,7 +16810,7 @@ async function runCodex(opts) {
16772
16810
  let abortInProgress = null;
16773
16811
  let turnActive = false;
16774
16812
  const { session: initialSession, reconnectionHandle } = setupOfflineReconnection({
16775
- api: api$1,
16813
+ api,
16776
16814
  sessionTag,
16777
16815
  metadata,
16778
16816
  state,
@@ -16795,7 +16833,7 @@ async function runCodex(opts) {
16795
16833
  if (response) {
16796
16834
  try {
16797
16835
  persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
16798
- const result = await api.notifyDaemonSessionStarted(response.id, metadata, {
16836
+ const result = await index.notifyDaemonSessionStarted(response.id, metadata, {
16799
16837
  encryptionKey: persistence.encodeBase64(response.encryptionKey),
16800
16838
  encryptionVariant: response.encryptionVariant,
16801
16839
  seq: response.seq,
@@ -16928,7 +16966,7 @@ async function runCodex(opts) {
16928
16966
  const sendReady = () => {
16929
16967
  session.sendSessionEvent({ type: "ready" });
16930
16968
  try {
16931
- api$1.push().sendSessionNotification({
16969
+ api.push().sendSessionNotification({
16932
16970
  kind: "done",
16933
16971
  metadata: session.getMetadata(),
16934
16972
  data: {
@@ -17058,7 +17096,7 @@ async function runCodex(opts) {
17058
17096
  }
17059
17097
  process.stdin.setEncoding("utf8");
17060
17098
  }
17061
- client = new api.CodexAppServerClient(sandboxConfig);
17099
+ client = new index.CodexAppServerClient(sandboxConfig);
17062
17100
  const idleRelease = new CodexIdleReleaseTimer({
17063
17101
  delayMs: resolveCodexIdleReleaseMs(process.env[CODEX_IDLE_RELEASE_ENV]),
17064
17102
  isIdle: () => shouldReleaseIdleCodex({
@@ -17617,7 +17655,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17617
17655
  return;
17618
17656
  } else if (subcommand === "install-terminal-hooks") {
17619
17657
  try {
17620
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-DA7SyFYW.cjs'); });
17658
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-De7_iOOC.cjs'); });
17621
17659
  const command = parseTerminalHooksArgs(args.slice(1));
17622
17660
  if (command.action === "help") {
17623
17661
  console.log(TERMINAL_HOOKS_HELP);
@@ -17632,9 +17670,18 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17632
17670
  }
17633
17671
  process.exit(1);
17634
17672
  }
17673
+ } else if (subcommand === "agent-home") {
17674
+ try {
17675
+ const { parseAgentHomeArgs, runAgentHomeCommand } = await Promise.resolve().then(function () { return require('./agentHome-uf1zs2Fi.cjs'); });
17676
+ await runAgentHomeCommand(parseAgentHomeArgs(args.slice(1)));
17677
+ process.exit(0);
17678
+ } catch (error) {
17679
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
17680
+ process.exit(1);
17681
+ }
17635
17682
  } else if (subcommand === "spawn") {
17636
17683
  try {
17637
- const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-COOcUwkG.cjs'); });
17684
+ const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-Be4nsNuQ.cjs'); });
17638
17685
  await handleSpawnCommand(args.slice(1));
17639
17686
  } catch (error) {
17640
17687
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17646,7 +17693,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17646
17693
  return;
17647
17694
  } else if (subcommand === "sessions") {
17648
17695
  try {
17649
- const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-DPimBZ8H.cjs'); });
17696
+ const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-CtVcoXvG.cjs'); });
17650
17697
  await handleSessionsCommand(args.slice(1));
17651
17698
  } catch (error) {
17652
17699
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17658,7 +17705,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17658
17705
  return;
17659
17706
  } else if (subcommand === "send") {
17660
17707
  try {
17661
- const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-Bg2oqt7f.cjs'); });
17708
+ const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-BA1Dgpgn.cjs'); });
17662
17709
  await handleSendCommand(args.slice(1));
17663
17710
  } catch (error) {
17664
17711
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17764,9 +17811,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17764
17811
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
17765
17812
  const projectId = args[3];
17766
17813
  try {
17767
- const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-BIbYBmTd.cjs'); });
17768
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-B3hngubn.cjs'); }).then(function (n) { return n.persistence; });
17769
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-Xd_LJRJN.cjs'); }).then(function (n) { return n.api; });
17814
+ const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-kx4y9oAI.cjs'); });
17815
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-C_Sklt--.cjs'); }).then(function (n) { return n.persistence; });
17816
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DZ5c-9f3.cjs'); }).then(function (n) { return n.api; });
17770
17817
  let userEmail = void 0;
17771
17818
  try {
17772
17819
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -17797,7 +17844,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17797
17844
  }
17798
17845
  if (geminiSubcommand === "project" && args[2] === "get") {
17799
17846
  try {
17800
- const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-BIbYBmTd.cjs'); });
17847
+ const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-kx4y9oAI.cjs'); });
17801
17848
  const config = readGeminiLocalConfig();
17802
17849
  if (config.googleCloudProject) {
17803
17850
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -17837,7 +17884,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17837
17884
  process.exit(0);
17838
17885
  }
17839
17886
  try {
17840
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-eJ08cXk7.cjs'); });
17887
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-CCdGxTF2.cjs'); });
17841
17888
  let startedBy = void 0;
17842
17889
  for (let i = 1; i < args.length; i++) {
17843
17890
  if (args[i] === "--started-by") {
@@ -17860,7 +17907,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17860
17907
  } else if (subcommand === "pi") {
17861
17908
  if (args[1] === "--terminal") {
17862
17909
  try {
17863
- const { runPiTerminal } = await Promise.resolve().then(function () { return require('./piTerminal-DNr3hkzY.cjs'); });
17910
+ const { runPiTerminal } = await Promise.resolve().then(function () { return require('./piTerminal-BFpwVGWr.cjs'); });
17864
17911
  process.exitCode = await runPiTerminal(args.slice(2));
17865
17912
  } catch (error) {
17866
17913
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17877,7 +17924,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17877
17924
  }
17878
17925
  };
17879
17926
  try {
17880
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-BPTPrjhL.cjs'); });
17927
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-Dox9iD5R.cjs'); });
17881
17928
  const parsed = parsePiRunnerArgs(args.slice(1));
17882
17929
  const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
17883
17930
  const { credentials } = await authAndSetupMachineIfNeeded();
@@ -17905,7 +17952,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17905
17952
  return;
17906
17953
  } else if (subcommand === "acp") {
17907
17954
  try {
17908
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-BPTPrjhL.cjs'); });
17955
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-Dox9iD5R.cjs'); });
17909
17956
  let startedBy = void 0;
17910
17957
  let verbose = false;
17911
17958
  const acpArgs = [];
@@ -17945,7 +17992,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17945
17992
  return;
17946
17993
  } else if (subcommand === "openclaw") {
17947
17994
  try {
17948
- const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-D0LVzxqM.cjs'); });
17995
+ const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-CRMUfrWk.cjs'); });
17949
17996
  let startedBy = void 0;
17950
17997
  let verbose = false;
17951
17998
  let gatewayUrl;
@@ -17996,7 +18043,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17996
18043
  return;
17997
18044
  } else if (subcommand === "todo") {
17998
18045
  try {
17999
- const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-DeauuUd6.cjs'); });
18046
+ const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-EffYAnre.cjs'); });
18000
18047
  await handleTodoCommand(args.slice(1));
18001
18048
  } catch (error) {
18002
18049
  console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
@@ -18005,7 +18052,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18005
18052
  return;
18006
18053
  } else if (subcommand === "teams") {
18007
18054
  try {
18008
- const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-DSQgHBLE.cjs'); });
18055
+ const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-CcjjNLi8.cjs'); });
18009
18056
  await handleTeamsCommand(args.slice(1));
18010
18057
  } catch (error) {
18011
18058
  console.error(error instanceof Error ? error.message : "Teams command failed");
@@ -18014,7 +18061,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18014
18061
  return;
18015
18062
  } else if (subcommand === "mcp" && (args.length === 1 || args.length === 2 && args[1] === "--terminal-tools")) {
18016
18063
  try {
18017
- const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-ySrfNOYl.cjs'); });
18064
+ const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-xyb8dYIQ.cjs'); });
18018
18065
  await handleMcpCommand(args[1] === "--terminal-tools");
18019
18066
  } catch (error) {
18020
18067
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -18037,7 +18084,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18037
18084
  const daemonSubcommand = args[1];
18038
18085
  if (daemonSubcommand === "list") {
18039
18086
  try {
18040
- const sessions = await api.listDaemonSessions();
18087
+ const sessions = await index.listDaemonSessions();
18041
18088
  if (sessions.length === 0) {
18042
18089
  console.log("No active sessions this daemon is aware of (they might have been started by a previous version of the daemon)");
18043
18090
  } else {
@@ -18055,7 +18102,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18055
18102
  process.exit(1);
18056
18103
  }
18057
18104
  try {
18058
- const success = await api.stopDaemonSession(sessionId);
18105
+ const success = await index.stopDaemonSession(sessionId);
18059
18106
  console.log(success ? "Session stopped" : "Failed to stop session");
18060
18107
  } catch (error) {
18061
18108
  console.log("No daemon running");
@@ -18063,7 +18110,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18063
18110
  return;
18064
18111
  } else if (daemonSubcommand === "start") {
18065
18112
  const currentState = await persistence.readDaemonState();
18066
- const running = await api.checkIfDaemonRunningAndCleanupStaleState();
18113
+ const running = await index.checkIfDaemonRunningAndCleanupStaleState();
18067
18114
  const currentDaemonMatches = currentState && currentState.startedWithCliVersion === persistence.configuration.currentCliVersion && daemonEndpointsMatch(
18068
18115
  currentState.serverUrl,
18069
18116
  currentState.webappUrl,
@@ -18072,7 +18119,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18072
18119
  );
18073
18120
  if (running && !currentDaemonMatches) {
18074
18121
  console.log("Configured relay or CLI version changed; restarting the existing daemon");
18075
- await api.stopDaemon();
18122
+ await index.stopDaemon();
18076
18123
  }
18077
18124
  const child = spawnHappyCLI(["daemon", "start-sync"], {
18078
18125
  detached: true,
@@ -18082,7 +18129,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18082
18129
  child.unref();
18083
18130
  let started = false;
18084
18131
  for (let i = 0; i < 50; i++) {
18085
- if (await api.checkIfDaemonRunningAndCleanupStaleState()) {
18132
+ if (await index.checkIfDaemonRunningAndCleanupStaleState()) {
18086
18133
  started = true;
18087
18134
  break;
18088
18135
  }
@@ -18099,7 +18146,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18099
18146
  await startDaemon();
18100
18147
  process.exit(0);
18101
18148
  } else if (daemonSubcommand === "stop") {
18102
- await api.stopDaemon();
18149
+ await index.stopDaemon();
18103
18150
  process.exit(0);
18104
18151
  } else if (daemonSubcommand === "status") {
18105
18152
  await runDoctorDaemon();
@@ -18244,6 +18291,8 @@ ${chalk.bold("Usage:")}
18244
18291
  very-happy install-terminal-hooks
18245
18292
  Install optional Claude terminal mirror hooks
18246
18293
  (add --remove to uninstall them)
18294
+ very-happy agent-home Show or pin where Claude Code / Codex keep their
18295
+ conversations on this machine (agent-home --help)
18247
18296
  very-happy connect Connect AI vendor API keys
18248
18297
  very-happy todo Built-in Todos and official agent skill (todo --help)
18249
18298
  very-happy sandbox Configure and manage OS-level sandboxing
@@ -18359,9 +18408,9 @@ ${chalk.bold("Examples:")}
18359
18408
  }
18360
18409
  console.log(chalk.blue("\u{1F4F1} Sending push notification..."));
18361
18410
  try {
18362
- const api$1 = await api.ApiClient.create(credentials);
18411
+ const api = await index.ApiClient.create(credentials);
18363
18412
  const notificationTitle = title || "Happy";
18364
- api$1.push().sendToAllDevices(
18413
+ api.push().sendToAllDevices(
18365
18414
  notificationTitle,
18366
18415
  message,
18367
18416
  {