very-happy-cli 0.2.110 → 0.2.112

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 (35) hide show
  1. package/dist/{AcpBackend-D0_wbTs6.cjs → AcpBackend-B3x-gQWP.cjs} +1 -1
  2. package/dist/{AcpBackend-DzZR7TEv.mjs → AcpBackend-DDEdYVW2.mjs} +1 -1
  3. package/dist/{AcpSessionManager-tWuFWeIF.mjs → AcpSessionManager-BORAhQ1r.mjs} +1 -1
  4. package/dist/{AcpSessionManager-Dcj_iHw8.cjs → AcpSessionManager-DGPLD-go.cjs} +1 -1
  5. package/dist/{config-CTyyVXHj.mjs → config-B_L5vXXu.mjs} +2 -2
  6. package/dist/{config-CTCGilz_.cjs → config-KX6e7GEu.cjs} +2 -2
  7. package/dist/{index-D-adqB7g.cjs → index-B7-t5Kwz.cjs} +4 -4
  8. package/dist/{index-CvnMiYgh.cjs → index-BnRQP3PL.cjs} +250 -20
  9. package/dist/{index-DW78HyvK.cjs → index-CTd0skWH.cjs} +2 -2
  10. package/dist/{index-Brhvj7p0.mjs → index-Cu5FdgTq.mjs} +5 -5
  11. package/dist/{index-BW9kDx5m.mjs → index-inkhalP5.mjs} +245 -17
  12. package/dist/{index-jYltd-ZW.mjs → index-lQzCAx9I.mjs} +2 -2
  13. package/dist/index.cjs +2 -2
  14. package/dist/index.mjs +2 -2
  15. package/dist/{installTerminalHooks-DhQ6k7YD.cjs → installTerminalHooks-BVk-r0yD.cjs} +2 -2
  16. package/dist/{installTerminalHooks-CJyoR9jp.mjs → installTerminalHooks-CQiW7Jn9.mjs} +2 -2
  17. package/dist/lib.cjs +1 -1
  18. package/dist/lib.d.cts +44 -0
  19. package/dist/lib.d.mts +44 -0
  20. package/dist/lib.mjs +1 -1
  21. package/dist/{mcp-Dr1PegOw.cjs → mcp-D0DIU8Q2.cjs} +2 -2
  22. package/dist/{mcp-BO9-sxMr.mjs → mcp-DD-0VkiA.mjs} +2 -2
  23. package/dist/{runGemini-CuzqF6Ys.mjs → runGemini-DHyBDo5P.mjs} +4 -4
  24. package/dist/{runGemini-D6Wwfk_0.cjs → runGemini-Dq1d8Ccb.cjs} +4 -4
  25. package/dist/{runOpenClaw-BYmlS-4Q.cjs → runOpenClaw-BHXnUF_m.cjs} +3 -3
  26. package/dist/{runOpenClaw-B5pkmSTb.mjs → runOpenClaw-DX-tgQ2V.mjs} +3 -3
  27. package/dist/{send-Btz1IZ9U.mjs → send-0TYDXiGx.mjs} +2 -2
  28. package/dist/{send-CuajooZC.cjs → send-By6zEUWo.cjs} +2 -2
  29. package/dist/{sessions-CVUBS3LG.cjs → sessions-DTBRcBRk.cjs} +2 -2
  30. package/dist/{sessions-DDwCphTQ.mjs → sessions-TM8VaCMY.mjs} +2 -2
  31. package/dist/{spawn-CwS8CPbr.cjs → spawn-CweTEYze.cjs} +57 -4
  32. package/dist/{spawn-DcA80_VN.mjs → spawn-D0oTo5BT.mjs} +56 -5
  33. package/dist/{types-BdO0jg7G.mjs → types-C5ewhu1Q.mjs} +96 -11
  34. package/dist/{types--t4zLibT.cjs → types-R11tMGyX.cjs} +97 -11
  35. package/package.json +7 -7
@@ -1,7 +1,7 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
2
  import os, { homedir, userInfo } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
4
- import { o as readDaemonState, l as logger, c as configuration, q as clearDaemonState, s as getProjectPath, p as projectPath, t as initializeSandbox, u as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, v as AsyncLock, x as ensurePrivateDirectory, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, y as hardenPrivateFile, f as packageJson, j as readSettings, z as readCredentials, B as credentialRelayProblem, C as deriveLocalCliUpdateSummary, k as encodeBase64, D as updateSettings, E as encodeBase64Url, F as decodeBase64, G as writeCredentialsLegacy, H as writeCredentialsDataKey, J as readCredentialsForConfiguredRelay, K as encrypt, r as readPersistedSessions, L as isClaudeSessionId, N as getLocalHappyAgentCredentialPath, O as readLocalHappyAgentCredentials, P as decryptWithDataKey, Q as decryptLegacy, S as extractCompleteLines, T as decideBackfill, U as parseTerminalHookPayload, V as tmuxArgs, W as scrubTmuxClientEnv, X as decideMirrorBinding, Y as MIRROR_BACKFILL_LINES_DEFAULT, Z as persistSession, _ as mirrorLineKey, $ as mirrorLocalId, w as writePrivateFileSync, a0 as detectResumeSupport, a1 as detectCLIAvailability, a2 as acquireDaemonLock, a3 as summarizeSpawnSessionForLog, a4 as deletePersistedSessions, a5 as shellescape, a6 as decrypt, a7 as writeDaemonState, A as ApiClient, a8 as writeSettings, a9 as fetchCliUpdateState, aa as resolveCliUpdateCheckInterval, ab as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, ac as releaseDaemonLock, i as isValidSessionId, ad as listVhTerminals, ae as isValidTerminalId, af as readVhTerminal, ag as sendToVhTerminal, ah as TITLE_PROMPT_PREFIX, ai as BOARD_ANALYZER_PROMPT_PREFIX, h as connectionState, aj as startOfflineReconnection, ak as clearCredentials, al as clearMachineId, m as ensurePrivateDirectorySync, am as SandboxConfigSchema, b as createEnvelope, an as CodexAppServerClient, ao as getLatestDaemonLog } from './types-BdO0jg7G.mjs';
4
+ import { o as readDaemonState, l as logger, c as configuration, q as clearDaemonState, s as getProjectPath, p as projectPath, t as initializeSandbox, u as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, v as AsyncLock, S as STREAM_DELTA_MAX_CHARS, x as ensurePrivateDirectory, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, y as hardenPrivateFile, f as packageJson, j as readSettings, z as readCredentials, B as credentialRelayProblem, C as deriveLocalCliUpdateSummary, k as encodeBase64, D as updateSettings, E as encodeBase64Url, F as decodeBase64, G as writeCredentialsLegacy, H as writeCredentialsDataKey, J as readCredentialsForConfiguredRelay, K as encrypt, r as readPersistedSessions, L as isClaudeSessionId, N as getLocalHappyAgentCredentialPath, O as readLocalHappyAgentCredentials, P as decryptWithDataKey, Q as decryptLegacy, T as extractCompleteLines, U as decideBackfill, V as parseTerminalHookPayload, W as tmuxArgs, X as scrubTmuxClientEnv, Y as decideMirrorBinding, Z as MIRROR_BACKFILL_LINES_DEFAULT, _ as persistSession, $ as mirrorLineKey, a0 as mirrorLocalId, w as writePrivateFileSync, a1 as detectResumeSupport, a2 as detectCLIAvailability, a3 as acquireDaemonLock, a4 as summarizeSpawnSessionForLog, a5 as deletePersistedSessions, a6 as shellescape, a7 as decrypt, a8 as writeDaemonState, A as ApiClient, a9 as writeSettings, aa as fetchCliUpdateState, ab as resolveCliUpdateCheckInterval, ac as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, ad as releaseDaemonLock, i as isValidSessionId, ae as listVhTerminals, af as isValidTerminalId, ag as readVhTerminal, ah as sendToVhTerminal, ai as TITLE_PROMPT_PREFIX, aj as BOARD_ANALYZER_PROMPT_PREFIX, h as connectionState, ak as startOfflineReconnection, al as clearCredentials, am as clearMachineId, m as ensurePrivateDirectorySync, an as SandboxConfigSchema, b as createEnvelope, ao as CodexAppServerClient, ap as getLatestDaemonLog } from './types-C5ewhu1Q.mjs';
5
5
  import spawn$1, { spawn } from 'cross-spawn';
6
6
  import path, { join, resolve, basename, delimiter, isAbsolute, normalize, sep, dirname } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
@@ -169,7 +169,14 @@ async function stopDaemonSession(sessionId) {
169
169
  return result.success || false;
170
170
  }
171
171
  async function spawnDaemonSession(directory, sessionId, opts) {
172
- const result = await daemonPost("/spawn-session", { directory, sessionId, spawnedBy: opts?.spawnedBy });
172
+ const result = await daemonPost("/spawn-session", {
173
+ directory,
174
+ sessionId,
175
+ spawnedBy: opts?.spawnedBy,
176
+ permissionMode: opts?.permissionMode,
177
+ agent: opts?.agent,
178
+ environmentVariables: opts?.environmentVariables
179
+ });
173
180
  return result;
174
181
  }
175
182
  async function notifyDaemonSessionEvent(sessionId, event, spawnedBy) {
@@ -1996,7 +2003,14 @@ async function claudeRemote(opts) {
1996
2003
  onUserDialog: opts.onUserDialog,
1997
2004
  supportedDialogKinds: opts.onUserDialog ? ["refusal_fallback_prompt"] : void 0,
1998
2005
  abort: opts.signal,
1999
- settingsPath: opts.hookSettingsPath
2006
+ settingsPath: opts.hookSettingsPath,
2007
+ // B-309: token-level partials. Without this the SDK emits nothing
2008
+ // between "turn started" and "entire assistant message", which is
2009
+ // exactly why the web used to show a spinner where the terminal shows
2010
+ // the model thinking out loud. The partials do NOT enter the
2011
+ // transcript; they are split off below and relayed on a side channel.
2012
+ // Only pay for them when someone is listening.
2013
+ includePartialMessages: opts.onStreamFrame ? true : void 0
2000
2014
  };
2001
2015
  let thinking = false;
2002
2016
  const updateThinking = (newThinking) => {
@@ -2046,10 +2060,26 @@ async function claudeRemote(opts) {
2046
2060
  try {
2047
2061
  logger.debug(`[claudeRemote] Starting to iterate over response`);
2048
2062
  for await (const message of response) {
2063
+ if (message.type === "stream_event") {
2064
+ if (opts.onStreamFrame && !message.parent_tool_use_id) {
2065
+ opts.onStreamFrame({ type: "stream_event", event: message.event });
2066
+ }
2067
+ continue;
2068
+ }
2049
2069
  logger.debug(`[claudeRemote] Message ${message.type}`, contentLogMetadata(message));
2050
2070
  if (message.type === "assistant" && message.error) {
2051
2071
  lastAssistantError = message.error;
2052
2072
  }
2073
+ if (opts.onStreamFrame && message.type === "system") {
2074
+ const subtype = message.subtype;
2075
+ if (subtype === "thinking_tokens") {
2076
+ const tokens = message;
2077
+ opts.onStreamFrame({ type: "system", subtype: "thinking_tokens", estimated_tokens: tokens.estimated_tokens });
2078
+ } else if (subtype === "status") {
2079
+ const status = message;
2080
+ opts.onStreamFrame({ type: "system", subtype: "status", status: status.status });
2081
+ }
2082
+ }
2053
2083
  const outboundMessage = isCompactCommand && message.type === "assistant" ? { ...message, isCompactSummary: true } : message;
2054
2084
  opts.onMessage(outboundMessage);
2055
2085
  if (message.type === "system" && message.subtype === "init") {
@@ -3249,6 +3279,197 @@ class OutgoingMessageQueue {
3249
3279
  }
3250
3280
  }
3251
3281
 
3282
+ const STREAM_FLUSH_MS = 80;
3283
+ const PROGRESS_FLUSH_MS = 250;
3284
+ const STREAM_FLUSH_MAX_BYTES = 16 * 1024;
3285
+ class StreamRelay {
3286
+ send;
3287
+ setTimer;
3288
+ clearTimer;
3289
+ now;
3290
+ /** The block currently accumulating deltas. At most one is open at a time
3291
+ * in practice; a switch flushes the previous one first, so out-of-order
3292
+ * SDK frames degrade to "slightly chunkier", never to interleaved text. */
3293
+ pending = null;
3294
+ flushHandle = null;
3295
+ progress = {};
3296
+ progressDirty = false;
3297
+ progressHandle = null;
3298
+ /** Message id of the block currently open, so `content_block_delta` (which
3299
+ * carries only an index) can be attributed. Reset per assistant message. */
3300
+ currentMid = null;
3301
+ openBlocks = /* @__PURE__ */ new Set();
3302
+ /** True while nothing has been ingested since the last sweep. Both the SDK
3303
+ * `result` frame and the launcher's `finally` call endTurn (the second is
3304
+ * the safety net for turns that die before producing a result), so
3305
+ * without this a normal turn would emit two sweeps. */
3306
+ idleSinceTurnEnd = true;
3307
+ constructor(options) {
3308
+ this.send = options.send;
3309
+ this.setTimer = options.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
3310
+ this.clearTimer = options.clearTimer ?? ((handle) => clearTimeout(handle));
3311
+ this.now = options.now ?? (() => Date.now());
3312
+ }
3313
+ /** Feed one SDK frame. Unknown shapes are ignored, never thrown on: this
3314
+ * channel must not be able to take a turn down. */
3315
+ ingest(message) {
3316
+ this.idleSinceTurnEnd = false;
3317
+ try {
3318
+ if (message.type === "stream_event") {
3319
+ this.ingestStreamEvent(message.event);
3320
+ return;
3321
+ }
3322
+ if (message.type === "system" && message.subtype === "thinking_tokens") {
3323
+ if (typeof message.estimated_tokens === "number") {
3324
+ this.setProgress({ thinkingTokens: message.estimated_tokens });
3325
+ }
3326
+ return;
3327
+ }
3328
+ if (message.type === "system" && message.subtype === "status") {
3329
+ const status = message.status === "requesting" || message.status === "compacting" ? message.status : void 0;
3330
+ this.progress.status = status;
3331
+ this.progressDirty = true;
3332
+ this.scheduleProgress();
3333
+ return;
3334
+ }
3335
+ } catch {
3336
+ }
3337
+ }
3338
+ /** The turn produced its result. Flushes everything and tells the web to
3339
+ * sweep drafts that no persisted message ever claimed. */
3340
+ endTurn() {
3341
+ if (this.idleSinceTurnEnd) {
3342
+ this.clearTimers();
3343
+ return;
3344
+ }
3345
+ this.idleSinceTurnEnd = true;
3346
+ this.flushPending();
3347
+ this.closeOpenBlocks();
3348
+ this.flushProgress();
3349
+ this.progress = {};
3350
+ this.currentMid = null;
3351
+ this.send({ t: "turn-end" });
3352
+ }
3353
+ /** Release timers without emitting anything (session teardown). */
3354
+ dispose() {
3355
+ this.clearTimers();
3356
+ this.pending = null;
3357
+ this.openBlocks.clear();
3358
+ }
3359
+ clearTimers() {
3360
+ if (this.flushHandle !== null) this.clearTimer(this.flushHandle);
3361
+ if (this.progressHandle !== null) this.clearTimer(this.progressHandle);
3362
+ this.flushHandle = null;
3363
+ this.progressHandle = null;
3364
+ }
3365
+ ingestStreamEvent(event) {
3366
+ const e = event;
3367
+ if (!e || typeof e.type !== "string") return;
3368
+ if (e.type === "message_start") {
3369
+ const mid = e.message?.id;
3370
+ this.flushPending();
3371
+ this.closeOpenBlocks();
3372
+ this.currentMid = typeof mid === "string" && mid.length > 0 ? mid : null;
3373
+ return;
3374
+ }
3375
+ if (e.type === "content_block_start") {
3376
+ const kind = e.content_block?.type === "thinking" ? "thinking" : e.content_block?.type === "text" ? "text" : null;
3377
+ if (!kind || !this.currentMid || typeof e.index !== "number") return;
3378
+ this.flushPending();
3379
+ this.openBlocks.add(e.index);
3380
+ this.send({ t: "block-start", mid: this.currentMid, idx: e.index, kind });
3381
+ return;
3382
+ }
3383
+ if (e.type === "content_block_delta") {
3384
+ const delta = e.delta;
3385
+ const text = delta?.type === "text_delta" ? delta.text : delta?.type === "thinking_delta" ? delta.thinking : null;
3386
+ if (typeof text !== "string" || text.length === 0) return;
3387
+ if (!this.currentMid || typeof e.index !== "number") return;
3388
+ if (!this.openBlocks.has(e.index)) return;
3389
+ this.appendDelta(this.currentMid, e.index, text);
3390
+ return;
3391
+ }
3392
+ if (e.type === "content_block_stop") {
3393
+ if (!this.currentMid || typeof e.index !== "number") return;
3394
+ if (!this.openBlocks.has(e.index)) return;
3395
+ this.flushPending();
3396
+ this.openBlocks.delete(e.index);
3397
+ this.send({ t: "block-end", mid: this.currentMid, idx: e.index });
3398
+ return;
3399
+ }
3400
+ if (e.type === "message_delta") {
3401
+ const outputTokens = e.usage?.output_tokens;
3402
+ if (typeof outputTokens === "number") {
3403
+ this.setProgress({ outputTokens });
3404
+ }
3405
+ return;
3406
+ }
3407
+ }
3408
+ appendDelta(mid, idx, text) {
3409
+ if (this.pending && (this.pending.mid !== mid || this.pending.idx !== idx)) {
3410
+ this.flushPending();
3411
+ }
3412
+ if (!this.pending) {
3413
+ this.pending = { mid, idx, text: "", bytes: 0 };
3414
+ }
3415
+ this.pending.text += text;
3416
+ this.pending.bytes += Buffer.byteLength(text, "utf8");
3417
+ if (this.pending.bytes >= STREAM_FLUSH_MAX_BYTES || this.pending.text.length >= STREAM_DELTA_MAX_CHARS) {
3418
+ this.flushPending();
3419
+ return;
3420
+ }
3421
+ if (this.flushHandle === null) {
3422
+ this.flushHandle = this.setTimer(() => {
3423
+ this.flushHandle = null;
3424
+ this.flushPending();
3425
+ }, STREAM_FLUSH_MS);
3426
+ }
3427
+ }
3428
+ flushPending() {
3429
+ if (this.flushHandle !== null) {
3430
+ this.clearTimer(this.flushHandle);
3431
+ this.flushHandle = null;
3432
+ }
3433
+ const pending = this.pending;
3434
+ this.pending = null;
3435
+ if (!pending || pending.text.length === 0) return;
3436
+ this.send({ t: "block-delta", mid: pending.mid, idx: pending.idx, text: pending.text });
3437
+ }
3438
+ /** Close blocks the SDK never stopped (interrupt, error, message switch) so
3439
+ * the web's draft does not keep a blinking cursor forever. */
3440
+ closeOpenBlocks() {
3441
+ if (!this.currentMid || this.openBlocks.size === 0) {
3442
+ this.openBlocks.clear();
3443
+ return;
3444
+ }
3445
+ for (const idx of [...this.openBlocks].sort((a, b) => a - b)) {
3446
+ this.send({ t: "block-end", mid: this.currentMid, idx });
3447
+ }
3448
+ this.openBlocks.clear();
3449
+ }
3450
+ setProgress(patch) {
3451
+ this.progress = { ...this.progress, ...patch };
3452
+ this.progressDirty = true;
3453
+ this.scheduleProgress();
3454
+ }
3455
+ scheduleProgress() {
3456
+ if (this.progressHandle !== null) return;
3457
+ this.progressHandle = this.setTimer(() => {
3458
+ this.progressHandle = null;
3459
+ this.flushProgress();
3460
+ }, PROGRESS_FLUSH_MS);
3461
+ }
3462
+ flushProgress() {
3463
+ if (this.progressHandle !== null) {
3464
+ this.clearTimer(this.progressHandle);
3465
+ this.progressHandle = null;
3466
+ }
3467
+ if (!this.progressDirty) return;
3468
+ this.progressDirty = false;
3469
+ this.send({ t: "progress", ...this.progress });
3470
+ }
3471
+ }
3472
+
3252
3473
  function getAskUserQuestionToolCallIds(message) {
3253
3474
  if (message.type !== "assistant") {
3254
3475
  return [];
@@ -3629,6 +3850,10 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
3629
3850
  return nextMode;
3630
3851
  };
3631
3852
  permissionHandler.reset("Previous CLI process exited before responding");
3853
+ const streamingEnabled = process.env.HAPPY_SESSION_STREAM_DISABLED !== "1";
3854
+ const streamRelay = new StreamRelay({
3855
+ send: (frame) => session.client.sendStreamFrame(frame)
3856
+ });
3632
3857
  const messageQueue = new OutgoingMessageQueue(
3633
3858
  (logMessage) => session.client.sendClaudeSessionMessage(logMessage)
3634
3859
  );
@@ -3887,6 +4112,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
3887
4112
  };
3888
4113
  },
3889
4114
  onThinkingChange: session.onThinkingChange,
4115
+ onStreamFrame: streamingEnabled ? (frame) => streamRelay.ingest(frame) : void 0,
3890
4116
  claudeEnvVars: session.claudeEnvVars,
3891
4117
  claudeArgs: session.claudeArgs,
3892
4118
  onMessage,
@@ -3966,6 +4192,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
3966
4192
  await messageQueue.flush();
3967
4193
  messageQueue.destroy();
3968
4194
  logger.debug("[remote]: message queue flushed");
4195
+ streamRelay.endTurn();
4196
+ streamRelay.dispose();
3969
4197
  abortController = null;
3970
4198
  abortFuture?.resolve(void 0);
3971
4199
  abortFuture = null;
@@ -10368,7 +10596,7 @@ function registerSideQuestionHandler(rpc, deps) {
10368
10596
  const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
10369
10597
  const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
10370
10598
  const run = deps.run ?? (async (input) => {
10371
- const { query } = await import('./index-jYltd-ZW.mjs');
10599
+ const { query } = await import('./index-lQzCAx9I.mjs');
10372
10600
  return runSideQuestion(query, input);
10373
10601
  });
10374
10602
  const slots = /* @__PURE__ */ new Map();
@@ -15298,7 +15526,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15298
15526
  process.exit(0);
15299
15527
  } else if (subcommand === "install-terminal-hooks") {
15300
15528
  try {
15301
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-CJyoR9jp.mjs');
15529
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-CQiW7Jn9.mjs');
15302
15530
  const command = parseTerminalHooksArgs(args.slice(1));
15303
15531
  if (command.action === "help") {
15304
15532
  console.log(TERMINAL_HOOKS_HELP);
@@ -15315,7 +15543,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15315
15543
  }
15316
15544
  } else if (subcommand === "spawn") {
15317
15545
  try {
15318
- const { handleSpawnCommand } = await import('./spawn-DcA80_VN.mjs');
15546
+ const { handleSpawnCommand } = await import('./spawn-D0oTo5BT.mjs');
15319
15547
  await handleSpawnCommand(args.slice(1));
15320
15548
  } catch (error) {
15321
15549
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -15327,7 +15555,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15327
15555
  return;
15328
15556
  } else if (subcommand === "sessions") {
15329
15557
  try {
15330
- const { handleSessionsCommand } = await import('./sessions-DDwCphTQ.mjs');
15558
+ const { handleSessionsCommand } = await import('./sessions-TM8VaCMY.mjs');
15331
15559
  await handleSessionsCommand(args.slice(1));
15332
15560
  } catch (error) {
15333
15561
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -15339,7 +15567,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15339
15567
  return;
15340
15568
  } else if (subcommand === "send") {
15341
15569
  try {
15342
- const { handleSendCommand } = await import('./send-Btz1IZ9U.mjs');
15570
+ const { handleSendCommand } = await import('./send-0TYDXiGx.mjs');
15343
15571
  await handleSendCommand(args.slice(1));
15344
15572
  } catch (error) {
15345
15573
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -15445,9 +15673,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15445
15673
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
15446
15674
  const projectId = args[3];
15447
15675
  try {
15448
- const { saveGoogleCloudProjectToConfig } = await import('./config-CTyyVXHj.mjs');
15449
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-BdO0jg7G.mjs').then(function (n) { return n.ap; });
15450
- const { ApiClient: ApiClient2 } = await import('./types-BdO0jg7G.mjs').then(function (n) { return n.aq; });
15676
+ const { saveGoogleCloudProjectToConfig } = await import('./config-B_L5vXXu.mjs');
15677
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-C5ewhu1Q.mjs').then(function (n) { return n.aq; });
15678
+ const { ApiClient: ApiClient2 } = await import('./types-C5ewhu1Q.mjs').then(function (n) { return n.ar; });
15451
15679
  let userEmail = void 0;
15452
15680
  try {
15453
15681
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -15478,7 +15706,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15478
15706
  }
15479
15707
  if (geminiSubcommand === "project" && args[2] === "get") {
15480
15708
  try {
15481
- const { readGeminiLocalConfig } = await import('./config-CTyyVXHj.mjs');
15709
+ const { readGeminiLocalConfig } = await import('./config-B_L5vXXu.mjs');
15482
15710
  const config = readGeminiLocalConfig();
15483
15711
  if (config.googleCloudProject) {
15484
15712
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -15518,7 +15746,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15518
15746
  process.exit(0);
15519
15747
  }
15520
15748
  try {
15521
- const { runGemini } = await import('./runGemini-CuzqF6Ys.mjs');
15749
+ const { runGemini } = await import('./runGemini-DHyBDo5P.mjs');
15522
15750
  let startedBy = void 0;
15523
15751
  for (let i = 1; i < args.length; i++) {
15524
15752
  if (args[i] === "--started-by") {
@@ -15540,7 +15768,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15540
15768
  return;
15541
15769
  } else if (subcommand === "acp") {
15542
15770
  try {
15543
- const { runAcp, resolveAcpAgentConfig } = await import('./index-Brhvj7p0.mjs');
15771
+ const { runAcp, resolveAcpAgentConfig } = await import('./index-Cu5FdgTq.mjs');
15544
15772
  let startedBy = void 0;
15545
15773
  let verbose = false;
15546
15774
  const acpArgs = [];
@@ -15580,7 +15808,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15580
15808
  return;
15581
15809
  } else if (subcommand === "openclaw") {
15582
15810
  try {
15583
- const { runOpenClaw } = await import('./runOpenClaw-B5pkmSTb.mjs');
15811
+ const { runOpenClaw } = await import('./runOpenClaw-DX-tgQ2V.mjs');
15584
15812
  let startedBy = void 0;
15585
15813
  let verbose = false;
15586
15814
  let gatewayUrl;
@@ -15631,7 +15859,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
15631
15859
  return;
15632
15860
  } else if (subcommand === "mcp" && args.length === 1) {
15633
15861
  try {
15634
- const { handleMcpCommand } = await import('./mcp-BO9-sxMr.mjs');
15862
+ const { handleMcpCommand } = await import('./mcp-DD-0VkiA.mjs');
15635
15863
  await handleMcpCommand();
15636
15864
  } catch (error) {
15637
15865
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -15989,4 +16217,4 @@ ${chalk.bold("Examples:")}
15989
16217
  }
15990
16218
  }
15991
16219
 
15992
- export { BasePermissionHandler as B, CHANGE_TITLE_INSTRUCTION as C, DEFAULT_RECENT_LIMIT as D, GEMINI_MODEL_ENV as G, MAX_READ_LIMIT as M, sessionWebUrl as a, sendUserMessage as b, checkIfDaemonRunningAndCleanupStaleState as c, stopSession as d, archiveSession as e, DEFAULT_GEMINI_MODEL as f, initialMachineMetadata as g, createSessionMetadata as h, isValidSpawnOrigin as i, setupOfflineReconnection as j, MessageQueue2 as k, listSessions as l, hashObject as m, notifyDaemonSessionStarted as n, startHappyServer as o, pushClipboardViaDaemon as p, query as q, readSessionTranscript as r, spawnDaemonSession as s, tmuxSupportsSessionEnv as t, registerKillSessionHandler as u, GEMINI_API_KEY_ENV as v, waitForSessionKey as w, GOOGLE_API_KEY_ENV as x, BaseReasoningProcessor as y, MessageBuffer as z };
16220
+ export { ALLOWED_SPAWN_PERMISSION_MODES as A, BasePermissionHandler as B, MessageBuffer as C, DEFAULT_RECENT_LIMIT as D, CHANGE_TITLE_INSTRUCTION as E, GEMINI_MODEL_ENV as G, MAX_READ_LIMIT as M, sessionWebUrl as a, sanitizeSpawnPermissionMode as b, checkIfDaemonRunningAndCleanupStaleState as c, sendUserMessage as d, stopSession as e, archiveSession as f, DEFAULT_GEMINI_MODEL as g, initialMachineMetadata as h, isValidSpawnOrigin as i, createSessionMetadata as j, setupOfflineReconnection as k, listSessions as l, MessageQueue2 as m, notifyDaemonSessionStarted as n, hashObject as o, pushClipboardViaDaemon as p, query as q, readSessionTranscript as r, spawnDaemonSession as s, tmuxSupportsSessionEnv as t, startHappyServer as u, registerKillSessionHandler as v, waitForSessionKey as w, GEMINI_API_KEY_ENV as x, GOOGLE_API_KEY_ENV as y, BaseReasoningProcessor as z };
@@ -1,9 +1,9 @@
1
- import { q as query } from './index-BW9kDx5m.mjs';
1
+ import { q as query } from './index-inkhalP5.mjs';
2
2
  export { AbortError } from '@anthropic-ai/claude-agent-sdk';
3
3
  import 'chalk';
4
4
  import 'node:os';
5
5
  import 'node:crypto';
6
- import './types-BdO0jg7G.mjs';
6
+ import './types-C5ewhu1Q.mjs';
7
7
  import 'axios';
8
8
  import 'node:util';
9
9
  import 'node:fs';
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-CvnMiYgh.cjs');
5
- require('./types--t4zLibT.cjs');
4
+ require('./index-BnRQP3PL.cjs');
5
+ require('./types-R11tMGyX.cjs');
6
6
  require('zod');
7
7
  require('node:child_process');
8
8
  require('node:os');
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'chalk';
2
- import './index-BW9kDx5m.mjs';
3
- import './types-BdO0jg7G.mjs';
2
+ import './index-inkhalP5.mjs';
3
+ import './types-C5ewhu1Q.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:os';
@@ -5,8 +5,8 @@ var path = require('node:path');
5
5
  var os = require('node:os');
6
6
  var node_child_process = require('node:child_process');
7
7
  var chalk = require('chalk');
8
- var persistence = require('./types--t4zLibT.cjs');
9
- var index = require('./index-CvnMiYgh.cjs');
8
+ var persistence = require('./types-R11tMGyX.cjs');
9
+ var index = require('./index-BnRQP3PL.cjs');
10
10
  require('axios');
11
11
  require('node:util');
12
12
  require('node:fs/promises');
@@ -3,8 +3,8 @@ import { join, resolve } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import chalk from 'chalk';
6
- import { p as projectPath } from './types-BdO0jg7G.mjs';
7
- import { t as tmuxSupportsSessionEnv } from './index-BW9kDx5m.mjs';
6
+ import { p as projectPath } from './types-C5ewhu1Q.mjs';
7
+ import { t as tmuxSupportsSessionEnv } from './index-inkhalP5.mjs';
8
8
  import 'axios';
9
9
  import 'node:util';
10
10
  import 'node:fs/promises';
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var persistence = require('./types--t4zLibT.cjs');
3
+ var persistence = require('./types-R11tMGyX.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('node:util');
package/dist/lib.d.cts CHANGED
@@ -44,6 +44,7 @@ declare const sessionEnvelopeSchema: z.ZodObject<{
44
44
  subagent: z.ZodOptional<z.ZodString>;
45
45
  claudeUuid: z.ZodOptional<z.ZodString>;
46
46
  codexItemId: z.ZodOptional<z.ZodString>;
47
+ streamKey: z.ZodOptional<z.ZodString>;
47
48
  usage: z.ZodOptional<z.ZodObject<{
48
49
  input_tokens: z.ZodNumber;
49
50
  output_tokens: z.ZodNumber;
@@ -139,6 +140,35 @@ declare const sessionEnvelopeSchema: z.ZodObject<{
139
140
  }, z.core.$strip>], "t">;
140
141
  }, z.core.$strip>;
141
142
  type SessionEnvelope = z.infer<typeof sessionEnvelopeSchema>;
143
+ declare const sessionStreamFrameSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
144
+ t: z.ZodLiteral<"block-start">;
145
+ mid: z.ZodString;
146
+ idx: z.ZodNumber;
147
+ kind: z.ZodEnum<{
148
+ text: "text";
149
+ thinking: "thinking";
150
+ }>;
151
+ }, z.core.$strip>, z.ZodObject<{
152
+ t: z.ZodLiteral<"block-delta">;
153
+ mid: z.ZodString;
154
+ idx: z.ZodNumber;
155
+ text: z.ZodString;
156
+ }, z.core.$strip>, z.ZodObject<{
157
+ t: z.ZodLiteral<"block-end">;
158
+ mid: z.ZodString;
159
+ idx: z.ZodNumber;
160
+ }, z.core.$strip>, z.ZodObject<{
161
+ t: z.ZodLiteral<"progress">;
162
+ thinkingTokens: z.ZodOptional<z.ZodNumber>;
163
+ outputTokens: z.ZodOptional<z.ZodNumber>;
164
+ status: z.ZodOptional<z.ZodEnum<{
165
+ requesting: "requesting";
166
+ compacting: "compacting";
167
+ }>>;
168
+ }, z.core.$strip>, z.ZodObject<{
169
+ t: z.ZodLiteral<"turn-end">;
170
+ }, z.core.$strip>], "t">;
171
+ type SessionStreamFrame = z.infer<typeof sessionStreamFrameSchema>;
142
172
 
143
173
  /**
144
174
  * Simplified schema that only validates fields actually used in the codebase
@@ -901,6 +931,20 @@ declare class ApiSessionClient extends EventEmitter {
901
931
  * Send a ping message to keep the connection alive
902
932
  */
903
933
  keepAlive(thinking: boolean, mode: 'local' | 'remote'): void;
934
+ /**
935
+ * B-309: push one live stream frame (thinking/text delta or progress) to
936
+ * this account's web clients.
937
+ *
938
+ * Encrypted with the SESSION key and relayed without being stored —
939
+ * clipboard-push's shape, for clipboard-push's reasons: the relay must not
940
+ * be able to read thinking text, and the session id is stamped by the
941
+ * server from the authenticated connection rather than trusted from here.
942
+ *
943
+ * `volatile` on purpose. A draft that misses the wire while disconnected
944
+ * is worth nothing — the persisted message is still coming, and replaying
945
+ * stale deltas after a reconnect would paint text that has already landed.
946
+ */
947
+ sendStreamFrame(frame: SessionStreamFrame): void;
904
948
  /**
905
949
  * Send session death message
906
950
  */
package/dist/lib.d.mts CHANGED
@@ -44,6 +44,7 @@ declare const sessionEnvelopeSchema: z.ZodObject<{
44
44
  subagent: z.ZodOptional<z.ZodString>;
45
45
  claudeUuid: z.ZodOptional<z.ZodString>;
46
46
  codexItemId: z.ZodOptional<z.ZodString>;
47
+ streamKey: z.ZodOptional<z.ZodString>;
47
48
  usage: z.ZodOptional<z.ZodObject<{
48
49
  input_tokens: z.ZodNumber;
49
50
  output_tokens: z.ZodNumber;
@@ -139,6 +140,35 @@ declare const sessionEnvelopeSchema: z.ZodObject<{
139
140
  }, z.core.$strip>], "t">;
140
141
  }, z.core.$strip>;
141
142
  type SessionEnvelope = z.infer<typeof sessionEnvelopeSchema>;
143
+ declare const sessionStreamFrameSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
144
+ t: z.ZodLiteral<"block-start">;
145
+ mid: z.ZodString;
146
+ idx: z.ZodNumber;
147
+ kind: z.ZodEnum<{
148
+ text: "text";
149
+ thinking: "thinking";
150
+ }>;
151
+ }, z.core.$strip>, z.ZodObject<{
152
+ t: z.ZodLiteral<"block-delta">;
153
+ mid: z.ZodString;
154
+ idx: z.ZodNumber;
155
+ text: z.ZodString;
156
+ }, z.core.$strip>, z.ZodObject<{
157
+ t: z.ZodLiteral<"block-end">;
158
+ mid: z.ZodString;
159
+ idx: z.ZodNumber;
160
+ }, z.core.$strip>, z.ZodObject<{
161
+ t: z.ZodLiteral<"progress">;
162
+ thinkingTokens: z.ZodOptional<z.ZodNumber>;
163
+ outputTokens: z.ZodOptional<z.ZodNumber>;
164
+ status: z.ZodOptional<z.ZodEnum<{
165
+ requesting: "requesting";
166
+ compacting: "compacting";
167
+ }>>;
168
+ }, z.core.$strip>, z.ZodObject<{
169
+ t: z.ZodLiteral<"turn-end">;
170
+ }, z.core.$strip>], "t">;
171
+ type SessionStreamFrame = z.infer<typeof sessionStreamFrameSchema>;
142
172
 
143
173
  /**
144
174
  * Simplified schema that only validates fields actually used in the codebase
@@ -901,6 +931,20 @@ declare class ApiSessionClient extends EventEmitter {
901
931
  * Send a ping message to keep the connection alive
902
932
  */
903
933
  keepAlive(thinking: boolean, mode: 'local' | 'remote'): void;
934
+ /**
935
+ * B-309: push one live stream frame (thinking/text delta or progress) to
936
+ * this account's web clients.
937
+ *
938
+ * Encrypted with the SESSION key and relayed without being stored —
939
+ * clipboard-push's shape, for clipboard-push's reasons: the relay must not
940
+ * be able to read thinking text, and the session id is stamped by the
941
+ * server from the authenticated connection rather than trusted from here.
942
+ *
943
+ * `volatile` on purpose. A draft that misses the wire while disconnected
944
+ * is worth nothing — the persisted message is still coming, and replaying
945
+ * stale deltas after a reconnect would paint text that has already landed.
946
+ */
947
+ sendStreamFrame(frame: SessionStreamFrame): void;
904
948
  /**
905
949
  * Send session death message
906
950
  */
package/dist/lib.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BdO0jg7G.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-C5ewhu1Q.mjs';
2
2
  import 'axios';
3
3
  import 'chalk';
4
4
  import 'node:util';
@@ -3,9 +3,9 @@
3
3
  var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
4
4
  var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
5
5
  var z = require('zod');
6
- var index = require('./index-CvnMiYgh.cjs');
6
+ var index = require('./index-BnRQP3PL.cjs');
7
7
  var limits = require('./limits-KdWKmwtH.cjs');
8
- var persistence = require('./types--t4zLibT.cjs');
8
+ var persistence = require('./types-R11tMGyX.cjs');
9
9
  require('chalk');
10
10
  require('node:os');
11
11
  require('node:crypto');
@@ -1,9 +1,9 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { z } from 'zod';
4
- import { p as pushClipboardViaDaemon } from './index-BW9kDx5m.mjs';
4
+ import { p as pushClipboardViaDaemon } from './index-inkhalP5.mjs';
5
5
  import { C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, c as CLIPBOARD_MAX_BYTES } from './limits-CwFb5S2b.mjs';
6
- import { l as logger } from './types-BdO0jg7G.mjs';
6
+ import { l as logger } from './types-C5ewhu1Q.mjs';
7
7
  import 'chalk';
8
8
  import 'node:os';
9
9
  import 'node:crypto';
@@ -2,10 +2,10 @@ import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { randomUUID } from 'node:crypto';
4
4
  import { join } from 'node:path';
5
- import { l as logger, h as connectionState, A as ApiClient, j as readSettings, e as errorLogMetadata, k as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-BdO0jg7G.mjs';
6
- import { v as GEMINI_API_KEY_ENV, x as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, y as BaseReasoningProcessor, g as initialMachineMetadata, h as createSessionMetadata, j as setupOfflineReconnection, n as notifyDaemonSessionStarted, k as MessageQueue2, m as hashObject, z as MessageBuffer, C as CHANGE_TITLE_INSTRUCTION, u as registerKillSessionHandler, o as startHappyServer } from './index-BW9kDx5m.mjs';
7
- import { A as AcpBackend } from './AcpBackend-DzZR7TEv.mjs';
8
- import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-CTyyVXHj.mjs';
5
+ import { l as logger, h as connectionState, A as ApiClient, j as readSettings, e as errorLogMetadata, k as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-C5ewhu1Q.mjs';
6
+ import { x as GEMINI_API_KEY_ENV, y as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, z as BaseReasoningProcessor, h as initialMachineMetadata, j as createSessionMetadata, k as setupOfflineReconnection, n as notifyDaemonSessionStarted, m as MessageQueue2, o as hashObject, C as MessageBuffer, E as CHANGE_TITLE_INSTRUCTION, v as registerKillSessionHandler, u as startHappyServer } from './index-inkhalP5.mjs';
7
+ import { A as AcpBackend } from './AcpBackend-DDEdYVW2.mjs';
8
+ import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-B_L5vXXu.mjs';
9
9
  import 'axios';
10
10
  import 'chalk';
11
11
  import 'node:util';