aicomputer 0.1.13 → 0.1.14

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.
Files changed (3) hide show
  1. package/README.md +12 -4
  2. package/dist/index.js +197 -56
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -8,6 +8,12 @@ Agent Computer CLI for creating, opening, and managing computers from the termin
8
8
  npm install -g aicomputer
9
9
  ```
10
10
 
11
+ Upgrade the installed CLI later with:
12
+
13
+ ```bash
14
+ computer upgrade
15
+ ```
16
+
11
17
  Or run it directly with Nix:
12
18
 
13
19
  ```bash
@@ -78,6 +84,7 @@ After installing, use the `computer` command:
78
84
 
79
85
  ```bash
80
86
  computer login
87
+ computer upgrade
81
88
  computer login --api-key <ac_live_...>
82
89
  computer claude-login
83
90
  computer codex-login
@@ -90,14 +97,15 @@ computer ssh my-box
90
97
  computer ssh --setup
91
98
  computer agent agents my-box
92
99
  computer agent sessions list my-box
93
- computer agent prompt my-box "inspect /workspace" --agent codex
94
- computer fleet status
100
+ computer agent prompt my-box "inspect /home/node/workspace-my-box" --agent codex
95
101
  computer acp serve my-box --agent codex
96
102
  ```
97
103
 
98
104
  `computer login` authenticates the CLI against Agent Computer. Use
99
105
  `computer claude-login` and `computer codex-login` to install Claude Code or
100
- Codex credentials onto a machine after the CLI is already logged in.
106
+ Codex credentials onto a machine after the CLI is already logged in. Use
107
+ `computer upgrade` to update a global npm install or the matching Nix profile
108
+ entry.
101
109
 
102
110
  Run `computer ssh` without a handle in an interactive terminal to pick from your available machines.
103
111
 
@@ -108,6 +116,6 @@ ssh agentcomputer.ai
108
116
  ssh my-box@agentcomputer.ai
109
117
  ```
110
118
 
111
- Use `computer agent` to inspect agents on one machine and manage remote sessions. Use `computer fleet status` to see active agent work across every machine in your fleet.
119
+ Use `computer agent` to inspect agents on one machine and manage remote sessions. Use `computer acp serve` when you want to expose one remote session through a local ACP bridge.
112
120
 
113
121
  You can also run without a global install via `npx aicomputer <command>`.
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command12 } from "commander";
5
- import chalk12 from "chalk";
6
- import { readFileSync as readFileSync3 } from "fs";
4
+ import { Command as Command13 } from "commander";
5
+ import chalk13 from "chalk";
6
+ import { readFileSync as readFileSync4 } from "fs";
7
7
  import { basename as basename2 } from "path";
8
8
 
9
9
  // src/commands/access.ts
@@ -586,7 +586,7 @@ var openCommand = new Command("open").description("Open a computer in your brows
586
586
  process.exit(1);
587
587
  }
588
588
  });
589
- var sshCommand = new Command("ssh").description("Open an SSH session to a computer").argument("[id-or-handle]", "Computer id or handle").option("--setup", "Register key and configure a global SSH alias").option("--alias <alias>", "SSH host alias", "agentcomputer.ai").option("--host <host>", "SSH gateway host", "ssh.agentcomputer.ai").option("--port <port>", "SSH gateway port", "22").action(
589
+ var sshCommand = new Command("ssh").description("Open an SSH session to a computer").argument("[id-or-handle]", "Computer id or handle").option("--setup", "Register key and configure a global SSH alias").option("--alias <alias>", "SSH host alias", "agentcomputer.ai").option("--host <host>", "SSH gateway host", "ssh.agentcomputer.ai").option("--port <port>", "SSH gateway port", "443").action(
590
590
  async (identifier, options) => {
591
591
  if (options.setup) {
592
592
  await setupSSHAlias(options);
@@ -698,7 +698,7 @@ async function setupSSHAlias(options) {
698
698
  try {
699
699
  const alias = normalizeSSHAlias(options.alias ?? "agentcomputer.ai");
700
700
  const host = normalizeSSHHost(options.host ?? "ssh.agentcomputer.ai");
701
- const port = parseSSHPort(options.port ?? "22");
701
+ const port = parseSSHPort(options.port ?? "443");
702
702
  const registered = await ensureDefaultSSHKeyRegistered();
703
703
  const configResult = await ensureSSHAliasConfig({
704
704
  alias,
@@ -782,10 +782,6 @@ async function listAgentSessions(computerID) {
782
782
  const response = await api(`/v1/computers/${computerID}/agent-sessions`);
783
783
  return response.sessions;
784
784
  }
785
- async function listFleetAgentSessions() {
786
- const response = await api("/v1/fleet/agent-sessions");
787
- return response.sessions;
788
- }
789
785
  async function createAgentSession(computerID, input) {
790
786
  const response = await api(`/v1/computers/${computerID}/agent-sessions`, {
791
787
  method: "POST",
@@ -1541,29 +1537,6 @@ agentCommand.command("close").description("Close and delete a machine agent sess
1541
1537
  process.exit(1);
1542
1538
  }
1543
1539
  });
1544
- var fleetCommand = new Command3("fleet").description("View agent activity across your fleet");
1545
- fleetCommand.command("status").description("List open agent sessions across all machines").option("--json", "Print raw JSON").action(async (options) => {
1546
- const spinner = options.json ? null : ora2("Fetching fleet status...").start();
1547
- try {
1548
- const [sessions, computers] = await Promise.all([
1549
- listFleetAgentSessions(),
1550
- listComputers()
1551
- ]);
1552
- spinner?.stop();
1553
- if (options.json) {
1554
- console.log(JSON.stringify({ sessions }, null, 2));
1555
- return;
1556
- }
1557
- const handleByComputerID = new Map(computers.map((computer) => [computer.id, computer.handle]));
1558
- printSessions(sessions, handleByComputerID);
1559
- } catch (error) {
1560
- spinner?.fail(error instanceof Error ? error.message : "Failed to fetch fleet status");
1561
- if (!spinner) {
1562
- console.error(error instanceof Error ? error.message : "Failed to fetch fleet status");
1563
- }
1564
- process.exit(1);
1565
- }
1566
- });
1567
1540
 
1568
1541
  // src/commands/claude-auth.ts
1569
1542
  import { randomBytes as randomBytes2, createHash } from "crypto";
@@ -2667,6 +2640,7 @@ _computer() {
2667
2640
  local -a commands
2668
2641
  commands=(
2669
2642
  'login:Authenticate the CLI'
2643
+ 'upgrade:Update the CLI to the latest version'
2670
2644
  'logout:Remove stored API key'
2671
2645
  'whoami:Show current user'
2672
2646
  'claude-login:Authenticate Claude Code on a computer'
@@ -2681,7 +2655,6 @@ _computer() {
2681
2655
  'ssh:SSH into a computer'
2682
2656
  'ports:Manage published ports'
2683
2657
  'agent:Manage cloud agent sessions'
2684
- 'fleet:View agent activity across your fleet'
2685
2658
  'acp:Run a local ACP bridge for remote agent sessions'
2686
2659
  'rm:Delete a computer'
2687
2660
  'completion:Generate shell completions'
@@ -2877,7 +2850,7 @@ var BASH_SCRIPT = `_computer() {
2877
2850
  local cur prev words cword
2878
2851
  _init_completion || return
2879
2852
 
2880
- local commands="login logout whoami claude-login claude-auth codex-login codex-auth create ls get image open ssh ports agent fleet acp rm completion help"
2853
+ local commands="login upgrade logout whoami claude-login claude-auth codex-login codex-auth create ls get image open ssh ports agent acp rm completion help"
2881
2854
  local ports_commands="ls publish rm"
2882
2855
  local image_commands="ls save default rebuild rm"
2883
2856
 
@@ -4194,12 +4167,180 @@ var logoutCommand = new Command10("logout").description("Remove stored API key")
4194
4167
  console.log();
4195
4168
  });
4196
4169
 
4197
- // src/commands/whoami.ts
4170
+ // src/commands/upgrade.ts
4171
+ import { spawnSync } from "child_process";
4172
+ import { readFileSync as readFileSync3, realpathSync } from "fs";
4198
4173
  import { Command as Command11 } from "commander";
4199
4174
  import chalk11 from "chalk";
4200
4175
  import ora9 from "ora";
4201
- var whoamiCommand = new Command11("whoami").description("Show current user").option("--json", "Print raw JSON").action(async (options) => {
4202
- const spinner = options.json ? null : ora9("Loading user...").start();
4176
+ var pkg2 = JSON.parse(
4177
+ readFileSync3(new URL("../package.json", import.meta.url), "utf8")
4178
+ );
4179
+ function normalizeVersion(version) {
4180
+ return version.split("-")[0].split(".").map((part) => Number.parseInt(part, 10)).map((part) => Number.isNaN(part) ? 0 : part);
4181
+ }
4182
+ function compareVersions(a, b) {
4183
+ const left = normalizeVersion(a);
4184
+ const right = normalizeVersion(b);
4185
+ const size = Math.max(left.length, right.length);
4186
+ for (let index = 0; index < size; index += 1) {
4187
+ const diff = (left[index] ?? 0) - (right[index] ?? 0);
4188
+ if (diff !== 0) {
4189
+ return diff;
4190
+ }
4191
+ }
4192
+ return 0;
4193
+ }
4194
+ function resolveExecutablePath() {
4195
+ const candidate = process.argv[1] || process.execPath;
4196
+ try {
4197
+ return realpathSync(candidate);
4198
+ } catch {
4199
+ return candidate;
4200
+ }
4201
+ }
4202
+ function detectInstallMethod(executablePath) {
4203
+ const resolved = `${executablePath}\0${process.execPath}`.toLowerCase();
4204
+ if (resolved.includes("/nix/store/") || resolved.includes("\\nix\\store\\")) {
4205
+ return "nix";
4206
+ }
4207
+ if (resolved.includes("/.pnpm/") || resolved.includes("/pnpm/") || resolved.includes("\\pnpm\\")) {
4208
+ return "pnpm";
4209
+ }
4210
+ if (resolved.includes("/.yarn/") || resolved.includes("/yarn/") || resolved.includes("\\yarn\\")) {
4211
+ return "yarn";
4212
+ }
4213
+ if (resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\")) {
4214
+ return "npm";
4215
+ }
4216
+ return "unknown";
4217
+ }
4218
+ function findNixProfileElement(executablePath) {
4219
+ const result = spawnSync("nix", ["profile", "list", "--json"], {
4220
+ encoding: "utf8"
4221
+ });
4222
+ if (result.status !== 0 || !result.stdout.trim()) {
4223
+ return null;
4224
+ }
4225
+ const profile = JSON.parse(result.stdout);
4226
+ const resolvedExecutable = executablePath.toLowerCase();
4227
+ for (const [name, element] of Object.entries(profile.elements ?? {})) {
4228
+ const storePaths = Array.isArray(element.storePaths) ? element.storePaths.map((storePath) => storePath.toLowerCase()) : [];
4229
+ if (storePaths.some((storePath) => resolvedExecutable.startsWith(storePath))) {
4230
+ return name;
4231
+ }
4232
+ }
4233
+ for (const [name, element] of Object.entries(profile.elements ?? {})) {
4234
+ const originalUrl = String(element.originalUrl ?? "").toLowerCase();
4235
+ if (originalUrl.includes("agentcomputer") || originalUrl.includes("apps/cli")) {
4236
+ return name;
4237
+ }
4238
+ }
4239
+ return null;
4240
+ }
4241
+ function resolveUpgradeCommand(method, executablePath) {
4242
+ const packageName = pkg2.name ?? "aicomputer";
4243
+ switch (method) {
4244
+ case "nix": {
4245
+ const element = findNixProfileElement(executablePath);
4246
+ if (!element) {
4247
+ throw new Error(
4248
+ "Nix install detected, but no matching Nix profile entry was found. Rerun your original Nix install command or update that profile manually."
4249
+ );
4250
+ }
4251
+ return {
4252
+ command: "nix",
4253
+ args: ["profile", "upgrade", element],
4254
+ label: `nix profile upgrade ${element}`
4255
+ };
4256
+ }
4257
+ case "pnpm":
4258
+ return {
4259
+ command: "pnpm",
4260
+ args: ["add", "-g", `${packageName}@latest`],
4261
+ label: `pnpm add -g ${packageName}@latest`
4262
+ };
4263
+ case "yarn":
4264
+ return {
4265
+ command: "yarn",
4266
+ args: ["global", "add", `${packageName}@latest`],
4267
+ label: `yarn global add ${packageName}@latest`
4268
+ };
4269
+ case "npm":
4270
+ case "unknown":
4271
+ return {
4272
+ command: "npm",
4273
+ args: ["install", "-g", `${packageName}@latest`],
4274
+ label: `npm install -g ${packageName}@latest`
4275
+ };
4276
+ }
4277
+ }
4278
+ async function getLatestVersion(packageName) {
4279
+ const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
4280
+ if (!response.ok) {
4281
+ throw new Error(`Failed to check npm registry (${response.status})`);
4282
+ }
4283
+ const payload = await response.json();
4284
+ if (!payload.version) {
4285
+ throw new Error("Registry response missing version");
4286
+ }
4287
+ return payload.version;
4288
+ }
4289
+ var upgradeCommand = new Command11("upgrade").description("Update the CLI to the latest version").action(async () => {
4290
+ const currentVersion = pkg2.version ?? "0.0.0";
4291
+ const packageName = pkg2.name ?? "aicomputer";
4292
+ const spinner = ora9("Checking for updates...").start();
4293
+ let latestVersion;
4294
+ try {
4295
+ latestVersion = await getLatestVersion(packageName);
4296
+ } catch (error) {
4297
+ spinner.fail(
4298
+ error instanceof Error ? error.message : "Failed to check for updates"
4299
+ );
4300
+ process.exit(1);
4301
+ return;
4302
+ }
4303
+ if (compareVersions(latestVersion, currentVersion) <= 0) {
4304
+ spinner.succeed(`You're up to date (v${currentVersion}).`);
4305
+ return;
4306
+ }
4307
+ const executablePath = resolveExecutablePath();
4308
+ const method = detectInstallMethod(executablePath);
4309
+ let upgrade;
4310
+ try {
4311
+ upgrade = resolveUpgradeCommand(method, executablePath);
4312
+ } catch (error) {
4313
+ spinner.fail(
4314
+ error instanceof Error ? error.message : "Failed to prepare upgrade"
4315
+ );
4316
+ process.exit(1);
4317
+ return;
4318
+ }
4319
+ spinner.stop();
4320
+ console.log();
4321
+ console.log(
4322
+ chalk11.dim(` Updating ${chalk11.bold(`v${currentVersion}`)} -> ${chalk11.bold(`v${latestVersion}`)}`)
4323
+ );
4324
+ console.log(chalk11.dim(` ${upgrade.label}`));
4325
+ console.log();
4326
+ const result = spawnSync(upgrade.command, upgrade.args, {
4327
+ stdio: "inherit"
4328
+ });
4329
+ if (result.status === 0) {
4330
+ console.log();
4331
+ console.log(chalk11.green(` Updated to v${latestVersion}.`));
4332
+ console.log();
4333
+ return;
4334
+ }
4335
+ process.exit(result.status ?? 1);
4336
+ });
4337
+
4338
+ // src/commands/whoami.ts
4339
+ import { Command as Command12 } from "commander";
4340
+ import chalk12 from "chalk";
4341
+ import ora10 from "ora";
4342
+ var whoamiCommand = new Command12("whoami").description("Show current user").option("--json", "Print raw JSON").action(async (options) => {
4343
+ const spinner = options.json ? null : ora10("Loading user...").start();
4203
4344
  try {
4204
4345
  const me = await api("/v1/me");
4205
4346
  spinner?.stop();
@@ -4208,14 +4349,14 @@ var whoamiCommand = new Command11("whoami").description("Show current user").opt
4208
4349
  return;
4209
4350
  }
4210
4351
  console.log();
4211
- console.log(` ${chalk11.bold.white(me.user.display_name || me.user.email)}`);
4352
+ console.log(` ${chalk12.bold.white(me.user.display_name || me.user.email)}`);
4212
4353
  if (me.user.display_name) {
4213
- console.log(` ${chalk11.dim(me.user.email)}`);
4354
+ console.log(` ${chalk12.dim(me.user.email)}`);
4214
4355
  }
4215
4356
  if (me.api_key.name) {
4216
- console.log(` ${chalk11.dim("Key:")} ${me.api_key.name}`);
4357
+ console.log(` ${chalk12.dim("Key:")} ${me.api_key.name}`);
4217
4358
  }
4218
- console.log(` ${chalk11.dim("API:")} ${chalk11.dim(getBaseURL())}`);
4359
+ console.log(` ${chalk12.dim("API:")} ${chalk12.dim(getBaseURL())}`);
4219
4360
  console.log();
4220
4361
  } catch (error) {
4221
4362
  if (spinner) {
@@ -4228,19 +4369,19 @@ var whoamiCommand = new Command11("whoami").description("Show current user").opt
4228
4369
  });
4229
4370
 
4230
4371
  // src/index.ts
4231
- var pkg2 = JSON.parse(
4232
- readFileSync3(new URL("../package.json", import.meta.url), "utf8")
4372
+ var pkg3 = JSON.parse(
4373
+ readFileSync4(new URL("../package.json", import.meta.url), "utf8")
4233
4374
  );
4234
4375
  var cliName = process.argv[1] ? basename2(process.argv[1]) : "agentcomputer";
4235
- var program = new Command12();
4376
+ var program = new Command13();
4236
4377
  function appendTextSection(lines, title, values) {
4237
4378
  if (values.length === 0) {
4238
4379
  return;
4239
4380
  }
4240
- lines.push(` ${chalk12.dim(title)}`);
4381
+ lines.push(` ${chalk13.dim(title)}`);
4241
4382
  lines.push("");
4242
4383
  for (const value of values) {
4243
- lines.push(` ${chalk12.white(value)}`);
4384
+ lines.push(` ${chalk13.white(value)}`);
4244
4385
  }
4245
4386
  lines.push("");
4246
4387
  }
@@ -4249,10 +4390,10 @@ function appendTableSection(lines, title, entries) {
4249
4390
  return;
4250
4391
  }
4251
4392
  const width = Math.max(...entries.map((entry) => entry.term.length), 0) + 2;
4252
- lines.push(` ${chalk12.dim(title)}`);
4393
+ lines.push(` ${chalk13.dim(title)}`);
4253
4394
  lines.push("");
4254
4395
  for (const entry of entries) {
4255
- lines.push(` ${chalk12.white(padEnd(entry.term, width))}${chalk12.dim(entry.desc)}`);
4396
+ lines.push(` ${chalk13.white(padEnd(entry.term, width))}${chalk13.dim(entry.desc)}`);
4256
4397
  }
4257
4398
  lines.push("");
4258
4399
  }
@@ -4266,7 +4407,7 @@ function commandPath(cmd) {
4266
4407
  return parts.join(" ");
4267
4408
  }
4268
4409
  function formatRootHelp(cmd) {
4269
- const version = pkg2.version ?? "0.0.0";
4410
+ const version = pkg3.version ?? "0.0.0";
4270
4411
  const lines = [];
4271
4412
  const groups = [
4272
4413
  ["Auth", []],
@@ -4277,10 +4418,10 @@ function formatRootHelp(cmd) {
4277
4418
  ["Other", []]
4278
4419
  ];
4279
4420
  const otherGroup = groups.find(([name]) => name === "Other")[1];
4280
- lines.push(`${chalk12.bold(cliName)} ${chalk12.dim(`v${version}`)}`);
4421
+ lines.push(`${chalk13.bold(cliName)} ${chalk13.dim(`v${version}`)}`);
4281
4422
  lines.push("");
4282
4423
  if (cmd.description()) {
4283
- lines.push(` ${chalk12.dim(cmd.description())}`);
4424
+ lines.push(` ${chalk13.dim(cmd.description())}`);
4284
4425
  lines.push("");
4285
4426
  }
4286
4427
  appendTextSection(lines, "Usage", [`${cliName} <command> [options]`]);
@@ -4295,7 +4436,7 @@ function formatRootHelp(cmd) {
4295
4436
  groups[2][1].push(entry);
4296
4437
  } else if (["open", "ssh", "ports"].includes(name)) {
4297
4438
  groups[3][1].push(entry);
4298
- } else if (["agent", "fleet", "acp"].includes(name)) {
4439
+ } else if (["agent", "acp"].includes(name)) {
4299
4440
  groups[4][1].push(entry);
4300
4441
  } else {
4301
4442
  otherGroup.push(entry);
@@ -4331,10 +4472,10 @@ function formatSubcommandHelp(cmd, helper) {
4331
4472
  term: helper.optionTerm(option),
4332
4473
  desc: helper.optionDescription(option)
4333
4474
  }));
4334
- lines.push(chalk12.bold(commandPath(cmd)));
4475
+ lines.push(chalk13.bold(commandPath(cmd)));
4335
4476
  lines.push("");
4336
4477
  if (description) {
4337
- lines.push(` ${chalk12.dim(description)}`);
4478
+ lines.push(` ${chalk13.dim(description)}`);
4338
4479
  lines.push("");
4339
4480
  }
4340
4481
  appendTextSection(lines, "Usage", [helper.commandUsage(cmd)]);
@@ -4357,8 +4498,9 @@ function applyHelpFormatting(cmd) {
4357
4498
  applyHelpFormatting(subcommand);
4358
4499
  }
4359
4500
  }
4360
- program.name(cliName).description("Agent Computer CLI").version(pkg2.version ?? "0.0.0").option("-y, --yes", "Skip confirmation prompts");
4501
+ program.name(cliName).description("Agent Computer CLI").version(pkg3.version ?? "0.0.0").option("-y, --yes", "Skip confirmation prompts");
4361
4502
  program.addCommand(loginCommand);
4503
+ program.addCommand(upgradeCommand);
4362
4504
  program.addCommand(logoutCommand);
4363
4505
  program.addCommand(whoamiCommand);
4364
4506
  program.addCommand(claudeLoginCommand);
@@ -4368,7 +4510,6 @@ program.addCommand(lsCommand);
4368
4510
  program.addCommand(getCommand);
4369
4511
  program.addCommand(imageCommand);
4370
4512
  program.addCommand(agentCommand);
4371
- program.addCommand(fleetCommand);
4372
4513
  program.addCommand(acpCommand);
4373
4514
  program.addCommand(openCommand);
4374
4515
  program.addCommand(sshCommand);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aicomputer",
3
- "version": "0.1.13",
4
- "description": "Computer CLI - manage your Agent Computer fleet from the terminal",
3
+ "version": "0.1.14",
4
+ "description": "Computer CLI - manage your Agent Computer machines from the terminal",
5
5
  "homepage": "https://agentcomputer.ai",
6
6
  "repository": {
7
7
  "type": "git",