openplanr 3.1.1 → 3.3.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 (452) hide show
  1. package/CHANGELOG.md +69 -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/cli/commands/spec.d.ts +2 -1
  13. package/dist/cli/commands/spec.d.ts.map +1 -1
  14. package/dist/cli/commands/spec.js +45 -5
  15. package/dist/cli/commands/spec.js.map +1 -1
  16. package/dist/dashboard/.vite/manifest.json +1 -1
  17. package/dist/dashboard/assets/index-B_96uzCl.js +572 -0
  18. package/dist/dashboard/assets/index-B_96uzCl.js.map +1 -0
  19. package/dist/dashboard/dashboard-manifest.json +10 -10
  20. package/dist/dashboard/index.html +1 -1
  21. package/dist/models/schema.d.ts +39 -23
  22. package/dist/models/schema.d.ts.map +1 -1
  23. package/dist/models/schema.js +19 -12
  24. package/dist/models/schema.js.map +1 -1
  25. package/dist/models/types.d.ts +6 -0
  26. package/dist/models/types.d.ts.map +1 -1
  27. package/dist/services/claude-plugin-service.d.ts +5 -0
  28. package/dist/services/claude-plugin-service.d.ts.map +1 -1
  29. package/dist/services/claude-plugin-service.js +18 -2
  30. package/dist/services/claude-plugin-service.js.map +1 -1
  31. package/dist/services/codex-plugin-service.d.ts.map +1 -1
  32. package/dist/services/codex-plugin-service.js +11 -3
  33. package/dist/services/codex-plugin-service.js.map +1 -1
  34. package/dist/services/id-service.d.ts +1 -5
  35. package/dist/services/id-service.d.ts.map +1 -1
  36. package/dist/services/id-service.js +1 -34
  37. package/dist/services/id-service.js.map +1 -1
  38. package/dist/services/runtime-manager/codex-discovery.d.ts +1 -3
  39. package/dist/services/runtime-manager/codex-discovery.d.ts.map +1 -1
  40. package/dist/services/runtime-manager/codex-discovery.js +3 -16
  41. package/dist/services/runtime-manager/codex-discovery.js.map +1 -1
  42. package/dist/services/runtime-manager/doctor.d.ts +25 -0
  43. package/dist/services/runtime-manager/doctor.d.ts.map +1 -1
  44. package/dist/services/runtime-manager/doctor.js +480 -0
  45. package/dist/services/runtime-manager/doctor.js.map +1 -1
  46. package/dist/services/runtime-manager/errors.d.ts +12 -0
  47. package/dist/services/runtime-manager/errors.d.ts.map +1 -0
  48. package/dist/services/runtime-manager/errors.js +14 -0
  49. package/dist/services/runtime-manager/errors.js.map +1 -0
  50. package/dist/services/runtime-manager/global-state.d.ts +7 -0
  51. package/dist/services/runtime-manager/global-state.d.ts.map +1 -1
  52. package/dist/services/runtime-manager/global-state.js +116 -0
  53. package/dist/services/runtime-manager/global-state.js.map +1 -1
  54. package/dist/services/runtime-manager/host-version-probe.d.ts +8 -0
  55. package/dist/services/runtime-manager/host-version-probe.d.ts.map +1 -0
  56. package/dist/services/runtime-manager/host-version-probe.js +14 -0
  57. package/dist/services/runtime-manager/host-version-probe.js.map +1 -0
  58. package/dist/services/runtime-manager/install-plan.d.ts +25 -0
  59. package/dist/services/runtime-manager/install-plan.d.ts.map +1 -1
  60. package/dist/services/runtime-manager/install-plan.js +305 -0
  61. package/dist/services/runtime-manager/install-plan.js.map +1 -1
  62. package/dist/services/runtime-manager/inventory.d.ts +6 -0
  63. package/dist/services/runtime-manager/inventory.d.ts.map +1 -1
  64. package/dist/services/runtime-manager/inventory.js +16 -1
  65. package/dist/services/runtime-manager/inventory.js.map +1 -1
  66. package/dist/services/runtime-manager/legacy-adapters.d.ts +9 -0
  67. package/dist/services/runtime-manager/legacy-adapters.d.ts.map +1 -0
  68. package/dist/services/runtime-manager/legacy-adapters.js +187 -0
  69. package/dist/services/runtime-manager/legacy-adapters.js.map +1 -0
  70. package/dist/services/runtime-manager/paths.d.ts +18 -0
  71. package/dist/services/runtime-manager/paths.d.ts.map +1 -0
  72. package/dist/services/runtime-manager/paths.js +83 -0
  73. package/dist/services/runtime-manager/paths.js.map +1 -0
  74. package/dist/services/runtime-manager/runtime-package.d.ts +21 -0
  75. package/dist/services/runtime-manager/runtime-package.d.ts.map +1 -1
  76. package/dist/services/runtime-manager/runtime-package.js +77 -0
  77. package/dist/services/runtime-manager/runtime-package.js.map +1 -1
  78. package/dist/services/runtime-manager/storage.d.ts +47 -0
  79. package/dist/services/runtime-manager/storage.d.ts.map +1 -0
  80. package/dist/services/runtime-manager/storage.js +604 -0
  81. package/dist/services/runtime-manager/storage.js.map +1 -0
  82. package/dist/services/runtime-manager-service.d.ts +7 -17
  83. package/dist/services/runtime-manager-service.d.ts.map +1 -1
  84. package/dist/services/runtime-manager-service.js +32 -1695
  85. package/dist/services/runtime-manager-service.js.map +1 -1
  86. package/dist/services/ship-checks/changes.d.ts +24 -0
  87. package/dist/services/ship-checks/changes.d.ts.map +1 -0
  88. package/dist/services/ship-checks/changes.js +135 -0
  89. package/dist/services/ship-checks/changes.js.map +1 -0
  90. package/dist/services/ship-checks/contract.d.ts +93 -0
  91. package/dist/services/ship-checks/contract.d.ts.map +1 -0
  92. package/dist/services/ship-checks/contract.js +7 -0
  93. package/dist/services/ship-checks/contract.js.map +1 -0
  94. package/dist/services/ship-checks/coverage.d.ts +4 -0
  95. package/dist/services/ship-checks/coverage.d.ts.map +1 -0
  96. package/dist/services/ship-checks/coverage.js +113 -0
  97. package/dist/services/ship-checks/coverage.js.map +1 -0
  98. package/dist/services/ship-checks/discover.d.ts +10 -0
  99. package/dist/services/ship-checks/discover.d.ts.map +1 -0
  100. package/dist/services/ship-checks/discover.js +253 -0
  101. package/dist/services/ship-checks/discover.js.map +1 -0
  102. package/dist/services/ship-checks/glob.d.ts +5 -0
  103. package/dist/services/ship-checks/glob.d.ts.map +1 -0
  104. package/dist/services/ship-checks/glob.js +39 -0
  105. package/dist/services/ship-checks/glob.js.map +1 -0
  106. package/dist/services/ship-checks/hooks.d.ts +7 -0
  107. package/dist/services/ship-checks/hooks.d.ts.map +1 -0
  108. package/dist/services/ship-checks/hooks.js +65 -0
  109. package/dist/services/ship-checks/hooks.js.map +1 -0
  110. package/dist/services/ship-checks/packages.d.ts +29 -0
  111. package/dist/services/ship-checks/packages.d.ts.map +1 -0
  112. package/dist/services/ship-checks/packages.js +197 -0
  113. package/dist/services/ship-checks/packages.js.map +1 -0
  114. package/dist/services/ship-checks/related-tests.d.ts +13 -0
  115. package/dist/services/ship-checks/related-tests.d.ts.map +1 -0
  116. package/dist/services/ship-checks/related-tests.js +73 -0
  117. package/dist/services/ship-checks/related-tests.js.map +1 -0
  118. package/dist/services/ship-checks/scope.d.ts +8 -0
  119. package/dist/services/ship-checks/scope.d.ts.map +1 -0
  120. package/dist/services/ship-checks/scope.js +66 -0
  121. package/dist/services/ship-checks/scope.js.map +1 -0
  122. package/dist/services/ship-checks/task-requirements.d.ts +14 -0
  123. package/dist/services/ship-checks/task-requirements.d.ts.map +1 -0
  124. package/dist/services/ship-checks/task-requirements.js +145 -0
  125. package/dist/services/ship-checks/task-requirements.js.map +1 -0
  126. package/dist/services/ship-checks/workflows.d.ts +21 -0
  127. package/dist/services/ship-checks/workflows.d.ts.map +1 -0
  128. package/dist/services/ship-checks/workflows.js +208 -0
  129. package/dist/services/ship-checks/workflows.js.map +1 -0
  130. package/dist/services/spec-service.d.ts +18 -0
  131. package/dist/services/spec-service.d.ts.map +1 -1
  132. package/dist/services/spec-service.js +174 -9
  133. package/dist/services/spec-service.js.map +1 -1
  134. package/dist/services/template-service.d.ts +2 -0
  135. package/dist/services/template-service.d.ts.map +1 -1
  136. package/dist/services/template-service.js +4 -0
  137. package/dist/services/template-service.js.map +1 -1
  138. package/dist/templates/spec/spec-shaped.md.hbs +1 -1
  139. package/dist/templates/spec/spec.md.hbs +2 -2
  140. package/dist/utils/slugify.d.ts +1 -8
  141. package/dist/utils/slugify.d.ts.map +1 -1
  142. package/dist/utils/slugify.js +1 -25
  143. package/dist/utils/slugify.js.map +1 -1
  144. package/docs/CLI.md +96 -2
  145. package/lib/backlog-item.d.mts +49 -0
  146. package/lib/backlog-item.mjs +339 -0
  147. package/lib/host-packages/adapter-registry.json +5 -5
  148. package/lib/host-packages/capability-map.json +3 -3
  149. package/lib/host-packages/claude/.claude-plugin/marketplace.json +2 -2
  150. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +1 -1
  151. package/lib/host-packages/claude/openplanr/.openplanr-content.json +134 -94
  152. package/lib/host-packages/claude/openplanr/CONNECTORS.md +4 -6
  153. package/lib/host-packages/claude/openplanr/README.md +1 -1
  154. package/lib/host-packages/claude/openplanr/agents/planr-qa.md +5 -3
  155. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-artifact-shell.mjs +1 -1
  156. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +1 -1
  157. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +471 -80
  158. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +2 -2
  159. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-resource-pack.mjs +1 -1
  160. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review.mjs +45 -4
  161. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/design-runtime-support-e34c388a8e59.mjs → claude/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs} +1 -1
  162. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +8 -5
  163. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +138 -12
  164. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +1 -1
  165. package/lib/host-packages/claude/openplanr/runtime/design/scripts/{design-shared-protocol-contracts-31a760fc.mjs → design-shared-protocol-contracts-b5f28f94.mjs} +413 -45
  166. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-upload-spool.mjs +1 -1
  167. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +482 -79
  168. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -32
  169. 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
  170. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +322 -45
  171. 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
  172. 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
  173. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +11 -10
  174. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -3
  175. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +16 -11
  176. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +7 -11
  177. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +165 -276
  178. 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
  179. 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
  180. 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
  181. 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
  182. 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
  183. 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
  184. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +119 -244
  185. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +7 -17
  186. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +3 -4
  187. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +285 -0
  188. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +2773 -0
  189. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +134 -0
  190. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +2207 -0
  191. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +16 -0
  192. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +8 -0
  193. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +3883 -0
  194. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +966 -0
  195. 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
  196. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +1597 -0
  197. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +101 -47
  198. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +6 -2
  199. 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.22.0}/design-document.schema.json +207 -7
  200. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
  201. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +324 -45
  202. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +73 -12
  203. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +6 -2
  204. package/lib/host-packages/claude/openplanr/skills/connect/references/connectors.md +4 -6
  205. package/lib/host-packages/claude/openplanr/skills/design/SKILL.md +12 -0
  206. package/lib/host-packages/claude/openplanr/skills/design/references/craft.md +14 -3
  207. package/lib/host-packages/claude/openplanr/skills/design/references/design-system.md +48 -1
  208. package/lib/host-packages/claude/openplanr/skills/design/references/discovery.md +18 -4
  209. package/lib/host-packages/claude/openplanr/skills/design/references/generation.md +133 -2
  210. package/lib/host-packages/claude/openplanr/skills/design/references/hosted-canvas.md +62 -0
  211. package/lib/host-packages/claude/openplanr/skills/design/references/review.md +46 -1
  212. package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +17 -1
  213. package/lib/host-packages/claude/openplanr/skills/design/schemas/design-document.schema.json +207 -7
  214. package/lib/host-packages/claude/openplanr/skills/design-loop/references/craft.md +14 -3
  215. package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-system.md +48 -1
  216. package/lib/host-packages/claude/openplanr/skills/design-loop/references/discovery.md +18 -4
  217. package/lib/host-packages/claude/openplanr/skills/design-loop/references/generation.md +133 -2
  218. package/lib/host-packages/claude/openplanr/skills/design-loop/references/review.md +46 -1
  219. package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +17 -1
  220. package/lib/host-packages/claude/openplanr/skills/design-loop/schemas/design-document.schema.json +207 -7
  221. package/lib/host-packages/claude/openplanr/skills/design-review/references/craft.md +14 -3
  222. package/lib/host-packages/claude/openplanr/skills/design-review/references/design-system.md +48 -1
  223. package/lib/host-packages/claude/openplanr/skills/design-review/references/discovery.md +18 -4
  224. package/lib/host-packages/claude/openplanr/skills/design-review/references/generation.md +133 -2
  225. package/lib/host-packages/claude/openplanr/skills/design-review/references/review.md +46 -1
  226. package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +17 -1
  227. package/lib/host-packages/claude/openplanr/skills/design-review/schemas/design-document.schema.json +207 -7
  228. package/lib/host-packages/claude/openplanr/skills/investigate/SKILL.md +11 -2
  229. package/lib/host-packages/claude/openplanr/skills/investigate/references/findings.md +92 -0
  230. package/lib/host-packages/claude/openplanr/skills/investigate/scripts/backlog-item.mjs +339 -0
  231. package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +24 -11
  232. package/lib/host-packages/claude/openplanr/skills/plan/schemas/design-document.schema.json +207 -7
  233. package/lib/host-packages/claude/openplanr/skills/share/references/connectors.md +4 -6
  234. package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +46 -14
  235. package/lib/host-packages/claude/openplanr/skills/ship/references/findings.md +92 -0
  236. package/lib/host-packages/claude/openplanr/skills/ship/references/result-contract.md +3 -1
  237. package/lib/host-packages/claude/openplanr/skills/ship/scripts/backlog-item.mjs +339 -0
  238. package/lib/host-packages/claude/openplanr/skills/spec/SKILL.md +6 -0
  239. package/lib/host-packages/claude/openplanr/skills/spec/references/specification-contract.md +3 -1
  240. package/lib/host-packages/claude/openplanr/skills/sprint/references/connectors.md +4 -6
  241. package/lib/host-packages/claude/openplanr/skills/status/references/connectors.md +4 -6
  242. package/lib/host-packages/claude/openplanr/skills/sync/references/connectors.md +4 -6
  243. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +132 -92
  244. package/lib/host-packages/cursor/openplanr/CONNECTORS.md +4 -6
  245. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  246. package/lib/host-packages/cursor/openplanr/rules/planr-connect/references/connectors.md +4 -6
  247. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/craft.md +14 -3
  248. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-system.md +48 -1
  249. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/discovery.md +18 -4
  250. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/generation.md +133 -2
  251. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/hosted-canvas.md +62 -0
  252. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/review.md +46 -1
  253. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +17 -1
  254. package/lib/host-packages/cursor/openplanr/rules/planr-design/schemas/design-document.schema.json +207 -7
  255. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/craft.md +14 -3
  256. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-system.md +48 -1
  257. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/discovery.md +18 -4
  258. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/generation.md +133 -2
  259. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/review.md +46 -1
  260. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +17 -1
  261. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/schemas/design-document.schema.json +207 -7
  262. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/craft.md +14 -3
  263. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-system.md +48 -1
  264. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/discovery.md +18 -4
  265. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/generation.md +133 -2
  266. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/review.md +46 -1
  267. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +17 -1
  268. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/schemas/design-document.schema.json +207 -7
  269. package/lib/host-packages/cursor/openplanr/rules/planr-design.mdc +12 -0
  270. package/lib/host-packages/cursor/openplanr/rules/planr-investigate/references/findings.md +92 -0
  271. package/lib/host-packages/cursor/openplanr/rules/planr-investigate/scripts/backlog-item.mjs +339 -0
  272. package/lib/host-packages/cursor/openplanr/rules/planr-investigate.mdc +11 -2
  273. package/lib/host-packages/cursor/openplanr/rules/planr-plan/schemas/design-document.schema.json +207 -7
  274. package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +24 -11
  275. package/lib/host-packages/cursor/openplanr/rules/planr-share/references/connectors.md +4 -6
  276. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/findings.md +92 -0
  277. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/result-contract.md +3 -1
  278. package/lib/host-packages/cursor/openplanr/rules/planr-ship/scripts/backlog-item.mjs +339 -0
  279. package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +46 -14
  280. package/lib/host-packages/cursor/openplanr/rules/planr-spec/references/specification-contract.md +3 -1
  281. package/lib/host-packages/cursor/openplanr/rules/planr-spec.mdc +6 -0
  282. package/lib/host-packages/cursor/openplanr/rules/planr-sprint/references/connectors.md +4 -6
  283. package/lib/host-packages/cursor/openplanr/rules/planr-status/references/connectors.md +4 -6
  284. package/lib/host-packages/cursor/openplanr/rules/planr-sync/references/connectors.md +4 -6
  285. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-artifact-shell.mjs +1 -1
  286. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +1 -1
  287. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +471 -80
  288. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +2 -2
  289. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-resource-pack.mjs +1 -1
  290. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review.mjs +45 -4
  291. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-runtime-support-e34c388a8e59.mjs → cursor/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs} +1 -1
  292. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +8 -5
  293. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +138 -12
  294. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +1 -1
  295. 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} +413 -45
  296. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-upload-spool.mjs +1 -1
  297. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +482 -79
  298. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -32
  299. 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
  300. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +322 -45
  301. 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
  302. 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
  303. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +11 -10
  304. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -3
  305. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +16 -11
  306. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +7 -11
  307. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +165 -276
  308. 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
  309. 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
  310. 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
  311. 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
  312. 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
  313. 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
  314. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +119 -244
  315. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +7 -17
  316. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +3 -4
  317. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +285 -0
  318. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +2773 -0
  319. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +134 -0
  320. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +2207 -0
  321. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +16 -0
  322. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +8 -0
  323. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +3883 -0
  324. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +966 -0
  325. 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
  326. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +1597 -0
  327. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +101 -47
  328. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +6 -2
  329. 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.22.0}/design-document.schema.json +207 -7
  330. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
  331. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +324 -45
  332. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +73 -12
  333. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +6 -2
  334. package/lib/host-packages/openai/.claude-plugin/marketplace.json +2 -2
  335. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +1 -1
  336. package/lib/host-packages/openai/openplanr/.openplanr-content.json +139 -99
  337. package/lib/host-packages/openai/openplanr/CONNECTORS.md +4 -6
  338. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-artifact-shell.mjs +1 -1
  339. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +1 -1
  340. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +471 -80
  341. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +2 -2
  342. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-resource-pack.mjs +1 -1
  343. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review.mjs +45 -4
  344. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/design-runtime-support-e34c388a8e59.mjs → openai/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs} +1 -1
  345. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +8 -5
  346. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +138 -12
  347. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +1 -1
  348. 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} +413 -45
  349. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-upload-spool.mjs +1 -1
  350. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +482 -79
  351. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -32
  352. 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
  353. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +322 -45
  354. 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
  355. 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
  356. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +11 -10
  357. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -3
  358. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +16 -11
  359. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +7 -11
  360. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +165 -276
  361. 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
  362. 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
  363. 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
  364. 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
  365. 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
  366. 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
  367. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +119 -244
  368. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +7 -17
  369. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +3 -4
  370. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +285 -0
  371. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +2773 -0
  372. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +134 -0
  373. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +2207 -0
  374. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +16 -0
  375. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +8 -0
  376. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +3883 -0
  377. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +966 -0
  378. 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
  379. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +1597 -0
  380. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +101 -47
  381. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +6 -2
  382. 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.22.0}/design-document.schema.json +207 -7
  383. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
  384. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +324 -45
  385. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +73 -12
  386. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +6 -2
  387. package/lib/host-packages/openai/openplanr/skills/connect/references/connectors.md +4 -6
  388. package/lib/host-packages/openai/openplanr/skills/design/SKILL.md +12 -0
  389. package/lib/host-packages/openai/openplanr/skills/design/openplanr.skill.json +11 -0
  390. package/lib/host-packages/openai/openplanr/skills/design/references/craft.md +14 -3
  391. package/lib/host-packages/openai/openplanr/skills/design/references/design-system.md +48 -1
  392. package/lib/host-packages/openai/openplanr/skills/design/references/discovery.md +18 -4
  393. package/lib/host-packages/openai/openplanr/skills/design/references/generation.md +133 -2
  394. package/lib/host-packages/openai/openplanr/skills/design/references/hosted-canvas.md +62 -0
  395. package/lib/host-packages/openai/openplanr/skills/design/references/review.md +46 -1
  396. package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +17 -1
  397. package/lib/host-packages/openai/openplanr/skills/design/schemas/design-document.schema.json +207 -7
  398. package/lib/host-packages/openai/openplanr/skills/design-loop/references/craft.md +14 -3
  399. package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-system.md +48 -1
  400. package/lib/host-packages/openai/openplanr/skills/design-loop/references/discovery.md +18 -4
  401. package/lib/host-packages/openai/openplanr/skills/design-loop/references/generation.md +133 -2
  402. package/lib/host-packages/openai/openplanr/skills/design-loop/references/review.md +46 -1
  403. package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +17 -1
  404. package/lib/host-packages/openai/openplanr/skills/design-loop/schemas/design-document.schema.json +207 -7
  405. package/lib/host-packages/openai/openplanr/skills/design-review/references/craft.md +14 -3
  406. package/lib/host-packages/openai/openplanr/skills/design-review/references/design-system.md +48 -1
  407. package/lib/host-packages/openai/openplanr/skills/design-review/references/discovery.md +18 -4
  408. package/lib/host-packages/openai/openplanr/skills/design-review/references/generation.md +133 -2
  409. package/lib/host-packages/openai/openplanr/skills/design-review/references/review.md +46 -1
  410. package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +17 -1
  411. package/lib/host-packages/openai/openplanr/skills/design-review/schemas/design-document.schema.json +207 -7
  412. package/lib/host-packages/openai/openplanr/skills/investigate/SKILL.md +11 -2
  413. package/lib/host-packages/openai/openplanr/skills/investigate/agents/openai.yaml +1 -1
  414. package/lib/host-packages/openai/openplanr/skills/investigate/openplanr.skill.json +23 -1
  415. package/lib/host-packages/openai/openplanr/skills/investigate/references/findings.md +92 -0
  416. package/lib/host-packages/openai/openplanr/skills/investigate/scripts/backlog-item.mjs +339 -0
  417. package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +24 -11
  418. package/lib/host-packages/openai/openplanr/skills/plan/openplanr.skill.json +1 -1
  419. package/lib/host-packages/openai/openplanr/skills/plan/schemas/design-document.schema.json +207 -7
  420. package/lib/host-packages/openai/openplanr/skills/share/references/connectors.md +4 -6
  421. package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +46 -14
  422. package/lib/host-packages/openai/openplanr/skills/ship/agents/openai.yaml +1 -1
  423. package/lib/host-packages/openai/openplanr/skills/ship/openplanr.skill.json +23 -1
  424. package/lib/host-packages/openai/openplanr/skills/ship/references/findings.md +92 -0
  425. package/lib/host-packages/openai/openplanr/skills/ship/references/result-contract.md +3 -1
  426. package/lib/host-packages/openai/openplanr/skills/ship/scripts/backlog-item.mjs +339 -0
  427. package/lib/host-packages/openai/openplanr/skills/spec/SKILL.md +6 -0
  428. package/lib/host-packages/openai/openplanr/skills/spec/openplanr.skill.json +1 -1
  429. package/lib/host-packages/openai/openplanr/skills/spec/references/specification-contract.md +3 -1
  430. package/lib/host-packages/openai/openplanr/skills/sprint/references/connectors.md +4 -6
  431. package/lib/host-packages/openai/openplanr/skills/status/references/connectors.md +4 -6
  432. package/lib/host-packages/openai/openplanr/skills/sync/references/connectors.md +4 -6
  433. package/lib/json-schema.mjs +4 -0
  434. package/package.json +13 -13
  435. package/dist/dashboard/assets/index-G7ygVDGg.js +0 -572
  436. package/dist/dashboard/assets/index-G7ygVDGg.js.map +0 -1
  437. package/dist/templates/backlog/backlog-item.md.hbs +0 -40
  438. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +0 -3589
  439. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +0 -184
  440. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +0 -5229
  441. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +0 -1733
  442. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +0 -1844
  443. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +0 -3589
  444. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +0 -184
  445. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +0 -5229
  446. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +0 -1733
  447. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +0 -1844
  448. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +0 -3589
  449. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +0 -184
  450. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +0 -5229
  451. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +0 -1733
  452. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +0 -1844
@@ -12,10 +12,13 @@ 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,
21
+ inspectLocalDocumentBody,
19
22
  json,
20
23
  loadReviewContext,
21
24
  parse,
@@ -40,21 +43,83 @@ import {
40
43
  resolveArtifactHtml
41
44
  } from "./design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs";
42
45
  import {
43
- assertDesignDocument
44
- } from "./design-shared-protocol-contracts-31a760fc.mjs";
46
+ DESIGN_DOCUMENT_SCHEMA,
47
+ assertDesignDocument,
48
+ initialFrameHeight,
49
+ validateDesignProps
50
+ } from "./design-shared-protocol-contracts-b5f28f94.mjs";
51
+
52
+ // packages/design/lib/design/frame-size.mjs
53
+ function designFrameLabel(frame) {
54
+ const dimensions = `${frame.width} \xD7 ${frame.height}`;
55
+ return frame.label.includes(dimensions) ? frame.label : `${frame.label} \xB7 ${dimensions}`;
56
+ }
57
+ function designFrameViewport(document2, frame) {
58
+ return {
59
+ width: frame.width,
60
+ height: frame.height === "auto" ? initialFrameHeight(document2) : frame.height
61
+ };
62
+ }
63
+ function matchesDesignFrame(frame, viewport) {
64
+ return Boolean(
65
+ frame && viewport?.width === frame.width && (frame.height === "auto" ? Number.isInteger(viewport.height) && viewport.height > 0 && viewport.height <= 16384 : viewport.height === frame.height)
66
+ );
67
+ }
68
+ function observeDesignFrameSize() {
69
+ let pending = false;
70
+ const measure = async () => {
71
+ if (pending) return;
72
+ pending = true;
73
+ try {
74
+ await document.fonts.ready;
75
+ await new Promise((resolve3) => requestAnimationFrame(() => requestAnimationFrame(resolve3)));
76
+ parent.postMessage(
77
+ {
78
+ type: "openplanr:design-size",
79
+ screenId: document.body.getAttribute("data-planr-screen"),
80
+ width: innerWidth,
81
+ height: Math.min(16384, Math.max(1, document.documentElement.scrollHeight))
82
+ },
83
+ "*"
84
+ );
85
+ } finally {
86
+ pending = false;
87
+ }
88
+ };
89
+ const schedule = () => {
90
+ void measure().catch((error) => {
91
+ parent.postMessage({ type: "openplanr:design-size-error", message: error.message }, "*");
92
+ });
93
+ };
94
+ addEventListener("message", (event) => {
95
+ if (event.source === parent && event.data?.type === "openplanr:design-measure") schedule();
96
+ });
97
+ addEventListener(
98
+ "load",
99
+ () => {
100
+ new ResizeObserver(schedule).observe(document.body);
101
+ schedule();
102
+ },
103
+ { once: true }
104
+ );
105
+ }
106
+
107
+ // packages/design/lib/design/layout-save.mjs
108
+ import { readFileSync as readFileSync6, statSync } from "node:fs";
109
+ import { join as join3 } from "node:path";
45
110
 
46
111
  // packages/design/lib/design/document.mjs
47
112
  import { randomUUID } from "node:crypto";
48
113
  import {
49
114
  existsSync as existsSync2,
50
115
  mkdirSync,
51
- readFileSync as readFileSync4,
116
+ readFileSync as readFileSync5,
52
117
  realpathSync,
53
118
  renameSync,
54
119
  rmSync,
55
120
  writeFileSync
56
121
  } from "node:fs";
57
- import { dirname, join, resolve as resolve2 } from "node:path";
122
+ import { dirname, join as join2, resolve as resolve2 } from "node:path";
58
123
 
59
124
  // packages/artifact/lib/artifact/bridge.mjs
60
125
  import { randomBytes as randomBytes2 } from "node:crypto";
@@ -149,7 +214,9 @@ function createArtifactViewportGestures(window2, emit) {
149
214
  mode: getter(window2.WheelEvent.prototype, "deltaMode")
150
215
  };
151
216
  let enabled = false, disposed = false, timer = 0, pending = null, pendingType = "";
217
+ let gestureScale = 1;
152
218
  const clear = () => {
219
+ gestureScale = 1;
153
220
  if (timer) cancel(timer);
154
221
  timer = 0;
155
222
  pending = null;
@@ -163,6 +230,29 @@ function createArtifactViewportGestures(window2, emit) {
163
230
  pendingType = "";
164
231
  if (enabled && !disposed && value) emit(type, value);
165
232
  };
233
+ const queue = (type, value) => {
234
+ const deltaX = value.deltaX ?? 0;
235
+ const deltaY = value.deltaY ?? 0;
236
+ if (pendingType && pendingType !== type) flush();
237
+ pendingType = type;
238
+ pending = type === "viewport.zoom" ? {
239
+ ...value,
240
+ deltaY: Math.max(
241
+ -ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA,
242
+ Math.min(ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA, (pending?.deltaY || 0) + deltaY)
243
+ )
244
+ } : {
245
+ deltaX: Math.max(
246
+ -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
247
+ Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, (pending?.deltaX || 0) + deltaX)
248
+ ),
249
+ deltaY: Math.max(
250
+ -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
251
+ Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, (pending?.deltaY || 0) + deltaY)
252
+ )
253
+ };
254
+ if (!timer) timer = schedule(flush, 16);
255
+ };
166
256
  const wheel = (event) => {
167
257
  if (!enabled || disposed || !event.isTrusted || !event.cancelable) return;
168
258
  let x, y, deltaX, deltaY, mode, zooming, shift;
@@ -213,34 +303,49 @@ function createArtifactViewportGestures(window2, emit) {
213
303
  if (!value) return;
214
304
  prevent.call(event);
215
305
  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);
306
+ queue(type, value);
307
+ };
308
+ const consumeGesture = (event) => {
309
+ if (!enabled || disposed || !event.isTrusted || !event.cancelable) return false;
310
+ prevent.call(event);
311
+ stop.call(event);
312
+ return true;
313
+ };
314
+ const gestureStart = (event) => {
315
+ if (consumeGesture(event)) gestureScale = 1;
316
+ };
317
+ const gestureChange = (raw) => {
318
+ if (!consumeGesture(raw)) return;
319
+ const event = raw;
320
+ if (!Number.isFinite(event.scale) || event.scale <= 0) return;
321
+ const deltaY = Math.max(
322
+ -ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA,
323
+ Math.min(ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA, -Math.log(event.scale / gestureScale) / 0.01)
324
+ );
325
+ gestureScale = event.scale;
326
+ const value = normalizeArtifactViewportZoom(
327
+ { x: event.clientX, y: event.clientY, deltaY },
328
+ { width: window2.innerWidth, height: window2.innerHeight }
329
+ );
330
+ if (value) queue("viewport.zoom", value);
331
+ };
332
+ const gestureEnd = (event) => {
333
+ if (consumeGesture(event)) gestureScale = 1;
235
334
  };
236
335
  const destroy = () => {
237
336
  disposed = true;
238
337
  enabled = false;
239
338
  clear();
240
339
  remove("wheel", wheel, true);
340
+ remove("gesturestart", gestureStart, true);
341
+ remove("gesturechange", gestureChange, true);
342
+ remove("gestureend", gestureEnd, true);
241
343
  remove("pagehide", destroy);
242
344
  };
243
345
  add("wheel", wheel, { capture: true, passive: false });
346
+ add("gesturestart", gestureStart, { capture: true, passive: false });
347
+ add("gesturechange", gestureChange, { capture: true, passive: false });
348
+ add("gestureend", gestureEnd, { capture: true, passive: false });
244
349
  add("pagehide", destroy, { once: true });
245
350
  return Object.freeze({
246
351
  setEnabled(value) {
@@ -288,8 +393,8 @@ function normalizeArtifactInspection(value, viewport) {
288
393
  const descriptor = plain(entry) ? Object.getOwnPropertyDescriptor(entry, key) : null;
289
394
  return descriptor && Object.hasOwn(descriptor, "value") ? descriptor.value : void 0;
290
395
  };
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"]))
396
+ const exact2 = (entry, keys) => plain(entry) && Object.keys(entry).length === keys.length && Object.keys(entry).every((key) => keys.includes(key));
397
+ if (!exact2(value, ["tagName", "anchor", "rect", "viewport", "styles", "accessibility"]))
293
398
  return null;
294
399
  const tagName = own(value, "tagName");
295
400
  const anchor = own(value, "anchor");
@@ -298,7 +403,7 @@ function normalizeArtifactInspection(value, viewport) {
298
403
  const styles = own(value, "styles");
299
404
  const accessibility = own(value, "accessibility");
300
405
  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;
406
+ if (!exact2(size, ["width", "height"]) || !exact2(rect, ["x", "y", "width", "height"])) return null;
302
407
  if (!["width", "height"].every(
303
408
  (key) => Number.isInteger(own(size, key)) && own(size, key) >= 1 && own(size, key) <= 16384 && own(size, key) === viewport?.[key]
304
409
  ))
@@ -308,14 +413,14 @@ function normalizeArtifactInspection(value, viewport) {
308
413
  ))
309
414
  return null;
310
415
  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))))
416
+ 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
417
  return null;
313
- if (!exact(styles, ARTIFACT_INSPECTION_PROPERTIES) || !ARTIFACT_INSPECTION_PROPERTIES.every((key) => {
418
+ if (!exact2(styles, ARTIFACT_INSPECTION_PROPERTIES) || !ARTIFACT_INSPECTION_PROPERTIES.every((key) => {
314
419
  const text = own(styles, key);
315
420
  return typeof text === "string" && text.length <= 256 && !/[\u0000-\u001f\u007f]/.test(text) && !/(?:url\s*\(|https?:|file:)/i.test(text);
316
421
  }))
317
422
  return null;
318
- if (!exact(accessibility, ["role", "ariaLabel", "alt", "tabIndex", "disabled"]) || !["role", "ariaLabel", "alt"].every(
423
+ if (!exact2(accessibility, ["role", "ariaLabel", "alt", "tabIndex", "disabled"]) || !["role", "ariaLabel", "alt"].every(
319
424
  (key) => typeof own(accessibility, key) === "string" && own(accessibility, key).length <= 256 && !/[\u0000-\u001f\u007f]/.test(own(accessibility, key))
320
425
  ) || !Number.isInteger(own(accessibility, "tabIndex")) || accessibility.tabIndex < -1 || accessibility.tabIndex > 32767 || typeof own(accessibility, "disabled") !== "boolean")
321
426
  return null;
@@ -340,20 +445,20 @@ function normalizeArtifactThumbnail(value) {
340
445
  }
341
446
  function normalizeArtifactBridgeToolResult(requestType, message, viewport) {
342
447
  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(
448
+ 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
449
  (descriptor) => Object.hasOwn(descriptor, "value")
345
450
  );
346
451
  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")
452
+ if (exact2(base) && message.type === "inspect.miss") return { valid: true, value: null };
453
+ if (!exact2([...base, "inspection"]) || message.type !== "inspect.result")
349
454
  return { valid: false };
350
455
  const value = normalizeArtifactInspection(message.inspection, viewport);
351
456
  return value ? { valid: true, value } : { valid: false };
352
457
  }
353
458
  if (requestType === "thumbnail.request") {
354
- if (exact([...base, "reason"]) && message.type === "thumbnail.error" && typeof message.reason === "string" && message.reason.length <= 256)
459
+ if (exact2([...base, "reason"]) && message.type === "thumbnail.error" && typeof message.reason === "string" && message.reason.length <= 256)
355
460
  return { valid: true, value: null };
356
- if (!exact([...base, "dataUrl", "width", "height", "label"]) || message.type !== "thumbnail.result")
461
+ if (!exact2([...base, "dataUrl", "width", "height", "label"]) || message.type !== "thumbnail.result")
357
462
  return { valid: false };
358
463
  const value = normalizeArtifactThumbnail({
359
464
  dataUrl: message.dataUrl,
@@ -1517,6 +1622,15 @@ function lintDesign(html, opts = {}) {
1517
1622
  const { designSystem = null } = opts;
1518
1623
  const errors = [];
1519
1624
  const warnings = [];
1625
+ if (opts.screen) {
1626
+ const values = Object.hasOwn(opts.variant?.props ?? {}, opts.screen.id) ? opts.variant.props[opts.screen.id] : {};
1627
+ errors.push(
1628
+ ...validateDesignProps({
1629
+ screens: [opts.screen],
1630
+ variants: [{ props: { [opts.screen.id]: values } }]
1631
+ }).map((message) => ({ rule: "invalid-instance-prop", level: "error", message }))
1632
+ );
1633
+ }
1520
1634
  const decls = [...styleBlockDecls(html), ...inlineStyleDecls(html)];
1521
1635
  for (const d of decls) {
1522
1636
  if (SPACING_PROP.test(d.prop)) {
@@ -1590,11 +1704,64 @@ function lintDesign(html, opts = {}) {
1590
1704
  summary: `${errors.length} error(s), ${warnings.length} warning(s)`
1591
1705
  };
1592
1706
  }
1707
+ function withoutRootTheme(html) {
1708
+ if (!/theme-(?:light|dark)|data-theme/iu.test(html)) return null;
1709
+ const body = inspectLocalDocumentBody(html);
1710
+ if (!body) return null;
1711
+ const edits = [];
1712
+ for (const { name, value } of body.attrs) {
1713
+ const location = body.location.attrs?.[name];
1714
+ if (!location) continue;
1715
+ let replacement;
1716
+ if (name === "data-theme" && ["light", "dark"].includes(value)) replacement = "";
1717
+ if (name === "class") {
1718
+ const raw = html.slice(location.startOffset, location.endOffset);
1719
+ const quoted = /^(class\s*=\s*)(["'])([\s\S]*)\2$/iu.exec(raw);
1720
+ if (quoted) {
1721
+ const kept = quoted[3].replace(/(^|\s)theme-(?:light|dark)(?=\s|$)/gu, "$1");
1722
+ if (kept !== quoted[3]) replacement = `${quoted[1]}${quoted[2]}${kept}${quoted[2]}`;
1723
+ } else if (/^class\s*=\s*theme-(?:light|dark)$/iu.test(raw)) replacement = "";
1724
+ }
1725
+ if (replacement !== void 0) edits.push({ ...location, replacement });
1726
+ }
1727
+ if (!edits.length) return null;
1728
+ let normalized = html;
1729
+ for (const { startOffset, endOffset, replacement } of edits.sort(
1730
+ (a, b) => b.startOffset - a.startOffset
1731
+ ))
1732
+ normalized = normalized.slice(0, startOffset) + replacement + normalized.slice(endOffset);
1733
+ return normalized;
1734
+ }
1735
+ function lintThemeOnlySources(sources) {
1736
+ const warnings = [];
1737
+ const seen = /* @__PURE__ */ new Map();
1738
+ for (const { screenId, source, html } of sources) {
1739
+ const normalized = withoutRootTheme(html);
1740
+ if (normalized === null) continue;
1741
+ const key = JSON.stringify({
1742
+ html: normalized,
1743
+ styles: source.styles ?? [],
1744
+ scripts: source.scripts ?? []
1745
+ });
1746
+ const previous = seen.get(key);
1747
+ if (previous && previous.screenId !== screenId && previous.source !== source.html && previous.html !== html)
1748
+ warnings.push({
1749
+ rule: "theme-only-source",
1750
+ level: "warn",
1751
+ screenId,
1752
+ message: `Screens ${previous.screenId} (${previous.source}) and ${screenId} (${source.html}) differ only by a root theme marker; declare a theme prop and share one source.`
1753
+ });
1754
+ else seen.set(key, { screenId, source: source.html, html });
1755
+ }
1756
+ return warnings;
1757
+ }
1593
1758
  function lintCanvasData(data, { frames } = {}) {
1594
1759
  const errors = [];
1595
1760
  for (const section of data?.sections || []) {
1596
1761
  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 });
1762
+ const accepted = frames?.length ? frames.some(
1763
+ (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)
1764
+ ) : isCanonicalFrame({ w: a.width, h: a.height });
1598
1765
  if (!accepted) {
1599
1766
  errors.push({
1600
1767
  rule: "frame-not-canonical",
@@ -1758,7 +1925,7 @@ function isRecord(value) {
1758
1925
  return value !== null && typeof value === "object" && !Array.isArray(value);
1759
1926
  }
1760
1927
  var digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
1761
- function boundedRead(url, label, { limit, exact, links = false }) {
1928
+ function boundedRead(url, label, { limit, exact: exact2, links = false }) {
1762
1929
  if (!links) {
1763
1930
  const stat = lstatSync(url, { throwIfNoEntry: false });
1764
1931
  if (!stat?.isFile()) throw new Error(`${label} must be a regular file, not a link.`);
@@ -1770,15 +1937,15 @@ function boundedRead(url, label, { limit, exact, links = false }) {
1770
1937
  try {
1771
1938
  const stat = fstatSync(descriptor);
1772
1939
  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;
1940
+ if (exact2 !== void 0 ? stat.size !== exact2 : stat.size > limit)
1941
+ throw new Error(`${label} is ${stat.size} bytes; expected ${exact2 ?? `at most ${limit}`}.`);
1942
+ const capacity = (exact2 ?? Math.min(stat.size, limit)) + 1;
1776
1943
  const buffer = Buffer.alloc(capacity);
1777
1944
  let length = 0;
1778
1945
  for (let read = -1; read !== 0 && length < capacity; length += read)
1779
1946
  read = readSync(descriptor, buffer, length, capacity - length, null);
1780
1947
  if (length === capacity) throw new Error(`${label} changed size while it was read.`);
1781
- if (exact !== void 0 && length !== exact)
1948
+ if (exact2 !== void 0 && length !== exact2)
1782
1949
  throw new Error(`${label} changed size while it was read.`);
1783
1950
  return buffer.subarray(0, length);
1784
1951
  } finally {
@@ -1994,7 +2161,7 @@ function designNotes(document2) {
1994
2161
  ).join("")}</div></details>`;
1995
2162
  }
1996
2163
  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>
2164
+ 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
2165
  <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
2166
  <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
2167
  <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 +2183,8 @@ function renderDesignStudioMarkup({
2016
2183
  stalePins = [],
2017
2184
  reviewContext = null,
2018
2185
  contextDigest = null,
2019
- fingerprints = []
2186
+ fingerprints = [],
2187
+ contentIdentity = null
2020
2188
  } = {}, {
2021
2189
  stageRuntimeUrl = "./artifact-review-stage.js",
2022
2190
  renderShell,
@@ -2047,6 +2215,7 @@ function renderDesignStudioMarkup({
2047
2215
  reviewContext,
2048
2216
  contextDigest,
2049
2217
  fingerprints,
2218
+ contentIdentity,
2050
2219
  artifactKinds: Object.fromEntries(
2051
2220
  envelope.artifacts.map((artifact) => [artifact.id, artifact.kind])
2052
2221
  ),
@@ -2138,7 +2307,8 @@ function createDesignStudioEntries(document2, envelope) {
2138
2307
  artifactId,
2139
2308
  variantId: variant.id,
2140
2309
  screenId,
2141
- frameId: frame.id
2310
+ frameId: frame.id,
2311
+ ...frame.height === "auto" ? { height: "auto" } : {}
2142
2312
  });
2143
2313
  }
2144
2314
  }
@@ -2163,6 +2333,101 @@ function renderDesignStudio(input = {}, options = {}) {
2163
2333
  );
2164
2334
  }
2165
2335
 
2336
+ // packages/design/lib/design/view-context.mjs
2337
+ import { readFileSync as readFileSync4 } from "node:fs";
2338
+ import { join } from "node:path";
2339
+ var anchorPattern = new RegExp(DESIGN_DOCUMENT_SCHEMA.$defs.id.pattern, "u");
2340
+ 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));
2341
+ var boardFields = ["screenId", "frameId", "variantId"];
2342
+ function validateDesignViewContext(input, current) {
2343
+ if (!exact(input, ["revision", "view", "visibleScreens", "selected", "dirty"]))
2344
+ throw new Error(
2345
+ "View context requires exactly revision, view, visibleScreens, selected and dirty."
2346
+ );
2347
+ if (input.revision !== current.revision)
2348
+ throw Object.assign(
2349
+ new Error(
2350
+ `View context revision ${input.revision} is stale; current revision is ${current.revision}.`
2351
+ ),
2352
+ { statusCode: 409 }
2353
+ );
2354
+ if (!["canvas", "prototype", "walkthrough"].includes(input.view))
2355
+ throw new Error(`Unknown view context view ${input.view}.`);
2356
+ if (typeof input.dirty !== "boolean")
2357
+ throw new Error(`View context dirty must be boolean; received ${input.dirty}.`);
2358
+ const board = (value, selected = false) => {
2359
+ if (!exact(value, selected ? [...boardFields, "planrId"] : boardFields))
2360
+ throw new Error(
2361
+ `View context ${selected ? "selected" : "visibleScreens entry"} has invalid fields.`
2362
+ );
2363
+ if (!current.entries.some((entry) => boardFields.every((key) => entry[key] === value[key])))
2364
+ throw new Error(`Unknown view context board ${JSON.stringify(value)}.`);
2365
+ return boardFields.map((key) => value[key]).join("/");
2366
+ };
2367
+ if (!Array.isArray(input.visibleScreens) || input.visibleScreens.length > current.entries.length)
2368
+ throw new Error(
2369
+ `View context visibleScreens must contain at most ${current.entries.length} boards.`
2370
+ );
2371
+ const keys = input.visibleScreens.map((value) => board(value));
2372
+ if (new Set(keys).size !== keys.length)
2373
+ throw new Error("View context visibleScreens contains duplicate boards.");
2374
+ board(input.selected, true);
2375
+ const { planrId } = input.selected;
2376
+ if (planrId !== null && (typeof planrId !== "string" || planrId.length > 128 || !anchorPattern.test(planrId)))
2377
+ throw new Error(
2378
+ `View context planrId ${JSON.stringify(planrId)} must be null or a document anchor ID of at most 128 characters.`
2379
+ );
2380
+ return structuredClone(input);
2381
+ }
2382
+ function saveDesignViewContext(file, input, clock) {
2383
+ const current = currentDesign(file);
2384
+ const context = validateDesignViewContext(input, current);
2385
+ const value = {
2386
+ kind: "openplanr-design-view-context",
2387
+ schemaVersion: "1.0.0",
2388
+ ...context,
2389
+ updatedAt: clock().toISOString()
2390
+ };
2391
+ atomicJson(join(current.root, ".design/view-context.json"), value);
2392
+ return { ok: true };
2393
+ }
2394
+ function readDesignViewContext(file, { requestTime } = {}) {
2395
+ try {
2396
+ const current = currentDesign(file);
2397
+ const path = join(current.root, ".design/view-context.json");
2398
+ const bytes = readFileSync4(path);
2399
+ if (bytes.length > 128 * 1024) throw new Error(`${path} exceeds 128 KB.`);
2400
+ const value = JSON.parse(bytes.toString("utf8"));
2401
+ if (!exact(value, [
2402
+ "kind",
2403
+ "schemaVersion",
2404
+ "revision",
2405
+ "updatedAt",
2406
+ "view",
2407
+ "visibleScreens",
2408
+ "selected",
2409
+ "dirty"
2410
+ ]) || value.kind !== "openplanr-design-view-context" || value.schemaVersion !== "1.0.0")
2411
+ throw new Error(`${path} is not a supported design view context.`);
2412
+ if (typeof value.updatedAt !== "string" || !Number.isFinite(Date.parse(value.updatedAt)))
2413
+ throw new Error(`${path} has an invalid updatedAt timestamp.`);
2414
+ const { kind, schemaVersion, updatedAt, ...input } = value;
2415
+ validateDesignViewContext(input, current);
2416
+ if (requestTime !== void 0) {
2417
+ const requestedAt = Date.parse(requestTime);
2418
+ if (!Number.isFinite(requestedAt))
2419
+ throw new Error(`Invalid view context request time ${requestTime}.`);
2420
+ if (Date.parse(updatedAt) < requestedAt)
2421
+ throw new Error(
2422
+ `View context updatedAt ${updatedAt} is older than request ${requestTime}.`
2423
+ );
2424
+ }
2425
+ return value;
2426
+ } catch (error) {
2427
+ return { viewContext: null, reason: error.message };
2428
+ }
2429
+ }
2430
+
2166
2431
  // packages/design/lib/design/document.mjs
2167
2432
  var DESIGN_VIEWS = Object.freeze(["canvas", "prototype", "walkthrough"]);
2168
2433
  var DESIGN_RENDERER_VERSION = "1.3.0";
@@ -2184,7 +2449,7 @@ function inspectDesignDocument(file, { readSource } = {}) {
2184
2449
  `This board needs ${sourceCount} screen sources and ${viewCount} viewport references. Split it into linked boards: one board supports 256 sources and 4096 views.`
2185
2450
  );
2186
2451
  const sources = new Set(document2.assets ?? []);
2187
- if (existsSync2(join(root, "review-context.json"))) sources.add("review-context.json");
2452
+ if (existsSync2(join2(root, "review-context.json"))) sources.add("review-context.json");
2188
2453
  if (document2.designSystem?.tokens) sources.add(document2.designSystem.tokens);
2189
2454
  for (const screen of document2.screens)
2190
2455
  for (const source of [
@@ -2212,7 +2477,7 @@ function inspectDesignDocument(file, { readSource } = {}) {
2212
2477
  missing,
2213
2478
  specPath: designSpecPath(root),
2214
2479
  // Guarded source preparation is independent of local render cache state.
2215
- current: readSource ? null : readJson(join(root, ".design/current.json"), null)
2480
+ current: readSource ? null : readJson(join2(root, ".design/current.json"), null)
2216
2481
  };
2217
2482
  }
2218
2483
  function prepareDesignDocument(file, { readSource, passive = false, maxBytes } = {}) {
@@ -2227,12 +2492,23 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2227
2492
  const sourceContents = new Map(
2228
2493
  inspected.sources.map((source) => [
2229
2494
  source,
2230
- readSource ? readSource(source, root).value : readFileSync4(resolveLocalDocumentFile(root, source))
2495
+ readSource ? readSource(source, root).value : readFileSync5(resolveLocalDocumentFile(root, source))
2231
2496
  ])
2232
2497
  );
2233
2498
  for (const variant of document2.variants.filter((item) => item.status === "ready")) {
2499
+ const themeWarnings = lintThemeOnlySources(
2500
+ document2.screens.map((screen) => {
2501
+ const source = variant.sources?.[screen.id] ?? screen.source;
2502
+ return {
2503
+ screenId: screen.id,
2504
+ source,
2505
+ html: sourceContents.get(source.html).toString("utf8")
2506
+ };
2507
+ })
2508
+ );
2234
2509
  for (const screenId of document2.screenOrder) {
2235
2510
  const screen = document2.screens.find((item) => item.id === screenId);
2511
+ const values = Object.hasOwn(variant.props ?? {}, screenId) ? variant.props[screenId] : {};
2236
2512
  const bundled = bundleLocalDocument({
2237
2513
  root,
2238
2514
  source: variant.sources?.[screenId] ?? screen.source,
@@ -2240,8 +2516,21 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2240
2516
  screenId,
2241
2517
  readSource,
2242
2518
  passive,
2519
+ ...screen.props ? {
2520
+ screenProps: Object.fromEntries(
2521
+ Object.entries(screen.props).map(([name, declaration]) => [
2522
+ name,
2523
+ Object.hasOwn(values, name) ? values[name] : declaration.default
2524
+ ])
2525
+ )
2526
+ } : {},
2243
2527
  ...maxBytes === void 0 ? {} : { maxBytes }
2244
2528
  });
2529
+ if (document2.frames.some(({ height }) => height === "auto"))
2530
+ bundled.html = bundled.html.replace(
2531
+ "</body>",
2532
+ `<script>(${observeDesignFrameSize.toString()})()</script></body>`
2533
+ );
2245
2534
  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
2535
  if (!passive) bundled.html = bundled.html.replace("</body>", `${navigate}</body>`);
2247
2536
  for (const name of bundled.files) {
@@ -2249,7 +2538,7 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2249
2538
  if (!sourceContents.has(name))
2250
2539
  sourceContents.set(
2251
2540
  name,
2252
- readSource ? readSource(name, root).value : readFileSync4(resolveLocalDocumentFile(root, name))
2541
+ readSource ? readSource(name, root).value : readFileSync5(resolveLocalDocumentFile(root, name))
2253
2542
  );
2254
2543
  if (hash(sourceContents.get(name)) !== bundled.sourceDigests[name])
2255
2544
  throw new Error(
@@ -2257,8 +2546,12 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2257
2546
  );
2258
2547
  }
2259
2548
  const report = lintDesign(bundled.html, {
2260
- designSystem: document2.designSystem
2549
+ designSystem: document2.designSystem,
2550
+ screen,
2551
+ variant
2261
2552
  });
2553
+ report.warnings.push(...themeWarnings.filter((item) => item.screenId === screenId));
2554
+ report.summary = `${report.errors.length} error(s), ${report.warnings.length} warning(s)`;
2262
2555
  lint.push({ variantId: variant.id, screenId, ...report });
2263
2556
  for (const anchor of screen.anchors ?? []) {
2264
2557
  if (!bundled.html.includes(`data-planr-id="${anchor}"`) && !bundled.html.includes(`id="${anchor}"`))
@@ -2287,14 +2580,15 @@ function prepareDesignDocument(file, { readSource, passive = false, maxBytes } =
2287
2580
  kind: "html",
2288
2581
  title: `${screen.title} \xB7 ${variant.label} \xB7 ${frame.label}`,
2289
2582
  sourceId,
2290
- viewport: { width: frame.width, height: frame.height },
2583
+ viewport: designFrameViewport(document2, frame),
2291
2584
  colorScheme: "light"
2292
2585
  });
2293
2586
  entries.push({
2294
2587
  artifactId,
2295
2588
  screenId,
2296
2589
  variantId: variant.id,
2297
- frameId: frame.id
2590
+ frameId: frame.id,
2591
+ ...frame.height === "auto" ? { height: "auto" } : {}
2298
2592
  });
2299
2593
  }
2300
2594
  }
@@ -2347,7 +2641,7 @@ function designRendererRevision() {
2347
2641
  (name) => name === "studio.js" || existsSync2(new URL(`../../templates/studio/${name}`, new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href))
2348
2642
  ).map(
2349
2643
  (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))
2644
+ name === "studio.js" ? readDesignStudioRuntime() : readFileSync5(new URL(`../../templates/studio/${name}`, new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href))
2351
2645
  )
2352
2646
  )
2353
2647
  })
@@ -2418,22 +2712,34 @@ ${runtime}` : runtime;
2418
2712
  { stageRuntimeUrl: runtimeUrl }
2419
2713
  );
2420
2714
  }
2421
- async function renderDesignDocument(file, {
2715
+ async function renderDesignDocument(file, options = {}) {
2716
+ return withDesignRenderLock(file, (render) => render(options));
2717
+ }
2718
+ async function withDesignRenderLock(file, action) {
2719
+ const { root } = loadDesignDocument(file);
2720
+ const work = join2(root, ".design");
2721
+ mkdirSync(work, { recursive: true });
2722
+ const release = await acquireStartLock(join2(work, "render.lock"), {
2723
+ timeout: 1e3,
2724
+ stale: 3e4
2725
+ });
2726
+ try {
2727
+ recoverDesignPublication(root, { ownsRenderLock: true });
2728
+ return await action((options) => renderDesignDocumentUnlocked(file, options));
2729
+ } finally {
2730
+ release();
2731
+ }
2732
+ }
2733
+ async function renderDesignDocumentUnlocked(file, {
2422
2734
  beforeCommit,
2423
2735
  writePointer = atomicJson,
2424
2736
  rendererRevision = designRendererRevision(),
2425
2737
  now = () => (/* @__PURE__ */ new Date()).toISOString()
2426
2738
  } = {}) {
2427
2739
  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
- });
2740
+ const work = join2(root, ".design");
2434
2741
  let temporary;
2435
2742
  try {
2436
- recoverDesignPublication(root, { ownsRenderLock: true });
2437
2743
  const prepared = prepareDesignDocument(file);
2438
2744
  const errors = prepared.lint.flatMap(
2439
2745
  (item) => item.errors.map((error) => `${item.screenId}: ${error.message}`)
@@ -2441,15 +2747,15 @@ async function renderDesignDocument(file, {
2441
2747
  if (errors.length) throw new Error(`Design lint failed:
2442
2748
  ${errors.join("\n")}`);
2443
2749
  const specPath = designSpecPath(root);
2444
- const spec = readFileSync4(specPath, "utf8");
2750
+ const spec = readFileSync5(specPath, "utf8");
2445
2751
  for (let section = 1; section <= 10; section++)
2446
2752
  if (!new RegExp(`^## ${section}\\. `, "m").test(spec))
2447
2753
  throw new Error(`design-spec.md is missing section ${section}.`);
2448
2754
  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);
2755
+ const directory = join2(work, "revisions", prepared.revision);
2756
+ const previous = readJson(join2(work, "current.json"), null);
2451
2757
  const generatedAt = now();
2452
- const manifest = existsSync2(directory) ? readJson(join(directory, "render.json")).manifest : buildManifest({
2758
+ const manifest = existsSync2(directory) ? readJson(join2(directory, "render.json")).manifest : buildManifest({
2453
2759
  framework: "vanilla",
2454
2760
  designFormat: prepared.document.defaultView,
2455
2761
  source: prepared.document.brief.source,
@@ -2474,39 +2780,39 @@ ${errors.join("\n")}`);
2474
2780
  manifest
2475
2781
  };
2476
2782
  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);
2783
+ temporary = join2(work, `pending-${randomUUID()}`);
2784
+ mkdirSync(join2(temporary, "sources"), { recursive: true });
2785
+ writeFileSync(join2(temporary, "render.json"), json(record));
2786
+ writeFileSync(join2(temporary, "design-document.json"), json(prepared.document));
2787
+ writeFileSync(join2(temporary, "design-spec.md"), spec);
2482
2788
  for (const source of prepared.sourceFiles) {
2483
- const destination = join(temporary, "sources", source);
2789
+ const destination = join2(temporary, "sources", source);
2484
2790
  mkdirSync(dirname(destination), { recursive: true });
2485
2791
  writeFileSync(destination, prepared.sourceContents.get(source));
2486
2792
  }
2487
2793
  for (const view of DESIGN_VIEWS)
2488
- writeFileSync(join(temporary, `${view}.html`), standaloneDesignHtml(record, view));
2794
+ writeFileSync(join2(temporary, `${view}.html`), standaloneDesignHtml(record, view));
2489
2795
  beforeCommit?.(record);
2490
2796
  mkdirSync(dirname(directory), { recursive: true });
2491
2797
  renameSync(temporary, directory);
2492
2798
  temporary = null;
2493
2799
  }
2494
- const manifestPath = join(root, "finalized.json");
2495
- atomicJson(join(work, "publication.json"), {
2800
+ const manifestPath = join2(root, "finalized.json");
2801
+ atomicJson(join2(work, "publication.json"), {
2496
2802
  revision: prepared.revision,
2497
2803
  previousRevision: previous?.revision ?? null,
2498
2804
  manifest,
2499
- previousManifest: existsSync2(manifestPath) ? readFileSync4(manifestPath).toString("base64") : null
2805
+ previousManifest: existsSync2(manifestPath) ? readFileSync5(manifestPath).toString("base64") : null
2500
2806
  });
2501
2807
  try {
2502
2808
  atomicJson(manifestPath, manifest);
2503
- writePointer(join(work, "current.json"), {
2809
+ writePointer(join2(work, "current.json"), {
2504
2810
  revision: prepared.revision,
2505
2811
  previousRevision: previous?.revision === prepared.revision ? previous.previousRevision : previous?.revision ?? null,
2506
2812
  iterations: manifest.iterations,
2507
2813
  generatedAt: manifest.generated_at
2508
2814
  });
2509
- rmSync(join(work, "publication.json"), { force: true });
2815
+ rmSync(join2(work, "publication.json"), { force: true });
2510
2816
  } catch (error) {
2511
2817
  recoverDesignPublication(root, { ownsRenderLock: true });
2512
2818
  throw error;
@@ -2515,20 +2821,100 @@ ${errors.join("\n")}`);
2515
2821
  ok: true,
2516
2822
  revision: prepared.revision,
2517
2823
  document: resolve2(file),
2518
- artifact: join(directory, `${prepared.document.defaultView}.html`),
2824
+ artifact: join2(directory, `${prepared.document.defaultView}.html`),
2519
2825
  views: Object.fromEntries(
2520
- DESIGN_VIEWS.map((view) => [view, join(directory, `${view}.html`)])
2826
+ DESIGN_VIEWS.map((view) => [view, join2(directory, `${view}.html`)])
2521
2827
  ),
2522
- manifest: join(root, "finalized.json"),
2828
+ manifest: join2(root, "finalized.json"),
2523
2829
  spec: specPath,
2524
2830
  verification: "unverified"
2525
2831
  };
2526
2832
  } finally {
2527
2833
  if (temporary) rmSync(temporary, { recursive: true, force: true });
2528
- release();
2529
2834
  }
2530
2835
  }
2531
2836
 
2837
+ // packages/design/lib/design/layout-save.mjs
2838
+ async function saveDesignLayout(file, input) {
2839
+ 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"))
2840
+ throw new Error("Design layout requires a revision and either boards or restoreRevision.");
2841
+ return withDesignRenderLock(file, async (render) => {
2842
+ const current = currentDesign(file);
2843
+ if (input.revision !== current.revision)
2844
+ throw Object.assign(new Error("The design changed. Reload before saving its layout."), {
2845
+ statusCode: 409
2846
+ });
2847
+ const authored = prepareDesignDocument(file);
2848
+ const authoredContent = { ...authored.document };
2849
+ const committedContent = { ...current.document };
2850
+ delete authoredContent.layout;
2851
+ delete committedContent.layout;
2852
+ 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"))
2853
+ throw Object.assign(
2854
+ new Error(
2855
+ "Design sources or content changed. Render the design and reload before saving its layout."
2856
+ ),
2857
+ { statusCode: 409 }
2858
+ );
2859
+ const previous = readFileSync6(file, "utf8");
2860
+ const mode = statSync(file).mode & 4095;
2861
+ const document2 = JSON.parse(previous);
2862
+ if (Object.hasOwn(input, "restoreRevision")) {
2863
+ if (typeof input.restoreRevision !== "string" || !/^[a-f0-9]{64}$/u.test(input.restoreRevision))
2864
+ throw new Error(`Invalid layout restore revision ${input.restoreRevision}.`);
2865
+ const restored = readJson(
2866
+ join3(current.root, ".design/revisions", input.restoreRevision, "design-document.json")
2867
+ );
2868
+ if (restored.layout === void 0) delete document2.layout;
2869
+ else document2.layout = structuredClone(restored.layout);
2870
+ } else {
2871
+ if (!input.boards || typeof input.boards !== "object" || Array.isArray(input.boards))
2872
+ throw new Error("Design layout boards must be an object of exact board keys.");
2873
+ const boards = { ...document2.layout?.boards };
2874
+ for (const [key, point] of Object.entries(input.boards)) {
2875
+ if (!current.entries.some(
2876
+ (entry) => `${entry.screenId}/${entry.frameId}/${entry.variantId}` === key
2877
+ ))
2878
+ throw new Error(`Unknown exact design board key ${key}.`);
2879
+ if (point === null) delete boards[key];
2880
+ else {
2881
+ 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)
2882
+ throw new Error(
2883
+ `Design board ${key} requires finite x and y coordinates within \xB110000000.`
2884
+ );
2885
+ boards[key] = { ...boards[key], x: point.x, y: point.y };
2886
+ }
2887
+ }
2888
+ document2.layout = { ...document2.layout, boards };
2889
+ if (!Object.keys(boards).length) delete document2.layout.boards;
2890
+ if (!Object.keys(document2.layout).length) delete document2.layout;
2891
+ }
2892
+ assertDesignDocument(document2);
2893
+ const indent = previous.match(/^([\t ]+)\S/mu)?.[1] ?? "";
2894
+ const formatted = indent ? JSON.stringify(document2, null, " ").replace(
2895
+ /^\t+/gmu,
2896
+ (tabs) => indent.repeat(tabs.length)
2897
+ ) : JSON.stringify(document2);
2898
+ const written = `${formatted}${previous.endsWith("\n") ? "\n" : ""}`;
2899
+ atomicBytes(file, written, mode);
2900
+ try {
2901
+ const result = await render();
2902
+ return { revision: result.revision };
2903
+ } catch (error) {
2904
+ if (hash(readFileSync6(file)) !== hash(written))
2905
+ throw Object.assign(
2906
+ new Error(
2907
+ `The authored document ${file} changed during the save. Its newer contents were preserved; reload before saving its layout.`,
2908
+ { cause: error }
2909
+ ),
2910
+ { statusCode: 409 }
2911
+ );
2912
+ atomicBytes(file, previous, mode);
2913
+ throw error;
2914
+ }
2915
+ });
2916
+ }
2917
+
2532
2918
  export {
2533
2919
  mintCapabilityToken,
2534
2920
  isCapabilityToken,
@@ -2536,11 +2922,16 @@ export {
2536
2922
  prepareArtifactDocument,
2537
2923
  createArtifactBridgeNonce,
2538
2924
  renderArtifactParentRuntime,
2925
+ matchesDesignFrame,
2539
2926
  readRuntimeAsset,
2540
2927
  renderDesignStudio,
2928
+ saveDesignLayout,
2929
+ saveDesignViewContext,
2930
+ readDesignViewContext,
2541
2931
  inspectDesignDocument,
2542
2932
  prepareDesignDocument,
2543
2933
  designRendererRevision,
2544
2934
  standaloneDesignHtml,
2545
- renderDesignDocument
2935
+ renderDesignDocument,
2936
+ withDesignRenderLock
2546
2937
  };