@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
package/src/commands/wake.ts
CHANGED
|
@@ -2,16 +2,23 @@ import {
|
|
|
2
2
|
SigningKeyContinuityError,
|
|
3
3
|
resolveExistingLocalSigningKey,
|
|
4
4
|
} from "@mycadet/local-mode";
|
|
5
|
-
import { writeFileSync } from "fs";
|
|
6
5
|
import { join } from "path";
|
|
7
6
|
|
|
8
7
|
import {
|
|
9
8
|
getDaemonPidPath,
|
|
9
|
+
loadAllAssistants,
|
|
10
10
|
resolveTargetAssistant,
|
|
11
11
|
saveAssistantEntry,
|
|
12
12
|
} from "../lib/assistant-config.js";
|
|
13
|
-
import {
|
|
13
|
+
import type { AssistantEntry } from "../lib/assistant-config.js";
|
|
14
14
|
import {
|
|
15
|
+
dockerResourceNames,
|
|
16
|
+
isNoSuchContainerError,
|
|
17
|
+
recreateDockerContainers,
|
|
18
|
+
wakeContainers,
|
|
19
|
+
} from "../lib/docker.js";
|
|
20
|
+
import {
|
|
21
|
+
GuardianLeasePermanentError,
|
|
15
22
|
leaseGuardianToken,
|
|
16
23
|
resetGuardianBootstrap,
|
|
17
24
|
seedGuardianTokenFromSiblingEnv,
|
|
@@ -39,22 +46,25 @@ import {
|
|
|
39
46
|
DOCKER_GATEWAY_READY_TIMEOUT_MS,
|
|
40
47
|
restoreContainerTunnelEdge,
|
|
41
48
|
restoreTunnelEdgeAndAutoTunnel,
|
|
42
|
-
} from "../lib/tunnel
|
|
49
|
+
} from "../lib/tunnel.js";
|
|
43
50
|
|
|
44
51
|
export const wake = Object.assign(
|
|
45
52
|
async function wake(): Promise<void> {
|
|
46
53
|
const args = process.argv.slice(3);
|
|
47
54
|
if (args.includes("--help") || args.includes("-h")) {
|
|
48
|
-
console.log("Usage: cadet wake [<name>] [options]");
|
|
55
|
+
console.log("Usage: cadet wake [<name> | --all] [options]");
|
|
49
56
|
console.log("");
|
|
50
57
|
console.log("Start the assistant and gateway processes.");
|
|
51
58
|
console.log("");
|
|
52
59
|
console.log("Arguments:");
|
|
53
60
|
console.log(
|
|
54
|
-
" <name> Name of the assistant to start
|
|
61
|
+
" <name> Name of the assistant to start, defaults to active or only local",
|
|
55
62
|
);
|
|
56
63
|
console.log("");
|
|
57
64
|
console.log("Options:");
|
|
65
|
+
console.log(
|
|
66
|
+
" --all Start every assistant across all remotes instead of one",
|
|
67
|
+
);
|
|
58
68
|
console.log(
|
|
59
69
|
" --watch Run assistant and gateway in watch mode (hot reload on source changes)",
|
|
60
70
|
);
|
|
@@ -80,7 +90,122 @@ export const wake = Object.assign(
|
|
|
80
90
|
// recovered deliberately via `cadet wake <id> --repair-guardian`.
|
|
81
91
|
const repairGuardian = args.includes("--repair-guardian");
|
|
82
92
|
const nameArg = args.find((a) => !a.startsWith("-"));
|
|
93
|
+
const all = args.includes("--all");
|
|
94
|
+
|
|
95
|
+
if (all && nameArg) {
|
|
96
|
+
console.error("Error: --all cannot be combined with an assistant name.");
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
if (all && (foreground || repairGuardian)) {
|
|
100
|
+
console.error(
|
|
101
|
+
"Error: --all cannot be combined with --foreground or --repair-guardian.",
|
|
102
|
+
);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (all) {
|
|
107
|
+
await wakeAll({ watch });
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
83
111
|
const entry = resolveTargetAssistant(nameArg);
|
|
112
|
+
try {
|
|
113
|
+
await wakeAssistant(entry, { watch, foreground, repairGuardian });
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (err instanceof WakeExit) {
|
|
116
|
+
console.error(`Error: ${err.message}`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Foreground blocking is a single-assistant concern (--all refuses the
|
|
123
|
+
// flag), and the docker path already warned that foreground is ignored.
|
|
124
|
+
if (foreground && entry.cloud !== "docker") {
|
|
125
|
+
console.log("Running in the foreground, Ctrl+C to stop...\n");
|
|
126
|
+
// Block forever — the daemon is running with inherited stdio so its
|
|
127
|
+
// output streams to this terminal. When the user hits Ctrl+C, SIGINT
|
|
128
|
+
// propagates to the daemon child and both exit.
|
|
129
|
+
await new Promise<void>((resolve) => {
|
|
130
|
+
process.on("SIGINT", () => {
|
|
131
|
+
console.log("\nShutting down...");
|
|
132
|
+
resolve();
|
|
133
|
+
});
|
|
134
|
+
process.on("SIGTERM", () => resolve());
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{ description: "Start the assistant and gateway" },
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Start every assistant this CLI's environment knows about — `--all`. The
|
|
143
|
+
* CLI only ever reaches one environment, so this is the current env's
|
|
144
|
+
* lockfile. Same per-assistant wake as the single path, but one assistant's
|
|
145
|
+
* failure never blocks the others; failures only decide the exit code.
|
|
146
|
+
*/
|
|
147
|
+
async function wakeAll(opts: { watch: boolean }): Promise<void> {
|
|
148
|
+
const entries = loadAllAssistants();
|
|
149
|
+
if (entries.length === 0) {
|
|
150
|
+
console.error("Error: no assistants found. Run 'cadet hatch' first.");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let failures = 0;
|
|
155
|
+
const seen = new Set<string>();
|
|
156
|
+
for (const entry of entries) {
|
|
157
|
+
if (seen.has(entry.assistantId)) continue;
|
|
158
|
+
seen.add(entry.assistantId);
|
|
159
|
+
if (entry.cloud === "apple-container" || entry.cloud === "paired") {
|
|
160
|
+
console.log(
|
|
161
|
+
`Skipping '${entry.assistantId}' (${entry.cloud}) — its lifecycle is managed elsewhere.`,
|
|
162
|
+
);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
await wakeAssistant(entry, {
|
|
167
|
+
watch: opts.watch,
|
|
168
|
+
foreground: false,
|
|
169
|
+
repairGuardian: false,
|
|
170
|
+
});
|
|
171
|
+
} catch (err) {
|
|
172
|
+
failures++;
|
|
173
|
+
console.error(
|
|
174
|
+
`Error: failed to wake '${entry.assistantId}': ${
|
|
175
|
+
err instanceof Error ? err.message : String(err)
|
|
176
|
+
}`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (failures > 0) {
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
type WakeAssistantOptions = {
|
|
186
|
+
watch: boolean;
|
|
187
|
+
foreground: boolean;
|
|
188
|
+
repairGuardian: boolean;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Marks a deliberate per-assistant refusal (an unmanageable runtime, missing
|
|
193
|
+
* resources, a daemon that died during startup). The single-assistant path
|
|
194
|
+
* renders it as the same "Error: …" + exit 1 the command always printed;
|
|
195
|
+
* `--all` treats it as one entry's failure and keeps waking the rest.
|
|
196
|
+
*/
|
|
197
|
+
class WakeExit extends Error {}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Start one assistant and its gateway. Throws WakeExit on deliberate
|
|
201
|
+
* refusals so the caller decides between exiting (single path) and
|
|
202
|
+
* continuing to the next entry (`--all`).
|
|
203
|
+
*/
|
|
204
|
+
async function wakeAssistant(
|
|
205
|
+
entry: AssistantEntry,
|
|
206
|
+
opts: WakeAssistantOptions,
|
|
207
|
+
): Promise<void> {
|
|
208
|
+
const { watch, foreground, repairGuardian } = opts;
|
|
84
209
|
|
|
85
210
|
if (entry.cloud === "docker") {
|
|
86
211
|
if (watch || foreground) {
|
|
@@ -88,11 +213,23 @@ export const wake = Object.assign(
|
|
|
88
213
|
.filter(Boolean)
|
|
89
214
|
.join(" and ");
|
|
90
215
|
console.warn(
|
|
91
|
-
`Warning: ${ignored} ignored for Docker instances
|
|
216
|
+
`Warning: ${ignored} ignored for Docker instances.`,
|
|
92
217
|
);
|
|
93
218
|
}
|
|
94
219
|
const res = dockerResourceNames(entry.assistantId);
|
|
95
|
-
|
|
220
|
+
try {
|
|
221
|
+
await wakeContainers(res);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
// A migrated install has data in the volumes but containers that were
|
|
224
|
+
// never created (v0.0.10 run feedback: "No such container"). Recreate
|
|
225
|
+
// the service group from the entry's recorded images; anything else
|
|
226
|
+
// is a real wake failure.
|
|
227
|
+
if (!isNoSuchContainerError(err)) throw err;
|
|
228
|
+
console.log(
|
|
229
|
+
`Containers for '${entry.assistantId}' don't exist yet — recreating from the recorded images...`,
|
|
230
|
+
);
|
|
231
|
+
await recreateDockerContainers(entry);
|
|
232
|
+
}
|
|
96
233
|
console.log("Docker containers started.");
|
|
97
234
|
await restoreContainerTunnelEdge(entry, DOCKER_GATEWAY_READY_TIMEOUT_MS);
|
|
98
235
|
console.log("Wake complete.");
|
|
@@ -100,31 +237,27 @@ export const wake = Object.assign(
|
|
|
100
237
|
}
|
|
101
238
|
|
|
102
239
|
if (entry.cloud === "apple-container") {
|
|
103
|
-
|
|
104
|
-
`
|
|
240
|
+
throw new WakeExit(
|
|
241
|
+
`'${entry.assistantId}' uses the Apple Containers runtime. Its lifecycle is managed by the macOS app — use the app to start it.`,
|
|
105
242
|
);
|
|
106
|
-
process.exit(1);
|
|
107
243
|
}
|
|
108
244
|
|
|
109
245
|
if (entry.cloud === "paired") {
|
|
110
|
-
|
|
111
|
-
`
|
|
246
|
+
throw new WakeExit(
|
|
247
|
+
`'${entry.assistantId}' is a remote assistant paired from another machine — its lifecycle is managed on its host machine, not here. Use \`cadet client ${entry.assistantId}\` to chat with it.`,
|
|
112
248
|
);
|
|
113
|
-
process.exit(1);
|
|
114
249
|
}
|
|
115
250
|
|
|
116
251
|
if (entry.cloud && entry.cloud !== "local") {
|
|
117
|
-
|
|
118
|
-
`
|
|
252
|
+
throw new WakeExit(
|
|
253
|
+
`'cadet wake' only works with local and docker assistants. '${entry.assistantId}' is a ${entry.cloud} instance.`,
|
|
119
254
|
);
|
|
120
|
-
process.exit(1);
|
|
121
255
|
}
|
|
122
256
|
|
|
123
257
|
if (!entry.resources) {
|
|
124
|
-
|
|
125
|
-
`
|
|
258
|
+
throw new WakeExit(
|
|
259
|
+
`Local assistant '${entry.assistantId}' is missing resource configuration. Re-hatch to fix.`,
|
|
126
260
|
);
|
|
127
|
-
process.exit(1);
|
|
128
261
|
}
|
|
129
262
|
const resources = entry.resources;
|
|
130
263
|
let signingKey: string;
|
|
@@ -231,7 +364,7 @@ export const wake = Object.assign(
|
|
|
231
364
|
daemonMigrationsFailed = daemonState.status === "migration_failed";
|
|
232
365
|
if (watch) {
|
|
233
366
|
console.log(
|
|
234
|
-
`Assistant running (pid ${daemonState.pid}) — watch mode not available
|
|
367
|
+
`Assistant running (pid ${daemonState.pid}) — watch mode not available, no source files. Keeping existing process.`,
|
|
235
368
|
);
|
|
236
369
|
} else if (daemonMigrationsFailed) {
|
|
237
370
|
console.log(
|
|
@@ -275,10 +408,9 @@ export const wake = Object.assign(
|
|
|
275
408
|
// first and fail the command instead of reporting a successful wake for
|
|
276
409
|
// an assistant that is not running.
|
|
277
410
|
if (!isProcessAlive(pidFile).alive) {
|
|
278
|
-
|
|
279
|
-
`
|
|
411
|
+
throw new WakeExit(
|
|
412
|
+
`the assistant exited during startup and is not running. Its runtime HTTP port ${resources.daemonPort} may be held by another process (check \`lsof -i :${resources.daemonPort}\`); the daemon log records the startup error it reported.`,
|
|
280
413
|
);
|
|
281
|
-
process.exit(1);
|
|
282
414
|
}
|
|
283
415
|
// startLocalDaemon's post-spawn wait is bounded (60s), and a longer
|
|
284
416
|
// migration outlives it. Classify the fresh spawn the same way the
|
|
@@ -356,7 +488,7 @@ export const wake = Object.assign(
|
|
|
356
488
|
} else {
|
|
357
489
|
if (watch) {
|
|
358
490
|
console.log(
|
|
359
|
-
`Gateway running (pid ${gatewayState.pid}) — watch mode not available
|
|
491
|
+
`Gateway running (pid ${gatewayState.pid}) — watch mode not available, no source files. Keeping existing process.`,
|
|
360
492
|
);
|
|
361
493
|
} else {
|
|
362
494
|
console.log(`Gateway already running (pid ${gatewayState.pid}).`);
|
|
@@ -430,11 +562,14 @@ export const wake = Object.assign(
|
|
|
430
562
|
console.log(" Re-provisioned guardian token.");
|
|
431
563
|
break;
|
|
432
564
|
} catch (err) {
|
|
433
|
-
if (
|
|
565
|
+
if (
|
|
566
|
+
attempt < maxAttempts &&
|
|
567
|
+
!(err instanceof GuardianLeasePermanentError)
|
|
568
|
+
) {
|
|
434
569
|
await new Promise((r) => setTimeout(r, 2000 * 2 ** (attempt - 1)));
|
|
435
570
|
} else {
|
|
436
571
|
console.warn(
|
|
437
|
-
` Guardian token re-provision failed after ${maxAttempts} attempts: ${err}`,
|
|
572
|
+
` Guardian token re-provision failed${err instanceof GuardianLeasePermanentError ?", not retrying — a malformed 200 will not fix itself" : ` after ${maxAttempts} attempts`}: ${err}`,
|
|
438
573
|
);
|
|
439
574
|
// The user explicitly confirmed this destructive repair — a
|
|
440
575
|
// success exit here would make callers (the web recovery flow)
|
|
@@ -446,18 +581,15 @@ export const wake = Object.assign(
|
|
|
446
581
|
}
|
|
447
582
|
}
|
|
448
583
|
|
|
449
|
-
// Restore the nginx edge and point the
|
|
450
|
-
//
|
|
584
|
+
// Restore the nginx edge and point the auto-tunnel at it. The spawned agent
|
|
585
|
+
// records itself in the root lockfile under `tunnel`. Non-fatal: a down
|
|
586
|
+
// edge is a degraded remote-web/webhook path, not a broken assistant.
|
|
451
587
|
const workspaceDir = join(resources.instanceDir, "workspace");
|
|
452
|
-
|
|
588
|
+
await restoreTunnelEdgeAndAutoTunnel(
|
|
453
589
|
entry.assistantId,
|
|
454
590
|
resources.gatewayPort,
|
|
455
591
|
workspaceDir,
|
|
456
592
|
);
|
|
457
|
-
if (ngrokChild?.pid) {
|
|
458
|
-
const ngrokPidFile = join(resources.instanceDir, "ngrok.pid");
|
|
459
|
-
writeFileSync(ngrokPidFile, String(ngrokChild.pid));
|
|
460
|
-
}
|
|
461
593
|
|
|
462
594
|
if (daemonMigrationsFailed) {
|
|
463
595
|
console.log(
|
|
@@ -469,21 +601,5 @@ export const wake = Object.assign(
|
|
|
469
601
|
);
|
|
470
602
|
}
|
|
471
603
|
console.log("Wake complete.");
|
|
472
|
-
|
|
473
|
-
if (foreground) {
|
|
474
|
-
console.log("Running in foreground (Ctrl+C to stop)...\n");
|
|
475
|
-
// Block forever — the daemon is running with inherited stdio so its
|
|
476
|
-
// output streams to this terminal. When the user hits Ctrl+C, SIGINT
|
|
477
|
-
// propagates to the daemon child and both exit.
|
|
478
|
-
await new Promise<void>((resolve) => {
|
|
479
|
-
process.on("SIGINT", () => {
|
|
480
|
-
console.log("\nShutting down...");
|
|
481
|
-
resolve();
|
|
482
|
-
});
|
|
483
|
-
process.on("SIGTERM", () => resolve());
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
},
|
|
487
|
-
{ description: "Start the assistant and gateway" },
|
|
488
|
-
);
|
|
604
|
+
}
|
|
489
605
|
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ import cliPkg from "../package.json";
|
|
|
14
14
|
import { backup } from "./commands/backup";
|
|
15
15
|
import { clean } from "./commands/clean";
|
|
16
16
|
import { client } from "./commands/client";
|
|
17
|
+
import { completeCadet, completions } from "./commands/completions";
|
|
17
18
|
import { confirm } from "./commands/confirm";
|
|
18
19
|
import { connect } from "./commands/connect";
|
|
19
20
|
import { devices } from "./commands/devices";
|
|
@@ -27,14 +28,12 @@ import { logs } from "./commands/logs";
|
|
|
27
28
|
import { message } from "./commands/message";
|
|
28
29
|
import { pair } from "./commands/pair";
|
|
29
30
|
import { ps } from "./commands/ps";
|
|
30
|
-
import { recover } from "./commands/recover";
|
|
31
31
|
import { restore } from "./commands/restore";
|
|
32
|
-
import { roadmap } from "./commands/roadmap";
|
|
33
32
|
import { retire } from "./commands/retire";
|
|
33
|
+
import { restart } from "./commands/restart";
|
|
34
34
|
import { rollback } from "./commands/rollback";
|
|
35
35
|
import { setup } from "./commands/setup";
|
|
36
36
|
import { sleep } from "./commands/sleep";
|
|
37
|
-
import { ssh } from "./commands/ssh";
|
|
38
37
|
import { debug } from "./commands/debug";
|
|
39
38
|
import { teleport } from "./commands/teleport";
|
|
40
39
|
import { terminal } from "./commands/terminal";
|
|
@@ -45,7 +44,6 @@ import { upgrade } from "./commands/upgrade";
|
|
|
45
44
|
import { use } from "./commands/use";
|
|
46
45
|
import { voice } from "./commands/voice";
|
|
47
46
|
import { wake } from "./commands/wake";
|
|
48
|
-
import { workflows } from "./commands/workflows";
|
|
49
47
|
import { red } from "./lib/color";
|
|
50
48
|
import { resolveAssistant, setActiveAssistant } from "./lib/assistant-config";
|
|
51
49
|
import { loadGuardianToken } from "./lib/guardian-token";
|
|
@@ -56,6 +54,7 @@ const commands = {
|
|
|
56
54
|
backup,
|
|
57
55
|
clean,
|
|
58
56
|
client,
|
|
57
|
+
completions,
|
|
59
58
|
confirm,
|
|
60
59
|
connect,
|
|
61
60
|
debug,
|
|
@@ -66,19 +65,17 @@ const commands = {
|
|
|
66
65
|
gateway,
|
|
67
66
|
hatch,
|
|
68
67
|
login,
|
|
69
|
-
logout,
|
|
70
68
|
logs,
|
|
69
|
+
logout,
|
|
71
70
|
message,
|
|
72
71
|
pair,
|
|
73
72
|
ps,
|
|
74
|
-
recover,
|
|
75
73
|
restore,
|
|
76
74
|
retire,
|
|
77
|
-
|
|
75
|
+
restart,
|
|
78
76
|
rollback,
|
|
79
77
|
setup,
|
|
80
78
|
sleep,
|
|
81
|
-
ssh,
|
|
82
79
|
teleport,
|
|
83
80
|
terminal,
|
|
84
81
|
tunnel,
|
|
@@ -89,7 +86,6 @@ const commands = {
|
|
|
89
86
|
voice,
|
|
90
87
|
wake,
|
|
91
88
|
whoami,
|
|
92
|
-
workflows,
|
|
93
89
|
};
|
|
94
90
|
|
|
95
91
|
type CommandName = keyof typeof commands;
|
|
@@ -237,6 +233,19 @@ async function main() {
|
|
|
237
233
|
process.exit(0);
|
|
238
234
|
}
|
|
239
235
|
|
|
236
|
+
// Hidden completion hook: the bash completion script calls
|
|
237
|
+
// `cadet __complete <words-up-to-cursor>` and filters the printed
|
|
238
|
+
// candidates against the word under the cursor. Deliberately unlisted in
|
|
239
|
+
// the command map so it never shows up in help.
|
|
240
|
+
if (commandName === "__complete") {
|
|
241
|
+
const candidates = completeCadet(
|
|
242
|
+
process.argv.slice(3),
|
|
243
|
+
Object.keys(commands),
|
|
244
|
+
);
|
|
245
|
+
console.log(candidates.join("\n"));
|
|
246
|
+
process.exit(0);
|
|
247
|
+
}
|
|
248
|
+
|
|
240
249
|
const command = commands[commandName as CommandName];
|
|
241
250
|
|
|
242
251
|
if (!command) {
|
package/src/lib/__tests__/{platform-client-signed-url.test.ts → cloud-client-signed-url.test.ts}
RENAMED
|
@@ -2,10 +2,10 @@ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
platformPollJobStatus,
|
|
5
|
-
|
|
5
|
+
cloudRequestSignedUrl,
|
|
6
6
|
VersionMismatchError,
|
|
7
7
|
type UnifiedJobStatus,
|
|
8
|
-
} from "../
|
|
8
|
+
} from "../cloud-client.js";
|
|
9
9
|
|
|
10
10
|
const PLATFORM_URL = "https://platform.example.test";
|
|
11
11
|
const VAK_TOKEN = "vak_test_1234567890"; // API-key path skips org-ID fetch.
|
|
@@ -69,7 +69,7 @@ afterEach(() => {
|
|
|
69
69
|
globalThis.fetch = originalFetch;
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
describe("
|
|
72
|
+
describe("cloudRequestSignedUrl", () => {
|
|
73
73
|
test("upload operation with just operation → posts correct body and parses response", async () => {
|
|
74
74
|
const { calls, fetchMock } = captureFetch(() => {
|
|
75
75
|
return new Response(
|
|
@@ -83,7 +83,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
83
83
|
});
|
|
84
84
|
globalThis.fetch = fetchMock;
|
|
85
85
|
|
|
86
|
-
const result = await
|
|
86
|
+
const result = await cloudRequestSignedUrl(
|
|
87
87
|
{ operation: "upload" },
|
|
88
88
|
VAK_TOKEN,
|
|
89
89
|
PLATFORM_URL,
|
|
@@ -117,7 +117,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
117
117
|
});
|
|
118
118
|
globalThis.fetch = fetchMock;
|
|
119
119
|
|
|
120
|
-
const result = await
|
|
120
|
+
const result = await cloudRequestSignedUrl(
|
|
121
121
|
{
|
|
122
122
|
operation: "upload",
|
|
123
123
|
contentType: "application/octet-stream",
|
|
@@ -148,7 +148,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
148
148
|
});
|
|
149
149
|
globalThis.fetch = fetchMock;
|
|
150
150
|
|
|
151
|
-
const result = await
|
|
151
|
+
const result = await cloudRequestSignedUrl(
|
|
152
152
|
{ operation: "download", bundleKey: "bundles/xyz.tar.gz" },
|
|
153
153
|
VAK_TOKEN,
|
|
154
154
|
PLATFORM_URL,
|
|
@@ -182,7 +182,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
182
182
|
});
|
|
183
183
|
globalThis.fetch = fetchMock;
|
|
184
184
|
|
|
185
|
-
const result = await
|
|
185
|
+
const result = await cloudRequestSignedUrl(
|
|
186
186
|
{ operation: "upload" },
|
|
187
187
|
VAK_TOKEN,
|
|
188
188
|
PLATFORM_URL,
|
|
@@ -263,7 +263,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
263
263
|
);
|
|
264
264
|
globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch;
|
|
265
265
|
|
|
266
|
-
const result = await
|
|
266
|
+
const result = await cloudRequestSignedUrl(
|
|
267
267
|
{ operation: "upload" },
|
|
268
268
|
SESSION_TOKEN,
|
|
269
269
|
PLATFORM_URL,
|
|
@@ -305,7 +305,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
305
305
|
});
|
|
306
306
|
globalThis.fetch = fetchMock;
|
|
307
307
|
|
|
308
|
-
await
|
|
308
|
+
await cloudRequestSignedUrl(
|
|
309
309
|
{
|
|
310
310
|
operation: "upload",
|
|
311
311
|
minRuntimeVersion: "1.2.3",
|
|
@@ -335,7 +335,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
335
335
|
});
|
|
336
336
|
globalThis.fetch = fetchMock;
|
|
337
337
|
|
|
338
|
-
await
|
|
338
|
+
await cloudRequestSignedUrl(
|
|
339
339
|
{
|
|
340
340
|
operation: "download",
|
|
341
341
|
bundleKey: "bundles/dl-v.tar.gz",
|
|
@@ -370,7 +370,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
370
370
|
|
|
371
371
|
let caught: unknown;
|
|
372
372
|
try {
|
|
373
|
-
await
|
|
373
|
+
await cloudRequestSignedUrl(
|
|
374
374
|
{
|
|
375
375
|
operation: "download",
|
|
376
376
|
bundleKey: "bundles/foo.tar.gz",
|
|
@@ -414,7 +414,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
414
414
|
|
|
415
415
|
let caught: unknown;
|
|
416
416
|
try {
|
|
417
|
-
await
|
|
417
|
+
await cloudRequestSignedUrl(
|
|
418
418
|
{
|
|
419
419
|
operation: "download",
|
|
420
420
|
bundleKey: "bundles/foo.tar.gz",
|
|
@@ -444,7 +444,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
444
444
|
|
|
445
445
|
let caught: unknown;
|
|
446
446
|
try {
|
|
447
|
-
await
|
|
447
|
+
await cloudRequestSignedUrl(
|
|
448
448
|
{ operation: "download", bundleKey: "bundles/foo.tar.gz" },
|
|
449
449
|
VAK_TOKEN,
|
|
450
450
|
PLATFORM_URL,
|
|
@@ -483,7 +483,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
483
483
|
|
|
484
484
|
let caught: unknown;
|
|
485
485
|
try {
|
|
486
|
-
await
|
|
486
|
+
await cloudRequestSignedUrl(
|
|
487
487
|
{
|
|
488
488
|
operation: "download",
|
|
489
489
|
bundleKey: "bundles/foo.tar.gz",
|
|
@@ -513,7 +513,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
513
513
|
});
|
|
514
514
|
globalThis.fetch = fetchMock;
|
|
515
515
|
|
|
516
|
-
const result = await
|
|
516
|
+
const result = await cloudRequestSignedUrl(
|
|
517
517
|
{ operation: "download", bundleKey: "bundles/xyz.tar.gz" },
|
|
518
518
|
VAK_TOKEN,
|
|
519
519
|
PLATFORM_URL,
|
|
@@ -535,7 +535,7 @@ describe("platformRequestSignedUrl", () => {
|
|
|
535
535
|
globalThis.fetch = fetchMock;
|
|
536
536
|
|
|
537
537
|
await expect(
|
|
538
|
-
|
|
538
|
+
cloudRequestSignedUrl(
|
|
539
539
|
{ operation: "upload" },
|
|
540
540
|
VAK_TOKEN,
|
|
541
541
|
PLATFORM_URL,
|