@armadra/agent 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/CHANGELOG.md +184 -1
  2. package/README.md +202 -83
  3. package/THIRD_PARTY_NOTICES.md +34 -0
  4. package/dist/acp.d.ts +18 -0
  5. package/dist/acp.js +19 -0
  6. package/dist/agent/limits.d.ts +38 -0
  7. package/dist/agent/limits.js +127 -0
  8. package/dist/agent/loop-guard.d.ts +38 -0
  9. package/dist/agent/loop-guard.js +95 -0
  10. package/dist/agent/loop.d.ts +4 -0
  11. package/dist/agent/loop.js +7 -0
  12. package/dist/agent/prompt-rules.d.ts +12 -0
  13. package/dist/agent/prompt-rules.js +18 -0
  14. package/dist/agent/reminders.d.ts +59 -0
  15. package/dist/agent/reminders.js +327 -0
  16. package/dist/agent/session-cache.d.ts +5 -0
  17. package/dist/agent/session-cache.js +17 -1
  18. package/dist/agent/session-classifier.d.ts +1 -1
  19. package/dist/agent/session-classifier.js +3 -1
  20. package/dist/agent/session-compaction.d.ts +35 -6
  21. package/dist/agent/session-compaction.js +157 -31
  22. package/dist/agent/session-core.d.ts +27 -1
  23. package/dist/agent/session-extensions.d.ts +61 -0
  24. package/dist/agent/session-extensions.js +129 -0
  25. package/dist/agent/session-images.d.ts +23 -0
  26. package/dist/agent/session-images.js +97 -0
  27. package/dist/agent/session-plan.d.ts +21 -0
  28. package/dist/agent/session-plan.js +524 -0
  29. package/dist/agent/session-rewind.d.ts +81 -0
  30. package/dist/agent/session-rewind.js +354 -0
  31. package/dist/agent/session-run.d.ts +28 -1
  32. package/dist/agent/session-run.js +157 -6
  33. package/dist/agent/session-settings.d.ts +49 -0
  34. package/dist/agent/session-settings.js +95 -0
  35. package/dist/agent/session-subagent.d.ts +36 -24
  36. package/dist/agent/session-subagent.js +259 -129
  37. package/dist/agent/session-sync.d.ts +10 -3
  38. package/dist/agent/session-sync.js +37 -8
  39. package/dist/agent/session-telemetry.d.ts +39 -0
  40. package/dist/agent/session-telemetry.js +231 -0
  41. package/dist/agent/session-tools.js +40 -1
  42. package/dist/agent/session.d.ts +30 -29
  43. package/dist/agent/session.js +79 -123
  44. package/dist/agent/subagent-registry.d.ts +91 -0
  45. package/dist/agent/subagent-registry.js +494 -0
  46. package/dist/agent/system-prompt.d.ts +6 -3
  47. package/dist/agent/system-prompt.js +7 -2
  48. package/dist/agent/tool-runner.d.ts +8 -1
  49. package/dist/agent/tool-runner.js +57 -4
  50. package/dist/agent/types-w5.d.ts +192 -0
  51. package/dist/agent/types-w5.js +10 -0
  52. package/dist/agent/types.d.ts +47 -4
  53. package/dist/agent/types.js +2 -0
  54. package/dist/agent/worktree.d.ts +36 -0
  55. package/dist/agent/worktree.js +86 -0
  56. package/dist/agents/builtin.d.ts +14 -0
  57. package/dist/agents/builtin.js +39 -0
  58. package/dist/agents/catalog.d.ts +43 -0
  59. package/dist/agents/catalog.js +82 -0
  60. package/dist/agents/discover.d.ts +35 -0
  61. package/dist/agents/discover.js +83 -0
  62. package/dist/agents/external.d.ts +82 -0
  63. package/dist/agents/external.js +326 -0
  64. package/dist/agents/parse.d.ts +18 -0
  65. package/dist/agents/parse.js +116 -0
  66. package/dist/agents/result.d.ts +32 -0
  67. package/dist/agents/result.js +67 -0
  68. package/dist/agents/task-control.d.ts +17 -0
  69. package/dist/agents/task-control.js +17 -0
  70. package/dist/agents/task-record.d.ts +78 -0
  71. package/dist/agents/task-record.js +141 -0
  72. package/dist/agents/types.d.ts +46 -0
  73. package/dist/agents/types.js +8 -0
  74. package/dist/ai/apis/anthropic-compat.d.ts +36 -0
  75. package/dist/ai/apis/anthropic-compat.js +92 -0
  76. package/dist/ai/apis/anthropic-request.d.ts +7 -6
  77. package/dist/ai/apis/anthropic-request.js +10 -28
  78. package/dist/ai/apis/cache-params.d.ts +11 -2
  79. package/dist/ai/apis/cache-params.js +25 -6
  80. package/dist/ai/apis/openai-compat.d.ts +4 -1
  81. package/dist/ai/apis/openai-compat.js +8 -1
  82. package/dist/ai/image-limits.d.ts +45 -0
  83. package/dist/ai/image-limits.js +68 -0
  84. package/dist/ai/providers/builtin.d.ts +18 -6
  85. package/dist/ai/providers/builtin.js +135 -6
  86. package/dist/ai/providers/catalog-data.js +17 -13
  87. package/dist/ai/providers/catalog.d.ts +60 -7
  88. package/dist/ai/providers/catalog.js +197 -38
  89. package/dist/ai/providers/channels.d.ts +33 -3
  90. package/dist/ai/providers/channels.js +108 -7
  91. package/dist/ai/providers/enrich.d.ts +6 -3
  92. package/dist/ai/providers/enrich.js +19 -4
  93. package/dist/ai/providers/models-dev-cache.d.ts +28 -24
  94. package/dist/ai/providers/models-dev-cache.js +92 -78
  95. package/dist/ai/providers/models-dev-data.d.ts +7 -0
  96. package/dist/ai/providers/models-dev-data.js +32 -0
  97. package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
  98. package/dist/ai/providers/models-dev-snapshot.js +137 -0
  99. package/dist/ai/providers/models-dev.d.ts +51 -10
  100. package/dist/ai/providers/models-dev.js +132 -39
  101. package/dist/ai/providers/registry.d.ts +20 -10
  102. package/dist/ai/providers/registry.js +82 -43
  103. package/dist/ai/types.d.ts +28 -2
  104. package/dist/ai/types.js +5 -0
  105. package/dist/bundle/ama.cjs +37605 -21619
  106. package/dist/checkpoints/backend.d.ts +61 -0
  107. package/dist/checkpoints/backend.js +135 -0
  108. package/dist/checkpoints/blobs.d.ts +60 -0
  109. package/dist/checkpoints/blobs.js +203 -0
  110. package/dist/checkpoints/gc.d.ts +47 -0
  111. package/dist/checkpoints/gc.js +144 -0
  112. package/dist/checkpoints/git-head.d.ts +15 -0
  113. package/dist/checkpoints/git-head.js +89 -0
  114. package/dist/checkpoints/index.d.ts +17 -0
  115. package/dist/checkpoints/index.js +17 -0
  116. package/dist/checkpoints/replay.d.ts +48 -0
  117. package/dist/checkpoints/replay.js +154 -0
  118. package/dist/checkpoints/restore.d.ts +86 -0
  119. package/dist/checkpoints/restore.js +263 -0
  120. package/dist/checkpoints/settings.d.ts +14 -0
  121. package/dist/checkpoints/settings.js +23 -0
  122. package/dist/checkpoints/shadow-git.d.ts +108 -0
  123. package/dist/checkpoints/shadow-git.js +491 -0
  124. package/dist/checkpoints/shadow-restore.d.ts +25 -0
  125. package/dist/checkpoints/shadow-restore.js +128 -0
  126. package/dist/checkpoints/tracker.d.ts +64 -0
  127. package/dist/checkpoints/tracker.js +192 -0
  128. package/dist/checkpoints/types.d.ts +99 -0
  129. package/dist/checkpoints/types.js +12 -0
  130. package/dist/cli/args.d.ts +8 -4
  131. package/dist/cli/args.js +17 -97
  132. package/dist/cli/bootstrap.js +13 -1
  133. package/dist/cli/choice-prompt.d.ts +58 -0
  134. package/dist/cli/choice-prompt.js +140 -0
  135. package/dist/cli/codemode-notice.d.ts +3 -2
  136. package/dist/cli/codemode-notice.js +3 -2
  137. package/dist/cli/compose-agents.d.ts +27 -0
  138. package/dist/cli/compose-agents.js +111 -0
  139. package/dist/cli/compose-extensions.d.ts +29 -0
  140. package/dist/cli/compose-extensions.js +44 -0
  141. package/dist/cli/compose-session.d.ts +3 -0
  142. package/dist/cli/compose-session.js +47 -4
  143. package/dist/cli/compose.d.ts +3 -0
  144. package/dist/cli/compose.js +33 -6
  145. package/dist/cli/deps.d.ts +6 -0
  146. package/dist/cli/exit-codes.d.ts +10 -0
  147. package/dist/cli/exit-codes.js +12 -0
  148. package/dist/cli/help-text.d.ts +4 -0
  149. package/dist/cli/help-text.js +102 -0
  150. package/dist/cli/startup-screen.js +5 -3
  151. package/dist/cli/startup-steps.js +7 -1
  152. package/dist/cli/subcommands/config.d.ts +4 -1
  153. package/dist/cli/subcommands/config.js +17 -6
  154. package/dist/cli/subcommands/doctor.js +21 -0
  155. package/dist/cli/subcommands/models-cache-probe.d.ts +1 -1
  156. package/dist/cli/subcommands/models-cache-probe.js +3 -12
  157. package/dist/cli/subcommands/models-discover.js +5 -6
  158. package/dist/cli/subcommands/models.d.ts +2 -0
  159. package/dist/cli/subcommands/models.js +33 -14
  160. package/dist/cli/subcommands/providers.d.ts +1 -1
  161. package/dist/cli/subcommands/providers.js +8 -15
  162. package/dist/cli/subcommands/sessions.d.ts +3 -1
  163. package/dist/cli/subcommands/sessions.js +36 -2
  164. package/dist/codemode/capability.d.ts +24 -7
  165. package/dist/codemode/capability.js +38 -10
  166. package/dist/codemode/host-side.d.ts +14 -0
  167. package/dist/codemode/host-side.js +24 -1
  168. package/dist/codemode/tool.d.ts +1 -1
  169. package/dist/codemode/tool.js +6 -4
  170. package/dist/compaction/breaker.d.ts +25 -9
  171. package/dist/compaction/breaker.js +47 -17
  172. package/dist/compaction/estimate.d.ts +11 -3
  173. package/dist/compaction/estimate.js +64 -22
  174. package/dist/compaction/image-budget.d.ts +45 -0
  175. package/dist/compaction/image-budget.js +115 -0
  176. package/dist/compaction/post-compact.d.ts +38 -0
  177. package/dist/compaction/post-compact.js +152 -0
  178. package/dist/compaction/protect.d.ts +27 -0
  179. package/dist/compaction/protect.js +56 -0
  180. package/dist/compaction/prune-tier.d.ts +58 -12
  181. package/dist/compaction/prune-tier.js +120 -54
  182. package/dist/compaction/summarize-tier.d.ts +23 -4
  183. package/dist/compaction/summarize-tier.js +100 -29
  184. package/dist/config/checker.d.ts +28 -0
  185. package/dist/config/checker.js +97 -0
  186. package/dist/config/json-schema.js +63 -2
  187. package/dist/config/key-docs.js +72 -3
  188. package/dist/config/merge.d.ts +5 -3
  189. package/dist/config/merge.js +81 -7
  190. package/dist/config/profile.d.ts +2 -0
  191. package/dist/config/profile.js +2 -0
  192. package/dist/config/schema-w5.d.ts +18 -0
  193. package/dist/config/schema-w5.js +109 -0
  194. package/dist/config/schema.d.ts +5 -9
  195. package/dist/config/schema.js +68 -114
  196. package/dist/config/types-w5.d.ts +118 -0
  197. package/dist/config/types-w5.js +20 -0
  198. package/dist/config/types.d.ts +50 -1
  199. package/dist/config/types.js +12 -0
  200. package/dist/drivers/acp/client.d.ts +57 -0
  201. package/dist/drivers/acp/client.js +160 -0
  202. package/dist/drivers/acp/driver.d.ts +31 -0
  203. package/dist/drivers/acp/driver.js +274 -0
  204. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  205. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  206. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  207. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  208. package/dist/drivers/acp/types.d.ts +285 -0
  209. package/dist/drivers/acp/types.js +36 -0
  210. package/dist/drivers/agents.d.ts +58 -0
  211. package/dist/drivers/agents.js +142 -0
  212. package/dist/drivers/base.d.ts +35 -0
  213. package/dist/drivers/base.js +59 -0
  214. package/dist/drivers/catalog.d.ts +46 -0
  215. package/dist/drivers/catalog.js +167 -0
  216. package/dist/drivers/env.d.ts +20 -0
  217. package/dist/drivers/env.js +46 -0
  218. package/dist/drivers/host-runners.d.ts +18 -0
  219. package/dist/drivers/host-runners.js +45 -0
  220. package/dist/drivers/jsonrpc.d.ts +58 -0
  221. package/dist/drivers/jsonrpc.js +180 -0
  222. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  223. package/dist/drivers/native/claude-normalize.js +106 -0
  224. package/dist/drivers/native/claude-stream.d.ts +29 -0
  225. package/dist/drivers/native/claude-stream.js +456 -0
  226. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  227. package/dist/drivers/native/codex-app-server.js +407 -0
  228. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  229. package/dist/drivers/native/codex-normalize.js +124 -0
  230. package/dist/drivers/native/oneshot.d.ts +28 -0
  231. package/dist/drivers/native/oneshot.js +312 -0
  232. package/dist/drivers/permissions.d.ts +40 -0
  233. package/dist/drivers/permissions.js +92 -0
  234. package/dist/drivers/pids.d.ts +32 -0
  235. package/dist/drivers/pids.js +93 -0
  236. package/dist/drivers/pool.d.ts +28 -0
  237. package/dist/drivers/pool.js +96 -0
  238. package/dist/drivers/probe.d.ts +47 -0
  239. package/dist/drivers/probe.js +172 -0
  240. package/dist/drivers/process.d.ts +48 -0
  241. package/dist/drivers/process.js +100 -0
  242. package/dist/drivers/runner.d.ts +61 -0
  243. package/dist/drivers/runner.js +388 -0
  244. package/dist/drivers/store.d.ts +49 -0
  245. package/dist/drivers/store.js +91 -0
  246. package/dist/drivers/turn.d.ts +41 -0
  247. package/dist/drivers/turn.js +99 -0
  248. package/dist/drivers/types.d.ts +122 -0
  249. package/dist/drivers/types.js +11 -0
  250. package/dist/git/info.d.ts +75 -0
  251. package/dist/git/info.js +191 -0
  252. package/dist/hooks/protocol.js +6 -1
  253. package/dist/hooks/types.d.ts +10 -1
  254. package/dist/hooks/types.js +2 -0
  255. package/dist/host/api-impl.d.ts +7 -0
  256. package/dist/host/api-impl.js +15 -0
  257. package/dist/host/types.d.ts +24 -2
  258. package/dist/host/types.js +4 -0
  259. package/dist/index.d.ts +3 -0
  260. package/dist/index.js +1 -0
  261. package/dist/modes/acp/acp-events.d.ts +46 -0
  262. package/dist/modes/acp/acp-events.js +233 -0
  263. package/dist/modes/acp/acp-mode.d.ts +17 -0
  264. package/dist/modes/acp/acp-mode.js +47 -0
  265. package/dist/modes/acp/acp-server.d.ts +79 -0
  266. package/dist/modes/acp/acp-server.js +315 -0
  267. package/dist/modes/commands-core.d.ts +13 -1
  268. package/dist/modes/commands-core.js +64 -0
  269. package/dist/modes/image-input.d.ts +12 -4
  270. package/dist/modes/image-input.js +22 -5
  271. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  272. package/dist/modes/interactive/agent-panels.js +103 -0
  273. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  274. package/dist/modes/interactive/agent-ui.js +234 -0
  275. package/dist/modes/interactive/approval-dialog.d.ts +21 -4
  276. package/dist/modes/interactive/approval-dialog.js +98 -20
  277. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  278. package/dist/modes/interactive/approval-merge.js +89 -0
  279. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  280. package/dist/modes/interactive/clipboard-paste.js +28 -0
  281. package/dist/modes/interactive/commands.d.ts +12 -1
  282. package/dist/modes/interactive/commands.js +31 -1
  283. package/dist/modes/interactive/confirm-dialog.d.ts +49 -0
  284. package/dist/modes/interactive/confirm-dialog.js +121 -0
  285. package/dist/modes/interactive/double-esc.d.ts +20 -0
  286. package/dist/modes/interactive/double-esc.js +34 -0
  287. package/dist/modes/interactive/event-notices.d.ts +32 -0
  288. package/dist/modes/interactive/event-notices.js +79 -0
  289. package/dist/modes/interactive/external-editor.d.ts +16 -0
  290. package/dist/modes/interactive/external-editor.js +39 -0
  291. package/dist/modes/interactive/interactive-mode.d.ts +14 -1
  292. package/dist/modes/interactive/interactive-mode.js +140 -136
  293. package/dist/modes/interactive/key-dispatch.d.ts +22 -2
  294. package/dist/modes/interactive/key-dispatch.js +66 -7
  295. package/dist/modes/interactive/line/line-mode.d.ts +4 -1
  296. package/dist/modes/interactive/line/line-mode.js +31 -5
  297. package/dist/modes/interactive/line/line-render.d.ts +2 -1
  298. package/dist/modes/interactive/line/line-render.js +40 -4
  299. package/dist/modes/interactive/message-view.d.ts +1 -1
  300. package/dist/modes/interactive/message-view.js +24 -2
  301. package/dist/modes/interactive/panels.d.ts +18 -1
  302. package/dist/modes/interactive/panels.js +19 -5
  303. package/dist/modes/interactive/plan-command.d.ts +40 -0
  304. package/dist/modes/interactive/plan-command.js +129 -0
  305. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  306. package/dist/modes/interactive/plan-dialog.js +290 -0
  307. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  308. package/dist/modes/interactive/plan-flow.js +98 -0
  309. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  310. package/dist/modes/interactive/rewind-command.js +106 -0
  311. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  312. package/dist/modes/interactive/rewind-flow.js +151 -0
  313. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  314. package/dist/modes/interactive/rewind-list.js +123 -0
  315. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  316. package/dist/modes/interactive/rewind-panel.js +309 -0
  317. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  318. package/dist/modes/interactive/rewind-text.js +139 -0
  319. package/dist/modes/interactive/session-events.d.ts +24 -0
  320. package/dist/modes/interactive/session-events.js +96 -0
  321. package/dist/modes/interactive/startup-ui.js +5 -1
  322. package/dist/modes/interactive/status-area.d.ts +73 -0
  323. package/dist/modes/interactive/status-area.js +190 -0
  324. package/dist/modes/interactive/status-bar.d.ts +99 -11
  325. package/dist/modes/interactive/status-bar.js +273 -90
  326. package/dist/modes/interactive/status-line.d.ts +33 -0
  327. package/dist/modes/interactive/status-line.js +113 -0
  328. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  329. package/dist/modes/interactive/subagent-view.js +154 -0
  330. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  331. package/dist/modes/interactive/tasks-report.js +114 -0
  332. package/dist/modes/interactive/tool-view.d.ts +12 -2
  333. package/dist/modes/interactive/tool-view.js +34 -4
  334. package/dist/modes/print/print-mode.d.ts +13 -4
  335. package/dist/modes/print/print-mode.js +56 -12
  336. package/dist/modes/rpc/commands.d.ts +9 -0
  337. package/dist/modes/rpc/commands.js +44 -0
  338. package/dist/modes/rpc/rpc-mode.js +7 -1
  339. package/dist/modes/session-report.d.ts +11 -0
  340. package/dist/modes/session-report.js +48 -1
  341. package/dist/permissions/auto-safe.d.ts +5 -0
  342. package/dist/permissions/auto-safe.js +18 -0
  343. package/dist/permissions/bypass.d.ts +32 -0
  344. package/dist/permissions/bypass.js +36 -0
  345. package/dist/permissions/classifier.d.ts +4 -0
  346. package/dist/permissions/classifier.js +2 -0
  347. package/dist/permissions/modes.js +1 -1
  348. package/dist/permissions/pipeline.d.ts +43 -4
  349. package/dist/permissions/pipeline.js +114 -9
  350. package/dist/permissions/readonly-bash.d.ts +30 -0
  351. package/dist/permissions/readonly-bash.js +118 -0
  352. package/dist/permissions/types.d.ts +42 -0
  353. package/dist/plan/compose.d.ts +9 -0
  354. package/dist/plan/compose.js +19 -0
  355. package/dist/plan/controller.d.ts +71 -0
  356. package/dist/plan/controller.js +27 -0
  357. package/dist/plan/done-markers.d.ts +17 -0
  358. package/dist/plan/done-markers.js +51 -0
  359. package/dist/plan/extract.d.ts +29 -0
  360. package/dist/plan/extract.js +160 -0
  361. package/dist/plan/prompts.d.ts +36 -0
  362. package/dist/plan/prompts.js +89 -0
  363. package/dist/plan/store.d.ts +37 -0
  364. package/dist/plan/store.js +90 -0
  365. package/dist/rpc.d.ts +58 -2
  366. package/dist/rpc.js +7 -0
  367. package/dist/sandbox/bash.d.ts +74 -0
  368. package/dist/sandbox/bash.js +126 -0
  369. package/dist/sandbox/detect.d.ts +48 -0
  370. package/dist/sandbox/detect.js +149 -0
  371. package/dist/sandbox/index.d.ts +5 -0
  372. package/dist/sandbox/index.js +5 -0
  373. package/dist/sandbox/profile.d.ts +33 -0
  374. package/dist/sandbox/profile.js +76 -0
  375. package/dist/sandbox/wrap.d.ts +29 -0
  376. package/dist/sandbox/wrap.js +117 -0
  377. package/dist/sdk.d.ts +33 -2
  378. package/dist/sdk.js +24 -2
  379. package/dist/session/types.d.ts +3 -1
  380. package/dist/session/types.js +1 -0
  381. package/dist/skills/builtin.d.ts +31 -0
  382. package/dist/skills/builtin.js +109 -0
  383. package/dist/skills/discover.d.ts +2 -1
  384. package/dist/skills/index-prompt.js +5 -8
  385. package/dist/tools/background-jobs.d.ts +71 -0
  386. package/dist/tools/background-jobs.js +198 -0
  387. package/dist/tools/bash.d.ts +53 -1
  388. package/dist/tools/bash.js +158 -7
  389. package/dist/tools/clipboard-image.d.ts +44 -0
  390. package/dist/tools/clipboard-image.js +148 -0
  391. package/dist/tools/edit.d.ts +2 -0
  392. package/dist/tools/edit.js +18 -3
  393. package/dist/tools/image-file.d.ts +38 -3
  394. package/dist/tools/image-file.js +81 -10
  395. package/dist/tools/image-resize.d.ts +58 -0
  396. package/dist/tools/image-resize.js +97 -0
  397. package/dist/tools/presets.d.ts +7 -2
  398. package/dist/tools/presets.js +11 -4
  399. package/dist/tools/read.d.ts +5 -2
  400. package/dist/tools/read.js +13 -10
  401. package/dist/tools/registry.d.ts +7 -1
  402. package/dist/tools/registry.js +27 -4
  403. package/dist/tools/task-ctl.d.ts +22 -0
  404. package/dist/tools/task-ctl.js +116 -0
  405. package/dist/tools/task.d.ts +22 -10
  406. package/dist/tools/task.js +66 -26
  407. package/dist/tools/todo.d.ts +22 -2
  408. package/dist/tools/todo.js +58 -14
  409. package/dist/tools/truncate.d.ts +15 -0
  410. package/dist/tools/truncate.js +25 -0
  411. package/dist/tools/types.d.ts +113 -0
  412. package/dist/tools/types.js +5 -0
  413. package/dist/tools/write.js +3 -0
  414. package/dist/tui/glyphs.d.ts +4 -0
  415. package/dist/tui/glyphs.js +4 -0
  416. package/dist/tui/keybindings.d.ts +6 -1
  417. package/dist/tui/keybindings.js +6 -1
  418. package/docs/acp.md +78 -0
  419. package/docs/agents.md +250 -0
  420. package/docs/codemode.md +12 -8
  421. package/docs/hooks.md +26 -22
  422. package/docs/permissions.md +78 -13
  423. package/docs/plan.md +107 -0
  424. package/docs/providers.md +228 -52
  425. package/docs/rewind-plan.md +181 -0
  426. package/docs/rpc.md +92 -5
  427. package/docs/sandbox.md +215 -0
  428. package/docs/session-format.md +41 -21
  429. package/docs/sessions.md +41 -1
  430. package/docs/tui-design.md +751 -0
  431. package/docs/tui.md +179 -21
  432. package/package.json +13 -2
@@ -0,0 +1,97 @@
1
+ /**
2
+ * 配置校验的诊断收集器(从 schema.ts 抽出,schema-w5.ts 共用)。[W5-C0]
3
+ */
4
+ export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
5
+ export class Checker {
6
+ diagnostics = [];
7
+ error(path, message) {
8
+ this.diagnostics.push({ severity: "error", path, message });
9
+ }
10
+ warn(path, message) {
11
+ this.diagnostics.push({ severity: "warning", path, message });
12
+ }
13
+ object(value, path) {
14
+ if (typeof value === "object" && value !== null && !Array.isArray(value))
15
+ return true;
16
+ this.error(path, "应为对象");
17
+ return false;
18
+ }
19
+ /** 未知字段只警告(前向兼容)。 */
20
+ keys(value, path, allowed) {
21
+ for (const key of Object.keys(value)) {
22
+ if (!allowed.includes(key))
23
+ this.warn(join(path, key), "未知字段,已忽略");
24
+ }
25
+ }
26
+ version(value, path) {
27
+ if (value["version"] !== 1)
28
+ this.error(join(path, "version"), "version 必须为 1");
29
+ }
30
+ string(value, key, path, required = false) {
31
+ const v = value[key];
32
+ if (v === undefined) {
33
+ if (required)
34
+ this.error(join(path, key), "缺少必填字符串");
35
+ return;
36
+ }
37
+ if (typeof v !== "string")
38
+ this.error(join(path, key), "应为字符串");
39
+ }
40
+ boolean(value, key, path) {
41
+ const v = value[key];
42
+ if (v !== undefined && typeof v !== "boolean")
43
+ this.error(join(path, key), "应为布尔值");
44
+ }
45
+ number(value, key, path, min = 0, max = Number.MAX_SAFE_INTEGER) {
46
+ const v = value[key];
47
+ if (v === undefined)
48
+ return;
49
+ if (typeof v !== "number" || !Number.isFinite(v)) {
50
+ this.error(join(path, key), "应为数字");
51
+ }
52
+ else if (v < min || v > max) {
53
+ this.error(join(path, key), `应在 ${min}–${max} 之间`);
54
+ }
55
+ }
56
+ oneOf(value, key, path, choices) {
57
+ const v = value[key];
58
+ if (v === undefined)
59
+ return;
60
+ if (typeof v !== "string" || !choices.includes(v)) {
61
+ this.error(join(path, key), `取值应为 ${choices.join(" | ")}`);
62
+ }
63
+ }
64
+ stringArray(value, key, path) {
65
+ const v = value[key];
66
+ if (v === undefined)
67
+ return;
68
+ if (!Array.isArray(v) || v.some((item) => typeof item !== "string")) {
69
+ this.error(join(path, key), "应为字符串数组");
70
+ }
71
+ }
72
+ stringRecord(value, key, path) {
73
+ const v = value[key];
74
+ if (v === undefined)
75
+ return;
76
+ if (!this.object(v, join(path, key)))
77
+ return;
78
+ for (const [k, item] of Object.entries(v)) {
79
+ if (typeof item !== "string")
80
+ this.error(join(join(path, key), k), "应为字符串");
81
+ }
82
+ }
83
+ }
84
+ export function join(path, key) {
85
+ if (typeof key === "number")
86
+ return `${path}[${key}]`;
87
+ return path === "" ? key : `${path}.${key}`;
88
+ }
89
+ export function checkSection(c, config, key, allowed, body) {
90
+ const section = config[key];
91
+ if (section === undefined)
92
+ return;
93
+ if (!c.object(section, key))
94
+ return;
95
+ c.keys(section, key, allowed);
96
+ body(section, key);
97
+ }
@@ -9,7 +9,9 @@ import { WARMING_MODES } from "../ai/cache/types.js";
9
9
  import { PERMISSION_MODES_STRICT_FIRST } from "../permissions/types.js";
10
10
  import { CONFIG_KEY_DOCS, DYNAMIC_DEFAULTS, defaultFor } from "./key-docs.js";
11
11
  import { HOOK_TIMEOUT_MAX_MS, THINKING_LEVELS } from "./schema.js";
12
- import { CACHE_RETENTIONS, CHANNEL_NAME_PATTERN, CODEMODE_MODES, TOOLS_PRESET_INPUTS, } from "./types.js";
12
+ import { CACHE_RETENTIONS, CHANNEL_NAME_PATTERN, CHECKPOINT_MODES, SANDBOX_ENABLED_MODES, SANDBOX_NETWORK_MODES, CODEMODE_MODES, IMAGE_RESIZE_MODES, PLAN_BASH_MODES_STRICT_FIRST, PLAN_UNATTENDED_MODES, STATUS_LINE_MODES, TOOLS_PRESET_INPUTS, } from "./types.js";
13
+ import { AGENT_ID_PATTERN } from "./schema-w5.js";
14
+ import { AGENTS_RESERVED_KEYS } from "./types-w5.js";
13
15
  export const CONFIG_SCHEMA_FILE = "config.schema.json";
14
16
  export const CONFIG_SCHEMA_ID = "https://github.com/Owlbay/armadra-agent/config.schema.json";
15
17
  const KNOWN_APIS = [
@@ -121,6 +123,42 @@ const provider = object({
121
123
  models: { type: "array", items: model("自定义模型(同 id 整条替换)") },
122
124
  modelOverrides: { type: "array", items: model("只改已有模型的元数据") },
123
125
  });
126
+ // [W5-C0] 第五波的段(规则同 schema-w5.ts)
127
+ const agentEntry = object({
128
+ maxConcurrent: num(1, 64),
129
+ maxMode: oneOf(PERMISSION_MODES_STRICT_FIRST),
130
+ model: str(),
131
+ env: object({ passthrough: strings }),
132
+ });
133
+ function w5Sections() {
134
+ return {
135
+ images: object({ resize: oneOf(IMAGE_RESIZE_MODES) }),
136
+ plan: object({
137
+ bash: oneOf(PLAN_BASH_MODES_STRICT_FIRST),
138
+ directory: str(),
139
+ unattended: oneOf(PLAN_UNATTENDED_MODES),
140
+ model: str(),
141
+ thinkingLevel: oneOf(THINKING_LEVELS),
142
+ }),
143
+ agents: object({ maxConcurrent: num(1, 64), sessionBudgetUsd: num(0), dirs: strings }, {
144
+ additionalProperties: agentEntry,
145
+ propertyNames: {
146
+ pattern: `^(${AGENTS_RESERVED_KEYS.join("|")}|${AGENT_ID_PATTERN.source.slice(1, -1)})$`,
147
+ },
148
+ }),
149
+ subagents: object({ maxConcurrent: num(1, 64), maxPending: num(0, 1024), defaultModel: str() }),
150
+ models: object({ aliases: object({ fast: str(), strong: str() }) }),
151
+ fallbackModel: str(),
152
+ limits: object({ maxTurns: num(1), maxCostUsd: num(0) }),
153
+ reminders: object({
154
+ todo: bool(),
155
+ fileChanges: bool(),
156
+ contextPressure: bool(),
157
+ budget: bool(),
158
+ }),
159
+ todo: object({ reminder: num(0) }),
160
+ };
161
+ }
124
162
  /** 给顶层与各段的键写上 description 与 default(key-docs.ts);供应商内部不动。 */
125
163
  function annotate(properties, prefix = "") {
126
164
  for (const [key, shared] of Object.entries(properties)) {
@@ -166,7 +204,16 @@ function buildBaseSchema() {
166
204
  autoModel: str("auto 模式分类器的模型 provider/model;缺省用当前会话模型"),
167
205
  autoSafeCommands: strings,
168
206
  }),
169
- compaction: object({ enabled: bool(), reserveTokens: num(0), keepRecentTokens: num(0) }),
207
+ compaction: object({
208
+ enabled: bool(),
209
+ reserveTokens: num(0),
210
+ keepRecentTokens: num(0),
211
+ prune: object({
212
+ keepResults: num(0),
213
+ clearAtLeast: { anyOf: [{ const: "auto" }, { type: "number", minimum: 0 }] },
214
+ }),
215
+ pruneExclude: strings,
216
+ }),
170
217
  retry: object({
171
218
  enabled: bool(),
172
219
  maxRetries: num(0, 100),
@@ -195,6 +242,8 @@ function buildBaseSchema() {
195
242
  ascii: bool(),
196
243
  compact: bool(),
197
244
  animation: bool(),
245
+ restoreOnCancel: bool(),
246
+ statusLine: oneOf(STATUS_LINE_MODES),
198
247
  }),
199
248
  skills: object({ dirs: strings }),
200
249
  cache: object({
@@ -205,6 +254,18 @@ function buildBaseSchema() {
205
254
  warmSubagents: bool(),
206
255
  }),
207
256
  request: object({ idleTimeoutMs: num(0) }),
257
+ checkpoints: object({
258
+ mode: oneOf(CHECKPOINT_MODES),
259
+ maxFileBytes: num(0),
260
+ keep: num(1),
261
+ }),
262
+ sandbox: object({
263
+ enabled: oneOf(SANDBOX_ENABLED_MODES),
264
+ bash: oneOf(SANDBOX_ENABLED_MODES, "bash 经 OS 沙箱运行(缺省 off)"),
265
+ network: oneOf(SANDBOX_NETWORK_MODES, "bash 沙箱里的网络(缺省 deny)"),
266
+ writable: { ...strings, description: "bash 沙箱追加的可写目录(绝对路径或 ~/…)" },
267
+ }),
268
+ ...w5Sections(),
208
269
  }),
209
270
  required: ["version"],
210
271
  };
@@ -12,7 +12,7 @@
12
12
  import { DEFAULT_IDLE_TIMEOUT_MS } from "../ai/http.js";
13
13
  import { DEFAULT_INLINE_BUDGET } from "../codemode/declarations.js";
14
14
  import { DEFAULT_CONFIG, mergeConfig } from "./merge.js";
15
- import { DEFAULT_CACHE_CONFIG } from "./types.js";
15
+ import { DEFAULT_CACHE_CONFIG, DEFAULT_CHECKPOINTS_CONFIG } from "./types.js";
16
16
  /** 代码里生效、但 DEFAULT_CONFIG 不写的缺省(写进去会改变合并结果或 `config.codemode` 的有无)。 */
17
17
  const IMPLICIT_DEFAULTS = {
18
18
  providers: {},
@@ -21,7 +21,17 @@ const IMPLICIT_DEFAULTS = {
21
21
  codemode: { inlineBudget: DEFAULT_INLINE_BUDGET, requireStrict: false },
22
22
  cache: { ...DEFAULT_CACHE_CONFIG },
23
23
  request: { idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS },
24
- ui: { compact: false, animation: true },
24
+ ui: { compact: false, animation: true, restoreOnCancel: true },
25
+ checkpoints: { ...DEFAULT_CHECKPOINTS_CONFIG },
26
+ sandbox: { enabled: "auto", bash: "off", network: "deny", writable: [] },
27
+ // [W5-C0] 第五波键的缺省(行为由各批次实现)
28
+ compaction: { prune: { keepResults: 5, clearAtLeast: "auto" }, pruneExclude: [] },
29
+ images: { resize: "auto" },
30
+ plan: { bash: "readonly", unattended: "stop" },
31
+ agents: { maxConcurrent: 3, dirs: [] },
32
+ subagents: { maxConcurrent: 4, maxPending: 16 },
33
+ reminders: { todo: true, fileChanges: true, contextPressure: true, budget: true },
34
+ todo: { reminder: 10 },
25
35
  };
26
36
  /** 全部有固定缺省值的键(展示用;运行时仍以 DEFAULT_CONFIG 合并)。 */
27
37
  export const DISPLAY_DEFAULTS = Object.freeze(mergeConfig(DEFAULT_CONFIG, IMPLICIT_DEFAULTS));
@@ -32,6 +42,18 @@ export const DYNAMIC_DEFAULTS = Object.freeze({
32
42
  "permission.autoModel": "当前会话模型",
33
43
  "codemode.mode": "跟随预设",
34
44
  "ui.ascii": "自动检测",
45
+ // [W5-C0]
46
+ "ui.statusLine": "独立终端 full,嵌入宿主(有 profile)compact",
47
+ "plan.directory": "<数据目录>/plans",
48
+ "plan.model": "不设:沿用当前模型",
49
+ "plan.thinkingLevel": "不设:沿用当前思考强度",
50
+ "agents.sessionBudgetUsd": "不设:不限",
51
+ "subagents.defaultModel": "不设:继承父会话模型",
52
+ "models.aliases.fast": "不设:fast 按 inherit 处理",
53
+ "models.aliases.strong": "不设:strong 按 inherit 处理",
54
+ fallbackModel: "不设:不回退",
55
+ "limits.maxTurns": "不设:不限",
56
+ "limits.maxCostUsd": "不设:不限",
35
57
  });
36
58
  /** 键路径 → 说明(段落本身也有一条)。 */
37
59
  export const CONFIG_KEY_DOCS = Object.freeze({
@@ -51,13 +73,17 @@ export const CONFIG_KEY_DOCS = Object.freeze({
51
73
  "compaction.enabled": "上下文接近上限时自动压缩",
52
74
  "compaction.reserveTokens": "为回复预留的 token;剩余不足时触发压缩",
53
75
  "compaction.keepRecentTokens": "压缩时原样保留的最近消息 token",
76
+ "compaction.prune": "档一裁剪(旧工具结果换成占位);只认用户级(第五波 W5-H1 起生效)",
77
+ "compaction.prune.keepResults": "保留最近 N 个工具结果不裁",
78
+ "compaction.prune.clearAtLeast": "一次至少能省这么多 token 才裁(避免频繁打断缓存);auto = max(20000, 0.1 × 上下文预算)",
79
+ "compaction.pruneExclude": "不被档一裁剪的工具名;只认用户级(第五波 W5-H1 起生效)",
54
80
  retry: "请求失败重试",
55
81
  "retry.enabled": "可重试的错误(限流、服务端错误、连接中断等)自动重试",
56
82
  "retry.maxRetries": "最多重试次数",
57
83
  "retry.baseDelayMs": "首次重试等待(毫秒,指数退避;有 Retry-After 时按它)",
58
84
  "retry.maxDelayMs": "单次等待上限(毫秒)",
59
85
  tools: "内置工具",
60
- "tools.preset": "工具预设:default(六个工具,Node ≥ 25 时另加 codemode)、minimal、codemode-only、coordinator;codemode 是 codemode-only 的旧名;项目级只能更严",
86
+ "tools.preset": "工具预设:default(六个工具;网络隔离时另加 codemode,todo 需在 tools.default 加 +todo)、minimal、codemode-only、coordinator;codemode 是 codemode-only 的旧名;项目级只能更严",
61
87
  "tools.default": "在预设上微调:+name 加、-name 去,不带前缀的名字整组替换预设的内置工具;只认用户级",
62
88
  "tools.maxToolResultChars": "单条工具结果进上下文的字符上限,超出保留首尾",
63
89
  "tools.bashTimeoutMs": "bash 缺省超时(毫秒,单次调用可覆盖,最大 600000)",
@@ -77,6 +103,8 @@ export const CONFIG_KEY_DOCS = Object.freeze({
77
103
  "ui.ascii": "ASCII 字形(> * L、+ - |);不写时自动检测:区域设置不含 UTF-8、TERM=linux、旧 conhost 时开启;AMA_ASCII=1/0 覆盖",
78
104
  "ui.compact": "消息区块间不空行、启动头不画框",
79
105
  "ui.animation": "false:运行中 spinner 静止,只在秒数变化时重绘",
106
+ "ui.restoreOnCancel": "运行中 Esc 中断、本回合还没有任何回复或工具调用时,撤回该回合并把原消息放回输入框",
107
+ "ui.statusLine": "底部信息行:full 两行(速率行 + 状态行),compact 一行;运行时 Ctrl+G 或 /statusline 切换(第五波 W5-A 起生效)",
80
108
  skills: "Skill",
81
109
  "skills.dirs": "追加的 Skill 目录;各层累加",
82
110
  cache: "提示缓存;整段只认用户级",
@@ -87,6 +115,47 @@ export const CONFIG_KEY_DOCS = Object.freeze({
87
115
  "cache.minSavingsUsd": "保温的最低期望节省(美元)",
88
116
  "cache.missNotices": "在消息区提示缓存未命中与上下文余量",
89
117
  "cache.warmSubagents": "子会话(task)也保温",
118
+ checkpoints: "检查点:回滚代码用的文件备份(docs/sessions.md「检查点与文件备份」)",
119
+ "checkpoints.mode": "tools:跟踪 edit / write 改过的文件;shadow-git:另用影子 git 快照整个工作目录,bash 等直接改动也能回滚(需要 git,大目录自动降级为 tools);off:关闭;AMA_CHECKPOINTS 覆盖;项目级只接受 off",
120
+ "checkpoints.maxFileBytes": "单个文件的备份上限(字节),超出不备份、回滚时报告无法恢复;项目级只能调小",
121
+ "checkpoints.keep": "可回滚的最近检查点数,更早的不再列为回滚点;只认用户级 / profile",
122
+ sandbox: '操作系统级沙箱(docs/sandbox.md);只认用户级 / profile,项目级只接受 network: "deny"',
123
+ "sandbox.enabled": "auto:探测到可用的 macOS sandbox-exec / Linux bwrap、unshare 就用(codemode 子进程拒绝网络与写入;Node 22 / 24 上 codemode 因此网络隔离);off:不用;AMA_SANDBOX=off 覆盖",
124
+ "sandbox.bash": "auto:bash 经 sandbox-exec / bwrap 运行(unshare 不算),写入只限工作区、临时目录、输出目录与 sandbox.writable,default 模式下沙箱内命令免审批;off:不用;只认用户级 / profile",
125
+ "sandbox.network": "bash 沙箱里的网络:deny 拒绝(沙箱内免审批的前提);allow 允许联网但写入仍受限、照常审批;项目级只能设 deny",
126
+ "sandbox.writable": "bash 沙箱追加的可写目录(绝对路径或 ~/…);只认用户级 / profile",
127
+ // [W5-C0] 第五波(docs/wave5-plan.md);括号里是起生效的批次
128
+ images: "图像输入;只认用户级(第五波 W5-I 起生效)",
129
+ "images.resize": "auto:图片超过端点上限时用系统工具(sips / magick)缩放,找不到工具按原规则拒绝;off:从不缩放",
130
+ plan: "Plan 模式(第五波 W5-F 起生效)",
131
+ "plan.bash": "plan 模式下的 bash:readonly 只读命令放行其余拒绝,ask 其余询问,deny 全拒;项目级只能更严",
132
+ "plan.directory": "计划文件目录(必须在项目根之内,否则回落缺省);只认用户级",
133
+ "plan.unattended": "无人值守(-p、RPC 未声明 plans 能力)时:stop 落盘计划后停下等人审批,approve 自动批准执行;只认用户级",
134
+ "plan.model": "规划用模型 provider/model[@channel]:进入 plan 时切换、批准时切回;只认用户级",
135
+ "plan.thinkingLevel": "规划时的思考强度;只认用户级",
136
+ agents: "外部 Agent(claude / codex / ACP)与子 Agent 类型;agents.<id> 设单个 Agent 的 maxConcurrent / maxMode / model / env.passthrough;只认用户级(第五波 W5-E / W5-G 起生效)",
137
+ "agents.maxConcurrent": "外部 Agent 的总并发",
138
+ "agents.sessionBudgetUsd": "本会话外部 Agent 的美元预算",
139
+ "agents.dirs": "追加的子 Agent 定义目录(*.md);各层累加",
140
+ subagents: "ama 自己的 task 子会话;只认用户级(第五波 W5-G 起生效)",
141
+ "subagents.maxConcurrent": "同时运行的子会话数",
142
+ "subagents.maxPending": "排队上限,超出时 task 报错",
143
+ "subagents.defaultModel": "子会话缺省模型 provider/model[@channel]",
144
+ models: "模型别名;只认用户级(第五波 W5-G 起生效)",
145
+ "models.aliases": "子 Agent 定义里 model: fast / strong 指向的模型",
146
+ "models.aliases.fast": "fast 别名的模型 provider/model[@channel]",
147
+ "models.aliases.strong": "strong 别名的模型 provider/model[@channel]",
148
+ fallbackModel: "回退模型 provider/model[@channel]:可重试错误用尽或过载时切换重试一次,下一回合回主模型;只认用户级(第五波 W5-H2 起生效)",
149
+ limits: "会话预算,到限结束本次运行(-p 退出码 8);--max-turns / --max-cost 覆盖;只认用户级(第五波 W5-H2 起生效)",
150
+ "limits.maxTurns": "一次运行最多回合数",
151
+ "limits.maxCostUsd": "一次运行的美元上限",
152
+ reminders: "附在对话尾部的提醒(不改缓存前缀);项目级可设(第五波 W5-H2 起生效)",
153
+ "reminders.todo": "todo 有未完成项且多回合未更新时复述",
154
+ "reminders.fileChanges": "读过的文件被外部改动时列出",
155
+ "reminders.contextPressure": "上下文用量到 70% / 85% 时各提醒一次",
156
+ "reminders.budget": "预算剩余不足 20% 时提醒",
157
+ todo: "todo 工具;只认用户级(第五波 W5-F / W5-H2 起生效)",
158
+ "todo.reminder": "连续 N 回合未更新且有未完成项时提醒复述;0 关闭",
90
159
  });
91
160
  /** 叶子路径(段落不算)。 */
92
161
  export function documentedLeaves() {
@@ -6,11 +6,13 @@
6
6
  * `tools.disabled`、`skills.dirs` 跨层拼接去重。
7
7
  * - 项目级 `.ama/config.json` 只接受:`permission.deny`(追加)、`permission.mode`(只能更严,且不能是
8
8
  * auto / full-auto)、
9
- * `compaction`、`tools.disabled`、`tools.preset`(只能更严)、`codemode.mode: "off"`、`ui`;
9
+ * `compaction`、`tools.disabled`、`tools.preset`(只能更严)、`codemode.mode: "off"`、`ui`、
10
+ * `checkpoints.mode: "off"`、`checkpoints.maxFileBytes`(只能调小)、(W5-C0)`plan.bash`(只能更严)、
11
+ * `reminders`;`compaction.prune / pruneExclude` 与第五波其余段只认用户级;
10
12
  * 其它字段与放宽项(含 `permission.builtinDeny / autoModel / autoSafeCommands`)被忽略并记 warning。
11
13
  * - 同时产出带来源的权限规则清单(`ruleSpecs`),交给权限管线(B3 的 rules.ts 解析)。
12
14
  */
13
- import type { AmaConfig, CodemodeMode, ToolsPresetInput } from "./types.js";
15
+ import type { AmaConfig, CodemodeMode, PlanBashMode, ToolsPresetInput } from "./types.js";
14
16
  import type { PermissionMode, RuleSource } from "../permissions/types.js";
15
17
  import type { ModelThinkingLevel } from "../ai/types.js";
16
18
  export declare const DEFAULT_CONFIG: Readonly<AmaConfig>;
@@ -35,7 +37,7 @@ export declare function isPresetStricterOrEqual(a: ToolsPresetInput, b: ToolsPre
35
37
  * 把项目级配置裁剪为受限字段(§7.2);`currentMode` / `currentPreset` 是合并到此为止的
36
38
  * 权限模式与工具预设。
37
39
  */
38
- export declare function restrictProjectConfig(project: AmaConfig, currentMode: PermissionMode, label?: string, currentPreset?: ToolsPresetInput): RestrictResult;
40
+ export declare function restrictProjectConfig(project: AmaConfig, currentMode: PermissionMode, label?: string, currentPreset?: ToolsPresetInput, currentMaxFileBytes?: number, currentPlanBash?: PlanBashMode): RestrictResult;
39
41
  /** 命令行对配置的覆盖(只含与 config 同名的那部分参数)。 */
40
42
  export interface CliConfigOverrides {
41
43
  thinkingLevel?: ModelThinkingLevel | undefined;
@@ -6,11 +6,13 @@
6
6
  * `tools.disabled`、`skills.dirs` 跨层拼接去重。
7
7
  * - 项目级 `.ama/config.json` 只接受:`permission.deny`(追加)、`permission.mode`(只能更严,且不能是
8
8
  * auto / full-auto)、
9
- * `compaction`、`tools.disabled`、`tools.preset`(只能更严)、`codemode.mode: "off"`、`ui`;
9
+ * `compaction`、`tools.disabled`、`tools.preset`(只能更严)、`codemode.mode: "off"`、`ui`、
10
+ * `checkpoints.mode: "off"`、`checkpoints.maxFileBytes`(只能调小)、(W5-C0)`plan.bash`(只能更严)、
11
+ * `reminders`;`compaction.prune / pruneExclude` 与第五波其余段只认用户级;
10
12
  * 其它字段与放宽项(含 `permission.builtinDeny / autoModel / autoSafeCommands`)被忽略并记 warning。
11
13
  * - 同时产出带来源的权限规则清单(`ruleSpecs`),交给权限管线(B3 的 rules.ts 解析)。
12
14
  */
13
- import { CONFIG_FILE_VERSION, TOOLS_PRESETS_STRICT_FIRST, canonicalPreset } from "./types.js";
15
+ import { CONFIG_FILE_VERSION, DEFAULT_CHECKPOINTS_CONFIG, PLAN_BASH_MODES_STRICT_FIRST, TOOLS_PRESETS_STRICT_FIRST, canonicalPreset, } from "./types.js";
14
16
  import { isAtLeastAsStrict } from "../permissions/rules.js";
15
17
  export const DEFAULT_CONFIG = Object.freeze({
16
18
  version: CONFIG_FILE_VERSION,
@@ -31,7 +33,8 @@ export const DEFAULT_CONFIG = Object.freeze({
31
33
  });
32
34
  /** 嵌入宿主(有 profile)时的缺省覆盖(§12.10)。 */
33
35
  export const PROFILE_DEFAULTS = Object.freeze({
34
- ui: { quietStartup: "header" },
36
+ // [W5-A] 嵌入宿主以「最后一行 = 状态栏」锚定,底部信息行缺省单行
37
+ ui: { quietStartup: "header", statusLine: "compact" },
35
38
  });
36
39
  /** 层名 → 规则来源(RuleSource)。 */
37
40
  const RULE_SOURCE = {
@@ -47,6 +50,7 @@ const ACCUMULATING = new Set([
47
50
  "permission.autoSafeCommands",
48
51
  "tools.disabled",
49
52
  "skills.dirs",
53
+ "agents.dirs",
50
54
  ]);
51
55
  function isPlainObject(value) {
52
56
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -94,7 +98,7 @@ export function isPresetStricterOrEqual(a, b) {
94
98
  * 把项目级配置裁剪为受限字段(§7.2);`currentMode` / `currentPreset` 是合并到此为止的
95
99
  * 权限模式与工具预设。
96
100
  */
97
- export function restrictProjectConfig(project, currentMode, label = ".ama/config.json", currentPreset = "default") {
101
+ export function restrictProjectConfig(project, currentMode, label = ".ama/config.json", currentPreset = "default", currentMaxFileBytes = DEFAULT_CHECKPOINTS_CONFIG.maxFileBytes, currentPlanBash = "readonly") {
98
102
  const warnings = [];
99
103
  const accepted = {};
100
104
  for (const [key, value] of Object.entries(project)) {
@@ -102,9 +106,24 @@ export function restrictProjectConfig(project, currentMode, label = ".ama/config
102
106
  continue;
103
107
  switch (key) {
104
108
  case "compaction":
105
- if (project.compaction !== undefined)
106
- accepted.compaction = structuredClone(project.compaction);
109
+ if (project.compaction !== undefined) {
110
+ const { prune, pruneExclude, ...rest } = structuredClone(project.compaction);
111
+ if (prune !== undefined || pruneExclude !== undefined)
112
+ warnings.push(`${label}: 项目级不能设 compaction.prune / pruneExclude,已忽略`);
113
+ if (Object.keys(rest).length > 0)
114
+ accepted.compaction = rest;
115
+ }
116
+ break;
117
+ case "reminders":
118
+ if (project.reminders !== undefined)
119
+ accepted.reminders = structuredClone(project.reminders);
120
+ break;
121
+ case "plan": {
122
+ const plan = restrictPlan(project.plan ?? {}, currentPlanBash, label, warnings);
123
+ if (plan !== undefined)
124
+ accepted.plan = plan;
107
125
  break;
126
+ }
108
127
  case "ui":
109
128
  if (project.ui !== undefined)
110
129
  accepted.ui = structuredClone(project.ui);
@@ -139,18 +158,73 @@ export function restrictProjectConfig(project, currentMode, label = ".ama/config
139
158
  accepted.codemode = { mode: "off" };
140
159
  break;
141
160
  }
161
+ case "checkpoints": {
162
+ const checkpoints = restrictCheckpoints(project.checkpoints ?? {}, currentMaxFileBytes, label, warnings);
163
+ if (checkpoints !== undefined)
164
+ accepted.checkpoints = checkpoints;
165
+ break;
166
+ }
142
167
  case "permission": {
143
168
  const permission = restrictPermission(project.permission ?? {}, currentMode, label, warnings);
144
169
  if (permission !== undefined)
145
170
  accepted.permission = permission;
146
171
  break;
147
172
  }
173
+ case "sandbox": {
174
+ // [S2] 只能收紧:network "deny"。enabled / bash 两个方向都不是单纯更严(打开 bash 沙箱会让 default
175
+ // 模式免审批,关闭会让命令裸跑),writable 是放宽,一律忽略。
176
+ const sandbox = project.sandbox ?? {};
177
+ for (const [sub, v] of Object.entries(sandbox)) {
178
+ if (sub === "network" && v === "deny")
179
+ continue;
180
+ warnings.push(`${label}: 项目级只接受 sandbox.network "deny",忽略 sandbox.${sub}${sub === "network" ? ` ${String(v)}` : ""}`);
181
+ }
182
+ if (sandbox.network === "deny")
183
+ accepted.sandbox = { network: "deny" };
184
+ break;
185
+ }
148
186
  default:
149
187
  warnings.push(`${label}: 项目级不能设 ${key},已忽略`);
150
188
  }
151
189
  }
152
190
  return { accepted, warnings };
153
191
  }
192
+ /** [W5-C0] 项目级 plan:只接受 `bash`,且只能更严(deny < readonly < ask)。 */
193
+ function restrictPlan(plan, current, label, warnings) {
194
+ for (const sub of Object.keys(plan)) {
195
+ if (sub !== "bash")
196
+ warnings.push(`${label}: 项目级只能设 plan.bash,忽略 plan.${sub}`);
197
+ }
198
+ if (plan.bash === undefined)
199
+ return undefined;
200
+ const order = PLAN_BASH_MODES_STRICT_FIRST;
201
+ if (order.indexOf(plan.bash) <= order.indexOf(current))
202
+ return { bash: plan.bash };
203
+ warnings.push(`${label}: 项目级只能收紧 plan.bash,忽略 ${plan.bash}(当前 ${current})`);
204
+ return undefined;
205
+ }
206
+ /** 项目级检查点:只能关闭、只能调小单文件上限(多备份即多占用户磁盘);`keep` 只认用户级。 */
207
+ function restrictCheckpoints(checkpoints, currentMaxFileBytes, label, warnings) {
208
+ const result = {};
209
+ for (const [sub, v] of Object.entries(checkpoints)) {
210
+ if (sub === "mode") {
211
+ if (v === "off")
212
+ result.mode = "off";
213
+ else
214
+ warnings.push(`${label}: 项目级只接受 checkpoints.mode "off",忽略 ${String(v)}`);
215
+ }
216
+ else if (sub === "maxFileBytes" && typeof v === "number") {
217
+ if (v <= currentMaxFileBytes)
218
+ result.maxFileBytes = v;
219
+ else
220
+ warnings.push(`${label}: 项目级只能调小 checkpoints.maxFileBytes,忽略 ${v}(当前 ${currentMaxFileBytes})`);
221
+ }
222
+ else {
223
+ warnings.push(`${label}: 项目级不能设 checkpoints.${sub},已忽略`);
224
+ }
225
+ }
226
+ return Object.keys(result).length > 0 ? result : undefined;
227
+ }
154
228
  function restrictPermission(permission, currentMode, label, warnings) {
155
229
  const result = {};
156
230
  if (permission.allow !== undefined && permission.allow.length > 0) {
@@ -242,7 +316,7 @@ export function mergeProjectAndCli(base, project, cli, projectLabel) {
242
316
  const present = [...base.layers];
243
317
  if (project !== undefined) {
244
318
  const baseline = config.permission?.mode ?? "default";
245
- const restricted = restrictProjectConfig(project, baseline, projectLabel, config.tools?.preset ?? "default");
319
+ const restricted = restrictProjectConfig(project, baseline, projectLabel, config.tools?.preset ?? "default", config.checkpoints?.maxFileBytes ?? DEFAULT_CHECKPOINTS_CONFIG.maxFileBytes, config.plan?.bash ?? "readonly");
246
320
  warnings.push(...restricted.warnings);
247
321
  config = mergeConfig(config, restricted.accepted);
248
322
  present.push("project");
@@ -12,6 +12,8 @@ export interface ProfileOptions {
12
12
  instructions: string[];
13
13
  skillDirs: string[];
14
14
  promptDirs: string[];
15
+ /** [W5-C0] 子 Agent 定义目录(W5-G 接入发现)。 */
16
+ agentDirs?: string[];
15
17
  hooksFile?: string;
16
18
  authFile?: string;
17
19
  /** false:key 只来自 authFile。 */
@@ -51,6 +51,8 @@ function profileToOptions(path, profile, warnings) {
51
51
  trustProject: profile.trustProject === true,
52
52
  warnings: [...warnings],
53
53
  };
54
+ if (profile.agentDirs !== undefined)
55
+ options.agentDirs = [...profile.agentDirs];
54
56
  if (profile.host !== undefined)
55
57
  options.host = profile.host;
56
58
  if (profile.hooksFile !== undefined)
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 第五波配置键的校验(docs/wave5-plan.md §9;schema.ts 已近 600 行,新键放这里)。[W5-C0]
3
+ *
4
+ * 规则与 json-schema.ts 一一对应(json-schema.test.ts 的正反例守住):类型 / 取值错误是 error,
5
+ * 未知字段是 warning。只校验形状;行为由各批次实现。
6
+ */
7
+ import { Checker, type Obj } from "./checker.js";
8
+ /** 第五波新增的顶层键(schema.ts 的 CONFIG_KEYS 并入)。 */
9
+ export declare const W5_CONFIG_KEYS: readonly ["images", "plan", "agents", "subagents", "models", "fallbackModel", "limits", "reminders", "todo"];
10
+ /** 已有段新增的键。 */
11
+ export declare const W5_UI_KEYS: readonly ["statusLine"];
12
+ export declare const W5_COMPACTION_KEYS: readonly ["prune", "pruneExclude"];
13
+ /** `agents.<id>` 的 id:子 Agent 名(`^[a-z0-9-]`)或外部 Agent(可带 `acp:` 前缀)。 */
14
+ export declare const AGENT_ID_PATTERN: RegExp;
15
+ export declare function checkUiW5(c: Checker, ui: Obj, path: string): void;
16
+ export declare function checkCompactionW5(c: Checker, compaction: Obj, path: string): void;
17
+ /** 第五波顶层段的校验(validateConfig 末尾调用)。 */
18
+ export declare function validateConfigW5(c: Checker, config: Obj): void;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * 第五波配置键的校验(docs/wave5-plan.md §9;schema.ts 已近 600 行,新键放这里)。[W5-C0]
3
+ *
4
+ * 规则与 json-schema.ts 一一对应(json-schema.test.ts 的正反例守住):类型 / 取值错误是 error,
5
+ * 未知字段是 warning。只校验形状;行为由各批次实现。
6
+ */
7
+ import { PERMISSION_MODES_STRICT_FIRST } from "../permissions/types.js";
8
+ import { Checker, THINKING_LEVELS, checkSection, join } from "./checker.js";
9
+ import { AGENTS_RESERVED_KEYS, IMAGE_RESIZE_MODES, PLAN_BASH_MODES_STRICT_FIRST, PLAN_UNATTENDED_MODES, STATUS_LINE_MODES, } from "./types-w5.js";
10
+ /** 第五波新增的顶层键(schema.ts 的 CONFIG_KEYS 并入)。 */
11
+ export const W5_CONFIG_KEYS = [
12
+ "images",
13
+ "plan",
14
+ "agents",
15
+ "subagents",
16
+ "models",
17
+ "fallbackModel",
18
+ "limits",
19
+ "reminders",
20
+ "todo",
21
+ ];
22
+ /** 已有段新增的键。 */
23
+ export const W5_UI_KEYS = ["statusLine"];
24
+ export const W5_COMPACTION_KEYS = ["prune", "pruneExclude"];
25
+ /** `agents.<id>` 的 id:子 Agent 名(`^[a-z0-9-]`)或外部 Agent(可带 `acp:` 前缀)。 */
26
+ export const AGENT_ID_PATTERN = /^(acp:)?[a-z0-9][a-z0-9._-]{0,63}$/;
27
+ const AGENT_ENTRY_KEYS = ["maxConcurrent", "maxMode", "model", "env"];
28
+ export function checkUiW5(c, ui, path) {
29
+ c.oneOf(ui, "statusLine", path, STATUS_LINE_MODES);
30
+ }
31
+ export function checkCompactionW5(c, compaction, path) {
32
+ c.stringArray(compaction, "pruneExclude", path);
33
+ const prune = compaction["prune"];
34
+ const p = join(path, "prune");
35
+ if (prune === undefined || !c.object(prune, p))
36
+ return;
37
+ c.keys(prune, p, ["keepResults", "clearAtLeast"]);
38
+ c.number(prune, "keepResults", p, 0);
39
+ const clear = prune["clearAtLeast"];
40
+ if (clear !== undefined && clear !== "auto" && (typeof clear !== "number" || clear < 0))
41
+ c.error(join(p, "clearAtLeast"), '应为 "auto" 或非负数字');
42
+ }
43
+ function checkAgentEntry(c, entry, path) {
44
+ if (!c.object(entry, path))
45
+ return;
46
+ c.keys(entry, path, AGENT_ENTRY_KEYS);
47
+ c.number(entry, "maxConcurrent", path, 1, 64);
48
+ c.oneOf(entry, "maxMode", path, PERMISSION_MODES_STRICT_FIRST);
49
+ c.string(entry, "model", path);
50
+ const env = entry["env"];
51
+ const envPath = join(path, "env");
52
+ if (env !== undefined && c.object(env, envPath)) {
53
+ c.keys(env, envPath, ["passthrough"]);
54
+ c.stringArray(env, "passthrough", envPath);
55
+ }
56
+ }
57
+ function checkAgents(c, config) {
58
+ const agents = config["agents"];
59
+ if (agents === undefined || !c.object(agents, "agents"))
60
+ return;
61
+ c.number(agents, "maxConcurrent", "agents", 1, 64);
62
+ c.number(agents, "sessionBudgetUsd", "agents", 0);
63
+ c.stringArray(agents, "dirs", "agents");
64
+ for (const [id, entry] of Object.entries(agents)) {
65
+ if (AGENTS_RESERVED_KEYS.includes(id))
66
+ continue;
67
+ const p = join("agents", id);
68
+ if (!AGENT_ID_PATTERN.test(id))
69
+ c.error(p, "Agent id 只能是小写字母、数字、- . _(可带 acp: 前缀)");
70
+ else
71
+ checkAgentEntry(c, entry, p);
72
+ }
73
+ }
74
+ /** 第五波顶层段的校验(validateConfig 末尾调用)。 */
75
+ export function validateConfigW5(c, config) {
76
+ checkSection(c, config, "images", ["resize"], (s, p) => c.oneOf(s, "resize", p, IMAGE_RESIZE_MODES));
77
+ checkSection(c, config, "plan", ["bash", "directory", "unattended", "model", "thinkingLevel"], (s, p) => {
78
+ c.oneOf(s, "bash", p, PLAN_BASH_MODES_STRICT_FIRST);
79
+ c.string(s, "directory", p);
80
+ c.oneOf(s, "unattended", p, PLAN_UNATTENDED_MODES);
81
+ c.string(s, "model", p);
82
+ c.oneOf(s, "thinkingLevel", p, THINKING_LEVELS);
83
+ });
84
+ checkAgents(c, config);
85
+ checkSection(c, config, "subagents", ["maxConcurrent", "maxPending", "defaultModel"], (s, p) => {
86
+ c.number(s, "maxConcurrent", p, 1, 64);
87
+ c.number(s, "maxPending", p, 0, 1024);
88
+ c.string(s, "defaultModel", p);
89
+ });
90
+ checkSection(c, config, "models", ["aliases"], (s, p) => {
91
+ const aliases = s["aliases"];
92
+ const ap = join(p, "aliases");
93
+ if (aliases === undefined || !c.object(aliases, ap))
94
+ return;
95
+ c.keys(aliases, ap, ["fast", "strong"]);
96
+ c.string(aliases, "fast", ap);
97
+ c.string(aliases, "strong", ap);
98
+ });
99
+ c.string(config, "fallbackModel", "");
100
+ checkSection(c, config, "limits", ["maxTurns", "maxCostUsd"], (s, p) => {
101
+ c.number(s, "maxTurns", p, 1);
102
+ c.number(s, "maxCostUsd", p, 0);
103
+ });
104
+ checkSection(c, config, "reminders", ["todo", "fileChanges", "contextPressure", "budget"], (s, p) => {
105
+ for (const key of ["todo", "fileChanges", "contextPressure", "budget"])
106
+ c.boolean(s, key, p);
107
+ });
108
+ checkSection(c, config, "todo", ["reminder"], (s, p) => c.number(s, "reminder", p, 0));
109
+ }