rovecode 0.3.2 → 0.4.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (491) hide show
  1. package/CHANGELOG.md +512 -0
  2. package/README.md +33 -45
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-dybnr56b.js +2 -0
  5. package/dist/cli/ask-user-p8hq4xgj.js +2 -0
  6. package/dist/cli/auth-login-ewpgw5sm.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-xv3ypwev.js +9 -0
  9. package/dist/cli/catalog-737wb2s0.js +2 -0
  10. package/dist/cli/cli-arhg40m0.js +2 -0
  11. package/dist/cli/client-cf2pxx8q.js +2 -0
  12. package/dist/cli/commands-3p7e4xxs.js +2 -0
  13. package/dist/cli/connect-3q93d7cb.js +2 -0
  14. package/dist/cli/context-cmd-eqxmxhzq.js +2 -0
  15. package/dist/cli/context-report-hbw9zfes.js +2 -0
  16. package/dist/cli/count-remote-mby98cd0.js +2 -0
  17. package/dist/cli/design-122y0axd.js +2 -0
  18. package/dist/cli/dispatch-b4egzvvh.js +2 -0
  19. package/dist/cli/doctor-x4jkv72e.js +3 -0
  20. package/dist/cli/executor-ftvg6tsy.js +2 -0
  21. package/dist/cli/export-pdgdhkch.js +2 -0
  22. package/dist/cli/files-cez9a96p.js +2 -0
  23. package/dist/cli/gauntlet-r3xxaszc.js +2 -0
  24. package/dist/cli/gauntlet-runner-r515m7kk.js +10 -0
  25. package/dist/cli/gauntlet-wave3-bnkjk2v2.js +5 -0
  26. package/dist/cli/gauntlet-wave4-acs9s60q.js +14 -0
  27. package/dist/cli/hashline-ewg5hbe3.js +2 -0
  28. package/dist/cli/http-n0kehsk8.js +5 -0
  29. package/dist/cli/index-z5qt1s76.js +2 -0
  30. package/dist/cli/install-80mp63kx.js +2 -0
  31. package/dist/cli/loop-12twjcat.js +2 -0
  32. package/dist/cli/main-01pv9206.js +4 -0
  33. package/dist/cli/main-0jys2ccn.js +3 -0
  34. package/dist/cli/main-1ztz6fkj.js +10 -0
  35. package/dist/cli/main-23q7cmww.js +9 -0
  36. package/dist/cli/main-2rzbexn2.js +3 -0
  37. package/dist/cli/main-2wyax8k9.js +9 -0
  38. package/dist/cli/main-2yeveeve.js +6 -0
  39. package/dist/cli/main-2z3dek0b.js +3 -0
  40. package/dist/cli/main-2zgsknth.js +3 -0
  41. package/dist/cli/main-45ejth3a.js +4 -0
  42. package/dist/cli/main-45rn3trk.js +22 -0
  43. package/dist/cli/main-4p4e2w7x.js +4 -0
  44. package/dist/cli/main-4y0tnfpa.js +16 -0
  45. package/dist/cli/main-5py0rkmc.js +4 -0
  46. package/dist/cli/main-6dtqmbt6.js +7 -0
  47. package/dist/cli/main-6h9x282m.js +4 -0
  48. package/dist/cli/main-6vjeds42.js +3 -0
  49. package/dist/cli/main-78gq4bt9.js +6 -0
  50. package/dist/cli/main-7jd5vh3x.js +4 -0
  51. package/dist/cli/main-7kt6r53y.js +4 -0
  52. package/dist/cli/main-8c1tbazx.js +58 -0
  53. package/dist/cli/main-9a9rnh47.js +19 -0
  54. package/dist/cli/main-9ht36z12.js +3 -0
  55. package/dist/cli/main-a2yfvcy9.js +7 -0
  56. package/dist/cli/main-a3f51n0x.js +5 -0
  57. package/dist/cli/main-b8zq261k.js +3 -0
  58. package/dist/cli/main-bxtvnf6d.js +13 -0
  59. package/dist/cli/main-edxc3yzt.js +4 -0
  60. package/dist/cli/main-evgz4mp5.js +21 -0
  61. package/dist/cli/main-f33fc5je.js +9 -0
  62. package/dist/cli/main-fvnpq46y.js +12 -0
  63. package/dist/cli/main-gbbty4d4.js +3 -0
  64. package/dist/cli/main-gth53dnt.js +25 -0
  65. package/dist/cli/main-hqbz10aw.js +9 -0
  66. package/dist/cli/main-hrrvcfan.js +38 -0
  67. package/dist/cli/main-hzwtsb2m.js +5 -0
  68. package/dist/cli/main-j7ttv0sd.js +34 -0
  69. package/dist/cli/main-jak598k9.js +5 -0
  70. package/dist/cli/main-kba6zeyd.js +6 -0
  71. package/dist/cli/main-kwwsz6rq.js +3 -0
  72. package/dist/cli/main-m8vm17zq.js +3 -0
  73. package/dist/cli/main-mg4f96e1.js +3 -0
  74. package/dist/cli/main-mg9b20ac.js +18 -0
  75. package/dist/cli/main-mgb9ccnx.js +3 -0
  76. package/dist/cli/main-mjt2p7aj.js +3 -0
  77. package/dist/cli/main-n6qrdbmy.js +3 -0
  78. package/dist/cli/main-na7wse0x.js +5 -0
  79. package/dist/cli/main-nqveez48.js +4 -0
  80. package/dist/cli/main-ntqef02r.js +10 -0
  81. package/dist/cli/main-nvc3yjay.js +136 -0
  82. package/dist/cli/main-p0cfn6nr.js +16 -0
  83. package/dist/cli/main-qj2djy17.js +19 -0
  84. package/dist/cli/main-qsevpgsv.js +3 -0
  85. package/dist/cli/main-qvarybsp.js +3 -0
  86. package/dist/cli/main-rebtt91r.js +5 -0
  87. package/dist/cli/main-rpg7h8mb.js +3 -0
  88. package/dist/cli/main-rsy72qmw.js +15 -0
  89. package/dist/cli/main-rvetps99.js +18 -0
  90. package/dist/cli/main-s4bb0jav.js +3 -0
  91. package/dist/cli/main-s9v8k74e.js +3 -0
  92. package/dist/cli/main-tjvwmscs.js +3 -0
  93. package/dist/cli/main-tkgarpjj.js +4 -0
  94. package/dist/cli/main-v8y60bb2.js +3 -0
  95. package/dist/cli/main-vhrrq337.js +3 -0
  96. package/dist/cli/main-vp2dfb7s.js +4 -0
  97. package/dist/cli/main-vqbr22sz.js +8 -0
  98. package/dist/cli/main-vxnwe5xx.js +18 -0
  99. package/dist/cli/main-wgph00xf.js +5 -0
  100. package/dist/cli/main-wk2csfnj.js +5 -0
  101. package/dist/cli/main-wm997zjx.js +3 -0
  102. package/dist/cli/main-wpkyraxh.js +3 -0
  103. package/dist/cli/main-wqt32p5x.js +4 -0
  104. package/dist/cli/main-x9ct6y1a.js +3 -0
  105. package/dist/cli/main-xfekqh9m.js +7 -0
  106. package/dist/cli/main-xt9zc3n6.js +7 -0
  107. package/dist/cli/main-xx2z3zh5.js +4 -0
  108. package/dist/cli/main-y5c82rxr.js +3 -0
  109. package/dist/cli/main-yrjt2sqt.js +14 -0
  110. package/dist/cli/main-ys6zj3yr.js +3 -0
  111. package/dist/cli/main-ywbxshqc.js +8 -0
  112. package/dist/cli/main-z13755t8.js +25 -0
  113. package/dist/cli/main-zc7pyrbj.js +4 -0
  114. package/dist/cli/main.js +279 -0
  115. package/dist/cli/market-cmd-bm5xvn9f.js +5 -0
  116. package/dist/cli/mcp-login-bthtfpt7.js +2 -0
  117. package/dist/cli/mcp-market-cmd-mbeshfyd.js +2 -0
  118. package/dist/cli/notify-54v5z9dz.js +2 -0
  119. package/dist/cli/oauth-g5gme95c.js +2 -0
  120. package/dist/cli/output-satndjap.js +16 -0
  121. package/dist/cli/profiles-sfhpbq3m.js +2 -0
  122. package/dist/cli/provider-config-hv3xtdt4.js +2 -0
  123. package/dist/cli/provider-kwzq6g84.js +2 -0
  124. package/dist/cli/registry-fh0hdnyn.js +2 -0
  125. package/dist/cli/registry-y1y8e94r.js +2 -0
  126. package/dist/cli/repl-t4z03mqq.js +11 -0
  127. package/dist/cli/resume-fqt4chg8.js +2 -0
  128. package/dist/cli/run-flags-rysbag9t.js +2 -0
  129. package/dist/cli/runtime-j19fjbsa.js +2 -0
  130. package/dist/cli/sandbox-config-g4qxd7y5.js +2 -0
  131. package/dist/cli/server-r0b6bksk.js +5 -0
  132. package/dist/cli/session-arg-txmn5g4x.js +2 -0
  133. package/dist/cli/session-ed250d9j.js +2 -0
  134. package/dist/cli/sessions-cmd-adw7svfn.js +7 -0
  135. package/dist/cli/settings-y9rzcqx8.js +2 -0
  136. package/dist/cli/setup-jmbr11j0.js +2 -0
  137. package/dist/cli/sextant-smoke-tcth0vea.js +5 -0
  138. package/dist/cli/skills-cmd-zbdy99v6.js +2 -0
  139. package/dist/cli/smoke-1bg937kx.js +8 -0
  140. package/dist/cli/start-chat-p01cdks3.js +12 -0
  141. package/dist/cli/stream-4wmyaypz.js +2 -0
  142. package/dist/cli/task-eg4s093s.js +2 -0
  143. package/dist/cli/tasks-12v9rr9k.js +2 -0
  144. package/dist/cli/thinking-a5ngvqyh.js +2 -0
  145. package/dist/cli/todo-1wxpcecx.js +2 -0
  146. package/dist/cli/tools-2ftsya7w.js +2 -0
  147. package/dist/cli/tools-x1tj4fxm.js +2 -0
  148. package/dist/cli/trust-cmd-hccxehzb.js +2 -0
  149. package/dist/cli/update-check-ygt3vd7m.js +2 -0
  150. package/dist/cli/update-cmd-v23qhr8c.js +2 -0
  151. package/dist/cli/voice-g1gtck92.js +2 -0
  152. package/dist/cli/webfetch-0nnrjgb5.js +2 -0
  153. package/dist/cli/websearch-f0vr2p7d.js +2 -0
  154. package/dist/cli/workspace-9rq1w4ta.js +2 -0
  155. package/dist/lib/index.js +62 -0
  156. package/dist/lib/models-index.json +1 -0
  157. package/dist/lib/plugins.js +6 -0
  158. package/dist/lib/providers.js +17 -0
  159. package/dist/lib/public-api.js +20 -0
  160. package/dist/rovecode.exe +4 -0
  161. package/package.json +38 -11
  162. package/bin/rovecode.ts +0 -21
  163. package/src/acp/server.ts +0 -374
  164. package/src/cli/auth-login.ts +0 -122
  165. package/src/cli/connect.ts +0 -244
  166. package/src/cli/context-cmd.ts +0 -199
  167. package/src/cli/dispatch.ts +0 -82
  168. package/src/cli/doctor.ts +0 -362
  169. package/src/cli/export.ts +0 -276
  170. package/src/cli/help.ts +0 -293
  171. package/src/cli/is-tui-invocation.ts +0 -8
  172. package/src/cli/main.ts +0 -583
  173. package/src/cli/market-cmd.ts +0 -658
  174. package/src/cli/mcp-login.ts +0 -141
  175. package/src/cli/mcp-market-cmd.ts +0 -302
  176. package/src/cli/output.ts +0 -382
  177. package/src/cli/repl.ts +0 -250
  178. package/src/cli/repomap-root.ts +0 -14
  179. package/src/cli/resume.ts +0 -57
  180. package/src/cli/run-flags.ts +0 -43
  181. package/src/cli/run-limits.ts +0 -78
  182. package/src/cli/runtime.ts +0 -931
  183. package/src/cli/session-arg.ts +0 -30
  184. package/src/cli/sessions-cmd.ts +0 -145
  185. package/src/cli/setup.ts +0 -153
  186. package/src/cli/skills-cmd.ts +0 -194
  187. package/src/cli/start-chat.ts +0 -65
  188. package/src/cli/trust-cmd.ts +0 -52
  189. package/src/coding/bash.ts +0 -148
  190. package/src/coding/checkpoints.ts +0 -327
  191. package/src/coding/diff.ts +0 -138
  192. package/src/coding/files.ts +0 -341
  193. package/src/coding/hashline.ts +0 -274
  194. package/src/coding/lsp-gate.ts +0 -254
  195. package/src/coding/lsp-servers.ts +0 -147
  196. package/src/coding/lsp.ts +0 -283
  197. package/src/coding/repomap-cache.ts +0 -99
  198. package/src/coding/repomap-files.ts +0 -192
  199. package/src/coding/repomap.ts +0 -481
  200. package/src/core/agents.ts +0 -255
  201. package/src/core/compaction.ts +0 -259
  202. package/src/core/config.ts +0 -289
  203. package/src/core/context-report.ts +0 -228
  204. package/src/core/context.ts +0 -60
  205. package/src/core/count-remote.ts +0 -107
  206. package/src/core/execpolicy-rules.ts +0 -196
  207. package/src/core/execpolicy.ts +0 -385
  208. package/src/core/executor.ts +0 -454
  209. package/src/core/guardrails.ts +0 -400
  210. package/src/core/hooks.ts +0 -411
  211. package/src/core/images.ts +0 -230
  212. package/src/core/intro.ts +0 -266
  213. package/src/core/loop.ts +0 -567
  214. package/src/core/modes.ts +0 -372
  215. package/src/core/orchestrator.ts +0 -245
  216. package/src/core/proc-group.ts +0 -48
  217. package/src/core/project-trust.ts +0 -98
  218. package/src/core/reflection.ts +0 -165
  219. package/src/core/sandbox-config.ts +0 -186
  220. package/src/core/session-id.ts +0 -24
  221. package/src/core/session-images.ts +0 -73
  222. package/src/core/session-ops.ts +0 -183
  223. package/src/core/session-text.ts +0 -29
  224. package/src/core/session.ts +0 -469
  225. package/src/core/settings.ts +0 -170
  226. package/src/core/tasks.ts +0 -646
  227. package/src/core/token-scale.ts +0 -108
  228. package/src/core/tools.ts +0 -309
  229. package/src/core/trust.ts +0 -104
  230. package/src/core/types.ts +0 -330
  231. package/src/core/update-check.ts +0 -171
  232. package/src/core/usage.ts +0 -204
  233. package/src/core/validate.ts +0 -121
  234. package/src/core/verify-gate.ts +0 -159
  235. package/src/core/verify.ts +0 -236
  236. package/src/core/voice.ts +0 -158
  237. package/src/core/win-job.ts +0 -183
  238. package/src/core/workspace.ts +0 -184
  239. package/src/design/audit.ts +0 -797
  240. package/src/design/direction.ts +0 -190
  241. package/src/design/rules.ts +0 -157
  242. package/src/eval/bench.ts +0 -150
  243. package/src/eval/gauntlet-runner.ts +0 -215
  244. package/src/eval/gauntlet-support.ts +0 -84
  245. package/src/eval/gauntlet-wave3.ts +0 -269
  246. package/src/eval/gauntlet-wave4.ts +0 -217
  247. package/src/eval/gauntlet.ts +0 -253
  248. package/src/index.ts +0 -17
  249. package/src/lanes/agy.ts +0 -95
  250. package/src/lanes/approval.ts +0 -24
  251. package/src/lanes/claude.ts +0 -129
  252. package/src/lanes/codex.ts +0 -127
  253. package/src/lanes/events.ts +0 -130
  254. package/src/lanes/job.ts +0 -142
  255. package/src/lanes/opencode.ts +0 -122
  256. package/src/lanes/process.ts +0 -184
  257. package/src/lanes/progress.ts +0 -183
  258. package/src/lanes/registry.ts +0 -178
  259. package/src/lanes/runner.ts +0 -124
  260. package/src/lanes/types.ts +0 -112
  261. package/src/market/catalogs/mcp-docs.json +0 -111
  262. package/src/market/catalogs/plugins.json +0 -111
  263. package/src/market/catalogs/skills.json +0 -478
  264. package/src/market/clone.ts +0 -72
  265. package/src/market/context-cost.ts +0 -121
  266. package/src/market/digest.ts +0 -106
  267. package/src/market/index.ts +0 -22
  268. package/src/market/install.ts +0 -578
  269. package/src/market/manifest.ts +0 -187
  270. package/src/market/prereq.ts +0 -145
  271. package/src/market/registry.ts +0 -363
  272. package/src/market/resolve.ts +0 -111
  273. package/src/market/types.ts +0 -236
  274. package/src/market/validate.ts +0 -227
  275. package/src/mcp/client.ts +0 -449
  276. package/src/mcp/config.ts +0 -252
  277. package/src/mcp/local-package.ts +0 -211
  278. package/src/mcp/market-catalog.ts +0 -84
  279. package/src/mcp/market-install.ts +0 -289
  280. package/src/mcp/market.ts +0 -362
  281. package/src/mcp/oauth.ts +0 -251
  282. package/src/mcp/prompts-resources.ts +0 -249
  283. package/src/mcp/shared.ts +0 -149
  284. package/src/mcp/status.ts +0 -67
  285. package/src/mcp/tools.ts +0 -275
  286. package/src/mcp/transport.ts +0 -122
  287. package/src/mcp/trust.ts +0 -25
  288. package/src/memory/blocks.ts +0 -278
  289. package/src/memory/recall.ts +0 -355
  290. package/src/memory/scope.ts +0 -182
  291. package/src/memory/store.ts +0 -105
  292. package/src/memory/tools.ts +0 -99
  293. package/src/plugins/cli.ts +0 -119
  294. package/src/plugins/discover.ts +0 -108
  295. package/src/plugins/index.ts +0 -50
  296. package/src/plugins/install.ts +0 -184
  297. package/src/plugins/load.ts +0 -124
  298. package/src/plugins/manifest.ts +0 -92
  299. package/src/plugins/state.ts +0 -83
  300. package/src/providers/auth.ts +0 -408
  301. package/src/providers/cache.ts +0 -223
  302. package/src/providers/catalog-local.ts +0 -160
  303. package/src/providers/catalog.ts +0 -421
  304. package/src/providers/middleware-context.ts +0 -86
  305. package/src/providers/middleware.ts +0 -373
  306. package/src/providers/model-list.ts +0 -23
  307. package/src/providers/oauth/common.ts +0 -105
  308. package/src/providers/oauth/device-code.ts +0 -107
  309. package/src/providers/oauth/github-copilot.ts +0 -146
  310. package/src/providers/oauth/loopback.ts +0 -158
  311. package/src/providers/oauth/openai.ts +0 -163
  312. package/src/providers/oauth/openrouter.ts +0 -89
  313. package/src/providers/oauth/pkce.ts +0 -45
  314. package/src/providers/oauth/registry.ts +0 -39
  315. package/src/providers/oauth/seam.ts +0 -89
  316. package/src/providers/profile-glm53.ts +0 -111
  317. package/src/providers/profile-sonnet5-persona.ts +0 -65
  318. package/src/providers/profile-sonnet5-voice.ts +0 -23
  319. package/src/providers/profiles.ts +0 -156
  320. package/src/providers/provider-config.ts +0 -311
  321. package/src/providers/registry.ts +0 -333
  322. package/src/providers/responses.ts +0 -209
  323. package/src/providers/retry.ts +0 -234
  324. package/src/providers/router.ts +0 -294
  325. package/src/providers/sse.ts +0 -26
  326. package/src/providers/stream-errors.ts +0 -117
  327. package/src/providers/stream.ts +0 -566
  328. package/src/providers/thinking.ts +0 -189
  329. package/src/providers/wire-messages.ts +0 -129
  330. package/src/providers/wire-responses.ts +0 -79
  331. package/src/providers/wire-select.ts +0 -53
  332. package/src/server/http.ts +0 -291
  333. package/src/server/openapi.ts +0 -246
  334. package/src/sextant/card-hits.ts +0 -102
  335. package/src/sextant/card-keys.ts +0 -55
  336. package/src/sextant/context-source.ts +0 -157
  337. package/src/sextant/crew-cards.ts +0 -350
  338. package/src/sextant/draw-agents.ts +0 -273
  339. package/src/sextant/draw-code.ts +0 -388
  340. package/src/sextant/draw-context.ts +0 -222
  341. package/src/sextant/draw-frame.ts +0 -164
  342. package/src/sextant/draw-market.ts +0 -573
  343. package/src/sextant/draw-messages.ts +0 -386
  344. package/src/sextant/draw-pet.ts +0 -230
  345. package/src/sextant/draw-plan.ts +0 -187
  346. package/src/sextant/draw-tabs.ts +0 -85
  347. package/src/sextant/draw-util.ts +0 -65
  348. package/src/sextant/draw-wizard.ts +0 -378
  349. package/src/sextant/engine.ts +0 -230
  350. package/src/sextant/frame-hits.ts +0 -25
  351. package/src/sextant/frame.ts +0 -101
  352. package/src/sextant/git-status.ts +0 -197
  353. package/src/sextant/grid.ts +0 -59
  354. package/src/sextant/input.ts +0 -119
  355. package/src/sextant/keys.ts +0 -521
  356. package/src/sextant/layout.ts +0 -86
  357. package/src/sextant/local-commands.ts +0 -169
  358. package/src/sextant/market-source.ts +0 -287
  359. package/src/sextant/mentions.ts +0 -200
  360. package/src/sextant/message-hits.ts +0 -26
  361. package/src/sextant/model.ts +0 -387
  362. package/src/sextant/overlays.ts +0 -456
  363. package/src/sextant/panel-hits.ts +0 -38
  364. package/src/sextant/pet.ts +0 -399
  365. package/src/sextant/screen.ts +0 -324
  366. package/src/sextant/scroll-hits.ts +0 -66
  367. package/src/sextant/scrollbar.ts +0 -82
  368. package/src/sextant/sextant-bridge.ts +0 -174
  369. package/src/sextant/sextant-cards.ts +0 -142
  370. package/src/sextant/sextant-diff-base.ts +0 -63
  371. package/src/sextant/sextant-files.ts +0 -154
  372. package/src/sextant/sextant-frame-loop.ts +0 -335
  373. package/src/sextant/sextant-renderer.ts +0 -574
  374. package/src/sextant/sextant-repo.ts +0 -140
  375. package/src/sextant/theme.ts +0 -66
  376. package/src/sextant/tool-rows.ts +0 -189
  377. package/src/sextant/types.ts +0 -493
  378. package/src/skills/index.ts +0 -387
  379. package/src/skills/pack.ts +0 -220
  380. package/src/skills/spec.ts +0 -162
  381. package/src/skills/tools.ts +0 -69
  382. package/src/skills/versioned.ts +0 -227
  383. package/src/telemetry/otel-export.ts +0 -122
  384. package/src/telemetry/otel-lanes.ts +0 -89
  385. package/src/telemetry/otel-logs.ts +0 -131
  386. package/src/telemetry/otel-metrics.ts +0 -136
  387. package/src/telemetry/otel.ts +0 -397
  388. package/src/telemetry/otlp.ts +0 -76
  389. package/src/tools/ask-user.ts +0 -156
  390. package/src/tools/bash-bg.ts +0 -94
  391. package/src/tools/bash-jobs.ts +0 -237
  392. package/src/tools/design.ts +0 -151
  393. package/src/tools/evalcell.ts +0 -338
  394. package/src/tools/html-text.ts +0 -139
  395. package/src/tools/provider.ts +0 -149
  396. package/src/tools/task.ts +0 -250
  397. package/src/tools/todo.ts +0 -320
  398. package/src/tools/webfetch.ts +0 -332
  399. package/src/tools/websearch.ts +0 -359
  400. package/src/tui/agents-cmd.ts +0 -41
  401. package/src/tui/app.ts +0 -749
  402. package/src/tui/attach.ts +0 -127
  403. package/src/tui/boot-notes.ts +0 -41
  404. package/src/tui/builtin-prompts.ts +0 -59
  405. package/src/tui/checkpoints-cmd.ts +0 -70
  406. package/src/tui/clipboard-image.ts +0 -81
  407. package/src/tui/clipboard.ts +0 -78
  408. package/src/tui/commands.ts +0 -283
  409. package/src/tui/config-view.ts +0 -53
  410. package/src/tui/context-cmds.ts +0 -282
  411. package/src/tui/cost.ts +0 -108
  412. package/src/tui/crash-guard.ts +0 -173
  413. package/src/tui/focus-terminal.ts +0 -34
  414. package/src/tui/git-cmds.ts +0 -273
  415. package/src/tui/git-plain.ts +0 -58
  416. package/src/tui/info-cmd.ts +0 -150
  417. package/src/tui/input-plain.ts +0 -76
  418. package/src/tui/mcp-cmd.ts +0 -128
  419. package/src/tui/memory-note.ts +0 -77
  420. package/src/tui/modes-cmd.ts +0 -45
  421. package/src/tui/notify-seq.ts +0 -100
  422. package/src/tui/notify.ts +0 -318
  423. package/src/tui/overlays.ts +0 -97
  424. package/src/tui/pi-renderer.ts +0 -428
  425. package/src/tui/providers-cmd.ts +0 -377
  426. package/src/tui/reasoning-view.ts +0 -56
  427. package/src/tui/renderer.ts +0 -128
  428. package/src/tui/replay-marker.ts +0 -29
  429. package/src/tui/session-cmd.ts +0 -148
  430. package/src/tui/session-manage.ts +0 -95
  431. package/src/tui/sextant-attach.ts +0 -102
  432. package/src/tui/sextant-io.ts +0 -202
  433. package/src/tui/sextant-smoke.ts +0 -110
  434. package/src/tui/shell-cmd.ts +0 -158
  435. package/src/tui/smoke.ts +0 -72
  436. package/src/tui/staged-terminal.ts +0 -50
  437. package/src/tui/startup.ts +0 -12
  438. package/src/tui/theme.ts +0 -59
  439. package/src/tui/todo-label.ts +0 -7
  440. package/src/tui/trust-card.ts +0 -107
  441. package/src/tui/tui-commands.ts +0 -87
  442. package/tsconfig.json +0 -30
  443. package/vendor/pi-tui/LICENSE +0 -21
  444. package/vendor/pi-tui/PATCHES.md +0 -12
  445. package/vendor/pi-tui/PROVENANCE.md +0 -12
  446. package/vendor/pi-tui/README.upstream.md +0 -854
  447. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  448. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  449. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  450. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  451. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  452. package/vendor/pi-tui/src/components/box.ts +0 -138
  453. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  454. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  455. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  456. package/vendor/pi-tui/src/components/image.ts +0 -128
  457. package/vendor/pi-tui/src/components/input.ts +0 -448
  458. package/vendor/pi-tui/src/components/loader.ts +0 -93
  459. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  460. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  461. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  462. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  463. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  464. package/vendor/pi-tui/src/components/stack.ts +0 -155
  465. package/vendor/pi-tui/src/components/text.ts +0 -108
  466. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  467. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  468. package/vendor/pi-tui/src/editor-component.ts +0 -75
  469. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  470. package/vendor/pi-tui/src/index.ts +0 -149
  471. package/vendor/pi-tui/src/keybindings.ts +0 -321
  472. package/vendor/pi-tui/src/keys.ts +0 -1402
  473. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  474. package/vendor/pi-tui/src/latex.ts +0 -1381
  475. package/vendor/pi-tui/src/layout-node.ts +0 -52
  476. package/vendor/pi-tui/src/layout.ts +0 -411
  477. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  478. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  479. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  480. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  481. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  482. package/vendor/pi-tui/src/terminal.ts +0 -554
  483. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  484. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  485. package/vendor/pi-tui/src/tui.ts +0 -1264
  486. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  487. package/vendor/pi-tui/src/utils.ts +0 -1327
  488. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  489. package/vendor/pi-tui/test/test-themes.ts +0 -39
  490. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  491. /package/{src/providers → dist/cli}/models-index.json +0 -0
package/src/tui/attach.ts DELETED
@@ -1,127 +0,0 @@
1
- /** Port #34 TUI wiring for image input: `/attach` stages image parts for the next user message,
2
- * user turns echo (and replay) with image chips, and the stage survives a session switch.
3
- *
4
- * The stage is the SessionStore's own (stageAttachments / stagedAttachments): the store folds it
5
- * into the NEXT role:"user" entry that lands in append() — the run's goal message when idle
6
- * (loop.ts userMsg), the queued steer when the loop drains it mid-run (loop.ts steering drain) —
7
- * so the ONE agentLoop (ADR-003) needs no attach change and the TUI keeps no second copy of the
8
- * list. Consequences, documented rather than hidden:
9
- * - a steer queued BEFORE /attach is the next user entry and takes the images instead; if the
10
- * run ends before any steer is drained, the images ride on the next run's goal message and the
11
- * steer text follows it in the same request — nothing is ever dropped;
12
- * - /sessions, /resume and a root /rewind replace the store INSTANCE: switchSession carries the
13
- * stage across with a visible note (carryOverAttachments); same-store /new and /rewind move
14
- * only the leaf, so the stage stays put;
15
- * - no image-only messages: the editor drops empty input (pi-renderer.ts onSubmit), so text is
16
- * required and every attach note says so — no "(see attached image)" text is invented on the
17
- * user's behalf.
18
- * Vision check at attach time (catalog.supportsImages on the current mode's model): false → warn
19
- * (wire-messages.ts will send a text placeholder), undefined → info (unknown model: sent as-is,
20
- * the provider may reject). Paths resolve against the runtime cwd; the loader sniffs magic bytes
21
- * (core/images.ts), never the extension. */
22
-
23
- import { resolve } from "node:path";
24
- import { checkImageCount, describeImage, imageChip, imageFromBytes, loadImageAttachment, MAX_IMAGES_PER_MESSAGE } from "../core/images.ts";
25
- import { clipboardImageName, readClipboardImage } from "./clipboard-image.ts";
26
- import type { SessionStore } from "../core/session.ts";
27
- import type { ImagePart, MessagePart } from "../core/types.ts";
28
- import { supportsImages } from "../providers/catalog.ts";
29
- import type { Renderer, SlashCommand } from "./renderer.ts";
30
-
31
- /** The TUI_COMMANDS entry (/help, palette, custom-command reserved names). */
32
- export const ATTACH_COMMAND: SlashCommand = {
33
- name: "attach",
34
- description: "Attach an image to your next message (text required): /attach <path> · /attach = list · /attach clear · or drag an image file onto the terminal",
35
- };
36
-
37
- export interface AttachCtx {
38
- renderer: Renderer;
39
- /** runtime cwd — relative paths resolve against it */
40
- cwd: string;
41
- /** the ACTIVE store, read live (/sessions and a root /rewind swap it) */
42
- store(): SessionStore;
43
- /** the current mode's model — the vision check */
44
- modelRef(): { provider: string; model: string };
45
- }
46
-
47
- const plural = (n: number): string => `${n} image${n === 1 ? "" : "s"}`;
48
-
49
- /** `/attach <path>` stages one image · `/attach` lists the stage · `/attach clear` empties it.
50
- * Never throws: a bad file, an oversize image or the 9th image is a note, nothing staged. */
51
- export function cmdAttach(ctx: AttachCtx, arg: string): void {
52
- const { renderer } = ctx;
53
- const store = ctx.store();
54
- const staged = store.stagedAttachments;
55
- if (arg === "") {
56
- renderer.addSystemNote(staged.length === 0
57
- ? "no images attached — /attach <path>"
58
- : `attached (${staged.length}/${MAX_IMAGES_PER_MESSAGE}):\n${staged.map((p, i) => `${i + 1}. ${describeImage(p)}`).join("\n")}`);
59
- return;
60
- }
61
- if (arg === "clear") {
62
- store.stageAttachments([]);
63
- renderer.addSystemNote(staged.length === 0 ? "no images attached" : `attachments cleared (${plural(staged.length)} removed)`);
64
- return;
65
- }
66
- const path = arg.replace(/^(["'])(.*)\1$/, "$2"); // a quoted path keeps its spaces
67
- const loaded = loadImageAttachment(resolve(ctx.cwd, path));
68
- if ("error" in loaded) { renderer.addSystemNote(loaded.error, "error"); return; }
69
- const over = checkImageCount(staged.length + 1);
70
- if (over !== undefined) { renderer.addSystemNote(over, "error"); return; }
71
- store.stageAttachments([...staged, loaded]); // replaces the stage; folds into the next user entry
72
- renderer.addSystemNote(`attached ${describeImage(loaded)} (${staged.length + 1}/${MAX_IMAGES_PER_MESSAGE}) — type your message and press Enter to send it`);
73
- const ref = ctx.modelRef();
74
- const vision = supportsImages(ref);
75
- if (vision === false) renderer.addSystemNote(`model ${ref.provider}/${ref.model} has no image input — it will be sent as a text placeholder`, "warn");
76
- else if (vision === undefined) renderer.addSystemNote(`unknown model ${ref.provider}/${ref.model}; image sent as-is (provider may reject)`);
77
- }
78
-
79
- /** `/paste` — the clipboard image as an attachment (⌃v in the sextant surface lands here). */
80
- export const PASTE_COMMAND: SlashCommand = {
81
- name: "paste",
82
- description: "attach the image on the clipboard (⌃v)",
83
- };
84
-
85
- /** Stage the image currently on the system clipboard. Berkay: "gorsel gonderebilme olayini yapalim" —
86
- * /attach <path> existed, but the thing everyone tries first is copying a screenshot and pressing ⌃v,
87
- * and a terminal delivers only TEXT pastes, so that did nothing. tui/clipboard-image.ts asks the OS.
88
- * Same rules as /attach: magic-byte sniff, size cap, the 8-image cap, the vision note; never throws.
89
- * `read` is injectable (tests never touch a real clipboard). */
90
- export function cmdPasteImage(ctx: AttachCtx, read: () => Uint8Array | null = () => readClipboardImage(), name = clipboardImageName()): void {
91
- const { renderer } = ctx;
92
- const bytes = read();
93
- if (bytes === null) { renderer.addSystemNote("no image on the clipboard — copy a screenshot or picture first, or /attach <path>"); return; }
94
- const loaded = imageFromBytes(bytes, { name });
95
- if ("error" in loaded) { renderer.addSystemNote(loaded.error, "error"); return; }
96
- const store = ctx.store();
97
- const staged = store.stagedAttachments;
98
- const over = checkImageCount(staged.length + 1);
99
- if (over !== undefined) { renderer.addSystemNote(over, "error"); return; }
100
- store.stageAttachments([...staged, loaded]);
101
- renderer.addSystemNote(`attached ${describeImage(loaded)} from the clipboard (${staged.length + 1}/${MAX_IMAGES_PER_MESSAGE}) — type your message and press Enter to send it`);
102
- const ref = ctx.modelRef();
103
- const vision = supportsImages(ref);
104
- if (vision === false) renderer.addSystemNote(`model ${ref.provider}/${ref.model} has no image input — it will be sent as a text placeholder`, "warn");
105
- }
106
-
107
- /** Transcript line for a user turn: the text, then one chip per image on a second line; an
108
- * image-only turn is just its chips; "" when there is nothing to show. Used by the submit echo
109
- * (with the stage about to fold) and by replay (with the persisted parts). */
110
- export function userTurnLine(text: string, parts: readonly MessagePart[]): string {
111
- const chips = parts.filter((p): p is ImagePart => p.kind === "image").map(imageChip).join(" ");
112
- return text && chips ? `${text}\n${chips}` : text || chips;
113
- }
114
-
115
- /** Suffix for the busy-submit note: what the queued steer will carry when the loop drains it. */
116
- export function queuedAttachNote(store: SessionStore): string {
117
- const n = store.stagedAttachments.length;
118
- return n === 0 ? "" : ` — ${plural(n)} attached to your queued message`;
119
- }
120
-
121
- /** After a store swap (/sessions, /resume, root /rewind): re-stage the images the OLD instance held
122
- * on the new one and say so — the switch must never lose them silently. */
123
- export function carryOverAttachments(ctx: AttachCtx, pending: readonly ImagePart[]): void {
124
- if (pending.length === 0) return;
125
- ctx.store().stageAttachments(pending);
126
- ctx.renderer.addSystemNote(`${plural(pending.length)} still attached — carried over to this session, rides on your next message`);
127
- }
@@ -1,41 +0,0 @@
1
- /** Boot-note extraction port: everything runTui says before the first prompt, in its original order.
2
- * Adapted from aion's boot-notes.ts, retaining rovecode's voice and runtime channels. Memory migration,
3
- * trust, workspace-root and agent-definition notes already ride plugins.onWarning: do not emit them twice.
4
- * No boot work or update fetch here; only the renderer and the runtime's buffered/live note listeners. */
5
- import type { Runtime } from "../cli/runtime.ts";
6
- import { resumedLine, welcomeCard } from "../core/voice.ts";
7
- import { summarizePlugins } from "../plugins/index.ts";
8
- import type { Renderer } from "./renderer.ts";
9
-
10
- export interface BootNotesCtx {
11
- renderer: Pick<Renderer, "addSystemNote">;
12
- rt: Pick<Runtime, "cwd" | "stream" | "noProviderReason" | "skillStore" | "mcp" | "providers" | "hooks" | "plugins" | "onRouterNote">;
13
- yolo: boolean;
14
- modelRef: { provider: string; model: string };
15
- mode: "plan" | "act";
16
- version: string;
17
- width: number;
18
- /** Undefined on a fresh boot; the active store's id on a resumed boot. */
19
- sessionId: string | undefined;
20
- bootWarn: string | undefined;
21
- commandWarnings: readonly string[];
22
- }
23
-
24
- export function emitBootNotes({ renderer, rt, yolo, modelRef, mode, version, width, sessionId, bootWarn, commandWarnings }: BootNotesCtx): void {
25
- const connected = rt.stream && rt.noProviderReason() === null ? modelRef : null;
26
- if (sessionId !== undefined) renderer.addSystemNote(resumedLine(sessionId, rt.cwd, yolo));
27
- else {
28
- // Count only what this runtime accepted, not untrusted/unfilled MCP entries or inactive plugins.
29
- const loaded = { skills: rt.skillStore.list().length, plugins: rt.plugins.found.filter((p) => p.status === "active").length, mcp: rt.mcp?.serverNames().length ?? 0 };
30
- renderer.addSystemNote(welcomeCard({ connected, cwd: rt.cwd, yolo, mode, version, loaded, width }));
31
- }
32
- if (bootWarn) renderer.addSystemNote(bootWarn); // a fact, not a fault (the original info tone)
33
- for (const w of commandWarnings) renderer.addSystemNote(w, "warn");
34
- for (const w of rt.providers.warnings()) renderer.addSystemNote(`providers: ${w}`, "warn");
35
- rt.hooks.onWarning((w) => renderer.addSystemNote(`hooks: ${w}`, "warn"));
36
- rt.plugins.onWarning((w) => renderer.addSystemNote(w, "warn"));
37
- const pluginLine = summarizePlugins(rt.plugins.found);
38
- if (pluginLine !== null) renderer.addSystemNote(pluginLine);
39
- // Retry notices arrive during backoff; the run's final drain then has nothing left to print.
40
- rt.onRouterNote((n) => renderer.addSystemNote(n, "warn"));
41
- }
@@ -1,59 +0,0 @@
1
- /** Built-in prompt commands (port #53): slash commands whose whole effect is a prompt the ONE agent
2
- * loop runs — today `/init`, which asks the agent to analyse the repo and write (or improve)
3
- * AGENTS.md. They expand exactly where custom commands do: the TUI submits the rendered prompt as a
4
- * plain user turn (context-cmds.ts) and `rovecode run "/init"` renders it headlessly through
5
- * commands.ts expandSlashPrompt, which consults this table BEFORE the custom-command files (a
6
- * built-in beats a same-named custom command, as in the TUI). No renderer, store or loop import
7
- * here — both the TUI and the headless path can depend on this module without a cycle.
8
- *
9
- * Pattern reference only, no code ported: gemini-cli @ 0bd1d43 packages/cli/src/ui/commands/
10
- * initCommand.ts (the command checks whether the context file exists in the target dir and turns
11
- * into a submitted prompt, :33-49) and packages/core/src/commands/init.ts performInit (:9-57 — a
12
- * guided analysis prompt: explore, read the README, pick up to ~10 key files, identify the project
13
- * type, then write the file). Deviation: gemini refuses when its file already exists ("No changes
14
- * were made", :10-17); rovecode asks for targeted improvements instead, and the write itself goes
15
- * through the ordinary edit/write approval seam — the command never touches the file. */
16
-
17
- import { existsSync } from "node:fs";
18
- import { join } from "node:path";
19
-
20
- /** The file the agent writes — the project-context file cli/boot-context.ts harvests (port #8). */
21
- export const INIT_TARGET = "AGENTS.md";
22
-
23
- /** `/init` — the analysis prompt; the variant depends on whether `<cwd>/AGENTS.md` exists. */
24
- export function initPrompt(cwd: string): string {
25
- const exists = existsSync(join(cwd, INIT_TARGET));
26
- const head = exists
27
- ? `${INIT_TARGET} already exists in this project. Analyse the repository, read the current ${INIT_TARGET}, and propose TARGETED improvements to it: fix what is stale or wrong, add what a future agent session would need and cannot infer quickly, remove nothing that is still true. Apply the changes with the edit tool (small anchored edits, never a wholesale rewrite) and finish with a short list of what changed and why.`
28
- : `Analyse this repository and write an ${INIT_TARGET} file at the project root: the instructional context a future agent session reads first.`;
29
- return `${head}
30
-
31
- Analysis:
32
- 1. List the top-level files and directories for an overview. Read the README (README.md or similar) first if there is one.
33
- 2. Read the files that matter most, up to about ten, letting each discovery guide the next: build/package manifests (package.json, pyproject.toml, Cargo.toml, go.mod, Makefile, …), the main entry points, existing agent or contributor guides (AGENTS.md, CLAUDE.md, CONTRIBUTING.md), CI config.
34
- 3. Decide whether this is a code project or something else (documentation, notes, data).
35
-
36
- ${INIT_TARGET} content — concise, factual, only what you verified in the files:
37
- - Project overview: purpose, main technologies, architecture in a few sentences.
38
- - Build, run and test: the exact commands, inferred from the manifests and scripts you read; mark anything you could not confirm with a TODO instead of guessing.
39
- - Conventions: code style, testing practice, layout rules, review or contribution rules the files reveal.
40
- - For a non-code directory: what it holds, the key files and how the contents are meant to be used.
41
-
42
- ${exists ? `Edit ${INIT_TARGET} in place; do not create a second file.` : `Write the complete file with the write tool as well-formatted Markdown; do not touch other files.`} Keep it under about 150 lines.`;
43
- }
44
-
45
- /** Built-in prompt commands by name → their renderer. `arg` is the remainder of the line (unused by
46
- * /init, which takes no arguments — kept in the signature so a later built-in can accept some). */
47
- export const BUILTIN_PROMPTS: Readonly<Record<string, (cwd: string, arg: string) => string>> = {
48
- init: (cwd) => initPrompt(cwd),
49
- };
50
-
51
- /** `"/name args"` → the rendered built-in prompt, or undefined when the line names no built-in
52
- * prompt command (a custom command, another built-in, plain text). Case-insensitive like custom
53
- * command names. */
54
- export function expandBuiltinSlash(prompt: string, cwd: string): string | undefined {
55
- const m = /^\/(\S+)(?:\s+([\s\S]*))?$/.exec(prompt.trim());
56
- if (!m) return undefined;
57
- const render = Object.hasOwn(BUILTIN_PROMPTS, m[1]!.toLowerCase()) ? BUILTIN_PROMPTS[m[1]!.toLowerCase()] : undefined;
58
- return render ? render(cwd, (m[2] ?? "").trim()) : undefined;
59
- }
@@ -1,70 +0,0 @@
1
- /** TUI surface for shadow-git checkpoints (port #11, cline): /checkpoints lists the
2
- * session's snapshots in a pickOne overlay; /restore <ref> [files|conversation|both]
3
- * replays cline's three restore modes. Conversation/both restores branch the session
4
- * tree to the checkpoint's recorded entryId (port #2 leaf machinery) — the CALLER
5
- * owns the store, so branching + replay run through the injected ctx. */
6
-
7
- import type { RestoreMode } from "../coding/checkpoints.ts";
8
- import type { Checkpoints } from "../coding/checkpoints.ts";
9
- import type { Renderer } from "./renderer.ts";
10
-
11
- export interface CheckpointCmdCtx {
12
- renderer: Renderer;
13
- busy(): boolean;
14
- /** active session id (checkpoints are per-session) */
15
- sessionId(): string;
16
- checkpointsFor(sessionId: string): Promise<Checkpoints | null>;
17
- /** branch the ACTIVE session store to entryId; false when the entry is unknown */
18
- branchTo(entryId: string): boolean;
19
- /** re-render transcript + usage after a conversation restore */
20
- replayAndRefresh(): void;
21
- }
22
-
23
- const MODES: readonly RestoreMode[] = ["files", "conversation", "both"];
24
-
25
- /** /checkpoints — list snapshots newest-first in the overlay; picking one prefills nothing
26
- * and just prints the /restore hint (restore is deliberately an explicit second step). */
27
- export async function cmdCheckpoints(ctx: CheckpointCmdCtx): Promise<void> {
28
- if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
29
- const cp = await ctx.checkpointsFor(ctx.sessionId());
30
- if (!cp) { ctx.renderer.addSystemNote("checkpoints unavailable (git missing or ROVECODE_NO_CHECKPOINTS=1)", "warn"); return; }
31
- const log = cp.list();
32
- if (log.length === 0) { ctx.renderer.addSystemNote("no checkpoints yet — snapshots land after each mutating tool call"); return; }
33
- const items = [...log].reverse().slice(0, 20).map((c, i) => ({
34
- value: c.hash,
35
- label: `#${log.length - i} ${c.label} · ${c.hash.slice(0, 8)}`,
36
- description: `${new Date(c.createdAt).toLocaleString()}${c.entryId ? " · conversation anchor" : ""}`,
37
- }));
38
- const picked = await ctx.renderer.pickOne(items, "checkpoints (Enter = show restore hint, Esc = close)");
39
- ctx.replayAndRefresh(); // clear the overlay title note
40
- if (picked) ctx.renderer.addSystemNote(`restore with: /restore ${picked.slice(0, 8)} [files|conversation|both]`);
41
- }
42
-
43
- /** /restore <hash-prefix> [mode] — files (workspace only), conversation (session branch
44
- * only), or both. Cline's three modes, checkpoint-restore semantics. */
45
- export async function cmdRestore(ctx: CheckpointCmdCtx, arg: string): Promise<void> {
46
- if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
47
- const [ref, modeArg] = arg.split(/\s+/);
48
- if (!ref) { ctx.renderer.addSystemNote("usage: /restore <checkpoint> [files|conversation|both] — list with /checkpoints", "warn"); return; }
49
- const mode = (modeArg || "files") as RestoreMode;
50
- if (!MODES.includes(mode)) { ctx.renderer.addSystemNote(`unknown restore mode "${modeArg}" (files|conversation|both)`, "warn"); return; }
51
- const cp = await ctx.checkpointsFor(ctx.sessionId());
52
- if (!cp) { ctx.renderer.addSystemNote("checkpoints unavailable (git missing or ROVECODE_NO_CHECKPOINTS=1)", "warn"); return; }
53
- // dedupe candidates BY HASH (identical content re-snapshotted shares one): counting
54
- // entries made even the full 40-char hash "match 2 checkpoints" forever. Latest entry
55
- // per hash wins, mirroring the module's own pick.
56
- const match = [...new Map(cp.list().filter((c) => c.hash.startsWith(ref)).map((c) => [c.hash, c])).values()];
57
- if (match.length !== 1) {
58
- ctx.renderer.addSystemNote(match.length === 0 ? `no checkpoint matching "${ref}"` : `"${ref}" matches ${match.length} checkpoints — be more specific`, "warn");
59
- return;
60
- }
61
- const res = await cp.restore(match[0]!.hash, mode);
62
- if (!res.ok) { ctx.renderer.addSystemNote(`restore failed: ${res.error}`, "error"); return; }
63
- let convNote = "";
64
- if (mode === "conversation" || mode === "both") {
65
- if (res.entryId && ctx.branchTo(res.entryId)) { ctx.replayAndRefresh(); convNote = " · conversation branched to the checkpoint's turn"; }
66
- else convNote = " · conversation anchor unavailable in this session tree (files unaffected by that)";
67
- }
68
- const fileNote = mode === "conversation" ? "" : "workspace rolled back";
69
- ctx.renderer.addSystemNote(`restored ${res.checkpoint.hash.slice(0, 8)} (${mode}) — ${fileNote}${convNote}; snapshots keep history`);
70
- }
@@ -1,81 +0,0 @@
1
- /** Read an IMAGE from the system clipboard (⌃v / `/paste`).
2
- *
3
- * A terminal only ever hands a program TEXT from the clipboard (bracketed paste). When the clipboard
4
- * holds an image — a screenshot, a copied picture — the terminal sends nothing useful, and users who
5
- * press ⌃v expecting the image to land (every chat app taught them that) get silence. So the surface
6
- * asks the OS itself, through the one tool each platform has for it, and converts to PNG:
7
- * win32 PowerShell + System.Windows.Forms.Clipboard.GetImage() → PNG → base64 on stdout
8
- * darwin osascript `the clipboard as «class PNGf»` → hex («data PNGf…»)
9
- * linux wl-paste -t image/png, else xclip -selection clipboard -t image/png -o
10
- *
11
- * The command runner is injected so tests never touch a real clipboard; every failure (no image on
12
- * the clipboard, tool missing, odd output) is `null`, never a throw — the caller says "no image on the
13
- * clipboard" and moves on. Nothing here writes a file: the bytes go straight to core/images.ts
14
- * imageFromBytes, which sniffs the magic bytes and enforces the size cap like any other attachment. */
15
-
16
- import { spawnSync } from "node:child_process";
17
-
18
- export interface ClipboardRunner {
19
- /** run a command, return stdout decoded as `encoding` (utf8 for text tools, latin1 when the tool
20
- * prints raw image bytes — utf8 decoding would corrupt them), or null when it failed / is missing */
21
- (cmd: string, args: readonly string[], encoding?: "utf8" | "latin1"): string | null;
22
- }
23
-
24
- const TIMEOUT_MS = 5_000;
25
- const MAX_OUT = 64 * 1024 * 1024; // a 5 MiB image is ~7 MiB of base64; leave room, never unbounded
26
-
27
- /** child_process.spawnSync under the contract above: non-zero exit, signal, timeout or ENOENT → null */
28
- export const spawnRunner: ClipboardRunner = (cmd, args, encoding = "utf8") => {
29
- try {
30
- const r = spawnSync(cmd, args, { encoding, timeout: TIMEOUT_MS, maxBuffer: MAX_OUT, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] });
31
- if (r.error || r.status !== 0 || r.signal) return null;
32
- return r.stdout;
33
- } catch { return null; }
34
- };
35
-
36
- /** PowerShell: the image as PNG base64, or nothing when the clipboard holds no image */
37
- const PS_SCRIPT = [
38
- "Add-Type -AssemblyName System.Windows.Forms,System.Drawing",
39
- "$i = [System.Windows.Forms.Clipboard]::GetImage()",
40
- "if ($i -eq $null) { exit 3 }",
41
- "$ms = New-Object System.IO.MemoryStream",
42
- "$i.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)",
43
- "[Console]::Out.Write([Convert]::ToBase64String($ms.ToArray()))",
44
- ].join("; ");
45
-
46
- function fromBase64(s: string | null): Uint8Array | null {
47
- const t = s?.trim() ?? "";
48
- if (t.length < 16 || !/^[A-Za-z0-9+/=\r\n]+$/.test(t)) return null;
49
- try { return new Uint8Array(Buffer.from(t.replace(/\s+/g, ""), "base64")); } catch { return null; }
50
- }
51
-
52
- /** osascript prints `«data PNGf89504E47…»`; take the hex between the marker and the closing » */
53
- function fromAppleScriptHex(s: string | null): Uint8Array | null {
54
- const m = /«data PNGf([0-9A-Fa-f]+)»/.exec(s ?? "");
55
- if (!m || m[1]!.length < 32 || m[1]!.length % 2 !== 0) return null;
56
- return new Uint8Array(Buffer.from(m[1]!, "hex"));
57
- }
58
-
59
- /** The clipboard image as raw bytes (PNG on win32/darwin, whatever the tool yields on linux — the
60
- * magic-byte sniff downstream decides), or null when there is none. `platform` defaults to the process's. */
61
- export function readClipboardImage(run: ClipboardRunner = spawnRunner, platform: NodeJS.Platform = process.platform): Uint8Array | null {
62
- if (platform === "win32") {
63
- return fromBase64(run("powershell", ["-NoProfile", "-NonInteractive", "-STA", "-Command", PS_SCRIPT]));
64
- }
65
- if (platform === "darwin") {
66
- return fromAppleScriptHex(run("osascript", ["-e", "the clipboard as «class PNGf»"]));
67
- }
68
- // linux and the rest: wayland first, then X11; both print the raw PNG, which the runner returns as a
69
- // utf8 string — decode it back to bytes with latin1 so no byte is altered
70
- for (const [cmd, args] of [["wl-paste", ["-t", "image/png"]], ["xclip", ["-selection", "clipboard", "-t", "image/png", "-o"]]] as const) {
71
- const out = run(cmd, args, "latin1");
72
- if (out !== null && out.length > 8) return new Uint8Array(Buffer.from(out, "latin1"));
73
- }
74
- return null;
75
- }
76
-
77
- /** what a pasted image is called in the transcript chip and the sidecar name: clipboard-HHMMSS.png */
78
- export function clipboardImageName(now: Date = new Date()): string {
79
- const p = (n: number): string => String(n).padStart(2, "0");
80
- return `clipboard-${p(now.getHours())}${p(now.getMinutes())}${p(now.getSeconds())}.png`;
81
- }
@@ -1,78 +0,0 @@
1
- /** System clipboard writer for `/copy` (port #53). ONE candidate chain per platform family, tried in
2
- * order until one succeeds; the process spawner is injectable so tests pin the order with a fake and
3
- * the only real-process test is the Windows round-trip (clipboard.test.ts, skipped elsewhere).
4
- * win32 powershell — `Set-Clipboard` fed the text on stdin, decoded as UTF-8 explicitly
5
- * ([Console]::InputEncoding, else the OEM code page garbles non-ASCII; verified: a string
6
- * with accents, an em dash, a check mark and CJK reads back byte-identical via
7
- * `Get-Clipboard -Raw`). clip.exe is NOT in the chain: its stdin decoding is code-page
8
- * dependent and was not proven.
9
- * everything pbcopy (macOS) → wl-copy (Wayland) → xclip -selection clipboard → xsel --clipboard --input
10
- * else — one chain for every non-Windows platform: a tool the host lacks fails to spawn
11
- * (ENOENT) and the chain simply moves on, so macOS stops at pbcopy and Linux skips it
12
- * A missing binary, a non-zero exit and a spawn error all mean "next candidate"; when the chain is
13
- * exhausted the result says which tools were tried. Never throws.
14
- *
15
- * Pattern reference only, no code ported: gemini-cli @ 0bd1d43 packages/cli/src/ui/commands/
16
- * copyCommand.ts (the last model message's text parts joined, "no output" / "no text" notes, :24-68).
17
- * gemini hands the write to the `clipboardy` package behind an OSC-52 attempt
18
- * (ui/utils/commandUtils.ts:256-283); the explicit tool chain, the stdin-fed PowerShell form and the
19
- * injectable spawner are rovecode's. */
20
-
21
- export interface SpawnOutcome { ok: boolean; detail?: string }
22
-
23
- /** Run `argv` with `input` on stdin; resolve ok on exit 0. Rejections are treated as failures. */
24
- export type ClipboardSpawn = (argv: readonly string[], input: string) => Promise<SpawnOutcome>;
25
-
26
- export interface ClipboardOptions {
27
- platform?: NodeJS.Platform;
28
- spawn?: ClipboardSpawn;
29
- }
30
-
31
- export type ClipboardResult =
32
- | { ok: true; tool: string }
33
- | { ok: false; tried: string[]; detail?: string };
34
-
35
- /** Windows: read ALL of stdin as UTF-8 (the default console input encoding is the OEM code page)
36
- * and hand it to Set-Clipboard verbatim — no trailing newline added, no line splitting. */
37
- export const WIN_SET_CLIPBOARD = "[Console]::InputEncoding=[Text.Encoding]::UTF8; $t=[Console]::In.ReadToEnd(); Set-Clipboard -Value $t";
38
-
39
- /** The candidates for a platform, in the order they are tried (header): PowerShell alone on Windows,
40
- * the pbcopy → wl-copy → xclip → xsel chain everywhere else. */
41
- export function clipboardChain(platform: NodeJS.Platform): readonly (readonly string[])[] {
42
- if (platform === "win32") return [["powershell", "-NoProfile", "-NonInteractive", "-Command", WIN_SET_CLIPBOARD]];
43
- return [["pbcopy"], ["wl-copy"], ["xclip", "-selection", "clipboard"], ["xsel", "--clipboard", "--input"]];
44
- }
45
-
46
- /** Default spawner: Bun.spawn with the text piped to stdin. A missing binary throws synchronously
47
- * (ENOENT) — caught here and reported as a failed candidate, like a non-zero exit. */
48
- export const bunClipboardSpawn: ClipboardSpawn = async (argv, input) => {
49
- try {
50
- const proc = Bun.spawn([...argv], { stdin: "pipe", stdout: "ignore", stderr: "pipe" });
51
- proc.stdin.write(input);
52
- await proc.stdin.end();
53
- const code = await proc.exited;
54
- if (code === 0) return { ok: true };
55
- const err = (await new Response(proc.stderr).text()).trim().split("\n")[0] ?? "";
56
- return { ok: false, detail: `exit ${code}${err ? `: ${err.slice(0, 120)}` : ""}` };
57
- } catch (e) {
58
- return { ok: false, detail: e instanceof Error ? e.message : String(e) };
59
- }
60
- };
61
-
62
- /** Copy `text` to the system clipboard through the platform's chain. Empty text is refused up
63
- * front (nothing is spawned): a blank clipboard write is never what /copy meant. */
64
- export async function copyToClipboard(text: string, opts: ClipboardOptions = {}): Promise<ClipboardResult> {
65
- const spawn = opts.spawn ?? bunClipboardSpawn;
66
- const tried: string[] = [];
67
- if (text.length === 0) return { ok: false, tried, detail: "nothing to copy (empty text)" };
68
- let detail: string | undefined;
69
- for (const argv of clipboardChain(opts.platform ?? process.platform)) {
70
- const tool = argv[0]!;
71
- tried.push(tool);
72
- let out: SpawnOutcome;
73
- try { out = await spawn(argv, text); } catch (e) { out = { ok: false, detail: e instanceof Error ? e.message : String(e) }; }
74
- if (out.ok) return { ok: true, tool };
75
- detail = out.detail;
76
- }
77
- return { ok: false, tried, ...(detail !== undefined ? { detail } : {}) };
78
- }