@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,349 @@
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 REVIEW_REF_PREFIX = "refs/hearth/review";
6
+ export function createReviewCheckpointManager() {
7
+ const states = new Map();
8
+ const initializations = new Map();
9
+ return {
10
+ async initializeWorkspace({ workspaceId, root }) {
11
+ const existingState = states.get(workspaceId);
12
+ assertWorkspaceRoot(existingState, workspaceId, root);
13
+ if (existingState?.root === root && existingState.gitRoot !== undefined) {
14
+ return reviewAvailability(existingState);
15
+ }
16
+ const pending = initializations.get(workspaceId);
17
+ if (pending) {
18
+ await pending;
19
+ const initializedState = states.get(workspaceId);
20
+ assertWorkspaceRoot(initializedState, workspaceId, root);
21
+ return reviewAvailability(initializedState);
22
+ }
23
+ const initialize = initializeWorkspaceState(states, workspaceId, root);
24
+ initializations.set(workspaceId, initialize);
25
+ try {
26
+ await initialize;
27
+ }
28
+ finally {
29
+ if (initializations.get(workspaceId) === initialize) {
30
+ initializations.delete(workspaceId);
31
+ }
32
+ }
33
+ return reviewAvailability(states.get(workspaceId));
34
+ },
35
+ async reviewChanges({ workspaceId, root, since = "last_shown", markReviewed = true }) {
36
+ let state = states.get(workspaceId);
37
+ assertWorkspaceRoot(state, workspaceId, root);
38
+ if (!isReadyState(state)) {
39
+ await this.initializeWorkspace({ workspaceId, root });
40
+ state = states.get(workspaceId);
41
+ }
42
+ assertWorkspaceRoot(state, workspaceId, root);
43
+ if (!state?.gitRoot) {
44
+ throw new Error(state?.diagnostic ?? "show_changes requires a Git workspace in this version.");
45
+ }
46
+ let effectiveSince = since;
47
+ let usedWorkspaceOpenFallback = false;
48
+ if (since === "last_shown" && !state.baselineRefAvailable) {
49
+ if (!state.openRefAvailable) {
50
+ throw new Error("Review checkpoints are missing; show_changes cannot reconstruct that history safely.");
51
+ }
52
+ effectiveSince = "workspace_open";
53
+ usedWorkspaceOpenFallback = true;
54
+ }
55
+ else if (since === "workspace_open" && !state.openRefAvailable) {
56
+ throw new Error("The workspace-open review checkpoint is missing; show_changes cannot reconstruct that history safely.");
57
+ }
58
+ const baselineRef = effectiveSince === "workspace_open" ? state.openRef : state.baselineRef;
59
+ const baseline = (await git(state.gitRoot, ["rev-parse", "--verify", `${baselineRef}^{commit}`])).stdout.trim();
60
+ const current = await createWorkingTreeSnapshot(state.gitRoot, baseline);
61
+ const review = await readReviewBetween(state.gitRoot, baseline, current);
62
+ if (markReviewed) {
63
+ await git(state.gitRoot, ["update-ref", state.baselineRef, current]);
64
+ state.baselineRefAvailable = true;
65
+ }
66
+ const fallbackNote = usedWorkspaceOpenFallback
67
+ ? ` The last-shown checkpoint was missing, so changes were compared from workspace open${markReviewed ? " and the baseline was re-established" : ""}.`
68
+ : "";
69
+ return {
70
+ reviewRef: current,
71
+ result: `${review.summary.files === 0
72
+ ? `No changes since ${effectiveSince === "workspace_open" ? "workspace open" : "last shown changes"}.`
73
+ : formatChangedFiles(review.summary)}${fallbackNote}`,
74
+ ...review,
75
+ };
76
+ },
77
+ async reviewByRef({ workspaceId, root, reviewRef }) {
78
+ let state = states.get(workspaceId);
79
+ assertWorkspaceRoot(state, workspaceId, root);
80
+ if (!isReadyState(state)) {
81
+ await this.initializeWorkspace({ workspaceId, root });
82
+ state = states.get(workspaceId);
83
+ }
84
+ assertWorkspaceRoot(state, workspaceId, root);
85
+ if (!state?.gitRoot) {
86
+ throw new Error(state?.diagnostic ?? "show_changes requires a Git workspace in this version.");
87
+ }
88
+ const [openCommit, baselineCommit, reviewCommit] = await Promise.all([
89
+ commitForRef(state.gitRoot, state.openRef),
90
+ commitForRef(state.gitRoot, state.baselineRef),
91
+ resolveReviewCommitOrUndefined(state.gitRoot, reviewRef),
92
+ ]);
93
+ if (!openCommit
94
+ || !baselineCommit
95
+ || !reviewCommit
96
+ || reviewCommit === openCommit) {
97
+ throw new Error(`Unknown review reference for workspace ${workspaceId}: ${reviewRef}`);
98
+ }
99
+ const [isAfterOpen, isBeforeBaseline] = await Promise.all([
100
+ isAncestor(state.gitRoot, openCommit, reviewCommit),
101
+ isAncestor(state.gitRoot, reviewCommit, baselineCommit),
102
+ ]);
103
+ if (!isAfterOpen || !isBeforeBaseline) {
104
+ throw new Error(`Unknown review reference for workspace ${workspaceId}: ${reviewRef}`);
105
+ }
106
+ return readReviewCommit(state.gitRoot, reviewCommit);
107
+ },
108
+ };
109
+ }
110
+ export async function readReviewRef(root, reviewRef) {
111
+ const eligibility = await getGitEligibility(root);
112
+ if (!eligibility.ok || !eligibility.gitRoot) {
113
+ throw new Error(eligibility.message ?? "show-changes requires a Git workspace.");
114
+ }
115
+ const commit = await resolveReviewCommit(eligibility.gitRoot, reviewRef);
116
+ if (!await isKnownReviewCommit(eligibility.gitRoot, commit)) {
117
+ throw new Error(`Unknown Hearth review reference: ${reviewRef}`);
118
+ }
119
+ return readReviewCommit(eligibility.gitRoot, commit);
120
+ }
121
+ function assertWorkspaceRoot(state, workspaceId, root) {
122
+ if (state && state.root !== root) {
123
+ throw new Error(`Review checkpoint workspace root mismatch for ${workspaceId}.`);
124
+ }
125
+ }
126
+ async function initializeWorkspaceState(states, workspaceId, root) {
127
+ const refs = reviewRefs(workspaceId);
128
+ const state = {
129
+ root,
130
+ ...refs,
131
+ openRefAvailable: false,
132
+ baselineRefAvailable: false,
133
+ };
134
+ try {
135
+ const eligibility = await getGitEligibility(root);
136
+ if (!eligibility.ok || !eligibility.gitRoot) {
137
+ state.diagnostic = eligibility.message ?? "show_changes requires a Git workspace in this version.";
138
+ return;
139
+ }
140
+ const [openCommit, baselineCommit] = await Promise.all([
141
+ commitForRef(eligibility.gitRoot, state.openRef),
142
+ commitForRef(eligibility.gitRoot, state.baselineRef),
143
+ ]);
144
+ if (!openCommit && !baselineCommit) {
145
+ const head = (await git(eligibility.gitRoot, ["rev-parse", "--verify", "HEAD^{commit}"])).stdout.trim();
146
+ const initialCommit = await createWorkingTreeSnapshot(eligibility.gitRoot, head);
147
+ await git(eligibility.gitRoot, ["update-ref", state.openRef, initialCommit]);
148
+ await git(eligibility.gitRoot, ["update-ref", state.baselineRef, initialCommit]);
149
+ state.openRefAvailable = true;
150
+ state.baselineRefAvailable = true;
151
+ }
152
+ else {
153
+ state.openRefAvailable = openCommit !== undefined;
154
+ state.baselineRefAvailable = baselineCommit !== undefined;
155
+ }
156
+ state.gitRoot = eligibility.gitRoot;
157
+ }
158
+ catch (error) {
159
+ state.diagnostic = error instanceof Error ? error.message : String(error);
160
+ }
161
+ finally {
162
+ states.set(workspaceId, state);
163
+ }
164
+ }
165
+ function reviewAvailability(state) {
166
+ return state?.gitRoot
167
+ ? { available: true }
168
+ : {
169
+ available: false,
170
+ reason: state?.diagnostic ?? "show_changes is unavailable for this workspace.",
171
+ };
172
+ }
173
+ function isReadyState(state) {
174
+ return state?.gitRoot !== undefined;
175
+ }
176
+ async function commitForRef(gitRoot, ref) {
177
+ try {
178
+ return (await git(gitRoot, ["rev-parse", "--verify", `${ref}^{commit}`])).stdout.trim();
179
+ }
180
+ catch {
181
+ return undefined;
182
+ }
183
+ }
184
+ function reviewRefs(workspaceId) {
185
+ const segment = safeWorkspaceRefSegment(workspaceId);
186
+ return {
187
+ openRef: `${REVIEW_REF_PREFIX}/${segment}/open`,
188
+ baselineRef: `${REVIEW_REF_PREFIX}/${segment}/baseline`,
189
+ };
190
+ }
191
+ async function createWorkingTreeSnapshot(gitRoot, parent) {
192
+ const tempDir = await mkdtemp(join(tmpdir(), "hearth-review-index-"));
193
+ const indexPath = join(tempDir, "index");
194
+ const env = checkpointEnv(indexPath);
195
+ try {
196
+ await git(gitRoot, ["read-tree", "HEAD"], { env });
197
+ await git(gitRoot, ["add", "-A", "--", "."], { env });
198
+ const tree = (await git(gitRoot, ["write-tree"], { env })).stdout.trim();
199
+ return (await git(gitRoot, ["commit-tree", tree, "-p", parent, "-m", "Hearth review snapshot"], { env })).stdout.trim();
200
+ }
201
+ finally {
202
+ await rm(tempDir, { recursive: true, force: true });
203
+ }
204
+ }
205
+ async function readReviewCommit(gitRoot, reviewRef) {
206
+ const parent = (await git(gitRoot, ["rev-parse", "--verify", `${reviewRef}^1`])).stdout.trim();
207
+ const review = await readReviewBetween(gitRoot, parent, reviewRef);
208
+ return {
209
+ reviewRef,
210
+ result: review.summary.files === 0 ? "No changes in this review." : formatChangedFiles(review.summary),
211
+ ...review,
212
+ };
213
+ }
214
+ async function readReviewBetween(gitRoot, before, after) {
215
+ const patch = (await git(gitRoot, ["diff", "--binary", "--no-color", before, after], {
216
+ maxBuffer: 50 * 1024 * 1024,
217
+ })).stdout;
218
+ const numstat = (await git(gitRoot, ["diff", "--numstat", "-z", before, after], {
219
+ maxBuffer: 50 * 1024 * 1024,
220
+ })).stdout;
221
+ const files = parseNumstat(numstat);
222
+ return {
223
+ summary: summarizeFiles(files),
224
+ files,
225
+ patch,
226
+ };
227
+ }
228
+ async function resolveReviewCommit(gitRoot, reviewRef) {
229
+ if (!isReviewRef(reviewRef)) {
230
+ throw new Error(`Invalid review reference: ${reviewRef}`);
231
+ }
232
+ return (await git(gitRoot, ["rev-parse", "--verify", `${reviewRef}^{commit}`])).stdout.trim();
233
+ }
234
+ async function resolveReviewCommitOrUndefined(gitRoot, reviewRef) {
235
+ try {
236
+ return await resolveReviewCommit(gitRoot, reviewRef);
237
+ }
238
+ catch {
239
+ return undefined;
240
+ }
241
+ }
242
+ async function isAncestor(gitRoot, ancestor, descendant) {
243
+ try {
244
+ await git(gitRoot, ["merge-base", "--is-ancestor", ancestor, descendant]);
245
+ return true;
246
+ }
247
+ catch {
248
+ return false;
249
+ }
250
+ }
251
+ async function isKnownReviewCommit(gitRoot, reviewCommit) {
252
+ const refs = (await git(gitRoot, [
253
+ "for-each-ref",
254
+ "--format=%(refname)\t%(objectname)",
255
+ REVIEW_REF_PREFIX,
256
+ ])).stdout.trim();
257
+ if (!refs)
258
+ return false;
259
+ const histories = new Map();
260
+ for (const line of refs.split("\n")) {
261
+ const [ref, commit] = line.split("\t");
262
+ if (!ref || !commit)
263
+ continue;
264
+ const match = ref.match(/^refs\/hearth\/review\/(.+)\/(open|baseline)$/);
265
+ if (!match)
266
+ continue;
267
+ const [, workspace, kind] = match;
268
+ if (!workspace || !kind)
269
+ continue;
270
+ const history = histories.get(workspace) ?? {};
271
+ history[kind] = commit;
272
+ histories.set(workspace, history);
273
+ }
274
+ const memberships = await Promise.all([...histories.values()].map(async ({ open, baseline }) => {
275
+ if (!open || !baseline || reviewCommit === open)
276
+ return false;
277
+ const [isAfterOpen, isBeforeBaseline] = await Promise.all([
278
+ isAncestor(gitRoot, open, reviewCommit),
279
+ isAncestor(gitRoot, reviewCommit, baseline),
280
+ ]);
281
+ return isAfterOpen && isBeforeBaseline;
282
+ }));
283
+ return memberships.some(Boolean);
284
+ }
285
+ function isReviewRef(value) {
286
+ return /^[0-9a-f]{40,64}$/.test(value);
287
+ }
288
+ function formatChangedFiles(summary) {
289
+ return `Changed ${summary.files} ${summary.files === 1 ? "file" : "files"} (+${summary.additions} -${summary.removals}).`;
290
+ }
291
+ function checkpointEnv(indexPath) {
292
+ return {
293
+ GIT_INDEX_FILE: indexPath,
294
+ GIT_AUTHOR_NAME: "Hearth",
295
+ GIT_AUTHOR_EMAIL: "hearth@users.noreply.local",
296
+ GIT_COMMITTER_NAME: "Hearth",
297
+ GIT_COMMITTER_EMAIL: "hearth@users.noreply.local",
298
+ };
299
+ }
300
+ function parseNumstat(output) {
301
+ const fields = output.split("\0").filter((field) => field.length > 0);
302
+ const files = [];
303
+ for (let index = 0; index < fields.length;) {
304
+ const header = fields[index++] ?? "";
305
+ const parts = header.split("\t");
306
+ const additions = parseStatNumber(parts[0]);
307
+ const removals = parseStatNumber(parts[1]);
308
+ if (parts.length >= 3) {
309
+ const path = parts[2] ?? "";
310
+ if (path)
311
+ files.push({ path, type: fileType(path, undefined, additions, removals), additions, removals });
312
+ continue;
313
+ }
314
+ const previousPath = fields[index++];
315
+ const path = fields[index++];
316
+ if (!path)
317
+ continue;
318
+ files.push({
319
+ path,
320
+ previousPath,
321
+ type: fileType(path, previousPath, additions, removals),
322
+ additions,
323
+ removals,
324
+ });
325
+ }
326
+ return files;
327
+ }
328
+ function parseStatNumber(value) {
329
+ if (!value || value === "-")
330
+ return 0;
331
+ const parsed = Number(value);
332
+ return Number.isFinite(parsed) ? parsed : 0;
333
+ }
334
+ function fileType(path, previousPath, additions, removals) {
335
+ if (previousPath)
336
+ return additions === 0 && removals === 0 ? "rename-pure" : "rename-changed";
337
+ if (additions > 0 && removals === 0)
338
+ return "new";
339
+ if (additions === 0 && removals > 0)
340
+ return "deleted";
341
+ return "change";
342
+ }
343
+ function summarizeFiles(files) {
344
+ return files.reduce((summary, file) => ({
345
+ files: summary.files + 1,
346
+ additions: summary.additions + file.additions,
347
+ removals: summary.removals + file.removals,
348
+ }), { files: 0, additions: 0, removals: 0 });
349
+ }
package/dist/roots.js ADDED
@@ -0,0 +1,37 @@
1
+ import { homedir } from "node:os";
2
+ import { isAbsolute, relative, resolve, sep } from "node:path";
3
+ export class AccessDeniedError extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ this.name = "AccessDeniedError";
7
+ }
8
+ }
9
+ export function expandHomePath(path) {
10
+ if (path === "~")
11
+ return homedir();
12
+ if (path.startsWith("~/") || path.startsWith("~\\")) {
13
+ return resolve(homedir(), path.slice(2));
14
+ }
15
+ return path;
16
+ }
17
+ export function isPathInsideRoot(path, root) {
18
+ const resolvedPath = resolve(expandHomePath(path));
19
+ const resolvedRoot = resolve(expandHomePath(root));
20
+ const relationship = relative(resolvedRoot, resolvedPath);
21
+ return (relationship === "" ||
22
+ (!isAbsolute(relationship) &&
23
+ !relationship.startsWith("..") &&
24
+ relationship !== ".." &&
25
+ !relationship.includes(`..${sep}`)));
26
+ }
27
+ export function assertAllowedPath(path, allowedRoots) {
28
+ const resolvedPath = resolve(expandHomePath(path));
29
+ if (allowedRoots.some((root) => isPathInsideRoot(resolvedPath, root))) {
30
+ return resolvedPath;
31
+ }
32
+ throw new AccessDeniedError(`Path is outside allowed roots: ${path}`);
33
+ }
34
+ export function resolveAllowedPath(inputPath, cwd, allowedRoots) {
35
+ const absolutePath = resolve(cwd, inputPath);
36
+ return assertAllowedPath(absolutePath, allowedRoots);
37
+ }
@@ -0,0 +1,12 @@
1
+ export async function shutdownHttpServer(httpServer, closeApplication) {
2
+ const httpClosed = new Promise((resolve, reject) => {
3
+ httpServer.close((error) => {
4
+ if (error)
5
+ reject(error);
6
+ else
7
+ resolve();
8
+ });
9
+ });
10
+ await closeApplication();
11
+ await httpClosed;
12
+ }