@kvell007/embed-labs-cli 0.1.0-alpha.22 → 0.1.0-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.js +109 -11
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -118,6 +118,7 @@ For local hardware access:
|
|
|
118
118
|
embed bridge start
|
|
119
119
|
embed device list
|
|
120
120
|
embed tool call wifi.scan --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
121
|
+
embed tool call rp2350.monitor.spi.transfer --input-json '{"hex":"a55a3cc3"}' --approve
|
|
121
122
|
embed tool call chip.temperature --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
122
123
|
embed flash plan --board <rp2350|taishanpi> --artifact ./artifact.bin
|
|
123
124
|
```
|
|
@@ -198,6 +199,7 @@ embed tool call chip.cpu.frequency --input-json '{"host":"198.19.77.2","user":"r
|
|
|
198
199
|
embed tool call chip.temperature --input-json '{"host":"198.19.77.2","user":"root"}' [--json]
|
|
199
200
|
embed tool call qml.runtime.status --input-json '{"host":"198.19.77.2","user":"root","port":18130}' [--json]
|
|
200
201
|
embed tool call qml.runtime.start --input-json '{"host":"198.19.77.2","user":"root","port":18130}' [--json]
|
|
202
|
+
embed tool call rp2350.monitor.spi.transfer --input-json '{"hex":"a55a3cc3"}' --approve [--json]
|
|
201
203
|
|
|
202
204
|
embed serial list [--json]
|
|
203
205
|
embed serial capture --path <port> [--baud 115200] [--duration 5] [--json]
|
package/dist/index.js
CHANGED
|
@@ -1392,19 +1392,34 @@ function isApiResponse(value) {
|
|
|
1392
1392
|
return isJsonObject(error) && typeof error.code === "string" && typeof error.message === "string";
|
|
1393
1393
|
}
|
|
1394
1394
|
async function bridgeGet(path) {
|
|
1395
|
-
|
|
1396
|
-
headers: bridgeHeaders("GET", path, "")
|
|
1397
|
-
});
|
|
1398
|
-
return await response.json();
|
|
1395
|
+
return await bridgeRequest("GET", path);
|
|
1399
1396
|
}
|
|
1400
1397
|
async function bridgePost(path, body) {
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1398
|
+
return await bridgeRequest("POST", path, body);
|
|
1399
|
+
}
|
|
1400
|
+
async function bridgeRequest(method, path, body) {
|
|
1401
|
+
const bodyText = body === undefined ? "" : JSON.stringify(body);
|
|
1402
|
+
const makeRequest = async () => {
|
|
1403
|
+
const response = await fetch(`${DEFAULT_BRIDGE_URL}${path}`, {
|
|
1404
|
+
method,
|
|
1405
|
+
headers: bridgeHeaders(method, path, method === "POST" ? bodyText : "", method === "POST" ? { "content-type": "application/json" } : {}),
|
|
1406
|
+
body: method === "POST" ? bodyText : undefined
|
|
1407
|
+
});
|
|
1408
|
+
return await response.json();
|
|
1409
|
+
};
|
|
1410
|
+
try {
|
|
1411
|
+
return await makeRequest();
|
|
1412
|
+
}
|
|
1413
|
+
catch (error) {
|
|
1414
|
+
if (!isBridgeConnectionFailure(error)) {
|
|
1415
|
+
throw error;
|
|
1416
|
+
}
|
|
1417
|
+
const started = await ensureBridgeStartedForRequest();
|
|
1418
|
+
if (!started.ok) {
|
|
1419
|
+
return started;
|
|
1420
|
+
}
|
|
1421
|
+
return await makeRequest();
|
|
1422
|
+
}
|
|
1408
1423
|
}
|
|
1409
1424
|
function bridgeHeaders(method, path, bodyText, base = {}) {
|
|
1410
1425
|
const token = process.env.EMBED_BRIDGE_TOKEN?.trim();
|
|
@@ -1433,6 +1448,87 @@ function addBridgeRequestSignature(headers, method, pathWithQuery, bodyText, tok
|
|
|
1433
1448
|
headers["x-embed-body-sha256"] = bodySha256;
|
|
1434
1449
|
headers["x-embed-signature"] = createHmac("sha256", token).update(canonical).digest("hex");
|
|
1435
1450
|
}
|
|
1451
|
+
function isBridgeConnectionFailure(error) {
|
|
1452
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1453
|
+
return message.includes("fetch failed") ||
|
|
1454
|
+
message.includes("ECONNREFUSED") ||
|
|
1455
|
+
message.includes("ECONNRESET") ||
|
|
1456
|
+
message.includes("UND_ERR_SOCKET");
|
|
1457
|
+
}
|
|
1458
|
+
async function ensureBridgeStartedForRequest() {
|
|
1459
|
+
if (process.env.EMBED_BRIDGE_AUTO_START === "0") {
|
|
1460
|
+
return fail("bridge_unavailable", `embed-local-bridge is not running at ${DEFAULT_BRIDGE_URL}.`, {
|
|
1461
|
+
remediation: `Start it with: embed bridge start`
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
let bridgeURL;
|
|
1465
|
+
try {
|
|
1466
|
+
bridgeURL = new URL(DEFAULT_BRIDGE_URL);
|
|
1467
|
+
}
|
|
1468
|
+
catch {
|
|
1469
|
+
return fail("bridge_url_invalid", `EMBED_BRIDGE_URL is not a valid URL: ${DEFAULT_BRIDGE_URL}`);
|
|
1470
|
+
}
|
|
1471
|
+
if (!isLocalBridgeURL(bridgeURL)) {
|
|
1472
|
+
return fail("bridge_unavailable", `embed-local-bridge is not reachable at ${DEFAULT_BRIDGE_URL}.`, {
|
|
1473
|
+
remediation: `Start the bridge for that host, or set EMBED_BRIDGE_URL to a local bridge URL.`
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
const launcher = await resolveBridgeLauncher();
|
|
1477
|
+
const host = bridgeURL.hostname === "::1" ? "::1" : bridgeURL.hostname || "127.0.0.1";
|
|
1478
|
+
const port = bridgeURL.port || "18083";
|
|
1479
|
+
const env = {
|
|
1480
|
+
...process.env,
|
|
1481
|
+
EMBED_BRIDGE_HOST: host,
|
|
1482
|
+
EMBED_BRIDGE_PORT: port
|
|
1483
|
+
};
|
|
1484
|
+
const child = spawn(launcher.command, [...launcher.args, "--host", host, "--port", port], {
|
|
1485
|
+
cwd: process.cwd(),
|
|
1486
|
+
detached: true,
|
|
1487
|
+
stdio: "ignore",
|
|
1488
|
+
env
|
|
1489
|
+
});
|
|
1490
|
+
child.unref();
|
|
1491
|
+
const ready = await waitForBridgeHealth(bridgeURL, 8000);
|
|
1492
|
+
if (!ready.ok) {
|
|
1493
|
+
return ready;
|
|
1494
|
+
}
|
|
1495
|
+
return ok({
|
|
1496
|
+
started: true,
|
|
1497
|
+
bridge_url: DEFAULT_BRIDGE_URL,
|
|
1498
|
+
command: launcher.command
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
function isLocalBridgeURL(url) {
|
|
1502
|
+
const host = url.hostname.toLowerCase();
|
|
1503
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
1504
|
+
}
|
|
1505
|
+
async function waitForBridgeHealth(bridgeURL, timeoutMs) {
|
|
1506
|
+
const deadline = Date.now() + timeoutMs;
|
|
1507
|
+
let lastError = "";
|
|
1508
|
+
while (Date.now() < deadline) {
|
|
1509
|
+
try {
|
|
1510
|
+
const response = await fetch(new URL("/healthz", bridgeURL), {
|
|
1511
|
+
headers: bridgeHeaders("GET", "/healthz", "")
|
|
1512
|
+
});
|
|
1513
|
+
const parsed = await response.json();
|
|
1514
|
+
if (parsed.ok) {
|
|
1515
|
+
return parsed;
|
|
1516
|
+
}
|
|
1517
|
+
lastError = parsed.error?.message ?? `HTTP ${response.status}`;
|
|
1518
|
+
}
|
|
1519
|
+
catch (error) {
|
|
1520
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
1521
|
+
}
|
|
1522
|
+
await delay(100);
|
|
1523
|
+
}
|
|
1524
|
+
return fail("bridge_start_failed", `embed-local-bridge did not become healthy at ${DEFAULT_BRIDGE_URL}.`, {
|
|
1525
|
+
remediation: `Run embed bridge start in a separate terminal and retry.`,
|
|
1526
|
+
details: { last_error: lastError }
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
function delay(ms) {
|
|
1530
|
+
return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
|
|
1531
|
+
}
|
|
1436
1532
|
async function cloudGet(path) {
|
|
1437
1533
|
return await cloudRequest("GET", path);
|
|
1438
1534
|
}
|
|
@@ -7557,6 +7653,7 @@ Local hardware:
|
|
|
7557
7653
|
embed tool list
|
|
7558
7654
|
embed tool call device.probe --input-json '{"host":"198.19.77.2","ports":[22,15301]}'
|
|
7559
7655
|
embed tool call wifi.scan --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
7656
|
+
embed tool call rp2350.monitor.spi.transfer --input-json '{"hex":"a55a3cc3"}' --approve
|
|
7560
7657
|
embed tool call chip.temperature --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
7561
7658
|
embed tool call qml.runtime.status --input-json '{"host":"198.19.77.2","user":"root","port":18130}'
|
|
7562
7659
|
embed device list
|
|
@@ -7781,6 +7878,7 @@ Usage:
|
|
|
7781
7878
|
embed tool call qml.runtime.start --input-json '{"host":"198.19.77.2","user":"root","port":18130}' [--json]
|
|
7782
7879
|
embed tool call rp2350.monitor.status [--json]
|
|
7783
7880
|
embed tool call rp2350.monitor.logic.capture --input-json '{"pin_base":16,"pin_count":4,"sample_rate":1000000,"samples":4096}' [--json]
|
|
7881
|
+
embed tool call rp2350.monitor.spi.transfer --input-json '{"hex":"a55a3cc3"}' --approve [--json]
|
|
7784
7882
|
embed tool call rp2350.monitor.logic.decode --input-json '{"input_path":".embed-labs/rp2350-monitor/captures/logic.jsonl","decoder":"summary"}' [--json]
|
|
7785
7883
|
embed deploy taishanpi --host <ip> --artifact <local_file> --approve [--remote-path /userdata/embed-labs/apps/app] [--run] [--json]
|
|
7786
7884
|
embed board deploy taishanpi --host <ip> --artifact <local_file> --approve [--remote-path /userdata/embed-labs/apps/app] [--run] [--json]
|