@mycadet/cli 0.12.7 → 0.12.9-dev.202610131452.9acab64

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 (185) hide show
  1. package/README.md +2 -2
  2. package/knip.json +1 -1
  3. package/node_modules/@mycadet/assistant-api/events/cloud-disconnected.ts +21 -0
  4. package/node_modules/@mycadet/assistant-api/events/host-bash.ts +1 -1
  5. package/node_modules/@mycadet/assistant-api/events/host-cu.ts +1 -1
  6. package/node_modules/@mycadet/assistant-api/events/host-file.ts +1 -1
  7. package/node_modules/@mycadet/assistant-api/events/notification-intent.ts +1 -1
  8. package/node_modules/@mycadet/assistant-api/events/show-cloud-login.ts +18 -0
  9. package/node_modules/@mycadet/assistant-api/index.ts +11 -11
  10. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/package.json +2 -2
  11. package/node_modules/@mycadet/{service-contracts/src/platform-credential.ts → assistant-api/node_modules/@mycadet/service-contracts/src/cloud-credential.ts} +9 -9
  12. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  13. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  14. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  15. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  16. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  17. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  18. package/node_modules/@mycadet/assistant-api/responses/home.ts +1 -1
  19. package/node_modules/@mycadet/assistant-api/surfaces.ts +4 -4
  20. package/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
  21. package/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
  22. package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
  23. package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
  24. package/node_modules/@mycadet/environments/src/types.ts +6 -6
  25. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
  26. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
  27. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/seeds.ts +6 -6
  28. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
  29. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/types.ts +6 -6
  30. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/package.json +2 -2
  31. package/node_modules/@mycadet/{assistant-api/node_modules/@mycadet/service-contracts/src/platform-credential.ts → local-mode/node_modules/@mycadet/service-contracts/src/cloud-credential.ts} +9 -9
  32. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  33. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  34. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  35. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  36. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  37. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  38. package/node_modules/@mycadet/local-mode/src/__tests__/pair.test.ts +5 -5
  39. package/node_modules/@mycadet/local-mode/src/__tests__/retire.test.ts +1 -1
  40. package/node_modules/@mycadet/local-mode/src/config.ts +2 -2
  41. package/node_modules/@mycadet/local-mode/src/index.ts +1 -1
  42. package/node_modules/@mycadet/local-mode/src/lockfile-contract.test.ts +3 -3
  43. package/node_modules/@mycadet/local-mode/src/lockfile-contract.ts +10 -5
  44. package/node_modules/@mycadet/local-mode/src/lockfile.test.ts +15 -15
  45. package/node_modules/@mycadet/local-mode/src/lockfile.ts +9 -9
  46. package/node_modules/@mycadet/local-mode/src/pair.ts +2 -2
  47. package/node_modules/@mycadet/local-mode/src/retire.ts +3 -3
  48. package/node_modules/@mycadet/local-mode/src/teleport-backup-policy.ts +2 -2
  49. package/node_modules/@mycadet/local-mode/src/unpair.ts +2 -2
  50. package/node_modules/@mycadet/service-contracts/package.json +2 -2
  51. package/node_modules/@mycadet/{local-mode/node_modules/@mycadet/service-contracts/src/platform-credential.ts → service-contracts/src/cloud-credential.ts} +9 -9
  52. package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  53. package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  54. package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  55. package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  56. package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  57. package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  58. package/package.json +6 -4
  59. package/src/__tests__/assistant-api-key-resolution.test.ts +6 -6
  60. package/src/__tests__/{assistant-client-platform-auth.test.ts → assistant-client-cloud-auth.test.ts} +10 -10
  61. package/src/__tests__/assistant-client-refresh.test.ts +2 -2
  62. package/src/__tests__/backup.test.ts +86 -91
  63. package/src/__tests__/client-token.test.ts +1 -1
  64. package/src/__tests__/client-tui-refresh.test.ts +1 -1
  65. package/src/__tests__/client-web-config.test.ts +1 -2
  66. package/src/__tests__/{platform-client.test.ts → cloud-client.test.ts} +59 -59
  67. package/src/__tests__/{platform-releases.test.ts → cloud-releases.test.ts} +28 -18
  68. package/src/__tests__/{cloudflare-tunnel.test.ts → cloudflare.test.ts} +1 -1
  69. package/src/__tests__/connect-import.test.ts +55 -39
  70. package/src/__tests__/debug.test.ts +38 -38
  71. package/src/__tests__/ensure-binary.test.ts +182 -0
  72. package/src/__tests__/guardian-token.test.ts +149 -56
  73. package/src/__tests__/hatch-provider-secrets.test.ts +2 -2
  74. package/src/__tests__/helpers/guardian-token.ts +22 -0
  75. package/src/__tests__/helpers/http.ts +10 -0
  76. package/src/__tests__/nginx-ingress.test.ts +15 -20
  77. package/src/__tests__/ngrok-spawn.test.ts +49 -0
  78. package/src/__tests__/orphan-detection.test.ts +1 -1
  79. package/src/__tests__/pair.test.ts +149 -85
  80. package/src/__tests__/{ps-platform-status.test.ts → ps-cloud-status.test.ts} +80 -26
  81. package/src/__tests__/ps-table.test.ts +79 -0
  82. package/src/__tests__/{recover.test.ts → restore.test.ts} +29 -28
  83. package/src/__tests__/retire.test.ts +58 -199
  84. package/src/__tests__/root-process-lockfile.test.ts +99 -0
  85. package/src/__tests__/sleep.test.ts +19 -19
  86. package/src/__tests__/statefulset.test.ts +8 -8
  87. package/src/__tests__/{tailscale-tunnel.test.ts → tailscale.test.ts} +2 -2
  88. package/src/__tests__/teleport-backup.test.ts +3 -3
  89. package/src/__tests__/teleport.test.ts +180 -211
  90. package/src/__tests__/tunnel.test.ts +490 -270
  91. package/src/__tests__/uninstall.test.ts +150 -9
  92. package/src/__tests__/upgrade-local.test.ts +3 -3
  93. package/src/__tests__/upgrade-replay-env.test.ts +12 -12
  94. package/src/__tests__/wake.test.ts +260 -43
  95. package/src/__tests__/workos-pkce.test.ts +2 -2
  96. package/src/commands/backup.ts +24 -24
  97. package/src/commands/client.ts +76 -78
  98. package/src/commands/completions.test.ts +104 -0
  99. package/src/commands/completions.ts +87 -0
  100. package/src/commands/debug.ts +20 -20
  101. package/src/commands/exec.ts +12 -12
  102. package/src/commands/flags.ts +2 -2
  103. package/src/commands/hatch.ts +27 -24
  104. package/src/commands/login.ts +22 -22
  105. package/src/commands/logs.ts +8 -8
  106. package/src/commands/pair.ts +140 -37
  107. package/src/commands/ps.ts +232 -86
  108. package/src/commands/restart.ts +30 -0
  109. package/src/commands/restore.ts +140 -22
  110. package/src/commands/retire.ts +48 -150
  111. package/src/commands/rollback.ts +20 -26
  112. package/src/commands/setup.ts +2 -2
  113. package/src/commands/sleep.ts +2 -2
  114. package/src/commands/teleport.ts +110 -129
  115. package/src/commands/terminal.ts +158 -18
  116. package/src/commands/tunnel.ts +156 -175
  117. package/src/commands/uninstall.ts +137 -54
  118. package/src/commands/unpair.ts +3 -3
  119. package/src/commands/upgrade.ts +30 -54
  120. package/src/commands/use.ts +1 -1
  121. package/src/commands/wake.ts +166 -50
  122. package/src/index.ts +18 -9
  123. package/src/lib/__tests__/{platform-client-signed-url.test.ts → cloud-client-signed-url.test.ts} +16 -16
  124. package/src/lib/__tests__/docker.test.ts +168 -20
  125. package/src/lib/__tests__/job-polling.test.ts +2 -2
  126. package/src/lib/__tests__/local-gateway-cli.test.ts +42 -0
  127. package/src/lib/__tests__/local-runtime-client.test.ts +4 -4
  128. package/src/lib/__tests__/runtime-url.test.ts +1 -1
  129. package/src/lib/assistant-api-key-resolution.ts +5 -5
  130. package/src/lib/assistant-client.ts +8 -8
  131. package/src/lib/assistant-config.ts +58 -12
  132. package/src/lib/{platform-client.ts → cloud-client.ts} +105 -99
  133. package/src/lib/cloud-login.ts +23 -24
  134. package/src/lib/{platform-releases.ts → cloud-releases.ts} +11 -9
  135. package/src/lib/cloud-values.ts +3 -0
  136. package/src/lib/color.ts +4 -0
  137. package/src/lib/config-utils.ts +1 -1
  138. package/src/lib/detached-process.ts +1 -1
  139. package/src/lib/docker.ts +300 -111
  140. package/src/lib/ensure-binary.ts +171 -0
  141. package/src/lib/environments/__tests__/paths.test.ts +29 -3
  142. package/src/lib/environments/__tests__/resolve.test.ts +26 -26
  143. package/src/lib/environments/paths.ts +16 -8
  144. package/src/lib/environments/resolve.ts +10 -12
  145. package/src/lib/flag-args.test.ts +1 -1
  146. package/src/lib/flag-args.ts +1 -1
  147. package/src/lib/guardian-token.ts +37 -5
  148. package/src/lib/hatch-local.ts +32 -29
  149. package/src/lib/hatch-next-steps.ts +5 -9
  150. package/src/lib/health-check.ts +6 -6
  151. package/src/lib/ingress-config.ts +8 -35
  152. package/src/lib/job-polling.ts +2 -2
  153. package/src/lib/live-voice/connection.ts +12 -12
  154. package/src/lib/live-voice/tunnel.test.ts +11 -11
  155. package/src/lib/live-voice/tunnel.ts +15 -15
  156. package/src/lib/local-runtime-client.ts +20 -20
  157. package/src/lib/local.ts +46 -34
  158. package/src/lib/nginx-ingress.ts +40 -15
  159. package/src/lib/pair.ts +1 -1
  160. package/src/lib/process.ts +1 -1
  161. package/src/lib/provider-secrets.ts +3 -3
  162. package/src/lib/retire-apple-container.ts +1 -1
  163. package/src/lib/runtime-url.ts +8 -8
  164. package/src/lib/statefulset.ts +2 -2
  165. package/src/lib/step-runner.ts +6 -1
  166. package/src/lib/sync-cloud-assistants.ts +19 -19
  167. package/src/lib/teleport-backup.ts +4 -4
  168. package/src/lib/terminal-client.ts +17 -17
  169. package/src/lib/terminal-session.ts +24 -24
  170. package/src/lib/{tunnel-edge.ts → tunnel.ts} +199 -11
  171. package/src/lib/tunnels/cadet.ts +29 -0
  172. package/src/lib/{cloudflare-tunnel.ts → tunnels/cloudflare.ts} +36 -15
  173. package/src/lib/tunnels/gateway-notify.ts +61 -0
  174. package/src/lib/{ngrok.ts → tunnels/ngrok.ts} +350 -89
  175. package/src/lib/{tailscale-tunnel.ts → tunnels/tailscale.ts} +53 -9
  176. package/src/lib/upgrade-lifecycle.ts +8 -21
  177. package/src/lib/upgrade-preflight.ts +2 -2
  178. package/src/lib/workos-pkce.ts +5 -5
  179. package/node_modules/@mycadet/assistant-api/events/platform-disconnected.ts +0 -21
  180. package/node_modules/@mycadet/assistant-api/events/show-platform-login.ts +0 -20
  181. package/src/commands/recover.ts +0 -131
  182. package/src/commands/roadmap.ts +0 -459
  183. package/src/commands/ssh.ts +0 -144
  184. package/src/commands/workflows.ts +0 -305
  185. package/src/lib/managed-cloud.ts +0 -3
@@ -1,7 +1,10 @@
1
+ import type { ProviderMeta, ProviderTunnelResult } from "../tunnel.js";
2
+
1
3
  import { spawnSync } from "node:child_process";
2
4
  import { win32 } from "node:path";
3
5
 
4
- import { GATEWAY_PORT } from "./constants.js";
6
+ import { GATEWAY_PORT } from "../constants.js";
7
+ import { ensureBinaryInstalled } from "../ensure-binary.js";
5
8
  import {
6
9
  clearIngressUrl,
7
10
  getDefaultWorkspaceDir,
@@ -9,7 +12,7 @@ import {
9
12
  saveIngressUrl,
10
13
  savePairingTunnel,
11
14
  stampLockfileIngressUrl,
12
- } from "./ingress-config.js";
15
+ } from "../ingress-config.js";
13
16
 
14
17
  // ── Tailscale CLI discovery + invocation ────────────────────────────────────
15
18
 
@@ -52,7 +55,7 @@ export function getTailscaleInstallMessage(
52
55
  hostPlatform === "win32"
53
56
  ? " Windows: winget install Tailscale.Tailscale"
54
57
  : hostPlatform === "darwin"
55
- ? " macOS: brew install tailscale (or install the Tailscale app)"
58
+ ? " macOS: brew install tailscale, or install the Tailscale app"
56
59
  : " Linux: https://tailscale.com/download/linux";
57
60
  return [
58
61
  "Tailscale is not installed or could not be found.",
@@ -77,12 +80,12 @@ export interface TailscaleCommandResult {
77
80
  */
78
81
  export interface TailscaleDeps {
79
82
  /** Locate the tailscale CLI; returns the invocable path, null if absent. */
80
- findBinary(): string | null;
83
+ findBinary(): Promise<string | null>;
81
84
  /** Run `<bin> <args>` synchronously (spawnSync semantics). */
82
85
  run(bin: string, args: string[]): TailscaleCommandResult;
83
86
  }
84
87
 
85
- function realFindBinary(): string | null {
88
+ function probeTailscaleBinary(): string | null {
86
89
  for (const candidate of getTailscaleBinaryCandidates()) {
87
90
  const res = spawnSync(candidate, ["version"], {
88
91
  encoding: "utf-8",
@@ -97,6 +100,35 @@ function realFindBinary(): string | null {
97
100
  return null;
98
101
  }
99
102
 
103
+ /**
104
+ * The real binary finder offers to install tailscale when it is missing
105
+ * (prompt-install via the shared helper; no-op hint on a non-interactive
106
+ * terminal) and re-probes after.
107
+ */
108
+ async function realFindBinary(): Promise<string | null> {
109
+ const found = probeTailscaleBinary();
110
+ if (found) return found;
111
+ await ensureBinaryInstalled({
112
+ binary: "tailscale",
113
+ purpose: "the tailscale tunnel",
114
+ packages: {
115
+ brew: ["brew", "install", "tailscale"],
116
+ winget: [
117
+ "winget",
118
+ "install",
119
+ "--silent",
120
+ "--accept-package-agreements",
121
+ "--accept-source-agreements",
122
+ "Tailscale.Tailscale",
123
+ ],
124
+ choco: ["choco", "install", "-y", "tailscale"],
125
+ },
126
+ manualHint: getTailscaleInstallMessage(),
127
+ probe: () => probeTailscaleBinary(),
128
+ });
129
+ return probeTailscaleBinary();
130
+ }
131
+
100
132
  function realRun(bin: string, args: string[]): TailscaleCommandResult {
101
133
  const res = spawnSync(bin, args, {
102
134
  encoding: "utf-8",
@@ -290,7 +322,7 @@ export async function startTailscaleServe(
290
322
  opts: RunTailscaleTunnelOptions = {},
291
323
  deps: TailscaleDeps = realTailscaleDeps(),
292
324
  ): Promise<TailscaleServeInfo> {
293
- const binary = deps.findBinary();
325
+ const binary = await deps.findBinary();
294
326
  if (!binary) {
295
327
  throw new Error(getTailscaleInstallMessage());
296
328
  }
@@ -351,7 +383,7 @@ export function stopTailscaleServe(
351
383
  */
352
384
  export async function runTailscaleTunnel(
353
385
  opts: RunTailscaleTunnelOptions = {},
354
- ): Promise<void> {
386
+ ): Promise<ProviderTunnelResult> {
355
387
  const deps = realTailscaleDeps();
356
388
  // What this run publishes, and therefore what Ctrl+C takes back.
357
389
  const publishedLabel = opts.preserveIngressUrl
@@ -375,7 +407,7 @@ export async function runTailscaleTunnel(
375
407
  "This URL is reachable only from devices signed in to your tailnet.",
376
408
  );
377
409
  console.log(
378
- "For public webhook ingress, use --provider ngrok or --provider cloudflare.",
410
+ "For public webhook ingress, run `cadet tunnel --help` to see the public providers.",
379
411
  );
380
412
  console.log("");
381
413
  console.log(
@@ -429,5 +461,17 @@ export async function runTailscaleTunnel(
429
461
  // Hold the process open until a signal fires. The serve itself lives in
430
462
  // tailscaled, so there is no child process to await — the registered signal
431
463
  // listeners keep the event loop alive.
432
- await new Promise<void>(() => {});
464
+ const waitForExit = new Promise<void>(() => {});
465
+ return { publicUrl, waitForExit };
433
466
  }
467
+
468
+ /** Per-provider copy `cadet tunnel`'s help renders for tailscale. */
469
+ export const TAILSCALE_TUNNEL_META: ProviderMeta = {
470
+ reach: "Tailnet-only tunnel, reachable from your own devices",
471
+ install: "install: https://tailscale.com/download, then run `tailscale up`",
472
+ notes: [
473
+ "When webhook integrations are configured it records its URL for device",
474
+ "pairing only, leaving the saved webhook callback base as it is.",
475
+ ],
476
+ supportsReservedDomain: false,
477
+ };
@@ -17,6 +17,7 @@ import {
17
17
  dockerResourceNames,
18
18
  GATEWAY_INTERNAL_PORT,
19
19
  ASSISTANT_INTERNAL_PORT,
20
+ pullImage,
20
21
  startContainers,
21
22
  stopContainers,
22
23
  } from "./docker.js";
@@ -24,7 +25,7 @@ import { getStateDir } from "./environments/paths.js";
24
25
  import { getCurrentEnvironment } from "./environments/resolve.js";
25
26
  import { loadGuardianToken } from "./guardian-token.js";
26
27
  import { classifyReadyzResponse } from "./http-client.js";
27
- import { fetchReleases, resolveImageRefs } from "./platform-releases.js";
28
+ import { fetchReleases, resolveImageRefs } from "./cloud-releases.js";
28
29
  import { z } from "zod";
29
30
 
30
31
  const GatewayHealthSchema = z.object({
@@ -40,7 +41,7 @@ import {
40
41
  type DockerStatefulSetSpec,
41
42
  type ServiceName,
42
43
  } from "./statefulset.js";
43
- import { exec, execOutput } from "./step-runner.js";
44
+ import { execOutput } from "./step-runner.js";
44
45
  import { compareVersions, stripVersionPrefix } from "./version-compat.js";
45
46
  import { loopbackSafeFetch } from "./loopback-fetch.js";
46
47
 
@@ -332,7 +333,7 @@ export async function fetchAssistantIngressUrl(
332
333
  publicBaseUrl?: string;
333
334
  managedCallbacks?: boolean;
334
335
  };
335
- // Ignore managed-callback URLs — those belong to the platform, not the
336
+ // Ignore managed-callback URLs — those belong to the cloud, not the
336
337
  // self-hosted assistant's own ingress.
337
338
  if (body.managedCallbacks) return undefined;
338
339
  return body.publicBaseUrl || undefined;
@@ -348,7 +349,7 @@ export async function fetchAssistantIngressUrl(
348
349
  *
349
350
  * Checks (in order):
350
351
  * 1. `entry.previousVersion` (saved by the upgrade flow from health).
351
- * 2. The releases list from the platform API — finds the version
352
+ * 2. The releases list from the cloud API — finds the version
352
353
  * immediately before `currentVersion`.
353
354
  *
354
355
  * Returns `undefined` when neither source yields a result.
@@ -418,7 +419,7 @@ export async function waitForReady(runtimeUrl: string): Promise<boolean> {
418
419
  const parts = [body?.status].filter(Boolean);
419
420
  if (body?.upstream != null) parts.push(`upstream=${body.upstream}`);
420
421
  const detail = parts.length > 0 ? ` — ${parts.join(", ")}` : "";
421
- console.log(`Readiness check: ${resp.status}${detail} (retrying...)`);
422
+ console.log(`Readiness check: ${resp.status}${detail}, retrying...`);
422
423
  } catch {
423
424
  // Connection refused / timeout — not up yet
424
425
  }
@@ -754,7 +755,7 @@ export async function performDockerRollback(
754
755
  console.log(` Backup saved: ${preRollbackBackupPath}\n`);
755
756
  pruneOldBackups(entry.assistantId, 3);
756
757
  } else {
757
- console.warn("⚠️ Pre-rollback backup failed (continuing with rollback)\n");
758
+ console.warn("⚠️ Pre-rollback backup failed, continuing with rollback\n");
758
759
  }
759
760
 
760
761
  const {
@@ -806,7 +807,7 @@ export async function performDockerRollback(
806
807
  try {
807
808
  for (const [service, image] of pullImages) {
808
809
  console.log(` Pulling ${service}: ${image}`);
809
- await exec("docker", ["pull", image]);
810
+ await pullImage(image);
810
811
  }
811
812
  } catch (pullErr) {
812
813
  const detail = pullErr instanceof Error ? pullErr.message : String(pullErr);
@@ -869,8 +870,6 @@ export async function performDockerRollback(
869
870
  );
870
871
 
871
872
  // Capture new digests from the rolled-back containers
872
- const newDigests = await captureImageRefs(res);
873
-
874
873
  // Swap current/previous state to enable "rollback the rollback"
875
874
  const updatedEntry: AssistantEntry = {
876
875
  ...entry,
@@ -878,10 +877,6 @@ export async function performDockerRollback(
878
877
  assistantImage: targetImageTags.assistant,
879
878
  gatewayImage: targetImageTags.gateway,
880
879
  cesImage: targetImageTags["credential-executor"],
881
- assistantDigest: newDigests?.assistant,
882
- gatewayDigest: newDigests?.gateway,
883
- cesDigest: newDigests?.["credential-executor"],
884
- networkName: res.network,
885
880
  assistantPort,
886
881
  },
887
882
  previousContainerInfo: entry.containerInfo,
@@ -1030,7 +1025,6 @@ export async function performDockerRollback(
1030
1025
  }
1031
1026
 
1032
1027
  // Restore lockfile state
1033
- const revertDigests = await captureImageRefs(res);
1034
1028
  const revertedEntry: AssistantEntry = {
1035
1029
  ...entry,
1036
1030
  containerInfo: {
@@ -1042,13 +1036,6 @@ export async function performDockerRollback(
1042
1036
  cesImage:
1043
1037
  entry.containerInfo?.cesImage ??
1044
1038
  currentImageRefs["credential-executor"],
1045
- assistantDigest:
1046
- revertDigests?.assistant ?? currentImageRefs.assistant,
1047
- gatewayDigest: revertDigests?.gateway ?? currentImageRefs.gateway,
1048
- cesDigest:
1049
- revertDigests?.["credential-executor"] ??
1050
- currentImageRefs["credential-executor"],
1051
- networkName: res.network,
1052
1039
  assistantPort,
1053
1040
  },
1054
1041
  previousContainerInfo: undefined,
@@ -1,4 +1,4 @@
1
- import type { ReleaseListItem } from "./platform-releases.js";
1
+ import type { ReleaseListItem } from "./cloud-releases.js";
2
2
  import { compareVersions, versionsEqual } from "./version-compat.js";
3
3
 
4
4
  export interface UpgradeTargetResolution {
@@ -88,7 +88,7 @@ export interface UpgradePollState {
88
88
  }
89
89
 
90
90
  /**
91
- * Completion predicate for the platform upgrade poll loop. Pure.
91
+ * Completion predicate for the cloud upgrade poll loop. Pure.
92
92
  *
93
93
  * The primary signal is the DB-backed `current_release_version` (works while
94
94
  * the service group restarts or the assistant sleeps); the upgrade-status
@@ -103,9 +103,9 @@ export function selectWorkosClientId(
103
103
  }
104
104
 
105
105
  export async function fetchWorkosClientId(
106
- platformUrl: string,
106
+ cloudUrl: string,
107
107
  ): Promise<string> {
108
- const url = `${new URL(platformUrl).origin}/_allauth/app/v1/config`;
108
+ const url = `${new URL(cloudUrl).origin}/_allauth/app/v1/config`;
109
109
  const response = await loopbackSafeFetch(url);
110
110
  if (!response.ok) {
111
111
  throw new Error(`Failed to fetch auth config (${response.status})`);
@@ -157,13 +157,13 @@ export async function exchangeCodeWithWorkos(options: {
157
157
  return parsed.data.access_token;
158
158
  }
159
159
 
160
- /** Exchange the WorkOS access token for a platform session token. */
160
+ /** Exchange the WorkOS access token for a cloud session token. */
161
161
  export async function exchangeAccessTokenForSession(
162
- platformUrl: string,
162
+ cloudUrl: string,
163
163
  clientId: string,
164
164
  accessToken: string,
165
165
  ): Promise<string> {
166
- const url = `${new URL(platformUrl).origin}/_allauth/app/v1/auth/provider/token`;
166
+ const url = `${new URL(cloudUrl).origin}/_allauth/app/v1/auth/provider/token`;
167
167
  const response = await loopbackSafeFetch(url, {
168
168
  method: "POST",
169
169
  headers: { "Content-Type": "application/json" },
@@ -1,21 +0,0 @@
1
- /**
2
- * `platform_disconnected` SSE event.
3
- *
4
- * Emitted by the platform-disconnect route after stored platform
5
- * credentials are deleted, notifying connected clients that the platform
6
- * connection is gone.
7
- *
8
- * Canonical wire-contract source. Daemon code imports the type
9
- * directly from this file; external consumers import via
10
- * `@mycadet/assistant-api`.
11
- */
12
-
13
- import { z } from "zod";
14
-
15
- export const PlatformDisconnectedEventSchema = z.object({
16
- type: z.literal("platform_disconnected"),
17
- });
18
-
19
- export type PlatformDisconnectedEvent = z.infer<
20
- typeof PlatformDisconnectedEventSchema
21
- >;
@@ -1,20 +0,0 @@
1
- /**
2
- * `show_platform_login` SSE event.
3
- *
4
- * Emitted by the platform-connect route when no cloud credentials are
5
- * stored yet, signalling connected clients to surface the cloud login UI.
6
- *
7
- * Canonical wire-contract source. Daemon code imports the type
8
- * directly from this file; external consumers import via
9
- * `@mycadet/assistant-api`.
10
- */
11
-
12
- import { z } from "zod";
13
-
14
- export const ShowPlatformLoginEventSchema = z.object({
15
- type: z.literal("show_platform_login"),
16
- });
17
-
18
- export type ShowPlatformLoginEvent = z.infer<
19
- typeof ShowPlatformLoginEventSchema
20
- >;
@@ -1,131 +0,0 @@
1
- import { resolveExistingLocalSigningKey } from "@mycadet/local-mode";
2
- import {
3
- existsSync,
4
- mkdirSync,
5
- readFileSync,
6
- renameSync,
7
- unlinkSync,
8
- } from "fs";
9
- import { basename, dirname, join } from "path";
10
-
11
- import { saveAssistantEntry } from "../lib/assistant-config";
12
- import type { AssistantEntry } from "../lib/assistant-config";
13
- import {
14
- generateLocalSigningKey,
15
- startCes,
16
- startLocalDaemon,
17
- startGateway,
18
- } from "../lib/local";
19
- import { getArchivePath, getMetadataPath } from "../lib/retire-archive";
20
- import { exec } from "../lib/step-runner";
21
-
22
- export const recover = Object.assign(
23
- async function recover(): Promise<void> {
24
- const args = process.argv.slice(3);
25
- if (args.includes("--help") || args.includes("-h")) {
26
- console.log("Usage: cadet recover <name>");
27
- console.log("");
28
- console.log(
29
- "Restore a previously retired local assistant from its archive.",
30
- );
31
- console.log("");
32
- console.log(
33
- "Extracts the archived workspace data back to its original location,",
34
- );
35
- console.log(
36
- "restores the lockfile entry, and starts the assistant and gateway.",
37
- );
38
- console.log(
39
- "Archives are stored in $XDG_DATA_HOME/cadet/retired/ (default: ~/.local/share/cadet/retired/).",
40
- );
41
- console.log("");
42
- console.log("Arguments:");
43
- console.log(" <name> Name of the retired assistant to recover");
44
- console.log("");
45
- console.log("Examples:");
46
- console.log(" $ cadet recover my-assistant");
47
- console.log(" $ cadet recover aria-7f3a");
48
- process.exit(0);
49
- }
50
-
51
- const name = process.argv[3];
52
- if (!name) {
53
- console.error("Usage: cadet recover <name>");
54
- process.exit(1);
55
- }
56
-
57
- const archivePath = getArchivePath(name);
58
- const metadataPath = getMetadataPath(name);
59
-
60
- // 1. Verify archive exists
61
- if (!existsSync(archivePath) || !existsSync(metadataPath)) {
62
- console.error(`No retired archive found for '${name}'.`);
63
- process.exit(1);
64
- }
65
-
66
- // 2. Read and validate metadata before any side effects
67
- const entry: AssistantEntry = JSON.parse(readFileSync(metadataPath, "utf-8"));
68
- if (!entry.resources) {
69
- throw new Error(
70
- `Retired assistant '${name}' is missing resource configuration. ` +
71
- `Fix the archive metadata at ${metadataPath} and retry, ` +
72
- `or run 'cadet hatch' to re-provision with proper resource allocation.`,
73
- );
74
- }
75
-
76
- // 3. Check that the recovering entry's own target directory is free.
77
- const target = entry.resources.instanceDir;
78
- if (existsSync(target)) {
79
- console.error(
80
- `Error: ${target} already exists (owned by ${entry.assistantId}). ` +
81
- `Retire the current assistant first.`,
82
- );
83
- process.exit(1);
84
- }
85
-
86
- // 4. Determine the original target directory, then extract and rename.
87
- //
88
- // retireLocal archives the full instanceDir. The directory is staged under
89
- // `<archive>.staging` inside the retired dir before being packed with
90
- // `tar -C <retiredDir> <stagingBasename>`, so the top-level entry inside
91
- // the tarball is always `<name>.tar.gz.staging`.
92
- //
93
- // Correct restoration: extract to retiredDir, then rename the staging entry
94
- // back to the original target path. Using homedir() as the -C target was
95
- // wrong for any instance stored outside the home directory.
96
- const targetDir = entry.resources.instanceDir;
97
- const retiredDir = dirname(archivePath);
98
- const extractedPath = join(retiredDir, basename(archivePath) + ".staging");
99
-
100
- await exec("tar", ["xzf", archivePath, "-C", retiredDir]);
101
- // Validate the staged identity before occupying the destination or updating
102
- // the registry. A failed validation leaves the archive available for retry.
103
- const signingKey = resolveExistingLocalSigningKey(
104
- entry.resources,
105
- extractedPath,
106
- );
107
- const bootstrapSecret =
108
- entry.guardianBootstrapSecret ?? generateLocalSigningKey();
109
- entry.resources = { ...entry.resources, signingKey };
110
- entry.guardianBootstrapSecret = bootstrapSecret;
111
- mkdirSync(dirname(targetDir), { recursive: true });
112
- renameSync(extractedPath, targetDir);
113
- saveAssistantEntry(entry);
114
-
115
- // 7. Start CES sibling + daemon + gateway in parallel, the way the
116
- // Docker topology brings its sibling processes up together. startCes
117
- // always launches the CES sibling.
118
- await Promise.all([
119
- startCes(false, entry.resources),
120
- startLocalDaemon(false, entry.resources, { signingKey }),
121
- startGateway(false, entry.resources, { signingKey, bootstrapSecret }),
122
- ]);
123
-
124
- unlinkSync(archivePath);
125
- unlinkSync(metadataPath);
126
-
127
- console.log(`✅ Recovered assistant '${name}'.`);
128
- },
129
- { description: "Restore a previously retired local assistant" },
130
- );
131
-