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.
- package/dist/{AcpBackend-tou8FQXI.cjs → AcpBackend-YPVwACkW.cjs} +1 -1
- package/dist/{AcpBackend-DiIJaJWG.mjs → AcpBackend-pgDnK76l.mjs} +1 -1
- package/dist/{AcpSessionManager-fF_HFB98.cjs → AcpSessionManager-6rypahwH.cjs} +51 -11
- package/dist/{AcpSessionManager-CZ0Az0GG.mjs → AcpSessionManager-Bq5Tiky1.mjs} +51 -11
- package/dist/{config-CGDxsTZg.mjs → config-BTEW041n.mjs} +2 -2
- package/dist/{config-CEbOao_0.cjs → config-rQdv_Yr0.cjs} +2 -2
- package/dist/{index-CYizH-JC.cjs → index-BHg0P9cY.cjs} +2 -2
- package/dist/{index-CUJ6faw1.mjs → index-BTnlYGaP.mjs} +139 -41
- package/dist/{index-D4_LW69g.mjs → index-BeHr5uMY.mjs} +25 -11
- package/dist/{index-DKj_0dqB.mjs → index-CaIsj1q7.mjs} +2 -2
- package/dist/{index-BlkIz9BQ.cjs → index-DKRU6E-x.cjs} +143 -44
- package/dist/{index-HKcuQ_fQ.cjs → index-uPpFZhhr.cjs} +24 -10
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-MWVPJDxV.cjs → installTerminalHooks-CGqopr1A.cjs} +2 -2
- package/dist/{installTerminalHooks-B3EGNaJr.mjs → installTerminalHooks-DFmKhCto.mjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +25 -1
- package/dist/lib.d.mts +25 -1
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-CZ1Z6AI5.mjs → mcp-DnKBKXYa.mjs} +2 -2
- package/dist/{mcp-DBKk5L6_.cjs → mcp-FlbfMw6_.cjs} +2 -2
- package/dist/{runGemini-C3BCKTMp.mjs → runGemini-BsfadDSa.mjs} +9 -5
- package/dist/{runGemini-BRUmjZgV.cjs → runGemini-DYawZQTu.cjs} +9 -5
- package/dist/{runOpenClaw-o1ImBlcJ.cjs → runOpenClaw-C2XjFP2m.cjs} +3 -3
- package/dist/{runOpenClaw-DEYzcGSV.mjs → runOpenClaw-xGtbJ7f8.mjs} +3 -3
- package/dist/{send-B9fh96vR.cjs → send-B0Wojz18.cjs} +2 -2
- package/dist/{send-DFGH_-s_.mjs → send-DRZppEr2.mjs} +2 -2
- package/dist/{sessions-CKVfXHyi.mjs → sessions-BuMgxuxd.mjs} +11 -4
- package/dist/{sessions-BNyEJ2_6.cjs → sessions-CTuUV0TW.cjs} +11 -4
- package/dist/{spawn-xPV7-s4S.cjs → spawn-7U_4QTHw.cjs} +2 -2
- package/dist/{spawn-B6kP4YjA.mjs → spawn-BRdfNDsu.mjs} +2 -2
- package/dist/{types-7ZSxm6Pi.cjs → types-Jag0GwhO.cjs} +209 -41
- package/dist/{types-Di0o0BdV.mjs → types-q7wtjfxb.mjs} +208 -41
- 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.
|
|
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.
|
|
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.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
|
-
*
|
|
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
|
-
|
|
14382
|
-
|
|
14383
|
-
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
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
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
|
|
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 {
|
|
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.
|
|
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.
|
|
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.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:*",
|