@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
package/dist/skills.js ADDED
@@ -0,0 +1,84 @@
1
+ import { existsSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join, resolve, sep } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { loadSkills, } from "@earendil-works/pi-coding-agent";
6
+ import { expandHomePath, isPathInsideRoot } from "./roots.js";
7
+ const SUBAGENTS_SKILL_NAME = "subagents";
8
+ const SUBAGENTS_SKILL = join(SUBAGENTS_SKILL_NAME, "SKILL.md");
9
+ function bundledSkillsDir() {
10
+ return fileURLToPath(new URL("../skills", import.meta.url));
11
+ }
12
+ function hasSubagentsSkill(skillDir) {
13
+ return existsSync(join(skillDir, SUBAGENTS_SKILL));
14
+ }
15
+ export function effectiveSkillPaths(config, cwd) {
16
+ const bundledSkills = bundledSkillsDir();
17
+ const defaultPathCandidates = [
18
+ join(homedir(), ".agents", "skills"),
19
+ resolve(cwd, ".agents", "skills"),
20
+ config.hearthSkillsDir,
21
+ join(config.agentDir, "skills"),
22
+ config.subagents.enabled && !hasSubagentsSkill(config.hearthSkillsDir)
23
+ ? bundledSkills
24
+ : undefined,
25
+ ];
26
+ const defaultPaths = defaultPathCandidates.filter((path) => path !== undefined && existsSync(path));
27
+ const seen = new Set();
28
+ return [...defaultPaths, ...config.skillPaths]
29
+ .map((path) => resolveSkillPath(path, cwd))
30
+ .filter((path) => {
31
+ if (seen.has(path))
32
+ return false;
33
+ seen.add(path);
34
+ return true;
35
+ });
36
+ }
37
+ function resolveSkillPath(path, cwd) {
38
+ return resolve(cwd, expandHomePath(path));
39
+ }
40
+ export function loadWorkspaceSkills(config, cwd) {
41
+ if (!config.skillsEnabled)
42
+ return { skills: [], diagnostics: [] };
43
+ const result = loadSkills({
44
+ cwd,
45
+ agentDir: config.agentDir,
46
+ skillPaths: effectiveSkillPaths(config, cwd),
47
+ includeDefaults: false,
48
+ });
49
+ if (config.subagents.enabled)
50
+ return result;
51
+ return {
52
+ skills: result.skills.filter((skill) => skill.name !== SUBAGENTS_SKILL_NAME),
53
+ diagnostics: result.diagnostics.filter((diagnostic) => {
54
+ const collision = diagnostic.collision;
55
+ return !(collision?.resourceType === "skill" && collision.name === SUBAGENTS_SKILL_NAME);
56
+ }),
57
+ };
58
+ }
59
+ export function resolveSkillReadPath(skills, inputPath) {
60
+ const absolutePath = resolve(expandHomePath(inputPath));
61
+ for (const skill of skills) {
62
+ const skillFilePath = resolve(skill.filePath);
63
+ if (absolutePath === skillFilePath) {
64
+ return { absolutePath, skill };
65
+ }
66
+ }
67
+ for (const skill of skills) {
68
+ const baseDir = resolve(skill.baseDir);
69
+ if (!isPathInsideRoot(absolutePath, baseDir))
70
+ continue;
71
+ return { absolutePath, skill };
72
+ }
73
+ return undefined;
74
+ }
75
+ export function formatPathForPrompt(path) {
76
+ const home = resolve(homedir());
77
+ const resolvedPath = resolve(path);
78
+ if (resolvedPath === home)
79
+ return "~";
80
+ if (resolvedPath.startsWith(`${home}${sep}`)) {
81
+ return `~/${resolvedPath.slice(home.length + 1).split(sep).join("/")}`;
82
+ }
83
+ return resolvedPath.split(sep).join("/");
84
+ }
@@ -0,0 +1,123 @@
1
+ import { mkdtemp, rm } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { git, getGitEligibility, safeWorkspaceRefSegment } from "./git.js";
5
+ const SNAPSHOT_REF_PREFIX = "refs/hearth/snapshots";
6
+ const SNAPSHOT_AUTHOR_ENV_BASE = "hearth-snapshot";
7
+ export class SnapshotError extends Error {
8
+ }
9
+ export async function createSnapshot(input) {
10
+ const eligibility = await getGitEligibility(input.root);
11
+ if (!eligibility.ok || !eligibility.gitRoot) {
12
+ throw new SnapshotError(eligibility.message ?? "snapshots require a Git workspace.");
13
+ }
14
+ const gitRoot = eligibility.gitRoot;
15
+ const head = await headCommit(gitRoot);
16
+ const tempDir = await mkdtemp(join(tmpdir(), "hearth-snapshot-index-"));
17
+ try {
18
+ const env = snapshotEnv(join(tempDir, "index"));
19
+ if (head)
20
+ await git(gitRoot, ["read-tree", head], { env });
21
+ await git(gitRoot, ["add", "-A", "--", input.root], { env });
22
+ const tree = (await git(gitRoot, ["write-tree"], { env })).stdout.trim();
23
+ const parentArgs = head ? ["-p", head] : [];
24
+ const commit = (await git(gitRoot, ["commit-tree", tree, ...parentArgs, "-m", `Hearth snapshot: ${input.label}`], { env })).stdout.trim();
25
+ const createdAt = new Date().toISOString();
26
+ const ref = snapshotRef(input.workspaceId, createdAt);
27
+ await git(gitRoot, ["update-ref", ref, commit]);
28
+ return {
29
+ snapshotId: commit,
30
+ ref,
31
+ label: input.label,
32
+ createdAt,
33
+ dirtyBaseline: head ? false : true,
34
+ };
35
+ }
36
+ finally {
37
+ await rm(tempDir, { recursive: true, force: true });
38
+ }
39
+ }
40
+ export async function listSnapshots(input) {
41
+ const eligibility = await getGitEligibility(input.root);
42
+ if (!eligibility.ok || !eligibility.gitRoot)
43
+ return [];
44
+ const gitRoot = eligibility.gitRoot;
45
+ const prefix = `${SNAPSHOT_REF_PREFIX}/${safeWorkspaceRefSegment(input.workspaceId)}/`;
46
+ const refs = (await git(gitRoot, [
47
+ "for-each-ref",
48
+ "--format=%(refname)\t%(objectname)\t%(creatordate:iso-strict)",
49
+ SNAPSHOT_REF_PREFIX,
50
+ ])).stdout.trim();
51
+ if (!refs)
52
+ return [];
53
+ const records = [];
54
+ for (const line of refs.split("\n")) {
55
+ const [ref, commit, createdAt] = line.split("\t");
56
+ if (!ref?.startsWith(prefix) || !commit)
57
+ continue;
58
+ const message = (await git(gitRoot, ["log", "-1", "--format=%s", commit])).stdout.trim();
59
+ records.push({
60
+ snapshotId: commit,
61
+ ref,
62
+ label: message.replace(/^Hearth snapshot: /, ""),
63
+ createdAt: createdAt || "",
64
+ });
65
+ }
66
+ return records.sort((a, b) => b.ref.localeCompare(a.ref));
67
+ }
68
+ export async function rollbackSnapshot(input) {
69
+ const eligibility = await getGitEligibility(input.root);
70
+ if (!eligibility.ok || !eligibility.gitRoot) {
71
+ throw new SnapshotError(eligibility.message ?? "rollback requires a Git workspace.");
72
+ }
73
+ const gitRoot = eligibility.gitRoot;
74
+ const known = await listSnapshots({ root: input.root, workspaceId: input.workspaceId });
75
+ const target = known.find((record) => record.snapshotId === input.snapshotId);
76
+ if (!target) {
77
+ throw new SnapshotError(`Unknown snapshot for this workspace: ${input.snapshotId}`);
78
+ }
79
+ const targetTree = (await git(gitRoot, ["rev-parse", "--verify", `${target.snapshotId}^{tree}`])).stdout.trim();
80
+ const tempDir = await mkdtemp(join(tmpdir(), "hearth-rollback-"));
81
+ try {
82
+ const env = snapshotEnv(join(tempDir, "index"));
83
+ const head = await headCommit(gitRoot);
84
+ if (head)
85
+ await git(gitRoot, ["read-tree", head], { env });
86
+ await git(gitRoot, ["add", "-A", "--", input.root], { env });
87
+ const currentTree = (await git(gitRoot, ["write-tree"], { env })).stdout.trim();
88
+ const patch = (await git(gitRoot, ["diff", "--binary", "--no-color", currentTree, targetTree], {
89
+ maxBuffer: 100 * 1024 * 1024,
90
+ })).stdout;
91
+ if (!patch.trim())
92
+ return { files: 0 };
93
+ const patchPath = join(tempDir, "rollback.patch");
94
+ const { writeFile } = await import("node:fs/promises");
95
+ await writeFile(patchPath, patch, "utf8");
96
+ await git(gitRoot, ["apply", "--binary", "--whitespace=nowarn", patchPath], {});
97
+ return { files: patch.split("\n").filter((line) => line.startsWith("diff --git ")).length };
98
+ }
99
+ finally {
100
+ await rm(tempDir, { recursive: true, force: true });
101
+ }
102
+ }
103
+ async function headCommit(gitRoot) {
104
+ try {
105
+ return (await git(gitRoot, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"])).stdout.trim() || undefined;
106
+ }
107
+ catch {
108
+ return undefined;
109
+ }
110
+ }
111
+ function snapshotEnv(indexPath) {
112
+ return {
113
+ GIT_INDEX_FILE: indexPath,
114
+ GIT_AUTHOR_NAME: "Hearth",
115
+ GIT_AUTHOR_EMAIL: `${SNAPSHOT_AUTHOR_ENV_BASE}@users.noreply.local`,
116
+ GIT_COMMITTER_NAME: "Hearth",
117
+ GIT_COMMITTER_EMAIL: `${SNAPSHOT_AUTHOR_ENV_BASE}@users.noreply.local`,
118
+ };
119
+ }
120
+ function snapshotRef(workspaceId, createdAt) {
121
+ const epoch = Date.parse(createdAt);
122
+ return `${SNAPSHOT_REF_PREFIX}/${safeWorkspaceRefSegment(workspaceId)}/${Number.isFinite(epoch) ? epoch : Date.now()}`;
123
+ }
@@ -0,0 +1,80 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { logEvent } from "./logger.js";
3
+ import { ProcessSessionManager } from "./process-sessions.js";
4
+ import { createReviewCheckpointManager } from "./review-checkpoints.js";
5
+ import { buildLocalAgentProviderStatuses, } from "./local-agent-catalog.js";
6
+ import { getLocalAgentProviderAvailabilitySnapshot } from "./local-agent-availability.js";
7
+ import { createWorkspaceStore } from "./workspace-store.js";
8
+ import { WorkspaceRegistry } from "./workspaces.js";
9
+ import { createMcpServer } from "./server.js";
10
+ import { TaskStore } from "./task-store.js";
11
+ import { probeSandboxAdapter, wrapCommandWithSandbox } from "./policy/sandbox.js";
12
+ import { resolveExecutionForWorkspace } from "./policy/workspace-profiles.js";
13
+ export function buildLocalMcpServer(config, options = {}) {
14
+ const workspaceStore = createWorkspaceStore(config.stateDir);
15
+ const workspaces = new WorkspaceRegistry(config, workspaceStore);
16
+ const taskStore = new TaskStore(config.stateDir);
17
+ taskStore.reconcileOnBoot();
18
+ const reviewCheckpoints = createReviewCheckpointManager();
19
+ const processJournalDir = `${config.stateDir}/process-journal`;
20
+ void import("./process-journal.js").then(({ reapProcessJournal }) => reapProcessJournal(processJournalDir, (event, details) => logEvent(config.logging, "warn", event, details)).catch(() => undefined)).catch(() => undefined);
21
+ const processSessions = new ProcessSessionManager({
22
+ environment: {
23
+ allowAll: config.execution.envAllowAll,
24
+ extraAllowlist: config.execution.envAllowlist,
25
+ },
26
+ journalDir: processJournalDir,
27
+ ...(config.execution.sandbox === "none" && config.workspaceProfiles.every((profile) => profile.sandbox !== "auto")
28
+ ? {}
29
+ : {
30
+ commandWrapper: (shell, ctx) => {
31
+ const resolved = resolveExecutionForWorkspace(config, ctx.workspaceRoot);
32
+ return wrapCommandWithSandbox(shell, probeSandboxAdapter(), {
33
+ workspaceRoot: ctx.workspaceRoot,
34
+ allowNetwork: (resolved.sandboxNetwork ?? config.execution.sandboxNetwork) === "allow",
35
+ });
36
+ },
37
+ }),
38
+ });
39
+ const resolveLocalAgentProviders = () => buildLocalAgentProviderStatuses(config.subagents, getLocalAgentProviderAvailabilitySnapshot());
40
+ const server = createMcpServer(config, workspaces, reviewCheckpoints, processSessions, resolveLocalAgentProviders, options.incomingArtifactAdapters ?? [], undefined, taskStore);
41
+ return {
42
+ server,
43
+ workspaces,
44
+ close: async () => {
45
+ processSessions.shutdown();
46
+ workspaceStore.close?.();
47
+ taskStore.close();
48
+ },
49
+ };
50
+ }
51
+ /**
52
+ * Run Hearth as a local stdio MCP server. stdout carries only the MCP
53
+ * protocol; human-readable logging goes to stderr.
54
+ */
55
+ export async function runStdioServer(config) {
56
+ const { server, close } = buildLocalMcpServer(config);
57
+ const transport = new StdioServerTransport();
58
+ await server.connect(transport);
59
+ logEvent(config.logging, "info", "stdio_server_started", {
60
+ allowedRoots: config.allowedRoots,
61
+ mode: config.execution.mode,
62
+ });
63
+ let shuttingDown = false;
64
+ const shutdown = () => {
65
+ if (shuttingDown)
66
+ return;
67
+ shuttingDown = true;
68
+ void (async () => {
69
+ try {
70
+ await server.close();
71
+ }
72
+ finally {
73
+ await close();
74
+ process.exit(0);
75
+ }
76
+ })();
77
+ };
78
+ process.once("SIGINT", shutdown);
79
+ process.once("SIGTERM", shutdown);
80
+ }
@@ -0,0 +1,203 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { resolve } from "node:path";
3
+ import { openDatabase } from "./db/client.js";
4
+ /** Allowed transitions; anything else is rejected by the state machine. */
5
+ const TRANSITIONS = {
6
+ planning: ["executing", "cancelled"],
7
+ executing: ["verifying", "cancelled", "failed"],
8
+ verifying: ["completed", "repairing", "failed", "cancelled"],
9
+ repairing: ["verifying", "executing", "cancelled", "failed"],
10
+ completed: [],
11
+ failed: [],
12
+ cancelled: [],
13
+ };
14
+ export class TaskTransitionError extends Error {
15
+ from;
16
+ to;
17
+ constructor(from, to) {
18
+ super(`Illegal task transition: ${from} → ${to}`);
19
+ this.from = from;
20
+ this.to = to;
21
+ this.name = "TaskTransitionError";
22
+ }
23
+ }
24
+ export class TaskStore {
25
+ database;
26
+ constructor(stateDir) {
27
+ this.database = openDatabase(stateDir);
28
+ }
29
+ create(input) {
30
+ const now = new Date().toISOString();
31
+ const record = {
32
+ id: `task_${randomUUID().replaceAll("-", "").slice(0, 12)}`,
33
+ workspaceId: input.workspaceId,
34
+ workspaceRoot: resolve(input.workspaceRoot),
35
+ goal: input.goal,
36
+ status: "planning",
37
+ mode: input.mode ?? "supervised",
38
+ evidence: [],
39
+ toolCalls: 0,
40
+ createdAt: now,
41
+ updatedAt: now,
42
+ };
43
+ this.database.sqlite
44
+ .prepare(`insert into tasks (
45
+ id, workspace_id, workspace_root, goal, status, completion_state,
46
+ mode, plan, evidence, error, tool_calls, created_at, updated_at
47
+ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
48
+ .run(record.id, record.workspaceId ?? null, record.workspaceRoot, record.goal, record.status, null, record.mode, null, JSON.stringify(record.evidence), null, 0, record.createdAt, record.updatedAt);
49
+ return record;
50
+ }
51
+ get(id) {
52
+ const row = this.database.sqlite
53
+ .prepare("select * from tasks where id = ? limit 1")
54
+ .get(id);
55
+ return row ? rowToTask(row) : undefined;
56
+ }
57
+ list(scope = {}) {
58
+ let rows;
59
+ if (scope.workspaceId) {
60
+ rows = this.database.sqlite
61
+ .prepare("select * from tasks where workspace_id = ? order by updated_at desc")
62
+ .all(scope.workspaceId);
63
+ }
64
+ else if (scope.workspaceRoot) {
65
+ rows = this.database.sqlite
66
+ .prepare("select * from tasks where workspace_root = ? order by updated_at desc")
67
+ .all(resolve(scope.workspaceRoot));
68
+ }
69
+ else {
70
+ rows = this.database.sqlite
71
+ .prepare("select * from tasks order by updated_at desc limit 200")
72
+ .all();
73
+ }
74
+ return rows.map(rowToTask);
75
+ }
76
+ /**
77
+ * Applies a guarded transition, appending an evidence entry for the move.
78
+ * Returns the updated record; throws TaskTransitionError on illegal moves.
79
+ */
80
+ transition(id, to, options = {}) {
81
+ const current = this.get(id);
82
+ if (!current)
83
+ throw new Error(`Unknown task: ${id}`);
84
+ if (current.status === to)
85
+ return current;
86
+ if (!TRANSITIONS[current.status].includes(to)) {
87
+ throw new TaskTransitionError(current.status, to);
88
+ }
89
+ const evidence = [
90
+ ...current.evidence,
91
+ ...(options.evidence
92
+ ? [options.evidence]
93
+ : [{
94
+ ts: new Date().toISOString(),
95
+ kind: "note",
96
+ summary: `status: ${current.status} → ${to}`,
97
+ }]),
98
+ ];
99
+ this.database.sqlite
100
+ .prepare(`update tasks set
101
+ status = ?,
102
+ completion_state = ?,
103
+ plan = ?,
104
+ evidence = ?,
105
+ error = ?,
106
+ updated_at = ?
107
+ where id = ?`)
108
+ .run(to, options.completionState ?? (to === "completed" ? current.completionState ?? null : null), options.plan ? JSON.stringify(options.plan) : current.plan ? JSON.stringify(current.plan) : null, JSON.stringify(evidence), options.error ?? (to === "failed" || to === "cancelled" ? options.error ?? current.error ?? null : null), new Date().toISOString(), id);
109
+ return this.get(id);
110
+ }
111
+ /**
112
+ * Resume a failed task (e.g. after crash reconcile or repair-budget
113
+ * exhaustion) back to planning with an audit trail. Only failed tasks can
114
+ * resume; completed/cancelled are terminal and in-flight tasks use the
115
+ * normal transitions.
116
+ */
117
+ replan(id, reason = "Resumed by client.") {
118
+ const current = this.get(id);
119
+ if (!current)
120
+ throw new Error(`Unknown task: ${id}`);
121
+ if (current.status !== "failed") {
122
+ throw new TaskTransitionError(current.status, "planning");
123
+ }
124
+ const evidence = [
125
+ ...current.evidence,
126
+ { ts: new Date().toISOString(), kind: "note", summary: `resume: failed → planning (${reason})` },
127
+ ];
128
+ this.database.sqlite
129
+ .prepare("update tasks set status = 'planning', error = ?, evidence = ?, updated_at = ? where id = ?")
130
+ .run(null, JSON.stringify(evidence), new Date().toISOString(), id);
131
+ return this.get(id);
132
+ }
133
+ appendEvidence(id, entry) {
134
+ const current = this.get(id);
135
+ if (!current)
136
+ throw new Error(`Unknown task: ${id}`);
137
+ const evidence = [...current.evidence, entry];
138
+ this.database.sqlite
139
+ .prepare("update tasks set evidence = ?, updated_at = ? where id = ?")
140
+ .run(JSON.stringify(evidence), new Date().toISOString(), id);
141
+ return this.get(id);
142
+ }
143
+ countToolCall(id) {
144
+ this.database.sqlite
145
+ .prepare("update tasks set tool_calls = tool_calls + 1, updated_at = ? where id = ?")
146
+ .run(new Date().toISOString(), id);
147
+ }
148
+ /**
149
+ * Crash recovery: on boot, tasks that were mid-flight are not magically
150
+ * resumable (their driving client is gone), so they are failed with an
151
+ * explicit reason. Paused agents remain resumable; tasks are recreated or
152
+ * re-planned by the client.
153
+ */
154
+ reconcileOnBoot() {
155
+ const result = this.database.sqlite
156
+ .prepare(`update tasks
157
+ set status = 'failed',
158
+ error = 'Hearth restarted while the task was in flight.',
159
+ updated_at = ?
160
+ where status in ('executing', 'verifying', 'repairing')`)
161
+ .run(new Date().toISOString());
162
+ return Number(result.changes);
163
+ }
164
+ close() {
165
+ this.database.close();
166
+ }
167
+ }
168
+ function rowToTask(row) {
169
+ return {
170
+ id: row.id,
171
+ workspaceId: row.workspace_id ?? undefined,
172
+ workspaceRoot: row.workspace_root,
173
+ goal: row.goal,
174
+ status: readStatus(row.status),
175
+ completionState: readCompletionState(row.completion_state),
176
+ mode: readMode(row.mode),
177
+ plan: row.plan ? safeParseArray(row.plan) : undefined,
178
+ evidence: row.evidence ? safeParseArray(row.evidence) : [],
179
+ error: row.error ?? undefined,
180
+ toolCalls: Number(row.tool_calls ?? 0),
181
+ createdAt: row.created_at,
182
+ updatedAt: row.updated_at,
183
+ };
184
+ }
185
+ function readStatus(value) {
186
+ const allowed = ["planning", "executing", "verifying", "repairing", "completed", "failed", "cancelled"];
187
+ return allowed.includes(value) ? value : "failed";
188
+ }
189
+ function readCompletionState(value) {
190
+ return value === "verified_complete" || value === "model_complete" ? value : undefined;
191
+ }
192
+ function readMode(value) {
193
+ return value === "autonomous" || value === "readonly" ? value : "supervised";
194
+ }
195
+ function safeParseArray(value) {
196
+ try {
197
+ const parsed = JSON.parse(value);
198
+ return Array.isArray(parsed) ? parsed : [];
199
+ }
200
+ catch {
201
+ return [];
202
+ }
203
+ }