@mycadet/cli 0.12.7 → 0.12.8
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-platform-login.ts → show-cloud-login.ts} +3 -5
- package/node_modules/@mycadet/assistant-api/index.ts +11 -11
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/package.json +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +3 -2
- 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 +2 -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} +5 -5
- 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__/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 +18 -18
- package/src/__tests__/orphan-detection.test.ts +1 -1
- package/src/__tests__/pair.test.ts +1 -8
- package/src/__tests__/{ps-platform-status.test.ts → ps-cloud-status.test.ts} +79 -26
- 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} +1 -1
- package/src/__tests__/teleport-backup.test.ts +3 -3
- package/src/__tests__/teleport.test.ts +180 -196
- package/src/__tests__/tunnel.test.ts +255 -227
- package/src/__tests__/uninstall.test.ts +13 -4
- 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 +258 -41
- package/src/__tests__/workos-pkce.test.ts +2 -2
- package/src/commands/backup.ts +22 -22
- package/src/commands/client.ts +76 -76
- package/src/commands/debug.ts +20 -20
- package/src/commands/exec.ts +5 -5
- package/src/commands/hatch.ts +22 -22
- package/src/commands/login.ts +22 -22
- package/src/commands/logs.ts +1 -1
- package/src/commands/ps.ts +188 -79
- package/src/commands/restart.ts +30 -0
- package/src/commands/restore.ts +138 -20
- package/src/commands/retire.ts +46 -148
- package/src/commands/rollback.ts +18 -24
- package/src/commands/setup.ts +2 -2
- package/src/commands/teleport.ts +93 -93
- package/src/commands/terminal.ts +157 -17
- package/src/commands/tunnel.ts +80 -122
- package/src/commands/uninstall.ts +55 -7
- package/src/commands/unpair.ts +3 -3
- package/src/commands/upgrade.ts +22 -46
- package/src/commands/wake.ts +162 -46
- package/src/index.ts +3 -9
- package/src/lib/__tests__/{platform-client-signed-url.test.ts → cloud-client-signed-url.test.ts} +16 -16
- package/src/lib/__tests__/job-polling.test.ts +1 -1
- 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} +107 -98
- package/src/lib/cloud-login.ts +24 -24
- package/src/lib/{platform-releases.ts → cloud-releases.ts} +5 -5
- package/src/lib/cloud-values.ts +3 -0
- package/src/lib/config-utils.ts +1 -1
- package/src/lib/detached-process.ts +1 -1
- package/src/lib/docker.ts +111 -10
- package/src/lib/environments/__tests__/paths.test.ts +2 -2
- package/src/lib/environments/__tests__/resolve.test.ts +26 -26
- package/src/lib/environments/resolve.ts +8 -8
- package/src/lib/guardian-token.ts +36 -4
- package/src/lib/hatch-local.ts +19 -23
- package/src/lib/health-check.ts +6 -6
- package/src/lib/ingress-config.ts +8 -35
- package/src/lib/job-polling.ts +1 -1
- 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 +9 -30
- package/src/lib/nginx-ingress.ts +41 -14
- 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/sync-cloud-assistants.ts +18 -18
- 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} +15 -4
- package/src/lib/tunnels/gateway-notify.ts +61 -0
- package/src/lib/{ngrok.ts → tunnels/ngrok.ts} +201 -30
- package/src/lib/{tailscale-tunnel.ts → tunnels/tailscale.ts} +19 -5
- package/src/lib/upgrade-lifecycle.ts +3 -17
- 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/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
package/src/commands/teleport.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isCloudHome } from "../lib/cloud-values.js";
|
|
2
2
|
import { resolveAssistantApiKeyForInjection } from "../lib/assistant-api-key-resolution";
|
|
3
3
|
import {
|
|
4
4
|
findAssistantByName,
|
|
@@ -15,20 +15,20 @@ import {
|
|
|
15
15
|
computeDeviceId,
|
|
16
16
|
} from "../lib/guardian-token.js";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
readCloudToken,
|
|
19
|
+
getCloudUrl,
|
|
20
20
|
hatchAssistant,
|
|
21
|
-
|
|
21
|
+
checkExistingCloudAssistant,
|
|
22
22
|
platformPollJobStatus,
|
|
23
23
|
platformImportBundleFromGcs,
|
|
24
24
|
platformImportPreflightFromGcs,
|
|
25
|
-
|
|
25
|
+
cloudRequestSignedUrl,
|
|
26
26
|
VersionMismatchError,
|
|
27
27
|
ensureSelfHostedLocalRegistration,
|
|
28
28
|
injectCredentialsIntoAssistant,
|
|
29
29
|
fetchCurrentUser,
|
|
30
30
|
fetchOrganizationId,
|
|
31
|
-
} from "../lib/
|
|
31
|
+
} from "../lib/cloud-client.js";
|
|
32
32
|
import {
|
|
33
33
|
localRuntimeExportToGcs,
|
|
34
34
|
localRuntimeIdentity,
|
|
@@ -387,7 +387,7 @@ interface ImportResponse {
|
|
|
387
387
|
succeeded: number;
|
|
388
388
|
failed: number;
|
|
389
389
|
failedAccounts: string[];
|
|
390
|
-
|
|
390
|
+
skippedCloud?: number;
|
|
391
391
|
};
|
|
392
392
|
}
|
|
393
393
|
|
|
@@ -417,18 +417,18 @@ async function backupSourceBeforeTeleport(
|
|
|
417
417
|
): Promise<void> {
|
|
418
418
|
console.log(`Backing up ${displayName} (${cloud})...`);
|
|
419
419
|
try {
|
|
420
|
-
if (
|
|
421
|
-
const
|
|
422
|
-
if (!
|
|
420
|
+
if (isCloudHome(cloud)) {
|
|
421
|
+
const cloudToken = readCloudToken();
|
|
422
|
+
if (!cloudToken) {
|
|
423
423
|
console.error("Not logged in. Run 'cadet login' first.");
|
|
424
424
|
process.exit(1);
|
|
425
425
|
}
|
|
426
|
-
const createdAts = await listPlatformBackups(entry,
|
|
426
|
+
const createdAts = await listPlatformBackups(entry, cloudToken);
|
|
427
427
|
if (hasRecentBackup(createdAts)) {
|
|
428
428
|
console.log("Recent backup found, reusing it.");
|
|
429
429
|
return;
|
|
430
430
|
}
|
|
431
|
-
await createPlatformBackup(entry,
|
|
431
|
+
await createPlatformBackup(entry, cloudToken);
|
|
432
432
|
console.log("Backup complete.");
|
|
433
433
|
return;
|
|
434
434
|
}
|
|
@@ -465,10 +465,10 @@ async function backupSourceBeforeTeleport(
|
|
|
465
465
|
async function exportFromAssistant(
|
|
466
466
|
entry: AssistantEntry,
|
|
467
467
|
cloud: string,
|
|
468
|
-
|
|
468
|
+
bundleCloudUrl?: string,
|
|
469
469
|
): Promise<{ bundleKey: string }> {
|
|
470
|
-
const
|
|
471
|
-
if (!
|
|
470
|
+
const cloudToken = readCloudToken();
|
|
471
|
+
if (!cloudToken) {
|
|
472
472
|
console.error(
|
|
473
473
|
"Not logged in. Run 'cadet login' first (required for GCS-based teleport).",
|
|
474
474
|
);
|
|
@@ -497,7 +497,7 @@ async function exportFromAssistant(
|
|
|
497
497
|
process.exit(1);
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
// Request a signed upload URL from the
|
|
500
|
+
// Request a signed upload URL from the cloud instance that will
|
|
501
501
|
// eventually own the bundle (i.e. the one the importer will read from).
|
|
502
502
|
// Passing the target's runtime URL here keeps upload and download on
|
|
503
503
|
// the same platform — otherwise a non-default/stale platform URL would
|
|
@@ -508,15 +508,15 @@ async function exportFromAssistant(
|
|
|
508
508
|
// is reachable; a docker daemon runs inside a container and reaches the
|
|
509
509
|
// host the same way managed pods do, so its URL must be signed for the
|
|
510
510
|
// runtime-reachable storage endpoint.
|
|
511
|
-
const { url: uploadUrl, bundleKey } = await
|
|
511
|
+
const { url: uploadUrl, bundleKey } = await cloudRequestSignedUrl(
|
|
512
512
|
{
|
|
513
513
|
operation: "upload",
|
|
514
514
|
minRuntimeVersion: sourceRuntimeVersion,
|
|
515
515
|
maxRuntimeVersion: null,
|
|
516
516
|
...(cloud === "docker" ? { consumer: "runtime" as const } : {}),
|
|
517
517
|
},
|
|
518
|
-
|
|
519
|
-
|
|
518
|
+
cloudToken,
|
|
519
|
+
bundleCloudUrl,
|
|
520
520
|
);
|
|
521
521
|
|
|
522
522
|
// Wrap the kickoff in a one-shot refresh-and-retry helper so a stale-but-
|
|
@@ -579,16 +579,16 @@ async function exportFromAssistant(
|
|
|
579
579
|
return { bundleKey };
|
|
580
580
|
}
|
|
581
581
|
|
|
582
|
-
if (
|
|
583
|
-
// Ask the
|
|
582
|
+
if (isCloudHome(cloud)) {
|
|
583
|
+
// Ask the cloud runtime which version it's running so the signed-URL
|
|
584
584
|
// request records the bundle's actual `min_runtime_version`. The
|
|
585
|
-
//
|
|
585
|
+
// cloud-managed runtime is the exporter; the CLI version is
|
|
586
586
|
// unrelated. Routed via the wildcard proxy with platform-token auth
|
|
587
587
|
// (resolveRuntimeUrl + migrationRequestHeaders inside
|
|
588
588
|
// localRuntimeIdentity).
|
|
589
589
|
let sourceRuntimeVersion: string;
|
|
590
590
|
try {
|
|
591
|
-
const identity = await localRuntimeIdentity(entry,
|
|
591
|
+
const identity = await localRuntimeIdentity(entry, cloudToken);
|
|
592
592
|
sourceRuntimeVersion = identity.version;
|
|
593
593
|
} catch (err) {
|
|
594
594
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -601,26 +601,26 @@ async function exportFromAssistant(
|
|
|
601
601
|
// Platform source — request a signed upload URL on the same platform
|
|
602
602
|
// instance the bundle will eventually be imported from, then ask the
|
|
603
603
|
// managed runtime to export directly to GCS. The runtime endpoint is
|
|
604
|
-
// reached via the
|
|
604
|
+
// reached via the cloud's wildcard runtime proxy at
|
|
605
605
|
// `/v1/assistants/<id>/migrations/export-to-gcs` — the
|
|
606
606
|
// `localRuntimeExportToGcs` helper uses `resolveRuntimeMigrationUrl` to
|
|
607
|
-
// pick that shape for `
|
|
607
|
+
// pick that shape for `isCloudHome(cloud)` and `migrationRequestHeaders`
|
|
608
608
|
// to send platform-token auth (no guardian-token bootstrap).
|
|
609
|
-
const { url: uploadUrl, bundleKey } = await
|
|
609
|
+
const { url: uploadUrl, bundleKey } = await cloudRequestSignedUrl(
|
|
610
610
|
{
|
|
611
611
|
operation: "upload",
|
|
612
612
|
minRuntimeVersion: sourceRuntimeVersion,
|
|
613
613
|
maxRuntimeVersion: null,
|
|
614
|
-
// The
|
|
614
|
+
// The cloud pod PUTs the bundle, not this CLI — the URL must be
|
|
615
615
|
// signed against the runtime-reachable storage endpoint.
|
|
616
616
|
consumer: "runtime",
|
|
617
617
|
},
|
|
618
|
-
|
|
619
|
-
|
|
618
|
+
cloudToken,
|
|
619
|
+
bundleCloudUrl,
|
|
620
620
|
);
|
|
621
621
|
|
|
622
622
|
let jobId: string;
|
|
623
|
-
let exportPlatformToken =
|
|
623
|
+
let exportPlatformToken = cloudToken;
|
|
624
624
|
try {
|
|
625
625
|
({ jobId } = await localRuntimeExportToGcs(entry, exportPlatformToken, {
|
|
626
626
|
uploadUrl,
|
|
@@ -639,18 +639,18 @@ async function exportFromAssistant(
|
|
|
639
639
|
console.log(`Export started (job ${jobId})...`);
|
|
640
640
|
|
|
641
641
|
// Polling also goes through the wildcard proxy — `localRuntimePollJobStatus`
|
|
642
|
-
// builds `/v1/assistants/<id>/migrations/jobs/<jobId>` for `
|
|
642
|
+
// builds `/v1/assistants/<id>/migrations/jobs/<jobId>` for `isCloudHome(cloud)`
|
|
643
643
|
// (the dedicated `/v1/migrations/jobs/{id}/` endpoint queries platform-side
|
|
644
644
|
// ImportJob records and 404s on runtime-created job IDs).
|
|
645
645
|
const terminal = await pollJobUntilDone({
|
|
646
646
|
label: "platform export",
|
|
647
647
|
poll: () => localRuntimePollJobStatus(entry, exportPlatformToken, jobId),
|
|
648
|
-
// The
|
|
648
|
+
// The cloud token is normally static per-process, but re-reading the
|
|
649
649
|
// on-disk credential covers the case where the user ran `cadet login`
|
|
650
650
|
// in another terminal during a long migration. A persistent 401 after
|
|
651
651
|
// a re-read surfaces to the caller with a clear next step.
|
|
652
652
|
refreshOn401: async () => {
|
|
653
|
-
const refreshed =
|
|
653
|
+
const refreshed = readCloudToken();
|
|
654
654
|
if (!refreshed) {
|
|
655
655
|
throw new Error(
|
|
656
656
|
"Platform auth expired during export and no credential was found on disk. Run 'cadet login' and retry.",
|
|
@@ -683,17 +683,17 @@ async function importToAssistant(
|
|
|
683
683
|
cloud: string,
|
|
684
684
|
bundleKey: string,
|
|
685
685
|
dryRun: boolean,
|
|
686
|
-
|
|
686
|
+
bundleCloudUrl?: string,
|
|
687
687
|
): Promise<void> {
|
|
688
|
-
const
|
|
689
|
-
if (!
|
|
688
|
+
const cloudToken = readCloudToken();
|
|
689
|
+
if (!cloudToken) {
|
|
690
690
|
console.error(
|
|
691
691
|
"Not logged in. Run 'cadet login' first (required for GCS-based teleport).",
|
|
692
692
|
);
|
|
693
693
|
process.exit(1);
|
|
694
694
|
}
|
|
695
695
|
|
|
696
|
-
if (
|
|
696
|
+
if (isCloudHome(cloud)) {
|
|
697
697
|
// Platform target — the bundle is already in GCS; kick off preflight or
|
|
698
698
|
// async import via the unified job-status endpoint.
|
|
699
699
|
if (dryRun) {
|
|
@@ -701,7 +701,7 @@ async function importToAssistant(
|
|
|
701
701
|
|
|
702
702
|
const preflight = await platformImportPreflightFromGcs(
|
|
703
703
|
bundleKey,
|
|
704
|
-
|
|
704
|
+
cloudToken,
|
|
705
705
|
entry.runtimeUrl,
|
|
706
706
|
);
|
|
707
707
|
|
|
@@ -742,7 +742,7 @@ async function importToAssistant(
|
|
|
742
742
|
|
|
743
743
|
const importResult = await platformImportBundleFromGcs(
|
|
744
744
|
bundleKey,
|
|
745
|
-
|
|
745
|
+
cloudToken,
|
|
746
746
|
entry.runtimeUrl,
|
|
747
747
|
);
|
|
748
748
|
|
|
@@ -781,13 +781,13 @@ async function importToAssistant(
|
|
|
781
781
|
process.exit(1);
|
|
782
782
|
}
|
|
783
783
|
|
|
784
|
-
let importPlatformToken =
|
|
784
|
+
let importPlatformToken = cloudToken;
|
|
785
785
|
const terminal = await pollJobUntilDone({
|
|
786
786
|
label: "platform import",
|
|
787
787
|
poll: () =>
|
|
788
788
|
platformPollJobStatus(jobId, importPlatformToken, entry.runtimeUrl),
|
|
789
789
|
refreshOn401: async () => {
|
|
790
|
-
const refreshed =
|
|
790
|
+
const refreshed = readCloudToken();
|
|
791
791
|
if (!refreshed) {
|
|
792
792
|
throw new Error(
|
|
793
793
|
"Platform auth expired during import and no credential was found on disk. Run 'cadet login' and retry.",
|
|
@@ -815,7 +815,7 @@ async function importToAssistant(
|
|
|
815
815
|
console.log("Running preflight analysis...\n");
|
|
816
816
|
|
|
817
817
|
// Query the target runtime's version before requesting a signed
|
|
818
|
-
// download URL — the
|
|
818
|
+
// download URL — the cloud uses it for the bundle compatibility check.
|
|
819
819
|
let targetRuntimeVersion: string;
|
|
820
820
|
try {
|
|
821
821
|
const identity = await callRuntimeWithAuthRetry(entry, (token) =>
|
|
@@ -833,10 +833,10 @@ async function importToAssistant(
|
|
|
833
833
|
|
|
834
834
|
let bundleUrl: string;
|
|
835
835
|
try {
|
|
836
|
-
const result = await
|
|
836
|
+
const result = await cloudRequestSignedUrl(
|
|
837
837
|
{ operation: "download", bundleKey, targetRuntimeVersion },
|
|
838
|
-
|
|
839
|
-
|
|
838
|
+
cloudToken,
|
|
839
|
+
bundleCloudUrl,
|
|
840
840
|
);
|
|
841
841
|
bundleUrl = result.url;
|
|
842
842
|
} catch (err) {
|
|
@@ -854,13 +854,13 @@ async function importToAssistant(
|
|
|
854
854
|
return;
|
|
855
855
|
}
|
|
856
856
|
|
|
857
|
-
// Ask the
|
|
857
|
+
// Ask the cloud for a signed download URL and hand it to the local
|
|
858
858
|
// runtime. The runtime streams the bundle straight out of GCS — the CLI
|
|
859
859
|
// never touches the bytes. The URL must target the same platform the
|
|
860
860
|
// bundle was uploaded to; otherwise the object won't exist on this
|
|
861
861
|
// platform's GCS bucket.
|
|
862
862
|
//
|
|
863
|
-
// The
|
|
863
|
+
// The cloud's vbundle version gate compares the **target runtime's**
|
|
864
864
|
// version against the bundle's compatibility range. The CLI and the
|
|
865
865
|
// target assistant's daemon can diverge (assistants upgrade
|
|
866
866
|
// independently), so we MUST query the target runtime's `/v1/identity`
|
|
@@ -887,14 +887,14 @@ async function importToAssistant(
|
|
|
887
887
|
|
|
888
888
|
let bundleUrl: string;
|
|
889
889
|
try {
|
|
890
|
-
const result = await
|
|
890
|
+
const result = await cloudRequestSignedUrl(
|
|
891
891
|
{
|
|
892
892
|
operation: "download",
|
|
893
893
|
bundleKey,
|
|
894
894
|
targetRuntimeVersion,
|
|
895
895
|
},
|
|
896
|
-
|
|
897
|
-
|
|
896
|
+
cloudToken,
|
|
897
|
+
bundleCloudUrl,
|
|
898
898
|
);
|
|
899
899
|
bundleUrl = result.url;
|
|
900
900
|
} catch (err) {
|
|
@@ -1053,7 +1053,7 @@ export async function resolveOrHatchTarget(
|
|
|
1053
1053
|
}
|
|
1054
1054
|
|
|
1055
1055
|
if (targetEnv === "platform") {
|
|
1056
|
-
const token =
|
|
1056
|
+
const token = readCloudToken();
|
|
1057
1057
|
if (!token) {
|
|
1058
1058
|
console.error("Not logged in. Run 'cadet login' first.");
|
|
1059
1059
|
process.exit(1);
|
|
@@ -1067,13 +1067,13 @@ export async function resolveOrHatchTarget(
|
|
|
1067
1067
|
if (reusedExisting) {
|
|
1068
1068
|
const entry: AssistantEntry = {
|
|
1069
1069
|
assistantId: result.id,
|
|
1070
|
-
runtimeUrl:
|
|
1070
|
+
runtimeUrl: getCloudUrl(),
|
|
1071
1071
|
cloud: "cloud",
|
|
1072
1072
|
hatchedAt: new Date().toISOString(),
|
|
1073
1073
|
};
|
|
1074
1074
|
saveAssistantEntry(entry);
|
|
1075
1075
|
console.error(
|
|
1076
|
-
`Error: You already have a
|
|
1076
|
+
`Error: You already have a cloud assistant '${result.id}'.`,
|
|
1077
1077
|
);
|
|
1078
1078
|
console.error(
|
|
1079
1079
|
`Retire it first with 'cadet retire ${result.id}', then retry the teleport.`,
|
|
@@ -1083,7 +1083,7 @@ export async function resolveOrHatchTarget(
|
|
|
1083
1083
|
|
|
1084
1084
|
const entry: AssistantEntry = {
|
|
1085
1085
|
assistantId: result.id,
|
|
1086
|
-
runtimeUrl:
|
|
1086
|
+
runtimeUrl: getCloudUrl(),
|
|
1087
1087
|
cloud: "cloud",
|
|
1088
1088
|
hatchedAt: new Date().toISOString(),
|
|
1089
1089
|
};
|
|
@@ -1173,8 +1173,8 @@ function printImportSummary(result: ImportResponse): void {
|
|
|
1173
1173
|
const creds = result.credentialsImported;
|
|
1174
1174
|
if (creds) {
|
|
1175
1175
|
console.log(` Credentials imported: ${creds.succeeded}/${creds.total}`);
|
|
1176
|
-
if (creds.
|
|
1177
|
-
console.log(` Cadet Cloud credentials skipped: ${creds.
|
|
1176
|
+
if (creds.skippedCloud) {
|
|
1177
|
+
console.log(` Cadet Cloud credentials skipped: ${creds.skippedCloud}`);
|
|
1178
1178
|
}
|
|
1179
1179
|
if (creds.failed > 0) {
|
|
1180
1180
|
console.log(` Credentials failed: ${creds.failed}`);
|
|
@@ -1196,13 +1196,13 @@ function printImportSummary(result: ImportResponse): void {
|
|
|
1196
1196
|
|
|
1197
1197
|
/**
|
|
1198
1198
|
* After teleporting to a local/docker target, register the assistant with
|
|
1199
|
-
* the
|
|
1199
|
+
* the cloud and inject fresh cloud credentials — mirroring the
|
|
1200
1200
|
* login flow. Non-fatal: failures are logged as warnings.
|
|
1201
1201
|
*/
|
|
1202
|
-
async function
|
|
1202
|
+
async function tryInjectCloudCredentials(
|
|
1203
1203
|
entry: AssistantEntry,
|
|
1204
1204
|
): Promise<void> {
|
|
1205
|
-
const token =
|
|
1205
|
+
const token = readCloudToken();
|
|
1206
1206
|
if (!token) {
|
|
1207
1207
|
console.log(" Skipped cloud credential injection (not logged in).");
|
|
1208
1208
|
return;
|
|
@@ -1216,7 +1216,7 @@ async function tryInjectPlatformCredentials(
|
|
|
1216
1216
|
fetchCurrentVersion(entry.runtimeUrl),
|
|
1217
1217
|
fetchAssistantIngressUrl(entry.runtimeUrl, entry.bearerToken),
|
|
1218
1218
|
]);
|
|
1219
|
-
const
|
|
1219
|
+
const cloudUrl = getCloudUrl();
|
|
1220
1220
|
const registration = await ensureSelfHostedLocalRegistration(
|
|
1221
1221
|
token,
|
|
1222
1222
|
orgId,
|
|
@@ -1224,14 +1224,14 @@ async function tryInjectPlatformCredentials(
|
|
|
1224
1224
|
entry.assistantId,
|
|
1225
1225
|
"cli",
|
|
1226
1226
|
assistantVersion,
|
|
1227
|
-
|
|
1227
|
+
cloudUrl,
|
|
1228
1228
|
ingressUrl,
|
|
1229
1229
|
);
|
|
1230
1230
|
saveAssistantEntry({
|
|
1231
1231
|
...entry,
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1232
|
+
cloudAssistantId: registration.assistant.id,
|
|
1233
|
+
cloudBaseUrl: cloudUrl,
|
|
1234
|
+
cloudOrganizationId: orgId,
|
|
1235
1235
|
});
|
|
1236
1236
|
|
|
1237
1237
|
// Which key to hand the assistant, and why. Shared with login so the two
|
|
@@ -1252,8 +1252,8 @@ async function tryInjectPlatformCredentials(
|
|
|
1252
1252
|
gatewayUrl: entry.runtimeUrl,
|
|
1253
1253
|
bearerToken: entry.bearerToken,
|
|
1254
1254
|
assistantApiKey,
|
|
1255
|
-
|
|
1256
|
-
|
|
1255
|
+
cloudAssistantId: registration.assistant.id,
|
|
1256
|
+
cloudBaseUrl: cloudUrl,
|
|
1257
1257
|
organizationId: orgId,
|
|
1258
1258
|
userId: user.id,
|
|
1259
1259
|
webhookSecret: registration.webhook_secret,
|
|
@@ -1360,7 +1360,7 @@ export const teleport = Object.assign(
|
|
|
1360
1360
|
// Nothing to reject — preflight-from-gcs is now implemented for all
|
|
1361
1361
|
// target topologies including local and docker.
|
|
1362
1362
|
|
|
1363
|
-
// Version guard: block platform→non-
|
|
1363
|
+
// Version guard: block platform→non-cloud when target is behind
|
|
1364
1364
|
if (fromCloud === "cadet" && toCloud !== "cadet") {
|
|
1365
1365
|
const [sourceVersion, targetVersion] = await Promise.all([
|
|
1366
1366
|
fetchCurrentVersion(fromEntry.runtimeUrl),
|
|
@@ -1373,7 +1373,7 @@ export const teleport = Object.assign(
|
|
|
1373
1373
|
if (cmp !== null && cmp < 0) {
|
|
1374
1374
|
console.error(
|
|
1375
1375
|
`Error: Target assistant '${existingTarget.assistantId}' is running ${targetVersion}, ` +
|
|
1376
|
-
`but the
|
|
1376
|
+
`but the cloud source is on ${sourceVersion}.`,
|
|
1377
1377
|
);
|
|
1378
1378
|
console.error(
|
|
1379
1379
|
`Upgrade your ${toCloud} assistant first: cadet upgrade ${existingTarget.assistantId}`,
|
|
@@ -1386,7 +1386,7 @@ export const teleport = Object.assign(
|
|
|
1386
1386
|
// platform targets the bundle is owned by the target platform; for
|
|
1387
1387
|
// platform sources it's owned by the source platform. Only one of
|
|
1388
1388
|
// these branches applies at a time (same-env was rejected earlier).
|
|
1389
|
-
const
|
|
1389
|
+
const bundleCloudUrl =
|
|
1390
1390
|
toCloud === "cadet"
|
|
1391
1391
|
? existingTarget.runtimeUrl
|
|
1392
1392
|
: fromCloud === "cadet"
|
|
@@ -1397,7 +1397,7 @@ export const teleport = Object.assign(
|
|
|
1397
1397
|
const { bundleKey } = await exportFromAssistant(
|
|
1398
1398
|
fromEntry,
|
|
1399
1399
|
fromCloud,
|
|
1400
|
-
|
|
1400
|
+
bundleCloudUrl,
|
|
1401
1401
|
);
|
|
1402
1402
|
console.log(`Importing to ${existingTarget.assistantId} (${toCloud})...`);
|
|
1403
1403
|
await importToAssistant(
|
|
@@ -1405,7 +1405,7 @@ export const teleport = Object.assign(
|
|
|
1405
1405
|
toCloud,
|
|
1406
1406
|
bundleKey,
|
|
1407
1407
|
true,
|
|
1408
|
-
|
|
1408
|
+
bundleCloudUrl,
|
|
1409
1409
|
);
|
|
1410
1410
|
} else {
|
|
1411
1411
|
// No existing target — just describe what would happen
|
|
@@ -1423,9 +1423,9 @@ export const teleport = Object.assign(
|
|
|
1423
1423
|
}
|
|
1424
1424
|
|
|
1425
1425
|
// Platform target: reordered flow — upload to GCS before hatching so that
|
|
1426
|
-
// if export/upload fails, no empty assistant is left dangling on the
|
|
1426
|
+
// if export/upload fails, no empty assistant is left dangling on the cloud.
|
|
1427
1427
|
if (targetEnv === "platform") {
|
|
1428
|
-
const token =
|
|
1428
|
+
const token = readCloudToken();
|
|
1429
1429
|
if (!token) {
|
|
1430
1430
|
console.error("Not logged in. Run 'cadet login' first.");
|
|
1431
1431
|
process.exit(1);
|
|
@@ -1447,24 +1447,24 @@ export const teleport = Object.assign(
|
|
|
1447
1447
|
|
|
1448
1448
|
// Use the existing target's runtimeUrl for all platform calls so the
|
|
1449
1449
|
// export, upload, and import all hit the same instance.
|
|
1450
|
-
const
|
|
1450
|
+
const targetCloudUrl = existingTarget?.runtimeUrl;
|
|
1451
1451
|
|
|
1452
|
-
// Pre-check: block if the user already has a
|
|
1452
|
+
// Pre-check: block if the user already has a cloud assistant. This
|
|
1453
1453
|
// runs BEFORE the expensive export so we don't waste the upload.
|
|
1454
1454
|
if (!existingTarget) {
|
|
1455
|
-
const existing = await
|
|
1455
|
+
const existing = await checkExistingCloudAssistant(
|
|
1456
1456
|
token,
|
|
1457
|
-
|
|
1457
|
+
targetCloudUrl,
|
|
1458
1458
|
);
|
|
1459
1459
|
if (existing) {
|
|
1460
1460
|
saveAssistantEntry({
|
|
1461
1461
|
assistantId: existing.id,
|
|
1462
|
-
runtimeUrl:
|
|
1462
|
+
runtimeUrl: getCloudUrl(),
|
|
1463
1463
|
cloud: "cloud",
|
|
1464
1464
|
hatchedAt: new Date().toISOString(),
|
|
1465
1465
|
});
|
|
1466
1466
|
console.error(
|
|
1467
|
-
`Error: You already have a
|
|
1467
|
+
`Error: You already have a cloud assistant '${existing.id}'.`,
|
|
1468
1468
|
);
|
|
1469
1469
|
console.error(
|
|
1470
1470
|
`Retire it first with 'cadet retire ${existing.id}', then retry the teleport.`,
|
|
@@ -1474,20 +1474,20 @@ export const teleport = Object.assign(
|
|
|
1474
1474
|
}
|
|
1475
1475
|
|
|
1476
1476
|
// Export — for local/docker sources this uploads straight into GCS via
|
|
1477
|
-
// the
|
|
1477
|
+
// the cloud's signed URL; for platform sources this runs a server-side
|
|
1478
1478
|
// export and we read the resulting bundle_key.
|
|
1479
1479
|
// The signed upload URL must be requested from the same platform instance
|
|
1480
1480
|
// where the import will run. For existing targets that's the lockfile's
|
|
1481
|
-
// runtimeUrl; for fresh hatches it's
|
|
1481
|
+
// runtimeUrl; for fresh hatches it's getCloudUrl() (which is what
|
|
1482
1482
|
// resolveOrHatchTarget writes to the new entry).
|
|
1483
1483
|
await backupSourceBeforeTeleport(fromEntry, fromCloud, from);
|
|
1484
1484
|
|
|
1485
1485
|
console.log(`Exporting from ${from} (${fromCloud})...`);
|
|
1486
|
-
const
|
|
1486
|
+
const bundleCloudUrl = targetCloudUrl ?? getCloudUrl();
|
|
1487
1487
|
const { bundleKey } = await exportFromAssistant(
|
|
1488
1488
|
fromEntry,
|
|
1489
1489
|
fromCloud,
|
|
1490
|
-
|
|
1490
|
+
bundleCloudUrl,
|
|
1491
1491
|
);
|
|
1492
1492
|
|
|
1493
1493
|
// Hatch (export succeeded — safe to create the target)
|
|
@@ -1501,14 +1501,14 @@ export const teleport = Object.assign(
|
|
|
1501
1501
|
toCloud,
|
|
1502
1502
|
bundleKey,
|
|
1503
1503
|
false,
|
|
1504
|
-
|
|
1504
|
+
bundleCloudUrl,
|
|
1505
1505
|
);
|
|
1506
1506
|
|
|
1507
1507
|
console.log(`Teleport complete: ${from} → ${toEntry.assistantId}`);
|
|
1508
1508
|
return;
|
|
1509
1509
|
}
|
|
1510
1510
|
|
|
1511
|
-
// Non-
|
|
1511
|
+
// Non-cloud targets (local/docker)
|
|
1512
1512
|
// For local<->docker transfers, stop (sleep) the source to free up ports
|
|
1513
1513
|
// before hatching the target. We do NOT retire yet — if hatch or import
|
|
1514
1514
|
// fails, the user can recover by running `cadet wake <source>`.
|
|
@@ -1532,7 +1532,7 @@ export const teleport = Object.assign(
|
|
|
1532
1532
|
if (cmp !== null && cmp < 0) {
|
|
1533
1533
|
console.error(
|
|
1534
1534
|
`Error: Target assistant '${existingTarget.assistantId}' is running ${existingVersion}, ` +
|
|
1535
|
-
`but the
|
|
1535
|
+
`but the cloud source is on ${sourceVersion}.`,
|
|
1536
1536
|
);
|
|
1537
1537
|
console.error(
|
|
1538
1538
|
`Upgrade your ${targetEnv} assistant first: cadet upgrade ${existingTarget.assistantId}`,
|
|
@@ -1547,10 +1547,10 @@ export const teleport = Object.assign(
|
|
|
1547
1547
|
// Pin the bundle's platform instance so upload and download land on the
|
|
1548
1548
|
// same GCS bucket. For platform sources the bundle is owned by the source
|
|
1549
1549
|
// platform. For local/docker→local/docker the bundle lives on whatever
|
|
1550
|
-
// platform
|
|
1550
|
+
// platform getCloudUrl() currently resolves to — we resolve it once
|
|
1551
1551
|
// here so a lockfile change mid-teleport can't split export and import.
|
|
1552
|
-
const
|
|
1553
|
-
fromCloud === "cadet" ? fromEntry.runtimeUrl :
|
|
1552
|
+
const bundleCloudUrl =
|
|
1553
|
+
fromCloud === "cadet" ? fromEntry.runtimeUrl : getCloudUrl();
|
|
1554
1554
|
|
|
1555
1555
|
await backupSourceBeforeTeleport(fromEntry, fromCloud, from);
|
|
1556
1556
|
|
|
@@ -1559,7 +1559,7 @@ export const teleport = Object.assign(
|
|
|
1559
1559
|
const { bundleKey } = await exportFromAssistant(
|
|
1560
1560
|
fromEntry,
|
|
1561
1561
|
fromCloud,
|
|
1562
|
-
|
|
1562
|
+
bundleCloudUrl,
|
|
1563
1563
|
);
|
|
1564
1564
|
|
|
1565
1565
|
if (sourceIsLocalOrDocker && targetIsLocalOrDocker && !keepSource) {
|
|
@@ -1622,7 +1622,7 @@ export const teleport = Object.assign(
|
|
|
1622
1622
|
removeAssistantEntry(toEntry.assistantId);
|
|
1623
1623
|
console.error(
|
|
1624
1624
|
`Error: Target assistant '${toEntry.assistantId}' was running ${targetVersion}, ` +
|
|
1625
|
-
`but the
|
|
1625
|
+
`but the cloud source is on ${sourceVersion}.`,
|
|
1626
1626
|
);
|
|
1627
1627
|
console.error(
|
|
1628
1628
|
`Upgrade your ${toCloud} environment first, then retry the teleport.`,
|
|
@@ -1638,14 +1638,14 @@ export const teleport = Object.assign(
|
|
|
1638
1638
|
toCloud,
|
|
1639
1639
|
bundleKey,
|
|
1640
1640
|
false,
|
|
1641
|
-
|
|
1641
|
+
bundleCloudUrl,
|
|
1642
1642
|
);
|
|
1643
1643
|
|
|
1644
1644
|
// After successful import, inject fresh cloud credentials if the
|
|
1645
1645
|
// user is logged in — replaces the source's stale cadet:* credentials
|
|
1646
1646
|
// that were filtered during import.
|
|
1647
1647
|
if (fromCloud === "cadet") {
|
|
1648
|
-
await
|
|
1648
|
+
await tryInjectCloudCredentials(toEntry);
|
|
1649
1649
|
}
|
|
1650
1650
|
|
|
1651
1651
|
// Retire source after successful import
|