@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.
- package/README.md +2 -2
- package/dist/build-root.js +3 -6
- package/dist/builtin-memory/crouter-development/marketplaces.md +6 -6
- package/dist/builtin-memory/crouter-development/plugins.md +13 -13
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -3
- package/dist/builtin-memory/internal/nodes-and-canvas.md +4 -4
- package/dist/builtin-personas/developer/PERSONA.md +1 -1
- package/dist/builtin-personas/orchestration-kernel.md +1 -1
- package/dist/builtin-personas/waiting.md +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +71 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/crtr-help-gate.test.ts +41 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +663 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/statusline.test.ts +52 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +418 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crouter-help.ts +87 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/filters.json +7 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +174 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-help-gate.ts +408 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +442 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/test.ts +119 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/nested-context.ts +327 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +574 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +260 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/strip-skills-docs.ts +40 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/sysprompt-window.ts +19 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/lib/package.json +3 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.js +1 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +479 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/LICENSE +13 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/README.md +172 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/bin.mjs +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/composer.js +219 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +225 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/Document.js +335 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/doc/directives.js +176 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/errors.js +57 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/index.js +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/log.js +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Alias.js +116 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/cst.js +98 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/lexer.js +721 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/parse/parser.js +975 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/public-api.js +102 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/tags.js +96 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +67 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +25 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/util.js +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/dist/visit.js +233 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/index.js +5 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/browser/package.json +3 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/cli.d.ts +8 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/cli.mjs +201 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-collection.js +90 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-doc.js +45 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-node.js +112 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/composer.d.ts +63 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/composer.js +224 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-end.js +39 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-flow-scalar.js +227 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/resolve-props.js +148 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/Document.d.ts +141 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/Document.js +337 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/anchors.js +76 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/applyReviver.js +57 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/createNode.js +90 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/directives.d.ts +49 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/doc/directives.js +178 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/errors.d.ts +21 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/errors.js +62 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/index.d.ts +25 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/index.js +50 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/log.d.ts +3 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/log.js +19 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Alias.js +118 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Collection.js +151 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Node.js +40 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Pair.js +39 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Scalar.d.ts +47 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/Scalar.js +27 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/identity.js +53 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/nodes/toJS.js +39 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/options.d.ts +350 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst-visit.js +99 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst.d.ts +109 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/cst.js +112 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/lexer.js +723 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/line-counter.js +41 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/parser.d.ts +84 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/parse/parser.js +980 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/public-api.d.ts +44 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/public-api.js +107 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/Schema.js +39 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/map.js +19 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/null.js +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/seq.js +19 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/common/string.js +16 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/bool.js +21 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/float.js +47 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/int.js +42 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/core/schema.js +25 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/json/schema.js +64 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/tags.d.ts +48 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/tags.js +99 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/types.d.ts +92 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/merge.js +71 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringify.js +132 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyNumber.js +27 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/test-events.d.ts +4 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/test-events.js +134 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/util.d.ts +16 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/util.js +28 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/visit.d.ts +102 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/dist/visit.js +236 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/package.json +97 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/node_modules/yaml/util.js +2 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/package-lock.json +3385 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/package.json +25 -0
- package/dist/builtin-pi-packages/pi-mode-switch/README.md +64 -0
- package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +40 -0
- package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +427 -0
- package/dist/builtin-pi-packages/pi-mode-switch/package.json +13 -0
- package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +55 -0
- package/dist/clients/attach/__tests__/crtr-output-render.test.js +2340 -0
- package/dist/clients/attach/attach-cmd.js +843 -743
- package/dist/clients/attach/auth-pickers.js +2 -2
- package/dist/clients/attach/canvas-panels.js +1 -1
- package/dist/clients/attach/chat-view.d.ts +3 -2
- package/dist/clients/attach/chat-view.js +30 -10
- package/dist/clients/attach/clipboard-image.js +1 -1
- package/dist/clients/attach/clipboard-text.js +1 -1
- package/dist/clients/attach/config-load.js +1 -1
- package/dist/clients/attach/crtr-output-render.d.ts +48 -0
- package/dist/clients/attach/crtr-output-render.js +646 -0
- package/dist/clients/attach/extension-dialogs.js +1 -1
- package/dist/clients/attach/graph-overlay.js +3 -3
- package/dist/clients/attach/input-controller.js +1 -1
- package/dist/clients/attach/pickers.js +1 -1
- package/dist/clients/attach/slash-commands.js +5 -6
- package/dist/clients/attach/titled-editor.d.ts +4 -0
- package/dist/clients/attach/titled-editor.js +13 -1
- package/dist/clients/attach/view-socket.js +1 -1
- package/dist/clients/web/__tests__/source-cache.test.js +5 -5
- package/dist/clients/web/server.js +29 -5
- package/dist/clients/web/source-cache.js +3 -3
- package/dist/clients/web/web-cmd.js +7 -7
- package/dist/commands/canvas-issue.js +1 -1
- package/dist/commands/canvas-prune.js +24 -2
- package/dist/commands/canvas-snapshot.js +3 -0
- package/dist/commands/canvas-tmux-spread.js +3 -3
- package/dist/commands/human.js +1 -1
- package/dist/commands/memory/lint.js +15 -8
- package/dist/commands/memory/origin.d.ts +1 -0
- package/dist/commands/memory/origin.js +88 -0
- package/dist/commands/memory/shared.d.ts +8 -0
- package/dist/commands/memory/shared.js +22 -1
- package/dist/commands/memory/write.js +17 -12
- package/dist/commands/memory.js +4 -3
- package/dist/commands/node-context.js +4 -4
- package/dist/commands/node-snapshot.js +4 -1
- package/dist/commands/node.d.ts +2 -2
- package/dist/commands/node.js +814 -606
- package/dist/commands/pkg/market-inspect.d.ts +2 -1
- package/dist/commands/pkg/market-inspect.js +14 -32
- package/dist/commands/pkg/market-manage.d.ts +3 -1
- package/dist/commands/pkg/market-manage.js +58 -154
- package/dist/commands/pkg/market.js +7 -7
- package/dist/commands/pkg/plugin-inspect.d.ts +2 -1
- package/dist/commands/pkg/plugin-inspect.js +8 -24
- package/dist/commands/pkg/plugin-manage.d.ts +5 -1
- package/dist/commands/pkg/plugin-manage.js +245 -171
- package/dist/commands/pkg/plugin.js +6 -6
- package/dist/commands/pkg.js +5 -5
- package/dist/commands/revive.js +5 -3
- package/dist/commands/search/answer.js +1 -1
- package/dist/commands/search/contents.js +1 -1
- package/dist/commands/search/web.js +2 -2
- package/dist/commands/search.js +1 -1
- package/dist/commands/surface.d.ts +2 -0
- package/dist/commands/surface.js +43 -0
- package/dist/commands/sys/promptstudio.js +1 -1
- package/dist/commands/sys/settings.js +2 -2
- package/dist/commands/sys/setup-core.d.ts +88 -0
- package/dist/commands/sys/setup-core.js +352 -0
- package/dist/commands/sys/setup.d.ts +2 -0
- package/dist/commands/sys/setup.js +516 -0
- package/dist/commands/sys/sysprompt.js +3 -0
- package/dist/commands/sys.js +3 -2
- package/dist/commands/view-cycle.js +5 -5
- package/dist/commands/view-list.js +3 -3
- package/dist/commands/view-new.js +5 -5
- package/dist/commands/view-pick.js +6 -6
- package/dist/commands/view-run.js +14 -14
- package/dist/commands/view.js +3 -3
- package/dist/commands/workspace.js +10 -10
- package/dist/core/__tests__/boot.test.js +140 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -27
- package/dist/core/__tests__/daemon-boot.test.js +22 -0
- package/dist/core/__tests__/fixtures/fake-engine.js +19 -9
- package/dist/core/__tests__/flagship-lifecycle.test.js +4 -1
- package/dist/core/__tests__/full/broker-attach-limits.test.js +1 -1
- package/dist/core/__tests__/full/broker-attach-stream.test.js +1 -1
- package/dist/core/__tests__/full/broker-crash-teardown.test.js +10 -5
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +1 -1
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +2 -2
- package/dist/core/__tests__/full/broker-pane-resolution.test.js +1 -1
- package/dist/core/__tests__/full/cascade-close.test.js +31 -18
- package/dist/core/__tests__/full/detach-focus.test.js +17 -3
- package/dist/core/__tests__/hearth-bootstrap.test.js +136 -0
- package/dist/core/__tests__/helpers/harness.js +1 -1
- package/dist/core/__tests__/live-mutation-verbs.test.js +17 -11
- package/dist/core/__tests__/live-mutation.test.js +15 -10
- package/dist/core/__tests__/migration.test.js +124 -0
- package/dist/core/__tests__/on-read-dedup-resume.test.js +40 -0
- package/dist/core/__tests__/preview-registry-sync.test.js +36 -0
- package/dist/core/__tests__/prune-to-limit.test.js +91 -0
- package/dist/core/__tests__/revive.test.js +64 -21
- package/dist/core/__tests__/trigger-migration.test.js +48 -0
- package/dist/core/__tests__/wake-bearings.test.js +23 -21
- package/dist/core/__tests__/wake-origin.test.js +36 -33
- package/dist/core/canvas/boot.d.ts +48 -0
- package/dist/core/canvas/boot.js +157 -0
- package/dist/core/canvas/canvas.d.ts +27 -1
- package/dist/core/canvas/canvas.js +86 -5
- package/dist/core/canvas/db.js +86 -1
- package/dist/core/canvas/index.d.ts +1 -1
- package/dist/core/canvas/index.js +1 -1
- package/dist/core/canvas/nav-model.js +1 -1
- package/dist/core/canvas/pid.d.ts +6 -0
- package/dist/core/canvas/pid.js +13 -0
- package/dist/core/canvas/triggers.d.ts +108 -0
- package/dist/core/canvas/triggers.js +320 -0
- package/dist/core/canvas/types.d.ts +128 -46
- package/dist/core/command.js +13 -4
- package/dist/core/hearth/__tests__/model-auth-guest.test.js +151 -0
- package/dist/core/hearth/config.d.ts +1 -0
- package/dist/core/hearth/config.js +36 -3
- package/dist/core/hearth/guest-env.d.ts +7 -0
- package/dist/core/hearth/guest-env.js +17 -1
- package/dist/core/hearth/index.d.ts +0 -1
- package/dist/core/hearth/index.js +0 -1
- package/dist/core/hearth/model-auth-guest.d.ts +8 -0
- package/dist/core/hearth/model-auth-guest.js +430 -0
- package/dist/core/hearth/provider.d.ts +13 -6
- package/dist/core/hearth/providers/blaxel-bootstrap.d.ts +2 -0
- package/dist/core/hearth/providers/blaxel-bootstrap.js +127 -19
- package/dist/core/hearth/providers/blaxel-home.d.ts +8 -4
- package/dist/core/hearth/providers/blaxel-home.js +85 -75
- package/dist/core/hearth/providers/blaxel.d.ts +5 -0
- package/dist/core/hearth/providers/blaxel.js +86 -12
- package/dist/core/hearth/providers/types.d.ts +6 -1
- package/dist/core/hearth/types.d.ts +35 -1
- package/dist/core/help.d.ts +16 -0
- package/dist/core/help.js +2 -0
- package/dist/core/memory-resolver.d.ts +8 -8
- package/dist/core/memory-resolver.js +58 -26
- package/dist/core/preview-registry.d.ts +25 -0
- package/dist/core/preview-registry.js +2047 -0
- package/dist/core/resolver.d.ts +1 -0
- package/dist/core/resolver.js +23 -16
- package/dist/core/runtime/bearings.d.ts +11 -10
- package/dist/core/runtime/bearings.js +8 -8
- package/dist/core/runtime/broker-protocol.d.ts +2 -2
- package/dist/core/runtime/broker-protocol.js +2 -2
- package/dist/core/runtime/close.js +2 -2
- package/dist/core/runtime/kickoff.js +1 -1
- package/dist/core/runtime/launch.d.ts +9 -3
- package/dist/core/runtime/launch.js +17 -9
- package/dist/core/runtime/lifecycle.js +7 -7
- package/dist/core/runtime/model-swap.js +1 -1
- package/dist/core/runtime/placement.d.ts +5 -5
- package/dist/core/runtime/placement.js +10 -10
- package/dist/core/runtime/recycle.js +7 -7
- package/dist/core/runtime/reset.d.ts +1 -1
- package/dist/core/runtime/reset.js +3 -3
- package/dist/core/runtime/revive-all.d.ts +5 -2
- package/dist/core/runtime/revive-all.js +5 -2
- package/dist/core/runtime/revive.d.ts +15 -8
- package/dist/core/runtime/revive.js +52 -16
- package/dist/core/runtime/spawn.d.ts +1 -1
- package/dist/core/runtime/spawn.js +7 -7
- package/dist/core/runtime/stop-guard.js +5 -5
- package/dist/core/runtime/surface-bg.js +1 -1
- package/dist/core/runtime/tmux.d.ts +1 -1
- package/dist/core/runtime/tmux.js +4 -4
- package/dist/core/scope.d.ts +9 -0
- package/dist/core/scope.js +37 -15
- package/dist/core/substrate/on-read.js +23 -21
- package/dist/core/substrate/render.js +3 -3
- package/dist/core/view/loader.js +2 -2
- package/dist/core/wake.d.ts +2 -2
- package/dist/core/wake.js +7 -7
- package/dist/daemon/__tests__/predicate-eval.test.js +109 -0
- package/dist/daemon/crtrd.js +222 -103
- package/dist/daemon/predicate-eval.d.ts +52 -0
- package/dist/daemon/predicate-eval.js +248 -0
- package/dist/hearth/control-plane/__tests__/node-message.test.js +60 -0
- package/dist/hearth/control-plane/__tests__/rate-limit-recurrence.test.js +49 -0
- package/dist/hearth/control-plane/__tests__/relay-security.test.js +314 -0
- package/dist/hearth/control-plane/__tests__/scheduler-scan-loop.test.js +133 -0
- package/dist/hearth/control-plane/__tests__/trigger-delivery.test.js +170 -0
- package/dist/hearth/control-plane/__tests__/webhook-ingress.test.js +167 -0
- package/dist/hearth/control-plane/config.d.ts +21 -0
- package/dist/hearth/control-plane/config.js +77 -0
- package/dist/hearth/control-plane/db.d.ts +30 -0
- package/dist/hearth/control-plane/db.js +534 -0
- package/dist/hearth/control-plane/ingress/rate-limit.d.ts +24 -0
- package/dist/hearth/control-plane/ingress/rate-limit.js +100 -0
- package/dist/hearth/control-plane/ingress/route-store.d.ts +31 -0
- package/dist/hearth/control-plane/ingress/route-store.js +61 -0
- package/dist/hearth/control-plane/ingress/webhook-delivery-store.d.ts +41 -0
- package/dist/hearth/control-plane/ingress/webhook-delivery-store.js +69 -0
- package/dist/hearth/control-plane/ingress/webhook-route.d.ts +55 -0
- package/dist/hearth/control-plane/ingress/webhook-route.js +285 -0
- package/dist/hearth/control-plane/main.js +88 -0
- package/dist/hearth/control-plane/node-message.d.ts +31 -0
- package/dist/hearth/control-plane/node-message.js +98 -0
- package/dist/hearth/control-plane/register.d.ts +15 -0
- package/dist/hearth/control-plane/register.js +34 -0
- package/dist/hearth/control-plane/registry.d.ts +17 -0
- package/dist/hearth/control-plane/registry.js +161 -0
- package/dist/hearth/control-plane/relay.d.ts +40 -0
- package/dist/hearth/{wake-proxy/proxy.js → control-plane/relay.js} +201 -275
- package/dist/hearth/control-plane/scheduler/fire-store.d.ts +36 -0
- package/dist/hearth/control-plane/scheduler/fire-store.js +73 -0
- package/dist/hearth/control-plane/scheduler/recurrence.d.ts +7 -0
- package/dist/hearth/control-plane/scheduler/recurrence.js +58 -0
- package/dist/hearth/control-plane/scheduler/scan-loop.d.ts +38 -0
- package/dist/hearth/control-plane/scheduler/scan-loop.js +138 -0
- package/dist/hearth/control-plane/scheduler/schedule-store.d.ts +32 -0
- package/dist/hearth/control-plane/scheduler/schedule-store.js +66 -0
- package/dist/hearth/control-plane/secrets.d.ts +17 -0
- package/dist/hearth/control-plane/secrets.js +113 -0
- package/dist/hearth/control-plane/server.d.ts +27 -0
- package/dist/hearth/control-plane/server.js +346 -0
- package/dist/hearth/control-plane/session.d.ts +68 -0
- package/dist/hearth/control-plane/session.js +273 -0
- package/dist/hearth/control-plane/triggers/acl.d.ts +14 -0
- package/dist/hearth/control-plane/triggers/acl.js +52 -0
- package/dist/hearth/control-plane/triggers/audit-store.d.ts +38 -0
- package/dist/hearth/control-plane/triggers/audit-store.js +79 -0
- package/dist/hearth/control-plane/triggers/deliver.d.ts +43 -0
- package/dist/hearth/control-plane/triggers/deliver.js +76 -0
- package/dist/hearth/control-plane/triggers/envelope.d.ts +29 -0
- package/dist/hearth/control-plane/triggers/envelope.js +38 -0
- package/dist/hearth/control-plane/types.d.ts +66 -0
- package/dist/hearth/control-plane/wake.d.ts +80 -0
- package/dist/hearth/control-plane/wake.js +312 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +28 -2
- package/dist/pi-extensions/canvas-nav.js +1 -1
- package/dist/prompts/view.js +7 -8
- package/dist/types.js +4 -4
- package/dist/web-client/assets/index-DUThOUzU.css +2 -0
- package/dist/web-client/assets/index-IAJVtuVe.js +80 -0
- package/dist/web-client/index.html +2 -2
- package/package.json +12 -9
- package/scripts/postinstall.mjs +8 -0
- package/dist/clients/attach/__tests__/action-parity.test.js +0 -48
- package/dist/clients/attach/__tests__/autocomplete-and-bash-mode.test.js +0 -96
- package/dist/clients/attach/__tests__/bash-bang-routing.test.js +0 -58
- package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.js +0 -56
- package/dist/clients/attach/__tests__/clipboard-image.test.js +0 -76
- package/dist/clients/attach/__tests__/editor-newline.test.js +0 -82
- package/dist/clients/attach/__tests__/git-info.test.js +0 -31
- package/dist/clients/attach/__tests__/onrequest-wired.test.js +0 -20
- package/dist/clients/attach/__tests__/reconnect-giveup.test.js +0 -30
- package/dist/clients/attach/__tests__/slash-quit-copy.test.js +0 -42
- package/dist/clients/attach/__tests__/titled-editor.test.js +0 -60
- package/dist/commands/memory/__tests__/lint-schema.test.js +0 -52
- package/dist/core/__tests__/argv-parser.test.js +0 -217
- package/dist/core/__tests__/artifact-paths.test.js +0 -44
- package/dist/core/__tests__/draw-style.test.js +0 -258
- package/dist/core/__tests__/editor-label.test.d.ts +0 -1
- package/dist/core/__tests__/editor-label.test.js +0 -26
- package/dist/core/__tests__/fault-marker.test.d.ts +0 -1
- package/dist/core/__tests__/fault-marker.test.js +0 -112
- package/dist/core/__tests__/fault-retry-rewind.test.d.ts +0 -1
- package/dist/core/__tests__/fault-retry-rewind.test.js +0 -123
- package/dist/core/__tests__/frame-decoder-perf.test.d.ts +0 -1
- package/dist/core/__tests__/frame-decoder-perf.test.js +0 -224
- package/dist/core/__tests__/keystone.test.d.ts +0 -1
- package/dist/core/__tests__/keystone.test.js +0 -185
- package/dist/core/__tests__/listing-completeness.test.d.ts +0 -1
- package/dist/core/__tests__/listing-completeness.test.js +0 -31
- package/dist/core/__tests__/memory-resolver.test.d.ts +0 -1
- package/dist/core/__tests__/memory-resolver.test.js +0 -119
- package/dist/core/__tests__/memory.test.d.ts +0 -1
- package/dist/core/__tests__/memory.test.js +0 -60
- package/dist/core/__tests__/model-ladders.test.d.ts +0 -1
- package/dist/core/__tests__/model-ladders.test.js +0 -160
- package/dist/core/__tests__/node-env.test.d.ts +0 -1
- package/dist/core/__tests__/node-env.test.js +0 -26
- package/dist/core/__tests__/pane-column.test.d.ts +0 -1
- package/dist/core/__tests__/pane-column.test.js +0 -153
- package/dist/core/__tests__/persona-compose.test.d.ts +0 -1
- package/dist/core/__tests__/persona-compose.test.js +0 -53
- package/dist/core/__tests__/persona-subkind.test.d.ts +0 -1
- package/dist/core/__tests__/persona-subkind.test.js +0 -65
- package/dist/core/__tests__/persona.test.d.ts +0 -1
- package/dist/core/__tests__/persona.test.js +0 -107
- package/dist/core/__tests__/unknown-path.test.d.ts +0 -1
- package/dist/core/__tests__/unknown-path.test.js +0 -58
- package/dist/core/canvas/wakeups.d.ts +0 -76
- package/dist/core/canvas/wakeups.js +0 -185
- package/dist/core/hearth/registry.d.ts +0 -15
- package/dist/core/hearth/registry.js +0 -179
- package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.js +0 -289
- package/dist/hearth/wake-proxy/__tests__/config-timeout.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/config-timeout.test.js +0 -34
- package/dist/hearth/wake-proxy/__tests__/guest-source.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/guest-source.test.js +0 -203
- package/dist/hearth/wake-proxy/__tests__/hardening.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/hardening.test.js +0 -59
- package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.js +0 -372
- package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.js +0 -258
- package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.js +0 -437
- package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.js +0 -455
- package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.js +0 -15
- package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.js +0 -141
- package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.d.ts +0 -1
- package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.js +0 -143
- package/dist/hearth/wake-proxy/anthropic-oauth.d.ts +0 -58
- package/dist/hearth/wake-proxy/anthropic-oauth.js +0 -189
- package/dist/hearth/wake-proxy/auth.d.ts +0 -22
- package/dist/hearth/wake-proxy/auth.js +0 -128
- package/dist/hearth/wake-proxy/config.d.ts +0 -2
- package/dist/hearth/wake-proxy/config.js +0 -151
- package/dist/hearth/wake-proxy/guest-source.d.ts +0 -14
- package/dist/hearth/wake-proxy/guest-source.js +0 -130
- package/dist/hearth/wake-proxy/hearth-status.d.ts +0 -44
- package/dist/hearth/wake-proxy/hearth-status.js +0 -267
- package/dist/hearth/wake-proxy/home.d.ts +0 -67
- package/dist/hearth/wake-proxy/home.js +0 -297
- package/dist/hearth/wake-proxy/main.js +0 -134
- package/dist/hearth/wake-proxy/model-auth.d.ts +0 -13
- package/dist/hearth/wake-proxy/model-auth.js +0 -345
- package/dist/hearth/wake-proxy/proxy.d.ts +0 -35
- package/dist/hearth/wake-proxy/public-source-gate.d.ts +0 -9
- package/dist/hearth/wake-proxy/public-source-gate.js +0 -409
- package/dist/hearth/wake-proxy/redact.d.ts +0 -1
- package/dist/hearth/wake-proxy/redact.js +0 -17
- package/dist/hearth/wake-proxy/server.d.ts +0 -11
- package/dist/hearth/wake-proxy/server.js +0 -142
- package/dist/hearth/wake-proxy/state.d.ts +0 -18
- package/dist/hearth/wake-proxy/state.js +0 -342
- package/dist/hearth/wake-proxy/types.d.ts +0 -76
- package/dist/web-client/assets/index-BZUxTkv5.css +0 -2
- package/dist/web-client/assets/index-D36PNBj4.js +0 -80
- /package/dist/clients/attach/__tests__/{action-parity.test.d.ts → crtr-output-coverage.test.d.ts} +0 -0
- /package/dist/clients/attach/__tests__/{autocomplete-and-bash-mode.test.d.ts → crtr-output-render.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/bash-bang-routing.test.d.ts → core/__tests__/boot.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/bundle-pi-tui-dedup.test.d.ts → core/__tests__/hearth-bootstrap.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/clipboard-image.test.d.ts → core/__tests__/preview-registry-sync.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/editor-newline.test.d.ts → core/__tests__/prune-to-limit.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/git-info.test.d.ts → core/__tests__/trigger-migration.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/onrequest-wired.test.d.ts → core/hearth/__tests__/model-auth-guest.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/reconnect-giveup.test.d.ts → daemon/__tests__/predicate-eval.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/slash-quit-copy.test.d.ts → hearth/control-plane/__tests__/node-message.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/titled-editor.test.d.ts → hearth/control-plane/__tests__/rate-limit-recurrence.test.d.ts} +0 -0
- /package/dist/{commands/memory/__tests__/lint-schema.test.d.ts → hearth/control-plane/__tests__/relay-security.test.d.ts} +0 -0
- /package/dist/{core/__tests__/argv-parser.test.d.ts → hearth/control-plane/__tests__/scheduler-scan-loop.test.d.ts} +0 -0
- /package/dist/{core/__tests__/artifact-paths.test.d.ts → hearth/control-plane/__tests__/trigger-delivery.test.d.ts} +0 -0
- /package/dist/{core/__tests__/draw-style.test.d.ts → hearth/control-plane/__tests__/webhook-ingress.test.d.ts} +0 -0
- /package/dist/hearth/{wake-proxy → control-plane}/main.d.ts +0 -0
- /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 {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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('
|
|
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('
|
|
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('
|
|
92
|
+
throw general('relay rejected control characters in request target', { requestUrl: '[redacted]' });
|
|
143
93
|
}
|
|
144
94
|
}
|
|
145
95
|
}
|
|
146
|
-
|
|
147
|
-
|
|
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('
|
|
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' ||
|
|
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
|
-
|
|
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
|
|
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
|
|
299
|
-
* Returns normally once the response is fully relayed;
|
|
300
|
-
* failure (connect refused/reset, DNS,
|
|
301
|
-
*
|
|
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.
|
|
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.
|
|
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
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
const
|
|
347
|
-
const
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
353
|
+
error: error instanceof Error ? error.message : String(error),
|
|
417
354
|
});
|
|
418
|
-
|
|
355
|
+
invalidate(home.home_id);
|
|
419
356
|
}
|
|
420
357
|
}
|
|
421
|
-
|
|
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
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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('
|
|
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
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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, {
|
|
539
|
-
|
|
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, {
|
|
508
|
+
stopBrowserKeepalive = attachWsKeepalive(browserWs, { home_id: home.home_id, leg: 'browser' }, { onStale: beginTeardown });
|
|
568
509
|
const logClose = (leg, code, reason) => {
|
|
569
|
-
logError('hearth
|
|
570
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
|
669
|
-
|
|
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
|
|
677
|
-
invalidateWarmVerdict(
|
|
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
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
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,
|
|
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
|
+
};
|