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.
Files changed (55) hide show
  1. package/dist/{AcpBackend-YDGv4E-g.mjs → AcpBackend-DVB0nzgR.mjs} +2 -2
  2. package/dist/{AcpBackend-DSt8nTYm.cjs → AcpBackend-DmFcRh54.cjs} +3 -3
  3. package/dist/{AcpSessionManager-uov6I9C8.cjs → AcpSessionManager-CWaSYTnT.cjs} +1 -1
  4. package/dist/{AcpSessionManager-Cxf5HQX1.mjs → AcpSessionManager-dGDgNb-p.mjs} +1 -1
  5. package/dist/agentGuidance-BWxFC6UL.mjs +1613 -0
  6. package/dist/agentGuidance-un7YPryB.cjs +1665 -0
  7. package/dist/{agentHome-D68Xh2ae.mjs → agentHome-ByLb2HFg.mjs} +5 -5
  8. package/dist/{agentHome-BJ7bde35.cjs → agentHome-aucT8BHw.cjs} +5 -5
  9. package/dist/{auto-CcXxfqkC.mjs → auto-BQnD6gVx.mjs} +21 -21
  10. package/dist/{auto-C-90ojIH.cjs → auto-P9RoJaY0.cjs} +24 -24
  11. package/dist/codex/happyMcpStdioBridge.cjs +6 -3
  12. package/dist/codex/happyMcpStdioBridge.mjs +6 -3
  13. package/dist/{config-CHJ189UJ.mjs → config-BPZ2Y6o8.mjs} +8 -8
  14. package/dist/{config-D23kF0_u.cjs → config-BoePh9PX.cjs} +8 -8
  15. package/dist/{index-D49WvbDT.cjs → index--KCpVs1c.cjs} +7 -7
  16. package/dist/{index-BacwoXzs.mjs → index-B4oXnbYw.mjs} +522 -729
  17. package/dist/{index-BgYZGODP.mjs → index-BjzdXb9x.mjs} +21 -13
  18. package/dist/{index-DEOVn46R.cjs → index-DRrLaljt.cjs} +21 -13
  19. package/dist/{index-BXA9fxbK.mjs → index-DVVRqaVG.mjs} +7 -7
  20. package/dist/{index-DHrwHxHf.cjs → index-D_fYUxVg.cjs} +579 -798
  21. package/dist/index.cjs +6 -6
  22. package/dist/index.mjs +6 -6
  23. package/dist/{install-BiOXBnnS.cjs → install-CGigiocs.cjs} +1 -1
  24. package/dist/{install-Ca7_Z3bV.mjs → install-DP5aPNEX.mjs} +1 -1
  25. package/dist/{installTerminalHooks-BF0kL0ae.cjs → installTerminalHooks-XrcPvfBs.cjs} +5 -5
  26. package/dist/{installTerminalHooks-Bpl32K75.mjs → installTerminalHooks-tIg7mANc.mjs} +5 -5
  27. package/dist/lib.cjs +2 -2
  28. package/dist/lib.mjs +2 -2
  29. package/dist/{limits-BtAuKRl2.mjs → limits-C_DW0M0q.mjs} +309 -13
  30. package/dist/{limits-DY_sFA3J.cjs → limits-DkfHJ3nS.cjs} +329 -12
  31. package/dist/{mcp-JpqI2POW.cjs → mcp-BqlXl10F.cjs} +23 -23
  32. package/dist/{mcp-DQkmk4VV.mjs → mcp-o7QglAQM.mjs} +17 -17
  33. package/dist/{piRuntime-DRbbeQ72.cjs → piRuntime-BxP4B_zY.cjs} +2 -2
  34. package/dist/{piRuntime-DBpe12NN.mjs → piRuntime-MjiJI-nV.mjs} +2 -2
  35. package/dist/{piTerminal-qdJ9KZVL.cjs → piTerminal-DYzRcwgb.cjs} +6 -6
  36. package/dist/{piTerminal-BoHvPEZ_.mjs → piTerminal-Dpq6yqKU.mjs} +6 -6
  37. package/dist/{runGemini-CtOEFvhf.cjs → runGemini-8Pxh94Fm.cjs} +7 -7
  38. package/dist/{runGemini-YqH7a-7O.mjs → runGemini-CDlcQ-OA.mjs} +6 -6
  39. package/dist/{runOpenClaw-DoqZXBvL.cjs → runOpenClaw-B5FSZIbK.cjs} +6 -6
  40. package/dist/{runOpenClaw-DSSyFQBb.mjs → runOpenClaw-YkhsgPs0.mjs} +5 -5
  41. package/dist/{send-9075kHZP.cjs → send-CwrYXTPr.cjs} +58 -54
  42. package/dist/{send-Cs-RwqNf.mjs → send-DJStmLBv.mjs} +56 -53
  43. package/dist/{sessions-iBnYzVUK.mjs → sessions-JaVXlSqj.mjs} +88 -45
  44. package/dist/{sessions-qULzUzlI.cjs → sessions-MX21NJXd.cjs} +99 -56
  45. package/dist/{spawn-C6fRkedx.mjs → spawn-BaPnjClT.mjs} +22 -22
  46. package/dist/{spawn-od9V23cc.cjs → spawn-cIoglKVf.cjs} +30 -30
  47. package/dist/{teams-CkrWQ4uM.mjs → teams-DXV5Pwwt.mjs} +8 -8
  48. package/dist/{teams-CrCzU-AV.cjs → teams-Dqk7F3D-.cjs} +8 -8
  49. package/dist/{todo-aCZmSt27.mjs → todo-2Z1REhfx.mjs} +8 -6
  50. package/dist/{todo-BCT_ZPuV.cjs → todo-Buuqn9gm.cjs} +8 -6
  51. package/dist/{types-BvqOVUOW.mjs → types-CkbfdRzq.mjs} +7 -267
  52. package/dist/{types-CUCU7Vw8.cjs → types-a2xsH2UI.cjs} +19 -295
  53. package/package.json +7 -7
  54. package/dist/agentGuidance-BM4kMNyr.cjs +0 -553
  55. 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-DY_sFA3J.cjs');
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. Pinned separately
98
- * from `recommendedVersion`; null means no unattended install. */
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$1 = /^[a-zA-Z0-9_-]{1,64}$/;
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$1.test(terminalId)) return { type: "error", reason: "invalid-id" };
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.153",
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.153",
121
- "very-happy-tools-x64-darwin": "0.2.153",
122
- "very-happy-tools-arm64-linux": "0.2.153",
123
- "very-happy-tools-x64-linux": "0.2.153",
124
- "very-happy-tools-arm64-win32": "0.2.153",
125
- "very-happy-tools-x64-win32": "0.2.153"
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:*",