@beeos-ai/cli 1.0.3 → 1.0.4
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/dist/index.js +215 -117
- package/package.json +10 -11
package/dist/index.js
CHANGED
|
@@ -67,17 +67,17 @@ function bindingPath() {
|
|
|
67
67
|
const p = getPlatformAdapter();
|
|
68
68
|
return p.joinPath(beeoHome(), "binding.json");
|
|
69
69
|
}
|
|
70
|
-
function agentDir(
|
|
70
|
+
function agentDir(agentFramework) {
|
|
71
71
|
const p = getPlatformAdapter();
|
|
72
|
-
return p.joinPath(beeoHome(), "agents",
|
|
72
|
+
return p.joinPath(beeoHome(), "agents", agentFramework);
|
|
73
73
|
}
|
|
74
|
-
function agentHome(
|
|
74
|
+
function agentHome(agentFramework) {
|
|
75
75
|
const p = getPlatformAdapter();
|
|
76
|
-
return p.joinPath(agentDir(
|
|
76
|
+
return p.joinPath(agentDir(agentFramework), "home");
|
|
77
77
|
}
|
|
78
|
-
function pidFile(
|
|
78
|
+
function pidFile(agentFramework) {
|
|
79
79
|
const p = getPlatformAdapter();
|
|
80
|
-
return p.joinPath(beeoHome(), `${
|
|
80
|
+
return p.joinPath(beeoHome(), `${agentFramework}.pid`);
|
|
81
81
|
}
|
|
82
82
|
async function loadOrCreateConfig() {
|
|
83
83
|
const p = getPlatformAdapter();
|
|
@@ -188,41 +188,54 @@ async function loadOrCreateGatewayToken() {
|
|
|
188
188
|
}
|
|
189
189
|
return token;
|
|
190
190
|
}
|
|
191
|
-
async function readPid(
|
|
191
|
+
async function readPid(agentFramework) {
|
|
192
192
|
const p = getPlatformAdapter();
|
|
193
|
-
const path2 = pidFile(
|
|
193
|
+
const path2 = pidFile(agentFramework);
|
|
194
194
|
if (!await p.exists(path2))
|
|
195
195
|
return null;
|
|
196
196
|
const raw = (await p.readFile(path2)).trim();
|
|
197
197
|
const pid = parseInt(raw, 10);
|
|
198
198
|
return isNaN(pid) ? null : pid;
|
|
199
199
|
}
|
|
200
|
-
async function writePid(
|
|
200
|
+
async function writePid(agentFramework, pid) {
|
|
201
201
|
const p = getPlatformAdapter();
|
|
202
|
-
await p.writeFile(pidFile(
|
|
202
|
+
await p.writeFile(pidFile(agentFramework), String(pid));
|
|
203
203
|
}
|
|
204
|
-
async function removePid(
|
|
204
|
+
async function removePid(agentFramework) {
|
|
205
205
|
const p = getPlatformAdapter();
|
|
206
|
-
const path2 = pidFile(
|
|
206
|
+
const path2 = pidFile(agentFramework);
|
|
207
207
|
if (await p.exists(path2)) {
|
|
208
208
|
await p.rm(path2);
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
// ../core/dist/identity/keypair.js
|
|
213
|
-
import { createHash } from "crypto";
|
|
214
213
|
import * as ed from "@noble/ed25519";
|
|
215
214
|
import { sha512 } from "@noble/hashes/sha512";
|
|
215
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
216
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
216
217
|
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
|
|
218
|
+
function toBase64(bytes) {
|
|
219
|
+
let binary = "";
|
|
220
|
+
for (let i = 0; i < bytes.length; i++)
|
|
221
|
+
binary += String.fromCharCode(bytes[i]);
|
|
222
|
+
return btoa(binary);
|
|
223
|
+
}
|
|
224
|
+
function fromBase64(b64) {
|
|
225
|
+
const binary = atob(b64);
|
|
226
|
+
const bytes = new Uint8Array(binary.length);
|
|
227
|
+
for (let i = 0; i < binary.length; i++)
|
|
228
|
+
bytes[i] = binary.charCodeAt(i);
|
|
229
|
+
return bytes;
|
|
230
|
+
}
|
|
217
231
|
function publicKeyB64(id) {
|
|
218
|
-
return
|
|
232
|
+
return toBase64(id.publicKey);
|
|
219
233
|
}
|
|
220
234
|
function fingerprint(id) {
|
|
221
|
-
return
|
|
235
|
+
return bytesToHex(sha256(id.publicKey));
|
|
222
236
|
}
|
|
223
237
|
function fingerprintFromB64(pubkeyB64) {
|
|
224
|
-
|
|
225
|
-
return createHash("sha256").update(raw).digest("hex");
|
|
238
|
+
return bytesToHex(sha256(fromBase64(pubkeyB64)));
|
|
226
239
|
}
|
|
227
240
|
async function loadOrCreateIdentity() {
|
|
228
241
|
const p = getPlatformAdapter();
|
|
@@ -240,8 +253,8 @@ async function ensureDeviceKey(keyPath) {
|
|
|
240
253
|
return;
|
|
241
254
|
const id = generate();
|
|
242
255
|
const stored = {
|
|
243
|
-
publicKey:
|
|
244
|
-
privateKey:
|
|
256
|
+
publicKey: toBase64(id.publicKey),
|
|
257
|
+
privateKey: toBase64(id.privateKey)
|
|
245
258
|
};
|
|
246
259
|
await p.mkdir(p.dirname(keyPath));
|
|
247
260
|
await p.writeFile(keyPath, JSON.stringify(stored, null, 2));
|
|
@@ -269,7 +282,7 @@ async function loadFromFile(path2) {
|
|
|
269
282
|
const p = getPlatformAdapter();
|
|
270
283
|
const raw = await p.readFile(path2);
|
|
271
284
|
const stored = JSON.parse(raw);
|
|
272
|
-
const privateKey =
|
|
285
|
+
const privateKey = fromBase64(stored.privateKey);
|
|
273
286
|
if (privateKey.length !== 32) {
|
|
274
287
|
throw new Error(`private key seed must be 32 bytes, got ${privateKey.length}`);
|
|
275
288
|
}
|
|
@@ -284,8 +297,8 @@ function generate() {
|
|
|
284
297
|
async function save(id) {
|
|
285
298
|
const p = getPlatformAdapter();
|
|
286
299
|
const stored = {
|
|
287
|
-
publicKey:
|
|
288
|
-
privateKey:
|
|
300
|
+
publicKey: toBase64(id.publicKey),
|
|
301
|
+
privateKey: toBase64(id.privateKey)
|
|
289
302
|
};
|
|
290
303
|
const kpPath = keypairPath();
|
|
291
304
|
await p.mkdir(p.dirname(kpPath));
|
|
@@ -353,7 +366,7 @@ function buildBindUrl(dashboardBaseUrl, bindId) {
|
|
|
353
366
|
const base = dashboardBaseUrl.replace(/\/+$/, "");
|
|
354
367
|
return `${base}/bind/${bindId}`;
|
|
355
368
|
}
|
|
356
|
-
async function agentBind(apiUrl, publicKey, fingerprint2,
|
|
369
|
+
async function agentBind(apiUrl, publicKey, fingerprint2, agentFramework, hostname) {
|
|
357
370
|
const p = getPlatformAdapter();
|
|
358
371
|
const url = `${apiUrl}/api/v1/agent/bind`;
|
|
359
372
|
const resp = await p.fetch(url, {
|
|
@@ -362,7 +375,7 @@ async function agentBind(apiUrl, publicKey, fingerprint2, agentType, hostname) {
|
|
|
362
375
|
body: JSON.stringify({
|
|
363
376
|
public_key: publicKey,
|
|
364
377
|
fingerprint: fingerprint2,
|
|
365
|
-
|
|
378
|
+
agent_framework: agentFramework,
|
|
366
379
|
hostname
|
|
367
380
|
})
|
|
368
381
|
});
|
|
@@ -761,7 +774,7 @@ ${stderr}`);
|
|
|
761
774
|
|
|
762
775
|
// ../core/dist/runtime/device.js
|
|
763
776
|
var deviceRuntime = {
|
|
764
|
-
|
|
777
|
+
agentFramework() {
|
|
765
778
|
return "device";
|
|
766
779
|
},
|
|
767
780
|
displayName() {
|
|
@@ -872,9 +885,9 @@ var GATEWAY_PORT = 18789;
|
|
|
872
885
|
async function isGatewayRunning() {
|
|
873
886
|
return getPlatformAdapter().tcpProbe("127.0.0.1", GATEWAY_PORT, 500);
|
|
874
887
|
}
|
|
875
|
-
async function managedBinary2(
|
|
888
|
+
async function managedBinary2(agentFramework) {
|
|
876
889
|
const p = getPlatformAdapter();
|
|
877
|
-
const base = agentDir(
|
|
890
|
+
const base = agentDir(agentFramework);
|
|
878
891
|
const currentLink = p.joinPath(base, "versions", "current");
|
|
879
892
|
if (!await p.exists(currentLink))
|
|
880
893
|
return null;
|
|
@@ -895,15 +908,35 @@ async function managedBinary2(agentType) {
|
|
|
895
908
|
const mjs = p.joinPath(resolved, "node_modules", "openclaw", "openclaw.mjs");
|
|
896
909
|
if (await p.exists(mjs))
|
|
897
910
|
return mjs;
|
|
911
|
+
const rootMjs = p.joinPath(resolved, "openclaw.mjs");
|
|
912
|
+
if (await p.exists(rootMjs))
|
|
913
|
+
return rootMjs;
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
async function readLocalPluginVersion(agentHome2) {
|
|
917
|
+
const p = getPlatformAdapter();
|
|
918
|
+
for (const rel of [
|
|
919
|
+
p.joinPath("extensions", "beeos-claw", "package.json"),
|
|
920
|
+
p.joinPath("extensions", "beeos-claw", "node_modules", "beeos-claw", "package.json")
|
|
921
|
+
]) {
|
|
922
|
+
const fullPath = p.joinPath(agentHome2, rel);
|
|
923
|
+
try {
|
|
924
|
+
const raw = await p.readFile(fullPath);
|
|
925
|
+
const parsed = JSON.parse(raw);
|
|
926
|
+
if (typeof parsed.version === "string")
|
|
927
|
+
return parsed.version;
|
|
928
|
+
} catch {
|
|
929
|
+
}
|
|
930
|
+
}
|
|
898
931
|
return null;
|
|
899
932
|
}
|
|
900
933
|
async function findAgent(driver) {
|
|
901
|
-
const managed = await managedBinary2(driver.
|
|
934
|
+
const managed = await managedBinary2(driver.agentFramework());
|
|
902
935
|
if (managed) {
|
|
903
936
|
return {
|
|
904
937
|
type: "managed",
|
|
905
938
|
binary: managed,
|
|
906
|
-
home: agentHome(driver.
|
|
939
|
+
home: agentHome(driver.agentFramework())
|
|
907
940
|
};
|
|
908
941
|
}
|
|
909
942
|
const local = await driver.detectLocal();
|
|
@@ -919,7 +952,7 @@ async function findAgent(driver) {
|
|
|
919
952
|
}
|
|
920
953
|
|
|
921
954
|
// ../core/dist/agent/downloader.js
|
|
922
|
-
async function downloadAgent(npmPackage, requestedVersion,
|
|
955
|
+
async function downloadAgent(npmPackage, requestedVersion, agentFramework, progress) {
|
|
923
956
|
const p = getPlatformAdapter();
|
|
924
957
|
const info = await fetchNpmPackageInfo(npmPackage);
|
|
925
958
|
const version = requestedVersion ?? info["dist-tags"]["latest"];
|
|
@@ -928,7 +961,7 @@ async function downloadAgent(npmPackage, requestedVersion, agentType, progress)
|
|
|
928
961
|
const verInfo = info.versions[version];
|
|
929
962
|
if (!verInfo)
|
|
930
963
|
throw new Error(`version ${version} not found in npm registry`);
|
|
931
|
-
const versionsDir = p.joinPath(agentDir(
|
|
964
|
+
const versionsDir = p.joinPath(agentDir(agentFramework), "versions");
|
|
932
965
|
const dest = p.joinPath(versionsDir, version);
|
|
933
966
|
if (await p.exists(dest)) {
|
|
934
967
|
progress.onStatus(`${npmPackage} v${version} already downloaded`);
|
|
@@ -954,19 +987,28 @@ async function downloadAgent(npmPackage, requestedVersion, agentType, progress)
|
|
|
954
987
|
}
|
|
955
988
|
return dest;
|
|
956
989
|
}
|
|
957
|
-
async function downloadPlugin(pluginPackage,
|
|
990
|
+
async function downloadPlugin(pluginPackage, agentFramework, progress, installedVersion) {
|
|
958
991
|
const p = getPlatformAdapter();
|
|
959
992
|
const info = await fetchNpmPackageInfo(pluginPackage);
|
|
960
993
|
const version = info["dist-tags"]["latest"];
|
|
961
994
|
if (!version)
|
|
962
995
|
throw new Error("no 'latest' tag for plugin");
|
|
996
|
+
if (installedVersion && semverGte(installedVersion, version)) {
|
|
997
|
+
progress.onStatus(`${pluginPackage} v${installedVersion} is up to date`);
|
|
998
|
+
const cacheDir2 = p.joinPath(agentDir(agentFramework), "beeos-claw");
|
|
999
|
+
const existing = p.joinPath(cacheDir2, version);
|
|
1000
|
+
if (await p.exists(existing))
|
|
1001
|
+
return existing;
|
|
1002
|
+
}
|
|
963
1003
|
const verInfo = info.versions[version];
|
|
964
1004
|
if (!verInfo)
|
|
965
1005
|
throw new Error("plugin version not found");
|
|
966
|
-
const cacheDir = p.joinPath(agentDir(
|
|
1006
|
+
const cacheDir = p.joinPath(agentDir(agentFramework), "beeos-claw");
|
|
967
1007
|
const dest = p.joinPath(cacheDir, version);
|
|
968
|
-
if (await p.exists(dest))
|
|
1008
|
+
if (await p.exists(dest)) {
|
|
1009
|
+
progress.onStatus(`${pluginPackage} v${version} already cached`);
|
|
969
1010
|
return dest;
|
|
1011
|
+
}
|
|
970
1012
|
progress.onStatus(`Downloading ${pluginPackage} v${version} ...`);
|
|
971
1013
|
const data = await downloadTarball(verInfo.dist.tarball);
|
|
972
1014
|
await extractTarball(data, dest);
|
|
@@ -974,6 +1016,7 @@ async function downloadPlugin(pluginPackage, agentType, progress) {
|
|
|
974
1016
|
if (await p.exists(pkgJson)) {
|
|
975
1017
|
await runNpmInstall(dest);
|
|
976
1018
|
}
|
|
1019
|
+
progress.onComplete(`${pluginPackage} v${version} ready`);
|
|
977
1020
|
return dest;
|
|
978
1021
|
}
|
|
979
1022
|
async function extractTarball(data, dest) {
|
|
@@ -1004,9 +1047,22 @@ async function runNpmInstall(dir) {
|
|
|
1004
1047
|
throw new Error(`npm install failed with exit code ${result.code}`);
|
|
1005
1048
|
}
|
|
1006
1049
|
}
|
|
1050
|
+
function semverGte(version, minVersion) {
|
|
1051
|
+
const parse2 = (s) => s.split(".").map((p) => parseInt(p, 10) || 0);
|
|
1052
|
+
const a = parse2(version);
|
|
1053
|
+
const b = parse2(minVersion);
|
|
1054
|
+
for (let i = 0; i < 3; i++) {
|
|
1055
|
+
if ((a[i] ?? 0) > (b[i] ?? 0))
|
|
1056
|
+
return true;
|
|
1057
|
+
if ((a[i] ?? 0) < (b[i] ?? 0))
|
|
1058
|
+
return false;
|
|
1059
|
+
}
|
|
1060
|
+
return true;
|
|
1061
|
+
}
|
|
1007
1062
|
|
|
1008
1063
|
// ../core/dist/agent/launcher.js
|
|
1009
|
-
import {
|
|
1064
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha256";
|
|
1065
|
+
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
|
1010
1066
|
var MAX_BACKUPS = 5;
|
|
1011
1067
|
async function backupOpenclawConfig(agentHome2) {
|
|
1012
1068
|
const p = getPlatformAdapter();
|
|
@@ -1152,6 +1208,28 @@ async function spawnOpenclaw(ctx) {
|
|
|
1152
1208
|
});
|
|
1153
1209
|
return result.pid;
|
|
1154
1210
|
}
|
|
1211
|
+
async function installPluginToHome(agentHome2, pluginDir) {
|
|
1212
|
+
const p = getPlatformAdapter();
|
|
1213
|
+
const dest = p.joinPath(agentHome2, "extensions", "beeos-claw");
|
|
1214
|
+
if (await p.exists(dest)) {
|
|
1215
|
+
await p.rmdir(dest);
|
|
1216
|
+
}
|
|
1217
|
+
await copyDirRecursive(pluginDir, dest);
|
|
1218
|
+
}
|
|
1219
|
+
async function copyDirRecursive(src, dst) {
|
|
1220
|
+
const p = getPlatformAdapter();
|
|
1221
|
+
await p.mkdir(dst);
|
|
1222
|
+
const entries = await p.readdir(src);
|
|
1223
|
+
for (const name of entries) {
|
|
1224
|
+
const srcPath = p.joinPath(src, name);
|
|
1225
|
+
const dstPath = p.joinPath(dst, name);
|
|
1226
|
+
if (await p.isDirectory(srcPath)) {
|
|
1227
|
+
await copyDirRecursive(srcPath, dstPath);
|
|
1228
|
+
} else {
|
|
1229
|
+
await p.copyFile(srcPath, dstPath);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1155
1233
|
async function writePairedJson(home, keyFile) {
|
|
1156
1234
|
const p = getPlatformAdapter();
|
|
1157
1235
|
const devicesDir = p.joinPath(home, "devices");
|
|
@@ -1167,8 +1245,11 @@ async function writePairedJson(home, keyFile) {
|
|
|
1167
1245
|
}
|
|
1168
1246
|
let deviceId = "beeos-claw-device";
|
|
1169
1247
|
if (pubKeyB64) {
|
|
1170
|
-
const
|
|
1171
|
-
const
|
|
1248
|
+
const binary = atob(pubKeyB64);
|
|
1249
|
+
const decoded = new Uint8Array(binary.length);
|
|
1250
|
+
for (let i = 0; i < binary.length; i++)
|
|
1251
|
+
decoded[i] = binary.charCodeAt(i);
|
|
1252
|
+
const hash = bytesToHex2(sha2562(decoded));
|
|
1172
1253
|
deviceId = `beeos-claw-${hash.slice(0, 12)}`;
|
|
1173
1254
|
}
|
|
1174
1255
|
const paired = {
|
|
@@ -1188,7 +1269,7 @@ async function writePairedJson(home, keyFile) {
|
|
|
1188
1269
|
|
|
1189
1270
|
// ../core/dist/agent/registry.js
|
|
1190
1271
|
var openClawDriver = {
|
|
1191
|
-
|
|
1272
|
+
agentFramework() {
|
|
1192
1273
|
return "openclaw";
|
|
1193
1274
|
},
|
|
1194
1275
|
npmPackage() {
|
|
@@ -1223,7 +1304,7 @@ var openClawDriver = {
|
|
|
1223
1304
|
// ../core/dist/runtime/openclaw.js
|
|
1224
1305
|
var GATEWAY_PORT2 = 18789;
|
|
1225
1306
|
var openclawRuntime = {
|
|
1226
|
-
|
|
1307
|
+
agentFramework() {
|
|
1227
1308
|
return "openclaw";
|
|
1228
1309
|
},
|
|
1229
1310
|
displayName() {
|
|
@@ -1259,11 +1340,11 @@ var openclawRuntime = {
|
|
|
1259
1340
|
async isHealthy() {
|
|
1260
1341
|
return getPlatformAdapter().tcpProbe("127.0.0.1", GATEWAY_PORT2, 500);
|
|
1261
1342
|
},
|
|
1262
|
-
async stop(
|
|
1263
|
-
const pid = await readPid(
|
|
1343
|
+
async stop(agentFramework) {
|
|
1344
|
+
const pid = await readPid(agentFramework);
|
|
1264
1345
|
if (pid != null) {
|
|
1265
1346
|
killProcess(pid);
|
|
1266
|
-
await removePid(
|
|
1347
|
+
await removePid(agentFramework);
|
|
1267
1348
|
}
|
|
1268
1349
|
},
|
|
1269
1350
|
async update(progress) {
|
|
@@ -1272,6 +1353,48 @@ var openclawRuntime = {
|
|
|
1272
1353
|
}
|
|
1273
1354
|
};
|
|
1274
1355
|
|
|
1356
|
+
// ../core/dist/service/local-agent.js
|
|
1357
|
+
async function ensurePlugin(agentFramework, agentHomeDir, progress) {
|
|
1358
|
+
const currentVersion = await readLocalPluginVersion(agentHomeDir) ?? void 0;
|
|
1359
|
+
const pluginDir = await downloadPlugin(openClawDriver.pluginPackage(), agentFramework, progress, currentVersion);
|
|
1360
|
+
await installPluginToHome(agentHomeDir, pluginDir);
|
|
1361
|
+
}
|
|
1362
|
+
async function bind(options) {
|
|
1363
|
+
const resp = await agentBind(options.apiUrl, options.publicKey, options.fingerprint, options.agentFramework, options.hostname);
|
|
1364
|
+
if (resp.status === "bound") {
|
|
1365
|
+
const instanceId = resp.instance_id ?? "";
|
|
1366
|
+
await saveBindingInfo({
|
|
1367
|
+
fingerprint: options.fingerprint,
|
|
1368
|
+
instance_id: instanceId,
|
|
1369
|
+
bound_at: Math.floor(Date.now() / 1e3)
|
|
1370
|
+
});
|
|
1371
|
+
return { status: "bound", instanceId };
|
|
1372
|
+
}
|
|
1373
|
+
if (resp.status === "pending") {
|
|
1374
|
+
const bindId = resp.bind_id ?? "";
|
|
1375
|
+
const bindUrl = buildBindUrl(options.dashboardBaseUrl, bindId);
|
|
1376
|
+
await removeBindingInfo();
|
|
1377
|
+
if (options.confirmFn) {
|
|
1378
|
+
const instanceId2 = await options.confirmFn(bindId);
|
|
1379
|
+
await saveBindingInfo({
|
|
1380
|
+
fingerprint: options.fingerprint,
|
|
1381
|
+
instance_id: instanceId2,
|
|
1382
|
+
bound_at: Math.floor(Date.now() / 1e3)
|
|
1383
|
+
});
|
|
1384
|
+
return { status: "bound", instanceId: instanceId2 };
|
|
1385
|
+
}
|
|
1386
|
+
await presentBindUrl(bindUrl, options.headless ?? false);
|
|
1387
|
+
const instanceId = await pollUntilBound(options.apiUrl, bindId, 6e5);
|
|
1388
|
+
await saveBindingInfo({
|
|
1389
|
+
fingerprint: options.fingerprint,
|
|
1390
|
+
instance_id: instanceId,
|
|
1391
|
+
bound_at: Math.floor(Date.now() / 1e3)
|
|
1392
|
+
});
|
|
1393
|
+
return { status: "bound", instanceId };
|
|
1394
|
+
}
|
|
1395
|
+
throw new Error(`unexpected bind status: ${resp.status}`);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1275
1398
|
// src/node-adapter.ts
|
|
1276
1399
|
import {
|
|
1277
1400
|
execFile,
|
|
@@ -1515,13 +1638,13 @@ var CliReporter = class {
|
|
|
1515
1638
|
};
|
|
1516
1639
|
|
|
1517
1640
|
// src/commands/start.ts
|
|
1518
|
-
async function run(
|
|
1641
|
+
async function run(agentFramework, options) {
|
|
1519
1642
|
const p = getPlatformAdapter();
|
|
1520
1643
|
await ensureDirs();
|
|
1521
1644
|
const cfg = await loadOrCreateConfig();
|
|
1522
1645
|
const reporter = new CliReporter();
|
|
1523
|
-
if (
|
|
1524
|
-
throw new Error(`Agent
|
|
1646
|
+
if (agentFramework !== "openclaw") {
|
|
1647
|
+
throw new Error(`Agent framework '${agentFramework}' is not yet supported. Use 'openclaw'.`);
|
|
1525
1648
|
}
|
|
1526
1649
|
const identity = await loadOrCreateIdentity();
|
|
1527
1650
|
const fp = fingerprint(identity);
|
|
@@ -1536,13 +1659,16 @@ async function run(agentType, options) {
|
|
|
1536
1659
|
if (location.type === "managed") {
|
|
1537
1660
|
binary = location.binary;
|
|
1538
1661
|
home = location.home;
|
|
1662
|
+
try {
|
|
1663
|
+
await ensurePlugin(agentFramework, home, reporter);
|
|
1664
|
+
} catch {
|
|
1665
|
+
}
|
|
1539
1666
|
} else if (location.type === "system") {
|
|
1540
1667
|
binary = location.binary;
|
|
1541
1668
|
home = location.home;
|
|
1542
1669
|
isSystemHome = true;
|
|
1543
1670
|
try {
|
|
1544
|
-
|
|
1545
|
-
await installPluginToHome(home, pluginDir, binary);
|
|
1671
|
+
await ensurePlugin(agentFramework, home, reporter);
|
|
1546
1672
|
} catch {
|
|
1547
1673
|
}
|
|
1548
1674
|
const systemToken = await readExistingGatewayToken(home);
|
|
@@ -1569,11 +1695,11 @@ async function run(agentType, options) {
|
|
|
1569
1695
|
}
|
|
1570
1696
|
} else {
|
|
1571
1697
|
reporter.onStatus(`Downloading ${openClawDriver.npmPackage()}...`);
|
|
1572
|
-
await downloadAgent(openClawDriver.npmPackage(), options.version ?? void 0,
|
|
1573
|
-
home = agentHome(
|
|
1698
|
+
await downloadAgent(openClawDriver.npmPackage(), options.version ?? void 0, agentFramework, reporter);
|
|
1699
|
+
home = agentHome(agentFramework);
|
|
1574
1700
|
await p.mkdir(home);
|
|
1575
|
-
await
|
|
1576
|
-
const managedBin = await managedBinary2(
|
|
1701
|
+
await ensurePlugin(agentFramework, home, reporter);
|
|
1702
|
+
const managedBin = await managedBinary2(agentFramework);
|
|
1577
1703
|
if (!managedBin) throw new Error("agent binary not found after download");
|
|
1578
1704
|
binary = managedBin;
|
|
1579
1705
|
}
|
|
@@ -1595,7 +1721,7 @@ async function run(agentType, options) {
|
|
|
1595
1721
|
await generateOpenclawConfig(ctx);
|
|
1596
1722
|
}
|
|
1597
1723
|
const pid = await spawnOpenclaw(ctx);
|
|
1598
|
-
await writePid(
|
|
1724
|
+
await writePid(agentFramework, pid);
|
|
1599
1725
|
gatewayPid = pid;
|
|
1600
1726
|
let alive = false;
|
|
1601
1727
|
for (let i = 0; i < 10; i++) {
|
|
@@ -1609,55 +1735,52 @@ async function run(agentType, options) {
|
|
|
1609
1735
|
throw new Error("Agent gateway did not start within 5s");
|
|
1610
1736
|
}
|
|
1611
1737
|
} else {
|
|
1612
|
-
gatewayPid = await readPid(
|
|
1738
|
+
gatewayPid = await readPid(agentFramework) ?? void 0;
|
|
1613
1739
|
}
|
|
1614
1740
|
const hostname = buildHostname();
|
|
1615
1741
|
try {
|
|
1616
|
-
const
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1742
|
+
const result = await bind({
|
|
1743
|
+
apiUrl: cfg.platform.api_url,
|
|
1744
|
+
dashboardBaseUrl: cfg.platform.dashboard_base_url,
|
|
1745
|
+
publicKey: pubkey,
|
|
1746
|
+
fingerprint: fp,
|
|
1747
|
+
agentFramework,
|
|
1748
|
+
hostname,
|
|
1749
|
+
headless: options.browser === false
|
|
1750
|
+
});
|
|
1751
|
+
if (result.status === "bound") {
|
|
1752
|
+
const out = {
|
|
1621
1753
|
status: "bound",
|
|
1622
1754
|
public_key: pubkey,
|
|
1623
1755
|
fingerprint: fp,
|
|
1624
1756
|
gateway_url: "http://127.0.0.1:18789",
|
|
1625
1757
|
gateway_pid: gatewayPid,
|
|
1626
1758
|
bridge_url: cfg.platform.bridge_url,
|
|
1627
|
-
instance_id: instanceId
|
|
1759
|
+
instance_id: result.instanceId
|
|
1628
1760
|
};
|
|
1629
1761
|
if (options.json) {
|
|
1630
|
-
console.log(JSON.stringify(
|
|
1762
|
+
console.log(JSON.stringify(out, null, 2));
|
|
1631
1763
|
} else {
|
|
1632
|
-
console.log(`Agent bound to instance: ${instanceId}`);
|
|
1764
|
+
console.log(`Agent bound to instance: ${result.instanceId}`);
|
|
1633
1765
|
}
|
|
1634
1766
|
return;
|
|
1635
1767
|
}
|
|
1636
|
-
if (
|
|
1637
|
-
const bindId = resp.bind_id ?? "";
|
|
1638
|
-
const bindUrl = buildBindUrl(cfg.platform.dashboard_base_url, bindId);
|
|
1639
|
-
await removeBindingInfo();
|
|
1768
|
+
if (result.status === "pending") {
|
|
1640
1769
|
if (options.json) {
|
|
1641
|
-
const
|
|
1770
|
+
const out = {
|
|
1642
1771
|
status: "pending",
|
|
1643
1772
|
public_key: pubkey,
|
|
1644
1773
|
fingerprint: fp,
|
|
1645
|
-
bind_id: bindId,
|
|
1646
|
-
bind_url: bindUrl,
|
|
1647
|
-
qr_data: bindUrl,
|
|
1774
|
+
bind_id: result.bindId,
|
|
1775
|
+
bind_url: result.bindUrl,
|
|
1776
|
+
qr_data: result.bindUrl,
|
|
1648
1777
|
gateway_url: "http://127.0.0.1:18789",
|
|
1649
1778
|
gateway_pid: gatewayPid,
|
|
1650
1779
|
bridge_url: cfg.platform.bridge_url
|
|
1651
1780
|
};
|
|
1652
|
-
console.log(JSON.stringify(
|
|
1781
|
+
console.log(JSON.stringify(out, null, 2));
|
|
1653
1782
|
return;
|
|
1654
1783
|
}
|
|
1655
|
-
await presentBindUrl(bindUrl, options.browser === false);
|
|
1656
|
-
console.log("");
|
|
1657
|
-
console.log(" Waiting for bind approval (timeout: 10min)...");
|
|
1658
|
-
const instanceId = await pollUntilBound(cfg.platform.api_url, bindId, 6e5);
|
|
1659
|
-
await saveBindingInfo({ fingerprint: fp, instance_id: instanceId, bound_at: nowUnix() });
|
|
1660
|
-
console.log(` Bind confirmed! Instance: ${instanceId}`);
|
|
1661
1784
|
}
|
|
1662
1785
|
} catch (e) {
|
|
1663
1786
|
const cached = await loadBindingInfo();
|
|
@@ -1680,50 +1803,25 @@ async function run(agentType, options) {
|
|
|
1680
1803
|
throw new Error(`Cannot reach platform to bind agent: ${e}`);
|
|
1681
1804
|
}
|
|
1682
1805
|
}
|
|
1683
|
-
async function installPluginToHome(home, pluginDir, binary) {
|
|
1684
|
-
const p = getPlatformAdapter();
|
|
1685
|
-
const dest = p.joinPath(home, "extensions", "beeos-claw");
|
|
1686
|
-
if (await p.exists(dest)) {
|
|
1687
|
-
await p.rmdir(dest);
|
|
1688
|
-
}
|
|
1689
|
-
await copyDirRecursive(pluginDir, dest);
|
|
1690
|
-
}
|
|
1691
|
-
async function copyDirRecursive(src, dst) {
|
|
1692
|
-
const p = getPlatformAdapter();
|
|
1693
|
-
await p.mkdir(dst);
|
|
1694
|
-
const entries = await p.readdir(src);
|
|
1695
|
-
for (const name of entries) {
|
|
1696
|
-
const srcPath = p.joinPath(src, name);
|
|
1697
|
-
const dstPath = p.joinPath(dst, name);
|
|
1698
|
-
if (await p.isDirectory(srcPath)) {
|
|
1699
|
-
await copyDirRecursive(srcPath, dstPath);
|
|
1700
|
-
} else {
|
|
1701
|
-
await p.copyFile(srcPath, dstPath);
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
1806
|
function buildHostname() {
|
|
1706
1807
|
const machine = os2.hostname();
|
|
1707
1808
|
const user = process.env.USER || process.env.USERNAME || "";
|
|
1708
1809
|
return user ? `${user}@${machine}` : machine;
|
|
1709
1810
|
}
|
|
1710
|
-
function nowUnix() {
|
|
1711
|
-
return Math.floor(Date.now() / 1e3);
|
|
1712
|
-
}
|
|
1713
1811
|
function sleep2(ms) {
|
|
1714
1812
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1715
1813
|
}
|
|
1716
1814
|
|
|
1717
1815
|
// src/commands/stop.ts
|
|
1718
|
-
async function run2(
|
|
1719
|
-
const pid = await readPid(
|
|
1816
|
+
async function run2(agentFramework) {
|
|
1817
|
+
const pid = await readPid(agentFramework);
|
|
1720
1818
|
if (pid == null) {
|
|
1721
|
-
console.log(`No running ${
|
|
1819
|
+
console.log(`No running ${agentFramework} agent found`);
|
|
1722
1820
|
return;
|
|
1723
1821
|
}
|
|
1724
1822
|
killProcess(pid);
|
|
1725
|
-
await removePid(
|
|
1726
|
-
console.log(`Stopped ${
|
|
1823
|
+
await removePid(agentFramework);
|
|
1824
|
+
console.log(`Stopped ${agentFramework} agent (pid ${pid})`);
|
|
1727
1825
|
}
|
|
1728
1826
|
|
|
1729
1827
|
// src/commands/status.ts
|
|
@@ -1757,25 +1855,25 @@ async function run3() {
|
|
|
1757
1855
|
}
|
|
1758
1856
|
|
|
1759
1857
|
// src/commands/update.ts
|
|
1760
|
-
async function run4(
|
|
1858
|
+
async function run4(agentFramework) {
|
|
1761
1859
|
const reporter = new CliReporter();
|
|
1762
|
-
const pid = await readPid(
|
|
1860
|
+
const pid = await readPid(agentFramework);
|
|
1763
1861
|
const wasRunning = pid != null && isProcessAlive(pid);
|
|
1764
1862
|
if (wasRunning) {
|
|
1765
|
-
await run2(
|
|
1863
|
+
await run2(agentFramework);
|
|
1766
1864
|
}
|
|
1767
|
-
if (
|
|
1865
|
+
if (agentFramework === "openclaw") {
|
|
1768
1866
|
await openclawRuntime.update(reporter);
|
|
1769
|
-
} else if (
|
|
1867
|
+
} else if (agentFramework === "device") {
|
|
1770
1868
|
await deviceRuntime.update(reporter);
|
|
1771
1869
|
} else {
|
|
1772
|
-
throw new Error(`Unknown agent
|
|
1870
|
+
throw new Error(`Unknown agent framework: ${agentFramework}`);
|
|
1773
1871
|
}
|
|
1774
1872
|
reporter.stop();
|
|
1775
|
-
console.log(`${
|
|
1873
|
+
console.log(`${agentFramework} updated`);
|
|
1776
1874
|
if (wasRunning) {
|
|
1777
1875
|
console.log("Restarting agent...");
|
|
1778
|
-
await run(
|
|
1876
|
+
await run(agentFramework, { force: true });
|
|
1779
1877
|
}
|
|
1780
1878
|
}
|
|
1781
1879
|
|
|
@@ -2116,10 +2214,10 @@ function sleep3(ms) {
|
|
|
2116
2214
|
setPlatformAdapter(new NodePlatformAdapter());
|
|
2117
2215
|
var program = new Command();
|
|
2118
2216
|
program.name("beeos").version("1.0.0").description("BeeOS \u2014 run AI agents from your desktop");
|
|
2119
|
-
program.command("start").description("Install and start an agent").argument("<agent_type>", "Agent type to start (e.g. openclaw)").option("--version <version>", "Pin to a specific version instead of latest").option("--force", "Skip confirmation prompts", false).option("--json", "Output machine-readable JSON to stdout (implies --force)", false).option("--no-browser", "Don't auto-open browser for bind confirmation").action(run);
|
|
2120
|
-
program.command("stop").description("Stop a running agent").argument("<agent_type>", "Agent type to stop").action(run2);
|
|
2217
|
+
program.command("start").description("Install and start an agent").argument("<agent_type>", "Agent type to start (e.g. openclaw)").option("--version <version>", "Pin to a specific version instead of latest").option("--force", "Skip confirmation prompts", false).option("--json", "Output machine-readable JSON to stdout (implies --force)", false).option("--no-browser", "Don't auto-open browser for bind confirmation").action((agentFramework, options) => run(agentFramework, options));
|
|
2218
|
+
program.command("stop").description("Stop a running agent").argument("<agent_type>", "Agent type to stop").action((agentFramework) => run2(agentFramework));
|
|
2121
2219
|
program.command("status").description("Show status of managed agents").action(run3);
|
|
2122
|
-
program.command("update").description("Update an agent to the latest version").argument("<agent_type>", "Agent type to update").action(run4);
|
|
2220
|
+
program.command("update").description("Update an agent to the latest version").argument("<agent_type>", "Agent type to update").action((agentFramework) => run4(agentFramework));
|
|
2123
2221
|
program.command("bind-status").description("Check agent binding status").argument("<bind_id>", "Bind session ID returned by `beeos start --json`").option("--json", "Output machine-readable JSON", false).action(run5);
|
|
2124
2222
|
var deviceCmd = program.command("device").description("Manage device agents (Android/Desktop/ChromeOS)");
|
|
2125
2223
|
deviceCmd.command("attach").description("Attach an ADB-connected device as an AI agent").option("--serial <serial>", "ADB device serial number").option("--name <name>", "Human-readable device name").option("--all", "Attach all connected ADB devices", false).action(attach);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beeos-ai/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "BeeOS CLI — run AI agents from your desktop",
|
|
6
6
|
"bin": {
|
|
@@ -13,13 +13,6 @@
|
|
|
13
13
|
"dist/",
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "tsup",
|
|
18
|
-
"type-check": "tsc --noEmit",
|
|
19
|
-
"lint": "eslint src/",
|
|
20
|
-
"test": "vitest run --passWithNoTests",
|
|
21
|
-
"prepublishOnly": "pnpm build"
|
|
22
|
-
},
|
|
23
16
|
"dependencies": {
|
|
24
17
|
"@noble/ed25519": "^2.2.0",
|
|
25
18
|
"@noble/hashes": "^1.7.0",
|
|
@@ -33,19 +26,25 @@
|
|
|
33
26
|
"which": "^5.0.0"
|
|
34
27
|
},
|
|
35
28
|
"devDependencies": {
|
|
36
|
-
"@beeos/core": "workspace:*",
|
|
37
29
|
"@types/node": "^22.0.0",
|
|
38
30
|
"@types/proper-lockfile": "^4.1.4",
|
|
39
31
|
"@types/qrcode": "^1.5.5",
|
|
40
32
|
"@types/which": "^3.0.4",
|
|
41
33
|
"tsup": "^8.3.0",
|
|
42
34
|
"typescript": "^5.7.0",
|
|
43
|
-
"vitest": "^3.0.0"
|
|
35
|
+
"vitest": "^3.0.0",
|
|
36
|
+
"@beeos/core": "0.1.0"
|
|
44
37
|
},
|
|
45
38
|
"engines": {
|
|
46
39
|
"node": ">=18"
|
|
47
40
|
},
|
|
48
41
|
"publishConfig": {
|
|
49
42
|
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"type-check": "tsc --noEmit",
|
|
47
|
+
"lint": "eslint src/",
|
|
48
|
+
"test": "vitest run --passWithNoTests"
|
|
50
49
|
}
|
|
51
|
-
}
|
|
50
|
+
}
|