@armadra/agent 0.5.0 → 0.6.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 (471) hide show
  1. package/CHANGELOG.md +177 -294
  2. package/CHANGELOG.zh-CN.md +442 -0
  3. package/README.md +408 -364
  4. package/README.zh-CN.md +705 -0
  5. package/dist/agent/session-plan.js +2 -2
  6. package/dist/agent/session-state.d.ts +3 -0
  7. package/dist/agent/session-state.js +20 -0
  8. package/dist/agent/session-subagent.d.ts +15 -1
  9. package/dist/agent/session-subagent.js +26 -3
  10. package/dist/agent/session-telemetry.d.ts +16 -2
  11. package/dist/agent/session-telemetry.js +29 -7
  12. package/dist/agent/session-tools.js +5 -2
  13. package/dist/agent/session-trace-writer.d.ts +27 -0
  14. package/dist/agent/session-trace-writer.js +253 -0
  15. package/dist/agent/session.d.ts +2 -0
  16. package/dist/agent/session.js +12 -0
  17. package/dist/agent/subagent-direct.d.ts +20 -0
  18. package/dist/agent/subagent-direct.js +76 -0
  19. package/dist/agent/subagent-registry.d.ts +8 -1
  20. package/dist/agent/subagent-registry.js +28 -1
  21. package/dist/agent/system-prompt.d.ts +3 -1
  22. package/dist/agent/system-prompt.js +3 -0
  23. package/dist/agent/tool-runner.d.ts +2 -1
  24. package/dist/agent/tool-runner.js +5 -4
  25. package/dist/agent/types-w6.d.ts +39 -0
  26. package/dist/agent/types-w6.js +4 -0
  27. package/dist/agent/types.d.ts +5 -2
  28. package/dist/agents/external.js +1 -1
  29. package/dist/agents/task-record.d.ts +74 -1
  30. package/dist/agents/task-record.js +100 -0
  31. package/dist/ai/apis/cache-params.js +2 -1
  32. package/dist/ai/apis/chatgpt-backend.d.ts +52 -0
  33. package/dist/ai/apis/chatgpt-backend.js +224 -0
  34. package/dist/ai/apis/chatgpt-rate-limits.d.ts +26 -0
  35. package/dist/ai/apis/chatgpt-rate-limits.js +91 -0
  36. package/dist/ai/apis/openai-responses-request.d.ts +2 -1
  37. package/dist/ai/apis/openai-responses-request.js +8 -2
  38. package/dist/ai/apis/openai-responses.d.ts +2 -0
  39. package/dist/ai/apis/openai-responses.js +51 -16
  40. package/dist/ai/overflow.d.ts +1 -1
  41. package/dist/ai/overflow.js +10 -7
  42. package/dist/ai/providers/auth.d.ts +15 -2
  43. package/dist/ai/providers/auth.js +69 -2
  44. package/dist/ai/providers/builtin.js +27 -0
  45. package/dist/ai/providers/catalog-data.js +1 -0
  46. package/dist/ai/providers/enrich.js +2 -7
  47. package/dist/ai/providers/models-dev-cache.js +15 -19
  48. package/dist/ai/providers/models-dev-snapshot.js +8 -7
  49. package/dist/ai/providers/models-dev.js +5 -15
  50. package/dist/ai/providers/suggest.js +2 -16
  51. package/dist/ai/types.d.ts +27 -1
  52. package/dist/auth/chatgpt/backend-client.d.ts +26 -0
  53. package/dist/auth/chatgpt/backend-client.js +74 -0
  54. package/dist/auth/chatgpt/claims.d.ts +17 -0
  55. package/dist/auth/chatgpt/claims.js +46 -0
  56. package/dist/auth/chatgpt/cli.d.ts +33 -0
  57. package/dist/auth/chatgpt/cli.js +252 -0
  58. package/dist/auth/chatgpt/doctor.d.ts +17 -0
  59. package/dist/auth/chatgpt/doctor.js +36 -0
  60. package/dist/auth/chatgpt/host-id.d.ts +7 -0
  61. package/dist/auth/chatgpt/host-id.js +26 -0
  62. package/dist/auth/chatgpt/login.d.ts +30 -0
  63. package/dist/auth/chatgpt/login.js +130 -0
  64. package/dist/auth/chatgpt/presets.d.ts +66 -0
  65. package/dist/auth/chatgpt/presets.js +120 -0
  66. package/dist/auth/chatgpt/quota-text.d.ts +13 -0
  67. package/dist/auth/chatgpt/quota-text.js +36 -0
  68. package/dist/auth/oauth/browser.d.ts +12 -0
  69. package/dist/auth/oauth/browser.js +27 -0
  70. package/dist/auth/oauth/callback-server.d.ts +47 -0
  71. package/dist/auth/oauth/callback-server.js +147 -0
  72. package/dist/auth/oauth/flows.d.ts +62 -0
  73. package/dist/auth/oauth/flows.js +113 -0
  74. package/dist/auth/oauth/jwt.d.ts +24 -0
  75. package/dist/auth/oauth/jwt.js +81 -0
  76. package/dist/auth/oauth/live.d.ts +21 -0
  77. package/dist/auth/oauth/live.js +25 -0
  78. package/dist/auth/oauth/oidc.d.ts +26 -0
  79. package/dist/auth/oauth/oidc.js +72 -0
  80. package/dist/auth/oauth/pkce.d.ts +15 -0
  81. package/dist/auth/oauth/pkce.js +20 -0
  82. package/dist/auth/oauth/refresh.d.ts +35 -0
  83. package/dist/auth/oauth/refresh.js +129 -0
  84. package/dist/auth/oauth/token-client.d.ts +33 -0
  85. package/dist/auth/oauth/token-client.js +121 -0
  86. package/dist/auth/oauth/token-store.d.ts +23 -0
  87. package/dist/auth/oauth/token-store.js +125 -0
  88. package/dist/auth/testing/fake-oauth.d.ts +73 -0
  89. package/dist/auth/testing/fake-oauth.js +271 -0
  90. package/dist/auth/testing/refresh-child.d.ts +5 -0
  91. package/dist/auth/testing/refresh-child.js +16 -0
  92. package/dist/bundle/ama.cjs +28307 -13241
  93. package/dist/checkpoints/backend.js +6 -5
  94. package/dist/checkpoints/restore.js +3 -2
  95. package/dist/checkpoints/settings.js +2 -1
  96. package/dist/checkpoints/shadow-git.js +7 -6
  97. package/dist/checkpoints/shadow-restore.js +3 -2
  98. package/dist/checkpoints/tracker.js +4 -3
  99. package/dist/cli/args.d.ts +9 -2
  100. package/dist/cli/args.js +74 -27
  101. package/dist/cli/bootstrap.js +53 -31
  102. package/dist/cli/choice-prompt.d.ts +58 -0
  103. package/dist/cli/choice-prompt.js +142 -0
  104. package/dist/cli/codemode-notice.js +2 -2
  105. package/dist/cli/compose-agents.js +2 -1
  106. package/dist/cli/compose-extensions.js +2 -0
  107. package/dist/cli/compose-memory.d.ts +53 -0
  108. package/dist/cli/compose-memory.js +127 -0
  109. package/dist/cli/compose-providers.d.ts +5 -0
  110. package/dist/cli/compose-providers.js +32 -2
  111. package/dist/cli/compose-session.d.ts +5 -0
  112. package/dist/cli/compose-session.js +27 -13
  113. package/dist/cli/compose-store.d.ts +2 -0
  114. package/dist/cli/compose-store.js +9 -5
  115. package/dist/cli/compose.d.ts +2 -0
  116. package/dist/cli/compose.js +13 -5
  117. package/dist/cli/default-model.d.ts +0 -2
  118. package/dist/cli/default-model.js +5 -8
  119. package/dist/cli/deps.d.ts +5 -1
  120. package/dist/cli/exit-codes.d.ts +1 -1
  121. package/dist/cli/exit-codes.js +7 -16
  122. package/dist/cli/from-prompt.js +3 -2
  123. package/dist/cli/help-text.d.ts +2 -1
  124. package/dist/cli/help-text.js +5 -99
  125. package/dist/cli/main.d.ts +5 -0
  126. package/dist/cli/main.js +21 -2
  127. package/dist/cli/proxy.js +14 -9
  128. package/dist/cli/runtime.d.ts +5 -0
  129. package/dist/cli/startup-screen.js +20 -27
  130. package/dist/cli/startup-steps.js +6 -8
  131. package/dist/cli/subcommands/auth.d.ts +6 -3
  132. package/dist/cli/subcommands/auth.js +52 -22
  133. package/dist/cli/subcommands/config-set.d.ts +21 -0
  134. package/dist/cli/subcommands/config-set.js +137 -0
  135. package/dist/cli/subcommands/config.d.ts +2 -1
  136. package/dist/cli/subcommands/config.js +51 -37
  137. package/dist/cli/subcommands/doctor.d.ts +2 -1
  138. package/dist/cli/subcommands/doctor.js +97 -58
  139. package/dist/cli/subcommands/init.d.ts +1 -1
  140. package/dist/cli/subcommands/init.js +8 -7
  141. package/dist/cli/subcommands/memory.d.ts +18 -0
  142. package/dist/cli/subcommands/memory.js +189 -0
  143. package/dist/cli/subcommands/model-meta.js +11 -9
  144. package/dist/cli/subcommands/models-cache-probe.d.ts +1 -1
  145. package/dist/cli/subcommands/models-cache-probe.js +26 -32
  146. package/dist/cli/subcommands/models-discover.d.ts +3 -0
  147. package/dist/cli/subcommands/models-discover.js +44 -21
  148. package/dist/cli/subcommands/models.d.ts +1 -1
  149. package/dist/cli/subcommands/models.js +29 -22
  150. package/dist/cli/subcommands/probe-runner.js +8 -7
  151. package/dist/cli/subcommands/providers-list.js +32 -21
  152. package/dist/cli/subcommands/providers-plan.js +24 -25
  153. package/dist/cli/subcommands/providers-probe.js +5 -6
  154. package/dist/cli/subcommands/providers.d.ts +2 -2
  155. package/dist/cli/subcommands/providers.js +48 -59
  156. package/dist/cli/subcommands/sessions-export.d.ts +1 -1
  157. package/dist/cli/subcommands/sessions-export.js +10 -9
  158. package/dist/cli/subcommands/sessions-search.d.ts +1 -1
  159. package/dist/cli/subcommands/sessions-search.js +11 -10
  160. package/dist/cli/subcommands/sessions-trace.d.ts +30 -0
  161. package/dist/cli/subcommands/sessions-trace.js +156 -0
  162. package/dist/cli/subcommands/sessions.d.ts +4 -3
  163. package/dist/cli/subcommands/sessions.js +40 -37
  164. package/dist/cli/subcommands/stats.d.ts +1 -1
  165. package/dist/cli/subcommands/stats.js +49 -30
  166. package/dist/cli/system-prompt-arg.js +3 -2
  167. package/dist/codemode/capability.js +3 -2
  168. package/dist/compaction/post-compact.d.ts +1 -0
  169. package/dist/compaction/post-compact.js +15 -1
  170. package/dist/compaction/prune-tier.d.ts +1 -1
  171. package/dist/compaction/prune-tier.js +3 -3
  172. package/dist/compaction/serialize.js +2 -1
  173. package/dist/config/auth-file.d.ts +12 -2
  174. package/dist/config/auth-file.js +32 -10
  175. package/dist/config/checker.js +12 -11
  176. package/dist/config/context-files.js +3 -2
  177. package/dist/config/edit.d.ts +106 -0
  178. package/dist/config/edit.js +350 -0
  179. package/dist/config/init.d.ts +4 -3
  180. package/dist/config/init.js +10 -18
  181. package/dist/config/json-schema.d.ts +2 -1
  182. package/dist/config/json-schema.js +101 -68
  183. package/dist/config/key-docs.d.ts +18 -7
  184. package/dist/config/key-docs.js +43 -128
  185. package/dist/config/load.js +7 -6
  186. package/dist/config/merge.d.ts +4 -1
  187. package/dist/config/merge.js +42 -22
  188. package/dist/config/paths.js +6 -5
  189. package/dist/config/profile.d.ts +5 -1
  190. package/dist/config/profile.js +7 -2
  191. package/dist/config/schema-w5.js +3 -2
  192. package/dist/config/schema-w6.d.ts +19 -0
  193. package/dist/config/schema-w6.js +115 -0
  194. package/dist/config/schema.js +34 -20
  195. package/dist/config/settings-registry.d.ts +78 -0
  196. package/dist/config/settings-registry.js +184 -0
  197. package/dist/config/types-w6.d.ts +109 -0
  198. package/dist/config/types-w6.js +19 -0
  199. package/dist/config/types.d.ts +11 -8
  200. package/dist/config/types.js +1 -0
  201. package/dist/drivers/acp/client.js +1 -1
  202. package/dist/drivers/acp/driver.js +13 -8
  203. package/dist/drivers/agents.js +4 -3
  204. package/dist/drivers/base.js +3 -2
  205. package/dist/drivers/host-runners.js +2 -1
  206. package/dist/drivers/native/claude-stream.js +12 -11
  207. package/dist/drivers/native/codex-app-server.js +17 -12
  208. package/dist/drivers/native/oneshot.js +8 -7
  209. package/dist/drivers/pool.js +1 -1
  210. package/dist/drivers/runner.d.ts +3 -1
  211. package/dist/drivers/runner.js +68 -20
  212. package/dist/drivers/turn.js +1 -1
  213. package/dist/hooks/config.js +3 -2
  214. package/dist/hooks/protocol.js +18 -12
  215. package/dist/host/api-impl.js +11 -10
  216. package/dist/host/loader.js +9 -8
  217. package/dist/host/types.d.ts +3 -0
  218. package/dist/i18n/catalog.d.ts +2169 -0
  219. package/dist/i18n/catalog.js +72 -0
  220. package/dist/i18n/format.d.ts +21 -0
  221. package/dist/i18n/format.js +58 -0
  222. package/dist/i18n/index.d.ts +58 -0
  223. package/dist/i18n/index.js +72 -0
  224. package/dist/i18n/messages/agents.d.ts +84 -0
  225. package/dist/i18n/messages/agents.js +85 -0
  226. package/dist/i18n/messages/approval.d.ts +99 -0
  227. package/dist/i18n/messages/approval.js +100 -0
  228. package/dist/i18n/messages/auth.d.ts +187 -0
  229. package/dist/i18n/messages/auth.js +189 -0
  230. package/dist/i18n/messages/cli-args.d.ts +46 -0
  231. package/dist/i18n/messages/cli-args.js +46 -0
  232. package/dist/i18n/messages/cli-help.d.ts +12 -0
  233. package/dist/i18n/messages/cli-help.js +244 -0
  234. package/dist/i18n/messages/cli.d.ts +336 -0
  235. package/dist/i18n/messages/cli.js +311 -0
  236. package/dist/i18n/messages/config-keys.d.ts +289 -0
  237. package/dist/i18n/messages/config-keys.js +292 -0
  238. package/dist/i18n/messages/config.d.ts +502 -0
  239. package/dist/i18n/messages/config.js +239 -0
  240. package/dist/i18n/messages/drivers.d.ts +123 -0
  241. package/dist/i18n/messages/drivers.js +124 -0
  242. package/dist/i18n/messages/errors.d.ts +83 -0
  243. package/dist/i18n/messages/errors.js +171 -0
  244. package/dist/i18n/messages/interactive-line.d.ts +61 -0
  245. package/dist/i18n/messages/interactive-line.js +69 -0
  246. package/dist/i18n/messages/interactive-startup.d.ts +103 -0
  247. package/dist/i18n/messages/interactive-startup.js +104 -0
  248. package/dist/i18n/messages/interactive-view.d.ts +140 -0
  249. package/dist/i18n/messages/interactive-view.js +141 -0
  250. package/dist/i18n/messages/interactive.d.ts +493 -0
  251. package/dist/i18n/messages/interactive.js +248 -0
  252. package/dist/i18n/messages/memory.d.ts +123 -0
  253. package/dist/i18n/messages/memory.js +128 -0
  254. package/dist/i18n/messages/panels.d.ts +190 -0
  255. package/dist/i18n/messages/panels.js +189 -0
  256. package/dist/i18n/messages/permissions.d.ts +126 -0
  257. package/dist/i18n/messages/permissions.js +151 -0
  258. package/dist/i18n/messages/plan.d.ts +123 -0
  259. package/dist/i18n/messages/plan.js +124 -0
  260. package/dist/i18n/messages/print.d.ts +86 -0
  261. package/dist/i18n/messages/print.js +91 -0
  262. package/dist/i18n/messages/report.d.ts +391 -0
  263. package/dist/i18n/messages/report.js +490 -0
  264. package/dist/i18n/messages/rewind.d.ts +198 -0
  265. package/dist/i18n/messages/rewind.js +217 -0
  266. package/dist/i18n/messages/session.d.ts +230 -0
  267. package/dist/i18n/messages/session.js +258 -0
  268. package/dist/i18n/messages/settings.d.ts +348 -0
  269. package/dist/i18n/messages/settings.js +336 -0
  270. package/dist/i18n/messages/subcommands-config.d.ts +111 -0
  271. package/dist/i18n/messages/subcommands-config.js +127 -0
  272. package/dist/i18n/messages/subcommands.d.ts +548 -0
  273. package/dist/i18n/messages/subcommands.js +474 -0
  274. package/dist/i18n/messages/trace.d.ts +243 -0
  275. package/dist/i18n/messages/trace.js +238 -0
  276. package/dist/i18n/types.d.ts +15 -0
  277. package/dist/i18n/types.js +7 -0
  278. package/dist/index.d.ts +6 -0
  279. package/dist/index.js +2 -0
  280. package/dist/memory/edit.d.ts +24 -0
  281. package/dist/memory/edit.js +63 -0
  282. package/dist/memory/frontmatter.d.ts +37 -0
  283. package/dist/memory/frontmatter.js +79 -0
  284. package/dist/memory/index.d.ts +28 -0
  285. package/dist/memory/index.js +126 -0
  286. package/dist/memory/lock.d.ts +17 -0
  287. package/dist/memory/lock.js +62 -0
  288. package/dist/memory/paths.d.ts +57 -0
  289. package/dist/memory/paths.js +175 -0
  290. package/dist/memory/report.d.ts +36 -0
  291. package/dist/memory/report.js +86 -0
  292. package/dist/memory/runtime.d.ts +42 -0
  293. package/dist/memory/runtime.js +36 -0
  294. package/dist/memory/secrets.d.ts +8 -0
  295. package/dist/memory/secrets.js +27 -0
  296. package/dist/memory/section.d.ts +28 -0
  297. package/dist/memory/section.js +59 -0
  298. package/dist/memory/store.d.ts +70 -0
  299. package/dist/memory/store.js +284 -0
  300. package/dist/memory/tool.d.ts +31 -0
  301. package/dist/memory/tool.js +94 -0
  302. package/dist/modes/acp/acp-events.js +2 -1
  303. package/dist/modes/acp/acp-server.js +13 -12
  304. package/dist/modes/commands-core.d.ts +17 -0
  305. package/dist/modes/commands-core.js +101 -61
  306. package/dist/modes/image-input.js +20 -6
  307. package/dist/modes/interactive/agent-bar.d.ts +95 -0
  308. package/dist/modes/interactive/agent-bar.js +248 -0
  309. package/dist/modes/interactive/agent-panels.js +27 -26
  310. package/dist/modes/interactive/agent-transcript.d.ts +47 -0
  311. package/dist/modes/interactive/agent-transcript.js +191 -0
  312. package/dist/modes/interactive/agent-ui.d.ts +36 -1
  313. package/dist/modes/interactive/agent-ui.js +180 -14
  314. package/dist/modes/interactive/agent-view.d.ts +72 -0
  315. package/dist/modes/interactive/agent-view.js +281 -0
  316. package/dist/modes/interactive/approval-dialog.js +46 -34
  317. package/dist/modes/interactive/clipboard-paste.d.ts +2 -2
  318. package/dist/modes/interactive/clipboard-paste.js +9 -4
  319. package/dist/modes/interactive/commands.d.ts +22 -1
  320. package/dist/modes/interactive/commands.js +93 -38
  321. package/dist/modes/interactive/completion.js +2 -1
  322. package/dist/modes/interactive/config-panel.d.ts +70 -0
  323. package/dist/modes/interactive/config-panel.js +319 -0
  324. package/dist/modes/interactive/config-ui.d.ts +96 -0
  325. package/dist/modes/interactive/config-ui.js +397 -0
  326. package/dist/modes/interactive/confirm-dialog.d.ts +49 -0
  327. package/dist/modes/interactive/confirm-dialog.js +120 -0
  328. package/dist/modes/interactive/event-notices.js +11 -9
  329. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  330. package/dist/modes/interactive/interactive-mode.js +25 -22
  331. package/dist/modes/interactive/key-dispatch.d.ts +18 -0
  332. package/dist/modes/interactive/key-dispatch.js +39 -13
  333. package/dist/modes/interactive/line/line-editor.js +2 -1
  334. package/dist/modes/interactive/line/line-mode.d.ts +2 -0
  335. package/dist/modes/interactive/line/line-mode.js +24 -4
  336. package/dist/modes/interactive/line/line-render.js +25 -24
  337. package/dist/modes/interactive/memory-panel.d.ts +64 -0
  338. package/dist/modes/interactive/memory-panel.js +221 -0
  339. package/dist/modes/interactive/message-view.d.ts +4 -2
  340. package/dist/modes/interactive/message-view.js +42 -33
  341. package/dist/modes/interactive/panels.js +39 -31
  342. package/dist/modes/interactive/pickers.d.ts +2 -1
  343. package/dist/modes/interactive/pickers.js +10 -6
  344. package/dist/modes/interactive/plan-command.d.ts +1 -1
  345. package/dist/modes/interactive/plan-command.js +24 -27
  346. package/dist/modes/interactive/plan-dialog.js +18 -17
  347. package/dist/modes/interactive/plan-flow.js +6 -5
  348. package/dist/modes/interactive/rewind-command.d.ts +1 -1
  349. package/dist/modes/interactive/rewind-command.js +18 -16
  350. package/dist/modes/interactive/rewind-flow.d.ts +0 -1
  351. package/dist/modes/interactive/rewind-flow.js +13 -14
  352. package/dist/modes/interactive/rewind-list.js +7 -6
  353. package/dist/modes/interactive/rewind-panel.js +40 -40
  354. package/dist/modes/interactive/rewind-text.d.ts +5 -3
  355. package/dist/modes/interactive/rewind-text.js +48 -38
  356. package/dist/modes/interactive/run-indicator.js +15 -12
  357. package/dist/modes/interactive/session-events.js +3 -2
  358. package/dist/modes/interactive/startup-header.js +22 -23
  359. package/dist/modes/interactive/startup-ui.js +41 -29
  360. package/dist/modes/interactive/status-area.d.ts +2 -0
  361. package/dist/modes/interactive/status-area.js +8 -2
  362. package/dist/modes/interactive/status-bar.js +4 -3
  363. package/dist/modes/interactive/subagent-view.js +9 -7
  364. package/dist/modes/interactive/tasks-report.d.ts +6 -0
  365. package/dist/modes/interactive/tasks-report.js +28 -31
  366. package/dist/modes/interactive/terminal-setup.d.ts +9 -0
  367. package/dist/modes/interactive/terminal-setup.js +23 -0
  368. package/dist/modes/interactive/tool-summary.js +19 -17
  369. package/dist/modes/interactive/tool-view.js +7 -4
  370. package/dist/modes/interactive/trace-view.d.ts +89 -0
  371. package/dist/modes/interactive/trace-view.js +332 -0
  372. package/dist/modes/print/print-mode.js +14 -15
  373. package/dist/modes/rpc/commands.js +7 -3
  374. package/dist/modes/rpc/rpc-mode.js +9 -3
  375. package/dist/modes/session-report.d.ts +2 -0
  376. package/dist/modes/session-report.js +101 -105
  377. package/dist/modes/startup-ui-text.js +11 -6
  378. package/dist/permissions/bypass.d.ts +30 -0
  379. package/dist/permissions/bypass.js +45 -0
  380. package/dist/permissions/memory-class.d.ts +23 -0
  381. package/dist/permissions/memory-class.js +54 -0
  382. package/dist/permissions/modes.d.ts +3 -3
  383. package/dist/permissions/modes.js +21 -16
  384. package/dist/permissions/pipeline.d.ts +1 -1
  385. package/dist/permissions/pipeline.js +9 -2
  386. package/dist/permissions/preview.js +49 -42
  387. package/dist/permissions/rules.js +5 -2
  388. package/dist/permissions/types.d.ts +4 -0
  389. package/dist/plan/store.js +2 -1
  390. package/dist/rpc.d.ts +39 -1
  391. package/dist/rpc.js +3 -0
  392. package/dist/sandbox/bash.js +11 -8
  393. package/dist/sandbox/detect.js +14 -11
  394. package/dist/sdk.d.ts +17 -1
  395. package/dist/sdk.js +29 -7
  396. package/dist/session/export.js +31 -30
  397. package/dist/session/manager.d.ts +1 -1
  398. package/dist/session/manager.js +5 -3
  399. package/dist/session/reuse.js +5 -4
  400. package/dist/session/scan.js +3 -2
  401. package/dist/session/stats-aggregate.d.ts +3 -1
  402. package/dist/session/stats-aggregate.js +5 -1
  403. package/dist/session/stats-index.js +2 -1
  404. package/dist/session/stats-scan.d.ts +4 -1
  405. package/dist/session/stats-scan.js +6 -2
  406. package/dist/session/store.d.ts +11 -0
  407. package/dist/session/store.js +48 -1
  408. package/dist/session/types.d.ts +2 -0
  409. package/dist/skills/builtin.js +2 -1
  410. package/dist/tools/image-file.d.ts +26 -1
  411. package/dist/tools/image-file.js +55 -13
  412. package/dist/tools/presets.d.ts +14 -1
  413. package/dist/tools/presets.js +3 -3
  414. package/dist/tools/registry.js +1 -1
  415. package/dist/tools/truncate.d.ts +1 -1
  416. package/dist/tools/truncate.js +2 -2
  417. package/dist/tools/types.d.ts +17 -1
  418. package/dist/trace/build-index.d.ts +91 -0
  419. package/dist/trace/build-index.js +127 -0
  420. package/dist/trace/build-nodes.d.ts +24 -0
  421. package/dist/trace/build-nodes.js +279 -0
  422. package/dist/trace/build-util.d.ts +43 -0
  423. package/dist/trace/build-util.js +120 -0
  424. package/dist/trace/build.d.ts +82 -0
  425. package/dist/trace/build.js +382 -0
  426. package/dist/trace/detail.d.ts +35 -0
  427. package/dist/trace/detail.js +205 -0
  428. package/dist/trace/flatten.d.ts +69 -0
  429. package/dist/trace/flatten.js +173 -0
  430. package/dist/trace/format.d.ts +47 -0
  431. package/dist/trace/format.js +329 -0
  432. package/dist/trace/html-template.d.ts +19 -0
  433. package/dist/trace/html-template.js +150 -0
  434. package/dist/trace/html.d.ts +104 -0
  435. package/dist/trace/html.js +292 -0
  436. package/dist/trace/preview.d.ts +29 -0
  437. package/dist/trace/preview.js +59 -0
  438. package/dist/trace/query-session.d.ts +14 -0
  439. package/dist/trace/query-session.js +38 -0
  440. package/dist/trace/query.d.ts +55 -0
  441. package/dist/trace/query.js +188 -0
  442. package/dist/trace/session.d.ts +40 -0
  443. package/dist/trace/session.js +168 -0
  444. package/dist/trace/types.d.ts +243 -0
  445. package/dist/trace/types.js +13 -0
  446. package/dist/tui/components/editor-paste.d.ts +2 -0
  447. package/dist/tui/components/editor-paste.js +6 -3
  448. package/dist/tui/components/editor.js +2 -2
  449. package/dist/tui/components/loader.d.ts +3 -0
  450. package/dist/tui/components/loader.js +14 -0
  451. package/dist/tui/components/settings-list.d.ts +61 -0
  452. package/dist/tui/components/settings-list.js +135 -0
  453. package/dist/tui/keybindings.d.ts +6 -1
  454. package/dist/tui/keybindings.js +18 -6
  455. package/dist/tui.d.ts +1 -0
  456. package/dist/tui.js +2 -0
  457. package/docs/en/host-api.md +167 -0
  458. package/docs/en/permissions.md +214 -0
  459. package/docs/en/providers.md +625 -0
  460. package/docs/en/rpc.md +361 -0
  461. package/docs/en/sessions.md +219 -0
  462. package/docs/en/tui.md +527 -0
  463. package/docs/host-api.md +18 -17
  464. package/docs/memory.md +172 -0
  465. package/docs/permissions.md +3 -2
  466. package/docs/providers.md +67 -1
  467. package/docs/rpc.md +31 -3
  468. package/docs/session-format.md +8 -2
  469. package/docs/sessions.md +29 -1
  470. package/docs/tui.md +189 -21
  471. package/package.json +8 -3
@@ -7,6 +7,7 @@
7
7
  *
8
8
  * `modelItems` / `sessionItems` 同时供交互模式里的选择器(pickers.ts)使用。
9
9
  */
10
+ import { msg } from "../../i18n/index.js";
10
11
  import { existsSync, statSync } from "node:fs";
11
12
  import { resolve } from "node:path";
12
13
  import { Container, Editor, ProcessTerminal, SelectList, TUI, Text, createTheme, defaultKeybindings, detectCapabilities, } from "../../tui.js";
@@ -43,12 +44,13 @@ function askSelect(r, prompt) {
43
44
  keybindings: r.keys,
44
45
  maxVisible: 10,
45
46
  filterable: prompt.filterable === true,
47
+ ...(prompt.numberKeys === true ? { numberKeys: true } : {}),
46
48
  onSelect: (item) => {
47
49
  finish(item.label);
48
50
  done(item);
49
51
  },
50
52
  onCancel: () => {
51
- finish("(已取消)");
53
+ finish(msg().interactive.startup.ui.cancelled);
52
54
  done(undefined);
53
55
  },
54
56
  });
@@ -56,8 +58,10 @@ function askSelect(r, prompt) {
56
58
  list.selectValue(prompt.selected);
57
59
  body.addChild(list);
58
60
  body.addChild(new Text(r.theme.fg("dim", prompt.filterable === true
59
- ? "输入过滤 · ↑↓ 选择 · Enter 确认 · Esc 取消"
60
- : "↑↓ 选择 · Enter 确认 · Esc 取消")));
61
+ ? msg().interactive.startup.ui.hintFilter("↑↓")
62
+ : prompt.numberKeys === true
63
+ ? msg().interactive.startup.ui.hintNumbers("↑↓", prompt.items.length)
64
+ : msg().interactive.startup.ui.hint("↑↓"))));
61
65
  tui.start();
62
66
  tui.setFocus(list);
63
67
  });
@@ -89,7 +93,7 @@ function askText(r, prompt) {
89
93
  body.addChild(error);
90
94
  tui.addInputListener((data) => {
91
95
  if (r.keys.matches(data, "tui.select.cancel") && !editor.isCompletionOpen) {
92
- finish("(已取消)");
96
+ finish(msg().interactive.startup.ui.cancelled);
93
97
  done(undefined);
94
98
  return true;
95
99
  }
@@ -128,11 +132,11 @@ export async function modelItems(providers) {
128
132
  let status;
129
133
  let ready = true;
130
134
  if (!provider.requiresApiKey)
131
- status = "本地";
135
+ status = msg().interactive.startup.ui.local;
132
136
  else {
133
137
  const key = await providers.resolveApiKey(provider.id).catch(() => ({ apiKey: undefined }));
134
138
  ready = key.apiKey !== undefined;
135
- status = ready ? "key ✓" : "无 key";
139
+ status = ready ? "key ✓" : msg().interactive.startup.ui.noKey;
136
140
  }
137
141
  const item = (model, group, channel) => {
138
142
  const suffix = channel !== undefined && channel !== model.channel ? `@${channel}` : "";
@@ -165,17 +169,18 @@ export function relativeTime(iso, now) {
165
169
  const at = Date.parse(iso);
166
170
  if (!Number.isFinite(at))
167
171
  return "";
172
+ const m = msg().interactive.startup.ui;
168
173
  const minutes = Math.floor((now - at) / 60_000);
169
174
  if (minutes < 1)
170
- return "刚刚";
175
+ return m.justNow;
171
176
  if (minutes < 60)
172
- return `${minutes} 分钟前`;
177
+ return m.minutesAgo(minutes);
173
178
  const hours = Math.floor(minutes / 60);
174
179
  if (hours < 24)
175
- return `${hours} 小时前`;
180
+ return m.hoursAgo(hours);
176
181
  const days = Math.floor(hours / 24);
177
182
  if (days < 30)
178
- return `${days} 天前`;
183
+ return m.daysAgo(days);
179
184
  return iso.slice(0, 10);
180
185
  }
181
186
  function oneLine(text, max = 60) {
@@ -189,18 +194,21 @@ export function sessionItems(items, now) {
189
194
  .map((item) => ({
190
195
  value: item.id,
191
196
  label: oneLine(item.name ?? item.firstPrompt ?? item.id.slice(0, 8)),
192
- description: `${relativeTime(item.modifiedAt, now)} · ${item.messageCount} 条`,
197
+ description: `${relativeTime(item.modifiedAt, now)} · ${msg().interactive.startup.ui.messages(item.messageCount)}`,
193
198
  }));
194
199
  }
195
200
  // ---------------------------------------------------------------------------
196
201
  // InteractiveUi
197
202
  // ---------------------------------------------------------------------------
198
- const TRUST_CHOICES = [
199
- { value: "trust", label: "信任并记住", answer: { trusted: true, remember: true } },
200
- { value: "once", label: "仅本次信任", answer: { trusted: true, remember: false } },
201
- { value: "skip", label: "本次不信任", answer: { trusted: false, remember: false } },
202
- { value: "never", label: "不信任并记住", answer: { trusted: false, remember: true } },
203
- ];
203
+ function trustChoices() {
204
+ const m = msg().interactive.startup.ui;
205
+ return [
206
+ { value: "trust", label: m.trustRemember, answer: { trusted: true, remember: true } },
207
+ { value: "once", label: m.trustOnce, answer: { trusted: true, remember: false } },
208
+ { value: "skip", label: m.trustSkip, answer: { trusted: false, remember: false } },
209
+ { value: "never", label: m.trustNever, answer: { trusted: false, remember: true } },
210
+ ];
211
+ }
204
212
  function isDirectory(path) {
205
213
  try {
206
214
  return statSync(path).isDirectory();
@@ -213,23 +221,26 @@ export function createStartupUi(options = {}) {
213
221
  const r = resolveOptions(options);
214
222
  return {
215
223
  async promptTrust(cwd, resources) {
224
+ const m = msg().interactive.startup.ui;
225
+ const choices = trustChoices();
216
226
  const shown = resources.slice(0, 6).map((p) => ` ${p}`);
217
227
  if (resources.length > shown.length)
218
- shown.push(` …另有 ${resources.length - shown.length} 项`);
228
+ shown.push(m.moreResources(resources.length - shown.length));
219
229
  const picked = await askSelect(r, {
220
- title: "信任这个目录的项目资源?",
230
+ title: m.trustTitle,
221
231
  lines: [cwd, ...shown],
222
- items: TRUST_CHOICES.map(({ value, label }) => ({ value, label })),
232
+ items: choices.map(({ value, label }) => ({ value, label })),
223
233
  selected: "once",
234
+ numberKeys: true,
224
235
  });
225
- const choice = TRUST_CHOICES.find((c) => c.value === picked?.value);
236
+ const choice = choices.find((c) => c.value === picked?.value);
226
237
  return choice?.answer ?? { trusted: false, remember: false };
227
238
  },
228
239
  async pickSession(items) {
229
240
  if (items.length === 0)
230
241
  return undefined;
231
242
  const picked = await askSelect(r, {
232
- title: "恢复哪个会话?",
243
+ title: msg().interactive.startup.ui.resumeTitle,
233
244
  items: sessionItems(items, r.now()),
234
245
  filterable: true,
235
246
  });
@@ -240,7 +251,7 @@ export function createStartupUi(options = {}) {
240
251
  if (items.length === 0)
241
252
  return undefined;
242
253
  const picked = await askSelect(r, {
243
- title: "选择模型",
254
+ title: msg().interactive.startup.ui.modelTitle,
244
255
  lines: [reason],
245
256
  items,
246
257
  filterable: true,
@@ -248,18 +259,19 @@ export function createStartupUi(options = {}) {
248
259
  return picked?.value;
249
260
  },
250
261
  askCwd(missing) {
262
+ const m = msg().interactive.startup.ui;
251
263
  return askText(r, {
252
- title: "会话的工作目录不存在",
253
- lines: [missing, "输入替代目录(Enter 确认 · Esc 取消)"],
254
- placeholder: "目录路径",
264
+ title: m.cwdTitle,
265
+ lines: [missing, m.cwdPrompt],
266
+ placeholder: m.cwdPlaceholder,
255
267
  validate: (text) => {
256
268
  if (text === "")
257
- return "请输入目录";
269
+ return m.cwdEmpty;
258
270
  const abs = resolve(text);
259
271
  if (!existsSync(abs))
260
- return `不存在:${abs}`;
272
+ return m.cwdMissing(abs);
261
273
  if (!isDirectory(abs))
262
- return `不是目录:${abs}`;
274
+ return m.cwdNotDir(abs);
263
275
  return undefined;
264
276
  },
265
277
  });
@@ -53,6 +53,8 @@ export declare class StatusArea {
53
53
  private bashSandbox;
54
54
  constructor(deps: StatusAreaDeps);
55
55
  layout(): StatusLineMode;
56
+ /** [W6-A] 界面配置(Agent 栏开关、子 Agent 视图的消息显示选项)。 */
57
+ ui(): NonNullable<Runtime["config"]["ui"]>;
56
58
  setLayout(mode: StatusLineMode): void;
57
59
  toggle(): StatusLineMode;
58
60
  refresh(): void;
@@ -9,6 +9,7 @@
9
9
  * - [W5-U] `model_fallback` 之后状态栏模型项显示 `主模型 → 回退模型`,切回主模型(`model_changed`)后消失。
10
10
  * - `telemetry_tick`(流式中 ≤ 2 Hz)只重取统计并重画(速率行),状态栏的内容这时不变。
11
11
  */
12
+ import { msg } from "../../i18n/index.js";
12
13
  import { basename } from "node:path";
13
14
  import { sandboxCapabilityFor } from "../../codemode/capability.js";
14
15
  import { formatModelRef } from "../../ai/providers/channels.js";
@@ -86,6 +87,10 @@ export class StatusArea {
86
87
  layout() {
87
88
  return this.mode;
88
89
  }
90
+ /** [W6-A] 界面配置(Agent 栏开关、子 Agent 视图的消息显示选项)。 */
91
+ ui() {
92
+ return this.deps.runtime.config.ui ?? {};
93
+ }
89
94
  setLayout(mode) {
90
95
  if (mode === this.mode)
91
96
  return;
@@ -179,12 +184,13 @@ export function statusLineSlash(area, line, notice) {
179
184
  else if (value === "full" || value === "compact")
180
185
  area.setLayout(value);
181
186
  else {
182
- notice("error", "用法:/statusline [full|compact]");
187
+ notice("error", msg().interactive.statusLine.usage);
183
188
  return true;
184
189
  }
185
190
  notice("info", statusLineText(area.layout()));
186
191
  return true;
187
192
  }
188
193
  export function statusLineText(mode) {
189
- return mode === "full" ? "状态栏:完整(两行)" : "状态栏:精简(一行)";
194
+ const m = msg().interactive.statusLine;
195
+ return mode === "full" ? m.full : m.compact;
190
196
  }
@@ -26,6 +26,7 @@
26
26
  * - 宽度不够时按优先级丢弃(数字大的先丢,表见 §1.2);会变的数字按最宽形状占位(`reserve`),
27
27
  * 数字变化不会让某项时有时无(40 列不抖动)。
28
28
  */
29
+ import { msg } from "../../i18n/index.js";
29
30
  import { permissionModeLabel } from "../../permissions/modes.js";
30
31
  import { formatModelRef } from "../../ai/providers/channels.js";
31
32
  import { Meter, levelColor, truncateToWidth, visibleWidth, } from "../../tui.js";
@@ -57,7 +58,7 @@ export function formatDuration(ms) {
57
58
  export function cacheText(cache, warm = "♨") {
58
59
  const rate = cache.lastHitRate ?? cache.hitRate;
59
60
  const value = cache.reporting === "silent"
60
- ? "未报告"
61
+ ? msg().interactive.statusLine.cacheSilent
61
62
  : cache.reporting === "reported" && rate !== undefined
62
63
  ? `${Math.round(rate * 100)}%`
63
64
  : "—";
@@ -178,7 +179,7 @@ export function usageItems(stats, queue, source, theme) {
178
179
  out.codemode = strict ? label : `${label} ${theme.fg("error", "net!")}`;
179
180
  }
180
181
  if (source.bashSandbox?.() === true)
181
- out.sandbox = dim("沙箱");
182
+ out.sandbox = dim(msg().interactive.statusLine.sandbox);
182
183
  const preset = source.preset();
183
184
  if (preset !== "default")
184
185
  out.preset = dim(`preset ${preset}`);
@@ -262,7 +263,7 @@ export class StatusBar {
262
263
  });
263
264
  if (width >= 40) {
264
265
  parts.push({
265
- text: dim("shift+tab 切换"),
266
+ text: dim(msg().interactive.statusLine.cycleHint),
266
267
  priority: full ? FULL_HINT : COMPACT.hint,
267
268
  zone: "left",
268
269
  });
@@ -13,6 +13,7 @@
13
13
  * 完成后父会话收到的 `<task-notification>` 只显示一行(`notificationSummary`),失败 / 停止另有一行提示。
14
14
  * 外部 runner(claude / codex)同一组事件,用量可能缺。
15
15
  */
16
+ import { msg } from "../../i18n/index.js";
16
17
  import { formatElapsed } from "../../tui.js";
17
18
  import { formatTokenCount } from "../session-report.js";
18
19
  import { taskStatusText } from "./tasks-report.js";
@@ -96,10 +97,12 @@ export function subagentLine(state, theme, now) {
96
97
  const g = theme.glyphs;
97
98
  const end = state.endedAt ?? now;
98
99
  const elapsed = formatElapsed(end - state.startedAt);
99
- const status = state.status === "running" ? `运行中 ${elapsed}` : `${taskStatusText(state.status)} ${elapsed}`;
100
+ const status = state.status === "running"
101
+ ? msg().interactive.subagent.running(elapsed)
102
+ : `${taskStatusText(state.status)} ${elapsed}`;
100
103
  const facts = [status];
101
104
  if (state.turns > 0)
102
- facts.push(`${state.turns} 轮`);
105
+ facts.push(msg().panels.tasks.turns(state.turns));
103
106
  if (state.tools.length > 0)
104
107
  facts.push(state.tools.join(" "));
105
108
  const usage = state.usage;
@@ -113,14 +116,13 @@ export function subagentLine(state, theme, now) {
113
116
  ? "error"
114
117
  : "warning";
115
118
  const agent = state.runner !== "ama" && state.runner !== state.agent
116
- ? `${state.agent}(${state.runner})`
119
+ ? msg().panels.tasks.agentRunner(state.agent, state.runner)
117
120
  : state.agent;
118
121
  return theme.fg("tool", agent) + theme.fg("dim", " · ") + theme.fg(color, facts.join(" · "));
119
122
  }
120
123
  /** 后台任务结束的一行提示。 */
121
124
  export function backgroundEndText(state) {
122
- const turns = state.turns > 0 ? ` · ${state.turns} 轮` : "";
123
- return `后台任务 ${state.taskId}(${state.agent})${taskStatusText(state.status)}${turns} · /tasks 查看输出`;
125
+ return msg().interactive.subagent.backgroundEnd(state.taskId, state.agent, taskStatusText(state.status), state.turns);
124
126
  }
125
127
  /**
126
128
  * 父会话收到的 `<task-notification …>`(origin `task` 的用户消息)在消息区只显示一行:
@@ -141,8 +143,8 @@ export function notificationSummary(text) {
141
143
  ];
142
144
  const turns = attrs.get("turns");
143
145
  if (turns !== undefined)
144
- parts.push(`${turns} 轮`);
145
- parts.push("/tasks 查看输出");
146
+ parts.push(msg().interactive.subagent.notificationTurns(turns));
147
+ parts.push(msg().interactive.subagent.viewOutput);
146
148
  return parts.join(" · ");
147
149
  }
148
150
  const STATUS_KEYS = {
@@ -23,5 +23,11 @@ export declare function describeTasks(sessionId: string, now: number): string;
23
23
  export declare function describeTaskOutput(sessionId: string, taskId: string, now: number): string;
24
24
  /** 类型一行的状态:外部 Agent 写安装与版本。 */
25
25
  export declare function agentFacts(agent: AgentInfo): string[];
26
+ /** [W6-C0] 带状态的事实项:界面按 `state` 上色,不按文案判断(文案会随界面语言变)。 */
27
+ export interface AgentFact {
28
+ text: string;
29
+ state?: "missing" | "installed";
30
+ }
31
+ export declare function agentFactItems(agent: AgentInfo): AgentFact[];
26
32
  /** `/agents` 的纯文本(line 模式)。 */
27
33
  export declare function describeAgents(sessionId: string): string;
@@ -7,18 +7,11 @@
7
7
  */
8
8
  import { cachedAgentInfos } from "../../agents/external.js";
9
9
  import { registryOf, sessionAgents, taskRegistryView } from "../../agent/subagent-registry.js";
10
+ import { msg } from "../../i18n/index.js";
10
11
  import { formatTokenCount, formatUsd } from "../session-report.js";
11
12
  import { formatDuration } from "./tool-summary.js";
12
- const STATUS = {
13
- running: "运行中",
14
- completed: "完成",
15
- failed: "失败",
16
- aborted: "已停止",
17
- max_turns: "轮数耗尽",
18
- interrupted: "已中断",
19
- };
20
13
  export function taskStatusText(status) {
21
- return STATUS[status];
14
+ return msg().panels.tasks.status[status];
22
15
  }
23
16
  export function listTasks(sessionId) {
24
17
  return taskRegistryView(sessionId)?.list() ?? [];
@@ -41,7 +34,7 @@ export function taskFacts(task, now) {
41
34
  const end = task.endedAt ?? now;
42
35
  const facts = [taskStatusText(task.status), formatDuration(end - task.startedAt)];
43
36
  if (task.turns !== undefined && task.turns > 0)
44
- facts.push(`${task.turns} 轮`);
37
+ facts.push(msg().panels.tasks.turns(task.turns));
45
38
  const usage = task.usage;
46
39
  if (usage !== undefined && usage.input + usage.output + usage.cacheRead > 0)
47
40
  facts.push(`↑${formatTokenCount(usage.input + usage.cacheRead + usage.cacheWrite)} ↓${formatTokenCount(usage.output)}`);
@@ -55,60 +48,64 @@ function oneLine(text, max = 60) {
55
48
  }
56
49
  /** `t1 explore · 运行中 · 1m05s · 7 轮 · 描述` */
57
50
  export function taskLine(task, now) {
51
+ const m = msg().panels.tasks;
58
52
  const agent = task.runner !== "ama" && task.runner !== task.agent
59
- ? `${task.agent}(${task.runner})`
53
+ ? m.agentRunner(task.agent, task.runner)
60
54
  : task.agent;
61
55
  const parts = [agent, ...taskFacts(task, now)];
62
56
  if (task.background)
63
- parts.push("后台");
57
+ parts.push(m.background);
64
58
  const description = oneLine(task.description);
65
59
  return `${task.taskId} ${parts.join(" · ")}${description !== "" ? ` ${description}` : ""}`;
66
60
  }
67
61
  /** `/tasks` 的纯文本(line 模式)。 */
68
62
  export function describeTasks(sessionId, now) {
63
+ const m = msg().panels.tasks;
69
64
  const tasks = listTasks(sessionId);
70
65
  if (tasks.length === 0)
71
- return "还没有子 Agent 任务";
66
+ return m.none;
72
67
  return [
73
- `子 Agent 任务(${tasks.length}):`,
68
+ m.heading(tasks.length),
74
69
  ...tasks.map((task) => ` ${taskLine(task, now)}`),
75
- "/tasks <id> 查看输出 · /tasks stop <id> 停止",
70
+ m.footer,
76
71
  ].join("\n");
77
72
  }
78
73
  /** 一个任务的输出全文(line 模式 `/tasks <id>`)。 */
79
74
  export function describeTaskOutput(sessionId, taskId, now) {
75
+ const m = msg().panels.tasks;
80
76
  const task = taskRegistryView(sessionId)?.get(taskId);
81
77
  if (task === undefined)
82
- return `没有任务 ${taskId}`;
78
+ return m.notFound(taskId);
83
79
  const output = taskOutput(sessionId, taskId) ?? "";
84
- const file = task.outputFile !== undefined ? `\n全文:${task.outputFile}` : "";
85
- return `${taskLine(task, now)}${file}\n${output.trim() === "" ? "(还没有输出)" : output.trimEnd()}`;
80
+ const file = task.outputFile !== undefined ? `\n${m.fullOutput(task.outputFile)}` : "";
81
+ return `${taskLine(task, now)}${file}\n${output.trim() === "" ? m.noOutput : output.trimEnd()}`;
82
+ }
83
+ function sourceText(source) {
84
+ const table = msg().panels.agents.source;
85
+ return table[source] ?? source;
86
86
  }
87
- const SOURCE = {
88
- builtin: "内置",
89
- cli: "命令行",
90
- profile: "profile",
91
- user: "用户",
92
- project: "项目",
93
- host: "宿主",
94
- };
95
87
  /** 类型一行的状态:外部 Agent 写安装与版本。 */
96
88
  export function agentFacts(agent) {
97
- const facts = [agent.runner, SOURCE[agent.source] ?? agent.source];
89
+ return agentFactItems(agent).map((fact) => fact.text);
90
+ }
91
+ export function agentFactItems(agent) {
92
+ const m = msg().panels.agents;
93
+ const facts = [{ text: agent.runner }, { text: sourceText(agent.source) }];
98
94
  if (agent.installed === false)
99
- facts.push("未安装");
95
+ facts.push({ text: m.notInstalled, state: "missing" });
100
96
  else if (agent.installed === true)
101
- facts.push(agent.version !== undefined ? `已安装 ${agent.version}` : "已安装");
97
+ facts.push({ text: m.installed(agent.version), state: "installed" });
102
98
  return facts;
103
99
  }
104
100
  /** `/agents` 的纯文本(line 模式)。 */
105
101
  export function describeAgents(sessionId) {
102
+ const m = msg().panels.agents;
106
103
  const agents = listAgents(sessionId);
107
104
  if (agents.length === 0)
108
- return "当前会话没有子 Agent(task 工具未启用)";
105
+ return m.none;
109
106
  const width = Math.max(...agents.map((a) => a.name.length));
110
107
  return [
111
- `子 Agent 类型(${agents.length}):`,
108
+ m.typesHeading(agents.length),
112
109
  ...agents.map((a) => ` ${a.name.padEnd(width)} ${agentFacts(a).join(" · ")} ${oneLine(a.description)}`),
113
110
  ].join("\n");
114
111
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 交互模式装配用到的两个小工具(从 interactive-mode.ts 拆出,控制单文件行数):真实终端与 keybindings.json。
3
+ */
4
+ import type { Runtime } from "../../cli/runtime.js";
5
+ import { Keybindings, type Terminal } from "../../tui.js";
6
+ /** stdin / stdout 都是 TTY 才用真实终端;否则抛 `terminal_init_failed`(调用方降级到行式界面)。 */
7
+ export declare function processTerminal(): Terminal;
8
+ /** 读 `<configDir>/keybindings.json`;问题逐条交给 `warn`。 */
9
+ export declare function loadKeys(runtime: Runtime, warn: (m: string) => void): Keybindings;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 交互模式装配用到的两个小工具(从 interactive-mode.ts 拆出,控制单文件行数):真实终端与 keybindings.json。
3
+ */
4
+ import { join } from "node:path";
5
+ import { KEYBINDINGS_FILE } from "../../config/paths.js";
6
+ import { AmaError } from "../../errors.js";
7
+ import { msg } from "../../i18n/index.js";
8
+ import { Keybindings, ProcessTerminal, loadKeybindingsFile } from "../../tui.js";
9
+ /** stdin / stdout 都是 TTY 才用真实终端;否则抛 `terminal_init_failed`(调用方降级到行式界面)。 */
10
+ export function processTerminal() {
11
+ const stdin = process.stdin;
12
+ if (stdin.isTTY !== true || typeof stdin.setRawMode !== "function" || !process.stdout.isTTY) {
13
+ throw new AmaError("terminal_init_failed", msg().interactive.app.notTty);
14
+ }
15
+ return new ProcessTerminal();
16
+ }
17
+ /** 读 `<configDir>/keybindings.json`;问题逐条交给 `warn`。 */
18
+ export function loadKeys(runtime, warn) {
19
+ const parsed = loadKeybindingsFile(join(runtime.paths.configDir, KEYBINDINGS_FILE));
20
+ for (const w of parsed.warnings)
21
+ warn(msg().interactive.app.keybindingsWarning(w));
22
+ return new Keybindings(parsed.overrides);
23
+ }
@@ -8,6 +8,7 @@
8
8
  * - grep `N 处匹配 · M 个文件`;glob `N 个文件`;codemode `N 个内层调用 · 脚本输出 M 行`;
9
9
  * - task `完成 · 耗时 · ↑in ↓out`;其它 `N 行输出`;失败(非 bash)取错误首行。
10
10
  */
11
+ import { msg } from "../../i18n/index.js";
11
12
  import { isAbsolute, relative } from "node:path";
12
13
  import { stripAnsi } from "../../tui.js";
13
14
  import { formatTokens } from "./status-bar.js";
@@ -135,6 +136,7 @@ export function bashOutput(result) {
135
136
  /** 完成后的一行结果摘要(已着色,不含 `⎿`)。 */
136
137
  export function resultSummary(input, theme) {
137
138
  const { name, result, isError, lines } = input;
139
+ const m = msg().interactive.view.tool;
138
140
  const details = record(result.details);
139
141
  const muted = (s) => theme.fg("muted", s);
140
142
  const sep = theme.fg("dim", " · ");
@@ -146,27 +148,27 @@ export function resultSummary(input, theme) {
146
148
  const code = num(details["exit_code"]) ?? (isError ? 1 : 0);
147
149
  const total = num(details["totalLines"]) ?? count;
148
150
  const head = details["aborted"] === true
149
- ? "已中断"
151
+ ? m.interrupted
150
152
  : details["timedOut"] === true
151
- ? "超时"
152
- : `退出 ${code}`;
153
- const parts = [head, duration, ...(total > 0 ? [`${total} 行`] : [])];
153
+ ? m.timedOut
154
+ : m.exit(code);
155
+ const parts = [head, duration, ...(total > 0 ? [m.lines(total)] : [])];
154
156
  const text = parts.join(" · ");
155
157
  return isError || code !== 0 ? theme.fg("error", text) : parts.map(muted).join(sep);
156
158
  }
157
159
  if (isError)
158
- return theme.fg("error", `${theme.glyphs.fail} ${lines[0] ?? "失败"}`);
160
+ return theme.fg("error", `${theme.glyphs.fail} ${lines[0] ?? m.failed}`);
159
161
  switch (name) {
160
162
  case "read": {
161
163
  const mime = details["mimeType"];
162
164
  if (typeof mime === "string")
163
- return muted(`图片 ${mime}`);
165
+ return muted(m.image(mime));
164
166
  const first = num(details["firstLine"]);
165
167
  const last = num(details["lastLine"]);
166
168
  if (num(details["totalLines"]) === 0)
167
- return muted("空文件");
169
+ return muted(m.emptyFile);
168
170
  const n = first !== undefined && last !== undefined ? last - first + 1 : count;
169
- return muted(`读取 ${n} 行`);
171
+ return muted(m.read(n));
170
172
  }
171
173
  case "edit": {
172
174
  const rows = parseDiff(diffOf(result) ?? "");
@@ -174,7 +176,7 @@ export function resultSummary(input, theme) {
174
176
  const del = rows.filter((r) => r.kind === "del").length;
175
177
  const edits = record(input.args)["edits"];
176
178
  const n = num(details["replacements"]) ?? (Array.isArray(edits) ? edits.length : 1);
177
- return (muted(`${n} 处修改`) +
179
+ return (muted(m.edits(n)) +
178
180
  sep +
179
181
  theme.fg("success", `+${add}`) +
180
182
  " " +
@@ -183,23 +185,23 @@ export function resultSummary(input, theme) {
183
185
  case "write": {
184
186
  const content = record(input.args)["content"];
185
187
  const n = typeof content === "string" ? cleanLines(content).length : 0;
186
- return muted(`${details["created"] === true ? "新建" : "覆盖"} · ${n} 行`);
188
+ return muted(m.write(details["created"] === true, n));
187
189
  }
188
190
  case "grep": {
189
191
  const matches = num(details["matches"]);
190
192
  if (matches === 0)
191
- return muted("无匹配");
193
+ return muted(m.noMatch);
192
194
  if (matches === undefined)
193
- return muted(`${count} 行`);
194
- return muted(`${matches} 处匹配 · ${num(details["files"]) ?? "?"} 个文件`);
195
+ return muted(m.lines(count));
196
+ return muted(m.matches(matches, num(details["files"])));
195
197
  }
196
198
  case "glob": {
197
199
  const n = num(details["count"]);
198
- return muted(n === 0 ? "无匹配" : `${n ?? count} 个文件`);
200
+ return muted(n === 0 ? m.noMatch : m.files(n ?? count));
199
201
  }
200
202
  case "codemode": {
201
203
  const calls = num(details["toolCalls"]) ?? input.nestedCount ?? 0;
202
- return muted(`${calls} 个内层调用 · 脚本输出 ${count} 行`);
204
+ return muted(m.codemode(calls, count));
203
205
  }
204
206
  case "task": {
205
207
  const usage = record(details["usage"]);
@@ -210,9 +212,9 @@ export function resultSummary(input, theme) {
210
212
  `${theme.glyphs.arrowUp}${formatTokens(input_)} ${theme.glyphs.arrowDown}${formatTokens(output)}`,
211
213
  ]
212
214
  : [];
213
- return muted(["完成", duration, ...tokens].join(" · "));
215
+ return muted([m.done, duration, ...tokens].join(" · "));
214
216
  }
215
217
  default:
216
- return muted(count === 0 ? "完成" : `${count} 行输出`);
218
+ return muted(count === 0 ? m.done : m.outputLines(count));
217
219
  }
218
220
  }
@@ -20,6 +20,7 @@
20
20
  * - 自定义渲染(`ToolDefinition.renderCall / renderResult`):标题摘要优先取 `renderCall` 第一行;成功的结果
21
21
  * 正文优先用 `renderResult`;抛错或返回空时回到缺省显示;错误结果始终用缺省显示。
22
22
  */
23
+ import { msg } from "../../i18n/index.js";
23
24
  import { formatElapsed, truncateToWidth, wrapTextWithAnsi, } from "../../tui.js";
24
25
  import { contentText } from "./message-view.js";
25
26
  import { subagentLine } from "./subagent-view.js";
@@ -159,7 +160,7 @@ export class ToolView {
159
160
  const g = theme.glyphs;
160
161
  const lead = " " + theme.fg("border", g.result) + " ";
161
162
  if (this.state === "running" && this.awaiting) {
162
- return truncateToWidth(lead + theme.fg("dim", `${g.spinnerStatic} 等待确认`), width);
163
+ return truncateToWidth(lead + theme.fg("dim", msg().interactive.view.tool.awaiting(g.spinnerStatic)), width);
163
164
  }
164
165
  const sub = this.subagentState();
165
166
  if (this.state === "running" && sub !== undefined) {
@@ -170,7 +171,8 @@ export class ToolView {
170
171
  if (this.state === "running") {
171
172
  const frame = this.options.spinner?.() ?? g.spinnerStatic;
172
173
  const elapsed = formatElapsed(this.now() - this.startedAt);
173
- const what = this.toolName === "task" ? `子 Agent · 运行中 ${elapsed}` : `运行中 · ${elapsed}`;
174
+ const m = msg().interactive.view.tool;
175
+ const what = this.toolName === "task" ? m.subagentRunning(elapsed) : m.running(elapsed);
174
176
  return truncateToWidth(lead + theme.fg("accent", frame) + " " + theme.fg("muted", what), width);
175
177
  }
176
178
  const result = this.result;
@@ -251,7 +253,7 @@ export class ToolView {
251
253
  }
252
254
  more(hidden) {
253
255
  const { theme } = this.options;
254
- return BODY + theme.fg("dim", `${theme.glyphs.ellipsis} 另 ${hidden} 行(Ctrl+O 展开)`);
256
+ return (BODY + theme.fg("dim", msg().interactive.view.tool.moreLines(theme.glyphs.ellipsis, hidden)));
255
257
  }
256
258
  nestedLines(width) {
257
259
  const { theme } = this.options;
@@ -269,7 +271,8 @@ export class ToolView {
269
271
  const shown = this.nested.slice(-COLLAPSED_CHILDREN);
270
272
  if (this.nested.length > shown.length) {
271
273
  const hidden = this.nested.length - shown.length;
272
- out.push(BODY + theme.fg("dim", `${theme.glyphs.ellipsis} 前 ${hidden} 个调用`));
274
+ out.push(BODY +
275
+ theme.fg("dim", msg().interactive.view.tool.earlierCalls(theme.glyphs.ellipsis, hidden)));
273
276
  }
274
277
  for (const child of shown) {
275
278
  out.push(BODY + child.header(inner));