@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
@@ -6,7 +6,7 @@
6
6
  //
7
7
  // (1) Gap 1 — `nodeInPane()` (src/commands/node.ts) resolved a pane via
8
8
  // window→node ONLY. A broker engine runs DETACHED with window=null, and its
9
- // on-screen presence is a `crtr attach` VIEWER pane, so the window lookup
9
+ // on-screen presence is a `crtr surface attach` VIEWER pane, so the window lookup
10
10
  // never found it: `node cycle`/`recycle`/`close`/`demote`/`lifecycle` all
11
11
  // broke when the current pane was a broker viewer. The fix has attach
12
12
  // self-tag its pane `@crtr_node=<id>` and nodeInPane resolve that tag first.
@@ -1,10 +1,10 @@
1
1
  // Run with: node --import tsx/esm --test src/core/__tests__/cascade-close.test.ts
2
2
  //
3
3
  // CASCADE CLOSE + exclusive-subtree ownership — a FAITHFUL integration test of
4
- // `crtr node close` on a MIDDLE node, driven through the REAL CLI against a REAL
4
+ // `crtr node lifecycle close` on a MIDDLE node, driven through the REAL CLI against a REAL
5
5
  // isolated tmux session with REAL fake-pi vehicles in REAL panes, asserting off
6
6
  // the canvas data layer and checked against the state-model ORACLE
7
- // (state-model.md §4 `node close`, §5 cascade-close ownership, invariant 3,
7
+ // (state-model.md §4 `node lifecycle close`, §5 cascade-close ownership, invariant 3,
8
8
  // ambiguity A5).
9
9
  //
10
10
  // WHY this exists alongside the unit `close.test.ts`: that test exercises
@@ -32,11 +32,11 @@
32
32
  // └── S sideways sibling subtree — MUST survive
33
33
  // └── G
34
34
  //
35
- // close(B) ⇒ exclusive subtree {B,C,D,E} reaped; A,S,G untouched.
35
+ // close(B) ⇒ exclusive subtree {B,C,D,E} canceled; A,S,G untouched.
36
36
  //
37
37
  // CRITICAL DELIVERABLE (ambiguity A5): the EXACT terminal status a cascade-
38
- // reaped descendant receives under `node close`. CURRENT behavior, asserted
39
- // end-to-end below: status === 'canceled', intent === null (cleared) — for the
38
+ // closed descendant receives under `node lifecycle close`. With the fixtures made
39
+ // non-empty below: status === 'canceled', intent === null (cleared) — for the
40
40
  // cascade ROOT and EVERY descendant alike (`transition(id,'cancel')`,
41
41
  // close.ts → lifecycle.ts cancel row: status='canceled', intent=null, from '*').
42
42
  // This differs from the ancestor-RESET path (`reapDescendants` → `reap` → 'done')
@@ -52,12 +52,18 @@
52
52
  import { test } from 'node:test';
53
53
  import assert from 'node:assert/strict';
54
54
  import { spawnSync } from 'node:child_process';
55
+ import { mkdirSync, writeFileSync } from 'node:fs';
56
+ import { join } from 'node:path';
55
57
  import { createHarness, hasTmux } from '../helpers/harness.js';
56
58
  import { isPidAlive } from '../../canvas/pid.js';
57
59
  function sessionExists(session) {
58
60
  return spawnSync('tmux', ['has-session', '-t', session], { stdio: 'ignore' }).status === 0;
59
61
  }
60
- test('cascade close: middle-node close reaps EXACTLY its subtree (canceled), ancestor + sideways untouched, edges persist', { skip: !hasTmux() ? 'tmux unavailable' : false, timeout: 180_000 }, async () => {
62
+ function seedAssistantSession(sessionFile) {
63
+ mkdirSync(join(sessionFile, '..'), { recursive: true });
64
+ writeFileSync(sessionFile, JSON.stringify({ type: 'message', message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] } }) + '\n');
65
+ }
66
+ test('cascade close: middle-node lifecycle close cancels EXACTLY its subtree, ancestor + sideways untouched, edges persist', { skip: !hasTmux() ? 'tmux unavailable' : false, timeout: 180_000 }, async () => {
61
67
  const h = await createHarness({ sessionPrefix: 'crtr-cascade' });
62
68
  try {
63
69
  // ===================================================================
@@ -73,16 +79,23 @@ test('cascade close: middle-node close reaps EXACTLY its subtree (canceled), anc
73
79
  const D = await h.spawnChild(B, 'B child two'); // breadth: B has {C, D}
74
80
  const S = await h.spawnChild(A, 'sideways sibling of B'); // sideways subtree
75
81
  const G = await h.spawnChild(S, 'child of the sideways sibling');
76
- const subtree = [B, C, D, E]; // B's exclusive subtree (the expected reap set)
82
+ const subtree = [B, C, D, E]; // B's exclusive subtree (the expected cancel set)
77
83
  const sideways = [S, G]; // a sibling subtree — must be wholly untouched
84
+ // Make the close-path fixtures NON-EMPTY so close exercises cancel+notice
85
+ // semantics instead of the new reap-empty path.
86
+ for (const id of subtree) {
87
+ const sessionFile = h.node(id).pi_session_file;
88
+ assert.ok(sessionFile !== null && sessionFile !== undefined, `${id} has a session file`);
89
+ seedAssistantSession(sessionFile);
90
+ }
78
91
  // Pre-close sanity: every node live + present, spine wired as drawn.
79
92
  {
80
93
  for (const id of [B, C, D, E, S, G]) {
81
- assert.equal(h.status(id), 'active', `${id} active before close`);
94
+ assert.ok(h.status(id) === 'active' || h.status(id) === 'idle', `${id} live before close`);
82
95
  const pid = h.node(id).pi_pid;
83
96
  assert.ok(pid != null && isPidAlive(pid), `${id} broker engine alive before close`);
84
97
  }
85
- assert.equal(h.status(A), 'active', 'A (root) active before close');
98
+ assert.ok(h.status(A) === 'active' || h.status(A) === 'idle', 'A (root) live before close');
86
99
  // Spine: A→{B,S}, B→{C,D}, C→{E}, S→{G} (all active spawn-seed edges).
87
100
  const subIds = (n) => h.subscriptions(n).map((s) => s.node_id).sort();
88
101
  assert.deepEqual(subIds(A), [B, S].sort(), 'A subscribes_to B and S');
@@ -105,19 +118,19 @@ test('cascade close: middle-node close reaps EXACTLY its subtree (canceled), anc
105
118
  const aInboxBefore = h.inbox(A);
106
119
  assert.ok(aInboxBefore.some((e) => e.from === B && e.kind === 'update'), "A's inbox holds B's pre-close update (non-vacuous 'intact' baseline)");
107
120
  // ===================================================================
108
- // CLOSE the MIDDLE node B, through the REAL CLI (`crtr node close --node B`,
121
+ // CLOSE the MIDDLE node B, through the REAL CLI (`crtr node lifecycle close --node B`,
109
122
  // run AS the root A). closeNode is synchronous in the subprocess: by the
110
123
  // time it returns, rows are flipped and panes are killed.
111
124
  // ===================================================================
112
- const closeRes = h.cli(A, ['node', 'close', '--node', B]);
113
- assert.equal(closeRes.code, 0, `node close exit 0\n${closeRes.stderr}`);
125
+ const closeRes = h.cli(A, ['node', 'lifecycle', 'close', '--node', B]);
126
+ assert.equal(closeRes.code, 0, `node lifecycle close exit 0\n${closeRes.stderr}`);
114
127
  // The CLI's own rendered report (plain markdown): cascade root B, exactly
115
128
  // 4 closed, 0 spared (no spared clause is emitted when none were spared).
116
129
  assert.match(closeRes.stdout, new RegExp(`^Closed ${B} and its exclusive subtree — 4 node\\(s\\) closed\\.`), `close report names B as root, count=4, spared=0\n${closeRes.stdout}`);
117
130
  // ===================================================================
118
131
  // ASSERT 1 — the A5 DELIVERABLE: the EXACT terminal status of every
119
- // cascade-reaped node. CURRENT behavior: status='canceled', intent=null,
120
- // for the ROOT (B) and EVERY descendant {C,D,E} identically.
132
+ // cascade-closed node. With the fixtures now non-empty, close exercises
133
+ // cancel+notice semantics and the rows remain present as canceled husks.
121
134
  // ===================================================================
122
135
  for (const id of subtree) {
123
136
  const n = h.node(id);
@@ -125,11 +138,11 @@ test('cascade close: middle-node close reaps EXACTLY its subtree (canceled), anc
125
138
  assert.strictEqual(n.intent ?? null, null, `${id} intent cleared to null on cancel`);
126
139
  }
127
140
  // Pin the exact field tuple once more, explicitly, for the human decision:
128
- // a cascade-reaped descendant under `node close` reads (canceled, null) —
141
+ // a cascade-closed descendant under `node lifecycle close` reads (canceled, null) —
129
142
  // NOT (done, done) and NOT (done, null). This is the confirmed A5 fact.
130
143
  {
131
144
  const e = h.node(E); // the deepest descendant
132
- assert.deepEqual({ status: e.status, intent: e.intent ?? null }, { status: 'canceled', intent: null }, "deepest reaped descendant E: (status,intent) === ('canceled', null)");
145
+ assert.deepEqual({ status: e.status, intent: e.intent ?? null }, { status: 'canceled', intent: null }, "deepest closed descendant E: (status,intent) === ('canceled', null)");
133
146
  }
134
147
  // ===================================================================
135
148
  // ASSERT 2 — broker ENGINE torn down for the ENTIRE subtree (the real
@@ -146,7 +159,7 @@ test('cascade close: middle-node close reaps EXACTLY its subtree (canceled), anc
146
159
  }
147
160
  // ===================================================================
148
161
  // ASSERT 3 — EXCLUSIVE-SUBTREE OWNERSHIP: nothing ABOVE (A) and nothing
149
- // SIDEWAYS (S, G) was reaped. close(B) reaped EXACTLY B's own subtree.
162
+ // SIDEWAYS (S, G) was reaped. close(B) canceled EXACTLY B's own subtree.
150
163
  // ===================================================================
151
164
  // Ancestor A — lifecycle untouched (still the live resident root), but A is
152
165
  // the SURVIVING manager of the close-root B, so the wake doctrine fix WAKES
@@ -168,7 +181,7 @@ test('cascade close: middle-node close reaps EXACTLY its subtree (canceled), anc
168
181
  }
169
182
  // Sideways subtree S→G — wholly alive: status active AND broker engine alive.
170
183
  for (const id of sideways) {
171
- assert.equal(h.status(id), 'active', `${id} (sideways) still active — not reaped`);
184
+ assert.equal(h.status(id), 'active', `${id} (sideways) still active — not canceled`);
172
185
  const pid = h.node(id).pi_pid;
173
186
  assert.ok(pid != null && isPidAlive(pid), `${id} (sideways) broker engine still alive`);
174
187
  }
@@ -5,7 +5,7 @@
5
5
  // BROKER-CUT ADAPTATION (taste/broker-is-the-host, 2026-06-10): every node is a
6
6
  // detached headless broker. After a09b71f a managed child opens NO viewer on
7
7
  // spawn — a viewer is opened on demand via `node focus`, registering its
8
- // `crtr attach` VIEWER pane in the focuses table. The engine is NOT in a pane, so the
8
+ // `crtr surface attach` VIEWER pane in the focuses table. The engine is NOT in a pane, so the
9
9
  // pre-cut "relocate the still-running pi pane to the backstage" behavior —
10
10
  // detachToBackground's engine break-pane/release path, and its isGenerating()
11
11
  // gate that released a non-generating node to dormant — is DELETED. The Bug-1
@@ -24,6 +24,8 @@
24
24
  import { test } from 'node:test';
25
25
  import assert from 'node:assert/strict';
26
26
  import { spawnSync } from 'node:child_process';
27
+ import { mkdirSync, writeFileSync } from 'node:fs';
28
+ import { join } from 'node:path';
27
29
  import { createHarness, hasTmux } from '../helpers/harness.js';
28
30
  import { getNode } from '../../canvas/canvas.js';
29
31
  import { getFocusByNode, getFocusByPane, listFocuses } from '../../canvas/focuses.js';
@@ -39,6 +41,13 @@ function paneExistsReal(pane) {
39
41
  }
40
42
  // Split a throwaway pane in the harness session; return its %id. The caller pane
41
43
  // `node focus` opens the viewer beside (a09b71f: spawn no longer auto-opens one).
44
+ // Write an assistant message into a node's pi session so it is NOT an empty
45
+ // shell — reapIfEmpty (0515e8d) tears output-less nodes down on detach, which
46
+ // would defeat the "broker survives" contract this test locks.
47
+ function seedAssistantSession(sessionFile) {
48
+ mkdirSync(join(sessionFile, '..'), { recursive: true });
49
+ writeFileSync(sessionFile, JSON.stringify({ type: 'message', message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] } }) + '\n');
50
+ }
42
51
  function makePane(session) {
43
52
  const r = spawnSync('tmux', ['split-window', '-d', '-t', session, '-P', '-F', '#{pane_id}', 'sleep 100000'], { encoding: 'utf8' });
44
53
  const pane = (r.stdout ?? '').trim();
@@ -60,7 +69,12 @@ test('node demote --detach: flips terminal in place, CLOSES the viewer pane + fo
60
69
  assert.equal(b0.status, 'active', 'B active after boot');
61
70
  const brokerPid = b0.pi_pid;
62
71
  assert.ok(brokerPid != null && isPidAlive(brokerPid), 'B broker engine alive before detach');
63
- // Put B genuinely "on screen": `node focus` opens its one `crtr attach`
72
+ // Make B NON-EMPTY (it produced an assistant message) so `--detach`
73
+ // exercises the "close the viewer, broker survives" contract and NOT the
74
+ // reap-empty path (0515e8d), which would tear an output-less shell down.
75
+ assert.ok(b0.pi_session_file != null, 'B has a session file');
76
+ seedAssistantSession(b0.pi_session_file);
77
+ // Put B genuinely "on screen": `node focus` opens its one `crtr surface attach`
64
78
  // VIEWER pane beside a caller pane in the harness session, registering the
65
79
  // viewer focus row (§A.3) — the on-demand viewer the detach then tears down.
66
80
  const caller = makePane(h.session);
@@ -74,7 +88,7 @@ test('node demote --detach: flips terminal in place, CLOSES the viewer pane + fo
74
88
  const viewerPane = viewerRow.pane;
75
89
  assert.equal(paneExistsReal(viewerPane), true, 'B viewer pane is live on screen');
76
90
  // --- Drive the REAL verb on the focused node (the Alt+C → D menu path). ---
77
- const res = h.cli(B, ['node', 'demote', '--node', B, '--pane', viewerPane, '--detach']);
91
+ const res = h.cli(B, ['node', 'lifecycle', 'demote', '--node', B, '--pane', viewerPane, '--detach']);
78
92
  assert.equal(res.code, 0, `node demote --detach exit 0\n${res.stderr}`);
79
93
  assert.match(res.stdout, /viewer closed \(broker still running off-screen\)/, `the viewer was closed\n${res.stdout}`);
80
94
  closeDb();
@@ -0,0 +1,136 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { buildBootstrapScript } from '../hearth/providers/blaxel-bootstrap.js';
4
+ const FIRST_BOOT_OPTS = {
5
+ guestHome: '/home/agent',
6
+ crtrVersion: '0.3.33',
7
+ relayToken: 'relay-token',
8
+ webPort: 7878,
9
+ piAuthJson: '{"anthropic":{"type":"oauth","refresh":"r","access":"a","expires":1}}',
10
+ piPackages: ['npm:pi-claude-oauth-adapter@0.1.2'],
11
+ modelLaddersJson: '{"modelLadders":{"anthropic":{"strong":"anthropic/claude-opus-4-8:high"},"openai":{"strong":"openai-codex/gpt-5.5:high"},"defaultProvider":"anthropic"}}',
12
+ isFirstProvision: true,
13
+ };
14
+ function indexOf(script, needle) {
15
+ const i = script.indexOf(needle);
16
+ assert.ok(i !== -1, `expected to find ${JSON.stringify(needle)} in script`);
17
+ return i;
18
+ }
19
+ test('first provision seeds config/ladders and pi settings, never the rotation pool, and never installs', () => {
20
+ const script = buildBootstrapScript(FIRST_BOOT_OPTS);
21
+ // Seeds that DO belong (config template + model ladders + pi settings +
22
+ // optional single auth.json).
23
+ assert.match(script, /settings\.json/);
24
+ assert.match(script, /pi-crtr-extensions/);
25
+ assert.match(script, /CRTR_CONFIG_JSON/);
26
+ assert.match(script, /PI_AUTH_JSON/);
27
+ // The rotation pool is dead product — bridge/migration only, never emitted
28
+ // by the rewritten bootstrap regardless of opts shape.
29
+ assert.doesNotMatch(script, /ANTHROPIC_SUBSCRIPTIONS_JSON/);
30
+ assert.doesNotMatch(script, /OPENAI_CODEX_SUBSCRIPTIONS_JSON/);
31
+ assert.doesNotMatch(script, /PROVIDER_ROTATION_JSON/);
32
+ assert.doesNotMatch(script, /anthropic-subscriptions\.json/);
33
+ assert.doesNotMatch(script, /openai-codex-subscriptions\.json/);
34
+ assert.doesNotMatch(script, /provider-rotation\.json/);
35
+ // No boot-time install of any kind — the image bakes crtr; bootstrap only
36
+ // asserts it.
37
+ assert.doesNotMatch(script, /npm install/);
38
+ });
39
+ test('recreate (isFirstProvision:false) emits no seeds at all and revives the existing node', () => {
40
+ const script = buildBootstrapScript({
41
+ ...FIRST_BOOT_OPTS,
42
+ isFirstProvision: false,
43
+ nodeId: 'node-123',
44
+ });
45
+ assert.doesNotMatch(script, /settings\.json/);
46
+ assert.doesNotMatch(script, /CRTR_CONFIG_JSON/);
47
+ assert.doesNotMatch(script, /PI_AUTH_JSON/);
48
+ assert.doesNotMatch(script, /ANTHROPIC_SUBSCRIPTIONS_JSON/);
49
+ assert.doesNotMatch(script, /OPENAI_CODEX_SUBSCRIPTIONS_JSON/);
50
+ assert.doesNotMatch(script, /PROVIDER_ROTATION_JSON/);
51
+ assert.match(script, /'\/usr\/local\/bin\/crtr' canvas revive 'node-123'/);
52
+ assert.doesNotMatch(script, /node new --root/);
53
+ });
54
+ test('recreate without a nodeId fails fast at script-generation time, not inside the guest', () => {
55
+ assert.throws(() => buildBootstrapScript({ ...FIRST_BOOT_OPTS, isFirstProvision: false, nodeId: null }));
56
+ assert.throws(() => buildBootstrapScript({ ...FIRST_BOOT_OPTS, isFirstProvision: false, nodeId: ' ' }));
57
+ });
58
+ test('an empty relay token fails fast at script-generation time — the web lane must never bind unauthenticated', () => {
59
+ assert.throws(() => buildBootstrapScript({ ...FIRST_BOOT_OPTS, relayToken: '' }));
60
+ assert.throws(() => buildBootstrapScript({ ...FIRST_BOOT_OPTS, relayToken: ' ' }));
61
+ });
62
+ test('asserts the baked crtr command surface — never falls back to the retired top-level alias', () => {
63
+ const script = buildBootstrapScript(FIRST_BOOT_OPTS);
64
+ assert.match(script, /'\/usr\/local\/bin\/crtr' surface web -h/);
65
+ assert.match(script, /'\/usr\/local\/bin\/crtr' surface web serve -h/);
66
+ assert.match(script, /command surface assertion FAILED/);
67
+ assert.match(script, /'\/usr\/local\/bin\/crtr' surface web serve --host 0\.0\.0\.0/);
68
+ // Never the retired top-level alias, anywhere in the script (e.g. as a
69
+ // fallback if the surface assertion fails).
70
+ assert.doesNotMatch(script, /[^/]crtr web serve/);
71
+ });
72
+ test('asserts the pinned crtr version against the baked binary and fails closed on mismatch', () => {
73
+ const script = buildBootstrapScript(FIRST_BOOT_OPTS);
74
+ assert.match(script, /'\/usr\/local\/bin\/crtr' --json sys version/);
75
+ assert.match(script, /crtr version assertion FAILED/);
76
+ assert.match(script, /!= '0\.3\.33'/);
77
+ });
78
+ test('every web-serve invocation carries a non-empty --token, enforcing relay-token auth on every lane', () => {
79
+ const firstBoot = buildBootstrapScript(FIRST_BOOT_OPTS);
80
+ const recreate = buildBootstrapScript({ ...FIRST_BOOT_OPTS, isFirstProvision: false, nodeId: 'node-123' });
81
+ for (const script of [firstBoot, recreate]) {
82
+ const serveLine = script.split('\n').find((line) => line.includes('surface web serve --host'));
83
+ assert.ok(serveLine, 'expected a crtr surface web serve invocation');
84
+ assert.match(serveLine, /--token 'relay-token'/);
85
+ }
86
+ });
87
+ test('every crtr invocation targets the baked binary by absolute path, never a bare PATH lookup, defeating a stale volume-installed crtr shadowing it (review Major 1)', () => {
88
+ const firstBoot = buildBootstrapScript(FIRST_BOOT_OPTS);
89
+ const recreate = buildBootstrapScript({ ...FIRST_BOOT_OPTS, isFirstProvision: false, nodeId: 'node-123' });
90
+ for (const script of [firstBoot, recreate]) {
91
+ assert.match(script, /'\/usr\/local\/bin\/crtr' --json sys version/);
92
+ assert.match(script, /'\/usr\/local\/bin\/crtr' surface web -h/);
93
+ assert.match(script, /'\/usr\/local\/bin\/crtr' surface web serve -h/);
94
+ assert.match(script, /'\/usr\/local\/bin\/crtr' canvas daemon start/);
95
+ assert.match(script, /'\/usr\/local\/bin\/crtr' surface web serve --host 0\.0\.0\.0/);
96
+ // No bare `crtr <subcommand>` invocation anywhere — only the `command -v
97
+ // crtr` shadow-detection probe and human-readable error-message text are
98
+ // allowed to reference it by bare name.
99
+ const bareInvocations = script
100
+ .split('\n')
101
+ .filter((line) => !line.trim().startsWith('printf'))
102
+ .filter((line) => /(^|[\s(])crtr (canvas|surface|--json)/.test(line));
103
+ assert.deepEqual(bareInvocations, []);
104
+ }
105
+ assert.match(firstBoot, /'\/usr\/local\/bin\/crtr' --json node new --root/);
106
+ });
107
+ test('asserts a bare `crtr` PATH lookup resolves to the baked binary, catching a stale volume-installed crtr shadowing it', () => {
108
+ const script = buildBootstrapScript(FIRST_BOOT_OPTS);
109
+ assert.match(script, /resolved_crtr="\$\(command -v crtr 2>\/dev\/null \|\| true\)"/);
110
+ assert.match(script, /if \[ "\$resolved_crtr" != '\/usr\/local\/bin\/crtr' \]; then/);
111
+ assert.match(script, /stale crtr shadowing baked binary/);
112
+ });
113
+ test('exports a PATH with the baked /usr/local/bin ahead of the legacy (dead) per-home runtime bin dir', () => {
114
+ const script = buildBootstrapScript(FIRST_BOOT_OPTS);
115
+ assert.match(script, /export PATH='\/usr\/local\/bin:\/usr\/bin:\/bin'/);
116
+ assert.doesNotMatch(script, /crtr-runtime\/bin/);
117
+ });
118
+ test('mkdirs the tmpfs CRTR_SOCK_DIR/CRTR_PIDFILE dirs strictly before the daemon starts, and CRTR_CANVAS_DB stays unset', () => {
119
+ const script = buildBootstrapScript(FIRST_BOOT_OPTS);
120
+ assert.match(script, /export CRTR_SOCK_DIR='\/run\/crtr\/socks'/);
121
+ assert.match(script, /export CRTR_PIDFILE='\/run\/crtr\/crtrd\.pid'/);
122
+ assert.match(script, /export CRTR_HOME='\/home\/agent\/\.crouter\/canvas'/);
123
+ assert.doesNotMatch(script, /CRTR_CANVAS_DB=/);
124
+ assert.match(script, /unset CRTR_CANVAS_DB/);
125
+ const mkdirIdx = indexOf(script, '/run/crtr/socks');
126
+ const daemonStartIdx = indexOf(script, "'/usr/local/bin/crtr' canvas daemon start");
127
+ assert.ok(mkdirIdx < daemonStartIdx, 'tmpfs mkdir must precede daemon start');
128
+ const mkdirLine = script.split('\n').find((line) => line.startsWith('mkdir -p') && line.includes('/run/crtr/socks'));
129
+ assert.ok(mkdirLine, 'expected a single mkdir line covering the tmpfs dirs');
130
+ });
131
+ test('primes the baked pi Claude OAuth adapter into the npm cache path pi resolves, existence-gated', () => {
132
+ const script = buildBootstrapScript(FIRST_BOOT_OPTS);
133
+ assert.match(script, /\/opt\/crouter\/node_modules\/pi-claude-oauth-adapter/);
134
+ assert.match(script, /\.pi\/agent\/npm\/node_modules\/pi-claude-oauth-adapter/);
135
+ assert.match(script, /cp -R/);
136
+ });
@@ -344,7 +344,7 @@ export async function createHarness(opts = {}) {
344
344
  async spawnHeadlessChild(parentId, task, o = {}) {
345
345
  const before = new Set(nodeDirs());
346
346
  // POST-CUT: `--headless` is gone — EVERY node is a broker. spawnChild may
347
- // still open a background `crtr attach` viewer WINDOW (the §A.3 spawn UX),
347
+ // still open a background `crtr surface attach` viewer WINDOW (the §A.3 spawn UX),
348
348
  // but that viewer connects to the broker over view.sock as a SEPARATE
349
349
  // process and never touches the engine — so the broker-socket gates here
350
350
  // (zero-viewer dialogs, controller arbitration, one-writer) are unaffected
@@ -8,9 +8,9 @@
8
8
  //
9
9
  // THREE-PART LOCK HEADER ──────────────────────────────────────────────────
10
10
  // (1) BUG LOCKED — the demote/recycle SPLIT and the A4 steer-loss boundary:
11
- // • `node demote` flips lifecycle→TERMINAL IN PLACE — keeps MODE, parentage,
11
+ // • `node lifecycle demote` flips lifecycle→TERMINAL IN PLACE — keeps MODE, parentage,
12
12
  // and a live (active) status; NOT finalized. It is NOT a mode flip.
13
- // • `node recycle` is FINISH+RECYCLE — pushes a final → done (mode KEPT), and
13
+ // • `node lifecycle recycle` is FINISH+RECYCLE — pushes a final → done (mode KEPT), and
14
14
  // mints a DIFFERENT fresh general/base/resident root.
15
15
  // • A4: a base→orchestrator yield auto-promotes (mode→orchestrator) and sets
16
16
  // intent=refresh but NEVER commits persona_ack — the drift is left pending
@@ -49,16 +49,20 @@ function persona(m) {
49
49
  }
50
50
  // ===========================================================================
51
51
  // (b) THE demote / recycle SPLIT — two DISTINCT verbs:
52
- // • `node demote` flips a LIVE node's lifecycle→TERMINAL IN PLACE — it keeps
52
+ // • `node lifecycle demote` flips a LIVE node's lifecycle→TERMINAL IN PLACE — it keeps
53
53
  // its MODE and parentage, keeps running (active), is NOT finalized; it now
54
54
  // merely owes a final up the spine (vision F5). MODE is untouched.
55
- // • `node recycle` is FINISH+RECYCLE — push final → done, then recycle the pane
55
+ // • `node lifecycle recycle` is FINISH+RECYCLE — push final → done, then recycle the pane
56
56
  // into a FRESH general/base/resident root (a DIFFERENT node). The recycled
57
57
  // node keeps mode=orchestrator (it is merely `done`).
58
58
  // This test drives demote via the real CLI verb and recycle via the real
59
59
  // recycleNode, pinning each behavior at the model layer.
60
60
  // ===========================================================================
61
- test('node demote flips lifecycle→terminal IN PLACE; node recycle is FINISH+RECYCLE', { timeout: 20_000 }, async () => {
61
+ test('node lifecycle demote flips lifecycle→terminal IN PLACE; node lifecycle recycle is FINISH+RECYCLE',
62
+ // Drives several full-CLI subprocess spawns (each a cold tsx compile of the
63
+ // whole CLI) + recycleNode; a 20s budget blew on the slower, concurrency-
64
+ // oversubscribed CI runner though it passes in ~8s locally. 60s = safe margin.
65
+ { timeout: 60_000 }, async () => {
62
66
  const h = await createHeadlessHarness({ sessionPrefix: 'crtr-live-demote' });
63
67
  try {
64
68
  const A = h.spawnRoot('resident root');
@@ -66,7 +70,7 @@ test('node demote flips lifecycle→terminal IN PLACE; node recycle is FINISH+RE
66
70
  subscribe(A, B, true);
67
71
  // Make B resident + orchestrator so the demote's flip→terminal is visible
68
72
  // and we can prove MODE/parentage survive it.
69
- assert.equal(h.cli(B, ['node', 'lifecycle', 'resident', '--node', B]).code, 0, 'B → resident');
73
+ assert.equal(h.cli(B, ['node', 'config', '--lifecycle', 'resident', '--node', B]).code, 0, 'B → resident');
70
74
  assert.equal(h.cli(B, ['node', 'promote', '--kind', 'developer']).code, 0, 'promote B');
71
75
  {
72
76
  const b = h.node(B);
@@ -74,10 +78,10 @@ test('node demote flips lifecycle→terminal IN PLACE; node recycle is FINISH+RE
74
78
  assert.equal(b.mode, 'orchestrator', 'B orchestrator before demote');
75
79
  }
76
80
  const bParent = h.node(B).parent;
77
- // --- node demote: flip-to-terminal IN PLACE. Keeps B alive, MODE/parentage
81
+ // --- node lifecycle demote: flip-to-terminal IN PLACE. Keeps B alive, MODE/parentage
78
82
  // untouched, NOT finalized.
79
- const dem = h.cli(B, ['node', 'demote', '--node', B]);
80
- assert.equal(dem.code, 0, `node demote exit 0\n${dem.stderr}`);
83
+ const dem = h.cli(B, ['node', 'lifecycle', 'demote', '--node', B]);
84
+ assert.equal(dem.code, 0, `node lifecycle demote exit 0\n${dem.stderr}`);
81
85
  assert.match(dem.stdout, /^Demoted /, `demote rendered\n${dem.stdout}`);
82
86
  {
83
87
  const b = h.node(B);
@@ -87,7 +91,7 @@ test('node demote flips lifecycle→terminal IN PLACE; node recycle is FINISH+RE
87
91
  assert.equal(b.status, 'active', 'demote does NOT finish B — it keeps running in place');
88
92
  assert.notEqual(b.intent ?? null, 'done', 'demote does NOT finalize B');
89
93
  }
90
- // --- node recycle: FINISH + RECYCLE. Driven through the real recycleNode.
94
+ // --- node lifecycle recycle: FINISH + RECYCLE. Driven through the real recycleNode.
91
95
  // Its FINISH+MINT model half runs fully; the pane respawn is the only
92
96
  // tmux artifact (no pane for a broker node), so recycled:false while
93
97
  // finalized:true and a fresh root IS minted — the bug-lock (recycle ≠
@@ -130,7 +134,9 @@ test('node demote flips lifecycle→terminal IN PLACE; node recycle is FINISH+RE
130
134
  // fires on the yield path, that ack moves WITHOUT the orchestration steer
131
135
  // ever being delivered — the A4 LOSS.
132
136
  // ===========================================================================
133
- test('A4: a base→orchestrator yield auto-promotes + sets refresh but leaves persona_ack PENDING (the steer is never delivered)', { timeout: 20_000 }, async () => {
137
+ test('A4: a base→orchestrator yield auto-promotes + sets refresh but leaves persona_ack PENDING (the steer is never delivered)',
138
+ // Full-CLI subprocess spawn under load — see the sibling test's budget note.
139
+ { timeout: 60_000 }, async () => {
134
140
  const h = await createHeadlessHarness({ sessionPrefix: 'crtr-live-a4' });
135
141
  try {
136
142
  const A = h.spawnRoot('resident root');
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // HEADLESS RETARGET (foundation-spec §C.12 + §E). AXIS: LIVE MUTATION of the
4
4
  // 2×2 state vector (mode {base,orchestrator} × lifecycle {terminal,resident})
5
- // driven through the REAL `node lifecycle` / `node promote` CLI verbs against
5
+ // driven through the REAL `node config --lifecycle` / `node promote` CLI verbs against
6
6
  // FABRICATED broker-hosted (paneless) nodes — no real tmux session, no pane
7
7
  // chrome, and NO real broker boot. The mutation verbs and the decisions they
8
8
  // gate are host-independent model logic, so the file never pays the ~5s SDK-boot
@@ -50,13 +50,16 @@ function persona(m) {
50
50
  }
51
51
  const SIGNALS = { pushedFinal: false, askedHuman: false };
52
52
  // ===========================================================================
53
- // (a) LIFECYCLE FLIP — `crtr node lifecycle` on a LIVE node, both directions,
53
+ // (a) LIFECYCLE FLIP — `crtr node config --lifecycle` on a LIVE node, both directions,
54
54
  // observing the idle-release DECISION change. A round-trip on ONE node
55
55
  // (terminal→resident→terminal) proves both directions: a flipped-resident
56
56
  // node no longer idle-releases (evaluateStop → dormant); flipped-terminal it
57
57
  // idle-releases again (evaluateStop → awaiting, on its active live sub).
58
58
  // ===========================================================================
59
- test('live lifecycle flip: terminal→resident suppresses idle-release; resident→terminal restores it', { timeout: 20_000 }, async () => {
59
+ test('live lifecycle flip: terminal→resident suppresses idle-release; resident→terminal restores it',
60
+ // Full-CLI subprocess spawns under load — 20s blew on the slower CI runner
61
+ // (passes fast locally); 60s = safe margin. Same class as live-mutation-verbs.
62
+ { timeout: 60_000 }, async () => {
60
63
  const h = await createHeadlessHarness({ sessionPrefix: 'crtr-live-life' });
61
64
  try {
62
65
  // A (resident root) ─ B (base/terminal) ─ C (base/terminal). B holds an
@@ -86,13 +89,13 @@ test('live lifecycle flip: terminal→resident suppresses idle-release; resident
86
89
  // --- FLIP 1: terminal → RESIDENT (live). Oracle §4: sets lifecycle + the
87
90
  // launch spec, status/intent UNTOUCHED. ---
88
91
  {
89
- const res = h.cli(B, ['node', 'lifecycle', 'resident', '--node', B]);
90
- assert.equal(res.code, 0, `lifecycle resident exit 0\n${res.stderr}`);
92
+ const res = h.cli(B, ['node', 'config', '--lifecycle', 'resident', '--node', B]);
93
+ assert.equal(res.code, 0, `config --lifecycle resident exit 0\n${res.stderr}`);
91
94
  const b = h.node(B);
92
95
  assert.equal(b.lifecycle, 'resident', 'B → resident');
93
96
  assert.equal(b.mode, 'base', 'mode UNCHANGED by a lifecycle flip (orthogonal axis)');
94
- assert.equal(b.status, 'active', 'status UNTOUCHED by node lifecycle (oracle §4)');
95
- assert.equal(b.intent ?? null, null, 'intent UNTOUCHED by node lifecycle (oracle §4)');
97
+ assert.equal(b.status, 'active', 'status UNTOUCHED by node config --lifecycle (oracle §4)');
98
+ assert.equal(b.intent ?? null, null, 'intent UNTOUCHED by node config --lifecycle (oracle §4)');
96
99
  }
97
100
  // THE SUPPRESSION LOCK — as RESIDENT, B's stop is 'dormant' (NOT awaiting):
98
101
  // a resident node is never forced to submit a final, so it does NOT idle-
@@ -108,8 +111,8 @@ test('live lifecycle flip: terminal→resident suppresses idle-release; resident
108
111
  }
109
112
  // --- FLIP 2: resident → TERMINAL (live), on the now-resident node. ---
110
113
  {
111
- const res = h.cli(B, ['node', 'lifecycle', 'terminal', '--node', B]);
112
- assert.equal(res.code, 0, `lifecycle terminal exit 0\n${res.stderr}`);
114
+ const res = h.cli(B, ['node', 'config', '--lifecycle', 'terminal', '--node', B]);
115
+ assert.equal(res.code, 0, `config --lifecycle terminal exit 0\n${res.stderr}`);
113
116
  const b = h.node(B);
114
117
  assert.equal(b.lifecycle, 'terminal', 'B → terminal');
115
118
  assert.equal(b.status, 'active', 'status still UNTOUCHED by the flip');
@@ -137,7 +140,9 @@ test('live lifecycle flip: terminal→resident suppresses idle-release; resident
137
140
  // the model precondition of the recompose (whose commit is locked by
138
141
  // persona.test.ts).
139
142
  // ===========================================================================
140
- test('live mode flip: promote base→orchestrator leaves persona_ack PENDING for the turn_end injector', { timeout: 20_000 }, async () => {
143
+ test('live mode flip: promote base→orchestrator leaves persona_ack PENDING for the turn_end injector',
144
+ // Full-CLI subprocess spawn under load — see the sibling test's budget note.
145
+ { timeout: 60_000 }, async () => {
141
146
  const h = await createHeadlessHarness({ sessionPrefix: 'crtr-live-mode' });
142
147
  try {
143
148
  const A = h.spawnRoot('resident root');
@@ -6,6 +6,7 @@ import { join } from 'node:path';
6
6
  import { DatabaseSync } from 'node:sqlite';
7
7
  import { openDb, closeDb, migrate, MIGRATIONS } from '../canvas/db.js';
8
8
  import { canvasDbPath, ensureHome } from '../canvas/paths.js';
9
+ import { listTriggers } from '../canvas/triggers.js';
9
10
  const RUNTIME_COLUMNS = ['intent', 'pi_pid', 'window', 'tmux_session'];
10
11
  let home;
11
12
  function userVersion(db) {
@@ -271,3 +272,126 @@ test('bug #99: a stale v4 db with later columns already present migrates cleanly
271
272
  assert.equal(row.pane, '%9');
272
273
  assert.equal(row.host_kind, 'broker');
273
274
  });
275
+ // --- v9: wakeups → triggers (the unified node-trigger-grammar substrate) ---
276
+ /** Build a hand-rolled db at exactly v8: baseline nodes/edges + the v7
277
+ * `wakeups` table, `user_version = 8` — the shape the live fleet reaches just
278
+ * before v9. Caller seeds `wakeups` rows, we close it; the next openDb() runs
279
+ * only v9 over it. */
280
+ function buildV8DbWithWakeups() {
281
+ ensureHome();
282
+ const raw = new DatabaseSync(canvasDbPath());
283
+ raw.exec(`
284
+ CREATE TABLE nodes (
285
+ node_id TEXT PRIMARY KEY,
286
+ name TEXT NOT NULL,
287
+ kind TEXT NOT NULL,
288
+ mode TEXT NOT NULL DEFAULT 'base',
289
+ lifecycle TEXT NOT NULL DEFAULT 'terminal',
290
+ status TEXT NOT NULL DEFAULT 'active',
291
+ cwd TEXT NOT NULL,
292
+ parent TEXT,
293
+ created TEXT NOT NULL,
294
+ intent TEXT,
295
+ pi_pid INTEGER,
296
+ window TEXT,
297
+ tmux_session TEXT,
298
+ pane TEXT,
299
+ host_kind TEXT
300
+ );
301
+ CREATE TABLE edges (
302
+ type TEXT NOT NULL,
303
+ from_id TEXT NOT NULL,
304
+ to_id TEXT NOT NULL,
305
+ active INTEGER NOT NULL DEFAULT 1,
306
+ created TEXT NOT NULL,
307
+ PRIMARY KEY (type, from_id, to_id)
308
+ );
309
+ CREATE TABLE wakeups (
310
+ wakeup_id TEXT PRIMARY KEY,
311
+ node_id TEXT,
312
+ owner_id TEXT NOT NULL,
313
+ fire_at TEXT NOT NULL,
314
+ kind TEXT NOT NULL,
315
+ recur TEXT,
316
+ payload TEXT,
317
+ created TEXT NOT NULL,
318
+ FOREIGN KEY (node_id) REFERENCES nodes(node_id) ON DELETE CASCADE
319
+ );
320
+ PRAGMA user_version = 8;
321
+ `);
322
+ insertNode(raw, 'armer');
323
+ insertNode(raw, 'tgt');
324
+ return raw;
325
+ }
326
+ function insertWakeup(db, row) {
327
+ db.prepare('INSERT INTO wakeups (wakeup_id, node_id, owner_id, fire_at, kind, recur, payload, created) VALUES (?,?,?,?,?,?,?,?)').run(row.wakeup_id, row.node_id, row.owner_id, row.fire_at, row.kind, row.recur ?? null, row.payload ?? null, '2020-01-01T00:00:00Z');
328
+ }
329
+ test('v9 migrates every wakeups row into triggers, preserving ids/fire data, then drops wakeups', () => {
330
+ const raw = buildV8DbWithWakeups();
331
+ insertWakeup(raw, { wakeup_id: 'wk-bare', node_id: 'tgt', owner_id: 'armer', fire_at: '2026-01-01T00:00:00.000Z', kind: 'bare' });
332
+ insertWakeup(raw, {
333
+ wakeup_id: 'wk-noted',
334
+ node_id: 'tgt',
335
+ owner_id: 'armer',
336
+ fire_at: '2026-01-02T00:00:00.000Z',
337
+ kind: 'noted',
338
+ payload: JSON.stringify({ body: 'check CI', label: 'check CI' }),
339
+ });
340
+ insertWakeup(raw, {
341
+ wakeup_id: 'wk-deadline',
342
+ node_id: 'tgt',
343
+ owner_id: 'tgt',
344
+ fire_at: '2026-01-03T00:00:00.000Z',
345
+ kind: 'deadline',
346
+ payload: JSON.stringify({ body: 'timed out', timeout: true, label: 'timed out' }),
347
+ });
348
+ insertWakeup(raw, {
349
+ wakeup_id: 'wk-spawn-cron',
350
+ node_id: null,
351
+ owner_id: 'armer',
352
+ fire_at: '2026-01-04T00:00:00.000Z',
353
+ kind: 'spawn',
354
+ recur: JSON.stringify({ every: '6h' }),
355
+ payload: JSON.stringify({ kind: 'general', mode: 'base', cwd: '/tmp/work', prompt: 'go', parent: 'armer' }),
356
+ });
357
+ assert.equal(userVersion(raw), 8);
358
+ raw.close();
359
+ const db = openDb();
360
+ assert.equal(userVersion(db), MIGRATIONS.length);
361
+ // The old table is gone — not kept as a parallel alias.
362
+ const tables = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((r) => r.name);
363
+ assert.ok(!tables.includes('wakeups'), 'wakeups table is dropped after migration');
364
+ assert.ok(tables.includes('triggers'), 'triggers table exists');
365
+ const byId = (id) => db.prepare('SELECT * FROM triggers WHERE trigger_id = ?').get(id);
366
+ const bare = byId('wk-bare');
367
+ assert.equal(bare.owner_id, 'armer');
368
+ assert.equal(bare.node_id, 'tgt');
369
+ assert.equal(bare.action, 'msg');
370
+ assert.equal(bare.action_mode, 'fresh_revive');
371
+ assert.equal(bare.trigger_type, 'at');
372
+ assert.equal(bare.fire_at, '2026-01-01T00:00:00.000Z');
373
+ const noted = byId('wk-noted');
374
+ assert.equal(noted.action, 'msg');
375
+ assert.equal(noted.action_mode, 'inbox_message');
376
+ assert.equal(noted.trigger_type, 'at');
377
+ assert.deepEqual(JSON.parse(noted.payload), { body: 'check CI', label: 'check CI' });
378
+ const deadline = byId('wk-deadline');
379
+ assert.equal(deadline.action, 'msg');
380
+ assert.equal(deadline.action_mode, 'deadline_message');
381
+ assert.equal(deadline.trigger_type, 'until', "a deadline row's trigger_type is 'until', not 'at'");
382
+ assert.equal(deadline.node_id, 'tgt');
383
+ const spawnCron = byId('wk-spawn-cron');
384
+ assert.equal(spawnCron.action, 'new');
385
+ assert.equal(spawnCron.action_mode, 'node_birth');
386
+ assert.equal(spawnCron.trigger_type, 'every', 'a recurring spawn keeps trigger_type=every');
387
+ assert.equal(spawnCron.node_id, null, 'a detached spawn-cron stays canvas-detached');
388
+ assert.equal(spawnCron.recur, JSON.stringify({ every: '6h' }));
389
+ // The migrated rows are readable via the current triggers DAO, keyed by
390
+ // trigger_id (preserved from wakeup_id) and the current action/action_mode
391
+ // vocabulary rather than the dropped per-kind wakeups shape.
392
+ const allTriggers = listTriggers({ canvas: true });
393
+ assert.equal(allTriggers.length, 4);
394
+ const migratedBare = allTriggers.find((t) => t.trigger_id === 'wk-bare');
395
+ assert.equal(migratedBare.action_mode, 'fresh_revive');
396
+ assert.equal(migratedBare.node_id, 'tgt');
397
+ });