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,544 @@
1
+ /**
2
+ * 扫描一段 argv:旗标消费 + 裸 `--` 终结符 + 位置参数收集 + help/version 越位记录。
3
+ *
4
+ * - 未识别 `--` 词 → error(执法①);
5
+ * - 取值旗标值缺席 / 空串 / 以 `--` 起头(占位缺失裁量)/ 值域外 / 非正整数 → error(执法③);
6
+ * - optional-value 仅当下一词存在且不以 `--` 起头时消费(--fork 形专用)。
7
+ */
8
+ function scanFlags(argv, schemas) {
9
+ const booleans = new Set();
10
+ const values = new Map();
11
+ const literals = [];
12
+ let overreach;
13
+ const byName = new Map(schemas.map((s) => [s.name, s]));
14
+ for (let i = 0; i < argv.length; i++) {
15
+ const tok = argv[i];
16
+ if (tok === '--') {
17
+ // 裸终结符:余下全字面(执法②——正当以 -- 起头的消息内容保真送达)
18
+ literals.push(...argv.slice(i + 1));
19
+ break;
20
+ }
21
+ if (tok.startsWith('--')) {
22
+ const name = tok.slice(2);
23
+ if (name === 'help' || name === 'version') {
24
+ overreach ??= tok; // 记录首个越位词(执法④)
25
+ continue;
26
+ }
27
+ const schema = byName.get(name);
28
+ if (!schema) {
29
+ return { booleans, values, literals, overreach, error: `未识别旗标 --${name}(全部旗标见 --help)` };
30
+ }
31
+ if (schema.kind === 'boolean') {
32
+ booleans.add(name);
33
+ continue;
34
+ }
35
+ if (schema.kind === 'optional-value') {
36
+ // 可选值形(--fork 专用):下一词存在且不以 `--` 起头才消费为值;否则记空串哨兵 = 在场无值
37
+ const next = argv[i + 1];
38
+ if (next !== undefined && next !== '' && !next.startsWith('--')) {
39
+ values.set(name, next);
40
+ i++;
41
+ }
42
+ else {
43
+ values.set(name, '');
44
+ }
45
+ continue;
46
+ }
47
+ const next = argv[i + 1];
48
+ if (next === undefined || next === '' || next.startsWith('--')) {
49
+ return { booleans, values, literals, overreach, error: `--${name} 须带值(空串占位或缺失即用法错)` };
50
+ }
51
+ if (schema.values && !schema.values.includes(next)) {
52
+ return {
53
+ booleans,
54
+ values,
55
+ literals,
56
+ overreach,
57
+ error: `--${name} 值域外:${next}(合法值:${schema.values.join('|')})`,
58
+ };
59
+ }
60
+ if (schema.positiveInt) {
61
+ const n = Number(next);
62
+ if (!Number.isInteger(n) || n < 1 || n > schema.positiveInt.upTo) {
63
+ return {
64
+ booleans,
65
+ values,
66
+ literals,
67
+ overreach,
68
+ error: `--${name} 须为 1–${schema.positiveInt.upTo} 的整数(收到:${next})`,
69
+ };
70
+ }
71
+ }
72
+ if (schema.nonNegativeInt) {
73
+ const n = Number(next);
74
+ if (!Number.isInteger(n) || n < 0 || n > schema.nonNegativeInt.upTo) {
75
+ return {
76
+ booleans,
77
+ values,
78
+ literals,
79
+ overreach,
80
+ error: `--${name} 须为 0–${schema.nonNegativeInt.upTo} 的整数(收到:${next})`,
81
+ };
82
+ }
83
+ }
84
+ values.set(name, next);
85
+ i++;
86
+ continue;
87
+ }
88
+ literals.push(tok);
89
+ }
90
+ return { booleans, values, literals, overreach };
91
+ }
92
+ function usageFail(message) {
93
+ return { ok: false, exitCode: 2, message };
94
+ }
95
+ /** 位置参数计数执法(不足/超出即退 2——usage 形描述期望) */
96
+ function expectArity(literals, min, max, usage) {
97
+ if (literals.length < min || literals.length > max) {
98
+ return usageFail(`位置参数数目不符(期望 ${min === max ? `恰 ${min}` : `${min}–${max}`},收到 ${literals.length})——用法:${usage}`);
99
+ }
100
+ return literals;
101
+ }
102
+ /* ---------------- 各入口旗标表(07 §5 旗标块收面逐条钉位) ---------------- */
103
+ /** 通用三旗标(--port/--no-plugins/--debug)——按入口拼装(自动化入口不透传 --no-plugins) */
104
+ const PORT_FLAG = { name: 'port', kind: 'value', positiveInt: { upTo: 65535 } };
105
+ const NO_PLUGINS_FLAG = { name: 'no-plugins', kind: 'boolean' };
106
+ const DEBUG_FLAG = { name: 'debug', kind: 'boolean' };
107
+ /** 快速试件旗标(--plugin-file <path>——TUI/run 两入口收;dump-config 收而互斥拒) */
108
+ const PLUGIN_FILE_FLAG = { name: 'plugin-file', kind: 'value' };
109
+ const TUI_SCHEMAS = [PORT_FLAG, NO_PLUGINS_FLAG, DEBUG_FLAG, PLUGIN_FILE_FLAG];
110
+ const RUN_SCHEMAS = [
111
+ PORT_FLAG,
112
+ NO_PLUGINS_FLAG,
113
+ DEBUG_FLAG,
114
+ { name: 'read-only', kind: 'boolean' },
115
+ // --tick <名>:取值形(批 20a——15a runner argv 先行定形 cli 侧跟齐;07 §5 同笔定名)
116
+ { name: 'tick', kind: 'value' },
117
+ { name: 'background', kind: 'boolean' },
118
+ { name: 'output-format', kind: 'value', values: ['text', 'json', 'stream'] },
119
+ { name: 'no-delta', kind: 'boolean' },
120
+ { name: 'output-last-message', kind: 'value' },
121
+ { name: 'ephemeral', kind: 'boolean' },
122
+ { name: 'max-turns', kind: 'value', positiveInt: { upTo: 1000 } },
123
+ { name: 'session', kind: 'value' },
124
+ { name: 'continue', kind: 'boolean' },
125
+ { name: 'fork', kind: 'optional-value' },
126
+ // --output-schema 未实现:显式传入即用法错退 2 不静默忽略(07 §5——实现随批 13 落地翻转)
127
+ { name: 'output-schema', kind: 'boolean' },
128
+ // --preset <名>:权限预设逐次形(04 §9 ⑥ ap-3——值域三档单源 safety/presets;
129
+ // 与 --read-only 互斥在 parseRun 执法——同层 mode 冲突)
130
+ { name: 'preset', kind: 'value', values: ['conservative', 'balanced', 'open'] },
131
+ // --plugin-file <path>:快速试件(03 §7 生态启动批 eco-3a——TUI 同位同语义)
132
+ PLUGIN_FILE_FLAG,
133
+ ];
134
+ const SERVE_SCHEMAS = [
135
+ PORT_FLAG,
136
+ DEBUG_FLAG,
137
+ { name: 'daemon', kind: 'boolean' },
138
+ { name: 'no-delta', kind: 'boolean' },
139
+ // daemon 形专属(07 §5 落码定名批):TCP 侧可选两旗标——前台 stdio 形无
140
+ // HTTP 面,传入即用法错(parseServe 互斥执法——防「收下不起」静默吞)
141
+ { name: 'sdk-port', kind: 'value', positiveInt: { upTo: 65535 } },
142
+ { name: 'sdk-host', kind: 'value' },
143
+ ];
144
+ const DUMP_SCHEMAS = [PORT_FLAG, NO_PLUGINS_FLAG, DEBUG_FLAG, PLUGIN_FILE_FLAG];
145
+ const UNINSTALL_SCHEMAS = [
146
+ { name: 'confirm', kind: 'boolean' },
147
+ { name: 'data', kind: 'value', values: ['keep', 'purge'] },
148
+ ];
149
+ /** install 旗标族(07 §5——--min-release-age 逐次覆盖 env 静置窗;0 = 显式关窗故走非负整数域) */
150
+ const INSTALL_SCHEMAS = [
151
+ { name: 'min-release-age', kind: 'value', nonNegativeInt: { upTo: 10_000_000 } },
152
+ ];
153
+ /* ---------------- 命令解析器 ---------------- */
154
+ /** 解析 run 命令段(子命令位已消费) */
155
+ function parseRun(rest) {
156
+ const scan = scanFlags(rest, RUN_SCHEMAS);
157
+ if (scan.error)
158
+ return usageFail(scan.error);
159
+ // --output-schema 显式传入即退 2(未实现——不静默忽略)
160
+ if (scan.booleans.has('output-schema')) {
161
+ return usageFail('--output-schema 尚未实现——显式传入即用法错(不静默忽略;实现随 SDK 通道批落地后翻转本闸)');
162
+ }
163
+ // --tick <名> 取值形(批 20a):与 message 位置参数互斥——到点形态提示词在行内不在
164
+ // argv(07 §5 定名);arity 随形态分档(--tick 在场零位置参数、缺席恰一)
165
+ const tickName = scan.values.get('tick');
166
+ if (tickName !== undefined && scan.literals.length > 0) {
167
+ return usageFail('--tick 与 message 位置参数互斥(到点形态提示词在 jobs 行内不在 argv)');
168
+ }
169
+ const msg = tickName !== undefined ? [] : expectArity(scan.literals, 1, 1, 'berry-agent run "<message>"');
170
+ if ('exitCode' in msg)
171
+ return msg;
172
+ const has = (b) => scan.booleans.has(b);
173
+ // 互斥组执法(执法⑤):--ephemeral × 续接族 + --tick/--background(续接族里 --session/--fork 是取值旗标——判在场看 values)
174
+ if (has('ephemeral')) {
175
+ const clash = scan.values.has('session') ||
176
+ has('continue') ||
177
+ scan.values.has('fork') ||
178
+ tickName !== undefined ||
179
+ has('background');
180
+ if (clash) {
181
+ return usageFail('--ephemeral 与 --session/--continue/--fork/--tick/--background 互斥(零落盘会话不进续接/定时/后台复用)');
182
+ }
183
+ }
184
+ // 续接族三者互斥
185
+ const resumePicks = (scan.values.has('session') ? 1 : 0) + (has('continue') ? 1 : 0) + (scan.values.has('fork') ? 1 : 0);
186
+ if (resumePicks > 1) {
187
+ return usageFail('--session / --continue / --fork 三者互斥(续接显式 opt-in 单选)');
188
+ }
189
+ // --read-only × --preset 互斥(ap-3):同为 CLI 层 sandbox 档定值位——预设
190
+ // 档已含沙箱档位(conservative=read-only/balanced|open=workspace-write),
191
+ // 同层冲突单选免层内优先级暗规则(04 §9 ⑥ ap-3 定形补充)
192
+ const preset = scan.values.get('preset');
193
+ if (preset !== undefined && has('read-only')) {
194
+ return usageFail('--read-only 与 --preset 互斥(预设档已含沙箱档位——单选:conservative=read-only / balanced|open=workspace-write)');
195
+ }
196
+ const port = scan.values.get('port');
197
+ const maxTurns = scan.values.get('max-turns');
198
+ const flags = {
199
+ port: port === undefined ? undefined : Number(port),
200
+ noPlugins: has('no-plugins'),
201
+ debug: has('debug'),
202
+ readOnly: has('read-only'),
203
+ tick: tickName,
204
+ background: has('background'),
205
+ outputFormat: scan.values.get('output-format'),
206
+ noDelta: has('no-delta'),
207
+ outputLastMessage: scan.values.get('output-last-message'),
208
+ ephemeral: has('ephemeral'),
209
+ maxTurns: maxTurns === undefined ? undefined : Number(maxTurns),
210
+ session: scan.values.get('session'),
211
+ continueLatest: has('continue'),
212
+ fork: scan.values.has('fork') ? { id: scan.values.get('fork') || undefined } : undefined,
213
+ preset,
214
+ pluginFile: scan.values.get('plugin-file'),
215
+ };
216
+ // tick 形 message 置空串(CliCommand 契约 string 必填保持——run-entry 按
217
+ // flags.tick 判到点形态,不消费 message 位;非 tick 形 arity 已保恰一非空)
218
+ const command = { kind: 'run', message: msg[0] ?? '', flags };
219
+ return finish(scan, command);
220
+ }
221
+ /** 解析 serve 命令段(serve status/serve stop 已在首层分派——此处仅 serve 本体) */
222
+ function parseServe(rest) {
223
+ const scan = scanFlags(rest, SERVE_SCHEMAS);
224
+ if (scan.error)
225
+ return usageFail(scan.error);
226
+ const arity = expectArity(scan.literals, 0, 0, 'berry-agent serve [--daemon] [--port <n>] [--sdk-port <n>] [--sdk-host <host>]');
227
+ if ('exitCode' in arity)
228
+ return arity;
229
+ // daemon 形专属旗标互斥执法(执法⑤同族):--sdk-port/--sdk-host 是 daemon 形
230
+ // sdk HTTP 面 TCP 侧可选(07 §5 落码定名批)——前台 stdio 形传入即用法错
231
+ if (!scan.booleans.has('daemon') && (scan.values.has('sdk-port') || scan.values.has('sdk-host'))) {
232
+ return usageFail('--sdk-port/--sdk-host 为 --daemon 形态专属(前台 stdio 形无 HTTP 面)');
233
+ }
234
+ const port = scan.values.get('port');
235
+ const sdkPort = scan.values.get('sdk-port');
236
+ const command = {
237
+ kind: 'serve',
238
+ flags: {
239
+ port: port === undefined ? undefined : Number(port),
240
+ debug: scan.booleans.has('debug'),
241
+ daemon: scan.booleans.has('daemon'),
242
+ noDelta: scan.booleans.has('no-delta'),
243
+ sdkPort: sdkPort === undefined ? undefined : Number(sdkPort),
244
+ sdkHost: scan.values.get('sdk-host'),
245
+ },
246
+ };
247
+ return finish(scan, command);
248
+ }
249
+ /** 解析 plugins 子命令段 */
250
+ function parsePlugins(rest) {
251
+ const [head, ...tail] = rest;
252
+ if (head === undefined || head.startsWith('--')) {
253
+ return usageFail('plugins 须带子命令(list/install/uninstall/mount/unmount/toggle/update/check)');
254
+ }
255
+ switch (head) {
256
+ case 'list':
257
+ case 'check': {
258
+ const scan = scanFlags(tail, []);
259
+ if (scan.error)
260
+ return usageFail(scan.error);
261
+ const arity = expectArity(scan.literals, 0, 0, `berry-agent plugins ${head}`);
262
+ if ('exitCode' in arity)
263
+ return arity;
264
+ return finish(scan, { kind: 'plugins', sub: { sub: head } });
265
+ }
266
+ case 'install': {
267
+ const scan = scanFlags(tail, INSTALL_SCHEMAS);
268
+ if (scan.error)
269
+ return usageFail(scan.error);
270
+ const args = expectArity(scan.literals, 1, 1, 'berry-agent plugins install <ref> [--min-release-age <分钟>]');
271
+ if ('exitCode' in args)
272
+ return args;
273
+ const ageRaw = scan.values.get('min-release-age');
274
+ // 非负整数域已由 scanFlags 执法——此处仅 Number 化(CLI > env > 缺省三级缺一)
275
+ const minReleaseAge = ageRaw === undefined ? undefined : Number(ageRaw);
276
+ return finish(scan, {
277
+ kind: 'plugins',
278
+ sub: {
279
+ sub: 'install',
280
+ ref: args[0],
281
+ ...(minReleaseAge !== undefined ? { minReleaseAge } : {}),
282
+ },
283
+ });
284
+ }
285
+ case 'uninstall': {
286
+ const scan = scanFlags(tail, UNINSTALL_SCHEMAS);
287
+ if (scan.error)
288
+ return usageFail(scan.error);
289
+ const args = expectArity(scan.literals, 1, 1, 'berry-agent plugins uninstall <id> [--confirm] [--data keep|purge]');
290
+ if ('exitCode' in args)
291
+ return args;
292
+ const dataRaw = scan.values.get('data');
293
+ return finish(scan, {
294
+ kind: 'plugins',
295
+ sub: {
296
+ sub: 'uninstall',
297
+ id: args[0],
298
+ confirm: scan.booleans.has('confirm'),
299
+ dataAction: dataRaw === undefined ? undefined : dataRaw,
300
+ },
301
+ });
302
+ }
303
+ case 'mount':
304
+ case 'unmount':
305
+ case 'toggle':
306
+ case 'update': {
307
+ const scan = scanFlags(tail, []);
308
+ if (scan.error)
309
+ return usageFail(scan.error);
310
+ const args = expectArity(scan.literals, 1, 1, `berry-agent plugins ${head} <id>`);
311
+ if ('exitCode' in args)
312
+ return args;
313
+ return finish(scan, { kind: 'plugins', sub: { sub: head, id: args[0] } });
314
+ }
315
+ default:
316
+ return usageFail(`未知 plugins 子命令:${head}(合法:list/install/uninstall/mount/unmount/toggle/update/check)`);
317
+ }
318
+ }
319
+ /** 解析 sessions 子命令段 */
320
+ function parseSessions(rest) {
321
+ const [head, ...tail] = rest;
322
+ if (head === undefined || head.startsWith('--')) {
323
+ return usageFail('sessions 须带子命令(list/resume/fork/search/reindex)');
324
+ }
325
+ const zeroArg = head === 'list' || head === 'reindex';
326
+ const oneArg = head === 'resume' || head === 'fork' || head === 'search';
327
+ if (!zeroArg && !oneArg) {
328
+ return usageFail(`未知 sessions 子命令:${head}(合法:list/resume/fork/search/reindex)`);
329
+ }
330
+ const scan = scanFlags(tail, []);
331
+ if (scan.error)
332
+ return usageFail(scan.error);
333
+ const usage = zeroArg
334
+ ? `berry-agent sessions ${head}`
335
+ : `berry-agent sessions ${head} <${head === 'search' ? 'query' : 'id'}>`;
336
+ const args = expectArity(scan.literals, zeroArg ? 0 : 1, zeroArg ? 0 : 1, usage);
337
+ if ('exitCode' in args)
338
+ return args;
339
+ if (zeroArg)
340
+ return finish(scan, { kind: 'sessions', sub: { sub: head } });
341
+ return finish(scan, {
342
+ kind: 'sessions',
343
+ sub: head === 'search'
344
+ ? { sub: 'search', query: args[0] }
345
+ : { sub: head, id: args[0] },
346
+ });
347
+ }
348
+ /** credentials 子命令族解析(03 §10.9 人面命令 CLI 面——c-5;namespace 值域执法归命令件单源,本层只执法解析律) */
349
+ const NAMESPACE_FLAG = { name: 'namespace', kind: 'value' };
350
+ function parseCredentials(rest) {
351
+ const [head, ...tail] = rest;
352
+ if (head === undefined || head.startsWith('--')) {
353
+ return usageFail('credentials 须带子命令(add/list/rm)');
354
+ }
355
+ const namespaceOf = (scan) => scan.values.has('namespace') ? scan.values.get('namespace') : undefined;
356
+ switch (head) {
357
+ case 'list': {
358
+ const scan = scanFlags(tail, []);
359
+ if (scan.error)
360
+ return usageFail(scan.error);
361
+ const arity = expectArity(scan.literals, 0, 0, 'berry-agent credentials list');
362
+ if ('exitCode' in arity)
363
+ return arity;
364
+ return finish(scan, { kind: 'credentials', sub: { sub: 'list' } });
365
+ }
366
+ case 'add': {
367
+ const scan = scanFlags(tail, [NAMESPACE_FLAG]);
368
+ if (scan.error)
369
+ return usageFail(scan.error);
370
+ const args = expectArity(scan.literals, 2, 2, 'berry-agent credentials add <name> <value> [--namespace <ns>]');
371
+ if ('exitCode' in args)
372
+ return args;
373
+ const ns = namespaceOf(scan);
374
+ return finish(scan, {
375
+ kind: 'credentials',
376
+ sub: {
377
+ sub: 'add',
378
+ name: args[0],
379
+ value: args[1],
380
+ ...(ns !== undefined ? { namespace: ns } : {}),
381
+ },
382
+ });
383
+ }
384
+ case 'rm': {
385
+ const scan = scanFlags(tail, [NAMESPACE_FLAG]);
386
+ if (scan.error)
387
+ return usageFail(scan.error);
388
+ const args = expectArity(scan.literals, 1, 1, 'berry-agent credentials rm <name> [--namespace <ns>]');
389
+ if ('exitCode' in args)
390
+ return args;
391
+ const ns = namespaceOf(scan);
392
+ return finish(scan, {
393
+ kind: 'credentials',
394
+ sub: { sub: 'rm', name: args[0], ...(ns !== undefined ? { namespace: ns } : {}) },
395
+ });
396
+ }
397
+ default:
398
+ return usageFail(`未知 credentials 子命令:${head}(合法:add/list/rm)`);
399
+ }
400
+ }
401
+ /**
402
+ * doors 子命令族解析(03 §4.6 / 07 §5 定名——CLI 面;g-2):list 受理、
403
+ * open/close 受理为合法解析形(语义拒退 1 归执行层 runDoorsEntry——用法错
404
+ * 与语义拒两档分立);值域执法归段编辑腿单源(plugin-store),本层只执法
405
+ * 解析律。
406
+ */
407
+ function parseDoors(rest) {
408
+ const [head, ...tail] = rest;
409
+ if (head === undefined || head.startsWith('--')) {
410
+ return usageFail('doors 须带子命令(list/open/close——open/close 写动词 TUI /doors 专属,CLI 只读 list)');
411
+ }
412
+ switch (head) {
413
+ case 'list': {
414
+ const scan = scanFlags(tail, []);
415
+ if (scan.error)
416
+ return usageFail(scan.error);
417
+ const arity = expectArity(scan.literals, 0, 0, 'berry-agent doors list');
418
+ if ('exitCode' in arity)
419
+ return arity;
420
+ return finish(scan, { kind: 'doors', sub: { sub: 'list' } });
421
+ }
422
+ case 'open':
423
+ case 'close': {
424
+ const scan = scanFlags(tail, []);
425
+ if (scan.error)
426
+ return usageFail(scan.error);
427
+ const args = expectArity(scan.literals, 1, 1, `berry-agent doors ${head} <capability>`);
428
+ if ('exitCode' in args)
429
+ return args;
430
+ return finish(scan, { kind: 'doors', sub: { sub: head, door: args[0] } });
431
+ }
432
+ default:
433
+ return usageFail(`未知 doors 子命令:${head}(合法:list/open/close)`);
434
+ }
435
+ }
436
+ /** 收尾统一口:help/version 越位短路(执法④——在一切解析错误之后) */
437
+ function finish(scan, command) {
438
+ if (scan.overreach === '--help')
439
+ return { ok: true, command: { kind: 'help', overreach: scan.overreach } };
440
+ if (scan.overreach === '--version')
441
+ return { ok: true, command: { kind: 'version', overreach: scan.overreach } };
442
+ return { ok: true, command };
443
+ }
444
+ /* ---------------- 主入口 ---------------- */
445
+ /**
446
+ * 解析进程 argv(不含 argv[0]/argv[1]——调用方传 process.argv.slice(2))。
447
+ *
448
+ * 分派序:首词 ∈ 子命令集 → 各命令解析器;首词以 `--` 起头或空 → TUI 入口
449
+ * (位置参数非空即退 2——无参 TUI 不收位置参数);其余非旗标首词 → 未知子命令
450
+ * 退 2。
451
+ */
452
+ export function parseCli(argv) {
453
+ const [head, ...rest] = argv;
454
+ if (head === undefined || head.startsWith('--')) {
455
+ const leading = head === undefined ? [] : [head];
456
+ const scan = scanFlags([...leading, ...rest], TUI_SCHEMAS);
457
+ if (scan.error)
458
+ return usageFail(scan.error);
459
+ const arity = expectArity(scan.literals, 0, 0, 'berry-agent(无参 = TUI 主入口;脚本化用 run/serve)');
460
+ if ('exitCode' in arity)
461
+ return arity;
462
+ const port = scan.values.get('port');
463
+ const command = {
464
+ kind: 'tui',
465
+ flags: {
466
+ port: port === undefined ? undefined : Number(port),
467
+ noPlugins: scan.booleans.has('no-plugins'),
468
+ debug: scan.booleans.has('debug'),
469
+ pluginFile: scan.values.get('plugin-file'),
470
+ },
471
+ };
472
+ return finish(scan, command);
473
+ }
474
+ switch (head) {
475
+ case 'run':
476
+ return parseRun(rest);
477
+ case 'serve': {
478
+ // serve status / serve stop 管理动词(零旗标面——单活跃机只读豁免)
479
+ const [sub, ...tail] = rest;
480
+ if (sub === 'status' || sub === 'stop') {
481
+ const scan = scanFlags(tail, []);
482
+ if (scan.error)
483
+ return usageFail(scan.error);
484
+ const arity = expectArity(scan.literals, 0, 0, `berry-agent serve ${sub}`);
485
+ if ('exitCode' in arity)
486
+ return arity;
487
+ return finish(scan, { kind: sub === 'status' ? 'serve-status' : 'serve-stop' });
488
+ }
489
+ return parseServe(rest);
490
+ }
491
+ case 'mcp': {
492
+ const scan = scanFlags(rest, []);
493
+ if (scan.error)
494
+ return usageFail(scan.error);
495
+ const arity = expectArity(scan.literals, 0, 0, 'berry-agent mcp');
496
+ if ('exitCode' in arity)
497
+ return arity;
498
+ return finish(scan, { kind: 'mcp' });
499
+ }
500
+ case 'dump-config': {
501
+ const scan = scanFlags(rest, DUMP_SCHEMAS);
502
+ if (scan.error)
503
+ return usageFail(scan.error);
504
+ // --plugin-file 互斥(03 §7 不变式 7)::memory: 同构诊断须呈现真实
505
+ // 装载面——试件行注入即诊断保真差;收而互斥拒(非未识别拒——message
506
+ // 指向互斥根因而非「拼错旗标」)
507
+ if (scan.values.has('plugin-file')) {
508
+ return usageFail('--plugin-file 与 dump-config 互斥(诊断保真::memory: 面须呈现真实装载形,不注入试件行)');
509
+ }
510
+ const arity = expectArity(scan.literals, 0, 0, 'berry-agent dump-config');
511
+ if ('exitCode' in arity)
512
+ return arity;
513
+ const port = scan.values.get('port');
514
+ const command = {
515
+ kind: 'dump-config',
516
+ flags: {
517
+ port: port === undefined ? undefined : Number(port),
518
+ noPlugins: scan.booleans.has('no-plugins'),
519
+ debug: scan.booleans.has('debug'),
520
+ },
521
+ };
522
+ return finish(scan, command);
523
+ }
524
+ case 'plugins':
525
+ return parsePlugins(rest);
526
+ case 'sessions':
527
+ return parseSessions(rest);
528
+ case 'credentials':
529
+ return parseCredentials(rest);
530
+ case 'doors':
531
+ return parseDoors(rest);
532
+ case 'upgrade': {
533
+ const scan = scanFlags(rest, [DEBUG_FLAG]);
534
+ if (scan.error)
535
+ return usageFail(scan.error);
536
+ const arity = expectArity(scan.literals, 0, 0, 'berry-agent upgrade');
537
+ if ('exitCode' in arity)
538
+ return arity;
539
+ return finish(scan, { kind: 'upgrade' });
540
+ }
541
+ default:
542
+ return usageFail(`未知子命令:${head}(合法:run/serve/mcp/dump-config/plugins/sessions/credentials/doors/upgrade;无参 = TUI 主入口)`);
543
+ }
544
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * host 域错误码补落——`PLUGIN_` 族装载面码(02 §5.3 前缀族明列;语义真源 03 篇)
3
+ * + `TRIGGER_` 族两码(2026-09-07 触发器面 C 批补入——module 段 host 落码定形,
4
+ * 语义真源 03 §2.2/§2.7 触发器行)。
5
+ *
6
+ * 注册纪律:import 发生才注册(与 tools/llm/session 的 codes.ts 同款);
7
+ * 同码重复注册由 contracts 注册表 fail-loud 执法(HOST_ERROR_CODE_CONFLICT)。
8
+ * `PLUGIN_SHAPE_INVALID` 与 `API_` 族四码已随 contracts 首批/API 治理批在册,
9
+ * 本处不重复注册。
10
+ *
11
+ * 批 12d 补落挂账两码:import 门禁越界拒载(03 §3.3 定名
12
+ * `PLUGIN_IMPORT_FORBIDDEN`——字面量腿 throw 形执法 + fsCache 关;动态构造
13
+ * 逃逸残差随沙箱立题,详 03 §3.3 批 12d 勘正段)与库句柄门禁(03 §4.3 定名
14
+ * `PLUGIN_DB_HANDLE_FORBIDDEN`——宿主主库句柄结构性不外露;执法位 =
15
+ * `berry-agent/sqlite` 虚拟键受局面 SqliteFace,face 件随其落码批消费本码)。
16
+ *
17
+ * 2026-09-09 装机面落码批(成熟度缺口 #10)补两码:`PLUGIN_INSTALL_FAILED`
18
+ * (三源执行器统一失败档)与 `PLUGIN_UNINSTALL_REFUSED`(清算防线拒绝档)
19
+ * ——02 §5.3 PLUGIN_ 族同笔入册。
20
+ */
21
+ import { registerErrorCodes } from '../contracts/index.js';
22
+ /** 批 12a 补落的 PLUGIN_ 族码目录(语义真源逐条注) */
23
+ export const HOST_PLUGIN_ERROR_CODES = [
24
+ {
25
+ code: 'PLUGIN_CONFIG_INVALID',
26
+ module: 'host',
27
+ description: '启用行 config 值不合清单 config schema(03 篇 §1.2——装载期拒绝式)',
28
+ },
29
+ {
30
+ code: 'PLUGIN_ROW_INVALID',
31
+ module: 'host',
32
+ description: '启用清单行 schema 违例:未知键/id 缺席或坏形(03 篇 §5.3——行校验拒绝式)',
33
+ },
34
+ {
35
+ code: 'PLUGIN_APPLY_FAILED',
36
+ module: 'host',
37
+ description: '插件 apply 入口抛错(03 篇 §1.3——处置按 /reload 失败三档行级隔离)',
38
+ },
39
+ {
40
+ code: 'PLUGIN_INJECT_UNRESOLVED',
41
+ module: 'host',
42
+ description: '硬依赖(inject)求值后服务缺席拒启(03 篇 §1.3——软依赖缺席仅记 warn)',
43
+ },
44
+ {
45
+ code: 'PLUGIN_ENTRY_UNRESOLVED',
46
+ module: 'host',
47
+ description: '入口模块解析失败:entry 指向文件不存在/不可解析(03 篇 §1.3)',
48
+ },
49
+ {
50
+ code: 'PLUGIN_LOAD_FAILED',
51
+ module: 'host',
52
+ description: 'jiti 装载失败:语法错误/运行时顶层抛错(03 篇 §1.3)',
53
+ },
54
+ {
55
+ code: 'PLUGIN_RATE_LIMITED',
56
+ module: 'host',
57
+ description: '装载器频率护栏:单插件注册/事件动作 >1000 次/1000ms 即拒(03 篇 §3.4)',
58
+ },
59
+ {
60
+ code: 'PLUGIN_EVENT_TYPE_CONFLICT',
61
+ module: 'host',
62
+ description: 'durable 事件词汇撞名拒注册:撞 LIVE 词表既有词汇即拒(03 篇 §2.7 逐动词冲突律——词法身份面拒绝式)',
63
+ },
64
+ {
65
+ code: 'PLUGIN_PROMPT_SLOT_INVALID',
66
+ module: 'host',
67
+ description: '提示词段 slot 非法:非域前缀两段式/域前缀不等于本插件 id(03 篇 §2.7——无 / 单段系宿主自留地不可达)',
68
+ },
69
+ {
70
+ code: 'PLUGIN_PROMPT_SECTION_CONFLICT',
71
+ module: 'host',
72
+ description: '提示词段同 slot 重复注册:两段同位即装配冲突响亮失败(03 篇 §2.7——不静默覆盖)',
73
+ },
74
+ {
75
+ code: 'PLUGIN_HOOK_UNKNOWN',
76
+ module: 'host',
77
+ description: 'hookName 不在钩子主表即拒订阅:fail-closed,未知钩子不静默吞(03 篇 §2.4/§2.7)',
78
+ },
79
+ {
80
+ code: 'PLUGIN_WINDOW_CLOSED',
81
+ module: 'host',
82
+ description: '装载窗口外调用注册动词拒(03 篇 §2.1——唯一例外:宿主回调上下文内〔钩子 handler/工具执行期〕合法,装载器以回调窗重入计数开合)',
83
+ },
84
+ {
85
+ code: 'PLUGIN_IMPORT_FORBIDDEN',
86
+ module: 'host',
87
+ description: 'import 门禁越界拒载:依赖图说明符不在三道白名单(虚拟键/node: 内建/插件目录树内——03 §3.3;字面量腿 transform 钩子 throw 形执法〔error 通道不抛已实证〕+ jiti fsCache 关;门禁定位 = 架构边界非反恶意沙箱,动态构造逃逸残差随沙箱立题)',
88
+ },
89
+ {
90
+ code: 'PLUGIN_DB_HANDLE_FORBIDDEN',
91
+ module: 'host',
92
+ description: '库句柄门禁:违例触达宿主主库句柄(主库句柄结构性不外露——03 §4.3;执法位 = berry-agent/sqlite 受局面 SqliteFace,随 face 件落码批消费)',
93
+ },
94
+ {
95
+ code: 'PLUGIN_CAPABILITY_DOOR_CLOSED',
96
+ module: 'host',
97
+ description: '高危面默认关拒:插件未获用户开门授予即触达高危面注册/换装(03 §4.6 用户主权开门制——授予位唯一正门 = 启用清单行 opens;裁决核 = contracts adjudicateCapabilityDoor,throw 位随界面后端换装缝/路由受理面落码批接线)',
98
+ },
99
+ {
100
+ code: 'PLUGIN_INSTALL_FAILED',
101
+ module: 'host',
102
+ description: '装机执行失败:三源执行器 spawn 非零/收割抛错/ref 与 env 坏形统一档(03 §5.4——成熟度缺口 #10 装机面落码批;失败回滚不留半装机残影)',
103
+ },
104
+ {
105
+ code: 'PLUGIN_UNINSTALL_REFUSED',
106
+ module: 'host',
107
+ description: '卸载清算防线拒绝档:删除目标逸出装机子树/插件数据子目录(assertInsideInstallSubtree/assertInsidePluginData——03 §5.5 段②③),或坏账本拒写防覆盖',
108
+ },
109
+ {
110
+ code: 'TRIGGER_NAME_EXISTS',
111
+ module: 'host',
112
+ description: '触发器撞名拒:name 撞既有在册触发器(含 issue 件 core: 域)——词法身份面拒绝式,审计归因面重影即歧义(03 §2.7;2026-09-07 触发器面 C 批锚定,执法随 C-2 注册面接线)',
113
+ },
114
+ {
115
+ code: 'TRIGGER_NAME_INVALID',
116
+ module: 'host',
117
+ description: '触发器名词法违例拒:name 非域名两段式或域前缀 ≠ 本插件 id(core: 件去前缀取 name 段——防跨插件冒名,03 §2.7 registerSection 行同法;2026-09-07 触发器面 C 批锚定,执法随 C-2 注册面接线)',
118
+ },
119
+ ];
120
+ registerErrorCodes(HOST_PLUGIN_ERROR_CODES);