@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,309 @@
1
+ /**
2
+ * 回滚确认面板(rewind-plan §4):底部覆盖层,左竖条样式与 `/session` 面板一致(`Card`)。[RW-C]
3
+ *
4
+ * - 标题「回滚到这条消息之前」+ 相对时间;消息原文最多 3 行(超出计数)。
5
+ * - 选项编号列表:恢复代码和对话 / 恢复对话 / 恢复代码(两个代码项只在 dry-run 有改动时出现)/
6
+ * 从这里摘要 / 摘要到这里 / 取消。每项下一行是预览(「将恢复 N 个文件 +x −y」「代码不变 · 对话将分叉」…);
7
+ * 宽 < 56 时只给选中项画预览、去空行。
8
+ * - 两个摘要项可以在行内输入说明:选中后直接打字,Enter 提交;数字键直接执行(不带说明);
9
+ * 有说明时 Esc 先清空说明,再按才关闭。
10
+ * - 冲突:选了代码类且 dry-run 有冲突 → 进入第二步「跳过冲突文件 / 覆盖冲突文件 / 返回」,
11
+ * 覆盖对应 `onConflict: "overwrite"`。
12
+ * - 明细:冲突与无法恢复的文件(各最多 5 个)、git HEAD 变化提示与两条命令(只显示,不执行)。
13
+ */
14
+ import { Card, defaultKeybindings, isPasteData, isPrintableText, matchesKey, padToWidth, truncateToWidth, unwrapPaste, wrapTextWithAnsi, } from "../../tui.js";
15
+ import { REWIND_DETAIL_MAX, SKIP_REASON_TEXT, gitHintLines, hasCodeChanges, restorePreview, } from "./rewind-text.js";
16
+ import { relativeTime } from "./startup-ui.js";
17
+ /** 宽度低于它(覆盖层外宽)时紧凑布局。 */
18
+ const COMPACT_WIDTH = 56;
19
+ const MESSAGE_LINES = 3;
20
+ const DIVERGE = "对话将分叉";
21
+ /** 面板的选项(按显示顺序)。 */
22
+ export function rewindOptions(model, ascii = false) {
23
+ const code = model.preview?.code;
24
+ const withCode = hasCodeChanges(code);
25
+ const options = [];
26
+ if (withCode) {
27
+ options.push({
28
+ action: "both",
29
+ label: "恢复代码和对话",
30
+ preview: `${restorePreview(code, ascii)} · ${DIVERGE}`,
31
+ });
32
+ }
33
+ options.push({
34
+ action: "conversation",
35
+ label: "恢复对话",
36
+ preview: withCode ? `代码不变(保留之后的修改)· ${DIVERGE}` : `代码不变 · ${DIVERGE}`,
37
+ });
38
+ if (withCode) {
39
+ options.push({
40
+ action: "code",
41
+ label: "恢复代码",
42
+ preview: `${restorePreview(code, ascii)} · 对话不变`,
43
+ });
44
+ }
45
+ options.push({
46
+ action: "summarize-from",
47
+ label: "从这里摘要",
48
+ preview: `${DIVERGE},离开的部分写成摘要`,
49
+ input: true,
50
+ }, {
51
+ action: "summarize-up-to",
52
+ label: "摘要到这里",
53
+ preview: "之前的对话压缩成摘要,之后的保留",
54
+ input: true,
55
+ }, { action: "cancel", label: "取消" });
56
+ return options;
57
+ }
58
+ const CONFLICT_OPTIONS = [
59
+ { value: "skip", label: "跳过冲突文件,恢复其余" },
60
+ { value: "overwrite", label: "覆盖冲突文件" },
61
+ { value: "back", label: "返回" },
62
+ ];
63
+ /** 行数组组件(交给 Card 加竖条)。 */
64
+ class Lines {
65
+ build;
66
+ constructor(build) {
67
+ this.build = build;
68
+ }
69
+ render(width) {
70
+ return this.build(width);
71
+ }
72
+ invalidate() { }
73
+ }
74
+ export class RewindPanel {
75
+ model;
76
+ host;
77
+ done;
78
+ focused = false;
79
+ selected = 0;
80
+ inputs = new Map();
81
+ stage;
82
+ /** 终端放不下时:原文 1 行、文件清单并成一行、git 提示去掉说明。 */
83
+ tight = false;
84
+ options;
85
+ constructor(model, host, done) {
86
+ this.model = model;
87
+ this.host = host;
88
+ this.done = done;
89
+ this.options = rewindOptions(model, host.theme.glyphs.ascii);
90
+ }
91
+ /** 当前选中项(测试用)。 */
92
+ get selectedOption() {
93
+ return this.options[this.selected];
94
+ }
95
+ /** 选中项的说明(测试用)。 */
96
+ inputOf(action) {
97
+ return this.inputs.get(action) ?? "";
98
+ }
99
+ get conflicts() {
100
+ return this.model.preview?.code?.conflicts ?? [];
101
+ }
102
+ choose(option, instructions) {
103
+ if (option.action === "cancel")
104
+ return this.done(undefined);
105
+ if ((option.action === "both" || option.action === "code") && this.conflicts.length > 0) {
106
+ this.stage = { action: option.action, selected: 0 };
107
+ return;
108
+ }
109
+ const choice = { action: option.action };
110
+ const text = instructions?.trim() ?? "";
111
+ if (option.input === true && text !== "")
112
+ choice.instructions = text;
113
+ this.done(choice);
114
+ }
115
+ handleInput(data) {
116
+ const keys = this.host.keybindings ?? defaultKeybindings;
117
+ if (this.stage !== undefined)
118
+ return this.conflictInput(data, keys);
119
+ const option = this.options[this.selected];
120
+ const action = option.action === "cancel" ? undefined : option.action;
121
+ const text = action === undefined ? "" : (this.inputs.get(action) ?? "");
122
+ const typing = option.input === true && text !== "";
123
+ if (keys.matches(data, "tui.select.up"))
124
+ this.move(-1);
125
+ else if (keys.matches(data, "tui.select.down"))
126
+ this.move(1);
127
+ else if (matchesKey(data, "enter"))
128
+ this.choose(option, text);
129
+ else if (matchesKey(data, "escape") || keys.matches(data, "app.clear")) {
130
+ if (typing && action !== undefined)
131
+ this.inputs.set(action, "");
132
+ else
133
+ this.done(undefined);
134
+ }
135
+ else if (/^[1-9]$/.test(data) && !typing) {
136
+ const index = Number(data) - 1;
137
+ if (index < this.options.length) {
138
+ this.selected = index;
139
+ this.choose(this.options[index], undefined);
140
+ }
141
+ }
142
+ else if (option.input === true && action !== undefined) {
143
+ if (matchesKey(data, "backspace"))
144
+ this.inputs.set(action, [...text].slice(0, -1).join(""));
145
+ else if (isPasteData(data)) {
146
+ this.inputs.set(action, text + unwrapPaste(data).replace(/\s+/g, " "));
147
+ }
148
+ else if (isPrintableText(data))
149
+ this.inputs.set(action, text + data);
150
+ }
151
+ }
152
+ move(delta) {
153
+ const n = this.options.length;
154
+ this.selected = (this.selected + delta + n) % n;
155
+ }
156
+ conflictInput(data, keys) {
157
+ const stage = this.stage;
158
+ const n = CONFLICT_OPTIONS.length;
159
+ const pick = (index) => {
160
+ const value = CONFLICT_OPTIONS[index].value;
161
+ if (value === "back")
162
+ this.stage = undefined;
163
+ else
164
+ this.done({ action: stage.action, onConflict: value });
165
+ };
166
+ if (keys.matches(data, "tui.select.up"))
167
+ stage.selected = (stage.selected + n - 1) % n;
168
+ else if (keys.matches(data, "tui.select.down"))
169
+ stage.selected = (stage.selected + 1) % n;
170
+ else if (matchesKey(data, "enter"))
171
+ pick(stage.selected);
172
+ else if (/^[1-3]$/.test(data))
173
+ pick(Number(data) - 1);
174
+ else if (matchesKey(data, "escape") || keys.matches(data, "app.clear"))
175
+ this.stage = undefined;
176
+ }
177
+ render(width) {
178
+ const { theme } = this.host;
179
+ const time = relativeTime(new Date(this.model.point.timestamp).toISOString(), this.model.now);
180
+ const build = (tight) => {
181
+ this.tight = tight;
182
+ return new Card(new Lines((w) => this.body(w, tight || width < COMPACT_WIDTH)), {
183
+ theme,
184
+ title: "回滚到这条消息之前",
185
+ ...(time !== "" ? { subtitle: time } : {}),
186
+ }).render(width);
187
+ };
188
+ const lines = build(false);
189
+ const rows = this.host.rows?.();
190
+ return rows !== undefined && lines.length > rows ? build(true) : lines;
191
+ }
192
+ invalidate() { }
193
+ body(width, compact) {
194
+ const { theme } = this.host;
195
+ const arrows = theme.glyphs.arrowUp + theme.glyphs.arrowDown;
196
+ const out = [...this.messageLines(width)];
197
+ const gap = () => {
198
+ if (!compact)
199
+ out.push("");
200
+ };
201
+ gap();
202
+ if (this.stage !== undefined) {
203
+ const conflicts = this.conflicts;
204
+ out.push(...this.fileLines(theme.fg("warning", `${conflicts.length} 个文件在回合外被改过:`), conflicts, width));
205
+ gap();
206
+ out.push(...CONFLICT_OPTIONS.map((o, i) => this.optionLine(`${i + 1}. ${o.label}`, i === this.stage.selected, width)));
207
+ gap();
208
+ out.push(theme.fg("dim", compact
209
+ ? `${arrows} Enter · Esc 返回`
210
+ : `${arrows} 选择 · 1-3 直接选 · Enter 确认 · Esc 返回`));
211
+ return out;
212
+ }
213
+ this.options.forEach((option, i) => {
214
+ const selected = i === this.selected;
215
+ out.push(this.optionLine(this.optionLabel(option, i, selected), selected, width));
216
+ if (option.preview !== undefined && (selected || !compact)) {
217
+ const wrapped = wrapTextWithAnsi(theme.fg("dim", option.preview), Math.max(1, width - 5));
218
+ out.push(...wrapped.map((line) => ` ${line}`));
219
+ }
220
+ });
221
+ const details = this.detailLines(width);
222
+ if (details.length > 0) {
223
+ gap();
224
+ out.push(...details);
225
+ }
226
+ gap();
227
+ const n = this.options.length;
228
+ out.push(theme.fg("dim", compact
229
+ ? `${arrows} Enter · 1-${n} · Esc 取消`
230
+ : `${arrows} 选择 · 1-${n} 直接执行 · Enter 确认 · Esc 取消`));
231
+ return out;
232
+ }
233
+ messageLines(width) {
234
+ const { theme } = this.host;
235
+ const prompt = theme.glyphs.prompt;
236
+ const all = this.model.point.text.replace(/\r\n?/g, "\n").split("\n");
237
+ while (all.length > 1 && all[all.length - 1].trim() === "")
238
+ all.pop();
239
+ const max = this.tight ? 1 : MESSAGE_LINES;
240
+ const shown = all
241
+ .slice(0, max)
242
+ .map((line, i) => truncateToWidth(`${i === 0 ? theme.fg("accent", prompt) : " "} ${line}`, width));
243
+ if (all.length > max && !this.tight) {
244
+ shown.push(theme.fg("dim", ` ${theme.glyphs.ellipsis} 另 ${all.length - max} 行`));
245
+ }
246
+ return shown;
247
+ }
248
+ optionLabel(option, index, selected) {
249
+ const { theme } = this.host;
250
+ let label = `${index + 1}. ${option.label}`;
251
+ if (option.input === true && option.action !== "cancel") {
252
+ const text = this.inputs.get(option.action) ?? "";
253
+ const cursor = selected ? (theme.glyphs.ascii ? "_" : "▏") : "";
254
+ if (text !== "")
255
+ label += ` 说明:${text}${cursor}`;
256
+ else if (selected)
257
+ label += theme.fg("dim", " 可输入说明");
258
+ }
259
+ return label;
260
+ }
261
+ optionLine(label, selected, width) {
262
+ const { theme } = this.host;
263
+ const left = `${selected ? theme.glyphs.prompt : " "} ${label}`;
264
+ if (!selected)
265
+ return truncateToWidth(left, width);
266
+ const line = padToWidth(truncateToWidth(theme.fg("accent", theme.bold(left)), width), width);
267
+ return theme.bg("selection", line);
268
+ }
269
+ /** 文件清单:每个一行(最多 5 个);紧凑时接在 `head` 后面并成一行。 */
270
+ fileLines(head, files, width, note) {
271
+ if (this.tight)
272
+ return [truncateToWidth(`${head}${files.join("、")}`, width)];
273
+ const lines = files
274
+ .slice(0, REWIND_DETAIL_MAX)
275
+ .map((f) => truncateToWidth(` ${f}${note !== undefined ? note(f) : ""}`, width));
276
+ lines.unshift(head);
277
+ if (files.length > REWIND_DETAIL_MAX) {
278
+ lines.push(this.host.theme.fg("dim", ` ${this.host.theme.glyphs.ellipsis} 另 ${files.length - REWIND_DETAIL_MAX} 个`));
279
+ }
280
+ return lines;
281
+ }
282
+ detailLines(width) {
283
+ const { theme } = this.host;
284
+ const out = [];
285
+ const { point, preview, previewError } = this.model;
286
+ if (!point.hasCheckpoint)
287
+ out.push(theme.fg("dim", "仅对话:这条消息没有代码检查点"));
288
+ if (previewError !== undefined)
289
+ out.push(theme.fg("warning", `代码预览失败:${previewError}`));
290
+ const code = preview?.code;
291
+ if (code !== undefined && code.conflicts.length > 0) {
292
+ const head = this.tight
293
+ ? `冲突 ${code.conflicts.length} 个:`
294
+ : `冲突 ${code.conflicts.length} 个(回合外被改过,缺省跳过):`;
295
+ out.push(...this.fileLines(theme.fg("warning", head), code.conflicts, width));
296
+ }
297
+ if (code !== undefined && code.skipped.length > 0) {
298
+ const reasons = new Map(code.skipped.map((s) => [s.path, SKIP_REASON_TEXT[s.reason]]));
299
+ out.push(...this.fileLines(theme.fg("dim", `无法恢复 ${code.skipped.length} 个:`), code.skipped.map((s) => s.path), width, (f) => theme.fg("dim", `:${reasons.get(f) ?? ""}`)));
300
+ }
301
+ if (preview?.gitHint !== undefined) {
302
+ const [head, ...commands] = gitHintLines(preview.gitHint, theme.glyphs.ascii, this.tight);
303
+ out.push(...wrapTextWithAnsi(theme.fg("warning", head), width));
304
+ for (const command of commands)
305
+ out.push(truncateToWidth(theme.fg("code", command), width));
306
+ }
307
+ return out;
308
+ }
309
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 回滚界面的文案(rewind-plan §4):交互模式的列表 / 面板 / 通知与 line 模式 `/rewind` 共用。[RW-C]
3
+ *
4
+ * - 统计:`N 文件 +x −y`(列表徽标)、`将恢复 N 个文件 +x −y`(面板预览);ASCII 模式减号用 `-`。
5
+ * - 结果:`已恢复 N 个文件,跳过 M 个(冲突 1、符号链接 1)` / `没有文件被恢复…` / `代码没有变化`,
6
+ * 之后最多 5 行跳过明细。
7
+ * - git:HEAD 与记录不同时给两条命令(只显示,不执行)。
8
+ * - 错误码 `busy / no_checkpoint / rewind_failed` 换成中文说明。
9
+ */
10
+ import type { CodeRestoreResult, RewindResult, RewindSkipReason } from "../../checkpoints/types.js";
11
+ /** 明细最多列出的文件数。 */
12
+ export declare const REWIND_DETAIL_MAX = 5;
13
+ export declare const SKIP_REASON_TEXT: Readonly<Record<RewindSkipReason, string>>;
14
+ /** 一行文本:空白压成一个空格,超长截断。 */
15
+ export declare function oneLine(text: string, max?: number, ellipsis?: string): string;
16
+ /** 将恢复 / 已恢复的文件数(恢复 + 删除)。 */
17
+ export declare function codeFileCount(code: CodeRestoreResult): number;
18
+ /** 有没有代码可恢复(含冲突文件)。 */
19
+ export declare function hasCodeChanges(code: CodeRestoreResult | undefined): boolean;
20
+ export declare function diffStat(code: CodeRestoreResult, ascii?: boolean): string;
21
+ /** 列表高亮行右侧的徽标。 */
22
+ export declare function badgeText(code: CodeRestoreResult, ascii?: boolean): string;
23
+ /** 面板里代码类选项的预览。 */
24
+ export declare function restorePreview(code: CodeRestoreResult, ascii?: boolean): string;
25
+ /** 跳过明细(最多 5 行,其余计数)。 */
26
+ export declare function skipDetailLines(code: CodeRestoreResult, overwrite?: boolean): string[];
27
+ /** 代码恢复结果一行(不含明细)。overwrite 时冲突文件已被覆盖,算作已恢复。 */
28
+ export declare function codeResultText(code: CodeRestoreResult, overwrite?: boolean): string;
29
+ /** 结果通知(多行):代码结果 + 明细 + 对话说明 + git 提示。 */
30
+ export declare function rewindResultLines(result: RewindResult, options?: {
31
+ overwrite?: boolean;
32
+ conversation?: string;
33
+ }): string[];
34
+ /** HEAD 变化提示:一行说明 + 两条命令(不执行);`brief` 去掉括号说明。 */
35
+ export declare function gitHintLines(hint: {
36
+ recordedHead: string;
37
+ currentHead: string;
38
+ }, ascii?: boolean, brief?: boolean): string[];
39
+ /** 回滚接口的错误 → 中文说明。 */
40
+ export declare function rewindErrorText(error: unknown): string;
@@ -0,0 +1,139 @@
1
+ /**
2
+ * 回滚界面的文案(rewind-plan §4):交互模式的列表 / 面板 / 通知与 line 模式 `/rewind` 共用。[RW-C]
3
+ *
4
+ * - 统计:`N 文件 +x −y`(列表徽标)、`将恢复 N 个文件 +x −y`(面板预览);ASCII 模式减号用 `-`。
5
+ * - 结果:`已恢复 N 个文件,跳过 M 个(冲突 1、符号链接 1)` / `没有文件被恢复…` / `代码没有变化`,
6
+ * 之后最多 5 行跳过明细。
7
+ * - git:HEAD 与记录不同时给两条命令(只显示,不执行)。
8
+ * - 错误码 `busy / no_checkpoint / rewind_failed` 换成中文说明。
9
+ */
10
+ import { isAmaError } from "../../errors.js";
11
+ /** 明细最多列出的文件数。 */
12
+ export const REWIND_DETAIL_MAX = 5;
13
+ export const SKIP_REASON_TEXT = {
14
+ symlink: "符号链接",
15
+ hardlink: "硬链接",
16
+ not_regular: "不是普通文件",
17
+ parent_moved: "父目录被移动",
18
+ too_large: "文件过大未备份",
19
+ backup_missing: "备份缺失",
20
+ };
21
+ /** 一行文本:空白压成一个空格,超长截断。 */
22
+ export function oneLine(text, max = 60, ellipsis = "…") {
23
+ const flat = text.replace(/\s+/g, " ").trim();
24
+ return flat.length > max ? `${flat.slice(0, max - ellipsis.length)}${ellipsis}` : flat;
25
+ }
26
+ /** 将恢复 / 已恢复的文件数(恢复 + 删除)。 */
27
+ export function codeFileCount(code) {
28
+ return code.restored.length + code.deleted.length;
29
+ }
30
+ /** 有没有代码可恢复(含冲突文件)。 */
31
+ export function hasCodeChanges(code) {
32
+ return code !== undefined && codeFileCount(code) + code.conflicts.length > 0;
33
+ }
34
+ export function diffStat(code, ascii = false) {
35
+ return `+${code.insertions} ${ascii ? "-" : "−"}${code.deletions}`;
36
+ }
37
+ /** 列表高亮行右侧的徽标。 */
38
+ export function badgeText(code, ascii = false) {
39
+ if (!hasCodeChanges(code))
40
+ return "无代码改动";
41
+ if (codeFileCount(code) === 0)
42
+ return `冲突 ${code.conflicts.length} 个`;
43
+ return `${codeFileCount(code)} 文件 ${diffStat(code, ascii)}`;
44
+ }
45
+ /** 面板里代码类选项的预览。 */
46
+ export function restorePreview(code, ascii = false) {
47
+ const conflicts = code.conflicts.length;
48
+ if (codeFileCount(code) === 0)
49
+ return `只有冲突文件 ${conflicts} 个(缺省跳过)`;
50
+ const suffix = conflicts > 0 ? `,冲突 ${conflicts} 个` : "";
51
+ return `将恢复 ${codeFileCount(code)} 个文件 ${diffStat(code, ascii)}${suffix}`;
52
+ }
53
+ function skips(code, overwrite) {
54
+ return [
55
+ ...(overwrite ? [] : code.conflicts.map((path) => ({ path, reason: "冲突" }))),
56
+ ...code.skipped.map((s) => ({ path: s.path, reason: SKIP_REASON_TEXT[s.reason] })),
57
+ ...code.failed.map((f) => ({ path: f.path, reason: `失败:${f.message}` })),
58
+ ];
59
+ }
60
+ function reasonCounts(list) {
61
+ const counts = new Map();
62
+ for (const skip of list) {
63
+ const key = skip.reason.startsWith("失败") ? "失败" : skip.reason;
64
+ counts.set(key, (counts.get(key) ?? 0) + 1);
65
+ }
66
+ return [...counts].map(([reason, n]) => `${reason} ${n}`).join("、");
67
+ }
68
+ /** 跳过明细(最多 5 行,其余计数)。 */
69
+ export function skipDetailLines(code, overwrite = false) {
70
+ const list = skips(code, overwrite);
71
+ const lines = list.slice(0, REWIND_DETAIL_MAX).map((s) => ` ${s.path}:${s.reason}`);
72
+ if (list.length > REWIND_DETAIL_MAX)
73
+ lines.push(` … 另 ${list.length - REWIND_DETAIL_MAX} 个`);
74
+ return lines;
75
+ }
76
+ /** 代码恢复结果一行(不含明细)。overwrite 时冲突文件已被覆盖,算作已恢复。 */
77
+ export function codeResultText(code, overwrite = false) {
78
+ const done = overwrite
79
+ ? new Set([...code.restored, ...code.deleted, ...code.conflicts]).size
80
+ : codeFileCount(code);
81
+ const skipped = skips(code, overwrite);
82
+ const why = skipped.length > 0 ? `(${reasonCounts(skipped)})` : "";
83
+ if (done > 0) {
84
+ return skipped.length > 0
85
+ ? `已恢复 ${done} 个文件,跳过 ${skipped.length} 个${why}`
86
+ : `已恢复 ${done} 个文件`;
87
+ }
88
+ if (skipped.length > 0)
89
+ return `没有文件被恢复,跳过 ${skipped.length} 个${why}`;
90
+ return "代码没有变化";
91
+ }
92
+ /** 结果通知(多行):代码结果 + 明细 + 对话说明 + git 提示。 */
93
+ export function rewindResultLines(result, options = {}) {
94
+ const lines = [];
95
+ const overwrite = options.overwrite === true;
96
+ if (result.code !== undefined) {
97
+ lines.push(codeResultText(result.code, overwrite), ...skipDetailLines(result.code, overwrite));
98
+ }
99
+ if (result.conversation !== undefined && options.conversation !== undefined) {
100
+ lines.push(options.conversation);
101
+ }
102
+ if (result.gitHint !== undefined)
103
+ lines.push(...gitHintLines(result.gitHint));
104
+ return lines;
105
+ }
106
+ function short(hash, n) {
107
+ return hash.slice(0, n);
108
+ }
109
+ /** HEAD 变化提示:一行说明 + 两条命令(不执行);`brief` 去掉括号说明。 */
110
+ export function gitHintLines(hint, ascii = false, brief = false) {
111
+ const recorded = short(hint.recordedHead, 12);
112
+ const change = `${short(hint.recordedHead, 7)} ${ascii ? "->" : "→"} ${short(hint.currentHead, 7)}`;
113
+ return [
114
+ `git HEAD 已变化:${change}${brief ? "" : "(ama 不动 git)"}`,
115
+ ` git log --oneline ${recorded}..HEAD`,
116
+ ` git reset --soft ${recorded}`,
117
+ ];
118
+ }
119
+ /** 回滚接口的错误 → 中文说明。 */
120
+ export function rewindErrorText(error) {
121
+ if (isAmaError(error)) {
122
+ switch (error.code) {
123
+ case "busy":
124
+ return "正在运行,不能回滚(先按 Esc 中断)";
125
+ case "no_checkpoint":
126
+ return "这条消息没有代码检查点,只能恢复对话";
127
+ case "rewind_failed": {
128
+ const detail = error.detail;
129
+ const failed = (detail?.failed ?? []).map((f) => `${f.path}:${f.message}`);
130
+ return failed.length > 0
131
+ ? `没有文件被恢复:${failed.slice(0, REWIND_DETAIL_MAX).join(";")}`
132
+ : "没有文件被恢复";
133
+ }
134
+ default:
135
+ return error.message;
136
+ }
137
+ }
138
+ return error instanceof Error ? error.message : String(error);
139
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 交互界面的会话事件分派:`SessionEvent` → 消息区、工具视图、状态栏、运行指示。[B7]
3
+ * 从 interactive-mode.ts 拆出(W5-U:第五波事件先交给 agent-ui.ts,预算到限的 agent_settled warning 不重复显示)。
4
+ */
5
+ import type { AgentSession, SessionEvent } from "../../agent/types.js";
6
+ import type { AgentUi } from "./agent-ui.js";
7
+ import type { MessageView, NoticeLevel } from "./message-view.js";
8
+ import type { RunIndicator } from "./run-indicator.js";
9
+ import type { StatusArea } from "./status-area.js";
10
+ import type { StatusBar } from "./status-bar.js";
11
+ import type { ToolTracker } from "./tool-view.js";
12
+ export interface SessionEventDeps {
13
+ view: MessageView;
14
+ tools: ToolTracker;
15
+ status: StatusBar;
16
+ area: StatusArea;
17
+ agentUi(): AgentUi;
18
+ indicator: RunIndicator;
19
+ session(): AgentSession;
20
+ setQueue(steering: readonly string[], followUp: readonly string[]): void;
21
+ notice(level: NoticeLevel, text: string): void;
22
+ render(): void;
23
+ }
24
+ export declare function createSessionEventHandler(deps: SessionEventDeps): (event: SessionEvent) => void;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * 交互界面的会话事件分派:`SessionEvent` → 消息区、工具视图、状态栏、运行指示。[B7]
3
+ * 从 interactive-mode.ts 拆出(W5-U:第五波事件先交给 agent-ui.ts,预算到限的 agent_settled warning 不重复显示)。
4
+ */
5
+ import { cacheEventNotice, cacheNoticesEnabled } from "../session-report.js";
6
+ import { compactionErrorText, ImageBudgetNotices, LIMIT_WARNING } from "./event-notices.js";
7
+ export function createSessionEventHandler(deps) {
8
+ const { view, tools, status, area, agentUi, indicator, session, setQueue, notice, render } = deps;
9
+ const images = new ImageBudgetNotices((text) => notice("info", text));
10
+ return (event) => {
11
+ if (area.onEvent(event) || agentUi().onEvent(event))
12
+ return render();
13
+ images.onEvent(event);
14
+ switch (event.type) {
15
+ case "agent_settled":
16
+ // 预算到限已由 limit_reached 给出友好提示
17
+ if (event.warning !== undefined && event.warning !== LIMIT_WARNING)
18
+ view.addNotice("warn", event.warning);
19
+ status.refresh();
20
+ break;
21
+ case "message_start": {
22
+ const message = event.message;
23
+ if (message.role === "user")
24
+ view.addUser(message);
25
+ else if (message.role === "assistant")
26
+ view.startAssistant(message);
27
+ else if (message.role === "custom" && message.display) {
28
+ view.addNotice("info", typeof message.content === "string" ? message.content : "");
29
+ }
30
+ break;
31
+ }
32
+ case "message_update":
33
+ view.updateAssistant(event.message);
34
+ break;
35
+ case "message_end":
36
+ if (event.message.role === "assistant") {
37
+ view.endAssistant(event.message);
38
+ status.refresh();
39
+ }
40
+ break;
41
+ case "tool_execution_start": {
42
+ const started = tools.start(event);
43
+ if (started.topLevel)
44
+ view.addTool(started.view);
45
+ break;
46
+ }
47
+ case "tool_execution_update":
48
+ tools.update(event.toolCallId, event.partial);
49
+ render();
50
+ return;
51
+ case "tool_execution_end":
52
+ tools.end(event.toolCallId, event.result, event.isError);
53
+ break;
54
+ case "queue_update":
55
+ setQueue(event.steering, event.followUp);
56
+ return;
57
+ case "compaction_end":
58
+ if (event.result !== undefined)
59
+ view.addCompaction(event.result);
60
+ else if (event.error !== undefined)
61
+ view.addNotice("error", `压缩失败:${compactionErrorText(event.error)}`);
62
+ else if (event.aborted)
63
+ view.addNotice("info", "压缩已取消");
64
+ status.refresh();
65
+ break;
66
+ case "auto_retry_start":
67
+ view.addRetry(event.attempt, event.maxAttempts, event.delayMs, event.errorMessage);
68
+ break;
69
+ case "auto_retry_end":
70
+ if (!event.success)
71
+ view.addRetryFailed(event.finalError);
72
+ break;
73
+ case "cache_miss":
74
+ case "context_pressure": {
75
+ const shown = cacheEventNotice(event, cacheNoticesEnabled(session()));
76
+ if (shown !== undefined)
77
+ view.addNotice(shown.level, shown.text);
78
+ status.refresh();
79
+ render();
80
+ return;
81
+ }
82
+ case "cache_warm":
83
+ case "permission_mode_changed":
84
+ case "model_changed":
85
+ case "thinking_level_changed":
86
+ case "session_changed":
87
+ status.refresh();
88
+ render();
89
+ return;
90
+ default:
91
+ break;
92
+ }
93
+ indicator.onEvent(event);
94
+ render();
95
+ };
96
+ }