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,236 +0,0 @@
1
- /** What check this project runs before the agent's work counts as done — decided without ever guessing.
2
- *
3
- * Berkay (2026-09-06): the CLI should govern its own work and catch its own mistakes before saying done. The
4
- * loop's gate (core/verify-gate.ts, nimbus-99) runs a command after the last edit; THIS module decides which one,
5
- * and it is the half that can do damage: a gate that runs the wrong command once — `npm test` that deploys,
6
- * wipes a database, or takes twenty minutes — is turned off forever. Two measurements shaped it (nimbus-6f, same
7
- * night): in Berkay's real projects (plain HTML/CSS/JS, no package.json) there is nothing to run at all, so
8
- * "none" is the MAIN path and its text is what a person reads; and in a TypeScript project a type-check caught
9
- * the same three constructed mistakes as the full suite in a tenth of the time (10 s against 170 s here). So:
10
- *
11
- * 1. Configuration first. `verify` in .rovecode/settings.json (project) or ~/.rovecode/settings.json (user),
12
- * a command string or a list, project winning like every other key. This is the one source that needs
13
- * no inference, and the ONLY way a test suite becomes the gate. `false` turns the gate off on purpose and
14
- * stops the inference below as well.
15
- * 2. Inference second, aimed at the FAST check, and only where both the name and the shape are recognised:
16
- * - package.json `typecheck` whose body is tsc; `lint` whose body is eslint, biome or oxlint. Name alone is
17
- * not enough (a `lint` script may do anything); the body has to be a runner known to run unattended and end.
18
- * - package.json `check`, only when neither of those was taken, and only when its body compiles or lints
19
- * without running tests: a `check` that runs the suite is the thorough gate, and the thorough gate is
20
- * configured, never inferred — the refusal names it and how to opt in.
21
- * - Cargo.toml → `cargo check`; go.mod → `go vet ./...`; a ruff-configured Python project → `ruff check .`.
22
- * - A `test` script, `cargo test`, `pytest`, Makefile targets: never inferred, always listed with the reason.
23
- * 3. Everything seen and NOT inferred goes into `refused`, in words specific enough that a person reads the
24
- * line and either agrees or sets the key. "Nothing" is a good answer; "could not infer" is not.
25
- *
26
- * The seam for the runner is `commands: string[]` it does not interpret, so per-file targeting ("tsc --noEmit"
27
- * plus the tests that import the changed files) can be added here later without touching anything downstream.
28
- * Pure apart from reading the files named above; never throws; never runs anything. */
29
-
30
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
31
- import { join } from "node:path";
32
- import { loadSettingsScoped, settingsPath } from "./settings.ts";
33
-
34
- export interface VerifyPlan {
35
- /** where the commands came from; "none" = the gate has nothing to run */
36
- source: "settings" | "inferred" | "none";
37
- /** the shell commands the gate runs, in order, uninterpreted; empty when source is "none" */
38
- commands: string[];
39
- /** one sentence: the file and key or script the answer came from, or why there is none */
40
- reason: string;
41
- /** what was seen and deliberately not inferred, each with its reason — the argument for trusting the gate */
42
- refused: string[];
43
- }
44
-
45
- export interface VerifyDeps {
46
- exists?: (p: string) => boolean;
47
- read?: (p: string) => string;
48
- }
49
-
50
- /** words in a `check` script's body that mean it is not a check */
51
- const DANGEROUS = /\b(deploy|publish|release|push|migrate|drop|rm\s+-rf|docker|kubectl|terraform|curl|wget|ssh|scp|rsync)\b/i;
52
- /** a body that keeps running until killed — never a gate */
53
- const WATCH = /(^|\s)(--watch(=\S*)?|-w|--watchAll)(\s|$)|\bnodemon\b|\bvitest\s*$/;
54
- /** a body that runs a test suite — the thorough gate, configured only */
55
- const RUNS_TESTS = /\b(bun test|vitest|jest|mocha|node --test|playwright test|cypress run|ava|tap|uvu)\b/;
56
- /** runners whose bare invocation runs once, unattended, and exits */
57
- const TYPECHECK_RUNNER = /^(bunx |npx |pnpm exec |yarn )?(tsc|vue-tsc|svelte-check)(\s|$)/;
58
- const LINT_RUNNER = /^(bunx |npx |pnpm exec |yarn )?(eslint|biome (check|lint)|oxlint)(\s|$)/;
59
-
60
- /** the package manager the lockfile says this project uses; npm when none says */
61
- function packageRunner(cwd: string, exists: (p: string) => boolean): { run: string; from: string } {
62
- if (exists(join(cwd, "bun.lock")) || exists(join(cwd, "bun.lockb"))) return { run: "bun run", from: "bun.lock" };
63
- if (exists(join(cwd, "pnpm-lock.yaml"))) return { run: "pnpm run", from: "pnpm-lock.yaml" };
64
- if (exists(join(cwd, "yarn.lock"))) return { run: "yarn", from: "yarn.lock" };
65
- if (exists(join(cwd, "package-lock.json"))) return { run: "npm run", from: "package-lock.json" };
66
- return { run: "npm run", from: "no lockfile (npm assumed)" };
67
- }
68
-
69
- export const NONE_REASON = "nothing configured and nothing fast and safe to infer — set verify in .rovecode/settings.json (a command, or a list) to turn the gate on";
70
- export const NOTHING_HERE = "no package.json, Cargo.toml, go.mod or pyproject.toml here, so there is no compiler, linter or test runner to run; for a plain HTML/CSS/JS site that is the normal answer, and the gate stays off";
71
-
72
- /** Resolve this project's verify command(s). */
73
- export function resolveVerify(cwd: string, deps: VerifyDeps = {}): VerifyPlan {
74
- const exists = deps.exists ?? existsSync;
75
- const read = deps.read ?? ((p: string) => readFileSync(p, "utf8"));
76
-
77
- // 1. configuration
78
- // loadSettingsScoped already applied the trust gate: an UNTRUSTED project file's `verify` is not here (core/settings.ts
79
- // COMMAND_KEYS) — a cloned repo does not choose the command this gate runs. `verify: false` is honoured from any file.
80
- const scoped = loadSettingsScoped(cwd);
81
- const settings = { ...scoped.user, ...scoped.project };
82
- if (settings.verify === false) {
83
- return { source: "none", commands: [], reason: "settings.json verify: false — the gate is off by choice, nothing is inferred", refused: [] };
84
- }
85
- if (settings.verify !== undefined) {
86
- const commands = Array.isArray(settings.verify) ? settings.verify : [settings.verify];
87
- const where = scoped.project.verify !== undefined ? scoped.projectPath : settingsPath("user", cwd);
88
- return { source: "settings", commands, reason: `${where} verify`, refused: [] };
89
- }
90
-
91
- // 2. inference
92
- const commands: string[] = [];
93
- const from: string[] = [];
94
- const refused: string[] = [];
95
-
96
- const pkgPath = join(cwd, "package.json");
97
- if (exists(pkgPath)) {
98
- let scripts: Record<string, string> = {};
99
- let ok = true;
100
- try {
101
- const raw = JSON.parse(read(pkgPath)) as { scripts?: unknown };
102
- const s = raw.scripts;
103
- if (s !== undefined && (typeof s !== "object" || s === null || Array.isArray(s))) { refused.push('package.json: "scripts" is not an object — nothing inferred from it'); ok = false; }
104
- else if (s) for (const [k, v] of Object.entries(s as Record<string, unknown>)) if (typeof v === "string") scripts[k] = v;
105
- } catch { refused.push("package.json is not valid JSON — nothing inferred from it"); ok = false; scripts = {}; }
106
- if (ok) {
107
- const pm = packageRunner(cwd, exists);
108
- const body = (name: string): string => scripts[name]!.trim();
109
- const optIn = (name: string) => `set \`"verify": "${pm.run} ${name}"\` in .rovecode/settings.json`;
110
-
111
- // the fast checks: a recognised runner, or a refusal that quotes the body
112
- const take = (name: string, runner: RegExp, what: string, known: string): void => {
113
- if (scripts[name] === undefined) return;
114
- const b = body(name);
115
- if (WATCH.test(b)) { refused.push(`package.json script "${name}" runs \`${b}\`: a watch mode never exits, so it cannot gate a run`); return; }
116
- if (!runner.test(b)) { refused.push(`package.json script "${name}" runs \`${b}\`: not a ${what} this gate knows runs unattended and ends (${known}) — ${optIn(name)} to run it anyway`); return; }
117
- commands.push(`${pm.run} ${name}`); from.push(`package.json script "${name}" (${pm.from})`);
118
- };
119
- take("typecheck", TYPECHECK_RUNNER, "type-checker", "tsc, vue-tsc, svelte-check");
120
- take("lint", LINT_RUNNER, "linter", "eslint, biome check, oxlint");
121
-
122
- // `check`: the convention means "verify, change nothing" — taken as the fallback fast check when it only
123
- // compiles or lints; refused, with the cost named, when it runs the suite or does anything a check must not
124
- if (scripts.check !== undefined) {
125
- const b = body("check");
126
- const bad = DANGEROUS.exec(b);
127
- const tests = RUNS_TESTS.exec(b);
128
- if (bad) refused.push(`package.json script "check" runs \`${b}\`: it names \`${bad[1]}\`, which a check must not do — ${optIn("check")} if that is really what you want the gate to run`);
129
- else if (WATCH.test(b)) refused.push(`package.json script "check" runs \`${b}\`: a watch mode never exits, so it cannot gate a run`);
130
- else if (tests) refused.push(`package.json script "check" runs \`${b}\`: it runs the test suite (\`${tests[1]}\`), which is minutes here rather than seconds; the thorough gate is configured, never inferred — ${optIn("check")} if that cost is right for this project`);
131
- else if (commands.length > 0) refused.push(`package.json script "check" runs \`${b}\`: a faster script already covers it (${from.map((f) => f.split(" (")[0]).join(", ")}) — ${optIn("check")} to run it instead`);
132
- else { commands.push(`${pm.run} check`); from.push(`package.json script "check" (${pm.from})`); }
133
- }
134
-
135
- // `test`: never inferred — the name promises nothing about the body, and a suite is the slow gate
136
- if (scripts.test !== undefined) {
137
- const b = body("test");
138
- refused.push(`package.json script "test" runs \`${b}\`: a test suite is never inferred, only configured (the fast gate is a type-check; a suite can take minutes and may need services) — ${optIn("test")} if it is quick enough here`);
139
- }
140
- if (commands.length === 0 && refused.length === 0) refused.push('package.json has no "typecheck", "lint", "check" or "test" script — name one, or set verify in .rovecode/settings.json');
141
- }
142
- }
143
-
144
- if (exists(join(cwd, "Cargo.toml"))) {
145
- commands.push("cargo check"); from.push("Cargo.toml");
146
- refused.push("`cargo test` is not inferred: it runs the crate's tests, which may be slow or need services — set verify to run it");
147
- }
148
- if (exists(join(cwd, "go.mod"))) {
149
- commands.push("go vet ./..."); from.push("go.mod");
150
- refused.push("`go test ./...` is not inferred: it runs the module's tests — set verify to run it");
151
- }
152
- const pyproject = join(cwd, "pyproject.toml");
153
- if (exists(pyproject) || exists(join(cwd, "ruff.toml"))) {
154
- const ruffToml = exists(join(cwd, "ruff.toml"));
155
- let ruff = ruffToml;
156
- if (!ruff && exists(pyproject)) { try { ruff = /^\[tool\.ruff(\.|\])/m.test(read(pyproject)); } catch { /* unreadable: no ruff */ } }
157
- if (ruff) { commands.push("ruff check ."); from.push(ruffToml ? "ruff.toml" : "pyproject.toml [tool.ruff]"); }
158
- else refused.push("pyproject.toml without a [tool.ruff] section: no linter is configured that this gate knows — set verify (for example `ruff check .` or `pytest -q`) to run one");
159
- refused.push("`pytest` is not inferred: it runs the project's tests — set verify to run it");
160
- }
161
- if (exists(join(cwd, "Makefile")) || exists(join(cwd, "makefile"))) {
162
- refused.push("a Makefile is here, but make targets are never inferred (a target can do anything) — set verify to `make check` or the target you mean");
163
- }
164
-
165
- if (commands.length > 0) {
166
- return { source: "inferred", commands, reason: `inferred from ${from.join(", ")}`, refused };
167
- }
168
- if (refused.length === 0) return { source: "none", commands: [], reason: NOTHING_HERE, refused: [] };
169
- return { source: "none", commands: [], reason: NONE_REASON, refused };
170
- }
171
-
172
-
173
- /** the commands as one label — the SAME words in the doctor row and in the loop's `verify` RunEvent ("running
174
- * bun run check && bun test"), so a person sees one name for one thing */
175
- export function verifyLabel(plan: VerifyPlan): string {
176
- return plan.commands.join(" && ");
177
- }
178
-
179
- /** one line for `rovecode doctor` and the settings docs */
180
- export function describeVerify(plan: VerifyPlan): string {
181
- if (plan.source === "none") return `none — ${plan.reason}`;
182
- return `${verifyLabel(plan)} — ${plan.reason}`;
183
- }
184
-
185
- /** what the gate does NOT see, said wherever the gate is described (doctor, README): the loop counts edits made
186
- * through `edit` and `write`; a run that changed files only through `bash` has no counted write, so it is not
187
- * verified. Owned here so the doctor row and the docs cannot drift apart. */
188
- export const VERIFY_BLIND_SPOT = "runs after edits made with `edit` or `write`; a run that changed files only through `bash` is not counted, so it is not verified";
189
-
190
- // ---- cost: a check's duration is the fact that makes the doctor row honest ("bun run check, 170 s last time").
191
- // The resolver never runs anything, so it cannot measure; the gate can, and records here after each run. Project-local
192
- // because the same command costs different amounts in different repos; one small file, one entry per command.
193
-
194
- export const VERIFY_TIMING_FILE = join(".rovecode", "verify-timing.json");
195
- type Timings = Record<string, { ms: number; at: string }>;
196
-
197
- function readTimings(cwd: string): Timings {
198
- try {
199
- const raw = JSON.parse(readFileSync(join(cwd, VERIFY_TIMING_FILE), "utf8")) as unknown;
200
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return {};
201
- const out: Timings = {};
202
- for (const [k, v] of Object.entries(raw as Record<string, unknown>)) {
203
- if (v && typeof v === "object" && typeof (v as { ms?: unknown }).ms === "number" && typeof (v as { at?: unknown }).at === "string") out[k] = v as { ms: number; at: string };
204
- }
205
- return out;
206
- } catch { return {}; }
207
- }
208
-
209
- /** for the gate: remember how long `command` took in this project. Never throws (a timing is not worth a crash). */
210
- export function recordVerifyTiming(cwd: string, command: string, ms: number, now: Date = new Date()): void {
211
- try {
212
- const t = readTimings(cwd);
213
- t[command] = { ms: Math.max(0, Math.round(ms)), at: now.toISOString() };
214
- mkdirSync(join(cwd, ".rovecode"), { recursive: true });
215
- writeFileSync(join(cwd, VERIFY_TIMING_FILE), JSON.stringify(t, null, 2) + "\n");
216
- } catch { /* a timing is not worth a crash */ }
217
- }
218
-
219
- /** the last measured duration of `command` here, or undefined when it has not run yet */
220
- export function lastVerifyTiming(cwd: string, command: string): number | undefined {
221
- return readTimings(cwd)[command]?.ms;
222
- }
223
-
224
- /** "3 s" / "170 s" / "2 min 50 s" — the cost as a person says it */
225
- export function formatDuration(ms: number): string {
226
- const s = Math.round(ms / 1000);
227
- if (s < 1) return "under a second";
228
- if (s < 120) return `${s} s`;
229
- const m = Math.floor(s / 60), r = s % 60;
230
- return r === 0 ? `${m} min` : `${m} min ${r} s`;
231
- }
232
-
233
- /** the label with each command's last cost when known: "bun run typecheck (9 s) && bun test (not run yet)" */
234
- export function verifyLabelWithCost(cwd: string, plan: VerifyPlan): string {
235
- return plan.commands.map((c) => { const ms = lastVerifyTiming(cwd, c); return ms === undefined ? `${c} (not run here yet)` : `${c} (${formatDuration(ms)} last time)`; }).join(" && ");
236
- }
package/src/core/voice.ts DELETED
@@ -1,158 +0,0 @@
1
- /** rovecode's voice — the one place user-facing wording lives: mode labels, the no-model recipe, the
2
- * welcome card, the panels' empty-state hints. First person, short plain sentences, one idea per
3
- * line, no emoji; the ◆ glyph marks rovecode's own lines; a problem always ends with the next step.
4
- * Pure strings and string builders: every surface (CLI, REPL, TUI, server, ACP) reads from here so a
5
- * wording change lands everywhere at once. */
6
-
7
- /** the permission modes as the screen names them; the flags/commands keep their names (--yolo, /yolo, ROVECODE_YOLO) */
8
- export const MODE_ASK = "ask first";
9
- export const MODE_AUTO = "auto (never asks)";
10
- export const MODE_ACCEPT = "accept edits";
11
-
12
- /** "ask first" | "auto (never asks)" — the status/notes label for the yolo flag */
13
- export function modeLabel(yolo: boolean): string { return yolo ? MODE_AUTO : MODE_ASK; }
14
- /** compact form for footers and status bars: "ask first" | "auto" */
15
- export function modeLabelShort(yolo: boolean): string { return yolo ? "auto" : MODE_ASK; }
16
- /** what each mode means, in one sentence */
17
- export function modeMeaning(yolo: boolean): string {
18
- return yolo ? "I won't stop to ask before writes or shell commands" : "I ask before I write or run anything";
19
- }
20
-
21
- /** the marker every problem message ends with */
22
- export const NEXT = "→ next:";
23
- export const next = (text: string): string => `${NEXT} ${text}`;
24
-
25
- /** The no-model recipe — three lines, `rovecode setup` first. `where` picks the commands that exist
26
- * on that surface; the first line is stable ("no provider configured") for callers that match it. */
27
- export function noModelHint(where: "cli" | "tui" = "cli"): string {
28
- const setup = where === "tui" ? "/setup" : "rovecode setup";
29
- const alt = where === "tui"
30
- ? "/provider add <id> <baseUrl> · /provider key <id> <secret>"
31
- : "rovecode provider add <id> <baseUrl>, then rovecode auth set <id>";
32
- return [
33
- "no provider configured — no model to think with yet.",
34
- ` ${next(setup)} (pick a provider, paste the key hidden, one test call)`,
35
- ` or: ${alt} · or set ROVECODE_BASE_URL + ROVECODE_API_KEY`,
36
- ].join("\n");
37
- }
38
-
39
- /** `rovecode run` with nothing configured answers from a scripted mock; this is what it says. */
40
- export const MOCK_PROVIDER_TEXT =
41
- `Rovecode mock provider: no model is connected, so this is a canned reply. ${next("rovecode setup")} (or rovecode provider add <id> <baseUrl> + rovecode auth set <id>, or set ROVECODE_BASE_URL and ROVECODE_API_KEY)`;
42
-
43
- export interface WelcomeOpts {
44
- /** the session's provider/model when one is connected; null = nothing configured */
45
- connected: { provider: string; model: string } | null;
46
- cwd: string;
47
- yolo: boolean;
48
- /** plan/act; act is the default and is not mentioned */
49
- mode?: "plan" | "act";
50
- /** the running version, so "which rovecode is this" never needs a second command */
51
- version?: string;
52
- /** what this session actually loaded. Zeroes are omitted rather than printed: a line reading
53
- * "0 skills · 0 plugins · 0 MCP servers" is three facts nobody asked for, while "19 skills · 2 MCP
54
- * servers" is the answer to "did my install take". */
55
- loaded?: { skills?: number; plugins?: number; mcp?: number };
56
- /** the one-line update notice, when there is one; see core/update-check.ts */
57
- update?: string | null;
58
- /** columns available; under BANNER_COLS the wordmark is dropped rather than wrapped (default 80) */
59
- width?: number;
60
- }
61
-
62
- /** ROVECODE in half-block letters, two rows. Berkay picked this over a boxed header and a plain block
63
- * (2026-09-06). It is 31 columns wide, so it fits a narrow split, and it only appears when the card
64
- * knows the version — a banner with nothing to say under it is decoration. */
65
- const WORDMARK = ["█▀█ █▀█ █ █ █▀▀ █▀▀ █▀█ █▀▄ █▀▀", "█▀▄ █▄█ ▀▄▀ █▄▄ █▄▄ █▄█ █▄▀ █▄▄"] as const;
66
- const BANNER_COLS = 46;
67
-
68
- /** "19 skills · 3 plugins · 2 MCP servers", counting only what is there. Null when nothing loaded,
69
- * because the absence of the line says that better than the line saying zero three times. */
70
- export function loadedLine(loaded: WelcomeOpts["loaded"]): string | null {
71
- if (!loaded) return null;
72
- const plural = (n: number, one: string) => `${n} ${one}${n === 1 ? "" : "s"}`;
73
- const bits: string[] = [];
74
- if (loaded.skills) bits.push(plural(loaded.skills, "skill"));
75
- if (loaded.plugins) bits.push(plural(loaded.plugins, "plugin"));
76
- if (loaded.mcp) bits.push(plural(loaded.mcp, "MCP server"));
77
- return bits.length > 0 ? bits.join(" · ") : null;
78
- }
79
-
80
- /** The card a fresh session opens with (the messages panel's first note). */
81
- export function welcomeCard(o: WelcomeOpts): string {
82
- const where = `${o.cwd} · ${modeLabelShort(o.yolo)}${o.mode === "plan" ? " · plan mode (read-only)" : ""}`;
83
- const version = o.version ? ` ${o.version}` : "";
84
- // the two optional footers, in the order a reader wants them: what this session has, then what it
85
- // could have. Both drop out entirely when there is nothing to say — see loadedLine and updateLine.
86
- const tail = [loadedLine(o.loaded), where, o.update ?? null].filter((l): l is string => l !== null);
87
- // The banner form: the wordmark, then one line per fact. It needs a version (there is nothing to put
88
- // beside the mark otherwise) and room (under BANNER_COLS the mark would wrap into noise), and it falls
89
- // back to exactly the prose card below — which is what a resumed or narrow session still sees.
90
- if (o.version !== undefined && (o.width ?? 80) >= BANNER_COLS) {
91
- const model = o.connected === null ? null
92
- : o.connected.model.length > 0 ? `${o.connected.provider}/${o.connected.model}` : o.connected.provider;
93
- const loaded = loadedLine(o.loaded);
94
- return [
95
- ` ${WORDMARK[0]}`,
96
- ` ${WORDMARK[1]} ${o.version}`,
97
- "",
98
- model === null ? " no model connected yet — /setup fixes that in about a minute"
99
- : ` ${[model, loaded].filter((s) => s !== null).join(" · ")}`,
100
- ` ${where}`,
101
- ...(model === null ? [] : [` I read first, then ${o.yolo ? "work without asking" : "ask before I write or run anything"}. /help lists commands by topic.`]),
102
- ...(o.update ? [` ${o.update}`] : []),
103
- ].join("\n");
104
- }
105
- if (o.connected === null) {
106
- return [
107
- `◆ rovecode${version} here. No model connected yet, so I can't think.`,
108
- "/setup fixes that in about a minute.",
109
- ...tail,
110
- ].join("\n");
111
- }
112
- const model = o.connected.model.length > 0 ? `${o.connected.provider}/${o.connected.model}` : o.connected.provider;
113
- return [
114
- `◆ rovecode${version} here. Connected to ${model}.`,
115
- `Tell me what you want done; I read first, then ${o.yolo ? "work without asking" : "ask before I write or run anything"}.`,
116
- "/help lists commands by topic.",
117
- ...tail,
118
- ].join("\n");
119
- }
120
-
121
- /** one-liner for a resumed session (its transcript is the card) */
122
- export function resumedLine(id: string, cwd: string, yolo: boolean): string {
123
- return `◆ back in session ${id.slice(0, 8)} · ${cwd} · ${modeLabelShort(yolo)}`;
124
- }
125
-
126
- /** the /effort note. Says what the level costs, because that is the part that surprises people:
127
- * thinking tokens are billed as output and they arrive before any answer does. */
128
- export function effortNote(level: string, receives?: string): string {
129
- const head = level === "off" ? "thinking: off — I answer straight away."
130
- : level === "auto" ? "thinking: auto — the model decides how much to reason; I send no dial."
131
- : `thinking: ${level} — I reason before answering. It costs output tokens and delays the first word.`;
132
- // the second line is the truth on the wire (providers/thinking.ts thinkingLine): the level is one word,
133
- // what this model's endpoint actually receives for it is another, and a model without a reasoning mode
134
- // receives nothing at all — the person should not have to guess which
135
- return receives ? `${head}\n ${receives}` : head;
136
- }
137
-
138
- /** the /yolo toggle's note */
139
- export function modeSwitchNote(yolo: boolean): string {
140
- return `mode: ${modeLabel(yolo)} — ${modeMeaning(yolo)}`;
141
- }
142
-
143
- /** the /accept-edits toggle's note. Says the boundary out loud: this is not auto mode, and the two
144
- * things it does NOT cover are the two that can leave the repository. */
145
- export function acceptEditsNote(on: boolean): string {
146
- return on
147
- ? `mode: ${MODE_ACCEPT} — I write inside this folder without asking. Shell commands, subagents, network and any write outside it still ask, and deny rules still hold.`
148
- : `mode: ${MODE_ASK} — I ask before every write again.`;
149
- }
150
-
151
- // ---------- panel empty states (one dim line each; a second line only when the panel has room) ----------
152
-
153
- export const EMPTY = {
154
- code: "nothing open — when I read a file it shows here",
155
- files: ["no files yet", "they appear as I read them"] as const,
156
- plan: ["no plan yet", "my steps show up here"] as const,
157
- usage: "0 so far",
158
- } as const;
@@ -1,183 +0,0 @@
1
- /** Windows process-TREE kill via a kernel Job Object (port #21 HIGH-1).
2
- *
3
- * `taskkill /T` walks LIVE parent links. msys2 (Git bash) implements a
4
- * Cygwin→Cygwin exec by handing the pid to the new image and exiting the
5
- * forked stub, so the external command actually running inside a compound
6
- * (`a; sleep N; b`), nested (`bash -c '…'`) or backgrounded (`x & y & wait`)
7
- * shape has a DEAD Win32 parent and the walk never reaches it. Measured
8
- * through bunRunner on the reference box with an msys `sleep` child: 3/3
9
- * leaks + 3/3 runner hangs per shape (the orphan kept stdout open); only a
10
- * bare `sleep N`, exec'd without a fork, died. A native child (bun.exe) stays
11
- * reachable, which is why the shipped test passed. A Job Object records
12
- * membership at CreateProcess time and inherits it down the tree, so
13
- * TerminateJobObject kills every descendant regardless of parent links.
14
- *
15
- * Per-spawn lifecycle (executor.ts bunRunner):
16
- * createWinJob() → assign(launcherPid) right after Bun.spawn
17
- * abort → terminate() TerminateJobObject, then close
18
- * settle → release() a run that completed on its own:
19
- * drop the close-kill limit, then close — a child the command
20
- * deliberately left behind (`server > log 2>&1 &`) survives, as
21
- * it does on POSIX and did before this port. While the command is
22
- * in flight the limit stays armed, so an rovecode crash takes the
23
- * tree with it (the OS closes the handle).
24
- * assign() also sweeps the launcher's already-visible descendants by a
25
- * Toolhelp32 parent-chain walk: a child forked in the spawn→assign window is
26
- * not a member by inheritance (under load that window can span a scheduler
27
- * quantum). Residual: a Cygwin stub that already exec'd AND exited inside
28
- * that window leaves its child unreachable by any parent walk. The sweep
29
- * costs one process snapshot (~15ms with ~300 processes on the loaded
30
- * reference box).
31
- * Fail-safe: non-win32, no bun:ffi, or any kernel32 call failing → null; the
32
- * caller keeps `taskkill /T /F` alone and reports treeKill "taskkill-only".
33
- * Nested jobs (Windows 8+) let this work when rovecode itself already runs
34
- * inside a job (terminals and IDEs do that): the launcher is then in both. */
35
-
36
- import { dlopen, FFIType, ptr } from "bun:ffi";
37
-
38
- const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000;
39
- const JobObjectExtendedLimitInformation = 9;
40
- /** sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION) on x64; LimitFlags sits at
41
- * BasicLimitInformation offset 16 (after two LARGE_INTEGERs). */
42
- const EXTENDED_LIMIT_SIZE = 144;
43
- const LIMIT_FLAGS_OFFSET = 16;
44
- const PROCESS_SET_QUOTA_AND_TERMINATE = 0x0101;
45
- const TH32CS_SNAPPROCESS = 0x2;
46
- /** sizeof(PROCESSENTRY32W) on x64; th32ProcessID at 8, th32ParentProcessID at 32. */
47
- const PE32_SIZE = 568;
48
- const PE32_PID = 8;
49
- const PE32_PPID = 32;
50
-
51
- type Handle = number;
52
-
53
- interface Kernel32 {
54
- CreateJobObjectW(attrs: null, name: null): Handle | null;
55
- SetInformationJobObject(job: Handle, cls: number, info: number, len: number): number;
56
- AssignProcessToJobObject(job: Handle, proc: Handle): number;
57
- TerminateJobObject(job: Handle, exitCode: number): number;
58
- OpenProcess(access: number, inherit: number, pid: number): Handle | null;
59
- CloseHandle(h: Handle): number;
60
- CreateToolhelp32Snapshot(flags: number, pid: number): Handle | null;
61
- Process32FirstW(snap: Handle, entry: number): number;
62
- Process32NextW(snap: Handle, entry: number): number;
63
- }
64
-
65
- let library: { symbols: unknown } | null | undefined; // undefined = not tried yet
66
- let override: boolean | null = null;
67
-
68
- function kernel32(): Kernel32 | null {
69
- if (library === undefined) {
70
- library = null;
71
- if (process.platform === "win32") {
72
- try {
73
- library = dlopen("kernel32.dll", {
74
- CreateJobObjectW: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr },
75
- SetInformationJobObject: { args: [FFIType.ptr, FFIType.i32, FFIType.ptr, FFIType.u32], returns: FFIType.i32 },
76
- AssignProcessToJobObject: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
77
- TerminateJobObject: { args: [FFIType.ptr, FFIType.u32], returns: FFIType.i32 },
78
- OpenProcess: { args: [FFIType.u32, FFIType.i32, FFIType.u32], returns: FFIType.ptr },
79
- CloseHandle: { args: [FFIType.ptr], returns: FFIType.i32 },
80
- CreateToolhelp32Snapshot: { args: [FFIType.u32, FFIType.u32], returns: FFIType.ptr },
81
- Process32FirstW: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
82
- Process32NextW: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
83
- });
84
- } catch { library = null; }
85
- }
86
- }
87
- return library ? (library.symbols as Kernel32) : null;
88
- }
89
-
90
- /** A kernel HANDLE is a small positive value: NULL arrives as null and
91
- * INVALID_HANDLE_VALUE (-1) fits this range in no representation. */
92
- const isHandle = (h: unknown): h is Handle => typeof h === "number" && h > 0 && h <= 0xffff_ffff;
93
-
94
- /** Whether the real Job Object path is usable here (status surfaces, tests). */
95
- export function winJobsAvailable(): boolean { return override ?? kernel32() !== null; }
96
-
97
- /** Test seam: `false` forces the fail-safe path (the box-without-kernel32
98
- * shape — callers fall back to taskkill-only); `null` restores detection. */
99
- export function overrideWinJobs(available: boolean | null): void { override = available; }
100
-
101
- export interface WinJob {
102
- /** Put `pid` and its currently visible descendants in the job. false →
103
- * nothing is a member (caller must fall back); the job is closed. */
104
- assign(pid: number): boolean;
105
- /** Abort: kill every member now, then close. Idempotent. */
106
- terminate(): void;
107
- /** Normal settle: clear the close-kill limit, then close — members that
108
- * outlived the command keep running. No-op after terminate(). */
109
- release(): void;
110
- }
111
-
112
- /** One job per spawn, armed with KILL_ON_JOB_CLOSE. null = unavailable. */
113
- export function createWinJob(): WinJob | null {
114
- if (override === false) return null;
115
- const k = kernel32();
116
- if (!k) return null;
117
- const job = k.CreateJobObjectW(null, null);
118
- if (!isHandle(job)) return null;
119
- const limits = new Uint8Array(EXTENDED_LIMIT_SIZE);
120
- new DataView(limits.buffer).setUint32(LIMIT_FLAGS_OFFSET, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, true);
121
- if (!k.SetInformationJobObject(job, JobObjectExtendedLimitInformation, ptr(limits), EXTENDED_LIMIT_SIZE)) {
122
- k.CloseHandle(job);
123
- return null;
124
- }
125
- let handle: Handle | null = job;
126
- const close = (): void => { if (handle !== null) { k.CloseHandle(handle); handle = null; } };
127
- const assignOne = (pid: number): boolean => {
128
- if (handle === null) return false;
129
- const p = k.OpenProcess(PROCESS_SET_QUOTA_AND_TERMINATE, 0, pid);
130
- if (!isHandle(p)) return false;
131
- try { return k.AssignProcessToJobObject(handle, p) !== 0; } finally { k.CloseHandle(p); }
132
- };
133
- return {
134
- assign(pid) {
135
- if (!assignOne(pid)) { close(); return false; }
136
- // belt-and-braces for the spawn→assign window; already-member or
137
- // already-exited descendants simply fail to assign, which is fine
138
- for (const d of descendants(k, pid)) assignOne(d);
139
- return true;
140
- },
141
- terminate() {
142
- if (handle === null) return;
143
- k.TerminateJobObject(handle, 1);
144
- close();
145
- },
146
- release() {
147
- if (handle === null) return;
148
- k.SetInformationJobObject(handle, JobObjectExtendedLimitInformation, ptr(new Uint8Array(EXTENDED_LIMIT_SIZE)), EXTENDED_LIMIT_SIZE);
149
- close();
150
- },
151
- };
152
- }
153
-
154
- /** Live descendants of `root` by parent-pid chain (one Toolhelp32 snapshot).
155
- * pids recycle, so a stale parent link could form a cycle: visited-set walk. */
156
- function descendants(k: Kernel32, root: number): number[] {
157
- const snap = k.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
158
- if (!isHandle(snap)) return [];
159
- const children = new Map<number, number[]>();
160
- try {
161
- const entry = new Uint8Array(PE32_SIZE);
162
- const view = new DataView(entry.buffer);
163
- view.setUint32(0, PE32_SIZE, true); // dwSize must be set before Process32FirstW
164
- if (!k.Process32FirstW(snap, ptr(entry))) return [];
165
- do {
166
- const pid = view.getUint32(PE32_PID, true);
167
- const ppid = view.getUint32(PE32_PPID, true);
168
- const list = children.get(ppid);
169
- if (list) list.push(pid); else children.set(ppid, [pid]);
170
- } while (k.Process32NextW(snap, ptr(entry)));
171
- } finally {
172
- k.CloseHandle(snap);
173
- }
174
- const seen = new Set<number>([root]);
175
- const out: number[] = [];
176
- const stack = [root];
177
- while (stack.length > 0) {
178
- for (const c of children.get(stack.pop()!) ?? []) {
179
- if (!seen.has(c)) { seen.add(c); out.push(c); stack.push(c); }
180
- }
181
- }
182
- return out;
183
- }