very-happy-cli 0.2.154 → 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-Ckyadhf4.mjs → AcpBackend-DVB0nzgR.mjs} +2 -2
- package/dist/{AcpBackend-B14xNj5L.cjs → AcpBackend-DmFcRh54.cjs} +3 -3
- package/dist/{AcpSessionManager-CCHmPdrR.cjs → AcpSessionManager-CWaSYTnT.cjs} +1 -1
- package/dist/{AcpSessionManager-H8t4P-IW.mjs → AcpSessionManager-dGDgNb-p.mjs} +1 -1
- package/dist/agentGuidance-BWxFC6UL.mjs +1613 -0
- package/dist/agentGuidance-un7YPryB.cjs +1665 -0
- package/dist/{agentHome-B20RWdgE.mjs → agentHome-ByLb2HFg.mjs} +5 -5
- package/dist/{agentHome-BUsLTZnz.cjs → agentHome-aucT8BHw.cjs} +5 -5
- package/dist/{auto-BQnncDcs.mjs → auto-BQnD6gVx.mjs} +21 -21
- package/dist/{auto-IeldARBS.cjs → auto-P9RoJaY0.cjs} +24 -24
- package/dist/codex/happyMcpStdioBridge.cjs +6 -3
- package/dist/codex/happyMcpStdioBridge.mjs +6 -3
- package/dist/{config-B-ocQh5V.mjs → config-BPZ2Y6o8.mjs} +8 -8
- package/dist/{config-DM_xI9M6.cjs → config-BoePh9PX.cjs} +8 -8
- package/dist/{index-okLyUzeD.cjs → index--KCpVs1c.cjs} +7 -7
- package/dist/{index-BELV05ko.mjs → index-B4oXnbYw.mjs} +463 -889
- package/dist/{index-ZKuBjvHi.mjs → index-BjzdXb9x.mjs} +21 -13
- package/dist/{index-BUxBxSxJ.cjs → index-DRrLaljt.cjs} +21 -13
- package/dist/{index-CIx3248o.mjs → index-DVVRqaVG.mjs} +7 -7
- package/dist/{index-eCjkm8Y2.cjs → index-D_fYUxVg.cjs} +521 -960
- package/dist/index.cjs +6 -6
- package/dist/index.mjs +6 -6
- package/dist/{install-BZOdxfPd.cjs → install-CGigiocs.cjs} +1 -1
- package/dist/{install-CoLN3whR.mjs → install-DP5aPNEX.mjs} +1 -1
- package/dist/{installTerminalHooks-CA4OcAS7.cjs → installTerminalHooks-XrcPvfBs.cjs} +5 -5
- package/dist/{installTerminalHooks-Dde_8t36.mjs → installTerminalHooks-tIg7mANc.mjs} +5 -5
- package/dist/lib.cjs +2 -2
- package/dist/lib.mjs +2 -2
- package/dist/{limits-Dt7_unH4.mjs → limits-C_DW0M0q.mjs} +309 -13
- package/dist/{limits-CmzISka2.cjs → limits-DkfHJ3nS.cjs} +329 -12
- package/dist/{mcp-7iDHlyCI.cjs → mcp-BqlXl10F.cjs} +23 -23
- package/dist/{mcp-9Ui4nQZL.mjs → mcp-o7QglAQM.mjs} +17 -17
- package/dist/{piRuntime-BesGGPME.cjs → piRuntime-BxP4B_zY.cjs} +2 -2
- package/dist/{piRuntime-C4E4pgye.mjs → piRuntime-MjiJI-nV.mjs} +2 -2
- package/dist/{piTerminal-fUogwxYr.cjs → piTerminal-DYzRcwgb.cjs} +6 -6
- package/dist/{piTerminal-CCEGCQOY.mjs → piTerminal-Dpq6yqKU.mjs} +6 -6
- package/dist/{runGemini-CNPGSsSK.cjs → runGemini-8Pxh94Fm.cjs} +7 -7
- package/dist/{runGemini-BW-pEklU.mjs → runGemini-CDlcQ-OA.mjs} +6 -6
- package/dist/{runOpenClaw-Bsodkg_s.cjs → runOpenClaw-B5FSZIbK.cjs} +6 -6
- package/dist/{runOpenClaw-NRB6-_jU.mjs → runOpenClaw-YkhsgPs0.mjs} +5 -5
- package/dist/{send-Bd00QcHC.cjs → send-CwrYXTPr.cjs} +8 -42
- package/dist/{send-DYeSFg8s.mjs → send-DJStmLBv.mjs} +5 -39
- package/dist/{sessions-DlPOYKLU.mjs → sessions-JaVXlSqj.mjs} +88 -45
- package/dist/{sessions-RIFUoy_g.cjs → sessions-MX21NJXd.cjs} +99 -56
- package/dist/{spawn-D1bhyHbH.mjs → spawn-BaPnjClT.mjs} +22 -22
- package/dist/{spawn-DxrfHTF4.cjs → spawn-cIoglKVf.cjs} +30 -30
- package/dist/{teams-pfKHpkgL.mjs → teams-DXV5Pwwt.mjs} +8 -8
- package/dist/{teams-Cfy0VMCo.cjs → teams-Dqk7F3D-.cjs} +8 -8
- package/dist/{todo-B2CjDg_V.mjs → todo-2Z1REhfx.mjs} +8 -6
- package/dist/{todo-B4cBFzHB.cjs → todo-Buuqn9gm.cjs} +8 -6
- package/dist/{types-D5RWyBE5.mjs → types-CkbfdRzq.mjs} +4 -282
- package/dist/{types-Bd_TGr0F.cjs → types-a2xsH2UI.cjs} +16 -311
- package/package.json +7 -7
- package/dist/agentGuidance-DUBXppv-.cjs +0 -554
- package/dist/agentGuidance-TLYQxsm2.mjs +0 -530
|
@@ -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');
|
|
@@ -353,41 +353,6 @@ const AgentMessageSchema = z.z.object({
|
|
|
353
353
|
});
|
|
354
354
|
z.z.union([UserMessageSchema, AgentMessageSchema]);
|
|
355
355
|
|
|
356
|
-
async function delay(ms) {
|
|
357
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
358
|
-
}
|
|
359
|
-
function exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount) {
|
|
360
|
-
let maxDelayRet = minDelay + (maxDelay - minDelay) / maxFailureCount * Math.min(currentFailureCount, maxFailureCount);
|
|
361
|
-
return Math.round(Math.random() * maxDelayRet);
|
|
362
|
-
}
|
|
363
|
-
function createBackoff(opts) {
|
|
364
|
-
return async (callback) => {
|
|
365
|
-
let currentFailureCount = 0;
|
|
366
|
-
const minDelay = opts && opts.minDelay !== void 0 ? opts.minDelay : 250;
|
|
367
|
-
const maxDelay = opts && opts.maxDelay !== void 0 ? opts.maxDelay : 1e3;
|
|
368
|
-
const maxFailureCount = opts && opts.maxFailureCount !== void 0 ? opts.maxFailureCount : 50;
|
|
369
|
-
while (true) {
|
|
370
|
-
try {
|
|
371
|
-
return await callback();
|
|
372
|
-
} catch (e) {
|
|
373
|
-
if (currentFailureCount < maxFailureCount) {
|
|
374
|
-
currentFailureCount++;
|
|
375
|
-
}
|
|
376
|
-
if (opts && opts.onError) {
|
|
377
|
-
opts.onError(e, currentFailureCount);
|
|
378
|
-
}
|
|
379
|
-
let waitForRequest = exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount);
|
|
380
|
-
await delay(waitForRequest);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
let backoff = createBackoff({
|
|
386
|
-
onError: (e, failuresCount) => {
|
|
387
|
-
persistence.logger.debug(`[BACKOFF] retry ${failuresCount}:`, e?.message || e);
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
|
|
391
356
|
function isRateQuotaCode(code) {
|
|
392
357
|
return typeof code === "string" && code.endsWith("_rate_quota_exceeded");
|
|
393
358
|
}
|
|
@@ -2084,7 +2049,7 @@ class InvalidateSync {
|
|
|
2084
2049
|
this._pendings = [];
|
|
2085
2050
|
};
|
|
2086
2051
|
_doSync = async () => {
|
|
2087
|
-
await backoff(async () => {
|
|
2052
|
+
await persistence.backoff(async () => {
|
|
2088
2053
|
if (this._stopped) {
|
|
2089
2054
|
return;
|
|
2090
2055
|
}
|
|
@@ -2242,240 +2207,6 @@ class TurnReporter {
|
|
|
2242
2207
|
}
|
|
2243
2208
|
}
|
|
2244
2209
|
|
|
2245
|
-
function daemonControlHeaders(controlToken) {
|
|
2246
|
-
return {
|
|
2247
|
-
"Content-Type": "application/json",
|
|
2248
|
-
...controlToken ? { Authorization: `Bearer ${controlToken}` } : {}
|
|
2249
|
-
};
|
|
2250
|
-
}
|
|
2251
|
-
async function daemonPost(path, body) {
|
|
2252
|
-
const state = await persistence.readDaemonState();
|
|
2253
|
-
if (!state?.httpPort) {
|
|
2254
|
-
const errorMessage = "No daemon running, no state file found";
|
|
2255
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2256
|
-
return {
|
|
2257
|
-
error: errorMessage
|
|
2258
|
-
};
|
|
2259
|
-
}
|
|
2260
|
-
try {
|
|
2261
|
-
process.kill(state.pid, 0);
|
|
2262
|
-
} catch (error) {
|
|
2263
|
-
const errorMessage = "Daemon is not running, file is stale";
|
|
2264
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2265
|
-
return {
|
|
2266
|
-
error: errorMessage
|
|
2267
|
-
};
|
|
2268
|
-
}
|
|
2269
|
-
try {
|
|
2270
|
-
const timeout = process.env.HAPPY_DAEMON_HTTP_TIMEOUT ? parseInt(process.env.HAPPY_DAEMON_HTTP_TIMEOUT) : 1e4;
|
|
2271
|
-
const response = await fetch(`http://127.0.0.1:${state.httpPort}${path}`, {
|
|
2272
|
-
method: "POST",
|
|
2273
|
-
// A state written by an old daemon has no token and must remain callable;
|
|
2274
|
-
// a new daemon always writes one and rejects requests without it.
|
|
2275
|
-
headers: daemonControlHeaders(state.controlToken),
|
|
2276
|
-
body: JSON.stringify(body || {}),
|
|
2277
|
-
// Mostly increased for stress test
|
|
2278
|
-
signal: AbortSignal.timeout(timeout)
|
|
2279
|
-
});
|
|
2280
|
-
if (!response.ok) {
|
|
2281
|
-
const failure = await response.json().catch(() => null);
|
|
2282
|
-
const reason = typeof failure?.error === "string" && failure.error ? failure.error : `HTTP ${response.status}`;
|
|
2283
|
-
const errorMessage = `Request failed: ${path}, ${reason}`;
|
|
2284
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2285
|
-
return {
|
|
2286
|
-
error: errorMessage
|
|
2287
|
-
};
|
|
2288
|
-
}
|
|
2289
|
-
return await response.json();
|
|
2290
|
-
} catch (error) {
|
|
2291
|
-
const errorMessage = `Request failed: ${path}, ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
2292
|
-
persistence.logger.debug(`[CONTROL CLIENT] ${errorMessage}`);
|
|
2293
|
-
return {
|
|
2294
|
-
error: errorMessage
|
|
2295
|
-
};
|
|
2296
|
-
}
|
|
2297
|
-
}
|
|
2298
|
-
const SESSION_STARTED_RETRY_TIMEOUT_MS = 3e3;
|
|
2299
|
-
const SESSION_STARTED_RETRY_INTERVAL_MS = 100;
|
|
2300
|
-
async function notifyDaemonSessionStarted(sessionId, metadata, encryption) {
|
|
2301
|
-
const payload = { sessionId, metadata, encryption };
|
|
2302
|
-
const deadline = Date.now() + SESSION_STARTED_RETRY_TIMEOUT_MS;
|
|
2303
|
-
let result;
|
|
2304
|
-
while (true) {
|
|
2305
|
-
result = await daemonPost("/session-started", payload);
|
|
2306
|
-
if (!result?.error) {
|
|
2307
|
-
return result;
|
|
2308
|
-
}
|
|
2309
|
-
if (Date.now() >= deadline) {
|
|
2310
|
-
return result;
|
|
2311
|
-
}
|
|
2312
|
-
await new Promise((resolve) => setTimeout(resolve, SESSION_STARTED_RETRY_INTERVAL_MS));
|
|
2313
|
-
}
|
|
2314
|
-
}
|
|
2315
|
-
async function listDaemonSessions() {
|
|
2316
|
-
const result = await daemonPost("/list");
|
|
2317
|
-
return result.children || [];
|
|
2318
|
-
}
|
|
2319
|
-
async function stopDaemonSession(sessionId) {
|
|
2320
|
-
const result = await daemonPost("/stop-session", { sessionId });
|
|
2321
|
-
return result.success || false;
|
|
2322
|
-
}
|
|
2323
|
-
async function spawnDaemonSession(directory, sessionId, opts) {
|
|
2324
|
-
const result = await daemonPost("/spawn-session", {
|
|
2325
|
-
directory,
|
|
2326
|
-
sessionId,
|
|
2327
|
-
spawnedBy: opts?.spawnedBy,
|
|
2328
|
-
permissionMode: opts?.permissionMode,
|
|
2329
|
-
agent: opts?.agent,
|
|
2330
|
-
environmentVariables: opts?.environmentVariables,
|
|
2331
|
-
resumeClaudeSessionId: opts?.resumeClaudeSessionId,
|
|
2332
|
-
resumeCodexThreadId: opts?.resumeCodexThreadId,
|
|
2333
|
-
parentSessionId: opts?.parentSessionId
|
|
2334
|
-
});
|
|
2335
|
-
return result;
|
|
2336
|
-
}
|
|
2337
|
-
const ROUTE_NOT_FOUND_RE = /, (Not Found|HTTP 404)$/;
|
|
2338
|
-
async function resumeDaemonSession(sessionId, opts) {
|
|
2339
|
-
const result = await daemonPost("/resume-session", {
|
|
2340
|
-
sessionId,
|
|
2341
|
-
...opts?.model !== void 0 ? { model: opts.model } : {},
|
|
2342
|
-
...opts?.permissionMode !== void 0 ? { permissionMode: opts.permissionMode } : {}
|
|
2343
|
-
});
|
|
2344
|
-
if (result?.error) {
|
|
2345
|
-
const raw = String(result.error);
|
|
2346
|
-
const error = ROUTE_NOT_FOUND_RE.test(raw) ? "daemon too old to resume sessions (no /resume-session route); upgrade very-happy-cli and run `very-happy daemon start`" : raw.replace(/^Request failed: \/resume-session, /, "");
|
|
2347
|
-
return { success: false, error };
|
|
2348
|
-
}
|
|
2349
|
-
if (result?.success === true && typeof result.sessionId === "string") {
|
|
2350
|
-
return { success: true, sessionId: result.sessionId };
|
|
2351
|
-
}
|
|
2352
|
-
return { success: false, error: typeof result?.error === "string" ? result.error : "unexpected daemon response" };
|
|
2353
|
-
}
|
|
2354
|
-
async function notifyDaemonSessionEvent(sessionId, event, spawnedBy) {
|
|
2355
|
-
return daemonPost("/session-event", { sessionId, event, spawnedBy });
|
|
2356
|
-
}
|
|
2357
|
-
async function notifyDaemonClaudeAuthFailed(sessionId) {
|
|
2358
|
-
return daemonPost("/session-event", { sessionId, event: "auth_failed" });
|
|
2359
|
-
}
|
|
2360
|
-
async function notifyDaemonTurnEvent(sessionId, event) {
|
|
2361
|
-
return daemonPost("/session-event", { sessionId, event });
|
|
2362
|
-
}
|
|
2363
|
-
async function stopDaemonHttp() {
|
|
2364
|
-
await daemonPost("/stop");
|
|
2365
|
-
}
|
|
2366
|
-
async function pushClipboardViaDaemon(text, terminalId) {
|
|
2367
|
-
const result = await daemonPost("/clipboard", { text, ...terminalId ? { terminalId } : {} });
|
|
2368
|
-
if (result?.error && result.delivered === void 0) {
|
|
2369
|
-
return { delivered: false, error: result.error };
|
|
2370
|
-
}
|
|
2371
|
-
return result;
|
|
2372
|
-
}
|
|
2373
|
-
async function pushFilePreviewViaDaemon(terminalId, path, mode = "file") {
|
|
2374
|
-
const result = await daemonPost("/file-preview", { terminalId, path, mode });
|
|
2375
|
-
if (result?.error) return { delivered: false, error: result.error };
|
|
2376
|
-
return { delivered: result?.delivered === true, ...result?.delivered === true ? {} : { error: "preview was not delivered" } };
|
|
2377
|
-
}
|
|
2378
|
-
async function setTerminalTitleViaDaemon(terminalId, title, ifAbsent = false) {
|
|
2379
|
-
const result = await daemonPost("/terminal-title", { terminalId, title, ifAbsent });
|
|
2380
|
-
if (result?.error) {
|
|
2381
|
-
return { ok: false, error: result.error };
|
|
2382
|
-
}
|
|
2383
|
-
return { ok: result?.status === "ok", error: result?.status === "ok" ? void 0 : "unexpected daemon response" };
|
|
2384
|
-
}
|
|
2385
|
-
async function checkIfDaemonRunningAndCleanupStaleState() {
|
|
2386
|
-
const state = await persistence.readDaemonState();
|
|
2387
|
-
if (!state) {
|
|
2388
|
-
return false;
|
|
2389
|
-
}
|
|
2390
|
-
try {
|
|
2391
|
-
process.kill(state.pid, 0);
|
|
2392
|
-
} catch {
|
|
2393
|
-
persistence.logger.debug("[DAEMON RUN] Daemon PID not running, cleaning up state");
|
|
2394
|
-
await cleanupDaemonState();
|
|
2395
|
-
return false;
|
|
2396
|
-
}
|
|
2397
|
-
if (state.httpPort) {
|
|
2398
|
-
try {
|
|
2399
|
-
const response = await fetch(`http://127.0.0.1:${state.httpPort}/list`, {
|
|
2400
|
-
method: "POST",
|
|
2401
|
-
headers: daemonControlHeaders(state.controlToken),
|
|
2402
|
-
body: "{}",
|
|
2403
|
-
signal: AbortSignal.timeout(2e3)
|
|
2404
|
-
});
|
|
2405
|
-
if (response.ok) {
|
|
2406
|
-
return true;
|
|
2407
|
-
}
|
|
2408
|
-
} catch {
|
|
2409
|
-
persistence.logger.debug(`[DAEMON RUN] PID ${state.pid} is alive but HTTP health check failed on port ${state.httpPort}, cleaning up stale state`);
|
|
2410
|
-
await cleanupDaemonState();
|
|
2411
|
-
return false;
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
return true;
|
|
2415
|
-
}
|
|
2416
|
-
async function isDaemonRunningCurrentlyInstalledHappyVersion() {
|
|
2417
|
-
persistence.logger.debug("[DAEMON CONTROL] Checking if daemon is running same version");
|
|
2418
|
-
const runningDaemon = await checkIfDaemonRunningAndCleanupStaleState();
|
|
2419
|
-
if (!runningDaemon) {
|
|
2420
|
-
persistence.logger.debug("[DAEMON CONTROL] No daemon running, returning false");
|
|
2421
|
-
return false;
|
|
2422
|
-
}
|
|
2423
|
-
const state = await persistence.readDaemonState();
|
|
2424
|
-
if (!state) {
|
|
2425
|
-
persistence.logger.debug("[DAEMON CONTROL] No daemon state found, returning false");
|
|
2426
|
-
return false;
|
|
2427
|
-
}
|
|
2428
|
-
const currentCliVersion = persistence.configuration.currentCliVersion;
|
|
2429
|
-
persistence.logger.debug(`[DAEMON CONTROL] Current CLI version: ${currentCliVersion}, Daemon started with version: ${state.startedWithCliVersion}`);
|
|
2430
|
-
return currentCliVersion === state.startedWithCliVersion;
|
|
2431
|
-
}
|
|
2432
|
-
async function cleanupDaemonState() {
|
|
2433
|
-
try {
|
|
2434
|
-
await persistence.clearDaemonState();
|
|
2435
|
-
persistence.logger.debug("[DAEMON RUN] Daemon state file removed");
|
|
2436
|
-
} catch (error) {
|
|
2437
|
-
persistence.logger.debug("[DAEMON RUN] Error cleaning up daemon metadata", error);
|
|
2438
|
-
}
|
|
2439
|
-
}
|
|
2440
|
-
async function stopDaemon() {
|
|
2441
|
-
try {
|
|
2442
|
-
const state = await persistence.readDaemonState();
|
|
2443
|
-
if (!state) {
|
|
2444
|
-
persistence.logger.debug("No daemon state found");
|
|
2445
|
-
return;
|
|
2446
|
-
}
|
|
2447
|
-
persistence.logger.debug(`Stopping daemon with PID ${state.pid}`);
|
|
2448
|
-
try {
|
|
2449
|
-
await stopDaemonHttp();
|
|
2450
|
-
await waitForProcessDeath(state.pid, 2e3);
|
|
2451
|
-
persistence.logger.debug("Daemon stopped gracefully via HTTP");
|
|
2452
|
-
return;
|
|
2453
|
-
} catch (error) {
|
|
2454
|
-
persistence.logger.debug("HTTP stop failed, will force kill", error);
|
|
2455
|
-
}
|
|
2456
|
-
try {
|
|
2457
|
-
process.kill(state.pid, "SIGKILL");
|
|
2458
|
-
persistence.logger.debug("Force killed daemon");
|
|
2459
|
-
} catch (error) {
|
|
2460
|
-
persistence.logger.debug("Daemon already dead");
|
|
2461
|
-
}
|
|
2462
|
-
} catch (error) {
|
|
2463
|
-
persistence.logger.debug("Error stopping daemon", error);
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
async function waitForProcessDeath(pid, timeout) {
|
|
2467
|
-
const start = Date.now();
|
|
2468
|
-
while (Date.now() - start < timeout) {
|
|
2469
|
-
try {
|
|
2470
|
-
process.kill(pid, 0);
|
|
2471
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2472
|
-
} catch {
|
|
2473
|
-
return;
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2476
|
-
throw new Error("Process did not die within timeout");
|
|
2477
|
-
}
|
|
2478
|
-
|
|
2479
2210
|
class ApiSessionClient extends node_events.EventEmitter {
|
|
2480
2211
|
token;
|
|
2481
2212
|
sessionId;
|
|
@@ -3268,7 +2999,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3268
2999
|
*/
|
|
3269
3000
|
/** B-466: turn edges (and a periodic lease) reported to the local daemon so
|
|
3270
3001
|
* auto-update waits for "no turn in flight" instead of "no sessions". */
|
|
3271
|
-
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)));
|
|
3272
3003
|
keepAlive(thinking, mode) {
|
|
3273
3004
|
if (process.env.DEBUG) {
|
|
3274
3005
|
persistence.logger.debug(`[API] Sending keep alive message: ${thinking}`);
|
|
@@ -3442,7 +3173,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3442
3173
|
updateMetadata(handler) {
|
|
3443
3174
|
this.metadataLock.inLock(async () => {
|
|
3444
3175
|
let rateRefusals = 0;
|
|
3445
|
-
await backoff(async () => {
|
|
3176
|
+
await persistence.backoff(async () => {
|
|
3446
3177
|
let updated = handler(this.metadata);
|
|
3447
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)) });
|
|
3448
3179
|
if (answer.result === "success") {
|
|
@@ -3462,7 +3193,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3462
3193
|
label: "session metadata",
|
|
3463
3194
|
code: answer.error,
|
|
3464
3195
|
attempt: rateRefusals,
|
|
3465
|
-
sleep: delay,
|
|
3196
|
+
sleep: persistence.delay,
|
|
3466
3197
|
log: (message) => persistence.logger.debug(message)
|
|
3467
3198
|
});
|
|
3468
3199
|
}
|
|
@@ -3479,7 +3210,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3479
3210
|
persistence.logger.debugLargeJson("Updating agent state", this.agentState);
|
|
3480
3211
|
this.agentStateLock.inLock(async () => {
|
|
3481
3212
|
let rateRefusals = 0;
|
|
3482
|
-
await backoff(async () => {
|
|
3213
|
+
await persistence.backoff(async () => {
|
|
3483
3214
|
let updated = handler(this.agentState || {});
|
|
3484
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 });
|
|
3485
3216
|
if (answer.result === "success") {
|
|
@@ -3500,7 +3231,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3500
3231
|
label: "session agent state",
|
|
3501
3232
|
code: answer.error,
|
|
3502
3233
|
attempt: rateRefusals,
|
|
3503
|
-
sleep: delay,
|
|
3234
|
+
sleep: persistence.delay,
|
|
3504
3235
|
log: (message) => persistence.logger.debug(message)
|
|
3505
3236
|
});
|
|
3506
3237
|
}
|
|
@@ -3515,7 +3246,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3515
3246
|
async flush() {
|
|
3516
3247
|
await Promise.race([
|
|
3517
3248
|
this.sendSync.invalidateAndAwait(),
|
|
3518
|
-
delay(1e4)
|
|
3249
|
+
persistence.delay(1e4)
|
|
3519
3250
|
]);
|
|
3520
3251
|
if (!this.socket.connected) {
|
|
3521
3252
|
return;
|
|
@@ -4182,7 +3913,7 @@ function attachStartupCommand(sessionId, socket) {
|
|
|
4182
3913
|
return ` TMUX= tmux${sock} attach-session -t ${shellescape(sessionId)}`;
|
|
4183
3914
|
}
|
|
4184
3915
|
|
|
4185
|
-
const TERMINAL_ID_RE
|
|
3916
|
+
const TERMINAL_ID_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
4186
3917
|
function recordGeometry(record) {
|
|
4187
3918
|
return record.cols !== void 0 && record.rows !== void 0 ? { cols: record.cols, rows: record.rows } : {};
|
|
4188
3919
|
}
|
|
@@ -10937,7 +10668,7 @@ class WebTerminalManager {
|
|
|
10937
10668
|
* the stale-client resurrection hole B-149 closed.
|
|
10938
10669
|
*/
|
|
10939
10670
|
restoreClosedTerminal(terminalId) {
|
|
10940
|
-
if (typeof terminalId !== "string" || !TERMINAL_ID_RE
|
|
10671
|
+
if (typeof terminalId !== "string" || !TERMINAL_ID_RE.test(terminalId)) return { type: "error", reason: "invalid-id" };
|
|
10941
10672
|
if (!isTmuxAvailable()) return { type: "error", reason: "no-tmux" };
|
|
10942
10673
|
const record = this.closedTerminals.find((r) => r.id === terminalId);
|
|
10943
10674
|
if (!record) return { type: "error", reason: "no-record" };
|
|
@@ -12142,15 +11873,6 @@ function sendToVhTerminal(terminalId, text, submit) {
|
|
|
12142
11873
|
return { ok: true };
|
|
12143
11874
|
}
|
|
12144
11875
|
|
|
12145
|
-
const SESSION_ID_RE = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
12146
|
-
const TERMINAL_ID_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
12147
|
-
function isValidSessionId(id) {
|
|
12148
|
-
return typeof id === "string" && SESSION_ID_RE.test(id);
|
|
12149
|
-
}
|
|
12150
|
-
function isValidTerminalId(id) {
|
|
12151
|
-
return typeof id === "string" && TERMINAL_ID_RE.test(id);
|
|
12152
|
-
}
|
|
12153
|
-
|
|
12154
11876
|
function parseTerminalHookPayload(body) {
|
|
12155
11877
|
if (!body || typeof body !== "object") return null;
|
|
12156
11878
|
const raw = body;
|
|
@@ -14757,7 +14479,7 @@ class ApiMachineClient {
|
|
|
14757
14479
|
return { type: "success" };
|
|
14758
14480
|
});
|
|
14759
14481
|
this.rpcHandlerManager.registerHandler("mirror-terminal-send", async (params) => {
|
|
14760
|
-
const parsed = parseMirrorSendParams(params, isValidTerminalId);
|
|
14482
|
+
const parsed = parseMirrorSendParams(params, persistence.isValidTerminalId);
|
|
14761
14483
|
if ("error" in parsed) {
|
|
14762
14484
|
throw new Error(parsed.error);
|
|
14763
14485
|
}
|
|
@@ -15173,7 +14895,7 @@ class ApiMachineClient {
|
|
|
15173
14895
|
*/
|
|
15174
14896
|
async updateMachineMetadata(handler) {
|
|
15175
14897
|
let rateRefusals = 0;
|
|
15176
|
-
await backoff(async () => {
|
|
14898
|
+
await persistence.backoff(async () => {
|
|
15177
14899
|
const updated = handler(this.machine.metadata);
|
|
15178
14900
|
const answer = await this.socket.emitWithAck("machine-update-metadata", {
|
|
15179
14901
|
machineId: this.machine.id,
|
|
@@ -15198,7 +14920,7 @@ class ApiMachineClient {
|
|
|
15198
14920
|
label: "machine metadata",
|
|
15199
14921
|
code: answer.error,
|
|
15200
14922
|
attempt: rateRefusals,
|
|
15201
|
-
sleep: delay,
|
|
14923
|
+
sleep: persistence.delay,
|
|
15202
14924
|
log: (message) => persistence.logger.debug(message)
|
|
15203
14925
|
});
|
|
15204
14926
|
}
|
|
@@ -15212,7 +14934,7 @@ class ApiMachineClient {
|
|
|
15212
14934
|
*/
|
|
15213
14935
|
async updateDaemonState(handler) {
|
|
15214
14936
|
let rateRefusals = 0;
|
|
15215
|
-
await backoff(async () => {
|
|
14937
|
+
await persistence.backoff(async () => {
|
|
15216
14938
|
const updated = handler(this.machine.daemonState);
|
|
15217
14939
|
const answer = await this.socket.emitWithAck("machine-update-state", {
|
|
15218
14940
|
machineId: this.machine.id,
|
|
@@ -15237,7 +14959,7 @@ class ApiMachineClient {
|
|
|
15237
14959
|
label: "daemon state",
|
|
15238
14960
|
code: answer.error,
|
|
15239
14961
|
attempt: rateRefusals,
|
|
15240
|
-
sleep: delay,
|
|
14962
|
+
sleep: persistence.delay,
|
|
15241
14963
|
log: (message) => persistence.logger.debug(message)
|
|
15242
14964
|
});
|
|
15243
14965
|
}
|
|
@@ -15880,7 +15602,7 @@ function startOfflineReconnection(config) {
|
|
|
15880
15602
|
};
|
|
15881
15603
|
const healthCheck = config.healthCheck ?? defaultHealthCheck;
|
|
15882
15604
|
const initialDelayMs = config.initialDelayMs ?? 5e3;
|
|
15883
|
-
const retryDelayMs = config.retryDelayMs ?? ((count) => exponentialBackoffDelay(count, 5e3, 6e4, 10));
|
|
15605
|
+
const retryDelayMs = config.retryDelayMs ?? ((count) => persistence.exponentialBackoffDelay(count, 5e3, 6e4, 10));
|
|
15884
15606
|
const attemptReconnect = async () => {
|
|
15885
15607
|
if (reconnected || cancelled) return;
|
|
15886
15608
|
try {
|
|
@@ -16687,15 +16409,12 @@ exports.TITLE_PROMPT_PREFIX = TITLE_PROMPT_PREFIX;
|
|
|
16687
16409
|
exports.TurnActivityTracker = TurnActivityTracker;
|
|
16688
16410
|
exports.agentHomeSpawnEnv = agentHomeSpawnEnv;
|
|
16689
16411
|
exports.api = api;
|
|
16690
|
-
exports.checkIfDaemonRunningAndCleanupStaleState = checkIfDaemonRunningAndCleanupStaleState;
|
|
16691
|
-
exports.cleanupDaemonState = cleanupDaemonState;
|
|
16692
16412
|
exports.commandOnPath = commandOnPath;
|
|
16693
16413
|
exports.compareExactVersions = compareExactVersions;
|
|
16694
16414
|
exports.connectionState = connectionState;
|
|
16695
16415
|
exports.contentLogMetadata = contentLogMetadata;
|
|
16696
16416
|
exports.decideBackfill = decideBackfill;
|
|
16697
16417
|
exports.decideMirrorBinding = decideMirrorBinding;
|
|
16698
|
-
exports.delay = delay;
|
|
16699
16418
|
exports.deriveLocalCliUpdateSummary = deriveLocalCliUpdateSummary;
|
|
16700
16419
|
exports.describeAgentHome = describeAgentHome;
|
|
16701
16420
|
exports.detectCLIAvailability = detectCLIAvailability;
|
|
@@ -16711,36 +16430,22 @@ exports.getProjectPath = getProjectPath;
|
|
|
16711
16430
|
exports.index = index;
|
|
16712
16431
|
exports.initializeSandbox = initializeSandbox;
|
|
16713
16432
|
exports.isClaudeSessionId = isClaudeSessionId;
|
|
16714
|
-
exports.isDaemonRunningCurrentlyInstalledHappyVersion = isDaemonRunningCurrentlyInstalledHappyVersion;
|
|
16715
|
-
exports.isValidSessionId = isValidSessionId;
|
|
16716
|
-
exports.isValidTerminalId = isValidTerminalId;
|
|
16717
|
-
exports.listDaemonSessions = listDaemonSessions;
|
|
16718
16433
|
exports.listVhTerminals = listVhTerminals;
|
|
16719
16434
|
exports.locateClaudeConversation = locateClaudeConversation;
|
|
16720
16435
|
exports.mirrorLineKey = mirrorLineKey;
|
|
16721
16436
|
exports.mirrorLocalId = mirrorLocalId;
|
|
16722
|
-
exports.notifyDaemonClaudeAuthFailed = notifyDaemonClaudeAuthFailed;
|
|
16723
|
-
exports.notifyDaemonSessionEvent = notifyDaemonSessionEvent;
|
|
16724
|
-
exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
|
|
16725
16437
|
exports.parseExactVersion = parseExactVersion;
|
|
16726
16438
|
exports.parseTerminalHookPayload = parseTerminalHookPayload;
|
|
16727
16439
|
exports.probeLoginShellEnv = probeLoginShellEnv;
|
|
16728
|
-
exports.pushClipboardViaDaemon = pushClipboardViaDaemon;
|
|
16729
|
-
exports.pushFilePreviewViaDaemon = pushFilePreviewViaDaemon;
|
|
16730
16440
|
exports.readLocalHappyAgentCredentials = readLocalHappyAgentCredentials;
|
|
16731
16441
|
exports.readVhTerminal = readVhTerminal;
|
|
16732
16442
|
exports.refreshAgentHomes = refreshAgentHomes;
|
|
16733
16443
|
exports.resolveAgentHomes = resolveAgentHomes;
|
|
16734
16444
|
exports.resolveCliUpdateCheckInterval = resolveCliUpdateCheckInterval;
|
|
16735
|
-
exports.resumeDaemonSession = resumeDaemonSession;
|
|
16736
16445
|
exports.scrubTmuxClientEnv = scrubTmuxClientEnv;
|
|
16737
16446
|
exports.sendToVhTerminal = sendToVhTerminal;
|
|
16738
|
-
exports.setTerminalTitleViaDaemon = setTerminalTitleViaDaemon;
|
|
16739
16447
|
exports.shellescape = shellescape;
|
|
16740
|
-
exports.spawnDaemonSession = spawnDaemonSession;
|
|
16741
16448
|
exports.startOfflineReconnection = startOfflineReconnection;
|
|
16742
|
-
exports.stopDaemon = stopDaemon;
|
|
16743
|
-
exports.stopDaemonSession = stopDaemonSession;
|
|
16744
16449
|
exports.summarizeSpawnSessionForLog = summarizeSpawnSessionForLog;
|
|
16745
16450
|
exports.tmuxArgs = tmuxArgs;
|
|
16746
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:*",
|