@armadra/agent 0.0.0-stage → 0.3.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 (433) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +470 -2
  4. package/dist/agent/agent.d.ts +56 -0
  5. package/dist/agent/agent.js +129 -0
  6. package/dist/agent/loop.d.ts +51 -0
  7. package/dist/agent/loop.js +158 -0
  8. package/dist/agent/queue.d.ts +25 -0
  9. package/dist/agent/queue.js +55 -0
  10. package/dist/agent/retry.d.ts +22 -0
  11. package/dist/agent/retry.js +92 -0
  12. package/dist/agent/schema.d.ts +27 -0
  13. package/dist/agent/schema.js +186 -0
  14. package/dist/agent/session-cache.d.ts +100 -0
  15. package/dist/agent/session-cache.js +514 -0
  16. package/dist/agent/session-compaction.d.ts +49 -0
  17. package/dist/agent/session-compaction.js +251 -0
  18. package/dist/agent/session-core.d.ts +103 -0
  19. package/dist/agent/session-core.js +7 -0
  20. package/dist/agent/session-run.d.ts +55 -0
  21. package/dist/agent/session-run.js +246 -0
  22. package/dist/agent/session-state.d.ts +39 -0
  23. package/dist/agent/session-state.js +119 -0
  24. package/dist/agent/session-subagent.d.ts +54 -0
  25. package/dist/agent/session-subagent.js +157 -0
  26. package/dist/agent/session-sync.d.ts +20 -0
  27. package/dist/agent/session-sync.js +111 -0
  28. package/dist/agent/session-tools.d.ts +24 -0
  29. package/dist/agent/session-tools.js +277 -0
  30. package/dist/agent/session.d.ts +117 -0
  31. package/dist/agent/session.js +485 -0
  32. package/dist/agent/system-prompt.d.ts +49 -0
  33. package/dist/agent/system-prompt.js +121 -0
  34. package/dist/agent/tool-runner.d.ts +64 -0
  35. package/dist/agent/tool-runner.js +309 -0
  36. package/dist/agent/transform.d.ts +26 -0
  37. package/dist/agent/transform.js +171 -0
  38. package/dist/agent/types.d.ts +378 -0
  39. package/dist/agent/types.js +21 -0
  40. package/dist/ai/apis/anthropic-messages.d.ts +26 -0
  41. package/dist/ai/apis/anthropic-messages.js +214 -0
  42. package/dist/ai/apis/anthropic-request.d.ts +42 -0
  43. package/dist/ai/apis/anthropic-request.js +282 -0
  44. package/dist/ai/apis/api.d.ts +28 -0
  45. package/dist/ai/apis/api.js +102 -0
  46. package/dist/ai/apis/cache-params.d.ts +48 -0
  47. package/dist/ai/apis/cache-params.js +163 -0
  48. package/dist/ai/apis/google-generative-ai.d.ts +32 -0
  49. package/dist/ai/apis/google-generative-ai.js +249 -0
  50. package/dist/ai/apis/google-request.d.ts +40 -0
  51. package/dist/ai/apis/google-request.js +255 -0
  52. package/dist/ai/apis/openai-compat.d.ts +35 -0
  53. package/dist/ai/apis/openai-compat.js +142 -0
  54. package/dist/ai/apis/openai-completions.d.ts +28 -0
  55. package/dist/ai/apis/openai-completions.js +246 -0
  56. package/dist/ai/apis/openai-request.d.ts +35 -0
  57. package/dist/ai/apis/openai-request.js +303 -0
  58. package/dist/ai/apis/openai-responses-request.d.ts +52 -0
  59. package/dist/ai/apis/openai-responses-request.js +266 -0
  60. package/dist/ai/apis/openai-responses.d.ts +28 -0
  61. package/dist/ai/apis/openai-responses.js +304 -0
  62. package/dist/ai/apis/shared.d.ts +56 -0
  63. package/dist/ai/apis/shared.js +179 -0
  64. package/dist/ai/cache/economics.d.ts +24 -0
  65. package/dist/ai/cache/economics.js +69 -0
  66. package/dist/ai/cache/fingerprint.d.ts +17 -0
  67. package/dist/ai/cache/fingerprint.js +39 -0
  68. package/dist/ai/cache/miss.d.ts +49 -0
  69. package/dist/ai/cache/miss.js +96 -0
  70. package/dist/ai/cache/reporting.d.ts +39 -0
  71. package/dist/ai/cache/reporting.js +103 -0
  72. package/dist/ai/cache/types.d.ts +94 -0
  73. package/dist/ai/cache/types.js +19 -0
  74. package/dist/ai/cache/warmer.d.ts +94 -0
  75. package/dist/ai/cache/warmer.js +224 -0
  76. package/dist/ai/context.d.ts +35 -0
  77. package/dist/ai/context.js +114 -0
  78. package/dist/ai/cost.d.ts +21 -0
  79. package/dist/ai/cost.js +60 -0
  80. package/dist/ai/event-stream.d.ts +33 -0
  81. package/dist/ai/event-stream.js +101 -0
  82. package/dist/ai/fake/fake-provider.d.ts +68 -0
  83. package/dist/ai/fake/fake-provider.js +278 -0
  84. package/dist/ai/fake/fake-script.d.ts +69 -0
  85. package/dist/ai/fake/fake-script.js +142 -0
  86. package/dist/ai/http.d.ts +54 -0
  87. package/dist/ai/http.js +212 -0
  88. package/dist/ai/json-partial.d.ts +17 -0
  89. package/dist/ai/json-partial.js +243 -0
  90. package/dist/ai/overflow.d.ts +22 -0
  91. package/dist/ai/overflow.js +61 -0
  92. package/dist/ai/providers/auth.d.ts +71 -0
  93. package/dist/ai/providers/auth.js +202 -0
  94. package/dist/ai/providers/builtin.d.ts +23 -0
  95. package/dist/ai/providers/builtin.js +148 -0
  96. package/dist/ai/providers/catalog-data.d.ts +5 -0
  97. package/dist/ai/providers/catalog-data.js +19 -0
  98. package/dist/ai/providers/catalog.d.ts +28 -0
  99. package/dist/ai/providers/catalog.js +166 -0
  100. package/dist/ai/providers/channels.d.ts +51 -0
  101. package/dist/ai/providers/channels.js +96 -0
  102. package/dist/ai/providers/enrich.d.ts +34 -0
  103. package/dist/ai/providers/enrich.js +86 -0
  104. package/dist/ai/providers/models-dev-cache.d.ts +53 -0
  105. package/dist/ai/providers/models-dev-cache.js +147 -0
  106. package/dist/ai/providers/models-dev.d.ts +99 -0
  107. package/dist/ai/providers/models-dev.js +315 -0
  108. package/dist/ai/providers/registry.d.ts +114 -0
  109. package/dist/ai/providers/registry.js +458 -0
  110. package/dist/ai/sse.d.ts +32 -0
  111. package/dist/ai/sse.js +140 -0
  112. package/dist/ai/thinking.d.ts +42 -0
  113. package/dist/ai/thinking.js +101 -0
  114. package/dist/ai/types.d.ts +448 -0
  115. package/dist/ai/types.js +19 -0
  116. package/dist/bundle/ama-sandbox.cjs +324 -0
  117. package/dist/bundle/ama.cjs +27837 -0
  118. package/dist/bundle.d.ts +9 -0
  119. package/dist/bundle.js +15 -0
  120. package/dist/cli/args.d.ts +85 -0
  121. package/dist/cli/args.js +408 -0
  122. package/dist/cli/bootstrap.d.ts +18 -0
  123. package/dist/cli/bootstrap.js +399 -0
  124. package/dist/cli/compose-providers.d.ts +37 -0
  125. package/dist/cli/compose-providers.js +107 -0
  126. package/dist/cli/compose-session.d.ts +72 -0
  127. package/dist/cli/compose-session.js +370 -0
  128. package/dist/cli/compose-store.d.ts +24 -0
  129. package/dist/cli/compose-store.js +125 -0
  130. package/dist/cli/compose.d.ts +108 -0
  131. package/dist/cli/compose.js +221 -0
  132. package/dist/cli/default-model.d.ts +16 -0
  133. package/dist/cli/default-model.js +24 -0
  134. package/dist/cli/deps.d.ts +207 -0
  135. package/dist/cli/deps.js +12 -0
  136. package/dist/cli/exit-codes.d.ts +29 -0
  137. package/dist/cli/exit-codes.js +40 -0
  138. package/dist/cli/main.d.ts +27 -0
  139. package/dist/cli/main.js +177 -0
  140. package/dist/cli/runtime.d.ts +90 -0
  141. package/dist/cli/runtime.js +8 -0
  142. package/dist/cli/startup-screen.d.ts +15 -0
  143. package/dist/cli/startup-screen.js +56 -0
  144. package/dist/cli/startup-steps.d.ts +35 -0
  145. package/dist/cli/startup-steps.js +202 -0
  146. package/dist/cli/subcommands/auth.d.ts +12 -0
  147. package/dist/cli/subcommands/auth.js +91 -0
  148. package/dist/cli/subcommands/config.d.ts +53 -0
  149. package/dist/cli/subcommands/config.js +277 -0
  150. package/dist/cli/subcommands/context.d.ts +21 -0
  151. package/dist/cli/subcommands/context.js +42 -0
  152. package/dist/cli/subcommands/doctor.d.ts +11 -0
  153. package/dist/cli/subcommands/doctor.js +246 -0
  154. package/dist/cli/subcommands/init.d.ts +6 -0
  155. package/dist/cli/subcommands/init.js +22 -0
  156. package/dist/cli/subcommands/model-meta.d.ts +16 -0
  157. package/dist/cli/subcommands/model-meta.js +54 -0
  158. package/dist/cli/subcommands/models-cache-probe.d.ts +34 -0
  159. package/dist/cli/subcommands/models-cache-probe.js +190 -0
  160. package/dist/cli/subcommands/models-discover.d.ts +46 -0
  161. package/dist/cli/subcommands/models-discover.js +232 -0
  162. package/dist/cli/subcommands/models.d.ts +40 -0
  163. package/dist/cli/subcommands/models.js +152 -0
  164. package/dist/cli/subcommands/providers-list.d.ts +8 -0
  165. package/dist/cli/subcommands/providers-list.js +97 -0
  166. package/dist/cli/subcommands/providers-plan.d.ts +79 -0
  167. package/dist/cli/subcommands/providers-plan.js +215 -0
  168. package/dist/cli/subcommands/providers.d.ts +27 -0
  169. package/dist/cli/subcommands/providers.js +433 -0
  170. package/dist/cli/subcommands/sessions.d.ts +11 -0
  171. package/dist/cli/subcommands/sessions.js +100 -0
  172. package/dist/codemode/capability.d.ts +37 -0
  173. package/dist/codemode/capability.js +55 -0
  174. package/dist/codemode/declarations.d.ts +44 -0
  175. package/dist/codemode/declarations.js +111 -0
  176. package/dist/codemode/host-side.d.ts +59 -0
  177. package/dist/codemode/host-side.js +253 -0
  178. package/dist/codemode/modes.d.ts +23 -0
  179. package/dist/codemode/modes.js +40 -0
  180. package/dist/codemode/protocol.d.ts +91 -0
  181. package/dist/codemode/protocol.js +114 -0
  182. package/dist/codemode/sandbox-entry.d.ts +25 -0
  183. package/dist/codemode/sandbox-entry.js +323 -0
  184. package/dist/codemode/store.d.ts +26 -0
  185. package/dist/codemode/store.js +53 -0
  186. package/dist/codemode/tool.d.ts +105 -0
  187. package/dist/codemode/tool.js +283 -0
  188. package/dist/compaction/branch-summary.d.ts +30 -0
  189. package/dist/compaction/branch-summary.js +79 -0
  190. package/dist/compaction/breaker.d.ts +32 -0
  191. package/dist/compaction/breaker.js +65 -0
  192. package/dist/compaction/cut-point.d.ts +23 -0
  193. package/dist/compaction/cut-point.js +70 -0
  194. package/dist/compaction/estimate.d.ts +30 -0
  195. package/dist/compaction/estimate.js +114 -0
  196. package/dist/compaction/prune-tier.d.ts +31 -0
  197. package/dist/compaction/prune-tier.js +83 -0
  198. package/dist/compaction/serialize.d.ts +20 -0
  199. package/dist/compaction/serialize.js +115 -0
  200. package/dist/compaction/summarize-tier.d.ts +111 -0
  201. package/dist/compaction/summarize-tier.js +305 -0
  202. package/dist/config/auth-file.d.ts +39 -0
  203. package/dist/config/auth-file.js +92 -0
  204. package/dist/config/context-files.d.ts +30 -0
  205. package/dist/config/context-files.js +77 -0
  206. package/dist/config/init.d.ts +30 -0
  207. package/dist/config/init.js +92 -0
  208. package/dist/config/json-schema.d.ts +14 -0
  209. package/dist/config/json-schema.js +182 -0
  210. package/dist/config/load.d.ts +45 -0
  211. package/dist/config/load.js +97 -0
  212. package/dist/config/merge.d.ts +73 -0
  213. package/dist/config/merge.js +248 -0
  214. package/dist/config/paths.d.ts +38 -0
  215. package/dist/config/paths.js +108 -0
  216. package/dist/config/profile.d.ts +27 -0
  217. package/dist/config/profile.js +65 -0
  218. package/dist/config/schema.d.ts +34 -0
  219. package/dist/config/schema.js +476 -0
  220. package/dist/config/trust.d.ts +42 -0
  221. package/dist/config/trust.js +122 -0
  222. package/dist/config/types.d.ts +190 -0
  223. package/dist/config/types.js +29 -0
  224. package/dist/config/write.d.ts +10 -0
  225. package/dist/config/write.js +25 -0
  226. package/dist/errors.d.ts +28 -0
  227. package/dist/errors.js +30 -0
  228. package/dist/hooks/config.d.ts +49 -0
  229. package/dist/hooks/config.js +102 -0
  230. package/dist/hooks/dispatcher.d.ts +41 -0
  231. package/dist/hooks/dispatcher.js +104 -0
  232. package/dist/hooks/matcher.d.ts +22 -0
  233. package/dist/hooks/matcher.js +108 -0
  234. package/dist/hooks/protocol.d.ts +33 -0
  235. package/dist/hooks/protocol.js +240 -0
  236. package/dist/hooks/runner.d.ts +30 -0
  237. package/dist/hooks/runner.js +143 -0
  238. package/dist/hooks/types.d.ts +147 -0
  239. package/dist/hooks/types.js +20 -0
  240. package/dist/host/api-impl.d.ts +75 -0
  241. package/dist/host/api-impl.js +173 -0
  242. package/dist/host/loader.d.ts +31 -0
  243. package/dist/host/loader.js +147 -0
  244. package/dist/host/types.d.ts +169 -0
  245. package/dist/host/types.js +14 -0
  246. package/dist/host.d.ts +5 -0
  247. package/dist/host.js +4 -0
  248. package/dist/index.d.ts +41 -0
  249. package/dist/index.js +28 -0
  250. package/dist/modes/commands-core.d.ts +44 -0
  251. package/dist/modes/commands-core.js +171 -0
  252. package/dist/modes/image-input.d.ts +27 -0
  253. package/dist/modes/image-input.js +78 -0
  254. package/dist/modes/interactive/approval-dialog.d.ts +48 -0
  255. package/dist/modes/interactive/approval-dialog.js +202 -0
  256. package/dist/modes/interactive/commands.d.ts +41 -0
  257. package/dist/modes/interactive/commands.js +201 -0
  258. package/dist/modes/interactive/completion.d.ts +53 -0
  259. package/dist/modes/interactive/completion.js +157 -0
  260. package/dist/modes/interactive/interactive-mode.d.ts +46 -0
  261. package/dist/modes/interactive/interactive-mode.js +491 -0
  262. package/dist/modes/interactive/key-dispatch.d.ts +29 -0
  263. package/dist/modes/interactive/key-dispatch.js +107 -0
  264. package/dist/modes/interactive/line/line-editor.d.ts +50 -0
  265. package/dist/modes/interactive/line/line-editor.js +232 -0
  266. package/dist/modes/interactive/line/line-mode.d.ts +20 -0
  267. package/dist/modes/interactive/line/line-mode.js +218 -0
  268. package/dist/modes/interactive/line/line-render.d.ts +35 -0
  269. package/dist/modes/interactive/line/line-render.js +171 -0
  270. package/dist/modes/interactive/line/paste-state.d.ts +26 -0
  271. package/dist/modes/interactive/line/paste-state.js +72 -0
  272. package/dist/modes/interactive/message-view.d.ts +77 -0
  273. package/dist/modes/interactive/message-view.js +269 -0
  274. package/dist/modes/interactive/pickers.d.ts +42 -0
  275. package/dist/modes/interactive/pickers.js +115 -0
  276. package/dist/modes/interactive/startup-ui.d.ts +33 -0
  277. package/dist/modes/interactive/startup-ui.js +268 -0
  278. package/dist/modes/interactive/status-bar.d.ts +48 -0
  279. package/dist/modes/interactive/status-bar.js +139 -0
  280. package/dist/modes/interactive/tool-view.d.ts +95 -0
  281. package/dist/modes/interactive/tool-view.js +344 -0
  282. package/dist/modes/print/json-event.d.ts +15 -0
  283. package/dist/modes/print/json-event.js +39 -0
  284. package/dist/modes/print/print-mode.d.ts +17 -0
  285. package/dist/modes/print/print-mode.js +107 -0
  286. package/dist/modes/rpc/commands.d.ts +40 -0
  287. package/dist/modes/rpc/commands.js +263 -0
  288. package/dist/modes/rpc/jsonl.d.ts +16 -0
  289. package/dist/modes/rpc/jsonl.js +55 -0
  290. package/dist/modes/rpc/rpc-mode.d.ts +22 -0
  291. package/dist/modes/rpc/rpc-mode.js +153 -0
  292. package/dist/modes/session-report.d.ts +55 -0
  293. package/dist/modes/session-report.js +278 -0
  294. package/dist/modes/shared.d.ts +13 -0
  295. package/dist/modes/shared.js +52 -0
  296. package/dist/modes/startup-ui-text.d.ts +16 -0
  297. package/dist/modes/startup-ui-text.js +103 -0
  298. package/dist/permissions/broker.d.ts +47 -0
  299. package/dist/permissions/broker.js +107 -0
  300. package/dist/permissions/dangerous.d.ts +47 -0
  301. package/dist/permissions/dangerous.js +370 -0
  302. package/dist/permissions/pipeline.d.ts +51 -0
  303. package/dist/permissions/pipeline.js +181 -0
  304. package/dist/permissions/preview.d.ts +43 -0
  305. package/dist/permissions/preview.js +463 -0
  306. package/dist/permissions/rules.d.ts +58 -0
  307. package/dist/permissions/rules.js +249 -0
  308. package/dist/permissions/types.d.ts +100 -0
  309. package/dist/permissions/types.js +18 -0
  310. package/dist/rpc.d.ts +173 -0
  311. package/dist/rpc.js +13 -0
  312. package/dist/sdk.d.ts +98 -0
  313. package/dist/sdk.js +195 -0
  314. package/dist/session/manager.d.ts +70 -0
  315. package/dist/session/manager.js +278 -0
  316. package/dist/session/migrate.d.ts +19 -0
  317. package/dist/session/migrate.js +53 -0
  318. package/dist/session/projection.d.ts +50 -0
  319. package/dist/session/projection.js +184 -0
  320. package/dist/session/store.d.ts +47 -0
  321. package/dist/session/store.js +210 -0
  322. package/dist/session/tree.d.ts +21 -0
  323. package/dist/session/tree.js +88 -0
  324. package/dist/session/types.d.ts +201 -0
  325. package/dist/session/types.js +18 -0
  326. package/dist/skills/discover.d.ts +60 -0
  327. package/dist/skills/discover.js +160 -0
  328. package/dist/skills/expand.d.ts +35 -0
  329. package/dist/skills/expand.js +46 -0
  330. package/dist/skills/frontmatter.d.ts +27 -0
  331. package/dist/skills/frontmatter.js +157 -0
  332. package/dist/skills/index-prompt.d.ts +13 -0
  333. package/dist/skills/index-prompt.js +42 -0
  334. package/dist/skills/templates.d.ts +52 -0
  335. package/dist/skills/templates.js +177 -0
  336. package/dist/tools/bash.d.ts +49 -0
  337. package/dist/tools/bash.js +222 -0
  338. package/dist/tools/edit-fuzzy.d.ts +36 -0
  339. package/dist/tools/edit-fuzzy.js +129 -0
  340. package/dist/tools/edit.d.ts +38 -0
  341. package/dist/tools/edit.js +241 -0
  342. package/dist/tools/file-mutex.d.ts +8 -0
  343. package/dist/tools/file-mutex.js +29 -0
  344. package/dist/tools/glob.d.ts +44 -0
  345. package/dist/tools/glob.js +217 -0
  346. package/dist/tools/grep.d.ts +39 -0
  347. package/dist/tools/grep.js +179 -0
  348. package/dist/tools/ignore.d.ts +40 -0
  349. package/dist/tools/ignore.js +174 -0
  350. package/dist/tools/image-file.d.ts +31 -0
  351. package/dist/tools/image-file.js +114 -0
  352. package/dist/tools/ls.d.ts +21 -0
  353. package/dist/tools/ls.js +96 -0
  354. package/dist/tools/output-accumulator.d.ts +48 -0
  355. package/dist/tools/output-accumulator.js +106 -0
  356. package/dist/tools/paths.d.ts +20 -0
  357. package/dist/tools/paths.js +58 -0
  358. package/dist/tools/presets.d.ts +71 -0
  359. package/dist/tools/presets.js +128 -0
  360. package/dist/tools/process-tree.d.ts +35 -0
  361. package/dist/tools/process-tree.js +125 -0
  362. package/dist/tools/read.d.ts +24 -0
  363. package/dist/tools/read.js +132 -0
  364. package/dist/tools/registry.d.ts +43 -0
  365. package/dist/tools/registry.js +106 -0
  366. package/dist/tools/shell.d.ts +38 -0
  367. package/dist/tools/shell.js +91 -0
  368. package/dist/tools/task.d.ts +29 -0
  369. package/dist/tools/task.js +107 -0
  370. package/dist/tools/todo.d.ts +28 -0
  371. package/dist/tools/todo.js +107 -0
  372. package/dist/tools/truncate.d.ts +44 -0
  373. package/dist/tools/truncate.js +175 -0
  374. package/dist/tools/types.d.ts +135 -0
  375. package/dist/tools/types.js +19 -0
  376. package/dist/tools/write.d.ts +20 -0
  377. package/dist/tools/write.js +84 -0
  378. package/dist/tui/ansi.d.ts +29 -0
  379. package/dist/tui/ansi.js +420 -0
  380. package/dist/tui/component.d.ts +38 -0
  381. package/dist/tui/component.js +13 -0
  382. package/dist/tui/components/box.d.ts +26 -0
  383. package/dist/tui/components/box.js +65 -0
  384. package/dist/tui/components/container.d.ts +14 -0
  385. package/dist/tui/components/container.js +39 -0
  386. package/dist/tui/components/editor-buffer.d.ts +67 -0
  387. package/dist/tui/components/editor-buffer.js +300 -0
  388. package/dist/tui/components/editor-paste.d.ts +29 -0
  389. package/dist/tui/components/editor-paste.js +64 -0
  390. package/dist/tui/components/editor.d.ts +114 -0
  391. package/dist/tui/components/editor.js +530 -0
  392. package/dist/tui/components/key-value.d.ts +29 -0
  393. package/dist/tui/components/key-value.js +48 -0
  394. package/dist/tui/components/loader.d.ts +35 -0
  395. package/dist/tui/components/loader.js +71 -0
  396. package/dist/tui/components/markdown.d.ts +90 -0
  397. package/dist/tui/components/markdown.js +462 -0
  398. package/dist/tui/components/meter.d.ts +29 -0
  399. package/dist/tui/components/meter.js +47 -0
  400. package/dist/tui/components/overlay.d.ts +24 -0
  401. package/dist/tui/components/overlay.js +52 -0
  402. package/dist/tui/components/select-list.d.ts +57 -0
  403. package/dist/tui/components/select-list.js +179 -0
  404. package/dist/tui/components/spacer.d.ts +11 -0
  405. package/dist/tui/components/spacer.js +16 -0
  406. package/dist/tui/components/text.d.ts +30 -0
  407. package/dist/tui/components/text.js +65 -0
  408. package/dist/tui/keybindings.d.ts +66 -0
  409. package/dist/tui/keybindings.js +120 -0
  410. package/dist/tui/keys.d.ts +38 -0
  411. package/dist/tui/keys.js +275 -0
  412. package/dist/tui/stdin-buffer.d.ts +41 -0
  413. package/dist/tui/stdin-buffer.js +206 -0
  414. package/dist/tui/terminal.d.ts +79 -0
  415. package/dist/tui/terminal.js +153 -0
  416. package/dist/tui/theme.d.ts +31 -0
  417. package/dist/tui/theme.js +199 -0
  418. package/dist/tui/tui.d.ts +103 -0
  419. package/dist/tui/tui.js +363 -0
  420. package/dist/tui/vt-screen.d.ts +46 -0
  421. package/dist/tui/vt-screen.js +251 -0
  422. package/dist/tui.d.ts +30 -0
  423. package/dist/tui.js +31 -0
  424. package/dist/version.d.ts +8 -0
  425. package/dist/version.js +24 -0
  426. package/docs/codemode.md +102 -0
  427. package/docs/hooks.md +196 -0
  428. package/docs/host-api.md +161 -0
  429. package/docs/providers.md +531 -0
  430. package/docs/rpc.md +253 -0
  431. package/docs/session-format.md +119 -0
  432. package/docs/tui.md +170 -0
  433. package/package.json +101 -4
package/docs/rpc.md ADDED
@@ -0,0 +1,253 @@
1
+ # RPC 协议(stdio JSONL)
2
+
3
+ `ama --mode rpc` 从 stdin 读命令、向 stdout 写响应与事件,每行一个 JSON。类型定义在 `@armadra/agent/rpc`(`src/rpc.ts`),实现在 `src/modes/rpc/`。`ama -p --output-format stream-json` 输出的事件与这里同形状。设计依据见 [design.md](design.md) §13.2。
4
+
5
+ ## 线路
6
+
7
+ - 读:只按 `\n` 切行(去掉行尾 `\r`,空行跳过),不按 U+2028 / U+2029 切;多字节 UTF-8 跨块拼接;stdin 结束时最后一段不带换行的行也算一行。
8
+ - 写:每行是一个 `JSON.stringify` 结果,U+2028 / U+2029 转义为 `\u2028` / `\u2029`,`Error` 序列化为 `{ name, message }`,bigint 转字符串,图片 base64 不截断。大行按 64 KiB 分片写出并等待背压,行与行不交错。
9
+ - stdout 只有协议行;日志、宿主通知的人读副本写 stderr。
10
+
11
+ ## 握手
12
+
13
+ 启动后先发 `hello`,再发当前会话的 `session_start`:
14
+
15
+ ```json
16
+ {"type":"hello","protocolVersion":1,"agent":"ama","version":"0.1.0","capabilities":["approvals","images","hooks"]}
17
+ {"type":"session_start","sessionId":"…","cwd":"/work","reason":"startup"}
18
+ ```
19
+
20
+ `protocolVersion` 是 `RPC_PROTOCOL_VERSION`(当前 1)。`capabilities` 列出服务端支持的能力;客户端要接审批时用 `set_client_capabilities` 声明(见「审批」)。
21
+
22
+ ## 命令与响应
23
+
24
+ 命令形状 `{ "id"?: string, "type": <命令名>, ...参数 }`。响应:
25
+
26
+ ```json
27
+ { "id": "1", "type": "response", "command": "prompt", "success": true, "data": { "disposition": "started" } }
28
+ { "id": "2", "type": "response", "command": "set_model", "success": false, "error": "…", "code": "model_not_found" }
29
+ ```
30
+
31
+ - 响应带回请求的 `id`(字符串才带)。命令并发处理:`prompt` 不阻塞后续命令,所以响应顺序不一定与请求顺序相同,用 `id` 对应。
32
+ - 失败时 `error` 是人读文本,`code` 是 `AmaError.code`(若有)。未知命令 → `code: "invalid_arguments"`。
33
+ - 一行不是合法 JSON 或缺 `type` → `{ "type": "response", "command": "parse", "success": false, "error": … }`,没有 `id`。
34
+ - 需要会话实现扩展方法的命令(下表标 †)在非 `AgentSessionImpl` 会话上返回 `code: "not_implemented"`;CLI 与 SDK 建出的会话都是 `AgentSessionImpl`。
35
+
36
+ ### 提示
37
+
38
+ | 命令 | 参数 | `data` |
39
+ | ------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
40
+ | `prompt` | `message: string`、`images?: ImageBlock[]`、`streamingBehavior?: "steer" \| "followUp"` | `{ disposition: "started" \| "queued" \| "handled" }` |
41
+ | `steer` | `message`、`images?` | 同上 |
42
+ | `follow_up` | `message`、`images?` | 同上 |
43
+ | `abort` | — | `{}`(回到空闲后应答;不清队列) |
44
+ | `clear_queue` | — | `{ steering: string[], followUp: string[] }`(被清掉的文本) |
45
+
46
+ 提示类命令**不等运行结束**:会话开始运行(`before_agent_start` / `agent_start`)、消息入队或被处理(例如斜杠命令、Hook 阻止)后立刻应答,运行进展走事件。运行中发 `prompt` 且不带 `streamingBehavior` → 失败,`code: "busy"`;带上 `steer` / `followUp` 则入队。应答发出之后的运行失败以 `{"type":"notification","level":"error","message":…}` 报告。
47
+
48
+ ### 状态
49
+
50
+ | 命令 | 参数 | `data` |
51
+ | ------------------------- | ---- | ---------------------------------------------------- |
52
+ | `get_state` | — | `SessionState`(下表) |
53
+ | `get_messages` | — | `{ messages: AgentMessage[] }`(投影后的上下文消息) |
54
+ | `get_last_assistant_text` | — | `{ text: string \| null }` |
55
+ | `get_session_stats` | — | `SessionStats`(见「会话统计」) |
56
+
57
+ `SessionState`:`isStreaming`、`isCompacting`、`isRetrying`、`model`(`{ provider, id, channel? }` 或缺省;`channel` 只在多渠道供应商上出现)、`thinkingLevel`、`permissionMode`、`sessionId`、`sessionFile`、`cwd`、`sessionName`、`messageCount`、`pendingMessageCount`、`steeringMode`、`followUpMode`、`autoCompaction`、`autoRetry`。
58
+
59
+ ### 模型
60
+
61
+ | 命令 | 参数 | `data` |
62
+ | ------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------- |
63
+ | `set_model` | `provider: string`、`modelId: string`、`channel?: string` | `{ model: { provider, id, channel? } }` |
64
+ | `get_available_models` | — | `{ models: RpcModelInfo[] }` |
65
+ | `set_thinking_level` | `level: off \| minimal \| low \| medium \| high \| xhigh` | `{ level }` |
66
+ | `get_available_thinking_levels` | — | `{ levels: string[] }`(当前模型支持的级别;无模型时 `["off"]`) |
67
+
68
+ `RpcModelInfo`:`provider`、`id`、`name`、`hasKey`、`keySource`(`cli` / `auth-file` / `config` / `env` / `none`)、`contextWindow?`、`maxTokens`、`reasoning`、`input`(`"text"` / `"image"`)。**密钥不离开进程**:只报有无与来源。
69
+
70
+ ### 队列、压缩、重试
71
+
72
+ | 命令 | 参数 | `data` |
73
+ | ----------------------- | -------------------------------- | ------------------------------------------------------------------------------------------- |
74
+ | `set_steering_mode` † | `mode: "one-at-a-time" \| "all"` | `{ mode }` |
75
+ | `set_follow_up_mode` † | `mode` | `{ mode }` |
76
+ | `compact` | `customInstructions?: string` | `CompactionResult`:`summary`、`firstKeptEntryId`、`tokensBefore`、`tokensAfter?`、`usage?` |
77
+ | `set_auto_compaction` † | `enabled: boolean` | `{ enabled }` |
78
+ | `set_auto_retry` † | `enabled: boolean` | `{ enabled }` |
79
+ | `abort_retry` | — | `{ aborted: boolean }`(正在重试等待时中断本次运行) |
80
+
81
+ ### 会话
82
+
83
+ | 命令 | 参数 | `data` |
84
+ | --------------------- | ------------------------ | ------------------------------------------------------------------------------------------- |
85
+ | `new_session` | `parentSession?: string` | `{ sessionId, sessionFile }` |
86
+ | `switch_session` | `sessionPath: string` | 同上 |
87
+ | `fork` | `entryId: string` | 同上(从该条目之前复制出新会话文件) |
88
+ | `get_entries` † | `since?: string` | `{ entries: SessionEntry[], leafId: string \| null }`;`since` 是 entry id 游标,不含它本身 |
89
+ | `get_tree` † | — | `{ tree: SessionTreeNode[] }`(`{ entry, children, label? }`) |
90
+ | `set_session_name` † | `name: string` | `{ name }` |
91
+ | `get_fork_messages` † | — | `{ messages: { entryId, text }[] }`(活动分支上的用户消息,`fork` 的候选) |
92
+
93
+ 换会话后服务端重新订阅事件,并为新会话发 `session_start`(`reason` 为 `new` / `resume` / `fork`)。`new_session` 目前不使用 `parentSession` 参数。条目形状见 [session-format.md](session-format.md)。
94
+
95
+ ### 审批
96
+
97
+ | 命令 | 参数 | `data` |
98
+ | ------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
99
+ | `set_client_capabilities` | `capabilities: ("approvals" \| "images" \| "hooks")[]` | `{ capabilities }` |
100
+ | `permission_response` | `requestId: string`、`decision: "allow" \| "deny" \| "allow_session"` | `{ accepted: boolean }`(false = 当前没在等这个 id,已暂存,稍后被问到时生效) |
101
+
102
+ ### 工具、权限、发现
103
+
104
+ | 命令 | 参数 | `data` |
105
+ | --------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
106
+ | `get_tools` | — | `{ tools: { name, description, parameters, permission, active }[] }`(注册表全部工具,`active` 表示模型当前能看到) |
107
+ | `set_active_tools` | `names: string[]` | `{ names }`(生效后的活动工具名) |
108
+ | `set_permission_mode` | `mode: plan \| default \| auto-edit \| full-auto` | `{ mode }` |
109
+ | `get_commands` | — | `{ commands: { name, description?, source: "builtin" \| "template" \| "skill" }[] }`;Skill 名写作 `skill:<名>` |
110
+ | `get_skills` | — | `{ skills: { name, description, location, … }[] }`(已发现的 Skill;`location` 是 SKILL.md 路径) |
111
+
112
+ 合计 33 条命令,名字即 `RpcCommandMap` 的键。
113
+
114
+ ## 事件
115
+
116
+ 事件就是进程内 `SessionEvent`(`src/agent/types.ts`),只有 `message_update` 在线上换成纯增量。按出现场景分组:
117
+
118
+ | 事件 | 字段 |
119
+ | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
120
+ | `session_start` | `sessionId`、`sessionFile?`、`cwd`、`reason: startup \| resume \| new \| fork` |
121
+ | `session_changed` | `sessionId`、`sessionFile?` |
122
+ | `before_agent_start` | `prompt`(经 UserPromptSubmit Hook 与模板展开之后) |
123
+ | `agent_start` / `turn_start` / `agent_before_settle` | — |
124
+ | `turn_end` | `message`(助手消息)、`toolResults` |
125
+ | `agent_end` | `stopReason`、`willRetry` |
126
+ | `agent_settled` | `warning?`(运行彻底结束,含重试与 followUp) |
127
+ | `message_start` / `message_end` | `message`(`AgentMessage`) |
128
+ | `message_update` | `assistantMessageEvent`、`usage?`(见下) |
129
+ | `tool_execution_start` | `toolCallId`、`toolName`、`args`、`parentToolCallId?` |
130
+ | `tool_execution_update` | `toolCallId`、`toolName`、`partial`(运行中的输出文本)、`parentToolCallId?` |
131
+ | `tool_execution_end` | `toolCallId`、`toolName`、`result`、`isError`、`parentToolCallId?` |
132
+ | `queue_update` | `steering: string[]`、`followUp: string[]` |
133
+ | `compaction_start` | `trigger: threshold \| overflow \| manual` |
134
+ | `compaction_end` | `trigger`、`result?`、`aborted`、`willRetry`、`error?` |
135
+ | `auto_retry_start` | `attempt`、`maxAttempts`、`delayMs`、`errorMessage` |
136
+ | `auto_retry_end` | `success`、`attempt`、`finalError?` |
137
+ | `permission_request` | `requestId`、`toolName`、`input`、`reason: mode \| dangerous \| hook`、`hookReason?`、`timeoutMs`、`preview?` |
138
+ | `permission_resolved` | `requestId`、`decision` |
139
+ | `permission_mode_changed` | `mode` |
140
+ | `model_changed` | `model: { provider, id, channel? }` |
141
+ | `thinking_level_changed` | `level` |
142
+ | `entry_appended` | `entry`(刚落盘的会话条目) |
143
+ | `hook_executed` | `event`、`command`、`exitCode`(超时或被信号杀死为 null)、`durationMs` |
144
+ | `cache_miss` | `missedTokens`、`missedCost?`、`reason`、`detail?`、`idleMs` |
145
+ | `cache_warm` | `phase: scheduled \| sent \| stopped`、`nextWarmAt?`、`usage?`、`cost?`、`reason?` |
146
+ | `context_pressure` | `percent`、`threshold: 70 \| 90`、`remainingTokens?`、`estimatedTurnsLeft?` |
147
+
148
+ 另有非会话事件 `{"type":"notification","level":"info"|"warn"|"error","message":…}`:宿主 `ui.notify` 与应答之后的运行失败。
149
+
150
+ `parentToolCallId` 只出现在 codemode 脚本里经 `tools.*` 发起的内层调用上,值是外层 `codemode` 调用的 id;客户端据此折叠显示。内层调用不进转录。
151
+
152
+ ### `message_update` 与消息重建
153
+
154
+ 线上的 `message_update` 去掉了累计消息与 `partial`,只有增量:
155
+
156
+ ```json
157
+ {
158
+ "type": "message_update",
159
+ "assistantMessageEvent": { "type": "text_delta", "contentIndex": 0, "delta": "hello" },
160
+ "usage": { "input": 12, "output": 3, "cacheRead": 0, "cacheWrite": 0, "totalTokens": 15 }
161
+ }
162
+ ```
163
+
164
+ `assistantMessageEvent.type` 取值:`start`、`text_start` / `text_delta` / `text_end`、`thinking_start` / `thinking_delta` / `thinking_end`、`toolcall_start`(带 `id`、`name`)/ `toolcall_delta`(参数 JSON 片段)/ `toolcall_end`(带完整 `toolCall`)、`done`(`reason: stop | length | toolUse`,带最终 `message`)、`error`(`reason: aborted | error`,带最终 `message`)。客户端重建:
165
+
166
+ 1. `message_start` 给出初始助手消息(`content: []`);
167
+ 2. 按 `contentIndex` 维护内容块:`*_start` 建块,`*_delta` 追加文本(工具参数先当字符串拼接),`toolcall_end` 用完整 `toolCall` 替换该块;
168
+ 3. `usage` 是该时刻的最新用量,直接覆盖;
169
+ 4. 以 `message_end`(或 `done` / `error` 的 `message`)为准替换整条消息——重建结果只用于流式显示。
170
+
171
+ ### 会话统计
172
+
173
+ `get_session_stats` 的 `data` 是 `SessionStats`:
174
+
175
+ | 字段 | 说明 |
176
+ | ------------------------------------------------------------------ | --------------------------------------------------------------------------- |
177
+ | `sessionId` / `sessionFile` | 会话标识 |
178
+ | `userMessages` / `assistantMessages` / `toolCalls` / `toolResults` | 计数 |
179
+ | `tokens` | `{ input, output, cacheRead, cacheWrite, total }`,含保温请求的用量 |
180
+ | `cost` | 美元;任一条消息缺成本时缺省(界面显示 `$?`) |
181
+ | `contextTokens` / `contextWindow` / `contextPercent` | 当前上下文估算、窗口与占用(0–100);模型没有窗口时缺省 |
182
+ | `cacheHitRate` | 旧口径命中率:cacheRead /(input + cacheRead + cacheWrite),全部请求进分母 |
183
+ | `cache` | `SessionCacheStats`(下例),会话层缓存控制器接线时才有 |
184
+
185
+ ```json
186
+ {
187
+ "type": "response",
188
+ "command": "get_session_stats",
189
+ "success": true,
190
+ "data": {
191
+ "tokens": { "input": 1177, "output": 64, "cacheRead": 2176, "cacheWrite": 0, "total": 3417 },
192
+ "cacheHitRate": 0.65,
193
+ "cache": {
194
+ "reporting": "reported",
195
+ "lastHitRate": 0.84,
196
+ "hitRate": 0.65,
197
+ "reBilledTokens": 0,
198
+ "reBilledUsd": 0,
199
+ "misses": { "count": 0, "byReason": {} },
200
+ "warming": { "mode": "streaming", "state": "stopped", "reason": "no_ttl" },
201
+ "contextRemainingTokens": 127077,
202
+ "estimatedTurnsLeft": 2443
203
+ }
204
+ }
205
+ }
206
+ ```
207
+
208
+ | `cache` 字段 | 说明 |
209
+ | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
210
+ | `reporting` | 当前端点(供应商、baseUrl 主机、模型)的三态:`unknown` / `reported` / `silent`;只在内存,同一进程内跨会话复用 |
211
+ | `lastHitRate` / `hitRate` | 最近一次 / 会话累计命中率(0–1);`unknown` / `silent` 时没有 `lastHitRate`,不报缓存的请求不进 `hitRate` 分母 |
212
+ | `reBilledTokens` / `reBilledUsd` | 未命中重计费合计;有无价模型参与时没有 `reBilledUsd` |
213
+ | `misses` | `count` 与 `byReason`(`prefix_changed` / `model_changed` / `idle` / `subtask` / `evicted`);统计计入全部未命中,不受界面提示门槛影响 |
214
+ | `warming` | `mode`(`off` / `streaming` / `idle`)、`state`(`inactive` / `scheduled` / `stopped`)、`phase?`、`nextWarmAt?`、停止原因 `reason?`、`sent?`、`costUsd?`、`expectedSavingsUsd?` |
215
+ | `contextRemainingTokens` / `estimatedTurnsLeft` | 上下文余量与按最近 5 回合增量估算的剩余回合 |
216
+ | `subagents` | task 子会话汇总:`count`、`hitRate?`、`reBilledTokens` |
217
+ | `granularity` | 可选:当前端点推断的缓存读分块粒度(token,非零 cacheRead 的最大公约数,≥ 2 个样本且在 128–8192 才给);未命中的噪声下限取它与 1024、`minTokens` 中的最大者 |
218
+
219
+ `tokens` / `cacheHitRate` 保持旧口径,新客户端用 `cache`。缓存事件示例:
220
+
221
+ ```json
222
+ {"type":"cache_miss","missedTokens":142000,"missedCost":0.1278,"reason":"evicted","idleMs":3}
223
+ {"type":"cache_warm","phase":"scheduled","nextWarmAt":1790000000000}
224
+ {"type":"cache_warm","phase":"sent","usage":{"input":1,"output":1,"cacheRead":12000,"cacheWrite":0,"totalTokens":12002},"cost":0.0012}
225
+ {"type":"cache_warm","phase":"stopped","reason":"no_cache_hits"}
226
+ {"type":"context_pressure","percent":71,"threshold":70,"remainingTokens":57990,"estimatedTurnsLeft":6}
227
+ ```
228
+
229
+ `cache_miss` 的 `detail` 只在 `prefix_changed` 时给出(`system` / `tools`)。`cache_warm{stopped}` 的 `reason` 取值与含义见 [tui.md](tui.md)「缓存与上下文」。`ama -p --output-format json` 的结果对象另有 `cache` 字段,形状同上。
230
+
231
+ ## 审批
232
+
233
+ 1. 工具调用需要确认时,服务端发 `permission_request`。`preview`(可选)是执行前预览:`{ kind: "bash" | "write" | "edit" | "other", lines: string[], severity: "info" | "warn" | "danger", affected?: { path, exists, bytes?, files? }[] }`,`lines` 已排好、不含颜色,可直接显示;预览只读、有上限,算不出时缺省。
234
+ 2. 客户端在此之前发过 `set_client_capabilities{capabilities:["approvals"]}` 才会被问到;否则这条 ask 无人作答 → deny。声明里去掉 `approvals` 会撤下客户端并让在等的审批全部按无人作答处理。
235
+ 3. 客户端回 `permission_response{requestId, decision}`。`allow_session` 在本会话内记住同一工具与归一化输入前缀,不落盘。先于请求到达的回答会暂存,等请求出现时使用。
236
+ 4. 回答者顺序:宿主 broker(`HostApi.approvals.setBroker`)→ RPC 客户端 → 无人作答 deny。审批串行,同一时刻只有一个在等。
237
+ 5. 超时:`timeoutMs`(缺省 600 000,即 10 分钟;环境变量 `AMA_APPROVAL_TIMEOUT_MS` 可改)内没有回答 → 服务端按 deny 处理并发 `permission_resolved`。运行被中断时同样 deny,即使客户端已经放行。
238
+
239
+ ## 退出
240
+
241
+ - stdin 关闭:不再接收命令,撤下审批(之后的 ask 按无人作答 deny),等在途命令与已开始的运行结束、响应写完,退出码 0。所以 `printf '{"type":"prompt","message":"hi"}\n' | ama --mode rpc` 能拿到完整回复;要提前停止,先发 `abort`。
242
+ - SIGINT / SIGTERM:中断当前运行后有序退出,退出码 130 / 143。
243
+ - 启动阶段的失败按 CLI 退出码([design.md](design.md) §11.3):配置错误 3、无模型或 key 4、会话错误 5、宿主 / Hook 启动失败 6、宿主 API 版本不匹配 78。
244
+
245
+ ## 示例
246
+
247
+ `test/fixtures/rpc/prompt.out.jsonl` 是一次完整往返的黄金文件(fake 供应商;`prompt` → `get_last_assistant_text`,会话 id、时间戳与路径已归一化):`hello` → `session_start` → `entry_appended`(模型、思考级别、首条 system 消息)→ `before_agent_start` → `agent_start` → `turn_start` → `prompt` 的响应 → 用户消息 → 助手消息的 `message_update` 增量 → `turn_end` → `agent_end` → `agent_before_settle` → `agent_settled` → 第二条命令的响应。改协议后由 `src/modes/rpc/rpc-mode.test.ts` 用 `UPDATE_GOLDEN=1` 更新并审阅差异。
248
+
249
+ 最小会话(stdin 关闭即撤下审批,所以管道方式只适合不需要审批的提示;要回答审批,保持 stdin 打开并先发 `set_client_capabilities`):
250
+
251
+ ```sh
252
+ printf '%s\n' '{"id":"1","type":"prompt","message":"hi"}' | ama --mode rpc --model anthropic/<model-id>
253
+ ```
@@ -0,0 +1,119 @@
1
+ # 会话文件格式(JSONL 条目树)
2
+
3
+ 会话是一个只追加的 JSONL 文件:首行是头,其后每行一个条目(以及可选的 `leaf` 行)。条目经 `parentId` 连成树,「当前分支」是从根到叶子的一条路径;发给模型的上下文由当前分支**投影**得到。类型定义在 `src/session/types.ts`(经 `@armadra/agent` 导出),格式版本 `SESSION_FORMAT_VERSION = 1`。设计依据见 [design.md](design.md) §8、§9。
4
+
5
+ ## 位置与文件
6
+
7
+ - 目录:`--session-dir` > profile `sessionDir` > `<数据目录>/sessions`(数据目录缺省 `~/.local/share/ama`,`AMA_DATA_DIR` 可改)。
8
+ - 文件:`<sessions>/<编码 cwd>/<ISO 时间>_<uuid>.jsonl`。编码 cwd = 去掉开头的分隔符,`/`、`\`、`:` 换成 `-`;ISO 时间里的 `:` 与 `.` 也换成 `-`。文件名里的 uuid 就是会话 id。
9
+ - 延迟落盘:新会话先在内存里,首次模型请求前才建文件、写头与已缓存的条目;之前退出不留文件。
10
+ - 只追加:每条记录一行 JSON + LF,以 O_APPEND 写入。打开时若末行是半行(写入中途崩溃),截掉半行再继续;中间行损坏 → 拒绝打开(`session_corrupt`,退出码 5),不猜测、不重写文件。
11
+ - 单写者锁:`<file>.lock`(O_EXCL 创建,内容为 pid);持锁进程已不在时视为陈旧锁并接管。
12
+ - `ama sessions prune [--older-than <天>]`(缺省 30 天)把文件移到 `<sessions>/.trash/`,文件名前缀删除时间;trash 里超过 7 天的再清理。
13
+
14
+ ## 头
15
+
16
+ ```json
17
+ {
18
+ "type": "session",
19
+ "version": 1,
20
+ "id": "0b7f…",
21
+ "timestamp": "2026-10-02T08:00:00.000Z",
22
+ "cwd": "/home/me/proj",
23
+ "agent": { "name": "ama", "version": "0.1.0" },
24
+ "parentSession": "/…/上一个会话.jsonl"
25
+ }
26
+ ```
27
+
28
+ `parentSession` 只在 fork 与 `task` 子会话里出现,指向来源文件。读取时 `version` 不是 1 → 拒绝并提示升级 ama;缺头、头损坏、条目缺 `id` 或 `type`、出现第二个头 → 拒绝。
29
+
30
+ ## 条目
31
+
32
+ 全部条目都有 `id`、`parentId`(根条目为 `null`)、`timestamp`(ISO 8601)。
33
+
34
+ | `type` | 字段 | 进上下文 |
35
+ | ----------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------- |
36
+ | `message` | `message`:`system` / `user` / `assistant` / `toolResult` 四种 LLM 消息 | 是 |
37
+ | `compaction` | `summary`、`firstKeptEntryId`、`tokensBefore`、`usage?`、`details?`(`readFiles` / `modifiedFiles`) | 是,作为摘要消息 |
38
+ | `branch_summary` | `fromId`、`summary`、`usage?`、`details?` | 是,作为分支摘要消息 |
39
+ | `context_edit` | `targetId`、`replacement: string \| null`、`reason: prune \| abort \| retry \| overflow \| manual` | 改写目标条目 |
40
+ | `model_change` | `provider`、`modelId`、可选 `channel`(多渠道供应商的渠道名) | 否(决定续会话时的模型) |
41
+ | `thinking_level_change` | `thinkingLevel` | 否(决定续会话时的思考级别) |
42
+ | `custom` | `customType`、`data` | 否 |
43
+ | `custom_message` | `customType`、`content`(字符串或内容块)、`display`、`details?` | 是,作为 custom 消息 |
44
+ | `label` | `targetId`、`label?`(缺省 = 清除标签) | 否 |
45
+ | `session_info` | `name?` | 否 |
46
+ | `usage` | `kind`、`provider`、`model`(不含 provider 的模型 id)、`usage` | 否 |
47
+
48
+ ### 消息
49
+
50
+ - `system`:`{ role: "system", sections, toolsAdded?, toolsRemoved?, timestamp }`。首条是全量:系统提示的命名节(固定顺序 `preamble → tools → rules → project_context → skills → hooks → cwd → host`)与工具声明表;之后只落**补丁**——节名级替换、值为 `null` 表示删除该节,`toolsAdded` / `toolsRemoved` 增删工具。依次重放得到当前系统提示;请求时由协议层重装全量。首条 system 消息在首次请求前落盘,也就是建文件的时刻。
51
+ - `user`:`content`、`origin?`(缺省 = 普通用户输入;`steer` / `followUp` 是运行中插话与排队,`host` 是宿主 `sendUser` 注入,其它字符串原样记录)。
52
+ - `assistant`:`content`(文本 / 思考 / 工具调用块)、`api`、`provider`、`model`、`usage`、`stopReason`,以及可选的 `responseId`、`thinkingLevel`、`providerThinkingLevel`、`rawStopReason`、`errorMessage`。`usage` 是 `{ input, output, cacheRead, cacheWrite, cacheWrite1h?, reasoning?, totalTokens, cost?, cacheReported? }`:`input` 不含缓存部分,`cost` 是 `{ input, output, cacheRead, cacheWrite, total }`(美元,模型无价格时缺省),`cacheReported` 表示原始响应里出现过缓存字段。
53
+ - `toolResult`:对应工具调用的结果(`toolCallId`、`toolName`、`content`、`isError`、`details?`)。
54
+
55
+ ### `usage` 条目
56
+
57
+ 不进上下文的请求用量,计入 `/session` 费用与 RPC 统计,投影时跳过。第一期只有 `kind: "cache_warm"`(缓存保温请求,见 [providers.md](providers.md)「缓存」):
58
+
59
+ ```json
60
+ {
61
+ "type": "usage",
62
+ "kind": "cache_warm",
63
+ "provider": "anthropic",
64
+ "model": "<model-id>",
65
+ "usage": {
66
+ "input": 1,
67
+ "output": 1,
68
+ "cacheRead": 12000,
69
+ "cacheWrite": 0,
70
+ "totalTokens": 12002,
71
+ "cost": { "input": 0, "output": 0, "cacheRead": 0.0036, "cacheWrite": 0, "total": 0.0036 }
72
+ },
73
+ "id": "…",
74
+ "parentId": "…",
75
+ "timestamp": "…"
76
+ }
77
+ ```
78
+
79
+ ### `leaf` 行
80
+
81
+ `/tree` 在同一文件里换叶子时追加一行 `{"type":"leaf","id":<条目 id 或 null>,"timestamp":…}`。它**不是条目**:没有 `parentId`,`get_entries` 与树不返回它,fork 不复制它。打开文件时,最后一条 `leaf` 行若在最后一条条目之后,就用它的 `id` 作叶子(`null` = 回到根之前的空分支);之后又追加了条目则作废。
82
+
83
+ `usage` 条目与 `leaf` 行都是 v1 的可选行,格式版本不升。
84
+
85
+ ## 投影
86
+
87
+ 当前分支 → 上下文消息(`src/session/projection.ts`):
88
+
89
+ 1. **压缩**:分支上若有 `compaction`,取最新一条。上下文 = 该 compaction(作为摘要消息)+ `firstKeptEntryId` 到它之间的非 system 条目 + 它之后的全部条目。compaction 之前的 system 消息依次重放后折成一条完整的 system **检查点**放在最前(文件里不另存检查点)。
90
+ 2. **改写**:对分支上每个目标取最新一条 `context_edit`:`replacement` 为 `null` → 从上下文剔除;字符串 → 只换内容,保留角色与元数据(assistant 换成一个文本块,摘要类换 `summary`,system 不改)。用途:档一裁剪旧工具结果(`prune`)、中断(`abort`)、失败重试的尝试(`retry`)、溢出恢复(`overflow`)、手动(`manual`)。
91
+ 3. **映射**:`message` → 原消息;`custom_message` → `{ role: "custom", customType, content, display, details? }`;`compaction` → `{ role: "compactionSummary", summary, tokensBefore }`;`branch_summary` → `{ role: "branchSummary", summary, fromId }`;其余类型(含 `usage` 与未知类型)不进上下文。
92
+ 4. **模型与思考级别**:分支上最近的 `model_change` / `thinking_level_change`,续会话时据此恢复。
93
+
94
+ 发给模型前,`convertToLlm` 把三种扩展角色(custom、compactionSummary、branchSummary)转成 user 消息。
95
+
96
+ ## 分支与 fork
97
+
98
+ - `/tree`:同一文件换叶子(落 `leaf` 行);从旧位置再发消息就形成新分支。离开的分支可以写 `branch_summary` 带进新分支。
99
+ - fork(`--fork <id>`、`/fork`、RPC `fork`):把根 → 指定条目的分支复制到新文件,头的 `parentSession` 指回原文件;不复制 `leaf` 行。
100
+ - `task` 子会话:独立文件,头带 `parentSession`,首条条目是 `custom{customType:"ama.task"}`。
101
+
102
+ ## custom 类型
103
+
104
+ `custom` 不进上下文,`custom_message` 进上下文。ama 自己使用的 `customType`:
105
+
106
+ | `customType` | 条目类型 | 内容 | 写入时机 |
107
+ | -------------------- | ---------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------- |
108
+ | `ama.todo` | `custom` | `data: { items: { id, text, status: pending \| in_progress \| done }[] }`,整表快照 | `todo` 工具 `set`;`get` 取分支上最近一条 |
109
+ | `ama.task` | `custom` | `data: { parentToolCallId, description, parentSession? }` | `task` 子会话的首条条目 |
110
+ | `ama.codemode-store` | `custom` | `data: { entries }`,`store()` 的完整快照 | codemode 脚本成功结束且写过 store;读取取分支上最近一条 |
111
+ | `ama.aborted` | `custom_message` | `content`:告诉模型上一条回复被用户中断;`display: false` | 用户中断运行 |
112
+ | `ama.hook_context` | `custom_message` | `content`:UserPromptSubmit Hook 的 `additionalContext`;`display: false` | 随用户提示进上下文 |
113
+
114
+ 其它程序(宿主、SDK 工具经 `ToolContext.session.appendCustom`)可以写自己的 `customType`;建议加前缀避免冲突,`ama.` 前缀保留给 ama。
115
+
116
+ ## 读取方
117
+
118
+ - `ama sessions list|show`、交互模式 `/resume`、RPC `get_entries{since}`(以 entry id 为游标返回 `{ entries, leafId }`)、`get_tree`。
119
+ - 嵌入方可以直接读文件:按行解析,首行为头,跳过 `type: "leaf"` 的行后按 `parentId` 建树;遇到不认识的条目类型保留但不进上下文。
package/docs/tui.md ADDED
@@ -0,0 +1,170 @@
1
+ # 终端界面
2
+
3
+ 交互模式的使用说明,以及终端组件库 `@armadra/agent/tui` 的 API。设计依据见 [design.md](design.md) §12。
4
+
5
+ `ama` 在终端里直接运行(stdin / stdout 都是 TTY、`TERM` 不是 `dumb`、没有 `--no-tui`)时进入交互模式。界面只用**主屏**:对话历史滚进终端回滚,不切备用屏,所以在 tmux 里 `capture-pane` 能读到完整对话,退出后对话也留在屏幕上。
6
+
7
+ ## 布局
8
+
9
+ ```
10
+ ama 0.1.0 · Enter 发送 · Esc 中断 · Ctrl+C 两次退出 · /help 命令 ← 启动画面
11
+ › 读一下 README ← 用户消息
12
+ 思考 · 120 token ← 思考块(折叠)
13
+ ● read README.md ← 工具调用
14
+ …前 3 行结果…
15
+ 回答正文(Markdown)
16
+ ↳ followUp 之后再提交 ← 排队消息
17
+ ⠋ 工作中 · Esc 中断 (12s) ← 运行中
18
+ ──────────────────────────────────
19
+ 输入框
20
+ ──────────────────────────────────
21
+ anthropic/claude-sonnet · think:medium · ↑12k ↓1.2k · cache 80% ♨ · $0.12 · rebill $0.11 · ctx 34% · mode:default · preset:default
22
+ ```
23
+
24
+ - **用户消息**:`›` 开头;运行中插话标 `↳ steer`,排到本轮之后的标 `↳ followUp`,宿主(Armadra 画布)注入的标 `↳ host`。
25
+ - **思考块**:`ui.showThinking` = `collapsed`(缺省,一行计数)/ `full`(全文)/ `hidden`。
26
+ - **工具调用**:一行标题,圆点运行中为强调色、成功绿、失败红;折叠显示结果前 3 行,`edit` 显示 diff(前 12 行),`bash` 运行中滚动显示最后 8 行。`Ctrl+O` 展开 / 折叠全部。codemode 脚本里的内层调用挂在外层调用下面。
27
+ - **提示**:压缩摘要卡、`↻ 重试 n/m`、`⛔ Hook 阻止`、宿主通知、审批被拒或超时的说明都进消息区。
28
+ - **状态栏**:模型 · 思考级别 · `↑` 输入(含缓存读写)`↓` 输出 · 缓存 · 费用 · 重计费 · 上下文占用 · 排队数 · 权限模式 · codemode · 工具预设 · 宿主状态。终端太窄时依次丢弃宿主状态、预设、重计费、费用、缓存、token、思考级别、排队数、codemode,模型、上下文与权限模式最后丢。
29
+
30
+ ## 缓存与上下文
31
+
32
+ 状态栏各项:
33
+
34
+ | 项 | 含义 |
35
+ | --------------- | ------------------------------------------------------------------------------------------------------------------- |
36
+ | `cache 83%` | **最近一次**请求的命中率(读缓存 /(输入 + 缓存读 + 缓存写));会话累计在 `/session` |
37
+ | `cache —` | 端点还没报过缓存(`unknown`:还没有足够长的可比请求) |
38
+ | `cache 未报告` | 端点不报缓存(`silent`:连续 3 个可比请求读写都是 0,或 `compat.cacheReporting: "silent"`);这类请求不进命中率分母 |
39
+ | `♨` | 保温计时中(工具长时间运行时按 TTL 重放前缀,`/cache warm` 可切换) |
40
+ | `rebill $0.11` | 本会话缓存未命中导致的重计费金额;模型没有价格时显示 token 数;为 0 不显示 |
41
+ | `ctx 72%` | 上下文占用,≥ 70% 黄色、≥ 90% 红色;`ctx ?` 表示模型没有窗口信息 |
42
+ | `codemode:only` | codemode 生效(`on` / `only`);运行时 Node 的权限模型不隔离网络(Node 22 / 24)时追加红色 `net!` |
43
+
44
+ 消息区(line 模式写 stderr,前缀 `ama: `)只在两种情况下提示一行,`cache.missNotices: false` 可关:
45
+
46
+ - 一次未命中重计费 ≥ 20k token 或 ≥ $0.10:`缓存未命中(空闲 7 分钟后):重计费 38.2k token(约 $0.11)`。原因有空闲超时、子任务运行、切换模型、系统提示 / 工具表变化、服务端淘汰;更小的未命中只进统计。
47
+ - 上下文占用跨过 70% / 90%(各一次):`上下文已用 72%,约剩 9 回合(按最近 5 回合均值)`;回合数估不出时给余量 token。
48
+ - line 模式在 `AMA_LOG=info` 时另写保温成功:`缓存保温已刷新(读 12k token,$0.001)`。
49
+
50
+ `/session` 在会话信息之后有「缓存」段,`/cache` 只显示这一段:
51
+
52
+ ```
53
+ 缓存
54
+ 输入 3.4k = 缓存读 2.2k(65%)+ 未缓存 1.2k
55
+ 报告状态 reported
56
+ 命中率 最近 84% · 会话 65%
57
+ 未命中 0 次
58
+ 保温 streaming · 已停止:模型目录没有缓存 TTL
59
+ 上下文 1%,余量 ≈ 127k token ≈ 2443 回合
60
+ ```
61
+
62
+ 未命中行按原因分列(`3 次,重计费 61k token ≈ $0.18(空闲超时 2 · 前缀变化 1)`);保温行在计时中显示 `streaming · 下次 2m 10s · 期望节省 $0.18 ≥ $0.05`,停止时给原因;有 task 子会话时另有「子任务」行。
63
+
64
+ - `/cache warm off|streaming|idle`:本会话内切换保温(不写配置;`idle` 在空闲时也保温,适合贵模型)。
65
+ - `/cache fingerprint`:最近一次真实请求的前缀指纹——system 与工具表各一个 16 位哈希加模型名。两次之间哈希变了,就是宿主或 Hook 中途改了系统提示 / 工具表。
66
+
67
+ 取舍:状态栏显示最近一次命中率(会话累计放 `/session`);`cache.missNotices` 缺省开(门槛下很少触发);`Meter` 组件不进缺省状态栏。命中率、未命中与保温的判定规则见 [providers.md](providers.md)「缓存」。
68
+
69
+ `ama models cache-probe <provider/model>` 用一个固定前缀相隔几秒发两次最小请求,判定端点 `reported` / `silent` / `inconclusive` 并给出配置建议(会计费:先打印预估,非交互环境需 `--yes`)。
70
+
71
+ ## 按键
72
+
73
+ | 按键 | 作用 |
74
+ | -------------------- | ------------------------------------------------------------------ |
75
+ | Enter | 发送;运行中 = steer(插到当前轮) |
76
+ | Alt+Enter | 运行中排到本轮之后(followUp);空闲时等同 Enter |
77
+ | Shift+Enter / Ctrl+J | 换行 |
78
+ | Esc | 中断:排队的消息回填到输入框,然后停止当前运行;补全打开时先关补全 |
79
+ | Alt+↑ | 取回最后一条排队消息 |
80
+ | Shift+Tab | 循环权限模式 plan → default → auto-edit → full-auto |
81
+ | Ctrl+O | 展开 / 折叠工具输出 |
82
+ | Ctrl+L / Ctrl+T | 选择模型 / 思考级别 |
83
+ | Ctrl+C | 清空输入;输入为空时 1.5 秒内再按一次退出(退出码 130) |
84
+ | Ctrl+D | 输入为空时退出 |
85
+ | Tab | 补全 |
86
+ | ↑ / ↓ | 单行时浏览历史(`<数据目录>/history`,500 条) |
87
+
88
+ 按键可在 `~/.config/ama/keybindings.json` 覆盖,键是动作 id(`app.interrupt`、`app.message.followUp`、`tui.editor.newLine` ……),值是按键或按键数组,空数组表示禁用。
89
+
90
+ ## 命令
91
+
92
+ `/help` 列出全部命令。交互模式另有:
93
+
94
+ - `/tree`:列出会话里的全部用户消息(分叉处缩进,`●` 是当前分支);选中一条后回到它之前,原文回填输入框,修改后发送就形成新分支。
95
+ - `/fork`(无参数):同样选一条用户消息,从它之前复制出新会话。
96
+ - `/model`、`/resume`、`/permission`、`/thinking` 不带参数时打开选择器;`/permissions` 显示权限判定顺序与已加载规则。
97
+ - `/model` 选择器按「供应商 · 渠道」分组(多渠道模型在每个渠道下各一项,非首选渠道带 `@渠道`),说明里有上下文与 `img`(收图片);`/model packy/kimi-k2.5@messages` 直接切到指定渠道。
98
+ - 输入里的 `@图片路径`(可加引号,Tab 补全路径)或粘贴 / 拖入的图片文件路径作为图片附件随消息发送;当前模型不收图片时 `@` 附件报错、不发送,未加 `@` 的路径忽略(见 [providers.md](providers.md)「图像输入」)。
99
+ - `/session`、`/cache`:会话用量与缓存统计(见下文「缓存与上下文」)。
100
+
101
+ ## 补全
102
+
103
+ - 首行行首输入 `/`:命令、提示模板(`/<名字>`)、Skill(`/skill:<名字>`)。
104
+ - `@`(行首或空格之后):当前目录下的文件与目录(尊重 `.gitignore`),含 `*` `?` `[` `{` 时按 glob 匹配相对路径。
105
+
106
+ ## 审批
107
+
108
+ 工具调用需要确认时,底部弹出对话框:bash 显示完整命令,write 显示路径与行数,edit 显示每处修改的 −/+ 摘要;子 Agent 发起的请求标 `[task]`。`y` 允许、`n` / Esc 拒绝、`a` 本会话内同类不再询问、`v` 查看完整输入。10 分钟不作答按拒绝处理(`AMA_APPROVAL_TIMEOUT_MS` 可改)。
109
+
110
+ 输入摘要之后是**执行前预览**:这一步会碰到什么。
111
+
112
+ - bash:识别每段命令(含 `sh -c`、`eval`、`xargs`、`find -exec` 里嵌套的命令)中的 `rm` / `rmdir` / `unlink`、`mv`、`git clean`、`git checkout -- <路径>`、`git reset --hard` 与 `>` / `>>` 重定向目标,列出路径是否存在、大小、目录里的文件数;通配符与变量不展开,原样显示并提示实际范围可能更大。
113
+ - write:目标是否存在、现有行数与大小 → 新内容;覆盖本会话没读过的文件标黄。
114
+ - edit:对原文干跑一遍,列出每处 −n/+m 行与总变化;匹配不到或不唯一时提前说明。
115
+
116
+ 预览按严重度着色(危险红、警告黄、其余暗色),只读、有上限:每个目录最多计 2000 项,整次预览 200 ms 预算,超出只给提示、不降低严重度;超过 2 MiB 的文件只报大小。预览失败不影响审批。line 模式在问句之前逐行打印同样的预览;RPC 客户端从 `permission_request.preview` 拿到它([rpc.md](rpc.md)「审批」)。
117
+
118
+ ## 启动画面
119
+
120
+ `ui.quietStartup` / `--quiet-startup`:`normal` 显示标题、模型、目录与信任状态、已加载的上下文文件 / Skill / 提示模板 / Hook;`header` 只有标题行(profile 缺省);`silent` 不显示。`--resume` 不带 id、模型没有 key、会话目录不存在、项目资源需要信任时,界面启动前会先出现一个小的选择 / 输入提示,答完收成一行留在屏幕上。
121
+
122
+ ## 在 tmux / Armadra 终端节点里
123
+
124
+ - 括号粘贴:启动时开启;粘贴的多行内容整体进入输入框(超过 10 行或 1 000 字符折叠为 `[paste #N +M lines]`),粘贴后紧跟的回车直接发送,适合由外部程序写入。
125
+ - 不查询终端能力、不开鼠标与 Kitty 键盘协议,避免回包混进输入;tmux ≥ 3.4 透传同步输出,旧版本也能正常显示。
126
+ - 窗口尺寸变化时整屏重画最后一屏,回滚里的历史不受影响。
127
+ - 自动降级:非 TTY、`TERM=dumb`、`--no-tui` 或终端初始化失败时使用行式界面,命令与审批问答相同。
128
+
129
+ ## 组件库(`@armadra/agent/tui`)
130
+
131
+ 交互模式用的终端组件单独导出,零依赖,宿主或其它 Node 程序可以直接用来画主屏界面。
132
+
133
+ ```ts
134
+ import { TUI, ProcessTerminal, Text, Editor, createTheme } from "@armadra/agent/tui";
135
+
136
+ const tui = new TUI(new ProcessTerminal());
137
+ const theme = createTheme("dark");
138
+ const log = new Text("");
139
+ const editor = new Editor({
140
+ theme,
141
+ requestRender: () => tui.requestRender(),
142
+ onSubmit: (text) => {
143
+ log.setText(`you said: ${text}`);
144
+ tui.requestRender();
145
+ },
146
+ });
147
+ tui.addChild(log);
148
+ tui.addChild(editor);
149
+ tui.setFocus(editor);
150
+ tui.start();
151
+ ```
152
+
153
+ | 导出 | 作用 |
154
+ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
155
+ | `Component`、`Focusable`、`CURSOR_MARKER` | 组件契约:`render(width)` 返回各行(每行可见宽 ≤ width)、`handleInput?(data)`、`invalidate()`;获焦组件在光标处输出 `CURSOR_MARKER` |
156
+ | `TUI` | 根容器与差分渲染(主屏、同步输出):`addChild`、`start` / `stop`、`requestRender`、`setFocus`、`addInputListener`、`showOverlay` |
157
+ | `ProcessTerminal`、`MemoryTerminal`、`VirtualScreen` | 真实终端(raw 模式、括号粘贴);内存终端与 VT 屏幕(测试、帧黄金) |
158
+ | `Container`、`Text`、`TruncatedText`、`Markdown`、`Box`、`Spacer`、`Loader` | 基础组件 |
159
+ | `Editor`、`EditorBuffer`、`PasteStore` | 多行编辑器(历史、补全接口 `AutocompleteProvider`、粘贴折叠) |
160
+ | `SelectList` | 可过滤的选择列表 |
161
+ | `KeyValue`、`Meter` | 两列对齐的键值表;进度条 |
162
+ | `compositeOverlays`、`OverlayOptions` | 覆盖层合成(居中 / 底部锚定) |
163
+ | `createTheme`、`plainTheme`、`detectCapabilities`、`Theme` | 主题与颜色能力探测(`NO_COLOR`、16 / 256 / truecolor);11 个语义色 |
164
+ | `Keybindings`、`DEFAULT_KEYBINDINGS`、`loadKeybindingsFile` | 动作 id → 按键,`keybindings.json` 覆盖 |
165
+ | `parseKey`、`matchesKey`、`StdinBuffer` | 键序列解析与 Esc 超时切分(`AMA_TUI_ESC_TIMEOUT`) |
166
+ | `visibleWidth`、`truncateToWidth`、`wrapTextWithAnsi`、`sliceByColumn` 等 | 带 ANSI 与宽字符的宽度计算与截断 |
167
+
168
+ ## 测试
169
+
170
+ `src/modes/interactive/interactive-mode.test.ts` 用 `MemoryTerminal`(80x24、40x24)+ fake 供应商跑一次完整的读文件 run,把启动、输入、工具运行中、结束、`Ctrl+O` 展开、退出各帧写进 `test/fixtures/tui/run-*.txt`。改界面后用 `AMA_UPDATE_GOLDEN=1 pnpm vitest run src/modes/interactive` 更新并审阅差异。