aicomputer 0.1.14 → 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 +8 -2
- 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 +730 -644
- 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 +4 -3
package/README.md
CHANGED
|
@@ -91,13 +91,14 @@ computer codex-login
|
|
|
91
91
|
computer whoami
|
|
92
92
|
computer create my-box
|
|
93
93
|
computer open my-box
|
|
94
|
-
computer open my-box --terminal
|
|
95
94
|
computer ssh
|
|
96
95
|
computer ssh my-box
|
|
97
96
|
computer ssh --setup
|
|
97
|
+
computer mount
|
|
98
|
+
computer mount status
|
|
98
99
|
computer agent agents my-box
|
|
99
100
|
computer agent sessions list my-box
|
|
100
|
-
computer agent prompt my-box "inspect /home/node
|
|
101
|
+
computer agent prompt my-box "inspect /home/node" --agent codex
|
|
101
102
|
computer acp serve my-box --agent codex
|
|
102
103
|
```
|
|
103
104
|
|
|
@@ -116,6 +117,11 @@ ssh agentcomputer.ai
|
|
|
116
117
|
ssh my-box@agentcomputer.ai
|
|
117
118
|
```
|
|
118
119
|
|
|
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
|
+
|
|
119
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.
|
|
120
126
|
|
|
121
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
|
+
};
|