@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.
- package/README.md +2 -2
- package/knip.json +1 -1
- package/node_modules/@mycadet/assistant-api/events/cloud-disconnected.ts +21 -0
- package/node_modules/@mycadet/assistant-api/events/host-bash.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/host-cu.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/host-file.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/notification-intent.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/show-cloud-login.ts +18 -0
- package/node_modules/@mycadet/assistant-api/index.ts +11 -11
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{service-contracts/src/platform-credential.ts → assistant-api/node_modules/@mycadet/service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/assistant-api/responses/home.ts +1 -1
- package/node_modules/@mycadet/assistant-api/surfaces.ts +4 -4
- package/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
- package/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
- package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
- package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
- package/node_modules/@mycadet/environments/src/types.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/seeds.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/types.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/package.json +2 -2
- 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
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/local-mode/src/__tests__/pair.test.ts +5 -5
- package/node_modules/@mycadet/local-mode/src/__tests__/retire.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/src/config.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/index.ts +1 -1
- package/node_modules/@mycadet/local-mode/src/lockfile-contract.test.ts +3 -3
- package/node_modules/@mycadet/local-mode/src/lockfile-contract.ts +10 -5
- package/node_modules/@mycadet/local-mode/src/lockfile.test.ts +15 -15
- package/node_modules/@mycadet/local-mode/src/lockfile.ts +9 -9
- package/node_modules/@mycadet/local-mode/src/pair.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/retire.ts +3 -3
- package/node_modules/@mycadet/local-mode/src/teleport-backup-policy.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/unpair.ts +2 -2
- package/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{local-mode/node_modules/@mycadet/service-contracts/src/platform-credential.ts → service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/package.json +6 -4
- package/src/__tests__/assistant-api-key-resolution.test.ts +6 -6
- package/src/__tests__/{assistant-client-platform-auth.test.ts → assistant-client-cloud-auth.test.ts} +10 -10
- package/src/__tests__/assistant-client-refresh.test.ts +2 -2
- package/src/__tests__/backup.test.ts +86 -91
- package/src/__tests__/client-token.test.ts +1 -1
- package/src/__tests__/client-tui-refresh.test.ts +1 -1
- package/src/__tests__/client-web-config.test.ts +1 -2
- package/src/__tests__/{platform-client.test.ts → cloud-client.test.ts} +59 -59
- package/src/__tests__/{platform-releases.test.ts → cloud-releases.test.ts} +28 -18
- package/src/__tests__/{cloudflare-tunnel.test.ts → cloudflare.test.ts} +1 -1
- package/src/__tests__/connect-import.test.ts +55 -39
- package/src/__tests__/debug.test.ts +38 -38
- package/src/__tests__/ensure-binary.test.ts +182 -0
- package/src/__tests__/guardian-token.test.ts +149 -56
- package/src/__tests__/hatch-provider-secrets.test.ts +2 -2
- package/src/__tests__/helpers/guardian-token.ts +22 -0
- package/src/__tests__/helpers/http.ts +10 -0
- package/src/__tests__/nginx-ingress.test.ts +15 -20
- package/src/__tests__/ngrok-spawn.test.ts +49 -0
- package/src/__tests__/orphan-detection.test.ts +1 -1
- package/src/__tests__/pair.test.ts +149 -85
- package/src/__tests__/{ps-platform-status.test.ts → ps-cloud-status.test.ts} +80 -26
- package/src/__tests__/ps-table.test.ts +79 -0
- package/src/__tests__/{recover.test.ts → restore.test.ts} +29 -28
- package/src/__tests__/retire.test.ts +58 -199
- package/src/__tests__/root-process-lockfile.test.ts +99 -0
- package/src/__tests__/sleep.test.ts +19 -19
- package/src/__tests__/statefulset.test.ts +8 -8
- package/src/__tests__/{tailscale-tunnel.test.ts → tailscale.test.ts} +2 -2
- package/src/__tests__/teleport-backup.test.ts +3 -3
- package/src/__tests__/teleport.test.ts +180 -211
- package/src/__tests__/tunnel.test.ts +490 -270
- package/src/__tests__/uninstall.test.ts +150 -9
- package/src/__tests__/upgrade-local.test.ts +3 -3
- package/src/__tests__/upgrade-replay-env.test.ts +12 -12
- package/src/__tests__/wake.test.ts +260 -43
- package/src/__tests__/workos-pkce.test.ts +2 -2
- package/src/commands/backup.ts +24 -24
- package/src/commands/client.ts +76 -78
- package/src/commands/completions.test.ts +104 -0
- package/src/commands/completions.ts +87 -0
- package/src/commands/debug.ts +20 -20
- package/src/commands/exec.ts +12 -12
- package/src/commands/flags.ts +2 -2
- package/src/commands/hatch.ts +27 -24
- package/src/commands/login.ts +22 -22
- package/src/commands/logs.ts +8 -8
- package/src/commands/pair.ts +140 -37
- package/src/commands/ps.ts +232 -86
- package/src/commands/restart.ts +30 -0
- package/src/commands/restore.ts +140 -22
- package/src/commands/retire.ts +48 -150
- package/src/commands/rollback.ts +20 -26
- package/src/commands/setup.ts +2 -2
- package/src/commands/sleep.ts +2 -2
- package/src/commands/teleport.ts +110 -129
- package/src/commands/terminal.ts +158 -18
- package/src/commands/tunnel.ts +156 -175
- package/src/commands/uninstall.ts +137 -54
- package/src/commands/unpair.ts +3 -3
- package/src/commands/upgrade.ts +30 -54
- package/src/commands/use.ts +1 -1
- package/src/commands/wake.ts +166 -50
- package/src/index.ts +18 -9
- package/src/lib/__tests__/{platform-client-signed-url.test.ts → cloud-client-signed-url.test.ts} +16 -16
- package/src/lib/__tests__/docker.test.ts +168 -20
- package/src/lib/__tests__/job-polling.test.ts +2 -2
- package/src/lib/__tests__/local-gateway-cli.test.ts +42 -0
- package/src/lib/__tests__/local-runtime-client.test.ts +4 -4
- package/src/lib/__tests__/runtime-url.test.ts +1 -1
- package/src/lib/assistant-api-key-resolution.ts +5 -5
- package/src/lib/assistant-client.ts +8 -8
- package/src/lib/assistant-config.ts +58 -12
- package/src/lib/{platform-client.ts → cloud-client.ts} +105 -99
- package/src/lib/cloud-login.ts +23 -24
- package/src/lib/{platform-releases.ts → cloud-releases.ts} +11 -9
- package/src/lib/cloud-values.ts +3 -0
- package/src/lib/color.ts +4 -0
- package/src/lib/config-utils.ts +1 -1
- package/src/lib/detached-process.ts +1 -1
- package/src/lib/docker.ts +300 -111
- package/src/lib/ensure-binary.ts +171 -0
- package/src/lib/environments/__tests__/paths.test.ts +29 -3
- package/src/lib/environments/__tests__/resolve.test.ts +26 -26
- package/src/lib/environments/paths.ts +16 -8
- package/src/lib/environments/resolve.ts +10 -12
- package/src/lib/flag-args.test.ts +1 -1
- package/src/lib/flag-args.ts +1 -1
- package/src/lib/guardian-token.ts +37 -5
- package/src/lib/hatch-local.ts +32 -29
- package/src/lib/hatch-next-steps.ts +5 -9
- package/src/lib/health-check.ts +6 -6
- package/src/lib/ingress-config.ts +8 -35
- package/src/lib/job-polling.ts +2 -2
- package/src/lib/live-voice/connection.ts +12 -12
- package/src/lib/live-voice/tunnel.test.ts +11 -11
- package/src/lib/live-voice/tunnel.ts +15 -15
- package/src/lib/local-runtime-client.ts +20 -20
- package/src/lib/local.ts +46 -34
- package/src/lib/nginx-ingress.ts +40 -15
- package/src/lib/pair.ts +1 -1
- package/src/lib/process.ts +1 -1
- package/src/lib/provider-secrets.ts +3 -3
- package/src/lib/retire-apple-container.ts +1 -1
- package/src/lib/runtime-url.ts +8 -8
- package/src/lib/statefulset.ts +2 -2
- package/src/lib/step-runner.ts +6 -1
- package/src/lib/sync-cloud-assistants.ts +19 -19
- package/src/lib/teleport-backup.ts +4 -4
- package/src/lib/terminal-client.ts +17 -17
- package/src/lib/terminal-session.ts +24 -24
- package/src/lib/{tunnel-edge.ts → tunnel.ts} +199 -11
- package/src/lib/tunnels/cadet.ts +29 -0
- package/src/lib/{cloudflare-tunnel.ts → tunnels/cloudflare.ts} +36 -15
- package/src/lib/tunnels/gateway-notify.ts +61 -0
- package/src/lib/{ngrok.ts → tunnels/ngrok.ts} +350 -89
- package/src/lib/{tailscale-tunnel.ts → tunnels/tailscale.ts} +53 -9
- package/src/lib/upgrade-lifecycle.ts +8 -21
- package/src/lib/upgrade-preflight.ts +2 -2
- package/src/lib/workos-pkce.ts +5 -5
- package/node_modules/@mycadet/assistant-api/events/platform-disconnected.ts +0 -21
- package/node_modules/@mycadet/assistant-api/events/show-platform-login.ts +0 -20
- package/src/commands/recover.ts +0 -131
- package/src/commands/roadmap.ts +0 -459
- package/src/commands/ssh.ts +0 -144
- package/src/commands/workflows.ts +0 -305
- 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 "
|
|
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 "
|
|
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
|
|
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
|
|
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<
|
|
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,
|
|
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
|
-
|
|
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 "./
|
|
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 {
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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 "./
|
|
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
|
|
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
|
package/src/lib/workos-pkce.ts
CHANGED
|
@@ -103,9 +103,9 @@ export function selectWorkosClientId(
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export async function fetchWorkosClientId(
|
|
106
|
-
|
|
106
|
+
cloudUrl: string,
|
|
107
107
|
): Promise<string> {
|
|
108
|
-
const url = `${new URL(
|
|
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
|
|
160
|
+
/** Exchange the WorkOS access token for a cloud session token. */
|
|
161
161
|
export async function exchangeAccessTokenForSession(
|
|
162
|
-
|
|
162
|
+
cloudUrl: string,
|
|
163
163
|
clientId: string,
|
|
164
164
|
accessToken: string,
|
|
165
165
|
): Promise<string> {
|
|
166
|
-
const url = `${new URL(
|
|
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
|
-
>;
|
package/src/commands/recover.ts
DELETED
|
@@ -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
|
-
|