@vellumai/cli 0.6.3 ā 0.6.5
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/AGENTS.md +12 -2
- package/README.md +3 -3
- package/bun.lock +17 -17
- package/bunfig.toml +6 -0
- package/package.json +18 -18
- package/src/__tests__/assistant-config.test.ts +124 -0
- package/src/__tests__/env-drift.test.ts +87 -0
- package/src/__tests__/guardian-token.test.ts +225 -0
- package/src/__tests__/llm-provider-env-var-parity.test.ts +64 -0
- package/src/__tests__/multi-local.test.ts +90 -13
- package/src/__tests__/orphan-detection.test.ts +214 -0
- package/src/__tests__/platform-client.test.ts +204 -0
- package/src/__tests__/preload.ts +27 -0
- package/src/__tests__/ssh-user-guard.test.ts +28 -0
- package/src/__tests__/teleport.test.ts +1073 -56
- package/src/commands/backup.ts +8 -0
- package/src/commands/exec.ts +186 -0
- package/src/commands/hatch.ts +1 -1
- package/src/commands/login.ts +209 -9
- package/src/commands/logs.ts +652 -0
- package/src/commands/pair.ts +9 -1
- package/src/commands/ps.ts +37 -7
- package/src/commands/recover.ts +8 -4
- package/src/commands/restore.ts +8 -0
- package/src/commands/retire.ts +16 -9
- package/src/commands/rollback.ts +32 -33
- package/src/commands/ssh.ts +7 -0
- package/src/commands/teleport.ts +253 -1
- package/src/commands/upgrade.ts +43 -52
- package/src/commands/wake.ts +25 -10
- package/src/components/DefaultMainScreen.tsx +7 -1
- package/src/index.ts +6 -0
- package/src/lib/__tests__/docker.test.ts +168 -0
- package/src/lib/assistant-config.ts +82 -108
- package/src/lib/aws.ts +12 -1
- package/src/lib/config-utils.ts +4 -4
- package/src/lib/constants.ts +0 -10
- package/src/lib/docker.ts +158 -8
- package/src/lib/environments/__tests__/paths.test.ts +228 -0
- package/src/lib/environments/__tests__/resolve.test.ts +226 -0
- package/src/lib/environments/__tests__/seeds.test.ts +72 -0
- package/src/lib/environments/paths.ts +109 -0
- package/src/lib/environments/resolve.ts +96 -0
- package/src/lib/environments/seeds.ts +74 -0
- package/src/lib/environments/types.ts +60 -0
- package/src/lib/exec-apple-container.ts +122 -0
- package/src/lib/gcp.ts +12 -1
- package/src/lib/guardian-token.ts +71 -10
- package/src/lib/hatch-local.ts +44 -23
- package/src/lib/local.ts +47 -5
- package/src/lib/orphan-detection.ts +28 -12
- package/src/lib/platform-client.ts +354 -24
- package/src/lib/retire-apple-container.ts +102 -0
- package/src/lib/ssh-apple-container.ts +166 -0
- package/src/lib/upgrade-lifecycle.ts +101 -28
- package/src/shared/provider-env-vars.ts +30 -6
package/src/commands/ps.ts
CHANGED
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
findAssistantByName,
|
|
5
5
|
getActiveAssistant,
|
|
6
6
|
loadAllAssistants,
|
|
7
|
-
updateServiceGroupVersion,
|
|
8
7
|
type AssistantEntry,
|
|
9
8
|
} from "../lib/assistant-config";
|
|
10
9
|
import { loadGuardianToken } from "../lib/guardian-token";
|
|
11
10
|
import { checkHealth, checkManagedHealth } from "../lib/health-check";
|
|
12
11
|
import { dockerResourceNames } from "../lib/docker";
|
|
12
|
+
import { existsSync } from "fs";
|
|
13
13
|
import {
|
|
14
14
|
classifyProcess,
|
|
15
15
|
detectOrphanedProcesses,
|
|
@@ -335,6 +335,31 @@ async function showAssistantProcesses(entry: AssistantEntry): Promise<void> {
|
|
|
335
335
|
return;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
if (cloud === "apple-container") {
|
|
339
|
+
const mgmtSocket = entry.mgmtSocket as string | undefined;
|
|
340
|
+
const socketAlive = mgmtSocket ? existsSync(mgmtSocket) : false;
|
|
341
|
+
const rows: TableRow[] = [
|
|
342
|
+
{
|
|
343
|
+
name: "container",
|
|
344
|
+
status: withStatusEmoji(socketAlive ? "running" : "not running"),
|
|
345
|
+
info: socketAlive
|
|
346
|
+
? `mgmt ${mgmtSocket}`
|
|
347
|
+
: "management socket not found",
|
|
348
|
+
},
|
|
349
|
+
];
|
|
350
|
+
if (entry.runtimeUrl) {
|
|
351
|
+
const token = loadGuardianToken(entry.assistantId)?.accessToken;
|
|
352
|
+
const health = await checkHealth(entry.runtimeUrl, token);
|
|
353
|
+
rows.push({
|
|
354
|
+
name: "gateway",
|
|
355
|
+
status: withStatusEmoji(health.status),
|
|
356
|
+
info: entry.runtimeUrl + (health.detail ? ` | ${health.detail}` : ""),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
printTable(rows);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
338
363
|
let output: string;
|
|
339
364
|
try {
|
|
340
365
|
if (cloud === "gcp") {
|
|
@@ -395,7 +420,8 @@ async function listAllAssistants(): Promise<void> {
|
|
|
395
420
|
}
|
|
396
421
|
|
|
397
422
|
const rows: TableRow[] = assistants.map((a) => {
|
|
398
|
-
const infoParts = [
|
|
423
|
+
const infoParts: string[] = [];
|
|
424
|
+
if (a.runtimeUrl) infoParts.push(a.runtimeUrl);
|
|
399
425
|
if (a.cloud) infoParts.push(`cloud: ${a.cloud}`);
|
|
400
426
|
if (a.species) infoParts.push(`species: ${a.species}`);
|
|
401
427
|
const prefix = a.assistantId === activeId ? "* " : " ";
|
|
@@ -445,6 +471,13 @@ async function listAllAssistants(): Promise<void> {
|
|
|
445
471
|
const token = loadGuardianToken(a.assistantId)?.accessToken;
|
|
446
472
|
health = await checkHealth(a.localUrl ?? a.runtimeUrl, token);
|
|
447
473
|
}
|
|
474
|
+
} else if (a.cloud === "apple-container") {
|
|
475
|
+
// Apple containers are managed by the macOS app. Probe the gateway
|
|
476
|
+
// (runtimeUrl is always written to the lockfile during hatch).
|
|
477
|
+
const token = loadGuardianToken(a.assistantId)?.accessToken;
|
|
478
|
+
health = a.runtimeUrl
|
|
479
|
+
? await checkHealth(a.runtimeUrl, token)
|
|
480
|
+
: { status: "unknown" as const, detail: "no runtime URL" };
|
|
448
481
|
} else if (a.cloud === "vellum") {
|
|
449
482
|
health = await checkManagedHealth(a.runtimeUrl, a.assistantId);
|
|
450
483
|
} else {
|
|
@@ -452,11 +485,8 @@ async function listAllAssistants(): Promise<void> {
|
|
|
452
485
|
health = await checkHealth(a.localUrl ?? a.runtimeUrl, token);
|
|
453
486
|
}
|
|
454
487
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
const infoParts = [a.runtimeUrl];
|
|
488
|
+
const infoParts: string[] = [];
|
|
489
|
+
if (a.runtimeUrl) infoParts.push(a.runtimeUrl);
|
|
460
490
|
if (a.cloud) infoParts.push(`cloud: ${a.cloud}`);
|
|
461
491
|
if (a.species) infoParts.push(`species: ${a.species}`);
|
|
462
492
|
if (health.detail) infoParts.push(health.detail);
|
package/src/commands/recover.ts
CHANGED
|
@@ -51,16 +51,20 @@ export async function recover(): Promise<void> {
|
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
// 3. Check
|
|
55
|
-
const
|
|
56
|
-
if (existsSync(
|
|
54
|
+
// 3. Check that the recovering entry's own target directory is free.
|
|
55
|
+
const target = join(entry.resources.instanceDir, ".vellum");
|
|
56
|
+
if (existsSync(target)) {
|
|
57
57
|
console.error(
|
|
58
|
-
|
|
58
|
+
`Error: ${target} already exists (owned by ${entry.assistantId}). ` +
|
|
59
|
+
`Retire the current assistant first.`,
|
|
59
60
|
);
|
|
60
61
|
process.exit(1);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// 4. Extract archive
|
|
65
|
+
// TODO: extraction target is hardcoded to homedir(); multi-instance entries
|
|
66
|
+
// whose instanceDir differs from homedir will extract to the wrong
|
|
67
|
+
// location. Tracked separately from the collision-check regression.
|
|
64
68
|
await exec("tar", ["xzf", archivePath, "-C", homedir()]);
|
|
65
69
|
|
|
66
70
|
// 5. Restore lockfile entry
|
package/src/commands/restore.ts
CHANGED
|
@@ -563,6 +563,14 @@ export async function restore(): Promise<void> {
|
|
|
563
563
|
// Detect topology and route platform assistants through Django import
|
|
564
564
|
const cloud =
|
|
565
565
|
entry.cloud || (entry.project ? "gcp" : entry.sshUser ? "custom" : "local");
|
|
566
|
+
|
|
567
|
+
if (cloud === "apple-container") {
|
|
568
|
+
console.error(
|
|
569
|
+
`Error: '${name}' uses the Apple Containers runtime. Restore is not yet supported for this topology.`,
|
|
570
|
+
);
|
|
571
|
+
process.exit(1);
|
|
572
|
+
}
|
|
573
|
+
|
|
566
574
|
if (cloud === "vellum") {
|
|
567
575
|
await restorePlatform(entry, name, bundleData, { version, dryRun });
|
|
568
576
|
return;
|
package/src/commands/retire.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { retireInstance as retireAwsInstance } from "../lib/aws";
|
|
|
12
12
|
import { retireDocker } from "../lib/docker";
|
|
13
13
|
import { retireInstance as retireGcpInstance } from "../lib/gcp";
|
|
14
14
|
import { retireLocal } from "../lib/retire-local";
|
|
15
|
+
import { retireAppleContainer } from "../lib/retire-apple-container";
|
|
15
16
|
import { exec } from "../lib/step-runner";
|
|
16
17
|
import {
|
|
17
18
|
openLogFile,
|
|
@@ -100,7 +101,12 @@ async function retireVellum(
|
|
|
100
101
|
headers: await authHeaders(token, runtimeUrl),
|
|
101
102
|
});
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
// Treat 404 as success: the assistant is already gone from the platform
|
|
105
|
+
// (previously retired, deleted from the web UI, or retired from another
|
|
106
|
+
// device) so the caller's job is done. Falling through to the lockfile
|
|
107
|
+
// cleanup avoids leaving a stale entry that would otherwise wedge the
|
|
108
|
+
// macOS app in a permanent health-check loop.
|
|
109
|
+
if (!response.ok && response.status !== 404) {
|
|
104
110
|
const body = await response.text();
|
|
105
111
|
console.error(
|
|
106
112
|
`Error: Platform retire failed (${response.status}): ${body}`,
|
|
@@ -108,7 +114,13 @@ async function retireVellum(
|
|
|
108
114
|
process.exit(1);
|
|
109
115
|
}
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
if (response.status === 404) {
|
|
118
|
+
console.log(
|
|
119
|
+
"\u2705 Platform-hosted instance already retired (404) ā cleaning up local state.",
|
|
120
|
+
);
|
|
121
|
+
} else {
|
|
122
|
+
console.log("\u2705 Platform-hosted instance retired.");
|
|
123
|
+
}
|
|
112
124
|
}
|
|
113
125
|
|
|
114
126
|
function parseSource(): string | undefined {
|
|
@@ -201,13 +213,8 @@ async function retireInner(): Promise<void> {
|
|
|
201
213
|
const cloud = resolveCloud(entry);
|
|
202
214
|
|
|
203
215
|
if (cloud === "apple-container") {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
);
|
|
207
|
-
process.exit(1);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (cloud === "gcp") {
|
|
216
|
+
await retireAppleContainer(name, entry);
|
|
217
|
+
} else if (cloud === "gcp") {
|
|
211
218
|
const project = entry.project;
|
|
212
219
|
const zone = entry.zone;
|
|
213
220
|
if (!project || !zone) {
|
package/src/commands/rollback.ts
CHANGED
|
@@ -29,12 +29,13 @@ import {
|
|
|
29
29
|
captureContainerEnv,
|
|
30
30
|
commitWorkspaceViaGateway,
|
|
31
31
|
CONTAINER_ENV_EXCLUDE_KEYS,
|
|
32
|
+
fetchCurrentVersion,
|
|
33
|
+
fetchPreviousVersion,
|
|
32
34
|
performDockerRollback,
|
|
33
35
|
rollbackMigrations,
|
|
34
36
|
UPGRADE_PROGRESS,
|
|
35
37
|
waitForReady,
|
|
36
38
|
} from "../lib/upgrade-lifecycle.js";
|
|
37
|
-
import { compareVersions } from "../lib/version-compat.js";
|
|
38
39
|
|
|
39
40
|
function parseArgs(): { name: string | null; version: string | null } {
|
|
40
41
|
const args = process.argv.slice(3);
|
|
@@ -148,20 +149,7 @@ async function rollbackPlatformViaEndpoint(
|
|
|
148
149
|
entry: AssistantEntry,
|
|
149
150
|
version?: string,
|
|
150
151
|
): Promise<void> {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// Step 1 ā Version validation (only if version provided)
|
|
154
|
-
if (version && currentVersion) {
|
|
155
|
-
const cmp = compareVersions(version, currentVersion);
|
|
156
|
-
if (cmp !== null && cmp >= 0) {
|
|
157
|
-
const msg = `Target version ${version} is not older than the current version ${currentVersion}. Use \`vellum upgrade --version ${version}\` to upgrade.`;
|
|
158
|
-
console.error(msg);
|
|
159
|
-
emitCliError("VERSION_DIRECTION", msg);
|
|
160
|
-
process.exit(1);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Step 2 ā Authenticate
|
|
152
|
+
// Step 1 ā Authenticate
|
|
165
153
|
const token = readPlatformToken();
|
|
166
154
|
if (!token) {
|
|
167
155
|
const msg =
|
|
@@ -171,6 +159,9 @@ async function rollbackPlatformViaEndpoint(
|
|
|
171
159
|
process.exit(1);
|
|
172
160
|
}
|
|
173
161
|
|
|
162
|
+
// Fetch current version from health endpoint (best-effort)
|
|
163
|
+
const currentVersion = await fetchCurrentVersion(entry.runtimeUrl);
|
|
164
|
+
|
|
174
165
|
// Step 3 ā Call rollback endpoint
|
|
175
166
|
if (version) {
|
|
176
167
|
console.log(`Rolling back to ${version}...`);
|
|
@@ -215,7 +206,7 @@ async function rollbackPlatformViaEndpoint(
|
|
|
215
206
|
await broadcastUpgradeEvent(
|
|
216
207
|
entry.runtimeUrl,
|
|
217
208
|
entry.assistantId,
|
|
218
|
-
buildCompleteEvent(currentVersion ?? "unknown", false),
|
|
209
|
+
buildCompleteEvent(currentVersion ?? version ?? "unknown", false),
|
|
219
210
|
);
|
|
220
211
|
process.exit(1);
|
|
221
212
|
}
|
|
@@ -234,6 +225,13 @@ export async function rollback(): Promise<void> {
|
|
|
234
225
|
const entry = resolveTargetAssistant(name);
|
|
235
226
|
const cloud = resolveCloud(entry);
|
|
236
227
|
|
|
228
|
+
if (cloud === "apple-container") {
|
|
229
|
+
console.error(
|
|
230
|
+
`Error: '${entry.assistantId}' uses the Apple Containers runtime. Rollback is not yet supported for this topology.`,
|
|
231
|
+
);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
|
|
237
235
|
// ---------- Managed (Vellum platform) rollback ----------
|
|
238
236
|
if (cloud === "vellum") {
|
|
239
237
|
await rollbackPlatformViaEndpoint(entry, version ?? undefined);
|
|
@@ -258,7 +256,7 @@ export async function rollback(): Promise<void> {
|
|
|
258
256
|
await broadcastUpgradeEvent(
|
|
259
257
|
entry.runtimeUrl,
|
|
260
258
|
entry.assistantId,
|
|
261
|
-
buildCompleteEvent(
|
|
259
|
+
buildCompleteEvent(version ?? "unknown", false),
|
|
262
260
|
);
|
|
263
261
|
emitCliError(categorizeUpgradeError(err), "Rollback failed", detail);
|
|
264
262
|
process.exit(1);
|
|
@@ -268,8 +266,14 @@ export async function rollback(): Promise<void> {
|
|
|
268
266
|
|
|
269
267
|
// ---------- Docker: Saved-state rollback (no --version) ----------
|
|
270
268
|
|
|
269
|
+
// Fetch current + previous version from live APIs
|
|
270
|
+
const currentVersion = await fetchCurrentVersion(entry.runtimeUrl);
|
|
271
|
+
const previousVersion =
|
|
272
|
+
(await fetchPreviousVersion(currentVersion, entry.previousVersion)) ??
|
|
273
|
+
"unknown";
|
|
274
|
+
|
|
271
275
|
// Verify rollback state exists
|
|
272
|
-
if (!entry.
|
|
276
|
+
if (!entry.previousContainerInfo) {
|
|
273
277
|
const msg =
|
|
274
278
|
"No rollback state available. Run `vellum upgrade` first to create a rollback point.";
|
|
275
279
|
console.error(msg);
|
|
@@ -305,15 +309,15 @@ export async function rollback(): Promise<void> {
|
|
|
305
309
|
buildUpgradeCommitMessage({
|
|
306
310
|
action: "rollback",
|
|
307
311
|
phase: "starting",
|
|
308
|
-
from:
|
|
309
|
-
to:
|
|
312
|
+
from: currentVersion ?? "unknown",
|
|
313
|
+
to: previousVersion,
|
|
310
314
|
topology: "docker",
|
|
311
315
|
assistantId: entry.assistantId,
|
|
312
316
|
}),
|
|
313
317
|
);
|
|
314
318
|
|
|
315
319
|
console.log(
|
|
316
|
-
`š Rolling back Docker assistant '${instanceName}' to ${
|
|
320
|
+
`š Rolling back Docker assistant '${instanceName}' to ${previousVersion}...\n`,
|
|
317
321
|
);
|
|
318
322
|
|
|
319
323
|
// Capture current container env
|
|
@@ -367,7 +371,7 @@ export async function rollback(): Promise<void> {
|
|
|
367
371
|
await broadcastUpgradeEvent(
|
|
368
372
|
entry.runtimeUrl,
|
|
369
373
|
entry.assistantId,
|
|
370
|
-
buildStartingEvent(
|
|
374
|
+
buildStartingEvent(previousVersion),
|
|
371
375
|
);
|
|
372
376
|
// Brief pause to allow SSE delivery before containers stop.
|
|
373
377
|
await new Promise((r) => setTimeout(r, 500));
|
|
@@ -428,7 +432,6 @@ export async function rollback(): Promise<void> {
|
|
|
428
432
|
// Swap current/previous state to enable "rollback the rollback"
|
|
429
433
|
const updatedEntry: AssistantEntry = {
|
|
430
434
|
...entry,
|
|
431
|
-
serviceGroupVersion: entry.previousServiceGroupVersion,
|
|
432
435
|
containerInfo: {
|
|
433
436
|
assistantImage: prev.assistantImage ?? previousImageRefs.assistant,
|
|
434
437
|
gatewayImage: prev.gatewayImage ?? previousImageRefs.gateway,
|
|
@@ -438,7 +441,6 @@ export async function rollback(): Promise<void> {
|
|
|
438
441
|
cesDigest: newDigests?.["credential-executor"],
|
|
439
442
|
networkName: res.network,
|
|
440
443
|
},
|
|
441
|
-
previousServiceGroupVersion: entry.serviceGroupVersion,
|
|
442
444
|
previousContainerInfo: entry.containerInfo,
|
|
443
445
|
// Clear the backup path ā it belonged to the upgrade we just rolled back
|
|
444
446
|
preUpgradeBackupPath: undefined,
|
|
@@ -451,7 +453,7 @@ export async function rollback(): Promise<void> {
|
|
|
451
453
|
await broadcastUpgradeEvent(
|
|
452
454
|
entry.runtimeUrl,
|
|
453
455
|
entry.assistantId,
|
|
454
|
-
buildCompleteEvent(
|
|
456
|
+
buildCompleteEvent(previousVersion, true),
|
|
455
457
|
);
|
|
456
458
|
|
|
457
459
|
// Record successful rollback in workspace git history
|
|
@@ -461,8 +463,8 @@ export async function rollback(): Promise<void> {
|
|
|
461
463
|
buildUpgradeCommitMessage({
|
|
462
464
|
action: "rollback",
|
|
463
465
|
phase: "complete",
|
|
464
|
-
from:
|
|
465
|
-
to:
|
|
466
|
+
from: currentVersion ?? "unknown",
|
|
467
|
+
to: previousVersion,
|
|
466
468
|
topology: "docker",
|
|
467
469
|
assistantId: entry.assistantId,
|
|
468
470
|
result: "success",
|
|
@@ -470,7 +472,7 @@ export async function rollback(): Promise<void> {
|
|
|
470
472
|
);
|
|
471
473
|
|
|
472
474
|
console.log(
|
|
473
|
-
`\nā
Docker assistant '${instanceName}' rolled back to ${
|
|
475
|
+
`\nā
Docker assistant '${instanceName}' rolled back to ${previousVersion}.`,
|
|
474
476
|
);
|
|
475
477
|
console.log(
|
|
476
478
|
"\nTip: To also restore data from before the upgrade, use `vellum restore --from <backup-path>`.",
|
|
@@ -485,10 +487,7 @@ export async function rollback(): Promise<void> {
|
|
|
485
487
|
await broadcastUpgradeEvent(
|
|
486
488
|
entry.runtimeUrl,
|
|
487
489
|
entry.assistantId,
|
|
488
|
-
buildCompleteEvent(
|
|
489
|
-
entry.previousServiceGroupVersion ?? "unknown",
|
|
490
|
-
false,
|
|
491
|
-
),
|
|
490
|
+
buildCompleteEvent(previousVersion, false),
|
|
492
491
|
);
|
|
493
492
|
emitCliError(
|
|
494
493
|
"READINESS_TIMEOUT",
|
|
@@ -502,7 +501,7 @@ export async function rollback(): Promise<void> {
|
|
|
502
501
|
await broadcastUpgradeEvent(
|
|
503
502
|
entry.runtimeUrl,
|
|
504
503
|
entry.assistantId,
|
|
505
|
-
buildCompleteEvent(
|
|
504
|
+
buildCompleteEvent(previousVersion, false),
|
|
506
505
|
);
|
|
507
506
|
emitCliError(categorizeUpgradeError(err), "Rollback failed", detail);
|
|
508
507
|
process.exit(1);
|
package/src/commands/ssh.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "../lib/assistant-config";
|
|
7
7
|
import type { AssistantEntry } from "../lib/assistant-config";
|
|
8
8
|
import { dockerResourceNames } from "../lib/docker";
|
|
9
|
+
import { sshAppleContainer } from "../lib/ssh-apple-container";
|
|
9
10
|
|
|
10
11
|
const SSH_OPTS = [
|
|
11
12
|
"-o",
|
|
@@ -81,6 +82,12 @@ export async function ssh(): Promise<void> {
|
|
|
81
82
|
process.exit(1);
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
// Apple container: connect to the management socket for an interactive shell.
|
|
86
|
+
if (cloud === "apple-container") {
|
|
87
|
+
await sshAppleContainer(entry);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
84
91
|
let child;
|
|
85
92
|
|
|
86
93
|
if (cloud === "docker") {
|