@armadra/agent 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (527) hide show
  1. package/CHANGELOG.md +257 -0
  2. package/README.md +263 -95
  3. package/THIRD_PARTY_NOTICES.md +34 -0
  4. package/dist/acp.d.ts +18 -0
  5. package/dist/acp.js +19 -0
  6. package/dist/agent/limits.d.ts +38 -0
  7. package/dist/agent/limits.js +127 -0
  8. package/dist/agent/loop-guard.d.ts +38 -0
  9. package/dist/agent/loop-guard.js +95 -0
  10. package/dist/agent/loop.d.ts +4 -0
  11. package/dist/agent/loop.js +7 -0
  12. package/dist/agent/prompt-rules.d.ts +12 -0
  13. package/dist/agent/prompt-rules.js +18 -0
  14. package/dist/agent/reminders.d.ts +59 -0
  15. package/dist/agent/reminders.js +327 -0
  16. package/dist/agent/retry.d.ts +1 -1
  17. package/dist/agent/retry.js +2 -1
  18. package/dist/agent/session-cache.d.ts +5 -0
  19. package/dist/agent/session-cache.js +18 -2
  20. package/dist/agent/session-classifier.d.ts +18 -0
  21. package/dist/agent/session-classifier.js +105 -0
  22. package/dist/agent/session-compaction.d.ts +35 -6
  23. package/dist/agent/session-compaction.js +157 -31
  24. package/dist/agent/session-core.d.ts +40 -1
  25. package/dist/agent/session-extensions.d.ts +61 -0
  26. package/dist/agent/session-extensions.js +129 -0
  27. package/dist/agent/session-images.d.ts +23 -0
  28. package/dist/agent/session-images.js +97 -0
  29. package/dist/agent/session-plan.d.ts +21 -0
  30. package/dist/agent/session-plan.js +524 -0
  31. package/dist/agent/session-rewind.d.ts +81 -0
  32. package/dist/agent/session-rewind.js +354 -0
  33. package/dist/agent/session-run.d.ts +28 -1
  34. package/dist/agent/session-run.js +157 -6
  35. package/dist/agent/session-settings.d.ts +49 -0
  36. package/dist/agent/session-settings.js +95 -0
  37. package/dist/agent/session-subagent.d.ts +36 -24
  38. package/dist/agent/session-subagent.js +259 -129
  39. package/dist/agent/session-sync.d.ts +10 -3
  40. package/dist/agent/session-sync.js +37 -8
  41. package/dist/agent/session-telemetry.d.ts +39 -0
  42. package/dist/agent/session-telemetry.js +231 -0
  43. package/dist/agent/session-tools.js +63 -3
  44. package/dist/agent/session.d.ts +33 -29
  45. package/dist/agent/session.js +91 -126
  46. package/dist/agent/subagent-registry.d.ts +91 -0
  47. package/dist/agent/subagent-registry.js +494 -0
  48. package/dist/agent/system-prompt.d.ts +6 -3
  49. package/dist/agent/system-prompt.js +7 -2
  50. package/dist/agent/tool-runner.d.ts +8 -1
  51. package/dist/agent/tool-runner.js +72 -6
  52. package/dist/agent/types-w5.d.ts +192 -0
  53. package/dist/agent/types-w5.js +10 -0
  54. package/dist/agent/types.d.ts +55 -4
  55. package/dist/agent/types.js +2 -0
  56. package/dist/agent/worktree.d.ts +36 -0
  57. package/dist/agent/worktree.js +86 -0
  58. package/dist/agents/builtin.d.ts +14 -0
  59. package/dist/agents/builtin.js +39 -0
  60. package/dist/agents/catalog.d.ts +43 -0
  61. package/dist/agents/catalog.js +82 -0
  62. package/dist/agents/discover.d.ts +35 -0
  63. package/dist/agents/discover.js +83 -0
  64. package/dist/agents/external.d.ts +82 -0
  65. package/dist/agents/external.js +326 -0
  66. package/dist/agents/parse.d.ts +18 -0
  67. package/dist/agents/parse.js +116 -0
  68. package/dist/agents/result.d.ts +32 -0
  69. package/dist/agents/result.js +67 -0
  70. package/dist/agents/task-control.d.ts +17 -0
  71. package/dist/agents/task-control.js +17 -0
  72. package/dist/agents/task-record.d.ts +78 -0
  73. package/dist/agents/task-record.js +141 -0
  74. package/dist/agents/types.d.ts +46 -0
  75. package/dist/agents/types.js +8 -0
  76. package/dist/ai/apis/anthropic-compat.d.ts +36 -0
  77. package/dist/ai/apis/anthropic-compat.js +92 -0
  78. package/dist/ai/apis/anthropic-messages.js +3 -2
  79. package/dist/ai/apis/anthropic-request.d.ts +7 -6
  80. package/dist/ai/apis/anthropic-request.js +10 -28
  81. package/dist/ai/apis/cache-params.d.ts +11 -2
  82. package/dist/ai/apis/cache-params.js +25 -6
  83. package/dist/ai/apis/google-generative-ai.js +3 -2
  84. package/dist/ai/apis/openai-compat.d.ts +4 -1
  85. package/dist/ai/apis/openai-compat.js +8 -1
  86. package/dist/ai/apis/openai-completions.js +3 -2
  87. package/dist/ai/apis/openai-responses.js +3 -2
  88. package/dist/ai/http.d.ts +28 -6
  89. package/dist/ai/http.js +41 -8
  90. package/dist/ai/image-limits.d.ts +45 -0
  91. package/dist/ai/image-limits.js +68 -0
  92. package/dist/ai/providers/builtin.d.ts +18 -6
  93. package/dist/ai/providers/builtin.js +135 -6
  94. package/dist/ai/providers/catalog-data.js +17 -13
  95. package/dist/ai/providers/catalog.d.ts +60 -7
  96. package/dist/ai/providers/catalog.js +197 -38
  97. package/dist/ai/providers/channels.d.ts +33 -3
  98. package/dist/ai/providers/channels.js +108 -7
  99. package/dist/ai/providers/enrich.d.ts +6 -3
  100. package/dist/ai/providers/enrich.js +19 -4
  101. package/dist/ai/providers/models-dev-cache.d.ts +28 -24
  102. package/dist/ai/providers/models-dev-cache.js +92 -78
  103. package/dist/ai/providers/models-dev-data.d.ts +7 -0
  104. package/dist/ai/providers/models-dev-data.js +32 -0
  105. package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
  106. package/dist/ai/providers/models-dev-snapshot.js +137 -0
  107. package/dist/ai/providers/models-dev.d.ts +51 -10
  108. package/dist/ai/providers/models-dev.js +132 -39
  109. package/dist/ai/providers/registry.d.ts +28 -11
  110. package/dist/ai/providers/registry.js +112 -65
  111. package/dist/ai/providers/suggest.d.ts +18 -0
  112. package/dist/ai/providers/suggest.js +72 -0
  113. package/dist/ai/sse.d.ts +6 -2
  114. package/dist/ai/sse.js +22 -2
  115. package/dist/ai/types.d.ts +37 -4
  116. package/dist/ai/types.js +5 -0
  117. package/dist/bundle/ama.cjs +41979 -21147
  118. package/dist/checkpoints/backend.d.ts +61 -0
  119. package/dist/checkpoints/backend.js +135 -0
  120. package/dist/checkpoints/blobs.d.ts +60 -0
  121. package/dist/checkpoints/blobs.js +203 -0
  122. package/dist/checkpoints/gc.d.ts +47 -0
  123. package/dist/checkpoints/gc.js +144 -0
  124. package/dist/checkpoints/git-head.d.ts +15 -0
  125. package/dist/checkpoints/git-head.js +89 -0
  126. package/dist/checkpoints/index.d.ts +17 -0
  127. package/dist/checkpoints/index.js +17 -0
  128. package/dist/checkpoints/replay.d.ts +48 -0
  129. package/dist/checkpoints/replay.js +154 -0
  130. package/dist/checkpoints/restore.d.ts +86 -0
  131. package/dist/checkpoints/restore.js +263 -0
  132. package/dist/checkpoints/settings.d.ts +14 -0
  133. package/dist/checkpoints/settings.js +23 -0
  134. package/dist/checkpoints/shadow-git.d.ts +108 -0
  135. package/dist/checkpoints/shadow-git.js +491 -0
  136. package/dist/checkpoints/shadow-restore.d.ts +25 -0
  137. package/dist/checkpoints/shadow-restore.js +128 -0
  138. package/dist/checkpoints/tracker.d.ts +64 -0
  139. package/dist/checkpoints/tracker.js +192 -0
  140. package/dist/checkpoints/types.d.ts +99 -0
  141. package/dist/checkpoints/types.js +12 -0
  142. package/dist/cli/args.d.ts +26 -7
  143. package/dist/cli/args.js +75 -82
  144. package/dist/cli/bootstrap.js +40 -4
  145. package/dist/cli/codemode-notice.d.ts +21 -0
  146. package/dist/cli/codemode-notice.js +56 -0
  147. package/dist/cli/compose-agents.d.ts +27 -0
  148. package/dist/cli/compose-agents.js +111 -0
  149. package/dist/cli/compose-extensions.d.ts +29 -0
  150. package/dist/cli/compose-extensions.js +44 -0
  151. package/dist/cli/compose-session.d.ts +8 -0
  152. package/dist/cli/compose-session.js +76 -2
  153. package/dist/cli/compose-store.d.ts +1 -1
  154. package/dist/cli/compose-store.js +3 -1
  155. package/dist/cli/compose.d.ts +17 -4
  156. package/dist/cli/compose.js +60 -14
  157. package/dist/cli/default-model.d.ts +38 -1
  158. package/dist/cli/default-model.js +96 -9
  159. package/dist/cli/deps.d.ts +42 -0
  160. package/dist/cli/exit-codes.d.ts +12 -0
  161. package/dist/cli/exit-codes.js +15 -0
  162. package/dist/cli/fake-visibility.d.ts +13 -0
  163. package/dist/cli/fake-visibility.js +26 -0
  164. package/dist/cli/from-prompt.d.ts +18 -0
  165. package/dist/cli/from-prompt.js +49 -0
  166. package/dist/cli/help-text.d.ts +4 -0
  167. package/dist/cli/help-text.js +102 -0
  168. package/dist/cli/main.d.ts +9 -2
  169. package/dist/cli/main.js +77 -3
  170. package/dist/cli/proxy.d.ts +51 -0
  171. package/dist/cli/proxy.js +135 -0
  172. package/dist/cli/startup-screen.d.ts +29 -0
  173. package/dist/cli/startup-screen.js +51 -2
  174. package/dist/cli/startup-steps.d.ts +1 -1
  175. package/dist/cli/startup-steps.js +21 -13
  176. package/dist/cli/subcommands/config.d.ts +22 -3
  177. package/dist/cli/subcommands/config.js +119 -21
  178. package/dist/cli/subcommands/context.js +4 -1
  179. package/dist/cli/subcommands/doctor.js +33 -1
  180. package/dist/cli/subcommands/init.js +2 -1
  181. package/dist/cli/subcommands/models-discover.d.ts +15 -9
  182. package/dist/cli/subcommands/models-discover.js +58 -52
  183. package/dist/cli/subcommands/models.d.ts +2 -0
  184. package/dist/cli/subcommands/models.js +33 -14
  185. package/dist/cli/subcommands/probe-runner.d.ts +96 -0
  186. package/dist/cli/subcommands/probe-runner.js +264 -0
  187. package/dist/cli/subcommands/providers-probe.d.ts +34 -0
  188. package/dist/cli/subcommands/providers-probe.js +87 -0
  189. package/dist/cli/subcommands/providers.d.ts +3 -2
  190. package/dist/cli/subcommands/providers.js +53 -51
  191. package/dist/cli/subcommands/sessions-export.d.ts +10 -0
  192. package/dist/cli/subcommands/sessions-export.js +59 -0
  193. package/dist/cli/subcommands/sessions-search.d.ts +13 -0
  194. package/dist/cli/subcommands/sessions-search.js +103 -0
  195. package/dist/cli/subcommands/sessions.d.ts +6 -3
  196. package/dist/cli/subcommands/sessions.js +58 -3
  197. package/dist/cli/subcommands/stats.d.ts +17 -0
  198. package/dist/cli/subcommands/stats.js +198 -0
  199. package/dist/cli/system-prompt-arg.d.ts +11 -0
  200. package/dist/cli/system-prompt-arg.js +34 -0
  201. package/dist/codemode/capability.d.ts +24 -7
  202. package/dist/codemode/capability.js +38 -10
  203. package/dist/codemode/host-side.d.ts +14 -0
  204. package/dist/codemode/host-side.js +24 -1
  205. package/dist/codemode/modes.d.ts +4 -11
  206. package/dist/codemode/modes.js +5 -27
  207. package/dist/codemode/tool.d.ts +18 -14
  208. package/dist/codemode/tool.js +76 -31
  209. package/dist/compaction/breaker.d.ts +25 -9
  210. package/dist/compaction/breaker.js +47 -17
  211. package/dist/compaction/estimate.d.ts +11 -3
  212. package/dist/compaction/estimate.js +64 -22
  213. package/dist/compaction/image-budget.d.ts +45 -0
  214. package/dist/compaction/image-budget.js +115 -0
  215. package/dist/compaction/post-compact.d.ts +38 -0
  216. package/dist/compaction/post-compact.js +152 -0
  217. package/dist/compaction/protect.d.ts +27 -0
  218. package/dist/compaction/protect.js +56 -0
  219. package/dist/compaction/prune-tier.d.ts +58 -12
  220. package/dist/compaction/prune-tier.js +120 -54
  221. package/dist/compaction/summarize-tier.d.ts +23 -4
  222. package/dist/compaction/summarize-tier.js +100 -29
  223. package/dist/config/checker.d.ts +28 -0
  224. package/dist/config/checker.js +97 -0
  225. package/dist/config/init.d.ts +6 -2
  226. package/dist/config/init.js +12 -5
  227. package/dist/config/json-schema.d.ts +1 -0
  228. package/dist/config/json-schema.js +98 -4
  229. package/dist/config/key-docs.d.ts +22 -0
  230. package/dist/config/key-docs.js +174 -0
  231. package/dist/config/merge.d.ts +12 -9
  232. package/dist/config/merge.js +102 -13
  233. package/dist/config/profile.d.ts +2 -0
  234. package/dist/config/profile.js +2 -0
  235. package/dist/config/schema-w5.d.ts +18 -0
  236. package/dist/config/schema-w5.js +109 -0
  237. package/dist/config/schema.d.ts +5 -9
  238. package/dist/config/schema.js +91 -118
  239. package/dist/config/types-w5.d.ts +118 -0
  240. package/dist/config/types-w5.js +20 -0
  241. package/dist/config/types.d.ts +84 -7
  242. package/dist/config/types.js +29 -1
  243. package/dist/drivers/acp/client.d.ts +57 -0
  244. package/dist/drivers/acp/client.js +160 -0
  245. package/dist/drivers/acp/driver.d.ts +31 -0
  246. package/dist/drivers/acp/driver.js +274 -0
  247. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  248. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  249. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  250. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  251. package/dist/drivers/acp/types.d.ts +285 -0
  252. package/dist/drivers/acp/types.js +36 -0
  253. package/dist/drivers/agents.d.ts +58 -0
  254. package/dist/drivers/agents.js +142 -0
  255. package/dist/drivers/base.d.ts +35 -0
  256. package/dist/drivers/base.js +59 -0
  257. package/dist/drivers/catalog.d.ts +46 -0
  258. package/dist/drivers/catalog.js +167 -0
  259. package/dist/drivers/env.d.ts +20 -0
  260. package/dist/drivers/env.js +46 -0
  261. package/dist/drivers/host-runners.d.ts +18 -0
  262. package/dist/drivers/host-runners.js +45 -0
  263. package/dist/drivers/jsonrpc.d.ts +58 -0
  264. package/dist/drivers/jsonrpc.js +180 -0
  265. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  266. package/dist/drivers/native/claude-normalize.js +106 -0
  267. package/dist/drivers/native/claude-stream.d.ts +29 -0
  268. package/dist/drivers/native/claude-stream.js +456 -0
  269. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  270. package/dist/drivers/native/codex-app-server.js +407 -0
  271. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  272. package/dist/drivers/native/codex-normalize.js +124 -0
  273. package/dist/drivers/native/oneshot.d.ts +28 -0
  274. package/dist/drivers/native/oneshot.js +312 -0
  275. package/dist/drivers/permissions.d.ts +40 -0
  276. package/dist/drivers/permissions.js +92 -0
  277. package/dist/drivers/pids.d.ts +32 -0
  278. package/dist/drivers/pids.js +93 -0
  279. package/dist/drivers/pool.d.ts +28 -0
  280. package/dist/drivers/pool.js +96 -0
  281. package/dist/drivers/probe.d.ts +47 -0
  282. package/dist/drivers/probe.js +172 -0
  283. package/dist/drivers/process.d.ts +48 -0
  284. package/dist/drivers/process.js +100 -0
  285. package/dist/drivers/runner.d.ts +61 -0
  286. package/dist/drivers/runner.js +388 -0
  287. package/dist/drivers/store.d.ts +49 -0
  288. package/dist/drivers/store.js +91 -0
  289. package/dist/drivers/turn.d.ts +41 -0
  290. package/dist/drivers/turn.js +99 -0
  291. package/dist/drivers/types.d.ts +122 -0
  292. package/dist/drivers/types.js +11 -0
  293. package/dist/git/info.d.ts +75 -0
  294. package/dist/git/info.js +191 -0
  295. package/dist/hooks/protocol.js +6 -1
  296. package/dist/hooks/types.d.ts +10 -1
  297. package/dist/hooks/types.js +2 -0
  298. package/dist/host/api-impl.d.ts +7 -0
  299. package/dist/host/api-impl.js +15 -0
  300. package/dist/host/types.d.ts +24 -2
  301. package/dist/host/types.js +4 -0
  302. package/dist/index.d.ts +3 -0
  303. package/dist/index.js +1 -0
  304. package/dist/modes/acp/acp-events.d.ts +46 -0
  305. package/dist/modes/acp/acp-events.js +233 -0
  306. package/dist/modes/acp/acp-mode.d.ts +17 -0
  307. package/dist/modes/acp/acp-mode.js +47 -0
  308. package/dist/modes/acp/acp-server.d.ts +79 -0
  309. package/dist/modes/acp/acp-server.js +315 -0
  310. package/dist/modes/commands-core.d.ts +7 -1
  311. package/dist/modes/commands-core.js +61 -5
  312. package/dist/modes/image-input.d.ts +12 -4
  313. package/dist/modes/image-input.js +22 -5
  314. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  315. package/dist/modes/interactive/agent-panels.js +103 -0
  316. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  317. package/dist/modes/interactive/agent-ui.js +234 -0
  318. package/dist/modes/interactive/approval-dialog.d.ts +40 -7
  319. package/dist/modes/interactive/approval-dialog.js +192 -35
  320. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  321. package/dist/modes/interactive/approval-merge.js +89 -0
  322. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  323. package/dist/modes/interactive/clipboard-paste.js +28 -0
  324. package/dist/modes/interactive/commands.d.ts +20 -3
  325. package/dist/modes/interactive/commands.js +75 -16
  326. package/dist/modes/interactive/double-esc.d.ts +20 -0
  327. package/dist/modes/interactive/double-esc.js +34 -0
  328. package/dist/modes/interactive/event-notices.d.ts +32 -0
  329. package/dist/modes/interactive/event-notices.js +79 -0
  330. package/dist/modes/interactive/external-editor.d.ts +16 -0
  331. package/dist/modes/interactive/external-editor.js +39 -0
  332. package/dist/modes/interactive/interactive-mode.d.ts +16 -2
  333. package/dist/modes/interactive/interactive-mode.js +184 -202
  334. package/dist/modes/interactive/key-dispatch.d.ts +18 -2
  335. package/dist/modes/interactive/key-dispatch.js +53 -6
  336. package/dist/modes/interactive/line/line-mode.d.ts +3 -1
  337. package/dist/modes/interactive/line/line-mode.js +28 -9
  338. package/dist/modes/interactive/line/line-render.d.ts +6 -1
  339. package/dist/modes/interactive/line/line-render.js +66 -8
  340. package/dist/modes/interactive/message-view.d.ts +49 -10
  341. package/dist/modes/interactive/message-view.js +262 -46
  342. package/dist/modes/interactive/panels.d.ts +35 -0
  343. package/dist/modes/interactive/panels.js +157 -0
  344. package/dist/modes/interactive/pickers.d.ts +23 -2
  345. package/dist/modes/interactive/pickers.js +48 -15
  346. package/dist/modes/interactive/plan-command.d.ts +40 -0
  347. package/dist/modes/interactive/plan-command.js +129 -0
  348. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  349. package/dist/modes/interactive/plan-dialog.js +290 -0
  350. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  351. package/dist/modes/interactive/plan-flow.js +98 -0
  352. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  353. package/dist/modes/interactive/rewind-command.js +106 -0
  354. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  355. package/dist/modes/interactive/rewind-flow.js +151 -0
  356. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  357. package/dist/modes/interactive/rewind-list.js +123 -0
  358. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  359. package/dist/modes/interactive/rewind-panel.js +309 -0
  360. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  361. package/dist/modes/interactive/rewind-text.js +139 -0
  362. package/dist/modes/interactive/run-indicator.d.ts +51 -0
  363. package/dist/modes/interactive/run-indicator.js +189 -0
  364. package/dist/modes/interactive/session-events.d.ts +24 -0
  365. package/dist/modes/interactive/session-events.js +96 -0
  366. package/dist/modes/interactive/startup-header.d.ts +40 -0
  367. package/dist/modes/interactive/startup-header.js +169 -0
  368. package/dist/modes/interactive/status-area.d.ts +73 -0
  369. package/dist/modes/interactive/status-area.js +190 -0
  370. package/dist/modes/interactive/status-bar.d.ts +107 -16
  371. package/dist/modes/interactive/status-bar.js +306 -81
  372. package/dist/modes/interactive/status-line.d.ts +33 -0
  373. package/dist/modes/interactive/status-line.js +113 -0
  374. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  375. package/dist/modes/interactive/subagent-view.js +154 -0
  376. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  377. package/dist/modes/interactive/tasks-report.js +114 -0
  378. package/dist/modes/interactive/tool-summary.d.ts +46 -0
  379. package/dist/modes/interactive/tool-summary.js +218 -0
  380. package/dist/modes/interactive/tool-view.d.ts +58 -15
  381. package/dist/modes/interactive/tool-view.js +233 -145
  382. package/dist/modes/print/print-mode.d.ts +40 -4
  383. package/dist/modes/print/print-mode.js +161 -8
  384. package/dist/modes/rpc/commands.d.ts +9 -0
  385. package/dist/modes/rpc/commands.js +49 -0
  386. package/dist/modes/rpc/rpc-mode.js +7 -1
  387. package/dist/modes/session-report.d.ts +11 -0
  388. package/dist/modes/session-report.js +48 -1
  389. package/dist/permissions/auto-safe.d.ts +65 -0
  390. package/dist/permissions/auto-safe.js +547 -0
  391. package/dist/permissions/classifier.d.ts +68 -0
  392. package/dist/permissions/classifier.js +186 -0
  393. package/dist/permissions/dangerous.d.ts +5 -0
  394. package/dist/permissions/dangerous.js +1 -1
  395. package/dist/permissions/modes.d.ts +30 -0
  396. package/dist/permissions/modes.js +78 -0
  397. package/dist/permissions/pipeline.d.ts +72 -6
  398. package/dist/permissions/pipeline.js +306 -11
  399. package/dist/permissions/protected.d.ts +19 -0
  400. package/dist/permissions/protected.js +74 -0
  401. package/dist/permissions/readonly-bash.d.ts +30 -0
  402. package/dist/permissions/readonly-bash.js +118 -0
  403. package/dist/permissions/rules.js +3 -0
  404. package/dist/permissions/types.d.ts +92 -3
  405. package/dist/permissions/types.js +3 -0
  406. package/dist/plan/compose.d.ts +9 -0
  407. package/dist/plan/compose.js +19 -0
  408. package/dist/plan/controller.d.ts +71 -0
  409. package/dist/plan/controller.js +27 -0
  410. package/dist/plan/done-markers.d.ts +17 -0
  411. package/dist/plan/done-markers.js +51 -0
  412. package/dist/plan/extract.d.ts +29 -0
  413. package/dist/plan/extract.js +160 -0
  414. package/dist/plan/prompts.d.ts +36 -0
  415. package/dist/plan/prompts.js +89 -0
  416. package/dist/plan/store.d.ts +37 -0
  417. package/dist/plan/store.js +90 -0
  418. package/dist/rpc.d.ts +58 -2
  419. package/dist/rpc.js +7 -0
  420. package/dist/sandbox/bash.d.ts +74 -0
  421. package/dist/sandbox/bash.js +126 -0
  422. package/dist/sandbox/detect.d.ts +48 -0
  423. package/dist/sandbox/detect.js +149 -0
  424. package/dist/sandbox/index.d.ts +5 -0
  425. package/dist/sandbox/index.js +5 -0
  426. package/dist/sandbox/profile.d.ts +33 -0
  427. package/dist/sandbox/profile.js +76 -0
  428. package/dist/sandbox/wrap.d.ts +29 -0
  429. package/dist/sandbox/wrap.js +117 -0
  430. package/dist/sdk.d.ts +42 -5
  431. package/dist/sdk.js +34 -4
  432. package/dist/session/export.d.ts +32 -0
  433. package/dist/session/export.js +187 -0
  434. package/dist/session/redact.d.ts +15 -0
  435. package/dist/session/redact.js +55 -0
  436. package/dist/session/reuse.d.ts +33 -0
  437. package/dist/session/reuse.js +86 -0
  438. package/dist/session/scan.d.ts +34 -0
  439. package/dist/session/scan.js +140 -0
  440. package/dist/session/search.d.ts +52 -0
  441. package/dist/session/search.js +211 -0
  442. package/dist/session/stats-aggregate.d.ts +63 -0
  443. package/dist/session/stats-aggregate.js +163 -0
  444. package/dist/session/stats-index.d.ts +26 -0
  445. package/dist/session/stats-index.js +91 -0
  446. package/dist/session/stats-scan.d.ts +54 -0
  447. package/dist/session/stats-scan.js +236 -0
  448. package/dist/session/types.d.ts +3 -1
  449. package/dist/session/types.js +1 -0
  450. package/dist/skills/builtin.d.ts +31 -0
  451. package/dist/skills/builtin.js +109 -0
  452. package/dist/skills/discover.d.ts +2 -1
  453. package/dist/skills/index-prompt.js +5 -8
  454. package/dist/tools/background-jobs.d.ts +71 -0
  455. package/dist/tools/background-jobs.js +198 -0
  456. package/dist/tools/bash.d.ts +53 -1
  457. package/dist/tools/bash.js +158 -7
  458. package/dist/tools/clipboard-image.d.ts +44 -0
  459. package/dist/tools/clipboard-image.js +148 -0
  460. package/dist/tools/edit.d.ts +2 -0
  461. package/dist/tools/edit.js +18 -3
  462. package/dist/tools/image-file.d.ts +38 -3
  463. package/dist/tools/image-file.js +81 -10
  464. package/dist/tools/image-resize.d.ts +58 -0
  465. package/dist/tools/image-resize.js +97 -0
  466. package/dist/tools/presets.d.ts +40 -8
  467. package/dist/tools/presets.js +65 -19
  468. package/dist/tools/read.d.ts +5 -2
  469. package/dist/tools/read.js +13 -10
  470. package/dist/tools/registry.d.ts +7 -1
  471. package/dist/tools/registry.js +27 -4
  472. package/dist/tools/task-ctl.d.ts +22 -0
  473. package/dist/tools/task-ctl.js +116 -0
  474. package/dist/tools/task.d.ts +22 -10
  475. package/dist/tools/task.js +66 -26
  476. package/dist/tools/todo.d.ts +22 -2
  477. package/dist/tools/todo.js +58 -14
  478. package/dist/tools/truncate.d.ts +15 -0
  479. package/dist/tools/truncate.js +25 -0
  480. package/dist/tools/types.d.ts +113 -0
  481. package/dist/tools/types.js +5 -0
  482. package/dist/tools/write.js +3 -0
  483. package/dist/tui/component.d.ts +8 -2
  484. package/dist/tui/component.js +3 -1
  485. package/dist/tui/components/box.d.ts +6 -1
  486. package/dist/tui/components/box.js +16 -6
  487. package/dist/tui/components/card.d.ts +23 -0
  488. package/dist/tui/components/card.js +37 -0
  489. package/dist/tui/components/editor-history.d.ts +6 -0
  490. package/dist/tui/components/editor-history.js +45 -0
  491. package/dist/tui/components/editor-paste.d.ts +1 -1
  492. package/dist/tui/components/editor-paste.js +4 -4
  493. package/dist/tui/components/editor.d.ts +11 -5
  494. package/dist/tui/components/editor.js +52 -58
  495. package/dist/tui/components/key-value.d.ts +3 -0
  496. package/dist/tui/components/key-value.js +16 -6
  497. package/dist/tui/components/loader.d.ts +37 -7
  498. package/dist/tui/components/loader.js +84 -21
  499. package/dist/tui/components/markdown.d.ts +5 -1
  500. package/dist/tui/components/markdown.js +45 -21
  501. package/dist/tui/components/meter.d.ts +3 -3
  502. package/dist/tui/components/meter.js +13 -11
  503. package/dist/tui/components/select-list.d.ts +23 -1
  504. package/dist/tui/components/select-list.js +76 -13
  505. package/dist/tui/glyphs.d.ts +72 -0
  506. package/dist/tui/glyphs.js +118 -0
  507. package/dist/tui/keybindings.d.ts +5 -0
  508. package/dist/tui/keybindings.js +5 -0
  509. package/dist/tui/theme.d.ts +30 -6
  510. package/dist/tui/theme.js +103 -17
  511. package/dist/tui.d.ts +4 -2
  512. package/dist/tui.js +3 -1
  513. package/docs/acp.md +78 -0
  514. package/docs/agents.md +250 -0
  515. package/docs/codemode.md +28 -10
  516. package/docs/hooks.md +36 -32
  517. package/docs/permissions.md +212 -0
  518. package/docs/plan.md +107 -0
  519. package/docs/providers.md +261 -62
  520. package/docs/rewind-plan.md +181 -0
  521. package/docs/rpc.md +127 -40
  522. package/docs/sandbox.md +215 -0
  523. package/docs/session-format.md +43 -22
  524. package/docs/sessions.md +174 -0
  525. package/docs/tui-design.md +751 -0
  526. package/docs/tui.md +260 -64
  527. package/package.json +15 -2
@@ -1,20 +1,29 @@
1
1
  /**
2
- * 工具调用显示(设计 §12.5)。[B7]
2
+ * 工具调用显示(设计 §12.5;终端界面视觉设计 v1 §3.5)。[B7]
3
3
  *
4
- * - 一行标题 `● bash git status`:圆点运行中为强调色,成功绿、失败红;摘要取最能代表这次调用的参数
5
- * (bash 命令、文件路径、搜索模式、task 描述……),路径相对会话 cwd。
6
- * - 折叠(缺省):结果前 3 行 + 剩余行数;`edit` 显示 `details.diff`(+/− 着色,前 12 行);
7
- * `bash` 运行中流式显示尾部 8 行;错误红色。`Ctrl+O` 展开全部(上限 400 行)。
8
- * - 嵌套:带 `parentToolCallId` 的调用(codemode 脚本里的 `tools.*`,B10)挂在外层调用下;折叠时只列
9
- * 内层调用的标题(最近 5 个),展开时完整显示。
4
+ * 三级层级,用缩进表达:
5
+ * ```
6
+ * ⏺ read src/tui/tui.ts:1+120 第 0 列:⏺(运行中 accent、成功 success、失败 error)+ 工具名 + 摘要
7
+ * ⎿ 读取 120 行 第 2 列:⎿ + 一行结果摘要(tool-summary.ts)
8
+ * 1 /** 第 4 列:输出正文
9
+ * … 另 117 行(Ctrl+O 展开)
10
+ * ```
11
+ * - 运行中摘要行 `⎿ ⠋ 运行中 · 4s`:spinner 与底部 Loader 同帧(ToolTracker.tick 由 Loader.onFrame 驱动),
12
+ * 标题行不变;bash 流式显示尾部 8 行(muted)。task 显示 `子 Agent · 运行中 1m05s`;有 `subagent_*`
13
+ * 事件时(W5-U,subagent-view.ts)改为 `explore · 运行中 1m05s · 3 轮 · 最近 3 个工具 · ↑↓`,后台任务
14
+ * 在结果摘要下多一行跟随状态。
15
+ * - 折叠(缺省):结果前 3 行;edit 显示 `details.diff`(`@@` dim、`+` success、`-` error、上下文 muted,
16
+ * 宽 ≥ 60 时带行号列),前 12 行;`Ctrl+O` 展开全部(上限 400 行,长行折行)。
17
+ * - 嵌套:带 `parentToolCallId` 的调用(codemode 脚本里的 `tools.*`)挂在外层调用下、右移 4 列;折叠时只列
18
+ * 最近 5 个内层调用的标题与摘要行,展开时完整显示。
10
19
  * - 工具输出先去掉 ANSI 与控制字符、Tab 换成空格,避免打乱布局。
11
- * - 自定义渲染(W3-B9a-2,`ToolDefinition.renderCall / renderResult`):`getTool` 能取到定义时,标题摘要
12
- * 优先取 `renderCall(input, width)` 的第一行(codemode 显示脚本首行);成功的结果优先用
13
- * `renderResult(result, width, expanded)`(去控制字符、按宽截断、上限 400 行);自定义渲染抛错或返回
14
- * 空时回到缺省显示;错误结果始终用缺省的红色显示。
20
+ * - 自定义渲染(`ToolDefinition.renderCall / renderResult`):标题摘要优先取 `renderCall` 第一行;成功的结果
21
+ * 正文优先用 `renderResult`;抛错或返回空时回到缺省显示;错误结果始终用缺省显示。
15
22
  */
16
23
  import type { ToolDefinition, ToolResult } from "../../tools/types.js";
17
24
  import { type Component, type Theme } from "../../tui.js";
25
+ import { type SubagentState } from "./subagent-view.js";
26
+ export { cleanLines, toolSummary } from "./tool-summary.js";
18
27
  export declare const COLLAPSED_RESULT_LINES = 3;
19
28
  export declare const COLLAPSED_DIFF_LINES = 12;
20
29
  export declare const BASH_TAIL_LINES = 8;
@@ -26,11 +35,13 @@ export interface ToolViewOptions {
26
35
  cwd?: string;
27
36
  /** 取工具定义(自定义渲染用);缺省或取不到时用内置摘要与结果显示。 */
28
37
  getTool?(name: string): ToolDefinition | undefined;
38
+ /** 计时(耗时与运行中秒数);缺省 Date.now。 */
39
+ now?(): number;
40
+ /** 运行中摘要行的 spinner 帧(与 Loader 同帧);缺省静态字形。 */
41
+ spinner?(): string;
42
+ /** [W5-U] task 调用对应的子 Agent 状态(折叠视图);缺省不显示。 */
43
+ subagent?(toolCallId: string): SubagentState | undefined;
29
44
  }
30
- /** 工具输出 → 可安全显示的行。 */
31
- export declare function cleanLines(text: string): string[];
32
- /** 标题行里的参数摘要。 */
33
- export declare function toolSummary(name: string, args: unknown, cwd?: string): string;
34
45
  export declare class ToolView implements Component {
35
46
  readonly toolCallId: string;
36
47
  readonly toolName: string;
@@ -43,9 +54,16 @@ export declare class ToolView implements Component {
43
54
  private readonly nested;
44
55
  private cache;
45
56
  private version;
57
+ private startedAt;
58
+ /** 审批对话框打开时还没开始执行(摘要行显示「等待确认」,关闭后重新计时)。 */
59
+ private awaiting;
60
+ private elapsedMs;
61
+ /** 重放的历史调用(没有真实耗时)。 */
62
+ replayed: boolean;
46
63
  /** 外层调用(嵌套时):子视图变化要让外层缓存失效。 */
47
64
  private parent;
48
65
  constructor(toolCallId: string, toolName: string, args: unknown, options: ToolViewOptions);
66
+ private now;
49
67
  get isRunning(): boolean;
50
68
  get isExpanded(): boolean;
51
69
  get children(): readonly ToolView[];
@@ -54,18 +72,37 @@ export declare class ToolView implements Component {
54
72
  update(partial: string): void;
55
73
  finish(result: ToolResult, isError: boolean): void;
56
74
  addNested(child: ToolView): void;
75
+ /** 审批打开 / 关闭:还没有输出的运行中调用显示「等待确认」,关闭后从此刻重新计时。 */
76
+ setAwaiting(awaiting: boolean): void;
77
+ /** spinner 换帧 / 秒数变化:运行中的视图重画摘要行(后台子 Agent 运行中也算)。 */
78
+ tick(): void;
79
+ /** 外部状态变了(子 Agent 事件):重画。 */
80
+ refresh(): void;
81
+ private subagentState;
57
82
  private touch;
58
83
  invalidate(): void;
59
84
  render(width: number): string[];
60
85
  header(width: number): string;
86
+ /** ` ⎿ 摘要`:运行中带 spinner 与秒数,完成后是结果摘要。 */
87
+ summaryLine(width: number): string | undefined;
88
+ /** 后台子 Agent:结果摘要下一行跟随状态 ` ↳ t2 explore · 完成 2m · 7 轮 …`。 */
89
+ private followLine;
61
90
  private custom;
62
91
  /** `renderCall` 的第一行(去控制字符、折叠空白);没有或为空时 undefined。 */
63
92
  private customCall;
64
93
  /** 成功结果的 `renderResult` 行;没有或为空时 undefined。 */
65
94
  private customResult;
95
+ /** 完成后的结果正文(已清洗):bash 取 `details.output`。 */
96
+ private resultLines;
66
97
  private indent;
67
98
  private more;
99
+ private nestedLines;
68
100
  private body;
101
+ /** read:行号右对齐(按最长行号,至少 3 位)dim,与正文隔两格。 */
102
+ private readLines;
103
+ /** grep:路径正文色,`:行号:` dim,命中片段 muted。 */
104
+ private grepLines;
105
+ private diffLines;
69
106
  }
70
107
  /** 按 toolCallId 管理视图与嵌套;`Ctrl+O` 的全局展开状态也在这里。 */
71
108
  export declare class ToolTracker {
@@ -75,6 +112,8 @@ export declare class ToolTracker {
75
112
  constructor(options: ToolViewOptions);
76
113
  get isExpanded(): boolean;
77
114
  get(toolCallId: string): ToolView | undefined;
115
+ /** 运行中的调用数(Loader 动词用)。 */
116
+ running(): ToolView[];
78
117
  /** 新调用;返回视图与它是否是顶层(顶层由调用方加进消息区)。 */
79
118
  start(event: {
80
119
  toolCallId: string;
@@ -87,6 +126,10 @@ export declare class ToolTracker {
87
126
  };
88
127
  update(toolCallId: string, partial: string): void;
89
128
  end(toolCallId: string, result: ToolResult, isError: boolean): void;
129
+ /** 审批对话框打开 / 关闭(见 ToolView.setAwaiting)。 */
130
+ setAwaiting(awaiting: boolean): void;
131
+ /** Loader 换帧:运行中的视图重画摘要行。 */
132
+ tick(): void;
90
133
  /** 已完成的调用(重放历史)。 */
91
134
  completed(toolCallId: string, toolName: string, args: unknown, result: ToolResult | undefined, isError: boolean): ToolView;
92
135
  /** Ctrl+O:切换全部调用的展开状态。 */
@@ -1,101 +1,39 @@
1
1
  /**
2
- * 工具调用显示(设计 §12.5)。[B7]
2
+ * 工具调用显示(设计 §12.5;终端界面视觉设计 v1 §3.5)。[B7]
3
3
  *
4
- * - 一行标题 `● bash git status`:圆点运行中为强调色,成功绿、失败红;摘要取最能代表这次调用的参数
5
- * (bash 命令、文件路径、搜索模式、task 描述……),路径相对会话 cwd。
6
- * - 折叠(缺省):结果前 3 行 + 剩余行数;`edit` 显示 `details.diff`(+/− 着色,前 12 行);
7
- * `bash` 运行中流式显示尾部 8 行;错误红色。`Ctrl+O` 展开全部(上限 400 行)。
8
- * - 嵌套:带 `parentToolCallId` 的调用(codemode 脚本里的 `tools.*`,B10)挂在外层调用下;折叠时只列
9
- * 内层调用的标题(最近 5 个),展开时完整显示。
4
+ * 三级层级,用缩进表达:
5
+ * ```
6
+ * ⏺ read src/tui/tui.ts:1+120 第 0 列:⏺(运行中 accent、成功 success、失败 error)+ 工具名 + 摘要
7
+ * ⎿ 读取 120 行 第 2 列:⎿ + 一行结果摘要(tool-summary.ts)
8
+ * 1 /** 第 4 列:输出正文
9
+ * … 另 117 行(Ctrl+O 展开)
10
+ * ```
11
+ * - 运行中摘要行 `⎿ ⠋ 运行中 · 4s`:spinner 与底部 Loader 同帧(ToolTracker.tick 由 Loader.onFrame 驱动),
12
+ * 标题行不变;bash 流式显示尾部 8 行(muted)。task 显示 `子 Agent · 运行中 1m05s`;有 `subagent_*`
13
+ * 事件时(W5-U,subagent-view.ts)改为 `explore · 运行中 1m05s · 3 轮 · 最近 3 个工具 · ↑↓`,后台任务
14
+ * 在结果摘要下多一行跟随状态。
15
+ * - 折叠(缺省):结果前 3 行;edit 显示 `details.diff`(`@@` dim、`+` success、`-` error、上下文 muted,
16
+ * 宽 ≥ 60 时带行号列),前 12 行;`Ctrl+O` 展开全部(上限 400 行,长行折行)。
17
+ * - 嵌套:带 `parentToolCallId` 的调用(codemode 脚本里的 `tools.*`)挂在外层调用下、右移 4 列;折叠时只列
18
+ * 最近 5 个内层调用的标题与摘要行,展开时完整显示。
10
19
  * - 工具输出先去掉 ANSI 与控制字符、Tab 换成空格,避免打乱布局。
11
- * - 自定义渲染(W3-B9a-2,`ToolDefinition.renderCall / renderResult`):`getTool` 能取到定义时,标题摘要
12
- * 优先取 `renderCall(input, width)` 的第一行(codemode 显示脚本首行);成功的结果优先用
13
- * `renderResult(result, width, expanded)`(去控制字符、按宽截断、上限 400 行);自定义渲染抛错或返回
14
- * 空时回到缺省显示;错误结果始终用缺省的红色显示。
20
+ * - 自定义渲染(`ToolDefinition.renderCall / renderResult`):标题摘要优先取 `renderCall` 第一行;成功的结果
21
+ * 正文优先用 `renderResult`;抛错或返回空时回到缺省显示;错误结果始终用缺省显示。
15
22
  */
16
- import { isAbsolute, relative } from "node:path";
17
- import { stripAnsi, truncateToWidth, wrapTextWithAnsi, } from "../../tui.js";
23
+ import { formatElapsed, truncateToWidth, wrapTextWithAnsi, } from "../../tui.js";
18
24
  import { contentText } from "./message-view.js";
25
+ import { subagentLine } from "./subagent-view.js";
26
+ import { bashOutput, cleanLines, diffOf, flat, parseDiff, resultSummary, toolSummary, } from "./tool-summary.js";
27
+ export { cleanLines, toolSummary } from "./tool-summary.js";
19
28
  export const COLLAPSED_RESULT_LINES = 3;
20
29
  export const COLLAPSED_DIFF_LINES = 12;
21
30
  export const BASH_TAIL_LINES = 8;
22
31
  export const EXPANDED_MAX_LINES = 400;
23
32
  export const COLLAPSED_CHILDREN = 5;
24
- /** 工具输出 → 可安全显示的行。 */
25
- export function cleanLines(text) {
26
- const clean = stripAnsi(text)
27
- .replace(/\r\n?/g, "\n")
28
- .replace(/\t/g, " ")
29
- .replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
30
- const lines = clean.split("\n");
31
- while (lines.length > 0 && lines[lines.length - 1].trim() === "")
32
- lines.pop();
33
- return lines;
34
- }
35
- function flat(text, max = 120) {
36
- const one = text.replace(/\s*\n\s*/g, " ⏎ ").trim();
37
- return one.length > max ? `${one.slice(0, max - 1)}…` : one;
38
- }
39
- function displayPath(path, cwd) {
40
- if (cwd === undefined || !isAbsolute(path))
41
- return path;
42
- const rel = relative(cwd, path);
43
- return rel === "" ? "." : rel.startsWith("..") || isAbsolute(rel) ? path : rel;
44
- }
45
- /** 标题行里的参数摘要。 */
46
- export function toolSummary(name, args, cwd) {
47
- if (typeof args !== "object" || args === null)
48
- return "";
49
- const a = args;
50
- const str = (key) => typeof a[key] === "string" && a[key] !== "" ? a[key] : undefined;
51
- const path = str("path") ?? str("file_path");
52
- switch (name) {
53
- case "bash":
54
- return flat(str("command") ?? "");
55
- case "read": {
56
- if (path === undefined)
57
- return "";
58
- const offset = typeof a["offset"] === "number" ? a["offset"] : undefined;
59
- const limit = typeof a["limit"] === "number" ? a["limit"] : undefined;
60
- const range = offset !== undefined || limit !== undefined
61
- ? `:${offset ?? 1}${limit !== undefined ? `+${limit}` : ""}`
62
- : "";
63
- return displayPath(path, cwd) + range;
64
- }
65
- case "grep":
66
- case "glob": {
67
- const pattern = str("pattern") ?? "";
68
- return path !== undefined ? `${flat(pattern)} in ${displayPath(path, cwd)}` : flat(pattern);
69
- }
70
- case "task":
71
- return flat(str("description") ?? str("prompt") ?? "");
72
- default:
73
- if (path !== undefined)
74
- return displayPath(path, cwd);
75
- for (const key of [
76
- "command",
77
- "pattern",
78
- "description",
79
- "query",
80
- "url",
81
- "name",
82
- "code",
83
- "script",
84
- ]) {
85
- const value = str(key);
86
- if (value !== undefined)
87
- return flat(value);
88
- }
89
- return "";
90
- }
91
- }
92
- function diffOf(result) {
93
- const details = result?.details;
94
- if (typeof details !== "object" || details === null)
95
- return undefined;
96
- const diff = details.diff;
97
- return typeof diff === "string" && diff !== "" ? diff : undefined;
98
- }
33
+ /** 正文缩进(第 4 列)。 */
34
+ const BODY = " ";
35
+ /** diff 行号列的最小显示宽度。 */
36
+ const DIFF_NUMBERS_MIN_WIDTH = 60;
99
37
  export class ToolView {
100
38
  toolCallId;
101
39
  toolName;
@@ -108,6 +46,12 @@ export class ToolView {
108
46
  nested = [];
109
47
  cache = null;
110
48
  version = 0;
49
+ startedAt;
50
+ /** 审批对话框打开时还没开始执行(摘要行显示「等待确认」,关闭后重新计时)。 */
51
+ awaiting = false;
52
+ elapsedMs = 0;
53
+ /** 重放的历史调用(没有真实耗时)。 */
54
+ replayed = false;
111
55
  /** 外层调用(嵌套时):子视图变化要让外层缓存失效。 */
112
56
  parent;
113
57
  constructor(toolCallId, toolName, args, options) {
@@ -115,6 +59,10 @@ export class ToolView {
115
59
  this.toolName = toolName;
116
60
  this.args = args;
117
61
  this.options = options;
62
+ this.startedAt = this.now();
63
+ }
64
+ now() {
65
+ return this.options.now?.() ?? Date.now();
118
66
  }
119
67
  get isRunning() {
120
68
  return this.state === "running";
@@ -141,6 +89,7 @@ export class ToolView {
141
89
  finish(result, isError) {
142
90
  this.result = result;
143
91
  this.state = isError || result.isError === true ? "error" : "done";
92
+ this.elapsedMs = this.now() - this.startedAt;
144
93
  this.touch();
145
94
  }
146
95
  addNested(child) {
@@ -149,6 +98,31 @@ export class ToolView {
149
98
  this.nested.push(child);
150
99
  this.touch();
151
100
  }
101
+ /** 审批打开 / 关闭:还没有输出的运行中调用显示「等待确认」,关闭后从此刻重新计时。 */
102
+ setAwaiting(awaiting) {
103
+ if (this.state !== "running")
104
+ return;
105
+ if (awaiting && this.partial !== "")
106
+ return;
107
+ if (!awaiting && this.awaiting)
108
+ this.startedAt = this.now();
109
+ if (this.awaiting === awaiting)
110
+ return;
111
+ this.awaiting = awaiting;
112
+ this.touch();
113
+ }
114
+ /** spinner 换帧 / 秒数变化:运行中的视图重画摘要行(后台子 Agent 运行中也算)。 */
115
+ tick() {
116
+ if (this.state === "running" || this.subagentState()?.status === "running")
117
+ this.touch();
118
+ }
119
+ /** 外部状态变了(子 Agent 事件):重画。 */
120
+ refresh() {
121
+ this.touch();
122
+ }
123
+ subagentState() {
124
+ return this.toolName === "task" ? this.options.subagent?.(this.toolCallId) : undefined;
125
+ }
152
126
  touch() {
153
127
  this.version++;
154
128
  this.parent?.touch();
@@ -162,20 +136,63 @@ export class ToolView {
162
136
  if (this.cache && this.cache.width === width && this.cache.version === this.version) {
163
137
  return this.cache.lines;
164
138
  }
165
- const lines = [this.header(width), ...this.body(width)];
139
+ const lines = [
140
+ this.header(width),
141
+ this.summaryLine(width),
142
+ this.followLine(width),
143
+ ...this.body(width),
144
+ ].filter((line) => line !== undefined);
166
145
  this.cache = { width, version: this.version, lines };
167
146
  return lines;
168
147
  }
169
148
  header(width) {
170
149
  const { theme } = this.options;
171
- const dot = this.state === "running"
172
- ? theme.fg("accent", "●")
173
- : this.state === "error"
174
- ? theme.fg("error", "●")
175
- : theme.fg("success", "●");
150
+ const color = this.state === "running" ? "accent" : this.state === "error" ? "error" : "success";
151
+ const dot = theme.fg(color, theme.glyphs.tool);
176
152
  const summary = this.customCall(width) ?? toolSummary(this.toolName, this.args, this.options.cwd);
177
153
  const title = `${dot} ${theme.bold(theme.fg("tool", this.toolName))}`;
178
- return truncateToWidth(summary === "" ? title : `${title} ${summary}`, width);
154
+ return truncateToWidth(summary === "" ? title : `${title} ${summary}`, width);
155
+ }
156
+ /** ` ⎿ 摘要`:运行中带 spinner 与秒数,完成后是结果摘要。 */
157
+ summaryLine(width) {
158
+ const { theme } = this.options;
159
+ const g = theme.glyphs;
160
+ const lead = " " + theme.fg("border", g.result) + " ";
161
+ if (this.state === "running" && this.awaiting) {
162
+ return truncateToWidth(lead + theme.fg("dim", `${g.spinnerStatic} 等待确认`), width);
163
+ }
164
+ const sub = this.subagentState();
165
+ if (this.state === "running" && sub !== undefined) {
166
+ const frame = this.options.spinner?.() ?? g.spinnerStatic;
167
+ const line = subagentLine(sub, theme, this.now());
168
+ return truncateToWidth(lead + theme.fg("accent", frame) + " " + line, width);
169
+ }
170
+ if (this.state === "running") {
171
+ const frame = this.options.spinner?.() ?? g.spinnerStatic;
172
+ const elapsed = formatElapsed(this.now() - this.startedAt);
173
+ const what = this.toolName === "task" ? `子 Agent · 运行中 ${elapsed}` : `运行中 · ${elapsed}`;
174
+ return truncateToWidth(lead + theme.fg("accent", frame) + " " + theme.fg("muted", what), width);
175
+ }
176
+ const result = this.result;
177
+ const text = resultSummary({
178
+ name: this.toolName,
179
+ args: this.args,
180
+ result,
181
+ isError: this.state === "error",
182
+ lines: this.resultLines(),
183
+ elapsedMs: this.replayed ? undefined : this.elapsedMs,
184
+ nestedCount: this.nested.length,
185
+ }, theme);
186
+ return truncateToWidth(lead + text, width);
187
+ }
188
+ /** 后台子 Agent:结果摘要下一行跟随状态 ` ↳ t2 explore · 完成 2m · 7 轮 …`。 */
189
+ followLine(width) {
190
+ const sub = this.subagentState();
191
+ if (this.state === "running" || sub === undefined || !sub.background)
192
+ return undefined;
193
+ const { theme } = this.options;
194
+ const head = theme.fg("dim", `${theme.glyphs.queued} ${sub.taskId} `);
195
+ return truncateToWidth(BODY + head + subagentLine(sub, theme, this.now()), width);
179
196
  }
180
197
  custom(render) {
181
198
  const tool = this.options.getTool?.(this.toolName);
@@ -201,93 +218,148 @@ export class ToolView {
201
218
  const result = this.result;
202
219
  if (result === undefined || this.state !== "done")
203
220
  return undefined;
204
- const inner = Math.max(1, width - 2);
221
+ const inner = Math.max(1, width - BODY.length);
205
222
  const rendered = this.custom((tool) => tool.renderResult?.(result, inner, this.expanded));
206
223
  if (!Array.isArray(rendered) || rendered.length === 0)
207
224
  return undefined;
208
225
  return rendered
209
226
  .slice(0, EXPANDED_MAX_LINES)
210
- .map((line) => " " + truncateToWidth(cleanLines(String(line)).join(" "), inner));
227
+ .map((line) => BODY + truncateToWidth(cleanLines(String(line)).join(" "), inner));
228
+ }
229
+ /** 完成后的结果正文(已清洗):bash 取 `details.output`。 */
230
+ resultLines() {
231
+ const result = this.result;
232
+ if (result === undefined)
233
+ return [];
234
+ if (this.toolName === "bash") {
235
+ const output = bashOutput(result);
236
+ if (output !== undefined)
237
+ return cleanLines(output);
238
+ }
239
+ return cleanLines(contentText(result.content));
211
240
  }
212
241
  indent(lines, width, color) {
213
242
  const { theme } = this.options;
214
- const inner = Math.max(1, width - 2);
243
+ const inner = Math.max(1, width - BODY.length);
215
244
  const out = [];
216
245
  for (const line of lines) {
217
246
  const pieces = this.expanded ? wrapTextWithAnsi(line, inner) : [truncateToWidth(line, inner)];
218
247
  for (const piece of pieces)
219
- out.push(" " + (color ? theme.fg(color, piece) : piece));
248
+ out.push(BODY + (color ? theme.fg(color, piece) : piece));
220
249
  }
221
250
  return out;
222
251
  }
223
252
  more(hidden) {
224
- return " " + this.options.theme.fg("dim", `… 另 ${hidden} 行(Ctrl+O 展开)`);
253
+ const { theme } = this.options;
254
+ return BODY + theme.fg("dim", `${theme.glyphs.ellipsis} 另 ${hidden} 行(Ctrl+O 展开)`);
225
255
  }
226
- body(width) {
256
+ nestedLines(width) {
227
257
  const { theme } = this.options;
258
+ if (this.nested.length === 0)
259
+ return [];
260
+ const inner = Math.max(1, width - BODY.length);
228
261
  const out = [];
229
- // 嵌套调用
230
- if (this.nested.length > 0) {
231
- if (this.expanded) {
232
- for (const child of this.nested) {
233
- for (const line of child.render(Math.max(1, width - 2)))
234
- out.push(" " + line);
235
- }
236
- }
237
- else {
238
- const shown = this.nested.slice(-COLLAPSED_CHILDREN);
239
- if (this.nested.length > shown.length) {
240
- out.push(" " + theme.fg("dim", `… 前 ${this.nested.length - shown.length} 个调用`));
241
- }
242
- for (const child of shown)
243
- out.push(" " + child.header(Math.max(1, width - 2)));
262
+ if (this.expanded) {
263
+ for (const child of this.nested) {
264
+ for (const line of child.render(inner))
265
+ out.push(BODY + line);
244
266
  }
267
+ return out;
268
+ }
269
+ const shown = this.nested.slice(-COLLAPSED_CHILDREN);
270
+ if (this.nested.length > shown.length) {
271
+ const hidden = this.nested.length - shown.length;
272
+ out.push(BODY + theme.fg("dim", `${theme.glyphs.ellipsis} 前 ${hidden} 个调用`));
245
273
  }
274
+ for (const child of shown) {
275
+ out.push(BODY + child.header(inner));
276
+ const summary = child.summaryLine(inner);
277
+ if (summary !== undefined)
278
+ out.push(BODY + summary);
279
+ }
280
+ return out;
281
+ }
282
+ body(width) {
283
+ const out = this.nestedLines(width);
246
284
  if (this.state === "running") {
247
285
  if (this.partial !== "") {
248
286
  const all = cleanLines(this.partial);
249
287
  const tail = this.expanded ? all.slice(-EXPANDED_MAX_LINES) : all.slice(-BASH_TAIL_LINES);
250
- out.push(...this.indent(tail, width, "dim"));
288
+ out.push(...this.indent(tail, width, "muted"));
251
289
  }
252
290
  return out;
253
291
  }
254
292
  const custom = this.customResult(width);
255
- if (custom !== undefined) {
256
- out.push(...custom);
257
- return out;
258
- }
293
+ if (custom !== undefined)
294
+ return [...out, ...custom];
259
295
  const diff = this.state === "done" ? diffOf(this.result) : undefined;
260
- if (diff !== undefined) {
261
- const all = cleanLines(diff).filter((l) => !l.startsWith("---") && !l.startsWith("+++"));
262
- const limit = this.expanded ? EXPANDED_MAX_LINES : COLLAPSED_DIFF_LINES;
263
- const shown = all.slice(0, limit);
264
- const inner = Math.max(1, width - 2);
265
- for (const line of shown) {
266
- const text = truncateToWidth(line, inner);
267
- const colored = line.startsWith("+")
268
- ? theme.fg("success", text)
269
- : line.startsWith("-")
270
- ? theme.fg("error", text)
271
- : line.startsWith("@@")
272
- ? theme.fg("accent", text)
273
- : theme.fg("dim", text);
274
- out.push(" " + colored);
275
- }
276
- if (all.length > shown.length)
277
- out.push(this.more(all.length - shown.length));
278
- return out;
279
- }
280
- const text = this.result === undefined ? "" : contentText(this.result.content);
281
- const all = cleanLines(text);
296
+ if (diff !== undefined)
297
+ return [...out, ...this.diffLines(parseDiff(diff), width)];
298
+ let all = this.resultLines();
299
+ // 非 bash 的失败:首行已在摘要里
300
+ if (this.state === "error" && this.toolName !== "bash")
301
+ all = all.slice(1);
282
302
  if (all.length === 0)
283
303
  return out;
284
304
  const limit = this.expanded ? EXPANDED_MAX_LINES : COLLAPSED_RESULT_LINES;
285
305
  const shown = all.slice(0, limit);
286
- out.push(...this.indent(shown, width, this.state === "error" ? "error" : "dim"));
306
+ if (this.state === "error")
307
+ out.push(...this.indent(shown, width, "error"));
308
+ else if (this.toolName === "read")
309
+ out.push(...this.readLines(shown, width));
310
+ else if (this.toolName === "grep")
311
+ out.push(...this.grepLines(shown, width));
312
+ else
313
+ out.push(...this.indent(shown, width, "muted"));
287
314
  if (all.length > shown.length)
288
315
  out.push(this.more(all.length - shown.length));
289
316
  return out;
290
317
  }
318
+ /** read:行号右对齐(按最长行号,至少 3 位)dim,与正文隔两格。 */
319
+ readLines(lines, width) {
320
+ const { theme } = this.options;
321
+ const parsed = lines.map((line) => /^\s*(\d+) {4}(.*)$/.exec(line));
322
+ const numWidth = Math.max(3, ...parsed.map((m) => (m ? m[1].length : 0)));
323
+ const styled = lines.map((line, i) => {
324
+ const m = parsed[i];
325
+ return m ? theme.fg("dim", m[1].padStart(numWidth)) + " " + m[2] : line;
326
+ });
327
+ return this.indent(styled, width);
328
+ }
329
+ /** grep:路径正文色,`:行号:` dim,命中片段 muted。 */
330
+ grepLines(lines, width) {
331
+ const { theme } = this.options;
332
+ const styled = lines.map((line) => {
333
+ const m = /^(.+?)(:\d+:)(.*)$/.exec(line);
334
+ return m
335
+ ? m[1] + theme.fg("dim", m[2]) + theme.fg("muted", m[3])
336
+ : theme.fg("muted", line);
337
+ });
338
+ return this.indent(styled, width);
339
+ }
340
+ diffLines(rows, width) {
341
+ const { theme } = this.options;
342
+ const limit = this.expanded ? EXPANDED_MAX_LINES : COLLAPSED_DIFF_LINES;
343
+ const shown = rows.slice(0, limit);
344
+ const numbers = width >= DIFF_NUMBERS_MIN_WIDTH;
345
+ const numWidth = Math.max(3, ...shown.map((r) => String(r.num ?? "").length));
346
+ const color = {
347
+ hunk: "dim",
348
+ add: "success",
349
+ del: "error",
350
+ ctx: "muted",
351
+ };
352
+ const styled = shown.map((row) => {
353
+ if (!numbers || row.kind === "hunk")
354
+ return theme.fg(color[row.kind], row.text);
355
+ const no = theme.fg("dim", String(row.num ?? "").padStart(numWidth));
356
+ return `${no} ${theme.fg(color[row.kind], row.text)}`;
357
+ });
358
+ const out = this.indent(styled, width);
359
+ if (rows.length > shown.length)
360
+ out.push(this.more(rows.length - shown.length));
361
+ return out;
362
+ }
291
363
  }
292
364
  /** 按 toolCallId 管理视图与嵌套;`Ctrl+O` 的全局展开状态也在这里。 */
293
365
  export class ToolTracker {
@@ -303,10 +375,15 @@ export class ToolTracker {
303
375
  get(toolCallId) {
304
376
  return this.views.get(toolCallId);
305
377
  }
378
+ /** 运行中的调用数(Loader 动词用)。 */
379
+ running() {
380
+ return [...this.views.values()].filter((view) => view.isRunning);
381
+ }
306
382
  /** 新调用;返回视图与它是否是顶层(顶层由调用方加进消息区)。 */
307
383
  start(event) {
308
384
  const existing = this.views.get(event.toolCallId);
309
- if (existing !== undefined)
385
+ // 同一调用的重复 start 复用;已结束的同名 id(有的供应商跨回合复用 id)另起一个视图
386
+ if (existing !== undefined && existing.isRunning)
310
387
  return { view: existing, topLevel: false };
311
388
  const view = new ToolView(event.toolCallId, event.toolName, event.args, this.options);
312
389
  view.setExpanded(this.expanded);
@@ -324,9 +401,20 @@ export class ToolTracker {
324
401
  end(toolCallId, result, isError) {
325
402
  this.views.get(toolCallId)?.finish(result, isError);
326
403
  }
404
+ /** 审批对话框打开 / 关闭(见 ToolView.setAwaiting)。 */
405
+ setAwaiting(awaiting) {
406
+ for (const view of this.views.values())
407
+ view.setAwaiting(awaiting);
408
+ }
409
+ /** Loader 换帧:运行中的视图重画摘要行。 */
410
+ tick() {
411
+ for (const view of this.views.values())
412
+ view.tick();
413
+ }
327
414
  /** 已完成的调用(重放历史)。 */
328
415
  completed(toolCallId, toolName, args, result, isError) {
329
416
  const { view } = this.start({ toolCallId, toolName, args });
417
+ view.replayed = true;
330
418
  if (result !== undefined)
331
419
  view.finish(result, isError);
332
420
  return view;