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,456 +0,0 @@
1
- /** Sextant overlays (port #43): prompt parsing, the suggestion box, the command palette and the
2
- * help card. Ported from the user's own sextant v0.4.0 prototype — src/commands.js:8-29
3
- * (parseInput, mentionAt), :51-59 (resolveFile), src/engine.js:125-137 (fuzzy) and
4
- * src/app.js:940-1029 (SLASH table, fileOptions, suggestions, drawSuggest), :1075-1089 (drawHelp),
5
- * :1097-1156 (palette groups/open/close/draw), :1564-1574 (onPaletteKey).
6
- * Dropped: intent matching, the mock shell table (`!cmd` is plain text for onSubmit), /spawn
7
- * /crew /undo /permissions /mode /changes /pet /tasks-as-scenarios. Renderer-local commands
8
- * (/help card, /theme, /open, /diff, /focus, /agents) are listed in LOCAL_COMMANDS and run by
9
- * local-commands.ts; every other slash line (built-ins + custom, from `s.commands` = setCommands)
10
- * is handed to onSubmit by keys.ts. `suggestions` caps its rows at MAX_SUGGESTIONS in one place;
11
- * the drawers never write the state (a paint is not an event).
12
- * Pure: no Date.now(), no timers, no process access. Palette actions are strings (contract
13
- * PaletteState.items): a slash line, or `theme:<name>` `mode:<CodeMode>` `focus:<Focus>`
14
- * `open:<path>` — keys.ts runs them. `fuzzy` is a parameter everywhere (default = the ported
15
- * scorer) so #40's engine.fuzzy can be plugged in without a hard import. */
16
-
17
- import type { HitZone } from "./keys.ts";
18
- import {
19
- ATTR, THEME_ORDER, type CodeMode, type KeyEvent, type Layout, type PaletteState, type Rect,
20
- type ScreenLike, type SextantState, type Style, type Theme, type ThemeName,
21
- } from "./types.ts";
22
- import { markNoticesRead } from "./model.ts";
23
- import { MENTION_RE } from "./mentions.ts";
24
-
25
- // ------------------------------------------------------------------ parsing (commands.js)
26
-
27
- export type Fuzzy = (q: string, s: string) => { score: number; idx: number[] } | null;
28
-
29
- /** engine.js:125-137 — subsequence match; +3 for a consecutive hit, +2 at a word/path start */
30
- export const fuzzy: Fuzzy = (q, s) => {
31
- q = q.toLowerCase(); s = s.toLowerCase();
32
- let qi = 0, score = 0, last = -2;
33
- const idx: number[] = [];
34
- for (let i = 0; i < s.length && qi < q.length; i++) {
35
- if (s[i] === q[qi]) {
36
- idx.push(i);
37
- score += (last === i - 1 ? 3 : 1) + (i === 0 || s[i - 1] === " " || s[i - 1] === "/" ? 2 : 0);
38
- last = i; qi++;
39
- }
40
- }
41
- return qi === q.length ? { score, idx } : null;
42
- };
43
-
44
- export interface ParsedInput {
45
- kind: "slash" | "shell" | "text";
46
- /** slash: the command name (may be ""); shell: the command after `!` */
47
- cmd?: string;
48
- /** slash only: undefined = no space typed yet, "" = space typed and nothing after */
49
- arg?: string;
50
- mentions: string[];
51
- }
52
-
53
- /** commands.js:8-21 — classify one prompt line (an empty line is `text` with no mentions) */
54
- export function parseInput(text: string): ParsedInput {
55
- const t = text.trim();
56
- if (t[0] === "/") {
57
- const m = /^\/(\S*)(\s+(.*))?$/s.exec(text.trimStart());
58
- return { kind: "slash", cmd: m?.[1] ?? "", arg: m?.[2] === undefined ? undefined : (m[3] ?? "").trim(), mentions: [] };
59
- }
60
- // `!cmd` runs a shell command (tui/shell-cmd.ts). Narrow on purpose: the bang must be followed by something that
61
- // is neither whitespace nor another bang, so `!`, `! x` and `!!x` stay plain text for the model. Until the
62
- // consumer existed this returned "shell" for a lone `!` too — harmless only for as long as nothing ran it.
63
- if (t[0] === "!" && t.length > 1 && t[1] !== "!" && !/\s/.test(t[1]!)) return { kind: "shell", cmd: t.slice(1).trim(), mentions: [] };
64
- return { kind: "text", mentions: [...t.matchAll(MENTION_RE)].map((m) => m[1]!) }; // one regex for both surfaces (mentions.ts)
65
- }
66
-
67
- /** commands.js:24-29 — the @mention token under the cursor */
68
- export function mentionAt(text: string, cur: number): { start: number; query: string } | null {
69
- const m = /(?:^|\s)@([\w./-]*)$/.exec(text.slice(0, cur));
70
- return m ? { start: cur - m[1]!.length - 1, query: m[1]! } : null;
71
- }
72
-
73
- /** commands.js:51-59 — exact path, then a unique basename, then the best fuzzy hit */
74
- export function resolveFile(query: string, paths: readonly string[], fz: Fuzzy = fuzzy): string | null {
75
- if (!query) return null;
76
- const q = query.replace(/^@/, "");
77
- if (paths.includes(q)) return q;
78
- const byBase = paths.filter((p) => p.endsWith("/" + q) || p.split("/").pop() === q);
79
- if (byBase.length === 1) return byBase[0]!;
80
- return rank(q, paths, fz)[0] ?? null;
81
- }
82
-
83
- /** fuzzy-ranked copy of `items` (stable: equal scores keep their order); all items when q is empty */
84
- function rank<T>(q: string, items: readonly T[], fz: Fuzzy, key: (t: T) => string = String): T[] {
85
- if (!q) return [...items];
86
- return items.map((it) => ({ it, m: fz(q, key(it)) })).filter((x) => x.m).sort((a, b) => b.m!.score - a.m!.score).map((x) => x.it);
87
- }
88
-
89
- // ------------------------------------------------------------------ commands
90
-
91
- export interface CommandInfo { name: string; description: string; arg?: string; local?: boolean; choices?: readonly string[] | (() => readonly string[]); choicesThen?: "submit" | "complete" }
92
- /** the argument set of an app command right now: a list as given, a function read at suggestion time */
93
- export const choicesOf = (c: { choices?: readonly string[] | (() => readonly string[]) }): readonly string[] =>
94
- typeof c.choices === "function" ? c.choices() : c.choices ?? [];
95
- interface Option { label: string; hint: string }
96
-
97
- /** app.js:940-965 SLASH minus the mock rows; `options` feeds the argument suggestions */
98
- export const LOCAL_COMMANDS: readonly (CommandInfo & { options?: (s: SextantState, q: string, fz: Fuzzy) => Option[] })[] = [
99
- { name: "help", description: "commands + keys card", local: true },
100
- { name: "theme", description: "switch palette", arg: "night·ember·contrast", local: true,
101
- options: (_s, q, fz) => rank(q, THEME_ORDER, fz).map((t) => ({ label: t, hint: THEME_HINT[t] })) },
102
- { name: "open", description: "open a file in the code view", arg: "path", local: true,
103
- options: (s, q, fz) => fileOptions(s, q, s.files.paths, fz) },
104
- { name: "diff", description: "diff of a file (or the current one)", arg: "path?", local: true,
105
- options: (s, q, fz) => { const changed = s.files.paths.filter((p) => s.files.statuses.has(p)); return fileOptions(s, q, changed.length ? changed : s.files.paths, fz); } },
106
- { name: "focus", description: "move keyboard focus", arg: "messages·code·files", local: true,
107
- options: (_s, q, fz) => rank(q, ["messages", "code", "files"], fz).map((f) => ({ label: f, hint: "" })) },
108
- { name: "agents", description: "the crew board (code panel ∷)", local: true },
109
- { name: "notices", description: "notification history (⌃b)", local: true },
110
- { name: "market", description: "install MCP servers, skills, plugins (⌃m)", local: true },
111
- { name: "context", description: "what is in the window right now, item by item (⌃g)", local: true },
112
- ];
113
-
114
- const THEME_HINT: Record<ThemeName, string> = { night: "night + mint", ember: "ink + ember", contrast: "pure contrast" };
115
- /** kbd hints for palette view rows and the help card */
116
- const MODE_KBD: Partial<Record<CodeMode, string>> = { code: "⌃s", diff: "⌃d", run: "⌃r", agents: "⌃a" };
117
-
118
- /** the prompt's command table: renderer-local rows first, then setCommands (built-ins + custom) */
119
- export function allCommands(s: SextantState): CommandInfo[] {
120
- const local = new Set(LOCAL_COMMANDS.map((c) => c.name));
121
- return [...LOCAL_COMMANDS.map(({ name, description, arg, local: l }) => ({ name, description, arg, local: l })),
122
- // an app command with a fixed argument set shows it the way a local one does ("auto·off·low·medium·high")
123
- // a fixed set reads like a local command's ("auto·off·low·medium·high"); a live one is named, not listed
124
- ...s.commands.filter((c) => !local.has(c.name)).map((c) => {
125
- if (!c.choices) return { name: c.name, description: c.description };
126
- const arg = typeof c.choices === "function" ? "provider/model" : c.choices.join("·");
127
- return { name: c.name, description: c.description, arg, choices: c.choices, ...(c.choicesThen ? { choicesThen: c.choicesThen } : {}) };
128
- })];
129
- }
130
-
131
- /** app.js:966-970 — top 6 fuzzy-ranked files with their git status as the hint */
132
- export function fileOptions(s: SextantState, q: string, pool: readonly string[], fz: Fuzzy = fuzzy): Option[] {
133
- return rank(q, pool, fz).slice(0, 6).map((p) => ({ label: p, hint: s.files.statuses.get(p) ?? "" }));
134
- }
135
-
136
- // ------------------------------------------------------------------ suggestions (app.js:973-1003)
137
-
138
- export interface Suggestion {
139
- kind: "slash" | "arg" | "mention";
140
- label: string;
141
- hint: string;
142
- /** argument placeholder shown dim after a slash command */
143
- arg?: string;
144
- /** what Tab does: the completed prompt text and cursor */
145
- apply: { text: string; cur: number };
146
- /** what Enter does after applying: "submit" the completed line, or only "complete" it
147
- * (a mention, or a command that still needs its argument) */
148
- enter: "submit" | "complete";
149
- }
150
-
151
- /** rows the box can show — keys.ts wraps ↑↓ over exactly these, so the cap lives here alone.
152
- * Raised from 8 when /market made the local list eight long: at 8 a bare `/` showed nothing BUT the
153
- * renderer-local commands, and the app's own (/exit, /model, /effort…) fell off the box entirely. */
154
- export const MAX_SUGGESTIONS = 10;
155
-
156
- /** the dropdown above the prompt, at most MAX_SUGGESTIONS rows; [] when nothing applies
157
- * (overlays, cards, empty or free text) */
158
- export function suggestions(s: SextantState, files: readonly string[], fz: Fuzzy = fuzzy): Suggestion[] {
159
- return suggestionRows(s, files, fz).slice(0, MAX_SUGGESTIONS);
160
- }
161
-
162
- function suggestionRows(s: SextantState, files: readonly string[], fz: Fuzzy): Suggestion[] {
163
- if (s.palette || s.help || s.card) return [];
164
- const text = s.input.text;
165
- if (!text.trim()) return [];
166
- const men = mentionAt(text, s.input.cur);
167
- if (men) {
168
- return fileOptions(s, men.query, files, fz).map((o) => ({
169
- kind: "mention", label: o.label, hint: o.hint, enter: "complete",
170
- apply: { text: text.slice(0, men.start) + "@" + o.label + " " + text.slice(s.input.cur), cur: men.start + o.label.length + 2 },
171
- }));
172
- }
173
- const p = parseInput(text);
174
- if (p.kind !== "slash") return [];
175
- if (p.arg === undefined) {
176
- return rank(p.cmd ?? "", allCommands(s), fz, (c) => c.name).map((c) => {
177
- const needsArg = c.arg !== undefined && !c.arg.endsWith("?");
178
- const t = "/" + c.name + (c.arg ? " " : "");
179
- return { kind: "slash", label: "/" + c.name, hint: c.description, arg: c.arg, apply: { text: t, cur: t.length }, enter: needsArg ? "complete" : "submit" };
180
- });
181
- }
182
- const c = LOCAL_COMMANDS.find((x) => x.name === p.cmd);
183
- if (c?.options) {
184
- return c.options(s, p.arg, fz).map((o) => {
185
- const t = "/" + c.name + " " + o.label;
186
- return { kind: "arg", label: o.label, hint: o.hint, apply: { text: t, cur: t.length }, enter: "submit" };
187
- });
188
- }
189
- // an app command with a fixed argument set (/effort auto|off|low|medium|high): the same rows, ranked by what is typed
190
- const app = allCommands(s).find((x) => x.name === p.cmd && x.choices);
191
- const values = app ? choicesOf(app) : [];
192
- if (!app || !values.length) return [];
193
- // a subcommand-style set ("complete") leaves the prompt open with a trailing space for the next word
194
- const complete = app.choicesThen === "complete";
195
- return rank(p.arg, values, fz).map((label) => {
196
- const t = "/" + app.name + " " + label + (complete ? " " : "");
197
- return { kind: "arg", label, hint: "", apply: { text: t, cur: t.length }, enter: complete ? "complete" : "submit" };
198
- });
199
- }
200
-
201
- const st = (fg: number, bg = -1, a = 0): Style => ({ fg, bg, a });
202
- const ENTER: KeyEvent = { type: "key", name: "enter" };
203
-
204
- /** app.js:1004-1023 — the box sits just above the prompt line inside the messages panel `rect`;
205
- * `sugs` is the `suggestions()` list (already capped); a row click selects it and replays Enter
206
- * (HitZone.key). Painting never writes the state: the highlight is clamped locally. */
207
- export function drawSuggest(scr: ScreenLike, rect: Rect, s: SextantState, sugs: readonly Suggestion[], C: Theme, hits?: HitZone[]): void {
208
- if (!sugs.length || s.input.sgSel < 0) return;
209
- const selected = Math.min(s.input.sgSel, sugs.length - 1);
210
- const kind = sugs[0]!.kind, cmd = parseInput(s.input.text).cmd;
211
- const title = kind === "mention" ? "mention a file" : kind === "slash" ? "commands"
212
- : `/${cmd} · ${allCommands(s).find((c) => c.name === cmd)?.arg ?? ""}`;
213
- const w = Math.min(rect.w - 4, 76), x = rect.x + 2, h = sugs.length + 3, y0 = Math.max(rect.y + 1, rect.y + rect.h - 3 - h);
214
- scr.box(x, y0, w, h, st(C.rule2), C.bg2);
215
- scr.text(x + 2, y0 + 1, [[title, st(C.dim, C.bg2)]]);
216
- const help = kind === "mention" ? "tab insert" : "tab complete ⏎ run";
217
- scr.put(x + w - 2 - help.length, y0 + 1, help, st(C.dim, C.bg2));
218
- sugs.forEach((it, i) => {
219
- const y = y0 + 2 + i, sel = i === selected;
220
- const segs: [string, Style][] = [[sel ? "▸ " : " ", st(C.accent, C.bg2)], [it.label, st(sel ? C.fg : C.fg2, C.bg2, sel ? ATTR.BOLD : 0)]];
221
- if (it.arg) segs.push([" " + it.arg, st(C.dim, C.bg2)]);
222
- scr.text(x + 2, y, segs, w - 4);
223
- if (it.hint) { const hw = Math.min(it.hint.length, 34); scr.clip(x + w - 2 - hw, y, it.hint, st(C.muted, C.bg2), hw); }
224
- hits?.push({ rect: { x, y, w, h: 1 }, onClick: () => { s.input.sgSel = i; }, key: ENTER });
225
- });
226
- }
227
-
228
- // ------------------------------------------------------------------ palette (app.js:1097-1156)
229
-
230
- const GROUPS = ["commands", "theme", "view", "open"];
231
- type PaletteItem = PaletteState["items"][number];
232
-
233
- /** groups: commands (local + setCommands), theme, view (code modes + focus), open (every file) */
234
- export function paletteItems(s: SextantState): PaletteItem[] {
235
- const items: PaletteItem[] = allCommands(s).map((c) => ({ label: "/" + c.name, group: "commands", action: "/" + c.name }));
236
- for (const t of THEME_ORDER) items.push({ label: `theme ${t}`, group: "theme", action: `theme:${t}` });
237
- const views: [string, CodeMode][] = [["code view", "code"], ["diff view", "diff"], ["run output", "run"], ["agents board", "agents"]];
238
- for (const [label, mode] of views) items.push({ label, group: "view", action: `mode:${mode}` });
239
- for (const f of ["messages", "code", "files"]) items.push({ label: `focus ${f}`, group: "view", action: `focus:${f}` });
240
- for (const p of s.files.paths) items.push({ label: p, group: "open", action: `open:${p}` });
241
- return items;
242
- }
243
-
244
- /** The overlays that can be on screen, and the one rule about them: at most one at a time.
245
- *
246
- * Nothing enforced that before — help, the palette and the market each wrote their own field, so ⌃m with
247
- * the help card up left BOTH set and help painted over a market nobody could reach. The fix is one
248
- * transition instead of three closers: every opener calls `openOverlay` first, and an opener that forgets
249
- * is caught by the invariant test rather than by a reader six months later.
250
- *
251
- * ADDING A FIFTH: add its field to `closeOthers` below and its name here. That is the whole contract —
252
- * do not write closing lines into your own opener, or the next one will forget one of them. */
253
- export type OverlayKind = "palette" | "market" | "help" | "context" | "wizard";
254
-
255
- /** close every overlay except `keep` (pass null to close them all). The single place that knows the set. */
256
- export function openOverlay(s: SextantState, keep: OverlayKind | null): void {
257
- if (keep !== "palette") s.palette = null;
258
- if (keep !== "market") s.market = null;
259
- if (keep !== "help") s.help = false;
260
- if (keep !== "context") s.context = null;
261
- if (keep !== "wizard") s.wizard = null;
262
- }
263
-
264
- /** which overlays are currently set — the invariant test asserts this is never longer than one */
265
- export function openOverlays(s: SextantState): OverlayKind[] {
266
- const out: OverlayKind[] = [];
267
- if (s.palette) out.push("palette");
268
- if (s.market) out.push("market");
269
- if (s.help) out.push("help");
270
- if (s.context) out.push("context");
271
- if (s.wizard) out.push("wizard");
272
- return out;
273
- }
274
-
275
- /** the help card, through the one transition (local-commands /help and anything else that opens it) */
276
- export function openHelp(s: SextantState): void {
277
- openOverlay(s, "help");
278
- s.help = true;
279
- }
280
-
281
- export function openPalette(s: SextantState, items: PaletteItem[] = paletteItems(s), title?: string): void {
282
- openOverlay(s, "palette");
283
- s.palette = { query: "", sel: 0, items, ...(title !== undefined ? { title } : {}) };
284
- }
285
- export function closePalette(s: SextantState): void { s.palette = null; }
286
-
287
- /** The notification history (⌃b, /notices): the palette box titled "notifications", newest first,
288
- * one row per Notice with its clock as the hint. Read-only rows — Enter just closes (the "noop:"
289
- * action is ignored by runAction). Opening marks everything read, which clears the frame badge.
290
- * Reuses the palette rather than adding a fourth overlay: same box, same keys, nothing new to learn. */
291
- export function openNotices(s: SextantState, now: number = Date.now()): void {
292
- const items = [...s.notices].reverse().map((n) => ({
293
- label: `${n.tone === "error" ? "✗" : n.tone === "warn" ? "◆" : "·"} ${n.text}`,
294
- group: "notices",
295
- action: "noop:",
296
- hint: agoLabel(now - n.at),
297
- }));
298
- markNoticesRead(s);
299
- openPalette(s, items.length ? items : [{ label: "no notifications yet", group: "notices", action: "noop:", hint: "" }], "notifications");
300
- }
301
-
302
- /** "just now" · "12s" · "3m" · "2h" — the age of a notice, coarse on purpose */
303
- export function agoLabel(ms: number): string {
304
- const sec = Math.max(0, Math.round(ms / 1000));
305
- if (sec < 5) return "just now";
306
- if (sec < 60) return `${sec}s`;
307
- if (sec < 3600) return `${Math.round(sec / 60)}m`;
308
- return `${Math.round(sec / 3600)}h`;
309
- }
310
-
311
- /** the rows the query leaves: no query = everything with `open` capped at 6; otherwise fuzzy
312
- * hits, best first inside each group, groups in their fixed order (app.js:1112-1118) */
313
- export function paletteVisible(p: PaletteState, fz: Fuzzy = fuzzy): PaletteItem[] {
314
- const q = p.query.trim();
315
- if (!q) { let open = 0; return p.items.filter((it) => it.group !== "open" || open++ < 6); }
316
- return rank(q, p.items, fz, (it) => it.label).sort((a, b) => GROUPS.indexOf(a.group) - GROUPS.indexOf(b.group));
317
- }
318
-
319
- /** right-aligned hint: command description, theme label, key chord, or git status */
320
- export function paletteHint(s: SextantState, it: PaletteItem): string {
321
- if (it.hint !== undefined) return it.hint; // an explicit hint wins, as PaletteState says it does
322
- if (it.action.startsWith("/")) return allCommands(s).find((c) => "/" + c.name === it.action)?.description ?? "";
323
- const i = it.action.indexOf(":"), kind = it.action.slice(0, i), rest = it.action.slice(i + 1);
324
- switch (kind) {
325
- case "theme": return THEME_HINT[rest as ThemeName] ?? "";
326
- case "mode": return MODE_KBD[rest as CodeMode] ?? "";
327
- case "focus": return rest === "files" ? "⌃e" : "";
328
- case "open": return s.files.statuses.get(rest) ?? "";
329
- default: return "";
330
- }
331
- }
332
-
333
- /** app.js:1122-1156 — returns the cursor cell (after the query). Hits: full-screen close, the box
334
- * (swallows), each row (select + Enter). */
335
- export function drawPalette(scr: ScreenLike, L: Layout, C: Theme, s: SextantState, fz: Fuzzy = fuzzy, hits?: HitZone[]): { x: number; y: number } | null {
336
- const P = s.palette;
337
- if (!P) return null;
338
- hits?.push({ rect: { x: 0, y: 0, w: L.w, h: L.h }, onClick: () => closePalette(s) });
339
- const vis = paletteVisible(P, fz);
340
- P.sel = Math.max(0, Math.min(P.sel, vis.length - 1));
341
- const list: ({ type: "group"; name: string } | { type: "item"; it: PaletteItem; idx: number })[] = [];
342
- let g = "";
343
- vis.forEach((it, idx) => { if (it.group !== g) { g = it.group; list.push({ type: "group", name: g }); } list.push({ type: "item", it, idx }); });
344
- const pw = Math.min(72, L.w - 10), px = Math.floor((L.w - pw) / 2);
345
- const maxList = Math.max(3, Math.min(list.length || 1, Math.floor(L.h / 2)));
346
- const ph = maxList + 5, py = Math.max(2, Math.floor(L.h * 0.14));
347
- scr.box(px, py, pw, ph, st(C.accent), C.bg2);
348
- // the box says what it is. A picker's title comes from the caller, so it is CLIPPED to the box —
349
- // leaving room for the corner and the `esc` label — rather than trusted to fit (an unclipped
350
- // sentence ran past the right border and over the panel behind it).
351
- const boxTitle = ` ${P.title ?? "commands"} `;
352
- scr.clip(px + 2, py, boxTitle, st(C.accent, -1, ATTR.BOLD), Math.max(0, pw - 4));
353
- hits?.push({ rect: { x: px, y: py, w: pw, h: ph }, onClick: () => {} });
354
- scr.put(px + 2, py + 1, "▌", st(C.accent, C.bg2));
355
- if (P.query) scr.put(px + 4, py + 1, P.query, st(C.fg, C.bg2, ATTR.BOLD), pw - 12);
356
- else scr.put(px + 4, py + 1, P.title === undefined ? "commands, themes, views, files…" : "type to filter…", st(C.dim, C.bg2), pw - 12);
357
- scr.put(px + pw - 6, py + 1, "esc", st(C.dim, C.bg2));
358
- scr.hline(px + 1, py + 2, pw - 2, st(C.rule2, C.bg2), "╌");
359
- const selRow = list.findIndex((r) => r.type === "item" && r.idx === P.sel);
360
- const off = selRow >= maxList - 1 ? selRow - maxList + 2 : 0;
361
- if (!list.length) scr.put(px + 4, py + 3, "no matches", st(C.muted, C.bg2));
362
- for (let i = 0; i < maxList; i++) {
363
- const r = list[off + i];
364
- if (!r) break;
365
- const y = py + 3 + i;
366
- if (r.type === "group") { scr.put(px + 4, y, r.name, st(C.dim, C.bg2), pw - 6); continue; } // clipped: a group name is data too
367
- const sel = r.idx === P.sel;
368
- scr.text(px + 2, y, [[sel ? "▸ " : " ", st(C.accent, C.bg2)], [r.it.label, st(sel ? C.fg : C.fg2, C.bg2, sel ? ATTR.BOLD : 0)]], pw - 30);
369
- const hint = paletteHint(s, r.it);
370
- if (hint) scr.clip(px + pw - 3 - Math.min(hint.length, 24), y, hint, st(C.muted, C.bg2), 24);
371
- hits?.push({ rect: { x: px, y, w: pw, h: 1 }, onClick: () => { P.sel = r.idx; }, key: ENTER });
372
- }
373
- return { x: px + 4 + P.query.length, y: py + 1 };
374
- }
375
-
376
- /** app.js:1564-1574 minus ⌃c (keys.ts handles it before delegating): Esc/⌃k/⌃p close, ↑↓ wrap,
377
- * Enter closes then runs the selected action through `run`, backspace/typing edit the query */
378
- export function onPaletteKey(s: SextantState, ev: KeyEvent, run: (action: string) => void, fz: Fuzzy = fuzzy): void {
379
- const P = s.palette;
380
- if (!P) return;
381
- const { name, ctrl, alt, ch } = ev;
382
- if (name === "escape" || (ctrl && (name === "k" || name === "p"))) { closePalette(s); return; }
383
- const vis = paletteVisible(P, fz), n = Math.max(1, vis.length);
384
- if (name === "up") { P.sel = (P.sel - 1 + n) % n; return; }
385
- if (name === "down") { P.sel = (P.sel + 1) % n; return; }
386
- if (name === "enter") { const it = vis[P.sel]; closePalette(s); if (it) run(it.action); return; }
387
- if (name === "backspace") { P.query = [...P.query].slice(0, -1).join(""); P.sel = 0; return; } // by code point (😀 is one)
388
- const c = name === "space" ? " " : ch;
389
- if (c && !ctrl && !alt) { P.query += c; P.sel = 0; }
390
- }
391
-
392
- // ------------------------------------------------------------------ help card (app.js:1075-1089)
393
-
394
- /** the README keys table with rovecode names */
395
- export const HELP_KEYS: readonly (readonly [string, string])[] = [
396
- ["⏎", "send · confirm a card · run the suggestion"],
397
- ["tab ⇧tab", "complete a suggestion · cycle focus"],
398
- ["esc esc", "stop the run (the first esc warns)"],
399
- ["⌃c", "quit (interrupts a run first)"],
400
- ["⌃k ⌃p", "command palette"],
401
- ["⌃s ⌃d ⌃r", "code · diff · run view"],
402
- ["⌃a", "agents board"],
403
- ["⌃e", "files panel"],
404
- ["⌃o", "next tab (narrow terminal)"],
405
- ["⌃b", "notifications"],
406
- ["⌃m", "market (install servers, skills, plugins)"],
407
- ["⌃g", "context (what is in the window, and how far our count is from the provider’s)"],
408
- ["⌥d", "market: the selected item's documentation"],
409
- ["⌃v", "paste image · drop a file to attach"],
410
- ["⌃t", "next theme"],
411
- ["⌃n", "new session (/new)"],
412
- ["⌃u", "clear the prompt line"],
413
- ["↑↓ ←→", "files: pick · fold — code: scroll · mode — prompt: history"],
414
- ["⌃← ⌃→", "prompt: jump by word"],
415
- ["home end", "prompt: line start · end (end re-sticks the tail)"],
416
- ["pgup pgdn", "scroll messages · end sticks to the tail"],
417
- ["mouse", "click · wheel · drag a scrollbar"],
418
- ["@file", "mention a file (picker)"],
419
- ];
420
-
421
- /** [name, description, arg] per command: local rows first, then setCommands */
422
- export function helpRows(s: SextantState): [string, string, string][] {
423
- return allCommands(s).map((c) => ["/" + c.name, c.description, c.arg ?? ""]);
424
- }
425
-
426
- /** centered card; the command column is cut to the height with an "… N more" row; any click closes */
427
- export function drawHelp(scr: ScreenLike, L: Layout, C: Theme, s: SextantState, hits?: HitZone[]): void {
428
- const rows = helpRows(s);
429
- const w = Math.min(L.w - 8, 112), wide = w >= 110;
430
- const maxRows = Math.max(1, L.h - 8);
431
- const shown = rows.length > maxRows ? [...rows.slice(0, maxRows - 1), ["…", `${rows.length - maxRows + 1} more · /help lists all`, ""] as [string, string, string]] : rows;
432
- // the KEYS column is capped by the same rule as the commands column. It used not to be, because it was
433
- // shorter than every terminal anyone tried — and then the box height took the max of the two, so adding
434
- // one chord pushed the bottom border past the frame on a 30-row terminal. A list that grows is a list
435
- // that has to be cut somewhere.
436
- const keys: (readonly [string, string])[] = HELP_KEYS.length > maxRows
437
- ? [...HELP_KEYS.slice(0, maxRows - 1), ["…", `${HELP_KEYS.length - maxRows + 1} more`] as [string, string]]
438
- : [...HELP_KEYS];
439
- const h = Math.max(shown.length, keys.length) + 6, x = Math.floor((L.w - w) / 2), y = Math.max(1, Math.floor((L.h - h) / 2));
440
- scr.box(x, y, w, h, st(C.accent), C.bg2);
441
- scr.text(x + 2, y, [[" help ", st(C.accent, -1, ATTR.BOLD)]]);
442
- scr.put(x + w - 14, y, " esc closes ", st(C.dim));
443
- const kx = wide ? x + 70 : x + 50;
444
- scr.put(x + 3, y + 2, "commands", st(C.muted, C.bg2)); scr.put(kx, y + 2, "keys", st(C.muted, C.bg2));
445
- shown.forEach(([name, desc, arg], i) => {
446
- const yy = y + 3 + i;
447
- scr.put(x + 3, yy, name, st(C.accent, C.bg2), 13); scr.put(x + 17, yy, desc, st(C.fg2, C.bg2), wide ? 28 : 30);
448
- if (wide && arg) scr.put(x + 46, yy, arg, st(C.dim, C.bg2), 22);
449
- });
450
- keys.forEach(([a, b], i) => {
451
- const yy = y + 3 + i;
452
- scr.put(kx, yy, a, st(C.fg, C.bg2, ATTR.BOLD), 10); scr.put(kx + 11, yy, b, st(C.fg2, C.bg2), w - (kx - x) - 13);
453
- });
454
- scr.put(x + 3, y + h - 2, "plain text and !commands reach the agent as typed · @file attaches the file as a read (400 lines, 8 files)", st(C.dim, C.bg2), w - 6);
455
- hits?.push({ rect: { x: 0, y: 0, w: L.w, h: L.h }, onClick: () => { s.help = false; } });
456
- }
@@ -1,38 +0,0 @@
1
- /** Click zones for the panels' own rows — today the files tree.
2
- *
3
- * The files panel drew a cursor row and answered to ↑↓ ←→ Enter, and a click anywhere in it merely
4
- * moved focus there (keys.ts onMouse's fallback), so "click the file to open it" — the one thing
5
- * everyone tries first — did nothing. Same shape of gap as the card (card-hits.ts): the painter knew
6
- * where every row was and told nobody.
7
- *
8
- * Geometry mirrors drawFiles exactly: rows start at the panel's inner top, one per line, the first
9
- * visible row is `files.scroll`. Computed AFTER the frame is painted (drawFiles clamps scroll and the
10
- * cursor while painting), so the zones describe what is actually on screen this frame.
11
- *
12
- * A click selects the row AND replays Enter: a directory toggles its fold, a file opens in the code
13
- * panel — the same two things Enter already does on the cursor row (keys.ts onEnter), so clicking
14
- * cannot do anything the keyboard could not. */
15
-
16
- import { inner } from "./draw-util.ts";
17
- import type { Rect, SextantState, TreeRow } from "./types.ts";
18
-
19
- export interface RowHit {
20
- rect: Rect;
21
- /** the row's index into the flattened tree (files.cursor takes this value) */
22
- index: number;
23
- }
24
-
25
- /** One zone per visible tree row, or [] when the files panel is hidden or empty. `rows` is the
26
- * flattened tree as drawn this frame (frame loop: treeRows(s)). */
27
- export function fileRowHits(files: Rect | null, s: SextantState, rows: readonly TreeRow[]): RowHit[] {
28
- if (files === null || rows.length === 0) return [];
29
- const B = inner(files);
30
- if (B.w <= 0 || B.h <= 0) return [];
31
- const out: RowHit[] = [];
32
- for (let i = 0; i < B.h; i++) {
33
- const index = s.files.scroll + i;
34
- if (index >= rows.length) break;
35
- out.push({ rect: { x: B.x, y: B.y + i, w: B.w, h: 1 }, index });
36
- }
37
- return out;
38
- }