aicomputer 0.1.13 → 0.1.15
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 +19 -5
- package/dist/chunk-5JVJROSI.js +186 -0
- package/dist/chunk-KQQUR2YX.js +655 -0
- package/dist/chunk-OWK5N76S.js +70 -0
- package/dist/index.js +892 -665
- package/dist/lib/mount-config.d.ts +69 -0
- package/dist/lib/mount-config.js +40 -0
- package/dist/lib/mount-host.d.ts +14 -0
- package/dist/lib/mount-host.js +10 -0
- package/dist/lib/mount-reconcile.d.ts +25 -0
- package/dist/lib/mount-reconcile.js +13 -0
- package/package.json +5 -4
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,26 +84,29 @@ 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
|
|
84
91
|
computer whoami
|
|
85
92
|
computer create my-box
|
|
86
93
|
computer open my-box
|
|
87
|
-
computer open my-box --terminal
|
|
88
94
|
computer ssh
|
|
89
95
|
computer ssh my-box
|
|
90
96
|
computer ssh --setup
|
|
97
|
+
computer mount
|
|
98
|
+
computer mount status
|
|
91
99
|
computer agent agents my-box
|
|
92
100
|
computer agent sessions list my-box
|
|
93
|
-
computer agent prompt my-box "inspect /
|
|
94
|
-
computer fleet status
|
|
101
|
+
computer agent prompt my-box "inspect /home/node" --agent codex
|
|
95
102
|
computer acp serve my-box --agent codex
|
|
96
103
|
```
|
|
97
104
|
|
|
98
105
|
`computer login` authenticates the CLI against Agent Computer. Use
|
|
99
106
|
`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.
|
|
107
|
+
Codex credentials onto a machine after the CLI is already logged in. Use
|
|
108
|
+
`computer upgrade` to update a global npm install or the matching Nix profile
|
|
109
|
+
entry.
|
|
101
110
|
|
|
102
111
|
Run `computer ssh` without a handle in an interactive terminal to pick from your available machines.
|
|
103
112
|
|
|
@@ -108,6 +117,11 @@ ssh agentcomputer.ai
|
|
|
108
117
|
ssh my-box@agentcomputer.ai
|
|
109
118
|
```
|
|
110
119
|
|
|
111
|
-
|
|
120
|
+
Run `computer mount` to start a foreground controller that mirrors all SSH-ready
|
|
121
|
+
machine homes under `~/agentcomputer/<handle>` while the command is running.
|
|
122
|
+
This uses the same SSH setup as `computer ssh --setup` and requires Mutagen plus
|
|
123
|
+
OpenSSH client tools (`ssh` and `scp`) to already be installed locally.
|
|
124
|
+
|
|
125
|
+
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
126
|
|
|
113
127
|
You can also run without a global install via `npx aicomputer <command>`.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// src/lib/mount-config.ts
|
|
2
|
+
import {
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
renameSync,
|
|
7
|
+
rmSync,
|
|
8
|
+
writeFileSync
|
|
9
|
+
} from "fs";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
var MOUNT_SERVICE_LABEL = "ai.agentcomputer.mount";
|
|
13
|
+
function getDefaultMountRoot() {
|
|
14
|
+
return join(homedir(), "agentcomputer");
|
|
15
|
+
}
|
|
16
|
+
function getMountStateDir() {
|
|
17
|
+
return join(homedir(), ".computer", "mount");
|
|
18
|
+
}
|
|
19
|
+
function getMountPaths(rootPath = getDefaultMountRoot()) {
|
|
20
|
+
const stateDir = getMountStateDir();
|
|
21
|
+
return {
|
|
22
|
+
stateDir,
|
|
23
|
+
rootPath,
|
|
24
|
+
configPath: join(stateDir, "config.json"),
|
|
25
|
+
statusPath: join(stateDir, "status.json"),
|
|
26
|
+
socketPath: join(stateDir, "control.sock"),
|
|
27
|
+
controllerLockPath: join(stateDir, "controller.lock.json"),
|
|
28
|
+
handlesDir: join(stateDir, "handles"),
|
|
29
|
+
sshToolsDir: join(stateDir, "ssh-tools"),
|
|
30
|
+
staleDir: join(stateDir, "stale")
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function getMountHandlePaths(handle, rootPath = getDefaultMountRoot()) {
|
|
34
|
+
const paths = getMountPaths(rootPath);
|
|
35
|
+
const stateDir = join(paths.handlesDir, handle);
|
|
36
|
+
return {
|
|
37
|
+
stateDir,
|
|
38
|
+
projectFilePath: join(stateDir, "mutagen.yml"),
|
|
39
|
+
metaPath: join(stateDir, "meta.json"),
|
|
40
|
+
sshToolsDir: join(stateDir, "ssh-tools")
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function defaultMountServiceConfig() {
|
|
44
|
+
return {
|
|
45
|
+
alias: "agentcomputer.ai",
|
|
46
|
+
host: "ssh.agentcomputer.ai",
|
|
47
|
+
port: 443,
|
|
48
|
+
rootPath: getDefaultMountRoot(),
|
|
49
|
+
pollIntervalMs: 5e3,
|
|
50
|
+
connectTimeoutSeconds: 5
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function ensureMountDirectories(paths) {
|
|
54
|
+
for (const directory of [
|
|
55
|
+
paths.stateDir,
|
|
56
|
+
paths.rootPath,
|
|
57
|
+
paths.handlesDir,
|
|
58
|
+
paths.sshToolsDir,
|
|
59
|
+
paths.staleDir
|
|
60
|
+
]) {
|
|
61
|
+
if (!existsSync(directory)) {
|
|
62
|
+
mkdirSync(directory, { recursive: true, mode: 448 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function ensureHandleDirectories(handle, rootPath) {
|
|
67
|
+
const handlePaths = getMountHandlePaths(handle, rootPath);
|
|
68
|
+
for (const directory of [handlePaths.stateDir, handlePaths.sshToolsDir]) {
|
|
69
|
+
if (!existsSync(directory)) {
|
|
70
|
+
mkdirSync(directory, { recursive: true, mode: 448 });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return handlePaths;
|
|
74
|
+
}
|
|
75
|
+
function readMountConfig() {
|
|
76
|
+
const defaults = defaultMountServiceConfig();
|
|
77
|
+
const paths = getMountPaths(defaults.rootPath);
|
|
78
|
+
if (!existsSync(paths.configPath)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const raw = JSON.parse(readFileSync(paths.configPath, "utf8"));
|
|
83
|
+
return {
|
|
84
|
+
alias: typeof raw.alias === "string" && raw.alias.trim() ? raw.alias.trim() : defaults.alias,
|
|
85
|
+
host: typeof raw.host === "string" && raw.host.trim() ? raw.host.trim() : defaults.host,
|
|
86
|
+
port: typeof raw.port === "number" ? raw.port : defaults.port,
|
|
87
|
+
rootPath: typeof raw.rootPath === "string" && raw.rootPath.trim() ? raw.rootPath.trim() : defaults.rootPath,
|
|
88
|
+
pollIntervalMs: typeof raw.pollIntervalMs === "number" && raw.pollIntervalMs > 0 ? raw.pollIntervalMs : defaults.pollIntervalMs,
|
|
89
|
+
connectTimeoutSeconds: typeof raw.connectTimeoutSeconds === "number" && raw.connectTimeoutSeconds > 0 ? raw.connectTimeoutSeconds : defaults.connectTimeoutSeconds
|
|
90
|
+
};
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function writeMountConfig(config) {
|
|
96
|
+
const paths = getMountPaths(config.rootPath);
|
|
97
|
+
ensureMountDirectories(paths);
|
|
98
|
+
writeJSONFile(paths.configPath, config);
|
|
99
|
+
}
|
|
100
|
+
function readMountStatusSnapshot(rootPath = getDefaultMountRoot()) {
|
|
101
|
+
const paths = getMountPaths(rootPath);
|
|
102
|
+
if (!existsSync(paths.statusPath)) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
return JSON.parse(readFileSync(paths.statusPath, "utf8"));
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function writeMountStatusSnapshot(snapshot, rootPath = getDefaultMountRoot()) {
|
|
112
|
+
const paths = getMountPaths(rootPath);
|
|
113
|
+
ensureMountDirectories(paths);
|
|
114
|
+
writeJSONFile(paths.statusPath, snapshot);
|
|
115
|
+
}
|
|
116
|
+
function readMountControllerLock(rootPath = getDefaultMountRoot()) {
|
|
117
|
+
const paths = getMountPaths(rootPath);
|
|
118
|
+
if (!existsSync(paths.controllerLockPath)) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
return JSON.parse(readFileSync(paths.controllerLockPath, "utf8"));
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function writeMountControllerLock(lock, rootPath = getDefaultMountRoot()) {
|
|
128
|
+
const paths = getMountPaths(rootPath);
|
|
129
|
+
ensureMountDirectories(paths);
|
|
130
|
+
writeJSONFile(paths.controllerLockPath, lock);
|
|
131
|
+
}
|
|
132
|
+
function removeMountControllerLock(rootPath = getDefaultMountRoot()) {
|
|
133
|
+
const paths = getMountPaths(rootPath);
|
|
134
|
+
try {
|
|
135
|
+
rmSync(paths.controllerLockPath, { force: true });
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function readMountHandleMeta(handle, rootPath = getDefaultMountRoot()) {
|
|
140
|
+
const paths = getMountHandlePaths(handle, rootPath);
|
|
141
|
+
if (!existsSync(paths.metaPath)) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
return JSON.parse(readFileSync(paths.metaPath, "utf8"));
|
|
146
|
+
} catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function writeMountHandleMeta(handle, meta, rootPath = getDefaultMountRoot()) {
|
|
151
|
+
const paths = ensureHandleDirectories(handle, rootPath);
|
|
152
|
+
writeJSONFile(paths.metaPath, meta);
|
|
153
|
+
}
|
|
154
|
+
function removeMountHandleState(handle, rootPath = getDefaultMountRoot()) {
|
|
155
|
+
const paths = getMountHandlePaths(handle, rootPath);
|
|
156
|
+
try {
|
|
157
|
+
rmSync(paths.stateDir, { recursive: true, force: true });
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function writeJSONFile(path, value) {
|
|
162
|
+
const tempFile = `${path}.${process.pid}.tmp`;
|
|
163
|
+
writeFileSync(tempFile, JSON.stringify(value, null, 2), { mode: 384 });
|
|
164
|
+
renameSync(tempFile, path);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export {
|
|
168
|
+
MOUNT_SERVICE_LABEL,
|
|
169
|
+
getDefaultMountRoot,
|
|
170
|
+
getMountStateDir,
|
|
171
|
+
getMountPaths,
|
|
172
|
+
getMountHandlePaths,
|
|
173
|
+
defaultMountServiceConfig,
|
|
174
|
+
ensureMountDirectories,
|
|
175
|
+
ensureHandleDirectories,
|
|
176
|
+
readMountConfig,
|
|
177
|
+
writeMountConfig,
|
|
178
|
+
readMountStatusSnapshot,
|
|
179
|
+
writeMountStatusSnapshot,
|
|
180
|
+
readMountControllerLock,
|
|
181
|
+
writeMountControllerLock,
|
|
182
|
+
removeMountControllerLock,
|
|
183
|
+
readMountHandleMeta,
|
|
184
|
+
writeMountHandleMeta,
|
|
185
|
+
removeMountHandleState
|
|
186
|
+
};
|