@doubao-dev/cli 0.0.35 → 0.0.36

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.
Files changed (142) hide show
  1. package/dist/1232.js +1 -0
  2. package/dist/1264.js +1 -0
  3. package/dist/1611.js +2 -0
  4. package/dist/2232.js +60 -0
  5. package/dist/2507.js +1 -0
  6. package/dist/275.js +5 -8
  7. package/dist/2932.js +1 -1
  8. package/dist/4525.js +1 -1
  9. package/dist/4880.js +1 -1
  10. package/dist/4931.js +1 -1
  11. package/dist/{3688.js → 5887.js} +3 -3
  12. package/dist/6438.js +140 -0
  13. package/dist/6976.js +280 -0
  14. package/dist/{8981.js.LICENSE.txt → 6976.js.LICENSE.txt} +108 -0
  15. package/dist/7410.js +1 -2
  16. package/dist/@byted-doubao-apps/create.js +1 -1
  17. package/dist/@byted-doubao-apps/kit.js +1 -1
  18. package/dist/@byted-doubao-apps/login.js +2 -2
  19. package/dist/@byted-doubao-apps/login~1.js +2 -2
  20. package/dist/@byted-doubao-apps/template-empty/package.json +3 -3
  21. package/dist/@byted-doubao-apps/template-starter/package.json +3 -3
  22. package/dist/@byted-hdt/cli.js +1 -1
  23. package/dist/@inquirer/select.js +1 -1
  24. package/dist/{assets/web-sdk-debugger/static/wasm/eaf690f2cd.module.wasm → @lynx-js/static/wasm/77fb77f77f.module.wasm} +0 -0
  25. package/dist/@lynx-js/{web-core-canary.js → web-core.js} +2 -2
  26. package/dist/app.js +1 -1
  27. package/dist/assets/web-sdk-debugger/__doubao_web_sdk_native_modules/applet-bridge-module-core.js +1 -1
  28. package/dist/assets/web-sdk-debugger/index.html +1 -1
  29. package/dist/assets/web-sdk-debugger/preact-devtools/index.js +4 -1
  30. package/dist/assets/web-sdk-debugger/static/css/index.ef5d8bc5ad.css +1 -0
  31. package/dist/assets/web-sdk-debugger/static/js/{682.de47e82f6b.js → 426.53c43a8594.js} +2 -2
  32. package/dist/assets/web-sdk-debugger/static/js/479.26e0b1d922.js +1829 -0
  33. package/dist/assets/web-sdk-debugger/static/js/async/503.259fed5610.js +1 -0
  34. package/dist/assets/web-sdk-debugger/static/js/async/{legacy-wasm-js.bacc8b5564.js → legacy-wasm-js.9b9367f818.js} +2 -2
  35. package/dist/assets/web-sdk-debugger/static/js/async/lynx-core-chunk.7f5e94dfae.js +5 -0
  36. package/dist/assets/web-sdk-debugger/static/js/async/web-core-main-chunk.f78260697f.js +1 -0
  37. package/dist/assets/web-sdk-debugger/static/js/async/web-core-markup-encoder.33c43c480e.js +4 -0
  38. package/dist/assets/web-sdk-debugger/static/js/async/web-core-template-loader-thread.ba290b32d7.js +4 -0
  39. package/dist/assets/web-sdk-debugger/static/js/async/web-core-worker-chunk.9a5989b104.js +1 -0
  40. package/dist/assets/web-sdk-debugger/static/js/async/web-elements.3fbd53918e.js +365 -0
  41. package/dist/assets/web-sdk-debugger/static/js/async/xmarkdown-deps.efd0ffb051.js +5 -0
  42. package/dist/assets/web-sdk-debugger/static/js/async/{xmarkdown-deps.3ea5672b2c.js.LICENSE.txt → xmarkdown-deps.efd0ffb051.js.LICENSE.txt} +1 -1
  43. package/dist/assets/web-sdk-debugger/static/js/index.b6e5c76345.js +44 -0
  44. package/dist/assets/web-sdk-debugger/static/js/lib-polyfill.c91181f230.js +1 -0
  45. package/dist/assets/web-sdk-debugger/static/wasm/{69a8ba8eb9.module.wasm → 4c402c7981.module.wasm} +0 -0
  46. package/dist/assets/web-sdk-debugger/static/wasm/{03b02f9e5a.module.wasm → 72aaf7d0aa.module.wasm} +0 -0
  47. package/dist/{@lynx-js/static/wasm/eaf690f2cd.module.wasm → assets/web-sdk-debugger/static/wasm/77fb77f77f.module.wasm} +0 -0
  48. package/dist/assets/web-sdk-debugger/wsd/doubao-apps-api.template.js +0 -0
  49. package/dist/assets/web-sdk-debugger/wsd/doubao-apps-framework.template.js +0 -0
  50. package/dist/assets/web-sdk-debugger/wsd/doubao-apps-react-dev.template.js +0 -0
  51. package/dist/assets/web-sdk-debugger/wsd/doubao-apps-react.template.js +0 -0
  52. package/dist/browser.js +1 -1
  53. package/dist/build.js +1 -1
  54. package/dist/build~1.js +10 -10
  55. package/dist/check.js +1 -1
  56. package/dist/client.js +1 -0
  57. package/dist/client~1.js +1 -0
  58. package/dist/components-loader.js +1 -1
  59. package/dist/demo-server.js +2 -2
  60. package/dist/demo.js +2 -2
  61. package/dist/dev-config.js +2 -2
  62. package/dist/dev-shell.js +1 -1
  63. package/dist/dev.js +19 -16
  64. package/dist/explore.js +10 -0
  65. package/dist/gen-explore.js +1 -1
  66. package/dist/gen-trajectory.js +1 -1
  67. package/dist/info.js +2 -2
  68. package/dist/init.js +4 -4
  69. package/dist/ink.js +1 -1
  70. package/dist/inquirer.js +1 -1
  71. package/dist/json-file.js +2 -2
  72. package/dist/legacy-status.js +1 -1
  73. package/dist/legacy-upload.js +1 -1
  74. package/dist/lepus.js +1 -1
  75. package/dist/login.js +2 -1
  76. package/dist/main.js +1 -1
  77. package/dist/{manifest-mcp-config.js → manifest-headers.js} +1 -1
  78. package/dist/ora.js +1 -1
  79. package/dist/portal.js +1 -1
  80. package/dist/project-layout.js +1 -1
  81. package/dist/project.js +1 -1
  82. package/dist/prompt.js +8 -8
  83. package/dist/prompts.js +1 -1
  84. package/dist/qrcode.js +1 -0
  85. package/dist/report.js +1 -1
  86. package/dist/run-registry.js +1 -1
  87. package/dist/run.js +321 -321
  88. package/dist/sandbox.js +1 -1
  89. package/dist/scan.js +1 -1
  90. package/dist/sdk.js +192 -59
  91. package/dist/sdk~1.js +66 -58
  92. package/dist/server.js +10 -10
  93. package/dist/skill.js +1 -1
  94. package/dist/skills.js +1 -1
  95. package/dist/skills~1.js +1 -1
  96. package/dist/status.js +1 -1
  97. package/dist/status~1.js +2 -2
  98. package/dist/stop.js +1 -1
  99. package/dist/sync.js +1 -1
  100. package/dist/trajectory.js +3 -0
  101. package/dist/update.js +1 -1
  102. package/dist/upgrade.js +1 -1
  103. package/dist/workspace.js +1 -1
  104. package/dist/yaml.js +1 -1
  105. package/package.json +7 -6
  106. package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/02-/347/263/273/347/273/237.md +2 -2
  107. package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/06-/350/267/257/347/224/261.md +4 -0
  108. package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/07-/347/225/214/351/235/242.md +8 -0
  109. package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/26-/345/237/272/347/241/200/344/277/241/346/201/257.md +2 -1
  110. package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/33-/345/261/217/345/271/225.md +124 -8
  111. package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/groups.md +1 -1
  112. package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/quick-reference.md +2 -1
  113. package/skills/doubao-agentic-service-development/references/frontend/examples/page-widget-basics.md +1 -0
  114. package/skills/doubao-agentic-service-development/references/frontend/guides/client-tools-and-events.md +209 -0
  115. package/skills/doubao-agentic-service-development/references/frontend/guides/component-development.md +7 -1
  116. package/skills/doubao-agentic-service-development/references/frontend/guides/debugger-mcp.md +1 -1
  117. package/skills/doubao-agentic-service-development/references/frontend/widget-templates/overview.md +13 -9
  118. package/skills/doubao-agentic-service-development/references/frontend/widget-templates/props.md +26 -1
  119. package/skills/doubao-agentic-service-development/references/frontend-dev.md +2 -0
  120. package/dist/2168.js +0 -60
  121. package/dist/318.js +0 -1
  122. package/dist/3974.js +0 -151
  123. package/dist/6427.js +0 -126
  124. package/dist/7417.js +0 -204
  125. package/dist/7417.js.LICENSE.txt +0 -107
  126. package/dist/7945.js +0 -1
  127. package/dist/8981.js +0 -78
  128. package/dist/assets/web-sdk-debugger/static/css/index.7c65607402.css +0 -1
  129. package/dist/assets/web-sdk-debugger/static/js/670.8a8f0f7d57.js +0 -1829
  130. package/dist/assets/web-sdk-debugger/static/js/async/503.cf61731bba.js +0 -1
  131. package/dist/assets/web-sdk-debugger/static/js/async/lynx-core-chunk.afc1ded023.js +0 -5
  132. package/dist/assets/web-sdk-debugger/static/js/async/web-core-main-chunk.7fe9af852c.js +0 -1
  133. package/dist/assets/web-sdk-debugger/static/js/async/web-core-markup-encoder.f81d6d2cae.js +0 -4
  134. package/dist/assets/web-sdk-debugger/static/js/async/web-core-template-loader-thread.4a49f8a286.js +0 -4
  135. package/dist/assets/web-sdk-debugger/static/js/async/web-core-worker-chunk.c315fd6753.js +0 -1
  136. package/dist/assets/web-sdk-debugger/static/js/async/web-elements.43d1e29387.js +0 -365
  137. package/dist/assets/web-sdk-debugger/static/js/async/xmarkdown-deps.3ea5672b2c.js +0 -5
  138. package/dist/assets/web-sdk-debugger/static/js/index.9f626ba3a2.js +0 -44
  139. package/dist/assets/web-sdk-debugger/static/js/lib-polyfill.9daa7c863e.js +0 -1
  140. package/dist/simulator-client.js +0 -1
  141. /package/dist/{7410.js.LICENSE.txt → 1611.js.LICENSE.txt} +0 -0
  142. /package/dist/assets/web-sdk-debugger/static/js/{670.8a8f0f7d57.js.LICENSE.txt → 479.26e0b1d922.js.LICENSE.txt} +0 -0
@@ -36,7 +36,7 @@
36
36
  <tbody>
37
37
  <tr><td>Android</td><td>支持</td></tr>
38
38
  <tr><td>iOS</td><td>支持</td></tr>
39
- <tr><td>PC</td><td>不支持</td></tr>
39
+ <tr><td>PC</td><td>支持</td></tr>
40
40
  <tr><td>HarmonyOS</td><td>不支持</td></tr>
41
41
  </tbody>
42
42
  </table>
@@ -112,6 +112,7 @@ console.log(result.platform, result.benchmarkLevel);
112
112
 
113
113
  - **Android**:`abi`、`deviceAbi`、`cpuType` 仅 Android 返回
114
114
  - **iOS**:不返回 `abi`、`deviceAbi`、`cpuType`
115
+ - **PC**:Flow Web 浏览器的 `platform` 返回 `web`;Windows、macOS 桌面客户端分别返回 `windows`、`mac`,不返回 Android 专属字段
115
116
 
116
117
  <a id="getdeviceinfosync"></a>
117
118
  ### getDeviceInfoSync()
@@ -9,6 +9,7 @@
9
9
  | API | 说明 |
10
10
  | --- | --- |
11
11
  | [getScreenBrightness](#getscreenbrightness) | 获取屏幕亮度。 |
12
+ | [setScreenBrightness](#setscreenbrightness) | 设置屏幕亮度。 |
12
13
  | [setKeepScreenOn](#setkeepscreenon) | 设置屏幕常亮状态。 |
13
14
  | [disableUserScreenRecord](#disableuserscreenrecord) | 禁止用户录屏。 |
14
15
  | [enableUserScreenRecord](#enableuserscreenrecord) | 允许用户录屏。 |
@@ -27,11 +28,6 @@
27
28
  ## 扫码预览
28
29
  ![扫码预览 getScreenBrightness](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=doubao%3A%2F%2Fdoubao_apps%3Fapp_id%3Ddb_1McM5Ni%26path%3D%252Fpages%252Fapi%252Fdevice%252Fget-screen-brightness%252Findex)
29
30
 
30
- ## 使用限制
31
-
32
- > [!WARNING]
33
- > **iOS**:豆包 iOS 暂不支持该接口,调用直接失败;iOS 上调用无法取得屏幕亮度。
34
-
35
31
  ## 支持版本
36
32
 
37
33
  前端库版本不低于 `0.0.19`。
@@ -44,7 +40,7 @@
44
40
  </thead>
45
41
  <tbody>
46
42
  <tr><td>Android</td><td>支持</td></tr>
47
- <tr><td>iOS</td><td>不支持</td></tr>
43
+ <tr><td>iOS</td><td>支持</td></tr>
48
44
  <tr><td>PC</td><td>不支持</td></tr>
49
45
  <tr><td>HarmonyOS</td><td>不支持</td></tr>
50
46
  </tbody>
@@ -64,7 +60,7 @@
64
60
 
65
61
  ## 使用说明
66
62
 
67
- - **Android**:返回值为归一化后的 0 到 1 亮度
63
+ - 返回值为归一化后的 0 到 1 亮度
68
64
 
69
65
  ## 调用方式
70
66
 
@@ -120,10 +116,121 @@ console.log(value);
120
116
  <tr><th>errNo</th><th>errMsg</th><th>说明</th><th>平台</th></tr>
121
117
  </thead>
122
118
  <tbody>
123
- <tr><td><code>102</code></td><td><code>internal error</code></td><td>内部错误</td><td>Android</td></tr>
119
+ <tr><td><code>102</code></td><td><code>internal error</code></td><td>内部错误</td><td>Android、iOS</td></tr>
120
+ </tbody>
121
+ </table>
122
+
123
+ <a id="setscreenbrightness"></a>
124
+ ### setScreenBrightness()
125
+
126
+ # setScreenBrightness
127
+
128
+ 设置屏幕亮度。
129
+
130
+ ## 扫码预览
131
+ ![扫码预览 setScreenBrightness](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=doubao%3A%2F%2Fdoubao_apps%3Fapp_id%3Ddb_1McM5Ni%26path%3D%252Fpages%252Fapi%252Fdevice%252Fget-screen-brightness%252Findex)
132
+
133
+ ## 支持版本
134
+
135
+ 前端库版本不低于 `0.4.0`。
136
+
137
+ ## 支持平台
138
+
139
+ <table>
140
+ <thead>
141
+ <tr><th>平台</th><th>支持情况</th></tr>
142
+ </thead>
143
+ <tbody>
144
+ <tr><td>Android</td><td>支持</td></tr>
145
+ <tr><td>iOS</td><td>支持</td></tr>
146
+ <tr><td>PC</td><td>不支持</td></tr>
147
+ <tr><td>HarmonyOS</td><td>不支持</td></tr>
148
+ </tbody>
149
+ </table>
150
+
151
+ ## 支持场景
152
+
153
+ <table>
154
+ <thead>
155
+ <tr><th>场景</th><th>支持情况</th></tr>
156
+ </thead>
157
+ <tbody>
158
+ <tr><td>页面</td><td>支持</td></tr>
159
+ <tr><td>卡片</td><td>不支持</td></tr>
160
+ </tbody>
161
+ </table>
162
+
163
+ ## 接入准备
164
+
165
+ ### 前置条件
166
+
167
+ - value 必须是 0 到 1 之间的有限数字
168
+
169
+ ## 使用说明
170
+
171
+ - 该设置仅在当前小程序生命周期内生效,退出后自动恢复原亮度
172
+
173
+ ## 调用方式
174
+
175
+ ### 异步 API
176
+
177
+ ```typescript
178
+ setScreenBrightness(params: SetScreenBrightnessParams): Promise<object>
179
+ ```
180
+
181
+ ## 入参
182
+
183
+ <table>
184
+ <thead>
185
+ <tr><th>名称</th><th>类型</th><th>必填</th><th>默认值</th><th>约束</th><th>说明</th></tr>
186
+ </thead>
187
+ <tbody>
188
+ <tr><td><code>value</code></td><td><code>number</code></td><td>是</td><td>-</td><td>取值范围 0 到 1,0 最暗,1 最亮</td><td>屏幕亮度值。</td></tr>
189
+ </tbody>
190
+ </table>
191
+
192
+ ## 调用示例
193
+
194
+ ```typescript
195
+ import { setScreenBrightness } from '@doubao-dev/framework/api';
196
+
197
+ await setScreenBrightness({ value: 0.8 });
198
+ ```
199
+
200
+ ## 成功返回
201
+
202
+ 无返回字段。
203
+
204
+ ### 返回示例
205
+
206
+ ```json
207
+ {}
208
+ ```
209
+
210
+ ## 错误处理
211
+
212
+ 错误对象和通用错误码见 [通用错误处理](./common-errors.md#错误返回)。
213
+
214
+ ### 错误码
215
+
216
+ #### 通用错误码
217
+
218
+ <table>
219
+ <thead>
220
+ <tr><th>errNo</th><th>errMsg</th><th>说明</th><th>平台</th></tr>
221
+ </thead>
222
+ <tbody>
223
+ <tr><td><code>102</code></td><td><code>internal error</code></td><td>内部错误</td><td>Android、iOS</td></tr>
224
+ <tr><td><code>103</code></td><td><code>feature not support</code></td><td>当前环境不支持该能力</td><td>Android、iOS</td></tr>
225
+ <tr><td><code>104</code></td><td><code>invalid parameter</code></td><td>参数不合法</td><td>Android、iOS</td></tr>
124
226
  </tbody>
125
227
  </table>
126
228
 
229
+ ## 平台差异
230
+
231
+ - **Android**:使用当前宿主窗口亮度,不修改系统全局亮度
232
+ - **iOS**:小程序进入后台时恢复系统亮度,回到前台时重新应用设置值
233
+
127
234
  <a id="setkeepscreenon"></a>
128
235
  ### setKeepScreenOn()
129
236
 
@@ -594,6 +701,15 @@ off();
594
701
 
595
702
  • **value**: `number` - 屏幕亮度值
596
703
 
704
+ <a id="setscreenbrightnessparams"></a>
705
+ ### SetScreenBrightnessParams
706
+
707
+ 设置屏幕亮度的请求参数。
708
+
709
+ #### Properties
710
+
711
+ • **value**: `number` - 屏幕亮度值
712
+
597
713
  <a id="setkeepscreenonparams"></a>
598
714
  ### SetKeepScreenOnParams
599
715
 
@@ -38,6 +38,6 @@
38
38
  | 日历 | 向系统日历添加事件和重复事件。 | 2 | [查看](./30-日历.md) |
39
39
  | 电话 | 拨打电话。 | 1 | [查看](./31-电话.md) |
40
40
  | 扫码 | 调起扫码并读取扫码结果。 | 1 | [查看](./32-扫码.md) |
41
- | 屏幕 | 屏幕亮度、常亮和截屏/录屏相关能力。 | 6 | [查看](./33-屏幕.md) |
41
+ | 屏幕 | 屏幕亮度、常亮和截屏/录屏相关能力。 | 7 | [查看](./33-屏幕.md) |
42
42
  | 震动 | 触发短震动和长震动。 | 2 | [查看](./34-震动.md) |
43
43
  | 文件系统 | 文件读写、目录管理和文件信息操作。 | 1 | [查看](./35-文件系统.md) |
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 这是豆包智能服务运行时 API,也称 Open API。默认从 `@doubao-dev/framework/api` 导入;本文件根据 `packages/open-api/src` 的导出结构自动生成,按模块列出 API 名称和说明。
4
4
 
5
- 覆盖 152 个函数。详细参数、返回值、示例和相关类型请查看 [豆包智能服务的端能力 API 分组目录](groups.md),精确字段也可按参数/结果类型名查看 IDE 类型提示或 `@doubao-dev/framework/api` 类型定义。
5
+ 覆盖 153 个函数。详细参数、返回值、示例和相关类型请查看 [豆包智能服务的端能力 API 分组目录](groups.md),精确字段也可按参数/结果类型名查看 IDE 类型提示或 `@doubao-dev/framework/api` 类型定义。
6
6
 
7
7
  ## 使用方式
8
8
 
@@ -406,6 +406,7 @@ iBeacon 搜索和结果读取能力。
406
406
  | API | 说明 |
407
407
  | --- | --- |
408
408
  | [getScreenBrightness](33-屏幕.md#getscreenbrightness) | 获取屏幕亮度。 |
409
+ | [setScreenBrightness](33-屏幕.md#setscreenbrightness) | 设置屏幕亮度。 |
409
410
  | [setKeepScreenOn](33-屏幕.md#setkeepscreenon) | 设置屏幕常亮状态。 |
410
411
  | [disableUserScreenRecord](33-屏幕.md#disableuserscreenrecord) | 禁止用户录屏。 |
411
412
  | [enableUserScreenRecord](33-屏幕.md#enableuserscreenrecord) | 允许用户录屏。 |
@@ -347,6 +347,7 @@ export default function RecommendList() {
347
347
  3. **卡片类型 (boxType)**
348
348
  - `inbox` - 普通卡片
349
349
  - `full_box` - 全宽卡片
350
+ - `custom_box` - 背景、圆角和描边由业务内容设置,标题栏仍遵循 `titleType`
350
351
 
351
352
  4. **消息交互**
352
353
  - 接收 AI 传入的数据
@@ -0,0 +1,209 @@
1
+ # 端工具、事件与页面上下文
2
+
3
+ ## 选择数据方向
4
+
5
+ | 能力 | 接入点 | 职责 |
6
+ | --- | --- | --- |
7
+ | Client Tool | `tools.json`、`app.config.ts.tools`、默认函数 handler | 执行端侧能力并返回工具结果 |
8
+ | Agent Event | `events.json`、业务 `SKILL.md` 事件占位符、`useAgentEvent` | 更新已打开页面 |
9
+ | Page Model Context | `useModelContext().setPageContext` | 提交当前页面完整状态,供后续模型轮次使用 |
10
+
11
+ 端工具不能直接读取其他 Page 的 React state;事件不会自动打开页面;提交模型上下文不会发起新一轮对话。
12
+
13
+ ## JSB 调用限制
14
+
15
+ 端工具在独立的 ToolRuntime 中执行,可调用的 JSB 受白名单限制。当前 Android 和 iOS 允许以下业务 JSB;表中名称是宿主方法名,业务仍通过 `@doubao-dev/framework/api` 中对应的公开 API 调用。
16
+
17
+ | 类别 | 允许的 JSB |
18
+ | --- | --- |
19
+ | 账号与登录 | `doubao.getAccountInfo`、`doubao.login` |
20
+ | 设置与授权状态 | `doubao.getSetting`、`doubao.getAppAuthorizeSetting`、`doubao.getSystemSetting` |
21
+ | 系统与设备 | `doubao.getSystemInfo`、`doubao.getDeviceInfo` |
22
+ | 网络与定位 | `doubao.request`、`doubao.getLocation` |
23
+ | 埋点 | `doubao.reportEvent` |
24
+ | 存储 | `doubao.setStorage`、`doubao.getStorage`、`doubao.removeStorage`、`doubao.clearStorage`、`doubao.getStorageInfo` |
25
+
26
+ 工具结果回传由 Framework 处理,业务只需返回符合协议的结果对象。
27
+
28
+ 不在白名单中的 JSB 会被拒绝,包括 `navigateTo`、`redirectTo`、`reLaunch`、`navigateBack`、`openPage` 等路由能力。SDK 导出了某个 API,或该 API 能在 Page / Widget 中使用,不代表它能在端工具中调用;需要页面跳转时,应在支持该路由能力的 Page / Widget 交互中完成。
29
+
30
+ 白名单放行也不代表调用必然成功:仍需满足接口权限、用户授权、宿主支持和限流等条件。在 `tools.json` 中声明 `permissions` 不能扩大端工具的 JSB 白名单;业务需要处理实际调用失败。
31
+
32
+
33
+
34
+ ## Schema 限制
35
+
36
+ 这里使用的是平台支持的 JSON Schema 子集,不支持 `enum`、数值上下界(`minimum` / `maximum`,即 min/max)等校验能力。不要在 schema 中添加这些约束;将可选值和取值范围写入字段 `description`,并在业务代码中校验。此限制同时适用于 `tools.json` 的 `inputSchema`、`outputSchema` 和 `events.json` 的 `payloadSchema`。
37
+
38
+ 优先使用基础结构字段 `type`、`properties`、`required`、`items` 和 `description`。描述中的约束不会自动执行:端工具在 handler 中检查输入,Page 在事件回调中检查 payload,输出也应符合声明的结果结构。
39
+
40
+ ## tools.json 与端工具注册
41
+
42
+ 在项目根目录声明 `tools.json`。`tools` 是非空数组;每项需要唯一 `name`、`description`、对象形式的 `inputSchema` 和 `outputSchema`。端工具显式设置 `tool_type: "client"`;省略时按远程工具处理。
43
+
44
+ ```json
45
+ {
46
+ "tools": [
47
+ {
48
+ "name": "calculate_total",
49
+ "description": "Calculate an amount in integer cents when the user explicitly provides unit price and quantity. Does not create orders or charge money.",
50
+ "tool_type": "client",
51
+ "inputSchema": {
52
+ "type": "object",
53
+ "properties": {
54
+ "unit_price_cents": { "type": "integer", "description": "Non-negative unit price in cents" },
55
+ "quantity": { "type": "integer", "description": "Positive item count" }
56
+ },
57
+ "required": ["unit_price_cents", "quantity"]
58
+ },
59
+ "outputSchema": {
60
+ "type": "object",
61
+ "properties": {
62
+ "total_cents": { "type": "integer" }
63
+ },
64
+ "required": ["total_cents"]
65
+ }
66
+ }
67
+ ]
68
+ }
69
+ ```
70
+
71
+ 将以下配置合入 `src/app.config.ts`,保留现有页面与卡片配置。`entry` 相对于 `src/`,注册名称与 `tools.json.name` 必须一致。
72
+
73
+ ```ts
74
+ import { defineAppConfig } from '@doubao-dev/framework/config';
75
+
76
+ export default defineAppConfig({
77
+ appId: 'your-app-id',
78
+ name: 'Amount Calculator',
79
+ tools: [{ entry: 'tools/calculate-total/index', name: 'calculate_total' }]
80
+ });
81
+ ```
82
+
83
+ 在 `src/tools/calculate-total/index.ts` 默认导出 handler,接收解析后的对象,返回结果对象或 Promise。以下示例只计算整数分金额,不下单、不扣款:
84
+
85
+ ```ts
86
+ export default function calculateTotal(input: Record<string, unknown>) {
87
+ const { unit_price_cents: unitPrice, quantity } = input;
88
+ if (
89
+ typeof unitPrice !== 'number' ||
90
+ !Number.isSafeInteger(unitPrice) ||
91
+ unitPrice < 0 ||
92
+ typeof quantity !== 'number' ||
93
+ !Number.isSafeInteger(quantity) ||
94
+ quantity <= 0
95
+ ) {
96
+ return {
97
+ isError: true,
98
+ content: [
99
+ { type: 'text', text: 'Provide a non-negative integer price and a positive integer quantity.' }
100
+ ]
101
+ };
102
+ }
103
+
104
+ // Integer cents avoid fractional currency rounding; reject unsafe totals before returning a result.
105
+ const total = unitPrice * quantity;
106
+ if (!Number.isSafeInteger(total)) {
107
+ return { isError: true, content: [{ type: 'text', text: 'The total exceeds the supported range.' }] };
108
+ }
109
+
110
+ return {
111
+ content: [{ type: 'text', text: `Total: ${total} cents. No order was placed.` }],
112
+ structuredContent: { total_cents: total }
113
+ };
114
+ }
115
+ ```
116
+
117
+ 结果必须包含文本块 `content` 数组;`structuredContent` 可为对象或对象数组,业务失败返回 `isError: true`。运行时的外形检查不替代业务校验。
118
+
119
+ 需要卡片时:声明 `_meta.ui.widgetId` 并匹配注册的 Widget ID;`outputSchema` 使用对象数组,实体顶层恰有一个字段标记 `x-db-is-entity-id: true`;handler 返回对应实体数组。`entity_type` 由运行时补充,不在 schema 中声明。使用 `same_conversation` 过期策略时,同一个实体 ID 字段还必须是唯一的 `x-db-is-refresh-key`。
120
+
121
+ ## events.json 与页面订阅
122
+
123
+ 在项目根目录声明 `events.json`。根对象的 `events` 数组中,每项包含 `name`、`description` 和对象形式的 `payloadSchema`:
124
+
125
+ ```json
126
+ {
127
+ "events": [
128
+ {
129
+ "name": "demo.pageDataUpdated",
130
+ "description": "Update the displayed title for the current page task when explicitly requested by the user.",
131
+ "payloadSchema": {
132
+ "type": "object",
133
+ "properties": {
134
+ "task_id": { "type": "string", "description": "The target page task ID" },
135
+ "title": { "type": "string", "description": "The title explicitly requested by the user" }
136
+ },
137
+ "required": ["task_id", "title"]
138
+ }
139
+ }
140
+ ]
141
+ }
142
+ ```
143
+
144
+ 在开发者的业务 `SKILL.md` 中加入事件占位符;业务 Skill 的存放位置按项目组织,不由本开发 Skill 指定。事件名必须与声明和订阅一致:
145
+
146
+ ```text
147
+ 仅当用户明确要求修改已打开页面的标题时,发送 demo.pageDataUpdated 事件。
148
+ 目标任务 ID 使用当前页面上下文或用户明确提供的值,标题使用用户要求的内容。
149
+ 缺少必要信息时先追问。普通问答不发送此事件,也不声称该事件会保存服务端数据。
150
+
151
+ {{event:demo.pageDataUpdated}}
152
+ ```
153
+
154
+ 将页面注册到 `app.config.ts.pages`,打开时传入 `taskId`。`task_id` 是业务目标标识,Framework 不会自动用它筛选页面:
155
+
156
+ ```tsx
157
+ import { useAgentEvent, useState, useViewData } from '@doubao-dev/framework';
158
+
159
+ export default function EventDemoPage() {
160
+ const { taskId } = useViewData<{ taskId?: string }>();
161
+ const [title, setTitle] = useState('Original title');
162
+
163
+ useAgentEvent('demo.pageDataUpdated', payload => {
164
+ // Event schemas do not enforce page ownership; validate the target before changing local state.
165
+ if (typeof taskId !== 'string' || !taskId || payload.task_id !== taskId) return;
166
+ if (typeof payload.title !== 'string' || !payload.title.trim()) {
167
+ console.error('Invalid demo.pageDataUpdated title');
168
+ return;
169
+ }
170
+ setTitle(payload.title);
171
+ });
172
+
173
+ if (!taskId) return <text>Missing taskId</text>;
174
+ return <text>{title}</text>;
175
+ }
176
+ ```
177
+
178
+ Framework 自动调用可选的 App `onAgentEvent` 后分发给订阅者,不要手动重复转发。Hook 随挂载订阅、卸载取消,不按页面可见性或栈顶筛选,也不重放历史事件。业务应校验目标、保证重复事件处理幂等,异步任务自行捕获错误。
179
+
180
+ ## 页面模型上下文
181
+
182
+ 在上面的页面中导入 `useEffect`、`useModelContext`,在条件返回前加入:
183
+
184
+ ```tsx
185
+ const modelContext = useModelContext();
186
+
187
+ useEffect(() => {
188
+ if (typeof taskId !== 'string' || !taskId) return;
189
+ void modelContext.setPageContext({
190
+ taskId,
191
+ pageInfo: {
192
+ context_schema: 'demo.page.v1',
193
+ task_id: taskId,
194
+ title
195
+ }
196
+ }).catch(error => {
197
+ console.error('Failed to update page context', error);
198
+ });
199
+ }, [modelContext, taskId, title]);
200
+ ```
201
+
202
+ 每次提交完整 `pageInfo`,不依赖局部字段合并。控制器稳定,但不会自动同步 React state;通过依赖最新 state 的 Effect 提交。处理调用失败,在下一轮对话确认模型使用最新页面值。此 Hook 的 `{ taskId, pageInfo }` 与 `/api` 的 `updateModelContext({ taskId?, entityId?, content })` 参数不同。
203
+
204
+ ## 调试检查
205
+
206
+ - 端工具:先固定参数直接运行,再检查真实调用结果;非法输入应返回业务错误。
207
+ - 页面事件:先打开页面,再手动触发;错误目标和非法 payload 不更新状态;随后验证 Agent 事件链路。
208
+ - 页面上下文:修改状态并提交后,在下一轮对话核对最新值。
209
+ - Web 模拟器通过不代表目标宿主已验证;需要读取运行现场时参考[Debugger MCP](debugger-mcp.md)。
@@ -289,7 +289,7 @@ export default defineAppConfig({
289
289
  id: 'my-widget', // 卡片唯一标识
290
290
  name: '我的卡片', // 卡片名称
291
291
  description: '卡片功能描述', // 卡片描述
292
- boxType: 'inbox', // 卡片类型: inbox | full_box
292
+ boxType: 'inbox', // 卡片类型: inbox | full_box | custom_box
293
293
  border: true,
294
294
  keywords: ['demo', 'widget'],
295
295
  titleType: 'none' // 不展示标题栏
@@ -390,6 +390,12 @@ export default defineAppConfig({
390
390
  });
391
391
  ```
392
392
 
393
+ **3. custom_box - 自定义容器样式**
394
+
395
+ 在 `src/app.config.ts` 的 Widget entry 上配置 `boxType: 'custom_box'`,构建后 Manifest 对应
396
+ `boxType: 4`。容器不添加默认背景、圆角和描边,由业务小程序的内容样式设置;标题栏仍由
397
+ `titleType` 控制。未配置时仍默认为 `inbox`。
398
+
393
399
  ### ViewData 类型
394
400
 
395
401
  Widget viewData 通过 `useViewData<T>()` 的泛型参数和 TypeScript 接口表达。数据结构应尽量贴近所选模板的 props
@@ -44,7 +44,7 @@ Page / Widget 运行现场。它不替代用户业务 MCP server,只描述 deb
44
44
  - 方法:`POST /__wsd_mcp`。
45
45
  - 会话:当前实现不生成 session id,每次请求创建一次 MCP server / transport。
46
46
  - CORS 预检:`OPTIONS /__wsd_mcp` 返回 204。
47
- - 数据来源:调试台 UI 通过 `/__wsd_connection` WebSocket 同步运行期快照、接收控制命令和 Sandbox 事件,查询 tools 从 debugger server 内存中的最新快照读取数据。`/__agent_trace` 保留为 HTTP 快照访问接口。
47
+ - 数据来源:调试台 UI 通过 `/__wsd_connection` WebSocket 同步运行期快照、接收控制命令和 Sandbox 事件,查询 tools 从 debugger server 内存中的最新快照读取数据。`GET /__agent_trace` 保留为只读的 HTTP 快照访问接口。
48
48
  - 浏览器控制:调试台通过共享 WebSocket 通道接收控制命令;渲染命令会在目标完成渲染且生成匹配命令的新 DOM 快照后回执。
49
49
 
50
50
  Web SDK Debugger 连接用户业务 MCP endpoint 时使用自动版本协商:优先选择 `2026-07-28`,对只支持 2025-era
@@ -7,7 +7,7 @@
7
7
  1. **一个 widget 一张卡片**:入口组件直接 return 模板组件,不要再包 `view` / `scroll-view`。
8
8
  2. **统一从 `@doubao-dev/template` 导入**模板组件和类型;新 Widget 默认直接导出组件函数。
9
9
  3. **优先用模板,不手搓卡片**:先按选型表找模板并使用其公开 Props;匹配不上时按模板能力或新设计需求确认。
10
- 4. **新代码不传 `children`**:部分模板和列表项仍保留该属性,但已经废弃,只用于兼容旧项目。生成或修改代码时,改用当前模板的结构化字段或已声明的具名 `ReactNode` 字段;没有匹配字段时按模板能力或新设计需求确认。
10
+ 4. **新代码不传 `children`**:改用当前模板的结构化字段或已声明的具名 `ReactNode` 字段;一个业务语义需要多个已知模块时使用 `CompositeCard`,不要自行开放卡片布局。
11
11
  5. **显式标注列表类型**:每个模板导出 `XxxProps` 和列表项类型,例如 `ContentCardItem`、`CheckoutCardProductItem`。
12
12
  6. **header/footer 统一约定**:带标题栏和底部操作区的模板统一使用 `header` / `footer`。`header` 只控制标题栏,`footer` 只控制底部按钮,二者不影响内容区展示数量。
13
13
  7. **底部按钮对象**:`footer.primaryActionButton` / `footer.secondaryActionButton` 内传 `text`、`onClick`、`disabled`、`loading`、`throttle`。只传一个按钮时占据整行。
@@ -19,14 +19,15 @@
19
19
 
20
20
  按业务意图依次判断:
21
21
 
22
- 1. 核对并提交订单:通用商品、机票或出行票务订单都使用 `CheckoutCard`。
23
- 2. 展示地图、路线、位置或叫车状态:用 `MapCard`。
24
- 3. 展示多条交通行程:用 `TransitCard`。
25
- 4. 在多个报价、权益或服务方案中选择:用 `PriceActionCard`。
26
- 5. 让用户在候选项中确认或执行固定跳转:用 `AskHumanCard`;单个或两个全宽跳转项使用 `variant="jump"`。
27
- 6. 其余图文、商品或服务列表:用 `ContentCard`。
22
+ 1. 一个业务语义需要组合多个模板已知模块,且没有完全匹配的具名模板:用 `CompositeCard`。
23
+ 2. 核对并提交订单:通用商品、机票或出行票务订单都使用 `CheckoutCard`。
24
+ 3. 展示地图、路线、位置或叫车状态:用 `MapCard`。
25
+ 4. 展示多条交通行程:用 `TransitCard`。
26
+ 5. 在多个报价、权益或服务方案中选择:用 `PriceActionCard`。
27
+ 6. 让用户在候选项中确认或执行固定跳转:用 `AskHumanCard`;单个或两个全宽跳转项使用 `variant="jump"`。
28
+ 7. 其余图文、商品或服务列表:用 `ContentCard`。
28
29
 
29
- 不能按以上意图选型时,不要直接拼新的卡片外壳。先查现有模板的公开 Props;无法表达时将其作为模板能力或新设计需求确认。
30
+ 不能按以上意图选型时,不要直接拼新的卡片外壳。先查 `CompositeCard` 的 section 白名单;白名单仍无法表达时,将其作为模板能力或新设计需求确认。
30
31
 
31
32
  ## Widget 骨架
32
33
 
@@ -74,6 +75,7 @@ export default function ProductCard() {
74
75
  | 下单/支付确认(通用电商) | `CheckoutCard` | 商品摘要 + 提单信息 + 费用汇总 + 合计 + 操作按钮 |
75
76
  | 机票/出行下单确认 | `CheckoutCard` | 商品或票务摘要 + 订单信息 + 费用明细 + 合计 + 操作按钮 |
76
77
  | 交通票务推荐列表 | `TransitCard` | 多条出发/到达行程,全量展示 items |
78
+ | 车票预订等复合业务 | `CompositeCard` | 在一个标准卡片外壳中按顺序组合行程、选项组等已知模块 |
77
79
  | 让用户在多个候选里人工确认 | `AskHumanCard` | 一组可点击选项,跳过入口也通过 items 表达 |
78
80
  | 单个全宽操作按钮(任务态) | `AskHumanCard`(`variant="jump"`) | 一个可带右箭头的全宽按钮 |
79
81
 
@@ -81,7 +83,8 @@ export default function ProductCard() {
81
83
 
82
84
  - **`header`**:标题栏配置,常用 `actionText` / `showAction` / `onActionClick`。
83
85
  - **`footer`**:底部操作区配置,常用 `primaryActionButton` / `secondaryActionButton`。
84
- - **`children`**:部分模板为兼容旧项目保留的废弃属性,新代码不要使用。
86
+ - **`children`**:不用于自定义卡片布局;复合场景使用 `CompositeCard.sections`。
87
+ - **`CompositeCard.sections`**:单层有序数组,只接受白名单 `type`,不接受任意 JSX;复用模块保留原有内容留白,`OptionGroup` 在组合卡内由专用容器补充左右 12px、下方 16px,上方不额外留白。
85
88
  - **图片资源**:传运行时可访问的图片 URL;本地图片放到业务项目 `src/assets` 后静态 `import` 再传入,不要直接写 `'/assets/xxx.png'`。`ContentCard` 普通缩略图使用 `thumbnailSrc`,需要媒体节点时使用 `thumbnail`,且节点优先。
86
89
  - **`className` / `style` / `onClick`**:作用在卡片根节点。
87
90
  - **列表项 `key`**:不传默认用数组下标,建议显式传稳定 key。
@@ -104,6 +107,7 @@ export default function ProductCard() {
104
107
  |------|------|
105
108
  | `render` 里把模板包在 `view` / `scroll-view` 里 | 直接 `return <XxxCard ... />` |
106
109
  | 想做卡片却手写 `view`+`text`+`image` 拼布局 | 先查选型表和公开 Props;没有内容槽位时按新模板或设计需求确认 |
110
+ | 用 `children` 或额外 `view` 拼接行程和乘车人选择 | 使用 `CompositeCard`,配置 `transit`、`content` 与 `option-group` sections |
107
111
  | 继续传 `moreText` / `primaryActionText` / `secondaryActionText` | 改为 `header.actionText` 和 `footer.primaryActionButton` / `footer.secondaryActionButton` |
108
112
  | 需要单个全宽跳转操作 | 使用 `AskHumanCard variant="jump"` 和一个 `items` 项 |
109
113
  | 列表项不传 `key` 导致更新错乱 | 给每个 item 传稳定 key |
@@ -82,7 +82,7 @@
82
82
 
83
83
  `OptionGroupLargeItem`:`value` · `title` · `subtitle?` · `disabled?` · `onClick?`,不支持 `icon`。
84
84
 
85
- 组件统一使用 8px 间距并自动换行;`lg` 最后一行保持单栏宽度,`md` 按内容宽度排列。用户点击时先触发选择变化,再触发 item 的 `onClick`;达到 `maxSelected` 后点击未选项不会触发 `onChange`,但仍会触发 item 的 `onClick`,已选项仍可取消;禁用项不触发事件。
85
+ 组件统一使用 8px 间距并自动换行;`lg` 单行选项平均填满可用宽度,发生换行后各行保持相同栏宽和列位置,`md` 按内容宽度排列。用户点击时先触发选择变化,再触发 item 的 `onClick`;达到 `maxSelected` 后点击未选项不会触发 `onChange`,但仍会触发 item 的 `onClick`,已选项仍可取消;禁用项不触发事件。
86
86
 
87
87
  ---
88
88
 
@@ -106,6 +106,29 @@
106
106
 
107
107
  ---
108
108
 
109
+ ## CompositeCard — 组合卡
110
+
111
+ `import { CompositeCard, type CompositeCardContentSection, type CompositeCardOptionGroupSection, type CompositeCardProps, type CompositeCardSection, type CompositeCardTransitSection } from '@doubao-dev/template'`
112
+
113
+ | Prop | 类型 | 说明 |
114
+ |------|------|------|
115
+ | `header` | `TemplateCardHeaderProps` | 标准标题栏配置 |
116
+ | `sections` | `CompositeCardSection[]` | 单层有序模块数组,按配置顺序展示 |
117
+ | `footer` | `TemplateCardFooterProps` | 标准底部操作区配置 |
118
+ | `className` / `style` / `onClick` | 对应根节点类型 | 作用在组合卡根节点 |
119
+
120
+ 当前白名单:
121
+
122
+ - `CompositeCardTransitSection`:`{ type: 'transit', props: { items?: TransitCardItem[] } }`。
123
+ - `CompositeCardContentSection`:`{ type: 'content', props: { items?: ContentCardItem[] } }`;只复用 ContentCard 的内容区域,不渲染其卡片外壳、header 或 footer。
124
+ - `CompositeCardOptionGroupSection`:`{ type: 'option-group', props: OptionGroupProps }`。
125
+
126
+ `props` 透传给对应模块,因此模块原有的回调、`className`、`style` 和具名 `ReactNode` 字段仍然有效;组合器不开放 section `children`、任意 JSX、布局参数或 wrapper 样式,也不提供独立标题字段。标题、说明等内容通过 `content` section 表达。卡片统一管理标准 header/footer,复用模块保留原有内容留白、内部布局与窄屏策略;`OptionGroup` 由组合卡内的专用容器补充左右 12px、下方 16px,上方不额外留白。
127
+
128
+ `items` 为空的 section 会连同间距一起收起;运行时未知 `type` 不展示。`sections` 不支持运行中插入、删除或重排,不要求配置 section key。
129
+
130
+ ---
131
+
109
132
  ## MapCard — 地图卡
110
133
 
111
134
  `import { MapCard, type MapCardMapProps, type MapCardMetaItem, type MapCardProps, type TemplateCardFooterActionButton } from '@doubao-dev/template'`
@@ -230,6 +253,8 @@ MapCard 的 `ref` 直接绑定到内部 Map,可通过 `MapRef` 调用地图实
230
253
 
231
254
  `TransitCardTag`:`text: string | number` · `tone?: 'marketing' | 'neutral'`(默认 `marketing`)。标签展示在价格下方;不传 `tag` 时保持单价格布局。
232
255
 
256
+ 窄屏下模板会先压缩行程与价格之间的空白,再压缩出发、中转和到达列之间的空白;空间仍不足时隐藏价格,内容块本身保持原有宽度。
257
+
233
258
  ---
234
259
 
235
260
  ## AskHumanCard — 人工确认选项卡
@@ -208,6 +208,7 @@ my-doubao-app/
208
208
  - **内置组件**:`button`、`switch`、`slider` 等直接使用小写标签,不要从组件包 import;`button` 点击使用 `onClick`,不要使用 `onTap` / `bindtap`;`switch.onChange` 直接接收 `boolean`,`slider.onChange` 直接接收 `number`,`slider` 不支持 `step` / `defaultValue`;事件和 props 先查 [组件 API](frontend/components/overview.md)
209
209
  - **Lynx 渲染规则**:实现 Page / Widget 的布局或样式前,先按 [Lynx API 文档导航](frontend/lynx/overview.md) 读取匹配文档;不要套用 Web HTML/CSS 的默认行为
210
210
  - **Framework Hooks**:`useState`、`useEffect` 等 Hooks 必须从 `@doubao-dev/framework` 导入,不要从 `react` 导入
211
+ - **端工具与全页事件**:实现前先读[端工具、事件与页面上下文](frontend/guides/client-tools-and-events.md),确认 `tools.json`、`events.json` 格式和入口注册。端工具调用宿主 API 前还需确认参考页中的 JSB 白名单及适用范围,不能沿用 Page / Widget 的可调用能力。两者使用平台支持的 JSON Schema 子集,不支持 `enum`、`minimum` / `maximum`(min/max)等校验;可选值和范围写入 `description`,由 handler 或事件回调校验。
211
212
  - **调试现场读取**:本地 Web SDK 调试台可通过 Debugger MCP 暴露只读运行现场;需要读取 runtime console、trace events、simulator tool calls 或 log snapshot 时,先查 [Debugger MCP 协议](frontend/guides/debugger-mcp.md)
212
213
  - **错误处理**:处理边界情况和错误状态
213
214
 
@@ -351,6 +352,7 @@ doubao build --env-mode ppe
351
352
 
352
353
  | 任务 | 必读 | 可选 | 不要读 / 不要做 |
353
354
  |-----|----------|--------|------|
355
+ | 开发端工具、声明 Agent 事件、提交页面模型上下文 | [端工具、事件与页面上下文](frontend/guides/client-tools-and-events.md) | [Framework 核心参考](frontend/framework/core.md) | 不要向 schema 添加 `enum`、min/max 等不支持的约束;不要假设工具可直接读取页面 state |
354
356
  | 创建 Page | [component-development.md](frontend/guides/component-development.md) 的 Page 开发、[dos-and-donts.md](frontend/rules/dos-and-donts.md) 的 Page 布局规则 | [page-widget-basics.md](frontend/examples/page-widget-basics.md) 的 Page 完整示例 | 不要同时加载全部 guides;不要把 Page metadata 写进源码入口 |
355
357
  | 创建 Widget | [Widget 模板库](frontend/widget-templates/overview.md) 的选型指南和模板 props、[component-development.md](frontend/guides/component-development.md) 的 Widget 开发 | [page-widget-basics.md](frontend/examples/page-widget-basics.md) 的 Widget 模板接入示例 | 不要手写卡片布局;不要把 Widget metadata 写进源码入口 |
356
358
  | 配置入口、metadata、多级目录、首页顺序 | [dos-and-donts.md](frontend/rules/dos-and-donts.md) 的 App 配置、入口和命名规则 | [component-development.md](frontend/guides/component-development.md) 的 Page / Widget 开发流程 | 不要省略显式入口的 `/index` |