rovecode 0.3.3 → 0.4.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +46 -48
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-j6gn14w3.js +2 -0
  5. package/dist/cli/ask-user-cwstt8fz.js +2 -0
  6. package/dist/cli/auth-login-9bbp9915.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-16zqdms5.js +9 -0
  9. package/dist/cli/catalog-1xchffa4.js +2 -0
  10. package/dist/cli/cli-1n1zb64f.js +2 -0
  11. package/dist/cli/client-2t9gjkck.js +2 -0
  12. package/dist/cli/commands-exafvm2b.js +2 -0
  13. package/dist/cli/connect-6zde0kn3.js +2 -0
  14. package/dist/cli/context-cmd-5t43wgqt.js +2 -0
  15. package/dist/cli/context-report-kt01pw8y.js +2 -0
  16. package/dist/cli/count-remote-ap7x3vh6.js +2 -0
  17. package/dist/cli/design-ne5zszyh.js +2 -0
  18. package/dist/cli/dispatch-2r5myxye.js +2 -0
  19. package/dist/cli/doctor-ws4fh4tn.js +3 -0
  20. package/dist/cli/executor-bdrjn634.js +2 -0
  21. package/dist/cli/export-1mxb9g5p.js +2 -0
  22. package/dist/cli/files-g104xghh.js +2 -0
  23. package/dist/cli/gauntlet-07xrjpj7.js +2 -0
  24. package/dist/cli/gauntlet-runner-xvy64436.js +10 -0
  25. package/dist/cli/gauntlet-wave3-jm91yt5w.js +5 -0
  26. package/dist/cli/gauntlet-wave4-r13py7p1.js +14 -0
  27. package/dist/cli/hashline-znvrat11.js +2 -0
  28. package/dist/cli/http-xafw6fsh.js +143 -0
  29. package/dist/cli/index-1sgjm25y.js +2 -0
  30. package/dist/cli/init-g2m0tn4m.js +51 -0
  31. package/dist/cli/install-avaqjjqq.js +2 -0
  32. package/dist/cli/loop-mmpfft01.js +2 -0
  33. package/dist/cli/main-0904f6ps.js +5 -0
  34. package/dist/cli/main-0ab9fc26.js +9 -0
  35. package/dist/cli/main-0jys2ccn.js +3 -0
  36. package/dist/cli/main-0mtcdbs7.js +3 -0
  37. package/dist/cli/main-0z1w2zsg.js +3 -0
  38. package/dist/cli/main-1dchs7xv.js +18 -0
  39. package/dist/cli/main-1ereejm1.js +3 -0
  40. package/dist/cli/main-1k1kw6b5.js +3 -0
  41. package/dist/cli/main-27y4sm2k.js +38 -0
  42. package/dist/cli/main-2wwjex5j.js +58 -0
  43. package/dist/cli/main-2yeveeve.js +6 -0
  44. package/dist/cli/main-2yfck9b5.js +3 -0
  45. package/dist/cli/main-2zmzgkwh.js +3 -0
  46. package/dist/cli/main-351pz3z7.js +7 -0
  47. package/dist/cli/main-3gjqfh7a.js +6 -0
  48. package/dist/cli/main-3nf3kgve.js +3 -0
  49. package/dist/cli/main-3pjrb2hd.js +3 -0
  50. package/dist/cli/main-3rxcvgna.js +19 -0
  51. package/dist/cli/main-4b3jgy66.js +19 -0
  52. package/dist/cli/main-4wndhjdc.js +7 -0
  53. package/dist/cli/main-4xcmvxnk.js +3 -0
  54. package/dist/cli/main-5tbz0wbz.js +4 -0
  55. package/dist/cli/main-5ywnwthm.js +3 -0
  56. package/dist/cli/main-6b62vkz0.js +14 -0
  57. package/dist/cli/main-6dnk69vp.js +3 -0
  58. package/dist/cli/main-6genrmhs.js +136 -0
  59. package/dist/cli/main-73g7eff4.js +15 -0
  60. package/dist/cli/main-7c5thhjd.js +5 -0
  61. package/dist/cli/main-7rn6bqje.js +3 -0
  62. package/dist/cli/main-80haw7qk.js +4 -0
  63. package/dist/cli/main-875s60s2.js +4 -0
  64. package/dist/cli/main-8kjxbpw4.js +8 -0
  65. package/dist/cli/main-90ds1z4e.js +10 -0
  66. package/dist/cli/main-9etavkew.js +3 -0
  67. package/dist/cli/main-a9njrkk1.js +3 -0
  68. package/dist/cli/main-aecrjq2d.js +12 -0
  69. package/dist/cli/main-ck9asesq.js +9 -0
  70. package/dist/cli/main-cta9racd.js +4 -0
  71. package/dist/cli/main-ddv7j2ag.js +3 -0
  72. package/dist/cli/main-dfreez27.js +10 -0
  73. package/dist/cli/main-f7rw7des.js +3 -0
  74. package/dist/cli/main-ggcn7rd7.js +5 -0
  75. package/dist/cli/main-gzkmycnv.js +3 -0
  76. package/dist/cli/main-hq51jg8v.js +18 -0
  77. package/dist/cli/main-jft389w9.js +8 -0
  78. package/dist/cli/main-k1eqkg83.js +3 -0
  79. package/dist/cli/main-k2y8a2aw.js +9 -0
  80. package/dist/cli/main-kcpbykxz.js +4 -0
  81. package/dist/cli/main-kd488vje.js +22 -0
  82. package/dist/cli/main-kh32yvgk.js +5 -0
  83. package/dist/cli/main-kqxnqjnv.js +25 -0
  84. package/dist/cli/main-kyn0xnsg.js +3 -0
  85. package/dist/cli/main-m1kk6fp5.js +21 -0
  86. package/dist/cli/main-mv40pcr2.js +4 -0
  87. package/dist/cli/main-n0t3973w.js +3 -0
  88. package/dist/cli/main-nqveez48.js +4 -0
  89. package/dist/cli/main-pknhvrmj.js +3 -0
  90. package/dist/cli/main-pn1w7a7j.js +3 -0
  91. package/dist/cli/main-prxxs70n.js +4 -0
  92. package/dist/cli/main-q3vsesf9.js +3 -0
  93. package/dist/cli/main-qsevpgsv.js +3 -0
  94. package/dist/cli/main-rdgdw24b.js +25 -0
  95. package/dist/cli/main-rfth4tbm.js +16 -0
  96. package/dist/cli/main-rg0wn0xf.js +5 -0
  97. package/dist/cli/main-sdmxhtv8.js +4 -0
  98. package/dist/cli/main-skbp13js.js +18 -0
  99. package/dist/cli/main-t4xnd213.js +7 -0
  100. package/dist/cli/main-vqak588n.js +4 -0
  101. package/dist/cli/main-w2n1303f.js +9 -0
  102. package/dist/cli/main-wbrdspr2.js +5 -0
  103. package/dist/cli/main-wsrg79c1.js +7 -0
  104. package/dist/cli/main-x4r0fne4.js +5 -0
  105. package/dist/cli/main-xea2f3tn.js +6 -0
  106. package/dist/cli/main-xg704a3c.js +3 -0
  107. package/dist/cli/main-xvnrabfp.js +16 -0
  108. package/dist/cli/main-xy53xf0r.js +4 -0
  109. package/dist/cli/main-y1fqy60y.js +3 -0
  110. package/dist/cli/main-yn8cd281.js +34 -0
  111. package/dist/cli/main-yr0ksc0h.js +4 -0
  112. package/dist/cli/main-z2ex2vyf.js +4 -0
  113. package/dist/cli/main-z3aayzvq.js +3 -0
  114. package/dist/cli/main-zaqh35jg.js +3 -0
  115. package/dist/cli/main-zc2e8e46.js +4 -0
  116. package/dist/cli/main-zzrfw6cf.js +13 -0
  117. package/dist/cli/main.js +280 -0
  118. package/dist/cli/market-cmd-e14kmx9n.js +5 -0
  119. package/dist/cli/mcp-login-wq7ktdek.js +2 -0
  120. package/dist/cli/mcp-market-cmd-9mg3jecy.js +2 -0
  121. package/dist/cli/notify-b7qc0cjb.js +2 -0
  122. package/dist/cli/oauth-z8whcgfx.js +2 -0
  123. package/dist/cli/output-b3ewj3ps.js +16 -0
  124. package/dist/cli/profiles-6mr5he5e.js +2 -0
  125. package/dist/cli/provider-config-g7j42q8x.js +2 -0
  126. package/dist/cli/provider-jr1y8vvm.js +2 -0
  127. package/dist/cli/registry-s8yk86g0.js +2 -0
  128. package/dist/cli/registry-t6p8d4mn.js +2 -0
  129. package/dist/cli/repl-bajwe1mh.js +11 -0
  130. package/dist/cli/resume-rwn9nz7y.js +2 -0
  131. package/dist/cli/run-flags-nah7ndpt.js +2 -0
  132. package/dist/cli/runtime-n7gafzhb.js +2 -0
  133. package/dist/cli/sandbox-config-emdy18x4.js +2 -0
  134. package/dist/cli/server-b0nvs2bn.js +5 -0
  135. package/dist/cli/session-arg-y75wd4kj.js +2 -0
  136. package/dist/cli/session-j62evmjq.js +2 -0
  137. package/dist/cli/sessions-cmd-tsnwz0ns.js +7 -0
  138. package/dist/cli/settings-df10wfez.js +2 -0
  139. package/dist/cli/setup-jzvv72fg.js +2 -0
  140. package/dist/cli/sextant-smoke-37m81ke6.js +5 -0
  141. package/dist/cli/skills-cmd-gjxnxnhx.js +2 -0
  142. package/dist/cli/smoke-p7748apt.js +8 -0
  143. package/dist/cli/start-chat-s4st3mm0.js +12 -0
  144. package/dist/cli/stream-gmeyewds.js +2 -0
  145. package/dist/cli/task-gh0kkp3n.js +2 -0
  146. package/dist/cli/tasks-z1kfpe8e.js +2 -0
  147. package/dist/cli/thinking-0eqkrz6t.js +2 -0
  148. package/dist/cli/todo-5brcrt9m.js +2 -0
  149. package/dist/cli/tools-7pzm0vj9.js +2 -0
  150. package/dist/cli/tools-s635p6s8.js +2 -0
  151. package/dist/cli/trust-cmd-cjav8zgm.js +2 -0
  152. package/dist/cli/update-check-pt31bm2f.js +2 -0
  153. package/dist/cli/update-cmd-tk131s9t.js +2 -0
  154. package/dist/cli/voice-56nabd8d.js +2 -0
  155. package/dist/cli/webfetch-xd8q596m.js +2 -0
  156. package/dist/cli/websearch-5hkf98k1.js +2 -0
  157. package/dist/cli/workflow-cmd-cy3cvzjp.js +4 -0
  158. package/dist/cli/workspace-q10g5z3e.js +2 -0
  159. package/dist/lib/index.js +62 -0
  160. package/dist/lib/models-index.json +1 -0
  161. package/dist/lib/plugins.js +55 -0
  162. package/dist/lib/providers.js +17 -0
  163. package/dist/lib/public-api.js +20 -0
  164. package/dist/lib/sdk.js +360 -0
  165. package/package.json +84 -72
  166. package/bin/rovecode.ts +0 -21
  167. package/src/acp/server.ts +0 -374
  168. package/src/cli/auth-login.ts +0 -122
  169. package/src/cli/connect.ts +0 -244
  170. package/src/cli/context-cmd.ts +0 -199
  171. package/src/cli/dispatch.ts +0 -82
  172. package/src/cli/doctor.ts +0 -362
  173. package/src/cli/export.ts +0 -276
  174. package/src/cli/help.ts +0 -293
  175. package/src/cli/is-tui-invocation.ts +0 -8
  176. package/src/cli/main.ts +0 -583
  177. package/src/cli/market-cmd.ts +0 -658
  178. package/src/cli/mcp-login.ts +0 -141
  179. package/src/cli/mcp-market-cmd.ts +0 -302
  180. package/src/cli/output.ts +0 -382
  181. package/src/cli/repl.ts +0 -250
  182. package/src/cli/repomap-root.ts +0 -14
  183. package/src/cli/resume.ts +0 -57
  184. package/src/cli/run-flags.ts +0 -43
  185. package/src/cli/run-limits.ts +0 -78
  186. package/src/cli/runtime.ts +0 -931
  187. package/src/cli/session-arg.ts +0 -30
  188. package/src/cli/sessions-cmd.ts +0 -145
  189. package/src/cli/setup.ts +0 -153
  190. package/src/cli/skills-cmd.ts +0 -194
  191. package/src/cli/start-chat.ts +0 -65
  192. package/src/cli/trust-cmd.ts +0 -52
  193. package/src/coding/bash.ts +0 -148
  194. package/src/coding/checkpoints.ts +0 -327
  195. package/src/coding/diff.ts +0 -138
  196. package/src/coding/files.ts +0 -341
  197. package/src/coding/hashline.ts +0 -274
  198. package/src/coding/lsp-gate.ts +0 -254
  199. package/src/coding/lsp-servers.ts +0 -147
  200. package/src/coding/lsp.ts +0 -283
  201. package/src/coding/repomap-cache.ts +0 -99
  202. package/src/coding/repomap-files.ts +0 -192
  203. package/src/coding/repomap.ts +0 -481
  204. package/src/core/agents.ts +0 -255
  205. package/src/core/compaction.ts +0 -259
  206. package/src/core/config.ts +0 -289
  207. package/src/core/context-report.ts +0 -228
  208. package/src/core/context.ts +0 -60
  209. package/src/core/count-remote.ts +0 -107
  210. package/src/core/execpolicy-rules.ts +0 -196
  211. package/src/core/execpolicy.ts +0 -385
  212. package/src/core/executor.ts +0 -454
  213. package/src/core/guardrails.ts +0 -400
  214. package/src/core/hooks.ts +0 -411
  215. package/src/core/images.ts +0 -230
  216. package/src/core/intro.ts +0 -266
  217. package/src/core/loop.ts +0 -567
  218. package/src/core/modes.ts +0 -372
  219. package/src/core/orchestrator.ts +0 -245
  220. package/src/core/proc-group.ts +0 -48
  221. package/src/core/project-trust.ts +0 -98
  222. package/src/core/reflection.ts +0 -165
  223. package/src/core/sandbox-config.ts +0 -186
  224. package/src/core/session-id.ts +0 -24
  225. package/src/core/session-images.ts +0 -73
  226. package/src/core/session-ops.ts +0 -183
  227. package/src/core/session-text.ts +0 -29
  228. package/src/core/session.ts +0 -469
  229. package/src/core/settings.ts +0 -170
  230. package/src/core/tasks.ts +0 -646
  231. package/src/core/token-scale.ts +0 -108
  232. package/src/core/tools.ts +0 -309
  233. package/src/core/trust.ts +0 -104
  234. package/src/core/types.ts +0 -330
  235. package/src/core/update-check.ts +0 -171
  236. package/src/core/usage.ts +0 -204
  237. package/src/core/validate.ts +0 -121
  238. package/src/core/verify-gate.ts +0 -159
  239. package/src/core/verify.ts +0 -236
  240. package/src/core/voice.ts +0 -158
  241. package/src/core/win-job.ts +0 -183
  242. package/src/core/workspace.ts +0 -184
  243. package/src/design/audit.ts +0 -797
  244. package/src/design/direction.ts +0 -190
  245. package/src/design/rules.ts +0 -157
  246. package/src/eval/bench.ts +0 -150
  247. package/src/eval/gauntlet-runner.ts +0 -215
  248. package/src/eval/gauntlet-support.ts +0 -84
  249. package/src/eval/gauntlet-wave3.ts +0 -269
  250. package/src/eval/gauntlet-wave4.ts +0 -217
  251. package/src/eval/gauntlet.ts +0 -253
  252. package/src/index.ts +0 -17
  253. package/src/lanes/agy.ts +0 -95
  254. package/src/lanes/approval.ts +0 -24
  255. package/src/lanes/claude.ts +0 -129
  256. package/src/lanes/codex.ts +0 -127
  257. package/src/lanes/events.ts +0 -130
  258. package/src/lanes/job.ts +0 -142
  259. package/src/lanes/opencode.ts +0 -122
  260. package/src/lanes/process.ts +0 -184
  261. package/src/lanes/progress.ts +0 -183
  262. package/src/lanes/registry.ts +0 -178
  263. package/src/lanes/runner.ts +0 -124
  264. package/src/lanes/types.ts +0 -112
  265. package/src/market/catalogs/mcp-docs.json +0 -111
  266. package/src/market/catalogs/plugins.json +0 -111
  267. package/src/market/catalogs/skills.json +0 -478
  268. package/src/market/clone.ts +0 -72
  269. package/src/market/context-cost.ts +0 -121
  270. package/src/market/digest.ts +0 -106
  271. package/src/market/index.ts +0 -22
  272. package/src/market/install.ts +0 -578
  273. package/src/market/manifest.ts +0 -187
  274. package/src/market/prereq.ts +0 -145
  275. package/src/market/registry.ts +0 -363
  276. package/src/market/resolve.ts +0 -111
  277. package/src/market/types.ts +0 -236
  278. package/src/market/validate.ts +0 -227
  279. package/src/mcp/client.ts +0 -449
  280. package/src/mcp/config.ts +0 -252
  281. package/src/mcp/local-package.ts +0 -211
  282. package/src/mcp/market-catalog.ts +0 -84
  283. package/src/mcp/market-install.ts +0 -289
  284. package/src/mcp/market.ts +0 -362
  285. package/src/mcp/oauth.ts +0 -251
  286. package/src/mcp/prompts-resources.ts +0 -249
  287. package/src/mcp/shared.ts +0 -149
  288. package/src/mcp/status.ts +0 -67
  289. package/src/mcp/tools.ts +0 -275
  290. package/src/mcp/transport.ts +0 -122
  291. package/src/mcp/trust.ts +0 -25
  292. package/src/memory/blocks.ts +0 -278
  293. package/src/memory/recall.ts +0 -355
  294. package/src/memory/scope.ts +0 -182
  295. package/src/memory/store.ts +0 -105
  296. package/src/memory/tools.ts +0 -99
  297. package/src/plugins/cli.ts +0 -119
  298. package/src/plugins/discover.ts +0 -108
  299. package/src/plugins/index.ts +0 -50
  300. package/src/plugins/install.ts +0 -184
  301. package/src/plugins/load.ts +0 -124
  302. package/src/plugins/manifest.ts +0 -92
  303. package/src/plugins/state.ts +0 -83
  304. package/src/providers/auth.ts +0 -408
  305. package/src/providers/cache.ts +0 -223
  306. package/src/providers/catalog-local.ts +0 -160
  307. package/src/providers/catalog.ts +0 -421
  308. package/src/providers/middleware-context.ts +0 -86
  309. package/src/providers/middleware.ts +0 -373
  310. package/src/providers/model-list.ts +0 -23
  311. package/src/providers/oauth/common.ts +0 -105
  312. package/src/providers/oauth/device-code.ts +0 -107
  313. package/src/providers/oauth/github-copilot.ts +0 -146
  314. package/src/providers/oauth/loopback.ts +0 -158
  315. package/src/providers/oauth/openai.ts +0 -163
  316. package/src/providers/oauth/openrouter.ts +0 -89
  317. package/src/providers/oauth/pkce.ts +0 -45
  318. package/src/providers/oauth/registry.ts +0 -39
  319. package/src/providers/oauth/seam.ts +0 -89
  320. package/src/providers/profile-glm53.ts +0 -111
  321. package/src/providers/profile-sonnet5-persona.ts +0 -65
  322. package/src/providers/profile-sonnet5-voice.ts +0 -23
  323. package/src/providers/profiles.ts +0 -156
  324. package/src/providers/provider-config.ts +0 -311
  325. package/src/providers/registry.ts +0 -333
  326. package/src/providers/responses.ts +0 -209
  327. package/src/providers/retry.ts +0 -234
  328. package/src/providers/router.ts +0 -294
  329. package/src/providers/sse.ts +0 -26
  330. package/src/providers/stream-errors.ts +0 -117
  331. package/src/providers/stream.ts +0 -566
  332. package/src/providers/thinking.ts +0 -189
  333. package/src/providers/wire-messages.ts +0 -129
  334. package/src/providers/wire-responses.ts +0 -79
  335. package/src/providers/wire-select.ts +0 -53
  336. package/src/server/http.ts +0 -291
  337. package/src/server/openapi.ts +0 -246
  338. package/src/sextant/card-hits.ts +0 -102
  339. package/src/sextant/card-keys.ts +0 -55
  340. package/src/sextant/context-source.ts +0 -157
  341. package/src/sextant/crew-cards.ts +0 -350
  342. package/src/sextant/draw-agents.ts +0 -273
  343. package/src/sextant/draw-code.ts +0 -388
  344. package/src/sextant/draw-context.ts +0 -222
  345. package/src/sextant/draw-frame.ts +0 -164
  346. package/src/sextant/draw-market.ts +0 -573
  347. package/src/sextant/draw-messages.ts +0 -386
  348. package/src/sextant/draw-pet.ts +0 -230
  349. package/src/sextant/draw-plan.ts +0 -187
  350. package/src/sextant/draw-tabs.ts +0 -85
  351. package/src/sextant/draw-util.ts +0 -65
  352. package/src/sextant/draw-wizard.ts +0 -378
  353. package/src/sextant/engine.ts +0 -230
  354. package/src/sextant/frame-hits.ts +0 -25
  355. package/src/sextant/frame.ts +0 -101
  356. package/src/sextant/git-status.ts +0 -197
  357. package/src/sextant/grid.ts +0 -59
  358. package/src/sextant/input.ts +0 -119
  359. package/src/sextant/keys.ts +0 -521
  360. package/src/sextant/layout.ts +0 -86
  361. package/src/sextant/local-commands.ts +0 -169
  362. package/src/sextant/market-source.ts +0 -287
  363. package/src/sextant/mentions.ts +0 -200
  364. package/src/sextant/message-hits.ts +0 -26
  365. package/src/sextant/model.ts +0 -387
  366. package/src/sextant/overlays.ts +0 -456
  367. package/src/sextant/panel-hits.ts +0 -38
  368. package/src/sextant/pet.ts +0 -399
  369. package/src/sextant/screen.ts +0 -324
  370. package/src/sextant/scroll-hits.ts +0 -66
  371. package/src/sextant/scrollbar.ts +0 -82
  372. package/src/sextant/sextant-bridge.ts +0 -174
  373. package/src/sextant/sextant-cards.ts +0 -142
  374. package/src/sextant/sextant-diff-base.ts +0 -63
  375. package/src/sextant/sextant-files.ts +0 -154
  376. package/src/sextant/sextant-frame-loop.ts +0 -335
  377. package/src/sextant/sextant-renderer.ts +0 -574
  378. package/src/sextant/sextant-repo.ts +0 -140
  379. package/src/sextant/theme.ts +0 -66
  380. package/src/sextant/tool-rows.ts +0 -189
  381. package/src/sextant/types.ts +0 -493
  382. package/src/skills/index.ts +0 -387
  383. package/src/skills/pack.ts +0 -220
  384. package/src/skills/spec.ts +0 -162
  385. package/src/skills/tools.ts +0 -69
  386. package/src/skills/versioned.ts +0 -227
  387. package/src/telemetry/otel-export.ts +0 -122
  388. package/src/telemetry/otel-lanes.ts +0 -89
  389. package/src/telemetry/otel-logs.ts +0 -131
  390. package/src/telemetry/otel-metrics.ts +0 -136
  391. package/src/telemetry/otel.ts +0 -397
  392. package/src/telemetry/otlp.ts +0 -76
  393. package/src/tools/ask-user.ts +0 -156
  394. package/src/tools/bash-bg.ts +0 -94
  395. package/src/tools/bash-jobs.ts +0 -237
  396. package/src/tools/design.ts +0 -151
  397. package/src/tools/evalcell.ts +0 -338
  398. package/src/tools/html-text.ts +0 -139
  399. package/src/tools/provider.ts +0 -149
  400. package/src/tools/task.ts +0 -250
  401. package/src/tools/todo.ts +0 -320
  402. package/src/tools/webfetch.ts +0 -332
  403. package/src/tools/websearch.ts +0 -359
  404. package/src/tui/agents-cmd.ts +0 -41
  405. package/src/tui/app.ts +0 -749
  406. package/src/tui/attach.ts +0 -127
  407. package/src/tui/boot-notes.ts +0 -41
  408. package/src/tui/builtin-prompts.ts +0 -59
  409. package/src/tui/checkpoints-cmd.ts +0 -70
  410. package/src/tui/clipboard-image.ts +0 -81
  411. package/src/tui/clipboard.ts +0 -78
  412. package/src/tui/commands.ts +0 -283
  413. package/src/tui/config-view.ts +0 -53
  414. package/src/tui/context-cmds.ts +0 -282
  415. package/src/tui/cost.ts +0 -108
  416. package/src/tui/crash-guard.ts +0 -173
  417. package/src/tui/focus-terminal.ts +0 -34
  418. package/src/tui/git-cmds.ts +0 -273
  419. package/src/tui/git-plain.ts +0 -58
  420. package/src/tui/info-cmd.ts +0 -150
  421. package/src/tui/input-plain.ts +0 -76
  422. package/src/tui/mcp-cmd.ts +0 -128
  423. package/src/tui/memory-note.ts +0 -77
  424. package/src/tui/modes-cmd.ts +0 -45
  425. package/src/tui/notify-seq.ts +0 -100
  426. package/src/tui/notify.ts +0 -318
  427. package/src/tui/overlays.ts +0 -97
  428. package/src/tui/pi-renderer.ts +0 -428
  429. package/src/tui/providers-cmd.ts +0 -377
  430. package/src/tui/reasoning-view.ts +0 -56
  431. package/src/tui/renderer.ts +0 -128
  432. package/src/tui/replay-marker.ts +0 -29
  433. package/src/tui/session-cmd.ts +0 -148
  434. package/src/tui/session-manage.ts +0 -95
  435. package/src/tui/sextant-attach.ts +0 -102
  436. package/src/tui/sextant-io.ts +0 -202
  437. package/src/tui/sextant-smoke.ts +0 -110
  438. package/src/tui/shell-cmd.ts +0 -158
  439. package/src/tui/smoke.ts +0 -72
  440. package/src/tui/staged-terminal.ts +0 -50
  441. package/src/tui/startup.ts +0 -12
  442. package/src/tui/theme.ts +0 -59
  443. package/src/tui/todo-label.ts +0 -7
  444. package/src/tui/trust-card.ts +0 -107
  445. package/src/tui/tui-commands.ts +0 -87
  446. package/tsconfig.json +0 -30
  447. package/vendor/pi-tui/LICENSE +0 -21
  448. package/vendor/pi-tui/PATCHES.md +0 -12
  449. package/vendor/pi-tui/PROVENANCE.md +0 -12
  450. package/vendor/pi-tui/README.upstream.md +0 -854
  451. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  452. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  453. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  454. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  455. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  456. package/vendor/pi-tui/src/components/box.ts +0 -138
  457. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  458. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  459. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  460. package/vendor/pi-tui/src/components/image.ts +0 -128
  461. package/vendor/pi-tui/src/components/input.ts +0 -448
  462. package/vendor/pi-tui/src/components/loader.ts +0 -93
  463. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  464. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  465. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  466. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  467. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  468. package/vendor/pi-tui/src/components/stack.ts +0 -155
  469. package/vendor/pi-tui/src/components/text.ts +0 -108
  470. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  471. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  472. package/vendor/pi-tui/src/editor-component.ts +0 -75
  473. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  474. package/vendor/pi-tui/src/index.ts +0 -149
  475. package/vendor/pi-tui/src/keybindings.ts +0 -321
  476. package/vendor/pi-tui/src/keys.ts +0 -1402
  477. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  478. package/vendor/pi-tui/src/latex.ts +0 -1381
  479. package/vendor/pi-tui/src/layout-node.ts +0 -52
  480. package/vendor/pi-tui/src/layout.ts +0 -411
  481. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  482. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  483. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  484. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  485. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  486. package/vendor/pi-tui/src/terminal.ts +0 -554
  487. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  488. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  489. package/vendor/pi-tui/src/tui.ts +0 -1264
  490. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  491. package/vendor/pi-tui/src/utils.ts +0 -1327
  492. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  493. package/vendor/pi-tui/test/test-themes.ts +0 -39
  494. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  495. /package/{src/providers → dist/cli}/models-index.json +0 -0
@@ -1,338 +0,0 @@
1
- /**
2
- * PORT #18 — persistent eval cell, feature-flagged (ROVECODE_EVAL_CELL=1).
3
- *
4
- * Concept sources (research/source_snapshots):
5
- * - OMP (can1357-oh-my-pi), MIT — persistent eval cells:
6
- * docs/tools/eval.md:3 ("one tool call is one cell; state survives later calls"),
7
- * :108 ("Persistent worker VM keyed by js:${sessionId}"; reset recreates the VM),
8
- * :179 ("Cancellation is destructive when needed: JS terminates its worker"),
9
- * :185 (output window byte budget), :65 ("(no output)" placeholder).
10
- * packages/coding-agent/src/eval/js/shared/indirect-eval.ts:13-23 — user code runs
11
- * through *indirect* `globalThis.eval` (global scope), deliberately NOT node:vm:
12
- * Bun SIGTRAPs when Worker.terminate() fires mid-vm.runInContext — and terminate
13
- * is exactly our timeout path.
14
- * packages/coding-agent/src/eval/js/worker-core.ts:279-308 — run/result message
15
- * protocol; execution errors become result payloads, never worker throws.
16
- * packages/coding-agent/src/eval/js/shared/rewrite-imports.ts:531-550 — TS strip +
17
- * async wrapping (docs/tools/eval.md:110). Simplified here: Bun.Transpiler with
18
- * deadCodeElimination:false (keeps the trailing expression), thenable completion
19
- * values awaited, and one async-IIFE retry at whichever stage rejects bare
20
- * top-level forms (enables top-level await / bare return; declarations in the
21
- * wrapped path are cell-local):
22
- * - transpile stage: the transpiler parses cells as ES modules, so bare
23
- * `return` is a BuildMessage error there — retry transpiling the ORIGINAL
24
- * source wrapped (types still strip); if that also fails, rethrow the first
25
- * error so diagnostics point at the unwrapped code;
26
- * - eval stage: top-level `await` is module-legal but eval-illegal
27
- * (SyntaxError) — retry evaluating the transpiled js wrapped.
28
- * - prime-agent RLM single-REPL concept: prime-agent-runtime/src/rlm/repl.md:3-5
29
- * (cells execute "in one persistent __main__ namespace" per session), :53-55
30
- * (result = repr of the trailing expression), repl.py. BLUEPRINT rejects the
31
- * Python kernel, so this is the TS-only analog: one Bun Worker per session.
32
- *
33
- * Ouroboros rule — what cell code CAN see:
34
- * - Standard Bun Worker realm globals: Bun, fetch, process (including the inherited
35
- * process.env — same trust level as the bash tool's child shell), timers, require.
36
- * This is NOT a security sandbox; the "execute" policy gate (deny-default → prompt)
37
- * is the control, exactly like bash.
38
- * - Bootstrap additions to the global scope: the six console methods are replaced
39
- * with capture stubs, and `self.onmessage` holds the (secret-free) runner.
40
- * Everything else lives in the bootstrap IIFE's closure, unreachable from cell
41
- * code, which evaluates via indirect eval in the worker's global scope.
42
- * What is NOT pre-exposed (a non-exposure claim, NOT unreachability): nothing from
43
- * the rovecode module graph is imported into or handed to the worker — it loads only
44
- * this inline bootstrap blob, so the tool registry (v1 deliberately has NO tool
45
- * re-entry bridge — scope note), session stores, permission/approval machinery,
46
- * and the graders under src/eval/* stay live only in the host process, and the
47
- * only traffic across the seam is {id, code} in and {id, ok, stdout, value, error}
48
- * out via postMessage. Cell code CAN still `await import()` or Bun.file-read any
49
- * file on disk (src/** included) exactly like the bash tool can run `bun -e` —
50
- * the execute-kind policy gate is the control there, not the worker boundary.
51
- *
52
- * Lifecycle: worker per ctx.sessionId, created lazily, unref'd so it never holds the
53
- * host process open. Cell errors keep the worker (state survives); timeout/abort/reset
54
- * terminate it and the session's cell state is lost (reported in the output). An
55
- * uncaught BACKGROUND error (timer throw / unhandled rejection firing the worker
56
- * "error" event, possibly with no call in flight) also kills the worker; the reason is
57
- * parked in `crashed` and the next call's output is prefixed with a crash note, so a
58
- * fresh cell never silently contradicts "state survives". A cell that kills its own
59
- * worker cleanly (e.g. process.exit()) fires no error event and surfaces as a timeout
60
- * on a later call.
61
- */
62
-
63
- import type { Tool, ToolContext, ToolOutput } from "../core/types.ts";
64
-
65
- export const EVAL_CELL_FLAG = "ROVECODE_EVAL_CELL";
66
-
67
- const DEFAULT_TIMEOUT_MS = 10_000;
68
- const MIN_TIMEOUT_MS = 50;
69
- const MAX_TIMEOUT_MS = 120_000;
70
- const DEFAULT_OUTPUT_BYTES = 16_384;
71
- const MIN_OUTPUT_BYTES = 256;
72
- const MAX_OUTPUT_BYTES = 65_536;
73
-
74
- /** Self-contained worker bootstrap (plain JS, no imports — see ouroboros note above).
75
- * Hard caps inside the worker bound postMessage payloads; the model-facing byte
76
- * budget is enforced host-side by truncateToBudget. */
77
- const BOOTSTRAP = `
78
- (() => {
79
- "use strict";
80
- const MAX_CAPTURE = 1048576;
81
- const MAX_VALUE = 262144;
82
- const transpiler = new Bun.Transpiler({ loader: "ts", deadCodeElimination: false });
83
- let buf = [];
84
- let bufLen = 0;
85
- let capped = false;
86
- const fmt = (v) => (typeof v === "string" ? v : Bun.inspect(v));
87
- const capture = (...parts) => {
88
- if (capped) return;
89
- const line = parts.map(fmt).join(" ") + "\\n";
90
- bufLen += line.length;
91
- if (bufLen > MAX_CAPTURE) { capped = true; buf.push("[console capture cap reached]\\n"); return; }
92
- buf.push(line);
93
- };
94
- for (const k of ["log", "info", "warn", "error", "debug", "trace"]) console[k] = capture;
95
- self.onmessage = async (ev) => {
96
- const { id, code } = ev.data;
97
- buf = []; bufLen = 0; capped = false;
98
- let ok = true; let value = ""; let error = "";
99
- try {
100
- // Bare top-level return is illegal in a module, so it fails at TRANSPILE time
101
- // (BuildMessage), before eval — retry with the original source async-wrapped.
102
- // If the wrapped transpile fails too, the code is genuinely broken: rethrow the
103
- // FIRST error so diagnostics describe the unwrapped source.
104
- let js; let preWrapped = false;
105
- try {
106
- js = transpiler.transformSync(code);
107
- } catch (e1) {
108
- try { js = transpiler.transformSync("(async () => {\\n" + code + "\\n})()"); preWrapped = true; }
109
- catch { throw e1; }
110
- }
111
- let v;
112
- try {
113
- v = (0, eval)(js);
114
- } catch (e) {
115
- // Top-level await is module-legal but a SyntaxError in plain eval; retry
116
- // wrapped (OMP docs/tools/eval.md:110). Declarations in wrapped paths
117
- // (either stage) are cell-local.
118
- if (!preWrapped && e instanceof SyntaxError) v = (0, eval)("(async () => {\\n" + js + "\\n})()");
119
- else throw e;
120
- }
121
- if (v && (typeof v === "object" || typeof v === "function") && typeof v.then === "function") v = await v;
122
- if (v !== undefined) {
123
- value = Bun.inspect(v);
124
- if (value.length > MAX_VALUE) value = value.slice(0, MAX_VALUE) + "...[value capped]";
125
- }
126
- } catch (e) {
127
- ok = false;
128
- error = e instanceof Error ? e.name + ": " + e.message : String(e);
129
- }
130
- postMessage({ id, ok, stdout: buf.join(""), value, error });
131
- };
132
- postMessage({ type: "ready" });
133
- })();
134
- `;
135
-
136
- interface WorkerResult { id: number; ok: boolean; stdout: string; value: string; error: string }
137
-
138
- interface CellRuntime {
139
- worker: Worker;
140
- pending: Map<number, (r: WorkerResult) => void>;
141
- ready: Promise<void>;
142
- }
143
-
144
- const cells = new Map<string, CellRuntime>();
145
- /** Reasons from worker "error" events (background timer throws / unhandled
146
- * rejections), parked per session: with no call in flight destroyCell has nobody
147
- * to tell, so the NEXT call consumes the reason and explains its fresh cell. */
148
- const crashed = new Map<string, string>();
149
- let callSeq = 0;
150
- let bootstrapUrl: string | null = null;
151
-
152
- /** Bun's ErrorEvent.message is a multi-line source excerpt + stack; condense to the
153
- * `error: …` line (or a flattened whole) so crash notes stay one line. */
154
- function crashReason(raw: string): string {
155
- const lines = raw.split("\n").map((l) => l.trim()).filter((l) => l !== "");
156
- const flat = (lines.find((l) => /^\w*[Ee]rror:/.test(l)) ?? lines.join(" ")).replace(/\s+/g, " ");
157
- return flat === "" ? "unknown worker error" : flat.length > 200 ? flat.slice(0, 200) + "…" : flat;
158
- }
159
-
160
- function urlForBootstrap(): string {
161
- if (bootstrapUrl === null) {
162
- bootstrapUrl = URL.createObjectURL(new Blob([BOOTSTRAP], { type: "application/javascript" }));
163
- }
164
- return bootstrapUrl;
165
- }
166
-
167
- function spawnCell(sessionId: string): CellRuntime {
168
- const worker = new Worker(urlForBootstrap());
169
- const pending = new Map<number, (r: WorkerResult) => void>();
170
- let readyResolve: () => void = () => {};
171
- const ready = new Promise<void>((res) => { readyResolve = res; });
172
- const runtime: CellRuntime = { worker, pending, ready };
173
- worker.addEventListener("message", (ev: MessageEvent) => {
174
- const d = ev.data as { type?: string } & Partial<WorkerResult>;
175
- if (d.type === "ready") { readyResolve(); return; }
176
- if (typeof d.id !== "number") return;
177
- const cb = pending.get(d.id);
178
- if (cb) {
179
- pending.delete(d.id);
180
- cb({ id: d.id, ok: d.ok === true, stdout: d.stdout ?? "", value: d.value ?? "", error: d.error ?? "" });
181
- }
182
- });
183
- worker.addEventListener("error", (ev) => {
184
- const msg = crashReason((ev as ErrorEvent).message || "unknown worker error");
185
- // Park the reason BEFORE destroying: a background crash (no call in flight)
186
- // otherwise leaves the next call a silently-fresh cell, contradicting the
187
- // "state survives later calls" contract. (preventDefault() does NOT stop Bun
188
- // from tearing the worker down — verified — so report-on-next-call it is.)
189
- crashed.set(sessionId, msg);
190
- destroyCell(sessionId, runtime, `worker crashed: ${msg}`);
191
- });
192
- // Never hold the host process open on account of an idle cell.
193
- (worker as unknown as { unref?: () => void }).unref?.();
194
- return runtime;
195
- }
196
-
197
- /** Terminate a runtime and fail its in-flight runs. Guarded against stale handles:
198
- * only unmaps when this runtime is still the session's current one. */
199
- function destroyCell(sessionId: string, runtime: CellRuntime, reason: string): void {
200
- if (cells.get(sessionId) === runtime) cells.delete(sessionId);
201
- for (const [id, cb] of [...runtime.pending]) {
202
- runtime.pending.delete(id);
203
- cb({ id, ok: false, stdout: "", value: "", error: reason });
204
- }
205
- try { runtime.worker.terminate(); } catch { /* already dead */ }
206
- }
207
-
208
- /** Kill every session's cell worker (test teardown / host shutdown). */
209
- export async function disposeEvalCells(): Promise<void> {
210
- for (const [sid, rt] of [...cells]) destroyCell(sid, rt, "eval cells disposed");
211
- crashed.clear();
212
- if (bootstrapUrl !== null) { URL.revokeObjectURL(bootstrapUrl); bootstrapUrl = null; }
213
- }
214
-
215
- /** Byte-budget truncation (OMP output window, docs/tools/eval.md:185). UTF-8 safe:
216
- * a torn trailing multibyte sequence is dropped, and a marker reports kept/total. */
217
- export function truncateToBudget(text: string, budgetBytes: number): string {
218
- const enc = new TextEncoder();
219
- const bytes = enc.encode(text);
220
- if (bytes.length <= budgetBytes) return text;
221
- const kept = new TextDecoder("utf-8", { fatal: false })
222
- .decode(bytes.slice(0, budgetBytes))
223
- .replace(/�+$/, "");
224
- return `${kept}\n[output truncated: sent ${enc.encode(kept).length} of ${bytes.length} bytes]`;
225
- }
226
-
227
- function clampInt(v: unknown, min: number, max: number, dflt: number): number {
228
- const n = typeof v === "number" && Number.isFinite(v) ? Math.floor(v) : dflt;
229
- return Math.min(max, Math.max(min, n));
230
- }
231
-
232
- async function runCell(
233
- sessionId: string, code: string, timeoutMs: number, budgetBytes: number,
234
- signal: AbortSignal, reset: boolean,
235
- ): Promise<ToolOutput> {
236
- let existing = cells.get(sessionId);
237
- if (reset && existing) { destroyCell(sessionId, existing, "cell reset"); existing = undefined; }
238
- // A spawn that replaces a crashed worker must SAY so: consume the parked reason
239
- // exactly once and prefix this call's output (outside the byte budget, like the
240
- // truncation marker — host metadata is never silently truncated away).
241
- let note = "";
242
- if (!existing) {
243
- const reason = crashed.get(sessionId);
244
- if (reason !== undefined) {
245
- crashed.delete(sessionId);
246
- note = `note: previous cell worker crashed (${reason}); state was reset\n`;
247
- }
248
- }
249
- const cell = existing ?? spawnCell(sessionId);
250
- if (!existing) cells.set(sessionId, cell);
251
-
252
- const id = ++callSeq;
253
- const result = new Promise<WorkerResult>((res) => { cell.pending.set(id, res); });
254
- let timer: ReturnType<typeof setTimeout> | undefined;
255
- const timedOut = new Promise<"timeout">((res) => { timer = setTimeout(() => res("timeout"), timeoutMs); });
256
- let onAbort: (() => void) | undefined;
257
- const aborted = new Promise<"aborted">((res) => {
258
- if (signal.aborted) { res("aborted"); return; }
259
- onAbort = () => res("aborted");
260
- signal.addEventListener("abort", onAbort, { once: true });
261
- });
262
-
263
- try {
264
- const up = await Promise.race([cell.ready.then(() => "ready" as const), timedOut, aborted]);
265
- if (up === "ready") cell.worker.postMessage({ id, code });
266
- const winner = up === "ready" ? await Promise.race([result, timedOut, aborted]) : up;
267
- if (winner === "timeout" || winner === "aborted") {
268
- // Destructive cancellation (OMP docs/tools/eval.md:179): a busy synchronous cell
269
- // can only be stopped by killing its worker; retained state dies with it.
270
- destroyCell(sessionId, cell, winner);
271
- return {
272
- ok: false,
273
- output: note + (winner === "timeout"
274
- ? `Error: eval cell timed out after ${timeoutMs}ms — worker killed; this session's cell state was reset`
275
- : "Error: eval cell aborted — worker killed; this session's cell state was reset"),
276
- };
277
- }
278
- const parts: string[] = [];
279
- if (winner.stdout !== "") parts.push(winner.stdout.replace(/\n$/, ""));
280
- if (winner.ok && winner.value !== "") parts.push(`=> ${winner.value}`);
281
- if (!winner.ok) parts.push(`Error: ${winner.error}`);
282
- const text = parts.length > 0 ? parts.join("\n") : "(no output)";
283
- return { ok: winner.ok, output: note + truncateToBudget(text, budgetBytes) };
284
- } finally {
285
- if (timer !== undefined) clearTimeout(timer);
286
- if (onAbort !== undefined) signal.removeEventListener("abort", onAbort);
287
- cell.pending.delete(id);
288
- }
289
- }
290
-
291
- const evalCellTool: Tool = {
292
- schema: {
293
- name: "eval_cell",
294
- description:
295
- "Execute JavaScript/TypeScript in this session's persistent eval cell (a Bun worker). " +
296
- "State survives across calls: `var`, function declarations, and `globalThis.*` assignments " +
297
- "persist; top-level `let`/`const` are cell-local. Console output is captured and the final " +
298
- "expression's value is returned as `=> value`. Cells using top-level `await` or bare `return` " +
299
- "run wrapped in an async function — persist state via `globalThis` there. No rovecode tool access " +
300
- "from inside the cell (v1 scope). Output is truncated to a byte budget. On timeout — or if a " +
301
- "background error crashes the worker between calls — cell state resets, and the next call " +
302
- "says so in a `note:` prefix. NOT a sandbox: gated by the same execute policy as bash.",
303
- args: {
304
- type: "object",
305
- properties: {
306
- code: { type: "string", description: "JS/TS source of one cell" },
307
- timeout_ms: { type: "integer", description: `kill budget in ms (default ${DEFAULT_TIMEOUT_MS}, max ${MAX_TIMEOUT_MS})` },
308
- max_output_bytes: { type: "integer", description: `output byte budget (default ${DEFAULT_OUTPUT_BYTES}, max ${MAX_OUTPUT_BYTES})` },
309
- reset: { type: "boolean", description: "discard this session's cell state before running (OMP reset semantics)" },
310
- },
311
- required: ["code"],
312
- },
313
- },
314
- kind: "execute", // → action "shell.exec": deny-default rules prompt for it like bash
315
- sequential: true,
316
- async execute(args: unknown, ctx: ToolContext): Promise<ToolOutput> {
317
- const a = (args ?? {}) as { code?: unknown; timeout_ms?: unknown; max_output_bytes?: unknown; reset?: unknown };
318
- if (typeof a.code !== "string" || a.code.trim() === "") {
319
- return { ok: false, output: "Error: eval_cell requires a non-empty string `code` argument" };
320
- }
321
- const timeoutMs = clampInt(a.timeout_ms, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS, DEFAULT_TIMEOUT_MS);
322
- const budget = clampInt(a.max_output_bytes, MIN_OUTPUT_BYTES, MAX_OUTPUT_BYTES, DEFAULT_OUTPUT_BYTES);
323
- try {
324
- return await runCell(ctx.sessionId, a.code, timeoutMs, budget, ctx.signal, a.reset === true);
325
- } catch (e) {
326
- // Never throw across the tool seam (ADR-005): host failures become typed output.
327
- return { ok: false, output: `Error: eval cell host failure: ${e instanceof Error ? e.message : String(e)}` };
328
- }
329
- },
330
- };
331
-
332
- /** Flag-gated factory: the ONLY door to the tool. Returns null unless ROVECODE_EVAL_CELL=1,
333
- * so flag-off runs register nothing (bar: OFF by default and unregistered when off). */
334
- export function createEvalCellTool(
335
- env: Record<string, string | undefined> = process.env,
336
- ): Tool | null {
337
- return env[EVAL_CELL_FLAG] === "1" ? evalCellTool : null;
338
- }
@@ -1,139 +0,0 @@
1
- /** Compact HTML → readable text (PORT #31). Stands in for the html-to-text
2
- * dependency gemini-cli uses (Apache-2.0, 0bd1d43, packages/core/src/tools/
3
- * web-fetch.ts:704-709: links keep their href, images are skipped) and for
4
- * opencode's htmlparser2 skip-depth extractor (MIT, ebece6e, packages/opencode/
5
- * src/tool/webfetch.ts:158-180: script/style/noscript/iframe/object subtrees
6
- * dropped; <embed> is void, so unlike opencode it is not depth-tracked). One
7
- * regex tokenizer pass: raw-text elements are jumped over wholesale, dropped
8
- * subtrees are depth-tracked, block elements become line breaks, list items
9
- * get "- ", links render as `text (href)` resolved against the page URL,
10
- * entities are decoded, whitespace collapses except inside <pre>. Not a spec
11
- * parser (no tree, no adoption agency) but the tokenizer follows the HTML5
12
- * tag and attribute states, so quoted attribute values may contain "<" and
13
- * ">". Every scan is bounded (see tagRx) so a hostile body parses in O(n):
14
- * the tool's timeout cannot interrupt a synchronous parse, so the parse must
15
- * never be the slow part. */
16
-
17
- /** Elements whose CONTENT is raw text up to the matching close tag. <title> is
18
- * RCDATA and never rendered, so a page that omits <head> still loses its title. */
19
- const RAW = new Set(["script", "style", "noscript", "template", "title"]);
20
- /** Elements dropped with their whole (markup) subtree. <head> also ends at the
21
- * first start tag outside HEAD_ONLY: an omitted </head> — even an omitted
22
- * <body> — is legal HTML, common in minified pages. */
23
- const DROP = new Set(["head", "svg", "iframe", "object", "canvas", "audio", "video", "select"]);
24
- /** Start tags the HTML5 "in head" insertion mode keeps inside <head>; any other
25
- * start tag implies </head> (and <body>). RAW members are jumped before the
26
- * check ever runs — listed so the set reads as the spec's. */
27
- const HEAD_ONLY = new Set(["head", "meta", "link", "base", "basefont", "bgsound", "noframes", "title", "style", "script", "noscript", "template"]);
28
- /** Elements that break lines; PARA members separate with a blank line. */
29
- const BLOCK = new Set([
30
- "address", "article", "aside", "blockquote", "body", "caption", "center", "dd", "details", "dialog", "div", "dl", "dt",
31
- "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hr", "html",
32
- "legend", "main", "menu", "nav", "ol", "p", "pre", "section", "summary", "table", "tbody", "tfoot", "thead", "tr", "ul",
33
- ]);
34
- const PARA = new Set(["p", "h1", "h2", "h3", "h4", "h5", "h6", "blockquote", "pre", "ul", "ol", "table", "figure"]);
35
-
36
- const ENTITIES: Record<string, string> = {
37
- amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " ", shy: "", copy: "©", reg: "®", trade: "™",
38
- hellip: "…", mdash: "—", ndash: "–", lsquo: "‘", rsquo: "’", ldquo: "“", rdquo: "”", laquo: "«", raquo: "»",
39
- bull: "•", middot: "·", deg: "°", times: "×", divide: "÷", plusmn: "±", euro: "€", pound: "£", yen: "¥", cent: "¢",
40
- sect: "§", para: "¶", larr: "←", rarr: "→", uarr: "↑", darr: "↓", harr: "↔", frac12: "½", frac14: "¼", frac34: "¾",
41
- sup2: "²", sup3: "³", micro: "µ", iexcl: "¡", iquest: "¿",
42
- };
43
-
44
- /** Named (common subset), decimal and hex character references; unknown ones are kept verbatim. */
45
- export function decodeEntities(s: string): string {
46
- return s.replace(/&(#[xX][0-9a-fA-F]+|#\d+|[a-zA-Z][a-zA-Z0-9]*);/g, (m, body: string) => {
47
- if (body[0] === "#") {
48
- const cp = body[1] === "x" || body[1] === "X" ? parseInt(body.slice(2), 16) : parseInt(body.slice(1), 10);
49
- return cp > 0 && cp <= 0x10ffff && (cp < 0xd800 || cp > 0xdfff) ? String.fromCodePoint(cp) : m;
50
- }
51
- return ENTITIES[body] ?? m;
52
- });
53
- }
54
-
55
- function attr(attrs: string, key: string): string | undefined {
56
- const m = new RegExp(`(?:^|\\s)${key}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'>]+))`, "i").exec(attrs);
57
- return m ? decodeEntities(m[1] ?? m[2] ?? m[3] ?? "").trim() : undefined;
58
- }
59
-
60
- function resolveHref(href: string, baseUrl: string | undefined): string {
61
- try { return new URL(href, baseUrl).href; } catch { return href; }
62
- }
63
-
64
- /** Readable text for an HTML document. `baseUrl` resolves relative link hrefs. */
65
- export function htmlToText(html: string, baseUrl?: string): string {
66
- const out: string[] = [];
67
- let skip = 0; // depth inside DROP subtrees
68
- let pre = 0; // depth inside <pre>
69
- let inHead = false; // between <head> and </head>, explicit or implied
70
- let link: { href: string; start: number } | null = null;
71
- // Linear-time tokenizer (MED-3): every alternative is deterministic, so each
72
- // character is examined once. Comment/CDATA run lazily to their close or EOF
73
- // (unterminated swallows the rest, as browsers do). A tag, once opened, never
74
- // backs out: the name runs to the next blank, "/" or ">" (HTML5 tag-name state —
75
- // `<a<a<a…` is ONE element, as in a browser), the attribute part must START with
76
- // a blank or "/" so the name and attribute quantifiers can never trade characters
77
- // (that nesting made `<aaaa…` quadratic), and inside it a quoted value consumes
78
- // "<" and ">" while an unterminated quote runs to EOF ("eof-in-tag"), so raw-text
79
- // jumps and subtree drops engage on legal markup like <script data-x="<">.
80
- const tagRx = /<!--[\s\S]*?(?:-->|$)|<!\[CDATA\[[\s\S]*?(?:\]\]>|$)|<[!?][^<>]*>|<\/?([a-zA-Z][^\s/>]*)((?:[\s/](?:[^>"']|"[^"]*(?:"|$)|'[^']*(?:'|$))*)?)(?:>|$)/g;
81
- let pos = 0;
82
-
83
- const text = (raw: string): void => {
84
- if (skip > 0 || raw === "") return;
85
- let s = decodeEntities(raw);
86
- if (pre === 0) {
87
- s = s.replace(/\s+/g, " ");
88
- const last = out.length > 0 ? out[out.length - 1]! : "\n";
89
- if (last.endsWith("\n") || last.endsWith("- ")) s = s.trimStart();
90
- }
91
- if (s) out.push(s);
92
- };
93
-
94
- let m: RegExpExecArray | null;
95
- while ((m = tagRx.exec(html)) !== null) {
96
- text(html.slice(pos, m.index));
97
- pos = tagRx.lastIndex;
98
- const name = m[1]?.toLowerCase();
99
- if (!name) continue; // comment, doctype, CDATA, processing instruction
100
- const closing = m[0].startsWith("</");
101
- if (RAW.has(name)) {
102
- if (closing) continue;
103
- const end = html.slice(pos).search(new RegExp(`</${name}\\s*>`, "i"));
104
- pos = end < 0 ? html.length : pos + end; // the close tag itself is tokenized next and ignored above
105
- tagRx.lastIndex = pos;
106
- continue;
107
- }
108
- // Browser "in head" insertion mode (MED-4): the first start tag that is not a
109
- // head-only element — <body>, but also a bare <p> — closes an unclosed <head>.
110
- if (inHead && !closing && !HEAD_ONLY.has(name)) { inHead = false; skip = 0; }
111
- if (name === "head") inHead = !closing;
112
- if (DROP.has(name)) { skip = closing ? Math.max(0, skip - 1) : skip + 1; continue; }
113
- if (skip > 0) continue;
114
- if (name === "a") {
115
- if (!closing) {
116
- // same-page fragments are judged on the RAW href: resolved against a base they never start with "#"
117
- const href = attr(m[2] ?? "", "href") ?? "";
118
- link = { href: href === "" || href.startsWith("#") ? "" : resolveHref(href, baseUrl), start: out.length };
119
- } else if (link) {
120
- const label = out.slice(link.start).join("").trim();
121
- const h = link.href;
122
- if (h && label && label !== h && !/^(javascript|data|mailto|tel):/i.test(h)) out.push(` (${h})`);
123
- link = null;
124
- }
125
- continue;
126
- }
127
- if (name === "br") { out.push("\n"); continue; }
128
- if (name === "li") { if (!closing) out.push("\n- "); continue; }
129
- const last = out.length > 0 ? out[out.length - 1]! : "\n";
130
- if (name === "td" || name === "th") { if (!closing && !last.endsWith("\n")) out.push(" "); continue; }
131
- if (name === "pre") pre = Math.max(0, pre + (closing ? -1 : 1));
132
- if (BLOCK.has(name)) { const sep = PARA.has(name) ? "\n\n" : "\n"; if (!last.endsWith(sep)) out.push(sep); }
133
- }
134
- text(html.slice(pos));
135
- // Trailing blanks before a newline: the lookbehind anchors each run at its
136
- // first blank so a <pre> full of spaces is scanned once (bare `[ \t]+\n`
137
- // re-scanned the run from every blank — quadratic, minutes on 512KB).
138
- return out.join("").replace(/(?<=^|[^ \t])[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
139
- }
@@ -1,149 +0,0 @@
1
- /** provider_list / provider_edit — the agent's window onto the provider registry (providers/registry.ts).
2
- *
3
- * Split like task/task_status (port #26): provider_list is kind "read" (policy action file.read →
4
- * auto-allowed under gated rules and in plan mode; it never mutates and never prompts), provider_edit
5
- * is kind "custom" → action tool.provider_edit, PROMPT under gated rules (cli/runtime.ts buildCfg),
6
- * denied in plan mode by the blanket tool.* rule, allowed under yolo. Children (task tool) get neither.
7
- *
8
- * Secrets: NEITHER tool accepts, returns or echoes an API key. provider_list prints key SOURCES
9
- * (stored / env NAME / none); provider_edit refuses any key-shaped argument (looksLikeSecret) and
10
- * tells the model how the human sets one — `rovecode auth set <id>` (masked prompt), `/provider key`
11
- * in the TUI, or the env var named by keyEnv. A key the model was given would otherwise sit in the
12
- * transcript and in the provider's logs forever.
13
- *
14
- * Effects are live: the registry re-reads its files, so the run that follows an add/use — and the
15
- * TUI, through registry.onChange — sees the new provider without a restart. */
16
-
17
- import type { Tool, ToolOutput } from "../core/types.ts";
18
- import { inferProtocol, isConfigured } from "../providers/provider-config.ts";
19
- import { formatProviderList, type ProviderRegistry } from "../providers/registry.ts";
20
-
21
- const SECRET_FIELD_RE = /^(api[_-]?key|key|secret|token|password|auth(orization)?|bearer)$/i;
22
- /** common key prefixes — a value that starts like this is a secret whatever the field is called */
23
- const SECRET_VALUE_RE = /^(sk-|sk_|key-|xai-|gsk_|AKIA|Bearer\s|ghp_)/;
24
-
25
- /** The argument name that carries something key-shaped, or null. `keyEnv`/`noKey` are legitimate. */
26
- export function looksLikeSecret(args: unknown): string | null {
27
- if (typeof args !== "object" || args === null) return null;
28
- for (const [k, v] of Object.entries(args as Record<string, unknown>)) {
29
- if (k === "keyEnv" || k === "noKey") continue;
30
- if (typeof v !== "string" || v.trim().length === 0) continue;
31
- if (SECRET_FIELD_RE.test(k)) return k;
32
- if (SECRET_VALUE_RE.test(v.trim())) return k;
33
- }
34
- return null;
35
- }
36
-
37
- const refusal = (field: string): string =>
38
- `provider_edit never accepts API keys (argument "${field}" looks like one) — nothing was stored. Keys stay with the human: ask them to run \`rovecode auth set <id>\` (masked prompt) or \`/provider key <id> <key>\` in the TUI, or to set the env var you name in keyEnv. Then retry without the key.`;
39
-
40
- export function providerListTool(reg: ProviderRegistry): Tool {
41
- return {
42
- schema: {
43
- name: "provider_list",
44
- description: "Inspect model providers (never prompts, never mutates, never shows a key). `list` shows the configured providers, the default provider/model and where each key comes from (stored / env NAME / none; `all` adds keyless built-ins); `models` lists the model ids a provider offers (its providers.json entry or its /models endpoint); `test` makes one tiny real call to a provider (optionally a specific model) and reports ok or the error. Use it before switching models, or when a run ends with a `config:` error.",
45
- args: {
46
- type: "object",
47
- properties: {
48
- action: { type: "string", enum: ["list", "models", "test"] },
49
- id: { type: "string", description: "provider id (models / test)" },
50
- model: { type: "string", description: "model id to test (default: the provider's default model)" },
51
- all: { type: "boolean", description: "list: include built-in providers that have no key yet" },
52
- },
53
- required: ["action"],
54
- },
55
- },
56
- kind: "read",
57
- sequential: false,
58
- async execute(args): Promise<ToolOutput> {
59
- const a = (args && typeof args === "object" ? args : {}) as { action?: string; id?: string; model?: string; all?: boolean };
60
- switch (a.action) {
61
- case "list":
62
- return { ok: true, output: formatProviderList(reg, { all: a.all === true }) };
63
- case "models": {
64
- if (!a.id) return { ok: false, output: "models needs `id`" };
65
- const r = await reg.models(a.id);
66
- if (!r.ok) return { ok: false, output: r.error };
67
- return r.models.length > 0
68
- ? { ok: true, output: `${a.id} models (${r.source}, ${r.models.length}):\n${r.models.join("\n")}` }
69
- : { ok: true, output: `${a.id}: the endpoint listed no models (it may not implement /models — try a model id directly with test)` };
70
- }
71
- case "test": {
72
- if (!a.id) return { ok: false, output: "test needs `id`" };
73
- const r = await reg.probe(a.id, a.model);
74
- return { ok: r.ok, output: `${a.id}/${r.model}: ${r.detail}` };
75
- }
76
- default:
77
- return { ok: false, output: "action must be list | models | test" };
78
- }
79
- },
80
- };
81
- }
82
-
83
- export function providerEditTool(reg: ProviderRegistry): Tool {
84
- return {
85
- schema: {
86
- name: "provider_edit",
87
- description: "Add, remove or select model providers; the human approves each call. `add` registers an endpoint {id, baseUrl, protocol? (openai|anthropic — inferred from the URL), keyEnv? (env var holding the key), defaultModel?, noKey? (local servers), scope? (user|project)} in providers.json. `remove` deletes a file-defined provider. `use` sets the default provider/model (`selector` = \"provider/model\" or a provider id) and takes effect immediately: the TUI switches now, the next run uses it, no restart. NEVER pass an API key here — the call is refused and nothing is stored. After `add`, tell the user to run `rovecode auth set <id>` (or `/provider key <id> <key>` in the TUI), or to set the keyEnv variable; the key is picked up live.",
88
- args: {
89
- type: "object",
90
- properties: {
91
- action: { type: "string", enum: ["add", "remove", "use"] },
92
- id: { type: "string" },
93
- baseUrl: { type: "string", description: "http(s) endpoint root, e.g. https://llm.example.com/v1" },
94
- protocol: { type: "string", enum: ["openai", "anthropic"] },
95
- keyEnv: { type: "string", description: "env var that holds the key (default <ID>_API_KEY)" },
96
- defaultModel: { type: "string" },
97
- noKey: { type: "boolean", description: "local server: no key required" },
98
- scope: { type: "string", enum: ["user", "project"], description: "which providers.json: ~/.rovecode (default) or ./.rovecode" },
99
- selector: { type: "string", description: "use: provider/model" },
100
- },
101
- required: ["action"],
102
- },
103
- },
104
- kind: "custom",
105
- sequential: true,
106
- async execute(args): Promise<ToolOutput> {
107
- const leaked = looksLikeSecret(args);
108
- if (leaked !== null) return { ok: false, output: refusal(leaked) };
109
- const a = (args && typeof args === "object" ? args : {}) as {
110
- action?: string; id?: string; baseUrl?: string; protocol?: "openai" | "anthropic"; keyEnv?: string;
111
- defaultModel?: string; noKey?: boolean; scope?: "user" | "project"; selector?: string;
112
- };
113
- const scope = a.scope === "project" ? "project" : "user";
114
- switch (a.action) {
115
- case "add": {
116
- if (!a.id || !a.baseUrl) return { ok: false, output: "add needs `id` and `baseUrl`" };
117
- const r = reg.add({
118
- id: a.id, baseUrl: a.baseUrl, protocol: a.protocol ?? inferProtocol(a.baseUrl),
119
- ...(a.keyEnv !== undefined ? { keyEnv: a.keyEnv } : {}),
120
- ...(a.defaultModel !== undefined ? { defaultModel: a.defaultModel } : {}),
121
- ...(a.noKey === true ? { noKey: true } : {}),
122
- }, scope);
123
- if ("error" in r) return { ok: false, output: r.error };
124
- const key = !isConfigured(r)
125
- ? `key: NOT SET — the user must run \`rovecode auth set ${r.id}\` (or \`/provider key ${r.id} <key>\` in the TUI), or set ${r.keyEnv}; it is picked up immediately, no restart`
126
- : r.keySource === "stored" ? "key: stored credential" : r.keySource === "env" ? `key: env ${r.keyEnv} (present)` : "key: not needed";
127
- return { ok: true, output: `added provider "${r.id}" (${r.protocol}, ${r.baseUrl}) to the ${scope} providers.json\n${key}${r.defaultModel !== undefined ? `\ndefault model: ${r.defaultModel}` : ""}\nselect it with provider_edit use ${r.id}/<model>` };
128
- }
129
- case "remove": {
130
- if (!a.id) return { ok: false, output: "remove needs `id`" };
131
- const r = reg.remove(a.id);
132
- if ("error" in r) return { ok: false, output: r.error };
133
- return { ok: true, output: r.removed.length > 0 ? `removed provider "${a.id}" from the ${r.removed.join(" and ")} providers.json` : `provider "${a.id}" was not in any providers.json` };
134
- }
135
- case "use": {
136
- const sel = a.selector ?? a.id;
137
- if (!sel) return { ok: false, output: "use needs `selector` (provider/model)" };
138
- const r = reg.setDefault(sel, scope);
139
- if ("error" in r) return { ok: false, output: r.error };
140
- const p = reg.get(r.provider);
141
- const note = p !== undefined && !isConfigured(p) ? `\nnote: ${reg.keyHint(p)}` : "";
142
- return { ok: true, output: `default → ${r.provider}/${r.model} (saved to the ${scope} providers.json; the TUI switches now, headless runs use it from the next run)${note}` };
143
- }
144
- default:
145
- return { ok: false, output: "action must be add | remove | use" };
146
- }
147
- },
148
- };
149
- }