very-happy-cli 0.2.121 → 0.2.123

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 (35) hide show
  1. package/dist/{AcpBackend-Cdj56ZfU.cjs → AcpBackend-DzIvpTxZ.cjs} +1 -1
  2. package/dist/{AcpBackend-BxvQ6O4k.mjs → AcpBackend-hM-qHLN3.mjs} +1 -1
  3. package/dist/{AcpSessionManager-DlWlQVhw.mjs → AcpSessionManager-CRPZPHPa.mjs} +1 -1
  4. package/dist/{AcpSessionManager-DahCU78z.cjs → AcpSessionManager-DyU3Ikgj.cjs} +1 -1
  5. package/dist/{config-DxOhdFEx.cjs → config-4RaHrVSV.cjs} +2 -2
  6. package/dist/{config-osO37dR1.mjs → config-alG86PDN.mjs} +2 -2
  7. package/dist/{index-Iz-M3qbz.mjs → index-36AkXNF2.mjs} +388 -188
  8. package/dist/{index-DObePs_K.cjs → index-5b9YhV-1.cjs} +390 -190
  9. package/dist/{index-Bv53Zygv.cjs → index-Beh0UZf8.cjs} +4 -4
  10. package/dist/{index-BcwAnM9k.mjs → index-Cg3Vfc00.mjs} +5 -5
  11. package/dist/{index-Vjo1jIJH.cjs → index-DWBKJ5zy.cjs} +2 -2
  12. package/dist/{index-DtZFY8aS.mjs → index-vyYHKKk6.mjs} +2 -2
  13. package/dist/index.cjs +2 -2
  14. package/dist/index.mjs +2 -2
  15. package/dist/{installTerminalHooks-DehsXLmV.cjs → installTerminalHooks-DWCa5j7u.cjs} +2 -2
  16. package/dist/{installTerminalHooks-Bq11vOqF.mjs → installTerminalHooks-DqUPkh0l.mjs} +2 -2
  17. package/dist/lib.cjs +1 -1
  18. package/dist/lib.d.cts +7 -0
  19. package/dist/lib.d.mts +7 -0
  20. package/dist/lib.mjs +1 -1
  21. package/dist/{mcp-Cpx9Qlch.cjs → mcp-BBya5dsZ.cjs} +2 -2
  22. package/dist/{mcp-Bx1B3uny.mjs → mcp-DZIdcsJp.mjs} +2 -2
  23. package/dist/{runGemini-CMgudbJs.mjs → runGemini-BQa2eF3i.mjs} +4 -4
  24. package/dist/{runGemini-DI8DipUx.cjs → runGemini-DmWxHIwS.cjs} +4 -4
  25. package/dist/{runOpenClaw-DR3fLtVf.mjs → runOpenClaw-362eg04u.mjs} +3 -3
  26. package/dist/{runOpenClaw-CetdjTl-.cjs → runOpenClaw-boyJtPBq.cjs} +3 -3
  27. package/dist/{send-Cq0NZCn8.cjs → send-BINA__Ke.cjs} +2 -2
  28. package/dist/{send-M4b_hD7t.mjs → send-CT22-8Tp.mjs} +2 -2
  29. package/dist/{sessions-DW4lrLOp.cjs → sessions-DXYxV6Np.cjs} +2 -2
  30. package/dist/{sessions-CelkWhqX.mjs → sessions-DemgtCkr.mjs} +2 -2
  31. package/dist/{spawn-D3cwBlWI.cjs → spawn-BtV9dU1i.cjs} +2 -2
  32. package/dist/{spawn-C4fF0q3Z.mjs → spawn-D2egvPgO.mjs} +2 -2
  33. package/dist/{types-P2cJWD0E.mjs → types-BqW7nEN_.mjs} +88 -39
  34. package/dist/{types-COOYpI8_.cjs → types-Cd_tUN3U.cjs} +89 -39
  35. package/package.json +7 -7
@@ -51,7 +51,7 @@ var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
51
51
  var pty__namespace = /*#__PURE__*/_interopNamespaceDefault(pty);
52
52
 
53
53
  var name = "very-happy-cli";
54
- var version = "0.2.121";
54
+ var version = "0.2.123";
55
55
  var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
56
56
  var author = "Kirill Dubovitskiy";
57
57
  var contributors = [
@@ -164,12 +164,12 @@ var dependencies = {
164
164
  zod: "^4.0.0"
165
165
  };
166
166
  var optionalDependencies = {
167
- "very-happy-tools-arm64-darwin": "0.2.121",
168
- "very-happy-tools-x64-darwin": "0.2.121",
169
- "very-happy-tools-arm64-linux": "0.2.121",
170
- "very-happy-tools-x64-linux": "0.2.121",
171
- "very-happy-tools-arm64-win32": "0.2.121",
172
- "very-happy-tools-x64-win32": "0.2.121"
167
+ "very-happy-tools-arm64-darwin": "0.2.123",
168
+ "very-happy-tools-x64-darwin": "0.2.123",
169
+ "very-happy-tools-arm64-linux": "0.2.123",
170
+ "very-happy-tools-x64-linux": "0.2.123",
171
+ "very-happy-tools-arm64-win32": "0.2.123",
172
+ "very-happy-tools-x64-win32": "0.2.123"
173
173
  };
174
174
  var devDependencies = {
175
175
  "@slopus/happy-wire": "workspace:*",
@@ -1032,6 +1032,22 @@ const ReleaseDrainNoticeSchema = z.z.object({
1032
1032
  deadline: z.z.number().int().positive(),
1033
1033
  mode: z.z.literal("make-before-break")
1034
1034
  });
1035
+ const ConnectionDiagnosticEventSchema = z.z.object({
1036
+ attemptId: z.z.string().uuid(),
1037
+ machineId: z.z.string().min(1).max(256).regex(/^[A-Za-z0-9_-]+$/).optional(),
1038
+ at: z.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1039
+ stage: z.z.enum(["control", "relay_discovery", "relay_connect", "relay_probe", "machine_rpc", "terminal_open"]),
1040
+ outcome: z.z.enum(["started", "success", "timeout", "error", "offline", "cancelled", "fallback"]),
1041
+ durationMs: z.z.number().int().min(0).max(3e5),
1042
+ deviceClass: z.z.enum(["mobile", "desktop", "unknown"]),
1043
+ visibility: z.z.enum(["visible", "hidden"]),
1044
+ relayRegion: z.z.enum(["central", "sg", "us", "other", "unknown"]).optional(),
1045
+ timing: z.z.enum(["active", "background", "censored", "unknown"]).optional(),
1046
+ client: z.z.string().regex(/^web\/(?:[a-f0-9]{7,40}|unknown)$/)
1047
+ }).strict();
1048
+ z.z.object({
1049
+ events: z.z.array(ConnectionDiagnosticEventSchema).min(1).max(32)
1050
+ }).strict();
1035
1051
 
1036
1052
  z.z.object({
1037
1053
  host: z.z.string(),
@@ -1081,6 +1097,7 @@ const CliUpdateStateSchema = z.z.object({
1081
1097
  /** B-351: the version this machine may install by itself. Pinned separately
1082
1098
  * from `recommendedVersion`; null means no unattended install. */
1083
1099
  autoUpdateVersion: z.z.string().nullable().optional(),
1100
+ retrySupported: z.z.boolean().optional(),
1084
1101
  checkedAt: z.z.number(),
1085
1102
  /**
1086
1103
  * B-321: a new bundle is on disk but refused to run, so the daemon is still
@@ -1691,7 +1708,7 @@ class RpcHandlerManager {
1691
1708
  }
1692
1709
  }
1693
1710
 
1694
- const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-COOYpI8_.cjs', document.baseURI).href))));
1711
+ const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-Cd_tUN3U.cjs', document.baseURI).href))));
1695
1712
  function projectPath() {
1696
1713
  const path = path$1.resolve(__dirname$1, "..");
1697
1714
  return path;
@@ -14506,28 +14523,50 @@ function selectStableRelay(candidates, probes, connectedRelayId, tracker = null)
14506
14523
  tracker: { challengerRelayId: fastest.id, consecutiveWins }
14507
14524
  };
14508
14525
  }
14526
+ const RELAY_REFRESH_TIMEOUT_MS = 8e3;
14527
+ async function withinDeadline(timeoutMs, operation, parent) {
14528
+ const controller = new AbortController();
14529
+ let timer;
14530
+ let cancel;
14531
+ const deadline = new Promise((_, reject) => {
14532
+ cancel = () => {
14533
+ reject(new Error("relay request deadline exceeded"));
14534
+ controller.abort();
14535
+ };
14536
+ timer = setTimeout(cancel, timeoutMs);
14537
+ parent?.addEventListener("abort", cancel, { once: true });
14538
+ if (parent?.aborted) cancel();
14539
+ });
14540
+ try {
14541
+ return await Promise.race([Promise.resolve().then(() => {
14542
+ controller.signal.throwIfAborted();
14543
+ return operation(controller.signal);
14544
+ }), deadline]);
14545
+ } finally {
14546
+ clearTimeout(timer);
14547
+ parent?.removeEventListener("abort", cancel);
14548
+ }
14549
+ }
14509
14550
  async function probeRelayCandidates(candidates, options = {}) {
14510
14551
  const timeoutMs = options.timeoutMs ?? 2e3;
14511
14552
  const fetchImpl = options.fetchImpl ?? fetch;
14512
14553
  const now = options.now ?? (() => performance.now());
14513
14554
  const measured = await Promise.all(candidates.map(async (candidate) => {
14514
- const controller = new AbortController();
14515
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
14516
14555
  const startedAt = now();
14517
14556
  try {
14518
- const response = await fetchImpl(`${candidate.url}/health`, {
14519
- method: "GET",
14520
- cache: "no-store",
14521
- signal: controller.signal
14522
- });
14523
- if (!response.ok) return null;
14524
- const body = await response.json();
14525
- if (body.ok !== true || body.relayId !== candidate.id) return null;
14526
- return { relayId: candidate.id, rttMs: Math.max(0, now() - startedAt) };
14557
+ return await withinDeadline(timeoutMs, async (signal) => {
14558
+ const response = await fetchImpl(`${candidate.url}/health`, {
14559
+ method: "GET",
14560
+ cache: "no-store",
14561
+ signal
14562
+ });
14563
+ if (!response.ok) return null;
14564
+ const body = await response.json();
14565
+ if (body.ok !== true || body.relayId !== candidate.id) return null;
14566
+ return { relayId: candidate.id, rttMs: Math.max(0, now() - startedAt) };
14567
+ }, options.signal);
14527
14568
  } catch {
14528
14569
  return null;
14529
- } finally {
14530
- clearTimeout(timeout);
14531
14570
  }
14532
14571
  }));
14533
14572
  return measured.filter((probe) => probe !== null);
@@ -14535,25 +14574,32 @@ async function probeRelayCandidates(candidates, options = {}) {
14535
14574
  async function discoverAndClaimRelay(input) {
14536
14575
  const fetchImpl = input.fetchImpl ?? fetch;
14537
14576
  try {
14538
- const discoveryResponse = await fetchImpl(`${input.controlUrl}/v1/relays`, {
14539
- headers: { Authorization: `Bearer ${input.token}` },
14540
- cache: "no-store"
14541
- });
14542
- if (!discoveryResponse.ok) return null;
14543
- const discovery = RelayCandidatesResponseSchema.parse(await discoveryResponse.json());
14544
- if (!discovery.enabled || discovery.candidates.length === 0) return null;
14545
- const probes = await probeRelayCandidates(discovery.candidates, { fetchImpl });
14546
- const decision = selectStableRelay(discovery.candidates, probes, input.connectedRelayId, input.switchTracker);
14547
- const selected = decision.candidate;
14548
- if (!selected) return null;
14549
- const claimResponse = await fetchImpl(`${input.controlUrl}/v1/relays/machines/${encodeURIComponent(input.machineId)}/claim`, {
14550
- method: "POST",
14551
- headers: { Authorization: `Bearer ${input.token}`, "Content-Type": "application/json" },
14552
- body: JSON.stringify({ relayId: selected.id, probes })
14577
+ return await withinDeadline(RELAY_REFRESH_TIMEOUT_MS, async (signal) => {
14578
+ const discoveryResponse = await fetchImpl(`${input.controlUrl}/v1/relays`, {
14579
+ headers: { Authorization: `Bearer ${input.token}` },
14580
+ cache: "no-store",
14581
+ signal
14582
+ });
14583
+ if (!discoveryResponse.ok) return null;
14584
+ const discovery = RelayCandidatesResponseSchema.parse(await discoveryResponse.json());
14585
+ signal.throwIfAborted();
14586
+ if (!discovery.enabled || discovery.candidates.length === 0) return null;
14587
+ const probes = await probeRelayCandidates(discovery.candidates, { fetchImpl, signal });
14588
+ signal.throwIfAborted();
14589
+ const decision = selectStableRelay(discovery.candidates, probes, input.connectedRelayId, input.switchTracker);
14590
+ const selected = decision.candidate;
14591
+ if (!selected) return null;
14592
+ const claimResponse = await fetchImpl(`${input.controlUrl}/v1/relays/machines/${encodeURIComponent(input.machineId)}/claim`, {
14593
+ method: "POST",
14594
+ signal,
14595
+ headers: { Authorization: `Bearer ${input.token}`, "Content-Type": "application/json" },
14596
+ body: JSON.stringify({ relayId: selected.id, probes })
14597
+ });
14598
+ if (!claimResponse.ok) return null;
14599
+ const claimed = RelayAssignmentResponseSchema.parse(await claimResponse.json());
14600
+ signal.throwIfAborted();
14601
+ return claimed.assignment ? { assignment: claimed.assignment, probes, switchTracker: decision.tracker } : null;
14553
14602
  });
14554
- if (!claimResponse.ok) return null;
14555
- const claimed = RelayAssignmentResponseSchema.parse(await claimResponse.json());
14556
- return claimed.assignment ? { assignment: claimed.assignment, probes, switchTracker: decision.tracker } : null;
14557
14603
  } catch {
14558
14604
  return null;
14559
14605
  }
@@ -14782,6 +14828,9 @@ class ApiMachineClient {
14782
14828
  encTerminalData(dataBase64) {
14783
14829
  return encodeBase64(encrypt(this.machine.encryptionKey, this.machine.encryptionVariant, dataBase64));
14784
14830
  }
14831
+ setCliUpdateRetryHandler(handler) {
14832
+ this.rpcHandlerManager.registerHandler("cli-update-retry", (params) => handler(params && typeof params === "object" ? params.version : void 0));
14833
+ }
14785
14834
  /** Cache the latest relay policy locally and publish it now or on the next
14786
14835
  * socket connect. This makes startup/offline races harmless. */
14787
14836
  setCliUpdateState(state) {
@@ -16851,6 +16900,7 @@ exports.logger = logger;
16851
16900
  exports.mirrorLineKey = mirrorLineKey;
16852
16901
  exports.mirrorLocalId = mirrorLocalId;
16853
16902
  exports.packageJson = packageJson;
16903
+ exports.parseExactVersion = parseExactVersion;
16854
16904
  exports.parseTerminalHookPayload = parseTerminalHookPayload;
16855
16905
  exports.persistSession = persistSession;
16856
16906
  exports.persistence = persistence;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "very-happy-cli",
3
- "version": "0.2.121",
3
+ "version": "0.2.123",
4
4
  "description": "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.",
5
5
  "author": "Kirill Dubovitskiy",
6
6
  "contributors": [
@@ -113,12 +113,12 @@
113
113
  "zod": "^4.0.0"
114
114
  },
115
115
  "optionalDependencies": {
116
- "very-happy-tools-arm64-darwin": "0.2.121",
117
- "very-happy-tools-x64-darwin": "0.2.121",
118
- "very-happy-tools-arm64-linux": "0.2.121",
119
- "very-happy-tools-x64-linux": "0.2.121",
120
- "very-happy-tools-arm64-win32": "0.2.121",
121
- "very-happy-tools-x64-win32": "0.2.121"
116
+ "very-happy-tools-arm64-darwin": "0.2.123",
117
+ "very-happy-tools-x64-darwin": "0.2.123",
118
+ "very-happy-tools-arm64-linux": "0.2.123",
119
+ "very-happy-tools-x64-linux": "0.2.123",
120
+ "very-happy-tools-arm64-win32": "0.2.123",
121
+ "very-happy-tools-x64-win32": "0.2.123"
122
122
  },
123
123
  "devDependencies": {
124
124
  "@slopus/happy-wire": "workspace:*",