@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,378 @@
1
+ import { basename, isAbsolute } from "node:path";
2
+ import { Readable } from "node:stream";
3
+ import { ArtifactError } from "./artifact-error.js";
4
+ const ADAPTER_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/u;
5
+ const OPENAI_FILE_HOSTS = new Set([
6
+ "files.oaiusercontent.com",
7
+ ]);
8
+ // ChatGPT-generated files are served from regional OpenAI-managed Azure storage
9
+ // accounts. Accept that account family only, never arbitrary Azure Blob hosts.
10
+ const OPENAI_REGIONAL_BLOB_HOST_PATTERN = /^oaisdmntpr[a-z0-9]+\.blob\.core\.windows\.net$/u;
11
+ const OPENAI_FILENAME_SAFE_FILE_ID_PATTERN = /^file[-_][A-Za-z0-9][A-Za-z0-9._-]{0,255}$/u;
12
+ const OPENAI_FILE_ID_MAX_LENGTH = 512;
13
+ const OPENAI_FILE_ID_CONTROL_PATTERN = /[\u0000-\u001F\u007F]/u;
14
+ const OPENAI_FILE_KEYS = new Set([
15
+ "download_url",
16
+ "file_id",
17
+ "mime_type",
18
+ "file_name",
19
+ "name",
20
+ "size",
21
+ ]);
22
+ const OPENAI_FILE_REDIRECT_LIMIT = 3;
23
+ const OPENAI_FILE_DOWNLOAD_TIMEOUT_MS = 30_000;
24
+ export class IncomingArtifactAdapterRegistry {
25
+ adapters;
26
+ constructor(adapters = []) {
27
+ const ids = new Set();
28
+ for (const adapter of adapters) {
29
+ if (!ADAPTER_ID_PATTERN.test(adapter.id)) {
30
+ throw new ArtifactError("invalid_incoming_adapter", "Incoming artifact adapter IDs must be short lowercase identifiers.");
31
+ }
32
+ if (ids.has(adapter.id)) {
33
+ throw new ArtifactError("duplicate_incoming_adapter", `Incoming artifact adapter '${adapter.id}' is registered more than once.`);
34
+ }
35
+ ids.add(adapter.id);
36
+ }
37
+ this.adapters = [...adapters];
38
+ }
39
+ async open(value) {
40
+ const matching = [];
41
+ for (const adapter of this.adapters) {
42
+ let handles = false;
43
+ try {
44
+ handles = adapter.canHandle(value);
45
+ }
46
+ catch {
47
+ throw new ArtifactError("incoming_artifact_adapter_failed", `Incoming artifact adapter '${adapter.id}' failed during recognition.`);
48
+ }
49
+ if (handles)
50
+ matching.push(adapter);
51
+ }
52
+ if (matching.length === 0) {
53
+ throw new ArtifactError("unsupported_incoming_artifact", "No trusted incoming artifact adapter recognized this file reference.");
54
+ }
55
+ if (matching.length > 1) {
56
+ throw new ArtifactError("ambiguous_incoming_artifact", "More than one trusted incoming artifact adapter recognized this file reference.");
57
+ }
58
+ const adapter = matching[0];
59
+ let source;
60
+ try {
61
+ source = await adapter.open(value);
62
+ }
63
+ catch (error) {
64
+ if (error instanceof ArtifactError)
65
+ throw error;
66
+ throw new ArtifactError("incoming_artifact_open_failed", `Incoming artifact adapter '${adapter.id}' could not open the file reference.`);
67
+ }
68
+ try {
69
+ validateIncomingArtifactSource(source);
70
+ }
71
+ catch (error) {
72
+ source?.stream?.destroy?.();
73
+ throw error;
74
+ }
75
+ return { ...source, adapterId: adapter.id };
76
+ }
77
+ }
78
+ export function createOpenAIIncomingArtifactAdapter(options = {}) {
79
+ const fetchFile = options.fetch ?? globalThis.fetch;
80
+ const timeoutMs = options.timeoutMs ?? OPENAI_FILE_DOWNLOAD_TIMEOUT_MS;
81
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {
82
+ throw new ArtifactError("invalid_openai_file_adapter", "OpenAI file download timeout must be a positive integer.");
83
+ }
84
+ return {
85
+ id: "openai-file",
86
+ canHandle: isOpenAIFileReferenceCandidate,
87
+ async open(value) {
88
+ const reference = normalizeOpenAIFileReference(value);
89
+ let downloadUrl = validateOpenAIFileUrl(reference.download_url);
90
+ let response;
91
+ for (let redirect = 0; redirect <= OPENAI_FILE_REDIRECT_LIMIT; redirect += 1) {
92
+ try {
93
+ response = await fetchFile(downloadUrl, {
94
+ redirect: "manual",
95
+ signal: AbortSignal.timeout(timeoutMs),
96
+ });
97
+ }
98
+ catch {
99
+ throw new ArtifactError("openai_file_download_failed", "ChatGPT file could not be downloaded.");
100
+ }
101
+ if (!isRedirectStatus(response.status))
102
+ break;
103
+ const location = response.headers.get("location");
104
+ await response.body?.cancel().catch(() => undefined);
105
+ if (!location || redirect === OPENAI_FILE_REDIRECT_LIMIT) {
106
+ throw new ArtifactError("openai_file_download_failed", "ChatGPT file download returned an invalid redirect.");
107
+ }
108
+ downloadUrl = validateOpenAIFileUrl(new URL(location, downloadUrl).toString());
109
+ }
110
+ if (!response?.ok || !response.body) {
111
+ await response?.body?.cancel().catch(() => undefined);
112
+ throw new ArtifactError("openai_file_download_failed", "ChatGPT file download did not return file content.");
113
+ }
114
+ const responseSize = responseContentLength(response);
115
+ if (reference.size !== undefined
116
+ && responseSize !== undefined
117
+ && reference.size !== responseSize) {
118
+ await response.body.cancel().catch(() => undefined);
119
+ throw new ArtifactError("openai_file_size_mismatch", "ChatGPT file metadata did not match the downloaded content.");
120
+ }
121
+ const mimeType = reference.mime_type ?? responseMimeType(response);
122
+ return {
123
+ name: normalizeOpenAIFileName(reference.file_name, reference.file_id, mimeType),
124
+ mimeType,
125
+ size: responseSize ?? reference.size,
126
+ stream: Readable.fromWeb(response.body),
127
+ };
128
+ },
129
+ };
130
+ }
131
+ export function describeIncomingArtifactValue(value, maxDepth = 4, maxEntries = 20) {
132
+ const seen = new WeakSet();
133
+ const describe = (current, depth) => {
134
+ if (current === null)
135
+ return { type: "null" };
136
+ if (current === undefined)
137
+ return { type: "undefined" };
138
+ if (typeof current === "boolean")
139
+ return { type: "boolean" };
140
+ if (typeof current === "number")
141
+ return { type: "number", finite: Number.isFinite(current) };
142
+ if (typeof current === "bigint")
143
+ return { type: "bigint" };
144
+ if (typeof current === "function")
145
+ return { type: "function" };
146
+ if (typeof current === "symbol")
147
+ return { type: "symbol" };
148
+ if (typeof current === "string") {
149
+ return {
150
+ type: "string",
151
+ kind: classifyValueString(current),
152
+ length: current.length,
153
+ };
154
+ }
155
+ if (seen.has(current))
156
+ return { type: "cycle" };
157
+ seen.add(current);
158
+ if (Array.isArray(current)) {
159
+ if (depth >= maxDepth) {
160
+ return { type: "array", length: current.length, items: [], truncated: current.length > 0 };
161
+ }
162
+ const items = current.slice(0, maxEntries).map((item) => describe(item, depth + 1));
163
+ return {
164
+ type: "array",
165
+ length: current.length,
166
+ items,
167
+ truncated: current.length > items.length,
168
+ };
169
+ }
170
+ const keys = Object.keys(current).sort();
171
+ if (depth >= maxDepth) {
172
+ return {
173
+ type: "object",
174
+ constructor: safeConstructorName(current),
175
+ entries: {},
176
+ truncated: keys.length > 0,
177
+ };
178
+ }
179
+ const entries = {};
180
+ for (const [index, key] of keys.slice(0, maxEntries).entries()) {
181
+ let entryValue;
182
+ try {
183
+ entryValue = current[key];
184
+ }
185
+ catch {
186
+ entryValue = undefined;
187
+ }
188
+ entries[safeValueEntryKey(key, index)] = describe(entryValue, depth + 1);
189
+ }
190
+ return {
191
+ type: "object",
192
+ constructor: safeConstructorName(current),
193
+ entries,
194
+ truncated: keys.length > Object.keys(entries).length,
195
+ };
196
+ };
197
+ return describe(value, 0);
198
+ }
199
+ function validateIncomingArtifactSource(source) {
200
+ if (!source || typeof source !== "object") {
201
+ throw new ArtifactError("invalid_incoming_artifact_source", "Incoming artifact adapter returned an invalid source.");
202
+ }
203
+ if (typeof source.name !== "string" || source.name.length === 0) {
204
+ throw new ArtifactError("invalid_incoming_artifact_source", "Incoming artifact adapter must provide a filename.");
205
+ }
206
+ if (source.mimeType !== undefined && typeof source.mimeType !== "string") {
207
+ throw new ArtifactError("invalid_incoming_artifact_source", "Incoming artifact adapter returned an invalid MIME hint.");
208
+ }
209
+ if (source.size !== undefined
210
+ && (!Number.isSafeInteger(source.size) || source.size < 0)) {
211
+ throw new ArtifactError("invalid_incoming_artifact_source", "Incoming artifact adapter returned an invalid byte size.");
212
+ }
213
+ const stream = source.stream;
214
+ if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
215
+ throw new ArtifactError("invalid_incoming_artifact_source", "Incoming artifact adapter must provide an async-readable stream.");
216
+ }
217
+ }
218
+ function isOpenAIFileReferenceCandidate(value) {
219
+ if (!isRecord(value))
220
+ return false;
221
+ const keys = Object.keys(value);
222
+ return keys.length >= 2
223
+ && keys.every((key) => OPENAI_FILE_KEYS.has(key))
224
+ && Object.hasOwn(value, "download_url")
225
+ && Object.hasOwn(value, "file_id");
226
+ }
227
+ function normalizeOpenAIFileReference(value) {
228
+ if (!isOpenAIFileReferenceCandidate(value)) {
229
+ throw new ArtifactError("invalid_openai_file_reference", "ChatGPT file reference is malformed.");
230
+ }
231
+ const downloadUrl = value.download_url;
232
+ const fileId = value.file_id;
233
+ if (typeof downloadUrl !== "string"
234
+ || typeof fileId !== "string"
235
+ || !isValidOpenAIFileId(fileId)) {
236
+ throw new ArtifactError("invalid_openai_file_reference", "ChatGPT file reference is malformed.");
237
+ }
238
+ const mimeType = nullableString(value.mime_type);
239
+ const fileName = nullableString(value.file_name);
240
+ const nameAlias = nullableString(value.name);
241
+ if (mimeType === null || fileName === null || nameAlias === null) {
242
+ throw new ArtifactError("invalid_openai_file_reference", "ChatGPT file reference is malformed.");
243
+ }
244
+ const normalizedFileName = normalizeSuppliedOpenAIFileName(fileName);
245
+ const normalizedNameAlias = normalizeSuppliedOpenAIFileName(nameAlias);
246
+ if (normalizedFileName
247
+ && normalizedNameAlias
248
+ && normalizedFileName !== normalizedNameAlias) {
249
+ throw new ArtifactError("ambiguous_openai_file_name", "ChatGPT file reference contained conflicting filenames.");
250
+ }
251
+ let size;
252
+ const rawSize = value.size;
253
+ if (rawSize !== undefined && rawSize !== null) {
254
+ if (typeof rawSize !== "number" || !Number.isSafeInteger(rawSize) || rawSize < 0) {
255
+ throw new ArtifactError("invalid_openai_file_reference", "ChatGPT file reference is malformed.");
256
+ }
257
+ size = rawSize;
258
+ }
259
+ return {
260
+ download_url: downloadUrl,
261
+ file_id: fileId,
262
+ mime_type: mimeType,
263
+ file_name: normalizedFileName ?? normalizedNameAlias,
264
+ size,
265
+ };
266
+ }
267
+ function nullableString(value) {
268
+ if (value === undefined || value === null)
269
+ return undefined;
270
+ return typeof value === "string" ? value : null;
271
+ }
272
+ function normalizeOpenAIFileName(suppliedName, fileId, mimeType) {
273
+ if (suppliedName)
274
+ return suppliedName;
275
+ const safeBaseName = OPENAI_FILENAME_SAFE_FILE_ID_PATTERN.test(fileId)
276
+ ? fileId
277
+ : "chatgpt-file";
278
+ return `${safeBaseName}${extensionForMimeType(mimeType) ?? ".bin"}`;
279
+ }
280
+ function isValidOpenAIFileId(value) {
281
+ return value.length > 0
282
+ && value.length <= OPENAI_FILE_ID_MAX_LENGTH
283
+ && !OPENAI_FILE_ID_CONTROL_PATTERN.test(value);
284
+ }
285
+ function normalizeSuppliedOpenAIFileName(value) {
286
+ if (!value)
287
+ return undefined;
288
+ const normalized = value.replaceAll("\\", "/");
289
+ const candidate = basename(normalized).trim();
290
+ if (!candidate || candidate === "." || candidate === ".." || candidate.startsWith(".")) {
291
+ return undefined;
292
+ }
293
+ return candidate;
294
+ }
295
+ function extensionForMimeType(mimeType) {
296
+ switch (mimeType?.toLowerCase()) {
297
+ case "image/png": return ".png";
298
+ case "image/jpeg": return ".jpg";
299
+ case "image/webp": return ".webp";
300
+ case "image/gif": return ".gif";
301
+ case "application/pdf": return ".pdf";
302
+ case "text/plain": return ".txt";
303
+ case "application/zip": return ".zip";
304
+ case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": return ".docx";
305
+ default: return undefined;
306
+ }
307
+ }
308
+ function validateOpenAIFileUrl(value) {
309
+ let url;
310
+ try {
311
+ url = new URL(value);
312
+ }
313
+ catch {
314
+ throw new ArtifactError("unsafe_openai_file_reference", "ChatGPT file download URL is invalid.");
315
+ }
316
+ if (url.protocol !== "https:"
317
+ || !isTrustedOpenAIFileHost(url.hostname)
318
+ || (url.port !== "" && url.port !== "443")
319
+ || url.username !== ""
320
+ || url.password !== ""
321
+ || url.hash !== "") {
322
+ throw new ArtifactError("unsafe_openai_file_reference", "ChatGPT file download URL is outside the trusted file host.");
323
+ }
324
+ return url.toString();
325
+ }
326
+ function isTrustedOpenAIFileHost(hostname) {
327
+ return OPENAI_FILE_HOSTS.has(hostname) || OPENAI_REGIONAL_BLOB_HOST_PATTERN.test(hostname);
328
+ }
329
+ function isRedirectStatus(status) {
330
+ return status === 301
331
+ || status === 302
332
+ || status === 303
333
+ || status === 307
334
+ || status === 308;
335
+ }
336
+ function responseMimeType(response) {
337
+ const value = response.headers.get("content-type")?.split(";", 1)[0]?.trim();
338
+ return value || undefined;
339
+ }
340
+ function responseContentLength(response) {
341
+ const value = response.headers.get("content-length");
342
+ if (!value || !/^\d+$/u.test(value))
343
+ return undefined;
344
+ const size = Number(value);
345
+ return Number.isSafeInteger(size) ? size : undefined;
346
+ }
347
+ function isRecord(value) {
348
+ return typeof value === "object" && value !== null && !Array.isArray(value);
349
+ }
350
+ function classifyValueString(value) {
351
+ if (value.startsWith("data:"))
352
+ return "data-url";
353
+ if (isAbsolute(value))
354
+ return "absolute-path";
355
+ try {
356
+ const parsed = new URL(value);
357
+ if (parsed.protocol === "http:" || parsed.protocol === "https:")
358
+ return "url";
359
+ }
360
+ catch {
361
+ // Non-URL strings are summarized only by type and length.
362
+ }
363
+ return "text";
364
+ }
365
+ function safeValueEntryKey(value, index) {
366
+ return /^[A-Za-z_][A-Za-z0-9_.-]{0,79}$/u.test(value)
367
+ ? value
368
+ : `<redacted-key-${index + 1}>`;
369
+ }
370
+ function safeConstructorName(value) {
371
+ try {
372
+ const name = value.constructor?.name;
373
+ return typeof name === "string" && name.length <= 80 ? name : undefined;
374
+ }
375
+ catch {
376
+ return undefined;
377
+ }
378
+ }