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,378 +0,0 @@
1
- /** The connect wizard (/connect, /setup on the sextant surface): ONE overlay that walks a model
2
- * connection end to end — provider, key, model, test — instead of a chain of pickers that each
3
- * close and reopen. Berkay's design, chosen 2026-09-08: a COLUMNED wizard, the left column the step
4
- * headers (✓ done / ● current / ○ ahead) and the right side the current step's content, separated by
5
- * SPACE (his pick over a dim rule and a filled block), so the header column reads as an index rather
6
- * than a frame.
7
- *
8
- * Like draw-context.ts this file owns FLAT view types and imports no registry: the adapter that opens
9
- * the wizard (sextant-renderer.ts openWizard) maps the provider table onto `WizardState`, and the
10
- * effects the keys request come back as requests the renderer owns (keys.ts has no registry either).
11
- * A test builds a state by hand.
12
- *
13
- * THE SECRET ROW: the key step's input is masked (•••). This is the only typed secret anywhere in the
14
- * surface — the question card types in the clear because its answers are conversation, and /provider
15
- * key refuses on-card entry for the same reason this wizard exists: a key typed in the clear lands in
16
- * the transcript. The wizard is not the composer; its input is a form field. */
17
-
18
- import { st } from "./draw-util.ts";
19
- import { openOverlay } from "./overlays.ts";
20
- import { ATTR, type HitZone, type KeyEvent, type Layout, type ScreenLike, type SextantState, type Theme } from "./types.ts";
21
-
22
- // ------------------------------------------------------------------ state
23
-
24
- /** one provider row in step 1 — flat, from SETUP_PICKS + the registry's knowledge */
25
- export interface WizardProvider {
26
- key: string;
27
- label: string;
28
- /** true when the registry already has a working entry: shown, and stepping onto it skips to MODEL */
29
- configured?: boolean;
30
- /** a local server: the KEY step is skipped for it */
31
- local?: boolean;
32
- /** one of the two "your own URL" doors (SETUP_PICKS 8/9): no registry row exists until the wizard
33
- * has asked for a short id and a base URL and REGISTERED it — the protocol the row speaks */
34
- url?: "openai" | "anthropic";
35
- }
36
-
37
- /** what step 3 lists: the models the registry can name for the chosen provider (endpoint or file).
38
- * `active` = the provider's pinned list today (spec.models — what /models serves from the file);
39
- * `defaultModel` = the row's default. Both are FACTS the row carries, painted as tags, and the
40
- * checked set starts FROM `active` so the step's opening state is the provider's current truth
41
- * rather than a blank form that silently re-pins everything away. */
42
- export interface WizardModel { id: string; note?: string; active?: boolean; defaultModel?: boolean }
43
-
44
- /** The four steps, in walk order. ENDPOINT (id + base URL) is walked only for a url door row.
45
- * There is no TEST step (Berkay, 2026-09-10): the walk ENDS at MODEL — the checked list is pinned
46
- * and the default set the moment ⏎ confirms, no probe call runs after it. */
47
- export const WIZARD_STEPS = ["PROVIDER", "ENDPOINT", "KEY", "MODEL"] as const;
48
- export type WizardStepName = (typeof WIZARD_STEPS)[number];
49
-
50
- export interface WizardState {
51
- /** 0..4 — WIZARD_STEPS[step] is current; a url door walks ENDPOINT (1), a local server skips KEY (2) */
52
- step: number;
53
- providers: WizardProvider[];
54
- /** index into `providers` once chosen */
55
- selected: number;
56
- /** the typed short id (ENDPOINT step) — the registry row this door will register under */
57
- idTyped: string;
58
- /** the typed base URL (ENDPOINT step) */
59
- urlTyped: string;
60
- /** which of the two ENDPOINT fields the caret is on: false = the id, true = the URL */
61
- urlField: boolean;
62
- /** the masked key input — the secret itself, never painted */
63
- secret: string;
64
- /** false while the key step is being confirmed: a paste that failed to store stays editable */
65
- keyAccepted: boolean;
66
- models: WizardModel[];
67
- /** index into `models`, or -1 when the list is empty and the id is typed */
68
- modelSel: number;
69
- /** the CHECKED model ids, in list order — what confirmModels carries as `models`. Space toggles
70
- * the row under the caret; the set starts as the provider's `active` list, so an untouched walk
71
- * through the step re-pins exactly what was already pinned (no silent change). */
72
- modelChecked: readonly string[];
73
- /** the id ⏎ will name as makeDefault: the marked row, or the FIRST checked one. The default is a
74
- * separate fact from the list — every checked row becomes active, exactly one becomes default. */
75
- modelDefaultTo: string | undefined;
76
- /** the typed model id when the list is empty (a proxy with no /models endpoint) */
77
- modelTyped: string;
78
- /** true from the moment the step opens until the endpoint answers (or fails): an empty list the
79
- * person can SEE is loading is a different thing from an empty list that claims there is none */
80
- modelsLoading: boolean;
81
- /** one line under the content when a step refused to advance (bad key, empty model id…) */
82
- error?: string;
83
- }
84
-
85
- /** open the wizard at its first step; the adapter has already built the provider rows */
86
- export function openWizard(s: SextantState, providers: WizardProvider[]): void {
87
- openOverlay(s, null); // one overlay at a time — closes palette/market/help/context like every opener
88
- s.wizard = { step: 0, providers, selected: 0, idTyped: "", urlTyped: "", urlField: false, secret: "", keyAccepted: false, models: [], modelSel: 0, modelChecked: [], modelDefaultTo: undefined, modelTyped: "", modelsLoading: false };
89
- }
90
- export function closeWizard(s: SextantState): void { s.wizard = null; }
91
-
92
- // ------------------------------------------------------------------ view (pure — tests read these)
93
-
94
- export const MASK = "•";
95
- /** the masked row: one • per code point, capped so a pasted 2 KB token cannot push the layout */
96
- export const MASKED_MAX = 24;
97
- export function masked(secret: string): string {
98
- const n = [...secret].length;
99
- return MASK.repeat(Math.min(n, MASKED_MAX)) + (n > MASKED_MAX ? ` ${n - MASKED_MAX} more` : "");
100
- }
101
-
102
- /** the left column's marker for step i: done, current or ahead */
103
- export function stepMarker(i: number, step: number): string { return i < step ? "✓" : i === step ? "●" : "○"; }
104
-
105
- /** what the right side of each step shows, as plain lines tagged with a tone — the drawer paints them,
106
- * the tests pin them. `secretLine` is the masked row; `caret` marks the row the caret sits on. */
107
- export type WizardTone = "head" | "normal" | "dim" | "warn" | "ok" | "accent";
108
- export interface WizardLine { text: string; tone: WizardTone; caret?: boolean }
109
-
110
- export function wizardLines(w: WizardState): WizardLine[] {
111
- const provider = w.providers[w.selected];
112
- const out: WizardLine[] = [];
113
- if (w.step === 0) {
114
- out.push({ text: "Which provider? ↑↓ choose, ⏎ confirm.", tone: "head" });
115
- w.providers.forEach((p, i) => out.push({ text: `${i === w.selected ? "❯ " : " "}${p.label}${p.configured ? " · already set up" : ""}`, tone: i === w.selected ? "accent" : "normal" }));
116
- return out;
117
- }
118
- if (provider === undefined) return out;
119
- if (w.step === 1) {
120
- // the url door's own two fields: a short id (the registry row this becomes) and the base URL.
121
- // ONE caret — on the active field, after its text (the inactive field is dim, no caret anywhere
122
- // else: two ▌ on screen at once read as two fields being typed into at the same time).
123
- const idCaret = !w.urlField;
124
- out.push({ text: `${provider.label.split(" (")[0] ?? provider.label} — name it and point it at the server.`, tone: "head" });
125
- out.push({ text: `Short name? ${w.idTyped}${idCaret ? "▌" : ""}`, tone: idCaret ? "normal" : "dim", ...(idCaret ? { caret: true } : {}) });
126
- out.push({ text: `Base URL? ${w.urlTyped}${w.urlField ? "▌" : ""}`, tone: w.urlField ? "normal" : "dim", ...(w.urlField ? { caret: true } : {}) });
127
- out.push({ text: "⇥ switches the field · ⏎ registers it and moves to the key", tone: "dim" });
128
- if (w.error !== undefined) out.push({ text: w.error, tone: "warn" });
129
- return out;
130
- }
131
- if (w.step === 2) {
132
- out.push({ text: `Paste the API key for ${provider.label.split(" — ")[0] ?? provider.label}.`, tone: "head" });
133
- out.push({ text: "It is stored in the credentials file, never in the transcript.", tone: "dim" });
134
- out.push({ text: "", tone: "dim" });
135
- out.push({ text: masked(w.secret) || "", tone: "normal", caret: true });
136
- if (w.error !== undefined) out.push({ text: w.error, tone: "warn" });
137
- return out;
138
- }
139
- if (w.step === 3) {
140
- out.push({ text: `Which models on ${provider.label.split(" — ")[0] ?? provider.label}? Space checks, ⏎ confirms.`, tone: "head" });
141
- if (w.modelsLoading && w.models.length === 0) {
142
- out.push({ text: "Fetching the model list from the endpoint…", tone: "accent" });
143
- return out;
144
- }
145
- if (w.models.length > 0) {
146
- w.models.forEach((m, i) => {
147
- // the checkbox is the row's state (✓ checked / ☐ not); the tags behind the id are the
148
- // provider's OWN facts — `active` (pinned today) and `default` — so the person edits a list
149
- // they can see the current truth of, and `•` marks which checked row becomes the default
150
- const checked = w.modelChecked.includes(m.id);
151
- const tags = `${m.active === true ? " · active" : ""}${m.defaultModel === true ? " · default" : ""}`;
152
- const mark = checked && w.modelDefaultTo === m.id ? "•" : "";
153
- out.push({ text: `${i === w.modelSel ? "❯ " : " "}${checked ? "✓" : "☐"} ${m.id}${tags}${mark ? ` ${mark}` : ""}`, tone: i === w.modelSel ? "accent" : "normal" });
154
- });
155
- } else {
156
- out.push({ text: "No model list from this endpoint — type the model id:", tone: "dim" });
157
- out.push({ text: w.modelTyped, tone: "normal", caret: true });
158
- }
159
- if (w.error !== undefined) out.push({ text: w.error, tone: "warn" });
160
- return out;
161
- }
162
- return out;
163
- }
164
-
165
- // ------------------------------------------------------------------ draw
166
-
167
- export function drawWizard(scr: ScreenLike, L: Layout, C: Theme, s: SextantState, hits?: HitZone[]): { x: number; y: number } | null {
168
- const w = s.wizard;
169
- if (!w) return null;
170
- hits?.push({ rect: { x: 0, y: 0, w: L.w, h: L.h }, onClick: () => { /* the box below swallows it */ } });
171
-
172
- const lines = wizardLines(w);
173
- const w0 = Math.min(L.w - 4, 64);
174
- const h = Math.max(10, Math.min(L.h - 4, Math.max(WIZARD_STEPS.length, lines.length) + 5));
175
- const x = Math.floor((L.w - w0) / 2), y = Math.max(1, Math.floor((L.h - h) / 2));
176
- scr.box(x, y, w0, h, st(C.accent), C.bg2);
177
- scr.text(x + 2, y, [[" connect a model ", st(C.accent, -1, ATTR.BOLD)]]);
178
- scr.put(x + w0 - 13, y, " esc closes ", st(C.dim, C.bg2));
179
- hits?.push({ rect: { x, y, w: w0, h }, onClick: () => {} }); // a click inside is not a close
180
-
181
- // the left column: the step headers, MARKED — done ✓ / current ● / ahead ○. Space separates the
182
- // columns (Berkay's pick): no rule, no fill — the markers carry the progression on their own.
183
- const leftW = 13;
184
- WIZARD_STEPS.forEach((name, i) => {
185
- const current = i === w.step;
186
- scr.put(x + 2, y + 2 + i, `${stepMarker(i, w.step)} ${name}`, current ? st(C.accent, C.bg2, ATTR.BOLD) : i < w.step ? st(C.fg2, C.bg2) : st(C.muted, C.bg2));
187
- });
188
-
189
- // the right side: the step's lines, clipped to the inner width, with the caret row on the box's edge
190
- const innerX = x + 2 + leftW + 2;
191
- const innerW = Math.max(10, w0 - (innerX - x) - 3);
192
- const rows = h - 3;
193
- lines.slice(0, rows).forEach((line, i) => {
194
- const style = line.tone === "head" ? st(C.fg, C.bg2, ATTR.BOLD)
195
- : line.tone === "warn" ? st(C.warn, C.bg2)
196
- : line.tone === "ok" ? st(C.ok, C.bg2)
197
- : line.tone === "accent" ? st(C.accent, C.bg2)
198
- : line.tone === "dim" ? st(C.muted, C.bg2)
199
- : st(C.fg2, C.bg2);
200
- // a caret row with TEXT carries its own ▌ in the text (the endpoint fields); an EMPTY caret row
201
- // (the masked secret, the typed model id) gets the ▌ painted here — exactly one caret either way
202
- const text = line.text === "" && line.caret ? "" : line.text;
203
- scr.clip(innerX, y + 1 + i, line.caret && line.text === "" ? `${text}▌` : text, style, innerW + 1);
204
- });
205
-
206
- // the footer hints, under both columns
207
- const back = w.step > 0 ? " ← back" : "";
208
- scr.put(x + 2, y + h - 1, `⏎ ${w.step === 0 ? "choose" : "next"}${back} esc cancel`, st(C.dim, C.bg2));
209
- return null; // no composer caret: the wizard paints its own on the secret/model row
210
- }
211
-
212
- // ------------------------------------------------------------------ keys
213
-
214
- /** What a key asked the renderer to DO. keys.ts owns no registry: the requests come back here and
215
- * sextant-renderer.ts runs them against the live runtime. `none` = the key only moved the state. */
216
- export type WizardRequest =
217
- | { kind: "none" }
218
- /** ENDPOINT confirmed for a url door: register the row (reg.add) under this id/URL/protocol */
219
- | { kind: "registerEndpoint"; id: string; url: string; protocol: "openai" | "anthropic" }
220
- /** KEY confirmed with a non-empty secret: store it (saveCredential + refresh) */
221
- | { kind: "storeKey"; provider: string; secret: string }
222
- /** MODEL confirmed (from a list): the CHECKED ids in list order — what the provider's active list
223
- * becomes (setModels) — and `makeDefault`, the id that also becomes the default (the marked row,
224
- * else the first checked; undefined only in the typed fallback, where there is no list to edit) */
225
- | { kind: "confirmModels"; provider: string; models: string[]; makeDefault: string | undefined }
226
- /** MODEL confirmed by TYPING (no list from the endpoint): one id, no list to pin */
227
- | { kind: "confirmModel"; model: string }
228
- /** the model step OPENED (or was re-entered after a key change): load the endpoint's list —
229
- * the renderer fetches through the wizardModels seam and answers with wizardModelConfirmed */
230
- | { kind: "loadModels" };
231
-
232
- /** A paste, while the wizard is up — the KEY step's whole input method: a key arrives as ONE paste
233
- * event, not as keystrokes, and keys.ts's onPaste routes every paste it does not recognise into the
234
- * composer (which is how the pasted key ended up in the chat box). Returns true when the paste was
235
- * consumed: KEY appends to the secret, MODEL appends to the typed id when there is no list, and
236
- * every other step swallows it (a paste onto a list step is not a selection). Multi-line text
237
- * collapses to one space — a secret or a model id is one line, and a trailing newline from a
238
- * terminal copy never becomes part of it. */
239
- export function wizardPaste(s: SextantState, text: string): boolean {
240
- const w = s.wizard;
241
- if (!w) return false;
242
- const one = text.replace(/\s+/g, " ");
243
- if (w.step === 1) { if (w.urlField) w.urlTyped += one; else w.idTyped += one; }
244
- else if (w.step === 2) w.secret += one;
245
- else if (w.step === 3 && w.models.length === 0) w.modelTyped += one;
246
- else return true; // swallowed, not typed: nothing leaves the overlay
247
- w.error = undefined;
248
- return true;
249
- }
250
-
251
- /** Keys, while the wizard is up. Swallows everything (an overlay that let keystrokes reach the
252
- * composer would type into a message the human cannot see) except ⌃c, which closes like every overlay. */
253
- export function onWizardKey(s: SextantState, ev: KeyEvent): WizardRequest {
254
- const w = s.wizard;
255
- if (!w) return { kind: "none" };
256
- const { name, ctrl, ch, alt } = ev;
257
- if (name === "escape" || (ctrl && name === "c")) { closeWizard(s); return { kind: "none" }; }
258
-
259
- // the ENDPOINT step's two fields: ⇥ (and ⇧⇥) move the caret between the id and the URL
260
- if (w.step === 1) {
261
- if (name === "tab" || name === "shift-tab") { w.urlField = !w.urlField; return { kind: "none" }; }
262
- }
263
- const inList = w.step === 0 || (w.step === 3 && w.models.length > 0);
264
- if (inList) {
265
- const n = w.step === 0 ? w.providers.length : w.models.length;
266
- if (name === "up" || name === "k") { if (w.step === 0) w.selected = (w.selected - 1 + n) % n; else w.modelSel = (w.modelSel - 1 + n) % n; return { kind: "none" }; }
267
- if (name === "down" || name === "j") { if (w.step === 0) w.selected = (w.selected + 1) % n; else w.modelSel = (w.modelSel + 1) % n; return { kind: "none" }; }
268
- if (name === "tab" && w.step === 3) { w.modelSel = (w.modelSel + 1) % n; return { kind: "none" }; }
269
- // space on the model list: check/uncheck the row under the caret. Checking the FIRST box moves
270
- // the default marker onto it (there was none); unchecking the marked row moves the marker to the
271
- // next checked row — the default is always a checked id, never a ghost
272
- if ((name === "space" || (ch === " " && !ctrl && !alt)) && w.step === 3) { toggleModelCheck(w); return { kind: "none" }; }
273
- }
274
- if (name === "left" && w.step > 0) { w.step -= 1; w.error = undefined; return { kind: "none" }; }
275
- if (name === "enter") return wizardConfirm(s);
276
-
277
- // the three typing steps: ENDPOINT (the two fields), KEY, and MODEL when the list is empty AND
278
- // the fetch has answered (while loading there is no field to type into yet — keys wait)
279
- const typing = w.step === 1 || w.step === 2 || (w.step === 3 && w.models.length === 0 && !w.modelsLoading);
280
- if (typing) {
281
- if (name === "backspace") {
282
- if (w.step === 1) { if (w.urlField) w.urlTyped = [...w.urlTyped].slice(0, -1).join(""); else w.idTyped = [...w.idTyped].slice(0, -1).join(""); }
283
- else if (w.step === 2) w.secret = [...w.secret].slice(0, -1).join("");
284
- else w.modelTyped = [...w.modelTyped].slice(0, -1).join("");
285
- w.error = undefined;
286
- return { kind: "none" };
287
- }
288
- const c = name === "space" ? " " : ch;
289
- if (!c || alt || ctrl) return { kind: "none" };
290
- if (w.step === 1) { if (w.urlField) w.urlTyped += c; else w.idTyped += c; }
291
- else if (w.step === 2) w.secret += c;
292
- else w.modelTyped += c;
293
- w.error = undefined;
294
- return { kind: "none" };
295
- }
296
- return { kind: "none" };
297
- }
298
-
299
- /** ⏎ on the current step: advance, refuse with an error line, or emit the step's request */
300
- function wizardConfirm(s: SextantState): WizardRequest {
301
- const w = s.wizard!;
302
- const provider = w.providers[w.selected];
303
- if (w.step === 0) {
304
- if (provider === undefined) return { kind: "none" };
305
- w.error = undefined;
306
- // a url door names its endpoint first; a local server has no key step; a configured provider's key already works
307
- const skip = provider.url !== undefined ? 1 : provider.local === true || provider.configured === true ? 3 : 2;
308
- w.step = skip;
309
- return skip === 3 ? { kind: "loadModels" } : { kind: "none" };
310
- }
311
- if (w.step === 1) {
312
- if (provider === undefined || provider.url === undefined) return { kind: "none" };
313
- const id = w.idTyped.trim().toLowerCase();
314
- if (id.length === 0) { w.error = "the short name is empty — it becomes the registry row's id"; return { kind: "none" }; }
315
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(id)) { w.error = `"${id}" won't work as an id — letters, digits, - _ . (myproxy, vllm-home)`; return { kind: "none" }; }
316
- if (!/^https?:\/\//.test(w.urlTyped.trim())) { w.error = `"${w.urlTyped.trim()}" is not an http(s) URL — the base URL the server answers on`; return { kind: "none" }; }
317
- w.error = undefined;
318
- return { kind: "registerEndpoint", id, url: w.urlTyped.trim(), protocol: provider.url };
319
- }
320
- if (w.step === 2) {
321
- const secret = w.secret.trim();
322
- if (secret.length === 0) { w.error = "the key is empty — paste it, or ← back to change provider"; return { kind: "none" }; }
323
- if (provider === undefined) return { kind: "none" };
324
- w.error = undefined;
325
- return { kind: "storeKey", provider: provider.key, secret };
326
- }
327
- if (w.step === 3) {
328
- if (provider === undefined) return { kind: "none" };
329
- if (w.models.length > 0) {
330
- const checked = w.models.filter((m) => w.modelChecked.includes(m.id)).map((m) => m.id);
331
- if (checked.length === 0) { w.error = "no model checked — space checks a row, or ← back to the key"; return { kind: "none" }; }
332
- w.error = undefined;
333
- const makeDefault = w.modelDefaultTo !== undefined && checked.includes(w.modelDefaultTo) ? w.modelDefaultTo : checked[0]!;
334
- return { kind: "confirmModels", provider: provider.key, models: checked, makeDefault };
335
- }
336
- const model = w.modelTyped.trim();
337
- if (model.length === 0) { w.error = "no model chosen — pick a row or type the id"; return { kind: "none" }; }
338
- w.error = undefined;
339
- return { kind: "confirmModel", model };
340
- }
341
- return { kind: "none" };
342
- }
343
-
344
- /** the renderer's answers, written back onto the state: registerEndpoint → the row exists now (or
345
- * the error line says why not); storeKey → advance or refuse; confirmModel → the model list / advance;
346
- * runTest → the probe outcome. */
347
- export function wizardEndpointRegistered(w: WizardState, ok: boolean, error?: string): void {
348
- if (ok) { w.step = 2; w.error = undefined; }
349
- else w.error = error ?? "the endpoint could not be registered";
350
- }
351
- export function wizardKeyStored(w: WizardState, ok: boolean, error?: string): void {
352
- if (ok) { w.keyAccepted = true; w.step = 3; w.modelsLoading = true; w.error = undefined; }
353
- else { w.keyAccepted = false; w.error = error ?? "the key could not be stored"; }
354
- }
355
- export function wizardModelConfirmed(w: WizardState, models: WizardModel[]): void {
356
- w.models = models;
357
- w.modelsLoading = false;
358
- w.modelSel = 0;
359
- // the checked set starts as the provider's OWN active list (a fact the rows carry): an untouched
360
- // pass through the step re-pins what was pinned, and the default marker starts on the row that is
361
- // the provider's default today — the form opens on the current truth, not on blank
362
- w.modelChecked = models.filter((m) => m.active === true).map((m) => m.id);
363
- const def = models.find((m) => m.defaultModel === true);
364
- w.modelDefaultTo = def !== undefined && w.modelChecked.includes(def.id) ? def.id : w.modelChecked[0];
365
- w.step = 3;
366
- w.error = undefined;
367
- }
368
-
369
- /** space on a model row: check/uncheck it, keeping the default marker on a CHECKED row */
370
- export function toggleModelCheck(w: WizardState): void {
371
- const m = w.models[w.modelSel];
372
- if (m === undefined) return;
373
- const has = w.modelChecked.includes(m.id);
374
- const next = has ? w.modelChecked.filter((id) => id !== m.id) : [...w.modelChecked, m.id];
375
- w.modelChecked = next;
376
- if (w.modelDefaultTo === undefined || !next.includes(w.modelDefaultTo)) w.modelDefaultTo = next[0];
377
- w.error = undefined;
378
- }
@@ -1,230 +0,0 @@
1
- /** ported from the user's sextant v0.4.0 prototype, src/engine.js (+ wrap() from app.js lines 66-78) */
2
- /* Pure helpers for the panels: syntax tokenizer, diff hunks/line marks over jsdiff output, fuzzy
3
- match, word wrap, small formatters. The prototype's O(n·m) LCS diffLines() is NOT ported —
4
- jsdiff (Myers, already a dependency) produces the ops, which then feed the same hunk/mark code. */
5
-
6
- import { diffLines, type ChangeObject, type StructuredPatch } from "diff";
7
- import type { DiffHunk } from "./types.ts";
8
-
9
- export type Lang = "ts" | "json" | "md" | "text";
10
- export const LANG_NAME: Readonly<Record<Lang, string>> = { ts: "TypeScript", json: "JSON", md: "Markdown", text: "Plain Text" };
11
-
12
- /** split on \n, dropping the empty tail a trailing newline leaves */
13
- export const splitLines = (s: string): string[] => { const l = s.split("\n"); if (l.length && l[l.length - 1] === "") l.pop(); return l; };
14
- export const basename = (p: string): string => p.slice(p.lastIndexOf("/") + 1);
15
- export const dirname = (p: string): string => (p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "");
16
-
17
- /** language by extension; the TS tokenizer serves the whole JS/TS family (the prototype knew .ts/.tsx only) */
18
- export function langOf(p: string): Lang {
19
- if (/\.[cm]?[jt]sx?$/.test(p)) return "ts";
20
- if (/\.jsonc?$/.test(p)) return "json";
21
- if (/\.(md|markdown)$/.test(p)) return "md";
22
- return "text";
23
- }
24
-
25
- /* ------------------------------------------------------------ tokenizer */
26
-
27
- export type TokenClass = "kw" | "str" | "num" | "cm" | "fn" | "ty" | "pu" | "op" | "prop" | "id" | "key" | "dec" | "plain";
28
- export type Token = [string, TokenClass];
29
-
30
- const KW = new Set("import export from const let var function return if else async await new type interface extends implements class throw try catch finally for while of in as default void typeof instanceof null undefined true false this readonly declare satisfies keyof enum switch case break continue do yield static private public protected".split(" "));
31
- const TS_RE = /(\/\/.*)|("(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'|`(?:[^`\\]|\\.)*`)|(\b\d[\d_]*(?:\.\d+)?\b)|(@?[A-Za-z_$][\w$]*)|([{}()[\]])|([;,.:])|(=>|\?\?|\?\.|[<>=!+\-*/%&|^~?]+)/g;
32
-
33
- /** one source line → [text, class] runs; "text" is one plain run, "md" goes through tokenizeMd */
34
- export function tokenize(line: string, lang: string): Token[] {
35
- if (lang === "md") return tokenizeMd(line);
36
- if (lang === "text") return [[line, "plain"]];
37
- const out: Token[] = [];
38
- let last = 0;
39
- let m: RegExpExecArray | null;
40
- TS_RE.lastIndex = 0;
41
- while ((m = TS_RE.exec(line))) {
42
- if (m.index > last) out.push([line.slice(last, m.index), "plain"]);
43
- const tok = m[0];
44
- let cls: TokenClass;
45
- if (m[1]) cls = "cm";
46
- else if (m[2]) cls = lang === "json" && /^\s*:/.test(line.slice(m.index + tok.length)) ? "key" : "str";
47
- else if (m[3]) cls = "num";
48
- else if (m[4]) {
49
- const before = line[m.index - 1];
50
- const after = line.slice(m.index + tok.length);
51
- if (tok[0] === "@") cls = "dec";
52
- else if (KW.has(tok)) cls = "kw";
53
- else if (before === ".") cls = "prop";
54
- else if (/^\s*\(/.test(after) || (/^</.test(after) && /^[a-z]/.test(tok))) cls = "fn";
55
- else if (/^[A-Z]/.test(tok)) cls = "ty";
56
- else if (/^\??:/.test(after)) cls = "prop";
57
- else cls = "id";
58
- } else if (m[5] || m[6]) cls = "pu";
59
- else cls = "op";
60
- out.push([tok, cls]);
61
- last = m.index + tok.length;
62
- }
63
- if (last < line.length) out.push([line.slice(last), "plain"]);
64
- return out;
65
- }
66
-
67
- export function tokenizeMd(line: string): Token[] {
68
- if (/^#{1,6}\s/.test(line)) return [[line, "kw"]];
69
- if (/^\s{4}/.test(line)) return [[line, "str"]];
70
- const out: Token[] = [];
71
- let last = 0;
72
- let m: RegExpExecArray | null;
73
- const re = /`[^`]+`/g;
74
- while ((m = re.exec(line))) {
75
- if (m.index > last) out.push([line.slice(last, m.index), "plain"]);
76
- out.push([m[0], "str"]);
77
- last = m.index + m[0].length;
78
- }
79
- if (last < line.length) out.push([line.slice(last), "plain"]);
80
- return out;
81
- }
82
-
83
- /* ------------------------------------------------------------ diff */
84
-
85
- export type OpKind = "eq" | "del" | "ins";
86
- /** one diff line; an/bn are the 1-based old/new line numbers (absent on the side the line is not on) */
87
- export interface DiffOp { t: OpKind; text: string; an?: number; bn?: number }
88
- /** a run of ops with its @@ header numbers: old start/count, new start/count */
89
- export interface Hunk { ops: DiffOp[]; as: number; bs: number; ac: number; bc: number }
90
- export type LineMark = "added" | "changed";
91
-
92
- /** jsdiff diffLines() change objects → the prototype's op list with line numbers */
93
- export function opsFromChanges(changes: readonly ChangeObject<string>[]): DiffOp[] {
94
- const ops: DiffOp[] = [];
95
- let an = 0, bn = 0;
96
- for (const c of changes) {
97
- const lines = c.value.split("\n");
98
- if (lines.length > c.count) lines.pop(); // the value ends with its last line's newline
99
- for (const text of lines) {
100
- if (c.added) ops.push({ t: "ins", text, bn: ++bn });
101
- else if (c.removed) ops.push({ t: "del", text, an: ++an });
102
- else ops.push({ t: "eq", text, an: ++an, bn: ++bn });
103
- }
104
- }
105
- return ops;
106
- }
107
-
108
- /** line-diff two texts (jsdiff Myers) → ops; replaces the prototype's O(n·m) LCS table */
109
- export function diffOps(a: string, b: string): DiffOp[] {
110
- return opsFromChanges(diffLines(a, b));
111
- }
112
-
113
- /** added/deleted line counts */
114
- export const opStats = (ops: readonly DiffOp[]): { a: number; d: number } => {
115
- let a = 0, d = 0;
116
- for (const o of ops) { if (o.t === "ins") a++; else if (o.t === "del") d++; }
117
- return { a, d };
118
- };
119
-
120
- function hunkOf(ops: readonly DiffOp[], s: number, e: number): Hunk {
121
- const slice = ops.slice(s, e);
122
- let as: number | null = null, bs: number | null = null, ac = 0, bc = 0;
123
- for (const o of slice) {
124
- if (o.an) { if (as == null) as = o.an; ac++; }
125
- if (o.bn) { if (bs == null) bs = o.bn; bc++; }
126
- }
127
- return { ops: slice, as: as ?? 0, bs: bs ?? 0, ac, bc };
128
- }
129
-
130
- /** group changes into hunks with `ctx` context lines; changes closer than 2·ctx share a hunk; Infinity = one hunk */
131
- export function buildHunks(ops: readonly DiffOp[], ctx: number): Hunk[] {
132
- if (!isFinite(ctx)) return ops.length ? [hunkOf(ops, 0, ops.length)] : [];
133
- const hunks: Hunk[] = [];
134
- let i = 0;
135
- while (i < ops.length) {
136
- if (ops[i]!.t === "eq") { i++; continue; }
137
- const start = Math.max(0, i - ctx);
138
- let end = i + 1, j = i + 1;
139
- while (j < ops.length) {
140
- if (ops[j]!.t !== "eq") { end = j + 1; j++; continue; }
141
- let k = j;
142
- while (k < ops.length && ops[k]!.t === "eq") k++;
143
- if (k < ops.length && k - j <= ctx * 2) { j = k; continue; }
144
- break;
145
- }
146
- end = Math.min(ops.length, end + ctx);
147
- hunks.push(hunkOf(ops, start, end));
148
- i = end;
149
- }
150
- return hunks;
151
- }
152
-
153
- /** new-line-number → "added" (pure insertion) | "changed" (insertion next to a deletion) */
154
- export function lineMarks(ops: readonly DiffOp[]): Map<number, LineMark> {
155
- const marks = new Map<number, LineMark>();
156
- let i = 0;
157
- while (i < ops.length) {
158
- if (ops[i]!.t === "eq") { i++; continue; }
159
- let j = i, hasDel = false;
160
- while (j < ops.length && ops[j]!.t !== "eq") { if (ops[j]!.t === "del") hasDel = true; j++; }
161
- for (let k = i; k < j; k++) { const o = ops[k]!; if (o.t === "ins" && o.bn) marks.set(o.bn, hasDel ? "changed" : "added"); }
162
- i = j;
163
- }
164
- return marks;
165
- }
166
-
167
- /** a prototype hunk → the contract's DiffHunk rows */
168
- export function toDiffHunk(h: Hunk): DiffHunk {
169
- return { rows: h.ops.map((o) => ({ op: o.t === "ins" ? "+" : o.t === "del" ? "-" : " ", text: o.text })), oldStart: h.as, newStart: h.bs };
170
- }
171
-
172
- /** jsdiff structuredPatch() hunks → the contract's DiffHunk rows ("" stays a context row) */
173
- export function hunksFromPatch(patch: StructuredPatch): DiffHunk[] {
174
- return patch.hunks.map((h) => ({
175
- oldStart: h.oldStart,
176
- newStart: h.newStart,
177
- rows: h.lines.map((l) => {
178
- const c = l[0];
179
- const op = c === "+" ? "+" : c === "-" ? "-" : " ";
180
- return { op, text: c === "+" || c === "-" || c === " " ? l.slice(1) : l };
181
- }),
182
- }));
183
- }
184
-
185
- /* ------------------------------------------------------------ fuzzy */
186
-
187
- export interface FuzzyMatch { score: number; idx: number[] }
188
-
189
- /** subsequence match, case-insensitive: +3 for a run, +1 otherwise, +2 at a word/path start; null when q is not in s */
190
- export function fuzzy(q: string, s: string): FuzzyMatch | null {
191
- q = q.toLowerCase(); s = s.toLowerCase();
192
- let qi = 0, score = 0, last = -2;
193
- const idx: number[] = [];
194
- for (let i = 0; i < s.length && qi < q.length; i++) {
195
- if (s[i] === q[qi]) {
196
- idx.push(i);
197
- score += (last === i - 1 ? 3 : 1) + (i === 0 || s[i - 1] === " " || s[i - 1] === "/" ? 2 : 0);
198
- last = i; qi++;
199
- }
200
- }
201
- return qi === q.length ? { score, idx } : null;
202
- }
203
-
204
- /* ------------------------------------------------------------ text */
205
-
206
- /** greedy word wrap per paragraph (\n); a word longer than width is hard-split (app.js wrap) */
207
- export function wrap(text: string, width: number): string[] {
208
- width = Math.max(1, width); // width ≤ 0 never advanced the hard-split loop below (prototype quirk)
209
- const out: string[] = [];
210
- for (const para of String(text).split("\n")) {
211
- let line = "";
212
- for (const w of para.split(" ")) {
213
- if (!line) { line = w; continue; }
214
- if (line.length + 1 + w.length <= width) line += " " + w; else { out.push(line); line = w; }
215
- }
216
- while (line.length > width) { out.push(line.slice(0, width)); line = line.slice(width); }
217
- out.push(line);
218
- }
219
- return out;
220
- }
221
-
222
- /** mm:ss.t run clock */
223
- export const fmtClock = (ms: number): string => {
224
- const s = Math.max(0, ms) / 1000;
225
- const m = Math.floor(s / 60);
226
- const r = s - m * 60;
227
- return `${String(m).padStart(2, "0")}:${r.toFixed(1).padStart(4, "0")}`;
228
- };
229
- export const fmtDur = (ms: number): string => (ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`);
230
- export const fmtK = (n: number): string => (n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n));
@@ -1,25 +0,0 @@
1
- /** Click zones on the outer frame's two border rows (draw-frame.ts headerRight / footerRight): the
2
- * unread badge `◆ N` opens the notices (⌃b), the theme name in the footer tag cycles the theme (⌃t),
3
- * and `effort X` prefills `/effort ` so the levels appear as suggestions. The words are located by
4
- * the same segment math the painter uses, so a zone is exactly the word it reads. */
5
- import { footerRight, headerRight } from "./draw-frame.ts";
6
- import { segWidth } from "./layout.ts";
7
- import type { HitZone, Rect, SextantState, Theme } from "./types.ts";
8
-
9
- export function frameHits(F: Rect, s: SextantState, theme: Theme, now: number): HitZone[] {
10
- const out: HitZone[] = [];
11
- const head = headerRight(s, theme, now);
12
- const hx = F.x + F.w - 2 - segWidth(head.segs);
13
- if (head.badge) out.push({ rect: { x: hx + head.badge[0], y: F.y, w: head.badge[1], h: 1 }, onClick: () => {}, key: { type: "key", name: "b", ctrl: true } });
14
- const foot = footerRight(s, theme);
15
- const fx = F.x + F.w - 2 - segWidth(foot.segs), fy = F.y + F.h - 1;
16
- if (foot.effort) {
17
- out.push({
18
- rect: { x: fx + foot.effort[0], y: fy, w: foot.effort[1], h: 1 },
19
- // the prompt gets `/effort ` with the cursor at the end; the suggestion strip then lists the levels
20
- onClick: () => { s.input.text = "/effort "; s.input.cur = s.input.text.length; s.input.sgSel = 0; s.focus = "messages"; },
21
- });
22
- }
23
- out.push({ rect: { x: fx + foot.theme[0], y: fy, w: foot.theme[1], h: 1 }, onClick: () => {}, key: { type: "key", name: "t", ctrl: true } });
24
- return out;
25
- }