very-happy-cli 0.2.81 → 0.2.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/{AcpBackend-cBt4R6ce.mjs → AcpBackend-DbS9-r10.mjs} +1 -1
  2. package/dist/{AcpBackend-B7Z1Gk_l.cjs → AcpBackend-sS5ln9nS.cjs} +1 -1
  3. package/dist/{AcpSessionManager-D3-rBUxk.cjs → AcpSessionManager-DX5IvruC.cjs} +1 -1
  4. package/dist/{AcpSessionManager-AyrINTu7.mjs → AcpSessionManager-DuZN34yy.mjs} +1 -1
  5. package/dist/{config-CZdNxl3d.mjs → config-3BOBElkv.mjs} +2 -2
  6. package/dist/{config-B2TBK1UZ.cjs → config-BkxNWcwM.cjs} +2 -2
  7. package/dist/{index-DuvoxKEM.mjs → index-08H6z21h.mjs} +5 -5
  8. package/dist/{index-W3oj-d6C.mjs → index-BDhR8Zbc.mjs} +105 -47
  9. package/dist/{index-SjWW0gIt.cjs → index-BVlYjP10.cjs} +108 -50
  10. package/dist/{index-C9UnJZEo.cjs → index-fFNtiTSl.cjs} +4 -4
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/{installTerminalHooks-BqpxXB8n.mjs → installTerminalHooks-C0X114sp.mjs} +2 -2
  14. package/dist/{installTerminalHooks-Xtl0pMWH.cjs → installTerminalHooks-DC2wMq-X.cjs} +2 -2
  15. package/dist/lib.cjs +1 -1
  16. package/dist/lib.d.cts +4 -0
  17. package/dist/lib.d.mts +4 -0
  18. package/dist/lib.mjs +1 -1
  19. package/dist/{mcp-DqaW6nz5.mjs → mcp-B9UtB3lP.mjs} +2 -2
  20. package/dist/{mcp-BxO80DMH.cjs → mcp-CuDdOqST.cjs} +2 -2
  21. package/dist/{runGemini-DZay2CN7.cjs → runGemini-Cqstl6qb.cjs} +4 -4
  22. package/dist/{runGemini-Ctc5nKHC.mjs → runGemini-Cvww7ebI.mjs} +4 -4
  23. package/dist/{runOpenClaw-CF0133Vk.mjs → runOpenClaw-BXmi-UcV.mjs} +3 -3
  24. package/dist/{runOpenClaw-W3Ogud1U.cjs → runOpenClaw-CHu488uC.cjs} +3 -3
  25. package/dist/{send-D0U0T_bK.cjs → send-C5dWPbV6.cjs} +2 -2
  26. package/dist/{send-By1xNQ6E.mjs → send-C6Uqkmxr.mjs} +2 -2
  27. package/dist/{spawn-BnvqaVCf.cjs → spawn-CZAHiPE6.cjs} +2 -2
  28. package/dist/{spawn-BLbFNopc.mjs → spawn-D8K3uJEp.mjs} +2 -2
  29. package/dist/{types-DFKdwxE-.mjs → types-RASD9X96.mjs} +13 -12
  30. package/dist/{types-DJC5rGtd.cjs → types-sFcb_Sfz.cjs} +14 -13
  31. package/package.json +7 -7
@@ -1,7 +1,7 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { l as logger, d as contentLogMetadata, e as errorLogMetadata, f as packageJson, g as delay } from './types-DFKdwxE-.mjs';
4
+ import { l as logger, d as contentLogMetadata, e as errorLogMetadata, f as packageJson, g as delay } from './types-RASD9X96.mjs';
5
5
 
6
6
  const DEFAULT_TIMEOUTS = {
7
7
  /** Default initialization timeout: 60 seconds */
@@ -3,7 +3,7 @@
3
3
  var node_child_process = require('node:child_process');
4
4
  var sdk = require('@agentclientprotocol/sdk');
5
5
  var node_crypto = require('node:crypto');
6
- var persistence = require('./types-DJC5rGtd.cjs');
6
+ var persistence = require('./types-sFcb_Sfz.cjs');
7
7
 
8
8
  const DEFAULT_TIMEOUTS = {
9
9
  /** Default initialization timeout: 60 seconds */
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var cuid2 = require('@paralleldrive/cuid2');
4
- var persistence = require('./types-DJC5rGtd.cjs');
4
+ var persistence = require('./types-sFcb_Sfz.cjs');
5
5
 
6
6
  function turnOptions(turnId, time) {
7
7
  return turnId ? { turn: turnId, time } : { time };
@@ -1,5 +1,5 @@
1
1
  import { createId } from '@paralleldrive/cuid2';
2
- import { b as createEnvelope } from './types-DFKdwxE-.mjs';
2
+ import { b as createEnvelope } from './types-RASD9X96.mjs';
3
3
 
4
4
  function turnOptions(turnId, time) {
5
5
  return turnId ? { turn: turnId, time } : { time };
@@ -2,8 +2,8 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { homedir } from 'os';
4
4
  import { execSync } from 'child_process';
5
- import { l as logger } from './types-DFKdwxE-.mjs';
6
- import { D as DEFAULT_GEMINI_MODEL, G as GEMINI_MODEL_ENV } from './index-W3oj-d6C.mjs';
5
+ import { l as logger } from './types-RASD9X96.mjs';
6
+ import { D as DEFAULT_GEMINI_MODEL, G as GEMINI_MODEL_ENV } from './index-BDhR8Zbc.mjs';
7
7
  import 'axios';
8
8
  import 'chalk';
9
9
  import 'node:util';
@@ -4,8 +4,8 @@ var fs = require('fs');
4
4
  var path = require('path');
5
5
  var os = require('os');
6
6
  var child_process = require('child_process');
7
- var persistence = require('./types-DJC5rGtd.cjs');
8
- var index = require('./index-SjWW0gIt.cjs');
7
+ var persistence = require('./types-sFcb_Sfz.cjs');
8
+ var index = require('./index-BVlYjP10.cjs');
9
9
  require('axios');
10
10
  require('chalk');
11
11
  require('node:util');
@@ -1,10 +1,10 @@
1
- import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-cBt4R6ce.mjs';
2
- export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-cBt4R6ce.mjs';
3
- import { h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, p as projectPath } from './types-DFKdwxE-.mjs';
4
- import { A as AcpSessionManager } from './AcpSessionManager-AyrINTu7.mjs';
1
+ import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-DbS9-r10.mjs';
2
+ export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-DbS9-r10.mjs';
3
+ import { h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, p as projectPath } from './types-RASD9X96.mjs';
4
+ import { A as AcpSessionManager } from './AcpSessionManager-DuZN34yy.mjs';
5
5
  import { randomUUID } from 'node:crypto';
6
6
  import { join } from 'node:path';
7
- import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, f as startHappyServer, r as registerKillSessionHandler, B as BasePermissionHandler } from './index-W3oj-d6C.mjs';
7
+ import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, f as startHappyServer, r as registerKillSessionHandler, B as BasePermissionHandler } from './index-BDhR8Zbc.mjs';
8
8
  import 'node:child_process';
9
9
  import '@agentclientprotocol/sdk';
10
10
  import 'axios';
@@ -1,7 +1,7 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
2
  import os, { homedir } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
4
- import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, f as packageJson, i as readSettings, v as readCredentials, x as credentialRelayProblem, y as deriveLocalCliUpdateSummary, j as encodeBase64, z as updateSettings, B as encodeBase64Url, C as decodeBase64, D as writeCredentialsLegacy, E as writeCredentialsDataKey, F as readCredentialsForConfiguredRelay, G as encrypt, r as readPersistedSessions, H as getLocalHappyAgentCredentialPath, J as readLocalHappyAgentCredentials, K as decryptWithDataKey, L as decryptLegacy, M as extractCompleteLines, N as decideBackfill, O as parseTerminalHookPayload, P as decideMirrorBinding, Q as persistSession, S as MIRROR_BACKFILL_LINES_DEFAULT, T as mirrorLineKey, U as mirrorLocalId, V as detectResumeSupport, W as detectCLIAvailability, X as acquireDaemonLock, Y as summarizeSpawnSessionForLog, Z as deletePersistedSessions, _ as decrypt, $ as writeDaemonState, A as ApiClient, a0 as fetchCliUpdateState, a1 as resolveCliUpdateCheckInterval, a2 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a3 as releaseDaemonLock, a4 as isValidSessionId, a5 as listVhTerminals, a6 as isValidTerminalId, a7 as readVhTerminal, a8 as sendToVhTerminal, h as connectionState, a9 as startOfflineReconnection, aa as clearCredentials, ab as clearMachineId, k as ensurePrivateDirectorySync, w as writePrivateFileSync, ac as SandboxConfigSchema, b as createEnvelope, ad as CodexAppServerClient, ae as getLatestDaemonLog } from './types-DFKdwxE-.mjs';
4
+ import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, f as packageJson, i as readSettings, v as readCredentials, x as credentialRelayProblem, y as deriveLocalCliUpdateSummary, j as encodeBase64, z as updateSettings, B as encodeBase64Url, C as decodeBase64, D as writeCredentialsLegacy, E as writeCredentialsDataKey, F as readCredentialsForConfiguredRelay, G as encrypt, r as readPersistedSessions, H as getLocalHappyAgentCredentialPath, J as readLocalHappyAgentCredentials, K as decryptWithDataKey, L as decryptLegacy, M as extractCompleteLines, N as decideBackfill, O as parseTerminalHookPayload, P as decideMirrorBinding, Q as persistSession, S as MIRROR_BACKFILL_LINES_DEFAULT, T as mirrorLineKey, U as mirrorLocalId, V as detectResumeSupport, W as detectCLIAvailability, X as acquireDaemonLock, Y as summarizeSpawnSessionForLog, Z as deletePersistedSessions, _ as decrypt, $ as writeDaemonState, A as ApiClient, a0 as fetchCliUpdateState, a1 as resolveCliUpdateCheckInterval, a2 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a3 as releaseDaemonLock, a4 as isValidSessionId, a5 as listVhTerminals, a6 as isValidTerminalId, a7 as readVhTerminal, a8 as sendToVhTerminal, h as connectionState, a9 as startOfflineReconnection, aa as clearCredentials, ab as clearMachineId, k as ensurePrivateDirectorySync, w as writePrivateFileSync, ac as SandboxConfigSchema, b as createEnvelope, ad as CodexAppServerClient, ae as getLatestDaemonLog } from './types-RASD9X96.mjs';
5
5
  import spawn$1, { spawn } from 'cross-spawn';
6
6
  import path, { join, resolve, isAbsolute, normalize, sep, dirname } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
@@ -2982,6 +2982,49 @@ function applyClaudeResultLifecycle(result, callbacks) {
2982
2982
  callbacks.onCompleted();
2983
2983
  }
2984
2984
 
2985
+ const CLAUDE_ATTACHMENT_KINDS = [
2986
+ "image/jpeg",
2987
+ "image/png",
2988
+ "image/gif",
2989
+ "image/webp",
2990
+ "application/pdf"
2991
+ ];
2992
+ function detectClaudeImageMime(bytes) {
2993
+ if (bytes.length >= 4 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
2994
+ return "image/png";
2995
+ }
2996
+ if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
2997
+ return "image/jpeg";
2998
+ }
2999
+ if (bytes.length >= 4 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 56) {
3000
+ return "image/gif";
3001
+ }
3002
+ if (bytes.length >= 12 && bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
3003
+ return "image/webp";
3004
+ }
3005
+ return null;
3006
+ }
3007
+ function isPdf(bytes) {
3008
+ return bytes.length >= 5 && bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70 && bytes[4] === 45;
3009
+ }
3010
+ function attachmentToClaudeContentBlock(bytes) {
3011
+ const data = Buffer.from(bytes).toString("base64");
3012
+ const imageMime = detectClaudeImageMime(bytes);
3013
+ if (imageMime) {
3014
+ return {
3015
+ type: "image",
3016
+ source: { type: "base64", media_type: imageMime, data }
3017
+ };
3018
+ }
3019
+ if (isPdf(bytes)) {
3020
+ return {
3021
+ type: "document",
3022
+ source: { type: "base64", media_type: "application/pdf", data }
3023
+ };
3024
+ }
3025
+ return null;
3026
+ }
3027
+
2985
3028
  function applyClaudeSdkMetadata(current, update) {
2986
3029
  return {
2987
3030
  ...current,
@@ -2989,6 +3032,8 @@ function applyClaudeSdkMetadata(current, update) {
2989
3032
  slashCommands: update.slashCommands,
2990
3033
  mcpServers: update.mcpServers,
2991
3034
  skills: update.skills,
3035
+ attachmentKinds: [...CLAUDE_ATTACHMENT_KINDS],
3036
+ queueCancellation: true,
2992
3037
  ...update.modelIsDefault && update.model ? { defaultModelCode: update.model } : {}
2993
3038
  };
2994
3039
  }
@@ -3264,23 +3309,23 @@ async function claudeRemoteLauncher(session) {
3264
3309
  const attachments = msg.attachments ?? [];
3265
3310
  if (attachments.length > 0) {
3266
3311
  const contentBlocks = [];
3312
+ let acceptedAttachments = 0;
3267
3313
  for (const att of attachments) {
3268
- const detected = detectClaudeImageMime(att.data);
3269
- if (!detected) {
3314
+ const block = attachmentToClaudeContentBlock(att.data);
3315
+ if (!block) {
3270
3316
  logger.debug(`[remote] Skipping unsupported attachment (no magic-byte match): ${att.name}, claimed mimeType=${att.mimeType}`);
3271
3317
  continue;
3272
3318
  }
3273
- contentBlocks.push({
3274
- type: "image",
3275
- source: {
3276
- type: "base64",
3277
- media_type: detected,
3278
- data: Buffer.from(att.data).toString("base64")
3279
- }
3280
- });
3319
+ contentBlocks.push(block);
3320
+ acceptedAttachments++;
3321
+ }
3322
+ if (msg.message.trim().length > 0) {
3323
+ contentBlocks.push({ type: "text", text: msg.message });
3324
+ }
3325
+ if (contentBlocks.length === 0) {
3326
+ throw new Error("No supported attachment content was available to send");
3281
3327
  }
3282
- contentBlocks.push({ type: "text", text: msg.message });
3283
- logger.debug(`[remote] Combined ${contentBlocks.length - 1} image(s) with text message`);
3328
+ logger.debug(`[remote] Combined ${acceptedAttachments} attachment(s) with${msg.message.trim() ? "" : "out"} text message`);
3284
3329
  return {
3285
3330
  message: contentBlocks,
3286
3331
  mode: msg.mode
@@ -3412,21 +3457,6 @@ async function claudeRemoteLauncher(session) {
3412
3457
  }
3413
3458
  return exitReason || "exit";
3414
3459
  }
3415
- function detectClaudeImageMime(bytes) {
3416
- if (bytes.length >= 4 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
3417
- return "image/png";
3418
- }
3419
- if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
3420
- return "image/jpeg";
3421
- }
3422
- if (bytes.length >= 4 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 56) {
3423
- return "image/gif";
3424
- }
3425
- if (bytes.length >= 12 && bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
3426
- return "image/webp";
3427
- }
3428
- return null;
3429
- }
3430
3460
 
3431
3461
  async function loop(opts) {
3432
3462
  const logPath = logger.logFilePath;
@@ -3502,7 +3532,7 @@ class MessageQueue2 {
3502
3532
  * Push a message to the queue with a mode and an optional list of
3503
3533
  * attachments that travel with this message.
3504
3534
  */
3505
- push(message, mode, attachments) {
3535
+ push(message, mode, attachments, sourceId) {
3506
3536
  if (this.closed) {
3507
3537
  throw new Error("Cannot push to closed queue");
3508
3538
  }
@@ -3513,7 +3543,8 @@ class MessageQueue2 {
3513
3543
  mode,
3514
3544
  modeHash,
3515
3545
  isolate: false,
3516
- attachments
3546
+ attachments,
3547
+ sourceId
3517
3548
  });
3518
3549
  if (this.onMessageHandler) {
3519
3550
  this.onMessageHandler(message, mode);
@@ -3558,7 +3589,7 @@ class MessageQueue2 {
3558
3589
  * Clears any pending messages and ensures this message is never batched with others.
3559
3590
  * Used for special commands that require dedicated processing.
3560
3591
  */
3561
- pushIsolateAndClear(message, mode, attachments) {
3592
+ pushIsolateAndClear(message, mode, attachments, sourceId) {
3562
3593
  if (this.closed) {
3563
3594
  throw new Error("Cannot push to closed queue");
3564
3595
  }
@@ -3570,7 +3601,8 @@ class MessageQueue2 {
3570
3601
  mode,
3571
3602
  modeHash,
3572
3603
  isolate: true,
3573
- attachments
3604
+ attachments,
3605
+ sourceId
3574
3606
  });
3575
3607
  if (this.onMessageHandler) {
3576
3608
  this.onMessageHandler(message, mode);
@@ -3642,6 +3674,21 @@ class MessageQueue2 {
3642
3674
  size() {
3643
3675
  return this.queue.length;
3644
3676
  }
3677
+ /**
3678
+ * Remove one message that has not yet been collected by the agent loop.
3679
+ * Source id is authoritative. Exact-text fallback only covers items that
3680
+ * entered this live process before transport ids were introduced.
3681
+ */
3682
+ cancelPending(sourceId, exactText) {
3683
+ let index = sourceId ? this.queue.findIndex((item) => item.sourceId === sourceId) : -1;
3684
+ if (index < 0 && exactText !== void 0) {
3685
+ index = this.queue.findIndex((item) => item.sourceId === void 0 && item.message === exactText);
3686
+ }
3687
+ if (index < 0) return false;
3688
+ this.queue.splice(index, 1);
3689
+ logger.debug(`[MessageQueue2] Cancelled pending item. Queue size: ${this.queue.length}`);
3690
+ return true;
3691
+ }
3645
3692
  /**
3646
3693
  * Wait for messages and return all messages with the same mode as a single string
3647
3694
  * Returns { message: string, mode: T } or null if aborted/closed
@@ -8934,6 +8981,10 @@ async function runClaude(credentials, options = {}) {
8934
8981
  lifecycleState: "running",
8935
8982
  lifecycleStateSince: Date.now(),
8936
8983
  flavor: "claude",
8984
+ // Advertise composer support before the first SDK response. Otherwise
8985
+ // a brand-new session cannot pick a PDF until after sending once.
8986
+ attachmentKinds: [...CLAUDE_ATTACHMENT_KINDS],
8987
+ queueCancellation: true,
8937
8988
  sandbox: sandboxConfig?.enabled ? sandboxConfig : null,
8938
8989
  dangerouslySkipPermissions,
8939
8990
  ...forkedFromSessionId ? { parentSessionId: forkedFromSessionId } : {},
@@ -9037,7 +9088,8 @@ async function runClaude(credentials, options = {}) {
9037
9088
  session.updateMetadata((meta) => ({
9038
9089
  ...meta,
9039
9090
  lifecycleState: "running",
9040
- archivedBy: void 0
9091
+ archivedBy: void 0,
9092
+ queueCancellation: true
9041
9093
  }));
9042
9094
  }
9043
9095
  const forkClaudeSessionId = process.env.HAPPY_FORK_CLAUDE_SESSION_ID;
@@ -9162,6 +9214,12 @@ async function runClaude(credentials, options = {}) {
9162
9214
  disallowedTools: mode.disallowedTools,
9163
9215
  effort: mode.effort
9164
9216
  }));
9217
+ session.rpcHandlerManager.registerHandler("cancelQueuedMessage", async (params) => ({
9218
+ removed: messageQueue.cancelPending(
9219
+ typeof params?.localKey === "string" ? params.localKey : void 0,
9220
+ typeof params?.text === "string" ? params.text : void 0
9221
+ )
9222
+ }));
9165
9223
  let currentPermissionMode = initialPermissionMode;
9166
9224
  let currentModel = options.model ?? DEFAULT_CLAUDE_MODEL;
9167
9225
  let currentFallbackModel = void 0;
@@ -9304,7 +9362,7 @@ async function runClaude(credentials, options = {}) {
9304
9362
  disallowedTools: messageDisallowedTools,
9305
9363
  effort: messageEffort
9306
9364
  };
9307
- messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage);
9365
+ messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
9308
9366
  logger.debug("[start] /compact command pushed to queue:", {
9309
9367
  ...contentLogMetadata(message.content.text),
9310
9368
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
@@ -9324,7 +9382,7 @@ async function runClaude(credentials, options = {}) {
9324
9382
  disallowedTools: messageDisallowedTools,
9325
9383
  effort: messageEffort
9326
9384
  };
9327
- messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage);
9385
+ messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
9328
9386
  logger.debug("[start] /clear command pushed to queue:", {
9329
9387
  ...contentLogMetadata(message.content.text),
9330
9388
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
@@ -9380,7 +9438,7 @@ async function runClaude(credentials, options = {}) {
9380
9438
  disallowedTools: messageDisallowedTools,
9381
9439
  effort: messageEffort
9382
9440
  };
9383
- messageQueue.push(message.content.text, enhancedMode, attachmentsForThisMessage);
9441
+ messageQueue.push(message.content.text, enhancedMode, attachmentsForThisMessage, message.localKey);
9384
9442
  logger.debug("User message pushed to queue:", {
9385
9443
  ...contentLogMetadata(message.content.text),
9386
9444
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
@@ -13212,7 +13270,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13212
13270
  process.exit(0);
13213
13271
  } else if (subcommand === "install-terminal-hooks") {
13214
13272
  try {
13215
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-BqpxXB8n.mjs');
13273
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-C0X114sp.mjs');
13216
13274
  const command = parseTerminalHooksArgs(args.slice(1));
13217
13275
  if (command.action === "help") {
13218
13276
  console.log(TERMINAL_HOOKS_HELP);
@@ -13229,7 +13287,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13229
13287
  }
13230
13288
  } else if (subcommand === "spawn") {
13231
13289
  try {
13232
- const { handleSpawnCommand } = await import('./spawn-BLbFNopc.mjs');
13290
+ const { handleSpawnCommand } = await import('./spawn-D8K3uJEp.mjs');
13233
13291
  await handleSpawnCommand(args.slice(1));
13234
13292
  } catch (error) {
13235
13293
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13241,7 +13299,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13241
13299
  return;
13242
13300
  } else if (subcommand === "send") {
13243
13301
  try {
13244
- const { handleSendCommand } = await import('./send-By1xNQ6E.mjs');
13302
+ const { handleSendCommand } = await import('./send-C6Uqkmxr.mjs');
13245
13303
  await handleSendCommand(args.slice(1));
13246
13304
  } catch (error) {
13247
13305
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13347,9 +13405,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13347
13405
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
13348
13406
  const projectId = args[3];
13349
13407
  try {
13350
- const { saveGoogleCloudProjectToConfig } = await import('./config-CZdNxl3d.mjs');
13351
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-DFKdwxE-.mjs').then(function (n) { return n.af; });
13352
- const { ApiClient: ApiClient2 } = await import('./types-DFKdwxE-.mjs').then(function (n) { return n.ag; });
13408
+ const { saveGoogleCloudProjectToConfig } = await import('./config-3BOBElkv.mjs');
13409
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-RASD9X96.mjs').then(function (n) { return n.af; });
13410
+ const { ApiClient: ApiClient2 } = await import('./types-RASD9X96.mjs').then(function (n) { return n.ag; });
13353
13411
  let userEmail = void 0;
13354
13412
  try {
13355
13413
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -13380,7 +13438,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13380
13438
  }
13381
13439
  if (geminiSubcommand === "project" && args[2] === "get") {
13382
13440
  try {
13383
- const { readGeminiLocalConfig } = await import('./config-CZdNxl3d.mjs');
13441
+ const { readGeminiLocalConfig } = await import('./config-3BOBElkv.mjs');
13384
13442
  const config = readGeminiLocalConfig();
13385
13443
  if (config.googleCloudProject) {
13386
13444
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -13420,7 +13478,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13420
13478
  process.exit(0);
13421
13479
  }
13422
13480
  try {
13423
- const { runGemini } = await import('./runGemini-Ctc5nKHC.mjs');
13481
+ const { runGemini } = await import('./runGemini-Cvww7ebI.mjs');
13424
13482
  let startedBy = void 0;
13425
13483
  for (let i = 1; i < args.length; i++) {
13426
13484
  if (args[i] === "--started-by") {
@@ -13442,7 +13500,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13442
13500
  return;
13443
13501
  } else if (subcommand === "acp") {
13444
13502
  try {
13445
- const { runAcp, resolveAcpAgentConfig } = await import('./index-DuvoxKEM.mjs');
13503
+ const { runAcp, resolveAcpAgentConfig } = await import('./index-08H6z21h.mjs');
13446
13504
  let startedBy = void 0;
13447
13505
  let verbose = false;
13448
13506
  const acpArgs = [];
@@ -13482,7 +13540,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13482
13540
  return;
13483
13541
  } else if (subcommand === "openclaw") {
13484
13542
  try {
13485
- const { runOpenClaw } = await import('./runOpenClaw-CF0133Vk.mjs');
13543
+ const { runOpenClaw } = await import('./runOpenClaw-BXmi-UcV.mjs');
13486
13544
  let startedBy = void 0;
13487
13545
  let verbose = false;
13488
13546
  let gatewayUrl;
@@ -13533,7 +13591,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13533
13591
  return;
13534
13592
  } else if (subcommand === "mcp" && args.length === 1) {
13535
13593
  try {
13536
- const { handleMcpCommand } = await import('./mcp-DqaW6nz5.mjs');
13594
+ const { handleMcpCommand } = await import('./mcp-B9UtB3lP.mjs');
13537
13595
  await handleMcpCommand();
13538
13596
  } catch (error) {
13539
13597
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -3,7 +3,7 @@
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
5
  var node_crypto = require('node:crypto');
6
- var persistence = require('./types-DJC5rGtd.cjs');
6
+ var persistence = require('./types-sFcb_Sfz.cjs');
7
7
  var spawn = require('cross-spawn');
8
8
  var path = require('node:path');
9
9
  var node_readline = require('node:readline');
@@ -3004,6 +3004,49 @@ function applyClaudeResultLifecycle(result, callbacks) {
3004
3004
  callbacks.onCompleted();
3005
3005
  }
3006
3006
 
3007
+ const CLAUDE_ATTACHMENT_KINDS = [
3008
+ "image/jpeg",
3009
+ "image/png",
3010
+ "image/gif",
3011
+ "image/webp",
3012
+ "application/pdf"
3013
+ ];
3014
+ function detectClaudeImageMime(bytes) {
3015
+ if (bytes.length >= 4 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
3016
+ return "image/png";
3017
+ }
3018
+ if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
3019
+ return "image/jpeg";
3020
+ }
3021
+ if (bytes.length >= 4 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 56) {
3022
+ return "image/gif";
3023
+ }
3024
+ if (bytes.length >= 12 && bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
3025
+ return "image/webp";
3026
+ }
3027
+ return null;
3028
+ }
3029
+ function isPdf(bytes) {
3030
+ return bytes.length >= 5 && bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70 && bytes[4] === 45;
3031
+ }
3032
+ function attachmentToClaudeContentBlock(bytes) {
3033
+ const data = Buffer.from(bytes).toString("base64");
3034
+ const imageMime = detectClaudeImageMime(bytes);
3035
+ if (imageMime) {
3036
+ return {
3037
+ type: "image",
3038
+ source: { type: "base64", media_type: imageMime, data }
3039
+ };
3040
+ }
3041
+ if (isPdf(bytes)) {
3042
+ return {
3043
+ type: "document",
3044
+ source: { type: "base64", media_type: "application/pdf", data }
3045
+ };
3046
+ }
3047
+ return null;
3048
+ }
3049
+
3007
3050
  function applyClaudeSdkMetadata(current, update) {
3008
3051
  return {
3009
3052
  ...current,
@@ -3011,6 +3054,8 @@ function applyClaudeSdkMetadata(current, update) {
3011
3054
  slashCommands: update.slashCommands,
3012
3055
  mcpServers: update.mcpServers,
3013
3056
  skills: update.skills,
3057
+ attachmentKinds: [...CLAUDE_ATTACHMENT_KINDS],
3058
+ queueCancellation: true,
3014
3059
  ...update.modelIsDefault && update.model ? { defaultModelCode: update.model } : {}
3015
3060
  };
3016
3061
  }
@@ -3286,23 +3331,23 @@ async function claudeRemoteLauncher(session) {
3286
3331
  const attachments = msg.attachments ?? [];
3287
3332
  if (attachments.length > 0) {
3288
3333
  const contentBlocks = [];
3334
+ let acceptedAttachments = 0;
3289
3335
  for (const att of attachments) {
3290
- const detected = detectClaudeImageMime(att.data);
3291
- if (!detected) {
3336
+ const block = attachmentToClaudeContentBlock(att.data);
3337
+ if (!block) {
3292
3338
  persistence.logger.debug(`[remote] Skipping unsupported attachment (no magic-byte match): ${att.name}, claimed mimeType=${att.mimeType}`);
3293
3339
  continue;
3294
3340
  }
3295
- contentBlocks.push({
3296
- type: "image",
3297
- source: {
3298
- type: "base64",
3299
- media_type: detected,
3300
- data: Buffer.from(att.data).toString("base64")
3301
- }
3302
- });
3341
+ contentBlocks.push(block);
3342
+ acceptedAttachments++;
3343
+ }
3344
+ if (msg.message.trim().length > 0) {
3345
+ contentBlocks.push({ type: "text", text: msg.message });
3346
+ }
3347
+ if (contentBlocks.length === 0) {
3348
+ throw new Error("No supported attachment content was available to send");
3303
3349
  }
3304
- contentBlocks.push({ type: "text", text: msg.message });
3305
- persistence.logger.debug(`[remote] Combined ${contentBlocks.length - 1} image(s) with text message`);
3350
+ persistence.logger.debug(`[remote] Combined ${acceptedAttachments} attachment(s) with${msg.message.trim() ? "" : "out"} text message`);
3306
3351
  return {
3307
3352
  message: contentBlocks,
3308
3353
  mode: msg.mode
@@ -3434,21 +3479,6 @@ async function claudeRemoteLauncher(session) {
3434
3479
  }
3435
3480
  return exitReason || "exit";
3436
3481
  }
3437
- function detectClaudeImageMime(bytes) {
3438
- if (bytes.length >= 4 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
3439
- return "image/png";
3440
- }
3441
- if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
3442
- return "image/jpeg";
3443
- }
3444
- if (bytes.length >= 4 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 56) {
3445
- return "image/gif";
3446
- }
3447
- if (bytes.length >= 12 && bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
3448
- return "image/webp";
3449
- }
3450
- return null;
3451
- }
3452
3482
 
3453
3483
  async function loop(opts) {
3454
3484
  const logPath = persistence.logger.logFilePath;
@@ -3524,7 +3554,7 @@ class MessageQueue2 {
3524
3554
  * Push a message to the queue with a mode and an optional list of
3525
3555
  * attachments that travel with this message.
3526
3556
  */
3527
- push(message, mode, attachments) {
3557
+ push(message, mode, attachments, sourceId) {
3528
3558
  if (this.closed) {
3529
3559
  throw new Error("Cannot push to closed queue");
3530
3560
  }
@@ -3535,7 +3565,8 @@ class MessageQueue2 {
3535
3565
  mode,
3536
3566
  modeHash,
3537
3567
  isolate: false,
3538
- attachments
3568
+ attachments,
3569
+ sourceId
3539
3570
  });
3540
3571
  if (this.onMessageHandler) {
3541
3572
  this.onMessageHandler(message, mode);
@@ -3580,7 +3611,7 @@ class MessageQueue2 {
3580
3611
  * Clears any pending messages and ensures this message is never batched with others.
3581
3612
  * Used for special commands that require dedicated processing.
3582
3613
  */
3583
- pushIsolateAndClear(message, mode, attachments) {
3614
+ pushIsolateAndClear(message, mode, attachments, sourceId) {
3584
3615
  if (this.closed) {
3585
3616
  throw new Error("Cannot push to closed queue");
3586
3617
  }
@@ -3592,7 +3623,8 @@ class MessageQueue2 {
3592
3623
  mode,
3593
3624
  modeHash,
3594
3625
  isolate: true,
3595
- attachments
3626
+ attachments,
3627
+ sourceId
3596
3628
  });
3597
3629
  if (this.onMessageHandler) {
3598
3630
  this.onMessageHandler(message, mode);
@@ -3664,6 +3696,21 @@ class MessageQueue2 {
3664
3696
  size() {
3665
3697
  return this.queue.length;
3666
3698
  }
3699
+ /**
3700
+ * Remove one message that has not yet been collected by the agent loop.
3701
+ * Source id is authoritative. Exact-text fallback only covers items that
3702
+ * entered this live process before transport ids were introduced.
3703
+ */
3704
+ cancelPending(sourceId, exactText) {
3705
+ let index = sourceId ? this.queue.findIndex((item) => item.sourceId === sourceId) : -1;
3706
+ if (index < 0 && exactText !== void 0) {
3707
+ index = this.queue.findIndex((item) => item.sourceId === void 0 && item.message === exactText);
3708
+ }
3709
+ if (index < 0) return false;
3710
+ this.queue.splice(index, 1);
3711
+ persistence.logger.debug(`[MessageQueue2] Cancelled pending item. Queue size: ${this.queue.length}`);
3712
+ return true;
3713
+ }
3667
3714
  /**
3668
3715
  * Wait for messages and return all messages with the same mode as a single string
3669
3716
  * Returns { message: string, mode: T } or null if aborted/closed
@@ -8503,7 +8550,7 @@ const MAX_TITLE_CHARS = 60;
8503
8550
  const GENERATION_TIMEOUT_MS = 3e4;
8504
8551
  function resolveClaudeBinary() {
8505
8552
  try {
8506
- 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-SjWW0gIt.cjs', document.baseURI).href)));
8553
+ 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-BVlYjP10.cjs', document.baseURI).href)));
8507
8554
  const utilsPath = path.resolve(path.join(persistence.projectPath(), "scripts", "claude_version_utils.cjs"));
8508
8555
  const { getClaudeCliPath } = require$1(utilsPath);
8509
8556
  const path$1 = getClaudeCliPath();
@@ -8956,6 +9003,10 @@ async function runClaude(credentials, options = {}) {
8956
9003
  lifecycleState: "running",
8957
9004
  lifecycleStateSince: Date.now(),
8958
9005
  flavor: "claude",
9006
+ // Advertise composer support before the first SDK response. Otherwise
9007
+ // a brand-new session cannot pick a PDF until after sending once.
9008
+ attachmentKinds: [...CLAUDE_ATTACHMENT_KINDS],
9009
+ queueCancellation: true,
8959
9010
  sandbox: sandboxConfig?.enabled ? sandboxConfig : null,
8960
9011
  dangerouslySkipPermissions,
8961
9012
  ...forkedFromSessionId ? { parentSessionId: forkedFromSessionId } : {},
@@ -9059,7 +9110,8 @@ async function runClaude(credentials, options = {}) {
9059
9110
  session.updateMetadata((meta) => ({
9060
9111
  ...meta,
9061
9112
  lifecycleState: "running",
9062
- archivedBy: void 0
9113
+ archivedBy: void 0,
9114
+ queueCancellation: true
9063
9115
  }));
9064
9116
  }
9065
9117
  const forkClaudeSessionId = process.env.HAPPY_FORK_CLAUDE_SESSION_ID;
@@ -9184,6 +9236,12 @@ async function runClaude(credentials, options = {}) {
9184
9236
  disallowedTools: mode.disallowedTools,
9185
9237
  effort: mode.effort
9186
9238
  }));
9239
+ session.rpcHandlerManager.registerHandler("cancelQueuedMessage", async (params) => ({
9240
+ removed: messageQueue.cancelPending(
9241
+ typeof params?.localKey === "string" ? params.localKey : void 0,
9242
+ typeof params?.text === "string" ? params.text : void 0
9243
+ )
9244
+ }));
9187
9245
  let currentPermissionMode = initialPermissionMode;
9188
9246
  let currentModel = options.model ?? DEFAULT_CLAUDE_MODEL;
9189
9247
  let currentFallbackModel = void 0;
@@ -9326,7 +9384,7 @@ async function runClaude(credentials, options = {}) {
9326
9384
  disallowedTools: messageDisallowedTools,
9327
9385
  effort: messageEffort
9328
9386
  };
9329
- messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage);
9387
+ messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
9330
9388
  persistence.logger.debug("[start] /compact command pushed to queue:", {
9331
9389
  ...persistence.contentLogMetadata(message.content.text),
9332
9390
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
@@ -9346,7 +9404,7 @@ async function runClaude(credentials, options = {}) {
9346
9404
  disallowedTools: messageDisallowedTools,
9347
9405
  effort: messageEffort
9348
9406
  };
9349
- messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage);
9407
+ messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
9350
9408
  persistence.logger.debug("[start] /clear command pushed to queue:", {
9351
9409
  ...persistence.contentLogMetadata(message.content.text),
9352
9410
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
@@ -9402,7 +9460,7 @@ async function runClaude(credentials, options = {}) {
9402
9460
  disallowedTools: messageDisallowedTools,
9403
9461
  effort: messageEffort
9404
9462
  };
9405
- messageQueue.push(message.content.text, enhancedMode, attachmentsForThisMessage);
9463
+ messageQueue.push(message.content.text, enhancedMode, attachmentsForThisMessage, message.localKey);
9406
9464
  persistence.logger.debug("User message pushed to queue:", {
9407
9465
  ...persistence.contentLogMetadata(message.content.text),
9408
9466
  attachmentCount: attachmentsForThisMessage?.length ?? 0,
@@ -10620,9 +10678,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
10620
10678
  };
10621
10679
  }
10622
10680
 
10623
- 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-SjWW0gIt.cjs', document.baseURI).href)));
10681
+ 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-BVlYjP10.cjs', document.baseURI).href)));
10624
10682
  const __dirname$1 = path.dirname(__filename$1);
10625
- const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-SjWW0gIt.cjs', document.baseURI).href)));
10683
+ const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BVlYjP10.cjs', document.baseURI).href)));
10626
10684
  const PRISMA_QUERY_ENGINE_FILES = {
10627
10685
  "arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
10628
10686
  "x64-darwin": "libquery_engine-darwin.dylib.node",
@@ -13234,7 +13292,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13234
13292
  process.exit(0);
13235
13293
  } else if (subcommand === "install-terminal-hooks") {
13236
13294
  try {
13237
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-Xtl0pMWH.cjs'); });
13295
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-DC2wMq-X.cjs'); });
13238
13296
  const command = parseTerminalHooksArgs(args.slice(1));
13239
13297
  if (command.action === "help") {
13240
13298
  console.log(TERMINAL_HOOKS_HELP);
@@ -13251,7 +13309,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13251
13309
  }
13252
13310
  } else if (subcommand === "spawn") {
13253
13311
  try {
13254
- const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-BnvqaVCf.cjs'); });
13312
+ const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-CZAHiPE6.cjs'); });
13255
13313
  await handleSpawnCommand(args.slice(1));
13256
13314
  } catch (error) {
13257
13315
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13263,7 +13321,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13263
13321
  return;
13264
13322
  } else if (subcommand === "send") {
13265
13323
  try {
13266
- const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-D0U0T_bK.cjs'); });
13324
+ const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-C5dWPbV6.cjs'); });
13267
13325
  await handleSendCommand(args.slice(1));
13268
13326
  } catch (error) {
13269
13327
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13369,9 +13427,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13369
13427
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
13370
13428
  const projectId = args[3];
13371
13429
  try {
13372
- const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-B2TBK1UZ.cjs'); });
13373
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-DJC5rGtd.cjs'); }).then(function (n) { return n.persistence; });
13374
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DJC5rGtd.cjs'); }).then(function (n) { return n.api; });
13430
+ const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-BkxNWcwM.cjs'); });
13431
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-sFcb_Sfz.cjs'); }).then(function (n) { return n.persistence; });
13432
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-sFcb_Sfz.cjs'); }).then(function (n) { return n.api; });
13375
13433
  let userEmail = void 0;
13376
13434
  try {
13377
13435
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -13402,7 +13460,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13402
13460
  }
13403
13461
  if (geminiSubcommand === "project" && args[2] === "get") {
13404
13462
  try {
13405
- const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-B2TBK1UZ.cjs'); });
13463
+ const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-BkxNWcwM.cjs'); });
13406
13464
  const config = readGeminiLocalConfig();
13407
13465
  if (config.googleCloudProject) {
13408
13466
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -13442,7 +13500,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13442
13500
  process.exit(0);
13443
13501
  }
13444
13502
  try {
13445
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-DZay2CN7.cjs'); });
13503
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-Cqstl6qb.cjs'); });
13446
13504
  let startedBy = void 0;
13447
13505
  for (let i = 1; i < args.length; i++) {
13448
13506
  if (args[i] === "--started-by") {
@@ -13464,7 +13522,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13464
13522
  return;
13465
13523
  } else if (subcommand === "acp") {
13466
13524
  try {
13467
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-C9UnJZEo.cjs'); });
13525
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-fFNtiTSl.cjs'); });
13468
13526
  let startedBy = void 0;
13469
13527
  let verbose = false;
13470
13528
  const acpArgs = [];
@@ -13504,7 +13562,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13504
13562
  return;
13505
13563
  } else if (subcommand === "openclaw") {
13506
13564
  try {
13507
- const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-W3Ogud1U.cjs'); });
13565
+ const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-CHu488uC.cjs'); });
13508
13566
  let startedBy = void 0;
13509
13567
  let verbose = false;
13510
13568
  let gatewayUrl;
@@ -13555,7 +13613,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13555
13613
  return;
13556
13614
  } else if (subcommand === "mcp" && args.length === 1) {
13557
13615
  try {
13558
- const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-BxO80DMH.cjs'); });
13616
+ const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-CuDdOqST.cjs'); });
13559
13617
  await handleMcpCommand();
13560
13618
  } catch (error) {
13561
13619
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var AcpBackend = require('./AcpBackend-B7Z1Gk_l.cjs');
4
- var persistence = require('./types-DJC5rGtd.cjs');
5
- var AcpSessionManager = require('./AcpSessionManager-D3-rBUxk.cjs');
3
+ var AcpBackend = require('./AcpBackend-sS5ln9nS.cjs');
4
+ var persistence = require('./types-sFcb_Sfz.cjs');
5
+ var AcpSessionManager = require('./AcpSessionManager-DX5IvruC.cjs');
6
6
  var node_crypto = require('node:crypto');
7
7
  var path = require('node:path');
8
- var index = require('./index-SjWW0gIt.cjs');
8
+ var index = require('./index-BVlYjP10.cjs');
9
9
  require('node:child_process');
10
10
  require('@agentclientprotocol/sdk');
11
11
  require('axios');
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-SjWW0gIt.cjs');
5
- require('./types-DJC5rGtd.cjs');
4
+ require('./index-BVlYjP10.cjs');
5
+ require('./types-sFcb_Sfz.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-W3oj-d6C.mjs';
3
- import './types-DFKdwxE-.mjs';
2
+ import './index-BDhR8Zbc.mjs';
3
+ import './types-RASD9X96.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:os';
@@ -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-DFKdwxE-.mjs';
7
- import { t as tmuxSupportsSessionEnv } from './index-W3oj-d6C.mjs';
6
+ import { p as projectPath } from './types-RASD9X96.mjs';
7
+ import { t as tmuxSupportsSessionEnv } from './index-BDhR8Zbc.mjs';
8
8
  import 'axios';
9
9
  import 'node:util';
10
10
  import 'node:fs/promises';
@@ -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-DJC5rGtd.cjs');
9
- var index = require('./index-SjWW0gIt.cjs');
8
+ var persistence = require('./types-sFcb_Sfz.cjs');
9
+ var index = require('./index-BVlYjP10.cjs');
10
10
  require('axios');
11
11
  require('node:util');
12
12
  require('node:fs/promises');
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var persistence = require('./types-DJC5rGtd.cjs');
3
+ var persistence = require('./types-sFcb_Sfz.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('node:util');
package/dist/lib.d.cts CHANGED
@@ -427,6 +427,10 @@ type Metadata = {
427
427
  status: string;
428
428
  }>;
429
429
  skills?: string[];
430
+ /** Attachment content blocks this daemon can forward to the active SDK. */
431
+ attachmentKinds?: string[];
432
+ /** Pending user messages can be canceled by stable transport id. */
433
+ queueCancellation?: boolean;
430
434
  homeDir: string;
431
435
  happyHomeDir: string;
432
436
  happyLibDir: string;
package/dist/lib.d.mts CHANGED
@@ -427,6 +427,10 @@ type Metadata = {
427
427
  status: string;
428
428
  }>;
429
429
  skills?: string[];
430
+ /** Attachment content blocks this daemon can forward to the active SDK. */
431
+ attachmentKinds?: string[];
432
+ /** Pending user messages can be canceled by stable transport id. */
433
+ queueCancellation?: boolean;
430
434
  homeDir: string;
431
435
  happyHomeDir: string;
432
436
  happyLibDir: string;
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-DFKdwxE-.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-RASD9X96.mjs';
2
2
  import 'axios';
3
3
  import 'chalk';
4
4
  import 'node:util';
@@ -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-W3oj-d6C.mjs';
4
+ import { p as pushClipboardViaDaemon } from './index-BDhR8Zbc.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-DFKdwxE-.mjs';
6
+ import { l as logger } from './types-RASD9X96.mjs';
7
7
  import 'chalk';
8
8
  import 'node:os';
9
9
  import 'node:crypto';
@@ -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-SjWW0gIt.cjs');
6
+ var index = require('./index-BVlYjP10.cjs');
7
7
  var limits = require('./limits-KdWKmwtH.cjs');
8
- var persistence = require('./types-DJC5rGtd.cjs');
8
+ var persistence = require('./types-sFcb_Sfz.cjs');
9
9
  require('chalk');
10
10
  require('node:os');
11
11
  require('node:crypto');
@@ -4,10 +4,10 @@ var ink = require('ink');
4
4
  var React = require('react');
5
5
  var node_crypto = require('node:crypto');
6
6
  var path = require('node:path');
7
- var persistence = require('./types-DJC5rGtd.cjs');
8
- var index = require('./index-SjWW0gIt.cjs');
9
- var AcpBackend = require('./AcpBackend-B7Z1Gk_l.cjs');
10
- var config = require('./config-B2TBK1UZ.cjs');
7
+ var persistence = require('./types-sFcb_Sfz.cjs');
8
+ var index = require('./index-BVlYjP10.cjs');
9
+ var AcpBackend = require('./AcpBackend-sS5ln9nS.cjs');
10
+ var config = require('./config-BkxNWcwM.cjs');
11
11
  require('axios');
12
12
  require('chalk');
13
13
  require('node:util');
@@ -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, i as readSettings, e as errorLogMetadata, j as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-DFKdwxE-.mjs';
6
- import { g as GEMINI_API_KEY_ENV, j as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, k as BaseReasoningProcessor, i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, l as MessageBuffer, C as CHANGE_TITLE_INSTRUCTION, r as registerKillSessionHandler, f as startHappyServer } from './index-W3oj-d6C.mjs';
7
- import { A as AcpBackend } from './AcpBackend-cBt4R6ce.mjs';
8
- import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-CZdNxl3d.mjs';
5
+ import { l as logger, h as connectionState, A as ApiClient, i as readSettings, e as errorLogMetadata, j as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-RASD9X96.mjs';
6
+ import { g as GEMINI_API_KEY_ENV, j as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, k as BaseReasoningProcessor, i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, l as MessageBuffer, C as CHANGE_TITLE_INSTRUCTION, r as registerKillSessionHandler, f as startHappyServer } from './index-BDhR8Zbc.mjs';
7
+ import { A as AcpBackend } from './AcpBackend-DbS9-r10.mjs';
8
+ import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-3BOBElkv.mjs';
9
9
  import 'axios';
10
10
  import 'chalk';
11
11
  import 'node:util';
@@ -3,9 +3,9 @@ import { execFileSync } from 'node:child_process';
3
3
  import os from 'node:os';
4
4
  import { existsSync, readFileSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
- import { k as ensurePrivateDirectorySync, m as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, c as configuration } from './types-DFKdwxE-.mjs';
7
- import { A as AcpSessionManager } from './AcpSessionManager-AyrINTu7.mjs';
8
- import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, r as registerKillSessionHandler } from './index-W3oj-d6C.mjs';
6
+ import { k as ensurePrivateDirectorySync, m as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, c as configuration } from './types-RASD9X96.mjs';
7
+ import { A as AcpSessionManager } from './AcpSessionManager-DuZN34yy.mjs';
8
+ import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, r as registerKillSessionHandler } from './index-BDhR8Zbc.mjs';
9
9
  import WebSocket from 'ws';
10
10
  import * as ed from '@noble/ed25519';
11
11
  import { sha512 } from '@noble/hashes/sha2.js';
@@ -5,9 +5,9 @@ var node_child_process = require('node:child_process');
5
5
  var os = require('node:os');
6
6
  var node_fs = require('node:fs');
7
7
  var path = require('node:path');
8
- var persistence = require('./types-DJC5rGtd.cjs');
9
- var AcpSessionManager = require('./AcpSessionManager-D3-rBUxk.cjs');
10
- var index = require('./index-SjWW0gIt.cjs');
8
+ var persistence = require('./types-sFcb_Sfz.cjs');
9
+ var AcpSessionManager = require('./AcpSessionManager-DX5IvruC.cjs');
10
+ var index = require('./index-BVlYjP10.cjs');
11
11
  var WebSocket = require('ws');
12
12
  var ed = require('@noble/ed25519');
13
13
  var sha2_js = require('@noble/hashes/sha2.js');
@@ -3,8 +3,8 @@
3
3
  var chalk = require('chalk');
4
4
  var node_fs = require('node:fs');
5
5
  var path = require('node:path');
6
- var persistence = require('./types-DJC5rGtd.cjs');
7
- var index = require('./index-SjWW0gIt.cjs');
6
+ var persistence = require('./types-sFcb_Sfz.cjs');
7
+ var index = require('./index-BVlYjP10.cjs');
8
8
  require('axios');
9
9
  require('node:util');
10
10
  require('node:os');
@@ -1,8 +1,8 @@
1
1
  import chalk from 'chalk';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
- import { r as readPersistedSessions, c as configuration } from './types-DFKdwxE-.mjs';
5
- import { b as sendUserMessage, a as sessionWebUrl } from './index-W3oj-d6C.mjs';
4
+ import { r as readPersistedSessions, c as configuration } from './types-RASD9X96.mjs';
5
+ import { b as sendUserMessage, a as sessionWebUrl } from './index-BDhR8Zbc.mjs';
6
6
  import 'axios';
7
7
  import 'node:util';
8
8
  import 'node:os';
@@ -3,8 +3,8 @@
3
3
  var chalk = require('chalk');
4
4
  var node_fs = require('node:fs');
5
5
  var path = require('node:path');
6
- var index = require('./index-SjWW0gIt.cjs');
7
- var persistence = require('./types-DJC5rGtd.cjs');
6
+ var index = require('./index-BVlYjP10.cjs');
7
+ var persistence = require('./types-sFcb_Sfz.cjs');
8
8
  require('node:os');
9
9
  require('node:crypto');
10
10
  require('cross-spawn');
@@ -1,8 +1,8 @@
1
1
  import chalk from 'chalk';
2
2
  import { readFileSync, statSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
- import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, w as waitForSessionKey, b as sendUserMessage } from './index-W3oj-d6C.mjs';
5
- import { l as logger } from './types-DFKdwxE-.mjs';
4
+ import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, w as waitForSessionKey, b as sendUserMessage } from './index-BDhR8Zbc.mjs';
5
+ import { l as logger } from './types-RASD9X96.mjs';
6
6
  import 'node:os';
7
7
  import 'node:crypto';
8
8
  import 'cross-spawn';
@@ -29,7 +29,7 @@ import { SandboxManager } from '@anthropic-ai/sandbox-runtime';
29
29
  import { Expo } from 'expo-server-sdk';
30
30
 
31
31
  var name = "very-happy-cli";
32
- var version = "0.2.81";
32
+ var version = "0.2.83";
33
33
  var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
34
34
  var author = "Kirill Dubovitskiy";
35
35
  var contributors = [
@@ -142,12 +142,12 @@ var dependencies = {
142
142
  zod: "^4.0.0"
143
143
  };
144
144
  var optionalDependencies = {
145
- "very-happy-tools-arm64-darwin": "0.2.81",
146
- "very-happy-tools-x64-darwin": "0.2.81",
147
- "very-happy-tools-arm64-linux": "0.2.81",
148
- "very-happy-tools-x64-linux": "0.2.81",
149
- "very-happy-tools-arm64-win32": "0.2.81",
150
- "very-happy-tools-x64-win32": "0.2.81"
145
+ "very-happy-tools-arm64-darwin": "0.2.83",
146
+ "very-happy-tools-x64-darwin": "0.2.83",
147
+ "very-happy-tools-arm64-linux": "0.2.83",
148
+ "very-happy-tools-x64-linux": "0.2.83",
149
+ "very-happy-tools-arm64-win32": "0.2.83",
150
+ "very-happy-tools-x64-win32": "0.2.83"
151
151
  };
152
152
  var devDependencies = {
153
153
  "@slopus/happy-wire": "workspace:*",
@@ -2915,7 +2915,7 @@ class ApiSessionClient extends EventEmitter {
2915
2915
  }
2916
2916
  const body = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(data.body.message.content.c));
2917
2917
  logger.debugLargeJson("[SOCKET] [UPDATE] Received update:", body);
2918
- this.routeIncomingMessage(body);
2918
+ this.routeIncomingMessage(body, localId);
2919
2919
  if (localId) this.rememberRoutedInbound(localId);
2920
2920
  this.lastSeq = messageSeq;
2921
2921
  } else if (data.body.t === "update-session") {
@@ -3143,8 +3143,9 @@ class ApiSessionClient extends EventEmitter {
3143
3143
  "X-Happy-Client": `cli-coding-session/${configuration.currentCliVersion}`
3144
3144
  };
3145
3145
  }
3146
- routeIncomingMessage(message) {
3147
- const userResult = UserMessageSchema.safeParse(message);
3146
+ routeIncomingMessage(message, sourceLocalId) {
3147
+ const messageWithSource = sourceLocalId && typeof message === "object" && message !== null ? { ...message, localKey: message.localKey ?? sourceLocalId } : message;
3148
+ const userResult = UserMessageSchema.safeParse(messageWithSource);
3148
3149
  if (userResult.success) {
3149
3150
  if (this.pendingMessageCallback) {
3150
3151
  this.pendingMessageCallback(userResult.data);
@@ -3199,7 +3200,7 @@ class ApiSessionClient extends EventEmitter {
3199
3200
  }
3200
3201
  try {
3201
3202
  const body = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(message.content.c));
3202
- this.routeIncomingMessage(body);
3203
+ this.routeIncomingMessage(body, message.localId);
3203
3204
  if (message.localId) this.rememberRoutedInbound(message.localId);
3204
3205
  } catch (error) {
3205
3206
  logger.debug("[API] Failed to decrypt fetched message", {
@@ -3319,7 +3320,7 @@ class ApiSessionClient extends EventEmitter {
3319
3320
  for (const item of batch) {
3320
3321
  if (this.routedInboundLocalIds.has(item.localId)) continue;
3321
3322
  const body = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(item.content));
3322
- this.routeIncomingMessage(body);
3323
+ this.routeIncomingMessage(body, item.localId);
3323
3324
  this.rememberRoutedInbound(item.localId);
3324
3325
  }
3325
3326
  callback({ ok: true, messages: stored });
@@ -51,7 +51,7 @@ var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
51
51
  var pty__namespace = /*#__PURE__*/_interopNamespaceDefault(pty);
52
52
 
53
53
  var name = "very-happy-cli";
54
- var version = "0.2.81";
54
+ var version = "0.2.83";
55
55
  var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
56
56
  var author = "Kirill Dubovitskiy";
57
57
  var contributors = [
@@ -164,12 +164,12 @@ var dependencies = {
164
164
  zod: "^4.0.0"
165
165
  };
166
166
  var optionalDependencies = {
167
- "very-happy-tools-arm64-darwin": "0.2.81",
168
- "very-happy-tools-x64-darwin": "0.2.81",
169
- "very-happy-tools-arm64-linux": "0.2.81",
170
- "very-happy-tools-x64-linux": "0.2.81",
171
- "very-happy-tools-arm64-win32": "0.2.81",
172
- "very-happy-tools-x64-win32": "0.2.81"
167
+ "very-happy-tools-arm64-darwin": "0.2.83",
168
+ "very-happy-tools-x64-darwin": "0.2.83",
169
+ "very-happy-tools-arm64-linux": "0.2.83",
170
+ "very-happy-tools-x64-linux": "0.2.83",
171
+ "very-happy-tools-arm64-win32": "0.2.83",
172
+ "very-happy-tools-x64-win32": "0.2.83"
173
173
  };
174
174
  var devDependencies = {
175
175
  "@slopus/happy-wire": "workspace:*",
@@ -1480,7 +1480,7 @@ class RpcHandlerManager {
1480
1480
  }
1481
1481
  }
1482
1482
 
1483
- const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-DJC5rGtd.cjs', document.baseURI).href))));
1483
+ const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-sFcb_Sfz.cjs', document.baseURI).href))));
1484
1484
  function projectPath() {
1485
1485
  const path = path$1.resolve(__dirname$1, "..");
1486
1486
  return path;
@@ -2937,7 +2937,7 @@ class ApiSessionClient extends node_events.EventEmitter {
2937
2937
  }
2938
2938
  const body = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(data.body.message.content.c));
2939
2939
  logger.debugLargeJson("[SOCKET] [UPDATE] Received update:", body);
2940
- this.routeIncomingMessage(body);
2940
+ this.routeIncomingMessage(body, localId);
2941
2941
  if (localId) this.rememberRoutedInbound(localId);
2942
2942
  this.lastSeq = messageSeq;
2943
2943
  } else if (data.body.t === "update-session") {
@@ -3165,8 +3165,9 @@ class ApiSessionClient extends node_events.EventEmitter {
3165
3165
  "X-Happy-Client": `cli-coding-session/${configuration.currentCliVersion}`
3166
3166
  };
3167
3167
  }
3168
- routeIncomingMessage(message) {
3169
- const userResult = UserMessageSchema.safeParse(message);
3168
+ routeIncomingMessage(message, sourceLocalId) {
3169
+ const messageWithSource = sourceLocalId && typeof message === "object" && message !== null ? { ...message, localKey: message.localKey ?? sourceLocalId } : message;
3170
+ const userResult = UserMessageSchema.safeParse(messageWithSource);
3170
3171
  if (userResult.success) {
3171
3172
  if (this.pendingMessageCallback) {
3172
3173
  this.pendingMessageCallback(userResult.data);
@@ -3221,7 +3222,7 @@ class ApiSessionClient extends node_events.EventEmitter {
3221
3222
  }
3222
3223
  try {
3223
3224
  const body = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(message.content.c));
3224
- this.routeIncomingMessage(body);
3225
+ this.routeIncomingMessage(body, message.localId);
3225
3226
  if (message.localId) this.rememberRoutedInbound(message.localId);
3226
3227
  } catch (error) {
3227
3228
  logger.debug("[API] Failed to decrypt fetched message", {
@@ -3341,7 +3342,7 @@ class ApiSessionClient extends node_events.EventEmitter {
3341
3342
  for (const item of batch) {
3342
3343
  if (this.routedInboundLocalIds.has(item.localId)) continue;
3343
3344
  const body = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(item.content));
3344
- this.routeIncomingMessage(body);
3345
+ this.routeIncomingMessage(body, item.localId);
3345
3346
  this.rememberRoutedInbound(item.localId);
3346
3347
  }
3347
3348
  callback({ ok: true, messages: stored });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "very-happy-cli",
3
- "version": "0.2.81",
3
+ "version": "0.2.83",
4
4
  "description": "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.",
5
5
  "author": "Kirill Dubovitskiy",
6
6
  "contributors": [
@@ -113,12 +113,12 @@
113
113
  "zod": "^4.0.0"
114
114
  },
115
115
  "optionalDependencies": {
116
- "very-happy-tools-arm64-darwin": "0.2.81",
117
- "very-happy-tools-x64-darwin": "0.2.81",
118
- "very-happy-tools-arm64-linux": "0.2.81",
119
- "very-happy-tools-x64-linux": "0.2.81",
120
- "very-happy-tools-arm64-win32": "0.2.81",
121
- "very-happy-tools-x64-win32": "0.2.81"
116
+ "very-happy-tools-arm64-darwin": "0.2.83",
117
+ "very-happy-tools-x64-darwin": "0.2.83",
118
+ "very-happy-tools-arm64-linux": "0.2.83",
119
+ "very-happy-tools-x64-linux": "0.2.83",
120
+ "very-happy-tools-arm64-win32": "0.2.83",
121
+ "very-happy-tools-x64-win32": "0.2.83"
122
122
  },
123
123
  "devDependencies": {
124
124
  "@slopus/happy-wire": "workspace:*",