very-happy-cli 0.2.120 → 0.2.122

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-tou8FQXI.cjs → AcpBackend-YPVwACkW.cjs} +1 -1
  2. package/dist/{AcpBackend-DiIJaJWG.mjs → AcpBackend-pgDnK76l.mjs} +1 -1
  3. package/dist/{AcpSessionManager-fF_HFB98.cjs → AcpSessionManager-6rypahwH.cjs} +51 -11
  4. package/dist/{AcpSessionManager-CZ0Az0GG.mjs → AcpSessionManager-Bq5Tiky1.mjs} +51 -11
  5. package/dist/{config-CGDxsTZg.mjs → config-BTEW041n.mjs} +2 -2
  6. package/dist/{config-CEbOao_0.cjs → config-rQdv_Yr0.cjs} +2 -2
  7. package/dist/{index-CYizH-JC.cjs → index-BHg0P9cY.cjs} +2 -2
  8. package/dist/{index-CUJ6faw1.mjs → index-BTnlYGaP.mjs} +139 -41
  9. package/dist/{index-D4_LW69g.mjs → index-BeHr5uMY.mjs} +25 -11
  10. package/dist/{index-DKj_0dqB.mjs → index-CaIsj1q7.mjs} +2 -2
  11. package/dist/{index-BlkIz9BQ.cjs → index-DKRU6E-x.cjs} +143 -44
  12. package/dist/{index-HKcuQ_fQ.cjs → index-uPpFZhhr.cjs} +24 -10
  13. package/dist/index.cjs +2 -2
  14. package/dist/index.mjs +2 -2
  15. package/dist/{installTerminalHooks-MWVPJDxV.cjs → installTerminalHooks-CGqopr1A.cjs} +2 -2
  16. package/dist/{installTerminalHooks-B3EGNaJr.mjs → installTerminalHooks-DFmKhCto.mjs} +2 -2
  17. package/dist/lib.cjs +1 -1
  18. package/dist/lib.d.cts +25 -1
  19. package/dist/lib.d.mts +25 -1
  20. package/dist/lib.mjs +1 -1
  21. package/dist/{mcp-CZ1Z6AI5.mjs → mcp-DnKBKXYa.mjs} +2 -2
  22. package/dist/{mcp-DBKk5L6_.cjs → mcp-FlbfMw6_.cjs} +2 -2
  23. package/dist/{runGemini-C3BCKTMp.mjs → runGemini-BsfadDSa.mjs} +9 -5
  24. package/dist/{runGemini-BRUmjZgV.cjs → runGemini-DYawZQTu.cjs} +9 -5
  25. package/dist/{runOpenClaw-o1ImBlcJ.cjs → runOpenClaw-C2XjFP2m.cjs} +3 -3
  26. package/dist/{runOpenClaw-DEYzcGSV.mjs → runOpenClaw-xGtbJ7f8.mjs} +3 -3
  27. package/dist/{send-B9fh96vR.cjs → send-B0Wojz18.cjs} +2 -2
  28. package/dist/{send-DFGH_-s_.mjs → send-DRZppEr2.mjs} +2 -2
  29. package/dist/{sessions-CKVfXHyi.mjs → sessions-BuMgxuxd.mjs} +11 -4
  30. package/dist/{sessions-BNyEJ2_6.cjs → sessions-CTuUV0TW.cjs} +11 -4
  31. package/dist/{spawn-xPV7-s4S.cjs → spawn-7U_4QTHw.cjs} +2 -2
  32. package/dist/{spawn-B6kP4YjA.mjs → spawn-BRdfNDsu.mjs} +2 -2
  33. package/dist/{types-7ZSxm6Pi.cjs → types-Jag0GwhO.cjs} +209 -41
  34. package/dist/{types-Di0o0BdV.mjs → types-q7wtjfxb.mjs} +208 -41
  35. package/package.json +7 -7
@@ -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-7ZSxm6Pi.cjs');
6
+ var persistence = require('./types-Jag0GwhO.cjs');
7
7
  var spawn = require('cross-spawn');
8
8
  var path = require('node:path');
9
9
  var node_readline = require('node:readline');
@@ -3406,9 +3406,7 @@ class StreamRelay {
3406
3406
  if (e.type === "content_block_start") {
3407
3407
  const kind = e.content_block?.type === "thinking" ? "thinking" : e.content_block?.type === "text" ? "text" : null;
3408
3408
  if (!kind || !this.currentMid || typeof e.index !== "number") return;
3409
- this.flushPending();
3410
- this.openBlocks.add(e.index);
3411
- this.send({ t: "block-start", mid: this.currentMid, idx: e.index, kind });
3409
+ this.openBlock(this.currentMid, e.index, kind);
3412
3410
  return;
3413
3411
  }
3414
3412
  if (e.type === "content_block_delta") {
@@ -3416,16 +3414,12 @@ class StreamRelay {
3416
3414
  const text = delta?.type === "text_delta" ? delta.text : delta?.type === "thinking_delta" ? delta.thinking : null;
3417
3415
  if (typeof text !== "string" || text.length === 0) return;
3418
3416
  if (!this.currentMid || typeof e.index !== "number") return;
3419
- if (!this.openBlocks.has(e.index)) return;
3420
3417
  this.appendDelta(this.currentMid, e.index, text);
3421
3418
  return;
3422
3419
  }
3423
3420
  if (e.type === "content_block_stop") {
3424
3421
  if (!this.currentMid || typeof e.index !== "number") return;
3425
- if (!this.openBlocks.has(e.index)) return;
3426
- this.flushPending();
3427
- this.openBlocks.delete(e.index);
3428
- this.send({ t: "block-end", mid: this.currentMid, idx: e.index });
3422
+ this.closeBlock(this.currentMid, e.index);
3429
3423
  return;
3430
3424
  }
3431
3425
  if (e.type === "message_delta") {
@@ -3436,7 +3430,29 @@ class StreamRelay {
3436
3430
  return;
3437
3431
  }
3438
3432
  }
3433
+ // ---- Block-level API (see module comment) --------------------------------
3434
+ /** Open a draft block. A different `mid` than the one currently open closes
3435
+ * whatever the previous message left open, exactly like the SDK's
3436
+ * `message_start` does. Re-opening an already open block is a no-op. */
3437
+ openBlock(mid, idx, kind) {
3438
+ this.idleSinceTurnEnd = false;
3439
+ if (this.currentMid !== mid) {
3440
+ this.flushPending();
3441
+ this.closeOpenBlocks();
3442
+ this.currentMid = mid;
3443
+ }
3444
+ if (this.openBlocks.has(idx)) return;
3445
+ this.flushPending();
3446
+ this.openBlocks.add(idx);
3447
+ this.send({ t: "block-start", mid, idx, kind });
3448
+ }
3449
+ /** Append text to an OPEN block; deltas for a block that was never opened
3450
+ * (or belongs to another message) are dropped — the SDK path relies on
3451
+ * this to ignore `input_json_delta` for tool_use blocks. */
3439
3452
  appendDelta(mid, idx, text) {
3453
+ this.idleSinceTurnEnd = false;
3454
+ if (text.length === 0) return;
3455
+ if (this.currentMid !== mid || !this.openBlocks.has(idx)) return;
3440
3456
  if (this.pending && (this.pending.mid !== mid || this.pending.idx !== idx)) {
3441
3457
  this.flushPending();
3442
3458
  }
@@ -3456,6 +3472,22 @@ class StreamRelay {
3456
3472
  }, STREAM_FLUSH_MS);
3457
3473
  }
3458
3474
  }
3475
+ /** Close an open block: pending text goes out first, then `block-end`. */
3476
+ closeBlock(mid, idx) {
3477
+ this.idleSinceTurnEnd = false;
3478
+ if (this.currentMid !== mid || !this.openBlocks.has(idx)) return;
3479
+ this.flushPending();
3480
+ this.openBlocks.delete(idx);
3481
+ this.send({ t: "block-end", mid, idx });
3482
+ }
3483
+ /** Merge quantified progress; flushed on the progress cadence. */
3484
+ setProgress(patch) {
3485
+ this.idleSinceTurnEnd = false;
3486
+ this.progress = { ...this.progress, ...patch };
3487
+ this.progressDirty = true;
3488
+ this.scheduleProgress();
3489
+ }
3490
+ // -------------------------------------------------------------------------
3459
3491
  flushPending() {
3460
3492
  if (this.flushHandle !== null) {
3461
3493
  this.clearTimer(this.flushHandle);
@@ -3478,11 +3510,6 @@ class StreamRelay {
3478
3510
  }
3479
3511
  this.openBlocks.clear();
3480
3512
  }
3481
- setProgress(patch) {
3482
- this.progress = { ...this.progress, ...patch };
3483
- this.progressDirty = true;
3484
- this.scheduleProgress();
3485
- }
3486
3513
  scheduleProgress() {
3487
3514
  if (this.progressHandle !== null) return;
3488
3515
  this.progressHandle = this.setTimer(() => {
@@ -4325,10 +4352,17 @@ class MessageQueue2 {
4325
4352
  waiter = null;
4326
4353
  closed = false;
4327
4354
  onMessageHandler = null;
4355
+ /**
4356
+ * B-332: fired for every item the queue itself destroys before it was ever
4357
+ * handed to the runner. The runner wires this to a queue-cancel tombstone
4358
+ * so the web stops painting a silently-lost message as "queued".
4359
+ */
4360
+ onDiscardHandler = null;
4328
4361
  modeHasher;
4329
- constructor(modeHasher, onMessageHandler = null) {
4362
+ constructor(modeHasher, onMessageHandler = null, onDiscardHandler = null) {
4330
4363
  this.modeHasher = modeHasher;
4331
4364
  this.onMessageHandler = onMessageHandler;
4365
+ this.onDiscardHandler = onDiscardHandler;
4332
4366
  persistence.logger.debug(`[MessageQueue2] Initialized`);
4333
4367
  }
4334
4368
  /**
@@ -4337,6 +4371,19 @@ class MessageQueue2 {
4337
4371
  setOnMessage(handler) {
4338
4372
  this.onMessageHandler = handler;
4339
4373
  }
4374
+ /**
4375
+ * Set a handler that will be called when messages are discarded without ever
4376
+ * being processed (B-332).
4377
+ */
4378
+ setOnDiscard(handler) {
4379
+ this.onDiscardHandler = handler;
4380
+ }
4381
+ /** Report the current items as destroyed for `reason` (caller clears next). */
4382
+ notifyDiscard(reason) {
4383
+ if (this.queue.length === 0) return;
4384
+ const entries = this.queue.map((item) => ({ sourceId: item.sourceId, reason }));
4385
+ this.onDiscardHandler?.(entries);
4386
+ }
4340
4387
  /**
4341
4388
  * Push a message to the queue with a mode and an optional list of
4342
4389
  * attachments that travel with this message.
@@ -4404,6 +4451,7 @@ class MessageQueue2 {
4404
4451
  }
4405
4452
  const modeHash = this.modeHasher(mode);
4406
4453
  persistence.logger.debug(`[MessageQueue2] pushIsolateAndClear() called with mode hash: ${modeHash} - clearing ${this.queue.length} pending messages`);
4454
+ this.notifyDiscard("cleared");
4407
4455
  this.queue = [];
4408
4456
  this.queue.push({
4409
4457
  message,
@@ -4455,6 +4503,7 @@ class MessageQueue2 {
4455
4503
  */
4456
4504
  reset() {
4457
4505
  persistence.logger.debug(`[MessageQueue2] reset() called. Clearing ${this.queue.length} messages`);
4506
+ this.notifyDiscard("aborted");
4458
4507
  this.queue = [];
4459
4508
  this.closed = false;
4460
4509
  this.waiter = null;
@@ -7352,7 +7401,7 @@ function parseJsonObject(text) {
7352
7401
  return null;
7353
7402
  }
7354
7403
  }
7355
- function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BlkIz9BQ.cjs', document.baseURI).href))).resolve(s)) {
7404
+ function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DKRU6E-x.cjs', document.baseURI).href))).resolve(s)) {
7356
7405
  const platformArch = `${platform}-${arch}`;
7357
7406
  const candidates = [
7358
7407
  `@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
@@ -9998,6 +10047,27 @@ async function openUserScopedSocket(token, options = {}) {
9998
10047
  };
9999
10048
  }
10000
10049
 
10050
+ const RPC_RATE_LIMIT_ERROR = "RPC rate limit reached";
10051
+ const RPC_ACCOUNT_RATE_LIMIT_ERROR = "RPC account rate limit reached";
10052
+ const RPC_RATE_RETRY_MIN_DELAY_MS = 2e3;
10053
+ const RPC_RATE_RETRY_MAX_DELAY_MS = 6e4;
10054
+ const RPC_RATE_MAX_RETRIES = 2;
10055
+ function isRpcRateLimitAck(ack) {
10056
+ if (!ack || typeof ack !== "object") return false;
10057
+ const a = ack;
10058
+ if (a.ok !== false) return false;
10059
+ if (a.code === "rpc_rate_limited" || a.code === "rpc_account_rate_limited") return true;
10060
+ return a.error === RPC_RATE_LIMIT_ERROR || a.error === RPC_ACCOUNT_RATE_LIMIT_ERROR;
10061
+ }
10062
+ function rpcRateRetryDelayMs(attempt, retryAfterMs, random = Math.random()) {
10063
+ if (typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0) {
10064
+ return Math.min(RPC_RATE_RETRY_MAX_DELAY_MS, Math.round(retryAfterMs * (1 + random * 0.5)));
10065
+ }
10066
+ const exponent = Math.max(0, Math.min(attempt, 32) - 1);
10067
+ const ceiling = Math.min(RPC_RATE_RETRY_MIN_DELAY_MS * 2 ** exponent, RPC_RATE_RETRY_MAX_DELAY_MS);
10068
+ return Math.round(RPC_RATE_RETRY_MIN_DELAY_MS + random * (ceiling - RPC_RATE_RETRY_MIN_DELAY_MS));
10069
+ }
10070
+
10001
10071
  const PERMISSION_OPS_CLIENT = "session-ops";
10002
10072
  const PERMISSION_RPC_TIMEOUT_MS = 3e4;
10003
10073
  const SETTLE_TIMEOUT_MS = 5e3;
@@ -10029,6 +10099,9 @@ function interpretPermissionAck(ack, decryptResult) {
10029
10099
  if (/timed? ?out/i.test(message)) {
10030
10100
  return { status: "timeout", message };
10031
10101
  }
10102
+ if (isRpcRateLimitAck(ack)) {
10103
+ return { status: "rate-limited", message, retryAfterMs: rpcRateRetryDelayMs(1, ack.retryAfterMs, 0) };
10104
+ }
10032
10105
  return { status: "rejected", message };
10033
10106
  }
10034
10107
  let body = null;
@@ -10090,15 +10163,24 @@ async function resolvePermissionRequest(sessionId, requestId, verdict, deps = {}
10090
10163
  const params = persistence.encodeBase64(persistence.encrypt(key, persisted.encryptionVariant, payload));
10091
10164
  const transport = await (deps.openTransport ?? openUserScopedSocket)(token);
10092
10165
  const rpcTimeoutMs = deps.rpcTimeoutMs ?? PERMISSION_RPC_TIMEOUT_MS;
10166
+ const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
10093
10167
  let ack;
10094
10168
  try {
10095
- ack = await withDeadline(
10096
- transport.rpcCall({ method: `${sessionId}:permission`, params }, rpcTimeoutMs),
10097
- rpcTimeoutMs + RPC_DEADLINE_GRACE_MS,
10098
- `permission RPC did not settle within ${rpcTimeoutMs}ms`
10099
- );
10100
- } catch (error) {
10101
- ack = { ok: false, error: error instanceof Error ? error.message : "RPC call failed" };
10169
+ for (let attempt = 1; ; attempt++) {
10170
+ try {
10171
+ ack = await withDeadline(
10172
+ transport.rpcCall({ method: `${sessionId}:permission`, params }, rpcTimeoutMs),
10173
+ rpcTimeoutMs + RPC_DEADLINE_GRACE_MS,
10174
+ `permission RPC did not settle within ${rpcTimeoutMs}ms`
10175
+ );
10176
+ } catch (error) {
10177
+ ack = { ok: false, error: error instanceof Error ? error.message : "RPC call failed" };
10178
+ }
10179
+ if (!isRpcRateLimitAck(ack) || attempt > RPC_RATE_MAX_RETRIES) break;
10180
+ const waitMs = rpcRateRetryDelayMs(attempt, ack.retryAfterMs, (deps.random ?? Math.random)());
10181
+ deps.onRateLimited?.({ attempt, waitMs, serverError: ack.error ?? "RPC rate limit reached" });
10182
+ await sleep(waitMs);
10183
+ }
10102
10184
  } finally {
10103
10185
  transport.close();
10104
10186
  }
@@ -10106,7 +10188,6 @@ async function resolvePermissionRequest(sessionId, requestId, verdict, deps = {}
10106
10188
  if (outcome.status !== "acknowledged") {
10107
10189
  return { sessionId, requestId, payload, outcome };
10108
10190
  }
10109
- const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
10110
10191
  const deadline = now() + (deps.settleTimeoutMs ?? SETTLE_TIMEOUT_MS);
10111
10192
  let settled = false;
10112
10193
  for (; ; ) {
@@ -11237,7 +11318,7 @@ function registerSideQuestionHandler(rpc, deps) {
11237
11318
  const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
11238
11319
  const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
11239
11320
  const run = deps.run ?? (async (input) => {
11240
- const { query } = await Promise.resolve().then(function () { return require('./index-CYizH-JC.cjs'); });
11321
+ const { query } = await Promise.resolve().then(function () { return require('./index-BHg0P9cY.cjs'); });
11241
11322
  return runSideQuestion(query, input);
11242
11323
  });
11243
11324
  const slots = /* @__PURE__ */ new Map();
@@ -11339,7 +11420,7 @@ const MAX_TITLE_CHARS = 60;
11339
11420
  const GENERATION_TIMEOUT_MS = 3e4;
11340
11421
  function resolveClaudeBinary() {
11341
11422
  try {
11342
- 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-BlkIz9BQ.cjs', document.baseURI).href)));
11423
+ 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-DKRU6E-x.cjs', document.baseURI).href)));
11343
11424
  const utilsPath = path.resolve(path.join(persistence.projectPath(), "scripts", "claude_version_utils.cjs"));
11344
11425
  const { getClaudeCliPath } = require$1(utilsPath);
11345
11426
  const path$1 = getClaudeCliPath();
@@ -11919,6 +12000,7 @@ async function runClaude(credentials, options = {}) {
11919
12000
  if (reconnectSessionId) {
11920
12001
  session.suppressNextArchiveSignal();
11921
12002
  if (!reconnectSeeded) session.skipExistingMessages();
12003
+ void session.cancelUndeliveredQueuedInputs();
11922
12004
  session.updateMetadata((meta) => ({
11923
12005
  ...mergeReconnectMetadata(meta, metadata, Date.now()),
11924
12006
  queueCancellation: true,
@@ -12043,6 +12125,16 @@ async function runClaude(credentials, options = {}) {
12043
12125
  controlledByUser: options.startingMode !== "remote"
12044
12126
  }));
12045
12127
  const messageQueue = new MessageQueue2(claudeModeHash);
12128
+ messageQueue.setOnDiscard((entries) => {
12129
+ const byReason = /* @__PURE__ */ new Map();
12130
+ for (const entry of entries) {
12131
+ if (!entry.sourceId) continue;
12132
+ const list = byReason.get(entry.reason) ?? [];
12133
+ list.push(entry.sourceId);
12134
+ byReason.set(entry.reason, list);
12135
+ }
12136
+ for (const [reason, keys] of byReason) session.sendQueueCancelReason(keys, reason);
12137
+ });
12046
12138
  session.rpcHandlerManager.registerHandler("cancelQueuedMessage", async (params) => ({
12047
12139
  removed: messageQueue.cancelPending(
12048
12140
  typeof params?.localKey === "string" ? params.localKey : void 0,
@@ -13545,9 +13637,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
13545
13637
  };
13546
13638
  }
13547
13639
 
13548
- 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-BlkIz9BQ.cjs', document.baseURI).href)));
13640
+ 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-DKRU6E-x.cjs', document.baseURI).href)));
13549
13641
  const __dirname$1 = path.dirname(__filename$1);
13550
- const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BlkIz9BQ.cjs', document.baseURI).href)));
13642
+ const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DKRU6E-x.cjs', document.baseURI).href)));
13551
13643
  const PRISMA_QUERY_ENGINE_FILES = {
13552
13644
  "arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
13553
13645
  "x64-darwin": "libquery_engine-darwin.dylib.node",
@@ -15255,10 +15347,10 @@ function isCodexClearText(text) {
15255
15347
  }
15256
15348
  function enqueueCodexUserText(opts) {
15257
15349
  if (isCodexClearText(opts.text)) {
15258
- opts.queue.pushIsolateAndClear(opts.text, opts.mode);
15350
+ opts.queue.pushIsolateAndClear(opts.text, opts.mode, void 0, opts.sourceId);
15259
15351
  return "clear";
15260
15352
  }
15261
- opts.queue.push(opts.text, opts.mode);
15353
+ opts.queue.push(opts.text, opts.mode, void 0, opts.sourceId);
15262
15354
  return "queued";
15263
15355
  }
15264
15356
 
@@ -15443,6 +15535,7 @@ async function runCodex(opts) {
15443
15535
  if (reconnectSessionId) {
15444
15536
  session.suppressNextArchiveSignal();
15445
15537
  if (!reconnectSeeded) session.skipExistingMessages();
15538
+ void session.cancelUndeliveredQueuedInputs();
15446
15539
  session.updateMetadata((meta) => mergeReconnectMetadata(meta, metadata, Date.now()));
15447
15540
  }
15448
15541
  if (response) {
@@ -15465,6 +15558,10 @@ async function runCodex(opts) {
15465
15558
  }
15466
15559
  }
15467
15560
  const messageQueue = new MessageQueue2(hashCodexEnhancedMode);
15561
+ messageQueue.setOnDiscard((entries) => {
15562
+ const keys = entries.map((entry) => entry.sourceId).filter((key) => typeof key === "string");
15563
+ if (keys.length > 0) session.sendQueueCancelReason(keys, entries[0].reason);
15564
+ });
15468
15565
  let currentPermissionMode = initialPermissionMode;
15469
15566
  let currentModel = DEFAULT_CODEX_MODEL;
15470
15567
  let currentEffort = DEFAULT_CODEX_EFFORT;
@@ -15546,7 +15643,8 @@ async function runCodex(opts) {
15546
15643
  const enqueueResult = enqueueCodexUserText({
15547
15644
  text: message.content.text,
15548
15645
  mode: enhancedMode,
15549
- queue: messageQueue
15646
+ queue: messageQueue,
15647
+ sourceId: message.localKey
15550
15648
  });
15551
15649
  if (enqueueResult === "clear") {
15552
15650
  persistence.logger.debug("[Codex] /clear command pushed to isolated queue");
@@ -16171,7 +16269,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16171
16269
  process.exit(0);
16172
16270
  } else if (subcommand === "install-terminal-hooks") {
16173
16271
  try {
16174
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-MWVPJDxV.cjs'); });
16272
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-CGqopr1A.cjs'); });
16175
16273
  const command = parseTerminalHooksArgs(args.slice(1));
16176
16274
  if (command.action === "help") {
16177
16275
  console.log(TERMINAL_HOOKS_HELP);
@@ -16188,7 +16286,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16188
16286
  }
16189
16287
  } else if (subcommand === "spawn") {
16190
16288
  try {
16191
- const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-xPV7-s4S.cjs'); });
16289
+ const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-7U_4QTHw.cjs'); });
16192
16290
  await handleSpawnCommand(args.slice(1));
16193
16291
  } catch (error) {
16194
16292
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -16200,7 +16298,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16200
16298
  return;
16201
16299
  } else if (subcommand === "sessions") {
16202
16300
  try {
16203
- const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-BNyEJ2_6.cjs'); });
16301
+ const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-CTuUV0TW.cjs'); });
16204
16302
  await handleSessionsCommand(args.slice(1));
16205
16303
  } catch (error) {
16206
16304
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -16212,7 +16310,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16212
16310
  return;
16213
16311
  } else if (subcommand === "send") {
16214
16312
  try {
16215
- const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-B9fh96vR.cjs'); });
16313
+ const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-B0Wojz18.cjs'); });
16216
16314
  await handleSendCommand(args.slice(1));
16217
16315
  } catch (error) {
16218
16316
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -16318,9 +16416,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16318
16416
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
16319
16417
  const projectId = args[3];
16320
16418
  try {
16321
- const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-CEbOao_0.cjs'); });
16322
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-7ZSxm6Pi.cjs'); }).then(function (n) { return n.persistence; });
16323
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-7ZSxm6Pi.cjs'); }).then(function (n) { return n.api; });
16419
+ const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-rQdv_Yr0.cjs'); });
16420
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-Jag0GwhO.cjs'); }).then(function (n) { return n.persistence; });
16421
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-Jag0GwhO.cjs'); }).then(function (n) { return n.api; });
16324
16422
  let userEmail = void 0;
16325
16423
  try {
16326
16424
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -16351,7 +16449,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16351
16449
  }
16352
16450
  if (geminiSubcommand === "project" && args[2] === "get") {
16353
16451
  try {
16354
- const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-CEbOao_0.cjs'); });
16452
+ const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-rQdv_Yr0.cjs'); });
16355
16453
  const config = readGeminiLocalConfig();
16356
16454
  if (config.googleCloudProject) {
16357
16455
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -16391,7 +16489,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16391
16489
  process.exit(0);
16392
16490
  }
16393
16491
  try {
16394
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BRUmjZgV.cjs'); });
16492
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-DYawZQTu.cjs'); });
16395
16493
  let startedBy = void 0;
16396
16494
  for (let i = 1; i < args.length; i++) {
16397
16495
  if (args[i] === "--started-by") {
@@ -16421,7 +16519,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16421
16519
  }
16422
16520
  };
16423
16521
  try {
16424
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-HKcuQ_fQ.cjs'); });
16522
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-uPpFZhhr.cjs'); });
16425
16523
  const parsed = parsePiRunnerArgs(args.slice(1));
16426
16524
  const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
16427
16525
  const { credentials } = await authAndSetupMachineIfNeeded();
@@ -16448,7 +16546,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16448
16546
  return;
16449
16547
  } else if (subcommand === "acp") {
16450
16548
  try {
16451
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-HKcuQ_fQ.cjs'); });
16549
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-uPpFZhhr.cjs'); });
16452
16550
  let startedBy = void 0;
16453
16551
  let verbose = false;
16454
16552
  const acpArgs = [];
@@ -16488,7 +16586,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16488
16586
  return;
16489
16587
  } else if (subcommand === "openclaw") {
16490
16588
  try {
16491
- const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-o1ImBlcJ.cjs'); });
16589
+ const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-C2XjFP2m.cjs'); });
16492
16590
  let startedBy = void 0;
16493
16591
  let verbose = false;
16494
16592
  let gatewayUrl;
@@ -16539,7 +16637,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16539
16637
  return;
16540
16638
  } else if (subcommand === "mcp" && args.length === 1) {
16541
16639
  try {
16542
- const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-DBKk5L6_.cjs'); });
16640
+ const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-FlbfMw6_.cjs'); });
16543
16641
  await handleMcpCommand();
16544
16642
  } catch (error) {
16545
16643
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -16913,6 +17011,7 @@ exports.MAX_READ_LIMIT = MAX_READ_LIMIT;
16913
17011
  exports.MessageBuffer = MessageBuffer;
16914
17012
  exports.MessageQueue2 = MessageQueue2;
16915
17013
  exports.SPAWN_AGENTS = SPAWN_AGENTS;
17014
+ exports.StreamRelay = StreamRelay;
16916
17015
  exports.TitleGenerator = TitleGenerator;
16917
17016
  exports.archiveSession = archiveSession;
16918
17017
  exports.checkIfDaemonRunningAndCleanupStaleState = checkIfDaemonRunningAndCleanupStaleState;
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var AcpBackend = require('./AcpBackend-tou8FQXI.cjs');
4
- var persistence = require('./types-7ZSxm6Pi.cjs');
5
- var AcpSessionManager = require('./AcpSessionManager-fF_HFB98.cjs');
3
+ var AcpBackend = require('./AcpBackend-YPVwACkW.cjs');
4
+ var persistence = require('./types-Jag0GwhO.cjs');
5
+ var AcpSessionManager = require('./AcpSessionManager-6rypahwH.cjs');
6
6
  var node_crypto = require('node:crypto');
7
7
  var path = require('node:path');
8
- var index = require('./index-BlkIz9BQ.cjs');
8
+ var index = require('./index-DKRU6E-x.cjs');
9
9
  require('node:child_process');
10
10
  require('@agentclientprotocol/sdk');
11
11
  require('axios');
@@ -637,7 +637,11 @@ async function runAcp(opts) {
637
637
  }
638
638
  permissionHandler = new GenericAcpPermissionHandler(session, opts.agentName);
639
639
  permissionHandler.reset("Previous CLI process exited before responding");
640
- const sessionManager = new AcpSessionManager.AcpSessionManager();
640
+ const streamingEnabled = process.env.HAPPY_SESSION_STREAM_DISABLED !== "1";
641
+ const streamRelay = new index.StreamRelay({
642
+ send: (frame) => session.sendStreamFrame(frame)
643
+ });
644
+ const sessionManager = new AcpSessionManager.AcpSessionManager(streamingEnabled ? { stream: streamRelay } : {});
641
645
  const messageQueue = new index.MessageQueue2((mode) => index.hashObject(mode));
642
646
  let currentPermissionMode;
643
647
  let currentModel;
@@ -691,6 +695,13 @@ async function runAcp(opts) {
691
695
  verbose
692
696
  });
693
697
  let thinking = false;
698
+ const setThinking = (next) => {
699
+ if (thinking === next) {
700
+ return;
701
+ }
702
+ thinking = next;
703
+ session.keepAlive(thinking, "remote");
704
+ };
694
705
  let acpSessionId = null;
695
706
  let shouldExit = false;
696
707
  let abortController = new AbortController();
@@ -935,11 +946,6 @@ async function runAcp(opts) {
935
946
  const suffix = msg.detail ? `: ${msg.detail}` : "";
936
947
  const statusLine = `Status: ${msg.status}${suffix}`;
937
948
  logAcp("muted", statusLine);
938
- const nextThinking = msg.status === "running";
939
- if (thinking !== nextThinking) {
940
- thinking = nextThinking;
941
- session.keepAlive(thinking, "remote");
942
- }
943
949
  if (msg.status === "idle") {
944
950
  clearPendingTurn();
945
951
  }
@@ -1052,6 +1058,7 @@ async function runAcp(opts) {
1052
1058
  }
1053
1059
  logAcp("incoming", `Incoming prompt: ${formatUnknownForConsole(batch.message, ACP_EVENT_PREVIEW_CHARS)}`);
1054
1060
  sendEnvelopes(sessionManager.startTurn());
1061
+ setThinking(true);
1055
1062
  const turnEnded = waitForTurnEnd();
1056
1063
  try {
1057
1064
  if (typeof batch.mode.permissionMode === "string" && batch.mode.permissionMode.length > 0) {
@@ -1063,12 +1070,16 @@ async function runAcp(opts) {
1063
1070
  await backend.sendPrompt(acpSessionId, batch.message);
1064
1071
  await turnEnded;
1065
1072
  sendEnvelopes(sessionManager.endTurn("completed"));
1073
+ streamRelay.endTurn();
1074
+ setThinking(false);
1066
1075
  session.sendSessionEvent({ type: "ready" });
1067
1076
  if (verbose) {
1068
1077
  logAcp("muted", `Outgoing prompt completion from ${opts.agentName}`);
1069
1078
  }
1070
1079
  } catch (error) {
1071
1080
  sendEnvelopes(sessionManager.endTurn("failed"));
1081
+ streamRelay.endTurn();
1082
+ setThinking(false);
1072
1083
  session.sendSessionEvent({ type: "ready" });
1073
1084
  logAcp("error", `Prompt error from ${opts.agentName}: ${error instanceof Error ? error.message : String(error)}`);
1074
1085
  clearPendingTurn(error instanceof Error ? error : new Error(String(error)));
@@ -1076,7 +1087,10 @@ async function runAcp(opts) {
1076
1087
  }
1077
1088
  }
1078
1089
  } finally {
1090
+ setThinking(false);
1079
1091
  clearInterval(keepAliveInterval);
1092
+ streamRelay.endTurn();
1093
+ streamRelay.dispose();
1080
1094
  reconnectionHandle?.cancel();
1081
1095
  clearPendingTurn(new Error("ACP runner shutting down"));
1082
1096
  try {
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-BlkIz9BQ.cjs');
5
- require('./types-7ZSxm6Pi.cjs');
4
+ require('./index-DKRU6E-x.cjs');
5
+ require('./types-Jag0GwhO.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-CUJ6faw1.mjs';
3
- import './types-Di0o0BdV.mjs';
2
+ import './index-BTnlYGaP.mjs';
3
+ import './types-q7wtjfxb.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-7ZSxm6Pi.cjs');
9
- var index = require('./index-BlkIz9BQ.cjs');
8
+ var persistence = require('./types-Jag0GwhO.cjs');
9
+ var index = require('./index-DKRU6E-x.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-Di0o0BdV.mjs';
7
- import { t as tmuxSupportsSessionEnv } from './index-CUJ6faw1.mjs';
6
+ import { p as projectPath } from './types-q7wtjfxb.mjs';
7
+ import { t as tmuxSupportsSessionEnv } from './index-BTnlYGaP.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-7ZSxm6Pi.cjs');
3
+ var persistence = require('./types-Jag0GwhO.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('node:util');
package/dist/lib.d.cts CHANGED
@@ -137,6 +137,10 @@ declare const sessionEnvelopeSchema: z.ZodObject<{
137
137
  totalTokens: z.ZodOptional<z.ZodNumber>;
138
138
  durationMs: z.ZodOptional<z.ZodNumber>;
139
139
  summary: z.ZodOptional<z.ZodString>;
140
+ }, z.core.$strip>, z.ZodObject<{
141
+ t: z.ZodLiteral<"queue-cancel">;
142
+ targetLocalKeys: z.ZodArray<z.ZodString>;
143
+ reason: z.ZodOptional<z.ZodString>;
140
144
  }, z.core.$strip>], "t">;
141
145
  }, z.core.$strip>;
142
146
  type SessionEnvelope = z.infer<typeof sessionEnvelopeSchema>;
@@ -922,8 +926,24 @@ declare class ApiSessionClient extends EventEmitter {
922
926
  private connectSessionRelay;
923
927
  private pushCommittedMessagesToRelay;
924
928
  private enqueueMessage;
929
+ /** B-332: emit a queue-cancel tombstone, mirroring the web's own signal. */
930
+ sendQueueCancelReason(localKeys: string[], reason: 'cleared' | 'aborted' | 'restarted'): void;
925
931
  /**
926
- * Send message to session
932
+ * B-332 site ③: find queued user input this wrapper destroyed (it was still
933
+ * in the previous wrapper's in-memory queue when it died) and tell the web.
934
+ *
935
+ * Walks NEWEST → OLDEST via `before_seq`, decrypting each page, and stops at
936
+ * the first turn-end. The runner calls this on EVERY reconnect (runClaude /
937
+ * runCodex), seeded or not: a cursor seeded at the server's latest seq skips
938
+ * the undelivered tail just as thoroughly as skipExistingMessages does —
939
+ * and the daemon's resume/restart always seeds, so gating on the skip path
940
+ * would miss the common case. Best-effort: a failed scan must not take a
941
+ * session down. Needs no socket; POSTs through the same session-message
942
+ * channel so the web receives it identically to a cancel-button tombstone.
943
+ */
944
+ cancelUndeliveredQueuedInputs(): Promise<void>;
945
+ /**
946
+ * Send a message to session
927
947
  * @param body - Message body (can be MessageContent or raw content for agent messages)
928
948
  */
929
949
  sendClaudeSessionMessage(body: RawJSONLines, opts?: {
@@ -1296,6 +1316,10 @@ declare class ApiMachineClient {
1296
1316
  private keepAliveInterval;
1297
1317
  private lastKnownCLIAvailability;
1298
1318
  private lastKnownResumeSupport;
1319
+ /** Wall-clock of the last CLI availability probe. Initialised as "already
1320
+ * stale" so the FIRST keep-alive tick always probes and populates the
1321
+ * machine metadata that a connecting/reconnecting web client reads. */
1322
+ private lastCliProbeAt;
1299
1323
  private cliUpdateState;
1300
1324
  private cliUpdatePushChain;
1301
1325
  private claudeAuthState;