@kvell007/embed-labs-cli 0.1.0-alpha.55 → 0.1.0-alpha.57

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 CHANGED
@@ -8,7 +8,7 @@ import { arch, hostname, homedir, platform, tmpdir } from "node:os";
8
8
  import { basename, delimiter, dirname, join, resolve } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { composeBootLogoPackage } from "./image-compose.js";
11
- import { buildTaishanPiQtSmoke, compileTaishanPiSingleFile, currentLocalToolchain, installLocalToolchain, latestLocalToolchain, listLocalToolchainEnvironments, uninstallLocalToolchain, validateLocalToolchain } from "./local-toolchain.js";
11
+ import { buildTaishanPiQtSmoke, compileTaishanPiSingleFile, currentLocalToolchain, installLocalToolchain, latestLocalToolchain, listLocalToolchainEnvironments, uninstallLocalToolchain, validateLocalToolchain, windowsWslInstall, windowsWslStatus } from "./local-toolchain.js";
12
12
  import { fail, ok } from "@embed-labs/protocol";
13
13
  const require = createRequire(import.meta.url);
14
14
  const CLI_MODULE_DIR = dirname(fileURLToPath(import.meta.url));
@@ -104,6 +104,8 @@ const LOCAL_TOOLCHAIN_CURRENT_USAGE = "Usage: embed local toolchain current [--i
104
104
  const LOCAL_TOOLCHAIN_INSTALL_USAGE = "Usage: embed local toolchain install [--board taishanpi-1m-rk3566|pico2w-rp2350-monitor|coloreasypico2-rp2350-monitor] [--channel stable] [--metadata-root <path>] [--source-url <tar.gz-url>|--source-release-root <path>] [--install-root <path>] [--mode minimal|runtime|compile|qt|firmware|full|images] [--force] [--json]\nDefault source: the production download channel at download.embedboard.com.";
105
105
  const LOCAL_TOOLCHAIN_UNINSTALL_USAGE = "Usage: embed local toolchain uninstall --board taishanpi-1m-rk3566|pico2w-rp2350-monitor|coloreasypico2-rp2350-monitor [--install-root <path>] [--json]";
106
106
  const LOCAL_TOOLCHAIN_VALIDATE_USAGE = "Usage: embed local toolchain validate [--board taishanpi-1m-rk3566|pico2w-rp2350-monitor|coloreasypico2-rp2350-monitor] [--release-root <path>] [--mode minimal|runtime|compile|qt|firmware|full|images] [--json]";
107
+ const LOCAL_WSL_STATUS_USAGE = "Usage: embed local wsl status [--json]";
108
+ const LOCAL_WSL_INSTALL_USAGE = "Usage: embed local wsl install [--distribution Ubuntu] [--no-launch true|false] [--web-download true|false] [--timeout-ms 600000] [--json]";
107
109
  const LOCAL_COMPILE_TAISHANPI_USAGE = "Usage: embed local compile taishanpi --source <main.c|main.cpp> --output <artifact> [--release-root <path>] [--account <account_id>] [--json]";
108
110
  const LOCAL_BUILD_QT_SMOKE_USAGE = "Usage: embed local build qt-smoke --build-dir <dir> [--source <qt-cmake-dir>] [--target-name <executable>] [--release-root <path>] [--account <account_id>] [--json]";
109
111
  const AUTH_DEVICE_STATUS_USAGE = "Usage: embed auth device status [--json]";
@@ -635,6 +637,21 @@ async function main(argv) {
635
637
  }
636
638
  return output(parsed, ok(await validateLocalToolchain(request)), renderLocalToolchainValidation);
637
639
  }
640
+ if (action === "wsl" && parsed.command[2] === "status") {
641
+ const unknownFlag = firstUnknownFlag(parsed, ["json"]);
642
+ const extra = parsed.command.slice(3);
643
+ if (unknownFlag || extra.length > 0) {
644
+ return output(parsed, fail("invalid_args", unknownFlag ? `Unknown flag --${unknownFlag}. ${LOCAL_WSL_STATUS_USAGE}` : LOCAL_WSL_STATUS_USAGE), undefined, 2);
645
+ }
646
+ return output(parsed, ok(await windowsWslStatus()), renderWindowsWslStatus);
647
+ }
648
+ if (action === "wsl" && parsed.command[2] === "install") {
649
+ const request = localWslInstallRequest(parsed);
650
+ if (typeof request === "string") {
651
+ return output(parsed, fail("invalid_args", request), undefined, 2);
652
+ }
653
+ return output(parsed, ok(await windowsWslInstall(request)), renderWindowsWslInstall);
654
+ }
638
655
  if (action === "compile" && parsed.command[2] === "taishanpi") {
639
656
  const request = localCompileTaishanPiRequest(parsed, await authStatus());
640
657
  if (typeof request === "string") {
@@ -657,6 +674,8 @@ async function main(argv) {
657
674
  LOCAL_TOOLCHAIN_INSTALL_USAGE,
658
675
  LOCAL_TOOLCHAIN_UNINSTALL_USAGE,
659
676
  LOCAL_TOOLCHAIN_VALIDATE_USAGE,
677
+ LOCAL_WSL_STATUS_USAGE,
678
+ LOCAL_WSL_INSTALL_USAGE,
660
679
  LOCAL_COMPILE_TAISHANPI_USAGE,
661
680
  LOCAL_BUILD_QT_SMOKE_USAGE
662
681
  ].join("\n")), undefined, 2);
@@ -1088,11 +1107,18 @@ async function main(argv) {
1088
1107
  return output(parsed, fail("unknown_command", `Unknown command: ${parsed.command.join(" ")}`), undefined, 2);
1089
1108
  }
1090
1109
  catch (error) {
1091
- return output(parsed, fail("command_failed", error instanceof Error ? error.message : String(error), {
1092
- remediation: `Check that embed-local-bridge is running at ${DEFAULT_BRIDGE_URL}. Start it with: embed bridge start`
1110
+ const message = error instanceof Error ? error.message : String(error);
1111
+ return output(parsed, fail("command_failed", message, {
1112
+ remediation: commandFailureRemediation(message)
1093
1113
  }), undefined, 1);
1094
1114
  }
1095
1115
  }
1116
+ function commandFailureRemediation(message) {
1117
+ if (message.includes("TaishanPi") && message.includes("WSL2")) {
1118
+ return "Run: embedlabs local wsl status";
1119
+ }
1120
+ return `Check that embed-local-bridge is running at ${DEFAULT_BRIDGE_URL}. Start it with: embed bridge start`;
1121
+ }
1096
1122
  function parseArgs(argv) {
1097
1123
  const command = [];
1098
1124
  const flags = {};
@@ -5710,6 +5736,32 @@ function localToolchainLatestRequest(parsed) {
5710
5736
  return metadataRoot.error;
5711
5737
  return { boardId: board.value, channel: channel.value, metadataRoot: metadataRoot.value };
5712
5738
  }
5739
+ function localWslInstallRequest(parsed) {
5740
+ const unknownFlag = firstUnknownFlag(parsed, ["json", "distribution", "distro", "no-launch", "web-download", "timeout-ms"]);
5741
+ if (unknownFlag) {
5742
+ return `Unknown flag --${unknownFlag}. ${LOCAL_WSL_INSTALL_USAGE}`;
5743
+ }
5744
+ const extra = parsed.command.slice(3);
5745
+ if (extra.length > 0) {
5746
+ return `Unexpected argument: ${extra[0]}. ${LOCAL_WSL_INSTALL_USAGE}`;
5747
+ }
5748
+ const distribution = stringFlag(parsed, "distribution") ?? stringFlag(parsed, "distro");
5749
+ const noLaunch = optionalBooleanFlag(parsed, "no-launch");
5750
+ if (typeof noLaunch === "string")
5751
+ return noLaunch;
5752
+ const webDownload = optionalBooleanFlag(parsed, "web-download");
5753
+ if (typeof webDownload === "string")
5754
+ return webDownload;
5755
+ const timeoutMs = optionalIntegerFlag(parsed, "timeout-ms", 1_000, 3_600_000);
5756
+ if (timeoutMs.error)
5757
+ return timeoutMs.error;
5758
+ return {
5759
+ distribution,
5760
+ noLaunch,
5761
+ webDownload,
5762
+ timeoutMs: timeoutMs.value
5763
+ };
5764
+ }
5713
5765
  function localToolchainCurrentRequest(parsed) {
5714
5766
  const unknownFlag = firstUnknownFlag(parsed, ["json", "install-root"]);
5715
5767
  if (unknownFlag) {
@@ -7103,6 +7155,61 @@ function localToolchainStatusLabel(status) {
7103
7155
  return "unsupported_host/当前系统暂不支持";
7104
7156
  return status;
7105
7157
  }
7158
+ function renderWindowsWslStatus(result) {
7159
+ const lines = [
7160
+ "Windows WSL2 status",
7161
+ `host=${result.host}`,
7162
+ `applicable=${result.applicable}`,
7163
+ `wsl_available=${result.wsl_available}`,
7164
+ `usable=${result.usable}`,
7165
+ `checked_at=${result.checked_at}`,
7166
+ `status_command=${result.commands.status}`,
7167
+ `list_command=${result.commands.list}`,
7168
+ `list_online_command=${result.commands.list_online}`,
7169
+ `install_command=${result.commands.install_ubuntu}`
7170
+ ];
7171
+ if (result.distributions.length > 0) {
7172
+ lines.push("distributions:");
7173
+ for (const distro of result.distributions) {
7174
+ lines.push(` ${distro.default ? "*" : "-"} ${distro.name} state=${distro.state ?? "unknown"} version=${distro.version ?? "unknown"}`);
7175
+ }
7176
+ }
7177
+ if (result.online_distributions.length > 0) {
7178
+ lines.push("online_distributions:");
7179
+ for (const distro of result.online_distributions) {
7180
+ lines.push(` ${distro.default ? "*" : "-"} ${distro.name}${distro.friendly_name ? ` (${distro.friendly_name})` : ""}`);
7181
+ }
7182
+ }
7183
+ for (const note of result.notes) {
7184
+ lines.push(`note=${note}`);
7185
+ }
7186
+ return lines.join("\n");
7187
+ }
7188
+ function renderWindowsWslInstall(result) {
7189
+ const lines = [
7190
+ "Windows WSL2 install",
7191
+ `host=${result.host}`,
7192
+ `command=${result.command.join(" ")}`,
7193
+ `exit_code=${result.exit_code}`,
7194
+ `usable_after=${result.status_after.usable}`
7195
+ ];
7196
+ if (result.stdout_tail.length > 0) {
7197
+ lines.push("stdout_tail:");
7198
+ for (const line of result.stdout_tail) {
7199
+ lines.push(` ${line}`);
7200
+ }
7201
+ }
7202
+ if (result.stderr_tail.length > 0) {
7203
+ lines.push("stderr_tail:");
7204
+ for (const line of result.stderr_tail) {
7205
+ lines.push(` ${line}`);
7206
+ }
7207
+ }
7208
+ for (const note of result.notes) {
7209
+ lines.push(`note=${note}`);
7210
+ }
7211
+ return lines.join("\n");
7212
+ }
7106
7213
  function localToolchainComponentSummary(components) {
7107
7214
  const totalBytes = components.reduce((total, component) => total + component.size_bytes, 0);
7108
7215
  return `${components.length} components, ${formatByteSize(totalBytes)}`;
@@ -7927,6 +8034,24 @@ function optionalPositiveIntegerFlag(parsed, name) {
7927
8034
  }
7928
8035
  return { value };
7929
8036
  }
8037
+ function optionalIntegerFlag(parsed, name, min, max) {
8038
+ const values = flagValues(parsed, name);
8039
+ if (values.length === 0) {
8040
+ return {};
8041
+ }
8042
+ if (values.some((value) => typeof value !== "string")) {
8043
+ return { error: `--${name} requires a value.` };
8044
+ }
8045
+ const raw = values[values.length - 1].trim();
8046
+ if (!/^-?\d+$/.test(raw)) {
8047
+ return { error: `--${name} must be an integer.` };
8048
+ }
8049
+ const value = Number(raw);
8050
+ if (!Number.isSafeInteger(value) || value < min || value > max) {
8051
+ return { error: `--${name} must be an integer from ${min} through ${max}.` };
8052
+ }
8053
+ return { value };
8054
+ }
7930
8055
  function jsonObjectListFlag(parsed, name) {
7931
8056
  const objects = [];
7932
8057
  for (const raw of flagValues(parsed, name)) {