very-happy-cli 0.2.138 → 0.2.140

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 (45) hide show
  1. package/dist/{AcpBackend-BUoDXZnv.cjs → AcpBackend-C0Lq4uoA.cjs} +2 -2
  2. package/dist/{AcpBackend-bqVGMkPh.mjs → AcpBackend-DsSYq8T-.mjs} +2 -2
  3. package/dist/{AcpSessionManager-BBAQ8EQf.mjs → AcpSessionManager-BAErE9s0.mjs} +1 -1
  4. package/dist/{AcpSessionManager-DmmA52Ep.cjs → AcpSessionManager-DIqByTH7.cjs} +1 -1
  5. package/dist/{agentGuidance-4HV-BOge.cjs → agentGuidance-Dl3apItH.cjs} +1 -1
  6. package/dist/{agentGuidance-WHZsBKpm.mjs → agentGuidance-xk3v4_7E.mjs} +1 -1
  7. package/dist/codex/happyMcpStdioBridge.cjs +2 -2
  8. package/dist/codex/happyMcpStdioBridge.mjs +2 -2
  9. package/dist/{config-BRXqgJJj.mjs → config-BVoHul9V.mjs} +4 -4
  10. package/dist/{config-DpuZN2Rs.cjs → config-D0-jnCOC.cjs} +4 -4
  11. package/dist/{index-DQe7ljLR.mjs → index-BNydKYvS.mjs} +7 -7
  12. package/dist/{index-D8Q3OhdR.mjs → index-BPnAbcz_.mjs} +4 -4
  13. package/dist/{index-CHP265gs.cjs → index-BuQn9kUK.cjs} +4 -4
  14. package/dist/{index-Dbl5U_N0.mjs → index-D0IP7gXG.mjs} +116 -232
  15. package/dist/{index-3N-qu-RG.cjs → index-DJvzGXVN.cjs} +7 -7
  16. package/dist/{index-CRRK5P1r.cjs → index-__h-pCTK.cjs} +147 -268
  17. package/dist/index.cjs +4 -4
  18. package/dist/index.mjs +4 -4
  19. package/dist/{installTerminalHooks-DfUGgeyb.mjs → installTerminalHooks-D2ice1a-.mjs} +4 -4
  20. package/dist/{installTerminalHooks-CWGkoWDD.cjs → installTerminalHooks-D3jfvbyY.cjs} +4 -4
  21. package/dist/lib.cjs +2 -2
  22. package/dist/lib.d.cts +21 -0
  23. package/dist/lib.d.mts +21 -0
  24. package/dist/lib.mjs +2 -2
  25. package/dist/{limits-CfzVummd.cjs → limits-Dbip6eVO.cjs} +26 -7
  26. package/dist/{limits-DEsg_gHi.mjs → limits-nhD0Wran.mjs} +26 -8
  27. package/dist/{mcp-CN2UVfut.cjs → mcp-DeapmTWN.cjs} +21 -21
  28. package/dist/{mcp-UnjB3I8_.mjs → mcp-V26C05fN.mjs} +19 -19
  29. package/dist/{runGemini-BUVjTJKn.cjs → runGemini-D34eCFpz.cjs} +7 -7
  30. package/dist/{runGemini-BZ0xXRj-.mjs → runGemini-sa5kAgPe.mjs} +6 -6
  31. package/dist/{runOpenClaw-Bj2EgRHB.cjs → runOpenClaw-B8F8D--R.cjs} +6 -6
  32. package/dist/{runOpenClaw-BcUmnBpW.mjs → runOpenClaw-Bdsq8KBa.mjs} +5 -5
  33. package/dist/{send-BkypdBpK.cjs → send-DP_S3wn0.cjs} +4 -4
  34. package/dist/{send-snK_NGAA.mjs → send-KICC_ACz.mjs} +4 -4
  35. package/dist/{sessions-DxlC4C4g.mjs → sessions-C6EvnC4B.mjs} +4 -4
  36. package/dist/{sessions-9A-uoJL_.cjs → sessions-CGBBgVZn.cjs} +4 -4
  37. package/dist/{spawn-BORLpj60.cjs → spawn-BhUK0Vt2.cjs} +8 -8
  38. package/dist/{spawn-DFfHCafP.mjs → spawn-C1OqXJNb.mjs} +6 -6
  39. package/dist/{teams-9x2FO9RW.cjs → teams-C29nEHFD.cjs} +4 -4
  40. package/dist/{teams-Cfr-2Yd-.mjs → teams-Dm5HGpNz.mjs} +4 -4
  41. package/dist/{todo-CU5cjQZU.mjs → todo-C-vovA0N.mjs} +3 -3
  42. package/dist/{todo-DydKcknX.cjs → todo-CeJX0z_2.cjs} +3 -3
  43. package/dist/{types-CRxf_3n8.cjs → types-DCVS050m.cjs} +571 -13
  44. package/dist/{types-D5EsIAOe.mjs → types-thyvQB2a.mjs} +558 -13
  45. package/package.json +7 -7
@@ -3,13 +3,13 @@
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-CRxf_3n8.cjs');
7
- var persistence = require('./limits-CfzVummd.cjs');
6
+ var api = require('./types-DCVS050m.cjs');
7
+ var persistence = require('./limits-Dbip6eVO.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
- var agentGuidance = require('./agentGuidance-4HV-BOge.cjs');
12
+ var agentGuidance = require('./agentGuidance-Dl3apItH.cjs');
13
13
  var promises = require('node:fs/promises');
14
14
  var fs = require('fs/promises');
15
15
  var ink = require('ink');
@@ -115,212 +115,6 @@ function withoutServerSnapshot(response) {
115
115
  return { ...response, metadataVersion: 0, agentStateVersion: 0 };
116
116
  }
117
117
 
118
- function daemonControlHeaders(controlToken) {
119
- return {
120
- "Content-Type": "application/json",
121
- ...controlToken ? { Authorization: `Bearer ${controlToken}` } : {}
122
- };
123
- }
124
- async function daemonPost(path, body) {
125
- const state = await persistence.readDaemonState();
126
- if (!state?.httpPort) {
127
- const errorMessage = "No daemon running, no state file found";
128
- persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
129
- return {
130
- error: errorMessage
131
- };
132
- }
133
- try {
134
- process.kill(state.pid, 0);
135
- } catch (error) {
136
- const errorMessage = "Daemon is not running, file is stale";
137
- persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
138
- return {
139
- error: errorMessage
140
- };
141
- }
142
- try {
143
- const timeout = process.env.HAPPY_DAEMON_HTTP_TIMEOUT ? parseInt(process.env.HAPPY_DAEMON_HTTP_TIMEOUT) : 1e4;
144
- const response = await fetch(`http://127.0.0.1:${state.httpPort}${path}`, {
145
- method: "POST",
146
- // A state written by an old daemon has no token and must remain callable;
147
- // a new daemon always writes one and rejects requests without it.
148
- headers: daemonControlHeaders(state.controlToken),
149
- body: JSON.stringify(body || {}),
150
- // Mostly increased for stress test
151
- signal: AbortSignal.timeout(timeout)
152
- });
153
- if (!response.ok) {
154
- const failure = await response.json().catch(() => null);
155
- const reason = typeof failure?.error === "string" && failure.error ? failure.error : `HTTP ${response.status}`;
156
- const errorMessage = `Request failed: ${path}, ${reason}`;
157
- persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
158
- return {
159
- error: errorMessage
160
- };
161
- }
162
- return await response.json();
163
- } catch (error) {
164
- const errorMessage = `Request failed: ${path}, ${error instanceof Error ? error.message : "Unknown error"}`;
165
- persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
166
- return {
167
- error: errorMessage
168
- };
169
- }
170
- }
171
- const SESSION_STARTED_RETRY_TIMEOUT_MS = 3e3;
172
- const SESSION_STARTED_RETRY_INTERVAL_MS = 100;
173
- async function notifyDaemonSessionStarted(sessionId, metadata, encryption) {
174
- const payload = { sessionId, metadata, encryption };
175
- const deadline = Date.now() + SESSION_STARTED_RETRY_TIMEOUT_MS;
176
- let result;
177
- while (true) {
178
- result = await daemonPost("/session-started", payload);
179
- if (!result?.error) {
180
- return result;
181
- }
182
- if (Date.now() >= deadline) {
183
- return result;
184
- }
185
- await new Promise((resolve) => setTimeout(resolve, SESSION_STARTED_RETRY_INTERVAL_MS));
186
- }
187
- }
188
- async function listDaemonSessions() {
189
- const result = await daemonPost("/list");
190
- return result.children || [];
191
- }
192
- async function stopDaemonSession(sessionId) {
193
- const result = await daemonPost("/stop-session", { sessionId });
194
- return result.success || false;
195
- }
196
- async function spawnDaemonSession(directory, sessionId, opts) {
197
- const result = await daemonPost("/spawn-session", {
198
- directory,
199
- sessionId,
200
- spawnedBy: opts?.spawnedBy,
201
- permissionMode: opts?.permissionMode,
202
- agent: opts?.agent,
203
- environmentVariables: opts?.environmentVariables
204
- });
205
- return result;
206
- }
207
- async function notifyDaemonSessionEvent(sessionId, event, spawnedBy) {
208
- return daemonPost("/session-event", { sessionId, event, spawnedBy });
209
- }
210
- async function notifyDaemonClaudeAuthFailed(sessionId) {
211
- return daemonPost("/session-event", { sessionId, event: "auth_failed" });
212
- }
213
- async function stopDaemonHttp() {
214
- await daemonPost("/stop");
215
- }
216
- async function pushClipboardViaDaemon(text) {
217
- const result = await daemonPost("/clipboard", { text });
218
- if (result?.error && result.delivered === void 0) {
219
- return { delivered: false, error: result.error };
220
- }
221
- return result;
222
- }
223
- async function setTerminalTitleViaDaemon(terminalId, title, ifAbsent = false) {
224
- const result = await daemonPost("/terminal-title", { terminalId, title, ifAbsent });
225
- if (result?.error) {
226
- return { ok: false, error: result.error };
227
- }
228
- return { ok: result?.status === "ok", error: result?.status === "ok" ? void 0 : "unexpected daemon response" };
229
- }
230
- async function checkIfDaemonRunningAndCleanupStaleState() {
231
- const state = await persistence.readDaemonState();
232
- if (!state) {
233
- return false;
234
- }
235
- try {
236
- process.kill(state.pid, 0);
237
- } catch {
238
- persistence.logger.debug("[DAEMON RUN] Daemon PID not running, cleaning up state");
239
- await cleanupDaemonState();
240
- return false;
241
- }
242
- if (state.httpPort) {
243
- try {
244
- const response = await fetch(`http://127.0.0.1:${state.httpPort}/list`, {
245
- method: "POST",
246
- headers: daemonControlHeaders(state.controlToken),
247
- body: "{}",
248
- signal: AbortSignal.timeout(2e3)
249
- });
250
- if (response.ok) {
251
- return true;
252
- }
253
- } catch {
254
- persistence.logger.debug(`[DAEMON RUN] PID ${state.pid} is alive but HTTP health check failed on port ${state.httpPort}, cleaning up stale state`);
255
- await cleanupDaemonState();
256
- return false;
257
- }
258
- }
259
- return true;
260
- }
261
- async function isDaemonRunningCurrentlyInstalledHappyVersion() {
262
- persistence.logger.debug("[DAEMON CONTROL] Checking if daemon is running same version");
263
- const runningDaemon = await checkIfDaemonRunningAndCleanupStaleState();
264
- if (!runningDaemon) {
265
- persistence.logger.debug("[DAEMON CONTROL] No daemon running, returning false");
266
- return false;
267
- }
268
- const state = await persistence.readDaemonState();
269
- if (!state) {
270
- persistence.logger.debug("[DAEMON CONTROL] No daemon state found, returning false");
271
- return false;
272
- }
273
- const currentCliVersion = persistence.configuration.currentCliVersion;
274
- persistence.logger.debug(`[DAEMON CONTROL] Current CLI version: ${currentCliVersion}, Daemon started with version: ${state.startedWithCliVersion}`);
275
- return currentCliVersion === state.startedWithCliVersion;
276
- }
277
- async function cleanupDaemonState() {
278
- try {
279
- await persistence.clearDaemonState();
280
- persistence.logger.debug("[DAEMON RUN] Daemon state file removed");
281
- } catch (error) {
282
- persistence.logger.debug("[DAEMON RUN] Error cleaning up daemon metadata", error);
283
- }
284
- }
285
- async function stopDaemon() {
286
- try {
287
- const state = await persistence.readDaemonState();
288
- if (!state) {
289
- persistence.logger.debug("No daemon state found");
290
- return;
291
- }
292
- persistence.logger.debug(`Stopping daemon with PID ${state.pid}`);
293
- try {
294
- await stopDaemonHttp();
295
- await waitForProcessDeath(state.pid, 2e3);
296
- persistence.logger.debug("Daemon stopped gracefully via HTTP");
297
- return;
298
- } catch (error) {
299
- persistence.logger.debug("HTTP stop failed, will force kill", error);
300
- }
301
- try {
302
- process.kill(state.pid, "SIGKILL");
303
- persistence.logger.debug("Force killed daemon");
304
- } catch (error) {
305
- persistence.logger.debug("Daemon already dead");
306
- }
307
- } catch (error) {
308
- persistence.logger.debug("Error stopping daemon", error);
309
- }
310
- }
311
- async function waitForProcessDeath(pid, timeout) {
312
- const start = Date.now();
313
- while (Date.now() - start < timeout) {
314
- try {
315
- process.kill(pid, 0);
316
- await new Promise((resolve) => setTimeout(resolve, 100));
317
- } catch {
318
- return;
319
- }
320
- }
321
- throw new Error("Process did not die within timeout");
322
- }
323
-
324
118
  class Session {
325
119
  path;
326
120
  logPath;
@@ -493,7 +287,7 @@ class Session {
493
287
  reportEventToDaemon = (event) => {
494
288
  const spawnedBy = process.env.HAPPY_SPAWNED_BY;
495
289
  if (!spawnedBy) return;
496
- void notifyDaemonSessionEvent(this.client.sessionId, event, spawnedBy).catch((error) => persistence.logger.debug("[Session] Failed to report session event to daemon:", error));
290
+ void api.notifyDaemonSessionEvent(this.client.sessionId, event, spawnedBy).catch((error) => persistence.logger.debug("[Session] Failed to report session event to daemon:", error));
497
291
  };
498
292
  /** Produce an `error` notification for an unexpected session failure. */
499
293
  onSessionError = (message) => {
@@ -3924,6 +3718,7 @@ function applyClaudeSdkMetadata(current, update) {
3924
3718
  function createTurnSteeringController() {
3925
3719
  let interrupt = null;
3926
3720
  let steering = false;
3721
+ let interrupting = false;
3927
3722
  return {
3928
3723
  setInterrupt(next) {
3929
3724
  interrupt = next;
@@ -3948,17 +3743,31 @@ function createTurnSteeringController() {
3948
3743
  */
3949
3744
  async interruptTurn() {
3950
3745
  if (!interrupt) return false;
3951
- await interrupt();
3952
- return true;
3746
+ interrupting = true;
3747
+ try {
3748
+ await interrupt();
3749
+ return true;
3750
+ } catch (error) {
3751
+ interrupting = false;
3752
+ throw error;
3753
+ }
3953
3754
  },
3954
3755
  consumeReady() {
3955
3756
  if (!steering) return false;
3956
3757
  steering = false;
3957
3758
  return true;
3958
3759
  },
3760
+ /** The next `result` belongs to a stop-button interrupt: close the
3761
+ * turn as cancelled and say "Aborted by user", not "failed". */
3762
+ consumeInterrupted() {
3763
+ if (!interrupting) return false;
3764
+ interrupting = false;
3765
+ return true;
3766
+ },
3959
3767
  reset() {
3960
3768
  interrupt = null;
3961
3769
  steering = false;
3770
+ interrupting = false;
3962
3771
  }
3963
3772
  };
3964
3773
  }
@@ -4120,6 +3929,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
4120
3929
  return;
4121
3930
  }
4122
3931
  persistence.logger.debug("[remote]: interrupt did not stop the turn in time; escalating to hard abort");
3932
+ turnSteering.consumeInterrupted();
4123
3933
  }
4124
3934
  await abort();
4125
3935
  }
@@ -4442,7 +4252,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
4442
4252
  },
4443
4253
  onAuthFailure: (reason) => {
4444
4254
  session.client.sendSessionEvent({ type: "message", message: `Claude Code auth: ${reason}`, kind: "claude-auth-failed" });
4445
- void notifyDaemonClaudeAuthFailed(session.client.sessionId).catch((error) => persistence.logger.debug("[remote]: auth_failed report to daemon failed:", error));
4255
+ void api.notifyDaemonClaudeAuthFailed(session.client.sessionId).catch((error) => persistence.logger.debug("[remote]: auth_failed report to daemon failed:", error));
4446
4256
  },
4447
4257
  onSessionReset: () => {
4448
4258
  persistence.logger.debug("[remote]: Session reset");
@@ -4453,6 +4263,11 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
4453
4263
  session.client.closeClaudeSessionTurn("cancelled");
4454
4264
  return;
4455
4265
  }
4266
+ if (turnSteering.consumeInterrupted()) {
4267
+ session.client.closeClaudeSessionTurn("cancelled");
4268
+ session.client.sendSessionEvent({ type: "message", message: "Aborted by user" });
4269
+ return;
4270
+ }
4456
4271
  applyClaudeResultLifecycle(result, {
4457
4272
  closeCompleted: () => session.client.closeClaudeSessionTurn("completed"),
4458
4273
  closeFailed: (error) => session.client.closeClaudeSessionTurn("failed", { error }),
@@ -5313,7 +5128,7 @@ function getLogFiles(logDir) {
5313
5128
  async function runDoctorDaemon() {
5314
5129
  console.log(chalk.bold("\n\u{1F916} Daemon Status"));
5315
5130
  try {
5316
- const isRunning = await checkIfDaemonRunningAndCleanupStaleState();
5131
+ const isRunning = await api.checkIfDaemonRunningAndCleanupStaleState();
5317
5132
  const state = await persistence.readDaemonState();
5318
5133
  if (isRunning && state) {
5319
5134
  console.log(chalk.green("\u2713 Daemon is running"));
@@ -5516,7 +5331,7 @@ ${typeLabels[type] || type}:`));
5516
5331
  }
5517
5332
  console.log(chalk.bold("\n\u{1F916} Daemon Status"));
5518
5333
  try {
5519
- const isRunning = await checkIfDaemonRunningAndCleanupStaleState();
5334
+ const isRunning = await api.checkIfDaemonRunningAndCleanupStaleState();
5520
5335
  const state = await persistence.readDaemonState();
5521
5336
  const summary = daemonReadiness(authenticated, isRunning, Boolean(state));
5522
5337
  if (summary.level === "ready" && state) {
@@ -6281,6 +6096,7 @@ function startDaemonControlServer({
6281
6096
  onHappySessionWebhook,
6282
6097
  onSessionStateEvent,
6283
6098
  onClaudeAuthFailed,
6099
+ onSessionTurnEvent,
6284
6100
  pushClipboard,
6285
6101
  onTerminalHook,
6286
6102
  setTerminalTitle
@@ -6337,7 +6153,7 @@ function startDaemonControlServer({
6337
6153
  schema: {
6338
6154
  body: z.z.object({
6339
6155
  sessionId: z.z.string(),
6340
- event: z.z.enum(["completed", "needs_input", "auth_failed"]),
6156
+ event: z.z.enum(["completed", "needs_input", "auth_failed", "turn_started", "turn_ended"]),
6341
6157
  spawnedBy: z.z.string().optional()
6342
6158
  }),
6343
6159
  response: {
@@ -6353,6 +6169,10 @@ function startDaemonControlServer({
6353
6169
  onClaudeAuthFailed?.(sessionId);
6354
6170
  return { status: "ok" };
6355
6171
  }
6172
+ if (event === "turn_started" || event === "turn_ended") {
6173
+ onSessionTurnEvent?.(sessionId, event);
6174
+ return { status: "ok" };
6175
+ }
6356
6176
  onSessionStateEvent?.(sessionId, event, spawnedBy);
6357
6177
  return { status: "ok" };
6358
6178
  });
@@ -8055,7 +7875,7 @@ function parseJsonObject(text) {
8055
7875
  return null;
8056
7876
  }
8057
7877
  }
8058
- 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-CRRK5P1r.cjs', document.baseURI).href))).resolve(s)) {
7878
+ 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-__h-pCTK.cjs', document.baseURI).href))).resolve(s)) {
8059
7879
  const platformArch = `${platform}-${arch}`;
8060
7880
  const candidates = [
8061
7881
  `@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
@@ -9670,7 +9490,7 @@ function toSummary(id, persisted, extra) {
9670
9490
  };
9671
9491
  }
9672
9492
  async function listSessions(options = {}) {
9673
- const live = await listDaemonSessions();
9493
+ const live = await api.listDaemonSessions();
9674
9494
  return mergeSessionSummaries(live, persistence.readPersistedSessions(), options);
9675
9495
  }
9676
9496
  function summarizeAccountSession(row, persisted, liveIds, now) {
@@ -9740,7 +9560,7 @@ async function listAccountSessions(options = {}) {
9740
9560
  });
9741
9561
  const rows = Array.isArray(response.data?.sessions) ? response.data.sessions : [];
9742
9562
  const persisted = persistence.readPersistedSessions();
9743
- const live = await listDaemonSessions();
9563
+ const live = await api.listDaemonSessions();
9744
9564
  const liveIds = new Set(live.map((child) => child.happySessionId).filter((id) => typeof id === "string"));
9745
9565
  const now = Date.now();
9746
9566
  const summaries = rows.filter((row) => typeof row?.id === "string").map((row) => summarizeAccountSession(row, persisted[row.id], liveIds, now)).filter((summary) => options.includeArchived || !summary.archived);
@@ -9774,7 +9594,7 @@ async function readSessionTranscript(sessionId, limit) {
9774
9594
  const messages = Array.isArray(response.data?.messages) ? response.data.messages : [];
9775
9595
  messages.reverse();
9776
9596
  const key = persistence.decodeBase64(persisted.encryptionKey);
9777
- const live = await listDaemonSessions();
9597
+ const live = await api.listDaemonSessions();
9778
9598
  const bodies = messages.map((message) => {
9779
9599
  if (message.content?.t !== "encrypted") return null;
9780
9600
  try {
@@ -9790,7 +9610,7 @@ async function readSessionTranscript(sessionId, limit) {
9790
9610
  };
9791
9611
  }
9792
9612
  async function stopSession(sessionId) {
9793
- return await stopDaemonSession(sessionId);
9613
+ return await api.stopDaemonSession(sessionId);
9794
9614
  }
9795
9615
  async function archiveSession(sessionId) {
9796
9616
  const token = await bearerToken();
@@ -10218,7 +10038,7 @@ async function startDaemon() {
10218
10038
  });
10219
10039
  persistence.logger.debug("[DAEMON RUN] Starting daemon process...");
10220
10040
  persistence.logger.debugLargeJson("[DAEMON RUN] Environment", getEnvironmentInfo());
10221
- const runningDaemonVersionMatches = await isDaemonRunningCurrentlyInstalledHappyVersion();
10041
+ const runningDaemonVersionMatches = await api.isDaemonRunningCurrentlyInstalledHappyVersion();
10222
10042
  const runningDaemonState = await persistence.readDaemonState();
10223
10043
  const runningDaemonEndpointsMatch = Boolean(runningDaemonState) && daemonEndpointsMatch(
10224
10044
  runningDaemonState?.serverUrl,
@@ -10228,7 +10048,7 @@ async function startDaemon() {
10228
10048
  );
10229
10049
  if (!runningDaemonVersionMatches || !runningDaemonEndpointsMatch) {
10230
10050
  persistence.logger.debug("[DAEMON RUN] Daemon version or endpoint mismatch detected, restarting daemon");
10231
- await stopDaemon();
10051
+ await api.stopDaemon();
10232
10052
  } else {
10233
10053
  persistence.logger.debug("[DAEMON RUN] Daemon version matches, keeping existing daemon");
10234
10054
  console.log("Daemon already running with matching version");
@@ -10247,6 +10067,7 @@ async function startDaemon() {
10247
10067
  const { credentials, machineId } = await authAndSetupMachineIfNeeded();
10248
10068
  persistence.logger.debug("[DAEMON RUN] Auth and machine setup complete");
10249
10069
  const pidToTrackedSession = /* @__PURE__ */ new Map();
10070
+ const turnActivity = new api.TurnActivityTracker();
10250
10071
  const sessionIdToFinishedSession = /* @__PURE__ */ new Map();
10251
10072
  let teamWorker;
10252
10073
  const persisted = persistence.readPersistedSessions();
@@ -10518,6 +10339,9 @@ async function startDaemon() {
10518
10339
  if (options.resumeCodexThreadId) {
10519
10340
  extraEnv.HAPPY_FORK_CODEX_THREAD_ID = options.resumeCodexThreadId;
10520
10341
  }
10342
+ if (options.importCodexThreadId && UUID_RE.test(options.importCodexThreadId)) {
10343
+ extraEnv.HAPPY_IMPORT_CODEX_THREAD_ID = options.importCodexThreadId;
10344
+ }
10521
10345
  if (options.variant === "assistant") {
10522
10346
  extraEnv.HAPPY_SESSION_VARIANT = "assistant";
10523
10347
  }
@@ -11082,6 +10906,7 @@ async function startDaemon() {
11082
10906
  const onChildExited = (pid) => {
11083
10907
  const session = pidToTrackedSession.get(pid);
11084
10908
  if (session?.happySessionId && (session.spawnedBy === "teams" || teamWorker?.hasSession(session.happySessionId))) teamWorker?.report(session.happySessionId, "exited");
10909
+ if (session?.happySessionId) turnActivity.forget(session.happySessionId);
11085
10910
  if (session?.happySessionId && session.encryption) {
11086
10911
  sessionIdToFinishedSession.set(session.happySessionId, session);
11087
10912
  persistence.logger.debug(`[DAEMON RUN] Process PID ${pid} exited, preserved session ${session.happySessionId} for resume`);
@@ -11163,6 +10988,7 @@ async function startDaemon() {
11163
10988
  onHappySessionWebhook,
11164
10989
  onSessionStateEvent,
11165
10990
  onClaudeAuthFailed: (sessionId) => claudeAuthServiceRef?.signalAuthFailed(sessionId),
10991
+ onSessionTurnEvent: (sessionId, event) => turnActivity.apply(sessionId, event),
11166
10992
  pushClipboard: (text) => {
11167
10993
  if (!apiMachineRef) {
11168
10994
  return { delivered: false, truncated: false, totalBytes: 0, error: "daemon is still starting up" };
@@ -11275,7 +11101,10 @@ async function startDaemon() {
11275
11101
  const updateController = createUpdateController({
11276
11102
  policy: () => api.fetchCliUpdateState(persistence.configuration.serverUrl, persistence.packageJson.version),
11277
11103
  enabled: async () => ((await persistence.readSettings()).cliAutoUpdate ?? "idle") !== "off",
11278
- idle: () => pidToTrackedSession.size === 0 && !apiMachine.hasLiveTerminals(),
11104
+ // B-466: "idle" = no agent turn in flight. Idle wrappers survive a
11105
+ // handover (they talk to the server themselves) and web terminals live
11106
+ // in tmux, so neither is a reason to hold an update.
11107
+ idle: () => !turnActivity.hasActiveTurn(),
11279
11108
  install: installCliSafely,
11280
11109
  publish: (state) => {
11281
11110
  cliUpdateStateRef = state;
@@ -11330,7 +11159,7 @@ async function startDaemon() {
11330
11159
  } catch {
11331
11160
  }
11332
11161
  }
11333
- if (bundleReplaced && !teamWorker?.busy && !updateController.isRunning() && pidToTrackedSession.size === 0 && !apiMachine.hasLiveTerminals()) {
11162
+ if (bundleReplaced && !teamWorker?.busy && !updateController.isRunning() && !turnActivity.hasActiveTurn()) {
11334
11163
  const preflight = await preflightNewBundle(bundlePath);
11335
11164
  if (preflight.action === "hold") {
11336
11165
  if (lastHandoverHold !== preflight.reason) {
@@ -11340,7 +11169,7 @@ async function startDaemon() {
11340
11169
  updateController.holdHandover(preflight.reason);
11341
11170
  return;
11342
11171
  }
11343
- if (teamWorker?.busy || updateController.isRunning() || pidToTrackedSession.size > 0 || apiMachine.hasLiveTerminals()) return;
11172
+ if (teamWorker?.busy || updateController.isRunning() || turnActivity.hasActiveTurn()) return;
11344
11173
  lastHandoverHold = null;
11345
11174
  persistence.logger.debug("[DAEMON RUN] Daemon bundle replaced on disk and verified, handing off to new daemon");
11346
11175
  teamWorker?.stop();
@@ -11350,7 +11179,7 @@ async function startDaemon() {
11350
11179
  claudeAuthService.stop();
11351
11180
  apiMachine.shutdown();
11352
11181
  await stopControlServer();
11353
- await cleanupDaemonState();
11182
+ await api.cleanupDaemonState();
11354
11183
  await persistence.releaseDaemonLock(daemonLockHandle);
11355
11184
  await stopCaffeinate();
11356
11185
  try {
@@ -11423,7 +11252,7 @@ async function startDaemon() {
11423
11252
  }
11424
11253
  apiMachine.shutdown();
11425
11254
  await stopControlServer();
11426
- await cleanupDaemonState();
11255
+ await api.cleanupDaemonState();
11427
11256
  await stopCaffeinate();
11428
11257
  await persistence.releaseDaemonLock(daemonLockHandle);
11429
11258
  persistence.logger.debug("[DAEMON RUN] Cleanup completed, exiting process");
@@ -11731,7 +11560,7 @@ ${body}`);
11731
11560
  if (!normalized.ok) return fail(normalized.error);
11732
11561
  const directory = normalized.directory;
11733
11562
  try {
11734
- const result = await spawnDaemonSession(directory, void 0, { spawnedBy: "assistant" });
11563
+ const result = await api.spawnDaemonSession(directory, void 0, { spawnedBy: "assistant" });
11735
11564
  if (result?.error || !result?.sessionId) {
11736
11565
  return fail(`Failed to spawn session: ${result?.error ?? "daemon returned no session id"}`);
11737
11566
  }
@@ -12498,7 +12327,7 @@ function registerSideQuestionHandler(rpc, deps) {
12498
12327
  const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
12499
12328
  const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
12500
12329
  const run = deps.run ?? (async (input) => {
12501
- const { query } = await Promise.resolve().then(function () { return require('./index-CHP265gs.cjs'); });
12330
+ const { query } = await Promise.resolve().then(function () { return require('./index-BuQn9kUK.cjs'); });
12502
12331
  return runSideQuestion(query, input);
12503
12332
  });
12504
12333
  const slots = /* @__PURE__ */ new Map();
@@ -12600,7 +12429,7 @@ const MAX_TITLE_CHARS = 60;
12600
12429
  const GENERATION_TIMEOUT_MS = 3e4;
12601
12430
  function resolveClaudeBinary() {
12602
12431
  try {
12603
- 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-CRRK5P1r.cjs', document.baseURI).href)));
12432
+ 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-__h-pCTK.cjs', document.baseURI).href)));
12604
12433
  const utilsPath = path.resolve(path.join(api.projectPath(), "scripts", "claude_version_utils.cjs"));
12605
12434
  const { getClaudeCliPath } = require$1(utilsPath);
12606
12435
  const path$1 = getClaudeCliPath();
@@ -13162,7 +12991,7 @@ async function runClaude(credentials, options = {}) {
13162
12991
  }
13163
12992
  try {
13164
12993
  persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
13165
- const result = await notifyDaemonSessionStarted(response.id, metadata, {
12994
+ const result = await api.notifyDaemonSessionStarted(response.id, metadata, {
13166
12995
  encryptionKey: persistence.encodeBase64(response.encryptionKey),
13167
12996
  encryptionVariant: response.encryptionVariant,
13168
12997
  seq: response.seq,
@@ -13890,7 +13719,7 @@ async function handleAuthLogin(args) {
13890
13719
  console.log(chalk.gray(" \u2022 Re-authenticate and register machine\n"));
13891
13720
  try {
13892
13721
  persistence.logger.debug("Stopping daemon for force auth...");
13893
- await stopDaemon();
13722
+ await api.stopDaemon();
13894
13723
  console.log(chalk.gray("\u2713 Stopped daemon"));
13895
13724
  } catch (error) {
13896
13725
  persistence.logger.debug("Daemon was not running or failed to stop:", error);
@@ -13955,7 +13784,7 @@ async function handleAuthLogout() {
13955
13784
  if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
13956
13785
  try {
13957
13786
  try {
13958
- await stopDaemon();
13787
+ await api.stopDaemon();
13959
13788
  console.log(chalk.gray("Stopped daemon"));
13960
13789
  } catch {
13961
13790
  }
@@ -14000,7 +13829,7 @@ async function handleAuthStatus() {
14000
13829
  console.log(chalk.gray(`
14001
13830
  Data directory: ${persistence.configuration.happyHomeDir}`));
14002
13831
  try {
14003
- const running = await checkIfDaemonRunningAndCleanupStaleState();
13832
+ const running = await api.checkIfDaemonRunningAndCleanupStaleState();
14004
13833
  if (running) {
14005
13834
  console.log(chalk.green("\u2713 Daemon running"));
14006
13835
  } else {
@@ -14826,9 +14655,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
14826
14655
  };
14827
14656
  }
14828
14657
 
14829
- 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-CRRK5P1r.cjs', document.baseURI).href)));
14658
+ 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-__h-pCTK.cjs', document.baseURI).href)));
14830
14659
  const __dirname$1 = path.dirname(__filename$1);
14831
- const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-CRRK5P1r.cjs', document.baseURI).href)));
14660
+ const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-__h-pCTK.cjs', document.baseURI).href)));
14832
14661
  const PRISMA_QUERY_ENGINE_FILES = {
14833
14662
  "arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
14834
14663
  "x64-darwin": "libquery_engine-darwin.dylib.node",
@@ -15217,7 +15046,7 @@ const DAEMON_READY_TIMEOUT_MS = 5e3;
15217
15046
  const DAEMON_READY_POLL_INTERVAL_MS = 100;
15218
15047
  async function ensureDaemonRunning() {
15219
15048
  persistence.logger.debug("Ensuring Happy background service is running & matches our version...");
15220
- const versionMatches = await isDaemonRunningCurrentlyInstalledHappyVersion();
15049
+ const versionMatches = await api.isDaemonRunningCurrentlyInstalledHappyVersion();
15221
15050
  const state = await persistence.readDaemonState();
15222
15051
  const endpointsMatch = Boolean(state) && daemonEndpointsMatch(
15223
15052
  state?.serverUrl,
@@ -15228,9 +15057,9 @@ async function ensureDaemonRunning() {
15228
15057
  if (versionMatches && endpointsMatch) {
15229
15058
  return;
15230
15059
  }
15231
- if (await checkIfDaemonRunningAndCleanupStaleState()) {
15060
+ if (await api.checkIfDaemonRunningAndCleanupStaleState()) {
15232
15061
  persistence.logger.debug("Stopping daemon whose version or configured relay no longer matches...");
15233
- await stopDaemon();
15062
+ await api.stopDaemon();
15234
15063
  }
15235
15064
  persistence.logger.debug("Starting Happy background service...");
15236
15065
  const daemonProcess = spawnHappyCLI(["daemon", "start-sync"], {
@@ -15241,7 +15070,7 @@ async function ensureDaemonRunning() {
15241
15070
  daemonProcess.unref();
15242
15071
  const deadline = Date.now() + DAEMON_READY_TIMEOUT_MS;
15243
15072
  while (Date.now() < deadline) {
15244
- if (await checkIfDaemonRunningAndCleanupStaleState()) {
15073
+ if (await api.checkIfDaemonRunningAndCleanupStaleState()) {
15245
15074
  persistence.logger.debug("Happy background service is ready");
15246
15075
  return;
15247
15076
  }
@@ -16594,6 +16423,43 @@ async function resumeExistingThread(opts) {
16594
16423
  }
16595
16424
  }
16596
16425
 
16426
+ const IMPORT_CODEX_THREAD_ENV = "HAPPY_IMPORT_CODEX_THREAD_ID";
16427
+ async function importCodexThread(opts) {
16428
+ let forked;
16429
+ try {
16430
+ forked = await opts.client.forkThread({
16431
+ threadId: opts.threadId,
16432
+ cwd: opts.cwd,
16433
+ mcpServers: opts.mcpServers
16434
+ });
16435
+ } catch (error) {
16436
+ const reason = error instanceof Error ? error.message : String(error);
16437
+ throw new Error(`Failed to import Codex thread ${opts.threadId}: ${reason}`);
16438
+ }
16439
+ if (!forked.threadId || forked.threadId === opts.threadId) {
16440
+ throw new Error(`Failed to import Codex thread ${opts.threadId}: Codex did not create an independent copy`);
16441
+ }
16442
+ opts.session.updateMetadata((currentMetadata) => ({
16443
+ ...currentMetadata,
16444
+ codexThreadId: forked.threadId,
16445
+ importedFromCodexThreadId: opts.threadId
16446
+ }));
16447
+ let thread = forked.thread;
16448
+ if (!Array.isArray(thread?.turns)) {
16449
+ thread = (await opts.client.readThread({ threadId: forked.threadId, includeTurns: true })).thread;
16450
+ }
16451
+ const envelopes = mapCodexThreadToSessionEnvelopes(thread);
16452
+ for (const envelope of envelopes) {
16453
+ opts.session.sendSessionProtocolMessage(envelope);
16454
+ }
16455
+ opts.messageBuffer.addMessage(`Imported thread ${agentGuidance.trimIdent(opts.threadId)} as ${agentGuidance.trimIdent(forked.threadId)}`, "status");
16456
+ opts.session.sendSessionEvent({
16457
+ type: "message",
16458
+ message: `Imported Codex thread ${opts.threadId} (continuing as ${forked.threadId})`
16459
+ });
16460
+ return { threadId: forked.threadId, model: forked.model, replayed: envelopes.length };
16461
+ }
16462
+
16597
16463
  function emitReadyIfIdle({ pending, queueSize, shouldExit, sendReady, notify }) {
16598
16464
  if (shouldExit) {
16599
16465
  return false;
@@ -16808,6 +16674,12 @@ async function runCodex(opts) {
16808
16674
  ...forkedFromMessageId ? { forkedFromMessageId } : {}
16809
16675
  });
16810
16676
  metadata.attachmentKinds = [...CLAUDE_ATTACHMENT_KINDS];
16677
+ const importCodexThreadId = process.env[IMPORT_CODEX_THREAD_ENV];
16678
+ if (importCodexThreadId) {
16679
+ metadata.importedFromCodexThreadId = importCodexThreadId;
16680
+ const importTitle = process.env.HAPPY_IMPORT_TITLE;
16681
+ if (importTitle) metadata.summary = { text: importTitle, updatedAt: Date.now() };
16682
+ }
16811
16683
  const reconnectSessionId = process.env.HAPPY_RECONNECT_SESSION_ID;
16812
16684
  const reconnectKeyBase64 = process.env.HAPPY_RECONNECT_ENCRYPTION_KEY;
16813
16685
  const reconnectVariant = process.env.HAPPY_RECONNECT_ENCRYPTION_VARIANT;
@@ -16878,7 +16750,7 @@ async function runCodex(opts) {
16878
16750
  if (response) {
16879
16751
  try {
16880
16752
  persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
16881
- const result = await notifyDaemonSessionStarted(response.id, metadata, {
16753
+ const result = await api.notifyDaemonSessionStarted(response.id, metadata, {
16882
16754
  encryptionKey: persistence.encodeBase64(response.encryptionKey),
16883
16755
  encryptionVariant: response.encryptionVariant,
16884
16756
  seq: response.seq,
@@ -17326,6 +17198,18 @@ async function runCodex(opts) {
17326
17198
  first = false;
17327
17199
  appendSystemPromptInjected = true;
17328
17200
  }
17201
+ if (!reconnectSessionId && !opts.resumeThreadId && importCodexThreadId) {
17202
+ await importCodexThread({
17203
+ client,
17204
+ session,
17205
+ messageBuffer,
17206
+ threadId: importCodexThreadId,
17207
+ cwd: process.cwd(),
17208
+ mcpServers
17209
+ });
17210
+ first = false;
17211
+ appendSystemPromptInjected = true;
17212
+ }
17329
17213
  const forkCodexThreadId = process.env.HAPPY_FORK_CODEX_THREAD_ID;
17330
17214
  if (!reconnectSessionId && forkCodexThreadId) {
17331
17215
  try {
@@ -17679,7 +17563,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17679
17563
  process.exit(0);
17680
17564
  } else if (subcommand === "install-terminal-hooks") {
17681
17565
  try {
17682
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-CWGkoWDD.cjs'); });
17566
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-D3jfvbyY.cjs'); });
17683
17567
  const command = parseTerminalHooksArgs(args.slice(1));
17684
17568
  if (command.action === "help") {
17685
17569
  console.log(TERMINAL_HOOKS_HELP);
@@ -17696,7 +17580,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17696
17580
  }
17697
17581
  } else if (subcommand === "spawn") {
17698
17582
  try {
17699
- const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-BORLpj60.cjs'); });
17583
+ const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-BhUK0Vt2.cjs'); });
17700
17584
  await handleSpawnCommand(args.slice(1));
17701
17585
  } catch (error) {
17702
17586
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17708,7 +17592,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17708
17592
  return;
17709
17593
  } else if (subcommand === "sessions") {
17710
17594
  try {
17711
- const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-9A-uoJL_.cjs'); });
17595
+ const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-CGBBgVZn.cjs'); });
17712
17596
  await handleSessionsCommand(args.slice(1));
17713
17597
  } catch (error) {
17714
17598
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17720,7 +17604,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17720
17604
  return;
17721
17605
  } else if (subcommand === "send") {
17722
17606
  try {
17723
- const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-BkypdBpK.cjs'); });
17607
+ const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-DP_S3wn0.cjs'); });
17724
17608
  await handleSendCommand(args.slice(1));
17725
17609
  } catch (error) {
17726
17610
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17826,9 +17710,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17826
17710
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
17827
17711
  const projectId = args[3];
17828
17712
  try {
17829
- const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-DpuZN2Rs.cjs'); });
17830
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-CfzVummd.cjs'); }).then(function (n) { return n.persistence; });
17831
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-CRxf_3n8.cjs'); }).then(function (n) { return n.api; });
17713
+ const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-D0-jnCOC.cjs'); });
17714
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-Dbip6eVO.cjs'); }).then(function (n) { return n.persistence; });
17715
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DCVS050m.cjs'); }).then(function (n) { return n.api; });
17832
17716
  let userEmail = void 0;
17833
17717
  try {
17834
17718
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -17859,7 +17743,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17859
17743
  }
17860
17744
  if (geminiSubcommand === "project" && args[2] === "get") {
17861
17745
  try {
17862
- const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-DpuZN2Rs.cjs'); });
17746
+ const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-D0-jnCOC.cjs'); });
17863
17747
  const config = readGeminiLocalConfig();
17864
17748
  if (config.googleCloudProject) {
17865
17749
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -17899,7 +17783,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17899
17783
  process.exit(0);
17900
17784
  }
17901
17785
  try {
17902
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BUVjTJKn.cjs'); });
17786
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-D34eCFpz.cjs'); });
17903
17787
  let startedBy = void 0;
17904
17788
  for (let i = 1; i < args.length; i++) {
17905
17789
  if (args[i] === "--started-by") {
@@ -17929,7 +17813,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17929
17813
  }
17930
17814
  };
17931
17815
  try {
17932
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-3N-qu-RG.cjs'); });
17816
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-DJvzGXVN.cjs'); });
17933
17817
  const parsed = parsePiRunnerArgs(args.slice(1));
17934
17818
  const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
17935
17819
  const { credentials } = await authAndSetupMachineIfNeeded();
@@ -17957,7 +17841,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17957
17841
  return;
17958
17842
  } else if (subcommand === "acp") {
17959
17843
  try {
17960
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-3N-qu-RG.cjs'); });
17844
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-DJvzGXVN.cjs'); });
17961
17845
  let startedBy = void 0;
17962
17846
  let verbose = false;
17963
17847
  const acpArgs = [];
@@ -17997,7 +17881,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17997
17881
  return;
17998
17882
  } else if (subcommand === "openclaw") {
17999
17883
  try {
18000
- const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-Bj2EgRHB.cjs'); });
17884
+ const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-B8F8D--R.cjs'); });
18001
17885
  let startedBy = void 0;
18002
17886
  let verbose = false;
18003
17887
  let gatewayUrl;
@@ -18048,7 +17932,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18048
17932
  return;
18049
17933
  } else if (subcommand === "todo") {
18050
17934
  try {
18051
- const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-DydKcknX.cjs'); });
17935
+ const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-CeJX0z_2.cjs'); });
18052
17936
  await handleTodoCommand(args.slice(1));
18053
17937
  } catch (error) {
18054
17938
  console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
@@ -18057,7 +17941,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18057
17941
  return;
18058
17942
  } else if (subcommand === "teams") {
18059
17943
  try {
18060
- const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-9x2FO9RW.cjs'); });
17944
+ const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-C29nEHFD.cjs'); });
18061
17945
  await handleTeamsCommand(args.slice(1));
18062
17946
  } catch (error) {
18063
17947
  console.error(error instanceof Error ? error.message : "Teams command failed");
@@ -18066,7 +17950,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18066
17950
  return;
18067
17951
  } else if (subcommand === "mcp" && args.length === 1) {
18068
17952
  try {
18069
- const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-CN2UVfut.cjs'); });
17953
+ const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-DeapmTWN.cjs'); });
18070
17954
  await handleMcpCommand();
18071
17955
  } catch (error) {
18072
17956
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -18089,7 +17973,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18089
17973
  const daemonSubcommand = args[1];
18090
17974
  if (daemonSubcommand === "list") {
18091
17975
  try {
18092
- const sessions = await listDaemonSessions();
17976
+ const sessions = await api.listDaemonSessions();
18093
17977
  if (sessions.length === 0) {
18094
17978
  console.log("No active sessions this daemon is aware of (they might have been started by a previous version of the daemon)");
18095
17979
  } else {
@@ -18107,7 +17991,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18107
17991
  process.exit(1);
18108
17992
  }
18109
17993
  try {
18110
- const success = await stopDaemonSession(sessionId);
17994
+ const success = await api.stopDaemonSession(sessionId);
18111
17995
  console.log(success ? "Session stopped" : "Failed to stop session");
18112
17996
  } catch (error) {
18113
17997
  console.log("No daemon running");
@@ -18115,7 +17999,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18115
17999
  return;
18116
18000
  } else if (daemonSubcommand === "start") {
18117
18001
  const currentState = await persistence.readDaemonState();
18118
- const running = await checkIfDaemonRunningAndCleanupStaleState();
18002
+ const running = await api.checkIfDaemonRunningAndCleanupStaleState();
18119
18003
  const currentDaemonMatches = currentState && currentState.startedWithCliVersion === persistence.configuration.currentCliVersion && daemonEndpointsMatch(
18120
18004
  currentState.serverUrl,
18121
18005
  currentState.webappUrl,
@@ -18124,7 +18008,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18124
18008
  );
18125
18009
  if (running && !currentDaemonMatches) {
18126
18010
  console.log("Configured relay or CLI version changed; restarting the existing daemon");
18127
- await stopDaemon();
18011
+ await api.stopDaemon();
18128
18012
  }
18129
18013
  const child = spawnHappyCLI(["daemon", "start-sync"], {
18130
18014
  detached: true,
@@ -18134,7 +18018,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18134
18018
  child.unref();
18135
18019
  let started = false;
18136
18020
  for (let i = 0; i < 50; i++) {
18137
- if (await checkIfDaemonRunningAndCleanupStaleState()) {
18021
+ if (await api.checkIfDaemonRunningAndCleanupStaleState()) {
18138
18022
  started = true;
18139
18023
  break;
18140
18024
  }
@@ -18151,7 +18035,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
18151
18035
  await startDaemon();
18152
18036
  process.exit(0);
18153
18037
  } else if (daemonSubcommand === "stop") {
18154
- await stopDaemon();
18038
+ await api.stopDaemon();
18155
18039
  process.exit(0);
18156
18040
  } else if (daemonSubcommand === "status") {
18157
18041
  await runDoctorDaemon();
@@ -18448,7 +18332,6 @@ exports.TEAM_SKILL = TEAM_SKILL;
18448
18332
  exports.TitleGenerator = TitleGenerator;
18449
18333
  exports.appendStagedAttachmentsToPrompt = appendStagedAttachmentsToPrompt;
18450
18334
  exports.archiveSession = archiveSession;
18451
- exports.checkIfDaemonRunningAndCleanupStaleState = checkIfDaemonRunningAndCleanupStaleState;
18452
18335
  exports.createSessionMetadata = createSessionMetadata;
18453
18336
  exports.hashObject = hashObject;
18454
18337
  exports.initialMachineMetadata = initialMachineMetadata;
@@ -18456,8 +18339,6 @@ exports.isValidSpawnOrigin = isValidSpawnOrigin;
18456
18339
  exports.listAccountSessions = listAccountSessions;
18457
18340
  exports.listSessions = listSessions;
18458
18341
  exports.normalizeAcpPermissionMode = normalizeAcpPermissionMode;
18459
- exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
18460
- exports.pushClipboardViaDaemon = pushClipboardViaDaemon;
18461
18342
  exports.query = query;
18462
18343
  exports.readSessionTranscript = readSessionTranscript;
18463
18344
  exports.registerAgentAttachmentDownloads = registerAgentAttachmentDownloads;
@@ -18468,9 +18349,7 @@ exports.resolvePermissionRequest = resolvePermissionRequest;
18468
18349
  exports.sanitizeSpawnPermissionMode = sanitizeSpawnPermissionMode;
18469
18350
  exports.sendUserMessage = sendUserMessage;
18470
18351
  exports.sessionWebUrl = sessionWebUrl;
18471
- exports.setTerminalTitleViaDaemon = setTerminalTitleViaDaemon;
18472
18352
  exports.setupOfflineReconnection = setupOfflineReconnection;
18473
- exports.spawnDaemonSession = spawnDaemonSession;
18474
18353
  exports.stageClaudeAttachments = stageClaudeAttachments;
18475
18354
  exports.startHappyServer = startHappyServer;
18476
18355
  exports.stopSession = stopSession;