@armadra/agent 0.3.0 → 0.5.0

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 (527) hide show
  1. package/CHANGELOG.md +257 -0
  2. package/README.md +263 -95
  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/retry.d.ts +1 -1
  17. package/dist/agent/retry.js +2 -1
  18. package/dist/agent/session-cache.d.ts +5 -0
  19. package/dist/agent/session-cache.js +18 -2
  20. package/dist/agent/session-classifier.d.ts +18 -0
  21. package/dist/agent/session-classifier.js +105 -0
  22. package/dist/agent/session-compaction.d.ts +35 -6
  23. package/dist/agent/session-compaction.js +157 -31
  24. package/dist/agent/session-core.d.ts +40 -1
  25. package/dist/agent/session-extensions.d.ts +61 -0
  26. package/dist/agent/session-extensions.js +129 -0
  27. package/dist/agent/session-images.d.ts +23 -0
  28. package/dist/agent/session-images.js +97 -0
  29. package/dist/agent/session-plan.d.ts +21 -0
  30. package/dist/agent/session-plan.js +524 -0
  31. package/dist/agent/session-rewind.d.ts +81 -0
  32. package/dist/agent/session-rewind.js +354 -0
  33. package/dist/agent/session-run.d.ts +28 -1
  34. package/dist/agent/session-run.js +157 -6
  35. package/dist/agent/session-settings.d.ts +49 -0
  36. package/dist/agent/session-settings.js +95 -0
  37. package/dist/agent/session-subagent.d.ts +36 -24
  38. package/dist/agent/session-subagent.js +259 -129
  39. package/dist/agent/session-sync.d.ts +10 -3
  40. package/dist/agent/session-sync.js +37 -8
  41. package/dist/agent/session-telemetry.d.ts +39 -0
  42. package/dist/agent/session-telemetry.js +231 -0
  43. package/dist/agent/session-tools.js +63 -3
  44. package/dist/agent/session.d.ts +33 -29
  45. package/dist/agent/session.js +91 -126
  46. package/dist/agent/subagent-registry.d.ts +91 -0
  47. package/dist/agent/subagent-registry.js +494 -0
  48. package/dist/agent/system-prompt.d.ts +6 -3
  49. package/dist/agent/system-prompt.js +7 -2
  50. package/dist/agent/tool-runner.d.ts +8 -1
  51. package/dist/agent/tool-runner.js +72 -6
  52. package/dist/agent/types-w5.d.ts +192 -0
  53. package/dist/agent/types-w5.js +10 -0
  54. package/dist/agent/types.d.ts +55 -4
  55. package/dist/agent/types.js +2 -0
  56. package/dist/agent/worktree.d.ts +36 -0
  57. package/dist/agent/worktree.js +86 -0
  58. package/dist/agents/builtin.d.ts +14 -0
  59. package/dist/agents/builtin.js +39 -0
  60. package/dist/agents/catalog.d.ts +43 -0
  61. package/dist/agents/catalog.js +82 -0
  62. package/dist/agents/discover.d.ts +35 -0
  63. package/dist/agents/discover.js +83 -0
  64. package/dist/agents/external.d.ts +82 -0
  65. package/dist/agents/external.js +326 -0
  66. package/dist/agents/parse.d.ts +18 -0
  67. package/dist/agents/parse.js +116 -0
  68. package/dist/agents/result.d.ts +32 -0
  69. package/dist/agents/result.js +67 -0
  70. package/dist/agents/task-control.d.ts +17 -0
  71. package/dist/agents/task-control.js +17 -0
  72. package/dist/agents/task-record.d.ts +78 -0
  73. package/dist/agents/task-record.js +141 -0
  74. package/dist/agents/types.d.ts +46 -0
  75. package/dist/agents/types.js +8 -0
  76. package/dist/ai/apis/anthropic-compat.d.ts +36 -0
  77. package/dist/ai/apis/anthropic-compat.js +92 -0
  78. package/dist/ai/apis/anthropic-messages.js +3 -2
  79. package/dist/ai/apis/anthropic-request.d.ts +7 -6
  80. package/dist/ai/apis/anthropic-request.js +10 -28
  81. package/dist/ai/apis/cache-params.d.ts +11 -2
  82. package/dist/ai/apis/cache-params.js +25 -6
  83. package/dist/ai/apis/google-generative-ai.js +3 -2
  84. package/dist/ai/apis/openai-compat.d.ts +4 -1
  85. package/dist/ai/apis/openai-compat.js +8 -1
  86. package/dist/ai/apis/openai-completions.js +3 -2
  87. package/dist/ai/apis/openai-responses.js +3 -2
  88. package/dist/ai/http.d.ts +28 -6
  89. package/dist/ai/http.js +41 -8
  90. package/dist/ai/image-limits.d.ts +45 -0
  91. package/dist/ai/image-limits.js +68 -0
  92. package/dist/ai/providers/builtin.d.ts +18 -6
  93. package/dist/ai/providers/builtin.js +135 -6
  94. package/dist/ai/providers/catalog-data.js +17 -13
  95. package/dist/ai/providers/catalog.d.ts +60 -7
  96. package/dist/ai/providers/catalog.js +197 -38
  97. package/dist/ai/providers/channels.d.ts +33 -3
  98. package/dist/ai/providers/channels.js +108 -7
  99. package/dist/ai/providers/enrich.d.ts +6 -3
  100. package/dist/ai/providers/enrich.js +19 -4
  101. package/dist/ai/providers/models-dev-cache.d.ts +28 -24
  102. package/dist/ai/providers/models-dev-cache.js +92 -78
  103. package/dist/ai/providers/models-dev-data.d.ts +7 -0
  104. package/dist/ai/providers/models-dev-data.js +32 -0
  105. package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
  106. package/dist/ai/providers/models-dev-snapshot.js +137 -0
  107. package/dist/ai/providers/models-dev.d.ts +51 -10
  108. package/dist/ai/providers/models-dev.js +132 -39
  109. package/dist/ai/providers/registry.d.ts +28 -11
  110. package/dist/ai/providers/registry.js +112 -65
  111. package/dist/ai/providers/suggest.d.ts +18 -0
  112. package/dist/ai/providers/suggest.js +72 -0
  113. package/dist/ai/sse.d.ts +6 -2
  114. package/dist/ai/sse.js +22 -2
  115. package/dist/ai/types.d.ts +37 -4
  116. package/dist/ai/types.js +5 -0
  117. package/dist/bundle/ama.cjs +41979 -21147
  118. package/dist/checkpoints/backend.d.ts +61 -0
  119. package/dist/checkpoints/backend.js +135 -0
  120. package/dist/checkpoints/blobs.d.ts +60 -0
  121. package/dist/checkpoints/blobs.js +203 -0
  122. package/dist/checkpoints/gc.d.ts +47 -0
  123. package/dist/checkpoints/gc.js +144 -0
  124. package/dist/checkpoints/git-head.d.ts +15 -0
  125. package/dist/checkpoints/git-head.js +89 -0
  126. package/dist/checkpoints/index.d.ts +17 -0
  127. package/dist/checkpoints/index.js +17 -0
  128. package/dist/checkpoints/replay.d.ts +48 -0
  129. package/dist/checkpoints/replay.js +154 -0
  130. package/dist/checkpoints/restore.d.ts +86 -0
  131. package/dist/checkpoints/restore.js +263 -0
  132. package/dist/checkpoints/settings.d.ts +14 -0
  133. package/dist/checkpoints/settings.js +23 -0
  134. package/dist/checkpoints/shadow-git.d.ts +108 -0
  135. package/dist/checkpoints/shadow-git.js +491 -0
  136. package/dist/checkpoints/shadow-restore.d.ts +25 -0
  137. package/dist/checkpoints/shadow-restore.js +128 -0
  138. package/dist/checkpoints/tracker.d.ts +64 -0
  139. package/dist/checkpoints/tracker.js +192 -0
  140. package/dist/checkpoints/types.d.ts +99 -0
  141. package/dist/checkpoints/types.js +12 -0
  142. package/dist/cli/args.d.ts +26 -7
  143. package/dist/cli/args.js +75 -82
  144. package/dist/cli/bootstrap.js +40 -4
  145. package/dist/cli/codemode-notice.d.ts +21 -0
  146. package/dist/cli/codemode-notice.js +56 -0
  147. package/dist/cli/compose-agents.d.ts +27 -0
  148. package/dist/cli/compose-agents.js +111 -0
  149. package/dist/cli/compose-extensions.d.ts +29 -0
  150. package/dist/cli/compose-extensions.js +44 -0
  151. package/dist/cli/compose-session.d.ts +8 -0
  152. package/dist/cli/compose-session.js +76 -2
  153. package/dist/cli/compose-store.d.ts +1 -1
  154. package/dist/cli/compose-store.js +3 -1
  155. package/dist/cli/compose.d.ts +17 -4
  156. package/dist/cli/compose.js +60 -14
  157. package/dist/cli/default-model.d.ts +38 -1
  158. package/dist/cli/default-model.js +96 -9
  159. package/dist/cli/deps.d.ts +42 -0
  160. package/dist/cli/exit-codes.d.ts +12 -0
  161. package/dist/cli/exit-codes.js +15 -0
  162. package/dist/cli/fake-visibility.d.ts +13 -0
  163. package/dist/cli/fake-visibility.js +26 -0
  164. package/dist/cli/from-prompt.d.ts +18 -0
  165. package/dist/cli/from-prompt.js +49 -0
  166. package/dist/cli/help-text.d.ts +4 -0
  167. package/dist/cli/help-text.js +102 -0
  168. package/dist/cli/main.d.ts +9 -2
  169. package/dist/cli/main.js +77 -3
  170. package/dist/cli/proxy.d.ts +51 -0
  171. package/dist/cli/proxy.js +135 -0
  172. package/dist/cli/startup-screen.d.ts +29 -0
  173. package/dist/cli/startup-screen.js +51 -2
  174. package/dist/cli/startup-steps.d.ts +1 -1
  175. package/dist/cli/startup-steps.js +21 -13
  176. package/dist/cli/subcommands/config.d.ts +22 -3
  177. package/dist/cli/subcommands/config.js +119 -21
  178. package/dist/cli/subcommands/context.js +4 -1
  179. package/dist/cli/subcommands/doctor.js +33 -1
  180. package/dist/cli/subcommands/init.js +2 -1
  181. package/dist/cli/subcommands/models-discover.d.ts +15 -9
  182. package/dist/cli/subcommands/models-discover.js +58 -52
  183. package/dist/cli/subcommands/models.d.ts +2 -0
  184. package/dist/cli/subcommands/models.js +33 -14
  185. package/dist/cli/subcommands/probe-runner.d.ts +96 -0
  186. package/dist/cli/subcommands/probe-runner.js +264 -0
  187. package/dist/cli/subcommands/providers-probe.d.ts +34 -0
  188. package/dist/cli/subcommands/providers-probe.js +87 -0
  189. package/dist/cli/subcommands/providers.d.ts +3 -2
  190. package/dist/cli/subcommands/providers.js +53 -51
  191. package/dist/cli/subcommands/sessions-export.d.ts +10 -0
  192. package/dist/cli/subcommands/sessions-export.js +59 -0
  193. package/dist/cli/subcommands/sessions-search.d.ts +13 -0
  194. package/dist/cli/subcommands/sessions-search.js +103 -0
  195. package/dist/cli/subcommands/sessions.d.ts +6 -3
  196. package/dist/cli/subcommands/sessions.js +58 -3
  197. package/dist/cli/subcommands/stats.d.ts +17 -0
  198. package/dist/cli/subcommands/stats.js +198 -0
  199. package/dist/cli/system-prompt-arg.d.ts +11 -0
  200. package/dist/cli/system-prompt-arg.js +34 -0
  201. package/dist/codemode/capability.d.ts +24 -7
  202. package/dist/codemode/capability.js +38 -10
  203. package/dist/codemode/host-side.d.ts +14 -0
  204. package/dist/codemode/host-side.js +24 -1
  205. package/dist/codemode/modes.d.ts +4 -11
  206. package/dist/codemode/modes.js +5 -27
  207. package/dist/codemode/tool.d.ts +18 -14
  208. package/dist/codemode/tool.js +76 -31
  209. package/dist/compaction/breaker.d.ts +25 -9
  210. package/dist/compaction/breaker.js +47 -17
  211. package/dist/compaction/estimate.d.ts +11 -3
  212. package/dist/compaction/estimate.js +64 -22
  213. package/dist/compaction/image-budget.d.ts +45 -0
  214. package/dist/compaction/image-budget.js +115 -0
  215. package/dist/compaction/post-compact.d.ts +38 -0
  216. package/dist/compaction/post-compact.js +152 -0
  217. package/dist/compaction/protect.d.ts +27 -0
  218. package/dist/compaction/protect.js +56 -0
  219. package/dist/compaction/prune-tier.d.ts +58 -12
  220. package/dist/compaction/prune-tier.js +120 -54
  221. package/dist/compaction/summarize-tier.d.ts +23 -4
  222. package/dist/compaction/summarize-tier.js +100 -29
  223. package/dist/config/checker.d.ts +28 -0
  224. package/dist/config/checker.js +97 -0
  225. package/dist/config/init.d.ts +6 -2
  226. package/dist/config/init.js +12 -5
  227. package/dist/config/json-schema.d.ts +1 -0
  228. package/dist/config/json-schema.js +98 -4
  229. package/dist/config/key-docs.d.ts +22 -0
  230. package/dist/config/key-docs.js +174 -0
  231. package/dist/config/merge.d.ts +12 -9
  232. package/dist/config/merge.js +102 -13
  233. package/dist/config/profile.d.ts +2 -0
  234. package/dist/config/profile.js +2 -0
  235. package/dist/config/schema-w5.d.ts +18 -0
  236. package/dist/config/schema-w5.js +109 -0
  237. package/dist/config/schema.d.ts +5 -9
  238. package/dist/config/schema.js +91 -118
  239. package/dist/config/types-w5.d.ts +118 -0
  240. package/dist/config/types-w5.js +20 -0
  241. package/dist/config/types.d.ts +84 -7
  242. package/dist/config/types.js +29 -1
  243. package/dist/drivers/acp/client.d.ts +57 -0
  244. package/dist/drivers/acp/client.js +160 -0
  245. package/dist/drivers/acp/driver.d.ts +31 -0
  246. package/dist/drivers/acp/driver.js +274 -0
  247. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  248. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  249. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  250. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  251. package/dist/drivers/acp/types.d.ts +285 -0
  252. package/dist/drivers/acp/types.js +36 -0
  253. package/dist/drivers/agents.d.ts +58 -0
  254. package/dist/drivers/agents.js +142 -0
  255. package/dist/drivers/base.d.ts +35 -0
  256. package/dist/drivers/base.js +59 -0
  257. package/dist/drivers/catalog.d.ts +46 -0
  258. package/dist/drivers/catalog.js +167 -0
  259. package/dist/drivers/env.d.ts +20 -0
  260. package/dist/drivers/env.js +46 -0
  261. package/dist/drivers/host-runners.d.ts +18 -0
  262. package/dist/drivers/host-runners.js +45 -0
  263. package/dist/drivers/jsonrpc.d.ts +58 -0
  264. package/dist/drivers/jsonrpc.js +180 -0
  265. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  266. package/dist/drivers/native/claude-normalize.js +106 -0
  267. package/dist/drivers/native/claude-stream.d.ts +29 -0
  268. package/dist/drivers/native/claude-stream.js +456 -0
  269. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  270. package/dist/drivers/native/codex-app-server.js +407 -0
  271. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  272. package/dist/drivers/native/codex-normalize.js +124 -0
  273. package/dist/drivers/native/oneshot.d.ts +28 -0
  274. package/dist/drivers/native/oneshot.js +312 -0
  275. package/dist/drivers/permissions.d.ts +40 -0
  276. package/dist/drivers/permissions.js +92 -0
  277. package/dist/drivers/pids.d.ts +32 -0
  278. package/dist/drivers/pids.js +93 -0
  279. package/dist/drivers/pool.d.ts +28 -0
  280. package/dist/drivers/pool.js +96 -0
  281. package/dist/drivers/probe.d.ts +47 -0
  282. package/dist/drivers/probe.js +172 -0
  283. package/dist/drivers/process.d.ts +48 -0
  284. package/dist/drivers/process.js +100 -0
  285. package/dist/drivers/runner.d.ts +61 -0
  286. package/dist/drivers/runner.js +388 -0
  287. package/dist/drivers/store.d.ts +49 -0
  288. package/dist/drivers/store.js +91 -0
  289. package/dist/drivers/turn.d.ts +41 -0
  290. package/dist/drivers/turn.js +99 -0
  291. package/dist/drivers/types.d.ts +122 -0
  292. package/dist/drivers/types.js +11 -0
  293. package/dist/git/info.d.ts +75 -0
  294. package/dist/git/info.js +191 -0
  295. package/dist/hooks/protocol.js +6 -1
  296. package/dist/hooks/types.d.ts +10 -1
  297. package/dist/hooks/types.js +2 -0
  298. package/dist/host/api-impl.d.ts +7 -0
  299. package/dist/host/api-impl.js +15 -0
  300. package/dist/host/types.d.ts +24 -2
  301. package/dist/host/types.js +4 -0
  302. package/dist/index.d.ts +3 -0
  303. package/dist/index.js +1 -0
  304. package/dist/modes/acp/acp-events.d.ts +46 -0
  305. package/dist/modes/acp/acp-events.js +233 -0
  306. package/dist/modes/acp/acp-mode.d.ts +17 -0
  307. package/dist/modes/acp/acp-mode.js +47 -0
  308. package/dist/modes/acp/acp-server.d.ts +79 -0
  309. package/dist/modes/acp/acp-server.js +315 -0
  310. package/dist/modes/commands-core.d.ts +7 -1
  311. package/dist/modes/commands-core.js +61 -5
  312. package/dist/modes/image-input.d.ts +12 -4
  313. package/dist/modes/image-input.js +22 -5
  314. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  315. package/dist/modes/interactive/agent-panels.js +103 -0
  316. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  317. package/dist/modes/interactive/agent-ui.js +234 -0
  318. package/dist/modes/interactive/approval-dialog.d.ts +40 -7
  319. package/dist/modes/interactive/approval-dialog.js +192 -35
  320. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  321. package/dist/modes/interactive/approval-merge.js +89 -0
  322. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  323. package/dist/modes/interactive/clipboard-paste.js +28 -0
  324. package/dist/modes/interactive/commands.d.ts +20 -3
  325. package/dist/modes/interactive/commands.js +75 -16
  326. package/dist/modes/interactive/double-esc.d.ts +20 -0
  327. package/dist/modes/interactive/double-esc.js +34 -0
  328. package/dist/modes/interactive/event-notices.d.ts +32 -0
  329. package/dist/modes/interactive/event-notices.js +79 -0
  330. package/dist/modes/interactive/external-editor.d.ts +16 -0
  331. package/dist/modes/interactive/external-editor.js +39 -0
  332. package/dist/modes/interactive/interactive-mode.d.ts +16 -2
  333. package/dist/modes/interactive/interactive-mode.js +184 -202
  334. package/dist/modes/interactive/key-dispatch.d.ts +18 -2
  335. package/dist/modes/interactive/key-dispatch.js +53 -6
  336. package/dist/modes/interactive/line/line-mode.d.ts +3 -1
  337. package/dist/modes/interactive/line/line-mode.js +28 -9
  338. package/dist/modes/interactive/line/line-render.d.ts +6 -1
  339. package/dist/modes/interactive/line/line-render.js +66 -8
  340. package/dist/modes/interactive/message-view.d.ts +49 -10
  341. package/dist/modes/interactive/message-view.js +262 -46
  342. package/dist/modes/interactive/panels.d.ts +35 -0
  343. package/dist/modes/interactive/panels.js +157 -0
  344. package/dist/modes/interactive/pickers.d.ts +23 -2
  345. package/dist/modes/interactive/pickers.js +48 -15
  346. package/dist/modes/interactive/plan-command.d.ts +40 -0
  347. package/dist/modes/interactive/plan-command.js +129 -0
  348. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  349. package/dist/modes/interactive/plan-dialog.js +290 -0
  350. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  351. package/dist/modes/interactive/plan-flow.js +98 -0
  352. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  353. package/dist/modes/interactive/rewind-command.js +106 -0
  354. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  355. package/dist/modes/interactive/rewind-flow.js +151 -0
  356. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  357. package/dist/modes/interactive/rewind-list.js +123 -0
  358. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  359. package/dist/modes/interactive/rewind-panel.js +309 -0
  360. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  361. package/dist/modes/interactive/rewind-text.js +139 -0
  362. package/dist/modes/interactive/run-indicator.d.ts +51 -0
  363. package/dist/modes/interactive/run-indicator.js +189 -0
  364. package/dist/modes/interactive/session-events.d.ts +24 -0
  365. package/dist/modes/interactive/session-events.js +96 -0
  366. package/dist/modes/interactive/startup-header.d.ts +40 -0
  367. package/dist/modes/interactive/startup-header.js +169 -0
  368. package/dist/modes/interactive/status-area.d.ts +73 -0
  369. package/dist/modes/interactive/status-area.js +190 -0
  370. package/dist/modes/interactive/status-bar.d.ts +107 -16
  371. package/dist/modes/interactive/status-bar.js +306 -81
  372. package/dist/modes/interactive/status-line.d.ts +33 -0
  373. package/dist/modes/interactive/status-line.js +113 -0
  374. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  375. package/dist/modes/interactive/subagent-view.js +154 -0
  376. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  377. package/dist/modes/interactive/tasks-report.js +114 -0
  378. package/dist/modes/interactive/tool-summary.d.ts +46 -0
  379. package/dist/modes/interactive/tool-summary.js +218 -0
  380. package/dist/modes/interactive/tool-view.d.ts +58 -15
  381. package/dist/modes/interactive/tool-view.js +233 -145
  382. package/dist/modes/print/print-mode.d.ts +40 -4
  383. package/dist/modes/print/print-mode.js +161 -8
  384. package/dist/modes/rpc/commands.d.ts +9 -0
  385. package/dist/modes/rpc/commands.js +49 -0
  386. package/dist/modes/rpc/rpc-mode.js +7 -1
  387. package/dist/modes/session-report.d.ts +11 -0
  388. package/dist/modes/session-report.js +48 -1
  389. package/dist/permissions/auto-safe.d.ts +65 -0
  390. package/dist/permissions/auto-safe.js +547 -0
  391. package/dist/permissions/classifier.d.ts +68 -0
  392. package/dist/permissions/classifier.js +186 -0
  393. package/dist/permissions/dangerous.d.ts +5 -0
  394. package/dist/permissions/dangerous.js +1 -1
  395. package/dist/permissions/modes.d.ts +30 -0
  396. package/dist/permissions/modes.js +78 -0
  397. package/dist/permissions/pipeline.d.ts +72 -6
  398. package/dist/permissions/pipeline.js +306 -11
  399. package/dist/permissions/protected.d.ts +19 -0
  400. package/dist/permissions/protected.js +74 -0
  401. package/dist/permissions/readonly-bash.d.ts +30 -0
  402. package/dist/permissions/readonly-bash.js +118 -0
  403. package/dist/permissions/rules.js +3 -0
  404. package/dist/permissions/types.d.ts +92 -3
  405. package/dist/permissions/types.js +3 -0
  406. package/dist/plan/compose.d.ts +9 -0
  407. package/dist/plan/compose.js +19 -0
  408. package/dist/plan/controller.d.ts +71 -0
  409. package/dist/plan/controller.js +27 -0
  410. package/dist/plan/done-markers.d.ts +17 -0
  411. package/dist/plan/done-markers.js +51 -0
  412. package/dist/plan/extract.d.ts +29 -0
  413. package/dist/plan/extract.js +160 -0
  414. package/dist/plan/prompts.d.ts +36 -0
  415. package/dist/plan/prompts.js +89 -0
  416. package/dist/plan/store.d.ts +37 -0
  417. package/dist/plan/store.js +90 -0
  418. package/dist/rpc.d.ts +58 -2
  419. package/dist/rpc.js +7 -0
  420. package/dist/sandbox/bash.d.ts +74 -0
  421. package/dist/sandbox/bash.js +126 -0
  422. package/dist/sandbox/detect.d.ts +48 -0
  423. package/dist/sandbox/detect.js +149 -0
  424. package/dist/sandbox/index.d.ts +5 -0
  425. package/dist/sandbox/index.js +5 -0
  426. package/dist/sandbox/profile.d.ts +33 -0
  427. package/dist/sandbox/profile.js +76 -0
  428. package/dist/sandbox/wrap.d.ts +29 -0
  429. package/dist/sandbox/wrap.js +117 -0
  430. package/dist/sdk.d.ts +42 -5
  431. package/dist/sdk.js +34 -4
  432. package/dist/session/export.d.ts +32 -0
  433. package/dist/session/export.js +187 -0
  434. package/dist/session/redact.d.ts +15 -0
  435. package/dist/session/redact.js +55 -0
  436. package/dist/session/reuse.d.ts +33 -0
  437. package/dist/session/reuse.js +86 -0
  438. package/dist/session/scan.d.ts +34 -0
  439. package/dist/session/scan.js +140 -0
  440. package/dist/session/search.d.ts +52 -0
  441. package/dist/session/search.js +211 -0
  442. package/dist/session/stats-aggregate.d.ts +63 -0
  443. package/dist/session/stats-aggregate.js +163 -0
  444. package/dist/session/stats-index.d.ts +26 -0
  445. package/dist/session/stats-index.js +91 -0
  446. package/dist/session/stats-scan.d.ts +54 -0
  447. package/dist/session/stats-scan.js +236 -0
  448. package/dist/session/types.d.ts +3 -1
  449. package/dist/session/types.js +1 -0
  450. package/dist/skills/builtin.d.ts +31 -0
  451. package/dist/skills/builtin.js +109 -0
  452. package/dist/skills/discover.d.ts +2 -1
  453. package/dist/skills/index-prompt.js +5 -8
  454. package/dist/tools/background-jobs.d.ts +71 -0
  455. package/dist/tools/background-jobs.js +198 -0
  456. package/dist/tools/bash.d.ts +53 -1
  457. package/dist/tools/bash.js +158 -7
  458. package/dist/tools/clipboard-image.d.ts +44 -0
  459. package/dist/tools/clipboard-image.js +148 -0
  460. package/dist/tools/edit.d.ts +2 -0
  461. package/dist/tools/edit.js +18 -3
  462. package/dist/tools/image-file.d.ts +38 -3
  463. package/dist/tools/image-file.js +81 -10
  464. package/dist/tools/image-resize.d.ts +58 -0
  465. package/dist/tools/image-resize.js +97 -0
  466. package/dist/tools/presets.d.ts +40 -8
  467. package/dist/tools/presets.js +65 -19
  468. package/dist/tools/read.d.ts +5 -2
  469. package/dist/tools/read.js +13 -10
  470. package/dist/tools/registry.d.ts +7 -1
  471. package/dist/tools/registry.js +27 -4
  472. package/dist/tools/task-ctl.d.ts +22 -0
  473. package/dist/tools/task-ctl.js +116 -0
  474. package/dist/tools/task.d.ts +22 -10
  475. package/dist/tools/task.js +66 -26
  476. package/dist/tools/todo.d.ts +22 -2
  477. package/dist/tools/todo.js +58 -14
  478. package/dist/tools/truncate.d.ts +15 -0
  479. package/dist/tools/truncate.js +25 -0
  480. package/dist/tools/types.d.ts +113 -0
  481. package/dist/tools/types.js +5 -0
  482. package/dist/tools/write.js +3 -0
  483. package/dist/tui/component.d.ts +8 -2
  484. package/dist/tui/component.js +3 -1
  485. package/dist/tui/components/box.d.ts +6 -1
  486. package/dist/tui/components/box.js +16 -6
  487. package/dist/tui/components/card.d.ts +23 -0
  488. package/dist/tui/components/card.js +37 -0
  489. package/dist/tui/components/editor-history.d.ts +6 -0
  490. package/dist/tui/components/editor-history.js +45 -0
  491. package/dist/tui/components/editor-paste.d.ts +1 -1
  492. package/dist/tui/components/editor-paste.js +4 -4
  493. package/dist/tui/components/editor.d.ts +11 -5
  494. package/dist/tui/components/editor.js +52 -58
  495. package/dist/tui/components/key-value.d.ts +3 -0
  496. package/dist/tui/components/key-value.js +16 -6
  497. package/dist/tui/components/loader.d.ts +37 -7
  498. package/dist/tui/components/loader.js +84 -21
  499. package/dist/tui/components/markdown.d.ts +5 -1
  500. package/dist/tui/components/markdown.js +45 -21
  501. package/dist/tui/components/meter.d.ts +3 -3
  502. package/dist/tui/components/meter.js +13 -11
  503. package/dist/tui/components/select-list.d.ts +23 -1
  504. package/dist/tui/components/select-list.js +76 -13
  505. package/dist/tui/glyphs.d.ts +72 -0
  506. package/dist/tui/glyphs.js +118 -0
  507. package/dist/tui/keybindings.d.ts +5 -0
  508. package/dist/tui/keybindings.js +5 -0
  509. package/dist/tui/theme.d.ts +30 -6
  510. package/dist/tui/theme.js +103 -17
  511. package/dist/tui.d.ts +4 -2
  512. package/dist/tui.js +3 -1
  513. package/docs/acp.md +78 -0
  514. package/docs/agents.md +250 -0
  515. package/docs/codemode.md +28 -10
  516. package/docs/hooks.md +36 -32
  517. package/docs/permissions.md +212 -0
  518. package/docs/plan.md +107 -0
  519. package/docs/providers.md +261 -62
  520. package/docs/rewind-plan.md +181 -0
  521. package/docs/rpc.md +127 -40
  522. package/docs/sandbox.md +215 -0
  523. package/docs/session-format.md +43 -22
  524. package/docs/sessions.md +174 -0
  525. package/docs/tui-design.md +751 -0
  526. package/docs/tui.md +260 -64
  527. package/package.json +15 -2
@@ -11,30 +11,41 @@
11
11
  * - 晚绑定:`runtime.approvals.setUiBroker`(审批对话框)与 `runtime.notifier.set`(宿主通知进消息区),
12
12
  * 退出时撤下。
13
13
  * - 键位:Enter 发送(运行中 = steer),其余应用级键位见 `key-dispatch.ts`。
14
- * - 启动画面按 `ui.quietStartup`:normal 标题 + 模型 / 信任 / 资源清单,header 只有标题,silent 不输出。
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 提示。
19
+ * - 启动头按 `ui.quietStartup`(startup-header.ts):normal 框 + 模型 / 目录 / 模式 / 资源清单(窄屏或
20
+ * `ui.compact` 去框),header 一行,silent 不输出。
15
21
  */
16
22
  import { promptImages, sessionModel } from "../image-input.js";
17
23
  import { join } from "node:path";
18
24
  import { AgentSessionImpl } from "../../agent/session.js";
25
+ import { taskRegistryView } from "../../agent/subagent-registry.js";
19
26
  import { currentSession, switchSession } from "../../cli/compose-session.js";
20
- import { buildStartupScreen } from "../../cli/startup-screen.js";
27
+ import { startupInfo, startupScreenLevel, tildePath } from "../../cli/startup-screen.js";
21
28
  import { KEYBINDINGS_FILE } from "../../config/paths.js";
22
29
  import { AmaError, isAmaError } from "../../errors.js";
23
- import { detectSandboxCapability } from "../../codemode/capability.js";
24
- import { effectiveCodemodeMode } from "../../tools/presets.js";
25
- import { Container, Editor, Keybindings, Loader, ProcessTerminal, Spacer, TUI, Text, createTheme, detectCapabilities, loadKeybindingsFile, truncateToWidth, } from "../../tui.js";
26
- 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";
27
31
  import { onTerminationSignals } from "../shared.js";
32
+ import { AgentUi } from "./agent-ui.js";
28
33
  import { ApprovalDialogBroker, approvalOutcomeText } from "./approval-dialog.js";
34
+ import { mergingBroker } from "./approval-merge.js";
29
35
  import { ALL_COMMANDS, runInteractiveCommand } from "./commands.js";
30
36
  import { InteractiveCompletion } from "./completion.js";
31
37
  import { createKeyDispatch } from "./key-dispatch.js";
32
- import { MessageView } from "./message-view.js";
38
+ import { MessageView, exitSummaryLines } from "./message-view.js";
33
39
  import { openPicker } from "./pickers.js";
34
- import { StatusBar } from "./status-bar.js";
40
+ import { createRewindFlow } from "./rewind-flow.js";
41
+ import { StartupHeader } from "./startup-header.js";
42
+ import { QueueView, RunIndicator } from "./run-indicator.js";
43
+ import { StatusArea, statusLineSlash } from "./status-area.js";
44
+ import { createSessionEventHandler } from "./session-events.js";
45
+ import { SubagentTracker } from "./subagent-view.js";
35
46
  import { ToolTracker } from "./tool-view.js";
36
47
  const HINT_MS = 2500;
37
- const QUEUE_PREVIEW = 3;
48
+ const EDITOR_PLACEHOLDER = "输入消息,/ 命令,@ 文件,Shift+Enter 换行";
38
49
  function processTerminal() {
39
50
  const stdin = process.stdin;
40
51
  if (stdin.isTTY !== true || typeof stdin.setRawMode !== "function" || !process.stdout.isTTY) {
@@ -48,28 +59,17 @@ function loadKeys(runtime, warn) {
48
59
  warn(`keybindings.json:${w}`);
49
60
  return new Keybindings(parsed.overrides);
50
61
  }
51
- /** 一行提示;空时不占行。 */
52
- class HintLine {
53
- text = "";
54
- setText(text) {
55
- this.text = text;
56
- }
57
- render(width) {
58
- return this.text === "" ? [] : [truncateToWidth(this.text, width)];
59
- }
60
- invalidate() { }
61
- }
62
- function oneLine(text) {
63
- return text.replace(/\s+/g, " ").trim();
64
- }
65
62
  export function runInteractiveMode(runtime, context, options = {}) {
66
63
  const terminal = options.terminal ?? processTerminal();
67
64
  const ui = runtime.config.ui ?? {};
65
+ const env = context.io.env;
68
66
  const theme = options.theme ??
69
- createTheme(ui.theme ?? "dark", {
70
- caps: detectCapabilities(context.io.env, context.io.stdoutIsTTY),
67
+ createTheme(resolveThemeName(ui.theme, env), {
68
+ caps: detectCapabilities(env, context.io.stdoutIsTTY),
69
+ ascii: resolveAscii(ui.ascii, env),
71
70
  });
72
71
  const now = options.now ?? Date.now;
72
+ const startedAt = now();
73
73
  const startupWarnings = [];
74
74
  const keys = options.keybindings ?? loadKeys(runtime, (m) => startupWarnings.push(m));
75
75
  let session = currentSession(runtime);
@@ -78,33 +78,38 @@ export function runInteractiveMode(runtime, context, options = {}) {
78
78
  theme,
79
79
  ...(ui.showThinking !== undefined ? { showThinking: ui.showThinking } : {}),
80
80
  ...(ui.markdown !== undefined ? { markdown: ui.markdown } : {}),
81
+ ...(ui.compact === true ? { compact: true } : {}),
81
82
  });
83
+ const subagents = new SubagentTracker(now);
82
84
  const tools = new ToolTracker({
83
85
  theme,
84
86
  cwd: session.state.cwd,
85
87
  getTool: (name) => session.getTools().find((tool) => tool.name === name),
88
+ now,
89
+ spinner: () => loader.frame,
90
+ subagent: (toolCallId) => subagents.forToolCall(toolCallId),
86
91
  });
87
- const queueText = new Text("");
92
+ const queueView = new QueueView(theme);
88
93
  const loaderSlot = new Container();
89
94
  const loader = new Loader(() => tui.requestRender(), {
90
95
  theme,
91
- message: "工作中" + theme.fg("dim", " · Esc 中断"),
96
+ message: "思考中",
92
97
  now,
98
+ ...(ui.animation === false ? { animation: false } : {}),
93
99
  ...(options.spinnerIntervalMs !== undefined ? { intervalMs: options.spinnerIntervalMs } : {}),
94
100
  });
95
- const hint = new HintLine();
96
- let sandboxStrict;
97
- const status = new StatusBar({
101
+ loader.onFrame(() => tools.tick());
102
+ const area = new StatusArea({
103
+ runtime,
104
+ theme,
98
105
  session: () => session,
99
- preset: () => runtime.config.tools?.preset ?? "default",
100
- hostStatus: () => runtime.host?.status(),
101
- codemode: () => {
102
- const mode = effectiveCodemodeMode(runtime.config);
103
- const active = session.getTools().some((tool) => tool.name === "codemode");
104
- return mode === "off" || !active ? undefined : mode;
105
- },
106
- sandboxStrict: () => (sandboxStrict ??= detectSandboxCapability().strict),
107
- }, theme);
106
+ now,
107
+ render: () => tui.requestRender(),
108
+ redraw: () => tui.forceFullRedraw(),
109
+ env,
110
+ ...(options.statusLine !== undefined ? { layout: options.statusLine } : {}),
111
+ });
112
+ const { hint, bar: status } = area;
108
113
  const historyFile = options.historyFile === false
109
114
  ? undefined
110
115
  : (options.historyFile ?? join(runtime.paths.dataDir, "history"));
@@ -119,6 +124,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
119
124
  theme,
120
125
  keybindings: keys,
121
126
  maxVisibleLines: 8,
127
+ placeholder: EDITOR_PLACEHOLDER,
122
128
  autocomplete: completion,
123
129
  requestRender: () => tui.requestRender(),
124
130
  ...(historyFile !== undefined ? { historyFile } : {}),
@@ -126,15 +132,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
126
132
  });
127
133
  tui.addChild(view);
128
134
  tui.addChild(new Spacer());
129
- tui.addChild(queueText);
135
+ tui.addChild(queueView);
130
136
  tui.addChild(loaderSlot);
131
137
  tui.addChild(editor);
132
138
  tui.addChild(hint);
139
+ tui.addChild(area.rate);
133
140
  tui.addChild(status);
134
141
  // ---- 小工具 ---------------------------------------------------------------
135
142
  let finished = false;
136
- let running = false;
137
- let compacting = false;
138
143
  let hintTimer;
139
144
  let resolveExit = () => undefined;
140
145
  const render = () => tui.requestRender();
@@ -142,7 +147,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
142
147
  view.addNotice(level, text);
143
148
  render();
144
149
  };
145
- const showHint = (text) => {
150
+ const showHint = (text, ms = HINT_MS) => {
146
151
  hint.setText(text === "" ? "" : theme.fg("dim", text));
147
152
  if (hintTimer !== undefined)
148
153
  clearTimeout(hintTimer);
@@ -151,144 +156,40 @@ export function runInteractiveMode(runtime, context, options = {}) {
151
156
  hintTimer = setTimeout(() => {
152
157
  hint.setText("");
153
158
  render();
154
- }, HINT_MS);
159
+ }, ms);
155
160
  hintTimer.unref?.();
156
161
  }
157
162
  render();
158
163
  };
159
- const syncLoader = () => {
160
- const active = running || compacting;
161
- if (active && loaderSlot.children.length === 0) {
162
- loader.setMessage((compacting && !running ? "压缩上下文" : "工作中") + theme.fg("dim", " · Esc 中断"));
163
- loaderSlot.addChild(loader);
164
- loader.start();
165
- }
166
- else if (!active && loaderSlot.children.length > 0) {
167
- loader.stop();
168
- loaderSlot.clear();
169
- }
170
- render();
171
- };
164
+ const indicator = new RunIndicator({ theme, loader, slot: loaderSlot, tools, render });
172
165
  const setQueue = (steering, followUp) => {
173
166
  status.setQueue(steering.length, followUp.length);
174
- const rows = [
175
- ...steering.map((t) => `↳ steer ${oneLine(t)}`),
176
- ...followUp.map((t) => `↳ followUp ${oneLine(t)}`),
177
- ];
178
- const shown = rows.slice(-QUEUE_PREVIEW);
179
- if (rows.length > shown.length)
180
- shown.unshift(`… 另 ${rows.length - shown.length} 条`);
181
- if (rows.length > 0)
182
- shown.push("Alt+↑ 取回 · Esc 全部回填并中断");
183
- queueText.setText(shown.map((l) => theme.fg("dim", l)).join("\n"));
167
+ queueView.setQueue(steering, followUp);
184
168
  render();
185
169
  };
186
170
  // ---- 会话事件 -------------------------------------------------------------
187
- const onEvent = (event) => {
188
- switch (event.type) {
189
- case "agent_start":
190
- running = true;
191
- syncLoader();
192
- return;
193
- case "agent_settled":
194
- running = false;
195
- if (event.warning !== undefined)
196
- view.addNotice("warn", event.warning);
197
- status.refresh();
198
- syncLoader();
199
- return;
200
- case "message_start": {
201
- const message = event.message;
202
- if (message.role === "user")
203
- view.addUser(message);
204
- else if (message.role === "assistant")
205
- view.startAssistant(message);
206
- else if (message.role === "custom" && message.display) {
207
- view.addNotice("info", typeof message.content === "string" ? message.content : "");
208
- }
209
- render();
210
- return;
211
- }
212
- case "message_update":
213
- view.updateAssistant(event.message);
214
- render();
215
- return;
216
- case "message_end":
217
- if (event.message.role === "assistant") {
218
- view.endAssistant(event.message);
219
- status.refresh();
220
- }
221
- render();
222
- return;
223
- case "tool_execution_start": {
224
- const started = tools.start(event);
225
- if (started.topLevel)
226
- view.add(started.view);
227
- render();
228
- return;
229
- }
230
- case "tool_execution_update":
231
- tools.update(event.toolCallId, event.partial);
232
- render();
233
- return;
234
- case "tool_execution_end":
235
- tools.end(event.toolCallId, event.result, event.isError);
236
- render();
237
- return;
238
- case "queue_update":
239
- setQueue(event.steering, event.followUp);
240
- return;
241
- case "compaction_start":
242
- compacting = true;
243
- syncLoader();
244
- return;
245
- case "compaction_end":
246
- compacting = false;
247
- if (event.result !== undefined)
248
- view.addCompaction(event.result);
249
- else if (event.error !== undefined)
250
- view.addNotice("error", `压缩失败:${event.error}`);
251
- else if (event.aborted)
252
- view.addNotice("info", "压缩已取消");
253
- status.refresh();
254
- syncLoader();
255
- return;
256
- case "auto_retry_start":
257
- view.addRetry(event.attempt, event.maxAttempts, event.delayMs, event.errorMessage);
258
- render();
259
- return;
260
- case "auto_retry_end":
261
- if (!event.success)
262
- view.addRetryFailed(event.finalError);
263
- render();
264
- return;
265
- case "cache_miss":
266
- case "context_pressure": {
267
- const shown = cacheEventNotice(event, cacheNoticesEnabled(session));
268
- if (shown !== undefined)
269
- view.addNotice(shown.level, shown.text);
270
- status.refresh();
271
- render();
272
- return;
273
- }
274
- case "cache_warm":
275
- case "permission_mode_changed":
276
- case "model_changed":
277
- case "thinking_level_changed":
278
- case "session_changed":
279
- status.refresh();
280
- render();
281
- return;
282
- default:
283
- return;
284
- }
285
- };
171
+ const onEvent = createSessionEventHandler({
172
+ view,
173
+ tools,
174
+ status,
175
+ area,
176
+ agentUi: () => agentUi,
177
+ indicator,
178
+ session: () => session,
179
+ setQueue,
180
+ notice,
181
+ render,
182
+ });
286
183
  let unsubscribe = session.subscribe(onEvent);
287
- const startup = buildStartupScreen(runtime);
288
- /** 清空消息区(切换会话、/tree):只留标题行。 */
184
+ const startupLevel = startupScreenLevel(runtime);
185
+ const home = env["HOME"] ?? env["USERPROFILE"];
186
+ const info = startupInfo(runtime, home);
187
+ const header = (level) => new StartupHeader(info, { theme, level, ...(ui.compact === true ? { compact: true } : {}) });
188
+ /** 清空消息区(切换会话、/tree):只留一行头。 */
289
189
  const resetView = () => {
290
190
  view.reset();
291
- view.addHeader(startup.slice(0, 1));
191
+ if (startupLevel !== "silent")
192
+ view.add(header("header"));
292
193
  };
293
194
  const replay = () => {
294
195
  view.replay(session.messages, {
@@ -308,11 +209,10 @@ export function runInteractiveMode(runtime, context, options = {}) {
308
209
  resetView();
309
210
  tools.clear();
310
211
  replay();
311
- running = false;
312
- compacting = false;
313
212
  setQueue([], []);
314
- status.refresh();
315
- syncLoader();
213
+ area.rebind();
214
+ agentUi.attach(next);
215
+ indicator.reset();
316
216
  if (next instanceof AgentSessionImpl)
317
217
  next.announceStart(reason);
318
218
  };
@@ -321,12 +221,20 @@ export function runInteractiveMode(runtime, context, options = {}) {
321
221
  * 空闲时发提示。agent_settled 之后会话周期还要一个微任务才结束,所以先 waitForIdle;
322
222
  * 仍然撞上运行中(极少)就排到本轮之后。
323
223
  */
224
+ let draftImages = [];
225
+ const resize = runtime.config.images?.resize;
226
+ const imageResize = resize !== undefined ? { resize } : {};
324
227
  const startPrompt = (text) => {
325
228
  const target = session;
229
+ const carried = draftImages;
230
+ draftImages = [];
326
231
  void target
327
232
  .waitForIdle()
328
233
  .then(async () => {
329
- const images = await promptImages(text, [], target.state.cwd, sessionModel(runtime.providers, target));
234
+ const images = [
235
+ ...carried,
236
+ ...(await promptImages(text, [], target.state.cwd, sessionModel(runtime.providers, target), imageResize)),
237
+ ];
330
238
  return target.prompt(text, images.length > 0 ? { images } : {});
331
239
  })
332
240
  .catch((error) => {
@@ -341,6 +249,38 @@ export function runInteractiveMode(runtime, context, options = {}) {
341
249
  render();
342
250
  });
343
251
  };
252
+ /** 对话换了路径(/tree、回滚):重画消息区。内容可能缩到视口顶以上,差分画不对,整屏重画。 */
253
+ const reloadView = () => {
254
+ resetView();
255
+ tools.clear();
256
+ replay();
257
+ status.refresh();
258
+ area.refreshGit();
259
+ tui.forceFullRedraw();
260
+ };
261
+ const setDraft = (draft) => {
262
+ editor.setText(draft.text);
263
+ draftImages = [...(draft.images ?? [])];
264
+ render();
265
+ };
266
+ const pickerHost = {
267
+ theme,
268
+ keybindings: keys,
269
+ showOverlay: (c, o) => tui.showOverlay(c, o),
270
+ columns: () => terminal.columns,
271
+ rows: () => terminal.rows,
272
+ };
273
+ const rewind = createRewindFlow({
274
+ ...pickerHost,
275
+ session: () => session,
276
+ now,
277
+ render,
278
+ notice,
279
+ hint: (text) => showHint(text),
280
+ reload: reloadView,
281
+ setDraft,
282
+ editorEmpty: () => editor.isEmpty(),
283
+ });
344
284
  const commandUi = {
345
285
  runtime,
346
286
  session: () => session,
@@ -349,29 +289,30 @@ export function runInteractiveMode(runtime, context, options = {}) {
349
289
  rebind(next, request.kind === "new" ? "new" : request.kind === "fork" ? "fork" : "resume");
350
290
  return next;
351
291
  },
352
- pick: (spec) => openPicker({
353
- theme,
354
- keybindings: keys,
355
- showOverlay: (c, o) => tui.showOverlay(c, o),
356
- columns: () => terminal.columns,
357
- }, spec),
292
+ pick: (spec) => openPicker(pickerHost, spec),
293
+ rewind: () => rewind.open(),
294
+ setDraft,
358
295
  notice,
296
+ panel: (component) => {
297
+ view.add(component);
298
+ render();
299
+ },
300
+ theme: () => theme,
301
+ env,
302
+ ...(home !== undefined ? { home } : {}),
359
303
  setEditorText: (text) => {
360
304
  editor.setText(text);
361
305
  render();
362
306
  },
363
307
  prompt: (text) => startPrompt(text),
364
- reload: () => {
365
- resetView();
366
- tools.clear();
367
- replay();
368
- status.refresh();
369
- render();
370
- },
308
+ reload: reloadView,
371
309
  exit: (code) => exit(code),
372
310
  now,
311
+ extra: (name, args) => agentUi.command(name, args),
373
312
  };
374
- const runCommand = (line) => runInteractiveCommand(line, commandUi).finally(() => {
313
+ const runCommand = (line) => (statusLineSlash(area, line, notice)
314
+ ? Promise.resolve(true)
315
+ : runInteractiveCommand(line, commandUi)).finally(() => {
375
316
  status.refresh();
376
317
  render();
377
318
  });
@@ -388,7 +329,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
388
329
  send(text, via);
389
330
  }
390
331
  function send(text, via) {
391
- if (!running)
332
+ if (!indicator.running)
392
333
  startPrompt(text);
393
334
  else if (via === "followUp")
394
335
  void session.followUp(text).catch(() => undefined);
@@ -403,34 +344,68 @@ export function runInteractiveMode(runtime, context, options = {}) {
403
344
  status,
404
345
  session: () => session,
405
346
  inactive: () => finished || tui.hasOverlay,
406
- busy: () => running || compacting,
347
+ busy: () => indicator.busy,
407
348
  now,
408
349
  showHint,
350
+ onExpandToggle: (expanded) => view.setThinkingExpanded(expanded),
351
+ onStatusLineToggle: () => area.toggle(),
352
+ onPasteImage: () => void agentUi.paste(),
409
353
  submit: (text, via) => submit(text, via),
410
354
  runCommand: (line) => void runCommand(line),
411
355
  exit: (code) => exit(code),
356
+ onInterrupted: (empty) => void rewind.afterInterrupt(empty),
412
357
  }));
413
358
  // ---- 晚绑定 ---------------------------------------------------------------
414
- const broker = new ApprovalDialogBroker({
415
- theme,
416
- keybindings: keys,
417
- cwd: session.state.cwd,
418
- permissionMode: () => session.state.permissionMode,
359
+ const overlayHooks = {
419
360
  showOverlay: (component) => tui.showOverlay(component, { anchor: "bottom" }),
420
361
  onOpen: () => {
421
362
  editor.disableSubmit = true;
422
- render();
363
+ tools.setAwaiting(true);
364
+ indicator.setApproval(true);
423
365
  },
424
366
  onClose: () => {
425
367
  editor.disableSubmit = false;
426
- render();
368
+ tools.setAwaiting(false);
369
+ indicator.setApproval(false);
427
370
  },
371
+ };
372
+ const agentUi = new AgentUi({
373
+ theme,
374
+ tui,
375
+ editor,
376
+ tools: () => tools,
377
+ subagents,
378
+ session: () => session,
379
+ dataDir: runtime.paths.dataDir,
380
+ env,
381
+ now,
382
+ notice,
383
+ panel: (component) => commandUi.panel?.(component),
384
+ pick: (spec) => openPicker(pickerHost, spec),
385
+ hint: (text) => showHint(text),
386
+ render,
387
+ switchSession: (request) => commandUi.switchSession(request),
388
+ prompt: (text) => startPrompt(text),
389
+ dialog: { theme, keybindings: keys, ...overlayHooks },
390
+ displayPath: (path) => tildePath(path, home),
391
+ ...(options.clipboard !== undefined ? { clipboard: options.clipboard } : {}),
392
+ });
393
+ const taskAgent = (taskId) => taskRegistryView(session.state.sessionId)?.get(taskId)?.agent;
394
+ const broker = mergingBroker(new ApprovalDialogBroker({
395
+ theme,
396
+ keybindings: keys,
397
+ cwd: session.state.cwd,
398
+ permissionMode: () => session.state.permissionMode,
399
+ taskAgent,
400
+ externalRunner: (agent) => agentUi.merge.externalRunner(agent),
401
+ ...overlayHooks,
428
402
  report: (request, outcome) => {
429
403
  if (outcome === "deny" || outcome === "cancelled") {
430
- notice(outcome === "deny" ? "info" : "warn", approvalOutcomeText(request, outcome));
404
+ const text = approvalOutcomeText(request, outcome, taskAgent);
405
+ notice(outcome === "deny" ? "info" : "warn", text);
431
406
  }
432
407
  },
433
- });
408
+ }), agentUi.merge, (request) => notice("info", `${approvalOutcomeText(request, "allow", taskAgent)}(随上一次确认)`));
434
409
  // ---- 启动与退出 -----------------------------------------------------------
435
410
  let offSignals = () => undefined;
436
411
  function exit(code) {
@@ -439,10 +414,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
439
414
  finished = true;
440
415
  if (hintTimer !== undefined)
441
416
  clearTimeout(hintTimer);
442
- hint.setText("");
443
417
  loader.stop();
444
- loaderSlot.clear();
418
+ area.dispose();
419
+ // 退出摘要留在回滚里;输入框、状态栏等底部区域撤掉,屏幕停在摘要下面
420
+ view.addExitSummary(exitSummaryLines(session.getStats(), now() - startedAt, theme));
421
+ tui.clear();
422
+ tui.addChild(view);
445
423
  offSignals();
424
+ agentUi.detach();
446
425
  runtime.approvals.setUiBroker(undefined);
447
426
  runtime.notifier.set(undefined);
448
427
  tui.stop();
@@ -455,7 +434,8 @@ export function runInteractiveMode(runtime, context, options = {}) {
455
434
  resolveExit(code);
456
435
  });
457
436
  }
458
- view.addHeader(startup);
437
+ if (startupLevel !== "silent")
438
+ view.add(header(startupLevel));
459
439
  for (const warning of startupWarnings)
460
440
  view.addNotice("warn", warning);
461
441
  replay();
@@ -472,6 +452,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
472
452
  }
473
453
  runtime.approvals.setUiBroker(broker);
474
454
  runtime.notifier.set((message, level) => notice(level, message));
455
+ agentUi.attach(session);
475
456
  offSignals = onTerminationSignals((code) => exit(code));
476
457
  tui.setFocus(editor);
477
458
  options.onReady?.({
@@ -480,6 +461,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
480
461
  view,
481
462
  tools,
482
463
  status,
464
+ area,
483
465
  session: () => session,
484
466
  exit,
485
467
  });
@@ -3,7 +3,12 @@
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";
9
14
  import type { Editor, Keybindings } from "../../tui.js";
@@ -20,10 +25,21 @@ export interface KeyDispatchDeps {
20
25
  /** 运行或压缩中(Esc 才中断)。 */
21
26
  busy(): boolean;
22
27
  now(): number;
23
- showHint(text: string): void;
28
+ /** 底部提示;`ms` 是停留时间(缺省由调用方决定)。 */
29
+ showHint(text: string, ms?: number): void;
30
+ /** Ctrl+O 之后(消息区思考块跟着展开 / 折叠)。 */
31
+ onExpandToggle?(expanded: boolean): void;
32
+ /** Ctrl+G:切换底部信息行,返回切换后的布局。 */
33
+ onStatusLineToggle?(): "full" | "compact";
34
+ /** Ctrl+V:粘贴剪贴板图片(W5-U)。 */
35
+ onPasteImage?(): void;
24
36
  submit(text: string, via: "followUp"): void;
25
37
  runCommand(line: string): void;
26
38
  exit(code: number): void;
39
+ /** Esc 中断之后(参数:中断后输入框是否为空)。 */
40
+ onInterrupted?(editorWasEmpty: boolean): void;
41
+ /** 双击 Esc 的间隔(测试注入)。 */
42
+ doubleEscMs?: number;
27
43
  }
28
44
  /** 返回输入监听器:已处理返回 true,交给编辑器返回 false。 */
29
45
  export declare function createKeyDispatch(deps: KeyDispatchDeps): (data: string) => boolean;