@sunshinelife83/hearth 1.0.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/LICENSE +21 -0
- package/README.md +323 -0
- package/bin/hearth-agentd.js +4 -0
- package/bin/hearth.js +4 -0
- package/bin/run-entrypoint.js +20 -0
- package/dist/agent-tools.js +738 -0
- package/dist/app-version.js +16 -0
- package/dist/apply-patch.js +402 -0
- package/dist/artifact-error.js +8 -0
- package/dist/artifact-tools.js +377 -0
- package/dist/cli-workspace.js +36 -0
- package/dist/cli.js +1086 -0
- package/dist/config-migration.js +82 -0
- package/dist/config-schema.js +136 -0
- package/dist/config.js +115 -0
- package/dist/context/context-tools.js +150 -0
- package/dist/context/repo-map.js +102 -0
- package/dist/dashboard/app.js +226 -0
- package/dist/dashboard/index.html +45 -0
- package/dist/dashboard/landing.html +57 -0
- package/dist/dashboard/styles.css +23 -0
- package/dist/dashboard.js +271 -0
- package/dist/db/client.js +29 -0
- package/dist/db/migrations.js +262 -0
- package/dist/db/schema.js +85 -0
- package/dist/device-tokens.js +61 -0
- package/dist/git-worktrees.js +134 -0
- package/dist/git.js +41 -0
- package/dist/incoming-artifacts.js +378 -0
- package/dist/local-agent-acp.js +768 -0
- package/dist/local-agent-adapters.js +20 -0
- package/dist/local-agent-availability.js +92 -0
- package/dist/local-agent-catalog.js +51 -0
- package/dist/local-agent-claude.js +334 -0
- package/dist/local-agent-client.js +519 -0
- package/dist/local-agent-codex.js +532 -0
- package/dist/local-agent-config.js +34 -0
- package/dist/local-agent-daemon-lifecycle.js +195 -0
- package/dist/local-agent-daemon-main.js +86 -0
- package/dist/local-agent-daemon-protocol.js +302 -0
- package/dist/local-agent-daemon.js +407 -0
- package/dist/local-agent-errors.js +378 -0
- package/dist/local-agent-grok.js +202 -0
- package/dist/local-agent-manager.js +715 -0
- package/dist/local-agent-opencode.js +463 -0
- package/dist/local-agent-path.js +24 -0
- package/dist/local-agent-pi-sandbox.js +472 -0
- package/dist/local-agent-pi.js +298 -0
- package/dist/local-agent-presentation.js +104 -0
- package/dist/local-agent-profiles.js +127 -0
- package/dist/local-agent-runtime-pool.js +481 -0
- package/dist/local-agent-runtime.js +1 -0
- package/dist/local-agent-store.js +193 -0
- package/dist/local-agent-targets.js +97 -0
- package/dist/logger.js +97 -0
- package/dist/machine-id.js +35 -0
- package/dist/mcp-modern-server.js +65 -0
- package/dist/oauth-provider.js +331 -0
- package/dist/oauth-store.js +144 -0
- package/dist/onboarding.js +35 -0
- package/dist/orchestration/brief.js +70 -0
- package/dist/orchestration/lanes.js +145 -0
- package/dist/orchestration/result.js +46 -0
- package/dist/orchestration/scope.js +61 -0
- package/dist/pi-tools.js +58 -0
- package/dist/policy/command-policy.js +104 -0
- package/dist/policy/env-allowlist.js +96 -0
- package/dist/policy/sandbox.js +68 -0
- package/dist/policy/workspace-profiles.js +47 -0
- package/dist/process-journal.js +116 -0
- package/dist/process-platform.js +49 -0
- package/dist/process-sessions.js +388 -0
- package/dist/rate-limit.js +77 -0
- package/dist/request-meta.js +9 -0
- package/dist/review-checkpoints.js +349 -0
- package/dist/roots.js +37 -0
- package/dist/server-shutdown.js +12 -0
- package/dist/server.js +980 -0
- package/dist/skills.js +84 -0
- package/dist/snapshot-manager.js +123 -0
- package/dist/stdio-server.js +80 -0
- package/dist/task-store.js +203 -0
- package/dist/task-tools.js +455 -0
- package/dist/tool-surfaces/claude.js +220 -0
- package/dist/tool-surfaces/codex.js +255 -0
- package/dist/tool-surfaces/index.js +15 -0
- package/dist/tool-surfaces/shared.js +228 -0
- package/dist/tool-surfaces/types.js +27 -0
- package/dist/ui/.vite/manifest.json +2544 -0
- package/dist/ui/assets/abap-CLvhMVsD.js +1 -0
- package/dist/ui/assets/actionscript-3--17pq3dv.js +1 -0
- package/dist/ui/assets/ada-C5qYipkI.js +1 -0
- package/dist/ui/assets/andromeeda-vGVdxbeo.js +1 -0
- package/dist/ui/assets/angular-html-DrbO3_Xe.js +1 -0
- package/dist/ui/assets/angular-ts-CmTVzHJx.js +1 -0
- package/dist/ui/assets/apache-U0d_L8uA.js +1 -0
- package/dist/ui/assets/apex-CGTLDQj6.js +1 -0
- package/dist/ui/assets/apl-BOpCpqXf.js +1 -0
- package/dist/ui/assets/applescript-CCn79oCD.js +1 -0
- package/dist/ui/assets/ara-4CJ0cIlV.js +1 -0
- package/dist/ui/assets/asciidoc-DE70LPWp.js +1 -0
- package/dist/ui/assets/asm-Cmm7eHzH.js +1 -0
- package/dist/ui/assets/astro-CxPeBwei.js +1 -0
- package/dist/ui/assets/aurora-x-CDeNXAV0.js +1 -0
- package/dist/ui/assets/awk-BWXHIvNe.js +1 -0
- package/dist/ui/assets/ayu-dark-DluEY0Gj.js +1 -0
- package/dist/ui/assets/ayu-light-C3h-C4tm.js +1 -0
- package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +1 -0
- package/dist/ui/assets/ballerina-B7ZEbQpA.js +1 -0
- package/dist/ui/assets/bat-Bo4NYOV-.js +1 -0
- package/dist/ui/assets/beancount-D-usSTwE.js +1 -0
- package/dist/ui/assets/berry-DKpUyyne.js +1 -0
- package/dist/ui/assets/bibtex-Ci_nEsc7.js +1 -0
- package/dist/ui/assets/bicep-CUHmPFLl.js +1 -0
- package/dist/ui/assets/bird2-C2hNVINV.js +1 -0
- package/dist/ui/assets/blade-DtsAAG4P.js +1 -0
- package/dist/ui/assets/bsl-BkkzgIyY.js +1 -0
- package/dist/ui/assets/c-D9hLjNUM.js +1 -0
- package/dist/ui/assets/c3-CnJL0r0V.js +1 -0
- package/dist/ui/assets/cadence-CQ2zXKGN.js +1 -0
- package/dist/ui/assets/cairo-DLTphjLi.js +1 -0
- package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
- package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
- package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
- package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
- package/dist/ui/assets/clarity-SemFz856.js +1 -0
- package/dist/ui/assets/clojure-DqKBuwfJ.js +1 -0
- package/dist/ui/assets/cmake-Bj61d0ZC.js +1 -0
- package/dist/ui/assets/cobol-C1SWlvZm.js +1 -0
- package/dist/ui/assets/codeowners-C8r90Shi.js +1 -0
- package/dist/ui/assets/codeql-oeQT6MSM.js +1 -0
- package/dist/ui/assets/coffee-B71R3v2U.js +1 -0
- package/dist/ui/assets/common-lisp-Cv5bFMCO.js +1 -0
- package/dist/ui/assets/coq-BrsZFFmf.js +1 -0
- package/dist/ui/assets/cpp--5a4c3v4.js +1 -0
- package/dist/ui/assets/crystal-AtqWYtE0.js +1 -0
- package/dist/ui/assets/csharp-Ct8U2NOr.js +1 -0
- package/dist/ui/assets/css-CbqKSHI-.js +1 -0
- package/dist/ui/assets/csv-Dx-8-gkx.js +1 -0
- package/dist/ui/assets/cue-CE9AQfxI.js +1 -0
- package/dist/ui/assets/cypher-ClKdZ_lG.js +1 -0
- package/dist/ui/assets/d-qD-0Kul2.js +1 -0
- package/dist/ui/assets/dark-plus-Cs2F2srj.js +1 -0
- package/dist/ui/assets/dart-DkHntEIa.js +1 -0
- package/dist/ui/assets/dax-BkyTk9wS.js +1 -0
- package/dist/ui/assets/desktop-Dlh5hvp9.js +1 -0
- package/dist/ui/assets/diff-woXpYk--.js +1 -0
- package/dist/ui/assets/docker-IyjqRm3v.js +1 -0
- package/dist/ui/assets/dotenv-_5a1GRtc.js +1 -0
- package/dist/ui/assets/dracula-BHWKrbxM.js +1 -0
- package/dist/ui/assets/dracula-soft-5eyTD99u.js +1 -0
- package/dist/ui/assets/dream-maker-DW3nJb8Q.js +1 -0
- package/dist/ui/assets/edge-BPwY_RrJ.js +1 -0
- package/dist/ui/assets/elixir-DVH2yLJf.js +1 -0
- package/dist/ui/assets/elm-BrleA6gS.js +1 -0
- package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +1 -0
- package/dist/ui/assets/erb-2SHiYe30.js +1 -0
- package/dist/ui/assets/erlang-Cphh6RMH.js +1 -0
- package/dist/ui/assets/everforest-dark-sB-x3p7T.js +1 -0
- package/dist/ui/assets/everforest-light-Df2xbC6M.js +1 -0
- package/dist/ui/assets/fennel-DQxkIbk2.js +1 -0
- package/dist/ui/assets/fish-BJitypiv.js +1 -0
- package/dist/ui/assets/fluent-C03EYrpw.js +1 -0
- package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
- package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +1 -0
- package/dist/ui/assets/fsharp-D13ZGOAj.js +1 -0
- package/dist/ui/assets/gdresource-C0sCabJj.js +1 -0
- package/dist/ui/assets/gdscript-Cp2uCuqX.js +1 -0
- package/dist/ui/assets/gdshader-CBce3t8t.js +1 -0
- package/dist/ui/assets/genie-CV2tkWYe.js +1 -0
- package/dist/ui/assets/gherkin-DExj1W_8.js +1 -0
- package/dist/ui/assets/git-commit-BSykSTBG.js +1 -0
- package/dist/ui/assets/git-rebase-Bc7atMaV.js +1 -0
- package/dist/ui/assets/github-dark-C-LZuMrd.js +1 -0
- package/dist/ui/assets/github-dark-default-DXG-b-1a.js +1 -0
- package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
- package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
- package/dist/ui/assets/github-light-EUqPIrTm.js +1 -0
- package/dist/ui/assets/github-light-default-BXViO-2h.js +1 -0
- package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +1 -0
- package/dist/ui/assets/gleam-CSRkHgEL.js +1 -0
- package/dist/ui/assets/glimmer-js-DXeTDPtW.js +1 -0
- package/dist/ui/assets/glimmer-ts-CEOoXHU4.js +1 -0
- package/dist/ui/assets/glsl-5-43-Gsg.js +1 -0
- package/dist/ui/assets/gn-ilITqXS6.js +1 -0
- package/dist/ui/assets/gnuplot-7GGW24-e.js +1 -0
- package/dist/ui/assets/go-BJwz_mda.js +1 -0
- package/dist/ui/assets/graphql-Bk7Ah1KA.js +1 -0
- package/dist/ui/assets/groovy-CacY0gHj.js +1 -0
- package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
- package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
- package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
- package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
- package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
- package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
- package/dist/ui/assets/hack-DUHz4rCJ.js +1 -0
- package/dist/ui/assets/haml-BPCuuTPR.js +1 -0
- package/dist/ui/assets/handlebars-CHxmUsnU.js +1 -0
- package/dist/ui/assets/haskell-D8IpX4py.js +1 -0
- package/dist/ui/assets/haxe-OTjmBuCE.js +1 -0
- package/dist/ui/assets/hcl-Dh228itO.js +1 -0
- package/dist/ui/assets/hjson-CxZEssPk.js +1 -0
- package/dist/ui/assets/hlsl-Cvrh5tZx.js +1 -0
- package/dist/ui/assets/horizon-CE9ld1lL.js +1 -0
- package/dist/ui/assets/horizon-bright-Br1oVSNq.js +1 -0
- package/dist/ui/assets/houston-CsvMBhTu.js +1 -0
- package/dist/ui/assets/html-BBJqizz0.js +1 -0
- package/dist/ui/assets/html-derivative-ShTPCcKN.js +1 -0
- package/dist/ui/assets/http-VFTyziwA.js +1 -0
- package/dist/ui/assets/hurl-B8yxTa4r.js +1 -0
- package/dist/ui/assets/hxml-B0Qn7Nwc.js +1 -0
- package/dist/ui/assets/hy-CZbG8q4J.js +1 -0
- package/dist/ui/assets/imba-DsUTQ-LC.js +1 -0
- package/dist/ui/assets/ini-B5eOa1yu.js +1 -0
- package/dist/ui/assets/java-BZ5DAgJZ.js +1 -0
- package/dist/ui/assets/javascript-C_zuIEaC.js +1 -0
- package/dist/ui/assets/jinja-DWd6xfNr.js +1 -0
- package/dist/ui/assets/jison-BbY63d1V.js +1 -0
- package/dist/ui/assets/json-C4DnajZs.js +1 -0
- package/dist/ui/assets/json5-BR5RXkoi.js +1 -0
- package/dist/ui/assets/jsonc-CYpm1nAK.js +1 -0
- package/dist/ui/assets/jsonl-CmCQp5Yx.js +1 -0
- package/dist/ui/assets/jsonnet-CJTPZ8u_.js +1 -0
- package/dist/ui/assets/jssm-DXw9l8Rf.js +1 -0
- package/dist/ui/assets/jsx-C4AACieZ.js +1 -0
- package/dist/ui/assets/julia-sRu7EFMW.js +1 -0
- package/dist/ui/assets/just-DpZ9Sx1v.js +1 -0
- package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
- package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +1 -0
- package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +1 -0
- package/dist/ui/assets/kdl-CsD5j6eV.js +1 -0
- package/dist/ui/assets/kotlin-DhhofPvG.js +1 -0
- package/dist/ui/assets/kusto-BUv0MjJC.js +1 -0
- package/dist/ui/assets/laserwave-C_8bwKvT.js +1 -0
- package/dist/ui/assets/latex-B6a_uum7.js +1 -0
- package/dist/ui/assets/lean-CewbzKMR.js +1 -0
- package/dist/ui/assets/less-DVTAwKKz.js +1 -0
- package/dist/ui/assets/light-plus-DVQuIRkW.js +1 -0
- package/dist/ui/assets/liquid-B2sVpjjr.js +1 -0
- package/dist/ui/assets/llvm-Cm23YOpf.js +1 -0
- package/dist/ui/assets/log-BNLmms1o.js +1 -0
- package/dist/ui/assets/logo-Cluzi2Zq.js +1 -0
- package/dist/ui/assets/lua-DxJJll61.js +1 -0
- package/dist/ui/assets/luau-CNKltnaQ.js +1 -0
- package/dist/ui/assets/make-Dixweg8N.js +1 -0
- package/dist/ui/assets/markdown-BYOwaDjH.js +1 -0
- package/dist/ui/assets/marko-Dx8mw-Wx.js +1 -0
- package/dist/ui/assets/material-theme-Bm3Qr25_.js +1 -0
- package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +1 -0
- package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +1 -0
- package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +1 -0
- package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +1 -0
- package/dist/ui/assets/matlab-D7qyCx1q.js +1 -0
- package/dist/ui/assets/mdc-vNKeXEwR.js +1 -0
- package/dist/ui/assets/mdx-DQZ5AkYe.js +1 -0
- package/dist/ui/assets/mermaid-Bk4SNUv9.js +1 -0
- package/dist/ui/assets/min-dark-BSWPekZh.js +1 -0
- package/dist/ui/assets/min-light-DDpmG2fV.js +1 -0
- package/dist/ui/assets/mipsasm-BMqwQI7S.js +1 -0
- package/dist/ui/assets/mojo-BgCJLMeH.js +1 -0
- package/dist/ui/assets/monokai-CdkpiU2Y.js +1 -0
- package/dist/ui/assets/moonbit-CaWjb8XO.js +1 -0
- package/dist/ui/assets/move-B1IS1UjX.js +1 -0
- package/dist/ui/assets/narrat-_X_XdTYD.js +1 -0
- package/dist/ui/assets/nextflow-Bbiyy34d.js +1 -0
- package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +1 -0
- package/dist/ui/assets/nginx-DScQAGLT.js +1 -0
- package/dist/ui/assets/night-owl-DhmEMT88.js +1 -0
- package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +1 -0
- package/dist/ui/assets/nim-lAJch9uT.js +1 -0
- package/dist/ui/assets/nix-IvuFDN5E.js +1 -0
- package/dist/ui/assets/nord-Cb4Vim4T.js +1 -0
- package/dist/ui/assets/nushell-DcLAeLz5.js +1 -0
- package/dist/ui/assets/objective-c-D1A_Heim.js +1 -0
- package/dist/ui/assets/objective-cpp-BsSzOQcm.js +1 -0
- package/dist/ui/assets/ocaml-O90oeIOV.js +1 -0
- package/dist/ui/assets/odin-B1RWQWA5.js +1 -0
- package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +1 -0
- package/dist/ui/assets/one-light-D7Lr4KcI.js +1 -0
- package/dist/ui/assets/openscad-BUDT5pXO.js +1 -0
- package/dist/ui/assets/pascal-4ZHwLPI5.js +1 -0
- package/dist/ui/assets/perl-C_GkVo_E.js +1 -0
- package/dist/ui/assets/php-DziV3K6J.js +1 -0
- package/dist/ui/assets/pierre-dark-CpLgRqie.js +1 -0
- package/dist/ui/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
- package/dist/ui/assets/pierre-dark-soft-kZQmAZld.js +1 -0
- package/dist/ui/assets/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
- package/dist/ui/assets/pierre-dark-vibrant-CpQYzh95.js +1 -0
- package/dist/ui/assets/pierre-light-CoaEpmwp.js +1 -0
- package/dist/ui/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
- package/dist/ui/assets/pierre-light-soft-lWLdNTOI.js +1 -0
- package/dist/ui/assets/pierre-light-tritanopia-CEbqgOJL.js +1 -0
- package/dist/ui/assets/pierre-light-vibrant-D80Fkn33.js +1 -0
- package/dist/ui/assets/pkl-ot-7Btpt.js +1 -0
- package/dist/ui/assets/plastic-DQwYfKfQ.js +1 -0
- package/dist/ui/assets/plsql-DGHpHOYJ.js +1 -0
- package/dist/ui/assets/po-BiJDBrnU.js +1 -0
- package/dist/ui/assets/poimandres-DRFjx7u4.js +1 -0
- package/dist/ui/assets/polar-C7UOKdEL.js +1 -0
- package/dist/ui/assets/postcss-BXeXVLqQ.js +1 -0
- package/dist/ui/assets/powerquery-DNMTfnFr.js +1 -0
- package/dist/ui/assets/powershell-DshXNtvi.js +1 -0
- package/dist/ui/assets/prisma-BsRQq5mF.js +1 -0
- package/dist/ui/assets/prolog-iXnhIJG7.js +1 -0
- package/dist/ui/assets/proto-DB4EqR-F.js +1 -0
- package/dist/ui/assets/pug-z75UIWVK.js +1 -0
- package/dist/ui/assets/puppet-CDv2pdJW.js +1 -0
- package/dist/ui/assets/purescript-9MfHhQsQ.js +1 -0
- package/dist/ui/assets/python-gzcpVVnB.js +1 -0
- package/dist/ui/assets/qml-Cmm4coz1.js +1 -0
- package/dist/ui/assets/qmldir-DCQb3MpD.js +1 -0
- package/dist/ui/assets/qss-Fe1Jh2GI.js +1 -0
- package/dist/ui/assets/r-Brd0axBE.js +1 -0
- package/dist/ui/assets/racket-DcIDlBhZ.js +1 -0
- package/dist/ui/assets/raku-B3gFvitq.js +1 -0
- package/dist/ui/assets/razor-DSbwmoiu.js +1 -0
- package/dist/ui/assets/red-CJ3rzSJv.js +1 -0
- package/dist/ui/assets/reg-CRGYupPL.js +1 -0
- package/dist/ui/assets/regexp-Bs3Uk-pY.js +1 -0
- package/dist/ui/assets/rel-BtDbiS_P.js +1 -0
- package/dist/ui/assets/review-payload-CbwCBKB1.js +1580 -0
- package/dist/ui/assets/riscv-Ckw8ddFX.js +1 -0
- package/dist/ui/assets/ron-VUp2lXgN.js +1 -0
- package/dist/ui/assets/rose-pine-BthvhNj6.js +1 -0
- package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
- package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +1 -0
- package/dist/ui/assets/rosmsg-CAekHB0j.js +1 -0
- package/dist/ui/assets/rst-ChIyKpUC.js +1 -0
- package/dist/ui/assets/ruby-BdAmvOMO.js +1 -0
- package/dist/ui/assets/rust-Cfkwpbl8.js +1 -0
- package/dist/ui/assets/sas-DpXn8hc5.js +1 -0
- package/dist/ui/assets/sass-DXrisJhu.js +1 -0
- package/dist/ui/assets/scala-DKOlJaKm.js +1 -0
- package/dist/ui/assets/scheme-DQCgrYNe.js +1 -0
- package/dist/ui/assets/scss-atX1Uuef.js +1 -0
- package/dist/ui/assets/sdbl-bTVj8UrX.js +1 -0
- package/dist/ui/assets/shaderlab-TOUzSsQk.js +1 -0
- package/dist/ui/assets/shellscript-BqgcAeMK.js +1 -0
- package/dist/ui/assets/shellsession-DfQSMRN5.js +1 -0
- package/dist/ui/assets/slack-dark-DnToyrRv.js +1 -0
- package/dist/ui/assets/slack-ochin-B2OO5cIa.js +1 -0
- package/dist/ui/assets/smalltalk-B16xEiuN.js +1 -0
- package/dist/ui/assets/snazzy-light-4G7pJPwS.js +1 -0
- package/dist/ui/assets/solarized-dark-DV17i1UV.js +1 -0
- package/dist/ui/assets/solarized-light-DSh2HLQt.js +1 -0
- package/dist/ui/assets/solidity-CKzVLygQ.js +1 -0
- package/dist/ui/assets/soy-DzP7zZTB.js +1 -0
- package/dist/ui/assets/sparql-D_iOobhT.js +1 -0
- package/dist/ui/assets/splunk-BC2Px7Mm.js +1 -0
- package/dist/ui/assets/sql-gmaLk66z.js +1 -0
- package/dist/ui/assets/ssh-config-BgfXC-Er.js +1 -0
- package/dist/ui/assets/stata-CJ0YTMcV.js +1 -0
- package/dist/ui/assets/stylus-B6D30XZt.js +1 -0
- package/dist/ui/assets/surrealql-LH7FciQz.js +1 -0
- package/dist/ui/assets/svelte-BME2PU6V.js +1 -0
- package/dist/ui/assets/swift-DonLKvLd.js +1 -0
- package/dist/ui/assets/synthwave-84-nFMaYfgc.js +1 -0
- package/dist/ui/assets/system-verilog-DJ5XKQeo.js +1 -0
- package/dist/ui/assets/systemd-BxMlprV5.js +1 -0
- package/dist/ui/assets/talonscript-CohzipZa.js +1 -0
- package/dist/ui/assets/tasl-DMoTqEGO.js +1 -0
- package/dist/ui/assets/tcl-CZd0xW_V.js +1 -0
- package/dist/ui/assets/templ-DHBNIfYW.js +1 -0
- package/dist/ui/assets/terraform-DswuEJGm.js +1 -0
- package/dist/ui/assets/tex-C8-kPEzO.js +1 -0
- package/dist/ui/assets/tokyo-night-oM2G3aXe.js +1 -0
- package/dist/ui/assets/toml-CcmNWLt0.js +1 -0
- package/dist/ui/assets/ts-tags-CiewV0vR.js +1 -0
- package/dist/ui/assets/tsv-sltzmVWM.js +1 -0
- package/dist/ui/assets/tsx-CUYPqmnq.js +1 -0
- package/dist/ui/assets/turtle-ByJddavk.js +1 -0
- package/dist/ui/assets/twig-BTkvsl0b.js +1 -0
- package/dist/ui/assets/typescript-DDQMaPwj.js +1 -0
- package/dist/ui/assets/typespec-B88KGewJ.js +1 -0
- package/dist/ui/assets/typst-DI99ib-x.js +1 -0
- package/dist/ui/assets/v-DETTlOr0.js +1 -0
- package/dist/ui/assets/vala-zf12oZj6.js +1 -0
- package/dist/ui/assets/vb-Djn5o6TS.js +1 -0
- package/dist/ui/assets/verilog-CiiDBU1e.js +1 -0
- package/dist/ui/assets/vesper-D5bVUKB1.js +1 -0
- package/dist/ui/assets/vhdl-BroJfC0k.js +1 -0
- package/dist/ui/assets/viml-DvXPmvsu.js +1 -0
- package/dist/ui/assets/vitesse-black-fwtXNY1n.js +1 -0
- package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +1 -0
- package/dist/ui/assets/vitesse-light-VbXTXTou.js +1 -0
- package/dist/ui/assets/vue-BH5SEWRH.js +1 -0
- package/dist/ui/assets/vue-html-BT7yeYez.js +1 -0
- package/dist/ui/assets/vue-vine-Cs5IN2rs.js +1 -0
- package/dist/ui/assets/vyper-CgoNMtux.js +1 -0
- package/dist/ui/assets/wasm-BnjxR4X6.js +1 -0
- package/dist/ui/assets/wasm-ByWQv1Qj.js +1 -0
- package/dist/ui/assets/wenyan-C8pVoKbM.js +1 -0
- package/dist/ui/assets/wgsl-BsKzXJz4.js +1 -0
- package/dist/ui/assets/wikitext-ClFFjSW2.js +1 -0
- package/dist/ui/assets/wit-DdvCle-K.js +1 -0
- package/dist/ui/assets/wolfram-DLL8P-h_.js +1 -0
- package/dist/ui/assets/workspace-app-B_BnSEHO.css +1 -0
- package/dist/ui/assets/workspace-app-DSFpnrIC.js +115 -0
- package/dist/ui/assets/xml-D3_1BEcO.js +1 -0
- package/dist/ui/assets/xsl-BBOCDn4Y.js +1 -0
- package/dist/ui/assets/yaml-lThBDT45.js +1 -0
- package/dist/ui/assets/zenscript-BnlCZFoB.js +1 -0
- package/dist/ui/assets/zig-CMLA9XwU.js +1 -0
- package/dist/ui/workspace-app.html +15 -0
- package/dist/user-config.js +228 -0
- package/dist/verification.js +74 -0
- package/dist/workspace-store.js +133 -0
- package/dist/workspaces.js +433 -0
- package/docs/adr/devspace-x-implementation-adrs.md +159 -0
- package/docs/agent-profile-schema.md +203 -0
- package/docs/artifact-exchange.md +44 -0
- package/docs/assets/devspace-logo-light.png +0 -0
- package/docs/assets/devspace-screenshot.png +0 -0
- package/docs/assets/v11-review-ui-after.png +0 -0
- package/docs/assets/v11-review-ui-before.png +0 -0
- package/docs/chatgpt-coding-workflow.md +215 -0
- package/docs/configuration.md +217 -0
- package/docs/gotchas.md +294 -0
- package/docs/local-agent-daemon.md +101 -0
- package/docs/security.md +197 -0
- package/docs/setup.md +174 -0
- package/examples/agents/claude-implementer.md +30 -0
- package/examples/agents/codex-explorer.md +27 -0
- package/examples/agents/codex-qa-tester.md +29 -0
- package/examples/agents/codex-worker.md +25 -0
- package/examples/agents/copilot-reviewer.md +25 -0
- package/examples/agents/cursor-agent-worker.md +26 -0
- package/examples/agents/grok-builder.md +10 -0
- package/examples/agents/opencode-explorer.md +27 -0
- package/examples/agents/pi-reviewer.md +27 -0
- package/package.json +102 -0
- package/schema/v1/hearth.schema.json +529 -0
- package/scripts/copy-dashboard.mjs +9 -0
- package/scripts/fix-node-pty-permissions.mjs +22 -0
- package/scripts/generate-config-schema.ts +9 -0
- package/skills/subagents/SKILL.md +57 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
import { logEvent } from "../logger.js";
|
|
3
|
+
import { applyPatch } from "../apply-patch.js";
|
|
4
|
+
import { EDIT_TOOL_ANNOTATIONS, SHELL_TOOL_ANNOTATIONS, toolNames, workspaceIdDescription, } from "./types.js";
|
|
5
|
+
import { enforceShellPolicy, resultOutputSchema, runLoggedToolOperation, sandboxDecision, snapshotBeforeRiskyExecution, textBlock, } from "./shared.js";
|
|
6
|
+
const CODEX_INSTRUCTIONS = `Use ${toolNames.read} for direct file reads, apply_patch for all file modifications, exec_command for inspection, tests, builds, and other commands, and write_stdin to poll or interact with running processes. Commands run with the local user's authority and are not sandboxed; workspace validation only selects their initial working directory. Command policy: inspection commands run freely; ordinary workspace work (builds, tests, local edits) runs freely; commands with effects outside the workspace (network fetches, package installs, recursive deletes, git push, permission changes) require explicit user approval in the conversation and the approvedByUser flag; privilege escalation, system management, and piping remote scripts into a shell are always blocked. Follow instructions returned by ${toolNames.openWorkspace}; read applicable instruction and skill files before working in their scope.`;
|
|
7
|
+
export function codexInstructions() {
|
|
8
|
+
return CODEX_INSTRUCTIONS;
|
|
9
|
+
}
|
|
10
|
+
export function registerCodexTools(context) {
|
|
11
|
+
for (const register of CODEX_REGISTRATIONS) {
|
|
12
|
+
register(context);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const CODEX_REGISTRATIONS = [
|
|
16
|
+
registerApplyPatchTool,
|
|
17
|
+
registerCodexProcessTools,
|
|
18
|
+
];
|
|
19
|
+
function processResult(snapshot) {
|
|
20
|
+
const status = snapshot.running
|
|
21
|
+
? `Process running with session ID ${snapshot.sessionId}.`
|
|
22
|
+
: snapshot.signal
|
|
23
|
+
? `Process exited after signal ${snapshot.signal}.`
|
|
24
|
+
: `Process exited with code ${snapshot.exitCode ?? "unknown"}.`;
|
|
25
|
+
return snapshot.output
|
|
26
|
+
? `${snapshot.output.replace(/\n$/, "")}\n${status}`
|
|
27
|
+
: status;
|
|
28
|
+
}
|
|
29
|
+
function processOutputSchema() {
|
|
30
|
+
return resultOutputSchema({
|
|
31
|
+
sessionId: z.number().optional(),
|
|
32
|
+
running: z.boolean(),
|
|
33
|
+
exitCode: z.number().int().optional(),
|
|
34
|
+
signal: z.string().optional(),
|
|
35
|
+
wallTimeMs: z.number().nonnegative(),
|
|
36
|
+
outputTruncated: z.boolean(),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function processToolResponse(snapshot) {
|
|
40
|
+
const result = processResult(snapshot);
|
|
41
|
+
const content = [textBlock(result)];
|
|
42
|
+
return {
|
|
43
|
+
content,
|
|
44
|
+
structuredContent: {
|
|
45
|
+
result,
|
|
46
|
+
sessionId: snapshot.sessionId,
|
|
47
|
+
running: snapshot.running,
|
|
48
|
+
exitCode: snapshot.exitCode,
|
|
49
|
+
signal: snapshot.signal,
|
|
50
|
+
wallTimeMs: snapshot.wallTimeMs,
|
|
51
|
+
outputTruncated: snapshot.outputTruncated,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function registerApplyPatchTool(context) {
|
|
56
|
+
const { server, config, workspaces } = context;
|
|
57
|
+
server.registerTool("apply_patch", {
|
|
58
|
+
title: "Apply patch",
|
|
59
|
+
description: "Apply one structured patch in a workspace. Supports adding, overwriting, updating, deleting, and moving files. Use this for all file modifications. Paths must be relative to the workspace.",
|
|
60
|
+
inputSchema: {
|
|
61
|
+
workspaceId: z.string().describe(workspaceIdDescription),
|
|
62
|
+
patch: z
|
|
63
|
+
.string()
|
|
64
|
+
.describe("Patch text enclosed by *** Begin Patch and *** End Patch markers."),
|
|
65
|
+
},
|
|
66
|
+
outputSchema: resultOutputSchema({
|
|
67
|
+
additions: z.number(),
|
|
68
|
+
removals: z.number(),
|
|
69
|
+
files: z.array(z.object({
|
|
70
|
+
path: z.string(),
|
|
71
|
+
previousPath: z.string().optional(),
|
|
72
|
+
operation: z.enum(["add", "update", "delete", "move"]),
|
|
73
|
+
})),
|
|
74
|
+
}),
|
|
75
|
+
annotations: EDIT_TOOL_ANNOTATIONS,
|
|
76
|
+
}, async ({ workspaceId, patch }) => {
|
|
77
|
+
const startedAt = performance.now();
|
|
78
|
+
const applied = await runLoggedToolOperation(config, { tool: "apply_patch", workspaceId }, startedAt, async () => {
|
|
79
|
+
const workspace = workspaces.getWorkspace(workspaceId);
|
|
80
|
+
return applyPatch(workspace.root, patch);
|
|
81
|
+
});
|
|
82
|
+
const paths = applied.files.map((file) => file.path).join(", ");
|
|
83
|
+
const result = `Applied patch to ${applied.files.length} file(s): ${paths}`;
|
|
84
|
+
const content = [textBlock(result)];
|
|
85
|
+
return {
|
|
86
|
+
content,
|
|
87
|
+
structuredContent: {
|
|
88
|
+
result,
|
|
89
|
+
additions: applied.additions,
|
|
90
|
+
removals: applied.removals,
|
|
91
|
+
files: applied.files,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function registerCodexProcessTools(context) {
|
|
97
|
+
const { server, config, workspaces, processSessions } = context;
|
|
98
|
+
server.registerTool("exec_command", {
|
|
99
|
+
title: "Execute command",
|
|
100
|
+
description: "Run a command with the local user's authority. Commands are not sandboxed; workspace validation only selects the initial working directory. Returns the result when it exits during the yield window, otherwise returns a sessionId for write_stdin. Use this for file inspection, tests, builds, package scripts, and long-running processes.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
workspaceId: z.string().describe(workspaceIdDescription),
|
|
103
|
+
cmd: z.string().min(1).describe("Shell command to execute."),
|
|
104
|
+
tty: z
|
|
105
|
+
.boolean()
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("Allocate a pseudo-terminal for interactive commands. Defaults to false."),
|
|
108
|
+
columns: z
|
|
109
|
+
.number()
|
|
110
|
+
.int()
|
|
111
|
+
.min(1)
|
|
112
|
+
.max(1_000)
|
|
113
|
+
.optional()
|
|
114
|
+
.describe("Initial PTY width. Defaults to 80."),
|
|
115
|
+
rows: z
|
|
116
|
+
.number()
|
|
117
|
+
.int()
|
|
118
|
+
.min(1)
|
|
119
|
+
.max(1_000)
|
|
120
|
+
.optional()
|
|
121
|
+
.describe("Initial PTY height. Defaults to 24."),
|
|
122
|
+
workingDirectory: z
|
|
123
|
+
.string()
|
|
124
|
+
.optional()
|
|
125
|
+
.describe("Working directory relative to the workspace root. Defaults to the workspace root."),
|
|
126
|
+
yieldTimeMs: z
|
|
127
|
+
.number()
|
|
128
|
+
.int()
|
|
129
|
+
.min(0)
|
|
130
|
+
.max(30_000)
|
|
131
|
+
.optional()
|
|
132
|
+
.describe("Milliseconds to wait before returning a running session. Defaults to 10000."),
|
|
133
|
+
maxOutputTokens: z
|
|
134
|
+
.number()
|
|
135
|
+
.int()
|
|
136
|
+
.positive()
|
|
137
|
+
.max(100_000)
|
|
138
|
+
.optional()
|
|
139
|
+
.describe("Approximate output token budget. Defaults to 10000."),
|
|
140
|
+
approvedByUser: z
|
|
141
|
+
.boolean()
|
|
142
|
+
.optional()
|
|
143
|
+
.describe("Set to true only after the user explicitly approved this exact command in the conversation. Required for tier-2 commands (network, installs, recursive deletes, pushes) unless the workspace runs in autonomous mode."),
|
|
144
|
+
},
|
|
145
|
+
outputSchema: processOutputSchema(),
|
|
146
|
+
annotations: SHELL_TOOL_ANNOTATIONS,
|
|
147
|
+
}, async ({ workspaceId, cmd, tty, columns, rows, workingDirectory, yieldTimeMs, maxOutputTokens, approvedByUser, }) => {
|
|
148
|
+
const startedAt = performance.now();
|
|
149
|
+
const workspace = workspaces.getWorkspace(workspaceId);
|
|
150
|
+
const verdict = enforceShellPolicy(config, { tool: "exec_command", workspaceId, command: cmd, workspaceRoot: workspace.root }, approvedByUser);
|
|
151
|
+
if (verdict.denial) {
|
|
152
|
+
logEvent(config.logging, "info", "tool_call", {
|
|
153
|
+
tool: "exec_command",
|
|
154
|
+
workspaceId,
|
|
155
|
+
success: false,
|
|
156
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
157
|
+
error: "policy_denied",
|
|
158
|
+
});
|
|
159
|
+
return verdict.denial;
|
|
160
|
+
}
|
|
161
|
+
const sandbox = sandboxDecision(config, verdict.classification.tier, workspace.root);
|
|
162
|
+
if (sandbox.denialReason) {
|
|
163
|
+
return {
|
|
164
|
+
content: [textBlock(sandbox.denialReason)],
|
|
165
|
+
isError: true,
|
|
166
|
+
structuredContent: { result: sandbox.denialReason },
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const snapshot = await runLoggedToolOperation(config, {
|
|
170
|
+
tool: "exec_command",
|
|
171
|
+
workspaceId,
|
|
172
|
+
workingDirectory: workingDirectory ?? ".",
|
|
173
|
+
command: cmd,
|
|
174
|
+
commandLength: cmd.length,
|
|
175
|
+
}, startedAt, async () => {
|
|
176
|
+
const workspace = workspaces.getWorkspace(workspaceId);
|
|
177
|
+
await snapshotBeforeRiskyExecution(config, workspace, cmd);
|
|
178
|
+
const cwd = workspaces.resolveWorkingDirectory(workspace, workingDirectory);
|
|
179
|
+
return processSessions.start({
|
|
180
|
+
workspaceId,
|
|
181
|
+
command: cmd,
|
|
182
|
+
cwd,
|
|
183
|
+
workspaceRoot: workspace.root,
|
|
184
|
+
sandbox: sandbox.enabled,
|
|
185
|
+
tty,
|
|
186
|
+
columns,
|
|
187
|
+
rows,
|
|
188
|
+
yieldTimeMs,
|
|
189
|
+
maxOutputTokens,
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
return processToolResponse(snapshot);
|
|
193
|
+
});
|
|
194
|
+
server.registerTool("write_stdin", {
|
|
195
|
+
title: "Write to process",
|
|
196
|
+
description: "Poll or write characters to a process returned by exec_command. Omit chars or pass an empty string to poll. Pass \\u0003 to send Ctrl-C.",
|
|
197
|
+
inputSchema: {
|
|
198
|
+
workspaceId: z
|
|
199
|
+
.string()
|
|
200
|
+
.describe("Workspace identifier used to start the process."),
|
|
201
|
+
sessionId: z
|
|
202
|
+
.number()
|
|
203
|
+
.describe("Process session identifier returned by exec_command."),
|
|
204
|
+
chars: z
|
|
205
|
+
.string()
|
|
206
|
+
.optional()
|
|
207
|
+
.describe("Characters to write. Omit or pass an empty string to poll."),
|
|
208
|
+
columns: z
|
|
209
|
+
.number()
|
|
210
|
+
.int()
|
|
211
|
+
.min(1)
|
|
212
|
+
.max(1_000)
|
|
213
|
+
.optional()
|
|
214
|
+
.describe("Resize a PTY to this width."),
|
|
215
|
+
rows: z
|
|
216
|
+
.number()
|
|
217
|
+
.int()
|
|
218
|
+
.min(1)
|
|
219
|
+
.max(1_000)
|
|
220
|
+
.optional()
|
|
221
|
+
.describe("Resize a PTY to this height."),
|
|
222
|
+
yieldTimeMs: z
|
|
223
|
+
.number()
|
|
224
|
+
.int()
|
|
225
|
+
.min(0)
|
|
226
|
+
.max(30_000)
|
|
227
|
+
.optional()
|
|
228
|
+
.describe("Milliseconds to wait for process output or completion. Defaults to 10000."),
|
|
229
|
+
maxOutputTokens: z
|
|
230
|
+
.number()
|
|
231
|
+
.int()
|
|
232
|
+
.positive()
|
|
233
|
+
.max(100_000)
|
|
234
|
+
.optional()
|
|
235
|
+
.describe("Approximate output token budget. Defaults to 10000."),
|
|
236
|
+
},
|
|
237
|
+
outputSchema: processOutputSchema(),
|
|
238
|
+
annotations: SHELL_TOOL_ANNOTATIONS,
|
|
239
|
+
}, async ({ workspaceId, sessionId, chars, columns, rows, yieldTimeMs, maxOutputTokens, }) => {
|
|
240
|
+
const startedAt = performance.now();
|
|
241
|
+
const snapshot = await runLoggedToolOperation(config, { tool: "write_stdin", workspaceId }, startedAt, async () => {
|
|
242
|
+
workspaces.getWorkspace(workspaceId);
|
|
243
|
+
return processSessions.write({
|
|
244
|
+
workspaceId,
|
|
245
|
+
sessionId,
|
|
246
|
+
chars,
|
|
247
|
+
columns,
|
|
248
|
+
rows,
|
|
249
|
+
yieldTimeMs,
|
|
250
|
+
maxOutputTokens,
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
return processToolResponse(snapshot);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { codexInstructions, registerCodexTools } from "./codex.js";
|
|
2
|
+
import { claudeInstructions, registerClaudeTools } from "./claude.js";
|
|
3
|
+
const TOOL_SURFACES = {
|
|
4
|
+
claude: {
|
|
5
|
+
register: registerClaudeTools,
|
|
6
|
+
instructions: claudeInstructions,
|
|
7
|
+
},
|
|
8
|
+
codex: {
|
|
9
|
+
register: registerCodexTools,
|
|
10
|
+
instructions: codexInstructions,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export function getToolSurface(mode) {
|
|
14
|
+
return TOOL_SURFACES[mode];
|
|
15
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
import { logEvent, commandPreview } from "../logger.js";
|
|
3
|
+
import { classifyCommand, decideExecution, } from "../policy/command-policy.js";
|
|
4
|
+
import { createSnapshot } from "../snapshot-manager.js";
|
|
5
|
+
import { probeSandboxAdapter } from "../policy/sandbox.js";
|
|
6
|
+
import { commandListVerdict, resolveExecutionForWorkspace, } from "../policy/workspace-profiles.js";
|
|
7
|
+
import { WORKSPACE_APP_URI, } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Policy gate for model-invoked shell commands. Every shell tool call passes
|
|
10
|
+
* through here before any process is spawned. Returns a denial response or
|
|
11
|
+
* the verdict allowing execution (with classification for audit/snapshot use).
|
|
12
|
+
*/
|
|
13
|
+
export function enforceShellPolicy(config, fields, approvedByUser) {
|
|
14
|
+
const resolved = fields.workspaceRoot
|
|
15
|
+
? resolveExecutionForWorkspace(config, fields.workspaceRoot)
|
|
16
|
+
: globalExecution(config);
|
|
17
|
+
const classification = classifyCommand(fields.command);
|
|
18
|
+
// Workspace allow/deny command lists run before the tier engine: an
|
|
19
|
+
// explicit deny is final; an allow list restricts to matching commands.
|
|
20
|
+
const listVerdict = commandListVerdict(resolved, fields.command);
|
|
21
|
+
if (!listVerdict.allowed) {
|
|
22
|
+
const reason = `Blocked by workspace policy: ${listVerdict.rule}. Ask the workspace owner to adjust this workspace's profile.`;
|
|
23
|
+
logEvent(config.logging, "warn", "policy_decision", {
|
|
24
|
+
tool: fields.tool,
|
|
25
|
+
workspaceId: fields.workspaceId,
|
|
26
|
+
tier: classification.tier,
|
|
27
|
+
decision: "deny",
|
|
28
|
+
mode: resolved.mode,
|
|
29
|
+
rule: listVerdict.rule,
|
|
30
|
+
commandPreview: commandPreview(fields.command),
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
classification,
|
|
34
|
+
decision: { decision: "deny", reason },
|
|
35
|
+
denial: {
|
|
36
|
+
content: [{ type: "text", text: reason }],
|
|
37
|
+
isError: true,
|
|
38
|
+
structuredContent: { result: reason },
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const decision = decideExecution({
|
|
43
|
+
mode: resolved.mode,
|
|
44
|
+
tier: classification.tier,
|
|
45
|
+
approvedByUser,
|
|
46
|
+
});
|
|
47
|
+
logEvent(config.logging, decision.decision === "allow" ? "info" : "warn", "policy_decision", {
|
|
48
|
+
tool: fields.tool,
|
|
49
|
+
workspaceId: fields.workspaceId,
|
|
50
|
+
tier: classification.tier,
|
|
51
|
+
rules: classification.rules,
|
|
52
|
+
decision: decision.decision,
|
|
53
|
+
mode: resolved.mode,
|
|
54
|
+
workspaceProfile: resolved.profilePath,
|
|
55
|
+
approvalClaimed: decision.approvalClaimed ?? (approvedByUser === true && classification.tier >= 2),
|
|
56
|
+
commandPreview: commandPreview(fields.command),
|
|
57
|
+
});
|
|
58
|
+
if (decision.decision === "allow") {
|
|
59
|
+
return { classification, decision };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
classification,
|
|
63
|
+
decision,
|
|
64
|
+
denial: {
|
|
65
|
+
content: [{ type: "text", text: decision.reason }],
|
|
66
|
+
isError: true,
|
|
67
|
+
// Structured content must match the tool's declared output schema
|
|
68
|
+
// (resultOutputSchema); tier/rule details live in the audit log.
|
|
69
|
+
structuredContent: {
|
|
70
|
+
result: decision.reason,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Best-effort snapshot before autonomous tier-2 execution. Best-effort by
|
|
77
|
+
* decision (ADR-006a): a non-Git workspace or a snapshot failure logs a
|
|
78
|
+
* warning and continues, because blocking every autonomous command on
|
|
79
|
+
* snapshot availability would make the mode unusable outside git repos.
|
|
80
|
+
*/
|
|
81
|
+
export async function snapshotBeforeRiskyExecution(config, workspace, command) {
|
|
82
|
+
if (config.execution.mode !== "autonomous")
|
|
83
|
+
return;
|
|
84
|
+
if (classifyCommand(command).tier < 2)
|
|
85
|
+
return;
|
|
86
|
+
try {
|
|
87
|
+
const snapshot = await createSnapshot({
|
|
88
|
+
root: workspace.root,
|
|
89
|
+
workspaceId: workspace.id,
|
|
90
|
+
label: `pre-tier2 ${commandPreview(command)}`,
|
|
91
|
+
});
|
|
92
|
+
logEvent(config.logging, "info", "snapshot_created", {
|
|
93
|
+
workspaceId: workspace.id,
|
|
94
|
+
snapshotId: snapshot.snapshotId,
|
|
95
|
+
reason: "autonomous_tier2",
|
|
96
|
+
commandPreview: commandPreview(command),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logEvent(config.logging, "warn", "snapshot_failed", {
|
|
101
|
+
workspaceId: workspace.id,
|
|
102
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
103
|
+
commandPreview: commandPreview(command),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function resultOutputSchema(extra = {}) {
|
|
108
|
+
return {
|
|
109
|
+
result: z
|
|
110
|
+
.string()
|
|
111
|
+
.describe("Model-readable result text for follow-up reasoning and plain MCP hosts."),
|
|
112
|
+
...extra,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export function workspaceAppDescriptorMeta(config) {
|
|
116
|
+
if (!config.uiEnabled)
|
|
117
|
+
return { _meta: {} };
|
|
118
|
+
return {
|
|
119
|
+
_meta: {
|
|
120
|
+
ui: {
|
|
121
|
+
resourceUri: WORKSPACE_APP_URI,
|
|
122
|
+
visibility: ["model"],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export function logToolCall(config, fields) {
|
|
128
|
+
if (!config.logging.toolCalls)
|
|
129
|
+
return;
|
|
130
|
+
const { command, ...safeFields } = fields;
|
|
131
|
+
logEvent(config.logging, fields.success ? "info" : "warn", "tool_call", {
|
|
132
|
+
...safeFields,
|
|
133
|
+
commandPreview: config.logging.shellCommands && command
|
|
134
|
+
? commandPreview(command)
|
|
135
|
+
: undefined,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
export async function runLoggedToolOperation(config, fields, startedAt, operation) {
|
|
139
|
+
try {
|
|
140
|
+
const result = await operation();
|
|
141
|
+
logToolCall(config, {
|
|
142
|
+
...fields,
|
|
143
|
+
success: true,
|
|
144
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
145
|
+
});
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
logToolCall(config, {
|
|
150
|
+
...fields,
|
|
151
|
+
success: false,
|
|
152
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
153
|
+
error: error instanceof Error ? error.message : String(error),
|
|
154
|
+
});
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function contentText(content) {
|
|
159
|
+
return content
|
|
160
|
+
.filter((item) => item.type === "text")
|
|
161
|
+
.map((item) => item.text)
|
|
162
|
+
.join("\n");
|
|
163
|
+
}
|
|
164
|
+
function toolErrorPreview(content) {
|
|
165
|
+
const text = contentText(content).replace(/\s+/g, " ").trim();
|
|
166
|
+
if (!text)
|
|
167
|
+
return undefined;
|
|
168
|
+
return text.length > 240 ? `${text.slice(0, 237)}...` : text;
|
|
169
|
+
}
|
|
170
|
+
export function logFailedToolResponse(config, fields, content, startedAt) {
|
|
171
|
+
logToolCall(config, {
|
|
172
|
+
...fields,
|
|
173
|
+
success: false,
|
|
174
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
175
|
+
error: toolErrorPreview(content),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
export function textBlock(text) {
|
|
179
|
+
return { type: "text", text };
|
|
180
|
+
}
|
|
181
|
+
export function countDiffStats(diff) {
|
|
182
|
+
if (!diff)
|
|
183
|
+
return { additions: 0, removals: 0 };
|
|
184
|
+
let additions = 0;
|
|
185
|
+
let removals = 0;
|
|
186
|
+
for (const line of diff.split("\n")) {
|
|
187
|
+
if (line.startsWith("+") && !line.startsWith("+++"))
|
|
188
|
+
additions++;
|
|
189
|
+
if (line.startsWith("-") && !line.startsWith("---"))
|
|
190
|
+
removals++;
|
|
191
|
+
}
|
|
192
|
+
return { additions, removals };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Sandbox decision for one command. "auto" sandboxes autonomous-mode
|
|
196
|
+
* executions when an adapter is available; requireSandboxForAutonomous
|
|
197
|
+
* hard-gates tier-2 commands on sandbox availability.
|
|
198
|
+
*/
|
|
199
|
+
export function sandboxDecision(config, tier, workspaceRoot) {
|
|
200
|
+
const resolved = workspaceRoot
|
|
201
|
+
? resolveExecutionForWorkspace(config, workspaceRoot)
|
|
202
|
+
: globalExecution(config);
|
|
203
|
+
const sandboxSetting = resolved.sandbox ?? config.execution.sandbox;
|
|
204
|
+
if (sandboxSetting === "none")
|
|
205
|
+
return { enabled: false };
|
|
206
|
+
const available = probeSandboxAdapter() !== "none";
|
|
207
|
+
const autonomous = resolved.mode === "autonomous";
|
|
208
|
+
if (autonomous && tier >= 2 && !available && resolved.requireSandboxForAutonomous) {
|
|
209
|
+
return {
|
|
210
|
+
enabled: false,
|
|
211
|
+
denialReason: "Autonomous tier-2 commands require an OS sandbox, but none is available on this machine. " +
|
|
212
|
+
"Install bubblewrap (Linux), set execution.sandbox to 'none' explicitly, or set " +
|
|
213
|
+
"execution.requireSandboxForAutonomous to false.",
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return { enabled: autonomous && available };
|
|
217
|
+
}
|
|
218
|
+
function globalExecution(config) {
|
|
219
|
+
return {
|
|
220
|
+
mode: config.execution.mode,
|
|
221
|
+
sandbox: undefined,
|
|
222
|
+
sandboxNetwork: undefined,
|
|
223
|
+
requireSandboxForAutonomous: config.execution.requireSandboxForAutonomous,
|
|
224
|
+
commandAllow: [],
|
|
225
|
+
commandDeny: [],
|
|
226
|
+
agentsAllowed: true,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const WORKSPACE_APP_URI = "ui://hearth/workspace-app.html";
|
|
2
|
+
export const toolNames = {
|
|
3
|
+
openWorkspace: "open_workspace",
|
|
4
|
+
read: "read",
|
|
5
|
+
write: "write",
|
|
6
|
+
edit: "edit",
|
|
7
|
+
shell: "bash",
|
|
8
|
+
};
|
|
9
|
+
export const workspaceIdDescription = "Workspace to use. Reuse the current project's workspaceId.";
|
|
10
|
+
export const WRITE_TOOL_ANNOTATIONS = {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: true,
|
|
13
|
+
idempotentHint: false,
|
|
14
|
+
openWorldHint: false,
|
|
15
|
+
};
|
|
16
|
+
export const EDIT_TOOL_ANNOTATIONS = {
|
|
17
|
+
readOnlyHint: false,
|
|
18
|
+
destructiveHint: true,
|
|
19
|
+
idempotentHint: false,
|
|
20
|
+
openWorldHint: false,
|
|
21
|
+
};
|
|
22
|
+
export const SHELL_TOOL_ANNOTATIONS = {
|
|
23
|
+
readOnlyHint: false,
|
|
24
|
+
destructiveHint: true,
|
|
25
|
+
idempotentHint: false,
|
|
26
|
+
openWorldHint: true,
|
|
27
|
+
};
|