@beeos-ai/cli 1.0.11 → 1.0.13
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 +73 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1148,26 +1148,56 @@ function archiveName(cfg, target) {
|
|
|
1148
1148
|
const suffix = target.includes("windows") ? "zip" : "tar.gz";
|
|
1149
1149
|
return `${cfg.name}-${target}.${suffix}`;
|
|
1150
1150
|
}
|
|
1151
|
+
async function fetchArchiveBuffer(cfg, url, progress, maxAttempts = 3) {
|
|
1152
|
+
const p = getPlatformAdapter();
|
|
1153
|
+
let lastError = null;
|
|
1154
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1155
|
+
let resp;
|
|
1156
|
+
try {
|
|
1157
|
+
resp = await p.fetch(url);
|
|
1158
|
+
} catch (e) {
|
|
1159
|
+
lastError = String(e);
|
|
1160
|
+
progress.onStatus(`${cfg.name} download attempt ${attempt}/${maxAttempts} failed: ${lastError}`);
|
|
1161
|
+
if (attempt < maxAttempts) {
|
|
1162
|
+
await new Promise((r) => setTimeout(r, 1e3 * 2 ** (attempt - 1)));
|
|
1163
|
+
}
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
if (!resp.ok) {
|
|
1167
|
+
progress.onStatus(`${cfg.name} download: ${resp.status} ${resp.statusText} (${url})`);
|
|
1168
|
+
if (resp.status === 404) {
|
|
1169
|
+
progress.onStatus(`Hint: the current release may not include the requested target. Try setting $${cfg.binaryEnv} to a locally built binary, ` + (cfg.releaseUrlEnv ? `or $${cfg.releaseUrlEnv} to a different release URL.` : `or check for a newer release.`));
|
|
1170
|
+
}
|
|
1171
|
+
if (resp.status === 404 || resp.status === 403 || resp.status === 401) {
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
lastError = `${resp.status} ${resp.statusText}`;
|
|
1175
|
+
if (attempt < maxAttempts) {
|
|
1176
|
+
await new Promise((r) => setTimeout(r, 1e3 * 2 ** (attempt - 1)));
|
|
1177
|
+
}
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
try {
|
|
1181
|
+
return new Uint8Array(await resp.arrayBuffer());
|
|
1182
|
+
} catch (e) {
|
|
1183
|
+
lastError = String(e);
|
|
1184
|
+
progress.onStatus(`${cfg.name} stream interrupted on attempt ${attempt}/${maxAttempts}: ${lastError}`);
|
|
1185
|
+
if (attempt < maxAttempts) {
|
|
1186
|
+
await new Promise((r) => setTimeout(r, 1e3 * 2 ** (attempt - 1)));
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
progress.onStatus(`${cfg.name} download gave up after ${maxAttempts} attempts (last: ${lastError ?? "unknown"}).`);
|
|
1191
|
+
return null;
|
|
1192
|
+
}
|
|
1151
1193
|
async function downloadManagedBinary(cfg, target, progress) {
|
|
1152
1194
|
const p = getPlatformAdapter();
|
|
1153
1195
|
const base = releaseBaseUrl(cfg);
|
|
1154
1196
|
const url = `${base}/${archiveName(cfg, target)}`;
|
|
1155
1197
|
progress.onStatus(`Downloading ${cfg.name} (${target})...`);
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
resp = await p.fetch(url);
|
|
1159
|
-
} catch (e) {
|
|
1160
|
-
progress.onStatus(`${cfg.name} download failed: ${String(e)}`);
|
|
1161
|
-
return null;
|
|
1162
|
-
}
|
|
1163
|
-
if (!resp.ok) {
|
|
1164
|
-
progress.onStatus(`${cfg.name} download: ${resp.status} ${resp.statusText} (${url})`);
|
|
1165
|
-
if (resp.status === 404) {
|
|
1166
|
-
progress.onStatus(`Hint: the current release may not include ${target}. Try setting $${cfg.binaryEnv} to a locally built binary, ` + (cfg.releaseUrlEnv ? `or $${cfg.releaseUrlEnv} to a different release URL.` : `or check for a newer release.`));
|
|
1167
|
-
}
|
|
1198
|
+
const data = await fetchArchiveBuffer(cfg, url, progress);
|
|
1199
|
+
if (!data)
|
|
1168
1200
|
return null;
|
|
1169
|
-
}
|
|
1170
|
-
const data = new Uint8Array(await resp.arrayBuffer());
|
|
1171
1201
|
const digestUrl = `${url}.sha256`;
|
|
1172
1202
|
let expected = null;
|
|
1173
1203
|
try {
|
|
@@ -2651,13 +2681,13 @@ function inferInitChoices(state) {
|
|
|
2651
2681
|
if (state.hasIdentity && state.binding) {
|
|
2652
2682
|
return {
|
|
2653
2683
|
defaultDecision: "upgrade",
|
|
2654
|
-
options: ["upgrade", "rebind-
|
|
2684
|
+
options: ["upgrade", "rebind-new-key", "skip"]
|
|
2655
2685
|
};
|
|
2656
2686
|
}
|
|
2657
2687
|
if (state.hasIdentity) {
|
|
2658
2688
|
return {
|
|
2659
|
-
defaultDecision: "
|
|
2660
|
-
options: ["upgrade", "rebind-
|
|
2689
|
+
defaultDecision: "upgrade",
|
|
2690
|
+
options: ["upgrade", "rebind-new-key", "skip"]
|
|
2661
2691
|
};
|
|
2662
2692
|
}
|
|
2663
2693
|
return { defaultDecision: "fresh", options: ["fresh", "skip"] };
|
|
@@ -2667,9 +2697,7 @@ function initDecisionLabel(decision) {
|
|
|
2667
2697
|
case "fresh":
|
|
2668
2698
|
return "Install + bind";
|
|
2669
2699
|
case "upgrade":
|
|
2670
|
-
return "Upgrade CLI & agents (keep binding)";
|
|
2671
|
-
case "rebind-keep-key":
|
|
2672
|
-
return "Re-bind (keep existing Ed25519 key)";
|
|
2700
|
+
return "Upgrade CLI & agents (keep binding & key)";
|
|
2673
2701
|
case "rebind-new-key":
|
|
2674
2702
|
return "Re-bind (rotate Ed25519 key)";
|
|
2675
2703
|
case "skip":
|
|
@@ -4658,7 +4686,11 @@ async function registerVideoBridge(_mgr, reporter, params) {
|
|
|
4658
4686
|
if (!params.withVideo) return { mode: "none" };
|
|
4659
4687
|
const agentGatewayUrl = resolveAgentGatewayUrl(params.cfg);
|
|
4660
4688
|
if (params.vncHost) {
|
|
4661
|
-
const binary2 = await
|
|
4689
|
+
const binary2 = await ensureBridgeBinaryDegraded(
|
|
4690
|
+
vncBridgeRuntime.ensureInstalled.bind(vncBridgeRuntime),
|
|
4691
|
+
reporter,
|
|
4692
|
+
"vnc-bridge"
|
|
4693
|
+
);
|
|
4662
4694
|
if (!binary2) {
|
|
4663
4695
|
console.error(
|
|
4664
4696
|
` vnc-bridge binary unavailable \u2014 ${params.serial} will run without VNC streaming.`
|
|
@@ -4678,16 +4710,33 @@ async function registerVideoBridge(_mgr, reporter, params) {
|
|
|
4678
4710
|
await installService(_mgr, spec);
|
|
4679
4711
|
return { mode: "vnc" };
|
|
4680
4712
|
}
|
|
4681
|
-
const binary = await
|
|
4713
|
+
const binary = await ensureBridgeBinaryDegraded(
|
|
4714
|
+
scrcpyBridgeRuntime.ensureInstalled.bind(scrcpyBridgeRuntime),
|
|
4715
|
+
reporter,
|
|
4716
|
+
"scrcpy-bridge"
|
|
4717
|
+
);
|
|
4682
4718
|
if (!binary) {
|
|
4683
4719
|
console.error(
|
|
4684
4720
|
` scrcpy-bridge binary unavailable \u2014 ${params.serial} will run without WebRTC video.
|
|
4685
|
-
|
|
4721
|
+
ACP control + screenshots still work. To recover live video later:
|
|
4722
|
+
\u2022 re-run: beeos device attach --serial ${params.serial} (will retry the download)
|
|
4723
|
+
\u2022 or download from https://github.com/beeos-ai/scrcpy-bridge/releases
|
|
4724
|
+
and set BEEOS_SCRCPY_BRIDGE_BIN to its absolute path.`
|
|
4686
4725
|
);
|
|
4687
4726
|
return { mode: "none" };
|
|
4688
4727
|
}
|
|
4689
4728
|
return { mode: "scrcpy" };
|
|
4690
4729
|
}
|
|
4730
|
+
async function ensureBridgeBinaryDegraded(fn, reporter, label) {
|
|
4731
|
+
try {
|
|
4732
|
+
return await fn(reporter);
|
|
4733
|
+
} catch (e) {
|
|
4734
|
+
console.error(
|
|
4735
|
+
` ${label} install threw unexpectedly (${String(e)}) \u2014 degrading to no-video mode.`
|
|
4736
|
+
);
|
|
4737
|
+
return null;
|
|
4738
|
+
}
|
|
4739
|
+
}
|
|
4691
4740
|
async function ensureAdbAvailable(reporter) {
|
|
4692
4741
|
const existing = await findAdb();
|
|
4693
4742
|
if (existing) return;
|
|
@@ -5746,8 +5795,6 @@ async function run7(options) {
|
|
|
5746
5795
|
}
|
|
5747
5796
|
if (decision === "rebind-new-key") {
|
|
5748
5797
|
await rotateIdentity();
|
|
5749
|
-
}
|
|
5750
|
-
if (decision === "rebind-keep-key" || decision === "rebind-new-key") {
|
|
5751
5798
|
await removeBindingInfo();
|
|
5752
5799
|
}
|
|
5753
5800
|
const frameworkId = await decideFramework(state, decision, options);
|
|
@@ -5800,7 +5847,7 @@ async function decideFramework(state, decision, options) {
|
|
|
5800
5847
|
if (options.framework && options.framework.trim()) {
|
|
5801
5848
|
return options.framework.trim();
|
|
5802
5849
|
}
|
|
5803
|
-
if (state.binding &&
|
|
5850
|
+
if (state.binding && decision === "upgrade") {
|
|
5804
5851
|
const persisted = state.binding.framework?.trim();
|
|
5805
5852
|
if (persisted) return persisted;
|
|
5806
5853
|
return defaultFrameworkId();
|