rovecode 0.3.3 → 0.4.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +46 -48
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-j6gn14w3.js +2 -0
  5. package/dist/cli/ask-user-cwstt8fz.js +2 -0
  6. package/dist/cli/auth-login-9bbp9915.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-16zqdms5.js +9 -0
  9. package/dist/cli/catalog-1xchffa4.js +2 -0
  10. package/dist/cli/cli-1n1zb64f.js +2 -0
  11. package/dist/cli/client-2t9gjkck.js +2 -0
  12. package/dist/cli/commands-exafvm2b.js +2 -0
  13. package/dist/cli/connect-6zde0kn3.js +2 -0
  14. package/dist/cli/context-cmd-5t43wgqt.js +2 -0
  15. package/dist/cli/context-report-kt01pw8y.js +2 -0
  16. package/dist/cli/count-remote-ap7x3vh6.js +2 -0
  17. package/dist/cli/design-ne5zszyh.js +2 -0
  18. package/dist/cli/dispatch-2r5myxye.js +2 -0
  19. package/dist/cli/doctor-ws4fh4tn.js +3 -0
  20. package/dist/cli/executor-bdrjn634.js +2 -0
  21. package/dist/cli/export-1mxb9g5p.js +2 -0
  22. package/dist/cli/files-g104xghh.js +2 -0
  23. package/dist/cli/gauntlet-07xrjpj7.js +2 -0
  24. package/dist/cli/gauntlet-runner-xvy64436.js +10 -0
  25. package/dist/cli/gauntlet-wave3-jm91yt5w.js +5 -0
  26. package/dist/cli/gauntlet-wave4-r13py7p1.js +14 -0
  27. package/dist/cli/hashline-znvrat11.js +2 -0
  28. package/dist/cli/http-xafw6fsh.js +143 -0
  29. package/dist/cli/index-1sgjm25y.js +2 -0
  30. package/dist/cli/init-g2m0tn4m.js +51 -0
  31. package/dist/cli/install-avaqjjqq.js +2 -0
  32. package/dist/cli/loop-mmpfft01.js +2 -0
  33. package/dist/cli/main-0904f6ps.js +5 -0
  34. package/dist/cli/main-0ab9fc26.js +9 -0
  35. package/dist/cli/main-0jys2ccn.js +3 -0
  36. package/dist/cli/main-0mtcdbs7.js +3 -0
  37. package/dist/cli/main-0z1w2zsg.js +3 -0
  38. package/dist/cli/main-1dchs7xv.js +18 -0
  39. package/dist/cli/main-1ereejm1.js +3 -0
  40. package/dist/cli/main-1k1kw6b5.js +3 -0
  41. package/dist/cli/main-27y4sm2k.js +38 -0
  42. package/dist/cli/main-2wwjex5j.js +58 -0
  43. package/dist/cli/main-2yeveeve.js +6 -0
  44. package/dist/cli/main-2yfck9b5.js +3 -0
  45. package/dist/cli/main-2zmzgkwh.js +3 -0
  46. package/dist/cli/main-351pz3z7.js +7 -0
  47. package/dist/cli/main-3gjqfh7a.js +6 -0
  48. package/dist/cli/main-3nf3kgve.js +3 -0
  49. package/dist/cli/main-3pjrb2hd.js +3 -0
  50. package/dist/cli/main-3rxcvgna.js +19 -0
  51. package/dist/cli/main-4b3jgy66.js +19 -0
  52. package/dist/cli/main-4wndhjdc.js +7 -0
  53. package/dist/cli/main-4xcmvxnk.js +3 -0
  54. package/dist/cli/main-5tbz0wbz.js +4 -0
  55. package/dist/cli/main-5ywnwthm.js +3 -0
  56. package/dist/cli/main-6b62vkz0.js +14 -0
  57. package/dist/cli/main-6dnk69vp.js +3 -0
  58. package/dist/cli/main-6genrmhs.js +136 -0
  59. package/dist/cli/main-73g7eff4.js +15 -0
  60. package/dist/cli/main-7c5thhjd.js +5 -0
  61. package/dist/cli/main-7rn6bqje.js +3 -0
  62. package/dist/cli/main-80haw7qk.js +4 -0
  63. package/dist/cli/main-875s60s2.js +4 -0
  64. package/dist/cli/main-8kjxbpw4.js +8 -0
  65. package/dist/cli/main-90ds1z4e.js +10 -0
  66. package/dist/cli/main-9etavkew.js +3 -0
  67. package/dist/cli/main-a9njrkk1.js +3 -0
  68. package/dist/cli/main-aecrjq2d.js +12 -0
  69. package/dist/cli/main-ck9asesq.js +9 -0
  70. package/dist/cli/main-cta9racd.js +4 -0
  71. package/dist/cli/main-ddv7j2ag.js +3 -0
  72. package/dist/cli/main-dfreez27.js +10 -0
  73. package/dist/cli/main-f7rw7des.js +3 -0
  74. package/dist/cli/main-ggcn7rd7.js +5 -0
  75. package/dist/cli/main-gzkmycnv.js +3 -0
  76. package/dist/cli/main-hq51jg8v.js +18 -0
  77. package/dist/cli/main-jft389w9.js +8 -0
  78. package/dist/cli/main-k1eqkg83.js +3 -0
  79. package/dist/cli/main-k2y8a2aw.js +9 -0
  80. package/dist/cli/main-kcpbykxz.js +4 -0
  81. package/dist/cli/main-kd488vje.js +22 -0
  82. package/dist/cli/main-kh32yvgk.js +5 -0
  83. package/dist/cli/main-kqxnqjnv.js +25 -0
  84. package/dist/cli/main-kyn0xnsg.js +3 -0
  85. package/dist/cli/main-m1kk6fp5.js +21 -0
  86. package/dist/cli/main-mv40pcr2.js +4 -0
  87. package/dist/cli/main-n0t3973w.js +3 -0
  88. package/dist/cli/main-nqveez48.js +4 -0
  89. package/dist/cli/main-pknhvrmj.js +3 -0
  90. package/dist/cli/main-pn1w7a7j.js +3 -0
  91. package/dist/cli/main-prxxs70n.js +4 -0
  92. package/dist/cli/main-q3vsesf9.js +3 -0
  93. package/dist/cli/main-qsevpgsv.js +3 -0
  94. package/dist/cli/main-rdgdw24b.js +25 -0
  95. package/dist/cli/main-rfth4tbm.js +16 -0
  96. package/dist/cli/main-rg0wn0xf.js +5 -0
  97. package/dist/cli/main-sdmxhtv8.js +4 -0
  98. package/dist/cli/main-skbp13js.js +18 -0
  99. package/dist/cli/main-t4xnd213.js +7 -0
  100. package/dist/cli/main-vqak588n.js +4 -0
  101. package/dist/cli/main-w2n1303f.js +9 -0
  102. package/dist/cli/main-wbrdspr2.js +5 -0
  103. package/dist/cli/main-wsrg79c1.js +7 -0
  104. package/dist/cli/main-x4r0fne4.js +5 -0
  105. package/dist/cli/main-xea2f3tn.js +6 -0
  106. package/dist/cli/main-xg704a3c.js +3 -0
  107. package/dist/cli/main-xvnrabfp.js +16 -0
  108. package/dist/cli/main-xy53xf0r.js +4 -0
  109. package/dist/cli/main-y1fqy60y.js +3 -0
  110. package/dist/cli/main-yn8cd281.js +34 -0
  111. package/dist/cli/main-yr0ksc0h.js +4 -0
  112. package/dist/cli/main-z2ex2vyf.js +4 -0
  113. package/dist/cli/main-z3aayzvq.js +3 -0
  114. package/dist/cli/main-zaqh35jg.js +3 -0
  115. package/dist/cli/main-zc2e8e46.js +4 -0
  116. package/dist/cli/main-zzrfw6cf.js +13 -0
  117. package/dist/cli/main.js +280 -0
  118. package/dist/cli/market-cmd-e14kmx9n.js +5 -0
  119. package/dist/cli/mcp-login-wq7ktdek.js +2 -0
  120. package/dist/cli/mcp-market-cmd-9mg3jecy.js +2 -0
  121. package/dist/cli/notify-b7qc0cjb.js +2 -0
  122. package/dist/cli/oauth-z8whcgfx.js +2 -0
  123. package/dist/cli/output-b3ewj3ps.js +16 -0
  124. package/dist/cli/profiles-6mr5he5e.js +2 -0
  125. package/dist/cli/provider-config-g7j42q8x.js +2 -0
  126. package/dist/cli/provider-jr1y8vvm.js +2 -0
  127. package/dist/cli/registry-s8yk86g0.js +2 -0
  128. package/dist/cli/registry-t6p8d4mn.js +2 -0
  129. package/dist/cli/repl-bajwe1mh.js +11 -0
  130. package/dist/cli/resume-rwn9nz7y.js +2 -0
  131. package/dist/cli/run-flags-nah7ndpt.js +2 -0
  132. package/dist/cli/runtime-n7gafzhb.js +2 -0
  133. package/dist/cli/sandbox-config-emdy18x4.js +2 -0
  134. package/dist/cli/server-b0nvs2bn.js +5 -0
  135. package/dist/cli/session-arg-y75wd4kj.js +2 -0
  136. package/dist/cli/session-j62evmjq.js +2 -0
  137. package/dist/cli/sessions-cmd-tsnwz0ns.js +7 -0
  138. package/dist/cli/settings-df10wfez.js +2 -0
  139. package/dist/cli/setup-jzvv72fg.js +2 -0
  140. package/dist/cli/sextant-smoke-37m81ke6.js +5 -0
  141. package/dist/cli/skills-cmd-gjxnxnhx.js +2 -0
  142. package/dist/cli/smoke-p7748apt.js +8 -0
  143. package/dist/cli/start-chat-s4st3mm0.js +12 -0
  144. package/dist/cli/stream-gmeyewds.js +2 -0
  145. package/dist/cli/task-gh0kkp3n.js +2 -0
  146. package/dist/cli/tasks-z1kfpe8e.js +2 -0
  147. package/dist/cli/thinking-0eqkrz6t.js +2 -0
  148. package/dist/cli/todo-5brcrt9m.js +2 -0
  149. package/dist/cli/tools-7pzm0vj9.js +2 -0
  150. package/dist/cli/tools-s635p6s8.js +2 -0
  151. package/dist/cli/trust-cmd-cjav8zgm.js +2 -0
  152. package/dist/cli/update-check-pt31bm2f.js +2 -0
  153. package/dist/cli/update-cmd-tk131s9t.js +2 -0
  154. package/dist/cli/voice-56nabd8d.js +2 -0
  155. package/dist/cli/webfetch-xd8q596m.js +2 -0
  156. package/dist/cli/websearch-5hkf98k1.js +2 -0
  157. package/dist/cli/workflow-cmd-cy3cvzjp.js +4 -0
  158. package/dist/cli/workspace-q10g5z3e.js +2 -0
  159. package/dist/lib/index.js +62 -0
  160. package/dist/lib/models-index.json +1 -0
  161. package/dist/lib/plugins.js +55 -0
  162. package/dist/lib/providers.js +17 -0
  163. package/dist/lib/public-api.js +20 -0
  164. package/dist/lib/sdk.js +360 -0
  165. package/package.json +84 -72
  166. package/bin/rovecode.ts +0 -21
  167. package/src/acp/server.ts +0 -374
  168. package/src/cli/auth-login.ts +0 -122
  169. package/src/cli/connect.ts +0 -244
  170. package/src/cli/context-cmd.ts +0 -199
  171. package/src/cli/dispatch.ts +0 -82
  172. package/src/cli/doctor.ts +0 -362
  173. package/src/cli/export.ts +0 -276
  174. package/src/cli/help.ts +0 -293
  175. package/src/cli/is-tui-invocation.ts +0 -8
  176. package/src/cli/main.ts +0 -583
  177. package/src/cli/market-cmd.ts +0 -658
  178. package/src/cli/mcp-login.ts +0 -141
  179. package/src/cli/mcp-market-cmd.ts +0 -302
  180. package/src/cli/output.ts +0 -382
  181. package/src/cli/repl.ts +0 -250
  182. package/src/cli/repomap-root.ts +0 -14
  183. package/src/cli/resume.ts +0 -57
  184. package/src/cli/run-flags.ts +0 -43
  185. package/src/cli/run-limits.ts +0 -78
  186. package/src/cli/runtime.ts +0 -931
  187. package/src/cli/session-arg.ts +0 -30
  188. package/src/cli/sessions-cmd.ts +0 -145
  189. package/src/cli/setup.ts +0 -153
  190. package/src/cli/skills-cmd.ts +0 -194
  191. package/src/cli/start-chat.ts +0 -65
  192. package/src/cli/trust-cmd.ts +0 -52
  193. package/src/coding/bash.ts +0 -148
  194. package/src/coding/checkpoints.ts +0 -327
  195. package/src/coding/diff.ts +0 -138
  196. package/src/coding/files.ts +0 -341
  197. package/src/coding/hashline.ts +0 -274
  198. package/src/coding/lsp-gate.ts +0 -254
  199. package/src/coding/lsp-servers.ts +0 -147
  200. package/src/coding/lsp.ts +0 -283
  201. package/src/coding/repomap-cache.ts +0 -99
  202. package/src/coding/repomap-files.ts +0 -192
  203. package/src/coding/repomap.ts +0 -481
  204. package/src/core/agents.ts +0 -255
  205. package/src/core/compaction.ts +0 -259
  206. package/src/core/config.ts +0 -289
  207. package/src/core/context-report.ts +0 -228
  208. package/src/core/context.ts +0 -60
  209. package/src/core/count-remote.ts +0 -107
  210. package/src/core/execpolicy-rules.ts +0 -196
  211. package/src/core/execpolicy.ts +0 -385
  212. package/src/core/executor.ts +0 -454
  213. package/src/core/guardrails.ts +0 -400
  214. package/src/core/hooks.ts +0 -411
  215. package/src/core/images.ts +0 -230
  216. package/src/core/intro.ts +0 -266
  217. package/src/core/loop.ts +0 -567
  218. package/src/core/modes.ts +0 -372
  219. package/src/core/orchestrator.ts +0 -245
  220. package/src/core/proc-group.ts +0 -48
  221. package/src/core/project-trust.ts +0 -98
  222. package/src/core/reflection.ts +0 -165
  223. package/src/core/sandbox-config.ts +0 -186
  224. package/src/core/session-id.ts +0 -24
  225. package/src/core/session-images.ts +0 -73
  226. package/src/core/session-ops.ts +0 -183
  227. package/src/core/session-text.ts +0 -29
  228. package/src/core/session.ts +0 -469
  229. package/src/core/settings.ts +0 -170
  230. package/src/core/tasks.ts +0 -646
  231. package/src/core/token-scale.ts +0 -108
  232. package/src/core/tools.ts +0 -309
  233. package/src/core/trust.ts +0 -104
  234. package/src/core/types.ts +0 -330
  235. package/src/core/update-check.ts +0 -171
  236. package/src/core/usage.ts +0 -204
  237. package/src/core/validate.ts +0 -121
  238. package/src/core/verify-gate.ts +0 -159
  239. package/src/core/verify.ts +0 -236
  240. package/src/core/voice.ts +0 -158
  241. package/src/core/win-job.ts +0 -183
  242. package/src/core/workspace.ts +0 -184
  243. package/src/design/audit.ts +0 -797
  244. package/src/design/direction.ts +0 -190
  245. package/src/design/rules.ts +0 -157
  246. package/src/eval/bench.ts +0 -150
  247. package/src/eval/gauntlet-runner.ts +0 -215
  248. package/src/eval/gauntlet-support.ts +0 -84
  249. package/src/eval/gauntlet-wave3.ts +0 -269
  250. package/src/eval/gauntlet-wave4.ts +0 -217
  251. package/src/eval/gauntlet.ts +0 -253
  252. package/src/index.ts +0 -17
  253. package/src/lanes/agy.ts +0 -95
  254. package/src/lanes/approval.ts +0 -24
  255. package/src/lanes/claude.ts +0 -129
  256. package/src/lanes/codex.ts +0 -127
  257. package/src/lanes/events.ts +0 -130
  258. package/src/lanes/job.ts +0 -142
  259. package/src/lanes/opencode.ts +0 -122
  260. package/src/lanes/process.ts +0 -184
  261. package/src/lanes/progress.ts +0 -183
  262. package/src/lanes/registry.ts +0 -178
  263. package/src/lanes/runner.ts +0 -124
  264. package/src/lanes/types.ts +0 -112
  265. package/src/market/catalogs/mcp-docs.json +0 -111
  266. package/src/market/catalogs/plugins.json +0 -111
  267. package/src/market/catalogs/skills.json +0 -478
  268. package/src/market/clone.ts +0 -72
  269. package/src/market/context-cost.ts +0 -121
  270. package/src/market/digest.ts +0 -106
  271. package/src/market/index.ts +0 -22
  272. package/src/market/install.ts +0 -578
  273. package/src/market/manifest.ts +0 -187
  274. package/src/market/prereq.ts +0 -145
  275. package/src/market/registry.ts +0 -363
  276. package/src/market/resolve.ts +0 -111
  277. package/src/market/types.ts +0 -236
  278. package/src/market/validate.ts +0 -227
  279. package/src/mcp/client.ts +0 -449
  280. package/src/mcp/config.ts +0 -252
  281. package/src/mcp/local-package.ts +0 -211
  282. package/src/mcp/market-catalog.ts +0 -84
  283. package/src/mcp/market-install.ts +0 -289
  284. package/src/mcp/market.ts +0 -362
  285. package/src/mcp/oauth.ts +0 -251
  286. package/src/mcp/prompts-resources.ts +0 -249
  287. package/src/mcp/shared.ts +0 -149
  288. package/src/mcp/status.ts +0 -67
  289. package/src/mcp/tools.ts +0 -275
  290. package/src/mcp/transport.ts +0 -122
  291. package/src/mcp/trust.ts +0 -25
  292. package/src/memory/blocks.ts +0 -278
  293. package/src/memory/recall.ts +0 -355
  294. package/src/memory/scope.ts +0 -182
  295. package/src/memory/store.ts +0 -105
  296. package/src/memory/tools.ts +0 -99
  297. package/src/plugins/cli.ts +0 -119
  298. package/src/plugins/discover.ts +0 -108
  299. package/src/plugins/index.ts +0 -50
  300. package/src/plugins/install.ts +0 -184
  301. package/src/plugins/load.ts +0 -124
  302. package/src/plugins/manifest.ts +0 -92
  303. package/src/plugins/state.ts +0 -83
  304. package/src/providers/auth.ts +0 -408
  305. package/src/providers/cache.ts +0 -223
  306. package/src/providers/catalog-local.ts +0 -160
  307. package/src/providers/catalog.ts +0 -421
  308. package/src/providers/middleware-context.ts +0 -86
  309. package/src/providers/middleware.ts +0 -373
  310. package/src/providers/model-list.ts +0 -23
  311. package/src/providers/oauth/common.ts +0 -105
  312. package/src/providers/oauth/device-code.ts +0 -107
  313. package/src/providers/oauth/github-copilot.ts +0 -146
  314. package/src/providers/oauth/loopback.ts +0 -158
  315. package/src/providers/oauth/openai.ts +0 -163
  316. package/src/providers/oauth/openrouter.ts +0 -89
  317. package/src/providers/oauth/pkce.ts +0 -45
  318. package/src/providers/oauth/registry.ts +0 -39
  319. package/src/providers/oauth/seam.ts +0 -89
  320. package/src/providers/profile-glm53.ts +0 -111
  321. package/src/providers/profile-sonnet5-persona.ts +0 -65
  322. package/src/providers/profile-sonnet5-voice.ts +0 -23
  323. package/src/providers/profiles.ts +0 -156
  324. package/src/providers/provider-config.ts +0 -311
  325. package/src/providers/registry.ts +0 -333
  326. package/src/providers/responses.ts +0 -209
  327. package/src/providers/retry.ts +0 -234
  328. package/src/providers/router.ts +0 -294
  329. package/src/providers/sse.ts +0 -26
  330. package/src/providers/stream-errors.ts +0 -117
  331. package/src/providers/stream.ts +0 -566
  332. package/src/providers/thinking.ts +0 -189
  333. package/src/providers/wire-messages.ts +0 -129
  334. package/src/providers/wire-responses.ts +0 -79
  335. package/src/providers/wire-select.ts +0 -53
  336. package/src/server/http.ts +0 -291
  337. package/src/server/openapi.ts +0 -246
  338. package/src/sextant/card-hits.ts +0 -102
  339. package/src/sextant/card-keys.ts +0 -55
  340. package/src/sextant/context-source.ts +0 -157
  341. package/src/sextant/crew-cards.ts +0 -350
  342. package/src/sextant/draw-agents.ts +0 -273
  343. package/src/sextant/draw-code.ts +0 -388
  344. package/src/sextant/draw-context.ts +0 -222
  345. package/src/sextant/draw-frame.ts +0 -164
  346. package/src/sextant/draw-market.ts +0 -573
  347. package/src/sextant/draw-messages.ts +0 -386
  348. package/src/sextant/draw-pet.ts +0 -230
  349. package/src/sextant/draw-plan.ts +0 -187
  350. package/src/sextant/draw-tabs.ts +0 -85
  351. package/src/sextant/draw-util.ts +0 -65
  352. package/src/sextant/draw-wizard.ts +0 -378
  353. package/src/sextant/engine.ts +0 -230
  354. package/src/sextant/frame-hits.ts +0 -25
  355. package/src/sextant/frame.ts +0 -101
  356. package/src/sextant/git-status.ts +0 -197
  357. package/src/sextant/grid.ts +0 -59
  358. package/src/sextant/input.ts +0 -119
  359. package/src/sextant/keys.ts +0 -521
  360. package/src/sextant/layout.ts +0 -86
  361. package/src/sextant/local-commands.ts +0 -169
  362. package/src/sextant/market-source.ts +0 -287
  363. package/src/sextant/mentions.ts +0 -200
  364. package/src/sextant/message-hits.ts +0 -26
  365. package/src/sextant/model.ts +0 -387
  366. package/src/sextant/overlays.ts +0 -456
  367. package/src/sextant/panel-hits.ts +0 -38
  368. package/src/sextant/pet.ts +0 -399
  369. package/src/sextant/screen.ts +0 -324
  370. package/src/sextant/scroll-hits.ts +0 -66
  371. package/src/sextant/scrollbar.ts +0 -82
  372. package/src/sextant/sextant-bridge.ts +0 -174
  373. package/src/sextant/sextant-cards.ts +0 -142
  374. package/src/sextant/sextant-diff-base.ts +0 -63
  375. package/src/sextant/sextant-files.ts +0 -154
  376. package/src/sextant/sextant-frame-loop.ts +0 -335
  377. package/src/sextant/sextant-renderer.ts +0 -574
  378. package/src/sextant/sextant-repo.ts +0 -140
  379. package/src/sextant/theme.ts +0 -66
  380. package/src/sextant/tool-rows.ts +0 -189
  381. package/src/sextant/types.ts +0 -493
  382. package/src/skills/index.ts +0 -387
  383. package/src/skills/pack.ts +0 -220
  384. package/src/skills/spec.ts +0 -162
  385. package/src/skills/tools.ts +0 -69
  386. package/src/skills/versioned.ts +0 -227
  387. package/src/telemetry/otel-export.ts +0 -122
  388. package/src/telemetry/otel-lanes.ts +0 -89
  389. package/src/telemetry/otel-logs.ts +0 -131
  390. package/src/telemetry/otel-metrics.ts +0 -136
  391. package/src/telemetry/otel.ts +0 -397
  392. package/src/telemetry/otlp.ts +0 -76
  393. package/src/tools/ask-user.ts +0 -156
  394. package/src/tools/bash-bg.ts +0 -94
  395. package/src/tools/bash-jobs.ts +0 -237
  396. package/src/tools/design.ts +0 -151
  397. package/src/tools/evalcell.ts +0 -338
  398. package/src/tools/html-text.ts +0 -139
  399. package/src/tools/provider.ts +0 -149
  400. package/src/tools/task.ts +0 -250
  401. package/src/tools/todo.ts +0 -320
  402. package/src/tools/webfetch.ts +0 -332
  403. package/src/tools/websearch.ts +0 -359
  404. package/src/tui/agents-cmd.ts +0 -41
  405. package/src/tui/app.ts +0 -749
  406. package/src/tui/attach.ts +0 -127
  407. package/src/tui/boot-notes.ts +0 -41
  408. package/src/tui/builtin-prompts.ts +0 -59
  409. package/src/tui/checkpoints-cmd.ts +0 -70
  410. package/src/tui/clipboard-image.ts +0 -81
  411. package/src/tui/clipboard.ts +0 -78
  412. package/src/tui/commands.ts +0 -283
  413. package/src/tui/config-view.ts +0 -53
  414. package/src/tui/context-cmds.ts +0 -282
  415. package/src/tui/cost.ts +0 -108
  416. package/src/tui/crash-guard.ts +0 -173
  417. package/src/tui/focus-terminal.ts +0 -34
  418. package/src/tui/git-cmds.ts +0 -273
  419. package/src/tui/git-plain.ts +0 -58
  420. package/src/tui/info-cmd.ts +0 -150
  421. package/src/tui/input-plain.ts +0 -76
  422. package/src/tui/mcp-cmd.ts +0 -128
  423. package/src/tui/memory-note.ts +0 -77
  424. package/src/tui/modes-cmd.ts +0 -45
  425. package/src/tui/notify-seq.ts +0 -100
  426. package/src/tui/notify.ts +0 -318
  427. package/src/tui/overlays.ts +0 -97
  428. package/src/tui/pi-renderer.ts +0 -428
  429. package/src/tui/providers-cmd.ts +0 -377
  430. package/src/tui/reasoning-view.ts +0 -56
  431. package/src/tui/renderer.ts +0 -128
  432. package/src/tui/replay-marker.ts +0 -29
  433. package/src/tui/session-cmd.ts +0 -148
  434. package/src/tui/session-manage.ts +0 -95
  435. package/src/tui/sextant-attach.ts +0 -102
  436. package/src/tui/sextant-io.ts +0 -202
  437. package/src/tui/sextant-smoke.ts +0 -110
  438. package/src/tui/shell-cmd.ts +0 -158
  439. package/src/tui/smoke.ts +0 -72
  440. package/src/tui/staged-terminal.ts +0 -50
  441. package/src/tui/startup.ts +0 -12
  442. package/src/tui/theme.ts +0 -59
  443. package/src/tui/todo-label.ts +0 -7
  444. package/src/tui/trust-card.ts +0 -107
  445. package/src/tui/tui-commands.ts +0 -87
  446. package/tsconfig.json +0 -30
  447. package/vendor/pi-tui/LICENSE +0 -21
  448. package/vendor/pi-tui/PATCHES.md +0 -12
  449. package/vendor/pi-tui/PROVENANCE.md +0 -12
  450. package/vendor/pi-tui/README.upstream.md +0 -854
  451. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  452. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  453. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  454. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  455. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  456. package/vendor/pi-tui/src/components/box.ts +0 -138
  457. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  458. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  459. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  460. package/vendor/pi-tui/src/components/image.ts +0 -128
  461. package/vendor/pi-tui/src/components/input.ts +0 -448
  462. package/vendor/pi-tui/src/components/loader.ts +0 -93
  463. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  464. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  465. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  466. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  467. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  468. package/vendor/pi-tui/src/components/stack.ts +0 -155
  469. package/vendor/pi-tui/src/components/text.ts +0 -108
  470. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  471. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  472. package/vendor/pi-tui/src/editor-component.ts +0 -75
  473. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  474. package/vendor/pi-tui/src/index.ts +0 -149
  475. package/vendor/pi-tui/src/keybindings.ts +0 -321
  476. package/vendor/pi-tui/src/keys.ts +0 -1402
  477. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  478. package/vendor/pi-tui/src/latex.ts +0 -1381
  479. package/vendor/pi-tui/src/layout-node.ts +0 -52
  480. package/vendor/pi-tui/src/layout.ts +0 -411
  481. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  482. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  483. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  484. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  485. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  486. package/vendor/pi-tui/src/terminal.ts +0 -554
  487. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  488. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  489. package/vendor/pi-tui/src/tui.ts +0 -1264
  490. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  491. package/vendor/pi-tui/src/utils.ts +0 -1327
  492. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  493. package/vendor/pi-tui/test/test-themes.ts +0 -39
  494. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  495. /package/{src/providers → dist/cli}/models-index.json +0 -0
@@ -1,94 +0,0 @@
1
- /** The three tools that read and stop background shell jobs (port #55): `bash_list`, `bash_output`,
2
- * `bash_kill`. The job manager itself is tools/bash-jobs.ts; starting a job is `bash` with a flag.
3
- *
4
- * WHY THREE READ/WRITE TOOLS AND NOT ONE. A model that starts a four-minute build has to be able to
5
- * ask three different questions — what is still running, what has it printed since I last looked, and
6
- * stop it — and folding them into one tool with an `action` argument means every call carries an
7
- * argument that could be wrong. The cost is three schema entries; the benefit is that each call says
8
- * what it does.
9
- *
10
- * `bash_output` returns only what is NEW since the previous read, so a model polling a build sees the
11
- * next hundred lines rather than the same first hundred again. That is the single most important
12
- * property here: a tool that re-sends its whole buffer every time turns a long build into a context
13
- * leak, and the model cannot tell the repeat from real progress. When the ring dropped output the
14
- * reader had not yet seen, the read SAYS how much it lost — a gap a model is told about can be worked
15
- * around; a silent one is read as the command having printed nothing. */
16
-
17
- import type { Tool, ToolOutput } from "../core/types.ts";
18
- import { jobManager, type JobInfo } from "./bash-jobs.ts";
19
-
20
- const NO_MANAGER = "background jobs are not available on this surface";
21
-
22
- function describe(j: JobInfo, now: number): string {
23
- const secs = Math.round(((j.finishedAt ?? now) - j.startedAt) / 1000);
24
- const code = j.exitCode !== undefined ? ` exit=${j.exitCode}` : "";
25
- const pid = j.pid !== undefined ? ` pid=${j.pid}` : "";
26
- const drop = j.dropped > 0 ? ` (${j.dropped} chars dropped from the buffer)` : "";
27
- return `${j.id} ${j.status}${code}${pid} ${secs}s — ${j.command}${drop}`;
28
- }
29
-
30
- export const bashListTool: Tool = {
31
- schema: {
32
- name: "bash_list",
33
- description:
34
- "List this session's background shell jobs (started with `bash … run_in_background: true`): id, status, exit code, pid, elapsed and the command. " +
35
- "A finished job stays listed until its output has been read at least once, so nothing you started disappears unseen.",
36
- args: { type: "object", properties: {} },
37
- },
38
- kind: "read",
39
- execute(_args, _ctx): Promise<ToolOutput> {
40
- const m = jobManager();
41
- if (!m) return Promise.resolve({ ok: false, output: NO_MANAGER });
42
- const jobs = m.list();
43
- if (jobs.length === 0) return Promise.resolve({ ok: true, output: "no background jobs in this session" });
44
- const now = Date.now();
45
- return Promise.resolve({ ok: true, output: jobs.map((j) => describe(j, now)).join("\n"), data: jobs });
46
- },
47
- };
48
-
49
- export const bashOutputTool: Tool = {
50
- schema: {
51
- name: "bash_output",
52
- description:
53
- "Read what a background job has printed SINCE YOUR LAST READ of it (not the whole buffer — repeated reads show progress, never the same lines twice). " +
54
- "Says `more output remains` when the job printed more than one read returns, and says how many characters were dropped if the job outran its buffer. " +
55
- "Do not poll in a tight loop: a finished job also posts one note into this conversation by itself.",
56
- args: { type: "object", properties: { id: { type: "string", description: "job id from bash_list (e.g. b1)" } }, required: ["id"] },
57
- },
58
- kind: "read",
59
- execute(args, _ctx): Promise<ToolOutput> {
60
- const m = jobManager();
61
- if (!m) return Promise.resolve({ ok: false, output: NO_MANAGER });
62
- const id = String((args as { id: string }).id ?? "").trim();
63
- if (id === "") return Promise.resolve({ ok: false, output: "bash_output needs an id (bash_list shows them)" });
64
- const r = m.read(id);
65
- if (!r.ok) return Promise.resolve({ ok: false, output: r.reason });
66
- const head = describe(r.info, Date.now());
67
- const lost = r.lost > 0 ? `\n[${r.lost} characters were dropped from this job's buffer before you read them]` : "";
68
- const more = r.more ? "\n[more output remains — read again]" : "";
69
- const body = r.text === "" ? "(nothing new)" : r.text;
70
- return Promise.resolve({ ok: true, output: `${head}${lost}\n${body}${more}`, data: r.info });
71
- },
72
- };
73
-
74
- export const bashKillTool: Tool = {
75
- schema: {
76
- name: "bash_kill",
77
- description:
78
- "Stop a background job and everything it started (the process TREE, not just the shell — a killed `npm run dev` must not leave its port bound). " +
79
- "Killing an already-finished job is not an error. Its output stays readable afterwards.",
80
- args: { type: "object", properties: { id: { type: "string", description: "job id from bash_list (e.g. b1)" } }, required: ["id"] },
81
- },
82
- kind: "execute",
83
- execute(args, _ctx): Promise<ToolOutput> {
84
- const m = jobManager();
85
- if (!m) return Promise.resolve({ ok: false, output: NO_MANAGER });
86
- const id = String((args as { id: string }).id ?? "").trim();
87
- if (id === "") return Promise.resolve({ ok: false, output: "bash_kill needs an id (bash_list shows them)" });
88
- const r = m.kill(id);
89
- if (!r.ok) return Promise.resolve({ ok: false, output: r.reason ?? `could not kill "${id}"` });
90
- return Promise.resolve({ ok: true, output: `${id} ${r.info?.status ?? "killed"} — its output is still readable with bash_output ${id}`, data: r.info });
91
- },
92
- };
93
-
94
- export const bashJobTools: readonly Tool[] = [bashListTool, bashOutputTool, bashKillTool];
@@ -1,237 +0,0 @@
1
- /** Background shell jobs (port #55). `bash … run_in_background: true` starts a job here instead of
2
- * awaiting it; `bash_list` / `bash_output` / `bash_kill` (tools/bash-bg.ts) read and stop them.
3
- *
4
- * WHAT A JOB IS NOT. It is not an agent. TaskManager (core/tasks.ts) stays the one agent-job registry
5
- * and nothing in this file runs a loop. A job is one shell command whose output the run can come back
6
- * to — a dev server, a long build, a test suite that takes four minutes — and the reason it exists is
7
- * that the alternative is worse in both directions: a foreground `bash` either blocks the whole run
8
- * until the command finishes, or gets killed by a timeout and loses whatever it had printed.
9
- *
10
- * SAME DOOR, SAME LOCKS. Every job runs through the SAME executor seam a foreground `bash` uses, so
11
- * the configured rung shapes its argv and `kill` is the rung's own tree kill (Windows Job Object +
12
- * taskkill sweep; SIGTERM to the process group on POSIX, #67 — a background `npm run dev` that forks
13
- * is exactly the case where killing only the launcher leaves the port bound). Policy is upstream:
14
- * the permission rules, execpolicy, hooks and the human approval all run before bashTool.execute, so
15
- * starting a job in the background is gated exactly like running it in the foreground. It is the same
16
- * tool with a flag, deliberately (ADR-005).
17
- *
18
- * BOUNDS, because an unbounded buffer is a memory leak with a feature name:
19
- * MAX_JOBS running at once; the next start is refused AS DATA, never thrown
20
- * RING_CHARS decoded output kept per job; the oldest is dropped and the drop is COUNTED, and a
21
- * read reports how many UNREAD characters it lost rather than silently skipping them
22
- * MAX_READ one read returns at most this much and says `more` when output remains
23
- * KEEP_FINISHED finished jobs stay listed until a read has seen their final output; after that only
24
- * the newest few are kept, buffers trimmed to a tail
25
- *
26
- * A finished job posts ONE note through the mechanisms that already exist: a push into the run's
27
- * SteeringQueue (the loop drains it before the next model call, like a task note) and one listener
28
- * emission for the TUI's transcript. It does not interrupt a turn and it does not poll.
29
- *
30
- * Pattern source (Apache-2.0, PATTERN LEVEL ONLY, no code copied): google-gemini/gemini-cli @ 0bd1d43
31
- * — `is_background` as a flag on the ONE shell tool, list rendering pid/status/command/exit code, a
32
- * bounded read that refuses a pid outside the session's own history, and a timed-out result that names
33
- * the timeout and keeps its partial output. Departures: a per-job cursor (each read returns only NEW
34
- * output) instead of a tail snapshot, an in-memory ring instead of a log file, a hard concurrency
35
- * bound, and the kill is the executor's tree-kill path rather than a bare signal. */
36
-
37
- import { getExecutor, type SpawnObserver } from "../core/executor.ts";
38
- import type { SteeringQueue } from "../core/loop.ts";
39
-
40
- export const MAX_JOBS = 4;
41
- export const RING_CHARS = 200_000;
42
- export const MAX_READ = 10_000;
43
- export const KEEP_FINISHED = 8;
44
-
45
- export type JobStatus = "running" | "exited" | "killed" | "failed";
46
-
47
- export interface JobInfo {
48
- id: string;
49
- command: string;
50
- status: JobStatus;
51
- startedAt: number;
52
- finishedAt?: number;
53
- /** the launcher's pid, once the process exists */
54
- pid?: number;
55
- /** the shell's exit code (exited/failed) */
56
- exitCode?: number;
57
- /** characters dropped from the ring because the job outran the buffer */
58
- dropped: number;
59
- /** true once a read has seen the job's final output — only then may it be reaped */
60
- drained: boolean;
61
- }
62
-
63
- interface JobRecord {
64
- info: JobInfo;
65
- buf: string;
66
- /** how far a reader has consumed `buf`; each read returns only what is new */
67
- cursor: number;
68
- ac: AbortController;
69
- done: Promise<void>;
70
- }
71
-
72
- export interface JobManagerOptions {
73
- /** where a finish note lands — the same queue the loop drains before its next model call */
74
- notify?: SteeringQueue;
75
- /** the run's signal: its abort kills every job, so background work never outlives the session */
76
- owner?: AbortSignal;
77
- }
78
-
79
- export class BashJobManager {
80
- private readonly jobs = new Map<string, JobRecord>();
81
- private readonly listeners = new Set<(j: JobInfo) => void>();
82
- private seq = 0;
83
- private unbind?: () => void;
84
-
85
- constructor(private readonly opts: JobManagerOptions = {}) {
86
- const owner = opts.owner;
87
- if (owner) {
88
- const onAbort = (): void => { this.killAll(); };
89
- owner.addEventListener("abort", onAbort, { once: true });
90
- this.unbind = () => owner.removeEventListener("abort", onAbort);
91
- }
92
- }
93
-
94
- /** Status-transition listener (the TUI's transcript note). Returns the unsubscribe. */
95
- subscribe(fn: (j: JobInfo) => void): () => void {
96
- this.listeners.add(fn);
97
- return () => this.listeners.delete(fn);
98
- }
99
-
100
- list(): JobInfo[] { return [...this.jobs.values()].map((j) => ({ ...j.info })); }
101
-
102
- status(id: string): JobInfo | undefined {
103
- const j = this.jobs.get(id);
104
- return j ? { ...j.info } : undefined;
105
- }
106
-
107
- private get running(): number {
108
- let n = 0;
109
- for (const j of this.jobs.values()) if (j.info.status === "running") n++;
110
- return n;
111
- }
112
-
113
- /** Start a job. Refusals are DATA — a full pool is a normal condition, not an exception. */
114
- start(command: string, cwd: string): { ok: true; info: JobInfo } | { ok: false; reason: string } {
115
- if (this.running >= MAX_JOBS) {
116
- return { ok: false, reason: `${MAX_JOBS} background jobs already running (bash_list shows them; bash_kill frees a slot) — run this one in the foreground or wait` };
117
- }
118
- const id = `b${++this.seq}`;
119
- const ac = new AbortController();
120
- const rec: JobRecord = {
121
- info: { id, command, status: "running", startedAt: Date.now(), dropped: 0, drained: false },
122
- buf: "", cursor: 0, ac,
123
- done: Promise.resolve(),
124
- };
125
- const dec = new TextDecoder();
126
- const observe: SpawnObserver = {
127
- onSpawn: (pid) => { rec.info.pid = pid; },
128
- onChunk: (_stream, bytes) => { this.append(rec, dec.decode(bytes, { stream: true })); },
129
- };
130
- this.jobs.set(id, rec);
131
- rec.done = getExecutor().run(command, cwd, ac.signal, observe).then(
132
- (r) => {
133
- // A killed job's non-zero exit is the kill, not the command's verdict — say which happened.
134
- if (rec.info.status === "killed") { this.finish(rec); return; }
135
- rec.info.status = r.code === 0 ? "exited" : "failed";
136
- rec.info.exitCode = r.code;
137
- // The observer streamed the bytes; the result's assembled text is the SAME output a foreground
138
- // run would have returned, so appending it would double every line. Only the tail of a run that
139
- // produced nothing through the taps (a rung that does not observe) is taken from the result.
140
- if (rec.buf === "" && r.text !== "") this.append(rec, r.text);
141
- this.finish(rec);
142
- },
143
- (e: unknown) => {
144
- rec.info.status = "failed";
145
- this.append(rec, `\n[job runner threw: ${e instanceof Error ? e.message : String(e)}]`);
146
- this.finish(rec);
147
- },
148
- );
149
- return { ok: true, info: { ...rec.info } };
150
- }
151
-
152
- private append(rec: JobRecord, text: string): void {
153
- if (text === "") return;
154
- rec.buf += text;
155
- if (rec.buf.length > RING_CHARS) {
156
- const cut = rec.buf.length - RING_CHARS;
157
- rec.buf = rec.buf.slice(cut);
158
- rec.info.dropped += cut;
159
- // the cursor moves with the window; what a reader has not read yet and lost is reported at read time
160
- rec.cursor = Math.max(0, rec.cursor - cut);
161
- }
162
- }
163
-
164
- private finish(rec: JobRecord): void {
165
- rec.info.finishedAt = Date.now();
166
- const info: JobInfo = { ...rec.info };
167
- for (const l of this.listeners) l(info);
168
- // ONE note, through the queue the loop already drains — never an interrupt, never a poll
169
- const how = rec.info.status === "killed" ? "killed" : `exit=${rec.info.exitCode}`;
170
- this.opts.notify?.push(`background job ${rec.info.id} finished (${how}): ${clip(rec.info.command, 60)} — bash_output ${rec.info.id} reads what it printed`);
171
- this.reap();
172
- }
173
-
174
- /** Read only what is NEW since the last read. `lost` is unread output the ring dropped: a reader that
175
- * is told "you missed 40k characters" can act on it; one that is silently handed a gap cannot. */
176
- read(id: string): { ok: false; reason: string } | { ok: true; info: JobInfo; text: string; more: boolean; lost: number } {
177
- const rec = this.jobs.get(id);
178
- if (!rec) return { ok: false, reason: `no background job "${id}" in this session (bash_list shows them; a finished job is dropped after its output has been read)` };
179
- const lostBefore = rec.info.dropped;
180
- const fresh = rec.buf.slice(rec.cursor);
181
- const text = fresh.slice(0, MAX_READ);
182
- rec.cursor += text.length;
183
- const more = rec.cursor < rec.buf.length;
184
- if (!more && rec.info.status !== "running") { rec.info.drained = true; this.reap(); }
185
- return { ok: true, info: { ...rec.info }, text, more, lost: lostBefore };
186
- }
187
-
188
- /** Kill a job through the executor's own abort path — the tree, not just the launcher. */
189
- kill(id: string): { ok: boolean; reason?: string; info?: JobInfo } {
190
- const rec = this.jobs.get(id);
191
- if (!rec) return { ok: false, reason: `no background job "${id}" in this session` };
192
- if (rec.info.status !== "running") return { ok: true, info: { ...rec.info } };
193
- rec.info.status = "killed";
194
- rec.ac.abort();
195
- return { ok: true, info: { ...rec.info } };
196
- }
197
-
198
- killAll(): number {
199
- let n = 0;
200
- for (const j of this.jobs.values()) if (j.info.status === "running") { this.kill(j.info.id); n++; }
201
- return n;
202
- }
203
-
204
- /** Wait for every job to settle (surface shutdown / tests). */
205
- async drain(): Promise<void> { await Promise.allSettled([...this.jobs.values()].map((j) => j.done)); }
206
-
207
- dispose(): void { this.killAll(); this.unbind?.(); this.listeners.clear(); }
208
-
209
- /** Drop drained finished jobs beyond KEEP_FINISHED, oldest first. A finished job whose output nobody
210
- * has read is NEVER dropped: that output is the only record the command ever ran. */
211
- private reap(): void {
212
- const done = [...this.jobs.values()].filter((j) => j.info.status !== "running" && j.info.drained);
213
- if (done.length <= KEEP_FINISHED) return;
214
- done.sort((a, b) => (a.info.finishedAt ?? 0) - (b.info.finishedAt ?? 0));
215
- for (const j of done.slice(0, done.length - KEEP_FINISHED)) this.jobs.delete(j.info.id);
216
- }
217
- }
218
-
219
- const clip = (s: string, n: number): string => (s.length > n ? s.slice(0, n - 1) + "…" : s);
220
-
221
- // ---------- the one manager a runtime installs ----------
222
- //
223
- // bashTool has to reach the manager without every call site threading it, and a runtime must be able to
224
- // exist without one (the `tools` listing, the gauntlet, a unit test): so `run_in_background` with no
225
- // manager installed is a refusal that names the surface, never a silent foreground run. A background
226
- // request that quietly ran in the foreground would block the run it was asked not to block.
227
-
228
- let installed: BashJobManager | null = null;
229
-
230
- export function installJobManager(m: BashJobManager | null): void { installed = m; }
231
- export function hasJobManager(): boolean { return installed !== null; }
232
- export function jobManager(): BashJobManager | null { return installed; }
233
-
234
- export function startBashJob(command: string, cwd: string): { ok: true; info: JobInfo } | { ok: false; reason: string } {
235
- if (!installed) return { ok: false, reason: "background jobs are not available on this surface — run the command in the foreground (drop run_in_background)" };
236
- return installed.start(command, cwd);
237
- }
@@ -1,151 +0,0 @@
1
- /** design_audit / design_direction — the agent's half of the design protocol (design/rules.ts).
2
- *
3
- * Split like provider_list/provider_edit (and task/task_status) for the same reason: reading must
4
- * never cost a prompt, writing must be visible.
5
- * - design_audit is kind "read" -> policy action file.read, auto-allowed under the gated rules and
6
- * in plan mode. Checking your own work has to be free, or it will not happen.
7
- * - design_direction is kind "custom" -> action tool.design_direction, PROMPT under the gated rules
8
- * (cli/runtime.ts buildCfg), denied in plan mode by the blanket tool.* rule, allowed under yolo.
9
- * It writes the project's design identity, and the approval card is where the human sees exactly
10
- * what is being recorded on their behalf. It is asked ONCE per project, which is the whole design
11
- * of the feature -- so the one prompt is the point, not friction.
12
- *
13
- * design_direction deliberately cannot invent a direction: `set` records what the human chose. The
14
- * model is expected to have asked first (the prompt section says so). Nothing here can enforce that
15
- * -- what it can do is keep the record honest and put the write in front of a human once. */
16
-
17
- import { isAbsolute, relative, resolve } from "node:path";
18
- import type { Tool, ToolOutput } from "../core/types.ts";
19
- import { auditFiles, auditProject, formatFindings, type Finding } from "../design/audit.ts";
20
- import {
21
- designPath, loadDirection, parseDirection, renderDirection, saveDirection,
22
- type DesignDirection,
23
- } from "../design/direction.ts";
24
-
25
- /** Resolve a caller-supplied path against the run's cwd and refuse to leave it: an audit is about
26
- * THIS project's files, and a read tool that wanders is a read tool nobody can reason about. */
27
- function insideCwd(cwd: string, p: string): string | null {
28
- const abs = isAbsolute(p) ? resolve(p) : resolve(cwd, p);
29
- const rel = relative(resolve(cwd), abs);
30
- return rel === "" || rel.startsWith("..") || isAbsolute(rel) ? null : abs;
31
- }
32
-
33
- export function designAuditTool(): Tool {
34
- return {
35
- schema: {
36
- name: "design_audit",
37
- description:
38
- "Check interface code for the patterns that arrive when nobody decided (a webfont loaded without a choice, amber doing accent duty, the three-up feature grid, a centred full-viewport hero, the violet-to-blue gradient, nothing but square corners) and for drift from the direction this project recorded in .rovecode/design.json. Run it on the SOURCE TREE, not on a fetched page: a built page measures the framework's output, not the design. Pass the page files you touched along with the components they import, because density and centring are scored per page and 'no rounded corner anywhere' is scored per project. It reports evidence, not verdicts: each finding says what it counted, so you can fix it or explain why it is wrong here. Never prompts, never writes.",
39
- args: {
40
- type: "object",
41
- properties: {
42
- files: { type: "array", items: { type: "string" }, description: "paths inside the project to audit (html/css/jsx/tsx/vue/svelte)" },
43
- source: { type: "string", description: "audit this markup/CSS directly instead of reading files" },
44
- ignore: { type: "array", items: { type: "string" }, description: "rule ids to skip (the full table is in docs/design.md): cliche-font, font-deviation, font-named-not-loaded, cliche-accent-amber, accent-deviation, template-grid, template-icons, reflex-hero, cliche-gradient, off-palette, decoration-density, rule-line-density, everything-centered, all-square" },
45
- },
46
- },
47
- },
48
- kind: "read",
49
- sequential: false,
50
- async execute(args, ctx): Promise<ToolOutput> {
51
- const a = (args && typeof args === "object" ? args : {}) as { files?: string[]; source?: string; ignore?: string[] };
52
- const direction = loadDirection(ctx.cwd);
53
- const ignore = a.ignore ?? [];
54
- const findings: Finding[] = [];
55
-
56
- // `source` is one pathless page: auditProject treats a lone file as a page so pasted markup still
57
- // gets the page-scoped density and centring checks (auditSource alone is file-scope by design).
58
- if (typeof a.source === "string" && a.source.length > 0) {
59
- findings.push(...auditProject([{ path: "source", text: a.source }], { direction, ignore }));
60
- }
61
- const paths = a.files ?? [];
62
- if (paths.length > 0) {
63
- const resolved: string[] = [];
64
- const outside: string[] = [];
65
- for (const p of paths) {
66
- const abs = insideCwd(ctx.cwd, p);
67
- if (abs === null) outside.push(p); else resolved.push(abs);
68
- }
69
- if (outside.length > 0) {
70
- return { ok: false, output: `design_audit only reads files inside the project. Outside: ${outside.join(", ")}` };
71
- }
72
- findings.push(...auditFiles(resolved, { direction, ignore }).map((f) => ({
73
- ...f, ...(f.file !== undefined ? { file: relative(resolve(ctx.cwd), f.file) || f.file } : {}),
74
- })));
75
- }
76
- if (paths.length === 0 && (a.source === undefined || a.source.length === 0)) {
77
- return { ok: false, output: "design_audit needs `files` (paths inside the project) or `source` (markup/CSS text)." };
78
- }
79
- return { ok: true, output: formatFindings(findings, direction), data: { findings, direction } };
80
- },
81
- };
82
- }
83
-
84
- export function designDirectionTool(): Tool {
85
- return {
86
- schema: {
87
- name: "design_direction",
88
- description:
89
- "Read or record this project's design direction (.rovecode/design.json). `get` returns the recorded direction, or says none is recorded. `set` records the direction THE HUMAN CHOSE after you proposed three — do not call it with a direction you picked yourself. The one exception is a headless run where nothing can ask a human: then build ONE direction and record it with provisional:true and the other two in `alternatives`, so the next interactive session asks before more UI is built. Recording it is what makes the choice a once-per-project question and lets design_audit check later screens for consistency.",
90
- args: {
91
- type: "object",
92
- properties: {
93
- action: { type: "string", enum: ["get", "set"] },
94
- name: { type: "string", description: "short name of the chosen direction, as presented to the human" },
95
- rationale: { type: "string", description: "one line: why it suits this product" },
96
- palette: { type: "object", description: "chosen colours, e.g. {\"ink\":\"#0b1a2e\",\"accent\":\"#c2410c\"}" },
97
- typeface: { type: "object", description: "{\"display\":\"...\",\"text\":\"...\"}" },
98
- corners: { type: "string", enum: ["sharp", "soft", "round"] },
99
- layout: { type: "string", enum: ["centered", "left", "asymmetric", "grid"] },
100
- density: { type: "string", enum: ["tight", "regular", "airy"] },
101
- sectionOrder: { type: "array", items: { type: "string" }, description: "the page's blocks in order, e.g. [\"hero\",\"proof\",\"pricing\",\"faq\"]" },
102
- heroPattern: { type: "string", description: "the hero pattern by name, e.g. \"command-first\" or \"product-forward\"" },
103
- typeScale: { type: "array", items: { type: "number" }, description: "the chosen type steps, e.g. [14,16,20,28,44]" },
104
- motion: { type: "string", description: "the motion rule in the human's words, e.g. \"one entrance per section, no loops\"" },
105
- copyRegister: { type: "string", description: "how the copy reads, e.g. \"technical, names and numbers, no marketing verbs\"" },
106
- notes: { type: "string", description: "what the audit cannot infer: imagery, what to avoid here" },
107
- provisional: { type: "boolean", description: "true ONLY when no human could be asked (a headless run): you built to one direction to get unblocked. Never true when a human answered." },
108
- alternatives: { type: "array", items: { type: "string" }, description: "with provisional: the names of the directions you did NOT build, so the next interactive session can offer them" },
109
- },
110
- required: ["action"],
111
- },
112
- },
113
- kind: "custom",
114
- sequential: true,
115
- // `get` reads .rovecode/design.json and writes nothing; `set` records the project's design
116
- // identity. Only the second is worth a human's attention, so the two get their own policy
117
- // resource (types.ts Tool.resource) instead of sharing one rule under the tool name. Anything
118
- // that is not the literal "get" is treated as the write: an unknown action must not read as
119
- // the safer of the two.
120
- resource(args: unknown): string {
121
- const a = args && typeof args === "object" ? (args as Record<string, unknown>) : undefined;
122
- return a?.["action"] === "get" ? "get" : "set";
123
- },
124
- async execute(args, ctx): Promise<ToolOutput> {
125
- const a = (args && typeof args === "object" ? args : {}) as Record<string, unknown>;
126
- if (a["action"] === "get") {
127
- const d = loadDirection(ctx.cwd);
128
- return d === null
129
- ? { ok: true, output: `No design direction recorded for this project (${designPath(ctx.cwd)} does not exist). Propose three distinct directions and let the human choose before writing UI. If nothing here can ask a human, build ONE and record it with provisional: true.` }
130
- : { ok: true, output: renderDirection(d), data: d };
131
- }
132
- if (a["action"] !== "set") return { ok: false, output: "design_direction: action must be \"get\" or \"set\"." };
133
-
134
- const parsed: DesignDirection | null = parseDirection(a);
135
- if (parsed === null) {
136
- return { ok: false, output: "design_direction set needs at least `name` — the short name of the direction the human chose." };
137
- }
138
- // Who chose is DERIVED, never taken from the call: `provisional` means the agent picked, its
139
- // absence means a human did. Trusting the model with both fields lets one contradict the other,
140
- // and the whole point of the field is that it can be believed. Stamped on every write, so a
141
- // record always says who — absent is only ever a file written before the field existed.
142
- parsed.chosenBy = parsed.provisional === true ? "agent" : "human";
143
- const path = saveDirection(ctx.cwd, parsed);
144
- if (parsed.provisional === true) {
145
- const alts = parsed.alternatives === undefined ? "" : ` The alternatives (${parsed.alternatives.join(", ")}) are recorded with it.`;
146
- return { ok: true, output: `Recorded "${parsed.name}" in ${path} as PROVISIONAL — you chose it, not the human.${alts} Build to it and say so in your final summary, naming what you did not build. The next interactive session asks before more UI is written.`, data: parsed };
147
- }
148
- return { ok: true, output: `Recorded "${parsed.name}" in ${path}. Later UI in this project is built to it, and design_audit checks against it.`, data: parsed };
149
- },
150
- };
151
- }