openplanr 3.3.0 → 3.5.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 (493) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/cli/commands/artifact-design-share.d.ts +9 -0
  3. package/dist/cli/commands/artifact-design-share.d.ts.map +1 -0
  4. package/dist/cli/commands/artifact-design-share.js +200 -0
  5. package/dist/cli/commands/artifact-design-share.js.map +1 -0
  6. package/dist/cli/commands/artifact.d.ts.map +1 -1
  7. package/dist/cli/commands/artifact.js +5 -18
  8. package/dist/cli/commands/artifact.js.map +1 -1
  9. package/dist/cli/commands/design.d.ts +3 -0
  10. package/dist/cli/commands/design.d.ts.map +1 -0
  11. package/dist/cli/commands/design.js +137 -0
  12. package/dist/cli/commands/design.js.map +1 -0
  13. package/dist/cli/commands/groups/operations.d.ts.map +1 -1
  14. package/dist/cli/commands/groups/operations.js +2 -0
  15. package/dist/cli/commands/groups/operations.js.map +1 -1
  16. package/dist/cli/commands/ship.d.ts.map +1 -1
  17. package/dist/cli/commands/ship.js +2 -0
  18. package/dist/cli/commands/ship.js.map +1 -1
  19. package/dist/dashboard/.vite/manifest.json +2 -2
  20. package/dist/dashboard/assets/index-B-l_941W.js +75 -0
  21. package/dist/dashboard/assets/index-B-l_941W.js.map +1 -0
  22. package/dist/dashboard/assets/index-Cv4Vwhuw.css +2 -0
  23. package/dist/dashboard/dashboard-manifest.json +14 -14
  24. package/dist/dashboard/index.html +2 -2
  25. package/dist/services/design-artifact-service.d.ts +42 -1
  26. package/dist/services/design-artifact-service.d.ts.map +1 -1
  27. package/dist/services/design-artifact-service.js +198 -19
  28. package/dist/services/design-artifact-service.js.map +1 -1
  29. package/dist/services/runtime-manager/runtime-package.js +1 -1
  30. package/dist/services/runtime-manager/runtime-package.js.map +1 -1
  31. package/dist/services/ship-checks/contract.d.ts +3 -1
  32. package/dist/services/ship-checks/contract.d.ts.map +1 -1
  33. package/dist/services/ship-checks/contract.js +1 -1
  34. package/dist/services/ship-checks/contract.js.map +1 -1
  35. package/dist/services/ship-checks/discover.d.ts.map +1 -1
  36. package/dist/services/ship-checks/discover.js +2 -1
  37. package/dist/services/ship-checks/discover.js.map +1 -1
  38. package/dist/services/ship-checks/package-contents.d.ts +4 -0
  39. package/dist/services/ship-checks/package-contents.d.ts.map +1 -0
  40. package/dist/services/ship-checks/package-contents.js +91 -0
  41. package/dist/services/ship-checks/package-contents.js.map +1 -0
  42. package/dist/services/ship-checks/packages.d.ts +2 -0
  43. package/dist/services/ship-checks/packages.d.ts.map +1 -1
  44. package/dist/services/ship-checks/packages.js +4 -0
  45. package/dist/services/ship-checks/packages.js.map +1 -1
  46. package/dist/services/ship-checks/scope.js +2 -1
  47. package/dist/services/ship-checks/scope.js.map +1 -1
  48. package/dist/utils/splice-managed-block.js +1 -1
  49. package/dist/utils/splice-managed-block.js.map +1 -1
  50. package/docs/CLI.md +67 -1
  51. package/lib/host-packages/adapter-registry.json +5 -5
  52. package/lib/host-packages/capability-map.json +1 -1
  53. package/lib/host-packages/claude/.claude-plugin/marketplace.json +3 -3
  54. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +6 -6
  55. package/lib/host-packages/claude/openplanr/.openplanr-content.json +57 -429
  56. package/lib/host-packages/claude/openplanr/README.md +16 -16
  57. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/task-context-resolution.md +4 -4
  58. package/lib/host-packages/claude/openplanr/skills/artifact/references/design-sharing.md +2 -2
  59. package/lib/host-packages/claude/openplanr/skills/delegate/SKILL.md +2 -1
  60. package/lib/host-packages/claude/openplanr/skills/delegate/references/integration-review.md +26 -20
  61. package/lib/host-packages/claude/openplanr/skills/delegate/references/operator-guide.md +25 -1
  62. package/lib/host-packages/claude/openplanr/skills/delegate/references/run-handoff.md +2 -2
  63. package/lib/host-packages/claude/openplanr/skills/delegate/references/worktree-custody.md +17 -9
  64. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/claude.mjs +15 -3
  65. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/codex.mjs +38 -2
  66. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/native.mjs +5 -0
  67. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/custody.mjs +217 -10
  68. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/handoff.mjs +1080 -0
  69. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integrate.mjs +96 -201
  70. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integration-files.mjs +3 -382
  71. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/presentation.mjs +29 -12
  72. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-contract.mjs +11 -0
  73. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-execution.mjs +1 -1
  74. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-lifecycle.mjs +14 -10
  75. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-preparation.mjs +4 -0
  76. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-record.mjs +2 -2
  77. package/lib/host-packages/claude/openplanr/skills/design/SKILL.md +23 -12
  78. package/lib/host-packages/claude/openplanr/skills/design/references/design-system.md +2 -2
  79. package/lib/host-packages/claude/openplanr/skills/design/references/generation.md +3 -3
  80. package/lib/host-packages/claude/openplanr/skills/design/references/hosted-canvas.md +6 -3
  81. package/lib/host-packages/claude/openplanr/skills/design/references/review.md +6 -6
  82. package/lib/host-packages/claude/openplanr/skills/design/references/team-review.md +3 -4
  83. package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +78 -32
  84. package/lib/host-packages/claude/openplanr/skills/design-loop/SKILL.md +15 -7
  85. package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-system.md +2 -2
  86. package/lib/host-packages/claude/openplanr/skills/design-loop/references/generation.md +3 -3
  87. package/lib/host-packages/claude/openplanr/skills/design-loop/references/review.md +6 -6
  88. package/lib/host-packages/claude/openplanr/skills/design-loop/references/team-review.md +3 -4
  89. package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +78 -32
  90. package/lib/host-packages/claude/openplanr/skills/design-review/SKILL.md +25 -5
  91. package/lib/host-packages/claude/openplanr/skills/design-review/references/design-system.md +2 -2
  92. package/lib/host-packages/claude/openplanr/skills/design-review/references/generation.md +3 -3
  93. package/lib/host-packages/claude/openplanr/skills/design-review/references/review.md +6 -6
  94. package/lib/host-packages/claude/openplanr/skills/design-review/references/team-review.md +3 -4
  95. package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +78 -32
  96. package/lib/host-packages/claude/openplanr/skills/investigate/SKILL.md +1 -0
  97. package/lib/host-packages/claude/openplanr/skills/investigate/references/fail-first.md +40 -0
  98. package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +7 -3
  99. package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +22 -10
  100. package/lib/host-packages/claude/openplanr/skills/ship/references/fail-first.md +40 -0
  101. package/lib/host-packages/claude/openplanr/skills/ship/references/result-contract.md +7 -3
  102. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +55 -427
  103. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  104. package/lib/host-packages/cursor/openplanr/rules/planr-artifact/references/design-sharing.md +2 -2
  105. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/integration-review.md +26 -20
  106. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/operator-guide.md +25 -1
  107. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/run-handoff.md +2 -2
  108. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/worktree-custody.md +17 -9
  109. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/claude.mjs +15 -3
  110. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/codex.mjs +38 -2
  111. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/native.mjs +5 -0
  112. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/custody.mjs +217 -10
  113. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/handoff.mjs +1080 -0
  114. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integrate.mjs +96 -201
  115. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integration-files.mjs +3 -382
  116. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/presentation.mjs +29 -12
  117. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-contract.mjs +11 -0
  118. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-execution.mjs +1 -1
  119. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-lifecycle.mjs +14 -10
  120. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-preparation.mjs +4 -0
  121. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-record.mjs +2 -2
  122. package/lib/host-packages/cursor/openplanr/rules/planr-delegate.mdc +2 -1
  123. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-system.md +2 -2
  124. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/generation.md +3 -3
  125. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/hosted-canvas.md +6 -3
  126. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/review.md +6 -6
  127. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/team-review.md +3 -4
  128. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +78 -32
  129. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-system.md +2 -2
  130. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/generation.md +3 -3
  131. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/review.md +6 -6
  132. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/team-review.md +3 -4
  133. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +78 -32
  134. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop.mdc +15 -7
  135. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-system.md +2 -2
  136. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/generation.md +3 -3
  137. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/review.md +6 -6
  138. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/team-review.md +3 -4
  139. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +78 -32
  140. package/lib/host-packages/cursor/openplanr/rules/planr-design-review.mdc +25 -5
  141. package/lib/host-packages/cursor/openplanr/rules/planr-design.mdc +23 -12
  142. package/lib/host-packages/cursor/openplanr/rules/planr-investigate/references/fail-first.md +40 -0
  143. package/lib/host-packages/cursor/openplanr/rules/planr-investigate.mdc +1 -0
  144. package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +7 -3
  145. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/fail-first.md +40 -0
  146. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/result-contract.md +7 -3
  147. package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +22 -10
  148. package/lib/host-packages/openai/.claude-plugin/marketplace.json +3 -3
  149. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +2 -2
  150. package/lib/host-packages/openai/openplanr/.openplanr-content.json +62 -434
  151. package/lib/host-packages/openai/openplanr/skills/artifact/references/design-sharing.md +2 -2
  152. package/lib/host-packages/openai/openplanr/skills/delegate/SKILL.md +2 -1
  153. package/lib/host-packages/openai/openplanr/skills/delegate/openplanr.skill.json +1 -1
  154. package/lib/host-packages/openai/openplanr/skills/delegate/references/integration-review.md +26 -20
  155. package/lib/host-packages/openai/openplanr/skills/delegate/references/operator-guide.md +25 -1
  156. package/lib/host-packages/openai/openplanr/skills/delegate/references/run-handoff.md +2 -2
  157. package/lib/host-packages/openai/openplanr/skills/delegate/references/worktree-custody.md +17 -9
  158. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/claude.mjs +15 -3
  159. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/codex.mjs +38 -2
  160. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/native.mjs +5 -0
  161. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/custody.mjs +217 -10
  162. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/handoff.mjs +1080 -0
  163. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integrate.mjs +96 -201
  164. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integration-files.mjs +3 -382
  165. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/presentation.mjs +29 -12
  166. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-contract.mjs +11 -0
  167. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-execution.mjs +1 -1
  168. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-lifecycle.mjs +14 -10
  169. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-preparation.mjs +4 -0
  170. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-record.mjs +2 -2
  171. package/lib/host-packages/openai/openplanr/skills/design/SKILL.md +23 -12
  172. package/lib/host-packages/openai/openplanr/skills/design/openplanr.skill.json +0 -11
  173. package/lib/host-packages/openai/openplanr/skills/design/references/design-system.md +2 -2
  174. package/lib/host-packages/openai/openplanr/skills/design/references/generation.md +3 -3
  175. package/lib/host-packages/openai/openplanr/skills/design/references/hosted-canvas.md +6 -3
  176. package/lib/host-packages/openai/openplanr/skills/design/references/review.md +6 -6
  177. package/lib/host-packages/openai/openplanr/skills/design/references/team-review.md +3 -4
  178. package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +78 -32
  179. package/lib/host-packages/openai/openplanr/skills/design-loop/SKILL.md +15 -7
  180. package/lib/host-packages/openai/openplanr/skills/design-loop/openplanr.skill.json +0 -11
  181. package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-system.md +2 -2
  182. package/lib/host-packages/openai/openplanr/skills/design-loop/references/generation.md +3 -3
  183. package/lib/host-packages/openai/openplanr/skills/design-loop/references/review.md +6 -6
  184. package/lib/host-packages/openai/openplanr/skills/design-loop/references/team-review.md +3 -4
  185. package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +78 -32
  186. package/lib/host-packages/openai/openplanr/skills/design-review/SKILL.md +25 -5
  187. package/lib/host-packages/openai/openplanr/skills/design-review/openplanr.skill.json +0 -11
  188. package/lib/host-packages/openai/openplanr/skills/design-review/references/design-system.md +2 -2
  189. package/lib/host-packages/openai/openplanr/skills/design-review/references/generation.md +3 -3
  190. package/lib/host-packages/openai/openplanr/skills/design-review/references/review.md +6 -6
  191. package/lib/host-packages/openai/openplanr/skills/design-review/references/team-review.md +3 -4
  192. package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +78 -32
  193. package/lib/host-packages/openai/openplanr/skills/investigate/SKILL.md +1 -0
  194. package/lib/host-packages/openai/openplanr/skills/investigate/openplanr.skill.json +12 -1
  195. package/lib/host-packages/openai/openplanr/skills/investigate/references/fail-first.md +40 -0
  196. package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +7 -3
  197. package/lib/host-packages/openai/openplanr/skills/plan/openplanr.skill.json +0 -11
  198. package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +22 -10
  199. package/lib/host-packages/openai/openplanr/skills/ship/openplanr.skill.json +12 -1
  200. package/lib/host-packages/openai/openplanr/skills/ship/references/fail-first.md +40 -0
  201. package/lib/host-packages/openai/openplanr/skills/ship/references/result-contract.md +7 -3
  202. package/package.json +8 -8
  203. package/dist/dashboard/assets/index-BU5fzjyz.css +0 -1
  204. package/dist/dashboard/assets/index-B_96uzCl.js +0 -572
  205. package/dist/dashboard/assets/index-B_96uzCl.js.map +0 -1
  206. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-artifact-shell.mjs +0 -1774
  207. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
  208. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
  209. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +0 -2937
  210. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
  211. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-entities.mjs +0 -439
  212. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +0 -1576
  213. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-loopback-server.mjs +0 -359
  214. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
  215. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-parse5-parser.mjs +0 -3970
  216. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-parse5-tokenizer.mjs +0 -3501
  217. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
  218. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review.mjs +0 -3385
  219. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -39
  220. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs +0 -24
  221. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-sandbox-guards.mjs +0 -1102
  222. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
  223. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +0 -1113
  224. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +0 -505
  225. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
  226. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5907
  227. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
  228. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +0 -1430
  229. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -2050
  230. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +0 -2
  231. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +0 -18
  232. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +0 -809
  233. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +0 -5693
  234. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
  235. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
  236. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
  237. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
  238. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
  239. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +0 -124
  240. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +0 -65
  241. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/enhancements.css +0 -388
  242. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/handoff-center.css +0 -81
  243. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.css +0 -1
  244. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +0 -133
  245. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +0 -1159
  246. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +0 -30
  247. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +0 -900
  248. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +0 -2261
  249. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +0 -1595
  250. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +0 -1467
  251. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +0 -1860
  252. 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 +0 -914
  253. 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 +0 -2578
  254. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +0 -582
  255. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +0 -17
  256. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +0 -12
  257. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +0 -285
  258. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +0 -2773
  259. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +0 -134
  260. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +0 -2207
  261. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +0 -16
  262. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +0 -8
  263. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +0 -3883
  264. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +0 -966
  265. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/20-studio-shell.js +0 -520
  266. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +0 -1597
  267. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +0 -311
  268. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +0 -159
  269. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/registries/artifact-theme.json +0 -64
  270. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +0 -90
  271. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +0 -142
  272. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
  273. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  274. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +0 -584
  275. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +0 -191
  276. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +0 -407
  277. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +0 -106
  278. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-handoff-readiness.schema.json +0 -398
  279. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-implementation-handoff.schema.json +0 -518
  280. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-planning-lineage.schema.json +0 -106
  281. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +0 -107
  282. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.14.0/artifact-theme.schema.json +0 -316
  283. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/artifact-envelope.schema.json +0 -408
  284. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/design-review-bundle.schema.json +0 -590
  285. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-document.schema.json +0 -506
  286. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +0 -822
  287. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +0 -346
  288. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
  289. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
  290. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
  291. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
  292. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +0 -5468
  293. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +0 -2844
  294. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -21
  295. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +0 -159
  296. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  297. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integration-transaction.mjs +0 -958
  298. package/lib/host-packages/claude/openplanr/skills/design/scripts/design.mjs +0 -12
  299. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/design.mjs +0 -12
  300. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/design.mjs +0 -12
  301. package/lib/host-packages/claude/openplanr/skills/plan/scripts/design.mjs +0 -12
  302. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integration-transaction.mjs +0 -958
  303. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/design.mjs +0 -12
  304. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/design.mjs +0 -12
  305. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/design.mjs +0 -12
  306. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/design.mjs +0 -12
  307. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-artifact-shell.mjs +0 -1774
  308. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
  309. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
  310. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +0 -2937
  311. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
  312. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-entities.mjs +0 -439
  313. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +0 -1576
  314. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-loopback-server.mjs +0 -359
  315. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
  316. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-parse5-parser.mjs +0 -3970
  317. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-parse5-tokenizer.mjs +0 -3501
  318. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
  319. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review.mjs +0 -3385
  320. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -39
  321. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs +0 -24
  322. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-sandbox-guards.mjs +0 -1102
  323. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
  324. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +0 -1113
  325. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +0 -505
  326. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
  327. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5907
  328. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
  329. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +0 -1430
  330. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -2050
  331. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +0 -2
  332. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +0 -18
  333. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +0 -809
  334. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +0 -5693
  335. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
  336. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
  337. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
  338. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
  339. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
  340. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +0 -124
  341. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +0 -65
  342. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/enhancements.css +0 -388
  343. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/handoff-center.css +0 -81
  344. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.css +0 -1
  345. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +0 -133
  346. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +0 -1159
  347. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +0 -30
  348. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +0 -900
  349. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +0 -2261
  350. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +0 -1595
  351. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +0 -1467
  352. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +0 -1860
  353. 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 +0 -914
  354. 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 +0 -2578
  355. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +0 -582
  356. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +0 -17
  357. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +0 -12
  358. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +0 -285
  359. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +0 -2773
  360. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +0 -134
  361. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +0 -2207
  362. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +0 -16
  363. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +0 -8
  364. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +0 -3883
  365. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +0 -966
  366. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/20-studio-shell.js +0 -520
  367. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +0 -1597
  368. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +0 -311
  369. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +0 -159
  370. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/registries/artifact-theme.json +0 -64
  371. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +0 -90
  372. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +0 -142
  373. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
  374. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  375. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +0 -584
  376. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +0 -191
  377. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +0 -407
  378. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +0 -106
  379. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-handoff-readiness.schema.json +0 -398
  380. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-implementation-handoff.schema.json +0 -518
  381. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-planning-lineage.schema.json +0 -106
  382. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +0 -107
  383. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.14.0/artifact-theme.schema.json +0 -316
  384. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/artifact-envelope.schema.json +0 -408
  385. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/design-review-bundle.schema.json +0 -590
  386. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-document.schema.json +0 -506
  387. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +0 -822
  388. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +0 -346
  389. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
  390. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
  391. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
  392. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
  393. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +0 -5468
  394. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +0 -2844
  395. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -21
  396. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +0 -159
  397. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  398. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-artifact-shell.mjs +0 -1774
  399. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
  400. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
  401. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +0 -2937
  402. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
  403. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-entities.mjs +0 -439
  404. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +0 -1576
  405. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-loopback-server.mjs +0 -359
  406. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
  407. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-parse5-parser.mjs +0 -3970
  408. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-parse5-tokenizer.mjs +0 -3501
  409. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
  410. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review.mjs +0 -3385
  411. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -39
  412. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs +0 -24
  413. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-sandbox-guards.mjs +0 -1102
  414. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
  415. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +0 -1113
  416. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs +0 -505
  417. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
  418. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5907
  419. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
  420. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +0 -1430
  421. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -2050
  422. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +0 -2
  423. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +0 -18
  424. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +0 -809
  425. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +0 -5693
  426. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
  427. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
  428. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
  429. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
  430. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
  431. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +0 -124
  432. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +0 -65
  433. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/enhancements.css +0 -388
  434. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/handoff-center.css +0 -81
  435. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.css +0 -1
  436. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +0 -133
  437. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +0 -1159
  438. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +0 -30
  439. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +0 -900
  440. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +0 -2261
  441. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +0 -1595
  442. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +0 -1467
  443. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +0 -1860
  444. 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 +0 -914
  445. 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 +0 -2578
  446. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +0 -582
  447. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +0 -17
  448. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +0 -12
  449. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +0 -285
  450. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +0 -2773
  451. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +0 -134
  452. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +0 -2207
  453. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +0 -16
  454. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +0 -8
  455. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +0 -3883
  456. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +0 -966
  457. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/20-studio-shell.js +0 -520
  458. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +0 -1597
  459. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +0 -311
  460. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +0 -159
  461. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/registries/artifact-theme.json +0 -64
  462. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +0 -90
  463. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +0 -142
  464. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
  465. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  466. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +0 -584
  467. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +0 -191
  468. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +0 -407
  469. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +0 -106
  470. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-handoff-readiness.schema.json +0 -398
  471. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-implementation-handoff.schema.json +0 -518
  472. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-planning-lineage.schema.json +0 -106
  473. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +0 -107
  474. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.14.0/artifact-theme.schema.json +0 -316
  475. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/artifact-envelope.schema.json +0 -408
  476. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/design-review-bundle.schema.json +0 -590
  477. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-document.schema.json +0 -506
  478. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +0 -822
  479. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +0 -346
  480. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
  481. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
  482. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
  483. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
  484. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +0 -5468
  485. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +0 -2844
  486. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -21
  487. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +0 -159
  488. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  489. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integration-transaction.mjs +0 -958
  490. package/lib/host-packages/openai/openplanr/skills/design/scripts/design.mjs +0 -12
  491. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/design.mjs +0 -12
  492. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/design.mjs +0 -12
  493. package/lib/host-packages/openai/openplanr/skills/plan/scripts/design.mjs +0 -12
@@ -1,2937 +0,0 @@
1
- import {
2
- AA_NORMAL,
3
- contrastRatio,
4
- embedJson,
5
- escapeHtml,
6
- renderArtifactShellDocument,
7
- renderPlanrMark
8
- } from "./design-artifact-shell.mjs";
9
- import {
10
- ARTIFACT_FRAME_GUARD_TEMPLATE,
11
- ARTIFACT_HOST_GUARD_TEMPLATE,
12
- ARTIFACT_WORKER_GUARD_SOURCE
13
- } from "./design-sandbox-guards.mjs";
14
- import {
15
- atomicBytes,
16
- atomicJson,
17
- bundleLocalDocument,
18
- currentDesign,
19
- designSpecPath,
20
- hash,
21
- inspectLocalDocumentBody,
22
- json,
23
- loadReviewContext,
24
- parse,
25
- parseFragment,
26
- readJson,
27
- recoverDesignPublication,
28
- resolveLocalDocumentFile,
29
- reviewDigest,
30
- reviewFingerprints,
31
- serialize
32
- } from "./design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs";
33
- import {
34
- acquireStartLock
35
- } from "./design-loopback-server.mjs";
36
- import {
37
- ARTIFACT_ERROR_CODES,
38
- ARTIFACT_MAX_SOURCES,
39
- ARTIFACT_MAX_VIEWS,
40
- PipelineError,
41
- createSharedArtifactEnvelope,
42
- digestArtifactEnvelope,
43
- resolveArtifactHtml
44
- } from "./design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs";
45
- import {
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";
110
-
111
- // packages/design/lib/design/document.mjs
112
- import { randomUUID } from "node:crypto";
113
- import {
114
- existsSync as existsSync2,
115
- mkdirSync,
116
- readFileSync as readFileSync5,
117
- realpathSync,
118
- renameSync,
119
- rmSync,
120
- writeFileSync
121
- } from "node:fs";
122
- import { dirname, join as join2, resolve as resolve2 } from "node:path";
123
-
124
- // packages/artifact/lib/artifact/bridge.mjs
125
- import { randomBytes as randomBytes2 } from "node:crypto";
126
-
127
- // packages/artifact/lib/artifact/internal/board-token.mjs
128
- import { randomBytes, timingSafeEqual } from "node:crypto";
129
- var BASE64URL_TOKEN_RE = /^[A-Za-z0-9_-]+$/;
130
- function mintCapabilityToken({
131
- bytes = 32,
132
- encoding = "base64url",
133
- randomBytesImpl = randomBytes
134
- } = {}) {
135
- if (!Number.isInteger(bytes) || bytes < 12 || bytes > 64) {
136
- throw new RangeError("Capability tokens require 12 through 64 random bytes.");
137
- }
138
- if (!["base64url", "hex"].includes(encoding)) {
139
- throw new TypeError(`Unsupported capability token encoding: ${String(encoding)}`);
140
- }
141
- const value = randomBytesImpl(bytes);
142
- if (!Buffer.isBuffer(value) || value.byteLength !== bytes) {
143
- throw new TypeError("Capability token random source returned the wrong byte length.");
144
- }
145
- return value.toString(encoding);
146
- }
147
- function isCapabilityToken(value, { bytes = 32, encoding = "base64url" } = {}) {
148
- if (typeof value !== "string") return false;
149
- if (encoding === "hex") return value.length === bytes * 2 && /^[a-f0-9]+$/.test(value);
150
- if (encoding !== "base64url" || !BASE64URL_TOKEN_RE.test(value)) return false;
151
- try {
152
- return Buffer.from(value, "base64url").byteLength === bytes && Buffer.from(value, "base64url").toString("base64url") === value;
153
- } catch {
154
- return false;
155
- }
156
- }
157
- function timingSafeTokenEqual(left, right) {
158
- if (typeof left !== "string" || typeof right !== "string") return false;
159
- const leftBytes = Buffer.from(left, "utf8");
160
- const rightBytes = Buffer.from(right, "utf8");
161
- return leftBytes.byteLength === rightBytes.byteLength && timingSafeEqual(leftBytes, rightBytes);
162
- }
163
-
164
- // packages/artifact/lib/artifact/ui/bridge-tools.mjs
165
- var ARTIFACT_THUMBNAIL_MAX_EDGE = 320;
166
- var ARTIFACT_THUMBNAIL_MAX_DATA_URL = 256 * 1024;
167
- var ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA = 1e3;
168
- var ARTIFACT_VIEWPORT_PAN_MAX_DELTA = 1e3;
169
- function normalizeArtifactViewportZoom(value, viewport) {
170
- if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
171
- return null;
172
- const keys = ["x", "y", "deltaY"];
173
- if (Object.keys(value).length !== keys.length || !Object.keys(value).every((key) => keys.includes(key)))
174
- return null;
175
- const descriptors = Object.getOwnPropertyDescriptors(value);
176
- if (!keys.every(
177
- (key) => Object.hasOwn(descriptors[key], "value") && typeof descriptors[key].value === "number" && Number.isFinite(descriptors[key].value)
178
- ))
179
- return null;
180
- const { x, y, deltaY } = value;
181
- if (!Number.isFinite(viewport?.width) || !Number.isFinite(viewport?.height) || viewport.width < 1 || viewport.height < 1 || viewport.width > 16384 || viewport.height > 16384 || x < 0 || y < 0 || x > viewport.width || y > viewport.height || deltaY === 0 || Math.abs(deltaY) > ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA)
182
- return null;
183
- return Object.freeze({ x, y, deltaY });
184
- }
185
- function normalizeArtifactViewportPan(value) {
186
- if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
187
- return null;
188
- const keys = ["deltaX", "deltaY"];
189
- if (Object.keys(value).length !== keys.length || !Object.keys(value).every((key) => keys.includes(key)))
190
- return null;
191
- const descriptors = Object.getOwnPropertyDescriptors(value);
192
- if (!keys.every(
193
- (key) => Object.hasOwn(descriptors[key], "value") && typeof descriptors[key].value === "number" && Number.isFinite(descriptors[key].value)
194
- ))
195
- return null;
196
- const { deltaX, deltaY } = value;
197
- if (!deltaX && !deltaY || Math.abs(deltaX) > ARTIFACT_VIEWPORT_PAN_MAX_DELTA || Math.abs(deltaY) > ARTIFACT_VIEWPORT_PAN_MAX_DELTA)
198
- return null;
199
- return Object.freeze({ deltaX, deltaY });
200
- }
201
- function createArtifactViewportGestures(window2, emit) {
202
- const add = window2.addEventListener.bind(window2), remove = window2.removeEventListener.bind(window2);
203
- const schedule = window2.setTimeout.bind(window2), cancel = window2.clearTimeout.bind(window2);
204
- const prevent = window2.Event.prototype.preventDefault, stop = window2.Event.prototype.stopImmediatePropagation;
205
- const getter = (prototype, name) => Object.getOwnPropertyDescriptor(prototype, name)?.get;
206
- const native = {
207
- x: getter(window2.MouseEvent.prototype, "clientX"),
208
- y: getter(window2.MouseEvent.prototype, "clientY"),
209
- ctrl: getter(window2.MouseEvent.prototype, "ctrlKey"),
210
- meta: getter(window2.MouseEvent.prototype, "metaKey"),
211
- shift: getter(window2.MouseEvent.prototype, "shiftKey"),
212
- deltaX: getter(window2.WheelEvent.prototype, "deltaX"),
213
- deltaY: getter(window2.WheelEvent.prototype, "deltaY"),
214
- mode: getter(window2.WheelEvent.prototype, "deltaMode")
215
- };
216
- let enabled = false, disposed = false, timer = 0, pending = null, pendingType = "";
217
- let gestureScale = 1;
218
- const clear = () => {
219
- gestureScale = 1;
220
- if (timer) cancel(timer);
221
- timer = 0;
222
- pending = null;
223
- pendingType = "";
224
- };
225
- const flush = () => {
226
- timer = 0;
227
- const value = pending;
228
- const type = pendingType;
229
- pending = null;
230
- pendingType = "";
231
- if (enabled && !disposed && value) emit(type, value);
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
- };
256
- const wheel = (event) => {
257
- if (!enabled || disposed || !event.isTrusted || !event.cancelable) return;
258
- let x, y, deltaX, deltaY, mode, zooming, shift;
259
- try {
260
- x = native.x.call(event);
261
- y = native.y.call(event);
262
- mode = native.mode.call(event);
263
- zooming = native.ctrl.call(event) || native.meta.call(event);
264
- shift = native.shift.call(event);
265
- deltaX = native.deltaX.call(event);
266
- deltaY = native.deltaY.call(event);
267
- } catch {
268
- return;
269
- }
270
- if (!Number.isFinite(deltaX) || !Number.isFinite(deltaY)) return;
271
- const scaleX = mode === 1 ? 16 : mode === 2 ? window2.innerWidth : 1;
272
- const scaleY = mode === 1 ? 16 : mode === 2 ? window2.innerHeight : 1;
273
- deltaX *= scaleX;
274
- deltaY *= scaleY;
275
- let type;
276
- let value;
277
- if (zooming) {
278
- type = "viewport.zoom";
279
- deltaY = Math.max(
280
- -ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA,
281
- Math.min(ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA, deltaY)
282
- );
283
- value = normalizeArtifactViewportZoom(
284
- { x, y, deltaY },
285
- { width: window2.innerWidth, height: window2.innerHeight }
286
- );
287
- } else {
288
- type = "viewport.pan";
289
- if (shift && !deltaX) {
290
- deltaX = deltaY;
291
- deltaY = 0;
292
- }
293
- deltaX = Math.max(
294
- -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
295
- Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, deltaX)
296
- );
297
- deltaY = Math.max(
298
- -ARTIFACT_VIEWPORT_PAN_MAX_DELTA,
299
- Math.min(ARTIFACT_VIEWPORT_PAN_MAX_DELTA, deltaY)
300
- );
301
- value = normalizeArtifactViewportPan({ deltaX, deltaY });
302
- }
303
- if (!value) return;
304
- prevent.call(event);
305
- stop.call(event);
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;
334
- };
335
- const destroy = () => {
336
- disposed = true;
337
- enabled = false;
338
- clear();
339
- remove("wheel", wheel, true);
340
- remove("gesturestart", gestureStart, true);
341
- remove("gesturechange", gestureChange, true);
342
- remove("gestureend", gestureEnd, true);
343
- remove("pagehide", destroy);
344
- };
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 });
349
- add("pagehide", destroy, { once: true });
350
- return Object.freeze({
351
- setEnabled(value) {
352
- if (disposed || typeof value !== "boolean") return false;
353
- enabled = value;
354
- if (!value) clear();
355
- return true;
356
- },
357
- destroy
358
- });
359
- }
360
- var ARTIFACT_BRIDGE_OPERATION_TIMEOUTS = Object.freeze({
361
- "inspect.point": 1200,
362
- "inspect.anchor": 1200,
363
- "thumbnail.request": 3e3,
364
- "export.request": 8e3
365
- });
366
- var ARTIFACT_INSPECTION_PROPERTIES = Object.freeze([
367
- "font-family",
368
- "font-size",
369
- "font-weight",
370
- "line-height",
371
- "letter-spacing",
372
- "color",
373
- "background-color",
374
- "display",
375
- "position",
376
- "gap",
377
- "padding-top",
378
- "padding-right",
379
- "padding-bottom",
380
- "padding-left",
381
- "margin-top",
382
- "margin-right",
383
- "margin-bottom",
384
- "margin-left",
385
- "border-radius",
386
- "border-width",
387
- "border-color",
388
- "box-sizing"
389
- ]);
390
- function normalizeArtifactInspection(value, viewport) {
391
- const plain = (entry) => entry && typeof entry === "object" && !Array.isArray(entry) && [Object.prototype, null].includes(Object.getPrototypeOf(entry));
392
- const own = (entry, key) => {
393
- const descriptor = plain(entry) ? Object.getOwnPropertyDescriptor(entry, key) : null;
394
- return descriptor && Object.hasOwn(descriptor, "value") ? descriptor.value : void 0;
395
- };
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"]))
398
- return null;
399
- const tagName = own(value, "tagName");
400
- const anchor = own(value, "anchor");
401
- const rect = own(value, "rect");
402
- const size = own(value, "viewport");
403
- const styles = own(value, "styles");
404
- const accessibility = own(value, "accessibility");
405
- if (typeof tagName !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(tagName)) return null;
406
- if (!exact2(size, ["width", "height"]) || !exact2(rect, ["x", "y", "width", "height"])) return null;
407
- if (!["width", "height"].every(
408
- (key) => Number.isInteger(own(size, key)) && own(size, key) >= 1 && own(size, key) <= 16384 && own(size, key) === viewport?.[key]
409
- ))
410
- return null;
411
- if (!["x", "y", "width", "height"].every(
412
- (key) => typeof own(rect, key) === "number" && Number.isFinite(own(rect, key)) && own(rect, key) >= 0
413
- ))
414
- return null;
415
- if (rect.x + rect.width > size.width || rect.y + rect.height > size.height) return null;
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))))
417
- return null;
418
- if (!exact2(styles, ARTIFACT_INSPECTION_PROPERTIES) || !ARTIFACT_INSPECTION_PROPERTIES.every((key) => {
419
- const text = own(styles, key);
420
- return typeof text === "string" && text.length <= 256 && !/[\u0000-\u001f\u007f]/.test(text) && !/(?:url\s*\(|https?:|file:)/i.test(text);
421
- }))
422
- return null;
423
- if (!exact2(accessibility, ["role", "ariaLabel", "alt", "tabIndex", "disabled"]) || !["role", "ariaLabel", "alt"].every(
424
- (key) => typeof own(accessibility, key) === "string" && own(accessibility, key).length <= 256 && !/[\u0000-\u001f\u007f]/.test(own(accessibility, key))
425
- ) || !Number.isInteger(own(accessibility, "tabIndex")) || accessibility.tabIndex < -1 || accessibility.tabIndex > 32767 || typeof own(accessibility, "disabled") !== "boolean")
426
- return null;
427
- return Object.freeze({
428
- tagName,
429
- anchor: anchor === null ? null : Object.freeze({ ...anchor }),
430
- rect: Object.freeze({ ...rect }),
431
- viewport: Object.freeze({ ...size }),
432
- styles: Object.freeze({ ...styles }),
433
- accessibility: Object.freeze({ ...accessibility })
434
- });
435
- }
436
- function normalizeArtifactThumbnail(value) {
437
- if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length !== 4 || !Object.keys(value).every((key) => ["dataUrl", "width", "height", "label"].includes(key)) || !Object.values(Object.getOwnPropertyDescriptors(value)).every(
438
- (descriptor) => Object.hasOwn(descriptor, "value")
439
- ))
440
- return null;
441
- const { dataUrl, width, height, label } = value;
442
- if (typeof dataUrl !== "string" || dataUrl.length > ARTIFACT_THUMBNAIL_MAX_DATA_URL || !/^data:image\/png;base64,[A-Za-z0-9+/]+=*$/.test(dataUrl) || !Number.isInteger(width) || !Number.isInteger(height) || width < 1 || height < 1 || width > ARTIFACT_THUMBNAIL_MAX_EDGE || height > ARTIFACT_THUMBNAIL_MAX_EDGE || typeof label !== "string" || label.length < 1 || label.length > 128)
443
- return null;
444
- return Object.freeze({ dataUrl, width, height, label });
445
- }
446
- function normalizeArtifactBridgeToolResult(requestType, message, viewport) {
447
- const base = ["channel", "schemaVersion", "type", "nonce", "artifactId", "requestId"];
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(
449
- (descriptor) => Object.hasOwn(descriptor, "value")
450
- );
451
- if (requestType === "inspect.point" || requestType === "inspect.anchor") {
452
- if (exact2(base) && message.type === "inspect.miss") return { valid: true, value: null };
453
- if (!exact2([...base, "inspection"]) || message.type !== "inspect.result")
454
- return { valid: false };
455
- const value = normalizeArtifactInspection(message.inspection, viewport);
456
- return value ? { valid: true, value } : { valid: false };
457
- }
458
- if (requestType === "thumbnail.request") {
459
- if (exact2([...base, "reason"]) && message.type === "thumbnail.error" && typeof message.reason === "string" && message.reason.length <= 256)
460
- return { valid: true, value: null };
461
- if (!exact2([...base, "dataUrl", "width", "height", "label"]) || message.type !== "thumbnail.result")
462
- return { valid: false };
463
- const value = normalizeArtifactThumbnail({
464
- dataUrl: message.dataUrl,
465
- width: message.width,
466
- height: message.height,
467
- label: message.label
468
- });
469
- return value ? { valid: true, value } : { valid: false };
470
- }
471
- return { valid: false };
472
- }
473
- function createArtifactBridgeTools(document2, window2) {
474
- const fromPoint = document2.elementFromPoint.bind(document2);
475
- const query = document2.querySelectorAll.bind(document2);
476
- const attr = window2.Element.prototype.getAttribute;
477
- const closest = window2.Element.prototype.closest;
478
- const bounds = window2.Element.prototype.getBoundingClientRect;
479
- const computed = window2.getComputedStyle.bind(window2);
480
- const cloneNode = window2.Node.prototype.cloneNode;
481
- const append = window2.Node.prototype.appendChild;
482
- const create = document2.createElement.bind(document2);
483
- const setAttribute = window2.Element.prototype.setAttribute;
484
- const serialize2 = window2.XMLSerializer.prototype.serializeToString;
485
- const Image = window2.Image;
486
- const Serializer = window2.XMLSerializer;
487
- const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
488
- const get = (element, key) => attr.call(element, key);
489
- const validId = (id) => typeof id === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/.test(id);
490
- const screen = (element) => {
491
- const owner = closest.call(element, "[data-planr-screen]");
492
- const value = owner && get(owner, "data-planr-screen");
493
- return typeof value === "string" && /^[^\u0000-\u001f\u007f]{1,128}$/.test(value) ? value : void 0;
494
- };
495
- const clean = (value) => String(value || "").replace(/[\u0000-\u001f\u007f]/g, " ").slice(0, 256);
496
- const inspectElement = (element) => {
497
- if (!(element instanceof window2.Element)) return null;
498
- const tagName = element.localName;
499
- if (typeof tagName !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(tagName)) return null;
500
- const rect = bounds.call(element), width = window2.innerWidth, height = window2.innerHeight;
501
- const x = clamp(rect.left, 0, width), y = clamp(rect.top, 0, height);
502
- const owner = closest.call(element, "[data-planr-id]");
503
- const planrId = owner && get(owner, "data-planr-id");
504
- const anchorScreen = owner && screen(owner);
505
- const style = computed(element);
506
- const styles = Object.fromEntries(
507
- ARTIFACT_INSPECTION_PROPERTIES.map((key) => {
508
- const value = clean(style.getPropertyValue(key));
509
- return [key, /(?:url\s*\(|https?:|file:)/i.test(value) ? "" : value];
510
- })
511
- );
512
- return {
513
- tagName,
514
- anchor: validId(planrId) ? { planrId, ...anchorScreen ? { screen: anchorScreen } : {} } : null,
515
- rect: {
516
- x,
517
- y,
518
- width: Math.max(0, clamp(rect.right, 0, width) - x),
519
- height: Math.max(0, clamp(rect.bottom, 0, height) - y)
520
- },
521
- viewport: { width, height },
522
- styles,
523
- accessibility: {
524
- role: clean(get(element, "role")),
525
- ariaLabel: clean(get(element, "aria-label")),
526
- alt: clean(get(element, "alt")),
527
- tabIndex: clamp(Number(element.tabIndex) || 0, -1, 32767),
528
- disabled: get(element, "disabled") !== null || get(element, "aria-disabled") === "true"
529
- }
530
- };
531
- };
532
- let capturing = false;
533
- return Object.freeze({
534
- inspectAt(x, y) {
535
- if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || y < 0 || x > window2.innerWidth || y > window2.innerHeight)
536
- return null;
537
- return inspectElement(fromPoint(x, y));
538
- },
539
- inspect(anchor) {
540
- if (!anchor || !validId(anchor.planrId) || Object.keys(anchor).some((key) => !["planrId", "screen"].includes(key)) || anchor.screen !== void 0 && (typeof anchor.screen !== "string" || !/^[^\u0000-\u001f\u007f]{1,128}$/.test(anchor.screen)))
541
- return null;
542
- let count = 0;
543
- for (const element of query("[data-planr-id]")) {
544
- if (++count > 1e4) return null;
545
- if (get(element, "data-planr-id") === anchor.planrId && (anchor.screen === void 0 || screen(element) === anchor.screen))
546
- return inspectElement(element);
547
- }
548
- return null;
549
- },
550
- async thumbnail() {
551
- if (capturing) throw new Error("Thumbnail capture is busy.");
552
- capturing = true;
553
- let image;
554
- try {
555
- const deadline = Date.now() + 2400;
556
- const width = window2.innerWidth, height = window2.innerHeight;
557
- if (!Number.isInteger(width) || !Number.isInteger(height) || width < 1 || height < 1 || width > 16384 || height > 16384)
558
- throw new Error("Thumbnail dimensions are unavailable.");
559
- let count = 0, contentSize = 0;
560
- const cloneStyled = (source) => {
561
- if (++count > 4e3 || Date.now() > deadline)
562
- throw new Error("Thumbnail capture limit exceeded.");
563
- if (source.nodeType === 8 || source.nodeType === 1 && ["SCRIPT", "STYLE", "LINK", "META"].includes(source.tagName))
564
- return document2.createTextNode("");
565
- const target = cloneNode.call(source, false);
566
- if (source.nodeType === 1) {
567
- const styles = computed(source);
568
- let css = "";
569
- for (let index = 0; index < styles.length; index++) {
570
- if (index >= 2048 || Date.now() > deadline)
571
- throw new Error("Thumbnail style limit exceeded.");
572
- const name = styles[index];
573
- if (!name.startsWith("--")) css += name + ":" + styles.getPropertyValue(name) + ";";
574
- }
575
- contentSize += css.length + (source.textContent?.length || 0);
576
- if (contentSize > 4 * 1024 * 1024) throw new Error("Thumbnail markup limit exceeded.");
577
- setAttribute.call(target, "style", css + "animation:none;transition:none;");
578
- for (const attribute of [...target.attributes])
579
- if (/^on/i.test(attribute.name) || ["value", "srcdoc"].includes(attribute.name))
580
- target.removeAttribute(attribute.name);
581
- if (source.tagName === "INPUT" || source.tagName === "TEXTAREA") {
582
- target.value = "";
583
- target.textContent = "";
584
- }
585
- if (source.tagName === "CANVAS") {
586
- try {
587
- const replacement = create("img");
588
- replacement.src = source.toDataURL("image/png");
589
- setAttribute.call(replacement, "style", css);
590
- return replacement;
591
- } catch {
592
- }
593
- }
594
- }
595
- if (source.nodeType !== 1 || source.tagName !== "TEXTAREA")
596
- for (let child = source.firstChild; child; child = child.nextSibling)
597
- append.call(target, cloneStyled(child));
598
- return target;
599
- };
600
- const clone = cloneStyled(document2.documentElement);
601
- setAttribute.call(clone, "xmlns", "http://www.w3.org/1999/xhtml");
602
- const markup = serialize2.call(new Serializer(), clone);
603
- if (markup.length > 4 * 1024 * 1024) throw new Error("Thumbnail markup limit exceeded.");
604
- const scale = Math.min(1, ARTIFACT_THUMBNAIL_MAX_EDGE / Math.max(width, height));
605
- const outputWidth = Math.max(1, Math.round(width * scale)), outputHeight = Math.max(1, Math.round(height * scale));
606
- const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' + outputWidth + '" height="' + outputHeight + '" viewBox="0 0 ' + width + " " + height + '"><foreignObject width="' + width + '" height="' + height + '">' + markup + "</foreignObject></svg>";
607
- image = new Image();
608
- await new Promise((resolve3, reject) => {
609
- const timer = setTimeout(
610
- () => reject(new Error("Thumbnail capture timed out.")),
611
- Math.max(1, deadline - Date.now())
612
- );
613
- image.onload = () => {
614
- clearTimeout(timer);
615
- resolve3();
616
- };
617
- image.onerror = () => {
618
- clearTimeout(timer);
619
- reject(new Error("Thumbnail rendering unavailable."));
620
- };
621
- image.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
622
- });
623
- const canvas = create("canvas");
624
- canvas.width = outputWidth;
625
- canvas.height = outputHeight;
626
- canvas.getContext("2d").drawImage(image, 0, 0, outputWidth, outputHeight);
627
- const dataUrl = canvas.toDataURL("image/png");
628
- if (dataUrl.length > ARTIFACT_THUMBNAIL_MAX_DATA_URL)
629
- throw new Error("Thumbnail output limit exceeded.");
630
- return { dataUrl, width: outputWidth, height: outputHeight, label: "screen" };
631
- } finally {
632
- if (image) {
633
- image.onload = null;
634
- image.onerror = null;
635
- }
636
- capturing = false;
637
- }
638
- }
639
- });
640
- }
641
- function renderArtifactBridgeToolsSource() {
642
- return `const ARTIFACT_THUMBNAIL_MAX_EDGE=${ARTIFACT_THUMBNAIL_MAX_EDGE};
643
- const ARTIFACT_THUMBNAIL_MAX_DATA_URL=${ARTIFACT_THUMBNAIL_MAX_DATA_URL};
644
- const ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA=${ARTIFACT_VIEWPORT_ZOOM_MAX_DELTA};
645
- const ARTIFACT_VIEWPORT_PAN_MAX_DELTA=${ARTIFACT_VIEWPORT_PAN_MAX_DELTA};
646
- const ARTIFACT_INSPECTION_PROPERTIES=${JSON.stringify(ARTIFACT_INSPECTION_PROPERTIES)};
647
- const ARTIFACT_BRIDGE_OPERATION_TIMEOUTS=${JSON.stringify(ARTIFACT_BRIDGE_OPERATION_TIMEOUTS)};
648
- ${normalizeArtifactInspection.toString()}
649
- ${normalizeArtifactThumbnail.toString()}
650
- ${normalizeArtifactBridgeToolResult.toString()}
651
- ${normalizeArtifactViewportZoom.toString()}
652
- ${normalizeArtifactViewportPan.toString()}
653
- ${createArtifactViewportGestures.toString()}
654
- ${createArtifactBridgeTools.toString()}`;
655
- }
656
-
657
- // packages/artifact/lib/artifact/ui/prototype-state.mjs
658
- function installPrototypeState(screenId, viewId, parentOrigin, nonce) {
659
- if (!/^[A-Za-z0-9_-]{43}$/.test(nonce)) return;
660
- const win = window;
661
- let snapshot = { session: {}, forms: {} }, restoring = false;
662
- let aliasFields = [];
663
- let aliasRestoreType = "";
664
- let aliasesConfigured = false;
665
- const earlyFields = /* @__PURE__ */ new Map();
666
- let sequence = 0, hostRevision = -1, acknowledgedSequence = 0, pendingReset = 0;
667
- const documentId = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(32)))).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
668
- let generation = null;
669
- const pendingSession = /* @__PURE__ */ new Map();
670
- let pendingForm = null;
671
- function valid(value) {
672
- let keys = 0;
673
- function visit(node, depth) {
674
- if (depth > 6) return false;
675
- if (node === null || typeof node === "boolean") return true;
676
- if (typeof node === "number") return Number.isFinite(node);
677
- if (typeof node === "string") return node.length <= 8192;
678
- if (Array.isArray(node))
679
- return node.length <= 128 && node.every((item) => visit(item, depth + 1));
680
- if (!node || typeof node !== "object" || Object.getPrototypeOf(node) !== Object.prototype)
681
- return false;
682
- return Object.entries(node).every(
683
- ([key, item]) => ++keys <= 128 && key.length <= 256 && !["__proto__", "constructor", "prototype"].includes(key) && visit(item, depth + 1)
684
- );
685
- }
686
- try {
687
- return !!value && Object.keys(value).every((key) => key === "session" || key === "forms") && !!value.session && !Array.isArray(value.session) && typeof value.session === "object" && !!value.forms && !Array.isArray(value.forms) && typeof value.forms === "object" && visit(value, 0) && new TextEncoder().encode(JSON.stringify(value)).byteLength <= 16384;
688
- } catch {
689
- return false;
690
- }
691
- }
692
- const post = (type, update) => win.parent.postMessage(
693
- {
694
- type,
695
- version: 1,
696
- nonce,
697
- screenId,
698
- viewId,
699
- documentId,
700
- generation,
701
- ...type === "openplanr:prototype-state" ? { state: snapshot, sequence, ...update } : {}
702
- },
703
- parentOrigin
704
- );
705
- const fields = () => [
706
- ...document.querySelectorAll(
707
- "input,textarea,select"
708
- )
709
- ].filter(
710
- (field) => !["password", "file", "hidden", "submit", "button", "reset"].includes(field.type) && !field.hasAttribute("data-planr-state-private")
711
- );
712
- const fieldKey = (field, index) => (field.id || field.name || `field-${index}`).slice(0, 256) + (field.type === "radio" ? `:${field.value}` : "");
713
- function capture(sessionValue = snapshot.session) {
714
- if (restoring) return;
715
- const form = {};
716
- fields().forEach((field, index) => {
717
- const input = field;
718
- form[fieldKey(field, index)] = ["checkbox", "radio"].includes(field.type) ? input.checked : field instanceof HTMLSelectElement && field.multiple ? [...field.selectedOptions].map((option) => option.value) : field.value;
719
- });
720
- const session = { ...sessionValue };
721
- for (const field of fields()) {
722
- if (aliasesConfigured && aliasFields.includes(field.id) && typeof field.value === "string" && field.value.length <= 4e3)
723
- session[field.id] = field.value;
724
- }
725
- const next = { session, forms: { ...snapshot.forms, [viewId]: form } };
726
- return commit(next);
727
- }
728
- function commit(next, reset = false) {
729
- if (!valid(next) || sequence === Number.MAX_SAFE_INTEGER) return false;
730
- const keys = [
731
- .../* @__PURE__ */ new Set([...Object.keys(snapshot.session), ...Object.keys(next.session)])
732
- ].filter(
733
- (key) => Object.hasOwn(snapshot.session, key) !== Object.hasOwn(next.session, key) || JSON.stringify(snapshot.session[key]) !== JSON.stringify(next.session[key])
734
- );
735
- const pending = new Map(pendingSession);
736
- if (reset) pending.clear();
737
- for (const key of keys)
738
- pending.set(key, {
739
- sequence: sequence + 1,
740
- present: Object.hasOwn(next.session, key),
741
- value: next.session[key]
742
- });
743
- if (pending.size > 256 || new TextEncoder().encode(JSON.stringify([...pending])).byteLength > 16384)
744
- return false;
745
- sequence++;
746
- pendingSession.clear();
747
- for (const [key, value] of pending) pendingSession.set(key, value);
748
- if (reset) {
749
- earlyFields.clear();
750
- pendingReset = sequence;
751
- pendingForm = null;
752
- } else if (Object.hasOwn(next.forms, viewId))
753
- pendingForm = { sequence, value: structuredClone(next.forms[viewId]) };
754
- snapshot = structuredClone(next);
755
- postPending();
756
- return true;
757
- }
758
- function postPending() {
759
- post("openplanr:prototype-state", {
760
- sessionKeys: [...pendingSession.keys()],
761
- sessionSequences: Object.fromEntries(
762
- [...pendingSession].map(([key, update]) => [key, update.sequence])
763
- ),
764
- ...pendingReset ? { reset: true, resetSequence: pendingReset } : {}
765
- });
766
- }
767
- function apply() {
768
- const form = snapshot.forms[viewId];
769
- if (!form) return;
770
- restoring = true;
771
- fields().forEach((field, index) => {
772
- const value = form[fieldKey(field, index)];
773
- if (value === void 0) return;
774
- if (["checkbox", "radio"].includes(field.type) && typeof value === "boolean")
775
- field.checked = value;
776
- else if (field instanceof HTMLSelectElement && field.multiple && Array.isArray(value))
777
- for (const option of field.options) option.selected = value.includes(option.value);
778
- else if (typeof value === "string") field.value = value;
779
- });
780
- restoring = false;
781
- }
782
- win.__OPENPLANR_PROTOTYPE_STATE__ = Object.freeze({
783
- get: () => structuredClone(snapshot.session),
784
- set(value) {
785
- const next = { session: value, forms: snapshot.forms };
786
- if (!valid(next)) throw new TypeError("Prototype state exceeds its bounded JSON contract.");
787
- if (!capture(structuredClone(value)))
788
- throw new TypeError("Pending prototype edits exceed their bounded JSON contract.");
789
- for (const key of Object.keys(value)) earlyFields.delete(key);
790
- },
791
- reset() {
792
- if (!commit({ session: {}, forms: {} }, true))
793
- throw new TypeError("Pending prototype edits exceed their bounded JSON contract.");
794
- }
795
- });
796
- win.addEventListener("message", (event) => {
797
- const data = event.data;
798
- if (event.source === win.parent && (parentOrigin === "*" || event.origin === parentOrigin) && data?.nonce === nonce && aliasRestoreType && data.type === aliasRestoreType) {
799
- data.state = Object.fromEntries(
800
- aliasFields.flatMap((field) => {
801
- const early = !aliasesConfigured ? earlyFields.get(field) : void 0;
802
- const value = early?.value ?? snapshot.session[field];
803
- return typeof value === "string" && value.length <= 4e3 ? [[field, value]] : [];
804
- })
805
- );
806
- return;
807
- }
808
- if (event.source !== win.parent || parentOrigin !== "*" && event.origin !== parentOrigin || data?.type !== "openplanr:prototype-state:restore" || data.version !== 1 || data.nonce !== nonce || data.screenId !== screenId || data.viewId !== viewId || !valid(data.state))
809
- return;
810
- const configuring = generation === null && data.generation !== void 0;
811
- if (data.generation !== void 0) {
812
- if (typeof data.generation !== "string" || !/^[A-Za-z0-9_-][A-Za-z0-9._:-]{7,127}$/.test(data.generation))
813
- return;
814
- if (data.documentId === void 0) {
815
- post("openplanr:prototype-state:ready");
816
- return;
817
- }
818
- if (data.documentId !== documentId || generation !== null && data.generation !== generation)
819
- return;
820
- } else if (generation !== null) return;
821
- if (data.revision !== void 0) {
822
- if (!Number.isSafeInteger(data.revision) || data.revision < 0 || data.revision < hostRevision || !Number.isSafeInteger(data.acknowledgedSequence) || data.acknowledgedSequence < acknowledgedSequence || data.acknowledgedSequence > sequence)
823
- return;
824
- } else if (hostRevision >= 0) return;
825
- const aliases = data.aliases;
826
- aliasRestoreType = aliases?.version === 1 && typeof aliases.restoreType === "string" && /^[a-zA-Z][a-zA-Z0-9:_-]{0,127}$/.test(aliases.restoreType) && !aliases.restoreType.startsWith("openplanr:") ? aliases.restoreType : "";
827
- aliasFields = aliases?.version === 1 && Array.isArray(aliases.fields) && aliases.fields.length <= 32 && aliases.fields.every(
828
- (field) => typeof field === "string" && /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(field) && !["constructor", "prototype", "__proto__"].includes(field)
829
- ) ? aliases.fields : [];
830
- const ack = data.revision === void 0 ? sequence : data.acknowledgedSequence;
831
- const next = structuredClone(data.state);
832
- if (pendingReset > ack) {
833
- next.session = {};
834
- next.forms = {};
835
- }
836
- for (const [key, update] of pendingSession) {
837
- if (update.sequence <= ack) continue;
838
- if (update.present && update.value !== void 0) next.session[key] = update.value;
839
- else delete next.session[key];
840
- }
841
- if (pendingForm && pendingForm.sequence > ack) next.forms[viewId] = pendingForm.value;
842
- if (!valid(next)) return;
843
- for (const [field, early] of earlyFields)
844
- if (early.sequence <= ack && JSON.stringify(data.state.forms[viewId]?.[early.fieldKey]) !== JSON.stringify(early.formValue))
845
- earlyFields.delete(field);
846
- hostRevision = data.revision ?? hostRevision;
847
- if (data.generation !== void 0) generation = data.generation;
848
- acknowledgedSequence = data.revision === void 0 ? 0 : ack;
849
- if (pendingReset <= ack) pendingReset = 0;
850
- for (const [key, update] of pendingSession)
851
- if (update.sequence <= ack) pendingSession.delete(key);
852
- if (pendingForm && pendingForm.sequence <= ack) pendingForm = null;
853
- snapshot = next;
854
- if (!aliasesConfigured && aliasRestoreType) {
855
- const promoted = structuredClone(snapshot);
856
- for (const field of aliasFields) {
857
- const early = earlyFields.get(field);
858
- if (!early || (pendingSession.get(field)?.sequence ?? 0) > early.sequence) continue;
859
- promoted.session[field] = early.value;
860
- promoted.forms[viewId] ??= {};
861
- promoted.forms[viewId][early.fieldKey] = early.formValue;
862
- }
863
- if (!aliasFields.some((field) => earlyFields.has(field)) || commit(promoted)) {
864
- aliasesConfigured = true;
865
- earlyFields.clear();
866
- }
867
- }
868
- apply();
869
- win.dispatchEvent(
870
- new CustomEvent("openplanr:prototype-state-restored", {
871
- detail: structuredClone(snapshot.session)
872
- })
873
- );
874
- if (data.revision !== void 0 && (pendingSession.size || pendingReset || pendingForm))
875
- postPending();
876
- else if (configuring) post("openplanr:prototype-state:ready");
877
- });
878
- const captureField = (event) => {
879
- if (!capture() || aliasesConfigured) return;
880
- const field = fields().find((candidate) => candidate === event.target);
881
- if (!field || !/^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(field.id) || ["constructor", "prototype", "__proto__"].includes(field.id) || field.value.length > 4e3)
882
- return;
883
- const key = fieldKey(field, fields().indexOf(field));
884
- const next = new Map(earlyFields);
885
- next.set(field.id, {
886
- value: field.value,
887
- fieldKey: key,
888
- formValue: snapshot.forms[viewId][key],
889
- sequence
890
- });
891
- if (next.size > 128 || new TextEncoder().encode(JSON.stringify([...next])).byteLength > 16384)
892
- return;
893
- earlyFields.clear();
894
- for (const [id, value] of next) earlyFields.set(id, value);
895
- };
896
- document.addEventListener("input", captureField, true);
897
- document.addEventListener("change", captureField, true);
898
- document.addEventListener("submit", () => capture(), true);
899
- if (document.readyState === "loading")
900
- document.addEventListener(
901
- "DOMContentLoaded",
902
- () => {
903
- apply();
904
- post("openplanr:prototype-state:ready");
905
- },
906
- { once: true }
907
- );
908
- else {
909
- apply();
910
- post("openplanr:prototype-state:ready");
911
- }
912
- post("openplanr:prototype-state:ready");
913
- win.setTimeout(() => post("openplanr:prototype-state:ready"), 500);
914
- }
915
- function renderPrototypeStateInstaller() {
916
- return installPrototypeState.toString();
917
- }
918
-
919
- // packages/artifact/lib/artifact/browser-sandbox.mjs
920
- function pipelineError(code, message, details) {
921
- return new PipelineError(code, message, "", details);
922
- }
923
- function browserCapabilityToken({ bytes = 32 } = {}) {
924
- const data = crypto.getRandomValues(new Uint8Array(bytes));
925
- return btoa(String.fromCharCode(...data)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
926
- }
927
- function isCapabilityToken2(value) {
928
- if (typeof value !== "string" || !/^[A-Za-z0-9_-]{43}$/u.test(value)) return false;
929
- try {
930
- const decoded = atob(value.replaceAll("-", "+").replaceAll("_", "/") + "=");
931
- return decoded.length === 32 && btoa(decoded).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "") === value;
932
- } catch {
933
- return false;
934
- }
935
- }
936
- function validHostedOrigin(origin) {
937
- if (typeof origin !== "string") return false;
938
- try {
939
- const parsed = new URL(origin);
940
- return parsed.protocol === "https:" && parsed.origin === origin && !parsed.username && !parsed.password;
941
- } catch {
942
- return false;
943
- }
944
- }
945
- var ARTIFACT_BRIDGE_CHANNEL = "openplanr.artifact-anchor";
946
- var ARTIFACT_BRIDGE_VERSION = "1.0.0";
947
- var ARTIFACT_BRIDGE_EVENT = "planr:artifact-anchor";
948
- var ARTIFACT_BRIDGE_READY_EVENT = "planr:artifact-bridge-ready";
949
- var ARTIFACT_BRIDGE_LAYOUT_EVENT = "planr:artifact-layout";
950
- var ARTIFACT_VIEWPORT_ZOOM_EVENT = "planr:artifact-viewport-zoom";
951
- var ARTIFACT_VIEWPORT_PAN_EVENT = "planr:artifact-viewport-pan";
952
- var ARTIFACT_EXPORT_MAX_EDGE = 11e3;
953
- var ARTIFACT_EXPORT_MAX_DATA_URL = 24 * 1024 * 1024;
954
- var ARTIFACT_LAYOUT_MAX_WIDTH = 16384;
955
- var ARTIFACT_LAYOUT_MAX_HEIGHT = 262144;
956
- var ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/;
957
- var SCRIPT_NONCE_RE = /^[A-Za-z0-9_-]{24}$/;
958
- var FORBIDDEN_TAGS = /* @__PURE__ */ new Set([
959
- "applet",
960
- "base",
961
- "embed",
962
- "fencedframe",
963
- "form",
964
- "frame",
965
- "frameset",
966
- "iframe",
967
- "noembed",
968
- "noframes",
969
- "noscript",
970
- "object",
971
- "portal"
972
- ]);
973
- var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
974
- "action",
975
- "archive",
976
- "background",
977
- "classid",
978
- "codebase",
979
- "formaction",
980
- "href",
981
- "longdesc",
982
- "manifest",
983
- "ping",
984
- "profile",
985
- "src",
986
- "srcdoc",
987
- "target",
988
- "xlink:href"
989
- ]);
990
- var REMOTE_URL_RE = /^(?:https?:|file:|ftp:|wss?:|\/\/)/i;
991
- function getAttr(node, name) {
992
- return node.attrs?.find((attribute) => attribute.name.toLowerCase() === name)?.value;
993
- }
994
- function setAttr(node, name, value) {
995
- const existing = node.attrs?.find((attribute) => attribute.name.toLowerCase() === name);
996
- if (existing) existing.value = value;
997
- else {
998
- node.attrs ??= [];
999
- node.attrs.push({ name, value });
1000
- }
1001
- }
1002
- function createElement(tagName) {
1003
- return parseFragment(`<${tagName}></${tagName}>`).childNodes[0];
1004
- }
1005
- function createText(value, parentNode) {
1006
- return { nodeName: "#text", value, parentNode };
1007
- }
1008
- function descendants(node) {
1009
- return [...node?.childNodes ?? [], ...node?.content?.childNodes ?? []];
1010
- }
1011
- function removeNode(node) {
1012
- const parent2 = node.parentNode;
1013
- const index = parent2?.childNodes?.indexOf(node) ?? -1;
1014
- if (index >= 0) parent2.childNodes.splice(index, 1);
1015
- }
1016
- function findElement(document2, tagName) {
1017
- const queue = descendants(document2);
1018
- while (queue.length > 0) {
1019
- const node = queue.shift();
1020
- if (node?.tagName?.toLowerCase() === tagName) return node;
1021
- queue.push(...descendants(node));
1022
- }
1023
- return null;
1024
- }
1025
- function artifactContentSecurityPolicy(scriptNonce) {
1026
- if (typeof scriptNonce !== "string" || !SCRIPT_NONCE_RE.test(scriptNonce)) {
1027
- throw pipelineError(ARTIFACT_ERROR_CODES.SANDBOX_POLICY, "Artifact script nonce is invalid.");
1028
- }
1029
- return [
1030
- "default-src 'none'",
1031
- `script-src 'nonce-${scriptNonce}' data: blob:`,
1032
- `script-src-elem 'nonce-${scriptNonce}' data: blob:`,
1033
- "script-src-attr 'unsafe-inline'",
1034
- "style-src 'unsafe-inline' data: blob:",
1035
- "img-src data: blob:",
1036
- "media-src data: blob:",
1037
- "font-src data:",
1038
- "worker-src data: blob:",
1039
- "connect-src 'none'",
1040
- "frame-src 'none'",
1041
- "child-src 'none'",
1042
- "object-src 'none'",
1043
- "manifest-src 'none'",
1044
- "form-action 'none'",
1045
- "base-uri 'none'"
1046
- ].join("; ");
1047
- }
1048
- function assertSandboxableTree(document2, { allowLocalForms = false } = {}) {
1049
- const queue = descendants(document2);
1050
- while (queue.length > 0) {
1051
- const node = queue.shift();
1052
- if (!node?.tagName) {
1053
- queue.push(...descendants(node));
1054
- continue;
1055
- }
1056
- const tag = node.tagName.toLowerCase();
1057
- if (FORBIDDEN_TAGS.has(tag) && !(tag === "form" && allowLocalForms)) {
1058
- throw pipelineError(
1059
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1060
- `Unsafe <${tag}> cannot enter an artifact review sandbox.`
1061
- );
1062
- }
1063
- if (tag === "meta" && getAttr(node, "http-equiv")?.trim().toLowerCase() === "refresh") {
1064
- throw pipelineError(
1065
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1066
- "Meta refresh navigation is forbidden."
1067
- );
1068
- }
1069
- for (const attribute of node.attrs ?? []) {
1070
- const name = attribute.name.toLowerCase();
1071
- const value = attribute.value.trim();
1072
- if (["srcdoc", "target", "action", "formaction"].includes(name)) {
1073
- throw pipelineError(
1074
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1075
- `Artifact navigation attribute ${name} is forbidden.`
1076
- );
1077
- }
1078
- if (URL_ATTRIBUTES.has(name) && REMOTE_URL_RE.test(value)) {
1079
- throw pipelineError(
1080
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1081
- `Remote artifact resource is forbidden: ${value.slice(0, 80)}`
1082
- );
1083
- }
1084
- if (name === "style" && /(?:@import|url\s*\(\s*['"]?(?:https?:|file:|\/\/))/i.test(value)) {
1085
- throw pipelineError(ARTIFACT_ERROR_CODES.SANDBOX_POLICY, "Remote inline CSS is forbidden.");
1086
- }
1087
- }
1088
- if (tag === "style") {
1089
- const css = (node.childNodes ?? []).map((child) => child.value ?? "").join("");
1090
- if (/(?:@import|url\s*\(\s*['"]?(?:https?:|file:|\/\/))/i.test(css)) {
1091
- throw pipelineError(
1092
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1093
- "Remote stylesheet resources are forbidden."
1094
- );
1095
- }
1096
- }
1097
- queue.push(...descendants(node));
1098
- }
1099
- }
1100
- var SANDBOX_GUARD_LIMITS = Object.freeze({
1101
- __PLANR_SANDBOX_EXPORT_MAX_EDGE__: String(ARTIFACT_EXPORT_MAX_EDGE),
1102
- __PLANR_SANDBOX_EXPORT_MAX_DATA_URL__: String(ARTIFACT_EXPORT_MAX_DATA_URL),
1103
- __PLANR_SANDBOX_LAYOUT_MAX_WIDTH__: String(ARTIFACT_LAYOUT_MAX_WIDTH),
1104
- __PLANR_SANDBOX_LAYOUT_MAX_HEIGHT__: String(ARTIFACT_LAYOUT_MAX_HEIGHT)
1105
- });
1106
- function sandboxGuardFiller(name, template, keys) {
1107
- const pattern = new RegExp(keys.join("|"), "gu");
1108
- const unfilled = [...new Set(template.replace(pattern, "").match(/__PLANR_SANDBOX_[A-Z_]+__/gu))];
1109
- const missing = keys.filter((key) => !template.includes(key));
1110
- if (unfilled.length > 0 || missing.length > 0) {
1111
- throw pipelineError(
1112
- ARTIFACT_ERROR_CODES.BRIDGE_INVALID,
1113
- `The generated ${name} does not match bridge.mjs (unfilled: ${unfilled.join(", ") || "none"}; missing: ${missing.join(", ") || "none"}). Run npm run generate.`
1114
- );
1115
- }
1116
- return (values) => template.replace(pattern, (key) => {
1117
- if (typeof values[key] !== "string") {
1118
- throw pipelineError(
1119
- ARTIFACT_ERROR_CODES.BRIDGE_INVALID,
1120
- `The ${name} needs a string for ${key}; received ${typeof values[key]}.`
1121
- );
1122
- }
1123
- return values[key];
1124
- });
1125
- }
1126
- var fillFrameGuard = sandboxGuardFiller("frame guard", ARTIFACT_FRAME_GUARD_TEMPLATE, [
1127
- "__PLANR_SANDBOX_CONTRACT__",
1128
- "__PLANR_SANDBOX_BRIDGE_TOOLS__;",
1129
- "__PLANR_SANDBOX_WORKER_GUARD__",
1130
- ...Object.keys(SANDBOX_GUARD_LIMITS)
1131
- ]);
1132
- function artifactGuardAndBridgeSource({
1133
- artifactId,
1134
- nonce,
1135
- parentOrigin,
1136
- prototypeState = false,
1137
- reviewSelection = false,
1138
- screenId = artifactId
1139
- }) {
1140
- const contract = JSON.stringify({
1141
- channel: ARTIFACT_BRIDGE_CHANNEL,
1142
- schemaVersion: ARTIFACT_BRIDGE_VERSION,
1143
- artifactId,
1144
- nonce,
1145
- parentOrigin,
1146
- ...prototypeState ? { screenId } : {},
1147
- ...reviewSelection ? { reviewSelection: true } : {}
1148
- }).replace(/</gu, "\\u003c");
1149
- const guard = fillFrameGuard({
1150
- __PLANR_SANDBOX_CONTRACT__: prototypeState || reviewSelection ? "__openplanrPrototypeContract" : contract,
1151
- "__PLANR_SANDBOX_BRIDGE_TOOLS__;": renderArtifactBridgeToolsSource(),
1152
- __PLANR_SANDBOX_WORKER_GUARD__: JSON.stringify(ARTIFACT_WORKER_GUARD_SOURCE),
1153
- ...SANDBOX_GUARD_LIMITS
1154
- });
1155
- if (!prototypeState && !reviewSelection) return guard;
1156
- const prototypeInstaller = prototypeState ? `(${renderPrototypeStateInstaller()})(__openplanrPrototypeContract.screenId,__openplanrPrototypeContract.artifactId,__openplanrPrototypeContract.parentOrigin === 'null' ? '*' : __openplanrPrototypeContract.parentOrigin,__openplanrPrototypeContract.nonce);` : "";
1157
- return `(function(__openplanrPrototypeContract){${guard};${prototypeInstaller}(${installPreviewNavigation.toString()})(__openplanrPrototypeContract);})(${contract});`;
1158
- }
1159
- function installPreviewNavigation(contract) {
1160
- const trustedParent = parent, post = trustedParent.postMessage.bind(trustedParent), NativeElement = Element, svgRoots = [], svgClick = () => {
1161
- }, addListener = EventTarget.prototype.addEventListener, removeListener = EventTarget.prototype.removeEventListener, queryAll = Document.prototype.querySelectorAll, query = NativeElement.prototype.querySelector, closest = NativeElement.prototype.closest, attribute = NativeElement.prototype.getAttribute, preventDefault = Event.prototype.preventDefault, stopImmediatePropagation = Event.prototype.stopImmediatePropagation, descriptors = Object.getOwnPropertyDescriptors, prototype = Object.getPrototypeOf, objectPrototype = Object.prototype, keys = Reflect.ownKeys;
1162
- let selectionEnabled = false;
1163
- if (contract.reviewSelection === true)
1164
- addEventListener("message", (event) => {
1165
- if (event.source !== trustedParent || event.origin !== contract.parentOrigin) return;
1166
- const data = event.data;
1167
- if (!data || typeof data !== "object") return;
1168
- const dataPrototype = prototype(data);
1169
- if (dataPrototype !== objectPrototype && dataPrototype !== null) return;
1170
- const fields = descriptors(data), allowed = ["schemaVersion", "type", "channel", "viewId", "enabled"];
1171
- if (keys(fields).length !== allowed.length || allowed.some((key) => !fields[key]?.enumerable || !("value" in fields[key])))
1172
- return;
1173
- if (fields.schemaVersion.value !== "1.0.0" || fields.type.value !== "openplanr:review-selection" || fields.channel.value !== contract.nonce || fields.viewId.value !== contract.artifactId || typeof fields.enabled.value !== "boolean")
1174
- return;
1175
- selectionEnabled = fields.enabled.value;
1176
- for (const svg of svgRoots) removeListener.call(svg, "click", svgClick);
1177
- svgRoots.length = 0;
1178
- if (selectionEnabled)
1179
- for (const svg of queryAll.call(document, "svg")) {
1180
- if (!attribute.call(svg, "data-planr-id") && !attribute.call(svg, "data-element-id") && !query.call(svg, "[data-planr-id],[data-element-id]"))
1181
- continue;
1182
- addListener.call(svg, "click", svgClick);
1183
- svgRoots.push(svg);
1184
- }
1185
- });
1186
- document.addEventListener(
1187
- "click",
1188
- (event) => {
1189
- if (!(event.target instanceof NativeElement)) return;
1190
- if (selectionEnabled) {
1191
- const target2 = closest.call(event.target, "[data-planr-id],[data-element-id]"), elementId = target2 ? attribute.call(target2, "data-planr-id") ?? attribute.call(target2, "data-element-id") : null;
1192
- if (!elementId || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(elementId)) return;
1193
- preventDefault.call(event);
1194
- stopImmediatePropagation.call(event);
1195
- post(
1196
- {
1197
- schemaVersion: "1.0.0",
1198
- channel: contract.nonce,
1199
- type: "select",
1200
- viewId: contract.artifactId,
1201
- elementId
1202
- },
1203
- contract.parentOrigin === "null" ? "*" : contract.parentOrigin
1204
- );
1205
- return;
1206
- }
1207
- if (!contract.screenId) return;
1208
- const target = closest.call(
1209
- event.target,
1210
- "[data-design-target],[data-planr-navigate],[data-design-navigate]"
1211
- );
1212
- if (!target) return;
1213
- const screenId = target.getAttribute("data-design-target") || target.getAttribute("data-planr-navigate") || target.getAttribute("data-design-navigate");
1214
- if (!screenId || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(screenId)) return;
1215
- event.preventDefault();
1216
- post(
1217
- {
1218
- schemaVersion: "1.0.0",
1219
- channel: contract.nonce,
1220
- type: "navigate",
1221
- viewId: contract.artifactId,
1222
- screenId
1223
- },
1224
- contract.parentOrigin === "null" ? "*" : contract.parentOrigin
1225
- );
1226
- },
1227
- true
1228
- );
1229
- }
1230
- function prepareArtifactDocument({
1231
- html,
1232
- artifactId,
1233
- nonce,
1234
- parentOrigin,
1235
- scriptNonce = browserCapabilityToken({ bytes: 18 }),
1236
- allowLocalForms = false,
1237
- portable = false,
1238
- trustedParentOrigin,
1239
- screenId = artifactId,
1240
- prototypeState = false,
1241
- reviewSelection = false
1242
- } = {}) {
1243
- if (typeof html !== "string" || html.length === 0) {
1244
- throw pipelineError(ARTIFACT_ERROR_CODES.SANDBOX_POLICY, "Artifact HTML is required.");
1245
- }
1246
- if (typeof artifactId !== "string" || !ID_RE.test(artifactId)) {
1247
- throw pipelineError(ARTIFACT_ERROR_CODES.SANDBOX_POLICY, "Artifact id is invalid.");
1248
- }
1249
- if (!isCapabilityToken2(nonce)) {
1250
- throw pipelineError(ARTIFACT_ERROR_CODES.SANDBOX_POLICY, "Artifact bridge nonce is invalid.");
1251
- }
1252
- if (typeof reviewSelection !== "boolean")
1253
- throw pipelineError(
1254
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1255
- "Artifact review selection option must be a boolean."
1256
- );
1257
- if (reviewSelection && artifactId.length > 128)
1258
- throw pipelineError(
1259
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1260
- "Review selection requires an artifact view id of at most 128 characters."
1261
- );
1262
- if (prototypeState && (typeof screenId !== "string" || !ID_RE.test(screenId)))
1263
- throw pipelineError(
1264
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1265
- "Prototype screen identity is invalid."
1266
- );
1267
- const originMatch = /^http:\/\/127\.0\.0\.1:(\d{1,5})$/.exec(parentOrigin ?? "");
1268
- const originPort = Number(originMatch?.[1]);
1269
- if (!(portable && parentOrigin === "null") && !(portable && parentOrigin === trustedParentOrigin && validHostedOrigin(parentOrigin)) && (!originMatch || !Number.isInteger(originPort) || originPort < 1 || originPort > 65535 || String(originPort) !== originMatch[1])) {
1270
- throw pipelineError(
1271
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1272
- "Artifact parent origin must be IPv4 loopback or an explicitly trusted HTTPS origin."
1273
- );
1274
- }
1275
- const document2 = parse(html, { sourceCodeLocationInfo: false });
1276
- assertSandboxableTree(document2, { allowLocalForms });
1277
- const head = findElement(document2, "head");
1278
- if (!head)
1279
- throw pipelineError(
1280
- ARTIFACT_ERROR_CODES.SANDBOX_POLICY,
1281
- "Artifact document has no head element."
1282
- );
1283
- for (const node of [...descendants(head)]) {
1284
- if (node?.tagName?.toLowerCase() === "meta") {
1285
- const httpEquiv = getAttr(node, "http-equiv")?.trim().toLowerCase();
1286
- if (httpEquiv === "content-security-policy") removeNode(node);
1287
- }
1288
- }
1289
- const csp = artifactContentSecurityPolicy(scriptNonce);
1290
- const hasViewport = descendants(head).some(
1291
- (node) => node?.tagName?.toLowerCase() === "meta" && getAttr(node, "name")?.trim().toLowerCase() === "viewport"
1292
- );
1293
- const viewportMeta = hasViewport ? null : createElement("meta");
1294
- if (viewportMeta) {
1295
- setAttr(viewportMeta, "name", "viewport");
1296
- setAttr(viewportMeta, "content", "width=device-width,initial-scale=1,viewport-fit=cover");
1297
- viewportMeta.parentNode = head;
1298
- }
1299
- const cspMeta = createElement("meta");
1300
- setAttr(cspMeta, "http-equiv", "Content-Security-Policy");
1301
- setAttr(cspMeta, "content", csp);
1302
- cspMeta.parentNode = head;
1303
- const referrerMeta = createElement("meta");
1304
- setAttr(referrerMeta, "name", "referrer");
1305
- setAttr(referrerMeta, "content", "no-referrer");
1306
- referrerMeta.parentNode = head;
1307
- const bridge = createElement("script");
1308
- setAttr(bridge, "nonce", scriptNonce);
1309
- bridge.childNodes = [
1310
- createText(
1311
- artifactGuardAndBridgeSource({
1312
- artifactId,
1313
- nonce,
1314
- parentOrigin,
1315
- prototypeState,
1316
- reviewSelection,
1317
- screenId
1318
- }),
1319
- bridge
1320
- )
1321
- ];
1322
- bridge.parentNode = head;
1323
- const queue = descendants(document2);
1324
- while (queue.length > 0) {
1325
- const node = queue.shift();
1326
- if (node?.tagName?.toLowerCase() === "script") setAttr(node, "nonce", scriptNonce);
1327
- queue.push(...descendants(node));
1328
- }
1329
- head.childNodes = [
1330
- cspMeta,
1331
- referrerMeta,
1332
- ...viewportMeta ? [viewportMeta] : [],
1333
- bridge,
1334
- ...head.childNodes ?? []
1335
- ];
1336
- return Object.freeze({ html: serialize(document2), csp, scriptNonce });
1337
- }
1338
- function prepareArtifactSourceTemplate(options = {}) {
1339
- const artifactId = `template-${browserCapabilityToken()}`;
1340
- const prepared = prepareArtifactDocument({
1341
- ...options,
1342
- artifactId,
1343
- portable: true,
1344
- parentOrigin: options.parentOrigin ?? "null"
1345
- });
1346
- const artifactIdToken = `"artifactId":${JSON.stringify(artifactId)}`;
1347
- if (prepared.html.split(artifactIdToken).length !== 2)
1348
- throw pipelineError(
1349
- ARTIFACT_ERROR_CODES.BRIDGE_INVALID,
1350
- "Shared source bridge identity is not unique."
1351
- );
1352
- return Object.freeze({ html: prepared.html, artifactIdToken });
1353
- }
1354
-
1355
- // packages/artifact/lib/artifact/bridge.mjs
1356
- var ID_RE2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/;
1357
- function pipelineError2(code, message, details) {
1358
- return new PipelineError(code, message, "", details);
1359
- }
1360
- function createArtifactBridgeNonce({ randomBytesImpl = randomBytes2 } = {}) {
1361
- return mintCapabilityToken({ bytes: 32, randomBytesImpl });
1362
- }
1363
- var fillHostGuard = sandboxGuardFiller("host guard", ARTIFACT_HOST_GUARD_TEMPLATE, [
1364
- "__PLANR_SANDBOX_CONFIG__",
1365
- "__PLANR_SANDBOX_BRIDGE_TOOLS__;",
1366
- ...Object.keys(SANDBOX_GUARD_LIMITS)
1367
- ]);
1368
- function validInlineSourcePool(sources, references) {
1369
- if (!sources || typeof sources !== "object" || Array.isArray(sources) || !references || typeof references !== "object" || Array.isArray(references))
1370
- return false;
1371
- const entries = Object.entries(sources), views = Object.entries(references);
1372
- if (!entries.length || entries.length > ARTIFACT_MAX_SOURCES || !views.length || views.length > ARTIFACT_MAX_VIEWS)
1373
- return false;
1374
- let bytes = 0;
1375
- for (const [id, source] of entries) {
1376
- if (!ID_RE2.test(id) || !source || Object.keys(source).length !== 2 || typeof source.html !== "string" || !/^"artifactId":"template-[A-Za-z0-9_-]{43}"$/u.test(source.artifactIdToken) || source.html.split(source.artifactIdToken).length !== 2)
1377
- return false;
1378
- bytes += Buffer.byteLength(source.html);
1379
- if (bytes > 100 * 1024 * 1024) return false;
1380
- }
1381
- return views.every(
1382
- ([id, sourceId]) => ID_RE2.test(id) && typeof sourceId === "string" && Object.hasOwn(sources, sourceId)
1383
- ) && new Set(Object.values(references)).size === entries.length;
1384
- }
1385
- function renderArtifactParentRuntime({
1386
- artifactBaseUrl,
1387
- stageRuntimeUrl,
1388
- adapterRuntimeUrl,
1389
- nonce,
1390
- inlineArtifacts,
1391
- inlineSources,
1392
- inlineArtifactSources,
1393
- sourceTransport = "blob",
1394
- frameBudget
1395
- } = {}) {
1396
- const canonicalPath = (value, { trailingSlash = false } = {}) => {
1397
- if (typeof value !== "string" || !value.startsWith("/") || value.startsWith("//") || value.includes("\\") || value.includes("?") || value.includes("#") || /[\u0000-\u001f]/.test(value) || /%(?:00|2f|5c)/i.test(value) || (trailingSlash ? !value.endsWith("/") : value.endsWith("/")))
1398
- return false;
1399
- try {
1400
- return value.split("/").filter(Boolean).every((segment) => {
1401
- const decoded = decodeURIComponent(segment);
1402
- return decoded !== "." && decoded !== ".." && !decoded.includes("/") && !decoded.includes("\\");
1403
- });
1404
- } catch {
1405
- return false;
1406
- }
1407
- };
1408
- const legacyPortable = inlineArtifacts && typeof inlineArtifacts === "object" && !Array.isArray(inlineArtifacts) && Object.values(inlineArtifacts).every((html) => typeof html === "string");
1409
- const pooledPortable = validInlineSourcePool(inlineSources, inlineArtifactSources);
1410
- const portable = legacyPortable || pooledPortable;
1411
- if ((inlineSources !== void 0 || inlineArtifactSources !== void 0) && (!pooledPortable || inlineArtifacts !== void 0) || !portable && !canonicalPath(artifactBaseUrl, { trailingSlash: true }) || !(canonicalPath(stageRuntimeUrl) || portable && /^data:text\/javascript;base64,[A-Za-z0-9+/=]+$/u.test(stageRuntimeUrl)) || adapterRuntimeUrl !== void 0 && !canonicalPath(adapterRuntimeUrl) || !isCapabilityToken(nonce) || !["blob", "srcdoc"].includes(sourceTransport) || frameBudget !== void 0 && (!Number.isInteger(frameBudget) || frameBudget < 1 || frameBudget > 8)) {
1412
- throw pipelineError2(
1413
- ARTIFACT_ERROR_CODES.BRIDGE_INVALID,
1414
- "Artifact parent runtime configuration is invalid."
1415
- );
1416
- }
1417
- const config = JSON.stringify({
1418
- artifactBaseUrl,
1419
- stageRuntimeUrl,
1420
- adapterRuntimeUrl: adapterRuntimeUrl ?? null,
1421
- nonce,
1422
- inlineArtifacts: legacyPortable ? inlineArtifacts : null,
1423
- ...pooledPortable ? { inlineSources, inlineArtifactSources } : {},
1424
- sourceTransport,
1425
- ...frameBudget === void 0 ? {} : { frameBudget },
1426
- channel: ARTIFACT_BRIDGE_CHANNEL,
1427
- schemaVersion: ARTIFACT_BRIDGE_VERSION,
1428
- anchorEvent: ARTIFACT_BRIDGE_EVENT,
1429
- readyEvent: ARTIFACT_BRIDGE_READY_EVENT,
1430
- layoutEvent: ARTIFACT_BRIDGE_LAYOUT_EVENT,
1431
- viewportZoomEvent: ARTIFACT_VIEWPORT_ZOOM_EVENT,
1432
- viewportPanEvent: ARTIFACT_VIEWPORT_PAN_EVENT,
1433
- navigationEvent: "planr:artifact-navigation-blocked",
1434
- frameCsp: [
1435
- "default-src 'none'",
1436
- "script-src 'unsafe-inline' data: blob:",
1437
- "script-src-attr 'unsafe-inline'",
1438
- "style-src 'unsafe-inline' data: blob:",
1439
- "img-src data: blob:",
1440
- "media-src data: blob:",
1441
- "font-src data:",
1442
- "worker-src data: blob:",
1443
- "connect-src 'none'",
1444
- "frame-src 'none'",
1445
- "child-src 'none'",
1446
- "object-src 'none'",
1447
- "manifest-src 'none'",
1448
- "form-action 'none'",
1449
- "base-uri 'none'"
1450
- ].join("; ")
1451
- });
1452
- return fillHostGuard({
1453
- __PLANR_SANDBOX_CONFIG__: config,
1454
- "__PLANR_SANDBOX_BRIDGE_TOOLS__;": renderArtifactBridgeToolsSource(),
1455
- ...SANDBOX_GUARD_LIMITS
1456
- });
1457
- }
1458
-
1459
- // packages/design/lib/design/lint.mjs
1460
- import { readFileSync } from "node:fs";
1461
- import { fileURLToPath } from "node:url";
1462
-
1463
- // packages/design/lib/design/tokens.mjs
1464
- var SPACING_STEP = 4;
1465
- var FRAMES = {
1466
- desktop: { w: 1440, h: 1024 },
1467
- tablet: { w: 834, h: 1194 },
1468
- mobile: { w: 390, h: 844 }
1469
- };
1470
- var DEFAULT_FRAME = FRAMES.desktop;
1471
- var RESPONSIVE_FRAMES = [
1472
- { name: "desktop", ...FRAMES.desktop },
1473
- { name: "tablet", ...FRAMES.tablet },
1474
- { name: "mobile", ...FRAMES.mobile }
1475
- ];
1476
- function isOnSpacingScale(px) {
1477
- const n = Math.abs(Number(px));
1478
- if (!Number.isInteger(n)) return false;
1479
- return n === 0 || n === 2 || n % SPACING_STEP === 0;
1480
- }
1481
- function nearestSpacing(px) {
1482
- const v = Number(px) || 0;
1483
- const n = Math.abs(v);
1484
- const sign = v < 0 ? -1 : 1;
1485
- const candidates = [.../* @__PURE__ */ new Set([0, 2, Math.round(n / SPACING_STEP) * SPACING_STEP])].sort(
1486
- (a, b) => a - b
1487
- );
1488
- const best = candidates.reduce(
1489
- (b, c) => Math.abs(c - n) <= Math.abs(b - n) ? c : b,
1490
- candidates[0]
1491
- );
1492
- return sign * best;
1493
- }
1494
- function isCanonicalFrame({ w, h } = {}) {
1495
- return Object.values(FRAMES).some((f) => f.w === Number(w) && f.h === Number(h));
1496
- }
1497
-
1498
- // packages/design/lib/design/lint.mjs
1499
- var SPACING_PROP = /^(padding|margin|gap|row-gap|column-gap|inset|top|right|bottom|left)(-(top|right|bottom|left|block|inline)(-(start|end))?)?$/;
1500
- var SIZING_PROP = /^(width|height|min-width|min-height|max-width|max-height|padding|margin|font-size|gap)/;
1501
- var COLOR_PROP = /^(color|background|background-color|border(-(top|right|bottom|left))?-color|outline-color|fill|stroke|caret-color|text-decoration-color)$/;
1502
- var COLOR_LITERAL = /#[0-9a-fA-F]{3,8}\b|rgba?\([^)]*\)|oklch\([^)]*\)/gi;
1503
- var SYSTEM_FONTS = /* @__PURE__ */ new Set([
1504
- "inherit",
1505
- "initial",
1506
- "sans-serif",
1507
- "serif",
1508
- "monospace",
1509
- "system-ui",
1510
- "ui-sans-serif",
1511
- "ui-monospace",
1512
- "ui-serif",
1513
- "-apple-system",
1514
- "blinkmacsystemfont",
1515
- "segoe ui",
1516
- "roboto",
1517
- "helvetica neue",
1518
- "helvetica",
1519
- "arial",
1520
- "sfmono-regular",
1521
- "sf mono",
1522
- "menlo",
1523
- "consolas",
1524
- "liberation mono",
1525
- "cursive"
1526
- ]);
1527
- function literalColors(value) {
1528
- return /gradient/i.test(value) ? [] : value.match(COLOR_LITERAL) || [];
1529
- }
1530
- function firstColor(value) {
1531
- if (/var\(|gradient/i.test(value)) return null;
1532
- const m = value.match(/#[0-9a-fA-F]{3,8}\b|rgba?\([^)]*\)|oklch\([^)]*\)|\b(?:white|black)\b/i);
1533
- return m ? m[0] : null;
1534
- }
1535
- function firstFontFamily(value) {
1536
- const first = value.split(",")[0].trim().replace(/^["']|["']$/g, "");
1537
- return first ? first.toLowerCase() : null;
1538
- }
1539
- function declBlocks(html) {
1540
- const blocks = [];
1541
- for (const m of html.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/gi))
1542
- for (const b of cssDeclBlocks(m[1])) blocks.push(declsFromBlock(b));
1543
- for (const m of html.matchAll(/style\s*=\s*(["'])([\s\S]*?)\1/gi))
1544
- blocks.push(declsFromBlock(m[2]));
1545
- return blocks;
1546
- }
1547
- function pxValues(value) {
1548
- if (/\bvar\(|\bcalc\(/.test(value)) return [];
1549
- const out = [];
1550
- for (const m of value.matchAll(/-?\d+(?:\.\d+)?(px|rem|em)\b/g)) {
1551
- const n = parseFloat(m[0]);
1552
- out.push(/r?em/.test(m[1]) ? Math.round(n * 16 * 1e3) / 1e3 : n);
1553
- }
1554
- return out;
1555
- }
1556
- function declsFromBlock(block) {
1557
- return block.split(";").map((s) => s.trim()).filter(Boolean).map((s) => {
1558
- const i = s.indexOf(":");
1559
- if (i < 0) return null;
1560
- return { prop: s.slice(0, i).trim().toLowerCase(), value: s.slice(i + 1).trim() };
1561
- }).filter(Boolean);
1562
- }
1563
- function cssDeclBlocks(css) {
1564
- const clean = css.replace(/\/\*[\s\S]*?\*\//g, "");
1565
- const blocks = [];
1566
- let depth = 0;
1567
- let buf = "";
1568
- for (const ch of clean) {
1569
- if (ch === "{") {
1570
- depth += 1;
1571
- buf = "";
1572
- continue;
1573
- }
1574
- if (ch === "}") {
1575
- if (depth >= 1) blocks.push(buf);
1576
- depth -= 1;
1577
- buf = "";
1578
- continue;
1579
- }
1580
- if (depth >= 1) buf += ch;
1581
- }
1582
- return blocks;
1583
- }
1584
- function styleBlockDecls(html) {
1585
- const out = [];
1586
- for (const m of html.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/gi)) {
1587
- for (const block of cssDeclBlocks(m[1])) {
1588
- for (const d of declsFromBlock(block)) out.push({ ...d, where: "style" });
1589
- }
1590
- }
1591
- return out;
1592
- }
1593
- function inlineStyleDecls(html) {
1594
- const out = [];
1595
- for (const m of html.matchAll(/style\s*=\s*(["'])([\s\S]*?)\1/gi)) {
1596
- for (const d of declsFromBlock(m[2])) out.push({ ...d, where: "inline" });
1597
- }
1598
- return out;
1599
- }
1600
- function inlineSizingDrift(html) {
1601
- const out = [];
1602
- for (const m of html.matchAll(/<([a-z][\w-]*)\b([^>]*)>/gi)) {
1603
- const attrs = m[2];
1604
- const cls = /\bclass\s*=\s*(["'])([\s\S]*?)\1/i.exec(attrs);
1605
- const style = /\bstyle\s*=\s*(["'])([\s\S]*?)\1/i.exec(attrs);
1606
- if (!cls || !style) continue;
1607
- const sized = declsFromBlock(style[2]).filter((d) => SIZING_PROP.test(d.prop));
1608
- if (sized.length) {
1609
- out.push({
1610
- rule: "inline-sizing-drift",
1611
- level: "warn",
1612
- tag: m[1],
1613
- class: cls[2].trim(),
1614
- props: sized.map((d) => d.prop).join(", "),
1615
- message: `<${m[1]} class="${cls[2].trim()}"> carries inline sizing (${sized.map((d) => d.prop).join(", ")}) \u2014 move it to the shared class so siblings can't drift`
1616
- });
1617
- }
1618
- }
1619
- return out;
1620
- }
1621
- function lintDesign(html, opts = {}) {
1622
- const { designSystem = null } = opts;
1623
- const errors = [];
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
- }
1634
- const decls = [...styleBlockDecls(html), ...inlineStyleDecls(html)];
1635
- for (const d of decls) {
1636
- if (SPACING_PROP.test(d.prop)) {
1637
- for (const px of pxValues(d.value)) {
1638
- const scale = opts.spacing ?? designSystem?.spacing;
1639
- const onScale = scale?.length ? scale.includes(Math.abs(px)) : isOnSpacingScale(px);
1640
- if (!onScale) {
1641
- errors.push({
1642
- rule: "spacing-off-grid",
1643
- level: "error",
1644
- prop: d.prop,
1645
- value: `${px}px`,
1646
- suggestion: `${nearestSpacing(px)}px`,
1647
- where: d.where,
1648
- message: `${d.prop}: ${px}px is off the 4-point grid (${d.where}) \u2192 use ${nearestSpacing(px)}px`
1649
- });
1650
- }
1651
- }
1652
- }
1653
- if (COLOR_PROP.test(d.prop)) {
1654
- for (const lit of literalColors(d.value)) {
1655
- warnings.push({
1656
- rule: "color-not-token",
1657
- level: "warn",
1658
- prop: d.prop,
1659
- value: lit,
1660
- where: d.where,
1661
- message: `${d.prop}: ${lit} is a raw color \u2014 use a design-system token via var(--\u2026)`
1662
- });
1663
- }
1664
- }
1665
- if ((d.prop === "font-family" || d.prop === "font") && designSystem?.fonts?.length) {
1666
- const fam = firstFontFamily(d.value);
1667
- const allowed = new Set(designSystem.fonts.map((f) => String(f.family || "").toLowerCase()));
1668
- if (fam && !allowed.has(fam) && !SYSTEM_FONTS.has(fam)) {
1669
- warnings.push({
1670
- rule: "font-not-token",
1671
- level: "warn",
1672
- value: fam,
1673
- where: d.where,
1674
- message: `font "${fam}" is not in the design system (${[...allowed].join(", ") || "none"})`
1675
- });
1676
- }
1677
- }
1678
- }
1679
- for (const block of declBlocks(html)) {
1680
- const c = block.find((d) => d.prop === "color");
1681
- const bg = block.find((d) => d.prop === "background" || d.prop === "background-color");
1682
- if (!c || !bg) continue;
1683
- const fg = firstColor(c.value);
1684
- const back = firstColor(bg.value);
1685
- if (!fg || !back) continue;
1686
- const ratio = contrastRatio(fg, back);
1687
- if (ratio != null && ratio < AA_NORMAL) {
1688
- errors.push({
1689
- rule: "contrast-below-aa",
1690
- level: "error",
1691
- value: `${ratio.toFixed(1)}:1`,
1692
- fg,
1693
- bg: back,
1694
- message: `text/background contrast ${ratio.toFixed(1)}:1 is below AA 4.5:1 (${fg} on ${back})`
1695
- });
1696
- }
1697
- }
1698
- warnings.push(...inlineSizingDrift(html));
1699
- return {
1700
- ok: errors.length === 0,
1701
- errors,
1702
- warnings,
1703
- declarations: decls.length,
1704
- summary: `${errors.length} error(s), ${warnings.length} warning(s)`
1705
- };
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
- }
1758
- function lintCanvasData(data, { frames } = {}) {
1759
- const errors = [];
1760
- for (const section of data?.sections || []) {
1761
- for (const a of section.artboards || []) {
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 });
1765
- if (!accepted) {
1766
- errors.push({
1767
- rule: "frame-not-canonical",
1768
- level: "error",
1769
- artboard: a.id || a.label || "(unnamed)",
1770
- value: `${a.width}\xD7${a.height}`,
1771
- suggestion: `${FRAMES.desktop.w}\xD7${FRAMES.desktop.h}`,
1772
- message: `artboard "${a.id || a.label || "?"}" is ${a.width}\xD7${a.height} \u2014 use the canonical ${FRAMES.desktop.w}\xD7${FRAMES.desktop.h} desktop frame`
1773
- });
1774
- }
1775
- }
1776
- }
1777
- return { ok: errors.length === 0, errors };
1778
- }
1779
- function extractCanvasData(html) {
1780
- const m = /(?:var\s+DATA\s*=|__CANVAS_DATA\s*=)\s*(\{[\s\S]*?\})\s*;/.exec(html);
1781
- if (!m) return null;
1782
- try {
1783
- return JSON.parse(m[1]);
1784
- } catch {
1785
- return null;
1786
- }
1787
- }
1788
- var isMain = process.argv[1] && fileURLToPath(new URL("./runtime/packages/design/lib/design/lint.mjs", import.meta.url).href) === process.argv[1];
1789
- if (isMain) {
1790
- const expectStyles = process.argv.includes("--expect-styles");
1791
- const files = process.argv.slice(2).filter((a) => a !== "--expect-styles");
1792
- if (!files.length) {
1793
- console.error("usage: node lib/design/lint.mjs [--expect-styles] <file.html> [<file2.html> \u2026]");
1794
- process.exit(2);
1795
- }
1796
- let totalErrors = 0;
1797
- let emptyParsed = false;
1798
- for (const file of files) {
1799
- let html;
1800
- try {
1801
- html = readFileSync(file, "utf-8");
1802
- } catch (e) {
1803
- console.error(`\u2717 cannot read ${file}: ${e.message}`);
1804
- totalErrors += 1;
1805
- continue;
1806
- }
1807
- if (/\.s?css$/i.test(file) || !/<style[\s>]/i.test(html) && /\{[^}]*:[^}]*\}/.test(html)) {
1808
- html = `<style>${html}</style>`;
1809
- }
1810
- const res = lintDesign(html);
1811
- const data = extractCanvasData(html);
1812
- const frame = data ? lintCanvasData(data) : { ok: true, errors: [] };
1813
- const allErrors = [...res.errors, ...frame.errors];
1814
- totalErrors += allErrors.length;
1815
- console.log(
1816
- `
1817
- ${file} \u2014 ${res.declarations} declaration(s), ${allErrors.length} error(s), ${res.warnings.length} warning(s)`
1818
- );
1819
- for (const e of allErrors) console.log(` \u2717 [${e.rule}] ${e.message}`);
1820
- for (const w of res.warnings) console.log(` \u26A0 [${w.rule}] ${w.message}`);
1821
- if (res.declarations === 0) {
1822
- emptyParsed = true;
1823
- console.log(
1824
- ` \u26A0 [no-styles-parsed] 0 CSS declarations found \u2014 point at COMPILED CSS, or wrap raw CSS as <style>\u2026</style>${expectStyles ? " (fails --expect-styles)" : ""}`
1825
- );
1826
- } else if (!allErrors.length && !res.warnings.length) {
1827
- console.log(" \u2713 clean");
1828
- }
1829
- }
1830
- process.exit(totalErrors ? 1 : expectStyles && emptyParsed ? 3 : 0);
1831
- }
1832
-
1833
- // packages/design/lib/design/recommend-format.mjs
1834
- var DESIGN_FORMATS = Object.freeze(["prototype", "walkthrough", "canvas"]);
1835
- var EXPLORATORY_KEYWORDS = Object.freeze([
1836
- "option",
1837
- "options",
1838
- "concept",
1839
- "concepts",
1840
- "explore",
1841
- "exploration",
1842
- "variant",
1843
- "variants",
1844
- "moodboard",
1845
- "brainstorm",
1846
- "compare",
1847
- "comparison"
1848
- ]);
1849
-
1850
- // packages/design/lib/design/manifest.mjs
1851
- var DESIGN_SOURCES = Object.freeze(["spec", "png", "describe"]);
1852
- var CONTENT_PROVENANCE = Object.freeze(["spec", "inferred"]);
1853
- var FRAMEWORKS = Object.freeze(["vanilla", "react"]);
1854
- var NAV_MODES = Object.freeze(["anchor", "lazy"]);
1855
- var SCHEMA_VERSION = "1.0.0";
1856
- function defaultFramework(designFormat) {
1857
- return designFormat === "canvas" ? "react" : "vanilla";
1858
- }
1859
- function buildManifest({
1860
- designFormat,
1861
- source,
1862
- generatedAt,
1863
- screens = [],
1864
- contentProvenance = "spec",
1865
- framework,
1866
- navMode = null,
1867
- screenName = "",
1868
- iterations = 0,
1869
- branch = "",
1870
- specId = "",
1871
- htmlFile = "",
1872
- pretextTier = ""
1873
- } = {}) {
1874
- if (!designFormat) throw new Error("buildManifest: designFormat is required");
1875
- if (!source) throw new Error("buildManifest: source is required");
1876
- if (!generatedAt) throw new Error("buildManifest: generatedAt is required");
1877
- const manifest = {
1878
- schema_version: SCHEMA_VERSION,
1879
- design_format: designFormat,
1880
- source,
1881
- content_provenance: contentProvenance,
1882
- framework: framework ?? defaultFramework(designFormat),
1883
- screens: [...screens],
1884
- screen_count: screens.length,
1885
- iterations,
1886
- generated_at: generatedAt
1887
- };
1888
- if (navMode) manifest.nav_mode = navMode;
1889
- if (screenName) manifest.screen_name = screenName;
1890
- if (branch) manifest.branch = branch;
1891
- if (specId) manifest.spec_id = specId;
1892
- if (htmlFile) manifest.html_file = htmlFile;
1893
- if (pretextTier) manifest.pretext_tier = pretextTier;
1894
- return manifest;
1895
- }
1896
-
1897
- // packages/design/lib/design/studio.mjs
1898
- import { createHash as createHash2 } from "node:crypto";
1899
- import { readFileSync as readFileSync3 } from "node:fs";
1900
-
1901
- // packages/artifact/lib/artifact/internal/runtime-asset.mjs
1902
- import { createHash } from "node:crypto";
1903
- import {
1904
- closeSync,
1905
- constants,
1906
- existsSync,
1907
- fstatSync,
1908
- lstatSync,
1909
- openSync,
1910
- readFileSync as readFileSync2,
1911
- readSync
1912
- } from "node:fs";
1913
- import { resolve } from "node:path";
1914
- import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
1915
- var DIGEST = /^[a-f0-9]{64}$/u;
1916
- var MAX_FRAGMENT_BYTES = 128 * 1024;
1917
- var MAX_SOURCE_BYTES = 256 * 1024;
1918
- var MAX_ASSET_BYTES = 16 * 1024 * 1024;
1919
- var MAX_SOURCES = 256;
1920
- var MAX_SCOPES = 16;
1921
- var MAX_SCOPE_TEXT_BYTES = 4096;
1922
- var MAX_MANIFEST_BYTES = 1024 * 1024;
1923
- var SCOPE_ID = /^[a-z][a-z0-9-]{0,63}$/u;
1924
- function isRecord(value) {
1925
- return value !== null && typeof value === "object" && !Array.isArray(value);
1926
- }
1927
- var digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
1928
- function boundedRead(url, label, { limit, exact: exact2, links = false }) {
1929
- if (!links) {
1930
- const stat = lstatSync(url, { throwIfNoEntry: false });
1931
- if (!stat?.isFile()) throw new Error(`${label} must be a regular file, not a link.`);
1932
- }
1933
- const descriptor = openSync(
1934
- fileURLToPath2(url),
1935
- constants.O_RDONLY | (links ? 0 : constants.O_NOFOLLOW ?? 0)
1936
- );
1937
- try {
1938
- const stat = fstatSync(descriptor);
1939
- if (!stat.isFile()) throw new Error(`${label} must be a regular file, not a link.`);
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;
1943
- const buffer = Buffer.alloc(capacity);
1944
- let length = 0;
1945
- for (let read = -1; read !== 0 && length < capacity; length += read)
1946
- read = readSync(descriptor, buffer, length, capacity - length, null);
1947
- if (length === capacity) throw new Error(`${label} changed size while it was read.`);
1948
- if (exact2 !== void 0 && length !== exact2)
1949
- throw new Error(`${label} changed size while it was read.`);
1950
- return buffer.subarray(0, length);
1951
- } finally {
1952
- closeSync(descriptor);
1953
- }
1954
- }
1955
- function sourceManifest(value, basename) {
1956
- const path = new RegExp(
1957
- `^${basename.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}\\.sources/\\d{2,4}-[a-z0-9-]+\\.js$`,
1958
- "u"
1959
- );
1960
- if (!isRecord(value) || value.kind !== "openplanr-runtime-asset-sources" || value.schemaVersion !== "1.0.0" || value.asset !== basename || typeof value.sha256 !== "string" || !DIGEST.test(value.sha256) || !Number.isSafeInteger(value.bytes) || value.bytes <= 0 || value.bytes > MAX_ASSET_BYTES || !Array.isArray(value.scopes) || !value.scopes.length || value.scopes.length > MAX_SCOPES || !Array.isArray(value.sources) || !value.sources.length || value.sources.length > MAX_SOURCES)
1961
- throw new Error("Runtime source manifest is invalid.");
1962
- const ids = /* @__PURE__ */ new Set();
1963
- const scopes = value.scopes.map((scope, index) => {
1964
- if (!isRecord(scope) || typeof scope.id !== "string" || !SCOPE_ID.test(scope.id) || ids.has(scope.id) || (index === 0 ? scope.parent !== null : typeof scope.parent !== "string" || !ids.has(scope.parent)) || typeof scope.open !== "string" || typeof scope.close !== "string" || Buffer.byteLength(scope.open) > MAX_SCOPE_TEXT_BYTES || Buffer.byteLength(scope.close) > MAX_SCOPE_TEXT_BYTES)
1965
- throw new Error("Runtime source scope is invalid.");
1966
- ids.add(scope.id);
1967
- return scope;
1968
- });
1969
- const paths = /* @__PURE__ */ new Set();
1970
- const sources = value.sources.map((source) => {
1971
- if (!isRecord(source) || typeof source.path !== "string" || !path.test(source.path) || paths.has(source.path) || typeof source.scope !== "string" || !ids.has(source.scope) || !Number.isSafeInteger(source.bytes) || source.bytes <= 0 || source.bytes >= MAX_SOURCE_BYTES || typeof source.sha256 !== "string" || !DIGEST.test(source.sha256))
1972
- throw new Error("Runtime source identity is invalid.");
1973
- paths.add(source.path);
1974
- return source;
1975
- });
1976
- return { bytes: value.bytes, sha256: value.sha256, scopes, sources };
1977
- }
1978
- function readSourceUnits(url, basename) {
1979
- const manifestUrl = new URL(`${basename}.sources.json`, url);
1980
- const manifest = boundedRead(manifestUrl, "Runtime source manifest", {
1981
- limit: MAX_MANIFEST_BYTES
1982
- });
1983
- const expected = sourceManifest(JSON.parse(manifest.toString("utf8")), basename);
1984
- const directory = lstatSync(new URL(`${basename}.sources`, url), { throwIfNoEntry: false });
1985
- if (!directory?.isDirectory()) throw new Error("Runtime source directory must not be a link.");
1986
- const byId = new Map(expected.scopes.map((scope) => [scope.id, scope]));
1987
- const parts = [];
1988
- const open = [];
1989
- const closed = /* @__PURE__ */ new Set();
1990
- let total = 0;
1991
- const append = (bytes2) => {
1992
- total += bytes2.length;
1993
- if (total > expected.bytes) throw new Error("Runtime sources exceed their declared size.");
1994
- parts.push(bytes2);
1995
- };
1996
- const close = () => {
1997
- const scope = open.pop();
1998
- if (!scope) return;
1999
- closed.add(scope.id);
2000
- append(Buffer.from(scope.close, "utf8"));
2001
- };
2002
- for (const source of expected.sources) {
2003
- const chain = [];
2004
- for (let scope = byId.get(source.scope); scope; scope = byId.get(scope.parent ?? ""))
2005
- chain.unshift(scope);
2006
- while (open.length && !chain.includes(open[open.length - 1])) close();
2007
- for (const scope of chain.slice(open.length)) {
2008
- if (closed.has(scope.id)) throw new Error("Runtime source scopes are not contiguous.");
2009
- open.push(scope);
2010
- append(Buffer.from(scope.open, "utf8"));
2011
- }
2012
- const unitUrl = new URL(source.path, url);
2013
- const bytes2 = boundedRead(unitUrl, `Runtime source unit ${source.path}`, {
2014
- limit: MAX_SOURCE_BYTES,
2015
- exact: source.bytes
2016
- });
2017
- if (digest(bytes2) !== source.sha256)
2018
- throw new Error("Runtime source unit failed integrity verification.");
2019
- append(bytes2);
2020
- }
2021
- while (open.length) close();
2022
- const bytes = Buffer.concat(parts);
2023
- if (bytes.length !== expected.bytes || digest(bytes) !== expected.sha256)
2024
- throw new Error("Runtime sources failed integrity verification.");
2025
- return bytes;
2026
- }
2027
- function readRuntimeAsset(file) {
2028
- const url = typeof file === "string" ? pathToFileURL(resolve(file)) : file;
2029
- if (existsSync(url)) return readFileSync2(url);
2030
- const basename = url.pathname.split("/").at(-1);
2031
- if (!basename) throw new Error("Studio runtime asset identity is invalid.");
2032
- if (lstatSync(new URL(`${basename}.sources.json`, url), { throwIfNoEntry: false }))
2033
- return readSourceUnits(url, basename);
2034
- const manifest = JSON.parse(
2035
- boundedRead(new URL(`${basename}.parts.json`, url), "Studio runtime fragment manifest", {
2036
- limit: MAX_MANIFEST_BYTES,
2037
- links: true
2038
- }).toString("utf8")
2039
- );
2040
- if (!isRecord(manifest) || manifest.schemaVersion !== "1.0.0" || typeof manifest.sha256 !== "string" || !DIGEST.test(manifest.sha256) || !Array.isArray(manifest.parts) || !manifest.parts.length || manifest.parts.length > 64)
2041
- throw new Error("Studio runtime fragment manifest is invalid.");
2042
- const parts = manifest.parts.map((part, index) => {
2043
- if (!isRecord(part) || part.name !== `${basename}.part-${String(index + 1).padStart(3, "0")}` || typeof part.sha256 !== "string" || !DIGEST.test(part.sha256))
2044
- throw new Error("Studio runtime fragment identity is invalid.");
2045
- const bytes2 = boundedRead(new URL(part.name, url), "Studio runtime fragment", {
2046
- limit: MAX_FRAGMENT_BYTES,
2047
- links: true
2048
- });
2049
- if (createHash("sha256").update(bytes2).digest("hex") !== part.sha256)
2050
- throw new Error("Studio runtime fragment failed integrity verification.");
2051
- return bytes2;
2052
- });
2053
- const bytes = Buffer.concat(parts);
2054
- if (createHash("sha256").update(bytes).digest("hex") !== manifest.sha256)
2055
- throw new Error("Studio runtime failed integrity verification.");
2056
- return bytes;
2057
- }
2058
-
2059
- // packages/design/lib/design/studio-render.mjs
2060
- var DESIGN_STUDIO_VERSION = "1.9.0";
2061
- var DESIGN_STUDIO_ASSETS = Object.freeze({
2062
- style: "templates/studio/studio.css",
2063
- runtime: "templates/studio/studio.js",
2064
- enhancementsStyle: "templates/studio/enhancements.css",
2065
- handoffCenterStyle: "templates/studio/handoff-center.css"
2066
- });
2067
- function applyDesignStudioTheme(preference) {
2068
- if (!preference) {
2069
- try {
2070
- preference = localStorage.getItem("openplanr.design.theme");
2071
- } catch {
2072
- }
2073
- }
2074
- if (!["dark", "light", "system"].includes(preference)) preference = "dark";
2075
- const resolved = preference === "system" ? globalThis.matchMedia?.("(prefers-color-scheme: light)").matches ? "light" : "dark" : preference;
2076
- Object.assign(document.documentElement.dataset, {
2077
- planrTheme: resolved,
2078
- designTheme: resolved,
2079
- designThemePreference: preference
2080
- });
2081
- const modelNode = document.getElementById("planr-artifact-shell-model");
2082
- if (modelNode) {
2083
- try {
2084
- const model = JSON.parse(modelNode.textContent);
2085
- model.theme = resolved;
2086
- modelNode.textContent = JSON.stringify(model);
2087
- } catch {
2088
- }
2089
- }
2090
- return { preference, resolved };
2091
- }
2092
- function applyDesignStudioResourcePolicy() {
2093
- const root = document.querySelector(".planr-shell");
2094
- if (!root || !document.documentElement.hasAttribute("data-design-studio")) return;
2095
- if (globalThis.matchMedia?.("(pointer: coarse)").matches) {
2096
- root.dataset.planrFrameBudget = "3";
2097
- root.dataset.designResourceMode = "bounded";
2098
- }
2099
- }
2100
- function designStudioThemeBootstrapSource() {
2101
- return `(${applyDesignStudioTheme.toString()})();(${applyDesignStudioResourcePolicy.toString()})();`;
2102
- }
2103
- function button(label, attributes = "", className = "") {
2104
- return `<button type="button"${className ? ` class="${className}"` : ""} ${attributes}>${escapeHtml(label)}</button>`;
2105
- }
2106
- var icons = {
2107
- left: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M9 4v16"/>',
2108
- right: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M15 4v16"/>',
2109
- canvas: '<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>',
2110
- prototype: '<path d="m8 4 12 8-12 8Z"/>',
2111
- walkthrough: '<rect x="3" y="4" width="18" height="14" rx="2"/><path d="m9 22 3-4 3 4M9 9h6M9 13h3"/>',
2112
- share: '<path d="M12 16V3m-4 4 4-4 4 4M5 13v6a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6"/>',
2113
- export: '<path d="M12 3v12m-4-4 4 4 4-4M5 16v4h14v-4"/>',
2114
- pointer: '<path d="m5 3 15 9-7 1-3 7Z"/>',
2115
- comment: '<path d="M21 11a8 8 0 0 1-8 8H7l-4 3V11a9 9 0 0 1 18 0Z"/><path d="M8 9h8M8 13h5"/>'
2116
- };
2117
- function icon(name) {
2118
- return `<svg class="design-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${icons[name]}</svg>`;
2119
- }
2120
- function iconButton(label, name, attributes = "", className = "") {
2121
- return `<button type="button" class="${className}" ${attributes} title="${escapeHtml(label)}" aria-label="${escapeHtml(label)}">${icon(name)}<span class="design-button-label">${escapeHtml(label)}</span></button>`;
2122
- }
2123
- function toolbar(document2) {
2124
- return `<header class="planr-toolbar design-toolbar">
2125
- <div class="design-toolbar-leading">
2126
- ${iconButton("Screens", "left", 'data-design-toggle-nav aria-controls="design-navigator" aria-expanded="true"', "planr-toolbar-action design-panel-toggle")}
2127
- <div class="planr-brand">${renderPlanrMark()}<span class="design-wordmark" aria-label="OpenPlanr">Open<span>Planr</span></span><span class="planr-title-block"><strong title="${escapeHtml(document2.title)}">${escapeHtml(document2.title)}</strong></span></div>
2128
- </div>
2129
- <div class="planr-segment design-view-picker" role="group" aria-label="Design view">${["canvas", "prototype", "walkthrough"].map((view) => iconButton(view[0].toUpperCase() + view.slice(1), view, `data-design-view="${view}" aria-pressed="${document2.defaultView === view}"`)).join("")}</div>
2130
- <div class="design-toolbar-trailing">
2131
- <span class="design-preview-state" role="status" data-design-preview-state>Loading preview</span>
2132
- <span class="design-save-state" role="status" aria-live="polite" data-design-save-state>Loading studio</span>
2133
- ${iconButton("Review", "right", 'data-planr-action="feedback" data-planr-review-label="Review" aria-controls="planr-review-rail" aria-expanded="true"', "planr-toolbar-action design-review-toggle")}
2134
- ${iconButton("Share design", "share", 'data-planr-action="share" aria-haspopup="dialog"', "planr-toolbar-action design-share")}
2135
- <details class="design-export"><summary aria-label="Export" title="Export">${icon("export")}</summary><div>${button("Portable HTML", 'data-design-export="html"')}${button("Screen PNG", 'data-design-export="png"')}</div></details>
2136
- </div>
2137
- </header>`;
2138
- }
2139
- function navigator(document2) {
2140
- const failed = document2.variants.filter(({ status }) => status === "failed");
2141
- return `<nav class="design-navigator" id="design-navigator" aria-label="Design screens">
2142
- <div class="design-nav-title"><strong>Screens <span>${document2.screenOrder.length}</span></strong>${iconButton("Close screens", "left", 'data-design-toggle-nav aria-controls="design-navigator" aria-expanded="true"', "design-nav-close")}</div>
2143
- <label class="design-field" for="design-variant">Direction<select id="design-variant" data-design-variant>${document2.variants.map((variant) => `<option value="${escapeHtml(variant.id)}"${variant.status !== "ready" ? " disabled" : ""}>${escapeHtml(variant.label)}${variant.status === "failed" ? " \u2014 unavailable" : ""}</option>`).join("")}</select></label>
2144
- ${document2.variants.filter(({ status }) => status === "ready").length > 1 ? `<label class="design-compare"><input type="checkbox" data-design-compare> Compare directions</label>` : ""}
2145
- <label class="design-field design-screen-search">Find a screen<input type="search" data-design-screen-search placeholder="Search screens" aria-label="Search screens"></label>
2146
- ${document2.flows?.length ? `<label class="design-field">Journey<select data-design-screen-group aria-label="Filter screens by journey"><option value="">All screens</option>${document2.flows.map((flow) => `<option value="${escapeHtml(flow.id)}">${escapeHtml(flow.title)}</option>`).join("")}</select></label>` : ""}
2147
- <p data-design-search-empty hidden>No screens match this search.</p>
2148
- <div class="design-screen-list">${document2.screenOrder.map((screenId, index) => {
2149
- const screen = document2.screens.find(({ id }) => id === screenId);
2150
- return `<button type="button" class="design-screen" data-design-screen="${escapeHtml(screen.id)}" aria-current="${index === 0 ? "page" : "false"}" title="${escapeHtml(screen.title)}"><span class="design-screen-number" aria-hidden="true">${String(index + 1).padStart(2, "0")}</span><span>${escapeHtml(screen.title)}</span></button>`;
2151
- }).join("")}</div>
2152
- <div class="design-nav-footer"><span data-design-verification>Browser inspection pending</span><span class="design-local">Local workspace</span></div>
2153
- ${failed.length ? `<details class="design-failed-variants"><summary>${failed.length} unavailable ${failed.length === 1 ? "direction" : "directions"}</summary>${failed.map((variant) => `<p><strong>${escapeHtml(variant.label)}</strong><br>${escapeHtml(variant.issue ?? "Generation did not complete. The previous design remains available.")}</p>`).join("")}</details>` : ""}
2154
- </nav>`;
2155
- }
2156
- function designNotes(document2) {
2157
- const screens = document2.screens.filter(({ description }) => description);
2158
- if (!screens.length) return "";
2159
- return `<details class="design-guidance" data-design-notes><summary aria-controls="design-guidance-panel" aria-expanded="false">Notes <span>${screens.length}</span></summary><div class="design-guidance-panel" id="design-guidance-panel" role="region" aria-labelledby="design-guidance-title"><header><div><strong id="design-guidance-title">Design notes</strong><p>Implementation context stays outside the product UI.</p></div><button type="button" data-design-close-notes aria-label="Close design notes" title="Close design notes">\xD7</button></header>${screens.map(
2160
- (screen, index) => `<details data-design-note-screen="${escapeHtml(screen.id)}"${index === 0 ? " open" : ""}><summary>${escapeHtml(screen.title)}</summary><p>${escapeHtml(screen.description)}</p></details>`
2161
- ).join("")}</div></details>`;
2162
- }
2163
- function stageDetails(document2) {
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>
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>
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>
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>`;
2168
- }
2169
- function directionDetails() {
2170
- return `<section class="planr-domain-rail design-direction-review" data-planr-slot="domain-rail" aria-label="Direction review"><div><strong data-design-direction-label>Direction</strong><span data-design-selected-direction></span></div><div class="design-rating" role="group" aria-label="Rate this direction">${[1, 2, 3, 4, 5].map((rating) => button("\u2606", `data-design-rating="${rating}" aria-label="Rate ${rating} out of 5" aria-pressed="false"`)).join("")}</div>${button("Use this direction", "data-design-select-direction")}<details class="design-refinement"><summary>Refine this direction</summary><div><label for="design-remix">Refinement note<textarea id="design-remix" maxlength="8192" data-design-remix placeholder="What should change in the next iteration?"></textarea></label>${button("Save refinement note", "data-design-save-remix")}<p data-design-review-hint>Saved with your review for the next iteration.</p></div></details></section>`;
2171
- }
2172
- function earlierFeedback(pins) {
2173
- if (!pins.length) return "";
2174
- return `<section class="design-stale-feedback" aria-label="Earlier feedback"><details open><summary>Earlier feedback <span>${pins.length}</span></summary><p>These comments refer to an earlier revision or a missing anchor. Review them before resolving.</p>${pins.map((pin) => `<article data-design-stale-pin="${escapeHtml(pin.id)}"><div><strong>${escapeHtml(pin.screenId ?? pin.anchor?.screen ?? "Earlier screen")}</strong><span>Stale</span></div><p>${escapeHtml(pin.comment)}</p>${pin.anchor?.planrId ? `<small>Anchor: ${escapeHtml(pin.anchor.planrId)}</small>` : ""}</article>`).join("")}</details></section>`;
2175
- }
2176
- function renderDesignStudioMarkup({
2177
- document: document2,
2178
- envelope,
2179
- entries,
2180
- state = null,
2181
- revision = null,
2182
- verification = null,
2183
- stalePins = [],
2184
- reviewContext = null,
2185
- contextDigest = null,
2186
- fingerprints = [],
2187
- contentIdentity = null
2188
- } = {}, {
2189
- stageRuntimeUrl = "./artifact-review-stage.js",
2190
- renderShell,
2191
- style = "",
2192
- runtime = "",
2193
- lazySources = false
2194
- } = {}) {
2195
- if (!document2 || !envelope)
2196
- throw new TypeError("Design studio requires a design document and artifact envelope.");
2197
- const artifactIds = new Set(envelope.artifacts.map(({ id }) => id));
2198
- for (const entry of entries) {
2199
- if (!artifactIds.has(entry.artifactId) || !document2.screens.some(({ id }) => id === entry.screenId) || !document2.variants.some(({ id, status }) => id === entry.variantId && status === "ready") || !document2.frames.some(({ id }) => id === entry.frameId)) {
2200
- throw new TypeError(`Invalid design studio entry: ${entry.artifactId}.`);
2201
- }
2202
- }
2203
- const activeEntry = entries.find(
2204
- ({ variantId, screenId, frameId }) => variantId === (state?.variantId ?? document2.selectedVariant) && screenId === (state?.screenId ?? document2.screenOrder[0]) && frameId === (state?.frameId ?? document2.frames[0].id)
2205
- );
2206
- if (!activeEntry)
2207
- throw new TypeError("Design studio requires the selected direction and first screen/frame.");
2208
- const payload = {
2209
- schemaVersion: DESIGN_STUDIO_VERSION,
2210
- document: document2,
2211
- entries,
2212
- state,
2213
- revision,
2214
- verification,
2215
- reviewContext,
2216
- contextDigest,
2217
- fingerprints,
2218
- contentIdentity,
2219
- artifactKinds: Object.fromEntries(
2220
- envelope.artifacts.map((artifact) => [artifact.id, artifact.kind])
2221
- ),
2222
- staticArtifacts: envelope.artifacts.filter(
2223
- (artifact) => artifact.kind !== "html" || !lazySources && /\bdata-(?:design|planr)-static(?:\s|=|>)/u.test(
2224
- resolveArtifactHtml(envelope, artifact)
2225
- )
2226
- ).map((artifact) => artifact.id)
2227
- };
2228
- let html = renderShell(
2229
- {
2230
- envelope,
2231
- viewer: {
2232
- mode: "single",
2233
- presentation: "canvas",
2234
- activeArtifactId: activeEntry.artifactId
2235
- },
2236
- shell: {
2237
- title: document2.title,
2238
- theme: "dark",
2239
- railOpen: true,
2240
- zoom: 100
2241
- }
2242
- },
2243
- { stageRuntimeUrl }
2244
- );
2245
- html = html.replace('class="planr-shell"', 'class="planr-shell" data-planr-frame-budget="3"');
2246
- html = html.replace(
2247
- /(<iframe\b[^>]*\bsandbox=")allow-scripts(")/g,
2248
- "$1allow-scripts allow-forms$2"
2249
- );
2250
- html = html.replace(/<header class="planr-toolbar">[\s\S]*?<\/header>/, toolbar(document2));
2251
- html = html.replace(
2252
- '<div class="planr-workspace">',
2253
- `<div class="planr-workspace">${navigator(document2)}`
2254
- );
2255
- html = html.replace(
2256
- '<main class="planr-stage" aria-label="Artifact review stage">',
2257
- `<main class="planr-stage" aria-label="Design canvas">${stageDetails(document2)}`
2258
- );
2259
- html = html.replace(/<section class="planr-domain-rail"[^>]*><\/section>/, directionDetails());
2260
- html = html.replace("<h2>Review comments</h2>", "<h2>Review</h2>");
2261
- html = html.replace(
2262
- 'aria-label="Close comments">\xD7',
2263
- `aria-label="Close review" title="Close review">${icon("right")}`
2264
- );
2265
- html = html.replace("Overall note for the coding agent\u2026", "Summarize your review\u2026");
2266
- html = html.replace(
2267
- '<div class="planr-feedback-slot"',
2268
- `${earlierFeedback(stalePins)}<div class="design-comment-action">${iconButton("Add comment", "comment", 'data-planr-action="add-comment" aria-pressed="false"')}</div><div class="planr-feedback-slot"`
2269
- );
2270
- html = html.replace(
2271
- '<html lang="en"',
2272
- `<html lang="en" data-design-studio="${DESIGN_STUDIO_VERSION}" data-design-opening="true"`
2273
- );
2274
- html = html.replace(
2275
- "</head>",
2276
- `<style>${style}</style><script>${designStudioThemeBootstrapSource()}</script></head>`
2277
- );
2278
- html = html.replace(
2279
- "</body>",
2280
- `<script type="application/json" id="planr-design-studio-payload">${embedJson(payload)}</script><script>${designStudioThemeBootstrapSource()}</script><script>${runtime}</script></body>`
2281
- );
2282
- return html;
2283
- }
2284
-
2285
- // packages/design/lib/design/studio.mjs
2286
- var templateRoot = new URL("../../templates/studio/", new URL("./runtime/packages/design/lib/design/studio.mjs", import.meta.url).href);
2287
- function readDesignStudioRuntime() {
2288
- return readRuntimeAsset(new URL("studio.js", templateRoot)).toString("utf8");
2289
- }
2290
- function designStudioArtifactId(variantId, screenId, frameId) {
2291
- const id = [
2292
- "design",
2293
- ...[variantId, screenId, frameId].map((value) => `${value.length}-${value}`)
2294
- ].join(".");
2295
- return id.length <= 128 ? id : `design.${createHash2("sha256").update(JSON.stringify([variantId, screenId, frameId])).digest("hex")}`;
2296
- }
2297
- function createDesignStudioEntries(document2, envelope) {
2298
- const ids = new Set(envelope.artifacts.map(({ id }) => id));
2299
- const entries = [];
2300
- for (const variant of document2.variants.filter(({ status }) => status === "ready")) {
2301
- for (const screenId of document2.screenOrder) {
2302
- for (const frame of document2.frames) {
2303
- const artifactId = designStudioArtifactId(variant.id, screenId, frame.id);
2304
- if (!ids.has(artifactId))
2305
- throw new Error(`Design studio is missing artifact ${artifactId}.`);
2306
- entries.push({
2307
- artifactId,
2308
- variantId: variant.id,
2309
- screenId,
2310
- frameId: frame.id,
2311
- ...frame.height === "auto" ? { height: "auto" } : {}
2312
- });
2313
- }
2314
- }
2315
- }
2316
- return entries;
2317
- }
2318
- function renderDesignStudio(input = {}, options = {}) {
2319
- return renderDesignStudioMarkup(
2320
- {
2321
- ...input,
2322
- entries: input.entries ?? createDesignStudioEntries(input.document, input.envelope)
2323
- },
2324
- {
2325
- ...options,
2326
- renderShell: renderArtifactShellDocument,
2327
- style: readFileSync3(
2328
- new URL(new URL("./runtime/packages/artifact/lib/artifact/ui/studio-shell.css", import.meta.url).href),
2329
- "utf8"
2330
- ) + "\n" + ["studio.css", "enhancements.css", "handoff-center.css"].map((file) => readFileSync3(new URL(file, templateRoot), "utf8")).join("\n"),
2331
- runtime: readDesignStudioRuntime()
2332
- }
2333
- );
2334
- }
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
-
2431
- // packages/design/lib/design/document.mjs
2432
- var DESIGN_VIEWS = Object.freeze(["canvas", "prototype", "walkthrough"]);
2433
- var DESIGN_RENDERER_VERSION = "1.3.0";
2434
- function loadDesignDocument(file, { readSource } = {}) {
2435
- const checked = readSource?.(file, process.cwd());
2436
- const path = checked?.file ?? realpathSync(resolve2(file));
2437
- const document2 = assertDesignDocument(
2438
- checked ? JSON.parse(checked.value.toString("utf8")) : readJson(path)
2439
- );
2440
- return { path, root: dirname(path), document: document2 };
2441
- }
2442
- function inspectDesignDocument(file, { readSource } = {}) {
2443
- const { path, root, document: document2 } = loadDesignDocument(file, { readSource });
2444
- const ready = document2.variants.filter((variant) => variant.status === "ready").length;
2445
- const sourceCount = document2.screenOrder.length * ready;
2446
- const viewCount = sourceCount * document2.frames.length;
2447
- if (sourceCount > 256 || viewCount > 4096)
2448
- throw new RangeError(
2449
- `This board needs ${sourceCount} screen sources and ${viewCount} viewport references. Split it into linked boards: one board supports 256 sources and 4096 views.`
2450
- );
2451
- const sources = new Set(document2.assets ?? []);
2452
- if (existsSync2(join2(root, "review-context.json"))) sources.add("review-context.json");
2453
- if (document2.designSystem?.tokens) sources.add(document2.designSystem.tokens);
2454
- for (const screen of document2.screens)
2455
- for (const source of [
2456
- screen.source,
2457
- ...document2.variants.filter((variant) => variant.status === "ready").map((variant) => variant.sources?.[screen.id]).filter(Boolean)
2458
- ]) {
2459
- sources.add(source.html);
2460
- for (const item of [...source.styles ?? [], ...source.scripts ?? []]) sources.add(item);
2461
- }
2462
- const missing = [];
2463
- for (const source of sources) {
2464
- try {
2465
- if (readSource) readSource(source, root);
2466
- else resolveLocalDocumentFile(root, source);
2467
- } catch (error) {
2468
- missing.push({ path: source, message: error.message });
2469
- }
2470
- }
2471
- return {
2472
- ok: missing.length === 0,
2473
- path,
2474
- root,
2475
- document: document2,
2476
- sources: [...sources],
2477
- missing,
2478
- specPath: designSpecPath(root),
2479
- // Guarded source preparation is independent of local render cache state.
2480
- current: readSource ? null : readJson(join2(root, ".design/current.json"), null)
2481
- };
2482
- }
2483
- function prepareDesignDocument(file, { readSource, passive = false, maxBytes } = {}) {
2484
- const inspected = inspectDesignDocument(file, { readSource });
2485
- if (!inspected.ok)
2486
- throw new Error(inspected.missing.map((item) => `${item.path}: ${item.message}`).join("\n"));
2487
- const { document: document2, root } = inspected;
2488
- const reviewContext = loadReviewContext(root, document2, { readSource });
2489
- const contextDigest = reviewDigest(reviewContext);
2490
- const fingerprints = [];
2491
- const artifacts = [], sources = [], entries = [], lint = [], sourceFiles = new Set(inspected.sources);
2492
- const sourceContents = new Map(
2493
- inspected.sources.map((source) => [
2494
- source,
2495
- readSource ? readSource(source, root).value : readFileSync5(resolveLocalDocumentFile(root, source))
2496
- ])
2497
- );
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
- );
2509
- for (const screenId of document2.screenOrder) {
2510
- const screen = document2.screens.find((item) => item.id === screenId);
2511
- const values = Object.hasOwn(variant.props ?? {}, screenId) ? variant.props[screenId] : {};
2512
- const bundled = bundleLocalDocument({
2513
- root,
2514
- source: variant.sources?.[screenId] ?? screen.source,
2515
- sharedStyles: document2.designSystem?.tokens ? [document2.designSystem.tokens] : [],
2516
- screenId,
2517
- readSource,
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
- } : {},
2527
- ...maxBytes === void 0 ? {} : { maxBytes }
2528
- });
2529
- if (document2.frames.some(({ height }) => height === "auto"))
2530
- bundled.html = bundled.html.replace(
2531
- "</body>",
2532
- `<script>(${observeDesignFrameSize.toString()})()</script></body>`
2533
- );
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>`;
2535
- if (!passive) bundled.html = bundled.html.replace("</body>", `${navigate}</body>`);
2536
- for (const name of bundled.files) {
2537
- sourceFiles.add(name);
2538
- if (!sourceContents.has(name))
2539
- sourceContents.set(
2540
- name,
2541
- readSource ? readSource(name, root).value : readFileSync5(resolveLocalDocumentFile(root, name))
2542
- );
2543
- if (hash(sourceContents.get(name)) !== bundled.sourceDigests[name])
2544
- throw new Error(
2545
- `Source ${name} changed during rendering. Retry with the completed source revision.`
2546
- );
2547
- }
2548
- const report = lintDesign(bundled.html, {
2549
- designSystem: document2.designSystem,
2550
- screen,
2551
- variant
2552
- });
2553
- report.warnings.push(...themeWarnings.filter((item) => item.screenId === screenId));
2554
- report.summary = `${report.errors.length} error(s), ${report.warnings.length} warning(s)`;
2555
- lint.push({ variantId: variant.id, screenId, ...report });
2556
- for (const anchor of screen.anchors ?? []) {
2557
- if (!bundled.html.includes(`data-planr-id="${anchor}"`) && !bundled.html.includes(`id="${anchor}"`))
2558
- throw new Error(`Screen ${screenId} is missing its declared anchor ${anchor}.`);
2559
- }
2560
- const sourceId = `source-${hash(`${variant.id}:${screenId}`).slice(0, 32)}`;
2561
- sources.push({ id: sourceId, kind: "html", html: bundled.html });
2562
- for (const frame of document2.frames) {
2563
- fingerprints.push(
2564
- reviewFingerprints({
2565
- document: document2,
2566
- context: reviewContext,
2567
- screen,
2568
- variant,
2569
- frame,
2570
- sourceDigests: bundled.sourceDigests
2571
- })
2572
- );
2573
- const artifactId = designStudioArtifactId(
2574
- `${document2.id}-${variant.id}`,
2575
- screenId,
2576
- frame.id
2577
- );
2578
- artifacts.push({
2579
- id: artifactId,
2580
- kind: "html",
2581
- title: `${screen.title} \xB7 ${variant.label} \xB7 ${frame.label}`,
2582
- sourceId,
2583
- viewport: designFrameViewport(document2, frame),
2584
- colorScheme: "light"
2585
- });
2586
- entries.push({
2587
- artifactId,
2588
- screenId,
2589
- variantId: variant.id,
2590
- frameId: frame.id,
2591
- ...frame.height === "auto" ? { height: "auto" } : {}
2592
- });
2593
- }
2594
- }
2595
- }
2596
- const activeArtifactId = [...artifacts].sort((a, b) => a.id.localeCompare(b.id))[0].id;
2597
- const envelope = createSharedArtifactEnvelope({
2598
- sources,
2599
- artifacts,
2600
- viewer: {
2601
- mode: artifacts.length > 1 ? "variants" : "single",
2602
- activeArtifactId,
2603
- presentation: "canvas"
2604
- }
2605
- });
2606
- const revision = hash(
2607
- json({ document: document2, contextDigest, digest: digestArtifactEnvelope(envelope) })
2608
- );
2609
- return {
2610
- ...inspected,
2611
- reviewContext,
2612
- contextDigest,
2613
- fingerprints,
2614
- envelope,
2615
- entries,
2616
- revision,
2617
- lint,
2618
- sourceFiles: [...sourceFiles],
2619
- sourceContents
2620
- };
2621
- }
2622
- function stageRuntimeBytes() {
2623
- const stagePath = new URL(
2624
- "../../../artifact/templates/artifact-review-stage.js",
2625
- new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href
2626
- );
2627
- try {
2628
- return readRuntimeAsset(stagePath);
2629
- } catch {
2630
- return readRuntimeAsset(
2631
- new URL("../../templates/artifact-review-stage.js", new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href)
2632
- );
2633
- }
2634
- }
2635
- function designRendererRevision() {
2636
- return hash(
2637
- json({
2638
- version: DESIGN_RENDERER_VERSION,
2639
- stage: hash(stageRuntimeBytes()),
2640
- assets: ["studio.css", "studio.js", "enhancements.css", "handoff-center.css"].filter(
2641
- (name) => name === "studio.js" || existsSync2(new URL(`../../templates/studio/${name}`, new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href))
2642
- ).map(
2643
- (name) => hash(
2644
- name === "studio.js" ? readDesignStudioRuntime() : readFileSync5(new URL(`../../templates/studio/${name}`, new URL("./runtime/packages/design/lib/design/document.mjs", import.meta.url).href))
2645
- )
2646
- )
2647
- })
2648
- );
2649
- }
2650
- function standaloneDesignHtml(prepared, view = prepared.document.defaultView, {
2651
- parentOrigin = "null",
2652
- sourceTransport = parentOrigin === "null" ? "blob" : "srcdoc",
2653
- prototypeStateAliases
2654
- } = {}) {
2655
- const nonce = createArtifactBridgeNonce();
2656
- const pool = prepared.envelope.schemaVersion === "1.1.0";
2657
- const sources = pool ? Object.fromEntries(
2658
- prepared.envelope.sources.map((source) => [
2659
- source.id,
2660
- prepareArtifactSourceTemplate({
2661
- html: source.html,
2662
- nonce,
2663
- parentOrigin,
2664
- allowLocalForms: true,
2665
- prototypeState: true,
2666
- screenId: prepared.entries.find(
2667
- (entry) => prepared.envelope.artifacts.find((artifact) => artifact.id === entry.artifactId)?.sourceId === source.id
2668
- )?.screenId ?? source.id
2669
- })
2670
- ])
2671
- ) : null;
2672
- const artifacts = pool ? null : Object.fromEntries(
2673
- prepared.envelope.artifacts.map((artifact) => [
2674
- artifact.id,
2675
- prepareArtifactDocument({
2676
- html: resolveArtifactHtml(prepared.envelope, artifact),
2677
- artifactId: artifact.id,
2678
- nonce,
2679
- parentOrigin,
2680
- portable: true,
2681
- allowLocalForms: true,
2682
- prototypeState: true,
2683
- screenId: prepared.entries.find((entry) => entry.artifactId === artifact.id)?.screenId ?? artifact.id
2684
- }).html
2685
- ])
2686
- );
2687
- const stage = stageRuntimeBytes();
2688
- const stageRuntimeUrl = `data:text/javascript;base64,${Buffer.from(stage).toString("base64")}`;
2689
- const runtime = renderArtifactParentRuntime({
2690
- nonce,
2691
- ...pool ? {
2692
- inlineSources: sources,
2693
- inlineArtifactSources: Object.fromEntries(
2694
- prepared.envelope.artifacts.map((artifact) => [artifact.id, artifact.sourceId])
2695
- )
2696
- } : { inlineArtifacts: artifacts },
2697
- sourceTransport,
2698
- frameBudget: 3,
2699
- stageRuntimeUrl
2700
- });
2701
- const configuredRuntime = prototypeStateAliases ? `globalThis.__OPENPLANR_DESIGN_STUDIO_OPTIONS__=${JSON.stringify({ prototypeStateAliases }).replaceAll("<", "\\u003c")};
2702
- ${runtime}` : runtime;
2703
- const runtimeUrl = `data:text/javascript;base64,${Buffer.from(configuredRuntime).toString("base64")}`;
2704
- const state = { ...prepared.state, view };
2705
- if (state.selectedVariant) state.variantId = state.selectedVariant;
2706
- return renderDesignStudio(
2707
- {
2708
- ...prepared,
2709
- state,
2710
- verification: prepared.verification ?? { status: "unverified" }
2711
- },
2712
- { stageRuntimeUrl: runtimeUrl }
2713
- );
2714
- }
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, {
2734
- beforeCommit,
2735
- writePointer = atomicJson,
2736
- rendererRevision = designRendererRevision(),
2737
- now = () => (/* @__PURE__ */ new Date()).toISOString()
2738
- } = {}) {
2739
- const { root } = loadDesignDocument(file);
2740
- const work = join2(root, ".design");
2741
- let temporary;
2742
- try {
2743
- const prepared = prepareDesignDocument(file);
2744
- const errors = prepared.lint.flatMap(
2745
- (item) => item.errors.map((error) => `${item.screenId}: ${error.message}`)
2746
- );
2747
- if (errors.length) throw new Error(`Design lint failed:
2748
- ${errors.join("\n")}`);
2749
- const specPath = designSpecPath(root);
2750
- const spec = readFileSync5(specPath, "utf8");
2751
- for (let section = 1; section <= 10; section++)
2752
- if (!new RegExp(`^## ${section}\\. `, "m").test(spec))
2753
- throw new Error(`design-spec.md is missing section ${section}.`);
2754
- prepared.revision = hash(json({ source: prepared.revision, spec, rendererRevision }));
2755
- const directory = join2(work, "revisions", prepared.revision);
2756
- const previous = readJson(join2(work, "current.json"), null);
2757
- const generatedAt = now();
2758
- const manifest = existsSync2(directory) ? readJson(join2(directory, "render.json")).manifest : buildManifest({
2759
- framework: "vanilla",
2760
- designFormat: prepared.document.defaultView,
2761
- source: prepared.document.brief.source,
2762
- contentProvenance: prepared.document.brief.provenance,
2763
- generatedAt,
2764
- screens: prepared.document.screenOrder.map(
2765
- (id) => prepared.document.screens.find((item) => item.id === id).title
2766
- ),
2767
- iterations: previous && previous.revision !== prepared.revision ? (previous.iterations ?? 0) + 1 : previous?.iterations ?? 0,
2768
- htmlFile: `.design/revisions/${prepared.revision}/${prepared.document.defaultView}.html`
2769
- });
2770
- const record = {
2771
- reviewContext: prepared.reviewContext,
2772
- contextDigest: prepared.contextDigest,
2773
- fingerprints: prepared.fingerprints,
2774
- document: prepared.document,
2775
- envelope: prepared.envelope,
2776
- entries: prepared.entries,
2777
- revision: prepared.revision,
2778
- rendererRevision,
2779
- lint: prepared.lint,
2780
- manifest
2781
- };
2782
- if (!existsSync2(directory)) {
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);
2788
- for (const source of prepared.sourceFiles) {
2789
- const destination = join2(temporary, "sources", source);
2790
- mkdirSync(dirname(destination), { recursive: true });
2791
- writeFileSync(destination, prepared.sourceContents.get(source));
2792
- }
2793
- for (const view of DESIGN_VIEWS)
2794
- writeFileSync(join2(temporary, `${view}.html`), standaloneDesignHtml(record, view));
2795
- beforeCommit?.(record);
2796
- mkdirSync(dirname(directory), { recursive: true });
2797
- renameSync(temporary, directory);
2798
- temporary = null;
2799
- }
2800
- const manifestPath = join2(root, "finalized.json");
2801
- atomicJson(join2(work, "publication.json"), {
2802
- revision: prepared.revision,
2803
- previousRevision: previous?.revision ?? null,
2804
- manifest,
2805
- previousManifest: existsSync2(manifestPath) ? readFileSync5(manifestPath).toString("base64") : null
2806
- });
2807
- try {
2808
- atomicJson(manifestPath, manifest);
2809
- writePointer(join2(work, "current.json"), {
2810
- revision: prepared.revision,
2811
- previousRevision: previous?.revision === prepared.revision ? previous.previousRevision : previous?.revision ?? null,
2812
- iterations: manifest.iterations,
2813
- generatedAt: manifest.generated_at
2814
- });
2815
- rmSync(join2(work, "publication.json"), { force: true });
2816
- } catch (error) {
2817
- recoverDesignPublication(root, { ownsRenderLock: true });
2818
- throw error;
2819
- }
2820
- return {
2821
- ok: true,
2822
- revision: prepared.revision,
2823
- document: resolve2(file),
2824
- artifact: join2(directory, `${prepared.document.defaultView}.html`),
2825
- views: Object.fromEntries(
2826
- DESIGN_VIEWS.map((view) => [view, join2(directory, `${view}.html`)])
2827
- ),
2828
- manifest: join2(root, "finalized.json"),
2829
- spec: specPath,
2830
- verification: "unverified"
2831
- };
2832
- } finally {
2833
- if (temporary) rmSync(temporary, { recursive: true, force: true });
2834
- }
2835
- }
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
-
2918
- export {
2919
- mintCapabilityToken,
2920
- isCapabilityToken,
2921
- timingSafeTokenEqual,
2922
- prepareArtifactDocument,
2923
- createArtifactBridgeNonce,
2924
- renderArtifactParentRuntime,
2925
- matchesDesignFrame,
2926
- readRuntimeAsset,
2927
- renderDesignStudio,
2928
- saveDesignLayout,
2929
- saveDesignViewContext,
2930
- readDesignViewContext,
2931
- inspectDesignDocument,
2932
- prepareDesignDocument,
2933
- designRendererRevision,
2934
- standaloneDesignHtml,
2935
- renderDesignDocument,
2936
- withDesignRenderLock
2937
- };