rovecode 0.3.3 → 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 -48
  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 +83 -72
  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,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
- }