rovecode 0.3.2 → 0.4.0-beta.2

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 (491) hide show
  1. package/CHANGELOG.md +512 -0
  2. package/README.md +33 -45
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-dybnr56b.js +2 -0
  5. package/dist/cli/ask-user-p8hq4xgj.js +2 -0
  6. package/dist/cli/auth-login-ewpgw5sm.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-xv3ypwev.js +9 -0
  9. package/dist/cli/catalog-737wb2s0.js +2 -0
  10. package/dist/cli/cli-arhg40m0.js +2 -0
  11. package/dist/cli/client-cf2pxx8q.js +2 -0
  12. package/dist/cli/commands-3p7e4xxs.js +2 -0
  13. package/dist/cli/connect-3q93d7cb.js +2 -0
  14. package/dist/cli/context-cmd-eqxmxhzq.js +2 -0
  15. package/dist/cli/context-report-hbw9zfes.js +2 -0
  16. package/dist/cli/count-remote-mby98cd0.js +2 -0
  17. package/dist/cli/design-122y0axd.js +2 -0
  18. package/dist/cli/dispatch-b4egzvvh.js +2 -0
  19. package/dist/cli/doctor-x4jkv72e.js +3 -0
  20. package/dist/cli/executor-ftvg6tsy.js +2 -0
  21. package/dist/cli/export-pdgdhkch.js +2 -0
  22. package/dist/cli/files-cez9a96p.js +2 -0
  23. package/dist/cli/gauntlet-r3xxaszc.js +2 -0
  24. package/dist/cli/gauntlet-runner-r515m7kk.js +10 -0
  25. package/dist/cli/gauntlet-wave3-bnkjk2v2.js +5 -0
  26. package/dist/cli/gauntlet-wave4-acs9s60q.js +14 -0
  27. package/dist/cli/hashline-ewg5hbe3.js +2 -0
  28. package/dist/cli/http-n0kehsk8.js +5 -0
  29. package/dist/cli/index-z5qt1s76.js +2 -0
  30. package/dist/cli/install-80mp63kx.js +2 -0
  31. package/dist/cli/loop-12twjcat.js +2 -0
  32. package/dist/cli/main-01pv9206.js +4 -0
  33. package/dist/cli/main-0jys2ccn.js +3 -0
  34. package/dist/cli/main-1ztz6fkj.js +10 -0
  35. package/dist/cli/main-23q7cmww.js +9 -0
  36. package/dist/cli/main-2rzbexn2.js +3 -0
  37. package/dist/cli/main-2wyax8k9.js +9 -0
  38. package/dist/cli/main-2yeveeve.js +6 -0
  39. package/dist/cli/main-2z3dek0b.js +3 -0
  40. package/dist/cli/main-2zgsknth.js +3 -0
  41. package/dist/cli/main-45ejth3a.js +4 -0
  42. package/dist/cli/main-45rn3trk.js +22 -0
  43. package/dist/cli/main-4p4e2w7x.js +4 -0
  44. package/dist/cli/main-4y0tnfpa.js +16 -0
  45. package/dist/cli/main-5py0rkmc.js +4 -0
  46. package/dist/cli/main-6dtqmbt6.js +7 -0
  47. package/dist/cli/main-6h9x282m.js +4 -0
  48. package/dist/cli/main-6vjeds42.js +3 -0
  49. package/dist/cli/main-78gq4bt9.js +6 -0
  50. package/dist/cli/main-7jd5vh3x.js +4 -0
  51. package/dist/cli/main-7kt6r53y.js +4 -0
  52. package/dist/cli/main-8c1tbazx.js +58 -0
  53. package/dist/cli/main-9a9rnh47.js +19 -0
  54. package/dist/cli/main-9ht36z12.js +3 -0
  55. package/dist/cli/main-a2yfvcy9.js +7 -0
  56. package/dist/cli/main-a3f51n0x.js +5 -0
  57. package/dist/cli/main-b8zq261k.js +3 -0
  58. package/dist/cli/main-bxtvnf6d.js +13 -0
  59. package/dist/cli/main-edxc3yzt.js +4 -0
  60. package/dist/cli/main-evgz4mp5.js +21 -0
  61. package/dist/cli/main-f33fc5je.js +9 -0
  62. package/dist/cli/main-fvnpq46y.js +12 -0
  63. package/dist/cli/main-gbbty4d4.js +3 -0
  64. package/dist/cli/main-gth53dnt.js +25 -0
  65. package/dist/cli/main-hqbz10aw.js +9 -0
  66. package/dist/cli/main-hrrvcfan.js +38 -0
  67. package/dist/cli/main-hzwtsb2m.js +5 -0
  68. package/dist/cli/main-j7ttv0sd.js +34 -0
  69. package/dist/cli/main-jak598k9.js +5 -0
  70. package/dist/cli/main-kba6zeyd.js +6 -0
  71. package/dist/cli/main-kwwsz6rq.js +3 -0
  72. package/dist/cli/main-m8vm17zq.js +3 -0
  73. package/dist/cli/main-mg4f96e1.js +3 -0
  74. package/dist/cli/main-mg9b20ac.js +18 -0
  75. package/dist/cli/main-mgb9ccnx.js +3 -0
  76. package/dist/cli/main-mjt2p7aj.js +3 -0
  77. package/dist/cli/main-n6qrdbmy.js +3 -0
  78. package/dist/cli/main-na7wse0x.js +5 -0
  79. package/dist/cli/main-nqveez48.js +4 -0
  80. package/dist/cli/main-ntqef02r.js +10 -0
  81. package/dist/cli/main-nvc3yjay.js +136 -0
  82. package/dist/cli/main-p0cfn6nr.js +16 -0
  83. package/dist/cli/main-qj2djy17.js +19 -0
  84. package/dist/cli/main-qsevpgsv.js +3 -0
  85. package/dist/cli/main-qvarybsp.js +3 -0
  86. package/dist/cli/main-rebtt91r.js +5 -0
  87. package/dist/cli/main-rpg7h8mb.js +3 -0
  88. package/dist/cli/main-rsy72qmw.js +15 -0
  89. package/dist/cli/main-rvetps99.js +18 -0
  90. package/dist/cli/main-s4bb0jav.js +3 -0
  91. package/dist/cli/main-s9v8k74e.js +3 -0
  92. package/dist/cli/main-tjvwmscs.js +3 -0
  93. package/dist/cli/main-tkgarpjj.js +4 -0
  94. package/dist/cli/main-v8y60bb2.js +3 -0
  95. package/dist/cli/main-vhrrq337.js +3 -0
  96. package/dist/cli/main-vp2dfb7s.js +4 -0
  97. package/dist/cli/main-vqbr22sz.js +8 -0
  98. package/dist/cli/main-vxnwe5xx.js +18 -0
  99. package/dist/cli/main-wgph00xf.js +5 -0
  100. package/dist/cli/main-wk2csfnj.js +5 -0
  101. package/dist/cli/main-wm997zjx.js +3 -0
  102. package/dist/cli/main-wpkyraxh.js +3 -0
  103. package/dist/cli/main-wqt32p5x.js +4 -0
  104. package/dist/cli/main-x9ct6y1a.js +3 -0
  105. package/dist/cli/main-xfekqh9m.js +7 -0
  106. package/dist/cli/main-xt9zc3n6.js +7 -0
  107. package/dist/cli/main-xx2z3zh5.js +4 -0
  108. package/dist/cli/main-y5c82rxr.js +3 -0
  109. package/dist/cli/main-yrjt2sqt.js +14 -0
  110. package/dist/cli/main-ys6zj3yr.js +3 -0
  111. package/dist/cli/main-ywbxshqc.js +8 -0
  112. package/dist/cli/main-z13755t8.js +25 -0
  113. package/dist/cli/main-zc7pyrbj.js +4 -0
  114. package/dist/cli/main.js +279 -0
  115. package/dist/cli/market-cmd-bm5xvn9f.js +5 -0
  116. package/dist/cli/mcp-login-bthtfpt7.js +2 -0
  117. package/dist/cli/mcp-market-cmd-mbeshfyd.js +2 -0
  118. package/dist/cli/notify-54v5z9dz.js +2 -0
  119. package/dist/cli/oauth-g5gme95c.js +2 -0
  120. package/dist/cli/output-satndjap.js +16 -0
  121. package/dist/cli/profiles-sfhpbq3m.js +2 -0
  122. package/dist/cli/provider-config-hv3xtdt4.js +2 -0
  123. package/dist/cli/provider-kwzq6g84.js +2 -0
  124. package/dist/cli/registry-fh0hdnyn.js +2 -0
  125. package/dist/cli/registry-y1y8e94r.js +2 -0
  126. package/dist/cli/repl-t4z03mqq.js +11 -0
  127. package/dist/cli/resume-fqt4chg8.js +2 -0
  128. package/dist/cli/run-flags-rysbag9t.js +2 -0
  129. package/dist/cli/runtime-j19fjbsa.js +2 -0
  130. package/dist/cli/sandbox-config-g4qxd7y5.js +2 -0
  131. package/dist/cli/server-r0b6bksk.js +5 -0
  132. package/dist/cli/session-arg-txmn5g4x.js +2 -0
  133. package/dist/cli/session-ed250d9j.js +2 -0
  134. package/dist/cli/sessions-cmd-adw7svfn.js +7 -0
  135. package/dist/cli/settings-y9rzcqx8.js +2 -0
  136. package/dist/cli/setup-jmbr11j0.js +2 -0
  137. package/dist/cli/sextant-smoke-tcth0vea.js +5 -0
  138. package/dist/cli/skills-cmd-zbdy99v6.js +2 -0
  139. package/dist/cli/smoke-1bg937kx.js +8 -0
  140. package/dist/cli/start-chat-p01cdks3.js +12 -0
  141. package/dist/cli/stream-4wmyaypz.js +2 -0
  142. package/dist/cli/task-eg4s093s.js +2 -0
  143. package/dist/cli/tasks-12v9rr9k.js +2 -0
  144. package/dist/cli/thinking-a5ngvqyh.js +2 -0
  145. package/dist/cli/todo-1wxpcecx.js +2 -0
  146. package/dist/cli/tools-2ftsya7w.js +2 -0
  147. package/dist/cli/tools-x1tj4fxm.js +2 -0
  148. package/dist/cli/trust-cmd-hccxehzb.js +2 -0
  149. package/dist/cli/update-check-ygt3vd7m.js +2 -0
  150. package/dist/cli/update-cmd-v23qhr8c.js +2 -0
  151. package/dist/cli/voice-g1gtck92.js +2 -0
  152. package/dist/cli/webfetch-0nnrjgb5.js +2 -0
  153. package/dist/cli/websearch-f0vr2p7d.js +2 -0
  154. package/dist/cli/workspace-9rq1w4ta.js +2 -0
  155. package/dist/lib/index.js +62 -0
  156. package/dist/lib/models-index.json +1 -0
  157. package/dist/lib/plugins.js +6 -0
  158. package/dist/lib/providers.js +17 -0
  159. package/dist/lib/public-api.js +20 -0
  160. package/dist/rovecode.exe +4 -0
  161. package/package.json +38 -11
  162. package/bin/rovecode.ts +0 -21
  163. package/src/acp/server.ts +0 -374
  164. package/src/cli/auth-login.ts +0 -122
  165. package/src/cli/connect.ts +0 -244
  166. package/src/cli/context-cmd.ts +0 -199
  167. package/src/cli/dispatch.ts +0 -82
  168. package/src/cli/doctor.ts +0 -362
  169. package/src/cli/export.ts +0 -276
  170. package/src/cli/help.ts +0 -293
  171. package/src/cli/is-tui-invocation.ts +0 -8
  172. package/src/cli/main.ts +0 -583
  173. package/src/cli/market-cmd.ts +0 -658
  174. package/src/cli/mcp-login.ts +0 -141
  175. package/src/cli/mcp-market-cmd.ts +0 -302
  176. package/src/cli/output.ts +0 -382
  177. package/src/cli/repl.ts +0 -250
  178. package/src/cli/repomap-root.ts +0 -14
  179. package/src/cli/resume.ts +0 -57
  180. package/src/cli/run-flags.ts +0 -43
  181. package/src/cli/run-limits.ts +0 -78
  182. package/src/cli/runtime.ts +0 -931
  183. package/src/cli/session-arg.ts +0 -30
  184. package/src/cli/sessions-cmd.ts +0 -145
  185. package/src/cli/setup.ts +0 -153
  186. package/src/cli/skills-cmd.ts +0 -194
  187. package/src/cli/start-chat.ts +0 -65
  188. package/src/cli/trust-cmd.ts +0 -52
  189. package/src/coding/bash.ts +0 -148
  190. package/src/coding/checkpoints.ts +0 -327
  191. package/src/coding/diff.ts +0 -138
  192. package/src/coding/files.ts +0 -341
  193. package/src/coding/hashline.ts +0 -274
  194. package/src/coding/lsp-gate.ts +0 -254
  195. package/src/coding/lsp-servers.ts +0 -147
  196. package/src/coding/lsp.ts +0 -283
  197. package/src/coding/repomap-cache.ts +0 -99
  198. package/src/coding/repomap-files.ts +0 -192
  199. package/src/coding/repomap.ts +0 -481
  200. package/src/core/agents.ts +0 -255
  201. package/src/core/compaction.ts +0 -259
  202. package/src/core/config.ts +0 -289
  203. package/src/core/context-report.ts +0 -228
  204. package/src/core/context.ts +0 -60
  205. package/src/core/count-remote.ts +0 -107
  206. package/src/core/execpolicy-rules.ts +0 -196
  207. package/src/core/execpolicy.ts +0 -385
  208. package/src/core/executor.ts +0 -454
  209. package/src/core/guardrails.ts +0 -400
  210. package/src/core/hooks.ts +0 -411
  211. package/src/core/images.ts +0 -230
  212. package/src/core/intro.ts +0 -266
  213. package/src/core/loop.ts +0 -567
  214. package/src/core/modes.ts +0 -372
  215. package/src/core/orchestrator.ts +0 -245
  216. package/src/core/proc-group.ts +0 -48
  217. package/src/core/project-trust.ts +0 -98
  218. package/src/core/reflection.ts +0 -165
  219. package/src/core/sandbox-config.ts +0 -186
  220. package/src/core/session-id.ts +0 -24
  221. package/src/core/session-images.ts +0 -73
  222. package/src/core/session-ops.ts +0 -183
  223. package/src/core/session-text.ts +0 -29
  224. package/src/core/session.ts +0 -469
  225. package/src/core/settings.ts +0 -170
  226. package/src/core/tasks.ts +0 -646
  227. package/src/core/token-scale.ts +0 -108
  228. package/src/core/tools.ts +0 -309
  229. package/src/core/trust.ts +0 -104
  230. package/src/core/types.ts +0 -330
  231. package/src/core/update-check.ts +0 -171
  232. package/src/core/usage.ts +0 -204
  233. package/src/core/validate.ts +0 -121
  234. package/src/core/verify-gate.ts +0 -159
  235. package/src/core/verify.ts +0 -236
  236. package/src/core/voice.ts +0 -158
  237. package/src/core/win-job.ts +0 -183
  238. package/src/core/workspace.ts +0 -184
  239. package/src/design/audit.ts +0 -797
  240. package/src/design/direction.ts +0 -190
  241. package/src/design/rules.ts +0 -157
  242. package/src/eval/bench.ts +0 -150
  243. package/src/eval/gauntlet-runner.ts +0 -215
  244. package/src/eval/gauntlet-support.ts +0 -84
  245. package/src/eval/gauntlet-wave3.ts +0 -269
  246. package/src/eval/gauntlet-wave4.ts +0 -217
  247. package/src/eval/gauntlet.ts +0 -253
  248. package/src/index.ts +0 -17
  249. package/src/lanes/agy.ts +0 -95
  250. package/src/lanes/approval.ts +0 -24
  251. package/src/lanes/claude.ts +0 -129
  252. package/src/lanes/codex.ts +0 -127
  253. package/src/lanes/events.ts +0 -130
  254. package/src/lanes/job.ts +0 -142
  255. package/src/lanes/opencode.ts +0 -122
  256. package/src/lanes/process.ts +0 -184
  257. package/src/lanes/progress.ts +0 -183
  258. package/src/lanes/registry.ts +0 -178
  259. package/src/lanes/runner.ts +0 -124
  260. package/src/lanes/types.ts +0 -112
  261. package/src/market/catalogs/mcp-docs.json +0 -111
  262. package/src/market/catalogs/plugins.json +0 -111
  263. package/src/market/catalogs/skills.json +0 -478
  264. package/src/market/clone.ts +0 -72
  265. package/src/market/context-cost.ts +0 -121
  266. package/src/market/digest.ts +0 -106
  267. package/src/market/index.ts +0 -22
  268. package/src/market/install.ts +0 -578
  269. package/src/market/manifest.ts +0 -187
  270. package/src/market/prereq.ts +0 -145
  271. package/src/market/registry.ts +0 -363
  272. package/src/market/resolve.ts +0 -111
  273. package/src/market/types.ts +0 -236
  274. package/src/market/validate.ts +0 -227
  275. package/src/mcp/client.ts +0 -449
  276. package/src/mcp/config.ts +0 -252
  277. package/src/mcp/local-package.ts +0 -211
  278. package/src/mcp/market-catalog.ts +0 -84
  279. package/src/mcp/market-install.ts +0 -289
  280. package/src/mcp/market.ts +0 -362
  281. package/src/mcp/oauth.ts +0 -251
  282. package/src/mcp/prompts-resources.ts +0 -249
  283. package/src/mcp/shared.ts +0 -149
  284. package/src/mcp/status.ts +0 -67
  285. package/src/mcp/tools.ts +0 -275
  286. package/src/mcp/transport.ts +0 -122
  287. package/src/mcp/trust.ts +0 -25
  288. package/src/memory/blocks.ts +0 -278
  289. package/src/memory/recall.ts +0 -355
  290. package/src/memory/scope.ts +0 -182
  291. package/src/memory/store.ts +0 -105
  292. package/src/memory/tools.ts +0 -99
  293. package/src/plugins/cli.ts +0 -119
  294. package/src/plugins/discover.ts +0 -108
  295. package/src/plugins/index.ts +0 -50
  296. package/src/plugins/install.ts +0 -184
  297. package/src/plugins/load.ts +0 -124
  298. package/src/plugins/manifest.ts +0 -92
  299. package/src/plugins/state.ts +0 -83
  300. package/src/providers/auth.ts +0 -408
  301. package/src/providers/cache.ts +0 -223
  302. package/src/providers/catalog-local.ts +0 -160
  303. package/src/providers/catalog.ts +0 -421
  304. package/src/providers/middleware-context.ts +0 -86
  305. package/src/providers/middleware.ts +0 -373
  306. package/src/providers/model-list.ts +0 -23
  307. package/src/providers/oauth/common.ts +0 -105
  308. package/src/providers/oauth/device-code.ts +0 -107
  309. package/src/providers/oauth/github-copilot.ts +0 -146
  310. package/src/providers/oauth/loopback.ts +0 -158
  311. package/src/providers/oauth/openai.ts +0 -163
  312. package/src/providers/oauth/openrouter.ts +0 -89
  313. package/src/providers/oauth/pkce.ts +0 -45
  314. package/src/providers/oauth/registry.ts +0 -39
  315. package/src/providers/oauth/seam.ts +0 -89
  316. package/src/providers/profile-glm53.ts +0 -111
  317. package/src/providers/profile-sonnet5-persona.ts +0 -65
  318. package/src/providers/profile-sonnet5-voice.ts +0 -23
  319. package/src/providers/profiles.ts +0 -156
  320. package/src/providers/provider-config.ts +0 -311
  321. package/src/providers/registry.ts +0 -333
  322. package/src/providers/responses.ts +0 -209
  323. package/src/providers/retry.ts +0 -234
  324. package/src/providers/router.ts +0 -294
  325. package/src/providers/sse.ts +0 -26
  326. package/src/providers/stream-errors.ts +0 -117
  327. package/src/providers/stream.ts +0 -566
  328. package/src/providers/thinking.ts +0 -189
  329. package/src/providers/wire-messages.ts +0 -129
  330. package/src/providers/wire-responses.ts +0 -79
  331. package/src/providers/wire-select.ts +0 -53
  332. package/src/server/http.ts +0 -291
  333. package/src/server/openapi.ts +0 -246
  334. package/src/sextant/card-hits.ts +0 -102
  335. package/src/sextant/card-keys.ts +0 -55
  336. package/src/sextant/context-source.ts +0 -157
  337. package/src/sextant/crew-cards.ts +0 -350
  338. package/src/sextant/draw-agents.ts +0 -273
  339. package/src/sextant/draw-code.ts +0 -388
  340. package/src/sextant/draw-context.ts +0 -222
  341. package/src/sextant/draw-frame.ts +0 -164
  342. package/src/sextant/draw-market.ts +0 -573
  343. package/src/sextant/draw-messages.ts +0 -386
  344. package/src/sextant/draw-pet.ts +0 -230
  345. package/src/sextant/draw-plan.ts +0 -187
  346. package/src/sextant/draw-tabs.ts +0 -85
  347. package/src/sextant/draw-util.ts +0 -65
  348. package/src/sextant/draw-wizard.ts +0 -378
  349. package/src/sextant/engine.ts +0 -230
  350. package/src/sextant/frame-hits.ts +0 -25
  351. package/src/sextant/frame.ts +0 -101
  352. package/src/sextant/git-status.ts +0 -197
  353. package/src/sextant/grid.ts +0 -59
  354. package/src/sextant/input.ts +0 -119
  355. package/src/sextant/keys.ts +0 -521
  356. package/src/sextant/layout.ts +0 -86
  357. package/src/sextant/local-commands.ts +0 -169
  358. package/src/sextant/market-source.ts +0 -287
  359. package/src/sextant/mentions.ts +0 -200
  360. package/src/sextant/message-hits.ts +0 -26
  361. package/src/sextant/model.ts +0 -387
  362. package/src/sextant/overlays.ts +0 -456
  363. package/src/sextant/panel-hits.ts +0 -38
  364. package/src/sextant/pet.ts +0 -399
  365. package/src/sextant/screen.ts +0 -324
  366. package/src/sextant/scroll-hits.ts +0 -66
  367. package/src/sextant/scrollbar.ts +0 -82
  368. package/src/sextant/sextant-bridge.ts +0 -174
  369. package/src/sextant/sextant-cards.ts +0 -142
  370. package/src/sextant/sextant-diff-base.ts +0 -63
  371. package/src/sextant/sextant-files.ts +0 -154
  372. package/src/sextant/sextant-frame-loop.ts +0 -335
  373. package/src/sextant/sextant-renderer.ts +0 -574
  374. package/src/sextant/sextant-repo.ts +0 -140
  375. package/src/sextant/theme.ts +0 -66
  376. package/src/sextant/tool-rows.ts +0 -189
  377. package/src/sextant/types.ts +0 -493
  378. package/src/skills/index.ts +0 -387
  379. package/src/skills/pack.ts +0 -220
  380. package/src/skills/spec.ts +0 -162
  381. package/src/skills/tools.ts +0 -69
  382. package/src/skills/versioned.ts +0 -227
  383. package/src/telemetry/otel-export.ts +0 -122
  384. package/src/telemetry/otel-lanes.ts +0 -89
  385. package/src/telemetry/otel-logs.ts +0 -131
  386. package/src/telemetry/otel-metrics.ts +0 -136
  387. package/src/telemetry/otel.ts +0 -397
  388. package/src/telemetry/otlp.ts +0 -76
  389. package/src/tools/ask-user.ts +0 -156
  390. package/src/tools/bash-bg.ts +0 -94
  391. package/src/tools/bash-jobs.ts +0 -237
  392. package/src/tools/design.ts +0 -151
  393. package/src/tools/evalcell.ts +0 -338
  394. package/src/tools/html-text.ts +0 -139
  395. package/src/tools/provider.ts +0 -149
  396. package/src/tools/task.ts +0 -250
  397. package/src/tools/todo.ts +0 -320
  398. package/src/tools/webfetch.ts +0 -332
  399. package/src/tools/websearch.ts +0 -359
  400. package/src/tui/agents-cmd.ts +0 -41
  401. package/src/tui/app.ts +0 -749
  402. package/src/tui/attach.ts +0 -127
  403. package/src/tui/boot-notes.ts +0 -41
  404. package/src/tui/builtin-prompts.ts +0 -59
  405. package/src/tui/checkpoints-cmd.ts +0 -70
  406. package/src/tui/clipboard-image.ts +0 -81
  407. package/src/tui/clipboard.ts +0 -78
  408. package/src/tui/commands.ts +0 -283
  409. package/src/tui/config-view.ts +0 -53
  410. package/src/tui/context-cmds.ts +0 -282
  411. package/src/tui/cost.ts +0 -108
  412. package/src/tui/crash-guard.ts +0 -173
  413. package/src/tui/focus-terminal.ts +0 -34
  414. package/src/tui/git-cmds.ts +0 -273
  415. package/src/tui/git-plain.ts +0 -58
  416. package/src/tui/info-cmd.ts +0 -150
  417. package/src/tui/input-plain.ts +0 -76
  418. package/src/tui/mcp-cmd.ts +0 -128
  419. package/src/tui/memory-note.ts +0 -77
  420. package/src/tui/modes-cmd.ts +0 -45
  421. package/src/tui/notify-seq.ts +0 -100
  422. package/src/tui/notify.ts +0 -318
  423. package/src/tui/overlays.ts +0 -97
  424. package/src/tui/pi-renderer.ts +0 -428
  425. package/src/tui/providers-cmd.ts +0 -377
  426. package/src/tui/reasoning-view.ts +0 -56
  427. package/src/tui/renderer.ts +0 -128
  428. package/src/tui/replay-marker.ts +0 -29
  429. package/src/tui/session-cmd.ts +0 -148
  430. package/src/tui/session-manage.ts +0 -95
  431. package/src/tui/sextant-attach.ts +0 -102
  432. package/src/tui/sextant-io.ts +0 -202
  433. package/src/tui/sextant-smoke.ts +0 -110
  434. package/src/tui/shell-cmd.ts +0 -158
  435. package/src/tui/smoke.ts +0 -72
  436. package/src/tui/staged-terminal.ts +0 -50
  437. package/src/tui/startup.ts +0 -12
  438. package/src/tui/theme.ts +0 -59
  439. package/src/tui/todo-label.ts +0 -7
  440. package/src/tui/trust-card.ts +0 -107
  441. package/src/tui/tui-commands.ts +0 -87
  442. package/tsconfig.json +0 -30
  443. package/vendor/pi-tui/LICENSE +0 -21
  444. package/vendor/pi-tui/PATCHES.md +0 -12
  445. package/vendor/pi-tui/PROVENANCE.md +0 -12
  446. package/vendor/pi-tui/README.upstream.md +0 -854
  447. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  448. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  449. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  450. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  451. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  452. package/vendor/pi-tui/src/components/box.ts +0 -138
  453. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  454. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  455. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  456. package/vendor/pi-tui/src/components/image.ts +0 -128
  457. package/vendor/pi-tui/src/components/input.ts +0 -448
  458. package/vendor/pi-tui/src/components/loader.ts +0 -93
  459. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  460. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  461. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  462. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  463. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  464. package/vendor/pi-tui/src/components/stack.ts +0 -155
  465. package/vendor/pi-tui/src/components/text.ts +0 -108
  466. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  467. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  468. package/vendor/pi-tui/src/editor-component.ts +0 -75
  469. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  470. package/vendor/pi-tui/src/index.ts +0 -149
  471. package/vendor/pi-tui/src/keybindings.ts +0 -321
  472. package/vendor/pi-tui/src/keys.ts +0 -1402
  473. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  474. package/vendor/pi-tui/src/latex.ts +0 -1381
  475. package/vendor/pi-tui/src/layout-node.ts +0 -52
  476. package/vendor/pi-tui/src/layout.ts +0 -411
  477. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  478. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  479. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  480. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  481. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  482. package/vendor/pi-tui/src/terminal.ts +0 -554
  483. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  484. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  485. package/vendor/pi-tui/src/tui.ts +0 -1264
  486. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  487. package/vendor/pi-tui/src/utils.ts +0 -1327
  488. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  489. package/vendor/pi-tui/test/test-themes.ts +0 -39
  490. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  491. /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
- }