@armadra/agent 0.5.1 → 0.6.1

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 (486) hide show
  1. package/CHANGELOG.md +203 -304
  2. package/CHANGELOG.zh-CN.md +462 -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/discovered-cache.d.ts +48 -0
  47. package/dist/ai/providers/discovered-cache.js +102 -0
  48. package/dist/ai/providers/enrich.js +2 -7
  49. package/dist/ai/providers/model-visibility.d.ts +33 -0
  50. package/dist/ai/providers/model-visibility.js +70 -0
  51. package/dist/ai/providers/models-dev-cache.js +15 -19
  52. package/dist/ai/providers/models-dev-snapshot.js +8 -7
  53. package/dist/ai/providers/models-dev.js +5 -15
  54. package/dist/ai/providers/registry.d.ts +2 -0
  55. package/dist/ai/providers/registry.js +6 -1
  56. package/dist/ai/providers/suggest.js +2 -16
  57. package/dist/ai/types.d.ts +27 -1
  58. package/dist/auth/chatgpt/backend-client.d.ts +26 -0
  59. package/dist/auth/chatgpt/backend-client.js +74 -0
  60. package/dist/auth/chatgpt/claims.d.ts +17 -0
  61. package/dist/auth/chatgpt/claims.js +46 -0
  62. package/dist/auth/chatgpt/cli.d.ts +35 -0
  63. package/dist/auth/chatgpt/cli.js +279 -0
  64. package/dist/auth/chatgpt/doctor.d.ts +17 -0
  65. package/dist/auth/chatgpt/doctor.js +36 -0
  66. package/dist/auth/chatgpt/host-id.d.ts +7 -0
  67. package/dist/auth/chatgpt/host-id.js +26 -0
  68. package/dist/auth/chatgpt/login.d.ts +30 -0
  69. package/dist/auth/chatgpt/login.js +130 -0
  70. package/dist/auth/chatgpt/presets.d.ts +66 -0
  71. package/dist/auth/chatgpt/presets.js +120 -0
  72. package/dist/auth/chatgpt/quota-text.d.ts +13 -0
  73. package/dist/auth/chatgpt/quota-text.js +36 -0
  74. package/dist/auth/oauth/browser.d.ts +12 -0
  75. package/dist/auth/oauth/browser.js +27 -0
  76. package/dist/auth/oauth/callback-server.d.ts +47 -0
  77. package/dist/auth/oauth/callback-server.js +147 -0
  78. package/dist/auth/oauth/flows.d.ts +62 -0
  79. package/dist/auth/oauth/flows.js +113 -0
  80. package/dist/auth/oauth/jwt.d.ts +24 -0
  81. package/dist/auth/oauth/jwt.js +81 -0
  82. package/dist/auth/oauth/live.d.ts +21 -0
  83. package/dist/auth/oauth/live.js +25 -0
  84. package/dist/auth/oauth/oidc.d.ts +26 -0
  85. package/dist/auth/oauth/oidc.js +72 -0
  86. package/dist/auth/oauth/pkce.d.ts +15 -0
  87. package/dist/auth/oauth/pkce.js +20 -0
  88. package/dist/auth/oauth/refresh.d.ts +35 -0
  89. package/dist/auth/oauth/refresh.js +129 -0
  90. package/dist/auth/oauth/token-client.d.ts +33 -0
  91. package/dist/auth/oauth/token-client.js +121 -0
  92. package/dist/auth/oauth/token-store.d.ts +23 -0
  93. package/dist/auth/oauth/token-store.js +125 -0
  94. package/dist/auth/testing/fake-oauth.d.ts +73 -0
  95. package/dist/auth/testing/fake-oauth.js +271 -0
  96. package/dist/auth/testing/refresh-child.d.ts +5 -0
  97. package/dist/auth/testing/refresh-child.js +16 -0
  98. package/dist/bundle/ama.cjs +26532 -11045
  99. package/dist/checkpoints/backend.js +6 -5
  100. package/dist/checkpoints/restore.js +3 -2
  101. package/dist/checkpoints/settings.js +2 -1
  102. package/dist/checkpoints/shadow-git.js +7 -6
  103. package/dist/checkpoints/shadow-restore.js +3 -2
  104. package/dist/checkpoints/tracker.js +4 -3
  105. package/dist/cli/args.d.ts +9 -2
  106. package/dist/cli/args.js +74 -27
  107. package/dist/cli/bootstrap.js +53 -31
  108. package/dist/cli/choice-prompt.js +8 -6
  109. package/dist/cli/codemode-notice.js +2 -2
  110. package/dist/cli/compose-agents.js +2 -1
  111. package/dist/cli/compose-extensions.js +2 -0
  112. package/dist/cli/compose-memory.d.ts +53 -0
  113. package/dist/cli/compose-memory.js +127 -0
  114. package/dist/cli/compose-providers.d.ts +6 -0
  115. package/dist/cli/compose-providers.js +38 -2
  116. package/dist/cli/compose-session.d.ts +5 -0
  117. package/dist/cli/compose-session.js +27 -13
  118. package/dist/cli/compose-store.d.ts +2 -0
  119. package/dist/cli/compose-store.js +9 -5
  120. package/dist/cli/compose.d.ts +2 -0
  121. package/dist/cli/compose.js +13 -5
  122. package/dist/cli/default-model.d.ts +0 -2
  123. package/dist/cli/default-model.js +5 -8
  124. package/dist/cli/deps.d.ts +5 -1
  125. package/dist/cli/exit-codes.d.ts +1 -1
  126. package/dist/cli/exit-codes.js +7 -16
  127. package/dist/cli/from-prompt.js +3 -2
  128. package/dist/cli/help-text.d.ts +2 -1
  129. package/dist/cli/help-text.js +5 -99
  130. package/dist/cli/main.d.ts +5 -0
  131. package/dist/cli/main.js +21 -2
  132. package/dist/cli/proxy.js +14 -9
  133. package/dist/cli/runtime.d.ts +5 -0
  134. package/dist/cli/startup-screen.js +20 -27
  135. package/dist/cli/startup-steps.js +6 -8
  136. package/dist/cli/subcommands/auth.d.ts +6 -3
  137. package/dist/cli/subcommands/auth.js +52 -22
  138. package/dist/cli/subcommands/config-set.d.ts +21 -0
  139. package/dist/cli/subcommands/config-set.js +145 -0
  140. package/dist/cli/subcommands/config.d.ts +2 -1
  141. package/dist/cli/subcommands/config.js +51 -37
  142. package/dist/cli/subcommands/doctor.d.ts +2 -1
  143. package/dist/cli/subcommands/doctor.js +97 -58
  144. package/dist/cli/subcommands/init.d.ts +1 -1
  145. package/dist/cli/subcommands/init.js +8 -7
  146. package/dist/cli/subcommands/memory.d.ts +18 -0
  147. package/dist/cli/subcommands/memory.js +189 -0
  148. package/dist/cli/subcommands/model-meta.js +11 -9
  149. package/dist/cli/subcommands/models-cache-probe.js +23 -20
  150. package/dist/cli/subcommands/models-discover.d.ts +4 -0
  151. package/dist/cli/subcommands/models-discover.js +60 -21
  152. package/dist/cli/subcommands/models-enable.d.ts +13 -0
  153. package/dist/cli/subcommands/models-enable.js +145 -0
  154. package/dist/cli/subcommands/models.d.ts +3 -1
  155. package/dist/cli/subcommands/models.js +39 -24
  156. package/dist/cli/subcommands/probe-runner.js +8 -7
  157. package/dist/cli/subcommands/providers-list.js +32 -21
  158. package/dist/cli/subcommands/providers-plan.js +24 -25
  159. package/dist/cli/subcommands/providers-probe.js +5 -6
  160. package/dist/cli/subcommands/providers.d.ts +1 -1
  161. package/dist/cli/subcommands/providers.js +45 -50
  162. package/dist/cli/subcommands/sessions-export.d.ts +1 -1
  163. package/dist/cli/subcommands/sessions-export.js +10 -9
  164. package/dist/cli/subcommands/sessions-search.d.ts +1 -1
  165. package/dist/cli/subcommands/sessions-search.js +11 -10
  166. package/dist/cli/subcommands/sessions-trace.d.ts +30 -0
  167. package/dist/cli/subcommands/sessions-trace.js +156 -0
  168. package/dist/cli/subcommands/sessions.d.ts +4 -3
  169. package/dist/cli/subcommands/sessions.js +40 -37
  170. package/dist/cli/subcommands/stats.d.ts +1 -1
  171. package/dist/cli/subcommands/stats.js +49 -30
  172. package/dist/cli/system-prompt-arg.js +3 -2
  173. package/dist/codemode/capability.js +3 -2
  174. package/dist/compaction/post-compact.d.ts +1 -0
  175. package/dist/compaction/post-compact.js +15 -1
  176. package/dist/compaction/prune-tier.d.ts +1 -1
  177. package/dist/compaction/prune-tier.js +3 -3
  178. package/dist/compaction/serialize.js +2 -1
  179. package/dist/config/auth-file.d.ts +12 -2
  180. package/dist/config/auth-file.js +32 -10
  181. package/dist/config/checker.js +12 -11
  182. package/dist/config/context-files.js +3 -2
  183. package/dist/config/edit.d.ts +106 -0
  184. package/dist/config/edit.js +350 -0
  185. package/dist/config/init.d.ts +4 -3
  186. package/dist/config/init.js +10 -18
  187. package/dist/config/json-schema.d.ts +2 -1
  188. package/dist/config/json-schema.js +102 -69
  189. package/dist/config/key-docs.d.ts +18 -7
  190. package/dist/config/key-docs.js +43 -128
  191. package/dist/config/load.js +7 -6
  192. package/dist/config/merge.d.ts +4 -1
  193. package/dist/config/merge.js +42 -22
  194. package/dist/config/paths.js +6 -5
  195. package/dist/config/profile.d.ts +5 -1
  196. package/dist/config/profile.js +7 -2
  197. package/dist/config/schema-w5.js +12 -4
  198. package/dist/config/schema-w6.d.ts +19 -0
  199. package/dist/config/schema-w6.js +115 -0
  200. package/dist/config/schema.js +34 -20
  201. package/dist/config/settings-registry.d.ts +81 -0
  202. package/dist/config/settings-registry.js +185 -0
  203. package/dist/config/types-w5.d.ts +7 -0
  204. package/dist/config/types-w5.js +2 -0
  205. package/dist/config/types-w6.d.ts +109 -0
  206. package/dist/config/types-w6.js +19 -0
  207. package/dist/config/types.d.ts +11 -8
  208. package/dist/config/types.js +1 -0
  209. package/dist/drivers/acp/client.js +1 -1
  210. package/dist/drivers/acp/driver.js +13 -8
  211. package/dist/drivers/agents.js +4 -3
  212. package/dist/drivers/base.js +3 -2
  213. package/dist/drivers/host-runners.js +2 -1
  214. package/dist/drivers/native/claude-stream.js +12 -11
  215. package/dist/drivers/native/codex-app-server.js +17 -12
  216. package/dist/drivers/native/oneshot.js +8 -7
  217. package/dist/drivers/pool.js +1 -1
  218. package/dist/drivers/runner.d.ts +3 -1
  219. package/dist/drivers/runner.js +68 -20
  220. package/dist/drivers/turn.js +1 -1
  221. package/dist/hooks/config.js +3 -2
  222. package/dist/hooks/protocol.js +18 -12
  223. package/dist/host/api-impl.js +11 -10
  224. package/dist/host/loader.js +9 -8
  225. package/dist/host/types.d.ts +3 -0
  226. package/dist/i18n/catalog.d.ts +2209 -0
  227. package/dist/i18n/catalog.js +72 -0
  228. package/dist/i18n/format.d.ts +21 -0
  229. package/dist/i18n/format.js +58 -0
  230. package/dist/i18n/index.d.ts +58 -0
  231. package/dist/i18n/index.js +72 -0
  232. package/dist/i18n/messages/agents.d.ts +84 -0
  233. package/dist/i18n/messages/agents.js +85 -0
  234. package/dist/i18n/messages/approval.d.ts +99 -0
  235. package/dist/i18n/messages/approval.js +100 -0
  236. package/dist/i18n/messages/auth.d.ts +189 -0
  237. package/dist/i18n/messages/auth.js +201 -0
  238. package/dist/i18n/messages/cli-args.d.ts +46 -0
  239. package/dist/i18n/messages/cli-args.js +46 -0
  240. package/dist/i18n/messages/cli-help.d.ts +12 -0
  241. package/dist/i18n/messages/cli-help.js +248 -0
  242. package/dist/i18n/messages/cli.d.ts +336 -0
  243. package/dist/i18n/messages/cli.js +311 -0
  244. package/dist/i18n/messages/config-keys.d.ts +293 -0
  245. package/dist/i18n/messages/config-keys.js +296 -0
  246. package/dist/i18n/messages/config.d.ts +508 -0
  247. package/dist/i18n/messages/config.js +241 -0
  248. package/dist/i18n/messages/drivers.d.ts +123 -0
  249. package/dist/i18n/messages/drivers.js +124 -0
  250. package/dist/i18n/messages/errors.d.ts +83 -0
  251. package/dist/i18n/messages/errors.js +171 -0
  252. package/dist/i18n/messages/interactive-line.d.ts +61 -0
  253. package/dist/i18n/messages/interactive-line.js +69 -0
  254. package/dist/i18n/messages/interactive-startup.d.ts +99 -0
  255. package/dist/i18n/messages/interactive-startup.js +100 -0
  256. package/dist/i18n/messages/interactive-view.d.ts +140 -0
  257. package/dist/i18n/messages/interactive-view.js +141 -0
  258. package/dist/i18n/messages/interactive.d.ts +489 -0
  259. package/dist/i18n/messages/interactive.js +248 -0
  260. package/dist/i18n/messages/memory.d.ts +123 -0
  261. package/dist/i18n/messages/memory.js +128 -0
  262. package/dist/i18n/messages/panels.d.ts +233 -0
  263. package/dist/i18n/messages/panels.js +232 -0
  264. package/dist/i18n/messages/permissions.d.ts +126 -0
  265. package/dist/i18n/messages/permissions.js +151 -0
  266. package/dist/i18n/messages/plan.d.ts +123 -0
  267. package/dist/i18n/messages/plan.js +124 -0
  268. package/dist/i18n/messages/print.d.ts +86 -0
  269. package/dist/i18n/messages/print.js +91 -0
  270. package/dist/i18n/messages/report.d.ts +391 -0
  271. package/dist/i18n/messages/report.js +490 -0
  272. package/dist/i18n/messages/rewind.d.ts +198 -0
  273. package/dist/i18n/messages/rewind.js +217 -0
  274. package/dist/i18n/messages/session.d.ts +230 -0
  275. package/dist/i18n/messages/session.js +258 -0
  276. package/dist/i18n/messages/settings.d.ts +355 -0
  277. package/dist/i18n/messages/settings.js +343 -0
  278. package/dist/i18n/messages/subcommands-config.d.ts +113 -0
  279. package/dist/i18n/messages/subcommands-config.js +129 -0
  280. package/dist/i18n/messages/subcommands-models.d.ts +34 -0
  281. package/dist/i18n/messages/subcommands-models.js +34 -0
  282. package/dist/i18n/messages/subcommands.d.ts +576 -0
  283. package/dist/i18n/messages/subcommands.js +477 -0
  284. package/dist/i18n/messages/trace.d.ts +243 -0
  285. package/dist/i18n/messages/trace.js +238 -0
  286. package/dist/i18n/types.d.ts +15 -0
  287. package/dist/i18n/types.js +7 -0
  288. package/dist/index.d.ts +6 -0
  289. package/dist/index.js +2 -0
  290. package/dist/memory/edit.d.ts +24 -0
  291. package/dist/memory/edit.js +63 -0
  292. package/dist/memory/frontmatter.d.ts +37 -0
  293. package/dist/memory/frontmatter.js +79 -0
  294. package/dist/memory/index.d.ts +28 -0
  295. package/dist/memory/index.js +126 -0
  296. package/dist/memory/lock.d.ts +17 -0
  297. package/dist/memory/lock.js +62 -0
  298. package/dist/memory/paths.d.ts +57 -0
  299. package/dist/memory/paths.js +175 -0
  300. package/dist/memory/report.d.ts +36 -0
  301. package/dist/memory/report.js +86 -0
  302. package/dist/memory/runtime.d.ts +42 -0
  303. package/dist/memory/runtime.js +36 -0
  304. package/dist/memory/secrets.d.ts +8 -0
  305. package/dist/memory/secrets.js +27 -0
  306. package/dist/memory/section.d.ts +28 -0
  307. package/dist/memory/section.js +59 -0
  308. package/dist/memory/store.d.ts +70 -0
  309. package/dist/memory/store.js +284 -0
  310. package/dist/memory/tool.d.ts +31 -0
  311. package/dist/memory/tool.js +94 -0
  312. package/dist/modes/acp/acp-events.js +2 -1
  313. package/dist/modes/acp/acp-server.js +13 -12
  314. package/dist/modes/commands-core.d.ts +11 -0
  315. package/dist/modes/commands-core.js +93 -62
  316. package/dist/modes/image-input.js +20 -6
  317. package/dist/modes/interactive/agent-bar.d.ts +95 -0
  318. package/dist/modes/interactive/agent-bar.js +248 -0
  319. package/dist/modes/interactive/agent-panels.js +27 -26
  320. package/dist/modes/interactive/agent-transcript.d.ts +47 -0
  321. package/dist/modes/interactive/agent-transcript.js +191 -0
  322. package/dist/modes/interactive/agent-ui.d.ts +36 -1
  323. package/dist/modes/interactive/agent-ui.js +180 -14
  324. package/dist/modes/interactive/agent-view.d.ts +72 -0
  325. package/dist/modes/interactive/agent-view.js +281 -0
  326. package/dist/modes/interactive/approval-dialog.js +46 -34
  327. package/dist/modes/interactive/clipboard-paste.d.ts +2 -2
  328. package/dist/modes/interactive/clipboard-paste.js +9 -4
  329. package/dist/modes/interactive/commands.d.ts +22 -1
  330. package/dist/modes/interactive/commands.js +100 -49
  331. package/dist/modes/interactive/completion.js +2 -1
  332. package/dist/modes/interactive/config-panel.d.ts +70 -0
  333. package/dist/modes/interactive/config-panel.js +319 -0
  334. package/dist/modes/interactive/config-ui.d.ts +96 -0
  335. package/dist/modes/interactive/config-ui.js +397 -0
  336. package/dist/modes/interactive/confirm-dialog.js +6 -7
  337. package/dist/modes/interactive/event-notices.js +11 -9
  338. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  339. package/dist/modes/interactive/interactive-mode.js +21 -22
  340. package/dist/modes/interactive/key-dispatch.d.ts +12 -0
  341. package/dist/modes/interactive/key-dispatch.js +24 -9
  342. package/dist/modes/interactive/line/line-editor.js +2 -1
  343. package/dist/modes/interactive/line/line-mode.js +18 -7
  344. package/dist/modes/interactive/line/line-render.js +25 -24
  345. package/dist/modes/interactive/memory-panel.d.ts +64 -0
  346. package/dist/modes/interactive/memory-panel.js +221 -0
  347. package/dist/modes/interactive/message-view.d.ts +4 -2
  348. package/dist/modes/interactive/message-view.js +42 -33
  349. package/dist/modes/interactive/model-items.d.ts +45 -0
  350. package/dist/modes/interactive/model-items.js +134 -0
  351. package/dist/modes/interactive/model-picker.d.ts +57 -0
  352. package/dist/modes/interactive/model-picker.js +191 -0
  353. package/dist/modes/interactive/panels.js +39 -31
  354. package/dist/modes/interactive/pickers.d.ts +2 -1
  355. package/dist/modes/interactive/pickers.js +10 -6
  356. package/dist/modes/interactive/plan-command.d.ts +1 -1
  357. package/dist/modes/interactive/plan-command.js +24 -27
  358. package/dist/modes/interactive/plan-dialog.js +18 -17
  359. package/dist/modes/interactive/plan-flow.js +6 -5
  360. package/dist/modes/interactive/rewind-command.d.ts +1 -1
  361. package/dist/modes/interactive/rewind-command.js +18 -16
  362. package/dist/modes/interactive/rewind-flow.d.ts +0 -1
  363. package/dist/modes/interactive/rewind-flow.js +13 -14
  364. package/dist/modes/interactive/rewind-list.js +7 -6
  365. package/dist/modes/interactive/rewind-panel.js +40 -40
  366. package/dist/modes/interactive/rewind-text.d.ts +5 -3
  367. package/dist/modes/interactive/rewind-text.js +48 -38
  368. package/dist/modes/interactive/run-indicator.js +15 -12
  369. package/dist/modes/interactive/session-events.js +3 -2
  370. package/dist/modes/interactive/startup-header.js +22 -23
  371. package/dist/modes/interactive/startup-ui.d.ts +3 -9
  372. package/dist/modes/interactive/startup-ui.js +44 -88
  373. package/dist/modes/interactive/status-area.d.ts +2 -0
  374. package/dist/modes/interactive/status-area.js +8 -2
  375. package/dist/modes/interactive/status-bar.js +4 -3
  376. package/dist/modes/interactive/subagent-view.js +9 -7
  377. package/dist/modes/interactive/tasks-report.d.ts +6 -0
  378. package/dist/modes/interactive/tasks-report.js +28 -31
  379. package/dist/modes/interactive/terminal-setup.d.ts +9 -0
  380. package/dist/modes/interactive/terminal-setup.js +23 -0
  381. package/dist/modes/interactive/tool-summary.js +19 -17
  382. package/dist/modes/interactive/tool-view.js +7 -4
  383. package/dist/modes/interactive/trace-view.d.ts +89 -0
  384. package/dist/modes/interactive/trace-view.js +332 -0
  385. package/dist/modes/print/print-mode.js +14 -15
  386. package/dist/modes/rpc/commands.js +7 -3
  387. package/dist/modes/rpc/rpc-mode.js +9 -3
  388. package/dist/modes/session-report.d.ts +2 -0
  389. package/dist/modes/session-report.js +101 -105
  390. package/dist/modes/startup-ui-text.js +11 -6
  391. package/dist/permissions/bypass.d.ts +8 -10
  392. package/dist/permissions/bypass.js +19 -10
  393. package/dist/permissions/memory-class.d.ts +23 -0
  394. package/dist/permissions/memory-class.js +54 -0
  395. package/dist/permissions/modes.d.ts +3 -3
  396. package/dist/permissions/modes.js +21 -16
  397. package/dist/permissions/pipeline.d.ts +1 -1
  398. package/dist/permissions/pipeline.js +9 -2
  399. package/dist/permissions/preview.js +49 -42
  400. package/dist/permissions/rules.js +5 -2
  401. package/dist/permissions/types.d.ts +4 -0
  402. package/dist/plan/store.js +2 -1
  403. package/dist/rpc.d.ts +39 -1
  404. package/dist/rpc.js +3 -0
  405. package/dist/sandbox/bash.js +11 -8
  406. package/dist/sandbox/detect.js +14 -11
  407. package/dist/sdk.d.ts +17 -1
  408. package/dist/sdk.js +29 -7
  409. package/dist/session/export.js +31 -30
  410. package/dist/session/manager.d.ts +1 -1
  411. package/dist/session/manager.js +5 -3
  412. package/dist/session/reuse.js +5 -4
  413. package/dist/session/scan.js +3 -2
  414. package/dist/session/stats-aggregate.d.ts +3 -1
  415. package/dist/session/stats-aggregate.js +5 -1
  416. package/dist/session/stats-index.js +2 -1
  417. package/dist/session/stats-scan.d.ts +4 -1
  418. package/dist/session/stats-scan.js +6 -2
  419. package/dist/session/store.d.ts +11 -0
  420. package/dist/session/store.js +48 -1
  421. package/dist/session/types.d.ts +2 -0
  422. package/dist/skills/builtin.js +2 -1
  423. package/dist/tools/image-file.d.ts +26 -1
  424. package/dist/tools/image-file.js +55 -13
  425. package/dist/tools/presets.d.ts +14 -1
  426. package/dist/tools/presets.js +3 -3
  427. package/dist/tools/registry.js +1 -1
  428. package/dist/tools/truncate.d.ts +1 -1
  429. package/dist/tools/truncate.js +2 -2
  430. package/dist/tools/types.d.ts +17 -1
  431. package/dist/trace/build-index.d.ts +91 -0
  432. package/dist/trace/build-index.js +127 -0
  433. package/dist/trace/build-nodes.d.ts +24 -0
  434. package/dist/trace/build-nodes.js +279 -0
  435. package/dist/trace/build-util.d.ts +43 -0
  436. package/dist/trace/build-util.js +120 -0
  437. package/dist/trace/build.d.ts +82 -0
  438. package/dist/trace/build.js +382 -0
  439. package/dist/trace/detail.d.ts +35 -0
  440. package/dist/trace/detail.js +205 -0
  441. package/dist/trace/flatten.d.ts +69 -0
  442. package/dist/trace/flatten.js +173 -0
  443. package/dist/trace/format.d.ts +47 -0
  444. package/dist/trace/format.js +329 -0
  445. package/dist/trace/html-template.d.ts +19 -0
  446. package/dist/trace/html-template.js +150 -0
  447. package/dist/trace/html.d.ts +104 -0
  448. package/dist/trace/html.js +292 -0
  449. package/dist/trace/preview.d.ts +29 -0
  450. package/dist/trace/preview.js +59 -0
  451. package/dist/trace/query-session.d.ts +14 -0
  452. package/dist/trace/query-session.js +38 -0
  453. package/dist/trace/query.d.ts +55 -0
  454. package/dist/trace/query.js +188 -0
  455. package/dist/trace/session.d.ts +40 -0
  456. package/dist/trace/session.js +168 -0
  457. package/dist/trace/types.d.ts +243 -0
  458. package/dist/trace/types.js +13 -0
  459. package/dist/tui/components/editor-paste.d.ts +2 -0
  460. package/dist/tui/components/editor-paste.js +6 -3
  461. package/dist/tui/components/editor.js +2 -2
  462. package/dist/tui/components/loader.d.ts +3 -0
  463. package/dist/tui/components/loader.js +14 -0
  464. package/dist/tui/components/select-list.d.ts +2 -0
  465. package/dist/tui/components/select-list.js +7 -0
  466. package/dist/tui/components/settings-list.d.ts +61 -0
  467. package/dist/tui/components/settings-list.js +135 -0
  468. package/dist/tui/keybindings.d.ts +5 -0
  469. package/dist/tui/keybindings.js +17 -5
  470. package/dist/tui.d.ts +1 -0
  471. package/dist/tui.js +2 -0
  472. package/docs/en/host-api.md +167 -0
  473. package/docs/en/permissions.md +214 -0
  474. package/docs/en/providers.md +627 -0
  475. package/docs/en/rpc.md +361 -0
  476. package/docs/en/sessions.md +219 -0
  477. package/docs/en/tui.md +534 -0
  478. package/docs/host-api.md +18 -17
  479. package/docs/memory.md +172 -0
  480. package/docs/permissions.md +2 -2
  481. package/docs/providers.md +73 -1
  482. package/docs/rpc.md +31 -3
  483. package/docs/session-format.md +8 -2
  484. package/docs/sessions.md +29 -1
  485. package/docs/tui.md +140 -4
  486. package/package.json +8 -3
@@ -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));
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `/trace` 覆盖层(docs/wave6-plan.md §2.4)。[W6-T1]
3
+ *
4
+ * - `/trace`(当前会话)、`/trace t2`(以任务 t2 为根:ama 子会话的子轨迹,或外部 Agent 骨架)。
5
+ * - 主屏约束下的覆盖层:`anchor: "bottom"`、高度 `rows − 1`(同 rewind 面板);退出撤掉覆盖层,消息区不变。
6
+ * - 布局:标题汇总一行 + 列表窗口 + 按键提示一行;只格式化可见窗口里的行(10k 节点也只算可见行)。
7
+ * - 键:↑↓ / PgUp PgDn / Home End 移动;→ 展开(子 Agent 展开即懒加载子轨迹)或进第一个子行;← 折叠或回父行;
8
+ * Enter 详情卡片(再按或 Esc 返回);「更早的 N 个回合」行上 Enter / ↑ 加载前一页;f 跟随开关(进行中自动开,
9
+ * 手动上移暂停,End 恢复);Esc 先关详情再关视图。
10
+ * - 刷新:会话事件(`entry_appended` / `telemetry_tick` / 工具起止 / 请求起止)触发,节流 ≤ 2 Hz;每次整棵
11
+ * 重建(构建器是 O(条目) 的纯函数,10k 节点实测见 trace-view.test.ts),展开状态与光标按行 key 保留。
12
+ */
13
+ import type { AgentSession } from "../../agent/types.js";
14
+ import { type Component, type Focusable, type Keybindings, type OverlayHandle, type Theme } from "../../tui.js";
15
+ import { type TraceRow } from "../../trace/flatten.js";
16
+ import { LiveTracker, type ChildLoader } from "../../trace/session.js";
17
+ import type { NoticeLevel } from "./message-view.js";
18
+ /** 尾部优先:首屏与每次向前翻页的回合数。 */
19
+ export declare const TRACE_PAGE_TURNS = 50;
20
+ /** 刷新节流(≤ 2 Hz)。 */
21
+ export declare const TRACE_REFRESH_MS = 500;
22
+ export interface TraceViewHost {
23
+ theme: Theme;
24
+ keybindings?: Keybindings;
25
+ showOverlay(component: Component, options: {
26
+ anchor: "bottom";
27
+ }): OverlayHandle;
28
+ rows(): number;
29
+ session(): AgentSession;
30
+ now(): number;
31
+ notice(level: NoticeLevel, text: string): void;
32
+ /** 请求重画(异步刷新后)。 */
33
+ render?(): void;
34
+ /** 子会话读取(测试注入);缺省只读读文件、按 mtime 缓存。 */
35
+ loadChild?: ChildLoader;
36
+ /** 刷新节流(测试用 0)。 */
37
+ refreshMs?: number;
38
+ }
39
+ export declare class TraceView implements Component, Focusable {
40
+ private readonly host;
41
+ private readonly taskId;
42
+ private readonly close;
43
+ focused: boolean;
44
+ private trace;
45
+ private root;
46
+ private rows;
47
+ private lookup;
48
+ private readonly expanded;
49
+ /** 已展开过的 ama 子 Agent(重建后重新挂子轨迹)。 */
50
+ private readonly loaded;
51
+ private fromTurn;
52
+ private cursor;
53
+ private top;
54
+ private follow;
55
+ private detail;
56
+ readonly live: LiveTracker;
57
+ private readonly loadChild;
58
+ constructor(host: TraceViewHost, taskId: string | undefined, close: () => void);
59
+ /** 任务存在(`/trace <id>`)或看主会话。 */
60
+ get found(): boolean;
61
+ private rowsKeyOfRoot;
62
+ /** 重建轨迹(会话条目 + live 叠加 + 已展开的子轨迹)。 */
63
+ rebuild(): void;
64
+ /** 重新摊平,光标按 key 保持;跟随时贴底。 */
65
+ private reflow;
66
+ /** 会话有变化:重建并重排。 */
67
+ refresh(): void;
68
+ /** 当前行数(测试用)。 */
69
+ get rowCount(): number;
70
+ get cursorIndex(): number;
71
+ get selected(): TraceRow | undefined;
72
+ get following(): boolean;
73
+ get detailOpen(): boolean;
74
+ private bodyHeight;
75
+ private move;
76
+ private loadEarlier;
77
+ private expand;
78
+ private collapse;
79
+ handleInput(data: string): void;
80
+ private detailInput;
81
+ private ctx;
82
+ private headerLine;
83
+ render(width: number): string[];
84
+ invalidate(): void;
85
+ }
86
+ /**
87
+ * 打开 `/trace` 覆盖层;关闭时 resolve。任务不存在时提示一行、不打开。
88
+ */
89
+ export declare function openTraceView(host: TraceViewHost, taskId?: string): Promise<void>;
@@ -0,0 +1,332 @@
1
+ /**
2
+ * `/trace` 覆盖层(docs/wave6-plan.md §2.4)。[W6-T1]
3
+ *
4
+ * - `/trace`(当前会话)、`/trace t2`(以任务 t2 为根:ama 子会话的子轨迹,或外部 Agent 骨架)。
5
+ * - 主屏约束下的覆盖层:`anchor: "bottom"`、高度 `rows − 1`(同 rewind 面板);退出撤掉覆盖层,消息区不变。
6
+ * - 布局:标题汇总一行 + 列表窗口 + 按键提示一行;只格式化可见窗口里的行(10k 节点也只算可见行)。
7
+ * - 键:↑↓ / PgUp PgDn / Home End 移动;→ 展开(子 Agent 展开即懒加载子轨迹)或进第一个子行;← 折叠或回父行;
8
+ * Enter 详情卡片(再按或 Esc 返回);「更早的 N 个回合」行上 Enter / ↑ 加载前一页;f 跟随开关(进行中自动开,
9
+ * 手动上移暂停,End 恢复);Esc 先关详情再关视图。
10
+ * - 刷新:会话事件(`entry_appended` / `telemetry_tick` / 工具起止 / 请求起止)触发,节流 ≤ 2 Hz;每次整棵
11
+ * 重建(构建器是 O(条目) 的纯函数,10k 节点实测见 trace-view.test.ts),展开状态与光标按行 key 保留。
12
+ */
13
+ import { msg } from "../../i18n/index.js";
14
+ import { defaultKeybindings, matchesKey, padToWidth, truncateToWidth, visibleWidth, } from "../../tui.js";
15
+ import { buildTrace, findSubagent, loadSubagentTrace } from "../../trace/build.js";
16
+ import { describeNode, detailLines, entryLookup, } from "../../trace/detail.js";
17
+ import { flattenNode, flattenTrace, needsChild, rowIndex, tailStart, } from "../../trace/flatten.js";
18
+ import { formatRow, rowLabel, summaryText } from "../../trace/format.js";
19
+ import { childLoader, LiveTracker, traceInputOf } from "../../trace/session.js";
20
+ /** 尾部优先:首屏与每次向前翻页的回合数。 */
21
+ export const TRACE_PAGE_TURNS = 50;
22
+ /** 刷新节流(≤ 2 Hz)。 */
23
+ export const TRACE_REFRESH_MS = 500;
24
+ export class TraceView {
25
+ host;
26
+ taskId;
27
+ close;
28
+ focused = false;
29
+ trace;
30
+ root;
31
+ rows = [];
32
+ lookup;
33
+ expanded = new Map();
34
+ /** 已展开过的 ama 子 Agent(重建后重新挂子轨迹)。 */
35
+ loaded = new Set();
36
+ fromTurn = 0;
37
+ cursor = 0;
38
+ top = 0;
39
+ follow = false;
40
+ detail;
41
+ live;
42
+ loadChild;
43
+ constructor(host, taskId, close) {
44
+ this.host = host;
45
+ this.taskId = taskId;
46
+ this.close = close;
47
+ this.live = new LiveTracker(host.session, host.now);
48
+ this.loadChild = host.loadChild ?? childLoader();
49
+ this.rebuild();
50
+ this.follow = this.trace.partial;
51
+ if (taskId === undefined)
52
+ this.fromTurn = tailStart(this.trace, TRACE_PAGE_TURNS);
53
+ if (this.root !== undefined)
54
+ this.expanded.set(this.rowsKeyOfRoot(), true);
55
+ this.reflow();
56
+ this.cursor = Math.max(0, this.rows.length - 1);
57
+ }
58
+ /** 任务存在(`/trace <id>`)或看主会话。 */
59
+ get found() {
60
+ return this.taskId === undefined || this.root !== undefined;
61
+ }
62
+ rowsKeyOfRoot() {
63
+ return `a:${this.taskId}`;
64
+ }
65
+ /** 重建轨迹(会话条目 + live 叠加 + 已展开的子轨迹)。 */
66
+ rebuild() {
67
+ const session = this.host.session();
68
+ const input = traceInputOf(session);
69
+ this.trace = buildTrace(input, { live: this.live.overlay() });
70
+ for (const taskId of this.loaded) {
71
+ const node = findSubagent(this.trace, taskId);
72
+ if (node !== undefined)
73
+ loadSubagentTrace(node, this.loadChild);
74
+ }
75
+ if (this.taskId !== undefined) {
76
+ this.root = findSubagent(this.trace, this.taskId);
77
+ if (this.root !== undefined)
78
+ loadSubagentTrace(this.root, this.loadChild);
79
+ }
80
+ const children = this.loadChild.inputs().flatMap((i) => i.entries);
81
+ this.lookup = entryLookup([...input.entries, ...children], session.state.cwd);
82
+ }
83
+ /** 重新摊平,光标按 key 保持;跟随时贴底。 */
84
+ reflow() {
85
+ const key = this.rows[this.cursor]?.key;
86
+ const opts = { expanded: this.expanded, fromTurn: this.fromTurn };
87
+ this.rows =
88
+ this.root !== undefined ? flattenNode(this.root, opts) : flattenTrace(this.trace, opts);
89
+ const at = key === undefined ? -1 : rowIndex(this.rows, key);
90
+ this.cursor = this.follow
91
+ ? Math.max(0, this.rows.length - 1)
92
+ : at >= 0
93
+ ? at
94
+ : Math.min(this.cursor, Math.max(0, this.rows.length - 1));
95
+ if (this.detail !== undefined) {
96
+ const fresh = this.rows[rowIndex(this.rows, this.detail.row.key)];
97
+ if (fresh !== undefined)
98
+ this.detail.row = fresh;
99
+ }
100
+ }
101
+ /** 会话有变化:重建并重排。 */
102
+ refresh() {
103
+ this.rebuild();
104
+ this.reflow();
105
+ }
106
+ /** 当前行数(测试用)。 */
107
+ get rowCount() {
108
+ return this.rows.length;
109
+ }
110
+ get cursorIndex() {
111
+ return this.cursor;
112
+ }
113
+ get selected() {
114
+ return this.rows[this.cursor];
115
+ }
116
+ get following() {
117
+ return this.follow;
118
+ }
119
+ get detailOpen() {
120
+ return this.detail !== undefined;
121
+ }
122
+ bodyHeight() {
123
+ return Math.max(1, this.host.rows() - 1 - 2);
124
+ }
125
+ move(delta) {
126
+ if (this.rows.length === 0)
127
+ return;
128
+ if (delta < 0)
129
+ this.follow = false;
130
+ // 第一行是「更早的回合」时继续上移 = 加载前一页
131
+ if (delta < 0 && this.cursor === 0 && this.rows[0]?.node.kind === "more")
132
+ return this.loadEarlier();
133
+ this.cursor = Math.max(0, Math.min(this.rows.length - 1, this.cursor + delta));
134
+ if (delta > 0 && this.cursor === this.rows.length - 1 && this.trace.partial)
135
+ this.follow = true;
136
+ }
137
+ loadEarlier() {
138
+ const key = this.rows[1]?.key;
139
+ this.fromTurn = Math.max(0, this.fromTurn - TRACE_PAGE_TURNS);
140
+ this.reflow();
141
+ const at = key === undefined ? -1 : rowIndex(this.rows, key);
142
+ this.cursor = Math.max(0, at - 1);
143
+ }
144
+ expand() {
145
+ const row = this.selected;
146
+ if (row === undefined)
147
+ return;
148
+ if (!row.expandable)
149
+ return;
150
+ if (!row.expanded) {
151
+ if (needsChild(row.node)) {
152
+ this.loaded.add(row.node.taskId);
153
+ loadSubagentTrace(row.node, this.loadChild);
154
+ this.rebuild();
155
+ }
156
+ this.expanded.set(row.key, true);
157
+ this.reflow();
158
+ return;
159
+ }
160
+ if (this.rows[this.cursor + 1]?.depth === row.depth + 1)
161
+ this.cursor++;
162
+ }
163
+ collapse() {
164
+ const row = this.selected;
165
+ if (row === undefined)
166
+ return;
167
+ this.follow = false;
168
+ if (row.expanded) {
169
+ this.expanded.set(row.key, false);
170
+ this.reflow();
171
+ return;
172
+ }
173
+ const slash = row.key.lastIndexOf("/");
174
+ if (slash < 0)
175
+ return;
176
+ const parent = rowIndex(this.rows, row.key.slice(0, slash));
177
+ if (parent >= 0)
178
+ this.cursor = parent;
179
+ }
180
+ handleInput(data) {
181
+ const keys = this.host.keybindings ?? defaultKeybindings;
182
+ if (this.detail !== undefined)
183
+ return this.detailInput(data, keys);
184
+ const page = this.bodyHeight();
185
+ if (keys.matches(data, "tui.select.up"))
186
+ this.move(-1);
187
+ else if (keys.matches(data, "tui.select.down"))
188
+ this.move(1);
189
+ else if (keys.matches(data, "tui.select.pageUp"))
190
+ this.move(-page);
191
+ else if (keys.matches(data, "tui.select.pageDown"))
192
+ this.move(page);
193
+ else if (matchesKey(data, "home")) {
194
+ this.follow = false;
195
+ this.cursor = 0;
196
+ }
197
+ else if (matchesKey(data, "end")) {
198
+ this.cursor = Math.max(0, this.rows.length - 1);
199
+ this.follow = this.trace.partial;
200
+ }
201
+ else if (matchesKey(data, "right"))
202
+ this.expand();
203
+ else if (matchesKey(data, "left"))
204
+ this.collapse();
205
+ else if (matchesKey(data, "enter")) {
206
+ const row = this.selected;
207
+ if (row?.node.kind === "more")
208
+ this.loadEarlier();
209
+ else if (row !== undefined && row.node.kind !== "aux_group")
210
+ this.detail = { row, scroll: 0 };
211
+ }
212
+ else if (data === "f") {
213
+ this.follow = !this.follow;
214
+ if (this.follow)
215
+ this.cursor = Math.max(0, this.rows.length - 1);
216
+ }
217
+ else if (matchesKey(data, "escape") || keys.matches(data, "tui.select.cancel"))
218
+ this.close();
219
+ }
220
+ detailInput(data, keys) {
221
+ const detail = this.detail;
222
+ const page = this.bodyHeight();
223
+ if (keys.matches(data, "tui.select.up"))
224
+ detail.scroll = Math.max(0, detail.scroll - 1);
225
+ else if (keys.matches(data, "tui.select.down"))
226
+ detail.scroll++;
227
+ else if (keys.matches(data, "tui.select.pageUp"))
228
+ detail.scroll = Math.max(0, detail.scroll - page);
229
+ else if (keys.matches(data, "tui.select.pageDown"))
230
+ detail.scroll += page;
231
+ else if (matchesKey(data, "escape") || matchesKey(data, "enter") || matchesKey(data, "left"))
232
+ this.detail = undefined;
233
+ }
234
+ ctx() {
235
+ return {
236
+ theme: this.host.theme,
237
+ describe: (n) => describeNode(n, this.lookup),
238
+ };
239
+ }
240
+ headerLine(width) {
241
+ const theme = this.host.theme;
242
+ const m = msg().trace;
243
+ const root = this.root;
244
+ const title = root !== undefined ? m.taskTitle(root.taskId, root.agent) : m.title;
245
+ const source = root !== undefined ? root.child : this.trace;
246
+ const summary = source !== undefined ? ` · ${summaryText(source, theme)}` : "";
247
+ const state = this.trace.partial ? (this.follow ? m.follow.on : m.follow.off) : "";
248
+ const right = state === "" ? "" : ` ${theme.fg(this.follow ? "accent" : "muted", state)}`;
249
+ const left = truncateToWidth(`${theme.bold(title)}${theme.fg("muted", summary)}`, Math.max(1, width - visibleWidth(right)), theme.glyphs.ellipsis);
250
+ return padToWidth(`${left}${right}`, width);
251
+ }
252
+ render(width) {
253
+ const theme = this.host.theme;
254
+ const height = this.bodyHeight();
255
+ const lines = [this.headerLine(width)];
256
+ if (this.detail !== undefined) {
257
+ const { row } = this.detail;
258
+ const body = [
259
+ theme.bold(rowLabel(row, this.ctx())),
260
+ ...detailLines(row.node, this.lookup, Math.max(8, width - 2), theme, this.trace.startedAt),
261
+ ].map((l) => ` ${l}`);
262
+ const max = Math.max(0, body.length - height);
263
+ this.detail.scroll = Math.min(this.detail.scroll, max);
264
+ for (const line of body.slice(this.detail.scroll, this.detail.scroll + height))
265
+ lines.push(padToWidth(truncateToWidth(line, width, theme.glyphs.ellipsis), width));
266
+ }
267
+ else if (this.rows.length === 0)
268
+ lines.push(padToWidth(theme.dim(` ${msg().trace.empty}`), width));
269
+ else {
270
+ // 窗口:光标始终可见;跟随时贴底
271
+ if (this.cursor < this.top)
272
+ this.top = this.cursor;
273
+ if (this.cursor >= this.top + height)
274
+ this.top = this.cursor - height + 1;
275
+ this.top = Math.max(0, Math.min(this.top, Math.max(0, this.rows.length - height)));
276
+ const ctx = this.ctx();
277
+ for (let i = this.top; i < Math.min(this.rows.length, this.top + height); i++)
278
+ lines.push(formatRow(this.rows[i], width, ctx, i === this.cursor));
279
+ }
280
+ while (lines.length < height + 1)
281
+ lines.push(" ".repeat(width));
282
+ const hints = msg().trace.hints;
283
+ const hint = this.detail !== undefined ? hints.detail : width < 60 ? hints.listNarrow : hints.list;
284
+ lines.push(padToWidth(truncateToWidth(theme.dim(hint), width, theme.glyphs.ellipsis), width));
285
+ return lines;
286
+ }
287
+ invalidate() { }
288
+ }
289
+ /**
290
+ * 打开 `/trace` 覆盖层;关闭时 resolve。任务不存在时提示一行、不打开。
291
+ */
292
+ export function openTraceView(host, taskId) {
293
+ return new Promise((resolve) => {
294
+ let handle;
295
+ let timer;
296
+ let unsubscribe;
297
+ let last = 0;
298
+ const finish = () => {
299
+ if (timer !== undefined)
300
+ clearTimeout(timer);
301
+ unsubscribe?.();
302
+ handle?.hide();
303
+ host.render?.();
304
+ resolve();
305
+ };
306
+ const view = new TraceView(host, taskId, finish);
307
+ if (!view.found) {
308
+ host.notice("warn", msg().trace.taskNotFound(taskId));
309
+ resolve();
310
+ return;
311
+ }
312
+ const throttle = host.refreshMs ?? TRACE_REFRESH_MS;
313
+ const flush = () => {
314
+ timer = undefined;
315
+ last = host.now();
316
+ view.refresh();
317
+ host.render?.();
318
+ };
319
+ unsubscribe = host.session().subscribe((event) => {
320
+ if (!view.live.onEvent(event) || timer !== undefined)
321
+ return;
322
+ const wait = Math.max(0, throttle - (host.now() - last));
323
+ if (wait === 0)
324
+ flush();
325
+ else {
326
+ timer = setTimeout(flush, wait);
327
+ timer.unref?.();
328
+ }
329
+ });
330
+ handle = host.showOverlay(view, { anchor: "bottom" });
331
+ });
332
+ }