@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,459 +0,0 @@
1
- import { readPlatformToken, getWebUrl } from "../lib/platform-client.js";
2
- import { loopbackSafeFetch } from "../lib/loopback-fetch.js";
3
-
4
- function printUsage(): void {
5
- console.log("Usage: cadet roadmap <subcommand>");
6
- console.log("");
7
- console.log("Manage roadmap items.");
8
- console.log("");
9
- console.log("Subcommands:");
10
- console.log(
11
- " list [--query <q>] [--status <s>] [--tag <slug>] [--sort upvotes|created] [--limit <n>]",
12
- );
13
- console.log(" get <slug>");
14
- console.log(
15
- " create --title <title> [--description <desc>] [--tag <slug>...]",
16
- );
17
- console.log(
18
- " update <slug> [--title <title>] [--description <desc>] [--status <s>] [--tag <slug>...]",
19
- );
20
- console.log(" delete <slug>");
21
- console.log(" upvote <slug>");
22
- console.log(" unvote <slug>");
23
- console.log("");
24
- console.log(
25
- "update: --status and --tag are staff-only. Anyone else can edit only the",
26
- );
27
- console.log(
28
- "title and description of an item they filed, while it is still open.",
29
- );
30
- console.log("");
31
- console.log("Examples:");
32
- console.log(' $ cadet roadmap list --query "dark mode"');
33
- console.log(" $ cadet roadmap list --status planned --sort upvotes");
34
- console.log(" $ cadet roadmap get my-feature-slug");
35
- console.log(' $ cadet roadmap create --title "Add dark mode"');
36
- console.log(
37
- ' $ cadet roadmap update my-feature --description "Follow the OS setting"',
38
- );
39
- console.log(" $ cadet roadmap upvote my-feature-slug");
40
- }
41
-
42
- function consumeValue(args: string[], i: number, flag: string): string {
43
- const next = args[i + 1];
44
- if (next === undefined || next.startsWith("--")) {
45
- console.error(`Error: ${flag} requires a value.`);
46
- process.exit(1);
47
- }
48
- return next;
49
- }
50
-
51
- function requireAuth(): string {
52
- const token = readPlatformToken();
53
- if (!token) {
54
- console.error("Not logged in. Run `cadet login` first.");
55
- process.exit(1);
56
- }
57
- return token;
58
- }
59
-
60
- function requireSlug(args: string[], command: string): string {
61
- const slug = args[0];
62
- if (!slug || slug.startsWith("--")) {
63
- console.error(`Usage: cadet roadmap ${command} <slug>`);
64
- process.exit(1);
65
- }
66
- return slug;
67
- }
68
-
69
- const ANSI_RE =
70
- /[\x00-\x08\x0b-\x1f\x7f]|\x1b(?:\[[0-9;]*[A-Za-z]|\].*?(?:\x07|\x1b\\))/g;
71
- function sanitize(text: string): string {
72
- return text.replace(ANSI_RE, "");
73
- }
74
-
75
- function makeLink(url: string): string {
76
- return `\x1b]8;;${url}\x1b\\${url}\x1b]8;;\x1b\\`;
77
- }
78
-
79
- async function apiFetch(
80
- path: string,
81
- options: {
82
- method?: string;
83
- token?: string;
84
- body?: Record<string, unknown>;
85
- params?: Record<string, string>;
86
- } = {},
87
- ): Promise<Response> {
88
- const webUrl = getWebUrl();
89
- let url = `${webUrl}/api/marketing${path}`;
90
- if (options.params) {
91
- const qs = new URLSearchParams(options.params).toString();
92
- if (qs) url += `?${qs}`;
93
- }
94
-
95
- const headers: Record<string, string> = {};
96
- if (options.token) headers["X-Session-Token"] = options.token;
97
- if (options.body) headers["Content-Type"] = "application/json";
98
-
99
- return loopbackSafeFetch(url, {
100
- method: options.method ?? "GET",
101
- headers,
102
- body: options.body ? JSON.stringify(options.body) : undefined,
103
- });
104
- }
105
-
106
- async function handleError(response: Response, action: string): Promise<never> {
107
- const text = await response.text().catch(() => "");
108
- console.error(`Failed to ${action} (${response.status}): ${text}`);
109
- process.exit(1);
110
- }
111
-
112
- // ── list ──
113
-
114
- interface ListItem {
115
- slug: string;
116
- title: string;
117
- status: string;
118
- upvote_count: number;
119
- comment_count: number;
120
- tags: { slug: string; name: string }[];
121
- viewer_upvoted: boolean | null;
122
- }
123
-
124
- async function roadmapList(args: string[]): Promise<void> {
125
- const params: Record<string, string> = {};
126
- const token = readPlatformToken() ?? undefined;
127
-
128
- for (let i = 0; i < args.length; i++) {
129
- switch (args[i]) {
130
- case "--query":
131
- case "-q":
132
- params.q = consumeValue(args, i, "--query");
133
- i++;
134
- break;
135
- case "--status":
136
- params.status = consumeValue(args, i, "--status");
137
- i++;
138
- break;
139
- case "--tag":
140
- params.tag = consumeValue(args, i, "--tag");
141
- i++;
142
- break;
143
- case "--sort":
144
- params.sort = consumeValue(args, i, "--sort");
145
- i++;
146
- break;
147
- case "--limit":
148
- params.limit = consumeValue(args, i, "--limit");
149
- i++;
150
- break;
151
- case "--offset":
152
- params.offset = consumeValue(args, i, "--offset");
153
- i++;
154
- break;
155
- }
156
- }
157
-
158
- const response = await apiFetch("/v1/roadmap", { params, token });
159
- if (!response.ok) return handleError(response, "list roadmap items");
160
-
161
- const data = (await response.json()) as {
162
- items: ListItem[];
163
- total: number;
164
- };
165
-
166
- if (data.items.length === 0) {
167
- console.log("No roadmap items found.");
168
- return;
169
- }
170
-
171
- const webUrl = getWebUrl();
172
- console.log(`Showing ${data.items.length} of ${data.total} items:\n`);
173
-
174
- for (const item of data.items) {
175
- const upvoted = item.viewer_upvoted ? " (upvoted)" : "";
176
- const tags =
177
- item.tags.length > 0
178
- ? ` [${item.tags.map((t) => sanitize(t.slug)).join(", ")}]`
179
- : "";
180
- console.log(
181
- ` ${sanitize(item.title)} ▲${item.upvote_count}${upvoted} 💬${item.comment_count} ${item.status}${tags}`,
182
- );
183
- console.log(` ${makeLink(`${webUrl}/roadmap/${item.slug}`)}`);
184
- }
185
- }
186
-
187
- // ── get ──
188
-
189
- async function roadmapGet(args: string[]): Promise<void> {
190
- const slug = requireSlug(args, "get");
191
- const token = readPlatformToken() ?? undefined;
192
- const response = await apiFetch(`/v1/roadmap/${slug}`, { token });
193
- if (!response.ok) return handleError(response, "get roadmap item");
194
-
195
- const item = (await response.json()) as {
196
- slug: string;
197
- title: string;
198
- description: string;
199
- status: string;
200
- upvote_count: number;
201
- comment_count: number;
202
- tags: { slug: string; name: string }[];
203
- viewer_upvoted: boolean | null;
204
- creator_username: string;
205
- created: string;
206
- comments: {
207
- id: string;
208
- author_username: string;
209
- author_is_staff: boolean;
210
- body: string;
211
- created: string;
212
- }[];
213
- };
214
-
215
- const webUrl = getWebUrl();
216
- const upvoted = item.viewer_upvoted ? " (upvoted)" : "";
217
- const tags =
218
- item.tags.length > 0
219
- ? item.tags.map((t) => sanitize(t.slug)).join(", ")
220
- : "none";
221
-
222
- console.log(sanitize(item.title));
223
- console.log(` slug: ${item.slug}`);
224
- console.log(` status: ${item.status}`);
225
- console.log(` upvotes: ${item.upvote_count}${upvoted}`);
226
- console.log(` tags: ${tags}`);
227
- console.log(` by: ${sanitize(item.creator_username)}`);
228
- console.log(` created: ${item.created}`);
229
- console.log(` url: ${makeLink(`${webUrl}/roadmap/${item.slug}`)}`);
230
- if (item.description) {
231
- console.log(`\n${sanitize(item.description)}`);
232
- }
233
-
234
- if (item.comments.length > 0) {
235
- console.log(`\nComments (${item.comments.length}):`);
236
- for (const c of item.comments) {
237
- const staff = c.author_is_staff ? " [staff]" : "";
238
- console.log(` ${sanitize(c.author_username)}${staff} (${c.created}):`);
239
- console.log(` ${sanitize(c.body)}`);
240
- }
241
- }
242
- }
243
-
244
- // ── create ──
245
-
246
- async function roadmapCreate(args: string[]): Promise<void> {
247
- let title: string | undefined;
248
- let description: string | undefined;
249
- const tags: string[] = [];
250
-
251
- for (let i = 0; i < args.length; i++) {
252
- switch (args[i]) {
253
- case "--title":
254
- title = consumeValue(args, i, "--title");
255
- i++;
256
- break;
257
- case "--description":
258
- description = consumeValue(args, i, "--description");
259
- i++;
260
- break;
261
- case "--tag":
262
- tags.push(consumeValue(args, i, "--tag"));
263
- i++;
264
- break;
265
- }
266
- }
267
-
268
- if (!title) {
269
- console.error("Error: --title is required.");
270
- console.error('Usage: cadet roadmap create --title "My feature request"');
271
- process.exitCode = 1;
272
- return;
273
- }
274
-
275
- const token = requireAuth();
276
- const body: Record<string, unknown> = { title };
277
- if (description) body.description = description;
278
- if (tags.length > 0) body.tags = tags;
279
-
280
- const response = await apiFetch("/v1/roadmap", {
281
- method: "POST",
282
- token,
283
- body,
284
- });
285
- if (!response.ok) return handleError(response, "create roadmap item");
286
-
287
- const item = (await response.json()) as {
288
- slug: string;
289
- title: string;
290
- status: string;
291
- };
292
-
293
- const webUrl = getWebUrl();
294
- console.log(`Created roadmap item: ${sanitize(item.title)}`);
295
- console.log(` slug: ${item.slug}`);
296
- console.log(` status: ${item.status}`);
297
- console.log(` url: ${makeLink(`${webUrl}/roadmap/${item.slug}`)}`);
298
- }
299
-
300
- // ── update ──
301
-
302
- async function roadmapUpdate(args: string[]): Promise<void> {
303
- const slug = requireSlug(args, "update");
304
-
305
- let title: string | undefined;
306
- let description: string | undefined;
307
- let status: string | undefined;
308
- const tags: string[] = [];
309
-
310
- for (let i = 1; i < args.length; i++) {
311
- switch (args[i]) {
312
- case "--title":
313
- title = consumeValue(args, i, "--title");
314
- i++;
315
- break;
316
- case "--description":
317
- description = consumeValue(args, i, "--description");
318
- i++;
319
- break;
320
- case "--status":
321
- status = consumeValue(args, i, "--status");
322
- i++;
323
- break;
324
- case "--tag":
325
- tags.push(consumeValue(args, i, "--tag"));
326
- i++;
327
- break;
328
- }
329
- }
330
-
331
- const body: Record<string, unknown> = {};
332
- if (title !== undefined) body.title = title;
333
- if (description !== undefined) body.description = description;
334
- if (status !== undefined) body.status = status;
335
- if (tags.length > 0) body.tags = tags;
336
-
337
- if (Object.keys(body).length === 0) {
338
- console.error("Error: at least one field to update is required.");
339
- process.exitCode = 1;
340
- return;
341
- }
342
-
343
- const token = requireAuth();
344
- const response = await apiFetch(`/v1/roadmap/${slug}`, {
345
- method: "PATCH",
346
- token,
347
- body,
348
- });
349
- if (!response.ok) return handleError(response, "update roadmap item");
350
-
351
- const item = (await response.json()) as {
352
- slug: string;
353
- title: string;
354
- status: string;
355
- };
356
-
357
- const webUrl = getWebUrl();
358
- console.log(`Updated roadmap item: ${sanitize(item.title)}`);
359
- console.log(` slug: ${item.slug}`);
360
- console.log(` status: ${item.status}`);
361
- console.log(` url: ${makeLink(`${webUrl}/roadmap/${item.slug}`)}`);
362
- }
363
-
364
- // ── delete ──
365
-
366
- async function roadmapDelete(args: string[]): Promise<void> {
367
- const slug = requireSlug(args, "delete");
368
- const token = requireAuth();
369
- const response = await apiFetch(`/v1/roadmap/${slug}`, {
370
- method: "DELETE",
371
- token,
372
- });
373
- if (!response.ok) return handleError(response, "delete roadmap item");
374
-
375
- console.log(`Deleted roadmap item: ${slug}`);
376
- }
377
-
378
- // ── upvote / unvote ──
379
-
380
- async function roadmapUpvote(args: string[]): Promise<void> {
381
- const slug = requireSlug(args, "upvote");
382
- const token = requireAuth();
383
- const response = await apiFetch(`/v1/roadmap/${slug}/upvote`, {
384
- method: "POST",
385
- token,
386
- });
387
- if (!response.ok) return handleError(response, "upvote roadmap item");
388
-
389
- const data = (await response.json()) as {
390
- slug: string;
391
- upvote_count: number;
392
- };
393
-
394
- console.log(`Upvoted: ${data.slug} (${data.upvote_count} total)`);
395
- }
396
-
397
- async function roadmapUnvote(args: string[]): Promise<void> {
398
- const slug = requireSlug(args, "unvote");
399
- const token = requireAuth();
400
- const response = await apiFetch(`/v1/roadmap/${slug}/upvote`, {
401
- method: "DELETE",
402
- token,
403
- });
404
- if (!response.ok) return handleError(response, "remove upvote");
405
-
406
- const data = (await response.json()) as {
407
- slug: string;
408
- upvote_count: number;
409
- };
410
-
411
- console.log(`Removed upvote: ${data.slug} (${data.upvote_count} total)`);
412
- }
413
-
414
- // ── main ──
415
-
416
- export const roadmap = Object.assign(
417
- async function roadmap(): Promise<void> {
418
- const args = process.argv.slice(3);
419
- const sub = args[0];
420
-
421
- if (!sub || sub === "--help" || sub === "-h") {
422
- printUsage();
423
- return;
424
- }
425
-
426
- switch (sub) {
427
- case "list":
428
- case "ls":
429
- await roadmapList(args.slice(1));
430
- break;
431
- case "get":
432
- case "show":
433
- await roadmapGet(args.slice(1));
434
- break;
435
- case "create":
436
- await roadmapCreate(args.slice(1));
437
- break;
438
- case "update":
439
- await roadmapUpdate(args.slice(1));
440
- break;
441
- case "delete":
442
- case "rm":
443
- await roadmapDelete(args.slice(1));
444
- break;
445
- case "upvote":
446
- await roadmapUpvote(args.slice(1));
447
- break;
448
- case "unvote":
449
- await roadmapUnvote(args.slice(1));
450
- break;
451
- default:
452
- console.error(`Unknown subcommand: ${sub}`);
453
- printUsage();
454
- process.exitCode = 1;
455
- }
456
- },
457
- { description: "Manage roadmap items" },
458
- );
459
-
@@ -1,144 +0,0 @@
1
- import { isManagedCloud } from "../lib/managed-cloud.js";
2
- import { spawn } from "child_process";
3
-
4
- import { extractHostFromUrl, resolveAssistant } from "../lib/assistant-config";
5
- import { dockerResourceNames } from "../lib/docker";
6
- import { getPlatformUrl, readPlatformToken } from "../lib/platform-client";
7
- import { sshAppleContainer } from "../lib/ssh-apple-container";
8
- import { interactiveSession } from "../lib/terminal-session";
9
-
10
- const SSH_OPTS = [
11
- "-o",
12
- "StrictHostKeyChecking=no",
13
- "-o",
14
- "UserKnownHostsFile=/dev/null",
15
- "-o",
16
- "ConnectTimeout=10",
17
- "-o",
18
- "LogLevel=ERROR",
19
- ];
20
-
21
- export const ssh = Object.assign(
22
- async function ssh(): Promise<void> {
23
- const args = process.argv.slice(3);
24
- if (args.includes("--help") || args.includes("-h")) {
25
- console.log("Usage: cadet ssh [<name>]");
26
- console.log("");
27
- console.log("SSH into a remote assistant instance.");
28
- console.log("");
29
- console.log("Arguments:");
30
- console.log(
31
- " <name> Name of the assistant to connect to (defaults to latest)",
32
- );
33
- process.exit(0);
34
- }
35
-
36
- const name = process.argv[3];
37
- const entry = resolveAssistant(name);
38
-
39
- if (!entry) {
40
- if (name) {
41
- console.error(`No assistant instance found with name '${name}'.`);
42
- } else {
43
- console.error("No assistant instance found. Run `cadet hatch` first.");
44
- }
45
- process.exit(1);
46
- }
47
-
48
- const cloud = entry.cloud;
49
-
50
- if (cloud === "local") {
51
- console.error(
52
- "Cannot SSH into a local assistant. Local assistants run directly on this machine.\n" +
53
- `Use 'cadet ps ${entry.assistantId}' to check its processes instead.`,
54
- );
55
- process.exit(1);
56
- }
57
-
58
- if (cloud === "aws") {
59
- console.error("SSH to AWS instances is not yet supported.");
60
- process.exit(1);
61
- }
62
-
63
- // Apple container: connect to the management socket for an interactive shell.
64
- if (cloud === "apple-container") {
65
- await sshAppleContainer(entry);
66
- return;
67
- }
68
-
69
- let child;
70
-
71
- if (cloud === "docker") {
72
- const res = dockerResourceNames(entry.assistantId);
73
- console.log(`🔗 Connecting to ${entry.assistantId} via docker exec...\n`);
74
-
75
- child = spawn(
76
- "docker",
77
- ["exec", "-it", res.assistantContainer, "/bin/sh"],
78
- { stdio: "inherit", windowsHide: true },
79
- );
80
- } else if (cloud === "gcp") {
81
- const project = entry.project;
82
- const zone = entry.zone;
83
- if (!project || !zone) {
84
- console.error(
85
- "Error: GCP project and zone not found in assistant config.",
86
- );
87
- process.exit(1);
88
- }
89
-
90
- const sshTarget = entry.sshUser
91
- ? `${entry.sshUser}@${entry.assistantId}`
92
- : entry.assistantId;
93
-
94
- console.log(`🔗 Connecting to ${entry.assistantId} via gcloud...\n`);
95
-
96
- child = spawn(
97
- "gcloud",
98
- ["compute", "ssh", sshTarget, `--project=${project}`, `--zone=${zone}`],
99
- { stdio: "inherit", windowsHide: true },
100
- );
101
- } else if (isManagedCloud(cloud)) {
102
- const token = readPlatformToken();
103
- if (!token) {
104
- console.error(
105
- "Not logged in. Run `cadet login` first to authenticate with Cadet Cloud.",
106
- );
107
- process.exit(1);
108
- }
109
- await interactiveSession({
110
- assistantId: entry.assistantId,
111
- token,
112
- platformUrl: getPlatformUrl(),
113
- });
114
- return;
115
- } else if (cloud === "custom") {
116
- const host = extractHostFromUrl(entry.runtimeUrl);
117
- const sshUser = entry.sshUser ?? "root";
118
- const sshTarget = `${sshUser}@${host}`;
119
-
120
- console.log(`🔗 Connecting to ${entry.assistantId} via ssh...\n`);
121
-
122
- child = spawn("ssh", [...SSH_OPTS, sshTarget], {
123
- stdio: "inherit",
124
- windowsHide: true,
125
- });
126
- } else {
127
- console.error(`Error: Unknown cloud type '${cloud}'.`);
128
- process.exit(1);
129
- }
130
-
131
- await new Promise<void>((resolve, reject) => {
132
- child.on("close", (code) => {
133
- if (code === 0) {
134
- resolve();
135
- } else {
136
- reject(new Error(`ssh exited with code ${code}`));
137
- }
138
- });
139
- child.on("error", reject);
140
- });
141
- },
142
- { description: "SSH into a remote assistant instance" },
143
- );
144
-