@crouton-kit/crouter 0.3.33 → 0.3.35

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 (617) hide show
  1. package/README.md +2 -2
  2. package/dist/build-root.js +3 -6
  3. package/dist/builtin-memory/crouter-development/marketplaces.md +6 -6
  4. package/dist/builtin-memory/crouter-development/plugins.md +13 -13
  5. package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -3
  6. package/dist/builtin-memory/internal/nodes-and-canvas.md +4 -4
  7. package/dist/builtin-personas/developer/PERSONA.md +1 -1
  8. package/dist/builtin-personas/orchestration-kernel.md +1 -1
  9. package/dist/builtin-personas/waiting.md +1 -1
  10. package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +71 -0
  11. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/crtr-help-gate.test.ts +41 -0
  12. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +663 -0
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/statusline.test.ts +52 -0
  14. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +418 -0
  15. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crouter-help.ts +87 -0
  16. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/filters.json +7 -0
  17. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +174 -0
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-help-gate.ts +408 -0
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +442 -0
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/test.ts +119 -0
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/nested-context.ts +327 -0
  22. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +574 -0
  23. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +260 -0
  24. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/strip-skills-docs.ts +40 -0
  25. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/sysprompt-window.ts +19 -0
  26. package/dist/builtin-pi-packages/pi-crtr-extensions/lib/package.json +3 -0
  27. package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.js +1 -0
  28. package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +479 -0
  29. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/LICENSE +13 -0
  30. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/README.md +172 -0
  31. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/bin.mjs +11 -0
  32. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
  33. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
  34. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
  35. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
  36. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/composer.js +219 -0
  37. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
  38. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
  39. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
  40. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
  41. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
  42. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +225 -0
  43. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
  44. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
  45. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
  47. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
  48. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/Document.js +335 -0
  49. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
  50. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
  51. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
  52. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/directives.js +176 -0
  53. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/errors.js +57 -0
  54. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/index.js +17 -0
  55. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/log.js +11 -0
  56. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Alias.js +116 -0
  57. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
  58. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
  59. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
  60. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
  61. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
  62. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
  63. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
  64. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
  65. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
  66. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
  67. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
  68. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
  69. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst.js +98 -0
  70. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/lexer.js +721 -0
  71. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
  72. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/parser.js +975 -0
  73. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/public-api.js +102 -0
  74. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
  75. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
  76. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
  77. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
  78. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
  79. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
  80. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
  81. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
  82. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
  83. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
  84. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/tags.js +96 -0
  85. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
  86. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
  87. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
  88. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
  89. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +67 -0
  90. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
  91. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
  92. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
  93. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
  94. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
  95. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
  96. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
  97. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
  98. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
  99. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
  100. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +25 -0
  101. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
  102. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
  103. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/util.js +11 -0
  104. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/visit.js +233 -0
  105. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/index.js +5 -0
  106. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/package.json +3 -0
  107. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/cli.d.ts +8 -0
  108. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/cli.mjs +201 -0
  109. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
  110. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-collection.js +90 -0
  111. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
  112. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-doc.js +45 -0
  113. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
  114. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-node.js +112 -0
  115. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
  116. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
  117. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/composer.d.ts +63 -0
  118. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/composer.js +224 -0
  119. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
  120. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
  121. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
  122. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
  123. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
  124. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
  125. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
  126. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-end.js +39 -0
  127. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
  128. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
  129. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
  130. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-scalar.js +227 -0
  131. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
  132. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-props.js +148 -0
  133. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
  134. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
  135. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
  136. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
  137. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
  138. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
  139. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
  140. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
  141. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/Document.d.ts +141 -0
  142. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/Document.js +337 -0
  143. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
  144. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/anchors.js +76 -0
  145. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
  146. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/applyReviver.js +57 -0
  147. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
  148. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/createNode.js +90 -0
  149. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/directives.d.ts +49 -0
  150. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/directives.js +178 -0
  151. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/errors.d.ts +21 -0
  152. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/errors.js +62 -0
  153. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/index.d.ts +25 -0
  154. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/index.js +50 -0
  155. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/log.d.ts +3 -0
  156. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/log.js +19 -0
  157. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
  158. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Alias.js +118 -0
  159. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
  160. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Collection.js +151 -0
  161. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
  162. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Node.js +40 -0
  163. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
  164. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Pair.js +39 -0
  165. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Scalar.d.ts +47 -0
  166. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Scalar.js +27 -0
  167. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
  168. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
  169. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
  170. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
  171. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
  172. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
  173. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
  174. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/identity.js +53 -0
  175. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
  176. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/toJS.js +39 -0
  177. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/options.d.ts +350 -0
  178. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
  179. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
  180. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
  181. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
  182. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
  183. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-visit.js +99 -0
  184. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst.d.ts +109 -0
  185. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst.js +112 -0
  186. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
  187. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/lexer.js +723 -0
  188. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
  189. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/line-counter.js +41 -0
  190. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/parser.d.ts +84 -0
  191. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/parser.js +980 -0
  192. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/public-api.d.ts +44 -0
  193. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/public-api.js +107 -0
  194. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
  195. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/Schema.js +39 -0
  196. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
  197. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/map.js +19 -0
  198. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
  199. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/null.js +17 -0
  200. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
  201. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/seq.js +19 -0
  202. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
  203. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/string.js +16 -0
  204. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
  205. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/bool.js +21 -0
  206. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
  207. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/float.js +47 -0
  208. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
  209. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/int.js +42 -0
  210. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
  211. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/schema.js +25 -0
  212. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
  213. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/json/schema.js +64 -0
  214. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
  215. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/tags.d.ts +48 -0
  216. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/tags.js +99 -0
  217. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/types.d.ts +92 -0
  218. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
  219. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
  220. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
  221. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
  222. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
  223. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
  224. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
  225. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
  226. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
  227. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/merge.js +71 -0
  228. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
  229. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
  230. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
  231. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
  232. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
  233. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
  234. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
  235. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
  236. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
  237. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
  238. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
  239. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
  240. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
  241. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringify.js +132 -0
  242. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
  243. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
  244. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
  245. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
  246. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
  247. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
  248. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
  249. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyNumber.js +27 -0
  250. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
  251. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
  252. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
  253. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
  254. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/test-events.d.ts +4 -0
  255. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/test-events.js +134 -0
  256. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/util.d.ts +16 -0
  257. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/util.js +28 -0
  258. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/visit.d.ts +102 -0
  259. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/visit.js +236 -0
  260. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/package.json +97 -0
  261. package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/util.js +2 -0
  262. package/dist/builtin-pi-packages/pi-crtr-extensions/package-lock.json +3385 -0
  263. package/dist/builtin-pi-packages/pi-crtr-extensions/package.json +25 -0
  264. package/dist/builtin-pi-packages/pi-mode-switch/README.md +64 -0
  265. package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +40 -0
  266. package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +427 -0
  267. package/dist/builtin-pi-packages/pi-mode-switch/package.json +13 -0
  268. package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +55 -0
  269. package/dist/clients/attach/__tests__/crtr-output-render.test.js +2340 -0
  270. package/dist/clients/attach/attach-cmd.js +843 -743
  271. package/dist/clients/attach/auth-pickers.js +2 -2
  272. package/dist/clients/attach/canvas-panels.js +1 -1
  273. package/dist/clients/attach/chat-view.d.ts +3 -2
  274. package/dist/clients/attach/chat-view.js +30 -10
  275. package/dist/clients/attach/clipboard-image.js +1 -1
  276. package/dist/clients/attach/clipboard-text.js +1 -1
  277. package/dist/clients/attach/config-load.js +1 -1
  278. package/dist/clients/attach/crtr-output-render.d.ts +48 -0
  279. package/dist/clients/attach/crtr-output-render.js +646 -0
  280. package/dist/clients/attach/extension-dialogs.js +1 -1
  281. package/dist/clients/attach/graph-overlay.js +3 -3
  282. package/dist/clients/attach/input-controller.js +1 -1
  283. package/dist/clients/attach/pickers.js +1 -1
  284. package/dist/clients/attach/slash-commands.js +5 -6
  285. package/dist/clients/attach/titled-editor.d.ts +4 -0
  286. package/dist/clients/attach/titled-editor.js +13 -1
  287. package/dist/clients/attach/view-socket.js +1 -1
  288. package/dist/clients/web/__tests__/source-cache.test.js +5 -5
  289. package/dist/clients/web/server.js +29 -5
  290. package/dist/clients/web/source-cache.js +3 -3
  291. package/dist/clients/web/web-cmd.js +7 -7
  292. package/dist/commands/canvas-issue.js +1 -1
  293. package/dist/commands/canvas-prune.js +24 -2
  294. package/dist/commands/canvas-snapshot.js +3 -0
  295. package/dist/commands/canvas-tmux-spread.js +3 -3
  296. package/dist/commands/human.js +1 -1
  297. package/dist/commands/memory/lint.js +15 -8
  298. package/dist/commands/memory/origin.d.ts +1 -0
  299. package/dist/commands/memory/origin.js +88 -0
  300. package/dist/commands/memory/shared.d.ts +8 -0
  301. package/dist/commands/memory/shared.js +22 -1
  302. package/dist/commands/memory/write.js +17 -12
  303. package/dist/commands/memory.js +4 -3
  304. package/dist/commands/node-context.js +4 -4
  305. package/dist/commands/node-snapshot.js +4 -1
  306. package/dist/commands/node.d.ts +2 -2
  307. package/dist/commands/node.js +814 -606
  308. package/dist/commands/pkg/market-inspect.d.ts +2 -1
  309. package/dist/commands/pkg/market-inspect.js +14 -32
  310. package/dist/commands/pkg/market-manage.d.ts +3 -1
  311. package/dist/commands/pkg/market-manage.js +58 -154
  312. package/dist/commands/pkg/market.js +7 -7
  313. package/dist/commands/pkg/plugin-inspect.d.ts +2 -1
  314. package/dist/commands/pkg/plugin-inspect.js +8 -24
  315. package/dist/commands/pkg/plugin-manage.d.ts +5 -1
  316. package/dist/commands/pkg/plugin-manage.js +245 -171
  317. package/dist/commands/pkg/plugin.js +6 -6
  318. package/dist/commands/pkg.js +5 -5
  319. package/dist/commands/revive.js +5 -3
  320. package/dist/commands/search/answer.js +1 -1
  321. package/dist/commands/search/contents.js +1 -1
  322. package/dist/commands/search/web.js +2 -2
  323. package/dist/commands/search.js +1 -1
  324. package/dist/commands/surface.d.ts +2 -0
  325. package/dist/commands/surface.js +43 -0
  326. package/dist/commands/sys/promptstudio.js +1 -1
  327. package/dist/commands/sys/settings.js +2 -2
  328. package/dist/commands/sys/setup-core.d.ts +88 -0
  329. package/dist/commands/sys/setup-core.js +352 -0
  330. package/dist/commands/sys/setup.d.ts +2 -0
  331. package/dist/commands/sys/setup.js +516 -0
  332. package/dist/commands/sys/sysprompt.js +3 -0
  333. package/dist/commands/sys.js +3 -2
  334. package/dist/commands/view-cycle.js +5 -5
  335. package/dist/commands/view-list.js +3 -3
  336. package/dist/commands/view-new.js +5 -5
  337. package/dist/commands/view-pick.js +6 -6
  338. package/dist/commands/view-run.js +14 -14
  339. package/dist/commands/view.js +3 -3
  340. package/dist/commands/workspace.js +10 -10
  341. package/dist/core/__tests__/boot.test.js +140 -0
  342. package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -27
  343. package/dist/core/__tests__/daemon-boot.test.js +22 -0
  344. package/dist/core/__tests__/fixtures/fake-engine.js +19 -9
  345. package/dist/core/__tests__/flagship-lifecycle.test.js +4 -1
  346. package/dist/core/__tests__/full/broker-attach-limits.test.js +1 -1
  347. package/dist/core/__tests__/full/broker-attach-stream.test.js +1 -1
  348. package/dist/core/__tests__/full/broker-crash-teardown.test.js +10 -5
  349. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +1 -1
  350. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +2 -2
  351. package/dist/core/__tests__/full/broker-pane-resolution.test.js +1 -1
  352. package/dist/core/__tests__/full/cascade-close.test.js +31 -18
  353. package/dist/core/__tests__/full/detach-focus.test.js +17 -3
  354. package/dist/core/__tests__/hearth-bootstrap.test.js +136 -0
  355. package/dist/core/__tests__/helpers/harness.js +1 -1
  356. package/dist/core/__tests__/live-mutation-verbs.test.js +17 -11
  357. package/dist/core/__tests__/live-mutation.test.js +15 -10
  358. package/dist/core/__tests__/migration.test.js +124 -0
  359. package/dist/core/__tests__/on-read-dedup-resume.test.js +40 -0
  360. package/dist/core/__tests__/preview-registry-sync.test.js +36 -0
  361. package/dist/core/__tests__/prune-to-limit.test.js +91 -0
  362. package/dist/core/__tests__/revive.test.js +64 -21
  363. package/dist/core/__tests__/trigger-migration.test.js +48 -0
  364. package/dist/core/__tests__/wake-bearings.test.js +23 -21
  365. package/dist/core/__tests__/wake-origin.test.js +36 -33
  366. package/dist/core/canvas/boot.d.ts +48 -0
  367. package/dist/core/canvas/boot.js +157 -0
  368. package/dist/core/canvas/canvas.d.ts +27 -1
  369. package/dist/core/canvas/canvas.js +86 -5
  370. package/dist/core/canvas/db.js +86 -1
  371. package/dist/core/canvas/index.d.ts +1 -1
  372. package/dist/core/canvas/index.js +1 -1
  373. package/dist/core/canvas/nav-model.js +1 -1
  374. package/dist/core/canvas/pid.d.ts +6 -0
  375. package/dist/core/canvas/pid.js +13 -0
  376. package/dist/core/canvas/triggers.d.ts +108 -0
  377. package/dist/core/canvas/triggers.js +320 -0
  378. package/dist/core/canvas/types.d.ts +128 -46
  379. package/dist/core/command.js +13 -4
  380. package/dist/core/hearth/__tests__/model-auth-guest.test.js +151 -0
  381. package/dist/core/hearth/config.d.ts +1 -0
  382. package/dist/core/hearth/config.js +36 -3
  383. package/dist/core/hearth/guest-env.d.ts +7 -0
  384. package/dist/core/hearth/guest-env.js +17 -1
  385. package/dist/core/hearth/index.d.ts +0 -1
  386. package/dist/core/hearth/index.js +0 -1
  387. package/dist/core/hearth/model-auth-guest.d.ts +8 -0
  388. package/dist/core/hearth/model-auth-guest.js +430 -0
  389. package/dist/core/hearth/provider.d.ts +13 -6
  390. package/dist/core/hearth/providers/blaxel-bootstrap.d.ts +2 -0
  391. package/dist/core/hearth/providers/blaxel-bootstrap.js +127 -19
  392. package/dist/core/hearth/providers/blaxel-home.d.ts +8 -4
  393. package/dist/core/hearth/providers/blaxel-home.js +85 -75
  394. package/dist/core/hearth/providers/blaxel.d.ts +5 -0
  395. package/dist/core/hearth/providers/blaxel.js +86 -12
  396. package/dist/core/hearth/providers/types.d.ts +6 -1
  397. package/dist/core/hearth/types.d.ts +35 -1
  398. package/dist/core/help.d.ts +16 -0
  399. package/dist/core/help.js +2 -0
  400. package/dist/core/memory-resolver.d.ts +8 -8
  401. package/dist/core/memory-resolver.js +58 -26
  402. package/dist/core/preview-registry.d.ts +25 -0
  403. package/dist/core/preview-registry.js +2047 -0
  404. package/dist/core/resolver.d.ts +1 -0
  405. package/dist/core/resolver.js +23 -16
  406. package/dist/core/runtime/bearings.d.ts +11 -10
  407. package/dist/core/runtime/bearings.js +8 -8
  408. package/dist/core/runtime/broker-protocol.d.ts +2 -2
  409. package/dist/core/runtime/broker-protocol.js +2 -2
  410. package/dist/core/runtime/close.js +2 -2
  411. package/dist/core/runtime/kickoff.js +1 -1
  412. package/dist/core/runtime/launch.d.ts +9 -3
  413. package/dist/core/runtime/launch.js +17 -9
  414. package/dist/core/runtime/lifecycle.js +7 -7
  415. package/dist/core/runtime/model-swap.js +1 -1
  416. package/dist/core/runtime/placement.d.ts +5 -5
  417. package/dist/core/runtime/placement.js +10 -10
  418. package/dist/core/runtime/recycle.js +7 -7
  419. package/dist/core/runtime/reset.d.ts +1 -1
  420. package/dist/core/runtime/reset.js +3 -3
  421. package/dist/core/runtime/revive-all.d.ts +5 -2
  422. package/dist/core/runtime/revive-all.js +5 -2
  423. package/dist/core/runtime/revive.d.ts +15 -8
  424. package/dist/core/runtime/revive.js +52 -16
  425. package/dist/core/runtime/spawn.d.ts +1 -1
  426. package/dist/core/runtime/spawn.js +7 -7
  427. package/dist/core/runtime/stop-guard.js +5 -5
  428. package/dist/core/runtime/surface-bg.js +1 -1
  429. package/dist/core/runtime/tmux.d.ts +1 -1
  430. package/dist/core/runtime/tmux.js +4 -4
  431. package/dist/core/scope.d.ts +9 -0
  432. package/dist/core/scope.js +37 -15
  433. package/dist/core/substrate/on-read.js +23 -21
  434. package/dist/core/substrate/render.js +3 -3
  435. package/dist/core/view/loader.js +2 -2
  436. package/dist/core/wake.d.ts +2 -2
  437. package/dist/core/wake.js +7 -7
  438. package/dist/daemon/__tests__/predicate-eval.test.js +109 -0
  439. package/dist/daemon/crtrd.js +222 -103
  440. package/dist/daemon/predicate-eval.d.ts +52 -0
  441. package/dist/daemon/predicate-eval.js +248 -0
  442. package/dist/hearth/control-plane/__tests__/node-message.test.js +60 -0
  443. package/dist/hearth/control-plane/__tests__/rate-limit-recurrence.test.js +49 -0
  444. package/dist/hearth/control-plane/__tests__/relay-security.test.js +314 -0
  445. package/dist/hearth/control-plane/__tests__/scheduler-scan-loop.test.js +133 -0
  446. package/dist/hearth/control-plane/__tests__/trigger-delivery.test.js +170 -0
  447. package/dist/hearth/control-plane/__tests__/webhook-ingress.test.js +167 -0
  448. package/dist/hearth/control-plane/config.d.ts +21 -0
  449. package/dist/hearth/control-plane/config.js +77 -0
  450. package/dist/hearth/control-plane/db.d.ts +30 -0
  451. package/dist/hearth/control-plane/db.js +534 -0
  452. package/dist/hearth/control-plane/ingress/rate-limit.d.ts +24 -0
  453. package/dist/hearth/control-plane/ingress/rate-limit.js +100 -0
  454. package/dist/hearth/control-plane/ingress/route-store.d.ts +31 -0
  455. package/dist/hearth/control-plane/ingress/route-store.js +61 -0
  456. package/dist/hearth/control-plane/ingress/webhook-delivery-store.d.ts +41 -0
  457. package/dist/hearth/control-plane/ingress/webhook-delivery-store.js +69 -0
  458. package/dist/hearth/control-plane/ingress/webhook-route.d.ts +55 -0
  459. package/dist/hearth/control-plane/ingress/webhook-route.js +285 -0
  460. package/dist/hearth/control-plane/main.js +88 -0
  461. package/dist/hearth/control-plane/node-message.d.ts +31 -0
  462. package/dist/hearth/control-plane/node-message.js +98 -0
  463. package/dist/hearth/control-plane/register.d.ts +15 -0
  464. package/dist/hearth/control-plane/register.js +34 -0
  465. package/dist/hearth/control-plane/registry.d.ts +17 -0
  466. package/dist/hearth/control-plane/registry.js +161 -0
  467. package/dist/hearth/control-plane/relay.d.ts +40 -0
  468. package/dist/hearth/{wake-proxy/proxy.js → control-plane/relay.js} +201 -275
  469. package/dist/hearth/control-plane/scheduler/fire-store.d.ts +36 -0
  470. package/dist/hearth/control-plane/scheduler/fire-store.js +73 -0
  471. package/dist/hearth/control-plane/scheduler/recurrence.d.ts +7 -0
  472. package/dist/hearth/control-plane/scheduler/recurrence.js +58 -0
  473. package/dist/hearth/control-plane/scheduler/scan-loop.d.ts +38 -0
  474. package/dist/hearth/control-plane/scheduler/scan-loop.js +138 -0
  475. package/dist/hearth/control-plane/scheduler/schedule-store.d.ts +32 -0
  476. package/dist/hearth/control-plane/scheduler/schedule-store.js +66 -0
  477. package/dist/hearth/control-plane/secrets.d.ts +17 -0
  478. package/dist/hearth/control-plane/secrets.js +113 -0
  479. package/dist/hearth/control-plane/server.d.ts +27 -0
  480. package/dist/hearth/control-plane/server.js +346 -0
  481. package/dist/hearth/control-plane/session.d.ts +68 -0
  482. package/dist/hearth/control-plane/session.js +273 -0
  483. package/dist/hearth/control-plane/triggers/acl.d.ts +14 -0
  484. package/dist/hearth/control-plane/triggers/acl.js +52 -0
  485. package/dist/hearth/control-plane/triggers/audit-store.d.ts +38 -0
  486. package/dist/hearth/control-plane/triggers/audit-store.js +79 -0
  487. package/dist/hearth/control-plane/triggers/deliver.d.ts +43 -0
  488. package/dist/hearth/control-plane/triggers/deliver.js +76 -0
  489. package/dist/hearth/control-plane/triggers/envelope.d.ts +29 -0
  490. package/dist/hearth/control-plane/triggers/envelope.js +38 -0
  491. package/dist/hearth/control-plane/types.d.ts +66 -0
  492. package/dist/hearth/control-plane/wake.d.ts +80 -0
  493. package/dist/hearth/control-plane/wake.js +312 -0
  494. package/dist/pi-extensions/canvas-doc-substrate.js +28 -2
  495. package/dist/pi-extensions/canvas-nav.js +1 -1
  496. package/dist/prompts/view.js +7 -8
  497. package/dist/types.js +4 -4
  498. package/dist/web-client/assets/index-DUThOUzU.css +2 -0
  499. package/dist/web-client/assets/index-IAJVtuVe.js +80 -0
  500. package/dist/web-client/index.html +2 -2
  501. package/package.json +12 -9
  502. package/scripts/postinstall.mjs +8 -0
  503. package/dist/clients/attach/__tests__/action-parity.test.js +0 -48
  504. package/dist/clients/attach/__tests__/autocomplete-and-bash-mode.test.js +0 -96
  505. package/dist/clients/attach/__tests__/bash-bang-routing.test.js +0 -58
  506. package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.js +0 -56
  507. package/dist/clients/attach/__tests__/clipboard-image.test.js +0 -76
  508. package/dist/clients/attach/__tests__/editor-newline.test.js +0 -82
  509. package/dist/clients/attach/__tests__/git-info.test.js +0 -31
  510. package/dist/clients/attach/__tests__/onrequest-wired.test.js +0 -20
  511. package/dist/clients/attach/__tests__/reconnect-giveup.test.js +0 -30
  512. package/dist/clients/attach/__tests__/slash-quit-copy.test.js +0 -42
  513. package/dist/clients/attach/__tests__/titled-editor.test.js +0 -60
  514. package/dist/commands/memory/__tests__/lint-schema.test.js +0 -52
  515. package/dist/core/__tests__/argv-parser.test.js +0 -217
  516. package/dist/core/__tests__/artifact-paths.test.js +0 -44
  517. package/dist/core/__tests__/draw-style.test.js +0 -258
  518. package/dist/core/__tests__/editor-label.test.d.ts +0 -1
  519. package/dist/core/__tests__/editor-label.test.js +0 -26
  520. package/dist/core/__tests__/fault-marker.test.d.ts +0 -1
  521. package/dist/core/__tests__/fault-marker.test.js +0 -112
  522. package/dist/core/__tests__/fault-retry-rewind.test.d.ts +0 -1
  523. package/dist/core/__tests__/fault-retry-rewind.test.js +0 -123
  524. package/dist/core/__tests__/frame-decoder-perf.test.d.ts +0 -1
  525. package/dist/core/__tests__/frame-decoder-perf.test.js +0 -224
  526. package/dist/core/__tests__/keystone.test.d.ts +0 -1
  527. package/dist/core/__tests__/keystone.test.js +0 -185
  528. package/dist/core/__tests__/listing-completeness.test.d.ts +0 -1
  529. package/dist/core/__tests__/listing-completeness.test.js +0 -31
  530. package/dist/core/__tests__/memory-resolver.test.d.ts +0 -1
  531. package/dist/core/__tests__/memory-resolver.test.js +0 -119
  532. package/dist/core/__tests__/memory.test.d.ts +0 -1
  533. package/dist/core/__tests__/memory.test.js +0 -60
  534. package/dist/core/__tests__/model-ladders.test.d.ts +0 -1
  535. package/dist/core/__tests__/model-ladders.test.js +0 -160
  536. package/dist/core/__tests__/node-env.test.d.ts +0 -1
  537. package/dist/core/__tests__/node-env.test.js +0 -26
  538. package/dist/core/__tests__/pane-column.test.d.ts +0 -1
  539. package/dist/core/__tests__/pane-column.test.js +0 -153
  540. package/dist/core/__tests__/persona-compose.test.d.ts +0 -1
  541. package/dist/core/__tests__/persona-compose.test.js +0 -53
  542. package/dist/core/__tests__/persona-subkind.test.d.ts +0 -1
  543. package/dist/core/__tests__/persona-subkind.test.js +0 -65
  544. package/dist/core/__tests__/persona.test.d.ts +0 -1
  545. package/dist/core/__tests__/persona.test.js +0 -107
  546. package/dist/core/__tests__/unknown-path.test.d.ts +0 -1
  547. package/dist/core/__tests__/unknown-path.test.js +0 -58
  548. package/dist/core/canvas/wakeups.d.ts +0 -76
  549. package/dist/core/canvas/wakeups.js +0 -185
  550. package/dist/core/hearth/registry.d.ts +0 -15
  551. package/dist/core/hearth/registry.js +0 -179
  552. package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.d.ts +0 -1
  553. package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.js +0 -289
  554. package/dist/hearth/wake-proxy/__tests__/config-timeout.test.d.ts +0 -1
  555. package/dist/hearth/wake-proxy/__tests__/config-timeout.test.js +0 -34
  556. package/dist/hearth/wake-proxy/__tests__/guest-source.test.d.ts +0 -1
  557. package/dist/hearth/wake-proxy/__tests__/guest-source.test.js +0 -203
  558. package/dist/hearth/wake-proxy/__tests__/hardening.test.d.ts +0 -1
  559. package/dist/hearth/wake-proxy/__tests__/hardening.test.js +0 -59
  560. package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.d.ts +0 -1
  561. package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.js +0 -372
  562. package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.d.ts +0 -1
  563. package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.js +0 -258
  564. package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.d.ts +0 -1
  565. package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.js +0 -437
  566. package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.d.ts +0 -1
  567. package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.js +0 -455
  568. package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.d.ts +0 -1
  569. package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.js +0 -15
  570. package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.d.ts +0 -1
  571. package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.js +0 -141
  572. package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.d.ts +0 -1
  573. package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.js +0 -143
  574. package/dist/hearth/wake-proxy/anthropic-oauth.d.ts +0 -58
  575. package/dist/hearth/wake-proxy/anthropic-oauth.js +0 -189
  576. package/dist/hearth/wake-proxy/auth.d.ts +0 -22
  577. package/dist/hearth/wake-proxy/auth.js +0 -128
  578. package/dist/hearth/wake-proxy/config.d.ts +0 -2
  579. package/dist/hearth/wake-proxy/config.js +0 -151
  580. package/dist/hearth/wake-proxy/guest-source.d.ts +0 -14
  581. package/dist/hearth/wake-proxy/guest-source.js +0 -130
  582. package/dist/hearth/wake-proxy/hearth-status.d.ts +0 -44
  583. package/dist/hearth/wake-proxy/hearth-status.js +0 -267
  584. package/dist/hearth/wake-proxy/home.d.ts +0 -67
  585. package/dist/hearth/wake-proxy/home.js +0 -297
  586. package/dist/hearth/wake-proxy/main.js +0 -134
  587. package/dist/hearth/wake-proxy/model-auth.d.ts +0 -13
  588. package/dist/hearth/wake-proxy/model-auth.js +0 -345
  589. package/dist/hearth/wake-proxy/proxy.d.ts +0 -35
  590. package/dist/hearth/wake-proxy/public-source-gate.d.ts +0 -9
  591. package/dist/hearth/wake-proxy/public-source-gate.js +0 -409
  592. package/dist/hearth/wake-proxy/redact.d.ts +0 -1
  593. package/dist/hearth/wake-proxy/redact.js +0 -17
  594. package/dist/hearth/wake-proxy/server.d.ts +0 -11
  595. package/dist/hearth/wake-proxy/server.js +0 -142
  596. package/dist/hearth/wake-proxy/state.d.ts +0 -18
  597. package/dist/hearth/wake-proxy/state.js +0 -342
  598. package/dist/hearth/wake-proxy/types.d.ts +0 -76
  599. package/dist/web-client/assets/index-BZUxTkv5.css +0 -2
  600. package/dist/web-client/assets/index-D36PNBj4.js +0 -80
  601. /package/dist/clients/attach/__tests__/{action-parity.test.d.ts → crtr-output-coverage.test.d.ts} +0 -0
  602. /package/dist/clients/attach/__tests__/{autocomplete-and-bash-mode.test.d.ts → crtr-output-render.test.d.ts} +0 -0
  603. /package/dist/{clients/attach/__tests__/bash-bang-routing.test.d.ts → core/__tests__/boot.test.d.ts} +0 -0
  604. /package/dist/{clients/attach/__tests__/bundle-pi-tui-dedup.test.d.ts → core/__tests__/hearth-bootstrap.test.d.ts} +0 -0
  605. /package/dist/{clients/attach/__tests__/clipboard-image.test.d.ts → core/__tests__/preview-registry-sync.test.d.ts} +0 -0
  606. /package/dist/{clients/attach/__tests__/editor-newline.test.d.ts → core/__tests__/prune-to-limit.test.d.ts} +0 -0
  607. /package/dist/{clients/attach/__tests__/git-info.test.d.ts → core/__tests__/trigger-migration.test.d.ts} +0 -0
  608. /package/dist/{clients/attach/__tests__/onrequest-wired.test.d.ts → core/hearth/__tests__/model-auth-guest.test.d.ts} +0 -0
  609. /package/dist/{clients/attach/__tests__/reconnect-giveup.test.d.ts → daemon/__tests__/predicate-eval.test.d.ts} +0 -0
  610. /package/dist/{clients/attach/__tests__/slash-quit-copy.test.d.ts → hearth/control-plane/__tests__/node-message.test.d.ts} +0 -0
  611. /package/dist/{clients/attach/__tests__/titled-editor.test.d.ts → hearth/control-plane/__tests__/rate-limit-recurrence.test.d.ts} +0 -0
  612. /package/dist/{commands/memory/__tests__/lint-schema.test.d.ts → hearth/control-plane/__tests__/relay-security.test.d.ts} +0 -0
  613. /package/dist/{core/__tests__/argv-parser.test.d.ts → hearth/control-plane/__tests__/scheduler-scan-loop.test.d.ts} +0 -0
  614. /package/dist/{core/__tests__/artifact-paths.test.d.ts → hearth/control-plane/__tests__/trigger-delivery.test.d.ts} +0 -0
  615. /package/dist/{core/__tests__/draw-style.test.d.ts → hearth/control-plane/__tests__/webhook-ingress.test.d.ts} +0 -0
  616. /package/dist/hearth/{wake-proxy → control-plane}/main.d.ts +0 -0
  617. /package/dist/hearth/{wake-proxy → control-plane}/types.js +0 -0
@@ -1,10 +1,42 @@
1
+ // control-plane/relay.ts — the CP→home HTTP+WS relay engine (P4.3 / part-plan
2
+ // T3.2). Implements the `RelayDispatcher` seam `server.ts` defines: every
3
+ // call here already passed `respondDynamicLane`'s/`handleUpgrade`'s
4
+ // session+registry gate (P4.1) — `home` is the registry row resolved FRESH
5
+ // from the caller's own session this request, never from anything client-
6
+ // supplied (R-CP-2). This module's only job is wake (P4.2's `ensureAwake`)
7
+ // plus the actual byte/frame relay to `home.preview_endpoint`, generalizing
8
+ // M0 `wake-proxy/proxy.ts` from a single-tenant/single-home proxy onto the
9
+ // CP's per-request resolved `Home` row.
10
+ //
11
+ // Re-binding (R-CP-6 / criterion 5): the upstream origin is always
12
+ // `home.preview_endpoint` (resolved by `ensureAwake`, never the request URL)
13
+ // and the WS node target is always `home.home_agent_target` — both read off
14
+ // the `home` row this function was called with. A client cannot widen or
15
+ // redirect the route by supplying `?target=` or a different `/node/<id>`
16
+ // path segment: this design's home model is a single resident root per home
17
+ // (design.md F1 — `home_agent_target` is the only legitimate relay target),
18
+ // and home selection itself is entirely session-derived upstream of this
19
+ // module (server.ts resolves `home` from the session on every call, never
20
+ // from the client). Re-deriving the target from the client path here would
21
+ // only reintroduce the cross-home surface this design avoids; a session for
22
+ // home A can therefore never reach home B's broker through this relay no
23
+ // matter what `?target=`/path id it sends — home B's `preview_endpoint` is
24
+ // never even looked up for that session.
25
+ //
26
+ // Two credentials, two legs (S4): the relay token is resolved by
27
+ // `ensureAwake` (via `secrets.ts`, from `relay_auth_ref`) and injected as the
28
+ // CP→home `Authorization: Bearer` header; the browser/worker leg's own
29
+ // Authorization/Cookie/Proxy-* headers are stripped before the request ever
30
+ // reaches the upstream fetch/WS call (R-CP-3). The browser/worker leg never
31
+ // sees or reflects the relay token.
1
32
  import { Readable } from 'node:stream';
2
33
  import { WebSocket, WebSocketServer } from 'ws';
3
34
  import { BROKER_READ_CAPS } from '../../core/runtime/broker-protocol.js';
4
- import { CrtrError, general } from '../../core/errors.js';
5
- import { loadProxyState, ensureProxyState } from './state.js';
6
- import { acquireActivity, ensureAwake, invalidateWarmVerdict, releaseActivity, resolveRunningHome } from './home.js';
7
- import { ownerAuthRedactedMessage, resolveOwnerAuth, setOwnerCookie } from './auth.js';
35
+ import { general } from '../../core/errors.js';
36
+ import { loadControlPlaneConfig } from './config.js';
37
+ import { ensureAwake, invalidateWarmVerdict, resolveRunning } from './wake.js';
38
+ import { redactSecrets } from './secrets.js';
39
+ import { tenantSessionAuthRedactedMessage } from './session.js';
8
40
  const hopByHopHeaders = new Set([
9
41
  'connection',
10
42
  'keep-alive',
@@ -16,11 +48,8 @@ const hopByHopHeaders = new Set([
16
48
  'transfer-encoding',
17
49
  'upgrade',
18
50
  ]);
19
- function currentState(runtime) {
20
- return loadProxyState(runtime.proxy.statePath) ?? ensureProxyState(runtime.proxy);
21
- }
22
51
  function redact(message) {
23
- return ownerAuthRedactedMessage(message).replace(/\bsha256:[0-9a-f]{64}\b/gi, 'sha256:[redacted]');
52
+ return redactSecrets(tenantSessionAuthRedactedMessage(message));
24
53
  }
25
54
  function redactDeep(value) {
26
55
  if (typeof value === 'string')
@@ -32,96 +61,17 @@ function redactDeep(value) {
32
61
  }
33
62
  return value;
34
63
  }
35
- export function serializeWakeProxyError(error) {
36
- if (error instanceof CrtrError) {
37
- return {
38
- error: {
39
- code: error.code,
40
- message: redact(error.message),
41
- exitCode: error.exitCode,
42
- ...(error.details === undefined ? {} : { details: redactDeep(error.details) }),
43
- },
44
- };
45
- }
46
- if (error instanceof Error) {
47
- return { error: { message: redact(error.message) } };
48
- }
49
- return { error: { message: redact(String(error)) } };
50
- }
64
+ /** Log a relay-side failure server-side only — never sent to the browser
65
+ * (callers always respond with a generic status + short body). Every field
66
+ * is redacted so a resolved relay token, a session cookie/bearer value, or
67
+ * an `Authorization:`/`?token=` fragment captured in an upstream error
68
+ * message can never reach stderr unredacted (criterion 7). */
51
69
  function logError(message, details = {}) {
52
- process.stderr.write(`${JSON.stringify({ level: 'error', message, details })}\n`);
70
+ process.stderr.write(`${JSON.stringify({ level: 'error', message, details: redactDeep(details) })}\n`);
53
71
  }
54
72
  function requestPath(req) {
55
73
  return req.url ?? '/';
56
74
  }
57
- function requestPathname(req) {
58
- return new URL(requestPath(req), 'http://127.0.0.1').pathname;
59
- }
60
- const publicStaticAssetPaths = new Set([
61
- '/favicon.ico',
62
- '/favicon.svg',
63
- '/favicon.png',
64
- '/apple-touch-icon.png',
65
- '/apple-touch-icon-precomposed.png',
66
- '/manifest.webmanifest',
67
- '/site.webmanifest',
68
- '/robots.txt',
69
- '/vite.svg',
70
- ]);
71
- const publicStaticAssetExtensions = new Set([
72
- '.css',
73
- '.js',
74
- '.mjs',
75
- '.map',
76
- '.png',
77
- '.jpg',
78
- '.jpeg',
79
- '.gif',
80
- '.webp',
81
- '.svg',
82
- '.ico',
83
- '.json',
84
- '.txt',
85
- ]);
86
- export function isPublicStaticAssetPath(pathname) {
87
- if (pathname.startsWith('/assets/'))
88
- return true;
89
- if (publicStaticAssetPaths.has(pathname))
90
- return true;
91
- const match = /^\/[^/?#]+(\.[^/?#]+)$/.exec(pathname);
92
- return match !== null && publicStaticAssetExtensions.has(match[1].toLowerCase());
93
- }
94
- function stripTokenFromTarget(rawUrl) {
95
- const url = new URL(rawUrl, 'http://127.0.0.1');
96
- url.searchParams.delete('token');
97
- const query = url.searchParams.toString();
98
- return `${url.pathname}${query === '' ? '' : `?${query}`}`;
99
- }
100
- function extractNodeId(pathname) {
101
- const match = /^\/node\/([^/?#]+)\/?$/.exec(pathname);
102
- if (match === null)
103
- return null;
104
- try {
105
- const nodeId = decodeURIComponent(match[1]);
106
- if (nodeId === '' || /[/\\]/.test(nodeId) || nodeId.includes('..'))
107
- return null;
108
- return nodeId;
109
- }
110
- catch {
111
- return null;
112
- }
113
- }
114
- function validateOriginFormRequestTarget(rawRequestUrl) {
115
- const raw = rawRequestUrl === undefined || rawRequestUrl === '' ? '/' : rawRequestUrl;
116
- if (!raw.startsWith('/')) {
117
- throw general('proxy only accepts origin-form request targets', { requestUrl: raw.replace(/\?.*$/, '') });
118
- }
119
- if (raw.startsWith('//')) {
120
- throw general('proxy rejected scheme-relative request target', { requestUrl: raw.replace(/\?.*$/, '') });
121
- }
122
- decodePathForValidation(raw);
123
- return raw;
124
- }
125
75
  function decodePathForValidation(raw) {
126
76
  for (let i = 0; i < raw.length; i += 1) {
127
77
  const ch = raw[i];
@@ -129,40 +79,71 @@ function decodePathForValidation(raw) {
129
79
  const a = raw[i + 1];
130
80
  const b = raw[i + 2];
131
81
  if (a === undefined || b === undefined || !/[0-9A-Fa-f]/.test(a) || !/[0-9A-Fa-f]/.test(b)) {
132
- throw general('proxy rejected malformed percent-encoding in request target', { requestUrl: '[redacted]' });
82
+ throw general('relay rejected malformed percent-encoding in request target', { requestUrl: '[redacted]' });
133
83
  }
134
84
  const decoded = Number.parseInt(`${a}${b}`, 16);
135
85
  if (decoded <= 0x1f || decoded === 0x7f || decoded === 0x5c) {
136
- throw general('proxy rejected control or backslash characters in request target', { requestUrl: '[redacted]' });
86
+ throw general('relay rejected control or backslash characters in request target', { requestUrl: '[redacted]' });
137
87
  }
138
88
  i += 2;
139
89
  continue;
140
90
  }
141
91
  if (ch === '\\' || ch === '\u0000' || ch < ' ' || ch === '\u007f') {
142
- throw general('proxy rejected control characters in request target', { requestUrl: '[redacted]' });
92
+ throw general('relay rejected control characters in request target', { requestUrl: '[redacted]' });
143
93
  }
144
94
  }
145
95
  }
146
- export function buildUpstreamHttpUrl(routeUrl, rawRequestUrl) {
147
- const route = new URL(routeUrl);
96
+ /** Origin-form-only request target validation (criterion 4): rejects
97
+ * scheme-relative (`//evil`) and any target that doesn't start with `/`,
98
+ * and rejects control/backslash characters (raw or percent-encoded) before
99
+ * the target is ever joined onto the upstream origin. */
100
+ function validateOriginFormRequestTarget(rawRequestUrl) {
101
+ const raw = rawRequestUrl === undefined || rawRequestUrl === '' ? '/' : rawRequestUrl;
102
+ if (!raw.startsWith('/')) {
103
+ throw general('relay only accepts origin-form request targets', { requestUrl: raw.replace(/\?.*$/, '') });
104
+ }
105
+ if (raw.startsWith('//')) {
106
+ throw general('relay rejected scheme-relative request target', { requestUrl: raw.replace(/\?.*$/, '') });
107
+ }
108
+ decodePathForValidation(raw);
109
+ return raw;
110
+ }
111
+ /** Join the validated origin-form request target onto `previewEndpoint` and
112
+ * reject anything that would escape that origin (criterion 4: "reject
113
+ * scheme-relative/absolute external escapes"). */
114
+ export function buildUpstreamHttpUrl(previewEndpoint, rawRequestUrl) {
115
+ const route = new URL(previewEndpoint);
148
116
  const raw = validateOriginFormRequestTarget(rawRequestUrl);
149
117
  const upstream = new URL(raw, route);
150
118
  if (upstream.origin !== route.origin) {
151
- throw general('proxy rejected request target that escapes the upstream origin', { requestUrl: raw.replace(/\?.*$/, '') });
119
+ throw general('relay rejected request target that escapes the upstream origin', { requestUrl: raw.replace(/\?.*$/, '') });
152
120
  }
153
121
  upstream.searchParams.delete('token');
154
- if (upstream.origin !== route.origin) {
155
- throw general('proxy rejected upstream origin mismatch', { requestUrl: raw.replace(/\?.*$/, '') });
156
- }
157
122
  return upstream;
158
123
  }
124
+ /** Strip every browser-leg auth header (Authorization/Cookie/Proxy-*) and
125
+ * every client-supplied forwarding/host-metadata header (Forwarded,
126
+ * X-Forwarded-*, X-Real-IP) before forwarding upstream — the relay is a
127
+ * single hop behind the CP, so the home should see no forwarding metadata
128
+ * at all rather than an attacker-controlled one — then inject the CP→home
129
+ * relay token as the sole Authorization header (criterion 2). */
159
130
  function filteredRequestHeaders(req, relayToken) {
160
131
  const headers = new Headers();
161
132
  for (const [name, value] of Object.entries(req.headers)) {
162
133
  if (value === undefined)
163
134
  continue;
164
135
  const lower = name.toLowerCase();
165
- if (lower === 'host' || lower === 'authorization' || lower === 'cookie' || lower === 'referer' || lower === 'referrer' || lower.startsWith('proxy-') || lower.startsWith('sec-websocket-') || hopByHopHeaders.has(lower)) {
136
+ if (lower === 'host' ||
137
+ lower === 'authorization' ||
138
+ lower === 'cookie' ||
139
+ lower === 'referer' ||
140
+ lower === 'referrer' ||
141
+ lower === 'forwarded' ||
142
+ lower === 'x-real-ip' ||
143
+ lower.startsWith('proxy-') ||
144
+ lower.startsWith('sec-websocket-') ||
145
+ lower.startsWith('x-forwarded-') ||
146
+ hopByHopHeaders.has(lower)) {
166
147
  continue;
167
148
  }
168
149
  headers.set(lower, Array.isArray(value) ? value.join(',') : value);
@@ -171,14 +152,17 @@ function filteredRequestHeaders(req, relayToken) {
171
152
  headers.set('accept-encoding', 'identity');
172
153
  return headers;
173
154
  }
155
+ /** Rewrite an upstream redirect to stay same-origin on the CP (criterion 3).
156
+ * A relative Location is forwarded verbatim (already same-origin to
157
+ * whatever origin the browser/worker considers itself on). An absolute
158
+ * Location back to the upstream route origin is rewritten to a CP-relative
159
+ * path so the browser never learns/visits the upstream origin directly; any
160
+ * other absolute origin is dropped. */
174
161
  function sanitizeLocation(location, upstreamOrigin) {
175
- // Same-origin relative redirect (origin-form) is safe to forward verbatim.
176
- if (location.startsWith('/') && !location.startsWith('//'))
162
+ if (location.startsWith('/') && !location.startsWith('//') && !location.includes('\\'))
177
163
  return location;
178
164
  try {
179
165
  const abs = new URL(location, upstreamOrigin);
180
- // An absolute redirect back to the upstream route origin is rewritten to a Hearth-relative path so
181
- // the browser stays behind the front door; any other absolute origin is dropped entirely.
182
166
  if (abs.origin === upstreamOrigin)
183
167
  return `${abs.pathname}${abs.search}${abs.hash}`;
184
168
  }
@@ -190,7 +174,7 @@ function sanitizeLocation(location, upstreamOrigin) {
190
174
  function applyResponseHeaders(res, headers, upstreamOrigin) {
191
175
  headers.forEach((value, key) => {
192
176
  const lower = key.toLowerCase();
193
- if (lower === 'set-cookie' || hopByHopHeaders.has(lower) || lower.startsWith('proxy-'))
177
+ if (lower === 'set-cookie' || lower === 'authorization' || hopByHopHeaders.has(lower) || lower.startsWith('proxy-'))
194
178
  return;
195
179
  if (lower === 'location') {
196
180
  const sanitized = sanitizeLocation(value, upstreamOrigin);
@@ -265,7 +249,7 @@ async function streamResponseBody(body, res, signal) {
265
249
  reader.releaseLock();
266
250
  }
267
251
  }
268
- async function withWakeTimeout(work, timeoutMs, label) {
252
+ async function withTimeout(work, timeoutMs, label) {
269
253
  if (timeoutMs <= 0)
270
254
  return work;
271
255
  let timer = null;
@@ -283,25 +267,30 @@ async function withWakeTimeout(work, timeoutMs, label) {
283
267
  clearTimeout(timer);
284
268
  }
285
269
  }
286
- export const proxyInternals = {
287
- withWakeTimeout,
288
- attachWsKeepalive,
289
- proxyWebSocketBrowser,
290
- };
291
270
  function closeHttpWithError(res, statusCode, message) {
292
271
  if (!res.headersSent) {
293
- res.writeHead(statusCode, { 'content-type': 'text/plain; charset=utf-8' });
272
+ res.writeHead(statusCode, { 'content-type': 'text/plain; charset=utf-8', 'cache-control': 'no-store' });
294
273
  }
295
274
  res.end(`${message}\n`);
296
275
  }
276
+ function addRequestAbort(req, res, controller) {
277
+ const abort = () => controller.abort();
278
+ req.once('aborted', abort);
279
+ res.once('close', abort);
280
+ return () => {
281
+ req.off('aborted', abort);
282
+ res.off('close', abort);
283
+ };
284
+ }
297
285
  /**
298
- * Forward one HTTP request to an already-selected upstream route and stream the response back.
299
- * Returns normally once the response is fully relayed; throws on a genuine upstream/network
300
- * failure (connect refused/reset, DNS, body-stream error). An app-level 4xx/5xx is a RESOLVED
301
- * fetch and is relayed verbatim it never throws here, so it is never mistaken for a dead home.
286
+ * Forward one HTTP request to the already-awakened home and stream the
287
+ * response back. Returns normally once the response is fully relayed;
288
+ * throws on a genuine upstream/network failure (connect refused/reset, DNS,
289
+ * body-stream error)an app-level 4xx/5xx is a RESOLVED fetch and is
290
+ * relayed verbatim, never thrown here.
302
291
  */
303
292
  async function forwardUpstream(req, res, awakened, controller) {
304
- const upstreamUrl = buildUpstreamHttpUrl(awakened.routeUrl, requestPath(req));
293
+ const upstreamUrl = buildUpstreamHttpUrl(awakened.preview_endpoint, requestPath(req));
305
294
  const method = req.method ?? 'GET';
306
295
  const canHaveBody = method !== 'GET' && method !== 'HEAD';
307
296
  const requestInit = {
@@ -316,12 +305,11 @@ async function forwardUpstream(req, res, awakened, controller) {
316
305
  const response = await fetch(upstreamUrl, requestInit);
317
306
  const responseHeaders = new Headers(response.headers);
318
307
  const isEventStream = /text\/event-stream/i.test(responseHeaders.get('content-type') ?? '');
319
- if (isEventStream) {
308
+ if (isEventStream)
320
309
  responseHeaders.delete('content-length');
321
- }
322
310
  res.statusCode = response.status;
323
311
  res.statusMessage = response.statusText;
324
- applyResponseHeaders(res, responseHeaders, new URL(awakened.routeUrl).origin);
312
+ applyResponseHeaders(res, responseHeaders, new URL(awakened.preview_endpoint).origin);
325
313
  tuneStreamingHeaders(res, isEventStream);
326
314
  if (response.body === null || method === 'HEAD') {
327
315
  res.end();
@@ -332,113 +320,61 @@ async function forwardUpstream(req, res, awakened, controller) {
332
320
  if (!res.writableEnded)
333
321
  res.end();
334
322
  }
335
- function addRequestAbort(req, res, controller) {
336
- const abort = () => controller.abort();
337
- req.once('aborted', abort);
338
- res.once('close', abort);
339
- return () => {
340
- req.off('aborted', abort);
341
- res.off('close', abort);
342
- };
343
- }
344
- export async function proxyHttpRequest(req, res, runtime) {
345
- const pathname = requestPathname(req);
346
- const isPublicStaticAsset = (req.method === 'GET' || req.method === 'HEAD') && isPublicStaticAssetPath(pathname);
347
- const state = currentState(runtime);
348
- let auth = null;
349
- try {
350
- auth = resolveOwnerAuth(req, runtime.proxy, state);
351
- }
352
- catch {
353
- if (!isPublicStaticAsset) {
354
- if (!res.headersSent)
355
- closeHttpWithError(res, 403, 'forbidden');
356
- return;
357
- }
358
- }
359
- if (auth === null && !isPublicStaticAsset) {
360
- if (!res.headersSent)
361
- closeHttpWithError(res, 401, 'owner token required');
362
- return;
363
- }
364
- const requestAuth = auth ?? {
365
- ownerUserId: state.owner.ownerUserId,
366
- tenantId: state.owner.defaultTenantId,
367
- source: 'cookie',
368
- token: '',
369
- };
370
- // An owner token in a ?token= query must never persist in the browser URL/history or be used to
371
- // serve a proxied response. On a GET/HEAD deep link, convert it to the HttpOnly cookie and 303
372
- // to the same tokenless path (mirroring GET /); reject it on any other method so the client
373
- // retries via cookie/Bearer. The only legitimate token URL is the one immediately swapped here.
374
- if (requestAuth.source === 'query') {
375
- if (req.method === 'GET' || req.method === 'HEAD') {
376
- setOwnerCookie(res, requestAuth.token, runtime.proxy);
377
- res.writeHead(303, {
378
- location: stripTokenFromTarget(requestPath(req)),
379
- 'cache-control': 'no-store',
380
- 'referrer-policy': 'no-referrer',
381
- });
382
- res.end();
383
- return;
384
- }
385
- if (!res.headersSent)
386
- closeHttpWithError(res, 401, 'owner token required');
387
- return;
388
- }
389
- const activity = acquireActivity(requestAuth.tenantId, 'http');
323
+ /** Forward one HTTP request to `home` (criterion 1: only after the caller's
324
+ * session/registry gate already resolved `home`, and only after
325
+ * `ensureAwake(home.home_id)` succeeds). Mirrors M0 `proxy.ts`'s
326
+ * fast-path-then-escalate shape: a fresh warm-verdict cache hit
327
+ * (`resolveRunning`, P4.2) is forwarded directly without re-entering the
328
+ * wake pipeline; only a missing/stale verdict, or a running route that just
329
+ * failed on a safely-replayable method, escalates to a bounded
330
+ * `ensureAwake`. */
331
+ export async function proxyHttp(req, res, home, deps = {}) {
332
+ const ensureAwakeImpl = deps.ensureAwake ?? ensureAwake;
333
+ const resolveRunningImpl = deps.resolveRunning ?? resolveRunning;
334
+ const invalidate = deps.invalidateWarmVerdict ?? invalidateWarmVerdict;
335
+ const config = (deps.loadConfig ?? loadControlPlaneConfig)();
390
336
  const controller = new AbortController();
391
337
  const cleanup = addRequestAbort(req, res, controller);
392
338
  try {
393
- // Fast path: a home crtr already records as `running` with a known route+token is forwarded
394
- // directly — the forward itself is the liveness check. Normal GET/asset/SSE traffic must NOT
395
- // enter the heavy ensureAwake/restore gate (probe + 150s serial guest execs) while the direct
396
- // home route is serving 200 in ~0.1s. Only a missing/not-running home, or a CLEAR upstream
397
- // failure against the trusted route, escalates to the deliberate wake path below.
398
- const running = resolveRunningHome(requestAuth.tenantId);
339
+ const running = resolveRunningImpl(home.home_id);
399
340
  if (running !== null) {
400
341
  try {
401
342
  await forwardUpstream(req, res, running, controller);
402
343
  return;
403
344
  }
404
345
  catch (error) {
405
- // Reaching here means a genuine upstream/network failure (app 4xx/5xx never throw). If
406
- // nothing was sent, the client is still here, and the request is safe to replay (no body),
407
- // the running verdict was stale — invalidate it and escalate to ONE deliberate wake.
408
- // Anything else (mid-stream failure, aborted, or a body-bearing method we can't replay)
409
- // rethrows to the handler's error path, which 502s and invalidates the warm verdict.
410
346
  const method = req.method ?? 'GET';
411
347
  const replayable = method === 'GET' || method === 'HEAD';
412
348
  if (res.headersSent || controller.signal.aborted || !replayable)
413
349
  throw error;
414
- logError('hearth wake proxy running-route forward failed; escalating to deliberate wake', {
350
+ logError('hearth control plane relay running-route forward failed; escalating to deliberate wake', {
351
+ home_id: home.home_id,
415
352
  path: requestPath(req).replace(/\?.*$/, ''),
416
- ...serializeWakeProxyError(error),
353
+ error: error instanceof Error ? error.message : String(error),
417
354
  });
418
- invalidateWarmVerdict(requestAuth.tenantId);
355
+ invalidate(home.home_id);
419
356
  }
420
357
  }
421
- // Deliberate wake path: missing/not-running home, or a stale running verdict that just failed.
422
- // Bounded by wakeTimeoutMs; ensureAwake probes/restores under the per-tenant lock.
423
- const awakened = await withWakeTimeout(ensureAwake(requestAuth.tenantId), runtime.proxy.wakeTimeoutMs, 'wake proxy request');
358
+ const awakened = await withTimeout(ensureAwakeImpl(home.home_id), config.wakeTimeoutMs, 'control plane relay wake');
424
359
  if (controller.signal.aborted)
425
360
  throw general('request closed while waking');
426
361
  await forwardUpstream(req, res, awakened, controller);
427
362
  }
428
363
  catch (error) {
429
364
  const message = error instanceof Error ? error.message : String(error);
430
- logError('hearth wake proxy HTTP request failed', { path: requestPath(req).replace(/\?.*$/, ''), ...serializeWakeProxyError(error) });
431
- // An upstream forward failure (bad gateway / wake timeout) may mean the home died mid-TTL. Drop
432
- // the cached warm verdict so the next request re-probes/restores instead of serving the stale
433
- // "serving" answer for the rest of the window. Pure request-validation errors leave it intact.
434
- if (!message.startsWith('proxy '))
435
- invalidateWarmVerdict(requestAuth.tenantId);
436
- if (controller.signal.aborted && /timed out/i.test(message)) {
365
+ logError('hearth control plane relay HTTP request failed', {
366
+ home_id: home.home_id,
367
+ path: requestPath(req).replace(/\?.*$/, ''),
368
+ error: message,
369
+ });
370
+ if (!message.startsWith('relay '))
371
+ invalidate(home.home_id);
372
+ if (/timed out/i.test(message)) {
437
373
  closeHttpWithError(res, 504, 'wake timeout');
438
374
  return;
439
375
  }
440
376
  if (!res.headersSent) {
441
- closeHttpWithError(res, message.startsWith('proxy ') ? 400 : 502, message.startsWith('proxy ') ? 'bad request' : 'bad gateway');
377
+ closeHttpWithError(res, message.startsWith('relay ') ? 400 : 502, message.startsWith('relay ') ? 'bad request' : 'bad gateway');
442
378
  return;
443
379
  }
444
380
  try {
@@ -450,20 +386,21 @@ export async function proxyHttpRequest(req, res, runtime) {
450
386
  }
451
387
  finally {
452
388
  cleanup();
453
- releaseActivity(activity);
454
389
  }
455
390
  }
456
- function toWssUrl(routeUrl, nodeId) {
457
- const url = new URL(routeUrl);
458
- url.protocol = 'wss:';
459
- url.pathname = `/node/${encodeURIComponent(nodeId)}`;
391
+ // --- WebSocket relay --------------------------------------------------
392
+ /** Build the upstream `wss://`/`ws://` URL for the home's single resident-
393
+ * root target. `target` is always `home.home_agent_target` (server-derived,
394
+ * never the client's request path — see module header). */
395
+ function toWssUrl(previewEndpoint, target) {
396
+ const url = new URL(previewEndpoint);
397
+ url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
398
+ url.pathname = `/node/${encodeURIComponent(target)}`;
460
399
  url.search = '';
461
400
  url.hash = '';
462
401
  return url.toString();
463
402
  }
464
403
  function sendableCloseCode(code) {
465
- // 1005 (no status) and 1006 (abnormal) are reserved and must never be sent; clamp anything
466
- // outside the sendable ranges back to 1000 so close() does not throw.
467
404
  if (!Number.isInteger(code) || code === 1005 || code === 1006 || code < 1000 || code > 4999)
468
405
  return 1000;
469
406
  return code;
@@ -482,6 +419,8 @@ function sendSocketClose(socket, code, reason) {
482
419
  }
483
420
  }
484
421
  const wsKeepaliveIntervalMs = 25_000;
422
+ /** 25s ping/pong keepalive (M0 shape, kept verbatim — criterion 4). A socket
423
+ * that never pongs back is terminated rather than left to leak. */
485
424
  function attachWsKeepalive(socket, context, options = {}) {
486
425
  const intervalMs = options.intervalMs ?? wsKeepaliveIntervalMs;
487
426
  let alive = true;
@@ -513,7 +452,7 @@ function attachWsKeepalive(socket, context, options = {}) {
513
452
  if (stopped || socket.readyState !== WebSocket.OPEN)
514
453
  return;
515
454
  if (!alive) {
516
- terminateStaleSocket('hearth wake proxy ws keepalive stale');
455
+ terminateStaleSocket('hearth control plane relay ws keepalive stale');
517
456
  return;
518
457
  }
519
458
  alive = false;
@@ -521,7 +460,7 @@ function attachWsKeepalive(socket, context, options = {}) {
521
460
  socket.ping();
522
461
  }
523
462
  catch {
524
- terminateStaleSocket('hearth wake proxy ws keepalive ping failed');
463
+ terminateStaleSocket('hearth control plane relay ws keepalive ping failed');
525
464
  }
526
465
  };
527
466
  socket.on('pong', onPong);
@@ -532,25 +471,28 @@ function attachWsKeepalive(socket, context, options = {}) {
532
471
  function createUpgradeServer() {
533
472
  return new WebSocketServer({ noServer: true, maxPayload: BROKER_READ_CAPS.maxLineBytes });
534
473
  }
535
- async function proxyWebSocketBrowser(browserWs, nodeId, tenantId, runtime, deps = {}) {
474
+ /** Bridge one already-upgraded browser WebSocket to the home's resident-root
475
+ * broker over `wss://<preview_endpoint>/node/<home_agent_target>`, carrying
476
+ * the relay token as the upstream Authorization header (never reflected
477
+ * back to the browser leg). Keepalive/teardown/close-code handling mirrors
478
+ * M0 `proxy.ts`'s `proxyWebSocketBrowser` (criterion 4). */
479
+ async function proxyWebSocketBrowser(browserWs, home, deps = {}) {
536
480
  const ensureAwakeImpl = deps.ensureAwake ?? ensureAwake;
481
+ const config = (deps.loadConfig ?? loadControlPlaneConfig)();
537
482
  const createUpstream = deps.createUpstream ??
538
- ((url, relayToken) => new WebSocket(url, { headers: { authorization: `Bearer ${relayToken}` }, perMessageDeflate: false }));
539
- const activity = acquireActivity(tenantId, 'ws');
483
+ ((url, relayToken) => new WebSocket(url, {
484
+ headers: { authorization: `Bearer ${relayToken}` },
485
+ perMessageDeflate: false,
486
+ handshakeTimeout: config.readyTimeoutMs,
487
+ maxPayload: BROKER_READ_CAPS.maxLineBytes,
488
+ }));
540
489
  const handshakeAt = Date.now();
541
490
  let upstream = null;
542
- let settled = false;
543
491
  let teardownStarted = false;
544
492
  let upstreamOpenAt = null;
545
493
  let browserClose = null;
546
494
  let upstreamClose = null;
547
495
  const queued = [];
548
- const release = () => {
549
- if (settled)
550
- return;
551
- settled = true;
552
- releaseActivity(activity);
553
- };
554
496
  let stopBrowserKeepalive = () => { };
555
497
  let stopUpstreamKeepalive = () => { };
556
498
  const stopKeepalives = () => {
@@ -562,13 +504,11 @@ async function proxyWebSocketBrowser(browserWs, nodeId, tenantId, runtime, deps
562
504
  return;
563
505
  teardownStarted = true;
564
506
  stopKeepalives();
565
- release();
566
507
  };
567
- stopBrowserKeepalive = attachWsKeepalive(browserWs, { nodeId, tenantId, leg: 'browser' }, { onStale: beginTeardown });
508
+ stopBrowserKeepalive = attachWsKeepalive(browserWs, { home_id: home.home_id, leg: 'browser' }, { onStale: beginTeardown });
568
509
  const logClose = (leg, code, reason) => {
569
- logError('hearth wake proxy ws close', {
570
- nodeId,
571
- tenantId,
510
+ logError('hearth control plane relay ws close', {
511
+ home_id: home.home_id,
572
512
  leg,
573
513
  code,
574
514
  reason,
@@ -613,16 +553,19 @@ async function proxyWebSocketBrowser(browserWs, nodeId, tenantId, runtime, deps
613
553
  }
614
554
  });
615
555
  browserWs.on('error', (error) => {
616
- logError('hearth wake proxy browser websocket failed', { nodeId, error: redact(error instanceof Error ? error.message : String(error)) });
556
+ logError('hearth control plane relay browser websocket failed', { home_id: home.home_id, error: error instanceof Error ? error.message : String(error) });
617
557
  closeBoth(1011, 'browser websocket error');
618
558
  });
619
559
  try {
620
- const awakened = await withWakeTimeout(ensureAwakeImpl(tenantId), runtime.proxy.wakeTimeoutMs, 'wake proxy websocket');
560
+ const awakened = await withTimeout(ensureAwakeImpl(home.home_id), config.wakeTimeoutMs, 'control plane relay websocket wake');
561
+ const target = home.home_agent_target?.trim() ?? '';
562
+ if (target === '')
563
+ throw general(`home ${home.home_id} is missing home_agent_target — cannot relay`, { home_id: home.home_id });
621
564
  if (browserWs.readyState !== WebSocket.OPEN) {
622
565
  beginTeardown();
623
566
  return;
624
567
  }
625
- upstream = createUpstream(toWssUrl(awakened.routeUrl, nodeId), awakened.relayToken);
568
+ upstream = createUpstream(toWssUrl(awakened.preview_endpoint, target), awakened.relayToken);
626
569
  upstream.on('open', () => {
627
570
  if (teardownStarted || browserWs.readyState !== WebSocket.OPEN) {
628
571
  beginTeardown();
@@ -632,14 +575,7 @@ async function proxyWebSocketBrowser(browserWs, nodeId, tenantId, runtime, deps
632
575
  return;
633
576
  }
634
577
  upstreamOpenAt = Date.now();
635
- logError('hearth wake proxy ws upstream open', {
636
- nodeId,
637
- tenantId,
638
- handshakeToUpstreamOpenMs: upstreamOpenAt - handshakeAt,
639
- browserReadyState: browserWs.readyState,
640
- upstreamReadyState: upstream.readyState,
641
- });
642
- stopUpstreamKeepalive = attachWsKeepalive(upstream, { nodeId, tenantId, leg: 'upstream' }, { onStale: beginTeardown });
578
+ stopUpstreamKeepalive = attachWsKeepalive(upstream, { home_id: home.home_id, leg: 'upstream' }, { onStale: beginTeardown });
643
579
  for (const frame of queued.splice(0, queued.length)) {
644
580
  try {
645
581
  upstream.send(frame.data, { binary: frame.isBinary });
@@ -665,52 +601,42 @@ async function proxyWebSocketBrowser(browserWs, nodeId, tenantId, runtime, deps
665
601
  }
666
602
  });
667
603
  upstream.on('error', (error) => {
668
- logError('hearth wake proxy WS upstream failed', { nodeId, error: redact(error instanceof Error ? error.message : String(error)) });
669
- // The upstream leg failed — the home may be down; re-probe on the next connect.
670
- invalidateWarmVerdict(tenantId);
604
+ logError('hearth control plane relay ws upstream failed', { home_id: home.home_id, error: error instanceof Error ? error.message : String(error) });
605
+ (deps.invalidateWarmVerdict ?? invalidateWarmVerdict)(home.home_id);
671
606
  closeBoth(1011, 'upstream websocket error');
672
607
  });
673
608
  }
674
609
  catch (error) {
675
610
  const message = error instanceof Error ? error.message : String(error);
676
- logError('hearth wake proxy websocket wake failed', { nodeId, ...serializeWakeProxyError(error) });
677
- invalidateWarmVerdict(tenantId);
611
+ logError('hearth control plane relay websocket wake failed', { home_id: home.home_id, error: message });
612
+ (deps.invalidateWarmVerdict ?? invalidateWarmVerdict)(home.home_id);
678
613
  closeBoth(/timed out/i.test(message) ? 1013 : 1011, /timed out/i.test(message) ? 'wake timeout' : 'wake failed');
679
614
  }
680
615
  }
681
- export function proxyUpgrade(req, socket, head, runtime) {
682
- let nodeId = null;
683
- try {
684
- const rawTarget = validateOriginFormRequestTarget(req.url);
685
- const pathname = new URL(rawTarget, 'http://127.0.0.1').pathname;
686
- nodeId = extractNodeId(pathname);
687
- }
688
- catch (error) {
689
- const message = error instanceof Error ? error.message : String(error);
690
- socket.write(`HTTP/1.1 ${message.startsWith('proxy ') ? '400 Bad Request' : '403 Forbidden'}\r\nConnection: close\r\n\r\n`);
691
- socket.destroy();
692
- return;
693
- }
694
- if (nodeId === null) {
695
- socket.write('HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n');
696
- socket.destroy();
697
- return;
698
- }
699
- let auth;
700
- try {
701
- const state = currentState(runtime);
702
- auth = resolveOwnerAuth(req, runtime.proxy, state);
703
- }
704
- catch {
705
- auth = null;
706
- }
707
- if (auth === null) {
708
- socket.write('HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n');
709
- socket.destroy();
710
- return;
711
- }
616
+ /** `RelayDispatcher.proxyUpgrade`: complete the WS handshake on the already
617
+ * session+registry-gated socket (`server.ts`'s `handleUpgrade`), then bridge
618
+ * it to the home. Errors after this point close the browser socket in-band
619
+ * with a WS close code (1011/1013) rather than a raw TCP reset, so the
620
+ * client sees a clean failure (criterion 4: "keep ... close behavior from
621
+ * M0 where applicable"). */
622
+ export function proxyUpgrade(req, socket, head, home, deps = {}) {
712
623
  const wss = createUpgradeServer();
713
624
  wss.handleUpgrade(req, socket, head, (browserWs) => {
714
- void proxyWebSocketBrowser(browserWs, nodeId, auth.tenantId, runtime);
625
+ void proxyWebSocketBrowser(browserWs, home, deps).catch((error) => {
626
+ logError('hearth control plane relay websocket bridge failed', { home_id: home.home_id, error: error instanceof Error ? error.message : String(error) });
627
+ try {
628
+ browserWs.terminate();
629
+ }
630
+ catch {
631
+ /* ignore */
632
+ }
633
+ });
715
634
  });
716
635
  }
636
+ /** The real `RelayDispatcher` `main.ts` wires in once the CP server is built
637
+ * — `server.ts`'s default (`notImplementedRelay`) is only ever used when a
638
+ * caller (test/smoke) doesn't inject one. */
639
+ export const controlPlaneRelay = {
640
+ proxyHttp,
641
+ proxyUpgrade,
642
+ };