@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.
Files changed (436) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +323 -0
  3. package/bin/hearth-agentd.js +4 -0
  4. package/bin/hearth.js +4 -0
  5. package/bin/run-entrypoint.js +20 -0
  6. package/dist/agent-tools.js +738 -0
  7. package/dist/app-version.js +16 -0
  8. package/dist/apply-patch.js +402 -0
  9. package/dist/artifact-error.js +8 -0
  10. package/dist/artifact-tools.js +377 -0
  11. package/dist/cli-workspace.js +36 -0
  12. package/dist/cli.js +1086 -0
  13. package/dist/config-migration.js +82 -0
  14. package/dist/config-schema.js +136 -0
  15. package/dist/config.js +115 -0
  16. package/dist/context/context-tools.js +150 -0
  17. package/dist/context/repo-map.js +102 -0
  18. package/dist/dashboard/app.js +226 -0
  19. package/dist/dashboard/index.html +45 -0
  20. package/dist/dashboard/landing.html +57 -0
  21. package/dist/dashboard/styles.css +23 -0
  22. package/dist/dashboard.js +271 -0
  23. package/dist/db/client.js +29 -0
  24. package/dist/db/migrations.js +262 -0
  25. package/dist/db/schema.js +85 -0
  26. package/dist/device-tokens.js +61 -0
  27. package/dist/git-worktrees.js +134 -0
  28. package/dist/git.js +41 -0
  29. package/dist/incoming-artifacts.js +378 -0
  30. package/dist/local-agent-acp.js +768 -0
  31. package/dist/local-agent-adapters.js +20 -0
  32. package/dist/local-agent-availability.js +92 -0
  33. package/dist/local-agent-catalog.js +51 -0
  34. package/dist/local-agent-claude.js +334 -0
  35. package/dist/local-agent-client.js +519 -0
  36. package/dist/local-agent-codex.js +532 -0
  37. package/dist/local-agent-config.js +34 -0
  38. package/dist/local-agent-daemon-lifecycle.js +195 -0
  39. package/dist/local-agent-daemon-main.js +86 -0
  40. package/dist/local-agent-daemon-protocol.js +302 -0
  41. package/dist/local-agent-daemon.js +407 -0
  42. package/dist/local-agent-errors.js +378 -0
  43. package/dist/local-agent-grok.js +202 -0
  44. package/dist/local-agent-manager.js +715 -0
  45. package/dist/local-agent-opencode.js +463 -0
  46. package/dist/local-agent-path.js +24 -0
  47. package/dist/local-agent-pi-sandbox.js +472 -0
  48. package/dist/local-agent-pi.js +298 -0
  49. package/dist/local-agent-presentation.js +104 -0
  50. package/dist/local-agent-profiles.js +127 -0
  51. package/dist/local-agent-runtime-pool.js +481 -0
  52. package/dist/local-agent-runtime.js +1 -0
  53. package/dist/local-agent-store.js +193 -0
  54. package/dist/local-agent-targets.js +97 -0
  55. package/dist/logger.js +97 -0
  56. package/dist/machine-id.js +35 -0
  57. package/dist/mcp-modern-server.js +65 -0
  58. package/dist/oauth-provider.js +331 -0
  59. package/dist/oauth-store.js +144 -0
  60. package/dist/onboarding.js +35 -0
  61. package/dist/orchestration/brief.js +70 -0
  62. package/dist/orchestration/lanes.js +145 -0
  63. package/dist/orchestration/result.js +46 -0
  64. package/dist/orchestration/scope.js +61 -0
  65. package/dist/pi-tools.js +58 -0
  66. package/dist/policy/command-policy.js +104 -0
  67. package/dist/policy/env-allowlist.js +96 -0
  68. package/dist/policy/sandbox.js +68 -0
  69. package/dist/policy/workspace-profiles.js +47 -0
  70. package/dist/process-journal.js +116 -0
  71. package/dist/process-platform.js +49 -0
  72. package/dist/process-sessions.js +388 -0
  73. package/dist/rate-limit.js +77 -0
  74. package/dist/request-meta.js +9 -0
  75. package/dist/review-checkpoints.js +349 -0
  76. package/dist/roots.js +37 -0
  77. package/dist/server-shutdown.js +12 -0
  78. package/dist/server.js +980 -0
  79. package/dist/skills.js +84 -0
  80. package/dist/snapshot-manager.js +123 -0
  81. package/dist/stdio-server.js +80 -0
  82. package/dist/task-store.js +203 -0
  83. package/dist/task-tools.js +455 -0
  84. package/dist/tool-surfaces/claude.js +220 -0
  85. package/dist/tool-surfaces/codex.js +255 -0
  86. package/dist/tool-surfaces/index.js +15 -0
  87. package/dist/tool-surfaces/shared.js +228 -0
  88. package/dist/tool-surfaces/types.js +27 -0
  89. package/dist/ui/.vite/manifest.json +2544 -0
  90. package/dist/ui/assets/abap-CLvhMVsD.js +1 -0
  91. package/dist/ui/assets/actionscript-3--17pq3dv.js +1 -0
  92. package/dist/ui/assets/ada-C5qYipkI.js +1 -0
  93. package/dist/ui/assets/andromeeda-vGVdxbeo.js +1 -0
  94. package/dist/ui/assets/angular-html-DrbO3_Xe.js +1 -0
  95. package/dist/ui/assets/angular-ts-CmTVzHJx.js +1 -0
  96. package/dist/ui/assets/apache-U0d_L8uA.js +1 -0
  97. package/dist/ui/assets/apex-CGTLDQj6.js +1 -0
  98. package/dist/ui/assets/apl-BOpCpqXf.js +1 -0
  99. package/dist/ui/assets/applescript-CCn79oCD.js +1 -0
  100. package/dist/ui/assets/ara-4CJ0cIlV.js +1 -0
  101. package/dist/ui/assets/asciidoc-DE70LPWp.js +1 -0
  102. package/dist/ui/assets/asm-Cmm7eHzH.js +1 -0
  103. package/dist/ui/assets/astro-CxPeBwei.js +1 -0
  104. package/dist/ui/assets/aurora-x-CDeNXAV0.js +1 -0
  105. package/dist/ui/assets/awk-BWXHIvNe.js +1 -0
  106. package/dist/ui/assets/ayu-dark-DluEY0Gj.js +1 -0
  107. package/dist/ui/assets/ayu-light-C3h-C4tm.js +1 -0
  108. package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +1 -0
  109. package/dist/ui/assets/ballerina-B7ZEbQpA.js +1 -0
  110. package/dist/ui/assets/bat-Bo4NYOV-.js +1 -0
  111. package/dist/ui/assets/beancount-D-usSTwE.js +1 -0
  112. package/dist/ui/assets/berry-DKpUyyne.js +1 -0
  113. package/dist/ui/assets/bibtex-Ci_nEsc7.js +1 -0
  114. package/dist/ui/assets/bicep-CUHmPFLl.js +1 -0
  115. package/dist/ui/assets/bird2-C2hNVINV.js +1 -0
  116. package/dist/ui/assets/blade-DtsAAG4P.js +1 -0
  117. package/dist/ui/assets/bsl-BkkzgIyY.js +1 -0
  118. package/dist/ui/assets/c-D9hLjNUM.js +1 -0
  119. package/dist/ui/assets/c3-CnJL0r0V.js +1 -0
  120. package/dist/ui/assets/cadence-CQ2zXKGN.js +1 -0
  121. package/dist/ui/assets/cairo-DLTphjLi.js +1 -0
  122. package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
  123. package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
  124. package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
  125. package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
  126. package/dist/ui/assets/clarity-SemFz856.js +1 -0
  127. package/dist/ui/assets/clojure-DqKBuwfJ.js +1 -0
  128. package/dist/ui/assets/cmake-Bj61d0ZC.js +1 -0
  129. package/dist/ui/assets/cobol-C1SWlvZm.js +1 -0
  130. package/dist/ui/assets/codeowners-C8r90Shi.js +1 -0
  131. package/dist/ui/assets/codeql-oeQT6MSM.js +1 -0
  132. package/dist/ui/assets/coffee-B71R3v2U.js +1 -0
  133. package/dist/ui/assets/common-lisp-Cv5bFMCO.js +1 -0
  134. package/dist/ui/assets/coq-BrsZFFmf.js +1 -0
  135. package/dist/ui/assets/cpp--5a4c3v4.js +1 -0
  136. package/dist/ui/assets/crystal-AtqWYtE0.js +1 -0
  137. package/dist/ui/assets/csharp-Ct8U2NOr.js +1 -0
  138. package/dist/ui/assets/css-CbqKSHI-.js +1 -0
  139. package/dist/ui/assets/csv-Dx-8-gkx.js +1 -0
  140. package/dist/ui/assets/cue-CE9AQfxI.js +1 -0
  141. package/dist/ui/assets/cypher-ClKdZ_lG.js +1 -0
  142. package/dist/ui/assets/d-qD-0Kul2.js +1 -0
  143. package/dist/ui/assets/dark-plus-Cs2F2srj.js +1 -0
  144. package/dist/ui/assets/dart-DkHntEIa.js +1 -0
  145. package/dist/ui/assets/dax-BkyTk9wS.js +1 -0
  146. package/dist/ui/assets/desktop-Dlh5hvp9.js +1 -0
  147. package/dist/ui/assets/diff-woXpYk--.js +1 -0
  148. package/dist/ui/assets/docker-IyjqRm3v.js +1 -0
  149. package/dist/ui/assets/dotenv-_5a1GRtc.js +1 -0
  150. package/dist/ui/assets/dracula-BHWKrbxM.js +1 -0
  151. package/dist/ui/assets/dracula-soft-5eyTD99u.js +1 -0
  152. package/dist/ui/assets/dream-maker-DW3nJb8Q.js +1 -0
  153. package/dist/ui/assets/edge-BPwY_RrJ.js +1 -0
  154. package/dist/ui/assets/elixir-DVH2yLJf.js +1 -0
  155. package/dist/ui/assets/elm-BrleA6gS.js +1 -0
  156. package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +1 -0
  157. package/dist/ui/assets/erb-2SHiYe30.js +1 -0
  158. package/dist/ui/assets/erlang-Cphh6RMH.js +1 -0
  159. package/dist/ui/assets/everforest-dark-sB-x3p7T.js +1 -0
  160. package/dist/ui/assets/everforest-light-Df2xbC6M.js +1 -0
  161. package/dist/ui/assets/fennel-DQxkIbk2.js +1 -0
  162. package/dist/ui/assets/fish-BJitypiv.js +1 -0
  163. package/dist/ui/assets/fluent-C03EYrpw.js +1 -0
  164. package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
  165. package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +1 -0
  166. package/dist/ui/assets/fsharp-D13ZGOAj.js +1 -0
  167. package/dist/ui/assets/gdresource-C0sCabJj.js +1 -0
  168. package/dist/ui/assets/gdscript-Cp2uCuqX.js +1 -0
  169. package/dist/ui/assets/gdshader-CBce3t8t.js +1 -0
  170. package/dist/ui/assets/genie-CV2tkWYe.js +1 -0
  171. package/dist/ui/assets/gherkin-DExj1W_8.js +1 -0
  172. package/dist/ui/assets/git-commit-BSykSTBG.js +1 -0
  173. package/dist/ui/assets/git-rebase-Bc7atMaV.js +1 -0
  174. package/dist/ui/assets/github-dark-C-LZuMrd.js +1 -0
  175. package/dist/ui/assets/github-dark-default-DXG-b-1a.js +1 -0
  176. package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
  177. package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
  178. package/dist/ui/assets/github-light-EUqPIrTm.js +1 -0
  179. package/dist/ui/assets/github-light-default-BXViO-2h.js +1 -0
  180. package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +1 -0
  181. package/dist/ui/assets/gleam-CSRkHgEL.js +1 -0
  182. package/dist/ui/assets/glimmer-js-DXeTDPtW.js +1 -0
  183. package/dist/ui/assets/glimmer-ts-CEOoXHU4.js +1 -0
  184. package/dist/ui/assets/glsl-5-43-Gsg.js +1 -0
  185. package/dist/ui/assets/gn-ilITqXS6.js +1 -0
  186. package/dist/ui/assets/gnuplot-7GGW24-e.js +1 -0
  187. package/dist/ui/assets/go-BJwz_mda.js +1 -0
  188. package/dist/ui/assets/graphql-Bk7Ah1KA.js +1 -0
  189. package/dist/ui/assets/groovy-CacY0gHj.js +1 -0
  190. package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
  191. package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
  192. package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  193. package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
  194. package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
  195. package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
  196. package/dist/ui/assets/hack-DUHz4rCJ.js +1 -0
  197. package/dist/ui/assets/haml-BPCuuTPR.js +1 -0
  198. package/dist/ui/assets/handlebars-CHxmUsnU.js +1 -0
  199. package/dist/ui/assets/haskell-D8IpX4py.js +1 -0
  200. package/dist/ui/assets/haxe-OTjmBuCE.js +1 -0
  201. package/dist/ui/assets/hcl-Dh228itO.js +1 -0
  202. package/dist/ui/assets/hjson-CxZEssPk.js +1 -0
  203. package/dist/ui/assets/hlsl-Cvrh5tZx.js +1 -0
  204. package/dist/ui/assets/horizon-CE9ld1lL.js +1 -0
  205. package/dist/ui/assets/horizon-bright-Br1oVSNq.js +1 -0
  206. package/dist/ui/assets/houston-CsvMBhTu.js +1 -0
  207. package/dist/ui/assets/html-BBJqizz0.js +1 -0
  208. package/dist/ui/assets/html-derivative-ShTPCcKN.js +1 -0
  209. package/dist/ui/assets/http-VFTyziwA.js +1 -0
  210. package/dist/ui/assets/hurl-B8yxTa4r.js +1 -0
  211. package/dist/ui/assets/hxml-B0Qn7Nwc.js +1 -0
  212. package/dist/ui/assets/hy-CZbG8q4J.js +1 -0
  213. package/dist/ui/assets/imba-DsUTQ-LC.js +1 -0
  214. package/dist/ui/assets/ini-B5eOa1yu.js +1 -0
  215. package/dist/ui/assets/java-BZ5DAgJZ.js +1 -0
  216. package/dist/ui/assets/javascript-C_zuIEaC.js +1 -0
  217. package/dist/ui/assets/jinja-DWd6xfNr.js +1 -0
  218. package/dist/ui/assets/jison-BbY63d1V.js +1 -0
  219. package/dist/ui/assets/json-C4DnajZs.js +1 -0
  220. package/dist/ui/assets/json5-BR5RXkoi.js +1 -0
  221. package/dist/ui/assets/jsonc-CYpm1nAK.js +1 -0
  222. package/dist/ui/assets/jsonl-CmCQp5Yx.js +1 -0
  223. package/dist/ui/assets/jsonnet-CJTPZ8u_.js +1 -0
  224. package/dist/ui/assets/jssm-DXw9l8Rf.js +1 -0
  225. package/dist/ui/assets/jsx-C4AACieZ.js +1 -0
  226. package/dist/ui/assets/julia-sRu7EFMW.js +1 -0
  227. package/dist/ui/assets/just-DpZ9Sx1v.js +1 -0
  228. package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
  229. package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +1 -0
  230. package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +1 -0
  231. package/dist/ui/assets/kdl-CsD5j6eV.js +1 -0
  232. package/dist/ui/assets/kotlin-DhhofPvG.js +1 -0
  233. package/dist/ui/assets/kusto-BUv0MjJC.js +1 -0
  234. package/dist/ui/assets/laserwave-C_8bwKvT.js +1 -0
  235. package/dist/ui/assets/latex-B6a_uum7.js +1 -0
  236. package/dist/ui/assets/lean-CewbzKMR.js +1 -0
  237. package/dist/ui/assets/less-DVTAwKKz.js +1 -0
  238. package/dist/ui/assets/light-plus-DVQuIRkW.js +1 -0
  239. package/dist/ui/assets/liquid-B2sVpjjr.js +1 -0
  240. package/dist/ui/assets/llvm-Cm23YOpf.js +1 -0
  241. package/dist/ui/assets/log-BNLmms1o.js +1 -0
  242. package/dist/ui/assets/logo-Cluzi2Zq.js +1 -0
  243. package/dist/ui/assets/lua-DxJJll61.js +1 -0
  244. package/dist/ui/assets/luau-CNKltnaQ.js +1 -0
  245. package/dist/ui/assets/make-Dixweg8N.js +1 -0
  246. package/dist/ui/assets/markdown-BYOwaDjH.js +1 -0
  247. package/dist/ui/assets/marko-Dx8mw-Wx.js +1 -0
  248. package/dist/ui/assets/material-theme-Bm3Qr25_.js +1 -0
  249. package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +1 -0
  250. package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +1 -0
  251. package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +1 -0
  252. package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +1 -0
  253. package/dist/ui/assets/matlab-D7qyCx1q.js +1 -0
  254. package/dist/ui/assets/mdc-vNKeXEwR.js +1 -0
  255. package/dist/ui/assets/mdx-DQZ5AkYe.js +1 -0
  256. package/dist/ui/assets/mermaid-Bk4SNUv9.js +1 -0
  257. package/dist/ui/assets/min-dark-BSWPekZh.js +1 -0
  258. package/dist/ui/assets/min-light-DDpmG2fV.js +1 -0
  259. package/dist/ui/assets/mipsasm-BMqwQI7S.js +1 -0
  260. package/dist/ui/assets/mojo-BgCJLMeH.js +1 -0
  261. package/dist/ui/assets/monokai-CdkpiU2Y.js +1 -0
  262. package/dist/ui/assets/moonbit-CaWjb8XO.js +1 -0
  263. package/dist/ui/assets/move-B1IS1UjX.js +1 -0
  264. package/dist/ui/assets/narrat-_X_XdTYD.js +1 -0
  265. package/dist/ui/assets/nextflow-Bbiyy34d.js +1 -0
  266. package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +1 -0
  267. package/dist/ui/assets/nginx-DScQAGLT.js +1 -0
  268. package/dist/ui/assets/night-owl-DhmEMT88.js +1 -0
  269. package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +1 -0
  270. package/dist/ui/assets/nim-lAJch9uT.js +1 -0
  271. package/dist/ui/assets/nix-IvuFDN5E.js +1 -0
  272. package/dist/ui/assets/nord-Cb4Vim4T.js +1 -0
  273. package/dist/ui/assets/nushell-DcLAeLz5.js +1 -0
  274. package/dist/ui/assets/objective-c-D1A_Heim.js +1 -0
  275. package/dist/ui/assets/objective-cpp-BsSzOQcm.js +1 -0
  276. package/dist/ui/assets/ocaml-O90oeIOV.js +1 -0
  277. package/dist/ui/assets/odin-B1RWQWA5.js +1 -0
  278. package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +1 -0
  279. package/dist/ui/assets/one-light-D7Lr4KcI.js +1 -0
  280. package/dist/ui/assets/openscad-BUDT5pXO.js +1 -0
  281. package/dist/ui/assets/pascal-4ZHwLPI5.js +1 -0
  282. package/dist/ui/assets/perl-C_GkVo_E.js +1 -0
  283. package/dist/ui/assets/php-DziV3K6J.js +1 -0
  284. package/dist/ui/assets/pierre-dark-CpLgRqie.js +1 -0
  285. package/dist/ui/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
  286. package/dist/ui/assets/pierre-dark-soft-kZQmAZld.js +1 -0
  287. package/dist/ui/assets/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
  288. package/dist/ui/assets/pierre-dark-vibrant-CpQYzh95.js +1 -0
  289. package/dist/ui/assets/pierre-light-CoaEpmwp.js +1 -0
  290. package/dist/ui/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
  291. package/dist/ui/assets/pierre-light-soft-lWLdNTOI.js +1 -0
  292. package/dist/ui/assets/pierre-light-tritanopia-CEbqgOJL.js +1 -0
  293. package/dist/ui/assets/pierre-light-vibrant-D80Fkn33.js +1 -0
  294. package/dist/ui/assets/pkl-ot-7Btpt.js +1 -0
  295. package/dist/ui/assets/plastic-DQwYfKfQ.js +1 -0
  296. package/dist/ui/assets/plsql-DGHpHOYJ.js +1 -0
  297. package/dist/ui/assets/po-BiJDBrnU.js +1 -0
  298. package/dist/ui/assets/poimandres-DRFjx7u4.js +1 -0
  299. package/dist/ui/assets/polar-C7UOKdEL.js +1 -0
  300. package/dist/ui/assets/postcss-BXeXVLqQ.js +1 -0
  301. package/dist/ui/assets/powerquery-DNMTfnFr.js +1 -0
  302. package/dist/ui/assets/powershell-DshXNtvi.js +1 -0
  303. package/dist/ui/assets/prisma-BsRQq5mF.js +1 -0
  304. package/dist/ui/assets/prolog-iXnhIJG7.js +1 -0
  305. package/dist/ui/assets/proto-DB4EqR-F.js +1 -0
  306. package/dist/ui/assets/pug-z75UIWVK.js +1 -0
  307. package/dist/ui/assets/puppet-CDv2pdJW.js +1 -0
  308. package/dist/ui/assets/purescript-9MfHhQsQ.js +1 -0
  309. package/dist/ui/assets/python-gzcpVVnB.js +1 -0
  310. package/dist/ui/assets/qml-Cmm4coz1.js +1 -0
  311. package/dist/ui/assets/qmldir-DCQb3MpD.js +1 -0
  312. package/dist/ui/assets/qss-Fe1Jh2GI.js +1 -0
  313. package/dist/ui/assets/r-Brd0axBE.js +1 -0
  314. package/dist/ui/assets/racket-DcIDlBhZ.js +1 -0
  315. package/dist/ui/assets/raku-B3gFvitq.js +1 -0
  316. package/dist/ui/assets/razor-DSbwmoiu.js +1 -0
  317. package/dist/ui/assets/red-CJ3rzSJv.js +1 -0
  318. package/dist/ui/assets/reg-CRGYupPL.js +1 -0
  319. package/dist/ui/assets/regexp-Bs3Uk-pY.js +1 -0
  320. package/dist/ui/assets/rel-BtDbiS_P.js +1 -0
  321. package/dist/ui/assets/review-payload-CbwCBKB1.js +1580 -0
  322. package/dist/ui/assets/riscv-Ckw8ddFX.js +1 -0
  323. package/dist/ui/assets/ron-VUp2lXgN.js +1 -0
  324. package/dist/ui/assets/rose-pine-BthvhNj6.js +1 -0
  325. package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
  326. package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +1 -0
  327. package/dist/ui/assets/rosmsg-CAekHB0j.js +1 -0
  328. package/dist/ui/assets/rst-ChIyKpUC.js +1 -0
  329. package/dist/ui/assets/ruby-BdAmvOMO.js +1 -0
  330. package/dist/ui/assets/rust-Cfkwpbl8.js +1 -0
  331. package/dist/ui/assets/sas-DpXn8hc5.js +1 -0
  332. package/dist/ui/assets/sass-DXrisJhu.js +1 -0
  333. package/dist/ui/assets/scala-DKOlJaKm.js +1 -0
  334. package/dist/ui/assets/scheme-DQCgrYNe.js +1 -0
  335. package/dist/ui/assets/scss-atX1Uuef.js +1 -0
  336. package/dist/ui/assets/sdbl-bTVj8UrX.js +1 -0
  337. package/dist/ui/assets/shaderlab-TOUzSsQk.js +1 -0
  338. package/dist/ui/assets/shellscript-BqgcAeMK.js +1 -0
  339. package/dist/ui/assets/shellsession-DfQSMRN5.js +1 -0
  340. package/dist/ui/assets/slack-dark-DnToyrRv.js +1 -0
  341. package/dist/ui/assets/slack-ochin-B2OO5cIa.js +1 -0
  342. package/dist/ui/assets/smalltalk-B16xEiuN.js +1 -0
  343. package/dist/ui/assets/snazzy-light-4G7pJPwS.js +1 -0
  344. package/dist/ui/assets/solarized-dark-DV17i1UV.js +1 -0
  345. package/dist/ui/assets/solarized-light-DSh2HLQt.js +1 -0
  346. package/dist/ui/assets/solidity-CKzVLygQ.js +1 -0
  347. package/dist/ui/assets/soy-DzP7zZTB.js +1 -0
  348. package/dist/ui/assets/sparql-D_iOobhT.js +1 -0
  349. package/dist/ui/assets/splunk-BC2Px7Mm.js +1 -0
  350. package/dist/ui/assets/sql-gmaLk66z.js +1 -0
  351. package/dist/ui/assets/ssh-config-BgfXC-Er.js +1 -0
  352. package/dist/ui/assets/stata-CJ0YTMcV.js +1 -0
  353. package/dist/ui/assets/stylus-B6D30XZt.js +1 -0
  354. package/dist/ui/assets/surrealql-LH7FciQz.js +1 -0
  355. package/dist/ui/assets/svelte-BME2PU6V.js +1 -0
  356. package/dist/ui/assets/swift-DonLKvLd.js +1 -0
  357. package/dist/ui/assets/synthwave-84-nFMaYfgc.js +1 -0
  358. package/dist/ui/assets/system-verilog-DJ5XKQeo.js +1 -0
  359. package/dist/ui/assets/systemd-BxMlprV5.js +1 -0
  360. package/dist/ui/assets/talonscript-CohzipZa.js +1 -0
  361. package/dist/ui/assets/tasl-DMoTqEGO.js +1 -0
  362. package/dist/ui/assets/tcl-CZd0xW_V.js +1 -0
  363. package/dist/ui/assets/templ-DHBNIfYW.js +1 -0
  364. package/dist/ui/assets/terraform-DswuEJGm.js +1 -0
  365. package/dist/ui/assets/tex-C8-kPEzO.js +1 -0
  366. package/dist/ui/assets/tokyo-night-oM2G3aXe.js +1 -0
  367. package/dist/ui/assets/toml-CcmNWLt0.js +1 -0
  368. package/dist/ui/assets/ts-tags-CiewV0vR.js +1 -0
  369. package/dist/ui/assets/tsv-sltzmVWM.js +1 -0
  370. package/dist/ui/assets/tsx-CUYPqmnq.js +1 -0
  371. package/dist/ui/assets/turtle-ByJddavk.js +1 -0
  372. package/dist/ui/assets/twig-BTkvsl0b.js +1 -0
  373. package/dist/ui/assets/typescript-DDQMaPwj.js +1 -0
  374. package/dist/ui/assets/typespec-B88KGewJ.js +1 -0
  375. package/dist/ui/assets/typst-DI99ib-x.js +1 -0
  376. package/dist/ui/assets/v-DETTlOr0.js +1 -0
  377. package/dist/ui/assets/vala-zf12oZj6.js +1 -0
  378. package/dist/ui/assets/vb-Djn5o6TS.js +1 -0
  379. package/dist/ui/assets/verilog-CiiDBU1e.js +1 -0
  380. package/dist/ui/assets/vesper-D5bVUKB1.js +1 -0
  381. package/dist/ui/assets/vhdl-BroJfC0k.js +1 -0
  382. package/dist/ui/assets/viml-DvXPmvsu.js +1 -0
  383. package/dist/ui/assets/vitesse-black-fwtXNY1n.js +1 -0
  384. package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +1 -0
  385. package/dist/ui/assets/vitesse-light-VbXTXTou.js +1 -0
  386. package/dist/ui/assets/vue-BH5SEWRH.js +1 -0
  387. package/dist/ui/assets/vue-html-BT7yeYez.js +1 -0
  388. package/dist/ui/assets/vue-vine-Cs5IN2rs.js +1 -0
  389. package/dist/ui/assets/vyper-CgoNMtux.js +1 -0
  390. package/dist/ui/assets/wasm-BnjxR4X6.js +1 -0
  391. package/dist/ui/assets/wasm-ByWQv1Qj.js +1 -0
  392. package/dist/ui/assets/wenyan-C8pVoKbM.js +1 -0
  393. package/dist/ui/assets/wgsl-BsKzXJz4.js +1 -0
  394. package/dist/ui/assets/wikitext-ClFFjSW2.js +1 -0
  395. package/dist/ui/assets/wit-DdvCle-K.js +1 -0
  396. package/dist/ui/assets/wolfram-DLL8P-h_.js +1 -0
  397. package/dist/ui/assets/workspace-app-B_BnSEHO.css +1 -0
  398. package/dist/ui/assets/workspace-app-DSFpnrIC.js +115 -0
  399. package/dist/ui/assets/xml-D3_1BEcO.js +1 -0
  400. package/dist/ui/assets/xsl-BBOCDn4Y.js +1 -0
  401. package/dist/ui/assets/yaml-lThBDT45.js +1 -0
  402. package/dist/ui/assets/zenscript-BnlCZFoB.js +1 -0
  403. package/dist/ui/assets/zig-CMLA9XwU.js +1 -0
  404. package/dist/ui/workspace-app.html +15 -0
  405. package/dist/user-config.js +228 -0
  406. package/dist/verification.js +74 -0
  407. package/dist/workspace-store.js +133 -0
  408. package/dist/workspaces.js +433 -0
  409. package/docs/adr/devspace-x-implementation-adrs.md +159 -0
  410. package/docs/agent-profile-schema.md +203 -0
  411. package/docs/artifact-exchange.md +44 -0
  412. package/docs/assets/devspace-logo-light.png +0 -0
  413. package/docs/assets/devspace-screenshot.png +0 -0
  414. package/docs/assets/v11-review-ui-after.png +0 -0
  415. package/docs/assets/v11-review-ui-before.png +0 -0
  416. package/docs/chatgpt-coding-workflow.md +215 -0
  417. package/docs/configuration.md +217 -0
  418. package/docs/gotchas.md +294 -0
  419. package/docs/local-agent-daemon.md +101 -0
  420. package/docs/security.md +197 -0
  421. package/docs/setup.md +174 -0
  422. package/examples/agents/claude-implementer.md +30 -0
  423. package/examples/agents/codex-explorer.md +27 -0
  424. package/examples/agents/codex-qa-tester.md +29 -0
  425. package/examples/agents/codex-worker.md +25 -0
  426. package/examples/agents/copilot-reviewer.md +25 -0
  427. package/examples/agents/cursor-agent-worker.md +26 -0
  428. package/examples/agents/grok-builder.md +10 -0
  429. package/examples/agents/opencode-explorer.md +27 -0
  430. package/examples/agents/pi-reviewer.md +27 -0
  431. package/package.json +102 -0
  432. package/schema/v1/hearth.schema.json +529 -0
  433. package/scripts/copy-dashboard.mjs +9 -0
  434. package/scripts/fix-node-pty-permissions.mjs +22 -0
  435. package/scripts/generate-config-schema.ts +9 -0
  436. package/skills/subagents/SKILL.md +57 -0
@@ -0,0 +1,768 @@
1
+ import { accessSync, constants } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { delimiter, resolve } from "node:path";
4
+ import { Readable, Writable } from "node:stream";
5
+ import { AgentProviderProtocolError, AgentProviderUnavailableError, captureAgentProviderResult, isProgrammerDefect, } from "./local-agent-errors.js";
6
+ import { terminateProcessTree } from "./process-platform.js";
7
+ import { GrokPromptCompletionRegistry, GROK_DEFAULT_MODEL, parseGrokPromptCompletion, readGrokSessionState, resolveGrokEffort, resolveGrokModelId, } from "./local-agent-grok.js";
8
+ const MAX_ACP_QUEUE_ITEMS = 10_000;
9
+ const MAX_ACP_STDERR_BYTES = 32 * 1024;
10
+ const ACP_INITIALIZE_TIMEOUT_MS = 10_000;
11
+ const ACP_GROK_PROMPT_COMPLETION_TIMEOUT_MS = 10 * 60_000;
12
+ const require = createRequire(import.meta.url);
13
+ const spawn = require("cross-spawn");
14
+ const HEARTH_VERSION = readHearthVersion();
15
+ const observeChildError = () => { };
16
+ const ACP_COMMANDS = {
17
+ cursor: ["cursor-agent", "acp"],
18
+ copilot: ["copilot", "--acp"],
19
+ grok: ["grok", "agent", "stdio"],
20
+ };
21
+ export class AcpRuntime {
22
+ outputSinks;
23
+ provider;
24
+ child;
25
+ connection;
26
+ capabilities;
27
+ queues;
28
+ liveSessions;
29
+ sessionWriteModes;
30
+ sessionMetadata;
31
+ grokCompletionRegistry;
32
+ promptCompletionTimeoutMs;
33
+ activeSessions = new Set();
34
+ promptSequence = 0;
35
+ alive = true;
36
+ closed = false;
37
+ constructor(options, connection) {
38
+ this.outputSinks = options.outputSinks ?? new Map();
39
+ this.provider = options.provider;
40
+ this.child = options.child;
41
+ this.connection = connection;
42
+ this.capabilities = options.capabilities ?? { resume: false, close: false };
43
+ this.queues = options.queues ?? new Map();
44
+ this.liveSessions = options.liveSessions ?? new Set();
45
+ this.sessionWriteModes = options.sessionWriteModes ?? new Map();
46
+ this.sessionMetadata = options.sessionMetadata ?? new Map();
47
+ this.grokCompletionRegistry = options.grokCompletionRegistry;
48
+ this.promptCompletionTimeoutMs = options.promptCompletionTimeoutMs ?? ACP_GROK_PROMPT_COMPLETION_TIMEOUT_MS;
49
+ void this.connection.closed.then(() => {
50
+ if (!this.closed)
51
+ this.alive = false;
52
+ this.grokCompletionRegistry?.rejectAll(new Error(`${this.provider} ACP connection closed.`));
53
+ }).catch(() => {
54
+ if (!this.closed)
55
+ this.alive = false;
56
+ this.grokCompletionRegistry?.rejectAll(new Error(`${this.provider} ACP connection closed.`));
57
+ });
58
+ this.child?.once("exit", () => {
59
+ this.alive = false;
60
+ this.connection.close(new Error(`${this.provider} ACP process exited.`));
61
+ });
62
+ this.child?.once("error", (error) => {
63
+ this.alive = false;
64
+ this.connection.close(error);
65
+ });
66
+ }
67
+ async run(input, callbacks) {
68
+ return captureAgentProviderResult({
69
+ provider: this.provider,
70
+ operation: "run",
71
+ run: async () => {
72
+ if (!this.isAlive()) {
73
+ throw new AgentProviderUnavailableError({
74
+ code: "PROVIDER_UNAVAILABLE",
75
+ provider: this.provider,
76
+ operation: "run",
77
+ retryable: true,
78
+ message: `${this.provider} ACP runtime is not running.`,
79
+ });
80
+ }
81
+ const sessionId = await this.openSession(input, callbacks);
82
+ if (this.activeSessions.has(sessionId)) {
83
+ throw new TypeError(`${this.provider} ACP session ${sessionId} already has an active turn.`);
84
+ }
85
+ this.activeSessions.add(sessionId);
86
+ const queue = this.queues.get(sessionId) ?? { values: [] };
87
+ this.queues.set(sessionId, queue);
88
+ const promptId = this.provider === "grok" ? this.nextPromptId() : undefined;
89
+ const completion = promptId && this.grokCompletionRegistry
90
+ ? this.grokCompletionRegistry.wait(sessionId, promptId, this.promptCompletionTimeoutMs, () => new AgentProviderProtocolError({
91
+ code: "PROVIDER_PROTOCOL_ERROR",
92
+ provider: this.provider,
93
+ operation: "run",
94
+ retryable: true,
95
+ message: "Grok ACP did not report completion for the prompt before the timeout.",
96
+ }))
97
+ : undefined;
98
+ try {
99
+ queue.values.length = 0;
100
+ if (callbacks?.onOutput)
101
+ this.outputSinks.set(sessionId, callbacks.onOutput);
102
+ const standardResponse = this.connection.agent.request("session/prompt", {
103
+ sessionId,
104
+ prompt: [{ type: "text", text: input.prompt }],
105
+ ...(promptId ? { _meta: { promptId, requestId: promptId } } : {}),
106
+ });
107
+ const response = completion
108
+ ? await Promise.race([standardResponse, completion])
109
+ : await standardResponse;
110
+ if (completion && isGrokPromptCompletion(response)) {
111
+ await yieldToAcpQueue();
112
+ }
113
+ else if (promptId) {
114
+ this.grokCompletionRegistry?.markCompleted(sessionId, promptId);
115
+ }
116
+ const updates = queue.values.splice(0);
117
+ const finalResponse = extractAcpText(updates);
118
+ if (!finalResponse) {
119
+ throw new AgentProviderProtocolError({
120
+ code: "PROVIDER_PROTOCOL_ERROR",
121
+ provider: this.provider,
122
+ operation: "run",
123
+ retryable: false,
124
+ cause: response,
125
+ message: `${this.provider} ACP did not return a final assistant response.`,
126
+ });
127
+ }
128
+ return {
129
+ provider: this.provider,
130
+ providerSessionId: sessionId,
131
+ finalResponse,
132
+ items: updates,
133
+ };
134
+ }
135
+ finally {
136
+ if (promptId)
137
+ this.grokCompletionRegistry?.remove(sessionId, promptId);
138
+ this.activeSessions.delete(sessionId);
139
+ this.outputSinks.delete(sessionId);
140
+ }
141
+ },
142
+ });
143
+ }
144
+ async releaseSession(providerSessionId) {
145
+ this.queues.delete(providerSessionId);
146
+ this.liveSessions.delete(providerSessionId);
147
+ this.sessionWriteModes.delete(providerSessionId);
148
+ this.sessionMetadata.delete(providerSessionId);
149
+ if (!this.capabilities.close || !this.isAlive())
150
+ return;
151
+ await this.connection.agent.request("session/close", { sessionId: providerSessionId });
152
+ }
153
+ isAlive() {
154
+ return this.alive && !this.closed && (!this.child || (this.child.exitCode === null && !this.child.killed));
155
+ }
156
+ async close() {
157
+ if (this.closed)
158
+ return;
159
+ this.closed = true;
160
+ this.alive = false;
161
+ this.queues.clear();
162
+ this.liveSessions.clear();
163
+ this.sessionWriteModes.clear();
164
+ this.sessionMetadata.clear();
165
+ this.activeSessions.clear();
166
+ this.grokCompletionRegistry?.rejectAll(new Error(`${this.provider} ACP runtime closed.`));
167
+ this.connection.close(new Error(`${this.provider} ACP runtime closed.`));
168
+ if (this.child && this.child.exitCode === null) {
169
+ const detached = process.platform !== "win32";
170
+ terminateProcessTree(this.child, "SIGTERM", detached);
171
+ if (!await waitForProcessExit(this.child, 1_000)) {
172
+ terminateProcessTree(this.child, "SIGKILL", detached);
173
+ }
174
+ }
175
+ }
176
+ async openSession(input, callbacks) {
177
+ if (input.providerSessionId) {
178
+ if (this.liveSessions.has(input.providerSessionId)) {
179
+ this.sessionWriteModes.set(input.providerSessionId, input.writeMode ?? "allowed");
180
+ await callbacks?.onSessionId?.(input.providerSessionId);
181
+ await this.configureSession(input.providerSessionId, input, this.sessionMetadata.get(input.providerSessionId), false);
182
+ return input.providerSessionId;
183
+ }
184
+ if (!this.capabilities.resume) {
185
+ throw new AgentProviderProtocolError({
186
+ code: "PROVIDER_PROTOCOL_ERROR",
187
+ provider: this.provider,
188
+ operation: "resume_session",
189
+ retryable: false,
190
+ message: `${this.provider} ACP does not advertise session resume support.`,
191
+ });
192
+ }
193
+ const response = await this.connection.agent.request("session/resume", {
194
+ sessionId: input.providerSessionId,
195
+ cwd: input.workspaceRoot,
196
+ mcpServers: [],
197
+ ...this.additionalDirectoryParams(),
198
+ });
199
+ this.cacheSessionMetadata(input.providerSessionId, response);
200
+ this.queues.set(input.providerSessionId, { values: [] });
201
+ this.liveSessions.add(input.providerSessionId);
202
+ this.sessionWriteModes.set(input.providerSessionId, input.writeMode ?? "allowed");
203
+ await callbacks?.onSessionId?.(input.providerSessionId);
204
+ await this.configureSession(input.providerSessionId, input, response, false);
205
+ return input.providerSessionId;
206
+ }
207
+ const response = await this.connection.agent.request("session/new", {
208
+ cwd: input.workspaceRoot,
209
+ mcpServers: [],
210
+ ...this.additionalDirectoryParams(),
211
+ });
212
+ const sessionId = readString(response, "sessionId");
213
+ if (!sessionId) {
214
+ throw new AgentProviderProtocolError({
215
+ code: "PROVIDER_PROTOCOL_ERROR",
216
+ provider: this.provider,
217
+ operation: "create_session",
218
+ retryable: false,
219
+ cause: response,
220
+ message: `${this.provider} ACP did not return a session id.`,
221
+ });
222
+ }
223
+ this.cacheSessionMetadata(sessionId, response);
224
+ this.queues.set(sessionId, { values: [] });
225
+ this.liveSessions.add(sessionId);
226
+ this.sessionWriteModes.set(sessionId, input.writeMode ?? "allowed");
227
+ await callbacks?.onSessionId?.(sessionId);
228
+ await this.configureSession(sessionId, input, response, true);
229
+ return sessionId;
230
+ }
231
+ cacheSessionMetadata(sessionId, response) {
232
+ if (hasAcpConfigOptions(response) || (this.provider === "grok" && readGrokSessionState(response))) {
233
+ this.sessionMetadata.set(sessionId, response);
234
+ }
235
+ }
236
+ async configureSession(sessionId, input, response, isNewSession = false) {
237
+ const metadata = response ?? this.sessionMetadata.get(sessionId);
238
+ if (this.provider === "grok") {
239
+ await this.configureGrokSession(sessionId, input, metadata, isNewSession);
240
+ return;
241
+ }
242
+ const canConfigure = isNewSession || hasAcpConfigOptions(metadata);
243
+ if (!canConfigure) {
244
+ const requested = [
245
+ input.model && input.modelOverrideRequested ? "model" : undefined,
246
+ input.effort && input.effortOverrideRequested ? "effort" : undefined,
247
+ ]
248
+ .filter(Boolean)
249
+ .join(" and ");
250
+ if (requested) {
251
+ throw new AgentProviderProtocolError({
252
+ code: "PROVIDER_PROTOCOL_ERROR",
253
+ provider: this.provider,
254
+ operation: "configure_session",
255
+ retryable: false,
256
+ message: `${this.provider} ACP cannot apply the requested ${requested} override because the resumed session did not advertise configurable options.`,
257
+ });
258
+ }
259
+ // A durable resumed session keeps its previously selected provider
260
+ // configuration. If resume does not re-advertise config options, do not
261
+ // force a redundant set operation for persisted model/effort values.
262
+ return;
263
+ }
264
+ if (input.model) {
265
+ const config = resolveAcpModelConfigUpdate(metadata, input.model, this.provider, sessionId);
266
+ await this.connection.agent.request("session/set_config_option", config);
267
+ }
268
+ if (input.effort) {
269
+ const config = resolveAcpEffortConfigUpdate(metadata, input.effort, this.provider, sessionId);
270
+ await this.connection.agent.request("session/set_config_option", config);
271
+ }
272
+ }
273
+ async configureGrokSession(sessionId, input, response, isNewSession) {
274
+ const state = readGrokSessionState(response);
275
+ if (!state) {
276
+ const requested = [
277
+ input.model && (isNewSession || input.modelOverrideRequested) ? "model" : undefined,
278
+ input.effort && (isNewSession || input.effortOverrideRequested) ? "effort" : undefined,
279
+ ].filter(Boolean).join(" and ");
280
+ if (requested) {
281
+ throw new AgentProviderProtocolError({
282
+ code: "PROVIDER_PROTOCOL_ERROR",
283
+ provider: this.provider,
284
+ operation: "configure_session",
285
+ retryable: false,
286
+ message: `${this.provider} ACP did not advertise typed model metadata required for the requested ${requested} override.`,
287
+ });
288
+ }
289
+ return;
290
+ }
291
+ const currentModel = state.currentModelId;
292
+ const requestedModel = input.model
293
+ ? resolveGrokModelId(input.model, state)
294
+ : currentModel ?? state.availableModels[0]?.id ?? GROK_DEFAULT_MODEL;
295
+ const effort = input.effort
296
+ ? resolveGrokEffort(input.effort, state, requestedModel)
297
+ : undefined;
298
+ const shouldSetModel = Boolean(input.model && requestedModel !== currentModel) || effort !== undefined;
299
+ if (!shouldSetModel)
300
+ return;
301
+ try {
302
+ await this.connection.agent.request("session/set_model", {
303
+ sessionId,
304
+ modelId: requestedModel,
305
+ ...(effort ? { _meta: { reasoningEffort: effort } } : {}),
306
+ });
307
+ }
308
+ catch (cause) {
309
+ throw new AgentProviderProtocolError({
310
+ code: "PROVIDER_PROTOCOL_ERROR",
311
+ provider: this.provider,
312
+ operation: "configure_session",
313
+ retryable: false,
314
+ cause,
315
+ message: `${this.provider} ACP could not select model '${requestedModel}'.`,
316
+ });
317
+ }
318
+ }
319
+ additionalDirectoryParams() {
320
+ // Hearth currently authorizes exactly one workspace root per agent turn.
321
+ // Do not advertise an empty additional-directory scope to ACP providers.
322
+ return {};
323
+ }
324
+ nextPromptId() {
325
+ this.promptSequence += 1;
326
+ return `hearth-grok-prompt-${this.promptSequence}`;
327
+ }
328
+ }
329
+ export class AcpLocalAgentDriver {
330
+ env;
331
+ commandResolver;
332
+ provider;
333
+ // Keep ACP warm briefly, then let the generic pool close the process so the
334
+ // daemon can reach its own idle shutdown state.
335
+ idleTimeoutMs = 5 * 60_000;
336
+ commandResolved = false;
337
+ resolvedCommand;
338
+ // Shared with the per-runtime output plumbing: run() registers per-session
339
+ // sinks, the long-lived session/update notification drains chunk text.
340
+ outputSinks = new Map();
341
+ constructor(provider, env = process.env, commandResolver = resolveAcpCommand) {
342
+ this.env = env;
343
+ this.commandResolver = commandResolver;
344
+ this.provider = provider;
345
+ }
346
+ runtimeKey(context) {
347
+ const command = this.resolveCommand() ?? ACP_COMMANDS[this.provider][0];
348
+ const writeMode = context.writeMode ?? "allowed";
349
+ return `acp:${this.provider}:${command}:${writeMode}:${resolve(context.workspaceRoot)}`;
350
+ }
351
+ async createRuntime(context) {
352
+ return captureAgentProviderResult({
353
+ provider: this.provider,
354
+ agentId: context.agentId,
355
+ operation: "create_runtime",
356
+ run: async () => {
357
+ const command = this.resolveCommand();
358
+ if (!command) {
359
+ throw new AgentProviderUnavailableError({
360
+ code: "PROVIDER_UNAVAILABLE",
361
+ provider: this.provider,
362
+ agentId: context.agentId,
363
+ operation: "create_runtime",
364
+ retryable: false,
365
+ message: `${this.provider} executable was not found.`,
366
+ });
367
+ }
368
+ const args = acpCommandArgs(this.provider, context, this.env);
369
+ const child = spawn(command, args, {
370
+ cwd: resolve(context.workspaceRoot),
371
+ env: this.env,
372
+ stdio: ["pipe", "pipe", "pipe"],
373
+ detached: process.platform !== "win32",
374
+ windowsHide: true,
375
+ });
376
+ let resolveStartupError;
377
+ const startupError = new Promise((resolveError) => { resolveStartupError = resolveError; });
378
+ const onStartupError = (error) => { resolveStartupError(error); };
379
+ child.once("error", onStartupError);
380
+ if (!child.stdin || !child.stdout || !child.stderr) {
381
+ child.on("error", observeChildError);
382
+ child.removeListener("error", onStartupError);
383
+ if (child.exitCode === null) {
384
+ const detached = process.platform !== "win32";
385
+ terminateProcessTree(child, "SIGTERM", detached);
386
+ if (!await waitForProcessExit(child, 1_000)) {
387
+ terminateProcessTree(child, "SIGKILL", detached);
388
+ }
389
+ }
390
+ throw new AgentProviderProtocolError({
391
+ code: "PROVIDER_PROTOCOL_ERROR",
392
+ provider: this.provider,
393
+ agentId: context.agentId,
394
+ operation: "create_runtime",
395
+ retryable: false,
396
+ message: `${this.provider} ACP process did not expose stdio pipes.`,
397
+ });
398
+ }
399
+ let connection;
400
+ child.stderr.setEncoding("utf8");
401
+ let stderrTail = "";
402
+ child.stderr.on("data", (chunk) => {
403
+ stderrTail = appendTail(stderrTail, chunk, MAX_ACP_STDERR_BYTES);
404
+ });
405
+ try {
406
+ const { client, methods, ndJsonStream } = await import("@agentclientprotocol/sdk");
407
+ const queues = new Map();
408
+ const sessionWriteModes = new Map();
409
+ const outputSinks = this.outputSinks;
410
+ const grokCompletionRegistry = this.provider === "grok"
411
+ ? new GrokPromptCompletionRegistry()
412
+ : undefined;
413
+ const app = client({ name: "Hearth" })
414
+ .onRequest(methods.client.session.requestPermission, (context) => {
415
+ const writeMode = sessionWriteModes.get(context.params.sessionId);
416
+ const selected = selectAcpPermissionOption(context.params.options, writeMode, this.provider);
417
+ return selected
418
+ ? { outcome: { outcome: "selected", optionId: selected.optionId } }
419
+ : { outcome: { outcome: "cancelled" } };
420
+ })
421
+ .onNotification(methods.client.session.update, (context) => {
422
+ const sessionId = context.params.sessionId;
423
+ const queue = queues.get(sessionId);
424
+ if (queue)
425
+ appendAcpQueueValue(queue, context.params);
426
+ const chunk = readAcpChunkText(context.params);
427
+ if (chunk)
428
+ outputSinks.get(sessionId)?.(chunk);
429
+ });
430
+ if (grokCompletionRegistry) {
431
+ for (const method of [
432
+ "x.ai/session/prompt_complete",
433
+ "_x.ai/session/prompt_complete",
434
+ "x.ai/session/update",
435
+ "_x.ai/session/update",
436
+ ]) {
437
+ app.onNotification(method, parseGrokPromptCompletion, (context) => {
438
+ if (context.params)
439
+ grokCompletionRegistry.resolve(context.params);
440
+ });
441
+ }
442
+ }
443
+ const stream = ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
444
+ connection = app.connect(stream);
445
+ const init = await withTimeout(Promise.race([
446
+ connection.agent.request(methods.agent.initialize, {
447
+ protocolVersion: 1,
448
+ clientInfo: { name: "Hearth", version: HEARTH_VERSION },
449
+ clientCapabilities: {},
450
+ }),
451
+ startupError.then((error) => { throw error; }),
452
+ ]), ACP_INITIALIZE_TIMEOUT_MS, `${this.provider} ACP initialize timed out.`);
453
+ const capabilities = readAcpCapabilities(init);
454
+ const runtime = new AcpRuntime({
455
+ provider: this.provider,
456
+ command,
457
+ args,
458
+ env: this.env,
459
+ child,
460
+ capabilities,
461
+ queues,
462
+ sessionWriteModes,
463
+ grokCompletionRegistry,
464
+ outputSinks: this.outputSinks,
465
+ }, connection);
466
+ // AcpRuntime installs the long-lived child error listener before this
467
+ // startup-only listener is removed, so there is no unobserved gap.
468
+ child.removeListener("error", onStartupError);
469
+ return runtime;
470
+ }
471
+ catch (error) {
472
+ child.on("error", observeChildError);
473
+ child.removeListener("error", onStartupError);
474
+ try {
475
+ connection?.close(error);
476
+ }
477
+ catch {
478
+ // The child still needs to be terminated if the protocol failed early.
479
+ }
480
+ if (child.exitCode === null) {
481
+ const detached = process.platform !== "win32";
482
+ terminateProcessTree(child, "SIGTERM", detached);
483
+ if (!await waitForProcessExit(child, 1_000)) {
484
+ terminateProcessTree(child, "SIGKILL", detached);
485
+ }
486
+ }
487
+ if (isProgrammerDefect(error))
488
+ throw error;
489
+ throw new AgentProviderProtocolError({
490
+ code: "PROVIDER_PROTOCOL_ERROR",
491
+ provider: this.provider,
492
+ agentId: context.agentId,
493
+ operation: "create_runtime",
494
+ retryable: true,
495
+ cause: { error, stderr: stderrTail.trim() || undefined },
496
+ message: `${this.provider} ACP initialization failed.`,
497
+ });
498
+ }
499
+ },
500
+ });
501
+ }
502
+ resolveCommand() {
503
+ if (!this.commandResolved) {
504
+ this.resolvedCommand = this.commandResolver(this.provider, this.env);
505
+ this.commandResolved = true;
506
+ }
507
+ return this.resolvedCommand;
508
+ }
509
+ }
510
+ async function waitForProcessExit(child, timeoutMs) {
511
+ if (child.exitCode !== null)
512
+ return true;
513
+ return new Promise((resolve) => {
514
+ const timer = setTimeout(() => {
515
+ child.removeListener("exit", onExit);
516
+ resolve(false);
517
+ }, timeoutMs);
518
+ timer.unref();
519
+ const onExit = () => {
520
+ clearTimeout(timer);
521
+ resolve(true);
522
+ };
523
+ child.once("exit", onExit);
524
+ });
525
+ }
526
+ export function resolveAcpCommand(provider, env = process.env) {
527
+ const configured = provider === "cursor"
528
+ ? env.CURSOR_COMMAND
529
+ : provider === "copilot"
530
+ ? env.COPILOT_COMMAND
531
+ : env.GROK_COMMAND;
532
+ const command = configured ?? ACP_COMMANDS[provider][0];
533
+ if (command.includes("/") || command.includes("\\"))
534
+ return executableExists(command) ? command : undefined;
535
+ const path = env.PATH;
536
+ if (!path)
537
+ return undefined;
538
+ const extensions = process.platform === "win32"
539
+ ? ["", ...(env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)]
540
+ : [""];
541
+ for (const directory of path.split(delimiter)) {
542
+ if (!directory)
543
+ continue;
544
+ for (const extension of extensions) {
545
+ const candidate = resolve(directory, `${command}${extension}`);
546
+ if (executableExists(candidate))
547
+ return candidate;
548
+ }
549
+ }
550
+ return undefined;
551
+ }
552
+ export function acpCommandArgs(provider, context, env = process.env) {
553
+ const writeMode = context.writeMode ?? "allowed";
554
+ if (provider === "cursor") {
555
+ return [
556
+ "acp",
557
+ "--sandbox", writeMode === "full_access" ? "disabled" : "enabled",
558
+ "--workspace", resolve(context.workspaceRoot),
559
+ ...(writeMode === "read_only" ? ["--mode", "plan"] : []),
560
+ ...(writeMode === "full_access" ? ["--force"] : []),
561
+ ];
562
+ }
563
+ if (provider === "grok") {
564
+ const agentProfile = env.GROK_AGENT_PROFILE?.trim();
565
+ const effort = context.effort
566
+ ? resolveGrokEffort(context.effort, undefined, undefined)
567
+ : undefined;
568
+ return [
569
+ "agent",
570
+ ...(agentProfile ? ["--agent-profile", agentProfile] : []),
571
+ ...(effort ? ["--reasoning-effort", effort] : []),
572
+ "stdio",
573
+ ];
574
+ }
575
+ const sandboxArgs = writeMode === "full_access"
576
+ ? ["--no-sandbox"]
577
+ : ["--experimental", "--sandbox"];
578
+ return [
579
+ "--acp",
580
+ ...sandboxArgs,
581
+ ...(writeMode === "full_access"
582
+ ? ["--allow-all"]
583
+ : ["--allow-all-tools", "--add-dir", resolve(context.workspaceRoot)]),
584
+ "-C", resolve(context.workspaceRoot),
585
+ ...(writeMode === "read_only" ? ["--mode", "plan"] : []),
586
+ ];
587
+ }
588
+ export function resolveAcpModelConfigUpdate(session, model, provider, sessionIdOverride) {
589
+ return resolveAcpSelectConfigUpdate(session, {
590
+ category: "model",
591
+ label: "model",
592
+ provider,
593
+ value: model,
594
+ sessionIdOverride,
595
+ });
596
+ }
597
+ export function resolveAcpEffortConfigUpdate(session, effort, provider, sessionIdOverride) {
598
+ return resolveAcpSelectConfigUpdate(session, {
599
+ category: "thought_level",
600
+ label: "reasoning effort option",
601
+ provider,
602
+ value: effort,
603
+ sessionIdOverride,
604
+ });
605
+ }
606
+ function resolveAcpSelectConfigUpdate(session, options) {
607
+ const record = asRecord(session);
608
+ if (!record)
609
+ throw new Error(`${options.provider} ACP session metadata is missing.`);
610
+ const sessionId = options.sessionIdOverride ?? directString(record?.sessionId);
611
+ if (!sessionId)
612
+ throw new Error(`${options.provider} ACP session did not return a session id.`);
613
+ const response = asRecord(record?.newSessionResponse) ?? record;
614
+ const configOptions = readArray(response, "configOptions") ?? [];
615
+ const config = configOptions
616
+ .map(asRecord)
617
+ .find((option) => option?.type === "select" && option.category === options.category);
618
+ if (!config)
619
+ throw new Error(`${options.provider} ACP server does not expose a ${options.label}.`);
620
+ const configId = directString(config.id);
621
+ if (!configId)
622
+ throw new Error(`${options.provider} ACP ${options.label} is missing an id.`);
623
+ const available = flattenAcpSelectValues(config);
624
+ if (!available.includes(options.value)) {
625
+ const suffix = available.length > 0 ? ` Available values: ${available.join(", ")}.` : "";
626
+ throw new Error(`${options.provider} ACP ${options.label} does not support '${options.value}'.${suffix}`);
627
+ }
628
+ return { sessionId, configId, value: options.value };
629
+ }
630
+ export function flattenAcpSelectValues(option) {
631
+ const values = [];
632
+ for (const item of readArray(option, "options") ?? []) {
633
+ const record = asRecord(item);
634
+ const value = directString(record?.value);
635
+ if (value) {
636
+ values.push(value);
637
+ continue;
638
+ }
639
+ for (const nested of readArray(record, "options") ?? []) {
640
+ const nestedValue = directString(asRecord(nested)?.value);
641
+ if (nestedValue)
642
+ values.push(nestedValue);
643
+ }
644
+ }
645
+ return values;
646
+ }
647
+ export function selectAcpAllowPermissionOption(options) {
648
+ return selectAcpPermissionOption(options, "allowed");
649
+ }
650
+ export function selectAcpPermissionOption(options, writeMode, provider) {
651
+ if (!writeMode)
652
+ return undefined;
653
+ // Copilot's native sandbox has a per-command escape hatch enabled by
654
+ // default. Normal turns already pass --allow-all-tools, so any permission
655
+ // request that reaches ACP is an attempted escalation (including a
656
+ // sandbox bypass). Cancel it instead of turning an ACP approval into host
657
+ // authority. Full access deliberately keeps the provider's unrestricted
658
+ // behavior.
659
+ if (provider === "copilot" && writeMode !== "full_access")
660
+ return undefined;
661
+ const selected = writeMode === "read_only"
662
+ ? options.find((option) => option.kind === "reject_once")
663
+ ?? options.find((option) => option.kind === "reject_always")
664
+ : options.find((option) => option.kind === "allow_once")
665
+ ?? options.find((option) => option.kind === "allow_always");
666
+ return selected ? { optionId: selected.optionId } : undefined;
667
+ }
668
+ function readAcpCapabilities(value) {
669
+ const capabilities = asRecord(asRecord(value)?.agentCapabilities);
670
+ const sessions = asRecord(capabilities?.sessionCapabilities);
671
+ return {
672
+ resume: Boolean(sessions?.resume),
673
+ close: Boolean(sessions?.close),
674
+ additionalDirectories: Boolean(sessions?.additionalDirectories),
675
+ };
676
+ }
677
+ function extractAcpText(updates) {
678
+ return updates
679
+ .map((value) => {
680
+ const update = asRecord(asRecord(value)?.update);
681
+ const content = asRecord(update?.content);
682
+ return update?.sessionUpdate === "agent_message_chunk" && content?.type === "text" && typeof content.text === "string"
683
+ ? content.text
684
+ : "";
685
+ })
686
+ .join("")
687
+ .trim();
688
+ }
689
+ function isGrokPromptCompletion(value) {
690
+ const record = asRecord(value);
691
+ return typeof record?.sessionId === "string";
692
+ }
693
+ async function yieldToAcpQueue() {
694
+ await new Promise((resolve) => setImmediate(resolve));
695
+ }
696
+ function hasAcpConfigOptions(value) {
697
+ const record = asRecord(value);
698
+ const response = asRecord(record?.newSessionResponse) ?? record;
699
+ return Array.isArray(response?.configOptions);
700
+ }
701
+ function readAcpChunkText(value) {
702
+ const record = asRecord(value);
703
+ const content = asRecord(record?.content);
704
+ if (record?.sessionUpdate === "agent_message_chunk"
705
+ && content?.type === "text"
706
+ && typeof content.text === "string"
707
+ && content.text.length > 0) {
708
+ return content.text;
709
+ }
710
+ return undefined;
711
+ }
712
+ function appendAcpQueueValue(queue, value) {
713
+ if (queue.values.length >= MAX_ACP_QUEUE_ITEMS)
714
+ queue.values.shift();
715
+ queue.values.push(value);
716
+ }
717
+ function appendTail(current, chunk, maxBytes) {
718
+ const next = current + chunk;
719
+ if (Buffer.byteLength(next, "utf8") <= maxBytes)
720
+ return next;
721
+ return Buffer.from(next, "utf8").subarray(-maxBytes).toString("utf8");
722
+ }
723
+ function executableExists(command) {
724
+ try {
725
+ accessSync(command, process.platform === "win32" ? constants.F_OK : constants.X_OK);
726
+ return true;
727
+ }
728
+ catch {
729
+ return false;
730
+ }
731
+ }
732
+ async function withTimeout(promise, timeoutMs, message) {
733
+ let timer;
734
+ const timeout = new Promise((_resolve, reject) => {
735
+ timer = setTimeout(() => reject(new Error(message)), timeoutMs);
736
+ timer.unref();
737
+ });
738
+ try {
739
+ return await Promise.race([promise, timeout]);
740
+ }
741
+ finally {
742
+ if (timer)
743
+ clearTimeout(timer);
744
+ }
745
+ }
746
+ function readHearthVersion() {
747
+ const packageJson = require("../package.json");
748
+ if (typeof packageJson.version !== "string" || !packageJson.version) {
749
+ throw new Error("Unable to read Hearth package version.");
750
+ }
751
+ return packageJson.version;
752
+ }
753
+ function readArray(value, key) {
754
+ const result = asRecord(value)?.[key];
755
+ return Array.isArray(result) ? result : undefined;
756
+ }
757
+ function readString(value, key) {
758
+ const result = asRecord(value)?.[key];
759
+ return typeof result === "string" ? result : undefined;
760
+ }
761
+ function directString(value) {
762
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
763
+ }
764
+ function asRecord(value) {
765
+ return value !== null && typeof value === "object" && !Array.isArray(value)
766
+ ? value
767
+ : undefined;
768
+ }