@mycadet/cli 0.12.7 → 0.12.9

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 (179) 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 +3 -2
  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 +2 -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 +21 -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 +1 -8
  80. package/src/__tests__/{ps-platform-status.test.ts → ps-cloud-status.test.ts} +79 -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 +181 -197
  90. package/src/__tests__/tunnel.test.ts +257 -222
  91. package/src/__tests__/uninstall.test.ts +13 -4
  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 -76
  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 +23 -23
  104. package/src/commands/login.ts +22 -22
  105. package/src/commands/logs.ts +8 -8
  106. package/src/commands/ps.ts +244 -86
  107. package/src/commands/restart.ts +30 -0
  108. package/src/commands/restore.ts +140 -22
  109. package/src/commands/retire.ts +48 -150
  110. package/src/commands/rollback.ts +20 -26
  111. package/src/commands/setup.ts +2 -2
  112. package/src/commands/sleep.ts +2 -2
  113. package/src/commands/teleport.ts +109 -109
  114. package/src/commands/terminal.ts +158 -18
  115. package/src/commands/tunnel.ts +138 -157
  116. package/src/commands/uninstall.ts +57 -9
  117. package/src/commands/unpair.ts +3 -3
  118. package/src/commands/upgrade.ts +30 -54
  119. package/src/commands/use.ts +1 -1
  120. package/src/commands/wake.ts +166 -50
  121. package/src/index.ts +18 -9
  122. package/src/lib/__tests__/{platform-client-signed-url.test.ts → cloud-client-signed-url.test.ts} +16 -16
  123. package/src/lib/__tests__/docker.test.ts +168 -20
  124. package/src/lib/__tests__/job-polling.test.ts +2 -2
  125. package/src/lib/__tests__/local-runtime-client.test.ts +4 -4
  126. package/src/lib/__tests__/runtime-url.test.ts +1 -1
  127. package/src/lib/assistant-api-key-resolution.ts +5 -5
  128. package/src/lib/assistant-client.ts +8 -8
  129. package/src/lib/assistant-config.ts +58 -12
  130. package/src/lib/{platform-client.ts → cloud-client.ts} +107 -98
  131. package/src/lib/cloud-login.ts +24 -24
  132. package/src/lib/{platform-releases.ts → cloud-releases.ts} +11 -9
  133. package/src/lib/cloud-values.ts +3 -0
  134. package/src/lib/config-utils.ts +1 -1
  135. package/src/lib/detached-process.ts +1 -1
  136. package/src/lib/docker.ts +260 -53
  137. package/src/lib/ensure-binary.ts +171 -0
  138. package/src/lib/environments/__tests__/paths.test.ts +2 -2
  139. package/src/lib/environments/__tests__/resolve.test.ts +26 -26
  140. package/src/lib/environments/resolve.ts +8 -8
  141. package/src/lib/flag-args.test.ts +1 -1
  142. package/src/lib/flag-args.ts +1 -1
  143. package/src/lib/guardian-token.ts +37 -5
  144. package/src/lib/hatch-local.ts +19 -23
  145. package/src/lib/health-check.ts +6 -6
  146. package/src/lib/ingress-config.ts +8 -35
  147. package/src/lib/job-polling.ts +2 -2
  148. package/src/lib/live-voice/connection.ts +12 -12
  149. package/src/lib/live-voice/tunnel.test.ts +11 -11
  150. package/src/lib/live-voice/tunnel.ts +15 -15
  151. package/src/lib/local-runtime-client.ts +20 -20
  152. package/src/lib/local.ts +10 -31
  153. package/src/lib/nginx-ingress.ts +42 -15
  154. package/src/lib/pair.ts +1 -1
  155. package/src/lib/process.ts +1 -1
  156. package/src/lib/provider-secrets.ts +3 -3
  157. package/src/lib/retire-apple-container.ts +1 -1
  158. package/src/lib/runtime-url.ts +8 -8
  159. package/src/lib/statefulset.ts +2 -2
  160. package/src/lib/sync-cloud-assistants.ts +19 -19
  161. package/src/lib/teleport-backup.ts +4 -4
  162. package/src/lib/terminal-client.ts +17 -17
  163. package/src/lib/terminal-session.ts +24 -24
  164. package/src/lib/{tunnel-edge.ts → tunnel.ts} +199 -11
  165. package/src/lib/tunnels/cadet.ts +29 -0
  166. package/src/lib/{cloudflare-tunnel.ts → tunnels/cloudflare.ts} +36 -15
  167. package/src/lib/tunnels/gateway-notify.ts +61 -0
  168. package/src/lib/{ngrok.ts → tunnels/ngrok.ts} +350 -89
  169. package/src/lib/{tailscale-tunnel.ts → tunnels/tailscale.ts} +53 -9
  170. package/src/lib/upgrade-lifecycle.ts +8 -21
  171. package/src/lib/upgrade-preflight.ts +2 -2
  172. package/src/lib/workos-pkce.ts +5 -5
  173. package/node_modules/@mycadet/assistant-api/events/platform-disconnected.ts +0 -21
  174. package/node_modules/@mycadet/assistant-api/events/show-platform-login.ts +0 -20
  175. package/src/commands/recover.ts +0 -131
  176. package/src/commands/roadmap.ts +0 -459
  177. package/src/commands/ssh.ts +0 -144
  178. package/src/commands/workflows.ts +0 -305
  179. package/src/lib/managed-cloud.ts +0 -3
@@ -19,10 +19,13 @@ import { join } from "node:path";
19
19
  import { cloudAssistantHubUrl } from "@mycadet/environments";
20
20
 
21
21
  import {
22
+ clearRootProcess,
22
23
  getAssistantDisplayName,
23
24
  lookupAssistantByIdentifier,
25
+ stampRootProcess,
24
26
  type AssistantEntry,
25
27
  } from "./assistant-config.js";
28
+ import type { RemoteHost } from "./constants.js";
26
29
  import { getCurrentEnvironment } from "./environments/resolve.js";
27
30
  import { waitForDaemonReady } from "./http-client.js";
28
31
  import {
@@ -159,6 +162,12 @@ export function cloudWebHubUrl(env: string | undefined): string {
159
162
  return cloudAssistantHubUrl(env);
160
163
  }
161
164
 
165
+ // The edge serves remote browsers, so the bundle's remote-gateway machinery
166
+ // must always run: it is reached through this self-hosted edge however the
167
+ // cadet itself is hosted. "cloud" is never stamped (the cloud serves its
168
+ // own bundles).
169
+ const EDGE_SERVED_REMOTE: RemoteHost = "custom";
170
+
162
171
  function remoteWebIngressConfig(
163
172
  opts: Pick<
164
173
  RemoteWebIngressOptions,
@@ -166,10 +175,10 @@ function remoteWebIngressConfig(
166
175
  >,
167
176
  ): Record<string, unknown> {
168
177
  return {
169
- mode: "remote-gateway",
178
+ remote: EDGE_SERVED_REMOTE,
170
179
  apiBaseUrl: "/v1",
171
- platformDisabled: true,
172
- disablePlatform: true,
180
+ cloudDisabled: true,
181
+ disableCloud: true,
173
182
  ...(opts.assistantName ? { assistantName: opts.assistantName } : {}),
174
183
  ...(opts.assistantId ? { assistantId: opts.assistantId } : {}),
175
184
  ...(opts.hubUrl ? { hubUrl: opts.hubUrl } : {}),
@@ -182,7 +191,7 @@ function remoteWebIngressConfig(
182
191
  * fingerprint matches, so this must change whenever the generated index or
183
192
  * nginx template does.
184
193
  */
185
- export const EDGE_TEMPLATE_VERSION = 8;
194
+ export const EDGE_TEMPLATE_VERSION = 9;
186
195
 
187
196
  /**
188
197
  * Stable fingerprint of the SPA config injected into the served index and
@@ -353,7 +362,7 @@ http {
353
362
  # remote client cannot smuggle one. Every caller reaches this loopback-only
354
363
  # listener through the TLS-terminating front (tunnel agent), so the raw peer
355
364
  # is always 127.0.0.1; the front records the real client as the RIGHTMOST
356
- # X-Forwarded-For entry (ngrok/cloudflared append, tailscale serve sets it),
365
+ # X-Forwarded-For entry (tunnel providers append one; tailscale serve sets it),
357
366
  # which the remote client cannot control. Fall back to the raw peer when the
358
367
  # front sets no X-Forwarded-For.
359
368
  map $http_x_forwarded_for $cadet_edge_client_ip {
@@ -487,7 +496,8 @@ export function getNginxVersion(): string | null {
487
496
  * process.ts helpers: stopProcessByPidFile's isCadetProcess() guard only
488
497
  * matches command lines containing a cadet path, which fails for a custom
489
498
  * CADET_WORKSPACE_DIR and would silently leave nginx running (the same
490
- * reason local.ts kills ngrok directly). This module is also imported by
499
+ * reason local.ts stops the tunnel agent directly). This module is also
500
+ * imported by
491
501
  * sleep/retire, whose tests mock.module() process.js process-globally —
492
502
  * depending on it here would couple this lib's behavior to those mocks.
493
503
  */
@@ -618,13 +628,15 @@ function clearIngressState(workspaceDir: string): void {
618
628
  function clearStoppedIngress(workspaceDir: string, pidPath: string): void {
619
629
  clearIngressState(workspaceDir);
620
630
  rmSync(pidPath, { force: true });
631
+ // The edge is gone; drop the root lockfile's process entry with it.
632
+ clearRootProcess("app");
621
633
  }
622
634
 
623
635
  /**
624
- * Write the nginx config and spawn nginx detached (same idiom as the ngrok
625
- * spawn in ngrok.ts: stdout/stderr to a log file, fd closed after spawn,
626
- * caller unrefs). nginx runs with `daemon off` so the spawned process is the
627
- * master; it writes its pid to nginx.pid under the prefix dir.
636
+ * Write the nginx config and spawn nginx detached (stdout/stderr to a log
637
+ * file, fd closed after spawn, caller unrefs). nginx runs with `daemon off`
638
+ * so the spawned process is the master; it writes its pid to nginx.pid under
639
+ * the prefix dir.
628
640
  */
629
641
  export function startIngressNginx(opts: {
630
642
  workspaceDir: string;
@@ -1028,8 +1040,22 @@ export async function stopContainerTunnelEdge(
1028
1040
  return stopIngressNginx(workspaceDir);
1029
1041
  }
1030
1042
 
1031
- /** Resolved edge a tunnel (or bring-your-own HTTPS front) should target. */
1032
- export interface TunnelEdge {
1043
+ /** Record the running edge's pid in the root lockfile for `cadet ps`. */
1044
+ function stampAppProcessEntry(
1045
+ workspaceDir: string,
1046
+ assistantId?: string,
1047
+ ): void {
1048
+ const pid = getIngressPid(workspaceDir);
1049
+ if (pid !== null) {
1050
+ stampRootProcess("app", {
1051
+ pid,
1052
+ startedAt: new Date().toISOString(),
1053
+ assistantId,
1054
+ });
1055
+ }
1056
+ }
1057
+
1058
+ /** Resolved edge a tunnel (or bring-your-own HTTPS front) should target. */ export interface TunnelEdge {
1033
1059
  /** Loopback listen port the HTTPS front should forward to. */
1034
1060
  port: number;
1035
1061
  /** True when this call started the edge, false when a running one was reused. */
@@ -1081,7 +1107,6 @@ export async function ensureTunnelEdge(opts: {
1081
1107
  const assistantName = opts.assistantId
1082
1108
  ? lockfileAssistantName(opts.assistantId)
1083
1109
  : undefined;
1084
-
1085
1110
  const result = await startRemoteWebIngress({
1086
1111
  workspaceDir: opts.workspaceDir,
1087
1112
  gatewayPort: opts.gatewayPort,
@@ -1093,6 +1118,7 @@ export async function ensureTunnelEdge(opts: {
1093
1118
 
1094
1119
  switch (result.status) {
1095
1120
  case "started":
1121
+ stampAppProcessEntry(opts.workspaceDir, opts.assistantId);
1096
1122
  return {
1097
1123
  port: result.listenPort,
1098
1124
  started: true,
@@ -1126,6 +1152,7 @@ export async function ensureTunnelEdge(opts: {
1126
1152
  stuckEdgeRecoveryHint(opts.workspaceDir),
1127
1153
  );
1128
1154
  }
1155
+ stampAppProcessEntry(opts.workspaceDir, opts.assistantId);
1129
1156
  return {
1130
1157
  port: result.listenPort,
1131
1158
  started: false,
@@ -1135,13 +1162,13 @@ export async function ensureTunnelEdge(opts: {
1135
1162
  case "nginx-missing":
1136
1163
  throw new Error(
1137
1164
  "nginx is not installed, so the tunnel edge cannot start. " +
1138
- "Install it (macOS: `brew install nginx`, Linux: `sudo apt install nginx`) " +
1165
+ "See https://nginx.org/en/docs/install.html for how to install, " +
1139
1166
  "or point NGINX_BIN at an existing binary.",
1140
1167
  );
1141
1168
  case "web-dist-missing":
1142
1169
  throw new Error(
1143
1170
  "Unable to locate built web assets for the remote web edge. " +
1144
- "Build the SPA (`cd clients/web && VITE_PLATFORM_MODE=false bun run build`) " +
1171
+ "Build the SPA with `cd clients/web && VITE_CLOUD_MODE=false bun run build`, " +
1145
1172
  "or install @mycadet/web so its packaged dist directory is available.",
1146
1173
  );
1147
1174
  case "unreachable":
package/src/lib/pair.ts CHANGED
@@ -50,6 +50,6 @@ export function formatWebApproveFailure(
50
50
  return [
51
51
  `${rejection} ${gatewayUrl} (assistant "${assistantReference}", environment "${envName}").`,
52
52
  `Codes are minted by the gateway that serves the pair page, expire after ${CODE_TTL_MINUTES} minutes, and are single-use.`,
53
- "If the pair page came from a different assistant or environment (e.g. the desktop app's), re-run with that environment's CADET_ENVIRONMENT and that assistant's name.",
53
+ "If the pair page came from a different assistant or environment, such as the desktop app's, re-run with that environment's CADET_ENVIRONMENT and that assistant's name.",
54
54
  ].join("\n");
55
55
  }
@@ -76,7 +76,7 @@ export function windowsCommandLineLookupArgs(pid: number): string[] {
76
76
  ];
77
77
  }
78
78
 
79
- /** Read a process command line using the platform's process inspection tool. */
79
+ /** Read a process command line using the cloud's process inspection tool. */
80
80
  export function readProcessCommandLine(
81
81
  pid: number,
82
82
  hostPlatform: NodeJS.Platform = platform(),
@@ -86,7 +86,7 @@ const PROVIDER_LABELS: Record<LlmProviderId, string> = {
86
86
  typesafe: "TypeSafe",
87
87
  };
88
88
 
89
- // Ranked for the hatch prompt: Cadet Cloud first (the managed connection —
89
+ // Ranked for the hatch prompt: Cadet Cloud first (the cloud connection —
90
90
  // no key to collect), then the hosted-inference gateways, then the BYO-key
91
91
  // incumbents, then the rest, with the endpoint-supplied catalogs last.
92
92
  export const HATCH_PROVIDER_CHOICES: readonly LlmProviderId[] = [
@@ -681,11 +681,11 @@ export async function ensureProviderApiKey(
681
681
 
682
682
  if (!envVarName) {
683
683
  // Managed-connection provider (e.g. Cadet Cloud): authenticated through
684
- // the platform, not a user-supplied API key. Checked before the
684
+ // the cloud, not a user-supplied API key. Checked before the
685
685
  // supported-provider guard so the keyless flow stays reachable.
686
686
  return {
687
687
  status: "skipped",
688
- message: `${providerName} authenticates through the managed connection; no API key needed.`,
688
+ message: `${providerName} authenticates through the cloud connection; no API key needed.`,
689
689
  };
690
690
  }
691
691
 
@@ -7,7 +7,7 @@ import type { AssistantEntry } from "./assistant-config.js";
7
7
  * Retire an Apple Container assistant by sending a retire command to the
8
8
  * macOS app via the management socket. The app handles the full lifecycle:
9
9
  * stop the pod, archive the instance directory, remove the guardian token,
10
- * deregister from the platform, and remove the lockfile entry.
10
+ * deregister from the cloud, and remove the lockfile entry.
11
11
  */
12
12
  export async function retireAppleContainer(
13
13
  name: string,
@@ -1,4 +1,4 @@
1
- import { isManagedCloud } from "./managed-cloud.js";
1
+ import { isCloudHome } from "./cloud-values.js";
2
2
  import { hostname } from "node:os";
3
3
 
4
4
  import { getLocalLanIPv4 } from "./local";
@@ -11,12 +11,12 @@ import type { AssistantEntry } from "./assistant-config.js";
11
11
  * - For local/docker assistants, `runtimeUrl` is the loopback gateway and
12
12
  * the runtime serves `/v1/migrations/<subpath>` directly. The CLI hits
13
13
  * that path with guardian-token bearer auth.
14
- * - For platform-managed (cloud="cadet") assistants, `runtimeUrl` is the
15
- * platform host (e.g. `https://cloud.mycadet.ai`). The platform's
14
+ * - For cloud-managed (cloud="cadet") assistants, `runtimeUrl` is the
15
+ * platform host (e.g. `https://cloud.mycadet.ai`). The cloud's
16
16
  * `MigrationViewSet` does NOT expose `export-to-gcs` or arbitrary runtime
17
17
  * migration paths under `/v1/migrations/...`. The wildcard runtime proxy
18
18
  * at `/v1/assistants/<id>/<path:rest>` is what forwards arbitrary runtime
19
- * paths to the managed runtime — vembda's unified proxy bootstraps the
19
+ * paths to the cloud runtime — vembda's unified proxy bootstraps the
20
20
  * guardian token internally for the runtime call. From the CLI side it's
21
21
  * user-session auth.
22
22
  *
@@ -27,7 +27,7 @@ export function resolveRuntimeMigrationUrl(
27
27
  entry: Pick<AssistantEntry, "cloud" | "runtimeUrl" | "assistantId">,
28
28
  subpath: string,
29
29
  ): string {
30
- if (isManagedCloud(entry.cloud)) {
30
+ if (isCloudHome(entry.cloud)) {
31
31
  return `${entry.runtimeUrl}/v1/assistants/${entry.assistantId}/migrations/${subpath}`;
32
32
  }
33
33
  return `${entry.runtimeUrl}/v1/migrations/${subpath}`;
@@ -39,9 +39,9 @@ export function resolveRuntimeMigrationUrl(
39
39
  *
40
40
  * - For local/docker assistants, `runtimeUrl` is the loopback gateway and
41
41
  * the runtime serves `/v1/<subpath>` directly.
42
- * - For platform-managed (cloud="cadet") assistants the path is rewritten
42
+ * - For cloud-managed (cloud="cadet") assistants the path is rewritten
43
43
  * to the wildcard runtime proxy:
44
- * `{platformUrl}/v1/assistants/<assistantId>/<subpath>`.
44
+ * `{cloudUrl}/v1/assistants/<assistantId>/<subpath>`.
45
45
  *
46
46
  * The `subpath` is appended verbatim (e.g. `"identity"`).
47
47
  */
@@ -49,7 +49,7 @@ export function resolveRuntimeUrl(
49
49
  entry: Pick<AssistantEntry, "cloud" | "runtimeUrl" | "assistantId">,
50
50
  subpath: string,
51
51
  ): string {
52
- if (isManagedCloud(entry.cloud)) {
52
+ if (isCloudHome(entry.cloud)) {
53
53
  return `${entry.runtimeUrl}/v1/assistants/${entry.assistantId}/${subpath}`;
54
54
  }
55
55
  return `${entry.runtimeUrl}/v1/${subpath}`;
@@ -199,7 +199,7 @@ export const DOCKER_STATEFUL_SET_SPEC: DockerStatefulSetSpec = {
199
199
  (v): HostEnv => ({ kind: "host", name: v }),
200
200
  ),
201
201
  { kind: "host", name: "CADET_ENVIRONMENT" },
202
- { kind: "host", name: "CADET_PLATFORM_URL" },
202
+ { kind: "host", name: "CADET_CLOUD_URL" },
203
203
  ],
204
204
  volumeMounts: [
205
205
  { volumeName: "assistant-workspace", mountPath: "/workspace" },
@@ -227,7 +227,7 @@ export const DOCKER_STATEFUL_SET_SPEC: DockerStatefulSetSpec = {
227
227
  { kind: "secret", name: "ACTOR_TOKEN_SIGNING_KEY", secret: "signingKey" },
228
228
  { kind: "secret", name: "GUARDIAN_BOOTSTRAP_SECRET", secret: "bootstrapSecret" },
229
229
  { kind: "host", name: "CADET_ENVIRONMENT" },
230
- { kind: "host", name: "CADET_PLATFORM_URL" },
230
+ { kind: "host", name: "CADET_CLOUD_URL" },
231
231
  { kind: "host", name: "TUNNEL_BASE_URL" },
232
232
  ],
233
233
  volumeMounts: [
@@ -2,7 +2,7 @@
2
2
  * Sync cloud-managed (platform) assistants into the local lockfile.
3
3
  *
4
4
  * - Adds new platform assistants that aren't in the lockfile yet.
5
- * - Removes lockfile entries whose IDs are no longer returned by the platform
5
+ * - Removes lockfile entries whose IDs are no longer returned by the cloud
6
6
  * (e.g. retired assistants).
7
7
  *
8
8
  * Used by both `cadet login` and `cadet ps` to keep the lockfile fresh.
@@ -10,10 +10,10 @@
10
10
  * **Contract:** callers must verify the user is logged in (i.e. a non-empty
11
11
  * platform token exists) before invoking this helper. The "is there a token?"
12
12
  * decision belongs at the command level so commands can render the right
13
- * "Platform: …" status without ever entering the platform fetch path.
13
+ * "Platform: …" status without ever entering the cloud fetch path.
14
14
  */
15
15
 
16
- import { isManagedCloud } from "./managed-cloud.js";
16
+ import { isCloudHome } from "./cloud-values.js";
17
17
  import {
18
18
  loadAllAssistants,
19
19
  removeAssistantEntry,
@@ -21,9 +21,9 @@ import {
21
21
  } from "./assistant-config.js";
22
22
  import {
23
23
  fetchCurrentUser,
24
- fetchPlatformAssistants,
25
- getPlatformUrl,
26
- } from "./platform-client.js";
24
+ fetchCloudAssistants,
25
+ getCloudUrl,
26
+ } from "./cloud-client.js";
27
27
 
28
28
  export type SyncLogger = (message: string) => void;
29
29
 
@@ -58,12 +58,12 @@ export async function syncCloudAssistants(
58
58
  ): Promise<SyncResult | null> {
59
59
  if (!token) {
60
60
  throw new Error(
61
- "syncCloudAssistants called without a token. Callers must check `readPlatformToken()` first.",
61
+ "syncCloudAssistants called without a token. Callers must check `readCloudToken()` first.",
62
62
  );
63
63
  }
64
64
  const log = options?.log;
65
- const platformUrl = getPlatformUrl();
66
- log?.(`Platform URL: ${platformUrl}`);
65
+ const cloudUrl = getCloudUrl();
66
+ log?.(`Platform URL: ${cloudUrl}`);
67
67
  log?.(`Token found (${token.length} chars, prefix: ${token.slice(0, 6)}…)`);
68
68
 
69
69
  // Fetch user info for the login status line
@@ -83,12 +83,12 @@ export async function syncCloudAssistants(
83
83
  }
84
84
  }
85
85
 
86
- let platformAssistants: { id: string; name: string; status: string }[];
86
+ let cloudAssistants: { id: string; name: string; status: string }[];
87
87
  try {
88
88
  log?.("Fetching Cadet Cloud assistants…");
89
- platformAssistants = await fetchPlatformAssistants(token);
89
+ cloudAssistants = await fetchCloudAssistants(token);
90
90
  log?.(
91
- `Cadet Cloud returned ${platformAssistants.length} assistant(s): ${platformAssistants.map((a) => a.name || a.id).join(", ") || "(none)"}`,
91
+ `Cadet Cloud returned ${cloudAssistants.length} ${cloudAssistants.length === 1 ? "assistant" : "assistants"}: ${cloudAssistants.map((a) => a.name || a.id).join(", ") || "(none)"}`,
92
92
  );
93
93
  } catch (err) {
94
94
  const msg = err instanceof Error ? err.message : String(err);
@@ -101,29 +101,29 @@ export async function syncCloudAssistants(
101
101
  return null;
102
102
  }
103
103
 
104
- if (platformAssistants.length === 0) {
104
+ if (cloudAssistants.length === 0) {
105
105
  log?.(
106
106
  "Cadet Cloud returned 0 assistants — this may mean the API returned a non-ok status (check token validity)",
107
107
  );
108
108
  }
109
109
 
110
- const platformIds = new Set(platformAssistants.map((a) => a.id));
110
+ const platformIds = new Set(cloudAssistants.map((a) => a.id));
111
111
 
112
112
  // Add new platform assistants not yet in the lockfile
113
113
  const existingCloudEntries = loadAllAssistants().filter((a) =>
114
- isManagedCloud(a.cloud),
114
+ isCloudHome(a.cloud),
115
115
  );
116
116
  const existingCloudById = new Map(
117
117
  existingCloudEntries.map((a) => [a.assistantId, a]),
118
118
  );
119
119
  const existingCloudIds = new Set(existingCloudById.keys());
120
120
  log?.(
121
- `Lockfile has ${existingCloudIds.size} cloud assistant(s): ${[...existingCloudIds].join(", ") || "(none)"}`,
121
+ `Lockfile has ${existingCloudIds.size} ${existingCloudIds.size === 1 ? "cloud assistant" : "cloud assistants"}: ${[...existingCloudIds].join(", ") || "(none)"}`,
122
122
  );
123
123
 
124
124
  let added = 0;
125
125
  let updated = 0;
126
- for (const pa of platformAssistants) {
126
+ for (const pa of cloudAssistants) {
127
127
  const existing = existingCloudById.get(pa.id);
128
128
  const assistantName = pa.name.trim();
129
129
  const nameFields = assistantName ? { name: assistantName } : {};
@@ -132,7 +132,7 @@ export async function syncCloudAssistants(
132
132
  saveAssistantEntry({
133
133
  assistantId: pa.id,
134
134
  ...nameFields,
135
- runtimeUrl: getPlatformUrl(),
135
+ runtimeUrl: getCloudUrl(),
136
136
  cloud: "cloud",
137
137
  hatchedAt: new Date().toISOString(),
138
138
  });
@@ -147,7 +147,7 @@ export async function syncCloudAssistants(
147
147
  }
148
148
  }
149
149
 
150
- // Remove stale lockfile entries that the platform no longer knows about
150
+ // Remove stale lockfile entries that the cloud no longer knows about
151
151
  let removed = 0;
152
152
  for (const id of existingCloudIds) {
153
153
  if (!platformIds.has(id)) {
@@ -23,7 +23,7 @@ import {
23
23
 
24
24
  import type { AssistantEntry } from "./assistant-config.js";
25
25
  import { loopbackSafeFetch } from "./loopback-fetch.js";
26
- import { authHeaders, invalidateOrgIdCache } from "./platform-client.js";
26
+ import { authHeaders, invalidateOrgIdCache } from "./cloud-client.js";
27
27
  import { z } from "zod";
28
28
 
29
29
  const ManagedBackupEntrySchema = z.object({
@@ -53,7 +53,7 @@ async function errorSuffix(response: Response): Promise<string> {
53
53
  }
54
54
 
55
55
  /**
56
- * Send a platform backup request with user-session auth, refreshing the
56
+ * Send a cloud backup request with user-session auth, refreshing the
57
57
  * cached organization id once on 401 (the same recovery the runtime identity
58
58
  * probe applies).
59
59
  */
@@ -93,7 +93,7 @@ async function fetchPlatformBackups(
93
93
  }
94
94
 
95
95
  /**
96
- * `created_at` of every restorable PVC snapshot of a platform assistant:
96
+ * `created_at` of every restorable PVC snapshot of a cloud assistant:
97
97
  * `GET /v1/assistants/<id>/backups/`.
98
98
  */
99
99
  export async function listPlatformBackups(
@@ -109,7 +109,7 @@ export interface CreatePlatformBackupOptions {
109
109
  }
110
110
 
111
111
  /**
112
- * Take a PVC snapshot of a platform assistant and wait until it is
112
+ * Take a PVC snapshot of a cloud assistant and wait until it is
113
113
  * restorable: `POST /v1/assistants/<id>/backups/`, then re-list until the
114
114
  * returned `snapshot_name` reports `ready_to_use`. Throws if the POST fails
115
115
  * or the snapshot is not ready within `timeoutMs`.
@@ -2,12 +2,12 @@
2
2
  * Platform terminal API client.
3
3
  *
4
4
  * Wraps the Django terminal session endpoints that proxy through vembda to
5
- * open K8s exec streams into managed assistant containers. Same transport
5
+ * open K8s exec streams into cloud assistant containers. Same transport
6
6
  * the web UI's xterm.js terminal uses.
7
7
  */
8
8
 
9
9
  import { loopbackSafeFetch } from "./loopback-fetch.js";
10
- import { authHeaders, getPlatformUrl } from "./platform-client.js";
10
+ import { authHeaders, getCloudUrl } from "./cloud-client.js";
11
11
  import { z } from "zod";
12
12
 
13
13
  const TerminalSessionResponseSchema = z.object({ session_id: z.string() });
@@ -29,10 +29,10 @@ export async function createTerminalSession(
29
29
  assistantId: string,
30
30
  cols: number,
31
31
  rows: number,
32
- platformUrl?: string,
32
+ cloudUrl?: string,
33
33
  service?: string,
34
34
  ): Promise<{ session_id: string }> {
35
- const baseUrl = platformUrl || getPlatformUrl();
35
+ const baseUrl = cloudUrl || getCloudUrl();
36
36
  const body: Record<string, unknown> = { cols, rows };
37
37
  if (service) {
38
38
  body.service = service;
@@ -41,7 +41,7 @@ export async function createTerminalSession(
41
41
  `${baseUrl}/v1/assistants/${assistantId}/terminal/sessions/`,
42
42
  {
43
43
  method: "POST",
44
- headers: await authHeaders(token, platformUrl),
44
+ headers: await authHeaders(token, cloudUrl),
45
45
  body: JSON.stringify(body),
46
46
  },
47
47
  );
@@ -62,14 +62,14 @@ export async function closeTerminalSession(
62
62
  token: string,
63
63
  assistantId: string,
64
64
  sessionId: string,
65
- platformUrl?: string,
65
+ cloudUrl?: string,
66
66
  ): Promise<void> {
67
- const baseUrl = platformUrl || getPlatformUrl();
67
+ const baseUrl = cloudUrl || getCloudUrl();
68
68
  const response = await loopbackSafeFetch(
69
69
  `${baseUrl}/v1/assistants/${assistantId}/terminal/sessions/${sessionId}/`,
70
70
  {
71
71
  method: "DELETE",
72
- headers: await authHeaders(token, platformUrl),
72
+ headers: await authHeaders(token, cloudUrl),
73
73
  },
74
74
  );
75
75
  // 404 = already closed, treat as success
@@ -89,14 +89,14 @@ export async function sendTerminalInput(
89
89
  assistantId: string,
90
90
  sessionId: string,
91
91
  data: string,
92
- platformUrl?: string,
92
+ cloudUrl?: string,
93
93
  ): Promise<void> {
94
- const baseUrl = platformUrl || getPlatformUrl();
94
+ const baseUrl = cloudUrl || getCloudUrl();
95
95
  const response = await loopbackSafeFetch(
96
96
  `${baseUrl}/v1/assistants/${assistantId}/terminal/sessions/${sessionId}/input/`,
97
97
  {
98
98
  method: "POST",
99
- headers: await authHeaders(token, platformUrl),
99
+ headers: await authHeaders(token, cloudUrl),
100
100
  body: JSON.stringify({ data }),
101
101
  },
102
102
  );
@@ -113,14 +113,14 @@ export async function resizeTerminalSession(
113
113
  sessionId: string,
114
114
  cols: number,
115
115
  rows: number,
116
- platformUrl?: string,
116
+ cloudUrl?: string,
117
117
  ): Promise<void> {
118
- const baseUrl = platformUrl || getPlatformUrl();
118
+ const baseUrl = cloudUrl || getCloudUrl();
119
119
  const response = await loopbackSafeFetch(
120
120
  `${baseUrl}/v1/assistants/${assistantId}/terminal/sessions/${sessionId}/resize/`,
121
121
  {
122
122
  method: "POST",
123
- headers: await authHeaders(token, platformUrl),
123
+ headers: await authHeaders(token, cloudUrl),
124
124
  body: JSON.stringify({ cols, rows }),
125
125
  },
126
126
  );
@@ -143,14 +143,14 @@ export async function* subscribeTerminalEvents(
143
143
  token: string,
144
144
  assistantId: string,
145
145
  sessionId: string,
146
- platformUrl?: string,
146
+ cloudUrl?: string,
147
147
  signal?: AbortSignal,
148
148
  ): AsyncGenerator<TerminalOutputEvent> {
149
- const baseUrl = platformUrl || getPlatformUrl();
149
+ const baseUrl = cloudUrl || getCloudUrl();
150
150
  const response = await loopbackSafeFetch(
151
151
  `${baseUrl}/v1/assistants/${assistantId}/terminal/sessions/${sessionId}/events/`,
152
152
  {
153
- headers: await authHeaders(token, platformUrl),
153
+ headers: await authHeaders(token, cloudUrl),
154
154
  signal,
155
155
  },
156
156
  );