openplanr 3.4.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 (336) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/cli/commands/design.d.ts +3 -0
  3. package/dist/cli/commands/design.d.ts.map +1 -0
  4. package/dist/cli/commands/design.js +137 -0
  5. package/dist/cli/commands/design.js.map +1 -0
  6. package/dist/cli/commands/groups/operations.d.ts.map +1 -1
  7. package/dist/cli/commands/groups/operations.js +2 -0
  8. package/dist/cli/commands/groups/operations.js.map +1 -1
  9. package/dist/dashboard/.vite/manifest.json +1 -1
  10. package/dist/dashboard/assets/{index-CvQAlBy3.js → index-B-l_941W.js} +2 -2
  11. package/dist/dashboard/assets/{index-CvQAlBy3.js.map → index-B-l_941W.js.map} +1 -1
  12. package/dist/dashboard/dashboard-manifest.json +13 -13
  13. package/dist/dashboard/index.html +1 -1
  14. package/dist/services/design-artifact-service.d.ts +22 -0
  15. package/dist/services/design-artifact-service.d.ts.map +1 -1
  16. package/dist/services/design-artifact-service.js +76 -16
  17. package/dist/services/design-artifact-service.js.map +1 -1
  18. package/dist/services/runtime-manager/runtime-package.js +1 -1
  19. package/dist/services/runtime-manager/runtime-package.js.map +1 -1
  20. package/docs/CLI.md +29 -0
  21. package/lib/host-packages/adapter-registry.json +5 -5
  22. package/lib/host-packages/capability-map.json +1 -1
  23. package/lib/host-packages/claude/.claude-plugin/marketplace.json +2 -2
  24. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +1 -1
  25. package/lib/host-packages/claude/openplanr/.openplanr-content.json +24 -340
  26. package/lib/host-packages/claude/openplanr/README.md +8 -8
  27. package/lib/host-packages/claude/openplanr/skills/artifact/references/design-sharing.md +2 -2
  28. package/lib/host-packages/claude/openplanr/skills/design/SKILL.md +23 -12
  29. package/lib/host-packages/claude/openplanr/skills/design/references/design-system.md +2 -2
  30. package/lib/host-packages/claude/openplanr/skills/design/references/generation.md +3 -3
  31. package/lib/host-packages/claude/openplanr/skills/design/references/hosted-canvas.md +6 -3
  32. package/lib/host-packages/claude/openplanr/skills/design/references/review.md +6 -6
  33. package/lib/host-packages/claude/openplanr/skills/design/references/team-review.md +3 -4
  34. package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +78 -38
  35. package/lib/host-packages/claude/openplanr/skills/design-loop/SKILL.md +15 -7
  36. package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-system.md +2 -2
  37. package/lib/host-packages/claude/openplanr/skills/design-loop/references/generation.md +3 -3
  38. package/lib/host-packages/claude/openplanr/skills/design-loop/references/review.md +6 -6
  39. package/lib/host-packages/claude/openplanr/skills/design-loop/references/team-review.md +3 -4
  40. package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +78 -38
  41. package/lib/host-packages/claude/openplanr/skills/design-review/SKILL.md +25 -5
  42. package/lib/host-packages/claude/openplanr/skills/design-review/references/design-system.md +2 -2
  43. package/lib/host-packages/claude/openplanr/skills/design-review/references/generation.md +3 -3
  44. package/lib/host-packages/claude/openplanr/skills/design-review/references/review.md +6 -6
  45. package/lib/host-packages/claude/openplanr/skills/design-review/references/team-review.md +3 -4
  46. package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +78 -38
  47. package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +7 -3
  48. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +23 -339
  49. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  50. package/lib/host-packages/cursor/openplanr/rules/planr-artifact/references/design-sharing.md +2 -2
  51. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-system.md +2 -2
  52. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/generation.md +3 -3
  53. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/hosted-canvas.md +6 -3
  54. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/review.md +6 -6
  55. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/team-review.md +3 -4
  56. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +78 -38
  57. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-system.md +2 -2
  58. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/generation.md +3 -3
  59. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/review.md +6 -6
  60. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/team-review.md +3 -4
  61. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +78 -38
  62. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop.mdc +15 -7
  63. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-system.md +2 -2
  64. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/generation.md +3 -3
  65. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/review.md +6 -6
  66. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/team-review.md +3 -4
  67. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +78 -38
  68. package/lib/host-packages/cursor/openplanr/rules/planr-design-review.mdc +25 -5
  69. package/lib/host-packages/cursor/openplanr/rules/planr-design.mdc +23 -12
  70. package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +7 -3
  71. package/lib/host-packages/openai/.claude-plugin/marketplace.json +2 -2
  72. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +1 -1
  73. package/lib/host-packages/openai/openplanr/.openplanr-content.json +27 -343
  74. package/lib/host-packages/openai/openplanr/skills/artifact/references/design-sharing.md +2 -2
  75. package/lib/host-packages/openai/openplanr/skills/design/SKILL.md +23 -12
  76. package/lib/host-packages/openai/openplanr/skills/design/openplanr.skill.json +0 -11
  77. package/lib/host-packages/openai/openplanr/skills/design/references/design-system.md +2 -2
  78. package/lib/host-packages/openai/openplanr/skills/design/references/generation.md +3 -3
  79. package/lib/host-packages/openai/openplanr/skills/design/references/hosted-canvas.md +6 -3
  80. package/lib/host-packages/openai/openplanr/skills/design/references/review.md +6 -6
  81. package/lib/host-packages/openai/openplanr/skills/design/references/team-review.md +3 -4
  82. package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +78 -38
  83. package/lib/host-packages/openai/openplanr/skills/design-loop/SKILL.md +15 -7
  84. package/lib/host-packages/openai/openplanr/skills/design-loop/openplanr.skill.json +0 -11
  85. package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-system.md +2 -2
  86. package/lib/host-packages/openai/openplanr/skills/design-loop/references/generation.md +3 -3
  87. package/lib/host-packages/openai/openplanr/skills/design-loop/references/review.md +6 -6
  88. package/lib/host-packages/openai/openplanr/skills/design-loop/references/team-review.md +3 -4
  89. package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +78 -38
  90. package/lib/host-packages/openai/openplanr/skills/design-review/SKILL.md +25 -5
  91. package/lib/host-packages/openai/openplanr/skills/design-review/openplanr.skill.json +0 -11
  92. package/lib/host-packages/openai/openplanr/skills/design-review/references/design-system.md +2 -2
  93. package/lib/host-packages/openai/openplanr/skills/design-review/references/generation.md +3 -3
  94. package/lib/host-packages/openai/openplanr/skills/design-review/references/review.md +6 -6
  95. package/lib/host-packages/openai/openplanr/skills/design-review/references/team-review.md +3 -4
  96. package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +78 -38
  97. package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +7 -3
  98. package/lib/host-packages/openai/openplanr/skills/plan/openplanr.skill.json +0 -11
  99. package/package.json +2 -2
  100. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-artifact-shell.mjs +0 -1772
  101. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +0 -2937
  102. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-entities.mjs +0 -439
  103. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +0 -2370
  104. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-loopback-server.mjs +0 -359
  105. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-parse5-parser.mjs +0 -3970
  106. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-parse5-tokenizer.mjs +0 -3501
  107. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review-state-store.mjs +0 -45
  108. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review.mjs +0 -3376
  109. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -38
  110. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-sandbox-guards.mjs +0 -1102
  111. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +0 -321
  112. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs +0 -1652
  113. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-9f6918b0.mjs +0 -1037
  114. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +0 -137
  115. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +0 -1500
  116. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -2023
  117. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +0 -2
  118. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +0 -18
  119. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +0 -814
  120. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +0 -10
  121. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +0 -2568
  122. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +0 -60
  123. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +0 -65
  124. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/enhancements.css +0 -388
  125. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/handoff-center.css +0 -81
  126. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.css +0 -1
  127. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +0 -139
  128. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +0 -1159
  129. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +0 -30
  130. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +0 -900
  131. 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
  132. 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
  133. 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
  134. 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
  135. 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
  136. 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
  137. 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
  138. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +0 -17
  139. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +0 -12
  140. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +0 -285
  141. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +0 -2773
  142. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +0 -134
  143. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +0 -2207
  144. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +0 -16
  145. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +0 -8
  146. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +0 -3883
  147. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +0 -966
  148. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/20-studio-shell.js +0 -520
  149. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +0 -1597
  150. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +0 -311
  151. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +0 -163
  152. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/registries/artifact-theme.json +0 -64
  153. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +0 -90
  154. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +0 -142
  155. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  156. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +0 -584
  157. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +0 -191
  158. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +0 -407
  159. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +0 -106
  160. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-handoff-readiness.schema.json +0 -398
  161. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-implementation-handoff.schema.json +0 -518
  162. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-planning-lineage.schema.json +0 -106
  163. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +0 -107
  164. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.14.0/artifact-theme.schema.json +0 -316
  165. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/artifact-envelope.schema.json +0 -408
  166. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/design-review-bundle.schema.json +0 -590
  167. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-document.schema.json +0 -506
  168. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +0 -822
  169. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +0 -346
  170. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +0 -1232
  171. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +0 -2611
  172. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -21
  173. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +0 -163
  174. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  175. package/lib/host-packages/claude/openplanr/skills/design/scripts/design.mjs +0 -12
  176. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/design.mjs +0 -12
  177. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/design.mjs +0 -12
  178. package/lib/host-packages/claude/openplanr/skills/plan/scripts/design.mjs +0 -12
  179. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/design.mjs +0 -12
  180. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/design.mjs +0 -12
  181. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/design.mjs +0 -12
  182. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/design.mjs +0 -12
  183. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-artifact-shell.mjs +0 -1772
  184. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +0 -2937
  185. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-entities.mjs +0 -439
  186. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +0 -2370
  187. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-loopback-server.mjs +0 -359
  188. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-parse5-parser.mjs +0 -3970
  189. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-parse5-tokenizer.mjs +0 -3501
  190. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review-state-store.mjs +0 -45
  191. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review.mjs +0 -3376
  192. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -38
  193. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-sandbox-guards.mjs +0 -1102
  194. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +0 -321
  195. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs +0 -1652
  196. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-9f6918b0.mjs +0 -1037
  197. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +0 -137
  198. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +0 -1500
  199. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -2023
  200. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +0 -2
  201. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +0 -18
  202. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +0 -814
  203. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +0 -10
  204. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +0 -2568
  205. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +0 -60
  206. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +0 -65
  207. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/enhancements.css +0 -388
  208. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/handoff-center.css +0 -81
  209. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.css +0 -1
  210. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +0 -139
  211. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +0 -1159
  212. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +0 -30
  213. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +0 -900
  214. 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
  215. 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
  216. 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
  217. 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
  218. 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
  219. 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
  220. 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
  221. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +0 -17
  222. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +0 -12
  223. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +0 -285
  224. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +0 -2773
  225. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +0 -134
  226. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +0 -2207
  227. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +0 -16
  228. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +0 -8
  229. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +0 -3883
  230. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +0 -966
  231. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/20-studio-shell.js +0 -520
  232. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +0 -1597
  233. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +0 -311
  234. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +0 -163
  235. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/registries/artifact-theme.json +0 -64
  236. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +0 -90
  237. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +0 -142
  238. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  239. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +0 -584
  240. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +0 -191
  241. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +0 -407
  242. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +0 -106
  243. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-handoff-readiness.schema.json +0 -398
  244. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-implementation-handoff.schema.json +0 -518
  245. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-planning-lineage.schema.json +0 -106
  246. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +0 -107
  247. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.14.0/artifact-theme.schema.json +0 -316
  248. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/artifact-envelope.schema.json +0 -408
  249. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/design-review-bundle.schema.json +0 -590
  250. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-document.schema.json +0 -506
  251. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +0 -822
  252. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +0 -346
  253. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +0 -1232
  254. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +0 -2611
  255. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -21
  256. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +0 -163
  257. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  258. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-artifact-shell.mjs +0 -1772
  259. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +0 -2937
  260. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-entities.mjs +0 -439
  261. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +0 -2370
  262. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-loopback-server.mjs +0 -359
  263. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-parse5-parser.mjs +0 -3970
  264. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-parse5-tokenizer.mjs +0 -3501
  265. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review-state-store.mjs +0 -45
  266. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review.mjs +0 -3376
  267. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -38
  268. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-sandbox-guards.mjs +0 -1102
  269. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +0 -321
  270. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs +0 -1652
  271. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-9f6918b0.mjs +0 -1037
  272. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +0 -137
  273. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +0 -1500
  274. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -2023
  275. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +0 -2
  276. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +0 -18
  277. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +0 -814
  278. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +0 -10
  279. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +0 -2568
  280. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +0 -60
  281. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +0 -65
  282. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/enhancements.css +0 -388
  283. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/handoff-center.css +0 -81
  284. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.css +0 -1
  285. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +0 -139
  286. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +0 -1159
  287. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +0 -30
  288. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +0 -900
  289. 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
  290. 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
  291. 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
  292. 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
  293. 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
  294. 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
  295. 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
  296. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +0 -17
  297. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +0 -12
  298. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +0 -285
  299. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +0 -2773
  300. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-studio-shell.js +0 -134
  301. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +0 -2207
  302. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-design-review-experience.js +0 -16
  303. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-studio-shell.js +0 -8
  304. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/18-interface-primitives.js +0 -3883
  305. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/19-interface-primitives.js +0 -966
  306. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/20-studio-shell.js +0 -520
  307. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +0 -1597
  308. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +0 -311
  309. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +0 -163
  310. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/registries/artifact-theme.json +0 -64
  311. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +0 -90
  312. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +0 -142
  313. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  314. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +0 -584
  315. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +0 -191
  316. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +0 -407
  317. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +0 -106
  318. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-handoff-readiness.schema.json +0 -398
  319. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-implementation-handoff.schema.json +0 -518
  320. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-planning-lineage.schema.json +0 -106
  321. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +0 -107
  322. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.14.0/artifact-theme.schema.json +0 -316
  323. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/artifact-envelope.schema.json +0 -408
  324. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.16.0/design-review-bundle.schema.json +0 -590
  325. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-document.schema.json +0 -506
  326. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +0 -822
  327. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +0 -346
  328. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +0 -1232
  329. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +0 -2611
  330. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -21
  331. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +0 -163
  332. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +0 -97
  333. package/lib/host-packages/openai/openplanr/skills/design/scripts/design.mjs +0 -12
  334. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/design.mjs +0 -12
  335. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/design.mjs +0 -12
  336. package/lib/host-packages/openai/openplanr/skills/plan/scripts/design.mjs +0 -12
@@ -1,1500 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- exportDesignReview,
4
- listArtifactReviewServers,
5
- resolveDesignPins,
6
- saveDesignState,
7
- serializeDesignReviewExport,
8
- startDesignReview,
9
- stopArtifactReviewServer
10
- } from "./design-review.mjs";
11
- import {
12
- ARTIFACT_REVIEW_MAX_STATE_BYTES,
13
- createReviewLedger,
14
- decodeArtifactReviewSources,
15
- mergeReviewLedger,
16
- normalizeArtifactReview,
17
- readArtifactReviewState,
18
- readDesignFeedback,
19
- readDesignHandoff,
20
- resolveArtifactReviewDestination,
21
- updateDesignHandoff,
22
- withArtifactReviewLock,
23
- writeArtifactReviewState
24
- } from "./design-handoff.mjs";
25
- import {
26
- inspectDesignDocument,
27
- matchesDesignFrame,
28
- prepareDesignDocument,
29
- readDesignViewContext,
30
- renderDesignDocument,
31
- standaloneDesignHtml
32
- } from "./design-document.mjs";
33
- import {
34
- listDesignRevisions,
35
- readDesignRevision
36
- } from "./design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs";
37
- import "./design-review-state-store.mjs";
38
- import "./design-parse5-parser.mjs";
39
- import "./design-parse5-tokenizer.mjs";
40
- import "./design-entities.mjs";
41
- import "./design-artifact-shell.mjs";
42
- import {
43
- ARTIFACT_ERROR_CODES,
44
- PipelineError,
45
- digestArtifactEnvelope
46
- } from "./design-shared-artifact-support-protocol-contracts-9f6918b0.mjs";
47
- import "./design-sandbox-guards.mjs";
48
- import {
49
- exportDesignShareRecovery,
50
- importDesignShareRecovery,
51
- manageDesignShare,
52
- publishDesignShare,
53
- shareDesign,
54
- syncDesignShare
55
- } from "./design-share-cli-bridge.mjs";
56
- import {
57
- atomicJson,
58
- currentDesign,
59
- hash,
60
- readJson
61
- } from "./design-shared-design-support-0bac378d.mjs";
62
- import "./design-runtime-home.mjs";
63
- import {
64
- acquireStartLock
65
- } from "./design-loopback-server.mjs";
66
-
67
- // packages/design/lib/design/utility.mjs
68
- import { spawn } from "node:child_process";
69
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, realpathSync, writeFileSync as writeFileSync2 } from "node:fs";
70
- import { dirname as dirname2, join as join4, resolve as resolve3 } from "node:path";
71
- import { fileURLToPath } from "node:url";
72
-
73
- // packages/design/lib/design/feedback-import.mjs
74
- import { closeSync, constants, fstatSync, openSync, readSync } from "node:fs";
75
- import { join, resolve } from "node:path";
76
- function invalid(message, code = ARTIFACT_ERROR_CODES.REVIEW_IMPORT) {
77
- throw new PipelineError(code, message);
78
- }
79
- function readDesignFeedbackImport(input) {
80
- if (typeof input !== "string" || !input.trim()) invalid("Feedback import requires a JSON file.");
81
- let fd;
82
- try {
83
- fd = openSync(resolve(input), constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
84
- const stat = fstatSync(fd);
85
- if (!stat.isFile()) invalid("Feedback import must be a regular JSON file.");
86
- if (stat.size > ARTIFACT_REVIEW_MAX_STATE_BYTES)
87
- invalid("Feedback import exceeds the 5 MB limit.", ARTIFACT_ERROR_CODES.REQUEST_LIMIT);
88
- const bytes = Buffer.alloc(ARTIFACT_REVIEW_MAX_STATE_BYTES + 1);
89
- let size = 0;
90
- while (size < bytes.length) {
91
- const read = readSync(fd, bytes, size, bytes.length - size, null);
92
- if (!read) break;
93
- size += read;
94
- }
95
- if (size > ARTIFACT_REVIEW_MAX_STATE_BYTES)
96
- invalid("Feedback import exceeds the 5 MB limit.", ARTIFACT_ERROR_CODES.REQUEST_LIMIT);
97
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
98
- } catch (error) {
99
- if (error instanceof PipelineError) throw error;
100
- invalid("Feedback import is unreadable or is not valid UTF-8 JSON.");
101
- } finally {
102
- if (fd !== void 0) closeSync(fd);
103
- }
104
- }
105
- function originalBundles(file, current) {
106
- return { file, current, cache: /* @__PURE__ */ new Map([[current.revision, current]]) };
107
- }
108
- function originalBundle(bundles, reviewOf, revisionId) {
109
- if (!/^[a-f0-9]{64}$/u.test(reviewOf ?? ""))
110
- invalid("Feedback has an invalid original artifact digest.");
111
- const load = (revision) => {
112
- if (!bundles.cache.has(revision)) {
113
- try {
114
- const historical = readDesignRevision(bundles.file, revision);
115
- bundles.cache.set(revision, { ...historical, document: historical.design });
116
- } catch {
117
- invalid(
118
- "The original feedback revision is unavailable. Restore its immutable render bundle before importing."
119
- );
120
- }
121
- }
122
- const bundle = bundles.cache.get(revision);
123
- if (bundle.document.id !== bundles.current.document.id)
124
- invalid("Feedback revision belongs to another design document.");
125
- return bundle;
126
- };
127
- if (revisionId && /^[a-f0-9]{64}$/u.test(revisionId)) {
128
- const exact = load(revisionId);
129
- if (digestArtifactEnvelope(exact.envelope) !== reviewOf)
130
- invalid("Feedback revision does not match its original artifact digest.");
131
- return exact;
132
- }
133
- for (const bundle of bundles.cache.values())
134
- if (digestArtifactEnvelope(bundle.envelope) === reviewOf) return bundle;
135
- for (const { revision } of listDesignRevisions(bundles.file).revisions) {
136
- const bundle = load(revision);
137
- if (digestArtifactEnvelope(bundle.envelope) === reviewOf) return bundle;
138
- }
139
- invalid(
140
- "The original feedback revision is unavailable. Restore its immutable render bundle before importing."
141
- );
142
- }
143
- function validatePin(pin, bundle) {
144
- const entry = bundle.entries.find((value) => value.artifactId === pin.artifactId);
145
- const frame = bundle.document.frames.find((value) => value.id === entry?.frameId);
146
- const screen = bundle.document.screens.find((value) => value.id === entry?.screenId);
147
- if (!entry || !matchesDesignFrame(frame, pin.viewport))
148
- invalid("Feedback pin does not match its original screen and captured frame.");
149
- if (pin.variant !== void 0 && pin.variant !== entry.variantId)
150
- invalid("Feedback pin targets another design direction.");
151
- if (pin.region.x + pin.region.w > 1.000001 || pin.region.y + pin.region.h > 1.000001)
152
- invalid("Feedback pin region extends beyond its original viewport or anchor.");
153
- if (pin.anchor && (pin.anchor.screen !== void 0 && pin.anchor.screen !== entry.screenId || pin.anchor.planrId !== screen.id && !screen.anchors?.includes(pin.anchor.planrId)))
154
- invalid("Feedback pin anchor is not declared in its original screen.");
155
- }
156
- function identity(value) {
157
- return { name: value?.name, ...value?.id == null ? {} : { id: value.id } };
158
- }
159
- function projectedPin(thread, group, bundle) {
160
- const source = thread.source;
161
- if (!source || source.reviewId !== group.reviewId || source.reviewOf !== group.reviewOf || source.artifactId !== group.artifactId || source.revisionId !== group.sourceRevisionId)
162
- invalid("Feedback thread and group have conflicting source identities.");
163
- const entry = bundle.entries.find((value) => value.artifactId === group.artifactId);
164
- if (!entry || entry.screenId !== group.screen?.id || entry.variantId !== group.direction?.id || entry.frameId !== group.frame?.id)
165
- invalid("Feedback group has an invalid original screen mapping.");
166
- const location = thread.location;
167
- if (!location || !["anchor-normalized", "viewport-normalized"].includes(location.coordinateSpace) || Boolean(location.anchor) !== (location.coordinateSpace === "anchor-normalized"))
168
- invalid("Feedback location has an invalid coordinate space.");
169
- if (!Array.isArray(thread.replies)) invalid("Feedback replies must be an array.");
170
- const pin = {
171
- id: thread.id,
172
- artifactId: source.artifactId,
173
- author: identity(thread.author),
174
- intent: thread.originalIntent,
175
- status: thread.status,
176
- comment: thread.comment,
177
- region: location.region,
178
- viewport: location.capturedViewport,
179
- ...location.anchor ? {
180
- anchor: {
181
- planrId: location.anchor.planrId,
182
- ...location.anchor.screen == null ? {} : { screen: location.anchor.screen }
183
- }
184
- } : {},
185
- createdAt: thread.createdAt,
186
- updatedAt: thread.updatedAt,
187
- replies: thread.replies.map((reply) => ({ ...reply, author: identity(reply.author) }))
188
- };
189
- return pin;
190
- }
191
- function appendProjectedThread(entry, thread, group, bundle, stored) {
192
- const pin = projectedPin(thread, group, bundle);
193
- const previousPin = stored?.reviews.find((value) => value.review.reviewId === group.reviewId)?.review.pins.find((value) => value.id === pin.id);
194
- if (previousPin?.variant !== void 0) pin.variant = previousPin.variant;
195
- entry.review.pins.push(pin);
196
- if (!entry.review.updatedAt || Date.parse(pin.updatedAt) > Date.parse(entry.review.updatedAt))
197
- entry.review.updatedAt = pin.updatedAt;
198
- entry.stale ||= thread.stale === true;
199
- }
200
- function decodeProjection(value, current, bundles, stored) {
201
- if (value.schemaVersion !== "1.0.0" || value.design?.id !== current.document.id || !Array.isArray(value.groups) || value.groups.length > 1e4 || !Array.isArray(value.overallNotes) || value.overallNotes.length > 1e4)
202
- invalid("Feedback export does not match this design document or supported schema.");
203
- originalBundle(bundles, value.currentArtifactDigest, value.currentRevisionId);
204
- const reviews = /* @__PURE__ */ new Map();
205
- const reviewFor = (reviewId, reviewOf) => {
206
- if (typeof reviewId !== "string" || !reviewId || reviewId.length > 128)
207
- invalid("Feedback export is missing its original review identity.");
208
- const previous = reviews.get(reviewId);
209
- if (previous && previous.review.reviewOf !== reviewOf)
210
- invalid("Feedback review identity is bound to conflicting artifact digests.");
211
- if (previous) return previous;
212
- const existing = stored?.reviews.find((entry2) => entry2.review.reviewId === reviewId)?.review;
213
- const entry = {
214
- review: {
215
- schemaVersion: "1.0.0",
216
- reviewId,
217
- reviewOf,
218
- decision: "pending",
219
- overall: "",
220
- pins: [],
221
- ...existing?.createdAt ? { createdAt: existing.createdAt } : {},
222
- ...existing?.updatedAt ? { updatedAt: existing.updatedAt } : {}
223
- },
224
- stale: false
225
- };
226
- reviews.set(reviewId, entry);
227
- return entry;
228
- };
229
- for (const group of value.groups) {
230
- if (!group || !Array.isArray(group.threads) || group.threads.length > 1e4 || group.sourceMapping !== "original-bundle")
231
- invalid("Feedback export lacks its original thread mapping.");
232
- const bundle = originalBundle(bundles, group.reviewOf, group.sourceRevisionId);
233
- const entry = reviewFor(group.reviewId, group.reviewOf);
234
- for (const thread of group.threads) appendProjectedThread(entry, thread, group, bundle, stored);
235
- }
236
- for (const note of value.overallNotes) {
237
- originalBundle(bundles, note?.reviewOf);
238
- const entry = reviewFor(note?.reviewId, note?.reviewOf);
239
- if (entry.review.overall) invalid("Feedback export contains duplicate overall notes.");
240
- entry.review.overall = note.comment;
241
- }
242
- return [...reviews.values()].map((entry) => ({
243
- ...entry,
244
- review: normalizeArtifactReview(entry.review)
245
- }));
246
- }
247
- function rejectLegacy(value) {
248
- if (value?.kind === "openplanr-design-review-export" || value?.kind === "artifact-review-state" || value?.artifacts || value?.reviewId || value?.review)
249
- return;
250
- invalid(
251
- "Legacy notes.json is not canonical review feedback. Keep the file and re-export JSON from the original supported Studio; it cannot be converted safely without its revision and anchor mapping."
252
- );
253
- }
254
- function rebaseLedger(stored, artifactId, digest) {
255
- if (stored && stored.artifactId !== artifactId)
256
- invalid("Stored feedback belongs to another design document.");
257
- return createReviewLedger({
258
- artifactId,
259
- currentReviewOf: digest,
260
- reviews: (stored?.reviews ?? []).map((entry) => ({
261
- ...entry,
262
- stale: entry.stale || entry.review.reviewOf !== digest
263
- }))
264
- });
265
- }
266
- function mergeImportedEntries(stored, artifactId, digest, entries, bundles, allowStale) {
267
- let ledger = rebaseLedger(stored, artifactId, digest);
268
- const imported = [];
269
- for (const entry of entries) {
270
- const bundle = originalBundle(bundles, entry.review.reviewOf);
271
- for (const pin of entry.review.pins) validatePin(pin, bundle);
272
- const stale = entry.stale || entry.review.reviewOf !== digest;
273
- if (stale && !allowStale)
274
- invalid(
275
- "Feedback belongs to an earlier revision. Inspect it and retry with explicit --allow-stale confirmation.",
276
- ARTIFACT_ERROR_CODES.STALE_REVIEW
277
- );
278
- const previous = ledger.reviews.find(
279
- (value) => value.review.reviewId === entry.review.reviewId
280
- )?.review;
281
- const review = { ...entry.review, decision: previous?.decision ?? "pending" };
282
- ledger = mergeReviewLedger(ledger, review, { stale });
283
- imported.push({ reviewId: review.reviewId, stale, pins: review.pins.length });
284
- }
285
- return { ledger, imported };
286
- }
287
- async function importDesignFeedback(file, { input, revision, allowStale = false, env = process.env } = {}) {
288
- if (!/^[a-f0-9]{64}$/u.test(revision ?? ""))
289
- invalid("Feedback import requires the current render revision from feedback inspect.");
290
- if (typeof allowStale !== "boolean")
291
- invalid("Stale feedback requires an explicit boolean confirmation.");
292
- const source = readDesignFeedbackImport(input);
293
- rejectLegacy(source);
294
- const initial = currentDesign(file);
295
- const release = await acquireStartLock(join(initial.root, ".design/render.lock"), {
296
- timeout: 1e3,
297
- stale: 3e4
298
- });
299
- try {
300
- const current = currentDesign(file);
301
- if (current.revision !== revision)
302
- invalid(
303
- "The design changed before feedback import. Inspect the current revision and retry.",
304
- ARTIFACT_ERROR_CODES.STALE_REVIEW
305
- );
306
- const artifactId = `design-${hash(current.document.id).slice(0, 24)}`;
307
- const path = resolveArtifactReviewDestination({ cwd: current.root, env, artifactId }).path;
308
- return await withArtifactReviewLock(path, async () => {
309
- const stored = readArtifactReviewState(path, { allowMissing: true });
310
- const bundles = originalBundles(file, current);
311
- const entries = source.kind === "openplanr-design-review-export" ? decodeProjection(source, current, bundles, stored) : await decodeArtifactReviewSources(source, { withMetadata: true });
312
- if (source.kind === "artifact-review-state" && source.artifactId !== artifactId)
313
- invalid("Imported ledger belongs to another design document.");
314
- const digest = digestArtifactEnvelope(current.envelope);
315
- const { ledger, imported } = mergeImportedEntries(
316
- stored,
317
- artifactId,
318
- digest,
319
- entries,
320
- bundles,
321
- allowStale
322
- );
323
- writeArtifactReviewState(path, ledger);
324
- return {
325
- ok: true,
326
- action: "design_feedback_imported",
327
- revision: current.revision,
328
- imported,
329
- note: "Feedback merged. Imported votes, dispositions and decisions do not change owner selection or handoff approval."
330
- };
331
- });
332
- } finally {
333
- release();
334
- }
335
- }
336
-
337
- // packages/design/lib/design/font-fetch.mjs
338
- import {
339
- chmodSync,
340
- existsSync,
341
- mkdirSync,
342
- mkdtempSync,
343
- readdirSync,
344
- renameSync,
345
- rmdirSync,
346
- rmSync,
347
- statSync,
348
- writeFileSync
349
- } from "node:fs";
350
- import { basename, dirname, join as join2, resolve as resolve2 } from "node:path";
351
- var MAX_FAMILIES = 2;
352
- var MAX_WEIGHTS = 3;
353
- var TIMEOUT_MS = 2e4;
354
- var MAX_FILE_BYTES = 15e5;
355
- var MAX_TOTAL_BYTES = 5e6;
356
- var STAGING_MAX_AGE_MS = 10 * 6e4;
357
- var STAGING_PREFIX = ".fonts-fetch-";
358
- var CSS_ENDPOINT = "https://fonts.googleapis.com/css2";
359
- var FONT_ORIGIN = "https://fonts.gstatic.com/";
360
- var CATALOG_ROOT = "https://raw.githubusercontent.com/google/fonts/main";
361
- var USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36";
362
- var LICENSES = Object.freeze([
363
- {
364
- directory: "ofl",
365
- metadata: "OFL",
366
- file: "OFL.txt",
367
- id: "OFL-1.1",
368
- text: /SIL Open Font License,?\s+Version 1\.1/iu
369
- },
370
- {
371
- directory: "apache",
372
- metadata: "APACHE2",
373
- file: "LICENSE.txt",
374
- id: "Apache-2.0",
375
- text: /Apache License\s+Version 2\.0/iu
376
- }
377
- ]);
378
- var FAMILY_SPEC = /^([A-Za-z0-9](?:[A-Za-z0-9 ]*[A-Za-z0-9])?):(\d{3}(?:,\d{3})*)$/u;
379
- function parseFontFamily(spec) {
380
- const match = typeof spec === "string" ? FAMILY_SPEC.exec(spec.trim()) : null;
381
- if (!match)
382
- throw new Error(
383
- `--family ${JSON.stringify(spec ?? "")} must look like "Inter:400,600" (a name, a colon, comma-separated weights).`
384
- );
385
- const weights = [...new Set(match[2].split(",").map(Number))].sort((a, b) => a - b);
386
- const invalid2 = weights.find((weight) => weight < 100 || weight > 900 || weight % 100 !== 0);
387
- if (invalid2 !== void 0)
388
- throw new Error(`--family "${spec}" has weight ${invalid2}; use 100 to 900 in steps of 100.`);
389
- if (weights.length > MAX_WEIGHTS)
390
- throw new Error(
391
- `--family "${spec}" has ${weights.length} weights; at most ${MAX_WEIGHTS} per family.`
392
- );
393
- return { family: match[1], weights };
394
- }
395
- function latinFontFaces(css, family) {
396
- const faces = [];
397
- for (const [, subset, body] of css.matchAll(
398
- /\/\*\s*([\w-]+)\s*\*\/\s*@font-face\s*\{([^}]*)\}/gu
399
- )) {
400
- const value = (name) => new RegExp(`(?:^|;)\\s*${name}\\s*:\\s*([^;]+)`, "iu").exec(body)?.[1].trim();
401
- if (subset !== "latin" || !/^U\+0000-00FF\b/iu.test(value("unicode-range") ?? "")) continue;
402
- const source = /^url\(([^)\s]+)\)\s*format\(['"]woff2['"]\)$/u.exec(value("src") ?? "");
403
- if (!source?.[1].startsWith(FONT_ORIGIN))
404
- throw new Error(
405
- `"${family}" Latin face is not a woff2 file on ${FONT_ORIGIN}: ${value("src")}`
406
- );
407
- faces.push({ weight: Number(value("font-weight")), url: source[1] });
408
- }
409
- return faces;
410
- }
411
- async function request(fetchImpl, url, { headers, allowMissing = false, redirect } = {}) {
412
- let response;
413
- try {
414
- response = await fetchImpl(url, {
415
- headers,
416
- redirect,
417
- signal: AbortSignal.timeout(TIMEOUT_MS)
418
- });
419
- } catch (error) {
420
- const reason = error?.name === "TimeoutError" ? `no response within ${TIMEOUT_MS / 1e3} s` : error?.message;
421
- throw new Error(`Font fetch failed: ${url}: ${reason}`);
422
- }
423
- if (allowMissing && response.status === 404) return null;
424
- if (!response.ok) throw new Error(`Font fetch failed: ${url}: HTTP ${response.status}`);
425
- return response;
426
- }
427
- async function verifiedLicense(fetchImpl, family) {
428
- const slug = family.toLowerCase().replace(/[^a-z0-9]/gu, "");
429
- const tried = [];
430
- for (const license of LICENSES) {
431
- const base = `${CATALOG_ROOT}/${license.directory}/${slug}`;
432
- tried.push(`${base}/METADATA.pb`);
433
- const metadata = await request(fetchImpl, `${base}/METADATA.pb`, { allowMissing: true });
434
- if (!metadata) continue;
435
- const text = await metadata.text();
436
- const name = /^name:\s*"([^"]*)"/mu.exec(text)?.[1];
437
- const declared = /^license:\s*"([^"]*)"/mu.exec(text)?.[1];
438
- if (name !== family && name?.toLowerCase() === family.toLowerCase())
439
- throw new Error(`"${family}" is listed as "${name}"; use the catalog name "${name}".`);
440
- if (name !== family || declared !== license.metadata)
441
- throw new Error(
442
- `"${family}" is not verified as ${license.id}: ${base}/METADATA.pb names ${JSON.stringify(name)} with license ${JSON.stringify(declared)}. Use the system stack.`
443
- );
444
- const body = Buffer.from(
445
- await (await request(fetchImpl, `${base}/${license.file}`, { redirect: "error" })).arrayBuffer()
446
- );
447
- if (!license.text.test(body.toString("utf8")))
448
- throw new Error(
449
- `"${family}" is not verified as ${license.id}: ${base}/${license.file} does not contain the license text. Use the system stack.`
450
- );
451
- return { slug, license, body };
452
- }
453
- throw new Error(
454
- `"${family}" is not an OFL or Apache licensed Google Fonts family (checked ${tried.join(", ")}). Use the system stack.`
455
- );
456
- }
457
- async function download(fetchImpl, url) {
458
- const bytes = Buffer.from(
459
- await (await request(fetchImpl, url, { redirect: "error" })).arrayBuffer()
460
- );
461
- if (bytes.length > MAX_FILE_BYTES)
462
- throw new Error(`Font file is ${bytes.length} bytes, over the ${MAX_FILE_BYTES} limit: ${url}`);
463
- if (bytes.toString("latin1", 0, 4) !== "wOF2") throw new Error(`Font file is not woff2: ${url}`);
464
- return bytes;
465
- }
466
- function assertWritableDestination(dest) {
467
- if (!existsSync(dest)) return;
468
- if (!statSync(dest).isDirectory() || readdirSync(dest).length > 0)
469
- throw new Error(
470
- `Font destination already exists and is not empty: ${dest}. Choose a new --dest or remove it.`
471
- );
472
- }
473
- function faceRule(family, weights, file) {
474
- const weight = weights.length > 1 ? `${weights[0]} ${weights.at(-1)}` : `${weights[0]}`;
475
- return `@font-face {
476
- font-family: "${family}";
477
- font-style: normal;
478
- font-weight: ${weight};
479
- font-display: swap;
480
- src: url("${file}") format("woff2");
481
- }
482
- `;
483
- }
484
- async function fetchDesignFonts({ families, dest, fetchImpl = fetch }) {
485
- if (!dest) throw new Error("fonts fetch requires --dest <design>/source/assets/fonts.");
486
- const specs = (families ?? []).map(parseFontFamily);
487
- if (specs.length === 0)
488
- throw new Error('fonts fetch requires at least one --family "<Name>:<weights>".');
489
- if (specs.length > MAX_FAMILIES)
490
- throw new Error(
491
- `${specs.length} families requested (${specs.map(({ family }) => family).join(", ")}); at most ${MAX_FAMILIES}.`
492
- );
493
- const names = specs.map(({ family }) => family.toLowerCase());
494
- if (new Set(names).size !== names.length)
495
- throw new Error(
496
- `--family names a family twice: ${specs.map(({ family }) => family).join(", ")}.`
497
- );
498
- const target = resolve2(dest);
499
- if (basename(target).startsWith(STAGING_PREFIX))
500
- throw new Error(
501
- `Font destination uses the reserved staging prefix ${STAGING_PREFIX}: ${target}`
502
- );
503
- assertWritableDestination(target);
504
- const files = /* @__PURE__ */ new Map();
505
- const rules = [];
506
- const summaries = [];
507
- let totalBytes = 0;
508
- const add = (path, bytes) => {
509
- totalBytes += bytes.length;
510
- if (totalBytes > MAX_TOTAL_BYTES)
511
- throw new Error(`Font snapshot exceeds ${MAX_TOTAL_BYTES} bytes at ${path}.`);
512
- files.set(path, bytes);
513
- };
514
- for (const { family, weights } of specs) {
515
- const { slug, license, body } = await verifiedLicense(fetchImpl, family);
516
- const source = `${CSS_ENDPOINT}?family=${encodeURIComponent(family).replaceAll("%20", "+")}:wght@${weights.join(";")}&display=swap`;
517
- const css = await (await request(fetchImpl, source, { headers: { "user-agent": USER_AGENT } })).text();
518
- const faces = latinFontFaces(css, family);
519
- const byUrl = /* @__PURE__ */ new Map();
520
- for (const weight of weights) {
521
- const face = faces.find((item) => item.weight === weight);
522
- if (!face)
523
- throw new Error(`"${family}" has no Latin woff2 face for weight ${weight} in ${source}`);
524
- byUrl.set(face.url, [...byUrl.get(face.url) ?? [], weight]);
525
- }
526
- rules.push(`/* ${family} (${license.id}, ${slug}/${license.file}): ${source} */
527
- `);
528
- for (const [url, covered] of byUrl) {
529
- const range = covered.length > 1 ? `${covered[0]}-${covered.at(-1)}` : `${covered[0]}`;
530
- const file = `${slug}/${slug}-${range}-latin.woff2`;
531
- add(file, await download(fetchImpl, url));
532
- rules.push(faceRule(family, covered, file));
533
- }
534
- add(`${slug}/${license.file}`, body);
535
- summaries.push({
536
- family,
537
- license: license.id,
538
- weights,
539
- source,
540
- licenseFile: `${slug}/${license.file}`
541
- });
542
- }
543
- add("fonts.css", Buffer.from(rules.join("")));
544
- const parent = dirname(target);
545
- const missingParents = [];
546
- for (let directory = parent; !existsSync(directory); directory = dirname(directory))
547
- missingParents.push(directory);
548
- const createdParents = [];
549
- let staging;
550
- try {
551
- for (const directory of missingParents.reverse()) {
552
- mkdirSync(directory);
553
- createdParents.push(directory);
554
- }
555
- const staleBefore = Date.now() - STAGING_MAX_AGE_MS;
556
- for (const entry of readdirSync(parent, { withFileTypes: true })) {
557
- if (!entry.isDirectory() || !entry.name.startsWith(STAGING_PREFIX)) continue;
558
- const path = join2(parent, entry.name);
559
- try {
560
- if (statSync(path).mtimeMs < staleBefore) rmSync(path, { recursive: true });
561
- } catch (error) {
562
- if (error.code === "ENOENT") continue;
563
- throw new Error(`Could not remove stale staging folder ${path}: ${error.message}`);
564
- }
565
- }
566
- staging = mkdtempSync(join2(parent, STAGING_PREFIX));
567
- for (const [path, bytes] of files) {
568
- mkdirSync(dirname(join2(staging, path)), { recursive: true });
569
- writeFileSync(join2(staging, path), bytes, { flag: "wx" });
570
- }
571
- assertWritableDestination(target);
572
- if (existsSync(target)) rmdirSync(target);
573
- chmodSync(staging, 493);
574
- renameSync(staging, target);
575
- } catch (error) {
576
- const cleanupErrors = [];
577
- for (const directory of [...staging ? [staging] : [], ...createdParents.reverse()]) {
578
- try {
579
- if (directory === staging) rmSync(directory, { recursive: true, force: true });
580
- else if (readdirSync(directory).length === 0) rmdirSync(directory);
581
- } catch (cleanupError) {
582
- cleanupErrors.push({ path: directory, message: cleanupError.message });
583
- }
584
- }
585
- if (cleanupErrors.length > 0) {
586
- error.cleanupErrors = cleanupErrors;
587
- error.message += cleanupErrors.map(({ path, message }) => ` (cleanup also failed for ${path}: ${message})`).join("");
588
- }
589
- throw error;
590
- }
591
- return {
592
- ok: true,
593
- dest: target,
594
- css: join2(target, "fonts.css"),
595
- families: summaries,
596
- files: [...files].map(([path, bytes]) => ({ path, bytes: bytes.length })),
597
- totalBytes
598
- };
599
- }
600
-
601
- // packages/design/lib/design/studio-lifecycle.mjs
602
- import { join as join3 } from "node:path";
603
- function localUrl(value, service, path) {
604
- if (typeof value !== "string") return null;
605
- try {
606
- const url = new URL(value);
607
- return url.origin === `http://127.0.0.1:${service.port}` && !url.search && !url.hash && path.test(url.pathname) ? url.href : null;
608
- } catch {
609
- return null;
610
- }
611
- }
612
- async function manageDesignStudio(file, { action = "status", instanceId, env = process.env, fetchImpl = fetch } = {}) {
613
- if (!["status", "stop"].includes(action))
614
- throw new Error("Studio action must be status or stop.");
615
- if (instanceId !== void 0 && (typeof instanceId !== "string" || !/^[A-Za-z0-9_-]{22}$/u.test(instanceId)))
616
- throw new Error("Studio requires a valid exact instance ID.");
617
- const current = currentDesign(file);
618
- const services = (await listArtifactReviewServers({ env, fetchImpl })).filter(
619
- (service2) => service2.kind === "design" && service2.projectRoot === current.root
620
- );
621
- const launcher = readJson(join3(current.root, ".design/server.json"), null);
622
- let service = services.find((value) => value.instanceId === (instanceId ?? launcher?.instanceId));
623
- if (instanceId !== void 0 && !service)
624
- throw new Error(
625
- "That Studio instance is not owned by this design in the current state directory."
626
- );
627
- const result = {
628
- ok: true,
629
- action: `design_studio_${action}`,
630
- documentId: current.document.id,
631
- revision: current.revision,
632
- verification: current.verification.status
633
- };
634
- if (action === "stop") {
635
- if (!service && services.length === 1) service = services[0];
636
- if (!service && services.length > 1)
637
- throw new Error(
638
- `Multiple owned Studio services need recovery. Run studio --action status, then stop an exact service with --instance-id. Owned instances: ${services.map((value) => value.instanceId).join(", ")}.`
639
- );
640
- if (!service)
641
- return {
642
- ...result,
643
- status: "stopped",
644
- notice: "Studio is stopped. Open the design to start it again."
645
- };
646
- const stopped = await stopArtifactReviewServer(service.instanceId, { env, fetchImpl });
647
- return {
648
- ...result,
649
- status: stopped.status,
650
- instanceId: service.instanceId,
651
- notice: "Feedback and arrangement are saved. Open the design to start Studio again."
652
- };
653
- }
654
- if (!service)
655
- return {
656
- ...result,
657
- status: services.length ? "attention" : "stopped",
658
- services,
659
- notice: services.length ? services.length === 1 ? "Stop this design\u2019s owned Studio service, then open the design again to restore its session link." : "Stop an exact owned Studio service with --instance-id, then reopen after all obsolete services are stopped." : "Open the design to start Studio."
660
- };
661
- const url = localUrl(launcher?.studioUrl, service, /^\/studio\/[A-Za-z0-9._-]+\/$/u) ?? service.url;
662
- let browserStatus = "not-checked";
663
- const privateUrl = localUrl(launcher?.url, service, /^\/r\/[A-Za-z0-9_-]+\/[A-Za-z0-9_-]+\/$/u);
664
- if (privateUrl) {
665
- try {
666
- const response = await fetchImpl(`${privateUrl}api/design-status`, {
667
- signal: AbortSignal.timeout(700)
668
- });
669
- const data = await response.json();
670
- if (response.ok && data.documentId === current.document.id && data.revision === current.revision && ["loading", "ready", "failed"].includes(data.status))
671
- browserStatus = data.status;
672
- } catch {
673
- }
674
- }
675
- return {
676
- ...result,
677
- status: "running",
678
- instanceId: service.instanceId,
679
- url,
680
- browserStatus,
681
- services
682
- };
683
- }
684
-
685
- // packages/design/lib/design/browser-audit.mjs
686
- function auditRenderedScreen({ height, frameBoundsSeverity = "warning" } = {}) {
687
- const issues = [];
688
- const add = (rule, severity, message) => issues.push({ rule, severity, message });
689
- const label = (node) => node.getAttribute("data-planr-id") || node.id || `${node.tagName.toLowerCase()} \u201C${(node.textContent || node.getAttribute("aria-label") || "").trim().replace(/\s+/gu, " ").slice(0, 60)}\u201D`;
690
- const viewport = { width: window.innerWidth, height: window.innerHeight };
691
- const screenId = document.body?.getAttribute("data-planr-screen") ?? null;
692
- if (!screenId)
693
- add("screen-not-loaded", "error", "The frame has no authored design screen identity.");
694
- if (document.readyState !== "complete")
695
- add("screen-loading", "error", `The frame is still ${document.readyState}.`);
696
- const documentHeight = document.documentElement.scrollHeight;
697
- if (document.body && getComputedStyle(document.body).boxSizing !== "border-box")
698
- add(
699
- "board-root-box-sizing",
700
- frameBoundsSeverity,
701
- "The screen root body must use box-sizing: border-box."
702
- );
703
- if (height !== "auto" && documentHeight > viewport.height + 1)
704
- add(
705
- "vertical-overflow",
706
- frameBoundsSeverity,
707
- `The screen is ${documentHeight}px tall in a ${viewport.height}px frame.`
708
- );
709
- const nodes = [...document.querySelectorAll("body *")];
710
- if (nodes.length > 5e3)
711
- add(
712
- "audit-limit",
713
- "error",
714
- "The screen exceeds the 5,000 element audit limit; inspect and split the screen before verification."
715
- );
716
- const canvas = document.createElement("canvas");
717
- canvas.width = canvas.height = 1;
718
- const context = canvas.getContext("2d", { willReadFrequently: true });
719
- const color = (input) => {
720
- if (!context) return null;
721
- context.clearRect(0, 0, 1, 1);
722
- context.fillStyle = input;
723
- context.fillRect(0, 0, 1, 1);
724
- return [...context.getImageData(0, 0, 1, 1).data].map((value) => value / 255);
725
- };
726
- const over = (foreground, background) => foreground.slice(0, 3).map((value, index) => value * foreground[3] + background[index] * (1 - foreground[3]));
727
- const luminance = (rgb) => rgb.reduce(
728
- (sum, value, index) => sum + [0.2126, 0.7152, 0.0722][index] * (value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4),
729
- 0
730
- );
731
- const effectiveBackground = (node) => {
732
- const chain = [];
733
- for (let ancestor = node; ancestor; ancestor = ancestor.parentElement) chain.unshift(ancestor);
734
- let background = [1, 1, 1];
735
- for (const ancestor of chain) {
736
- const style = getComputedStyle(ancestor);
737
- if (style.backgroundImage !== "none" || Number(style.opacity) < 1 || style.mixBlendMode !== "normal" || style.filter !== "none")
738
- return null;
739
- const resolved = color(style.backgroundColor);
740
- if (!resolved) return null;
741
- background = over(resolved, background);
742
- }
743
- return background;
744
- };
745
- const visible = (node) => {
746
- const rect = node.getBoundingClientRect();
747
- const style = getComputedStyle(node);
748
- return rect.width > 0 && rect.height > 0 && !node.closest('[hidden],[aria-hidden="true"],[inert]') && style.visibility !== "hidden" && style.visibility !== "collapse" && Number(style.opacity) > 0;
749
- };
750
- let checkedElements = 0, checkedContrast = 0, skippedContrast = 0, checkedFocus = 0;
751
- const focusTargets = [];
752
- for (const node of nodes.slice(0, 5e3)) {
753
- const style = getComputedStyle(node);
754
- const rect = node.getBoundingClientRect();
755
- if (rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.visibility !== "collapse" && Number(style.opacity) > 0 && ["absolute", "fixed"].includes(style.position)) {
756
- let { left, right, top, bottom } = rect;
757
- for (let ancestor = node.parentElement; ancestor && ancestor !== document.body; ancestor = ancestor.parentElement) {
758
- const clip = getComputedStyle(ancestor);
759
- const bounds = ancestor.getBoundingClientRect();
760
- if (["auto", "scroll", "hidden", "clip"].includes(clip.overflowX)) {
761
- left = Math.max(left, bounds.left + ancestor.clientLeft);
762
- right = Math.min(right, bounds.left + ancestor.clientLeft + ancestor.clientWidth);
763
- }
764
- if (["auto", "scroll", "hidden", "clip"].includes(clip.overflowY)) {
765
- top = Math.max(top, bounds.top + ancestor.clientTop);
766
- bottom = Math.min(bottom, bounds.top + ancestor.clientTop + ancestor.clientHeight);
767
- }
768
- }
769
- if (right > left && bottom > top && (left < -1 || right > viewport.width + 1 || top < -1 || bottom > (height === "auto" ? documentHeight : viewport.height) + 1))
770
- add(
771
- "outside-frame",
772
- frameBoundsSeverity,
773
- `${label(node)} is positioned outside the frame box.`
774
- );
775
- }
776
- if (!visible(node)) continue;
777
- checkedElements += 1;
778
- const directText = [...node.childNodes].some(
779
- (child) => child.nodeType === 3 && child.textContent.trim()
780
- );
781
- if (node.tagName === "IMG" && (!node.complete || node.naturalWidth === 0))
782
- add("missing-image", "error", `${label(node)} has not loaded its image.`);
783
- if (directText) {
784
- const background = effectiveBackground(node);
785
- const foreground = color(style.color);
786
- if (background && foreground) {
787
- const a = luminance(over(foreground, background)), b = luminance(background);
788
- const ratio = (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
789
- const large = parseFloat(style.fontSize) >= 24 || parseFloat(style.fontSize) >= 18.666 && parseFloat(style.fontWeight) >= 700;
790
- const required = large ? 3 : 4.5;
791
- checkedContrast += 1;
792
- if (ratio + 0.01 < required)
793
- add(
794
- "contrast-below-aa",
795
- "error",
796
- `${label(node)} has computed contrast ${ratio.toFixed(2)}:1; ${required}:1 is required.`
797
- );
798
- } else skippedContrast += 1;
799
- if (!["INPUT", "TEXTAREA", "SELECT", "OPTION"].includes(node.tagName)) {
800
- const clipsX = ["hidden", "clip"].includes(style.overflowX) && node.scrollWidth > node.clientWidth + 1;
801
- const clipsY = ["hidden", "clip"].includes(style.overflowY) && node.scrollHeight > node.clientHeight + 1;
802
- if (clipsX || clipsY) {
803
- const intentional = style.textOverflow === "ellipsis" || style.webkitLineClamp && style.webkitLineClamp !== "none";
804
- add(
805
- "clipped-content",
806
- intentional ? "warning" : "error",
807
- `${label(node)} clips ${clipsX ? "horizontal" : "vertical"} text${intentional ? "; confirm intentional truncation in the screenshot" : ""}.`
808
- );
809
- }
810
- }
811
- }
812
- if (node.tabIndex >= 0 && !node.disabled && node.matches(
813
- 'button,a[href],input:not([type="hidden"]),select,textarea,[tabindex],[contenteditable="true"]'
814
- )) {
815
- focusTargets.push(node);
816
- const name = node.getAttribute("aria-label") || (node.getAttribute("aria-labelledby") || "").split(/\s+/u).map((id) => document.getElementById(id)?.textContent || "").join(" ").trim() || [...node.labels || []].map((item) => item.textContent).join(" ").trim() || node.getAttribute("title") || (node.matches('input[type="button"],input[type="submit"],input[type="reset"]') ? node.value : node.matches("input,select,textarea") ? "" : node.textContent.trim());
817
- if (!name) add("unnamed-control", "error", `${label(node)} has no accessible name.`);
818
- }
819
- }
820
- if (document.documentElement.scrollWidth > viewport.width + 1)
821
- add(
822
- "horizontal-overflow",
823
- "error",
824
- `The screen is ${document.documentElement.scrollWidth}px wide in a ${viewport.width}px frame.`
825
- );
826
- if (checkedElements === 0)
827
- add("empty-render", "error", "The frame contains no visible rendered content.");
828
- if (skippedContrast > 0)
829
- add(
830
- "contrast-needs-inspection",
831
- "warning",
832
- `${skippedContrast} text elements use images, blending or transparency effects; inspect their screenshot contrast.`
833
- );
834
- if (document.fonts?.status === "loading")
835
- add("fonts-loading", "error", "Fonts are still loading; inspect again after they settle.");
836
- const previousFocus = document.activeElement;
837
- const previousScroll = { x: window.scrollX, y: window.scrollY };
838
- let keyboardInspectionNeeded = 0;
839
- for (const node of focusTargets.slice(0, 150)) {
840
- const before = getComputedStyle(node);
841
- const baseline = [
842
- before.boxShadow,
843
- before.backgroundColor,
844
- before.borderColor,
845
- before.textDecorationLine
846
- ];
847
- node.focus({ preventScroll: true });
848
- if (document.activeElement !== node) {
849
- add("unreachable-control", "error", `${label(node)} cannot receive focus.`);
850
- continue;
851
- }
852
- if (!node.matches(":focus-visible")) {
853
- keyboardInspectionNeeded += 1;
854
- continue;
855
- }
856
- const focused = getComputedStyle(node);
857
- const outlined = focused.outlineStyle !== "none" && parseFloat(focused.outlineWidth) > 0 && (color(focused.outlineColor)?.[3] ?? 0) > 0;
858
- const changed = [
859
- focused.boxShadow,
860
- focused.backgroundColor,
861
- focused.borderColor,
862
- focused.textDecorationLine
863
- ].some((value, index) => value !== baseline[index]);
864
- checkedFocus += 1;
865
- if (!outlined && !changed)
866
- add(
867
- "missing-focus-indicator",
868
- "error",
869
- `${label(node)} has no visible keyboard focus style.`
870
- );
871
- }
872
- previousFocus?.focus?.({ preventScroll: true });
873
- if (document.activeElement !== previousFocus) document.activeElement?.blur?.();
874
- if (window.scrollX !== previousScroll.x || window.scrollY !== previousScroll.y)
875
- window.scrollTo(previousScroll.x, previousScroll.y);
876
- if (keyboardInspectionNeeded > 0)
877
- add(
878
- "focus-needs-keyboard-inspection",
879
- "warning",
880
- `${keyboardInspectionNeeded} controls need a keyboard focus walkthrough.`
881
- );
882
- if (focusTargets.length > 150)
883
- add("focus-audit-limit", "warning", "Only the first 150 focusable controls were inspected.");
884
- return {
885
- screenId,
886
- viewport,
887
- checkedElements,
888
- checkedContrast,
889
- skippedContrast,
890
- checkedFocus,
891
- issues
892
- };
893
- }
894
- async function attachedArtifactFrame(page, artifactId, warn) {
895
- const deadline = Date.now() + 5e3;
896
- const escaped = artifactId.replace(
897
- /[^a-z0-9_-]/giu,
898
- (char) => `\\${char.codePointAt(0).toString(16)} `
899
- );
900
- const handle = await page.waitForSelector(
901
- `iframe[data-planr-artifact-frame="${escaped}"], iframe[data-planr-artifact-id="${escaped}"]`,
902
- { state: "attached", timeout: 5e3 }
903
- );
904
- try {
905
- return await new Promise((resolve4, reject) => {
906
- let settled = false;
907
- const finish = (error, frame) => {
908
- if (settled) return;
909
- settled = true;
910
- clearTimeout(timer);
911
- page.off("frameattached", inspect);
912
- page.off("framenavigated", inspect);
913
- if (error) reject(error);
914
- else resolve4(frame);
915
- };
916
- const inspect = async (frame) => {
917
- if (settled || frame === page.mainFrame?.()) return;
918
- try {
919
- const candidate = await frame.frameElement();
920
- let matches;
921
- try {
922
- matches = await handle.evaluate((element, other) => element === other, candidate);
923
- } finally {
924
- await candidate.dispose?.();
925
- }
926
- if (matches) finish(null, frame);
927
- } catch (error) {
928
- if (!settled) warn(error);
929
- }
930
- };
931
- const timer = setTimeout(
932
- () => finish(new Error(`No frame attached for artifact ${artifactId} within 5000ms.`)),
933
- Math.max(1, deadline - Date.now())
934
- );
935
- page.on("frameattached", inspect);
936
- page.on("framenavigated", inspect);
937
- handle.contentFrame().then((frame) => {
938
- if (frame) finish(null, frame);
939
- }, finish);
940
- });
941
- } finally {
942
- await handle.dispose?.();
943
- }
944
- }
945
- async function auditDesignPage(page, { revision, document: document2, entries = [], screenshotPaths = [], scenarios = [] } = {}) {
946
- if (!document2 || typeof document2 !== "object" || Array.isArray(document2))
947
- throw new TypeError("Audit requires a design document input.");
948
- const issues = [], checkedArtifacts = [], screens = [];
949
- const frameBoundsSeverity = document2.frames?.some((frame) => frame.height === "auto") ? "error" : "warning";
950
- const expected = new Map(entries.map((entry) => [entry.artifactId, entry]));
951
- const add = (artifactId, rule, severity, message) => issues.push({ artifactId, rule, severity, message });
952
- if (!entries.length || expected.size !== entries.length)
953
- add(
954
- "studio",
955
- "invalid-audit-scope",
956
- "error",
957
- "Audit scope must contain every expected artifact exactly once."
958
- );
959
- if (!page || typeof page.frames !== "function") {
960
- return {
961
- schemaVersion: "1.0.0",
962
- revision,
963
- status: "unverified",
964
- checkedArtifacts,
965
- issues: [
966
- {
967
- artifactId: "studio",
968
- rule: "browser-unavailable",
969
- severity: "warning",
970
- message: "A browser page is required for rendered verification."
971
- }
972
- ],
973
- screenshots: screenshotPaths,
974
- scenarios,
975
- screens
976
- };
977
- }
978
- const loaded = /* @__PURE__ */ new Set();
979
- for (const entry of expected.values()) {
980
- let frameHold;
981
- try {
982
- try {
983
- frameHold = await page.evaluateHandle?.((id) => {
984
- const stage = window.__openPlanrArtifactStage;
985
- return stage?.frameBudget ? stage.holdFrames([id]) : null;
986
- }, entry.artifactId);
987
- await page.evaluate?.(async (id) => {
988
- const stage = window.__openPlanrArtifactStage;
989
- if (stage?.frameBudget) await stage.ensureFrames([id]);
990
- }, entry.artifactId);
991
- } catch (error) {
992
- add(
993
- entry.artifactId,
994
- "frame-load-error",
995
- "error",
996
- `The rendered frame could not be mounted: ${error.message}`
997
- );
998
- continue;
999
- }
1000
- let frames;
1001
- if (["waitForSelector", "on", "off"].every((method) => typeof page[method] === "function")) {
1002
- try {
1003
- const frame = await attachedArtifactFrame(
1004
- page,
1005
- entry.artifactId,
1006
- (error) => add(
1007
- entry.artifactId,
1008
- "frame-attachment-inspection-error",
1009
- "warning",
1010
- `A frame attachment could not be matched to artifact ${entry.artifactId}: ${error.message}`
1011
- )
1012
- );
1013
- frames = [frame, ...page.frames().filter((candidate) => candidate !== frame)];
1014
- } catch (error) {
1015
- add(
1016
- entry.artifactId,
1017
- "frame-load-error",
1018
- "error",
1019
- `Artifact ${entry.artifactId} has no frame attached for inspection: ${error.message}`
1020
- );
1021
- continue;
1022
- }
1023
- } else frames = page.frames();
1024
- for (const frame of frames) {
1025
- let handle, artifactId, panelState;
1026
- try {
1027
- if (frame === page.mainFrame?.()) continue;
1028
- handle = await frame.frameElement();
1029
- artifactId = await handle.getAttribute("data-planr-artifact-frame") ?? await handle.getAttribute("data-planr-artifact-id");
1030
- if (artifactId !== entry.artifactId) continue;
1031
- if (loaded.has(artifactId)) {
1032
- add(
1033
- artifactId,
1034
- "duplicate-frame",
1035
- "error",
1036
- "Multiple frames claim the same artifact identity."
1037
- );
1038
- continue;
1039
- }
1040
- loaded.add(artifactId);
1041
- await frame.waitForLoadState?.("load", { timeout: 5e3 });
1042
- panelState = await handle.evaluate((element) => {
1043
- const panel = element.closest("[data-artifact-id]");
1044
- if (!panel) return null;
1045
- const hidden = panel.hidden;
1046
- panel.hidden = false;
1047
- return { hidden };
1048
- });
1049
- await page.keyboard?.press("Tab");
1050
- const result = await frame.evaluate(auditRenderedScreen, {
1051
- height: entry.height,
1052
- frameBoundsSeverity
1053
- });
1054
- if (result.screenId !== entry.screenId) {
1055
- add(
1056
- artifactId,
1057
- "screen-identity-mismatch",
1058
- "error",
1059
- `Expected screen ${entry.screenId}; loaded ${result.screenId ?? "none"}.`
1060
- );
1061
- continue;
1062
- }
1063
- checkedArtifacts.push(artifactId);
1064
- screens.push({ artifactId, ...result });
1065
- for (const issue of result.issues)
1066
- add(artifactId, issue.rule, issue.severity, issue.message);
1067
- } catch (error) {
1068
- if (artifactId && expected.has(artifactId))
1069
- add(
1070
- artifactId,
1071
- "frame-load-error",
1072
- "error",
1073
- `The rendered frame could not be inspected: ${error.message}`
1074
- );
1075
- } finally {
1076
- if (panelState && handle) {
1077
- await handle.evaluate((element, state) => {
1078
- const panel = element.closest("[data-artifact-id]");
1079
- if (panel) panel.hidden = state.hidden;
1080
- }, panelState).catch(
1081
- (error) => add(
1082
- artifactId,
1083
- "panel-visibility-restore-error",
1084
- "warning",
1085
- `Artifact ${artifactId} panel visibility could not be restored: ${error.message}`
1086
- )
1087
- );
1088
- }
1089
- await handle?.dispose?.();
1090
- }
1091
- }
1092
- } finally {
1093
- try {
1094
- await frameHold?.evaluate((release) => release?.());
1095
- } finally {
1096
- await frameHold?.dispose();
1097
- }
1098
- }
1099
- }
1100
- for (const artifactId of expected.keys()) {
1101
- if (!checkedArtifacts.includes(artifactId))
1102
- add(
1103
- artifactId,
1104
- "missing-frame-inspection",
1105
- "error",
1106
- "The expected artifact has no completed rendered inspection."
1107
- );
1108
- }
1109
- for (const error of await page.pageErrors?.() ?? [])
1110
- add("studio", "browser-script-error", "error", error.message ?? String(error));
1111
- const evidenceComplete = screenshotPaths.length > 0 && scenarios.length > 0 && scenarios.every(({ status: status2 }) => status2 === "passed");
1112
- const status = issues.some(({ severity }) => severity === "error") ? "failed" : evidenceComplete ? "verified" : "unverified";
1113
- return {
1114
- schemaVersion: "1.0.0",
1115
- revision,
1116
- status,
1117
- checkedArtifacts,
1118
- issues,
1119
- screenshots: screenshotPaths,
1120
- scenarios,
1121
- screens
1122
- };
1123
- }
1124
-
1125
- // packages/design/lib/design/utility.mjs
1126
- function isPng(bytes) {
1127
- if (bytes.length < 57 || !bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])))
1128
- return false;
1129
- let offset = 8, header = false, pixels = false;
1130
- while (offset + 12 <= bytes.length) {
1131
- const length = bytes.readUInt32BE(offset), type = bytes.toString("ascii", offset + 4, offset + 8);
1132
- if (length > bytes.length - offset - 12) return false;
1133
- if (!header) {
1134
- if (type !== "IHDR" || length !== 13 || bytes.readUInt32BE(offset + 8) === 0 || bytes.readUInt32BE(offset + 12) === 0)
1135
- return false;
1136
- header = true;
1137
- } else if (type === "IHDR") return false;
1138
- if (type === "IDAT" && length > 0) pixels = true;
1139
- offset += length + 12;
1140
- if (type === "IEND") return length === 0 && pixels && offset === bytes.length;
1141
- }
1142
- return false;
1143
- }
1144
- function verifyDesignDocument(file, report) {
1145
- const current = currentDesign(file);
1146
- if (!report || report.revision !== current.revision)
1147
- throw new Error("Browser report belongs to a different render revision.");
1148
- const screenEvidence = Array.isArray(report.screens) ? report.screens : [];
1149
- const checkedArtifacts = Array.isArray(report.checkedArtifacts) ? report.checkedArtifacts : [];
1150
- const coverage = current.entries.every((entry) => {
1151
- const frame = current.document.frames.find((item) => item.id === entry.frameId);
1152
- const matches = screenEvidence.filter((item) => item?.artifactId === entry.artifactId);
1153
- return checkedArtifacts.includes(entry.artifactId) && matches.length === 1 && matches[0].screenId === entry.screenId && matchesDesignFrame(frame, matches[0].viewport) && Number.isInteger(matches[0].checkedElements) && matches[0].checkedElements > 0;
1154
- });
1155
- const images = (Array.isArray(report.screenshots) ? report.screenshots : []).filter((item) => {
1156
- const path = typeof item === "string" ? item : item?.path;
1157
- try {
1158
- return typeof path === "string" && isPng(readFileSync(resolve3(path)));
1159
- } catch {
1160
- return false;
1161
- }
1162
- });
1163
- const journeys = Array.isArray(report.scenarios) && report.scenarios.length > 0 && report.scenarios.every(
1164
- (item) => item?.status === "passed" && [item.name, item.id].some((value) => typeof value === "string" && value.trim().length > 0)
1165
- );
1166
- const issues = [
1167
- ...Array.isArray(report.issues) ? report.issues : [],
1168
- ...screenEvidence.flatMap((item) => Array.isArray(item?.issues) ? item.issues : [])
1169
- ];
1170
- const status = issues.some((item) => item?.severity === "error") || report.status === "failed" ? "failed" : coverage && images.length > 0 && journeys && report.status !== "unverified" ? "verified" : "unverified";
1171
- const saved = {
1172
- ...report,
1173
- issues,
1174
- schemaVersion: "1.0.0",
1175
- revision: current.revision,
1176
- status,
1177
- checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
1178
- coverage,
1179
- screenshotCount: images.length,
1180
- primaryJourneysChecked: Boolean(journeys)
1181
- };
1182
- atomicJson(join4(current.root, ".design/verification", `${current.revision}.json`), saved);
1183
- return saved;
1184
- }
1185
- var HELP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h"]);
1186
- var COMMAND_SUMMARIES = Object.freeze({
1187
- inspect: "Report the design document and its current render.",
1188
- validate: "Validate the design document without rendering.",
1189
- render: "Render the design document into its review revision.",
1190
- open: "Open the local review studio.",
1191
- studio: "Report or stop a running local studio (--action status|stop).",
1192
- "view-context": "Report what the studio is showing.",
1193
- export: "Export the design as html, json, or markdown.",
1194
- feedback: "Inspect, export, or import review feedback.",
1195
- verify: "Record a browser verification report.",
1196
- share: "Create a hosted review of the current revision.",
1197
- publish: "Publish the current revision to the existing hosted review.",
1198
- sync: "Retrieve hosted review feedback.",
1199
- manage: "Manage a hosted review (--action rotate|pause|resume|revoke|delete|recovery|restore).",
1200
- handoff: "Inspect or update the review handoff.",
1201
- fonts: "Download open-license fonts (fonts fetch --family ... --dest ...)."
1202
- });
1203
- function commandHelp(command) {
1204
- if (!Object.hasOwn(COMMAND_SUMMARIES, command))
1205
- throw new Error(`Unknown command: ${command}. Run design.mjs --help for the command list.`);
1206
- return {
1207
- command,
1208
- usage: command === "fonts" ? 'design.mjs fonts fetch --family "<Name>:<weights>" [--family ...] --dest <dir>' : `design.mjs ${command} <design-document.json> [options]`,
1209
- summary: COMMAND_SUMMARIES[command],
1210
- note: "Run design.mjs --help for every option. A help request never reads, renders, or sends anything."
1211
- };
1212
- }
1213
- async function designUtility(argv, {
1214
- stdout = (value) => process.stdout.write(`${JSON.stringify(value)}
1215
- `),
1216
- openUrl,
1217
- env = process.env,
1218
- fetchImpl = fetch
1219
- } = {}) {
1220
- if (argv.length === 0 || ["--help", "-h", "help"].includes(argv[0])) {
1221
- const help = {
1222
- usage: 'design.mjs inspect|validate|render|open|studio|view-context|export|feedback|verify|share|publish|sync|manage|handoff <design-document.json> | design.mjs fonts fetch --family "<Name>:<weights>" [--family ...] --dest <dir>',
1223
- flags: [
1224
- "--json",
1225
- "--no-open",
1226
- "--view canvas|prototype|walkthrough",
1227
- "--port <number>",
1228
- "--format html|json|markdown",
1229
- "--scope current|all",
1230
- "--output <path>",
1231
- "--report <browser-report.json>",
1232
- "--action inspect|export|import|select|resolve|rotate|pause|resume|revoke|delete|recovery|restore|status|stop",
1233
- "--input <private recovery or feedback JSON file>",
1234
- "--revision <current-render-revision>",
1235
- "--request-time <ISO-timestamp>",
1236
- "--allow-stale",
1237
- "--variant <id>",
1238
- "--pins <id,id>",
1239
- "--summary <text>",
1240
- "--family <Name>:<weight,weight> (fonts fetch; at most 2 families, 3 weights each)",
1241
- "--dest <design>/source/assets/fonts (fonts fetch)"
1242
- ],
1243
- note: "The host authors design sources. This utility only validates, renders, reviews and exports them; fonts fetch downloads open-license fonts only when run."
1244
- };
1245
- stdout(help);
1246
- return help;
1247
- }
1248
- const [command, input, ...args] = argv;
1249
- if (argv.some((value) => HELP_FLAGS.has(value))) {
1250
- const help = commandHelp(command);
1251
- stdout(help);
1252
- return help;
1253
- }
1254
- if (typeof input === "string" && input.startsWith("-"))
1255
- throw new Error(`${input} must be a design document path, not an option.`);
1256
- if (![
1257
- "inspect",
1258
- "validate",
1259
- "render",
1260
- "open",
1261
- "studio",
1262
- "view-context",
1263
- "export",
1264
- "feedback",
1265
- "verify",
1266
- "share",
1267
- "publish",
1268
- "sync",
1269
- "manage",
1270
- "handoff",
1271
- "fonts"
1272
- ].includes(command) || !input)
1273
- throw new Error(
1274
- 'Usage: design.mjs inspect|validate|render|open|studio|view-context|export|feedback|verify|share|publish|sync|manage|handoff <design-document.json> [--json] [--no-open] [--view canvas|prototype|walkthrough] | design.mjs fonts fetch --family "<Name>:<weights>" [--family ...] --dest <dir>'
1275
- );
1276
- const flags = {};
1277
- for (let i = 0; i < args.length; i++) {
1278
- if (!args[i].startsWith("--")) throw new Error(`Unexpected argument: ${args[i]}`);
1279
- const key = args[i].slice(2);
1280
- if (![
1281
- "json",
1282
- "no-open",
1283
- "view",
1284
- "format",
1285
- "output",
1286
- "port",
1287
- "report",
1288
- "action",
1289
- "instance-id",
1290
- "pins",
1291
- "summary",
1292
- "variant",
1293
- "input",
1294
- "scope",
1295
- "revision",
1296
- "request-time",
1297
- "allow-stale",
1298
- "family",
1299
- "dest"
1300
- ].includes(key))
1301
- throw new Error(`Unknown option: ${args[i]}`);
1302
- if (["family", "dest"].includes(key) && command !== "fonts")
1303
- throw new Error(`Unknown option for ${command}: ${args[i]}`);
1304
- if (key === "family") flags.family = [...flags.family ?? [], args[++i]];
1305
- else flags[key] = ["json", "no-open", "allow-stale"].includes(key) ? true : args[++i];
1306
- }
1307
- if (flags.view && !["canvas", "prototype", "walkthrough"].includes(flags.view))
1308
- throw new Error("View must be canvas, prototype, or walkthrough.");
1309
- if (command === "fonts") {
1310
- if (input !== "fetch")
1311
- throw new Error(
1312
- 'Usage: design.mjs fonts fetch --family "<Name>:<weights>" [--family ...] --dest <dir>'
1313
- );
1314
- const result2 = await fetchDesignFonts({ families: flags.family, dest: flags.dest, fetchImpl });
1315
- stdout(result2);
1316
- return result2;
1317
- }
1318
- const file = resolve3(input);
1319
- let result;
1320
- if (command === "view-context")
1321
- result = readDesignViewContext(file, { requestTime: flags["request-time"] });
1322
- if (command === "studio")
1323
- result = await manageDesignStudio(file, {
1324
- action: flags.action,
1325
- instanceId: flags["instance-id"],
1326
- env,
1327
- fetchImpl
1328
- });
1329
- if (command === "handoff") {
1330
- const action = flags.action ?? "inspect";
1331
- if (action === "inspect") result = readDesignHandoff(file);
1332
- else {
1333
- const snapshot = readDesignHandoff(file);
1334
- const input2 = flags.input ? readJson(resolve3(flags.input)) : {};
1335
- result = await updateDesignHandoff(file, {
1336
- ...input2,
1337
- action,
1338
- revision: input2.revision ?? snapshot.revision,
1339
- version: input2.version ?? snapshot.draft?.version ?? 0
1340
- });
1341
- }
1342
- }
1343
- if (command === "share") result = await shareDesign(file);
1344
- if (command === "publish") result = await publishDesignShare(file);
1345
- if (command === "sync") result = await syncDesignShare(file);
1346
- if (command === "manage" && !["rotate", "pause", "resume", "revoke", "delete", "recovery", "restore"].includes(flags.action))
1347
- throw new Error("manage requires --action rotate|pause|resume|revoke|delete|recovery|restore.");
1348
- if (command === "manage")
1349
- result = flags.action === "restore" ? await importDesignShareRecovery(file, { input: flags.input }) : flags.action === "recovery" ? await exportDesignShareRecovery(file, { output: flags.output }) : await manageDesignShare(file, flags.action);
1350
- if (command === "inspect") result = inspectDesignDocument(file);
1351
- if (command === "validate") {
1352
- const prepared = prepareDesignDocument(file);
1353
- result = {
1354
- ok: prepared.lint.every((item) => item.ok),
1355
- lint: prepared.lint,
1356
- screens: prepared.document.screens.length,
1357
- artifacts: prepared.entries.length,
1358
- verification: "unverified"
1359
- };
1360
- }
1361
- if (command === "render") result = await renderDesignDocument(file);
1362
- if (command === "open") {
1363
- const port = flags.port === void 0 ? 0 : Number(flags.port);
1364
- if (!Number.isInteger(port) || port < 0 || port > 65535)
1365
- throw new Error("Port must be 0\u201365535.");
1366
- result = await startDesignReview(file, {
1367
- port,
1368
- view: flags.view,
1369
- noOpen: Boolean(flags["no-open"]),
1370
- openUrl,
1371
- env,
1372
- fetchImpl
1373
- });
1374
- const close = result.close;
1375
- if (close) {
1376
- process.once("SIGINT", async () => {
1377
- await close();
1378
- process.exit(0);
1379
- });
1380
- process.once("SIGTERM", async () => {
1381
- await close();
1382
- process.exit(0);
1383
- });
1384
- }
1385
- }
1386
- if (command === "export") {
1387
- const current = currentDesign(file), view = flags.view ?? current.document.defaultView;
1388
- const state = readJson(join4(current.root, ".design/studio-state.json"), { state: {} }).state;
1389
- if (flags.format && flags.format !== "html")
1390
- throw new Error(
1391
- "Portable export supports HTML. Use the studio PNG action for browser-rendered captures."
1392
- );
1393
- const output = resolve3(flags.output ?? join4(current.root, `${view}-export.html`));
1394
- if (existsSync2(output))
1395
- throw new Error(`Export already exists: ${output}. Choose a new --output path.`);
1396
- mkdirSync2(dirname2(output), { recursive: true });
1397
- writeFileSync2(output, standaloneDesignHtml({ ...current, state }, view), { flag: "wx" });
1398
- result = { ok: true, output, view, revision: current.revision };
1399
- }
1400
- if (command === "verify") {
1401
- if (!flags.report) throw new Error("verify requires --report <browser-report.json>.");
1402
- result = verifyDesignDocument(file, readJson(resolve3(flags.report)));
1403
- }
1404
- if (command === "feedback") {
1405
- const action = flags.action ?? "inspect";
1406
- const synced = action === "import" ? void 0 : await syncDesignShare(file, { env, fetchImpl, unavailable: "skip" });
1407
- if (action === "import")
1408
- result = await importDesignFeedback(file, {
1409
- input: flags.input,
1410
- revision: flags.revision,
1411
- allowStale: Boolean(flags["allow-stale"]),
1412
- env
1413
- });
1414
- else if (action === "inspect") result = readDesignFeedback(file, env);
1415
- else if (action === "export") {
1416
- const format = flags.format ?? "json", scope = flags.scope ?? "all";
1417
- if (!["json", "markdown"].includes(format))
1418
- throw new Error("Feedback export format must be json or markdown.");
1419
- if (!["current", "all"].includes(scope))
1420
- throw new Error("Feedback export scope must be current or all.");
1421
- if (!flags.output) throw new Error("Feedback export requires --output <path>.");
1422
- const output = resolve3(flags.output);
1423
- if (existsSync2(output))
1424
- throw new Error("Feedback export already exists. Choose a new --output path.");
1425
- const snapshot = exportDesignReview(file, { scope, env });
1426
- mkdirSync2(dirname2(output), { recursive: true });
1427
- writeFileSync2(output, serializeDesignReviewExport(snapshot, format), {
1428
- flag: "wx",
1429
- mode: 384
1430
- });
1431
- result = {
1432
- ok: true,
1433
- output,
1434
- format,
1435
- scope,
1436
- revision: snapshot.currentRevisionId,
1437
- summary: snapshot.summary
1438
- };
1439
- } else if (action === "resolve")
1440
- result = await resolveDesignPins(file, {
1441
- pinIds: flags.pins?.split(",").filter(Boolean),
1442
- summary: flags.summary,
1443
- env
1444
- });
1445
- else if (action === "select") {
1446
- const current = currentDesign(file), saved = readJson(join4(current.root, ".design/studio-state.json"), {
1447
- state: {},
1448
- stateVersion: 0
1449
- });
1450
- const variant = flags.variant ?? saved.state.selectedVariant;
1451
- if (!current.document.variants.some((item) => item.id === variant && item.status === "ready"))
1452
- throw new Error("Select a ready variant with --variant.");
1453
- const selected = [variant], rejected = (saved.state.preferences?.rejected ?? []).filter((id) => id !== variant);
1454
- result = await saveDesignState(file, {
1455
- ...saved,
1456
- revision: current.revision,
1457
- state: { ...saved.state, selectedVariant: variant, preferences: { selected, rejected } }
1458
- });
1459
- result = {
1460
- ok: true,
1461
- selectedVariant: variant,
1462
- tastePath: result.tastePath,
1463
- revision: current.revision
1464
- };
1465
- } else throw new Error("Feedback action must be inspect, export, import, select, or resolve.");
1466
- if (synced?.skipped)
1467
- result = { ...result, sync: { skipped: synced.skipped, reason: synced.reason } };
1468
- }
1469
- stdout(result);
1470
- return result;
1471
- }
1472
- async function main(argv = process.argv.slice(2)) {
1473
- try {
1474
- const result = await designUtility(argv, {
1475
- openUrl: async (url) => {
1476
- const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "explorer.exe" : "xdg-open";
1477
- const child = spawn(command, [url], { stdio: "ignore" });
1478
- child.on("error", () => {
1479
- });
1480
- child.unref();
1481
- }
1482
- });
1483
- if (result?.ok === false || result?.status === "failed") process.exitCode = 1;
1484
- return result;
1485
- } catch (error) {
1486
- process.stderr.write(`${error.message}
1487
- `);
1488
- process.exitCode = 1;
1489
- }
1490
- }
1491
- var invokedDirectly = process.argv[1] && fileURLToPath(import.meta.url) === realpathSync(process.argv[1]);
1492
- if (invokedDirectly) await main();
1493
- export {
1494
- auditDesignPage,
1495
- auditRenderedScreen,
1496
- designUtility,
1497
- main,
1498
- readDesignViewContext,
1499
- verifyDesignDocument
1500
- };