@dp-bohrium/widget-cli 0.4.0 → 0.5.0

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 CHANGED
@@ -1,14 +1,13 @@
1
1
  # Widget CLI Agent 使用说明
2
2
 
3
- `@dp-bohrium/widget-cli` 是 Widget 工程的本地执行器。Agent 应先读取本文件和
4
- `llms.txt`,再根据任务选择一个命令;不要猜测参数,也不要把 CLI 的成功输出解释为
5
- 平台 已渲染或已发布。
3
+ `bohr-widget` 用于创建、迁移、校验、开发、构建和打包 Widget 工程。Agent 先读取
4
+ `llms.txt` 和本文件,再按任务选择命令;不要猜测参数,也不要把 CLI 的成功输出解释为
5
+ 平台已渲染或已发布。
6
6
 
7
7
  CLI 本身要求 Node.js >=20,默认生成工程构建器要求 `^22.18.0 || >=24.11.0`。
8
8
  `integration.requirements.node` 和 `generatedProjectNode` 分别表达这两项要求。
9
- 本包自包含固定 SDK/contracts、Schema、compiler、校验器和模板,
10
- 通过文档站提供教程与参考。生成工程只直接安装锁定的 SDK 与构建器;
11
- 公开类型和 Schema 从 SDK 导入,contracts 由 SDK 的传递依赖提供。
9
+ 生成工程精确依赖 SDK 与构建器,类型、Schema 和工程命令均由 SDK 提供。
10
+ 教程与参考见文档站。
12
11
 
13
12
  先看全局帮助,再按命令查看参数、默认值、示例和必要提示:
14
13
 
@@ -24,9 +23,10 @@ pnpm exec bohr-widget --version --json
24
23
  `<命令路径> --help` 与 `help <命令路径>` 查看对应层级;例如 `dev -h`、`pack --help` 或
25
24
  `migrate dsh --help`。`-v` / `--version` 等价于 `version`,`--version --json` 等价于 `version --json`。
26
25
  帮助仅输出本地文本,不执行所选命令或联网获取文档。npm 的全局帮助用
27
- `npx --no-install bohr-widget --help`,其他命令同样替换前缀;未安装时可用
28
- 新工程用 `pnpm dlx @dp-bohrium/widget-sdk --help` 查看 SDK 自带入口;
29
- `pnpm dlx @dp-bohrium/widget-cli --help` 在兼容期保持原行为。
26
+ `npx --no-install bohr-widget --help`,其他命令同样替换前缀。
27
+ 创建新工程可用 `pnpm dlx @dp-bohrium/widget-sdk --help` 查看 SDK 自带命令;
28
+ 工具集成可用 `pnpm dlx @dp-bohrium/widget-cli --help`,并核对执行包版本与 SDK profile。
29
+ 升级时迁移并重建工程,不复用不匹配的执行器或 receipt。
30
30
 
31
31
  ## 入口
32
32
 
@@ -50,7 +50,7 @@ bohr-widget help [<命令路径>]
50
50
  ```
51
51
 
52
52
  工程命令均可通过 `--host-compat <声明文件>` 检查目标宿主。接入方先调用
53
- `integration --json`:`interfaceVersion=2`,`toolchain.formatVersion=2`;返回固定 profile、
53
+ `integration --json`:`interfaceVersion=3`,`toolchain.formatVersion=3`;返回固定 profile、
54
54
  执行器与 `documentation`,不返回 `skills`。文档字段为 `url`、`quickStart`、`cli`、`llms`、
55
55
  `llmsFull`。先读[文档索引](https://dev.dp.tech/bohrium-widget-sdk/llms.txt),再选取相关页面;
56
56
  需要完整材料时读[完整文档](https://dev.dp.tech/bohrium-widget-sdk/llms-full.txt)。
@@ -78,7 +78,7 @@ bohr-widget help [<命令路径>]
78
78
  `pack --no-build` 要求上次 `bohr-widget build` 生成的 `.widget-build-receipt.json` 与当前工具链、
79
79
  实际依赖、源文件和 `dist` 内容一致;缺失或变化时重新 build,不补写或篡改 receipt。
80
80
  receipt 的执行摘要只有 `compiler`、`validators`、`schemas`、`templates` 四项;
81
- 文档站更新不改变这些摘要、不使 receipt 失效,也不要求 CLI 发版。
81
+ 文档站更新不改变这些摘要,也不使 receipt 失效。
82
82
  6. Bohr CLI 或平台侧必须继续使用同一份 ZIP 和 digest;Widget CLI 不负责 upload、preview、
83
83
  commit、版本发布或 Agent binding。
84
84
 
@@ -168,19 +168,13 @@ profile。`ready` 在此基础上还要求
168
168
  `warnings` 里。
169
169
 
170
170
  旧工程缺少 `widget-toolchain.json` 时,先检查 `doctor` 输出,恢复当前 profile 的精确依赖并安装,
171
- 再运行 `adopt <目录>`。`adopt` 会校验实际安装的 SDK/contracts、Manifest 和 samples 后写锁定文件,
172
- 不自动迁移字段或升级依赖。工程命令会检查精确 SDK 声明与直接安装版本,再从该 SDK 的真实依赖
173
- 核对 contracts 与固定 profile;源码工作区支持 `workspace:*`,发布包必须转换为精确版本。
174
- 已有工程若仍直接声明 contracts,也会继续核对其精确声明与实际版本;缺少依赖时不能向工程祖先
175
- 或 CLI 借用。该作者用法已废弃,机器诊断为 `WIDGET_CLI_DIRECT_CONTRACTS_DEPRECATED`;
176
- 读取 `deprecations` 中的替代出口、`migration.status` 与 `removal`,不要将暂时通过解释为长期支持。
177
- R0 只做本地改造;统一入口切换发布 R1 前必须移除。实际内部消费者迁移、旧实现删除与
178
- Host 验收未完成时阻止 R1;不存在的旧 Widget 不要求专用转换规则。版本号由发布计划决定。根计划为
179
- `docs/plans/2026-10-29-widget-sdk-forge-unified-entry.md`。
180
- SDK 出口准备批只为消费者迁移提供可安装版本,不代表 Bohr 与内部宿主联合切换 R1 已完成。
171
+ 再运行 `adopt <目录>`。`adopt` 会校验实际安装的 SDK 与内置协议资产、Manifest 和 samples 后写锁定文件,
172
+ 不自动迁移字段或升级依赖。工程命令会检查精确 SDK 声明与直接安装版本,再核对该 SDK 自身的协议元数据、公开 Schema 与执行摘要;不能通过祖先目录或旧包补齐资产。
173
+ 旧工程直接声明 contracts 或 CLI 时会失败;先在独立候选中改用 SDK 出口并移除旧包,
174
+ 重新安装、构建和验收。锁和 receipt 为 v2,integration 与 toolchain 为 v3;不自动回选旧执行器。
181
175
  保留已有作者源码、跨 profile 升级或准备候选工程时,先读[准备迁移候选](https://dev.dp.tech/bohrium-widget-sdk/guides/migration),按指南完成候选审阅、plan/apply 和后续验收。
182
- Host / 控制面在 R0 保留现有公开 contracts,R1 转 SDK 的协议/Schema/conformance 出口;
183
- 协议类型仍由 contracts 同源维护,不给 canonical 类型标记 `@deprecated`。
176
+ Host 或控制面可使用 `@dp-bohrium/widget-contracts`,也可使用 SDK 的协议、Schema 和 conformance
177
+ 入口;固定与目标 SDK 配套的精确版本,不混用不同版本的协议资产。
184
178
 
185
179
  ## 宿主兼容声明
186
180
 
@@ -189,8 +183,8 @@ Host / 控制面在 R0 保留现有公开 contracts,R1 转 SDK 的协议/Schem
189
183
  或过期声明;只有本次在线取得、仍有效且接受当前 profile 时才是 `confirmed`。后者是调用方报告
190
184
  的兼容证据,不是发布许可。格式错误、时间无效或 profile 不被接受时按错误处理。
191
185
 
192
- 本次只交付 A、B 阶段的本地能力,平台在线发现接口与 Bohr 在线取声明尚需后续接入。不要把
193
- 本地 profile、SDK package.json 或 `unknown` 解释为线上平台已兼容。
186
+ CLI 不自动获取线上声明。调用方需提供目标 Host 的兼容证据,不要把本地 profile、
187
+ SDK package.json 或 `unknown` 解释为线上平台已兼容。
194
188
 
195
189
  ## 错误处理
196
190
 
@@ -228,13 +222,13 @@ Host / 控制面在 R0 保留现有公开 contracts,R1 转 SDK 的协议/Schem
228
222
  里带 `profileUrl`、`statusUrl`、`hostUrl`、digest 和 assets,不得把整个 stdout 当作单个 JSON
229
223
  文档解析。watch 重建失败时从 `statusUrl` 读取 `lastBuildError`,修复工程后重新保存源码或重新
230
224
  执行 build。`statusUrl` 是本地诊断接口,不是生产 Host API。
231
- 每轮重建都会重新核对工具链与实际 SDK/contracts,失败时继续保留上一轮可用 generation。
225
+ 每轮重建都会重新核对工具链与实际 SDK 与内置协议摘要,失败时继续保留上一轮可用 generation。
232
226
 
233
227
  `/core` 是模板、compiler、校验和打包的底层 API;直接调用它时,调用方负责工程锁定、实际依赖
234
228
  和宿主兼容策略。完整预检由上述命令提供。`sdkVersion` 不能用来伪造另一代 compiler 的版本。
235
229
 
236
230
  `--open` 优先协商 Widget Development Host v1,旧宿主才回落 legacy profile 并告警。
237
- 该降级仅在 R0 保留且已废弃,R1 前随旧开发桥接迁移删除;目标 Host 应升级到当前协议。
231
+ legacy profile 已废弃,目标 Host 应升级到当前协议。
238
232
  descriptor、status、events、control、一次性 claim 和 session token 都通过命令返回的 URL
239
233
  与类型声明表达;不要依赖源码仓库中的内部设计文档来猜测协议。
240
234
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # `@dp-bohrium/widget-cli` 变更记录
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 破坏性变更:本版配套 SDK `0.7.0`,新建 Widget 工程只直接依赖 SDK;CLI 仍可作为独立工具安装。
8
+ `version --json` 和 `integration --json` 报告实际执行包的身份、版本及配套 SDK。
9
+
10
+ integration/toolchain 升为 v3,工程锁和构建回执(receipt)升为 v2。旧工程须保留原源码,
11
+ 在新目录按当前模板迁移并重新构建;旧格式的锁和回执不能直接复用。
12
+
13
+ ### Patch Changes
14
+
15
+ - 修复 `/core` 类型入口在独立安装后无法通过 TypeScript 编译的问题,保留工程检查、清单编译和
16
+ 打包 API 的准确类型。
17
+ - 修复独立安装 CLI 后,清单编译和迁移命令错误依赖另行安装的 SDK 包元数据的问题。
18
+ - 86773d8: 修复开发 Host 面板投影使用 `snapshot.id` 而被正式 Host 拒绝的问题,统一输出既有契约要求的
19
+ `snapshot.panelType`,并同步开发会话类型声明。Manifest 的 `contribution.id` 和
20
+ RenderRequest 的 `content.id` 保持原义。
21
+ - af5aee4: 破坏性变更:取消 `files.read` 的累计字节额度,让文件预览和 Panel 可以持续读取已授权文件。
22
+ `resourceBudget.files.readBytesPerRun` 与读取 grant 的 `bytesPerRun` 改为已废弃的可选历史字段;
23
+ 新宿主不再下发或执行这两项额度。单次大小、调用频率、并发、授权以及写入、下载和状态预算不变。
24
+
25
+ 消费者须先升级协议与宿主校验器,再省略旧字段;仍要求历史字段的旧宿主不能消费新配置。
26
+
3
27
  ## 0.4.0
4
28
 
5
29
  ### Minor Changes
package/README.md CHANGED
@@ -2,11 +2,8 @@
2
2
 
3
3
  创建、开发和打包 Bohrium 自定义 Widget 的命令行工具。
4
4
 
5
- `bohr-widget` 现已随 `@dp-bohrium/widget-sdk` 一起交付,作者工程统一只直接安装 SDK。
6
- 本包在迁移期继续保留原有直接安装与命令行为,但创建和迁移出的新工程同样只依赖 SDK;
7
- 它只按现行发布治理保留过渡分发、历史审计和废弃诊断,按阶段 3 退出新作者安装和发布流程。
8
- 两包的同名命令不保证在 npm/pnpm 下保留旧 CLI 身份。旧工程按[单 SDK 迁移步骤](https://dev.dp.tech/bohrium-widget-sdk/reference/versioning)
9
- 移除本包、重新安装并由 SDK `build` 重建 receipt,再校验和打包;不复用旧 CLI 的 receipt。
5
+ 提供 `bohr-widget` 命令,支持工程创建、构建、校验、开发联调与 ZIP 打包。
6
+ SDK 已包含此命令,开发 Widget 推荐从 SDK 开始;脚本或工具集成也可直接调用本包。
10
7
 
11
8
  [文档站](https://dev.dp.tech/bohrium-widget-sdk/) · [快速开始](https://dev.dp.tech/bohrium-widget-sdk/guides/quick-start) · [命令行指南](https://dev.dp.tech/bohrium-widget-sdk/guides/cli)
12
9
 
@@ -15,21 +12,6 @@
15
12
  推荐使用 Node.js 24(>=24.11.0)。CLI 本身支持 Node.js >=20,默认模板的构建器要求
16
13
  `^22.18.0 || >=24.11.0`。安装 pnpm 或 npm 后即可开始。
17
14
 
18
- SDK 与内部 contracts 的配套版本由 CLI 固定管理,创建工程后安装其依赖即可。
19
- Widget 作者从 SDK 导入公开类型与 Schema,无需单独选择或安装 contracts。
20
-
21
- 独立消费者直接依赖 contracts 的旧入口已废弃。`doctor --json` 与工程命令的
22
- `deprecations` 返回 `WIDGET_CLI_DIRECT_CONTRACTS_DEPRECATED`,包含替代出口、迁移状态和
23
- 移除阶段“统一入口切换发布 R1”。R0 是本地改造,R1 前必须移除旧分支;实际内部消费者
24
- 迁移、SDK 出口交付或 Host 验收未完成时阻止 R1,不能据此延长兼容。版本号以正式发布计划为准,
25
- 不从当前源码推算。当前仍严格核对旧声明和实际依赖,版本漂移继续失败。
26
- SDK 出口准备批只提供消费者迁移所需的可安装版本,不代表 Bohr 与内部宿主联合切换 R1 已完成。
27
-
28
- `migrate project plan/apply` 核对 Agent 准备的候选并写入新目录,具体边界见下方。
29
- `adopt` 仅为已符合当前 profile 的工程补锁,不升级代码、依赖或旧 Bundle。Host / 控制面在 R0 暂时使用现有已公开 contracts,
30
- R1 改经 SDK `/contracts`、`/schemas`、`/conformance` 消费;canonical 协议类型本身没有废弃。
31
- 仓库移除计划见 `docs/plans/2026-10-29-widget-sdk-forge-unified-entry.md`。
32
-
33
15
  ## 创建并打包
34
16
 
35
17
  下面创建一个 React 面板,构建、检查后生成 ZIP:
@@ -89,7 +71,8 @@ pnpm exec bohr-widget --version
89
71
  ```
90
72
 
91
73
  无参数、`-h`、`help` 也可查看帮助。npm 使用 `npx --no-install bohr-widget --help`;
92
- 尚未安装时推荐运行 `pnpm dlx @dp-bohrium/widget-sdk --help`;本包原入口仍可使用。
74
+ 尚未安装时可运行 `pnpm dlx @dp-bohrium/widget-sdk --help`,
75
+ 也可通过 `pnpm dlx @dp-bohrium/widget-cli --help` 调用本包。
93
76
 
94
77
  以下命令通过 `pnpm exec bohr-widget` 或 `npx --no-install bohr-widget` 执行:
95
78
 
@@ -821,7 +821,6 @@
821
821
  "additionalProperties": false,
822
822
  "required": [
823
823
  "bytesPerRequest",
824
- "bytesPerRun",
825
824
  "callsPerMinute"
826
825
  ],
827
826
  "properties": {
@@ -830,6 +829,8 @@
830
829
  "minimum": 1
831
830
  },
832
831
  "bytesPerRun": {
832
+ "description": "历史读取累计额度字段,仅为兼容旧配置保留;当前 files.read 不累计或执行此额度,新宿主不再下发。",
833
+ "deprecated": true,
833
834
  "type": "integer",
834
835
  "minimum": 1
835
836
  },
@@ -1998,13 +1999,16 @@
1998
1999
  "additionalProperties": false,
1999
2000
  "required": [
2000
2001
  "readBytesPerRequest",
2001
- "readBytesPerRun",
2002
2002
  "callsPerMinute",
2003
2003
  "listPageSize"
2004
2004
  ],
2005
2005
  "properties": {
2006
2006
  "readBytesPerRequest": { "type": "integer", "minimum": 1 },
2007
- "readBytesPerRun": { "type": "integer", "minimum": 1 },
2007
+ "readBytesPerRun": {
2008
+ "description": "历史读取累计额度字段,仅为兼容旧配置保留;当前 files.read 不累计或执行此额度,新宿主不再下发。",
2009
+ "deprecated": true,
2010
+ "type": "integer", "minimum": 1
2011
+ },
2008
2012
  "callsPerMinute": { "type": "integer", "minimum": 1 },
2009
2013
  "listPageSize": { "type": "integer", "minimum": 1 },
2010
2014
  "writeBytesPerRequest": {
@@ -1,11 +1,15 @@
1
1
  {
2
- "formatVersion": 2,
2
+ "formatVersion": 3,
3
3
  "packageName": "@dp-bohrium/widget-cli",
4
- "cli": "0.4.0",
4
+ "cli": "0.5.0",
5
5
  "profile": {
6
- "id": "widget-sdk-0.6.0-contracts-0.6.0",
7
- "sdk": "0.6.0",
8
- "contracts": "0.6.0"
6
+ "id": "widget-sdk-0.7.0",
7
+ "sdk": "0.7.0"
8
+ },
9
+ "protocol": {
10
+ "schemaVersion": 1,
11
+ "hostApiVersion": 1,
12
+ "digest": "sha256:ee3023e337559bbf83c096365fe1eb49ce6809a880a5e5d65e2a2f6fd53a7ddb"
9
13
  },
10
14
  "hostAcceptance": "unknown",
11
15
  "documentation": {
@@ -16,9 +20,9 @@
16
20
  "llms": "https://dev.dp.tech/bohrium-widget-sdk/llms.txt"
17
21
  },
18
22
  "digests": {
19
- "compiler": "sha256:d541f305c8cccdfc8e122ab84d57103da68c734325df2ead3729cc3a21b7d222",
20
- "validators": "sha256:e3e411c6ea3c09f07554222141ccb92124cdf8921ab39dbaeb8f79f4ad8d12aa",
21
- "schemas": "sha256:2286156c619d6482471966fb97a2a4adbb9c86ef9ec17225eb1b070d8489dd9c",
22
- "templates": "sha256:34f08fb56072c2722a1e02cee09b3130d075853129c333aa8916e0411cee5618"
23
+ "compiler": "sha256:6b6ac1585a3f2bc0f8b2717b2475584a502a9026045b840337547528b7a063b0",
24
+ "validators": "sha256:8712fb004d9decf1eeae56c1e7057092a8abc0eeae1093c29546bb56e3261922",
25
+ "schemas": "sha256:ee3023e337559bbf83c096365fe1eb49ce6809a880a5e5d65e2a2f6fd53a7ddb",
26
+ "templates": "sha256:60f555788f33fb38d707525f571d13b6fa78875be7d2d87cb864db6926a52ccb"
23
27
  }
24
28
  }
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-BkPMTfZ_.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: {}
@@ -1382,7 +1380,7 @@ function commandTopics(context) {
1382
1380
  notes: [
1383
1381
  "不传 --project 时只发现 CLI 自带工具链,不检查当前目录是否为 Widget 工程。",
1384
1382
  "传入工程时要求工具链锁;尚未安装依赖时先核对声明,已安装时同时核对实际版本。",
1385
- "JSON 使用 interfaceVersion=2、toolchain.formatVersion=2;返回 execution、profile、requirements 和 documentation。",
1383
+ "JSON 使用 interfaceVersion=3、toolchain.formatVersion=3;返回 execution、profile、requirements 和 documentation。",
1386
1384
  "调用方应使用 execution.executable 与 execution.entry 启动同一份 CLI,避免 PATH 指向另一版本。",
1387
1385
  "宿主声明由调用方提供;unknown、snapshot、confirmed 不代表上传或发布许可。"
1388
1386
  ],
@@ -1395,7 +1393,7 @@ function commandTopics(context) {
1395
1393
  options: [HOST_OPTION, JSON_OPTION],
1396
1394
  examples: ["bohr-widget adopt ./existing-widget --json", "bohr-widget adopt . --host-compat ./host.json --json"],
1397
1395
  notes: [
1398
- "先运行 doctor,恢复当前 profile 的精确 SDK/contracts 依赖并安装。",
1396
+ "先运行 doctor,恢复当前 profile 的精确 SDK 依赖并安装。",
1399
1397
  "核对实际依赖、Manifest 和 samples 后才写锁;不要求已构建入口。",
1400
1398
  "不会自动升级依赖、迁移源码或修正协议字段;检查不通过时先修复工程。"
1401
1399
  ]
@@ -1412,7 +1410,7 @@ function commandTopics(context) {
1412
1410
  ]
1413
1411
  },
1414
1412
  version: {
1415
- description: "查看当前 CLI 及其固定的 SDK/contracts 版本。",
1413
+ description: "查看当前 SDK 执行器及内置协议摘要。",
1416
1414
  usage: ["bohr-widget version [--json]", "bohr-widget --version [--json]"],
1417
1415
  options: [JSON_OPTION],
1418
1416
  examples: ["bohr-widget version --json", "bohr-widget -v"],
@@ -1483,9 +1481,9 @@ function section(title, lines) {
1483
1481
  return lines.length ? `\n${title}:\n${lines.map((line) => ` ${line}`).join("\n")}\n` : "";
1484
1482
  }
1485
1483
  function globalHelp(context) {
1486
- const { cli, sdk, contracts, packageName = "@dp-bohrium/widget-cli", generatedProjectNode, documentation } = context;
1484
+ const { cli, sdk, packageName = "@dp-bohrium/widget-cli", generatedProjectNode, documentation } = context;
1487
1485
  return `bohr-widget ${cli} — Bohrium Widget 插件工程工具
1488
- SDK ${sdk} / contracts ${contracts}
1486
+ SDK ${sdk}(协议与执行工具链均由 SDK 内置)
1489
1487
  创建、校验、构建、开发调试与打包;上传、发布和 Agent 绑定由 Bohr CLI 或平台执行。
1490
1488
 
1491
1489
  用法:
@@ -1505,7 +1503,7 @@ SDK ${sdk} / contracts ${contracts}
1505
1503
  schema 打印作者 Manifest Schema 的本地路径
1506
1504
  migrate project plan|apply 比较 Agent 准备的候选并安全复制到新目录
1507
1505
  migrate dsh audit|scaffold 审计 DSH 来源或按已审查配方生成工程
1508
- version 查看 CLI 与固定的 SDK/contracts 版本
1506
+ version 查看 SDK 执行器与内置协议版本
1509
1507
  help [命令...] 查看全局或指定主题帮助
1510
1508
 
1511
1509
  全局选项:
@@ -1645,10 +1643,7 @@ function lintAuthorManifest(manifest, options = {}) {
1645
1643
  //#region src/project-executor.mjs
1646
1644
  const PROJECT_TOOLCHAIN_FILE = "widget-toolchain.json";
1647
1645
  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
- });
1646
+ const PACKAGES = Object.freeze({ sdk: "@dp-bohrium/widget-sdk" });
1652
1647
  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
1648
  function failure(code, message, context, recovery) {
1654
1649
  return Object.assign(new Error(message), {
@@ -1722,12 +1717,12 @@ async function assertHostCompatibility(hostCompatPath, toolchain, { now = Date.n
1722
1717
  }
1723
1718
  function assertMatchingLock(lock, toolchain, root) {
1724
1719
  const { profile } = toolchain;
1725
- if (!record$1(lock) || lock.formatVersion !== 1 || lock.profileId !== profile.id) throw failure("PROJECT_PROFILE_MISMATCH", "工程锁定的 profile 与当前 Widget CLI 不一致", {
1720
+ if (!record$1(lock) || lock.formatVersion !== 2 || lock.profileId !== profile.id) throw failure("PROJECT_PROFILE_MISMATCH", "工程锁定格式或 profile 与当前 SDK 不一致;旧工程需准备当前源码候选后迁移,不能复用历史执行器", {
1726
1721
  projectRoot: root,
1727
1722
  expectedProfile: profile.id,
1728
1723
  actualProfile: lock?.profileId
1729
1724
  }, ["使用当前受支持的 CLI,并在新目录显式迁移工程与验收;不要回选旧 CLI 绕过 profile 差异。"]);
1730
- if (lock.sdk !== profile.sdk || lock.contracts !== profile.contracts) throw failure("PROJECT_SDK_MISMATCH", "工程锁定的 SDK/contracts 与当前 profile 不一致", {
1725
+ if (lock.sdk !== profile.sdk || !isDeepStrictEqual(lock.protocol, toolchain.protocol)) throw failure("PROJECT_SDK_MISMATCH", "工程锁定的 SDK 或内置协议与当前 profile 不一致", {
1731
1726
  projectRoot: root,
1732
1727
  expected: profile,
1733
1728
  actual: lock
@@ -1766,39 +1761,58 @@ function assertInstalledPackage(actual, name, expected, root) {
1766
1761
  installed: actual?.version
1767
1762
  }, ["按工程锁定信息恢复依赖并重新安装,再重新构建。"]);
1768
1763
  }
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;
1764
+ /** 名称和字节同时参与摘要;禁止通过协议资产链接借用其他安装。 */
1765
+ async function schemaDigest(directory) {
1766
+ const hash = createHash("sha256");
1767
+ const paths = [];
1768
+ async function visit(path) {
1769
+ const entry = await lstat(path);
1770
+ if (entry.isSymbolicLink()) throw new Error("SDK 协议资产不允许符号链接");
1771
+ if (entry.isDirectory()) for (const name of (await readdir(path)).sort()) await visit(join(path, name));
1772
+ else if (entry.isFile()) paths.push(path);
1773
+ else throw new Error("SDK 协议资产必须是普通文件");
1774
+ }
1775
+ await visit(directory);
1776
+ if (!paths.length) throw new Error("SDK 协议资产为空");
1777
+ for (const path of paths.sort()) {
1778
+ const bytes = await readFile(path);
1779
+ hash.update(relative(directory, path).split(sep).join("/"));
1780
+ hash.update("\0");
1781
+ hash.update(String(bytes.length));
1782
+ hash.update("\0");
1783
+ hash.update(bytes);
1777
1784
  }
1785
+ return `sha256:${hash.digest("hex")}`;
1786
+ }
1787
+ async function assertEmbeddedProtocol(sdkPath, toolchain, root) {
1788
+ const sdkRoot = dirname(await realpath(sdkPath));
1778
1789
  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
- }
1790
+ const embedded = JSON.parse(await readFile(join(sdkRoot, "assets/toolchain.json"), "utf8"));
1791
+ 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 内置协议或执行工具链元数据与当前执行器不一致");
1792
+ for (const directory of ["schemas", "assets/schemas"]) if (await schemaDigest(join(sdkRoot, directory)) !== embedded.protocol.digest) throw new Error("SDK 内置协议资产已漂移");
1788
1793
  } catch (error) {
1789
- if (error.cliCode) throw error;
1794
+ throw failure("PROJECT_SDK_MISMATCH", "工程 SDK 缺少有效的自包含协议资产或摘要不一致", {
1795
+ projectRoot: root,
1796
+ package: PACKAGES.sdk,
1797
+ cause: error.message
1798
+ }, ["在当前工程安装正确的 SDK 完整包,再重新构建;不能借用祖先目录或旧 contracts 包。"]);
1790
1799
  }
1791
- throw failure("PROJECT_SDK_MISMATCH", "工程 SDK 缺少自身可解析的配套 contracts,不能借用祖先目录或 CLI 的依赖", {
1792
- projectRoot: root,
1793
- package: PACKAGES.contracts
1794
- }, ["在该 Widget 工程目录重新安装依赖,并保留 SDK 自身的传递依赖。"]);
1795
1800
  }
1796
- /** SDK 必须由工程直接安装,contracts 从该 SDK 的真实依赖核对。 */
1801
+ /** SDK 必须由工程直接安装;协议只能来自该 SDK 自己的冻结资产。 */
1797
1802
  async function validateProjectToolchain(projectRoot, toolchain, { requireInstalled = true, requireLock = true } = {}) {
1798
1803
  const root = resolve(projectRoot);
1799
1804
  const lock = await readLock(root, toolchain, requireLock);
1800
1805
  const pkg = await json(join(root, "package.json"), "PROJECT_SDK_MISMATCH", ["恢复工程 package.json 中的精确 SDK 依赖。"]);
1801
1806
  if (!record$1(pkg)) throw failure("PROJECT_SDK_MISMATCH", "工程 package.json 必须是对象", { projectRoot: root }, ["恢复工程 package.json 中的精确 SDK 依赖。"]);
1807
+ for (const section of [
1808
+ "dependencies",
1809
+ "devDependencies",
1810
+ "optionalDependencies",
1811
+ "peerDependencies"
1812
+ ]) 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 入口", {
1813
+ projectRoot: root,
1814
+ package: name
1815
+ }, ["作者工程统一依赖 SDK;独立 CLI 请在工具目录或通过 npx 使用,Contracts 独立包供 Host 等消费者使用。保留作者源码,在独立候选中移除重复依赖、重新安装和构建。"]);
1802
1816
  const declared = {};
1803
1817
  const installed = {};
1804
1818
  for (const [key, name] of Object.entries(PACKAGES)) {
@@ -1821,53 +1835,22 @@ async function validateProjectToolchain(projectRoot, toolchain, { requireInstall
1821
1835
  const actual = await json(path, "PROJECT_SDK_MISMATCH", ["在该 Widget 工程目录安装依赖,再重试;父目录或 CLI 的安装不能替代工程安装。"]);
1822
1836
  assertInstalledPackage(actual, name, expected, root);
1823
1837
  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
- }
1838
+ for (const name of ["@dp-bohrium/widget-contracts", "@dp-bohrium/widget-cli"]) if ([
1839
+ "dependencies",
1840
+ "optionalDependencies",
1841
+ "peerDependencies"
1842
+ ].some((section) => actual[section]?.[name] !== void 0)) throw failure("PROJECT_SDK_MISMATCH", "工程 SDK 仍包含独立协议或 CLI 运行依赖,不符合当前自包含发布契约", {
1843
+ projectRoot: root,
1844
+ package: name
1845
+ }, ["安装当前自包含 SDK 包,再重新构建。"]);
1846
+ await assertEmbeddedProtocol(path, toolchain, root);
1836
1847
  }
1837
1848
  return {
1838
1849
  projectRoot: root,
1839
1850
  profile: { ...toolchain.profile },
1840
1851
  declared,
1841
1852
  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
- }] : [],
1853
+ deprecations: [],
1871
1854
  dependenciesVerified: requireInstalled,
1872
1855
  lock
1873
1856
  };
@@ -1877,10 +1860,10 @@ async function writeProjectToolchain(projectRoot, toolchain) {
1877
1860
  const existing = await readLock(root, toolchain, false);
1878
1861
  if (existing) return existing;
1879
1862
  const value = {
1880
- formatVersion: 1,
1863
+ formatVersion: 2,
1881
1864
  profileId: toolchain.profile.id,
1882
1865
  sdk: toolchain.profile.sdk,
1883
- contracts: toolchain.profile.contracts,
1866
+ protocol: toolchain.protocol,
1884
1867
  createdWithCli: toolchain.cli
1885
1868
  };
1886
1869
  await mkdir(root, { recursive: true });
@@ -1921,6 +1904,7 @@ function receiptToolchain(toolchain) {
1921
1904
  return {
1922
1905
  cli: toolchain.cli,
1923
1906
  profile: toolchain.profile,
1907
+ protocol: toolchain.protocol,
1924
1908
  digests: toolchain.digests
1925
1909
  };
1926
1910
  }
@@ -1965,7 +1949,7 @@ async function writeBuildReceipt(projectRoot, toolchain, { inputsBefore } = {})
1965
1949
  const outputs = await fingerprint(result.projectRoot, { outputs: true });
1966
1950
  if (outputs.files.length === 0) throw failure("BUILD_RECEIPT_MISMATCH", "构建目录 dist 没有可记录的产物", { projectRoot: result.projectRoot }, ["执行标准 build,确认 dist 产物存在后再打包。"]);
1967
1951
  const receipt = {
1968
- formatVersion: 1,
1952
+ formatVersion: 2,
1969
1953
  toolchain: receiptToolchain(toolchain),
1970
1954
  dependencies: result.installed,
1971
1955
  inputs,
@@ -1984,7 +1968,7 @@ async function assertBuildReceipt(projectRoot, toolchain) {
1984
1968
  };
1985
1969
  const receipt = await json(join(root, BUILD_RECEIPT_FILE), "BUILD_RECEIPT_MISMATCH", ["先执行 bohr-widget build,或去掉 pack 的 --no-build。"]);
1986
1970
  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 工具链或实际依赖与本次执行不一致");
1971
+ 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
1972
  let inputs;
1989
1973
  let outputs;
1990
1974
  try {
@@ -2635,7 +2619,6 @@ export { activate };
2635
2619
  name: "files.read",
2636
2620
  limits: {
2637
2621
  bytesPerRequest: 65536,
2638
- bytesPerRun: 262144,
2639
2622
  callsPerMinute: 60
2640
2623
  }
2641
2624
  }
@@ -2758,12 +2741,11 @@ function getSchemaPath(name = "widget-manifest.schema.json") {
2758
2741
  const toolchain = getToolchain();
2759
2742
  const packageJson = { version: toolchain.cli };
2760
2743
  const sdkPackage = { version: toolchain.profile.sdk };
2761
- const contractsPackage = { version: toolchain.profile.contracts };
2762
2744
  function usage(path = []) {
2763
2745
  return renderHelp(path, {
2764
2746
  cli: packageJson.version,
2765
2747
  sdk: sdkPackage.version,
2766
- contracts: contractsPackage.version,
2748
+ protocol: toolchain.protocol,
2767
2749
  packageName: toolchain.packageName,
2768
2750
  documentation: getDocumentation(),
2769
2751
  generatedProjectNode: GENERATED_PROJECT_NODE
@@ -2914,7 +2896,7 @@ async function commandIntegration(options) {
2914
2896
  const result = {
2915
2897
  ok: true,
2916
2898
  command: "integration",
2917
- interfaceVersion: 2,
2899
+ interfaceVersion: 3,
2918
2900
  requirements: {
2919
2901
  node: ">=20",
2920
2902
  generatedProjectNode: GENERATED_PROJECT_NODE
@@ -3482,9 +3464,9 @@ async function commandPack(directory, options) {
3482
3464
  const warnings = [];
3483
3465
  if (options.includePreviewFixtures && !hasFixtures) warnings.push("使用了 --include-preview-fixtures,但 preview/fixtures.json 不存在,ZIP 未包含任何 fixtures。");
3484
3466
  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);
3467
+ const prepared = prepareWidgetPackage(result, { includePreviewFixtures: fixturesIncluded });
3468
+ warnings.push(...oversizedAssetWarnings(prepared.files));
3469
+ const bundle = prepared.archive;
3488
3470
  await mkdir(dirname(destination), { recursive: true });
3489
3471
  await writeFile(destination, bundle);
3490
3472
  const artifact = {
@@ -3492,12 +3474,12 @@ async function commandPack(directory, options) {
3492
3474
  command: "pack",
3493
3475
  projectRoot: result.projectRoot,
3494
3476
  path: destination,
3495
- bytes: bundle.byteLength,
3496
- sha256: `sha256:${createHash("sha256").update(bundle).digest("hex")}`,
3477
+ bytes: prepared.bytes,
3478
+ sha256: prepared.sha256,
3497
3479
  toolchain: {
3498
3480
  cli: packageJson.version,
3499
3481
  sdk: sdkPackage.version,
3500
- contracts: contractsPackage.version
3482
+ protocol: toolchain.protocol
3501
3483
  },
3502
3484
  ...compatibility,
3503
3485
  hostCompatibility: await assertHostCompatibility(options.hostCompat, toolchain),
@@ -3553,10 +3535,7 @@ async function commandMigrate(positional, options) {
3553
3535
  if (action === "scaffold") {
3554
3536
  if (!options.output) throw new Error("migrate dsh scaffold 需要 --out <widget-dir>");
3555
3537
  const hostCompatibility = await assertHostCompatibility(options.hostCompat, toolchain);
3556
- const result = await scaffoldDshWidget(input, options.output, {
3557
- sdkVersion: sdkPackage.version,
3558
- contractsVersion: contractsPackage.version
3559
- });
3538
+ const result = await scaffoldDshWidget(input, options.output, { sdkVersion: sdkPackage.version });
3560
3539
  await writeProjectToolchain(result.projectRoot, toolchain);
3561
3540
  result.profile = toolchain.profile;
3562
3541
  result.hostCompatibility = hostCompatibility;
@@ -3575,7 +3554,7 @@ async function commandDoctor(directory, options) {
3575
3554
  cli: packageJson.version,
3576
3555
  node: process.versions.node,
3577
3556
  sdk: sdkPackage.version,
3578
- contracts: contractsPackage.version,
3557
+ protocol: toolchain.protocol,
3579
3558
  project: root,
3580
3559
  packageJson: existsSync(packagePath),
3581
3560
  manifest: existsSync(manifestPath),
@@ -3650,7 +3629,7 @@ function commandVersion(options) {
3650
3629
  command: "version",
3651
3630
  cli: packageJson.version,
3652
3631
  sdk: sdkPackage.version,
3653
- contracts: contractsPackage.version
3632
+ protocol: toolchain.protocol
3654
3633
  };
3655
3634
  if (options.json) console.log(JSON.stringify(result, null, 2));
3656
3635
  else console.log(`${result.cli} (SDK ${result.sdk})`);