@akira-tl/forgerelay 0.1.0

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 (373) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/LICENSE +22 -0
  3. package/NOTICE.md +19 -0
  4. package/README.md +270 -0
  5. package/dist/apply-patch.js +402 -0
  6. package/dist/artifact-error.js +8 -0
  7. package/dist/artifact-tools.js +377 -0
  8. package/dist/cli.js +597 -0
  9. package/dist/config.js +224 -0
  10. package/dist/db/client.js +29 -0
  11. package/dist/db/migrations.js +189 -0
  12. package/dist/db/schema.js +85 -0
  13. package/dist/git-worktrees.js +255 -0
  14. package/dist/git.js +41 -0
  15. package/dist/incoming-artifacts.js +378 -0
  16. package/dist/local-agent-adapters.js +653 -0
  17. package/dist/local-agent-availability.js +119 -0
  18. package/dist/local-agent-path.js +25 -0
  19. package/dist/local-agent-profiles.js +136 -0
  20. package/dist/local-agent-runtime.js +48 -0
  21. package/dist/local-agent-store.js +145 -0
  22. package/dist/local-agent-targets.js +80 -0
  23. package/dist/logger.js +69 -0
  24. package/dist/mcp/server-instructions.js +78 -0
  25. package/dist/mcp-sessions.js +56 -0
  26. package/dist/oauth-provider.js +237 -0
  27. package/dist/oauth-store.js +138 -0
  28. package/dist/pi-tools.js +81 -0
  29. package/dist/process-platform.js +49 -0
  30. package/dist/process-sessions.js +337 -0
  31. package/dist/request-meta.js +9 -0
  32. package/dist/review-checkpoints.js +219 -0
  33. package/dist/roots.js +37 -0
  34. package/dist/server-shutdown.js +12 -0
  35. package/dist/server.js +1596 -0
  36. package/dist/skills.js +89 -0
  37. package/dist/ui/.vite/manifest.json +2521 -0
  38. package/dist/ui/assets/abap-CLvhMVsD.js +1 -0
  39. package/dist/ui/assets/actionscript-3--17pq3dv.js +1 -0
  40. package/dist/ui/assets/ada-C5qYipkI.js +1 -0
  41. package/dist/ui/assets/andromeeda-vGVdxbeo.js +1 -0
  42. package/dist/ui/assets/angular-html-CovppXt5.js +1 -0
  43. package/dist/ui/assets/angular-ts-0Y9l6YXu.js +1 -0
  44. package/dist/ui/assets/apache-U0d_L8uA.js +1 -0
  45. package/dist/ui/assets/apex-CGTLDQj6.js +1 -0
  46. package/dist/ui/assets/apl-BmBhiklA.js +1 -0
  47. package/dist/ui/assets/applescript-CCn79oCD.js +1 -0
  48. package/dist/ui/assets/ara-4CJ0cIlV.js +1 -0
  49. package/dist/ui/assets/asciidoc-DE70LPWp.js +1 -0
  50. package/dist/ui/assets/asm-Cmm7eHzH.js +1 -0
  51. package/dist/ui/assets/astro-BAmqcqyV.js +1 -0
  52. package/dist/ui/assets/aurora-x-CDeNXAV0.js +1 -0
  53. package/dist/ui/assets/awk-BWXHIvNe.js +1 -0
  54. package/dist/ui/assets/ayu-dark-DluEY0Gj.js +1 -0
  55. package/dist/ui/assets/ayu-light-C3h-C4tm.js +1 -0
  56. package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +1 -0
  57. package/dist/ui/assets/ballerina-B7ZEbQpA.js +1 -0
  58. package/dist/ui/assets/bat-Bo4NYOV-.js +1 -0
  59. package/dist/ui/assets/beancount-D-usSTwE.js +1 -0
  60. package/dist/ui/assets/berry-DKpUyyne.js +1 -0
  61. package/dist/ui/assets/bibtex-Ci_nEsc7.js +1 -0
  62. package/dist/ui/assets/bicep-CUHmPFLl.js +1 -0
  63. package/dist/ui/assets/bird2-C2hNVINV.js +1 -0
  64. package/dist/ui/assets/blade-BjFcmRJo.js +1 -0
  65. package/dist/ui/assets/bsl-BkkzgIyY.js +1 -0
  66. package/dist/ui/assets/c-CaOJn4x0.js +1 -0
  67. package/dist/ui/assets/c3-CnJL0r0V.js +1 -0
  68. package/dist/ui/assets/cadence-CQ2zXKGN.js +1 -0
  69. package/dist/ui/assets/cairo-DLTphjLi.js +1 -0
  70. package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
  71. package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
  72. package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
  73. package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
  74. package/dist/ui/assets/clarity-SemFz856.js +1 -0
  75. package/dist/ui/assets/clojure-DqKBuwfJ.js +1 -0
  76. package/dist/ui/assets/cmake-Bj61d0ZC.js +1 -0
  77. package/dist/ui/assets/cobol-DR4zWFMt.js +1 -0
  78. package/dist/ui/assets/codeowners-C8r90Shi.js +1 -0
  79. package/dist/ui/assets/codeql-oeQT6MSM.js +1 -0
  80. package/dist/ui/assets/coffee-ReGSThmM.js +1 -0
  81. package/dist/ui/assets/common-lisp-Cv5bFMCO.js +1 -0
  82. package/dist/ui/assets/coq-BrsZFFmf.js +1 -0
  83. package/dist/ui/assets/cpp-CnlQh6MO.js +1 -0
  84. package/dist/ui/assets/crystal-BrpPbH1U.js +1 -0
  85. package/dist/ui/assets/csharp-Ct8U2NOr.js +1 -0
  86. package/dist/ui/assets/css-DRBEvyPU.js +1 -0
  87. package/dist/ui/assets/csv-Dx-8-gkx.js +1 -0
  88. package/dist/ui/assets/cue-CE9AQfxI.js +1 -0
  89. package/dist/ui/assets/cypher-ClKdZ_lG.js +1 -0
  90. package/dist/ui/assets/d-qD-0Kul2.js +1 -0
  91. package/dist/ui/assets/dark-plus-Cs2F2srj.js +1 -0
  92. package/dist/ui/assets/dart-DkHntEIa.js +1 -0
  93. package/dist/ui/assets/dax-BkyTk9wS.js +1 -0
  94. package/dist/ui/assets/desktop-Dlh5hvp9.js +1 -0
  95. package/dist/ui/assets/diff-woXpYk--.js +1 -0
  96. package/dist/ui/assets/docker-IyjqRm3v.js +1 -0
  97. package/dist/ui/assets/dotenv-_5a1GRtc.js +1 -0
  98. package/dist/ui/assets/dracula-BHWKrbxM.js +1 -0
  99. package/dist/ui/assets/dracula-soft-5eyTD99u.js +1 -0
  100. package/dist/ui/assets/dream-maker-DW3nJb8Q.js +1 -0
  101. package/dist/ui/assets/edge-cfwpdvl9.js +1 -0
  102. package/dist/ui/assets/elixir-7owrJxb6.js +1 -0
  103. package/dist/ui/assets/elm-udiOjODk.js +1 -0
  104. package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +1 -0
  105. package/dist/ui/assets/erb-8ctXHMkS.js +1 -0
  106. package/dist/ui/assets/erlang-Cphh6RMH.js +1 -0
  107. package/dist/ui/assets/everforest-dark-sB-x3p7T.js +1 -0
  108. package/dist/ui/assets/everforest-light-Df2xbC6M.js +1 -0
  109. package/dist/ui/assets/fennel-DQxkIbk2.js +1 -0
  110. package/dist/ui/assets/fish-BJitypiv.js +1 -0
  111. package/dist/ui/assets/fluent-C03EYrpw.js +1 -0
  112. package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
  113. package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +1 -0
  114. package/dist/ui/assets/fsharp-D13ZGOAj.js +1 -0
  115. package/dist/ui/assets/gdresource-C0sCabJj.js +1 -0
  116. package/dist/ui/assets/gdscript-Cp2uCuqX.js +1 -0
  117. package/dist/ui/assets/gdshader-CBce3t8t.js +1 -0
  118. package/dist/ui/assets/genie-CV2tkWYe.js +1 -0
  119. package/dist/ui/assets/gherkin-DExj1W_8.js +1 -0
  120. package/dist/ui/assets/git-commit-BSykSTBG.js +1 -0
  121. package/dist/ui/assets/git-rebase-P0V_qK1w.js +1 -0
  122. package/dist/ui/assets/github-dark-C-LZuMrd.js +1 -0
  123. package/dist/ui/assets/github-dark-default-DXG-b-1a.js +1 -0
  124. package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
  125. package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
  126. package/dist/ui/assets/github-light-EUqPIrTm.js +1 -0
  127. package/dist/ui/assets/github-light-default-BXViO-2h.js +1 -0
  128. package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +1 -0
  129. package/dist/ui/assets/gleam-CSRkHgEL.js +1 -0
  130. package/dist/ui/assets/glimmer-js-CZ14ED7U.js +1 -0
  131. package/dist/ui/assets/glimmer-ts-DtBSFP-o.js +1 -0
  132. package/dist/ui/assets/glsl-BX2BkZJK.js +1 -0
  133. package/dist/ui/assets/gn-ilITqXS6.js +1 -0
  134. package/dist/ui/assets/gnuplot-7GGW24-e.js +1 -0
  135. package/dist/ui/assets/go-BJwz_mda.js +1 -0
  136. package/dist/ui/assets/graphql-Dj_cPv4w.js +1 -0
  137. package/dist/ui/assets/groovy-CacY0gHj.js +1 -0
  138. package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
  139. package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
  140. package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  141. package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
  142. package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
  143. package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
  144. package/dist/ui/assets/hack-DGRkd8xn.js +1 -0
  145. package/dist/ui/assets/haml-BAPSvujW.js +1 -0
  146. package/dist/ui/assets/handlebars-PYksdULG.js +1 -0
  147. package/dist/ui/assets/haskell-D8IpX4py.js +1 -0
  148. package/dist/ui/assets/haxe-OTjmBuCE.js +1 -0
  149. package/dist/ui/assets/hcl-Dh228itO.js +1 -0
  150. package/dist/ui/assets/heavy-payload-BjE0LSUi.js +4 -0
  151. package/dist/ui/assets/hjson-CxZEssPk.js +1 -0
  152. package/dist/ui/assets/hlsl-Cvrh5tZx.js +1 -0
  153. package/dist/ui/assets/horizon-CE9ld1lL.js +1 -0
  154. package/dist/ui/assets/horizon-bright-Br1oVSNq.js +1 -0
  155. package/dist/ui/assets/houston-CsvMBhTu.js +1 -0
  156. package/dist/ui/assets/html-DloAPGZ1.js +1 -0
  157. package/dist/ui/assets/html-derivative-C6q86ZrS.js +1 -0
  158. package/dist/ui/assets/http-fPvYDvHA.js +1 -0
  159. package/dist/ui/assets/hurl-Dbir4WvE.js +1 -0
  160. package/dist/ui/assets/hxml-B0Qn7Nwc.js +1 -0
  161. package/dist/ui/assets/hy-CZbG8q4J.js +1 -0
  162. package/dist/ui/assets/imba-DsUTQ-LC.js +1 -0
  163. package/dist/ui/assets/ini-B5eOa1yu.js +1 -0
  164. package/dist/ui/assets/java-DvkqXg3z.js +1 -0
  165. package/dist/ui/assets/javascript-TONTV6Ty.js +1 -0
  166. package/dist/ui/assets/jinja-OM1F5Gct.js +1 -0
  167. package/dist/ui/assets/jison-CBttugts.js +1 -0
  168. package/dist/ui/assets/json-Db5oY-7J.js +1 -0
  169. package/dist/ui/assets/json5-BR5RXkoi.js +1 -0
  170. package/dist/ui/assets/jsonc-CYpm1nAK.js +1 -0
  171. package/dist/ui/assets/jsonl-CmCQp5Yx.js +1 -0
  172. package/dist/ui/assets/jsonnet-CJTPZ8u_.js +1 -0
  173. package/dist/ui/assets/jssm-DXw9l8Rf.js +1 -0
  174. package/dist/ui/assets/jsx-DKeJCgsc.js +1 -0
  175. package/dist/ui/assets/julia-NlIPhXaL.js +1 -0
  176. package/dist/ui/assets/just-BXBJB-mX.js +1 -0
  177. package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
  178. package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +1 -0
  179. package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +1 -0
  180. package/dist/ui/assets/kdl-CsD5j6eV.js +1 -0
  181. package/dist/ui/assets/kotlin-DhhofPvG.js +1 -0
  182. package/dist/ui/assets/kusto-BUv0MjJC.js +1 -0
  183. package/dist/ui/assets/laserwave-C_8bwKvT.js +1 -0
  184. package/dist/ui/assets/latex-CGK-6yDy.js +1 -0
  185. package/dist/ui/assets/lean-CewbzKMR.js +1 -0
  186. package/dist/ui/assets/less-DVTAwKKz.js +1 -0
  187. package/dist/ui/assets/light-plus-DVQuIRkW.js +1 -0
  188. package/dist/ui/assets/liquid-D7waQ0MY.js +1 -0
  189. package/dist/ui/assets/llvm-Cm23YOpf.js +1 -0
  190. package/dist/ui/assets/log-BNLmms1o.js +1 -0
  191. package/dist/ui/assets/logo-Cluzi2Zq.js +1 -0
  192. package/dist/ui/assets/lua-C_kkt4h1.js +1 -0
  193. package/dist/ui/assets/luau-CNKltnaQ.js +1 -0
  194. package/dist/ui/assets/make-Dixweg8N.js +1 -0
  195. package/dist/ui/assets/markdown-BYOwaDjH.js +1 -0
  196. package/dist/ui/assets/marko-BokXuCts.js +1 -0
  197. package/dist/ui/assets/material-theme-Bm3Qr25_.js +1 -0
  198. package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +1 -0
  199. package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +1 -0
  200. package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +1 -0
  201. package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +1 -0
  202. package/dist/ui/assets/matlab-D7qyCx1q.js +1 -0
  203. package/dist/ui/assets/mdc-Bk0nnUJA.js +1 -0
  204. package/dist/ui/assets/mdx-DQZ5AkYe.js +1 -0
  205. package/dist/ui/assets/mermaid-Bk4SNUv9.js +1 -0
  206. package/dist/ui/assets/min-dark-BSWPekZh.js +1 -0
  207. package/dist/ui/assets/min-light-DDpmG2fV.js +1 -0
  208. package/dist/ui/assets/mipsasm-BMqwQI7S.js +1 -0
  209. package/dist/ui/assets/mojo-BgCJLMeH.js +1 -0
  210. package/dist/ui/assets/monokai-CdkpiU2Y.js +1 -0
  211. package/dist/ui/assets/moonbit-CaWjb8XO.js +1 -0
  212. package/dist/ui/assets/move-B1IS1UjX.js +1 -0
  213. package/dist/ui/assets/narrat-_X_XdTYD.js +1 -0
  214. package/dist/ui/assets/nextflow-Bbiyy34d.js +1 -0
  215. package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +1 -0
  216. package/dist/ui/assets/nginx-jM6NF9TV.js +1 -0
  217. package/dist/ui/assets/night-owl-DhmEMT88.js +1 -0
  218. package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +1 -0
  219. package/dist/ui/assets/nim-hYsL-WKb.js +1 -0
  220. package/dist/ui/assets/nix-IvuFDN5E.js +1 -0
  221. package/dist/ui/assets/nord-Cb4Vim4T.js +1 -0
  222. package/dist/ui/assets/nushell-DcLAeLz5.js +1 -0
  223. package/dist/ui/assets/objective-c-D1A_Heim.js +1 -0
  224. package/dist/ui/assets/objective-cpp-BsSzOQcm.js +1 -0
  225. package/dist/ui/assets/ocaml-O90oeIOV.js +1 -0
  226. package/dist/ui/assets/odin-B1RWQWA5.js +1 -0
  227. package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +1 -0
  228. package/dist/ui/assets/one-light-D7Lr4KcI.js +1 -0
  229. package/dist/ui/assets/openscad-BUDT5pXO.js +1 -0
  230. package/dist/ui/assets/pascal-4ZHwLPI5.js +1 -0
  231. package/dist/ui/assets/perl-DBI_cUHJ.js +1 -0
  232. package/dist/ui/assets/php-BX_aQhFl.js +1 -0
  233. package/dist/ui/assets/pierre-dark-sU4Zdns8.js +1 -0
  234. package/dist/ui/assets/pierre-dark-soft-HXgun5vs.js +1 -0
  235. package/dist/ui/assets/pierre-light-DWBk51d8.js +1 -0
  236. package/dist/ui/assets/pierre-light-soft-CodEzPxf.js +1 -0
  237. package/dist/ui/assets/pkl-ot-7Btpt.js +1 -0
  238. package/dist/ui/assets/plastic-DQwYfKfQ.js +1 -0
  239. package/dist/ui/assets/plsql-DGHpHOYJ.js +1 -0
  240. package/dist/ui/assets/po-BiJDBrnU.js +1 -0
  241. package/dist/ui/assets/poimandres-DRFjx7u4.js +1 -0
  242. package/dist/ui/assets/polar-C7UOKdEL.js +1 -0
  243. package/dist/ui/assets/postcss-BXeXVLqQ.js +1 -0
  244. package/dist/ui/assets/powerquery-DNMTfnFr.js +1 -0
  245. package/dist/ui/assets/powershell-DshXNtvi.js +1 -0
  246. package/dist/ui/assets/prisma-BsRQq5mF.js +1 -0
  247. package/dist/ui/assets/prolog-iXnhIJG7.js +1 -0
  248. package/dist/ui/assets/proto-DB4EqR-F.js +1 -0
  249. package/dist/ui/assets/pug-DwFAYy1e.js +1 -0
  250. package/dist/ui/assets/puppet-CDv2pdJW.js +1 -0
  251. package/dist/ui/assets/purescript-9MfHhQsQ.js +1 -0
  252. package/dist/ui/assets/python-gzcpVVnB.js +1 -0
  253. package/dist/ui/assets/qml-eLSwQUKt.js +1 -0
  254. package/dist/ui/assets/qmldir-DCQb3MpD.js +1 -0
  255. package/dist/ui/assets/qss-Fe1Jh2GI.js +1 -0
  256. package/dist/ui/assets/r-BMnQsMLf.js +1 -0
  257. package/dist/ui/assets/racket-DcIDlBhZ.js +1 -0
  258. package/dist/ui/assets/raku-B3gFvitq.js +1 -0
  259. package/dist/ui/assets/razor-CgciiMyw.js +1 -0
  260. package/dist/ui/assets/red-CJ3rzSJv.js +1 -0
  261. package/dist/ui/assets/reg-CRGYupPL.js +1 -0
  262. package/dist/ui/assets/regexp-ZrURNrn5.js +1 -0
  263. package/dist/ui/assets/rel-BtDbiS_P.js +1 -0
  264. package/dist/ui/assets/review-payload-HGkpJjjm.js +1 -0
  265. package/dist/ui/assets/riscv-Ckw8ddFX.js +1 -0
  266. package/dist/ui/assets/ron-VUp2lXgN.js +1 -0
  267. package/dist/ui/assets/rose-pine-BthvhNj6.js +1 -0
  268. package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
  269. package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +1 -0
  270. package/dist/ui/assets/rosmsg-CAekHB0j.js +1 -0
  271. package/dist/ui/assets/rst-EoAOr3M6.js +1 -0
  272. package/dist/ui/assets/ruby-Dqx5_Rqw.js +1 -0
  273. package/dist/ui/assets/rust-Cfkwpbl8.js +1 -0
  274. package/dist/ui/assets/sas-Bf6xPLSX.js +1 -0
  275. package/dist/ui/assets/sass-DXrisJhu.js +1 -0
  276. package/dist/ui/assets/scala-DKOlJaKm.js +1 -0
  277. package/dist/ui/assets/scheme-DQCgrYNe.js +1 -0
  278. package/dist/ui/assets/scrollbar-DX4Ujotb.js +287 -0
  279. package/dist/ui/assets/scss-DDpW3yTd.js +1 -0
  280. package/dist/ui/assets/sdbl-bTVj8UrX.js +1 -0
  281. package/dist/ui/assets/shaderlab-TOUzSsQk.js +1 -0
  282. package/dist/ui/assets/shellscript-DayAQ-W9.js +1 -0
  283. package/dist/ui/assets/shellsession-jPr_lSnA.js +1 -0
  284. package/dist/ui/assets/slack-dark-DnToyrRv.js +1 -0
  285. package/dist/ui/assets/slack-ochin-B2OO5cIa.js +1 -0
  286. package/dist/ui/assets/smalltalk-B16xEiuN.js +1 -0
  287. package/dist/ui/assets/snazzy-light-4G7pJPwS.js +1 -0
  288. package/dist/ui/assets/solarized-dark-DV17i1UV.js +1 -0
  289. package/dist/ui/assets/solarized-light-DSh2HLQt.js +1 -0
  290. package/dist/ui/assets/solidity-CKzVLygQ.js +1 -0
  291. package/dist/ui/assets/soy-X9adks8G.js +1 -0
  292. package/dist/ui/assets/sparql-D_iOobhT.js +1 -0
  293. package/dist/ui/assets/splunk-BC2Px7Mm.js +1 -0
  294. package/dist/ui/assets/sql-Bmt09AIR.js +1 -0
  295. package/dist/ui/assets/ssh-config-BgfXC-Er.js +1 -0
  296. package/dist/ui/assets/stata-DVkNpH8r.js +1 -0
  297. package/dist/ui/assets/stylus-B6D30XZt.js +1 -0
  298. package/dist/ui/assets/surrealql-eEXzMb8j.js +1 -0
  299. package/dist/ui/assets/svelte-CFoBxZF3.js +1 -0
  300. package/dist/ui/assets/swift-DonLKvLd.js +1 -0
  301. package/dist/ui/assets/synthwave-84-nFMaYfgc.js +1 -0
  302. package/dist/ui/assets/system-verilog-DJ5XKQeo.js +1 -0
  303. package/dist/ui/assets/systemd-BxMlprV5.js +1 -0
  304. package/dist/ui/assets/talonscript-CohzipZa.js +1 -0
  305. package/dist/ui/assets/tasl-DMoTqEGO.js +1 -0
  306. package/dist/ui/assets/tcl-CZd0xW_V.js +1 -0
  307. package/dist/ui/assets/templ-Da_324JF.js +1 -0
  308. package/dist/ui/assets/terraform-DswuEJGm.js +1 -0
  309. package/dist/ui/assets/tex-HAzlmKJ0.js +1 -0
  310. package/dist/ui/assets/tokyo-night-oM2G3aXe.js +1 -0
  311. package/dist/ui/assets/toml-CcmNWLt0.js +1 -0
  312. package/dist/ui/assets/ts-tags-7iLrNH8p.js +1 -0
  313. package/dist/ui/assets/tsv-sltzmVWM.js +1 -0
  314. package/dist/ui/assets/tsx-gZaXf8PJ.js +1 -0
  315. package/dist/ui/assets/turtle-ByJddavk.js +1 -0
  316. package/dist/ui/assets/twig-CLpQ7p1N.js +1 -0
  317. package/dist/ui/assets/typescript-B2WWCRI2.js +1 -0
  318. package/dist/ui/assets/typespec-B88KGewJ.js +1 -0
  319. package/dist/ui/assets/typst-DI99ib-x.js +1 -0
  320. package/dist/ui/assets/v-DETTlOr0.js +1 -0
  321. package/dist/ui/assets/vala-zf12oZj6.js +1 -0
  322. package/dist/ui/assets/vb-Djn5o6TS.js +1 -0
  323. package/dist/ui/assets/verilog-CiiDBU1e.js +1 -0
  324. package/dist/ui/assets/vesper-D5bVUKB1.js +1 -0
  325. package/dist/ui/assets/vhdl-BroJfC0k.js +1 -0
  326. package/dist/ui/assets/viml-DvXPmvsu.js +1 -0
  327. package/dist/ui/assets/vitesse-black-fwtXNY1n.js +1 -0
  328. package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +1 -0
  329. package/dist/ui/assets/vitesse-light-VbXTXTou.js +1 -0
  330. package/dist/ui/assets/vue-No_8Jygd.js +1 -0
  331. package/dist/ui/assets/vue-html-kHJg98Kk.js +1 -0
  332. package/dist/ui/assets/vue-vine-Df4cEYaN.js +1 -0
  333. package/dist/ui/assets/vyper-CgoNMtux.js +1 -0
  334. package/dist/ui/assets/wasm-BnjxR4X6.js +1 -0
  335. package/dist/ui/assets/wasm-ByWQv1Qj.js +1 -0
  336. package/dist/ui/assets/wenyan-C8pVoKbM.js +1 -0
  337. package/dist/ui/assets/wgsl-BsKzXJz4.js +1 -0
  338. package/dist/ui/assets/wikitext-ClFFjSW2.js +1 -0
  339. package/dist/ui/assets/wit-DdvCle-K.js +1 -0
  340. package/dist/ui/assets/wolfram-DLL8P-h_.js +1 -0
  341. package/dist/ui/assets/workspace-app-C_wsC6VL.js +117 -0
  342. package/dist/ui/assets/workspace-app-DHvE2ojW.css +1 -0
  343. package/dist/ui/assets/xml-DUZ05dpG.js +1 -0
  344. package/dist/ui/assets/xsl-Bwp3w2OF.js +1 -0
  345. package/dist/ui/assets/yaml-IA_-TEM1.js +1 -0
  346. package/dist/ui/assets/zenscript-BnlCZFoB.js +1 -0
  347. package/dist/ui/assets/zig-CMLA9XwU.js +1 -0
  348. package/dist/ui/workspace-app.html +15 -0
  349. package/dist/user-config.js +97 -0
  350. package/dist/workspace-store.js +162 -0
  351. package/dist/workspaces.js +528 -0
  352. package/docs/agent-profile-schema.md +119 -0
  353. package/docs/artifact-exchange.md +63 -0
  354. package/docs/chatgpt-coding-workflow.md +183 -0
  355. package/docs/configuration.md +197 -0
  356. package/docs/gotchas.md +243 -0
  357. package/docs/roadmap.md +195 -0
  358. package/docs/security.md +142 -0
  359. package/docs/setup.md +132 -0
  360. package/docs/versioning.md +189 -0
  361. package/examples/agents/claude-implementer.md +30 -0
  362. package/examples/agents/codex-explorer.md +27 -0
  363. package/examples/agents/codex-qa-tester.md +29 -0
  364. package/examples/agents/codex-worker.md +25 -0
  365. package/examples/agents/copilot-reviewer.md +25 -0
  366. package/examples/agents/cursor-agent-worker.md +26 -0
  367. package/examples/agents/opencode-explorer.md +27 -0
  368. package/examples/agents/pi-reviewer.md +27 -0
  369. package/package.json +102 -0
  370. package/scripts/dev-server.mjs +120 -0
  371. package/scripts/fix-node-pty-permissions.mjs +22 -0
  372. package/scripts/release-version.mjs +207 -0
  373. package/skills/subagent-delegation/SKILL.md +132 -0
package/dist/cli.js ADDED
@@ -0,0 +1,597 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ import { stdin as input, stdout as output } from "node:process";
4
+ import { spawn } from "node:child_process";
5
+ import { mkdtempSync, writeFileSync } from "node:fs";
6
+ import { readFile } from "node:fs/promises";
7
+ import { tmpdir } from "node:os";
8
+ import { join, resolve } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import * as prompts from "@clack/prompts";
11
+ import { getShellConfig } from "@earendil-works/pi-coding-agent";
12
+ import { satisfies } from "semver";
13
+ import { loadConfig } from "./config.js";
14
+ import { runLocalAgentProvider } from "./local-agent-adapters.js";
15
+ import { isLocalAgentProvider, loadLocalAgentProfiles, } from "./local-agent-profiles.js";
16
+ import { assertLocalAgentProviderAvailable, formatLocalAgentProviderAvailabilitySummary, } from "./local-agent-availability.js";
17
+ import { formatAvailableLocalAgentTargets, parseLocalAgentRunArgs, resolveLocalAgentTarget, } from "./local-agent-targets.js";
18
+ import { createLocalAgentStore } from "./local-agent-store.js";
19
+ import { ensureDevspaceDefaultSkills, generateOwnerToken, loadDevspaceFiles, resolveSubagentsFlag, writeDevspaceAuth, writeDevspaceConfig, } from "./user-config.js";
20
+ import { expandHomePath } from "./roots.js";
21
+ import { shutdownHttpServer } from "./server-shutdown.js";
22
+ const require = createRequire(import.meta.url);
23
+ const SUPPORTED_NODE_RANGE = ">=20.12 <27";
24
+ async function main(argv) {
25
+ assertSupportedNode();
26
+ const [rawCommand, ...args] = argv;
27
+ const command = normalizeCommand(rawCommand);
28
+ switch (command) {
29
+ case "serve":
30
+ await ensureConfigured();
31
+ await serve();
32
+ return;
33
+ case "init":
34
+ await runInit({ force: args.includes("--force") });
35
+ return;
36
+ case "doctor":
37
+ await runDoctor();
38
+ return;
39
+ case "config":
40
+ runConfigCommand(args);
41
+ return;
42
+ case "agents":
43
+ await runAgentsCommand(args);
44
+ return;
45
+ case "help":
46
+ printHelp();
47
+ return;
48
+ case "version":
49
+ printVersion();
50
+ return;
51
+ }
52
+ }
53
+ function normalizeCommand(command) {
54
+ if (!command || command === "serve" || command === "start")
55
+ return "serve";
56
+ if (command === "init" || command === "doctor" || command === "config" || command === "agents")
57
+ return command;
58
+ if (command === "help" || command === "--help" || command === "-h")
59
+ return "help";
60
+ if (command === "version" || command === "--version" || command === "-v")
61
+ return "version";
62
+ throw new Error(`Unknown command: ${command}`);
63
+ }
64
+ async function ensureConfigured() {
65
+ const files = loadDevspaceFiles();
66
+ if (files.configExists && files.authExists)
67
+ return;
68
+ if (process.env.FORGERELAY_OAUTH_OWNER_TOKEN ?? process.env.DEVSPACE_OAUTH_OWNER_TOKEN)
69
+ return;
70
+ if (!input.isTTY || !output.isTTY) {
71
+ throw new Error([
72
+ "ForgeRelay is not configured and this terminal is non-interactive.",
73
+ "",
74
+ "Run:",
75
+ " forgerelay init",
76
+ "",
77
+ "Or provide FORGERELAY_OAUTH_OWNER_TOKEN and FORGERELAY_ALLOWED_ROOTS.",
78
+ ].join("\n"));
79
+ }
80
+ await runInit({ force: false });
81
+ }
82
+ async function runInit({ force }) {
83
+ const files = loadDevspaceFiles();
84
+ if (!force && files.configExists && files.authExists) {
85
+ prompts.log.info(`ForgeRelay is already configured at ${files.dir}`);
86
+ prompts.log.info("Run `forgerelay init --force` to update it.");
87
+ return;
88
+ }
89
+ try {
90
+ prompts.intro("ForgeRelay setup");
91
+ const defaultRoots = files.config.allowedRoots?.join(", ") || process.cwd();
92
+ const rootsAnswer = await textPrompt({
93
+ message: `Where are your projects located? Press Enter to use ${defaultRoots}`,
94
+ placeholder: defaultRoots,
95
+ defaultValue: defaultRoots,
96
+ validate: (value) => value?.trim() ? undefined : "Enter at least one project root.",
97
+ });
98
+ const allowedRoots = rootsAnswer
99
+ .split(",")
100
+ .map((root) => resolve(expandHomePath(root.trim())))
101
+ .filter(Boolean);
102
+ const defaultPort = String(files.config.port ?? 7676);
103
+ const portAnswer = await textPrompt({
104
+ message: `Which local port should ForgeRelay use? Press Enter to use ${defaultPort}`,
105
+ placeholder: defaultPort,
106
+ defaultValue: defaultPort,
107
+ validate: validatePort,
108
+ });
109
+ const port = Number(portAnswer);
110
+ prompts.note([
111
+ "ForgeRelay needs a public base URL so ChatGPT or Claude can reach this MCP server.",
112
+ "Create a tunnel or reverse proxy with Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or your own HTTPS proxy.",
113
+ "Paste the public origin here, without /mcp.",
114
+ "",
115
+ "Example: https://your-tunnel-host.example.com",
116
+ ].join("\n"), "Public URL required");
117
+ const publicBaseUrl = normalizePublicBaseUrl(await textPrompt({
118
+ message: files.config.publicBaseUrl
119
+ ? `What is the public base URL? Press Enter to keep ${files.config.publicBaseUrl}`
120
+ : "What is the public base URL?",
121
+ placeholder: files.config.publicBaseUrl ?? "https://your-tunnel-host.example.com",
122
+ defaultValue: files.config.publicBaseUrl ?? "",
123
+ validate: validateRequiredPublicBaseUrl,
124
+ }));
125
+ const config = {
126
+ host: files.config.host ?? "127.0.0.1",
127
+ port,
128
+ allowedRoots,
129
+ publicBaseUrl,
130
+ workflowInstructions: files.config.workflowInstructions,
131
+ appendInstructions: files.config.appendInstructions,
132
+ subagents: resolveSubagentsFlag(files.config),
133
+ };
134
+ const auth = {
135
+ ownerToken: files.auth.ownerToken ?? generateOwnerToken(),
136
+ };
137
+ const configPath = writeDevspaceConfig(config);
138
+ const authPath = writeDevspaceAuth(auth);
139
+ const seededSkillPaths = config.subagents ? ensureDevspaceDefaultSkills() : [];
140
+ const lines = [
141
+ `Config: ${configPath}`,
142
+ `Auth: ${authPath}`,
143
+ ...seededSkillPaths.map((path) => `Default skill: ${path}`),
144
+ `Local MCP URL: http://${config.host}:${config.port}/mcp`,
145
+ ...(publicBaseUrl ? [`Public MCP URL: ${publicBaseUrl}/mcp`] : []),
146
+ ];
147
+ prompts.note(lines.join("\n"), "ForgeRelay configured");
148
+ prompts.note([
149
+ `Owner password: ${auth.ownerToken}`,
150
+ "Use this when ChatGPT or Claude asks you to approve ForgeRelay access.",
151
+ `Stored at: ${authPath}`,
152
+ ].join("\n"), "Owner password");
153
+ prompts.outro("Run `forgerelay serve` to start the MCP server.");
154
+ }
155
+ catch (error) {
156
+ if (error instanceof SetupCancelledError) {
157
+ prompts.cancel("Setup cancelled");
158
+ return;
159
+ }
160
+ throw error;
161
+ }
162
+ }
163
+ async function serve() {
164
+ const sqliteStatus = checkSqliteNative();
165
+ if (sqliteStatus !== "ok") {
166
+ throw new Error([
167
+ "better-sqlite3 could not load for this Node runtime.",
168
+ sqliteStatus,
169
+ "",
170
+ "Try reinstalling or rebuilding dependencies under the active Node version:",
171
+ " npm rebuild better-sqlite3",
172
+ ].join("\n"));
173
+ }
174
+ const { createServer } = await import("./server.js");
175
+ const config = loadConfig();
176
+ const { app, close, localAgentProviders } = createServer(config);
177
+ const httpServer = app.listen(config.port, config.host, () => {
178
+ console.log(`forgerelay listening on http://${config.host}:${config.port}/mcp`);
179
+ console.log(`public base url: ${config.publicBaseUrl}`);
180
+ console.log(`allowed roots: ${config.allowedRoots.join(", ")}`);
181
+ console.log(`allowed hosts: ${config.allowedHosts.join(", ")}`);
182
+ if (config.allowedHosts.includes("*")) {
183
+ console.warn("warning: Host header allowlist is disabled because FORGERELAY_ALLOWED_HOSTS=*");
184
+ }
185
+ console.log("auth: Owner password approval required");
186
+ console.log(`logging: ${config.logging.level} ${config.logging.format}`);
187
+ if (config.subagents) {
188
+ console.log(`subagent providers: ${formatLocalAgentProviderAvailabilitySummary(localAgentProviders)}`);
189
+ }
190
+ });
191
+ let shuttingDown = false;
192
+ const shutdown = async () => {
193
+ if (shuttingDown)
194
+ return;
195
+ shuttingDown = true;
196
+ await shutdownHttpServer(httpServer, close);
197
+ process.exit(0);
198
+ };
199
+ const handleShutdown = () => {
200
+ void shutdown().catch((error) => {
201
+ console.error("forgerelay shutdown failed", error);
202
+ process.exit(1);
203
+ });
204
+ };
205
+ process.once("SIGINT", handleShutdown);
206
+ process.once("SIGTERM", handleShutdown);
207
+ }
208
+ async function runDoctor() {
209
+ const files = loadDevspaceFiles();
210
+ console.log(`Config dir: ${files.dir}`);
211
+ console.log(`Config file: ${files.configExists ? files.configPath : "missing"}`);
212
+ console.log(`Auth file: ${files.authExists ? files.authPath : "missing"}`);
213
+ console.log(`Node: ${process.version} (${nodeVersionStatus()})`);
214
+ console.log(`Node ABI: ${process.versions.modules}`);
215
+ console.log(`Platform: ${process.platform} ${process.arch}`);
216
+ console.log(`Git: ${checkGitAvailable()}`);
217
+ console.log(`Bash shell: ${checkBashShell()}`);
218
+ console.log(`SQLite native dependency: ${checkSqliteNative()}`);
219
+ try {
220
+ const config = loadConfig();
221
+ console.log(`Local MCP URL: http://${config.host}:${config.port}/mcp`);
222
+ console.log(`Public MCP URL: ${new URL("/mcp", config.publicBaseUrl).toString()}`);
223
+ console.log(`Allowed roots: ${config.allowedRoots.join(", ")}`);
224
+ console.log(`Allowed hosts: ${config.allowedHosts.join(", ")}`);
225
+ }
226
+ catch (error) {
227
+ console.log(`Config status: ${error instanceof Error ? error.message : String(error)}`);
228
+ }
229
+ }
230
+ function runConfigCommand(args) {
231
+ const [subcommand, key, ...rest] = args;
232
+ const files = loadDevspaceFiles();
233
+ if (!subcommand || subcommand === "get") {
234
+ console.log(JSON.stringify(files.config, null, 2));
235
+ return;
236
+ }
237
+ if (subcommand !== "set") {
238
+ throw new Error(`Unknown config command: ${subcommand}`);
239
+ }
240
+ if (key !== "publicBaseUrl") {
241
+ throw new Error("Only `forgerelay config set publicBaseUrl <url|null>` is supported right now.");
242
+ }
243
+ const value = rest.join(" ").trim();
244
+ if (!value) {
245
+ throw new Error("Missing publicBaseUrl value.");
246
+ }
247
+ writeDevspaceConfig({
248
+ ...files.config,
249
+ publicBaseUrl: normalizeOptionalPublicBaseUrl(value),
250
+ });
251
+ console.log(`Updated ${files.configPath}`);
252
+ }
253
+ function printHelp() {
254
+ console.log([
255
+ "ForgeRelay",
256
+ "",
257
+ "Usage:",
258
+ " forgerelay Run first-time setup if needed, then start the server",
259
+ " forgerelay serve Start the server",
260
+ " forgerelay init Create or update ~/.forgerelay/config.json and auth.json",
261
+ " forgerelay doctor Show config, runtime, and native dependency status",
262
+ " forgerelay config get Print persisted config",
263
+ " forgerelay config set publicBaseUrl <url|null>",
264
+ " forgerelay agents ls List subagent sessions",
265
+ " forgerelay agents run <profile-or-provider-or-id> [--model <model>] <prompt>",
266
+ " forgerelay agents show <id>",
267
+ " forgerelay -v, --version Print the installed version",
268
+ "",
269
+ "For temporary tunnels:",
270
+ " FORGERELAY_PUBLIC_BASE_URL=https://example.trycloudflare.com forgerelay serve",
271
+ ].join("\n"));
272
+ }
273
+ async function runAgentsCommand(args) {
274
+ const [subcommand, ...rest] = args;
275
+ switch (subcommand) {
276
+ case "ls":
277
+ case "list":
278
+ await runAgentsList();
279
+ return;
280
+ case "run":
281
+ await runAgentsRun(rest);
282
+ return;
283
+ case "show":
284
+ await runAgentsShow(rest);
285
+ return;
286
+ case "__worker":
287
+ await runAgentsWorker(rest);
288
+ return;
289
+ case undefined:
290
+ case "help":
291
+ case "--help":
292
+ case "-h":
293
+ printAgentsHelp();
294
+ return;
295
+ default:
296
+ throw new Error(`Unknown agents command: ${subcommand}`);
297
+ }
298
+ }
299
+ async function runAgentsList() {
300
+ const config = loadConfig();
301
+ const store = createLocalAgentStore(config);
302
+ const agents = store.list(resolveCurrentWorkspaceScope());
303
+ if (agents.length === 0) {
304
+ console.log("No subagent sessions found for this workspace.");
305
+ return;
306
+ }
307
+ for (const agent of agents) {
308
+ console.log(formatAgentLine(agent));
309
+ }
310
+ }
311
+ async function runAgentsRun(args) {
312
+ const parsed = parseLocalAgentRunArgs(args);
313
+ const config = loadConfig();
314
+ const workspaceRoot = resolveCurrentWorkspaceRoot();
315
+ const store = createLocalAgentStore(config);
316
+ const existing = store.get(parsed.target);
317
+ if (existing) {
318
+ if (!isLocalAgentProvider(existing.provider)) {
319
+ throw new Error(`Unknown subagent provider for existing session: ${existing.provider}`);
320
+ }
321
+ assertLocalAgentProviderAvailable(existing.provider);
322
+ const promptFile = writeAgentPromptFile(parsed.prompt);
323
+ store.update(existing.id, {
324
+ status: "starting",
325
+ model: parsed.model ?? existing.model,
326
+ thinking: parsed.thinking ?? existing.thinking,
327
+ latestResponse: undefined,
328
+ error: undefined,
329
+ });
330
+ spawnAgentWorker(existing.id, promptFile);
331
+ console.log(formatAgentLine({
332
+ ...existing,
333
+ status: "running",
334
+ model: parsed.model ?? existing.model,
335
+ thinking: parsed.thinking ?? existing.thinking,
336
+ }));
337
+ return;
338
+ }
339
+ const profiles = await loadLocalAgentProfiles(config, workspaceRoot);
340
+ const target = resolveLocalAgentTarget(parsed.target, profiles, parsed.model, parsed.thinking);
341
+ if (!target) {
342
+ throw new Error(`Unknown subagent profile, provider, or id: ${parsed.target}. Available ${formatAvailableLocalAgentTargets(profiles)}`);
343
+ }
344
+ assertLocalAgentProviderAvailable(target.provider);
345
+ const promptFile = writeAgentPromptFile(parsed.prompt);
346
+ const record = store.create({
347
+ workspaceId: process.env.FORGERELAY_WORKSPACE_ID ?? process.env.DEVSPACE_WORKSPACE_ID,
348
+ workspaceRoot,
349
+ profileName: target.name,
350
+ provider: target.provider,
351
+ model: target.model,
352
+ thinking: target.thinking,
353
+ });
354
+ spawnAgentWorker(record.id, promptFile);
355
+ console.log(formatAgentLine({ ...record, status: "running" }));
356
+ }
357
+ async function runAgentsShow(args) {
358
+ const [id] = args;
359
+ if (!id)
360
+ throw new Error("Usage: forgerelay agents show <id>");
361
+ const config = loadConfig();
362
+ const store = createLocalAgentStore(config);
363
+ let record = store.get(id);
364
+ if (!record)
365
+ throw new Error(`Unknown subagent id: ${id}`);
366
+ const deadline = Date.now() + 15_000;
367
+ while ((record.status === "starting" || record.status === "running") && Date.now() < deadline) {
368
+ await sleep(500);
369
+ record = store.get(id) ?? record;
370
+ }
371
+ console.log(formatAgentLine(record));
372
+ if (record.latestResponse) {
373
+ console.log(record.latestResponse);
374
+ return;
375
+ }
376
+ if (record.error) {
377
+ console.log(record.error);
378
+ return;
379
+ }
380
+ if (record.status === "starting" || record.status === "running") {
381
+ console.log(`No final response yet. Call \`forgerelay agents show ${record.id}\` again later.`);
382
+ }
383
+ }
384
+ async function runAgentsWorker(args) {
385
+ const [id, promptFileFlag, promptFile] = args;
386
+ if (!id || promptFileFlag !== "--prompt-file" || !promptFile) {
387
+ throw new Error("Usage: forgerelay agents __worker <id> --prompt-file <path>");
388
+ }
389
+ const config = loadConfig();
390
+ const store = createLocalAgentStore(config);
391
+ const record = store.get(id);
392
+ if (!record)
393
+ throw new Error(`Unknown subagent id: ${id}`);
394
+ store.update(record.id, { status: "running", error: undefined });
395
+ try {
396
+ const profiles = await loadLocalAgentProfiles(config, record.workspaceRoot);
397
+ const profile = profiles.find((candidate) => candidate.name === record.profileName);
398
+ const prompt = await readFile(promptFile, "utf8");
399
+ const result = profile
400
+ ? await runLocalAgentProfile(profile, record, prompt)
401
+ : await runRawLocalAgentProvider(record, prompt);
402
+ store.update(record.id, {
403
+ providerSessionId: result.providerSessionId ?? undefined,
404
+ status: "idle",
405
+ latestResponse: result.finalResponse,
406
+ error: undefined,
407
+ });
408
+ }
409
+ catch (error) {
410
+ store.update(record.id, {
411
+ status: "error",
412
+ error: error instanceof Error ? error.message : String(error),
413
+ });
414
+ }
415
+ }
416
+ async function runLocalAgentProfile(profile, record, prompt) {
417
+ const body = profile.body.trim();
418
+ const fullPrompt = body ? `${body}\n\nTask:\n${prompt}` : prompt;
419
+ return runLocalAgentProvider(profile.provider, {
420
+ prompt: fullPrompt,
421
+ workspace: record.workspaceRoot,
422
+ providerSessionId: record.providerSessionId,
423
+ writeMode: "allowed",
424
+ model: record.model ?? profile.model,
425
+ thinking: record.thinking ?? profile.thinking,
426
+ });
427
+ }
428
+ async function runRawLocalAgentProvider(record, prompt) {
429
+ if (record.profileName !== record.provider || !isLocalAgentProvider(record.provider)) {
430
+ throw new Error(`Subagent profile not found: ${record.profileName}`);
431
+ }
432
+ return runLocalAgentProvider(record.provider, {
433
+ prompt,
434
+ workspace: record.workspaceRoot,
435
+ providerSessionId: record.providerSessionId,
436
+ writeMode: "allowed",
437
+ model: record.model,
438
+ thinking: record.thinking,
439
+ });
440
+ }
441
+ function spawnAgentWorker(agentId, promptFile) {
442
+ const child = spawn(process.execPath, [
443
+ ...process.execArgv,
444
+ fileURLToPath(import.meta.url),
445
+ "agents",
446
+ "__worker",
447
+ agentId,
448
+ "--prompt-file",
449
+ promptFile,
450
+ ], {
451
+ detached: true,
452
+ stdio: "ignore",
453
+ env: process.env,
454
+ });
455
+ child.unref();
456
+ }
457
+ function writeAgentPromptFile(prompt) {
458
+ const directory = mkdtempSync(join(tmpdir(), "forgerelay-agent-prompt-"));
459
+ const filePath = join(directory, "prompt.txt");
460
+ writeFileSync(filePath, prompt, { mode: 0o600 });
461
+ return filePath;
462
+ }
463
+ function resolveCurrentWorkspaceRoot() {
464
+ return resolve(process.env.FORGERELAY_WORKSPACE_ROOT ?? process.env.DEVSPACE_WORKSPACE_ROOT ?? process.cwd());
465
+ }
466
+ function resolveCurrentWorkspaceScope() {
467
+ return {
468
+ workspaceId: process.env.FORGERELAY_WORKSPACE_ID ?? process.env.DEVSPACE_WORKSPACE_ID,
469
+ workspaceRoot: resolveCurrentWorkspaceRoot(),
470
+ };
471
+ }
472
+ function formatAgentLine(agent) {
473
+ const model = agent.model ? ` ${agent.model}` : "";
474
+ const thinking = agent.thinking ? ` thinking=${agent.thinking}` : "";
475
+ return `${agent.id} ${agent.status} ${agent.profileName} ${agent.provider}${model}${thinking}`;
476
+ }
477
+ function sleep(ms) {
478
+ return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
479
+ }
480
+ function printAgentsHelp() {
481
+ console.log([
482
+ "ForgeRelay agents",
483
+ "",
484
+ "Usage:",
485
+ " forgerelay agents ls",
486
+ " forgerelay agents run <profile-or-provider-or-id> [--model <model>] [--thinking <level>] <prompt>",
487
+ " forgerelay agents show <id>",
488
+ ].join("\n"));
489
+ }
490
+ function printVersion() {
491
+ const packageJson = require("../package.json");
492
+ if (typeof packageJson.version !== "string") {
493
+ throw new Error("Unable to read ForgeRelay package version.");
494
+ }
495
+ console.log(packageJson.version);
496
+ }
497
+ function normalizeOptionalPublicBaseUrl(value) {
498
+ const trimmed = value.trim();
499
+ if (!trimmed || trimmed === "null" || trimmed === "none")
500
+ return null;
501
+ return normalizePublicBaseUrl(trimmed);
502
+ }
503
+ function normalizePublicBaseUrl(value) {
504
+ const trimmed = value.trim();
505
+ const parsed = new URL(trimmed);
506
+ parsed.hash = "";
507
+ parsed.search = "";
508
+ parsed.pathname = parsed.pathname.replace(/\/+$/, "");
509
+ return parsed.toString().replace(/\/$/, "");
510
+ }
511
+ async function textPrompt(options) {
512
+ const result = await prompts.text({
513
+ ...options,
514
+ validate: (value) => options.validate?.(value?.trim() ? value : options.defaultValue),
515
+ });
516
+ if (prompts.isCancel(result))
517
+ throw new SetupCancelledError();
518
+ const value = String(result).trim();
519
+ return value || options.defaultValue;
520
+ }
521
+ function validatePort(value) {
522
+ const port = Number(value);
523
+ return Number.isInteger(port) && port >= 1 && port <= 65535
524
+ ? undefined
525
+ : "Enter a port between 1 and 65535.";
526
+ }
527
+ function validateRequiredPublicBaseUrl(value) {
528
+ const trimmed = value?.trim() ?? "";
529
+ if (!trimmed)
530
+ return "Enter the public URL from your tunnel or reverse proxy.";
531
+ if (trimmed.endsWith("/mcp"))
532
+ return "Enter the base URL only, without /mcp.";
533
+ return validatePublicBaseUrl(trimmed);
534
+ }
535
+ function validatePublicBaseUrl(value) {
536
+ try {
537
+ const parsed = new URL(value);
538
+ return parsed.protocol === "http:" || parsed.protocol === "https:"
539
+ ? undefined
540
+ : "Use an http or https URL.";
541
+ }
542
+ catch {
543
+ return "Enter a valid URL, for example https://your-tunnel-host.example.com.";
544
+ }
545
+ }
546
+ function assertSupportedNode() {
547
+ if (satisfies(process.versions.node, SUPPORTED_NODE_RANGE))
548
+ return;
549
+ throw new Error([
550
+ `ForgeRelay requires Node ${SUPPORTED_NODE_RANGE}.`,
551
+ `Current Node: ${process.version}`,
552
+ "",
553
+ "Install Node 22 LTS or use a version manager such as nvm, fnm, or mise.",
554
+ ].join("\n"));
555
+ }
556
+ function nodeVersionStatus() {
557
+ return satisfies(process.versions.node, SUPPORTED_NODE_RANGE)
558
+ ? `supported ${SUPPORTED_NODE_RANGE}`
559
+ : `unsupported, requires ${SUPPORTED_NODE_RANGE}`;
560
+ }
561
+ class SetupCancelledError extends Error {
562
+ }
563
+ function checkSqliteNative() {
564
+ try {
565
+ const Database = require("better-sqlite3");
566
+ const db = new Database(":memory:");
567
+ db.close();
568
+ return "ok";
569
+ }
570
+ catch (error) {
571
+ return error instanceof Error ? error.message : String(error);
572
+ }
573
+ }
574
+ function checkGitAvailable() {
575
+ try {
576
+ const { execFileSync } = require("node:child_process");
577
+ return execFileSync("git", ["--version"], { encoding: "utf8" }).trim();
578
+ }
579
+ catch (error) {
580
+ const message = error instanceof Error ? error.message : String(error);
581
+ return `unavailable (${message})`;
582
+ }
583
+ }
584
+ function checkBashShell() {
585
+ try {
586
+ const { shell, args } = getShellConfig();
587
+ return `${shell} ${args.join(" ")}`;
588
+ }
589
+ catch (error) {
590
+ const message = error instanceof Error ? error.message : String(error);
591
+ return `unavailable (${message})`;
592
+ }
593
+ }
594
+ main(process.argv.slice(2)).catch((error) => {
595
+ console.error(error instanceof Error ? error.message : String(error));
596
+ process.exitCode = 1;
597
+ });