@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.
- package/CHANGELOG.md +45 -0
- package/LICENSE +22 -0
- package/NOTICE.md +19 -0
- package/README.md +270 -0
- package/dist/apply-patch.js +402 -0
- package/dist/artifact-error.js +8 -0
- package/dist/artifact-tools.js +377 -0
- package/dist/cli.js +597 -0
- package/dist/config.js +224 -0
- package/dist/db/client.js +29 -0
- package/dist/db/migrations.js +189 -0
- package/dist/db/schema.js +85 -0
- package/dist/git-worktrees.js +255 -0
- package/dist/git.js +41 -0
- package/dist/incoming-artifacts.js +378 -0
- package/dist/local-agent-adapters.js +653 -0
- package/dist/local-agent-availability.js +119 -0
- package/dist/local-agent-path.js +25 -0
- package/dist/local-agent-profiles.js +136 -0
- package/dist/local-agent-runtime.js +48 -0
- package/dist/local-agent-store.js +145 -0
- package/dist/local-agent-targets.js +80 -0
- package/dist/logger.js +69 -0
- package/dist/mcp/server-instructions.js +78 -0
- package/dist/mcp-sessions.js +56 -0
- package/dist/oauth-provider.js +237 -0
- package/dist/oauth-store.js +138 -0
- package/dist/pi-tools.js +81 -0
- package/dist/process-platform.js +49 -0
- package/dist/process-sessions.js +337 -0
- package/dist/request-meta.js +9 -0
- package/dist/review-checkpoints.js +219 -0
- package/dist/roots.js +37 -0
- package/dist/server-shutdown.js +12 -0
- package/dist/server.js +1596 -0
- package/dist/skills.js +89 -0
- package/dist/ui/.vite/manifest.json +2521 -0
- package/dist/ui/assets/abap-CLvhMVsD.js +1 -0
- package/dist/ui/assets/actionscript-3--17pq3dv.js +1 -0
- package/dist/ui/assets/ada-C5qYipkI.js +1 -0
- package/dist/ui/assets/andromeeda-vGVdxbeo.js +1 -0
- package/dist/ui/assets/angular-html-CovppXt5.js +1 -0
- package/dist/ui/assets/angular-ts-0Y9l6YXu.js +1 -0
- package/dist/ui/assets/apache-U0d_L8uA.js +1 -0
- package/dist/ui/assets/apex-CGTLDQj6.js +1 -0
- package/dist/ui/assets/apl-BmBhiklA.js +1 -0
- package/dist/ui/assets/applescript-CCn79oCD.js +1 -0
- package/dist/ui/assets/ara-4CJ0cIlV.js +1 -0
- package/dist/ui/assets/asciidoc-DE70LPWp.js +1 -0
- package/dist/ui/assets/asm-Cmm7eHzH.js +1 -0
- package/dist/ui/assets/astro-BAmqcqyV.js +1 -0
- package/dist/ui/assets/aurora-x-CDeNXAV0.js +1 -0
- package/dist/ui/assets/awk-BWXHIvNe.js +1 -0
- package/dist/ui/assets/ayu-dark-DluEY0Gj.js +1 -0
- package/dist/ui/assets/ayu-light-C3h-C4tm.js +1 -0
- package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +1 -0
- package/dist/ui/assets/ballerina-B7ZEbQpA.js +1 -0
- package/dist/ui/assets/bat-Bo4NYOV-.js +1 -0
- package/dist/ui/assets/beancount-D-usSTwE.js +1 -0
- package/dist/ui/assets/berry-DKpUyyne.js +1 -0
- package/dist/ui/assets/bibtex-Ci_nEsc7.js +1 -0
- package/dist/ui/assets/bicep-CUHmPFLl.js +1 -0
- package/dist/ui/assets/bird2-C2hNVINV.js +1 -0
- package/dist/ui/assets/blade-BjFcmRJo.js +1 -0
- package/dist/ui/assets/bsl-BkkzgIyY.js +1 -0
- package/dist/ui/assets/c-CaOJn4x0.js +1 -0
- package/dist/ui/assets/c3-CnJL0r0V.js +1 -0
- package/dist/ui/assets/cadence-CQ2zXKGN.js +1 -0
- package/dist/ui/assets/cairo-DLTphjLi.js +1 -0
- package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
- package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
- package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
- package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
- package/dist/ui/assets/clarity-SemFz856.js +1 -0
- package/dist/ui/assets/clojure-DqKBuwfJ.js +1 -0
- package/dist/ui/assets/cmake-Bj61d0ZC.js +1 -0
- package/dist/ui/assets/cobol-DR4zWFMt.js +1 -0
- package/dist/ui/assets/codeowners-C8r90Shi.js +1 -0
- package/dist/ui/assets/codeql-oeQT6MSM.js +1 -0
- package/dist/ui/assets/coffee-ReGSThmM.js +1 -0
- package/dist/ui/assets/common-lisp-Cv5bFMCO.js +1 -0
- package/dist/ui/assets/coq-BrsZFFmf.js +1 -0
- package/dist/ui/assets/cpp-CnlQh6MO.js +1 -0
- package/dist/ui/assets/crystal-BrpPbH1U.js +1 -0
- package/dist/ui/assets/csharp-Ct8U2NOr.js +1 -0
- package/dist/ui/assets/css-DRBEvyPU.js +1 -0
- package/dist/ui/assets/csv-Dx-8-gkx.js +1 -0
- package/dist/ui/assets/cue-CE9AQfxI.js +1 -0
- package/dist/ui/assets/cypher-ClKdZ_lG.js +1 -0
- package/dist/ui/assets/d-qD-0Kul2.js +1 -0
- package/dist/ui/assets/dark-plus-Cs2F2srj.js +1 -0
- package/dist/ui/assets/dart-DkHntEIa.js +1 -0
- package/dist/ui/assets/dax-BkyTk9wS.js +1 -0
- package/dist/ui/assets/desktop-Dlh5hvp9.js +1 -0
- package/dist/ui/assets/diff-woXpYk--.js +1 -0
- package/dist/ui/assets/docker-IyjqRm3v.js +1 -0
- package/dist/ui/assets/dotenv-_5a1GRtc.js +1 -0
- package/dist/ui/assets/dracula-BHWKrbxM.js +1 -0
- package/dist/ui/assets/dracula-soft-5eyTD99u.js +1 -0
- package/dist/ui/assets/dream-maker-DW3nJb8Q.js +1 -0
- package/dist/ui/assets/edge-cfwpdvl9.js +1 -0
- package/dist/ui/assets/elixir-7owrJxb6.js +1 -0
- package/dist/ui/assets/elm-udiOjODk.js +1 -0
- package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +1 -0
- package/dist/ui/assets/erb-8ctXHMkS.js +1 -0
- package/dist/ui/assets/erlang-Cphh6RMH.js +1 -0
- package/dist/ui/assets/everforest-dark-sB-x3p7T.js +1 -0
- package/dist/ui/assets/everforest-light-Df2xbC6M.js +1 -0
- package/dist/ui/assets/fennel-DQxkIbk2.js +1 -0
- package/dist/ui/assets/fish-BJitypiv.js +1 -0
- package/dist/ui/assets/fluent-C03EYrpw.js +1 -0
- package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
- package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +1 -0
- package/dist/ui/assets/fsharp-D13ZGOAj.js +1 -0
- package/dist/ui/assets/gdresource-C0sCabJj.js +1 -0
- package/dist/ui/assets/gdscript-Cp2uCuqX.js +1 -0
- package/dist/ui/assets/gdshader-CBce3t8t.js +1 -0
- package/dist/ui/assets/genie-CV2tkWYe.js +1 -0
- package/dist/ui/assets/gherkin-DExj1W_8.js +1 -0
- package/dist/ui/assets/git-commit-BSykSTBG.js +1 -0
- package/dist/ui/assets/git-rebase-P0V_qK1w.js +1 -0
- package/dist/ui/assets/github-dark-C-LZuMrd.js +1 -0
- package/dist/ui/assets/github-dark-default-DXG-b-1a.js +1 -0
- package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
- package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
- package/dist/ui/assets/github-light-EUqPIrTm.js +1 -0
- package/dist/ui/assets/github-light-default-BXViO-2h.js +1 -0
- package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +1 -0
- package/dist/ui/assets/gleam-CSRkHgEL.js +1 -0
- package/dist/ui/assets/glimmer-js-CZ14ED7U.js +1 -0
- package/dist/ui/assets/glimmer-ts-DtBSFP-o.js +1 -0
- package/dist/ui/assets/glsl-BX2BkZJK.js +1 -0
- package/dist/ui/assets/gn-ilITqXS6.js +1 -0
- package/dist/ui/assets/gnuplot-7GGW24-e.js +1 -0
- package/dist/ui/assets/go-BJwz_mda.js +1 -0
- package/dist/ui/assets/graphql-Dj_cPv4w.js +1 -0
- package/dist/ui/assets/groovy-CacY0gHj.js +1 -0
- package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
- package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
- package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
- package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
- package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
- package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
- package/dist/ui/assets/hack-DGRkd8xn.js +1 -0
- package/dist/ui/assets/haml-BAPSvujW.js +1 -0
- package/dist/ui/assets/handlebars-PYksdULG.js +1 -0
- package/dist/ui/assets/haskell-D8IpX4py.js +1 -0
- package/dist/ui/assets/haxe-OTjmBuCE.js +1 -0
- package/dist/ui/assets/hcl-Dh228itO.js +1 -0
- package/dist/ui/assets/heavy-payload-BjE0LSUi.js +4 -0
- package/dist/ui/assets/hjson-CxZEssPk.js +1 -0
- package/dist/ui/assets/hlsl-Cvrh5tZx.js +1 -0
- package/dist/ui/assets/horizon-CE9ld1lL.js +1 -0
- package/dist/ui/assets/horizon-bright-Br1oVSNq.js +1 -0
- package/dist/ui/assets/houston-CsvMBhTu.js +1 -0
- package/dist/ui/assets/html-DloAPGZ1.js +1 -0
- package/dist/ui/assets/html-derivative-C6q86ZrS.js +1 -0
- package/dist/ui/assets/http-fPvYDvHA.js +1 -0
- package/dist/ui/assets/hurl-Dbir4WvE.js +1 -0
- package/dist/ui/assets/hxml-B0Qn7Nwc.js +1 -0
- package/dist/ui/assets/hy-CZbG8q4J.js +1 -0
- package/dist/ui/assets/imba-DsUTQ-LC.js +1 -0
- package/dist/ui/assets/ini-B5eOa1yu.js +1 -0
- package/dist/ui/assets/java-DvkqXg3z.js +1 -0
- package/dist/ui/assets/javascript-TONTV6Ty.js +1 -0
- package/dist/ui/assets/jinja-OM1F5Gct.js +1 -0
- package/dist/ui/assets/jison-CBttugts.js +1 -0
- package/dist/ui/assets/json-Db5oY-7J.js +1 -0
- package/dist/ui/assets/json5-BR5RXkoi.js +1 -0
- package/dist/ui/assets/jsonc-CYpm1nAK.js +1 -0
- package/dist/ui/assets/jsonl-CmCQp5Yx.js +1 -0
- package/dist/ui/assets/jsonnet-CJTPZ8u_.js +1 -0
- package/dist/ui/assets/jssm-DXw9l8Rf.js +1 -0
- package/dist/ui/assets/jsx-DKeJCgsc.js +1 -0
- package/dist/ui/assets/julia-NlIPhXaL.js +1 -0
- package/dist/ui/assets/just-BXBJB-mX.js +1 -0
- package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
- package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +1 -0
- package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +1 -0
- package/dist/ui/assets/kdl-CsD5j6eV.js +1 -0
- package/dist/ui/assets/kotlin-DhhofPvG.js +1 -0
- package/dist/ui/assets/kusto-BUv0MjJC.js +1 -0
- package/dist/ui/assets/laserwave-C_8bwKvT.js +1 -0
- package/dist/ui/assets/latex-CGK-6yDy.js +1 -0
- package/dist/ui/assets/lean-CewbzKMR.js +1 -0
- package/dist/ui/assets/less-DVTAwKKz.js +1 -0
- package/dist/ui/assets/light-plus-DVQuIRkW.js +1 -0
- package/dist/ui/assets/liquid-D7waQ0MY.js +1 -0
- package/dist/ui/assets/llvm-Cm23YOpf.js +1 -0
- package/dist/ui/assets/log-BNLmms1o.js +1 -0
- package/dist/ui/assets/logo-Cluzi2Zq.js +1 -0
- package/dist/ui/assets/lua-C_kkt4h1.js +1 -0
- package/dist/ui/assets/luau-CNKltnaQ.js +1 -0
- package/dist/ui/assets/make-Dixweg8N.js +1 -0
- package/dist/ui/assets/markdown-BYOwaDjH.js +1 -0
- package/dist/ui/assets/marko-BokXuCts.js +1 -0
- package/dist/ui/assets/material-theme-Bm3Qr25_.js +1 -0
- package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +1 -0
- package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +1 -0
- package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +1 -0
- package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +1 -0
- package/dist/ui/assets/matlab-D7qyCx1q.js +1 -0
- package/dist/ui/assets/mdc-Bk0nnUJA.js +1 -0
- package/dist/ui/assets/mdx-DQZ5AkYe.js +1 -0
- package/dist/ui/assets/mermaid-Bk4SNUv9.js +1 -0
- package/dist/ui/assets/min-dark-BSWPekZh.js +1 -0
- package/dist/ui/assets/min-light-DDpmG2fV.js +1 -0
- package/dist/ui/assets/mipsasm-BMqwQI7S.js +1 -0
- package/dist/ui/assets/mojo-BgCJLMeH.js +1 -0
- package/dist/ui/assets/monokai-CdkpiU2Y.js +1 -0
- package/dist/ui/assets/moonbit-CaWjb8XO.js +1 -0
- package/dist/ui/assets/move-B1IS1UjX.js +1 -0
- package/dist/ui/assets/narrat-_X_XdTYD.js +1 -0
- package/dist/ui/assets/nextflow-Bbiyy34d.js +1 -0
- package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +1 -0
- package/dist/ui/assets/nginx-jM6NF9TV.js +1 -0
- package/dist/ui/assets/night-owl-DhmEMT88.js +1 -0
- package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +1 -0
- package/dist/ui/assets/nim-hYsL-WKb.js +1 -0
- package/dist/ui/assets/nix-IvuFDN5E.js +1 -0
- package/dist/ui/assets/nord-Cb4Vim4T.js +1 -0
- package/dist/ui/assets/nushell-DcLAeLz5.js +1 -0
- package/dist/ui/assets/objective-c-D1A_Heim.js +1 -0
- package/dist/ui/assets/objective-cpp-BsSzOQcm.js +1 -0
- package/dist/ui/assets/ocaml-O90oeIOV.js +1 -0
- package/dist/ui/assets/odin-B1RWQWA5.js +1 -0
- package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +1 -0
- package/dist/ui/assets/one-light-D7Lr4KcI.js +1 -0
- package/dist/ui/assets/openscad-BUDT5pXO.js +1 -0
- package/dist/ui/assets/pascal-4ZHwLPI5.js +1 -0
- package/dist/ui/assets/perl-DBI_cUHJ.js +1 -0
- package/dist/ui/assets/php-BX_aQhFl.js +1 -0
- package/dist/ui/assets/pierre-dark-sU4Zdns8.js +1 -0
- package/dist/ui/assets/pierre-dark-soft-HXgun5vs.js +1 -0
- package/dist/ui/assets/pierre-light-DWBk51d8.js +1 -0
- package/dist/ui/assets/pierre-light-soft-CodEzPxf.js +1 -0
- package/dist/ui/assets/pkl-ot-7Btpt.js +1 -0
- package/dist/ui/assets/plastic-DQwYfKfQ.js +1 -0
- package/dist/ui/assets/plsql-DGHpHOYJ.js +1 -0
- package/dist/ui/assets/po-BiJDBrnU.js +1 -0
- package/dist/ui/assets/poimandres-DRFjx7u4.js +1 -0
- package/dist/ui/assets/polar-C7UOKdEL.js +1 -0
- package/dist/ui/assets/postcss-BXeXVLqQ.js +1 -0
- package/dist/ui/assets/powerquery-DNMTfnFr.js +1 -0
- package/dist/ui/assets/powershell-DshXNtvi.js +1 -0
- package/dist/ui/assets/prisma-BsRQq5mF.js +1 -0
- package/dist/ui/assets/prolog-iXnhIJG7.js +1 -0
- package/dist/ui/assets/proto-DB4EqR-F.js +1 -0
- package/dist/ui/assets/pug-DwFAYy1e.js +1 -0
- package/dist/ui/assets/puppet-CDv2pdJW.js +1 -0
- package/dist/ui/assets/purescript-9MfHhQsQ.js +1 -0
- package/dist/ui/assets/python-gzcpVVnB.js +1 -0
- package/dist/ui/assets/qml-eLSwQUKt.js +1 -0
- package/dist/ui/assets/qmldir-DCQb3MpD.js +1 -0
- package/dist/ui/assets/qss-Fe1Jh2GI.js +1 -0
- package/dist/ui/assets/r-BMnQsMLf.js +1 -0
- package/dist/ui/assets/racket-DcIDlBhZ.js +1 -0
- package/dist/ui/assets/raku-B3gFvitq.js +1 -0
- package/dist/ui/assets/razor-CgciiMyw.js +1 -0
- package/dist/ui/assets/red-CJ3rzSJv.js +1 -0
- package/dist/ui/assets/reg-CRGYupPL.js +1 -0
- package/dist/ui/assets/regexp-ZrURNrn5.js +1 -0
- package/dist/ui/assets/rel-BtDbiS_P.js +1 -0
- package/dist/ui/assets/review-payload-HGkpJjjm.js +1 -0
- package/dist/ui/assets/riscv-Ckw8ddFX.js +1 -0
- package/dist/ui/assets/ron-VUp2lXgN.js +1 -0
- package/dist/ui/assets/rose-pine-BthvhNj6.js +1 -0
- package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
- package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +1 -0
- package/dist/ui/assets/rosmsg-CAekHB0j.js +1 -0
- package/dist/ui/assets/rst-EoAOr3M6.js +1 -0
- package/dist/ui/assets/ruby-Dqx5_Rqw.js +1 -0
- package/dist/ui/assets/rust-Cfkwpbl8.js +1 -0
- package/dist/ui/assets/sas-Bf6xPLSX.js +1 -0
- package/dist/ui/assets/sass-DXrisJhu.js +1 -0
- package/dist/ui/assets/scala-DKOlJaKm.js +1 -0
- package/dist/ui/assets/scheme-DQCgrYNe.js +1 -0
- package/dist/ui/assets/scrollbar-DX4Ujotb.js +287 -0
- package/dist/ui/assets/scss-DDpW3yTd.js +1 -0
- package/dist/ui/assets/sdbl-bTVj8UrX.js +1 -0
- package/dist/ui/assets/shaderlab-TOUzSsQk.js +1 -0
- package/dist/ui/assets/shellscript-DayAQ-W9.js +1 -0
- package/dist/ui/assets/shellsession-jPr_lSnA.js +1 -0
- package/dist/ui/assets/slack-dark-DnToyrRv.js +1 -0
- package/dist/ui/assets/slack-ochin-B2OO5cIa.js +1 -0
- package/dist/ui/assets/smalltalk-B16xEiuN.js +1 -0
- package/dist/ui/assets/snazzy-light-4G7pJPwS.js +1 -0
- package/dist/ui/assets/solarized-dark-DV17i1UV.js +1 -0
- package/dist/ui/assets/solarized-light-DSh2HLQt.js +1 -0
- package/dist/ui/assets/solidity-CKzVLygQ.js +1 -0
- package/dist/ui/assets/soy-X9adks8G.js +1 -0
- package/dist/ui/assets/sparql-D_iOobhT.js +1 -0
- package/dist/ui/assets/splunk-BC2Px7Mm.js +1 -0
- package/dist/ui/assets/sql-Bmt09AIR.js +1 -0
- package/dist/ui/assets/ssh-config-BgfXC-Er.js +1 -0
- package/dist/ui/assets/stata-DVkNpH8r.js +1 -0
- package/dist/ui/assets/stylus-B6D30XZt.js +1 -0
- package/dist/ui/assets/surrealql-eEXzMb8j.js +1 -0
- package/dist/ui/assets/svelte-CFoBxZF3.js +1 -0
- package/dist/ui/assets/swift-DonLKvLd.js +1 -0
- package/dist/ui/assets/synthwave-84-nFMaYfgc.js +1 -0
- package/dist/ui/assets/system-verilog-DJ5XKQeo.js +1 -0
- package/dist/ui/assets/systemd-BxMlprV5.js +1 -0
- package/dist/ui/assets/talonscript-CohzipZa.js +1 -0
- package/dist/ui/assets/tasl-DMoTqEGO.js +1 -0
- package/dist/ui/assets/tcl-CZd0xW_V.js +1 -0
- package/dist/ui/assets/templ-Da_324JF.js +1 -0
- package/dist/ui/assets/terraform-DswuEJGm.js +1 -0
- package/dist/ui/assets/tex-HAzlmKJ0.js +1 -0
- package/dist/ui/assets/tokyo-night-oM2G3aXe.js +1 -0
- package/dist/ui/assets/toml-CcmNWLt0.js +1 -0
- package/dist/ui/assets/ts-tags-7iLrNH8p.js +1 -0
- package/dist/ui/assets/tsv-sltzmVWM.js +1 -0
- package/dist/ui/assets/tsx-gZaXf8PJ.js +1 -0
- package/dist/ui/assets/turtle-ByJddavk.js +1 -0
- package/dist/ui/assets/twig-CLpQ7p1N.js +1 -0
- package/dist/ui/assets/typescript-B2WWCRI2.js +1 -0
- package/dist/ui/assets/typespec-B88KGewJ.js +1 -0
- package/dist/ui/assets/typst-DI99ib-x.js +1 -0
- package/dist/ui/assets/v-DETTlOr0.js +1 -0
- package/dist/ui/assets/vala-zf12oZj6.js +1 -0
- package/dist/ui/assets/vb-Djn5o6TS.js +1 -0
- package/dist/ui/assets/verilog-CiiDBU1e.js +1 -0
- package/dist/ui/assets/vesper-D5bVUKB1.js +1 -0
- package/dist/ui/assets/vhdl-BroJfC0k.js +1 -0
- package/dist/ui/assets/viml-DvXPmvsu.js +1 -0
- package/dist/ui/assets/vitesse-black-fwtXNY1n.js +1 -0
- package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +1 -0
- package/dist/ui/assets/vitesse-light-VbXTXTou.js +1 -0
- package/dist/ui/assets/vue-No_8Jygd.js +1 -0
- package/dist/ui/assets/vue-html-kHJg98Kk.js +1 -0
- package/dist/ui/assets/vue-vine-Df4cEYaN.js +1 -0
- package/dist/ui/assets/vyper-CgoNMtux.js +1 -0
- package/dist/ui/assets/wasm-BnjxR4X6.js +1 -0
- package/dist/ui/assets/wasm-ByWQv1Qj.js +1 -0
- package/dist/ui/assets/wenyan-C8pVoKbM.js +1 -0
- package/dist/ui/assets/wgsl-BsKzXJz4.js +1 -0
- package/dist/ui/assets/wikitext-ClFFjSW2.js +1 -0
- package/dist/ui/assets/wit-DdvCle-K.js +1 -0
- package/dist/ui/assets/wolfram-DLL8P-h_.js +1 -0
- package/dist/ui/assets/workspace-app-C_wsC6VL.js +117 -0
- package/dist/ui/assets/workspace-app-DHvE2ojW.css +1 -0
- package/dist/ui/assets/xml-DUZ05dpG.js +1 -0
- package/dist/ui/assets/xsl-Bwp3w2OF.js +1 -0
- package/dist/ui/assets/yaml-IA_-TEM1.js +1 -0
- package/dist/ui/assets/zenscript-BnlCZFoB.js +1 -0
- package/dist/ui/assets/zig-CMLA9XwU.js +1 -0
- package/dist/ui/workspace-app.html +15 -0
- package/dist/user-config.js +97 -0
- package/dist/workspace-store.js +162 -0
- package/dist/workspaces.js +528 -0
- package/docs/agent-profile-schema.md +119 -0
- package/docs/artifact-exchange.md +63 -0
- package/docs/chatgpt-coding-workflow.md +183 -0
- package/docs/configuration.md +197 -0
- package/docs/gotchas.md +243 -0
- package/docs/roadmap.md +195 -0
- package/docs/security.md +142 -0
- package/docs/setup.md +132 -0
- package/docs/versioning.md +189 -0
- package/examples/agents/claude-implementer.md +30 -0
- package/examples/agents/codex-explorer.md +27 -0
- package/examples/agents/codex-qa-tester.md +29 -0
- package/examples/agents/codex-worker.md +25 -0
- package/examples/agents/copilot-reviewer.md +25 -0
- package/examples/agents/cursor-agent-worker.md +26 -0
- package/examples/agents/opencode-explorer.md +27 -0
- package/examples/agents/pi-reviewer.md +27 -0
- package/package.json +102 -0
- package/scripts/dev-server.mjs +120 -0
- package/scripts/fix-node-pty-permissions.mjs +22 -0
- package/scripts/release-version.mjs +207 -0
- package/skills/subagent-delegation/SKILL.md +132 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: forgerelay-agent/v1
|
|
3
|
+
name: codex-qa-tester
|
|
4
|
+
description: Manual QA profile for browser testing, workflow verification, and regression checks.
|
|
5
|
+
provider: codex
|
|
6
|
+
model: gpt-5.4-mini
|
|
7
|
+
thinking: high
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Verify the requested user workflow from the outside, like a QA pass before
|
|
11
|
+
release. Prefer running the app and using browser tools when the task involves
|
|
12
|
+
UI, navigation, forms, visual states, or end-to-end behavior.
|
|
13
|
+
|
|
14
|
+
- Do not modify files.
|
|
15
|
+
- Start from the acceptance criteria in the prompt; turn vague requests into a small checklist.
|
|
16
|
+
- Use the browser to exercise real interactions when a local preview or dev server is available.
|
|
17
|
+
- Cover the main happy path plus at least one realistic edge or failure state.
|
|
18
|
+
- Capture exact reproduction steps for every issue found.
|
|
19
|
+
- Distinguish confirmed failures from untested risks.
|
|
20
|
+
|
|
21
|
+
Report:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
qa_summary:
|
|
25
|
+
checks_run:
|
|
26
|
+
issues_found:
|
|
27
|
+
reproduction_steps:
|
|
28
|
+
untested_risks:
|
|
29
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: forgerelay-agent/v1
|
|
3
|
+
name: codex-worker
|
|
4
|
+
description: Implementation profile for focused coding tasks with clear acceptance criteria.
|
|
5
|
+
provider: codex
|
|
6
|
+
model: gpt-5.4
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Implement the requested change with minimal surface area. Use this profile when
|
|
10
|
+
the prompt already defines the desired behavior or acceptance criteria.
|
|
11
|
+
|
|
12
|
+
- Read nearby code before editing.
|
|
13
|
+
- Match existing project patterns instead of introducing new abstractions.
|
|
14
|
+
- Keep unrelated files, formatting, and dependency metadata untouched.
|
|
15
|
+
- Prefer targeted tests for the changed behavior.
|
|
16
|
+
- Surface build, test, or environment failures exactly; do not summarize them as success.
|
|
17
|
+
|
|
18
|
+
Report:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
summary:
|
|
22
|
+
tests_run:
|
|
23
|
+
blockers:
|
|
24
|
+
notes:
|
|
25
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: forgerelay-agent/v1
|
|
3
|
+
name: copilot-reviewer
|
|
4
|
+
description: Read-only review profile for bug risk, regressions, and missing test coverage.
|
|
5
|
+
provider: copilot
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Review the requested code path or diff without editing. Prioritize concrete
|
|
9
|
+
bugs, behavior regressions, security issues, and missing tests over style
|
|
10
|
+
preferences.
|
|
11
|
+
|
|
12
|
+
- Do not modify files.
|
|
13
|
+
- Lead with findings ordered by severity.
|
|
14
|
+
- Tie each finding to a specific file, symbol, or behavior.
|
|
15
|
+
- Ignore purely subjective style feedback unless it creates a maintenance risk.
|
|
16
|
+
- If no issue is found, say that clearly and mention any residual test or runtime risk.
|
|
17
|
+
|
|
18
|
+
Report:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
findings:
|
|
22
|
+
evidence:
|
|
23
|
+
test_gaps:
|
|
24
|
+
residual_risk:
|
|
25
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: forgerelay-agent/v1
|
|
3
|
+
name: cursor-agent-worker
|
|
4
|
+
description: Implementation profile for UI-heavy changes, small refactors, and alternative solution passes.
|
|
5
|
+
provider: cursor
|
|
6
|
+
model: composer-2.5-fast
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Work on the requested change with a bias toward practical, shippable edits. This
|
|
10
|
+
profile is useful for UI polish, small refactors, and trying an alternate
|
|
11
|
+
implementation path.
|
|
12
|
+
|
|
13
|
+
- Keep edits scoped to the requested workflow or component.
|
|
14
|
+
- Preserve existing visual language and interaction patterns.
|
|
15
|
+
- Avoid changing data contracts or public APIs unless the prompt asks for it.
|
|
16
|
+
- Check responsive and empty/error states when touching UI.
|
|
17
|
+
- Report what was verified and what still needs a human look.
|
|
18
|
+
|
|
19
|
+
Report:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
summary:
|
|
23
|
+
verification:
|
|
24
|
+
blockers:
|
|
25
|
+
open_questions:
|
|
26
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: forgerelay-agent/v1
|
|
3
|
+
name: opencode-explorer
|
|
4
|
+
description: Read-only profile for fast relevant-file discovery and small architecture questions.
|
|
5
|
+
provider: opencode
|
|
6
|
+
model: opencode/deepseek-v4-flash-free
|
|
7
|
+
thinking: high
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Find the answer quickly without editing. Use this profile when the main need is
|
|
11
|
+
to identify relevant files, understand a small code path, or gather enough
|
|
12
|
+
context before implementation.
|
|
13
|
+
|
|
14
|
+
- Do not modify files.
|
|
15
|
+
- Search first, then read only the files needed to answer the prompt.
|
|
16
|
+
- Prefer precise file paths and symbols over broad summaries.
|
|
17
|
+
- Keep the response short unless the code path is genuinely complex.
|
|
18
|
+
- State uncertainty when evidence is incomplete.
|
|
19
|
+
|
|
20
|
+
Report:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
answer:
|
|
24
|
+
evidence:
|
|
25
|
+
relevant_files:
|
|
26
|
+
unknowns:
|
|
27
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: forgerelay-agent/v1
|
|
3
|
+
name: pi-reviewer
|
|
4
|
+
description: Read-only review profile for quick risk checks and targeted implementation questions.
|
|
5
|
+
provider: pi
|
|
6
|
+
model: openai-codex/gpt-5.5
|
|
7
|
+
thinking: high
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Review or investigate only the area requested. This profile is best for quick
|
|
11
|
+
risk checks, small diffs, and targeted questions where a concise answer is more
|
|
12
|
+
valuable than a broad audit.
|
|
13
|
+
|
|
14
|
+
- Do not modify files.
|
|
15
|
+
- Focus on actionable issues that could affect correctness, safety, or tests.
|
|
16
|
+
- Cite the specific code evidence for each point.
|
|
17
|
+
- Avoid broad rewrite suggestions unless the current design blocks the requested behavior.
|
|
18
|
+
- Keep low-confidence observations under `unknowns`.
|
|
19
|
+
|
|
20
|
+
Report:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
findings:
|
|
24
|
+
evidence:
|
|
25
|
+
risk_level:
|
|
26
|
+
unknowns:
|
|
27
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@akira-tl/forgerelay",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local development control plane for MCP coding agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"homepage": "https://github.com/Akira-TL/forgerelay#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Akira-TL/forgerelay.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/Akira-TL/forgerelay/issues"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/server.js",
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22.19 <27"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"forgerelay": "dist/cli.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"docs/*.md",
|
|
24
|
+
"examples",
|
|
25
|
+
"scripts",
|
|
26
|
+
"skills",
|
|
27
|
+
"README.md",
|
|
28
|
+
"CHANGELOG.md",
|
|
29
|
+
"NOTICE.md"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"tag": "latest"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
37
|
+
"build": "npm run clean && npm run build:app && tsc -p tsconfig.build.json",
|
|
38
|
+
"build:app": "vite build",
|
|
39
|
+
"dev": "node scripts/dev-server.mjs",
|
|
40
|
+
"postinstall": "node scripts/fix-node-pty-permissions.mjs",
|
|
41
|
+
"start": "node dist/cli.js serve",
|
|
42
|
+
"test": "tsx src/config.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/request-meta.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/local-agent-runtime.test.ts && tsx src/local-agent-adapters.test.ts && tsx src/local-agent-availability.test.ts && tsx src/local-agent-profiles.test.ts && tsx src/local-agent-targets.test.ts && tsx src/local-agent-store.test.ts && tsx src/roots.test.ts && tsx src/skills.test.ts && tsx src/workspaces.test.ts && tsx src/workspace-conversation.test.ts && tsx src/review-checkpoints.test.ts && tsx src/server.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts",
|
|
43
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
44
|
+
"release:check": "node scripts/release-version.mjs check",
|
|
45
|
+
"release:tag-check": "node scripts/release-version.mjs tag",
|
|
46
|
+
"release:next": "node scripts/release-version.mjs next patch",
|
|
47
|
+
"release:patch": "node scripts/release-version.mjs next patch",
|
|
48
|
+
"release:minor": "node scripts/release-version.mjs next minor",
|
|
49
|
+
"release:major": "node scripts/release-version.mjs next major",
|
|
50
|
+
"release:verify": "npm run release:check && npm run typecheck && npm test && npm run build"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"mcp",
|
|
54
|
+
"chatgpt",
|
|
55
|
+
"coding-agent",
|
|
56
|
+
"developer-tools",
|
|
57
|
+
"git-worktree"
|
|
58
|
+
],
|
|
59
|
+
"author": "Akira-TL",
|
|
60
|
+
"license": "MIT",
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@agentclientprotocol/sdk": "^1.1.0",
|
|
63
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.200",
|
|
64
|
+
"@clack/prompts": "^1.5.1",
|
|
65
|
+
"@earendil-works/pi-coding-agent": "^0.80.3",
|
|
66
|
+
"@modelcontextprotocol/ext-apps": "^1.7.2",
|
|
67
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
68
|
+
"@openai/codex-sdk": "^0.142.5",
|
|
69
|
+
"@opencode-ai/sdk": "^1.17.13",
|
|
70
|
+
"@pierre/diffs": "^1.2.5",
|
|
71
|
+
"better-sqlite3": "^12.10.0",
|
|
72
|
+
"diff": "^8.0.3",
|
|
73
|
+
"drizzle-orm": "^0.45.2",
|
|
74
|
+
"express": "^5.2.1",
|
|
75
|
+
"lucide": "^1.24.0",
|
|
76
|
+
"react": "^19.2.6",
|
|
77
|
+
"react-dom": "^19.2.6",
|
|
78
|
+
"semver": "^7.8.4",
|
|
79
|
+
"yaml": "^2.9.0",
|
|
80
|
+
"zod": "^4.4.3"
|
|
81
|
+
},
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
84
|
+
"@types/express": "^5.0.6",
|
|
85
|
+
"@types/node": "^25.9.1",
|
|
86
|
+
"@types/react": "^19.2.15",
|
|
87
|
+
"@types/react-dom": "^19.2.3",
|
|
88
|
+
"@types/semver": "^7.7.1",
|
|
89
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
90
|
+
"tsx": "^4.22.3",
|
|
91
|
+
"typescript": "^6.0.3",
|
|
92
|
+
"vite": "^8.0.14"
|
|
93
|
+
},
|
|
94
|
+
"overrides": {
|
|
95
|
+
"protobufjs": "7.6.4",
|
|
96
|
+
"ws": "8.21.0",
|
|
97
|
+
"undici": "8.5.0"
|
|
98
|
+
},
|
|
99
|
+
"optionalDependencies": {
|
|
100
|
+
"node-pty": "^1.1.0"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { readdirSync, statSync, watch } from "node:fs";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const repoRoot = resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
7
|
+
const watchRoots = ["src"].map((entry) => join(repoRoot, entry));
|
|
8
|
+
const restartDelayMs = 750;
|
|
9
|
+
const crashDelayMs = 1500;
|
|
10
|
+
|
|
11
|
+
let child;
|
|
12
|
+
let restartTimer;
|
|
13
|
+
let stoppingForRestart = false;
|
|
14
|
+
let shuttingDown = false;
|
|
15
|
+
|
|
16
|
+
function log(message) {
|
|
17
|
+
console.error(`[forgerelay:dev] ${message}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function start() {
|
|
21
|
+
stoppingForRestart = false;
|
|
22
|
+
child = spawn("npx", ["tsx", "src/cli.ts", "serve"], {
|
|
23
|
+
cwd: repoRoot,
|
|
24
|
+
env: process.env,
|
|
25
|
+
stdio: "inherit",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
child.on("exit", (code, signal) => {
|
|
29
|
+
child = undefined;
|
|
30
|
+
if (shuttingDown) return;
|
|
31
|
+
if (stoppingForRestart) return;
|
|
32
|
+
|
|
33
|
+
log(`server exited (${signal ?? code ?? "unknown"}); restarting in ${crashDelayMs}ms`);
|
|
34
|
+
scheduleRestart(crashDelayMs);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function scheduleRestart(delayMs = restartDelayMs) {
|
|
39
|
+
clearTimeout(restartTimer);
|
|
40
|
+
restartTimer = setTimeout(restart, delayMs);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function restart() {
|
|
44
|
+
if (shuttingDown) return;
|
|
45
|
+
clearTimeout(restartTimer);
|
|
46
|
+
|
|
47
|
+
if (!child) {
|
|
48
|
+
start();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
stoppingForRestart = true;
|
|
53
|
+
child.once("exit", () => {
|
|
54
|
+
if (!shuttingDown) start();
|
|
55
|
+
});
|
|
56
|
+
child.kill("SIGTERM");
|
|
57
|
+
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
if (child && stoppingForRestart) child.kill("SIGKILL");
|
|
60
|
+
}, 3000).unref();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function watchDirectory(root) {
|
|
64
|
+
const watchers = [];
|
|
65
|
+
const seen = new Set();
|
|
66
|
+
|
|
67
|
+
function addDirectory(dir) {
|
|
68
|
+
if (seen.has(dir)) return;
|
|
69
|
+
seen.add(dir);
|
|
70
|
+
|
|
71
|
+
const watcher = watch(dir, (event, filename) => {
|
|
72
|
+
if (!filename) {
|
|
73
|
+
scheduleRestart();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const path = join(dir, filename.toString());
|
|
78
|
+
if (event === "rename") maybeAddDirectory(path);
|
|
79
|
+
scheduleRestart();
|
|
80
|
+
});
|
|
81
|
+
watchers.push(watcher);
|
|
82
|
+
|
|
83
|
+
for (const entry of readdirSync(dir)) {
|
|
84
|
+
maybeAddDirectory(join(dir, entry));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function maybeAddDirectory(path) {
|
|
89
|
+
try {
|
|
90
|
+
const stats = statSync(path);
|
|
91
|
+
if (stats.isDirectory()) addDirectory(path);
|
|
92
|
+
} catch {
|
|
93
|
+
// The file may have been deleted between the watch event and stat call.
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
addDirectory(root);
|
|
98
|
+
return watchers;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function shutdown() {
|
|
102
|
+
shuttingDown = true;
|
|
103
|
+
clearTimeout(restartTimer);
|
|
104
|
+
if (!child) return process.exit(0);
|
|
105
|
+
|
|
106
|
+
child.once("exit", () => process.exit(0));
|
|
107
|
+
child.kill("SIGTERM");
|
|
108
|
+
setTimeout(() => process.exit(1), 3000).unref();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
112
|
+
process.on(signal, shutdown);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
for (const root of watchRoots) {
|
|
116
|
+
watchDirectory(root);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
log("watching src; server restarts on changes and after crashes");
|
|
120
|
+
start();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { chmod } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
if (process.platform === "darwin") {
|
|
6
|
+
const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
7
|
+
for (const architecture of ["arm64", "x64"]) {
|
|
8
|
+
const helper = resolve(
|
|
9
|
+
projectRoot,
|
|
10
|
+
"node_modules",
|
|
11
|
+
"node-pty",
|
|
12
|
+
"prebuilds",
|
|
13
|
+
`darwin-${architecture}`,
|
|
14
|
+
"spawn-helper",
|
|
15
|
+
);
|
|
16
|
+
try {
|
|
17
|
+
await chmod(helper, 0o755);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error.code !== "ENOENT") throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
+
const packagePath = resolve(repoRoot, "package.json");
|
|
7
|
+
const lockPath = resolve(repoRoot, "package-lock.json");
|
|
8
|
+
const changelogPath = resolve(repoRoot, "CHANGELOG.md");
|
|
9
|
+
const noticePath = resolve(repoRoot, "NOTICE.md");
|
|
10
|
+
const licensePath = resolve(repoRoot, "LICENSE");
|
|
11
|
+
const stableVersionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
12
|
+
const expectedPackageName = "@akira-tl/forgerelay";
|
|
13
|
+
const expectedRepositoryUrl = "git+https://github.com/Akira-TL/forgerelay.git";
|
|
14
|
+
const expectedHomepage = "https://github.com/Akira-TL/forgerelay#readme";
|
|
15
|
+
const expectedBugsUrl = "https://github.com/Akira-TL/forgerelay/issues";
|
|
16
|
+
|
|
17
|
+
const [command = "check", argument, ...rest] = process.argv.slice(2);
|
|
18
|
+
const dryRun = rest.includes("--dry-run") || argument === "--dry-run";
|
|
19
|
+
const value = argument === "--dry-run" ? undefined : argument;
|
|
20
|
+
const state = await readState();
|
|
21
|
+
|
|
22
|
+
switch (command) {
|
|
23
|
+
case "check":
|
|
24
|
+
checkState(state);
|
|
25
|
+
console.log(`release metadata is consistent at ${state.pkg.version}`);
|
|
26
|
+
break;
|
|
27
|
+
case "tag": {
|
|
28
|
+
checkState(state);
|
|
29
|
+
if (!value) fail("usage: node scripts/release-version.mjs tag vX.Y.Z");
|
|
30
|
+
if (getUnreleasedBody(state.changelog)) {
|
|
31
|
+
fail("CHANGELOG.md still has Unreleased changes; prepare the next version before creating a release tag");
|
|
32
|
+
}
|
|
33
|
+
const expectedTag = `v${state.pkg.version}`;
|
|
34
|
+
if (value !== expectedTag) {
|
|
35
|
+
fail(`tag ${JSON.stringify(value)} does not match package version; expected ${expectedTag}`);
|
|
36
|
+
}
|
|
37
|
+
console.log(`release tag ${value} matches package version and changelog`);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case "next": {
|
|
41
|
+
checkState(state);
|
|
42
|
+
const bump = value ?? "patch";
|
|
43
|
+
if (!new Set(["patch", "minor", "major"]).has(bump)) {
|
|
44
|
+
fail("usage: node scripts/release-version.mjs next [patch|minor|major] [--dry-run]");
|
|
45
|
+
}
|
|
46
|
+
await prepareRelease(state, incrementVersion(state.pkg.version, bump), dryRun);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
default:
|
|
50
|
+
fail(`unknown release command ${JSON.stringify(command)}; expected check, tag, or next`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function readState() {
|
|
54
|
+
const [packageText, lockText, changelog, notice, license] = await Promise.all([
|
|
55
|
+
readFile(packagePath, "utf8"),
|
|
56
|
+
readFile(lockPath, "utf8"),
|
|
57
|
+
readFile(changelogPath, "utf8"),
|
|
58
|
+
readFile(noticePath, "utf8"),
|
|
59
|
+
readFile(licensePath, "utf8"),
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
packageText,
|
|
64
|
+
lockText,
|
|
65
|
+
changelog,
|
|
66
|
+
notice,
|
|
67
|
+
license,
|
|
68
|
+
pkg: JSON.parse(packageText),
|
|
69
|
+
lock: JSON.parse(lockText),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function checkState(state) {
|
|
74
|
+
const version = state.pkg.version;
|
|
75
|
+
if (state.pkg.name !== expectedPackageName) {
|
|
76
|
+
fail(`unexpected package name ${JSON.stringify(state.pkg.name)}; expected ${expectedPackageName}`);
|
|
77
|
+
}
|
|
78
|
+
if (typeof version !== "string" || !stableVersionPattern.test(version)) {
|
|
79
|
+
fail(`package version ${JSON.stringify(version)} must be a stable X.Y.Z version`);
|
|
80
|
+
}
|
|
81
|
+
if (state.pkg.repository?.url !== expectedRepositoryUrl) {
|
|
82
|
+
fail(`package repository.url must be ${expectedRepositoryUrl} for GitHub/npm trusted publishing`);
|
|
83
|
+
}
|
|
84
|
+
if (state.pkg.homepage !== expectedHomepage) {
|
|
85
|
+
fail(`package homepage must be ${expectedHomepage}`);
|
|
86
|
+
}
|
|
87
|
+
if (state.pkg.bugs?.url !== expectedBugsUrl) {
|
|
88
|
+
fail(`package bugs.url must be ${expectedBugsUrl}`);
|
|
89
|
+
}
|
|
90
|
+
if (state.pkg.publishConfig?.access !== "public") {
|
|
91
|
+
fail("package publishConfig.access must be public");
|
|
92
|
+
}
|
|
93
|
+
if (state.pkg.publishConfig?.tag !== "latest") {
|
|
94
|
+
fail("package publishConfig.tag must be latest");
|
|
95
|
+
}
|
|
96
|
+
if (state.pkg.bin?.forgerelay !== "dist/cli.js") {
|
|
97
|
+
fail("package bin.forgerelay must point to dist/cli.js");
|
|
98
|
+
}
|
|
99
|
+
if (state.lock.name !== expectedPackageName || state.lock.version !== version) {
|
|
100
|
+
fail("package-lock.json root name/version does not match package.json");
|
|
101
|
+
}
|
|
102
|
+
if (state.lock.packages?.[""]?.name !== expectedPackageName || state.lock.packages?.[""]?.version !== version) {
|
|
103
|
+
fail("package-lock root package name/version does not match package.json");
|
|
104
|
+
}
|
|
105
|
+
if (!state.changelog.includes("## [Unreleased]")) {
|
|
106
|
+
fail("CHANGELOG.md is missing ## [Unreleased]");
|
|
107
|
+
}
|
|
108
|
+
if (!state.changelog.includes(`## [${version}]`)) {
|
|
109
|
+
fail(`CHANGELOG.md is missing the current release heading ## [${version}]`);
|
|
110
|
+
}
|
|
111
|
+
checkAttribution(state);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function checkAttribution(state) {
|
|
115
|
+
if (!state.license.includes("Copyright (c) 2026 Waishnav")) {
|
|
116
|
+
fail("LICENSE must preserve the upstream Waishnav copyright notice");
|
|
117
|
+
}
|
|
118
|
+
if (!state.license.includes("Copyright (c) 2026 Akira-TL, modifications")) {
|
|
119
|
+
fail("LICENSE must identify Akira-TL modifications");
|
|
120
|
+
}
|
|
121
|
+
if (!state.notice.includes("https://github.com/Waishnav/devspace")) {
|
|
122
|
+
fail("NOTICE.md must identify the upstream DevSpace repository");
|
|
123
|
+
}
|
|
124
|
+
if (!state.notice.includes("independently maintained by Akira-TL")) {
|
|
125
|
+
fail("NOTICE.md must identify this distribution as independently maintained by Akira-TL");
|
|
126
|
+
}
|
|
127
|
+
if (!state.pkg.files?.includes("NOTICE.md")) {
|
|
128
|
+
fail("package files must include NOTICE.md");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function prepareRelease(state, nextVersion, dryRun) {
|
|
133
|
+
const nextChangelog = promoteUnreleased(state.changelog, nextVersion);
|
|
134
|
+
const nextPackage = { ...state.pkg, version: nextVersion };
|
|
135
|
+
const nextLock = structuredClone(state.lock);
|
|
136
|
+
nextLock.version = nextVersion;
|
|
137
|
+
nextLock.packages[""].version = nextVersion;
|
|
138
|
+
|
|
139
|
+
if (dryRun) {
|
|
140
|
+
console.log(`${state.pkg.version} -> ${nextVersion}`);
|
|
141
|
+
console.log("dry run only; no files changed");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await Promise.all([
|
|
146
|
+
writeFile(packagePath, `${JSON.stringify(nextPackage, null, 2)}\n`),
|
|
147
|
+
writeFile(lockPath, `${JSON.stringify(nextLock, null, 2)}\n`),
|
|
148
|
+
writeFile(changelogPath, nextChangelog),
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
console.log(`${state.pkg.version} -> ${nextVersion}`);
|
|
152
|
+
console.log("updated package.json, package-lock.json, and CHANGELOG.md");
|
|
153
|
+
console.log("next: review the diff, run npm run release:verify, commit, then push the matching vX.Y.Z tag");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function promoteUnreleased(changelog, nextVersion) {
|
|
157
|
+
const unreleasedBody = getUnreleasedBody(changelog);
|
|
158
|
+
if (!unreleasedBody) {
|
|
159
|
+
fail("CHANGELOG.md Unreleased section is empty; add release notes before preparing a release");
|
|
160
|
+
}
|
|
161
|
+
if (changelog.includes(`## [${nextVersion}]`)) {
|
|
162
|
+
fail(`CHANGELOG.md already contains release ${nextVersion}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const heading = "## [Unreleased]";
|
|
166
|
+
const headingIndex = changelog.indexOf(heading);
|
|
167
|
+
const bodyStart = headingIndex + heading.length;
|
|
168
|
+
const nextHeadingIndex = changelog.indexOf("\n## [", bodyStart);
|
|
169
|
+
const bodyEnd = nextHeadingIndex < 0 ? changelog.length : nextHeadingIndex;
|
|
170
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
171
|
+
const replacement = `${heading}\n\n## [${nextVersion}] - ${date}\n\n${unreleasedBody}\n`;
|
|
172
|
+
return `${changelog.slice(0, headingIndex)}${replacement}${changelog.slice(bodyEnd)}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getUnreleasedBody(changelog) {
|
|
176
|
+
const heading = "## [Unreleased]";
|
|
177
|
+
const headingIndex = changelog.indexOf(heading);
|
|
178
|
+
if (headingIndex < 0) return "";
|
|
179
|
+
const bodyStart = headingIndex + heading.length;
|
|
180
|
+
const nextHeadingIndex = changelog.indexOf("\n## [", bodyStart);
|
|
181
|
+
const bodyEnd = nextHeadingIndex < 0 ? changelog.length : nextHeadingIndex;
|
|
182
|
+
return changelog.slice(bodyStart, bodyEnd).trim();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function incrementVersion(version, bump) {
|
|
186
|
+
const match = version.match(stableVersionPattern);
|
|
187
|
+
if (!match) fail(`cannot increment invalid stable version ${JSON.stringify(version)}`);
|
|
188
|
+
let major = Number(match[1]);
|
|
189
|
+
let minor = Number(match[2]);
|
|
190
|
+
let patch = Number(match[3]);
|
|
191
|
+
if (bump === "major") {
|
|
192
|
+
major += 1;
|
|
193
|
+
minor = 0;
|
|
194
|
+
patch = 0;
|
|
195
|
+
} else if (bump === "minor") {
|
|
196
|
+
minor += 1;
|
|
197
|
+
patch = 0;
|
|
198
|
+
} else {
|
|
199
|
+
patch += 1;
|
|
200
|
+
}
|
|
201
|
+
return `${major}.${minor}.${patch}`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function fail(message) {
|
|
205
|
+
console.error(`release-version: ${message}`);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|