@dp-bohrium/widget-cli 0.4.0 → 0.5.1
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/AGENTS.md +32 -30
- package/CHANGELOG.md +33 -0
- package/README.md +4 -21
- package/assets/schemas/widget-runtime-contracts.schema.json +7 -3
- package/assets/toolchain.json +13 -9
- package/dist/cli.mjs +194 -114
- package/dist/core.d.mts +869 -0
- package/dist/core.mjs +1 -1
- package/{src → dist}/development-host.d.mts +18 -35
- package/dist/{dsh-BvnlfCRX.mjs → dsh-BlpXm2Bv.mjs} +10066 -10233
- package/llms.txt +16 -14
- package/package.json +14 -18
- package/assets/licenses/widget-contracts.LICENSE +0 -21
- package/src/core.d.mts +0 -58
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as normalizeArchivePath, c as
|
|
3
|
-
import { createRequire } from "node:module";
|
|
2
|
+
import { a as normalizeArchivePath, c as compileAuthorManifest, i as prepareWidgetPackage, n as scaffoldDshWidget, o as checkWidgetProject, s as resolveWidgetProjects, t as auditDshPlugin } from "./dsh-BlpXm2Bv.mjs";
|
|
4
3
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
5
4
|
import { constants, existsSync, lstatSync, readFileSync, readdirSync, realpathSync, statSync, watch } from "node:fs";
|
|
6
5
|
import { chmod, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
@@ -8,6 +7,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "nod
|
|
|
8
7
|
import { fileURLToPath } from "node:url";
|
|
9
8
|
import { spawn, spawnSync } from "node:child_process";
|
|
10
9
|
import { createServer } from "node:http";
|
|
10
|
+
import { isDeepStrictEqual } from "node:util";
|
|
11
11
|
//#region ../../scripts/widget/widget-dev.mjs
|
|
12
12
|
const repoRoot = resolve(fileURLToPath(new URL("../..", import.meta.url)));
|
|
13
13
|
const DEFAULT_PORT = 4300;
|
|
@@ -57,7 +57,6 @@ const RESOURCE_BUDGET = {
|
|
|
57
57
|
},
|
|
58
58
|
files: {
|
|
59
59
|
readBytesPerRequest: 4194304,
|
|
60
|
-
readBytesPerRun: 16777216,
|
|
61
60
|
callsPerMinute: 120,
|
|
62
61
|
listPageSize: 100
|
|
63
62
|
},
|
|
@@ -286,7 +285,6 @@ function requestedGrants(requested = {}) {
|
|
|
286
285
|
name: "files.read",
|
|
287
286
|
limits: {
|
|
288
287
|
bytesPerRequest: 4194304,
|
|
289
|
-
bytesPerRun: 16777216,
|
|
290
288
|
callsPerMinute: 120
|
|
291
289
|
}
|
|
292
290
|
});
|
|
@@ -384,7 +382,7 @@ function panelDevelopmentDescriptor(generation, profileUrl, statusUrl) {
|
|
|
384
382
|
widgetId,
|
|
385
383
|
widgetVersionId,
|
|
386
384
|
snapshot: {
|
|
387
|
-
id,
|
|
385
|
+
panelType: id,
|
|
388
386
|
title: generation.manifest.name,
|
|
389
387
|
state: "complete",
|
|
390
388
|
data: {}
|
|
@@ -1271,13 +1269,14 @@ function commandTopics(context) {
|
|
|
1271
1269
|
options: [
|
|
1272
1270
|
"--template <模板> panel 或 file-preview(默认 panel)",
|
|
1273
1271
|
"--ui <模式> vanilla 或 react(默认 vanilla)",
|
|
1274
|
-
"--panel-id <id>
|
|
1272
|
+
"--panel-id <id> 自定义面板标识,仅用于 panel;默认取规范化后的工程名",
|
|
1275
1273
|
"--extensions <列表> 仅用于 file-preview;逗号分隔扩展名(默认 txt)",
|
|
1276
1274
|
"--tool <名称> 按指定工具成功结果激活,不注册工具卡片",
|
|
1277
1275
|
HOST_OPTION,
|
|
1278
1276
|
JSON_OPTION
|
|
1279
1277
|
],
|
|
1280
1278
|
examples: [
|
|
1279
|
+
"bohr-widget create my-widget --ui react --panel-id my-widget",
|
|
1281
1280
|
"bohr-widget create workspace-browser --ui react --panel-id workspace-files",
|
|
1282
1281
|
"bohr-widget create text-preview --template file-preview --extensions txt,csv --ui vanilla --json",
|
|
1283
1282
|
"bohr-widget create search-panel --tool ScholarSearch --json"
|
|
@@ -1285,8 +1284,9 @@ function commandTopics(context) {
|
|
|
1285
1284
|
notes: [
|
|
1286
1285
|
`默认组合为 panel + vanilla;生成工程的构建环境要求 Node.js ${context.generatedProjectNode}。`,
|
|
1287
1286
|
"不会自动安装依赖;创建后进入目录,运行 pnpm install 或 npm install。",
|
|
1288
|
-
"
|
|
1289
|
-
"
|
|
1287
|
+
"Panel ID 可自定义,用于工作台识别面板;打包后按目标工作台的安装流程加载。",
|
|
1288
|
+
"workspace-files 是可选的文件浏览面板预设,会补齐 files.list、files.metadata、files.read 和目录引用样例;文件树界面与逻辑需自行实现。",
|
|
1289
|
+
"生成 README.md 和 AGENTS.md;先读取项目指引与公开文档,再安装依赖和执行工程命令。",
|
|
1290
1290
|
"将 widget-toolchain.json 与包管理器 lockfile 一起保存。"
|
|
1291
1291
|
],
|
|
1292
1292
|
quickStart: true
|
|
@@ -1382,7 +1382,7 @@ function commandTopics(context) {
|
|
|
1382
1382
|
notes: [
|
|
1383
1383
|
"不传 --project 时只发现 CLI 自带工具链,不检查当前目录是否为 Widget 工程。",
|
|
1384
1384
|
"传入工程时要求工具链锁;尚未安装依赖时先核对声明,已安装时同时核对实际版本。",
|
|
1385
|
-
"JSON 使用 interfaceVersion=
|
|
1385
|
+
"JSON 使用 interfaceVersion=3、toolchain.formatVersion=3;返回 execution、profile、requirements 和 documentation。",
|
|
1386
1386
|
"调用方应使用 execution.executable 与 execution.entry 启动同一份 CLI,避免 PATH 指向另一版本。",
|
|
1387
1387
|
"宿主声明由调用方提供;unknown、snapshot、confirmed 不代表上传或发布许可。"
|
|
1388
1388
|
],
|
|
@@ -1395,7 +1395,7 @@ function commandTopics(context) {
|
|
|
1395
1395
|
options: [HOST_OPTION, JSON_OPTION],
|
|
1396
1396
|
examples: ["bohr-widget adopt ./existing-widget --json", "bohr-widget adopt . --host-compat ./host.json --json"],
|
|
1397
1397
|
notes: [
|
|
1398
|
-
"先运行 doctor,恢复当前 profile 的精确 SDK
|
|
1398
|
+
"先运行 doctor,恢复当前 profile 的精确 SDK 依赖并安装。",
|
|
1399
1399
|
"核对实际依赖、Manifest 和 samples 后才写锁;不要求已构建入口。",
|
|
1400
1400
|
"不会自动升级依赖、迁移源码或修正协议字段;检查不通过时先修复工程。"
|
|
1401
1401
|
]
|
|
@@ -1412,7 +1412,7 @@ function commandTopics(context) {
|
|
|
1412
1412
|
]
|
|
1413
1413
|
},
|
|
1414
1414
|
version: {
|
|
1415
|
-
description: "查看当前
|
|
1415
|
+
description: "查看当前 SDK 执行器及内置协议摘要。",
|
|
1416
1416
|
usage: ["bohr-widget version [--json]", "bohr-widget --version [--json]"],
|
|
1417
1417
|
options: [JSON_OPTION],
|
|
1418
1418
|
examples: ["bohr-widget version --json", "bohr-widget -v"],
|
|
@@ -1483,9 +1483,9 @@ function section(title, lines) {
|
|
|
1483
1483
|
return lines.length ? `\n${title}:\n${lines.map((line) => ` ${line}`).join("\n")}\n` : "";
|
|
1484
1484
|
}
|
|
1485
1485
|
function globalHelp(context) {
|
|
1486
|
-
const { cli, sdk,
|
|
1486
|
+
const { cli, sdk, packageName = "@dp-bohrium/widget-cli", generatedProjectNode, documentation } = context;
|
|
1487
1487
|
return `bohr-widget ${cli} — Bohrium Widget 插件工程工具
|
|
1488
|
-
SDK ${sdk}
|
|
1488
|
+
SDK ${sdk}(协议与执行工具链均由 SDK 内置)
|
|
1489
1489
|
创建、校验、构建、开发调试与打包;上传、发布和 Agent 绑定由 Bohr CLI 或平台执行。
|
|
1490
1490
|
|
|
1491
1491
|
用法:
|
|
@@ -1505,7 +1505,7 @@ SDK ${sdk} / contracts ${contracts}
|
|
|
1505
1505
|
schema 打印作者 Manifest Schema 的本地路径
|
|
1506
1506
|
migrate project plan|apply 比较 Agent 准备的候选并安全复制到新目录
|
|
1507
1507
|
migrate dsh audit|scaffold 审计 DSH 来源或按已审查配方生成工程
|
|
1508
|
-
version 查看
|
|
1508
|
+
version 查看 SDK 执行器与内置协议版本
|
|
1509
1509
|
help [命令...] 查看全局或指定主题帮助
|
|
1510
1510
|
|
|
1511
1511
|
全局选项:
|
|
@@ -1521,7 +1521,7 @@ SDK ${sdk} / contracts ${contracts}
|
|
|
1521
1521
|
CLI 要求 Node.js >=20;默认生成工程要求 Node.js ${generatedProjectNode}。
|
|
1522
1522
|
|
|
1523
1523
|
典型开发流程:
|
|
1524
|
-
pnpm dlx ${packageName} create my-widget --
|
|
1524
|
+
pnpm dlx ${packageName} create my-widget --template panel --ui react
|
|
1525
1525
|
cd my-widget
|
|
1526
1526
|
pnpm install
|
|
1527
1527
|
pnpm exec bohr-widget build .
|
|
@@ -1556,7 +1556,7 @@ function renderHelp(path = [], context) {
|
|
|
1556
1556
|
/**
|
|
1557
1557
|
* 作者清单(VS Code 风格 `contributes` 清单)的本地静态检查。
|
|
1558
1558
|
*
|
|
1559
|
-
*
|
|
1559
|
+
* SDK 的 host schema 只在 `compileAuthorManifest` 之后生效,
|
|
1560
1560
|
* 而编译只保留宿主运行时需要的字段:作者的 `version`、`displayName` 和未知顶层键会被
|
|
1561
1561
|
* 静默丢弃,于是"清单写错但 check 全绿"。这里只补下游永远看不到的作者侧约束,报错文案
|
|
1562
1562
|
* 直接指向作者填的字段名。
|
|
@@ -1645,10 +1645,7 @@ function lintAuthorManifest(manifest, options = {}) {
|
|
|
1645
1645
|
//#region src/project-executor.mjs
|
|
1646
1646
|
const PROJECT_TOOLCHAIN_FILE = "widget-toolchain.json";
|
|
1647
1647
|
const BUILD_RECEIPT_FILE = ".widget-build-receipt.json";
|
|
1648
|
-
const PACKAGES = Object.freeze({
|
|
1649
|
-
sdk: "@dp-bohrium/widget-sdk",
|
|
1650
|
-
contracts: "@dp-bohrium/widget-contracts"
|
|
1651
|
-
});
|
|
1648
|
+
const PACKAGES = Object.freeze({ sdk: "@dp-bohrium/widget-sdk" });
|
|
1652
1649
|
const EXACT_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
|
|
1653
1650
|
function failure(code, message, context, recovery) {
|
|
1654
1651
|
return Object.assign(new Error(message), {
|
|
@@ -1722,12 +1719,12 @@ async function assertHostCompatibility(hostCompatPath, toolchain, { now = Date.n
|
|
|
1722
1719
|
}
|
|
1723
1720
|
function assertMatchingLock(lock, toolchain, root) {
|
|
1724
1721
|
const { profile } = toolchain;
|
|
1725
|
-
if (!record$1(lock) || lock.formatVersion !==
|
|
1722
|
+
if (!record$1(lock) || lock.formatVersion !== 2 || lock.profileId !== profile.id) throw failure("PROJECT_PROFILE_MISMATCH", "工程锁定格式或 profile 与当前 SDK 不一致;旧工程需准备当前源码候选后迁移,不能复用历史执行器", {
|
|
1726
1723
|
projectRoot: root,
|
|
1727
1724
|
expectedProfile: profile.id,
|
|
1728
1725
|
actualProfile: lock?.profileId
|
|
1729
1726
|
}, ["使用当前受支持的 CLI,并在新目录显式迁移工程与验收;不要回选旧 CLI 绕过 profile 差异。"]);
|
|
1730
|
-
if (lock.sdk !== profile.sdk || lock.
|
|
1727
|
+
if (lock.sdk !== profile.sdk || !isDeepStrictEqual(lock.protocol, toolchain.protocol)) throw failure("PROJECT_SDK_MISMATCH", "工程锁定的 SDK 或内置协议与当前 profile 不一致", {
|
|
1731
1728
|
projectRoot: root,
|
|
1732
1729
|
expected: profile,
|
|
1733
1730
|
actual: lock
|
|
@@ -1766,39 +1763,58 @@ function assertInstalledPackage(actual, name, expected, root) {
|
|
|
1766
1763
|
installed: actual?.version
|
|
1767
1764
|
}, ["按工程锁定信息恢复依赖并重新安装,再重新构建。"]);
|
|
1768
1765
|
}
|
|
1769
|
-
/**
|
|
1770
|
-
async function
|
|
1771
|
-
const
|
|
1772
|
-
const
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1766
|
+
/** 名称和字节同时参与摘要;禁止通过协议资产链接借用其他安装。 */
|
|
1767
|
+
async function schemaDigest(directory) {
|
|
1768
|
+
const hash = createHash("sha256");
|
|
1769
|
+
const paths = [];
|
|
1770
|
+
async function visit(path) {
|
|
1771
|
+
const entry = await lstat(path);
|
|
1772
|
+
if (entry.isSymbolicLink()) throw new Error("SDK 协议资产不允许符号链接");
|
|
1773
|
+
if (entry.isDirectory()) for (const name of (await readdir(path)).sort()) await visit(join(path, name));
|
|
1774
|
+
else if (entry.isFile()) paths.push(path);
|
|
1775
|
+
else throw new Error("SDK 协议资产必须是普通文件");
|
|
1776
|
+
}
|
|
1777
|
+
await visit(directory);
|
|
1778
|
+
if (!paths.length) throw new Error("SDK 协议资产为空");
|
|
1779
|
+
for (const path of paths.sort()) {
|
|
1780
|
+
const bytes = await readFile(path);
|
|
1781
|
+
hash.update(relative(directory, path).split(sep).join("/"));
|
|
1782
|
+
hash.update("\0");
|
|
1783
|
+
hash.update(String(bytes.length));
|
|
1784
|
+
hash.update("\0");
|
|
1785
|
+
hash.update(bytes);
|
|
1777
1786
|
}
|
|
1787
|
+
return `sha256:${hash.digest("hex")}`;
|
|
1788
|
+
}
|
|
1789
|
+
async function assertEmbeddedProtocol(sdkPath, toolchain, root) {
|
|
1790
|
+
const sdkRoot = dirname(await realpath(sdkPath));
|
|
1778
1791
|
try {
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
try {
|
|
1783
|
-
if (await realpath(join(lookup, PACKAGES.contracts, "package.json")) === resolvedPath) return await json(resolvedPath, "PROJECT_SDK_MISMATCH", ["重新安装工程 SDK 及其配套 contracts 依赖。"]);
|
|
1784
|
-
} catch (error) {
|
|
1785
|
-
if (error.code !== "ENOENT") throw error;
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1792
|
+
const embedded = JSON.parse(await readFile(join(sdkRoot, "assets/toolchain.json"), "utf8"));
|
|
1793
|
+
if (embedded.formatVersion !== 3 || embedded.packageName !== PACKAGES.sdk || embedded.cli !== toolchain.profile.sdk || !isDeepStrictEqual(embedded.profile, toolchain.profile) || !isDeepStrictEqual(embedded.protocol, toolchain.protocol) || !isDeepStrictEqual(embedded.digests, toolchain.digests) || embedded.protocol?.schemaVersion !== 1 || embedded.protocol?.hostApiVersion !== 1 || embedded.protocol?.digest !== embedded.digests?.schemas) throw new Error("SDK 内置协议或执行工具链元数据与当前执行器不一致");
|
|
1794
|
+
for (const directory of ["schemas", "assets/schemas"]) if (await schemaDigest(join(sdkRoot, directory)) !== embedded.protocol.digest) throw new Error("SDK 内置协议资产已漂移");
|
|
1788
1795
|
} catch (error) {
|
|
1789
|
-
|
|
1796
|
+
throw failure("PROJECT_SDK_MISMATCH", "工程 SDK 缺少有效的自包含协议资产或摘要不一致", {
|
|
1797
|
+
projectRoot: root,
|
|
1798
|
+
package: PACKAGES.sdk,
|
|
1799
|
+
cause: error.message
|
|
1800
|
+
}, ["在当前工程安装正确的 SDK 完整包,再重新构建;不能借用祖先目录或旧 contracts 包。"]);
|
|
1790
1801
|
}
|
|
1791
|
-
throw failure("PROJECT_SDK_MISMATCH", "工程 SDK 缺少自身可解析的配套 contracts,不能借用祖先目录或 CLI 的依赖", {
|
|
1792
|
-
projectRoot: root,
|
|
1793
|
-
package: PACKAGES.contracts
|
|
1794
|
-
}, ["在该 Widget 工程目录重新安装依赖,并保留 SDK 自身的传递依赖。"]);
|
|
1795
1802
|
}
|
|
1796
|
-
/** SDK
|
|
1803
|
+
/** SDK 必须由工程直接安装;协议只能来自该 SDK 自己的冻结资产。 */
|
|
1797
1804
|
async function validateProjectToolchain(projectRoot, toolchain, { requireInstalled = true, requireLock = true } = {}) {
|
|
1798
1805
|
const root = resolve(projectRoot);
|
|
1799
1806
|
const lock = await readLock(root, toolchain, requireLock);
|
|
1800
1807
|
const pkg = await json(join(root, "package.json"), "PROJECT_SDK_MISMATCH", ["恢复工程 package.json 中的精确 SDK 依赖。"]);
|
|
1801
1808
|
if (!record$1(pkg)) throw failure("PROJECT_SDK_MISMATCH", "工程 package.json 必须是对象", { projectRoot: root }, ["恢复工程 package.json 中的精确 SDK 依赖。"]);
|
|
1809
|
+
for (const section of [
|
|
1810
|
+
"dependencies",
|
|
1811
|
+
"devDependencies",
|
|
1812
|
+
"optionalDependencies",
|
|
1813
|
+
"peerDependencies"
|
|
1814
|
+
]) for (const name of ["@dp-bohrium/widget-contracts", "@dp-bohrium/widget-cli"]) if (pkg[section]?.[name] !== void 0) throw failure("PROJECT_SDK_MISMATCH", "作者工程仍直接声明 contracts 或 CLI,需统一使用 SDK 入口", {
|
|
1815
|
+
projectRoot: root,
|
|
1816
|
+
package: name
|
|
1817
|
+
}, ["作者工程统一依赖 SDK;协议从 SDK 的 /contracts 与 /schemas 出口读取。保留作者源码,在独立候选中移除重复依赖、重新安装和构建。"]);
|
|
1802
1818
|
const declared = {};
|
|
1803
1819
|
const installed = {};
|
|
1804
1820
|
for (const [key, name] of Object.entries(PACKAGES)) {
|
|
@@ -1821,53 +1837,22 @@ async function validateProjectToolchain(projectRoot, toolchain, { requireInstall
|
|
|
1821
1837
|
const actual = await json(path, "PROJECT_SDK_MISMATCH", ["在该 Widget 工程目录安装依赖,再重试;父目录或 CLI 的安装不能替代工程安装。"]);
|
|
1822
1838
|
assertInstalledPackage(actual, name, expected, root);
|
|
1823
1839
|
installed[key] = actual.version;
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
assertInstalledPackage(contracts, PACKAGES.contracts, toolchain.profile.contracts, root);
|
|
1834
|
-
installed.contracts = contracts.version;
|
|
1835
|
-
}
|
|
1840
|
+
for (const name of ["@dp-bohrium/widget-contracts", "@dp-bohrium/widget-cli"]) if ([
|
|
1841
|
+
"dependencies",
|
|
1842
|
+
"optionalDependencies",
|
|
1843
|
+
"peerDependencies"
|
|
1844
|
+
].some((section) => actual[section]?.[name] !== void 0)) throw failure("PROJECT_SDK_MISMATCH", "工程 SDK 仍包含独立协议或 CLI 运行依赖,不符合当前自包含发布契约", {
|
|
1845
|
+
projectRoot: root,
|
|
1846
|
+
package: name
|
|
1847
|
+
}, ["安装当前自包含 SDK 包,再重新构建。"]);
|
|
1848
|
+
await assertEmbeddedProtocol(path, toolchain, root);
|
|
1836
1849
|
}
|
|
1837
1850
|
return {
|
|
1838
1851
|
projectRoot: root,
|
|
1839
1852
|
profile: { ...toolchain.profile },
|
|
1840
1853
|
declared,
|
|
1841
1854
|
installed,
|
|
1842
|
-
deprecations:
|
|
1843
|
-
code: "WIDGET_CLI_DIRECT_CONTRACTS_DEPRECATED",
|
|
1844
|
-
message: "独立消费者直接声明 contracts 的旧入口已废弃,将在统一入口切换发布 R1 前移除;协议类型与资产改从 SDK 导入。",
|
|
1845
|
-
replacement: {
|
|
1846
|
-
package: PACKAGES.sdk,
|
|
1847
|
-
entryPoints: [
|
|
1848
|
-
".",
|
|
1849
|
-
"./contracts",
|
|
1850
|
-
"./schemas/*.json",
|
|
1851
|
-
"./conformance/*"
|
|
1852
|
-
]
|
|
1853
|
-
},
|
|
1854
|
-
removal: {
|
|
1855
|
-
release: "R1",
|
|
1856
|
-
phase: "before-publish",
|
|
1857
|
-
policyDocument: "docs/plans/2026-10-29-widget-sdk-forge-unified-entry.md",
|
|
1858
|
-
prerequisites: [
|
|
1859
|
-
"unified-sdk-entries-deliverable",
|
|
1860
|
-
"agent-guided-project-migration-ready",
|
|
1861
|
-
"bohr-and-hosts-upgraded"
|
|
1862
|
-
]
|
|
1863
|
-
},
|
|
1864
|
-
migration: {
|
|
1865
|
-
status: "agent-guided",
|
|
1866
|
-
project: "migrate project plan/apply",
|
|
1867
|
-
candidateRequired: true
|
|
1868
|
-
},
|
|
1869
|
-
recovery: ["先核实目标 SDK 的统一出口已公开,再迁移类型和 Schema 导入、删除工程直接 contracts 依赖,并重新安装、构建、校验和打包。", "由 Agent 或开发者依据当前 SDK 准备候选,再用 migrate project plan --candidate 只读审阅差异,确认 canApply 后在新目录 apply;不自动改写源码或依赖,adopt 只补锁。"]
|
|
1870
|
-
}] : [],
|
|
1855
|
+
deprecations: [],
|
|
1871
1856
|
dependenciesVerified: requireInstalled,
|
|
1872
1857
|
lock
|
|
1873
1858
|
};
|
|
@@ -1877,10 +1862,10 @@ async function writeProjectToolchain(projectRoot, toolchain) {
|
|
|
1877
1862
|
const existing = await readLock(root, toolchain, false);
|
|
1878
1863
|
if (existing) return existing;
|
|
1879
1864
|
const value = {
|
|
1880
|
-
formatVersion:
|
|
1865
|
+
formatVersion: 2,
|
|
1881
1866
|
profileId: toolchain.profile.id,
|
|
1882
1867
|
sdk: toolchain.profile.sdk,
|
|
1883
|
-
|
|
1868
|
+
protocol: toolchain.protocol,
|
|
1884
1869
|
createdWithCli: toolchain.cli
|
|
1885
1870
|
};
|
|
1886
1871
|
await mkdir(root, { recursive: true });
|
|
@@ -1921,6 +1906,7 @@ function receiptToolchain(toolchain) {
|
|
|
1921
1906
|
return {
|
|
1922
1907
|
cli: toolchain.cli,
|
|
1923
1908
|
profile: toolchain.profile,
|
|
1909
|
+
protocol: toolchain.protocol,
|
|
1924
1910
|
digests: toolchain.digests
|
|
1925
1911
|
};
|
|
1926
1912
|
}
|
|
@@ -1965,7 +1951,7 @@ async function writeBuildReceipt(projectRoot, toolchain, { inputsBefore } = {})
|
|
|
1965
1951
|
const outputs = await fingerprint(result.projectRoot, { outputs: true });
|
|
1966
1952
|
if (outputs.files.length === 0) throw failure("BUILD_RECEIPT_MISMATCH", "构建目录 dist 没有可记录的产物", { projectRoot: result.projectRoot }, ["执行标准 build,确认 dist 产物存在后再打包。"]);
|
|
1967
1953
|
const receipt = {
|
|
1968
|
-
formatVersion:
|
|
1954
|
+
formatVersion: 2,
|
|
1969
1955
|
toolchain: receiptToolchain(toolchain),
|
|
1970
1956
|
dependencies: result.installed,
|
|
1971
1957
|
inputs,
|
|
@@ -1984,7 +1970,7 @@ async function assertBuildReceipt(projectRoot, toolchain) {
|
|
|
1984
1970
|
};
|
|
1985
1971
|
const receipt = await json(join(root, BUILD_RECEIPT_FILE), "BUILD_RECEIPT_MISMATCH", ["先执行 bohr-widget build,或去掉 pack 的 --no-build。"]);
|
|
1986
1972
|
const project = await validateProjectToolchain(root, toolchain);
|
|
1987
|
-
if (!record$1(receipt) || receipt.formatVersion !==
|
|
1973
|
+
if (!record$1(receipt) || receipt.formatVersion !== 2 || JSON.stringify(receipt.toolchain) !== JSON.stringify(receiptToolchain(toolchain)) || JSON.stringify(receipt.dependencies) !== JSON.stringify(project.installed)) mismatch("receipt 工具链或实际依赖与本次执行不一致");
|
|
1988
1974
|
let inputs;
|
|
1989
1975
|
let outputs;
|
|
1990
1976
|
try {
|
|
@@ -2429,11 +2415,35 @@ function projectPackage({ name, ui, sdkVersion }) {
|
|
|
2429
2415
|
}
|
|
2430
2416
|
};
|
|
2431
2417
|
}
|
|
2432
|
-
function
|
|
2418
|
+
function projectAgentGuide({ sdkVersion, sourceFile, hostFile, documentation, agentSetupUrl }) {
|
|
2419
|
+
return `# 项目开发指引
|
|
2420
|
+
|
|
2421
|
+
创建时 SDK:\`@dp-bohrium/widget-sdk@${sdkVersion}\`。
|
|
2422
|
+
|
|
2423
|
+
以下路径均相对于本工程根目录:
|
|
2424
|
+
|
|
2425
|
+
- \`${sourceFile}\`:本工程的 Widget 界面与业务逻辑,通常在这里修改功能。
|
|
2426
|
+
- \`${hostFile}\`:本工程的启动文件,调用 SDK 的 \`runWidgetHost\` 启动 Widget。
|
|
2427
|
+
- \`manifest.json\`:本工程的 Widget 声明。
|
|
2428
|
+
- \`samples/default.json\`:本工程的样例输入。
|
|
2429
|
+
|
|
2430
|
+
本工程的依赖版本与工具链记录在 \`package.json\`、\`widget-toolchain.json\` 和包管理器 lockfile 中。
|
|
2431
|
+
|
|
2432
|
+
阅读入口:
|
|
2433
|
+
|
|
2434
|
+
- [README.md](./README.md):本工程的环境、安装、命令和验收说明。
|
|
2435
|
+
- [开发 Agent 引导](${agentSetupUrl}):通用的能力选型与开发阅读路径。
|
|
2436
|
+
- [文档索引](${documentation.llms}):按当前任务查找指南、API 和示例。
|
|
2437
|
+
`;
|
|
2438
|
+
}
|
|
2439
|
+
function projectReadme({ name, template, ui, sourceFile, hostFile, sdkVersion, documentation, agentSetupUrl }) {
|
|
2433
2440
|
return `# ${name}
|
|
2434
2441
|
|
|
2435
2442
|
Bohrium Widget ${template} 插件工程(${ui})。
|
|
2436
2443
|
|
|
2444
|
+
创建时 SDK:\`@dp-bohrium/widget-sdk@${sdkVersion}\`。项目上下文与 Agent 阅读入口见 [AGENTS.md](./AGENTS.md);安装依赖前即可读取[开发 Agent 引导](${agentSetupUrl})、[文档索引](${documentation.llms})和[快速开始](${documentation.quickStart})。
|
|
2445
|
+
文档独立更新;接口以本工程固定 SDK 和目标 Host 实际支持为准。
|
|
2446
|
+
|
|
2437
2447
|
默认构建器要求 Node.js \`${GENERATED_PROJECT_NODE}\`,高于执行器自身的 Node.js 20 要求。
|
|
2438
2448
|
工程已经精确依赖提供命令的 \`${PROJECT_EXECUTOR_PACKAGE}\`;在本目录安装后使用本地命令,无需全局安装或源码仓库。
|
|
2439
2449
|
|
|
@@ -2447,7 +2457,7 @@ pnpm run widget:pack --json
|
|
|
2447
2457
|
使用 npm 时,安装后可执行 \`npm run build\`、\`npm run check\`、\`npm run widget:pack\`;需要构建 receipt 时执行 \`npx --no-install bohr-widget build .\`。
|
|
2448
2458
|
Widget ZIP 使用 \`pnpm run widget:pack\` 或 \`npm run widget:pack\`;\`pnpm pack\` 是制作 npm \`.tgz\` 包的内置命令。
|
|
2449
2459
|
|
|
2450
|
-
-
|
|
2460
|
+
- Widget 界面与业务逻辑在 ${sourceFile} 中;本工程的 ${hostFile} 调用 SDK 的 runWidgetHost 启动 Widget。
|
|
2451
2461
|
- 高度链、布局与滚动策略直接写在 ${sourceFile} 中,样式随 activate 安装并在释放时清理;JSON 展示元素单独处理换行。
|
|
2452
2462
|
- manifest.json 是作者清单,打包时由 CLI 编译为宿主清单。
|
|
2453
2463
|
- 提交 widget-toolchain.json 与依赖 lockfile;dist/widget.js 与生成的 ZIP 不提交。
|
|
@@ -2635,7 +2645,6 @@ export { activate };
|
|
|
2635
2645
|
name: "files.read",
|
|
2636
2646
|
limits: {
|
|
2637
2647
|
bytesPerRequest: 65536,
|
|
2638
|
-
bytesPerRun: 262144,
|
|
2639
2648
|
callsPerMinute: 60
|
|
2640
2649
|
}
|
|
2641
2650
|
}
|
|
@@ -2758,12 +2767,11 @@ function getSchemaPath(name = "widget-manifest.schema.json") {
|
|
|
2758
2767
|
const toolchain = getToolchain();
|
|
2759
2768
|
const packageJson = { version: toolchain.cli };
|
|
2760
2769
|
const sdkPackage = { version: toolchain.profile.sdk };
|
|
2761
|
-
const contractsPackage = { version: toolchain.profile.contracts };
|
|
2762
2770
|
function usage(path = []) {
|
|
2763
2771
|
return renderHelp(path, {
|
|
2764
2772
|
cli: packageJson.version,
|
|
2765
2773
|
sdk: sdkPackage.version,
|
|
2766
|
-
|
|
2774
|
+
protocol: toolchain.protocol,
|
|
2767
2775
|
packageName: toolchain.packageName,
|
|
2768
2776
|
documentation: getDocumentation(),
|
|
2769
2777
|
generatedProjectNode: GENERATED_PROJECT_NODE
|
|
@@ -2914,7 +2922,7 @@ async function commandIntegration(options) {
|
|
|
2914
2922
|
const result = {
|
|
2915
2923
|
ok: true,
|
|
2916
2924
|
command: "integration",
|
|
2917
|
-
interfaceVersion:
|
|
2925
|
+
interfaceVersion: 3,
|
|
2918
2926
|
requirements: {
|
|
2919
2927
|
node: ">=20",
|
|
2920
2928
|
generatedProjectNode: GENERATED_PROJECT_NODE
|
|
@@ -3001,6 +3009,17 @@ async function commandCreate(directory, options) {
|
|
|
3001
3009
|
await writeFile(join(root, "samples/default.json"), `${JSON.stringify(sample, null, 2)}\n`);
|
|
3002
3010
|
const sourceFile = options.ui === "react" ? "src/widget.tsx" : "src/widget.ts";
|
|
3003
3011
|
const hostFile = "src/widget-host.ts";
|
|
3012
|
+
const documentation = getDocumentation();
|
|
3013
|
+
const agentSetupUrl = new URL("agent-setup/prompt.md", documentation.url).href;
|
|
3014
|
+
const projectGuidance = {
|
|
3015
|
+
sdkVersion: sdkPackage.version,
|
|
3016
|
+
sourceFile,
|
|
3017
|
+
hostFile,
|
|
3018
|
+
documentation,
|
|
3019
|
+
agentSetupUrl
|
|
3020
|
+
};
|
|
3021
|
+
const readmePath = join(root, "README.md");
|
|
3022
|
+
const agentGuidePath = join(root, "AGENTS.md");
|
|
3004
3023
|
const source = options.ui === "react" && template.reactSource ? template.reactSource({ name }) : typeof template.source === "function" ? template.source({
|
|
3005
3024
|
ui: options.ui,
|
|
3006
3025
|
name
|
|
@@ -3009,13 +3028,13 @@ async function commandCreate(directory, options) {
|
|
|
3009
3028
|
await writeFile(join(root, hostFile), template.hostSource({ sourceFile }));
|
|
3010
3029
|
await writeFile(join(root, "scripts/rename-iife.mjs"), `import { rename } from "node:fs/promises";\n\nawait rename("dist/widget.iife.js", "dist/widget.js");\n`);
|
|
3011
3030
|
await writeFile(join(root, ".gitignore"), "node_modules/\ndist/\n.artifacts/\n.widget-build-receipt.json\n*.zip\n");
|
|
3012
|
-
await writeFile(
|
|
3031
|
+
await writeFile(readmePath, projectReadme({
|
|
3032
|
+
...projectGuidance,
|
|
3013
3033
|
name,
|
|
3014
3034
|
template: options.template,
|
|
3015
|
-
ui: options.ui
|
|
3016
|
-
sourceFile,
|
|
3017
|
-
hostFile
|
|
3035
|
+
ui: options.ui
|
|
3018
3036
|
}));
|
|
3037
|
+
await writeFile(agentGuidePath, projectAgentGuide(projectGuidance));
|
|
3019
3038
|
await writeFile(join(root, "tsconfig.json"), `${JSON.stringify({
|
|
3020
3039
|
compilerOptions: {
|
|
3021
3040
|
target: "ES2022",
|
|
@@ -3039,7 +3058,60 @@ async function commandCreate(directory, options) {
|
|
|
3039
3058
|
const warnings = [];
|
|
3040
3059
|
await writeProjectToolchain(root, toolchain);
|
|
3041
3060
|
if (name !== directoryName) warnings.push(`目录名 "${directoryName}" 不是合法标识符,manifest 的 name 已取 "${name}";需要其他取值请直接编辑 manifest.json。`);
|
|
3042
|
-
|
|
3061
|
+
const nextSteps = [
|
|
3062
|
+
{
|
|
3063
|
+
cwd: root,
|
|
3064
|
+
command: "pnpm",
|
|
3065
|
+
args: ["install"]
|
|
3066
|
+
},
|
|
3067
|
+
{
|
|
3068
|
+
cwd: root,
|
|
3069
|
+
command: "pnpm",
|
|
3070
|
+
args: [
|
|
3071
|
+
"exec",
|
|
3072
|
+
"bohr-widget",
|
|
3073
|
+
"integration",
|
|
3074
|
+
"--project",
|
|
3075
|
+
".",
|
|
3076
|
+
"--json"
|
|
3077
|
+
]
|
|
3078
|
+
},
|
|
3079
|
+
{
|
|
3080
|
+
cwd: root,
|
|
3081
|
+
command: "pnpm",
|
|
3082
|
+
args: [
|
|
3083
|
+
"exec",
|
|
3084
|
+
"bohr-widget",
|
|
3085
|
+
"build",
|
|
3086
|
+
".",
|
|
3087
|
+
"--json"
|
|
3088
|
+
]
|
|
3089
|
+
},
|
|
3090
|
+
{
|
|
3091
|
+
cwd: root,
|
|
3092
|
+
command: "pnpm",
|
|
3093
|
+
args: [
|
|
3094
|
+
"exec",
|
|
3095
|
+
"bohr-widget",
|
|
3096
|
+
"check",
|
|
3097
|
+
".",
|
|
3098
|
+
"--json"
|
|
3099
|
+
]
|
|
3100
|
+
},
|
|
3101
|
+
{
|
|
3102
|
+
cwd: root,
|
|
3103
|
+
command: "pnpm",
|
|
3104
|
+
args: [
|
|
3105
|
+
"exec",
|
|
3106
|
+
"bohr-widget",
|
|
3107
|
+
"pack",
|
|
3108
|
+
".",
|
|
3109
|
+
"--out",
|
|
3110
|
+
"artifacts/my-widget.zip",
|
|
3111
|
+
"--json"
|
|
3112
|
+
]
|
|
3113
|
+
}
|
|
3114
|
+
];
|
|
3043
3115
|
const result = {
|
|
3044
3116
|
ok: true,
|
|
3045
3117
|
command: "create",
|
|
@@ -3051,6 +3123,11 @@ async function commandCreate(directory, options) {
|
|
|
3051
3123
|
...panelId ? { panelId } : {},
|
|
3052
3124
|
manifestPath: join(root, "manifest.json"),
|
|
3053
3125
|
packagePath: join(root, "package.json"),
|
|
3126
|
+
readmePath,
|
|
3127
|
+
agentGuidePath,
|
|
3128
|
+
documentation,
|
|
3129
|
+
agentSetupUrl,
|
|
3130
|
+
nextSteps,
|
|
3054
3131
|
profile: toolchain.profile,
|
|
3055
3132
|
hostCompatibility,
|
|
3056
3133
|
...warnings.length === 0 ? {} : { warnings }
|
|
@@ -3058,8 +3135,14 @@ async function commandCreate(directory, options) {
|
|
|
3058
3135
|
if (options.json) console.log(JSON.stringify(result, null, 2));
|
|
3059
3136
|
else {
|
|
3060
3137
|
console.log(`已创建 Widget 工程:${root}(manifest name: ${name})`);
|
|
3138
|
+
if (panelId) console.log(`Panel ID:${panelId}(可自定义)`);
|
|
3139
|
+
console.log(`创建时 SDK:@dp-bohrium/widget-sdk@${sdkPackage.version}`);
|
|
3140
|
+
console.log(`项目说明:${readmePath}\nAgent 指引:${agentGuidePath}`);
|
|
3141
|
+
console.log(`文档站:${documentation.url}\nAgent 阅读入口:${agentSetupUrl}`);
|
|
3142
|
+
console.log(`文档索引:${documentation.llms}`);
|
|
3061
3143
|
for (const warning of warnings) console.warn(`提示:${warning}`);
|
|
3062
|
-
console.log(
|
|
3144
|
+
console.log(`先读取项目指引和公开文档,再进入工程目录:${root}`);
|
|
3145
|
+
console.log(`依次执行:\n${nextSteps.map((step) => [step.command, ...step.args].join(" ")).join("\n")}`);
|
|
3063
3146
|
}
|
|
3064
3147
|
return result;
|
|
3065
3148
|
}
|
|
@@ -3482,9 +3565,9 @@ async function commandPack(directory, options) {
|
|
|
3482
3565
|
const warnings = [];
|
|
3483
3566
|
if (options.includePreviewFixtures && !hasFixtures) warnings.push("使用了 --include-preview-fixtures,但 preview/fixtures.json 不存在,ZIP 未包含任何 fixtures。");
|
|
3484
3567
|
else if (hasFixtures && !options.includePreviewFixtures) warnings.push("工程包含 preview/fixtures.json,未使用 --include-preview-fixtures,ZIP 未包含 fixtures。");
|
|
3485
|
-
const
|
|
3486
|
-
warnings.push(...oversizedAssetWarnings(files));
|
|
3487
|
-
const bundle =
|
|
3568
|
+
const prepared = prepareWidgetPackage(result, { includePreviewFixtures: fixturesIncluded });
|
|
3569
|
+
warnings.push(...oversizedAssetWarnings(prepared.files));
|
|
3570
|
+
const bundle = prepared.archive;
|
|
3488
3571
|
await mkdir(dirname(destination), { recursive: true });
|
|
3489
3572
|
await writeFile(destination, bundle);
|
|
3490
3573
|
const artifact = {
|
|
@@ -3492,12 +3575,12 @@ async function commandPack(directory, options) {
|
|
|
3492
3575
|
command: "pack",
|
|
3493
3576
|
projectRoot: result.projectRoot,
|
|
3494
3577
|
path: destination,
|
|
3495
|
-
bytes:
|
|
3496
|
-
sha256:
|
|
3578
|
+
bytes: prepared.bytes,
|
|
3579
|
+
sha256: prepared.sha256,
|
|
3497
3580
|
toolchain: {
|
|
3498
3581
|
cli: packageJson.version,
|
|
3499
3582
|
sdk: sdkPackage.version,
|
|
3500
|
-
|
|
3583
|
+
protocol: toolchain.protocol
|
|
3501
3584
|
},
|
|
3502
3585
|
...compatibility,
|
|
3503
3586
|
hostCompatibility: await assertHostCompatibility(options.hostCompat, toolchain),
|
|
@@ -3553,10 +3636,7 @@ async function commandMigrate(positional, options) {
|
|
|
3553
3636
|
if (action === "scaffold") {
|
|
3554
3637
|
if (!options.output) throw new Error("migrate dsh scaffold 需要 --out <widget-dir>");
|
|
3555
3638
|
const hostCompatibility = await assertHostCompatibility(options.hostCompat, toolchain);
|
|
3556
|
-
const result = await scaffoldDshWidget(input, options.output, {
|
|
3557
|
-
sdkVersion: sdkPackage.version,
|
|
3558
|
-
contractsVersion: contractsPackage.version
|
|
3559
|
-
});
|
|
3639
|
+
const result = await scaffoldDshWidget(input, options.output, { sdkVersion: sdkPackage.version });
|
|
3560
3640
|
await writeProjectToolchain(result.projectRoot, toolchain);
|
|
3561
3641
|
result.profile = toolchain.profile;
|
|
3562
3642
|
result.hostCompatibility = hostCompatibility;
|
|
@@ -3575,7 +3655,7 @@ async function commandDoctor(directory, options) {
|
|
|
3575
3655
|
cli: packageJson.version,
|
|
3576
3656
|
node: process.versions.node,
|
|
3577
3657
|
sdk: sdkPackage.version,
|
|
3578
|
-
|
|
3658
|
+
protocol: toolchain.protocol,
|
|
3579
3659
|
project: root,
|
|
3580
3660
|
packageJson: existsSync(packagePath),
|
|
3581
3661
|
manifest: existsSync(manifestPath),
|
|
@@ -3650,7 +3730,7 @@ function commandVersion(options) {
|
|
|
3650
3730
|
command: "version",
|
|
3651
3731
|
cli: packageJson.version,
|
|
3652
3732
|
sdk: sdkPackage.version,
|
|
3653
|
-
|
|
3733
|
+
protocol: toolchain.protocol
|
|
3654
3734
|
};
|
|
3655
3735
|
if (options.json) console.log(JSON.stringify(result, null, 2));
|
|
3656
3736
|
else console.log(`${result.cli} (SDK ${result.sdk})`);
|