@mycadet/cli 0.12.10 → 0.13.0

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 (105) hide show
  1. package/README.md +13 -0
  2. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
  3. package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
  4. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
  5. package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
  6. package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
  7. package/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
  8. package/package.json +3 -2
  9. package/src/__tests__/assistant-client-cloud-auth.test.ts +2 -2
  10. package/src/__tests__/backup-ops-matching.test.ts +15 -13
  11. package/src/__tests__/backup-ops.test.ts +105 -0
  12. package/src/__tests__/backup.test.ts +114 -673
  13. package/src/__tests__/cloud-login-poll.test.ts +69 -0
  14. package/src/__tests__/cloud-releases.test.ts +82 -0
  15. package/src/__tests__/commands-mock.ts +101 -0
  16. package/src/__tests__/debug.test.ts +17 -91
  17. package/src/__tests__/devices.test.ts +64 -2
  18. package/src/__tests__/ensure-binary.test.ts +52 -0
  19. package/src/__tests__/gateway-token.test.ts +267 -0
  20. package/src/__tests__/hatch-next-steps.test.ts +38 -0
  21. package/src/__tests__/host-teleport-docker.test.ts +371 -0
  22. package/src/__tests__/host-teleport.test.ts +405 -0
  23. package/src/__tests__/multi-local.test.ts +3 -3
  24. package/src/__tests__/nginx-ingress.test.ts +233 -36
  25. package/src/__tests__/orphan-detection.test.ts +1 -1
  26. package/src/__tests__/paired-lifecycle.test.ts +2 -2
  27. package/src/__tests__/ps-cloud-status.test.ts +8 -7
  28. package/src/__tests__/root-backup-docker.test.ts +294 -0
  29. package/src/__tests__/root-backup.test.ts +527 -0
  30. package/src/__tests__/root-restore-command.test.ts +147 -0
  31. package/src/__tests__/root-signing-key.test.ts +50 -0
  32. package/src/__tests__/setup.test.ts +17 -7
  33. package/src/__tests__/sleep.test.ts +11 -0
  34. package/src/__tests__/teleport.test.ts +68 -2996
  35. package/src/__tests__/tunnel-startup-summary.test.ts +110 -0
  36. package/src/__tests__/tunnel-stop.test.ts +226 -0
  37. package/src/__tests__/tunnel.test.ts +13 -3
  38. package/src/__tests__/upgrade-local.test.ts +21 -11
  39. package/src/__tests__/upgrade-replay-env.test.ts +2 -2
  40. package/src/__tests__/upgrade-root-recovery.test.ts +185 -0
  41. package/src/__tests__/windows-lifecycle.test.ts +25 -0
  42. package/src/commands/backup.ts +44 -399
  43. package/src/commands/client.ts +3 -3
  44. package/src/commands/completions.ts +0 -2
  45. package/src/commands/debug.ts +75 -131
  46. package/src/commands/devices.ts +117 -47
  47. package/src/commands/gateway/token.ts +77 -23
  48. package/src/commands/hatch.ts +10 -52
  49. package/src/commands/pair.ts +9 -3
  50. package/src/commands/ps.ts +4 -2
  51. package/src/commands/restore.ts +77 -444
  52. package/src/commands/retire.ts +2 -3
  53. package/src/commands/sleep.ts +15 -2
  54. package/src/commands/teleport.ts +47 -1559
  55. package/src/commands/tunnel.ts +43 -4
  56. package/src/commands/upgrade.ts +84 -157
  57. package/src/commands/wake.ts +1 -1
  58. package/src/index.ts +0 -4
  59. package/src/lib/__tests__/http-client-version.test.ts +29 -0
  60. package/src/lib/__tests__/runtime-url.test.ts +3 -75
  61. package/src/lib/__tests__/web-dist.test.ts +27 -1
  62. package/src/lib/assistant-client.ts +1 -1
  63. package/src/lib/assistant-config.ts +20 -23
  64. package/src/lib/backup-ops.ts +37 -251
  65. package/src/lib/cloud-client.ts +10 -13
  66. package/src/lib/cloud-login-poll.ts +75 -0
  67. package/src/lib/cloud-login.ts +5 -2
  68. package/src/lib/cloud-releases.ts +54 -10
  69. package/src/lib/cloud-values.ts +1 -1
  70. package/src/lib/confirm-action.ts +2 -2
  71. package/src/lib/docker.ts +65 -34
  72. package/src/lib/ensure-binary.ts +65 -6
  73. package/src/lib/github-repository.ts +2 -0
  74. package/src/lib/guardian-token.ts +1 -23
  75. package/src/lib/hatch-local.ts +18 -52
  76. package/src/lib/hatch-next-steps.ts +15 -2
  77. package/src/lib/host-teleport.ts +506 -0
  78. package/src/lib/http-client.ts +25 -0
  79. package/src/lib/live-voice/tunnel.test.ts +1 -1
  80. package/src/lib/live-voice/tunnel.ts +3 -3
  81. package/src/lib/local.ts +10 -8
  82. package/src/lib/nginx-ingress.ts +254 -36
  83. package/src/lib/process.ts +13 -0
  84. package/src/lib/root-backup.ts +917 -0
  85. package/src/lib/root-signing-key.ts +31 -0
  86. package/src/lib/runtime-url.ts +0 -29
  87. package/src/lib/teleport-backup.ts +3 -16
  88. package/src/lib/tunnel.ts +86 -34
  89. package/src/lib/tunnels/cadet.ts +12 -1
  90. package/src/lib/tunnels/cloudflare.ts +36 -1
  91. package/src/lib/tunnels/ngrok.ts +16 -2
  92. package/src/lib/tunnels/process-lifecycle.ts +26 -0
  93. package/src/lib/tunnels/tailscale.ts +79 -1
  94. package/src/lib/upgrade-lifecycle.ts +63 -141
  95. package/src/lib/web-dist.ts +23 -1
  96. package/src/lib/xdg-log.ts +11 -0
  97. package/src/__tests__/bundle-staging.test.ts +0 -268
  98. package/src/__tests__/unpair.test.ts +0 -160
  99. package/src/commands/rollback.ts +0 -479
  100. package/src/commands/unpair.ts +0 -122
  101. package/src/lib/__tests__/job-polling.test.ts +0 -278
  102. package/src/lib/__tests__/local-runtime-client.test.ts +0 -666
  103. package/src/lib/bundle-staging.ts +0 -220
  104. package/src/lib/job-polling.ts +0 -195
  105. package/src/lib/local-runtime-client.ts +0 -374
@@ -0,0 +1,50 @@
1
+ import { afterEach, expect, test } from "bun:test";
2
+ import {
3
+ mkdtempSync,
4
+ readFileSync,
5
+ rmSync,
6
+ statSync,
7
+ symlinkSync,
8
+ writeFileSync,
9
+ } from "node:fs";
10
+ import { tmpdir } from "node:os";
11
+ import { join } from "node:path";
12
+ import { persistRootSigningKey } from "../lib/root-signing-key.js";
13
+ const directories: string[] = [];
14
+ function fixture() {
15
+ const root = mkdtempSync(join(tmpdir(), "root-signing-key-"));
16
+ directories.push(root);
17
+ return root;
18
+ }
19
+ afterEach(() => {
20
+ for (const root of directories.splice(0)) {
21
+ rmSync(root, { recursive: true, force: true });
22
+ }
23
+ });
24
+ test("persists the raw key privately so offline capture retains installation identity", () => {
25
+ const root = fixture();
26
+ persistRootSigningKey(root, "07".repeat(32));
27
+ const file = join(root, "gateway-security", "actor-token-signing-key");
28
+ expect(readFileSync(file)).toEqual(Buffer.alloc(32, 7));
29
+ if (process.platform !== "win32") {
30
+ expect(statSync(file).mode & 0o777).toBe(0o600);
31
+ }
32
+ });
33
+ test("replaces a key file link without changing its target", () => {
34
+ const root = fixture();
35
+ persistRootSigningKey(root, "07".repeat(32));
36
+ const target = join(root, "other");
37
+ writeFileSync(target, "unchanged");
38
+ const file = join(root, "gateway-security", "actor-token-signing-key");
39
+ rmSync(file);
40
+ symlinkSync(target, file);
41
+ persistRootSigningKey(root, "09".repeat(32));
42
+ expect(readFileSync(target, "utf8")).toBe("unchanged");
43
+ expect(readFileSync(file)).toEqual(Buffer.alloc(32, 9));
44
+ });
45
+ test("rejects invalid key data before writing service state", () => {
46
+ const root = fixture();
47
+ expect(() => persistRootSigningKey(root, "bad")).toThrow(
48
+ "Invalid gateway signing key",
49
+ );
50
+ });
@@ -62,7 +62,7 @@ function writeLockfile(entry: AssistantEntry): void {
62
62
  const lockfileDir = process.env.CADET_LOCKFILE_DIR!;
63
63
  mkdirSync(lockfileDir, { recursive: true });
64
64
  writeFileSync(
65
- join(lockfileDir, ".cadet.lock.json"),
65
+ join(lockfileDir, "lockfile.json"),
66
66
  JSON.stringify(
67
67
  {
68
68
  assistants: [entry],
@@ -119,6 +119,10 @@ function installFetchStub(
119
119
  });
120
120
  }
121
121
 
122
+ if (url.endsWith("/v1/config/llm/default-provider")) {
123
+ return Response.json({ provider: "anthropic" });
124
+ }
125
+
122
126
  if (url.endsWith("/v1/secrets/read")) {
123
127
  return new Response(JSON.stringify({ found: false }), {
124
128
  status: 200,
@@ -189,7 +193,9 @@ describe("setup command", () => {
189
193
 
190
194
  await setup();
191
195
 
192
- expect(fetchCalls[0].url).toBe("http://127.0.0.1:3000/v1/secrets/read");
196
+ expect(fetchCalls[0].url).toBe(
197
+ "http://127.0.0.1:3000/v1/config/llm/default-provider",
198
+ );
193
199
  expect(fetchCalls[0].headers.get("Authorization")).toBe(
194
200
  "Bearer guardian-token",
195
201
  );
@@ -245,7 +251,9 @@ describe("setup command", () => {
245
251
  // gate instead of burning retry attempts against it.
246
252
  expect(fetchCalls[0].url).toBe("http://127.0.0.1:3000/readyz");
247
253
  expect(fetchCalls[1].url).toBe("http://127.0.0.1:3000/v1/guardian/init");
248
- expect(fetchCalls[2].url).toBe("http://127.0.0.1:3000/v1/secrets/read");
254
+ expect(fetchCalls[2].url).toBe(
255
+ "http://127.0.0.1:3000/v1/config/llm/default-provider",
256
+ );
249
257
  expect(fetchCalls[2].headers.get("Authorization")).toBe(
250
258
  "Bearer leased-guardian-token",
251
259
  );
@@ -283,12 +291,14 @@ describe("setup command", () => {
283
291
  assistantId: "assistant-123",
284
292
  runtimeUrl: "https://assistant.example",
285
293
  bearerToken: "entry-token",
286
- cloud: "cadet",
294
+ cloud: "cloud",
287
295
  });
288
296
 
289
297
  await setup();
290
298
 
291
- expect(fetchCalls[0].url).toBe("https://assistant.example/v1/secrets/read");
299
+ expect(fetchCalls[0].url).toBe(
300
+ "https://assistant.example/v1/config/llm/default-provider",
301
+ );
292
302
  expect(fetchCalls[0].headers.get("Authorization")).toBe(
293
303
  "Bearer entry-token",
294
304
  );
@@ -300,7 +310,7 @@ describe("setup command", () => {
300
310
  assistantId: "assistant-123",
301
311
  runtimeUrl: "https://assistant.example",
302
312
  bearerToken: "entry-token",
303
- cloud: "cadet",
313
+ cloud: "cloud",
304
314
  });
305
315
  saveGuardianToken(
306
316
  "assistant-123",
@@ -329,7 +339,7 @@ describe("setup command", () => {
329
339
  assistantId: "assistant-123",
330
340
  runtimeUrl: "https://assistant.example",
331
341
  bearerToken: "entry-token",
332
- cloud: "cadet",
342
+ cloud: "cloud",
333
343
  });
334
344
  saveGuardianToken(
335
345
  "assistant-123",
@@ -216,6 +216,12 @@ describe("sleep command", () => {
216
216
  expect(stopProcessByPidFileMock).toHaveBeenCalledTimes(3);
217
217
  });
218
218
 
219
+ test("default sleep passes the non-escalating service stopper", async () => {
220
+ process.argv = ["bun", "cadet", "sleep", "sleep-test"];
221
+ await sleep();
222
+ expect(stopProcessByPidFileMock).toHaveBeenNthCalledWith(1, join(assistantRootDir, "workspace", "cadet.pid"), "assistant", undefined, 45_000, realProcess.stopProcessGracefully);
223
+ });
224
+
219
225
  test("force stops the assistant even when an active call lease exists", async () => {
220
226
  writeLeaseFile(["call-active-1"]);
221
227
  process.argv = ["bun", "cadet", "sleep", "sleep-test", "--force"];
@@ -238,6 +244,7 @@ describe("sleep command", () => {
238
244
  "assistant",
239
245
  undefined,
240
246
  45_000,
247
+ expect.any(Function),
241
248
  );
242
249
  expect(stopProcessByPidFileMock).toHaveBeenNthCalledWith(
243
250
  2,
@@ -245,12 +252,16 @@ describe("sleep command", () => {
245
252
  "gateway",
246
253
  undefined,
247
254
  7000,
255
+ expect.any(Function),
248
256
  );
249
257
  // The CES sibling is stopped by its PID file; a no-op when absent.
250
258
  expect(stopProcessByPidFileMock).toHaveBeenNthCalledWith(
251
259
  3,
252
260
  join(assistantRootDir, "ces.pid"),
253
261
  "credential-executor",
262
+ undefined,
263
+ 45_000,
264
+ expect.any(Function),
254
265
  );
255
266
  });
256
267