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
package/src/tui/notify.ts DELETED
@@ -1,318 +0,0 @@
1
- /** Notifications for the interactive TUI: ONE decorator over the Renderer seam rings the terminal (BEL / OSC 9 / OSC 777)
2
- * and/or spawns a desktop hook when a run ends or a card needs the user — and ONLY while the terminal is unfocused, because
3
- * the whole value is telling someone who looked away; a bell on every turn is a bell nobody hears. Both surfaces, one
4
- * place: the renderers themselves no longer ring (their `ring()` moved here on 2026-09-07).
5
- *
6
- * Pattern source: openai/codex (Apache-2.0, pattern level; no code copied) — codex-rs/tui/src/tui.rs (the unfocused | always
7
- * gate; terminal_focused starts true; a write error warns once and disables the backend for the session),
8
- * codex-rs/tui/src/chatwidget/notifications.rs (the event set: turn complete / approval requested / elicitation),
9
- * codex-rs/hooks/src/legacy_notify.rs (the `notify` argv hook: payload appended as the LAST argument, stdin/stdout/stderr
10
- * nulled, never awaited; the agent-turn-complete payload shape — the approval / question payloads are rovecode's own).
11
- * Deviations: codex disables focus reporting on Windows — Windows Terminal ≥ 1.14 reports focus through VT input, so the
12
- * tracker is installed on every TTY; codex fires the hook regardless of focus — here the hook obeys the SAME gate, because a
13
- * desktop toast while the person is looking at the terminal is the same noise wearing a different coat.
14
- *
15
- * Knobs (core/settings.ts; env beats file, project beats user, read directly at boot):
16
- * bell (existing) true (default) | false — the on/off switch for terminal notifications
17
- * notify auto (default) | bell | osc9 | osc777 — the method; auto = OSC 9 toast on Ghostty / iTerm2 / kitty /
18
- * Warp / WezTerm, BEL everywhere else. ROVECODE_NOTIFY=off is the env spelling of `bell: false`.
19
- * notify_when unfocused (default) | always ROVECODE_NOTIFY_WHEN
20
- * notify_command argv — a JSON string array or whitespace-split words, NEVER a shell ROVECODE_NOTIFY_COMMAND
21
- *
22
- * notify_command's permission path (Berkay's 2026-09-04 trust decision applied): from the env or the USER file it is the
23
- * person's own configuration; from the PROJECT file it is a repo-supplied command and applies only when that file is
24
- * approved in the digest trust store (mcp/trust.ts — the same store as project mcp.json; any edit re-asks), else it is
25
- * dropped with one note naming the key. The argv then goes through the same classification bash commands get (port #9:
26
- * execpolicy forbidden / dangerous-command → the hook is off, with a note). It is spawned as argv with no shell, every
27
- * stdio nulled, never awaited; the run's text reaches it ONLY as one JSON object in argv[last]. Not through the sandbox
28
- * rung: the hook is a desktop-side program (notify-send, a toast exe) — under docker/wsl the toast would appear inside the
29
- * container. Headless surfaces (`run`, `serve`, `acp`, `--plain`) never construct any of this. */
30
-
31
- import { dangerousCommandMatch, defaultExecPolicy } from "../core/execpolicy.ts";
32
- import { loadSettingsScoped, type ScopedSettings, type Settings } from "../core/settings.ts";
33
- import { FocusTerminal } from "./focus-terminal.ts";
34
- import { FOCUS_OFF, FOCUS_ON, FocusTracker, autoMethod, isArgvError, isTmux, message, parseArgv, sequenceFor, type Env, type NotifyDetail, type NotifyKind, type NotifyMethod } from "./notify-seq.ts";
35
- import type { AssistantView, Renderer } from "./renderer.ts";
36
- import { pickRenderer, type RawStdin, type RawStdout } from "./sextant-io.ts";
37
-
38
- export type NotifyWhen = "unfocused" | "always";
39
- export const NOTIFY_METHODS = ["auto", "bell", "osc9", "osc777"] as const;
40
- export type NotifyMethodSetting = (typeof NOTIFY_METHODS)[number];
41
- export const NOTIFY_WHENS: readonly NotifyWhen[] = ["unfocused", "always"];
42
-
43
- /** everything fire() needs, decided once at boot */
44
- export interface NotifyConfig {
45
- /** the terminal method; undefined = terminal notifications off (`bell: false` / ROVECODE_NOTIFY=off) */
46
- method?: NotifyMethod;
47
- when: NotifyWhen;
48
- /** the hook argv, validated and classified; undefined = no hook */
49
- hook?: string[];
50
- /** where the hook came from, for the notes (`ROVECODE_NOTIFY_COMMAND` or a settings file path) */
51
- hookSource?: string;
52
- /** OSC sequences ride a DCS passthrough inside tmux */
53
- tmux: boolean;
54
- /** one-shot warn notes: what was dropped and why (shown once the surface is live) */
55
- notes: string[];
56
- }
57
-
58
- export interface ResolveDeps {
59
- /** default process.env */
60
- env?: Env;
61
- /** the two settings files, the project layer already gated (default: core/settings.ts loadSettingsScoped(cwd)) */
62
- settings?: ScopedSettings;
63
- }
64
-
65
- const norm = (v: string | undefined): string => (v ?? "").trim().toLowerCase();
66
-
67
- /** the knobs → one config. Never throws; every refusal is a note. */
68
- export function resolveNotifyConfig(cwd: string, d: ResolveDeps = {}): NotifyConfig {
69
- const env = d.env ?? process.env;
70
- const scoped = d.settings ?? loadSettingsScoped(cwd);
71
- const merged: Settings = { ...scoped.user, ...scoped.project };
72
- const notes: string[] = [];
73
-
74
- // the terminal method: ROVECODE_NOTIFY (off | auto | bell | osc9 | osc777) beats the files; `bell: false` is off
75
- let method: NotifyMethodSetting | undefined;
76
- const envMethod = norm(env.ROVECODE_NOTIFY);
77
- if (envMethod === "off") method = undefined;
78
- else if ((NOTIFY_METHODS as readonly string[]).includes(envMethod)) method = envMethod as NotifyMethodSetting;
79
- else {
80
- if (envMethod !== "") notes.push(`notify: unknown value "${envMethod}" in ROVECODE_NOTIFY — off | auto | bell | osc9 | osc777; using the settings files`);
81
- method = merged.bell === false ? undefined : (merged.notify ?? "auto");
82
- }
83
- const resolved: NotifyMethod | undefined = method === "auto" ? autoMethod(env) : method;
84
-
85
- // the gate: ROVECODE_NOTIFY_WHEN beats the files; unfocused unless told otherwise
86
- let when: NotifyWhen = merged.notify_when ?? "unfocused";
87
- const envWhen = norm(env.ROVECODE_NOTIFY_WHEN);
88
- if ((NOTIFY_WHENS as readonly string[]).includes(envWhen)) when = envWhen as NotifyWhen;
89
- else if (envWhen !== "") notes.push(`notify_when: unknown value "${envWhen}" in ROVECODE_NOTIFY_WHEN — unfocused | always; using ${when}`);
90
-
91
- // the hook: env → the project file (trust-gated) → the user file
92
- let raw: string | undefined, source: string | undefined;
93
- const envCmd = env.ROVECODE_NOTIFY_COMMAND;
94
- if (envCmd !== undefined && envCmd.trim() !== "") { raw = envCmd; source = "ROVECODE_NOTIFY_COMMAND"; }
95
- else {
96
- // the project layer arrives GATED (core/settings.ts COMMAND_KEYS): an untrusted file's notify_command is already gone
97
- // and named in `dropped` — the same store and the same yes as hooks.ts, sandbox.json and mcp.json (`rovecode trust`)
98
- if (scoped.project.notify_command !== undefined) { raw = scoped.project.notify_command; source = scoped.projectPath; }
99
- else if (scoped.dropped.includes("notify_command")) notes.push(`notify_command: set by ${scoped.projectPath}, a repository file this machine has not approved — ignored (rovecode trust show · rovecode trust; in the TUI: /trust); set it in ~/.rovecode/settings.json or ROVECODE_NOTIFY_COMMAND to use your own`);
100
- if (raw === undefined && scoped.user.notify_command !== undefined) { raw = scoped.user.notify_command; source = "~/.rovecode/settings.json"; }
101
- }
102
- let hook: string[] | undefined;
103
- if (raw !== undefined) {
104
- const argv = parseArgv(raw);
105
- if (isArgvError(argv)) notes.push(`notify_command (${source}): ${argv.error} — the hook is off`);
106
- else {
107
- const danger = dangerousCommandMatch(argv);
108
- const decision = defaultExecPolicy().check(argv).decision;
109
- if (danger !== null) notes.push(`notify_command (${source}): "${argv.join(" ")}" is a dangerous command (${danger}) — the hook is off`);
110
- else if (decision === "forbidden") notes.push(`notify_command (${source}): execpolicy forbids "${argv.join(" ")}" — the hook is off`);
111
- else hook = argv;
112
- }
113
- }
114
- return { ...(resolved !== undefined ? { method: resolved } : {}), when, ...(hook !== undefined ? { hook, hookSource: source } : {}), tmux: isTmux(env), notes };
115
- }
116
-
117
- /** the last completed assistant text kept for the preview / payload */
118
- const PREVIEW_MAX = 400;
119
-
120
- /** the JSON handed to `notify_command` as its LAST argument (codex legacy-notify shape for the turn; rovecode's own for the cards) */
121
- export type NotifyPayload =
122
- | { type: "agent-turn-complete"; cwd: string; "last-assistant-message": string | null }
123
- | { type: "approval-requested"; cwd: string; tool: string; "args-preview": string }
124
- | { type: "question-requested"; cwd: string; question: string };
125
-
126
- export function payloadFor(kind: NotifyKind, d: NotifyDetail, cwd: string): NotifyPayload {
127
- if (kind === "approval") return { type: "approval-requested", cwd, tool: d.tool ?? "", "args-preview": d.argsPreview ?? "" };
128
- if (kind === "question") return { type: "question-requested", cwd, question: d.question ?? "" };
129
- return { type: "agent-turn-complete", cwd, "last-assistant-message": d.lastText ?? null };
130
- }
131
-
132
- /** the Bun.spawn slice the default spawner needs (tests inject a recorder) */
133
- export interface SpawnLike { (argv: string[], opts: { stdio: ["ignore", "ignore", "ignore"] }): { unref(): void } }
134
- const bunSpawn: SpawnLike = (argv, opts) => Bun.spawn(argv, opts);
135
-
136
- /** the default hook spawner: argv, no shell, every stdio nulled, `unref()` so a hung hook never pins the event loop at
137
- * quit, never awaited */
138
- export function defaultSpawner(spawnFn: SpawnLike = bunSpawn): (argv: string[]) => void {
139
- return (argv) => { spawnFn(argv, { stdio: ["ignore", "ignore", "ignore"] }).unref(); };
140
- }
141
-
142
- export interface NotifierDeps {
143
- config: NotifyConfig;
144
- /** payload cwd (default process.cwd()) */
145
- cwd?: string;
146
- /** terminal sequences go here (default: nowhere — the composition root wires stdout when it is a TTY) */
147
- write?: (s: string) => void;
148
- /** the FocusTracker's flag (default: always focused = watched = silent under `unfocused`) */
149
- focused?: () => boolean;
150
- /** the hook spawner (default defaultSpawner()) */
151
- spawn?: (argv: string[]) => void;
152
- /** the one-shot warn notes (default: dropped) */
153
- note?: (text: string, tone: "warn") => void;
154
- }
155
-
156
- const reason = (e: unknown): string => (e instanceof Error ? e.message : String(e));
157
-
158
- export class Notifier {
159
- readonly config: NotifyConfig;
160
- private readonly cwd: string;
161
- private readonly write: (s: string) => void;
162
- private readonly focused: () => boolean;
163
- private readonly spawn: (argv: string[]) => void;
164
- private readonly note: (text: string, tone: "warn") => void;
165
- private seqOff = false;
166
- private hookOff = false;
167
- private notesShown = false;
168
- private decset = false;
169
-
170
- constructor(d: NotifierDeps) {
171
- this.config = d.config;
172
- this.cwd = d.cwd ?? process.cwd();
173
- this.write = d.write ?? (() => {});
174
- this.focused = d.focused ?? (() => true);
175
- this.spawn = d.spawn ?? defaultSpawner();
176
- this.note = d.note ?? (() => {});
177
- }
178
-
179
- /** can anything fire — a terminal method or a hook */
180
- active(): boolean { return this.config.method !== undefined || this.config.hook !== undefined; }
181
-
182
- /** the config's notes, once, the first time the surface can show them */
183
- private showNotes(): void {
184
- if (this.notesShown) return;
185
- this.notesShown = true;
186
- for (const n of this.config.notes) this.note(n, "warn");
187
- }
188
-
189
- /** DECSET 1004 — written by withNotifications right after the surface's start writes; true when it was written */
190
- focusOn(): boolean {
191
- this.showNotes();
192
- if (!this.active()) return false;
193
- this.decset = true;
194
- this.emit(FOCUS_ON);
195
- return true;
196
- }
197
- /** DECRST 1004 — right before the surface's stop writes; a no-op unless a focusOn() wrote (never an unpaired `?1004l`) */
198
- focusOff(): void {
199
- if (!this.decset) return;
200
- this.decset = false;
201
- this.emit(FOCUS_OFF);
202
- }
203
-
204
- /** one trigger → the sequence and/or the hook, ONLY when `when` is always or the terminal is unfocused. Never throws. */
205
- fire(kind: NotifyKind, d: NotifyDetail): void {
206
- this.showNotes();
207
- if (!(this.config.when === "always" || !this.focused())) return; // the person is watching: nothing to tell them
208
- const { method, hook } = this.config;
209
- if (method !== undefined) this.emit(sequenceFor(method, message(kind, d), this.config.tmux));
210
- if (hook !== undefined && !this.hookOff) this.runHook(hook, payloadFor(kind, d, this.cwd));
211
- }
212
-
213
- private emit(seq: string): void {
214
- if (this.seqOff) return;
215
- try { this.write(seq); } catch (e) {
216
- this.seqOff = true;
217
- this.note(`notify: the terminal write failed (${reason(e)}) — terminal notifications are off for this session`, "warn");
218
- }
219
- }
220
-
221
- private runHook(argv: string[], payload: NotifyPayload): void {
222
- try { this.spawn([...argv, JSON.stringify(payload)]); } catch (e) {
223
- this.hookOff = true;
224
- this.note(`notify_command: could not start ${argv[0]} (${reason(e)}) — the hook is off for this session`, "warn");
225
- }
226
- }
227
- }
228
-
229
- type Overridden = Pick<Renderer, "start" | "stop" | "askApproval" | "askQuestion" | "setBusy" | "beginAssistant">;
230
-
231
- /** The decorator: a Proxy over the inner renderer that adds NO member the inner lacks (`"onEvent" in wrapped` follows the
232
- * inner; `instanceof` follows the inner's prototype) and forwards every other member bound to the inner. Overridden: start
233
- * (DECSET 1004 after the surface's own start writes, when anything can fire) · stop (DECRST 1004 before its stop writes) ·
234
- * askApproval / askQuestion (a trigger each, from ANY caller) · setBusy (run end = a label-less `false` after a `true` —
235
- * never a labelled outcome, never a second `false`) · beginAssistant (keeps the last completed text for the preview / payload). */
236
- export function withNotifications<R extends Renderer>(inner: R, n: Notifier): R {
237
- let busy = false, started = false, decset = false;
238
- let generation = 0;
239
- let lastText: string | undefined;
240
- const over: Overridden = {
241
- start(hooks, options) {
242
- const epoch = generation;
243
- const starting = inner.start(hooks, options);
244
- const activated = () => { if (epoch === generation && !started) { started = true; decset = n.focusOn(); } };
245
- if (starting) return starting.then(activated);
246
- activated();
247
- },
248
- stop() {
249
- generation++; // a prepared renderer resolving after cancellation must not re-enable focus reporting
250
- if (decset) { decset = false; n.focusOff(); }
251
- started = false; // after leave nothing rings: a run's finally racing the user's exit has no terminal to reach
252
- inner.stop();
253
- },
254
- askApproval(tool, argsPreview, detail) {
255
- if (started) n.fire("approval", { tool, argsPreview });
256
- return inner.askApproval(tool, argsPreview, detail);
257
- },
258
- askQuestion(q, signal) {
259
- if (started) n.fire("question", { question: q.question });
260
- return inner.askQuestion(q, signal);
261
- },
262
- setBusy(b, label) {
263
- inner.setBusy(b, label);
264
- if (b) { busy = true; lastText = undefined; return; }
265
- const ended = busy && label === undefined;
266
- busy = false;
267
- if (ended && started) n.fire("run_end", { ...(lastText !== undefined ? { lastText } : {}) }); // a surface that never started has no terminal to hear it
268
- },
269
- beginAssistant(): AssistantView {
270
- const v = inner.beginAssistant();
271
- let buf = "";
272
- return {
273
- append(delta) { v.append(delta); if (buf.length < PREVIEW_MAX) buf = (buf + delta).slice(0, PREVIEW_MAX); },
274
- done() { v.done(); lastText = buf; },
275
- };
276
- },
277
- };
278
- return new Proxy(inner, {
279
- get(target, prop) {
280
- if (typeof prop === "string" && Object.hasOwn(over, prop)) return over[prop as keyof Overridden];
281
- const v = Reflect.get(target, prop, target);
282
- return typeof v === "function" ? (v as (...a: unknown[]) => unknown).bind(target) : v;
283
- },
284
- });
285
- }
286
-
287
- /** main.ts's ONE composition root for the interactive TUI: the surface pickRenderer would have chosen (sextant on a capable
288
- * TTY, else the classic PiTuiRenderer with `cwd` — app.ts parity), its raw-input path carrying a FocusTracker on every TTY
289
- * (classic: FocusTerminal around ProcessTerminal; sextant: the ProcessIO option), wrapped in withNotifications over a
290
- * Notifier that writes to `stdout` only when it is a TTY. */
291
- export function interactiveRenderer(cli: { classic: boolean; pet?: string }, env: Env = process.env, stdout: RawStdout = process.stdout, stdin: RawStdin = process.stdin, cwd: string = process.cwd()): Renderer {
292
- const tty = stdout.isTTY === true;
293
- const tracker = tty ? new FocusTracker() : undefined;
294
- let inner: Renderer | undefined = pickRenderer(cli, env, stdout, { stdin, ...(tracker ? { focus: tracker } : {}) });
295
- if (!inner) {
296
- // The classic surface is optional: do not load its editor/markdown graph into a sextant session.
297
- const { PiTuiRenderer } = require("./pi-renderer.ts") as typeof import("./pi-renderer.ts");
298
- const { ProcessTerminal } = require("../../vendor/pi-tui/src/terminal.ts") as typeof import("../../vendor/pi-tui/src/terminal.ts");
299
- inner = new PiTuiRenderer({ cwd, terminal: tracker ? new FocusTerminal(new ProcessTerminal(), tracker) : new ProcessTerminal() });
300
- }
301
- // EOF on stdin (the pipe or wrapper that launched us went away). The classic surface listens for
302
- // "data" only and the vendored terminal never sees an end, so a piped launch that loses its writer
303
- // hangs forever — measured 60 s+ under a test timeout. The sextant side handles this in ProcessIO
304
- // (sextant-io.ts, same ETX shape); the classic side cannot be reached through its own seams, so
305
- // the fallback here is direct: exit the PROCESS, after restoring the terminal through the crash
306
- // guard's own path. A TUI whose input is gone has nothing left to wait for, and its terminal
307
- // state is the only thing that must not be lost on the way out. Skipped for a TTY — a TTY does not end.
308
- if ((stdin as { isTTY?: boolean }).isTTY !== true) {
309
- stdin.on?.("end", () => { try { process.exit(0); } catch { /* already going */ } });
310
- }
311
- const notifier = new Notifier({
312
- config: resolveNotifyConfig(cwd, { env }), cwd,
313
- write: tty ? (s) => { stdout.write(s); } : () => {},
314
- focused: () => tracker?.focused ?? true,
315
- note: (text, tone) => inner!.addSystemNote(text, tone),
316
- });
317
- return withNotifications(inner, notifier);
318
- }
@@ -1,97 +0,0 @@
1
- /** Overlay bodies for PiTuiRenderer: the port #24 approval diff card and the port #33 question
2
- * card. Each is a pi-tui Component that routes keys to the SelectList (or Input) it wraps, so
3
- * the renderer's overlay lifecycle (show → settle → hide → refocus editor) is shared and the
4
- * wrapped list's bindings are untouched. Only pi-renderer.ts, this module and theme.ts may
5
- * import from vendor/pi-tui. */
6
-
7
- import {
8
- type Component,
9
- Input,
10
- type SelectList,
11
- truncateToWidth,
12
- visibleWidth,
13
- wrapTextWithAnsi,
14
- } from "../../vendor/pi-tui/src/index.ts";
15
- import { pal, st } from "./theme.ts";
16
-
17
- /** One overlay row: leading space, clipped to width-2, padded so the right gutter stays clean. */
18
- export function fitLine(s: string, width: number): string {
19
- const t = truncateToWidth(s, width - 2, "…");
20
- return ` ${t}${" ".repeat(Math.max(0, width - 1 - visibleWidth(t)))}`;
21
- }
22
-
23
- /** Port #24: body of an edit/write approval overlay — title, the bounded unified diff
24
- * (+ green, - red, headers/@@ dim), a spacer, then the verdict list. Keys go straight
25
- * to the list, so verdicts and bindings are identical to the plain approval overlay. */
26
- const MORE_RE = /^… \+(\d+) more line/;
27
- export class ApprovalCard implements Component {
28
- constructor(
29
- private readonly title: string,
30
- private readonly diff: string[],
31
- private readonly list: SelectList,
32
- private readonly rows: () => number,
33
- ) {}
34
- handleInput(data: string): void { this.list.handleInput(data); }
35
- invalidate(): void { this.list.invalidate(); }
36
- render(width: number): string[] {
37
- // physical bound: title, list and some transcript must stay visible. previewDiff already
38
- // clipped logically — fold its marker's count into ours rather than stacking two markers.
39
- const max = Math.max(4, this.rows() - 12);
40
- let lines = this.diff;
41
- if (lines.length > max) {
42
- const tail = MORE_RE.exec(lines[lines.length - 1]!);
43
- const hidden = lines.length - max + (tail ? Number(tail[1]) - 1 : 0);
44
- lines = [...lines.slice(0, max), `… +${hidden} more line${hidden === 1 ? "" : "s"}`];
45
- }
46
- return [fitLine(pal.warn(this.title), width), ...lines.map((l, i) => fitLine(paintDiff(l, i), width)), " ".repeat(width), ...this.list.render(width)];
47
- }
48
- }
49
-
50
- function paintDiff(line: string, idx: number): string {
51
- if ((idx === 0 && line.startsWith("--- ")) || (idx === 1 && line.startsWith("+++ "))) return st.dim(line);
52
- const c = line[0];
53
- return c === "+" ? pal.ok(line) : c === "-" ? pal.err(line) : c === " " ? line : st.dim(line);
54
- }
55
-
56
- /** SelectList value of the "type an answer…" entry — can never collide with an option index. */
57
- export const FREE_TEXT = "\u0000free-text";
58
-
59
- /** SelectList value of the "skip this question" entry: the NON-destructive decline (resolves null →
60
- * the tool reports "user declined to answer"), so a busy run — where Escape means "stop the run" —
61
- * can still be left unanswered without killing it (port #33 critic LOW). Same escape idiom as
62
- * FREE_TEXT: an option index can never look like this. */
63
- export const SKIP_QUESTION = "\u0000skip-question";
64
-
65
- /** Port #33: body of a question overlay — title, the wrapped question (bounded by the terminal),
66
- * a spacer, then either the option list (options + the free-text entry + skip) or a one-line
67
- * Input for a typed answer, each with a key hint. Keys route to whichever is active; the renderer
68
- * wires the list/input callbacks (select, submit, escape) and flips `typing`. */
69
- export class QuestionCard implements Component {
70
- private typing: boolean;
71
- readonly input = new Input();
72
- constructor(
73
- private readonly question: string,
74
- private readonly list: SelectList,
75
- private readonly optionCount: number,
76
- private readonly freeText: boolean,
77
- private readonly rows: () => number,
78
- /** true while a run is in flight — decides what Escape means in the hint */
79
- private readonly busy: () => boolean,
80
- ) { this.typing = optionCount === 0; } // no options: straight to the input
81
- get isTyping(): boolean { return this.typing; }
82
- setTyping(on: boolean): void { this.typing = on; }
83
- handleInput(data: string): void { if (this.typing) this.input.handleInput(data); else this.list.handleInput(data); }
84
- invalidate(): void { this.list.invalidate(); this.input.invalidate(); }
85
- render(width: number): string[] {
86
- const bodyRows = this.typing ? 1 : this.optionCount + (this.freeText ? 1 : 0) + 1; // + the skip entry
87
- // physical bound: title, body, hint and some transcript must stay visible
88
- const max = Math.max(2, this.rows() - 9 - bodyRows);
89
- let lines = wrapTextWithAnsi(this.question, width - 2);
90
- if (lines.length > max) lines = [...lines.slice(0, max - 1), st.dim(`… +${lines.length - max + 1} more lines`)];
91
- const esc = this.busy() ? "Esc stop the run" : "Esc skip";
92
- const body = this.typing
93
- ? [fitLine(this.input.render(width - 2)[0] ?? "", width), fitLine(st.dim(this.optionCount > 0 ? "Enter sends · Esc back to the options" : `Enter sends · ${esc}`), width)]
94
- : [...this.list.render(width), fitLine(st.dim(`↑↓ choose · Enter answer · ${esc}`), width)];
95
- return [fitLine(pal.warn("question"), width), ...lines.map((l) => fitLine(l, width)), " ".repeat(width), ...body];
96
- }
97
- }