@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,22 +1,34 @@
1
1
  /**
2
- * 状态栏(设计 §12.6):编辑器下方一行。[B7]
2
+ * 状态栏(设计 §12.6;终端界面视觉设计 v1 §3.10;第五波 §1):编辑器下方,永远是最后一行。[B7][W5-A]
3
3
  *
4
- * `provider/model · think:medium · ↑12.3k ↓1.2k · cache 80% ♨ · $0.12 · rebill $0.11 · ctx 34%
5
- * · queue 1 · mode:default · codemode:only net! · preset:default · [宿主状态]`
4
+ * 两区:左区「权限模式 + shift+tab 切换」,右区信息,中间用空格撑开;空隙不足 4 列时退回单区。模式永远在最左;
5
+ * 同组项(模型与思考级别、目录与 git)以空格相连。compact 分隔符固定为 ` · `(tmux 宿主按此解析),full 按用户
6
+ * 样例用 ` | `。
6
7
  *
7
- * - 用量来自 `session.getStats()`(`↑` = 输入含缓存读写,`↓` = 输出),只在 `refresh()` 时读取
8
- * (事件驱动),渲染只拼字符串;
9
- * - [W3-C2] `cache` 是**最近一次**请求的命中率(会话累计在 `/session`);端点三态:`unknown` →
10
- * `cache —`,`silent` → `cache 未报告`;保温计时中追加 `♨`;会话有重计费时显示 `rebill $x`
11
- * (无价模型显示重计费 token);会话层缓存未接线时回落到会话命中率 `cacheHitRate`;
12
- * - `ctx ?` 表示模型没有上下文窗口;≥ 70% 黄、≥ 90% 红;没有用量时不显示 token / cache / 费用;
13
- * - [W3-C2 A4] codemode 生效时显示 `codemode:on|only`,运行时 Node 的权限模型不隔离网络
14
- * (`detectSandboxCapability().strict` 为 false)时追加红色 `net!`;
15
- * - 宿主状态读 `HostAdapterHandle.status()`(宿主 `ui.setStatus`),每次渲染现取;
16
- * - 宽度不够时按优先级丢弃(宿主 → 预设 → rebill → 费用 → cache → token → think → 队列 →
17
- * codemode),模型、ctx、权限模式最后丢。
8
+ * 两种布局(`ui.statusLine`,§1.1):
9
+ * - `compact`(嵌入宿主缺省,即原单行状态栏):
10
+ * `Manual · shift+tab 切换 sonnet-4-5 · medium · ↑12.3k ↓1.2k · cache 80% ♨ · $0.12 · ctx 34% · proj ⎇ main 5ae9e54 +12 −3 · 2h24m`
11
+ * 右区顺序:模型 · 思考 · `↑ ↓` · cache · 费用 · rebill · ctx · git · 时长 · queue · codemode · 预设 · [宿主]。
12
+ * - `full`(独立终端缺省,用户样例):用量类项移到上方速率行(status-line.ts),本行为
13
+ * `Manual | 模型 思考 | Ctx 3.0% | 目录 ⎇ 分支 短提交 (+a,-d) | $费用 | 会话时长`;Ctx 一位小数、不换余量表。
14
+ *
15
+ * - 用量来自 `session.getStats()`,只在 `refresh()` 时读取(事件驱动),渲染只拼字符串;时长按渲染时刻算。
16
+ * - [W3-C2] `cache` 是**最近一次**请求的命中率;端点三态 `cache —` / `cache 未报告`;保温中追加 `♨`;
17
+ * 重计费 `rebill $x`(无价模型显示 token);codemode 生效时 `codemode on|only`,网络未隔离追加 `net!`
18
+ * (S2:Node 权限模型与 OS 沙箱都不隔离网络时)。
19
+ * - 费用 = `stats.cost` + 外部 Agent 以美元计的用量(`stats.external`,W5-E;其它单位只在 /session 显示)。
20
+ * - 着色:整行 dim;模式名正文色(Bypass permissions warning、Plan accent);模型 accent;ctx 按阈值
21
+ * success / warning / error;rebill、queue warning;`net!` error。宽 ≥ 110 时 ctx 用余量表。
22
+ * - [W5-U] bash 在操作系统沙箱里跑时(S2)用量类项多一个 `沙箱`(与 codemode 同一丢弃优先级)。
23
+ * - [W5-U] 模型回退中(`model_fallback`)模型项显示 `主模型 → 回退模型`,切回主模型后恢复。
24
+ * - 模型名缩写:宽 < 100 去掉供应商前缀,< 60 再去掉 `@渠道`,< 48 去掉版本后缀(第一个 `-数字` 起)。
25
+ * - ASCII:`⎇` → `git`(字形表 `branch`)、`−` → `-`、`♨` → `~`。
26
+ * - 宽度不够时按优先级丢弃(数字大的先丢,表见 §1.2);会变的数字按最宽形状占位(`reserve`),
27
+ * 数字变化不会让某项时有时无(40 列不抖动)。
18
28
  */
19
- import { truncateToWidth, visibleWidth } from "../../tui.js";
29
+ import { permissionModeLabel } from "../../permissions/modes.js";
30
+ import { formatModelRef } from "../../ai/providers/channels.js";
31
+ import { Meter, levelColor, truncateToWidth, visibleWidth, } from "../../tui.js";
20
32
  export function formatTokens(count) {
21
33
  if (count < 1000)
22
34
  return String(count);
@@ -31,16 +43,177 @@ export function formatCost(cost) {
31
43
  return `$${cost.toFixed(2)}`;
32
44
  return `$${cost.toFixed(3)}`;
33
45
  }
46
+ /** 会话时长:`Ns` / `Nm` / `NhMm`。 */
47
+ export function formatDuration(ms) {
48
+ const seconds = Math.max(0, Math.floor(ms / 1000));
49
+ if (seconds < 60)
50
+ return `${seconds}s`;
51
+ const minutes = Math.floor(seconds / 60);
52
+ if (minutes < 60)
53
+ return `${minutes}m`;
54
+ return `${Math.floor(minutes / 60)}h${minutes % 60}m`;
55
+ }
34
56
  /** `cache 83%` / `cache —` / `cache 未报告`,保温计时中追加 ` ♨`。 */
35
- export function cacheText(cache) {
57
+ export function cacheText(cache, warm = "♨") {
36
58
  const rate = cache.lastHitRate ?? cache.hitRate;
37
59
  const value = cache.reporting === "silent"
38
60
  ? "未报告"
39
61
  : cache.reporting === "reported" && rate !== undefined
40
62
  ? `${Math.round(rate * 100)}%`
41
63
  : "—";
42
- return `cache ${value}${cache.warming.state === "scheduled" ? " ♨" : ""}`;
64
+ return `cache ${value}${cache.warming.state === "scheduled" ? ` ${warm}` : ""}`;
65
+ }
66
+ /** 状态费用:会话费用 + 外部 Agent 以美元计的用量;会话费用未知为 undefined。 */
67
+ export function statusCost(stats) {
68
+ if (stats.cost === undefined)
69
+ return undefined;
70
+ let external = 0;
71
+ for (const usage of Object.values(stats.external?.byAgent ?? {})) {
72
+ if (usage.unit === "usd")
73
+ external += usage.amount;
74
+ }
75
+ return stats.cost + external;
76
+ }
77
+ /** 两区之间至少留的空格;不足时退回单区。 */
78
+ const MIN_GAP = 4;
79
+ /** ctx 改用余量表的最小宽度。 */
80
+ const METER_WIDTH = 110;
81
+ /** 按优先级丢弃后排成一行(两区 / 单区);连接符都是 dim。 */
82
+ export function layoutRow(parts, width, theme, style = {}) {
83
+ const sep = style.sep ?? " · ";
84
+ const dim = (text) => (text === "" ? "" : theme.fg("dim", text));
85
+ /** 返回 [文本, 占位宽度]。 */
86
+ const join = (list) => {
87
+ let out = "";
88
+ let size = 0;
89
+ const add = (text, measured = visibleWidth(text)) => {
90
+ out += text;
91
+ size += measured;
92
+ };
93
+ list.forEach((p, i) => {
94
+ const prev = i === 0 ? undefined : list[i - 1];
95
+ const group = p.group === undefined ? undefined : style.groups?.[p.group];
96
+ const continues = prev !== undefined && p.group !== undefined && p.group === prev.group;
97
+ if (continues)
98
+ add(dim(group?.glue ?? " "));
99
+ else {
100
+ if (prev !== undefined) {
101
+ const prevGroup = prev.group === undefined ? undefined : style.groups?.[prev.group];
102
+ add(dim(prevGroup?.close ?? ""));
103
+ add(dim(p.lead ?? sep));
104
+ }
105
+ add(dim(group?.open ?? ""));
106
+ }
107
+ add(p.text, Math.max(visibleWidth(p.text), p.reserve ?? 0));
108
+ });
109
+ const last = list[list.length - 1];
110
+ if (last?.group !== undefined)
111
+ add(dim(style.groups?.[last.group]?.close ?? ""));
112
+ return [out, size];
113
+ };
114
+ let kept = [...parts];
115
+ const zone = (z) => kept.filter((p) => p.zone === z);
116
+ const fits = () => {
117
+ const l = join(zone("left"))[1];
118
+ const right = zone("right");
119
+ return l + (right.length === 0 ? 0 : sep.length + join(right)[1]) <= width;
120
+ };
121
+ while (!fits()) {
122
+ const droppable = kept.filter((p) => p.priority !== undefined);
123
+ if (droppable.length === 0)
124
+ break;
125
+ const drop = droppable.reduce((worst, p) => (p.priority > worst.priority ? p : worst));
126
+ kept = kept.filter((p) => p !== drop);
127
+ }
128
+ const l = join(zone("left"))[0];
129
+ const r = join(zone("right"))[0];
130
+ const gap = width - visibleWidth(l) - visibleWidth(r);
131
+ const line = r === "" ? l : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep) + r;
132
+ return truncateToWidth(line, width);
43
133
  }
134
+ /** 按终端宽度缩写模型名(§3.10)。 */
135
+ export function abbreviateModel(ref, width) {
136
+ let out = ref;
137
+ if (width < 100)
138
+ out = out.slice(out.indexOf("/") + 1);
139
+ if (width < 60)
140
+ out = out.replace(/@.*$/, "");
141
+ if (width < 48)
142
+ out = out.replace(/-\d.*$/, "");
143
+ return out;
144
+ }
145
+ /** 用量类项的文本(已着色;普通项 dim)。 */
146
+ export function usageItems(stats, queue, source, theme) {
147
+ const g = theme.glyphs;
148
+ const dim = (text) => theme.fg("dim", text);
149
+ const out = {};
150
+ const t = stats.tokens;
151
+ const prompt = t.input + t.cacheRead + t.cacheWrite;
152
+ const cache = stats.cache;
153
+ if (prompt + t.output > 0) {
154
+ out.tokens = dim(`${g.arrowUp}${formatTokens(prompt)} ${g.arrowDown}${formatTokens(t.output)}`);
155
+ if (cache !== undefined)
156
+ out.cache = dim(cacheText(cache, g.warm));
157
+ else if (stats.cacheHitRate !== undefined) {
158
+ out.cache = dim(`cache ${Math.round(stats.cacheHitRate * 100)}%`);
159
+ }
160
+ const cost = statusCost(stats);
161
+ if (cost === undefined)
162
+ out.cost = dim("$?");
163
+ else if (cost > 0)
164
+ out.cost = dim(formatCost(cost));
165
+ if (cache !== undefined && cache.reBilledTokens > 0) {
166
+ const amount = cache.reBilledUsd === undefined
167
+ ? `${formatTokens(cache.reBilledTokens)} tok`
168
+ : formatCost(cache.reBilledUsd);
169
+ out.rebill = theme.fg("warning", `rebill ${amount}`);
170
+ }
171
+ }
172
+ if (queue > 0)
173
+ out.queue = theme.fg("warning", `queue ${queue}`);
174
+ const codemode = source.codemode?.();
175
+ if (codemode !== undefined) {
176
+ const strict = source.sandboxStrict?.() ?? true;
177
+ const label = dim(`codemode ${codemode}`);
178
+ out.codemode = strict ? label : `${label} ${theme.fg("error", "net!")}`;
179
+ }
180
+ if (source.bashSandbox?.() === true)
181
+ out.sandbox = dim("沙箱");
182
+ const preset = source.preset();
183
+ if (preset !== "default")
184
+ out.preset = dim(`preset ${preset}`);
185
+ const host = source.hostStatus?.();
186
+ if (host !== undefined && host.size > 0) {
187
+ const values = [...host.values()].filter((v) => v.trim() !== "");
188
+ if (values.length > 0)
189
+ out.host = dim(`[${values.join(" · ")}]`);
190
+ }
191
+ return out;
192
+ }
193
+ /** compact 布局的优先级(§1.2:现状顺序,git 三项与时长插在 ctx 之后)。 */
194
+ const COMPACT = {
195
+ model: 0,
196
+ ctx: 1,
197
+ duration: 3,
198
+ branch: 4,
199
+ dir: 5,
200
+ diff: 6,
201
+ codemode: 7,
202
+ queue: 8,
203
+ thinking: 9,
204
+ tokens: 10,
205
+ cache: 11,
206
+ cost: 12,
207
+ rebill: 13,
208
+ preset: 14,
209
+ host: 15,
210
+ hint: 16,
211
+ };
212
+ /** full 布局本行的优先级(§1.2 下行表)。 */
213
+ const FULL = { model: 0, ctx: 1, cost: 2, duration: 3, branch: 4, dir: 5, diff: 6, thinking: 7 };
214
+ const FULL_HINT = 12;
215
+ /** full 状态栏(用户样例):段间 ` | `。 */
216
+ const FULL_STYLE = { sep: " | " };
44
217
  export class StatusBar {
45
218
  source;
46
219
  theme;
@@ -57,81 +230,133 @@ export class StatusBar {
57
230
  setQueue(steering, followUp) {
58
231
  this.queue = steering + followUp;
59
232
  }
60
- parts() {
233
+ /** 当前统计(速率行共用,避免重复 getStats)。 */
234
+ current() {
235
+ this.stats ??= this.source.session().getStats();
236
+ return this.stats;
237
+ }
238
+ queued() {
239
+ return this.queue;
240
+ }
241
+ layout() {
242
+ return this.source.layout?.() ?? "compact";
243
+ }
244
+ parts(width) {
61
245
  const theme = this.theme;
62
- const session = this.source.session();
63
- const state = session.state;
64
- const stats = this.stats ?? session.getStats();
65
- this.stats = stats;
246
+ const g = theme.glyphs;
247
+ const state = this.source.session().state;
248
+ const stats = this.current();
249
+ const full = this.layout() === "full";
66
250
  const parts = [];
67
- const model = state.model === undefined ? "?" : `${state.model.provider}/${state.model.id}`;
68
- parts.push({ text: theme.fg("accent", model), priority: 0 });
69
- parts.push({ text: `think:${state.thinkingLevel}`, priority: 5 });
70
- const t = stats.tokens;
71
- const prompt = t.input + t.cacheRead + t.cacheWrite;
72
- if (prompt + t.output > 0) {
73
- parts.push({ text: `↑${formatTokens(prompt)} ↓${formatTokens(t.output)}`, priority: 6 });
74
- const cache = stats.cache;
75
- if (cache !== undefined)
76
- parts.push({ text: cacheText(cache), priority: 7 });
77
- else if (stats.cacheHitRate !== undefined) {
78
- parts.push({ text: `cache ${Math.round(stats.cacheHitRate * 100)}%`, priority: 7 });
79
- }
80
- if (stats.cost === undefined)
81
- parts.push({ text: "$?", priority: 8 });
82
- else if (stats.cost > 0)
83
- parts.push({ text: formatCost(stats.cost), priority: 8 });
84
- if (cache !== undefined && cache.reBilledTokens > 0) {
85
- const amount = cache.reBilledUsd === undefined
86
- ? `${formatTokens(cache.reBilledTokens)} tok`
87
- : formatCost(cache.reBilledUsd);
88
- parts.push({ text: theme.fg("warning", `rebill ${amount}`), priority: 9 });
89
- }
90
- }
91
- const ctx = stats.contextPercent;
92
- const ctxText = ctx === undefined ? "ctx ?" : `ctx ${Math.round(ctx)}%`;
93
- parts.push({
94
- text: ctx !== undefined && ctx >= 90
95
- ? theme.fg("error", ctxText)
96
- : ctx !== undefined && ctx >= 70
97
- ? theme.fg("warning", ctxText)
98
- : ctxText,
99
- priority: 1,
100
- });
101
- if (this.queue > 0)
102
- parts.push({ text: theme.fg("warning", `queue ${this.queue}`), priority: 4 });
103
- const mode = `mode:${state.permissionMode}`;
251
+ const dim = (text) => theme.fg("dim", text);
252
+ const right = (text, priority, extra = {}) => void parts.push({ text, priority, zone: "right", ...extra });
253
+ const mode = permissionModeLabel(state.permissionMode);
104
254
  parts.push({
105
- text: state.permissionMode === "full-auto" ? theme.fg("warning", mode) : mode,
106
- priority: 2,
255
+ text: state.permissionMode === "full-auto"
256
+ ? theme.fg("warning", mode)
257
+ : state.permissionMode === "plan"
258
+ ? theme.fg("accent", mode)
259
+ : theme.fg("text", mode),
260
+ priority: undefined,
261
+ zone: "left",
107
262
  });
108
- const codemode = this.source.codemode?.();
109
- if (codemode !== undefined) {
110
- const strict = this.source.sandboxStrict?.() ?? true;
263
+ if (width >= 40) {
111
264
  parts.push({
112
- text: `codemode:${codemode}${strict ? "" : ` ${theme.fg("error", "net!")}`}`,
113
- priority: 3,
265
+ text: dim("shift+tab 切换"),
266
+ priority: full ? FULL_HINT : COMPACT.hint,
267
+ zone: "left",
114
268
  });
115
269
  }
116
- parts.push({ text: `preset:${this.source.preset()}`, priority: 10 });
117
- const host = this.source.hostStatus?.();
118
- if (host !== undefined && host.size > 0) {
119
- const values = [...host.values()].filter((v) => v.trim() !== "");
120
- if (values.length > 0)
121
- parts.push({ text: `[${values.join(" · ")}]`, priority: 11 });
270
+ const model = state.model === undefined ? "?" : abbreviateModel(formatModelRef(state.model), width);
271
+ const p = full ? FULL : COMPACT;
272
+ const fallback = this.source.fallback?.();
273
+ // 回退中:`主模型 → 回退模型`(回退模型 warning),切回主模型后恢复原样
274
+ const modelText = fallback === undefined
275
+ ? theme.fg("accent", model)
276
+ : theme.fg("accent", abbreviateModel(fallback.from, width)) +
277
+ dim(g.ascii ? " -> " : " → ") +
278
+ theme.fg("warning", abbreviateModel(fallback.to, width));
279
+ right(modelText, p.model, full ? { group: "model" } : {});
280
+ if (state.thinkingLevel !== "off") {
281
+ right(dim(state.thinkingLevel), p.thinking, full ? { group: "model" } : {});
282
+ }
283
+ const usage = full ? {} : usageItems(stats, this.queue, this.source, theme);
284
+ if (usage.tokens !== undefined)
285
+ right(usage.tokens, COMPACT.tokens);
286
+ if (usage.cache !== undefined)
287
+ right(usage.cache, COMPACT.cache);
288
+ if (usage.cost !== undefined)
289
+ right(usage.cost, COMPACT.cost);
290
+ if (usage.rebill !== undefined)
291
+ right(usage.rebill, COMPACT.rebill);
292
+ right(this.ctxText(stats.contextPercent, width, full), p.ctx, full ? { reserve: 10 } : {});
293
+ this.gitParts(p, full).forEach((part) => parts.push(part));
294
+ if (full) {
295
+ const cost = statusCost(stats);
296
+ const used = stats.tokens.input + stats.tokens.output + stats.tokens.cacheRead > 0;
297
+ if (cost === undefined && used)
298
+ right(dim("$?"), FULL.cost);
299
+ else if (cost !== undefined && cost > 0)
300
+ right(dim(formatCost(cost)), FULL.cost);
122
301
  }
302
+ const started = this.source.sessionStartedAt?.() ?? stats.telemetry?.sessionStartedAt;
303
+ if (started !== undefined) {
304
+ const now = this.source.now?.() ?? Date.now();
305
+ right(dim(formatDuration(now - started)), p.duration, { reserve: 6 });
306
+ }
307
+ if (usage.queue !== undefined)
308
+ right(usage.queue, COMPACT.queue);
309
+ if (usage.codemode !== undefined)
310
+ right(usage.codemode, COMPACT.codemode);
311
+ if (usage.sandbox !== undefined)
312
+ right(usage.sandbox, COMPACT.codemode);
313
+ if (usage.preset !== undefined)
314
+ right(usage.preset, COMPACT.preset);
315
+ if (usage.host !== undefined)
316
+ right(usage.host, COMPACT.host);
123
317
  return parts;
124
318
  }
125
- render(width) {
126
- const parts = this.parts();
127
- const sep = this.theme.fg("dim", " · ");
128
- const join = (list) => list.map((p) => p.text).join(sep);
129
- let kept = parts;
130
- while (kept.length > 1 && visibleWidth(join(kept)) > width) {
131
- const drop = kept.reduce((worst, p) => (p.priority > worst.priority ? p : worst));
132
- kept = kept.filter((p) => p !== drop);
319
+ /** `目录 ⎇ 分支 短提交 +a −b`:三项同组、各自按优先级丢弃。 */
320
+ gitParts(p, full) {
321
+ const git = this.source.git?.();
322
+ if (git === undefined)
323
+ return [];
324
+ const theme = this.theme;
325
+ const g = theme.glyphs;
326
+ const dim = (text) => theme.fg("dim", text);
327
+ const out = [];
328
+ const add = (text, priority) => void out.push({ text: dim(text), priority, zone: "right", group: "git" });
329
+ if (git.dir !== "")
330
+ add(git.dir, p.dir);
331
+ const info = git.info;
332
+ if (info === undefined)
333
+ return out;
334
+ const head = [info.branch, info.shortHead].filter((s) => s !== undefined).join(" ");
335
+ if (head !== "")
336
+ add(`${g.branch} ${head}`, p.branch);
337
+ if (info.insertions !== undefined && info.deletions !== undefined) {
338
+ const { insertions: a, deletions: d } = info;
339
+ add(full ? `(+${a},-${d})` : `+${a} ${g.ascii ? "-" : "−"}${d}`, p.diff);
340
+ }
341
+ return out;
342
+ }
343
+ ctxText(percent, width, decimal) {
344
+ const theme = this.theme;
345
+ if (percent === undefined)
346
+ return theme.fg("dim", decimal ? "Ctx ?" : "ctx ?");
347
+ const color = levelColor(percent / 100);
348
+ // full 按用户样例总是 `Ctx 3.0%`;compact 宽屏换余量表(现状)
349
+ if (!decimal && width >= METER_WIDTH) {
350
+ const meter = new Meter(percent / 100, { label: theme.fg("dim", "ctx"), theme });
351
+ return meter.render(80)[0] ?? "";
133
352
  }
134
- return [truncateToWidth(join(kept), width)];
353
+ if (decimal)
354
+ return theme.fg("dim", "Ctx ") + theme.fg(color, `${percent.toFixed(1)}%`);
355
+ return theme.fg("dim", "ctx ") + theme.fg(color, `${Math.round(percent)}%`);
356
+ }
357
+ render(width) {
358
+ const style = this.layout() === "full" ? FULL_STYLE : {};
359
+ return [layoutRow(this.parts(width), width, this.theme, style)];
135
360
  }
136
361
  invalidate() {
137
362
  this.stats = undefined;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 速率行(第五波 §1.1,D1、D2):`ui.statusLine: "full"` 时在状态栏上方多一行。[W5-A]
3
+ *
4
+ * ```text
5
+ * tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s) ↑12.3k ↓1.2k · cache 83% ♨ · [-]
6
+ * ```
7
+ *
8
+ * - 左区(用户样例):`tps: <速率>`(流式中是最近 2 s 窗口的瞬时值、前缀 accent;结束后是该请求的平均值;
9
+ * 还没有请求时 `tps: —`)• `<输出 token> tok / <耗时>`(首 token 起算)`(avg <会话均速> · ttft <首 token 延迟>)`;
10
+ * `•` 走字形表(ASCII `*`);
11
+ * - 右区:从状态栏迁来的用量类项 `↑ ↓` · cache · rebill · queue · codemode · 预设 · [宿主],行尾 `[-]`
12
+ * (折叠提示:Ctrl+G 或 `/statusline compact`);
13
+ * - 数据:`StatusBar.current()` 的 `telemetry` 与用量(同一次 getStats);流式中 `telemetry_tick` 时刷新;
14
+ * - 丢弃顺序(§1.2,数字大先丢;`tps` 与 `[-]` 永不丢):tok/耗时 10 → codemode 9 → queue 8 → token 7 →
15
+ * cache 6 → rebill 5 → 预设 4 → 宿主 3 → avg 2 → ttft 1;数字按最宽形状占位,不随数值抖动;
16
+ * - `compact` 时不占行(render 返回空)。
17
+ */
18
+ import { type Component, type Theme } from "../../tui.js";
19
+ import { type StatusBar, type StatusBarSource } from "./status-bar.js";
20
+ /** 速率:< 10 保留一位小数,其余取整。 */
21
+ export declare function formatRate(tps: number): string;
22
+ /** 耗时:< 60 s 一位小数(`5.5s`),其余 `1m05s`。 */
23
+ export declare function formatSeconds(ms: number): string;
24
+ export declare const COLLAPSE_HINT = "[-]";
25
+ export declare class StatusLine implements Component {
26
+ private readonly bar;
27
+ private readonly source;
28
+ private readonly theme;
29
+ constructor(bar: StatusBar, source: StatusBarSource, theme: Theme);
30
+ private parts;
31
+ render(width: number): string[];
32
+ invalidate(): void;
33
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * 速率行(第五波 §1.1,D1、D2):`ui.statusLine: "full"` 时在状态栏上方多一行。[W5-A]
3
+ *
4
+ * ```text
5
+ * tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s) ↑12.3k ↓1.2k · cache 83% ♨ · [-]
6
+ * ```
7
+ *
8
+ * - 左区(用户样例):`tps: <速率>`(流式中是最近 2 s 窗口的瞬时值、前缀 accent;结束后是该请求的平均值;
9
+ * 还没有请求时 `tps: —`)• `<输出 token> tok / <耗时>`(首 token 起算)`(avg <会话均速> · ttft <首 token 延迟>)`;
10
+ * `•` 走字形表(ASCII `*`);
11
+ * - 右区:从状态栏迁来的用量类项 `↑ ↓` · cache · rebill · queue · codemode · 预设 · [宿主],行尾 `[-]`
12
+ * (折叠提示:Ctrl+G 或 `/statusline compact`);
13
+ * - 数据:`StatusBar.current()` 的 `telemetry` 与用量(同一次 getStats);流式中 `telemetry_tick` 时刷新;
14
+ * - 丢弃顺序(§1.2,数字大先丢;`tps` 与 `[-]` 永不丢):tok/耗时 10 → codemode 9 → queue 8 → token 7 →
15
+ * cache 6 → rebill 5 → 预设 4 → 宿主 3 → avg 2 → ttft 1;数字按最宽形状占位,不随数值抖动;
16
+ * - `compact` 时不占行(render 返回空)。
17
+ */
18
+ import { truncateToWidth } from "../../tui.js";
19
+ import { formatTokens, layoutRow, usageItems, } from "./status-bar.js";
20
+ /** 速率:< 10 保留一位小数,其余取整。 */
21
+ export function formatRate(tps) {
22
+ return tps < 10 ? tps.toFixed(1) : String(Math.round(tps));
23
+ }
24
+ /** 耗时:< 60 s 一位小数(`5.5s`),其余 `1m05s`。 */
25
+ export function formatSeconds(ms) {
26
+ const seconds = Math.max(0, ms) / 1000;
27
+ if (seconds < 60)
28
+ return `${seconds.toFixed(1)}s`;
29
+ const whole = Math.floor(seconds);
30
+ return `${Math.floor(whole / 60)}m${String(whole % 60).padStart(2, "0")}s`;
31
+ }
32
+ /** 占位宽度(常见的最宽形状):`tps: 999 tok/s`、`1.2k tok / 59.9s`、`avg 999`、`ttft 9.9s`。 */
33
+ const RESERVE = { tps: 14, amount: 16, avg: 7, ttft: 9 };
34
+ const PRIORITY = {
35
+ ttft: 1,
36
+ avg: 2,
37
+ host: 3,
38
+ preset: 4,
39
+ rebill: 5,
40
+ cache: 6,
41
+ tokens: 7,
42
+ queue: 8,
43
+ codemode: 9,
44
+ amount: 10,
45
+ };
46
+ export const COLLAPSE_HINT = "[-]";
47
+ /** 用户样例:`tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s)`;右区用量项仍以 ` · ` 分隔。 */
48
+ const RATE_STYLE = { groups: { stats: { glue: " · ", open: "(", close: ")" } } };
49
+ export class StatusLine {
50
+ bar;
51
+ source;
52
+ theme;
53
+ constructor(bar, source, theme) {
54
+ this.bar = bar;
55
+ this.source = source;
56
+ this.theme = theme;
57
+ }
58
+ parts() {
59
+ const theme = this.theme;
60
+ const dim = (text) => theme.fg("dim", text);
61
+ const stats = this.bar.current();
62
+ const telemetry = stats.telemetry;
63
+ const live = telemetry?.live;
64
+ const last = telemetry?.last;
65
+ const parts = [];
66
+ const left = (text, priority, reserve, extra = {}) => void parts.push({ text, priority, zone: "left", reserve, ...extra });
67
+ const right = (text, priority) => {
68
+ if (text !== undefined)
69
+ parts.push({ text, priority, zone: "right" });
70
+ };
71
+ let tps;
72
+ let amount;
73
+ if (live !== undefined) {
74
+ tps = live.tps;
75
+ amount = `${formatTokens(live.outputTokens)} tok / ${formatSeconds(live.elapsedMs)}`;
76
+ }
77
+ else if (last?.doneAt !== undefined) {
78
+ tps = last.tps;
79
+ if (last.outputTokens !== undefined && last.firstTokenAt !== undefined) {
80
+ amount = `${formatTokens(last.outputTokens)} tok / ${formatSeconds(last.doneAt - last.firstTokenAt)}`;
81
+ }
82
+ }
83
+ const label = live !== undefined ? theme.fg("accent", "tps:") : dim("tps:");
84
+ left(`${label} ${dim(tps === undefined ? "—" : `${formatRate(tps)} tok/s`)}`, undefined, RESERVE.tps);
85
+ if (amount !== undefined) {
86
+ left(dim(amount), PRIORITY.amount, RESERVE.amount, { lead: ` ${theme.glyphs.dot} ` });
87
+ }
88
+ const stat = { group: "stats", lead: " " };
89
+ if (telemetry?.avgTps !== undefined) {
90
+ left(dim(`avg ${formatRate(telemetry.avgTps)}`), PRIORITY.avg, RESERVE.avg, stat);
91
+ }
92
+ if (last?.ttftMs !== undefined) {
93
+ left(dim(`ttft ${formatSeconds(last.ttftMs)}`), PRIORITY.ttft, RESERVE.ttft, stat);
94
+ }
95
+ const usage = usageItems(stats, this.bar.queued(), this.source, theme);
96
+ right(usage.tokens, PRIORITY.tokens);
97
+ right(usage.cache, PRIORITY.cache);
98
+ right(usage.rebill, PRIORITY.rebill);
99
+ right(usage.queue, PRIORITY.queue);
100
+ right(usage.codemode, PRIORITY.codemode);
101
+ right(usage.sandbox, PRIORITY.codemode);
102
+ right(usage.preset, PRIORITY.preset);
103
+ right(usage.host, PRIORITY.host);
104
+ right(dim(COLLAPSE_HINT), undefined);
105
+ return parts;
106
+ }
107
+ render(width) {
108
+ if (this.bar.layout() !== "full")
109
+ return [];
110
+ return [truncateToWidth(layoutRow(this.parts(), width, this.theme, RATE_STYLE), width)];
111
+ }
112
+ invalidate() { }
113
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * 消息区的子 Agent 折叠视图(docs/wave5-plan.md §7.5)。[W5-U]
3
+ *
4
+ * 消费 `subagent_start / update / end`,按 taskId 记下类型、状态、轮数、最近 3 个工具与用量;task 工具行
5
+ * (tool-view.ts)据 `parentToolCallId` 取来显示一行:
6
+ *
7
+ * ```
8
+ * ⏺ task 检查 src/tui 的测试覆盖缺口
9
+ * ⎿ ⠋ explore · 运行中 1m05s · 3 轮 · read grep bash · ↑12k ↓3.4k
10
+ * ```
11
+ *
12
+ * 后台任务的工具调用立即返回,工具行下面多一行跟随状态(`↳ t2 explore · 完成 · 7 轮 …`,运行中每秒刷新);
13
+ * 完成后父会话收到的 `<task-notification>` 只显示一行(`notificationSummary`),失败 / 停止另有一行提示。
14
+ * 外部 runner(claude / codex)同一组事件,用量可能缺。
15
+ */
16
+ import type { SessionEvent, SubagentStatus } from "../../agent/types.js";
17
+ import type { Usage } from "../../ai/types.js";
18
+ import { type Theme } from "../../tui.js";
19
+ export declare const RECENT_TOOLS = 3;
20
+ export interface SubagentState {
21
+ taskId: string;
22
+ parentToolCallId: string;
23
+ agent: string;
24
+ runner: string;
25
+ background: boolean;
26
+ status: SubagentStatus | "running";
27
+ turns: number;
28
+ /** 最近的工具名(最多 3 个,新的在后)。 */
29
+ tools: string[];
30
+ usage?: Usage;
31
+ startedAt: number;
32
+ endedAt?: number;
33
+ }
34
+ export declare class SubagentTracker {
35
+ private readonly now;
36
+ private readonly tasks;
37
+ private readonly byCall;
38
+ constructor(now?: () => number);
39
+ /** 子 Agent 事件:更新状态并返回它;其它事件返回 undefined。 */
40
+ onEvent(event: SessionEvent): SubagentState | undefined;
41
+ /** 运行中的任务。 */
42
+ running(): SubagentState[];
43
+ get(taskId: string): SubagentState | undefined;
44
+ /** task 工具调用对应的子 Agent(续聊时是同一 taskId)。 */
45
+ forToolCall(toolCallId: string): SubagentState | undefined;
46
+ clear(): void;
47
+ }
48
+ /** `explore · 运行中 1m05s · 3 轮 · read grep bash · ↑12k ↓3.4k`(已着色:类型 tool 色,其余 muted)。 */
49
+ export declare function subagentLine(state: SubagentState, theme: Theme, now: number): string;
50
+ /** 后台任务结束的一行提示。 */
51
+ export declare function backgroundEndText(state: SubagentState): string;
52
+ /**
53
+ * 父会话收到的 `<task-notification …>`(origin `task` 的用户消息)在消息区只显示一行:
54
+ * `t1 explore 完成 · 7 轮 · /tasks 查看输出`;不是通知格式返回 undefined。
55
+ */
56
+ export declare function notificationSummary(text: string): string | undefined;