@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,377 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { constants as fsConstants } from "node:fs";
|
|
3
|
+
import { link, lstat, mkdir, open, readdir, unlink, } from "node:fs/promises";
|
|
4
|
+
import { isAbsolute, join, normalize, sep } from "node:path";
|
|
5
|
+
import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
|
|
6
|
+
import * as z from "zod/v4";
|
|
7
|
+
import { ArtifactError } from "./artifact-error.js";
|
|
8
|
+
import { describeIncomingArtifactValue, IncomingArtifactAdapterRegistry, } from "./incoming-artifacts.js";
|
|
9
|
+
import { logEvent } from "./logger.js";
|
|
10
|
+
const ARTIFACT_WRITE_ANNOTATIONS = {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
idempotentHint: false,
|
|
14
|
+
openWorldHint: true,
|
|
15
|
+
};
|
|
16
|
+
const NO_FOLLOW = fsConstants.O_NOFOLLOW ?? 0;
|
|
17
|
+
const DIRECTORY_FLAGS = fsConstants.O_RDONLY | (fsConstants.O_DIRECTORY ?? 0) | NO_FOLLOW;
|
|
18
|
+
const PARTIAL_PREFIX = ".forgerelay-download-";
|
|
19
|
+
const PARTIAL_SUFFIX = ".partial";
|
|
20
|
+
const STALE_PARTIAL_AGE_MS = 24 * 60 * 60 * 1_000;
|
|
21
|
+
const MAX_STALE_PARTIAL_CLEANUP = 32;
|
|
22
|
+
const ARTIFACT_DOWNLOAD_PLATFORMS = new Set(["linux"]);
|
|
23
|
+
const openAIFileReferenceInputSchema = z.strictObject({
|
|
24
|
+
download_url: z.string(),
|
|
25
|
+
file_id: z.string(),
|
|
26
|
+
mime_type: z.string().nullable().optional(),
|
|
27
|
+
file_name: z.string().nullable().optional(),
|
|
28
|
+
name: z.string().nullable().optional(),
|
|
29
|
+
size: z.number().int().nonnegative().nullable().optional(),
|
|
30
|
+
});
|
|
31
|
+
export function isArtifactDownloadSupportedPlatform(platform = process.platform) {
|
|
32
|
+
return ARTIFACT_DOWNLOAD_PLATFORMS.has(platform);
|
|
33
|
+
}
|
|
34
|
+
export function registerArtifactTools(server, { config, workspaces, incomingArtifactAdapters = [], }) {
|
|
35
|
+
const incomingRegistry = new IncomingArtifactAdapterRegistry(incomingArtifactAdapters);
|
|
36
|
+
registerAppTool(server, "download_artifact", {
|
|
37
|
+
title: "Download attached or generated file",
|
|
38
|
+
description: "Stream one MCP-host-provided native file to a requested relative path inside an already-open workspace. Existing destinations, arbitrary URLs, absolute paths, traversal, symlinked parents, local source paths, and malformed file objects are rejected.",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
file: openAIFileReferenceInputSchema.describe("Native file value authorized and supplied by the MCP host."),
|
|
41
|
+
workspaceId: z.string().min(1).describe("Workspace identifier returned by open_workspace."),
|
|
42
|
+
path: z.string().min(1).describe("Relative destination path inside the selected workspace. The destination must not already exist."),
|
|
43
|
+
},
|
|
44
|
+
outputSchema: {
|
|
45
|
+
path: z.string(),
|
|
46
|
+
},
|
|
47
|
+
_meta: { "openai/fileParams": ["file"] },
|
|
48
|
+
annotations: ARTIFACT_WRITE_ANNOTATIONS,
|
|
49
|
+
}, async (input) => executeArtifactTool(config, input, async () => {
|
|
50
|
+
const workspace = workspaces.getWorkspace(input.workspaceId);
|
|
51
|
+
const downloaded = await downloadIncomingArtifact({
|
|
52
|
+
registry: incomingRegistry,
|
|
53
|
+
workspaceId: workspace.id,
|
|
54
|
+
workspaceRoot: workspace.root,
|
|
55
|
+
maxFileBytes: config.artifactMaxFileBytes,
|
|
56
|
+
file: input.file,
|
|
57
|
+
path: input.path,
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
publicResult: { path: downloaded.path },
|
|
61
|
+
logResult: downloaded,
|
|
62
|
+
};
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Stream a trusted native file directly into one already-open workspace.
|
|
67
|
+
*
|
|
68
|
+
* Bytes are written to an exclusive partial beside the requested destination,
|
|
69
|
+
* hashed and size-checked, fsynced, and only then published without overwriting
|
|
70
|
+
* the requested workspace path. No project-level staging directory is created.
|
|
71
|
+
*/
|
|
72
|
+
export async function downloadIncomingArtifact({ registry, workspaceId, workspaceRoot, maxFileBytes, file, path, publishLink = link, }) {
|
|
73
|
+
if (!isArtifactDownloadSupportedPlatform()) {
|
|
74
|
+
throw new ArtifactError("artifact_platform_unsupported", "Native file download requires descriptor-anchored directory operations on this platform.");
|
|
75
|
+
}
|
|
76
|
+
if (!Number.isSafeInteger(maxFileBytes) || maxFileBytes < 1) {
|
|
77
|
+
throw new ArtifactError("artifact_limit_invalid", "Artifact file-size limit must be a positive integer.");
|
|
78
|
+
}
|
|
79
|
+
if (!workspaceId) {
|
|
80
|
+
throw new ArtifactError("artifact_workspace_invalid", "A selected workspace is required for native file download.");
|
|
81
|
+
}
|
|
82
|
+
const destination = normalizeArtifactDestination(path);
|
|
83
|
+
const opened = await registry.open(file);
|
|
84
|
+
let workspaceHandle;
|
|
85
|
+
let destinationDirectory;
|
|
86
|
+
let partialPath;
|
|
87
|
+
let handle;
|
|
88
|
+
try {
|
|
89
|
+
if (opened.size !== undefined && opened.size > maxFileBytes) {
|
|
90
|
+
throw new ArtifactError("artifact_file_too_large", "Native file exceeds the configured per-file limit.");
|
|
91
|
+
}
|
|
92
|
+
workspaceHandle = await openDirectoryNoFollow(workspaceRoot, "artifact_workspace_unsafe", "Selected workspace root is not a real directory.");
|
|
93
|
+
destinationDirectory = await prepareDestinationDirectory(workspaceHandle, destination.parentParts);
|
|
94
|
+
await cleanupStalePartials(destinationDirectory);
|
|
95
|
+
partialPath = join(destinationDirectory.anchorPath, `${PARTIAL_PREFIX}${randomUUID()}${PARTIAL_SUFFIX}`);
|
|
96
|
+
handle = await open(partialPath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | NO_FOLLOW, 0o600);
|
|
97
|
+
const hash = createHash("sha256");
|
|
98
|
+
let size = 0;
|
|
99
|
+
for await (const value of opened.stream) {
|
|
100
|
+
const chunk = incomingStreamChunk(value);
|
|
101
|
+
if (size + chunk.length > maxFileBytes) {
|
|
102
|
+
throw new ArtifactError("artifact_file_too_large", "Native file exceeds the configured per-file limit.");
|
|
103
|
+
}
|
|
104
|
+
await writeAll(handle, chunk, size);
|
|
105
|
+
hash.update(chunk);
|
|
106
|
+
size += chunk.length;
|
|
107
|
+
}
|
|
108
|
+
if (opened.size !== undefined && opened.size !== size) {
|
|
109
|
+
throw new ArtifactError("artifact_file_size_mismatch", "Native file metadata did not match the downloaded content.");
|
|
110
|
+
}
|
|
111
|
+
await handle.sync();
|
|
112
|
+
const writtenEntry = await handle.stat();
|
|
113
|
+
if (!writtenEntry.isFile() || writtenEntry.size !== size) {
|
|
114
|
+
throw new ArtifactError("artifact_write_integrity_failed", "Native file could not be verified before publication.");
|
|
115
|
+
}
|
|
116
|
+
const partialEntry = await lstat(partialPath);
|
|
117
|
+
if (partialEntry.isSymbolicLink()
|
|
118
|
+
|| !partialEntry.isFile()
|
|
119
|
+
|| partialEntry.dev !== writtenEntry.dev
|
|
120
|
+
|| partialEntry.ino !== writtenEntry.ino
|
|
121
|
+
|| partialEntry.size !== writtenEntry.size) {
|
|
122
|
+
throw new ArtifactError("artifact_partial_unsafe", "Native file partial changed before publication.");
|
|
123
|
+
}
|
|
124
|
+
await publishDestination(destinationDirectory, partialPath, destination.name, writtenEntry, handle, publishLink);
|
|
125
|
+
await unlink(partialPath).catch(() => undefined);
|
|
126
|
+
partialPath = undefined;
|
|
127
|
+
return {
|
|
128
|
+
path: destination.path,
|
|
129
|
+
size,
|
|
130
|
+
sha256: `sha256:${hash.digest("hex")}`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
opened.stream.destroy();
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
await handle?.close().catch(() => undefined);
|
|
139
|
+
if (partialPath)
|
|
140
|
+
await unlink(partialPath).catch(() => undefined);
|
|
141
|
+
await destinationDirectory?.close().catch(() => undefined);
|
|
142
|
+
await workspaceHandle?.close().catch(() => undefined);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export function artifactToolLogFields(input) {
|
|
146
|
+
return {
|
|
147
|
+
fileProvided: input.file !== undefined,
|
|
148
|
+
fileReferenceShape: describeIncomingArtifactValue(input.file),
|
|
149
|
+
downloadUrlHostname: incomingFileDownloadHostname(input.file),
|
|
150
|
+
workspaceId: input.workspaceId,
|
|
151
|
+
path: input.path,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async function executeArtifactTool(config, input, operation) {
|
|
155
|
+
const startedAt = performance.now();
|
|
156
|
+
try {
|
|
157
|
+
const { publicResult, logResult } = await operation();
|
|
158
|
+
if (config.logging.toolCalls) {
|
|
159
|
+
logEvent(config.logging, "info", "artifact_tool_call", {
|
|
160
|
+
tool: "download_artifact",
|
|
161
|
+
...artifactToolLogFields(input),
|
|
162
|
+
path: logResult.path,
|
|
163
|
+
size: logResult.size,
|
|
164
|
+
sha256: logResult.sha256,
|
|
165
|
+
success: true,
|
|
166
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return artifactToolResponse(publicResult);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (config.logging.toolCalls) {
|
|
173
|
+
logEvent(config.logging, "warn", "artifact_tool_call", {
|
|
174
|
+
tool: "download_artifact",
|
|
175
|
+
...artifactToolLogFields(input),
|
|
176
|
+
success: false,
|
|
177
|
+
errorCode: error instanceof ArtifactError ? error.code : "internal_error",
|
|
178
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function artifactToolResponse(result) {
|
|
185
|
+
return {
|
|
186
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
187
|
+
structuredContent: result,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async function openDirectoryNoFollow(path, code, message) {
|
|
191
|
+
let handle;
|
|
192
|
+
try {
|
|
193
|
+
handle = await open(path, DIRECTORY_FLAGS);
|
|
194
|
+
await assertDirectoryHandle(handle);
|
|
195
|
+
return handle;
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
await handle?.close().catch(() => undefined);
|
|
199
|
+
if (error instanceof ArtifactError)
|
|
200
|
+
throw error;
|
|
201
|
+
throw new ArtifactError(code, message);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async function assertDirectoryHandle(handle) {
|
|
205
|
+
const entry = await handle.stat();
|
|
206
|
+
if (!entry.isDirectory()) {
|
|
207
|
+
throw new ArtifactError("artifact_directory_unsafe", "Artifact destination parent is not a directory.");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function descriptorDirectoryPath(handle) {
|
|
211
|
+
if (isArtifactDownloadSupportedPlatform())
|
|
212
|
+
return `/proc/self/fd/${handle.fd}`;
|
|
213
|
+
throw new ArtifactError("artifact_platform_unsupported", "Native file download requires descriptor-anchored directory operations on this platform.");
|
|
214
|
+
}
|
|
215
|
+
function normalizeArtifactDestination(value) {
|
|
216
|
+
const rawParts = value.split(sep);
|
|
217
|
+
if (!value
|
|
218
|
+
|| value.includes("\u0000")
|
|
219
|
+
|| isAbsolute(value)
|
|
220
|
+
|| value.endsWith(sep)
|
|
221
|
+
|| rawParts.includes("..")) {
|
|
222
|
+
throw new ArtifactError("artifact_destination_invalid", "Artifact destination must be a non-empty relative file path inside the workspace.");
|
|
223
|
+
}
|
|
224
|
+
const normalized = normalize(value);
|
|
225
|
+
if (normalized === "."
|
|
226
|
+
|| normalized === ".."
|
|
227
|
+
|| normalized.startsWith(`..${sep}`)) {
|
|
228
|
+
throw new ArtifactError("artifact_destination_invalid", "Artifact destination must stay inside the selected workspace.");
|
|
229
|
+
}
|
|
230
|
+
const parts = normalized.split(sep);
|
|
231
|
+
const name = parts.at(-1);
|
|
232
|
+
if (!name || name === "." || name === "..") {
|
|
233
|
+
throw new ArtifactError("artifact_destination_invalid", "Artifact destination must name a file inside the selected workspace.");
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
path: normalized,
|
|
237
|
+
parentParts: parts.slice(0, -1),
|
|
238
|
+
name,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
async function prepareDestinationDirectory(rootHandle, parentParts) {
|
|
242
|
+
const openedHandles = [];
|
|
243
|
+
let parentHandle = rootHandle;
|
|
244
|
+
let parentAnchor = descriptorDirectoryPath(rootHandle);
|
|
245
|
+
try {
|
|
246
|
+
for (const part of parentParts) {
|
|
247
|
+
const child = await ensureWorkspaceChildDirectory(parentHandle, parentAnchor, part);
|
|
248
|
+
openedHandles.push(child);
|
|
249
|
+
parentHandle = child;
|
|
250
|
+
parentAnchor = descriptorDirectoryPath(child);
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
handle: parentHandle,
|
|
254
|
+
anchorPath: parentAnchor,
|
|
255
|
+
async close() {
|
|
256
|
+
for (const handle of openedHandles.reverse()) {
|
|
257
|
+
await handle.close().catch(() => undefined);
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
for (const handle of openedHandles.reverse()) {
|
|
264
|
+
await handle.close().catch(() => undefined);
|
|
265
|
+
}
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async function ensureWorkspaceChildDirectory(parentHandle, parentAnchor, name) {
|
|
270
|
+
await assertDirectoryHandle(parentHandle);
|
|
271
|
+
const path = join(parentAnchor, name);
|
|
272
|
+
try {
|
|
273
|
+
await mkdir(path, { mode: 0o755 });
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
if (!isNodeError(error) || error.code !== "EEXIST")
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
return openDirectoryNoFollow(path, "artifact_destination_parent_unsafe", "Artifact destination parent must be a real directory inside the workspace.");
|
|
280
|
+
}
|
|
281
|
+
async function publishDestination(directory, partialPath, filename, writtenEntry, handle, publishLink) {
|
|
282
|
+
await assertDirectoryHandle(directory.handle);
|
|
283
|
+
const candidate = join(directory.anchorPath, filename);
|
|
284
|
+
try {
|
|
285
|
+
await publishLink(partialPath, candidate);
|
|
286
|
+
assertPublishedArtifactEntry(await lstat(candidate), writtenEntry);
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
if (isNodeError(error) && error.code === "EEXIST") {
|
|
290
|
+
throw new ArtifactError("artifact_destination_exists", "Artifact destination already exists.");
|
|
291
|
+
}
|
|
292
|
+
// Once the destination path exists, never unlink it during failure cleanup.
|
|
293
|
+
// Another process may have replaced that path after publication, and a
|
|
294
|
+
// path-based verification followed by unlink would introduce another race.
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function assertPublishedArtifactEntry(entry, writtenEntry) {
|
|
299
|
+
if (entry.isSymbolicLink()
|
|
300
|
+
|| !entry.isFile()
|
|
301
|
+
|| entry.dev !== writtenEntry.dev
|
|
302
|
+
|| entry.ino !== writtenEntry.ino
|
|
303
|
+
|| entry.size !== writtenEntry.size) {
|
|
304
|
+
throw new ArtifactError("artifact_destination_publish_failed", "Published artifact did not match the verified download.");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async function cleanupStalePartials(directory) {
|
|
308
|
+
await assertDirectoryHandle(directory.handle);
|
|
309
|
+
const entries = await readdir(directory.anchorPath, { withFileTypes: true });
|
|
310
|
+
let inspected = 0;
|
|
311
|
+
const cutoff = Date.now() - STALE_PARTIAL_AGE_MS;
|
|
312
|
+
for (const entry of entries) {
|
|
313
|
+
if (inspected >= MAX_STALE_PARTIAL_CLEANUP)
|
|
314
|
+
break;
|
|
315
|
+
if (!entry.name.startsWith(PARTIAL_PREFIX)
|
|
316
|
+
|| !entry.name.endsWith(PARTIAL_SUFFIX))
|
|
317
|
+
continue;
|
|
318
|
+
inspected += 1;
|
|
319
|
+
const path = join(directory.anchorPath, entry.name);
|
|
320
|
+
const metadata = await lstatOrUndefined(path);
|
|
321
|
+
if (!metadata
|
|
322
|
+
|| metadata.isSymbolicLink()
|
|
323
|
+
|| !metadata.isFile()
|
|
324
|
+
|| metadata.mtimeMs >= cutoff
|
|
325
|
+
|| (process.getuid?.() !== undefined && metadata.uid !== process.getuid?.()))
|
|
326
|
+
continue;
|
|
327
|
+
await unlink(path).catch(() => undefined);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async function writeAll(handle, buffer, position) {
|
|
331
|
+
let offset = 0;
|
|
332
|
+
while (offset < buffer.length) {
|
|
333
|
+
const { bytesWritten } = await handle.write(buffer, offset, buffer.length - offset, position + offset);
|
|
334
|
+
if (bytesWritten <= 0) {
|
|
335
|
+
throw new ArtifactError("artifact_short_write", "Native file was not fully written.");
|
|
336
|
+
}
|
|
337
|
+
offset += bytesWritten;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function incomingFileDownloadHostname(value) {
|
|
341
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
const rawUrl = value.download_url;
|
|
345
|
+
if (typeof rawUrl !== "string")
|
|
346
|
+
return undefined;
|
|
347
|
+
try {
|
|
348
|
+
const hostname = new URL(rawUrl).hostname.toLowerCase();
|
|
349
|
+
return hostname.length > 0 && hostname.length <= 253 ? hostname : undefined;
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function incomingStreamChunk(value) {
|
|
356
|
+
if (Buffer.isBuffer(value))
|
|
357
|
+
return value;
|
|
358
|
+
if (typeof value === "string")
|
|
359
|
+
return Buffer.from(value);
|
|
360
|
+
if (value instanceof Uint8Array) {
|
|
361
|
+
return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
362
|
+
}
|
|
363
|
+
throw new ArtifactError("invalid_incoming_artifact_chunk", "Incoming artifact stream yielded a value that is not bytes or text.");
|
|
364
|
+
}
|
|
365
|
+
async function lstatOrUndefined(path) {
|
|
366
|
+
try {
|
|
367
|
+
return await lstat(path);
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (isNodeError(error) && error.code === "ENOENT")
|
|
371
|
+
return undefined;
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function isNodeError(error) {
|
|
376
|
+
return error instanceof Error && "code" in error;
|
|
377
|
+
}
|