@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,39 @@
1
+ /**
2
+ * 外部编辑器(计划审批框的「编辑计划」与「继续修改」):`$VISUAL` → `$EDITOR` → `vi`(Windows `notepad`)。
3
+ * [W5-U] 编辑期间 TUI 挂起(交还终端),回来后整屏重画。临时文件在系统临时目录,读完即删。
4
+ */
5
+ import { spawnSync } from "node:child_process";
6
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ export function editorCommand(env, platform = process.platform) {
10
+ const configured = env["VISUAL"]?.trim() || env["EDITOR"]?.trim();
11
+ if (configured !== undefined && configured !== "")
12
+ return configured;
13
+ return platform === "win32" ? "notepad" : "vi";
14
+ }
15
+ function runEditor(command, file) {
16
+ // 编辑器变量常带参数(`code --wait`),交给 shell 拆;路径加引号
17
+ const result = spawnSync(`${command} "${file}"`, { stdio: "inherit", shell: true });
18
+ return result.status;
19
+ }
20
+ /** 在外部编辑器里改 `text`;编辑器非零退出或读不回来返回 undefined。 */
21
+ export async function editExternally(text, name, deps) {
22
+ const dir = mkdtempSync(join(tmpdir(), "ama-edit-"));
23
+ const file = join(dir, name);
24
+ writeFileSync(file, text);
25
+ deps.suspend();
26
+ try {
27
+ const code = (deps.run ?? runEditor)(editorCommand(deps.env, deps.platform), file);
28
+ if (code !== 0)
29
+ return undefined;
30
+ return readFileSync(file, "utf8");
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ finally {
36
+ deps.resume();
37
+ rmSync(dir, { recursive: true, force: true });
38
+ }
39
+ }
@@ -11,15 +11,23 @@
11
11
  * - 晚绑定:`runtime.approvals.setUiBroker`(审批对话框)与 `runtime.notifier.set`(宿主通知进消息区),
12
12
  * 退出时撤下。
13
13
  * - 键位:Enter 发送(运行中 = steer),其余应用级键位见 `key-dispatch.ts`。
14
+ * - 回滚(RW-C):`/rewind` 与空闲双击 Esc 走 rewind-flow.ts;回填的原消息图片暂存,随下一条消息发送。
15
+ * - 底部(W5-A,status-area.ts):`ui.statusLine` full 时状态栏上方多一行速率行;Ctrl+G / `/statusline`
16
+ * 切换(只影响本会话)。
17
+ * - 第五波(W5-U,agent-ui.ts):计划审批框、子 Agent 折叠视图、`/tasks` `/agents` `/paste` 与 Ctrl+V、审批来源
18
+ * 标注与外部 Agent 首次运行的合并确认(approval-merge.ts)、harness 提示。
14
19
  * - 启动头按 `ui.quietStartup`(startup-header.ts):normal 框 + 模型 / 目录 / 模式 / 资源清单(窄屏或
15
20
  * `ui.compact` 去框),header 一行,silent 不输出。
16
21
  */
17
22
  import type { AgentSession } from "../../agent/types.js";
18
23
  import type { ModeContext } from "../../cli/deps.js";
19
24
  import type { Runtime } from "../../cli/runtime.js";
25
+ import type { StatusLineMode } from "../../config/types.js";
26
+ import type { ClipboardDeps } from "../../tools/clipboard-image.js";
20
27
  import { Editor, Keybindings, TUI, type Terminal, type Theme } from "../../tui.js";
21
28
  import { MessageView } from "./message-view.js";
22
- import { StatusBar } from "./status-bar.js";
29
+ import { StatusArea } from "./status-area.js";
30
+ import type { StatusBar } from "./status-bar.js";
23
31
  import { ToolTracker } from "./tool-view.js";
24
32
  export interface InteractiveModeOptions {
25
33
  /** 缺省 `ProcessTerminal`(测试注入 MemoryTerminal)。 */
@@ -32,8 +40,12 @@ export interface InteractiveModeOptions {
32
40
  spinnerIntervalMs?: number;
33
41
  /** 输入历史文件;false 不读写(缺省 `<dataDir>/history`)。 */
34
42
  historyFile?: string | false;
43
+ /** 底部布局(缺省按 `ui.statusLine`;测试固定)。 */
44
+ statusLine?: StatusLineMode;
35
45
  /** 界面就绪后回调(测试驱动用)。 */
36
46
  onReady?(handle: InteractiveHandle): void;
47
+ /** 剪贴板读取的注入(测试;缺省调系统命令)。 */
48
+ clipboard?: ClipboardDeps;
37
49
  }
38
50
  export interface InteractiveHandle {
39
51
  readonly tui: TUI;
@@ -41,6 +53,7 @@ export interface InteractiveHandle {
41
53
  readonly view: MessageView;
42
54
  readonly tools: ToolTracker;
43
55
  readonly status: StatusBar;
56
+ readonly area: StatusArea;
44
57
  session(): AgentSession;
45
58
  exit(code: number): void;
46
59
  }
@@ -11,30 +11,40 @@
11
11
  * - 晚绑定:`runtime.approvals.setUiBroker`(审批对话框)与 `runtime.notifier.set`(宿主通知进消息区),
12
12
  * 退出时撤下。
13
13
  * - 键位:Enter 发送(运行中 = steer),其余应用级键位见 `key-dispatch.ts`。
14
+ * - 回滚(RW-C):`/rewind` 与空闲双击 Esc 走 rewind-flow.ts;回填的原消息图片暂存,随下一条消息发送。
15
+ * - 底部(W5-A,status-area.ts):`ui.statusLine` full 时状态栏上方多一行速率行;Ctrl+G / `/statusline`
16
+ * 切换(只影响本会话)。
17
+ * - 第五波(W5-U,agent-ui.ts):计划审批框、子 Agent 折叠视图、`/tasks` `/agents` `/paste` 与 Ctrl+V、审批来源
18
+ * 标注与外部 Agent 首次运行的合并确认(approval-merge.ts)、harness 提示。
14
19
  * - 启动头按 `ui.quietStartup`(startup-header.ts):normal 框 + 模型 / 目录 / 模式 / 资源清单(窄屏或
15
20
  * `ui.compact` 去框),header 一行,silent 不输出。
16
21
  */
17
22
  import { promptImages, sessionModel } from "../image-input.js";
18
23
  import { join } from "node:path";
19
24
  import { AgentSessionImpl } from "../../agent/session.js";
25
+ import { taskRegistryView } from "../../agent/subagent-registry.js";
20
26
  import { currentSession, switchSession } from "../../cli/compose-session.js";
21
- import { startupInfo, startupScreenLevel } from "../../cli/startup-screen.js";
27
+ import { startupInfo, startupScreenLevel, tildePath } from "../../cli/startup-screen.js";
22
28
  import { KEYBINDINGS_FILE } from "../../config/paths.js";
23
29
  import { AmaError, isAmaError } from "../../errors.js";
24
- import { detectSandboxCapability } from "../../codemode/capability.js";
25
- import { effectiveCodemodeMode } from "../../tools/presets.js";
26
- import { Container, Editor, Keybindings, Loader, ProcessTerminal, Spacer, TUI, Text, createTheme, detectCapabilities, resolveAscii, resolveThemeName, loadKeybindingsFile, truncateToWidth, } from "../../tui.js";
27
- import { cacheEventNotice, cacheNoticesEnabled } from "../session-report.js";
30
+ import { Container, Editor, Keybindings, Loader, ProcessTerminal, Spacer, TUI, Text, createTheme, detectCapabilities, resolveAscii, resolveThemeName, loadKeybindingsFile, } from "../../tui.js";
31
+ import { BYPASS_MODE, createBypassGate } from "../../permissions/bypass.js";
28
32
  import { onTerminationSignals } from "../shared.js";
33
+ import { AgentUi } from "./agent-ui.js";
29
34
  import { ApprovalDialogBroker, approvalOutcomeText } from "./approval-dialog.js";
35
+ import { mergingBroker } from "./approval-merge.js";
30
36
  import { ALL_COMMANDS, runInteractiveCommand } from "./commands.js";
31
37
  import { InteractiveCompletion } from "./completion.js";
38
+ import { confirmBypass } from "./confirm-dialog.js";
32
39
  import { createKeyDispatch } from "./key-dispatch.js";
33
40
  import { MessageView, exitSummaryLines } from "./message-view.js";
34
41
  import { openPicker } from "./pickers.js";
42
+ import { createRewindFlow } from "./rewind-flow.js";
35
43
  import { StartupHeader } from "./startup-header.js";
36
44
  import { QueueView, RunIndicator } from "./run-indicator.js";
37
- import { StatusBar } from "./status-bar.js";
45
+ import { StatusArea, statusLineSlash } from "./status-area.js";
46
+ import { createSessionEventHandler } from "./session-events.js";
47
+ import { SubagentTracker } from "./subagent-view.js";
38
48
  import { ToolTracker } from "./tool-view.js";
39
49
  const HINT_MS = 2500;
40
50
  const EDITOR_PLACEHOLDER = "输入消息,/ 命令,@ 文件,Shift+Enter 换行";
@@ -51,17 +61,6 @@ function loadKeys(runtime, warn) {
51
61
  warn(`keybindings.json:${w}`);
52
62
  return new Keybindings(parsed.overrides);
53
63
  }
54
- /** 一行提示;空时不占行。 */
55
- class HintLine {
56
- text = "";
57
- setText(text) {
58
- this.text = text;
59
- }
60
- render(width) {
61
- return this.text === "" ? [] : [truncateToWidth(this.text, width)];
62
- }
63
- invalidate() { }
64
- }
65
64
  export function runInteractiveMode(runtime, context, options = {}) {
66
65
  const terminal = options.terminal ?? processTerminal();
67
66
  const ui = runtime.config.ui ?? {};
@@ -83,12 +82,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
83
82
  ...(ui.markdown !== undefined ? { markdown: ui.markdown } : {}),
84
83
  ...(ui.compact === true ? { compact: true } : {}),
85
84
  });
85
+ const subagents = new SubagentTracker(now);
86
86
  const tools = new ToolTracker({
87
87
  theme,
88
88
  cwd: session.state.cwd,
89
89
  getTool: (name) => session.getTools().find((tool) => tool.name === name),
90
90
  now,
91
91
  spinner: () => loader.frame,
92
+ subagent: (toolCallId) => subagents.forToolCall(toolCallId),
92
93
  });
93
94
  const queueView = new QueueView(theme);
94
95
  const loaderSlot = new Container();
@@ -100,19 +101,17 @@ export function runInteractiveMode(runtime, context, options = {}) {
100
101
  ...(options.spinnerIntervalMs !== undefined ? { intervalMs: options.spinnerIntervalMs } : {}),
101
102
  });
102
103
  loader.onFrame(() => tools.tick());
103
- const hint = new HintLine();
104
- let sandboxStrict;
105
- const status = new StatusBar({
104
+ const area = new StatusArea({
105
+ runtime,
106
+ theme,
106
107
  session: () => session,
107
- preset: () => runtime.config.tools?.preset ?? "default",
108
- hostStatus: () => runtime.host?.status(),
109
- codemode: () => {
110
- const mode = effectiveCodemodeMode(runtime.config);
111
- const active = session.getTools().some((tool) => tool.name === "codemode");
112
- return mode === "off" || !active ? undefined : mode;
113
- },
114
- sandboxStrict: () => (sandboxStrict ??= detectSandboxCapability().strict),
115
- }, theme);
108
+ now,
109
+ render: () => tui.requestRender(),
110
+ redraw: () => tui.forceFullRedraw(),
111
+ env,
112
+ ...(options.statusLine !== undefined ? { layout: options.statusLine } : {}),
113
+ });
114
+ const { hint, bar: status } = area;
116
115
  const historyFile = options.historyFile === false
117
116
  ? undefined
118
117
  : (options.historyFile ?? join(runtime.paths.dataDir, "history"));
@@ -139,6 +138,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
139
138
  tui.addChild(loaderSlot);
140
139
  tui.addChild(editor);
141
140
  tui.addChild(hint);
141
+ tui.addChild(area.rate);
142
142
  tui.addChild(status);
143
143
  // ---- 小工具 ---------------------------------------------------------------
144
144
  let finished = false;
@@ -149,7 +149,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
149
149
  view.addNotice(level, text);
150
150
  render();
151
151
  };
152
- const showHint = (text) => {
152
+ const showHint = (text, ms = HINT_MS) => {
153
153
  hint.setText(text === "" ? "" : theme.fg("dim", text));
154
154
  if (hintTimer !== undefined)
155
155
  clearTimeout(hintTimer);
@@ -158,7 +158,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
158
158
  hintTimer = setTimeout(() => {
159
159
  hint.setText("");
160
160
  render();
161
- }, HINT_MS);
161
+ }, ms);
162
162
  hintTimer.unref?.();
163
163
  }
164
164
  render();
@@ -170,88 +170,18 @@ export function runInteractiveMode(runtime, context, options = {}) {
170
170
  render();
171
171
  };
172
172
  // ---- 会话事件 -------------------------------------------------------------
173
- const onEvent = (event) => {
174
- switch (event.type) {
175
- case "agent_settled":
176
- if (event.warning !== undefined)
177
- view.addNotice("warn", event.warning);
178
- status.refresh();
179
- break;
180
- case "message_start": {
181
- const message = event.message;
182
- if (message.role === "user")
183
- view.addUser(message);
184
- else if (message.role === "assistant")
185
- view.startAssistant(message);
186
- else if (message.role === "custom" && message.display) {
187
- view.addNotice("info", typeof message.content === "string" ? message.content : "");
188
- }
189
- break;
190
- }
191
- case "message_update":
192
- view.updateAssistant(event.message);
193
- break;
194
- case "message_end":
195
- if (event.message.role === "assistant") {
196
- view.endAssistant(event.message);
197
- status.refresh();
198
- }
199
- break;
200
- case "tool_execution_start": {
201
- const started = tools.start(event);
202
- if (started.topLevel)
203
- view.addTool(started.view);
204
- break;
205
- }
206
- case "tool_execution_update":
207
- tools.update(event.toolCallId, event.partial);
208
- render();
209
- return;
210
- case "tool_execution_end":
211
- tools.end(event.toolCallId, event.result, event.isError);
212
- break;
213
- case "queue_update":
214
- setQueue(event.steering, event.followUp);
215
- return;
216
- case "compaction_end":
217
- if (event.result !== undefined)
218
- view.addCompaction(event.result);
219
- else if (event.error !== undefined)
220
- view.addNotice("error", `压缩失败:${event.error}`);
221
- else if (event.aborted)
222
- view.addNotice("info", "压缩已取消");
223
- status.refresh();
224
- break;
225
- case "auto_retry_start":
226
- view.addRetry(event.attempt, event.maxAttempts, event.delayMs, event.errorMessage);
227
- break;
228
- case "auto_retry_end":
229
- if (!event.success)
230
- view.addRetryFailed(event.finalError);
231
- break;
232
- case "cache_miss":
233
- case "context_pressure": {
234
- const shown = cacheEventNotice(event, cacheNoticesEnabled(session));
235
- if (shown !== undefined)
236
- view.addNotice(shown.level, shown.text);
237
- status.refresh();
238
- render();
239
- return;
240
- }
241
- case "cache_warm":
242
- case "permission_mode_changed":
243
- case "model_changed":
244
- case "thinking_level_changed":
245
- case "session_changed":
246
- status.refresh();
247
- render();
248
- return;
249
- default:
250
- break;
251
- }
252
- indicator.onEvent(event);
253
- render();
254
- };
173
+ const onEvent = createSessionEventHandler({
174
+ view,
175
+ tools,
176
+ status,
177
+ area,
178
+ agentUi: () => agentUi,
179
+ indicator,
180
+ session: () => session,
181
+ setQueue,
182
+ notice,
183
+ render,
184
+ });
255
185
  let unsubscribe = session.subscribe(onEvent);
256
186
  const startupLevel = startupScreenLevel(runtime);
257
187
  const home = env["HOME"] ?? env["USERPROFILE"];
@@ -282,7 +212,8 @@ export function runInteractiveMode(runtime, context, options = {}) {
282
212
  tools.clear();
283
213
  replay();
284
214
  setQueue([], []);
285
- status.refresh();
215
+ area.rebind();
216
+ agentUi.attach(next);
286
217
  indicator.reset();
287
218
  if (next instanceof AgentSessionImpl)
288
219
  next.announceStart(reason);
@@ -292,12 +223,20 @@ export function runInteractiveMode(runtime, context, options = {}) {
292
223
  * 空闲时发提示。agent_settled 之后会话周期还要一个微任务才结束,所以先 waitForIdle;
293
224
  * 仍然撞上运行中(极少)就排到本轮之后。
294
225
  */
226
+ let draftImages = [];
227
+ const resize = runtime.config.images?.resize;
228
+ const imageResize = resize !== undefined ? { resize } : {};
295
229
  const startPrompt = (text) => {
296
230
  const target = session;
231
+ const carried = draftImages;
232
+ draftImages = [];
297
233
  void target
298
234
  .waitForIdle()
299
235
  .then(async () => {
300
- const images = await promptImages(text, [], target.state.cwd, sessionModel(runtime.providers, target));
236
+ const images = [
237
+ ...carried,
238
+ ...(await promptImages(text, [], target.state.cwd, sessionModel(runtime.providers, target), imageResize)),
239
+ ];
301
240
  return target.prompt(text, images.length > 0 ? { images } : {});
302
241
  })
303
242
  .catch((error) => {
@@ -312,6 +251,40 @@ export function runInteractiveMode(runtime, context, options = {}) {
312
251
  render();
313
252
  });
314
253
  };
254
+ /** 对话换了路径(/tree、回滚):重画消息区。内容可能缩到视口顶以上,差分画不对,整屏重画。 */
255
+ const reloadView = () => {
256
+ resetView();
257
+ tools.clear();
258
+ replay();
259
+ status.refresh();
260
+ area.refreshGit();
261
+ tui.forceFullRedraw();
262
+ };
263
+ const setDraft = (draft) => {
264
+ editor.setText(draft.text);
265
+ draftImages = [...(draft.images ?? [])];
266
+ render();
267
+ };
268
+ const pickerHost = {
269
+ theme,
270
+ keybindings: keys,
271
+ showOverlay: (c, o) => tui.showOverlay(c, o),
272
+ columns: () => terminal.columns,
273
+ rows: () => terminal.rows,
274
+ };
275
+ // 进入 Bypass 前确认一次;启动时已是 Bypass(命令行 / 配置指定)视为已确认
276
+ const confirmMode = createBypassGate(() => confirmBypass(pickerHost), session.state.permissionMode === BYPASS_MODE);
277
+ const rewind = createRewindFlow({
278
+ ...pickerHost,
279
+ session: () => session,
280
+ now,
281
+ render,
282
+ notice,
283
+ hint: (text) => showHint(text),
284
+ reload: reloadView,
285
+ setDraft,
286
+ editorEmpty: () => editor.isEmpty(),
287
+ });
315
288
  const commandUi = {
316
289
  runtime,
317
290
  session: () => session,
@@ -320,12 +293,10 @@ export function runInteractiveMode(runtime, context, options = {}) {
320
293
  rebind(next, request.kind === "new" ? "new" : request.kind === "fork" ? "fork" : "resume");
321
294
  return next;
322
295
  },
323
- pick: (spec) => openPicker({
324
- theme,
325
- keybindings: keys,
326
- showOverlay: (c, o) => tui.showOverlay(c, o),
327
- columns: () => terminal.columns,
328
- }, spec),
296
+ pick: (spec) => openPicker(pickerHost, spec),
297
+ confirmMode,
298
+ rewind: () => rewind.open(),
299
+ setDraft,
329
300
  notice,
330
301
  panel: (component) => {
331
302
  view.add(component);
@@ -339,17 +310,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
339
310
  render();
340
311
  },
341
312
  prompt: (text) => startPrompt(text),
342
- reload: () => {
343
- resetView();
344
- tools.clear();
345
- replay();
346
- status.refresh();
347
- render();
348
- },
313
+ reload: reloadView,
349
314
  exit: (code) => exit(code),
350
315
  now,
316
+ extra: (name, args) => agentUi.command(name, args),
351
317
  };
352
- const runCommand = (line) => runInteractiveCommand(line, commandUi).finally(() => {
318
+ const runCommand = (line) => (statusLineSlash(area, line, notice)
319
+ ? Promise.resolve(true)
320
+ : runInteractiveCommand(line, commandUi)).finally(() => {
353
321
  status.refresh();
354
322
  render();
355
323
  });
@@ -385,16 +353,16 @@ export function runInteractiveMode(runtime, context, options = {}) {
385
353
  now,
386
354
  showHint,
387
355
  onExpandToggle: (expanded) => view.setThinkingExpanded(expanded),
356
+ onStatusLineToggle: () => area.toggle(),
357
+ onPasteImage: () => void agentUi.paste(),
358
+ confirmMode,
388
359
  submit: (text, via) => submit(text, via),
389
360
  runCommand: (line) => void runCommand(line),
390
361
  exit: (code) => exit(code),
362
+ onInterrupted: (empty) => void rewind.afterInterrupt(empty),
391
363
  }));
392
364
  // ---- 晚绑定 ---------------------------------------------------------------
393
- const broker = new ApprovalDialogBroker({
394
- theme,
395
- keybindings: keys,
396
- cwd: session.state.cwd,
397
- permissionMode: () => session.state.permissionMode,
365
+ const overlayHooks = {
398
366
  showOverlay: (component) => tui.showOverlay(component, { anchor: "bottom" }),
399
367
  onOpen: () => {
400
368
  editor.disableSubmit = true;
@@ -406,12 +374,44 @@ export function runInteractiveMode(runtime, context, options = {}) {
406
374
  tools.setAwaiting(false);
407
375
  indicator.setApproval(false);
408
376
  },
377
+ };
378
+ const agentUi = new AgentUi({
379
+ theme,
380
+ tui,
381
+ editor,
382
+ tools: () => tools,
383
+ subagents,
384
+ session: () => session,
385
+ dataDir: runtime.paths.dataDir,
386
+ env,
387
+ now,
388
+ notice,
389
+ panel: (component) => commandUi.panel?.(component),
390
+ pick: (spec) => openPicker(pickerHost, spec),
391
+ hint: (text) => showHint(text),
392
+ render,
393
+ switchSession: (request) => commandUi.switchSession(request),
394
+ prompt: (text) => startPrompt(text),
395
+ dialog: { theme, keybindings: keys, ...overlayHooks },
396
+ displayPath: (path) => tildePath(path, home),
397
+ ...(options.clipboard !== undefined ? { clipboard: options.clipboard } : {}),
398
+ });
399
+ const taskAgent = (taskId) => taskRegistryView(session.state.sessionId)?.get(taskId)?.agent;
400
+ const broker = mergingBroker(new ApprovalDialogBroker({
401
+ theme,
402
+ keybindings: keys,
403
+ cwd: session.state.cwd,
404
+ permissionMode: () => session.state.permissionMode,
405
+ taskAgent,
406
+ externalRunner: (agent) => agentUi.merge.externalRunner(agent),
407
+ ...overlayHooks,
409
408
  report: (request, outcome) => {
410
409
  if (outcome === "deny" || outcome === "cancelled") {
411
- notice(outcome === "deny" ? "info" : "warn", approvalOutcomeText(request, outcome));
410
+ const text = approvalOutcomeText(request, outcome, taskAgent);
411
+ notice(outcome === "deny" ? "info" : "warn", text);
412
412
  }
413
413
  },
414
- });
414
+ }), agentUi.merge, (request) => notice("info", `${approvalOutcomeText(request, "allow", taskAgent)}(随上一次确认)`));
415
415
  // ---- 启动与退出 -----------------------------------------------------------
416
416
  let offSignals = () => undefined;
417
417
  function exit(code) {
@@ -421,11 +421,13 @@ export function runInteractiveMode(runtime, context, options = {}) {
421
421
  if (hintTimer !== undefined)
422
422
  clearTimeout(hintTimer);
423
423
  loader.stop();
424
+ area.dispose();
424
425
  // 退出摘要留在回滚里;输入框、状态栏等底部区域撤掉,屏幕停在摘要下面
425
426
  view.addExitSummary(exitSummaryLines(session.getStats(), now() - startedAt, theme));
426
427
  tui.clear();
427
428
  tui.addChild(view);
428
429
  offSignals();
430
+ agentUi.detach();
429
431
  runtime.approvals.setUiBroker(undefined);
430
432
  runtime.notifier.set(undefined);
431
433
  tui.stop();
@@ -456,6 +458,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
456
458
  }
457
459
  runtime.approvals.setUiBroker(broker);
458
460
  runtime.notifier.set((message, level) => notice(level, message));
461
+ agentUi.attach(session);
459
462
  offSignals = onTerminationSignals((code) => exit(code));
460
463
  tui.setFocus(editor);
461
464
  options.onReady?.({
@@ -464,6 +467,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
464
467
  view,
465
468
  tools,
466
469
  status,
470
+ area,
467
471
  session: () => session,
468
472
  exit,
469
473
  });
@@ -3,9 +3,15 @@
3
3
  *
4
4
  * 编辑器之前的输入监听:Ctrl+C 清空输入 / 再按退出、Esc 中断(clearQueue 回填编辑器后 abort)、
5
5
  * Ctrl+D 空输入退出、Alt+Enter followUp、Alt+↑ 取回最后一条排队消息、Shift+Tab 循环权限模式、
6
- * Ctrl+O 展开工具输出与思考块、Ctrl+L 模型、Ctrl+T 思考级别。键位由 `keybindings.json` 覆盖。
6
+ * Ctrl+O 展开工具输出与思考块、Ctrl+L 模型、Ctrl+T 思考级别、Ctrl+G 底部信息行 full ↔ compact(W5-A)、
7
+ * Ctrl+V 粘贴剪贴板图片(`app.paste.image`,W5-U)。
8
+ * 键位由 `keybindings.json` 覆盖。
9
+ *
10
+ * [RW-C] 空闲时双击 Esc(`app.rewind`,double-esc.ts):输入框为空打开回滚列表,有字则清空并存进
11
+ * 输入历史;运行中 Esc 仍为中断,中断后交给 `onInterrupted`(中断即撤回)。
7
12
  */
8
13
  import type { AgentSession } from "../../agent/types.js";
14
+ import type { PermissionMode } from "../../permissions/types.js";
9
15
  import type { Editor, Keybindings } from "../../tui.js";
10
16
  import type { StatusBar } from "./status-bar.js";
11
17
  import type { ToolTracker } from "./tool-view.js";
@@ -20,12 +26,26 @@ export interface KeyDispatchDeps {
20
26
  /** 运行或压缩中(Esc 才中断)。 */
21
27
  busy(): boolean;
22
28
  now(): number;
23
- showHint(text: string): void;
29
+ /** 底部提示;`ms` 是停留时间(缺省由调用方决定)。 */
30
+ showHint(text: string, ms?: number): void;
24
31
  /** Ctrl+O 之后(消息区思考块跟着展开 / 折叠)。 */
25
32
  onExpandToggle?(expanded: boolean): void;
33
+ /** Ctrl+G:切换底部信息行,返回切换后的布局。 */
34
+ onStatusLineToggle?(): "full" | "compact";
35
+ /**
36
+ * 循环到某模式前的确认(进入 Bypass 前弹确认框,permissions/bypass.ts);返回 false 时跳过该模式,
37
+ * 落到循环里的下一个。没有时直接切换。
38
+ */
39
+ confirmMode?(mode: PermissionMode): boolean | Promise<boolean>;
40
+ /** Ctrl+V:粘贴剪贴板图片(W5-U)。 */
41
+ onPasteImage?(): void;
26
42
  submit(text: string, via: "followUp"): void;
27
43
  runCommand(line: string): void;
28
44
  exit(code: number): void;
45
+ /** Esc 中断之后(参数:中断后输入框是否为空)。 */
46
+ onInterrupted?(editorWasEmpty: boolean): void;
47
+ /** 双击 Esc 的间隔(测试注入)。 */
48
+ doubleEscMs?: number;
29
49
  }
30
50
  /** 返回输入监听器:已处理返回 true,交给编辑器返回 false。 */
31
51
  export declare function createKeyDispatch(deps: KeyDispatchDeps): (data: string) => boolean;