openplanr 3.3.0 → 3.4.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 (267) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/cli/commands/artifact-design-share.d.ts +9 -0
  3. package/dist/cli/commands/artifact-design-share.d.ts.map +1 -0
  4. package/dist/cli/commands/artifact-design-share.js +200 -0
  5. package/dist/cli/commands/artifact-design-share.js.map +1 -0
  6. package/dist/cli/commands/artifact.d.ts.map +1 -1
  7. package/dist/cli/commands/artifact.js +5 -18
  8. package/dist/cli/commands/artifact.js.map +1 -1
  9. package/dist/cli/commands/ship.d.ts.map +1 -1
  10. package/dist/cli/commands/ship.js +2 -0
  11. package/dist/cli/commands/ship.js.map +1 -1
  12. package/dist/dashboard/.vite/manifest.json +2 -2
  13. package/dist/dashboard/assets/index-Cv4Vwhuw.css +2 -0
  14. package/dist/dashboard/assets/index-CvQAlBy3.js +75 -0
  15. package/dist/dashboard/assets/index-CvQAlBy3.js.map +1 -0
  16. package/dist/dashboard/dashboard-manifest.json +14 -14
  17. package/dist/dashboard/index.html +2 -2
  18. package/dist/services/design-artifact-service.d.ts +20 -1
  19. package/dist/services/design-artifact-service.d.ts.map +1 -1
  20. package/dist/services/design-artifact-service.js +137 -18
  21. package/dist/services/design-artifact-service.js.map +1 -1
  22. package/dist/services/ship-checks/contract.d.ts +3 -1
  23. package/dist/services/ship-checks/contract.d.ts.map +1 -1
  24. package/dist/services/ship-checks/contract.js +1 -1
  25. package/dist/services/ship-checks/contract.js.map +1 -1
  26. package/dist/services/ship-checks/discover.d.ts.map +1 -1
  27. package/dist/services/ship-checks/discover.js +2 -1
  28. package/dist/services/ship-checks/discover.js.map +1 -1
  29. package/dist/services/ship-checks/package-contents.d.ts +4 -0
  30. package/dist/services/ship-checks/package-contents.d.ts.map +1 -0
  31. package/dist/services/ship-checks/package-contents.js +91 -0
  32. package/dist/services/ship-checks/package-contents.js.map +1 -0
  33. package/dist/services/ship-checks/packages.d.ts +2 -0
  34. package/dist/services/ship-checks/packages.d.ts.map +1 -1
  35. package/dist/services/ship-checks/packages.js +4 -0
  36. package/dist/services/ship-checks/packages.js.map +1 -1
  37. package/dist/services/ship-checks/scope.js +2 -1
  38. package/dist/services/ship-checks/scope.js.map +1 -1
  39. package/dist/utils/splice-managed-block.js +1 -1
  40. package/dist/utils/splice-managed-block.js.map +1 -1
  41. package/docs/CLI.md +38 -1
  42. package/lib/host-packages/adapter-registry.json +5 -5
  43. package/lib/host-packages/capability-map.json +1 -1
  44. package/lib/host-packages/claude/.claude-plugin/marketplace.json +3 -3
  45. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +6 -6
  46. package/lib/host-packages/claude/openplanr/.openplanr-content.json +67 -123
  47. package/lib/host-packages/claude/openplanr/README.md +12 -12
  48. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/task-context-resolution.md +4 -4
  49. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-artifact-shell.mjs +2 -4
  50. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +26 -26
  51. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +850 -56
  52. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review-state-store.mjs +45 -0
  53. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review.mjs +65 -74
  54. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -1
  55. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +321 -0
  56. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs → claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs} +762 -223
  57. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs → claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-9f6918b0.mjs} +537 -5
  58. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +137 -0
  59. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +107 -37
  60. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -27
  61. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +138 -133
  62. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +1 -5684
  63. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +2568 -0
  64. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +10 -74
  65. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  66. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +8 -2
  67. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  68. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +545 -4781
  69. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +219 -452
  70. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  71. package/lib/host-packages/claude/openplanr/skills/delegate/SKILL.md +2 -1
  72. package/lib/host-packages/claude/openplanr/skills/delegate/references/integration-review.md +26 -20
  73. package/lib/host-packages/claude/openplanr/skills/delegate/references/operator-guide.md +25 -1
  74. package/lib/host-packages/claude/openplanr/skills/delegate/references/run-handoff.md +2 -2
  75. package/lib/host-packages/claude/openplanr/skills/delegate/references/worktree-custody.md +17 -9
  76. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/claude.mjs +15 -3
  77. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/codex.mjs +38 -2
  78. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/native.mjs +5 -0
  79. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/custody.mjs +217 -10
  80. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/handoff.mjs +1080 -0
  81. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integrate.mjs +96 -201
  82. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integration-files.mjs +3 -382
  83. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/presentation.mjs +29 -12
  84. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-contract.mjs +11 -0
  85. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-execution.mjs +1 -1
  86. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-lifecycle.mjs +14 -10
  87. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-preparation.mjs +4 -0
  88. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-record.mjs +2 -2
  89. package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +14 -8
  90. package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +14 -8
  91. package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +14 -8
  92. package/lib/host-packages/claude/openplanr/skills/investigate/SKILL.md +1 -0
  93. package/lib/host-packages/claude/openplanr/skills/investigate/references/fail-first.md +40 -0
  94. package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +22 -10
  95. package/lib/host-packages/claude/openplanr/skills/ship/references/fail-first.md +40 -0
  96. package/lib/host-packages/claude/openplanr/skills/ship/references/result-contract.md +7 -3
  97. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +65 -121
  98. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  99. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/integration-review.md +26 -20
  100. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/operator-guide.md +25 -1
  101. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/run-handoff.md +2 -2
  102. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/worktree-custody.md +17 -9
  103. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/claude.mjs +15 -3
  104. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/codex.mjs +38 -2
  105. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/native.mjs +5 -0
  106. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/custody.mjs +217 -10
  107. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/handoff.mjs +1080 -0
  108. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integrate.mjs +96 -201
  109. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integration-files.mjs +3 -382
  110. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/presentation.mjs +29 -12
  111. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-contract.mjs +11 -0
  112. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-execution.mjs +1 -1
  113. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-lifecycle.mjs +14 -10
  114. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-preparation.mjs +4 -0
  115. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-record.mjs +2 -2
  116. package/lib/host-packages/cursor/openplanr/rules/planr-delegate.mdc +2 -1
  117. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +14 -8
  118. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +14 -8
  119. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +14 -8
  120. package/lib/host-packages/cursor/openplanr/rules/planr-investigate/references/fail-first.md +40 -0
  121. package/lib/host-packages/cursor/openplanr/rules/planr-investigate.mdc +1 -0
  122. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/fail-first.md +40 -0
  123. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/result-contract.md +7 -3
  124. package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +22 -10
  125. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-artifact-shell.mjs +2 -4
  126. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +26 -26
  127. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +850 -56
  128. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review-state-store.mjs +45 -0
  129. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review.mjs +65 -74
  130. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -1
  131. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +321 -0
  132. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/{design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs → design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs} +762 -223
  133. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/{design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs → design-shared-artifact-support-protocol-contracts-9f6918b0.mjs} +537 -5
  134. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +137 -0
  135. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +107 -37
  136. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -27
  137. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +138 -133
  138. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +1 -5684
  139. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +2568 -0
  140. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +10 -74
  141. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  142. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +8 -2
  143. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  144. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +545 -4781
  145. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +219 -452
  146. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  147. package/lib/host-packages/openai/.claude-plugin/marketplace.json +3 -3
  148. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +2 -2
  149. package/lib/host-packages/openai/openplanr/.openplanr-content.json +68 -124
  150. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-artifact-shell.mjs +2 -4
  151. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +26 -26
  152. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +850 -56
  153. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review-state-store.mjs +45 -0
  154. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review.mjs +65 -74
  155. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -1
  156. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +321 -0
  157. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs → openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs} +762 -223
  158. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs → openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-9f6918b0.mjs} +537 -5
  159. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +137 -0
  160. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +107 -37
  161. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +0 -27
  162. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +138 -133
  163. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +1 -5684
  164. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +2568 -0
  165. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +10 -74
  166. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  167. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +8 -2
  168. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  169. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +545 -4781
  170. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +219 -452
  171. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  172. package/lib/host-packages/openai/openplanr/skills/delegate/SKILL.md +2 -1
  173. package/lib/host-packages/openai/openplanr/skills/delegate/openplanr.skill.json +1 -1
  174. package/lib/host-packages/openai/openplanr/skills/delegate/references/integration-review.md +26 -20
  175. package/lib/host-packages/openai/openplanr/skills/delegate/references/operator-guide.md +25 -1
  176. package/lib/host-packages/openai/openplanr/skills/delegate/references/run-handoff.md +2 -2
  177. package/lib/host-packages/openai/openplanr/skills/delegate/references/worktree-custody.md +17 -9
  178. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/claude.mjs +15 -3
  179. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/codex.mjs +38 -2
  180. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/native.mjs +5 -0
  181. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/custody.mjs +217 -10
  182. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/handoff.mjs +1080 -0
  183. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integrate.mjs +96 -201
  184. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integration-files.mjs +3 -382
  185. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/presentation.mjs +29 -12
  186. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-contract.mjs +11 -0
  187. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-execution.mjs +1 -1
  188. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-lifecycle.mjs +14 -10
  189. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-preparation.mjs +4 -0
  190. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-record.mjs +2 -2
  191. package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +14 -8
  192. package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +14 -8
  193. package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +14 -8
  194. package/lib/host-packages/openai/openplanr/skills/investigate/SKILL.md +1 -0
  195. package/lib/host-packages/openai/openplanr/skills/investigate/openplanr.skill.json +12 -1
  196. package/lib/host-packages/openai/openplanr/skills/investigate/references/fail-first.md +40 -0
  197. package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +22 -10
  198. package/lib/host-packages/openai/openplanr/skills/ship/openplanr.skill.json +12 -1
  199. package/lib/host-packages/openai/openplanr/skills/ship/references/fail-first.md +40 -0
  200. package/lib/host-packages/openai/openplanr/skills/ship/references/result-contract.md +7 -3
  201. package/package.json +8 -8
  202. package/dist/dashboard/assets/index-BU5fzjyz.css +0 -1
  203. package/dist/dashboard/assets/index-B_96uzCl.js +0 -572
  204. package/dist/dashboard/assets/index-B_96uzCl.js.map +0 -1
  205. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
  206. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
  207. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
  208. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
  209. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
  210. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs +0 -24
  211. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
  212. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
  213. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5907
  214. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
  215. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
  216. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
  217. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
  218. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
  219. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
  220. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
  221. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
  222. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
  223. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
  224. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
  225. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integration-transaction.mjs +0 -958
  226. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integration-transaction.mjs +0 -958
  227. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
  228. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
  229. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
  230. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
  231. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
  232. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs +0 -24
  233. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
  234. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
  235. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5907
  236. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
  237. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
  238. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
  239. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
  240. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
  241. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
  242. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
  243. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
  244. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
  245. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
  246. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
  247. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
  248. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
  249. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
  250. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
  251. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
  252. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-support-25485dbf1cb2.mjs +0 -24
  253. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
  254. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
  255. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5907
  256. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
  257. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
  258. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
  259. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
  260. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
  261. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
  262. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
  263. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
  264. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
  265. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
  266. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
  267. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integration-transaction.mjs +0 -958
@@ -1,40 +1,817 @@
1
- import {
2
- getDesignShareStatus,
3
- publishDesignReviewMetadata,
4
- readArtifactReviewState,
5
- resolveArtifactReviewDestination,
6
- withArtifactReviewLock
7
- } from "./design-share.mjs";
8
1
  import {
9
2
  DESIGN_HANDOFF_CONTENT_SCHEMA,
10
3
  DESIGN_HANDOFF_SCHEMA,
4
+ assertPlainData,
11
5
  assertReviewExperience,
6
+ canonicalizeJson,
7
+ deepFreeze,
8
+ emptyReviewContext,
9
+ reviewDigest,
10
+ sha256Hex
11
+ } from "./design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs";
12
+ import {
13
+ ARTIFACT_ERROR_CODES,
14
+ PipelineError,
15
+ canonicalSerialize,
16
+ digestArtifactEnvelope,
17
+ validateArtifactEnvelope,
18
+ validateArtifactReview,
19
+ validateJson
20
+ } from "./design-shared-artifact-support-protocol-contracts-9f6918b0.mjs";
21
+ import {
22
+ assertDesignShareAvailable,
23
+ getDesignShareStatus,
24
+ publishDesignReviewMetadata
25
+ } from "./design-share-cli-bridge.mjs";
26
+ import {
12
27
  atomicJson,
13
28
  currentDesign,
14
29
  designSpecPath,
15
- emptyReviewContext,
16
30
  hash,
17
- readJson,
18
- reviewDigest
19
- } from "./design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs";
31
+ readJson
32
+ } from "./design-shared-design-support-0bac378d.mjs";
33
+ import {
34
+ planrHome
35
+ } from "./design-runtime-home.mjs";
20
36
  import {
21
37
  acquireStartLock
22
38
  } from "./design-loopback-server.mjs";
39
+
40
+ // packages/design/lib/design/feedback-reader.mjs
41
+ import { join as join2 } from "node:path";
42
+
43
+ // packages/artifact/lib/artifact/import.mjs
23
44
  import {
24
- digestArtifactEnvelope
25
- } from "./design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs";
26
- import {
27
- validateJson
28
- } from "./design-shared-protocol-contracts-b5f28f94.mjs";
45
+ existsSync as existsSync2,
46
+ lstatSync as lstatSync2,
47
+ mkdirSync as mkdirSync2,
48
+ readFileSync as readFileSync2,
49
+ realpathSync,
50
+ renameSync as renameSync2,
51
+ rmSync as rmSync2,
52
+ statSync as statSync2,
53
+ writeFileSync as writeFileSync2
54
+ } from "node:fs";
55
+ import { homedir } from "node:os";
56
+ import { dirname as dirname2, isAbsolute, join, relative, resolve } from "node:path";
57
+
58
+ // packages/protocol/src/names.mjs
59
+ var PLANNING_FOLDER = ".planr";
60
+ var CLI_COMMAND = "openplanr";
61
+
62
+ // packages/artifact/lib/artifact/internal/feedback.mjs
63
+ var FEEDBACK_FILE = "feedback.json";
64
+
65
+ // packages/artifact/lib/artifact/merge.mjs
66
+ var ARTIFACT_REVIEW_STATE_VERSION = "1.0.0";
67
+ var ARTIFACT_REVIEW_STATE_KIND = "artifact-review-state";
68
+ var SHA256_RE = /^[a-f0-9]{64}$/;
69
+ var ARTIFACT_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
70
+ function conflict(message2, details = void 0) {
71
+ throw new PipelineError(
72
+ ARTIFACT_ERROR_CODES.MERGE_CONFLICT,
73
+ message2,
74
+ "Keep both reviews under different stable IDs or resolve the conflicting item explicitly.",
75
+ details
76
+ );
77
+ }
78
+ function assertUniqueReviewItemIds(review) {
79
+ const pinIds = /* @__PURE__ */ new Set();
80
+ for (const pin of review.pins ?? []) {
81
+ if (pinIds.has(pin.id)) {
82
+ throw new PipelineError(
83
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
84
+ "Artifact review contains a duplicate pin ID."
85
+ );
86
+ }
87
+ pinIds.add(pin.id);
88
+ const replyIds = /* @__PURE__ */ new Set();
89
+ for (const reply of pin.replies ?? []) {
90
+ if (replyIds.has(reply.id)) {
91
+ throw new PipelineError(
92
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
93
+ "Artifact review contains a duplicate reply ID in one thread."
94
+ );
95
+ }
96
+ replyIds.add(reply.id);
97
+ }
98
+ }
99
+ return review;
100
+ }
101
+ function clone(value) {
102
+ return structuredClone(value);
103
+ }
104
+ function same(a, b) {
105
+ return canonicalSerialize(a) === canonicalSerialize(b);
106
+ }
107
+ function timeValue(value) {
108
+ if (typeof value !== "string") return Number.NEGATIVE_INFINITY;
109
+ const parsed = Date.parse(value);
110
+ return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
111
+ }
112
+ function compareStable(a, b, idKey) {
113
+ const aTime = a.createdAt ?? a.updatedAt ?? "";
114
+ const bTime = b.createdAt ?? b.updatedAt ?? "";
115
+ return aTime.localeCompare(bTime) || String(a[idKey]).localeCompare(String(b[idKey]));
116
+ }
117
+ function replyMap(replies) {
118
+ const map = /* @__PURE__ */ new Map();
119
+ for (const reply of replies ?? []) {
120
+ const previous = map.get(reply.id);
121
+ if (previous && !same(previous, reply)) {
122
+ conflict("A reply ID refers to different immutable reply content.", { entity: "reply" });
123
+ }
124
+ map.set(reply.id, clone(reply));
125
+ }
126
+ return map;
127
+ }
128
+ function mergeReplies(stored = [], incoming = []) {
129
+ const merged = replyMap(stored);
130
+ for (const reply of incoming) {
131
+ const previous = merged.get(reply.id);
132
+ if (previous && !same(previous, reply)) {
133
+ conflict("A reply ID refers to different immutable reply content.", { entity: "reply" });
134
+ }
135
+ if (!previous) merged.set(reply.id, clone(reply));
136
+ }
137
+ return [...merged.values()].sort((a, b) => compareStable(a, b, "id"));
138
+ }
139
+ var immutablePin = (pin) => ({
140
+ id: pin.id,
141
+ author: pin.author,
142
+ artifactId: pin.artifactId,
143
+ ...pin.variant === void 0 ? {} : { variant: pin.variant },
144
+ region: pin.region,
145
+ viewport: pin.viewport,
146
+ ...pin.anchor === void 0 ? {} : { anchor: pin.anchor },
147
+ createdAt: pin.createdAt
148
+ });
149
+ var mutablePin = (pin) => ({
150
+ intent: pin.intent,
151
+ status: pin.status,
152
+ comment: pin.comment
153
+ });
154
+ function mergePin(stored, incoming) {
155
+ if (!same(immutablePin(stored), immutablePin(incoming))) {
156
+ conflict("A pin ID refers to different immutable geometry, author, or artifact content.", {
157
+ entity: "pin"
158
+ });
159
+ }
160
+ const replies = mergeReplies(stored.replies, incoming.replies);
161
+ const storedTime = timeValue(stored.updatedAt);
162
+ const incomingTime = timeValue(incoming.updatedAt);
163
+ let selected = stored;
164
+ if (incomingTime > storedTime) selected = incoming;
165
+ if (incomingTime === storedTime && !same(mutablePin(stored), mutablePin(incoming))) {
166
+ conflict("A pin has divergent mutable content at the same update time.", { entity: "pin" });
167
+ }
168
+ return { ...clone(selected), replies };
169
+ }
170
+ function mergePins(stored = [], incoming = []) {
171
+ const merged = /* @__PURE__ */ new Map();
172
+ for (const pin of stored) merged.set(pin.id, clone(pin));
173
+ for (const pin of incoming) {
174
+ const previous = merged.get(pin.id);
175
+ merged.set(pin.id, previous ? mergePin(previous, pin) : clone(pin));
176
+ }
177
+ return [...merged.values()].sort((a, b) => compareStable(a, b, "id"));
178
+ }
179
+ var immutableReview = (review) => ({
180
+ schemaVersion: review.schemaVersion,
181
+ reviewId: review.reviewId,
182
+ reviewOf: review.reviewOf,
183
+ ...review.createdAt === void 0 ? {} : { createdAt: review.createdAt }
184
+ });
185
+ var mutableReview = (review) => ({ decision: review.decision, overall: review.overall });
186
+ function mergeArtifactReviews(stored, incoming) {
187
+ validateArtifactReview(stored);
188
+ validateArtifactReview(incoming);
189
+ assertUniqueReviewItemIds(stored);
190
+ assertUniqueReviewItemIds(incoming);
191
+ if (stored.reviewId !== incoming.reviewId) {
192
+ conflict("Only reviews with the same review ID can be revision-merged.", {
193
+ entity: "review"
194
+ });
195
+ }
196
+ if (same(stored, incoming)) return stored;
197
+ if (!same(immutableReview(stored), immutableReview(incoming))) {
198
+ conflict("A review ID refers to a different digest or creation identity.", {
199
+ entity: "review"
200
+ });
201
+ }
202
+ const storedTime = timeValue(stored.updatedAt);
203
+ const incomingTime = timeValue(incoming.updatedAt);
204
+ let selected = stored;
205
+ if (incomingTime > storedTime) selected = incoming;
206
+ if (incomingTime === storedTime && !same(mutableReview(stored), mutableReview(incoming))) {
207
+ conflict("A review has divergent verdict or overall feedback at the same update time.", {
208
+ entity: "review"
209
+ });
210
+ }
211
+ const merged = {
212
+ ...clone(selected),
213
+ pins: mergePins(stored.pins, incoming.pins)
214
+ };
215
+ validateArtifactReview(merged);
216
+ return merged;
217
+ }
218
+ function validateReviewLedger(ledger) {
219
+ if (!ledger || typeof ledger !== "object" || Array.isArray(ledger) || ledger.schemaVersion !== ARTIFACT_REVIEW_STATE_VERSION || ledger.kind !== ARTIFACT_REVIEW_STATE_KIND || !ARTIFACT_ID_RE.test(ledger.artifactId ?? "") || !SHA256_RE.test(ledger.currentReviewOf ?? "") || !Array.isArray(ledger.reviews)) {
220
+ throw new PipelineError(
221
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
222
+ "Artifact review state is not a valid versioned review ledger."
223
+ );
224
+ }
225
+ const ids = /* @__PURE__ */ new Set();
226
+ for (const entry of ledger.reviews) {
227
+ if (!entry || typeof entry !== "object" || Array.isArray(entry) || typeof entry.stale !== "boolean" || !entry.review) {
228
+ throw new PipelineError(
229
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
230
+ "Artifact review ledger entry is invalid."
231
+ );
232
+ }
233
+ validateArtifactReview(entry.review);
234
+ assertUniqueReviewItemIds(entry.review);
235
+ if (ids.has(entry.review.reviewId)) {
236
+ throw new PipelineError(
237
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
238
+ "Artifact review ledger IDs must be unique."
239
+ );
240
+ }
241
+ ids.add(entry.review.reviewId);
242
+ }
243
+ return ledger;
244
+ }
245
+ function createReviewLedger({ artifactId, currentReviewOf, reviews = [] } = {}) {
246
+ const ledger = {
247
+ schemaVersion: ARTIFACT_REVIEW_STATE_VERSION,
248
+ kind: ARTIFACT_REVIEW_STATE_KIND,
249
+ artifactId,
250
+ currentReviewOf,
251
+ reviews: reviews.map((entry) => ({ review: clone(entry.review), stale: Boolean(entry.stale) }))
252
+ };
253
+ ledger.reviews.sort((a, b) => compareStable(a.review, b.review, "reviewId"));
254
+ return validateReviewLedger(ledger);
255
+ }
256
+ function mergeReviewLedger(ledger, incoming, { stale = false } = {}) {
257
+ validateReviewLedger(ledger);
258
+ const reviews = Array.isArray(incoming) ? incoming : [incoming];
259
+ const byId = new Map(
260
+ ledger.reviews.map((entry) => [
261
+ entry.review.reviewId,
262
+ {
263
+ review: clone(entry.review),
264
+ stale: entry.stale
265
+ }
266
+ ])
267
+ );
268
+ for (const review of reviews) {
269
+ validateArtifactReview(review);
270
+ const previous = byId.get(review.reviewId);
271
+ if (previous) {
272
+ byId.set(review.reviewId, {
273
+ review: mergeArtifactReviews(previous.review, review),
274
+ stale: previous.stale || Boolean(stale)
275
+ });
276
+ } else {
277
+ byId.set(review.reviewId, { review: clone(review), stale: Boolean(stale) });
278
+ }
279
+ }
280
+ const merged = createReviewLedger({
281
+ artifactId: ledger.artifactId,
282
+ currentReviewOf: ledger.currentReviewOf,
283
+ reviews: [...byId.values()]
284
+ });
285
+ return same(ledger, merged) ? ledger : merged;
286
+ }
287
+ function effectiveReviewDecision(value) {
288
+ const entries = Array.isArray(value) ? value : value?.reviews ?? [];
289
+ const decisions = entries.map((entry) => entry.review?.decision ?? entry.decision);
290
+ if (decisions.includes("changes_requested")) return "changes_requested";
291
+ if (decisions.includes("pending")) return "pending";
292
+ return decisions.length > 0 && decisions.every((decision) => decision === "approved") ? "approved" : "pending";
293
+ }
294
+
295
+ // packages/artifact/lib/artifact/review.mjs
296
+ import { randomBytes, randomUUID } from "node:crypto";
29
297
  import {
30
- assertPlainData,
31
- canonicalizeJson,
32
- deepFreeze,
33
- sha256Hex
34
- } from "./design-shared-protocol-contracts-75a938cc.mjs";
298
+ existsSync,
299
+ lstatSync,
300
+ mkdirSync,
301
+ readFileSync,
302
+ renameSync,
303
+ rmSync,
304
+ statSync,
305
+ writeFileSync
306
+ } from "node:fs";
307
+ import { dirname } from "node:path";
308
+ var ARTIFACT_REVIEW_MAX_STATE_BYTES = 5 * 1024 * 1024;
309
+ var reviewPathQueues = /* @__PURE__ */ new Map();
310
+ function finalEntry(path, fs = { lstatSync }) {
311
+ try {
312
+ return fs.lstatSync(path);
313
+ } catch (error) {
314
+ if (error?.code === "ENOENT") return null;
315
+ throw error;
316
+ }
317
+ }
318
+ function clone2(value) {
319
+ return structuredClone(value);
320
+ }
321
+ function canonicalObject(value) {
322
+ if (Array.isArray(value)) return value.map(canonicalObject);
323
+ if (!value || typeof value !== "object") return value;
324
+ return Object.fromEntries(
325
+ Object.keys(value).sort().map((key) => [key, canonicalObject(value[key])])
326
+ );
327
+ }
328
+ function stableItemSort(a, b) {
329
+ return String(a.createdAt ?? a.updatedAt ?? "").localeCompare(
330
+ String(b.createdAt ?? b.updatedAt ?? "")
331
+ ) || String(a.id ?? a.reviewId).localeCompare(String(b.id ?? b.reviewId));
332
+ }
333
+ function normalizeArtifactReview(review) {
334
+ let normalized;
335
+ try {
336
+ normalized = clone2(review);
337
+ } catch {
338
+ throw new PipelineError(
339
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
340
+ "Artifact review is not cloneable."
341
+ );
342
+ }
343
+ try {
344
+ validateArtifactReview(normalized);
345
+ assertUniqueReviewItemIds(normalized);
346
+ } catch (error) {
347
+ if (error instanceof PipelineError) {
348
+ throw new PipelineError(
349
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
350
+ "Artifact review does not satisfy the Protocol v1.1 review contract.",
351
+ "",
352
+ { issues: error.details?.issues ?? [] }
353
+ );
354
+ }
355
+ throw error;
356
+ }
357
+ normalized.pins = normalized.pins.map((pin) => ({
358
+ ...pin,
359
+ replies: [...pin.replies].sort(stableItemSort)
360
+ })).sort(stableItemSort);
361
+ validateArtifactReview(normalized);
362
+ return normalized;
363
+ }
364
+ function serializeReviewState(value) {
365
+ const normalized = value?.kind === "artifact-review-state" ? validateReviewLedger(clone2(value)) : normalizeArtifactReview(value);
366
+ return `${JSON.stringify(canonicalObject(normalized), null, 2)}
367
+ `;
368
+ }
369
+ function readArtifactReviewState(path, { allowMissing = false } = {}) {
370
+ const entry = finalEntry(path);
371
+ if (!entry) {
372
+ if (allowMissing) return null;
373
+ throw new PipelineError(
374
+ ARTIFACT_ERROR_CODES.REVIEW_IMPORT,
375
+ "Artifact review state does not exist."
376
+ );
377
+ }
378
+ try {
379
+ if (entry.isSymbolicLink() || !entry.isFile()) {
380
+ throw new PipelineError(
381
+ ARTIFACT_ERROR_CODES.SYMLINK_ESCAPE,
382
+ "Artifact review state destination is not a regular file."
383
+ );
384
+ }
385
+ if (statSync(path).size > ARTIFACT_REVIEW_MAX_STATE_BYTES) {
386
+ throw new PipelineError(
387
+ ARTIFACT_ERROR_CODES.REQUEST_LIMIT,
388
+ `Artifact review state exceeds ${ARTIFACT_REVIEW_MAX_STATE_BYTES} bytes.`
389
+ );
390
+ }
391
+ return validateReviewLedger(JSON.parse(readFileSync(path, "utf8")));
392
+ } catch (error) {
393
+ if (error instanceof PipelineError) throw error;
394
+ throw new PipelineError(
395
+ ARTIFACT_ERROR_CODES.REVIEW_INVALID,
396
+ "Artifact review state is malformed."
397
+ );
398
+ }
399
+ }
400
+ function writeArtifactReviewState(path, ledger, { fileSystem = {}, suffix = `${process.pid}.${randomBytes(8).toString("hex")}` } = {}) {
401
+ validateReviewLedger(ledger);
402
+ const fs = { existsSync, lstatSync, mkdirSync, writeFileSync, renameSync, rmSync, ...fileSystem };
403
+ const temporary = `${path}.${suffix}.tmp`;
404
+ const serialized = serializeReviewState(ledger);
405
+ if (Buffer.byteLength(serialized, "utf8") > ARTIFACT_REVIEW_MAX_STATE_BYTES) {
406
+ throw new PipelineError(
407
+ ARTIFACT_ERROR_CODES.REQUEST_LIMIT,
408
+ `Artifact review state exceeds ${ARTIFACT_REVIEW_MAX_STATE_BYTES} bytes.`
409
+ );
410
+ }
411
+ try {
412
+ const initial = finalEntry(path, fs);
413
+ if (initial) {
414
+ const target = initial;
415
+ if (target.isSymbolicLink() || !target.isFile()) throw new Error("unsafe final target");
416
+ }
417
+ fs.mkdirSync(dirname(path), { recursive: true, mode: 448 });
418
+ fs.writeFileSync(temporary, serialized, { mode: 384, flag: "wx" });
419
+ const final = finalEntry(path, fs);
420
+ if (final) {
421
+ const target = final;
422
+ if (target.isSymbolicLink() || !target.isFile()) throw new Error("unsafe final target");
423
+ }
424
+ fs.renameSync(temporary, path);
425
+ } catch {
426
+ try {
427
+ fs.rmSync(temporary, { force: true });
428
+ } catch {
429
+ }
430
+ throw new PipelineError(
431
+ ARTIFACT_ERROR_CODES.REVIEW_WRITE,
432
+ "Artifact review state could not be written atomically.",
433
+ "Check destination permissions and retry; the previous review state was left unchanged."
434
+ );
435
+ }
436
+ return ledger;
437
+ }
438
+ function withArtifactReviewLock(path, action3) {
439
+ const previous = reviewPathQueues.get(path) ?? Promise.resolve();
440
+ const run = async () => {
441
+ let release;
442
+ try {
443
+ release = await acquireStartLock(`${path}.lock`, { timeout: 15e3, stale: 3e4 });
444
+ return await action3();
445
+ } catch (error) {
446
+ if (error instanceof PipelineError) throw error;
447
+ throw new PipelineError(
448
+ ARTIFACT_ERROR_CODES.REVIEW_WRITE,
449
+ "Artifact review state is busy or its cross-process lock is unavailable.",
450
+ "Wait for the active review write to finish, then retry."
451
+ );
452
+ } finally {
453
+ release?.();
454
+ }
455
+ };
456
+ const operation = previous.then(run, run);
457
+ const tail = operation.then(
458
+ () => void 0,
459
+ () => void 0
460
+ );
461
+ reviewPathQueues.set(path, tail);
462
+ tail.finally(() => {
463
+ if (reviewPathQueues.get(path) === tail) reviewPathQueues.delete(path);
464
+ });
465
+ return operation;
466
+ }
467
+ function normalizedExportInput(value) {
468
+ if (value?.kind === "artifact-review-state") return validateReviewLedger(clone2(value));
469
+ if (value?.review && value?.artifacts) return normalizeArtifactReview(value.review);
470
+ return normalizeArtifactReview(value);
471
+ }
472
+ function markdownText(value) {
473
+ return String(value ?? "").replace(/\r\n?/g, "\n").trim();
474
+ }
475
+ function renderPinMarkdown(pin, number) {
476
+ const region = `${pin.region.x}, ${pin.region.y}, ${pin.region.w}, ${pin.region.h}`;
477
+ const lines = [
478
+ `### ${number}. ${pin.intent.toUpperCase()} \xB7 ${pin.status}`,
479
+ "",
480
+ `- Pin: \`${pin.id}\``,
481
+ `- Artifact: \`${pin.artifactId}\`${pin.variant ? ` \xB7 variant \`${pin.variant}\`` : ""}`,
482
+ `- Author: ${pin.author.name}`,
483
+ `- Region: \`${region}\` at ${pin.viewport.width}\xD7${pin.viewport.height}`,
484
+ ...pin.anchor ? [
485
+ `- Anchor: \`${pin.anchor.planrId}\`${pin.anchor.screen ? ` \xB7 screen \`${pin.anchor.screen}\`` : ""}`
486
+ ] : [],
487
+ `- Updated: ${pin.updatedAt}`,
488
+ "",
489
+ markdownText(pin.comment)
490
+ ];
491
+ if (pin.replies.length > 0) {
492
+ lines.push("", "#### Thread", "");
493
+ for (const reply of pin.replies) {
494
+ lines.push(`- **${reply.author.name}** (${reply.createdAt}): ${markdownText(reply.comment)}`);
495
+ }
496
+ }
497
+ return lines.join("\n");
498
+ }
499
+ function reviewMarkdown(review, headingLevel = 2, stale = false) {
500
+ const mark = "#".repeat(headingLevel);
501
+ const lines = [
502
+ `${mark} Review ${review.reviewId}${stale ? " \xB7 STALE" : ""}`,
503
+ "",
504
+ `- Digest: \`${review.reviewOf}\``,
505
+ `- Decision: **${review.decision}**`,
506
+ `- Pins: ${review.pins.length}`,
507
+ ...review.createdAt ? [`- Created: ${review.createdAt}`] : [],
508
+ ...review.updatedAt ? [`- Updated: ${review.updatedAt}`] : [],
509
+ "",
510
+ `${mark}# Overall feedback`,
511
+ "",
512
+ markdownText(review.overall) || "_No overall feedback._"
513
+ ];
514
+ if (review.pins.length > 0) {
515
+ lines.push("", `${mark}# Pins`, "");
516
+ review.pins.forEach((pin, index) => lines.push(renderPinMarkdown(pin, index + 1), ""));
517
+ if (lines.at(-1) === "") lines.pop();
518
+ }
519
+ return lines.join("\n");
520
+ }
521
+ function exportArtifactReview(value, { format = "json" } = {}) {
522
+ let normalized;
523
+ try {
524
+ normalized = normalizedExportInput(value);
525
+ } catch (error) {
526
+ if (error instanceof PipelineError) throw error;
527
+ throw new PipelineError(
528
+ ARTIFACT_ERROR_CODES.REVIEW_EXPORT,
529
+ "Artifact review cannot be exported."
530
+ );
531
+ }
532
+ if (format === "json") return serializeReviewState(normalized);
533
+ if (format !== "markdown") {
534
+ throw new PipelineError(
535
+ ARTIFACT_ERROR_CODES.REVIEW_EXPORT,
536
+ "Artifact review export format must be json or markdown."
537
+ );
538
+ }
539
+ if (normalized.kind !== "artifact-review-state") {
540
+ return `# OpenPlanr Artifact Review
541
+
542
+ ${reviewMarkdown(normalized)}
543
+ `;
544
+ }
545
+ const lines = [
546
+ "# OpenPlanr Artifact Reviews",
547
+ "",
548
+ `- Artifact: \`${normalized.artifactId}\``,
549
+ `- Current digest: \`${normalized.currentReviewOf}\``,
550
+ `- Effective decision: **${effectiveReviewDecision(normalized)}**`,
551
+ `- Reviews: ${normalized.reviews.length}`
552
+ ];
553
+ for (const entry of normalized.reviews) {
554
+ lines.push("", reviewMarkdown(entry.review, 2, entry.stale));
555
+ }
556
+ return `${lines.join("\n")}
557
+ `;
558
+ }
559
+
560
+ // packages/artifact/lib/artifact/import.mjs
561
+ var ARTIFACT_ID_RE2 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
562
+ function pathError(code, message2) {
563
+ throw new PipelineError(
564
+ code,
565
+ message2,
566
+ "Choose a real, non-symlinked project or user review destination."
567
+ );
568
+ }
569
+ function pathEntry(path, fs = { lstatSync: lstatSync2 }) {
570
+ try {
571
+ return fs.lstatSync(path);
572
+ } catch (error) {
573
+ if (error?.code === "ENOENT") return null;
574
+ throw error;
575
+ }
576
+ }
577
+ function inside(base, candidate) {
578
+ const rel = relative(base, candidate);
579
+ return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
580
+ }
581
+ function parseablePlanrConfig(root) {
582
+ const path = join(root, PLANNING_FOLDER, "config.json");
583
+ if (!existsSync2(path)) return false;
584
+ try {
585
+ if (lstatSync2(path).isSymbolicLink()) return false;
586
+ const value = JSON.parse(readFileSync2(path, "utf8"));
587
+ return value && typeof value === "object" && !Array.isArray(value) && (typeof value.projectName === "string" && value.projectName.trim() !== "" || value.idPrefix && typeof value.idPrefix === "object" && !Array.isArray(value.idPrefix) && Object.keys(value.idPrefix).length > 0);
588
+ } catch {
589
+ return false;
590
+ }
591
+ }
592
+ function hasGitMarker(root) {
593
+ const marker = join(root, ".git");
594
+ if (!existsSync2(marker)) return false;
595
+ try {
596
+ const stat = lstatSync2(marker);
597
+ if (stat.isSymbolicLink()) return false;
598
+ if (stat.isDirectory()) {
599
+ const head = join(marker, "HEAD");
600
+ return existsSync2(head) && lstatSync2(head).isFile();
601
+ }
602
+ if (!stat.isFile() || stat.size > 4096) return false;
603
+ const match = /^gitdir:\s*(.+?)\s*$/u.exec(readFileSync2(marker, "utf8"));
604
+ if (!match) return false;
605
+ const gitDir = resolve(root, match[1]);
606
+ return existsSync2(gitDir) && statSync2(gitDir).isDirectory() && existsSync2(join(gitDir, "HEAD")) && lstatSync2(join(gitDir, "HEAD")).isFile();
607
+ } catch {
608
+ return false;
609
+ }
610
+ }
611
+ function findArtifactProjectRoot(start = process.cwd(), { env = process.env } = {}) {
612
+ let current;
613
+ try {
614
+ current = realpathSync(resolve(start));
615
+ } catch {
616
+ pathError(
617
+ ARTIFACT_ERROR_CODES.REVIEW_IMPORT,
618
+ "Artifact review working directory does not exist."
619
+ );
620
+ }
621
+ const homeCandidate = resolve(env.HOME ?? homedir());
622
+ let home = homeCandidate;
623
+ try {
624
+ home = realpathSync(homeCandidate);
625
+ } catch {
626
+ }
627
+ while (true) {
628
+ if (current !== home && (parseablePlanrConfig(current) || hasGitMarker(current)))
629
+ return current;
630
+ const parent = dirname2(current);
631
+ if (parent === current) return null;
632
+ current = parent;
633
+ }
634
+ }
635
+ function assertSafeDestination(base, relativeParts) {
636
+ const absoluteBase = resolve(base);
637
+ if (existsSync2(absoluteBase) && lstatSync2(absoluteBase).isSymbolicLink()) {
638
+ pathError(
639
+ ARTIFACT_ERROR_CODES.SYMLINK_ESCAPE,
640
+ "Artifact review destination base is a symlink."
641
+ );
642
+ }
643
+ let realBase = absoluteBase;
644
+ if (existsSync2(absoluteBase)) realBase = realpathSync(absoluteBase);
645
+ let current = absoluteBase;
646
+ for (const part of relativeParts) {
647
+ if (!part || part === "." || part === ".." || part.includes("/") || part.includes("\\") || part.includes("\0")) {
648
+ pathError(
649
+ ARTIFACT_ERROR_CODES.PATH_TRAVERSAL,
650
+ "Artifact review destination contains an unsafe segment."
651
+ );
652
+ }
653
+ current = join(current, part);
654
+ const entry = pathEntry(current);
655
+ if (!entry) continue;
656
+ if (entry.isSymbolicLink()) {
657
+ pathError(
658
+ ARTIFACT_ERROR_CODES.SYMLINK_ESCAPE,
659
+ "Artifact review destination contains a symlink."
660
+ );
661
+ }
662
+ if (!inside(realBase, realpathSync(current))) {
663
+ pathError(
664
+ ARTIFACT_ERROR_CODES.PATH_TRAVERSAL,
665
+ "Artifact review destination escapes its storage root."
666
+ );
667
+ }
668
+ }
669
+ if (!inside(absoluteBase, current)) {
670
+ pathError(
671
+ ARTIFACT_ERROR_CODES.PATH_TRAVERSAL,
672
+ "Artifact review destination escapes its storage root."
673
+ );
674
+ }
675
+ return current;
676
+ }
677
+ function resolveArtifactReviewDestination({
678
+ cwd = process.cwd(),
679
+ env = process.env,
680
+ artifactId,
681
+ designDir
682
+ } = {}) {
683
+ if (!ARTIFACT_ID_RE2.test(artifactId ?? "")) {
684
+ pathError(
685
+ ARTIFACT_ERROR_CODES.PATH_TRAVERSAL,
686
+ "Artifact review ID is unsafe for local storage."
687
+ );
688
+ }
689
+ if (designDir !== void 0) {
690
+ const lexical = resolve(designDir);
691
+ if (!existsSync2(lexical) || !statSync2(lexical).isDirectory()) {
692
+ pathError(ARTIFACT_ERROR_CODES.REVIEW_IMPORT, "Design review destination does not exist.");
693
+ }
694
+ if (lstatSync2(lexical).isSymbolicLink()) {
695
+ pathError(
696
+ ARTIFACT_ERROR_CODES.SYMLINK_ESCAPE,
697
+ "Design review destination must be a real directory."
698
+ );
699
+ }
700
+ const requested = realpathSync(lexical);
701
+ return Object.freeze({
702
+ kind: "design",
703
+ artifactId,
704
+ directory: requested,
705
+ path: join(requested, FEEDBACK_FILE),
706
+ reviewStatePath: join(requested, "artifact-review-state.json")
707
+ });
708
+ }
709
+ const projectRoot = findArtifactProjectRoot(cwd, { env });
710
+ if (projectRoot) {
711
+ const directory2 = assertSafeDestination(projectRoot, [
712
+ PLANNING_FOLDER,
713
+ "artifacts",
714
+ artifactId
715
+ ]);
716
+ return Object.freeze({
717
+ kind: "project",
718
+ artifactId,
719
+ root: projectRoot,
720
+ directory: directory2,
721
+ path: join(directory2, "review-state.json")
722
+ });
723
+ }
724
+ const root = resolve(planrHome(env));
725
+ const directory = assertSafeDestination(root, ["artifacts", artifactId]);
726
+ return Object.freeze({
727
+ kind: "user",
728
+ artifactId,
729
+ root,
730
+ directory,
731
+ path: join(directory, "review-state.json")
732
+ });
733
+ }
734
+ function reviewsFromDecoded(value) {
735
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
736
+ throw new PipelineError(
737
+ ARTIFACT_ERROR_CODES.REVIEW_IMPORT,
738
+ "Decoded review payload is not an object."
739
+ );
740
+ }
741
+ if (value.kind === "artifact-review-state") {
742
+ validateReviewLedger(value);
743
+ return value.reviews.map((entry) => ({ review: entry.review, stale: entry.stale }));
744
+ }
745
+ if (value.artifacts && value.viewer) {
746
+ validateArtifactEnvelope(value);
747
+ if (!value.review) {
748
+ throw new PipelineError(
749
+ ARTIFACT_ERROR_CODES.REVIEW_IMPORT,
750
+ "Decoded artifact envelope contains no review."
751
+ );
752
+ }
753
+ return [{ review: value.review, stale: false }];
754
+ }
755
+ if (value.review && !value.reviewId) return reviewsFromDecoded(value.review);
756
+ validateArtifactReview(value);
757
+ return [{ review: value, stale: false }];
758
+ }
759
+ async function decodeArtifactReviewSources(sources, { decodeSource, withMetadata = false } = {}) {
760
+ const list2 = Array.isArray(sources) ? sources : [sources];
761
+ if (list2.length === 0) {
762
+ throw new PipelineError(
763
+ ARTIFACT_ERROR_CODES.REVIEW_IMPORT,
764
+ "At least one artifact review source is required."
765
+ );
766
+ }
767
+ const entries = [];
768
+ for (let index = 0; index < list2.length; index += 1) {
769
+ const source = list2[index];
770
+ let decoded = source;
771
+ if (typeof source === "string") {
772
+ if (typeof decodeSource !== "function") {
773
+ throw new PipelineError(
774
+ ARTIFACT_ERROR_CODES.REVIEW_DECODER_REQUIRED,
775
+ "String and URL review sources require an injected async decoder.",
776
+ "Provide decodeSource(source, { index }); the review lifecycle has no transport dependency.",
777
+ { sourceIndex: index }
778
+ );
779
+ }
780
+ try {
781
+ decoded = await decodeSource(source, { index });
782
+ } catch {
783
+ throw new PipelineError(
784
+ ARTIFACT_ERROR_CODES.REVIEW_IMPORT,
785
+ "Artifact review source could not be decoded.",
786
+ "Verify the immutable review link and retry.",
787
+ { sourceIndex: index }
788
+ );
789
+ }
790
+ }
791
+ try {
792
+ entries.push(
793
+ ...reviewsFromDecoded(decoded).map((entry) => ({
794
+ review: structuredClone(entry.review),
795
+ stale: Boolean(entry.stale)
796
+ }))
797
+ );
798
+ } catch (error) {
799
+ if (error instanceof PipelineError && error.code === ARTIFACT_ERROR_CODES.REVIEW_IMPORT) {
800
+ error.details = { sourceIndex: index };
801
+ throw error;
802
+ }
803
+ throw new PipelineError(
804
+ ARTIFACT_ERROR_CODES.REVIEW_IMPORT,
805
+ "Decoded artifact review does not satisfy the Protocol v1.1 contract.",
806
+ "",
807
+ { sourceIndex: index }
808
+ );
809
+ }
810
+ }
811
+ return withMetadata ? entries : entries.map((entry) => entry.review);
812
+ }
35
813
 
36
814
  // packages/design/lib/design/feedback-reader.mjs
37
- import { join } from "node:path";
38
815
  var designReviewKey = (document) => `design-${hash(document.id).slice(0, 24)}`;
39
816
  function designReviewPath(file, env = process.env, options = {}) {
40
817
  const { root, document } = currentDesign(file, options);
@@ -69,18 +846,18 @@ function readDesignFeedback(file, env = process.env, options = {}) {
69
846
  revision: current.revision,
70
847
  reviewPath: designReviewPath(file, env, options),
71
848
  pins,
72
- state: readJson(join(current.root, ".design/studio-state.json"), {
849
+ state: readJson(join2(current.root, ".design/studio-state.json"), {
73
850
  state: {},
74
851
  stateVersion: 0
75
852
  }).state,
76
853
  ledger,
77
- shared: readJson(join(current.root, ".design/shared-feedback.json"), null)
854
+ shared: readJson(join2(current.root, ".design/shared-feedback.json"), null)
78
855
  };
79
856
  }
80
857
 
81
858
  // packages/design/lib/design/handoff-reader.mjs
82
- import { existsSync, readFileSync } from "node:fs";
83
- import { dirname, join as join2 } from "node:path";
859
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
860
+ import { dirname as dirname3, join as join3 } from "node:path";
84
861
 
85
862
  // packages/design/lib/design/handoff-format.mjs
86
863
  var safeMd = (text2) => String(text2).replaceAll("[", "\\[").replaceAll("]", "\\]").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
@@ -836,7 +1613,7 @@ var digestPattern2 = /^[a-f0-9]{64}$/u;
836
1613
  var revisionOf = (pin) => pin.revisionId ?? pin.reviewId;
837
1614
  var keyOf = (pin) => `${revisionOf(pin)}:${pin.id}`;
838
1615
  var compare = (left, right) => left.localeCompare(right, "en");
839
- var clone = (value) => {
1616
+ var clone3 = (value) => {
840
1617
  assertPlainData(value, "Review resolution data");
841
1618
  return JSON.parse(canonicalizeJson(value));
842
1619
  };
@@ -942,7 +1719,7 @@ function unknownMetadata(metadata2, known, diagnostics) {
942
1719
  }
943
1720
  }
944
1721
  function compileDesignHandoffResolution(input) {
945
- const source = clone(input ?? {});
1722
+ const source = clone3(input ?? {});
946
1723
  const pins = Array.isArray(source.pins) ? source.pins : [];
947
1724
  if (pins.length > MAX_COMMENTS)
948
1725
  throw new RangeError("Review resolution exceeds the comment limit.");
@@ -1017,9 +1794,9 @@ function compileDesignHandoffResolution(input) {
1017
1794
  anchor: pin.elementId ? { screenId: pin.screenId, elementId: pin.elementId } : pin.screenId ? { screenId: pin.screenId } : pin.anchor?.planrId ? { planrId: pin.anchor.planrId } : { artifactId: pin.artifactId },
1018
1795
  source: {
1019
1796
  text: pin.comment,
1020
- author: clone(pin.author),
1797
+ author: clone3(pin.author),
1021
1798
  status: pin.status,
1022
- ...resolved.disposition && typeof resolved.disposition === "object" ? { decision: clone(resolved.disposition) } : {}
1799
+ ...resolved.disposition && typeof resolved.disposition === "object" ? { decision: clone3(resolved.disposition) } : {}
1023
1800
  }
1024
1801
  };
1025
1802
  });
@@ -1089,7 +1866,7 @@ function canApproveDesignHandoffResolution(value) {
1089
1866
 
1090
1867
  // packages/design/lib/design/handoff-reader.mjs
1091
1868
  var sections = ["agreedChanges", "openQuestions", "deferred", "rejected"];
1092
- var metadataPath = (current) => join2(current.root, ".design/review-metadata.json");
1869
+ var metadataPath = (current) => join3(current.root, ".design/review-metadata.json");
1093
1870
  var revisionOf2 = (pin) => pin.revisionId ?? pin.reviewId;
1094
1871
  var pinKey = (pin) => `${revisionOf2(pin)}:${pin.id}`;
1095
1872
  function metadata(current, feedback) {
@@ -1218,12 +1995,12 @@ function readDesignExperience(file, { env = process.env } = {}) {
1218
1995
  }
1219
1996
  function readDesignHandoff(file, { env = process.env, ...shareOptions } = {}) {
1220
1997
  const value = snapshot(file, env, shareOptions);
1221
- const path = join2(dirname(designSpecPath(value.current.root)), "review-handoff.json");
1998
+ const path = join3(dirname3(designSpecPath(value.current.root)), "review-handoff.json");
1222
1999
  const draft = readJson(path, null);
1223
2000
  if (draft) {
1224
2001
  assertDraft(draft);
1225
2002
  const markdownPath = path.replace(/\.json$/u, ".md");
1226
- if (!existsSync(markdownPath) || readFileSync(markdownPath, "utf8") !== draft.markdown)
2003
+ if (!existsSync3(markdownPath) || readFileSync3(markdownPath, "utf8") !== draft.markdown)
1227
2004
  throw new Error(
1228
2005
  "The handoff Markdown differs from its approved JSON. Rebuild the handoff projection before using it in Plan."
1229
2006
  );
@@ -1242,7 +2019,7 @@ function readDesignHandoff(file, { env = process.env, ...shareOptions } = {}) {
1242
2019
  }
1243
2020
  function readDesignHandoffReadiness(file, { env = process.env, ...shareOptions } = {}) {
1244
2021
  const value = snapshot(file, env, shareOptions);
1245
- const path = join2(dirname(designSpecPath(value.current.root)), "review-handoff.json");
2022
+ const path = join3(dirname3(designSpecPath(value.current.root)), "review-handoff.json");
1246
2023
  const handoff = readJson(path, null);
1247
2024
  if (handoff) assertDraft(handoff);
1248
2025
  const outcomes = new Map(value.resolution.items.map((item) => [item.id, item]));
@@ -1259,13 +2036,13 @@ function readDesignHandoffReadiness(file, { env = process.env, ...shareOptions }
1259
2036
  };
1260
2037
  });
1261
2038
  const specificationPath = designSpecPath(value.current.root);
1262
- const specification = existsSync(specificationPath) ? {
2039
+ const specification = existsSync3(specificationPath) ? {
1263
2040
  path: "design-spec.md",
1264
2041
  revision: value.current.revision,
1265
- digest: `sha256:${hash(readFileSync(specificationPath))}`,
2042
+ digest: `sha256:${hash(readFileSync3(specificationPath))}`,
1266
2043
  complete: true
1267
2044
  } : void 0;
1268
- const studioState = readJson(join2(value.current.root, ".design/studio-state.json"), {
2045
+ const studioState = readJson(join3(value.current.root, ".design/studio-state.json"), {
1269
2046
  state: {}
1270
2047
  }).state;
1271
2048
  const readiness = compileDesignHandoffReadiness({
@@ -1311,9 +2088,9 @@ function assertDraft(draft) {
1311
2088
  }
1312
2089
 
1313
2090
  // packages/design/lib/design/handoff.mjs
1314
- import { existsSync as existsSync2, writeFileSync } from "node:fs";
1315
- import { dirname as dirname2, join as join3 } from "node:path";
1316
- var conflict = (message2) => Object.assign(new Error(message2), { statusCode: 409 });
2091
+ import { existsSync as existsSync4, writeFileSync as writeFileSync3 } from "node:fs";
2092
+ import { dirname as dirname4, join as join4 } from "node:path";
2093
+ var conflict2 = (message2) => Object.assign(new Error(message2), { statusCode: 409 });
1317
2094
  function sourceItem(pin, shareUrl) {
1318
2095
  const source = pin.revisionId ? `${shareUrl ?? ""}#revision=${encodeURIComponent(pin.revisionId)}&pin=${encodeURIComponent(pin.id)}` : `#review=${encodeURIComponent(pin.reviewId)}&pin=${encodeURIComponent(pin.id)}`;
1319
2096
  return {
@@ -1394,28 +2171,29 @@ async function preserveReviewErrors(path, action3) {
1394
2171
  if (failure) throw failure;
1395
2172
  return result;
1396
2173
  }
1397
- async function updateDesignHandoff(file, input, { env = process.env, fetchImpl = fetch, ...shareOptions } = {}) {
2174
+ async function updateDesignHandoff(file, input, { env = process.env, ...shareOptions } = {}) {
1398
2175
  if (!input || !["draft", "update", "approve", "category", "disposition"].includes(input.action))
1399
2176
  throw new Error("Unknown design handoff action.");
1400
2177
  const initial = currentDesign(file);
1401
- const unlockRender = await acquireStartLock(join3(initial.root, ".design/render.lock"));
2178
+ const unlockRender = await acquireStartLock(join4(initial.root, ".design/render.lock"));
1402
2179
  let outgoing;
1403
2180
  try {
1404
- const unlock = await acquireStartLock(join3(initial.root, ".design/handoff.lock"));
2181
+ const unlock = await acquireStartLock(join4(initial.root, ".design/handoff.lock"));
1405
2182
  try {
1406
2183
  await preserveReviewErrors(designReviewPath(file, env), async () => {
1407
2184
  const value = snapshot(file, env, shareOptions);
1408
2185
  if (input.revision !== value.current.revision)
1409
- throw conflict("The design changed. Refresh the review before updating its handoff.");
2186
+ throw conflict2("The design changed. Refresh the review before updating its handoff.");
1410
2187
  if (["category", "disposition"].includes(input.action)) {
1411
2188
  if (input.version !== value.metadata.version)
1412
- throw conflict("Review organization changed in another window. Reload before saving.");
2189
+ throw conflict2("Review organization changed in another window. Reload before saving.");
1413
2190
  const pin = findPin(value.feedback.pins, input.pinId, input.revisionId ?? input.reviewId);
1414
2191
  if (!pin) throw new Error("The comment is no longer available.");
1415
2192
  const choices = input.action === "category" ? ["question", "suggestion", "change-request", "blocker"] : ["accepted", "deferred", "rejected"];
1416
2193
  if (!choices.includes(input[input.action])) throw new Error(`Invalid ${input.action}.`);
1417
2194
  if (typeof (input.reason ?? "") !== "string" || (input.reason ?? "").length > 16384)
1418
2195
  throw new Error("Disposition reason is too long.");
2196
+ if (pin.revisionId) assertDesignShareAvailable({ env, ...shareOptions });
1419
2197
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1420
2198
  const local = normalizedLocalMetadata(
1421
2199
  readJson(metadataPath(value.current), { version: 0, byRevision: {} }),
@@ -1457,11 +2235,11 @@ async function updateDesignHandoff(file, input, { env = process.env, fetchImpl =
1457
2235
  };
1458
2236
  return;
1459
2237
  }
1460
- const path = join3(dirname2(designSpecPath(value.current.root)), "review-handoff.json");
2238
+ const path = join4(dirname4(designSpecPath(value.current.root)), "review-handoff.json");
1461
2239
  const previous = readJson(path, null);
1462
2240
  if (previous) assertDraft(previous);
1463
2241
  if (input.version !== (previous?.version ?? 0))
1464
- throw conflict("The handoff changed in another window. Reload before saving.");
2242
+ throw conflict2("The handoff changed in another window. Reload before saving.");
1465
2243
  let shareUrl;
1466
2244
  try {
1467
2245
  shareUrl = getDesignShareStatus(file, { env, ...shareOptions }).url;
@@ -1469,12 +2247,12 @@ async function updateDesignHandoff(file, input, { env = process.env, fetchImpl =
1469
2247
  }
1470
2248
  if (input.action === "approve") {
1471
2249
  if (!previous || input.contentHash !== previous.contentHash || reviewDigest(previous.basis) !== reviewDigest(value.basis))
1472
- throw conflict(
2250
+ throw conflict2(
1473
2251
  "The handoff is out of date. Rebuild and review the current draft before approving."
1474
2252
  );
1475
2253
  if (!canApproveDesignHandoffResolution(value.resolution)) {
1476
2254
  const diagnostic = value.resolution.diagnostics[0];
1477
- throw conflict(
2255
+ throw conflict2(
1478
2256
  diagnostic?.message ?? "Resolve the blocking review decisions before approving this handoff."
1479
2257
  );
1480
2258
  }
@@ -1488,19 +2266,19 @@ async function updateDesignHandoff(file, input, { env = process.env, fetchImpl =
1488
2266
  };
1489
2267
  approved.markdown = renderMarkdown(approved, value.current.document.title);
1490
2268
  assertReviewExperience(approved, DESIGN_HANDOFF_SCHEMA);
1491
- const archive = join3(
2269
+ const archive = join4(
1492
2270
  value.current.root,
1493
2271
  ".design/handoff-approvals",
1494
2272
  `${approved.contentHash}.json`
1495
2273
  );
1496
- if (!existsSync2(archive)) atomicJson(archive, approved);
2274
+ if (!existsSync4(archive)) atomicJson(archive, approved);
1497
2275
  atomicJson(path, approved);
1498
- writeFileSync(path.replace(/\.json$/u, ".md"), approved.markdown);
2276
+ writeFileSync3(path.replace(/\.json$/u, ".md"), approved.markdown);
1499
2277
  return;
1500
2278
  }
1501
2279
  const content = input.action === "draft" ? contentFromFeedback(value, shareUrl) : enrichContent(input.content, value, shareUrl);
1502
2280
  if (input.action === "update" && (!previous || reviewDigest(previous.basis) !== reviewDigest(value.basis)))
1503
- throw conflict("The review changed. Rebuild the draft before refining it.");
2281
+ throw conflict2("The review changed. Rebuild the draft before refining it.");
1504
2282
  const affectedScreens = [
1505
2283
  ...new Set(
1506
2284
  sections.flatMap((key) => content[key].map((item) => item.screenId).filter(Boolean))
@@ -1535,7 +2313,7 @@ async function updateDesignHandoff(file, input, { env = process.env, fetchImpl =
1535
2313
  draft.markdown = renderMarkdown(draft, value.current.document.title);
1536
2314
  assertReviewExperience(draft, DESIGN_HANDOFF_SCHEMA);
1537
2315
  atomicJson(path, draft);
1538
- writeFileSync(path.replace(/\.json$/u, ".md"), draft.markdown);
2316
+ writeFileSync3(path.replace(/\.json$/u, ".md"), draft.markdown);
1539
2317
  });
1540
2318
  } finally {
1541
2319
  unlock();
@@ -1549,11 +2327,14 @@ async function updateDesignHandoff(file, input, { env = process.env, fetchImpl =
1549
2327
  synchronization = await publishDesignReviewMetadata(file, outgoing.payload, {
1550
2328
  revisionId: outgoing.revisionId,
1551
2329
  env,
1552
- fetchImpl,
1553
2330
  ...shareOptions
1554
2331
  });
1555
2332
  } catch (error) {
1556
- synchronization = { pending: true, error: error.message };
2333
+ synchronization = {
2334
+ pending: false,
2335
+ error: error.message,
2336
+ ...error.code ? { code: error.code } : {}
2337
+ };
1557
2338
  }
1558
2339
  }
1559
2340
  return {
@@ -1563,6 +2344,19 @@ async function updateDesignHandoff(file, input, { env = process.env, fetchImpl =
1563
2344
  }
1564
2345
 
1565
2346
  export {
2347
+ PLANNING_FOLDER,
2348
+ CLI_COMMAND,
2349
+ createReviewLedger,
2350
+ mergeReviewLedger,
2351
+ effectiveReviewDecision,
2352
+ ARTIFACT_REVIEW_MAX_STATE_BYTES,
2353
+ normalizeArtifactReview,
2354
+ readArtifactReviewState,
2355
+ writeArtifactReviewState,
2356
+ withArtifactReviewLock,
2357
+ exportArtifactReview,
2358
+ resolveArtifactReviewDestination,
2359
+ decodeArtifactReviewSources,
1566
2360
  designReviewKey,
1567
2361
  designReviewPath,
1568
2362
  readDesignFeedback,