aicomputer 0.1.17 → 0.1.18
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 +8 -3
- package/dist/{chunk-5IEWKH52.js → chunk-3ZUTAUUD.js} +70 -280
- package/dist/chunk-F2U4SFJ4.js +517 -0
- package/dist/{chunk-OWK5N76S.js → chunk-JMRAYXUO.js} +3 -11
- package/dist/index.js +324 -114
- package/dist/lib/mount-config.d.ts +4 -1
- package/dist/lib/mount-host.d.ts +1 -2
- package/dist/lib/mount-host.js +1 -1
- package/dist/lib/mount-mutagen.d.ts +37 -0
- package/dist/lib/mount-mutagen.js +23 -0
- package/dist/lib/mount-reconcile.d.ts +4 -18
- package/dist/lib/mount-reconcile.js +2 -1
- package/package.json +5 -3
- package/scripts/postinstall.mjs +35 -0
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
formatMountHostInstallGuidance,
|
|
4
4
|
getMountHostValidationIssues
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-JMRAYXUO.js";
|
|
6
6
|
import {
|
|
7
7
|
ApiError,
|
|
8
8
|
api,
|
|
@@ -33,7 +33,13 @@ import {
|
|
|
33
33
|
timeAgo,
|
|
34
34
|
vncURL,
|
|
35
35
|
webURL
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-3ZUTAUUD.js";
|
|
37
|
+
import {
|
|
38
|
+
AGENTCOMPUTER_MUTAGEN_PATH_ENV,
|
|
39
|
+
ensureBundledMutagenInstalled,
|
|
40
|
+
ensureMutagenCommandPath,
|
|
41
|
+
isAbortError
|
|
42
|
+
} from "./chunk-F2U4SFJ4.js";
|
|
37
43
|
import {
|
|
38
44
|
defaultMountServiceConfig,
|
|
39
45
|
ensureMountDirectories,
|
|
@@ -48,8 +54,8 @@ import {
|
|
|
48
54
|
} from "./chunk-KXLTHWW3.js";
|
|
49
55
|
|
|
50
56
|
// src/index.ts
|
|
51
|
-
import { Command as
|
|
52
|
-
import
|
|
57
|
+
import { Command as Command15 } from "commander";
|
|
58
|
+
import chalk13 from "chalk";
|
|
53
59
|
import { readFileSync as readFileSync3 } from "fs";
|
|
54
60
|
import { basename as basename2 } from "path";
|
|
55
61
|
|
|
@@ -3561,9 +3567,35 @@ async function confirmDeletion(sourceID) {
|
|
|
3561
3567
|
});
|
|
3562
3568
|
}
|
|
3563
3569
|
|
|
3564
|
-
// src/commands/
|
|
3570
|
+
// src/commands/internal-install-mutagen.ts
|
|
3565
3571
|
import { Command as Command9 } from "commander";
|
|
3566
3572
|
import chalk7 from "chalk";
|
|
3573
|
+
var internalInstallMutagenCommand = new Command9("internal-install-mutagen").option("--quiet", "Suppress output unless installation fails").action(async (options) => {
|
|
3574
|
+
try {
|
|
3575
|
+
const executablePath = await ensureBundledMutagenInstalled();
|
|
3576
|
+
if (!options.quiet) {
|
|
3577
|
+
console.log();
|
|
3578
|
+
console.log(
|
|
3579
|
+
chalk7.green(
|
|
3580
|
+
` Bundled Mutagen ready at ${executablePath}.`
|
|
3581
|
+
)
|
|
3582
|
+
);
|
|
3583
|
+
console.log();
|
|
3584
|
+
}
|
|
3585
|
+
} catch (error) {
|
|
3586
|
+
if (!options.quiet) {
|
|
3587
|
+
const message = error instanceof Error ? error.message : "failed to install bundled Mutagen";
|
|
3588
|
+
console.error();
|
|
3589
|
+
console.error(chalk7.red(` ${message}`));
|
|
3590
|
+
console.error();
|
|
3591
|
+
}
|
|
3592
|
+
process.exit(1);
|
|
3593
|
+
}
|
|
3594
|
+
});
|
|
3595
|
+
|
|
3596
|
+
// src/commands/login.ts
|
|
3597
|
+
import { Command as Command10 } from "commander";
|
|
3598
|
+
import chalk8 from "chalk";
|
|
3567
3599
|
import ora8 from "ora";
|
|
3568
3600
|
|
|
3569
3601
|
// src/lib/browser-login.ts
|
|
@@ -3831,12 +3863,12 @@ function escapeHTML(value) {
|
|
|
3831
3863
|
}
|
|
3832
3864
|
|
|
3833
3865
|
// src/commands/login.ts
|
|
3834
|
-
var loginCommand = new
|
|
3866
|
+
var loginCommand = new Command10("login").description("Authenticate the CLI").option("--api-key <key>", "API key starting with ac_live_").option("--stdin", "Read the API key from stdin").option("-f, --force", "Overwrite an existing stored API key").action(async (options) => {
|
|
3835
3867
|
const existingKey = getStoredAPIKey();
|
|
3836
3868
|
if (existingKey && !options.force) {
|
|
3837
3869
|
console.log();
|
|
3838
3870
|
console.log(
|
|
3839
|
-
|
|
3871
|
+
chalk8.yellow(" Already logged in. Use --force to overwrite.")
|
|
3840
3872
|
);
|
|
3841
3873
|
console.log();
|
|
3842
3874
|
return;
|
|
@@ -3845,8 +3877,8 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3845
3877
|
const apiKey = await resolveAPIKeyInput(options.apiKey, options.stdin);
|
|
3846
3878
|
if (!apiKey && wantsManualLogin) {
|
|
3847
3879
|
console.log();
|
|
3848
|
-
console.log(
|
|
3849
|
-
console.log(
|
|
3880
|
+
console.log(chalk8.dim(" Usage: computer login --api-key <ac_live_...>"));
|
|
3881
|
+
console.log(chalk8.dim(` API: ${getBaseURL()}`));
|
|
3850
3882
|
console.log();
|
|
3851
3883
|
process.exit(1);
|
|
3852
3884
|
}
|
|
@@ -3856,7 +3888,7 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3856
3888
|
}
|
|
3857
3889
|
if (!apiKey.startsWith("ac_live_")) {
|
|
3858
3890
|
console.log();
|
|
3859
|
-
console.log(
|
|
3891
|
+
console.log(chalk8.red(" API key must start with ac_live_"));
|
|
3860
3892
|
console.log();
|
|
3861
3893
|
process.exit(1);
|
|
3862
3894
|
}
|
|
@@ -3864,7 +3896,7 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3864
3896
|
try {
|
|
3865
3897
|
const me = await apiWithKey(apiKey, "/v1/me");
|
|
3866
3898
|
setAPIKey(apiKey);
|
|
3867
|
-
spinner.succeed(`Logged in as ${
|
|
3899
|
+
spinner.succeed(`Logged in as ${chalk8.bold(me.user.email)}`);
|
|
3868
3900
|
} catch (error) {
|
|
3869
3901
|
spinner.fail(
|
|
3870
3902
|
error instanceof Error ? error.message : "Failed to validate API key"
|
|
@@ -3884,15 +3916,15 @@ async function runBrowserLogin() {
|
|
|
3884
3916
|
spinner.stop();
|
|
3885
3917
|
console.log();
|
|
3886
3918
|
console.log(
|
|
3887
|
-
|
|
3919
|
+
chalk8.yellow(" Browser auto-open failed. Open this URL to continue:")
|
|
3888
3920
|
);
|
|
3889
|
-
console.log(
|
|
3921
|
+
console.log(chalk8.dim(` ${attempt.loginURL}`));
|
|
3890
3922
|
console.log();
|
|
3891
3923
|
spinner.start("Waiting for browser login...");
|
|
3892
3924
|
}
|
|
3893
3925
|
spinner.text = "Waiting for browser login...";
|
|
3894
3926
|
const result = await attempt.waitForResult();
|
|
3895
|
-
spinner.succeed(`Logged in as ${
|
|
3927
|
+
spinner.succeed(`Logged in as ${chalk8.bold(result.me.user.email)}`);
|
|
3896
3928
|
await continueFirstLoginFlow(result);
|
|
3897
3929
|
} catch (error) {
|
|
3898
3930
|
spinner.fail(
|
|
@@ -3926,8 +3958,8 @@ async function continueFirstLoginFlow(result) {
|
|
|
3926
3958
|
}
|
|
3927
3959
|
console.log();
|
|
3928
3960
|
console.log(
|
|
3929
|
-
|
|
3930
|
-
`Continuing first-time setup for ${
|
|
3961
|
+
chalk8.cyan(
|
|
3962
|
+
`Continuing first-time setup for ${chalk8.bold(machineHandle)}...
|
|
3931
3963
|
`
|
|
3932
3964
|
)
|
|
3933
3965
|
);
|
|
@@ -3940,8 +3972,8 @@ async function continueFirstLoginFlow(result) {
|
|
|
3940
3972
|
const spinner = ora8(`Preparing SSH access for ${machineHandle}...`).start();
|
|
3941
3973
|
try {
|
|
3942
3974
|
const connection = await prepareSSHConnectionByIdentifier(machineHandle);
|
|
3943
|
-
spinner.succeed(`Connecting to ${
|
|
3944
|
-
console.log(
|
|
3975
|
+
spinner.succeed(`Connecting to ${chalk8.bold(machineHandle)}`);
|
|
3976
|
+
console.log(chalk8.dim(` ${connection.command}`));
|
|
3945
3977
|
console.log();
|
|
3946
3978
|
await openSSHConnection(connection);
|
|
3947
3979
|
} catch (error) {
|
|
@@ -3952,19 +3984,19 @@ async function continueFirstLoginFlow(result) {
|
|
|
3952
3984
|
}
|
|
3953
3985
|
} catch (error) {
|
|
3954
3986
|
const message = error instanceof Error ? error.message : "Failed to finish first-time setup";
|
|
3955
|
-
console.error(
|
|
3987
|
+
console.error(chalk8.red(`
|
|
3956
3988
|
${message}`));
|
|
3957
3989
|
console.log();
|
|
3958
3990
|
if (result.provider === "claude") {
|
|
3959
3991
|
console.log(
|
|
3960
|
-
|
|
3992
|
+
chalk8.dim(` computer claude-login --machine ${machineHandle}`)
|
|
3961
3993
|
);
|
|
3962
3994
|
} else if (result.provider === "codex") {
|
|
3963
3995
|
console.log(
|
|
3964
|
-
|
|
3996
|
+
chalk8.dim(` computer codex-login --machine ${machineHandle}`)
|
|
3965
3997
|
);
|
|
3966
3998
|
}
|
|
3967
|
-
console.log(
|
|
3999
|
+
console.log(chalk8.dim(` computer ssh ${machineHandle}`));
|
|
3968
4000
|
console.log();
|
|
3969
4001
|
process.exit(1);
|
|
3970
4002
|
}
|
|
@@ -3978,19 +4010,19 @@ async function runSelectedProvider(provider, machineHandle) {
|
|
|
3978
4010
|
await runCodexLogin({ machine: machineHandle });
|
|
3979
4011
|
return;
|
|
3980
4012
|
}
|
|
3981
|
-
console.log(
|
|
4013
|
+
console.log(chalk8.green(`Sandbox ${chalk8.bold(machineHandle)} is ready.`));
|
|
3982
4014
|
console.log();
|
|
3983
4015
|
}
|
|
3984
4016
|
function printNextStep(machineHandle) {
|
|
3985
|
-
console.log(
|
|
3986
|
-
console.log(
|
|
4017
|
+
console.log(chalk8.green(`Sandbox ${chalk8.bold(machineHandle)} is ready.`));
|
|
4018
|
+
console.log(chalk8.dim(` computer ssh ${machineHandle}`));
|
|
3987
4019
|
console.log();
|
|
3988
4020
|
}
|
|
3989
4021
|
|
|
3990
4022
|
// src/commands/mount.ts
|
|
3991
4023
|
import { spawn as spawn4 } from "child_process";
|
|
3992
|
-
import { Command as
|
|
3993
|
-
import
|
|
4024
|
+
import { Command as Command11, Option } from "commander";
|
|
4025
|
+
import chalk9 from "chalk";
|
|
3994
4026
|
import ora9 from "ora";
|
|
3995
4027
|
|
|
3996
4028
|
// src/lib/mount-daemon.ts
|
|
@@ -4007,7 +4039,7 @@ function getMountControllerState(rootPath = defaultMountServiceConfig().rootPath
|
|
|
4007
4039
|
return { running: true, pid: lock.pid };
|
|
4008
4040
|
}
|
|
4009
4041
|
async function runMountDaemon(config, options = {}) {
|
|
4010
|
-
const { onStarted } = options;
|
|
4042
|
+
const { onReady, onStarted } = options;
|
|
4011
4043
|
const paths = getMountPaths(config.rootPath);
|
|
4012
4044
|
ensureMountDirectories(paths);
|
|
4013
4045
|
await mkdir3(paths.rootPath, { recursive: true });
|
|
@@ -4017,16 +4049,35 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4017
4049
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4018
4050
|
controllerPid: process.pid,
|
|
4019
4051
|
running: true,
|
|
4052
|
+
startupPhase: "starting",
|
|
4053
|
+
startupMessage: "Starting mount controller...",
|
|
4020
4054
|
mounts: []
|
|
4021
4055
|
},
|
|
4022
4056
|
config.rootPath
|
|
4023
4057
|
);
|
|
4024
4058
|
onStarted?.();
|
|
4059
|
+
writeMountStatusSnapshot(
|
|
4060
|
+
{
|
|
4061
|
+
...readMountStatusSnapshot(config.rootPath) ?? {
|
|
4062
|
+
controllerPid: process.pid,
|
|
4063
|
+
running: true,
|
|
4064
|
+
mounts: []
|
|
4065
|
+
},
|
|
4066
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4067
|
+
controllerPid: process.pid,
|
|
4068
|
+
running: true,
|
|
4069
|
+
startupPhase: "cleaning",
|
|
4070
|
+
startupMessage: "Cleaning stale mount state..."
|
|
4071
|
+
},
|
|
4072
|
+
config.rootPath
|
|
4073
|
+
);
|
|
4025
4074
|
await teardownManagedSessions(config, paths);
|
|
4075
|
+
await mkdir3(paths.rootPath, { recursive: true });
|
|
4026
4076
|
let running = false;
|
|
4027
4077
|
let queued = false;
|
|
4028
4078
|
let shuttingDown = false;
|
|
4029
4079
|
let activeRun = null;
|
|
4080
|
+
let activeRunController = null;
|
|
4030
4081
|
const runOnce = async () => {
|
|
4031
4082
|
if (shuttingDown) {
|
|
4032
4083
|
return;
|
|
@@ -4035,12 +4086,19 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4035
4086
|
queued = true;
|
|
4036
4087
|
return activeRun ?? void 0;
|
|
4037
4088
|
}
|
|
4089
|
+
const controller = new AbortController();
|
|
4090
|
+
activeRunController = controller;
|
|
4038
4091
|
activeRun = (async () => {
|
|
4039
4092
|
running = true;
|
|
4040
4093
|
try {
|
|
4041
|
-
await reconcileMounts(
|
|
4094
|
+
await reconcileMounts(
|
|
4095
|
+
config,
|
|
4096
|
+
paths,
|
|
4097
|
+
process.pid,
|
|
4098
|
+
controller.signal
|
|
4099
|
+
);
|
|
4042
4100
|
} catch (error) {
|
|
4043
|
-
if (shuttingDown) {
|
|
4101
|
+
if (shuttingDown && isAbortError(error)) {
|
|
4044
4102
|
return;
|
|
4045
4103
|
}
|
|
4046
4104
|
const previous = readMountStatusSnapshot(config.rootPath);
|
|
@@ -4049,6 +4107,8 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4049
4107
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4050
4108
|
controllerPid: process.pid,
|
|
4051
4109
|
running: true,
|
|
4110
|
+
startupPhase: previous?.startupPhase === "ready" ? "ready" : "syncing",
|
|
4111
|
+
startupMessage: previous?.startupPhase === "ready" ? void 0 : "Waiting for initial sync...",
|
|
4052
4112
|
lastHealthySyncAt: previous?.lastHealthySyncAt,
|
|
4053
4113
|
lastSuccessfulSyncAt: previous?.lastSuccessfulSyncAt,
|
|
4054
4114
|
lastIssueAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4064,6 +4124,7 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4064
4124
|
} finally {
|
|
4065
4125
|
running = false;
|
|
4066
4126
|
activeRun = null;
|
|
4127
|
+
activeRunController = null;
|
|
4067
4128
|
if (queued && !shuttingDown) {
|
|
4068
4129
|
queued = false;
|
|
4069
4130
|
void runOnce();
|
|
@@ -4079,6 +4140,21 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4079
4140
|
server.once("error", reject);
|
|
4080
4141
|
server.listen(paths.socketPath, () => resolve());
|
|
4081
4142
|
});
|
|
4143
|
+
writeMountStatusSnapshot(
|
|
4144
|
+
{
|
|
4145
|
+
...readMountStatusSnapshot(config.rootPath) ?? {
|
|
4146
|
+
controllerPid: process.pid,
|
|
4147
|
+
running: true,
|
|
4148
|
+
mounts: []
|
|
4149
|
+
},
|
|
4150
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4151
|
+
controllerPid: process.pid,
|
|
4152
|
+
running: true,
|
|
4153
|
+
startupPhase: "syncing",
|
|
4154
|
+
startupMessage: "Waiting for initial sync..."
|
|
4155
|
+
},
|
|
4156
|
+
config.rootPath
|
|
4157
|
+
);
|
|
4082
4158
|
const interval = setInterval(() => {
|
|
4083
4159
|
void runOnce();
|
|
4084
4160
|
}, config.pollIntervalMs);
|
|
@@ -4089,6 +4165,7 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4089
4165
|
shuttingDown = true;
|
|
4090
4166
|
clearInterval(interval);
|
|
4091
4167
|
server.close();
|
|
4168
|
+
activeRunController?.abort();
|
|
4092
4169
|
if (activeRun) {
|
|
4093
4170
|
await activeRun.catch(() => {
|
|
4094
4171
|
});
|
|
@@ -4100,6 +4177,8 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4100
4177
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4101
4178
|
controllerPid: previous?.controllerPid,
|
|
4102
4179
|
running: false,
|
|
4180
|
+
startupPhase: void 0,
|
|
4181
|
+
startupMessage: void 0,
|
|
4103
4182
|
lastHealthySyncAt: previous?.lastHealthySyncAt,
|
|
4104
4183
|
lastSuccessfulSyncAt: previous?.lastSuccessfulSyncAt,
|
|
4105
4184
|
lastIssueAt: previous?.lastIssueAt,
|
|
@@ -4119,6 +4198,8 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4119
4198
|
void shutdown();
|
|
4120
4199
|
});
|
|
4121
4200
|
await runOnce();
|
|
4201
|
+
writeMountStatusSnapshot(markMountStartupReady(readMountStatusSnapshot(config.rootPath), process.pid), config.rootPath);
|
|
4202
|
+
onReady?.();
|
|
4122
4203
|
await new Promise(() => {
|
|
4123
4204
|
});
|
|
4124
4205
|
}
|
|
@@ -4147,41 +4228,69 @@ function processExists(pid) {
|
|
|
4147
4228
|
return false;
|
|
4148
4229
|
}
|
|
4149
4230
|
}
|
|
4231
|
+
function markMountStartupReady(snapshot, controllerPid) {
|
|
4232
|
+
return {
|
|
4233
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4234
|
+
controllerPid,
|
|
4235
|
+
running: true,
|
|
4236
|
+
startupPhase: "ready",
|
|
4237
|
+
startupMessage: void 0,
|
|
4238
|
+
lastHealthySyncAt: snapshot?.lastHealthySyncAt,
|
|
4239
|
+
lastSuccessfulSyncAt: snapshot?.lastSuccessfulSyncAt,
|
|
4240
|
+
lastIssueAt: snapshot?.lastIssueAt,
|
|
4241
|
+
lastIssue: snapshot?.lastIssue,
|
|
4242
|
+
lastError: snapshot?.lastError,
|
|
4243
|
+
mounts: snapshot?.mounts ?? []
|
|
4244
|
+
};
|
|
4245
|
+
}
|
|
4150
4246
|
|
|
4151
4247
|
// src/commands/mount.ts
|
|
4152
|
-
var
|
|
4248
|
+
var MOUNT_START_SPINNER = {
|
|
4249
|
+
interval: 90,
|
|
4250
|
+
frames: ["\u25F0", "\u25F3", "\u25F2", "\u25F1"]
|
|
4251
|
+
};
|
|
4252
|
+
var mountCommand = new Command11("mount").description("Mirror SSH-ready machines under ~/agentcomputer with a local mount controller").option("--alias <alias>", "SSH host alias", "agentcomputer.ai").option("--host <host>", "SSH gateway host", "ssh.agentcomputer.ai").option("--port <port>", "SSH gateway port", "443").option("--poll-interval <ms>", "Reconcile interval in milliseconds", "5000").option("--connect-timeout <seconds>", "SSH connect timeout for Mutagen", "5").option(
|
|
4153
4253
|
"--background",
|
|
4154
4254
|
"Run the mount controller in the background and print its PID"
|
|
4155
|
-
).addOption(new Option("--daemonized").hideHelp()).action(async (options) => {
|
|
4156
|
-
const spinner = ora9(
|
|
4157
|
-
|
|
4158
|
-
|
|
4255
|
+
).addOption(new Option("--daemonized").hideHelp()).addOption(new Option("--open-root-when-ready").hideHelp()).action(async (options) => {
|
|
4256
|
+
const spinner = ora9({
|
|
4257
|
+
spinner: MOUNT_START_SPINNER,
|
|
4258
|
+
text: options.background ? "Starting machine mount controller in background..." : "Starting machine mount controller..."
|
|
4259
|
+
}).start();
|
|
4159
4260
|
try {
|
|
4160
4261
|
if (options.daemonized) {
|
|
4161
|
-
const
|
|
4162
|
-
await runMountDaemon(
|
|
4262
|
+
const config = readMountConfig() ?? defaultMountServiceConfig();
|
|
4263
|
+
await runMountDaemon(config, {
|
|
4163
4264
|
onStarted: () => {
|
|
4164
4265
|
spinner.succeed("Machine mount controller running");
|
|
4165
|
-
printMountStartSummary(
|
|
4266
|
+
printMountStartSummary(config, process.pid, "foreground");
|
|
4267
|
+
},
|
|
4268
|
+
onReady: () => {
|
|
4269
|
+
if (options.openRootWhenReady) {
|
|
4270
|
+
revealMountRootInFinder(config.rootPath);
|
|
4271
|
+
}
|
|
4166
4272
|
}
|
|
4167
4273
|
});
|
|
4168
4274
|
return;
|
|
4169
4275
|
}
|
|
4170
|
-
const
|
|
4171
|
-
writeMountConfig(config);
|
|
4276
|
+
const resolved = await resolveMountServiceConfig(options);
|
|
4277
|
+
writeMountConfig(resolved.config);
|
|
4278
|
+
process.env[AGENTCOMPUTER_MUTAGEN_PATH_ENV] = resolved.mutagenPath;
|
|
4172
4279
|
if (options.background) {
|
|
4173
|
-
const pid = await startMountControllerInBackground(config.rootPath);
|
|
4280
|
+
const pid = await startMountControllerInBackground(resolved.config.rootPath);
|
|
4174
4281
|
spinner.succeed("Machine mount controller running in background");
|
|
4175
|
-
printMountStartSummary(config, pid, "background");
|
|
4282
|
+
printMountStartSummary(resolved.config, pid, "background");
|
|
4176
4283
|
return;
|
|
4177
4284
|
}
|
|
4178
|
-
await
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4285
|
+
const child = await startMountControllerInForeground(resolved.config.rootPath);
|
|
4286
|
+
await waitForMountControllerReady(resolved.config.rootPath, child.pid, spinner);
|
|
4287
|
+
spinner.succeed("Machine mount controller running");
|
|
4288
|
+
printMountStartSummary(
|
|
4289
|
+
resolved.config,
|
|
4290
|
+
child.pid ?? process.pid,
|
|
4291
|
+
"foreground"
|
|
4292
|
+
);
|
|
4293
|
+
await superviseForegroundMountController(child);
|
|
4185
4294
|
} catch (error) {
|
|
4186
4295
|
spinner.fail(
|
|
4187
4296
|
error instanceof Error ? error.message : "Failed to start machine mount controller"
|
|
@@ -4189,40 +4298,40 @@ var mountCommand = new Command10("mount").description("Mirror SSH-ready machines
|
|
|
4189
4298
|
process.exit(1);
|
|
4190
4299
|
}
|
|
4191
4300
|
}).addCommand(
|
|
4192
|
-
new
|
|
4301
|
+
new Command11("status").description("Show machine mount controller status").action(() => {
|
|
4193
4302
|
const config = readMountConfig() ?? defaultMountServiceConfig();
|
|
4194
4303
|
const controller = getMountControllerState(config.rootPath);
|
|
4195
4304
|
const snapshot = readMountStatusSnapshot(config.rootPath);
|
|
4196
4305
|
console.log();
|
|
4197
|
-
console.log(` ${
|
|
4306
|
+
console.log(` ${chalk9.bold("Machine Mounts")}`);
|
|
4198
4307
|
console.log();
|
|
4199
4308
|
console.log(
|
|
4200
|
-
` ${
|
|
4309
|
+
` ${chalk9.dim("Running")} ${controller.running ? chalk9.green("yes") : chalk9.dim("no")}`
|
|
4201
4310
|
);
|
|
4202
4311
|
if (controller.pid) {
|
|
4203
|
-
console.log(` ${
|
|
4312
|
+
console.log(` ${chalk9.dim("PID")} ${controller.pid}`);
|
|
4204
4313
|
}
|
|
4205
|
-
console.log(` ${
|
|
4206
|
-
console.log(` ${
|
|
4314
|
+
console.log(` ${chalk9.dim("Root")} ${config.rootPath}`);
|
|
4315
|
+
console.log(` ${chalk9.dim("Alias")} ${config.alias}`);
|
|
4207
4316
|
console.log(
|
|
4208
|
-
` ${
|
|
4317
|
+
` ${chalk9.dim("Updated")} ${snapshot?.updatedAt ? timeAgo(snapshot.updatedAt) : chalk9.dim("never")}`
|
|
4209
4318
|
);
|
|
4210
4319
|
console.log(
|
|
4211
|
-
` ${
|
|
4320
|
+
` ${chalk9.dim("Healthy")} ${snapshot?.lastHealthySyncAt ? timeAgo(snapshot.lastHealthySyncAt) : chalk9.dim("never")}`
|
|
4212
4321
|
);
|
|
4213
4322
|
if (controller.running && snapshot?.mounts.length) {
|
|
4214
4323
|
console.log();
|
|
4215
4324
|
for (const mount of snapshot.mounts) {
|
|
4216
4325
|
const state = formatMountState(mount.state);
|
|
4217
|
-
console.log(` ${
|
|
4326
|
+
console.log(` ${chalk9.white(mount.handle)} ${state} ${chalk9.dim(mount.mountPath)}`);
|
|
4218
4327
|
if (mount.message) {
|
|
4219
|
-
console.log(` ${
|
|
4328
|
+
console.log(` ${chalk9.dim(mount.message)}`);
|
|
4220
4329
|
}
|
|
4221
4330
|
}
|
|
4222
4331
|
}
|
|
4223
4332
|
if (snapshot?.lastIssue) {
|
|
4224
4333
|
console.log();
|
|
4225
|
-
console.log(` ${
|
|
4334
|
+
console.log(` ${chalk9.dim("Last issue")} ${chalk9.yellow(snapshot.lastIssue)}`);
|
|
4226
4335
|
}
|
|
4227
4336
|
console.log();
|
|
4228
4337
|
})
|
|
@@ -4244,20 +4353,35 @@ async function resolveMountServiceConfig(options) {
|
|
|
4244
4353
|
].join("\n")
|
|
4245
4354
|
);
|
|
4246
4355
|
}
|
|
4356
|
+
const mutagenPath = await ensureMutagenCommandPath();
|
|
4247
4357
|
const sshSetup = await ensureSSHAccessConfigured(options);
|
|
4248
4358
|
return {
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4359
|
+
config: {
|
|
4360
|
+
...defaultMountServiceConfig(),
|
|
4361
|
+
alias: sshSetup.alias,
|
|
4362
|
+
host: sshSetup.host,
|
|
4363
|
+
port: sshSetup.port,
|
|
4364
|
+
pollIntervalMs: parsePositiveInt(options.pollInterval, "poll interval"),
|
|
4365
|
+
connectTimeoutSeconds: parsePositiveInt(
|
|
4366
|
+
options.connectTimeout,
|
|
4367
|
+
"connect timeout"
|
|
4368
|
+
)
|
|
4369
|
+
},
|
|
4370
|
+
mutagenPath
|
|
4258
4371
|
};
|
|
4259
4372
|
}
|
|
4260
4373
|
async function startMountControllerInBackground(rootPath) {
|
|
4374
|
+
const child = startMountControllerProcess(rootPath, true, false);
|
|
4375
|
+
child.unref();
|
|
4376
|
+
await waitForMountControllerRunning(rootPath, child.pid);
|
|
4377
|
+
return child.pid;
|
|
4378
|
+
}
|
|
4379
|
+
async function startMountControllerInForeground(rootPath) {
|
|
4380
|
+
const child = startMountControllerProcess(rootPath, false, true);
|
|
4381
|
+
await waitForMountControllerRunning(rootPath, child.pid);
|
|
4382
|
+
return child;
|
|
4383
|
+
}
|
|
4384
|
+
function startMountControllerProcess(rootPath, detached, openRootWhenReady) {
|
|
4261
4385
|
const controller = getMountControllerState(rootPath);
|
|
4262
4386
|
if (controller.running) {
|
|
4263
4387
|
throw new Error(`computer mount is already running (pid ${controller.pid})`);
|
|
@@ -4266,20 +4390,22 @@ async function startMountControllerInBackground(rootPath) {
|
|
|
4266
4390
|
if (!entrypoint) {
|
|
4267
4391
|
throw new Error("unable to determine CLI entrypoint for background mount");
|
|
4268
4392
|
}
|
|
4269
|
-
const
|
|
4393
|
+
const args = ["mount", "--daemonized"];
|
|
4394
|
+
if (openRootWhenReady) {
|
|
4395
|
+
args.push("--open-root-when-ready");
|
|
4396
|
+
}
|
|
4397
|
+
const child = spawn4(process.execPath, [entrypoint, ...args], {
|
|
4270
4398
|
cwd: process.cwd(),
|
|
4271
|
-
detached
|
|
4399
|
+
detached,
|
|
4272
4400
|
env: process.env,
|
|
4273
4401
|
stdio: "ignore"
|
|
4274
4402
|
});
|
|
4275
4403
|
if (!child.pid) {
|
|
4276
|
-
throw new Error("failed to start machine mount controller
|
|
4404
|
+
throw new Error("failed to start machine mount controller");
|
|
4277
4405
|
}
|
|
4278
|
-
child
|
|
4279
|
-
await waitForBackgroundMountController(rootPath, child.pid);
|
|
4280
|
-
return child.pid;
|
|
4406
|
+
return child;
|
|
4281
4407
|
}
|
|
4282
|
-
async function
|
|
4408
|
+
async function waitForMountControllerRunning(rootPath, pid) {
|
|
4283
4409
|
const deadline = Date.now() + 3e3;
|
|
4284
4410
|
while (Date.now() < deadline) {
|
|
4285
4411
|
const controller = getMountControllerState(rootPath);
|
|
@@ -4293,15 +4419,77 @@ async function waitForBackgroundMountController(rootPath, pid) {
|
|
|
4293
4419
|
}
|
|
4294
4420
|
throw new Error("failed to start machine mount controller in background");
|
|
4295
4421
|
}
|
|
4422
|
+
async function waitForMountControllerReady(rootPath, pid, spinner) {
|
|
4423
|
+
const deadline = Date.now() + 12e4;
|
|
4424
|
+
while (Date.now() < deadline) {
|
|
4425
|
+
const controller = getMountControllerState(rootPath);
|
|
4426
|
+
const snapshot = readMountStatusSnapshot(rootPath);
|
|
4427
|
+
if (snapshot?.controllerPid === pid && snapshot.startupMessage) {
|
|
4428
|
+
spinner.text = snapshot.startupMessage;
|
|
4429
|
+
}
|
|
4430
|
+
if (snapshot?.controllerPid === pid && snapshot.startupPhase === "ready") {
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4433
|
+
if (!controller.running && !processExists2(pid)) {
|
|
4434
|
+
break;
|
|
4435
|
+
}
|
|
4436
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4437
|
+
}
|
|
4438
|
+
throw new Error("mount controller did not finish startup");
|
|
4439
|
+
}
|
|
4440
|
+
async function superviseForegroundMountController(child) {
|
|
4441
|
+
await new Promise((resolve, reject) => {
|
|
4442
|
+
const cleanup = () => {
|
|
4443
|
+
process.off("SIGINT", onSigint);
|
|
4444
|
+
process.off("SIGTERM", onSigterm);
|
|
4445
|
+
child.off("error", onError);
|
|
4446
|
+
child.off("exit", onExit);
|
|
4447
|
+
};
|
|
4448
|
+
const stopAndExit = (signal) => {
|
|
4449
|
+
cleanup();
|
|
4450
|
+
try {
|
|
4451
|
+
child.kill(signal);
|
|
4452
|
+
} catch {
|
|
4453
|
+
}
|
|
4454
|
+
process.exit(0);
|
|
4455
|
+
};
|
|
4456
|
+
const onSigint = () => {
|
|
4457
|
+
stopAndExit("SIGINT");
|
|
4458
|
+
};
|
|
4459
|
+
const onSigterm = () => {
|
|
4460
|
+
stopAndExit("SIGTERM");
|
|
4461
|
+
};
|
|
4462
|
+
const onError = (error) => {
|
|
4463
|
+
cleanup();
|
|
4464
|
+
reject(error);
|
|
4465
|
+
};
|
|
4466
|
+
const onExit = (code, signal) => {
|
|
4467
|
+
cleanup();
|
|
4468
|
+
if (code === 0) {
|
|
4469
|
+
resolve();
|
|
4470
|
+
return;
|
|
4471
|
+
}
|
|
4472
|
+
reject(
|
|
4473
|
+
new Error(
|
|
4474
|
+
signal ? `machine mount controller exited from ${signal}` : `machine mount controller exited with code ${code ?? "unknown"}`
|
|
4475
|
+
)
|
|
4476
|
+
);
|
|
4477
|
+
};
|
|
4478
|
+
process.once("SIGINT", onSigint);
|
|
4479
|
+
process.once("SIGTERM", onSigterm);
|
|
4480
|
+
child.once("error", onError);
|
|
4481
|
+
child.once("exit", onExit);
|
|
4482
|
+
});
|
|
4483
|
+
}
|
|
4296
4484
|
function printMountStartSummary(config, pid, mode) {
|
|
4297
4485
|
console.log();
|
|
4298
|
-
console.log(
|
|
4299
|
-
console.log(
|
|
4300
|
-
console.log(
|
|
4301
|
-
console.log(
|
|
4486
|
+
console.log(chalk9.dim(` PID: ${pid}`));
|
|
4487
|
+
console.log(chalk9.dim(` Root: ${config.rootPath}`));
|
|
4488
|
+
console.log(chalk9.dim(` SSH alias: ${config.alias}`));
|
|
4489
|
+
console.log(chalk9.dim(` Poll: ${config.pollIntervalMs}ms`));
|
|
4302
4490
|
console.log();
|
|
4303
4491
|
console.log(
|
|
4304
|
-
|
|
4492
|
+
chalk9.dim(
|
|
4305
4493
|
mode === "background" ? " Use `computer mount status` to inspect sync state." : " Press Ctrl-C to stop syncing."
|
|
4306
4494
|
)
|
|
4307
4495
|
);
|
|
@@ -4333,35 +4521,35 @@ function revealMountRootInFinder(rootPath) {
|
|
|
4333
4521
|
function formatMountState(state) {
|
|
4334
4522
|
switch (state) {
|
|
4335
4523
|
case "mounted":
|
|
4336
|
-
return
|
|
4524
|
+
return chalk9.green(state);
|
|
4337
4525
|
case "reconnecting":
|
|
4338
|
-
return
|
|
4526
|
+
return chalk9.cyan(state);
|
|
4339
4527
|
case "degraded":
|
|
4340
4528
|
case "pending":
|
|
4341
|
-
return
|
|
4529
|
+
return chalk9.yellow(state);
|
|
4342
4530
|
default:
|
|
4343
|
-
return
|
|
4531
|
+
return chalk9.red(state);
|
|
4344
4532
|
}
|
|
4345
4533
|
}
|
|
4346
4534
|
|
|
4347
4535
|
// src/commands/logout.ts
|
|
4348
|
-
import { Command as
|
|
4349
|
-
import
|
|
4350
|
-
var logoutCommand = new
|
|
4536
|
+
import { Command as Command12 } from "commander";
|
|
4537
|
+
import chalk10 from "chalk";
|
|
4538
|
+
var logoutCommand = new Command12("logout").description("Remove stored API key").action(() => {
|
|
4351
4539
|
if (!getStoredAPIKey()) {
|
|
4352
4540
|
console.log();
|
|
4353
|
-
console.log(
|
|
4541
|
+
console.log(chalk10.dim(" Not logged in."));
|
|
4354
4542
|
if (hasEnvAPIKey()) {
|
|
4355
|
-
console.log(
|
|
4543
|
+
console.log(chalk10.dim(" Environment API key is still active in this shell."));
|
|
4356
4544
|
}
|
|
4357
4545
|
console.log();
|
|
4358
4546
|
return;
|
|
4359
4547
|
}
|
|
4360
4548
|
clearAPIKey();
|
|
4361
4549
|
console.log();
|
|
4362
|
-
console.log(
|
|
4550
|
+
console.log(chalk10.green(" Logged out."));
|
|
4363
4551
|
if (hasEnvAPIKey()) {
|
|
4364
|
-
console.log(
|
|
4552
|
+
console.log(chalk10.dim(" Environment API key is still active in this shell."));
|
|
4365
4553
|
}
|
|
4366
4554
|
console.log();
|
|
4367
4555
|
});
|
|
@@ -4369,8 +4557,8 @@ var logoutCommand = new Command11("logout").description("Remove stored API key")
|
|
|
4369
4557
|
// src/commands/upgrade.ts
|
|
4370
4558
|
import { spawnSync } from "child_process";
|
|
4371
4559
|
import { readFileSync as readFileSync2, realpathSync } from "fs";
|
|
4372
|
-
import { Command as
|
|
4373
|
-
import
|
|
4560
|
+
import { Command as Command13 } from "commander";
|
|
4561
|
+
import chalk11 from "chalk";
|
|
4374
4562
|
import ora10 from "ora";
|
|
4375
4563
|
var pkg2 = JSON.parse(
|
|
4376
4564
|
readFileSync2(new URL("../package.json", import.meta.url), "utf8")
|
|
@@ -4485,7 +4673,25 @@ async function getLatestVersion(packageName) {
|
|
|
4485
4673
|
}
|
|
4486
4674
|
return payload.version;
|
|
4487
4675
|
}
|
|
4488
|
-
|
|
4676
|
+
function attemptBundledMutagenRefresh(executablePath) {
|
|
4677
|
+
const install = spawnSync(
|
|
4678
|
+
process.execPath,
|
|
4679
|
+
[executablePath, "internal-install-mutagen", "--quiet"],
|
|
4680
|
+
{
|
|
4681
|
+
stdio: "ignore"
|
|
4682
|
+
}
|
|
4683
|
+
);
|
|
4684
|
+
if (install.status === 0) {
|
|
4685
|
+
return;
|
|
4686
|
+
}
|
|
4687
|
+
console.log();
|
|
4688
|
+
console.log(
|
|
4689
|
+
chalk11.yellow(
|
|
4690
|
+
" CLI updated, but bundled Mutagen did not finish installing. `computer mount` will retry on first use."
|
|
4691
|
+
)
|
|
4692
|
+
);
|
|
4693
|
+
}
|
|
4694
|
+
var upgradeCommand = new Command13("upgrade").description("Update the CLI to the latest version").action(async () => {
|
|
4489
4695
|
const currentVersion = pkg2.version ?? "0.0.0";
|
|
4490
4696
|
const packageName = pkg2.name ?? "aicomputer";
|
|
4491
4697
|
const spinner = ora10("Checking for updates...").start();
|
|
@@ -4518,16 +4724,19 @@ var upgradeCommand = new Command12("upgrade").description("Update the CLI to the
|
|
|
4518
4724
|
spinner.stop();
|
|
4519
4725
|
console.log();
|
|
4520
4726
|
console.log(
|
|
4521
|
-
|
|
4727
|
+
chalk11.dim(` Updating ${chalk11.bold(`v${currentVersion}`)} -> ${chalk11.bold(`v${latestVersion}`)}`)
|
|
4522
4728
|
);
|
|
4523
|
-
console.log(
|
|
4729
|
+
console.log(chalk11.dim(` ${upgrade.label}`));
|
|
4524
4730
|
console.log();
|
|
4525
4731
|
const result = spawnSync(upgrade.command, upgrade.args, {
|
|
4526
4732
|
stdio: "inherit"
|
|
4527
4733
|
});
|
|
4528
4734
|
if (result.status === 0) {
|
|
4735
|
+
if (method !== "nix") {
|
|
4736
|
+
attemptBundledMutagenRefresh(executablePath);
|
|
4737
|
+
}
|
|
4529
4738
|
console.log();
|
|
4530
|
-
console.log(
|
|
4739
|
+
console.log(chalk11.green(` Updated to v${latestVersion}.`));
|
|
4531
4740
|
console.log();
|
|
4532
4741
|
return;
|
|
4533
4742
|
}
|
|
@@ -4535,10 +4744,10 @@ var upgradeCommand = new Command12("upgrade").description("Update the CLI to the
|
|
|
4535
4744
|
});
|
|
4536
4745
|
|
|
4537
4746
|
// src/commands/whoami.ts
|
|
4538
|
-
import { Command as
|
|
4539
|
-
import
|
|
4747
|
+
import { Command as Command14 } from "commander";
|
|
4748
|
+
import chalk12 from "chalk";
|
|
4540
4749
|
import ora11 from "ora";
|
|
4541
|
-
var whoamiCommand = new
|
|
4750
|
+
var whoamiCommand = new Command14("whoami").description("Show current user").option("--json", "Print raw JSON").action(async (options) => {
|
|
4542
4751
|
const spinner = options.json ? null : ora11("Loading user...").start();
|
|
4543
4752
|
try {
|
|
4544
4753
|
const me = await api("/v1/me");
|
|
@@ -4548,14 +4757,14 @@ var whoamiCommand = new Command13("whoami").description("Show current user").opt
|
|
|
4548
4757
|
return;
|
|
4549
4758
|
}
|
|
4550
4759
|
console.log();
|
|
4551
|
-
console.log(` ${
|
|
4760
|
+
console.log(` ${chalk12.bold.white(me.user.display_name || me.user.email)}`);
|
|
4552
4761
|
if (me.user.display_name) {
|
|
4553
|
-
console.log(` ${
|
|
4762
|
+
console.log(` ${chalk12.dim(me.user.email)}`);
|
|
4554
4763
|
}
|
|
4555
4764
|
if (me.api_key.name) {
|
|
4556
|
-
console.log(` ${
|
|
4765
|
+
console.log(` ${chalk12.dim("Key:")} ${me.api_key.name}`);
|
|
4557
4766
|
}
|
|
4558
|
-
console.log(` ${
|
|
4767
|
+
console.log(` ${chalk12.dim("API:")} ${chalk12.dim(getBaseURL())}`);
|
|
4559
4768
|
console.log();
|
|
4560
4769
|
} catch (error) {
|
|
4561
4770
|
if (spinner) {
|
|
@@ -4572,15 +4781,15 @@ var pkg3 = JSON.parse(
|
|
|
4572
4781
|
readFileSync3(new URL("../package.json", import.meta.url), "utf8")
|
|
4573
4782
|
);
|
|
4574
4783
|
var cliName = process.argv[1] ? basename2(process.argv[1]) : "agentcomputer";
|
|
4575
|
-
var program = new
|
|
4784
|
+
var program = new Command15();
|
|
4576
4785
|
function appendTextSection(lines, title, values) {
|
|
4577
4786
|
if (values.length === 0) {
|
|
4578
4787
|
return;
|
|
4579
4788
|
}
|
|
4580
|
-
lines.push(` ${
|
|
4789
|
+
lines.push(` ${chalk13.dim(title)}`);
|
|
4581
4790
|
lines.push("");
|
|
4582
4791
|
for (const value of values) {
|
|
4583
|
-
lines.push(` ${
|
|
4792
|
+
lines.push(` ${chalk13.white(value)}`);
|
|
4584
4793
|
}
|
|
4585
4794
|
lines.push("");
|
|
4586
4795
|
}
|
|
@@ -4589,10 +4798,10 @@ function appendTableSection(lines, title, entries) {
|
|
|
4589
4798
|
return;
|
|
4590
4799
|
}
|
|
4591
4800
|
const width = Math.max(...entries.map((entry) => entry.term.length), 0) + 2;
|
|
4592
|
-
lines.push(` ${
|
|
4801
|
+
lines.push(` ${chalk13.dim(title)}`);
|
|
4593
4802
|
lines.push("");
|
|
4594
4803
|
for (const entry of entries) {
|
|
4595
|
-
lines.push(` ${
|
|
4804
|
+
lines.push(` ${chalk13.white(padEnd(entry.term, width))}${chalk13.dim(entry.desc)}`);
|
|
4596
4805
|
}
|
|
4597
4806
|
lines.push("");
|
|
4598
4807
|
}
|
|
@@ -4618,10 +4827,10 @@ function formatRootHelp(cmd) {
|
|
|
4618
4827
|
["Other", []]
|
|
4619
4828
|
];
|
|
4620
4829
|
const otherGroup = groups.find(([name]) => name === "Other")[1];
|
|
4621
|
-
lines.push(`${
|
|
4830
|
+
lines.push(`${chalk13.bold(cliName)} ${chalk13.dim(`v${version}`)}`);
|
|
4622
4831
|
lines.push("");
|
|
4623
4832
|
if (cmd.description()) {
|
|
4624
|
-
lines.push(` ${
|
|
4833
|
+
lines.push(` ${chalk13.dim(cmd.description())}`);
|
|
4625
4834
|
lines.push("");
|
|
4626
4835
|
}
|
|
4627
4836
|
appendTextSection(lines, "Usage", [`${cliName} <command> [options]`]);
|
|
@@ -4674,10 +4883,10 @@ function formatSubcommandHelp(cmd, helper) {
|
|
|
4674
4883
|
term: helper.optionTerm(option),
|
|
4675
4884
|
desc: helper.optionDescription(option)
|
|
4676
4885
|
}));
|
|
4677
|
-
lines.push(
|
|
4886
|
+
lines.push(chalk13.bold(commandPath(cmd)));
|
|
4678
4887
|
lines.push("");
|
|
4679
4888
|
if (description) {
|
|
4680
|
-
lines.push(` ${
|
|
4889
|
+
lines.push(` ${chalk13.dim(description)}`);
|
|
4681
4890
|
lines.push("");
|
|
4682
4891
|
}
|
|
4683
4892
|
appendTextSection(lines, "Usage", [helper.commandUsage(cmd)]);
|
|
@@ -4703,6 +4912,7 @@ function applyHelpFormatting(cmd) {
|
|
|
4703
4912
|
program.name(cliName).description("Agent Computer CLI").version(pkg3.version ?? "0.0.0").option("-y, --yes", "Skip confirmation prompts");
|
|
4704
4913
|
program.addCommand(loginCommand);
|
|
4705
4914
|
program.addCommand(upgradeCommand);
|
|
4915
|
+
program.addCommand(internalInstallMutagenCommand, { hidden: true });
|
|
4706
4916
|
program.addCommand(logoutCommand);
|
|
4707
4917
|
program.addCommand(whoamiCommand);
|
|
4708
4918
|
program.addCommand(claudeLoginCommand);
|