rovecode 0.3.2 → 0.4.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (491) hide show
  1. package/CHANGELOG.md +512 -0
  2. package/README.md +33 -45
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-dybnr56b.js +2 -0
  5. package/dist/cli/ask-user-p8hq4xgj.js +2 -0
  6. package/dist/cli/auth-login-ewpgw5sm.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-xv3ypwev.js +9 -0
  9. package/dist/cli/catalog-737wb2s0.js +2 -0
  10. package/dist/cli/cli-arhg40m0.js +2 -0
  11. package/dist/cli/client-cf2pxx8q.js +2 -0
  12. package/dist/cli/commands-3p7e4xxs.js +2 -0
  13. package/dist/cli/connect-3q93d7cb.js +2 -0
  14. package/dist/cli/context-cmd-eqxmxhzq.js +2 -0
  15. package/dist/cli/context-report-hbw9zfes.js +2 -0
  16. package/dist/cli/count-remote-mby98cd0.js +2 -0
  17. package/dist/cli/design-122y0axd.js +2 -0
  18. package/dist/cli/dispatch-b4egzvvh.js +2 -0
  19. package/dist/cli/doctor-x4jkv72e.js +3 -0
  20. package/dist/cli/executor-ftvg6tsy.js +2 -0
  21. package/dist/cli/export-pdgdhkch.js +2 -0
  22. package/dist/cli/files-cez9a96p.js +2 -0
  23. package/dist/cli/gauntlet-r3xxaszc.js +2 -0
  24. package/dist/cli/gauntlet-runner-r515m7kk.js +10 -0
  25. package/dist/cli/gauntlet-wave3-bnkjk2v2.js +5 -0
  26. package/dist/cli/gauntlet-wave4-acs9s60q.js +14 -0
  27. package/dist/cli/hashline-ewg5hbe3.js +2 -0
  28. package/dist/cli/http-n0kehsk8.js +5 -0
  29. package/dist/cli/index-z5qt1s76.js +2 -0
  30. package/dist/cli/install-80mp63kx.js +2 -0
  31. package/dist/cli/loop-12twjcat.js +2 -0
  32. package/dist/cli/main-01pv9206.js +4 -0
  33. package/dist/cli/main-0jys2ccn.js +3 -0
  34. package/dist/cli/main-1ztz6fkj.js +10 -0
  35. package/dist/cli/main-23q7cmww.js +9 -0
  36. package/dist/cli/main-2rzbexn2.js +3 -0
  37. package/dist/cli/main-2wyax8k9.js +9 -0
  38. package/dist/cli/main-2yeveeve.js +6 -0
  39. package/dist/cli/main-2z3dek0b.js +3 -0
  40. package/dist/cli/main-2zgsknth.js +3 -0
  41. package/dist/cli/main-45ejth3a.js +4 -0
  42. package/dist/cli/main-45rn3trk.js +22 -0
  43. package/dist/cli/main-4p4e2w7x.js +4 -0
  44. package/dist/cli/main-4y0tnfpa.js +16 -0
  45. package/dist/cli/main-5py0rkmc.js +4 -0
  46. package/dist/cli/main-6dtqmbt6.js +7 -0
  47. package/dist/cli/main-6h9x282m.js +4 -0
  48. package/dist/cli/main-6vjeds42.js +3 -0
  49. package/dist/cli/main-78gq4bt9.js +6 -0
  50. package/dist/cli/main-7jd5vh3x.js +4 -0
  51. package/dist/cli/main-7kt6r53y.js +4 -0
  52. package/dist/cli/main-8c1tbazx.js +58 -0
  53. package/dist/cli/main-9a9rnh47.js +19 -0
  54. package/dist/cli/main-9ht36z12.js +3 -0
  55. package/dist/cli/main-a2yfvcy9.js +7 -0
  56. package/dist/cli/main-a3f51n0x.js +5 -0
  57. package/dist/cli/main-b8zq261k.js +3 -0
  58. package/dist/cli/main-bxtvnf6d.js +13 -0
  59. package/dist/cli/main-edxc3yzt.js +4 -0
  60. package/dist/cli/main-evgz4mp5.js +21 -0
  61. package/dist/cli/main-f33fc5je.js +9 -0
  62. package/dist/cli/main-fvnpq46y.js +12 -0
  63. package/dist/cli/main-gbbty4d4.js +3 -0
  64. package/dist/cli/main-gth53dnt.js +25 -0
  65. package/dist/cli/main-hqbz10aw.js +9 -0
  66. package/dist/cli/main-hrrvcfan.js +38 -0
  67. package/dist/cli/main-hzwtsb2m.js +5 -0
  68. package/dist/cli/main-j7ttv0sd.js +34 -0
  69. package/dist/cli/main-jak598k9.js +5 -0
  70. package/dist/cli/main-kba6zeyd.js +6 -0
  71. package/dist/cli/main-kwwsz6rq.js +3 -0
  72. package/dist/cli/main-m8vm17zq.js +3 -0
  73. package/dist/cli/main-mg4f96e1.js +3 -0
  74. package/dist/cli/main-mg9b20ac.js +18 -0
  75. package/dist/cli/main-mgb9ccnx.js +3 -0
  76. package/dist/cli/main-mjt2p7aj.js +3 -0
  77. package/dist/cli/main-n6qrdbmy.js +3 -0
  78. package/dist/cli/main-na7wse0x.js +5 -0
  79. package/dist/cli/main-nqveez48.js +4 -0
  80. package/dist/cli/main-ntqef02r.js +10 -0
  81. package/dist/cli/main-nvc3yjay.js +136 -0
  82. package/dist/cli/main-p0cfn6nr.js +16 -0
  83. package/dist/cli/main-qj2djy17.js +19 -0
  84. package/dist/cli/main-qsevpgsv.js +3 -0
  85. package/dist/cli/main-qvarybsp.js +3 -0
  86. package/dist/cli/main-rebtt91r.js +5 -0
  87. package/dist/cli/main-rpg7h8mb.js +3 -0
  88. package/dist/cli/main-rsy72qmw.js +15 -0
  89. package/dist/cli/main-rvetps99.js +18 -0
  90. package/dist/cli/main-s4bb0jav.js +3 -0
  91. package/dist/cli/main-s9v8k74e.js +3 -0
  92. package/dist/cli/main-tjvwmscs.js +3 -0
  93. package/dist/cli/main-tkgarpjj.js +4 -0
  94. package/dist/cli/main-v8y60bb2.js +3 -0
  95. package/dist/cli/main-vhrrq337.js +3 -0
  96. package/dist/cli/main-vp2dfb7s.js +4 -0
  97. package/dist/cli/main-vqbr22sz.js +8 -0
  98. package/dist/cli/main-vxnwe5xx.js +18 -0
  99. package/dist/cli/main-wgph00xf.js +5 -0
  100. package/dist/cli/main-wk2csfnj.js +5 -0
  101. package/dist/cli/main-wm997zjx.js +3 -0
  102. package/dist/cli/main-wpkyraxh.js +3 -0
  103. package/dist/cli/main-wqt32p5x.js +4 -0
  104. package/dist/cli/main-x9ct6y1a.js +3 -0
  105. package/dist/cli/main-xfekqh9m.js +7 -0
  106. package/dist/cli/main-xt9zc3n6.js +7 -0
  107. package/dist/cli/main-xx2z3zh5.js +4 -0
  108. package/dist/cli/main-y5c82rxr.js +3 -0
  109. package/dist/cli/main-yrjt2sqt.js +14 -0
  110. package/dist/cli/main-ys6zj3yr.js +3 -0
  111. package/dist/cli/main-ywbxshqc.js +8 -0
  112. package/dist/cli/main-z13755t8.js +25 -0
  113. package/dist/cli/main-zc7pyrbj.js +4 -0
  114. package/dist/cli/main.js +279 -0
  115. package/dist/cli/market-cmd-bm5xvn9f.js +5 -0
  116. package/dist/cli/mcp-login-bthtfpt7.js +2 -0
  117. package/dist/cli/mcp-market-cmd-mbeshfyd.js +2 -0
  118. package/dist/cli/notify-54v5z9dz.js +2 -0
  119. package/dist/cli/oauth-g5gme95c.js +2 -0
  120. package/dist/cli/output-satndjap.js +16 -0
  121. package/dist/cli/profiles-sfhpbq3m.js +2 -0
  122. package/dist/cli/provider-config-hv3xtdt4.js +2 -0
  123. package/dist/cli/provider-kwzq6g84.js +2 -0
  124. package/dist/cli/registry-fh0hdnyn.js +2 -0
  125. package/dist/cli/registry-y1y8e94r.js +2 -0
  126. package/dist/cli/repl-t4z03mqq.js +11 -0
  127. package/dist/cli/resume-fqt4chg8.js +2 -0
  128. package/dist/cli/run-flags-rysbag9t.js +2 -0
  129. package/dist/cli/runtime-j19fjbsa.js +2 -0
  130. package/dist/cli/sandbox-config-g4qxd7y5.js +2 -0
  131. package/dist/cli/server-r0b6bksk.js +5 -0
  132. package/dist/cli/session-arg-txmn5g4x.js +2 -0
  133. package/dist/cli/session-ed250d9j.js +2 -0
  134. package/dist/cli/sessions-cmd-adw7svfn.js +7 -0
  135. package/dist/cli/settings-y9rzcqx8.js +2 -0
  136. package/dist/cli/setup-jmbr11j0.js +2 -0
  137. package/dist/cli/sextant-smoke-tcth0vea.js +5 -0
  138. package/dist/cli/skills-cmd-zbdy99v6.js +2 -0
  139. package/dist/cli/smoke-1bg937kx.js +8 -0
  140. package/dist/cli/start-chat-p01cdks3.js +12 -0
  141. package/dist/cli/stream-4wmyaypz.js +2 -0
  142. package/dist/cli/task-eg4s093s.js +2 -0
  143. package/dist/cli/tasks-12v9rr9k.js +2 -0
  144. package/dist/cli/thinking-a5ngvqyh.js +2 -0
  145. package/dist/cli/todo-1wxpcecx.js +2 -0
  146. package/dist/cli/tools-2ftsya7w.js +2 -0
  147. package/dist/cli/tools-x1tj4fxm.js +2 -0
  148. package/dist/cli/trust-cmd-hccxehzb.js +2 -0
  149. package/dist/cli/update-check-ygt3vd7m.js +2 -0
  150. package/dist/cli/update-cmd-v23qhr8c.js +2 -0
  151. package/dist/cli/voice-g1gtck92.js +2 -0
  152. package/dist/cli/webfetch-0nnrjgb5.js +2 -0
  153. package/dist/cli/websearch-f0vr2p7d.js +2 -0
  154. package/dist/cli/workspace-9rq1w4ta.js +2 -0
  155. package/dist/lib/index.js +62 -0
  156. package/dist/lib/models-index.json +1 -0
  157. package/dist/lib/plugins.js +6 -0
  158. package/dist/lib/providers.js +17 -0
  159. package/dist/lib/public-api.js +20 -0
  160. package/dist/rovecode.exe +4 -0
  161. package/package.json +38 -11
  162. package/bin/rovecode.ts +0 -21
  163. package/src/acp/server.ts +0 -374
  164. package/src/cli/auth-login.ts +0 -122
  165. package/src/cli/connect.ts +0 -244
  166. package/src/cli/context-cmd.ts +0 -199
  167. package/src/cli/dispatch.ts +0 -82
  168. package/src/cli/doctor.ts +0 -362
  169. package/src/cli/export.ts +0 -276
  170. package/src/cli/help.ts +0 -293
  171. package/src/cli/is-tui-invocation.ts +0 -8
  172. package/src/cli/main.ts +0 -583
  173. package/src/cli/market-cmd.ts +0 -658
  174. package/src/cli/mcp-login.ts +0 -141
  175. package/src/cli/mcp-market-cmd.ts +0 -302
  176. package/src/cli/output.ts +0 -382
  177. package/src/cli/repl.ts +0 -250
  178. package/src/cli/repomap-root.ts +0 -14
  179. package/src/cli/resume.ts +0 -57
  180. package/src/cli/run-flags.ts +0 -43
  181. package/src/cli/run-limits.ts +0 -78
  182. package/src/cli/runtime.ts +0 -931
  183. package/src/cli/session-arg.ts +0 -30
  184. package/src/cli/sessions-cmd.ts +0 -145
  185. package/src/cli/setup.ts +0 -153
  186. package/src/cli/skills-cmd.ts +0 -194
  187. package/src/cli/start-chat.ts +0 -65
  188. package/src/cli/trust-cmd.ts +0 -52
  189. package/src/coding/bash.ts +0 -148
  190. package/src/coding/checkpoints.ts +0 -327
  191. package/src/coding/diff.ts +0 -138
  192. package/src/coding/files.ts +0 -341
  193. package/src/coding/hashline.ts +0 -274
  194. package/src/coding/lsp-gate.ts +0 -254
  195. package/src/coding/lsp-servers.ts +0 -147
  196. package/src/coding/lsp.ts +0 -283
  197. package/src/coding/repomap-cache.ts +0 -99
  198. package/src/coding/repomap-files.ts +0 -192
  199. package/src/coding/repomap.ts +0 -481
  200. package/src/core/agents.ts +0 -255
  201. package/src/core/compaction.ts +0 -259
  202. package/src/core/config.ts +0 -289
  203. package/src/core/context-report.ts +0 -228
  204. package/src/core/context.ts +0 -60
  205. package/src/core/count-remote.ts +0 -107
  206. package/src/core/execpolicy-rules.ts +0 -196
  207. package/src/core/execpolicy.ts +0 -385
  208. package/src/core/executor.ts +0 -454
  209. package/src/core/guardrails.ts +0 -400
  210. package/src/core/hooks.ts +0 -411
  211. package/src/core/images.ts +0 -230
  212. package/src/core/intro.ts +0 -266
  213. package/src/core/loop.ts +0 -567
  214. package/src/core/modes.ts +0 -372
  215. package/src/core/orchestrator.ts +0 -245
  216. package/src/core/proc-group.ts +0 -48
  217. package/src/core/project-trust.ts +0 -98
  218. package/src/core/reflection.ts +0 -165
  219. package/src/core/sandbox-config.ts +0 -186
  220. package/src/core/session-id.ts +0 -24
  221. package/src/core/session-images.ts +0 -73
  222. package/src/core/session-ops.ts +0 -183
  223. package/src/core/session-text.ts +0 -29
  224. package/src/core/session.ts +0 -469
  225. package/src/core/settings.ts +0 -170
  226. package/src/core/tasks.ts +0 -646
  227. package/src/core/token-scale.ts +0 -108
  228. package/src/core/tools.ts +0 -309
  229. package/src/core/trust.ts +0 -104
  230. package/src/core/types.ts +0 -330
  231. package/src/core/update-check.ts +0 -171
  232. package/src/core/usage.ts +0 -204
  233. package/src/core/validate.ts +0 -121
  234. package/src/core/verify-gate.ts +0 -159
  235. package/src/core/verify.ts +0 -236
  236. package/src/core/voice.ts +0 -158
  237. package/src/core/win-job.ts +0 -183
  238. package/src/core/workspace.ts +0 -184
  239. package/src/design/audit.ts +0 -797
  240. package/src/design/direction.ts +0 -190
  241. package/src/design/rules.ts +0 -157
  242. package/src/eval/bench.ts +0 -150
  243. package/src/eval/gauntlet-runner.ts +0 -215
  244. package/src/eval/gauntlet-support.ts +0 -84
  245. package/src/eval/gauntlet-wave3.ts +0 -269
  246. package/src/eval/gauntlet-wave4.ts +0 -217
  247. package/src/eval/gauntlet.ts +0 -253
  248. package/src/index.ts +0 -17
  249. package/src/lanes/agy.ts +0 -95
  250. package/src/lanes/approval.ts +0 -24
  251. package/src/lanes/claude.ts +0 -129
  252. package/src/lanes/codex.ts +0 -127
  253. package/src/lanes/events.ts +0 -130
  254. package/src/lanes/job.ts +0 -142
  255. package/src/lanes/opencode.ts +0 -122
  256. package/src/lanes/process.ts +0 -184
  257. package/src/lanes/progress.ts +0 -183
  258. package/src/lanes/registry.ts +0 -178
  259. package/src/lanes/runner.ts +0 -124
  260. package/src/lanes/types.ts +0 -112
  261. package/src/market/catalogs/mcp-docs.json +0 -111
  262. package/src/market/catalogs/plugins.json +0 -111
  263. package/src/market/catalogs/skills.json +0 -478
  264. package/src/market/clone.ts +0 -72
  265. package/src/market/context-cost.ts +0 -121
  266. package/src/market/digest.ts +0 -106
  267. package/src/market/index.ts +0 -22
  268. package/src/market/install.ts +0 -578
  269. package/src/market/manifest.ts +0 -187
  270. package/src/market/prereq.ts +0 -145
  271. package/src/market/registry.ts +0 -363
  272. package/src/market/resolve.ts +0 -111
  273. package/src/market/types.ts +0 -236
  274. package/src/market/validate.ts +0 -227
  275. package/src/mcp/client.ts +0 -449
  276. package/src/mcp/config.ts +0 -252
  277. package/src/mcp/local-package.ts +0 -211
  278. package/src/mcp/market-catalog.ts +0 -84
  279. package/src/mcp/market-install.ts +0 -289
  280. package/src/mcp/market.ts +0 -362
  281. package/src/mcp/oauth.ts +0 -251
  282. package/src/mcp/prompts-resources.ts +0 -249
  283. package/src/mcp/shared.ts +0 -149
  284. package/src/mcp/status.ts +0 -67
  285. package/src/mcp/tools.ts +0 -275
  286. package/src/mcp/transport.ts +0 -122
  287. package/src/mcp/trust.ts +0 -25
  288. package/src/memory/blocks.ts +0 -278
  289. package/src/memory/recall.ts +0 -355
  290. package/src/memory/scope.ts +0 -182
  291. package/src/memory/store.ts +0 -105
  292. package/src/memory/tools.ts +0 -99
  293. package/src/plugins/cli.ts +0 -119
  294. package/src/plugins/discover.ts +0 -108
  295. package/src/plugins/index.ts +0 -50
  296. package/src/plugins/install.ts +0 -184
  297. package/src/plugins/load.ts +0 -124
  298. package/src/plugins/manifest.ts +0 -92
  299. package/src/plugins/state.ts +0 -83
  300. package/src/providers/auth.ts +0 -408
  301. package/src/providers/cache.ts +0 -223
  302. package/src/providers/catalog-local.ts +0 -160
  303. package/src/providers/catalog.ts +0 -421
  304. package/src/providers/middleware-context.ts +0 -86
  305. package/src/providers/middleware.ts +0 -373
  306. package/src/providers/model-list.ts +0 -23
  307. package/src/providers/oauth/common.ts +0 -105
  308. package/src/providers/oauth/device-code.ts +0 -107
  309. package/src/providers/oauth/github-copilot.ts +0 -146
  310. package/src/providers/oauth/loopback.ts +0 -158
  311. package/src/providers/oauth/openai.ts +0 -163
  312. package/src/providers/oauth/openrouter.ts +0 -89
  313. package/src/providers/oauth/pkce.ts +0 -45
  314. package/src/providers/oauth/registry.ts +0 -39
  315. package/src/providers/oauth/seam.ts +0 -89
  316. package/src/providers/profile-glm53.ts +0 -111
  317. package/src/providers/profile-sonnet5-persona.ts +0 -65
  318. package/src/providers/profile-sonnet5-voice.ts +0 -23
  319. package/src/providers/profiles.ts +0 -156
  320. package/src/providers/provider-config.ts +0 -311
  321. package/src/providers/registry.ts +0 -333
  322. package/src/providers/responses.ts +0 -209
  323. package/src/providers/retry.ts +0 -234
  324. package/src/providers/router.ts +0 -294
  325. package/src/providers/sse.ts +0 -26
  326. package/src/providers/stream-errors.ts +0 -117
  327. package/src/providers/stream.ts +0 -566
  328. package/src/providers/thinking.ts +0 -189
  329. package/src/providers/wire-messages.ts +0 -129
  330. package/src/providers/wire-responses.ts +0 -79
  331. package/src/providers/wire-select.ts +0 -53
  332. package/src/server/http.ts +0 -291
  333. package/src/server/openapi.ts +0 -246
  334. package/src/sextant/card-hits.ts +0 -102
  335. package/src/sextant/card-keys.ts +0 -55
  336. package/src/sextant/context-source.ts +0 -157
  337. package/src/sextant/crew-cards.ts +0 -350
  338. package/src/sextant/draw-agents.ts +0 -273
  339. package/src/sextant/draw-code.ts +0 -388
  340. package/src/sextant/draw-context.ts +0 -222
  341. package/src/sextant/draw-frame.ts +0 -164
  342. package/src/sextant/draw-market.ts +0 -573
  343. package/src/sextant/draw-messages.ts +0 -386
  344. package/src/sextant/draw-pet.ts +0 -230
  345. package/src/sextant/draw-plan.ts +0 -187
  346. package/src/sextant/draw-tabs.ts +0 -85
  347. package/src/sextant/draw-util.ts +0 -65
  348. package/src/sextant/draw-wizard.ts +0 -378
  349. package/src/sextant/engine.ts +0 -230
  350. package/src/sextant/frame-hits.ts +0 -25
  351. package/src/sextant/frame.ts +0 -101
  352. package/src/sextant/git-status.ts +0 -197
  353. package/src/sextant/grid.ts +0 -59
  354. package/src/sextant/input.ts +0 -119
  355. package/src/sextant/keys.ts +0 -521
  356. package/src/sextant/layout.ts +0 -86
  357. package/src/sextant/local-commands.ts +0 -169
  358. package/src/sextant/market-source.ts +0 -287
  359. package/src/sextant/mentions.ts +0 -200
  360. package/src/sextant/message-hits.ts +0 -26
  361. package/src/sextant/model.ts +0 -387
  362. package/src/sextant/overlays.ts +0 -456
  363. package/src/sextant/panel-hits.ts +0 -38
  364. package/src/sextant/pet.ts +0 -399
  365. package/src/sextant/screen.ts +0 -324
  366. package/src/sextant/scroll-hits.ts +0 -66
  367. package/src/sextant/scrollbar.ts +0 -82
  368. package/src/sextant/sextant-bridge.ts +0 -174
  369. package/src/sextant/sextant-cards.ts +0 -142
  370. package/src/sextant/sextant-diff-base.ts +0 -63
  371. package/src/sextant/sextant-files.ts +0 -154
  372. package/src/sextant/sextant-frame-loop.ts +0 -335
  373. package/src/sextant/sextant-renderer.ts +0 -574
  374. package/src/sextant/sextant-repo.ts +0 -140
  375. package/src/sextant/theme.ts +0 -66
  376. package/src/sextant/tool-rows.ts +0 -189
  377. package/src/sextant/types.ts +0 -493
  378. package/src/skills/index.ts +0 -387
  379. package/src/skills/pack.ts +0 -220
  380. package/src/skills/spec.ts +0 -162
  381. package/src/skills/tools.ts +0 -69
  382. package/src/skills/versioned.ts +0 -227
  383. package/src/telemetry/otel-export.ts +0 -122
  384. package/src/telemetry/otel-lanes.ts +0 -89
  385. package/src/telemetry/otel-logs.ts +0 -131
  386. package/src/telemetry/otel-metrics.ts +0 -136
  387. package/src/telemetry/otel.ts +0 -397
  388. package/src/telemetry/otlp.ts +0 -76
  389. package/src/tools/ask-user.ts +0 -156
  390. package/src/tools/bash-bg.ts +0 -94
  391. package/src/tools/bash-jobs.ts +0 -237
  392. package/src/tools/design.ts +0 -151
  393. package/src/tools/evalcell.ts +0 -338
  394. package/src/tools/html-text.ts +0 -139
  395. package/src/tools/provider.ts +0 -149
  396. package/src/tools/task.ts +0 -250
  397. package/src/tools/todo.ts +0 -320
  398. package/src/tools/webfetch.ts +0 -332
  399. package/src/tools/websearch.ts +0 -359
  400. package/src/tui/agents-cmd.ts +0 -41
  401. package/src/tui/app.ts +0 -749
  402. package/src/tui/attach.ts +0 -127
  403. package/src/tui/boot-notes.ts +0 -41
  404. package/src/tui/builtin-prompts.ts +0 -59
  405. package/src/tui/checkpoints-cmd.ts +0 -70
  406. package/src/tui/clipboard-image.ts +0 -81
  407. package/src/tui/clipboard.ts +0 -78
  408. package/src/tui/commands.ts +0 -283
  409. package/src/tui/config-view.ts +0 -53
  410. package/src/tui/context-cmds.ts +0 -282
  411. package/src/tui/cost.ts +0 -108
  412. package/src/tui/crash-guard.ts +0 -173
  413. package/src/tui/focus-terminal.ts +0 -34
  414. package/src/tui/git-cmds.ts +0 -273
  415. package/src/tui/git-plain.ts +0 -58
  416. package/src/tui/info-cmd.ts +0 -150
  417. package/src/tui/input-plain.ts +0 -76
  418. package/src/tui/mcp-cmd.ts +0 -128
  419. package/src/tui/memory-note.ts +0 -77
  420. package/src/tui/modes-cmd.ts +0 -45
  421. package/src/tui/notify-seq.ts +0 -100
  422. package/src/tui/notify.ts +0 -318
  423. package/src/tui/overlays.ts +0 -97
  424. package/src/tui/pi-renderer.ts +0 -428
  425. package/src/tui/providers-cmd.ts +0 -377
  426. package/src/tui/reasoning-view.ts +0 -56
  427. package/src/tui/renderer.ts +0 -128
  428. package/src/tui/replay-marker.ts +0 -29
  429. package/src/tui/session-cmd.ts +0 -148
  430. package/src/tui/session-manage.ts +0 -95
  431. package/src/tui/sextant-attach.ts +0 -102
  432. package/src/tui/sextant-io.ts +0 -202
  433. package/src/tui/sextant-smoke.ts +0 -110
  434. package/src/tui/shell-cmd.ts +0 -158
  435. package/src/tui/smoke.ts +0 -72
  436. package/src/tui/staged-terminal.ts +0 -50
  437. package/src/tui/startup.ts +0 -12
  438. package/src/tui/theme.ts +0 -59
  439. package/src/tui/todo-label.ts +0 -7
  440. package/src/tui/trust-card.ts +0 -107
  441. package/src/tui/tui-commands.ts +0 -87
  442. package/tsconfig.json +0 -30
  443. package/vendor/pi-tui/LICENSE +0 -21
  444. package/vendor/pi-tui/PATCHES.md +0 -12
  445. package/vendor/pi-tui/PROVENANCE.md +0 -12
  446. package/vendor/pi-tui/README.upstream.md +0 -854
  447. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  448. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  449. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  450. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  451. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  452. package/vendor/pi-tui/src/components/box.ts +0 -138
  453. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  454. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  455. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  456. package/vendor/pi-tui/src/components/image.ts +0 -128
  457. package/vendor/pi-tui/src/components/input.ts +0 -448
  458. package/vendor/pi-tui/src/components/loader.ts +0 -93
  459. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  460. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  461. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  462. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  463. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  464. package/vendor/pi-tui/src/components/stack.ts +0 -155
  465. package/vendor/pi-tui/src/components/text.ts +0 -108
  466. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  467. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  468. package/vendor/pi-tui/src/editor-component.ts +0 -75
  469. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  470. package/vendor/pi-tui/src/index.ts +0 -149
  471. package/vendor/pi-tui/src/keybindings.ts +0 -321
  472. package/vendor/pi-tui/src/keys.ts +0 -1402
  473. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  474. package/vendor/pi-tui/src/latex.ts +0 -1381
  475. package/vendor/pi-tui/src/layout-node.ts +0 -52
  476. package/vendor/pi-tui/src/layout.ts +0 -411
  477. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  478. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  479. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  480. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  481. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  482. package/vendor/pi-tui/src/terminal.ts +0 -554
  483. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  484. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  485. package/vendor/pi-tui/src/tui.ts +0 -1264
  486. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  487. package/vendor/pi-tui/src/utils.ts +0 -1327
  488. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  489. package/vendor/pi-tui/test/test-themes.ts +0 -39
  490. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  491. /package/{src/providers → dist/cli}/models-index.json +0 -0
@@ -1,187 +0,0 @@
1
- /** Sextant plan + usage painters (port #41). Ported from the user's sextant v0.4.0 app.js:675-744
2
- * (drawPlan steps/crew/next, drawUsage tokens/context bar/cost); the scenario phases are gone — the
3
- * steps ARE the session's todos (tools/todo.ts loadTodos), the crew rows are TaskManager TaskInfo,
4
- * usage comes from the run's real token/cost accounting. Pure: `now` only drives the crew spinner. */
5
-
6
- import { ATTR } from "./types.ts";
7
- import type { Rect, ScreenLike, Seg, SextantState, Theme } from "./types.ts";
8
- import type { TaskInfo } from "../core/tasks.ts";
9
- import { EMPTY } from "../core/voice.ts";
10
- import type { TodoItem } from "../tools/todo.ts";
11
- import { fmtK, planCounts } from "./model.ts";
12
- import { crewSummary, laneGlyph, laneStatus, laneTone } from "./draw-agents.ts";
13
- import { crewCardBlock, crewCardHeight, groupCrew, paintCrewCards, type CrewTask } from "./crew-cards.ts";
14
- import { panel } from "./layout.ts";
15
- import { st } from "./theme.ts";
16
- import { driftRow } from "./draw-context.ts";
17
-
18
- /** the crew section's row ceiling: two full cards and the separator between them (the card is 3 rows —
19
- * crew-cards.ts). Beyond that the plan's own steps lose their room, and the `+N more` footer says what is
20
- * not shown; the full board is `∷` (draw-agents.ts). */
21
- const CREW_ROWS_MAX = 7;
22
- export const STEP_GLYPH: Record<TodoItem["status"], string> = { completed: "◆", in_progress: "◈", pending: "◇" };
23
-
24
- const oneLine = (text: string): string => text.replace(/\s+/g, " ").trim();
25
- /** greedy word wrap (app.js wrap) — long words are split at the width */
26
- export function wrapText(text: string, width: number): string[] {
27
- const out: string[] = [];
28
- if (width <= 0) return out;
29
- for (const para of oneLine(text).split("\n")) {
30
- let line = "";
31
- for (const w of para.split(" ")) {
32
- if (!line) { line = w; continue; }
33
- if ([...line].length + 1 + [...w].length <= width) line += " " + w; else { out.push(line); line = w; }
34
- }
35
- while ([...line].length > width) { const cps = [...line]; out.push(cps.slice(0, width).join("")); line = cps.slice(width).join(""); }
36
- out.push(line);
37
- }
38
- return out;
39
- }
40
-
41
- /** `next` = the in_progress item, then the first pending one */
42
- export function nextSteps(todos: readonly TodoItem[]): TodoItem[] {
43
- const out: TodoItem[] = [];
44
- const cur = todos.find((t) => t.status === "in_progress"); if (cur) out.push(cur);
45
- const pend = todos.find((t) => t.status === "pending"); if (pend) out.push(pend);
46
- return out;
47
- }
48
- /** non-terminal tasks = "working" (queued + running) — crewSummary(crew).working agrees */
49
- export const crewWorking = (crew: readonly TaskInfo[]): number => crewSummary(crew).working;
50
- /** the crew board's glyph + tone (#46 draw-agents): ◇ queued · spinner running · ◆ done · × failed · ▪ cancelled */
51
- export function crewGlyph(t: TaskInfo, theme: Theme, now: number): [string, number] {
52
- return [laneGlyph(t.status, now), laneTone(t.status, theme)];
53
- }
54
- /** the crew board's status word (#46 laneStatus): `working mm:ss` while running, else the status */
55
- export const crewStatus = (t: TaskInfo, now = 0): string => laneStatus(t, now);
56
-
57
- /** Plan panel: `plan done/total` title, todo steps (◆ done · ◈ in_progress · ◇ pending, priority hint
58
- * at the right), then — anchored to the bottom — `crew k working` (when any) and `next`. */
59
- export function drawPlan(scr: ScreenLike, R: Rect, s: SextantState, theme: Theme, now = 0): void {
60
- const todos = s.plan.todos, c = planCounts(s);
61
- const B = panel(scr, R, "plan", false, todos.length ? [[`${c.completed}/${c.total}`, st(theme.muted)]] : [], theme);
62
- const yEnd = B.y + B.h;
63
- let y = B.y;
64
- if (s.plan.note) for (const line of wrapText(s.plan.note, B.w).slice(0, 2)) if (y < yEnd) scr.put(B.x, y++, line, st(theme.warn), B.w);
65
- const next = nextSteps(todos);
66
- // the crew section is CARDS now (Berkay's pick): one card per workflow — the tasks of one run — never one row
67
- // per task. The height is what the cards actually need, capped; the block itself drops spacing, then names,
68
- // then whole cards behind a footer (crew-cards.ts states the order).
69
- const groups = groupCrew(s.crew as readonly CrewTask[]);
70
- const crewNeed = groups.length ? Math.min(CREW_ROWS_MAX, crewCardHeight(groups, B.w, now)) : 0;
71
- let nextRows = next.length ? next.length + 1 : 0, crewRows = crewNeed ? crewNeed + 1 : 0;
72
- let nextY = yEnd - nextRows;
73
- let crewY = (nextRows ? nextY - 1 : yEnd) - crewRows;
74
- const minY = y + 2; // keep the steps header + one row above the anchored blocks
75
- if (crewRows && crewY < minY) { crewRows = 0; crewY = yEnd; }
76
- if (nextRows && nextY < minY) { nextRows = 0; nextY = yEnd; }
77
- const stepsEnd = crewRows ? crewY - 1 : nextRows ? nextY - 1 : yEnd;
78
- scr.text(B.x, y++, [["steps", st(theme.muted)], [todos.length ? ` ${c.completed}/${c.total}` : "", st(theme.dim)]], B.w);
79
- if (!todos.length && y < stepsEnd) { // empty plan: the hint's second line only when there is room
80
- scr.put(B.x, y++, EMPTY.plan[0], st(theme.dim), B.w);
81
- if (y < stepsEnd) scr.put(B.x, y++, EMPTY.plan[1], st(theme.dim), B.w);
82
- }
83
- // a long plan windows around the step in progress instead of always showing its head: the person
84
- // wants to see what is being done now, not steps 1-8 of 30. One row above says how many are earlier.
85
- const room = Math.max(0, stepsEnd - y), curIdx = todos.findIndex((t) => t.status === "in_progress");
86
- let start = 0;
87
- if (todos.length > room && curIdx >= room - 1) { // the current step would be hidden (or be the marker row)
88
- const visible = Math.max(1, room - 2); // minus the "earlier" row and the "+N more" row
89
- start = Math.max(0, Math.min(curIdx - Math.floor(visible / 2), todos.length - visible));
90
- }
91
- if (start > 0 && y < stepsEnd) scr.put(B.x, y++, ` …${start} earlier`, st(theme.dim), B.w);
92
- let shown = start;
93
- for (const t of todos.slice(start)) {
94
- if (y >= stepsEnd) break;
95
- const cur = t.status === "in_progress", done = t.status === "completed";
96
- const pr = t.priority === "high" ? "high" : t.priority === "low" ? "low" : "";
97
- scr.put(B.x, y, STEP_GLYPH[t.status], st(done ? theme.okDim : cur ? theme.accent : theme.dim));
98
- scr.clip(B.x + 3, y, oneLine(t.content), st(done ? theme.fg2 : cur ? theme.fg : theme.muted, -1, cur ? ATTR.BOLD : 0), B.w - 3 - (pr ? pr.length + 1 : 0));
99
- if (pr) scr.put(B.x + B.w - pr.length, y, pr, st(t.priority === "high" ? theme.warn : theme.dim));
100
- y++; shown++;
101
- }
102
- if (shown < todos.length && shown > 0) { y--; scr.fill(B.x, y, B.w, 1, " "); scr.put(B.x, y, ` +${todos.length - shown + 1} more`, st(theme.dim), B.w); }
103
- if (crewRows) {
104
- let cy = crewY;
105
- scr.text(B.x, cy++, [["crew", st(theme.muted)], [` ${crewSummary(s.crew).text}`, st(theme.dim)]], B.w);
106
- const block = crewCardBlock(groups, B.w, crewRows - 1, now);
107
- paintCrewCards(scr, B.x, cy, B.w, block.lines, theme);
108
- }
109
- if (nextRows) {
110
- let ny = nextY;
111
- scr.put(B.x, ny++, "next", st(theme.muted));
112
- for (const t of next) {
113
- const cur = t.status === "in_progress";
114
- scr.text(B.x, ny++, [[STEP_GLYPH[t.status] + " ", st(cur ? theme.accent : theme.dim)], [oneLine(t.content), st(cur ? theme.fg : theme.muted)]], B.w);
115
- }
116
- }
117
- }
118
-
119
- /** filled cells of a `width`-wide context bar at `pct` (0..100) */
120
- export const barFilled = (pct: number, width: number): number => Math.round((Math.max(0, Math.min(100, pct)) / 100) * width);
121
- /** the first candidate that fits `width` cells, else the last one clipped with an ellipsis */
122
- export function fitText(candidates: readonly string[], width: number): string {
123
- for (const c of candidates) if ([...c].length <= width) return c;
124
- const last = candidates[candidates.length - 1];
125
- if (last === undefined || width <= 0) return "";
126
- return width === 1 ? "…" : [...last].slice(0, width - 1).join("") + "…";
127
- }
128
-
129
- /** Usage panel (3 inner rows): `tokens 4.2k` (+ in/out split when it fits), `context ━━──── 12%`
130
- * (or `context ?` when the window is unknown), `cost $0.030` (or `cost —` when unpriced) +
131
- * provider/model (model alone, then clipped, when narrow). */
132
- /** Token counts for the context row, as short as they can be and still be read: `842`, `4.2k`, `24k`,
133
- * `200k`, `1M`. fmtK keeps a decimal at every size, which is right where a number stands alone and
134
- * wrong in a pair — `24.0k/200.0k` costs six characters that say nothing and eats the bar beside it. */
135
- function fmtCtx(n: number): string {
136
- if (n < 1000) return String(Math.round(n));
137
- if (n < 10_000) return `${(n / 1000).toFixed(1)}k`;
138
- if (n < 1_000_000) return `${Math.round(n / 1000)}k`;
139
- const m = n / 1_000_000;
140
- return m < 10 && m !== Math.round(m) ? `${m.toFixed(1)}M` : `${Math.round(m)}M`;
141
- }
142
-
143
- export function drawUsage(scr: ScreenLike, R: Rect, s: SextantState, theme: Theme): void {
144
- const B = panel(scr, R, "usage", false, [], theme);
145
- const u = s.usage;
146
- const label = (t: string): Seg => [t.padEnd(10), st(theme.muted)];
147
- const total = fmtK(u.tokensIn + u.tokensOut);
148
- const split = fitText([` ${fmtK(u.tokensIn)} in · ${fmtK(u.tokensOut)} out`, ` ${fmtK(u.tokensIn)}/${fmtK(u.tokensOut)}`, ""], B.w - 10 - total.length);
149
- if (u.tokensIn + u.tokensOut === 0) scr.text(B.x, B.y, [label("tokens"), [EMPTY.usage, st(theme.dim)]], B.w); // nothing spent yet
150
- else scr.text(B.x, B.y, [label("tokens"), [total, st(theme.fg)], [split, st(theme.dim)]], B.w);
151
- scr.text(B.x, B.y + 1, [label("context")]);
152
- if (u.contextPct === null) scr.put(B.x + 10, B.y + 1, "?", st(theme.dim));
153
- else {
154
- // A percentage alone goes blind on a large window. claude-opus-5 carries 1,000,000 tokens, so a
155
- // real working session sits at 0% for hours: you need 10k tokens to move the first digit, and
156
- // Berkay's report was exactly this — "context shows 0%, we cannot see how much context there is".
157
- // The numbers are what a person acts on ("42k of 1M" is a decision; "0%" is not), so they get the
158
- // room and the percent keeps only what is left. The bar stays: it is the at-a-glance channel, and
159
- // it is the only part that reads correctly when the window is small.
160
- const pct = `${Math.round(u.contextPct)}%`;
161
- const nums = u.contextWindow !== undefined ? `${fmtCtx(u.contextTokens ?? 0)}/${fmtCtx(u.contextWindow)}` : "";
162
- const tail = nums === "" ? pct : `${nums} ${pct}`;
163
- const barW = Math.max(4, B.w - 10 - tail.length - 2);
164
- const filled = barFilled(u.contextPct, barW);
165
- for (let i = 0; i < barW; i++) scr.put(B.x + 10 + i, B.y + 1, i < filled ? "━" : "─", st(i < filled ? theme.accent : theme.rule2));
166
- const tailX = B.x + 10 + barW + 2;
167
- if (nums !== "") scr.put(tailX, B.y + 1, nums, st(theme.dim));
168
- scr.put(tailX + (nums === "" ? 0 : nums.length + 1), B.y + 1, pct, st(u.contextPct > 80 ? theme.warn : theme.fg));
169
- }
170
- const cost = u.costUsd === null ? "—" : `$${u.costUsd.toFixed(3)}`;
171
- const model = u.model ? fitText([u.provider ? ` ${u.provider}/${u.model}` : ` ${u.model}`, ` ${u.model}`], B.w - 10 - cost.length) : "";
172
- scr.text(B.x, B.y + 2, [label("cost"), [cost, st(theme.fg)], [model, st(theme.dim)]], B.w);
173
-
174
- // How far the bar above is from what the provider actually counted. It matters here rather than only
175
- // inside /context because compaction fires on OUR estimate: a model whose real prompt is a fifth bigger
176
- // than the bar says gets compacted late, and the bar is the thing the human is looking at when they
177
- // decide whether one more turn fits.
178
- //
179
- // Drawn only once /context has been opened, and silent otherwise. The number comes from comparing our
180
- // count with a turn that reported usage, which the cockpit does not do on its own — and inventing a
181
- // placeholder ("drift —") would take a row to say nothing. `driftRow` returns undefined when there is
182
- // nothing honest to say, so this is one condition rather than a special case.
183
- const d = s.context ? driftRow(s.context.drift, s.context.tolerance) : undefined;
184
- if (d && B.h > 3) {
185
- scr.text(B.x, B.y + 3, [label("drift"), [fitText([d.text, ""], B.w - 10), st(d.warn ? theme.warn : theme.dim)]], B.w);
186
- }
187
- }
@@ -1,85 +0,0 @@
1
- /** The tab strip: paging between panels the terminal is too narrow to show at once.
2
- *
3
- * layout.ts hides the files panel under 140 columns and the plan/usage column under 110, and until
4
- * now a hidden panel was simply gone — ⌃e answered "the files panel needs ≥ 140 columns" and that was
5
- * that. Berkay asked for the panels to behave like tabs instead: on a narrow terminal the MAIN slot
6
- * (the code panel's rect) shows whichever panel `s.page` names, and a strip on that slot's top border
7
- * says which panels exist and which one is showing. Clicking a tab pages to it; ⌃e pages to files,
8
- * ⌃o cycles.
9
- *
10
- * Deliberately absent on a wide terminal: when every panel is on screen there is nothing to page,
11
- * and a strip would be one more thing to read. tabsFor() returns [] and nothing is drawn.
12
- *
13
- * Geometry and painting live together here so the hit zones the frame loop registers are the cells
14
- * that were actually painted — the same rule card-hits.ts and panel-hits.ts follow. The strip
15
- * overpaints the panel title on the top border (panel() draws the title at x+2); the active tab IS
16
- * the title. */
17
-
18
- import { st } from "./draw-util.ts";
19
- import { strWidth } from "./screen.ts";
20
- import { ATTR, PAGES, type Layout, type Page, type Rect, type ScreenLike, type SextantState, type Theme } from "./types.ts";
21
-
22
- export interface Tab {
23
- page: Page;
24
- /** the cells the label occupies on the border row */
25
- rect: Rect;
26
- active: boolean;
27
- }
28
-
29
- const LABEL: Record<Page, string> = { code: "code", files: "files", plan: "plan" };
30
- const SEP = " · ";
31
-
32
- /** is this page's own panel hidden by the layout, so it needs a tab to be reachable? */
33
- export function hiddenByLayout(L: Layout, page: Page): boolean {
34
- return page === "files" ? L.files === null : page === "plan" ? L.plan === null : false;
35
- }
36
-
37
- /** the page actually showing in the main slot: `s.page` if that panel is hidden by the layout (so
38
- * paging is what makes it visible), else code — a page pointing at a panel that is already on
39
- * screen is inert, never a duplicate */
40
- export function mainPage(L: Layout, s: SextantState): Page {
41
- return hiddenByLayout(L, s.page) ? s.page : "code";
42
- }
43
-
44
- /** The tabs to show, positioned on the main slot's top border; [] on a wide terminal. */
45
- export function tabsFor(L: Layout, s: SextantState): Tab[] {
46
- const hidden = PAGES.filter((p) => hiddenByLayout(L, p));
47
- if (hidden.length === 0) return [];
48
- const pages: Page[] = ["code", ...hidden];
49
- const active = mainPage(L, s);
50
- const y = L.code.y;
51
- const right = L.code.x + L.code.w - 2; // the border's last usable cell before the corner
52
- let x = L.code.x + 2;
53
- const out: Tab[] = [];
54
- for (const [i, page] of pages.entries()) {
55
- const w = strWidth(LABEL[page]) + 2; // ` label `
56
- if (x + w > right) break; // a strip the border cannot hold stops, never wraps
57
- out.push({ page, rect: { x, y, w, h: 1 }, active: page === active });
58
- x += w + (i < pages.length - 1 ? strWidth(SEP) : 0);
59
- }
60
- return out;
61
- }
62
-
63
- /** Paint the strip over the main slot's top border. Pure; returns what it painted. */
64
- export function drawTabs(scr: ScreenLike, L: Layout, s: SextantState, theme: Theme): Tab[] {
65
- const tabs = tabsFor(L, s);
66
- if (tabs.length === 0) return tabs;
67
- const focused = s.focus === "code" || s.focus === "files";
68
- for (const [i, t] of tabs.entries()) {
69
- const style = t.active
70
- ? st(theme.bg, focused ? theme.accent : theme.fg2, ATTR.BOLD)
71
- : st(theme.muted);
72
- scr.text(t.rect.x, t.rect.y, [[` ${LABEL[t.page]} `, style]], t.rect.w);
73
- const next = tabs[i + 1];
74
- if (next) scr.text(t.rect.x + t.rect.w, t.rect.y, [[SEP, st(theme.frame)]], next.rect.x - (t.rect.x + t.rect.w));
75
- }
76
- return tabs;
77
- }
78
-
79
- /** the page after `page` among the tabs on screen (⌃o); `page` itself when there is nothing to cycle */
80
- export function nextPage(L: Layout, s: SextantState): Page {
81
- const tabs = tabsFor(L, s);
82
- if (tabs.length < 2) return s.page;
83
- const i = tabs.findIndex((t) => t.active);
84
- return tabs[(i + 1) % tabs.length]!.page;
85
- }
@@ -1,65 +0,0 @@
1
- /** Sextant surface (port #42) — small pure drawing helpers shared by the code and messages panels.
2
- * Ported from the user's own sextant v0.4.0 prototype: src/app.js:37 (st), :66-78 (wrap), :210-220
3
- * (panel). Pure: no clock, no timers, no process access — `now` arrives as a parameter.
4
- * #44 dedupe: `st` and `panel` are the shared theme.ts / layout.ts ones, re-exported here so the
5
- * panels' imports stay put (layout.ts panel() = this file's former one: interior cleared to the
6
- * theme background, extras clipped with an ellipsis before they are dropped). */
7
-
8
- import { SPIN, type Rect } from "./types.ts";
9
-
10
- export { st } from "./theme.ts";
11
- export { panel } from "./layout.ts";
12
-
13
- /** the four-glyph diamond spinner, phase from the frame clock (140 ms per step) */
14
- export const spinner = (now: number): string => SPIN[Math.floor(now / 140) % SPIN.length] ?? "◇";
15
-
16
- /** split file content into lines; a trailing newline does not produce a phantom empty line */
17
- export function splitLines(s: string): string[] {
18
- const l = s.split("\n");
19
- if (l.length && l[l.length - 1] === "") l.pop();
20
- return l;
21
- }
22
-
23
- /** 1-slot cache: splitLines is called twice per frame (drawFileView + codeScrollTop/rowCount).
24
- * File content is a stable string reference within a frame; reference equality is the cheapest guard. */
25
- let _splitCache: { src: string; lines: string[] } | null = null;
26
- export function splitLinesCached(s: string): string[] {
27
- if (_splitCache && _splitCache.src === s) return _splitCache.lines;
28
- const lines = splitLines(s);
29
- _splitCache = { src: s, lines };
30
- return lines;
31
- }
32
-
33
- /** Word-wrap to `width` cells — one cell per code point (types.ts), so an emoji counts once and a
34
- * surrogate pair never straddles two rows — keeping explicit newlines (a blank paragraph stays a
35
- * blank row); a word longer than the width is hard-split wherever it starts. Never returns []. */
36
- export function wrap(text: string, width: number): string[] {
37
- const w = Math.max(1, width);
38
- const out: string[] = [];
39
- for (const para of String(text).split("\n")) {
40
- let line = "", len = 0;
41
- for (const word of para.split(" ")) {
42
- const cps = [...word];
43
- if (line && len + 1 + cps.length <= w) { line += " " + word; len += 1 + cps.length; continue; }
44
- if (line) out.push(line);
45
- while (cps.length > w) out.push(cps.splice(0, w).join(""));
46
- line = cps.join(""); len = cps.length;
47
- }
48
- out.push(line);
49
- }
50
- return out;
51
- }
52
-
53
- /** hard-split a line into `width`-cell chunks (terminal-style, no word boundaries; one cell per
54
- * code point — an astral glyph moves to the next row whole); "" → [""] */
55
- export function hardWrap(line: string, width: number): string[] {
56
- const w = Math.max(1, width);
57
- const cps = [...line];
58
- if (cps.length <= w) return [line];
59
- const out: string[] = [];
60
- for (let i = 0; i < cps.length; i += w) out.push(cps.slice(i, i + w).join(""));
61
- return out;
62
- }
63
-
64
- /** inner rect of a panel drawn at `r` (2 cells of horizontal padding, 1 row for each border) */
65
- export const inner = (r: Rect): Rect => ({ x: r.x + 2, y: r.y + 1, w: r.w - 4, h: r.h - 2 });