@coreplane/switchboard 1.204.0 → 1.205.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/dist/assets/config/config.example.yaml +32 -3
- package/dist/assets/deploy/cloudflare-memory/worker.ts +129 -3
- package/dist/assets/deploy/cloudflare-memory/wrangler.template.jsonc +7 -2
- package/dist/assets/deploy/cloudflare-sandbox/worker.ts +4 -1
- package/dist/assets/package-lock.json +291 -97
- package/dist/assets/package.json +1 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/agents/registry.ts +466 -0
- package/dist/assets/src/config/profile.ts +200 -0
- package/dist/assets/src/core/delivery.ts +775 -0
- package/dist/assets/src/core/deliverySnapshotStore.ts +200 -0
- package/dist/assets/src/core/runLedger/types.ts +6 -0
- package/dist/assets/src/core/runRecord.ts +44 -0
- package/dist/assets/src/core/ship/contract.ts +502 -0
- package/dist/assets/src/core/workerError.ts +12 -0
- package/dist/assets/web/dist/.vite/manifest.json +2770 -70
- package/dist/assets/web/dist/assets/AppShell-lYVcj-k7.js +1 -0
- package/dist/assets/web/dist/assets/{CostsPage-XQ-fQzdz.js → CostsPage-DGSE48l1.js} +1 -1
- package/dist/assets/web/dist/assets/DeliveryPage-Cx7kQC_e.js +1 -0
- package/dist/assets/web/dist/assets/NotFoundPage-BzWS4Ca1.js +1 -0
- package/dist/assets/web/dist/assets/ResidentDetailPage-Bcasasjb.js +1 -0
- package/dist/assets/web/dist/assets/ResidentsIndexPage-BJwyrphn.js +1 -0
- package/dist/assets/web/dist/assets/RunRoutePage-6eStApqP.js +12 -0
- package/dist/assets/web/dist/assets/RunRoutePage-f6TSNPeW.css +1 -0
- package/dist/assets/web/dist/assets/RunsIndexPage-CWrkv7v8.js +1 -0
- package/dist/assets/web/dist/assets/RunsTabs-DEICQ4FY.js +1 -0
- package/dist/assets/web/dist/assets/ScheduledPage-BX2py1X3.js +1 -0
- package/dist/assets/web/dist/assets/StatusDot-CwCK84JN.js +1 -0
- package/dist/assets/web/dist/assets/Tooltip-CFC88_-Z.js +1 -0
- package/dist/assets/web/dist/assets/abap-CLvhMVsD.js +1 -0
- package/dist/assets/web/dist/assets/actionscript-3-Cs6JJXT5.js +1 -0
- package/dist/assets/web/dist/assets/ada-C5qYipkI.js +1 -0
- package/dist/assets/web/dist/assets/ahk-CA9gdOdF.js +1 -0
- package/dist/assets/web/dist/assets/ahk2-_6rzW9BS.js +1 -0
- package/dist/assets/web/dist/assets/andromeeda-vGVdxbeo.js +1 -0
- package/dist/assets/web/dist/assets/angular-html-Cw130Zyi.js +1 -0
- package/dist/assets/web/dist/assets/angular-ts-DY1m4C2s.js +1 -0
- package/dist/assets/web/dist/assets/apache-U0d_L8uA.js +1 -0
- package/dist/assets/web/dist/assets/apex-KFGFyKwG.js +1 -0
- package/dist/assets/web/dist/assets/apl-W6Ty7v05.js +1 -0
- package/dist/assets/web/dist/assets/applescript-CCn79oCD.js +1 -0
- package/dist/assets/web/dist/assets/ara-4CJ0cIlV.js +1 -0
- package/dist/assets/web/dist/assets/asciidoc-SCjQUq34.js +1 -0
- package/dist/assets/web/dist/assets/asm-Cmm7eHzH.js +1 -0
- package/dist/assets/web/dist/assets/astro-DlLVHwVk.js +1 -0
- package/dist/assets/web/dist/assets/aurora-x-CDeNXAV0.js +1 -0
- package/dist/assets/web/dist/assets/awk-BWXHIvNe.js +1 -0
- package/dist/assets/web/dist/assets/ayu-dark-DluEY0Gj.js +1 -0
- package/dist/assets/web/dist/assets/ayu-light-C3h-C4tm.js +1 -0
- package/dist/assets/web/dist/assets/ayu-mirage-Bqwy1Gya.js +1 -0
- package/dist/assets/web/dist/assets/ballerina-B7ZEbQpA.js +1 -0
- package/dist/assets/web/dist/assets/bat-qdxAdBWQ.js +1 -0
- package/dist/assets/web/dist/assets/beancount-D-usSTwE.js +1 -0
- package/dist/assets/web/dist/assets/berry-DKpUyyne.js +1 -0
- package/dist/assets/web/dist/assets/bibtex-Ci_nEsc7.js +1 -0
- package/dist/assets/web/dist/assets/bicep-CUHmPFLl.js +1 -0
- package/dist/assets/web/dist/assets/bird2-CYIUgYqB.js +1 -0
- package/dist/assets/web/dist/assets/blade-Bco3tDh4.js +1 -0
- package/dist/assets/web/dist/assets/bsl-_VjlB9mv.js +1 -0
- package/dist/assets/web/dist/assets/c-1LaFY_cj.js +1 -0
- package/dist/assets/web/dist/assets/c3-D0apG41V.js +1 -0
- package/dist/assets/web/dist/assets/cadence-CQ2zXKGN.js +1 -0
- package/dist/assets/web/dist/assets/cairo-DLTphjLi.js +1 -0
- package/dist/assets/web/dist/assets/catppuccin-frappe-C9Q5zVZY.js +1 -0
- package/dist/assets/web/dist/assets/catppuccin-latte-CtsyrtPq.js +1 -0
- package/dist/assets/web/dist/assets/catppuccin-macchiato-R8nAf1vR.js +1 -0
- package/dist/assets/web/dist/assets/catppuccin-mocha-DjuaAJKi.js +1 -0
- package/dist/assets/web/dist/assets/chapel-B-OvrOL5.js +1 -0
- package/dist/assets/web/dist/assets/clarity-CtfBBspg.js +1 -0
- package/dist/assets/web/dist/assets/clojure-DqKBuwfJ.js +1 -0
- package/dist/assets/web/dist/assets/cmake-Bj61d0ZC.js +1 -0
- package/dist/assets/web/dist/assets/cobol-Ch3EPlHu.js +1 -0
- package/dist/assets/web/dist/assets/codeowners-C8r90Shi.js +1 -0
- package/dist/assets/web/dist/assets/codeql-oeQT6MSM.js +1 -0
- package/dist/assets/web/dist/assets/coffee-hZuITnto.js +1 -0
- package/dist/assets/web/dist/assets/common-lisp-Cv5bFMCO.js +1 -0
- package/dist/assets/web/dist/assets/coq-DuBRPxYg.js +1 -0
- package/dist/assets/web/dist/assets/cpp-B8iRVo8m.js +1 -0
- package/dist/assets/web/dist/assets/crystal-DKveI7lr.js +1 -0
- package/dist/assets/web/dist/assets/csharp-oqKa8noW.js +1 -0
- package/dist/assets/web/dist/assets/css-_2_CD-rr.js +1 -0
- package/dist/assets/web/dist/assets/csv-Dx-8-gkx.js +1 -0
- package/dist/assets/web/dist/assets/cue-CE9AQfxI.js +1 -0
- package/dist/assets/web/dist/assets/cypher-ClKdZ_lG.js +1 -0
- package/dist/assets/web/dist/assets/d-qD-0Kul2.js +1 -0
- package/dist/assets/web/dist/assets/dark-plus-Cs2F2srj.js +1 -0
- package/dist/assets/web/dist/assets/dart-CnvKMtbv.js +1 -0
- package/dist/assets/web/dist/assets/dax-BkyTk9wS.js +1 -0
- package/dist/assets/web/dist/assets/desktop-Dlh5hvp9.js +1 -0
- package/dist/assets/web/dist/assets/diff-woXpYk--.js +1 -0
- package/dist/assets/web/dist/assets/dist-BoLiHpua.js +1547 -0
- package/dist/assets/web/dist/assets/docker-IyjqRm3v.js +1 -0
- package/dist/assets/web/dist/assets/dotenv-_5a1GRtc.js +1 -0
- package/dist/assets/web/dist/assets/dracula-BHWKrbxM.js +1 -0
- package/dist/assets/web/dist/assets/dracula-soft-5eyTD99u.js +1 -0
- package/dist/assets/web/dist/assets/dream-maker-DW3nJb8Q.js +1 -0
- package/dist/assets/web/dist/assets/edge-BenMDPct.js +1 -0
- package/dist/assets/web/dist/assets/elixir-CBbdEqG6.js +1 -0
- package/dist/assets/web/dist/assets/elm-DMub_2lY.js +1 -0
- package/dist/assets/web/dist/assets/emacs-lisp-c_oH4hRZ.js +1 -0
- package/dist/assets/web/dist/assets/erb-CI9He_Up.js +1 -0
- package/dist/assets/web/dist/assets/erlang-Cphh6RMH.js +1 -0
- package/dist/assets/web/dist/assets/everforest-dark-sB-x3p7T.js +1 -0
- package/dist/assets/web/dist/assets/everforest-light-Df2xbC6M.js +1 -0
- package/dist/assets/web/dist/assets/{favicon-CFfbl2AI.js → favicon-CWPcvWvp.js} +1 -1
- package/dist/assets/web/dist/assets/fennel-DQxkIbk2.js +1 -0
- package/dist/assets/web/dist/assets/fish-BJitypiv.js +1 -0
- package/dist/assets/web/dist/assets/fluent-C03EYrpw.js +1 -0
- package/dist/assets/web/dist/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
- package/dist/assets/web/dist/assets/fortran-free-form-CYNrtFtB.js +1 -0
- package/dist/assets/web/dist/assets/fsharp-D13ZGOAj.js +1 -0
- package/dist/assets/web/dist/assets/gdresource-xMC7jr7x.js +1 -0
- package/dist/assets/web/dist/assets/gdscript-DYvRD3hg.js +1 -0
- package/dist/assets/web/dist/assets/gdshader-CBce3t8t.js +1 -0
- package/dist/assets/web/dist/assets/genie-CV2tkWYe.js +1 -0
- package/dist/assets/web/dist/assets/gherkin-DExj1W_8.js +1 -0
- package/dist/assets/web/dist/assets/git-commit-BSykSTBG.js +1 -0
- package/dist/assets/web/dist/assets/git-rebase-BBfhnyF8.js +1 -0
- package/dist/assets/web/dist/assets/github-dark-C-LZuMrd.js +1 -0
- package/dist/assets/web/dist/assets/github-dark-default-DXG-b-1a.js +1 -0
- package/dist/assets/web/dist/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
- package/dist/assets/web/dist/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
- package/dist/assets/web/dist/assets/github-light-EUqPIrTm.js +1 -0
- package/dist/assets/web/dist/assets/github-light-default-BXViO-2h.js +1 -0
- package/dist/assets/web/dist/assets/github-light-high-contrast-B68TUdTA.js +1 -0
- package/dist/assets/web/dist/assets/gleam-CSRkHgEL.js +1 -0
- package/dist/assets/web/dist/assets/glimmer-js-CR9Fxrau.js +1 -0
- package/dist/assets/web/dist/assets/glimmer-ts-CwFwX_XS.js +1 -0
- package/dist/assets/web/dist/assets/glsl-Daiodp1r.js +1 -0
- package/dist/assets/web/dist/assets/gn-ilITqXS6.js +1 -0
- package/dist/assets/web/dist/assets/gnuplot-7GGW24-e.js +1 -0
- package/dist/assets/web/dist/assets/go-rLFTqkRN.js +1 -0
- package/dist/assets/web/dist/assets/graphql-DZvrsEkB.js +1 -0
- package/dist/assets/web/dist/assets/groovy-CacY0gHj.js +1 -0
- package/dist/assets/web/dist/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
- package/dist/assets/web/dist/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
- package/dist/assets/web/dist/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
- package/dist/assets/web/dist/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
- package/dist/assets/web/dist/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
- package/dist/assets/web/dist/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
- package/dist/assets/web/dist/assets/hack-BaXOzdg7.js +1 -0
- package/dist/assets/web/dist/assets/haml-CMskq_VA.js +1 -0
- package/dist/assets/web/dist/assets/handlebars-Dhw_f7jD.js +1 -0
- package/dist/assets/web/dist/assets/haskell-D8IpX4py.js +1 -0
- package/dist/assets/web/dist/assets/haxe-C8oCnwJJ.js +1 -0
- package/dist/assets/web/dist/assets/hcl-Dh228itO.js +1 -0
- package/dist/assets/web/dist/assets/hjson-CxZEssPk.js +1 -0
- package/dist/assets/web/dist/assets/hlsl-Cvrh5tZx.js +1 -0
- package/dist/assets/web/dist/assets/horizon-CE9ld1lL.js +1 -0
- package/dist/assets/web/dist/assets/horizon-bright-DSNQnXHK.js +1 -0
- package/dist/assets/web/dist/assets/houston-CsvMBhTu.js +1 -0
- package/dist/assets/web/dist/assets/html-C9k99z0z.js +1 -0
- package/dist/assets/web/dist/assets/html-derivative-VckPItXN.js +1 -0
- package/dist/assets/web/dist/assets/http-DXU_3h9v.js +1 -0
- package/dist/assets/web/dist/assets/hurl-KU24JNdp.js +1 -0
- package/dist/assets/web/dist/assets/hxml-Dcm88srW.js +1 -0
- package/dist/assets/web/dist/assets/hy-CZbG8q4J.js +1 -0
- package/dist/assets/web/dist/assets/imba-DsUTQ-LC.js +1 -0
- package/dist/assets/web/dist/assets/indexFormat-B-pd4r7Y.js +1 -0
- package/dist/assets/web/dist/assets/ini-B5eOa1yu.js +1 -0
- package/dist/assets/web/dist/assets/java-BbZjTNgf.js +1 -0
- package/dist/assets/web/dist/assets/javascript-DXCdqcZZ.js +1 -0
- package/dist/assets/web/dist/assets/jinja-pDlsjTVp.js +1 -0
- package/dist/assets/web/dist/assets/jison-DsXDk66e.js +1 -0
- package/dist/assets/web/dist/assets/json-tCxXfRgG.js +1 -0
- package/dist/assets/web/dist/assets/json5-BR5RXkoi.js +1 -0
- package/dist/assets/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
- package/dist/assets/web/dist/assets/jsonl-CmCQp5Yx.js +1 -0
- package/dist/assets/web/dist/assets/jsonnet-CJTPZ8u_.js +1 -0
- package/dist/assets/web/dist/assets/jssm-DXw9l8Rf.js +1 -0
- package/dist/assets/web/dist/assets/jsx-B0ZYkCmi.js +1 -0
- package/dist/assets/web/dist/assets/julia-BLzzeI6x.js +1 -0
- package/dist/assets/web/dist/assets/just-DvD2_60c.js +1 -0
- package/dist/assets/web/dist/assets/kanagawa-dragon-Bozd7klA.js +1 -0
- package/dist/assets/web/dist/assets/kanagawa-lotus-BmuOG9ZW.js +1 -0
- package/dist/assets/web/dist/assets/kanagawa-wave-BML5mF2J.js +1 -0
- package/dist/assets/web/dist/assets/kdl-CsD5j6eV.js +1 -0
- package/dist/assets/web/dist/assets/kotlin-DhhofPvG.js +1 -0
- package/dist/assets/web/dist/assets/kusto-C7mF5XQf.js +1 -0
- package/dist/assets/web/dist/assets/laserwave-C_8bwKvT.js +1 -0
- package/dist/assets/web/dist/assets/latex-511zn3h7.js +1 -0
- package/dist/assets/web/dist/assets/lean-CewbzKMR.js +1 -0
- package/dist/assets/web/dist/assets/less-DVTAwKKz.js +1 -0
- package/dist/assets/web/dist/assets/light-plus-DVQuIRkW.js +1 -0
- package/dist/assets/web/dist/assets/liquid-BD0BkMox.js +1 -0
- package/dist/assets/web/dist/assets/llvm-DqHOMS-s.js +1 -0
- package/dist/assets/web/dist/assets/log-BNLmms1o.js +1 -0
- package/dist/assets/web/dist/assets/logo-Cluzi2Zq.js +1 -0
- package/dist/assets/web/dist/assets/lua-NFicKm6N.js +1 -0
- package/dist/assets/web/dist/assets/luau-C2pBCSgt.js +1 -0
- package/dist/assets/web/dist/assets/main-i3ZNDRLK.css +1 -0
- package/dist/assets/web/dist/assets/main-tYcFk9Dc.js +28 -0
- package/dist/assets/web/dist/assets/make-Dixweg8N.js +1 -0
- package/dist/assets/web/dist/assets/markdown-BYOwaDjH.js +1 -0
- package/dist/assets/web/dist/assets/marko-1-G_nEXK.js +1 -0
- package/dist/assets/web/dist/assets/material-theme-Bm3Qr25_.js +1 -0
- package/dist/assets/web/dist/assets/material-theme-darker-2IIEA8gg.js +1 -0
- package/dist/assets/web/dist/assets/material-theme-lighter-uhdI0v04.js +1 -0
- package/dist/assets/web/dist/assets/material-theme-ocean-CHQ94UKr.js +1 -0
- package/dist/assets/web/dist/assets/material-theme-palenight-B5W6OYN7.js +1 -0
- package/dist/assets/web/dist/assets/matlab-D7qyCx1q.js +1 -0
- package/dist/assets/web/dist/assets/mdc-DUe3AQLp.js +1 -0
- package/dist/assets/web/dist/assets/mdx-DQZ5AkYe.js +1 -0
- package/dist/assets/web/dist/assets/mermaid-BxpfTIzt.js +1 -0
- package/dist/assets/web/dist/assets/min-dark-BSWPekZh.js +1 -0
- package/dist/assets/web/dist/assets/min-light-DDpmG2fV.js +1 -0
- package/dist/assets/web/dist/assets/mipsasm-BMqwQI7S.js +1 -0
- package/dist/assets/web/dist/assets/mojo-fg40_ntQ.js +1 -0
- package/dist/assets/web/dist/assets/monokai-B_bV9PQ9.js +1 -0
- package/dist/assets/web/dist/assets/moonbit-DgjMoLWr.js +1 -0
- package/dist/assets/web/dist/assets/move-BYnGhZoM.js +1 -0
- package/dist/assets/web/dist/assets/narrat-_X_XdTYD.js +1 -0
- package/dist/assets/web/dist/assets/nextflow-BJtWHP5T.js +1 -0
- package/dist/assets/web/dist/assets/nextflow-groovy-DJMQeKeT.js +1 -0
- package/dist/assets/web/dist/assets/nginx-Dg379_bA.js +1 -0
- package/dist/assets/web/dist/assets/night-owl-DhmEMT88.js +1 -0
- package/dist/assets/web/dist/assets/night-owl-light-eJ-hLW7d.js +1 -0
- package/dist/assets/web/dist/assets/nim-BnFq97ZO.js +1 -0
- package/dist/assets/web/dist/assets/nix-IvuFDN5E.js +1 -0
- package/dist/assets/web/dist/assets/nord-Cb4Vim4T.js +1 -0
- package/dist/assets/web/dist/assets/nsis-CjNLYCLg.js +1 -0
- package/dist/assets/web/dist/assets/nushell-DHYfO66s.js +1 -0
- package/dist/assets/web/dist/assets/objective-c-D1A_Heim.js +1 -0
- package/dist/assets/web/dist/assets/objective-cpp-BsSzOQcm.js +1 -0
- package/dist/assets/web/dist/assets/ocaml-O90oeIOV.js +1 -0
- package/dist/assets/web/dist/assets/odin-B1RWQWA5.js +1 -0
- package/dist/assets/web/dist/assets/one-dark-pro-CLwyXe_n.js +1 -0
- package/dist/assets/web/dist/assets/one-light-D7Lr4KcI.js +1 -0
- package/dist/assets/web/dist/assets/openscad-BUDT5pXO.js +1 -0
- package/dist/assets/web/dist/assets/org-F0uiwGvq.js +1 -0
- package/dist/assets/web/dist/assets/pascal-4ZHwLPI5.js +1 -0
- package/dist/assets/web/dist/assets/perl-B0euczkl.js +1 -0
- package/dist/assets/web/dist/assets/php-DkL3k_n7.js +1 -0
- package/dist/assets/web/dist/assets/pierre-dark-CpLgRqie.js +1 -0
- package/dist/assets/web/dist/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
- package/dist/assets/web/dist/assets/pierre-dark-soft-kZQmAZld.js +1 -0
- package/dist/assets/web/dist/assets/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
- package/dist/assets/web/dist/assets/pierre-dark-vibrant-CpQYzh95.js +1 -0
- package/dist/assets/web/dist/assets/pierre-light-CoaEpmwp.js +1 -0
- package/dist/assets/web/dist/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
- package/dist/assets/web/dist/assets/pierre-light-soft-lWLdNTOI.js +1 -0
- package/dist/assets/web/dist/assets/pierre-light-tritanopia-CEbqgOJL.js +1 -0
- package/dist/assets/web/dist/assets/pierre-light-vibrant-D80Fkn33.js +1 -0
- package/dist/assets/web/dist/assets/pkl-ot-7Btpt.js +1 -0
- package/dist/assets/web/dist/assets/plastic-DQwYfKfQ.js +1 -0
- package/dist/assets/web/dist/assets/plsql-DGHpHOYJ.js +1 -0
- package/dist/assets/web/dist/assets/po-BiJDBrnU.js +1 -0
- package/dist/assets/web/dist/assets/poimandres-DRFjx7u4.js +1 -0
- package/dist/assets/web/dist/assets/polar-C7UOKdEL.js +1 -0
- package/dist/assets/web/dist/assets/postcss-BXeXVLqQ.js +1 -0
- package/dist/assets/web/dist/assets/powerquery-DNMTfnFr.js +1 -0
- package/dist/assets/web/dist/assets/powershell-CCSX75yM.js +1 -0
- package/dist/assets/web/dist/assets/prisma-DMgNhnYS.js +1 -0
- package/dist/assets/web/dist/assets/prolog-iXnhIJG7.js +1 -0
- package/dist/assets/web/dist/assets/proto-DB4EqR-F.js +1 -0
- package/dist/assets/web/dist/assets/pug-L_OjjZP4.js +1 -0
- package/dist/assets/web/dist/assets/puppet-CDv2pdJW.js +1 -0
- package/dist/assets/web/dist/assets/purescript-9MfHhQsQ.js +1 -0
- package/dist/assets/web/dist/assets/python-gzcpVVnB.js +1 -0
- package/dist/assets/web/dist/assets/qml-BMjB00Zz.js +1 -0
- package/dist/assets/web/dist/assets/qmldir-DCQb3MpD.js +1 -0
- package/dist/assets/web/dist/assets/qss-Fe1Jh2GI.js +1 -0
- package/dist/assets/web/dist/assets/r-DoeLdnqR.js +1 -0
- package/dist/assets/web/dist/assets/racket-DcIDlBhZ.js +1 -0
- package/dist/assets/web/dist/assets/raku-B3gFvitq.js +1 -0
- package/dist/assets/web/dist/assets/razor-BzYNkAWy.js +1 -0
- package/dist/assets/web/dist/assets/rbs-C0MpOrj4.js +1 -0
- package/dist/assets/web/dist/assets/red-DX1BQOs8.js +1 -0
- package/dist/assets/web/dist/assets/reg-CRGYupPL.js +1 -0
- package/dist/assets/web/dist/assets/regexp-CPmElMk3.js +1 -0
- package/dist/assets/web/dist/assets/rel-BtDbiS_P.js +1 -0
- package/dist/assets/web/dist/assets/riscv-Ckw8ddFX.js +1 -0
- package/dist/assets/web/dist/assets/ron-VUp2lXgN.js +1 -0
- package/dist/assets/web/dist/assets/rose-pine-aMsaMD1D.js +1 -0
- package/dist/assets/web/dist/assets/rose-pine-dawn-8PwUyIlP.js +1 -0
- package/dist/assets/web/dist/assets/rose-pine-moon-DO-qXg-I.js +1 -0
- package/dist/assets/web/dist/assets/rosmsg-CAekHB0j.js +1 -0
- package/dist/assets/web/dist/assets/rst-DrsjgfI7.js +1 -0
- package/dist/assets/web/dist/assets/ruby-cB42ppvx.js +1 -0
- package/dist/assets/web/dist/assets/rust-Cfkwpbl8.js +1 -0
- package/dist/assets/web/dist/assets/sas-R5Y3NM_I.js +1 -0
- package/dist/assets/web/dist/assets/sass-DXrisJhu.js +1 -0
- package/dist/assets/web/dist/assets/scala-BiFt_7mu.js +1 -0
- package/dist/assets/web/dist/assets/scheme-DQCgrYNe.js +1 -0
- package/dist/assets/web/dist/assets/scss-C-zWxV9s.js +1 -0
- package/dist/assets/web/dist/assets/sdbl-bTVj8UrX.js +1 -0
- package/dist/assets/web/dist/assets/seed-DeKSHrt2.js +6 -0
- package/dist/assets/web/dist/assets/shaderlab-TOUzSsQk.js +1 -0
- package/dist/assets/web/dist/assets/shellscript-oJF96aAU.js +1 -0
- package/dist/assets/web/dist/assets/shellsession-CznECKyi.js +1 -0
- package/dist/assets/web/dist/assets/slack-dark-DnToyrRv.js +1 -0
- package/dist/assets/web/dist/assets/slack-ochin-B2OO5cIa.js +1 -0
- package/dist/assets/web/dist/assets/smalltalk-BHpQb5nM.js +1 -0
- package/dist/assets/web/dist/assets/smithy-Dgaz7aur.js +1 -0
- package/dist/assets/web/dist/assets/snazzy-light-4G7pJPwS.js +1 -0
- package/dist/assets/web/dist/assets/solarized-dark-UdsmMDCL.js +1 -0
- package/dist/assets/web/dist/assets/solarized-light-C1IUL_tW.js +1 -0
- package/dist/assets/web/dist/assets/solidity-Bj7E1mRn.js +1 -0
- package/dist/assets/web/dist/assets/soy-wjHLSRag.js +1 -0
- package/dist/assets/web/dist/assets/sparql-D_iOobhT.js +1 -0
- package/dist/assets/web/dist/assets/splunk-BC2Px7Mm.js +1 -0
- package/dist/assets/web/dist/assets/sql-C_BM8IOW.js +1 -0
- package/dist/assets/web/dist/assets/ssh-config-BgfXC-Er.js +1 -0
- package/dist/assets/web/dist/assets/stata-D31HO8aQ.js +1 -0
- package/dist/assets/web/dist/assets/stylus-B6D30XZt.js +1 -0
- package/dist/assets/web/dist/assets/surrealql-CKCLyplA.js +1 -0
- package/dist/assets/web/dist/assets/svelte-3geWk2iu.js +1 -0
- package/dist/assets/web/dist/assets/swift-CyEgAFGc.js +1 -0
- package/dist/assets/web/dist/assets/synthwave-84-nFMaYfgc.js +1 -0
- package/dist/assets/web/dist/assets/system-verilog-Dh5ihWbf.js +1 -0
- package/dist/assets/web/dist/assets/systemd-BxMlprV5.js +1 -0
- package/dist/assets/web/dist/assets/talonscript-CohzipZa.js +1 -0
- package/dist/assets/web/dist/assets/tasl-DMoTqEGO.js +1 -0
- package/dist/assets/web/dist/assets/tcl-CZd0xW_V.js +1 -0
- package/dist/assets/web/dist/assets/templ-DiJr_hTD.js +1 -0
- package/dist/assets/web/dist/assets/terraform-DswuEJGm.js +1 -0
- package/dist/assets/web/dist/assets/tex-BEJGWyeF.js +1 -0
- package/dist/assets/web/dist/assets/tokyo-night-oM2G3aXe.js +1 -0
- package/dist/assets/web/dist/assets/toml-CcmNWLt0.js +1 -0
- package/dist/assets/web/dist/assets/ts-tags-C8Mzdpxx.js +1 -0
- package/dist/assets/web/dist/assets/tsv-sltzmVWM.js +1 -0
- package/dist/assets/web/dist/assets/tsx-UQiSm_p3.js +1 -0
- package/dist/assets/web/dist/assets/turtle-ByJddavk.js +1 -0
- package/dist/assets/web/dist/assets/twig-_Pvzkeo9.js +1 -0
- package/dist/assets/web/dist/assets/typescript-BWMkINKK.js +1 -0
- package/dist/assets/web/dist/assets/typespec-BRdr0IET.js +1 -0
- package/dist/assets/web/dist/assets/typst-Bdg9m-e7.js +1 -0
- package/dist/assets/web/dist/assets/v-DBj4K9d_.js +1 -0
- package/dist/assets/web/dist/assets/vala-zf12oZj6.js +1 -0
- package/dist/assets/web/dist/assets/vb-DOwzaHZ0.js +1 -0
- package/dist/assets/web/dist/assets/verilog-B2gwz-sJ.js +1 -0
- package/dist/assets/web/dist/assets/vesper-DdrHHSXu.js +1 -0
- package/dist/assets/web/dist/assets/vhdl-BroJfC0k.js +1 -0
- package/dist/assets/web/dist/assets/viml-DvXPmvsu.js +1 -0
- package/dist/assets/web/dist/assets/vitesse-black-fwtXNY1n.js +1 -0
- package/dist/assets/web/dist/assets/vitesse-dark-BZCL-v6S.js +1 -0
- package/dist/assets/web/dist/assets/vitesse-light-VbXTXTou.js +1 -0
- package/dist/assets/web/dist/assets/vue-CDZrrAZ8.js +1 -0
- package/dist/assets/web/dist/assets/vue-html-tAlpNhfN.js +1 -0
- package/dist/assets/web/dist/assets/vue-vine-C27UF_rh.js +1 -0
- package/dist/assets/web/dist/assets/vyper-CgoNMtux.js +1 -0
- package/dist/assets/web/dist/assets/wallClock-61NpVkY6.js +1 -0
- package/dist/assets/web/dist/assets/wasm-BnjxR4X6.js +1 -0
- package/dist/assets/web/dist/assets/wasm-ByWQv1Qj.js +1 -0
- package/dist/assets/web/dist/assets/wenyan-C8pVoKbM.js +1 -0
- package/dist/assets/web/dist/assets/wgsl-BsKzXJz4.js +1 -0
- package/dist/assets/web/dist/assets/wikitext-ClFFjSW2.js +1 -0
- package/dist/assets/web/dist/assets/wit-DdvCle-K.js +1 -0
- package/dist/assets/web/dist/assets/wolfram-DLL8P-h_.js +1 -0
- package/dist/assets/web/dist/assets/xml-CxeDr9Zh.js +1 -0
- package/dist/assets/web/dist/assets/xsl-Bpi0uUnM.js +1 -0
- package/dist/assets/web/dist/assets/yaml-BtUgZ1GN.js +1 -0
- package/dist/assets/web/dist/assets/zenscript-BnlCZFoB.js +1 -0
- package/dist/assets/web/dist/assets/zig-CMLA9XwU.js +1 -0
- package/dist/cli.js +1005 -233
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/AppShell-Bw3-_TTE.js +0 -1
- package/dist/assets/web/dist/assets/DeliveryPage-BRwcQyr7.js +0 -1
- package/dist/assets/web/dist/assets/NotFoundPage-RjH-9dPy.js +0 -1
- package/dist/assets/web/dist/assets/ResidentDetailPage-BRy5wkv9.js +0 -1
- package/dist/assets/web/dist/assets/ResidentsIndexPage-DAEVLN8j.js +0 -1
- package/dist/assets/web/dist/assets/RunRoutePage-B1KHmkZ9.js +0 -126
- package/dist/assets/web/dist/assets/RunRoutePage-CdbrbqU2.css +0 -1
- package/dist/assets/web/dist/assets/RunsIndexPage-3hUWFpFV.js +0 -1
- package/dist/assets/web/dist/assets/RunsTabs-Qn_5TVJU.js +0 -1
- package/dist/assets/web/dist/assets/ScheduledPage-DysVvVm1.js +0 -1
- package/dist/assets/web/dist/assets/StatusDot-Bug2a6T6.js +0 -1
- package/dist/assets/web/dist/assets/Tooltip-C2eEUbwn.js +0 -1
- package/dist/assets/web/dist/assets/main-0uhp-taL.js +0 -28
- package/dist/assets/web/dist/assets/main-Xickfv8V.css +0 -1
- package/dist/assets/web/dist/assets/seed-B8mQEhhw.js +0 -6
- package/dist/assets/web/dist/assets/wallClock-DI4HIEN5.js +0 -1
package/dist/cli.js
CHANGED
|
@@ -615,8 +615,8 @@ var init_policy = __esm({
|
|
|
615
615
|
};
|
|
616
616
|
PLACEHOLDER = /\{([^{}]*)\}/g;
|
|
617
617
|
PolicyError = class extends Error {
|
|
618
|
-
constructor(
|
|
619
|
-
super(`authz policy: ${
|
|
618
|
+
constructor(message2, rule) {
|
|
619
|
+
super(`authz policy: ${message2} (rule ${describeRule(rule)})`);
|
|
620
620
|
this.name = "PolicyError";
|
|
621
621
|
}
|
|
622
622
|
};
|
|
@@ -1188,6 +1188,42 @@ var init_schedules = __esm({
|
|
|
1188
1188
|
}
|
|
1189
1189
|
});
|
|
1190
1190
|
|
|
1191
|
+
// ../../src/execution/bashTimeout.ts
|
|
1192
|
+
function clampBashTimeout(requested) {
|
|
1193
|
+
if (typeof requested !== "number" || !Number.isFinite(requested)) return BASH_TIMEOUT_MS;
|
|
1194
|
+
return Math.min(Math.max(Math.trunc(requested), BASH_TIMEOUT_MIN_MS), BASH_TIMEOUT_MAX_MS);
|
|
1195
|
+
}
|
|
1196
|
+
function bashBudgetWithinRun(wantedMs, remainingMs) {
|
|
1197
|
+
const secs = (ms) => Math.max(0, Math.round(ms / 1e3));
|
|
1198
|
+
const cap = Math.trunc(remainingMs - RUN_DEADLINE_RESERVE_MS);
|
|
1199
|
+
if (cap < BASH_TIMEOUT_MIN_MS) {
|
|
1200
|
+
return {
|
|
1201
|
+
kind: "exhausted",
|
|
1202
|
+
note: `run budget exhausted \u2014 ${secs(remainingMs)}s of wall clock left, inside the ${secs(RUN_DEADLINE_RESERVE_MS)}s write-up reserve, so the command was not run; write up what you have now`
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
if (cap >= wantedMs) return { kind: "unchanged" };
|
|
1206
|
+
return {
|
|
1207
|
+
kind: "clipped",
|
|
1208
|
+
timeoutMs: cap,
|
|
1209
|
+
note: `[timeout clipped to ${secs(cap)}s \u2014 the run's wall clock ends in ${secs(remainingMs)}s]`
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
function bashTimeoutNote(timeoutMs) {
|
|
1213
|
+
return `aborted at the ${Math.round(timeoutMs / 1e3)}s command timeout (pass the bash tool's timeoutMs for longer commands, max ${BASH_TIMEOUT_MAX_MS} ms)`;
|
|
1214
|
+
}
|
|
1215
|
+
var BASH_TIMEOUT_MS, BASH_TIMEOUT_MIN_MS, BASH_TIMEOUT_MAX_MS, RUN_DEADLINE_RESERVE_MS, EXEC_CALL_MARGIN_MS;
|
|
1216
|
+
var init_bashTimeout = __esm({
|
|
1217
|
+
"../../src/execution/bashTimeout.ts"() {
|
|
1218
|
+
"use strict";
|
|
1219
|
+
BASH_TIMEOUT_MS = 5 * 6e4;
|
|
1220
|
+
BASH_TIMEOUT_MIN_MS = 1e3;
|
|
1221
|
+
BASH_TIMEOUT_MAX_MS = 20 * 6e4;
|
|
1222
|
+
RUN_DEADLINE_RESERVE_MS = 6e4;
|
|
1223
|
+
EXEC_CALL_MARGIN_MS = 3e4;
|
|
1224
|
+
}
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1191
1227
|
// ../../src/core/ship/contract.ts
|
|
1192
1228
|
function parsePlanUnit(planMarkdown, unitId) {
|
|
1193
1229
|
const lines = planMarkdown.split("\n");
|
|
@@ -1495,11 +1531,14 @@ function getAgent(name) {
|
|
|
1495
1531
|
}
|
|
1496
1532
|
return a;
|
|
1497
1533
|
}
|
|
1498
|
-
var PR_DESCRIPTION_TEMPLATE, NEVER_MERGE, CONTRACT_HEADINGS_LIST, UNIT_CONTRACT, UNIT_HANDOFF, CODING_SYSTEM, CODING_SYSTEM_RESIDENT, REVIEW_VERDICT_INSTRUCTION, REVIEW_SPEC_CHECK, REVIEW_UNIT_CONTRACT, REVIEW_WHOLE_CHANGE, REVIEW_SYSTEM, REVIEW_SYSTEM_RESIDENT, RESEARCH_SYSTEM, GENERAL_SYSTEM, AGENTS;
|
|
1534
|
+
var MACHINE_CLASSES, IDENTITIES, PR_DESCRIPTION_TEMPLATE, NEVER_MERGE, CONTRACT_HEADINGS_LIST, UNIT_CONTRACT, UNIT_HANDOFF, CODING_SYSTEM, CODING_SYSTEM_RESIDENT, REVIEW_VERDICT_INSTRUCTION, REVIEW_SPEC_CHECK, REVIEW_UNIT_CONTRACT, REVIEW_WHOLE_CHANGE, REVIEW_SYSTEM, REVIEW_SYSTEM_RESIDENT, RESEARCH_SYSTEM, GENERAL_SYSTEM, EXPLORE_SYSTEM, AGENTS;
|
|
1499
1535
|
var init_registry = __esm({
|
|
1500
1536
|
"../../src/agents/registry.ts"() {
|
|
1501
1537
|
"use strict";
|
|
1538
|
+
init_bashTimeout();
|
|
1502
1539
|
init_contract();
|
|
1540
|
+
MACHINE_CLASSES = ["none", "blank", "repo-cold", "repo-resident"];
|
|
1541
|
+
IDENTITIES = ["none", "read", "write"];
|
|
1503
1542
|
PR_DESCRIPTION_TEMPLATE = `PR description \u2014 submit it with the submit_pr_description tool for EVERY PR (this is the default, not something to wait to be asked for). Switchboard renders the GitHub body from the object you submit, so never author PR-body markdown yourself. Content contract per field (each renders as its own section): prose is unwrapped \u2014 no hard line breaks inside a paragraph. Always hyperlink the triggering issue/request. Never fabricate validation \u2014 state exactly what you ran and the real result. Keep each field concise, not padded.
|
|
1504
1543
|
EVERY PR includes one that already exists when you push \u2014 opened by a person, by dependabot, or by an earlier run. After EVERY push to such a PR: read its current title and body (\`github_issue_get\` with the PR number works for pull requests; \`gh pr view\` where gh exists), judge them against the change as it now stands at the pushed head, and submit the object that describes the PR as it is NOW \u2014 carry forward what the existing body says that is still true (a dependency bump's release notes belong in whatWhy), add what you changed, and anchor the Tour at the new head. Switchboard replaces the PR's title and body with your rendering. A description that describes an earlier state of its branch is a bug; "it is someone else's PR" is never a reason to leave it.
|
|
1505
1544
|
- **title**: the PR title \u2014 one line naming the change, specific enough to pick out of a PR list.
|
|
@@ -1651,6 +1690,19 @@ Answer directly and concisely. Use Slack-friendly formatting (no markdown header
|
|
|
1651
1690
|
Your tools work without a workspace: the GitHub tools \u2014 \`github_repos\` (the org repositories you can reach), \`github_tree\` / \`github_file\` / \`github_search_code\` (browse, read, search their code and docs, private repos included), \`github_issue_list\` / \`github_issue_get\` (read issues), \`github_issue_create\` / \`github_issue_update\` / \`github_issue_comment\` / \`github_issue_delete\` (act on issues) \u2014 and \`web_fetch\` (read a public URL). Use them: when the user names a repo loosely ("the switchboard app"), resolve it with github_repos (or the thread) rather than asking; when asked about one of our repos, read it before answering. Report exactly what a tool did (issue number + URL) \u2014 never claim an action you did not perform, and never fabricate file contents, URLs, or command output.
|
|
1652
1691
|
|
|
1653
1692
|
You cannot run commands, clone repositories, edit code, or review pull requests, and you cannot search the web. Other Switchboard agents can: for code changes or PRs tell the user to re-send with \`agent:coding\`; for a PR review, \`agent:review\`; for a web-research question, \`agent:research\` (e.g. "\`agent:coding fix the failing login test in acme/api\`", "\`agent:research compare X and Y\`"). Delete an issue only when the user explicitly asked to delete it (closing is an update).`;
|
|
1693
|
+
EXPLORE_SYSTEM = `You are Switchboard's explore agent: a long, read-only investigation of a repository, answering a request from Slack.
|
|
1694
|
+
|
|
1695
|
+
You work in a fresh sandbox with a shell (bash), read_file, and a read-scoped GitHub credential: git and gh are authenticated for reads, so clone the target repository into your workspace first (\`gh repo clone <owner/name>\` or \`git clone\`; check out the ref the request names), install what you need and run whatever the investigation calls for \u2014 builds, test suites, benchmarks, \`act\` (Docker is available). You cannot push. Your other tools: \`web_search\` and \`web_fetch\` (sources and pages), the GitHub reads \u2014 \`github_repos\`, \`github_tree\` / \`github_file\` (browse and read our repos at any ref), \`github_search_code\`, \`github_issue_list\` / \`github_issue_get\` \u2014 and \`list_skills\` / \`use_skill\`.
|
|
1696
|
+
|
|
1697
|
+
THE DELIVERABLE IS A CLAIM TABLE. Turn the request into the claims it makes or asks about \u2014 explicit ones ("the suite runs in 4 minutes") and the implicit ones a careful engineer would check \u2014 and verify each one by running it, not by reading about it. One row per claim: the claim, the exact command you ran to check it, the number or output it produced, and a verdict (holds / does not hold / could not check \u2014 and why). Numbers over adjectives: measure a duration, count the failures, quote the version. Say what you did not get to.
|
|
1698
|
+
|
|
1699
|
+
TIME. Your budget is up to two hours \u2014 less when a boundary or the request's \`budget:\` directive clipped it, which the runtime-config block above says \u2014 and the wrap-up warning tells you when to stop starting new checks. A single command is capped at ${BASH_TIMEOUT_MAX_MS / 6e4} minutes (pass the bash tool's \`timeoutMs\`, up to ${BASH_TIMEOUT_MAX_MS} ms, for a long one). A job that needs longer \u2014 a full suite, a build, a pipeline run \u2014 is started detached and polled across tool calls: \`setsid -f sh -c '<command> > /tmp/job.log 2>&1; echo $? > /tmp/job.exit'\`, then \`tail -n 40 /tmp/job.log\` and \`cat /tmp/job.exit\` on later calls (a plain background job dies with the command that started it; a \`setsid -f\` job outlives it). Batch commands into few tool calls; never explore file by file.
|
|
1700
|
+
|
|
1701
|
+
READ-ONLY: NEVER open a pull request, and never commit or push \u2014 no branch, no \`gh pr create\`, no PR or issue write of any kind. You hold a read credential and your job is to find out, not to change. If the investigation shows a change is needed, say exactly what and where in your write-up and point the user at \`agent:coding\`.
|
|
1702
|
+
|
|
1703
|
+
Maintain the user-facing status card with the update_status tool: post your plan as a checklist (\u25CB pending) once you have it, and update items as they start (\u2731) and finish (\u2713 \u2014 only after they actually happened). Items are short outcomes ("Clone and install", "Time the full suite"), never commands.
|
|
1704
|
+
|
|
1705
|
+
Report outcomes faithfully: a check you could not run is "could not check", never a guess. Use Slack-friendly formatting (no markdown headers; *bold*, bullets, code blocks \u2014 render the claim table as aligned rows inside a code block). Your final message is posted to Slack: lead with the overall verdict in one line, then the claim table, then what a follow-up should do.`;
|
|
1654
1706
|
AGENTS = {
|
|
1655
1707
|
general: {
|
|
1656
1708
|
name: "general",
|
|
@@ -1658,8 +1710,10 @@ You cannot run commands, clone repositories, edit code, or review pull requests,
|
|
|
1658
1710
|
system: GENERAL_SYSTEM,
|
|
1659
1711
|
toolset: "assistant",
|
|
1660
1712
|
// The GitHub tools are REST in the bot process, so a general ask never
|
|
1661
|
-
// provisions a workspace or sandbox (docs/reference/specs/agent-general.md item 4)
|
|
1713
|
+
// provisions a workspace or sandbox (docs/reference/specs/agent-general.md item 4)
|
|
1714
|
+
// and mints no credential of its own.
|
|
1662
1715
|
machine: "none",
|
|
1716
|
+
identity: "none",
|
|
1663
1717
|
maxTurns: 8,
|
|
1664
1718
|
// a repo read is 2-3 calls (repos → tree → file); an issue action 1-2; still fast
|
|
1665
1719
|
maxTokens: 16e3,
|
|
@@ -1681,7 +1735,9 @@ You cannot run commands, clone repositories, edit code, or review pull requests,
|
|
|
1681
1735
|
cacheTtl: "1h",
|
|
1682
1736
|
// No built-in effort: the deployment decides (`defaults.efforts.coding`,
|
|
1683
1737
|
// `config set channel efforts.coding=…`, or `effort:` per request).
|
|
1684
|
-
machine: "repo-resident"
|
|
1738
|
+
machine: "repo-resident",
|
|
1739
|
+
identity: "write"
|
|
1740
|
+
// pushes branches and opens pull requests
|
|
1685
1741
|
},
|
|
1686
1742
|
review: {
|
|
1687
1743
|
name: "review",
|
|
@@ -1690,6 +1746,8 @@ You cannot run commands, clone repositories, edit code, or review pull requests,
|
|
|
1690
1746
|
residentSystem: REVIEW_SYSTEM_RESIDENT,
|
|
1691
1747
|
toolset: "readonly",
|
|
1692
1748
|
machine: "repo-resident",
|
|
1749
|
+
identity: "read",
|
|
1750
|
+
// a read-scoped token and a read-only worktree: it cannot post or push from inside
|
|
1693
1751
|
maxTurns: 30,
|
|
1694
1752
|
// backstop only; wall clock is the real budget (12 bound at ~4 min in practice)
|
|
1695
1753
|
maxTokens: 64e3,
|
|
@@ -1706,14 +1764,19 @@ You cannot run commands, clone repositories, edit code, or review pull requests,
|
|
|
1706
1764
|
// on the coding/review defs above — runAgent is never called with THIS def.
|
|
1707
1765
|
system: "You are Switchboard's ship pipeline. This prompt is never sent to a model \u2014 the pipeline orchestrates coding and review child runs on their own definitions.",
|
|
1708
1766
|
// Full toolset and the coding machine class, so repo and PR resolution
|
|
1709
|
-
// gate a ship thread like a coding one
|
|
1710
|
-
//
|
|
1711
|
-
//
|
|
1767
|
+
// gate a ship thread like a coding one. `maxMinutes` is the pipeline's
|
|
1768
|
+
// wall clock (docs/reference/specs/agent-ship.md item 8): the ship preset's
|
|
1769
|
+
// declared budget, which a deployment's `ship.maxMinutes` knob replaces
|
|
1770
|
+
// (`shipPresetFor`) and a boundary or a `budget:` directive clips like any
|
|
1771
|
+
// preset's; every child round runs its own agent's budget clipped to what
|
|
1772
|
+
// remains of it. Turns and tokens are placeholders: no model call is ever
|
|
1773
|
+
// made with this def.
|
|
1712
1774
|
toolset: "full",
|
|
1713
1775
|
machine: "repo-resident",
|
|
1776
|
+
identity: "write",
|
|
1714
1777
|
maxTurns: 1,
|
|
1715
1778
|
maxTokens: 16e3,
|
|
1716
|
-
maxMinutes:
|
|
1779
|
+
maxMinutes: 120
|
|
1717
1780
|
},
|
|
1718
1781
|
research: {
|
|
1719
1782
|
name: "research",
|
|
@@ -1722,10 +1785,30 @@ You cannot run commands, clone repositories, edit code, or review pull requests,
|
|
|
1722
1785
|
toolset: "web",
|
|
1723
1786
|
machine: "none",
|
|
1724
1787
|
// web I/O only; no workspace is provisioned
|
|
1788
|
+
identity: "none",
|
|
1725
1789
|
maxTurns: 12,
|
|
1726
1790
|
maxTokens: 24e3,
|
|
1727
1791
|
maxMinutes: 8,
|
|
1728
1792
|
effort: "medium"
|
|
1793
|
+
},
|
|
1794
|
+
explore: {
|
|
1795
|
+
name: "explore",
|
|
1796
|
+
description: "Long, read-only investigation of a repository in a cold sandbox: runs builds, suites and pipelines, searches the web, and reports a claim table with commands and numbers. Never opens a PR. Up to two hours.",
|
|
1797
|
+
system: EXPLORE_SYSTEM,
|
|
1798
|
+
toolset: "explore",
|
|
1799
|
+
// Always a cold per-thread sandbox with the checkout, never the resident a
|
|
1800
|
+
// review depends on: a two-hour job shares no container with anyone.
|
|
1801
|
+
machine: "repo-cold",
|
|
1802
|
+
identity: "read",
|
|
1803
|
+
// a read-scoped token: it can clone and read, never push — whatever the caller holds
|
|
1804
|
+
maxTurns: 150,
|
|
1805
|
+
// a backstop for a two-hour loop of batched checks; the wall clock is the budget
|
|
1806
|
+
maxTokens: 64e3,
|
|
1807
|
+
maxMinutes: 120,
|
|
1808
|
+
// A detached job polled across calls makes long steps: a 5m cache entry
|
|
1809
|
+
// would expire between them, so the 2× write buys reads for the whole run.
|
|
1810
|
+
cacheTtl: "1h"
|
|
1811
|
+
// No built-in effort: the deployment decides, as for coding.
|
|
1729
1812
|
}
|
|
1730
1813
|
};
|
|
1731
1814
|
}
|
|
@@ -2014,8 +2097,8 @@ var init_web = __esm({
|
|
|
2014
2097
|
"../../src/tools/web.ts"() {
|
|
2015
2098
|
"use strict";
|
|
2016
2099
|
WebSearchUnavailableError = class extends Error {
|
|
2017
|
-
constructor(
|
|
2018
|
-
super(
|
|
2100
|
+
constructor(message2) {
|
|
2101
|
+
super(message2);
|
|
2019
2102
|
this.name = "WebSearchUnavailableError";
|
|
2020
2103
|
}
|
|
2021
2104
|
};
|
|
@@ -2053,8 +2136,8 @@ var init_web = __esm({
|
|
|
2053
2136
|
return records.map((r) => r.address);
|
|
2054
2137
|
};
|
|
2055
2138
|
BlockedUrlError = class extends Error {
|
|
2056
|
-
constructor(
|
|
2057
|
-
super(
|
|
2139
|
+
constructor(message2) {
|
|
2140
|
+
super(message2);
|
|
2058
2141
|
this.name = "BlockedUrlError";
|
|
2059
2142
|
}
|
|
2060
2143
|
};
|
|
@@ -2323,6 +2406,38 @@ function validateScopeEfforts(layer, source2) {
|
|
|
2323
2406
|
}
|
|
2324
2407
|
}
|
|
2325
2408
|
}
|
|
2409
|
+
function boundaryProblem(path, raw) {
|
|
2410
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return `${path} must be a mapping`;
|
|
2411
|
+
for (const key of unknownKeys(raw, BOUNDARY_KEYS)) return `${path}: unknown field ${key}`;
|
|
2412
|
+
const b = raw;
|
|
2413
|
+
if (b.maxMinutes !== void 0 && (!Number.isInteger(b.maxMinutes) || b.maxMinutes < MIN_BOUNDARY_MINUTES))
|
|
2414
|
+
return `${path}.maxMinutes must be an integer >= ${MIN_BOUNDARY_MINUTES}`;
|
|
2415
|
+
if (b.maxIdentity !== void 0 && !IDENTITIES.includes(b.maxIdentity))
|
|
2416
|
+
return `${path}.maxIdentity is "${String(b.maxIdentity)}" \u2014 valid identities: ${IDENTITIES.join(", ")}`;
|
|
2417
|
+
if (b.machines !== void 0) {
|
|
2418
|
+
if (!Array.isArray(b.machines)) return `${path}.machines must be a list of classes`;
|
|
2419
|
+
if (b.machines.length === 0) return `${path}.machines must name at least one class`;
|
|
2420
|
+
for (const m of b.machines) {
|
|
2421
|
+
if (!MACHINE_CLASSES.includes(m))
|
|
2422
|
+
return `${path}.machines names "${String(m)}" \u2014 valid classes: ${MACHINE_CLASSES.join(", ")}`;
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
return void 0;
|
|
2426
|
+
}
|
|
2427
|
+
function validateBoundaries(layer, source2) {
|
|
2428
|
+
const check = (path, raw) => {
|
|
2429
|
+
if (raw === void 0) return;
|
|
2430
|
+
const problem = boundaryProblem(path, raw);
|
|
2431
|
+
if (problem) throw new Error(`${source2}: ${problem}`);
|
|
2432
|
+
};
|
|
2433
|
+
check("defaults.boundary", layer.defaults?.boundary);
|
|
2434
|
+
for (const [kind, scopes] of [
|
|
2435
|
+
["channels", layer.channels],
|
|
2436
|
+
["users", layer.users]
|
|
2437
|
+
]) {
|
|
2438
|
+
for (const [id, scope] of Object.entries(scopes ?? {})) check(`${kind}.${id}.boundary`, scope.boundary);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2326
2441
|
function validateMcpServers(layer, source2) {
|
|
2327
2442
|
const check = (path, tier, servers) => {
|
|
2328
2443
|
if (servers === void 0) return;
|
|
@@ -2375,6 +2490,7 @@ function validateMcpServers(layer, source2) {
|
|
|
2375
2490
|
function validateConfig(cfg) {
|
|
2376
2491
|
for (const key of unknownKeys(cfg, CONFIG_KEYS)) throw new Error(`config.yaml: unknown key \`${key}\``);
|
|
2377
2492
|
validateScopeEfforts(cfg, "config.yaml");
|
|
2493
|
+
validateBoundaries(cfg, "config.yaml");
|
|
2378
2494
|
validateMcpServers(cfg, "config.yaml");
|
|
2379
2495
|
if (typeof cfg.organization !== "string" || cfg.organization.trim() === "") {
|
|
2380
2496
|
throw new Error(
|
|
@@ -2474,7 +2590,7 @@ function validateRuntimeOverrides(ro) {
|
|
|
2474
2590
|
}
|
|
2475
2591
|
}
|
|
2476
2592
|
}
|
|
2477
|
-
var MAX_INSTRUCTIONS_LENGTH, CONFIG_KEYS, SELF_IMPROVEMENT_KEYS;
|
|
2593
|
+
var MAX_INSTRUCTIONS_LENGTH, CONFIG_KEYS, SELF_IMPROVEMENT_KEYS, BOUNDARY_KEYS, MIN_BOUNDARY_MINUTES;
|
|
2478
2594
|
var init_validate = __esm({
|
|
2479
2595
|
"../../src/config/validate.ts"() {
|
|
2480
2596
|
"use strict";
|
|
@@ -2516,6 +2632,90 @@ var init_validate = __esm({
|
|
|
2516
2632
|
minRuns: true,
|
|
2517
2633
|
top: true
|
|
2518
2634
|
};
|
|
2635
|
+
BOUNDARY_KEYS = { maxMinutes: true, maxIdentity: true, machines: true };
|
|
2636
|
+
MIN_BOUNDARY_MINUTES = 2;
|
|
2637
|
+
}
|
|
2638
|
+
});
|
|
2639
|
+
|
|
2640
|
+
// ../../src/config/profile.ts
|
|
2641
|
+
function clipSourceLabel(scope) {
|
|
2642
|
+
return scope === "directive" ? "budget directive" : `${scope} boundary`;
|
|
2643
|
+
}
|
|
2644
|
+
function identityWithin(identity2, cap) {
|
|
2645
|
+
return IDENTITY_ORDER[identity2] <= IDENTITY_ORDER[cap];
|
|
2646
|
+
}
|
|
2647
|
+
function declaredProfile(preset) {
|
|
2648
|
+
return { machine: preset.machine, identity: preset.identity, minutes: preset.maxMinutes };
|
|
2649
|
+
}
|
|
2650
|
+
function budgetedAgent(agent, profile) {
|
|
2651
|
+
return { ...agent, maxMinutes: profile.minutes };
|
|
2652
|
+
}
|
|
2653
|
+
function intersectBoundaries(layers) {
|
|
2654
|
+
const out = {};
|
|
2655
|
+
for (const { scope, boundary } of layers) {
|
|
2656
|
+
if (boundary.maxMinutes !== void 0 && (!out.maxMinutes || boundary.maxMinutes < out.maxMinutes.value)) {
|
|
2657
|
+
out.maxMinutes = { value: boundary.maxMinutes, scope };
|
|
2658
|
+
}
|
|
2659
|
+
if (boundary.maxIdentity !== void 0 && (!out.maxIdentity || !identityWithin(out.maxIdentity.value, boundary.maxIdentity))) {
|
|
2660
|
+
out.maxIdentity = { value: boundary.maxIdentity, scope };
|
|
2661
|
+
}
|
|
2662
|
+
if (boundary.machines !== void 0) {
|
|
2663
|
+
const allowed = boundary.machines;
|
|
2664
|
+
const value = (out.machines ? out.machines.value : allowed).filter((m) => allowed.includes(m)).sort((a, b) => MACHINE_ORDER[a] - MACHINE_ORDER[b]);
|
|
2665
|
+
out.machines = { value, by: [...out.machines?.by ?? [], { scope, machines: [...allowed] }] };
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
return out.maxMinutes || out.maxIdentity || out.machines ? out : void 0;
|
|
2669
|
+
}
|
|
2670
|
+
function effectiveProfile(preset, directives, boundary) {
|
|
2671
|
+
if (boundary?.maxIdentity && !identityWithin(preset.identity, boundary.maxIdentity.value)) {
|
|
2672
|
+
return {
|
|
2673
|
+
kind: "refused",
|
|
2674
|
+
refusal: {
|
|
2675
|
+
axis: "identity",
|
|
2676
|
+
needs: preset.identity,
|
|
2677
|
+
cap: boundary.maxIdentity.value,
|
|
2678
|
+
scope: boundary.maxIdentity.scope
|
|
2679
|
+
}
|
|
2680
|
+
};
|
|
2681
|
+
}
|
|
2682
|
+
if (boundary?.machines && !boundary.machines.value.includes(preset.machine)) {
|
|
2683
|
+
return {
|
|
2684
|
+
kind: "refused",
|
|
2685
|
+
refusal: {
|
|
2686
|
+
axis: "machine",
|
|
2687
|
+
needs: preset.machine,
|
|
2688
|
+
allowed: boundary.machines.value,
|
|
2689
|
+
scopes: boundary.machines.by.filter((b) => !b.machines.includes(preset.machine)).map((b) => b.scope)
|
|
2690
|
+
}
|
|
2691
|
+
};
|
|
2692
|
+
}
|
|
2693
|
+
let minutes = preset.maxMinutes;
|
|
2694
|
+
let boundedBy;
|
|
2695
|
+
if (directives.budget !== void 0 && directives.budget < minutes) {
|
|
2696
|
+
minutes = directives.budget;
|
|
2697
|
+
boundedBy = "directive";
|
|
2698
|
+
}
|
|
2699
|
+
if (boundary?.maxMinutes && boundary.maxMinutes.value < minutes) {
|
|
2700
|
+
minutes = boundary.maxMinutes.value;
|
|
2701
|
+
boundedBy = boundary.maxMinutes.scope;
|
|
2702
|
+
}
|
|
2703
|
+
return {
|
|
2704
|
+
kind: "profile",
|
|
2705
|
+
profile: {
|
|
2706
|
+
machine: preset.machine,
|
|
2707
|
+
identity: preset.identity,
|
|
2708
|
+
minutes,
|
|
2709
|
+
...boundedBy !== void 0 ? { boundedBy } : {}
|
|
2710
|
+
}
|
|
2711
|
+
};
|
|
2712
|
+
}
|
|
2713
|
+
var IDENTITY_ORDER, MACHINE_ORDER;
|
|
2714
|
+
var init_profile = __esm({
|
|
2715
|
+
"../../src/config/profile.ts"() {
|
|
2716
|
+
"use strict";
|
|
2717
|
+
IDENTITY_ORDER = { none: 0, read: 1, write: 2 };
|
|
2718
|
+
MACHINE_ORDER = { none: 0, blank: 1, "repo-cold": 2, "repo-resident": 3 };
|
|
2519
2719
|
}
|
|
2520
2720
|
});
|
|
2521
2721
|
|
|
@@ -2594,6 +2794,7 @@ function formatConfigDescription(d) {
|
|
|
2594
2794
|
const orgMcp = d.org?.mcpServers && Object.keys(d.org.mcpServers).length > 0 ? `, mcp ${Object.keys(d.org.mcpServers).map((n2) => `\`${n2}\``).join(" ")}` : "";
|
|
2595
2795
|
const lines = [
|
|
2596
2796
|
`*Effective for you in this channel:* ${effective}`,
|
|
2797
|
+
...d.effective.boundary ? [`*Effective boundary:* ${fmtEffectiveBoundary(d.effective.boundary)}`] : [],
|
|
2597
2798
|
`*Defaults:* ${defaults}${orgMcp}`,
|
|
2598
2799
|
`*Channel scope:* ${fmtScope(d.channel)}`,
|
|
2599
2800
|
`*Your scope:* ${fmtScope(d.user)}`
|
|
@@ -2618,8 +2819,26 @@ function fmtScope(s) {
|
|
|
2618
2819
|
parts.push(
|
|
2619
2820
|
`mcp ${Object.keys(s.mcpServers).map((n2) => `\`${n2}\``).join(" ")}`
|
|
2620
2821
|
);
|
|
2822
|
+
if (s.boundary) parts.push(`boundary ${fmtBoundary(s.boundary)}`);
|
|
2621
2823
|
return parts.length > 0 ? parts.join(", ") : "_none_";
|
|
2622
2824
|
}
|
|
2825
|
+
function fmtBoundary(b) {
|
|
2826
|
+
const parts = [];
|
|
2827
|
+
if (b.maxMinutes !== void 0) parts.push(`maxMinutes=${b.maxMinutes}`);
|
|
2828
|
+
if (b.maxIdentity !== void 0) parts.push(`maxIdentity=${b.maxIdentity}`);
|
|
2829
|
+
if (b.machines !== void 0) parts.push(`machines=${b.machines.join(",")}`);
|
|
2830
|
+
return parts.length > 0 ? parts.join(" ") : "(caps nothing)";
|
|
2831
|
+
}
|
|
2832
|
+
function fmtEffectiveBoundary(b) {
|
|
2833
|
+
const parts = [];
|
|
2834
|
+
if (b.maxMinutes) parts.push(`maxMinutes ${b.maxMinutes.value} (${b.maxMinutes.scope})`);
|
|
2835
|
+
if (b.maxIdentity) parts.push(`maxIdentity \`${b.maxIdentity.value}\` (${b.maxIdentity.scope})`);
|
|
2836
|
+
if (b.machines)
|
|
2837
|
+
parts.push(
|
|
2838
|
+
`machines ${b.machines.value.map((m) => `\`${m}\``).join(", ")} (${b.machines.by.map((l) => l.scope).join(", ")})`
|
|
2839
|
+
);
|
|
2840
|
+
return parts.join(", ");
|
|
2841
|
+
}
|
|
2623
2842
|
function fmtModels(m) {
|
|
2624
2843
|
return Object.entries(m).map(([k, v]) => `\`${k}=${v}\``).join(" ");
|
|
2625
2844
|
}
|
|
@@ -2636,6 +2855,7 @@ var init_config = __esm({
|
|
|
2636
2855
|
init_schedules();
|
|
2637
2856
|
init_registry();
|
|
2638
2857
|
init_validate();
|
|
2858
|
+
init_profile();
|
|
2639
2859
|
FileOverridesBacking = class {
|
|
2640
2860
|
path;
|
|
2641
2861
|
constructor(path) {
|
|
@@ -2756,6 +2976,7 @@ var init_config = __esm({
|
|
|
2756
2976
|
doc.users ??= {};
|
|
2757
2977
|
validateInstructions(doc, `overrides (${this.backing.describe()})`);
|
|
2758
2978
|
validateScopeEfforts(doc, `overrides (${this.backing.describe()})`);
|
|
2979
|
+
validateBoundaries(doc, `overrides (${this.backing.describe()})`);
|
|
2759
2980
|
validateMcpServers(
|
|
2760
2981
|
{ channels: doc.channels, users: doc.users, defaults: doc.org },
|
|
2761
2982
|
`overrides (${this.backing.describe()})`
|
|
@@ -2847,22 +3068,43 @@ var init_config = __esm({
|
|
|
2847
3068
|
return { channel: this.channelScope(channelId), user: this.userScope(userId) };
|
|
2848
3069
|
}
|
|
2849
3070
|
/**
|
|
2850
|
-
* Resolve which agent, model, and effort serve a request
|
|
2851
|
-
*
|
|
2852
|
-
*
|
|
2853
|
-
*
|
|
2854
|
-
*
|
|
3071
|
+
* Resolve which agent, model, and effort serve a request, and the boundary
|
|
3072
|
+
* every run on this path meets.
|
|
3073
|
+
* Agent: request directive > user scope > channel scope > default.
|
|
3074
|
+
* Model: request directive > (user > channel) forced model
|
|
3075
|
+
* > (user > channel > defaults) per-agent model.
|
|
3076
|
+
* Effort: the same ladder as model; unset at every layer → undefined.
|
|
3077
|
+
* Boundary: NOT a ladder — the defaults', the channel's and the user's
|
|
3078
|
+
* boundaries intersect (the smallest budget, the lowest identity,
|
|
3079
|
+
* the classes every layer allows), so a scope can only tighten what
|
|
3080
|
+
* the layers below it allow; no layer set → absent.
|
|
2855
3081
|
*/
|
|
2856
3082
|
resolve(opts) {
|
|
2857
3083
|
const ch = this.channelScope(opts.channelId);
|
|
2858
3084
|
const us = this.userScope(opts.userId);
|
|
2859
3085
|
const agentName = opts.request.agent ?? us.agent ?? ch.agent ?? this.config.defaults.agent;
|
|
3086
|
+
const boundary = intersectBoundaries(this.boundaryLayers(ch, us));
|
|
2860
3087
|
const modelRef2 = opts.request.model ?? us.model ?? ch.model ?? us.models?.[agentName] ?? ch.models?.[agentName] ?? this.config.defaults.models[agentName] ?? this.config.defaults.models["general"];
|
|
2861
3088
|
if (!modelRef2) {
|
|
2862
3089
|
throw new Error(`No model configured for agent "${agentName}" \u2014 set defaults.models.${agentName} in config.yaml`);
|
|
2863
3090
|
}
|
|
2864
3091
|
const effort2 = opts.request.effort ?? us.effort ?? ch.effort ?? us.efforts?.[agentName] ?? ch.efforts?.[agentName] ?? this.config.defaults.efforts?.[agentName];
|
|
2865
|
-
return {
|
|
3092
|
+
return {
|
|
3093
|
+
agentName,
|
|
3094
|
+
modelRef: modelRef2,
|
|
3095
|
+
...effort2 !== void 0 ? { effort: effort2 } : {},
|
|
3096
|
+
...boundary !== void 0 ? { boundary } : {}
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
/** The boundary layers on a path, in resolution order, keeping only the
|
|
3100
|
+
* scopes that set one — `intersectBoundaries` names each axis's scope from it. */
|
|
3101
|
+
boundaryLayers(channel, user) {
|
|
3102
|
+
const layers = [
|
|
3103
|
+
["defaults", this.config.defaults.boundary],
|
|
3104
|
+
["channel", channel.boundary],
|
|
3105
|
+
["user", user.boundary]
|
|
3106
|
+
];
|
|
3107
|
+
return layers.flatMap(([scope, boundary]) => boundary ? [{ scope, boundary }] : []);
|
|
2866
3108
|
}
|
|
2867
3109
|
// ---- authorization gates ----------------------------------------------------
|
|
2868
3110
|
// Every gate reads the grants table (authorization.md item 9): what an actor
|
|
@@ -2987,7 +3229,8 @@ var init_config = __esm({
|
|
|
2987
3229
|
effective: {
|
|
2988
3230
|
agent: resolved.agentName,
|
|
2989
3231
|
model: resolved.modelRef,
|
|
2990
|
-
...resolved.effort ? { effort: resolved.effort } : {}
|
|
3232
|
+
...resolved.effort ? { effort: resolved.effort } : {},
|
|
3233
|
+
...resolved.boundary ? { boundary: resolved.boundary } : {}
|
|
2991
3234
|
},
|
|
2992
3235
|
defaults: {
|
|
2993
3236
|
agent: this.config.defaults.agent,
|
|
@@ -3971,8 +4214,8 @@ var init_tracer = __esm({
|
|
|
3971
4214
|
delete this.rec.errorMessage;
|
|
3972
4215
|
return;
|
|
3973
4216
|
}
|
|
3974
|
-
const
|
|
3975
|
-
this.rec.errorMessage = redactAndCap(
|
|
4217
|
+
const message2 = err2 instanceof Error ? err2.message : String(err2);
|
|
4218
|
+
this.rec.errorMessage = redactAndCap(message2, ERROR_MESSAGE_CAP);
|
|
3976
4219
|
}
|
|
3977
4220
|
setAttrs(attrs) {
|
|
3978
4221
|
this.rec.attrs = { ...this.rec.attrs, ...attrs };
|
|
@@ -4191,7 +4434,7 @@ function isExampleProfile(p) {
|
|
|
4191
4434
|
return p.account === EXAMPLE_ACCOUNT;
|
|
4192
4435
|
}
|
|
4193
4436
|
var WORKER_KINDS, PROFILE_PATH, PROFILE_EXAMPLE_PATH, PROFILE_ENV, hostname, endpoint, source, IMAGE_MODES, profileSchema, EXAMPLE_ACCOUNT;
|
|
4194
|
-
var
|
|
4437
|
+
var init_profile2 = __esm({
|
|
4195
4438
|
"../../src/deploy/profile.ts"() {
|
|
4196
4439
|
"use strict";
|
|
4197
4440
|
WORKER_KINDS = ["memory", "bot", "resident", "sandbox"];
|
|
@@ -4456,7 +4699,7 @@ var init_plan = __esm({
|
|
|
4456
4699
|
init_configDocument();
|
|
4457
4700
|
init_images();
|
|
4458
4701
|
init_operatorRoot();
|
|
4459
|
-
|
|
4702
|
+
init_profile2();
|
|
4460
4703
|
UNSET_ENV = ["CLOUDFLARE_ACCOUNT_ID"];
|
|
4461
4704
|
SANDBOX_CONTAINER_CLASS = "SwitchboardSandbox";
|
|
4462
4705
|
SANDBOX_BEARER_ENV = "SANDBOX_TOKEN";
|
|
@@ -5207,7 +5450,7 @@ var init_wranglerTemplate = __esm({
|
|
|
5207
5450
|
"use strict";
|
|
5208
5451
|
init_images();
|
|
5209
5452
|
init_plan();
|
|
5210
|
-
|
|
5453
|
+
init_profile2();
|
|
5211
5454
|
init_images();
|
|
5212
5455
|
TEMPLATE_FILE = "wrangler.template.jsonc";
|
|
5213
5456
|
RENDERED_FILE = "wrangler.jsonc";
|
|
@@ -5406,7 +5649,7 @@ var init_restart = __esm({
|
|
|
5406
5649
|
init_ingressTokens();
|
|
5407
5650
|
init_authorize();
|
|
5408
5651
|
init_liveGate();
|
|
5409
|
-
|
|
5652
|
+
init_profile2();
|
|
5410
5653
|
RESTART_TOKEN_ENV = "SWITCHBOARD_DEPLOY_TOKEN";
|
|
5411
5654
|
RESTART_SCOPE = "deploy:write";
|
|
5412
5655
|
RESTART_AUTHORIZE_PATH = "/admin/restart/authorize";
|
|
@@ -6387,7 +6630,7 @@ var init_run = __esm({
|
|
|
6387
6630
|
init_wranglerTemplate();
|
|
6388
6631
|
init_configSource();
|
|
6389
6632
|
init_images();
|
|
6390
|
-
|
|
6633
|
+
init_profile2();
|
|
6391
6634
|
init_restart();
|
|
6392
6635
|
init_wranglerTemplate();
|
|
6393
6636
|
init_sandboxLiveGate();
|
|
@@ -6869,8 +7112,8 @@ var init_registryTransferHost = __esm({
|
|
|
6869
7112
|
SHORT_MS = 6e4;
|
|
6870
7113
|
LONG_MS = 30 * 6e4;
|
|
6871
7114
|
TransferProblem = class extends Error {
|
|
6872
|
-
constructor(
|
|
6873
|
-
super(
|
|
7115
|
+
constructor(message2, unauthorized = false) {
|
|
7116
|
+
super(message2);
|
|
6874
7117
|
this.unauthorized = unauthorized;
|
|
6875
7118
|
}
|
|
6876
7119
|
unauthorized;
|
|
@@ -7497,7 +7740,7 @@ var TEMPLATE_PATHS;
|
|
|
7497
7740
|
var init_host3 = __esm({
|
|
7498
7741
|
"../../src/setup/host.ts"() {
|
|
7499
7742
|
"use strict";
|
|
7500
|
-
|
|
7743
|
+
init_profile2();
|
|
7501
7744
|
init_packageRoot();
|
|
7502
7745
|
init_host();
|
|
7503
7746
|
init_meatProcess();
|
|
@@ -7509,42 +7752,6 @@ var init_host3 = __esm({
|
|
|
7509
7752
|
}
|
|
7510
7753
|
});
|
|
7511
7754
|
|
|
7512
|
-
// ../../src/execution/bashTimeout.ts
|
|
7513
|
-
function clampBashTimeout(requested) {
|
|
7514
|
-
if (typeof requested !== "number" || !Number.isFinite(requested)) return BASH_TIMEOUT_MS;
|
|
7515
|
-
return Math.min(Math.max(Math.trunc(requested), BASH_TIMEOUT_MIN_MS), BASH_TIMEOUT_MAX_MS);
|
|
7516
|
-
}
|
|
7517
|
-
function bashBudgetWithinRun(wantedMs, remainingMs) {
|
|
7518
|
-
const secs = (ms) => Math.max(0, Math.round(ms / 1e3));
|
|
7519
|
-
const cap = Math.trunc(remainingMs - RUN_DEADLINE_RESERVE_MS);
|
|
7520
|
-
if (cap < BASH_TIMEOUT_MIN_MS) {
|
|
7521
|
-
return {
|
|
7522
|
-
kind: "exhausted",
|
|
7523
|
-
note: `run budget exhausted \u2014 ${secs(remainingMs)}s of wall clock left, inside the ${secs(RUN_DEADLINE_RESERVE_MS)}s write-up reserve, so the command was not run; write up what you have now`
|
|
7524
|
-
};
|
|
7525
|
-
}
|
|
7526
|
-
if (cap >= wantedMs) return { kind: "unchanged" };
|
|
7527
|
-
return {
|
|
7528
|
-
kind: "clipped",
|
|
7529
|
-
timeoutMs: cap,
|
|
7530
|
-
note: `[timeout clipped to ${secs(cap)}s \u2014 the run's wall clock ends in ${secs(remainingMs)}s]`
|
|
7531
|
-
};
|
|
7532
|
-
}
|
|
7533
|
-
function bashTimeoutNote(timeoutMs) {
|
|
7534
|
-
return `aborted at the ${Math.round(timeoutMs / 1e3)}s command timeout (pass the bash tool's timeoutMs for longer commands, max ${BASH_TIMEOUT_MAX_MS} ms)`;
|
|
7535
|
-
}
|
|
7536
|
-
var BASH_TIMEOUT_MS, BASH_TIMEOUT_MIN_MS, BASH_TIMEOUT_MAX_MS, RUN_DEADLINE_RESERVE_MS, EXEC_CALL_MARGIN_MS;
|
|
7537
|
-
var init_bashTimeout = __esm({
|
|
7538
|
-
"../../src/execution/bashTimeout.ts"() {
|
|
7539
|
-
"use strict";
|
|
7540
|
-
BASH_TIMEOUT_MS = 5 * 6e4;
|
|
7541
|
-
BASH_TIMEOUT_MIN_MS = 1e3;
|
|
7542
|
-
BASH_TIMEOUT_MAX_MS = 20 * 6e4;
|
|
7543
|
-
RUN_DEADLINE_RESERVE_MS = 6e4;
|
|
7544
|
-
EXEC_CALL_MARGIN_MS = 3e4;
|
|
7545
|
-
}
|
|
7546
|
-
});
|
|
7547
|
-
|
|
7548
7755
|
// ../../src/execution/executor.ts
|
|
7549
7756
|
import { execFile } from "node:child_process";
|
|
7550
7757
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
@@ -7602,15 +7809,15 @@ var init_executor = __esm({
|
|
|
7602
7809
|
init_bashTimeout();
|
|
7603
7810
|
ExecInfraError = class extends Error {
|
|
7604
7811
|
infra = true;
|
|
7605
|
-
constructor(
|
|
7606
|
-
super(
|
|
7812
|
+
constructor(message2) {
|
|
7813
|
+
super(message2);
|
|
7607
7814
|
this.name = "ExecInfraError";
|
|
7608
7815
|
}
|
|
7609
7816
|
};
|
|
7610
7817
|
ExecCapacityError = class extends Error {
|
|
7611
7818
|
capacity = true;
|
|
7612
|
-
constructor(
|
|
7613
|
-
super(
|
|
7819
|
+
constructor(message2) {
|
|
7820
|
+
super(message2);
|
|
7614
7821
|
this.name = "ExecCapacityError";
|
|
7615
7822
|
}
|
|
7616
7823
|
};
|
|
@@ -8905,7 +9112,7 @@ var init_residentState = __esm({
|
|
|
8905
9112
|
import { resolve as resolve7 } from "node:path";
|
|
8906
9113
|
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
8907
9114
|
async function makeExecutor(opts, ctx, span) {
|
|
8908
|
-
const machine = ctx.
|
|
9115
|
+
const machine = ctx.profile.machine;
|
|
8909
9116
|
if (machine === "none") {
|
|
8910
9117
|
return { executor: new NullExecutor(ctx.agent.name), backend: "local" };
|
|
8911
9118
|
}
|
|
@@ -8930,7 +9137,7 @@ async function makeExecutor(opts, ctx, span) {
|
|
|
8930
9137
|
if (probe.kind === "status" && isServiceable(probe.state, probe.reason)) {
|
|
8931
9138
|
try {
|
|
8932
9139
|
const nonWarm = probe.state === "warm" ? void 0 : oneLine(`${probe.state}${probe.reason ? ` (${probe.reason})` : ""}`);
|
|
8933
|
-
const readonly = ctx.
|
|
9140
|
+
const readonly = ctx.profile.identity === "read" ? true : void 0;
|
|
8934
9141
|
return await openResident(
|
|
8935
9142
|
{
|
|
8936
9143
|
baseUrl: resident.baseUrl,
|
|
@@ -9056,7 +9263,12 @@ function localWorkspaceDir(baseDir, threadKey) {
|
|
|
9056
9263
|
return resolve7(baseDir, safe);
|
|
9057
9264
|
}
|
|
9058
9265
|
function perThreadCheckout(ctx) {
|
|
9059
|
-
return {
|
|
9266
|
+
return {
|
|
9267
|
+
threadKey: ctx.threadKey,
|
|
9268
|
+
repo: ctx.repo,
|
|
9269
|
+
ref: ctx.ref,
|
|
9270
|
+
resolveEnvs: () => githubEnvs(ctx.profile.identity)
|
|
9271
|
+
};
|
|
9060
9272
|
}
|
|
9061
9273
|
async function makePerThreadExecutor(opts, input) {
|
|
9062
9274
|
const { threadKey } = input;
|
|
@@ -9098,11 +9310,13 @@ async function makePerThreadExecutor(opts, input) {
|
|
|
9098
9310
|
}
|
|
9099
9311
|
throw new Error(`Unknown execution.type "${type}" (valid: local, e2b, cloudflare)`);
|
|
9100
9312
|
}
|
|
9101
|
-
function githubTokenScopeFor(
|
|
9102
|
-
return
|
|
9313
|
+
function githubTokenScopeFor(identity2) {
|
|
9314
|
+
return identity2 === "none" ? void 0 : identity2;
|
|
9103
9315
|
}
|
|
9104
|
-
async function githubEnvs(
|
|
9105
|
-
const
|
|
9316
|
+
async function githubEnvs(identity2) {
|
|
9317
|
+
const scope = githubTokenScopeFor(identity2);
|
|
9318
|
+
if (scope === void 0) return {};
|
|
9319
|
+
const token = await resolveGithubToken(scope);
|
|
9106
9320
|
return token ? { GH_TOKEN: token } : {};
|
|
9107
9321
|
}
|
|
9108
9322
|
function perThreadBackend(opts) {
|
|
@@ -9170,9 +9384,9 @@ function parseFindings(body) {
|
|
|
9170
9384
|
function isAgentLogin(login, identities) {
|
|
9171
9385
|
return login.endsWith("[bot]") || identities.agentLogins.includes(login);
|
|
9172
9386
|
}
|
|
9173
|
-
function coauthorsOf(
|
|
9387
|
+
function coauthorsOf(message2) {
|
|
9174
9388
|
const out = [];
|
|
9175
|
-
for (const line3 of
|
|
9389
|
+
for (const line3 of message2.split("\n")) {
|
|
9176
9390
|
const m = /^\s*co-authored-by:\s*(.+?)\s*$/i.exec(line3);
|
|
9177
9391
|
if (m) out.push(m[1]);
|
|
9178
9392
|
}
|
|
@@ -9365,9 +9579,25 @@ function indicatorLines(x) {
|
|
|
9365
9579
|
`agent runs: ${x.agentRuns.count} \xB7 ${x.agentRuns.minutes.toFixed(1)} min`
|
|
9366
9580
|
];
|
|
9367
9581
|
}
|
|
9368
|
-
function
|
|
9582
|
+
function snapshotAgeText(snapshotAt, nowMs) {
|
|
9583
|
+
const minutes = Math.max(0, Math.floor((nowMs - Date.parse(snapshotAt)) / 6e4));
|
|
9584
|
+
if (!Number.isFinite(minutes)) return "";
|
|
9585
|
+
const unit = (n2, word) => `${n2} ${word}${n2 === 1 ? "" : "s"} ago`;
|
|
9586
|
+
if (minutes < 1) return "just now";
|
|
9587
|
+
if (minutes < 90) return unit(minutes, "minute");
|
|
9588
|
+
const hours2 = Math.round(minutes / 60);
|
|
9589
|
+
if (hours2 < 48) return unit(hours2, "hour");
|
|
9590
|
+
return unit(Math.round(hours2 / 24), "day");
|
|
9591
|
+
}
|
|
9592
|
+
function asOf(snapshotAt, nowMs) {
|
|
9593
|
+
return `as of ${snapshotAt.slice(0, 10)} ${snapshotAt.slice(11, 16)} UTC, ${snapshotAgeText(snapshotAt, nowMs)}`;
|
|
9594
|
+
}
|
|
9595
|
+
function renderDeliveryReport(report2, nowMs = systemClock()) {
|
|
9369
9596
|
const lines = [
|
|
9370
|
-
|
|
9597
|
+
[
|
|
9598
|
+
`${report2.repo} \xB7 ${report2.range.since} \u2192 ${report2.range.until} \xB7 ${report2.range.weeks} week${report2.range.weeks === 1 ? "" : "s"}`,
|
|
9599
|
+
...report2.snapshotAt !== void 0 ? [asOf(report2.snapshotAt, nowMs)] : []
|
|
9600
|
+
].join(" \xB7 ")
|
|
9371
9601
|
];
|
|
9372
9602
|
if (report2.truncated) lines.push("(the newest pull requests only \u2014 the fetch stopped before the range's start)");
|
|
9373
9603
|
for (const w of report2.weeks) {
|
|
@@ -9409,6 +9639,18 @@ function stringList(raw, what, valid = () => true) {
|
|
|
9409
9639
|
throw new Error(`${what} must be a list of ${what.endsWith("repos") ? "owner/name repositories" : "names"}`);
|
|
9410
9640
|
return raw;
|
|
9411
9641
|
}
|
|
9642
|
+
function snapshotConfig(raw) {
|
|
9643
|
+
if (raw === void 0) return { everyMinutes: SNAPSHOT_EVERY_MINUTES.default };
|
|
9644
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
9645
|
+
throw new Error("delivery.snapshot must be a mapping");
|
|
9646
|
+
const every = raw.everyMinutes;
|
|
9647
|
+
if (every === void 0) return { everyMinutes: SNAPSHOT_EVERY_MINUTES.default };
|
|
9648
|
+
if (typeof every !== "number" || !Number.isInteger(every) || every < SNAPSHOT_EVERY_MINUTES.min || every > SNAPSHOT_EVERY_MINUTES.max)
|
|
9649
|
+
throw new Error(
|
|
9650
|
+
`delivery.snapshot.everyMinutes must be a whole number of minutes between ${SNAPSHOT_EVERY_MINUTES.min} and ${SNAPSHOT_EVERY_MINUTES.max}`
|
|
9651
|
+
);
|
|
9652
|
+
return { everyMinutes: every };
|
|
9653
|
+
}
|
|
9412
9654
|
function parseDeliveryConfig(raw) {
|
|
9413
9655
|
if (raw === void 0 || raw === null) return void 0;
|
|
9414
9656
|
if (typeof raw !== "object" || Array.isArray(raw)) throw new Error("delivery: must be a mapping");
|
|
@@ -9417,7 +9659,8 @@ function parseDeliveryConfig(raw) {
|
|
|
9417
9659
|
repos: stringList(r.repos, "delivery.repos", (s) => REPO_SLUG.test(s)),
|
|
9418
9660
|
reviewers: stringList(r.reviewers, "delivery.reviewers"),
|
|
9419
9661
|
agentLogins: stringList(r.agentLogins, "delivery.agentLogins"),
|
|
9420
|
-
agentCoauthors: stringList(r.agentCoauthors, "delivery.agentCoauthors")
|
|
9662
|
+
agentCoauthors: stringList(r.agentCoauthors, "delivery.agentCoauthors"),
|
|
9663
|
+
snapshot: snapshotConfig(r.snapshot)
|
|
9421
9664
|
};
|
|
9422
9665
|
}
|
|
9423
9666
|
function createDeliveryService(cfg, source2, opts = {}) {
|
|
@@ -9427,9 +9670,10 @@ function createDeliveryService(cfg, source2, opts = {}) {
|
|
|
9427
9670
|
repos: () => [...cfg?.repos ?? []],
|
|
9428
9671
|
async report(repo, o) {
|
|
9429
9672
|
if (!REPO_SLUG.test(repo)) throw new Error(`repository must be owner/name, got ${JSON.stringify(repo)}`);
|
|
9430
|
-
const
|
|
9673
|
+
const at = now();
|
|
9674
|
+
const range = resolveDeliveryRange({ since: o.since, weeks: o.weeks }, at);
|
|
9431
9675
|
const [fetched, process2, runs] = await Promise.all([
|
|
9432
|
-
source2.fetchPullRequests(repo, range),
|
|
9676
|
+
source2.fetchPullRequests(repo, range, o.fresh ? { fresh: true } : void 0),
|
|
9433
9677
|
opts.identities?.() ?? Promise.resolve({}),
|
|
9434
9678
|
o.runs?.(range) ?? Promise.resolve([])
|
|
9435
9679
|
]);
|
|
@@ -9438,18 +9682,22 @@ function createDeliveryService(cfg, source2, opts = {}) {
|
|
|
9438
9682
|
agentLogins: [.../* @__PURE__ */ new Set([...cfg?.agentLogins ?? [], ...process2.agentLogins ?? []])],
|
|
9439
9683
|
agentCoauthors: [.../* @__PURE__ */ new Set([...cfg?.agentCoauthors ?? [], ...process2.agentCoauthors ?? []])]
|
|
9440
9684
|
};
|
|
9441
|
-
return
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9685
|
+
return {
|
|
9686
|
+
...buildDeliveryReport({
|
|
9687
|
+
repo,
|
|
9688
|
+
range,
|
|
9689
|
+
prs: fetched.prs,
|
|
9690
|
+
runs,
|
|
9691
|
+
identities,
|
|
9692
|
+
truncated: fetched.truncated
|
|
9693
|
+
}),
|
|
9694
|
+
// A source behind a snapshot says when it read; a bare one read just now.
|
|
9695
|
+
snapshotAt: fetched.fetchedAt ?? at.toISOString()
|
|
9696
|
+
};
|
|
9449
9697
|
}
|
|
9450
9698
|
};
|
|
9451
9699
|
}
|
|
9452
|
-
var FINDING_SEVERITIES, DAY_MS, HOUR_MS, emptyCounts, CI_TRIGGERS, CI_DECISIVE, byTime, EMPTY_IDENTITIES, DEFAULT_WEEKS, MAX_WEEKS, ISO_DAY, pct, hours, REPO_SLUG, DELIVERY_OFF_MESSAGE, NullDeliveryService;
|
|
9700
|
+
var FINDING_SEVERITIES, DAY_MS, HOUR_MS, emptyCounts, CI_TRIGGERS, CI_DECISIVE, byTime, EMPTY_IDENTITIES, DEFAULT_WEEKS, MAX_WEEKS, ISO_DAY, pct, hours, SNAPSHOT_EVERY_MINUTES, REPO_SLUG, DELIVERY_OFF_MESSAGE, NullDeliveryService;
|
|
9453
9701
|
var init_delivery = __esm({
|
|
9454
9702
|
"../../src/core/delivery.ts"() {
|
|
9455
9703
|
"use strict";
|
|
@@ -9477,6 +9725,7 @@ var init_delivery = __esm({
|
|
|
9477
9725
|
ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
9478
9726
|
pct = (share) => share === null ? "\u2014" : `${Math.round(share * 100)}%`;
|
|
9479
9727
|
hours = (h, digits2 = 1) => h === null ? "\u2014" : `${h.toFixed(digits2)} h`;
|
|
9728
|
+
SNAPSHOT_EVERY_MINUTES = Object.freeze({ default: 60, min: 5, max: 1440 });
|
|
9480
9729
|
REPO_SLUG = /^(?!\.+\/)[\w.-]+\/(?!\.+$)[\w.-]+$/;
|
|
9481
9730
|
DELIVERY_OFF_MESSAGE = "Delivery indicators aren't available \u2014 this process has no GitHub credential (the GitHub App triple or GH_TOKEN); set one, then name repositories under delivery.repos.";
|
|
9482
9731
|
NullDeliveryService = class {
|
|
@@ -9730,12 +9979,16 @@ var init_githubDelivery = __esm({
|
|
|
9730
9979
|
const json = async (res) => res.status === 404 ? void 0 : res.json();
|
|
9731
9980
|
const merged = [];
|
|
9732
9981
|
let truncated = false;
|
|
9982
|
+
let oldestUpdated;
|
|
9733
9983
|
for (let page2 = 1; ; page2++) {
|
|
9734
9984
|
const res = await get(
|
|
9735
9985
|
"pulls",
|
|
9736
9986
|
`/repos/${repo}/pulls?state=closed&sort=updated&direction=desc&per_page=${PAGE_SIZE}&page=${page2}`
|
|
9737
9987
|
);
|
|
9738
9988
|
const items = parsePullListPage(await json(res));
|
|
9989
|
+
for (const item of items) {
|
|
9990
|
+
if (!oldestUpdated || Date.parse(item.updatedAt) < Date.parse(oldestUpdated.updatedAt)) oldestUpdated = item;
|
|
9991
|
+
}
|
|
9739
9992
|
const selected = selectMerged(items, range);
|
|
9740
9993
|
merged.push(...selected.merged);
|
|
9741
9994
|
if (selected.olderSeen || items.length < PAGE_SIZE) break;
|
|
@@ -9744,6 +9997,7 @@ var init_githubDelivery = __esm({
|
|
|
9744
9997
|
break;
|
|
9745
9998
|
}
|
|
9746
9999
|
}
|
|
10000
|
+
const completeFrom = truncated && oldestUpdated ? oldestUpdated.updatedAt : `${range.since}T00:00:00Z`;
|
|
9747
10001
|
const issues = /* @__PURE__ */ new Map();
|
|
9748
10002
|
const issueOf = (n2) => {
|
|
9749
10003
|
let p = issues.get(n2);
|
|
@@ -9790,12 +10044,257 @@ var init_githubDelivery = __esm({
|
|
|
9790
10044
|
...issue ? { issue } : {}
|
|
9791
10045
|
};
|
|
9792
10046
|
});
|
|
9793
|
-
return { prs, truncated };
|
|
10047
|
+
return { prs, truncated, completeFrom };
|
|
9794
10048
|
}
|
|
9795
10049
|
};
|
|
9796
10050
|
}
|
|
9797
10051
|
});
|
|
9798
10052
|
|
|
10053
|
+
// ../../src/core/deliverySnapshot.ts
|
|
10054
|
+
function snapshotAgeMinutes(snapshotAt, nowMs) {
|
|
10055
|
+
return Math.max(0, Math.floor((nowMs - Date.parse(snapshotAt)) / 6e4));
|
|
10056
|
+
}
|
|
10057
|
+
function serve(snapshot, range) {
|
|
10058
|
+
return {
|
|
10059
|
+
prs: snapshot.prs,
|
|
10060
|
+
truncated: dayStart(range.since) < Date.parse(snapshot.completeFrom),
|
|
10061
|
+
fetchedAt: snapshot.snapshotAt
|
|
10062
|
+
};
|
|
10063
|
+
}
|
|
10064
|
+
var SNAPSHOT_WEEKS, SNAPSHOT_TICK_MS, dayStart, message, SnapshottingDeliverySource;
|
|
10065
|
+
var init_deliverySnapshot = __esm({
|
|
10066
|
+
"../../src/core/deliverySnapshot.ts"() {
|
|
10067
|
+
"use strict";
|
|
10068
|
+
init_delivery();
|
|
10069
|
+
init_clock();
|
|
10070
|
+
SNAPSHOT_WEEKS = 13;
|
|
10071
|
+
SNAPSHOT_TICK_MS = 6e4;
|
|
10072
|
+
dayStart = (day) => Date.parse(`${day}T00:00:00Z`);
|
|
10073
|
+
message = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
10074
|
+
SnapshottingDeliverySource = class {
|
|
10075
|
+
constructor(inner, store, opts = {}) {
|
|
10076
|
+
this.inner = inner;
|
|
10077
|
+
this.store = store;
|
|
10078
|
+
this.now = opts.now ?? (() => new Date(systemClock()));
|
|
10079
|
+
this.warn = opts.warn ?? (() => void 0);
|
|
10080
|
+
this.weeks = opts.weeks ?? SNAPSHOT_WEEKS;
|
|
10081
|
+
}
|
|
10082
|
+
inner;
|
|
10083
|
+
store;
|
|
10084
|
+
memory = /* @__PURE__ */ new Map();
|
|
10085
|
+
/** Store reads in flight, one per repository. */
|
|
10086
|
+
loading = /* @__PURE__ */ new Map();
|
|
10087
|
+
/** GitHub reads in flight, one per repository: concurrent callers share it. */
|
|
10088
|
+
refreshing = /* @__PURE__ */ new Map();
|
|
10089
|
+
now;
|
|
10090
|
+
warn;
|
|
10091
|
+
weeks;
|
|
10092
|
+
async fetchPullRequests(repo, range, opts) {
|
|
10093
|
+
const snapshot = opts?.fresh ? void 0 : await this.current(repo);
|
|
10094
|
+
if (snapshot && range.since >= snapshot.range.since) return serve(snapshot, range);
|
|
10095
|
+
if (range.since < this.window().since) return this.live(repo, range);
|
|
10096
|
+
return serve(await this.refresh(repo), range);
|
|
10097
|
+
}
|
|
10098
|
+
/** The repository's snapshot as this process knows it: memory, else the store, read once. */
|
|
10099
|
+
current(repo) {
|
|
10100
|
+
const known = this.memory.get(repo);
|
|
10101
|
+
if (known) return Promise.resolve(known);
|
|
10102
|
+
let loading = this.loading.get(repo);
|
|
10103
|
+
if (!loading) {
|
|
10104
|
+
loading = this.store.get(repo).then((stored) => {
|
|
10105
|
+
if (stored) this.memory.set(repo, stored);
|
|
10106
|
+
return stored;
|
|
10107
|
+
}).catch((err2) => {
|
|
10108
|
+
this.warn(`delivery snapshot for ${repo} not read from the store: ${message(err2)}`);
|
|
10109
|
+
return void 0;
|
|
10110
|
+
}).finally(() => this.loading.delete(repo));
|
|
10111
|
+
this.loading.set(repo, loading);
|
|
10112
|
+
}
|
|
10113
|
+
return loading;
|
|
10114
|
+
}
|
|
10115
|
+
/** Read the window from GitHub now, keep it in memory and store it. One read at a time per repository. */
|
|
10116
|
+
refresh(repo) {
|
|
10117
|
+
let refreshing = this.refreshing.get(repo);
|
|
10118
|
+
if (!refreshing) {
|
|
10119
|
+
refreshing = this.read(repo).finally(() => this.refreshing.delete(repo));
|
|
10120
|
+
this.refreshing.set(repo, refreshing);
|
|
10121
|
+
}
|
|
10122
|
+
return refreshing;
|
|
10123
|
+
}
|
|
10124
|
+
/**
|
|
10125
|
+
* Keep every named repository's snapshot within `everyMinutes`: a tick a
|
|
10126
|
+
* minute (unref'd — it never holds the process open) refreshes the ones
|
|
10127
|
+
* missing or older than the interval, one repository at a time, and runs
|
|
10128
|
+
* once at start so a stale snapshot after a restart is refreshed at once
|
|
10129
|
+
* and a young one is left alone. A failing refresh is a warning; the next
|
|
10130
|
+
* tick tries again. `tick()` is the pass itself, for tests.
|
|
10131
|
+
*/
|
|
10132
|
+
startRefreshLoop(opts) {
|
|
10133
|
+
let running;
|
|
10134
|
+
const pass = async () => {
|
|
10135
|
+
for (const repo of opts.repos) {
|
|
10136
|
+
try {
|
|
10137
|
+
const current = await this.current(repo);
|
|
10138
|
+
if (current && snapshotAgeMinutes(current.snapshotAt, this.now().getTime()) < opts.everyMinutes) continue;
|
|
10139
|
+
await this.refresh(repo);
|
|
10140
|
+
} catch (err2) {
|
|
10141
|
+
this.warn(`delivery snapshot for ${repo} not refreshed: ${message(err2)}`);
|
|
10142
|
+
}
|
|
10143
|
+
}
|
|
10144
|
+
};
|
|
10145
|
+
const tick = () => running ??= pass().finally(() => {
|
|
10146
|
+
running = void 0;
|
|
10147
|
+
});
|
|
10148
|
+
const start2 = opts.setInterval ?? ((fn, ms) => {
|
|
10149
|
+
const t = setInterval(fn, ms);
|
|
10150
|
+
t.unref?.();
|
|
10151
|
+
return t;
|
|
10152
|
+
});
|
|
10153
|
+
const stop = opts.clearInterval ?? ((t) => clearInterval(t));
|
|
10154
|
+
const timer = start2(() => void tick(), SNAPSHOT_TICK_MS);
|
|
10155
|
+
timer.unref?.();
|
|
10156
|
+
void tick();
|
|
10157
|
+
return { stop: () => stop(timer), tick };
|
|
10158
|
+
}
|
|
10159
|
+
window() {
|
|
10160
|
+
return resolveDeliveryRange({ weeks: this.weeks }, this.now());
|
|
10161
|
+
}
|
|
10162
|
+
async live(repo, range) {
|
|
10163
|
+
const startedAt = this.now();
|
|
10164
|
+
const fetched = await this.inner.fetchPullRequests(repo, range);
|
|
10165
|
+
return { prs: fetched.prs, truncated: fetched.truncated, fetchedAt: startedAt.toISOString() };
|
|
10166
|
+
}
|
|
10167
|
+
async read(repo) {
|
|
10168
|
+
const startedAt = this.now();
|
|
10169
|
+
const range = resolveDeliveryRange({ weeks: this.weeks }, startedAt);
|
|
10170
|
+
const fetched = await this.inner.fetchPullRequests(repo, range);
|
|
10171
|
+
const snapshot = {
|
|
10172
|
+
repo,
|
|
10173
|
+
snapshotAt: startedAt.toISOString(),
|
|
10174
|
+
range,
|
|
10175
|
+
prs: fetched.prs,
|
|
10176
|
+
truncated: fetched.truncated,
|
|
10177
|
+
completeFrom: fetched.completeFrom ?? `${range.since}T00:00:00Z`
|
|
10178
|
+
};
|
|
10179
|
+
this.memory.set(repo, snapshot);
|
|
10180
|
+
try {
|
|
10181
|
+
await this.store.put(snapshot);
|
|
10182
|
+
} catch (err2) {
|
|
10183
|
+
this.warn(`delivery snapshot for ${repo} not stored: ${message(err2)}`);
|
|
10184
|
+
}
|
|
10185
|
+
return snapshot;
|
|
10186
|
+
}
|
|
10187
|
+
};
|
|
10188
|
+
}
|
|
10189
|
+
});
|
|
10190
|
+
|
|
10191
|
+
// ../../src/core/workerError.ts
|
|
10192
|
+
async function errorSuffix(res) {
|
|
10193
|
+
const text = await res.text().catch(() => "");
|
|
10194
|
+
try {
|
|
10195
|
+
const parsed = JSON.parse(text);
|
|
10196
|
+
return parsed?.error ? `: ${String(parsed.error)}` : "";
|
|
10197
|
+
} catch {
|
|
10198
|
+
return "";
|
|
10199
|
+
}
|
|
10200
|
+
}
|
|
10201
|
+
var init_workerError = __esm({
|
|
10202
|
+
"../../src/core/workerError.ts"() {
|
|
10203
|
+
"use strict";
|
|
10204
|
+
}
|
|
10205
|
+
});
|
|
10206
|
+
|
|
10207
|
+
// ../../src/core/deliverySnapshotStore.ts
|
|
10208
|
+
function isPullRequestFacts(v) {
|
|
10209
|
+
if (typeof v !== "object" || v === null) return false;
|
|
10210
|
+
const p = v;
|
|
10211
|
+
return typeof p.number === "number" && Number.isFinite(p.number) && typeof p.title === "string" && typeof p.author === "string" && isInstant(p.createdAt) && isInstant(p.mergedAt) && (p.firstHeadSha === void 0 || typeof p.firstHeadSha === "string") && Array.isArray(p.ci) && Array.isArray(p.reviews) && Array.isArray(p.pushes) && (p.issue === void 0 || typeof p.issue === "object" && p.issue !== null);
|
|
10212
|
+
}
|
|
10213
|
+
function isDeliverySnapshot(v) {
|
|
10214
|
+
if (typeof v !== "object" || v === null) return false;
|
|
10215
|
+
const s = v;
|
|
10216
|
+
if (typeof s.repo !== "string" || !REPO_SLUG.test(s.repo)) return false;
|
|
10217
|
+
if (!isInstant(s.snapshotAt) || !isInstant(s.completeFrom)) return false;
|
|
10218
|
+
if (typeof s.truncated !== "boolean") return false;
|
|
10219
|
+
const range = s.range;
|
|
10220
|
+
if (typeof range !== "object" || range === null || typeof range.since !== "string" || !ISO_DAY2.test(range.since) || typeof range.until !== "string" || !ISO_DAY2.test(range.until) || typeof range.weeks !== "number" || !Number.isFinite(range.weeks))
|
|
10221
|
+
return false;
|
|
10222
|
+
return Array.isArray(s.prs) && s.prs.every(isPullRequestFacts);
|
|
10223
|
+
}
|
|
10224
|
+
function buildDeliverySnapshotStore(config, secrets, warn) {
|
|
10225
|
+
const worker = [config.runtimeOverrides, config.runHistory, config.schedules, config.memory].find(
|
|
10226
|
+
(block) => block?.worker?.baseUrl
|
|
10227
|
+
)?.worker;
|
|
10228
|
+
if (!worker) {
|
|
10229
|
+
warn(
|
|
10230
|
+
"delivery snapshots are kept in memory \u2014 a restart loses them and the first request after one reads GitHub live. Name the state Worker (runHistory.worker, runtimeOverrides.worker, schedules.worker or memory.worker) to keep them on it."
|
|
10231
|
+
);
|
|
10232
|
+
return new InMemoryDeliverySnapshotStore();
|
|
10233
|
+
}
|
|
10234
|
+
const tokenEnv = worker.tokenEnv ?? DEFAULT_TOKEN_ENV;
|
|
10235
|
+
const token = secrets.named(tokenEnv);
|
|
10236
|
+
if (!token) {
|
|
10237
|
+
warn(
|
|
10238
|
+
`the state Worker is configured but ${tokenEnv} is unset \u2014 delivery snapshots are kept in memory and a restart loses them. Set ${tokenEnv} to the state Worker's bearer.`
|
|
10239
|
+
);
|
|
10240
|
+
return new InMemoryDeliverySnapshotStore();
|
|
10241
|
+
}
|
|
10242
|
+
return new WorkerDeliverySnapshotStore({ baseUrl: worker.baseUrl, token: token.reveal() });
|
|
10243
|
+
}
|
|
10244
|
+
var ISO_DAY2, isInstant, InMemoryDeliverySnapshotStore, SNAPSHOT_WORKER_TIMEOUT_MS, WorkerDeliverySnapshotStore, DEFAULT_TOKEN_ENV;
|
|
10245
|
+
var init_deliverySnapshotStore = __esm({
|
|
10246
|
+
"../../src/core/deliverySnapshotStore.ts"() {
|
|
10247
|
+
"use strict";
|
|
10248
|
+
init_delivery();
|
|
10249
|
+
init_workerError();
|
|
10250
|
+
ISO_DAY2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
10251
|
+
isInstant = (v) => typeof v === "string" && Number.isFinite(Date.parse(v));
|
|
10252
|
+
InMemoryDeliverySnapshotStore = class {
|
|
10253
|
+
byRepo = /* @__PURE__ */ new Map();
|
|
10254
|
+
async get(repo) {
|
|
10255
|
+
const s = this.byRepo.get(repo);
|
|
10256
|
+
return s ? structuredClone(s) : void 0;
|
|
10257
|
+
}
|
|
10258
|
+
async put(snapshot) {
|
|
10259
|
+
this.byRepo.set(snapshot.repo, structuredClone(snapshot));
|
|
10260
|
+
}
|
|
10261
|
+
};
|
|
10262
|
+
SNAPSHOT_WORKER_TIMEOUT_MS = 3e4;
|
|
10263
|
+
WorkerDeliverySnapshotStore = class {
|
|
10264
|
+
constructor(opts) {
|
|
10265
|
+
this.opts = opts;
|
|
10266
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
10267
|
+
this.fetchImpl = opts.fetch ?? fetch;
|
|
10268
|
+
}
|
|
10269
|
+
opts;
|
|
10270
|
+
baseUrl;
|
|
10271
|
+
fetchImpl;
|
|
10272
|
+
async get(repo) {
|
|
10273
|
+
const res = await this.post("/delivery/get", { repo });
|
|
10274
|
+
if (!res.ok) throw new Error(`state Worker /delivery/get HTTP ${res.status}${await errorSuffix(res)}`);
|
|
10275
|
+
const data = await res.json().catch(() => ({}));
|
|
10276
|
+
if (data.snapshot === null || data.snapshot === void 0) return void 0;
|
|
10277
|
+
if (!isDeliverySnapshot(data.snapshot))
|
|
10278
|
+
throw new Error(`state Worker /delivery/get: the answer for ${repo} is not a delivery snapshot`);
|
|
10279
|
+
return data.snapshot;
|
|
10280
|
+
}
|
|
10281
|
+
async put(snapshot) {
|
|
10282
|
+
const res = await this.post("/delivery/put", { snapshot });
|
|
10283
|
+
if (!res.ok) throw new Error(`state Worker /delivery/put HTTP ${res.status}${await errorSuffix(res)}`);
|
|
10284
|
+
}
|
|
10285
|
+
post(path, body) {
|
|
10286
|
+
return this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
10287
|
+
method: "POST",
|
|
10288
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${this.opts.token}` },
|
|
10289
|
+
body: JSON.stringify(body),
|
|
10290
|
+
signal: AbortSignal.timeout(SNAPSHOT_WORKER_TIMEOUT_MS)
|
|
10291
|
+
});
|
|
10292
|
+
}
|
|
10293
|
+
};
|
|
10294
|
+
DEFAULT_TOKEN_ENV = "MEMORY_TOKEN";
|
|
10295
|
+
}
|
|
10296
|
+
});
|
|
10297
|
+
|
|
9799
10298
|
// ../../src/core/runDuration.ts
|
|
9800
10299
|
function runDurationMs(stamps, now) {
|
|
9801
10300
|
const end = stamps.finishedAt ?? now;
|
|
@@ -10678,8 +11177,8 @@ function bindCommands(registry, deps) {
|
|
|
10678
11177
|
settle: (id, value, caller) => registry.settle(id, value, caller, deps)
|
|
10679
11178
|
};
|
|
10680
11179
|
}
|
|
10681
|
-
function fail(error,
|
|
10682
|
-
return { ok: false, error, status: ERROR_STATUS[error], message, decidedBy };
|
|
11180
|
+
function fail(error, message2, decidedBy = "registry") {
|
|
11181
|
+
return { ok: false, error, status: ERROR_STATUS[error], message: message2, decidedBy };
|
|
10683
11182
|
}
|
|
10684
11183
|
function rawInput(input) {
|
|
10685
11184
|
const args = typeof input === "object" && input !== null && Array.isArray(input.args) ? input.args : [];
|
|
@@ -10798,8 +11297,8 @@ var init_commandRegistry = __esm({
|
|
|
10798
11297
|
CAMEL_KEY = /^[a-z][A-Za-z0-9]*$/;
|
|
10799
11298
|
flag = z4.union([z4.boolean(), z4.enum(["true", "false"]).transform((v) => v === "true")]);
|
|
10800
11299
|
CommandError = class extends Error {
|
|
10801
|
-
constructor(code,
|
|
10802
|
-
super(
|
|
11300
|
+
constructor(code, message2) {
|
|
11301
|
+
super(message2);
|
|
10803
11302
|
this.code = code;
|
|
10804
11303
|
this.name = "CommandError";
|
|
10805
11304
|
}
|
|
@@ -10953,12 +11452,13 @@ function summarizeScope(s) {
|
|
|
10953
11452
|
function registerConfigCommands(registry) {
|
|
10954
11453
|
for (const cmd of configCommands) registry.register(cmd);
|
|
10955
11454
|
}
|
|
10956
|
-
var defineCommand2, scopeArg, channelOption, effort, effortLevels, modelRef, who, configShow, configSet, configClear, quote, configInstructions, configCommands;
|
|
11455
|
+
var defineCommand2, scopeArg, channelOption, effort, effortLevels, modelRef, boundaryOption, who, configShow, configSet, configClear, quote, configInstructions, configCommands;
|
|
10957
11456
|
var init_config3 = __esm({
|
|
10958
11457
|
"../../src/core/commands/config.ts"() {
|
|
10959
11458
|
"use strict";
|
|
10960
11459
|
init_config();
|
|
10961
11460
|
init_validate();
|
|
11461
|
+
init_registry();
|
|
10962
11462
|
init_effort();
|
|
10963
11463
|
init_authorize();
|
|
10964
11464
|
init_commandRegistry();
|
|
@@ -10972,6 +11472,11 @@ var init_config3 = __esm({
|
|
|
10972
11472
|
effort = z5.enum(EFFORT_LEVELS);
|
|
10973
11473
|
effortLevels = `<${EFFORT_LEVELS.join("|")}>`;
|
|
10974
11474
|
modelRef = z5.string().min(1);
|
|
11475
|
+
boundaryOption = z5.object({
|
|
11476
|
+
maxMinutes: z5.coerce.number().int().min(MIN_BOUNDARY_MINUTES).optional().describe(`cap the wall-clock budget of every run in this scope (minutes, >= ${MIN_BOUNDARY_MINUTES})`),
|
|
11477
|
+
maxIdentity: z5.enum(IDENTITIES).optional().describe(`cap the identity runs may act as <${IDENTITIES.join("|")}> \u2014 a preset above it is refused`),
|
|
11478
|
+
machines: z5.string().optional().describe(`the machine classes runs may execute on, comma-separated from ${MACHINE_CLASSES.join(", ")}`)
|
|
11479
|
+
}).optional();
|
|
10975
11480
|
who = (scope) => scope === "channel" ? "channel" : "your";
|
|
10976
11481
|
configShow = defineCommand2({
|
|
10977
11482
|
id: "config.show",
|
|
@@ -10998,11 +11503,12 @@ var init_config3 = __esm({
|
|
|
10998
11503
|
models: z5.record(z5.string(), modelRef).optional().describe("per-agent model: --models.<agent> provider/model"),
|
|
10999
11504
|
effort: effort.optional().describe(`force a model effort ${effortLevels}`),
|
|
11000
11505
|
efforts: z5.record(z5.string(), effort).optional().describe(`per-agent effort: --efforts.<agent> ${effortLevels}`),
|
|
11506
|
+
boundary: boundaryOption,
|
|
11001
11507
|
channel: channelOption
|
|
11002
11508
|
}),
|
|
11003
11509
|
action: "config:write",
|
|
11004
11510
|
effect: "write",
|
|
11005
|
-
describe: "Set the agent, model, or
|
|
11511
|
+
describe: "Set the agent, model, effort or boundary for a channel (gated) or for yourself; per-agent forms take --models.<agent> / --efforts.<agent>, the boundary's axes --boundary.<axis> (a boundary caps every run in the scope and never grants).",
|
|
11006
11512
|
render: (output) => {
|
|
11007
11513
|
const o = output;
|
|
11008
11514
|
return `Updated ${who(o.scope)} scope. Now: ${JSON.stringify(o.effective)}`;
|
|
@@ -11031,10 +11537,26 @@ var init_config3 = __esm({
|
|
|
11031
11537
|
if (options.models) patch.models = options.models;
|
|
11032
11538
|
if (options.effort !== void 0) patch.effort = options.effort;
|
|
11033
11539
|
if (options.efforts) patch.efforts = options.efforts;
|
|
11540
|
+
if (options.boundary) {
|
|
11541
|
+
const { machines, ...axes } = options.boundary;
|
|
11542
|
+
const boundary = { ...axes };
|
|
11543
|
+
if (machines !== void 0) {
|
|
11544
|
+
const classes = machines.split(",").map((m) => m.trim());
|
|
11545
|
+
if (classes.length === 0 || classes.some((m) => !MACHINE_CLASSES.includes(m)))
|
|
11546
|
+
throw new CommandError(
|
|
11547
|
+
"invalid_input",
|
|
11548
|
+
`boundary.machines: expected a comma-separated list of ${MACHINE_CLASSES.join(", ")}`
|
|
11549
|
+
);
|
|
11550
|
+
boundary.machines = classes;
|
|
11551
|
+
}
|
|
11552
|
+
const problem = boundaryProblem("boundary", boundary);
|
|
11553
|
+
if (problem) throw new CommandError("invalid_input", problem);
|
|
11554
|
+
if (Object.keys(boundary).length > 0) patch.boundary = boundary;
|
|
11555
|
+
}
|
|
11034
11556
|
if (Object.keys(patch).length === 0)
|
|
11035
11557
|
throw new CommandError(
|
|
11036
11558
|
"invalid_input",
|
|
11037
|
-
"nothing to set: pass --agent, --model, --models.<agent>, --effort, or --
|
|
11559
|
+
"nothing to set: pass --agent, --model, --models.<agent>, --effort, --efforts.<agent>, or --boundary.<maxMinutes|maxIdentity|machines>"
|
|
11038
11560
|
);
|
|
11039
11561
|
let effective;
|
|
11040
11562
|
if (args.scope === "channel") {
|
|
@@ -12244,6 +12766,17 @@ var init_runFriction = __esm({
|
|
|
12244
12766
|
});
|
|
12245
12767
|
|
|
12246
12768
|
// ../../src/core/runRecord.ts
|
|
12769
|
+
function isRunProfileRecord(v) {
|
|
12770
|
+
if (typeof v !== "object" || v === null) return false;
|
|
12771
|
+
const p = v;
|
|
12772
|
+
if (typeof p.preset !== "string") return false;
|
|
12773
|
+
if (typeof p.machine !== "string" || !Object.hasOwn(MACHINE_CLASSES_IN_RECORD, p.machine)) return false;
|
|
12774
|
+
if (typeof p.identity !== "string" || !Object.hasOwn(IDENTITIES_IN_RECORD, p.identity)) return false;
|
|
12775
|
+
if (!isFiniteNumber(p.minutes) || p.minutes <= 0) return false;
|
|
12776
|
+
if (p.boundedBy !== void 0 && (typeof p.boundedBy !== "string" || !Object.hasOwn(BOUNDARY_SCOPES_IN_RECORD, p.boundedBy)))
|
|
12777
|
+
return false;
|
|
12778
|
+
return true;
|
|
12779
|
+
}
|
|
12247
12780
|
function storedEventSeqs(events) {
|
|
12248
12781
|
let prev = 0;
|
|
12249
12782
|
for (const e of events) {
|
|
@@ -12369,6 +12902,7 @@ function isRunRecord(v) {
|
|
|
12369
12902
|
return false;
|
|
12370
12903
|
if (!isOptionalString(r.activity) || !isOptionalString(r.sourceUrl) || !isOptionalString(r.userName)) return false;
|
|
12371
12904
|
if (r.handoff !== void 0 && !isHandoffShape(r.handoff)) return false;
|
|
12905
|
+
if (r.profile !== void 0 && !isRunProfileRecord(r.profile)) return false;
|
|
12372
12906
|
if (typeof r.channelId !== "string" || typeof r.userId !== "string" || typeof r.threadKey !== "string") return false;
|
|
12373
12907
|
if (r.channelVisibility !== void 0 && !CHANNEL_VISIBILITIES2.includes(r.channelVisibility))
|
|
12374
12908
|
return false;
|
|
@@ -12495,7 +13029,7 @@ function dropSpanPairsFromTheMiddle(events, eventBudget) {
|
|
|
12495
13029
|
}
|
|
12496
13030
|
return events.filter((_, k) => !dropped.has(k));
|
|
12497
13031
|
}
|
|
12498
|
-
var RUN_STATUSES, RUN_ID_PATTERN, RUN_LIST_DEFAULT_LIMIT, RUN_LIST_MAX_LIMIT, RUN_EVENTS_DEFAULT_PAGE, RUN_EVENTS_MAX_PAGE, CHANNEL_VISIBILITIES2, KIB, MIB, GIB2, DEFAULT_RETENTION_POLICY, RETENTION_BOUNDS, MAX_RECORD_BYTES, MAX_EVENT_BYTES, ELLIPSIS, encoder;
|
|
13032
|
+
var RUN_STATUSES, RUN_ID_PATTERN, MACHINE_CLASSES_IN_RECORD, IDENTITIES_IN_RECORD, BOUNDARY_SCOPES_IN_RECORD, RUN_LIST_DEFAULT_LIMIT, RUN_LIST_MAX_LIMIT, RUN_EVENTS_DEFAULT_PAGE, RUN_EVENTS_MAX_PAGE, CHANNEL_VISIBILITIES2, KIB, MIB, GIB2, DEFAULT_RETENTION_POLICY, RETENTION_BOUNDS, MAX_RECORD_BYTES, MAX_EVENT_BYTES, ELLIPSIS, encoder;
|
|
12499
13033
|
var init_runRecord = __esm({
|
|
12500
13034
|
"../../src/core/runRecord.ts"() {
|
|
12501
13035
|
"use strict";
|
|
@@ -12504,6 +13038,19 @@ var init_runRecord = __esm({
|
|
|
12504
13038
|
init_runFriction();
|
|
12505
13039
|
RUN_STATUSES = ["completed", "stopped_soft", "stopped_hard", "failed", "interrupted"];
|
|
12506
13040
|
RUN_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
13041
|
+
MACHINE_CLASSES_IN_RECORD = {
|
|
13042
|
+
none: true,
|
|
13043
|
+
blank: true,
|
|
13044
|
+
"repo-cold": true,
|
|
13045
|
+
"repo-resident": true
|
|
13046
|
+
};
|
|
13047
|
+
IDENTITIES_IN_RECORD = { none: true, read: true, write: true };
|
|
13048
|
+
BOUNDARY_SCOPES_IN_RECORD = {
|
|
13049
|
+
defaults: true,
|
|
13050
|
+
channel: true,
|
|
13051
|
+
user: true,
|
|
13052
|
+
directive: true
|
|
13053
|
+
};
|
|
12507
13054
|
RUN_LIST_DEFAULT_LIMIT = 50;
|
|
12508
13055
|
RUN_LIST_MAX_LIMIT = 200;
|
|
12509
13056
|
RUN_EVENTS_DEFAULT_PAGE = 1e3;
|
|
@@ -12534,7 +13081,7 @@ import { z as z7 } from "zod";
|
|
|
12534
13081
|
function registerDeliveryCommands(registry) {
|
|
12535
13082
|
for (const cmd of deliveryCommands) registry.register(cmd);
|
|
12536
13083
|
}
|
|
12537
|
-
var defineCommand4, REPO_SLUG2,
|
|
13084
|
+
var defineCommand4, REPO_SLUG2, ISO_DAY3, asJson, deliveryReport, deliveryCommands;
|
|
12538
13085
|
var init_delivery2 = __esm({
|
|
12539
13086
|
"../../src/core/commands/delivery.ts"() {
|
|
12540
13087
|
"use strict";
|
|
@@ -12544,21 +13091,22 @@ var init_delivery2 = __esm({
|
|
|
12544
13091
|
init_runRecord();
|
|
12545
13092
|
defineCommand4 = commandDefiner();
|
|
12546
13093
|
REPO_SLUG2 = /^(?!\.+\/)[\w.-]+\/(?!\.+$)[\w.-]+$/;
|
|
12547
|
-
|
|
13094
|
+
ISO_DAY3 = /^\d{4}-\d{2}-\d{2}$/;
|
|
12548
13095
|
asJson = (v) => v;
|
|
12549
13096
|
deliveryReport = defineCommand4({
|
|
12550
13097
|
id: "delivery.report",
|
|
12551
13098
|
options: z7.object({
|
|
12552
13099
|
repo: z7.string().regex(REPO_SLUG2).optional().describe("the repository (`owner/name`); default: the first under `delivery.repos`"),
|
|
12553
|
-
since: z7.string().regex(
|
|
13100
|
+
since: z7.string().regex(ISO_DAY3).optional().describe("the first day of the range (`YYYY-MM-DD`, UTC); the range ends today"),
|
|
12554
13101
|
weeks: z7.coerce.number().int().min(1).max(MAX_WEEKS).optional().describe(
|
|
12555
13102
|
`Monday-start weeks back from this one (default 4, at most ${MAX_WEEKS}); --since, when given, decides instead`
|
|
12556
|
-
)
|
|
13103
|
+
),
|
|
13104
|
+
fresh: flag.optional().describe("read GitHub now instead of the repository's snapshot, and refresh the snapshot")
|
|
12557
13105
|
}),
|
|
12558
13106
|
action: "delivery:read",
|
|
12559
13107
|
effect: "read",
|
|
12560
13108
|
enabledWhen: (caps) => caps.github,
|
|
12561
|
-
describe: "Delivery indicators per week and per unit \u2014 issue-to-merge time, first-pass CI, review rounds, findings and the share resolved with no human edit \u2014
|
|
13109
|
+
describe: "Delivery indicators per week and per unit \u2014 issue-to-merge time, first-pass CI, review rounds, findings and the share resolved with no human edit \u2014 from the repository's snapshot of GitHub's facts (--fresh reads GitHub now) and the run history; nothing written.",
|
|
12562
13110
|
render: (output) => renderDeliveryReport(output),
|
|
12563
13111
|
handler: async ({ options, caller, deps }) => {
|
|
12564
13112
|
const service = await deps.delivery.service();
|
|
@@ -12578,11 +13126,13 @@ var init_delivery2 = __esm({
|
|
|
12578
13126
|
return runFactsOf(page2.runs, repo);
|
|
12579
13127
|
};
|
|
12580
13128
|
try {
|
|
12581
|
-
return asJson(
|
|
13129
|
+
return asJson(
|
|
13130
|
+
await service.report(repo, { since: options.since, weeks: options.weeks, fresh: options.fresh, runs })
|
|
13131
|
+
);
|
|
12582
13132
|
} catch (err2) {
|
|
12583
|
-
const
|
|
12584
|
-
if (
|
|
12585
|
-
throw new CommandError("unavailable", `delivery indicators unavailable: ${
|
|
13133
|
+
const message2 = err2 instanceof Error ? err2.message : String(err2);
|
|
13134
|
+
if (message2 === DELIVERY_OFF_MESSAGE) throw new CommandError("unavailable", message2);
|
|
13135
|
+
throw new CommandError("unavailable", `delivery indicators unavailable: ${message2}`);
|
|
12586
13136
|
}
|
|
12587
13137
|
}
|
|
12588
13138
|
});
|
|
@@ -12712,7 +13262,7 @@ var init_deploy = __esm({
|
|
|
12712
13262
|
init_operatorRoot();
|
|
12713
13263
|
init_restart();
|
|
12714
13264
|
init_run();
|
|
12715
|
-
|
|
13265
|
+
init_profile2();
|
|
12716
13266
|
init_wranglerTemplate();
|
|
12717
13267
|
init_secrets();
|
|
12718
13268
|
init_commandRegistry();
|
|
@@ -14307,7 +14857,7 @@ var init_help = __esm({
|
|
|
14307
14857
|
init_commandRegistry();
|
|
14308
14858
|
init_commandSurface();
|
|
14309
14859
|
defineCommand8 = commandDefiner();
|
|
14310
|
-
DIRECTIVES_HELP = "`agent:review model:anthropic/claude-opus-5 effort:low look at PR 42` (effort: low | medium | high \u2014 lower = faster turns)";
|
|
14860
|
+
DIRECTIVES_HELP = "`agent:review model:anthropic/claude-opus-5 effort:low budget:20 look at PR 42` (effort: low | medium | high \u2014 lower = faster turns; budget: whole minutes, at least 2 \u2014 narrows this run's wall clock, never widens it)";
|
|
14311
14861
|
helpShow = defineCommand8({
|
|
14312
14862
|
id: "help.show",
|
|
14313
14863
|
action: "help:read",
|
|
@@ -14446,8 +14996,8 @@ var init_types2 = __esm({
|
|
|
14446
14996
|
"../../src/mcp/types.ts"() {
|
|
14447
14997
|
"use strict";
|
|
14448
14998
|
McpError = class extends Error {
|
|
14449
|
-
constructor(code,
|
|
14450
|
-
super(
|
|
14999
|
+
constructor(code, message2) {
|
|
15000
|
+
super(message2);
|
|
14451
15001
|
this.code = code;
|
|
14452
15002
|
this.name = "McpError";
|
|
14453
15003
|
}
|
|
@@ -14630,12 +15180,12 @@ var init_client = __esm({
|
|
|
14630
15180
|
const res = await this.post({ jsonrpc: "2.0", id, method, params }, signal, o);
|
|
14631
15181
|
const session = res.headers.get("mcp-session-id");
|
|
14632
15182
|
if (session && o?.initializing) this.sessionId = session;
|
|
14633
|
-
const
|
|
14634
|
-
if (
|
|
14635
|
-
const code = typeof
|
|
14636
|
-
throw new McpError(code, `${method}: ${String(
|
|
15183
|
+
const message2 = await this.readResponse(res, id, signal);
|
|
15184
|
+
if (message2.error) {
|
|
15185
|
+
const code = typeof message2.error.code === "number" ? message2.error.code : "protocol";
|
|
15186
|
+
throw new McpError(code, `${method}: ${String(message2.error.message ?? "error")}`);
|
|
14637
15187
|
}
|
|
14638
|
-
return
|
|
15188
|
+
return message2.result;
|
|
14639
15189
|
}
|
|
14640
15190
|
async post(body, signal, o) {
|
|
14641
15191
|
const headers = {
|
|
@@ -15042,8 +15592,8 @@ var init_oauth = __esm({
|
|
|
15042
15592
|
init_web();
|
|
15043
15593
|
init_client();
|
|
15044
15594
|
OAuthError = class extends Error {
|
|
15045
|
-
constructor(
|
|
15046
|
-
super(
|
|
15595
|
+
constructor(message2) {
|
|
15596
|
+
super(message2);
|
|
15047
15597
|
this.name = "OAuthError";
|
|
15048
15598
|
}
|
|
15049
15599
|
};
|
|
@@ -15186,9 +15736,9 @@ function bridgeMcpTools(server, client, tools, opts) {
|
|
|
15186
15736
|
try {
|
|
15187
15737
|
result = await client.callTool(t.name, input ?? {}, { signal: ctx.signal });
|
|
15188
15738
|
} catch (err2) {
|
|
15189
|
-
const
|
|
15739
|
+
const message2 = err2 instanceof McpError ? err2.message : err2 instanceof Error ? err2.message : String(err2);
|
|
15190
15740
|
const failed = classifyError(
|
|
15191
|
-
new Error(`MCP ${server.name}/${t.name} failed: ${
|
|
15741
|
+
new Error(`MCP ${server.name}/${t.name} failed: ${message2}`, { cause: err2 }),
|
|
15192
15742
|
mcpClass(err2)
|
|
15193
15743
|
);
|
|
15194
15744
|
span?.fail(failed);
|
|
@@ -15395,8 +15945,8 @@ var init_service = __esm({
|
|
|
15395
15945
|
init_source();
|
|
15396
15946
|
MCP_OFF_MESSAGE = "External MCP servers are not enabled in this deployment (no `mcp` block in config.yaml).";
|
|
15397
15947
|
McpServiceError = class extends Error {
|
|
15398
|
-
constructor(code,
|
|
15399
|
-
super(
|
|
15948
|
+
constructor(code, message2) {
|
|
15949
|
+
super(message2);
|
|
15400
15950
|
this.code = code;
|
|
15401
15951
|
this.name = "McpServiceError";
|
|
15402
15952
|
}
|
|
@@ -16004,12 +16554,12 @@ var init_service = __esm({
|
|
|
16004
16554
|
const tools = await this.opts.factory(spec).listTools();
|
|
16005
16555
|
return { kind: "ok", toolCount: tools.length };
|
|
16006
16556
|
} catch (err2) {
|
|
16007
|
-
const
|
|
16008
|
-
if (/HTTP 40[13]\b/.test(
|
|
16009
|
-
return { kind: "rejected", error: `the server rejected the token (${
|
|
16557
|
+
const message2 = err2 instanceof Error ? err2.message : String(err2);
|
|
16558
|
+
if (/HTTP 40[13]\b/.test(message2))
|
|
16559
|
+
return { kind: "rejected", error: `the server rejected the token (${message2})` };
|
|
16010
16560
|
return {
|
|
16011
16561
|
kind: "error",
|
|
16012
|
-
error: `stored, but the server could not be reached to verify it: ${
|
|
16562
|
+
error: `stored, but the server could not be reached to verify it: ${message2.slice(0, 200)}`
|
|
16013
16563
|
};
|
|
16014
16564
|
}
|
|
16015
16565
|
}
|
|
@@ -17899,8 +18449,8 @@ var init_githubApi = __esm({
|
|
|
17899
18449
|
MAX_FILE_CHARS = 2e5;
|
|
17900
18450
|
COMPARE_DIFF_MAX_CHARS = 12e5;
|
|
17901
18451
|
GithubApiError = class extends Error {
|
|
17902
|
-
constructor(status3,
|
|
17903
|
-
super(
|
|
18452
|
+
constructor(status3, message2) {
|
|
18453
|
+
super(message2);
|
|
17904
18454
|
this.status = status3;
|
|
17905
18455
|
this.name = "GithubApiError";
|
|
17906
18456
|
}
|
|
@@ -18222,8 +18772,8 @@ var init_reviewAbridge = __esm({
|
|
|
18222
18772
|
init_clock();
|
|
18223
18773
|
isReadingDiff = (e) => e.type === "review_artifact" && e.artifact === "reading_diff";
|
|
18224
18774
|
AbridgeRefusal = class extends Error {
|
|
18225
|
-
constructor(code,
|
|
18226
|
-
super(
|
|
18775
|
+
constructor(code, message2) {
|
|
18776
|
+
super(message2);
|
|
18227
18777
|
this.code = code;
|
|
18228
18778
|
this.name = "AbridgeRefusal";
|
|
18229
18779
|
}
|
|
@@ -19268,7 +19818,7 @@ var init_plan2 = __esm({
|
|
|
19268
19818
|
init_config();
|
|
19269
19819
|
init_capabilities();
|
|
19270
19820
|
init_secrets2();
|
|
19271
|
-
|
|
19821
|
+
init_profile2();
|
|
19272
19822
|
ENV_PATH = ".env";
|
|
19273
19823
|
CONFIG_PATH = "config/config.yaml";
|
|
19274
19824
|
PROFILE_PATH2 = "deploy/profile.json";
|
|
@@ -19281,7 +19831,7 @@ var init_plan2 = __esm({
|
|
|
19281
19831
|
];
|
|
19282
19832
|
OPENAI_PROVIDER = "openai";
|
|
19283
19833
|
OPENAI_KEY_ENV = "OPENAI_API_KEY";
|
|
19284
|
-
DEFAULT_MODEL_AGENTS = ["general", "coding", "review"];
|
|
19834
|
+
DEFAULT_MODEL_AGENTS = ["general", "coding", "review", "explore"];
|
|
19285
19835
|
ENV_LINE = /^(#\s*)?([A-Z][A-Z0-9_]*)=(.*)$/;
|
|
19286
19836
|
}
|
|
19287
19837
|
});
|
|
@@ -19772,7 +20322,12 @@ function buildCoreCommands(config, store, wiring) {
|
|
|
19772
20322
|
const delivery = once(async () => {
|
|
19773
20323
|
if (wiring.delivery) return wiring.delivery();
|
|
19774
20324
|
if (wiring.capabilities && !wiring.capabilities.github) return new NullDeliveryService();
|
|
19775
|
-
|
|
20325
|
+
const config2 = (await cfg()).config;
|
|
20326
|
+
const warn = (m) => wiring.warn(`[delivery] ${m}`);
|
|
20327
|
+
return deliveryFromConfig(parseDeliveryConfig(config2.delivery), {
|
|
20328
|
+
snapshots: buildDeliverySnapshotStore(config2, wiring.secrets, warn),
|
|
20329
|
+
warn
|
|
20330
|
+
}).service;
|
|
19776
20331
|
});
|
|
19777
20332
|
const deps = {
|
|
19778
20333
|
help: {
|
|
@@ -19837,13 +20392,19 @@ function buildCoreCommands(config, store, wiring) {
|
|
|
19837
20392
|
};
|
|
19838
20393
|
return bindCommands(registry, deps);
|
|
19839
20394
|
}
|
|
19840
|
-
function
|
|
19841
|
-
|
|
20395
|
+
function deliveryFromConfig(cfg, opts = {}) {
|
|
20396
|
+
const source2 = new SnapshottingDeliverySource(
|
|
20397
|
+
new GithubDeliverySource(),
|
|
20398
|
+
opts.snapshots ?? new InMemoryDeliverySnapshotStore(),
|
|
20399
|
+
{ ...opts.warn ? { warn: opts.warn } : {} }
|
|
20400
|
+
);
|
|
20401
|
+
const service = createDeliveryService(cfg, source2, {
|
|
19842
20402
|
identities: async () => {
|
|
19843
20403
|
const identity2 = await resolveGithubIdentity();
|
|
19844
20404
|
return identity2 ? { reviewers: [identity2.login] } : {};
|
|
19845
20405
|
}
|
|
19846
20406
|
});
|
|
20407
|
+
return { service, source: source2 };
|
|
19847
20408
|
}
|
|
19848
20409
|
var init_commandCatalogue = __esm({
|
|
19849
20410
|
"../../src/core/commandCatalogue.ts"() {
|
|
@@ -19862,6 +20423,8 @@ var init_commandCatalogue = __esm({
|
|
|
19862
20423
|
init_githubDelivery();
|
|
19863
20424
|
init_resident();
|
|
19864
20425
|
init_delivery();
|
|
20426
|
+
init_deliverySnapshot();
|
|
20427
|
+
init_deliverySnapshotStore();
|
|
19865
20428
|
init_commandRegistry();
|
|
19866
20429
|
init_secrets2();
|
|
19867
20430
|
init_all();
|
|
@@ -22320,6 +22883,21 @@ ${raw.trim()}`;
|
|
|
22320
22883
|
* and URL reading, so a plain mention can answer from the repos and act on
|
|
22321
22884
|
* issues without being re-sent to another agent. */
|
|
22322
22885
|
assistant: [webFetchTool, updateStatusTool, ...GITHUB_READ_TOOLS, ...GITHUB_ISSUE_WRITE_TOOLS],
|
|
22886
|
+
/** The explore agent (docs/reference/specs/agent-explore.md): a shell and
|
|
22887
|
+
* file reads in a cold sandbox, the web with search, the skills and the
|
|
22888
|
+
* GitHub reads — and nothing that writes: no `write_file`, no `submit_*`,
|
|
22889
|
+
* no issue writes. Read-only is a toolset-and-prompt contract; the wall is
|
|
22890
|
+
* the read-scoped credential its machine holds. */
|
|
22891
|
+
explore: [
|
|
22892
|
+
bashTool,
|
|
22893
|
+
readFileTool,
|
|
22894
|
+
updateStatusTool,
|
|
22895
|
+
webFetchTool,
|
|
22896
|
+
webSearchTool,
|
|
22897
|
+
listSkillsTool,
|
|
22898
|
+
useSkillTool,
|
|
22899
|
+
...GITHUB_READ_TOOLS
|
|
22900
|
+
],
|
|
22323
22901
|
none: []
|
|
22324
22902
|
};
|
|
22325
22903
|
}
|
|
@@ -22524,9 +23102,9 @@ async function runLoop(opts, now, note, emit, agentSpan) {
|
|
|
22524
23102
|
);
|
|
22525
23103
|
throw err2;
|
|
22526
23104
|
}
|
|
22527
|
-
const
|
|
23105
|
+
const message2 = err2 instanceof Error ? err2.message : String(err2);
|
|
22528
23106
|
if (err2 instanceof ExecCapacityError) {
|
|
22529
|
-
const text2 = `\u23F3 Sandbox fleet busy \u2014 ${
|
|
23107
|
+
const text2 = `\u23F3 Sandbox fleet busy \u2014 ${message2}. Retry the command in a minute or finish with what you have.`;
|
|
22530
23108
|
emit({ type: "tool_result", tool: tu.name, ok: false, callId: tu.id, ...prepareToolResult(text2), ...spanId });
|
|
22531
23109
|
note("fleet_busy", text2);
|
|
22532
23110
|
settle2(false, { infra: true });
|
|
@@ -22538,7 +23116,7 @@ async function runLoop(opts, now, note, emit, agentSpan) {
|
|
|
22538
23116
|
tool: tu.name,
|
|
22539
23117
|
ok: false,
|
|
22540
23118
|
callId: tu.id,
|
|
22541
|
-
...prepareToolResult(
|
|
23119
|
+
...prepareToolResult(message2),
|
|
22542
23120
|
...infra ? { infra: true } : {},
|
|
22543
23121
|
...spanId
|
|
22544
23122
|
});
|
|
@@ -22547,7 +23125,7 @@ async function runLoop(opts, now, note, emit, agentSpan) {
|
|
|
22547
23125
|
return {
|
|
22548
23126
|
type: "tool_result",
|
|
22549
23127
|
toolUseId: tu.id,
|
|
22550
|
-
content: capToolResultContent(`Error: ${
|
|
23128
|
+
content: capToolResultContent(`Error: ${message2}`),
|
|
22551
23129
|
isError: true
|
|
22552
23130
|
};
|
|
22553
23131
|
}
|
|
@@ -22916,8 +23494,8 @@ function rereviewFollowUp(input) {
|
|
|
22916
23494
|
`Re-review at ${c}: focus on what changed since ${r} (\`git diff ${r} HEAD\` if ${r} is still present, otherwise diff against the base), re-check any finding above that the new commits address, and report the complete updated review \u2014 same format, verdict line first. Then call \`submit_verdict\` again with \`head\` = \`${input.current}\`; the earlier verdict is void.`
|
|
22917
23495
|
].join("\n");
|
|
22918
23496
|
}
|
|
22919
|
-
function subject(
|
|
22920
|
-
return
|
|
23497
|
+
function subject(message2) {
|
|
23498
|
+
return message2.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
22921
23499
|
}
|
|
22922
23500
|
function short3(sha) {
|
|
22923
23501
|
return sha.trim().toLowerCase().slice(0, 7);
|
|
@@ -23043,16 +23621,17 @@ var init_digestCoverage = __esm({
|
|
|
23043
23621
|
});
|
|
23044
23622
|
|
|
23045
23623
|
// ../../src/core/reviewRound.ts
|
|
23046
|
-
function releaseModeFor(
|
|
23047
|
-
return
|
|
23624
|
+
function releaseModeFor(identity2, opts) {
|
|
23625
|
+
return identity2 === "read" || opts.hardStopped ? "always" : "if-clean";
|
|
23048
23626
|
}
|
|
23049
23627
|
async function attachRoundWorkspace(input) {
|
|
23050
|
-
const { agent } = input.round;
|
|
23628
|
+
const { agent, profile } = input.round;
|
|
23051
23629
|
const selection = await makeExecutor(
|
|
23052
23630
|
input.factory,
|
|
23053
23631
|
{
|
|
23054
23632
|
threadKey: input.round.threadKey,
|
|
23055
23633
|
agent,
|
|
23634
|
+
profile,
|
|
23056
23635
|
repo: input.round.repo,
|
|
23057
23636
|
ref: input.round.ref,
|
|
23058
23637
|
headSha: input.round.headSha
|
|
@@ -23062,7 +23641,7 @@ async function attachRoundWorkspace(input) {
|
|
|
23062
23641
|
const release = async (opts) => {
|
|
23063
23642
|
const { executor } = selection;
|
|
23064
23643
|
if (!executor.release) return;
|
|
23065
|
-
const mode = releaseModeFor(
|
|
23644
|
+
const mode = releaseModeFor(profile.identity, opts);
|
|
23066
23645
|
try {
|
|
23067
23646
|
const r = await executor.release(mode, opts.span ? { span: opts.span } : void 0);
|
|
23068
23647
|
console.log(`[release] ${input.logKey} ${r.released ? "released" : "kept"}${r.reason ? ` (${r.reason})` : ""}`);
|
|
@@ -23776,6 +24355,9 @@ function reclaimedRunRecord(input) {
|
|
|
23776
24355
|
},
|
|
23777
24356
|
channelVisibility: row.meta.channelVisibility ?? "unknown",
|
|
23778
24357
|
repo: row.meta.repo,
|
|
24358
|
+
// The row carries the profile the run was admitted with (a clipped budget
|
|
24359
|
+
// included); a row from before profiles existed leaves the record without one.
|
|
24360
|
+
...row.meta.profile && row.meta.agent ? { profile: { preset: row.meta.agent, ...row.meta.profile } } : {},
|
|
23779
24361
|
finishedAt,
|
|
23780
24362
|
status: status3,
|
|
23781
24363
|
diagnosis: analyzeRunFriction(events, {
|
|
@@ -23834,12 +24416,16 @@ function assembleRunRecord(input) {
|
|
|
23834
24416
|
...activityOfEvents(events) !== void 0 ? { activity: activityOfEvents(events) } : {},
|
|
23835
24417
|
...msg.sourceUrl !== void 0 ? { sourceUrl: msg.sourceUrl } : {},
|
|
23836
24418
|
...msg.userName !== void 0 ? { userName: msg.userName } : {},
|
|
23837
|
-
...input.handoff !== void 0 ? { handoff: redactHandoff(input.handoff) } : {}
|
|
24419
|
+
...input.handoff !== void 0 ? { handoff: redactHandoff(input.handoff) } : {},
|
|
24420
|
+
...input.profile !== void 0 ? { profile: input.profile } : {}
|
|
23838
24421
|
});
|
|
23839
24422
|
return fitted.eventCount !== fitted.storedEventCount ? { ...fitted, truncated: true } : fitted;
|
|
23840
24423
|
}
|
|
24424
|
+
function profileRecordOf(agent, profile) {
|
|
24425
|
+
return { preset: agent.name, ...profile };
|
|
24426
|
+
}
|
|
23841
24427
|
function writeTombstone(deps, ctx) {
|
|
23842
|
-
const { msg, agent, resolved, repoCtx, channelVisibility, run: run2, registry, resume } = ctx;
|
|
24428
|
+
const { msg, agent, profile, resolved, repoCtx, channelVisibility, run: run2, registry, resume } = ctx;
|
|
23843
24429
|
if (!resume) {
|
|
23844
24430
|
const startSnap = registry.snapshot(run2.id, run2.token);
|
|
23845
24431
|
if (startSnap) {
|
|
@@ -23852,6 +24438,7 @@ function writeTombstone(deps, ctx) {
|
|
|
23852
24438
|
msg,
|
|
23853
24439
|
channelVisibility,
|
|
23854
24440
|
repo: repoCtx.repo,
|
|
24441
|
+
profile: profileRecordOf(agent, profile),
|
|
23855
24442
|
finishedAt: startSnap.startedAt,
|
|
23856
24443
|
status: "interrupted",
|
|
23857
24444
|
diagnosis: analyzeRunFriction(startSnap.events, {
|
|
@@ -23870,6 +24457,7 @@ function registerFinishRecord(deps, ctx) {
|
|
|
23870
24457
|
run: run2,
|
|
23871
24458
|
snap,
|
|
23872
24459
|
agent,
|
|
24460
|
+
profile,
|
|
23873
24461
|
resolved,
|
|
23874
24462
|
msg,
|
|
23875
24463
|
channelVisibility,
|
|
@@ -23893,6 +24481,7 @@ function registerFinishRecord(deps, ctx) {
|
|
|
23893
24481
|
msg,
|
|
23894
24482
|
channelVisibility,
|
|
23895
24483
|
repo: repoCtx.repo,
|
|
24484
|
+
profile: profileRecordOf(agent, profile),
|
|
23896
24485
|
finishedAt,
|
|
23897
24486
|
status: failedAfterFinish && status3 === "completed" ? "failed" : status3,
|
|
23898
24487
|
diagnosis,
|
|
@@ -24244,10 +24833,10 @@ ${chatCatalogueText(inGroup)}` };
|
|
|
24244
24833
|
const id = `${group}.${verb}`;
|
|
24245
24834
|
const cmd = exposed.find((c) => c.id === id);
|
|
24246
24835
|
if (!cmd) return null;
|
|
24247
|
-
const rejected = (
|
|
24836
|
+
const rejected = (message2) => ({
|
|
24248
24837
|
kind: "reply",
|
|
24249
24838
|
error: "invalid_input",
|
|
24250
|
-
text: `\u26A0\uFE0F \`${chatForm(id)}\`: ${
|
|
24839
|
+
text: `\u26A0\uFE0F \`${chatForm(id)}\`: ${message2}`
|
|
24251
24840
|
});
|
|
24252
24841
|
const tokens = tokenize(text);
|
|
24253
24842
|
if (!tokens.ok) return rejected(tokens.error);
|
|
@@ -24269,15 +24858,15 @@ function chatCallerFor(msg, config, resolveRepo) {
|
|
|
24269
24858
|
origin: { channelId: msg.channelId, threadKey: msg.threadKey, ...resolveRepo ? { repo: resolveRepo } : {} }
|
|
24270
24859
|
};
|
|
24271
24860
|
}
|
|
24272
|
-
function chatErrorLine(id, error,
|
|
24861
|
+
function chatErrorLine(id, error, message2, config, decidedBy = "registry") {
|
|
24273
24862
|
const name = chatForm(id);
|
|
24274
24863
|
switch (error) {
|
|
24275
24864
|
case "unauthorized":
|
|
24276
|
-
return decidedBy === "handler" ? `\u{1F6AB} \`${name}\`: ${
|
|
24865
|
+
return decidedBy === "handler" ? `\u{1F6AB} \`${name}\`: ${message2} Ask ${config.adminsHint()}.` : `\u{1F6AB} \`${name}\` is restricted. Ask ${config.adminsHint()}.`;
|
|
24277
24866
|
case "internal":
|
|
24278
|
-
return `\u26A0\uFE0F \`${name}\` failed: ${
|
|
24867
|
+
return `\u26A0\uFE0F \`${name}\` failed: ${message2}`;
|
|
24279
24868
|
default:
|
|
24280
|
-
return `\u26A0\uFE0F \`${name}\`: ${
|
|
24869
|
+
return `\u26A0\uFE0F \`${name}\`: ${message2}`;
|
|
24281
24870
|
}
|
|
24282
24871
|
}
|
|
24283
24872
|
async function invokeChatCommand({
|
|
@@ -25082,6 +25671,11 @@ var init_fastPath = __esm({
|
|
|
25082
25671
|
});
|
|
25083
25672
|
|
|
25084
25673
|
// ../../src/directives.ts
|
|
25674
|
+
function parseBudgetMinutes(value) {
|
|
25675
|
+
if (!/^\d+$/.test(value)) return void 0;
|
|
25676
|
+
const minutes = Number(value);
|
|
25677
|
+
return minutes >= MIN_BOUNDARY_MINUTES ? minutes : void 0;
|
|
25678
|
+
}
|
|
25085
25679
|
function lastThreadDirectives(history) {
|
|
25086
25680
|
const out = {};
|
|
25087
25681
|
for (const h of history) {
|
|
@@ -25114,6 +25708,14 @@ function parseDirectives(input) {
|
|
|
25114
25708
|
throw new Error(`Unknown effort "${f.value}". Valid: ${EFFORT_LEVELS_HINT}`);
|
|
25115
25709
|
}
|
|
25116
25710
|
out.effort = f.value;
|
|
25711
|
+
} else if (f.key === "budget") {
|
|
25712
|
+
const minutes = parseBudgetMinutes(f.value);
|
|
25713
|
+
if (minutes === void 0) {
|
|
25714
|
+
throw new Error(
|
|
25715
|
+
`Invalid budget "${f.value}": budget:<minutes> takes a whole number of minutes, at least ${MIN_BOUNDARY_MINUTES} (e.g. budget:30). It narrows this run's wall clock and never widens it.`
|
|
25716
|
+
);
|
|
25717
|
+
}
|
|
25718
|
+
out.budget = minutes;
|
|
25117
25719
|
}
|
|
25118
25720
|
text = text.replace(f.match, " ");
|
|
25119
25721
|
}
|
|
@@ -25125,8 +25727,9 @@ var init_directives = __esm({
|
|
|
25125
25727
|
"../../src/directives.ts"() {
|
|
25126
25728
|
"use strict";
|
|
25127
25729
|
init_registry();
|
|
25730
|
+
init_validate();
|
|
25128
25731
|
init_effort();
|
|
25129
|
-
DIRECTIVE_RE = /(?:^|\s)(agent|model|effort)[:=](\S+)/g;
|
|
25732
|
+
DIRECTIVE_RE = /(?:^|\s)(agent|model|effort|budget)[:=](\S+)/g;
|
|
25130
25733
|
}
|
|
25131
25734
|
});
|
|
25132
25735
|
|
|
@@ -25138,7 +25741,7 @@ function githubRepoProbe(opts) {
|
|
|
25138
25741
|
if (!SLUG.test(slug)) return false;
|
|
25139
25742
|
let bearer;
|
|
25140
25743
|
try {
|
|
25141
|
-
bearer = await token(opts.scope);
|
|
25744
|
+
bearer = opts.scope === void 0 ? null : await token(opts.scope);
|
|
25142
25745
|
} catch {
|
|
25143
25746
|
return "unreachable";
|
|
25144
25747
|
}
|
|
@@ -25189,29 +25792,44 @@ function resolveRun(deps, ctx) {
|
|
|
25189
25792
|
});
|
|
25190
25793
|
return { sticky, resolved };
|
|
25191
25794
|
}
|
|
25795
|
+
function resolveProfile(ctx) {
|
|
25796
|
+
const carried = ctx.resume?.row.meta.profile;
|
|
25797
|
+
const declared = carried ? { machine: carried.machine, identity: carried.identity, maxMinutes: carried.minutes } : ctx.agent;
|
|
25798
|
+
const resolution = effectiveProfile(
|
|
25799
|
+
declared,
|
|
25800
|
+
ctx.budget !== void 0 ? { budget: ctx.budget } : {},
|
|
25801
|
+
ctx.resolved.boundary
|
|
25802
|
+
);
|
|
25803
|
+
if (resolution.kind === "profile" && carried?.boundedBy && !resolution.profile.boundedBy) {
|
|
25804
|
+
return { kind: "profile", profile: { ...resolution.profile, boundedBy: carried.boundedBy } };
|
|
25805
|
+
}
|
|
25806
|
+
return resolution;
|
|
25807
|
+
}
|
|
25192
25808
|
function resolveTarget(deps, ctx) {
|
|
25193
|
-
const { msg, history,
|
|
25809
|
+
const { msg, history, profile, resolved, resume, root } = ctx;
|
|
25194
25810
|
const { provider: providerName, model } = parseModelRef(resolved.modelRef);
|
|
25195
25811
|
const provider = deps.providers.get(providerName);
|
|
25196
|
-
const needsRepo = machineNeedsRepo(
|
|
25812
|
+
const needsRepo = machineNeedsRepo(profile.machine);
|
|
25197
25813
|
const repoCtxP = root.span(
|
|
25198
25814
|
"dispatch.repo_context",
|
|
25199
25815
|
() => resume ? Promise.resolve(resume.repoCtx) : needsRepo ? Promise.resolve(
|
|
25200
|
-
deps.resolveRepoContext ? deps.resolveRepoContext(msg, history) : resolveRepoContext(msg, history, ...repoVetFor(
|
|
25816
|
+
deps.resolveRepoContext ? deps.resolveRepoContext(msg, history) : resolveRepoContext(msg, history, ...repoVetFor(profile, deps.config.config.execution?.resident))
|
|
25201
25817
|
).then((ctx2) => ctx2 ?? {}) : Promise.resolve({})
|
|
25202
25818
|
);
|
|
25203
25819
|
repoCtxP.catch(() => {
|
|
25204
25820
|
});
|
|
25205
25821
|
return { provider, model, needsRepo, repoCtxP };
|
|
25206
25822
|
}
|
|
25207
|
-
function repoVetFor(
|
|
25208
|
-
if (
|
|
25823
|
+
function repoVetFor(profile, resident) {
|
|
25824
|
+
if (profile.machine === "repo-cold")
|
|
25825
|
+
return [githubRepoProbe({ scope: githubTokenScopeFor(profile.identity) }), void 0];
|
|
25209
25826
|
return [residentOnboardedProbe(resident), residentSlugsLister(resident)];
|
|
25210
25827
|
}
|
|
25211
25828
|
var init_resolve = __esm({
|
|
25212
25829
|
"../../src/core/dispatch/resolve.ts"() {
|
|
25213
25830
|
"use strict";
|
|
25214
25831
|
init_registry();
|
|
25832
|
+
init_profile();
|
|
25215
25833
|
init_directives();
|
|
25216
25834
|
init_types3();
|
|
25217
25835
|
init_factory();
|
|
@@ -25234,9 +25852,63 @@ async function authorizeAgent(deps, ctx) {
|
|
|
25234
25852
|
}
|
|
25235
25853
|
return { kind: "allowed" };
|
|
25236
25854
|
}
|
|
25855
|
+
async function authorizeProfile(deps, ctx) {
|
|
25856
|
+
const { msg, io, refuse: refuse3, agent, resolution } = ctx;
|
|
25857
|
+
if (resolution.kind === "profile") return { kind: "allowed", profile: resolution.profile };
|
|
25858
|
+
const { refusal } = resolution;
|
|
25859
|
+
console.log(`[dispatch] ${msg.threadKey} not started: profile bounded (${agent.name}: ${refusalSummary(refusal)})`);
|
|
25860
|
+
await refuse3("profile_bounded", () => io.reply(profileRefusalReply(agent.name, refusal, deps.config.adminsHint())));
|
|
25861
|
+
return { kind: "refused", reason: "profile_bounded" };
|
|
25862
|
+
}
|
|
25863
|
+
function refusalSummary(refusal) {
|
|
25864
|
+
return refusal.axis === "identity" ? `identity ${refusal.needs} > ${refusal.cap} (${refusal.scope})` : `machine ${refusal.needs} not in ${refusal.allowed.join(",")} (${refusal.scopes.join(",")})`;
|
|
25865
|
+
}
|
|
25866
|
+
function boundaryOf(scope) {
|
|
25867
|
+
switch (scope) {
|
|
25868
|
+
case "channel":
|
|
25869
|
+
return "this channel's boundary";
|
|
25870
|
+
case "user":
|
|
25871
|
+
return "your own boundary";
|
|
25872
|
+
case "defaults":
|
|
25873
|
+
return "the installation's default boundary";
|
|
25874
|
+
case "directive":
|
|
25875
|
+
return "this message's own budget";
|
|
25876
|
+
}
|
|
25877
|
+
}
|
|
25878
|
+
function wayForward(scope, axis, needs, adminsHint) {
|
|
25879
|
+
switch (scope) {
|
|
25880
|
+
case "channel":
|
|
25881
|
+
return `run it in a channel that allows \`${needs}\`, or ask ${adminsHint} to raise this channel's boundary`;
|
|
25882
|
+
case "user":
|
|
25883
|
+
return `raise your own boundary with \`config set me --boundary.${axis} ${needs}\`, or drop your overrides with \`config clear me\``;
|
|
25884
|
+
case "defaults":
|
|
25885
|
+
return `ask ${adminsHint} to raise \`defaults.boundary\` in the configuration`;
|
|
25886
|
+
case "directive":
|
|
25887
|
+
return "send the message again without the budget directive";
|
|
25888
|
+
}
|
|
25889
|
+
}
|
|
25890
|
+
function profileRefusalReply(agentName, refusal, adminsHint) {
|
|
25891
|
+
const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
25892
|
+
if (refusal.axis === "identity") {
|
|
25893
|
+
const how2 = wayForward(refusal.scope, "maxIdentity", refusal.needs, adminsHint);
|
|
25894
|
+
return `\u{1F6AB} \`${agentName}\` needs a \`${refusal.needs}\` credential; ${boundaryOf(refusal.scope)} caps runs at \`${refusal.cap}\`. ${capitalize(how2)}.`;
|
|
25895
|
+
}
|
|
25896
|
+
const scopes = refusal.scopes.map(boundaryOf);
|
|
25897
|
+
const who2 = scopes.length > 1 ? `${scopes.join(" and ")} allow` : `${scopes[0] ?? "the boundary"} allows`;
|
|
25898
|
+
const allowed = refusal.allowed.map((m) => `\`${m}\``).join(", ");
|
|
25899
|
+
const how = refusal.scopes.map(
|
|
25900
|
+
(scope) => wayForward(
|
|
25901
|
+
scope,
|
|
25902
|
+
"machines",
|
|
25903
|
+
scope === "user" ? `<classes including ${refusal.needs}>` : refusal.needs,
|
|
25904
|
+
adminsHint
|
|
25905
|
+
)
|
|
25906
|
+
).join("; ");
|
|
25907
|
+
return `\u{1F6AB} \`${agentName}\` runs on a \`${refusal.needs}\` machine; ${who2} only ${allowed}. ${capitalize(how)}.`;
|
|
25908
|
+
}
|
|
25237
25909
|
async function authorizeRepo(deps, ctx) {
|
|
25238
|
-
const { msg, io, refuse: refuse3, card, shell, closeLines, clock: clock2, agent, needsRepo, repoCtx } = ctx;
|
|
25239
|
-
if (
|
|
25910
|
+
const { msg, io, refuse: refuse3, card, shell, closeLines, clock: clock2, agent, profile, needsRepo, repoCtx } = ctx;
|
|
25911
|
+
if (profile.machine === "repo-cold" && needsRepo && !repoCtx.repo) {
|
|
25240
25912
|
if (repoCtx.rejectedRepo) {
|
|
25241
25913
|
const slug = repoCtx.rejectedRepo;
|
|
25242
25914
|
console.log(`[dispatch] ${msg.threadKey} not started: repo not visible (${slug}: GitHub answered 404)`);
|
|
@@ -25647,10 +26319,24 @@ function configAwarenessBlock(i) {
|
|
|
25647
26319
|
);
|
|
25648
26320
|
}
|
|
25649
26321
|
}
|
|
26322
|
+
if (i.boundary) {
|
|
26323
|
+
lines.push(
|
|
26324
|
+
`Boundary in force: ${fmtEffectiveBoundary(i.boundary)} \u2014 a boundary caps what any run in its scope may have and never grants; a preset above a cap is refused, a budget above it clipped. Users set their own with \`config set me --boundary.maxMinutes <n> --boundary.maxIdentity <none|read|write> --boundary.machines <a,b>\` (it can only tighten the channel's and the defaults'); \`config set channel --boundary.\u2026\` caps a channel.`
|
|
26325
|
+
);
|
|
26326
|
+
}
|
|
26327
|
+
if (i.budget?.boundedBy !== void 0) {
|
|
26328
|
+
lines.push(
|
|
26329
|
+
`Budget: ${i.budget.minutes} min (clipped by the ${clipSourceLabel(i.budget.boundedBy)}; the preset asks ${i.budget.presetMinutes}).`
|
|
26330
|
+
);
|
|
26331
|
+
}
|
|
26332
|
+
if (i.budget?.directive !== void 0 && i.budget.boundedBy !== "directive") {
|
|
26333
|
+
const stands = i.budget.boundedBy === void 0 ? `the preset's ${i.budget.presetMinutes} min` : `${i.budget.minutes} min`;
|
|
26334
|
+
lines.push(`This message's \`budget:${i.budget.directive}\` narrowed nothing: the run's budget is ${stands}.`);
|
|
26335
|
+
}
|
|
25650
26336
|
const channelGate = i.canEditChannelConfig ? "per-channel" : "per-channel; restricted for this user \u2014 ask an admin";
|
|
25651
26337
|
const levels = `<${EFFORT_LEVELS.join("|")}>`;
|
|
25652
26338
|
lines.push(
|
|
25653
|
-
`Users inspect and tune settings: \`config show\`, \`config set me --agent <name> --model <provider>/<model> --effort ${levels}\` (per-user; \`--models.<agent>\` / \`--efforts.<agent>\` per agent), \`config set channel \u2026\` (${channelGate}), \`config instructions me "<free text>"\` (custom instructions
|
|
26339
|
+
`Users inspect and tune settings: \`config show\`, \`config set me --agent <name> --model <provider>/<model> --effort ${levels}\` (per-user; \`--models.<agent>\` / \`--efforts.<agent>\` per agent), \`config set channel \u2026\` (${channelGate}), \`config instructions me|channel "<free text>"\` (custom instructions), \`config clear me|channel\`, and per-message \`agent:<name>\` / \`model:<provider>/<model>\` / \`effort:<level>\` / \`budget:<minutes>\` directives.`,
|
|
25654
26340
|
"When asked about your settings or tuning, answer from this block \u2014 you are not stateless or untunable."
|
|
25655
26341
|
);
|
|
25656
26342
|
return lines.join("\n");
|
|
@@ -25675,12 +26361,15 @@ function fmtDirective(d) {
|
|
|
25675
26361
|
if (d.agent) parts.push(`agent:${d.agent}`);
|
|
25676
26362
|
if (d.model) parts.push(`model:${d.model}`);
|
|
25677
26363
|
if (d.effort) parts.push(`effort:${d.effort}`);
|
|
26364
|
+
if (d.budget !== void 0) parts.push(`budget:${d.budget}`);
|
|
25678
26365
|
return parts.length > 0 ? parts.join(" ") : void 0;
|
|
25679
26366
|
}
|
|
25680
26367
|
var CONFIG_AWARENESS_HEADER;
|
|
25681
26368
|
var init_configAwareness = __esm({
|
|
25682
26369
|
"../../src/core/configAwareness.ts"() {
|
|
25683
26370
|
"use strict";
|
|
26371
|
+
init_config();
|
|
26372
|
+
init_profile();
|
|
25684
26373
|
init_effort();
|
|
25685
26374
|
CONFIG_AWARENESS_HEADER = "Switchboard runtime config for this run:";
|
|
25686
26375
|
}
|
|
@@ -25891,6 +26580,15 @@ async function openAckCard(deps, ctx) {
|
|
|
25891
26580
|
const heartbeat = setInterval(() => card.update(shell.live()), 5e3);
|
|
25892
26581
|
return { shell, card, heartbeat };
|
|
25893
26582
|
}
|
|
26583
|
+
function budgetClipLabel(agent, profile, budgetDirective) {
|
|
26584
|
+
const idle = budgetDirective !== void 0 && profile.boundedBy !== "directive";
|
|
26585
|
+
if (profile.boundedBy === void 0) {
|
|
26586
|
+
return idle ? `budget:${budgetDirective} narrowed nothing (preset asks ${agent.maxMinutes})` : void 0;
|
|
26587
|
+
}
|
|
26588
|
+
const facts = [`${clipSourceLabel(profile.boundedBy)}; preset asks ${agent.maxMinutes}`];
|
|
26589
|
+
if (idle) facts.push(`budget:${budgetDirective} narrowed nothing`);
|
|
26590
|
+
return `budget ${profile.minutes} min (${facts.join("; ")})`;
|
|
26591
|
+
}
|
|
25894
26592
|
async function registerRun(deps, ctx) {
|
|
25895
26593
|
const {
|
|
25896
26594
|
msg,
|
|
@@ -25993,6 +26691,7 @@ async function reserveRun(deps, ctx) {
|
|
|
25993
26691
|
const {
|
|
25994
26692
|
msg,
|
|
25995
26693
|
agent,
|
|
26694
|
+
profile,
|
|
25996
26695
|
resolved,
|
|
25997
26696
|
repoCtx,
|
|
25998
26697
|
channelVisibility,
|
|
@@ -26028,7 +26727,8 @@ async function reserveRun(deps, ctx) {
|
|
|
26028
26727
|
...repoCtx.ref !== void 0 ? { ref: repoCtx.ref } : {},
|
|
26029
26728
|
...repoCtx.headSha !== void 0 ? { headSha: repoCtx.headSha } : {},
|
|
26030
26729
|
...repoCtx.pr !== void 0 ? { pr: repoCtx.pr } : {},
|
|
26031
|
-
readonly:
|
|
26730
|
+
readonly: profile.identity === "read",
|
|
26731
|
+
profile,
|
|
26032
26732
|
request: requestRow
|
|
26033
26733
|
},
|
|
26034
26734
|
card: card.handle ?? null,
|
|
@@ -26041,7 +26741,7 @@ async function reserveRun(deps, ctx) {
|
|
|
26041
26741
|
return void 0;
|
|
26042
26742
|
}
|
|
26043
26743
|
async function attachWorkspace(deps, ctx) {
|
|
26044
|
-
const { msg, io, refuse: refuse3, card, shell, closeLines, clock: clock2, agent, repoCtx, root } = ctx;
|
|
26744
|
+
const { msg, io, refuse: refuse3, card, shell, closeLines, clock: clock2, agent, profile, repoCtx, root } = ctx;
|
|
26045
26745
|
let round;
|
|
26046
26746
|
try {
|
|
26047
26747
|
round = await root.span("dispatch.workspace.attach", async (span) => {
|
|
@@ -26060,7 +26760,14 @@ async function attachWorkspace(deps, ctx) {
|
|
|
26060
26760
|
workspaceDir: deps.config.config.workspaceDir ?? "./workspaces",
|
|
26061
26761
|
dataDir: deps.dataDir ?? "./data"
|
|
26062
26762
|
},
|
|
26063
|
-
round: {
|
|
26763
|
+
round: {
|
|
26764
|
+
threadKey: msg.threadKey,
|
|
26765
|
+
agent,
|
|
26766
|
+
profile,
|
|
26767
|
+
repo: repoCtx.repo,
|
|
26768
|
+
ref: repoCtx.ref,
|
|
26769
|
+
headSha: repoCtx.headSha
|
|
26770
|
+
},
|
|
26064
26771
|
logKey: msg.threadKey,
|
|
26065
26772
|
span
|
|
26066
26773
|
});
|
|
@@ -26094,6 +26801,7 @@ async function composePrompt(deps, ctx) {
|
|
|
26094
26801
|
const {
|
|
26095
26802
|
msg,
|
|
26096
26803
|
agent,
|
|
26804
|
+
profile,
|
|
26097
26805
|
resolved,
|
|
26098
26806
|
directives,
|
|
26099
26807
|
sticky,
|
|
@@ -26119,9 +26827,23 @@ async function composePrompt(deps, ctx) {
|
|
|
26119
26827
|
effort: resolved.effort,
|
|
26120
26828
|
channel: scopes.channel,
|
|
26121
26829
|
user: scopes.user,
|
|
26122
|
-
messageDirective: {
|
|
26830
|
+
messageDirective: {
|
|
26831
|
+
agent: directives.agent,
|
|
26832
|
+
model: directives.model,
|
|
26833
|
+
effort: directives.effort,
|
|
26834
|
+
budget: directives.budget
|
|
26835
|
+
},
|
|
26123
26836
|
threadDirective: { agent: sticky.agent, model: sticky.model, effort: sticky.effort },
|
|
26124
26837
|
canEditChannelConfig: deps.config.canEditChannelConfig(msg.userId),
|
|
26838
|
+
// The boundary in force and the budget this run actually has — the same
|
|
26839
|
+
// values the gate judged, so "how long do you have?" is answered from fact.
|
|
26840
|
+
...resolved.boundary ? { boundary: resolved.boundary } : {},
|
|
26841
|
+
budget: {
|
|
26842
|
+
minutes: profile.minutes,
|
|
26843
|
+
presetMinutes: agent.maxMinutes,
|
|
26844
|
+
...profile.boundedBy !== void 0 ? { boundedBy: profile.boundedBy } : {},
|
|
26845
|
+
...directives.budget !== void 0 ? { directive: directives.budget } : {}
|
|
26846
|
+
},
|
|
26125
26847
|
mcp: {
|
|
26126
26848
|
registryOn: deps.capabilities.mcp,
|
|
26127
26849
|
served: mcpForRun.servers.filter((s) => s.toolCount !== void 0).map((s) => s.server),
|
|
@@ -26167,6 +26889,7 @@ var init_provision = __esm({
|
|
|
26167
26889
|
"../../src/core/dispatch/provision.ts"() {
|
|
26168
26890
|
"use strict";
|
|
26169
26891
|
init_registry();
|
|
26892
|
+
init_profile();
|
|
26170
26893
|
init_residentTrace();
|
|
26171
26894
|
init_resident();
|
|
26172
26895
|
init_memory();
|
|
@@ -26198,6 +26921,7 @@ async function claimRun(deps, ctx) {
|
|
|
26198
26921
|
channelVisibility,
|
|
26199
26922
|
run: run2,
|
|
26200
26923
|
registry,
|
|
26924
|
+
profile,
|
|
26201
26925
|
selection,
|
|
26202
26926
|
requestRow,
|
|
26203
26927
|
reserved,
|
|
@@ -26233,7 +26957,8 @@ async function claimRun(deps, ctx) {
|
|
|
26233
26957
|
...repoCtx.ref !== void 0 ? { ref: repoCtx.ref } : {},
|
|
26234
26958
|
...repoCtx.headSha !== void 0 ? { headSha: repoCtx.headSha } : {},
|
|
26235
26959
|
...repoCtx.pr !== void 0 ? { pr: repoCtx.pr } : {},
|
|
26236
|
-
readonly:
|
|
26960
|
+
readonly: profile.identity === "read",
|
|
26961
|
+
profile,
|
|
26237
26962
|
selection: resident === true ? "resident" : "sandbox",
|
|
26238
26963
|
...binding?.workspace !== void 0 ? { workspace: binding.workspace } : {},
|
|
26239
26964
|
...requestRow !== void 0 ? { request: requestRow } : {}
|
|
@@ -26246,7 +26971,9 @@ async function claimRun(deps, ctx) {
|
|
|
26246
26971
|
tools: mergeTools(TOOLSETS[agent.toolset] ?? [], mcpForRun?.tools).map(
|
|
26247
26972
|
({ name, description, inputSchema }) => ({ name, description, inputSchema })
|
|
26248
26973
|
),
|
|
26249
|
-
seed
|
|
26974
|
+
// The seed carries the EFFECTIVE budget, so a resume runs on what
|
|
26975
|
+
// this run was admitted with, not on the preset's own number.
|
|
26976
|
+
seed: { messages, budgetMs: profile.minutes * 6e4 },
|
|
26250
26977
|
// A stop asked of another container (`/runs/stop` there) reaches this
|
|
26251
26978
|
// run through its heartbeat and is honored like a local one; a fence
|
|
26252
26979
|
// (another generation took the run) is a hard stop — nothing more may
|
|
@@ -26738,7 +27465,7 @@ async function runLoop2(deps, ctx) {
|
|
|
26738
27465
|
const {
|
|
26739
27466
|
msg,
|
|
26740
27467
|
io,
|
|
26741
|
-
|
|
27468
|
+
profile,
|
|
26742
27469
|
resolved,
|
|
26743
27470
|
provider,
|
|
26744
27471
|
model,
|
|
@@ -26765,6 +27492,7 @@ async function runLoop2(deps, ctx) {
|
|
|
26765
27492
|
publishText,
|
|
26766
27493
|
ending
|
|
26767
27494
|
} = ctx;
|
|
27495
|
+
const agent = budgetedAgent(ctx.agent, profile);
|
|
26768
27496
|
const { executor, binding } = round.selection;
|
|
26769
27497
|
let reviewHead = ctx.reviewHead;
|
|
26770
27498
|
let lastActivityAt = ctx.loopStartedAt;
|
|
@@ -27092,6 +27820,7 @@ async function runLoop2(deps, ctx) {
|
|
|
27092
27820
|
run: run2,
|
|
27093
27821
|
snap,
|
|
27094
27822
|
agent,
|
|
27823
|
+
profile,
|
|
27095
27824
|
resolved,
|
|
27096
27825
|
msg,
|
|
27097
27826
|
channelVisibility,
|
|
@@ -27128,6 +27857,7 @@ async function runLoop2(deps, ctx) {
|
|
|
27128
27857
|
var init_runLoop = __esm({
|
|
27129
27858
|
"../../src/core/dispatch/runLoop.ts"() {
|
|
27130
27859
|
"use strict";
|
|
27860
|
+
init_profile();
|
|
27131
27861
|
init_runner();
|
|
27132
27862
|
init_githubPulls();
|
|
27133
27863
|
init_repoContext();
|
|
@@ -27183,6 +27913,7 @@ async function runShipCodingChild(input, ctx, opts, roundSpan) {
|
|
|
27183
27913
|
round: {
|
|
27184
27914
|
threadKey: input.threadKey,
|
|
27185
27915
|
agent: spec.agent,
|
|
27916
|
+
profile: declaredProfile(spec.agent),
|
|
27186
27917
|
repo: entry.repo,
|
|
27187
27918
|
ref: entry.branch,
|
|
27188
27919
|
headSha: opts.attachHeadSha
|
|
@@ -27371,6 +28102,7 @@ var init_codingChild = __esm({
|
|
|
27371
28102
|
"../../src/core/ship/codingChild.ts"() {
|
|
27372
28103
|
"use strict";
|
|
27373
28104
|
init_runner();
|
|
28105
|
+
init_profile();
|
|
27374
28106
|
init_descriptionTurn();
|
|
27375
28107
|
init_reviewVerdict();
|
|
27376
28108
|
init_codingPrPostStep();
|
|
@@ -27412,7 +28144,14 @@ async function runShipReviewChild(input, ctx, round, roundSpan) {
|
|
|
27412
28144
|
if (!pf.ok) return { refusal: pf.reply };
|
|
27413
28145
|
const ws = await attachRoundWorkspace({
|
|
27414
28146
|
factory: input.factory,
|
|
27415
|
-
round: {
|
|
28147
|
+
round: {
|
|
28148
|
+
threadKey: input.threadKey,
|
|
28149
|
+
agent: spec.agent,
|
|
28150
|
+
profile: declaredProfile(spec.agent),
|
|
28151
|
+
repo: entry.repo,
|
|
28152
|
+
ref: entry.branch,
|
|
28153
|
+
headSha: pinned
|
|
28154
|
+
},
|
|
27416
28155
|
logKey
|
|
27417
28156
|
});
|
|
27418
28157
|
const { executor, resident, binding, note } = ws.selection;
|
|
@@ -27546,6 +28285,7 @@ var init_reviewChild = __esm({
|
|
|
27546
28285
|
"../../src/core/ship/reviewChild.ts"() {
|
|
27547
28286
|
"use strict";
|
|
27548
28287
|
init_runner();
|
|
28288
|
+
init_profile();
|
|
27549
28289
|
init_reviewVerdict();
|
|
27550
28290
|
init_reviewedHead();
|
|
27551
28291
|
init_reviewRound();
|
|
@@ -27560,6 +28300,9 @@ function resolveShipCaps(cfg) {
|
|
|
27560
28300
|
maxMinutes: cfg?.maxMinutes ?? SHIP_DEFAULT_MAX_MINUTES
|
|
27561
28301
|
};
|
|
27562
28302
|
}
|
|
28303
|
+
function shipPresetFor(cfg) {
|
|
28304
|
+
return { ...AGENTS.ship, maxMinutes: resolveShipCaps(cfg).maxMinutes };
|
|
28305
|
+
}
|
|
27563
28306
|
function shipInterruptedNote(prUrl) {
|
|
27564
28307
|
const stands = prUrl ? `Its work stands on GitHub: ${prUrl}.` : "Whatever it pushed stands on its pipeline branch; no PR was opened yet.";
|
|
27565
28308
|
const reissue = prUrl ? `To continue the review loop, re-issue \`agent:ship\` in this thread with only the PR URL (${prUrl}).` : "To continue, re-issue `agent:ship` in this thread with the task \u2014 round 0 runs again on the same branch.";
|
|
@@ -27881,12 +28624,13 @@ var SHIP_DEFAULT_MAX_ROUNDS, SHIP_DEFAULT_MAX_MINUTES, SHIP_ROUND_RESERVE_MS;
|
|
|
27881
28624
|
var init_shipPipeline = __esm({
|
|
27882
28625
|
"../../src/core/shipPipeline.ts"() {
|
|
27883
28626
|
"use strict";
|
|
28627
|
+
init_registry();
|
|
27884
28628
|
init_reviewVerdict();
|
|
27885
28629
|
init_reviewedHead();
|
|
27886
28630
|
init_codingChild();
|
|
27887
28631
|
init_reviewChild();
|
|
27888
28632
|
SHIP_DEFAULT_MAX_ROUNDS = 3;
|
|
27889
|
-
SHIP_DEFAULT_MAX_MINUTES =
|
|
28633
|
+
SHIP_DEFAULT_MAX_MINUTES = AGENTS.ship.maxMinutes;
|
|
27890
28634
|
SHIP_ROUND_RESERVE_MS = 3 * 6e4;
|
|
27891
28635
|
}
|
|
27892
28636
|
});
|
|
@@ -28044,7 +28788,7 @@ var init_preflight = __esm({
|
|
|
28044
28788
|
|
|
28045
28789
|
// ../../src/core/dispatch/ship.ts
|
|
28046
28790
|
async function runShipBranch(deps, msg, io, ctx) {
|
|
28047
|
-
const { agent, card, directives, history, repoCtx, label, ending, trace, closeLines, refuse: refuse3, doneLines } = ctx;
|
|
28791
|
+
const { agent, profile, card, directives, history, repoCtx, label, ending, trace, closeLines, refuse: refuse3, doneLines } = ctx;
|
|
28048
28792
|
const root = trace.root;
|
|
28049
28793
|
const clock2 = deps.clock ?? systemClock;
|
|
28050
28794
|
const shell = createCardShell({ label, startedAt: ctx.startedAt, now: clock2 });
|
|
@@ -28146,7 +28890,8 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
28146
28890
|
diagnosis: analyzeRunFriction(startSnap.events, {
|
|
28147
28891
|
finished: false,
|
|
28148
28892
|
truncated: startSnap.truncated
|
|
28149
|
-
})
|
|
28893
|
+
}),
|
|
28894
|
+
profile: profileRecordOf(agent, profile)
|
|
28150
28895
|
}),
|
|
28151
28896
|
{ provisional: true }
|
|
28152
28897
|
);
|
|
@@ -28167,7 +28912,8 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
28167
28912
|
...repoCtx.repo !== void 0 ? { repo: repoCtx.repo } : {},
|
|
28168
28913
|
...msg.sourceUrl !== void 0 ? { sourceUrl: msg.sourceUrl } : {},
|
|
28169
28914
|
...msg.userName !== void 0 ? { userName: msg.userName } : {},
|
|
28170
|
-
...entry.resume !== void 0 ? { pr: entry.resume.pr } : {}
|
|
28915
|
+
...entry.resume !== void 0 ? { pr: entry.resume.pr } : {},
|
|
28916
|
+
profile
|
|
28171
28917
|
},
|
|
28172
28918
|
card: card.handle ?? null,
|
|
28173
28919
|
system: "",
|
|
@@ -28242,7 +28988,12 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
28242
28988
|
effort: spec.effort,
|
|
28243
28989
|
channel: scopes.channel,
|
|
28244
28990
|
user: scopes.user,
|
|
28245
|
-
messageDirective: {
|
|
28991
|
+
messageDirective: {
|
|
28992
|
+
agent: directives.agent,
|
|
28993
|
+
model: directives.model,
|
|
28994
|
+
effort: directives.effort,
|
|
28995
|
+
budget: directives.budget
|
|
28996
|
+
},
|
|
28246
28997
|
threadDirective: { agent: ctx.sticky.agent, model: ctx.sticky.model, effort: ctx.sticky.effort },
|
|
28247
28998
|
canEditChannelConfig: deps.config.canEditChannelConfig(msg.userId)
|
|
28248
28999
|
// No `mcp` here: ship rounds receive no MCP tools yet (docs/reference/specs/mcp-tools.md
|
|
@@ -28281,7 +29032,11 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
28281
29032
|
dataDir: deps.dataDir ?? "./data"
|
|
28282
29033
|
},
|
|
28283
29034
|
threadKey: msg.threadKey,
|
|
28284
|
-
|
|
29035
|
+
// The rounds cap is the config block's; the wall clock is the parent's
|
|
29036
|
+
// effective budget — the preset's declared `ship.maxMinutes` as a
|
|
29037
|
+
// boundary or a `budget:` directive clipped it (agent-ship.md item 8) —
|
|
29038
|
+
// so every child round is clipped to what remains of THAT.
|
|
29039
|
+
caps: { ...resolveShipCaps(deps.config.config.ship), maxMinutes: profile.minutes },
|
|
28285
29040
|
control: run2.control,
|
|
28286
29041
|
inbox: ctx.live.inbox,
|
|
28287
29042
|
// thread follow-ups steered into this run reach the child round in flight (thread-admission item 2)
|
|
@@ -28347,7 +29102,8 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
28347
29102
|
seal,
|
|
28348
29103
|
// The last coding round's handoff (agent-ship.md item 14) — the
|
|
28349
29104
|
// pipeline's, so the ship record carries what its child handed back.
|
|
28350
|
-
...outcome?.handoff !== void 0 ? { handoff: outcome.handoff } : {}
|
|
29105
|
+
...outcome?.handoff !== void 0 ? { handoff: outcome.handoff } : {},
|
|
29106
|
+
profile: profileRecordOf(agent, profile)
|
|
28351
29107
|
}),
|
|
28352
29108
|
{ span: root, ...ledgerRun ? { via: ledgerRun.sink } : {} }
|
|
28353
29109
|
)
|
|
@@ -28601,7 +29357,16 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28601
29357
|
if (await answerOperation(deps, { msg, io, ending, trace, directives, history })) return;
|
|
28602
29358
|
const { sticky, resolved } = resolveRun(deps, { msg, directives, history });
|
|
28603
29359
|
if ((await authorizeAgent(deps, { msg, io, refuse: refuse3, agentName: resolved.agentName })).kind === "refused") return;
|
|
28604
|
-
const agent = getAgent(resolved.agentName);
|
|
29360
|
+
const agent = resolved.agentName === "ship" ? shipPresetFor(deps.config.config.ship) : getAgent(resolved.agentName);
|
|
29361
|
+
const profileGate = await authorizeProfile(deps, {
|
|
29362
|
+
msg,
|
|
29363
|
+
io,
|
|
29364
|
+
refuse: refuse3,
|
|
29365
|
+
agent,
|
|
29366
|
+
resolution: resolveProfile({ agent, resolved, resume, budget: directives.budget })
|
|
29367
|
+
});
|
|
29368
|
+
if (profileGate.kind === "refused") return;
|
|
29369
|
+
const { profile } = profileGate;
|
|
28605
29370
|
const carriedRow = resume?.row ?? restart?.row;
|
|
28606
29371
|
const admissionCtx = {
|
|
28607
29372
|
msg,
|
|
@@ -28636,6 +29401,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28636
29401
|
msg,
|
|
28637
29402
|
history,
|
|
28638
29403
|
agent,
|
|
29404
|
+
profile,
|
|
28639
29405
|
resolved,
|
|
28640
29406
|
resume,
|
|
28641
29407
|
root
|
|
@@ -28657,15 +29423,19 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28657
29423
|
closeLines,
|
|
28658
29424
|
clock: clock2,
|
|
28659
29425
|
agent,
|
|
29426
|
+
profile,
|
|
28660
29427
|
needsRepo,
|
|
28661
29428
|
repoCtx
|
|
28662
29429
|
});
|
|
28663
29430
|
if (repoGate.kind === "refused") return;
|
|
29431
|
+
const clip3 = budgetClipLabel(agent, profile, directives.budget);
|
|
29432
|
+
if (clip3) shell.setLabel(`${shell.label} \xB7 ${clip3}`);
|
|
28664
29433
|
if (agent.name === "ship") {
|
|
28665
29434
|
setupCard = void 0;
|
|
28666
29435
|
clearInterval(setupHeartbeat);
|
|
28667
29436
|
await runShipBranch(deps, msg, io, {
|
|
28668
29437
|
agent,
|
|
29438
|
+
profile,
|
|
28669
29439
|
modelRef: resolved.modelRef,
|
|
28670
29440
|
label: shell.label,
|
|
28671
29441
|
startedAt,
|
|
@@ -28722,6 +29492,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28722
29492
|
const reservation = await reserveRun(deps, {
|
|
28723
29493
|
msg,
|
|
28724
29494
|
agent,
|
|
29495
|
+
profile,
|
|
28725
29496
|
resolved,
|
|
28726
29497
|
repoCtx,
|
|
28727
29498
|
channelVisibility,
|
|
@@ -28748,6 +29519,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28748
29519
|
closeLines,
|
|
28749
29520
|
clock: clock2,
|
|
28750
29521
|
agent,
|
|
29522
|
+
profile,
|
|
28751
29523
|
repoCtx,
|
|
28752
29524
|
root
|
|
28753
29525
|
});
|
|
@@ -28785,6 +29557,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28785
29557
|
const prompt = await composePrompt(deps, {
|
|
28786
29558
|
msg,
|
|
28787
29559
|
agent,
|
|
29560
|
+
profile,
|
|
28788
29561
|
resolved,
|
|
28789
29562
|
directives,
|
|
28790
29563
|
sticky,
|
|
@@ -28812,10 +29585,11 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28812
29585
|
`[resume] ${msg.threadKey} run ${run2.id} continues under ${deps.runLedger.gen}: from step ${resume.plan.step}, ${resume.plan.settlements.length} call(s) to settle, ${resume.events.length} event(s) replayed`
|
|
28813
29586
|
);
|
|
28814
29587
|
}
|
|
28815
|
-
writeTombstone(deps, { msg, agent, resolved, repoCtx, channelVisibility, run: run2, registry, resume });
|
|
29588
|
+
writeTombstone(deps, { msg, agent, profile, resolved, repoCtx, channelVisibility, run: run2, registry, resume });
|
|
28816
29589
|
ledgerRun = await claimRun(deps, {
|
|
28817
29590
|
msg,
|
|
28818
29591
|
agent,
|
|
29592
|
+
profile,
|
|
28819
29593
|
resolved,
|
|
28820
29594
|
repoCtx,
|
|
28821
29595
|
channelVisibility,
|
|
@@ -28837,6 +29611,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
28837
29611
|
msg,
|
|
28838
29612
|
io,
|
|
28839
29613
|
agent,
|
|
29614
|
+
profile,
|
|
28840
29615
|
resolved,
|
|
28841
29616
|
provider,
|
|
28842
29617
|
model,
|
|
@@ -29000,6 +29775,7 @@ var init_dispatcher = __esm({
|
|
|
29000
29775
|
init_reply();
|
|
29001
29776
|
init_record();
|
|
29002
29777
|
init_ship();
|
|
29778
|
+
init_shipPipeline();
|
|
29003
29779
|
init_settle();
|
|
29004
29780
|
init_runRegistry();
|
|
29005
29781
|
init_runEnding();
|
|
@@ -29007,22 +29783,6 @@ var init_dispatcher = __esm({
|
|
|
29007
29783
|
}
|
|
29008
29784
|
});
|
|
29009
29785
|
|
|
29010
|
-
// ../../src/core/workerError.ts
|
|
29011
|
-
async function errorSuffix(res) {
|
|
29012
|
-
const text = await res.text().catch(() => "");
|
|
29013
|
-
try {
|
|
29014
|
-
const parsed = JSON.parse(text);
|
|
29015
|
-
return parsed?.error ? `: ${String(parsed.error)}` : "";
|
|
29016
|
-
} catch {
|
|
29017
|
-
return "";
|
|
29018
|
-
}
|
|
29019
|
-
}
|
|
29020
|
-
var init_workerError = __esm({
|
|
29021
|
-
"../../src/core/workerError.ts"() {
|
|
29022
|
-
"use strict";
|
|
29023
|
-
}
|
|
29024
|
-
});
|
|
29025
|
-
|
|
29026
29786
|
// ../../src/core/runStoreWorker.ts
|
|
29027
29787
|
function describeError2(err2, depth = 0) {
|
|
29028
29788
|
if (!(err2 instanceof Error)) return String(err2);
|
|
@@ -29137,10 +29897,10 @@ var init_runStoreWorker = __esm({
|
|
|
29137
29897
|
throw new TransientStoreError(`run store ${path}: ${describeError2(err2)}`);
|
|
29138
29898
|
}
|
|
29139
29899
|
if (!res.ok) {
|
|
29140
|
-
const
|
|
29141
|
-
if (res.status === 404) throw new RouteMissingError(
|
|
29142
|
-
if (res.status >= 500 || res.status === 408 || res.status === 429) throw new TransientStoreError(
|
|
29143
|
-
throw new PermanentStoreError(
|
|
29900
|
+
const message2 = `run store ${path} HTTP ${res.status}${await errorSuffix(res)}`;
|
|
29901
|
+
if (res.status === 404) throw new RouteMissingError(message2);
|
|
29902
|
+
if (res.status >= 500 || res.status === 408 || res.status === 429) throw new TransientStoreError(message2);
|
|
29903
|
+
throw new PermanentStoreError(message2);
|
|
29144
29904
|
}
|
|
29145
29905
|
const data = await res.json().catch(() => null);
|
|
29146
29906
|
if (typeof data !== "object" || data === null)
|
|
@@ -29710,7 +30470,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
29710
30470
|
* no record at all was killed before its conversation was stored and
|
|
29711
30471
|
* closes `interrupted`. */
|
|
29712
30472
|
async seed(messages, budgetMs) {
|
|
29713
|
-
const turns = messages.map((
|
|
30473
|
+
const turns = messages.map((message2, idx) => ({ idx, message: message2 }));
|
|
29714
30474
|
try {
|
|
29715
30475
|
const seeded = await ledger.seed(this.runId, gen, turns);
|
|
29716
30476
|
if (!seeded.ok) {
|
|
@@ -29740,7 +30500,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
29740
30500
|
}
|
|
29741
30501
|
async step(report2) {
|
|
29742
30502
|
if (this.detached) return;
|
|
29743
|
-
const turns = report2.turns.map((
|
|
30503
|
+
const turns = report2.turns.map((message2, i) => ({ idx: report2.firstIdx + i, message: message2 }));
|
|
29744
30504
|
const record = {
|
|
29745
30505
|
step: ++this.stepNo,
|
|
29746
30506
|
seq: this.lastSeq,
|
|
@@ -29905,9 +30665,9 @@ function createLedgerWriteThrough(opts) {
|
|
|
29905
30665
|
return run2;
|
|
29906
30666
|
},
|
|
29907
30667
|
liveRuns: () => [...live],
|
|
29908
|
-
async pushInbox(runId3,
|
|
30668
|
+
async pushInbox(runId3, message2) {
|
|
29909
30669
|
try {
|
|
29910
|
-
const result = await ledger.pushInbox(runId3,
|
|
30670
|
+
const result = await ledger.pushInbox(runId3, message2);
|
|
29911
30671
|
if (result.ok && result.seq !== void 0) return result.seq;
|
|
29912
30672
|
warn(`[ledger] inbox push refused for run ${runId3}: no live row \u2014 the follow-up rides in memory only`);
|
|
29913
30673
|
return void 0;
|
|
@@ -31448,8 +32208,8 @@ function createSlackApp(deps) {
|
|
|
31448
32208
|
}
|
|
31449
32209
|
);
|
|
31450
32210
|
});
|
|
31451
|
-
app.message(async ({ message, client }) => {
|
|
31452
|
-
const m =
|
|
32211
|
+
app.message(async ({ message: message2, client }) => {
|
|
32212
|
+
const m = message2;
|
|
31453
32213
|
if (classifyMessage(m) === "skip") return;
|
|
31454
32214
|
botUserId ??= (await client.auth.test()).user_id ?? void 0;
|
|
31455
32215
|
const decision = classifyMessage(m, botUserId);
|
|
@@ -32138,8 +32898,8 @@ function toIncomingMessage2(identity2, args) {
|
|
|
32138
32898
|
function ok(id, result) {
|
|
32139
32899
|
return { jsonrpc: "2.0", id, result };
|
|
32140
32900
|
}
|
|
32141
|
-
function err(id, code,
|
|
32142
|
-
return { jsonrpc: "2.0", id, error: data ? { code, message, data } : { code, message } };
|
|
32901
|
+
function err(id, code, message2, data) {
|
|
32902
|
+
return { jsonrpc: "2.0", id, error: data ? { code, message: message2, data } : { code, message: message2 } };
|
|
32143
32903
|
}
|
|
32144
32904
|
function readId(msg) {
|
|
32145
32905
|
const id = msg.id;
|
|
@@ -33095,7 +33855,7 @@ function loadWebAssets(distDir) {
|
|
|
33095
33855
|
const full = join13(assetsDir, name);
|
|
33096
33856
|
if (statSync3(full).isFile()) files.set(`/assets/${name}`, readFileSync16(full));
|
|
33097
33857
|
}
|
|
33098
|
-
const
|
|
33858
|
+
const serve2 = (req, res) => {
|
|
33099
33859
|
const path = (req.url ?? "/").split("?")[0];
|
|
33100
33860
|
if (!path.startsWith("/assets/")) return false;
|
|
33101
33861
|
const method = (req.method ?? "GET").toUpperCase();
|
|
@@ -33119,7 +33879,7 @@ function loadWebAssets(distDir) {
|
|
|
33119
33879
|
else res.end(body);
|
|
33120
33880
|
return true;
|
|
33121
33881
|
};
|
|
33122
|
-
return { entry, serve };
|
|
33882
|
+
return { entry, serve: serve2 };
|
|
33123
33883
|
}
|
|
33124
33884
|
var CONTENT_TYPES, WEB_DIST_DIR;
|
|
33125
33885
|
var init_webAssets = __esm({
|
|
@@ -33323,6 +34083,7 @@ function createDeliveryViewHandler(deps, shell) {
|
|
|
33323
34083
|
}
|
|
33324
34084
|
const weeksParam = url.searchParams.get("weeks");
|
|
33325
34085
|
const sinceParam = url.searchParams.get("since");
|
|
34086
|
+
const fresh = url.searchParams.get("fresh") === "1";
|
|
33326
34087
|
const runs = async (range) => {
|
|
33327
34088
|
if (!deps.runs) return [];
|
|
33328
34089
|
const page2 = await deps.runs.listRuns({
|
|
@@ -33336,6 +34097,7 @@ function createDeliveryViewHandler(deps, shell) {
|
|
|
33336
34097
|
deps.service.report(repo, {
|
|
33337
34098
|
...weeksParam !== null ? { weeks: Number(weeksParam) } : {},
|
|
33338
34099
|
...sinceParam !== null ? { since: sinceParam } : {},
|
|
34100
|
+
...fresh ? { fresh } : {},
|
|
33339
34101
|
runs
|
|
33340
34102
|
}).then((report2) => {
|
|
33341
34103
|
if (route2.kind === "json") {
|
|
@@ -33719,14 +34481,14 @@ function createMcpConnectViewHandler(deps) {
|
|
|
33719
34481
|
async function complete(svc, nonce, identity2, token, res) {
|
|
33720
34482
|
const { decision, verified, toolCount, warning, server } = await svc.completeTicket(nonce, identity2, token);
|
|
33721
34483
|
if (!decision.ok) {
|
|
33722
|
-
const
|
|
34484
|
+
const message2 = refusalMessage(decision.refusal);
|
|
33723
34485
|
if (decision.refusal.kind === "bad_token" && server)
|
|
33724
|
-
return page(res, 400, "Token not accepted", `<p class="err">${esc(
|
|
34486
|
+
return page(res, 400, "Token not accepted", `<p class="err">${esc(message2)}</p>${entryForm(server, nonce)}`);
|
|
33725
34487
|
return page(
|
|
33726
34488
|
res,
|
|
33727
34489
|
statusFor(decision.refusal.kind),
|
|
33728
34490
|
"Connect link unavailable",
|
|
33729
|
-
`<p class="err">${esc(
|
|
34491
|
+
`<p class="err">${esc(message2)}</p>`
|
|
33730
34492
|
);
|
|
33731
34493
|
}
|
|
33732
34494
|
if (verified === false) {
|
|
@@ -33742,15 +34504,15 @@ async function complete(svc, nonce, identity2, token, res) {
|
|
|
33742
34504
|
async function start(svc, nonce, identity2, res) {
|
|
33743
34505
|
const result = await svc.startOAuth(nonce, identity2);
|
|
33744
34506
|
if (!result.ok) {
|
|
33745
|
-
const
|
|
34507
|
+
const message2 = refusalMessage(result.refusal);
|
|
33746
34508
|
if (result.refusal.kind === "oauth_failed" && result.server)
|
|
33747
34509
|
return page(
|
|
33748
34510
|
res,
|
|
33749
34511
|
502,
|
|
33750
34512
|
"Sign-in could not start",
|
|
33751
|
-
`<p class="err">${esc(
|
|
34513
|
+
`<p class="err">${esc(message2)}</p><p>Nothing was stored.</p>${entryForm(result.server, nonce)}`
|
|
33752
34514
|
);
|
|
33753
|
-
return page(res, statusFor(result.refusal.kind), "Connect link unavailable", `<p class="err">${esc(
|
|
34515
|
+
return page(res, statusFor(result.refusal.kind), "Connect link unavailable", `<p class="err">${esc(message2)}</p>`);
|
|
33754
34516
|
}
|
|
33755
34517
|
const host = hostOf(result.redirectUrl);
|
|
33756
34518
|
page(
|
|
@@ -33784,13 +34546,13 @@ function callback(svc, params, identity2, res) {
|
|
|
33784
34546
|
}).then((result) => {
|
|
33785
34547
|
if (!result.ok) {
|
|
33786
34548
|
const refusal = result.refusal ?? { kind: "not_found" };
|
|
33787
|
-
const
|
|
34549
|
+
const message2 = refusalMessage(refusal);
|
|
33788
34550
|
const retry = result.server && refusal.kind === "oauth_failed" ? `<p>Nothing was stored. Open the connect link again to retry.</p>` : "";
|
|
33789
34551
|
return page(
|
|
33790
34552
|
res,
|
|
33791
34553
|
refusal.kind === "oauth_failed" ? 502 : statusFor(refusal.kind),
|
|
33792
34554
|
"Sign-in did not complete",
|
|
33793
|
-
`<p class="err">${esc(
|
|
34555
|
+
`<p class="err">${esc(message2)}</p>${retry}`
|
|
33794
34556
|
);
|
|
33795
34557
|
}
|
|
33796
34558
|
return connected(res, result.server, result.toolCount, result.warning);
|
|
@@ -33989,19 +34751,19 @@ var init_processMetrics = __esm({
|
|
|
33989
34751
|
function hasData(part) {
|
|
33990
34752
|
return (part.type === "image" || part.type === "document") && typeof part.data === "string";
|
|
33991
34753
|
}
|
|
33992
|
-
function turnRows(idx,
|
|
34754
|
+
function turnRows(idx, message2, opts = {}) {
|
|
33993
34755
|
const partBytes = opts.partBytes ?? TRANSCRIPT_PART_BYTES;
|
|
33994
34756
|
const refBytes = opts.attachmentRefBytes ?? ATTACHMENT_REF_BYTES;
|
|
33995
34757
|
const rows = [];
|
|
33996
34758
|
const attachments = [];
|
|
33997
|
-
|
|
34759
|
+
message2.content.forEach((part, i) => {
|
|
33998
34760
|
let stored = part;
|
|
33999
34761
|
if (hasData(part) && part.data.length > refBytes) {
|
|
34000
34762
|
const ref = attachmentRef(idx, i);
|
|
34001
34763
|
attachments.push({ ref, mediaType: part.mediaType, data: part.data });
|
|
34002
34764
|
stored = { ...part, data: "", dataRef: ref };
|
|
34003
34765
|
}
|
|
34004
|
-
const json = JSON.stringify({ role:
|
|
34766
|
+
const json = JSON.stringify({ role: message2.role, part: stored });
|
|
34005
34767
|
const bytes = utf8ByteLength(json);
|
|
34006
34768
|
if (bytes > partBytes) {
|
|
34007
34769
|
throw new Error(`transcript: part ${i} of turn ${idx} is ${bytes} bytes, over the ${partBytes} row budget`);
|
|
@@ -34210,9 +34972,9 @@ var init_runLedgerWorker = __esm({
|
|
|
34210
34972
|
this.checkIds(runId3, gen);
|
|
34211
34973
|
return this.fenceResult(await this.post("/runs/state", { storeKey: this.opts.storeKey, runId: runId3, gen, state }));
|
|
34212
34974
|
}
|
|
34213
|
-
async pushInbox(runId3,
|
|
34975
|
+
async pushInbox(runId3, message2) {
|
|
34214
34976
|
this.checkIds(runId3);
|
|
34215
|
-
const r = await this.post("/runs/inbox", { storeKey: this.opts.storeKey, runId: runId3, message });
|
|
34977
|
+
const r = await this.post("/runs/inbox", { storeKey: this.opts.storeKey, runId: runId3, message: message2 });
|
|
34216
34978
|
return { ok: r.data.ok === true, ...typeof r.data.seq === "number" ? { seq: r.data.seq } : {} };
|
|
34217
34979
|
}
|
|
34218
34980
|
async readInbox(runId3, afterSeq) {
|
|
@@ -34599,7 +35361,7 @@ var init_resume = __esm({
|
|
|
34599
35361
|
"submit_handoff",
|
|
34600
35362
|
"submit_dispositions"
|
|
34601
35363
|
]);
|
|
34602
|
-
toolUsesOf = (
|
|
35364
|
+
toolUsesOf = (message2) => message2?.role === "assistant" ? message2.content.filter((p) => p.type === "tool_use") : [];
|
|
34603
35365
|
}
|
|
34604
35366
|
});
|
|
34605
35367
|
|
|
@@ -35292,7 +36054,16 @@ async function runBot() {
|
|
|
35292
36054
|
};
|
|
35293
36055
|
const runsService = createRunsService({ registry: defaultRunRegistry, store: runStore, ledger: ledgerClient });
|
|
35294
36056
|
const scheduleStore = buildScheduleStore(config.config.schedules, processSecrets, (m) => console.warn(`[schedules] ${m}`)) ?? new NullScheduleStore();
|
|
35295
|
-
const
|
|
36057
|
+
const deliveryWarn = (m) => console.warn(`[delivery] ${m}`);
|
|
36058
|
+
const deliveryConfig = parseDeliveryConfig(config.config.delivery);
|
|
36059
|
+
const delivery = capabilities.github ? deliveryFromConfig(deliveryConfig, {
|
|
36060
|
+
snapshots: buildDeliverySnapshotStore(config.config, processSecrets, deliveryWarn),
|
|
36061
|
+
warn: deliveryWarn
|
|
36062
|
+
}) : void 0;
|
|
36063
|
+
const deliveryService = delivery?.service ?? new NullDeliveryService();
|
|
36064
|
+
const deliveryEveryMinutes = deliveryConfig?.snapshot.everyMinutes ?? SNAPSHOT_EVERY_MINUTES.default;
|
|
36065
|
+
if (delivery && deliveryService.repos().length > 0)
|
|
36066
|
+
delivery.source.startRefreshLoop({ repos: deliveryService.repos(), everyMinutes: deliveryEveryMinutes });
|
|
35296
36067
|
const commands = buildCoreCommands(config, runStore, {
|
|
35297
36068
|
registry: defaultRunRegistry,
|
|
35298
36069
|
secrets: processSecrets,
|
|
@@ -35350,7 +36121,7 @@ async function runBot() {
|
|
|
35350
36121
|
const costsView = createCostsViewHandler(costsService, shell);
|
|
35351
36122
|
const costsState = capabilities.costs ? `GET /costs (${costsService.groups().join(",")}; LLM ${anthropicAdminKey ? "on" : "off"})` : costsCfg ? `GET /costs (503 \u2014 ${costsCfg.cloudflareTokenEnv} not set)` : "GET /costs (503 \u2014 no costs config)";
|
|
35352
36123
|
const deliveryView = createDeliveryViewHandler({ service: deliveryService, runs: runsService }, shell);
|
|
35353
|
-
const deliveryState = !capabilities.github ? "GET /delivery (503 \u2014 no GitHub credential)" : deliveryService.repos().length === 0 ? "GET /delivery (503 \u2014 no delivery.repos)" : `GET /delivery (${deliveryService.repos().join(",")})`;
|
|
36124
|
+
const deliveryState = !capabilities.github ? "GET /delivery (503 \u2014 no GitHub credential)" : deliveryService.repos().length === 0 ? "GET /delivery (503 \u2014 no delivery.repos)" : `GET /delivery (${deliveryService.repos().join(",")}; snapshot every ${deliveryEveryMinutes} min)`;
|
|
35354
36125
|
const tokenCount = Object.keys(auth.tokens).length;
|
|
35355
36126
|
const liveViewState = process.env.PUBLIC_BASE_URL ? "GET /runs (index) + /runs/:id (live view)" : "GET /runs (index) + live view (no PUBLIC_BASE_URL \u2014 per-run links omitted)";
|
|
35356
36127
|
const accessConfig = parseAccessConfig(publicEnv());
|
|
@@ -35676,6 +36447,7 @@ var init_index = __esm({
|
|
|
35676
36447
|
init_costsView();
|
|
35677
36448
|
init_deliveryView();
|
|
35678
36449
|
init_delivery();
|
|
36450
|
+
init_deliverySnapshotStore();
|
|
35679
36451
|
init_costs();
|
|
35680
36452
|
init_residentAdmin();
|
|
35681
36453
|
init_residentFleet();
|
|
@@ -35883,8 +36655,8 @@ function exitCodeFor(error) {
|
|
|
35883
36655
|
if (error === "busy") return 75;
|
|
35884
36656
|
return 1;
|
|
35885
36657
|
}
|
|
35886
|
-
function errorLine(code,
|
|
35887
|
-
return `error (${code}): ${
|
|
36658
|
+
function errorLine(code, message2) {
|
|
36659
|
+
return `error (${code}): ${message2}`;
|
|
35888
36660
|
}
|
|
35889
36661
|
async function runCommand(commands, parsed, caller, opts = {}) {
|
|
35890
36662
|
const cmd = commands.get(parsed.id);
|