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.
Files changed (55) hide show
  1. package/dist/{AcpBackend-Ckyadhf4.mjs → AcpBackend-DVB0nzgR.mjs} +2 -2
  2. package/dist/{AcpBackend-B14xNj5L.cjs → AcpBackend-DmFcRh54.cjs} +3 -3
  3. package/dist/{AcpSessionManager-CCHmPdrR.cjs → AcpSessionManager-CWaSYTnT.cjs} +1 -1
  4. package/dist/{AcpSessionManager-H8t4P-IW.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-B20RWdgE.mjs → agentHome-ByLb2HFg.mjs} +5 -5
  8. package/dist/{agentHome-BUsLTZnz.cjs → agentHome-aucT8BHw.cjs} +5 -5
  9. package/dist/{auto-BQnncDcs.mjs → auto-BQnD6gVx.mjs} +21 -21
  10. package/dist/{auto-IeldARBS.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-B-ocQh5V.mjs → config-BPZ2Y6o8.mjs} +8 -8
  14. package/dist/{config-DM_xI9M6.cjs → config-BoePh9PX.cjs} +8 -8
  15. package/dist/{index-okLyUzeD.cjs → index--KCpVs1c.cjs} +7 -7
  16. package/dist/{index-BELV05ko.mjs → index-B4oXnbYw.mjs} +463 -889
  17. package/dist/{index-ZKuBjvHi.mjs → index-BjzdXb9x.mjs} +21 -13
  18. package/dist/{index-BUxBxSxJ.cjs → index-DRrLaljt.cjs} +21 -13
  19. package/dist/{index-CIx3248o.mjs → index-DVVRqaVG.mjs} +7 -7
  20. package/dist/{index-eCjkm8Y2.cjs → index-D_fYUxVg.cjs} +521 -960
  21. package/dist/index.cjs +6 -6
  22. package/dist/index.mjs +6 -6
  23. package/dist/{install-BZOdxfPd.cjs → install-CGigiocs.cjs} +1 -1
  24. package/dist/{install-CoLN3whR.mjs → install-DP5aPNEX.mjs} +1 -1
  25. package/dist/{installTerminalHooks-CA4OcAS7.cjs → installTerminalHooks-XrcPvfBs.cjs} +5 -5
  26. package/dist/{installTerminalHooks-Dde_8t36.mjs → installTerminalHooks-tIg7mANc.mjs} +5 -5
  27. package/dist/lib.cjs +2 -2
  28. package/dist/lib.mjs +2 -2
  29. package/dist/{limits-Dt7_unH4.mjs → limits-C_DW0M0q.mjs} +309 -13
  30. package/dist/{limits-CmzISka2.cjs → limits-DkfHJ3nS.cjs} +329 -12
  31. package/dist/{mcp-7iDHlyCI.cjs → mcp-BqlXl10F.cjs} +23 -23
  32. package/dist/{mcp-9Ui4nQZL.mjs → mcp-o7QglAQM.mjs} +17 -17
  33. package/dist/{piRuntime-BesGGPME.cjs → piRuntime-BxP4B_zY.cjs} +2 -2
  34. package/dist/{piRuntime-C4E4pgye.mjs → piRuntime-MjiJI-nV.mjs} +2 -2
  35. package/dist/{piTerminal-fUogwxYr.cjs → piTerminal-DYzRcwgb.cjs} +6 -6
  36. package/dist/{piTerminal-CCEGCQOY.mjs → piTerminal-Dpq6yqKU.mjs} +6 -6
  37. package/dist/{runGemini-CNPGSsSK.cjs → runGemini-8Pxh94Fm.cjs} +7 -7
  38. package/dist/{runGemini-BW-pEklU.mjs → runGemini-CDlcQ-OA.mjs} +6 -6
  39. package/dist/{runOpenClaw-Bsodkg_s.cjs → runOpenClaw-B5FSZIbK.cjs} +6 -6
  40. package/dist/{runOpenClaw-NRB6-_jU.mjs → runOpenClaw-YkhsgPs0.mjs} +5 -5
  41. package/dist/{send-Bd00QcHC.cjs → send-CwrYXTPr.cjs} +8 -42
  42. package/dist/{send-DYeSFg8s.mjs → send-DJStmLBv.mjs} +5 -39
  43. package/dist/{sessions-DlPOYKLU.mjs → sessions-JaVXlSqj.mjs} +88 -45
  44. package/dist/{sessions-RIFUoy_g.cjs → sessions-MX21NJXd.cjs} +99 -56
  45. package/dist/{spawn-D1bhyHbH.mjs → spawn-BaPnjClT.mjs} +22 -22
  46. package/dist/{spawn-DxrfHTF4.cjs → spawn-cIoglKVf.cjs} +30 -30
  47. package/dist/{teams-pfKHpkgL.mjs → teams-DXV5Pwwt.mjs} +8 -8
  48. package/dist/{teams-Cfy0VMCo.cjs → teams-Dqk7F3D-.cjs} +8 -8
  49. package/dist/{todo-B2CjDg_V.mjs → todo-2Z1REhfx.mjs} +8 -6
  50. package/dist/{todo-B4cBFzHB.cjs → todo-Buuqn9gm.cjs} +8 -6
  51. package/dist/{types-D5RWyBE5.mjs → types-CkbfdRzq.mjs} +4 -282
  52. package/dist/{types-Bd_TGr0F.cjs → types-a2xsH2UI.cjs} +16 -311
  53. package/package.json +7 -7
  54. package/dist/agentGuidance-DUBXppv-.cjs +0 -554
  55. 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-CmzISka2.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');
@@ -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$1 = /^[a-zA-Z0-9_-]{1,64}$/;
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$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" };
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.154",
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.154",
121
- "very-happy-tools-x64-darwin": "0.2.154",
122
- "very-happy-tools-arm64-linux": "0.2.154",
123
- "very-happy-tools-x64-linux": "0.2.154",
124
- "very-happy-tools-arm64-win32": "0.2.154",
125
- "very-happy-tools-x64-win32": "0.2.154"
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:*",