@armadra/agent 0.4.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 (422) hide show
  1. package/CHANGELOG.md +174 -1
  2. package/README.md +201 -82
  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 +36203 -20499
  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/codemode-notice.d.ts +3 -2
  134. package/dist/cli/codemode-notice.js +3 -2
  135. package/dist/cli/compose-agents.d.ts +27 -0
  136. package/dist/cli/compose-agents.js +111 -0
  137. package/dist/cli/compose-extensions.d.ts +29 -0
  138. package/dist/cli/compose-extensions.js +44 -0
  139. package/dist/cli/compose-session.d.ts +3 -0
  140. package/dist/cli/compose-session.js +47 -4
  141. package/dist/cli/compose.d.ts +3 -0
  142. package/dist/cli/compose.js +33 -6
  143. package/dist/cli/deps.d.ts +6 -0
  144. package/dist/cli/exit-codes.d.ts +10 -0
  145. package/dist/cli/exit-codes.js +12 -0
  146. package/dist/cli/help-text.d.ts +4 -0
  147. package/dist/cli/help-text.js +102 -0
  148. package/dist/cli/startup-screen.js +5 -3
  149. package/dist/cli/startup-steps.js +7 -1
  150. package/dist/cli/subcommands/config.d.ts +4 -1
  151. package/dist/cli/subcommands/config.js +17 -6
  152. package/dist/cli/subcommands/doctor.js +21 -0
  153. package/dist/cli/subcommands/models-discover.js +5 -6
  154. package/dist/cli/subcommands/models.d.ts +2 -0
  155. package/dist/cli/subcommands/models.js +33 -14
  156. package/dist/cli/subcommands/providers.js +5 -6
  157. package/dist/cli/subcommands/sessions.d.ts +3 -1
  158. package/dist/cli/subcommands/sessions.js +36 -2
  159. package/dist/codemode/capability.d.ts +24 -7
  160. package/dist/codemode/capability.js +38 -10
  161. package/dist/codemode/host-side.d.ts +14 -0
  162. package/dist/codemode/host-side.js +24 -1
  163. package/dist/codemode/tool.d.ts +1 -1
  164. package/dist/codemode/tool.js +6 -4
  165. package/dist/compaction/breaker.d.ts +25 -9
  166. package/dist/compaction/breaker.js +47 -17
  167. package/dist/compaction/estimate.d.ts +11 -3
  168. package/dist/compaction/estimate.js +64 -22
  169. package/dist/compaction/image-budget.d.ts +45 -0
  170. package/dist/compaction/image-budget.js +115 -0
  171. package/dist/compaction/post-compact.d.ts +38 -0
  172. package/dist/compaction/post-compact.js +152 -0
  173. package/dist/compaction/protect.d.ts +27 -0
  174. package/dist/compaction/protect.js +56 -0
  175. package/dist/compaction/prune-tier.d.ts +58 -12
  176. package/dist/compaction/prune-tier.js +120 -54
  177. package/dist/compaction/summarize-tier.d.ts +23 -4
  178. package/dist/compaction/summarize-tier.js +100 -29
  179. package/dist/config/checker.d.ts +28 -0
  180. package/dist/config/checker.js +97 -0
  181. package/dist/config/json-schema.js +63 -2
  182. package/dist/config/key-docs.js +72 -3
  183. package/dist/config/merge.d.ts +5 -3
  184. package/dist/config/merge.js +81 -7
  185. package/dist/config/profile.d.ts +2 -0
  186. package/dist/config/profile.js +2 -0
  187. package/dist/config/schema-w5.d.ts +18 -0
  188. package/dist/config/schema-w5.js +109 -0
  189. package/dist/config/schema.d.ts +5 -9
  190. package/dist/config/schema.js +68 -114
  191. package/dist/config/types-w5.d.ts +118 -0
  192. package/dist/config/types-w5.js +20 -0
  193. package/dist/config/types.d.ts +50 -1
  194. package/dist/config/types.js +12 -0
  195. package/dist/drivers/acp/client.d.ts +57 -0
  196. package/dist/drivers/acp/client.js +160 -0
  197. package/dist/drivers/acp/driver.d.ts +31 -0
  198. package/dist/drivers/acp/driver.js +274 -0
  199. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  200. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  201. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  202. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  203. package/dist/drivers/acp/types.d.ts +285 -0
  204. package/dist/drivers/acp/types.js +36 -0
  205. package/dist/drivers/agents.d.ts +58 -0
  206. package/dist/drivers/agents.js +142 -0
  207. package/dist/drivers/base.d.ts +35 -0
  208. package/dist/drivers/base.js +59 -0
  209. package/dist/drivers/catalog.d.ts +46 -0
  210. package/dist/drivers/catalog.js +167 -0
  211. package/dist/drivers/env.d.ts +20 -0
  212. package/dist/drivers/env.js +46 -0
  213. package/dist/drivers/host-runners.d.ts +18 -0
  214. package/dist/drivers/host-runners.js +45 -0
  215. package/dist/drivers/jsonrpc.d.ts +58 -0
  216. package/dist/drivers/jsonrpc.js +180 -0
  217. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  218. package/dist/drivers/native/claude-normalize.js +106 -0
  219. package/dist/drivers/native/claude-stream.d.ts +29 -0
  220. package/dist/drivers/native/claude-stream.js +456 -0
  221. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  222. package/dist/drivers/native/codex-app-server.js +407 -0
  223. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  224. package/dist/drivers/native/codex-normalize.js +124 -0
  225. package/dist/drivers/native/oneshot.d.ts +28 -0
  226. package/dist/drivers/native/oneshot.js +312 -0
  227. package/dist/drivers/permissions.d.ts +40 -0
  228. package/dist/drivers/permissions.js +92 -0
  229. package/dist/drivers/pids.d.ts +32 -0
  230. package/dist/drivers/pids.js +93 -0
  231. package/dist/drivers/pool.d.ts +28 -0
  232. package/dist/drivers/pool.js +96 -0
  233. package/dist/drivers/probe.d.ts +47 -0
  234. package/dist/drivers/probe.js +172 -0
  235. package/dist/drivers/process.d.ts +48 -0
  236. package/dist/drivers/process.js +100 -0
  237. package/dist/drivers/runner.d.ts +61 -0
  238. package/dist/drivers/runner.js +388 -0
  239. package/dist/drivers/store.d.ts +49 -0
  240. package/dist/drivers/store.js +91 -0
  241. package/dist/drivers/turn.d.ts +41 -0
  242. package/dist/drivers/turn.js +99 -0
  243. package/dist/drivers/types.d.ts +122 -0
  244. package/dist/drivers/types.js +11 -0
  245. package/dist/git/info.d.ts +75 -0
  246. package/dist/git/info.js +191 -0
  247. package/dist/hooks/protocol.js +6 -1
  248. package/dist/hooks/types.d.ts +10 -1
  249. package/dist/hooks/types.js +2 -0
  250. package/dist/host/api-impl.d.ts +7 -0
  251. package/dist/host/api-impl.js +15 -0
  252. package/dist/host/types.d.ts +24 -2
  253. package/dist/host/types.js +4 -0
  254. package/dist/index.d.ts +3 -0
  255. package/dist/index.js +1 -0
  256. package/dist/modes/acp/acp-events.d.ts +46 -0
  257. package/dist/modes/acp/acp-events.js +233 -0
  258. package/dist/modes/acp/acp-mode.d.ts +17 -0
  259. package/dist/modes/acp/acp-mode.js +47 -0
  260. package/dist/modes/acp/acp-server.d.ts +79 -0
  261. package/dist/modes/acp/acp-server.js +315 -0
  262. package/dist/modes/commands-core.d.ts +7 -1
  263. package/dist/modes/commands-core.js +55 -0
  264. package/dist/modes/image-input.d.ts +12 -4
  265. package/dist/modes/image-input.js +22 -5
  266. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  267. package/dist/modes/interactive/agent-panels.js +103 -0
  268. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  269. package/dist/modes/interactive/agent-ui.js +234 -0
  270. package/dist/modes/interactive/approval-dialog.d.ts +21 -4
  271. package/dist/modes/interactive/approval-dialog.js +98 -20
  272. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  273. package/dist/modes/interactive/approval-merge.js +89 -0
  274. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  275. package/dist/modes/interactive/clipboard-paste.js +28 -0
  276. package/dist/modes/interactive/commands.d.ts +9 -1
  277. package/dist/modes/interactive/commands.js +19 -0
  278. package/dist/modes/interactive/double-esc.d.ts +20 -0
  279. package/dist/modes/interactive/double-esc.js +34 -0
  280. package/dist/modes/interactive/event-notices.d.ts +32 -0
  281. package/dist/modes/interactive/event-notices.js +79 -0
  282. package/dist/modes/interactive/external-editor.d.ts +16 -0
  283. package/dist/modes/interactive/external-editor.js +39 -0
  284. package/dist/modes/interactive/interactive-mode.d.ts +14 -1
  285. package/dist/modes/interactive/interactive-mode.js +134 -136
  286. package/dist/modes/interactive/key-dispatch.d.ts +16 -2
  287. package/dist/modes/interactive/key-dispatch.js +49 -1
  288. package/dist/modes/interactive/line/line-mode.d.ts +2 -1
  289. package/dist/modes/interactive/line/line-mode.js +22 -5
  290. package/dist/modes/interactive/line/line-render.d.ts +2 -1
  291. package/dist/modes/interactive/line/line-render.js +40 -4
  292. package/dist/modes/interactive/message-view.d.ts +1 -1
  293. package/dist/modes/interactive/message-view.js +24 -2
  294. package/dist/modes/interactive/panels.d.ts +18 -1
  295. package/dist/modes/interactive/panels.js +19 -5
  296. package/dist/modes/interactive/plan-command.d.ts +40 -0
  297. package/dist/modes/interactive/plan-command.js +129 -0
  298. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  299. package/dist/modes/interactive/plan-dialog.js +290 -0
  300. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  301. package/dist/modes/interactive/plan-flow.js +98 -0
  302. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  303. package/dist/modes/interactive/rewind-command.js +106 -0
  304. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  305. package/dist/modes/interactive/rewind-flow.js +151 -0
  306. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  307. package/dist/modes/interactive/rewind-list.js +123 -0
  308. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  309. package/dist/modes/interactive/rewind-panel.js +309 -0
  310. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  311. package/dist/modes/interactive/rewind-text.js +139 -0
  312. package/dist/modes/interactive/session-events.d.ts +24 -0
  313. package/dist/modes/interactive/session-events.js +96 -0
  314. package/dist/modes/interactive/status-area.d.ts +73 -0
  315. package/dist/modes/interactive/status-area.js +190 -0
  316. package/dist/modes/interactive/status-bar.d.ts +99 -11
  317. package/dist/modes/interactive/status-bar.js +273 -90
  318. package/dist/modes/interactive/status-line.d.ts +33 -0
  319. package/dist/modes/interactive/status-line.js +113 -0
  320. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  321. package/dist/modes/interactive/subagent-view.js +154 -0
  322. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  323. package/dist/modes/interactive/tasks-report.js +114 -0
  324. package/dist/modes/interactive/tool-view.d.ts +12 -2
  325. package/dist/modes/interactive/tool-view.js +34 -4
  326. package/dist/modes/print/print-mode.d.ts +13 -4
  327. package/dist/modes/print/print-mode.js +56 -12
  328. package/dist/modes/rpc/commands.d.ts +9 -0
  329. package/dist/modes/rpc/commands.js +44 -0
  330. package/dist/modes/rpc/rpc-mode.js +7 -1
  331. package/dist/modes/session-report.d.ts +11 -0
  332. package/dist/modes/session-report.js +48 -1
  333. package/dist/permissions/auto-safe.d.ts +5 -0
  334. package/dist/permissions/auto-safe.js +18 -0
  335. package/dist/permissions/classifier.d.ts +4 -0
  336. package/dist/permissions/classifier.js +2 -0
  337. package/dist/permissions/modes.js +1 -1
  338. package/dist/permissions/pipeline.d.ts +43 -4
  339. package/dist/permissions/pipeline.js +114 -9
  340. package/dist/permissions/readonly-bash.d.ts +30 -0
  341. package/dist/permissions/readonly-bash.js +118 -0
  342. package/dist/permissions/types.d.ts +42 -0
  343. package/dist/plan/compose.d.ts +9 -0
  344. package/dist/plan/compose.js +19 -0
  345. package/dist/plan/controller.d.ts +71 -0
  346. package/dist/plan/controller.js +27 -0
  347. package/dist/plan/done-markers.d.ts +17 -0
  348. package/dist/plan/done-markers.js +51 -0
  349. package/dist/plan/extract.d.ts +29 -0
  350. package/dist/plan/extract.js +160 -0
  351. package/dist/plan/prompts.d.ts +36 -0
  352. package/dist/plan/prompts.js +89 -0
  353. package/dist/plan/store.d.ts +37 -0
  354. package/dist/plan/store.js +90 -0
  355. package/dist/rpc.d.ts +58 -2
  356. package/dist/rpc.js +7 -0
  357. package/dist/sandbox/bash.d.ts +74 -0
  358. package/dist/sandbox/bash.js +126 -0
  359. package/dist/sandbox/detect.d.ts +48 -0
  360. package/dist/sandbox/detect.js +149 -0
  361. package/dist/sandbox/index.d.ts +5 -0
  362. package/dist/sandbox/index.js +5 -0
  363. package/dist/sandbox/profile.d.ts +33 -0
  364. package/dist/sandbox/profile.js +76 -0
  365. package/dist/sandbox/wrap.d.ts +29 -0
  366. package/dist/sandbox/wrap.js +117 -0
  367. package/dist/sdk.d.ts +33 -2
  368. package/dist/sdk.js +24 -2
  369. package/dist/session/types.d.ts +3 -1
  370. package/dist/session/types.js +1 -0
  371. package/dist/skills/builtin.d.ts +31 -0
  372. package/dist/skills/builtin.js +109 -0
  373. package/dist/skills/discover.d.ts +2 -1
  374. package/dist/skills/index-prompt.js +5 -8
  375. package/dist/tools/background-jobs.d.ts +71 -0
  376. package/dist/tools/background-jobs.js +198 -0
  377. package/dist/tools/bash.d.ts +53 -1
  378. package/dist/tools/bash.js +158 -7
  379. package/dist/tools/clipboard-image.d.ts +44 -0
  380. package/dist/tools/clipboard-image.js +148 -0
  381. package/dist/tools/edit.d.ts +2 -0
  382. package/dist/tools/edit.js +18 -3
  383. package/dist/tools/image-file.d.ts +38 -3
  384. package/dist/tools/image-file.js +81 -10
  385. package/dist/tools/image-resize.d.ts +58 -0
  386. package/dist/tools/image-resize.js +97 -0
  387. package/dist/tools/presets.d.ts +7 -2
  388. package/dist/tools/presets.js +11 -4
  389. package/dist/tools/read.d.ts +5 -2
  390. package/dist/tools/read.js +13 -10
  391. package/dist/tools/registry.d.ts +7 -1
  392. package/dist/tools/registry.js +27 -4
  393. package/dist/tools/task-ctl.d.ts +22 -0
  394. package/dist/tools/task-ctl.js +116 -0
  395. package/dist/tools/task.d.ts +22 -10
  396. package/dist/tools/task.js +66 -26
  397. package/dist/tools/todo.d.ts +22 -2
  398. package/dist/tools/todo.js +58 -14
  399. package/dist/tools/truncate.d.ts +15 -0
  400. package/dist/tools/truncate.js +25 -0
  401. package/dist/tools/types.d.ts +113 -0
  402. package/dist/tools/types.js +5 -0
  403. package/dist/tools/write.js +3 -0
  404. package/dist/tui/glyphs.d.ts +4 -0
  405. package/dist/tui/glyphs.js +4 -0
  406. package/dist/tui/keybindings.d.ts +5 -0
  407. package/dist/tui/keybindings.js +5 -0
  408. package/docs/acp.md +78 -0
  409. package/docs/agents.md +250 -0
  410. package/docs/codemode.md +12 -8
  411. package/docs/hooks.md +26 -22
  412. package/docs/permissions.md +77 -13
  413. package/docs/plan.md +107 -0
  414. package/docs/providers.md +228 -52
  415. package/docs/rewind-plan.md +181 -0
  416. package/docs/rpc.md +92 -5
  417. package/docs/sandbox.md +215 -0
  418. package/docs/session-format.md +41 -21
  419. package/docs/sessions.md +41 -1
  420. package/docs/tui-design.md +751 -0
  421. package/docs/tui.md +125 -6
  422. package/package.json +13 -2
@@ -0,0 +1,751 @@
1
+ # ama 终端界面视觉设计 v1
2
+
3
+ > 适用:`src/tui/**`(组件库)与 `src/modes/interactive/**`(交互模式)。基线 main 217017c。
4
+ > 约束不变:主屏模式(不用备用屏,历史进终端回滚,tmux `capture-pane` 可读)、差分渲染、运行时零依赖、`NO_COLOR` / 16 / 256 / truecolor 降级、40 列可用、中文宽字符正确、Windows Terminal 可用、括号粘贴。
5
+ > 参考对象只有两个:Pi 1.0(组件模型、主题 JSON 的角色划分)与 Claude Code(视觉语言:`›` 输入、`⏺` / `⎿` 工具层级、spinner 动词、底部模式提示、编号审批)。
6
+
7
+ ## 0. 现状诊断(对照 test/fixtures/tui/*.txt)
8
+
9
+ | 现象 | 位置 | 问题 |
10
+ | -------------------------------------------------------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------- |
11
+ | 首行 `ama 0.1.0 · Enter 发送 · Esc 中断 · Ctrl+C 两次退出 · /help 命令` | `cli/startup-screen.ts` `headerLine()` | 标题行塞满按键说明,没有身份信息(模型 / 目录 / 模式);40 列折成两行 |
12
+ | 用户消息 `› 文本`,续行顶格 | `message-view.ts` `addUser` | 多行用户消息第二行与助手正文无法区分 |
13
+ | 助手正文、工具、提示全部顶格、块间统一空一行 | `message-view.ts` `add()` | 没有层级:连续三个工具调用占 6 行;提示与正文同权重 |
14
+ | 工具 `● read README.md` + 顶格缩进 2 的结果 | `tool-view.ts` | 结果没有「挂在调用下」的视觉连接;`… 另 2 行(Ctrl+O 展开)` 与结果同色 |
15
+ | 代码块全宽圆角框、正文整体橙色(`code`) | `markdown.ts` `renderCode` | 大段橙色抢眼;语言标签与边框同样醒目 |
16
+ | 输入框两条全宽 `─`,无提示符、无占位 | `editor.ts` | 空闲时看不出这是输入区;与状态栏的分隔线视觉重复(三条线叠在一起) |
17
+ | 状态栏 `fake/echo · think:medium · ↑12.3k ↓1.2k · cache 80% · $0.002 · ctx 1% · mode:Manual` | `status-bar.ts` | 全部同权重、`key:value` 机器味;40 列截断成 `…` 丢掉最重要的模式 |
18
+ | 审批框 `[y] 允许 [n] 拒绝 [a] 本会话允许同类 [v] 完整输入` 一行 | `approval-dialog.ts` | 40 列折行后难读;没有「当前选项」概念,不能方向键选 |
19
+ | 压缩摘要是全宽 Box | `message-view.ts` `addSummaryCard` | 与代码块、审批框三种东西共用同一种重框 |
20
+ | 运行中 `⠋ 工作中 · Esc 中断 (0s)` | `interactive-mode.ts` `syncLoader` | 不知道在做什么(思考 / 回复 / 跑哪个工具),没有 token 计数 |
21
+
22
+ ## 1. 设计原则
23
+
24
+ 1. **三级信息层级,用缩进而不是颜色表达。** 第 0 列:用户 `›`、工具 `⏺`、提示符号(`✗ ! ↻ ◇`);第 2 列:结果连接符 `⎿` 与助手正文的续行;第 4 列:工具输出正文。颜色只做第二通道——`capture-pane` 不带 `-e` 时得到的纯文本仍然能读出结构。
25
+ 2. **留白按组分配,不按块平均。** 一个「回合」(用户消息 → 助手正文 → 若干工具调用 → 助手正文)内部,相邻工具调用之间不空行;回合之间空一行;`ui.compact: true` 时全部不空行。24 行的 tmux 节点里能多看 30% 内容。
26
+ 3. **颜色克制:一屏最多三种彩色。** 正文 `text`、次要 `muted`、禁用 / 装饰 `dim` 三级灰;彩色只给状态(成功 / 警告 / 错误)、焦点(`accent`)和身份(`user` / `tool`)。背景色只在 ≥ 256 色时用,且只用于「选中行」与 diff 行底色;16 色与 `NO_COLOR` 下靠字形与粗体。
27
+ 4. **状态一目了然。** 每个可变状态都有字形:`⏺` 颜色 + 结果行首字(`✓ ✗`)、spinner 动词、状态栏模式名;颜色与字形冗余编码,去掉颜色不丢信息。
28
+ 5. **对读屏友好。** 每行末尾重置样式、不用 OSC 8 超链接、不用 bg 跨整行、没有只靠颜色区分的字段;状态栏永远是最后一行,输入框永远在它上面,宿主可以用倒数第 1 / 第 3 行锚定。
29
+ 6. **差分友好。** 流式期间只有正在增长的块变行;spinner 行每帧只改一个字;代码块永远全宽(不随内容变宽),避免框线抖动;所有「运行中 → 完成」的切换都是**原地替换**,行数只增不减(结果行追加在标题下面)。
30
+ 7. **窄屏优先裁剪,不换布局。** 40 列与 80 列是同一套组件、同一套规则:截断 / 丢字段 / 折行,不切换成另一种结构(避免两套黄金两套 bug)。
31
+
32
+ ## 2. 主题
33
+
34
+ ### 2.1 语义色(`SemanticColor`)
35
+
36
+ 在现有 11 个名字上**只加 3 个**:`muted`(正文与 dim 之间的次要文字)、`link`、`selection`(选中行底色,只在 ≥ 256 色时作 bg 用)。`component.ts` 是契约文件,这是唯一需要改的契约点。
37
+
38
+ | 名字 | 用途 | dark truecolor | dark 256 | dark 16 | light truecolor | light 256 | light 16 |
39
+ | ----------- | ------------------------------------------------ | -------------- | -------- | ------- | --------------- | --------- | -------- |
40
+ | `text` | 正文、工具摘要、代码块正文 | `#e4e4e4` | 254 | 7 | `#1c1c1c` | 234 | 0 |
41
+ | `muted` | 结果摘要、列表圆点、表格线、思考正文 | `#a8a8a8` | 248 | 7 | `#585858` | 240 | 8 |
42
+ | `dim` | 占位、折叠提示、分隔符 `·`、时间 | `#6c6c6c` | 242 | 8 | `#8a8a8a` | 245 | 8 |
43
+ | `accent` | 焦点、选中项、运行中 `⏺`、标题 h1/h2、spinner | `#5fafff` | 75 | 12 | `#005fd7` | 26 | 4 |
44
+ | `success` | 成功 `⏺` / `✓`、diff `+`、ctx < 70% | `#5fd787` | 78 | 10 | `#008700` | 28 | 2 |
45
+ | `warning` | `!` 提示、重试、ctx ≥ 70%、Bypass 模式 | `#ffd75f` | 221 | 11 | `#af5f00` | 130 | 3 |
46
+ | `error` | `✗`、失败 `⏺`、diff `−`、ctx ≥ 90%、危险审批 | `#ff5f5f` | 203 | 9 | `#d70000` | 160 | 1 |
47
+ | `user` | 用户 `›`、输入框提示符 | `#87afff` | 111 | 12 | `#005faf` | 25 | 4 |
48
+ | `assistant` | 保留(= text) | `#e4e4e4` | 254 | 7 | `#1c1c1c` | 234 | 0 |
49
+ | `tool` | 工具名 | `#af87ff` | 141 | 13 | `#8700af` | 91 | 5 |
50
+ | `border` | 框线、规则线、`⎿`、引用竖线 | `#585858` | 240 | 8 | `#bcbcbc` | 250 | 7 |
51
+ | `code` | **只用于行内代码**与审批框里的命令 | `#ffaf5f` | 215 | 11 | `#875f00` | 94 | 3 |
52
+ | `link` | Markdown 链接文字(下划线) | `#87d7ff` | 117 | 14 | `#0087af` | 31 | 6 |
53
+ | `selection` | 选中行 bg(≥ 256 色);16 色下退化为 accent 粗体 | `#303030` | 236 | — | `#e4e4e4` | 254 | — |
54
+
55
+ - truecolor 值全部取自 xterm 256 立方 / 灰阶上的点,所以 256 色回退**无损**(`rgbTo256` 直接命中);16 色列是期望值,加一条测试锁定 `rgbTo16(parseHex(x)) === 期望`,防止 `distance()` 权重调整后变色。
56
+ - 阈值着色统一走一个工具函数 `levelColor(ratio, {warnAt: .7, dangerAt: .9})`(`Meter.level()` 已有,提到 theme.ts 导出),状态栏 ctx、Meter、`/session` 上下文行都用它。
57
+ - bg 规则:`theme.caps.colors >= 256` 时 `selection` 作 bg;否则 `theme.bg("selection", s)` 返回 `bold(fg("accent", s))`。diff 行**不加 bg**(tmux 里 bg 跨行与截断后的 `\x1b[0m` 组合常出现「尾巴」)。
58
+ - `ui.theme: "auto"`:不发查询序列。顺序:`COLORFGBG`(`15;0` → dark,`0;15` → light)→ `TERM_PROGRAM=Apple_Terminal` 且无 COLORFGBG → dark → 缺省 dark。文档里明说 auto 只是猜,建议显式配置。
59
+
60
+ ### 2.2 字形与 ASCII 回退
61
+
62
+ 新增 `src/tui/glyphs.ts`:`interface Glyphs`、`UNICODE_GLYPHS`、`ASCII_GLYPHS`、`detectAscii(env)`。挂到 `Theme`(`theme.glyphs`),所有组件通过 theme 取,不另加参数。
63
+
64
+ | 键 | Unicode | ASCII | 用处 |
65
+ | ----------------------- | ---------------------- | --------------- | --------------------------------------- |
66
+ | `prompt` | `›` | `>` | 用户消息、输入框 |
67
+ | `tool` | `⏺` | `*` | 工具调用标题 |
68
+ | `result` | `⎿` | `L` | 结果连接符 |
69
+ | `ok` / `fail` / `warn` | `✓` `✗` `!` | `v` `x` `!` | 结果摘要首字、提示 |
70
+ | `thinking` | `✻` | `~` | 思考块 |
71
+ | `queued` | `↳` | `->` | 排队消息 |
72
+ | `retry` | `↻` | `@` | 重试提示 |
73
+ | `card` | `▎` | `\|` | 左侧竖条卡片(压缩摘要、/session 面板) |
74
+ | `expand` / `collapse` | `▸` `▾` | `>` `v` | 可展开提示 |
75
+ | `warm` | `♨` | `~` | 缓存保温 |
76
+ | `bullet[]` | `• ◦ ▪` | `- * +` | 列表 |
77
+ | `meter` | `▮ ▯` | `# .` | 余量条 |
78
+ | `box` | `╭ ╮ ╰ ╯ │ ─` | `+ + + + \| -` | 边框 |
79
+ | `spinner[]` | 10 帧盲文 `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏` | 4 帧 `- \ \| /` | Loader |
80
+ | `ellipsis` | `…` | `...` | 截断 |
81
+ | `arrowUp` / `arrowDown` | `↑` `↓` | `^` `v` | token 计数 |
82
+
83
+ - 触发 ASCII:`ui.ascii: true` 或 `AMA_ASCII=1`,或自动检测:`LANG`/`LC_ALL`/`LC_CTYPE` 不含 `UTF-8`、`TERM=linux`、Windows 上 `WT_SESSION` 与 `TERM_PROGRAM` 都为空(旧 conhost)。Windows Terminal 走 Unicode。
84
+ - `⏺`(U+23FA)在部分 emoji 字体下渲染为两格但 `codePointWidth` 判 1 格。对策:`ansi.ts` 的宽度表不改(保持 wcwidth 一致);提供 `ui.glyphs: "unicode" | "safe" | "ascii"` 三档?——**不加**。只在文档「排错」里说明用 `AMA_ASCII=1`,并在 tui-frames 测试里锁定 `visibleWidth("⏺") === 1`。
85
+
86
+ ## 3. 逐屏样稿
87
+
88
+ 记号:样稿行内 `⟨accent⟩` 这类标注在实际渲染中不存在;为了保持列宽准确,着色说明统一写在每张样稿下面。所有 80 列样稿左边界是终端第 0 列。
89
+
90
+ ### 3.1 启动头
91
+
92
+ `ui.quietStartup: normal`(80 列):
93
+
94
+ ```
95
+ ╭──────────────────────────────────────────────────────────╮
96
+ │ ✻ ama 0.1.0 │
97
+ │ │
98
+ │ 模型 anthropic/claude-sonnet-4-5@messages · 思考 medium │
99
+ │ 目录 ~/Projects/armadra-agent · 已信任(trust.json) │
100
+ │ 模式 Accept edits · 预设 default · codemode on │
101
+ │ 已加载 CLAUDE.md, AGENTS.md · 3 Skill · 2 模板 · 4 Hook │
102
+ │ │
103
+ │ /help 命令 · Shift+Tab 切模式 · Ctrl+O 展开工具输出 │
104
+ ╰──────────────────────────────────────────────────────────╯
105
+ ```
106
+
107
+ - 框宽 `min(width, 60)`,不居中(左对齐,便于回滚里对齐正文);边框 `border`;`✻ ama 0.1.0` 粗体,`✻` `accent`;键名列 `dim`,值 `text`,模型 `accent`,`已信任` `success` / `未信任` `warning`,`Bypass permissions` 时模式值 `warning`;最后一行 `dim`。
108
+ - 警告条数 `警告 2 条(ama doctor 查看)` 用 `warning`,放在「已加载」之后。
109
+ - `header` 档(profile 缺省):一行 `✻ ama 0.1.0 · anthropic/claude-sonnet-4-5 · Accept edits · /help`,无框。`silent` 不输出。
110
+
111
+ 40 列(normal 自动降为无框多行,键列省略):
112
+
113
+ ```
114
+ ✻ ama 0.1.0
115
+ anthropic/claude-sonnet-4-5 · medium
116
+ ~/Projects/armadra-agent · 已信任
117
+ Accept edits · default · codemode on
118
+ CLAUDE.md, AGENTS.md · 3 Skill · 4 Hook
119
+ /help · Shift+Tab 切模式
120
+ ```
121
+
122
+ 规则:`width < 56` 时去框去键列;路径用 `~` 缩写并从左侧截断(`…/armadra-agent`)。
123
+
124
+ ### 3.2 用户消息
125
+
126
+ ```
127
+ › 帮我检查差分渲染在小终端里是否正确,宽字符 😀 也要对齐,
128
+ 顺便看看 resize 之后光标位置对不对
129
+ ```
130
+
131
+ - `›` `user` 粗体;文本 `text`;续行缩进 2 列对齐正文首字(当前实现顶格)。
132
+ - 运行中插话 `↳ 插话 继续:再加一个 resize 的测试`、排到之后的 `↳ 之后 …`、宿主注入 `↳ 宿主 …`:整行 `muted`,`↳` `dim`。(原 `↳ steer` / `↳ followUp` / `↳ host` 改中文标签,`origin` 字段不变。)
133
+ - 40 列同样规则,折行点由 `wrapTextWithAnsi` 决定(宽字符间可断)。
134
+
135
+ ### 3.3 助手 Markdown
136
+
137
+ ```
138
+ 差分渲染的规则
139
+
140
+ 我先看一下 src/tui/tui.ts 的 diff() 逻辑,然后只改必要的部分。
141
+ 见 差分渲染说明 (docs/tui.md#差分渲染)。
142
+
143
+ 1. 首帧全量输出
144
+ 2. 修改 diff():首变化行在视口之上时全量重画
145
+ • 已滚出终端顶部的历史行留在回滚里
146
+ 3. 跑测试
147
+
148
+ ╭─ ts ─────────────────────────────────────────────────────────────────────────╮
149
+ │ if (first < viewportTop) fullViewport(); │
150
+ │ for (let i = first; i <= last; i++) out.push(moveTo(i) + clear + lines[i]); │
151
+ ╰──────────────────────────────────────────────────────────────────────────────╯
152
+
153
+ ▎ 注意:已滚出终端顶部的历史行不再重绘。
154
+
155
+ 情况 写入
156
+ ─────────────────
157
+ 改一行 1 行
158
+ resize 一屏
159
+ ```
160
+
161
+ - h1 / h2:`accent` 粗体;h3+:`text` 粗体。标题后不加下划线。
162
+ - 段落 `text`;行内代码 `code`(不加反引号);粗体 / 斜体按 SGR;链接:文字 `link` + 下划线,URL 在后面以 ` (url)` `dim` 追加,文字与 URL 相同时只显示一次。
163
+ - 列表:数字 / 圆点 `muted`(原 `accent`,太跳);嵌套圆点 `• ◦ ▪`。
164
+ - 代码块:**全宽**(不随内容收缩,避免流式时框线抖动);边框 `border`,语言标签 `dim`;正文 `text`(原 `code` 橙色整块去掉);`width < 8` 退化为裸文本。
165
+ - 引用:`▎`(原 `│`)`border` + 正文 `muted` 斜体。
166
+ - 表格:首行粗体,其下加一条 `─` 规则线(`border`),列间两个空格(原 `│`,去掉竖线更干净);超宽截断。
167
+ - `ui.markdown: false` 时整段 `text`。
168
+
169
+ 40 列下代码块仍全宽(内宽 36),长行按列硬断;列表缩进保持。
170
+
171
+ ### 3.4 思考块
172
+
173
+ 折叠(缺省 `collapsed`)、流式中、展开:
174
+
175
+ ```
176
+ ✻ 思考中…
177
+
178
+ ✻ 思考 · 1.2k token
179
+
180
+ ✻ 思考 · 1.2k token ▾
181
+ 先确认差分逻辑在 viewportTop 之上的情形……
182
+ 然后看 resize 路径是否清掉旧行。
183
+ ```
184
+
185
+ - `✻` 与文字 `dim` 斜体;流式中 `思考中…` 末尾三点由 Loader 不驱动(避免每帧重绘思考行);完成后换成 token 数。
186
+ - Ctrl+O 现在**同时**展开思考块与工具输出(`collapsed` 模式下;`hidden` 不受影响,`full` 本来就展开);展开时标题末尾 `▾`,正文缩进 2 列 `muted` 斜体,最多 60 行后 `… 另 N 行`。
187
+
188
+ ### 3.5 工具调用
189
+
190
+ 通用结构:第 0 列 `⏺`,工具名,摘要;第 2 列 `⎿` + **一行结果摘要**;第 4 列输出正文;折叠提示 `… 另 N 行(Ctrl+O 展开)`。相邻工具调用之间不空行。
191
+
192
+ **read**
193
+
194
+ ```
195
+ ⏺ read src/tui/tui.ts:1+120
196
+ ⎿ 读取 120 行
197
+ 1 /**
198
+ 2 * TUI 主类(设计 §12.1、§12.2,主屏 regular 模式)。[B4]
199
+ 3 *
200
+ … 另 117 行(Ctrl+O 展开)
201
+ ```
202
+
203
+ - `⏺` 运行中 `accent`、成功 `success`、失败 `error`;工具名 `tool` 粗体;摘要 `text`;`⎿` `border`;摘要行 `muted`;行号右对齐宽 6 `dim`,正文 `text`;折叠提示 `dim`。
204
+
205
+ **edit(diff)**
206
+
207
+ ```
208
+ ⏺ edit src/tui/tui.ts
209
+ ⎿ 2 处修改 · +5 −2
210
+ @@ -212,4 +212,7 @@
211
+ 212 if (first === -1) return;
212
+ 213 - if (first < this.viewportTop(height)) {
213
+ 213 + if (first < this.viewportTop(height) || lines.length < prev.length) {
214
+ 214 + // 内容变短也走全量,避免残影
215
+ … 另 9 行(Ctrl+O 展开)
216
+ ```
217
+
218
+ - `@@` `dim`;`-` 行 `error`,`+` 行 `success`,上下文 `muted`;行号列 `dim`(旧 / 新各取一个,宽 4)。折叠 12 行,展开 400 行。`+N −M` 在摘要行用对应颜色。
219
+
220
+ **bash(流式尾部 → 完成)**
221
+
222
+ ```
223
+ ⏺ bash pnpm vitest run src/tui
224
+ ⎿ ⠋ 运行中 · 4s
225
+ ✓ src/tui/ansi.test.ts (31)
226
+ ✓ src/tui/theme.test.ts (12)
227
+ ⠋ src/tui/tui.test.ts
228
+
229
+ ⏺ bash pnpm vitest run src/tui
230
+ ⎿ 退出 0 · 2.1s · 48 行
231
+ Test Files 6 passed (6)
232
+ Tests 112 passed (112)
233
+ Duration 2.08s
234
+ … 另 45 行(Ctrl+O 展开)
235
+
236
+ ⏺ bash git push --force origin main
237
+ ⎿ 退出 128 · 0.3s
238
+ fatal: refusing to update checked out branch
239
+ ```
240
+
241
+ - 运行中摘要行带 spinner(与底部 Loader 同帧,`accent`);尾部 8 行 `muted`;完成后摘要 `退出 0 · 耗时 · 行数`,非零退出码 `error`,正文(stderr)`error`。工具输出先 `cleanLines()` 去 ANSI(现有)。
242
+
243
+ **grep / glob**
244
+
245
+ ```
246
+ ⏺ grep requestRender in src/
247
+ ⎿ 14 处匹配 · 6 个文件
248
+ src/tui/tui.ts:180: requestRender(immediate = false): void {
249
+ src/tui/components/loader.ts:52: this.requestRender();
250
+ src/tui/components/editor.ts:311: this.options.requestRender();
251
+ … 另 11 行(Ctrl+O 展开)
252
+ ```
253
+
254
+ - 文件路径部分 `text`,行号与冒号 `dim`,命中片段 `muted`(需要 grep 结果 `details.matches`;没有结构化数据时整行 `muted`)。
255
+
256
+ **codemode 与嵌套内层调用**
257
+
258
+ ```
259
+ ⏺ codemode const files = await tools.glob("src/**/*.ts")
260
+ ⎿ 3 个内层调用 · 脚本输出 2 行
261
+ ⏺ glob src/**/*.ts
262
+ ⎿ 42 个文件
263
+ ⏺ read src/tui/tui.ts
264
+ ⎿ 读取 399 行
265
+ ⏺ grep requestRender in src/
266
+ ⎿ 14 处匹配 · 6 个文件
267
+ 42 files, 14 matches
268
+ ```
269
+
270
+ - 内层调用整体右移 2 列,复用同一组件(`ToolView.render(width - 2)` 已有);折叠时只显示最近 5 个内层标题 + 摘要行(不显示内层正文);展开时完整。`… 前 N 个调用` `dim`。
271
+
272
+ **task 子 Agent**
273
+
274
+ ```
275
+ ⏺ task 检查 src/tui 的测试覆盖缺口
276
+ ⎿ 子 Agent · 运行中 1m05s · 7 次工具调用 · ↓3.4k
277
+
278
+ ⏺ task 检查 src/tui 的测试覆盖缺口
279
+ ⎿ 完成 · 1m42s · 9 次工具调用 · ↑28k ↓4.1k
280
+ 缺口主要在 overlay.ts 的 bottom 锚点与 editor 的粘贴折叠……
281
+ … 另 6 行(Ctrl+O 展开)
282
+ ```
283
+
284
+ - 运行中摘要每秒刷新耗时(`tool_execution_update` 的 partial 带统计时解析;否则只显示 `运行中 · 耗时`)。
285
+
286
+ 40 列(以 edit 为例):
287
+
288
+ ```
289
+ ⏺ edit src/tui/tui.ts
290
+ ⎿ 2 处修改 · +5 −2
291
+ @@ -212,4 +212,7 @@
292
+ - if (first < this.viewportTop(hei…
293
+ + if (first < this.viewportTop(hei…
294
+ … 另 10 行(Ctrl+O 展开)
295
+ ```
296
+
297
+ - `width < 60` 时 diff 行不显示行号列(省 5 列)、折叠行截断加 `…`(不折行);展开时折行。
298
+
299
+ ### 3.6 提示:错误、重试、压缩、缓存
300
+
301
+ ```
302
+ ✗ 模型调用失败:401 invalid x-api-key(anthropic)
303
+
304
+ ↻ 重试 1/3(2s 后):429 rate_limit_error
305
+
306
+ ▎ 上下文已压缩 128k → 24k token
307
+ ▎ 用户要求检查差分渲染与 resize 行为;已修改 diff() 并补测试……
308
+ ▎ … 另 4 行
309
+
310
+ ! 缓存未命中(空闲 7 分钟后):重计费 38.2k token(约 $0.11)
311
+ ! 上下文已用 72%,约剩 9 回合(按最近 5 回合均值)
312
+ ✗ 上下文已用 91%,约剩 1 回合
313
+
314
+ ⛔ Hook 阻止:pre-tool-use 拒绝了 bash(禁止 force push)
315
+ 已拒绝 bash
316
+ ```
317
+
318
+ - `✗` + 文本 `error`;`↻` 行 `warning`;`!` 行 `warning`;≥ 90% 的 ctx 提示升为 `✗` `error`;`⛔` 行 `warning`;审批结果说明(已拒绝 / 已取消)`dim`。
319
+ - 压缩摘要卡:改为**左竖条卡片**(`▎` `border`,标题 `text` 粗体,token 变化 `muted`,摘要 `muted`),不再用全宽 Box——Box 只留给代码块、启动头、覆盖层三处。
320
+ - 助手消息收尾状态(`已中断` / `输出达到长度上限`)保持一行 `dim` / `warning`。
321
+
322
+ ### 3.7 运行中 spinner
323
+
324
+ ```
325
+ ⠋ 思考中 · 4s · Esc 中断
326
+ ⠹ 回复中 · 12s · ↓≈1.2k · Esc 中断
327
+ ⠸ 运行 bash · 38s · Esc 中断
328
+ ⠼ 等待确认 · 2m10s
329
+ ⠴ 压缩上下文 · 6s · Esc 中断
330
+ ⠦ 重试 2/3 · 2s 后
331
+ ```
332
+
333
+ - spinner `accent`;动词 `text`;其余 `dim`。动词由事件推导:`message_start(assistant)` → 思考中(有 thinking 块在流)/ 回复中;`tool_execution_start` → `运行 <工具名>`(并行多个时 `运行 3 个工具`);审批打开 → `等待确认`(无 Esc 提示,Esc 由对话框消费);`compaction_start` → 压缩上下文;`auto_retry_start` → 重试 n/m。
334
+ - `↓≈N` 是本回合输出 token 的估算(`estimateTokens`,4 字符 ≈ 1),`message_end` 后用真实 usage 修正;没有文本时不显示。
335
+ - 帧率:80 ms(12.5 fps);耗时只在整秒变化;ASCII 模式 4 帧 250 ms;`ui.animation: false`(或检测到 `AMA_ASCII`)时 spinner 固定为 `·`,整行每秒只因耗时变一次。
336
+ - 位置不变:排队消息之下、输入框之上。
337
+
338
+ ### 3.8 排队消息
339
+
340
+ ```
341
+ ↳ 插话 继续:再加一个 resize 的测试
342
+ ↳ 之后 顺便更新 docs/tui.md
343
+ Alt+↑ 取回 · Esc 回填并中断
344
+ ⠋ 运行 bash · 38s · Esc 中断
345
+ ```
346
+
347
+ - 整体 `muted`,标签 `dim`,缩进 2 列(与 `⎿` 对齐,表示「挂在当前回合下」);超过 3 条时首行 `… 另 N 条`。
348
+
349
+ ### 3.9 输入框
350
+
351
+ 空闲、占位(80 列):
352
+
353
+ ```
354
+ ────────────────────────────────────────────────────────────────────────────────
355
+ › 输入消息,/ 命令,@ 文件,Shift+Enter 换行
356
+ ────────────────────────────────────────────────────────────────────────────────
357
+ ```
358
+
359
+ 多行、粘贴折叠、超出可视行:
360
+
361
+ ```
362
+ ─── ↑ 2 ────────────────────────────────────────────────────────────────────────
363
+ 把这段日志贴给你看:
364
+ [粘贴 #1 · 142 行]
365
+ 第三行是我自己打的,请对比 ▌
366
+ ─── ↓ 1 ────────────────────────────────────────────────────────────────────────
367
+ ```
368
+
369
+ 补全弹层(`/` 命令):
370
+
371
+ ```
372
+ ────────────────────────────────────────────────────────────────────────────────
373
+ › /mo▌
374
+ ────────────────────────────────────────────────────────────────────────────────
375
+ › /model [provider/model] 切换模型
376
+ /mode 切换权限模式
377
+ (1/2) Tab 接受 · Esc 关闭
378
+ ```
379
+
380
+ - 上下规则线 `border`;提示符 `›` `user` 粗体,`disableSubmit`(审批中)时 `dim`;占位 `dim`,获焦时也显示直到有输入(原实现只在失焦时显示——交互模式里编辑器永远获焦,所以占位从未出现过)。续行缩进 2 列对齐。
381
+ - 光标:反显一格(现有);硬件光标仍摆到该处供输入法。
382
+ - 粘贴折叠标记 `[粘贴 #1 · 142 行]`:`accent` 不下划线;提交展开(现有)。
383
+ - 规则线上的 `↑ 2` / `↓ 1` `dim`(现有,颜色改 dim)。
384
+ - 补全:最多 8 行;选中行 `selection` bg(≥ 256 色)否则 `accent` 粗体 + `›`;label 列对齐,参数提示 `dim`,描述 `muted`;尾行 `(1/2) Tab 接受 · Esc 关闭` `dim`。`@` 文件补全同样,目录以 `/` 结尾。
385
+ - 规则:输入框与状态栏之间**不再有第三条线**——状态栏自己没有上边线,靠输入框的下边线分隔;提示行(`HintLine`)在两者之间,空时 0 行。
386
+
387
+ 40 列:
388
+
389
+ ```
390
+ ────────────────────────────────────────
391
+ › 读一下 README,说说是什么▌
392
+ ────────────────────────────────────────
393
+ ```
394
+
395
+ ### 3.10 底部状态栏
396
+
397
+ > 第五波 W5-A(wave5-plan §1)起分两种布局:`ui.statusLine: "full"`(独立终端缺省,两行)与 `"compact"`(有 profile 的嵌入宿主缺省,一行);`Ctrl+G`(`app.statusLine.toggle`)或 `/statusline [full|compact]` 切换,只影响本会话。实现:`status-line.ts`(速率行)、`status-bar.ts`(状态栏)、`status-area.ts`(装配)。
398
+
399
+ `full`,宽屏(按用户样例:速率行 `•` 与括号,状态栏 `|` 分隔):
400
+
401
+ ```
402
+ tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s) ↑12k ↓1.2k · cache 83% ♨ · [-]
403
+ Manual | shift+tab 切换 claude-opus-5-5 medium | Ctx 3.0% | vitaweave ⎇ main 5ae9e54 (+12,-3) | $0.26 | 2h24m
404
+ ```
405
+
406
+ `compact`,80 列(原单行状态栏 + git 与时长):
407
+
408
+ ```
409
+ Manual claude-opus-5-5 · ctx 3% · vitaweave ⎇ main 5ae9e54 +12 −3 · 2h24m
410
+ ```
411
+
412
+ `compact` 超宽(≥ 110 列)时 ctx 换成小表:`ctx ▮▮▮▯▯▯▯▯▯▯ 34%`;`full` 总是 `Ctx 3.0%`。
413
+
414
+ - 两区:左区「模式 + 切换提示」,右区信息,中间用空格撑开;装不下时退回单区。分隔符:`compact` 固定 `·`;`full` 状态栏 `|`、速率行 `tps: … • … (avg · ttft)` 加右区 `·`。同组项以空格相连:`full` 下行的「模型 思考级别」,以及「目录 ⎇ 分支 短提交 +a −b / (+a,-d)」。
415
+ - **速率行**(只在 `full`):`tps:` 流式中取最近 2 s 窗口的瞬时值、前缀 `accent`,结束后是该请求的平均值(生成不足 0.25 s 的整块回复记 `—`);`N tok / T`(从首 token 起);`avg` 会话均速;`ttft` 首 token 延迟。右区是从状态栏迁来的用量类项,行尾 `[-]`。流式中由 `telemetry_tick`(≤ 2 Hz)刷新,只有这一行随流变化;状态栏仍只在事件时刷新。
416
+ - 整行基色 `dim`;模式名 `text`(Bypass permissions → `warning`,Plan → `accent`);模型 `accent`;`think` 级别只显示值;`ctx` 按阈值 `success`/`warning`/`error`(`full` 保留一位小数);`rebill $x` `warning`;`queue 1` `warning`;codemode 后的 `net!` `error`(Node 权限模型与 OS 沙箱都不隔离网络时);宿主状态 `[…]` `dim`。
417
+ - 模型名缩写:`width < 100` 去掉供应商前缀;`< 60` 再去掉 `@渠道`;`< 48` 去掉 `-4-5` 之类版本后缀(按 `-\d` 截)。
418
+ - ASCII(字形表):`⎇` → `git`(`branch`)、`•` → `*`(`dot`)、`−` → `-`、`♨` → `~`;无色时信息不丢。
419
+ - 会变的数字(tps、输出量 / 耗时、avg、ttft、`full` 的 ctx、时长)在判断放不放得下时按最宽形状占位,数值变化不会让某项时有时无(40 列不抖动)。
420
+
421
+ 丢弃顺序(宽度不够时先丢优先级数字大的):
422
+
423
+ | 速率行(`full`) | 优先级 | `full` 下行 | 优先级 | `compact` | 优先级 |
424
+ | ---------------- | ------ | ---------------- | ------ | ----------------------------- | ------ |
425
+ | `tps`、`[-]` | 永不丢 | 模式 | 永不丢 | 模式 | 永不丢 |
426
+ | `ttft` | 1 | 模型 | 0 | 模型 | 0 |
427
+ | `avg` | 2 | `ctx` | 1 | `ctx` | 1 |
428
+ | 宿主状态 | 3 | `$` 费用 | 2 | 会话时长 | 3 |
429
+ | `preset` | 4 | 会话时长 | 3 | git 分支与提交 | 4 |
430
+ | `rebill` | 5 | git 分支与提交 | 4 | 目录名 | 5 |
431
+ | `cache` | 6 | 目录名 | 5 | git `+a −b` | 6 |
432
+ | `↑ ↓` token | 7 | git `+a −b` | 6 | `codemode` | 7 |
433
+ | `queue` | 8 | 思考级别 | 7 | `queue` | 8 |
434
+ | `codemode` | 9 | `shift+tab 切换` | 12 | 思考级别 | 9 |
435
+ | `N tok / T` | 10 | | | `↑ ↓` token / cache / `$` | 10–12 |
436
+ | | | | | rebill / preset / 宿主 / 提示 | 13–16 |
437
+
438
+ `< 40` 列时不显示 `shift+tab 切换`。
439
+
440
+ 40 列(`full`):
441
+
442
+ ```
443
+ tps: 99 tok/s (ttft 1.4s) [-]
444
+ Manual claude-opus | Ctx 3.0%
445
+ ```
446
+
447
+ tmux 节点里宿主要解析最后一行:嵌入缺省 `compact`,字段顺序固定、分隔符固定为 `·`,模式永远在最左,布局与第五波之前相同(输入框在倒数第 3 行);`full` 时输入框在倒数第 4 行。
448
+
449
+ ### 3.11 审批对话框
450
+
451
+ ```
452
+ ╭─ 需要确认 ───────────────────────────────────────────────────────────────────╮
453
+ │ bash 危险命令 │
454
+ │ $ rm -rf build dist/*.map > out.log │
455
+ │ │
456
+ │ 删除 build/:目录,132 个文件,1.2 MB │
457
+ │ 删除 dist/*.map:含通配符或变量,未展开,实际范围可能更大 │
458
+ │ 覆盖写入 out.log:文件,4.0 KB │
459
+ │ 这条命令可能有破坏性,请确认 │
460
+ │ │
461
+ │ 1. 允许 y │
462
+ │ 2. 本会话允许同类 a │
463
+ │ › 3. 拒绝 n Esc │
464
+ │ │
465
+ │ ↑↓ 选择 · Enter 确认 · v 完整输入 │
466
+ ╰──────────────────────────────────────────────────────────────────────────────╯
467
+ ```
468
+
469
+ - 标题由原因决定:`需要确认`(mode)/ `危险命令`(dangerous)/ `Hook 要求确认`;来源标注见下文「来源标注」(第五波 W5-U)。边框颜色随预览严重度:danger `error`、warn `warning`、其余 `border`。
470
+ - 工具名 `tool` 粗体,原因标签 `error` / `warning` / `dim`;命令 `code`;预览行按严重度着色(现有);Auto 判定行 `warning`。
471
+ - 选项编号列表(Claude Code 风格):选中行 `›` + `selection` bg;右侧按键提示 `dim`。缺省选中:dangerous → 拒绝;其余 → 允许。按键 `y / a / n / Esc / 1 2 3 / ↑↓ Enter / v` 全部有效(旧按键不废)。edit / write 的输入摘要(`−/+` 摘要、`写入 N 行`、本会话未读过标黄)保留。
472
+ - 覆盖层仍为 `bottom` 锚定全宽;对话框打开时输入框提示符变 `dim`,Loader 动词 `等待确认`。
473
+
474
+ 40 列:
475
+
476
+ ```
477
+ ╭─ 危险命令 ───────────────────────────╮
478
+ │ bash │
479
+ │ $ rm -rf build dist/*.map > out.log │
480
+ │ 删除 build/:目录,132 个文件,1.2 │
481
+ │ MB │
482
+ │ 删除 dist/*.map:含通配符,范围可能 │
483
+ │ 更大 │
484
+ │ 1. 允许 y │
485
+ │ 2. 本会话允许同类 a │
486
+ │ › 3. 拒绝 n │
487
+ │ ↑↓ Enter · v 完整输入 │
488
+ ╰──────────────────────────────────────╯
489
+ ```
490
+
491
+ `width < 56`:标题行只放原因、工具名另起一行;预览行折行;去掉空行;按键提示缩短。
492
+
493
+ **来源标注**(第五波 W5-U):子 Agent 与外部 Agent 发起的审批在边框标题与首行前加来源,选项不变(允许 / 本会话允许同类 / 拒绝)。帧黄金 `test/fixtures/tui/approval-{origin,task-agent,task-external,first-run}-*.txt`。
494
+
495
+ | 来源 | 标题 | 正文 |
496
+ | ------------------------------------------ | ------------------------------------------------ | ----------------------------------------------------------- |
497
+ | task 子 Agent 的工具调用 | `[task:explore] 需要确认`(查不到类型 `[task]`) | 同主会话 |
498
+ | 外部 Agent(claude / codex / ACP)请求权限 | `[claude · 会话 abc12345] 需要确认` | 外部 Agent 给的标题、种类(`dim`)、涉及路径与输入摘要 |
499
+ | 外部 Agent 本会话首次运行 | `首次运行外部 Agent` | `task claude 首次运行`,下面是说明(以现有登录运行)与模式 |
500
+
501
+ ```
502
+ ╭─ [claude · 会话 abc12345] 需要确认 ──────────────────────────────────────────╮
503
+ │ [claude · 会话 abc12345] Write note.txt edit │
504
+ │ note.txt │
505
+ │ content: hi │
506
+ │ │
507
+ │ claude 请求确认 │
508
+ │ │
509
+ │ › 1. 允许 y │
510
+ │ 2. 本会话允许同类 a │
511
+ │ 3. 拒绝 n Esc │
512
+ │ │
513
+ │ ↑↓ 选择 · Enter 确认 · v 完整输入 │
514
+ ╰──────────────────────────────────────────────────────────────────────────────╯
515
+ ```
516
+
517
+ Manual 模式下 `task(agent="claude")` 的 task 调用审批正文多一行「以你在 claude CLI 的登录运行(含本会话首次运行确认)」,允许后紧接着的首次运行确认自动通过(消息区一行「已允许 task(随上一次确认)」)。
518
+
519
+ **计划审批框**(第五波 W5-U,[plan.md](plan.md)、[tui.md](tui.md)「Plan 审批」):同一个底部覆盖层与 `Box`,标题 `计划待审批`;帧黄金 `test/fixtures/tui/plan-dialog-*.txt`。
520
+
521
+ ```
522
+ ╭─ 计划待审批 ─────────────────────────────────────────────────────────────────╮
523
+ │ 计划 v1 · 3 步 · ~/.local/share/ama/plans/3f2a9c1e-…-v1.md │
524
+ │ 状态栏显示回退模型 │
525
+ │ S1 读 status-bar.ts 与 status-area.ts │
526
+ │ S2 model_fallback 时记下主模型与回退模型 │
527
+ │ S3 帧黄金与文档 │
528
+ │ │
529
+ │ › 1. 批准并执行 │
530
+ │ 2. 批准,在新上下文执行 │
531
+ │ 3. 继续修改… │
532
+ │ 4. 放弃,退出 Plan 模式 │
533
+ │ │
534
+ │ ↑↓ 选择 · Enter 确认 · e 编辑计划 · Esc 留在 Plan │
535
+ ╰──────────────────────────────────────────────────────────────────────────────╯
536
+ ```
537
+
538
+ - 首行版本、步数、计划文件(`~` 缩写,`muted`);第二行计划标题(粗体);步骤最多显示 6 条,多出的一行「… 另 N 步(/plan 查看全部)」。
539
+ - 选 1 / 2 后第二屏选执行模式:`回到进入前的模式(Manual)` / `Accept edits` / `Auto`,Esc 返回第一屏。选 3 后框内变成单行输入(Enter 发送、`Ctrl+E` 外部编辑器、Esc 返回)。
540
+ - `e` 用 `$VISUAL` / `$EDITOR` 打开计划全文,界面挂起;保存后步骤列表换成一行「已在编辑器里修改:批准时以修改后的计划执行」(`warning`)。Esc:放弃这一版但留在 Plan。
541
+ - 选中项 `›` + `accent` 粗体 + `selection` 底色,与 3.11 的选项列表一致。
542
+ - `width < 56`:去空行,按键提示缩成 `↑↓ Enter · e 编辑 · Esc 留在 Plan`;ASCII 模式选中符 `>`、箭头 `^v`。
543
+
544
+ ### 3.12 模式选择器(已实现,微调)
545
+
546
+ ```
547
+ ╭─ 权限模式 ───────────────────────────────────────────────────────╮
548
+ │ │
549
+ │ Manual Default 1 │
550
+ │ 写文件、执行命令前询问 │
551
+ │ › ✓ Accept edits 2 │
552
+ │ 自动接受文件编辑,执行命令仍询问 │
553
+ │ Plan 3 │
554
+ │ 只读调研,只跑只读命令,出计划后审批执行 │
555
+ │ Auto Recommended 4 │
556
+ │ 由 ama 判断每一步:安全的自动放行,有风险的才问 │
557
+ │ Bypass permissions 5 │
558
+ │ 全部放行(危险命令仍询问) │
559
+ │ Allowlist only 6 │
560
+ │ 只放行 allow 规则命中的,其余拒绝,从不询问 │
561
+ │ │
562
+ │ ↑↓ 选择 · 1-6 直接选 · Enter 确认 · Esc 取消 │
563
+ ╰──────────────────────────────────────────────────────────────────╯
564
+ ```
565
+
566
+ - 标题 `Mode` → `权限模式`(与 /help 一致);`✔` → `✓`(glyph 表);选中行 label + 描述两行都上 `selection` bg;徽标 `Default` `dim`、`Recommended` `accent`;底部加按键提示行 `dim`;上下各留一空行(`paddingY: 1`)。
567
+ - 40 列:Box 宽 `width - 2`,描述截断(现有)。
568
+
569
+ ### 3.13 面板:/model、/session、/cache、/permissions
570
+
571
+ **/model**(居中覆盖层,可过滤)
572
+
573
+ ```
574
+ ╭─ 选择模型 ───────────────────────────────────────────────────────╮
575
+ │ › claude▌ │
576
+ │ │
577
+ │ anthropic · messages · key ✓ │
578
+ │ › ✓ claude-sonnet-4-5 200k · img │
579
+ │ claude-opus-4-1 200k · img │
580
+ │ packy · messages · key ✓ │
581
+ │ kimi-k2.5@messages 256k │
582
+ │ openai · 无 key │
583
+ │ gpt-5 400k · img │
584
+ │ (1/4) ↑↓ 选择 · Enter 确认 · Esc 取消 │
585
+ ╰──────────────────────────────────────────────────────────────────╯
586
+ ```
587
+
588
+ - 过滤框第一行,`›` `accent`;分组标题 `dim`(`无 key` 的组 `dim` 且项 `dim`);当前模型 `✓`;说明列 `muted`。
589
+
590
+ **/session、/cache**(消息区,左竖条卡片 + KeyValue + Meter)
591
+
592
+ ```
593
+ ▎ 会话 3f2a9c1e · ~/.local/share/ama/sessions/…/3f2a9c1e.jsonl
594
+ ▎ 模型 anthropic/claude-sonnet-4-5 · 思考 medium · 权限 Accept edits
595
+ ▎ 消息 用户 7 · 助手 9 · 工具调用 23
596
+ ▎ 用量 输入 3.4k · 输出 9.4k · 缓存读 118k · 缓存写 6.2k · $0.42
597
+ ▎ 上下文 ▮▮▮▯▯▯▯▯▯▯ 34% · 68k / 200k
598
+ ▎
599
+ ▎ 缓存
600
+ ▎ 输入 3.4k = 缓存读 2.2k(65%)+ 未缓存 1.2k
601
+ ▎ 报告状态 reported
602
+ ▎ 命中率 最近 84% · 会话 65%
603
+ ▎ 未命中 1 次,重计费 38.2k token ≈ $0.11(空闲超时 1)
604
+ ▎ 保温 streaming · 下次 2m10s · 期望节省 $0.18 ≥ $0.05
605
+ ```
606
+
607
+ - `▎` `border`;键列 `dim`(KeyValue 现有);值 `text`;上下文行用 `Meter`(阈值着色)。`/cache` 只输出「缓存」段。`describeSession()` 继续产出 KeyValueRow,交互模式用 `Card(KeyValue)` 渲染而不是把文本拍进 `addNotice`。
608
+
609
+ **/permissions**
610
+
611
+ ```
612
+ ▎ 权限模式 Accept edits(auto-edit)
613
+ ▎ 判定顺序 deny 规则 → Hook deny → 危险命令确认 → 权限模式 → allow 规则 /
614
+ ▎ Hook allow / 本会话记忆 → 询问
615
+ ▎ 规则(3)
616
+ ▎ allow bash(git *) [project]
617
+ ▎ allow read(**) [user]
618
+ ▎ deny bash(rm -rf *) [builtin]
619
+ ▎ 最近的 auto 判定(2)
620
+ ▎ 规则层 allow bash git status — 只读命令
621
+ ▎ 分类器 ask edit src/… — 修改受保护路径(缓存)
622
+ ```
623
+
624
+ - `allow` `success`、`deny` `error`、`ask` `warning`;来源 `[…]` `dim`。判定顺序长行折行对齐值列(KeyValue 现在不折行;加 `wrap: true` 选项)。
625
+
626
+ ### 3.14 退出摘要
627
+
628
+ 退出前追加到消息区(留在回滚里),然后 `tui.stop()`:
629
+
630
+ ```
631
+ ─ 会话 3f2a9c1e · 12 分钟 · 7 回合 · ↑128k ↓9.4k · cache 81% · $0.42(重计费 $0.03)
632
+ 恢复:ama --resume 3f2a9c1e
633
+ ```
634
+
635
+ - 整体 `dim`,会话 id 与 `ama --resume …` `text`;没有用量(0 回合)时只输出第一行到 `回合`;SIGTERM 路径也走这里(`exit()` 里 `view.add` 后 `tui.stop()`,不等异步)。
636
+
637
+ ## 4. 交互细节
638
+
639
+ - **动画**:Loader 80 ms;bash 运行中摘要行的 spinner 与 Loader 共用 `frame`(Loader 暴露 `frame` 或 ToolTracker 订阅 Loader tick),保证一帧只多改一行;`ui.animation: false` / ASCII → 静态 `·`,耗时每秒更新。
640
+ - **Ctrl+O**:全局切换(现有),范围扩大到思考块(§3.4);提示行 `工具输出:展开`。
641
+ - **流式防闪烁**:Markdown 按块缓存只重渲末块(现有);代码块固定全宽;工具调用标题行在运行中不变(spinner 不放标题,放 `⎿` 摘要行);状态栏只在事件时 `refresh()`;状态栏右区 token 数在流式期间不更新(`message_end` 才更新),避免每 chunk 改最后一行。
642
+ - **行数只增不减**:运行中 → 完成的替换保持 ≥ 原行数(bash 尾部 8 行 → 完成后 3 行 + 折叠提示会变短;允许,但差分会清多出的行——这是现有 `diff()` 覆盖的路径)。
643
+ - **宽度变化**:全量重画最后一屏(现有);Markdown / ToolView / KeyValue 缓存都带 width 键;启动头 Box 按新宽重算是否去框。
644
+ - **覆盖层**:审批 bottom 全宽;选择器 center 宽 `min(width - 2, 72)`;覆盖层打开时编辑器提示符变 dim、Loader 动词 `等待确认`。
645
+ - **tmux**:所有新字形都是 1 列;`▎`(U+258E)、`⎿`、`⏺` 在 Windows Terminal + Cascadia / 等宽回退字体下测过宽度为 1;检测失败的用户用 `AMA_ASCII=1`。
646
+
647
+ ## 5. 实施清单
648
+
649
+ ### 5.1 配置项(只加必要的)
650
+
651
+ | 键 | 类型 | 缺省 | 说明 |
652
+ | -------------- | ----------------------------- | -------- | ---------------------- |
653
+ | `ui.theme` | `"dark" \| "light" \| "auto"` | `dark` | 新增 `auto`(§2.1) |
654
+ | `ui.ascii` | boolean | 自动检测 | `AMA_ASCII=1` 等价 |
655
+ | `ui.compact` | boolean | `false` | 块间不空行、启动头无框 |
656
+ | `ui.animation` | boolean | `true` | false → spinner 静态 |
657
+
658
+ 改 `src/config/types.ts`(`UiConfig`)、`src/config/schema.ts`(`checkSection("ui", …)` 加键)、`src/config/json-schema.ts`、`docs/design.md §10.2`。`AMA_ASCII` 加进 `src/config/paths.ts` 旁的环境变量表(有文档的话)。
659
+
660
+ ### 5.2 按文件改动
661
+
662
+ **组件库 `src/tui/`**
663
+
664
+ - `component.ts`:`SemanticColor` 加 `muted` `link` `selection`;`Theme` 加 `readonly glyphs: Glyphs`。
665
+ - `glyphs.ts`(新):§2.2 的表、`detectAscii(env)`。
666
+ - `theme.ts`:新色板;`createTheme(name | "auto", { caps, ascii })`;`PlainTheme` 也带 glyphs;`levelColor()` 导出;`bg("selection")` 在 < 256 色时退化。
667
+ - `components/box.ts`:`borderColor?: SemanticColor`(审批严重度);`paddingY` 已有。新增 `components/card.ts`:左竖条卡片(`▎` 前缀 + 可选标题行),不加边框,用于压缩摘要与面板。
668
+ - `components/loader.ts`:帧表来自 `theme.glyphs.spinner`;`setMessage` 改成 `setVerb(verb, extras[])`;暴露 `frame`;`animation: false` 支持;耗时整秒才触发渲染。
669
+ - `components/markdown.ts`:颜色调整(标题 / 列表 / 代码块正文 / 链接 / 引用 / 表格规则线);`renderInline` 链接输出 `link` + ` (url)`。
670
+ - `components/editor.ts`:首行 `› ` 提示符、续行缩进 2、占位在获焦时也显示、`promptColor` 随 `disableSubmit` 变 dim、粘贴标记文案 `[粘贴 #N · M 行]`、规则线标签 dim;补全列表尾行提示。
671
+ - `components/select-list.ts`:选中行 `selection` bg(stacked 时两行)、`footer?: string`、`currentValue?: string` 画 `✓`;过滤框 `› `。
672
+ - `components/key-value.ts`:`wrap?: boolean`(值折行对齐)。
673
+ - `components/meter.ts`:字形取 glyphs。
674
+ - `components/text.ts` / `container.ts` / `spacer.ts` / `overlay.ts`:不改。
675
+ - `tui.ts` / `ansi.ts` / `terminal.ts`:不改(新增一条测试锁定新字形宽度为 1)。
676
+
677
+ **交互模式 `src/modes/interactive/`**
678
+
679
+ - `startup-header.ts`(新):由 `StartupInfo` 结构体画 §3.1 的框 / 无框两态;`cli/startup-screen.ts` 新增 `startupInfo(runtime): StartupInfo`(结构化字段),`buildStartupScreen` 保留给 line 模式。
680
+ - `message-view.ts`:`addUser` 续行缩进与中文标签;思考块 `✻` + 展开态(`setThinkingExpanded`);`addNotice` 字形走 glyphs,`info` 级不加前缀;`addSummaryCard` 改 Card;回合分组(相邻 `ToolView` 之间不加 Spacer;`compact` 全部不加);新增 `addExitSummary(stats)`、`addPanel(title, rows)`。
681
+ - `tool-view.ts`:标题 `⏺ name summary`;新增 `summaryLine()`(按工具:read 行数、edit `N 处修改 · +a −b`、bash `退出 c · 耗时 · 行数`、grep `N 处匹配 · M 个文件`、codemode `N 个内层调用`、task 状态);结果正文缩进 4;diff 行号列(`width ≥ 60`);运行中 `⎿ ⠋ 运行中 · Ns` 使用共享 spinner frame;需要在 `finish()` 记录耗时(`start` 时记 `now()`,options 加 `now`)。
682
+ - `status-bar.ts`:两区布局、模型名缩写、`shift+tab 切换` 提示(优先级 12)、`preset` 仅非 default、ctx Meter(≥ 110 列)。
683
+ - `approval-dialog.ts`:编号选项 + 方向键 / 数字 / 旧按键;缺省选中按原因;标题按原因;`Box` 边框色按严重度;`< 56` 列紧凑态。
684
+ - `pickers.ts`:`title: "权限模式"`、`footer`、`currentValue`;模型选择器 `currentValue` 画 `✓`。
685
+ - `commands.ts`:`/session` `/cache` `/permissions` 走 `ui.panel(title, rows)`(CommandUi 新增),不再拍成文本 notice;`/help` 文案同步新按键。
686
+ - `key-dispatch.ts`:Ctrl+O 同时切思考块;审批打开时不拦 ↑↓ / 数字(`inactive()` 已覆盖)。
687
+ - `interactive-mode.ts`:Loader 动词状态机(§3.7);编辑器 `placeholder`;`exit()` 前 `view.addExitSummary`;主题 `auto` / ascii / compact / animation 接线;去掉 `tui.addChild(new Spacer())`(消息区与排队消息之间的空行改由排队组件自带)。
688
+ - `startup-ui.ts`:迷你 TUI 的问句 `? ` 改 `› `?——**不改**,保持启动期问答与正文区分。
689
+
690
+ **文档与示例**
691
+
692
+ - `docs/tui.md`:布局图、按键表、配置项、ASCII 模式与排错;`docs/design.md §12.5–§12.7` 同步(语义色 14 个、glyphs)。
693
+ - `examples/tui-demo.ts`:加 Card、新 Loader API、审批编号选项演示。
694
+
695
+ ### 5.3 新增 / 更新的帧黄金
696
+
697
+ `test/fixtures/tui/`(80x24 与 40x24 各一份,除注明):
698
+
699
+ | 文件 | 场景 |
700
+ | ------------------------------------ | ------------------------------------------------------------------------ |
701
+ | `run-*.txt`(更新) | 启动头 normal、输入、工具运行中、完成、Ctrl+O、退出摘要 |
702
+ | `header-quiet-80x24.txt`(新) | `quietStartup: header` 一行头 |
703
+ | `markdown-*.txt`(新,tui-frames) | 标题 / 列表 / 代码块 / 链接 / 引用 / 表格 |
704
+ | `thinking-expanded-*.txt`(新) | Ctrl+O 展开思考块 |
705
+ | `tools-*.txt`(新) | read / edit diff / bash 运行中与完成 / grep / codemode 嵌套 / task,一屏 |
706
+ | `notices-80x24.txt`(新) | 错误 / 重试 / 压缩卡 / 缓存未命中 / Hook 阻止 |
707
+ | `loader-verbs-80x24.txt`(新,多帧) | 思考中 → 回复中 → 运行 bash → 等待确认 |
708
+ | `editor-*.txt`(新) | 占位 / 多行溢出 / 粘贴折叠 / 补全弹层 |
709
+ | `status-widths.txt`(新) | 40 / 60 / 80 / 110 列状态栏各一行 |
710
+ | `approval-*.txt`(更新) | 编号选项、danger 红框、`< 56` 紧凑态 |
711
+ | `mode-picker-*.txt`(更新) | 新标题、底部提示、选中 bg(MemoryTerminal 无色,只验布局) |
712
+ | `panel-session-80x24.txt`(新) | /session 卡片 |
713
+ | `ascii-run-80x24.txt`(新) | `AMA_ASCII=1` 整条 run 序列 |
714
+ | `theme-16color.test.ts`(新单测) | 14 色 → 16 色索引表锁定;新字形宽度为 1 |
715
+
716
+ 更新命令不变:`AMA_UPDATE_GOLDEN=1 pnpm vitest run src/modes/interactive src/tui`。
717
+
718
+ ### 5.4 提交顺序(细粒度,每步可独立合并、测试绿)
719
+
720
+ 1. `tui: 新增 glyphs.ts 与 Theme.glyphs;ASCII 检测`(纯增量,PlainTheme 带 glyphs;无视觉变化)
721
+ 2. `tui: 语义色加 muted/link/selection,新色板,16 色表测试,levelColor`
722
+ 3. `config: ui.theme auto / ui.ascii / ui.compact / ui.animation`(schema + types + json-schema + 文档)
723
+ 4. `tui: Loader 动词 API、共享 frame、animation 关闭`
724
+ 5. `tui: Card 组件;Box.borderColor;KeyValue.wrap;Meter 字形`
725
+ 6. `tui: Markdown 配色与链接 / 表格 / 引用样式`(更新 markdown 单测与新 markdown 帧黄金)
726
+ 7. `tui: Editor 提示符、续行缩进、占位、粘贴标记、补全尾行`(editor 单测 + editor 帧黄金)
727
+ 8. `tui: SelectList 选中底色、footer、currentValue`
728
+ 9. `interactive: 启动头组件 + startupInfo`(run 黄金更新 1/4)
729
+ 10. `interactive: message-view 用户续行 / 思考块 / 提示字形 / 压缩卡 / 回合分组`
730
+ 11. `interactive: tool-view ⏺/⎿ 布局、摘要行、diff 行号、耗时`(tools 黄金)
731
+ 12. `interactive: 状态栏两区与缩写`(status-widths 黄金)
732
+ 13. `interactive: Loader 动词状态机接线`(loader-verbs 黄金)
733
+ 14. `interactive: 审批对话框编号选项与严重度边框`(approval 黄金)
734
+ 15. `interactive: 选择器标题 / footer / ✓;/session /cache /permissions 面板`(mode-picker、panel 黄金)
735
+ 16. `interactive: 退出摘要;Ctrl+O 含思考块`(run 黄金收尾)
736
+ 17. `docs/examples: tui.md、design.md §12、tui-demo`
737
+ 18. `test: ascii-run 黄金 + 全量黄金审阅`
738
+
739
+ ### 5.5 风险
740
+
741
+ | 风险 | 影响 | 对策 |
742
+ | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
743
+ | 多行组件高度在差分下变化(bash 尾部 8 行 → 完成 4 行;思考展开;审批紧凑态) | 下方所有行位移,`diff()` 重写从首变化行到底;在 24 行终端里几乎等于整屏重写 | 可接受(现有行为);保证一帧内只发生一次高度变化:`finish()` 与 `update()` 不在同一 tick 触发两次渲染(`requestRender` 已合并到 nextTick) |
744
+ | 首变化行滚出视口触发 `fullViewport` | 工具调用很长时每次追加都全视口重画 | 结果正文折叠上限不变(3 / 8 / 12 行),折叠态高度有界 |
745
+ | `selection` bg 在 tmux 老版本 / 16 色下残留 | 选中行尾出现色块 | 只在 ≥ 256 色启用;每行末尾 `\x1b[0m`(`compose()` 已保证);`spliceLine` 中段后已有 reset |
746
+ | `⏺` `⎿` `▎` 在个别字体下宽度不一致 | 列错位、差分误判 | 宽度表以 wcwidth 为准,不随字体改;文档给 `AMA_ASCII=1`;黄金用 MemoryTerminal 不受字体影响 |
747
+ | 状态栏两区用空格撑开 | 窄屏频繁回退单区,文本抖动 | 两区切换阈值取整 10 列(hysteresis 无需,resize 本来全量重画) |
748
+ | Loader 动词状态机与事件乱序(tool_end 先于 message_update) | 动词闪回 | 动词按「当前最深状态」取:有运行中工具 → 运行 X;否则有流式助手消息 → 思考 / 回复;否则压缩 / 重试 |
749
+ | `auto` 主题猜错 | 浅色终端下 dark 色板对比度差 | 文档明说;`/theme` 不做,改配置即可 |
750
+ | 黄金文件数翻倍 | 审阅成本 | 每个新黄金只覆盖一屏;`AMA_UPDATE_GOLDEN` 后用 `git diff --stat` 审 |
751
+ | `SemanticColor` 契约变更 | 外部用 `@armadra/agent/tui` 的宿主自定义 Theme 编译失败 | 新字段都是必填——改为 Theme 实现里由 `createTheme` 填充,宿主若自实现 Theme 需补 3 个颜色与 `glyphs`;在 CHANGELOG 标 breaking |