very-happy-cli 0.2.111 → 0.2.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AcpBackend-B_olk79F.cjs → AcpBackend-B3x-gQWP.cjs} +1 -1
- package/dist/{AcpBackend-CeXVb_s_.mjs → AcpBackend-DDEdYVW2.mjs} +1 -1
- package/dist/{AcpSessionManager-vqdqfD1l.mjs → AcpSessionManager-BORAhQ1r.mjs} +1 -1
- package/dist/{AcpSessionManager-uXwWO2Tn.cjs → AcpSessionManager-DGPLD-go.cjs} +1 -1
- package/dist/{config-vGkcq9nM.mjs → config-B_L5vXXu.mjs} +2 -2
- package/dist/{config-BR3tkFL_.cjs → config-KX6e7GEu.cjs} +2 -2
- package/dist/{index-CtBP0Qvc.cjs → index-B7-t5Kwz.cjs} +4 -4
- package/dist/{index-BOoGJGQc.cjs → index-BnRQP3PL.cjs} +240 -19
- package/dist/{index-SjthsMid.cjs → index-CTd0skWH.cjs} +2 -2
- package/dist/{index-JAhGeW4_.mjs → index-Cu5FdgTq.mjs} +5 -5
- package/dist/{index-Bn-xsguz.mjs → index-inkhalP5.mjs} +236 -15
- package/dist/{index-C-RLk8-e.mjs → index-lQzCAx9I.mjs} +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-FbKaK149.cjs → installTerminalHooks-BVk-r0yD.cjs} +2 -2
- package/dist/{installTerminalHooks-ADNcNdnB.mjs → installTerminalHooks-CQiW7Jn9.mjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +44 -0
- package/dist/lib.d.mts +44 -0
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-DPp-bYNE.cjs → mcp-D0DIU8Q2.cjs} +2 -2
- package/dist/{mcp-DHPm_gvL.mjs → mcp-DD-0VkiA.mjs} +2 -2
- package/dist/{runGemini-CWWyjQMz.mjs → runGemini-DHyBDo5P.mjs} +4 -4
- package/dist/{runGemini-D5ySpYIZ.cjs → runGemini-Dq1d8Ccb.cjs} +4 -4
- package/dist/{runOpenClaw-Bwrb1LXP.cjs → runOpenClaw-BHXnUF_m.cjs} +3 -3
- package/dist/{runOpenClaw-Bv4rUTyJ.mjs → runOpenClaw-DX-tgQ2V.mjs} +3 -3
- package/dist/{send-BlkxFZu4.mjs → send-0TYDXiGx.mjs} +2 -2
- package/dist/{send-DBfSNILO.cjs → send-By6zEUWo.cjs} +2 -2
- package/dist/{sessions-CVuEsdRl.cjs → sessions-DTBRcBRk.cjs} +2 -2
- package/dist/{sessions-1fW8soBM.mjs → sessions-TM8VaCMY.mjs} +2 -2
- package/dist/{spawn-D_ZexrY9.cjs → spawn-CweTEYze.cjs} +2 -2
- package/dist/{spawn-BorKN3W2.mjs → spawn-D0oTo5BT.mjs} +2 -2
- package/dist/{types-k_ipDb0c.mjs → types-C5ewhu1Q.mjs} +96 -11
- package/dist/{types-BG_5QKX5.cjs → types-R11tMGyX.cjs} +97 -11
- package/package.json +7 -7
|
@@ -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 { m as ensurePrivateDirectorySync, n as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, j as readSettings, k as encodeBase64, l as logger, c as configuration } from './types-
|
|
7
|
-
import { A as AcpSessionManager } from './AcpSessionManager-
|
|
8
|
-
import { h as initialMachineMetadata, j as createSessionMetadata, k as setupOfflineReconnection, n as notifyDaemonSessionStarted, m as MessageQueue2, v as registerKillSessionHandler } from './index-
|
|
6
|
+
import { m as ensurePrivateDirectorySync, n as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, j as readSettings, k as encodeBase64, l as logger, c as configuration } from './types-C5ewhu1Q.mjs';
|
|
7
|
+
import { A as AcpSessionManager } from './AcpSessionManager-BORAhQ1r.mjs';
|
|
8
|
+
import { h as initialMachineMetadata, j as createSessionMetadata, k as setupOfflineReconnection, n as notifyDaemonSessionStarted, m as MessageQueue2, v as registerKillSessionHandler } from './index-inkhalP5.mjs';
|
|
9
9
|
import WebSocket from 'ws';
|
|
10
10
|
import * as ed from '@noble/ed25519';
|
|
11
11
|
import { sha512 } from '@noble/hashes/sha2.js';
|
|
@@ -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-
|
|
5
|
-
import { d as sendUserMessage, a as sessionWebUrl } from './index-
|
|
4
|
+
import { r as readPersistedSessions, c as configuration } from './types-C5ewhu1Q.mjs';
|
|
5
|
+
import { d as sendUserMessage, a as sessionWebUrl } from './index-inkhalP5.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 persistence = require('./types-
|
|
7
|
-
var index = require('./index-
|
|
6
|
+
var persistence = require('./types-R11tMGyX.cjs');
|
|
7
|
+
var index = require('./index-BnRQP3PL.cjs');
|
|
8
8
|
require('axios');
|
|
9
9
|
require('node:util');
|
|
10
10
|
require('node:os');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
|
-
var index = require('./index-
|
|
5
|
-
var persistence = require('./types-
|
|
4
|
+
var index = require('./index-BnRQP3PL.cjs');
|
|
5
|
+
var persistence = require('./types-R11tMGyX.cjs');
|
|
6
6
|
require('node:os');
|
|
7
7
|
require('node:crypto');
|
|
8
8
|
require('cross-spawn');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { D as DEFAULT_RECENT_LIMIT, M as MAX_READ_LIMIT, l as listSessions, r as readSessionTranscript, e as stopSession, f as archiveSession } from './index-
|
|
3
|
-
import { i as isValidSessionId } from './types-
|
|
2
|
+
import { D as DEFAULT_RECENT_LIMIT, M as MAX_READ_LIMIT, l as listSessions, r as readSessionTranscript, e as stopSession, f as archiveSession } from './index-inkhalP5.mjs';
|
|
3
|
+
import { i as isValidSessionId } from './types-C5ewhu1Q.mjs';
|
|
4
4
|
import 'node:os';
|
|
5
5
|
import 'node:crypto';
|
|
6
6
|
import 'cross-spawn';
|
|
@@ -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-
|
|
7
|
-
var persistence = require('./types-
|
|
6
|
+
var index = require('./index-BnRQP3PL.cjs');
|
|
7
|
+
var persistence = require('./types-R11tMGyX.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, i as isValidSpawnOrigin, b as sanitizeSpawnPermissionMode, A as ALLOWED_SPAWN_PERMISSION_MODES, w as waitForSessionKey, d as sendUserMessage } from './index-
|
|
5
|
-
import { l as logger } from './types-
|
|
4
|
+
import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, i as isValidSpawnOrigin, b as sanitizeSpawnPermissionMode, A as ALLOWED_SPAWN_PERMISSION_MODES, w as waitForSessionKey, d as sendUserMessage } from './index-inkhalP5.mjs';
|
|
5
|
+
import { l as logger } from './types-C5ewhu1Q.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.
|
|
32
|
+
var version = "0.2.112";
|
|
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.
|
|
146
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
147
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
148
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
149
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
150
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
145
|
+
"very-happy-tools-arm64-darwin": "0.2.112",
|
|
146
|
+
"very-happy-tools-x64-darwin": "0.2.112",
|
|
147
|
+
"very-happy-tools-arm64-linux": "0.2.112",
|
|
148
|
+
"very-happy-tools-x64-linux": "0.2.112",
|
|
149
|
+
"very-happy-tools-arm64-win32": "0.2.112",
|
|
150
|
+
"very-happy-tools-x64-win32": "0.2.112"
|
|
151
151
|
};
|
|
152
152
|
var devDependencies = {
|
|
153
153
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -747,6 +747,14 @@ const sessionEnvelopeSchema = z.object({
|
|
|
747
747
|
// Codex app-server item id for this envelope. Used as the precise
|
|
748
748
|
// rollback point for Codex thread duplicate/fork-from-message.
|
|
749
749
|
codexItemId: z.string().min(1).optional(),
|
|
750
|
+
// B-309: identity of the live draft this envelope supersedes,
|
|
751
|
+
// `"<api message id>:<content block index>"`. Set on text/thinking
|
|
752
|
+
// envelopes mapped from a Claude assistant message so the web can replace
|
|
753
|
+
// the streamed draft with the persisted message in a single frame instead
|
|
754
|
+
// of letting it flicker out and back in. Absent from every other producer
|
|
755
|
+
// (and from CLIs older than the streaming relay) — consumers must treat a
|
|
756
|
+
// missing key as "no draft to claim", never as an error.
|
|
757
|
+
streamKey: z.string().min(1).optional(),
|
|
750
758
|
// Per-API-call token usage of the assistant message this envelope was
|
|
751
759
|
// mapped from (B-108). Envelope-level (not inside `ev`) so every envelope
|
|
752
760
|
// type carries it uniformly — the web feeds it into its context meter.
|
|
@@ -785,6 +793,7 @@ function createEnvelope(role, ev, opts = {}) {
|
|
|
785
793
|
...opts.subagent ? { subagent: opts.subagent } : {},
|
|
786
794
|
...opts.claudeUuid ? { claudeUuid: opts.claudeUuid } : {},
|
|
787
795
|
...opts.codexItemId ? { codexItemId: opts.codexItemId } : {},
|
|
796
|
+
...opts.streamKey ? { streamKey: opts.streamKey } : {},
|
|
788
797
|
...opts.usage ? { usage: opts.usage } : {},
|
|
789
798
|
ev
|
|
790
799
|
});
|
|
@@ -887,6 +896,44 @@ z.object({
|
|
|
887
896
|
body: CoreUpdateBodySchema,
|
|
888
897
|
createdAt: z.number()
|
|
889
898
|
});
|
|
899
|
+
const STREAM_DELTA_MAX_CHARS = 16 * 1024;
|
|
900
|
+
const sessionStreamBlockKindSchema = z.enum(["text", "thinking"]);
|
|
901
|
+
const sessionStreamBlockStartSchema = z.object({
|
|
902
|
+
t: z.literal("block-start"),
|
|
903
|
+
mid: z.string().min(1),
|
|
904
|
+
idx: z.number().int().min(0),
|
|
905
|
+
kind: sessionStreamBlockKindSchema
|
|
906
|
+
});
|
|
907
|
+
const sessionStreamBlockDeltaSchema = z.object({
|
|
908
|
+
t: z.literal("block-delta"),
|
|
909
|
+
mid: z.string().min(1),
|
|
910
|
+
idx: z.number().int().min(0),
|
|
911
|
+
text: z.string().max(STREAM_DELTA_MAX_CHARS)
|
|
912
|
+
});
|
|
913
|
+
const sessionStreamBlockEndSchema = z.object({
|
|
914
|
+
t: z.literal("block-end"),
|
|
915
|
+
mid: z.string().min(1),
|
|
916
|
+
idx: z.number().int().min(0)
|
|
917
|
+
});
|
|
918
|
+
const sessionStreamProgressSchema = z.object({
|
|
919
|
+
t: z.literal("progress"),
|
|
920
|
+
thinkingTokens: z.number().int().min(0).optional(),
|
|
921
|
+
outputTokens: z.number().int().min(0).optional(),
|
|
922
|
+
status: z.enum(["requesting", "compacting"]).optional()
|
|
923
|
+
});
|
|
924
|
+
const sessionStreamTurnEndSchema = z.object({
|
|
925
|
+
t: z.literal("turn-end")
|
|
926
|
+
});
|
|
927
|
+
z.discriminatedUnion("t", [
|
|
928
|
+
sessionStreamBlockStartSchema,
|
|
929
|
+
sessionStreamBlockDeltaSchema,
|
|
930
|
+
sessionStreamBlockEndSchema,
|
|
931
|
+
sessionStreamProgressSchema,
|
|
932
|
+
sessionStreamTurnEndSchema
|
|
933
|
+
]);
|
|
934
|
+
function streamKeyOf(messageId, blockIndex) {
|
|
935
|
+
return `${messageId}:${blockIndex}`;
|
|
936
|
+
}
|
|
890
937
|
const VoiceConversationGrantedSchema = z.object({
|
|
891
938
|
allowed: z.literal(true),
|
|
892
939
|
conversationToken: z.string(),
|
|
@@ -2769,13 +2816,24 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
|
|
|
2769
2816
|
maybeEmitSubagentStart(state, turnId, subagent, envelopes);
|
|
2770
2817
|
const usage = pickAssistantUsage(message);
|
|
2771
2818
|
const blocks = Array.isArray(message.message?.content) ? message.message.content : [];
|
|
2772
|
-
|
|
2819
|
+
const apiMessageId = !isSidechainMessage(message) && typeof message.message?.id === "string" && message.message.id.length > 0 ? message.message.id : void 0;
|
|
2820
|
+
let blockCursor = 0;
|
|
2821
|
+
if (apiMessageId) {
|
|
2822
|
+
if (state.streamBlockMessageId !== apiMessageId) {
|
|
2823
|
+
state.streamBlockMessageId = apiMessageId;
|
|
2824
|
+
state.streamBlockCursor = 0;
|
|
2825
|
+
}
|
|
2826
|
+
blockCursor = state.streamBlockCursor ?? 0;
|
|
2827
|
+
state.streamBlockCursor = blockCursor + blocks.length;
|
|
2828
|
+
}
|
|
2829
|
+
const draftKey = (index) => apiMessageId ? streamKeyOf(apiMessageId, blockCursor + index) : void 0;
|
|
2830
|
+
for (const [blockIndex, block] of blocks.entries()) {
|
|
2773
2831
|
if (block.type === "text" && typeof block.text === "string" && block.text.trim().length > 0) {
|
|
2774
|
-
envelopes.push(createEnvelope("agent", { t: "text", text: block.text }, { turn: turnId, subagent, claudeUuid, usage }));
|
|
2832
|
+
envelopes.push(createEnvelope("agent", { t: "text", text: block.text }, { turn: turnId, subagent, claudeUuid, usage, streamKey: draftKey(blockIndex) }));
|
|
2775
2833
|
continue;
|
|
2776
2834
|
}
|
|
2777
2835
|
if (block.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim().length > 0) {
|
|
2778
|
-
envelopes.push(createEnvelope("agent", { t: "text", text: block.thinking, thinking: true }, { turn: turnId, subagent, claudeUuid, usage }));
|
|
2836
|
+
envelopes.push(createEnvelope("agent", { t: "text", text: block.thinking, thinking: true }, { turn: turnId, subagent, claudeUuid, usage, streamKey: draftKey(blockIndex) }));
|
|
2779
2837
|
continue;
|
|
2780
2838
|
}
|
|
2781
2839
|
if (block.type === "tool_use") {
|
|
@@ -3774,6 +3832,33 @@ class ApiSessionClient extends EventEmitter {
|
|
|
3774
3832
|
mode
|
|
3775
3833
|
});
|
|
3776
3834
|
}
|
|
3835
|
+
/**
|
|
3836
|
+
* B-309: push one live stream frame (thinking/text delta or progress) to
|
|
3837
|
+
* this account's web clients.
|
|
3838
|
+
*
|
|
3839
|
+
* Encrypted with the SESSION key and relayed without being stored —
|
|
3840
|
+
* clipboard-push's shape, for clipboard-push's reasons: the relay must not
|
|
3841
|
+
* be able to read thinking text, and the session id is stamped by the
|
|
3842
|
+
* server from the authenticated connection rather than trusted from here.
|
|
3843
|
+
*
|
|
3844
|
+
* `volatile` on purpose. A draft that misses the wire while disconnected
|
|
3845
|
+
* is worth nothing — the persisted message is still coming, and replaying
|
|
3846
|
+
* stale deltas after a reconnect would paint text that has already landed.
|
|
3847
|
+
*/
|
|
3848
|
+
sendStreamFrame(frame) {
|
|
3849
|
+
if (!this.socket.connected) return;
|
|
3850
|
+
try {
|
|
3851
|
+
this.socket.volatile.emit("session-stream", {
|
|
3852
|
+
// The frame object, NOT a JSON string: `encrypt` serializes
|
|
3853
|
+
// internally, so pre-stringifying would double-encode and
|
|
3854
|
+
// escape every quote in the streamed text.
|
|
3855
|
+
payload: encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, frame)),
|
|
3856
|
+
enc: true
|
|
3857
|
+
});
|
|
3858
|
+
} catch (error) {
|
|
3859
|
+
logger.debug(`[API] Failed to relay stream frame: ${error}`);
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3777
3862
|
/**
|
|
3778
3863
|
* Send session death message
|
|
3779
3864
|
*/
|
|
@@ -16302,4 +16387,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
|
|
|
16302
16387
|
}).passthrough()
|
|
16303
16388
|
]);
|
|
16304
16389
|
|
|
16305
|
-
export {
|
|
16390
|
+
export { mirrorLineKey as $, ApiClient as A, credentialRelayProblem as B, deriveLocalCliUpdateSummary as C, updateSettings as D, encodeBase64Url as E, decodeBase64 as F, writeCredentialsLegacy as G, writeCredentialsDataKey as H, InvalidateSync as I, readCredentialsForConfiguredRelay as J, encrypt as K, isClaudeSessionId as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, getLocalHappyAgentCredentialPath as N, readLocalHappyAgentCredentials as O, decryptWithDataKey as P, decryptLegacy as Q, RawJSONLinesSchema as R, STREAM_DELTA_MAX_CHARS as S, extractCompleteLines as T, decideBackfill as U, parseTerminalHookPayload as V, tmuxArgs as W, scrubTmuxClientEnv as X, decideMirrorBinding as Y, MIRROR_BACKFILL_LINES_DEFAULT as Z, persistSession as _, ApiSessionClient as a, mirrorLocalId as a0, detectResumeSupport as a1, detectCLIAvailability as a2, acquireDaemonLock as a3, summarizeSpawnSessionForLog as a4, deletePersistedSessions as a5, shellescape as a6, decrypt as a7, writeDaemonState as a8, writeSettings as a9, fetchCliUpdateState as aa, resolveCliUpdateCheckInterval as ab, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as ac, releaseDaemonLock as ad, listVhTerminals as ae, isValidTerminalId as af, readVhTerminal as ag, sendToVhTerminal as ah, TITLE_PROMPT_PREFIX as ai, BOARD_ANALYZER_PROMPT_PREFIX as aj, startOfflineReconnection as ak, clearCredentials as al, clearMachineId as am, SandboxConfigSchema as an, CodexAppServerClient as ao, getLatestDaemonLog as ap, persistence as aq, api as ar, createEnvelope as b, configuration as c, contentLogMetadata as d, errorLogMetadata as e, packageJson as f, delay as g, connectionState as h, isValidSessionId as i, readSettings as j, encodeBase64 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, readCredentials as z };
|
|
@@ -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.
|
|
54
|
+
var version = "0.2.112";
|
|
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.
|
|
168
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
169
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
170
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
171
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
172
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
167
|
+
"very-happy-tools-arm64-darwin": "0.2.112",
|
|
168
|
+
"very-happy-tools-x64-darwin": "0.2.112",
|
|
169
|
+
"very-happy-tools-arm64-linux": "0.2.112",
|
|
170
|
+
"very-happy-tools-x64-linux": "0.2.112",
|
|
171
|
+
"very-happy-tools-arm64-win32": "0.2.112",
|
|
172
|
+
"very-happy-tools-x64-win32": "0.2.112"
|
|
173
173
|
};
|
|
174
174
|
var devDependencies = {
|
|
175
175
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -769,6 +769,14 @@ const sessionEnvelopeSchema = z__namespace.object({
|
|
|
769
769
|
// Codex app-server item id for this envelope. Used as the precise
|
|
770
770
|
// rollback point for Codex thread duplicate/fork-from-message.
|
|
771
771
|
codexItemId: z__namespace.string().min(1).optional(),
|
|
772
|
+
// B-309: identity of the live draft this envelope supersedes,
|
|
773
|
+
// `"<api message id>:<content block index>"`. Set on text/thinking
|
|
774
|
+
// envelopes mapped from a Claude assistant message so the web can replace
|
|
775
|
+
// the streamed draft with the persisted message in a single frame instead
|
|
776
|
+
// of letting it flicker out and back in. Absent from every other producer
|
|
777
|
+
// (and from CLIs older than the streaming relay) — consumers must treat a
|
|
778
|
+
// missing key as "no draft to claim", never as an error.
|
|
779
|
+
streamKey: z__namespace.string().min(1).optional(),
|
|
772
780
|
// Per-API-call token usage of the assistant message this envelope was
|
|
773
781
|
// mapped from (B-108). Envelope-level (not inside `ev`) so every envelope
|
|
774
782
|
// type carries it uniformly — the web feeds it into its context meter.
|
|
@@ -807,6 +815,7 @@ function createEnvelope(role, ev, opts = {}) {
|
|
|
807
815
|
...opts.subagent ? { subagent: opts.subagent } : {},
|
|
808
816
|
...opts.claudeUuid ? { claudeUuid: opts.claudeUuid } : {},
|
|
809
817
|
...opts.codexItemId ? { codexItemId: opts.codexItemId } : {},
|
|
818
|
+
...opts.streamKey ? { streamKey: opts.streamKey } : {},
|
|
810
819
|
...opts.usage ? { usage: opts.usage } : {},
|
|
811
820
|
ev
|
|
812
821
|
});
|
|
@@ -909,6 +918,44 @@ z__namespace.object({
|
|
|
909
918
|
body: CoreUpdateBodySchema,
|
|
910
919
|
createdAt: z__namespace.number()
|
|
911
920
|
});
|
|
921
|
+
const STREAM_DELTA_MAX_CHARS = 16 * 1024;
|
|
922
|
+
const sessionStreamBlockKindSchema = z__namespace.enum(["text", "thinking"]);
|
|
923
|
+
const sessionStreamBlockStartSchema = z__namespace.object({
|
|
924
|
+
t: z__namespace.literal("block-start"),
|
|
925
|
+
mid: z__namespace.string().min(1),
|
|
926
|
+
idx: z__namespace.number().int().min(0),
|
|
927
|
+
kind: sessionStreamBlockKindSchema
|
|
928
|
+
});
|
|
929
|
+
const sessionStreamBlockDeltaSchema = z__namespace.object({
|
|
930
|
+
t: z__namespace.literal("block-delta"),
|
|
931
|
+
mid: z__namespace.string().min(1),
|
|
932
|
+
idx: z__namespace.number().int().min(0),
|
|
933
|
+
text: z__namespace.string().max(STREAM_DELTA_MAX_CHARS)
|
|
934
|
+
});
|
|
935
|
+
const sessionStreamBlockEndSchema = z__namespace.object({
|
|
936
|
+
t: z__namespace.literal("block-end"),
|
|
937
|
+
mid: z__namespace.string().min(1),
|
|
938
|
+
idx: z__namespace.number().int().min(0)
|
|
939
|
+
});
|
|
940
|
+
const sessionStreamProgressSchema = z__namespace.object({
|
|
941
|
+
t: z__namespace.literal("progress"),
|
|
942
|
+
thinkingTokens: z__namespace.number().int().min(0).optional(),
|
|
943
|
+
outputTokens: z__namespace.number().int().min(0).optional(),
|
|
944
|
+
status: z__namespace.enum(["requesting", "compacting"]).optional()
|
|
945
|
+
});
|
|
946
|
+
const sessionStreamTurnEndSchema = z__namespace.object({
|
|
947
|
+
t: z__namespace.literal("turn-end")
|
|
948
|
+
});
|
|
949
|
+
z__namespace.discriminatedUnion("t", [
|
|
950
|
+
sessionStreamBlockStartSchema,
|
|
951
|
+
sessionStreamBlockDeltaSchema,
|
|
952
|
+
sessionStreamBlockEndSchema,
|
|
953
|
+
sessionStreamProgressSchema,
|
|
954
|
+
sessionStreamTurnEndSchema
|
|
955
|
+
]);
|
|
956
|
+
function streamKeyOf(messageId, blockIndex) {
|
|
957
|
+
return `${messageId}:${blockIndex}`;
|
|
958
|
+
}
|
|
912
959
|
const VoiceConversationGrantedSchema = z__namespace.object({
|
|
913
960
|
allowed: z__namespace.literal(true),
|
|
914
961
|
conversationToken: z__namespace.string(),
|
|
@@ -1603,7 +1650,7 @@ class RpcHandlerManager {
|
|
|
1603
1650
|
}
|
|
1604
1651
|
}
|
|
1605
1652
|
|
|
1606
|
-
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-
|
|
1653
|
+
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-R11tMGyX.cjs', document.baseURI).href))));
|
|
1607
1654
|
function projectPath() {
|
|
1608
1655
|
const path = path$1.resolve(__dirname$1, "..");
|
|
1609
1656
|
return path;
|
|
@@ -2791,13 +2838,24 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
|
|
|
2791
2838
|
maybeEmitSubagentStart(state, turnId, subagent, envelopes);
|
|
2792
2839
|
const usage = pickAssistantUsage(message);
|
|
2793
2840
|
const blocks = Array.isArray(message.message?.content) ? message.message.content : [];
|
|
2794
|
-
|
|
2841
|
+
const apiMessageId = !isSidechainMessage(message) && typeof message.message?.id === "string" && message.message.id.length > 0 ? message.message.id : void 0;
|
|
2842
|
+
let blockCursor = 0;
|
|
2843
|
+
if (apiMessageId) {
|
|
2844
|
+
if (state.streamBlockMessageId !== apiMessageId) {
|
|
2845
|
+
state.streamBlockMessageId = apiMessageId;
|
|
2846
|
+
state.streamBlockCursor = 0;
|
|
2847
|
+
}
|
|
2848
|
+
blockCursor = state.streamBlockCursor ?? 0;
|
|
2849
|
+
state.streamBlockCursor = blockCursor + blocks.length;
|
|
2850
|
+
}
|
|
2851
|
+
const draftKey = (index) => apiMessageId ? streamKeyOf(apiMessageId, blockCursor + index) : void 0;
|
|
2852
|
+
for (const [blockIndex, block] of blocks.entries()) {
|
|
2795
2853
|
if (block.type === "text" && typeof block.text === "string" && block.text.trim().length > 0) {
|
|
2796
|
-
envelopes.push(createEnvelope("agent", { t: "text", text: block.text }, { turn: turnId, subagent, claudeUuid, usage }));
|
|
2854
|
+
envelopes.push(createEnvelope("agent", { t: "text", text: block.text }, { turn: turnId, subagent, claudeUuid, usage, streamKey: draftKey(blockIndex) }));
|
|
2797
2855
|
continue;
|
|
2798
2856
|
}
|
|
2799
2857
|
if (block.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim().length > 0) {
|
|
2800
|
-
envelopes.push(createEnvelope("agent", { t: "text", text: block.thinking, thinking: true }, { turn: turnId, subagent, claudeUuid, usage }));
|
|
2858
|
+
envelopes.push(createEnvelope("agent", { t: "text", text: block.thinking, thinking: true }, { turn: turnId, subagent, claudeUuid, usage, streamKey: draftKey(blockIndex) }));
|
|
2801
2859
|
continue;
|
|
2802
2860
|
}
|
|
2803
2861
|
if (block.type === "tool_use") {
|
|
@@ -3796,6 +3854,33 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3796
3854
|
mode
|
|
3797
3855
|
});
|
|
3798
3856
|
}
|
|
3857
|
+
/**
|
|
3858
|
+
* B-309: push one live stream frame (thinking/text delta or progress) to
|
|
3859
|
+
* this account's web clients.
|
|
3860
|
+
*
|
|
3861
|
+
* Encrypted with the SESSION key and relayed without being stored —
|
|
3862
|
+
* clipboard-push's shape, for clipboard-push's reasons: the relay must not
|
|
3863
|
+
* be able to read thinking text, and the session id is stamped by the
|
|
3864
|
+
* server from the authenticated connection rather than trusted from here.
|
|
3865
|
+
*
|
|
3866
|
+
* `volatile` on purpose. A draft that misses the wire while disconnected
|
|
3867
|
+
* is worth nothing — the persisted message is still coming, and replaying
|
|
3868
|
+
* stale deltas after a reconnect would paint text that has already landed.
|
|
3869
|
+
*/
|
|
3870
|
+
sendStreamFrame(frame) {
|
|
3871
|
+
if (!this.socket.connected) return;
|
|
3872
|
+
try {
|
|
3873
|
+
this.socket.volatile.emit("session-stream", {
|
|
3874
|
+
// The frame object, NOT a JSON string: `encrypt` serializes
|
|
3875
|
+
// internally, so pre-stringifying would double-encode and
|
|
3876
|
+
// escape every quote in the streamed text.
|
|
3877
|
+
payload: encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, frame)),
|
|
3878
|
+
enc: true
|
|
3879
|
+
});
|
|
3880
|
+
} catch (error) {
|
|
3881
|
+
logger.debug(`[API] Failed to relay stream frame: ${error}`);
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3799
3884
|
/**
|
|
3800
3885
|
* Send session death message
|
|
3801
3886
|
*/
|
|
@@ -16334,6 +16419,7 @@ exports.InvalidateSync = InvalidateSync;
|
|
|
16334
16419
|
exports.MAX_CHAT_ATTACHMENT_SOURCE_BYTES = MAX_CHAT_ATTACHMENT_SOURCE_BYTES;
|
|
16335
16420
|
exports.MIRROR_BACKFILL_LINES_DEFAULT = MIRROR_BACKFILL_LINES_DEFAULT;
|
|
16336
16421
|
exports.RawJSONLinesSchema = RawJSONLinesSchema;
|
|
16422
|
+
exports.STREAM_DELTA_MAX_CHARS = STREAM_DELTA_MAX_CHARS;
|
|
16337
16423
|
exports.SandboxConfigSchema = SandboxConfigSchema;
|
|
16338
16424
|
exports.TITLE_PROMPT_PREFIX = TITLE_PROMPT_PREFIX;
|
|
16339
16425
|
exports.acquireDaemonLock = acquireDaemonLock;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "very-happy-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.112",
|
|
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.
|
|
117
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
118
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
119
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
120
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
121
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
116
|
+
"very-happy-tools-arm64-darwin": "0.2.112",
|
|
117
|
+
"very-happy-tools-x64-darwin": "0.2.112",
|
|
118
|
+
"very-happy-tools-arm64-linux": "0.2.112",
|
|
119
|
+
"very-happy-tools-x64-linux": "0.2.112",
|
|
120
|
+
"very-happy-tools-arm64-win32": "0.2.112",
|
|
121
|
+
"very-happy-tools-x64-win32": "0.2.112"
|
|
122
122
|
},
|
|
123
123
|
"devDependencies": {
|
|
124
124
|
"@slopus/happy-wire": "workspace:*",
|