rovecode 0.3.3 → 0.4.0-beta.3

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 (495) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +46 -48
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-j6gn14w3.js +2 -0
  5. package/dist/cli/ask-user-cwstt8fz.js +2 -0
  6. package/dist/cli/auth-login-9bbp9915.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-16zqdms5.js +9 -0
  9. package/dist/cli/catalog-1xchffa4.js +2 -0
  10. package/dist/cli/cli-1n1zb64f.js +2 -0
  11. package/dist/cli/client-2t9gjkck.js +2 -0
  12. package/dist/cli/commands-exafvm2b.js +2 -0
  13. package/dist/cli/connect-6zde0kn3.js +2 -0
  14. package/dist/cli/context-cmd-5t43wgqt.js +2 -0
  15. package/dist/cli/context-report-kt01pw8y.js +2 -0
  16. package/dist/cli/count-remote-ap7x3vh6.js +2 -0
  17. package/dist/cli/design-ne5zszyh.js +2 -0
  18. package/dist/cli/dispatch-2r5myxye.js +2 -0
  19. package/dist/cli/doctor-ws4fh4tn.js +3 -0
  20. package/dist/cli/executor-bdrjn634.js +2 -0
  21. package/dist/cli/export-1mxb9g5p.js +2 -0
  22. package/dist/cli/files-g104xghh.js +2 -0
  23. package/dist/cli/gauntlet-07xrjpj7.js +2 -0
  24. package/dist/cli/gauntlet-runner-xvy64436.js +10 -0
  25. package/dist/cli/gauntlet-wave3-jm91yt5w.js +5 -0
  26. package/dist/cli/gauntlet-wave4-r13py7p1.js +14 -0
  27. package/dist/cli/hashline-znvrat11.js +2 -0
  28. package/dist/cli/http-xafw6fsh.js +143 -0
  29. package/dist/cli/index-1sgjm25y.js +2 -0
  30. package/dist/cli/init-g2m0tn4m.js +51 -0
  31. package/dist/cli/install-avaqjjqq.js +2 -0
  32. package/dist/cli/loop-mmpfft01.js +2 -0
  33. package/dist/cli/main-0904f6ps.js +5 -0
  34. package/dist/cli/main-0ab9fc26.js +9 -0
  35. package/dist/cli/main-0jys2ccn.js +3 -0
  36. package/dist/cli/main-0mtcdbs7.js +3 -0
  37. package/dist/cli/main-0z1w2zsg.js +3 -0
  38. package/dist/cli/main-1dchs7xv.js +18 -0
  39. package/dist/cli/main-1ereejm1.js +3 -0
  40. package/dist/cli/main-1k1kw6b5.js +3 -0
  41. package/dist/cli/main-27y4sm2k.js +38 -0
  42. package/dist/cli/main-2wwjex5j.js +58 -0
  43. package/dist/cli/main-2yeveeve.js +6 -0
  44. package/dist/cli/main-2yfck9b5.js +3 -0
  45. package/dist/cli/main-2zmzgkwh.js +3 -0
  46. package/dist/cli/main-351pz3z7.js +7 -0
  47. package/dist/cli/main-3gjqfh7a.js +6 -0
  48. package/dist/cli/main-3nf3kgve.js +3 -0
  49. package/dist/cli/main-3pjrb2hd.js +3 -0
  50. package/dist/cli/main-3rxcvgna.js +19 -0
  51. package/dist/cli/main-4b3jgy66.js +19 -0
  52. package/dist/cli/main-4wndhjdc.js +7 -0
  53. package/dist/cli/main-4xcmvxnk.js +3 -0
  54. package/dist/cli/main-5tbz0wbz.js +4 -0
  55. package/dist/cli/main-5ywnwthm.js +3 -0
  56. package/dist/cli/main-6b62vkz0.js +14 -0
  57. package/dist/cli/main-6dnk69vp.js +3 -0
  58. package/dist/cli/main-6genrmhs.js +136 -0
  59. package/dist/cli/main-73g7eff4.js +15 -0
  60. package/dist/cli/main-7c5thhjd.js +5 -0
  61. package/dist/cli/main-7rn6bqje.js +3 -0
  62. package/dist/cli/main-80haw7qk.js +4 -0
  63. package/dist/cli/main-875s60s2.js +4 -0
  64. package/dist/cli/main-8kjxbpw4.js +8 -0
  65. package/dist/cli/main-90ds1z4e.js +10 -0
  66. package/dist/cli/main-9etavkew.js +3 -0
  67. package/dist/cli/main-a9njrkk1.js +3 -0
  68. package/dist/cli/main-aecrjq2d.js +12 -0
  69. package/dist/cli/main-ck9asesq.js +9 -0
  70. package/dist/cli/main-cta9racd.js +4 -0
  71. package/dist/cli/main-ddv7j2ag.js +3 -0
  72. package/dist/cli/main-dfreez27.js +10 -0
  73. package/dist/cli/main-f7rw7des.js +3 -0
  74. package/dist/cli/main-ggcn7rd7.js +5 -0
  75. package/dist/cli/main-gzkmycnv.js +3 -0
  76. package/dist/cli/main-hq51jg8v.js +18 -0
  77. package/dist/cli/main-jft389w9.js +8 -0
  78. package/dist/cli/main-k1eqkg83.js +3 -0
  79. package/dist/cli/main-k2y8a2aw.js +9 -0
  80. package/dist/cli/main-kcpbykxz.js +4 -0
  81. package/dist/cli/main-kd488vje.js +22 -0
  82. package/dist/cli/main-kh32yvgk.js +5 -0
  83. package/dist/cli/main-kqxnqjnv.js +25 -0
  84. package/dist/cli/main-kyn0xnsg.js +3 -0
  85. package/dist/cli/main-m1kk6fp5.js +21 -0
  86. package/dist/cli/main-mv40pcr2.js +4 -0
  87. package/dist/cli/main-n0t3973w.js +3 -0
  88. package/dist/cli/main-nqveez48.js +4 -0
  89. package/dist/cli/main-pknhvrmj.js +3 -0
  90. package/dist/cli/main-pn1w7a7j.js +3 -0
  91. package/dist/cli/main-prxxs70n.js +4 -0
  92. package/dist/cli/main-q3vsesf9.js +3 -0
  93. package/dist/cli/main-qsevpgsv.js +3 -0
  94. package/dist/cli/main-rdgdw24b.js +25 -0
  95. package/dist/cli/main-rfth4tbm.js +16 -0
  96. package/dist/cli/main-rg0wn0xf.js +5 -0
  97. package/dist/cli/main-sdmxhtv8.js +4 -0
  98. package/dist/cli/main-skbp13js.js +18 -0
  99. package/dist/cli/main-t4xnd213.js +7 -0
  100. package/dist/cli/main-vqak588n.js +4 -0
  101. package/dist/cli/main-w2n1303f.js +9 -0
  102. package/dist/cli/main-wbrdspr2.js +5 -0
  103. package/dist/cli/main-wsrg79c1.js +7 -0
  104. package/dist/cli/main-x4r0fne4.js +5 -0
  105. package/dist/cli/main-xea2f3tn.js +6 -0
  106. package/dist/cli/main-xg704a3c.js +3 -0
  107. package/dist/cli/main-xvnrabfp.js +16 -0
  108. package/dist/cli/main-xy53xf0r.js +4 -0
  109. package/dist/cli/main-y1fqy60y.js +3 -0
  110. package/dist/cli/main-yn8cd281.js +34 -0
  111. package/dist/cli/main-yr0ksc0h.js +4 -0
  112. package/dist/cli/main-z2ex2vyf.js +4 -0
  113. package/dist/cli/main-z3aayzvq.js +3 -0
  114. package/dist/cli/main-zaqh35jg.js +3 -0
  115. package/dist/cli/main-zc2e8e46.js +4 -0
  116. package/dist/cli/main-zzrfw6cf.js +13 -0
  117. package/dist/cli/main.js +280 -0
  118. package/dist/cli/market-cmd-e14kmx9n.js +5 -0
  119. package/dist/cli/mcp-login-wq7ktdek.js +2 -0
  120. package/dist/cli/mcp-market-cmd-9mg3jecy.js +2 -0
  121. package/dist/cli/notify-b7qc0cjb.js +2 -0
  122. package/dist/cli/oauth-z8whcgfx.js +2 -0
  123. package/dist/cli/output-b3ewj3ps.js +16 -0
  124. package/dist/cli/profiles-6mr5he5e.js +2 -0
  125. package/dist/cli/provider-config-g7j42q8x.js +2 -0
  126. package/dist/cli/provider-jr1y8vvm.js +2 -0
  127. package/dist/cli/registry-s8yk86g0.js +2 -0
  128. package/dist/cli/registry-t6p8d4mn.js +2 -0
  129. package/dist/cli/repl-bajwe1mh.js +11 -0
  130. package/dist/cli/resume-rwn9nz7y.js +2 -0
  131. package/dist/cli/run-flags-nah7ndpt.js +2 -0
  132. package/dist/cli/runtime-n7gafzhb.js +2 -0
  133. package/dist/cli/sandbox-config-emdy18x4.js +2 -0
  134. package/dist/cli/server-b0nvs2bn.js +5 -0
  135. package/dist/cli/session-arg-y75wd4kj.js +2 -0
  136. package/dist/cli/session-j62evmjq.js +2 -0
  137. package/dist/cli/sessions-cmd-tsnwz0ns.js +7 -0
  138. package/dist/cli/settings-df10wfez.js +2 -0
  139. package/dist/cli/setup-jzvv72fg.js +2 -0
  140. package/dist/cli/sextant-smoke-37m81ke6.js +5 -0
  141. package/dist/cli/skills-cmd-gjxnxnhx.js +2 -0
  142. package/dist/cli/smoke-p7748apt.js +8 -0
  143. package/dist/cli/start-chat-s4st3mm0.js +12 -0
  144. package/dist/cli/stream-gmeyewds.js +2 -0
  145. package/dist/cli/task-gh0kkp3n.js +2 -0
  146. package/dist/cli/tasks-z1kfpe8e.js +2 -0
  147. package/dist/cli/thinking-0eqkrz6t.js +2 -0
  148. package/dist/cli/todo-5brcrt9m.js +2 -0
  149. package/dist/cli/tools-7pzm0vj9.js +2 -0
  150. package/dist/cli/tools-s635p6s8.js +2 -0
  151. package/dist/cli/trust-cmd-cjav8zgm.js +2 -0
  152. package/dist/cli/update-check-pt31bm2f.js +2 -0
  153. package/dist/cli/update-cmd-tk131s9t.js +2 -0
  154. package/dist/cli/voice-56nabd8d.js +2 -0
  155. package/dist/cli/webfetch-xd8q596m.js +2 -0
  156. package/dist/cli/websearch-5hkf98k1.js +2 -0
  157. package/dist/cli/workflow-cmd-cy3cvzjp.js +4 -0
  158. package/dist/cli/workspace-q10g5z3e.js +2 -0
  159. package/dist/lib/index.js +62 -0
  160. package/dist/lib/models-index.json +1 -0
  161. package/dist/lib/plugins.js +55 -0
  162. package/dist/lib/providers.js +17 -0
  163. package/dist/lib/public-api.js +20 -0
  164. package/dist/lib/sdk.js +360 -0
  165. package/package.json +84 -72
  166. package/bin/rovecode.ts +0 -21
  167. package/src/acp/server.ts +0 -374
  168. package/src/cli/auth-login.ts +0 -122
  169. package/src/cli/connect.ts +0 -244
  170. package/src/cli/context-cmd.ts +0 -199
  171. package/src/cli/dispatch.ts +0 -82
  172. package/src/cli/doctor.ts +0 -362
  173. package/src/cli/export.ts +0 -276
  174. package/src/cli/help.ts +0 -293
  175. package/src/cli/is-tui-invocation.ts +0 -8
  176. package/src/cli/main.ts +0 -583
  177. package/src/cli/market-cmd.ts +0 -658
  178. package/src/cli/mcp-login.ts +0 -141
  179. package/src/cli/mcp-market-cmd.ts +0 -302
  180. package/src/cli/output.ts +0 -382
  181. package/src/cli/repl.ts +0 -250
  182. package/src/cli/repomap-root.ts +0 -14
  183. package/src/cli/resume.ts +0 -57
  184. package/src/cli/run-flags.ts +0 -43
  185. package/src/cli/run-limits.ts +0 -78
  186. package/src/cli/runtime.ts +0 -931
  187. package/src/cli/session-arg.ts +0 -30
  188. package/src/cli/sessions-cmd.ts +0 -145
  189. package/src/cli/setup.ts +0 -153
  190. package/src/cli/skills-cmd.ts +0 -194
  191. package/src/cli/start-chat.ts +0 -65
  192. package/src/cli/trust-cmd.ts +0 -52
  193. package/src/coding/bash.ts +0 -148
  194. package/src/coding/checkpoints.ts +0 -327
  195. package/src/coding/diff.ts +0 -138
  196. package/src/coding/files.ts +0 -341
  197. package/src/coding/hashline.ts +0 -274
  198. package/src/coding/lsp-gate.ts +0 -254
  199. package/src/coding/lsp-servers.ts +0 -147
  200. package/src/coding/lsp.ts +0 -283
  201. package/src/coding/repomap-cache.ts +0 -99
  202. package/src/coding/repomap-files.ts +0 -192
  203. package/src/coding/repomap.ts +0 -481
  204. package/src/core/agents.ts +0 -255
  205. package/src/core/compaction.ts +0 -259
  206. package/src/core/config.ts +0 -289
  207. package/src/core/context-report.ts +0 -228
  208. package/src/core/context.ts +0 -60
  209. package/src/core/count-remote.ts +0 -107
  210. package/src/core/execpolicy-rules.ts +0 -196
  211. package/src/core/execpolicy.ts +0 -385
  212. package/src/core/executor.ts +0 -454
  213. package/src/core/guardrails.ts +0 -400
  214. package/src/core/hooks.ts +0 -411
  215. package/src/core/images.ts +0 -230
  216. package/src/core/intro.ts +0 -266
  217. package/src/core/loop.ts +0 -567
  218. package/src/core/modes.ts +0 -372
  219. package/src/core/orchestrator.ts +0 -245
  220. package/src/core/proc-group.ts +0 -48
  221. package/src/core/project-trust.ts +0 -98
  222. package/src/core/reflection.ts +0 -165
  223. package/src/core/sandbox-config.ts +0 -186
  224. package/src/core/session-id.ts +0 -24
  225. package/src/core/session-images.ts +0 -73
  226. package/src/core/session-ops.ts +0 -183
  227. package/src/core/session-text.ts +0 -29
  228. package/src/core/session.ts +0 -469
  229. package/src/core/settings.ts +0 -170
  230. package/src/core/tasks.ts +0 -646
  231. package/src/core/token-scale.ts +0 -108
  232. package/src/core/tools.ts +0 -309
  233. package/src/core/trust.ts +0 -104
  234. package/src/core/types.ts +0 -330
  235. package/src/core/update-check.ts +0 -171
  236. package/src/core/usage.ts +0 -204
  237. package/src/core/validate.ts +0 -121
  238. package/src/core/verify-gate.ts +0 -159
  239. package/src/core/verify.ts +0 -236
  240. package/src/core/voice.ts +0 -158
  241. package/src/core/win-job.ts +0 -183
  242. package/src/core/workspace.ts +0 -184
  243. package/src/design/audit.ts +0 -797
  244. package/src/design/direction.ts +0 -190
  245. package/src/design/rules.ts +0 -157
  246. package/src/eval/bench.ts +0 -150
  247. package/src/eval/gauntlet-runner.ts +0 -215
  248. package/src/eval/gauntlet-support.ts +0 -84
  249. package/src/eval/gauntlet-wave3.ts +0 -269
  250. package/src/eval/gauntlet-wave4.ts +0 -217
  251. package/src/eval/gauntlet.ts +0 -253
  252. package/src/index.ts +0 -17
  253. package/src/lanes/agy.ts +0 -95
  254. package/src/lanes/approval.ts +0 -24
  255. package/src/lanes/claude.ts +0 -129
  256. package/src/lanes/codex.ts +0 -127
  257. package/src/lanes/events.ts +0 -130
  258. package/src/lanes/job.ts +0 -142
  259. package/src/lanes/opencode.ts +0 -122
  260. package/src/lanes/process.ts +0 -184
  261. package/src/lanes/progress.ts +0 -183
  262. package/src/lanes/registry.ts +0 -178
  263. package/src/lanes/runner.ts +0 -124
  264. package/src/lanes/types.ts +0 -112
  265. package/src/market/catalogs/mcp-docs.json +0 -111
  266. package/src/market/catalogs/plugins.json +0 -111
  267. package/src/market/catalogs/skills.json +0 -478
  268. package/src/market/clone.ts +0 -72
  269. package/src/market/context-cost.ts +0 -121
  270. package/src/market/digest.ts +0 -106
  271. package/src/market/index.ts +0 -22
  272. package/src/market/install.ts +0 -578
  273. package/src/market/manifest.ts +0 -187
  274. package/src/market/prereq.ts +0 -145
  275. package/src/market/registry.ts +0 -363
  276. package/src/market/resolve.ts +0 -111
  277. package/src/market/types.ts +0 -236
  278. package/src/market/validate.ts +0 -227
  279. package/src/mcp/client.ts +0 -449
  280. package/src/mcp/config.ts +0 -252
  281. package/src/mcp/local-package.ts +0 -211
  282. package/src/mcp/market-catalog.ts +0 -84
  283. package/src/mcp/market-install.ts +0 -289
  284. package/src/mcp/market.ts +0 -362
  285. package/src/mcp/oauth.ts +0 -251
  286. package/src/mcp/prompts-resources.ts +0 -249
  287. package/src/mcp/shared.ts +0 -149
  288. package/src/mcp/status.ts +0 -67
  289. package/src/mcp/tools.ts +0 -275
  290. package/src/mcp/transport.ts +0 -122
  291. package/src/mcp/trust.ts +0 -25
  292. package/src/memory/blocks.ts +0 -278
  293. package/src/memory/recall.ts +0 -355
  294. package/src/memory/scope.ts +0 -182
  295. package/src/memory/store.ts +0 -105
  296. package/src/memory/tools.ts +0 -99
  297. package/src/plugins/cli.ts +0 -119
  298. package/src/plugins/discover.ts +0 -108
  299. package/src/plugins/index.ts +0 -50
  300. package/src/plugins/install.ts +0 -184
  301. package/src/plugins/load.ts +0 -124
  302. package/src/plugins/manifest.ts +0 -92
  303. package/src/plugins/state.ts +0 -83
  304. package/src/providers/auth.ts +0 -408
  305. package/src/providers/cache.ts +0 -223
  306. package/src/providers/catalog-local.ts +0 -160
  307. package/src/providers/catalog.ts +0 -421
  308. package/src/providers/middleware-context.ts +0 -86
  309. package/src/providers/middleware.ts +0 -373
  310. package/src/providers/model-list.ts +0 -23
  311. package/src/providers/oauth/common.ts +0 -105
  312. package/src/providers/oauth/device-code.ts +0 -107
  313. package/src/providers/oauth/github-copilot.ts +0 -146
  314. package/src/providers/oauth/loopback.ts +0 -158
  315. package/src/providers/oauth/openai.ts +0 -163
  316. package/src/providers/oauth/openrouter.ts +0 -89
  317. package/src/providers/oauth/pkce.ts +0 -45
  318. package/src/providers/oauth/registry.ts +0 -39
  319. package/src/providers/oauth/seam.ts +0 -89
  320. package/src/providers/profile-glm53.ts +0 -111
  321. package/src/providers/profile-sonnet5-persona.ts +0 -65
  322. package/src/providers/profile-sonnet5-voice.ts +0 -23
  323. package/src/providers/profiles.ts +0 -156
  324. package/src/providers/provider-config.ts +0 -311
  325. package/src/providers/registry.ts +0 -333
  326. package/src/providers/responses.ts +0 -209
  327. package/src/providers/retry.ts +0 -234
  328. package/src/providers/router.ts +0 -294
  329. package/src/providers/sse.ts +0 -26
  330. package/src/providers/stream-errors.ts +0 -117
  331. package/src/providers/stream.ts +0 -566
  332. package/src/providers/thinking.ts +0 -189
  333. package/src/providers/wire-messages.ts +0 -129
  334. package/src/providers/wire-responses.ts +0 -79
  335. package/src/providers/wire-select.ts +0 -53
  336. package/src/server/http.ts +0 -291
  337. package/src/server/openapi.ts +0 -246
  338. package/src/sextant/card-hits.ts +0 -102
  339. package/src/sextant/card-keys.ts +0 -55
  340. package/src/sextant/context-source.ts +0 -157
  341. package/src/sextant/crew-cards.ts +0 -350
  342. package/src/sextant/draw-agents.ts +0 -273
  343. package/src/sextant/draw-code.ts +0 -388
  344. package/src/sextant/draw-context.ts +0 -222
  345. package/src/sextant/draw-frame.ts +0 -164
  346. package/src/sextant/draw-market.ts +0 -573
  347. package/src/sextant/draw-messages.ts +0 -386
  348. package/src/sextant/draw-pet.ts +0 -230
  349. package/src/sextant/draw-plan.ts +0 -187
  350. package/src/sextant/draw-tabs.ts +0 -85
  351. package/src/sextant/draw-util.ts +0 -65
  352. package/src/sextant/draw-wizard.ts +0 -378
  353. package/src/sextant/engine.ts +0 -230
  354. package/src/sextant/frame-hits.ts +0 -25
  355. package/src/sextant/frame.ts +0 -101
  356. package/src/sextant/git-status.ts +0 -197
  357. package/src/sextant/grid.ts +0 -59
  358. package/src/sextant/input.ts +0 -119
  359. package/src/sextant/keys.ts +0 -521
  360. package/src/sextant/layout.ts +0 -86
  361. package/src/sextant/local-commands.ts +0 -169
  362. package/src/sextant/market-source.ts +0 -287
  363. package/src/sextant/mentions.ts +0 -200
  364. package/src/sextant/message-hits.ts +0 -26
  365. package/src/sextant/model.ts +0 -387
  366. package/src/sextant/overlays.ts +0 -456
  367. package/src/sextant/panel-hits.ts +0 -38
  368. package/src/sextant/pet.ts +0 -399
  369. package/src/sextant/screen.ts +0 -324
  370. package/src/sextant/scroll-hits.ts +0 -66
  371. package/src/sextant/scrollbar.ts +0 -82
  372. package/src/sextant/sextant-bridge.ts +0 -174
  373. package/src/sextant/sextant-cards.ts +0 -142
  374. package/src/sextant/sextant-diff-base.ts +0 -63
  375. package/src/sextant/sextant-files.ts +0 -154
  376. package/src/sextant/sextant-frame-loop.ts +0 -335
  377. package/src/sextant/sextant-renderer.ts +0 -574
  378. package/src/sextant/sextant-repo.ts +0 -140
  379. package/src/sextant/theme.ts +0 -66
  380. package/src/sextant/tool-rows.ts +0 -189
  381. package/src/sextant/types.ts +0 -493
  382. package/src/skills/index.ts +0 -387
  383. package/src/skills/pack.ts +0 -220
  384. package/src/skills/spec.ts +0 -162
  385. package/src/skills/tools.ts +0 -69
  386. package/src/skills/versioned.ts +0 -227
  387. package/src/telemetry/otel-export.ts +0 -122
  388. package/src/telemetry/otel-lanes.ts +0 -89
  389. package/src/telemetry/otel-logs.ts +0 -131
  390. package/src/telemetry/otel-metrics.ts +0 -136
  391. package/src/telemetry/otel.ts +0 -397
  392. package/src/telemetry/otlp.ts +0 -76
  393. package/src/tools/ask-user.ts +0 -156
  394. package/src/tools/bash-bg.ts +0 -94
  395. package/src/tools/bash-jobs.ts +0 -237
  396. package/src/tools/design.ts +0 -151
  397. package/src/tools/evalcell.ts +0 -338
  398. package/src/tools/html-text.ts +0 -139
  399. package/src/tools/provider.ts +0 -149
  400. package/src/tools/task.ts +0 -250
  401. package/src/tools/todo.ts +0 -320
  402. package/src/tools/webfetch.ts +0 -332
  403. package/src/tools/websearch.ts +0 -359
  404. package/src/tui/agents-cmd.ts +0 -41
  405. package/src/tui/app.ts +0 -749
  406. package/src/tui/attach.ts +0 -127
  407. package/src/tui/boot-notes.ts +0 -41
  408. package/src/tui/builtin-prompts.ts +0 -59
  409. package/src/tui/checkpoints-cmd.ts +0 -70
  410. package/src/tui/clipboard-image.ts +0 -81
  411. package/src/tui/clipboard.ts +0 -78
  412. package/src/tui/commands.ts +0 -283
  413. package/src/tui/config-view.ts +0 -53
  414. package/src/tui/context-cmds.ts +0 -282
  415. package/src/tui/cost.ts +0 -108
  416. package/src/tui/crash-guard.ts +0 -173
  417. package/src/tui/focus-terminal.ts +0 -34
  418. package/src/tui/git-cmds.ts +0 -273
  419. package/src/tui/git-plain.ts +0 -58
  420. package/src/tui/info-cmd.ts +0 -150
  421. package/src/tui/input-plain.ts +0 -76
  422. package/src/tui/mcp-cmd.ts +0 -128
  423. package/src/tui/memory-note.ts +0 -77
  424. package/src/tui/modes-cmd.ts +0 -45
  425. package/src/tui/notify-seq.ts +0 -100
  426. package/src/tui/notify.ts +0 -318
  427. package/src/tui/overlays.ts +0 -97
  428. package/src/tui/pi-renderer.ts +0 -428
  429. package/src/tui/providers-cmd.ts +0 -377
  430. package/src/tui/reasoning-view.ts +0 -56
  431. package/src/tui/renderer.ts +0 -128
  432. package/src/tui/replay-marker.ts +0 -29
  433. package/src/tui/session-cmd.ts +0 -148
  434. package/src/tui/session-manage.ts +0 -95
  435. package/src/tui/sextant-attach.ts +0 -102
  436. package/src/tui/sextant-io.ts +0 -202
  437. package/src/tui/sextant-smoke.ts +0 -110
  438. package/src/tui/shell-cmd.ts +0 -158
  439. package/src/tui/smoke.ts +0 -72
  440. package/src/tui/staged-terminal.ts +0 -50
  441. package/src/tui/startup.ts +0 -12
  442. package/src/tui/theme.ts +0 -59
  443. package/src/tui/todo-label.ts +0 -7
  444. package/src/tui/trust-card.ts +0 -107
  445. package/src/tui/tui-commands.ts +0 -87
  446. package/tsconfig.json +0 -30
  447. package/vendor/pi-tui/LICENSE +0 -21
  448. package/vendor/pi-tui/PATCHES.md +0 -12
  449. package/vendor/pi-tui/PROVENANCE.md +0 -12
  450. package/vendor/pi-tui/README.upstream.md +0 -854
  451. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  452. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  453. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  454. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  455. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  456. package/vendor/pi-tui/src/components/box.ts +0 -138
  457. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  458. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  459. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  460. package/vendor/pi-tui/src/components/image.ts +0 -128
  461. package/vendor/pi-tui/src/components/input.ts +0 -448
  462. package/vendor/pi-tui/src/components/loader.ts +0 -93
  463. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  464. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  465. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  466. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  467. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  468. package/vendor/pi-tui/src/components/stack.ts +0 -155
  469. package/vendor/pi-tui/src/components/text.ts +0 -108
  470. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  471. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  472. package/vendor/pi-tui/src/editor-component.ts +0 -75
  473. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  474. package/vendor/pi-tui/src/index.ts +0 -149
  475. package/vendor/pi-tui/src/keybindings.ts +0 -321
  476. package/vendor/pi-tui/src/keys.ts +0 -1402
  477. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  478. package/vendor/pi-tui/src/latex.ts +0 -1381
  479. package/vendor/pi-tui/src/layout-node.ts +0 -52
  480. package/vendor/pi-tui/src/layout.ts +0 -411
  481. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  482. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  483. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  484. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  485. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  486. package/vendor/pi-tui/src/terminal.ts +0 -554
  487. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  488. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  489. package/vendor/pi-tui/src/tui.ts +0 -1264
  490. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  491. package/vendor/pi-tui/src/utils.ts +0 -1327
  492. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  493. package/vendor/pi-tui/test/test-themes.ts +0 -39
  494. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  495. /package/{src/providers → dist/cli}/models-index.json +0 -0
@@ -1,55 +0,0 @@
1
- /** Sextant card keys (port #43): the key route of the ONE modal card — ←→↑↓ (and Tab) move the
2
- * selection, Enter resolves it (approval: once / always / deny; question: an option, the free-text
3
- * row or skip), Esc dismisses (deny / null) and the free-text row takes typing and Backspace.
4
- * Ported from the user's own sextant v0.4.0 prototype app.js:1503-1510 and :1434; split out of
5
- * keys.ts for the line budget. Pure state mutation, no clock: the card leaves the state before
6
- * its promise settles, so a re-entrant hook never sees a stale card. */
7
-
8
- import type { CardState, KeyEvent, SextantState } from "./types.ts";
9
-
10
- /** false = not a card key: it falls through to the prompt (typing a follow-up while a card waits) */
11
- export function onCardKey(s: SextantState, c: CardState, ev: KeyEvent): boolean {
12
- const { name } = ev;
13
- const n = c.kind === "approval" ? c.verdicts.length // allow · always · [all edits] · deny
14
- : (c.prompt.options?.length ?? 0) + (c.prompt.allowFreeText !== false ? 1 : 0) + 1; // options · free text · skip
15
- if (name === "left" || name === "up") return move(c, n, -1);
16
- if (name === "right" || name === "down" || name === "tab") return move(c, n, 1);
17
- if (name === "escape") { dismissCard(s); return true; }
18
- if (c.kind === "approval") {
19
- if (name !== "enter") return false;
20
- s.card = null;
21
- c.resolve(c.verdicts[c.selected] ?? "deny");
22
- return true;
23
- }
24
- const opts = c.prompt.options?.length ?? 0, freeIdx = c.prompt.allowFreeText !== false ? opts : -1;
25
- if (name === "enter") {
26
- if (c.selected === n - 1) { dismissCard(s); return true; } // skip
27
- if (c.selected !== freeIdx) { s.card = null; c.resolve({ kind: "option", index: c.selected }); return true; }
28
- const t = c.freeText.trim();
29
- if (t) { s.card = null; c.resolve({ kind: "text", text: t }); }
30
- return true; // an empty free-text row is not an answer yet
31
- }
32
- if (c.selected !== freeIdx) return false;
33
- if (name === "backspace") { // by code point: 😀 is one glyph, two UTF-16 units
34
- c.freeText = [...c.freeText].slice(0, -1).join("");
35
- return true;
36
- }
37
- const ch = name === "space" ? " " : ev.ch;
38
- if (!ch || ev.alt) return false;
39
- c.freeText += ch;
40
- return true;
41
- }
42
-
43
- /** wrap the selection over the card's n rows */
44
- function move(c: CardState, n: number, d: -1 | 1): true {
45
- const v = (c.selected + d + n) % n;
46
- c.selected = v;
47
- return true;
48
- }
49
-
50
- /** approval → deny, question → null; the card leaves the state before the promise settles */
51
- export function dismissCard(s: SextantState): void {
52
- const c = s.card;
53
- s.card = null;
54
- if (c?.kind === "approval") c.resolve("deny"); else c?.resolve(null);
55
- }
@@ -1,157 +0,0 @@
1
- /** The seam between the context overlay and core/context-report.ts.
2
- *
3
- * draw-context.ts is pure over `ContextState` and never counts anything. This file is the only place that
4
- * knows the report module exists: it lazily imports it (the boot rule — nothing in that dependency tree is
5
- * loaded until someone opens /context), asks the LIVE runtime for the two rows a transcript cannot know,
6
- * and maps the report onto the overlay's flat view.
7
- *
8
- * The live runtime is the whole reason this overlay is worth having. `rovecode context` on a shell has to
9
- * BUILD a runtime to learn the system prompt and the tool schemas, and in a fresh session those two are
10
- * most of the window; here they are already in memory, so the number is complete without constructing
11
- * anything. What is still missing is MCP tools — their schemas do not exist until a server is connected —
12
- * and the panel says so on its own line rather than letting a complete-looking total imply otherwise.
13
- *
14
- * Two numbers travel, never one. `raw` is what o200k counted; `estimated` is that corrected towards the
15
- * model's own tokenizer. Presenting only the second would be presenting a corrected figure as a
16
- * measurement, and someone comparing this panel against a provider's dashboard needs to know which is
17
- * which. `scale.note` says where the factor came from, including when nobody has measured this model.
18
- *
19
- * Nothing here throws. A runtime that cannot answer, a model the catalog does not know, an empty
20
- * transcript — each is a state the overlay draws, because a panel that reports on the session must not be
21
- * the thing that ends it. */
22
-
23
- import type { ContextState } from "./draw-context.ts";
24
-
25
- /** What the live runtime can tell us that the transcript cannot. Both optional: a session whose runtime
26
- * is mid-rebuild still opens the panel, and `live: false` makes the total read as a floor. */
27
- export interface ContextFixed {
28
- /** the system prompt a real turn would send — buildDef's, not the base alone */
29
- system?: string;
30
- /** rovecode's own tool schemas, serialized. MCP tools are deliberately absent. */
31
- toolSchemas?: string;
32
- }
33
-
34
- /** the runtime shape this file needs, structurally — declared here so the overlay never imports the
35
- * runtime's types and so a test can hand in three lines instead of a process */
36
- export interface LiveRuntime {
37
- registry: { list(): { schema: unknown }[] };
38
- // method syntax, and `unknown` for the prompt: the real AgentDefinition types `systemPrompt` as a string
39
- // or a function over its own AgentVars, and pinning either shape here would make this file depend on the
40
- // runtime's types — which is exactly what the overlay must not do. It is narrowed where it is read.
41
- buildDef(ref: { provider: string; model: string; effort: "auto" }): { systemPrompt: unknown };
42
- /** optional: the market overlay uses it after installing an MCP server (types.ts SextantAttach) */
43
- reloadMcp?(): Promise<{ added: string[]; removed: string[]; failed: { name: string; error: string }[]; skipped: string[] }>;
44
- }
45
-
46
- /** Pull the two fixed rows out of a runtime that is ALREADY running.
47
- *
48
- * Deliberately not `createRuntime`: the CLI builds one because it has none, and paid for that decision
49
- * with a session directory it had to pass in to avoid creating a stray empty session. Inside the TUI the
50
- * runtime is the one the next turn will use, so this is a read, not a construction — and it cannot leave
51
- * anything behind.
52
- *
53
- * `buildDef`, not `systemPrompt()`: the prompt a run actually sends is the base plus the model profile,
54
- * the design section, and — for a model without native tool calling — the tool block. Asking for the base
55
- * alone under-counts the largest fixed row by everything that makes it large. */
56
- export function fixedFrom(rt: LiveRuntime | null | undefined, ref: { provider: string; model: string }): ContextFixed {
57
- if (!rt) return {};
58
- try {
59
- const schemas = rt.registry.list().map((t) => t.schema);
60
- const def = rt.buildDef({ ...ref, effort: "auto" });
61
- const sp = def.systemPrompt;
62
- const system = typeof sp === "string" ? sp : typeof sp === "function" ? String((sp as (x: Record<string, unknown>) => unknown)({})) : undefined;
63
- if (system === undefined) return {};
64
- return { system, toolSchemas: JSON.stringify(schemas) };
65
- } catch {
66
- // a runtime that cannot describe itself is a panel that says so, not a crashed frame
67
- return {};
68
- }
69
- }
70
-
71
- /** the report module's shape, structurally: this file must compile and be testable without importing it */
72
- interface Slice { label: string; tokens: number; share: number; note?: string }
73
- interface Drift { estimated: number; reported: number; delta: number; fraction: number; beyondTolerance: boolean }
74
- interface Report {
75
- model: { provider: string; model: string };
76
- window?: number;
77
- estimated: number;
78
- corrected: number;
79
- scale: { factor: number; measured: boolean; note: string };
80
- slices: Slice[];
81
- remaining?: number;
82
- fraction?: number;
83
- nearLimit?: boolean;
84
- drift?: Drift;
85
- totals: { inputTokens?: number; outputTokens?: number; cacheReadTokens?: number; cacheWriteTokens?: number };
86
- costUsd?: number;
87
- unpricedTurns: number;
88
- images: number;
89
- }
90
-
91
- export interface ContextLoadInput {
92
- messages: readonly unknown[];
93
- current: { provider: string; model: string };
94
- /** window + pricing, however the caller has them */
95
- lookup: (r: { provider: string; model: string }) => unknown;
96
- fixed: ContextFixed;
97
- /** the tolerance drift is judged against; printed by the panel, never assumed by a reader */
98
- tolerance?: number;
99
- /** tests inject the report function; production lazily imports the real one */
100
- report?: (input: unknown) => Report;
101
- }
102
-
103
- /** the fraction past which drift is called out rather than merely shown. Matches core/context-report.ts;
104
- * it travels in the state so the panel can print it instead of asserting a number the reader cannot see. */
105
- const TOLERANCE = 0.05;
106
-
107
- /** Build the overlay's state. Never throws: every failure becomes something the panel can draw. */
108
- export async function loadContext(input: ContextLoadInput): Promise<Omit<ContextState, "scroll">> {
109
- const tolerance = input.tolerance ?? TOLERANCE;
110
- const model = `${input.current.provider}/${input.current.model}`;
111
-
112
- let report: Report;
113
- try {
114
- const fn = input.report ?? (await import("../core/context-report.ts")).contextReport as unknown as (i: unknown) => Report;
115
- report = fn({
116
- messages: input.messages,
117
- current: input.current,
118
- lookup: input.lookup,
119
- ...(input.fixed.system !== undefined ? { system: input.fixed.system } : {}),
120
- ...(input.fixed.toolSchemas !== undefined ? { toolSchemas: input.fixed.toolSchemas } : {}),
121
- });
122
- } catch {
123
- // the panel opens and says it has nothing, which is more useful than a frame that died counting
124
- return {
125
- model, raw: 0, estimated: 0, scale: { factor: 1, measured: false, note: "the context report could not be built" },
126
- slices: [], images: 0, billed: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
127
- unpricedTurns: 0, live: false, tolerance,
128
- };
129
- }
130
-
131
- const t = report.totals;
132
- return {
133
- model,
134
- ...(report.window !== undefined ? { window: report.window } : {}),
135
- // `estimated` on the panel is the CORRECTED number, because that is what the window and the bill are
136
- // computed from; `raw` carries what o200k counted so the panel can show both
137
- raw: report.estimated,
138
- estimated: report.corrected,
139
- scale: report.scale,
140
- ...(report.remaining !== undefined ? { remaining: report.remaining } : {}),
141
- ...(report.fraction !== undefined ? { fraction: report.fraction } : {}),
142
- ...(report.nearLimit !== undefined ? { nearLimit: report.nearLimit } : {}),
143
- slices: report.slices.map((s) => ({ label: s.label, tokens: s.tokens, share: s.share, ...(s.note ? { note: s.note } : {}) })),
144
- images: report.images,
145
- ...(report.drift ? { drift: { ...report.drift } } : {}),
146
- billed: {
147
- input: t.inputTokens ?? 0, output: t.outputTokens ?? 0,
148
- cacheRead: t.cacheReadTokens ?? 0, cacheWrite: t.cacheWriteTokens ?? 0,
149
- },
150
- ...(report.costUsd !== undefined ? { costUsd: report.costUsd } : {}),
151
- unpricedTurns: report.unpricedTurns,
152
- // "live" is about the two rows a transcript cannot know. The system prompt is the one that matters:
153
- // tool schemas can legitimately be an empty list, so their absence proves nothing.
154
- live: input.fixed.system !== undefined,
155
- tolerance,
156
- };
157
- }
@@ -1,350 +0,0 @@
1
- /** The CREW CARD (Berkay's pick, 2026-09-07): the plan panel's crew section as titled cards — one card per
2
- * WORKFLOW rather than one row per task, with a chip per agent showing which CLI opened.
3
- *
4
- * crew 3 working
5
- * test-project-scan ›
6
- * 3 agents · 01s
7
- * ▪▪▫ codex claude codex
8
- *
9
- * WHAT A WORKFLOW IS HERE. rovecode has no workflow concept and this file does not invent one: `s.crew` is a flat
10
- * TaskInfo[], and the only grouping that exists in the data is "tasks started under the same run" — TaskManager
11
- * stamps `batch` / `batchLabel` from bindRun (core/tasks.ts, nimbus-5f's slice), which every surface already calls
12
- * once per run. No heuristic: no time buckets, no label-prefix matching. A task with no batch (started outside a
13
- * bound run) gets its own single-task card titled by its own label, which is exactly what the flat list showed.
14
- *
15
- * THE CHIP RULE — a chip must never claim a CLI ran when it did not:
16
- * - queued is a HOLLOW chip and a dim name; only running/done chips are filled. "codex is queued" and "codex is
17
- * working" cannot look the same, because the difference is whether a process exists.
18
- * - only an EXTERNAL lane (TaskInfo.kind "external") shows a CLI name, from its `lane` adapter id. One of our own
19
- * subagents shows its AGENT name; if such a task were ever named after an adapter (the ids are reserved in
20
- * tasks.ts, so this is a defence rather than a case) it renders as `agent:<name>` and never as a bare CLI name.
21
- *
22
- * WHAT GOES FIRST WHEN IT DOES NOT FIT (the panel is 32 cells; stated rather than discovered by clipping):
23
- * 1. the blank row between cards — spacing carries no information;
24
- * 2. the names row collapses: repeats become counts (`codex ×2`), then a `+N` tail. Whole names are dropped, never
25
- * clipped mid-word — half a CLI's name is a different CLI's name;
26
- * 3. the title is truncated with an ellipsis, at a word boundary when there is one;
27
- * 4. the chips cap at what fits and the rest become `+N`;
28
- * 5. whole cards go, newest kept, with a `+N more` footer.
29
- * NEVER dropped: the agent count and the clock. A card that cannot show those two is not drawn at all — a title
30
- * alone would say a workflow exists without saying whether anything is running.
31
- *
32
- * PURE: `now` is a parameter (the clock and the card's age), no timers, no process access, no state writes. The
33
- * painter at the bottom is the only part that touches a screen. */
34
-
35
- import type { TaskInfo } from "../core/tasks.ts";
36
- import { isAdapterId } from "../lanes/types.ts";
37
- import { laneElapsed } from "./draw-agents.ts";
38
- import { fmtK } from "./model.ts";
39
- import { st } from "./theme.ts";
40
- import { ATTR, type ScreenLike, type Seg, type Theme } from "./types.ts";
41
-
42
- /** TaskInfo as the card reads it. `batch` / `batchLabel` / `progress` / `files` are all on TaskInfo now (core/tasks.ts);
43
- * the alias stays as this module's own name for what it consumes. */
44
- export type CrewTask = TaskInfo;
45
-
46
- export type CardTone = "fg" | "fg2" | "muted" | "dim" | "ok" | "err" | "accent" | "warn";
47
- export interface CardSpan { text: string; tone: CardTone; bold?: boolean }
48
- /** one painted row; `right` is anchored to the card's right edge (the `›` affordance) */
49
- export interface CardLine { spans: CardSpan[]; right?: CardSpan }
50
-
51
- export interface CrewGroup {
52
- /** the batch id, or `task:<id>` for a task that has none */
53
- key: string;
54
- label: string;
55
- tasks: CrewTask[];
56
- /** min(startedAt ?? createdAt) over the group */
57
- startedAt: number;
58
- /** max(finishedAt) when EVERY task has finished; undefined while any is live (the clock still runs) */
59
- finishedAt?: number;
60
- working: number;
61
- }
62
-
63
- const oneLine = (s: string): string => s.replace(/\s+/g, " ").trim();
64
- const cps = (s: string): string[] => [...s];
65
- const width = (s: string): number => cps(s).length;
66
-
67
- // ------------------------------------------------------------------ grouping
68
-
69
- /** Group by `batch`, first-seen order kept (the crew list is already in start order). A task without a batch is its
70
- * own group. The label is the batch label when the surface set one, else the first task's label — never invented. */
71
- export function groupCrew(crew: readonly CrewTask[]): CrewGroup[] {
72
- const out: CrewGroup[] = [];
73
- const byKey = new Map<string, CrewGroup>();
74
- for (const t of crew) {
75
- const key = t.batch ?? `task:${t.id}`;
76
- let g = byKey.get(key);
77
- if (g === undefined) {
78
- g = { key, label: oneLine(t.batchLabel ?? t.label) || "(no label)", tasks: [], startedAt: t.startedAt ?? t.createdAt, working: 0 };
79
- byKey.set(key, g);
80
- out.push(g);
81
- }
82
- g.tasks.push(t);
83
- g.startedAt = Math.min(g.startedAt, t.startedAt ?? t.createdAt);
84
- }
85
- for (const g of out) {
86
- g.working = g.tasks.filter((t) => t.status === "queued" || t.status === "running").length;
87
- const ends = g.tasks.map((t) => t.finishedAt);
88
- if (ends.every((e): e is number => e !== undefined)) g.finishedAt = Math.max(...ends);
89
- }
90
- return out;
91
- }
92
-
93
- /** the card's age: the WHOLE workflow's span, live until every task in it has finished */
94
- export function groupElapsed(g: CrewGroup, now: number): number {
95
- if (g.finishedAt !== undefined) return Math.max(0, g.finishedAt - g.startedAt);
96
- return Math.max(0, now - g.startedAt, ...g.tasks.map((t) => laneElapsed(t, now)));
97
- }
98
-
99
- /** `01s` · `04m` · `1h02m` — the compact age from the card Berkay picked; mm:ss (laneClock) is the per-task form */
100
- export function compactAge(ms: number): string {
101
- const s = Math.max(0, Math.floor(ms / 1000));
102
- if (s < 60) return `${String(s).padStart(2, "0")}s`;
103
- const m = Math.floor(s / 60);
104
- if (m < 60) return `${String(m).padStart(2, "0")}m`;
105
- return `${Math.floor(m / 60)}h${String(m % 60).padStart(2, "0")}m`;
106
- }
107
-
108
- // ------------------------------------------------------------------ chips
109
-
110
- /** ▫ queued (nothing has run) · ▪ running · ◆ done · × failed · · cancelled */
111
- export function chipGlyph(status: TaskInfo["status"]): string {
112
- switch (status) {
113
- case "queued": return "▫";
114
- case "running": return "▪";
115
- case "done": return "◆";
116
- case "failed": return "×";
117
- default: return "·";
118
- }
119
- }
120
- export function chipTone(status: TaskInfo["status"]): CardTone {
121
- switch (status) {
122
- case "queued": return "dim";
123
- case "running": return "accent";
124
- case "done": return "ok";
125
- case "failed": return "err";
126
- default: return "muted";
127
- }
128
- }
129
-
130
- /** the name under a chip: a CLI id ONLY for an external lane; our own agents show their agent name. An external
131
- * lane with no adapter id recorded says `cli?` rather than borrowing a name we do not have. */
132
- export function chipName(t: CrewTask): string {
133
- if (t.kind === "external") return t.lane ?? "cli?";
134
- return isAdapterId(t.agent) ? `agent:${t.agent}` : t.agent;
135
- }
136
-
137
- /** the chip row's glyphs, one per task in order; `+N` when more tasks than fit in `w` cells */
138
- export function chipRow(tasks: readonly CrewTask[], w: number): CardSpan[] {
139
- if (w <= 0 || tasks.length === 0) return [];
140
- const spans: CardSpan[] = [];
141
- let used = 0;
142
- for (let i = 0; i < tasks.length; i++) {
143
- const rest = tasks.length - i;
144
- const tail = rest > 1 ? `+${rest}` : "";
145
- if (used + 1 + width(tail) > w && i > 0) { spans.push({ text: `+${rest}`, tone: "dim" }); return spans; }
146
- if (used + 1 > w) return spans;
147
- const t = tasks[i]!;
148
- spans.push({ text: chipGlyph(t.status), tone: chipTone(t.status), bold: t.status === "running" });
149
- used += 1;
150
- }
151
- return spans;
152
- }
153
-
154
- /** The names, collapsed to fit: `codex claude codex` → `codex ×2 claude` when repeats cost less, then a `+N` tail.
155
- * Whole names only — a clipped name is a lie about which CLI ran. Empty when nothing fits. */
156
- export function nameRow(tasks: readonly CrewTask[], w: number): CardSpan[] {
157
- if (w <= 0 || tasks.length === 0) return [];
158
- const runs: { name: string; count: number; tone: CardTone }[] = [];
159
- for (const t of tasks) {
160
- const name = chipName(t), tone = chipTone(t.status);
161
- const last = runs[runs.length - 1];
162
- if (last !== undefined && last.name === name && last.tone === tone) last.count++;
163
- else runs.push({ name, count: 1, tone });
164
- }
165
- const label = (r: { name: string; count: number }): string => (r.count > 1 ? `${r.name} ×${r.count}` : r.name);
166
- const spans: CardSpan[] = [];
167
- let used = 0;
168
- for (let i = 0; i < runs.length; i++) {
169
- const r = runs[i]!;
170
- const text = label(r);
171
- // the tail counts the AGENTS still unnamed, not the runs: "+2" when three agents are hidden would be a wrong number
172
- const left = runs.slice(i).reduce((n, x) => n + x.count, 0);
173
- const tail = ` +${left}`;
174
- const sep = spans.length > 0 ? 1 : 0;
175
- const more = i < runs.length - 1 ? width(` +${left - r.count}`) : 0;
176
- if (used + sep + width(text) + more > w) {
177
- if (spans.length > 0 && used + width(tail) <= w) spans.push({ text: tail, tone: "dim" });
178
- return spans;
179
- }
180
- if (sep) { spans.push({ text: " ", tone: "dim" }); used += 1; }
181
- spans.push({ text, tone: r.tone });
182
- used += width(text);
183
- }
184
- return spans;
185
- }
186
-
187
- // ------------------------------------------------------------------ card rows
188
-
189
- /** ellipsis truncation at a word boundary when there is one in the last third of the space */
190
- export function fitTitle(title: string, w: number): string {
191
- const c = cps(oneLine(title));
192
- if (w <= 0) return "";
193
- if (c.length <= w) return c.join("");
194
- if (w === 1) return "…";
195
- const head = c.slice(0, w - 1).join("");
196
- const cut = head.lastIndexOf(" ");
197
- return (cut >= Math.floor((w - 1) * 0.67) ? head.slice(0, cut) : head) + "…";
198
- }
199
-
200
- /** the card: title (+ `›`), `N agents · age`, then the chips and the names on one row. The meta row is the
201
- * honesty core — it is never dropped, so a card is only produced when `w` can hold it. */
202
- export function cardLines(g: CrewGroup, w: number, now: number): CardLine[] {
203
- const count = `${g.tasks.length} agent${g.tasks.length === 1 ? "" : "s"}`;
204
- const meta = `${count} · ${compactAge(groupElapsed(g, now))}`;
205
- if (w < width(meta)) return [];
206
- const lines: CardLine[] = [];
207
- const arrow = w >= width(meta) + 2 ? { text: "›", tone: "dim" as CardTone } : undefined;
208
- lines.push({ spans: [{ text: fitTitle(g.label, w - (arrow ? 2 : 0)), tone: g.working > 0 ? "fg" : "fg2", bold: g.working > 0 }], ...(arrow ? { right: arrow } : {}) });
209
- lines.push({ spans: [{ text: meta, tone: "dim" }] });
210
- const chips = chipRow(g.tasks, Math.max(0, Math.min(g.tasks.length + 2, Math.floor(w / 2))));
211
- const chipW = chips.reduce((n, s) => n + width(s.text), 0);
212
- const names = nameRow(g.tasks, w - chipW - 2);
213
- if (chips.length > 0) lines.push({ spans: names.length > 0 ? [...chips, { text: " ", tone: "dim" }, ...names] : chips });
214
- const progress = progressRow(g, w);
215
- if (progress.length > 0) lines.push({ spans: progress });
216
- return lines;
217
- }
218
-
219
- /** THE PROGRESS ROW — `wrote 4 files · 12 calls · 4.2k`, summed over a workflow's tasks, and it is the second thing
220
- * dropped at a narrow width (after the blank separator): the chips and the CLI names are what the card exists for.
221
- * Four rules, all of them about not overstating what a CLI did (lanes/progress.ts, nimbus-24's measurements):
222
- * - a RUNNING lane with nothing confirmed shows no file segment at all. `filesWritten` is what the CLI has
223
- * confirmed so far, and one of the four (agy) confirms nothing until it ends — it sits at zero for minutes and
224
- * then jumps to the measured count. "wrote 0 files" for a lane that is writing would be a wrong statement, and
225
- * treating that zero as a stall would be wrong about exactly one CLI.
226
- * - a FINISHED task's list is the worktree diff, so there zero is a measurement and is worth printing.
227
- * - a task whose patch never reached the tree did not WRITE anything the person has: its count is reported as
228
- * `discarded` / `so far`, never as `wrote`. The signal is `progress.applied` (tri-state, written by the code
229
- * that does the applying): absent = nothing offered to the tree yet, true = merged back, false = the writes
230
- * stayed in a worktree that was deleted. NOT `patchLines`, and not the status either: a lane that finishes
231
- * cleanly whose patch git refuses — a concurrent task touched the same lines — still reports ok AND gets a
232
- * patchLines, so both of those would print `wrote 4 files` about a tree that has none of them (nimbus-24's
233
- * lanes-job tests cover the case). One of OUR isolated children has no progress object, and orchestrator.ts
234
- * has the same hole — so the signal there is `files`, which tasks.ts sets only for a patch that applied
235
- * (5f gated it on progress.applied, else the runner's own "patch-apply-failed" marker). `patchLines` is a
236
- * SIZE and never a verdict; the one thing it still settles is the empty patch, where 0 lines means there was
237
- * nothing to apply and nothing that could fail.
238
- * - `usage` ABSENT is not zero. A lane we could not read reports nothing; a lane that burned nothing reports
239
- * zeros. Absent contributes no token segment; explicit zeros show `0`.
240
- * `calls` counts every tool the CLI reported, reads included, so the word stays `calls`. Only lanes report them,
241
- * so a mixed workflow's row says what its lanes did without implying the native agents did nothing. */
242
- /** Did this task's work reach the person's tree? `true` landed · `false` written and thrown away · `undefined`
243
- * nothing offered yet. A lane answers from `progress.applied` (the code that applies, not the code beside it); one
244
- * of our own children answers from `files`, which exists only for a patch that applied — except for the empty
245
- * patch, where `patchLines === 0` means there was nothing to apply, and that counts as landed. */
246
- export function landedOf(t: CrewTask): boolean | undefined {
247
- if (t.progress !== undefined && "applied" in t.progress) return t.progress.applied;
248
- if (t.status === "running" || t.status === "queued") return undefined;
249
- if (t.files !== undefined) return true;
250
- return t.status === "done" && t.patchLines === 0;
251
- }
252
-
253
- export function progressRow(g: CrewGroup, w: number): CardSpan[] {
254
- let calls = 0, applied = 0, pending = 0, discarded = 0, tokens = 0, sawUsage = false;
255
- for (const t of g.tasks) {
256
- calls += t.progress?.toolCalls ?? 0;
257
- const n = t.files?.length ?? t.progress?.filesWrittenTotal ?? 0;
258
- const landed = landedOf(t);
259
- if (landed === true) applied += n;
260
- else if (landed === undefined) pending += n;
261
- else discarded += n;
262
- const u = t.progress?.usage ?? t.usage;
263
- if (u !== undefined) { sawUsage = true; tokens += u.input + u.output; }
264
- }
265
- const parts: { text: string; tone: CardTone }[] = [];
266
- if (applied > 0) parts.push({ text: `wrote ${applied} file${applied === 1 ? "" : "s"}`, tone: "ok" });
267
- if (pending > 0) parts.push({ text: `${pending} file${pending === 1 ? "" : "s"} so far`, tone: "dim" });
268
- if (discarded > 0) parts.push({ text: `${discarded} discarded`, tone: "muted" });
269
- // every task settled and nothing landed: that zero IS the measurement, and saying so beats an empty row
270
- const merged = g.tasks.some((t) => landedOf(t) === true);
271
- if (parts.length === 0 && g.working === 0 && merged) parts.push({ text: "wrote 0 files", tone: "dim" });
272
- if (calls > 0) parts.push({ text: `${calls} call${calls === 1 ? "" : "s"}`, tone: "dim" });
273
- if (sawUsage) parts.push({ text: fmtK(tokens), tone: "dim" });
274
- if (parts.length === 0) return [];
275
- const spans: CardSpan[] = [];
276
- let used = 0;
277
- for (const part of parts) {
278
- const sep = spans.length > 0 ? 3 : 0; // " · "
279
- if (used + sep + width(part.text) > w) break;
280
- if (sep) { spans.push({ text: " · ", tone: "dim" }); used += 3; }
281
- spans.push(part);
282
- used += width(part.text);
283
- }
284
- return spans;
285
- }
286
-
287
- export interface CrewCardBlock {
288
- lines: CardLine[];
289
- /** cards that did not fit — the `+N more` footer is already the last line when this is > 0 */
290
- hidden: number;
291
- }
292
-
293
- /** The card order: WORKING workflows first, newest of them at the top, then the settled ones newest first. The
294
- * section's header says "2 working"; a panel that then shows two finished cards and hides the running one is
295
- * answering a different question from the one it just asked. Within each half the newest card is first because
296
- * the crew list is start-ordered, so its tail is the live work. */
297
- export function crewCardOrder(groups: readonly CrewGroup[]): CrewGroup[] {
298
- const newestFirst = [...groups].reverse();
299
- return [...newestFirst.filter((g) => g.working > 0), ...newestFirst.filter((g) => g.working === 0)];
300
- }
301
-
302
- /** Pack the cards into `rows` rows in crewCardOrder. Blank separators are dropped before any card is. */
303
- export function crewCardBlock(groups: readonly CrewGroup[], w: number, rows: number, now: number): CrewCardBlock {
304
- if (rows <= 0 || w <= 0 || groups.length === 0) return { lines: [], hidden: groups.length };
305
- const order = crewCardOrder(groups);
306
- const cards = order.map((g) => cardLines(g, w, now)).filter((c) => c.length > 0);
307
- const pack = (gap: boolean): CrewCardBlock & { shown: number } => {
308
- const lines: CardLine[] = [];
309
- let used = 0, shown = 0;
310
- for (const card of cards) {
311
- const need = card.length + (gap && shown > 0 ? 1 : 0);
312
- const footer = cards.length - shown - 1 > 0 ? 1 : 0;
313
- if (used + need + footer > rows) break;
314
- if (gap && shown > 0) { lines.push({ spans: [] }); used++; }
315
- lines.push(...card);
316
- used += card.length;
317
- shown++;
318
- }
319
- const hidden = groups.length - shown;
320
- if (hidden > 0 && shown > 0 && used < rows) lines.push({ spans: [{ text: `+${hidden} more`, tone: "dim" }] });
321
- return { lines: shown > 0 ? lines : [], hidden: shown > 0 ? hidden : groups.length, shown };
322
- };
323
- // separators are spacing; a card is information. Take the spaced packing only when it costs no card.
324
- const spaced = pack(true), dense = pack(false);
325
- return dense.shown > spaced.shown ? { lines: dense.lines, hidden: dense.hidden } : { lines: spaced.lines, hidden: spaced.hidden };
326
- }
327
-
328
- /** rows a full render of these groups would take (cards + separators), for a panel deciding its budget */
329
- export function crewCardHeight(groups: readonly CrewGroup[], w: number, now: number): number {
330
- const cards = groups.map((g) => cardLines(g, w, now)).filter((c) => c.length > 0);
331
- return cards.reduce((n, c) => n + c.length, 0) + Math.max(0, cards.length - 1);
332
- }
333
-
334
- // ------------------------------------------------------------------ painter
335
-
336
- const TONE: Record<CardTone, keyof Theme> = { fg: "fg", fg2: "fg2", muted: "muted", dim: "dim", ok: "ok", err: "err", accent: "accent", warn: "warn" };
337
-
338
- /** paint `lines` at (x, y) in `w` cells — the only impure part, and it writes nothing but those rows */
339
- export function paintCrewCards(scr: ScreenLike, x: number, y: number, w: number, lines: readonly CardLine[], theme: Theme): void {
340
- lines.forEach((line, i) => {
341
- const row = y + i;
342
- if (line.right !== undefined) {
343
- const r = line.right;
344
- scr.put(x + w - width(r.text), row, r.text, st(theme[TONE[r.tone]] as number), width(r.text));
345
- }
346
- if (line.spans.length === 0) return;
347
- const segs: Seg[] = line.spans.map((s) => [s.text, st(theme[TONE[s.tone]] as number, -1, s.bold ? ATTR.BOLD : 0)]);
348
- scr.text(x, row, segs, w - (line.right ? width(line.right.text) + 1 : 0));
349
- });
350
- }