berry-agent 0.1.0-alpha.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.
Files changed (401) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/dist/.api-emit.stamp +1 -0
  4. package/dist/.build-meta.json +6 -0
  5. package/dist/agent/events.js +1 -0
  6. package/dist/agent/index.js +2 -0
  7. package/dist/agent/loop.js +139 -0
  8. package/dist/agent/queue.js +119 -0
  9. package/dist/agent/stream.js +62 -0
  10. package/dist/agent/tools-batch.js +221 -0
  11. package/dist/agent/types.js +8 -0
  12. package/dist/api/berry-agent-llm.d.ts +18 -0
  13. package/dist/api/berry-agent.d.ts +9 -0
  14. package/dist/api/surface.json +1632 -0
  15. package/dist/api/tsconfig.paths.json +12 -0
  16. package/dist/api/typebox-compile.d.ts +2 -0
  17. package/dist/api/typebox-value.d.ts +2 -0
  18. package/dist/api/typebox.d.ts +2 -0
  19. package/dist/browser/cdp.js +256 -0
  20. package/dist/browser/codes.js +31 -0
  21. package/dist/browser/discover.js +107 -0
  22. package/dist/browser/engine.js +169 -0
  23. package/dist/browser/index.js +17 -0
  24. package/dist/browser/install.js +342 -0
  25. package/dist/browser/page.js +321 -0
  26. package/dist/browser/service.js +158 -0
  27. package/dist/browser/tools.js +198 -0
  28. package/dist/browser/types.js +81 -0
  29. package/dist/channels/ask-queue.js +82 -0
  30. package/dist/channels/commands.js +129 -0
  31. package/dist/channels/engine/cell.js +143 -0
  32. package/dist/channels/engine/diff.js +143 -0
  33. package/dist/channels/engine/engine.js +416 -0
  34. package/dist/channels/engine/index.js +8 -0
  35. package/dist/channels/engine/input-keys.js +86 -0
  36. package/dist/channels/engine/input.js +596 -0
  37. package/dist/channels/engine/memory-io.js +71 -0
  38. package/dist/channels/engine/process-io.js +38 -0
  39. package/dist/channels/engine/types.js +17 -0
  40. package/dist/channels/engine/width.js +122 -0
  41. package/dist/channels/index.js +15 -0
  42. package/dist/channels/registry.js +56 -0
  43. package/dist/channels/sdk/admit.js +29 -0
  44. package/dist/channels/sdk/backend.js +102 -0
  45. package/dist/channels/sdk/cursor.js +56 -0
  46. package/dist/channels/sdk/index.js +20 -0
  47. package/dist/channels/sdk/jsonl.js +208 -0
  48. package/dist/channels/sdk/protocol.js +24 -0
  49. package/dist/channels/sdk/schema.js +91 -0
  50. package/dist/channels/sdk/wire-core.js +446 -0
  51. package/dist/channels/service.js +169 -0
  52. package/dist/channels/tui/autocomplete/autocomplete.js +42 -0
  53. package/dist/channels/tui/autocomplete/file-mentions.js +106 -0
  54. package/dist/channels/tui/autocomplete/popup.js +148 -0
  55. package/dist/channels/tui/autocomplete/provider.js +7 -0
  56. package/dist/channels/tui/autocomplete/token.js +68 -0
  57. package/dist/channels/tui/backend/ansi-rows.js +211 -0
  58. package/dist/channels/tui/backend/main-screen.js +207 -0
  59. package/dist/channels/tui/backend/osc.js +91 -0
  60. package/dist/channels/tui/backend/transcript.js +230 -0
  61. package/dist/channels/tui/backend/tui-backend.js +915 -0
  62. package/dist/channels/tui/editor/editor-model.js +543 -0
  63. package/dist/channels/tui/editor/editor-view.js +140 -0
  64. package/dist/channels/tui/editor/editor.js +275 -0
  65. package/dist/channels/tui/editor/undo-stack.js +35 -0
  66. package/dist/channels/tui/editor/visual-lines.js +126 -0
  67. package/dist/channels/tui/editor/word-nav.js +106 -0
  68. package/dist/channels/tui/history/history-viewer.js +403 -0
  69. package/dist/channels/tui/index.js +3 -0
  70. package/dist/channels/tui/layout.js +167 -0
  71. package/dist/channels/tui/markdown/blocks.js +111 -0
  72. package/dist/channels/tui/markdown/inline.js +75 -0
  73. package/dist/channels/tui/markdown/markdown.js +182 -0
  74. package/dist/channels/tui/memory/memory-viewer.js +540 -0
  75. package/dist/channels/tui/overlay/alt-screen.js +105 -0
  76. package/dist/channels/tui/overlay/overlay.js +57 -0
  77. package/dist/channels/tui/overlay/select-confirm.js +156 -0
  78. package/dist/channels/tui/panels/todo-panel.js +54 -0
  79. package/dist/channels/tui/panels/tool-progress-panel.js +93 -0
  80. package/dist/channels/tui/scroll/scroll-view.js +254 -0
  81. package/dist/channels/tui/status/status-line.js +76 -0
  82. package/dist/channels/tui/text.js +38 -0
  83. package/dist/channels/tui/theme.js +41 -0
  84. package/dist/channels/types.js +11 -0
  85. package/dist/channels/ui-core.js +209 -0
  86. package/dist/checkpoint/capture.js +45 -0
  87. package/dist/checkpoint/codes.js +33 -0
  88. package/dist/checkpoint/command.js +82 -0
  89. package/dist/checkpoint/gate.js +48 -0
  90. package/dist/checkpoint/index.js +20 -0
  91. package/dist/checkpoint/restore.js +172 -0
  92. package/dist/checkpoint/store.js +247 -0
  93. package/dist/checkpoint/types.js +4 -0
  94. package/dist/checkpoint/walk.js +146 -0
  95. package/dist/compaction/ccr-tools.js +112 -0
  96. package/dist/compaction/ccr.js +84 -0
  97. package/dist/compaction/codes.js +21 -0
  98. package/dist/compaction/index.js +18 -0
  99. package/dist/compaction/policy.js +200 -0
  100. package/dist/compaction/service.js +422 -0
  101. package/dist/compaction/slots.js +121 -0
  102. package/dist/compaction/types.js +10 -0
  103. package/dist/context/codes.js +40 -0
  104. package/dist/context/events.js +160 -0
  105. package/dist/context/index.js +13 -0
  106. package/dist/context/logger.js +136 -0
  107. package/dist/context/scope.js +182 -0
  108. package/dist/context/workspace.js +104 -0
  109. package/dist/contracts/agent-events.d.ts +73 -0
  110. package/dist/contracts/agent-events.js +16 -0
  111. package/dist/contracts/api.d.ts +249 -0
  112. package/dist/contracts/api.js +299 -0
  113. package/dist/contracts/approval.d.ts +37 -0
  114. package/dist/contracts/approval.js +9 -0
  115. package/dist/contracts/env-ref.d.ts +41 -0
  116. package/dist/contracts/env-ref.js +32 -0
  117. package/dist/contracts/errors.d.ts +56 -0
  118. package/dist/contracts/errors.js +266 -0
  119. package/dist/contracts/events.d.ts +70 -0
  120. package/dist/contracts/events.js +329 -0
  121. package/dist/contracts/index.d.ts +32 -0
  122. package/dist/contracts/index.js +26 -0
  123. package/dist/contracts/llm.d.ts +275 -0
  124. package/dist/contracts/llm.js +12 -0
  125. package/dist/contracts/messages.d.ts +63 -0
  126. package/dist/contracts/messages.js +65 -0
  127. package/dist/contracts/redact.d.ts +46 -0
  128. package/dist/contracts/redact.js +223 -0
  129. package/dist/contracts/tools.d.ts +197 -0
  130. package/dist/contracts/tools.js +33 -0
  131. package/dist/contracts/types.d.ts +302 -0
  132. package/dist/contracts/types.js +50 -0
  133. package/dist/contracts/ui.d.ts +122 -0
  134. package/dist/contracts/ui.js +15 -0
  135. package/dist/conversation/agent-service.js +61 -0
  136. package/dist/conversation/approval-wiring.js +82 -0
  137. package/dist/conversation/backoff.js +38 -0
  138. package/dist/conversation/codes.js +47 -0
  139. package/dist/conversation/control-tools.js +102 -0
  140. package/dist/conversation/control.js +210 -0
  141. package/dist/conversation/driver.js +922 -0
  142. package/dist/conversation/index.js +12 -0
  143. package/dist/conversation/model-visible.js +169 -0
  144. package/dist/conversation/open-tools.js +126 -0
  145. package/dist/conversation/reseed.js +132 -0
  146. package/dist/conversation/sessions.js +215 -0
  147. package/dist/conversation/todo.js +203 -0
  148. package/dist/conversation/types.js +35 -0
  149. package/dist/conversation/wiring.js +204 -0
  150. package/dist/credentials/codes.js +59 -0
  151. package/dist/credentials/commands.js +186 -0
  152. package/dist/credentials/env-ref.js +34 -0
  153. package/dist/credentials/index.js +28 -0
  154. package/dist/credentials/migration.js +18 -0
  155. package/dist/credentials/oauth.js +266 -0
  156. package/dist/credentials/refresh.js +152 -0
  157. package/dist/credentials/secrets.js +118 -0
  158. package/dist/credentials/types.js +30 -0
  159. package/dist/exec/bash.js +279 -0
  160. package/dist/exec/codes.js +37 -0
  161. package/dist/exec/env.js +99 -0
  162. package/dist/exec/environment.js +39 -0
  163. package/dist/exec/git-guard.js +623 -0
  164. package/dist/exec/index.js +24 -0
  165. package/dist/exec/registry.js +120 -0
  166. package/dist/exec/spawn.js +281 -0
  167. package/dist/exec/tail.js +77 -0
  168. package/dist/exec/types.js +5 -0
  169. package/dist/goal/codes.js +33 -0
  170. package/dist/goal/command.js +175 -0
  171. package/dist/goal/fold.js +121 -0
  172. package/dist/goal/gates.js +122 -0
  173. package/dist/goal/index.js +22 -0
  174. package/dist/goal/migration.js +48 -0
  175. package/dist/goal/service.js +501 -0
  176. package/dist/goal/todo-tool.js +174 -0
  177. package/dist/goal/types.js +1 -0
  178. package/dist/goal/update-tool.js +46 -0
  179. package/dist/host/approval-cmd.js +276 -0
  180. package/dist/host/assembly.js +1146 -0
  181. package/dist/host/boot-failures.js +104 -0
  182. package/dist/host/budget-advisory.js +74 -0
  183. package/dist/host/budget-broadcast.js +50 -0
  184. package/dist/host/builtins.js +54 -0
  185. package/dist/host/cli.js +544 -0
  186. package/dist/host/codes.js +120 -0
  187. package/dist/host/config-schema.js +195 -0
  188. package/dist/host/conversation-stack.js +654 -0
  189. package/dist/host/core-plugins.js +1685 -0
  190. package/dist/host/credentials-cmd.js +42 -0
  191. package/dist/host/disclosure.js +30 -0
  192. package/dist/host/dispatch.js +105 -0
  193. package/dist/host/doors-cmd.js +154 -0
  194. package/dist/host/dump-config.js +44 -0
  195. package/dist/host/hook-dispatch-guard.js +27 -0
  196. package/dist/host/import-gate.js +153 -0
  197. package/dist/host/index.js +54 -0
  198. package/dist/host/issue-session.js +241 -0
  199. package/dist/host/loader.js +372 -0
  200. package/dist/host/main.js +161 -0
  201. package/dist/host/manifest.js +381 -0
  202. package/dist/host/mcp-entry.js +53 -0
  203. package/dist/host/plugin-boot.js +952 -0
  204. package/dist/host/plugin-context.js +672 -0
  205. package/dist/host/plugin-install.js +480 -0
  206. package/dist/host/plugin-reload.js +124 -0
  207. package/dist/host/plugin-store.js +462 -0
  208. package/dist/host/plugin-tools.js +359 -0
  209. package/dist/host/plugin-uninstall.js +257 -0
  210. package/dist/host/plugins-cmd.js +302 -0
  211. package/dist/host/plugins-command.js +130 -0
  212. package/dist/host/plugins-config.js +195 -0
  213. package/dist/host/prompt-sections.js +133 -0
  214. package/dist/host/run-entry.js +544 -0
  215. package/dist/host/runtime.js +209 -0
  216. package/dist/host/scheduler-tick.js +294 -0
  217. package/dist/host/serve-daemon.js +501 -0
  218. package/dist/host/serve-entry.js +279 -0
  219. package/dist/host/session-anchor.js +41 -0
  220. package/dist/host/sessions-cmd.js +219 -0
  221. package/dist/host/sessions-face.js +47 -0
  222. package/dist/host/settings-store.js +112 -0
  223. package/dist/host/signals.js +69 -0
  224. package/dist/host/single-instance.js +105 -0
  225. package/dist/host/subagent-factory.js +291 -0
  226. package/dist/host/testkit/harness.js +283 -0
  227. package/dist/host/testkit/index.js +14 -0
  228. package/dist/host/testkit/matrix.js +302 -0
  229. package/dist/host/tool-policy-store.js +177 -0
  230. package/dist/host/triggers.js +212 -0
  231. package/dist/host/tui-entry.js +216 -0
  232. package/dist/host/webui-bridge.js +165 -0
  233. package/dist/issue/codes.js +38 -0
  234. package/dist/issue/filter.js +146 -0
  235. package/dist/issue/github.js +116 -0
  236. package/dist/issue/index.js +17 -0
  237. package/dist/issue/mount.js +70 -0
  238. package/dist/issue/poll.js +58 -0
  239. package/dist/issue/service.js +341 -0
  240. package/dist/issue/tools.js +70 -0
  241. package/dist/issue/types.js +34 -0
  242. package/dist/issue/webhook.js +126 -0
  243. package/dist/llm/codes.js +77 -0
  244. package/dist/llm/complete.js +196 -0
  245. package/dist/llm/events.js +15 -0
  246. package/dist/llm/index.js +24 -0
  247. package/dist/llm/inflight.js +65 -0
  248. package/dist/llm/model-id.js +58 -0
  249. package/dist/llm/provider-face.d.ts +32 -0
  250. package/dist/llm/provider-face.js +34 -0
  251. package/dist/llm/recovery.js +146 -0
  252. package/dist/llm/runtime.js +46 -0
  253. package/dist/llm/stream-fn.js +147 -0
  254. package/dist/lsp/codes.js +31 -0
  255. package/dist/lsp/connection.js +147 -0
  256. package/dist/lsp/frame.js +110 -0
  257. package/dist/lsp/index.js +16 -0
  258. package/dist/lsp/inject.js +58 -0
  259. package/dist/lsp/instance.js +264 -0
  260. package/dist/lsp/service.js +522 -0
  261. package/dist/lsp/tools.js +53 -0
  262. package/dist/lsp/types.js +201 -0
  263. package/dist/mcp/bridge.js +222 -0
  264. package/dist/mcp/codes.js +21 -0
  265. package/dist/mcp/index.js +19 -0
  266. package/dist/mcp/jsonrpc.js +230 -0
  267. package/dist/mcp/service.js +125 -0
  268. package/dist/mcp/tools.js +145 -0
  269. package/dist/mcp/types.js +108 -0
  270. package/dist/memory/cite.js +131 -0
  271. package/dist/memory/codes.js +50 -0
  272. package/dist/memory/command.js +71 -0
  273. package/dist/memory/consolidate.js +219 -0
  274. package/dist/memory/cycle.js +109 -0
  275. package/dist/memory/dao.js +878 -0
  276. package/dist/memory/diff.js +238 -0
  277. package/dist/memory/extract.js +181 -0
  278. package/dist/memory/fts.js +58 -0
  279. package/dist/memory/index.js +42 -0
  280. package/dist/memory/inject.js +354 -0
  281. package/dist/memory/merge.js +178 -0
  282. package/dist/memory/migration.js +132 -0
  283. package/dist/memory/pollution.js +59 -0
  284. package/dist/memory/port.js +385 -0
  285. package/dist/memory/review.js +201 -0
  286. package/dist/memory/scan.js +89 -0
  287. package/dist/memory/tools.js +508 -0
  288. package/dist/memory/types.js +140 -0
  289. package/dist/obs/codes.js +38 -0
  290. package/dist/obs/db.js +115 -0
  291. package/dist/obs/index.js +20 -0
  292. package/dist/obs/rollup.js +61 -0
  293. package/dist/obs/service.js +363 -0
  294. package/dist/obs/session-tools.js +282 -0
  295. package/dist/obs/session-view.js +225 -0
  296. package/dist/obs/tool.js +97 -0
  297. package/dist/obs/types.js +1 -0
  298. package/dist/persist/audit.js +63 -0
  299. package/dist/persist/aux.js +39 -0
  300. package/dist/persist/codes.js +35 -0
  301. package/dist/persist/index.js +30 -0
  302. package/dist/persist/load-history.js +50 -0
  303. package/dist/persist/migrations.js +37 -0
  304. package/dist/persist/paths.js +108 -0
  305. package/dist/persist/persistence.js +229 -0
  306. package/dist/persist/schema.js +99 -0
  307. package/dist/persist/secret-box.js +95 -0
  308. package/dist/persist/store.js +706 -0
  309. package/dist/persist/write-behind.js +238 -0
  310. package/dist/safety/approval.js +171 -0
  311. package/dist/safety/bwrap.js +123 -0
  312. package/dist/safety/codes.js +57 -0
  313. package/dist/safety/danger.js +505 -0
  314. package/dist/safety/gate.js +226 -0
  315. package/dist/safety/index.js +24 -0
  316. package/dist/safety/presets.js +73 -0
  317. package/dist/safety/roots.js +139 -0
  318. package/dist/safety/sandbox.js +214 -0
  319. package/dist/safety/seatbelt.js +88 -0
  320. package/dist/safety/sensitive.js +34 -0
  321. package/dist/safety/tool-policy.js +203 -0
  322. package/dist/safety/types.js +13 -0
  323. package/dist/scheduler/codes.js +54 -0
  324. package/dist/scheduler/cron-backend.js +135 -0
  325. package/dist/scheduler/engine.js +280 -0
  326. package/dist/scheduler/gates.js +60 -0
  327. package/dist/scheduler/index.js +25 -0
  328. package/dist/scheduler/migration.js +22 -0
  329. package/dist/scheduler/runner.js +171 -0
  330. package/dist/scheduler/schedule.js +193 -0
  331. package/dist/scheduler/service.js +283 -0
  332. package/dist/scheduler/tick.js +139 -0
  333. package/dist/scheduler/types.js +1 -0
  334. package/dist/sdk/http.js +865 -0
  335. package/dist/sdk/index.js +22 -0
  336. package/dist/sdk/mcp.js +289 -0
  337. package/dist/sdk/plugin-route-registry.js +126 -0
  338. package/dist/sdk/plugin-routes.js +149 -0
  339. package/dist/sdk/security.js +116 -0
  340. package/dist/sdk/types.js +32 -0
  341. package/dist/session/budget.js +159 -0
  342. package/dist/session/codes.js +40 -0
  343. package/dist/session/derive.js +180 -0
  344. package/dist/session/event-data.js +1 -0
  345. package/dist/session/fork.js +72 -0
  346. package/dist/session/import-gates.js +148 -0
  347. package/dist/session/index.js +18 -0
  348. package/dist/session/recover.js +103 -0
  349. package/dist/session/session.js +279 -0
  350. package/dist/session/snapshot.js +107 -0
  351. package/dist/skills/agents.js +242 -0
  352. package/dist/skills/codes.js +51 -0
  353. package/dist/skills/discovery.js +266 -0
  354. package/dist/skills/frontmatter.js +215 -0
  355. package/dist/skills/index.js +28 -0
  356. package/dist/skills/load.js +118 -0
  357. package/dist/skills/manage.js +201 -0
  358. package/dist/skills/registry.js +138 -0
  359. package/dist/skills/render.js +124 -0
  360. package/dist/skills/sections.js +171 -0
  361. package/dist/skills/types.js +21 -0
  362. package/dist/subagent/codes.js +50 -0
  363. package/dist/subagent/declarative.js +55 -0
  364. package/dist/subagent/index.js +19 -0
  365. package/dist/subagent/notify.js +51 -0
  366. package/dist/subagent/provide.js +7 -0
  367. package/dist/subagent/registry.js +149 -0
  368. package/dist/subagent/service.js +338 -0
  369. package/dist/subagent/surface.js +44 -0
  370. package/dist/subagent/tool.js +153 -0
  371. package/dist/subagent/types.js +25 -0
  372. package/dist/tools/apply-patch.js +164 -0
  373. package/dist/tools/codes.js +109 -0
  374. package/dist/tools/fs.js +501 -0
  375. package/dist/tools/index.js +17 -0
  376. package/dist/tools/observed.js +99 -0
  377. package/dist/tools/pipeline.js +176 -0
  378. package/dist/tools/protected-read.js +54 -0
  379. package/dist/tools/registry.js +250 -0
  380. package/dist/tools/search.js +451 -0
  381. package/dist/tools/worktree.js +327 -0
  382. package/dist/web/codes.js +37 -0
  383. package/dist/web/gate.js +43 -0
  384. package/dist/web/hygiene.js +195 -0
  385. package/dist/web/index.js +16 -0
  386. package/dist/web/service.js +207 -0
  387. package/dist/web/ssrf-guard.js +44 -0
  388. package/dist/web/tool.js +76 -0
  389. package/dist/web/types.js +10 -0
  390. package/dist/webui/assets/index-B-t2O8gh.js +22 -0
  391. package/dist/webui/assets/index-DOlgSZ9Q.css +2 -0
  392. package/dist/webui/index.html +14 -0
  393. package/dist/webui/index.js +14 -0
  394. package/dist/webui/server.js +549 -0
  395. package/dist/webui/types.js +38 -0
  396. package/examples/README.md +26 -0
  397. package/examples/minimal-code-plugin/entry.js +43 -0
  398. package/examples/minimal-code-plugin/package.json +12 -0
  399. package/examples/pure-skill-pack/package.json +14 -0
  400. package/examples/pure-skill-pack/skills/markdown-table/SKILL.md +32 -0
  401. package/package.json +86 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * host/config-schema — 插件配置字段声明面(03 §1.2 configSchema 条款;
3
+ * 2026-09-11 交互动词族批 ix-3)。
4
+ *
5
+ * 字段描述数组(letta channel.json `config_schema` 形)——JSON 可序列化、
6
+ * 字段型闭集可控,宿主侧编译为校验器;typebox JSON Schema 原生形不采
7
+ * (插件清单是 package.json 纯 JSON,typebox Type 对象不可序列化进清单,
8
+ * 且 secret 凭证域联动在原生 JSON Schema 无语义位——RP4 改裁)。
9
+ *
10
+ * 双消费源(03 §1.2):①装载期字段级校验(本件 synthesizePluginConfig
11
+ * ——PLUGIN_CONFIG_INVALID 执法源,行 config 与宿主默认 config 双源过校验);
12
+ * ②TUI `/plugins config <id>` 表单腿(fields 驱动逐字段问答,ix-3c 接线)。
13
+ *
14
+ * 合成序(03 §1.2 通用字段位 default 句):行 config 整值覆盖宿主默认 →
15
+ * 声明字段过字段级校验 → 余键字段 default 兜底 → secret 键凭证直取注回 →
16
+ * 未声明键原样透传。呈现纪律:一切人面呈现位 secret 值遮蔽 `'***'`
17
+ * (maskConfigSecrets——明文只进 apply config 实参与凭证盒读写)。
18
+ */
19
+ import { BaseError } from '../contracts/index.js';
20
+ /** 配置键词法:小写字母/数字/连字符,首字符字母(与插件 id 同形——YAML 键友好、点/斜杠/冒号禁入防路径歧义) */
21
+ const CONFIG_KEY_RE = /^[a-z][a-z0-9-]*$/;
22
+ /** 字段型闭集(v1 四值) */
23
+ const FIELD_TYPES = new Set(['text', 'secret', 'select', 'boolean']);
24
+ /** 字段对象已知键闭集(未知键拒绝式——拼写错误当场红) */
25
+ const FIELD_KEYS = new Set(['key', 'type', 'label', 'description', 'required', 'default', 'options']);
26
+ /**
27
+ * 清单 configSchema 深校验(纯函数——PLUGIN_SHAPE_INVALID 面)。
28
+ *
29
+ * 执法项:数组形 / 逐字段对象形 / key 必携且过词法 / type 四值闭集 /
30
+ * select 必携非空 options(value/label 字符串)/ default 型匹配
31
+ * (text·select 须字符串、boolean 须布尔、secret 携 default 拒)/
32
+ * key 重复拒。失败 message 自带指路(manifest 侧 shapeFail 包装消费)。
33
+ */
34
+ export function parseConfigSchemaFields(raw, opts) {
35
+ const fail = (message) => ({ ok: false, message });
36
+ if (!Array.isArray(raw) || raw.length === 0) {
37
+ return fail(`berryAgent.configSchema 须为非空字段描述数组(插件 ${opts.pluginId})`);
38
+ }
39
+ const seen = new Set();
40
+ for (const item of raw) {
41
+ if (typeof item !== 'object' || item === null || Array.isArray(item)) {
42
+ return fail(`configSchema 字段描述须为对象(插件 ${opts.pluginId})`);
43
+ }
44
+ const field = item;
45
+ for (const key of Object.keys(field)) {
46
+ if (!FIELD_KEYS.has(key)) {
47
+ return fail(`configSchema 字段未知键 "${key}"(插件 ${opts.pluginId})——闭集:key/type/label/description/required/default/options`);
48
+ }
49
+ }
50
+ const key = field['key'];
51
+ if (typeof key !== 'string' || !CONFIG_KEY_RE.test(key)) {
52
+ return fail(`configSchema 字段 key "${String(key)}" 违词法 ^[a-z][a-z0-9-]*$(插件 ${opts.pluginId}——与插件 id 同形,点/斜杠/冒号禁入)`);
53
+ }
54
+ if (seen.has(key)) {
55
+ return fail(`configSchema 字段 key "${key}" 重复出现(插件 ${opts.pluginId})`);
56
+ }
57
+ seen.add(key);
58
+ const type = field['type'];
59
+ if (typeof type !== 'string' || !FIELD_TYPES.has(type)) {
60
+ return fail(`configSchema 字段 "${key}" 型 "${String(type)}" 不在闭集 text/secret/select/boolean(插件 ${opts.pluginId})`);
61
+ }
62
+ if (field['label'] !== undefined && typeof field['label'] !== 'string') {
63
+ return fail(`configSchema 字段 "${key}" label 须字符串(插件 ${opts.pluginId})`);
64
+ }
65
+ if (field['description'] !== undefined && typeof field['description'] !== 'string') {
66
+ return fail(`configSchema 字段 "${key}" description 须字符串(插件 ${opts.pluginId})`);
67
+ }
68
+ if (field['required'] !== undefined && typeof field['required'] !== 'boolean') {
69
+ return fail(`configSchema 字段 "${key}" required 须布尔(插件 ${opts.pluginId})`);
70
+ }
71
+ if (type === 'secret') {
72
+ if (field['default'] !== undefined) {
73
+ return fail(`configSchema secret 型字段 "${key}" 不得携 default(插件 ${opts.pluginId}——敏感值缺省走凭证盒,不落清单明文)`);
74
+ }
75
+ continue; // secret 无 options/default 两判位
76
+ }
77
+ if (type === 'select') {
78
+ const options = field['options'];
79
+ const badOption = (o) => {
80
+ if (typeof o !== 'object' || o === null)
81
+ return true;
82
+ const opt = o;
83
+ return typeof opt['value'] !== 'string' || opt['value'].length === 0 || typeof opt['label'] !== 'string';
84
+ };
85
+ if (!Array.isArray(options) || options.length === 0 || options.some(badOption)) {
86
+ return fail(`configSchema select 型字段 "${key}" 必携非空 options: { value, label }[](插件 ${opts.pluginId})`);
87
+ }
88
+ }
89
+ if (field['default'] !== undefined) {
90
+ const expected = type === 'boolean' ? 'boolean' : 'string';
91
+ if (typeof field['default'] !== expected) {
92
+ return fail(`configSchema 字段 "${key}" default 须 ${expected} 型(插件 ${opts.pluginId})`);
93
+ }
94
+ }
95
+ }
96
+ return { ok: true, fields: raw };
97
+ }
98
+ /**
99
+ * 装载位配置合成(03 §1.2 合成序——PLUGIN_CONFIG_INVALID 执法源)。
100
+ *
101
+ * configSchema 缺席时行为零变化:返回 rowConfig ?? defaultConfig 原值
102
+ * (不校验不合成——config 键与 configSchema 键分立后各单源)。在场时:
103
+ * ① base = 行 config ?? 宿主默认(整值替换非合并);② secret 型键在
104
+ * base 出现即拒(明文拒双源同律——行 config 与清单 config 均拒,
105
+ * message 分流指路:行侧指路 /plugins config 表单、清单侧指路作者
106
+ * 从 package.json 删该键);③ 声明字段过字段级校验(text 须字符串 /
107
+ * boolean 须布尔 / select 须 options 值域内;required 合成后值缺席拒);
108
+ * ④ 余键字段 default 兜底;⑤ secret 键凭证直取注回(缺席即不注——
109
+ * required 的 secret 缺席走诊断豁免位);⑥ 未声明键原样透传。
110
+ */
111
+ export function synthesizePluginConfig(input) {
112
+ if (input.fields === undefined || input.fields.length === 0) {
113
+ // 行为零变化档:整值回落原样透传(磁盘轨旧 typebox 消费路径已拆——无 schema 即无校验)
114
+ return input.rowConfig !== undefined ? input.rowConfig : input.defaultConfig;
115
+ }
116
+ const base = input.rowConfig !== undefined ? input.rowConfig : input.defaultConfig;
117
+ const configInvalid = (message) => {
118
+ throw new BaseError('PLUGIN_CONFIG_INVALID', `${message}(插件 ${input.pluginId})`);
119
+ };
120
+ if (base !== undefined && (typeof base !== 'object' || Array.isArray(base))) {
121
+ configInvalid('config 须为对象(整值替换非合并)');
122
+ }
123
+ const baseRecord = (base ?? {});
124
+ // ② secret 明文拒(双源同律——message 分流指路)
125
+ for (const field of input.fields) {
126
+ if (field.type !== 'secret')
127
+ continue;
128
+ if (!(field.key in baseRecord))
129
+ continue;
130
+ if (input.rowConfig !== undefined && field.key in input.rowConfig) {
131
+ configInvalid(`行 config 携 secret 型键 "${field.key}" 明文值拒——secret 值不落 enabled.yaml(走 /plugins config 表单写凭证盒,加密存储语义不容 yaml 明文旁路)`);
132
+ }
133
+ configInvalid(`清单 config 键(宿主默认值位)携 secret 型键 "${field.key}" 明文值拒——从 package.json 删该键、走表单/凭证盒(package.json 随 npm 分发明文更烈)`);
134
+ }
135
+ // ③④⑤ 逐声明字段:在场过校验 → 缺席 default 兜底 → secret 凭证直取 → required 终判
136
+ const merged = { ...baseRecord }; // ⑥ 未声明键随展开原样透传
137
+ for (const field of input.fields) {
138
+ const present = field.key in merged;
139
+ if (field.type === 'secret') {
140
+ // secret 只走凭证直取(base 里的明文已在上一步拒掉——此处值必缺席)
141
+ const secret = input.getSecret?.(field.key);
142
+ if (secret !== undefined) {
143
+ merged[field.key] = secret;
144
+ }
145
+ else if (field.required === true) {
146
+ if (input.allowMissingRequiredSecret === true) {
147
+ // 诊断豁免(07 §5 dump-config)::memory: 形凭证盒结构性恒空——降级 warn 提示行装载照走
148
+ input.warn?.(`插件 ${input.pluginId} required secret 字段 "${field.key}" 未合成——凭证盒 :memory: 空诊断形豁免(真实装载将拒载 PLUGIN_CONFIG_INVALID)`);
149
+ }
150
+ else {
151
+ configInvalid(`required secret 字段 "${field.key}" 凭证盒缺席——经 /plugins config 表单或 credentials 域写入`);
152
+ }
153
+ }
154
+ continue;
155
+ }
156
+ if (present) {
157
+ const value = merged[field.key];
158
+ if (field.type === 'text' && typeof value !== 'string') {
159
+ configInvalid(`config 字段 "${field.key}"(text 型)须字符串`);
160
+ }
161
+ if (field.type === 'boolean' && typeof value !== 'boolean') {
162
+ configInvalid(`config 字段 "${field.key}"(boolean 型)须布尔`);
163
+ }
164
+ if (field.type === 'select' && (typeof value !== 'string' || !field.options.some((o) => o.value === value))) {
165
+ configInvalid(`config 字段 "${field.key}"(select 型)值不在 options 值域内`);
166
+ }
167
+ continue;
168
+ }
169
+ if (field.default !== undefined) {
170
+ merged[field.key] = field.default; // ④ 字段级缺省兜底
171
+ }
172
+ else if (field.required === true) {
173
+ configInvalid(`required 字段 "${field.key}" 合成后缺席——/reload 时刻可修`);
174
+ }
175
+ }
176
+ return Object.keys(merged).length > 0 ? merged : undefined;
177
+ }
178
+ /**
179
+ * 呈现纪律(03 §1.2——合成结果的一切人面/诊断呈现位):secret 型键值
180
+ * 遮蔽占位符 `'***'`。纯函数不改性参——返回遮蔽副本(明文只进 apply
181
+ * config 实参与凭证盒读写;打印面即外泄面)。
182
+ */
183
+ export function maskConfigSecrets(fields, config) {
184
+ if (fields === undefined || typeof config !== 'object' || config === null)
185
+ return config;
186
+ const record = config;
187
+ let masked;
188
+ for (const field of fields) {
189
+ if (field.type !== 'secret' || !(field.key in record))
190
+ continue;
191
+ masked ??= { ...record };
192
+ masked[field.key] = '***';
193
+ }
194
+ return masked ?? config;
195
+ }