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/core/usage.ts DELETED
@@ -1,204 +0,0 @@
1
- /** Token & cost accounting: o200k token counting, provider usage normalization, USD costing,
2
- * and context-window health.
3
- *
4
- * Normalization convention (the part that makes cost math coherent across providers):
5
- * `input` = tokens billed at the BASE input rate — i.e. excluding cache reads and cache writes.
6
- * - Anthropic `/messages` usage already follows this convention: `input_tokens` excludes both
7
- * `cache_read_input_tokens` (billed ~0.1x input) and `cache_creation_input_tokens` (~1.25x).
8
- * - OpenAI `/chat/completions` does NOT: `prompt_tokens` INCLUDES
9
- * `prompt_tokens_details.cached_tokens`, so we subtract the cached share (clamped at 0) or the
10
- * cached tokens would be double-billed (once at the input rate, once at the cache-read rate).
11
- * The cached-inclusive convention is detected by the PRESENCE of `prompt_tokens`, or of a
12
- * *_details cached count when no Anthropic `cache_read_input_tokens` coexists — NOT by the
13
- * absence of `input_tokens` (gateways like OpenRouter emit BOTH spellings in one payload, and
14
- * keying on absence would skip the subtraction there and double-bill the cached share), and
15
- * NOT by a bare *_details block (a payload that also carries `cache_read_input_tokens` has a
16
- * cache-EXCLUSIVE base; subtracting again would double-subtract and clamp input to 0).
17
- *
18
- * tokenlens (v1.3.1) is used where it fits: `breakdownTokens` from tokenlens/helpers already
19
- * recognizes both providers' field spellings (prompt_tokens/completion_tokens/
20
- * prompt_tokens_details.cached_tokens as well as input_tokens/output_tokens/
21
- * cache_read_input_tokens/cache_creation_input_tokens) and tolerates junk input. What it does
22
- * NOT do is reconcile the OpenAI inclusive-input asymmetry above — that part is hand-mapped here.
23
- */
24
-
25
- import type { countTokens as CountTokensFn } from "gpt-tokenizer/encoding/o200k_base";
26
- import { breakdownTokens } from "tokenlens/helpers";
27
-
28
- // lazy loader — the o200k rank table is deferred until the first countTokens() call that needs it.
29
- // Measured (scripts/probe-import.ts, 2026-09-06): loading it takes 385–520 ms and adds ~136 MB of
30
- // resident memory, and 3.8 MB of the 8 MB CLI bundle is this table. So nothing on a session's boot
31
- // path may call countTokens(): the sextant usage panel goes through countTokensIfLoaded() and the
32
- // chars-based estimator instead (tui/cost.ts), and the table loads when a person asks for the exact
33
- // figure — /cost, /context, `rovecode context`.
34
- type GptTokenizerMod = { countTokens: typeof CountTokensFn };
35
- let _gptMod: GptTokenizerMod | null = null;
36
- function lazyTokenizer(): GptTokenizerMod {
37
- if (_gptMod === null) {
38
- // eslint-disable-next-line @typescript-eslint/no-require-imports
39
- _gptMod = require("gpt-tokenizer/encoding/o200k_base") as GptTokenizerMod;
40
- }
41
- return _gptMod;
42
- }
43
- /** the o200k table is resident (some caller already paid for it) */
44
- export function tokenizerLoaded(): boolean { return _gptMod !== null; }
45
-
46
- // ---------- pricing ----------
47
-
48
- export interface PricingRow {
49
- inputPerMTok?: number;
50
- outputPerMTok?: number;
51
- cacheReadPerMTok?: number;
52
- cacheWritePerMTok?: number;
53
- }
54
-
55
- export interface NormalizedUsage {
56
- /** tokens billed at the base input rate (cache reads/writes excluded) */
57
- input: number;
58
- output: number;
59
- cacheRead: number;
60
- cacheWrite: number;
61
- }
62
-
63
- // ---------- token counting ----------
64
-
65
- /** Synchronous token count using gpt-tokenizer's o200k_base encoding.
66
- * An ESTIMATE for non-OpenAI models (Anthropic's tokenizer is not public); good enough for
67
- * context-budget arithmetic, not for billing reconciliation — use provider usage for that. */
68
- export function countTokens(text: string): number {
69
- if (text.length === 0) return 0; // a fresh session's empty transcript must not load a 136 MB table to learn it is empty
70
- return lazyTokenizer().countTokens(text);
71
- }
72
-
73
- /** The exact o200k count when the table is already resident, else null — never loads it. For callers
74
- * that run on a session's boot path or on every repaint and have a cheaper estimator to fall back on. */
75
- export function countTokensIfLoaded(text: string): number | null {
76
- if (text.length === 0) return 0;
77
- return _gptMod === null ? null : _gptMod.countTokens(text);
78
- }
79
-
80
- // ---------- usage normalization ----------
81
-
82
- /** Non-negative finite number, else 0. Keeps NaN/negatives out of cost arithmetic. */
83
- function nz(v: unknown): number {
84
- return typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
85
- }
86
-
87
- function isRec(v: unknown): v is Record<string, unknown> {
88
- return typeof v === "object" && v !== null && !Array.isArray(v);
89
- }
90
-
91
- /** cached_tokens read straight from prompt_tokens_details/input_tokens_details — tokenlens
92
- * recognizes the former but not the Responses-API latter, so this is the fallback source. */
93
- function detailsCachedTokens(raw: unknown): number {
94
- if (!isRec(raw)) return 0;
95
- for (const k of ["prompt_tokens_details", "input_tokens_details"]) {
96
- const d = raw[k];
97
- if (isRec(d)) return nz(d["cached_tokens"]);
98
- }
99
- return 0;
100
- }
101
-
102
- /** Normalize a raw provider usage payload (OpenAI or Anthropic wire shape) to a single
103
- * cost-coherent structure. Unrecognized/malformed input normalizes to all zeros. */
104
- export function normalizeUsage(raw: unknown): NormalizedUsage {
105
- const b = breakdownTokens(raw as Parameters<typeof breakdownTokens>[0]);
106
- const cacheRead = nz(b.cacheReads) || detailsCachedTokens(raw);
107
- const cacheWrite = nz(b.cacheWrites);
108
- let input = nz(b.input);
109
- // OpenAI-style cache-INCLUSIVE base, i.e. the reported input still contains the cached share
110
- // and it must be subtracted (clamped) so `input` means "billed at the base rate". Detected by
111
- // PRESENCE of prompt_tokens — never by absence of input_tokens, which OpenRouter emits
112
- // alongside prompt_tokens — or by a *_details cached count with NO cache_read_input_tokens
113
- // beside it: that Anthropic spelling marks the base as already cache-EXCLUSIVE, so a payload
114
- // carrying both (gateway mirroring the cached share into a details block) must not be
115
- // subtracted a second time — that would clamp input to 0 and under-report /cost.
116
- const cachedInclusive = isRec(raw) && (
117
- typeof raw["prompt_tokens"] === "number"
118
- || (detailsCachedTokens(raw) > 0 && raw["cache_read_input_tokens"] === undefined)
119
- );
120
- if (cachedInclusive) input = Math.max(0, input - cacheRead);
121
- return { input, output: nz(b.output), cacheRead, cacheWrite };
122
- }
123
-
124
- // ---------- cost ----------
125
-
126
- /** USD cost of a normalized usage under a pricing row (rates are $ per 1M tokens).
127
- * Returns undefined when a rate needed for a NONZERO component is missing — an honest "unknown"
128
- * beats silently under-billing (e.g. pricing cache reads at 0) or over-billing (at the full
129
- * input rate). Zero components never require a rate; an all-zero usage costs 0. */
130
- /** A prompt-size-dependent rate table, structurally what providers/catalog.ts `ratesFor()` returns.
131
- * Declared here rather than imported so this module stays free of the catalog (and of its snapshot):
132
- * a caller that knows the model builds the breakdown, this one only multiplies. */
133
- export interface TieredRates {
134
- /** prompt tokens billed at `base` */
135
- promptBase: number;
136
- /** prompt tokens billed at `above` */
137
- promptAbove: number;
138
- base: PricingRow;
139
- above?: PricingRow;
140
- /** the rates for everything that is not the prompt on this request — both vendors that tier also
141
- * select the OUTPUT price by prompt size */
142
- request: PricingRow;
143
- }
144
-
145
- /** USD for one turn under a tiered rate table. The prompt's three components (base input, cache reads,
146
- * cache writes) are split in the same proportion as `promptBase`/`promptAbove`, which is exact for the
147
- * two shapes that exist today — flat (everything base) and per-request (everything above) — and a
148
- * documented approximation for a marginal tier, where no shipping provider states how a partly cached
149
- * prompt divides across the threshold. Same honesty rule as costUsd: a missing rate for a nonzero
150
- * component returns undefined rather than a wrong number. */
151
- export function costUsdTiered(u: NormalizedUsage, r: TieredRates): number | undefined {
152
- const promptTotal = r.promptBase + r.promptAbove;
153
- const aboveShare = promptTotal > 0 ? r.promptAbove / promptTotal : 0;
154
- const above = r.above ?? r.base;
155
- const split = (count: number): readonly (readonly [number, PricingRow])[] =>
156
- aboveShare <= 0 ? [[count, r.base]]
157
- : aboveShare >= 1 ? [[count, above]]
158
- : [[count * (1 - aboveShare), r.base], [count * aboveShare, above]];
159
-
160
- let total = 0;
161
- for (const [count, row] of [
162
- ...split(u.input).map(([c, p]) => [c, p.inputPerMTok] as const),
163
- ...split(u.cacheRead).map(([c, p]) => [c, p.cacheReadPerMTok] as const),
164
- ...split(u.cacheWrite).map(([c, p]) => [c, p.cacheWritePerMTok] as const),
165
- [u.output, r.request.outputPerMTok] as const,
166
- ]) {
167
- const c = nz(count);
168
- if (c === 0) continue;
169
- if (typeof row !== "number" || !Number.isFinite(row)) return undefined;
170
- total += (c / 1_000_000) * row;
171
- }
172
- return total;
173
- }
174
-
175
- export function costUsd(u: NormalizedUsage, p: PricingRow): number | undefined {
176
- const parts: readonly (readonly [number, number | undefined])[] = [
177
- [u.input, p.inputPerMTok],
178
- [u.output, p.outputPerMTok],
179
- [u.cacheRead, p.cacheReadPerMTok],
180
- [u.cacheWrite, p.cacheWritePerMTok],
181
- ];
182
- let total = 0;
183
- for (const [count, rate] of parts) {
184
- const c = nz(count);
185
- if (c === 0) continue;
186
- if (typeof rate !== "number" || !Number.isFinite(rate)) return undefined;
187
- total += (c / 1_000_000) * rate;
188
- }
189
- return total;
190
- }
191
-
192
- // ---------- context health ----------
193
-
194
- export const NEAR_LIMIT_FRACTION = 0.8;
195
-
196
- /** Fraction of the context window consumed. `nearLimit` trips at ≥ 0.8 — the compaction signal.
197
- * The fraction is deliberately NOT clamped above 1 (callers may want the overflow magnitude);
198
- * negative/NaN usedTokens counts as 0. A degenerate window (≤ 0 or non-finite) reports full
199
- * (fraction 1, nearLimit true): compacting on broken config beats silently overflowing. */
200
- export function contextHealth(usedTokens: number, contextWindow: number): { fraction: number; nearLimit: boolean } {
201
- if (!Number.isFinite(contextWindow) || contextWindow <= 0) return { fraction: 1, nearLimit: true };
202
- const fraction = nz(usedTokens) / contextWindow;
203
- return { fraction, nearLimit: fraction >= NEAR_LIMIT_FRACTION };
204
- }
@@ -1,121 +0,0 @@
1
- /** Tool argument validation — the "validate" that ADR-005 names first in
2
- * `validate → revise → policy → approve → sandbox → execute` and that nothing actually did.
3
- *
4
- * Until this file existed, `call.args` went from the model straight into `execute`, where every tool
5
- * casts it: `const a = args as { path: string; content: string }`. A cast is not a check. A model
6
- * that sent `content` as an object got Node's own message back —
7
- *
8
- * Error: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView
9
- *
10
- * — which names no tool, no property, and no fix, so the model's next attempt is a guess. Worse are
11
- * the cases that do not throw: a number where a string belongs stringifies somewhere downstream and
12
- * the wrong thing happens quietly.
13
- *
14
- * This validates against the schema the tool already publishes (ToolSchema.args, the same object the
15
- * provider is told about), so there is nothing new to maintain: a tool that documents its arguments
16
- * is validated by that documentation. The message names the tool, the property, what was expected
17
- * and what arrived — everything a model needs to fix the call on the next turn without a human.
18
- *
19
- * Deliberately a SUBSET of JSON Schema — type, required, enum, array item type, nested objects —
20
- * because that is what the tool schemas in this repo use. An unknown keyword is ignored rather than
21
- * rejected: a schema this validator does not fully understand must never make a working tool
22
- * unusable. Unknown PROPERTIES are likewise allowed through: policy already re-aims resources from
23
- * declared keys only (tools.ts describeResource), and a strict-mode rejection here would break every
24
- * provider that decorates calls with its own metadata. */
25
-
26
- export interface ValidationIssue {
27
- /** dotted path from the argument root: "todos.3.status", "" for the root itself */
28
- path: string;
29
- message: string;
30
- }
31
-
32
- interface Schema {
33
- type?: unknown;
34
- properties?: unknown;
35
- required?: unknown;
36
- enum?: unknown;
37
- items?: unknown;
38
- }
39
-
40
- const isRec = (v: unknown): v is Record<string, unknown> => typeof v === "object" && v !== null && !Array.isArray(v);
41
-
42
- /** what a value IS, in the words the schema uses — so "expected string, got array" reads plainly */
43
- export function jsonTypeOf(v: unknown): string {
44
- if (v === null) return "null";
45
- if (Array.isArray(v)) return "array";
46
- const t = typeof v;
47
- if (t === "number") return Number.isInteger(v) ? "integer" : "number";
48
- return t === "object" || t === "boolean" || t === "string" ? t : t; // function/symbol/undefined pass through as themselves
49
- }
50
-
51
- /** JSON Schema's `type` accepts a string or a list of them */
52
- function typeMatches(want: unknown, v: unknown): boolean {
53
- if (Array.isArray(want)) return want.some((w) => typeMatches(w, v));
54
- if (typeof want !== "string") return true; // no usable type keyword: nothing to check
55
- const actual = jsonTypeOf(v);
56
- if (want === "number") return actual === "number" || actual === "integer";
57
- if (want === "integer") return actual === "integer";
58
- if (want === "object") return isRec(v);
59
- return actual === want;
60
- }
61
-
62
- function join(base: string, key: string | number): string {
63
- return base === "" ? String(key) : `${base}.${key}`;
64
- }
65
-
66
- function check(schema: unknown, value: unknown, path: string, out: ValidationIssue[]): void {
67
- if (!isRec(schema)) return;
68
- const s = schema as Schema;
69
-
70
- if (s.type !== undefined && !typeMatches(s.type, value)) {
71
- const want = Array.isArray(s.type) ? s.type.join(" or ") : String(s.type);
72
- out.push({ path, message: `expected ${want}, got ${jsonTypeOf(value)}` });
73
- return; // one complaint per value: the nested checks below would only repeat it
74
- }
75
-
76
- if (Array.isArray(s.enum) && s.enum.length > 0 && !s.enum.includes(value as never)) {
77
- out.push({ path, message: `expected one of ${s.enum.map((e) => JSON.stringify(e)).join(" | ")}, got ${JSON.stringify(value)}` });
78
- return;
79
- }
80
-
81
- if (Array.isArray(value) && s.items !== undefined) {
82
- value.forEach((item, i) => check(s.items, item, join(path, i), out));
83
- return;
84
- }
85
-
86
- if (isRec(value)) {
87
- if (Array.isArray(s.required)) {
88
- for (const key of s.required) {
89
- // present-but-undefined is missing: a provider that serializes an omitted argument as
90
- // `{"path": undefined}` has not supplied it
91
- if (typeof key === "string" && (!(key in value) || value[key] === undefined)) {
92
- out.push({ path: join(path, key), message: "is required but was not provided" });
93
- }
94
- }
95
- }
96
- if (isRec(s.properties)) {
97
- for (const [key, sub] of Object.entries(s.properties)) {
98
- if (key in value && value[key] !== undefined) check(sub, value[key], join(path, key), out);
99
- }
100
- }
101
- }
102
- }
103
-
104
- /** Every problem with these arguments, in schema order. Empty = usable. */
105
- export function validateArgs(schema: unknown, args: unknown): ValidationIssue[] {
106
- const out: ValidationIssue[] = [];
107
- // a schema with no `type` still describes an object when it lists properties/required
108
- const root = isRec(schema) && (schema as Schema).type === undefined && ((schema as Schema).properties !== undefined || (schema as Schema).required !== undefined)
109
- ? { ...(schema as Record<string, unknown>), type: "object" }
110
- : schema;
111
- check(root, args, "", out);
112
- return out;
113
- }
114
-
115
- /** The line the model reads. Names the tool and each bad property; the model's next attempt is a
116
- * correction, not a guess. Bounded: a list of 50 malformed todos must not become a 50-line error. */
117
- export function formatIssues(tool: string, issues: readonly ValidationIssue[], max = 5): string {
118
- const shown = issues.slice(0, max).map((i) => (i.path === "" ? i.message : `${i.path} ${i.message}`));
119
- const more = issues.length > shown.length ? ` (+${issues.length - shown.length} more)` : "";
120
- return `Invalid arguments for ${tool}: ${shown.join("; ")}${more}`;
121
- }
@@ -1,159 +0,0 @@
1
- /** The verify gate: a run that changed files runs the project's own check before it is allowed to end "done".
2
- *
3
- * Why: "done" is the model's silence (loop.ts, the finish check). The finish check catches the model stopping
4
- * right after a failure it could see. This catches the failure it could NOT see — the edit landed, the tests it
5
- * never ran are red. The check's failing part goes back to the model ONCE, the same way the finish check's
6
- * message does; then the run ends with working code or with an honest "check failed: …" on run_end.
7
- *
8
- * What is here: the runner (bounded by its own timeout, the run's abort, the executor's 10k clip), the
9
- * failing-part extraction, the nudge text and the one-clause rendering. What is NOT here: deciding WHICH
10
- * command runs. That is core/verify.ts (resolveVerify: configuration or an unambiguous script, never a guess),
11
- * taken here as an injected function — this file never reads settings itself. No resolution = the gate does
12
- * not run and run_end says "not verified: no check configured". Silence about an unverified change is the
13
- * bug the finish check exists for; it is not reintroduced here.
14
- *
15
- * Blind spot, stated rather than hidden: the gate keys on RunOutstanding.writes (successful edit/write calls).
16
- * A run that changed files only through `bash` (sed, git apply, a generator) has writes 0 and is not verified —
17
- * and not reported either, because a bash call that changed nothing (ls, grep, cat) looks identical from here
18
- * and "not verified" on every lookup would be the noise the finish check was careful to avoid. */
19
-
20
- import type { RunOutstanding } from "./types.ts";
21
- import { resolveVerify, recordVerifyTiming } from "./verify.ts";
22
-
23
- /** what the resolver (core/verify.ts) answers, in the shape this file needs: the commands to run in order,
24
- * uninterpreted (targeting — "typecheck plus the tests that import the changed files" — is the resolver's
25
- * business, this runner never has to understand a command); what it saw and refused, each with its reason;
26
- * and, when there is nothing to run, why. */
27
- export interface VerifyResolution {
28
- commands: string[];
29
- refused?: string[];
30
- /** where the commands came from ("settings", "inferred", "none") */
31
- source?: string;
32
- /** one sentence from the resolver: the file and key the answer came from, or why there is none */
33
- reason?: string;
34
- }
35
- export type VerifyResolver = (cwd: string) => VerifyResolution | null;
36
-
37
- /** the seam, one direction: this file asks core/verify.ts, never the other way round. `resolveVerify` reads
38
- * settings and the project's manifests and decides; nothing here second-guesses it. */
39
- export const resolveForGate: VerifyResolver = (cwd) => {
40
- const plan = resolveVerify(cwd);
41
- return { commands: plan.commands, refused: plan.refused, source: plan.source, reason: plan.reason };
42
- };
43
-
44
- /** what one check cost, for the doctor row and the "on by default?" question (core/verify.ts timing file) */
45
- export function noteVerifyCost(cwd: string, o: VerifyOutcome): void {
46
- try { if (o.ran > 0) recordVerifyTiming(cwd, o.command, o.ms); } catch { /* a timing file that cannot be written is not the run's problem */ }
47
- }
48
-
49
- export interface VerifyOutcome {
50
- /** the command that decided the outcome: the failing one, or the last one when all passed */
51
- command: string;
52
- ok: boolean;
53
- code: number;
54
- timedOut: boolean;
55
- ms: number;
56
- /** the failing part of the output — never the whole log (failingPart); "" when ok */
57
- failure: string;
58
- /** how many of the resolved commands ran (a failure stops the list) */
59
- ran: number;
60
- }
61
-
62
- /** run one command through the same executor `bash` uses; injectable for tests */
63
- export type Exec = (cmd: string, cwd: string, signal: AbortSignal) => Promise<{ code: number; text: string }>;
64
-
65
- export const VERIFY_TIMEOUT_MS = 120_000;
66
- export const FAILURE_CHARS = 3_000;
67
- const TAIL_LINES = 40;
68
- const EARLIER_LINES = 20;
69
-
70
- const defaultExec: Exec = async (cmd, cwd, signal) => {
71
- const { getExecutor } = await import("./executor.ts");
72
- return getExecutor().run(cmd, cwd, signal);
73
- };
74
-
75
- /** The part of a check's output that says what failed: the last 40 lines (test runners summarize at the end),
76
- * preceded by up to 20 earlier lines that name a failure, clipped from the FRONT to `cap` chars so the summary
77
- * survives. Never the whole log — 4 000 lines of test output back to the model is the same as no information. */
78
- export function failingPart(text: string, cap = FAILURE_CHARS): string {
79
- const lines = text.replace(/\r\n?/g, "\n").split("\n");
80
- while (lines.length > 0 && lines.at(-1)!.trim() === "") lines.pop();
81
- const tailStart = Math.max(0, lines.length - TAIL_LINES);
82
- const earlier = lines.slice(0, tailStart).filter((l) => /\b(fail|failed|failing|error|not ok|assert(ion)?|exception|panic)\b|✗|×|✘/i.test(l));
83
- const picked = earlier.length > EARLIER_LINES ? [...earlier.slice(0, EARLIER_LINES), `… ${earlier.length - EARLIER_LINES} more lines naming a failure`] : earlier;
84
- const parts = [...picked];
85
- if (picked.length > 0 && tailStart > 0) parts.push("…");
86
- parts.push(...lines.slice(tailStart));
87
- let out = parts.join("\n");
88
- if (out.length > cap) out = `[… ${out.length - cap} chars clipped]\n${out.slice(out.length - cap)}`;
89
- return out;
90
- }
91
-
92
- /** Run the resolved commands in order, stopping at the first failure. Bounded by `timeoutMs` (its own clock,
93
- * combined with the run's abort). A timeout or an abort ends the command through the executor's kill path and
94
- * is reported as ok:false — a timed-out check is a failed check, not a passed one. An executor that cannot run
95
- * at all (no rung configured, bash missing) is a failure with that message, never a throw. */
96
- export async function runVerify(
97
- res: VerifyResolution, cwd: string,
98
- opts: { signal?: AbortSignal; timeoutMs?: number; exec?: Exec; clock?: () => number } = {},
99
- ): Promise<VerifyOutcome> {
100
- const exec = opts.exec ?? defaultExec;
101
- const clock = opts.clock ?? Date.now;
102
- const timeoutMs = opts.timeoutMs ?? VERIFY_TIMEOUT_MS;
103
- const started = clock();
104
- let ran = 0;
105
- let last = res.commands[0] ?? "";
106
- for (const command of res.commands) {
107
- last = command;
108
- const ac = new AbortController();
109
- let timedOut = false;
110
- const onAbort = () => ac.abort();
111
- if (opts.signal?.aborted) ac.abort(); else opts.signal?.addEventListener("abort", onAbort, { once: true });
112
- const timer = setTimeout(() => { timedOut = true; ac.abort(); }, timeoutMs);
113
- let r: { code: number; text: string };
114
- try { r = await exec(command, cwd, ac.signal); }
115
- catch (e) { r = { code: -1, text: `could not run the check: ${e instanceof Error ? e.message : String(e)}` }; }
116
- finally { clearTimeout(timer); opts.signal?.removeEventListener("abort", onAbort); }
117
- ran++;
118
- if (timedOut) return { command, ok: false, code: r.code, timedOut: true, ms: clock() - started, failure: failingPart(r.text), ran };
119
- if (r.code !== 0 || opts.signal?.aborted) return { command, ok: false, code: r.code, timedOut: false, ms: clock() - started, failure: failingPart(r.text), ran };
120
- }
121
- return { command: last, ok: true, code: 0, timedOut: false, ms: clock() - started, failure: "", ran };
122
- }
123
-
124
- /** The one continuation turn after a failed check. A harness message, not the user's; both answers — fix it, or
125
- * say plainly why it cannot be made to pass — are acceptable, and the next silence ends the run either way. */
126
- export function verifyNudgeText(o: VerifyOutcome, timeoutMs = VERIFY_TIMEOUT_MS): string {
127
- const head = o.timedOut
128
- ? `The project's check did not finish within ${Math.round(timeoutMs / 1000)}s and was stopped: \`${o.command}\``
129
- : `The project's check failed (exit ${o.code}) after your changes: \`${o.command}\``;
130
- return [
131
- "<verify-check>",
132
- "You stopped, but the work does not pass — this is a check by the harness, not a message from the user.",
133
- head,
134
- o.failure.trim() === "" ? "(the check produced no output)" : "Failing part of its output:\n" + o.failure,
135
- "Fix what your changes broke and run the check yourself, or say plainly why it cannot be made to pass. This check runs once per run; your next reply ends it either way.",
136
- "</verify-check>",
137
- ].join("\n");
138
- }
139
-
140
- /** one clause for the surfaces ("done · check failed (bun test): 2 tests failed") */
141
- export function verifyClause(v: NonNullable<RunOutstanding["verify"]>): string {
142
- const refused = v.refused && v.refused.length > 0 ? ` · ${v.refused.length} check${v.refused.length === 1 ? "" : "s"} refused (${v.refused.join("; ")})` : "";
143
- // a configured check can be a whole shell line; the clause names it, the transcript carries it
144
- const cmd = "command" in v ? (v.command.length > 60 ? `${v.command.slice(0, 59)}…` : v.command) : "";
145
- switch (v.state) {
146
- case "unconfigured": return `not verified: ${v.reason ?? "no check configured"}${refused}`;
147
- case "passed": return `check passed (${cmd})${refused}`;
148
- case "timeout": return `check timed out after ${v.seconds}s (${cmd})${refused}`;
149
- case "failed": return `check failed (${cmd}): ${(v.failure.split("\n").filter((l) => l.trim() !== "").at(-1) ?? "").slice(0, 120)}${refused}`;
150
- }
151
- }
152
-
153
- /** first line for the surfaces while it runs / when it ends (the RunEvent "verify" detail) */
154
- export function verifyDetail(o: VerifyOutcome): string {
155
- if (o.ok) return `passed in ${(o.ms / 1000).toFixed(1)}s`;
156
- if (o.timedOut) return `timed out after ${(o.ms / 1000).toFixed(0)}s`;
157
- const lastLine = o.failure.split("\n").filter((l) => l.trim() !== "").at(-1) ?? "";
158
- return `exit ${o.code}${lastLine ? ` — ${lastLine.slice(0, 120)}` : ""}`;
159
- }