@kvell007/embed-labs-cli 0.1.0-alpha.11 → 0.1.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +317 -23
- package/dist/index.js.map +1 -1
- package/dist/local-toolchain.d.ts +40 -5
- package/dist/local-toolchain.js +244 -59
- package/dist/local-toolchain.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { constants } from "node:fs";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
-
import { access, cp, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
5
|
+
import { access, cp, mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { homedir, tmpdir } from "node:os";
|
|
8
8
|
import { basename, delimiter, dirname, join, resolve } from "node:path";
|
|
@@ -83,8 +83,8 @@ const BUILD_IMAGE_DTB_USAGE = "Usage: embed build image dtb --dtb <local.dtb|loc
|
|
|
83
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
84
|
const LOCAL_TOOLCHAIN_LATEST_USAGE = "Usage: embed local toolchain latest [--board taishanpi-1m-rk3566] [--channel stable] [--metadata-root <path>] [--json]";
|
|
85
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]\nDefault source: the production download channel at download.embedboard.com.";
|
|
87
|
-
const LOCAL_TOOLCHAIN_VALIDATE_USAGE = "Usage: embed local toolchain validate [--release-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>] [--mode minimal|compile|qt|full|images] [--force] [--json]\nDefault source: the production download channel at download.embedboard.com.";
|
|
87
|
+
const LOCAL_TOOLCHAIN_VALIDATE_USAGE = "Usage: embed local toolchain validate [--release-root <path>] [--mode minimal|compile|qt|full|images] [--json]";
|
|
88
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
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]";
|
|
90
90
|
const BOARD_REGISTRY_LIST_USAGE = "Usage: embed board registry list [--json]";
|
|
@@ -543,7 +543,7 @@ async function main(argv) {
|
|
|
543
543
|
if (typeof request === "string") {
|
|
544
544
|
return output(parsed, fail("invalid_args", request), undefined, 2);
|
|
545
545
|
}
|
|
546
|
-
return output(parsed, ok(await validateLocalToolchain(request
|
|
546
|
+
return output(parsed, ok(await validateLocalToolchain(request)), renderLocalToolchainValidation);
|
|
547
547
|
}
|
|
548
548
|
if (action === "compile" && parsed.command[2] === "taishanpi") {
|
|
549
549
|
const request = localCompileTaishanPiRequest(parsed, await authStatus());
|
|
@@ -1351,17 +1351,29 @@ function isApiResponse(value) {
|
|
|
1351
1351
|
return isJsonObject(error) && typeof error.code === "string" && typeof error.message === "string";
|
|
1352
1352
|
}
|
|
1353
1353
|
async function bridgeGet(path) {
|
|
1354
|
-
const response = await fetch(`${DEFAULT_BRIDGE_URL}${path}
|
|
1354
|
+
const response = await fetch(`${DEFAULT_BRIDGE_URL}${path}`, {
|
|
1355
|
+
headers: bridgeHeaders()
|
|
1356
|
+
});
|
|
1355
1357
|
return await response.json();
|
|
1356
1358
|
}
|
|
1357
1359
|
async function bridgePost(path, body) {
|
|
1358
1360
|
const response = await fetch(`${DEFAULT_BRIDGE_URL}${path}`, {
|
|
1359
1361
|
method: "POST",
|
|
1360
|
-
headers: { "content-type": "application/json" },
|
|
1362
|
+
headers: bridgeHeaders({ "content-type": "application/json" }),
|
|
1361
1363
|
body: JSON.stringify(body)
|
|
1362
1364
|
});
|
|
1363
1365
|
return await response.json();
|
|
1364
1366
|
}
|
|
1367
|
+
function bridgeHeaders(base = {}) {
|
|
1368
|
+
const token = process.env.EMBED_BRIDGE_TOKEN?.trim();
|
|
1369
|
+
if (!token) {
|
|
1370
|
+
return base;
|
|
1371
|
+
}
|
|
1372
|
+
return {
|
|
1373
|
+
...base,
|
|
1374
|
+
authorization: `Bearer ${token}`
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1365
1377
|
async function cloudGet(path) {
|
|
1366
1378
|
return await cloudRequest("GET", path);
|
|
1367
1379
|
}
|
|
@@ -1535,6 +1547,7 @@ async function installCodexPlugin(parsed, context) {
|
|
|
1535
1547
|
}
|
|
1536
1548
|
const targetRoot = codexPluginTargetRoot(parsed, context.installingAll);
|
|
1537
1549
|
const targetPath = join(targetRoot, "embed-labs");
|
|
1550
|
+
const legacyCleanup = await cleanupLegacyCodexPluginRemnants(targetRoot);
|
|
1538
1551
|
if (await pathExists(targetPath) && !booleanFlag(parsed, "force")) {
|
|
1539
1552
|
return fail("plugin_already_installed", `Codex plugin already exists at ${targetPath}.`, {
|
|
1540
1553
|
remediation: "Pass --force to replace it, or pass --codex-target/--target to install into a different directory."
|
|
@@ -1552,8 +1565,10 @@ async function installCodexPlugin(parsed, context) {
|
|
|
1552
1565
|
command_hint: mcpRegistration.registered
|
|
1553
1566
|
? "Codex MCP was registered. Start a new Codex session to reload tools."
|
|
1554
1567
|
: mcpRegistration.hint,
|
|
1568
|
+
warning: legacyCodexCleanupWarning(legacyCleanup),
|
|
1555
1569
|
mcp_registered: mcpRegistration.registered,
|
|
1556
|
-
mcp_warning: mcpRegistration.warning
|
|
1570
|
+
mcp_warning: mcpRegistration.warning,
|
|
1571
|
+
cleanup: legacyCleanup
|
|
1557
1572
|
});
|
|
1558
1573
|
}
|
|
1559
1574
|
async function installOpenCodePlugin(parsed, context) {
|
|
@@ -1562,8 +1577,10 @@ async function installOpenCodePlugin(parsed, context) {
|
|
|
1562
1577
|
return source;
|
|
1563
1578
|
}
|
|
1564
1579
|
const targetRoot = openCodePluginTargetRoot(parsed, context.installingAll);
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1580
|
+
const globalInstall = isGlobalOpenCodeRoot(targetRoot);
|
|
1581
|
+
const wrapperPath = join(targetRoot, "plugins", "embed-labs.js");
|
|
1582
|
+
const legacyCleanup = await cleanupLegacyOpenCodePluginRemnants(targetRoot, globalInstall);
|
|
1583
|
+
if (!globalInstall && await pathExists(wrapperPath) && !booleanFlag(parsed, "force")) {
|
|
1567
1584
|
return fail("plugin_already_installed", `OpenCode plugin wrapper already exists at ${wrapperPath}.`, {
|
|
1568
1585
|
remediation: "Pass --force to replace it, or pass --opencode-target/--target to install into a different directory."
|
|
1569
1586
|
});
|
|
@@ -1589,15 +1606,25 @@ async function installOpenCodePlugin(parsed, context) {
|
|
|
1589
1606
|
});
|
|
1590
1607
|
}
|
|
1591
1608
|
await ensureOpenCodeInstallPackageJson(targetRoot);
|
|
1592
|
-
|
|
1609
|
+
if (globalInstall) {
|
|
1610
|
+
await rm(wrapperPath, { force: true });
|
|
1611
|
+
legacyCleanup.legacy_removed_config_entries?.push(...await ensureOpenCodeGlobalPluginConfig());
|
|
1612
|
+
}
|
|
1613
|
+
else {
|
|
1614
|
+
await writeFile(wrapperPath, `export { default, DevelopmentBoardToolchainPlugin } from "embed-labs";\n`, "utf8");
|
|
1615
|
+
}
|
|
1593
1616
|
const duplicateWarning = await openCodeDuplicatePluginWarning(targetRoot);
|
|
1617
|
+
const cleanupWarning = legacyOpenCodeCleanupWarning(legacyCleanup);
|
|
1594
1618
|
return ok({
|
|
1595
1619
|
id: "opencode",
|
|
1596
1620
|
target_path: targetRoot,
|
|
1597
1621
|
source: source.data.sourceLabel,
|
|
1598
1622
|
version: source.data.version,
|
|
1599
|
-
command_hint:
|
|
1600
|
-
|
|
1623
|
+
command_hint: globalInstall
|
|
1624
|
+
? "Restart OpenCode so the global embed-labs package plugin is reloaded."
|
|
1625
|
+
: "Start OpenCode from the project containing this .opencode directory.",
|
|
1626
|
+
warning: combineWarnings(cleanupWarning, duplicateWarning),
|
|
1627
|
+
cleanup: legacyCleanup
|
|
1601
1628
|
});
|
|
1602
1629
|
}
|
|
1603
1630
|
async function resolveCodexPluginSource(context) {
|
|
@@ -1811,7 +1838,204 @@ function openCodePluginTargetRoot(parsed, installingAll) {
|
|
|
1811
1838
|
return resolve(target ?? defaultOpenCodeRoot());
|
|
1812
1839
|
}
|
|
1813
1840
|
function defaultCodexPluginRoot() {
|
|
1814
|
-
return join(
|
|
1841
|
+
return join(defaultCodexHome(), "plugins");
|
|
1842
|
+
}
|
|
1843
|
+
function defaultCodexHome() {
|
|
1844
|
+
return resolve(process.env.CODEX_HOME?.trim() || join(homedir(), ".codex"));
|
|
1845
|
+
}
|
|
1846
|
+
function codexConfigPath() {
|
|
1847
|
+
return join(defaultCodexHome(), "config.toml");
|
|
1848
|
+
}
|
|
1849
|
+
async function cleanupLegacyCodexPluginRemnants(targetRoot) {
|
|
1850
|
+
const removedPaths = [];
|
|
1851
|
+
const removedConfigTables = [];
|
|
1852
|
+
const warnings = [];
|
|
1853
|
+
const legacyPaths = [
|
|
1854
|
+
join(targetRoot, "dbt-agent"),
|
|
1855
|
+
join(targetRoot, "development-board-toolchain"),
|
|
1856
|
+
join(targetRoot, "cache", "embed-labs", "dbt-agent"),
|
|
1857
|
+
join(targetRoot, "cache", "dbt-agent"),
|
|
1858
|
+
join(targetRoot, "cache", "plugins", "dbt-agent")
|
|
1859
|
+
];
|
|
1860
|
+
legacyPaths.push(...await discoverLegacyCodexCachePaths(targetRoot));
|
|
1861
|
+
if (resolve(targetRoot) === resolve(defaultCodexPluginRoot())) {
|
|
1862
|
+
legacyPaths.push(join(defaultCodexHome(), ".tmp", "plugins"), join(defaultCodexHome(), ".tmp", "plugins.sha"));
|
|
1863
|
+
}
|
|
1864
|
+
for (const candidate of legacyPaths) {
|
|
1865
|
+
try {
|
|
1866
|
+
if (await pathExists(candidate)) {
|
|
1867
|
+
await rm(candidate, { recursive: true, force: true });
|
|
1868
|
+
removedPaths.push(candidate);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
catch (error) {
|
|
1872
|
+
warnings.push(`Could not remove ${candidate}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
if (resolve(targetRoot) === resolve(defaultCodexPluginRoot())) {
|
|
1876
|
+
const configPath = codexConfigPath();
|
|
1877
|
+
try {
|
|
1878
|
+
if (await pathExists(configPath)) {
|
|
1879
|
+
const current = await readFile(configPath, "utf8");
|
|
1880
|
+
const updated = removeLegacyCodexConfigTables(current);
|
|
1881
|
+
if (updated.text !== current) {
|
|
1882
|
+
await writeFile(configPath, updated.text, "utf8");
|
|
1883
|
+
}
|
|
1884
|
+
removedConfigTables.push(...updated.removedTables);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
catch (error) {
|
|
1888
|
+
warnings.push(`Could not update ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
const removedHistoryEntries = await cleanupLegacyCodexHistoryMentions(warnings);
|
|
1892
|
+
return {
|
|
1893
|
+
legacy_removed_paths: Array.from(new Set(removedPaths)),
|
|
1894
|
+
legacy_removed_config_tables: removedConfigTables,
|
|
1895
|
+
legacy_removed_history_entries: removedHistoryEntries,
|
|
1896
|
+
...(warnings.length > 0 ? { warnings } : {})
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
async function discoverLegacyCodexCachePaths(targetRoot) {
|
|
1900
|
+
const paths = [];
|
|
1901
|
+
const cacheRoot = join(targetRoot, "cache");
|
|
1902
|
+
try {
|
|
1903
|
+
const marketplaces = await readdir(cacheRoot, { withFileTypes: true });
|
|
1904
|
+
for (const entry of marketplaces) {
|
|
1905
|
+
if (!entry.isDirectory())
|
|
1906
|
+
continue;
|
|
1907
|
+
paths.push(join(cacheRoot, entry.name, "dbt-agent"));
|
|
1908
|
+
paths.push(join(cacheRoot, entry.name, "development-board-toolchain"));
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
catch {
|
|
1912
|
+
return paths;
|
|
1913
|
+
}
|
|
1914
|
+
return paths;
|
|
1915
|
+
}
|
|
1916
|
+
async function cleanupLegacyCodexHistoryMentions(warnings) {
|
|
1917
|
+
const historyPath = join(defaultCodexHome(), "history.jsonl");
|
|
1918
|
+
try {
|
|
1919
|
+
if (!await pathExists(historyPath))
|
|
1920
|
+
return 0;
|
|
1921
|
+
const current = await readFile(historyPath, "utf8");
|
|
1922
|
+
const lines = current.split("\n");
|
|
1923
|
+
let removed = 0;
|
|
1924
|
+
const kept = lines.filter((line) => {
|
|
1925
|
+
if (!line)
|
|
1926
|
+
return true;
|
|
1927
|
+
if (isLegacyCodexHistoryMention(line)) {
|
|
1928
|
+
removed += 1;
|
|
1929
|
+
return false;
|
|
1930
|
+
}
|
|
1931
|
+
return true;
|
|
1932
|
+
});
|
|
1933
|
+
if (removed > 0) {
|
|
1934
|
+
await writeFile(historyPath, kept.join("\n"), "utf8");
|
|
1935
|
+
}
|
|
1936
|
+
return removed;
|
|
1937
|
+
}
|
|
1938
|
+
catch (error) {
|
|
1939
|
+
warnings.push(`Could not clean Codex legacy history mentions: ${error instanceof Error ? error.message : String(error)}`);
|
|
1940
|
+
return 0;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
function isLegacyCodexHistoryMention(line) {
|
|
1944
|
+
return line.includes("plugin://dbt-agent@plugins")
|
|
1945
|
+
|| line.includes("plugin://dbt-agent@embed-labs")
|
|
1946
|
+
|| /dbt-agent/i.test(line);
|
|
1947
|
+
}
|
|
1948
|
+
function removeLegacyCodexConfigTables(text) {
|
|
1949
|
+
const lines = text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
1950
|
+
const output = [];
|
|
1951
|
+
const removedTables = [];
|
|
1952
|
+
let skipping = false;
|
|
1953
|
+
for (const line of lines) {
|
|
1954
|
+
const table = parseTomlTableHeader(line);
|
|
1955
|
+
if (table) {
|
|
1956
|
+
skipping = isLegacyCodexConfigTable(table);
|
|
1957
|
+
if (skipping) {
|
|
1958
|
+
removedTables.push(table);
|
|
1959
|
+
continue;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
if (!skipping) {
|
|
1963
|
+
output.push(line);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return { text: output.join("").replace(/\n{3,}/g, "\n\n"), removedTables };
|
|
1967
|
+
}
|
|
1968
|
+
function parseTomlTableHeader(line) {
|
|
1969
|
+
const match = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/.exec(line);
|
|
1970
|
+
return match?.[1]?.trim();
|
|
1971
|
+
}
|
|
1972
|
+
function isLegacyCodexConfigTable(table) {
|
|
1973
|
+
return /^plugins\."dbt-agent@[^"]+"$/.test(table)
|
|
1974
|
+
|| table === "mcp_servers.dbt-agent"
|
|
1975
|
+
|| table.startsWith("mcp_servers.dbt-agent.")
|
|
1976
|
+
|| table === 'mcp_servers."dbt-agent"'
|
|
1977
|
+
|| table.startsWith('mcp_servers."dbt-agent".');
|
|
1978
|
+
}
|
|
1979
|
+
function legacyCodexCleanupWarning(cleanup) {
|
|
1980
|
+
const parts = [];
|
|
1981
|
+
if (cleanup.legacy_removed_paths.length > 0) {
|
|
1982
|
+
parts.push(`removed ${cleanup.legacy_removed_paths.length} legacy Codex plugin path(s)`);
|
|
1983
|
+
}
|
|
1984
|
+
if (cleanup.legacy_removed_config_tables?.length) {
|
|
1985
|
+
parts.push(`removed ${cleanup.legacy_removed_config_tables.length} legacy Codex config table(s)`);
|
|
1986
|
+
}
|
|
1987
|
+
if (cleanup.legacy_removed_history_entries) {
|
|
1988
|
+
parts.push(`removed ${cleanup.legacy_removed_history_entries} legacy Codex history mention(s)`);
|
|
1989
|
+
}
|
|
1990
|
+
if (cleanup.warnings?.length) {
|
|
1991
|
+
parts.push(`cleanup warning(s): ${cleanup.warnings.join("; ")}`);
|
|
1992
|
+
}
|
|
1993
|
+
return parts.length > 0 ? `Legacy dbt-agent cleanup: ${parts.join(", ")}.` : undefined;
|
|
1994
|
+
}
|
|
1995
|
+
async function cleanupLegacyOpenCodePluginRemnants(targetRoot, globalInstall) {
|
|
1996
|
+
const removedPaths = [];
|
|
1997
|
+
const warnings = [];
|
|
1998
|
+
const legacyPaths = [
|
|
1999
|
+
join(targetRoot, "plugins", "development-board-toolchain.js"),
|
|
2000
|
+
join(targetRoot, "plugins", "dbt-agent.js"),
|
|
2001
|
+
join(targetRoot, "node_modules", "dbt-agent")
|
|
2002
|
+
];
|
|
2003
|
+
if (globalInstall) {
|
|
2004
|
+
legacyPaths.push(join(targetRoot, "plugins", "embed-labs.js"));
|
|
2005
|
+
}
|
|
2006
|
+
for (const candidate of legacyPaths) {
|
|
2007
|
+
try {
|
|
2008
|
+
if (await pathExists(candidate)) {
|
|
2009
|
+
await rm(candidate, { recursive: true, force: true });
|
|
2010
|
+
removedPaths.push(candidate);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
catch (error) {
|
|
2014
|
+
warnings.push(`Could not remove ${candidate}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
return {
|
|
2018
|
+
legacy_removed_paths: removedPaths,
|
|
2019
|
+
legacy_removed_config_entries: [],
|
|
2020
|
+
...(warnings.length > 0 ? { warnings } : {})
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
function legacyOpenCodeCleanupWarning(cleanup) {
|
|
2024
|
+
const parts = [];
|
|
2025
|
+
if (cleanup.legacy_removed_paths.length > 0) {
|
|
2026
|
+
parts.push(`removed ${cleanup.legacy_removed_paths.length} legacy OpenCode plugin path(s)`);
|
|
2027
|
+
}
|
|
2028
|
+
if (cleanup.legacy_removed_config_entries?.length) {
|
|
2029
|
+
parts.push(`removed ${cleanup.legacy_removed_config_entries.length} legacy OpenCode config entry(s)`);
|
|
2030
|
+
}
|
|
2031
|
+
if (cleanup.warnings?.length) {
|
|
2032
|
+
parts.push(`cleanup warning(s): ${cleanup.warnings.join("; ")}`);
|
|
2033
|
+
}
|
|
2034
|
+
return parts.length > 0 ? `Legacy OpenCode cleanup: ${parts.join(", ")}.` : undefined;
|
|
2035
|
+
}
|
|
2036
|
+
function combineWarnings(...warnings) {
|
|
2037
|
+
const actual = warnings.filter((warning) => Boolean(warning));
|
|
2038
|
+
return actual.length > 0 ? actual.join(" ") : undefined;
|
|
1815
2039
|
}
|
|
1816
2040
|
async function maybeRegisterCodexMcp(parsed, targetRoot, targetPath) {
|
|
1817
2041
|
const explicitTarget = Boolean(stringFlag(parsed, "target") || stringFlag(parsed, "codex-target"));
|
|
@@ -1984,10 +2208,54 @@ async function resolveExecutableOnPath(name) {
|
|
|
1984
2208
|
return undefined;
|
|
1985
2209
|
}
|
|
1986
2210
|
function defaultOpenCodeRoot() {
|
|
1987
|
-
return
|
|
2211
|
+
return globalOpenCodeRoot();
|
|
2212
|
+
}
|
|
2213
|
+
function globalOpenCodeRoot() {
|
|
2214
|
+
return join(homedir(), ".config", "opencode");
|
|
2215
|
+
}
|
|
2216
|
+
function isGlobalOpenCodeRoot(targetRoot) {
|
|
2217
|
+
return resolve(targetRoot) === resolve(globalOpenCodeRoot());
|
|
2218
|
+
}
|
|
2219
|
+
async function ensureOpenCodeGlobalPluginConfig() {
|
|
2220
|
+
const configPath = join(globalOpenCodeRoot(), "opencode.json");
|
|
2221
|
+
let existing = {};
|
|
2222
|
+
try {
|
|
2223
|
+
const parsed = JSON.parse(await readFile(configPath, "utf8"));
|
|
2224
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2225
|
+
existing = parsed;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
catch {
|
|
2229
|
+
existing = {};
|
|
2230
|
+
}
|
|
2231
|
+
const configured = Array.isArray(existing.plugin)
|
|
2232
|
+
? existing.plugin.filter((item) => typeof item === "string")
|
|
2233
|
+
: Array.isArray(existing.plugins)
|
|
2234
|
+
? existing.plugins.filter((item) => typeof item === "string")
|
|
2235
|
+
: [];
|
|
2236
|
+
const removed = configured.filter(isLegacyOpenCodePluginConfigEntry);
|
|
2237
|
+
const cleaned = configured.filter((item) => !isLegacyOpenCodePluginConfigEntry(item));
|
|
2238
|
+
if (!cleaned.includes("embed-labs")) {
|
|
2239
|
+
cleaned.push("embed-labs");
|
|
2240
|
+
}
|
|
2241
|
+
await writeFile(configPath, `${JSON.stringify({
|
|
2242
|
+
...existing,
|
|
2243
|
+
plugin: cleaned,
|
|
2244
|
+
plugins: undefined
|
|
2245
|
+
}, null, 2)}\n`, "utf8");
|
|
2246
|
+
return removed;
|
|
2247
|
+
}
|
|
2248
|
+
function isLegacyOpenCodePluginConfigEntry(item) {
|
|
2249
|
+
const normalized = item.replace(/\\/g, "/");
|
|
2250
|
+
return item === "dbt-agent"
|
|
2251
|
+
|| item === "development-board-toolchain"
|
|
2252
|
+
|| normalized === "./plugins/development-board-toolchain"
|
|
2253
|
+
|| normalized === "./plugins/development-board-toolchain.js"
|
|
2254
|
+
|| normalized.endsWith("/plugins/development-board-toolchain.js")
|
|
2255
|
+
|| normalized.includes("development-board-toolchain");
|
|
1988
2256
|
}
|
|
1989
2257
|
async function openCodeDuplicatePluginWarning(targetRoot) {
|
|
1990
|
-
const globalRoot =
|
|
2258
|
+
const globalRoot = globalOpenCodeRoot();
|
|
1991
2259
|
if (resolve(targetRoot) === resolve(globalRoot))
|
|
1992
2260
|
return undefined;
|
|
1993
2261
|
const configPath = join(globalRoot, "opencode.json");
|
|
@@ -4164,7 +4432,7 @@ function localToolchainCurrentRequest(parsed) {
|
|
|
4164
4432
|
return { installRoot: installRoot.value };
|
|
4165
4433
|
}
|
|
4166
4434
|
function localToolchainInstallRequest(parsed) {
|
|
4167
|
-
const unknownFlag = firstUnknownFlag(parsed, ["json", "board", "board-id", "channel", "metadata-root", "source-url", "source-release-root", "install-root", "force"]);
|
|
4435
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "board", "board-id", "channel", "metadata-root", "source-url", "source-release-root", "install-root", "mode", "force"]);
|
|
4168
4436
|
if (unknownFlag) {
|
|
4169
4437
|
return `Unknown flag --${unknownFlag}. ${LOCAL_TOOLCHAIN_INSTALL_USAGE}`;
|
|
4170
4438
|
}
|
|
@@ -4193,6 +4461,9 @@ function localToolchainInstallRequest(parsed) {
|
|
|
4193
4461
|
const installRoot = optionalTrimmedStringFlag(parsed, "install-root");
|
|
4194
4462
|
if (installRoot.error)
|
|
4195
4463
|
return installRoot.error;
|
|
4464
|
+
const mode = optionalTrimmedStringFlag(parsed, "mode");
|
|
4465
|
+
if (mode.error)
|
|
4466
|
+
return mode.error;
|
|
4196
4467
|
return {
|
|
4197
4468
|
boardId: board.value,
|
|
4198
4469
|
channel: channel.value,
|
|
@@ -4200,11 +4471,12 @@ function localToolchainInstallRequest(parsed) {
|
|
|
4200
4471
|
sourceUrl: sourceUrl.value,
|
|
4201
4472
|
sourceReleaseRoot: sourceReleaseRoot.value,
|
|
4202
4473
|
installRoot: installRoot.value,
|
|
4474
|
+
mode: mode.value,
|
|
4203
4475
|
force: booleanFlag(parsed, "force")
|
|
4204
4476
|
};
|
|
4205
4477
|
}
|
|
4206
4478
|
function localToolchainValidateRequest(parsed) {
|
|
4207
|
-
const unknownFlag = firstUnknownFlag(parsed, ["json", "release-root"]);
|
|
4479
|
+
const unknownFlag = firstUnknownFlag(parsed, ["json", "release-root", "mode"]);
|
|
4208
4480
|
if (unknownFlag) {
|
|
4209
4481
|
return `Unknown flag --${unknownFlag}. ${LOCAL_TOOLCHAIN_VALIDATE_USAGE}`;
|
|
4210
4482
|
}
|
|
@@ -4216,7 +4488,11 @@ function localToolchainValidateRequest(parsed) {
|
|
|
4216
4488
|
if (releaseRoot.error) {
|
|
4217
4489
|
return releaseRoot.error;
|
|
4218
4490
|
}
|
|
4219
|
-
|
|
4491
|
+
const mode = optionalTrimmedStringFlag(parsed, "mode");
|
|
4492
|
+
if (mode.error) {
|
|
4493
|
+
return mode.error;
|
|
4494
|
+
}
|
|
4495
|
+
return { releaseRoot: releaseRoot.value, mode: mode.value };
|
|
4220
4496
|
}
|
|
4221
4497
|
function localCompileTaishanPiRequest(parsed, auth) {
|
|
4222
4498
|
const unknownFlag = firstUnknownFlag(parsed, ["json", "source", "output", "release-root", "account", "account-id"]);
|
|
@@ -5359,11 +5635,19 @@ function renderLocalToolchainLatest(result) {
|
|
|
5359
5635
|
`version=${result.version}`,
|
|
5360
5636
|
`host=${result.host}`,
|
|
5361
5637
|
result.metadata_root ? `metadata_root=${result.metadata_root}` : "metadata=built-in",
|
|
5362
|
-
result.download ? `download=${result.download.mirror_kind}:${result.download.source_url}` : "",
|
|
5363
|
-
result.download ? `archive_sha256=${result.download.archive.sha256}` : "",
|
|
5364
|
-
result.download ? `archive_size_bytes=${result.download.archive.size_bytes}` : "",
|
|
5638
|
+
result.download?.source_url ? `download=${result.download.mirror_kind}:${result.download.source_url}` : "",
|
|
5639
|
+
result.download?.archive ? `archive_sha256=${result.download.archive.sha256}` : "",
|
|
5640
|
+
result.download?.archive ? `archive_size_bytes=${result.download.archive.size_bytes}` : "",
|
|
5641
|
+
result.download?.components?.length ? `components=${result.download.components.length}` : "",
|
|
5642
|
+
result.download?.default_mode ? `default_mode=${result.download.default_mode}` : "",
|
|
5365
5643
|
result.download_error ? `download_error=${result.download_error}` : ""
|
|
5366
5644
|
].filter(Boolean);
|
|
5645
|
+
if (result.download?.components?.length) {
|
|
5646
|
+
lines.push("download_components:");
|
|
5647
|
+
for (const component of result.download.components) {
|
|
5648
|
+
lines.push(` ${component.id}@${component.version} modes=${component.install_modes?.join(",") || "all"} bytes=${component.archive.size_bytes}`);
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5367
5651
|
if (result.packages.length > 0) {
|
|
5368
5652
|
lines.push("packages:");
|
|
5369
5653
|
for (const pkg of result.packages) {
|
|
@@ -5386,6 +5670,7 @@ function renderLocalToolchainCurrent(result) {
|
|
|
5386
5670
|
`board=${result.board_id}`,
|
|
5387
5671
|
result.version ? `version=${result.version}` : "",
|
|
5388
5672
|
result.channel ? `channel=${result.channel}` : "",
|
|
5673
|
+
result.mode ? `mode=${result.mode}` : "",
|
|
5389
5674
|
result.release_root ? `release_root=${result.release_root}` : "",
|
|
5390
5675
|
`install_root=${result.install_root}`,
|
|
5391
5676
|
`registry=${result.registry_path}`
|
|
@@ -5398,13 +5683,21 @@ function renderLocalToolchainInstall(result) {
|
|
|
5398
5683
|
`version=${result.version}`,
|
|
5399
5684
|
`channel=${result.channel}`,
|
|
5400
5685
|
`host=${result.host}`,
|
|
5686
|
+
`mode=${result.mode}`,
|
|
5401
5687
|
`install_root=${result.install_root}`,
|
|
5402
5688
|
`release_root=${result.release_root}`,
|
|
5403
5689
|
`registry=${result.registry_path}`,
|
|
5404
5690
|
`source=${result.source.kind}:${result.source.value}`,
|
|
5405
5691
|
result.source.downloaded_path ? `downloaded=${result.source.downloaded_path}` : "",
|
|
5692
|
+
result.source.components?.length ? `components=${result.source.components.length}` : "",
|
|
5406
5693
|
`validation=${result.validation.ok ? "ok" : "failed"}`
|
|
5407
5694
|
].filter(Boolean);
|
|
5695
|
+
if (result.source.components?.length) {
|
|
5696
|
+
lines.push("installed_components:");
|
|
5697
|
+
for (const component of result.source.components) {
|
|
5698
|
+
lines.push(` ${component.id}@${component.version} ${component.mirror_kind || ""} bytes=${component.size_bytes}`);
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5408
5701
|
if (result.installed_paths.length > 0) {
|
|
5409
5702
|
lines.push("installed_paths:");
|
|
5410
5703
|
for (const installedPath of result.installed_paths) {
|
|
@@ -5423,6 +5716,7 @@ function renderLocalToolchainValidation(result) {
|
|
|
5423
5716
|
const lines = [
|
|
5424
5717
|
result.ok ? "Local toolchain ready." : "Local toolchain not ready.",
|
|
5425
5718
|
`board=${result.board_id}`,
|
|
5719
|
+
`mode=${result.mode}`,
|
|
5426
5720
|
`host=${result.host.platform}/${result.host.arch}`,
|
|
5427
5721
|
`release_root=${result.release_root}`
|
|
5428
5722
|
];
|
|
@@ -6450,9 +6744,9 @@ Usage:
|
|
|
6450
6744
|
embed image boot-logo compose --package <boot-logo-package.json> --base-image <boot.img|image.img> --output <image> [--manifest <manifest.json>] [--force] [--json]
|
|
6451
6745
|
embed local toolchain latest [--board taishanpi-1m-rk3566] [--channel stable] [--metadata-root <path>] [--json]
|
|
6452
6746
|
embed local toolchain current [--install-root <path>] [--json]
|
|
6453
|
-
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]
|
|
6747
|
+
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>] [--mode minimal|compile|qt|full|images] [--force] [--json]
|
|
6454
6748
|
Defaults to the production download channel at download.embedboard.com.
|
|
6455
|
-
embed local toolchain validate [--release-root <path>] [--json]
|
|
6749
|
+
embed local toolchain validate [--release-root <path>] [--mode minimal|compile|qt|full|images] [--json]
|
|
6456
6750
|
embed local compile taishanpi --source <main.c|main.cpp> --output <artifact> [--release-root <path>] [--account <account_id>] [--json]
|
|
6457
6751
|
embed local build qt-smoke --build-dir <dir> [--source <qt-smoke-dir>] [--release-root <path>] [--account <account_id>] [--json]
|
|
6458
6752
|
embed debug tools [--json]
|