@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/dist/cli.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as normalizeArchivePath, c as resolveWidgetProjects, i as collectWidgetPackageFiles, l as compileAuthorManifest, n as scaffoldDshWidget, o as storedZip, s as checkWidgetProject, t as auditDshPlugin } from "./dsh-BvnlfCRX.mjs";
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> 仅用于 panel;默认取规范化后的工程名",
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
- "workspace-files 会补齐 files.list、files.metadata、files.read 和目录引用样例;文件树逻辑与夹具需自行实现。",
1289
- "其他 Panel id 需要 Host 预先注册和绑定;更改 id 不会自动接管宿主界面。",
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=2、toolchain.formatVersion=2;返回 execution、profile、requirements 和 documentation。",
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/contracts 依赖并安装。",
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: "查看当前 CLI 及其固定的 SDK/contracts 版本。",
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, contracts, packageName = "@dp-bohrium/widget-cli", generatedProjectNode, documentation } = context;
1486
+ const { cli, sdk, packageName = "@dp-bohrium/widget-cli", generatedProjectNode, documentation } = context;
1487
1487
  return `bohr-widget ${cli} — Bohrium Widget 插件工程工具
1488
- SDK ${sdk} / contracts ${contracts}
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 查看 CLI 与固定的 SDK/contracts 版本
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 --ui react --panel-id workspace-files
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
- * `@dp-bohrium/widget-contracts` 的 host schema 只在 `compileAuthorManifest` 之后生效,
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 !== 1 || lock.profileId !== profile.id) throw failure("PROJECT_PROFILE_MISMATCH", "工程锁定的 profile 与当前 Widget CLI 不一致", {
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.contracts !== profile.contracts) throw failure("PROJECT_SDK_MISMATCH", "工程锁定的 SDK/contracts 与当前 profile 不一致", {
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
- /** 只接受 SDK 自身依赖或其安装目录中的提升依赖,不向工作区祖先借用。 */
1770
- async function sdkContractsMetadata(sdkPath, root) {
1771
- const sdkRoot = dirname(await realpath(sdkPath));
1772
- const resolver = createRequire(join(sdkRoot, "package.json"));
1773
- const lookupRoots = /* @__PURE__ */ new Set([join(sdkRoot, "node_modules")]);
1774
- for (let current = sdkRoot; dirname(current) !== current; current = dirname(current)) if (basename(current) === "node_modules") {
1775
- lookupRoots.add(current);
1776
- break;
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 resolvedPath = await realpath(resolver.resolve(`${PACKAGES.contracts}/package.json`));
1780
- for (const lookup of resolver.resolve.paths(PACKAGES.contracts) ?? []) {
1781
- if (!lookupRoots.has(lookup)) continue;
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
- if (error.cliCode) throw error;
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 必须由工程直接安装,contracts 从该 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
- if (key === "sdk") {
1825
- const dependency = actual.dependencies?.[PACKAGES.contracts];
1826
- if (dependency !== toolchain.profile.contracts && dependency !== "workspace:*" && dependency !== `workspace:${toolchain.profile.contracts}`) throw failure("PROJECT_SDK_MISMATCH", "工程 SDK 的 contracts 依赖与固定 profile 不一致", {
1827
- projectRoot: root,
1828
- package: name,
1829
- expected: toolchain.profile.contracts,
1830
- declared: dependency
1831
- }, ["安装固定 profile 对应的 SDK;发布包的 contracts 依赖必须为精确版本。"]);
1832
- const contracts = await sdkContractsMetadata(path, root);
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: declared.contracts ? [{
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: 1,
1865
+ formatVersion: 2,
1881
1866
  profileId: toolchain.profile.id,
1882
1867
  sdk: toolchain.profile.sdk,
1883
- contracts: toolchain.profile.contracts,
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: 1,
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 !== 1 || JSON.stringify(receipt.toolchain) !== JSON.stringify(receiptToolchain(toolchain)) || JSON.stringify(receipt.dependencies) !== JSON.stringify(project.installed)) mismatch("receipt 工具链或实际依赖与本次执行不一致");
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 projectReadme({ name, template, ui, sourceFile, hostFile }) {
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
- - 源码入口:${sourceFile},由 ${hostFile} 调用 SDK 的 runWidgetHost 启动。
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
- contracts: contractsPackage.version,
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: 2,
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(join(root, "README.md"), projectReadme({
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
- if (options.template === "panel" && panelId !== "workspace-files") warnings.push(`Panel id "${panelId}" 需要 Host 预先注册并绑定;工作区文件面板请使用 --panel-id workspace-files。`);
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(`下一步:cd ${JSON.stringify(root)},执行 pnpm install,再执行 pnpm exec bohr-widget build . --json 和 pnpm exec bohr-widget check . --json。`);
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 files = collectWidgetPackageFiles(result, { includePreviewFixtures: fixturesIncluded });
3486
- warnings.push(...oversizedAssetWarnings(files));
3487
- const bundle = storedZip(files);
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: bundle.byteLength,
3496
- sha256: `sha256:${createHash("sha256").update(bundle).digest("hex")}`,
3578
+ bytes: prepared.bytes,
3579
+ sha256: prepared.sha256,
3497
3580
  toolchain: {
3498
3581
  cli: packageJson.version,
3499
3582
  sdk: sdkPackage.version,
3500
- contracts: contractsPackage.version
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
- contracts: contractsPackage.version,
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
- contracts: contractsPackage.version
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})`);