aicomputer 0.1.17 → 0.1.19
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-5JYMQXKN.js} +70 -280
- package/dist/chunk-GGBVVRLL.js +32 -0
- package/dist/{chunk-OWK5N76S.js → chunk-JMRAYXUO.js} +3 -11
- package/dist/chunk-MDSPJ57B.js +188 -0
- package/dist/chunk-NN4GECN6.js +354 -0
- package/dist/index.js +342 -142
- 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 +24 -0
- package/dist/lib/mount-reconcile.d.ts +4 -18
- package/dist/lib/mount-reconcile.js +3 -1
- package/dist/lib/mutagen-runtime.d.ts +21 -0
- package/dist/lib/mutagen-runtime.js +20 -0
- package/dist/lib/upgrade-version.d.ts +10 -0
- package/dist/lib/upgrade-version.js +8 -0
- 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,10 @@ import {
|
|
|
33
33
|
timeAgo,
|
|
34
34
|
vncURL,
|
|
35
35
|
webURL
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-5JYMQXKN.js";
|
|
37
|
+
import {
|
|
38
|
+
isAbortError
|
|
39
|
+
} from "./chunk-NN4GECN6.js";
|
|
37
40
|
import {
|
|
38
41
|
defaultMountServiceConfig,
|
|
39
42
|
ensureMountDirectories,
|
|
@@ -46,10 +49,19 @@ import {
|
|
|
46
49
|
writeMountControllerLock,
|
|
47
50
|
writeMountStatusSnapshot
|
|
48
51
|
} from "./chunk-KXLTHWW3.js";
|
|
52
|
+
import {
|
|
53
|
+
AGENTCOMPUTER_MUTAGEN_PATH_ENV,
|
|
54
|
+
ensureBundledMutagenInstalled,
|
|
55
|
+
ensureMutagenCommandPath
|
|
56
|
+
} from "./chunk-MDSPJ57B.js";
|
|
57
|
+
import {
|
|
58
|
+
compareVersions,
|
|
59
|
+
resolveLatestPublishedVersion
|
|
60
|
+
} from "./chunk-GGBVVRLL.js";
|
|
49
61
|
|
|
50
62
|
// src/index.ts
|
|
51
|
-
import { Command as
|
|
52
|
-
import
|
|
63
|
+
import { Command as Command15 } from "commander";
|
|
64
|
+
import chalk13 from "chalk";
|
|
53
65
|
import { readFileSync as readFileSync3 } from "fs";
|
|
54
66
|
import { basename as basename2 } from "path";
|
|
55
67
|
|
|
@@ -3561,9 +3573,35 @@ async function confirmDeletion(sourceID) {
|
|
|
3561
3573
|
});
|
|
3562
3574
|
}
|
|
3563
3575
|
|
|
3564
|
-
// src/commands/
|
|
3576
|
+
// src/commands/internal-install-mutagen.ts
|
|
3565
3577
|
import { Command as Command9 } from "commander";
|
|
3566
3578
|
import chalk7 from "chalk";
|
|
3579
|
+
var internalInstallMutagenCommand = new Command9("internal-install-mutagen").option("--quiet", "Suppress output unless installation fails").action(async (options) => {
|
|
3580
|
+
try {
|
|
3581
|
+
const executablePath = await ensureBundledMutagenInstalled();
|
|
3582
|
+
if (!options.quiet) {
|
|
3583
|
+
console.log();
|
|
3584
|
+
console.log(
|
|
3585
|
+
chalk7.green(
|
|
3586
|
+
` Bundled Mutagen ready at ${executablePath}.`
|
|
3587
|
+
)
|
|
3588
|
+
);
|
|
3589
|
+
console.log();
|
|
3590
|
+
}
|
|
3591
|
+
} catch (error) {
|
|
3592
|
+
if (!options.quiet) {
|
|
3593
|
+
const message = error instanceof Error ? error.message : "failed to install bundled Mutagen";
|
|
3594
|
+
console.error();
|
|
3595
|
+
console.error(chalk7.red(` ${message}`));
|
|
3596
|
+
console.error();
|
|
3597
|
+
}
|
|
3598
|
+
process.exit(1);
|
|
3599
|
+
}
|
|
3600
|
+
});
|
|
3601
|
+
|
|
3602
|
+
// src/commands/login.ts
|
|
3603
|
+
import { Command as Command10 } from "commander";
|
|
3604
|
+
import chalk8 from "chalk";
|
|
3567
3605
|
import ora8 from "ora";
|
|
3568
3606
|
|
|
3569
3607
|
// src/lib/browser-login.ts
|
|
@@ -3831,12 +3869,12 @@ function escapeHTML(value) {
|
|
|
3831
3869
|
}
|
|
3832
3870
|
|
|
3833
3871
|
// src/commands/login.ts
|
|
3834
|
-
var loginCommand = new
|
|
3872
|
+
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
3873
|
const existingKey = getStoredAPIKey();
|
|
3836
3874
|
if (existingKey && !options.force) {
|
|
3837
3875
|
console.log();
|
|
3838
3876
|
console.log(
|
|
3839
|
-
|
|
3877
|
+
chalk8.yellow(" Already logged in. Use --force to overwrite.")
|
|
3840
3878
|
);
|
|
3841
3879
|
console.log();
|
|
3842
3880
|
return;
|
|
@@ -3845,8 +3883,8 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3845
3883
|
const apiKey = await resolveAPIKeyInput(options.apiKey, options.stdin);
|
|
3846
3884
|
if (!apiKey && wantsManualLogin) {
|
|
3847
3885
|
console.log();
|
|
3848
|
-
console.log(
|
|
3849
|
-
console.log(
|
|
3886
|
+
console.log(chalk8.dim(" Usage: computer login --api-key <ac_live_...>"));
|
|
3887
|
+
console.log(chalk8.dim(` API: ${getBaseURL()}`));
|
|
3850
3888
|
console.log();
|
|
3851
3889
|
process.exit(1);
|
|
3852
3890
|
}
|
|
@@ -3856,7 +3894,7 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3856
3894
|
}
|
|
3857
3895
|
if (!apiKey.startsWith("ac_live_")) {
|
|
3858
3896
|
console.log();
|
|
3859
|
-
console.log(
|
|
3897
|
+
console.log(chalk8.red(" API key must start with ac_live_"));
|
|
3860
3898
|
console.log();
|
|
3861
3899
|
process.exit(1);
|
|
3862
3900
|
}
|
|
@@ -3864,7 +3902,7 @@ var loginCommand = new Command9("login").description("Authenticate the CLI").opt
|
|
|
3864
3902
|
try {
|
|
3865
3903
|
const me = await apiWithKey(apiKey, "/v1/me");
|
|
3866
3904
|
setAPIKey(apiKey);
|
|
3867
|
-
spinner.succeed(`Logged in as ${
|
|
3905
|
+
spinner.succeed(`Logged in as ${chalk8.bold(me.user.email)}`);
|
|
3868
3906
|
} catch (error) {
|
|
3869
3907
|
spinner.fail(
|
|
3870
3908
|
error instanceof Error ? error.message : "Failed to validate API key"
|
|
@@ -3884,15 +3922,15 @@ async function runBrowserLogin() {
|
|
|
3884
3922
|
spinner.stop();
|
|
3885
3923
|
console.log();
|
|
3886
3924
|
console.log(
|
|
3887
|
-
|
|
3925
|
+
chalk8.yellow(" Browser auto-open failed. Open this URL to continue:")
|
|
3888
3926
|
);
|
|
3889
|
-
console.log(
|
|
3927
|
+
console.log(chalk8.dim(` ${attempt.loginURL}`));
|
|
3890
3928
|
console.log();
|
|
3891
3929
|
spinner.start("Waiting for browser login...");
|
|
3892
3930
|
}
|
|
3893
3931
|
spinner.text = "Waiting for browser login...";
|
|
3894
3932
|
const result = await attempt.waitForResult();
|
|
3895
|
-
spinner.succeed(`Logged in as ${
|
|
3933
|
+
spinner.succeed(`Logged in as ${chalk8.bold(result.me.user.email)}`);
|
|
3896
3934
|
await continueFirstLoginFlow(result);
|
|
3897
3935
|
} catch (error) {
|
|
3898
3936
|
spinner.fail(
|
|
@@ -3926,8 +3964,8 @@ async function continueFirstLoginFlow(result) {
|
|
|
3926
3964
|
}
|
|
3927
3965
|
console.log();
|
|
3928
3966
|
console.log(
|
|
3929
|
-
|
|
3930
|
-
`Continuing first-time setup for ${
|
|
3967
|
+
chalk8.cyan(
|
|
3968
|
+
`Continuing first-time setup for ${chalk8.bold(machineHandle)}...
|
|
3931
3969
|
`
|
|
3932
3970
|
)
|
|
3933
3971
|
);
|
|
@@ -3940,8 +3978,8 @@ async function continueFirstLoginFlow(result) {
|
|
|
3940
3978
|
const spinner = ora8(`Preparing SSH access for ${machineHandle}...`).start();
|
|
3941
3979
|
try {
|
|
3942
3980
|
const connection = await prepareSSHConnectionByIdentifier(machineHandle);
|
|
3943
|
-
spinner.succeed(`Connecting to ${
|
|
3944
|
-
console.log(
|
|
3981
|
+
spinner.succeed(`Connecting to ${chalk8.bold(machineHandle)}`);
|
|
3982
|
+
console.log(chalk8.dim(` ${connection.command}`));
|
|
3945
3983
|
console.log();
|
|
3946
3984
|
await openSSHConnection(connection);
|
|
3947
3985
|
} catch (error) {
|
|
@@ -3952,19 +3990,19 @@ async function continueFirstLoginFlow(result) {
|
|
|
3952
3990
|
}
|
|
3953
3991
|
} catch (error) {
|
|
3954
3992
|
const message = error instanceof Error ? error.message : "Failed to finish first-time setup";
|
|
3955
|
-
console.error(
|
|
3993
|
+
console.error(chalk8.red(`
|
|
3956
3994
|
${message}`));
|
|
3957
3995
|
console.log();
|
|
3958
3996
|
if (result.provider === "claude") {
|
|
3959
3997
|
console.log(
|
|
3960
|
-
|
|
3998
|
+
chalk8.dim(` computer claude-login --machine ${machineHandle}`)
|
|
3961
3999
|
);
|
|
3962
4000
|
} else if (result.provider === "codex") {
|
|
3963
4001
|
console.log(
|
|
3964
|
-
|
|
4002
|
+
chalk8.dim(` computer codex-login --machine ${machineHandle}`)
|
|
3965
4003
|
);
|
|
3966
4004
|
}
|
|
3967
|
-
console.log(
|
|
4005
|
+
console.log(chalk8.dim(` computer ssh ${machineHandle}`));
|
|
3968
4006
|
console.log();
|
|
3969
4007
|
process.exit(1);
|
|
3970
4008
|
}
|
|
@@ -3978,19 +4016,19 @@ async function runSelectedProvider(provider, machineHandle) {
|
|
|
3978
4016
|
await runCodexLogin({ machine: machineHandle });
|
|
3979
4017
|
return;
|
|
3980
4018
|
}
|
|
3981
|
-
console.log(
|
|
4019
|
+
console.log(chalk8.green(`Sandbox ${chalk8.bold(machineHandle)} is ready.`));
|
|
3982
4020
|
console.log();
|
|
3983
4021
|
}
|
|
3984
4022
|
function printNextStep(machineHandle) {
|
|
3985
|
-
console.log(
|
|
3986
|
-
console.log(
|
|
4023
|
+
console.log(chalk8.green(`Sandbox ${chalk8.bold(machineHandle)} is ready.`));
|
|
4024
|
+
console.log(chalk8.dim(` computer ssh ${machineHandle}`));
|
|
3987
4025
|
console.log();
|
|
3988
4026
|
}
|
|
3989
4027
|
|
|
3990
4028
|
// src/commands/mount.ts
|
|
3991
4029
|
import { spawn as spawn4 } from "child_process";
|
|
3992
|
-
import { Command as
|
|
3993
|
-
import
|
|
4030
|
+
import { Command as Command11, Option } from "commander";
|
|
4031
|
+
import chalk9 from "chalk";
|
|
3994
4032
|
import ora9 from "ora";
|
|
3995
4033
|
|
|
3996
4034
|
// src/lib/mount-daemon.ts
|
|
@@ -4007,7 +4045,7 @@ function getMountControllerState(rootPath = defaultMountServiceConfig().rootPath
|
|
|
4007
4045
|
return { running: true, pid: lock.pid };
|
|
4008
4046
|
}
|
|
4009
4047
|
async function runMountDaemon(config, options = {}) {
|
|
4010
|
-
const { onStarted } = options;
|
|
4048
|
+
const { onReady, onStarted } = options;
|
|
4011
4049
|
const paths = getMountPaths(config.rootPath);
|
|
4012
4050
|
ensureMountDirectories(paths);
|
|
4013
4051
|
await mkdir3(paths.rootPath, { recursive: true });
|
|
@@ -4017,16 +4055,35 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4017
4055
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4018
4056
|
controllerPid: process.pid,
|
|
4019
4057
|
running: true,
|
|
4058
|
+
startupPhase: "starting",
|
|
4059
|
+
startupMessage: "Starting mount controller...",
|
|
4020
4060
|
mounts: []
|
|
4021
4061
|
},
|
|
4022
4062
|
config.rootPath
|
|
4023
4063
|
);
|
|
4024
4064
|
onStarted?.();
|
|
4065
|
+
writeMountStatusSnapshot(
|
|
4066
|
+
{
|
|
4067
|
+
...readMountStatusSnapshot(config.rootPath) ?? {
|
|
4068
|
+
controllerPid: process.pid,
|
|
4069
|
+
running: true,
|
|
4070
|
+
mounts: []
|
|
4071
|
+
},
|
|
4072
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4073
|
+
controllerPid: process.pid,
|
|
4074
|
+
running: true,
|
|
4075
|
+
startupPhase: "cleaning",
|
|
4076
|
+
startupMessage: "Cleaning stale mount state..."
|
|
4077
|
+
},
|
|
4078
|
+
config.rootPath
|
|
4079
|
+
);
|
|
4025
4080
|
await teardownManagedSessions(config, paths);
|
|
4081
|
+
await mkdir3(paths.rootPath, { recursive: true });
|
|
4026
4082
|
let running = false;
|
|
4027
4083
|
let queued = false;
|
|
4028
4084
|
let shuttingDown = false;
|
|
4029
4085
|
let activeRun = null;
|
|
4086
|
+
let activeRunController = null;
|
|
4030
4087
|
const runOnce = async () => {
|
|
4031
4088
|
if (shuttingDown) {
|
|
4032
4089
|
return;
|
|
@@ -4035,12 +4092,19 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4035
4092
|
queued = true;
|
|
4036
4093
|
return activeRun ?? void 0;
|
|
4037
4094
|
}
|
|
4095
|
+
const controller = new AbortController();
|
|
4096
|
+
activeRunController = controller;
|
|
4038
4097
|
activeRun = (async () => {
|
|
4039
4098
|
running = true;
|
|
4040
4099
|
try {
|
|
4041
|
-
await reconcileMounts(
|
|
4100
|
+
await reconcileMounts(
|
|
4101
|
+
config,
|
|
4102
|
+
paths,
|
|
4103
|
+
process.pid,
|
|
4104
|
+
controller.signal
|
|
4105
|
+
);
|
|
4042
4106
|
} catch (error) {
|
|
4043
|
-
if (shuttingDown) {
|
|
4107
|
+
if (shuttingDown && isAbortError(error)) {
|
|
4044
4108
|
return;
|
|
4045
4109
|
}
|
|
4046
4110
|
const previous = readMountStatusSnapshot(config.rootPath);
|
|
@@ -4049,6 +4113,8 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4049
4113
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4050
4114
|
controllerPid: process.pid,
|
|
4051
4115
|
running: true,
|
|
4116
|
+
startupPhase: previous?.startupPhase === "ready" ? "ready" : "syncing",
|
|
4117
|
+
startupMessage: previous?.startupPhase === "ready" ? void 0 : "Waiting for initial sync...",
|
|
4052
4118
|
lastHealthySyncAt: previous?.lastHealthySyncAt,
|
|
4053
4119
|
lastSuccessfulSyncAt: previous?.lastSuccessfulSyncAt,
|
|
4054
4120
|
lastIssueAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4064,6 +4130,7 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4064
4130
|
} finally {
|
|
4065
4131
|
running = false;
|
|
4066
4132
|
activeRun = null;
|
|
4133
|
+
activeRunController = null;
|
|
4067
4134
|
if (queued && !shuttingDown) {
|
|
4068
4135
|
queued = false;
|
|
4069
4136
|
void runOnce();
|
|
@@ -4079,6 +4146,21 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4079
4146
|
server.once("error", reject);
|
|
4080
4147
|
server.listen(paths.socketPath, () => resolve());
|
|
4081
4148
|
});
|
|
4149
|
+
writeMountStatusSnapshot(
|
|
4150
|
+
{
|
|
4151
|
+
...readMountStatusSnapshot(config.rootPath) ?? {
|
|
4152
|
+
controllerPid: process.pid,
|
|
4153
|
+
running: true,
|
|
4154
|
+
mounts: []
|
|
4155
|
+
},
|
|
4156
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4157
|
+
controllerPid: process.pid,
|
|
4158
|
+
running: true,
|
|
4159
|
+
startupPhase: "syncing",
|
|
4160
|
+
startupMessage: "Waiting for initial sync..."
|
|
4161
|
+
},
|
|
4162
|
+
config.rootPath
|
|
4163
|
+
);
|
|
4082
4164
|
const interval = setInterval(() => {
|
|
4083
4165
|
void runOnce();
|
|
4084
4166
|
}, config.pollIntervalMs);
|
|
@@ -4089,6 +4171,7 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4089
4171
|
shuttingDown = true;
|
|
4090
4172
|
clearInterval(interval);
|
|
4091
4173
|
server.close();
|
|
4174
|
+
activeRunController?.abort();
|
|
4092
4175
|
if (activeRun) {
|
|
4093
4176
|
await activeRun.catch(() => {
|
|
4094
4177
|
});
|
|
@@ -4100,6 +4183,8 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4100
4183
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4101
4184
|
controllerPid: previous?.controllerPid,
|
|
4102
4185
|
running: false,
|
|
4186
|
+
startupPhase: void 0,
|
|
4187
|
+
startupMessage: void 0,
|
|
4103
4188
|
lastHealthySyncAt: previous?.lastHealthySyncAt,
|
|
4104
4189
|
lastSuccessfulSyncAt: previous?.lastSuccessfulSyncAt,
|
|
4105
4190
|
lastIssueAt: previous?.lastIssueAt,
|
|
@@ -4119,6 +4204,8 @@ async function runMountDaemon(config, options = {}) {
|
|
|
4119
4204
|
void shutdown();
|
|
4120
4205
|
});
|
|
4121
4206
|
await runOnce();
|
|
4207
|
+
writeMountStatusSnapshot(markMountStartupReady(readMountStatusSnapshot(config.rootPath), process.pid), config.rootPath);
|
|
4208
|
+
onReady?.();
|
|
4122
4209
|
await new Promise(() => {
|
|
4123
4210
|
});
|
|
4124
4211
|
}
|
|
@@ -4147,41 +4234,69 @@ function processExists(pid) {
|
|
|
4147
4234
|
return false;
|
|
4148
4235
|
}
|
|
4149
4236
|
}
|
|
4237
|
+
function markMountStartupReady(snapshot, controllerPid) {
|
|
4238
|
+
return {
|
|
4239
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4240
|
+
controllerPid,
|
|
4241
|
+
running: true,
|
|
4242
|
+
startupPhase: "ready",
|
|
4243
|
+
startupMessage: void 0,
|
|
4244
|
+
lastHealthySyncAt: snapshot?.lastHealthySyncAt,
|
|
4245
|
+
lastSuccessfulSyncAt: snapshot?.lastSuccessfulSyncAt,
|
|
4246
|
+
lastIssueAt: snapshot?.lastIssueAt,
|
|
4247
|
+
lastIssue: snapshot?.lastIssue,
|
|
4248
|
+
lastError: snapshot?.lastError,
|
|
4249
|
+
mounts: snapshot?.mounts ?? []
|
|
4250
|
+
};
|
|
4251
|
+
}
|
|
4150
4252
|
|
|
4151
4253
|
// src/commands/mount.ts
|
|
4152
|
-
var
|
|
4254
|
+
var MOUNT_START_SPINNER = {
|
|
4255
|
+
interval: 90,
|
|
4256
|
+
frames: ["\u25F0", "\u25F3", "\u25F2", "\u25F1"]
|
|
4257
|
+
};
|
|
4258
|
+
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
4259
|
"--background",
|
|
4154
4260
|
"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
|
-
|
|
4261
|
+
).addOption(new Option("--daemonized").hideHelp()).addOption(new Option("--open-root-when-ready").hideHelp()).action(async (options) => {
|
|
4262
|
+
const spinner = ora9({
|
|
4263
|
+
spinner: MOUNT_START_SPINNER,
|
|
4264
|
+
text: options.background ? "Starting machine mount controller in background..." : "Starting machine mount controller..."
|
|
4265
|
+
}).start();
|
|
4159
4266
|
try {
|
|
4160
4267
|
if (options.daemonized) {
|
|
4161
|
-
const
|
|
4162
|
-
await runMountDaemon(
|
|
4268
|
+
const config = readMountConfig() ?? defaultMountServiceConfig();
|
|
4269
|
+
await runMountDaemon(config, {
|
|
4163
4270
|
onStarted: () => {
|
|
4164
4271
|
spinner.succeed("Machine mount controller running");
|
|
4165
|
-
printMountStartSummary(
|
|
4272
|
+
printMountStartSummary(config, process.pid, "foreground");
|
|
4273
|
+
},
|
|
4274
|
+
onReady: () => {
|
|
4275
|
+
if (options.openRootWhenReady) {
|
|
4276
|
+
revealMountRootInFinder(config.rootPath);
|
|
4277
|
+
}
|
|
4166
4278
|
}
|
|
4167
4279
|
});
|
|
4168
4280
|
return;
|
|
4169
4281
|
}
|
|
4170
|
-
const
|
|
4171
|
-
writeMountConfig(config);
|
|
4282
|
+
const resolved = await resolveMountServiceConfig(options);
|
|
4283
|
+
writeMountConfig(resolved.config);
|
|
4284
|
+
process.env[AGENTCOMPUTER_MUTAGEN_PATH_ENV] = resolved.mutagenPath;
|
|
4172
4285
|
if (options.background) {
|
|
4173
|
-
const pid = await startMountControllerInBackground(config.rootPath);
|
|
4286
|
+
const pid = await startMountControllerInBackground(resolved.config.rootPath);
|
|
4174
4287
|
spinner.succeed("Machine mount controller running in background");
|
|
4175
|
-
printMountStartSummary(config, pid, "background");
|
|
4288
|
+
printMountStartSummary(resolved.config, pid, "background");
|
|
4176
4289
|
return;
|
|
4177
4290
|
}
|
|
4178
|
-
await
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4291
|
+
const child = await startMountControllerInForeground(resolved.config.rootPath);
|
|
4292
|
+
await waitForMountControllerReady(resolved.config.rootPath, child.pid, spinner);
|
|
4293
|
+
spinner.succeed("Machine mount controller running");
|
|
4294
|
+
printMountStartSummary(
|
|
4295
|
+
resolved.config,
|
|
4296
|
+
child.pid ?? process.pid,
|
|
4297
|
+
"foreground"
|
|
4298
|
+
);
|
|
4299
|
+
await superviseForegroundMountController(child);
|
|
4185
4300
|
} catch (error) {
|
|
4186
4301
|
spinner.fail(
|
|
4187
4302
|
error instanceof Error ? error.message : "Failed to start machine mount controller"
|
|
@@ -4189,40 +4304,40 @@ var mountCommand = new Command10("mount").description("Mirror SSH-ready machines
|
|
|
4189
4304
|
process.exit(1);
|
|
4190
4305
|
}
|
|
4191
4306
|
}).addCommand(
|
|
4192
|
-
new
|
|
4307
|
+
new Command11("status").description("Show machine mount controller status").action(() => {
|
|
4193
4308
|
const config = readMountConfig() ?? defaultMountServiceConfig();
|
|
4194
4309
|
const controller = getMountControllerState(config.rootPath);
|
|
4195
4310
|
const snapshot = readMountStatusSnapshot(config.rootPath);
|
|
4196
4311
|
console.log();
|
|
4197
|
-
console.log(` ${
|
|
4312
|
+
console.log(` ${chalk9.bold("Machine Mounts")}`);
|
|
4198
4313
|
console.log();
|
|
4199
4314
|
console.log(
|
|
4200
|
-
` ${
|
|
4315
|
+
` ${chalk9.dim("Running")} ${controller.running ? chalk9.green("yes") : chalk9.dim("no")}`
|
|
4201
4316
|
);
|
|
4202
4317
|
if (controller.pid) {
|
|
4203
|
-
console.log(` ${
|
|
4318
|
+
console.log(` ${chalk9.dim("PID")} ${controller.pid}`);
|
|
4204
4319
|
}
|
|
4205
|
-
console.log(` ${
|
|
4206
|
-
console.log(` ${
|
|
4320
|
+
console.log(` ${chalk9.dim("Root")} ${config.rootPath}`);
|
|
4321
|
+
console.log(` ${chalk9.dim("Alias")} ${config.alias}`);
|
|
4207
4322
|
console.log(
|
|
4208
|
-
` ${
|
|
4323
|
+
` ${chalk9.dim("Updated")} ${snapshot?.updatedAt ? timeAgo(snapshot.updatedAt) : chalk9.dim("never")}`
|
|
4209
4324
|
);
|
|
4210
4325
|
console.log(
|
|
4211
|
-
` ${
|
|
4326
|
+
` ${chalk9.dim("Healthy")} ${snapshot?.lastHealthySyncAt ? timeAgo(snapshot.lastHealthySyncAt) : chalk9.dim("never")}`
|
|
4212
4327
|
);
|
|
4213
4328
|
if (controller.running && snapshot?.mounts.length) {
|
|
4214
4329
|
console.log();
|
|
4215
4330
|
for (const mount of snapshot.mounts) {
|
|
4216
4331
|
const state = formatMountState(mount.state);
|
|
4217
|
-
console.log(` ${
|
|
4332
|
+
console.log(` ${chalk9.white(mount.handle)} ${state} ${chalk9.dim(mount.mountPath)}`);
|
|
4218
4333
|
if (mount.message) {
|
|
4219
|
-
console.log(` ${
|
|
4334
|
+
console.log(` ${chalk9.dim(mount.message)}`);
|
|
4220
4335
|
}
|
|
4221
4336
|
}
|
|
4222
4337
|
}
|
|
4223
4338
|
if (snapshot?.lastIssue) {
|
|
4224
4339
|
console.log();
|
|
4225
|
-
console.log(` ${
|
|
4340
|
+
console.log(` ${chalk9.dim("Last issue")} ${chalk9.yellow(snapshot.lastIssue)}`);
|
|
4226
4341
|
}
|
|
4227
4342
|
console.log();
|
|
4228
4343
|
})
|
|
@@ -4244,20 +4359,35 @@ async function resolveMountServiceConfig(options) {
|
|
|
4244
4359
|
].join("\n")
|
|
4245
4360
|
);
|
|
4246
4361
|
}
|
|
4362
|
+
const mutagenPath = await ensureMutagenCommandPath();
|
|
4247
4363
|
const sshSetup = await ensureSSHAccessConfigured(options);
|
|
4248
4364
|
return {
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4365
|
+
config: {
|
|
4366
|
+
...defaultMountServiceConfig(),
|
|
4367
|
+
alias: sshSetup.alias,
|
|
4368
|
+
host: sshSetup.host,
|
|
4369
|
+
port: sshSetup.port,
|
|
4370
|
+
pollIntervalMs: parsePositiveInt(options.pollInterval, "poll interval"),
|
|
4371
|
+
connectTimeoutSeconds: parsePositiveInt(
|
|
4372
|
+
options.connectTimeout,
|
|
4373
|
+
"connect timeout"
|
|
4374
|
+
)
|
|
4375
|
+
},
|
|
4376
|
+
mutagenPath
|
|
4258
4377
|
};
|
|
4259
4378
|
}
|
|
4260
4379
|
async function startMountControllerInBackground(rootPath) {
|
|
4380
|
+
const child = startMountControllerProcess(rootPath, true, false);
|
|
4381
|
+
child.unref();
|
|
4382
|
+
await waitForMountControllerRunning(rootPath, child.pid);
|
|
4383
|
+
return child.pid;
|
|
4384
|
+
}
|
|
4385
|
+
async function startMountControllerInForeground(rootPath) {
|
|
4386
|
+
const child = startMountControllerProcess(rootPath, false, true);
|
|
4387
|
+
await waitForMountControllerRunning(rootPath, child.pid);
|
|
4388
|
+
return child;
|
|
4389
|
+
}
|
|
4390
|
+
function startMountControllerProcess(rootPath, detached, openRootWhenReady) {
|
|
4261
4391
|
const controller = getMountControllerState(rootPath);
|
|
4262
4392
|
if (controller.running) {
|
|
4263
4393
|
throw new Error(`computer mount is already running (pid ${controller.pid})`);
|
|
@@ -4266,20 +4396,22 @@ async function startMountControllerInBackground(rootPath) {
|
|
|
4266
4396
|
if (!entrypoint) {
|
|
4267
4397
|
throw new Error("unable to determine CLI entrypoint for background mount");
|
|
4268
4398
|
}
|
|
4269
|
-
const
|
|
4399
|
+
const args = ["mount", "--daemonized"];
|
|
4400
|
+
if (openRootWhenReady) {
|
|
4401
|
+
args.push("--open-root-when-ready");
|
|
4402
|
+
}
|
|
4403
|
+
const child = spawn4(process.execPath, [entrypoint, ...args], {
|
|
4270
4404
|
cwd: process.cwd(),
|
|
4271
|
-
detached
|
|
4405
|
+
detached,
|
|
4272
4406
|
env: process.env,
|
|
4273
4407
|
stdio: "ignore"
|
|
4274
4408
|
});
|
|
4275
4409
|
if (!child.pid) {
|
|
4276
|
-
throw new Error("failed to start machine mount controller
|
|
4410
|
+
throw new Error("failed to start machine mount controller");
|
|
4277
4411
|
}
|
|
4278
|
-
child
|
|
4279
|
-
await waitForBackgroundMountController(rootPath, child.pid);
|
|
4280
|
-
return child.pid;
|
|
4412
|
+
return child;
|
|
4281
4413
|
}
|
|
4282
|
-
async function
|
|
4414
|
+
async function waitForMountControllerRunning(rootPath, pid) {
|
|
4283
4415
|
const deadline = Date.now() + 3e3;
|
|
4284
4416
|
while (Date.now() < deadline) {
|
|
4285
4417
|
const controller = getMountControllerState(rootPath);
|
|
@@ -4293,15 +4425,77 @@ async function waitForBackgroundMountController(rootPath, pid) {
|
|
|
4293
4425
|
}
|
|
4294
4426
|
throw new Error("failed to start machine mount controller in background");
|
|
4295
4427
|
}
|
|
4428
|
+
async function waitForMountControllerReady(rootPath, pid, spinner) {
|
|
4429
|
+
const deadline = Date.now() + 12e4;
|
|
4430
|
+
while (Date.now() < deadline) {
|
|
4431
|
+
const controller = getMountControllerState(rootPath);
|
|
4432
|
+
const snapshot = readMountStatusSnapshot(rootPath);
|
|
4433
|
+
if (snapshot?.controllerPid === pid && snapshot.startupMessage) {
|
|
4434
|
+
spinner.text = snapshot.startupMessage;
|
|
4435
|
+
}
|
|
4436
|
+
if (snapshot?.controllerPid === pid && snapshot.startupPhase === "ready") {
|
|
4437
|
+
return;
|
|
4438
|
+
}
|
|
4439
|
+
if (!controller.running && !processExists2(pid)) {
|
|
4440
|
+
break;
|
|
4441
|
+
}
|
|
4442
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4443
|
+
}
|
|
4444
|
+
throw new Error("mount controller did not finish startup");
|
|
4445
|
+
}
|
|
4446
|
+
async function superviseForegroundMountController(child) {
|
|
4447
|
+
await new Promise((resolve, reject) => {
|
|
4448
|
+
const cleanup = () => {
|
|
4449
|
+
process.off("SIGINT", onSigint);
|
|
4450
|
+
process.off("SIGTERM", onSigterm);
|
|
4451
|
+
child.off("error", onError);
|
|
4452
|
+
child.off("exit", onExit);
|
|
4453
|
+
};
|
|
4454
|
+
const stopAndExit = (signal) => {
|
|
4455
|
+
cleanup();
|
|
4456
|
+
try {
|
|
4457
|
+
child.kill(signal);
|
|
4458
|
+
} catch {
|
|
4459
|
+
}
|
|
4460
|
+
process.exit(0);
|
|
4461
|
+
};
|
|
4462
|
+
const onSigint = () => {
|
|
4463
|
+
stopAndExit("SIGINT");
|
|
4464
|
+
};
|
|
4465
|
+
const onSigterm = () => {
|
|
4466
|
+
stopAndExit("SIGTERM");
|
|
4467
|
+
};
|
|
4468
|
+
const onError = (error) => {
|
|
4469
|
+
cleanup();
|
|
4470
|
+
reject(error);
|
|
4471
|
+
};
|
|
4472
|
+
const onExit = (code, signal) => {
|
|
4473
|
+
cleanup();
|
|
4474
|
+
if (code === 0) {
|
|
4475
|
+
resolve();
|
|
4476
|
+
return;
|
|
4477
|
+
}
|
|
4478
|
+
reject(
|
|
4479
|
+
new Error(
|
|
4480
|
+
signal ? `machine mount controller exited from ${signal}` : `machine mount controller exited with code ${code ?? "unknown"}`
|
|
4481
|
+
)
|
|
4482
|
+
);
|
|
4483
|
+
};
|
|
4484
|
+
process.once("SIGINT", onSigint);
|
|
4485
|
+
process.once("SIGTERM", onSigterm);
|
|
4486
|
+
child.once("error", onError);
|
|
4487
|
+
child.once("exit", onExit);
|
|
4488
|
+
});
|
|
4489
|
+
}
|
|
4296
4490
|
function printMountStartSummary(config, pid, mode) {
|
|
4297
4491
|
console.log();
|
|
4298
|
-
console.log(
|
|
4299
|
-
console.log(
|
|
4300
|
-
console.log(
|
|
4301
|
-
console.log(
|
|
4492
|
+
console.log(chalk9.dim(` PID: ${pid}`));
|
|
4493
|
+
console.log(chalk9.dim(` Root: ${config.rootPath}`));
|
|
4494
|
+
console.log(chalk9.dim(` SSH alias: ${config.alias}`));
|
|
4495
|
+
console.log(chalk9.dim(` Poll: ${config.pollIntervalMs}ms`));
|
|
4302
4496
|
console.log();
|
|
4303
4497
|
console.log(
|
|
4304
|
-
|
|
4498
|
+
chalk9.dim(
|
|
4305
4499
|
mode === "background" ? " Use `computer mount status` to inspect sync state." : " Press Ctrl-C to stop syncing."
|
|
4306
4500
|
)
|
|
4307
4501
|
);
|
|
@@ -4333,35 +4527,35 @@ function revealMountRootInFinder(rootPath) {
|
|
|
4333
4527
|
function formatMountState(state) {
|
|
4334
4528
|
switch (state) {
|
|
4335
4529
|
case "mounted":
|
|
4336
|
-
return
|
|
4530
|
+
return chalk9.green(state);
|
|
4337
4531
|
case "reconnecting":
|
|
4338
|
-
return
|
|
4532
|
+
return chalk9.cyan(state);
|
|
4339
4533
|
case "degraded":
|
|
4340
4534
|
case "pending":
|
|
4341
|
-
return
|
|
4535
|
+
return chalk9.yellow(state);
|
|
4342
4536
|
default:
|
|
4343
|
-
return
|
|
4537
|
+
return chalk9.red(state);
|
|
4344
4538
|
}
|
|
4345
4539
|
}
|
|
4346
4540
|
|
|
4347
4541
|
// src/commands/logout.ts
|
|
4348
|
-
import { Command as
|
|
4349
|
-
import
|
|
4350
|
-
var logoutCommand = new
|
|
4542
|
+
import { Command as Command12 } from "commander";
|
|
4543
|
+
import chalk10 from "chalk";
|
|
4544
|
+
var logoutCommand = new Command12("logout").description("Remove stored API key").action(() => {
|
|
4351
4545
|
if (!getStoredAPIKey()) {
|
|
4352
4546
|
console.log();
|
|
4353
|
-
console.log(
|
|
4547
|
+
console.log(chalk10.dim(" Not logged in."));
|
|
4354
4548
|
if (hasEnvAPIKey()) {
|
|
4355
|
-
console.log(
|
|
4549
|
+
console.log(chalk10.dim(" Environment API key is still active in this shell."));
|
|
4356
4550
|
}
|
|
4357
4551
|
console.log();
|
|
4358
4552
|
return;
|
|
4359
4553
|
}
|
|
4360
4554
|
clearAPIKey();
|
|
4361
4555
|
console.log();
|
|
4362
|
-
console.log(
|
|
4556
|
+
console.log(chalk10.green(" Logged out."));
|
|
4363
4557
|
if (hasEnvAPIKey()) {
|
|
4364
|
-
console.log(
|
|
4558
|
+
console.log(chalk10.dim(" Environment API key is still active in this shell."));
|
|
4365
4559
|
}
|
|
4366
4560
|
console.log();
|
|
4367
4561
|
});
|
|
@@ -4369,27 +4563,12 @@ var logoutCommand = new Command11("logout").description("Remove stored API key")
|
|
|
4369
4563
|
// src/commands/upgrade.ts
|
|
4370
4564
|
import { spawnSync } from "child_process";
|
|
4371
4565
|
import { readFileSync as readFileSync2, realpathSync } from "fs";
|
|
4372
|
-
import { Command as
|
|
4373
|
-
import
|
|
4566
|
+
import { Command as Command13 } from "commander";
|
|
4567
|
+
import chalk11 from "chalk";
|
|
4374
4568
|
import ora10 from "ora";
|
|
4375
4569
|
var pkg2 = JSON.parse(
|
|
4376
4570
|
readFileSync2(new URL("../package.json", import.meta.url), "utf8")
|
|
4377
4571
|
);
|
|
4378
|
-
function normalizeVersion(version) {
|
|
4379
|
-
return version.split("-")[0].split(".").map((part) => Number.parseInt(part, 10)).map((part) => Number.isNaN(part) ? 0 : part);
|
|
4380
|
-
}
|
|
4381
|
-
function compareVersions(a, b) {
|
|
4382
|
-
const left = normalizeVersion(a);
|
|
4383
|
-
const right = normalizeVersion(b);
|
|
4384
|
-
const size = Math.max(left.length, right.length);
|
|
4385
|
-
for (let index = 0; index < size; index += 1) {
|
|
4386
|
-
const diff = (left[index] ?? 0) - (right[index] ?? 0);
|
|
4387
|
-
if (diff !== 0) {
|
|
4388
|
-
return diff;
|
|
4389
|
-
}
|
|
4390
|
-
}
|
|
4391
|
-
return 0;
|
|
4392
|
-
}
|
|
4393
4572
|
function resolveExecutablePath() {
|
|
4394
4573
|
const candidate = process.argv[1] || process.execPath;
|
|
4395
4574
|
try {
|
|
@@ -4437,8 +4616,9 @@ function findNixProfileElement(executablePath) {
|
|
|
4437
4616
|
}
|
|
4438
4617
|
return null;
|
|
4439
4618
|
}
|
|
4440
|
-
function resolveUpgradeCommand(method, executablePath) {
|
|
4619
|
+
function resolveUpgradeCommand(method, executablePath, targetVersion) {
|
|
4441
4620
|
const packageName = pkg2.name ?? "aicomputer";
|
|
4621
|
+
const packageSpec = `${packageName}@${targetVersion}`;
|
|
4442
4622
|
switch (method) {
|
|
4443
4623
|
case "nix": {
|
|
4444
4624
|
const element = findNixProfileElement(executablePath);
|
|
@@ -4456,36 +4636,52 @@ function resolveUpgradeCommand(method, executablePath) {
|
|
|
4456
4636
|
case "pnpm":
|
|
4457
4637
|
return {
|
|
4458
4638
|
command: "pnpm",
|
|
4459
|
-
args: ["add", "-g",
|
|
4460
|
-
label: `pnpm add -g ${
|
|
4639
|
+
args: ["add", "-g", packageSpec],
|
|
4640
|
+
label: `pnpm add -g ${packageSpec}`
|
|
4461
4641
|
};
|
|
4462
4642
|
case "yarn":
|
|
4463
4643
|
return {
|
|
4464
4644
|
command: "yarn",
|
|
4465
|
-
args: ["global", "add",
|
|
4466
|
-
label: `yarn global add ${
|
|
4645
|
+
args: ["global", "add", packageSpec],
|
|
4646
|
+
label: `yarn global add ${packageSpec}`
|
|
4467
4647
|
};
|
|
4468
4648
|
case "npm":
|
|
4469
4649
|
case "unknown":
|
|
4470
4650
|
return {
|
|
4471
4651
|
command: "npm",
|
|
4472
|
-
args: ["install", "-g",
|
|
4473
|
-
label: `npm install -g ${
|
|
4652
|
+
args: ["install", "-g", packageSpec],
|
|
4653
|
+
label: `npm install -g ${packageSpec}`
|
|
4474
4654
|
};
|
|
4475
4655
|
}
|
|
4476
4656
|
}
|
|
4477
4657
|
async function getLatestVersion(packageName) {
|
|
4478
|
-
const response = await fetch(`https://registry.npmjs.org/${packageName}
|
|
4658
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
|
|
4479
4659
|
if (!response.ok) {
|
|
4480
4660
|
throw new Error(`Failed to check npm registry (${response.status})`);
|
|
4481
4661
|
}
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4662
|
+
return resolveLatestPublishedVersion(
|
|
4663
|
+
await response.json()
|
|
4664
|
+
);
|
|
4665
|
+
}
|
|
4666
|
+
function attemptBundledMutagenRefresh(executablePath) {
|
|
4667
|
+
const install = spawnSync(
|
|
4668
|
+
process.execPath,
|
|
4669
|
+
[executablePath, "internal-install-mutagen", "--quiet"],
|
|
4670
|
+
{
|
|
4671
|
+
stdio: "ignore"
|
|
4672
|
+
}
|
|
4673
|
+
);
|
|
4674
|
+
if (install.status === 0) {
|
|
4675
|
+
return;
|
|
4485
4676
|
}
|
|
4486
|
-
|
|
4677
|
+
console.log();
|
|
4678
|
+
console.log(
|
|
4679
|
+
chalk11.yellow(
|
|
4680
|
+
" CLI updated, but bundled Mutagen did not finish installing. `computer mount` will retry on first use."
|
|
4681
|
+
)
|
|
4682
|
+
);
|
|
4487
4683
|
}
|
|
4488
|
-
var upgradeCommand = new
|
|
4684
|
+
var upgradeCommand = new Command13("upgrade").description("Update the CLI to the latest version").action(async () => {
|
|
4489
4685
|
const currentVersion = pkg2.version ?? "0.0.0";
|
|
4490
4686
|
const packageName = pkg2.name ?? "aicomputer";
|
|
4491
4687
|
const spinner = ora10("Checking for updates...").start();
|
|
@@ -4507,7 +4703,7 @@ var upgradeCommand = new Command12("upgrade").description("Update the CLI to the
|
|
|
4507
4703
|
const method = detectInstallMethod(executablePath);
|
|
4508
4704
|
let upgrade;
|
|
4509
4705
|
try {
|
|
4510
|
-
upgrade = resolveUpgradeCommand(method, executablePath);
|
|
4706
|
+
upgrade = resolveUpgradeCommand(method, executablePath, latestVersion);
|
|
4511
4707
|
} catch (error) {
|
|
4512
4708
|
spinner.fail(
|
|
4513
4709
|
error instanceof Error ? error.message : "Failed to prepare upgrade"
|
|
@@ -4518,16 +4714,19 @@ var upgradeCommand = new Command12("upgrade").description("Update the CLI to the
|
|
|
4518
4714
|
spinner.stop();
|
|
4519
4715
|
console.log();
|
|
4520
4716
|
console.log(
|
|
4521
|
-
|
|
4717
|
+
chalk11.dim(` Updating ${chalk11.bold(`v${currentVersion}`)} -> ${chalk11.bold(`v${latestVersion}`)}`)
|
|
4522
4718
|
);
|
|
4523
|
-
console.log(
|
|
4719
|
+
console.log(chalk11.dim(` ${upgrade.label}`));
|
|
4524
4720
|
console.log();
|
|
4525
4721
|
const result = spawnSync(upgrade.command, upgrade.args, {
|
|
4526
4722
|
stdio: "inherit"
|
|
4527
4723
|
});
|
|
4528
4724
|
if (result.status === 0) {
|
|
4725
|
+
if (method !== "nix") {
|
|
4726
|
+
attemptBundledMutagenRefresh(executablePath);
|
|
4727
|
+
}
|
|
4529
4728
|
console.log();
|
|
4530
|
-
console.log(
|
|
4729
|
+
console.log(chalk11.green(` Updated to v${latestVersion}.`));
|
|
4531
4730
|
console.log();
|
|
4532
4731
|
return;
|
|
4533
4732
|
}
|
|
@@ -4535,10 +4734,10 @@ var upgradeCommand = new Command12("upgrade").description("Update the CLI to the
|
|
|
4535
4734
|
});
|
|
4536
4735
|
|
|
4537
4736
|
// src/commands/whoami.ts
|
|
4538
|
-
import { Command as
|
|
4539
|
-
import
|
|
4737
|
+
import { Command as Command14 } from "commander";
|
|
4738
|
+
import chalk12 from "chalk";
|
|
4540
4739
|
import ora11 from "ora";
|
|
4541
|
-
var whoamiCommand = new
|
|
4740
|
+
var whoamiCommand = new Command14("whoami").description("Show current user").option("--json", "Print raw JSON").action(async (options) => {
|
|
4542
4741
|
const spinner = options.json ? null : ora11("Loading user...").start();
|
|
4543
4742
|
try {
|
|
4544
4743
|
const me = await api("/v1/me");
|
|
@@ -4548,14 +4747,14 @@ var whoamiCommand = new Command13("whoami").description("Show current user").opt
|
|
|
4548
4747
|
return;
|
|
4549
4748
|
}
|
|
4550
4749
|
console.log();
|
|
4551
|
-
console.log(` ${
|
|
4750
|
+
console.log(` ${chalk12.bold.white(me.user.display_name || me.user.email)}`);
|
|
4552
4751
|
if (me.user.display_name) {
|
|
4553
|
-
console.log(` ${
|
|
4752
|
+
console.log(` ${chalk12.dim(me.user.email)}`);
|
|
4554
4753
|
}
|
|
4555
4754
|
if (me.api_key.name) {
|
|
4556
|
-
console.log(` ${
|
|
4755
|
+
console.log(` ${chalk12.dim("Key:")} ${me.api_key.name}`);
|
|
4557
4756
|
}
|
|
4558
|
-
console.log(` ${
|
|
4757
|
+
console.log(` ${chalk12.dim("API:")} ${chalk12.dim(getBaseURL())}`);
|
|
4559
4758
|
console.log();
|
|
4560
4759
|
} catch (error) {
|
|
4561
4760
|
if (spinner) {
|
|
@@ -4572,15 +4771,15 @@ var pkg3 = JSON.parse(
|
|
|
4572
4771
|
readFileSync3(new URL("../package.json", import.meta.url), "utf8")
|
|
4573
4772
|
);
|
|
4574
4773
|
var cliName = process.argv[1] ? basename2(process.argv[1]) : "agentcomputer";
|
|
4575
|
-
var program = new
|
|
4774
|
+
var program = new Command15();
|
|
4576
4775
|
function appendTextSection(lines, title, values) {
|
|
4577
4776
|
if (values.length === 0) {
|
|
4578
4777
|
return;
|
|
4579
4778
|
}
|
|
4580
|
-
lines.push(` ${
|
|
4779
|
+
lines.push(` ${chalk13.dim(title)}`);
|
|
4581
4780
|
lines.push("");
|
|
4582
4781
|
for (const value of values) {
|
|
4583
|
-
lines.push(` ${
|
|
4782
|
+
lines.push(` ${chalk13.white(value)}`);
|
|
4584
4783
|
}
|
|
4585
4784
|
lines.push("");
|
|
4586
4785
|
}
|
|
@@ -4589,10 +4788,10 @@ function appendTableSection(lines, title, entries) {
|
|
|
4589
4788
|
return;
|
|
4590
4789
|
}
|
|
4591
4790
|
const width = Math.max(...entries.map((entry) => entry.term.length), 0) + 2;
|
|
4592
|
-
lines.push(` ${
|
|
4791
|
+
lines.push(` ${chalk13.dim(title)}`);
|
|
4593
4792
|
lines.push("");
|
|
4594
4793
|
for (const entry of entries) {
|
|
4595
|
-
lines.push(` ${
|
|
4794
|
+
lines.push(` ${chalk13.white(padEnd(entry.term, width))}${chalk13.dim(entry.desc)}`);
|
|
4596
4795
|
}
|
|
4597
4796
|
lines.push("");
|
|
4598
4797
|
}
|
|
@@ -4618,10 +4817,10 @@ function formatRootHelp(cmd) {
|
|
|
4618
4817
|
["Other", []]
|
|
4619
4818
|
];
|
|
4620
4819
|
const otherGroup = groups.find(([name]) => name === "Other")[1];
|
|
4621
|
-
lines.push(`${
|
|
4820
|
+
lines.push(`${chalk13.bold(cliName)} ${chalk13.dim(`v${version}`)}`);
|
|
4622
4821
|
lines.push("");
|
|
4623
4822
|
if (cmd.description()) {
|
|
4624
|
-
lines.push(` ${
|
|
4823
|
+
lines.push(` ${chalk13.dim(cmd.description())}`);
|
|
4625
4824
|
lines.push("");
|
|
4626
4825
|
}
|
|
4627
4826
|
appendTextSection(lines, "Usage", [`${cliName} <command> [options]`]);
|
|
@@ -4674,10 +4873,10 @@ function formatSubcommandHelp(cmd, helper) {
|
|
|
4674
4873
|
term: helper.optionTerm(option),
|
|
4675
4874
|
desc: helper.optionDescription(option)
|
|
4676
4875
|
}));
|
|
4677
|
-
lines.push(
|
|
4876
|
+
lines.push(chalk13.bold(commandPath(cmd)));
|
|
4678
4877
|
lines.push("");
|
|
4679
4878
|
if (description) {
|
|
4680
|
-
lines.push(` ${
|
|
4879
|
+
lines.push(` ${chalk13.dim(description)}`);
|
|
4681
4880
|
lines.push("");
|
|
4682
4881
|
}
|
|
4683
4882
|
appendTextSection(lines, "Usage", [helper.commandUsage(cmd)]);
|
|
@@ -4703,6 +4902,7 @@ function applyHelpFormatting(cmd) {
|
|
|
4703
4902
|
program.name(cliName).description("Agent Computer CLI").version(pkg3.version ?? "0.0.0").option("-y, --yes", "Skip confirmation prompts");
|
|
4704
4903
|
program.addCommand(loginCommand);
|
|
4705
4904
|
program.addCommand(upgradeCommand);
|
|
4905
|
+
program.addCommand(internalInstallMutagenCommand, { hidden: true });
|
|
4706
4906
|
program.addCommand(logoutCommand);
|
|
4707
4907
|
program.addCommand(whoamiCommand);
|
|
4708
4908
|
program.addCommand(claudeLoginCommand);
|