openplanr 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/cli/commands/groups/delivery.d.ts.map +1 -1
  3. package/dist/cli/commands/groups/delivery.js +2 -0
  4. package/dist/cli/commands/groups/delivery.js.map +1 -1
  5. package/dist/cli/commands/planning-artifacts.d.ts.map +1 -1
  6. package/dist/cli/commands/planning-artifacts.js +22 -12
  7. package/dist/cli/commands/planning-artifacts.js.map +1 -1
  8. package/dist/cli/commands/ship.d.ts +3 -0
  9. package/dist/cli/commands/ship.d.ts.map +1 -0
  10. package/dist/cli/commands/ship.js +65 -0
  11. package/dist/cli/commands/ship.js.map +1 -0
  12. package/dist/dashboard/.vite/manifest.json +1 -1
  13. package/dist/dashboard/assets/{index-G7ygVDGg.js → index-L8qtwqv6.js} +2 -2
  14. package/dist/dashboard/assets/{index-G7ygVDGg.js.map → index-L8qtwqv6.js.map} +1 -1
  15. package/dist/dashboard/dashboard-manifest.json +8 -8
  16. package/dist/dashboard/index.html +1 -1
  17. package/dist/models/schema.d.ts +39 -23
  18. package/dist/models/schema.d.ts.map +1 -1
  19. package/dist/models/schema.js +19 -12
  20. package/dist/models/schema.js.map +1 -1
  21. package/dist/models/types.d.ts +6 -0
  22. package/dist/models/types.d.ts.map +1 -1
  23. package/dist/services/id-service.d.ts +1 -5
  24. package/dist/services/id-service.d.ts.map +1 -1
  25. package/dist/services/id-service.js +1 -34
  26. package/dist/services/id-service.js.map +1 -1
  27. package/dist/services/ship-checks/changes.d.ts +24 -0
  28. package/dist/services/ship-checks/changes.d.ts.map +1 -0
  29. package/dist/services/ship-checks/changes.js +135 -0
  30. package/dist/services/ship-checks/changes.js.map +1 -0
  31. package/dist/services/ship-checks/contract.d.ts +81 -0
  32. package/dist/services/ship-checks/contract.d.ts.map +1 -0
  33. package/dist/services/ship-checks/contract.js +7 -0
  34. package/dist/services/ship-checks/contract.js.map +1 -0
  35. package/dist/services/ship-checks/discover.d.ts +10 -0
  36. package/dist/services/ship-checks/discover.d.ts.map +1 -0
  37. package/dist/services/ship-checks/discover.js +250 -0
  38. package/dist/services/ship-checks/discover.js.map +1 -0
  39. package/dist/services/ship-checks/glob.d.ts +5 -0
  40. package/dist/services/ship-checks/glob.d.ts.map +1 -0
  41. package/dist/services/ship-checks/glob.js +39 -0
  42. package/dist/services/ship-checks/glob.js.map +1 -0
  43. package/dist/services/ship-checks/hooks.d.ts +7 -0
  44. package/dist/services/ship-checks/hooks.d.ts.map +1 -0
  45. package/dist/services/ship-checks/hooks.js +65 -0
  46. package/dist/services/ship-checks/hooks.js.map +1 -0
  47. package/dist/services/ship-checks/packages.d.ts +29 -0
  48. package/dist/services/ship-checks/packages.d.ts.map +1 -0
  49. package/dist/services/ship-checks/packages.js +197 -0
  50. package/dist/services/ship-checks/packages.js.map +1 -0
  51. package/dist/services/ship-checks/related-tests.d.ts +13 -0
  52. package/dist/services/ship-checks/related-tests.d.ts.map +1 -0
  53. package/dist/services/ship-checks/related-tests.js +73 -0
  54. package/dist/services/ship-checks/related-tests.js.map +1 -0
  55. package/dist/services/ship-checks/scope.d.ts +8 -0
  56. package/dist/services/ship-checks/scope.d.ts.map +1 -0
  57. package/dist/services/ship-checks/scope.js +66 -0
  58. package/dist/services/ship-checks/scope.js.map +1 -0
  59. package/dist/services/ship-checks/task-requirements.d.ts +14 -0
  60. package/dist/services/ship-checks/task-requirements.d.ts.map +1 -0
  61. package/dist/services/ship-checks/task-requirements.js +145 -0
  62. package/dist/services/ship-checks/task-requirements.js.map +1 -0
  63. package/dist/services/ship-checks/workflows.d.ts +21 -0
  64. package/dist/services/ship-checks/workflows.d.ts.map +1 -0
  65. package/dist/services/ship-checks/workflows.js +208 -0
  66. package/dist/services/ship-checks/workflows.js.map +1 -0
  67. package/dist/services/template-service.d.ts +2 -0
  68. package/dist/services/template-service.d.ts.map +1 -1
  69. package/dist/services/template-service.js +4 -0
  70. package/dist/services/template-service.js.map +1 -1
  71. package/dist/utils/slugify.d.ts +1 -8
  72. package/dist/utils/slugify.d.ts.map +1 -1
  73. package/dist/utils/slugify.js +1 -25
  74. package/dist/utils/slugify.js.map +1 -1
  75. package/docs/CLI.md +48 -1
  76. package/lib/backlog-item.d.mts +49 -0
  77. package/lib/backlog-item.mjs +339 -0
  78. package/lib/host-packages/adapter-registry.json +5 -5
  79. package/lib/host-packages/capability-map.json +1 -1
  80. package/lib/host-packages/claude/.claude-plugin/marketplace.json +2 -2
  81. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +1 -1
  82. package/lib/host-packages/claude/openplanr/.openplanr-content.json +126 -90
  83. package/lib/host-packages/claude/openplanr/CONNECTORS.md +4 -6
  84. package/lib/host-packages/claude/openplanr/README.md +1 -1
  85. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-artifact-shell.mjs +1 -1
  86. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +1 -1
  87. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +385 -79
  88. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +1 -1
  89. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-resource-pack.mjs +1 -1
  90. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review.mjs +45 -4
  91. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/design-runtime-support-e34c388a8e59.mjs → claude/openplanr/runtime/design/scripts/design-runtime-support-6774fd3d5d02.mjs} +1 -1
  92. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +8 -5
  93. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +40 -7
  94. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +1 -1
  95. package/lib/host-packages/claude/openplanr/runtime/design/scripts/{design-shared-protocol-contracts-31a760fc.mjs → design-shared-protocol-contracts-b5f28f94.mjs} +284 -45
  96. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-upload-spool.mjs +1 -1
  97. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +215 -55
  98. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +23 -23
  99. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +246 -45
  100. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +12 -12
  101. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +47 -14
  102. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +11 -10
  103. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -3
  104. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +16 -11
  105. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +7 -11
  106. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +163 -274
  107. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +494 -967
  108. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +346 -678
  109. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +382 -810
  110. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +406 -730
  111. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +259 -522
  112. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +585 -937
  113. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +115 -240
  114. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +7 -17
  115. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +3 -4
  116. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +215 -0
  117. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +2766 -0
  118. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +134 -0
  119. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +2170 -0
  120. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +16 -0
  121. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +8 -0
  122. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +3883 -0
  123. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +966 -0
  124. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/{16-studio-shell.js → 20-studio-shell.js} +122 -227
  125. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +1583 -0
  126. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +101 -47
  127. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  128. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0 → claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0}/design-document.schema.json +78 -5
  129. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +247 -45
  130. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +45 -12
  131. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  132. package/lib/host-packages/claude/openplanr/skills/connect/references/connectors.md +4 -6
  133. package/lib/host-packages/claude/openplanr/skills/design/SKILL.md +12 -0
  134. package/lib/host-packages/claude/openplanr/skills/design/references/craft.md +14 -3
  135. package/lib/host-packages/claude/openplanr/skills/design/references/design-system.md +33 -1
  136. package/lib/host-packages/claude/openplanr/skills/design/references/discovery.md +18 -4
  137. package/lib/host-packages/claude/openplanr/skills/design/references/generation.md +74 -1
  138. package/lib/host-packages/claude/openplanr/skills/design/references/hosted-canvas.md +62 -0
  139. package/lib/host-packages/claude/openplanr/skills/design/references/review.md +46 -1
  140. package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +6 -0
  141. package/lib/host-packages/claude/openplanr/skills/design/schemas/design-document.schema.json +78 -5
  142. package/lib/host-packages/claude/openplanr/skills/design-loop/references/craft.md +14 -3
  143. package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-system.md +33 -1
  144. package/lib/host-packages/claude/openplanr/skills/design-loop/references/discovery.md +18 -4
  145. package/lib/host-packages/claude/openplanr/skills/design-loop/references/generation.md +74 -1
  146. package/lib/host-packages/claude/openplanr/skills/design-loop/references/review.md +46 -1
  147. package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +6 -0
  148. package/lib/host-packages/claude/openplanr/skills/design-loop/schemas/design-document.schema.json +78 -5
  149. package/lib/host-packages/claude/openplanr/skills/design-review/references/craft.md +14 -3
  150. package/lib/host-packages/claude/openplanr/skills/design-review/references/design-system.md +33 -1
  151. package/lib/host-packages/claude/openplanr/skills/design-review/references/discovery.md +18 -4
  152. package/lib/host-packages/claude/openplanr/skills/design-review/references/generation.md +74 -1
  153. package/lib/host-packages/claude/openplanr/skills/design-review/references/review.md +46 -1
  154. package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +6 -0
  155. package/lib/host-packages/claude/openplanr/skills/design-review/schemas/design-document.schema.json +78 -5
  156. package/lib/host-packages/claude/openplanr/skills/investigate/SKILL.md +10 -1
  157. package/lib/host-packages/claude/openplanr/skills/investigate/references/findings.md +92 -0
  158. package/lib/host-packages/claude/openplanr/skills/investigate/scripts/backlog-item.mjs +339 -0
  159. package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +3 -0
  160. package/lib/host-packages/claude/openplanr/skills/plan/schemas/design-document.schema.json +78 -5
  161. package/lib/host-packages/claude/openplanr/skills/share/references/connectors.md +4 -6
  162. package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +15 -4
  163. package/lib/host-packages/claude/openplanr/skills/ship/references/findings.md +92 -0
  164. package/lib/host-packages/claude/openplanr/skills/ship/references/result-contract.md +3 -1
  165. package/lib/host-packages/claude/openplanr/skills/ship/scripts/backlog-item.mjs +339 -0
  166. package/lib/host-packages/claude/openplanr/skills/sprint/references/connectors.md +4 -6
  167. package/lib/host-packages/claude/openplanr/skills/status/references/connectors.md +4 -6
  168. package/lib/host-packages/claude/openplanr/skills/sync/references/connectors.md +4 -6
  169. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +125 -89
  170. package/lib/host-packages/cursor/openplanr/CONNECTORS.md +4 -6
  171. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  172. package/lib/host-packages/cursor/openplanr/rules/planr-connect/references/connectors.md +4 -6
  173. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/craft.md +14 -3
  174. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-system.md +33 -1
  175. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/discovery.md +18 -4
  176. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/generation.md +74 -1
  177. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/hosted-canvas.md +62 -0
  178. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/review.md +46 -1
  179. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +6 -0
  180. package/lib/host-packages/cursor/openplanr/rules/planr-design/schemas/design-document.schema.json +78 -5
  181. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/craft.md +14 -3
  182. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-system.md +33 -1
  183. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/discovery.md +18 -4
  184. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/generation.md +74 -1
  185. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/review.md +46 -1
  186. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +6 -0
  187. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/schemas/design-document.schema.json +78 -5
  188. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/craft.md +14 -3
  189. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-system.md +33 -1
  190. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/discovery.md +18 -4
  191. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/generation.md +74 -1
  192. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/review.md +46 -1
  193. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +6 -0
  194. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/schemas/design-document.schema.json +78 -5
  195. package/lib/host-packages/cursor/openplanr/rules/planr-design.mdc +12 -0
  196. package/lib/host-packages/cursor/openplanr/rules/planr-investigate/references/findings.md +92 -0
  197. package/lib/host-packages/cursor/openplanr/rules/planr-investigate/scripts/backlog-item.mjs +339 -0
  198. package/lib/host-packages/cursor/openplanr/rules/planr-investigate.mdc +10 -1
  199. package/lib/host-packages/cursor/openplanr/rules/planr-plan/schemas/design-document.schema.json +78 -5
  200. package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +3 -0
  201. package/lib/host-packages/cursor/openplanr/rules/planr-share/references/connectors.md +4 -6
  202. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/findings.md +92 -0
  203. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/result-contract.md +3 -1
  204. package/lib/host-packages/cursor/openplanr/rules/planr-ship/scripts/backlog-item.mjs +339 -0
  205. package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +15 -4
  206. package/lib/host-packages/cursor/openplanr/rules/planr-sprint/references/connectors.md +4 -6
  207. package/lib/host-packages/cursor/openplanr/rules/planr-status/references/connectors.md +4 -6
  208. package/lib/host-packages/cursor/openplanr/rules/planr-sync/references/connectors.md +4 -6
  209. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-artifact-shell.mjs +1 -1
  210. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +1 -1
  211. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +385 -79
  212. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +1 -1
  213. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-resource-pack.mjs +1 -1
  214. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review.mjs +45 -4
  215. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-runtime-support-e34c388a8e59.mjs → cursor/openplanr/runtime/design/scripts/design-runtime-support-6774fd3d5d02.mjs} +1 -1
  216. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +8 -5
  217. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +40 -7
  218. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +1 -1
  219. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-31a760fc.mjs → cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs} +284 -45
  220. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-upload-spool.mjs +1 -1
  221. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +215 -55
  222. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +23 -23
  223. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +246 -45
  224. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +12 -12
  225. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +47 -14
  226. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +11 -10
  227. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -3
  228. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +16 -11
  229. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +7 -11
  230. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +163 -274
  231. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +494 -967
  232. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +346 -678
  233. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +382 -810
  234. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +406 -730
  235. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +259 -522
  236. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +585 -937
  237. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +115 -240
  238. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +7 -17
  239. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +3 -4
  240. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +215 -0
  241. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +2766 -0
  242. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +134 -0
  243. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +2170 -0
  244. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +16 -0
  245. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +8 -0
  246. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +3883 -0
  247. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +966 -0
  248. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/{16-studio-shell.js → 20-studio-shell.js} +122 -227
  249. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +1583 -0
  250. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +101 -47
  251. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  252. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0 → cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0}/design-document.schema.json +78 -5
  253. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +247 -45
  254. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +45 -12
  255. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  256. package/lib/host-packages/openai/.claude-plugin/marketplace.json +2 -2
  257. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +1 -1
  258. package/lib/host-packages/openai/openplanr/.openplanr-content.json +128 -92
  259. package/lib/host-packages/openai/openplanr/CONNECTORS.md +4 -6
  260. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-artifact-shell.mjs +1 -1
  261. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +1 -1
  262. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +385 -79
  263. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +1 -1
  264. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-resource-pack.mjs +1 -1
  265. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review.mjs +45 -4
  266. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/design-runtime-support-e34c388a8e59.mjs → openai/openplanr/runtime/design/scripts/design-runtime-support-6774fd3d5d02.mjs} +1 -1
  267. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +8 -5
  268. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +40 -7
  269. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +1 -1
  270. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-31a760fc.mjs → openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs} +284 -45
  271. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-upload-spool.mjs +1 -1
  272. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +215 -55
  273. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +23 -23
  274. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +246 -45
  275. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +12 -12
  276. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +47 -14
  277. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +11 -10
  278. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -3
  279. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +16 -11
  280. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +7 -11
  281. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +163 -274
  282. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +494 -967
  283. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +346 -678
  284. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +382 -810
  285. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +406 -730
  286. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +259 -522
  287. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +585 -937
  288. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +115 -240
  289. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +7 -17
  290. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +3 -4
  291. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +215 -0
  292. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +2766 -0
  293. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +134 -0
  294. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +2170 -0
  295. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +16 -0
  296. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +8 -0
  297. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +3883 -0
  298. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +966 -0
  299. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/{16-studio-shell.js → 20-studio-shell.js} +122 -227
  300. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +1583 -0
  301. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +101 -47
  302. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  303. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0 → openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0}/design-document.schema.json +78 -5
  304. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +247 -45
  305. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +45 -12
  306. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  307. package/lib/host-packages/openai/openplanr/skills/connect/references/connectors.md +4 -6
  308. package/lib/host-packages/openai/openplanr/skills/design/SKILL.md +12 -0
  309. package/lib/host-packages/openai/openplanr/skills/design/openplanr.skill.json +11 -0
  310. package/lib/host-packages/openai/openplanr/skills/design/references/craft.md +14 -3
  311. package/lib/host-packages/openai/openplanr/skills/design/references/design-system.md +33 -1
  312. package/lib/host-packages/openai/openplanr/skills/design/references/discovery.md +18 -4
  313. package/lib/host-packages/openai/openplanr/skills/design/references/generation.md +74 -1
  314. package/lib/host-packages/openai/openplanr/skills/design/references/hosted-canvas.md +62 -0
  315. package/lib/host-packages/openai/openplanr/skills/design/references/review.md +46 -1
  316. package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +6 -0
  317. package/lib/host-packages/openai/openplanr/skills/design/schemas/design-document.schema.json +78 -5
  318. package/lib/host-packages/openai/openplanr/skills/design-loop/references/craft.md +14 -3
  319. package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-system.md +33 -1
  320. package/lib/host-packages/openai/openplanr/skills/design-loop/references/discovery.md +18 -4
  321. package/lib/host-packages/openai/openplanr/skills/design-loop/references/generation.md +74 -1
  322. package/lib/host-packages/openai/openplanr/skills/design-loop/references/review.md +46 -1
  323. package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +6 -0
  324. package/lib/host-packages/openai/openplanr/skills/design-loop/schemas/design-document.schema.json +78 -5
  325. package/lib/host-packages/openai/openplanr/skills/design-review/references/craft.md +14 -3
  326. package/lib/host-packages/openai/openplanr/skills/design-review/references/design-system.md +33 -1
  327. package/lib/host-packages/openai/openplanr/skills/design-review/references/discovery.md +18 -4
  328. package/lib/host-packages/openai/openplanr/skills/design-review/references/generation.md +74 -1
  329. package/lib/host-packages/openai/openplanr/skills/design-review/references/review.md +46 -1
  330. package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +6 -0
  331. package/lib/host-packages/openai/openplanr/skills/design-review/schemas/design-document.schema.json +78 -5
  332. package/lib/host-packages/openai/openplanr/skills/investigate/SKILL.md +10 -1
  333. package/lib/host-packages/openai/openplanr/skills/investigate/openplanr.skill.json +22 -0
  334. package/lib/host-packages/openai/openplanr/skills/investigate/references/findings.md +92 -0
  335. package/lib/host-packages/openai/openplanr/skills/investigate/scripts/backlog-item.mjs +339 -0
  336. package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +3 -0
  337. package/lib/host-packages/openai/openplanr/skills/plan/schemas/design-document.schema.json +78 -5
  338. package/lib/host-packages/openai/openplanr/skills/share/references/connectors.md +4 -6
  339. package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +15 -4
  340. package/lib/host-packages/openai/openplanr/skills/ship/openplanr.skill.json +22 -0
  341. package/lib/host-packages/openai/openplanr/skills/ship/references/findings.md +92 -0
  342. package/lib/host-packages/openai/openplanr/skills/ship/references/result-contract.md +3 -1
  343. package/lib/host-packages/openai/openplanr/skills/ship/scripts/backlog-item.mjs +339 -0
  344. package/lib/host-packages/openai/openplanr/skills/sprint/references/connectors.md +4 -6
  345. package/lib/host-packages/openai/openplanr/skills/status/references/connectors.md +4 -6
  346. package/lib/host-packages/openai/openplanr/skills/sync/references/connectors.md +4 -6
  347. package/package.json +3 -3
  348. package/dist/templates/backlog/backlog-item.md.hbs +0 -40
  349. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +0 -3589
  350. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +0 -184
  351. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +0 -5229
  352. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +0 -1733
  353. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +0 -1844
  354. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +0 -3589
  355. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +0 -184
  356. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +0 -5229
  357. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +0 -1733
  358. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +0 -1844
  359. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +0 -3589
  360. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +0 -184
  361. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +0 -5229
  362. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +0 -1733
  363. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +0 -1844
@@ -12,8 +12,10 @@ import {
12
12
  ARTIFACT_WORKER_GUARD_SOURCE
13
13
  } from "./design-sandbox-guards.mjs";
14
14
  import {
15
+ atomicBytes,
15
16
  atomicJson,
16
17
  bundleLocalDocument,
18
+ currentDesign,
17
19
  designSpecPath,
18
20
  hash,
19
21
  json,
@@ -40,21 +42,82 @@ import {
40
42
  resolveArtifactHtml
41
43
  } from "./design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs";
42
44
  import {
43
- assertDesignDocument
44
- } from "./design-shared-protocol-contracts-31a760fc.mjs";
45
+ DESIGN_DOCUMENT_SCHEMA,
46
+ assertDesignDocument,
47
+ initialFrameHeight
48
+ } from "./design-shared-protocol-contracts-b5f28f94.mjs";
49
+
50
+ // packages/design/lib/design/frame-size.mjs
51
+ function designFrameLabel(frame) {
52
+ const dimensions = `${frame.width} \xD7 ${frame.height}`;
53
+ return frame.label.includes(dimensions) ? frame.label : `${frame.label} \xB7 ${dimensions}`;
54
+ }
55
+ function designFrameViewport(document2, frame) {
56
+ return {
57
+ width: frame.width,
58
+ height: frame.height === "auto" ? initialFrameHeight(document2) : frame.height
59
+ };
60
+ }
61
+ function matchesDesignFrame(frame, viewport) {
62
+ return Boolean(
63
+ frame && viewport?.width === frame.width && (frame.height === "auto" ? Number.isInteger(viewport.height) && viewport.height > 0 && viewport.height <= 16384 : viewport.height === frame.height)
64
+ );
65
+ }
66
+ function observeDesignFrameSize() {
67
+ let pending = false;
68
+ const measure = async () => {
69
+ if (pending) return;
70
+ pending = true;
71
+ try {
72
+ await document.fonts.ready;
73
+ await new Promise((resolve3) => requestAnimationFrame(() => requestAnimationFrame(resolve3)));
74
+ parent.postMessage(
75
+ {
76
+ type: "openplanr:design-size",
77
+ screenId: document.body.getAttribute("data-planr-screen"),
78
+ width: innerWidth,
79
+ height: Math.min(16384, Math.max(1, document.documentElement.scrollHeight))
80
+ },
81
+ "*"
82
+ );
83
+ } finally {
84
+ pending = false;
85
+ }
86
+ };
87
+ const schedule = () => {
88
+ void measure().catch((error) => {
89
+ parent.postMessage({ type: "openplanr:design-size-error", message: error.message }, "*");
90
+ });
91
+ };
92
+ addEventListener("message", (event) => {
93
+ if (event.source === parent && event.data?.type === "openplanr:design-measure") schedule();
94
+ });
95
+ addEventListener(
96
+ "load",
97
+ () => {
98
+ new ResizeObserver(schedule).observe(document.body);
99
+ schedule();
100
+ },
101
+ { once: true }
102
+ );
103
+ }
104
+
105
+ // packages/design/lib/design/layout-save.mjs
106
+ import { readFileSync as readFileSync6, statSync } from "node:fs";
107
+ import { join as join3 } from "node:path";
45
108
 
46
109
  // packages/design/lib/design/document.mjs
47
110
  import { randomUUID } from "node:crypto";
48
111
  import {
49
112
  existsSync as existsSync2,
50
113
  mkdirSync,
51
- readFileSync as readFileSync4,
114
+ readFileSync as readFileSync5,
52
115
  realpathSync,
53
116
  renameSync,
54
117
  rmSync,
55
118
  writeFileSync
56
119
  } from "node:fs";
57
- import { dirname, join, resolve as resolve2 } from "node:path";
120
+ import { dirname, join as join2, resolve as resolve2 } from "node:path";
58
121
 
59
122
  // packages/artifact/lib/artifact/bridge.mjs
60
123
  import { randomBytes as randomBytes2 } from "node:crypto";
@@ -149,7 +212,9 @@ function createArtifactViewportGestures(window2, emit) {
149
212
  mode: getter(window2.WheelEvent.prototype, "deltaMode")
150
213
  };
151
214
  let enabled = false, disposed = false, timer = 0, pending = null, pendingType = "";
215
+ let gestureScale = 1;
152
216
  const clear = () => {
217
+ gestureScale = 1;
153
218
  if (timer) cancel(timer);
154
219
  timer = 0;
155
220
  pending = null;
@@ -163,6 +228,29 @@ function createArtifactViewportGestures(window2, emit) {
163
228
  pendingType = "";
164
229
  if (enabled && !disposed && value) emit(type, value);
165
230
  };
231
+ const queue = (type, value) => {
232
+ const deltaX = value.deltaX ?? 0;
233
+ const deltaY = value.deltaY ?? 0;
234
+ if (pendingType && pendingType !== type) flush();
235
+ pendingType = type;
236
+ pending = type === "viewport.zoom" ? {
237
+ ...value,
238
+ deltaY: Math.max(
239
+ -ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA,
240
+ Math.min(ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA, (pending?.deltaY || 0) + deltaY)
241
+ )
242
+ } : {
243
+ deltaX: Math.max(
244
+ -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
245
+ Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, (pending?.deltaX || 0) + deltaX)
246
+ ),
247
+ deltaY: Math.max(
248
+ -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
249
+ Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, (pending?.deltaY || 0) + deltaY)
250
+ )
251
+ };
252
+ if (!timer) timer = schedule(flush, 16);
253
+ };
166
254
  const wheel = (event) => {
167
255
  if (!enabled || disposed || !event.isTrusted || !event.cancelable) return;
168
256
  let x, y, deltaX, deltaY, mode, zooming, shift;
@@ -213,34 +301,49 @@ function createArtifactViewportGestures(window2, emit) {
213
301
  if (!value) return;
214
302
  prevent.call(event);
215
303
  stop.call(event);
216
- if (pendingType && pendingType !== type) flush();
217
- pendingType = type;
218
- pending = type === "viewport.zoom" ? {
219
- ...value,
220
- deltaY: Math.max(
221
- -ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA,
222
- Math.min(ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA, (pending?.deltaY || 0) + deltaY)
223
- )
224
- } : {
225
- deltaX: Math.max(
226
- -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
227
- Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, (pending?.deltaX || 0) + deltaX)
228
- ),
229
- deltaY: Math.max(
230
- -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
231
- Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, (pending?.deltaY || 0) + deltaY)
232
- )
233
- };
234
- if (!timer) timer = schedule(flush, 16);
304
+ queue(type, value);
305
+ };
306
+ const consumeGesture = (event) => {
307
+ if (!enabled || disposed || !event.isTrusted || !event.cancelable) return false;
308
+ prevent.call(event);
309
+ stop.call(event);
310
+ return true;
311
+ };
312
+ const gestureStart = (event) => {
313
+ if (consumeGesture(event)) gestureScale = 1;
314
+ };
315
+ const gestureChange = (raw) => {
316
+ if (!consumeGesture(raw)) return;
317
+ const event = raw;
318
+ if (!Number.isFinite(event.scale) || event.scale <= 0) return;
319
+ const deltaY = Math.max(
320
+ -ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA,
321
+ Math.min(ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA, -Math.log(event.scale / gestureScale) / 0.01)
322
+ );
323
+ gestureScale = event.scale;
324
+ const value = normalizeArtifactViewportZoom(
325
+ { x: event.clientX, y: event.clientY, deltaY },
326
+ { width: window2.innerWidth, height: window2.innerHeight }
327
+ );
328
+ if (value) queue("viewport.zoom", value);
329
+ };
330
+ const gestureEnd = (event) => {
331
+ if (consumeGesture(event)) gestureScale = 1;
235
332
  };
236
333
  const destroy = () => {
237
334
  disposed = true;
238
335
  enabled = false;
239
336
  clear();
240
337
  remove("wheel", wheel, true);
338
+ remove("gesturestart", gestureStart, true);
339
+ remove("gesturechange", gestureChange, true);
340
+ remove("gestureend", gestureEnd, true);
241
341
  remove("pagehide", destroy);
242
342
  };
243
343
  add("wheel", wheel, { capture: true, passive: false });
344
+ add("gesturestart", gestureStart, { capture: true, passive: false });
345
+ add("gesturechange", gestureChange, { capture: true, passive: false });
346
+ add("gestureend", gestureEnd, { capture: true, passive: false });
244
347
  add("pagehide", destroy, { once: true });
245
348
  return Object.freeze({
246
349
  setEnabled(value) {
@@ -288,8 +391,8 @@ function normalizeArtifactInspection(value, viewport) {
288
391
  const descriptor = plain(entry) ? Object.getOwnPropertyDescriptor(entry, key) : null;
289
392
  return descriptor && Object.hasOwn(descriptor, "value") ? descriptor.value : void 0;
290
393
  };
291
- const exact = (entry, keys) => plain(entry) && Object.keys(entry).length === keys.length && Object.keys(entry).every((key) => keys.includes(key));
292
- if (!exact(value, ["tagName", "anchor", "rect", "viewport", "styles", "accessibility"]))
394
+ const exact2 = (entry, keys) => plain(entry) && Object.keys(entry).length === keys.length && Object.keys(entry).every((key) => keys.includes(key));
395
+ if (!exact2(value, ["tagName", "anchor", "rect", "viewport", "styles", "accessibility"]))
293
396
  return null;
294
397
  const tagName = own(value, "tagName");
295
398
  const anchor = own(value, "anchor");
@@ -298,7 +401,7 @@ function normalizeArtifactInspection(value, viewport) {
298
401
  const styles = own(value, "styles");
299
402
  const accessibility = own(value, "accessibility");
300
403
  if (typeof tagName !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(tagName)) return null;
301
- if (!exact(size, ["width", "height"]) || !exact(rect, ["x", "y", "width", "height"])) return null;
404
+ if (!exact2(size, ["width", "height"]) || !exact2(rect, ["x", "y", "width", "height"])) return null;
302
405
  if (!["width", "height"].every(
303
406
  (key) => Number.isInteger(own(size, key)) && own(size, key) >= 1 && own(size, key) <= 16384 && own(size, key) === viewport?.[key]
304
407
  ))
@@ -308,14 +411,14 @@ function normalizeArtifactInspection(value, viewport) {
308
411
  ))
309
412
  return null;
310
413
  if (rect.x + rect.width > size.width || rect.y + rect.height > size.height) return null;
311
- if (anchor !== null && (!exact(anchor, own(anchor, "screen") === void 0 ? ["planrId"] : ["planrId", "screen"]) || typeof own(anchor, "planrId") !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/.test(anchor.planrId) || own(anchor, "screen") !== void 0 && (typeof anchor.screen !== "string" || !/^[^\u0000-\u001f\u007f]{1,128}$/.test(anchor.screen))))
414
+ if (anchor !== null && (!exact2(anchor, own(anchor, "screen") === void 0 ? ["planrId"] : ["planrId", "screen"]) || typeof own(anchor, "planrId") !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/.test(anchor.planrId) || own(anchor, "screen") !== void 0 && (typeof anchor.screen !== "string" || !/^[^\u0000-\u001f\u007f]{1,128}$/.test(anchor.screen))))
312
415
  return null;
313
- if (!exact(styles, ARTIFACT_INSPECTION_PROPERTIES) || !ARTIFACT_INSPECTION_PROPERTIES.every((key) => {
416
+ if (!exact2(styles, ARTIFACT_INSPECTION_PROPERTIES) || !ARTIFACT_INSPECTION_PROPERTIES.every((key) => {
314
417
  const text = own(styles, key);
315
418
  return typeof text === "string" && text.length <= 256 && !/[\u0000-\u001f\u007f]/.test(text) && !/(?:url\s*\(|https?:|file:)/i.test(text);
316
419
  }))
317
420
  return null;
318
- if (!exact(accessibility, ["role", "ariaLabel", "alt", "tabIndex", "disabled"]) || !["role", "ariaLabel", "alt"].every(
421
+ if (!exact2(accessibility, ["role", "ariaLabel", "alt", "tabIndex", "disabled"]) || !["role", "ariaLabel", "alt"].every(
319
422
  (key) => typeof own(accessibility, key) === "string" && own(accessibility, key).length <= 256 && !/[\u0000-\u001f\u007f]/.test(own(accessibility, key))
320
423
  ) || !Number.isInteger(own(accessibility, "tabIndex")) || accessibility.tabIndex < -1 || accessibility.tabIndex > 32767 || typeof own(accessibility, "disabled") !== "boolean")
321
424
  return null;
@@ -340,20 +443,20 @@ function normalizeArtifactThumbnail(value) {
340
443
  }
341
444
  function normalizeArtifactBridgeToolResult(requestType, message, viewport) {
342
445
  const base = ["channel", "schemaVersion", "type", "nonce", "artifactId", "requestId"];
343
- const exact = (keys) => message && typeof message === "object" && !Array.isArray(message) && Object.keys(message).length === keys.length && Object.keys(message).every((key) => keys.includes(key)) && Object.values(Object.getOwnPropertyDescriptors(message)).every(
446
+ const exact2 = (keys) => message && typeof message === "object" && !Array.isArray(message) && Object.keys(message).length === keys.length && Object.keys(message).every((key) => keys.includes(key)) && Object.values(Object.getOwnPropertyDescriptors(message)).every(
344
447
  (descriptor) => Object.hasOwn(descriptor, "value")
345
448
  );
346
449
  if (requestType === "inspect.point" || requestType === "inspect.anchor") {
347
- if (exact(base) && message.type === "inspect.miss") return { valid: true, value: null };
348
- if (!exact([...base, "inspection"]) || message.type !== "inspect.result")
450
+ if (exact2(base) && message.type === "inspect.miss") return { valid: true, value: null };
451
+ if (!exact2([...base, "inspection"]) || message.type !== "inspect.result")
349
452
  return { valid: false };
350
453
  const value = normalizeArtifactInspection(message.inspection, viewport);
351
454
  return value ? { valid: true, value } : { valid: false };
352
455
  }
353
456
  if (requestType === "thumbnail.request") {
354
- if (exact([...base, "reason"]) && message.type === "thumbnail.error" && typeof message.reason === "string" && message.reason.length <= 256)
457
+ if (exact2([...base, "reason"]) && message.type === "thumbnail.error" && typeof message.reason === "string" && message.reason.length <= 256)
355
458
  return { valid: true, value: null };
356
- if (!exact([...base, "dataUrl", "width", "height", "label"]) || message.type !== "thumbnail.result")
459
+ if (!exact2([...base, "dataUrl", "width", "height", "label"]) || message.type !== "thumbnail.result")
357
460
  return { valid: false };
358
461
  const value = normalizeArtifactThumbnail({
359
462
  dataUrl: message.dataUrl,
@@ -1594,7 +1697,9 @@ function lintCanvasData(data, { frames } = {}) {
1594
1697
  const errors = [];
1595
1698
  for (const section of data?.sections || []) {
1596
1699
  for (const a of section.artboards || []) {
1597
- const accepted = frames?.length ? frames.some((frame) => frame.width === a.width && frame.height === a.height) : isCanonicalFrame({ w: a.width, h: a.height });
1700
+ const accepted = frames?.length ? frames.some(
1701
+ (frame) => frame.width === a.width && (frame.height === "auto" ? a.height === "auto" || Number.isInteger(a.height) && a.height > 0 && a.height <= 16384 : frame.height === a.height)
1702
+ ) : isCanonicalFrame({ w: a.width, h: a.height });
1598
1703
  if (!accepted) {
1599
1704
  errors.push({
1600
1705
  rule: "frame-not-canonical",
@@ -1758,7 +1863,7 @@ function isRecord(value) {
1758
1863
  return value !== null && typeof value === "object" && !Array.isArray(value);
1759
1864
  }
1760
1865
  var digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
1761
- function boundedRead(url, label, { limit, exact, links = false }) {
1866
+ function boundedRead(url, label, { limit, exact: exact2, links = false }) {
1762
1867
  if (!links) {
1763
1868
  const stat = lstatSync(url, { throwIfNoEntry: false });
1764
1869
  if (!stat?.isFile()) throw new Error(`${label} must be a regular file, not a link.`);
@@ -1770,15 +1875,15 @@ function boundedRead(url, label, { limit, exact, links = false }) {
1770
1875
  try {
1771
1876
  const stat = fstatSync(descriptor);
1772
1877
  if (!stat.isFile()) throw new Error(`${label} must be a regular file, not a link.`);
1773
- if (exact !== void 0 ? stat.size !== exact : stat.size > limit)
1774
- throw new Error(`${label} is ${stat.size} bytes; expected ${exact ?? `at most ${limit}`}.`);
1775
- const capacity = (exact ?? Math.min(stat.size, limit)) + 1;
1878
+ if (exact2 !== void 0 ? stat.size !== exact2 : stat.size > limit)
1879
+ throw new Error(`${label} is ${stat.size} bytes; expected ${exact2 ?? `at most ${limit}`}.`);
1880
+ const capacity = (exact2 ?? Math.min(stat.size, limit)) + 1;
1776
1881
  const buffer = Buffer.alloc(capacity);
1777
1882
  let length = 0;
1778
1883
  for (let read = -1; read !== 0 && length < capacity; length += read)
1779
1884
  read = readSync(descriptor, buffer, length, capacity - length, null);
1780
1885
  if (length === capacity) throw new Error(`${label} changed size while it was read.`);
1781
- if (exact !== void 0 && length !== exact)
1886
+ if (exact2 !== void 0 && length !== exact2)
1782
1887
  throw new Error(`${label} changed size while it was read.`);
1783
1888
  return buffer.subarray(0, length);
1784
1889
  } finally {
@@ -1994,7 +2099,7 @@ function designNotes(document2) {
1994
2099
  ).join("")}</div></details>`;
1995
2100
  }
1996
2101
  function stageDetails(document2) {
1997
- return `<div class="design-stage-context"><div><strong data-design-screen-title>${escapeHtml(document2.screens.find(({ id }) => id === document2.screenOrder[0]).title)}</strong><span data-design-stage-description>Every screen, one connected design</span></div><div class="design-stage-actions">${designNotes(document2)}<label class="design-frame-picker">Frame<select aria-label="Responsive frame" data-design-frame>${document2.frames.map((frame) => `<option value="${escapeHtml(frame.id)}">${escapeHtml(frame.label)} \xB7 ${frame.width} \xD7 ${frame.height}</option>`).join("")}</select></label></div></div>
2102
+ return `<div class="design-stage-context"><div><strong data-design-screen-title>${escapeHtml(document2.screens.find(({ id }) => id === document2.screenOrder[0]).title)}</strong><span data-design-stage-description>Every screen, one connected design</span></div><div class="design-stage-actions">${designNotes(document2)}<label class="design-frame-picker">Frame<select aria-label="Responsive frame" data-design-frame>${document2.frames.map((frame) => `<option value="${escapeHtml(frame.id)}">${escapeHtml(designFrameLabel(frame))}</option>`).join("")}</select></label></div></div>
1998
2103
  <div class="design-canvas-tools" role="group" aria-label="Canvas controls"><div class="planr-segment design-interaction-picker" role="group" aria-label="Review mode">${iconButton("Interact", "pointer", 'data-planr-mode="interact" aria-pressed="true" aria-keyshortcuts="I"')}${iconButton("Annotate", "comment", 'data-planr-mode="comment" aria-pressed="false" aria-keyshortcuts="C"')}</div><span></span>${button("\u2212", 'data-design-zoom="out" aria-label="Zoom out"')}${button("100%", 'data-design-zoom="reset" aria-label="Reset zoom"')}${button("+", 'data-design-zoom="in" aria-label="Zoom in"')}<span></span>${button("100%", 'data-design-actual-size aria-label="Inspect screen at actual size" aria-pressed="false"')}${button("Focus", 'data-design-focus aria-label="Focus on the preview"')}${button("Fit", 'data-design-fit aria-label="Fit all visible artboards"')}${button("Pan", 'data-design-pan aria-pressed="false" aria-label="Pan canvas" aria-keyshortcuts="H Space" title="Pan canvas (H). Hold Space to pan temporarily; Escape returns to Interact."')}</div>
1999
2104
  <div class="design-walkthrough-caption" hidden><div><span data-design-step></span><h2 data-design-narrative-title></h2><p data-design-narrative></p></div><div>${button("Previous", 'data-design-step-change="-1"')}${button("Next", 'data-design-step-change="1"')}</div></div>
2000
2105
  <div class="design-notice" role="status" aria-live="polite" hidden><span data-design-notice-message></span><button type="button" data-design-dismiss-notice aria-label="Dismiss notification" title="Dismiss notification"><span aria-hidden="true">\xD7</span></button></div>`;
@@ -2016,7 +2121,8 @@ function renderDesignStudioMarkup({
2016
2121
  stalePins = [],
2017
2122
  reviewContext = null,
2018
2123
  contextDigest = null,
2019
- fingerprints = []
2124
+ fingerprints = [],
2125
+ contentIdentity = null
2020
2126
  } = {}, {
2021
2127
  stageRuntimeUrl = "./artifact-review-stage.js",
2022
2128
  renderShell,
@@ -2047,6 +2153,7 @@ function renderDesignStudioMarkup({
2047
2153
  reviewContext,
2048
2154
  contextDigest,
2049
2155
  fingerprints,
2156
+ contentIdentity,
2050
2157
  artifactKinds: Object.fromEntries(
2051
2158
  envelope.artifacts.map((artifact) => [artifact.id, artifact.kind])
2052
2159
  ),
@@ -2138,7 +2245,8 @@ function createDesignStudioEntries(document2, envelope) {
2138
2245
  artifactId,
2139
2246
  variantId: variant.id,
2140
2247
  screenId,
2141
- frameId: frame.id
2248
+ frameId: frame.id,
2249
+ ...frame.height === "auto" ? { height: "auto" } : {}
2142
2250
  });
2143
2251
  }
2144
2252
  }
@@ -2163,6 +2271,101 @@ function renderDesignStudio(input = {}, options = {}) {
2163
2271
  );
2164
2272
  }
2165
2273
 
2274
+ // packages/design/lib/design/view-context.mjs
2275
+ import { readFileSync as readFileSync4 } from "node:fs";
2276
+ import { join } from "node:path";
2277
+ var anchorPattern = new RegExp(DESIGN_DOCUMENT_SCHEMA.$defs.id.pattern, "u");
2278
+ var exact = (value, keys) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
2279
+ var boardFields = ["screenId", "frameId", "variantId"];
2280
+ function validateDesignViewContext(input, current) {
2281
+ if (!exact(input, ["revision", "view", "visibleScreens", "selected", "dirty"]))
2282
+ throw new Error(
2283
+ "View context requires exactly revision, view, visibleScreens, selected and dirty."
2284
+ );
2285
+ if (input.revision !== current.revision)
2286
+ throw Object.assign(
2287
+ new Error(
2288
+ `View context revision ${input.revision} is stale; current revision is ${current.revision}.`
2289
+ ),
2290
+ { statusCode: 409 }
2291
+ );
2292
+ if (!["canvas", "prototype", "walkthrough"].includes(input.view))
2293
+ throw new Error(`Unknown view context view ${input.view}.`);
2294
+ if (typeof input.dirty !== "boolean")
2295
+ throw new Error(`View context dirty must be boolean; received ${input.dirty}.`);
2296
+ const board = (value, selected = false) => {
2297
+ if (!exact(value, selected ? [...boardFields, "planrId"] : boardFields))
2298
+ throw new Error(
2299
+ `View context ${selected ? "selected" : "visibleScreens entry"} has invalid fields.`
2300
+ );
2301
+ if (!current.entries.some((entry) => boardFields.every((key) => entry[key] === value[key])))
2302
+ throw new Error(`Unknown view context board ${JSON.stringify(value)}.`);
2303
+ return boardFields.map((key) => value[key]).join("/");
2304
+ };
2305
+ if (!Array.isArray(input.visibleScreens) || input.visibleScreens.length > current.entries.length)
2306
+ throw new Error(
2307
+ `View context visibleScreens must contain at most ${current.entries.length} boards.`
2308
+ );
2309
+ const keys = input.visibleScreens.map((value) => board(value));
2310
+ if (new Set(keys).size !== keys.length)
2311
+ throw new Error("View context visibleScreens contains duplicate boards.");
2312
+ board(input.selected, true);
2313
+ const { planrId } = input.selected;
2314
+ if (planrId !== null && (typeof planrId !== "string" || planrId.length > 128 || !anchorPattern.test(planrId)))
2315
+ throw new Error(
2316
+ `View context planrId ${JSON.stringify(planrId)} must be null or a document anchor ID of at most 128 characters.`
2317
+ );
2318
+ return structuredClone(input);
2319
+ }
2320
+ function saveDesignViewContext(file, input, clock) {
2321
+ const current = currentDesign(file);
2322
+ const context = validateDesignViewContext(input, current);
2323
+ const value = {
2324
+ kind: "openplanr-design-view-context",
2325
+ schemaVersion: "1.0.0",
2326
+ ...context,
2327
+ updatedAt: clock().toISOString()
2328
+ };
2329
+ atomicJson(join(current.root, ".design/view-context.json"), value);
2330
+ return { ok: true };
2331
+ }
2332
+ function readDesignViewContext(file, { requestTime } = {}) {
2333
+ try {
2334
+ const current = currentDesign(file);
2335
+ const path = join(current.root, ".design/view-context.json");
2336
+ const bytes = readFileSync4(path);
2337
+ if (bytes.length > 128 * 1024) throw new Error(`${path} exceeds 128 KB.`);
2338
+ const value = JSON.parse(bytes.toString("utf8"));
2339
+ if (!exact(value, [
2340
+ "kind",
2341
+ "schemaVersion",
2342
+ "revision",
2343
+ "updatedAt",
2344
+ "view",
2345
+ "visibleScreens",
2346
+ "selected",
2347
+ "dirty"
2348
+ ]) || value.kind !== "openplanr-design-view-context" || value.schemaVersion !== "1.0.0")
2349
+ throw new Error(`${path} is not a supported design view context.`);
2350
+ if (typeof value.updatedAt !== "string" || !Number.isFinite(Date.parse(value.updatedAt)))
2351
+ throw new Error(`${path} has an invalid updatedAt timestamp.`);
2352
+ const { kind, schemaVersion, updatedAt, ...input } = value;
2353
+ validateDesignViewContext(input, current);
2354
+ if (requestTime !== void 0) {
2355
+ const requestedAt = Date.parse(requestTime);
2356
+ if (!Number.isFinite(requestedAt))
2357
+ throw new Error(`Invalid view context request time ${requestTime}.`);
2358
+ if (Date.parse(updatedAt) < requestedAt)
2359
+ throw new Error(
2360
+ `View context updatedAt ${updatedAt} is older than request ${requestTime}.`
2361
+ );
2362
+ }
2363
+ return value;
2364
+ } catch (error) {
2365
+ return { viewContext: null, reason: error.message };
2366
+ }
2367
+ }
2368
+
2166
2369
  // packages/design/lib/design/document.mjs
2167
2370
  var DESIGN_VIEWS = Object.freeze(["canvas", "prototype", "walkthrough"]);
2168
2371
  var DESIGN_RENDERER_VERSION = "1.3.0";
@@ -2184,7 +2387,7 @@ function inspectDesignDocument(file, { readSource } = {}) {
2184
2387
  `This board needs ${sourceCount} screen sources and ${viewCount} viewport references. Split it into linked boards: one board supports 256 sources and 4096 views.`
2185
2388
  );
2186
2389
  const sources = new Set(document2.assets ?? []);
2187
- if (existsSync2(join(root, "review-context.json"))) sources.add("review-context.json");
2390
+ if (existsSync2(join2(root, "review-context.json"))) sources.add("review-context.json");
2188
2391
  if (document2.designSystem?.tokens) sources.add(document2.designSystem.tokens);
2189
2392
  for (const screen of document2.screens)
2190
2393
  for (const source of [
@@ -2212,7 +2415,7 @@ function inspectDesignDocument(file, { readSource } = {}) {
2212
2415
  missing,
2213
2416
  specPath: designSpecPath(root),
2214
2417
  // Guarded source preparation is independent of local render cache state.
2215
- current: readSource ? null : readJson(join(root, ".design/current.json"), null)
2418
+ current: readSource ? null : readJson(join2(root, ".design/current.json"), null)
2216
2419
  };
2217
2420
  }
2218
2421
  function prepareDesignDocument(file, { readSource, passive = false, maxBytes } = {}) {
@@ -2227,7 +2430,7 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2227
2430
  const sourceContents = new Map(
2228
2431
  inspected.sources.map((source) => [
2229
2432
  source,
2230
- readSource ? readSource(source, root).value : readFileSync4(resolveLocalDocumentFile(root, source))
2433
+ readSource ? readSource(source, root).value : readFileSync5(resolveLocalDocumentFile(root, source))
2231
2434
  ])
2232
2435
  );
2233
2436
  for (const variant of document2.variants.filter((item) => item.status === "ready")) {
@@ -2242,6 +2445,11 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2242
2445
  passive,
2243
2446
  ...maxBytes === void 0 ? {} : { maxBytes }
2244
2447
  });
2448
+ if (document2.frames.some(({ height }) => height === "auto"))
2449
+ bundled.html = bundled.html.replace(
2450
+ "</body>",
2451
+ `<script>(${observeDesignFrameSize.toString()})()</script></body>`
2452
+ );
2245
2453
  const navigate = `<script>document.addEventListener('click',function(event){var link=event.target.closest('[data-design-target],[data-planr-navigate],[data-design-navigate]');if(!link)return;event.preventDefault();parent.postMessage({type:'openplanr:design-navigate',screenId:link.getAttribute('data-design-target')||link.getAttribute('data-planr-navigate')||link.getAttribute('data-design-navigate')},'*')});document.addEventListener('submit',function(event){event.preventDefault()});</script>`;
2246
2454
  if (!passive) bundled.html = bundled.html.replace("</body>", `${navigate}</body>`);
2247
2455
  for (const name of bundled.files) {
@@ -2249,7 +2457,7 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2249
2457
  if (!sourceContents.has(name))
2250
2458
  sourceContents.set(
2251
2459
  name,
2252
- readSource ? readSource(name, root).value : readFileSync4(resolveLocalDocumentFile(root, name))
2460
+ readSource ? readSource(name, root).value : readFileSync5(resolveLocalDocumentFile(root, name))
2253
2461
  );
2254
2462
  if (hash(sourceContents.get(name)) !== bundled.sourceDigests[name])
2255
2463
  throw new Error(
@@ -2287,14 +2495,15 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2287
2495
  kind: "html",
2288
2496
  title: `${screen.title} \xB7 ${variant.label} \xB7 ${frame.label}`,
2289
2497
  sourceId,
2290
- viewport: { width: frame.width, height: frame.height },
2498
+ viewport: designFrameViewport(document2, frame),
2291
2499
  colorScheme: "light"
2292
2500
  });
2293
2501
  entries.push({
2294
2502
  artifactId,
2295
2503
  screenId,
2296
2504
  variantId: variant.id,
2297
- frameId: frame.id
2505
+ frameId: frame.id,
2506
+ ...frame.height === "auto" ? { height: "auto" } : {}
2298
2507
  });
2299
2508
  }
2300
2509
  }
@@ -2347,7 +2556,7 @@ function designRendererRevision() {
2347
2556
  (name) => name === "studio.js" || existsSync2(new URL(`../../templates/studio/${name}`, new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href))
2348
2557
  ).map(
2349
2558
  (name) => hash(
2350
- name === "studio.js" ? readDesignStudioRuntime() : readFileSync4(new URL(`../../templates/studio/${name}`, new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href))
2559
+ name === "studio.js" ? readDesignStudioRuntime() : readFileSync5(new URL(`../../templates/studio/${name}`, new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href))
2351
2560
  )
2352
2561
  )
2353
2562
  })
@@ -2418,22 +2627,34 @@ ${runtime}` : runtime;
2418
2627
  { stageRuntimeUrl: runtimeUrl }
2419
2628
  );
2420
2629
  }
2421
- async function renderDesignDocument(file, {
2630
+ async function renderDesignDocument(file, options = {}) {
2631
+ return withDesignRenderLock(file, (render) => render(options));
2632
+ }
2633
+ async function withDesignRenderLock(file, action) {
2634
+ const { root } = loadDesignDocument(file);
2635
+ const work = join2(root, ".design");
2636
+ mkdirSync(work, { recursive: true });
2637
+ const release = await acquireStartLock(join2(work, "render.lock"), {
2638
+ timeout: 1e3,
2639
+ stale: 3e4
2640
+ });
2641
+ try {
2642
+ recoverDesignPublication(root, { ownsRenderLock: true });
2643
+ return await action((options) => renderDesignDocumentUnlocked(file, options));
2644
+ } finally {
2645
+ release();
2646
+ }
2647
+ }
2648
+ async function renderDesignDocumentUnlocked(file, {
2422
2649
  beforeCommit,
2423
2650
  writePointer = atomicJson,
2424
2651
  rendererRevision = designRendererRevision(),
2425
2652
  now = () => (/* @__PURE__ */ new Date()).toISOString()
2426
2653
  } = {}) {
2427
2654
  const { root } = loadDesignDocument(file);
2428
- const work = join(root, ".design");
2429
- mkdirSync(work, { recursive: true });
2430
- const release = await acquireStartLock(join(work, "render.lock"), {
2431
- timeout: 1e3,
2432
- stale: 3e4
2433
- });
2655
+ const work = join2(root, ".design");
2434
2656
  let temporary;
2435
2657
  try {
2436
- recoverDesignPublication(root, { ownsRenderLock: true });
2437
2658
  const prepared = prepareDesignDocument(file);
2438
2659
  const errors = prepared.lint.flatMap(
2439
2660
  (item) => item.errors.map((error) => `${item.screenId}: ${error.message}`)
@@ -2441,15 +2662,15 @@ async function renderDesignDocument(file, {
2441
2662
  if (errors.length) throw new Error(`Design lint failed:
2442
2663
  ${errors.join("\n")}`);
2443
2664
  const specPath = designSpecPath(root);
2444
- const spec = readFileSync4(specPath, "utf8");
2665
+ const spec = readFileSync5(specPath, "utf8");
2445
2666
  for (let section = 1; section <= 10; section++)
2446
2667
  if (!new RegExp(`^## ${section}\\. `, "m").test(spec))
2447
2668
  throw new Error(`design-spec.md is missing section ${section}.`);
2448
2669
  prepared.revision = hash(json({ source: prepared.revision, spec, rendererRevision }));
2449
- const directory = join(work, "revisions", prepared.revision);
2450
- const previous = readJson(join(work, "current.json"), null);
2670
+ const directory = join2(work, "revisions", prepared.revision);
2671
+ const previous = readJson(join2(work, "current.json"), null);
2451
2672
  const generatedAt = now();
2452
- const manifest = existsSync2(directory) ? readJson(join(directory, "render.json")).manifest : buildManifest({
2673
+ const manifest = existsSync2(directory) ? readJson(join2(directory, "render.json")).manifest : buildManifest({
2453
2674
  framework: "vanilla",
2454
2675
  designFormat: prepared.document.defaultView,
2455
2676
  source: prepared.document.brief.source,
@@ -2474,39 +2695,39 @@ ${errors.join("\n")}`);
2474
2695
  manifest
2475
2696
  };
2476
2697
  if (!existsSync2(directory)) {
2477
- temporary = join(work, `pending-${randomUUID()}`);
2478
- mkdirSync(join(temporary, "sources"), { recursive: true });
2479
- writeFileSync(join(temporary, "render.json"), json(record));
2480
- writeFileSync(join(temporary, "design-document.json"), json(prepared.document));
2481
- writeFileSync(join(temporary, "design-spec.md"), spec);
2698
+ temporary = join2(work, `pending-${randomUUID()}`);
2699
+ mkdirSync(join2(temporary, "sources"), { recursive: true });
2700
+ writeFileSync(join2(temporary, "render.json"), json(record));
2701
+ writeFileSync(join2(temporary, "design-document.json"), json(prepared.document));
2702
+ writeFileSync(join2(temporary, "design-spec.md"), spec);
2482
2703
  for (const source of prepared.sourceFiles) {
2483
- const destination = join(temporary, "sources", source);
2704
+ const destination = join2(temporary, "sources", source);
2484
2705
  mkdirSync(dirname(destination), { recursive: true });
2485
2706
  writeFileSync(destination, prepared.sourceContents.get(source));
2486
2707
  }
2487
2708
  for (const view of DESIGN_VIEWS)
2488
- writeFileSync(join(temporary, `${view}.html`), standaloneDesignHtml(record, view));
2709
+ writeFileSync(join2(temporary, `${view}.html`), standaloneDesignHtml(record, view));
2489
2710
  beforeCommit?.(record);
2490
2711
  mkdirSync(dirname(directory), { recursive: true });
2491
2712
  renameSync(temporary, directory);
2492
2713
  temporary = null;
2493
2714
  }
2494
- const manifestPath = join(root, "finalized.json");
2495
- atomicJson(join(work, "publication.json"), {
2715
+ const manifestPath = join2(root, "finalized.json");
2716
+ atomicJson(join2(work, "publication.json"), {
2496
2717
  revision: prepared.revision,
2497
2718
  previousRevision: previous?.revision ?? null,
2498
2719
  manifest,
2499
- previousManifest: existsSync2(manifestPath) ? readFileSync4(manifestPath).toString("base64") : null
2720
+ previousManifest: existsSync2(manifestPath) ? readFileSync5(manifestPath).toString("base64") : null
2500
2721
  });
2501
2722
  try {
2502
2723
  atomicJson(manifestPath, manifest);
2503
- writePointer(join(work, "current.json"), {
2724
+ writePointer(join2(work, "current.json"), {
2504
2725
  revision: prepared.revision,
2505
2726
  previousRevision: previous?.revision === prepared.revision ? previous.previousRevision : previous?.revision ?? null,
2506
2727
  iterations: manifest.iterations,
2507
2728
  generatedAt: manifest.generated_at
2508
2729
  });
2509
- rmSync(join(work, "publication.json"), { force: true });
2730
+ rmSync(join2(work, "publication.json"), { force: true });
2510
2731
  } catch (error) {
2511
2732
  recoverDesignPublication(root, { ownsRenderLock: true });
2512
2733
  throw error;
@@ -2515,20 +2736,100 @@ ${errors.join("\n")}`);
2515
2736
  ok: true,
2516
2737
  revision: prepared.revision,
2517
2738
  document: resolve2(file),
2518
- artifact: join(directory, `${prepared.document.defaultView}.html`),
2739
+ artifact: join2(directory, `${prepared.document.defaultView}.html`),
2519
2740
  views: Object.fromEntries(
2520
- DESIGN_VIEWS.map((view) => [view, join(directory, `${view}.html`)])
2741
+ DESIGN_VIEWS.map((view) => [view, join2(directory, `${view}.html`)])
2521
2742
  ),
2522
- manifest: join(root, "finalized.json"),
2743
+ manifest: join2(root, "finalized.json"),
2523
2744
  spec: specPath,
2524
2745
  verification: "unverified"
2525
2746
  };
2526
2747
  } finally {
2527
2748
  if (temporary) rmSync(temporary, { recursive: true, force: true });
2528
- release();
2529
2749
  }
2530
2750
  }
2531
2751
 
2752
+ // packages/design/lib/design/layout-save.mjs
2753
+ async function saveDesignLayout(file, input) {
2754
+ if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).some((key) => !["revision", "boards", "restoreRevision"].includes(key)) || typeof input.revision !== "string" || Object.hasOwn(input, "boards") === Object.hasOwn(input, "restoreRevision"))
2755
+ throw new Error("Design layout requires a revision and either boards or restoreRevision.");
2756
+ return withDesignRenderLock(file, async (render) => {
2757
+ const current = currentDesign(file);
2758
+ if (input.revision !== current.revision)
2759
+ throw Object.assign(new Error("The design changed. Reload before saving its layout."), {
2760
+ statusCode: 409
2761
+ });
2762
+ const authored = prepareDesignDocument(file);
2763
+ const authoredContent = { ...authored.document };
2764
+ const committedContent = { ...current.document };
2765
+ delete authoredContent.layout;
2766
+ delete committedContent.layout;
2767
+ if (digestArtifactEnvelope(authored.envelope) !== digestArtifactEnvelope(current.envelope) || JSON.stringify(authored.fingerprints) !== JSON.stringify(current.fingerprints) || JSON.stringify(authoredContent) !== JSON.stringify(committedContent) || readFileSync6(designSpecPath(current.root), "utf8") !== readFileSync6(join3(current.directory, "design-spec.md"), "utf8"))
2768
+ throw Object.assign(
2769
+ new Error(
2770
+ "Design sources or content changed. Render the design and reload before saving its layout."
2771
+ ),
2772
+ { statusCode: 409 }
2773
+ );
2774
+ const previous = readFileSync6(file, "utf8");
2775
+ const mode = statSync(file).mode & 4095;
2776
+ const document2 = JSON.parse(previous);
2777
+ if (Object.hasOwn(input, "restoreRevision")) {
2778
+ if (typeof input.restoreRevision !== "string" || !/^[a-f0-9]{64}$/u.test(input.restoreRevision))
2779
+ throw new Error(`Invalid layout restore revision ${input.restoreRevision}.`);
2780
+ const restored = readJson(
2781
+ join3(current.root, ".design/revisions", input.restoreRevision, "design-document.json")
2782
+ );
2783
+ if (restored.layout === void 0) delete document2.layout;
2784
+ else document2.layout = structuredClone(restored.layout);
2785
+ } else {
2786
+ if (!input.boards || typeof input.boards !== "object" || Array.isArray(input.boards))
2787
+ throw new Error("Design layout boards must be an object of exact board keys.");
2788
+ const boards = { ...document2.layout?.boards };
2789
+ for (const [key, point] of Object.entries(input.boards)) {
2790
+ if (!current.entries.some(
2791
+ (entry) => `${entry.screenId}/${entry.frameId}/${entry.variantId}` === key
2792
+ ))
2793
+ throw new Error(`Unknown exact design board key ${key}.`);
2794
+ if (point === null) delete boards[key];
2795
+ else {
2796
+ if (!point || typeof point !== "object" || Array.isArray(point) || Object.keys(point).some((field) => !["x", "y"].includes(field)) || !Number.isFinite(point.x) || !Number.isFinite(point.y) || Math.abs(point.x) > 1e7 || Math.abs(point.y) > 1e7)
2797
+ throw new Error(
2798
+ `Design board ${key} requires finite x and y coordinates within \xB110000000.`
2799
+ );
2800
+ boards[key] = { ...boards[key], x: point.x, y: point.y };
2801
+ }
2802
+ }
2803
+ document2.layout = { ...document2.layout, boards };
2804
+ if (!Object.keys(boards).length) delete document2.layout.boards;
2805
+ if (!Object.keys(document2.layout).length) delete document2.layout;
2806
+ }
2807
+ assertDesignDocument(document2);
2808
+ const indent = previous.match(/^([\t ]+)\S/mu)?.[1] ?? "";
2809
+ const formatted = indent ? JSON.stringify(document2, null, " ").replace(
2810
+ /^\t+/gmu,
2811
+ (tabs) => indent.repeat(tabs.length)
2812
+ ) : JSON.stringify(document2);
2813
+ const written = `${formatted}${previous.endsWith("\n") ? "\n" : ""}`;
2814
+ atomicBytes(file, written, mode);
2815
+ try {
2816
+ const result = await render();
2817
+ return { revision: result.revision };
2818
+ } catch (error) {
2819
+ if (hash(readFileSync6(file)) !== hash(written))
2820
+ throw Object.assign(
2821
+ new Error(
2822
+ `The authored document ${file} changed during the save. Its newer contents were preserved; reload before saving its layout.`,
2823
+ { cause: error }
2824
+ ),
2825
+ { statusCode: 409 }
2826
+ );
2827
+ atomicBytes(file, previous, mode);
2828
+ throw error;
2829
+ }
2830
+ });
2831
+ }
2832
+
2532
2833
  export {
2533
2834
  mintCapabilityToken,
2534
2835
  isCapabilityToken,
@@ -2536,11 +2837,16 @@ export {
2536
2837
  prepareArtifactDocument,
2537
2838
  createArtifactBridgeNonce,
2538
2839
  renderArtifactParentRuntime,
2840
+ matchesDesignFrame,
2539
2841
  readRuntimeAsset,
2540
2842
  renderDesignStudio,
2843
+ saveDesignLayout,
2844
+ saveDesignViewContext,
2845
+ readDesignViewContext,
2541
2846
  inspectDesignDocument,
2542
2847
  prepareDesignDocument,
2543
2848
  designRendererRevision,
2544
2849
  standaloneDesignHtml,
2545
- renderDesignDocument
2850
+ renderDesignDocument,
2851
+ withDesignRenderLock
2546
2852
  };