@beeos-ai/cli 1.0.16 → 1.0.18
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 +424 -41
- package/package.json +1 -1
- package/scripts/_existing_install_actions.json +47 -22
- package/scripts/install.Tests.ps1 +36 -19
- package/scripts/install.ps1 +39 -163
- package/scripts/install.sh +35 -150
package/dist/index.js
CHANGED
|
@@ -1546,22 +1546,36 @@ var init_device = __esm({
|
|
|
1546
1546
|
const lines = result.stdout.split("\n").slice(1);
|
|
1547
1547
|
for (const line of lines) {
|
|
1548
1548
|
const parts = line.trim().split(/\s+/);
|
|
1549
|
-
if (parts.length
|
|
1550
|
-
|
|
1551
|
-
|
|
1549
|
+
if (parts.length < 2)
|
|
1550
|
+
continue;
|
|
1551
|
+
const serial = parts[0];
|
|
1552
|
+
const rawStatus = parts[1];
|
|
1553
|
+
let status2;
|
|
1554
|
+
if (rawStatus === "device")
|
|
1555
|
+
status2 = "device";
|
|
1556
|
+
else if (rawStatus === "unauthorized")
|
|
1557
|
+
status2 = "unauthorized";
|
|
1558
|
+
else
|
|
1559
|
+
status2 = "offline";
|
|
1560
|
+
devices.push({ serial, status: status2, rawStatus });
|
|
1552
1561
|
}
|
|
1553
1562
|
return devices;
|
|
1554
1563
|
},
|
|
1555
1564
|
async detectSingleDevice() {
|
|
1556
|
-
const
|
|
1557
|
-
|
|
1565
|
+
const all = await this.listAdbDevices();
|
|
1566
|
+
const ready = all.filter((d) => d.status === "device");
|
|
1567
|
+
if (ready.length === 0) {
|
|
1568
|
+
if (all.length > 0) {
|
|
1569
|
+
const issues = all.map((d) => `${d.serial}=${d.rawStatus}`).join(", ");
|
|
1570
|
+
throw new Error(`No ADB devices ready (only: ${issues}). Accept the USB prompt on the phone or check the cable.`);
|
|
1571
|
+
}
|
|
1558
1572
|
throw new Error("No ADB devices found. Connect a device and try again.");
|
|
1559
1573
|
}
|
|
1560
|
-
if (
|
|
1561
|
-
const serials =
|
|
1574
|
+
if (ready.length > 1) {
|
|
1575
|
+
const serials = ready.map((d) => d.serial).join(", ");
|
|
1562
1576
|
throw new Error(`Multiple ADB devices found: ${serials}. Use --serial to specify one.`);
|
|
1563
1577
|
}
|
|
1564
|
-
return
|
|
1578
|
+
return ready[0].serial;
|
|
1565
1579
|
},
|
|
1566
1580
|
async spawnForDevice(serial, agentBin, bridgeUrl, httpEnabled, httpPort, agentGatewayUrl) {
|
|
1567
1581
|
const p = getPlatformAdapter();
|
|
@@ -3347,13 +3361,13 @@ function inferInitChoices(state) {
|
|
|
3347
3361
|
if (state.hasIdentity && state.binding) {
|
|
3348
3362
|
return {
|
|
3349
3363
|
defaultDecision: "upgrade",
|
|
3350
|
-
options: ["upgrade", "rebind-
|
|
3364
|
+
options: ["upgrade", "rebind", "reset-all", "skip"]
|
|
3351
3365
|
};
|
|
3352
3366
|
}
|
|
3353
3367
|
if (state.hasIdentity) {
|
|
3354
3368
|
return {
|
|
3355
3369
|
defaultDecision: "upgrade",
|
|
3356
|
-
options: ["upgrade", "
|
|
3370
|
+
options: ["upgrade", "reset-all", "skip"]
|
|
3357
3371
|
};
|
|
3358
3372
|
}
|
|
3359
3373
|
return { defaultDecision: "fresh", options: ["fresh", "skip"] };
|
|
@@ -3364,8 +3378,10 @@ function initDecisionLabel(decision) {
|
|
|
3364
3378
|
return "Install + bind";
|
|
3365
3379
|
case "upgrade":
|
|
3366
3380
|
return "Upgrade CLI & agents (keep binding & key)";
|
|
3367
|
-
case "rebind
|
|
3368
|
-
return "Re-bind (
|
|
3381
|
+
case "rebind":
|
|
3382
|
+
return "Re-bind (keep key, refresh binding \u2014 same instance)";
|
|
3383
|
+
case "reset-all":
|
|
3384
|
+
return "Reset everything (NEW key, NEW instance \u2014 for compromised key)";
|
|
3369
3385
|
case "skip":
|
|
3370
3386
|
return "Skip (do nothing)";
|
|
3371
3387
|
}
|
|
@@ -5109,6 +5125,20 @@ var init_fallback_banner = __esm({
|
|
|
5109
5125
|
}
|
|
5110
5126
|
});
|
|
5111
5127
|
|
|
5128
|
+
// src/json-envelope.ts
|
|
5129
|
+
function jsonOk(data) {
|
|
5130
|
+
return { ok: true, data };
|
|
5131
|
+
}
|
|
5132
|
+
function emitJsonEnvelope(env) {
|
|
5133
|
+
console.log(JSON.stringify(env, null, 2));
|
|
5134
|
+
}
|
|
5135
|
+
var init_json_envelope = __esm({
|
|
5136
|
+
"src/json-envelope.ts"() {
|
|
5137
|
+
"use strict";
|
|
5138
|
+
init_dist();
|
|
5139
|
+
}
|
|
5140
|
+
});
|
|
5141
|
+
|
|
5112
5142
|
// src/commands/device/fleet-notify.ts
|
|
5113
5143
|
async function notifyFleetReloadBestEffort(baseUrl = FLEET_STATUS_BASE_URL) {
|
|
5114
5144
|
try {
|
|
@@ -5245,6 +5275,207 @@ var init_upgrade2 = __esm({
|
|
|
5245
5275
|
}
|
|
5246
5276
|
});
|
|
5247
5277
|
|
|
5278
|
+
// src/lib/instance-picker.ts
|
|
5279
|
+
import readline from "readline";
|
|
5280
|
+
function resolveIO(ctx) {
|
|
5281
|
+
return {
|
|
5282
|
+
input: ctx.input ?? process.stdin,
|
|
5283
|
+
output: ctx.output ?? process.stdout
|
|
5284
|
+
};
|
|
5285
|
+
}
|
|
5286
|
+
function isTTY(ctx, io) {
|
|
5287
|
+
if (ctx.isTTY !== void 0) return ctx.isTTY;
|
|
5288
|
+
return Boolean(io.input.isTTY);
|
|
5289
|
+
}
|
|
5290
|
+
function ask(io, question) {
|
|
5291
|
+
const rl = readline.createInterface({ input: io.input, output: io.output });
|
|
5292
|
+
return new Promise((resolve) => {
|
|
5293
|
+
rl.question(question, (answer) => {
|
|
5294
|
+
rl.close();
|
|
5295
|
+
resolve(answer);
|
|
5296
|
+
});
|
|
5297
|
+
});
|
|
5298
|
+
}
|
|
5299
|
+
function statusBlurb(status2) {
|
|
5300
|
+
switch (status2) {
|
|
5301
|
+
case "device":
|
|
5302
|
+
return "device";
|
|
5303
|
+
case "unauthorized":
|
|
5304
|
+
return "unauthorized \u2014 accept the USB prompt on the phone";
|
|
5305
|
+
case "offline":
|
|
5306
|
+
return "offline \u2014 check the USB cable / `adb kill-server`";
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
async function pickInstanceInteractive(candidates, ctx) {
|
|
5310
|
+
const io = resolveIO(ctx);
|
|
5311
|
+
if (!isTTY(ctx, io)) {
|
|
5312
|
+
return { kind: "skip" };
|
|
5313
|
+
}
|
|
5314
|
+
const frameworks = candidates.filter(
|
|
5315
|
+
(c) => c.kind === "framework"
|
|
5316
|
+
);
|
|
5317
|
+
const devices = candidates.filter(
|
|
5318
|
+
(c) => c.kind === "device"
|
|
5319
|
+
);
|
|
5320
|
+
if (ctx.caller === "init") {
|
|
5321
|
+
if (frameworks.length === 1 && devices.length === 0) {
|
|
5322
|
+
return { kind: "framework", id: frameworks[0].id };
|
|
5323
|
+
}
|
|
5324
|
+
return renderMixedMenu(frameworks, devices, io);
|
|
5325
|
+
}
|
|
5326
|
+
if (devices.length === 0) {
|
|
5327
|
+
if (ctx.caller === "discover") {
|
|
5328
|
+
io.output.write("No ADB devices found. Connect a device and try again.\n");
|
|
5329
|
+
}
|
|
5330
|
+
return { kind: "skip" };
|
|
5331
|
+
}
|
|
5332
|
+
if (devices.length === 1) {
|
|
5333
|
+
return askYesNoSingleDevice(devices[0], io);
|
|
5334
|
+
}
|
|
5335
|
+
return renderDeviceMenu(devices, io);
|
|
5336
|
+
}
|
|
5337
|
+
async function renderMixedMenu(frameworks, devices, io) {
|
|
5338
|
+
const items = [];
|
|
5339
|
+
let idx = 1;
|
|
5340
|
+
for (const fw of frameworks) {
|
|
5341
|
+
items.push({
|
|
5342
|
+
idx: idx++,
|
|
5343
|
+
kind: "framework",
|
|
5344
|
+
id: fw.id,
|
|
5345
|
+
label: fw.label,
|
|
5346
|
+
isDefault: fw.isDefault === true
|
|
5347
|
+
});
|
|
5348
|
+
}
|
|
5349
|
+
for (const d of devices) {
|
|
5350
|
+
items.push({
|
|
5351
|
+
idx: idx++,
|
|
5352
|
+
kind: "device",
|
|
5353
|
+
serial: d.serial,
|
|
5354
|
+
status: d.status,
|
|
5355
|
+
selectable: d.status === "device"
|
|
5356
|
+
});
|
|
5357
|
+
}
|
|
5358
|
+
const defaultItem = items.find((i) => i.kind === "framework" && i.isDefault) ?? items[0];
|
|
5359
|
+
io.output.write("\n");
|
|
5360
|
+
io.output.write("What would you like to bind on this machine?\n");
|
|
5361
|
+
io.output.write("\n");
|
|
5362
|
+
if (frameworks.length > 0) {
|
|
5363
|
+
io.output.write(" Local agent:\n");
|
|
5364
|
+
for (const it of items) {
|
|
5365
|
+
if (it.kind !== "framework") continue;
|
|
5366
|
+
const def = it.isDefault ? " (default)" : "";
|
|
5367
|
+
io.output.write(` [${it.idx}] ${it.label}${def}
|
|
5368
|
+
`);
|
|
5369
|
+
}
|
|
5370
|
+
io.output.write("\n");
|
|
5371
|
+
}
|
|
5372
|
+
if (devices.length > 0) {
|
|
5373
|
+
io.output.write(` ADB devices (${devices.length} found):
|
|
5374
|
+
`);
|
|
5375
|
+
for (const it of items) {
|
|
5376
|
+
if (it.kind !== "device") continue;
|
|
5377
|
+
const tag = statusBlurb(it.status);
|
|
5378
|
+
io.output.write(` [${it.idx}] ${it.serial.padEnd(20)} ${tag}
|
|
5379
|
+
`);
|
|
5380
|
+
}
|
|
5381
|
+
io.output.write("\n");
|
|
5382
|
+
}
|
|
5383
|
+
io.output.write(" [s] Skip\n");
|
|
5384
|
+
io.output.write("\n");
|
|
5385
|
+
return promptForChoice(items, defaultItem.idx, io);
|
|
5386
|
+
}
|
|
5387
|
+
async function renderDeviceMenu(devices, io) {
|
|
5388
|
+
const items = devices.map((d, i) => ({
|
|
5389
|
+
idx: i + 1,
|
|
5390
|
+
kind: "device",
|
|
5391
|
+
serial: d.serial,
|
|
5392
|
+
status: d.status,
|
|
5393
|
+
selectable: d.status === "device"
|
|
5394
|
+
}));
|
|
5395
|
+
io.output.write("\n");
|
|
5396
|
+
io.output.write(`Detected ${devices.length} ADB devices:
|
|
5397
|
+
`);
|
|
5398
|
+
for (const it of items) {
|
|
5399
|
+
io.output.write(` [${it.idx}] ${it.serial.padEnd(20)} ${statusBlurb(it.status)}
|
|
5400
|
+
`);
|
|
5401
|
+
}
|
|
5402
|
+
io.output.write("\n");
|
|
5403
|
+
return promptForChoice(
|
|
5404
|
+
items,
|
|
5405
|
+
/* defaultIdx */
|
|
5406
|
+
-1,
|
|
5407
|
+
io
|
|
5408
|
+
);
|
|
5409
|
+
}
|
|
5410
|
+
async function askYesNoSingleDevice(device, io) {
|
|
5411
|
+
if (device.status !== "device") {
|
|
5412
|
+
io.output.write(
|
|
5413
|
+
`Found 1 ADB device (serial=${device.serial}) but its status is ${statusBlurb(device.status)}.
|
|
5414
|
+
Skipping. Fix the device state and re-run.
|
|
5415
|
+
`
|
|
5416
|
+
);
|
|
5417
|
+
return { kind: "skip" };
|
|
5418
|
+
}
|
|
5419
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
5420
|
+
const answer = (await ask(io, `Found 1 ADB device (serial=${device.serial}). Attach now? [Y/n]: `)).trim().toLowerCase();
|
|
5421
|
+
if (answer === "" || answer === "y" || answer === "yes") {
|
|
5422
|
+
return { kind: "device", serial: device.serial };
|
|
5423
|
+
}
|
|
5424
|
+
if (answer === "n" || answer === "no" || answer === "s" || answer === "skip") {
|
|
5425
|
+
return { kind: "skip" };
|
|
5426
|
+
}
|
|
5427
|
+
io.output.write(` invalid input '${answer}'. Please answer Y or n.
|
|
5428
|
+
`);
|
|
5429
|
+
}
|
|
5430
|
+
io.output.write(" too many invalid inputs \u2014 skipping.\n");
|
|
5431
|
+
return { kind: "skip" };
|
|
5432
|
+
}
|
|
5433
|
+
async function promptForChoice(items, defaultIdx, io) {
|
|
5434
|
+
const range = `1-${items.length}`;
|
|
5435
|
+
const defaultHint = defaultIdx > 0 ? `default ${defaultIdx}` : "default skip";
|
|
5436
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
5437
|
+
const raw = await ask(io, `Choose [${range} / s] (${defaultHint}): `);
|
|
5438
|
+
const trimmed = raw.trim().toLowerCase();
|
|
5439
|
+
if (trimmed === "" && defaultIdx > 0) {
|
|
5440
|
+
return itemToSelection(items[defaultIdx - 1], io);
|
|
5441
|
+
}
|
|
5442
|
+
if (trimmed === "" || trimmed === "s" || trimmed === "skip") {
|
|
5443
|
+
return { kind: "skip" };
|
|
5444
|
+
}
|
|
5445
|
+
const n = Number.parseInt(trimmed, 10);
|
|
5446
|
+
if (!Number.isFinite(n) || n < 1 || n > items.length) {
|
|
5447
|
+
io.output.write(` invalid input '${raw.trim()}'. Please pick a number in ${range} or 's'.
|
|
5448
|
+
`);
|
|
5449
|
+
continue;
|
|
5450
|
+
}
|
|
5451
|
+
const picked = items[n - 1];
|
|
5452
|
+
if (picked.kind === "device" && !picked.selectable) {
|
|
5453
|
+
io.output.write(
|
|
5454
|
+
` device ${picked.serial} is ${statusBlurb(picked.status)} and cannot be attached yet.
|
|
5455
|
+
Fix the device state on the phone and re-run.
|
|
5456
|
+
`
|
|
5457
|
+
);
|
|
5458
|
+
continue;
|
|
5459
|
+
}
|
|
5460
|
+
return itemToSelection(picked, io);
|
|
5461
|
+
}
|
|
5462
|
+
io.output.write(" too many invalid inputs \u2014 skipping.\n");
|
|
5463
|
+
return { kind: "skip" };
|
|
5464
|
+
}
|
|
5465
|
+
function itemToSelection(item, _io) {
|
|
5466
|
+
if (item.kind === "framework") {
|
|
5467
|
+
return { kind: "framework", id: item.id };
|
|
5468
|
+
}
|
|
5469
|
+
return { kind: "device", serial: item.serial };
|
|
5470
|
+
}
|
|
5471
|
+
var MAX_RETRIES;
|
|
5472
|
+
var init_instance_picker = __esm({
|
|
5473
|
+
"src/lib/instance-picker.ts"() {
|
|
5474
|
+
"use strict";
|
|
5475
|
+
MAX_RETRIES = 3;
|
|
5476
|
+
}
|
|
5477
|
+
});
|
|
5478
|
+
|
|
5248
5479
|
// src/commands/device/state.ts
|
|
5249
5480
|
import lockfile from "proper-lockfile";
|
|
5250
5481
|
function deviceAgentTargetId(serial) {
|
|
@@ -5310,7 +5541,7 @@ var init_state2 = __esm({
|
|
|
5310
5541
|
|
|
5311
5542
|
// src/commands/device/attach.ts
|
|
5312
5543
|
import { spawn as spawn2 } from "child_process";
|
|
5313
|
-
import
|
|
5544
|
+
import readline2 from "readline";
|
|
5314
5545
|
function resolvePerDeviceAgentGatewayUrl(cfg, override) {
|
|
5315
5546
|
if (override === void 0) return resolveAgentGatewayUrl(cfg);
|
|
5316
5547
|
const trimmed = override.trim();
|
|
@@ -5342,6 +5573,24 @@ function resolvePerDeviceAgentGatewayUrl(cfg, override) {
|
|
|
5342
5573
|
}
|
|
5343
5574
|
return trimmed;
|
|
5344
5575
|
}
|
|
5576
|
+
async function pickAttachSerial() {
|
|
5577
|
+
const devices = await deviceRuntime.listAdbDevices();
|
|
5578
|
+
const ready = devices.filter((d) => d.status === "device");
|
|
5579
|
+
if (ready.length <= 1) {
|
|
5580
|
+
return deviceRuntime.detectSingleDevice();
|
|
5581
|
+
}
|
|
5582
|
+
if (!process.stdin.isTTY) {
|
|
5583
|
+
return deviceRuntime.detectSingleDevice();
|
|
5584
|
+
}
|
|
5585
|
+
const candidates = devices.map((d) => ({
|
|
5586
|
+
kind: "device",
|
|
5587
|
+
serial: d.serial,
|
|
5588
|
+
status: d.status
|
|
5589
|
+
}));
|
|
5590
|
+
const sel = await pickInstanceInteractive(candidates, { caller: "attach" });
|
|
5591
|
+
if (sel.kind === "device") return sel.serial;
|
|
5592
|
+
return deviceRuntime.detectSingleDevice();
|
|
5593
|
+
}
|
|
5345
5594
|
async function attach(options) {
|
|
5346
5595
|
const cfg = await loadOrCreateConfig();
|
|
5347
5596
|
const reporter = new CliReporter();
|
|
@@ -5353,7 +5602,7 @@ async function attach(options) {
|
|
|
5353
5602
|
if (options.all) {
|
|
5354
5603
|
return attachAll(cfg, reporter, withVideo, options);
|
|
5355
5604
|
}
|
|
5356
|
-
const serial = options.serial ?? await
|
|
5605
|
+
const serial = options.serial ?? await pickAttachSerial();
|
|
5357
5606
|
const name = options.name ?? serial;
|
|
5358
5607
|
await deviceRuntime.ensureAgent(reporter);
|
|
5359
5608
|
reporter.stop();
|
|
@@ -5468,11 +5717,26 @@ async function attach(options) {
|
|
|
5468
5717
|
await maybeNotifyFleetWithHint(cfg);
|
|
5469
5718
|
}
|
|
5470
5719
|
async function attachAll(cfg, reporter, withVideo, options) {
|
|
5471
|
-
const
|
|
5720
|
+
const all = await deviceRuntime.listAdbDevices();
|
|
5721
|
+
const devices = all.filter((d) => d.status === "device");
|
|
5722
|
+
const skipped = all.filter((d) => d.status !== "device");
|
|
5472
5723
|
if (devices.length === 0) {
|
|
5473
|
-
|
|
5724
|
+
if (skipped.length > 0) {
|
|
5725
|
+
console.log("No ADB devices ready to attach. Issues:");
|
|
5726
|
+
for (const d of skipped) {
|
|
5727
|
+
console.log(` ${d.serial}: ${d.rawStatus}`);
|
|
5728
|
+
}
|
|
5729
|
+
} else {
|
|
5730
|
+
console.log("No ADB devices detected");
|
|
5731
|
+
}
|
|
5474
5732
|
return;
|
|
5475
5733
|
}
|
|
5734
|
+
if (skipped.length > 0) {
|
|
5735
|
+
console.log(`Skipping ${skipped.length} device(s) not in 'device' state:`);
|
|
5736
|
+
for (const d of skipped) {
|
|
5737
|
+
console.log(` ${d.serial}: ${d.rawStatus}`);
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5476
5740
|
console.log(`Discovered ${devices.length} device(s) via adb.`);
|
|
5477
5741
|
await deviceRuntime.ensureAgent(reporter);
|
|
5478
5742
|
reporter.stop();
|
|
@@ -5712,7 +5976,7 @@ async function maybeNotifyFleetWithHint(cfg) {
|
|
|
5712
5976
|
console.log("it, the device is recorded in ~/.beeos/devices.json but");
|
|
5713
5977
|
console.log("no process is supervising the per-device agent.");
|
|
5714
5978
|
console.log("");
|
|
5715
|
-
const rl =
|
|
5979
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
5716
5980
|
const answer = await new Promise((resolve) => {
|
|
5717
5981
|
rl.question("Enable fleet now (registers a launchd service)? [Y/n]: ", (a) => {
|
|
5718
5982
|
rl.close();
|
|
@@ -5886,7 +6150,7 @@ Android SDK Platform-Tools (adb) is licensed under the Android SDK License Agree
|
|
|
5886
6150
|
Set BEEOS_ACCEPT_ADB_LICENSE=1 in your environment to skip this prompt next time.
|
|
5887
6151
|
`
|
|
5888
6152
|
);
|
|
5889
|
-
const rl =
|
|
6153
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
5890
6154
|
const ans = await new Promise((resolve) => {
|
|
5891
6155
|
rl.question("Agree to the Android SDK license and download platform-tools? [Y/n]: ", (a) => {
|
|
5892
6156
|
rl.close();
|
|
@@ -5900,6 +6164,7 @@ var init_attach = __esm({
|
|
|
5900
6164
|
"use strict";
|
|
5901
6165
|
init_dist();
|
|
5902
6166
|
init_progress2();
|
|
6167
|
+
init_instance_picker();
|
|
5903
6168
|
init_fallback_banner();
|
|
5904
6169
|
init_fleet_notify();
|
|
5905
6170
|
init_state2();
|
|
@@ -6136,11 +6401,65 @@ var init_refresh_config = __esm({
|
|
|
6136
6401
|
}
|
|
6137
6402
|
});
|
|
6138
6403
|
|
|
6404
|
+
// src/commands/device/discover.ts
|
|
6405
|
+
async function run6(options = {}) {
|
|
6406
|
+
const reporter = new CliReporter();
|
|
6407
|
+
await ensureAdb(reporter, { autoInstall: false });
|
|
6408
|
+
reporter.stop();
|
|
6409
|
+
let devices;
|
|
6410
|
+
try {
|
|
6411
|
+
devices = await deviceRuntime.listAdbDevices();
|
|
6412
|
+
} catch (e) {
|
|
6413
|
+
if (options.json) {
|
|
6414
|
+
emitJsonEnvelope(jsonOk({ devices: [], selected: null, action: "skip" }));
|
|
6415
|
+
return;
|
|
6416
|
+
}
|
|
6417
|
+
console.log("ADB is not available \u2014 install Android platform-tools or run `beeos device attach` once to auto-install.");
|
|
6418
|
+
console.log(` (${e instanceof Error ? e.message : String(e)})`);
|
|
6419
|
+
return;
|
|
6420
|
+
}
|
|
6421
|
+
if (options.json) {
|
|
6422
|
+
emitJsonEnvelope(
|
|
6423
|
+
jsonOk({
|
|
6424
|
+
devices: devices.map((d) => ({
|
|
6425
|
+
serial: d.serial,
|
|
6426
|
+
status: d.status,
|
|
6427
|
+
rawStatus: d.rawStatus
|
|
6428
|
+
})),
|
|
6429
|
+
selected: null,
|
|
6430
|
+
action: "list"
|
|
6431
|
+
})
|
|
6432
|
+
);
|
|
6433
|
+
return;
|
|
6434
|
+
}
|
|
6435
|
+
const candidates = devices.map((d) => ({
|
|
6436
|
+
kind: "device",
|
|
6437
|
+
serial: d.serial,
|
|
6438
|
+
status: d.status
|
|
6439
|
+
}));
|
|
6440
|
+
const sel = await pickInstanceInteractive(candidates, { caller: "discover" });
|
|
6441
|
+
if (sel.kind === "skip") return;
|
|
6442
|
+
if (sel.kind === "device") {
|
|
6443
|
+
await attach({ serial: sel.serial });
|
|
6444
|
+
}
|
|
6445
|
+
}
|
|
6446
|
+
var init_discover = __esm({
|
|
6447
|
+
"src/commands/device/discover.ts"() {
|
|
6448
|
+
"use strict";
|
|
6449
|
+
init_dist();
|
|
6450
|
+
init_progress2();
|
|
6451
|
+
init_json_envelope();
|
|
6452
|
+
init_instance_picker();
|
|
6453
|
+
init_attach();
|
|
6454
|
+
}
|
|
6455
|
+
});
|
|
6456
|
+
|
|
6139
6457
|
// src/commands/device/index.ts
|
|
6140
6458
|
var device_exports = {};
|
|
6141
6459
|
__export(device_exports, {
|
|
6142
6460
|
attach: () => attach,
|
|
6143
6461
|
detach: () => detach,
|
|
6462
|
+
discover: () => run6,
|
|
6144
6463
|
exec: () => exec,
|
|
6145
6464
|
list: () => list,
|
|
6146
6465
|
nextHttpPort: () => nextHttpPort,
|
|
@@ -6156,6 +6475,7 @@ var init_device2 = __esm({
|
|
|
6156
6475
|
init_exec();
|
|
6157
6476
|
init_upgrade2();
|
|
6158
6477
|
init_refresh_config();
|
|
6478
|
+
init_discover();
|
|
6159
6479
|
init_state2();
|
|
6160
6480
|
}
|
|
6161
6481
|
});
|
|
@@ -6379,18 +6699,8 @@ var NodePlatformAdapter = class {
|
|
|
6379
6699
|
init_dist();
|
|
6380
6700
|
init_progress2();
|
|
6381
6701
|
init_fallback_banner();
|
|
6702
|
+
init_json_envelope();
|
|
6382
6703
|
import os6 from "os";
|
|
6383
|
-
|
|
6384
|
-
// src/json-envelope.ts
|
|
6385
|
-
init_dist();
|
|
6386
|
-
function jsonOk(data) {
|
|
6387
|
-
return { ok: true, data };
|
|
6388
|
-
}
|
|
6389
|
-
function emitJsonEnvelope(env) {
|
|
6390
|
-
console.log(JSON.stringify(env, null, 2));
|
|
6391
|
-
}
|
|
6392
|
-
|
|
6393
|
-
// src/commands/start.ts
|
|
6394
6704
|
async function run(agentFramework, options) {
|
|
6395
6705
|
const p = getPlatformAdapter();
|
|
6396
6706
|
await ensureDirs();
|
|
@@ -6581,6 +6891,7 @@ async function run2(agentFramework) {
|
|
|
6581
6891
|
|
|
6582
6892
|
// src/commands/status.ts
|
|
6583
6893
|
init_dist();
|
|
6894
|
+
init_json_envelope();
|
|
6584
6895
|
async function run3(options = {}) {
|
|
6585
6896
|
const home = beeoHome();
|
|
6586
6897
|
const cfg = await loadOrCreateConfig();
|
|
@@ -6646,6 +6957,7 @@ function formatService(s) {
|
|
|
6646
6957
|
|
|
6647
6958
|
// src/commands/update.ts
|
|
6648
6959
|
init_dist();
|
|
6960
|
+
init_json_envelope();
|
|
6649
6961
|
init_upgrade2();
|
|
6650
6962
|
async function run4(agentFramework, options = {}) {
|
|
6651
6963
|
if (agentFramework === "device") {
|
|
@@ -6686,6 +6998,7 @@ async function run4(agentFramework, options = {}) {
|
|
|
6686
6998
|
|
|
6687
6999
|
// src/commands/bind-status.ts
|
|
6688
7000
|
init_dist();
|
|
7001
|
+
init_json_envelope();
|
|
6689
7002
|
async function run5(bindId, options) {
|
|
6690
7003
|
const cfg = await loadOrCreateConfig();
|
|
6691
7004
|
const resp = await getBindStatus(cfg.platform.api_url, bindId);
|
|
@@ -6749,14 +7062,15 @@ init_device2();
|
|
|
6749
7062
|
|
|
6750
7063
|
// src/commands/init.ts
|
|
6751
7064
|
init_dist();
|
|
6752
|
-
import
|
|
7065
|
+
import readline3 from "readline";
|
|
6753
7066
|
|
|
6754
7067
|
// src/commands/doctor.ts
|
|
6755
7068
|
init_dist();
|
|
7069
|
+
init_json_envelope();
|
|
6756
7070
|
import fs9 from "fs/promises";
|
|
6757
7071
|
import path9 from "path";
|
|
6758
7072
|
var LOG_SIZE_WARN_BYTES = 50 * 1024 * 1024;
|
|
6759
|
-
async function
|
|
7073
|
+
async function run7(options) {
|
|
6760
7074
|
const state = await detectExistingInstall();
|
|
6761
7075
|
const cfg = await loadOrCreateConfig();
|
|
6762
7076
|
const p = getPlatformAdapter();
|
|
@@ -7062,9 +7376,11 @@ function formatAgentGatewayStatus(h) {
|
|
|
7062
7376
|
}
|
|
7063
7377
|
|
|
7064
7378
|
// src/commands/init.ts
|
|
7379
|
+
init_attach();
|
|
7065
7380
|
init_progress2();
|
|
7066
7381
|
init_fallback_banner();
|
|
7067
|
-
|
|
7382
|
+
init_instance_picker();
|
|
7383
|
+
async function run8(options) {
|
|
7068
7384
|
await ensureDirs();
|
|
7069
7385
|
if (options.device) {
|
|
7070
7386
|
const { attach: attach2 } = await Promise.resolve().then(() => (init_device2(), device_exports));
|
|
@@ -7073,7 +7389,7 @@ async function run7(options) {
|
|
|
7073
7389
|
}
|
|
7074
7390
|
const state = await detectExistingInstall();
|
|
7075
7391
|
if (options.json) {
|
|
7076
|
-
await
|
|
7392
|
+
await run7({ json: true });
|
|
7077
7393
|
} else {
|
|
7078
7394
|
printBanner();
|
|
7079
7395
|
for (const line of summarizeExistingInstall(state)) {
|
|
@@ -7099,10 +7415,45 @@ async function run7(options) {
|
|
|
7099
7415
|
}
|
|
7100
7416
|
console.log("Ensuring OpenClaw is running...\n");
|
|
7101
7417
|
}
|
|
7102
|
-
if (decision === "rebind
|
|
7418
|
+
if (decision === "rebind") {
|
|
7419
|
+
await removeBindingInfo();
|
|
7420
|
+
}
|
|
7421
|
+
if (decision === "reset-all") {
|
|
7103
7422
|
await rotateIdentity();
|
|
7104
7423
|
await removeBindingInfo();
|
|
7105
7424
|
}
|
|
7425
|
+
if (decision === "fresh" && !options.framework && !options.yes && !options.json && process.stdin.isTTY) {
|
|
7426
|
+
const sel = await pickFreshInstance(options);
|
|
7427
|
+
if (sel.kind === "skip") {
|
|
7428
|
+
console.log("Skipped. Re-run `beeos init` or `beeos device attach` whenever ready.");
|
|
7429
|
+
return;
|
|
7430
|
+
}
|
|
7431
|
+
if (sel.kind === "device") {
|
|
7432
|
+
await attach({ serial: sel.serial });
|
|
7433
|
+
return;
|
|
7434
|
+
}
|
|
7435
|
+
const descriptor2 = frameworkById(sel.id);
|
|
7436
|
+
if (!descriptor2 || descriptor2.status !== "available") {
|
|
7437
|
+
throw new BeeosError({
|
|
7438
|
+
code: "framework_unavailable",
|
|
7439
|
+
message: `Agent framework '${sel.id}' is not available.`,
|
|
7440
|
+
hint: "Pick a different framework or reinstall the CLI.",
|
|
7441
|
+
details: { requested: sel.id, available: availableFrameworks().map((f) => f.id) }
|
|
7442
|
+
});
|
|
7443
|
+
}
|
|
7444
|
+
await run(descriptor2.id, {
|
|
7445
|
+
force: true,
|
|
7446
|
+
json: options.json,
|
|
7447
|
+
browser: options.browser !== false
|
|
7448
|
+
});
|
|
7449
|
+
if (!options.json && !options.skipServicePrompt) {
|
|
7450
|
+
await maybePromptServiceInstall();
|
|
7451
|
+
}
|
|
7452
|
+
if (!options.json) {
|
|
7453
|
+
printNextSteps();
|
|
7454
|
+
}
|
|
7455
|
+
return;
|
|
7456
|
+
}
|
|
7106
7457
|
const frameworkId = await decideFramework(state, decision, options);
|
|
7107
7458
|
const descriptor = frameworkById(frameworkId);
|
|
7108
7459
|
if (!descriptor || descriptor.status !== "available") {
|
|
@@ -7201,6 +7552,32 @@ async function decideFramework(state, decision, options) {
|
|
|
7201
7552
|
}
|
|
7202
7553
|
return picked.id;
|
|
7203
7554
|
}
|
|
7555
|
+
async function safeListAdbDevices() {
|
|
7556
|
+
const adbPath = await findAdb().catch(() => null);
|
|
7557
|
+
if (!adbPath) return [];
|
|
7558
|
+
try {
|
|
7559
|
+
return await deviceRuntime.listAdbDevices();
|
|
7560
|
+
} catch {
|
|
7561
|
+
return [];
|
|
7562
|
+
}
|
|
7563
|
+
}
|
|
7564
|
+
async function pickFreshInstance(_opts) {
|
|
7565
|
+
const frameworks = availableFrameworks().map((f) => ({
|
|
7566
|
+
kind: "framework",
|
|
7567
|
+
id: f.id,
|
|
7568
|
+
label: f.displayName,
|
|
7569
|
+
description: f.description,
|
|
7570
|
+
isDefault: f.id === defaultFrameworkId()
|
|
7571
|
+
}));
|
|
7572
|
+
const devices = (await safeListAdbDevices()).map((d) => ({
|
|
7573
|
+
kind: "device",
|
|
7574
|
+
serial: d.serial,
|
|
7575
|
+
status: d.status
|
|
7576
|
+
}));
|
|
7577
|
+
return pickInstanceInteractive([...frameworks, ...devices], {
|
|
7578
|
+
caller: "init"
|
|
7579
|
+
});
|
|
7580
|
+
}
|
|
7204
7581
|
async function maybePromptServiceInstall() {
|
|
7205
7582
|
try {
|
|
7206
7583
|
const mgr = await getServiceManager();
|
|
@@ -7252,7 +7629,7 @@ function printNextSteps() {
|
|
|
7252
7629
|
console.log("");
|
|
7253
7630
|
}
|
|
7254
7631
|
function prompt(question) {
|
|
7255
|
-
const rl =
|
|
7632
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
7256
7633
|
return new Promise((resolve) => {
|
|
7257
7634
|
rl.question(question, (answer) => {
|
|
7258
7635
|
rl.close();
|
|
@@ -7328,6 +7705,7 @@ async function pickInstalledPackages() {
|
|
|
7328
7705
|
|
|
7329
7706
|
// src/commands/service.ts
|
|
7330
7707
|
init_dist();
|
|
7708
|
+
init_json_envelope();
|
|
7331
7709
|
async function install(options) {
|
|
7332
7710
|
const mgr = await getServiceManager();
|
|
7333
7711
|
const check = await mgr.selfCheck();
|
|
@@ -7412,7 +7790,8 @@ async function status(options) {
|
|
|
7412
7790
|
|
|
7413
7791
|
// src/commands/migrate.ts
|
|
7414
7792
|
init_dist();
|
|
7415
|
-
|
|
7793
|
+
init_json_envelope();
|
|
7794
|
+
async function run9(options) {
|
|
7416
7795
|
await ensureDirs();
|
|
7417
7796
|
const mgr = await getServiceManager();
|
|
7418
7797
|
const mig = await migrateLegacySupervisor(mgr);
|
|
@@ -7449,6 +7828,7 @@ async function run8(options) {
|
|
|
7449
7828
|
|
|
7450
7829
|
// src/commands/logs.ts
|
|
7451
7830
|
init_dist();
|
|
7831
|
+
init_json_envelope();
|
|
7452
7832
|
function resolveLogTarget(input, services) {
|
|
7453
7833
|
const exact = services.find((s) => s.id === input);
|
|
7454
7834
|
if (exact) {
|
|
@@ -7470,7 +7850,7 @@ function resolveLogTarget(input, services) {
|
|
|
7470
7850
|
matchedFrom: "fallback"
|
|
7471
7851
|
};
|
|
7472
7852
|
}
|
|
7473
|
-
async function
|
|
7853
|
+
async function run10(idArg, options) {
|
|
7474
7854
|
const mgr = await getServiceManager();
|
|
7475
7855
|
let services = [];
|
|
7476
7856
|
try {
|
|
@@ -7544,12 +7924,12 @@ setPlatformAdapter(new NodePlatformAdapter());
|
|
|
7544
7924
|
var program = new Command();
|
|
7545
7925
|
var cliVersion = getCliVersion(import.meta.url, resolveActiveDistTag());
|
|
7546
7926
|
program.name("beeos").version(cliVersion.display).description("BeeOS \u2014 run AI agents from your desktop");
|
|
7547
|
-
program.command("init").description("One-shot install + bind flow (default entry from the curl installer)").option("--framework <name>", "Agent framework to install (default: openclaw)").option("--yes", "Non-interactive \u2014 accept the default action", false).option("--json", "Output machine-readable JSON (implies --yes)", false).option("--no-browser", "Don't auto-open a browser for bind confirmation").option("--headless", "Never open a browser (use terminal QR only)", false).option("--skip-service-prompt", "Skip the system-service install prompt", false).option("--device", "Jump straight into `beeos device attach` instead", false).action((opts) =>
|
|
7548
|
-
program.command("doctor").description("Inspect local BeeOS state (install, binding, services, warnings)").option("--json", "Output machine-readable JSON", false).action((opts) =>
|
|
7549
|
-
program.command("migrate").description("Migrate legacy Node supervisor state to OS-native services (one-shot)").option("--json", "Output machine-readable JSON", false).action((opts) =>
|
|
7927
|
+
program.command("init").description("One-shot install + bind flow (default entry from the curl installer)").option("--framework <name>", "Agent framework to install (default: openclaw)").option("--yes", "Non-interactive \u2014 accept the default action", false).option("--json", "Output machine-readable JSON (implies --yes)", false).option("--no-browser", "Don't auto-open a browser for bind confirmation").option("--headless", "Never open a browser (use terminal QR only)", false).option("--skip-service-prompt", "Skip the system-service install prompt", false).option("--device", "Jump straight into `beeos device attach` instead", false).action((opts) => run8(opts));
|
|
7928
|
+
program.command("doctor").description("Inspect local BeeOS state (install, binding, services, warnings)").option("--json", "Output machine-readable JSON", false).action((opts) => run7(opts));
|
|
7929
|
+
program.command("migrate").description("Migrate legacy Node supervisor state to OS-native services (one-shot)").option("--json", "Output machine-readable JSON", false).action((opts) => run9(opts));
|
|
7550
7930
|
program.command("logs").description(
|
|
7551
7931
|
"Tail logs for a BeeOS service. Pass an ADB serial or service id; omit to list every registered service's log file path."
|
|
7552
|
-
).argument("[id]", "Service id (e.g. `device-agent-<serial>`) or raw ADB serial").option("-f, --follow", "Stream new log lines (Ctrl-C to exit)", false).option("-n, --lines <n>", "Initial trailing lines to print (default 50)", (v) => Number(v)).option("--json", "Output machine-readable JSON (resolves the path; does not stream)", false).action((id, opts) =>
|
|
7932
|
+
).argument("[id]", "Service id (e.g. `device-agent-<serial>`) or raw ADB serial").option("-f, --follow", "Stream new log lines (Ctrl-C to exit)", false).option("-n, --lines <n>", "Initial trailing lines to print (default 50)", (v) => Number(v)).option("--json", "Output machine-readable JSON (resolves the path; does not stream)", false).action((id, opts) => run10(id, opts));
|
|
7553
7933
|
var serviceCmd = program.command("service").description("Inspect and manage the OS-native service manager (launchd / systemd --user / Task Scheduler)");
|
|
7554
7934
|
serviceCmd.command("install").description("Verify the OS service manager is available (per-target services install automatically)").option("--json", "Output machine-readable JSON", false).action((opts) => install(opts));
|
|
7555
7935
|
serviceCmd.command("uninstall").description("Uninstall every BeeOS-managed OS service").option("--json", "Output machine-readable JSON", false).action((opts) => uninstall(opts));
|
|
@@ -7577,6 +7957,9 @@ deviceCmd.command("upgrade").description("Upgrade the device-agent (and scrcpy/v
|
|
|
7577
7957
|
deviceCmd.command("refresh-config").description(
|
|
7578
7958
|
"Re-fetch this device's VLM/ARouter config from Agent Gateway and rewrite ~/.beeos/<instance_id>.config.json (use after dashboard changes)."
|
|
7579
7959
|
).option("--serial <serial>", "ADB device serial number").option("--all", "Refresh every attached device", false).action(refreshConfig);
|
|
7960
|
+
deviceCmd.command("discover").description(
|
|
7961
|
+
"List ADB devices and pick one to attach (interactive). Use this when you've plugged in a phone after `beeos init` and want to attach it without remembering --serial."
|
|
7962
|
+
).option("--json", "Output machine-readable JSON envelope ({ok,data})", false).action((opts) => run6(opts));
|
|
7580
7963
|
program.parseAsync(process.argv).catch((err) => {
|
|
7581
7964
|
const wantsJson = process.argv.includes("--json");
|
|
7582
7965
|
if (isBeeosError(err)) {
|