@beeos-ai/cli 1.0.2 → 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 +238 -131
- package/package.json +15 -15
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
|
});
|
|
@@ -560,22 +573,14 @@ async function upgradeDeviceAgent(progress) {
|
|
|
560
573
|
}
|
|
561
574
|
async function findExisting() {
|
|
562
575
|
const p = getPlatformAdapter();
|
|
576
|
+
const whichCmd = p.platform() === "win32" ? "where" : "which";
|
|
563
577
|
try {
|
|
564
|
-
const result = await p.exec(
|
|
578
|
+
const result = await p.exec(whichCmd, ["device-agent"]);
|
|
565
579
|
if (result.code === 0 && result.stdout.trim()) {
|
|
566
|
-
return { type: "executable", path: result.stdout.trim() };
|
|
580
|
+
return { type: "executable", path: result.stdout.trim().split("\n")[0].trim() };
|
|
567
581
|
}
|
|
568
582
|
} catch {
|
|
569
583
|
}
|
|
570
|
-
if (p.platform() === "win32") {
|
|
571
|
-
try {
|
|
572
|
-
const result = await p.exec("where", ["device-agent"]);
|
|
573
|
-
if (result.code === 0 && result.stdout.trim()) {
|
|
574
|
-
return { type: "executable", path: result.stdout.trim().split("\n")[0].trim() };
|
|
575
|
-
}
|
|
576
|
-
} catch {
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
584
|
const managed = managedBinary();
|
|
580
585
|
if (await p.exists(managed)) {
|
|
581
586
|
return { type: "executable", path: managed };
|
|
@@ -665,7 +670,7 @@ async function installWithPython(progress, venv, source, python) {
|
|
|
665
670
|
async function installSource() {
|
|
666
671
|
const p = getPlatformAdapter();
|
|
667
672
|
try {
|
|
668
|
-
const cwd = p.
|
|
673
|
+
const cwd = p.cwd();
|
|
669
674
|
let dir = cwd;
|
|
670
675
|
for (let i = 0; i < 10; i++) {
|
|
671
676
|
const da = p.joinPath(dir, "agents", "device-agent", "pyproject.toml");
|
|
@@ -769,7 +774,7 @@ ${stderr}`);
|
|
|
769
774
|
|
|
770
775
|
// ../core/dist/runtime/device.js
|
|
771
776
|
var deviceRuntime = {
|
|
772
|
-
|
|
777
|
+
agentFramework() {
|
|
773
778
|
return "device";
|
|
774
779
|
},
|
|
775
780
|
displayName() {
|
|
@@ -880,9 +885,9 @@ var GATEWAY_PORT = 18789;
|
|
|
880
885
|
async function isGatewayRunning() {
|
|
881
886
|
return getPlatformAdapter().tcpProbe("127.0.0.1", GATEWAY_PORT, 500);
|
|
882
887
|
}
|
|
883
|
-
async function managedBinary2(
|
|
888
|
+
async function managedBinary2(agentFramework) {
|
|
884
889
|
const p = getPlatformAdapter();
|
|
885
|
-
const base = agentDir(
|
|
890
|
+
const base = agentDir(agentFramework);
|
|
886
891
|
const currentLink = p.joinPath(base, "versions", "current");
|
|
887
892
|
if (!await p.exists(currentLink))
|
|
888
893
|
return null;
|
|
@@ -893,20 +898,45 @@ async function managedBinary2(agentType) {
|
|
|
893
898
|
resolved = currentLink;
|
|
894
899
|
}
|
|
895
900
|
const binShim = p.joinPath(resolved, "node_modules", ".bin", "openclaw");
|
|
901
|
+
if (p.platform() === "win32") {
|
|
902
|
+
const cmdShim = binShim + ".cmd";
|
|
903
|
+
if (await p.exists(cmdShim))
|
|
904
|
+
return cmdShim;
|
|
905
|
+
}
|
|
896
906
|
if (await p.exists(binShim))
|
|
897
907
|
return binShim;
|
|
898
908
|
const mjs = p.joinPath(resolved, "node_modules", "openclaw", "openclaw.mjs");
|
|
899
909
|
if (await p.exists(mjs))
|
|
900
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
|
+
}
|
|
901
931
|
return null;
|
|
902
932
|
}
|
|
903
933
|
async function findAgent(driver) {
|
|
904
|
-
const managed = await managedBinary2(driver.
|
|
934
|
+
const managed = await managedBinary2(driver.agentFramework());
|
|
905
935
|
if (managed) {
|
|
906
936
|
return {
|
|
907
937
|
type: "managed",
|
|
908
938
|
binary: managed,
|
|
909
|
-
home: agentHome(driver.
|
|
939
|
+
home: agentHome(driver.agentFramework())
|
|
910
940
|
};
|
|
911
941
|
}
|
|
912
942
|
const local = await driver.detectLocal();
|
|
@@ -922,7 +952,7 @@ async function findAgent(driver) {
|
|
|
922
952
|
}
|
|
923
953
|
|
|
924
954
|
// ../core/dist/agent/downloader.js
|
|
925
|
-
async function downloadAgent(npmPackage, requestedVersion,
|
|
955
|
+
async function downloadAgent(npmPackage, requestedVersion, agentFramework, progress) {
|
|
926
956
|
const p = getPlatformAdapter();
|
|
927
957
|
const info = await fetchNpmPackageInfo(npmPackage);
|
|
928
958
|
const version = requestedVersion ?? info["dist-tags"]["latest"];
|
|
@@ -931,7 +961,7 @@ async function downloadAgent(npmPackage, requestedVersion, agentType, progress)
|
|
|
931
961
|
const verInfo = info.versions[version];
|
|
932
962
|
if (!verInfo)
|
|
933
963
|
throw new Error(`version ${version} not found in npm registry`);
|
|
934
|
-
const versionsDir = p.joinPath(agentDir(
|
|
964
|
+
const versionsDir = p.joinPath(agentDir(agentFramework), "versions");
|
|
935
965
|
const dest = p.joinPath(versionsDir, version);
|
|
936
966
|
if (await p.exists(dest)) {
|
|
937
967
|
progress.onStatus(`${npmPackage} v${version} already downloaded`);
|
|
@@ -957,19 +987,28 @@ async function downloadAgent(npmPackage, requestedVersion, agentType, progress)
|
|
|
957
987
|
}
|
|
958
988
|
return dest;
|
|
959
989
|
}
|
|
960
|
-
async function downloadPlugin(pluginPackage,
|
|
990
|
+
async function downloadPlugin(pluginPackage, agentFramework, progress, installedVersion) {
|
|
961
991
|
const p = getPlatformAdapter();
|
|
962
992
|
const info = await fetchNpmPackageInfo(pluginPackage);
|
|
963
993
|
const version = info["dist-tags"]["latest"];
|
|
964
994
|
if (!version)
|
|
965
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
|
+
}
|
|
966
1003
|
const verInfo = info.versions[version];
|
|
967
1004
|
if (!verInfo)
|
|
968
1005
|
throw new Error("plugin version not found");
|
|
969
|
-
const cacheDir = p.joinPath(agentDir(
|
|
1006
|
+
const cacheDir = p.joinPath(agentDir(agentFramework), "beeos-claw");
|
|
970
1007
|
const dest = p.joinPath(cacheDir, version);
|
|
971
|
-
if (await p.exists(dest))
|
|
1008
|
+
if (await p.exists(dest)) {
|
|
1009
|
+
progress.onStatus(`${pluginPackage} v${version} already cached`);
|
|
972
1010
|
return dest;
|
|
1011
|
+
}
|
|
973
1012
|
progress.onStatus(`Downloading ${pluginPackage} v${version} ...`);
|
|
974
1013
|
const data = await downloadTarball(verInfo.dist.tarball);
|
|
975
1014
|
await extractTarball(data, dest);
|
|
@@ -977,6 +1016,7 @@ async function downloadPlugin(pluginPackage, agentType, progress) {
|
|
|
977
1016
|
if (await p.exists(pkgJson)) {
|
|
978
1017
|
await runNpmInstall(dest);
|
|
979
1018
|
}
|
|
1019
|
+
progress.onComplete(`${pluginPackage} v${version} ready`);
|
|
980
1020
|
return dest;
|
|
981
1021
|
}
|
|
982
1022
|
async function extractTarball(data, dest) {
|
|
@@ -985,7 +1025,12 @@ async function extractTarball(data, dest) {
|
|
|
985
1025
|
const tmpFile = p.joinPath(dest, "__tmp.tgz");
|
|
986
1026
|
await p.writeFileBytes(tmpFile, data);
|
|
987
1027
|
try {
|
|
988
|
-
|
|
1028
|
+
try {
|
|
1029
|
+
const tar = await import("tar");
|
|
1030
|
+
await tar.extract({ file: tmpFile, cwd: dest, strip: 1 });
|
|
1031
|
+
} catch {
|
|
1032
|
+
await p.exec("tar", ["-xzf", tmpFile, "--strip-components=1", "-C", dest]);
|
|
1033
|
+
}
|
|
989
1034
|
} finally {
|
|
990
1035
|
try {
|
|
991
1036
|
await p.rm(tmpFile);
|
|
@@ -1002,9 +1047,22 @@ async function runNpmInstall(dir) {
|
|
|
1002
1047
|
throw new Error(`npm install failed with exit code ${result.code}`);
|
|
1003
1048
|
}
|
|
1004
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
|
+
}
|
|
1005
1062
|
|
|
1006
1063
|
// ../core/dist/agent/launcher.js
|
|
1007
|
-
import {
|
|
1064
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha256";
|
|
1065
|
+
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
|
1008
1066
|
var MAX_BACKUPS = 5;
|
|
1009
1067
|
async function backupOpenclawConfig(agentHome2) {
|
|
1010
1068
|
const p = getPlatformAdapter();
|
|
@@ -1150,6 +1208,28 @@ async function spawnOpenclaw(ctx) {
|
|
|
1150
1208
|
});
|
|
1151
1209
|
return result.pid;
|
|
1152
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
|
+
}
|
|
1153
1233
|
async function writePairedJson(home, keyFile) {
|
|
1154
1234
|
const p = getPlatformAdapter();
|
|
1155
1235
|
const devicesDir = p.joinPath(home, "devices");
|
|
@@ -1165,8 +1245,11 @@ async function writePairedJson(home, keyFile) {
|
|
|
1165
1245
|
}
|
|
1166
1246
|
let deviceId = "beeos-claw-device";
|
|
1167
1247
|
if (pubKeyB64) {
|
|
1168
|
-
const
|
|
1169
|
-
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));
|
|
1170
1253
|
deviceId = `beeos-claw-${hash.slice(0, 12)}`;
|
|
1171
1254
|
}
|
|
1172
1255
|
const paired = {
|
|
@@ -1186,7 +1269,7 @@ async function writePairedJson(home, keyFile) {
|
|
|
1186
1269
|
|
|
1187
1270
|
// ../core/dist/agent/registry.js
|
|
1188
1271
|
var openClawDriver = {
|
|
1189
|
-
|
|
1272
|
+
agentFramework() {
|
|
1190
1273
|
return "openclaw";
|
|
1191
1274
|
},
|
|
1192
1275
|
npmPackage() {
|
|
@@ -1221,7 +1304,7 @@ var openClawDriver = {
|
|
|
1221
1304
|
// ../core/dist/runtime/openclaw.js
|
|
1222
1305
|
var GATEWAY_PORT2 = 18789;
|
|
1223
1306
|
var openclawRuntime = {
|
|
1224
|
-
|
|
1307
|
+
agentFramework() {
|
|
1225
1308
|
return "openclaw";
|
|
1226
1309
|
},
|
|
1227
1310
|
displayName() {
|
|
@@ -1257,11 +1340,11 @@ var openclawRuntime = {
|
|
|
1257
1340
|
async isHealthy() {
|
|
1258
1341
|
return getPlatformAdapter().tcpProbe("127.0.0.1", GATEWAY_PORT2, 500);
|
|
1259
1342
|
},
|
|
1260
|
-
async stop(
|
|
1261
|
-
const pid = await readPid(
|
|
1343
|
+
async stop(agentFramework) {
|
|
1344
|
+
const pid = await readPid(agentFramework);
|
|
1262
1345
|
if (pid != null) {
|
|
1263
1346
|
killProcess(pid);
|
|
1264
|
-
await removePid(
|
|
1347
|
+
await removePid(agentFramework);
|
|
1265
1348
|
}
|
|
1266
1349
|
},
|
|
1267
1350
|
async update(progress) {
|
|
@@ -1270,6 +1353,48 @@ var openclawRuntime = {
|
|
|
1270
1353
|
}
|
|
1271
1354
|
};
|
|
1272
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
|
+
|
|
1273
1398
|
// src/node-adapter.ts
|
|
1274
1399
|
import {
|
|
1275
1400
|
execFile,
|
|
@@ -1361,7 +1486,9 @@ var NodePlatformAdapter = class {
|
|
|
1361
1486
|
env,
|
|
1362
1487
|
timeout: options?.timeout,
|
|
1363
1488
|
maxBuffer: 10 * 1024 * 1024,
|
|
1364
|
-
encoding: "utf-8"
|
|
1489
|
+
encoding: "utf-8",
|
|
1490
|
+
shell: process.platform === "win32",
|
|
1491
|
+
windowsHide: true
|
|
1365
1492
|
},
|
|
1366
1493
|
(error, stdout, stderr) => {
|
|
1367
1494
|
const code = error && "code" in error && typeof error.code === "number" ? error.code : error ? 1 : 0;
|
|
@@ -1390,6 +1517,8 @@ var NodePlatformAdapter = class {
|
|
|
1390
1517
|
cwd: options?.cwd,
|
|
1391
1518
|
env,
|
|
1392
1519
|
detached: options?.detached ?? false,
|
|
1520
|
+
shell: process.platform === "win32",
|
|
1521
|
+
windowsHide: true,
|
|
1393
1522
|
stdio: [
|
|
1394
1523
|
"ignore",
|
|
1395
1524
|
stdoutFd != null ? stdoutFd : "ignore",
|
|
@@ -1457,6 +1586,9 @@ var NodePlatformAdapter = class {
|
|
|
1457
1586
|
env(key) {
|
|
1458
1587
|
return process.env[key];
|
|
1459
1588
|
}
|
|
1589
|
+
cwd() {
|
|
1590
|
+
return process.cwd();
|
|
1591
|
+
}
|
|
1460
1592
|
// ── UI ──────────────────────────────────────────────────
|
|
1461
1593
|
async openUrl(url) {
|
|
1462
1594
|
const open = await import("open");
|
|
@@ -1506,13 +1638,13 @@ var CliReporter = class {
|
|
|
1506
1638
|
};
|
|
1507
1639
|
|
|
1508
1640
|
// src/commands/start.ts
|
|
1509
|
-
async function run(
|
|
1641
|
+
async function run(agentFramework, options) {
|
|
1510
1642
|
const p = getPlatformAdapter();
|
|
1511
1643
|
await ensureDirs();
|
|
1512
1644
|
const cfg = await loadOrCreateConfig();
|
|
1513
1645
|
const reporter = new CliReporter();
|
|
1514
|
-
if (
|
|
1515
|
-
throw new Error(`Agent
|
|
1646
|
+
if (agentFramework !== "openclaw") {
|
|
1647
|
+
throw new Error(`Agent framework '${agentFramework}' is not yet supported. Use 'openclaw'.`);
|
|
1516
1648
|
}
|
|
1517
1649
|
const identity = await loadOrCreateIdentity();
|
|
1518
1650
|
const fp = fingerprint(identity);
|
|
@@ -1527,13 +1659,16 @@ async function run(agentType, options) {
|
|
|
1527
1659
|
if (location.type === "managed") {
|
|
1528
1660
|
binary = location.binary;
|
|
1529
1661
|
home = location.home;
|
|
1662
|
+
try {
|
|
1663
|
+
await ensurePlugin(agentFramework, home, reporter);
|
|
1664
|
+
} catch {
|
|
1665
|
+
}
|
|
1530
1666
|
} else if (location.type === "system") {
|
|
1531
1667
|
binary = location.binary;
|
|
1532
1668
|
home = location.home;
|
|
1533
1669
|
isSystemHome = true;
|
|
1534
1670
|
try {
|
|
1535
|
-
|
|
1536
|
-
await installPluginToHome(home, pluginDir, binary);
|
|
1671
|
+
await ensurePlugin(agentFramework, home, reporter);
|
|
1537
1672
|
} catch {
|
|
1538
1673
|
}
|
|
1539
1674
|
const systemToken = await readExistingGatewayToken(home);
|
|
@@ -1560,11 +1695,11 @@ async function run(agentType, options) {
|
|
|
1560
1695
|
}
|
|
1561
1696
|
} else {
|
|
1562
1697
|
reporter.onStatus(`Downloading ${openClawDriver.npmPackage()}...`);
|
|
1563
|
-
await downloadAgent(openClawDriver.npmPackage(), options.version ?? void 0,
|
|
1564
|
-
home = agentHome(
|
|
1698
|
+
await downloadAgent(openClawDriver.npmPackage(), options.version ?? void 0, agentFramework, reporter);
|
|
1699
|
+
home = agentHome(agentFramework);
|
|
1565
1700
|
await p.mkdir(home);
|
|
1566
|
-
await
|
|
1567
|
-
const managedBin = await managedBinary2(
|
|
1701
|
+
await ensurePlugin(agentFramework, home, reporter);
|
|
1702
|
+
const managedBin = await managedBinary2(agentFramework);
|
|
1568
1703
|
if (!managedBin) throw new Error("agent binary not found after download");
|
|
1569
1704
|
binary = managedBin;
|
|
1570
1705
|
}
|
|
@@ -1586,7 +1721,7 @@ async function run(agentType, options) {
|
|
|
1586
1721
|
await generateOpenclawConfig(ctx);
|
|
1587
1722
|
}
|
|
1588
1723
|
const pid = await spawnOpenclaw(ctx);
|
|
1589
|
-
await writePid(
|
|
1724
|
+
await writePid(agentFramework, pid);
|
|
1590
1725
|
gatewayPid = pid;
|
|
1591
1726
|
let alive = false;
|
|
1592
1727
|
for (let i = 0; i < 10; i++) {
|
|
@@ -1600,55 +1735,52 @@ async function run(agentType, options) {
|
|
|
1600
1735
|
throw new Error("Agent gateway did not start within 5s");
|
|
1601
1736
|
}
|
|
1602
1737
|
} else {
|
|
1603
|
-
gatewayPid = await readPid(
|
|
1738
|
+
gatewayPid = await readPid(agentFramework) ?? void 0;
|
|
1604
1739
|
}
|
|
1605
1740
|
const hostname = buildHostname();
|
|
1606
1741
|
try {
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
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 = {
|
|
1612
1753
|
status: "bound",
|
|
1613
1754
|
public_key: pubkey,
|
|
1614
1755
|
fingerprint: fp,
|
|
1615
1756
|
gateway_url: "http://127.0.0.1:18789",
|
|
1616
1757
|
gateway_pid: gatewayPid,
|
|
1617
1758
|
bridge_url: cfg.platform.bridge_url,
|
|
1618
|
-
instance_id: instanceId
|
|
1759
|
+
instance_id: result.instanceId
|
|
1619
1760
|
};
|
|
1620
1761
|
if (options.json) {
|
|
1621
|
-
console.log(JSON.stringify(
|
|
1762
|
+
console.log(JSON.stringify(out, null, 2));
|
|
1622
1763
|
} else {
|
|
1623
|
-
console.log(`Agent bound to instance: ${instanceId}`);
|
|
1764
|
+
console.log(`Agent bound to instance: ${result.instanceId}`);
|
|
1624
1765
|
}
|
|
1625
1766
|
return;
|
|
1626
1767
|
}
|
|
1627
|
-
if (
|
|
1628
|
-
const bindId = resp.bind_id ?? "";
|
|
1629
|
-
const bindUrl = buildBindUrl(cfg.platform.dashboard_base_url, bindId);
|
|
1630
|
-
await removeBindingInfo();
|
|
1768
|
+
if (result.status === "pending") {
|
|
1631
1769
|
if (options.json) {
|
|
1632
|
-
const
|
|
1770
|
+
const out = {
|
|
1633
1771
|
status: "pending",
|
|
1634
1772
|
public_key: pubkey,
|
|
1635
1773
|
fingerprint: fp,
|
|
1636
|
-
bind_id: bindId,
|
|
1637
|
-
bind_url: bindUrl,
|
|
1638
|
-
qr_data: bindUrl,
|
|
1774
|
+
bind_id: result.bindId,
|
|
1775
|
+
bind_url: result.bindUrl,
|
|
1776
|
+
qr_data: result.bindUrl,
|
|
1639
1777
|
gateway_url: "http://127.0.0.1:18789",
|
|
1640
1778
|
gateway_pid: gatewayPid,
|
|
1641
1779
|
bridge_url: cfg.platform.bridge_url
|
|
1642
1780
|
};
|
|
1643
|
-
console.log(JSON.stringify(
|
|
1781
|
+
console.log(JSON.stringify(out, null, 2));
|
|
1644
1782
|
return;
|
|
1645
1783
|
}
|
|
1646
|
-
await presentBindUrl(bindUrl, options.browser === false);
|
|
1647
|
-
console.log("");
|
|
1648
|
-
console.log(" Waiting for bind approval (timeout: 10min)...");
|
|
1649
|
-
const instanceId = await pollUntilBound(cfg.platform.api_url, bindId, 6e5);
|
|
1650
|
-
await saveBindingInfo({ fingerprint: fp, instance_id: instanceId, bound_at: nowUnix() });
|
|
1651
|
-
console.log(` Bind confirmed! Instance: ${instanceId}`);
|
|
1652
1784
|
}
|
|
1653
1785
|
} catch (e) {
|
|
1654
1786
|
const cached = await loadBindingInfo();
|
|
@@ -1671,50 +1803,25 @@ async function run(agentType, options) {
|
|
|
1671
1803
|
throw new Error(`Cannot reach platform to bind agent: ${e}`);
|
|
1672
1804
|
}
|
|
1673
1805
|
}
|
|
1674
|
-
async function installPluginToHome(home, pluginDir, binary) {
|
|
1675
|
-
const p = getPlatformAdapter();
|
|
1676
|
-
const dest = p.joinPath(home, "extensions", "beeos-claw");
|
|
1677
|
-
if (await p.exists(dest)) {
|
|
1678
|
-
await p.rmdir(dest);
|
|
1679
|
-
}
|
|
1680
|
-
await copyDirRecursive(pluginDir, dest);
|
|
1681
|
-
}
|
|
1682
|
-
async function copyDirRecursive(src, dst) {
|
|
1683
|
-
const p = getPlatformAdapter();
|
|
1684
|
-
await p.mkdir(dst);
|
|
1685
|
-
const entries = await p.readdir(src);
|
|
1686
|
-
for (const name of entries) {
|
|
1687
|
-
const srcPath = p.joinPath(src, name);
|
|
1688
|
-
const dstPath = p.joinPath(dst, name);
|
|
1689
|
-
if (await p.isDirectory(srcPath)) {
|
|
1690
|
-
await copyDirRecursive(srcPath, dstPath);
|
|
1691
|
-
} else {
|
|
1692
|
-
await p.copyFile(srcPath, dstPath);
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
1806
|
function buildHostname() {
|
|
1697
1807
|
const machine = os2.hostname();
|
|
1698
1808
|
const user = process.env.USER || process.env.USERNAME || "";
|
|
1699
1809
|
return user ? `${user}@${machine}` : machine;
|
|
1700
1810
|
}
|
|
1701
|
-
function nowUnix() {
|
|
1702
|
-
return Math.floor(Date.now() / 1e3);
|
|
1703
|
-
}
|
|
1704
1811
|
function sleep2(ms) {
|
|
1705
1812
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1706
1813
|
}
|
|
1707
1814
|
|
|
1708
1815
|
// src/commands/stop.ts
|
|
1709
|
-
async function run2(
|
|
1710
|
-
const pid = await readPid(
|
|
1816
|
+
async function run2(agentFramework) {
|
|
1817
|
+
const pid = await readPid(agentFramework);
|
|
1711
1818
|
if (pid == null) {
|
|
1712
|
-
console.log(`No running ${
|
|
1819
|
+
console.log(`No running ${agentFramework} agent found`);
|
|
1713
1820
|
return;
|
|
1714
1821
|
}
|
|
1715
1822
|
killProcess(pid);
|
|
1716
|
-
await removePid(
|
|
1717
|
-
console.log(`Stopped ${
|
|
1823
|
+
await removePid(agentFramework);
|
|
1824
|
+
console.log(`Stopped ${agentFramework} agent (pid ${pid})`);
|
|
1718
1825
|
}
|
|
1719
1826
|
|
|
1720
1827
|
// src/commands/status.ts
|
|
@@ -1748,25 +1855,25 @@ async function run3() {
|
|
|
1748
1855
|
}
|
|
1749
1856
|
|
|
1750
1857
|
// src/commands/update.ts
|
|
1751
|
-
async function run4(
|
|
1858
|
+
async function run4(agentFramework) {
|
|
1752
1859
|
const reporter = new CliReporter();
|
|
1753
|
-
const pid = await readPid(
|
|
1860
|
+
const pid = await readPid(agentFramework);
|
|
1754
1861
|
const wasRunning = pid != null && isProcessAlive(pid);
|
|
1755
1862
|
if (wasRunning) {
|
|
1756
|
-
await run2(
|
|
1863
|
+
await run2(agentFramework);
|
|
1757
1864
|
}
|
|
1758
|
-
if (
|
|
1865
|
+
if (agentFramework === "openclaw") {
|
|
1759
1866
|
await openclawRuntime.update(reporter);
|
|
1760
|
-
} else if (
|
|
1867
|
+
} else if (agentFramework === "device") {
|
|
1761
1868
|
await deviceRuntime.update(reporter);
|
|
1762
1869
|
} else {
|
|
1763
|
-
throw new Error(`Unknown agent
|
|
1870
|
+
throw new Error(`Unknown agent framework: ${agentFramework}`);
|
|
1764
1871
|
}
|
|
1765
1872
|
reporter.stop();
|
|
1766
|
-
console.log(`${
|
|
1873
|
+
console.log(`${agentFramework} updated`);
|
|
1767
1874
|
if (wasRunning) {
|
|
1768
1875
|
console.log("Restarting agent...");
|
|
1769
|
-
await run(
|
|
1876
|
+
await run(agentFramework, { force: true });
|
|
1770
1877
|
}
|
|
1771
1878
|
}
|
|
1772
1879
|
|
|
@@ -2107,10 +2214,10 @@ function sleep3(ms) {
|
|
|
2107
2214
|
setPlatformAdapter(new NodePlatformAdapter());
|
|
2108
2215
|
var program = new Command();
|
|
2109
2216
|
program.name("beeos").version("1.0.0").description("BeeOS \u2014 run AI agents from your desktop");
|
|
2110
|
-
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);
|
|
2111
|
-
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));
|
|
2112
2219
|
program.command("status").description("Show status of managed agents").action(run3);
|
|
2113
|
-
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));
|
|
2114
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);
|
|
2115
2222
|
var deviceCmd = program.command("device").description("Manage device agents (Android/Desktop/ChromeOS)");
|
|
2116
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,38 +13,38 @@
|
|
|
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": {
|
|
17
|
+
"@noble/ed25519": "^2.2.0",
|
|
18
|
+
"@noble/hashes": "^1.7.0",
|
|
24
19
|
"commander": "^13.0.0",
|
|
25
20
|
"open": "^10.1.0",
|
|
26
21
|
"ora": "^8.1.0",
|
|
27
22
|
"proper-lockfile": "^4.1.2",
|
|
28
|
-
"
|
|
29
|
-
"@noble/ed25519": "^2.2.0",
|
|
30
|
-
"@noble/hashes": "^1.7.0",
|
|
23
|
+
"qrcode": "^1.5.4",
|
|
31
24
|
"smol-toml": "^1.3.0",
|
|
32
|
-
"
|
|
25
|
+
"tar": "^7.5.13",
|
|
26
|
+
"which": "^5.0.0"
|
|
33
27
|
},
|
|
34
28
|
"devDependencies": {
|
|
35
|
-
"@beeos/core": "workspace:*",
|
|
36
29
|
"@types/node": "^22.0.0",
|
|
37
30
|
"@types/proper-lockfile": "^4.1.4",
|
|
38
31
|
"@types/qrcode": "^1.5.5",
|
|
39
32
|
"@types/which": "^3.0.4",
|
|
40
33
|
"tsup": "^8.3.0",
|
|
41
34
|
"typescript": "^5.7.0",
|
|
42
|
-
"vitest": "^3.0.0"
|
|
35
|
+
"vitest": "^3.0.0",
|
|
36
|
+
"@beeos/core": "0.1.0"
|
|
43
37
|
},
|
|
44
38
|
"engines": {
|
|
45
39
|
"node": ">=18"
|
|
46
40
|
},
|
|
47
41
|
"publishConfig": {
|
|
48
42
|
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"type-check": "tsc --noEmit",
|
|
47
|
+
"lint": "eslint src/",
|
|
48
|
+
"test": "vitest run --passWithNoTests"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|