@kvell007/embed-labs-cli 0.1.0-alpha.2 → 0.1.0-alpha.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/README.md +35 -13
- package/dist/image-compose.d.ts +38 -0
- package/dist/image-compose.js +334 -0
- package/dist/image-compose.js.map +1 -0
- package/dist/index.js +1057 -35
- package/dist/index.js.map +1 -1
- package/dist/local-toolchain.d.ts +143 -0
- package/dist/local-toolchain.js +576 -0
- package/dist/local-toolchain.js.map +1 -0
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
+
import { constants } from "node:fs";
|
|
3
4
|
import { spawn } from "node:child_process";
|
|
4
|
-
import { cp, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
5
|
+
import { access, cp, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
5
6
|
import { createRequire } from "node:module";
|
|
6
7
|
import { homedir, tmpdir } from "node:os";
|
|
7
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
8
|
+
import { basename, delimiter, dirname, join, resolve } from "node:path";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { startServer } from "@embed-labs/local-bridge";
|
|
11
|
+
import { composeBootLogoPackage } from "./image-compose.js";
|
|
12
|
+
import { buildTaishanPiQtSmoke, compileTaishanPiSingleFile, currentLocalToolchain, installLocalToolchain, latestLocalToolchain, validateLocalToolchain } from "./local-toolchain.js";
|
|
10
13
|
import { fail, ok } from "@embed-labs/protocol";
|
|
11
14
|
const require = createRequire(import.meta.url);
|
|
12
15
|
const CLI_MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
@@ -74,6 +77,16 @@ const BUILD_APPLICATION_STUB_USAGE = "Usage: embed build application stub --work
|
|
|
74
77
|
const BUILD_APPLICATION_GENERATE_USAGE = "Usage: embed build application generate --workspace <workspace_id> --prompt <request> [--account <account_id>] [--target <source_path>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--json]";
|
|
75
78
|
const BUILD_APPLICATION_COMPILE_USAGE = "Usage: embed build application compile --workspace <workspace_id> [--account <account_id>] [--source <source_path>] [--execution-mode docker_worker|server_direct|dry_run] [--compiler auto|cc|gcc|clang|aarch64-linux-gnu-gcc] [--json]";
|
|
76
79
|
const BUILD_IMAGE_GENERATE_USAGE = "Usage: embed build image generate --workspace <workspace_id> --prompt <request> [--account <account_id>] [--image-profile <profile_id>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--execution-mode cloud_worker|dry_run] [--worker-pool <pool>] [--json]";
|
|
80
|
+
const BUILD_IMAGE_BOOT_LOGO_USAGE = "Usage: embed build image boot-logo --logo <local_image> [--account <account_id>] [--project <project_id>] [--board taishanpi] [--variant 1M-RK3566] [--kernel-logo <local_image>] [--rotate -90] [--scale 100] [--output <package.json>] [--json]";
|
|
81
|
+
const IMAGE_BOOT_LOGO_COMPOSE_USAGE = "Usage: embed image boot-logo compose --package <boot-logo-package.json> --base-image <boot.img|image.img> --output <image> [--manifest <manifest.json>] [--force] [--json]";
|
|
82
|
+
const BUILD_IMAGE_DTB_USAGE = "Usage: embed build image dtb --dtb <local.dtb|local.dts> [--input-format auto|dtb|dts] [--account <account_id>] [--project <project_id>] [--board taishanpi] [--variant 1M-RK3566] [--output <package.json>] [--json]";
|
|
83
|
+
const IMAGE_DTB_COMPOSE_USAGE = "Usage: embed image dtb compose --package <dtb-package.json> --base-image <boot.img|image.img> --output <image> [--manifest <manifest.json>] [--force] [--json]";
|
|
84
|
+
const LOCAL_TOOLCHAIN_LATEST_USAGE = "Usage: embed local toolchain latest [--board taishanpi-1m-rk3566] [--channel stable] [--metadata-root <path>] [--json]";
|
|
85
|
+
const LOCAL_TOOLCHAIN_CURRENT_USAGE = "Usage: embed local toolchain current [--install-root <path>] [--json]";
|
|
86
|
+
const LOCAL_TOOLCHAIN_INSTALL_USAGE = "Usage: embed local toolchain install [--board taishanpi-1m-rk3566] [--channel stable] [--metadata-root <path>] [--source-url <tar.gz-url>|--source-release-root <path>] [--install-root <path>] [--force] [--json]";
|
|
87
|
+
const LOCAL_TOOLCHAIN_VALIDATE_USAGE = "Usage: embed local toolchain validate [--release-root <path>] [--json]";
|
|
88
|
+
const LOCAL_COMPILE_TAISHANPI_USAGE = "Usage: embed local compile taishanpi --source <main.c|main.cpp> --output <artifact> [--release-root <path>] [--account <account_id>] [--json]";
|
|
89
|
+
const LOCAL_BUILD_QT_SMOKE_USAGE = "Usage: embed local build qt-smoke --build-dir <dir> [--source <qt-smoke-dir>] [--release-root <path>] [--account <account_id>] [--json]";
|
|
77
90
|
const BOARD_REGISTRY_LIST_USAGE = "Usage: embed board registry list [--json]";
|
|
78
91
|
const BOARD_REGISTRY_SHOW_USAGE = "Usage: embed board registry show <template_id> [--json]";
|
|
79
92
|
const BOARD_METHODS_USAGE = "Usage: embed board methods <template_id> [--json]";
|
|
@@ -82,7 +95,7 @@ const BOARD_KNOWLEDGE_FILE_USAGE = "Usage: embed board knowledge file <template_
|
|
|
82
95
|
const MODEL_LIST_USAGE = "Usage: embed model list [--json]";
|
|
83
96
|
const MODEL_DEFAULT_USAGE = "Usage: embed model default [--json]";
|
|
84
97
|
const SERVICE_MODES_USAGE = "Usage: embed service modes [--json]";
|
|
85
|
-
const AGENT_RUN_USAGE = "Usage: embed agent run --prompt <request> [--account <account_id>] [--workspace <workspace_id>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--max-tool-calls
|
|
98
|
+
const AGENT_RUN_USAGE = "Usage: embed agent run --prompt <request> [--account <account_id>] [--workspace <workspace_id>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--max-tool-calls 6] [--host <ip>] [--ports 22,15301] [--artifact <local_file>|--artifact-id <artifact_id>|--artifact-task <task_id>] [--artifact-output <path>] [--remote-path <path>] [--run] [--approve] [--json]";
|
|
86
99
|
const TOOL_LIST_USAGE = "Usage: embed tool list [--json]";
|
|
87
100
|
const TOOL_CALL_USAGE = "Usage: embed tool call <capability_id> [--input-json '<json>'] [--approve] [--json]";
|
|
88
101
|
const BOARD_DEPLOY_TAISHANPI_USAGE = "Usage: embed deploy taishanpi --host <ip> --artifact <local_file> --approve [--user root] [--remote-path /userdata/embed-labs/apps/app] [--run] [--timeout 30] [--json]";
|
|
@@ -475,6 +488,75 @@ async function main(argv) {
|
|
|
475
488
|
BILLING_SNAPSHOT_SHOW_USAGE
|
|
476
489
|
].join("\n")), undefined, 2);
|
|
477
490
|
}
|
|
491
|
+
if (area === "image") {
|
|
492
|
+
if ((action === "boot-logo" && parsed.command[2] === "compose") || (action === "compose" && parsed.command[2] === "boot-logo")) {
|
|
493
|
+
const request = imageBootLogoComposeRequest(parsed, IMAGE_BOOT_LOGO_COMPOSE_USAGE);
|
|
494
|
+
if (typeof request === "string") {
|
|
495
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
496
|
+
}
|
|
497
|
+
return output(parsed, ok(await composeBootLogoPackage(request)), renderBootLogoComposeResult);
|
|
498
|
+
}
|
|
499
|
+
if ((action === "dtb" && parsed.command[2] === "compose") || (action === "compose" && parsed.command[2] === "dtb")) {
|
|
500
|
+
const request = imageBootLogoComposeRequest(parsed, IMAGE_DTB_COMPOSE_USAGE);
|
|
501
|
+
if (typeof request === "string") {
|
|
502
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
503
|
+
}
|
|
504
|
+
return output(parsed, ok(await composeBootLogoPackage(request)), renderBootLogoComposeResult);
|
|
505
|
+
}
|
|
506
|
+
return output(parsed, fail("invalid_args", [IMAGE_BOOT_LOGO_COMPOSE_USAGE, IMAGE_DTB_COMPOSE_USAGE].join("\n")), undefined, 2);
|
|
507
|
+
}
|
|
508
|
+
if (area === "local") {
|
|
509
|
+
if (action === "toolchain" && parsed.command[2] === "latest") {
|
|
510
|
+
const request = localToolchainLatestRequest(parsed);
|
|
511
|
+
if (typeof request === "string") {
|
|
512
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
513
|
+
}
|
|
514
|
+
return output(parsed, ok(await latestLocalToolchain(request)), renderLocalToolchainLatest);
|
|
515
|
+
}
|
|
516
|
+
if (action === "toolchain" && parsed.command[2] === "current") {
|
|
517
|
+
const request = localToolchainCurrentRequest(parsed);
|
|
518
|
+
if (typeof request === "string") {
|
|
519
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
520
|
+
}
|
|
521
|
+
return output(parsed, ok(await currentLocalToolchain(request.installRoot)), renderLocalToolchainCurrent);
|
|
522
|
+
}
|
|
523
|
+
if (action === "toolchain" && parsed.command[2] === "install") {
|
|
524
|
+
const request = localToolchainInstallRequest(parsed);
|
|
525
|
+
if (typeof request === "string") {
|
|
526
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
527
|
+
}
|
|
528
|
+
return output(parsed, ok(await installLocalToolchain(request)), renderLocalToolchainInstall);
|
|
529
|
+
}
|
|
530
|
+
if (action === "toolchain" && parsed.command[2] === "validate") {
|
|
531
|
+
const request = localToolchainValidateRequest(parsed);
|
|
532
|
+
if (typeof request === "string") {
|
|
533
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
534
|
+
}
|
|
535
|
+
return output(parsed, ok(await validateLocalToolchain(request.releaseRoot)), renderLocalToolchainValidation);
|
|
536
|
+
}
|
|
537
|
+
if (action === "compile" && parsed.command[2] === "taishanpi") {
|
|
538
|
+
const request = localCompileTaishanPiRequest(parsed, await authStatus());
|
|
539
|
+
if (typeof request === "string") {
|
|
540
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
541
|
+
}
|
|
542
|
+
return output(parsed, ok(await compileTaishanPiSingleFile(request)), renderLocalCompileResult);
|
|
543
|
+
}
|
|
544
|
+
if (action === "build" && parsed.command[2] === "qt-smoke") {
|
|
545
|
+
const request = localBuildQtSmokeRequest(parsed, await authStatus());
|
|
546
|
+
if (typeof request === "string") {
|
|
547
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
548
|
+
}
|
|
549
|
+
return output(parsed, ok(await buildTaishanPiQtSmoke(request)), renderLocalCompileResult);
|
|
550
|
+
}
|
|
551
|
+
return output(parsed, fail("invalid_args", [
|
|
552
|
+
LOCAL_TOOLCHAIN_LATEST_USAGE,
|
|
553
|
+
LOCAL_TOOLCHAIN_CURRENT_USAGE,
|
|
554
|
+
LOCAL_TOOLCHAIN_INSTALL_USAGE,
|
|
555
|
+
LOCAL_TOOLCHAIN_VALIDATE_USAGE,
|
|
556
|
+
LOCAL_COMPILE_TAISHANPI_USAGE,
|
|
557
|
+
LOCAL_BUILD_QT_SMOKE_USAGE
|
|
558
|
+
].join("\n")), undefined, 2);
|
|
559
|
+
}
|
|
478
560
|
if (area === "build") {
|
|
479
561
|
if (action === "template") {
|
|
480
562
|
const templateAction = parsed.command[2];
|
|
@@ -620,6 +702,44 @@ async function main(argv) {
|
|
|
620
702
|
}
|
|
621
703
|
return output(parsed, await cloudPost("/v1/build/image-generate", body), renderJob);
|
|
622
704
|
}
|
|
705
|
+
if (action === "image" && (parsed.command[2] === "boot-logo" || parsed.command[2] === "boot-logo-package")) {
|
|
706
|
+
const request = await buildImageBootLogoPackageRequest(parsed);
|
|
707
|
+
if (typeof request === "string") {
|
|
708
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
709
|
+
}
|
|
710
|
+
const created = await cloudPost("/v1/build/image/boot-logo-package", request.body);
|
|
711
|
+
if (!created.ok || !request.output_path) {
|
|
712
|
+
return output(parsed, created, renderJob, created.ok ? 0 : 2);
|
|
713
|
+
}
|
|
714
|
+
const packageArtifact = created.data.artifacts?.find((artifact) => artifact.kind === "patch" && artifact.name === "boot-logo-package.json");
|
|
715
|
+
if (!packageArtifact) {
|
|
716
|
+
return output(parsed, fail("artifact_not_found", "Boot-logo package task did not include boot-logo-package.json."), undefined, 2);
|
|
717
|
+
}
|
|
718
|
+
const downloaded = await cloudDownloadArtifact(packageArtifact.artifact_id, request.output_path);
|
|
719
|
+
if (!downloaded.ok) {
|
|
720
|
+
return output(parsed, downloaded, renderArtifactDownload, 2);
|
|
721
|
+
}
|
|
722
|
+
return output(parsed, ok({ task: created.data, downloaded_artifact: downloaded.data }), renderBootLogoPackageResult);
|
|
723
|
+
}
|
|
724
|
+
if (action === "image" && (parsed.command[2] === "dtb" || parsed.command[2] === "dtb-package")) {
|
|
725
|
+
const request = await buildImageDtbPackageRequest(parsed);
|
|
726
|
+
if (typeof request === "string") {
|
|
727
|
+
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
728
|
+
}
|
|
729
|
+
const created = await cloudPost("/v1/build/image/dtb-package", request.body);
|
|
730
|
+
if (!created.ok || !request.output_path) {
|
|
731
|
+
return output(parsed, created, renderJob, created.ok ? 0 : 2);
|
|
732
|
+
}
|
|
733
|
+
const packageArtifact = created.data.artifacts?.find((artifact) => artifact.kind === "patch" && artifact.name === "dtb-package.json");
|
|
734
|
+
if (!packageArtifact) {
|
|
735
|
+
return output(parsed, fail("artifact_not_found", "DTB package task did not include dtb-package.json."), undefined, 2);
|
|
736
|
+
}
|
|
737
|
+
const downloaded = await cloudDownloadArtifact(packageArtifact.artifact_id, request.output_path);
|
|
738
|
+
if (!downloaded.ok) {
|
|
739
|
+
return output(parsed, downloaded, renderArtifactDownload, 2);
|
|
740
|
+
}
|
|
741
|
+
return output(parsed, ok({ task: created.data, downloaded_artifact: downloaded.data }), renderDtbPackageResult);
|
|
742
|
+
}
|
|
623
743
|
return output(parsed, fail("invalid_args", [
|
|
624
744
|
BUILD_TEMPLATE_LIST_USAGE,
|
|
625
745
|
BUILD_TEMPLATE_SHOW_USAGE,
|
|
@@ -636,7 +756,9 @@ async function main(argv) {
|
|
|
636
756
|
BUILD_APPLICATION_STUB_USAGE,
|
|
637
757
|
BUILD_APPLICATION_GENERATE_USAGE,
|
|
638
758
|
BUILD_APPLICATION_COMPILE_USAGE,
|
|
639
|
-
BUILD_IMAGE_GENERATE_USAGE
|
|
759
|
+
BUILD_IMAGE_GENERATE_USAGE,
|
|
760
|
+
BUILD_IMAGE_BOOT_LOGO_USAGE,
|
|
761
|
+
BUILD_IMAGE_DTB_USAGE
|
|
640
762
|
].join("\n")), undefined, 2);
|
|
641
763
|
}
|
|
642
764
|
if (area === "project" && action === "create") {
|
|
@@ -1307,16 +1429,16 @@ async function pluginList(parsed) {
|
|
|
1307
1429
|
return remoteManifest;
|
|
1308
1430
|
}
|
|
1309
1431
|
const effectiveManifest = manifest?.data ?? remoteManifest?.data;
|
|
1310
|
-
const codexPackage = manifest?.data.packages?.find((item) => item.id === "codex-
|
|
1311
|
-
const opencodePackage = manifest?.data.packages?.find((item) => item.id === "opencode-
|
|
1312
|
-
const effectiveCodexPackage = effectiveManifest?.packages?.find((item) => item.id === "codex-
|
|
1313
|
-
const effectiveOpenCodePackage = effectiveManifest?.packages?.find((item) => item.id === "opencode-
|
|
1432
|
+
const codexPackage = manifest?.data.packages?.find((item) => item.id === "codex-embed-labs");
|
|
1433
|
+
const opencodePackage = manifest?.data.packages?.find((item) => item.id === "opencode-embed-labs");
|
|
1434
|
+
const effectiveCodexPackage = effectiveManifest?.packages?.find((item) => item.id === "codex-embed-labs") ?? codexPackage;
|
|
1435
|
+
const effectiveOpenCodePackage = effectiveManifest?.packages?.find((item) => item.id === "opencode-embed-labs") ?? opencodePackage;
|
|
1314
1436
|
const source = releaseDir || remoteManifest ? "release_dir" : "source_checkout";
|
|
1315
1437
|
return ok({
|
|
1316
1438
|
plugins: [
|
|
1317
1439
|
{
|
|
1318
1440
|
id: "codex",
|
|
1319
|
-
display_name: "Embed Labs
|
|
1441
|
+
display_name: "Embed Labs Codex plugin",
|
|
1320
1442
|
source,
|
|
1321
1443
|
version: effectiveCodexPackage?.version ?? effectiveManifest?.version ?? await localPluginVersion("codex"),
|
|
1322
1444
|
release_file: effectiveCodexPackage?.file,
|
|
@@ -1325,7 +1447,7 @@ async function pluginList(parsed) {
|
|
|
1325
1447
|
},
|
|
1326
1448
|
{
|
|
1327
1449
|
id: "opencode",
|
|
1328
|
-
display_name: "Embed Labs
|
|
1450
|
+
display_name: "Embed Labs OpenCode plugin",
|
|
1329
1451
|
source,
|
|
1330
1452
|
version: effectiveOpenCodePackage?.version ?? effectiveManifest?.version ?? await localPluginVersion("opencode"),
|
|
1331
1453
|
release_file: effectiveOpenCodePackage?.file,
|
|
@@ -1401,7 +1523,7 @@ async function installCodexPlugin(parsed, context) {
|
|
|
1401
1523
|
return source;
|
|
1402
1524
|
}
|
|
1403
1525
|
const targetRoot = codexPluginTargetRoot(parsed, context.installingAll);
|
|
1404
|
-
const targetPath = join(targetRoot, "
|
|
1526
|
+
const targetPath = join(targetRoot, "embed-labs");
|
|
1405
1527
|
if (await pathExists(targetPath) && !booleanFlag(parsed, "force")) {
|
|
1406
1528
|
return fail("plugin_already_installed", `Codex plugin already exists at ${targetPath}.`, {
|
|
1407
1529
|
remediation: "Pass --force to replace it, or pass --codex-target/--target to install into a different directory."
|
|
@@ -1410,12 +1532,17 @@ async function installCodexPlugin(parsed, context) {
|
|
|
1410
1532
|
await rm(targetPath, { recursive: true, force: true });
|
|
1411
1533
|
await mkdir(targetRoot, { recursive: true });
|
|
1412
1534
|
await cp(source.data.sourcePath, targetPath, { recursive: true });
|
|
1535
|
+
const mcpRegistration = await maybeRegisterCodexMcp(parsed, targetRoot, targetPath);
|
|
1413
1536
|
return ok({
|
|
1414
1537
|
id: "codex",
|
|
1415
1538
|
target_path: targetPath,
|
|
1416
1539
|
source: source.data.sourceLabel,
|
|
1417
1540
|
version: source.data.version,
|
|
1418
|
-
command_hint:
|
|
1541
|
+
command_hint: mcpRegistration.registered
|
|
1542
|
+
? "Codex MCP was registered. Start a new Codex session to reload tools."
|
|
1543
|
+
: mcpRegistration.hint,
|
|
1544
|
+
mcp_registered: mcpRegistration.registered,
|
|
1545
|
+
mcp_warning: mcpRegistration.warning
|
|
1419
1546
|
});
|
|
1420
1547
|
}
|
|
1421
1548
|
async function installOpenCodePlugin(parsed, context) {
|
|
@@ -1451,20 +1578,22 @@ async function installOpenCodePlugin(parsed, context) {
|
|
|
1451
1578
|
});
|
|
1452
1579
|
}
|
|
1453
1580
|
await ensureOpenCodeInstallPackageJson(targetRoot);
|
|
1454
|
-
await writeFile(wrapperPath, `export { default, DevelopmentBoardToolchainPlugin } from "
|
|
1581
|
+
await writeFile(wrapperPath, `export { default, DevelopmentBoardToolchainPlugin } from "embed-labs";\n`, "utf8");
|
|
1582
|
+
const duplicateWarning = await openCodeDuplicatePluginWarning(targetRoot);
|
|
1455
1583
|
return ok({
|
|
1456
1584
|
id: "opencode",
|
|
1457
1585
|
target_path: targetRoot,
|
|
1458
1586
|
source: source.data.sourceLabel,
|
|
1459
1587
|
version: source.data.version,
|
|
1460
|
-
command_hint: "Start OpenCode from the project containing this .opencode directory."
|
|
1588
|
+
command_hint: "Start OpenCode from the project containing this .opencode directory.",
|
|
1589
|
+
warning: duplicateWarning
|
|
1461
1590
|
});
|
|
1462
1591
|
}
|
|
1463
1592
|
async function resolveCodexPluginSource(context) {
|
|
1464
1593
|
if (context.releaseDir) {
|
|
1465
|
-
const item = context.manifest?.packages?.find((entry) => entry.id === "codex-
|
|
1594
|
+
const item = context.manifest?.packages?.find((entry) => entry.id === "codex-embed-labs");
|
|
1466
1595
|
if (!item?.file) {
|
|
1467
|
-
return fail("plugin_release_not_found", `Release manifest in ${context.releaseDir} does not include codex-
|
|
1596
|
+
return fail("plugin_release_not_found", `Release manifest in ${context.releaseDir} does not include codex-embed-labs.`);
|
|
1468
1597
|
}
|
|
1469
1598
|
const tarball = resolve(context.releaseDir, item.file);
|
|
1470
1599
|
const verified = await verifyReleasePackage(tarball, item);
|
|
@@ -1479,13 +1608,13 @@ async function resolveCodexPluginSource(context) {
|
|
|
1479
1608
|
details: { exit_code: tarResult.code, stderr_tail: tarResult.stderr.split("\n").slice(-20) }
|
|
1480
1609
|
});
|
|
1481
1610
|
}
|
|
1482
|
-
const sourcePath = join(extractDir, "codex_plugin", "plugins", "
|
|
1611
|
+
const sourcePath = join(extractDir, "codex_plugin", "plugins", "embed-labs");
|
|
1483
1612
|
if (!await pathExists(join(sourcePath, ".codex-plugin", "plugin.json"))) {
|
|
1484
|
-
return fail("plugin_release_invalid", `Codex plugin release ${tarball} did not contain plugins/
|
|
1613
|
+
return fail("plugin_release_invalid", `Codex plugin release ${tarball} did not contain plugins/embed-labs/.codex-plugin/plugin.json.`);
|
|
1485
1614
|
}
|
|
1486
1615
|
return ok({ sourcePath, sourceLabel: tarball, version: item.version ?? context.manifest?.version });
|
|
1487
1616
|
}
|
|
1488
|
-
const sourcePath = sourceCheckoutPath("platform_plugins", "codex_plugin", "plugins", "
|
|
1617
|
+
const sourcePath = sourceCheckoutPath("platform_plugins", "codex_plugin", "plugins", "embed-labs");
|
|
1489
1618
|
if (!await pathExists(join(sourcePath, ".codex-plugin", "plugin.json"))) {
|
|
1490
1619
|
return fail("plugin_source_not_found", "Could not find Codex plugin source in this checkout.", {
|
|
1491
1620
|
remediation: "Run from the Embed-Labs-Cloud repo root or pass --release-dir pointing to a plugin release directory."
|
|
@@ -1495,9 +1624,9 @@ async function resolveCodexPluginSource(context) {
|
|
|
1495
1624
|
}
|
|
1496
1625
|
async function resolveOpenCodePluginSource(context) {
|
|
1497
1626
|
if (context.releaseDir) {
|
|
1498
|
-
const item = context.manifest?.packages?.find((entry) => entry.id === "opencode-
|
|
1627
|
+
const item = context.manifest?.packages?.find((entry) => entry.id === "opencode-embed-labs");
|
|
1499
1628
|
if (!item?.file) {
|
|
1500
|
-
return fail("plugin_release_not_found", `Release manifest in ${context.releaseDir} does not include opencode-
|
|
1629
|
+
return fail("plugin_release_not_found", `Release manifest in ${context.releaseDir} does not include opencode-embed-labs.`);
|
|
1501
1630
|
}
|
|
1502
1631
|
const tarball = resolve(context.releaseDir, item.file);
|
|
1503
1632
|
const verified = await verifyReleasePackage(tarball, item);
|
|
@@ -1512,7 +1641,32 @@ async function resolveOpenCodePluginSource(context) {
|
|
|
1512
1641
|
remediation: "Run from the Embed-Labs-Cloud repo root or pass --release-dir pointing to a plugin release directory."
|
|
1513
1642
|
});
|
|
1514
1643
|
}
|
|
1515
|
-
|
|
1644
|
+
const packed = await runLocalProcess("npm", ["pack", packagePath, "--pack-destination", context.tempDir, "--json"]);
|
|
1645
|
+
if (packed.code !== 0) {
|
|
1646
|
+
return fail("opencode_plugin_pack_failed", "npm pack failed while preparing the OpenCode plugin source package.", {
|
|
1647
|
+
details: {
|
|
1648
|
+
exit_code: packed.code,
|
|
1649
|
+
stdout_tail: packed.stdout.split("\n").slice(-20),
|
|
1650
|
+
stderr_tail: packed.stderr.split("\n").slice(-20)
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
let tarballName = "";
|
|
1655
|
+
try {
|
|
1656
|
+
const parsed = JSON.parse(packed.stdout);
|
|
1657
|
+
tarballName = basename(parsed[0]?.filename || "");
|
|
1658
|
+
}
|
|
1659
|
+
catch {
|
|
1660
|
+
tarballName = "";
|
|
1661
|
+
}
|
|
1662
|
+
if (!tarballName) {
|
|
1663
|
+
return fail("opencode_plugin_pack_failed", "npm pack did not report an OpenCode plugin tarball filename.");
|
|
1664
|
+
}
|
|
1665
|
+
const tarballPath = join(context.tempDir, tarballName);
|
|
1666
|
+
if (!await pathExists(tarballPath)) {
|
|
1667
|
+
return fail("opencode_plugin_pack_failed", `npm pack reported ${tarballName}, but the tarball was not found.`);
|
|
1668
|
+
}
|
|
1669
|
+
return ok({ packagePath: tarballPath, sourceLabel: `${packagePath} -> ${tarballPath}`, version: await localPluginVersion("opencode") });
|
|
1516
1670
|
}
|
|
1517
1671
|
async function fetchRemotePluginManifest(parsed) {
|
|
1518
1672
|
const manifestUrl = `${pluginReleaseBaseUrl(parsed)}/manifest.json`;
|
|
@@ -1648,12 +1802,203 @@ function openCodePluginTargetRoot(parsed, installingAll) {
|
|
|
1648
1802
|
function defaultCodexPluginRoot() {
|
|
1649
1803
|
return join(process.env.CODEX_HOME?.trim() || join(homedir(), ".codex"), "plugins");
|
|
1650
1804
|
}
|
|
1805
|
+
async function maybeRegisterCodexMcp(parsed, targetRoot, targetPath) {
|
|
1806
|
+
const explicitTarget = Boolean(stringFlag(parsed, "target") || stringFlag(parsed, "codex-target"));
|
|
1807
|
+
if (explicitTarget && process.env.EMBED_CODEX_MCP_REGISTER !== "1") {
|
|
1808
|
+
return {
|
|
1809
|
+
registered: false,
|
|
1810
|
+
hint: `Installed into a custom target. Register manually with: codex mcp add embed-labs -- node ${join(targetPath, "scripts", "embed-labs-mcp-bridge.mjs")}`
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1813
|
+
const bridgePath = join(targetPath, "scripts", "embed-labs-mcp-bridge.mjs");
|
|
1814
|
+
if (!await pathExists(bridgePath)) {
|
|
1815
|
+
return {
|
|
1816
|
+
registered: false,
|
|
1817
|
+
hint: "Restart Codex or reload plugins after installing.",
|
|
1818
|
+
warning: `Codex MCP bridge was not found at ${bridgePath}.`
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
const codexBin = await resolveExecutableOnPath("codex");
|
|
1822
|
+
if (!codexBin) {
|
|
1823
|
+
return {
|
|
1824
|
+
registered: false,
|
|
1825
|
+
hint: `Codex CLI was not found on PATH. Register manually with: codex mcp add embed-labs -- node ${bridgePath}`
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
const embedCliBin = process.env.EMBED_CLI_BIN?.trim() || await resolveExecutableOnPath("embedlabs") || await resolveExecutableOnPath("embed") || "";
|
|
1829
|
+
const authFile = resolve(process.env.EMBED_AUTH_FILE?.trim() || DEFAULT_AUTH_FILE);
|
|
1830
|
+
const cloudUrl = pluginMcpCloudApiUrl(parsed);
|
|
1831
|
+
const existing = await runLocalProcess(codexBin, ["mcp", "get", "embed-labs", "--json"]);
|
|
1832
|
+
if (existing.code === 0 && codexMcpAlreadyRegistered(existing.stdout, bridgePath, cloudUrl, authFile, embedCliBin)) {
|
|
1833
|
+
const warning = await upsertCodexMcpRuntimeConfig(bridgePath);
|
|
1834
|
+
if (warning) {
|
|
1835
|
+
return { registered: true, warning };
|
|
1836
|
+
}
|
|
1837
|
+
return { registered: true };
|
|
1838
|
+
}
|
|
1839
|
+
await runLocalProcess(codexBin, ["mcp", "remove", "embed-labs"]);
|
|
1840
|
+
const args = [
|
|
1841
|
+
"mcp",
|
|
1842
|
+
"add",
|
|
1843
|
+
"embed-labs",
|
|
1844
|
+
"--env",
|
|
1845
|
+
`EMBED_CLOUD_API_URL=${cloudUrl}`,
|
|
1846
|
+
"--env",
|
|
1847
|
+
`EMBED_AUTH_FILE=${authFile}`
|
|
1848
|
+
];
|
|
1849
|
+
if (embedCliBin) {
|
|
1850
|
+
args.push("--env", `EMBED_CLI_BIN=${embedCliBin}`);
|
|
1851
|
+
}
|
|
1852
|
+
args.push("--", process.execPath, bridgePath);
|
|
1853
|
+
const addResult = await runLocalProcess(codexBin, args);
|
|
1854
|
+
if (addResult.code !== 0) {
|
|
1855
|
+
return {
|
|
1856
|
+
registered: false,
|
|
1857
|
+
hint: `Codex plugin installed. Register manually with: codex mcp add embed-labs -- ${process.execPath} ${bridgePath}`,
|
|
1858
|
+
warning: `codex mcp add failed: ${addResult.stderr.trim() || addResult.stdout.trim() || `exit ${addResult.code}`}`
|
|
1859
|
+
};
|
|
1860
|
+
}
|
|
1861
|
+
const warning = await upsertCodexMcpRuntimeConfig(bridgePath);
|
|
1862
|
+
return warning ? { registered: true, warning } : { registered: true };
|
|
1863
|
+
}
|
|
1864
|
+
function codexMcpAlreadyRegistered(stdout, bridgePath, cloudUrl, authFile, embedCliBin) {
|
|
1865
|
+
try {
|
|
1866
|
+
const parsed = JSON.parse(stdout);
|
|
1867
|
+
const transport = parsed.transport;
|
|
1868
|
+
if (transport?.type !== "stdio" || transport.command !== process.execPath)
|
|
1869
|
+
return false;
|
|
1870
|
+
if (!transport.args?.includes(bridgePath))
|
|
1871
|
+
return false;
|
|
1872
|
+
const env = transport.env || {};
|
|
1873
|
+
if (env.EMBED_CLOUD_API_URL !== cloudUrl)
|
|
1874
|
+
return false;
|
|
1875
|
+
if (env.EMBED_AUTH_FILE !== authFile)
|
|
1876
|
+
return false;
|
|
1877
|
+
if (embedCliBin && env.EMBED_CLI_BIN !== embedCliBin)
|
|
1878
|
+
return false;
|
|
1879
|
+
return true;
|
|
1880
|
+
}
|
|
1881
|
+
catch {
|
|
1882
|
+
return false;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
async function upsertCodexMcpRuntimeConfig(bridgePath) {
|
|
1886
|
+
const configPath = join(process.env.CODEX_HOME?.trim() || join(homedir(), ".codex"), "config.toml");
|
|
1887
|
+
try {
|
|
1888
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
1889
|
+
let text = "";
|
|
1890
|
+
try {
|
|
1891
|
+
text = await readFile(configPath, "utf8");
|
|
1892
|
+
}
|
|
1893
|
+
catch {
|
|
1894
|
+
text = "";
|
|
1895
|
+
}
|
|
1896
|
+
const updated = upsertTomlTableKeys(text, "mcp_servers.embed-labs", {
|
|
1897
|
+
command: tomlString(process.execPath),
|
|
1898
|
+
args: `[${tomlString(bridgePath)}]`,
|
|
1899
|
+
startup_timeout_sec: "120"
|
|
1900
|
+
});
|
|
1901
|
+
if (updated !== text) {
|
|
1902
|
+
await writeFile(configPath, updated, "utf8");
|
|
1903
|
+
}
|
|
1904
|
+
return undefined;
|
|
1905
|
+
}
|
|
1906
|
+
catch (error) {
|
|
1907
|
+
return `Codex MCP was registered, but ${configPath} could not be updated with startup_timeout_sec: ${error instanceof Error ? error.message : String(error)}`;
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
function upsertTomlTableKeys(text, tableName, values) {
|
|
1911
|
+
const normalized = text.endsWith("\n") || text.length === 0 ? text : `${text}\n`;
|
|
1912
|
+
const header = `[${tableName}]`;
|
|
1913
|
+
const tablePattern = new RegExp(`(^|\\n)(\\[${escapeRegExp(tableName)}\\]\\n)([\\s\\S]*?)(?=\\n\\[|$)`);
|
|
1914
|
+
const match = tablePattern.exec(normalized);
|
|
1915
|
+
const bodyWithValues = (body) => {
|
|
1916
|
+
let updated = body;
|
|
1917
|
+
for (const [key, value] of Object.entries(values)) {
|
|
1918
|
+
const keyPattern = new RegExp(`^${escapeRegExp(key)}\\s*=.*$`, "m");
|
|
1919
|
+
if (keyPattern.test(updated)) {
|
|
1920
|
+
updated = updated.replace(keyPattern, `${key} = ${value}`);
|
|
1921
|
+
}
|
|
1922
|
+
else {
|
|
1923
|
+
updated = `${updated.replace(/\s*$/, "\n")}${key} = ${value}\n`;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
return updated;
|
|
1927
|
+
};
|
|
1928
|
+
if (!match) {
|
|
1929
|
+
const prefix = normalized.length > 0 && !normalized.endsWith("\n\n") ? `${normalized}\n` : normalized;
|
|
1930
|
+
return `${prefix}${header}\n${bodyWithValues("")}`;
|
|
1931
|
+
}
|
|
1932
|
+
return `${normalized.slice(0, match.index)}${match[1]}${match[2]}${bodyWithValues(match[3])}${normalized.slice(match.index + match[0].length)}`;
|
|
1933
|
+
}
|
|
1934
|
+
function tomlString(value) {
|
|
1935
|
+
return JSON.stringify(value);
|
|
1936
|
+
}
|
|
1937
|
+
function escapeRegExp(value) {
|
|
1938
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1939
|
+
}
|
|
1940
|
+
function pluginMcpCloudApiUrl(parsed) {
|
|
1941
|
+
const explicit = process.env.EMBED_CLOUD_API_URL?.trim();
|
|
1942
|
+
if (explicit)
|
|
1943
|
+
return explicit.replace(/\/+$/, "");
|
|
1944
|
+
const releaseUrl = stringFlag(parsed, "release-url") || DEFAULT_PLUGIN_RELEASE_URL;
|
|
1945
|
+
try {
|
|
1946
|
+
return new URL(releaseUrl).origin;
|
|
1947
|
+
}
|
|
1948
|
+
catch {
|
|
1949
|
+
return DEFAULT_CLOUD_API_URL.replace(/\/+$/, "");
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
async function resolveExecutableOnPath(name) {
|
|
1953
|
+
if (name.includes("/")) {
|
|
1954
|
+
try {
|
|
1955
|
+
await access(name, constants.X_OK);
|
|
1956
|
+
return name;
|
|
1957
|
+
}
|
|
1958
|
+
catch {
|
|
1959
|
+
return undefined;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
const pathEntries = (process.env.PATH || "").split(delimiter).filter(Boolean);
|
|
1963
|
+
for (const entry of pathEntries) {
|
|
1964
|
+
const candidate = join(entry, name);
|
|
1965
|
+
try {
|
|
1966
|
+
await access(candidate, constants.X_OK);
|
|
1967
|
+
return candidate;
|
|
1968
|
+
}
|
|
1969
|
+
catch {
|
|
1970
|
+
// Keep searching PATH.
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
return undefined;
|
|
1974
|
+
}
|
|
1651
1975
|
function defaultOpenCodeRoot() {
|
|
1652
1976
|
return join(process.cwd(), ".opencode");
|
|
1653
1977
|
}
|
|
1978
|
+
async function openCodeDuplicatePluginWarning(targetRoot) {
|
|
1979
|
+
const globalRoot = join(homedir(), ".config", "opencode");
|
|
1980
|
+
if (resolve(targetRoot) === resolve(globalRoot))
|
|
1981
|
+
return undefined;
|
|
1982
|
+
const configPath = join(globalRoot, "opencode.json");
|
|
1983
|
+
try {
|
|
1984
|
+
const parsed = JSON.parse(await readFile(configPath, "utf8"));
|
|
1985
|
+
const configuredPlugins = Array.isArray(parsed.plugin)
|
|
1986
|
+
? parsed.plugin
|
|
1987
|
+
: Array.isArray(parsed.plugins)
|
|
1988
|
+
? parsed.plugins
|
|
1989
|
+
: [];
|
|
1990
|
+
if (configuredPlugins.some((item) => item === "embed-labs")) {
|
|
1991
|
+
return "Global OpenCode config already enables embed-labs; OpenCode may load both the global plugin and this project .opencode plugin. Disable one entry if duplicate DBT tools appear.";
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
catch {
|
|
1995
|
+
return undefined;
|
|
1996
|
+
}
|
|
1997
|
+
return undefined;
|
|
1998
|
+
}
|
|
1654
1999
|
async function localPluginVersion(kind) {
|
|
1655
2000
|
const filePath = kind === "codex"
|
|
1656
|
-
? sourceCheckoutPath("platform_plugins", "codex_plugin", "plugins", "
|
|
2001
|
+
? sourceCheckoutPath("platform_plugins", "codex_plugin", "plugins", "embed-labs", ".codex-plugin", "plugin.json")
|
|
1657
2002
|
: sourceCheckoutPath("platform_plugins", "opencode_plugin", "package.json");
|
|
1658
2003
|
try {
|
|
1659
2004
|
const parsed = JSON.parse(await readFile(filePath, "utf8"));
|
|
@@ -1664,7 +2009,7 @@ async function localPluginVersion(kind) {
|
|
|
1664
2009
|
}
|
|
1665
2010
|
}
|
|
1666
2011
|
async function localPluginSourcesAvailable() {
|
|
1667
|
-
return await pathExists(sourceCheckoutPath("platform_plugins", "codex_plugin", "plugins", "
|
|
2012
|
+
return await pathExists(sourceCheckoutPath("platform_plugins", "codex_plugin", "plugins", "embed-labs", ".codex-plugin", "plugin.json"))
|
|
1668
2013
|
&& await pathExists(sourceCheckoutPath("platform_plugins", "opencode_plugin", "package.json"));
|
|
1669
2014
|
}
|
|
1670
2015
|
function sourceCheckoutPath(...segments) {
|
|
@@ -2104,6 +2449,36 @@ function agentRunToolInputs(parsed) {
|
|
|
2104
2449
|
ports: ports.values.length > 0 ? ports.values : [22, 15301],
|
|
2105
2450
|
timeout_ms: timeout.value !== undefined ? timeout.value * 1000 : undefined
|
|
2106
2451
|
});
|
|
2452
|
+
inputs["wifi.scan"] = compactBody({
|
|
2453
|
+
host: host.value,
|
|
2454
|
+
user: user.value,
|
|
2455
|
+
timeout_seconds: timeout.value
|
|
2456
|
+
});
|
|
2457
|
+
inputs["bluetooth.scan"] = compactBody({
|
|
2458
|
+
host: host.value,
|
|
2459
|
+
user: user.value,
|
|
2460
|
+
timeout_seconds: timeout.value
|
|
2461
|
+
});
|
|
2462
|
+
inputs["chip.cpu.frequency"] = compactBody({
|
|
2463
|
+
host: host.value,
|
|
2464
|
+
user: user.value,
|
|
2465
|
+
timeout_seconds: timeout.value
|
|
2466
|
+
});
|
|
2467
|
+
inputs["chip.temperature"] = compactBody({
|
|
2468
|
+
host: host.value,
|
|
2469
|
+
user: user.value,
|
|
2470
|
+
timeout_seconds: timeout.value
|
|
2471
|
+
});
|
|
2472
|
+
inputs["qml.runtime.status"] = compactBody({
|
|
2473
|
+
host: host.value,
|
|
2474
|
+
user: user.value,
|
|
2475
|
+
timeout_seconds: timeout.value
|
|
2476
|
+
});
|
|
2477
|
+
inputs["qml.runtime.start"] = compactBody({
|
|
2478
|
+
host: host.value,
|
|
2479
|
+
user: user.value,
|
|
2480
|
+
timeout_seconds: timeout.value
|
|
2481
|
+
});
|
|
2107
2482
|
}
|
|
2108
2483
|
if (artifact.value || remotePath.value || user.value || booleanFlag(parsed, "run")) {
|
|
2109
2484
|
inputs["taishanpi.deploy"] = compactBody({
|
|
@@ -2784,6 +3159,231 @@ function buildImageGenerateBody(parsed) {
|
|
|
2784
3159
|
worker_pool: workerPool.value
|
|
2785
3160
|
});
|
|
2786
3161
|
}
|
|
3162
|
+
async function buildImageBootLogoPackageRequest(parsed) {
|
|
3163
|
+
const unknownFlag = firstUnknownFlag(parsed, [
|
|
3164
|
+
"json",
|
|
3165
|
+
"account",
|
|
3166
|
+
"project",
|
|
3167
|
+
"project-id",
|
|
3168
|
+
"board",
|
|
3169
|
+
"board-id",
|
|
3170
|
+
"variant",
|
|
3171
|
+
"variant-id",
|
|
3172
|
+
"logo",
|
|
3173
|
+
"logo-path",
|
|
3174
|
+
"kernel-logo",
|
|
3175
|
+
"kernel-logo-path",
|
|
3176
|
+
"rotate",
|
|
3177
|
+
"scale",
|
|
3178
|
+
"output"
|
|
3179
|
+
]);
|
|
3180
|
+
if (unknownFlag) {
|
|
3181
|
+
return `Unknown flag --${unknownFlag}. ${BUILD_IMAGE_BOOT_LOGO_USAGE}`;
|
|
3182
|
+
}
|
|
3183
|
+
const extra = parsed.command.slice(3);
|
|
3184
|
+
if (extra.length > 0) {
|
|
3185
|
+
return `Unexpected argument: ${extra[0]}. ${BUILD_IMAGE_BOOT_LOGO_USAGE}`;
|
|
3186
|
+
}
|
|
3187
|
+
const logo = optionalTrimmedStringAliasFlag(parsed, ["logo", "logo-path"], "logo or logo-path");
|
|
3188
|
+
if (logo.error) {
|
|
3189
|
+
return logo.error;
|
|
3190
|
+
}
|
|
3191
|
+
if (!logo.value) {
|
|
3192
|
+
return BUILD_IMAGE_BOOT_LOGO_USAGE;
|
|
3193
|
+
}
|
|
3194
|
+
const logoPath = resolve(logo.value);
|
|
3195
|
+
const logoRead = await readLocalFileForUpload(logoPath, "logo");
|
|
3196
|
+
if (typeof logoRead === "string") {
|
|
3197
|
+
return logoRead;
|
|
3198
|
+
}
|
|
3199
|
+
const kernelLogo = optionalTrimmedStringAliasFlag(parsed, ["kernel-logo", "kernel-logo-path"], "kernel-logo or kernel-logo-path");
|
|
3200
|
+
if (kernelLogo.error) {
|
|
3201
|
+
return kernelLogo.error;
|
|
3202
|
+
}
|
|
3203
|
+
let kernelLogoRead;
|
|
3204
|
+
if (kernelLogo.value) {
|
|
3205
|
+
const kernelLogoPath = resolve(kernelLogo.value);
|
|
3206
|
+
const read = await readLocalFileForUpload(kernelLogoPath, "kernel-logo");
|
|
3207
|
+
if (typeof read === "string") {
|
|
3208
|
+
return read;
|
|
3209
|
+
}
|
|
3210
|
+
kernelLogoRead = read;
|
|
3211
|
+
}
|
|
3212
|
+
const account = optionalTrimmedStringFlag(parsed, "account");
|
|
3213
|
+
if (account.error) {
|
|
3214
|
+
return account.error;
|
|
3215
|
+
}
|
|
3216
|
+
const project = optionalTrimmedStringAliasFlag(parsed, ["project", "project-id"], "project or project-id");
|
|
3217
|
+
if (project.error) {
|
|
3218
|
+
return project.error;
|
|
3219
|
+
}
|
|
3220
|
+
const board = optionalTrimmedStringAliasFlag(parsed, ["board", "board-id"], "board or board-id");
|
|
3221
|
+
if (board.error) {
|
|
3222
|
+
return board.error;
|
|
3223
|
+
}
|
|
3224
|
+
const variant = optionalTrimmedStringAliasFlag(parsed, ["variant", "variant-id"], "variant or variant-id");
|
|
3225
|
+
if (variant.error) {
|
|
3226
|
+
return variant.error;
|
|
3227
|
+
}
|
|
3228
|
+
const rotate = optionalTrimmedStringFlag(parsed, "rotate");
|
|
3229
|
+
if (rotate.error) {
|
|
3230
|
+
return rotate.error;
|
|
3231
|
+
}
|
|
3232
|
+
const scale = optionalTrimmedStringFlag(parsed, "scale");
|
|
3233
|
+
if (scale.error) {
|
|
3234
|
+
return scale.error;
|
|
3235
|
+
}
|
|
3236
|
+
const outputPath = optionalTrimmedStringFlag(parsed, "output");
|
|
3237
|
+
if (outputPath.error) {
|
|
3238
|
+
return outputPath.error;
|
|
3239
|
+
}
|
|
3240
|
+
const body = {
|
|
3241
|
+
account_id: account.value,
|
|
3242
|
+
project_id: project.value,
|
|
3243
|
+
board_id: board.value ?? "taishanpi",
|
|
3244
|
+
variant_id: variant.value,
|
|
3245
|
+
logo_name: basename(logoRead.path),
|
|
3246
|
+
logo_content_base64: logoRead.bytes.toString("base64"),
|
|
3247
|
+
logo_sha256: logoRead.sha256,
|
|
3248
|
+
kernel_logo_name: kernelLogoRead ? basename(kernelLogoRead.path) : undefined,
|
|
3249
|
+
kernel_logo_content_base64: kernelLogoRead?.bytes.toString("base64"),
|
|
3250
|
+
kernel_logo_sha256: kernelLogoRead?.sha256,
|
|
3251
|
+
rotate: rotate.value,
|
|
3252
|
+
scale: scale.value
|
|
3253
|
+
};
|
|
3254
|
+
return {
|
|
3255
|
+
body,
|
|
3256
|
+
output_path: outputPath.value ? resolve(outputPath.value) : undefined
|
|
3257
|
+
};
|
|
3258
|
+
}
|
|
3259
|
+
async function buildImageDtbPackageRequest(parsed) {
|
|
3260
|
+
const unknownFlag = firstUnknownFlag(parsed, [
|
|
3261
|
+
"json",
|
|
3262
|
+
"account",
|
|
3263
|
+
"project",
|
|
3264
|
+
"project-id",
|
|
3265
|
+
"board",
|
|
3266
|
+
"board-id",
|
|
3267
|
+
"variant",
|
|
3268
|
+
"variant-id",
|
|
3269
|
+
"dtb",
|
|
3270
|
+
"dtb-path",
|
|
3271
|
+
"dts",
|
|
3272
|
+
"dts-path",
|
|
3273
|
+
"input-format",
|
|
3274
|
+
"output"
|
|
3275
|
+
]);
|
|
3276
|
+
if (unknownFlag) {
|
|
3277
|
+
return `Unknown flag --${unknownFlag}. ${BUILD_IMAGE_DTB_USAGE}`;
|
|
3278
|
+
}
|
|
3279
|
+
const extra = parsed.command.slice(3);
|
|
3280
|
+
if (extra.length > 0) {
|
|
3281
|
+
return `Unexpected argument: ${extra[0]}. ${BUILD_IMAGE_DTB_USAGE}`;
|
|
3282
|
+
}
|
|
3283
|
+
const dtb = optionalTrimmedStringAliasFlag(parsed, ["dtb", "dtb-path", "dts", "dts-path"], "dtb or dts path");
|
|
3284
|
+
if (dtb.error) {
|
|
3285
|
+
return dtb.error;
|
|
3286
|
+
}
|
|
3287
|
+
if (!dtb.value) {
|
|
3288
|
+
return BUILD_IMAGE_DTB_USAGE;
|
|
3289
|
+
}
|
|
3290
|
+
const dtbPath = resolve(dtb.value);
|
|
3291
|
+
const dtbRead = await readLocalFileForUpload(dtbPath, "dtb");
|
|
3292
|
+
if (typeof dtbRead === "string") {
|
|
3293
|
+
return dtbRead;
|
|
3294
|
+
}
|
|
3295
|
+
const account = optionalTrimmedStringFlag(parsed, "account");
|
|
3296
|
+
if (account.error) {
|
|
3297
|
+
return account.error;
|
|
3298
|
+
}
|
|
3299
|
+
const project = optionalTrimmedStringAliasFlag(parsed, ["project", "project-id"], "project or project-id");
|
|
3300
|
+
if (project.error) {
|
|
3301
|
+
return project.error;
|
|
3302
|
+
}
|
|
3303
|
+
const board = optionalTrimmedStringAliasFlag(parsed, ["board", "board-id"], "board or board-id");
|
|
3304
|
+
if (board.error) {
|
|
3305
|
+
return board.error;
|
|
3306
|
+
}
|
|
3307
|
+
const variant = optionalTrimmedStringAliasFlag(parsed, ["variant", "variant-id"], "variant or variant-id");
|
|
3308
|
+
if (variant.error) {
|
|
3309
|
+
return variant.error;
|
|
3310
|
+
}
|
|
3311
|
+
const inputFormat = optionalTrimmedStringFlag(parsed, "input-format");
|
|
3312
|
+
if (inputFormat.error) {
|
|
3313
|
+
return inputFormat.error;
|
|
3314
|
+
}
|
|
3315
|
+
const outputPath = optionalTrimmedStringFlag(parsed, "output");
|
|
3316
|
+
if (outputPath.error) {
|
|
3317
|
+
return outputPath.error;
|
|
3318
|
+
}
|
|
3319
|
+
const body = {
|
|
3320
|
+
account_id: account.value,
|
|
3321
|
+
project_id: project.value,
|
|
3322
|
+
board_id: board.value ?? "taishanpi",
|
|
3323
|
+
variant_id: variant.value,
|
|
3324
|
+
dtb_name: basename(dtbRead.path),
|
|
3325
|
+
dtb_content_base64: dtbRead.bytes.toString("base64"),
|
|
3326
|
+
dtb_sha256: dtbRead.sha256,
|
|
3327
|
+
input_format: inputFormat.value
|
|
3328
|
+
};
|
|
3329
|
+
return {
|
|
3330
|
+
body,
|
|
3331
|
+
output_path: outputPath.value ? resolve(outputPath.value) : undefined
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
function imageBootLogoComposeRequest(parsed, usage) {
|
|
3335
|
+
const unknownFlag = firstUnknownFlag(parsed, [
|
|
3336
|
+
"json",
|
|
3337
|
+
"package",
|
|
3338
|
+
"package-path",
|
|
3339
|
+
"base-image",
|
|
3340
|
+
"base-image-path",
|
|
3341
|
+
"output",
|
|
3342
|
+
"output-image",
|
|
3343
|
+
"manifest",
|
|
3344
|
+
"manifest-path",
|
|
3345
|
+
"force"
|
|
3346
|
+
]);
|
|
3347
|
+
if (unknownFlag) {
|
|
3348
|
+
return `Unknown flag --${unknownFlag}. ${usage}`;
|
|
3349
|
+
}
|
|
3350
|
+
const extra = parsed.command.slice(3);
|
|
3351
|
+
if (extra.length > 0) {
|
|
3352
|
+
return `Unexpected argument: ${extra[0]}. ${usage}`;
|
|
3353
|
+
}
|
|
3354
|
+
const packagePath = optionalTrimmedStringAliasFlag(parsed, ["package", "package-path"], "package or package-path");
|
|
3355
|
+
if (packagePath.error) {
|
|
3356
|
+
return packagePath.error;
|
|
3357
|
+
}
|
|
3358
|
+
if (!packagePath.value) {
|
|
3359
|
+
return usage;
|
|
3360
|
+
}
|
|
3361
|
+
const baseImage = optionalTrimmedStringAliasFlag(parsed, ["base-image", "base-image-path"], "base-image or base-image-path");
|
|
3362
|
+
if (baseImage.error) {
|
|
3363
|
+
return baseImage.error;
|
|
3364
|
+
}
|
|
3365
|
+
if (!baseImage.value) {
|
|
3366
|
+
return usage;
|
|
3367
|
+
}
|
|
3368
|
+
const outputImage = optionalTrimmedStringAliasFlag(parsed, ["output", "output-image"], "output or output-image");
|
|
3369
|
+
if (outputImage.error) {
|
|
3370
|
+
return outputImage.error;
|
|
3371
|
+
}
|
|
3372
|
+
if (!outputImage.value) {
|
|
3373
|
+
return usage;
|
|
3374
|
+
}
|
|
3375
|
+
const manifest = optionalTrimmedStringAliasFlag(parsed, ["manifest", "manifest-path"], "manifest or manifest-path");
|
|
3376
|
+
if (manifest.error) {
|
|
3377
|
+
return manifest.error;
|
|
3378
|
+
}
|
|
3379
|
+
return {
|
|
3380
|
+
packagePath: resolve(packagePath.value),
|
|
3381
|
+
baseImagePath: resolve(baseImage.value),
|
|
3382
|
+
outputImagePath: resolve(outputImage.value),
|
|
3383
|
+
manifestPath: manifest.value ? resolve(manifest.value) : undefined,
|
|
3384
|
+
force: booleanFlag(parsed, "force")
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
2787
3387
|
function boardKnowledgeFileRequest(parsed) {
|
|
2788
3388
|
const unknownFlag = firstUnknownFlag(parsed, ["json", "source", "path", "output"]);
|
|
2789
3389
|
if (unknownFlag) {
|
|
@@ -3451,6 +4051,181 @@ function billingSnapshotListRequest(parsed) {
|
|
|
3451
4051
|
}
|
|
3452
4052
|
return { path: `/v1/accounts/${encodeURIComponent(accountResult.value)}/billing/snapshots` };
|
|
3453
4053
|
}
|
|
4054
|
+
function localToolchainLatestRequest(parsed) {
|
|
4055
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "board", "board-id", "channel", "metadata-root"]);
|
|
4056
|
+
if (unknownFlag) {
|
|
4057
|
+
return `Unknown flag --${unknownFlag}. ${LOCAL_TOOLCHAIN_LATEST_USAGE}`;
|
|
4058
|
+
}
|
|
4059
|
+
const extra = parsed.command.slice(3);
|
|
4060
|
+
if (extra.length > 0) {
|
|
4061
|
+
return `Unexpected argument: ${extra[0]}. ${LOCAL_TOOLCHAIN_LATEST_USAGE}`;
|
|
4062
|
+
}
|
|
4063
|
+
const board = optionalTrimmedStringAliasFlag(parsed, ["board", "board-id"], "board or board-id");
|
|
4064
|
+
if (board.error)
|
|
4065
|
+
return board.error;
|
|
4066
|
+
const channel = optionalTrimmedStringFlag(parsed, "channel");
|
|
4067
|
+
if (channel.error)
|
|
4068
|
+
return channel.error;
|
|
4069
|
+
const metadataRoot = optionalTrimmedStringFlag(parsed, "metadata-root");
|
|
4070
|
+
if (metadataRoot.error)
|
|
4071
|
+
return metadataRoot.error;
|
|
4072
|
+
return { boardId: board.value, channel: channel.value, metadataRoot: metadataRoot.value };
|
|
4073
|
+
}
|
|
4074
|
+
function localToolchainCurrentRequest(parsed) {
|
|
4075
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "install-root"]);
|
|
4076
|
+
if (unknownFlag) {
|
|
4077
|
+
return `Unknown flag --${unknownFlag}. ${LOCAL_TOOLCHAIN_CURRENT_USAGE}`;
|
|
4078
|
+
}
|
|
4079
|
+
const extra = parsed.command.slice(3);
|
|
4080
|
+
if (extra.length > 0) {
|
|
4081
|
+
return `Unexpected argument: ${extra[0]}. ${LOCAL_TOOLCHAIN_CURRENT_USAGE}`;
|
|
4082
|
+
}
|
|
4083
|
+
const installRoot = optionalTrimmedStringFlag(parsed, "install-root");
|
|
4084
|
+
if (installRoot.error)
|
|
4085
|
+
return installRoot.error;
|
|
4086
|
+
return { installRoot: installRoot.value };
|
|
4087
|
+
}
|
|
4088
|
+
function localToolchainInstallRequest(parsed) {
|
|
4089
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "board", "board-id", "channel", "metadata-root", "source-url", "source-release-root", "install-root", "force"]);
|
|
4090
|
+
if (unknownFlag) {
|
|
4091
|
+
return `Unknown flag --${unknownFlag}. ${LOCAL_TOOLCHAIN_INSTALL_USAGE}`;
|
|
4092
|
+
}
|
|
4093
|
+
const extra = parsed.command.slice(3);
|
|
4094
|
+
if (extra.length > 0) {
|
|
4095
|
+
return `Unexpected argument: ${extra[0]}. ${LOCAL_TOOLCHAIN_INSTALL_USAGE}`;
|
|
4096
|
+
}
|
|
4097
|
+
const board = optionalTrimmedStringAliasFlag(parsed, ["board", "board-id"], "board or board-id");
|
|
4098
|
+
if (board.error)
|
|
4099
|
+
return board.error;
|
|
4100
|
+
const channel = optionalTrimmedStringFlag(parsed, "channel");
|
|
4101
|
+
if (channel.error)
|
|
4102
|
+
return channel.error;
|
|
4103
|
+
const metadataRoot = optionalTrimmedStringFlag(parsed, "metadata-root");
|
|
4104
|
+
if (metadataRoot.error)
|
|
4105
|
+
return metadataRoot.error;
|
|
4106
|
+
const sourceUrl = optionalTrimmedStringFlag(parsed, "source-url");
|
|
4107
|
+
if (sourceUrl.error)
|
|
4108
|
+
return sourceUrl.error;
|
|
4109
|
+
const sourceReleaseRoot = optionalTrimmedStringFlag(parsed, "source-release-root");
|
|
4110
|
+
if (sourceReleaseRoot.error)
|
|
4111
|
+
return sourceReleaseRoot.error;
|
|
4112
|
+
if (sourceUrl.value && sourceReleaseRoot.value) {
|
|
4113
|
+
return "Use only one of --source-url or --source-release-root.";
|
|
4114
|
+
}
|
|
4115
|
+
const installRoot = optionalTrimmedStringFlag(parsed, "install-root");
|
|
4116
|
+
if (installRoot.error)
|
|
4117
|
+
return installRoot.error;
|
|
4118
|
+
return {
|
|
4119
|
+
boardId: board.value,
|
|
4120
|
+
channel: channel.value,
|
|
4121
|
+
metadataRoot: metadataRoot.value,
|
|
4122
|
+
sourceUrl: sourceUrl.value,
|
|
4123
|
+
sourceReleaseRoot: sourceReleaseRoot.value,
|
|
4124
|
+
installRoot: installRoot.value,
|
|
4125
|
+
force: booleanFlag(parsed, "force")
|
|
4126
|
+
};
|
|
4127
|
+
}
|
|
4128
|
+
function localToolchainValidateRequest(parsed) {
|
|
4129
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "release-root"]);
|
|
4130
|
+
if (unknownFlag) {
|
|
4131
|
+
return `Unknown flag --${unknownFlag}. ${LOCAL_TOOLCHAIN_VALIDATE_USAGE}`;
|
|
4132
|
+
}
|
|
4133
|
+
const extra = parsed.command.slice(3);
|
|
4134
|
+
if (extra.length > 0) {
|
|
4135
|
+
return `Unexpected argument: ${extra[0]}. ${LOCAL_TOOLCHAIN_VALIDATE_USAGE}`;
|
|
4136
|
+
}
|
|
4137
|
+
const releaseRoot = optionalTrimmedStringFlag(parsed, "release-root");
|
|
4138
|
+
if (releaseRoot.error) {
|
|
4139
|
+
return releaseRoot.error;
|
|
4140
|
+
}
|
|
4141
|
+
return { releaseRoot: releaseRoot.value };
|
|
4142
|
+
}
|
|
4143
|
+
function localCompileTaishanPiRequest(parsed, auth) {
|
|
4144
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "source", "output", "release-root", "account", "account-id"]);
|
|
4145
|
+
if (unknownFlag) {
|
|
4146
|
+
return `Unknown flag --${unknownFlag}. ${LOCAL_COMPILE_TAISHANPI_USAGE}`;
|
|
4147
|
+
}
|
|
4148
|
+
const extra = parsed.command.slice(3);
|
|
4149
|
+
if (extra.length > 0) {
|
|
4150
|
+
return `Unexpected argument: ${extra[0]}. ${LOCAL_COMPILE_TAISHANPI_USAGE}`;
|
|
4151
|
+
}
|
|
4152
|
+
const source = optionalTrimmedStringFlag(parsed, "source");
|
|
4153
|
+
if (source.error) {
|
|
4154
|
+
return source.error;
|
|
4155
|
+
}
|
|
4156
|
+
const outputPath = optionalTrimmedStringFlag(parsed, "output");
|
|
4157
|
+
if (outputPath.error) {
|
|
4158
|
+
return outputPath.error;
|
|
4159
|
+
}
|
|
4160
|
+
if (!source.value || !outputPath.value) {
|
|
4161
|
+
return LOCAL_COMPILE_TAISHANPI_USAGE;
|
|
4162
|
+
}
|
|
4163
|
+
const releaseRoot = optionalTrimmedStringFlag(parsed, "release-root");
|
|
4164
|
+
if (releaseRoot.error) {
|
|
4165
|
+
return releaseRoot.error;
|
|
4166
|
+
}
|
|
4167
|
+
const account = optionalTrimmedStringAliasFlag(parsed, ["account", "account-id"], "account or account-id");
|
|
4168
|
+
if (account.error) {
|
|
4169
|
+
return account.error;
|
|
4170
|
+
}
|
|
4171
|
+
return {
|
|
4172
|
+
boardId: "taishanpi-1m-rk3566",
|
|
4173
|
+
sourcePath: source.value,
|
|
4174
|
+
outputPath: outputPath.value,
|
|
4175
|
+
releaseRoot: releaseRoot.value,
|
|
4176
|
+
accountId: account.value,
|
|
4177
|
+
auth: localToolchainAuthContext(auth, account.value)
|
|
4178
|
+
};
|
|
4179
|
+
}
|
|
4180
|
+
function localBuildQtSmokeRequest(parsed, auth) {
|
|
4181
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "source", "build-dir", "release-root", "target-name", "account", "account-id"]);
|
|
4182
|
+
if (unknownFlag) {
|
|
4183
|
+
return `Unknown flag --${unknownFlag}. ${LOCAL_BUILD_QT_SMOKE_USAGE}`;
|
|
4184
|
+
}
|
|
4185
|
+
const extra = parsed.command.slice(3);
|
|
4186
|
+
if (extra.length > 0) {
|
|
4187
|
+
return `Unexpected argument: ${extra[0]}. ${LOCAL_BUILD_QT_SMOKE_USAGE}`;
|
|
4188
|
+
}
|
|
4189
|
+
const buildDir = optionalTrimmedStringFlag(parsed, "build-dir");
|
|
4190
|
+
if (buildDir.error) {
|
|
4191
|
+
return buildDir.error;
|
|
4192
|
+
}
|
|
4193
|
+
if (!buildDir.value) {
|
|
4194
|
+
return LOCAL_BUILD_QT_SMOKE_USAGE;
|
|
4195
|
+
}
|
|
4196
|
+
const source = optionalTrimmedStringFlag(parsed, "source");
|
|
4197
|
+
if (source.error) {
|
|
4198
|
+
return source.error;
|
|
4199
|
+
}
|
|
4200
|
+
const releaseRoot = optionalTrimmedStringFlag(parsed, "release-root");
|
|
4201
|
+
if (releaseRoot.error) {
|
|
4202
|
+
return releaseRoot.error;
|
|
4203
|
+
}
|
|
4204
|
+
const targetName = optionalTrimmedStringFlag(parsed, "target-name");
|
|
4205
|
+
if (targetName.error) {
|
|
4206
|
+
return targetName.error;
|
|
4207
|
+
}
|
|
4208
|
+
const account = optionalTrimmedStringAliasFlag(parsed, ["account", "account-id"], "account or account-id");
|
|
4209
|
+
if (account.error) {
|
|
4210
|
+
return account.error;
|
|
4211
|
+
}
|
|
4212
|
+
return {
|
|
4213
|
+
sourceDir: source.value,
|
|
4214
|
+
buildDir: buildDir.value,
|
|
4215
|
+
releaseRoot: releaseRoot.value,
|
|
4216
|
+
targetName: targetName.value,
|
|
4217
|
+
accountId: account.value,
|
|
4218
|
+
auth: localToolchainAuthContext(auth, account.value)
|
|
4219
|
+
};
|
|
4220
|
+
}
|
|
4221
|
+
function localToolchainAuthContext(auth, accountId) {
|
|
4222
|
+
return {
|
|
4223
|
+
authenticated: auth.authenticated,
|
|
4224
|
+
profile: auth.profile,
|
|
4225
|
+
source: auth.source,
|
|
4226
|
+
account_id: accountId
|
|
4227
|
+
};
|
|
4228
|
+
}
|
|
3454
4229
|
function usageEventsRequest(parsed) {
|
|
3455
4230
|
const unknownFlag = firstUnknownFlag(parsed, ["json", "account", "account-id", "api-key-id", "from", "to", "limit"]);
|
|
3456
4231
|
if (unknownFlag) {
|
|
@@ -3508,6 +4283,26 @@ function compactBody(input) {
|
|
|
3508
4283
|
}
|
|
3509
4284
|
return body;
|
|
3510
4285
|
}
|
|
4286
|
+
async function readLocalFileForUpload(filePath, label) {
|
|
4287
|
+
try {
|
|
4288
|
+
const info = await stat(filePath);
|
|
4289
|
+
if (!info.isFile()) {
|
|
4290
|
+
return `${label} must point to a file: ${filePath}`;
|
|
4291
|
+
}
|
|
4292
|
+
const bytes = await readFile(filePath);
|
|
4293
|
+
if (bytes.length === 0) {
|
|
4294
|
+
return `${label} must not be empty: ${filePath}`;
|
|
4295
|
+
}
|
|
4296
|
+
return {
|
|
4297
|
+
path: filePath,
|
|
4298
|
+
bytes,
|
|
4299
|
+
sha256: createHash("sha256").update(bytes).digest("hex")
|
|
4300
|
+
};
|
|
4301
|
+
}
|
|
4302
|
+
catch (error) {
|
|
4303
|
+
return `Could not read ${label} file ${filePath}: ${error instanceof Error ? error.message : String(error)}`;
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
3511
4306
|
function projectCreateBody(parsed) {
|
|
3512
4307
|
const extra = parsed.command.slice(3);
|
|
3513
4308
|
if (extra.length > 0) {
|
|
@@ -3801,8 +4596,15 @@ function renderServiceModeCatalog(catalog) {
|
|
|
3801
4596
|
` model_gateway=${catalog.boundaries.model_gateway}`,
|
|
3802
4597
|
` server_resource_orchestration=${catalog.boundaries.server_resource_orchestration}`,
|
|
3803
4598
|
` local_bridge=${catalog.boundaries.local_bridge}`,
|
|
4599
|
+
catalog.boundaries.free_registered_operations ? ` free_registered_operations=${catalog.boundaries.free_registered_operations}` : "",
|
|
4600
|
+
catalog.boundaries.paid_server_operations ? ` paid_server_operations=${catalog.boundaries.paid_server_operations}` : "",
|
|
4601
|
+
catalog.allocation_rule ? `allocation_rule=${catalog.allocation_rule}` : "",
|
|
4602
|
+
"free_registered_capabilities:",
|
|
4603
|
+
...(catalog.free_registered_capabilities ?? []).map((item) => ` - ${item.policy_id} workspace=${item.requires_server_workspace} lease=${item.allocates_server_resource_lease} meters=${item.meters.join(",") || "none"}`),
|
|
4604
|
+
"paid_capabilities:",
|
|
4605
|
+
...(catalog.paid_capabilities ?? []).map((item) => ` - ${item.policy_id} workspace=${item.requires_server_workspace} lease=${item.allocates_server_resource_lease} meters=${item.meters.join(",") || "none"}`),
|
|
3804
4606
|
"modes:"
|
|
3805
|
-
];
|
|
4607
|
+
].filter(Boolean);
|
|
3806
4608
|
for (const mode of catalog.modes) {
|
|
3807
4609
|
lines.push([
|
|
3808
4610
|
` ${mode.default ? "*" : "-"}`,
|
|
@@ -3843,6 +4645,15 @@ function renderPluginInstall(result) {
|
|
|
3843
4645
|
if (item.command_hint) {
|
|
3844
4646
|
lines.push(` ${item.command_hint}`);
|
|
3845
4647
|
}
|
|
4648
|
+
if (item.warning) {
|
|
4649
|
+
lines.push(` warning=${item.warning}`);
|
|
4650
|
+
}
|
|
4651
|
+
if (item.mcp_registered !== undefined) {
|
|
4652
|
+
lines.push(` codex_mcp_registered=${item.mcp_registered}`);
|
|
4653
|
+
}
|
|
4654
|
+
if (item.mcp_warning) {
|
|
4655
|
+
lines.push(` warning=${item.mcp_warning}`);
|
|
4656
|
+
}
|
|
3846
4657
|
}
|
|
3847
4658
|
return lines.join("\n");
|
|
3848
4659
|
}
|
|
@@ -4214,10 +5025,13 @@ function renderBoardMethods(data) {
|
|
|
4214
5025
|
method.operation,
|
|
4215
5026
|
`status=${method.status}`,
|
|
4216
5027
|
`runtime=${method.runtime}`,
|
|
5028
|
+
method.access_tier ? `access=${method.access_tier}` : "",
|
|
4217
5029
|
`endpoint=${method.http_method} ${method.path}`,
|
|
4218
5030
|
`workspace=${method.requires_workspace}`,
|
|
5031
|
+
method.allocates_server_workspace !== undefined ? `alloc_workspace=${method.allocates_server_workspace}` : "",
|
|
5032
|
+
method.allocates_server_resource_lease !== undefined ? `alloc_lease=${method.allocates_server_resource_lease}` : "",
|
|
4219
5033
|
`approval=${method.requires_approval}`
|
|
4220
|
-
].join(" ")).join("\n");
|
|
5034
|
+
].filter(Boolean).join(" ")).join("\n");
|
|
4221
5035
|
}
|
|
4222
5036
|
function renderBoardKnowledge(data) {
|
|
4223
5037
|
const files = isJsonObject(data) && Array.isArray(data.knowledge_files)
|
|
@@ -4446,6 +5260,119 @@ function renderBuildWorkspaceSourcePatch(result) {
|
|
|
4446
5260
|
}
|
|
4447
5261
|
return lines.join("\n");
|
|
4448
5262
|
}
|
|
5263
|
+
function renderLocalToolchainLatest(result) {
|
|
5264
|
+
const lines = [
|
|
5265
|
+
`board=${result.board_id}`,
|
|
5266
|
+
`channel=${result.channel}`,
|
|
5267
|
+
`version=${result.version}`,
|
|
5268
|
+
`host=${result.host}`,
|
|
5269
|
+
result.metadata_root ? `metadata_root=${result.metadata_root}` : "metadata=built-in"
|
|
5270
|
+
];
|
|
5271
|
+
if (result.packages.length > 0) {
|
|
5272
|
+
lines.push("packages:");
|
|
5273
|
+
for (const pkg of result.packages) {
|
|
5274
|
+
lines.push(` ${pkg.id}@${pkg.version}`);
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
return lines.join("\n");
|
|
5278
|
+
}
|
|
5279
|
+
function renderLocalToolchainCurrent(result) {
|
|
5280
|
+
if (!result.installed) {
|
|
5281
|
+
return [
|
|
5282
|
+
"No local toolchain installed.",
|
|
5283
|
+
`board=${result.board_id}`,
|
|
5284
|
+
`install_root=${result.install_root}`,
|
|
5285
|
+
`registry=${result.registry_path}`
|
|
5286
|
+
].join("\n");
|
|
5287
|
+
}
|
|
5288
|
+
return [
|
|
5289
|
+
"Local toolchain installed.",
|
|
5290
|
+
`board=${result.board_id}`,
|
|
5291
|
+
result.version ? `version=${result.version}` : "",
|
|
5292
|
+
result.channel ? `channel=${result.channel}` : "",
|
|
5293
|
+
result.release_root ? `release_root=${result.release_root}` : "",
|
|
5294
|
+
`install_root=${result.install_root}`,
|
|
5295
|
+
`registry=${result.registry_path}`
|
|
5296
|
+
].filter(Boolean).join("\n");
|
|
5297
|
+
}
|
|
5298
|
+
function renderLocalToolchainInstall(result) {
|
|
5299
|
+
const lines = [
|
|
5300
|
+
"Local toolchain installed.",
|
|
5301
|
+
`board=${result.board_id}`,
|
|
5302
|
+
`version=${result.version}`,
|
|
5303
|
+
`channel=${result.channel}`,
|
|
5304
|
+
`host=${result.host}`,
|
|
5305
|
+
`install_root=${result.install_root}`,
|
|
5306
|
+
`release_root=${result.release_root}`,
|
|
5307
|
+
`registry=${result.registry_path}`,
|
|
5308
|
+
`source=${result.source.kind}:${result.source.value}`,
|
|
5309
|
+
result.source.downloaded_path ? `downloaded=${result.source.downloaded_path}` : "",
|
|
5310
|
+
`validation=${result.validation.ok ? "ok" : "failed"}`
|
|
5311
|
+
].filter(Boolean);
|
|
5312
|
+
if (result.installed_paths.length > 0) {
|
|
5313
|
+
lines.push("installed_paths:");
|
|
5314
|
+
for (const installedPath of result.installed_paths) {
|
|
5315
|
+
lines.push(` ${installedPath}`);
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
if (result.packages.length > 0) {
|
|
5319
|
+
lines.push("packages:");
|
|
5320
|
+
for (const pkg of result.packages) {
|
|
5321
|
+
lines.push(` ${pkg.id}@${pkg.version}`);
|
|
5322
|
+
}
|
|
5323
|
+
}
|
|
5324
|
+
return lines.join("\n");
|
|
5325
|
+
}
|
|
5326
|
+
function renderLocalToolchainValidation(result) {
|
|
5327
|
+
const lines = [
|
|
5328
|
+
result.ok ? "Local toolchain ready." : "Local toolchain not ready.",
|
|
5329
|
+
`board=${result.board_id}`,
|
|
5330
|
+
`host=${result.host.platform}/${result.host.arch}`,
|
|
5331
|
+
`release_root=${result.release_root}`
|
|
5332
|
+
];
|
|
5333
|
+
for (const check of result.checked_paths) {
|
|
5334
|
+
lines.push(`${check.exists ? "ok" : "missing"} ${check.label}: ${check.path}`);
|
|
5335
|
+
}
|
|
5336
|
+
if (result.notes.length > 0) {
|
|
5337
|
+
lines.push("notes:");
|
|
5338
|
+
for (const note of result.notes) {
|
|
5339
|
+
lines.push(` ${note}`);
|
|
5340
|
+
}
|
|
5341
|
+
}
|
|
5342
|
+
return lines.join("\n");
|
|
5343
|
+
}
|
|
5344
|
+
function renderLocalCompileResult(result) {
|
|
5345
|
+
const lines = [
|
|
5346
|
+
`${result.operation} succeeded.`,
|
|
5347
|
+
`board=${result.board_id}`,
|
|
5348
|
+
result.account_id ? `account=${result.account_id}` : "",
|
|
5349
|
+
`auth=${result.auth.authenticated ? "authenticated" : "anonymous"} profile=${result.auth.profile}${result.auth.source ? ` source=${result.auth.source}` : ""}`,
|
|
5350
|
+
`source=${result.source_path}`,
|
|
5351
|
+
result.build_dir ? `build_dir=${result.build_dir}` : "",
|
|
5352
|
+
`artifact=${result.artifact_path}`,
|
|
5353
|
+
`size=${result.artifact_size_bytes}`,
|
|
5354
|
+
`sha256=${result.artifact_sha256}`,
|
|
5355
|
+
result.file_info ? `file=${result.file_info}` : "",
|
|
5356
|
+
`manifest=${result.manifest_path}`
|
|
5357
|
+
].filter(Boolean);
|
|
5358
|
+
for (const command of result.commands) {
|
|
5359
|
+
lines.push(`command_exit=${command.exit_code} cwd=${command.cwd}`);
|
|
5360
|
+
lines.push(` ${command.command.join(" ")}`);
|
|
5361
|
+
if (command.stdout_tail.length > 0) {
|
|
5362
|
+
lines.push(" stdout_tail:");
|
|
5363
|
+
for (const line of command.stdout_tail.slice(-12)) {
|
|
5364
|
+
lines.push(` ${line}`);
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
if (command.stderr_tail.length > 0) {
|
|
5368
|
+
lines.push(" stderr_tail:");
|
|
5369
|
+
for (const line of command.stderr_tail.slice(-12)) {
|
|
5370
|
+
lines.push(` ${line}`);
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
return lines.join("\n");
|
|
5375
|
+
}
|
|
4449
5376
|
function renderDoctor(result) {
|
|
4450
5377
|
const lines = [
|
|
4451
5378
|
`${result.status === "ready" ? "Ready" : "Not ready"}: ${result.summary_for_user}`,
|
|
@@ -4616,6 +5543,46 @@ function renderJob(job) {
|
|
|
4616
5543
|
}
|
|
4617
5544
|
return lines.join("\n");
|
|
4618
5545
|
}
|
|
5546
|
+
function renderBootLogoPackageResult(result) {
|
|
5547
|
+
const lines = [renderJob(result.task)];
|
|
5548
|
+
if (result.downloaded_artifact) {
|
|
5549
|
+
lines.push("downloaded_package:");
|
|
5550
|
+
lines.push(` artifact=${result.downloaded_artifact.artifact_id}`);
|
|
5551
|
+
lines.push(` output=${result.downloaded_artifact.output_path}`);
|
|
5552
|
+
lines.push(` size=${result.downloaded_artifact.size_bytes}`);
|
|
5553
|
+
}
|
|
5554
|
+
lines.push("next=merge the downloaded package with the local base image, then flash only after explicit approval.");
|
|
5555
|
+
return lines.join("\n");
|
|
5556
|
+
}
|
|
5557
|
+
function renderDtbPackageResult(result) {
|
|
5558
|
+
const lines = [renderJob(result.task)];
|
|
5559
|
+
if (result.downloaded_artifact) {
|
|
5560
|
+
lines.push("downloaded_package:");
|
|
5561
|
+
lines.push(` artifact=${result.downloaded_artifact.artifact_id}`);
|
|
5562
|
+
lines.push(` output=${result.downloaded_artifact.output_path}`);
|
|
5563
|
+
lines.push(` size=${result.downloaded_artifact.size_bytes}`);
|
|
5564
|
+
}
|
|
5565
|
+
lines.push("next=merge the downloaded DTB package with the local base image, then flash only after explicit approval.");
|
|
5566
|
+
return lines.join("\n");
|
|
5567
|
+
}
|
|
5568
|
+
function renderBootLogoComposeResult(result) {
|
|
5569
|
+
const label = result.operation_kind === "image.dtb.compose" ? "DTB" : "Boot-logo";
|
|
5570
|
+
return [
|
|
5571
|
+
result.ready_for_flash ? `${label} compose ready for flash review.` : `${label} compose created a guarded local result.`,
|
|
5572
|
+
`board=${result.board_id}`,
|
|
5573
|
+
result.variant_id ? `variant=${result.variant_id}` : "",
|
|
5574
|
+
`package=${result.package_path}`,
|
|
5575
|
+
`base=${result.base_image_path}`,
|
|
5576
|
+
`output=${result.output_image_path}`,
|
|
5577
|
+
`manifest=${result.manifest_path}`,
|
|
5578
|
+
`strategy=${result.local_merge_strategy}`,
|
|
5579
|
+
`patches=${result.patch_operations_applied}/${result.patch_operations_total}`,
|
|
5580
|
+
`replacement_applied=${result.replacement_applied}`,
|
|
5581
|
+
`ready_for_flash=${result.ready_for_flash}`,
|
|
5582
|
+
`cross_platform=${result.cross_platform} platform=${result.platform}/${result.arch}`,
|
|
5583
|
+
result.summary_for_user
|
|
5584
|
+
].filter(Boolean).join("\n");
|
|
5585
|
+
}
|
|
4619
5586
|
function safeArtifactOutputFileName(name) {
|
|
4620
5587
|
return name.replace(/[^A-Za-z0-9._-]+/g, "_") || "artifact.out";
|
|
4621
5588
|
}
|
|
@@ -5095,7 +6062,7 @@ async function waitForever() {
|
|
|
5095
6062
|
return 0;
|
|
5096
6063
|
}
|
|
5097
6064
|
function printHelp() {
|
|
5098
|
-
|
|
6065
|
+
printCliHelp(`embed CLI
|
|
5099
6066
|
|
|
5100
6067
|
Usage:
|
|
5101
6068
|
embed <command> [options]
|
|
@@ -5117,13 +6084,19 @@ Main workflow:
|
|
|
5117
6084
|
embed model default
|
|
5118
6085
|
4. Run a natural-language local tool loop:
|
|
5119
6086
|
embed agent run --prompt "验证开发板状态"
|
|
5120
|
-
5.
|
|
6087
|
+
5. Validate or use the local TaishanPi toolchain:
|
|
6088
|
+
embed local toolchain latest
|
|
6089
|
+
embed local toolchain install --source-url <toolchain.tar.gz>
|
|
6090
|
+
embed local toolchain validate
|
|
6091
|
+
embed local compile taishanpi --source ./main.c --output ./.embed-labs/build/main
|
|
6092
|
+
embed local build qt-smoke --build-dir ./.embed-labs/build/qt-smoke
|
|
6093
|
+
6. Pick a cloud build template:
|
|
5121
6094
|
embed board registry list
|
|
5122
6095
|
embed board methods taishanpi-1m-rk3566
|
|
5123
6096
|
embed board knowledge taishanpi-1m-rk3566
|
|
5124
6097
|
embed build template list
|
|
5125
6098
|
embed build template show <template_id>
|
|
5126
|
-
|
|
6099
|
+
7. Provision and populate a build workspace:
|
|
5127
6100
|
embed build workspace provision --account <account_id> --project <project_id> --template <template_id>
|
|
5128
6101
|
embed build resource lease create --workspace <workspace_id> --execution-mode cloud_worker
|
|
5129
6102
|
embed build workspace source put <workspace_id> --file ./main.c:src/main.c
|
|
@@ -5132,13 +6105,15 @@ Main workflow:
|
|
|
5132
6105
|
embed build workspace source search <workspace_id> --query init --glob "**/*.c"
|
|
5133
6106
|
embed build workspace source patch <workspace_id> --patch ./fix.patch
|
|
5134
6107
|
embed build workspace release <workspace_id> --dry-run
|
|
5135
|
-
|
|
6108
|
+
8. Generate application source on the server and follow artifacts:
|
|
5136
6109
|
embed build application generate --workspace <workspace_id> --prompt "Create a minimal Linux app" --provider bai --model gpt-5.2
|
|
5137
6110
|
embed build application compile --workspace <workspace_id> --source app/generated.c --execution-mode docker_worker
|
|
5138
6111
|
embed build image generate --workspace <workspace_id> --prompt "Generate a minimal TaishanPi image"
|
|
6112
|
+
embed build image boot-logo --logo ./logo.png --board taishanpi --variant 1M-RK3566 --output ./boot-logo-package.json
|
|
6113
|
+
embed image boot-logo compose --package ./boot-logo-package.json --base-image ./boot.img --output ./boot-logo.img
|
|
5139
6114
|
embed cloud task artifacts <task_id>
|
|
5140
6115
|
embed artifact download <artifact_id> --output ./artifact.bin
|
|
5141
|
-
|
|
6116
|
+
9. Check credits or create a recharge QR:
|
|
5142
6117
|
embed billing balance --account <account_id>
|
|
5143
6118
|
embed billing tokens --account <account_id>
|
|
5144
6119
|
embed billing ledger --account <account_id>
|
|
@@ -5153,7 +6128,17 @@ Local hardware:
|
|
|
5153
6128
|
embed agent run --prompt "部署生成的泰山派应用" --host 198.19.77.2 --artifact-task <task_id> --remote-path /userdata/embed-labs/apps/app --approve --run
|
|
5154
6129
|
embed tool list
|
|
5155
6130
|
embed tool call device.probe --input-json '{"host":"198.19.77.2","ports":[22,15301]}'
|
|
6131
|
+
embed tool call wifi.scan --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
6132
|
+
embed tool call chip.temperature --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
6133
|
+
embed tool call qml.runtime.status --input-json '{"host":"198.19.77.2","user":"root","port":18130}'
|
|
5156
6134
|
embed device list
|
|
6135
|
+
embed local toolchain latest
|
|
6136
|
+
embed local toolchain current
|
|
6137
|
+
embed local toolchain install --source-url <toolchain.tar.gz>
|
|
6138
|
+
embed local toolchain validate
|
|
6139
|
+
embed local compile taishanpi --source ./main.c --output ./.embed-labs/build/main
|
|
6140
|
+
embed local build qt-smoke --build-dir ./.embed-labs/build/qt-smoke
|
|
6141
|
+
embed image boot-logo compose --package ./boot-logo-package.json --base-image ./boot.img --output ./boot-logo.img
|
|
5157
6142
|
embed deploy taishanpi --host 198.19.77.2 --artifact ./artifact.bin --approve --run
|
|
5158
6143
|
embed flash plan --board <rp2350|taishanpi>
|
|
5159
6144
|
|
|
@@ -5188,7 +6173,7 @@ function printHelpTopic(topic) {
|
|
|
5188
6173
|
printCommandReference();
|
|
5189
6174
|
return;
|
|
5190
6175
|
}
|
|
5191
|
-
|
|
6176
|
+
printCliHelp(`Unknown help topic: ${topic}
|
|
5192
6177
|
|
|
5193
6178
|
Available topics:
|
|
5194
6179
|
embed help getting-started
|
|
@@ -5196,7 +6181,7 @@ Available topics:
|
|
|
5196
6181
|
`);
|
|
5197
6182
|
}
|
|
5198
6183
|
function printGettingStartedHelp() {
|
|
5199
|
-
|
|
6184
|
+
printCliHelp(`embed getting started
|
|
5200
6185
|
|
|
5201
6186
|
After npm install, use the installed embed binary directly:
|
|
5202
6187
|
|
|
@@ -5225,6 +6210,9 @@ Cloud build path:
|
|
|
5225
6210
|
embed model list
|
|
5226
6211
|
embed model default
|
|
5227
6212
|
embed agent run --prompt "验证开发板状态"
|
|
6213
|
+
embed local toolchain validate
|
|
6214
|
+
embed local compile taishanpi --source ./main.c --output ./.embed-labs/build/main
|
|
6215
|
+
embed local build qt-smoke --build-dir ./.embed-labs/build/qt-smoke
|
|
5228
6216
|
embed board registry list
|
|
5229
6217
|
embed board registry show taishanpi-1m-rk3566
|
|
5230
6218
|
embed board methods taishanpi-1m-rk3566
|
|
@@ -5242,6 +6230,8 @@ Cloud build path:
|
|
|
5242
6230
|
embed build application generate --workspace <workspace_id> --prompt "Create a minimal Linux app" --provider bai --model gpt-5.2
|
|
5243
6231
|
embed build application compile --workspace <workspace_id> --source app/generated.c --execution-mode docker_worker
|
|
5244
6232
|
embed build image generate --workspace <workspace_id> --prompt "Generate a minimal TaishanPi image"
|
|
6233
|
+
embed build image boot-logo --logo ./logo.png --board taishanpi --variant 1M-RK3566 --output ./boot-logo-package.json
|
|
6234
|
+
embed image boot-logo compose --package ./boot-logo-package.json --base-image ./boot.img --output ./boot-logo.img
|
|
5245
6235
|
embed cloud task status <task_id>
|
|
5246
6236
|
embed cloud task artifacts <task_id>
|
|
5247
6237
|
embed artifact download <artifact_id> --output ./artifact.bin
|
|
@@ -5279,7 +6269,7 @@ Use --json on commands when scripting or running in CI.
|
|
|
5279
6269
|
`);
|
|
5280
6270
|
}
|
|
5281
6271
|
function printCommandReference() {
|
|
5282
|
-
|
|
6272
|
+
printCliHelp(`embed CLI
|
|
5283
6273
|
|
|
5284
6274
|
Usage:
|
|
5285
6275
|
embed doctor [--json]
|
|
@@ -5299,7 +6289,7 @@ Usage:
|
|
|
5299
6289
|
embed board methods <template_id> [--json]
|
|
5300
6290
|
embed board knowledge <template_id> [--json]
|
|
5301
6291
|
embed board knowledge file <template_id> --source board_pack|build_template|registry --path <relative_path> [--output <local_path>] [--json]
|
|
5302
|
-
embed agent run --prompt <request> [--account <account_id>] [--workspace <workspace_id>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--max-tool-calls
|
|
6292
|
+
embed agent run --prompt <request> [--account <account_id>] [--workspace <workspace_id>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--max-tool-calls 6] [--host <ip>] [--ports 22,15301] [--artifact <local_file>|--artifact-id <artifact_id>|--artifact-task <task_id>] [--artifact-output <path>] [--remote-path <path>] [--run] [--approve] [--json]
|
|
5303
6293
|
embed run <natural language request> [--provider stub|openai|bai|cc|claude-code] [--approve] [--json]
|
|
5304
6294
|
embed tool list [--json]
|
|
5305
6295
|
embed tool call <capability_id> [--input-json '<json>'] [--approve] [--json]
|
|
@@ -5344,7 +6334,22 @@ Usage:
|
|
|
5344
6334
|
embed build application generate --workspace <workspace_id> --prompt <request> [--account <account_id>] [--target <source_path>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--json]
|
|
5345
6335
|
embed build application compile --workspace <workspace_id> [--account <account_id>] [--source <source_path>] [--execution-mode docker_worker|server_direct|dry_run] [--compiler auto|cc|gcc|clang|aarch64-linux-gnu-gcc] [--json]
|
|
5346
6336
|
embed build image generate --workspace <workspace_id> --prompt <request> [--account <account_id>] [--image-profile <profile_id>] [--provider stub|openai|bai|cc|claude-code] [--model <model>] [--execution-mode cloud_worker|dry_run] [--worker-pool <pool>] [--json]
|
|
6337
|
+
embed build image boot-logo --logo <local_image> [--account <account_id>] [--project <project_id>] [--board taishanpi] [--variant 1M-RK3566] [--kernel-logo <local_image>] [--rotate -90] [--scale 100] [--output <package.json>] [--json]
|
|
6338
|
+
embed image boot-logo compose --package <boot-logo-package.json> --base-image <boot.img|image.img> --output <image> [--manifest <manifest.json>] [--force] [--json]
|
|
6339
|
+
embed local toolchain latest [--board taishanpi-1m-rk3566] [--channel stable] [--metadata-root <path>] [--json]
|
|
6340
|
+
embed local toolchain current [--install-root <path>] [--json]
|
|
6341
|
+
embed local toolchain install [--board taishanpi-1m-rk3566] [--channel stable] [--metadata-root <path>] [--source-url <tar.gz-url>|--source-release-root <path>] [--install-root <path>] [--force] [--json]
|
|
6342
|
+
embed local toolchain validate [--release-root <path>] [--json]
|
|
6343
|
+
embed local compile taishanpi --source <main.c|main.cpp> --output <artifact> [--release-root <path>] [--account <account_id>] [--json]
|
|
6344
|
+
embed local build qt-smoke --build-dir <dir> [--source <qt-smoke-dir>] [--release-root <path>] [--account <account_id>] [--json]
|
|
5347
6345
|
embed debug tools [--json]
|
|
6346
|
+
embed tool list [--json]
|
|
6347
|
+
embed tool call wifi.scan --input-json '{"host":"198.19.77.2","user":"root"}' [--json]
|
|
6348
|
+
embed tool call bluetooth.scan --input-json '{"host":"198.19.77.2","user":"root","duration_seconds":8}' [--json]
|
|
6349
|
+
embed tool call chip.cpu.frequency --input-json '{"host":"198.19.77.2","user":"root"}' [--json]
|
|
6350
|
+
embed tool call chip.temperature --input-json '{"host":"198.19.77.2","user":"root"}' [--json]
|
|
6351
|
+
embed tool call qml.runtime.status --input-json '{"host":"198.19.77.2","user":"root","port":18130}' [--json]
|
|
6352
|
+
embed tool call qml.runtime.start --input-json '{"host":"198.19.77.2","user":"root","port":18130}' [--json]
|
|
5348
6353
|
embed deploy taishanpi --host <ip> --artifact <local_file> --approve [--remote-path /userdata/embed-labs/apps/app] [--run] [--json]
|
|
5349
6354
|
embed board deploy taishanpi --host <ip> --artifact <local_file> --approve [--remote-path /userdata/embed-labs/apps/app] [--run] [--json]
|
|
5350
6355
|
embed device list [--json]
|
|
@@ -5383,6 +6388,23 @@ Environment:
|
|
|
5383
6388
|
CODEX_HOME=~/.codex
|
|
5384
6389
|
`);
|
|
5385
6390
|
}
|
|
6391
|
+
function printCliHelp(text) {
|
|
6392
|
+
console.log(formatCliHelp(text));
|
|
6393
|
+
}
|
|
6394
|
+
function formatCliHelp(text) {
|
|
6395
|
+
if (currentCommandName() !== "embedlabs") {
|
|
6396
|
+
return text;
|
|
6397
|
+
}
|
|
6398
|
+
return text
|
|
6399
|
+
.replace(/^embed CLI$/m, "embedlabs CLI")
|
|
6400
|
+
.replace(/^embed getting started$/m, "embedlabs getting started")
|
|
6401
|
+
.replace("After npm install, use the installed embed binary directly:", "After npm install, use the installed embedlabs binary directly:")
|
|
6402
|
+
.replace(/(^|\n)(\s*)embed(\s+)/g, "$1$2embedlabs$3");
|
|
6403
|
+
}
|
|
6404
|
+
function currentCommandName() {
|
|
6405
|
+
const invoked = basename(process.argv[1] ?? "");
|
|
6406
|
+
return invoked.startsWith("embedlabs") ? "embedlabs" : "embed";
|
|
6407
|
+
}
|
|
5386
6408
|
main(process.argv.slice(2))
|
|
5387
6409
|
.then((code) => {
|
|
5388
6410
|
process.exitCode = code;
|