aicomputer 0.1.5 → 0.1.6
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 +7 -0
- package/dist/index.js +175 -64
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,11 @@ computer open my-box --terminal
|
|
|
22
22
|
computer ssh
|
|
23
23
|
computer ssh my-box
|
|
24
24
|
computer ssh --setup
|
|
25
|
+
computer agent agents my-box
|
|
26
|
+
computer agent sessions list my-box
|
|
27
|
+
computer agent prompt my-box "inspect /workspace" --agent codex
|
|
28
|
+
computer fleet status
|
|
29
|
+
computer acp serve my-box --agent codex
|
|
25
30
|
```
|
|
26
31
|
|
|
27
32
|
Run `computer ssh` without a handle in an interactive terminal to pick from your available machines.
|
|
@@ -33,4 +38,6 @@ ssh agentcomputer.ai
|
|
|
33
38
|
ssh my-box@agentcomputer.ai
|
|
34
39
|
```
|
|
35
40
|
|
|
41
|
+
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.
|
|
42
|
+
|
|
36
43
|
You can also run without a global install via `npx aicomputer <command>`.
|
package/dist/index.js
CHANGED
|
@@ -857,8 +857,28 @@ function emitError(id, code, message) {
|
|
|
857
857
|
}
|
|
858
858
|
});
|
|
859
859
|
}
|
|
860
|
-
|
|
861
|
-
|
|
860
|
+
function forwardBridgePayload(payload, publicSessionID, backendSessionID) {
|
|
861
|
+
let message;
|
|
862
|
+
try {
|
|
863
|
+
message = JSON.parse(payload);
|
|
864
|
+
} catch {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
const method = typeof message.method === "string" ? message.method : "";
|
|
868
|
+
if (method !== "session/update" && method !== "session/request_permission") {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const params = typeof message.params === "object" && message.params !== null ? { ...message.params } : {};
|
|
872
|
+
const payloadSessionID = typeof params.sessionId === "string" ? params.sessionId.trim() : "";
|
|
873
|
+
if (backendSessionID?.trim() && payloadSessionID && payloadSessionID !== backendSessionID.trim()) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
params.sessionId = publicSessionID;
|
|
877
|
+
process.stdout.write(`${JSON.stringify({ ...message, params })}
|
|
878
|
+
`);
|
|
879
|
+
}
|
|
880
|
+
async function forwardRawEventStream(computerID, publicSessionID, backendSessionID, signal) {
|
|
881
|
+
const response = await openAgentSessionEventsStream(computerID, publicSessionID, { signal });
|
|
862
882
|
if (!response.body) {
|
|
863
883
|
return;
|
|
864
884
|
}
|
|
@@ -882,8 +902,7 @@ async function forwardRawEventStream(computerID, sessionID, signal) {
|
|
|
882
902
|
if (!payload || payload === "heartbeat") {
|
|
883
903
|
continue;
|
|
884
904
|
}
|
|
885
|
-
|
|
886
|
-
`);
|
|
905
|
+
forwardBridgePayload(payload, publicSessionID, backendSessionID);
|
|
887
906
|
}
|
|
888
907
|
}
|
|
889
908
|
}
|
|
@@ -904,15 +923,21 @@ async function handlePromptRequest(computerID, sessionID, id, params) {
|
|
|
904
923
|
if (prompt.length === 0) {
|
|
905
924
|
throw new Error("session/prompt requires prompt content");
|
|
906
925
|
}
|
|
926
|
+
const accepted = await promptAgentSession(computerID, sessionID, { prompt });
|
|
927
|
+
const current = await getAgentSession(computerID, sessionID);
|
|
907
928
|
const controller = new AbortController();
|
|
908
|
-
const streamPromise = forwardRawEventStream(
|
|
929
|
+
const streamPromise = forwardRawEventStream(
|
|
930
|
+
computerID,
|
|
931
|
+
sessionID,
|
|
932
|
+
current.backend_session_id,
|
|
933
|
+
controller.signal
|
|
934
|
+
).catch((error) => {
|
|
909
935
|
if (error instanceof Error && error.name === "AbortError") {
|
|
910
936
|
return;
|
|
911
937
|
}
|
|
912
|
-
|
|
938
|
+
return;
|
|
913
939
|
});
|
|
914
940
|
try {
|
|
915
|
-
const accepted = await promptAgentSession(computerID, sessionID, { prompt });
|
|
916
941
|
const settled = await waitForSessionToSettle(computerID, sessionID, accepted.prompt_id);
|
|
917
942
|
emitResult(id, {
|
|
918
943
|
stopReason: settled.last_stop_reason || "end_turn"
|
|
@@ -1129,7 +1154,7 @@ var StreamPrinter = class {
|
|
|
1129
1154
|
};
|
|
1130
1155
|
async function streamSessionEvents(computerID, sessionID, options = {}) {
|
|
1131
1156
|
const response = await openAgentSessionEventsStream(computerID, sessionID, {
|
|
1132
|
-
lastEventId: options.
|
|
1157
|
+
lastEventId: options.lastEventId?.trim() || void 0,
|
|
1133
1158
|
signal: options.signal
|
|
1134
1159
|
});
|
|
1135
1160
|
if (!response.body) {
|
|
@@ -1314,22 +1339,33 @@ agentCommand.command("prompt").description("Send a prompt to a machine agent ses
|
|
|
1314
1339
|
const computer = await resolveComputer(identifier);
|
|
1315
1340
|
const session = await resolvePromptSession(computer.id, options);
|
|
1316
1341
|
spinner?.stop();
|
|
1317
|
-
|
|
1342
|
+
const canStreamImmediately = !options.noStream && Boolean(session.backend_session_id?.trim());
|
|
1343
|
+
if (canStreamImmediately) {
|
|
1318
1344
|
streamPromise = streamSessionEvents(computer.id, session.id, {
|
|
1319
|
-
replay: false,
|
|
1320
1345
|
json: options.json,
|
|
1321
1346
|
signal: controller.signal
|
|
1322
1347
|
}).catch((error) => {
|
|
1323
1348
|
if (error instanceof Error && error.name === "AbortError") {
|
|
1324
1349
|
return;
|
|
1325
1350
|
}
|
|
1326
|
-
|
|
1351
|
+
return;
|
|
1327
1352
|
});
|
|
1328
1353
|
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
1329
1354
|
}
|
|
1330
1355
|
const promptResponse = await promptAgentSession(computer.id, session.id, {
|
|
1331
1356
|
prompt: [{ type: "text", text }]
|
|
1332
1357
|
});
|
|
1358
|
+
if (!options.noStream && !canStreamImmediately) {
|
|
1359
|
+
streamPromise = streamSessionEvents(computer.id, session.id, {
|
|
1360
|
+
json: options.json,
|
|
1361
|
+
signal: controller.signal
|
|
1362
|
+
}).catch((error) => {
|
|
1363
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
return;
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1333
1369
|
const settled = await waitForSessionToSettle(computer.id, session.id, promptResponse.prompt_id);
|
|
1334
1370
|
controller.abort();
|
|
1335
1371
|
if (streamPromise) {
|
|
@@ -1358,11 +1394,14 @@ agentCommand.command("prompt").description("Send a prompt to a machine agent ses
|
|
|
1358
1394
|
process.exit(1);
|
|
1359
1395
|
}
|
|
1360
1396
|
});
|
|
1361
|
-
agentCommand.command("watch").description("Watch a machine agent session event stream").argument("<machine>", "Computer id or handle").requiredOption("--session <id>", "Session id").option("--
|
|
1397
|
+
agentCommand.command("watch").description("Watch a machine agent session event stream").argument("<machine>", "Computer id or handle").requiredOption("--session <id>", "Session id").option("--last-event-id <id>", "Replay buffered events after this event id").option("--json", "Print raw event envelopes").action(async (identifier, options) => {
|
|
1362
1398
|
try {
|
|
1363
1399
|
const computer = await resolveComputer(identifier);
|
|
1400
|
+
if (options.lastEventId && !/^[1-9]\d*$/.test(options.lastEventId.trim())) {
|
|
1401
|
+
throw new Error("--last-event-id must be a positive integer");
|
|
1402
|
+
}
|
|
1364
1403
|
await streamSessionEvents(computer.id, options.session.trim(), {
|
|
1365
|
-
|
|
1404
|
+
lastEventId: options.lastEventId,
|
|
1366
1405
|
json: options.json
|
|
1367
1406
|
});
|
|
1368
1407
|
} catch (error) {
|
|
@@ -1876,6 +1915,9 @@ _computer() {
|
|
|
1876
1915
|
'open:Open in browser'
|
|
1877
1916
|
'ssh:SSH into a computer'
|
|
1878
1917
|
'ports:Manage published ports'
|
|
1918
|
+
'agent:Manage cloud agent sessions'
|
|
1919
|
+
'fleet:View agent activity across your fleet'
|
|
1920
|
+
'acp:Run a local ACP bridge for remote agent sessions'
|
|
1879
1921
|
'rm:Delete a computer'
|
|
1880
1922
|
'completion:Generate shell completions'
|
|
1881
1923
|
'help:Display help'
|
|
@@ -2002,7 +2044,7 @@ var BASH_SCRIPT = `_computer() {
|
|
|
2002
2044
|
local cur prev words cword
|
|
2003
2045
|
_init_completion || return
|
|
2004
2046
|
|
|
2005
|
-
local commands="login logout whoami create ls get open ssh ports rm completion help"
|
|
2047
|
+
local commands="login logout whoami create ls get open ssh ports agent fleet acp rm completion help"
|
|
2006
2048
|
local ports_commands="ls publish rm"
|
|
2007
2049
|
|
|
2008
2050
|
if [[ $cword -eq 1 ]]; then
|
|
@@ -2444,60 +2486,128 @@ var pkg2 = JSON.parse(
|
|
|
2444
2486
|
);
|
|
2445
2487
|
var cliName = process.argv[1] ? basename2(process.argv[1]) : "agentcomputer";
|
|
2446
2488
|
var program = new Command9();
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2489
|
+
function appendTextSection(lines, title, values) {
|
|
2490
|
+
if (values.length === 0) {
|
|
2491
|
+
return;
|
|
2492
|
+
}
|
|
2493
|
+
lines.push(` ${chalk8.dim(title)}`);
|
|
2494
|
+
lines.push("");
|
|
2495
|
+
for (const value of values) {
|
|
2496
|
+
lines.push(` ${chalk8.white(value)}`);
|
|
2497
|
+
}
|
|
2498
|
+
lines.push("");
|
|
2499
|
+
}
|
|
2500
|
+
function appendTableSection(lines, title, entries) {
|
|
2501
|
+
if (entries.length === 0) {
|
|
2502
|
+
return;
|
|
2503
|
+
}
|
|
2504
|
+
const width = Math.max(...entries.map((entry) => entry.term.length), 0) + 2;
|
|
2505
|
+
lines.push(` ${chalk8.dim(title)}`);
|
|
2506
|
+
lines.push("");
|
|
2507
|
+
for (const entry of entries) {
|
|
2508
|
+
lines.push(` ${chalk8.white(padEnd(entry.term, width))}${chalk8.dim(entry.desc)}`);
|
|
2509
|
+
}
|
|
2510
|
+
lines.push("");
|
|
2511
|
+
}
|
|
2512
|
+
function commandPath(cmd) {
|
|
2513
|
+
const parts = [];
|
|
2514
|
+
let current = cmd;
|
|
2515
|
+
while (current) {
|
|
2516
|
+
parts.unshift(current.name());
|
|
2517
|
+
current = current.parent ?? null;
|
|
2518
|
+
}
|
|
2519
|
+
return parts.join(" ");
|
|
2520
|
+
}
|
|
2521
|
+
function formatRootHelp(cmd) {
|
|
2522
|
+
const version = pkg2.version ?? "0.0.0";
|
|
2523
|
+
const lines = [];
|
|
2524
|
+
const groups = [
|
|
2525
|
+
["Auth", []],
|
|
2526
|
+
["Computers", []],
|
|
2527
|
+
["Access", []],
|
|
2528
|
+
["Agents", []],
|
|
2529
|
+
["Other", []]
|
|
2530
|
+
];
|
|
2531
|
+
const otherGroup = groups.find(([name]) => name === "Other")[1];
|
|
2532
|
+
lines.push(`${chalk8.bold(cliName)} ${chalk8.dim(`v${version}`)}`);
|
|
2533
|
+
lines.push("");
|
|
2534
|
+
if (cmd.description()) {
|
|
2535
|
+
lines.push(` ${chalk8.dim(cmd.description())}`);
|
|
2452
2536
|
lines.push("");
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
groups.Computers.push(entry);
|
|
2469
|
-
} else if (["agent", "fleet", "acp"].includes(name)) {
|
|
2470
|
-
groups.Agents.push(entry);
|
|
2471
|
-
} else if (["open", "ssh", "ports"].includes(name)) {
|
|
2472
|
-
groups.Access.push(entry);
|
|
2473
|
-
} else {
|
|
2474
|
-
groups.Other.push(entry);
|
|
2475
|
-
}
|
|
2476
|
-
}
|
|
2477
|
-
for (const [groupName, entries] of Object.entries(groups)) {
|
|
2478
|
-
if (entries.length === 0) continue;
|
|
2479
|
-
lines.push(` ${chalk8.dim(groupName)}`);
|
|
2480
|
-
for (const entry of entries) {
|
|
2481
|
-
const padded = entry.name.padEnd(14);
|
|
2482
|
-
lines.push(` ${chalk8.white(padded)}${chalk8.dim(entry.desc)}`);
|
|
2483
|
-
}
|
|
2484
|
-
lines.push("");
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
const globalOpts = [
|
|
2488
|
-
{ flags: "-y, --yes", desc: "Skip confirmation prompts" },
|
|
2489
|
-
{ flags: "-V, --version", desc: "Show version" },
|
|
2490
|
-
{ flags: "-h, --help", desc: "Show help" }
|
|
2491
|
-
];
|
|
2492
|
-
lines.push(` ${chalk8.dim("Options")}`);
|
|
2493
|
-
for (const opt of globalOpts) {
|
|
2494
|
-
const padded = opt.flags.padEnd(14);
|
|
2495
|
-
lines.push(` ${chalk8.white(padded)}${chalk8.dim(opt.desc)}`);
|
|
2537
|
+
}
|
|
2538
|
+
appendTextSection(lines, "Usage", [`${cliName} <command> [options]`]);
|
|
2539
|
+
for (const sub of cmd.commands) {
|
|
2540
|
+
const name = sub.name();
|
|
2541
|
+
const entry = { term: name, desc: sub.description() };
|
|
2542
|
+
if (["login", "logout", "whoami"].includes(name)) {
|
|
2543
|
+
groups[0][1].push(entry);
|
|
2544
|
+
} else if (["create", "ls", "get", "rm"].includes(name)) {
|
|
2545
|
+
groups[1][1].push(entry);
|
|
2546
|
+
} else if (["open", "ssh", "ports"].includes(name)) {
|
|
2547
|
+
groups[2][1].push(entry);
|
|
2548
|
+
} else if (["agent", "fleet", "acp"].includes(name)) {
|
|
2549
|
+
groups[3][1].push(entry);
|
|
2550
|
+
} else {
|
|
2551
|
+
otherGroup.push(entry);
|
|
2496
2552
|
}
|
|
2553
|
+
}
|
|
2554
|
+
for (const [groupName, entries] of groups) {
|
|
2555
|
+
appendTableSection(
|
|
2556
|
+
lines,
|
|
2557
|
+
groupName,
|
|
2558
|
+
entries
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2561
|
+
appendTableSection(lines, "Options", [
|
|
2562
|
+
{ term: "-y, --yes", desc: "Skip confirmation prompts" },
|
|
2563
|
+
{ term: "-V, --version", desc: "Show version" },
|
|
2564
|
+
{ term: "-h, --help", desc: "Show help" }
|
|
2565
|
+
]);
|
|
2566
|
+
return `${lines.join("\n").trimEnd()}
|
|
2567
|
+
`;
|
|
2568
|
+
}
|
|
2569
|
+
function formatSubcommandHelp(cmd, helper) {
|
|
2570
|
+
const lines = [];
|
|
2571
|
+
const description = helper.commandDescription(cmd);
|
|
2572
|
+
const argumentsList = helper.visibleArguments(cmd).map((argument) => ({
|
|
2573
|
+
term: helper.argumentTerm(argument),
|
|
2574
|
+
desc: helper.argumentDescription(argument)
|
|
2575
|
+
}));
|
|
2576
|
+
const commandList = helper.visibleCommands(cmd).map((subcommand) => ({
|
|
2577
|
+
term: helper.subcommandTerm(subcommand),
|
|
2578
|
+
desc: helper.subcommandDescription(subcommand)
|
|
2579
|
+
}));
|
|
2580
|
+
const optionList = helper.visibleOptions(cmd).map((option) => ({
|
|
2581
|
+
term: helper.optionTerm(option),
|
|
2582
|
+
desc: helper.optionDescription(option)
|
|
2583
|
+
}));
|
|
2584
|
+
lines.push(chalk8.bold(commandPath(cmd)));
|
|
2585
|
+
lines.push("");
|
|
2586
|
+
if (description) {
|
|
2587
|
+
lines.push(` ${chalk8.dim(description)}`);
|
|
2497
2588
|
lines.push("");
|
|
2498
|
-
return lines.join("\n");
|
|
2499
2589
|
}
|
|
2500
|
-
|
|
2590
|
+
appendTextSection(lines, "Usage", [helper.commandUsage(cmd)]);
|
|
2591
|
+
appendTableSection(lines, "Arguments", argumentsList);
|
|
2592
|
+
appendTableSection(lines, "Commands", commandList);
|
|
2593
|
+
appendTableSection(lines, "Options", optionList);
|
|
2594
|
+
return `${lines.join("\n").trimEnd()}
|
|
2595
|
+
`;
|
|
2596
|
+
}
|
|
2597
|
+
function applyHelpFormatting(cmd) {
|
|
2598
|
+
cmd.configureHelp({
|
|
2599
|
+
formatHelp(current, helper) {
|
|
2600
|
+
if (!current.parent) {
|
|
2601
|
+
return formatRootHelp(current);
|
|
2602
|
+
}
|
|
2603
|
+
return formatSubcommandHelp(current, helper);
|
|
2604
|
+
}
|
|
2605
|
+
});
|
|
2606
|
+
for (const subcommand of cmd.commands) {
|
|
2607
|
+
applyHelpFormatting(subcommand);
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
program.name(cliName).description("Agent Computer CLI").version(pkg2.version ?? "0.0.0").option("-y, --yes", "Skip confirmation prompts");
|
|
2501
2611
|
program.addCommand(loginCommand);
|
|
2502
2612
|
program.addCommand(logoutCommand);
|
|
2503
2613
|
program.addCommand(whoamiCommand);
|
|
@@ -2512,4 +2622,5 @@ program.addCommand(sshCommand);
|
|
|
2512
2622
|
program.addCommand(portsCommand);
|
|
2513
2623
|
program.addCommand(removeCommand);
|
|
2514
2624
|
program.addCommand(completionCommand);
|
|
2625
|
+
applyHelpFormatting(program);
|
|
2515
2626
|
program.parse();
|