aicomputer 0.1.16 → 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 +18 -5
- 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 +427 -105
- 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
|
|
|
@@ -2460,7 +2466,7 @@ _computer() {
|
|
|
2460
2466
|
'open:Open in browser'
|
|
2461
2467
|
'ssh:SSH into a computer'
|
|
2462
2468
|
'ports:Manage published ports'
|
|
2463
|
-
'mount:Mirror SSH-ready machine homes into ~/agentcomputer
|
|
2469
|
+
'mount:Mirror SSH-ready machine homes into ~/agentcomputer'
|
|
2464
2470
|
'agent:Manage cloud agent sessions'
|
|
2465
2471
|
'acp:Run a local ACP bridge for remote agent sessions'
|
|
2466
2472
|
'rm:Delete a computer'
|
|
@@ -2600,6 +2606,7 @@ _computer() {
|
|
|
2600
2606
|
;;
|
|
2601
2607
|
mount)
|
|
2602
2608
|
_arguments -C \\
|
|
2609
|
+
'--background[Run the mount controller in the background and print its PID]' \\
|
|
2603
2610
|
'--alias[SSH host alias]:alias:' \\
|
|
2604
2611
|
'--host[SSH gateway host]:host:' \\
|
|
2605
2612
|
'--port[SSH gateway port]:port:' \\
|
|
@@ -2771,9 +2778,9 @@ var BASH_SCRIPT = `_computer() {
|
|
|
2771
2778
|
;;
|
|
2772
2779
|
mount)
|
|
2773
2780
|
if [[ $cword -eq 2 ]]; then
|
|
2774
|
-
COMPREPLY=($(compgen -W "$mount_commands" -- "$cur"))
|
|
2781
|
+
COMPREPLY=($(compgen -W "$mount_commands --background --alias --host --port --poll-interval --connect-timeout" -- "$cur"))
|
|
2775
2782
|
elif [[ $cword -ge 3 ]]; then
|
|
2776
|
-
COMPREPLY=($(compgen -W "--alias --host --port --poll-interval --connect-timeout" -- "$cur"))
|
|
2783
|
+
COMPREPLY=($(compgen -W "--background --alias --host --port --poll-interval --connect-timeout" -- "$cur"))
|
|
2777
2784
|
fi
|
|
2778
2785
|
;;
|
|
2779
2786
|
ports)
|
|
@@ -3560,9 +3567,35 @@ async function confirmDeletion(sourceID) {
|
|
|
3560
3567
|
});
|
|
3561
3568
|
}
|
|
3562
3569
|
|
|
3563
|
-
// src/commands/
|
|
3570
|
+
// src/commands/internal-install-mutagen.ts
|
|
3564
3571
|
import { Command as Command9 } from "commander";
|
|
3565
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";
|
|
3566
3599
|
import ora8 from "ora";
|
|
3567
3600
|
|
|
3568
3601
|
// src/lib/browser-login.ts
|
|
@@ -3830,12 +3863,12 @@ function escapeHTML(value) {
|
|
|
3830
3863
|
}
|
|
3831
3864
|
|
|
3832
3865
|
// src/commands/login.ts
|
|
3833
|
-
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) => {
|
|
3834
3867
|
const existingKey = getStoredAPIKey();
|
|
3835
3868
|
if (existingKey && !options.force) {
|
|
3836
3869
|
console.log();
|
|
3837
3870
|
console.log(
|
|
3838
|
-
|
|
3871
|
+
chalk8.yellow(" Already logged in. Use --force to overwrite.")
|
|
3839
3872
|
);
|
|
3840
3873
|
console.log();
|
|
3841
3874
|
return;
|
|
@@ -3844,8 +3877,8 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3844
3877
|
const apiKey = await resolveAPIKeyInput(options.apiKey, options.stdin);
|
|
3845
3878
|
if (!apiKey && wantsManualLogin) {
|
|
3846
3879
|
console.log();
|
|
3847
|
-
console.log(
|
|
3848
|
-
console.log(
|
|
3880
|
+
console.log(chalk8.dim(" Usage: computer login --api-key <ac_live_...>"));
|
|
3881
|
+
console.log(chalk8.dim(` API: ${getBaseURL()}`));
|
|
3849
3882
|
console.log();
|
|
3850
3883
|
process.exit(1);
|
|
3851
3884
|
}
|
|
@@ -3855,7 +3888,7 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3855
3888
|
}
|
|
3856
3889
|
if (!apiKey.startsWith("ac_live_")) {
|
|
3857
3890
|
console.log();
|
|
3858
|
-
console.log(
|
|
3891
|
+
console.log(chalk8.red(" API key must start with ac_live_"));
|
|
3859
3892
|
console.log();
|
|
3860
3893
|
process.exit(1);
|
|
3861
3894
|
}
|
|
@@ -3863,7 +3896,7 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3863
3896
|
try {
|
|
3864
3897
|
const me = await apiWithKey(apiKey, "/v1/me");
|
|
3865
3898
|
setAPIKey(apiKey);
|
|
3866
|
-
spinner.succeed(`Logged in as ${
|
|
3899
|
+
spinner.succeed(`Logged in as ${chalk8.bold(me.user.email)}`);
|
|
3867
3900
|
} catch (error) {
|
|
3868
3901
|
spinner.fail(
|
|
3869
3902
|
error instanceof Error ? error.message : "Failed to validate API key"
|
|
@@ -3883,15 +3916,15 @@ async function runBrowserLogin() {
|
|
|
3883
3916
|
spinner.stop();
|
|
3884
3917
|
console.log();
|
|
3885
3918
|
console.log(
|
|
3886
|
-
|
|
3919
|
+
chalk8.yellow(" Browser auto-open failed. Open this URL to continue:")
|
|
3887
3920
|
);
|
|
3888
|
-
console.log(
|
|
3921
|
+
console.log(chalk8.dim(` ${attempt.loginURL}`));
|
|
3889
3922
|
console.log();
|
|
3890
3923
|
spinner.start("Waiting for browser login...");
|
|
3891
3924
|
}
|
|
3892
3925
|
spinner.text = "Waiting for browser login...";
|
|
3893
3926
|
const result = await attempt.waitForResult();
|
|
3894
|
-
spinner.succeed(`Logged in as ${
|
|
3927
|
+
spinner.succeed(`Logged in as ${chalk8.bold(result.me.user.email)}`);
|
|
3895
3928
|
await continueFirstLoginFlow(result);
|
|
3896
3929
|
} catch (error) {
|
|
3897
3930
|
spinner.fail(
|
|
@@ -3925,8 +3958,8 @@ async function continueFirstLoginFlow(result) {
|
|
|
3925
3958
|
}
|
|
3926
3959
|
console.log();
|
|
3927
3960
|
console.log(
|
|
3928
|
-
|
|
3929
|
-
`Continuing first-time setup for ${
|
|
3961
|
+
chalk8.cyan(
|
|
3962
|
+
`Continuing first-time setup for ${chalk8.bold(machineHandle)}...
|
|
3930
3963
|
`
|
|
3931
3964
|
)
|
|
3932
3965
|
);
|
|
@@ -3939,8 +3972,8 @@ async function continueFirstLoginFlow(result) {
|
|
|
3939
3972
|
const spinner = ora8(`Preparing SSH access for ${machineHandle}...`).start();
|
|
3940
3973
|
try {
|
|
3941
3974
|
const connection = await prepareSSHConnectionByIdentifier(machineHandle);
|
|
3942
|
-
spinner.succeed(`Connecting to ${
|
|
3943
|
-
console.log(
|
|
3975
|
+
spinner.succeed(`Connecting to ${chalk8.bold(machineHandle)}`);
|
|
3976
|
+
console.log(chalk8.dim(` ${connection.command}`));
|
|
3944
3977
|
console.log();
|
|
3945
3978
|
await openSSHConnection(connection);
|
|
3946
3979
|
} catch (error) {
|
|
@@ -3951,19 +3984,19 @@ async function continueFirstLoginFlow(result) {
|
|
|
3951
3984
|
}
|
|
3952
3985
|
} catch (error) {
|
|
3953
3986
|
const message = error instanceof Error ? error.message : "Failed to finish first-time setup";
|
|
3954
|
-
console.error(
|
|
3987
|
+
console.error(chalk8.red(`
|
|
3955
3988
|
${message}`));
|
|
3956
3989
|
console.log();
|
|
3957
3990
|
if (result.provider === "claude") {
|
|
3958
3991
|
console.log(
|
|
3959
|
-
|
|
3992
|
+
chalk8.dim(` computer claude-login --machine ${machineHandle}`)
|
|
3960
3993
|
);
|
|
3961
3994
|
} else if (result.provider === "codex") {
|
|
3962
3995
|
console.log(
|
|
3963
|
-
|
|
3996
|
+
chalk8.dim(` computer codex-login --machine ${machineHandle}`)
|
|
3964
3997
|
);
|
|
3965
3998
|
}
|
|
3966
|
-
console.log(
|
|
3999
|
+
console.log(chalk8.dim(` computer ssh ${machineHandle}`));
|
|
3967
4000
|
console.log();
|
|
3968
4001
|
process.exit(1);
|
|
3969
4002
|
}
|
|
@@ -3977,18 +4010,19 @@ async function runSelectedProvider(provider, machineHandle) {
|
|
|
3977
4010
|
await runCodexLogin({ machine: machineHandle });
|
|
3978
4011
|
return;
|
|
3979
4012
|
}
|
|
3980
|
-
console.log(
|
|
4013
|
+
console.log(chalk8.green(`Sandbox ${chalk8.bold(machineHandle)} is ready.`));
|
|
3981
4014
|
console.log();
|
|
3982
4015
|
}
|
|
3983
4016
|
function printNextStep(machineHandle) {
|
|
3984
|
-
console.log(
|
|
3985
|
-
console.log(
|
|
4017
|
+
console.log(chalk8.green(`Sandbox ${chalk8.bold(machineHandle)} is ready.`));
|
|
4018
|
+
console.log(chalk8.dim(` computer ssh ${machineHandle}`));
|
|
3986
4019
|
console.log();
|
|
3987
4020
|
}
|
|
3988
4021
|
|
|
3989
4022
|
// src/commands/mount.ts
|
|
3990
|
-
import {
|
|
3991
|
-
import
|
|
4023
|
+
import { spawn as spawn4 } from "child_process";
|
|
4024
|
+
import { Command as Command11, Option } from "commander";
|
|
4025
|
+
import chalk9 from "chalk";
|
|
3992
4026
|
import ora9 from "ora";
|
|
3993
4027
|
|
|
3994
4028
|
// src/lib/mount-daemon.ts
|
|
@@ -4004,7 +4038,8 @@ function getMountControllerState(rootPath = defaultMountServiceConfig().rootPath
|
|
|
4004
4038
|
}
|
|
4005
4039
|
return { running: true, pid: lock.pid };
|
|
4006
4040
|
}
|
|
4007
|
-
async function runMountDaemon(config) {
|
|
4041
|
+
async function runMountDaemon(config, options = {}) {
|
|
4042
|
+
const { onReady, onStarted } = options;
|
|
4008
4043
|
const paths = getMountPaths(config.rootPath);
|
|
4009
4044
|
ensureMountDirectories(paths);
|
|
4010
4045
|
await mkdir3(paths.rootPath, { recursive: true });
|
|
@@ -4014,15 +4049,35 @@ async function runMountDaemon(config) {
|
|
|
4014
4049
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4015
4050
|
controllerPid: process.pid,
|
|
4016
4051
|
running: true,
|
|
4052
|
+
startupPhase: "starting",
|
|
4053
|
+
startupMessage: "Starting mount controller...",
|
|
4017
4054
|
mounts: []
|
|
4018
4055
|
},
|
|
4019
4056
|
config.rootPath
|
|
4020
4057
|
);
|
|
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
|
+
);
|
|
4021
4074
|
await teardownManagedSessions(config, paths);
|
|
4075
|
+
await mkdir3(paths.rootPath, { recursive: true });
|
|
4022
4076
|
let running = false;
|
|
4023
4077
|
let queued = false;
|
|
4024
4078
|
let shuttingDown = false;
|
|
4025
4079
|
let activeRun = null;
|
|
4080
|
+
let activeRunController = null;
|
|
4026
4081
|
const runOnce = async () => {
|
|
4027
4082
|
if (shuttingDown) {
|
|
4028
4083
|
return;
|
|
@@ -4031,12 +4086,19 @@ async function runMountDaemon(config) {
|
|
|
4031
4086
|
queued = true;
|
|
4032
4087
|
return activeRun ?? void 0;
|
|
4033
4088
|
}
|
|
4089
|
+
const controller = new AbortController();
|
|
4090
|
+
activeRunController = controller;
|
|
4034
4091
|
activeRun = (async () => {
|
|
4035
4092
|
running = true;
|
|
4036
4093
|
try {
|
|
4037
|
-
await reconcileMounts(
|
|
4094
|
+
await reconcileMounts(
|
|
4095
|
+
config,
|
|
4096
|
+
paths,
|
|
4097
|
+
process.pid,
|
|
4098
|
+
controller.signal
|
|
4099
|
+
);
|
|
4038
4100
|
} catch (error) {
|
|
4039
|
-
if (shuttingDown) {
|
|
4101
|
+
if (shuttingDown && isAbortError(error)) {
|
|
4040
4102
|
return;
|
|
4041
4103
|
}
|
|
4042
4104
|
const previous = readMountStatusSnapshot(config.rootPath);
|
|
@@ -4045,6 +4107,8 @@ async function runMountDaemon(config) {
|
|
|
4045
4107
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4046
4108
|
controllerPid: process.pid,
|
|
4047
4109
|
running: true,
|
|
4110
|
+
startupPhase: previous?.startupPhase === "ready" ? "ready" : "syncing",
|
|
4111
|
+
startupMessage: previous?.startupPhase === "ready" ? void 0 : "Waiting for initial sync...",
|
|
4048
4112
|
lastHealthySyncAt: previous?.lastHealthySyncAt,
|
|
4049
4113
|
lastSuccessfulSyncAt: previous?.lastSuccessfulSyncAt,
|
|
4050
4114
|
lastIssueAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4060,6 +4124,7 @@ async function runMountDaemon(config) {
|
|
|
4060
4124
|
} finally {
|
|
4061
4125
|
running = false;
|
|
4062
4126
|
activeRun = null;
|
|
4127
|
+
activeRunController = null;
|
|
4063
4128
|
if (queued && !shuttingDown) {
|
|
4064
4129
|
queued = false;
|
|
4065
4130
|
void runOnce();
|
|
@@ -4075,6 +4140,21 @@ async function runMountDaemon(config) {
|
|
|
4075
4140
|
server.once("error", reject);
|
|
4076
4141
|
server.listen(paths.socketPath, () => resolve());
|
|
4077
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
|
+
);
|
|
4078
4158
|
const interval = setInterval(() => {
|
|
4079
4159
|
void runOnce();
|
|
4080
4160
|
}, config.pollIntervalMs);
|
|
@@ -4085,6 +4165,7 @@ async function runMountDaemon(config) {
|
|
|
4085
4165
|
shuttingDown = true;
|
|
4086
4166
|
clearInterval(interval);
|
|
4087
4167
|
server.close();
|
|
4168
|
+
activeRunController?.abort();
|
|
4088
4169
|
if (activeRun) {
|
|
4089
4170
|
await activeRun.catch(() => {
|
|
4090
4171
|
});
|
|
@@ -4096,6 +4177,8 @@ async function runMountDaemon(config) {
|
|
|
4096
4177
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4097
4178
|
controllerPid: previous?.controllerPid,
|
|
4098
4179
|
running: false,
|
|
4180
|
+
startupPhase: void 0,
|
|
4181
|
+
startupMessage: void 0,
|
|
4099
4182
|
lastHealthySyncAt: previous?.lastHealthySyncAt,
|
|
4100
4183
|
lastSuccessfulSyncAt: previous?.lastSuccessfulSyncAt,
|
|
4101
4184
|
lastIssueAt: previous?.lastIssueAt,
|
|
@@ -4115,6 +4198,8 @@ async function runMountDaemon(config) {
|
|
|
4115
4198
|
void shutdown();
|
|
4116
4199
|
});
|
|
4117
4200
|
await runOnce();
|
|
4201
|
+
writeMountStatusSnapshot(markMountStartupReady(readMountStatusSnapshot(config.rootPath), process.pid), config.rootPath);
|
|
4202
|
+
onReady?.();
|
|
4118
4203
|
await new Promise(() => {
|
|
4119
4204
|
});
|
|
4120
4205
|
}
|
|
@@ -4143,42 +4228,69 @@ function processExists(pid) {
|
|
|
4143
4228
|
return false;
|
|
4144
4229
|
}
|
|
4145
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
|
+
}
|
|
4146
4246
|
|
|
4147
4247
|
// src/commands/mount.ts
|
|
4148
|
-
var
|
|
4149
|
-
|
|
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(
|
|
4253
|
+
"--background",
|
|
4254
|
+
"Run the mount controller in the background and print its PID"
|
|
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();
|
|
4150
4260
|
try {
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4261
|
+
if (options.daemonized) {
|
|
4262
|
+
const config = readMountConfig() ?? defaultMountServiceConfig();
|
|
4263
|
+
await runMountDaemon(config, {
|
|
4264
|
+
onStarted: () => {
|
|
4265
|
+
spinner.succeed("Machine mount controller running");
|
|
4266
|
+
printMountStartSummary(config, process.pid, "foreground");
|
|
4267
|
+
},
|
|
4268
|
+
onReady: () => {
|
|
4269
|
+
if (options.openRootWhenReady) {
|
|
4270
|
+
revealMountRootInFinder(config.rootPath);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
});
|
|
4274
|
+
return;
|
|
4159
4275
|
}
|
|
4160
|
-
const
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
};
|
|
4172
|
-
writeMountConfig(config);
|
|
4276
|
+
const resolved = await resolveMountServiceConfig(options);
|
|
4277
|
+
writeMountConfig(resolved.config);
|
|
4278
|
+
process.env[AGENTCOMPUTER_MUTAGEN_PATH_ENV] = resolved.mutagenPath;
|
|
4279
|
+
if (options.background) {
|
|
4280
|
+
const pid = await startMountControllerInBackground(resolved.config.rootPath);
|
|
4281
|
+
spinner.succeed("Machine mount controller running in background");
|
|
4282
|
+
printMountStartSummary(resolved.config, pid, "background");
|
|
4283
|
+
return;
|
|
4284
|
+
}
|
|
4285
|
+
const child = await startMountControllerInForeground(resolved.config.rootPath);
|
|
4286
|
+
await waitForMountControllerReady(resolved.config.rootPath, child.pid, spinner);
|
|
4173
4287
|
spinner.succeed("Machine mount controller running");
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
console.log();
|
|
4181
|
-
await runMountDaemon(config);
|
|
4288
|
+
printMountStartSummary(
|
|
4289
|
+
resolved.config,
|
|
4290
|
+
child.pid ?? process.pid,
|
|
4291
|
+
"foreground"
|
|
4292
|
+
);
|
|
4293
|
+
await superviseForegroundMountController(child);
|
|
4182
4294
|
} catch (error) {
|
|
4183
4295
|
spinner.fail(
|
|
4184
4296
|
error instanceof Error ? error.message : "Failed to start machine mount controller"
|
|
@@ -4186,40 +4298,40 @@ var mountCommand = new Command10("mount").description("Mirror SSH-ready machines
|
|
|
4186
4298
|
process.exit(1);
|
|
4187
4299
|
}
|
|
4188
4300
|
}).addCommand(
|
|
4189
|
-
new
|
|
4301
|
+
new Command11("status").description("Show machine mount controller status").action(() => {
|
|
4190
4302
|
const config = readMountConfig() ?? defaultMountServiceConfig();
|
|
4191
4303
|
const controller = getMountControllerState(config.rootPath);
|
|
4192
4304
|
const snapshot = readMountStatusSnapshot(config.rootPath);
|
|
4193
4305
|
console.log();
|
|
4194
|
-
console.log(` ${
|
|
4306
|
+
console.log(` ${chalk9.bold("Machine Mounts")}`);
|
|
4195
4307
|
console.log();
|
|
4196
4308
|
console.log(
|
|
4197
|
-
` ${
|
|
4309
|
+
` ${chalk9.dim("Running")} ${controller.running ? chalk9.green("yes") : chalk9.dim("no")}`
|
|
4198
4310
|
);
|
|
4199
4311
|
if (controller.pid) {
|
|
4200
|
-
console.log(` ${
|
|
4312
|
+
console.log(` ${chalk9.dim("PID")} ${controller.pid}`);
|
|
4201
4313
|
}
|
|
4202
|
-
console.log(` ${
|
|
4203
|
-
console.log(` ${
|
|
4314
|
+
console.log(` ${chalk9.dim("Root")} ${config.rootPath}`);
|
|
4315
|
+
console.log(` ${chalk9.dim("Alias")} ${config.alias}`);
|
|
4204
4316
|
console.log(
|
|
4205
|
-
` ${
|
|
4317
|
+
` ${chalk9.dim("Updated")} ${snapshot?.updatedAt ? timeAgo(snapshot.updatedAt) : chalk9.dim("never")}`
|
|
4206
4318
|
);
|
|
4207
4319
|
console.log(
|
|
4208
|
-
` ${
|
|
4320
|
+
` ${chalk9.dim("Healthy")} ${snapshot?.lastHealthySyncAt ? timeAgo(snapshot.lastHealthySyncAt) : chalk9.dim("never")}`
|
|
4209
4321
|
);
|
|
4210
4322
|
if (controller.running && snapshot?.mounts.length) {
|
|
4211
4323
|
console.log();
|
|
4212
4324
|
for (const mount of snapshot.mounts) {
|
|
4213
|
-
const state =
|
|
4214
|
-
console.log(` ${
|
|
4325
|
+
const state = formatMountState(mount.state);
|
|
4326
|
+
console.log(` ${chalk9.white(mount.handle)} ${state} ${chalk9.dim(mount.mountPath)}`);
|
|
4215
4327
|
if (mount.message) {
|
|
4216
|
-
console.log(` ${
|
|
4328
|
+
console.log(` ${chalk9.dim(mount.message)}`);
|
|
4217
4329
|
}
|
|
4218
4330
|
}
|
|
4219
4331
|
}
|
|
4220
4332
|
if (snapshot?.lastIssue) {
|
|
4221
4333
|
console.log();
|
|
4222
|
-
console.log(` ${
|
|
4334
|
+
console.log(` ${chalk9.dim("Last issue")} ${chalk9.yellow(snapshot.lastIssue)}`);
|
|
4223
4335
|
}
|
|
4224
4336
|
console.log();
|
|
4225
4337
|
})
|
|
@@ -4231,25 +4343,213 @@ function parsePositiveInt(raw, label) {
|
|
|
4231
4343
|
}
|
|
4232
4344
|
return Math.round(value);
|
|
4233
4345
|
}
|
|
4346
|
+
async function resolveMountServiceConfig(options) {
|
|
4347
|
+
const issues = getMountHostValidationIssues();
|
|
4348
|
+
if (issues.length > 0) {
|
|
4349
|
+
throw new Error(
|
|
4350
|
+
[
|
|
4351
|
+
...issues.map((issue) => issue.message),
|
|
4352
|
+
...formatMountHostInstallGuidance(issues)
|
|
4353
|
+
].join("\n")
|
|
4354
|
+
);
|
|
4355
|
+
}
|
|
4356
|
+
const mutagenPath = await ensureMutagenCommandPath();
|
|
4357
|
+
const sshSetup = await ensureSSHAccessConfigured(options);
|
|
4358
|
+
return {
|
|
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
|
|
4371
|
+
};
|
|
4372
|
+
}
|
|
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) {
|
|
4385
|
+
const controller = getMountControllerState(rootPath);
|
|
4386
|
+
if (controller.running) {
|
|
4387
|
+
throw new Error(`computer mount is already running (pid ${controller.pid})`);
|
|
4388
|
+
}
|
|
4389
|
+
const entrypoint = process.argv[1];
|
|
4390
|
+
if (!entrypoint) {
|
|
4391
|
+
throw new Error("unable to determine CLI entrypoint for background mount");
|
|
4392
|
+
}
|
|
4393
|
+
const args = ["mount", "--daemonized"];
|
|
4394
|
+
if (openRootWhenReady) {
|
|
4395
|
+
args.push("--open-root-when-ready");
|
|
4396
|
+
}
|
|
4397
|
+
const child = spawn4(process.execPath, [entrypoint, ...args], {
|
|
4398
|
+
cwd: process.cwd(),
|
|
4399
|
+
detached,
|
|
4400
|
+
env: process.env,
|
|
4401
|
+
stdio: "ignore"
|
|
4402
|
+
});
|
|
4403
|
+
if (!child.pid) {
|
|
4404
|
+
throw new Error("failed to start machine mount controller");
|
|
4405
|
+
}
|
|
4406
|
+
return child;
|
|
4407
|
+
}
|
|
4408
|
+
async function waitForMountControllerRunning(rootPath, pid) {
|
|
4409
|
+
const deadline = Date.now() + 3e3;
|
|
4410
|
+
while (Date.now() < deadline) {
|
|
4411
|
+
const controller = getMountControllerState(rootPath);
|
|
4412
|
+
if (controller.running && controller.pid === pid) {
|
|
4413
|
+
return;
|
|
4414
|
+
}
|
|
4415
|
+
if (!processExists2(pid)) {
|
|
4416
|
+
break;
|
|
4417
|
+
}
|
|
4418
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
4419
|
+
}
|
|
4420
|
+
throw new Error("failed to start machine mount controller in background");
|
|
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
|
+
}
|
|
4484
|
+
function printMountStartSummary(config, pid, mode) {
|
|
4485
|
+
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`));
|
|
4490
|
+
console.log();
|
|
4491
|
+
console.log(
|
|
4492
|
+
chalk9.dim(
|
|
4493
|
+
mode === "background" ? " Use `computer mount status` to inspect sync state." : " Press Ctrl-C to stop syncing."
|
|
4494
|
+
)
|
|
4495
|
+
);
|
|
4496
|
+
console.log();
|
|
4497
|
+
}
|
|
4498
|
+
function processExists2(pid) {
|
|
4499
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
4500
|
+
return false;
|
|
4501
|
+
}
|
|
4502
|
+
try {
|
|
4503
|
+
process.kill(pid, 0);
|
|
4504
|
+
return true;
|
|
4505
|
+
} catch {
|
|
4506
|
+
return false;
|
|
4507
|
+
}
|
|
4508
|
+
}
|
|
4509
|
+
function revealMountRootInFinder(rootPath) {
|
|
4510
|
+
if (process.platform !== "darwin") {
|
|
4511
|
+
return;
|
|
4512
|
+
}
|
|
4513
|
+
const child = spawn4("open", [rootPath], {
|
|
4514
|
+
stdio: "ignore",
|
|
4515
|
+
detached: true
|
|
4516
|
+
});
|
|
4517
|
+
child.on("error", () => {
|
|
4518
|
+
});
|
|
4519
|
+
child.unref();
|
|
4520
|
+
}
|
|
4521
|
+
function formatMountState(state) {
|
|
4522
|
+
switch (state) {
|
|
4523
|
+
case "mounted":
|
|
4524
|
+
return chalk9.green(state);
|
|
4525
|
+
case "reconnecting":
|
|
4526
|
+
return chalk9.cyan(state);
|
|
4527
|
+
case "degraded":
|
|
4528
|
+
case "pending":
|
|
4529
|
+
return chalk9.yellow(state);
|
|
4530
|
+
default:
|
|
4531
|
+
return chalk9.red(state);
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4234
4534
|
|
|
4235
4535
|
// src/commands/logout.ts
|
|
4236
|
-
import { Command as
|
|
4237
|
-
import
|
|
4238
|
-
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(() => {
|
|
4239
4539
|
if (!getStoredAPIKey()) {
|
|
4240
4540
|
console.log();
|
|
4241
|
-
console.log(
|
|
4541
|
+
console.log(chalk10.dim(" Not logged in."));
|
|
4242
4542
|
if (hasEnvAPIKey()) {
|
|
4243
|
-
console.log(
|
|
4543
|
+
console.log(chalk10.dim(" Environment API key is still active in this shell."));
|
|
4244
4544
|
}
|
|
4245
4545
|
console.log();
|
|
4246
4546
|
return;
|
|
4247
4547
|
}
|
|
4248
4548
|
clearAPIKey();
|
|
4249
4549
|
console.log();
|
|
4250
|
-
console.log(
|
|
4550
|
+
console.log(chalk10.green(" Logged out."));
|
|
4251
4551
|
if (hasEnvAPIKey()) {
|
|
4252
|
-
console.log(
|
|
4552
|
+
console.log(chalk10.dim(" Environment API key is still active in this shell."));
|
|
4253
4553
|
}
|
|
4254
4554
|
console.log();
|
|
4255
4555
|
});
|
|
@@ -4257,8 +4557,8 @@ var logoutCommand = new Command11("logout").description("Remove stored API key")
|
|
|
4257
4557
|
// src/commands/upgrade.ts
|
|
4258
4558
|
import { spawnSync } from "child_process";
|
|
4259
4559
|
import { readFileSync as readFileSync2, realpathSync } from "fs";
|
|
4260
|
-
import { Command as
|
|
4261
|
-
import
|
|
4560
|
+
import { Command as Command13 } from "commander";
|
|
4561
|
+
import chalk11 from "chalk";
|
|
4262
4562
|
import ora10 from "ora";
|
|
4263
4563
|
var pkg2 = JSON.parse(
|
|
4264
4564
|
readFileSync2(new URL("../package.json", import.meta.url), "utf8")
|
|
@@ -4373,7 +4673,25 @@ async function getLatestVersion(packageName) {
|
|
|
4373
4673
|
}
|
|
4374
4674
|
return payload.version;
|
|
4375
4675
|
}
|
|
4376
|
-
|
|
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 () => {
|
|
4377
4695
|
const currentVersion = pkg2.version ?? "0.0.0";
|
|
4378
4696
|
const packageName = pkg2.name ?? "aicomputer";
|
|
4379
4697
|
const spinner = ora10("Checking for updates...").start();
|
|
@@ -4406,16 +4724,19 @@ var upgradeCommand = new Command12("upgrade").description("Update the CLI to the
|
|
|
4406
4724
|
spinner.stop();
|
|
4407
4725
|
console.log();
|
|
4408
4726
|
console.log(
|
|
4409
|
-
|
|
4727
|
+
chalk11.dim(` Updating ${chalk11.bold(`v${currentVersion}`)} -> ${chalk11.bold(`v${latestVersion}`)}`)
|
|
4410
4728
|
);
|
|
4411
|
-
console.log(
|
|
4729
|
+
console.log(chalk11.dim(` ${upgrade.label}`));
|
|
4412
4730
|
console.log();
|
|
4413
4731
|
const result = spawnSync(upgrade.command, upgrade.args, {
|
|
4414
4732
|
stdio: "inherit"
|
|
4415
4733
|
});
|
|
4416
4734
|
if (result.status === 0) {
|
|
4735
|
+
if (method !== "nix") {
|
|
4736
|
+
attemptBundledMutagenRefresh(executablePath);
|
|
4737
|
+
}
|
|
4417
4738
|
console.log();
|
|
4418
|
-
console.log(
|
|
4739
|
+
console.log(chalk11.green(` Updated to v${latestVersion}.`));
|
|
4419
4740
|
console.log();
|
|
4420
4741
|
return;
|
|
4421
4742
|
}
|
|
@@ -4423,10 +4744,10 @@ var upgradeCommand = new Command12("upgrade").description("Update the CLI to the
|
|
|
4423
4744
|
});
|
|
4424
4745
|
|
|
4425
4746
|
// src/commands/whoami.ts
|
|
4426
|
-
import { Command as
|
|
4427
|
-
import
|
|
4747
|
+
import { Command as Command14 } from "commander";
|
|
4748
|
+
import chalk12 from "chalk";
|
|
4428
4749
|
import ora11 from "ora";
|
|
4429
|
-
var whoamiCommand = new
|
|
4750
|
+
var whoamiCommand = new Command14("whoami").description("Show current user").option("--json", "Print raw JSON").action(async (options) => {
|
|
4430
4751
|
const spinner = options.json ? null : ora11("Loading user...").start();
|
|
4431
4752
|
try {
|
|
4432
4753
|
const me = await api("/v1/me");
|
|
@@ -4436,14 +4757,14 @@ var whoamiCommand = new Command13("whoami").description("Show current user").opt
|
|
|
4436
4757
|
return;
|
|
4437
4758
|
}
|
|
4438
4759
|
console.log();
|
|
4439
|
-
console.log(` ${
|
|
4760
|
+
console.log(` ${chalk12.bold.white(me.user.display_name || me.user.email)}`);
|
|
4440
4761
|
if (me.user.display_name) {
|
|
4441
|
-
console.log(` ${
|
|
4762
|
+
console.log(` ${chalk12.dim(me.user.email)}`);
|
|
4442
4763
|
}
|
|
4443
4764
|
if (me.api_key.name) {
|
|
4444
|
-
console.log(` ${
|
|
4765
|
+
console.log(` ${chalk12.dim("Key:")} ${me.api_key.name}`);
|
|
4445
4766
|
}
|
|
4446
|
-
console.log(` ${
|
|
4767
|
+
console.log(` ${chalk12.dim("API:")} ${chalk12.dim(getBaseURL())}`);
|
|
4447
4768
|
console.log();
|
|
4448
4769
|
} catch (error) {
|
|
4449
4770
|
if (spinner) {
|
|
@@ -4460,15 +4781,15 @@ var pkg3 = JSON.parse(
|
|
|
4460
4781
|
readFileSync3(new URL("../package.json", import.meta.url), "utf8")
|
|
4461
4782
|
);
|
|
4462
4783
|
var cliName = process.argv[1] ? basename2(process.argv[1]) : "agentcomputer";
|
|
4463
|
-
var program = new
|
|
4784
|
+
var program = new Command15();
|
|
4464
4785
|
function appendTextSection(lines, title, values) {
|
|
4465
4786
|
if (values.length === 0) {
|
|
4466
4787
|
return;
|
|
4467
4788
|
}
|
|
4468
|
-
lines.push(` ${
|
|
4789
|
+
lines.push(` ${chalk13.dim(title)}`);
|
|
4469
4790
|
lines.push("");
|
|
4470
4791
|
for (const value of values) {
|
|
4471
|
-
lines.push(` ${
|
|
4792
|
+
lines.push(` ${chalk13.white(value)}`);
|
|
4472
4793
|
}
|
|
4473
4794
|
lines.push("");
|
|
4474
4795
|
}
|
|
@@ -4477,10 +4798,10 @@ function appendTableSection(lines, title, entries) {
|
|
|
4477
4798
|
return;
|
|
4478
4799
|
}
|
|
4479
4800
|
const width = Math.max(...entries.map((entry) => entry.term.length), 0) + 2;
|
|
4480
|
-
lines.push(` ${
|
|
4801
|
+
lines.push(` ${chalk13.dim(title)}`);
|
|
4481
4802
|
lines.push("");
|
|
4482
4803
|
for (const entry of entries) {
|
|
4483
|
-
lines.push(` ${
|
|
4804
|
+
lines.push(` ${chalk13.white(padEnd(entry.term, width))}${chalk13.dim(entry.desc)}`);
|
|
4484
4805
|
}
|
|
4485
4806
|
lines.push("");
|
|
4486
4807
|
}
|
|
@@ -4506,10 +4827,10 @@ function formatRootHelp(cmd) {
|
|
|
4506
4827
|
["Other", []]
|
|
4507
4828
|
];
|
|
4508
4829
|
const otherGroup = groups.find(([name]) => name === "Other")[1];
|
|
4509
|
-
lines.push(`${
|
|
4830
|
+
lines.push(`${chalk13.bold(cliName)} ${chalk13.dim(`v${version}`)}`);
|
|
4510
4831
|
lines.push("");
|
|
4511
4832
|
if (cmd.description()) {
|
|
4512
|
-
lines.push(` ${
|
|
4833
|
+
lines.push(` ${chalk13.dim(cmd.description())}`);
|
|
4513
4834
|
lines.push("");
|
|
4514
4835
|
}
|
|
4515
4836
|
appendTextSection(lines, "Usage", [`${cliName} <command> [options]`]);
|
|
@@ -4562,10 +4883,10 @@ function formatSubcommandHelp(cmd, helper) {
|
|
|
4562
4883
|
term: helper.optionTerm(option),
|
|
4563
4884
|
desc: helper.optionDescription(option)
|
|
4564
4885
|
}));
|
|
4565
|
-
lines.push(
|
|
4886
|
+
lines.push(chalk13.bold(commandPath(cmd)));
|
|
4566
4887
|
lines.push("");
|
|
4567
4888
|
if (description) {
|
|
4568
|
-
lines.push(` ${
|
|
4889
|
+
lines.push(` ${chalk13.dim(description)}`);
|
|
4569
4890
|
lines.push("");
|
|
4570
4891
|
}
|
|
4571
4892
|
appendTextSection(lines, "Usage", [helper.commandUsage(cmd)]);
|
|
@@ -4591,6 +4912,7 @@ function applyHelpFormatting(cmd) {
|
|
|
4591
4912
|
program.name(cliName).description("Agent Computer CLI").version(pkg3.version ?? "0.0.0").option("-y, --yes", "Skip confirmation prompts");
|
|
4592
4913
|
program.addCommand(loginCommand);
|
|
4593
4914
|
program.addCommand(upgradeCommand);
|
|
4915
|
+
program.addCommand(internalInstallMutagenCommand, { hidden: true });
|
|
4594
4916
|
program.addCommand(logoutCommand);
|
|
4595
4917
|
program.addCommand(whoamiCommand);
|
|
4596
4918
|
program.addCommand(claudeLoginCommand);
|