@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
@@ -1,15 +1,19 @@
1
1
  /**
2
- * `task` 工具:同进程子 Agent(设计 §5.2、D14)。[B3]
2
+ * `task` 工具:子 Agent 的统一入口(设计 §5.2、D14;第五波 docs/wave5-plan.md §7.3,D13、D23)。
3
+ * [B3 → W5-G]
3
4
  *
4
- * 子会话由 `ctx.spawnSubagent`(B2 的 AgentSession 提供)创建:独立 JSONL、继承权限模式与 broker、
5
- * 审批串到父。本工具负责:
6
- * - 深度 ≤ 1:`ctx.depth ≥ 1` 或无 `spawnSubagent` → 错误(子 Agent 里没有 task);
7
- * - 并发 ≤ 4:由会话的 `SubagentPool`(agent/session-subagent.ts,`subagents.maxConcurrent`)排队,
8
- * 本工具不再自带一层信号量;排队中父 abort → 子会话抛 aborted,这里返回 aborted;
9
- * - 工具子集:`tools` 里去掉 `task`(缺省交给 spawnSubagent = 父活动集去掉 task);
10
- * - 父 abort 级联:把 `ctx.signal` 传给子;
11
- * - 结果 = 子的最后助手文本 + `details{ sessionFile, usage, stopReason }`。
5
+ * - `agent`:子 Agent 类型(内置 general / explore / plan、`.ama/agents/*.md`)或外部 Agent;缺省
6
+ * general。描述里列出可用类型(catalog 由 compose-agents.ts 经 `bindTaskAgents` 绑定;没绑定时
7
+ * 只列内置类型)。
8
+ * - `background`:立即返回 taskId,完成后父会话收到 `<task-notification>`;`taskId`:向已有子会话
9
+ * 追加消息(续聊,忽略 agent / tools / model);`isolation: "worktree"`:在独立 git worktree 里跑。
10
+ * - **parallel**:同一回复里的多个 task 真并行(会话注册表的池限流,缺省 4);与 sequential 工具
11
+ * (edit 等)同批时仍按 tool-runner 的规则整批串行。
12
+ * - 深度 ≤ 1:子会话的工具表里保留 task(与父字节一致,缓存前缀可复用),运行时在这里拒绝。
13
+ * - 结果 = 子 Agent 的最终报告(> 50 KB 截头尾、全文落 outputs/,见 agents/result.ts)+ details。
12
14
  */
15
+ import { AgentCatalog } from "../agents/catalog.js";
16
+ import { TASK_NOTIFICATION_RULE } from "../agents/result.js";
13
17
  export const MAX_TASK_DEPTH = 1;
14
18
  export const DEFAULT_TASK_MAX_TURNS = 30;
15
19
  const THINKING = [
@@ -20,6 +24,17 @@ const THINKING = [
20
24
  "high",
21
25
  "xhigh",
22
26
  ];
27
+ const BASE_DESCRIPTION = "Delegate to a sub-agent (fresh context; give full instructions). Returns its final report. " +
28
+ "Tasks in one reply run in parallel; writers should use isolation worktree. background: " +
29
+ "returns a taskId now (see task_ctl); taskId: continue that task.";
30
+ /** 描述里类型清单的标题(清单本身另有 400 token 预算,见 agents/catalog.ts)。 */
31
+ export const TASK_AGENTS_HEADING = "\nAgents:\n";
32
+ const catalogs = new WeakMap();
33
+ /** 组装根把会话的类型目录绑到 task 工具上(描述里的类型清单)。 */
34
+ export function bindTaskAgents(tool, catalog) {
35
+ if (tool !== undefined)
36
+ catalogs.set(tool, catalog);
37
+ }
23
38
  function fail(message) {
24
39
  return { content: message, isError: true };
25
40
  }
@@ -27,21 +42,37 @@ export function buildSubagentRequest(input, ctx) {
27
42
  if (typeof input.prompt !== "string" || input.prompt.trim() === "") {
28
43
  return "prompt must be a non-empty string";
29
44
  }
30
- const maxTurns = input.maxTurns ?? DEFAULT_TASK_MAX_TURNS;
31
- if (!Number.isInteger(maxTurns) || maxTurns < 1)
45
+ if (input.maxTurns !== undefined && (!Number.isInteger(input.maxTurns) || input.maxTurns < 1))
32
46
  return "maxTurns must be an integer ≥ 1";
33
47
  if (input.thinkingLevel !== undefined && !THINKING.includes(input.thinkingLevel)) {
34
48
  return `thinkingLevel must be one of ${THINKING.join(", ")}`;
35
49
  }
50
+ if (input.isolation !== undefined && input.isolation !== "none" && input.isolation !== "worktree")
51
+ return 'isolation must be "none" or "worktree"';
52
+ if (input.budgetUsd !== undefined && !(input.budgetUsd > 0))
53
+ return "budgetUsd must be > 0";
36
54
  const request = {
37
55
  prompt: input.prompt,
38
- maxTurns,
39
56
  parentToolCallId: ctx.toolCallId,
40
57
  signal: ctx.signal,
41
58
  onUpdate: (partial) => ctx.onUpdate(partial),
42
59
  };
60
+ if (input.maxTurns !== undefined)
61
+ request.maxTurns = input.maxTurns;
43
62
  if (input.description !== undefined)
44
63
  request.description = input.description;
64
+ if (input.background !== undefined)
65
+ request.background = input.background;
66
+ if (input.taskId !== undefined) {
67
+ request.taskId = input.taskId;
68
+ return request;
69
+ }
70
+ if (input.agent !== undefined)
71
+ request.agent = input.agent;
72
+ if (input.isolation !== undefined)
73
+ request.isolation = input.isolation;
74
+ if (input.budgetUsd !== undefined)
75
+ request.budgetUsd = input.budgetUsd;
45
76
  if (input.tools !== undefined)
46
77
  request.tools = input.tools.filter((t) => t !== "task");
47
78
  if (input.model !== undefined)
@@ -51,31 +82,35 @@ export function buildSubagentRequest(input, ctx) {
51
82
  return request;
52
83
  }
53
84
  export function createTaskTool(_options = {}) {
54
- return {
85
+ const tool = {
55
86
  name: "task",
56
87
  label: "Task",
57
- description: "Delegate to a fresh sub-agent. It cannot see this chat: give full instructions. " +
58
- "Returns its final answer.",
88
+ get description() {
89
+ const catalog = catalogs.get(tool) ?? new AgentCatalog();
90
+ return `${BASE_DESCRIPTION}${TASK_AGENTS_HEADING}${catalog.describe()}`;
91
+ },
59
92
  parameters: {
60
93
  type: "object",
61
94
  properties: {
62
95
  prompt: { type: "string" },
63
- description: { type: "string", description: "Label" },
64
- tools: {
65
- type: "array",
66
- items: { type: "string" },
67
- description: "Default: all but task",
68
- },
69
- model: { type: "string", description: "provider/model" },
96
+ agent: { type: "string", description: "Default general" },
97
+ description: { type: "string" },
98
+ background: { type: "boolean" },
99
+ taskId: { type: "string" },
100
+ isolation: { type: "string", enum: ["none", "worktree"] },
101
+ budgetUsd: { type: "number" },
102
+ tools: { type: "array", items: { type: "string" } },
103
+ model: { type: "string" },
70
104
  thinkingLevel: { type: "string", enum: [...THINKING] },
71
- maxTurns: { type: "integer", description: `Default ${DEFAULT_TASK_MAX_TURNS}` },
105
+ maxTurns: { type: "integer" },
72
106
  },
73
107
  required: ["prompt"],
74
108
  additionalProperties: false,
75
109
  },
76
110
  permission: "execute",
77
- executionMode: "sequential",
111
+ executionMode: "parallel",
78
112
  promptSnippet: "task: run a sub-agent",
113
+ promptGuidelines: [TASK_NOTIFICATION_RULE],
79
114
  async execute(input, ctx) {
80
115
  if (ctx.depth >= MAX_TASK_DEPTH || ctx.spawnSubagent === undefined) {
81
116
  return fail("Sub-agents are not available here (nested tasks are not allowed).");
@@ -88,14 +123,18 @@ export function createTaskTool(_options = {}) {
88
123
  try {
89
124
  const result = await ctx.spawnSubagent(request);
90
125
  const details = {
126
+ ...(result.taskId !== undefined ? { taskId: result.taskId } : {}),
127
+ ...(result.status !== undefined ? { status: result.status } : {}),
91
128
  ...(result.sessionFile !== undefined ? { sessionFile: result.sessionFile } : {}),
129
+ ...(result.outputFile !== undefined ? { outputFile: result.outputFile } : {}),
92
130
  usage: result.usage,
93
131
  stopReason: result.stopReason,
94
132
  };
95
- if (ctx.signal.aborted)
133
+ if (ctx.signal.aborted && result.status !== "running")
96
134
  return { content: "aborted by user", isError: true, details };
97
135
  const text = result.text.trim() === "" ? "(the sub-agent returned no text)" : result.text;
98
- return { content: text, isError: result.isError, details };
136
+ const head = result.taskId !== undefined ? `[task ${result.taskId}] ` : "";
137
+ return { content: `${head}${text}`, isError: result.isError, details };
99
138
  }
100
139
  catch (err) {
101
140
  if (ctx.signal.aborted)
@@ -104,4 +143,5 @@ export function createTaskTool(_options = {}) {
104
143
  }
105
144
  },
106
145
  };
146
+ return tool;
107
147
  }
@@ -4,6 +4,9 @@
4
4
  * 会话内任务清单:`set` 整表替换并写 `custom{customType:"ama.todo"}` 条目(不进上下文),`get`
5
5
  * 读活动分支上最近一条。`renderTodoList()` 给 TUI / 结果文本共用。待定项「todo 是否进系统提示」:
6
6
  * 第一期不进(只有 promptSnippet 一行说明工具存在)。
7
+ * [W5-F] `update` 按 id 局部更新(`items: {id, status?, text?}[]`,省得整表重发);条目可带 `planStep`
8
+ * 指回计划步骤(批准计划时由 plan 扩展生成清单)。plan 模式下 `set / update` 由权限管线拒绝。
9
+ * 「连续多回合未更新」的提醒走 W5-H2 的提醒通道(`ama.reminder`,config `todo.reminder`)。
7
10
  */
8
11
  import type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
9
12
  export declare const TODO_CUSTOM_TYPE = "ama.todo";
@@ -12,17 +15,34 @@ export interface TodoItem {
12
15
  id: string;
13
16
  text: string;
14
17
  status: TodoStatus;
18
+ /** [W5-F] 来自计划的步骤 id(`S1`…)。 */
19
+ planStep?: string;
20
+ }
21
+ /** [W5-F] `update` 的一条补丁:按 id 改状态或文字。 */
22
+ export interface TodoPatch {
23
+ id: string;
24
+ status?: TodoStatus;
25
+ text?: string;
15
26
  }
16
27
  export interface TodoState {
17
28
  items: TodoItem[];
18
29
  }
19
30
  export interface TodoInput {
20
- action: "set" | "get";
21
- items?: TodoItem[];
31
+ action: "set" | "get" | "update";
32
+ /** set:整表;update:补丁(`{id, status?, text?}`)。 */
33
+ items?: TodoItem[] | TodoPatch[];
22
34
  }
23
35
  export declare function validateTodoItems(items: unknown): string | undefined;
36
+ /** `ama.todo` 条目的 data → 清单;形状不对返回空表。 */
37
+ export declare function parseTodoState(data: unknown): TodoState;
24
38
  /** 读当前清单;无记录或形状不对返回空表。 */
25
39
  export declare function readTodoState(ctx: Pick<ToolContext, "session">): TodoState;
40
+ /** [W5-F] 按 id 应用补丁;返回新清单或错误说明。 */
41
+ export declare function applyTodoPatches(items: readonly TodoItem[], updates: unknown): {
42
+ items: TodoItem[];
43
+ } | {
44
+ error: string;
45
+ };
26
46
  export declare function renderTodoList(items: readonly TodoItem[]): string[];
27
47
  export declare function executeTodo(input: TodoInput, ctx: ToolContext): Promise<ToolResult>;
28
48
  export declare function createTodoTool(): ToolDefinition<TodoInput>;
@@ -4,6 +4,9 @@
4
4
  * 会话内任务清单:`set` 整表替换并写 `custom{customType:"ama.todo"}` 条目(不进上下文),`get`
5
5
  * 读活动分支上最近一条。`renderTodoList()` 给 TUI / 结果文本共用。待定项「todo 是否进系统提示」:
6
6
  * 第一期不进(只有 promptSnippet 一行说明工具存在)。
7
+ * [W5-F] `update` 按 id 局部更新(`items: {id, status?, text?}[]`,省得整表重发);条目可带 `planStep`
8
+ * 指回计划步骤(批准计划时由 plan 扩展生成清单)。plan 模式下 `set / update` 由权限管线拒绝。
9
+ * 「连续多回合未更新」的提醒走 W5-H2 的提醒通道(`ama.reminder`,config `todo.reminder`)。
7
10
  */
8
11
  export const TODO_CUSTOM_TYPE = "ama.todo";
9
12
  const STATUSES = ["pending", "in_progress", "done"];
@@ -15,7 +18,7 @@ export function validateTodoItems(items) {
15
18
  for (const [i, item] of items.entries()) {
16
19
  if (typeof item !== "object" || item === null)
17
20
  return `items[${i}] must be an object`;
18
- const { id, text, status } = item;
21
+ const { id, text, status, planStep } = item;
19
22
  if (typeof id !== "string" || id === "")
20
23
  return `items[${i}].id must be a non-empty string`;
21
24
  if (typeof text !== "string" || text === "")
@@ -23,15 +26,16 @@ export function validateTodoItems(items) {
23
26
  if (!STATUSES.includes(status)) {
24
27
  return `items[${i}].status must be one of ${STATUSES.join(", ")}`;
25
28
  }
29
+ if (planStep !== undefined && typeof planStep !== "string")
30
+ return `items[${i}].planStep must be a string`;
26
31
  if (ids.has(id))
27
32
  return `duplicate id "${id}"`;
28
33
  ids.add(id);
29
34
  }
30
35
  return undefined;
31
36
  }
32
- /** 读当前清单;无记录或形状不对返回空表。 */
33
- export function readTodoState(ctx) {
34
- const data = ctx.session.lastCustom(TODO_CUSTOM_TYPE);
37
+ /** `ama.todo` 条目的 data → 清单;形状不对返回空表。 */
38
+ export function parseTodoState(data) {
35
39
  if (typeof data === "object" && data !== null && Array.isArray(data.items)) {
36
40
  const items = data.items;
37
41
  if (validateTodoItems(items) === undefined)
@@ -39,6 +43,36 @@ export function readTodoState(ctx) {
39
43
  }
40
44
  return { items: [] };
41
45
  }
46
+ /** 读当前清单;无记录或形状不对返回空表。 */
47
+ export function readTodoState(ctx) {
48
+ return parseTodoState(ctx.session.lastCustom(TODO_CUSTOM_TYPE));
49
+ }
50
+ /** [W5-F] 按 id 应用补丁;返回新清单或错误说明。 */
51
+ export function applyTodoPatches(items, updates) {
52
+ if (!Array.isArray(updates) || updates.length === 0)
53
+ return { error: "items must be a non-empty array of {id, status?, text?}" };
54
+ const next = items.map((it) => ({ ...it }));
55
+ for (const [i, patch] of updates.entries()) {
56
+ if (typeof patch !== "object" || patch === null)
57
+ return { error: `items[${i}] must be an object` };
58
+ const { id, status, text } = patch;
59
+ const item = next.find((it) => it.id === id);
60
+ if (item === undefined)
61
+ return { error: `items[${i}]: no task with id "${String(id)}"` };
62
+ if (status !== undefined) {
63
+ if (!STATUSES.includes(status)) {
64
+ return { error: `items[${i}].status must be one of ${STATUSES.join(", ")}` };
65
+ }
66
+ item.status = status;
67
+ }
68
+ if (text !== undefined) {
69
+ if (typeof text !== "string" || text === "")
70
+ return { error: `items[${i}].text must be a non-empty string` };
71
+ item.text = text;
72
+ }
73
+ }
74
+ return { items: next };
75
+ }
42
76
  export function renderTodoList(items) {
43
77
  if (items.length === 0)
44
78
  return ["(no tasks)"];
@@ -56,12 +90,22 @@ export async function executeTodo(input, ctx) {
56
90
  details: state,
57
91
  };
58
92
  }
59
- if (input.action !== "set")
60
- return { content: 'action must be "set" or "get"', isError: true };
61
- const problem = validateTodoItems(input.items ?? []);
62
- if (problem !== undefined)
63
- return { content: problem, isError: true };
64
- const state = { items: (input.items ?? []).map((it) => ({ ...it })) };
93
+ let state;
94
+ if (input.action === "update") {
95
+ const patched = applyTodoPatches(readTodoState(ctx).items, input.items);
96
+ if ("error" in patched)
97
+ return { content: patched.error, isError: true };
98
+ state = patched;
99
+ }
100
+ else if (input.action === "set") {
101
+ const problem = validateTodoItems(input.items ?? []);
102
+ if (problem !== undefined)
103
+ return { content: problem, isError: true };
104
+ state = { items: (input.items ?? []).map((it) => ({ ...it })) };
105
+ }
106
+ else {
107
+ return { content: 'action must be "set", "update" or "get"', isError: true };
108
+ }
65
109
  ctx.session.appendCustom(TODO_CUSTOM_TYPE, state);
66
110
  return {
67
111
  content: [`Updated tasks (${summary(state.items)}):`, ...renderTodoList(state.items)].join("\n"),
@@ -72,22 +116,22 @@ export function createTodoTool() {
72
116
  return {
73
117
  name: "todo",
74
118
  label: "Todo",
75
- description: "Session task list for multi-step work: `set` replaces the whole list, `get` returns it.",
119
+ description: "Session task list: `set` replaces all items, `update` changes items by id (only given fields), `get` reads.",
76
120
  parameters: {
77
121
  type: "object",
78
122
  properties: {
79
- action: { type: "string", enum: ["set", "get"] },
123
+ action: { type: "string", enum: ["set", "update", "get"] },
80
124
  items: {
81
125
  type: "array",
82
- description: "Full list (set)",
83
126
  items: {
84
127
  type: "object",
85
128
  properties: {
86
129
  id: { type: "string" },
87
130
  text: { type: "string" },
88
131
  status: { type: "string", enum: ["pending", "in_progress", "done"] },
132
+ planStep: { type: "string" },
89
133
  },
90
- required: ["id", "text", "status"],
134
+ required: ["id"],
91
135
  additionalProperties: false,
92
136
  },
93
137
  },
@@ -2,6 +2,8 @@
2
2
  * 头 / 尾截断(行数 + 字节双阈值,先到者为准)与全文落盘(设计 §5.2、§4.4)。[B3]
3
3
  *
4
4
  * - read / grep 用**头截断**(保留开头,提示 offset 续读);bash 用**尾截断**(保留结尾)。
5
+ * - [W5-H2] 会话层通用截断(`maxToolResultChars`)用**头 + 尾**(`truncateMiddle`):保留前 70% 与
6
+ * 后 30%,中间换成省略说明(错误信息常在尾部)。
5
7
  * - 字节按 UTF-8 计;不切断多字节字符;单行超过字节上限时按字符边界截该行。
6
8
  */
7
9
  export declare const DEFAULT_MAX_LINES = 2000;
@@ -33,6 +35,19 @@ export declare function sliceTailBytes(text: string, maxBytes: number): string;
33
35
  export declare function truncateHead(text: string, options?: TruncateOptions): TruncateResult;
34
36
  /** 保留结尾。 */
35
37
  export declare function truncateTail(text: string, options?: TruncateOptions): TruncateResult;
38
+ /** 头 + 尾截断时开头所占的比例(§8.3 H5)。 */
39
+ export declare const HEAD_TAIL_RATIO = 0.7;
40
+ export interface MiddleTruncation {
41
+ /** 截断后的文本(未超限时原样)。 */
42
+ content: string;
43
+ /** 省略的字符数(UTF-16 单元);未截断为 0。 */
44
+ omitted: number;
45
+ }
46
+ /**
47
+ * 头 + 尾截断([W5-H2] §8.3 H5):超过 `maxChars` 时保留前 70% 与后 30%,中间换成
48
+ * `marker(省略字符数)` 的文本(缺省 `[… N 字符已省略]`)。
49
+ */
50
+ export declare function truncateMiddle(text: string, maxChars: number, marker?: (omitted: number) => string): MiddleTruncation;
36
51
  /** 单行按字符截断,附省略提示。 */
37
52
  export declare function truncateLine(line: string, maxChars?: number): string;
38
53
  export declare function formatSize(bytes: number): string;
@@ -2,6 +2,8 @@
2
2
  * 头 / 尾截断(行数 + 字节双阈值,先到者为准)与全文落盘(设计 §5.2、§4.4)。[B3]
3
3
  *
4
4
  * - read / grep 用**头截断**(保留开头,提示 offset 续读);bash 用**尾截断**(保留结尾)。
5
+ * - [W5-H2] 会话层通用截断(`maxToolResultChars`)用**头 + 尾**(`truncateMiddle`):保留前 70% 与
6
+ * 后 30%,中间换成省略说明(错误信息常在尾部)。
5
7
  * - 字节按 UTF-8 计;不切断多字节字符;单行超过字节上限时按字符边界截该行。
6
8
  */
7
9
  import { mkdirSync, writeFileSync } from "node:fs";
@@ -142,6 +144,29 @@ export function truncateTail(text, options = {}) {
142
144
  outputBytes: byteLength(content),
143
145
  };
144
146
  }
147
+ /** 头 + 尾截断时开头所占的比例(§8.3 H5)。 */
148
+ export const HEAD_TAIL_RATIO = 0.7;
149
+ /** 下标落在代理对中间时往前挪一位,不切断字符。 */
150
+ function charBoundary(text, index) {
151
+ if (index <= 0 || index >= text.length)
152
+ return index;
153
+ const code = text.charCodeAt(index);
154
+ return code >= 0xdc00 && code <= 0xdfff ? index - 1 : index;
155
+ }
156
+ /**
157
+ * 头 + 尾截断([W5-H2] §8.3 H5):超过 `maxChars` 时保留前 70% 与后 30%,中间换成
158
+ * `marker(省略字符数)` 的文本(缺省 `[… N 字符已省略]`)。
159
+ */
160
+ export function truncateMiddle(text, maxChars, marker = (omitted) => `[… ${omitted} 字符已省略]`) {
161
+ if (text.length <= maxChars)
162
+ return { content: text, omitted: 0 };
163
+ const limit = Math.max(0, Math.floor(maxChars));
164
+ const headEnd = charBoundary(text, Math.floor(limit * HEAD_TAIL_RATIO));
165
+ const tailStart = charBoundary(text, text.length - (limit - headEnd));
166
+ const omitted = tailStart - headEnd;
167
+ const content = `${text.slice(0, headEnd)}\n\n${marker(omitted)}\n\n${text.slice(tailStart)}`;
168
+ return { content, omitted };
169
+ }
145
170
  /** 单行按字符截断,附省略提示。 */
146
171
  export function truncateLine(line, maxChars = GREP_MAX_LINE_CHARS) {
147
172
  const chars = Array.from(line);
@@ -12,8 +12,15 @@
12
12
  * - `defineTool()` 是恒等函数,只为推断 `I`;放在契约文件里供 SDK 再导出。
13
13
  * - `ToolRegistryApi` 是 Runtime 需要的最小接口,B3 的 `ToolRegistry` 实现它。
14
14
  * - (W3-C0)`SubagentResult.cache` 可选:子会话的命中率与重计费 token。
15
+ * - (W5-C0)第五波(docs/wave5-plan.md §7.3–§7.6、§8.2 C4、§8.3 H1):`annotations.pollable /
16
+ * keepInContext`;`SubagentRequest` 加 `agent / background / taskId / isolation / budgetUsd`;
17
+ * `SubagentResult` 加 `taskId / status / outputFile / sessionRef`(契约要求向后兼容,全部可选);
18
+ * 统一入口 `SubagentRunner / RunnerHandle / SubagentEvent`(ama 子会话、外部 CLI、宿主 runner);
19
+ * `ToolContext.tasks` 为任务注册表的只读视图(W5-G 提供)。
15
20
  */
16
21
  import type { ContentBlock, JsonSchema, ModelRef, ModelThinkingLevel, Usage } from "../ai/types.js";
22
+ import type { CheckpointHooks } from "../checkpoints/types.js";
23
+ import type { PermissionMode } from "../permissions/types.js";
17
24
  export type { JsonSchema } from "../ai/types.js";
18
25
  /** 权限管线的粗分类(§7)。 */
19
26
  export type ToolPermission = "read" | "write" | "execute";
@@ -22,6 +29,10 @@ export interface ToolAnnotations {
22
29
  readOnly?: boolean;
23
30
  destructive?: boolean;
24
31
  openWorld?: boolean;
32
+ /** [W5-C0] 轮询类调用(`task_ctl wait`、后台 bash 查询):重复调用检测豁免(§8.3 H1)。 */
33
+ pollable?: boolean;
34
+ /** [W5-C0] 结果不被档一裁剪(压缩保护集,§8.2 C4)。 */
35
+ keepInContext?: boolean;
25
36
  }
26
37
  export interface ToolDefinition<I = unknown> {
27
38
  /** `^[a-z][a-z0-9_]{1,63}$`;宿主工具建议前缀(canvas_*)。 */
@@ -66,6 +77,24 @@ export interface SubagentRequest {
66
77
  parentToolCallId: string;
67
78
  signal: AbortSignal;
68
79
  onUpdate?(partial: string): void;
80
+ /** [W5-C0] 子 Agent 类型或外部 Agent id;缺省 `general`。 */
81
+ agent?: string;
82
+ /** [W5-C0] 后台运行:立即返回 taskId,完成后以 `<task-notification>` 通知。 */
83
+ background?: boolean;
84
+ /** [W5-C0] 续聊:向已有子会话追加消息(忽略 agent / tools / model)。 */
85
+ taskId?: string;
86
+ /** [W5-C0] `worktree`:在 `<repo>/.ama/worktrees/<taskId>` 里运行;缺省 `none`。 */
87
+ isolation?: "none" | "worktree";
88
+ /** [W5-C0] 外部 Agent 的美元预算。 */
89
+ budgetUsd?: number;
90
+ }
91
+ /** [W5-C0] 子 Agent 任务的终态(`subagent_end.status`)。 */
92
+ export type SubagentStatus = "completed" | "failed" | "aborted" | "max_turns" | "interrupted";
93
+ /** [W5-C0] 会话引用:ama 子会话文件,或外部 CLI 自己的会话 id(`custom{ama.agent-session}`)。 */
94
+ export interface SubagentSessionRef {
95
+ runner: string;
96
+ sessionId: string;
97
+ sessionFile?: string;
69
98
  }
70
99
  export interface SubagentResult {
71
100
  /** 子会话最后一条助手文本。 */
@@ -82,6 +111,86 @@ export interface SubagentResult {
82
111
  hitRate?: number;
83
112
  reBilledTokens: number;
84
113
  };
114
+ /** [W5-C0] 注册表里的任务 id(W5-G 起总有)。 */
115
+ taskId?: string;
116
+ /** [W5-C0] 终态;后台启动时为 `running`。 */
117
+ status?: SubagentStatus | "running";
118
+ /** [W5-C0] 结果全文(> 50 KB 截断时、后台任务的输出文件)。 */
119
+ outputFile?: string;
120
+ sessionRef?: SubagentSessionRef;
121
+ }
122
+ /** runner 上报的进度(由注册表转成 `subagent_update` 事件)。 */
123
+ export type SubagentEvent = {
124
+ type: "text";
125
+ delta: string;
126
+ } | {
127
+ type: "thought";
128
+ delta: string;
129
+ } | {
130
+ type: "tool";
131
+ toolName: string;
132
+ status: "started" | "completed" | "failed";
133
+ } | {
134
+ type: "turn";
135
+ turn: number;
136
+ } | {
137
+ type: "usage";
138
+ usage?: Usage;
139
+ /** 无美元单位的外部 Agent 按各自单位记(不换算)。 */
140
+ unit?: "usd" | "tokens" | "requests";
141
+ amount?: number;
142
+ } | {
143
+ type: "notice";
144
+ level: "info" | "warn";
145
+ text: string;
146
+ };
147
+ export interface SubagentRunRequest {
148
+ prompt: string;
149
+ cwd: string;
150
+ /** 不得比父会话当前模式宽(`isAtLeastAsStrict`)。 */
151
+ mode: PermissionMode;
152
+ model?: string;
153
+ /** 续聊的会话 id(runner 自己的)。 */
154
+ resume?: string;
155
+ budgetUsd?: number;
156
+ /** [W5-EG] 发起的任务 id(审批标注 `context.taskId`、外部会话引用记账用);可选。 */
157
+ taskId?: string;
158
+ signal: AbortSignal;
159
+ onEvent(event: SubagentEvent): void;
160
+ }
161
+ export interface RunnerHandle {
162
+ /** 子会话 / 外部会话 id。 */
163
+ readonly id: string;
164
+ /** 续聊。 */
165
+ send(text: string): Promise<void>;
166
+ wait(): Promise<SubagentResult>;
167
+ stop(): Promise<void>;
168
+ }
169
+ /** `ama`(AmaRunner)| `claude` | `codex` | `acp:<program>`(ProcessRunner,W5-E)| 宿主 id。 */
170
+ export interface SubagentRunner {
171
+ readonly id: string;
172
+ start(request: SubagentRunRequest): Promise<RunnerHandle>;
173
+ }
174
+ /** [W5-C0] 任务注册表里一条任务的快照(`task_ctl list`、RPC `get_tasks`、`/tasks`)。 */
175
+ export interface TaskInfo {
176
+ taskId: string;
177
+ agent: string;
178
+ runner: string;
179
+ description: string;
180
+ background: boolean;
181
+ status: SubagentStatus | "running";
182
+ startedAt: number;
183
+ endedAt?: number;
184
+ turns?: number;
185
+ usage?: Usage;
186
+ costUsd?: number;
187
+ outputFile?: string;
188
+ sessionRef?: SubagentSessionRef;
189
+ }
190
+ /** [W5-C0] 任务注册表的只读视图(W5-G 的 `SubagentRegistry` 提供)。 */
191
+ export interface TaskRegistryView {
192
+ list(): readonly TaskInfo[];
193
+ get(taskId: string): TaskInfo | undefined;
85
194
  }
86
195
  export interface ToolContext {
87
196
  readonly toolCallId: string;
@@ -115,8 +224,12 @@ export interface ToolContext {
115
224
  /** 活动分支上最近一条该类型 custom 条目的 data。 */
116
225
  lastCustom(customType: string): unknown;
117
226
  };
227
+ /** 检查点(docs/rewind-plan.md §2):edit / write 写文件前后调用;未启用时为 undefined。 */
228
+ readonly checkpoint?: CheckpointHooks;
118
229
  /** 仅 depth 0 且 task 可用时存在。 */
119
230
  readonly spawnSubagent?: (request: SubagentRequest) => Promise<SubagentResult>;
231
+ /** [W5-C0] 任务注册表只读视图(`task_ctl`);注册表未装配时 undefined。 */
232
+ readonly tasks?: TaskRegistryView;
120
233
  log(level: "debug" | "info" | "warn", message: string): void;
121
234
  }
122
235
  export type ToolSource = "builtin" | "host" | "sdk";
@@ -12,6 +12,11 @@
12
12
  * - `defineTool()` 是恒等函数,只为推断 `I`;放在契约文件里供 SDK 再导出。
13
13
  * - `ToolRegistryApi` 是 Runtime 需要的最小接口,B3 的 `ToolRegistry` 实现它。
14
14
  * - (W3-C0)`SubagentResult.cache` 可选:子会话的命中率与重计费 token。
15
+ * - (W5-C0)第五波(docs/wave5-plan.md §7.3–§7.6、§8.2 C4、§8.3 H1):`annotations.pollable /
16
+ * keepInContext`;`SubagentRequest` 加 `agent / background / taskId / isolation / budgetUsd`;
17
+ * `SubagentResult` 加 `taskId / status / outputFile / sessionRef`(契约要求向后兼容,全部可选);
18
+ * 统一入口 `SubagentRunner / RunnerHandle / SubagentEvent`(ama 子会话、外部 CLI、宿主 runner);
19
+ * `ToolContext.tasks` 为任务注册表的只读视图(W5-G 提供)。
15
20
  */
16
21
  /** 恒等函数,帮助推断输入类型。 */
17
22
  export function defineTool(tool) {
@@ -8,6 +8,7 @@ import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
8
8
  import { dirname } from "node:path";
9
9
  import { displayPath, resolvePath } from "./paths.js";
10
10
  import { withFileMutex } from "./file-mutex.js";
11
+ import { beforeWrite } from "./edit.js";
11
12
  import { BOM, detectLineEnding, normalizeToLF, restoreLineEndings, splitBom, } from "./edit-fuzzy.js";
12
13
  async function exists(path) {
13
14
  try {
@@ -48,8 +49,10 @@ export async function executeWrite(input, ctx) {
48
49
  }
49
50
  output = conformToOriginal(await readFile(abs, "utf8"), input.content);
50
51
  }
52
+ await beforeWrite(ctx, abs);
51
53
  await mkdir(dirname(abs), { recursive: true });
52
54
  await writeFile(abs, output, "utf8");
55
+ ctx.checkpoint?.afterWrite(abs, output);
53
56
  ctx.markRead(abs);
54
57
  const details = {
55
58
  path: abs,
@@ -58,6 +58,10 @@ export interface Glyphs {
58
58
  readonly ellipsis: string;
59
59
  readonly arrowUp: string;
60
60
  readonly arrowDown: string;
61
+ /** [W5-A] 状态栏 git 分支标记。 */
62
+ readonly branch: string;
63
+ /** [W5-A] 速率行分隔点。 */
64
+ readonly dot: string;
61
65
  }
62
66
  export declare const UNICODE_GLYPHS: Glyphs;
63
67
  export declare const ASCII_GLYPHS: Glyphs;
@@ -42,6 +42,8 @@ export const UNICODE_GLYPHS = {
42
42
  ellipsis: "…",
43
43
  arrowUp: "↑",
44
44
  arrowDown: "↓",
45
+ branch: "⎇",
46
+ dot: "•",
45
47
  };
46
48
  export const ASCII_GLYPHS = {
47
49
  ascii: true,
@@ -77,6 +79,8 @@ export const ASCII_GLYPHS = {
77
79
  ellipsis: "...",
78
80
  arrowUp: "^",
79
81
  arrowDown: "v",
82
+ branch: "git",
83
+ dot: "*",
80
84
  };
81
85
  function truthy(value) {
82
86
  if (value === undefined || value === "")
@@ -31,14 +31,19 @@ export declare const DEFAULT_KEYBINDINGS: {
31
31
  readonly "tui.select.confirm": readonly ["enter", "tab"];
32
32
  readonly "tui.select.cancel": readonly ["escape", "ctrl+c"];
33
33
  readonly "app.interrupt": readonly ["escape"];
34
+ readonly "app.rewind": readonly ["escape"];
34
35
  readonly "app.clear": readonly ["ctrl+c"];
35
36
  readonly "app.exit": readonly ["ctrl+d"];
36
37
  readonly "app.message.followUp": readonly ["alt+enter"];
37
38
  readonly "app.message.dequeue": readonly ["alt+up"];
38
- readonly "app.permission.cycle": readonly ["shift+tab"];
39
+ readonly "app.permission.cycle": readonly ["shift+tab", "tab"];
39
40
  readonly "app.tools.expand": readonly ["ctrl+o"];
40
41
  readonly "app.model.select": readonly ["ctrl+l"];
41
42
  readonly "app.thinking.select": readonly ["ctrl+t"];
43
+ /** [W5-A] 底部信息行 full ↔ compact(只影响本会话)。 */
44
+ readonly "app.statusLine.toggle": readonly ["ctrl+g"];
45
+ /** [W5-U] 粘贴剪贴板图片(写进数据目录,输入框插入 `@路径`)。 */
46
+ readonly "app.paste.image": readonly ["ctrl+v"];
42
47
  };
43
48
  export type ActionId = keyof typeof DEFAULT_KEYBINDINGS;
44
49
  export type KeybindingOverrides = Partial<Record<ActionId, readonly string[]>>;