very-happy-cli 0.2.153 → 0.2.155
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-YDGv4E-g.mjs → AcpBackend-DVB0nzgR.mjs} +2 -2
- package/dist/{AcpBackend-DSt8nTYm.cjs → AcpBackend-DmFcRh54.cjs} +3 -3
- package/dist/{AcpSessionManager-uov6I9C8.cjs → AcpSessionManager-CWaSYTnT.cjs} +1 -1
- package/dist/{AcpSessionManager-Cxf5HQX1.mjs → AcpSessionManager-dGDgNb-p.mjs} +1 -1
- package/dist/agentGuidance-BWxFC6UL.mjs +1613 -0
- package/dist/agentGuidance-un7YPryB.cjs +1665 -0
- package/dist/{agentHome-D68Xh2ae.mjs → agentHome-ByLb2HFg.mjs} +5 -5
- package/dist/{agentHome-BJ7bde35.cjs → agentHome-aucT8BHw.cjs} +5 -5
- package/dist/{auto-CcXxfqkC.mjs → auto-BQnD6gVx.mjs} +21 -21
- package/dist/{auto-C-90ojIH.cjs → auto-P9RoJaY0.cjs} +24 -24
- package/dist/codex/happyMcpStdioBridge.cjs +6 -3
- package/dist/codex/happyMcpStdioBridge.mjs +6 -3
- package/dist/{config-CHJ189UJ.mjs → config-BPZ2Y6o8.mjs} +8 -8
- package/dist/{config-D23kF0_u.cjs → config-BoePh9PX.cjs} +8 -8
- package/dist/{index-D49WvbDT.cjs → index--KCpVs1c.cjs} +7 -7
- package/dist/{index-BacwoXzs.mjs → index-B4oXnbYw.mjs} +522 -729
- package/dist/{index-BgYZGODP.mjs → index-BjzdXb9x.mjs} +21 -13
- package/dist/{index-DEOVn46R.cjs → index-DRrLaljt.cjs} +21 -13
- package/dist/{index-BXA9fxbK.mjs → index-DVVRqaVG.mjs} +7 -7
- package/dist/{index-DHrwHxHf.cjs → index-D_fYUxVg.cjs} +579 -798
- package/dist/index.cjs +6 -6
- package/dist/index.mjs +6 -6
- package/dist/{install-BiOXBnnS.cjs → install-CGigiocs.cjs} +1 -1
- package/dist/{install-Ca7_Z3bV.mjs → install-DP5aPNEX.mjs} +1 -1
- package/dist/{installTerminalHooks-BF0kL0ae.cjs → installTerminalHooks-XrcPvfBs.cjs} +5 -5
- package/dist/{installTerminalHooks-Bpl32K75.mjs → installTerminalHooks-tIg7mANc.mjs} +5 -5
- package/dist/lib.cjs +2 -2
- package/dist/lib.mjs +2 -2
- package/dist/{limits-BtAuKRl2.mjs → limits-C_DW0M0q.mjs} +309 -13
- package/dist/{limits-DY_sFA3J.cjs → limits-DkfHJ3nS.cjs} +329 -12
- package/dist/{mcp-JpqI2POW.cjs → mcp-BqlXl10F.cjs} +23 -23
- package/dist/{mcp-DQkmk4VV.mjs → mcp-o7QglAQM.mjs} +17 -17
- package/dist/{piRuntime-DRbbeQ72.cjs → piRuntime-BxP4B_zY.cjs} +2 -2
- package/dist/{piRuntime-DBpe12NN.mjs → piRuntime-MjiJI-nV.mjs} +2 -2
- package/dist/{piTerminal-qdJ9KZVL.cjs → piTerminal-DYzRcwgb.cjs} +6 -6
- package/dist/{piTerminal-BoHvPEZ_.mjs → piTerminal-Dpq6yqKU.mjs} +6 -6
- package/dist/{runGemini-CtOEFvhf.cjs → runGemini-8Pxh94Fm.cjs} +7 -7
- package/dist/{runGemini-YqH7a-7O.mjs → runGemini-CDlcQ-OA.mjs} +6 -6
- package/dist/{runOpenClaw-DoqZXBvL.cjs → runOpenClaw-B5FSZIbK.cjs} +6 -6
- package/dist/{runOpenClaw-DSSyFQBb.mjs → runOpenClaw-YkhsgPs0.mjs} +5 -5
- package/dist/{send-9075kHZP.cjs → send-CwrYXTPr.cjs} +58 -54
- package/dist/{send-Cs-RwqNf.mjs → send-DJStmLBv.mjs} +56 -53
- package/dist/{sessions-iBnYzVUK.mjs → sessions-JaVXlSqj.mjs} +88 -45
- package/dist/{sessions-qULzUzlI.cjs → sessions-MX21NJXd.cjs} +99 -56
- package/dist/{spawn-C6fRkedx.mjs → spawn-BaPnjClT.mjs} +22 -22
- package/dist/{spawn-od9V23cc.cjs → spawn-cIoglKVf.cjs} +30 -30
- package/dist/{teams-CkrWQ4uM.mjs → teams-DXV5Pwwt.mjs} +8 -8
- package/dist/{teams-CrCzU-AV.cjs → teams-Dqk7F3D-.cjs} +8 -8
- package/dist/{todo-aCZmSt27.mjs → todo-2Z1REhfx.mjs} +8 -6
- package/dist/{todo-BCT_ZPuV.cjs → todo-Buuqn9gm.cjs} +8 -6
- package/dist/{types-BvqOVUOW.mjs → types-CkbfdRzq.mjs} +7 -267
- package/dist/{types-CUCU7Vw8.cjs → types-a2xsH2UI.cjs} +19 -295
- package/package.json +7 -7
- package/dist/agentGuidance-BM4kMNyr.cjs +0 -553
- package/dist/agentGuidance-C8unGWp7.mjs +0 -529
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var axios = require('axios');
|
|
4
|
-
var persistence = require('./limits-
|
|
4
|
+
var persistence = require('./limits-DkfHJ3nS.cjs');
|
|
5
5
|
var node_events = require('node:events');
|
|
6
6
|
var socket_ioClient = require('socket.io-client');
|
|
7
7
|
var z = require('zod');
|
|
@@ -94,8 +94,9 @@ const CliUpdateStateSchema = z.z.object({
|
|
|
94
94
|
recommendedVersion: z.z.string().nullable(),
|
|
95
95
|
minimumVersion: z.z.string().nullable(),
|
|
96
96
|
status: z.z.enum(["current", "available", "required"]),
|
|
97
|
-
/** B-351: the version this machine may install by itself
|
|
98
|
-
*
|
|
97
|
+
/** B-351/B-503: the version this machine may install by itself, as decided
|
|
98
|
+
* by the relay (exact pin or the promoted `latest`); null means no
|
|
99
|
+
* unattended install. */
|
|
99
100
|
autoUpdateVersion: z.z.string().nullable().optional(),
|
|
100
101
|
retrySupported: z.z.boolean().optional(),
|
|
101
102
|
manualUpdateSupported: z.z.boolean().optional(),
|
|
@@ -352,41 +353,6 @@ const AgentMessageSchema = z.z.object({
|
|
|
352
353
|
});
|
|
353
354
|
z.z.union([UserMessageSchema, AgentMessageSchema]);
|
|
354
355
|
|
|
355
|
-
async function delay(ms) {
|
|
356
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
357
|
-
}
|
|
358
|
-
function exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount) {
|
|
359
|
-
let maxDelayRet = minDelay + (maxDelay - minDelay) / maxFailureCount * Math.min(currentFailureCount, maxFailureCount);
|
|
360
|
-
return Math.round(Math.random() * maxDelayRet);
|
|
361
|
-
}
|
|
362
|
-
function createBackoff(opts) {
|
|
363
|
-
return async (callback) => {
|
|
364
|
-
let currentFailureCount = 0;
|
|
365
|
-
const minDelay = opts && opts.minDelay !== void 0 ? opts.minDelay : 250;
|
|
366
|
-
const maxDelay = opts && opts.maxDelay !== void 0 ? opts.maxDelay : 1e3;
|
|
367
|
-
const maxFailureCount = opts && opts.maxFailureCount !== void 0 ? opts.maxFailureCount : 50;
|
|
368
|
-
while (true) {
|
|
369
|
-
try {
|
|
370
|
-
return await callback();
|
|
371
|
-
} catch (e) {
|
|
372
|
-
if (currentFailureCount < maxFailureCount) {
|
|
373
|
-
currentFailureCount++;
|
|
374
|
-
}
|
|
375
|
-
if (opts && opts.onError) {
|
|
376
|
-
opts.onError(e, currentFailureCount);
|
|
377
|
-
}
|
|
378
|
-
let waitForRequest = exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount);
|
|
379
|
-
await delay(waitForRequest);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
let backoff = createBackoff({
|
|
385
|
-
onError: (e, failuresCount) => {
|
|
386
|
-
persistence.logger.debug(`[BACKOFF] retry ${failuresCount}:`, e?.message || e);
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
|
|
390
356
|
function isRateQuotaCode(code) {
|
|
391
357
|
return typeof code === "string" && code.endsWith("_rate_quota_exceeded");
|
|
392
358
|
}
|
|
@@ -2083,7 +2049,7 @@ class InvalidateSync {
|
|
|
2083
2049
|
this._pendings = [];
|
|
2084
2050
|
};
|
|
2085
2051
|
_doSync = async () => {
|
|
2086
|
-
await backoff(async () => {
|
|
2052
|
+
await persistence.backoff(async () => {
|
|
2087
2053
|
if (this._stopped) {
|
|
2088
2054
|
return;
|
|
2089
2055
|
}
|
|
@@ -2241,223 +2207,6 @@ class TurnReporter {
|
|
|
2241
2207
|
}
|
|
2242
2208
|
}
|
|
2243
2209
|
|
|
2244
|
-
function daemonControlHeaders(controlToken) {
|
|
2245
|
-
return {
|
|
2246
|
-
"Content-Type": "application/json",
|
|
2247
|
-
...controlToken ? { Authorization: `Bearer ${controlToken}` } : {}
|
|
2248
|
-
};
|
|
2249
|
-
}
|
|
2250
|
-
async function daemonPost(path, body) {
|
|
2251
|
-
const state = await persistence.readDaemonState();
|
|
2252
|
-
if (!state?.httpPort) {
|
|
2253
|
-
const errorMessage = "No daemon running, no state file found";
|
|
2254
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2255
|
-
return {
|
|
2256
|
-
error: errorMessage
|
|
2257
|
-
};
|
|
2258
|
-
}
|
|
2259
|
-
try {
|
|
2260
|
-
process.kill(state.pid, 0);
|
|
2261
|
-
} catch (error) {
|
|
2262
|
-
const errorMessage = "Daemon is not running, file is stale";
|
|
2263
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2264
|
-
return {
|
|
2265
|
-
error: errorMessage
|
|
2266
|
-
};
|
|
2267
|
-
}
|
|
2268
|
-
try {
|
|
2269
|
-
const timeout = process.env.HAPPY_DAEMON_HTTP_TIMEOUT ? parseInt(process.env.HAPPY_DAEMON_HTTP_TIMEOUT) : 1e4;
|
|
2270
|
-
const response = await fetch(`http://127.0.0.1:${state.httpPort}${path}`, {
|
|
2271
|
-
method: "POST",
|
|
2272
|
-
// A state written by an old daemon has no token and must remain callable;
|
|
2273
|
-
// a new daemon always writes one and rejects requests without it.
|
|
2274
|
-
headers: daemonControlHeaders(state.controlToken),
|
|
2275
|
-
body: JSON.stringify(body || {}),
|
|
2276
|
-
// Mostly increased for stress test
|
|
2277
|
-
signal: AbortSignal.timeout(timeout)
|
|
2278
|
-
});
|
|
2279
|
-
if (!response.ok) {
|
|
2280
|
-
const failure = await response.json().catch(() => null);
|
|
2281
|
-
const reason = typeof failure?.error === "string" && failure.error ? failure.error : `HTTP ${response.status}`;
|
|
2282
|
-
const errorMessage = `Request failed: ${path}, ${reason}`;
|
|
2283
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2284
|
-
return {
|
|
2285
|
-
error: errorMessage
|
|
2286
|
-
};
|
|
2287
|
-
}
|
|
2288
|
-
return await response.json();
|
|
2289
|
-
} catch (error) {
|
|
2290
|
-
const errorMessage = `Request failed: ${path}, ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
2291
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2292
|
-
return {
|
|
2293
|
-
error: errorMessage
|
|
2294
|
-
};
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2297
|
-
const SESSION_STARTED_RETRY_TIMEOUT_MS = 3e3;
|
|
2298
|
-
const SESSION_STARTED_RETRY_INTERVAL_MS = 100;
|
|
2299
|
-
async function notifyDaemonSessionStarted(sessionId, metadata, encryption) {
|
|
2300
|
-
const payload = { sessionId, metadata, encryption };
|
|
2301
|
-
const deadline = Date.now() + SESSION_STARTED_RETRY_TIMEOUT_MS;
|
|
2302
|
-
let result;
|
|
2303
|
-
while (true) {
|
|
2304
|
-
result = await daemonPost("/session-started", payload);
|
|
2305
|
-
if (!result?.error) {
|
|
2306
|
-
return result;
|
|
2307
|
-
}
|
|
2308
|
-
if (Date.now() >= deadline) {
|
|
2309
|
-
return result;
|
|
2310
|
-
}
|
|
2311
|
-
await new Promise((resolve) => setTimeout(resolve, SESSION_STARTED_RETRY_INTERVAL_MS));
|
|
2312
|
-
}
|
|
2313
|
-
}
|
|
2314
|
-
async function listDaemonSessions() {
|
|
2315
|
-
const result = await daemonPost("/list");
|
|
2316
|
-
return result.children || [];
|
|
2317
|
-
}
|
|
2318
|
-
async function stopDaemonSession(sessionId) {
|
|
2319
|
-
const result = await daemonPost("/stop-session", { sessionId });
|
|
2320
|
-
return result.success || false;
|
|
2321
|
-
}
|
|
2322
|
-
async function spawnDaemonSession(directory, sessionId, opts) {
|
|
2323
|
-
const result = await daemonPost("/spawn-session", {
|
|
2324
|
-
directory,
|
|
2325
|
-
sessionId,
|
|
2326
|
-
spawnedBy: opts?.spawnedBy,
|
|
2327
|
-
permissionMode: opts?.permissionMode,
|
|
2328
|
-
agent: opts?.agent,
|
|
2329
|
-
environmentVariables: opts?.environmentVariables,
|
|
2330
|
-
resumeClaudeSessionId: opts?.resumeClaudeSessionId,
|
|
2331
|
-
resumeCodexThreadId: opts?.resumeCodexThreadId,
|
|
2332
|
-
parentSessionId: opts?.parentSessionId
|
|
2333
|
-
});
|
|
2334
|
-
return result;
|
|
2335
|
-
}
|
|
2336
|
-
async function notifyDaemonSessionEvent(sessionId, event, spawnedBy) {
|
|
2337
|
-
return daemonPost("/session-event", { sessionId, event, spawnedBy });
|
|
2338
|
-
}
|
|
2339
|
-
async function notifyDaemonClaudeAuthFailed(sessionId) {
|
|
2340
|
-
return daemonPost("/session-event", { sessionId, event: "auth_failed" });
|
|
2341
|
-
}
|
|
2342
|
-
async function notifyDaemonTurnEvent(sessionId, event) {
|
|
2343
|
-
return daemonPost("/session-event", { sessionId, event });
|
|
2344
|
-
}
|
|
2345
|
-
async function stopDaemonHttp() {
|
|
2346
|
-
await daemonPost("/stop");
|
|
2347
|
-
}
|
|
2348
|
-
async function pushClipboardViaDaemon(text, terminalId) {
|
|
2349
|
-
const result = await daemonPost("/clipboard", { text, ...terminalId ? { terminalId } : {} });
|
|
2350
|
-
if (result?.error && result.delivered === void 0) {
|
|
2351
|
-
return { delivered: false, error: result.error };
|
|
2352
|
-
}
|
|
2353
|
-
return result;
|
|
2354
|
-
}
|
|
2355
|
-
async function pushFilePreviewViaDaemon(terminalId, path, mode = "file") {
|
|
2356
|
-
const result = await daemonPost("/file-preview", { terminalId, path, mode });
|
|
2357
|
-
if (result?.error) return { delivered: false, error: result.error };
|
|
2358
|
-
return { delivered: result?.delivered === true, ...result?.delivered === true ? {} : { error: "preview was not delivered" } };
|
|
2359
|
-
}
|
|
2360
|
-
async function setTerminalTitleViaDaemon(terminalId, title, ifAbsent = false) {
|
|
2361
|
-
const result = await daemonPost("/terminal-title", { terminalId, title, ifAbsent });
|
|
2362
|
-
if (result?.error) {
|
|
2363
|
-
return { ok: false, error: result.error };
|
|
2364
|
-
}
|
|
2365
|
-
return { ok: result?.status === "ok", error: result?.status === "ok" ? void 0 : "unexpected daemon response" };
|
|
2366
|
-
}
|
|
2367
|
-
async function checkIfDaemonRunningAndCleanupStaleState() {
|
|
2368
|
-
const state = await persistence.readDaemonState();
|
|
2369
|
-
if (!state) {
|
|
2370
|
-
return false;
|
|
2371
|
-
}
|
|
2372
|
-
try {
|
|
2373
|
-
process.kill(state.pid, 0);
|
|
2374
|
-
} catch {
|
|
2375
|
-
persistence.logger.debug("[DAEMON RUN] Daemon PID not running, cleaning up state");
|
|
2376
|
-
await cleanupDaemonState();
|
|
2377
|
-
return false;
|
|
2378
|
-
}
|
|
2379
|
-
if (state.httpPort) {
|
|
2380
|
-
try {
|
|
2381
|
-
const response = await fetch(`http://127.0.0.1:${state.httpPort}/list`, {
|
|
2382
|
-
method: "POST",
|
|
2383
|
-
headers: daemonControlHeaders(state.controlToken),
|
|
2384
|
-
body: "{}",
|
|
2385
|
-
signal: AbortSignal.timeout(2e3)
|
|
2386
|
-
});
|
|
2387
|
-
if (response.ok) {
|
|
2388
|
-
return true;
|
|
2389
|
-
}
|
|
2390
|
-
} catch {
|
|
2391
|
-
persistence.logger.debug(`[DAEMON RUN] PID ${state.pid} is alive but HTTP health check failed on port ${state.httpPort}, cleaning up stale state`);
|
|
2392
|
-
await cleanupDaemonState();
|
|
2393
|
-
return false;
|
|
2394
|
-
}
|
|
2395
|
-
}
|
|
2396
|
-
return true;
|
|
2397
|
-
}
|
|
2398
|
-
async function isDaemonRunningCurrentlyInstalledHappyVersion() {
|
|
2399
|
-
persistence.logger.debug("[DAEMON CONTROL] Checking if daemon is running same version");
|
|
2400
|
-
const runningDaemon = await checkIfDaemonRunningAndCleanupStaleState();
|
|
2401
|
-
if (!runningDaemon) {
|
|
2402
|
-
persistence.logger.debug("[DAEMON CONTROL] No daemon running, returning false");
|
|
2403
|
-
return false;
|
|
2404
|
-
}
|
|
2405
|
-
const state = await persistence.readDaemonState();
|
|
2406
|
-
if (!state) {
|
|
2407
|
-
persistence.logger.debug("[DAEMON CONTROL] No daemon state found, returning false");
|
|
2408
|
-
return false;
|
|
2409
|
-
}
|
|
2410
|
-
const currentCliVersion = persistence.configuration.currentCliVersion;
|
|
2411
|
-
persistence.logger.debug(`[DAEMON CONTROL] Current CLI version: ${currentCliVersion}, Daemon started with version: ${state.startedWithCliVersion}`);
|
|
2412
|
-
return currentCliVersion === state.startedWithCliVersion;
|
|
2413
|
-
}
|
|
2414
|
-
async function cleanupDaemonState() {
|
|
2415
|
-
try {
|
|
2416
|
-
await persistence.clearDaemonState();
|
|
2417
|
-
persistence.logger.debug("[DAEMON RUN] Daemon state file removed");
|
|
2418
|
-
} catch (error) {
|
|
2419
|
-
persistence.logger.debug("[DAEMON RUN] Error cleaning up daemon metadata", error);
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2422
|
-
async function stopDaemon() {
|
|
2423
|
-
try {
|
|
2424
|
-
const state = await persistence.readDaemonState();
|
|
2425
|
-
if (!state) {
|
|
2426
|
-
persistence.logger.debug("No daemon state found");
|
|
2427
|
-
return;
|
|
2428
|
-
}
|
|
2429
|
-
persistence.logger.debug(`Stopping daemon with PID ${state.pid}`);
|
|
2430
|
-
try {
|
|
2431
|
-
await stopDaemonHttp();
|
|
2432
|
-
await waitForProcessDeath(state.pid, 2e3);
|
|
2433
|
-
persistence.logger.debug("Daemon stopped gracefully via HTTP");
|
|
2434
|
-
return;
|
|
2435
|
-
} catch (error) {
|
|
2436
|
-
persistence.logger.debug("HTTP stop failed, will force kill", error);
|
|
2437
|
-
}
|
|
2438
|
-
try {
|
|
2439
|
-
process.kill(state.pid, "SIGKILL");
|
|
2440
|
-
persistence.logger.debug("Force killed daemon");
|
|
2441
|
-
} catch (error) {
|
|
2442
|
-
persistence.logger.debug("Daemon already dead");
|
|
2443
|
-
}
|
|
2444
|
-
} catch (error) {
|
|
2445
|
-
persistence.logger.debug("Error stopping daemon", error);
|
|
2446
|
-
}
|
|
2447
|
-
}
|
|
2448
|
-
async function waitForProcessDeath(pid, timeout) {
|
|
2449
|
-
const start = Date.now();
|
|
2450
|
-
while (Date.now() - start < timeout) {
|
|
2451
|
-
try {
|
|
2452
|
-
process.kill(pid, 0);
|
|
2453
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2454
|
-
} catch {
|
|
2455
|
-
return;
|
|
2456
|
-
}
|
|
2457
|
-
}
|
|
2458
|
-
throw new Error("Process did not die within timeout");
|
|
2459
|
-
}
|
|
2460
|
-
|
|
2461
2210
|
class ApiSessionClient extends node_events.EventEmitter {
|
|
2462
2211
|
token;
|
|
2463
2212
|
sessionId;
|
|
@@ -3250,7 +2999,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3250
2999
|
*/
|
|
3251
3000
|
/** B-466: turn edges (and a periodic lease) reported to the local daemon so
|
|
3252
3001
|
* auto-update waits for "no turn in flight" instead of "no sessions". */
|
|
3253
|
-
turnReporter = new TurnReporter((event) => void notifyDaemonTurnEvent(this.sessionId, event).catch((error) => persistence.logger.debug("[API] Failed to report turn event to daemon:", error)));
|
|
3002
|
+
turnReporter = new TurnReporter((event) => void persistence.notifyDaemonTurnEvent(this.sessionId, event).catch((error) => persistence.logger.debug("[API] Failed to report turn event to daemon:", error)));
|
|
3254
3003
|
keepAlive(thinking, mode) {
|
|
3255
3004
|
if (process.env.DEBUG) {
|
|
3256
3005
|
persistence.logger.debug(`[API] Sending keep alive message: ${thinking}`);
|
|
@@ -3424,7 +3173,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3424
3173
|
updateMetadata(handler) {
|
|
3425
3174
|
this.metadataLock.inLock(async () => {
|
|
3426
3175
|
let rateRefusals = 0;
|
|
3427
|
-
await backoff(async () => {
|
|
3176
|
+
await persistence.backoff(async () => {
|
|
3428
3177
|
let updated = handler(this.metadata);
|
|
3429
3178
|
const answer = await this.socket.emitWithAck("update-metadata", { sid: this.sessionId, expectedVersion: this.metadataVersion, metadata: persistence.encodeBase64(persistence.encrypt(this.encryptionKey, this.encryptionVariant, updated)) });
|
|
3430
3179
|
if (answer.result === "success") {
|
|
@@ -3444,7 +3193,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3444
3193
|
label: "session metadata",
|
|
3445
3194
|
code: answer.error,
|
|
3446
3195
|
attempt: rateRefusals,
|
|
3447
|
-
sleep: delay,
|
|
3196
|
+
sleep: persistence.delay,
|
|
3448
3197
|
log: (message) => persistence.logger.debug(message)
|
|
3449
3198
|
});
|
|
3450
3199
|
}
|
|
@@ -3461,7 +3210,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3461
3210
|
persistence.logger.debugLargeJson("Updating agent state", this.agentState);
|
|
3462
3211
|
this.agentStateLock.inLock(async () => {
|
|
3463
3212
|
let rateRefusals = 0;
|
|
3464
|
-
await backoff(async () => {
|
|
3213
|
+
await persistence.backoff(async () => {
|
|
3465
3214
|
let updated = handler(this.agentState || {});
|
|
3466
3215
|
const answer = await this.socket.emitWithAck("update-state", { sid: this.sessionId, expectedVersion: this.agentStateVersion, agentState: updated ? persistence.encodeBase64(persistence.encrypt(this.encryptionKey, this.encryptionVariant, updated)) : null });
|
|
3467
3216
|
if (answer.result === "success") {
|
|
@@ -3482,7 +3231,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3482
3231
|
label: "session agent state",
|
|
3483
3232
|
code: answer.error,
|
|
3484
3233
|
attempt: rateRefusals,
|
|
3485
|
-
sleep: delay,
|
|
3234
|
+
sleep: persistence.delay,
|
|
3486
3235
|
log: (message) => persistence.logger.debug(message)
|
|
3487
3236
|
});
|
|
3488
3237
|
}
|
|
@@ -3497,7 +3246,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3497
3246
|
async flush() {
|
|
3498
3247
|
await Promise.race([
|
|
3499
3248
|
this.sendSync.invalidateAndAwait(),
|
|
3500
|
-
delay(1e4)
|
|
3249
|
+
persistence.delay(1e4)
|
|
3501
3250
|
]);
|
|
3502
3251
|
if (!this.socket.connected) {
|
|
3503
3252
|
return;
|
|
@@ -4164,7 +3913,7 @@ function attachStartupCommand(sessionId, socket) {
|
|
|
4164
3913
|
return ` TMUX= tmux${sock} attach-session -t ${shellescape(sessionId)}`;
|
|
4165
3914
|
}
|
|
4166
3915
|
|
|
4167
|
-
const TERMINAL_ID_RE
|
|
3916
|
+
const TERMINAL_ID_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
4168
3917
|
function recordGeometry(record) {
|
|
4169
3918
|
return record.cols !== void 0 && record.rows !== void 0 ? { cols: record.cols, rows: record.rows } : {};
|
|
4170
3919
|
}
|
|
@@ -10919,7 +10668,7 @@ class WebTerminalManager {
|
|
|
10919
10668
|
* the stale-client resurrection hole B-149 closed.
|
|
10920
10669
|
*/
|
|
10921
10670
|
restoreClosedTerminal(terminalId) {
|
|
10922
|
-
if (typeof terminalId !== "string" || !TERMINAL_ID_RE
|
|
10671
|
+
if (typeof terminalId !== "string" || !TERMINAL_ID_RE.test(terminalId)) return { type: "error", reason: "invalid-id" };
|
|
10923
10672
|
if (!isTmuxAvailable()) return { type: "error", reason: "no-tmux" };
|
|
10924
10673
|
const record = this.closedTerminals.find((r) => r.id === terminalId);
|
|
10925
10674
|
if (!record) return { type: "error", reason: "no-record" };
|
|
@@ -12124,15 +11873,6 @@ function sendToVhTerminal(terminalId, text, submit) {
|
|
|
12124
11873
|
return { ok: true };
|
|
12125
11874
|
}
|
|
12126
11875
|
|
|
12127
|
-
const SESSION_ID_RE = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
12128
|
-
const TERMINAL_ID_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
12129
|
-
function isValidSessionId(id) {
|
|
12130
|
-
return typeof id === "string" && SESSION_ID_RE.test(id);
|
|
12131
|
-
}
|
|
12132
|
-
function isValidTerminalId(id) {
|
|
12133
|
-
return typeof id === "string" && TERMINAL_ID_RE.test(id);
|
|
12134
|
-
}
|
|
12135
|
-
|
|
12136
11876
|
function parseTerminalHookPayload(body) {
|
|
12137
11877
|
if (!body || typeof body !== "object") return null;
|
|
12138
11878
|
const raw = body;
|
|
@@ -14739,7 +14479,7 @@ class ApiMachineClient {
|
|
|
14739
14479
|
return { type: "success" };
|
|
14740
14480
|
});
|
|
14741
14481
|
this.rpcHandlerManager.registerHandler("mirror-terminal-send", async (params) => {
|
|
14742
|
-
const parsed = parseMirrorSendParams(params, isValidTerminalId);
|
|
14482
|
+
const parsed = parseMirrorSendParams(params, persistence.isValidTerminalId);
|
|
14743
14483
|
if ("error" in parsed) {
|
|
14744
14484
|
throw new Error(parsed.error);
|
|
14745
14485
|
}
|
|
@@ -15155,7 +14895,7 @@ class ApiMachineClient {
|
|
|
15155
14895
|
*/
|
|
15156
14896
|
async updateMachineMetadata(handler) {
|
|
15157
14897
|
let rateRefusals = 0;
|
|
15158
|
-
await backoff(async () => {
|
|
14898
|
+
await persistence.backoff(async () => {
|
|
15159
14899
|
const updated = handler(this.machine.metadata);
|
|
15160
14900
|
const answer = await this.socket.emitWithAck("machine-update-metadata", {
|
|
15161
14901
|
machineId: this.machine.id,
|
|
@@ -15180,7 +14920,7 @@ class ApiMachineClient {
|
|
|
15180
14920
|
label: "machine metadata",
|
|
15181
14921
|
code: answer.error,
|
|
15182
14922
|
attempt: rateRefusals,
|
|
15183
|
-
sleep: delay,
|
|
14923
|
+
sleep: persistence.delay,
|
|
15184
14924
|
log: (message) => persistence.logger.debug(message)
|
|
15185
14925
|
});
|
|
15186
14926
|
}
|
|
@@ -15194,7 +14934,7 @@ class ApiMachineClient {
|
|
|
15194
14934
|
*/
|
|
15195
14935
|
async updateDaemonState(handler) {
|
|
15196
14936
|
let rateRefusals = 0;
|
|
15197
|
-
await backoff(async () => {
|
|
14937
|
+
await persistence.backoff(async () => {
|
|
15198
14938
|
const updated = handler(this.machine.daemonState);
|
|
15199
14939
|
const answer = await this.socket.emitWithAck("machine-update-state", {
|
|
15200
14940
|
machineId: this.machine.id,
|
|
@@ -15219,7 +14959,7 @@ class ApiMachineClient {
|
|
|
15219
14959
|
label: "daemon state",
|
|
15220
14960
|
code: answer.error,
|
|
15221
14961
|
attempt: rateRefusals,
|
|
15222
|
-
sleep: delay,
|
|
14962
|
+
sleep: persistence.delay,
|
|
15223
14963
|
log: (message) => persistence.logger.debug(message)
|
|
15224
14964
|
});
|
|
15225
14965
|
}
|
|
@@ -15862,7 +15602,7 @@ function startOfflineReconnection(config) {
|
|
|
15862
15602
|
};
|
|
15863
15603
|
const healthCheck = config.healthCheck ?? defaultHealthCheck;
|
|
15864
15604
|
const initialDelayMs = config.initialDelayMs ?? 5e3;
|
|
15865
|
-
const retryDelayMs = config.retryDelayMs ?? ((count) => exponentialBackoffDelay(count, 5e3, 6e4, 10));
|
|
15605
|
+
const retryDelayMs = config.retryDelayMs ?? ((count) => persistence.exponentialBackoffDelay(count, 5e3, 6e4, 10));
|
|
15866
15606
|
const attemptReconnect = async () => {
|
|
15867
15607
|
if (reconnected || cancelled) return;
|
|
15868
15608
|
try {
|
|
@@ -16669,15 +16409,12 @@ exports.TITLE_PROMPT_PREFIX = TITLE_PROMPT_PREFIX;
|
|
|
16669
16409
|
exports.TurnActivityTracker = TurnActivityTracker;
|
|
16670
16410
|
exports.agentHomeSpawnEnv = agentHomeSpawnEnv;
|
|
16671
16411
|
exports.api = api;
|
|
16672
|
-
exports.checkIfDaemonRunningAndCleanupStaleState = checkIfDaemonRunningAndCleanupStaleState;
|
|
16673
|
-
exports.cleanupDaemonState = cleanupDaemonState;
|
|
16674
16412
|
exports.commandOnPath = commandOnPath;
|
|
16675
16413
|
exports.compareExactVersions = compareExactVersions;
|
|
16676
16414
|
exports.connectionState = connectionState;
|
|
16677
16415
|
exports.contentLogMetadata = contentLogMetadata;
|
|
16678
16416
|
exports.decideBackfill = decideBackfill;
|
|
16679
16417
|
exports.decideMirrorBinding = decideMirrorBinding;
|
|
16680
|
-
exports.delay = delay;
|
|
16681
16418
|
exports.deriveLocalCliUpdateSummary = deriveLocalCliUpdateSummary;
|
|
16682
16419
|
exports.describeAgentHome = describeAgentHome;
|
|
16683
16420
|
exports.detectCLIAvailability = detectCLIAvailability;
|
|
@@ -16693,22 +16430,13 @@ exports.getProjectPath = getProjectPath;
|
|
|
16693
16430
|
exports.index = index;
|
|
16694
16431
|
exports.initializeSandbox = initializeSandbox;
|
|
16695
16432
|
exports.isClaudeSessionId = isClaudeSessionId;
|
|
16696
|
-
exports.isDaemonRunningCurrentlyInstalledHappyVersion = isDaemonRunningCurrentlyInstalledHappyVersion;
|
|
16697
|
-
exports.isValidSessionId = isValidSessionId;
|
|
16698
|
-
exports.isValidTerminalId = isValidTerminalId;
|
|
16699
|
-
exports.listDaemonSessions = listDaemonSessions;
|
|
16700
16433
|
exports.listVhTerminals = listVhTerminals;
|
|
16701
16434
|
exports.locateClaudeConversation = locateClaudeConversation;
|
|
16702
16435
|
exports.mirrorLineKey = mirrorLineKey;
|
|
16703
16436
|
exports.mirrorLocalId = mirrorLocalId;
|
|
16704
|
-
exports.notifyDaemonClaudeAuthFailed = notifyDaemonClaudeAuthFailed;
|
|
16705
|
-
exports.notifyDaemonSessionEvent = notifyDaemonSessionEvent;
|
|
16706
|
-
exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
|
|
16707
16437
|
exports.parseExactVersion = parseExactVersion;
|
|
16708
16438
|
exports.parseTerminalHookPayload = parseTerminalHookPayload;
|
|
16709
16439
|
exports.probeLoginShellEnv = probeLoginShellEnv;
|
|
16710
|
-
exports.pushClipboardViaDaemon = pushClipboardViaDaemon;
|
|
16711
|
-
exports.pushFilePreviewViaDaemon = pushFilePreviewViaDaemon;
|
|
16712
16440
|
exports.readLocalHappyAgentCredentials = readLocalHappyAgentCredentials;
|
|
16713
16441
|
exports.readVhTerminal = readVhTerminal;
|
|
16714
16442
|
exports.refreshAgentHomes = refreshAgentHomes;
|
|
@@ -16716,12 +16444,8 @@ exports.resolveAgentHomes = resolveAgentHomes;
|
|
|
16716
16444
|
exports.resolveCliUpdateCheckInterval = resolveCliUpdateCheckInterval;
|
|
16717
16445
|
exports.scrubTmuxClientEnv = scrubTmuxClientEnv;
|
|
16718
16446
|
exports.sendToVhTerminal = sendToVhTerminal;
|
|
16719
|
-
exports.setTerminalTitleViaDaemon = setTerminalTitleViaDaemon;
|
|
16720
16447
|
exports.shellescape = shellescape;
|
|
16721
|
-
exports.spawnDaemonSession = spawnDaemonSession;
|
|
16722
16448
|
exports.startOfflineReconnection = startOfflineReconnection;
|
|
16723
|
-
exports.stopDaemon = stopDaemon;
|
|
16724
|
-
exports.stopDaemonSession = stopDaemonSession;
|
|
16725
16449
|
exports.summarizeSpawnSessionForLog = summarizeSpawnSessionForLog;
|
|
16726
16450
|
exports.tmuxArgs = tmuxArgs;
|
|
16727
16451
|
exports.wrapCommand = wrapCommand;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "very-happy-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.155",
|
|
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": [
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
"zod": "^4.0.0"
|
|
118
118
|
},
|
|
119
119
|
"optionalDependencies": {
|
|
120
|
-
"very-happy-tools-arm64-darwin": "0.2.
|
|
121
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
122
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
123
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
124
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
125
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
120
|
+
"very-happy-tools-arm64-darwin": "0.2.155",
|
|
121
|
+
"very-happy-tools-x64-darwin": "0.2.155",
|
|
122
|
+
"very-happy-tools-arm64-linux": "0.2.155",
|
|
123
|
+
"very-happy-tools-x64-linux": "0.2.155",
|
|
124
|
+
"very-happy-tools-arm64-win32": "0.2.155",
|
|
125
|
+
"very-happy-tools-x64-win32": "0.2.155"
|
|
126
126
|
},
|
|
127
127
|
"devDependencies": {
|
|
128
128
|
"@slopus/happy-wire": "workspace:*",
|