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
@@ -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.120";
32
+ var version = "0.2.122";
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.120",
146
- "very-happy-tools-x64-darwin": "0.2.120",
147
- "very-happy-tools-arm64-linux": "0.2.120",
148
- "very-happy-tools-x64-linux": "0.2.120",
149
- "very-happy-tools-arm64-win32": "0.2.120",
150
- "very-happy-tools-x64-win32": "0.2.120"
145
+ "very-happy-tools-arm64-darwin": "0.2.122",
146
+ "very-happy-tools-x64-darwin": "0.2.122",
147
+ "very-happy-tools-arm64-linux": "0.2.122",
148
+ "very-happy-tools-x64-linux": "0.2.122",
149
+ "very-happy-tools-arm64-win32": "0.2.122",
150
+ "very-happy-tools-x64-win32": "0.2.122"
151
151
  };
152
152
  var devDependencies = {
153
153
  "@slopus/happy-wire": "workspace:*",
@@ -720,6 +720,11 @@ const sessionProgressEventSchema = z.object({
720
720
  durationMs: z.number().optional(),
721
721
  summary: z.string().optional()
722
722
  });
723
+ const sessionQueueCancelEventSchema = z.object({
724
+ t: z.literal("queue-cancel"),
725
+ targetLocalKeys: z.array(z.string().min(1)).min(1),
726
+ reason: z.string().min(1).optional()
727
+ });
723
728
  const sessionEventSchema = z.discriminatedUnion("t", [
724
729
  sessionTextEventSchema,
725
730
  sessionServiceMessageEventSchema,
@@ -730,7 +735,8 @@ const sessionEventSchema = z.discriminatedUnion("t", [
730
735
  sessionStartEventSchema,
731
736
  sessionTurnEndEventSchema,
732
737
  sessionStopEventSchema,
733
- sessionProgressEventSchema
738
+ sessionProgressEventSchema,
739
+ sessionQueueCancelEventSchema
734
740
  ]);
735
741
  const sessionEnvelopeSchema = z.object({
736
742
  id: z.string(),
@@ -1004,6 +1010,20 @@ const ReleaseDrainNoticeSchema = z$1.object({
1004
1010
  deadline: z$1.number().int().positive(),
1005
1011
  mode: z$1.literal("make-before-break")
1006
1012
  });
1013
+ const ConnectionDiagnosticEventSchema = z$1.object({
1014
+ attemptId: z$1.string().uuid(),
1015
+ machineId: z$1.string().min(1).max(256).regex(/^[A-Za-z0-9_-]+$/).optional(),
1016
+ at: z$1.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1017
+ stage: z$1.enum(["control", "relay_discovery", "relay_connect", "relay_probe", "machine_rpc", "terminal_open"]),
1018
+ outcome: z$1.enum(["started", "success", "timeout", "error", "offline", "cancelled", "fallback"]),
1019
+ durationMs: z$1.number().int().min(0).max(3e5),
1020
+ deviceClass: z$1.enum(["mobile", "desktop", "unknown"]),
1021
+ visibility: z$1.enum(["visible", "hidden"]),
1022
+ client: z$1.string().regex(/^web\/(?:[a-f0-9]{7,40}|unknown)$/)
1023
+ }).strict();
1024
+ z$1.object({
1025
+ events: z$1.array(ConnectionDiagnosticEventSchema).min(1).max(32)
1026
+ }).strict();
1007
1027
 
1008
1028
  z$1.object({
1009
1029
  host: z$1.string(),
@@ -3113,6 +3133,48 @@ class InvalidateSync {
3113
3133
  };
3114
3134
  }
3115
3135
 
3136
+ function sessionEnvelopeOf(body) {
3137
+ if (!body || typeof body !== "object") return null;
3138
+ const record = body;
3139
+ if (record.role !== "session" || !record.content || typeof record.content !== "object") return null;
3140
+ const content = record.content;
3141
+ if (content.type === "session" && content.data && typeof content.data === "object") {
3142
+ return content.data;
3143
+ }
3144
+ if (content.ev !== void 0) return content;
3145
+ return null;
3146
+ }
3147
+ function isQueuedUserText(body) {
3148
+ if (!body || typeof body !== "object") return false;
3149
+ const record = body;
3150
+ return record.role === "user" && record.content?.type === "text" && typeof record.meta?.queuedAt === "number";
3151
+ }
3152
+ function scanUndeliveredQueuedInputs(records, prior) {
3153
+ const canceled = prior?.canceled ?? /* @__PURE__ */ new Set();
3154
+ const undelivered = [];
3155
+ let reachedBoundary = false;
3156
+ for (const record of records) {
3157
+ const envelope = sessionEnvelopeOf(record.body);
3158
+ if (envelope) {
3159
+ const t = envelope.ev?.t;
3160
+ if (t === "turn-end") {
3161
+ reachedBoundary = true;
3162
+ break;
3163
+ }
3164
+ if (t === "queue-cancel" && Array.isArray(envelope.ev?.targetLocalKeys)) {
3165
+ for (const key of envelope.ev.targetLocalKeys) {
3166
+ if (typeof key === "string") canceled.add(key);
3167
+ }
3168
+ }
3169
+ continue;
3170
+ }
3171
+ if (isQueuedUserText(record.body) && record.localId && !canceled.has(record.localId)) {
3172
+ undelivered.push(record.localId);
3173
+ }
3174
+ }
3175
+ return { undeliveredLocalKeys: undelivered, reachedBoundary, canceled };
3176
+ }
3177
+
3116
3178
  function record(value) {
3117
3179
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
3118
3180
  }
@@ -3756,8 +3818,75 @@ class ApiSessionClient extends EventEmitter {
3756
3818
  this.sendSync.invalidate();
3757
3819
  }
3758
3820
  }
3821
+ /** B-332: emit a queue-cancel tombstone, mirroring the web's own signal. */
3822
+ sendQueueCancelReason(localKeys, reason) {
3823
+ if (localKeys.length === 0) return;
3824
+ const envelope = createEnvelope("user", { t: "queue-cancel", targetLocalKeys: localKeys, reason });
3825
+ this.sendSessionProtocolMessage(envelope);
3826
+ }
3759
3827
  /**
3760
- * Send message to session
3828
+ * B-332 site ③: find queued user input this wrapper destroyed (it was still
3829
+ * in the previous wrapper's in-memory queue when it died) and tell the web.
3830
+ *
3831
+ * Walks NEWEST → OLDEST via `before_seq`, decrypting each page, and stops at
3832
+ * the first turn-end. The runner calls this on EVERY reconnect (runClaude /
3833
+ * runCodex), seeded or not: a cursor seeded at the server's latest seq skips
3834
+ * the undelivered tail just as thoroughly as skipExistingMessages does —
3835
+ * and the daemon's resume/restart always seeds, so gating on the skip path
3836
+ * would miss the common case. Best-effort: a failed scan must not take a
3837
+ * session down. Needs no socket; POSTs through the same session-message
3838
+ * channel so the web receives it identically to a cancel-button tombstone.
3839
+ */
3840
+ async cancelUndeliveredQueuedInputs() {
3841
+ const MAX_SCAN_PAGES = 10;
3842
+ const canceled = /* @__PURE__ */ new Set();
3843
+ const undelivered = [];
3844
+ let beforeSeq = 2147483647;
3845
+ let reachedBoundary = false;
3846
+ let pages = 0;
3847
+ try {
3848
+ while (!reachedBoundary && pages < MAX_SCAN_PAGES) {
3849
+ pages += 1;
3850
+ const response = await axios.get(
3851
+ `${configuration.serverUrl}/v3/sessions/${encodeURIComponent(this.sessionId)}/messages`,
3852
+ {
3853
+ params: { before_seq: beforeSeq, limit: 100 },
3854
+ headers: this.authHeaders(),
3855
+ timeout: 6e4
3856
+ }
3857
+ );
3858
+ const messages = Array.isArray(response.data.messages) ? response.data.messages : [];
3859
+ if (messages.length === 0) break;
3860
+ const records = messages.map((message) => {
3861
+ let body = null;
3862
+ try {
3863
+ body = message.content?.t === "encrypted" ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(message.content.c)) : null;
3864
+ } catch (error) {
3865
+ logger.debug("[API] Failed to decrypt during undelivered scan:", error);
3866
+ }
3867
+ return { seq: message.seq, localId: message.localId, body };
3868
+ });
3869
+ const scan = scanUndeliveredQueuedInputs(records, { canceled });
3870
+ for (const key of scan.canceled) canceled.add(key);
3871
+ undelivered.push(...scan.undeliveredLocalKeys);
3872
+ reachedBoundary = scan.reachedBoundary;
3873
+ const oldest = records.at(-1)?.seq;
3874
+ if (oldest === void 0 || messages.length < 100) break;
3875
+ beforeSeq = oldest;
3876
+ }
3877
+ } catch (error) {
3878
+ logger.debug("[API] cancelUndeliveredQueuedInputs scan failed:", error);
3879
+ return;
3880
+ }
3881
+ if (!reachedBoundary) {
3882
+ logger.debug("[API] cancelUndeliveredQueuedInputs found no turn boundary; leaving messages as-is");
3883
+ return;
3884
+ }
3885
+ undelivered.reverse();
3886
+ this.sendQueueCancelReason(undelivered, "restarted");
3887
+ }
3888
+ /**
3889
+ * Send a message to session
3761
3890
  * @param body - Message body (can be MessageContent or raw content for agent messages)
3762
3891
  */
3763
3892
  sendClaudeSessionMessage(body, opts) {
@@ -14369,28 +14498,50 @@ function selectStableRelay(candidates, probes, connectedRelayId, tracker = null)
14369
14498
  tracker: { challengerRelayId: fastest.id, consecutiveWins }
14370
14499
  };
14371
14500
  }
14501
+ const RELAY_REFRESH_TIMEOUT_MS = 8e3;
14502
+ async function withinDeadline(timeoutMs, operation, parent) {
14503
+ const controller = new AbortController();
14504
+ let timer;
14505
+ let cancel;
14506
+ const deadline = new Promise((_, reject) => {
14507
+ cancel = () => {
14508
+ reject(new Error("relay request deadline exceeded"));
14509
+ controller.abort();
14510
+ };
14511
+ timer = setTimeout(cancel, timeoutMs);
14512
+ parent?.addEventListener("abort", cancel, { once: true });
14513
+ if (parent?.aborted) cancel();
14514
+ });
14515
+ try {
14516
+ return await Promise.race([Promise.resolve().then(() => {
14517
+ controller.signal.throwIfAborted();
14518
+ return operation(controller.signal);
14519
+ }), deadline]);
14520
+ } finally {
14521
+ clearTimeout(timer);
14522
+ parent?.removeEventListener("abort", cancel);
14523
+ }
14524
+ }
14372
14525
  async function probeRelayCandidates(candidates, options = {}) {
14373
14526
  const timeoutMs = options.timeoutMs ?? 2e3;
14374
14527
  const fetchImpl = options.fetchImpl ?? fetch;
14375
14528
  const now = options.now ?? (() => performance.now());
14376
14529
  const measured = await Promise.all(candidates.map(async (candidate) => {
14377
- const controller = new AbortController();
14378
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
14379
14530
  const startedAt = now();
14380
14531
  try {
14381
- const response = await fetchImpl(`${candidate.url}/health`, {
14382
- method: "GET",
14383
- cache: "no-store",
14384
- signal: controller.signal
14385
- });
14386
- if (!response.ok) return null;
14387
- const body = await response.json();
14388
- if (body.ok !== true || body.relayId !== candidate.id) return null;
14389
- return { relayId: candidate.id, rttMs: Math.max(0, now() - startedAt) };
14532
+ return await withinDeadline(timeoutMs, async (signal) => {
14533
+ const response = await fetchImpl(`${candidate.url}/health`, {
14534
+ method: "GET",
14535
+ cache: "no-store",
14536
+ signal
14537
+ });
14538
+ if (!response.ok) return null;
14539
+ const body = await response.json();
14540
+ if (body.ok !== true || body.relayId !== candidate.id) return null;
14541
+ return { relayId: candidate.id, rttMs: Math.max(0, now() - startedAt) };
14542
+ }, options.signal);
14390
14543
  } catch {
14391
14544
  return null;
14392
- } finally {
14393
- clearTimeout(timeout);
14394
14545
  }
14395
14546
  }));
14396
14547
  return measured.filter((probe) => probe !== null);
@@ -14398,25 +14549,32 @@ async function probeRelayCandidates(candidates, options = {}) {
14398
14549
  async function discoverAndClaimRelay(input) {
14399
14550
  const fetchImpl = input.fetchImpl ?? fetch;
14400
14551
  try {
14401
- const discoveryResponse = await fetchImpl(`${input.controlUrl}/v1/relays`, {
14402
- headers: { Authorization: `Bearer ${input.token}` },
14403
- cache: "no-store"
14404
- });
14405
- if (!discoveryResponse.ok) return null;
14406
- const discovery = RelayCandidatesResponseSchema.parse(await discoveryResponse.json());
14407
- if (!discovery.enabled || discovery.candidates.length === 0) return null;
14408
- const probes = await probeRelayCandidates(discovery.candidates, { fetchImpl });
14409
- const decision = selectStableRelay(discovery.candidates, probes, input.connectedRelayId, input.switchTracker);
14410
- const selected = decision.candidate;
14411
- if (!selected) return null;
14412
- const claimResponse = await fetchImpl(`${input.controlUrl}/v1/relays/machines/${encodeURIComponent(input.machineId)}/claim`, {
14413
- method: "POST",
14414
- headers: { Authorization: `Bearer ${input.token}`, "Content-Type": "application/json" },
14415
- body: JSON.stringify({ relayId: selected.id, probes })
14552
+ return await withinDeadline(RELAY_REFRESH_TIMEOUT_MS, async (signal) => {
14553
+ const discoveryResponse = await fetchImpl(`${input.controlUrl}/v1/relays`, {
14554
+ headers: { Authorization: `Bearer ${input.token}` },
14555
+ cache: "no-store",
14556
+ signal
14557
+ });
14558
+ if (!discoveryResponse.ok) return null;
14559
+ const discovery = RelayCandidatesResponseSchema.parse(await discoveryResponse.json());
14560
+ signal.throwIfAborted();
14561
+ if (!discovery.enabled || discovery.candidates.length === 0) return null;
14562
+ const probes = await probeRelayCandidates(discovery.candidates, { fetchImpl, signal });
14563
+ signal.throwIfAborted();
14564
+ const decision = selectStableRelay(discovery.candidates, probes, input.connectedRelayId, input.switchTracker);
14565
+ const selected = decision.candidate;
14566
+ if (!selected) return null;
14567
+ const claimResponse = await fetchImpl(`${input.controlUrl}/v1/relays/machines/${encodeURIComponent(input.machineId)}/claim`, {
14568
+ method: "POST",
14569
+ signal,
14570
+ headers: { Authorization: `Bearer ${input.token}`, "Content-Type": "application/json" },
14571
+ body: JSON.stringify({ relayId: selected.id, probes })
14572
+ });
14573
+ if (!claimResponse.ok) return null;
14574
+ const claimed = RelayAssignmentResponseSchema.parse(await claimResponse.json());
14575
+ signal.throwIfAborted();
14576
+ return claimed.assignment ? { assignment: claimed.assignment, probes, switchTracker: decision.tracker } : null;
14416
14577
  });
14417
- if (!claimResponse.ok) return null;
14418
- const claimed = RelayAssignmentResponseSchema.parse(await claimResponse.json());
14419
- return claimed.assignment ? { assignment: claimed.assignment, probes, switchTracker: decision.tracker } : null;
14420
14578
  } catch {
14421
14579
  return null;
14422
14580
  }
@@ -14530,6 +14688,7 @@ async function withCodexAppServerClient(handler) {
14530
14688
  await client.disconnect();
14531
14689
  }
14532
14690
  }
14691
+ const CLI_AVAILABILITY_RECHECK_MS = 5 * 60 * 1e3;
14533
14692
  class ApiMachineClient {
14534
14693
  constructor(token, machine) {
14535
14694
  this.token = token;
@@ -14553,6 +14712,10 @@ class ApiMachineClient {
14553
14712
  keepAliveInterval = null;
14554
14713
  lastKnownCLIAvailability = null;
14555
14714
  lastKnownResumeSupport = null;
14715
+ /** Wall-clock of the last CLI availability probe. Initialised as "already
14716
+ * stale" so the FIRST keep-alive tick always probes and populates the
14717
+ * machine metadata that a connecting/reconnecting web client reads. */
14718
+ lastCliProbeAt = Date.now() - CLI_AVAILABILITY_RECHECK_MS;
14556
14719
  cliUpdateState = null;
14557
14720
  cliUpdatePushChain = Promise.resolve();
14558
14721
  claudeAuthState = null;
@@ -15420,6 +15583,10 @@ class ApiMachineClient {
15420
15583
  }
15421
15584
  this.socket.emit("machine-alive", payload);
15422
15585
  void this.refreshRelayConnection();
15586
+ if (Date.now() - this.lastCliProbeAt < CLI_AVAILABILITY_RECHECK_MS) {
15587
+ return;
15588
+ }
15589
+ this.lastCliProbeAt = Date.now();
15423
15590
  const newAvailability = detectCLIAvailability();
15424
15591
  const prev = this.lastKnownCLIAvailability;
15425
15592
  const newResumeSupport = detectResumeSupport();
@@ -16647,4 +16814,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
16647
16814
  }).passthrough()
16648
16815
  ]);
16649
16816
 
16650
- export { decideMirrorBinding as $, ApiClient as A, readCredentials as B, credentialRelayProblem as C, deriveLocalCliUpdateSummary as D, readSettingsOutcome as E, updateSettings as F, encodeBase64Url as G, decodeBase64 as H, InvalidateSync as I, writeCredentialsLegacy as J, writeCredentialsDataKey as K, readCredentialsForConfiguredRelay as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, encrypt as N, isClaudeSessionId as O, getLocalHappyAgentCredentialPath as P, readLocalHappyAgentCredentials as Q, RawJSONLinesSchema as R, STREAM_DELTA_MAX_CHARS as S, decryptWithDataKey as T, decryptLegacy as U, compareExactVersions as V, extractCompleteLines as W, decideBackfill as X, parseTerminalHookPayload as Y, tmuxArgs as Z, scrubTmuxClientEnv as _, ApiSessionClient as a, MIRROR_BACKFILL_LINES_DEFAULT as a0, persistSession as a1, mirrorLineKey as a2, mirrorLocalId as a3, detectCLIAvailability as a4, detectResumeSupport as a5, acquireDaemonLock as a6, summarizeSpawnSessionForLog as a7, deletePersistedSessions as a8, shellescape as a9, decrypt as aa, writeDaemonState as ab, writeSettings as ac, fetchCliUpdateState as ad, resolveCliUpdateCheckInterval as ae, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as af, releaseDaemonLock as ag, listVhTerminals as ah, isValidTerminalId as ai, readVhTerminal as aj, sendToVhTerminal as ak, TITLE_PROMPT_PREFIX as al, BOARD_ANALYZER_PROMPT_PREFIX as am, startOfflineReconnection as an, clearCredentials as ao, clearMachineId as ap, SandboxConfigSchema as aq, CodexAppServerClient as ar, getLatestDaemonLog as as, persistence as at, api as au, createEnvelope as b, configuration as c, connectionState as d, readSettings as e, encodeBase64 as f, contentLogMetadata as g, errorLogMetadata as h, isValidSessionId as i, packageJson as j, delay as k, logger as l, ensurePrivateDirectorySync as m, hardenPrivateFileSync as n, readDaemonState as o, projectPath as p, clearDaemonState as q, readPersistedSessions as r, getProjectPath as s, initializeSandbox as t, wrapCommand as u, AsyncLock as v, writePrivateFileSync as w, ensurePrivateDirectory as x, hardenPrivateFile as y, commandOnPath as z };
16817
+ export { scrubTmuxClientEnv as $, ApiClient as A, commandOnPath as B, readCredentials as C, credentialRelayProblem as D, deriveLocalCliUpdateSummary as E, readSettingsOutcome as F, updateSettings as G, encodeBase64Url as H, InvalidateSync as I, decodeBase64 as J, writeCredentialsLegacy as K, writeCredentialsDataKey as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, readCredentialsForConfiguredRelay as N, encrypt as O, isClaudeSessionId as P, getLocalHappyAgentCredentialPath as Q, RawJSONLinesSchema as R, STREAM_DELTA_MAX_CHARS as S, readLocalHappyAgentCredentials as T, decryptWithDataKey as U, decryptLegacy as V, compareExactVersions as W, extractCompleteLines as X, decideBackfill as Y, parseTerminalHookPayload as Z, tmuxArgs as _, ApiSessionClient as a, decideMirrorBinding as a0, MIRROR_BACKFILL_LINES_DEFAULT as a1, persistSession as a2, mirrorLineKey as a3, mirrorLocalId as a4, detectCLIAvailability as a5, detectResumeSupport as a6, acquireDaemonLock as a7, summarizeSpawnSessionForLog as a8, deletePersistedSessions as a9, shellescape as aa, decrypt as ab, writeDaemonState as ac, writeSettings as ad, fetchCliUpdateState as ae, resolveCliUpdateCheckInterval as af, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as ag, releaseDaemonLock as ah, listVhTerminals as ai, isValidTerminalId as aj, readVhTerminal as ak, sendToVhTerminal as al, TITLE_PROMPT_PREFIX as am, BOARD_ANALYZER_PROMPT_PREFIX as an, startOfflineReconnection as ao, clearCredentials as ap, clearMachineId as aq, SandboxConfigSchema as ar, CodexAppServerClient as as, getLatestDaemonLog as at, persistence as au, api as av, createEnvelope as b, configuration as c, connectionState as d, readSettings as e, encodeBase64 as f, contentLogMetadata as g, errorLogMetadata as h, isValidSessionId as i, packageJson as j, delay as k, logger as l, ensurePrivateDirectorySync as m, hardenPrivateFileSync as n, readDaemonState as o, projectPath as p, clearDaemonState as q, readPersistedSessions as r, streamKeyOf as s, getProjectPath as t, initializeSandbox as u, wrapCommand as v, writePrivateFileSync as w, AsyncLock as x, ensurePrivateDirectory as y, hardenPrivateFile as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "very-happy-cli",
3
- "version": "0.2.120",
3
+ "version": "0.2.122",
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.120",
117
- "very-happy-tools-x64-darwin": "0.2.120",
118
- "very-happy-tools-arm64-linux": "0.2.120",
119
- "very-happy-tools-x64-linux": "0.2.120",
120
- "very-happy-tools-arm64-win32": "0.2.120",
121
- "very-happy-tools-x64-win32": "0.2.120"
116
+ "very-happy-tools-arm64-darwin": "0.2.122",
117
+ "very-happy-tools-x64-darwin": "0.2.122",
118
+ "very-happy-tools-arm64-linux": "0.2.122",
119
+ "very-happy-tools-x64-linux": "0.2.122",
120
+ "very-happy-tools-arm64-win32": "0.2.122",
121
+ "very-happy-tools-x64-win32": "0.2.122"
122
122
  },
123
123
  "devDependencies": {
124
124
  "@slopus/happy-wire": "workspace:*",