openplanr 1.25.3 → 2.0.1

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 (1738) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/CONTRIBUTING.md +33 -0
  3. package/README.md +154 -131
  4. package/dist/cli/commands/artifact.d.ts.map +1 -1
  5. package/dist/cli/commands/artifact.js +214 -30
  6. package/dist/cli/commands/artifact.js.map +1 -1
  7. package/dist/cli/commands/backlog.d.ts +1 -21
  8. package/dist/cli/commands/backlog.d.ts.map +1 -1
  9. package/dist/cli/commands/backlog.js +1 -428
  10. package/dist/cli/commands/backlog.js.map +1 -1
  11. package/dist/cli/commands/company.d.ts +3 -0
  12. package/dist/cli/commands/company.d.ts.map +1 -0
  13. package/dist/cli/commands/company.js +173 -0
  14. package/dist/cli/commands/company.js.map +1 -0
  15. package/dist/cli/commands/config-deterministic.d.ts +3 -0
  16. package/dist/cli/commands/config-deterministic.d.ts.map +1 -0
  17. package/dist/cli/commands/config-deterministic.js +88 -0
  18. package/dist/cli/commands/config-deterministic.js.map +1 -0
  19. package/dist/cli/commands/dashboard.d.ts +3 -0
  20. package/dist/cli/commands/dashboard.d.ts.map +1 -0
  21. package/dist/cli/commands/dashboard.js +36 -0
  22. package/dist/cli/commands/dashboard.js.map +1 -0
  23. package/dist/cli/commands/diagram/index.d.ts +3 -0
  24. package/dist/cli/commands/diagram/index.d.ts.map +1 -0
  25. package/dist/cli/commands/diagram/index.js +73 -0
  26. package/dist/cli/commands/diagram/index.js.map +1 -0
  27. package/dist/cli/commands/diagram/presentation.d.ts +4 -0
  28. package/dist/cli/commands/diagram/presentation.d.ts.map +1 -0
  29. package/dist/cli/commands/diagram/presentation.js +38 -0
  30. package/dist/cli/commands/diagram/presentation.js.map +1 -0
  31. package/dist/cli/commands/doctor.d.ts.map +1 -1
  32. package/dist/cli/commands/doctor.js +1 -11
  33. package/dist/cli/commands/doctor.js.map +1 -1
  34. package/dist/cli/commands/epic.d.ts +1 -9
  35. package/dist/cli/commands/epic.d.ts.map +1 -1
  36. package/dist/cli/commands/epic.js +1 -259
  37. package/dist/cli/commands/epic.js.map +1 -1
  38. package/dist/cli/commands/feature.d.ts +1 -8
  39. package/dist/cli/commands/feature.d.ts.map +1 -1
  40. package/dist/cli/commands/feature.js +1 -220
  41. package/dist/cli/commands/feature.js.map +1 -1
  42. package/dist/cli/commands/groups/delivery.d.ts +3 -0
  43. package/dist/cli/commands/groups/delivery.d.ts.map +1 -0
  44. package/dist/cli/commands/groups/delivery.js +13 -0
  45. package/dist/cli/commands/groups/delivery.js.map +1 -0
  46. package/dist/cli/commands/groups/foundation.d.ts +3 -0
  47. package/dist/cli/commands/groups/foundation.d.ts.map +1 -0
  48. package/dist/cli/commands/groups/foundation.js +11 -0
  49. package/dist/cli/commands/groups/foundation.js.map +1 -0
  50. package/dist/cli/commands/groups/intelligence.d.ts +3 -0
  51. package/dist/cli/commands/groups/intelligence.d.ts.map +1 -0
  52. package/dist/cli/commands/groups/intelligence.js +19 -0
  53. package/dist/cli/commands/groups/intelligence.js.map +1 -0
  54. package/dist/cli/commands/groups/operations.d.ts +3 -0
  55. package/dist/cli/commands/groups/operations.d.ts.map +1 -0
  56. package/dist/cli/commands/groups/operations.js +17 -0
  57. package/dist/cli/commands/groups/operations.js.map +1 -0
  58. package/dist/cli/commands/groups/planning.d.ts +3 -0
  59. package/dist/cli/commands/groups/planning.d.ts.map +1 -0
  60. package/dist/cli/commands/groups/planning.js +25 -0
  61. package/dist/cli/commands/groups/planning.js.map +1 -0
  62. package/dist/cli/commands/index.d.ts +4 -0
  63. package/dist/cli/commands/index.d.ts.map +1 -0
  64. package/dist/cli/commands/index.js +14 -0
  65. package/dist/cli/commands/index.js.map +1 -0
  66. package/dist/cli/commands/init-deterministic.d.ts +3 -0
  67. package/dist/cli/commands/init-deterministic.d.ts.map +1 -0
  68. package/dist/cli/commands/init-deterministic.js +40 -0
  69. package/dist/cli/commands/init-deterministic.js.map +1 -0
  70. package/dist/cli/commands/land.d.ts +15 -0
  71. package/dist/cli/commands/land.d.ts.map +1 -0
  72. package/dist/cli/commands/land.js +176 -0
  73. package/dist/cli/commands/land.js.map +1 -0
  74. package/dist/cli/commands/operate/input.d.ts +54 -0
  75. package/dist/cli/commands/operate/input.d.ts.map +1 -0
  76. package/dist/cli/commands/operate/input.js +98 -0
  77. package/dist/cli/commands/operate/input.js.map +1 -0
  78. package/dist/cli/commands/operate/registrars/assignments.d.ts +5 -0
  79. package/dist/cli/commands/operate/registrars/assignments.d.ts.map +1 -0
  80. package/dist/cli/commands/operate/registrars/assignments.js +167 -0
  81. package/dist/cli/commands/operate/registrars/assignments.js.map +1 -0
  82. package/dist/cli/commands/operate/registrars/catalog.d.ts +4 -0
  83. package/dist/cli/commands/operate/registrars/catalog.d.ts.map +1 -0
  84. package/dist/cli/commands/operate/registrars/catalog.js +12 -0
  85. package/dist/cli/commands/operate/registrars/catalog.js.map +1 -0
  86. package/dist/cli/commands/operate/registrars/contracts.d.ts +41 -0
  87. package/dist/cli/commands/operate/registrars/contracts.d.ts.map +1 -0
  88. package/dist/cli/commands/operate/registrars/contracts.js +2 -0
  89. package/dist/cli/commands/operate/registrars/contracts.js.map +1 -0
  90. package/dist/cli/commands/operate/registrars/dashboard.d.ts +4 -0
  91. package/dist/cli/commands/operate/registrars/dashboard.d.ts.map +1 -0
  92. package/dist/cli/commands/operate/registrars/dashboard.js +26 -0
  93. package/dist/cli/commands/operate/registrars/dashboard.js.map +1 -0
  94. package/dist/cli/commands/operate/registrars/dispatch.d.ts +7 -0
  95. package/dist/cli/commands/operate/registrars/dispatch.d.ts.map +1 -0
  96. package/dist/cli/commands/operate/registrars/dispatch.js +55 -0
  97. package/dist/cli/commands/operate/registrars/dispatch.js.map +1 -0
  98. package/dist/cli/commands/operate/registrars/experience.d.ts +4 -0
  99. package/dist/cli/commands/operate/registrars/experience.d.ts.map +1 -0
  100. package/dist/cli/commands/operate/registrars/experience.js +93 -0
  101. package/dist/cli/commands/operate/registrars/experience.js.map +1 -0
  102. package/dist/cli/commands/operate/registrars/index.d.ts +5 -0
  103. package/dist/cli/commands/operate/registrars/index.d.ts.map +1 -0
  104. package/dist/cli/commands/operate/registrars/index.js +28 -0
  105. package/dist/cli/commands/operate/registrars/index.js.map +1 -0
  106. package/dist/cli/commands/operate/registrars/lifecycle.d.ts +4 -0
  107. package/dist/cli/commands/operate/registrars/lifecycle.d.ts.map +1 -0
  108. package/dist/cli/commands/operate/registrars/lifecycle.js +46 -0
  109. package/dist/cli/commands/operate/registrars/lifecycle.js.map +1 -0
  110. package/dist/cli/commands/operate/registrars/measurement.d.ts +4 -0
  111. package/dist/cli/commands/operate/registrars/measurement.d.ts.map +1 -0
  112. package/dist/cli/commands/operate/registrars/measurement.js +122 -0
  113. package/dist/cli/commands/operate/registrars/measurement.js.map +1 -0
  114. package/dist/cli/commands/operate/registrars/note-validation.d.ts +6 -0
  115. package/dist/cli/commands/operate/registrars/note-validation.d.ts.map +1 -0
  116. package/dist/cli/commands/operate/registrars/note-validation.js +103 -0
  117. package/dist/cli/commands/operate/registrars/note-validation.js.map +1 -0
  118. package/dist/cli/commands/operate/registrars/planning.d.ts +4 -0
  119. package/dist/cli/commands/operate/registrars/planning.d.ts.map +1 -0
  120. package/dist/cli/commands/operate/registrars/planning.js +41 -0
  121. package/dist/cli/commands/operate/registrars/planning.js.map +1 -0
  122. package/dist/cli/commands/operate/registrars/recovery.d.ts +4 -0
  123. package/dist/cli/commands/operate/registrars/recovery.d.ts.map +1 -0
  124. package/dist/cli/commands/operate/registrars/recovery.js +65 -0
  125. package/dist/cli/commands/operate/registrars/recovery.js.map +1 -0
  126. package/dist/cli/commands/operate/registrars/reviews.d.ts +4 -0
  127. package/dist/cli/commands/operate/registrars/reviews.d.ts.map +1 -0
  128. package/dist/cli/commands/operate/registrars/reviews.js +83 -0
  129. package/dist/cli/commands/operate/registrars/reviews.js.map +1 -0
  130. package/dist/cli/commands/operate/registration.d.ts +4 -0
  131. package/dist/cli/commands/operate/registration.d.ts.map +1 -0
  132. package/dist/cli/commands/operate/registration.js +3 -0
  133. package/dist/cli/commands/operate/registration.js.map +1 -0
  134. package/dist/cli/commands/operate/render.d.ts +19 -0
  135. package/dist/cli/commands/operate/render.d.ts.map +1 -0
  136. package/dist/cli/commands/operate/render.js +201 -0
  137. package/dist/cli/commands/operate/render.js.map +1 -0
  138. package/dist/cli/commands/operate.d.ts +58 -13
  139. package/dist/cli/commands/operate.d.ts.map +1 -1
  140. package/dist/cli/commands/operate.js +169 -984
  141. package/dist/cli/commands/operate.js.map +1 -1
  142. package/dist/cli/commands/planning-artifacts.d.ts +10 -0
  143. package/dist/cli/commands/planning-artifacts.d.ts.map +1 -0
  144. package/dist/cli/commands/planning-artifacts.js +350 -0
  145. package/dist/cli/commands/planning-artifacts.js.map +1 -0
  146. package/dist/cli/commands/quick/interaction.d.ts +8 -0
  147. package/dist/cli/commands/quick/interaction.d.ts.map +1 -0
  148. package/dist/cli/commands/quick/interaction.js +8 -0
  149. package/dist/cli/commands/quick/interaction.js.map +1 -0
  150. package/dist/cli/commands/quick/project.d.ts +8 -0
  151. package/dist/cli/commands/quick/project.d.ts.map +1 -0
  152. package/dist/cli/commands/quick/project.js +8 -0
  153. package/dist/cli/commands/quick/project.js.map +1 -0
  154. package/dist/cli/commands/quick.d.ts +1 -29
  155. package/dist/cli/commands/quick.d.ts.map +1 -1
  156. package/dist/cli/commands/quick.js +1 -337
  157. package/dist/cli/commands/quick.js.map +1 -1
  158. package/dist/cli/commands/rules.js +1 -1
  159. package/dist/cli/commands/rules.js.map +1 -1
  160. package/dist/cli/commands/setup.d.ts.map +1 -1
  161. package/dist/cli/commands/setup.js +40 -18
  162. package/dist/cli/commands/setup.js.map +1 -1
  163. package/dist/cli/commands/spec.d.ts +6 -4
  164. package/dist/cli/commands/spec.d.ts.map +1 -1
  165. package/dist/cli/commands/spec.js +166 -174
  166. package/dist/cli/commands/spec.js.map +1 -1
  167. package/dist/cli/commands/sprint.d.ts +1 -8
  168. package/dist/cli/commands/sprint.d.ts.map +1 -1
  169. package/dist/cli/commands/sprint.js +1 -522
  170. package/dist/cli/commands/sprint.js.map +1 -1
  171. package/dist/cli/commands/story/interaction.d.ts +7 -0
  172. package/dist/cli/commands/story/interaction.d.ts.map +1 -0
  173. package/dist/cli/commands/story/interaction.js +7 -0
  174. package/dist/cli/commands/story/interaction.js.map +1 -0
  175. package/dist/cli/commands/story/project.d.ts +10 -0
  176. package/dist/cli/commands/story/project.d.ts.map +1 -0
  177. package/dist/cli/commands/story/project.js +10 -0
  178. package/dist/cli/commands/story/project.js.map +1 -0
  179. package/dist/cli/commands/story.d.ts +1 -8
  180. package/dist/cli/commands/story.d.ts.map +1 -1
  181. package/dist/cli/commands/story.js +1 -358
  182. package/dist/cli/commands/story.js.map +1 -1
  183. package/dist/cli/commands/task.d.ts +1 -9
  184. package/dist/cli/commands/task.d.ts.map +1 -1
  185. package/dist/cli/commands/task.js +1 -351
  186. package/dist/cli/commands/task.js.map +1 -1
  187. package/dist/cli/error-boundary.d.ts +29 -0
  188. package/dist/cli/error-boundary.d.ts.map +1 -0
  189. package/dist/cli/error-boundary.js +103 -0
  190. package/dist/cli/error-boundary.js.map +1 -0
  191. package/dist/cli/helpers/bulk-checkbox-update.d.ts +1 -1
  192. package/dist/cli/helpers/bulk-checkbox-update.js +1 -1
  193. package/dist/cli/index.js +38 -113
  194. package/dist/cli/index.js.map +1 -1
  195. package/dist/dashboard/.vite/manifest.json +68 -0
  196. package/dist/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  197. package/dist/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  198. package/dist/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  199. package/dist/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  200. package/dist/dashboard/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  201. package/dist/dashboard/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  202. package/dist/dashboard/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  203. package/dist/dashboard/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  204. package/dist/dashboard/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  205. package/dist/dashboard/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  206. package/dist/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  207. package/dist/dashboard/assets/index-Bk8DyO_2.css +1 -0
  208. package/dist/dashboard/assets/index-zeygL5iu.js +557 -0
  209. package/dist/dashboard/assets/index-zeygL5iu.js.map +1 -0
  210. package/dist/dashboard/dashboard-manifest.json +84 -0
  211. package/dist/dashboard/index.html +13 -0
  212. package/dist/generators/base-generator.d.ts +2 -0
  213. package/dist/generators/base-generator.d.ts.map +1 -1
  214. package/dist/generators/base-generator.js +8 -0
  215. package/dist/generators/base-generator.js.map +1 -1
  216. package/dist/generators/claude-generator.d.ts.map +1 -1
  217. package/dist/generators/claude-generator.js +12 -14
  218. package/dist/generators/claude-generator.js.map +1 -1
  219. package/dist/generators/codex-generator.d.ts.map +1 -1
  220. package/dist/generators/codex-generator.js +7 -7
  221. package/dist/generators/codex-generator.js.map +1 -1
  222. package/dist/generators/cursor-generator.d.ts.map +1 -1
  223. package/dist/generators/cursor-generator.js +11 -30
  224. package/dist/generators/cursor-generator.js.map +1 -1
  225. package/dist/models/schema.d.ts +0 -23
  226. package/dist/models/schema.d.ts.map +1 -1
  227. package/dist/models/schema.js +0 -7
  228. package/dist/models/schema.js.map +1 -1
  229. package/dist/models/types.d.ts +3 -14
  230. package/dist/models/types.d.ts.map +1 -1
  231. package/dist/services/artifact-pipeline-service.d.ts +99 -1
  232. package/dist/services/artifact-pipeline-service.d.ts.map +1 -1
  233. package/dist/services/artifact-pipeline-service.js +681 -4
  234. package/dist/services/artifact-pipeline-service.js.map +1 -1
  235. package/dist/services/canonical-json.d.ts +3 -0
  236. package/dist/services/canonical-json.d.ts.map +1 -0
  237. package/dist/services/canonical-json.js +71 -0
  238. package/dist/services/canonical-json.js.map +1 -0
  239. package/dist/services/claude-plugin-service.d.ts +6 -1
  240. package/dist/services/claude-plugin-service.d.ts.map +1 -1
  241. package/dist/services/claude-plugin-service.js +184 -12
  242. package/dist/services/claude-plugin-service.js.map +1 -1
  243. package/dist/services/codex-plugin-service.d.ts +30 -0
  244. package/dist/services/codex-plugin-service.d.ts.map +1 -0
  245. package/dist/services/codex-plugin-service.js +195 -0
  246. package/dist/services/codex-plugin-service.js.map +1 -0
  247. package/dist/services/company-auth-service.d.ts +70 -0
  248. package/dist/services/company-auth-service.d.ts.map +1 -0
  249. package/dist/services/company-auth-service.js +720 -0
  250. package/dist/services/company-auth-service.js.map +1 -0
  251. package/dist/services/company-auth-store.d.ts +22 -0
  252. package/dist/services/company-auth-store.d.ts.map +1 -0
  253. package/dist/services/company-auth-store.js +158 -0
  254. package/dist/services/company-auth-store.js.map +1 -0
  255. package/dist/services/company-common.d.ts +9 -0
  256. package/dist/services/company-common.d.ts.map +1 -0
  257. package/dist/services/company-common.js +35 -0
  258. package/dist/services/company-common.js.map +1 -0
  259. package/dist/services/company-sync-service.d.ts +214 -0
  260. package/dist/services/company-sync-service.d.ts.map +1 -0
  261. package/dist/services/company-sync-service.js +1299 -0
  262. package/dist/services/company-sync-service.js.map +1 -0
  263. package/dist/services/connectors/adapters/business-metrics.d.ts +5 -0
  264. package/dist/services/connectors/adapters/business-metrics.d.ts.map +1 -0
  265. package/dist/services/connectors/adapters/business-metrics.js +41 -0
  266. package/dist/services/connectors/adapters/business-metrics.js.map +1 -0
  267. package/dist/services/connectors/adapters/deployment-health.d.ts +18 -0
  268. package/dist/services/connectors/adapters/deployment-health.d.ts.map +1 -0
  269. package/dist/services/connectors/adapters/deployment-health.js +67 -0
  270. package/dist/services/connectors/adapters/deployment-health.js.map +1 -0
  271. package/dist/services/connectors/adapters/github.d.ts +5 -0
  272. package/dist/services/connectors/adapters/github.d.ts.map +1 -0
  273. package/dist/services/connectors/adapters/github.js +31 -0
  274. package/dist/services/connectors/adapters/github.js.map +1 -0
  275. package/dist/services/connectors/adapters/linear-jira.d.ts +5 -0
  276. package/dist/services/connectors/adapters/linear-jira.d.ts.map +1 -0
  277. package/dist/services/connectors/adapters/linear-jira.js +26 -0
  278. package/dist/services/connectors/adapters/linear-jira.js.map +1 -0
  279. package/dist/services/connectors/adapters/posthog.d.ts +5 -0
  280. package/dist/services/connectors/adapters/posthog.d.ts.map +1 -0
  281. package/dist/services/connectors/adapters/posthog.js +31 -0
  282. package/dist/services/connectors/adapters/posthog.js.map +1 -0
  283. package/dist/services/connectors/adapters/sentry.d.ts +5 -0
  284. package/dist/services/connectors/adapters/sentry.d.ts.map +1 -0
  285. package/dist/services/connectors/adapters/sentry.js +31 -0
  286. package/dist/services/connectors/adapters/sentry.js.map +1 -0
  287. package/dist/services/connectors/checkpoint-custody.d.ts +45 -0
  288. package/dist/services/connectors/checkpoint-custody.d.ts.map +1 -0
  289. package/dist/services/connectors/checkpoint-custody.js +496 -0
  290. package/dist/services/connectors/checkpoint-custody.js.map +1 -0
  291. package/dist/services/connectors/connector-registry.d.ts +144 -0
  292. package/dist/services/connectors/connector-registry.d.ts.map +1 -0
  293. package/dist/services/connectors/connector-registry.js +423 -0
  294. package/dist/services/connectors/connector-registry.js.map +1 -0
  295. package/dist/services/connectors/connector-runtime.d.ts +200 -0
  296. package/dist/services/connectors/connector-runtime.d.ts.map +1 -0
  297. package/dist/services/connectors/connector-runtime.js +1297 -0
  298. package/dist/services/connectors/connector-runtime.js.map +1 -0
  299. package/dist/services/connectors/credential-custody.d.ts +96 -0
  300. package/dist/services/connectors/credential-custody.d.ts.map +1 -0
  301. package/dist/services/connectors/credential-custody.js +390 -0
  302. package/dist/services/connectors/credential-custody.js.map +1 -0
  303. package/dist/services/credential-backends.d.ts +11 -1
  304. package/dist/services/credential-backends.d.ts.map +1 -1
  305. package/dist/services/credential-backends.js +104 -21
  306. package/dist/services/credential-backends.js.map +1 -1
  307. package/dist/services/credential-write-lock.d.ts +8 -0
  308. package/dist/services/credential-write-lock.d.ts.map +1 -0
  309. package/dist/services/credential-write-lock.js +104 -0
  310. package/dist/services/credential-write-lock.js.map +1 -0
  311. package/dist/services/credentials-service.d.ts +8 -2
  312. package/dist/services/credentials-service.d.ts.map +1 -1
  313. package/dist/services/credentials-service.js +66 -21
  314. package/dist/services/credentials-service.js.map +1 -1
  315. package/dist/services/deprecation-notices.d.ts +2 -2
  316. package/dist/services/deprecation-notices.d.ts.map +1 -1
  317. package/dist/services/deprecation-notices.js +2 -2
  318. package/dist/services/deprecation-notices.js.map +1 -1
  319. package/dist/services/design-artifact-service.d.ts +37 -0
  320. package/dist/services/design-artifact-service.d.ts.map +1 -0
  321. package/dist/services/design-artifact-service.js +94 -0
  322. package/dist/services/design-artifact-service.js.map +1 -0
  323. package/dist/services/diagram-artifact-service.d.ts +12 -0
  324. package/dist/services/diagram-artifact-service.d.ts.map +1 -0
  325. package/dist/services/diagram-artifact-service.js +41 -0
  326. package/dist/services/diagram-artifact-service.js.map +1 -0
  327. package/dist/services/diagram-pipeline-service.d.ts +125 -0
  328. package/dist/services/diagram-pipeline-service.d.ts.map +1 -0
  329. package/dist/services/diagram-pipeline-service.js +329 -0
  330. package/dist/services/diagram-pipeline-service.js.map +1 -0
  331. package/dist/services/gherkin-service.d.ts +3 -0
  332. package/dist/services/gherkin-service.d.ts.map +1 -0
  333. package/dist/services/gherkin-service.js +9 -0
  334. package/dist/services/gherkin-service.js.map +1 -0
  335. package/dist/services/graph-service.d.ts.map +1 -1
  336. package/dist/services/graph-service.js +6 -4
  337. package/dist/services/graph-service.js.map +1 -1
  338. package/dist/services/landing/landing-service.d.ts +42 -0
  339. package/dist/services/landing/landing-service.d.ts.map +1 -0
  340. package/dist/services/landing/landing-service.js +197 -0
  341. package/dist/services/landing/landing-service.js.map +1 -0
  342. package/dist/services/landing/operation-registry.d.ts +56 -0
  343. package/dist/services/landing/operation-registry.d.ts.map +1 -0
  344. package/dist/services/landing/operation-registry.js +165 -0
  345. package/dist/services/landing/operation-registry.js.map +1 -0
  346. package/dist/services/landing/receipt-custody.d.ts +48 -0
  347. package/dist/services/landing/receipt-custody.d.ts.map +1 -0
  348. package/dist/services/landing/receipt-custody.js +375 -0
  349. package/dist/services/landing/receipt-custody.js.map +1 -0
  350. package/dist/services/linear/constants.d.ts.map +1 -1
  351. package/dist/services/linear/constants.js +2 -6
  352. package/dist/services/linear/constants.js.map +1 -1
  353. package/dist/services/linear/task-status-aggregation.d.ts +1 -1
  354. package/dist/services/linear/task-status-aggregation.js +1 -1
  355. package/dist/services/linear-pull-service.d.ts.map +1 -1
  356. package/dist/services/linear-pull-service.js +7 -30
  357. package/dist/services/linear-pull-service.js.map +1 -1
  358. package/dist/services/linear-push-service.d.ts.map +1 -1
  359. package/dist/services/linear-push-service.js +4 -5
  360. package/dist/services/linear-push-service.js.map +1 -1
  361. package/dist/services/migration-registry.d.ts +0 -19
  362. package/dist/services/migration-registry.d.ts.map +1 -1
  363. package/dist/services/migration-registry.js +18 -32
  364. package/dist/services/migration-registry.js.map +1 -1
  365. package/dist/services/operate/assignment-lifecycle-service.d.ts +135 -0
  366. package/dist/services/operate/assignment-lifecycle-service.d.ts.map +1 -0
  367. package/dist/services/operate/assignment-lifecycle-service.js +113 -0
  368. package/dist/services/operate/assignment-lifecycle-service.js.map +1 -0
  369. package/dist/services/operate/assignment-packet-service.d.ts +79 -0
  370. package/dist/services/operate/assignment-packet-service.d.ts.map +1 -0
  371. package/dist/services/operate/assignment-packet-service.js +1030 -0
  372. package/dist/services/operate/assignment-packet-service.js.map +1 -0
  373. package/dist/services/operate/client/governance.d.ts +4 -0
  374. package/dist/services/operate/client/governance.d.ts.map +1 -0
  375. package/dist/services/operate/client/governance.js +3 -0
  376. package/dist/services/operate/client/governance.js.map +1 -0
  377. package/dist/services/operate/client/lifecycle.d.ts +18 -0
  378. package/dist/services/operate/client/lifecycle.d.ts.map +1 -0
  379. package/dist/services/operate/client/lifecycle.js +15 -0
  380. package/dist/services/operate/client/lifecycle.js.map +1 -0
  381. package/dist/services/operate/client/runtime.d.ts +13 -0
  382. package/dist/services/operate/client/runtime.d.ts.map +1 -0
  383. package/dist/services/operate/client/runtime.js +11 -0
  384. package/dist/services/operate/client/runtime.js.map +1 -0
  385. package/dist/services/operate/client-error.d.ts +9 -0
  386. package/dist/services/operate/client-error.d.ts.map +1 -0
  387. package/dist/services/operate/client-error.js +14 -0
  388. package/dist/services/operate/client-error.js.map +1 -0
  389. package/dist/services/operate/client.d.ts +415 -0
  390. package/dist/services/operate/client.d.ts.map +1 -0
  391. package/dist/services/operate/client.js +2432 -0
  392. package/dist/services/operate/client.js.map +1 -0
  393. package/dist/services/operate/command-gateway.d.ts +152 -0
  394. package/dist/services/operate/command-gateway.d.ts.map +1 -0
  395. package/dist/services/operate/command-gateway.js +883 -0
  396. package/dist/services/operate/command-gateway.js.map +1 -0
  397. package/dist/services/operate/composition.d.ts +421 -0
  398. package/dist/services/operate/composition.d.ts.map +1 -0
  399. package/dist/services/operate/composition.js +394 -0
  400. package/dist/services/operate/composition.js.map +1 -0
  401. package/dist/services/operate/cycle-lifecycle-service.d.ts +35 -0
  402. package/dist/services/operate/cycle-lifecycle-service.d.ts.map +1 -0
  403. package/dist/services/operate/cycle-lifecycle-service.js +427 -0
  404. package/dist/services/operate/cycle-lifecycle-service.js.map +1 -0
  405. package/dist/services/operate/delivery-evidence.d.ts +34 -0
  406. package/dist/services/operate/delivery-evidence.d.ts.map +1 -0
  407. package/dist/services/operate/delivery-evidence.js +666 -0
  408. package/dist/services/operate/delivery-evidence.js.map +1 -0
  409. package/dist/services/operate/domain-catalog-service.d.ts +24 -0
  410. package/dist/services/operate/domain-catalog-service.d.ts.map +1 -0
  411. package/dist/services/operate/domain-catalog-service.js +99 -0
  412. package/dist/services/operate/domain-catalog-service.js.map +1 -0
  413. package/dist/services/operate/experience-read-service.d.ts +64 -0
  414. package/dist/services/operate/experience-read-service.d.ts.map +1 -0
  415. package/dist/services/operate/experience-read-service.js +109 -0
  416. package/dist/services/operate/experience-read-service.js.map +1 -0
  417. package/dist/services/operate/governed-action-service.d.ts +80 -0
  418. package/dist/services/operate/governed-action-service.d.ts.map +1 -0
  419. package/dist/services/operate/governed-action-service.js +497 -0
  420. package/dist/services/operate/governed-action-service.js.map +1 -0
  421. package/dist/services/operate/identity-contract.d.ts +3 -0
  422. package/dist/services/operate/identity-contract.d.ts.map +1 -0
  423. package/dist/services/operate/identity-contract.js +6 -0
  424. package/dist/services/operate/identity-contract.js.map +1 -0
  425. package/dist/services/operate/measurement-schedule-service.d.ts +81 -0
  426. package/dist/services/operate/measurement-schedule-service.d.ts.map +1 -0
  427. package/dist/services/operate/measurement-schedule-service.js +461 -0
  428. package/dist/services/operate/measurement-schedule-service.js.map +1 -0
  429. package/dist/services/operate/path-custody.d.ts +16 -0
  430. package/dist/services/operate/path-custody.d.ts.map +1 -0
  431. package/dist/services/operate/path-custody.js +120 -0
  432. package/dist/services/operate/path-custody.js.map +1 -0
  433. package/dist/services/operate/pinned-legacy-replay-runner.d.ts +9 -0
  434. package/dist/services/operate/pinned-legacy-replay-runner.d.ts.map +1 -0
  435. package/dist/services/operate/pinned-legacy-replay-runner.js +441 -0
  436. package/dist/services/operate/pinned-legacy-replay-runner.js.map +1 -0
  437. package/dist/services/operate/planning-bridge.d.ts +28 -0
  438. package/dist/services/operate/planning-bridge.d.ts.map +1 -0
  439. package/dist/services/operate/planning-bridge.js +341 -0
  440. package/dist/services/operate/planning-bridge.js.map +1 -0
  441. package/dist/services/operate/planning-handoff-gateway.d.ts +47 -0
  442. package/dist/services/operate/planning-handoff-gateway.d.ts.map +1 -0
  443. package/dist/services/operate/planning-handoff-gateway.js +169 -0
  444. package/dist/services/operate/planning-handoff-gateway.js.map +1 -0
  445. package/dist/services/operate/planning-handoff-service.d.ts +38 -0
  446. package/dist/services/operate/planning-handoff-service.d.ts.map +1 -0
  447. package/dist/services/operate/planning-handoff-service.js +304 -0
  448. package/dist/services/operate/planning-handoff-service.js.map +1 -0
  449. package/dist/services/operate/project-transaction-lock.d.ts +6 -0
  450. package/dist/services/operate/project-transaction-lock.d.ts.map +1 -0
  451. package/dist/services/operate/project-transaction-lock.js +146 -0
  452. package/dist/services/operate/project-transaction-lock.js.map +1 -0
  453. package/dist/services/operate/recovery-service.d.ts +16 -0
  454. package/dist/services/operate/recovery-service.d.ts.map +1 -0
  455. package/dist/services/operate/recovery-service.js +59 -0
  456. package/dist/services/operate/recovery-service.js.map +1 -0
  457. package/dist/services/operate/replay-safe-retry-service.d.ts +21 -0
  458. package/dist/services/operate/replay-safe-retry-service.d.ts.map +1 -0
  459. package/dist/services/operate/replay-safe-retry-service.js +66 -0
  460. package/dist/services/operate/replay-safe-retry-service.js.map +1 -0
  461. package/dist/services/operate/repository-read-service.d.ts +13 -0
  462. package/dist/services/operate/repository-read-service.d.ts.map +1 -0
  463. package/dist/services/operate/repository-read-service.js +153 -0
  464. package/dist/services/operate/repository-read-service.js.map +1 -0
  465. package/dist/services/operate/review-lifecycle-service.d.ts +50 -0
  466. package/dist/services/operate/review-lifecycle-service.d.ts.map +1 -0
  467. package/dist/services/operate/review-lifecycle-service.js +63 -0
  468. package/dist/services/operate/review-lifecycle-service.js.map +1 -0
  469. package/dist/services/operate/review-read-gateway.d.ts +21 -0
  470. package/dist/services/operate/review-read-gateway.d.ts.map +1 -0
  471. package/dist/services/operate/review-read-gateway.js +119 -0
  472. package/dist/services/operate/review-read-gateway.js.map +1 -0
  473. package/dist/services/operate/screened-evidence-service.d.ts +24 -0
  474. package/dist/services/operate/screened-evidence-service.d.ts.map +1 -0
  475. package/dist/services/operate/screened-evidence-service.js +186 -0
  476. package/dist/services/operate/screened-evidence-service.js.map +1 -0
  477. package/dist/services/operate/search-hit-contract.d.ts +11 -0
  478. package/dist/services/operate/search-hit-contract.d.ts.map +1 -0
  479. package/dist/services/operate/search-hit-contract.js +29 -0
  480. package/dist/services/operate/search-hit-contract.js.map +1 -0
  481. package/dist/services/operate/session-capability.d.ts +61 -0
  482. package/dist/services/operate/session-capability.d.ts.map +1 -0
  483. package/dist/services/operate/session-capability.js +124 -0
  484. package/dist/services/operate/session-capability.js.map +1 -0
  485. package/dist/services/operate/spec-operating-origin-service.d.ts +60 -0
  486. package/dist/services/operate/spec-operating-origin-service.d.ts.map +1 -0
  487. package/dist/services/operate/spec-operating-origin-service.js +401 -0
  488. package/dist/services/operate/spec-operating-origin-service.js.map +1 -0
  489. package/dist/services/operate/storage-layout.d.ts +82 -0
  490. package/dist/services/operate/storage-layout.d.ts.map +1 -0
  491. package/dist/services/operate/storage-layout.js +1244 -0
  492. package/dist/services/operate/storage-layout.js.map +1 -0
  493. package/dist/services/operate/storage-migration-service.d.ts +15 -0
  494. package/dist/services/operate/storage-migration-service.d.ts.map +1 -0
  495. package/dist/services/operate/storage-migration-service.js +27 -0
  496. package/dist/services/operate/storage-migration-service.js.map +1 -0
  497. package/dist/services/operate/store.d.ts +132 -0
  498. package/dist/services/operate/store.d.ts.map +1 -0
  499. package/dist/services/operate/store.js +1344 -0
  500. package/dist/services/operate/store.js.map +1 -0
  501. package/dist/services/pipeline-package-service.d.ts +93 -2
  502. package/dist/services/pipeline-package-service.d.ts.map +1 -1
  503. package/dist/services/pipeline-package-service.js +867 -7
  504. package/dist/services/pipeline-package-service.js.map +1 -1
  505. package/dist/services/planning-id-service.d.ts +8 -0
  506. package/dist/services/planning-id-service.d.ts.map +1 -0
  507. package/dist/services/planning-id-service.js +114 -0
  508. package/dist/services/planning-id-service.js.map +1 -0
  509. package/dist/services/provenance-service.d.ts +33 -1
  510. package/dist/services/provenance-service.d.ts.map +1 -1
  511. package/dist/services/provenance-service.js +104 -8
  512. package/dist/services/provenance-service.js.map +1 -1
  513. package/dist/services/runtime-manager/doctor.d.ts +22 -0
  514. package/dist/services/runtime-manager/doctor.d.ts.map +1 -0
  515. package/dist/services/runtime-manager/doctor.js +74 -0
  516. package/dist/services/runtime-manager/doctor.js.map +1 -0
  517. package/dist/services/runtime-manager/global-state.d.ts +47 -0
  518. package/dist/services/runtime-manager/global-state.d.ts.map +1 -0
  519. package/dist/services/runtime-manager/global-state.js +59 -0
  520. package/dist/services/runtime-manager/global-state.js.map +1 -0
  521. package/dist/services/runtime-manager/install-plan.d.ts +37 -0
  522. package/dist/services/runtime-manager/install-plan.d.ts.map +1 -0
  523. package/dist/services/runtime-manager/install-plan.js +91 -0
  524. package/dist/services/runtime-manager/install-plan.js.map +1 -0
  525. package/dist/services/runtime-manager/inventory.d.ts +29 -0
  526. package/dist/services/runtime-manager/inventory.d.ts.map +1 -0
  527. package/dist/services/runtime-manager/inventory.js +46 -0
  528. package/dist/services/runtime-manager/inventory.js.map +1 -0
  529. package/dist/services/runtime-manager-service.d.ts +16 -71
  530. package/dist/services/runtime-manager-service.d.ts.map +1 -1
  531. package/dist/services/runtime-manager-service.js +1288 -505
  532. package/dist/services/runtime-manager-service.js.map +1 -1
  533. package/dist/services/spec-service.d.ts +213 -39
  534. package/dist/services/spec-service.d.ts.map +1 -1
  535. package/dist/services/spec-service.js +938 -171
  536. package/dist/services/spec-service.js.map +1 -1
  537. package/dist/services/template-service.d.ts.map +1 -1
  538. package/dist/services/template-service.js +1 -0
  539. package/dist/services/template-service.js.map +1 -1
  540. package/dist/templates/quick/quick-task.md.hbs +6 -0
  541. package/dist/templates/rules/claude/CLAUDE.md.hbs +3 -111
  542. package/dist/templates/rules/codex/AGENTS.md.hbs +2 -92
  543. package/dist/templates/rules/cursor/create-task-list.mdc.hbs +1 -1
  544. package/dist/templates/rules/cursor/implement-task-list.mdc.hbs +5 -83
  545. package/dist/templates/rules/cursor/openplanr.mdc.hbs +12 -0
  546. package/dist/templates/rules/shared/host-native-guidance.md.hbs +12 -0
  547. package/dist/templates/rules/shared/implementation-guidance.md.hbs +44 -0
  548. package/dist/templates/spec/spec-shaped.md.hbs +66 -22
  549. package/dist/templates/spec/spec.md.hbs +46 -23
  550. package/dist/templates/spec/story.md.hbs +15 -4
  551. package/dist/templates/spec/task.md.hbs +53 -5
  552. package/dist/utils/constants.d.ts +1 -1
  553. package/dist/utils/constants.js +1 -1
  554. package/dist/utils/logger.d.ts +0 -3
  555. package/dist/utils/logger.d.ts.map +1 -1
  556. package/dist/utils/logger.js +0 -6
  557. package/dist/utils/logger.js.map +1 -1
  558. package/docs/ARTIFACT_REVIEW.md +110 -0
  559. package/docs/CLI.md +1228 -0
  560. package/docs/CROSS_RUNTIME_SETUP.md +168 -0
  561. package/docs/TROUBLESHOOTING.md +227 -0
  562. package/lib/dashboard-verifier.d.mts +29 -0
  563. package/lib/dashboard-verifier.mjs +307 -0
  564. package/lib/host-packages/adapter-registry.json +44 -0
  565. package/lib/host-packages/claude/.claude-plugin/marketplace.json +20 -0
  566. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +9 -0
  567. package/lib/host-packages/claude/openplanr/.openplanr-content.json +1179 -0
  568. package/lib/host-packages/claude/openplanr/agents/planr-backend.md +66 -0
  569. package/lib/host-packages/claude/openplanr/agents/planr-database.md +165 -0
  570. package/lib/host-packages/claude/openplanr/agents/planr-designer.md +57 -0
  571. package/lib/host-packages/claude/openplanr/agents/planr-devops.md +57 -0
  572. package/lib/host-packages/claude/openplanr/agents/planr-documentation.md +63 -0
  573. package/lib/host-packages/claude/openplanr/agents/planr-entity-scaffold.md +29 -0
  574. package/lib/host-packages/claude/openplanr/agents/planr-frontend.md +69 -0
  575. package/lib/host-packages/claude/openplanr/agents/planr-qa.md +162 -0
  576. package/lib/host-packages/claude/openplanr/agents/planr-specification.md +124 -0
  577. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/default/backend.md +93 -0
  578. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/default/designer.md +90 -0
  579. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/default/devops.md +55 -0
  580. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/default/doc-gen.md +67 -0
  581. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/default/frontend.md +94 -0
  582. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/default/qa.md +17 -0
  583. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/default/specification.md +111 -0
  584. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/contract-create-modify-preserve.md +17 -0
  585. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/design-craft-rubric.md +51 -0
  586. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/design-principles.md +43 -0
  587. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/design-spec-template.md +88 -0
  588. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/task-context-resolution.md +60 -0
  589. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/verification-and-recovery-backend.md +26 -0
  590. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/verification-and-recovery-frontend.md +27 -0
  591. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/spec-driven/backend.md +96 -0
  592. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/spec-driven/designer.md +83 -0
  593. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/spec-driven/devops.md +55 -0
  594. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/spec-driven/doc-gen.md +67 -0
  595. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/spec-driven/frontend.md +96 -0
  596. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/spec-driven/qa.md +17 -0
  597. package/lib/host-packages/claude/openplanr/references/agents/shared/modes/spec-driven/specification.md +112 -0
  598. package/lib/host-packages/claude/openplanr/references/pipeline/stacks/backend/nestjs.md +130 -0
  599. package/lib/host-packages/claude/openplanr/references/pipeline/stacks/database/mongodb.md +122 -0
  600. package/lib/host-packages/claude/openplanr/references/pipeline/stacks/database/prisma.md +155 -0
  601. package/lib/host-packages/claude/openplanr/references/pipeline/stacks/devops/docker-compose.md +140 -0
  602. package/lib/host-packages/claude/openplanr/references/pipeline/stacks/frontend/nextjs.md +123 -0
  603. package/lib/host-packages/claude/openplanr/skills/artifact/SKILL.md +54 -0
  604. package/lib/host-packages/claude/openplanr/skills/artifact/openplanr.skill.json +48 -0
  605. package/lib/host-packages/claude/openplanr/skills/artifact/references/company-review.md +18 -0
  606. package/lib/host-packages/claude/openplanr/skills/artifact/references/design-sharing.md +51 -0
  607. package/lib/host-packages/claude/openplanr/skills/browser-qa/SKILL.md +34 -0
  608. package/lib/host-packages/claude/openplanr/skills/browser-qa/openplanr.skill.json +26 -0
  609. package/lib/host-packages/claude/openplanr/skills/ceo-review/SKILL.md +47 -0
  610. package/lib/host-packages/claude/openplanr/skills/ceo-review/openplanr.skill.json +81 -0
  611. package/lib/host-packages/claude/openplanr/skills/ceo-review/references/operate-advisor-contract.md +111 -0
  612. package/lib/host-packages/claude/openplanr/skills/ceo-review/scripts/errors.mjs +8 -0
  613. package/lib/host-packages/claude/openplanr/skills/ceo-review/scripts/operate-review-contract.mjs +438 -0
  614. package/lib/host-packages/claude/openplanr/skills/ceo-review/scripts/operate-review-note.mjs +595 -0
  615. package/lib/host-packages/claude/openplanr/skills/ceo-review/scripts/validate-note.mjs +31 -0
  616. package/lib/host-packages/claude/openplanr/skills/chair-review/SKILL.md +101 -0
  617. package/lib/host-packages/claude/openplanr/skills/chair-review/openplanr.skill.json +70 -0
  618. package/lib/host-packages/claude/openplanr/skills/chair-review/scripts/errors.mjs +8 -0
  619. package/lib/host-packages/claude/openplanr/skills/chair-review/scripts/operate-review-contract.mjs +438 -0
  620. package/lib/host-packages/claude/openplanr/skills/chair-review/scripts/operate-review-note.mjs +595 -0
  621. package/lib/host-packages/claude/openplanr/skills/chair-review/scripts/validate-note.mjs +31 -0
  622. package/lib/host-packages/claude/openplanr/skills/challenger-review/SKILL.md +86 -0
  623. package/lib/host-packages/claude/openplanr/skills/challenger-review/openplanr.skill.json +70 -0
  624. package/lib/host-packages/claude/openplanr/skills/challenger-review/scripts/errors.mjs +8 -0
  625. package/lib/host-packages/claude/openplanr/skills/challenger-review/scripts/operate-review-contract.mjs +438 -0
  626. package/lib/host-packages/claude/openplanr/skills/challenger-review/scripts/operate-review-note.mjs +595 -0
  627. package/lib/host-packages/claude/openplanr/skills/challenger-review/scripts/validate-note.mjs +31 -0
  628. package/lib/host-packages/claude/openplanr/skills/cmo-review/SKILL.md +46 -0
  629. package/lib/host-packages/claude/openplanr/skills/cmo-review/openplanr.skill.json +81 -0
  630. package/lib/host-packages/claude/openplanr/skills/cmo-review/references/operate-advisor-contract.md +111 -0
  631. package/lib/host-packages/claude/openplanr/skills/cmo-review/scripts/errors.mjs +8 -0
  632. package/lib/host-packages/claude/openplanr/skills/cmo-review/scripts/operate-review-contract.mjs +438 -0
  633. package/lib/host-packages/claude/openplanr/skills/cmo-review/scripts/operate-review-note.mjs +595 -0
  634. package/lib/host-packages/claude/openplanr/skills/cmo-review/scripts/validate-note.mjs +31 -0
  635. package/lib/host-packages/claude/openplanr/skills/coo-review/SKILL.md +45 -0
  636. package/lib/host-packages/claude/openplanr/skills/coo-review/openplanr.skill.json +81 -0
  637. package/lib/host-packages/claude/openplanr/skills/coo-review/references/operate-advisor-contract.md +111 -0
  638. package/lib/host-packages/claude/openplanr/skills/coo-review/scripts/errors.mjs +8 -0
  639. package/lib/host-packages/claude/openplanr/skills/coo-review/scripts/operate-review-contract.mjs +438 -0
  640. package/lib/host-packages/claude/openplanr/skills/coo-review/scripts/operate-review-note.mjs +595 -0
  641. package/lib/host-packages/claude/openplanr/skills/coo-review/scripts/validate-note.mjs +31 -0
  642. package/lib/host-packages/claude/openplanr/skills/cpo-review/SKILL.md +48 -0
  643. package/lib/host-packages/claude/openplanr/skills/cpo-review/openplanr.skill.json +81 -0
  644. package/lib/host-packages/claude/openplanr/skills/cpo-review/references/operate-advisor-contract.md +111 -0
  645. package/lib/host-packages/claude/openplanr/skills/cpo-review/scripts/errors.mjs +8 -0
  646. package/lib/host-packages/claude/openplanr/skills/cpo-review/scripts/operate-review-contract.mjs +438 -0
  647. package/lib/host-packages/claude/openplanr/skills/cpo-review/scripts/operate-review-note.mjs +595 -0
  648. package/lib/host-packages/claude/openplanr/skills/cpo-review/scripts/validate-note.mjs +31 -0
  649. package/lib/host-packages/claude/openplanr/skills/cto-review/SKILL.md +47 -0
  650. package/lib/host-packages/claude/openplanr/skills/cto-review/openplanr.skill.json +81 -0
  651. package/lib/host-packages/claude/openplanr/skills/cto-review/references/operate-advisor-contract.md +111 -0
  652. package/lib/host-packages/claude/openplanr/skills/cto-review/scripts/errors.mjs +8 -0
  653. package/lib/host-packages/claude/openplanr/skills/cto-review/scripts/operate-review-contract.mjs +438 -0
  654. package/lib/host-packages/claude/openplanr/skills/cto-review/scripts/operate-review-note.mjs +595 -0
  655. package/lib/host-packages/claude/openplanr/skills/cto-review/scripts/validate-note.mjs +31 -0
  656. package/lib/host-packages/claude/openplanr/skills/dashboard/SKILL.md +20 -0
  657. package/lib/host-packages/claude/openplanr/skills/dashboard/openplanr.skill.json +26 -0
  658. package/lib/host-packages/claude/openplanr/skills/design/SKILL.md +73 -0
  659. package/lib/host-packages/claude/openplanr/skills/design/openplanr.skill.json +466 -0
  660. package/lib/host-packages/claude/openplanr/skills/design/references/craft.md +68 -0
  661. package/lib/host-packages/claude/openplanr/skills/design/references/design-spec-template.md +88 -0
  662. package/lib/host-packages/claude/openplanr/skills/design/references/design-system.md +33 -0
  663. package/lib/host-packages/claude/openplanr/skills/design/references/discovery.md +53 -0
  664. package/lib/host-packages/claude/openplanr/skills/design/references/generation.md +105 -0
  665. package/lib/host-packages/claude/openplanr/skills/design/references/handoff.md +47 -0
  666. package/lib/host-packages/claude/openplanr/skills/design/references/review.md +88 -0
  667. package/lib/host-packages/claude/openplanr/skills/design/references/team-review.md +131 -0
  668. package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +93 -0
  669. package/lib/host-packages/claude/openplanr/skills/design/schemas/design-document.schema.json +306 -0
  670. package/lib/host-packages/claude/openplanr/skills/design/schemas/design-review-context.schema.json +191 -0
  671. package/lib/host-packages/claude/openplanr/skills/design/schemas/design-review-handoff.schema.json +407 -0
  672. package/lib/host-packages/claude/openplanr/skills/design/scripts/design.mjs +17323 -0
  673. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/notices/entities.txt +13 -0
  674. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/notices/parse5.txt +21 -0
  675. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  676. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  677. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  678. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  679. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  680. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  681. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  682. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/package.json +115 -0
  683. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  684. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  685. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  686. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  687. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  688. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  689. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  690. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  691. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  692. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  693. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  694. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  695. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  696. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  697. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  698. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  699. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  700. package/lib/host-packages/claude/openplanr/skills/design-loop/SKILL.md +58 -0
  701. package/lib/host-packages/claude/openplanr/skills/design-loop/openplanr.skill.json +466 -0
  702. package/lib/host-packages/claude/openplanr/skills/design-loop/references/craft.md +68 -0
  703. package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-spec-template.md +88 -0
  704. package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-system.md +33 -0
  705. package/lib/host-packages/claude/openplanr/skills/design-loop/references/discovery.md +53 -0
  706. package/lib/host-packages/claude/openplanr/skills/design-loop/references/generation.md +105 -0
  707. package/lib/host-packages/claude/openplanr/skills/design-loop/references/handoff.md +47 -0
  708. package/lib/host-packages/claude/openplanr/skills/design-loop/references/review.md +88 -0
  709. package/lib/host-packages/claude/openplanr/skills/design-loop/references/team-review.md +131 -0
  710. package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +93 -0
  711. package/lib/host-packages/claude/openplanr/skills/design-loop/schemas/design-document.schema.json +306 -0
  712. package/lib/host-packages/claude/openplanr/skills/design-loop/schemas/design-review-context.schema.json +191 -0
  713. package/lib/host-packages/claude/openplanr/skills/design-loop/schemas/design-review-handoff.schema.json +407 -0
  714. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/design.mjs +17323 -0
  715. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/notices/entities.txt +13 -0
  716. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/notices/parse5.txt +21 -0
  717. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  718. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  719. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  720. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  721. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  722. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  723. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  724. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/package.json +115 -0
  725. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  726. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  727. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  728. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  729. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  730. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  731. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  732. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  733. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  734. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  735. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  736. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  737. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  738. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  739. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  740. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  741. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  742. package/lib/host-packages/claude/openplanr/skills/design-review/SKILL.md +54 -0
  743. package/lib/host-packages/claude/openplanr/skills/design-review/openplanr.skill.json +466 -0
  744. package/lib/host-packages/claude/openplanr/skills/design-review/references/craft.md +68 -0
  745. package/lib/host-packages/claude/openplanr/skills/design-review/references/design-spec-template.md +88 -0
  746. package/lib/host-packages/claude/openplanr/skills/design-review/references/design-system.md +33 -0
  747. package/lib/host-packages/claude/openplanr/skills/design-review/references/discovery.md +53 -0
  748. package/lib/host-packages/claude/openplanr/skills/design-review/references/generation.md +105 -0
  749. package/lib/host-packages/claude/openplanr/skills/design-review/references/handoff.md +47 -0
  750. package/lib/host-packages/claude/openplanr/skills/design-review/references/review.md +88 -0
  751. package/lib/host-packages/claude/openplanr/skills/design-review/references/team-review.md +131 -0
  752. package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +93 -0
  753. package/lib/host-packages/claude/openplanr/skills/design-review/schemas/design-document.schema.json +306 -0
  754. package/lib/host-packages/claude/openplanr/skills/design-review/schemas/design-review-context.schema.json +191 -0
  755. package/lib/host-packages/claude/openplanr/skills/design-review/schemas/design-review-handoff.schema.json +407 -0
  756. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/design.mjs +17323 -0
  757. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/notices/entities.txt +13 -0
  758. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/notices/parse5.txt +21 -0
  759. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  760. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  761. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  762. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  763. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  764. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  765. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  766. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/package.json +115 -0
  767. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  768. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  769. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  770. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  771. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  772. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  773. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  774. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  775. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  776. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  777. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  778. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  779. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  780. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  781. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  782. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  783. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  784. package/lib/host-packages/claude/openplanr/skills/diagram/SKILL.md +65 -0
  785. package/lib/host-packages/claude/openplanr/skills/diagram/openplanr.skill.json +59 -0
  786. package/lib/host-packages/claude/openplanr/skills/diagram/references/diagram-document.md +86 -0
  787. package/lib/host-packages/claude/openplanr/skills/diagram/references/diagram-fidelity.md +19 -0
  788. package/lib/host-packages/claude/openplanr/skills/diagram/references/diagram-intent-to-ir.md +22 -0
  789. package/lib/host-packages/claude/openplanr/skills/doctor/SKILL.md +40 -0
  790. package/lib/host-packages/claude/openplanr/skills/doctor/openplanr.skill.json +37 -0
  791. package/lib/host-packages/claude/openplanr/skills/doctor/references/upgrade.md +106 -0
  792. package/lib/host-packages/claude/openplanr/skills/investigate/SKILL.md +31 -0
  793. package/lib/host-packages/claude/openplanr/skills/investigate/openplanr.skill.json +26 -0
  794. package/lib/host-packages/claude/openplanr/skills/land/SKILL.md +33 -0
  795. package/lib/host-packages/claude/openplanr/skills/land/openplanr.skill.json +26 -0
  796. package/lib/host-packages/claude/openplanr/skills/operate/SKILL.md +181 -0
  797. package/lib/host-packages/claude/openplanr/skills/operate/openplanr.skill.json +70 -0
  798. package/lib/host-packages/claude/openplanr/skills/operate/scripts/errors.mjs +8 -0
  799. package/lib/host-packages/claude/openplanr/skills/operate/scripts/operate-review-contract.mjs +438 -0
  800. package/lib/host-packages/claude/openplanr/skills/operate/scripts/operate-review-note.mjs +595 -0
  801. package/lib/host-packages/claude/openplanr/skills/operate/scripts/validate-note.mjs +31 -0
  802. package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +106 -0
  803. package/lib/host-packages/claude/openplanr/skills/plan/openplanr.skill.json +389 -0
  804. package/lib/host-packages/claude/openplanr/skills/plan/references/artifact-contract.md +39 -0
  805. package/lib/host-packages/claude/openplanr/skills/plan/schemas/design-document.schema.json +306 -0
  806. package/lib/host-packages/claude/openplanr/skills/plan/schemas/design-review-context.schema.json +191 -0
  807. package/lib/host-packages/claude/openplanr/skills/plan/schemas/design-review-handoff.schema.json +407 -0
  808. package/lib/host-packages/claude/openplanr/skills/plan/scripts/design.mjs +17323 -0
  809. package/lib/host-packages/claude/openplanr/skills/plan/scripts/planning-ids.mjs +120 -0
  810. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/notices/entities.txt +13 -0
  811. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/notices/parse5.txt +21 -0
  812. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  813. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  814. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  815. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  816. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  817. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  818. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  819. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/package.json +115 -0
  820. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  821. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  822. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  823. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  824. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  825. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  826. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  827. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  828. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  829. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  830. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  831. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  832. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  833. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  834. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  835. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  836. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  837. package/lib/host-packages/claude/openplanr/skills/plan-review/SKILL.md +39 -0
  838. package/lib/host-packages/claude/openplanr/skills/plan-review/openplanr.skill.json +26 -0
  839. package/lib/host-packages/claude/openplanr/skills/release/SKILL.md +180 -0
  840. package/lib/host-packages/claude/openplanr/skills/release/assets/changelog-template.md +18 -0
  841. package/lib/host-packages/claude/openplanr/skills/release/assets/profile-template.md +45 -0
  842. package/lib/host-packages/claude/openplanr/skills/release/openplanr.skill.json +92 -0
  843. package/lib/host-packages/claude/openplanr/skills/release/references/cadence.md +92 -0
  844. package/lib/host-packages/claude/openplanr/skills/release/references/release-notes.md +127 -0
  845. package/lib/host-packages/claude/openplanr/skills/release/references/schemes.md +103 -0
  846. package/lib/host-packages/claude/openplanr/skills/release/scripts/collect_changes.sh +85 -0
  847. package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +80 -0
  848. package/lib/host-packages/claude/openplanr/skills/ship/openplanr.skill.json +48 -0
  849. package/lib/host-packages/claude/openplanr/skills/ship/references/result-contract.md +14 -0
  850. package/lib/host-packages/claude/openplanr/skills/ship/scripts/discover-verification.mjs +107 -0
  851. package/lib/host-packages/claude/openplanr/skills/spec/SKILL.md +53 -0
  852. package/lib/host-packages/claude/openplanr/skills/spec/openplanr.skill.json +37 -0
  853. package/lib/host-packages/claude/openplanr/skills/spec/references/specification-contract.md +32 -0
  854. package/lib/host-packages/claude/openplanr/skills/status/SKILL.md +21 -0
  855. package/lib/host-packages/claude/openplanr/skills/status/openplanr.skill.json +26 -0
  856. package/lib/host-packages/claude/openplanr/skills/sync/SKILL.md +30 -0
  857. package/lib/host-packages/claude/openplanr/skills/sync/openplanr.skill.json +37 -0
  858. package/lib/host-packages/claude/openplanr/skills/sync/scripts/sync.mjs +230 -0
  859. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +939 -0
  860. package/lib/host-packages/cursor/openplanr/manifest.json +32 -0
  861. package/lib/host-packages/cursor/openplanr/rules/planr-artifact/references/company-review.md +18 -0
  862. package/lib/host-packages/cursor/openplanr/rules/planr-artifact/references/design-sharing.md +51 -0
  863. package/lib/host-packages/cursor/openplanr/rules/planr-artifact.mdc +53 -0
  864. package/lib/host-packages/cursor/openplanr/rules/planr-browser-qa.mdc +34 -0
  865. package/lib/host-packages/cursor/openplanr/rules/planr-ceo-review/references/operate-advisor-contract.md +111 -0
  866. package/lib/host-packages/cursor/openplanr/rules/planr-ceo-review/scripts/errors.mjs +8 -0
  867. package/lib/host-packages/cursor/openplanr/rules/planr-ceo-review/scripts/operate-review-contract.mjs +438 -0
  868. package/lib/host-packages/cursor/openplanr/rules/planr-ceo-review/scripts/operate-review-note.mjs +595 -0
  869. package/lib/host-packages/cursor/openplanr/rules/planr-ceo-review/scripts/validate-note.mjs +31 -0
  870. package/lib/host-packages/cursor/openplanr/rules/planr-ceo-review.mdc +45 -0
  871. package/lib/host-packages/cursor/openplanr/rules/planr-chair-review/scripts/errors.mjs +8 -0
  872. package/lib/host-packages/cursor/openplanr/rules/planr-chair-review/scripts/operate-review-contract.mjs +438 -0
  873. package/lib/host-packages/cursor/openplanr/rules/planr-chair-review/scripts/operate-review-note.mjs +595 -0
  874. package/lib/host-packages/cursor/openplanr/rules/planr-chair-review/scripts/validate-note.mjs +31 -0
  875. package/lib/host-packages/cursor/openplanr/rules/planr-chair-review.mdc +99 -0
  876. package/lib/host-packages/cursor/openplanr/rules/planr-challenger-review/scripts/errors.mjs +8 -0
  877. package/lib/host-packages/cursor/openplanr/rules/planr-challenger-review/scripts/operate-review-contract.mjs +438 -0
  878. package/lib/host-packages/cursor/openplanr/rules/planr-challenger-review/scripts/operate-review-note.mjs +595 -0
  879. package/lib/host-packages/cursor/openplanr/rules/planr-challenger-review/scripts/validate-note.mjs +31 -0
  880. package/lib/host-packages/cursor/openplanr/rules/planr-challenger-review.mdc +84 -0
  881. package/lib/host-packages/cursor/openplanr/rules/planr-cmo-review/references/operate-advisor-contract.md +111 -0
  882. package/lib/host-packages/cursor/openplanr/rules/planr-cmo-review/scripts/errors.mjs +8 -0
  883. package/lib/host-packages/cursor/openplanr/rules/planr-cmo-review/scripts/operate-review-contract.mjs +438 -0
  884. package/lib/host-packages/cursor/openplanr/rules/planr-cmo-review/scripts/operate-review-note.mjs +595 -0
  885. package/lib/host-packages/cursor/openplanr/rules/planr-cmo-review/scripts/validate-note.mjs +31 -0
  886. package/lib/host-packages/cursor/openplanr/rules/planr-cmo-review.mdc +44 -0
  887. package/lib/host-packages/cursor/openplanr/rules/planr-coo-review/references/operate-advisor-contract.md +111 -0
  888. package/lib/host-packages/cursor/openplanr/rules/planr-coo-review/scripts/errors.mjs +8 -0
  889. package/lib/host-packages/cursor/openplanr/rules/planr-coo-review/scripts/operate-review-contract.mjs +438 -0
  890. package/lib/host-packages/cursor/openplanr/rules/planr-coo-review/scripts/operate-review-note.mjs +595 -0
  891. package/lib/host-packages/cursor/openplanr/rules/planr-coo-review/scripts/validate-note.mjs +31 -0
  892. package/lib/host-packages/cursor/openplanr/rules/planr-coo-review.mdc +43 -0
  893. package/lib/host-packages/cursor/openplanr/rules/planr-cpo-review/references/operate-advisor-contract.md +111 -0
  894. package/lib/host-packages/cursor/openplanr/rules/planr-cpo-review/scripts/errors.mjs +8 -0
  895. package/lib/host-packages/cursor/openplanr/rules/planr-cpo-review/scripts/operate-review-contract.mjs +438 -0
  896. package/lib/host-packages/cursor/openplanr/rules/planr-cpo-review/scripts/operate-review-note.mjs +595 -0
  897. package/lib/host-packages/cursor/openplanr/rules/planr-cpo-review/scripts/validate-note.mjs +31 -0
  898. package/lib/host-packages/cursor/openplanr/rules/planr-cpo-review.mdc +46 -0
  899. package/lib/host-packages/cursor/openplanr/rules/planr-cto-review/references/operate-advisor-contract.md +111 -0
  900. package/lib/host-packages/cursor/openplanr/rules/planr-cto-review/scripts/errors.mjs +8 -0
  901. package/lib/host-packages/cursor/openplanr/rules/planr-cto-review/scripts/operate-review-contract.mjs +438 -0
  902. package/lib/host-packages/cursor/openplanr/rules/planr-cto-review/scripts/operate-review-note.mjs +595 -0
  903. package/lib/host-packages/cursor/openplanr/rules/planr-cto-review/scripts/validate-note.mjs +31 -0
  904. package/lib/host-packages/cursor/openplanr/rules/planr-cto-review.mdc +45 -0
  905. package/lib/host-packages/cursor/openplanr/rules/planr-dashboard.mdc +19 -0
  906. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/craft.md +68 -0
  907. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-spec-template.md +88 -0
  908. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-system.md +33 -0
  909. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/discovery.md +53 -0
  910. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/generation.md +105 -0
  911. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/handoff.md +47 -0
  912. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/review.md +88 -0
  913. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/team-review.md +131 -0
  914. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +93 -0
  915. package/lib/host-packages/cursor/openplanr/rules/planr-design/schemas/design-document.schema.json +306 -0
  916. package/lib/host-packages/cursor/openplanr/rules/planr-design/schemas/design-review-context.schema.json +191 -0
  917. package/lib/host-packages/cursor/openplanr/rules/planr-design/schemas/design-review-handoff.schema.json +407 -0
  918. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/design.mjs +17323 -0
  919. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/notices/entities.txt +13 -0
  920. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/notices/parse5.txt +21 -0
  921. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  922. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  923. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  924. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  925. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  926. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  927. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  928. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/package.json +115 -0
  929. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  930. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  931. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  932. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  933. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  934. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  935. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  936. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  937. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  938. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  939. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  940. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  941. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  942. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  943. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  944. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  945. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  946. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/craft.md +68 -0
  947. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-spec-template.md +88 -0
  948. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-system.md +33 -0
  949. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/discovery.md +53 -0
  950. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/generation.md +105 -0
  951. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/handoff.md +47 -0
  952. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/review.md +88 -0
  953. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/team-review.md +131 -0
  954. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +93 -0
  955. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/schemas/design-document.schema.json +306 -0
  956. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/schemas/design-review-context.schema.json +191 -0
  957. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/schemas/design-review-handoff.schema.json +407 -0
  958. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/design.mjs +17323 -0
  959. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/notices/entities.txt +13 -0
  960. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/notices/parse5.txt +21 -0
  961. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  962. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  963. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  964. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  965. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  966. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  967. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  968. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/package.json +115 -0
  969. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  970. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  971. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  972. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  973. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  974. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  975. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  976. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  977. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  978. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  979. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  980. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  981. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  982. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  983. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  984. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  985. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  986. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop.mdc +57 -0
  987. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/craft.md +68 -0
  988. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-spec-template.md +88 -0
  989. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-system.md +33 -0
  990. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/discovery.md +53 -0
  991. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/generation.md +105 -0
  992. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/handoff.md +47 -0
  993. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/review.md +88 -0
  994. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/team-review.md +131 -0
  995. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +93 -0
  996. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/schemas/design-document.schema.json +306 -0
  997. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/schemas/design-review-context.schema.json +191 -0
  998. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/schemas/design-review-handoff.schema.json +407 -0
  999. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/design.mjs +17323 -0
  1000. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/notices/entities.txt +13 -0
  1001. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/notices/parse5.txt +21 -0
  1002. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  1003. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  1004. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  1005. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  1006. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  1007. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  1008. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  1009. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/package.json +115 -0
  1010. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  1011. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  1012. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  1013. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  1014. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  1015. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  1016. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  1017. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  1018. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  1019. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  1020. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  1021. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  1022. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  1023. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  1024. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  1025. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  1026. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  1027. package/lib/host-packages/cursor/openplanr/rules/planr-design-review.mdc +53 -0
  1028. package/lib/host-packages/cursor/openplanr/rules/planr-design.mdc +72 -0
  1029. package/lib/host-packages/cursor/openplanr/rules/planr-diagram/references/diagram-document.md +86 -0
  1030. package/lib/host-packages/cursor/openplanr/rules/planr-diagram/references/diagram-fidelity.md +19 -0
  1031. package/lib/host-packages/cursor/openplanr/rules/planr-diagram/references/diagram-intent-to-ir.md +22 -0
  1032. package/lib/host-packages/cursor/openplanr/rules/planr-diagram.mdc +64 -0
  1033. package/lib/host-packages/cursor/openplanr/rules/planr-doctor/references/upgrade.md +106 -0
  1034. package/lib/host-packages/cursor/openplanr/rules/planr-doctor.mdc +39 -0
  1035. package/lib/host-packages/cursor/openplanr/rules/planr-investigate.mdc +31 -0
  1036. package/lib/host-packages/cursor/openplanr/rules/planr-land.mdc +32 -0
  1037. package/lib/host-packages/cursor/openplanr/rules/planr-operate/scripts/errors.mjs +8 -0
  1038. package/lib/host-packages/cursor/openplanr/rules/planr-operate/scripts/operate-review-contract.mjs +438 -0
  1039. package/lib/host-packages/cursor/openplanr/rules/planr-operate/scripts/operate-review-note.mjs +595 -0
  1040. package/lib/host-packages/cursor/openplanr/rules/planr-operate/scripts/validate-note.mjs +31 -0
  1041. package/lib/host-packages/cursor/openplanr/rules/planr-operate.mdc +180 -0
  1042. package/lib/host-packages/cursor/openplanr/rules/planr-plan/references/artifact-contract.md +39 -0
  1043. package/lib/host-packages/cursor/openplanr/rules/planr-plan/schemas/design-document.schema.json +306 -0
  1044. package/lib/host-packages/cursor/openplanr/rules/planr-plan/schemas/design-review-context.schema.json +191 -0
  1045. package/lib/host-packages/cursor/openplanr/rules/planr-plan/schemas/design-review-handoff.schema.json +407 -0
  1046. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/design.mjs +17323 -0
  1047. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/planning-ids.mjs +120 -0
  1048. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/notices/entities.txt +13 -0
  1049. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/notices/parse5.txt +21 -0
  1050. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  1051. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  1052. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  1053. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  1054. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  1055. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  1056. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  1057. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/package.json +115 -0
  1058. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  1059. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  1060. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  1061. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  1062. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  1063. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  1064. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  1065. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  1066. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  1067. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  1068. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  1069. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  1070. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  1071. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  1072. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  1073. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  1074. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  1075. package/lib/host-packages/cursor/openplanr/rules/planr-plan-review.mdc +38 -0
  1076. package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +105 -0
  1077. package/lib/host-packages/cursor/openplanr/rules/planr-release/assets/changelog-template.md +18 -0
  1078. package/lib/host-packages/cursor/openplanr/rules/planr-release/assets/profile-template.md +45 -0
  1079. package/lib/host-packages/cursor/openplanr/rules/planr-release/references/cadence.md +92 -0
  1080. package/lib/host-packages/cursor/openplanr/rules/planr-release/references/release-notes.md +127 -0
  1081. package/lib/host-packages/cursor/openplanr/rules/planr-release/references/schemes.md +103 -0
  1082. package/lib/host-packages/cursor/openplanr/rules/planr-release/scripts/collect_changes.sh +85 -0
  1083. package/lib/host-packages/cursor/openplanr/rules/planr-release.mdc +179 -0
  1084. package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/result-contract.md +14 -0
  1085. package/lib/host-packages/cursor/openplanr/rules/planr-ship/scripts/discover-verification.mjs +107 -0
  1086. package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +79 -0
  1087. package/lib/host-packages/cursor/openplanr/rules/planr-spec/references/specification-contract.md +32 -0
  1088. package/lib/host-packages/cursor/openplanr/rules/planr-spec.mdc +52 -0
  1089. package/lib/host-packages/cursor/openplanr/rules/planr-status.mdc +20 -0
  1090. package/lib/host-packages/cursor/openplanr/rules/planr-sync/scripts/sync.mjs +230 -0
  1091. package/lib/host-packages/cursor/openplanr/rules/planr-sync.mdc +29 -0
  1092. package/lib/host-packages/openai/.claude-plugin/marketplace.json +19 -0
  1093. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +10 -0
  1094. package/lib/host-packages/openai/openplanr/.openplanr-content.json +1139 -0
  1095. package/lib/host-packages/openai/openplanr/skills/artifact/SKILL.md +54 -0
  1096. package/lib/host-packages/openai/openplanr/skills/artifact/agents/openai.yaml +6 -0
  1097. package/lib/host-packages/openai/openplanr/skills/artifact/openplanr.skill.json +48 -0
  1098. package/lib/host-packages/openai/openplanr/skills/artifact/references/company-review.md +18 -0
  1099. package/lib/host-packages/openai/openplanr/skills/artifact/references/design-sharing.md +51 -0
  1100. package/lib/host-packages/openai/openplanr/skills/browser-qa/SKILL.md +34 -0
  1101. package/lib/host-packages/openai/openplanr/skills/browser-qa/agents/openai.yaml +6 -0
  1102. package/lib/host-packages/openai/openplanr/skills/browser-qa/openplanr.skill.json +26 -0
  1103. package/lib/host-packages/openai/openplanr/skills/ceo-review/SKILL.md +47 -0
  1104. package/lib/host-packages/openai/openplanr/skills/ceo-review/agents/openai.yaml +6 -0
  1105. package/lib/host-packages/openai/openplanr/skills/ceo-review/openplanr.skill.json +81 -0
  1106. package/lib/host-packages/openai/openplanr/skills/ceo-review/references/operate-advisor-contract.md +111 -0
  1107. package/lib/host-packages/openai/openplanr/skills/ceo-review/scripts/errors.mjs +8 -0
  1108. package/lib/host-packages/openai/openplanr/skills/ceo-review/scripts/operate-review-contract.mjs +438 -0
  1109. package/lib/host-packages/openai/openplanr/skills/ceo-review/scripts/operate-review-note.mjs +595 -0
  1110. package/lib/host-packages/openai/openplanr/skills/ceo-review/scripts/validate-note.mjs +31 -0
  1111. package/lib/host-packages/openai/openplanr/skills/chair-review/SKILL.md +101 -0
  1112. package/lib/host-packages/openai/openplanr/skills/chair-review/agents/openai.yaml +6 -0
  1113. package/lib/host-packages/openai/openplanr/skills/chair-review/openplanr.skill.json +70 -0
  1114. package/lib/host-packages/openai/openplanr/skills/chair-review/scripts/errors.mjs +8 -0
  1115. package/lib/host-packages/openai/openplanr/skills/chair-review/scripts/operate-review-contract.mjs +438 -0
  1116. package/lib/host-packages/openai/openplanr/skills/chair-review/scripts/operate-review-note.mjs +595 -0
  1117. package/lib/host-packages/openai/openplanr/skills/chair-review/scripts/validate-note.mjs +31 -0
  1118. package/lib/host-packages/openai/openplanr/skills/challenger-review/SKILL.md +86 -0
  1119. package/lib/host-packages/openai/openplanr/skills/challenger-review/agents/openai.yaml +6 -0
  1120. package/lib/host-packages/openai/openplanr/skills/challenger-review/openplanr.skill.json +70 -0
  1121. package/lib/host-packages/openai/openplanr/skills/challenger-review/scripts/errors.mjs +8 -0
  1122. package/lib/host-packages/openai/openplanr/skills/challenger-review/scripts/operate-review-contract.mjs +438 -0
  1123. package/lib/host-packages/openai/openplanr/skills/challenger-review/scripts/operate-review-note.mjs +595 -0
  1124. package/lib/host-packages/openai/openplanr/skills/challenger-review/scripts/validate-note.mjs +31 -0
  1125. package/lib/host-packages/openai/openplanr/skills/cmo-review/SKILL.md +46 -0
  1126. package/lib/host-packages/openai/openplanr/skills/cmo-review/agents/openai.yaml +6 -0
  1127. package/lib/host-packages/openai/openplanr/skills/cmo-review/openplanr.skill.json +81 -0
  1128. package/lib/host-packages/openai/openplanr/skills/cmo-review/references/operate-advisor-contract.md +111 -0
  1129. package/lib/host-packages/openai/openplanr/skills/cmo-review/scripts/errors.mjs +8 -0
  1130. package/lib/host-packages/openai/openplanr/skills/cmo-review/scripts/operate-review-contract.mjs +438 -0
  1131. package/lib/host-packages/openai/openplanr/skills/cmo-review/scripts/operate-review-note.mjs +595 -0
  1132. package/lib/host-packages/openai/openplanr/skills/cmo-review/scripts/validate-note.mjs +31 -0
  1133. package/lib/host-packages/openai/openplanr/skills/coo-review/SKILL.md +45 -0
  1134. package/lib/host-packages/openai/openplanr/skills/coo-review/agents/openai.yaml +6 -0
  1135. package/lib/host-packages/openai/openplanr/skills/coo-review/openplanr.skill.json +81 -0
  1136. package/lib/host-packages/openai/openplanr/skills/coo-review/references/operate-advisor-contract.md +111 -0
  1137. package/lib/host-packages/openai/openplanr/skills/coo-review/scripts/errors.mjs +8 -0
  1138. package/lib/host-packages/openai/openplanr/skills/coo-review/scripts/operate-review-contract.mjs +438 -0
  1139. package/lib/host-packages/openai/openplanr/skills/coo-review/scripts/operate-review-note.mjs +595 -0
  1140. package/lib/host-packages/openai/openplanr/skills/coo-review/scripts/validate-note.mjs +31 -0
  1141. package/lib/host-packages/openai/openplanr/skills/cpo-review/SKILL.md +48 -0
  1142. package/lib/host-packages/openai/openplanr/skills/cpo-review/agents/openai.yaml +6 -0
  1143. package/lib/host-packages/openai/openplanr/skills/cpo-review/openplanr.skill.json +81 -0
  1144. package/lib/host-packages/openai/openplanr/skills/cpo-review/references/operate-advisor-contract.md +111 -0
  1145. package/lib/host-packages/openai/openplanr/skills/cpo-review/scripts/errors.mjs +8 -0
  1146. package/lib/host-packages/openai/openplanr/skills/cpo-review/scripts/operate-review-contract.mjs +438 -0
  1147. package/lib/host-packages/openai/openplanr/skills/cpo-review/scripts/operate-review-note.mjs +595 -0
  1148. package/lib/host-packages/openai/openplanr/skills/cpo-review/scripts/validate-note.mjs +31 -0
  1149. package/lib/host-packages/openai/openplanr/skills/cto-review/SKILL.md +47 -0
  1150. package/lib/host-packages/openai/openplanr/skills/cto-review/agents/openai.yaml +6 -0
  1151. package/lib/host-packages/openai/openplanr/skills/cto-review/openplanr.skill.json +81 -0
  1152. package/lib/host-packages/openai/openplanr/skills/cto-review/references/operate-advisor-contract.md +111 -0
  1153. package/lib/host-packages/openai/openplanr/skills/cto-review/scripts/errors.mjs +8 -0
  1154. package/lib/host-packages/openai/openplanr/skills/cto-review/scripts/operate-review-contract.mjs +438 -0
  1155. package/lib/host-packages/openai/openplanr/skills/cto-review/scripts/operate-review-note.mjs +595 -0
  1156. package/lib/host-packages/openai/openplanr/skills/cto-review/scripts/validate-note.mjs +31 -0
  1157. package/lib/host-packages/openai/openplanr/skills/dashboard/SKILL.md +20 -0
  1158. package/lib/host-packages/openai/openplanr/skills/dashboard/agents/openai.yaml +6 -0
  1159. package/lib/host-packages/openai/openplanr/skills/dashboard/openplanr.skill.json +26 -0
  1160. package/lib/host-packages/openai/openplanr/skills/design/SKILL.md +73 -0
  1161. package/lib/host-packages/openai/openplanr/skills/design/agents/openai.yaml +6 -0
  1162. package/lib/host-packages/openai/openplanr/skills/design/openplanr.skill.json +466 -0
  1163. package/lib/host-packages/openai/openplanr/skills/design/references/craft.md +68 -0
  1164. package/lib/host-packages/openai/openplanr/skills/design/references/design-spec-template.md +88 -0
  1165. package/lib/host-packages/openai/openplanr/skills/design/references/design-system.md +33 -0
  1166. package/lib/host-packages/openai/openplanr/skills/design/references/discovery.md +53 -0
  1167. package/lib/host-packages/openai/openplanr/skills/design/references/generation.md +105 -0
  1168. package/lib/host-packages/openai/openplanr/skills/design/references/handoff.md +47 -0
  1169. package/lib/host-packages/openai/openplanr/skills/design/references/review.md +88 -0
  1170. package/lib/host-packages/openai/openplanr/skills/design/references/team-review.md +131 -0
  1171. package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +93 -0
  1172. package/lib/host-packages/openai/openplanr/skills/design/schemas/design-document.schema.json +306 -0
  1173. package/lib/host-packages/openai/openplanr/skills/design/schemas/design-review-context.schema.json +191 -0
  1174. package/lib/host-packages/openai/openplanr/skills/design/schemas/design-review-handoff.schema.json +407 -0
  1175. package/lib/host-packages/openai/openplanr/skills/design/scripts/design.mjs +17323 -0
  1176. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/notices/entities.txt +13 -0
  1177. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/notices/parse5.txt +21 -0
  1178. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  1179. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  1180. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  1181. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  1182. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  1183. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  1184. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  1185. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/package.json +115 -0
  1186. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  1187. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  1188. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  1189. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  1190. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  1191. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  1192. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  1193. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  1194. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  1195. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  1196. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  1197. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  1198. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  1199. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  1200. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  1201. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  1202. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  1203. package/lib/host-packages/openai/openplanr/skills/design-loop/SKILL.md +58 -0
  1204. package/lib/host-packages/openai/openplanr/skills/design-loop/agents/openai.yaml +6 -0
  1205. package/lib/host-packages/openai/openplanr/skills/design-loop/openplanr.skill.json +466 -0
  1206. package/lib/host-packages/openai/openplanr/skills/design-loop/references/craft.md +68 -0
  1207. package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-spec-template.md +88 -0
  1208. package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-system.md +33 -0
  1209. package/lib/host-packages/openai/openplanr/skills/design-loop/references/discovery.md +53 -0
  1210. package/lib/host-packages/openai/openplanr/skills/design-loop/references/generation.md +105 -0
  1211. package/lib/host-packages/openai/openplanr/skills/design-loop/references/handoff.md +47 -0
  1212. package/lib/host-packages/openai/openplanr/skills/design-loop/references/review.md +88 -0
  1213. package/lib/host-packages/openai/openplanr/skills/design-loop/references/team-review.md +131 -0
  1214. package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +93 -0
  1215. package/lib/host-packages/openai/openplanr/skills/design-loop/schemas/design-document.schema.json +306 -0
  1216. package/lib/host-packages/openai/openplanr/skills/design-loop/schemas/design-review-context.schema.json +191 -0
  1217. package/lib/host-packages/openai/openplanr/skills/design-loop/schemas/design-review-handoff.schema.json +407 -0
  1218. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/design.mjs +17323 -0
  1219. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/notices/entities.txt +13 -0
  1220. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/notices/parse5.txt +21 -0
  1221. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  1222. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  1223. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  1224. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  1225. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  1226. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  1227. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  1228. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/package.json +115 -0
  1229. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  1230. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  1231. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  1232. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  1233. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  1234. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  1235. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  1236. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  1237. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  1238. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  1239. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  1240. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  1241. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  1242. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  1243. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  1244. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  1245. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  1246. package/lib/host-packages/openai/openplanr/skills/design-review/SKILL.md +54 -0
  1247. package/lib/host-packages/openai/openplanr/skills/design-review/agents/openai.yaml +6 -0
  1248. package/lib/host-packages/openai/openplanr/skills/design-review/openplanr.skill.json +466 -0
  1249. package/lib/host-packages/openai/openplanr/skills/design-review/references/craft.md +68 -0
  1250. package/lib/host-packages/openai/openplanr/skills/design-review/references/design-spec-template.md +88 -0
  1251. package/lib/host-packages/openai/openplanr/skills/design-review/references/design-system.md +33 -0
  1252. package/lib/host-packages/openai/openplanr/skills/design-review/references/discovery.md +53 -0
  1253. package/lib/host-packages/openai/openplanr/skills/design-review/references/generation.md +105 -0
  1254. package/lib/host-packages/openai/openplanr/skills/design-review/references/handoff.md +47 -0
  1255. package/lib/host-packages/openai/openplanr/skills/design-review/references/review.md +88 -0
  1256. package/lib/host-packages/openai/openplanr/skills/design-review/references/team-review.md +131 -0
  1257. package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +93 -0
  1258. package/lib/host-packages/openai/openplanr/skills/design-review/schemas/design-document.schema.json +306 -0
  1259. package/lib/host-packages/openai/openplanr/skills/design-review/schemas/design-review-context.schema.json +191 -0
  1260. package/lib/host-packages/openai/openplanr/skills/design-review/schemas/design-review-handoff.schema.json +407 -0
  1261. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/design.mjs +17323 -0
  1262. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/notices/entities.txt +13 -0
  1263. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/notices/parse5.txt +21 -0
  1264. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  1265. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  1266. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  1267. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  1268. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  1269. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  1270. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  1271. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/package.json +115 -0
  1272. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  1273. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  1274. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  1275. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  1276. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  1277. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  1278. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  1279. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  1280. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  1281. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  1282. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  1283. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  1284. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  1285. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  1286. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  1287. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  1288. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  1289. package/lib/host-packages/openai/openplanr/skills/diagram/SKILL.md +65 -0
  1290. package/lib/host-packages/openai/openplanr/skills/diagram/agents/openai.yaml +6 -0
  1291. package/lib/host-packages/openai/openplanr/skills/diagram/openplanr.skill.json +59 -0
  1292. package/lib/host-packages/openai/openplanr/skills/diagram/references/diagram-document.md +86 -0
  1293. package/lib/host-packages/openai/openplanr/skills/diagram/references/diagram-fidelity.md +19 -0
  1294. package/lib/host-packages/openai/openplanr/skills/diagram/references/diagram-intent-to-ir.md +22 -0
  1295. package/lib/host-packages/openai/openplanr/skills/doctor/SKILL.md +40 -0
  1296. package/lib/host-packages/openai/openplanr/skills/doctor/agents/openai.yaml +6 -0
  1297. package/lib/host-packages/openai/openplanr/skills/doctor/openplanr.skill.json +37 -0
  1298. package/lib/host-packages/openai/openplanr/skills/doctor/references/upgrade.md +106 -0
  1299. package/lib/host-packages/openai/openplanr/skills/investigate/SKILL.md +31 -0
  1300. package/lib/host-packages/openai/openplanr/skills/investigate/agents/openai.yaml +6 -0
  1301. package/lib/host-packages/openai/openplanr/skills/investigate/openplanr.skill.json +26 -0
  1302. package/lib/host-packages/openai/openplanr/skills/land/SKILL.md +33 -0
  1303. package/lib/host-packages/openai/openplanr/skills/land/agents/openai.yaml +6 -0
  1304. package/lib/host-packages/openai/openplanr/skills/land/openplanr.skill.json +26 -0
  1305. package/lib/host-packages/openai/openplanr/skills/operate/SKILL.md +181 -0
  1306. package/lib/host-packages/openai/openplanr/skills/operate/agents/openai.yaml +6 -0
  1307. package/lib/host-packages/openai/openplanr/skills/operate/openplanr.skill.json +70 -0
  1308. package/lib/host-packages/openai/openplanr/skills/operate/scripts/errors.mjs +8 -0
  1309. package/lib/host-packages/openai/openplanr/skills/operate/scripts/operate-review-contract.mjs +438 -0
  1310. package/lib/host-packages/openai/openplanr/skills/operate/scripts/operate-review-note.mjs +595 -0
  1311. package/lib/host-packages/openai/openplanr/skills/operate/scripts/validate-note.mjs +31 -0
  1312. package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +106 -0
  1313. package/lib/host-packages/openai/openplanr/skills/plan/agents/openai.yaml +6 -0
  1314. package/lib/host-packages/openai/openplanr/skills/plan/openplanr.skill.json +389 -0
  1315. package/lib/host-packages/openai/openplanr/skills/plan/references/artifact-contract.md +39 -0
  1316. package/lib/host-packages/openai/openplanr/skills/plan/schemas/design-document.schema.json +306 -0
  1317. package/lib/host-packages/openai/openplanr/skills/plan/schemas/design-review-context.schema.json +191 -0
  1318. package/lib/host-packages/openai/openplanr/skills/plan/schemas/design-review-handoff.schema.json +407 -0
  1319. package/lib/host-packages/openai/openplanr/skills/plan/scripts/design.mjs +17323 -0
  1320. package/lib/host-packages/openai/openplanr/skills/plan/scripts/planning-ids.mjs +120 -0
  1321. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/notices/entities.txt +13 -0
  1322. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/notices/parse5.txt +21 -0
  1323. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +3994 -0
  1324. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/enhancements.css +378 -0
  1325. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/enhancements.js +805 -0
  1326. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/share.css +1 -0
  1327. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/share.js +132 -0
  1328. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/studio.css +1103 -0
  1329. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/design/templates/studio/studio.js +1775 -0
  1330. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/package.json +115 -0
  1331. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/registry/artifact-theme.json +60 -0
  1332. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.0.0/design-manifest.schema.json +90 -0
  1333. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-envelope.schema.json +142 -0
  1334. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +49 -0
  1335. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-review.schema.json +97 -0
  1336. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-theme.schema.json +139 -0
  1337. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-bundle.schema.json +584 -0
  1338. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-context.schema.json +191 -0
  1339. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-handoff.schema.json +407 -0
  1340. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.10.0/design-review-metadata-payload.schema.json +106 -0
  1341. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.11.0/design-review-metadata-payload.schema.json +107 -0
  1342. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-document.schema.json +306 -0
  1343. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-bundle.schema.json +346 -0
  1344. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +108 -0
  1345. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +170 -0
  1346. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +97 -0
  1347. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +56 -0
  1348. package/lib/host-packages/openai/openplanr/skills/plan-review/SKILL.md +39 -0
  1349. package/lib/host-packages/openai/openplanr/skills/plan-review/agents/openai.yaml +6 -0
  1350. package/lib/host-packages/openai/openplanr/skills/plan-review/openplanr.skill.json +26 -0
  1351. package/lib/host-packages/openai/openplanr/skills/release/SKILL.md +180 -0
  1352. package/lib/host-packages/openai/openplanr/skills/release/agents/openai.yaml +6 -0
  1353. package/lib/host-packages/openai/openplanr/skills/release/assets/changelog-template.md +18 -0
  1354. package/lib/host-packages/openai/openplanr/skills/release/assets/profile-template.md +45 -0
  1355. package/lib/host-packages/openai/openplanr/skills/release/openplanr.skill.json +92 -0
  1356. package/lib/host-packages/openai/openplanr/skills/release/references/cadence.md +92 -0
  1357. package/lib/host-packages/openai/openplanr/skills/release/references/release-notes.md +127 -0
  1358. package/lib/host-packages/openai/openplanr/skills/release/references/schemes.md +103 -0
  1359. package/lib/host-packages/openai/openplanr/skills/release/scripts/collect_changes.sh +85 -0
  1360. package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +80 -0
  1361. package/lib/host-packages/openai/openplanr/skills/ship/agents/openai.yaml +6 -0
  1362. package/lib/host-packages/openai/openplanr/skills/ship/openplanr.skill.json +48 -0
  1363. package/lib/host-packages/openai/openplanr/skills/ship/references/result-contract.md +14 -0
  1364. package/lib/host-packages/openai/openplanr/skills/ship/scripts/discover-verification.mjs +107 -0
  1365. package/lib/host-packages/openai/openplanr/skills/spec/SKILL.md +53 -0
  1366. package/lib/host-packages/openai/openplanr/skills/spec/agents/openai.yaml +6 -0
  1367. package/lib/host-packages/openai/openplanr/skills/spec/openplanr.skill.json +37 -0
  1368. package/lib/host-packages/openai/openplanr/skills/spec/references/specification-contract.md +32 -0
  1369. package/lib/host-packages/openai/openplanr/skills/status/SKILL.md +21 -0
  1370. package/lib/host-packages/openai/openplanr/skills/status/agents/openai.yaml +6 -0
  1371. package/lib/host-packages/openai/openplanr/skills/status/openplanr.skill.json +26 -0
  1372. package/lib/host-packages/openai/openplanr/skills/sync/SKILL.md +30 -0
  1373. package/lib/host-packages/openai/openplanr/skills/sync/agents/openai.yaml +6 -0
  1374. package/lib/host-packages/openai/openplanr/skills/sync/openplanr.skill.json +37 -0
  1375. package/lib/host-packages/openai/openplanr/skills/sync/scripts/sync.mjs +230 -0
  1376. package/lib/integrations.d.mts +43 -0
  1377. package/lib/integrations.mjs +230 -0
  1378. package/lib/skill-runtime/errors.mjs +8 -0
  1379. package/lib/skill-runtime/operate-review-contract.mjs +438 -0
  1380. package/lib/skill-runtime/operate-review-note.mjs +595 -0
  1381. package/package.json +56 -18
  1382. package/dist/ai/codebase/context-builder.d.ts +0 -50
  1383. package/dist/ai/codebase/context-builder.d.ts.map +0 -1
  1384. package/dist/ai/codebase/context-builder.js +0 -281
  1385. package/dist/ai/codebase/context-builder.js.map +0 -1
  1386. package/dist/ai/codebase/file-reader.d.ts +0 -22
  1387. package/dist/ai/codebase/file-reader.d.ts.map +0 -1
  1388. package/dist/ai/codebase/file-reader.js +0 -144
  1389. package/dist/ai/codebase/file-reader.js.map +0 -1
  1390. package/dist/ai/codebase/index.d.ts +0 -7
  1391. package/dist/ai/codebase/index.d.ts.map +0 -1
  1392. package/dist/ai/codebase/index.js +0 -7
  1393. package/dist/ai/codebase/index.js.map +0 -1
  1394. package/dist/ai/codebase/pattern-rules.d.ts +0 -28
  1395. package/dist/ai/codebase/pattern-rules.d.ts.map +0 -1
  1396. package/dist/ai/codebase/pattern-rules.js +0 -186
  1397. package/dist/ai/codebase/pattern-rules.js.map +0 -1
  1398. package/dist/ai/codebase/rules-reader.d.ts +0 -14
  1399. package/dist/ai/codebase/rules-reader.d.ts.map +0 -1
  1400. package/dist/ai/codebase/rules-reader.js +0 -25
  1401. package/dist/ai/codebase/rules-reader.js.map +0 -1
  1402. package/dist/ai/codebase/stack-detector.d.ts +0 -18
  1403. package/dist/ai/codebase/stack-detector.d.ts.map +0 -1
  1404. package/dist/ai/codebase/stack-detector.js +0 -173
  1405. package/dist/ai/codebase/stack-detector.js.map +0 -1
  1406. package/dist/ai/codebase/tree-generator.d.ts +0 -8
  1407. package/dist/ai/codebase/tree-generator.d.ts.map +0 -1
  1408. package/dist/ai/codebase/tree-generator.js +0 -84
  1409. package/dist/ai/codebase/tree-generator.js.map +0 -1
  1410. package/dist/ai/errors.d.ts +0 -22
  1411. package/dist/ai/errors.d.ts.map +0 -1
  1412. package/dist/ai/errors.js +0 -72
  1413. package/dist/ai/errors.js.map +0 -1
  1414. package/dist/ai/index.d.ts +0 -11
  1415. package/dist/ai/index.d.ts.map +0 -1
  1416. package/dist/ai/index.js +0 -10
  1417. package/dist/ai/index.js.map +0 -1
  1418. package/dist/ai/prompts/prompt-builder.d.ts +0 -134
  1419. package/dist/ai/prompts/prompt-builder.d.ts.map +0 -1
  1420. package/dist/ai/prompts/prompt-builder.js +0 -295
  1421. package/dist/ai/prompts/prompt-builder.js.map +0 -1
  1422. package/dist/ai/prompts/system-prompts.d.ts +0 -41
  1423. package/dist/ai/prompts/system-prompts.d.ts.map +0 -1
  1424. package/dist/ai/prompts/system-prompts.js +0 -512
  1425. package/dist/ai/prompts/system-prompts.js.map +0 -1
  1426. package/dist/ai/provider-factory.d.ts +0 -10
  1427. package/dist/ai/provider-factory.d.ts.map +0 -1
  1428. package/dist/ai/provider-factory.js +0 -49
  1429. package/dist/ai/provider-factory.js.map +0 -1
  1430. package/dist/ai/providers/anthropic-provider.d.ts +0 -24
  1431. package/dist/ai/providers/anthropic-provider.d.ts.map +0 -1
  1432. package/dist/ai/providers/anthropic-provider.js +0 -97
  1433. package/dist/ai/providers/anthropic-provider.js.map +0 -1
  1434. package/dist/ai/providers/ollama-provider.d.ts +0 -13
  1435. package/dist/ai/providers/ollama-provider.d.ts.map +0 -1
  1436. package/dist/ai/providers/ollama-provider.js +0 -16
  1437. package/dist/ai/providers/ollama-provider.js.map +0 -1
  1438. package/dist/ai/providers/openai-provider.d.ts +0 -19
  1439. package/dist/ai/providers/openai-provider.d.ts.map +0 -1
  1440. package/dist/ai/providers/openai-provider.js +0 -84
  1441. package/dist/ai/providers/openai-provider.js.map +0 -1
  1442. package/dist/ai/schemas/ai-response-schemas.d.ts +0 -340
  1443. package/dist/ai/schemas/ai-response-schemas.d.ts.map +0 -1
  1444. package/dist/ai/schemas/ai-response-schemas.js +0 -278
  1445. package/dist/ai/schemas/ai-response-schemas.js.map +0 -1
  1446. package/dist/ai/types.d.ts +0 -76
  1447. package/dist/ai/types.d.ts.map +0 -1
  1448. package/dist/ai/types.js +0 -49
  1449. package/dist/ai/types.js.map +0 -1
  1450. package/dist/ai/validation/index.d.ts +0 -2
  1451. package/dist/ai/validation/index.d.ts.map +0 -1
  1452. package/dist/ai/validation/index.js +0 -2
  1453. package/dist/ai/validation/index.js.map +0 -1
  1454. package/dist/ai/validation/task-validator.d.ts +0 -37
  1455. package/dist/ai/validation/task-validator.d.ts.map +0 -1
  1456. package/dist/ai/validation/task-validator.js +0 -81
  1457. package/dist/ai/validation/task-validator.js.map +0 -1
  1458. package/dist/cli/commands/config.d.ts +0 -8
  1459. package/dist/cli/commands/config.d.ts.map +0 -1
  1460. package/dist/cli/commands/config.js +0 -224
  1461. package/dist/cli/commands/config.js.map +0 -1
  1462. package/dist/cli/commands/estimate.d.ts +0 -3
  1463. package/dist/cli/commands/estimate.d.ts.map +0 -1
  1464. package/dist/cli/commands/estimate.js +0 -368
  1465. package/dist/cli/commands/estimate.js.map +0 -1
  1466. package/dist/cli/commands/init.d.ts +0 -9
  1467. package/dist/cli/commands/init.d.ts.map +0 -1
  1468. package/dist/cli/commands/init.js +0 -166
  1469. package/dist/cli/commands/init.js.map +0 -1
  1470. package/dist/cli/commands/pipeline.d.ts +0 -3
  1471. package/dist/cli/commands/pipeline.d.ts.map +0 -1
  1472. package/dist/cli/commands/pipeline.js +0 -59
  1473. package/dist/cli/commands/pipeline.js.map +0 -1
  1474. package/dist/cli/commands/plan.d.ts +0 -15
  1475. package/dist/cli/commands/plan.d.ts.map +0 -1
  1476. package/dist/cli/commands/plan.js +0 -444
  1477. package/dist/cli/commands/plan.js.map +0 -1
  1478. package/dist/cli/commands/refine.d.ts +0 -10
  1479. package/dist/cli/commands/refine.d.ts.map +0 -1
  1480. package/dist/cli/commands/refine.js +0 -226
  1481. package/dist/cli/commands/refine.js.map +0 -1
  1482. package/dist/cli/commands/revise.d.ts +0 -24
  1483. package/dist/cli/commands/revise.d.ts.map +0 -1
  1484. package/dist/cli/commands/revise.js +0 -572
  1485. package/dist/cli/commands/revise.js.map +0 -1
  1486. package/dist/cli/helpers/task-creation.d.ts +0 -89
  1487. package/dist/cli/helpers/task-creation.d.ts.map +0 -1
  1488. package/dist/cli/helpers/task-creation.js +0 -139
  1489. package/dist/cli/helpers/task-creation.js.map +0 -1
  1490. package/dist/services/ai-service.d.ts +0 -77
  1491. package/dist/services/ai-service.d.ts.map +0 -1
  1492. package/dist/services/ai-service.js +0 -241
  1493. package/dist/services/ai-service.js.map +0 -1
  1494. package/dist/services/artifact-gathering.d.ts +0 -55
  1495. package/dist/services/artifact-gathering.d.ts.map +0 -1
  1496. package/dist/services/artifact-gathering.js +0 -147
  1497. package/dist/services/artifact-gathering.js.map +0 -1
  1498. package/dist/services/operate/advisors.d.ts +0 -625
  1499. package/dist/services/operate/advisors.d.ts.map +0 -1
  1500. package/dist/services/operate/advisors.js +0 -1545
  1501. package/dist/services/operate/advisors.js.map +0 -1
  1502. package/dist/services/operate/artifact-route-generation.d.ts +0 -111
  1503. package/dist/services/operate/artifact-route-generation.d.ts.map +0 -1
  1504. package/dist/services/operate/artifact-route-generation.js +0 -460
  1505. package/dist/services/operate/artifact-route-generation.js.map +0 -1
  1506. package/dist/services/operate/artifacts.d.ts +0 -66
  1507. package/dist/services/operate/artifacts.d.ts.map +0 -1
  1508. package/dist/services/operate/artifacts.js +0 -336
  1509. package/dist/services/operate/artifacts.js.map +0 -1
  1510. package/dist/services/operate/cadence.d.ts +0 -50
  1511. package/dist/services/operate/cadence.d.ts.map +0 -1
  1512. package/dist/services/operate/cadence.js +0 -56
  1513. package/dist/services/operate/cadence.js.map +0 -1
  1514. package/dist/services/operate/canonical.d.ts +0 -18
  1515. package/dist/services/operate/canonical.d.ts.map +0 -1
  1516. package/dist/services/operate/canonical.js +0 -157
  1517. package/dist/services/operate/canonical.js.map +0 -1
  1518. package/dist/services/operate/citation-resolution.d.ts +0 -161
  1519. package/dist/services/operate/citation-resolution.d.ts.map +0 -1
  1520. package/dist/services/operate/citation-resolution.js +0 -593
  1521. package/dist/services/operate/citation-resolution.js.map +0 -1
  1522. package/dist/services/operate/completion.d.ts +0 -80
  1523. package/dist/services/operate/completion.d.ts.map +0 -1
  1524. package/dist/services/operate/completion.js +0 -279
  1525. package/dist/services/operate/completion.js.map +0 -1
  1526. package/dist/services/operate/config.d.ts +0 -154
  1527. package/dist/services/operate/config.d.ts.map +0 -1
  1528. package/dist/services/operate/config.js +0 -791
  1529. package/dist/services/operate/config.js.map +0 -1
  1530. package/dist/services/operate/consolidation.d.ts +0 -18
  1531. package/dist/services/operate/consolidation.d.ts.map +0 -1
  1532. package/dist/services/operate/consolidation.js +0 -539
  1533. package/dist/services/operate/consolidation.js.map +0 -1
  1534. package/dist/services/operate/context-research.d.ts +0 -84
  1535. package/dist/services/operate/context-research.d.ts.map +0 -1
  1536. package/dist/services/operate/context-research.js +0 -448
  1537. package/dist/services/operate/context-research.js.map +0 -1
  1538. package/dist/services/operate/decision-brief.d.ts +0 -237
  1539. package/dist/services/operate/decision-brief.d.ts.map +0 -1
  1540. package/dist/services/operate/decision-brief.js +0 -368
  1541. package/dist/services/operate/decision-brief.js.map +0 -1
  1542. package/dist/services/operate/doctor.d.ts +0 -85
  1543. package/dist/services/operate/doctor.d.ts.map +0 -1
  1544. package/dist/services/operate/doctor.js +0 -1070
  1545. package/dist/services/operate/doctor.js.map +0 -1
  1546. package/dist/services/operate/drafts.d.ts +0 -48
  1547. package/dist/services/operate/drafts.d.ts.map +0 -1
  1548. package/dist/services/operate/drafts.js +0 -398
  1549. package/dist/services/operate/drafts.js.map +0 -1
  1550. package/dist/services/operate/engine.d.ts +0 -151
  1551. package/dist/services/operate/engine.d.ts.map +0 -1
  1552. package/dist/services/operate/engine.js +0 -1896
  1553. package/dist/services/operate/engine.js.map +0 -1
  1554. package/dist/services/operate/event-store.d.ts +0 -113
  1555. package/dist/services/operate/event-store.d.ts.map +0 -1
  1556. package/dist/services/operate/event-store.js +0 -384
  1557. package/dist/services/operate/event-store.js.map +0 -1
  1558. package/dist/services/operate/evidence-cache.d.ts +0 -41
  1559. package/dist/services/operate/evidence-cache.d.ts.map +0 -1
  1560. package/dist/services/operate/evidence-cache.js +0 -193
  1561. package/dist/services/operate/evidence-cache.js.map +0 -1
  1562. package/dist/services/operate/evidence-import.d.ts +0 -40
  1563. package/dist/services/operate/evidence-import.d.ts.map +0 -1
  1564. package/dist/services/operate/evidence-import.js +0 -340
  1565. package/dist/services/operate/evidence-import.js.map +0 -1
  1566. package/dist/services/operate/evidence.d.ts +0 -21
  1567. package/dist/services/operate/evidence.d.ts.map +0 -1
  1568. package/dist/services/operate/evidence.js +0 -20
  1569. package/dist/services/operate/evidence.js.map +0 -1
  1570. package/dist/services/operate/ids.d.ts +0 -7
  1571. package/dist/services/operate/ids.d.ts.map +0 -1
  1572. package/dist/services/operate/ids.js +0 -23
  1573. package/dist/services/operate/ids.js.map +0 -1
  1574. package/dist/services/operate/index.d.ts +0 -16
  1575. package/dist/services/operate/index.d.ts.map +0 -1
  1576. package/dist/services/operate/index.js +0 -1864
  1577. package/dist/services/operate/index.js.map +0 -1
  1578. package/dist/services/operate/integrity.d.ts +0 -81
  1579. package/dist/services/operate/integrity.d.ts.map +0 -1
  1580. package/dist/services/operate/integrity.js +0 -152
  1581. package/dist/services/operate/integrity.js.map +0 -1
  1582. package/dist/services/operate/interaction/action-service.d.ts +0 -34
  1583. package/dist/services/operate/interaction/action-service.d.ts.map +0 -1
  1584. package/dist/services/operate/interaction/action-service.js +0 -103
  1585. package/dist/services/operate/interaction/action-service.js.map +0 -1
  1586. package/dist/services/operate/interaction/answer-service.d.ts +0 -40
  1587. package/dist/services/operate/interaction/answer-service.d.ts.map +0 -1
  1588. package/dist/services/operate/interaction/answer-service.js +0 -317
  1589. package/dist/services/operate/interaction/answer-service.js.map +0 -1
  1590. package/dist/services/operate/interaction/charter-suggestions.d.ts +0 -29
  1591. package/dist/services/operate/interaction/charter-suggestions.d.ts.map +0 -1
  1592. package/dist/services/operate/interaction/charter-suggestions.js +0 -104
  1593. package/dist/services/operate/interaction/charter-suggestions.js.map +0 -1
  1594. package/dist/services/operate/interaction/confirmation-service.d.ts +0 -30
  1595. package/dist/services/operate/interaction/confirmation-service.d.ts.map +0 -1
  1596. package/dist/services/operate/interaction/confirmation-service.js +0 -78
  1597. package/dist/services/operate/interaction/confirmation-service.js.map +0 -1
  1598. package/dist/services/operate/interaction/initialization-replay.d.ts +0 -9
  1599. package/dist/services/operate/interaction/initialization-replay.d.ts.map +0 -1
  1600. package/dist/services/operate/interaction/initialization-replay.js +0 -64
  1601. package/dist/services/operate/interaction/initialization-replay.js.map +0 -1
  1602. package/dist/services/operate/interaction/question-engine.d.ts +0 -41
  1603. package/dist/services/operate/interaction/question-engine.d.ts.map +0 -1
  1604. package/dist/services/operate/interaction/question-engine.js +0 -434
  1605. package/dist/services/operate/interaction/question-engine.js.map +0 -1
  1606. package/dist/services/operate/interaction/question-registry.d.ts +0 -52
  1607. package/dist/services/operate/interaction/question-registry.d.ts.map +0 -1
  1608. package/dist/services/operate/interaction/question-registry.js +0 -305
  1609. package/dist/services/operate/interaction/question-registry.js.map +0 -1
  1610. package/dist/services/operate/interaction/session-service.d.ts +0 -55
  1611. package/dist/services/operate/interaction/session-service.d.ts.map +0 -1
  1612. package/dist/services/operate/interaction/session-service.js +0 -304
  1613. package/dist/services/operate/interaction/session-service.js.map +0 -1
  1614. package/dist/services/operate/interaction/terminal-renderer.d.ts +0 -19
  1615. package/dist/services/operate/interaction/terminal-renderer.d.ts.map +0 -1
  1616. package/dist/services/operate/interaction/terminal-renderer.js +0 -124
  1617. package/dist/services/operate/interaction/terminal-renderer.js.map +0 -1
  1618. package/dist/services/operate/journal.d.ts +0 -34
  1619. package/dist/services/operate/journal.d.ts.map +0 -1
  1620. package/dist/services/operate/journal.js +0 -235
  1621. package/dist/services/operate/journal.js.map +0 -1
  1622. package/dist/services/operate/legacy-import-service.d.ts +0 -58
  1623. package/dist/services/operate/legacy-import-service.d.ts.map +0 -1
  1624. package/dist/services/operate/legacy-import-service.js +0 -922
  1625. package/dist/services/operate/legacy-import-service.js.map +0 -1
  1626. package/dist/services/operate/lifecycle-driver.d.ts +0 -309
  1627. package/dist/services/operate/lifecycle-driver.d.ts.map +0 -1
  1628. package/dist/services/operate/lifecycle-driver.js +0 -434
  1629. package/dist/services/operate/lifecycle-driver.js.map +0 -1
  1630. package/dist/services/operate/lifecycle.d.ts +0 -96
  1631. package/dist/services/operate/lifecycle.d.ts.map +0 -1
  1632. package/dist/services/operate/lifecycle.js +0 -596
  1633. package/dist/services/operate/lifecycle.js.map +0 -1
  1634. package/dist/services/operate/lock-service.d.ts +0 -37
  1635. package/dist/services/operate/lock-service.d.ts.map +0 -1
  1636. package/dist/services/operate/lock-service.js +0 -215
  1637. package/dist/services/operate/lock-service.js.map +0 -1
  1638. package/dist/services/operate/maintenance.d.ts +0 -139
  1639. package/dist/services/operate/maintenance.d.ts.map +0 -1
  1640. package/dist/services/operate/maintenance.js +0 -2200
  1641. package/dist/services/operate/maintenance.js.map +0 -1
  1642. package/dist/services/operate/migration.d.ts +0 -68
  1643. package/dist/services/operate/migration.d.ts.map +0 -1
  1644. package/dist/services/operate/migration.js +0 -243
  1645. package/dist/services/operate/migration.js.map +0 -1
  1646. package/dist/services/operate/mission-dispatch.d.ts +0 -271
  1647. package/dist/services/operate/mission-dispatch.d.ts.map +0 -1
  1648. package/dist/services/operate/mission-dispatch.js +0 -590
  1649. package/dist/services/operate/mission-dispatch.js.map +0 -1
  1650. package/dist/services/operate/outcomes.d.ts +0 -48
  1651. package/dist/services/operate/outcomes.d.ts.map +0 -1
  1652. package/dist/services/operate/outcomes.js +0 -312
  1653. package/dist/services/operate/outcomes.js.map +0 -1
  1654. package/dist/services/operate/pipeline-handoff.d.ts +0 -138
  1655. package/dist/services/operate/pipeline-handoff.d.ts.map +0 -1
  1656. package/dist/services/operate/pipeline-handoff.js +0 -175
  1657. package/dist/services/operate/pipeline-handoff.js.map +0 -1
  1658. package/dist/services/operate/profile-migration.d.ts +0 -69
  1659. package/dist/services/operate/profile-migration.d.ts.map +0 -1
  1660. package/dist/services/operate/profile-migration.js +0 -462
  1661. package/dist/services/operate/profile-migration.js.map +0 -1
  1662. package/dist/services/operate/projection-persistence.d.ts +0 -126
  1663. package/dist/services/operate/projection-persistence.d.ts.map +0 -1
  1664. package/dist/services/operate/projection-persistence.js +0 -752
  1665. package/dist/services/operate/projection-persistence.js.map +0 -1
  1666. package/dist/services/operate/projection.d.ts +0 -37
  1667. package/dist/services/operate/projection.d.ts.map +0 -1
  1668. package/dist/services/operate/projection.js +0 -209
  1669. package/dist/services/operate/projection.js.map +0 -1
  1670. package/dist/services/operate/protocol.d.ts +0 -86
  1671. package/dist/services/operate/protocol.d.ts.map +0 -1
  1672. package/dist/services/operate/protocol.js +0 -76
  1673. package/dist/services/operate/protocol.js.map +0 -1
  1674. package/dist/services/operate/read-only-providers.d.ts +0 -76
  1675. package/dist/services/operate/read-only-providers.d.ts.map +0 -1
  1676. package/dist/services/operate/read-only-providers.js +0 -421
  1677. package/dist/services/operate/read-only-providers.js.map +0 -1
  1678. package/dist/services/operate/redaction.d.ts +0 -74
  1679. package/dist/services/operate/redaction.d.ts.map +0 -1
  1680. package/dist/services/operate/redaction.js +0 -406
  1681. package/dist/services/operate/redaction.js.map +0 -1
  1682. package/dist/services/operate/reducer.d.ts +0 -10
  1683. package/dist/services/operate/reducer.d.ts.map +0 -1
  1684. package/dist/services/operate/reducer.js +0 -11
  1685. package/dist/services/operate/reducer.js.map +0 -1
  1686. package/dist/services/operate/report-html.d.ts +0 -32
  1687. package/dist/services/operate/report-html.d.ts.map +0 -1
  1688. package/dist/services/operate/report-html.js +0 -289
  1689. package/dist/services/operate/report-html.js.map +0 -1
  1690. package/dist/services/operate/reports.d.ts +0 -72
  1691. package/dist/services/operate/reports.d.ts.map +0 -1
  1692. package/dist/services/operate/reports.js +0 -481
  1693. package/dist/services/operate/reports.js.map +0 -1
  1694. package/dist/services/operate/routes.d.ts +0 -133
  1695. package/dist/services/operate/routes.d.ts.map +0 -1
  1696. package/dist/services/operate/routes.js +0 -1577
  1697. package/dist/services/operate/routes.js.map +0 -1
  1698. package/dist/services/operate/scratch.d.ts +0 -81
  1699. package/dist/services/operate/scratch.d.ts.map +0 -1
  1700. package/dist/services/operate/scratch.js +0 -190
  1701. package/dist/services/operate/scratch.js.map +0 -1
  1702. package/dist/services/operate/shipment-observer.d.ts +0 -14
  1703. package/dist/services/operate/shipment-observer.d.ts.map +0 -1
  1704. package/dist/services/operate/shipment-observer.js +0 -320
  1705. package/dist/services/operate/shipment-observer.js.map +0 -1
  1706. package/dist/services/operate/stalled-item-service.d.ts +0 -18
  1707. package/dist/services/operate/stalled-item-service.d.ts.map +0 -1
  1708. package/dist/services/operate/stalled-item-service.js +0 -121
  1709. package/dist/services/operate/stalled-item-service.js.map +0 -1
  1710. package/dist/services/operate/subprocess-env.d.ts +0 -4
  1711. package/dist/services/operate/subprocess-env.d.ts.map +0 -1
  1712. package/dist/services/operate/subprocess-env.js +0 -45
  1713. package/dist/services/operate/subprocess-env.js.map +0 -1
  1714. package/dist/services/operate/types.d.ts +0 -1064
  1715. package/dist/services/operate/types.d.ts.map +0 -1
  1716. package/dist/services/operate/types.js +0 -27
  1717. package/dist/services/operate/types.js.map +0 -1
  1718. package/dist/services/operate/workspace.d.ts +0 -76
  1719. package/dist/services/operate/workspace.d.ts.map +0 -1
  1720. package/dist/services/operate/workspace.js +0 -350
  1721. package/dist/services/operate/workspace.js.map +0 -1
  1722. package/dist/services/revise-service.d.ts +0 -115
  1723. package/dist/services/revise-service.d.ts.map +0 -1
  1724. package/dist/services/revise-service.js +0 -294
  1725. package/dist/services/revise-service.js.map +0 -1
  1726. package/dist/templates/rules/claude/planr-pipeline.md.hbs +0 -69
  1727. package/dist/templates/rules/codex/_pipeline-section.md.hbs +0 -154
  1728. package/dist/templates/rules/cursor/agents/backend-agent.md +0 -299
  1729. package/dist/templates/rules/cursor/agents/db-agent.md +0 -163
  1730. package/dist/templates/rules/cursor/agents/designer-agent.md +0 -219
  1731. package/dist/templates/rules/cursor/agents/devops-agent.md +0 -197
  1732. package/dist/templates/rules/cursor/agents/doc-gen-agent.md +0 -203
  1733. package/dist/templates/rules/cursor/agents/frontend-agent.md +0 -220
  1734. package/dist/templates/rules/cursor/agents/qa-agent.md +0 -170
  1735. package/dist/templates/rules/cursor/agents/specification-agent.md +0 -282
  1736. package/dist/templates/rules/cursor/planr-pipeline-plan.mdc.hbs +0 -196
  1737. package/dist/templates/rules/cursor/planr-pipeline-ship.mdc.hbs +0 -246
  1738. package/dist/templates/rules/cursor/planr-pipeline.mdc.hbs +0 -134
@@ -0,0 +1,3994 @@
1
+ var OpenPlanrArtifactStage = (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // lib/artifact/ui/stage.mjs
21
+ var stage_exports = {};
22
+ __export(stage_exports, {
23
+ ARTIFACT_STAGE_EVENTS: () => ARTIFACT_STAGE_EVENTS,
24
+ ARTIFACT_STAGE_LIMITS: () => ARTIFACT_STAGE_LIMITS,
25
+ bootstrapArtifactStage: () => bootstrapArtifactStage,
26
+ clientPointToNormalized: () => clientPointToNormalized,
27
+ createArtifactStagePayload: () => createArtifactStagePayload,
28
+ createArtifactStageState: () => createArtifactStageState,
29
+ mountArtifactStage: () => mountArtifactStage,
30
+ normalizedPointToClient: () => normalizedPointToClient,
31
+ reduceArtifactStageState: () => reduceArtifactStageState,
32
+ resolveArtifactPresentation: () => resolveArtifactPresentation,
33
+ visibleArtifactIds: () => visibleArtifactIds
34
+ });
35
+
36
+ // lib/artifact/ui/annotations.mjs
37
+ var ARTIFACT_ANNOTATION_EVENTS = Object.freeze({
38
+ draft: "planr:artifact-annotation-draft",
39
+ focus: "planr:artifact-annotation-focus"
40
+ });
41
+ var ARTIFACT_ANNOTATION_LIMITS = Object.freeze({
42
+ dragThreshold: 4,
43
+ maxCommentLength: 65536,
44
+ maxIdentityLength: 256
45
+ });
46
+ var INTENTS = Object.freeze(["fix", "improve", "question"]);
47
+ function finite(value, fallback = 0) {
48
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
49
+ }
50
+ function clamp(value, min = 0, max = 1) {
51
+ return Math.min(max, Math.max(min, finite(value)));
52
+ }
53
+ function normalized(value) {
54
+ return Math.round(clamp(value) * 1e6) / 1e6;
55
+ }
56
+ function assertRect(rect) {
57
+ if (!rect || !Number.isFinite(rect.left) || !Number.isFinite(rect.top) || !Number.isFinite(rect.width) || !Number.isFinite(rect.height) || rect.width <= 0 || rect.height <= 0) {
58
+ throw new RangeError("Artifact bounds must have positive finite dimensions.");
59
+ }
60
+ }
61
+ function clientSelectionToNormalized(rect, start, end = start, { dragThreshold = ARTIFACT_ANNOTATION_LIMITS.dragThreshold } = {}) {
62
+ assertRect(rect);
63
+ const startX = clamp(finite(start?.x ?? start?.clientX, rect.left), rect.left, rect.left + rect.width);
64
+ const startY = clamp(finite(start?.y ?? start?.clientY, rect.top), rect.top, rect.top + rect.height);
65
+ const endX = clamp(finite(end?.x ?? end?.clientX, startX), rect.left, rect.left + rect.width);
66
+ const endY = clamp(finite(end?.y ?? end?.clientY, startY), rect.top, rect.top + rect.height);
67
+ const dragged = Math.hypot(endX - startX, endY - startY) >= Math.max(0, finite(dragThreshold, 4));
68
+ const left = dragged ? Math.min(startX, endX) : startX;
69
+ const top = dragged ? Math.min(startY, endY) : startY;
70
+ const right = dragged ? Math.max(startX, endX) : startX;
71
+ const bottom = dragged ? Math.max(startY, endY) : startY;
72
+ return Object.freeze({
73
+ x: normalized((left - rect.left) / rect.width),
74
+ y: normalized((top - rect.top) / rect.height),
75
+ w: normalized((right - left) / rect.width),
76
+ h: normalized((bottom - top) / rect.height)
77
+ });
78
+ }
79
+ function artifactAnchorPoint(region, viewport) {
80
+ const width = Number.isInteger(viewport?.width) && viewport.width > 0 ? viewport.width : 1;
81
+ const height = Number.isInteger(viewport?.height) && viewport.height > 0 ? viewport.height : 1;
82
+ return Object.freeze({
83
+ x: Math.round(clamp(region?.x + finite(region?.w) / 2) * width),
84
+ y: Math.round(clamp(region?.y + finite(region?.h) / 2) * height)
85
+ });
86
+ }
87
+ function annotationStyle(region) {
88
+ const percent = (value) => `${Math.round(clamp(value) * 1e6) / 1e4}%`;
89
+ return Object.freeze({
90
+ left: percent(region?.x),
91
+ top: percent(region?.y),
92
+ width: percent(region?.w),
93
+ height: percent(region?.h)
94
+ });
95
+ }
96
+ function viewportRegionToAnchorRegion(region, viewport, anchorRect) {
97
+ const width = Number.isInteger(viewport?.width) && viewport.width > 0 ? viewport.width : 1;
98
+ const height = Number.isInteger(viewport?.height) && viewport.height > 0 ? viewport.height : 1;
99
+ const anchorWidth = Math.max(1, finite(anchorRect?.width, 1));
100
+ const anchorHeight = Math.max(1, finite(anchorRect?.height, 1));
101
+ const left = clamp(region?.x) * width;
102
+ const top = clamp(region?.y) * height;
103
+ const right = left + clamp(region?.w) * width;
104
+ const bottom = top + clamp(region?.h) * height;
105
+ const x = clamp((left - finite(anchorRect?.x)) / anchorWidth);
106
+ const y = clamp((top - finite(anchorRect?.y)) / anchorHeight);
107
+ return Object.freeze({
108
+ x: normalized(x),
109
+ y: normalized(y),
110
+ w: normalized(Math.max(0, Math.min(1 - x, (right - left) / anchorWidth))),
111
+ h: normalized(Math.max(0, Math.min(1 - y, (bottom - top) / anchorHeight)))
112
+ });
113
+ }
114
+ function anchorRegionToViewportRegion(region, viewport, anchorRect) {
115
+ const width = Number.isInteger(viewport?.width) && viewport.width > 0 ? viewport.width : 1;
116
+ const height = Number.isInteger(viewport?.height) && viewport.height > 0 ? viewport.height : 1;
117
+ const anchorWidth = Math.max(0, finite(anchorRect?.width));
118
+ const anchorHeight = Math.max(0, finite(anchorRect?.height));
119
+ return Object.freeze({
120
+ x: normalized((finite(anchorRect?.x) + clamp(region?.x) * anchorWidth) / width),
121
+ y: normalized((finite(anchorRect?.y) + clamp(region?.y) * anchorHeight) / height),
122
+ w: normalized(clamp(region?.w) * anchorWidth / width),
123
+ h: normalized(clamp(region?.h) * anchorHeight / height)
124
+ });
125
+ }
126
+ function domToken(value) {
127
+ const source = String(value);
128
+ let token = "";
129
+ for (let index = 0; index < source.length; index += 1) {
130
+ token += source.charCodeAt(index).toString(16).padStart(4, "0");
131
+ }
132
+ return token;
133
+ }
134
+ function annotationDomIds(pinId) {
135
+ const suffix = domToken(pinId);
136
+ return Object.freeze({
137
+ pin: `planr-pin-${suffix}`,
138
+ thread: `planr-thread-${suffix}`
139
+ });
140
+ }
141
+ function text(value, max = ARTIFACT_ANNOTATION_LIMITS.maxCommentLength) {
142
+ return typeof value === "string" ? value.trim().slice(0, max) : "";
143
+ }
144
+ function make(document2, tag, { className, textContent, attributes = {} } = {}) {
145
+ const node = document2.createElement(tag);
146
+ if (className) node.className = className;
147
+ if (textContent !== void 0) node.textContent = textContent;
148
+ for (const [name, value] of Object.entries(attributes)) {
149
+ if (value !== void 0 && value !== null) node.setAttribute(name, String(value));
150
+ }
151
+ return node;
152
+ }
153
+ function setRegionStyle(node, region) {
154
+ const style = annotationStyle(region);
155
+ if (node.style.left !== style.left) node.style.left = style.left;
156
+ if (node.style.top !== style.top) node.style.top = style.top;
157
+ if (region.w > 0 || region.h > 0) {
158
+ if (node.style.width !== style.width) node.style.width = style.width;
159
+ if (node.style.height !== style.height) node.style.height = style.height;
160
+ }
161
+ }
162
+ function announce(document2, value) {
163
+ const node = document2.querySelector('[data-planr-slot="review-announcer"]');
164
+ if (node) node.textContent = value;
165
+ }
166
+ function identityName(reviewController) {
167
+ return text(reviewController?.getIdentity?.()?.name, ARTIFACT_ANNOTATION_LIMITS.maxIdentityLength);
168
+ }
169
+ function createIntentPicker(document2) {
170
+ const group = make(document2, "div", {
171
+ className: "planr-intent-picker",
172
+ attributes: { role: "radiogroup", "aria-label": "Feedback intent" }
173
+ });
174
+ for (const [index, intent] of INTENTS.entries()) {
175
+ const button = make(document2, "button", {
176
+ textContent: intent[0].toUpperCase() + intent.slice(1),
177
+ attributes: {
178
+ type: "button",
179
+ role: "radio",
180
+ "aria-checked": String(index === 0),
181
+ tabindex: index === 0 ? 0 : -1,
182
+ "data-planr-intent": intent
183
+ }
184
+ });
185
+ group.append(button);
186
+ }
187
+ return group;
188
+ }
189
+ function mountArtifactAnnotations({
190
+ document: document2 = globalThis.document,
191
+ window = document2?.defaultView,
192
+ root = document2?.querySelector?.(".planr-shell"),
193
+ stageController,
194
+ reviewController,
195
+ onFocusPin
196
+ } = {}) {
197
+ if (!document2 || !window || !root || !stageController || !reviewController) return null;
198
+ const cleanup = [];
199
+ let draft = null;
200
+ let suspendedDraft = null;
201
+ let draftToken = 0;
202
+ let draftFieldCleanup = null;
203
+ let composerLayoutCleanup = null;
204
+ let composerReturnFocus = null;
205
+ const pinRecords = /* @__PURE__ */ new Map();
206
+ const anchorRequests = /* @__PURE__ */ new Map();
207
+ let destroyed = false;
208
+ function listen(target, type, handler, options) {
209
+ target.addEventListener(type, handler, options);
210
+ cleanup.push(() => target.removeEventListener(type, handler, options));
211
+ }
212
+ function review() {
213
+ return reviewController.getReview?.() ?? reviewController.getState?.()?.review ?? reviewController.getState?.();
214
+ }
215
+ function layerFor(artifactId) {
216
+ return [...document2.querySelectorAll("[data-planr-annotation-layer]")].find((node) => node.dataset.planrAnnotationLayer === artifactId) ?? null;
217
+ }
218
+ function frameFor(artifactId) {
219
+ return [...document2.querySelectorAll("[data-planr-artifact-frame]")].find((node) => node.dataset.planrArtifactFrame === artifactId) ?? null;
220
+ }
221
+ function focusThread(pinId) {
222
+ const pin = review()?.pins?.find((item) => item.id === pinId);
223
+ if (!pin) return;
224
+ reviewController.selectPin?.(pinId);
225
+ const state = stageController.getState();
226
+ if (state.activeArtifactId !== pin.artifactId) {
227
+ stageController.dispatch({ type: "set-active", artifactId: pin.artifactId });
228
+ }
229
+ stageController.dispatch({ type: "set-rail-open", railOpen: true });
230
+ queueMicrotask(() => document2.getElementById(annotationDomIds(pinId).thread)?.focus());
231
+ }
232
+ function focusPin(pinId) {
233
+ const pin = review()?.pins?.find((item) => item.id === pinId);
234
+ if (!pin) return;
235
+ reviewController.selectPin?.(pinId);
236
+ const state = stageController.getState();
237
+ if (state.activeArtifactId !== pin.artifactId) {
238
+ stageController.dispatch({ type: "set-active", artifactId: pin.artifactId });
239
+ }
240
+ queueMicrotask(() => {
241
+ const marker = document2.getElementById(annotationDomIds(pinId).pin);
242
+ if (marker?.hidden) {
243
+ announce(document2, "This pin’s element is not currently visible. The original comment remains in Review.");
244
+ return;
245
+ }
246
+ if (onFocusPin) onFocusPin(pin);
247
+ else marker?.scrollIntoView?.({ block: "center", inline: "center", behavior: "smooth" });
248
+ marker?.focus?.({ preventScroll: true });
249
+ marker?.classList.add("planr-pin-highlight");
250
+ window.setTimeout(() => marker?.classList.remove("planr-pin-highlight"), 1200);
251
+ });
252
+ }
253
+ function pinGeometryKey(pin) {
254
+ return JSON.stringify([
255
+ reviewController.getReviewOf?.() ?? review()?.reviewOf,
256
+ pin.artifactId,
257
+ pin.anchor,
258
+ pin.region,
259
+ pin.viewport
260
+ ]);
261
+ }
262
+ function setPinPosition(record2, region) {
263
+ const point = { x: region.x + region.w / 2, y: region.y + region.h / 2, w: 0, h: 0 };
264
+ setRegionStyle(record2.button, point);
265
+ if (record2.region) setRegionStyle(record2.region, region);
266
+ if (record2.button.hidden) record2.button.hidden = false;
267
+ if (record2.region?.hidden) record2.region.hidden = false;
268
+ }
269
+ function hidePin(record2) {
270
+ if (!record2.button.hidden) record2.button.hidden = true;
271
+ if (record2.region && !record2.region.hidden) record2.region.hidden = true;
272
+ }
273
+ function removePin(record2) {
274
+ record2.pending = null;
275
+ record2.button.remove();
276
+ record2.region?.remove();
277
+ }
278
+ function refreshAnchors() {
279
+ if (destroyed) return;
280
+ const now = window.performance.now();
281
+ const frames = new Map([...document2.querySelectorAll("[data-planr-artifact-frame]")].map((frame) => [frame.dataset.planrArtifactFrame, frame]));
282
+ const records = [...pinRecords.values()].flatMap((records2) => [...records2.values()]).filter((record2) => record2.pin.anchor?.planrId).sort((a, b) => a.requestedAt - b.requestedAt);
283
+ for (const record2 of records) {
284
+ if (record2.pending || now - record2.requestedAt < 200 || !record2.button.isConnected) continue;
285
+ const frame = frames.get(record2.pin.artifactId);
286
+ const bridge = frame?.__openPlanrBridge;
287
+ if (!bridge?.resolve || frame.closest("[hidden]") || frame.dataset.planrBridgeTrusted === "false" || (anchorRequests.get(frame) ?? 0) >= 8) continue;
288
+ const request = {}, key = record2.geometryKey, pin = record2.pin;
289
+ record2.pending = request;
290
+ record2.requestedAt = now;
291
+ anchorRequests.set(frame, (anchorRequests.get(frame) ?? 0) + 1);
292
+ Promise.resolve().then(() => bridge.resolve(pin.anchor.planrId, pin.anchor.screen)).then((anchor) => {
293
+ if (destroyed || record2.pending !== request || record2.geometryKey !== key || !record2.button.isConnected || frame.__openPlanrBridge !== bridge) return;
294
+ if (!anchor || anchor.rect.width <= 0 || anchor.rect.height <= 0) {
295
+ hidePin(record2);
296
+ if (record2.button.dataset.planrAnchorStatus !== "unavailable") record2.button.dataset.planrAnchorStatus = "unavailable";
297
+ return;
298
+ }
299
+ const projected = anchorRegionToViewportRegion(pin.region, anchor.viewport ?? pin.viewport, anchor.rect);
300
+ setPinPosition(record2, projected);
301
+ if (record2.button.dataset.planrAnchorStatus !== "resolved") record2.button.dataset.planrAnchorStatus = "resolved";
302
+ }).catch(() => {
303
+ }).finally(() => {
304
+ const remaining = (anchorRequests.get(frame) ?? 1) - 1;
305
+ if (remaining > 0) anchorRequests.set(frame, remaining);
306
+ else anchorRequests.delete(frame);
307
+ if (record2.pending === request) record2.pending = null;
308
+ });
309
+ }
310
+ }
311
+ function renderPins() {
312
+ if (destroyed) return;
313
+ const pins = Array.isArray(review()?.pins) ? review().pins : [];
314
+ const layers = new Set(document2.querySelectorAll("[data-planr-annotation-layer]"));
315
+ for (const [layer, records] of pinRecords) {
316
+ if (layers.has(layer)) continue;
317
+ for (const record2 of records.values()) removePin(record2);
318
+ pinRecords.delete(layer);
319
+ }
320
+ for (const layer of layers) {
321
+ let records = pinRecords.get(layer);
322
+ if (!records) {
323
+ records = /* @__PURE__ */ new Map();
324
+ pinRecords.set(layer, records);
325
+ }
326
+ const current = /* @__PURE__ */ new Set();
327
+ for (const [index, pin] of pins.entries()) {
328
+ if (pin.artifactId !== layer.dataset.planrAnnotationLayer) continue;
329
+ current.add(pin.id);
330
+ const ids = annotationDomIds(pin.id), ordinal = index + 1;
331
+ const hasRegion = pin.region.w > 0 || pin.region.h > 0;
332
+ let record2 = records.get(pin.id);
333
+ if (!record2) {
334
+ const button = make(document2, "button", { attributes: {
335
+ type: "button",
336
+ id: ids.pin,
337
+ "data-planr-pin-id": pin.id,
338
+ "aria-controls": ids.thread
339
+ } });
340
+ button.addEventListener("click", () => focusThread(pin.id));
341
+ layer.append(button);
342
+ record2 = { button, region: null, pin, geometryKey: null, pending: null, requestedAt: -Infinity };
343
+ records.set(pin.id, record2);
344
+ }
345
+ record2.pin = pin;
346
+ if (hasRegion && !record2.region) {
347
+ record2.region = make(document2, "span", { attributes: { "data-planr-pin-region-id": pin.id, "aria-hidden": "true" } });
348
+ layer.insertBefore(record2.region, record2.button);
349
+ } else if (!hasRegion && record2.region) {
350
+ record2.region.remove();
351
+ record2.region = null;
352
+ }
353
+ const buttonClass = `planr-pin planr-pin-${pin.intent} planr-pin-${pin.status}${hasRegion ? " planr-pin-region-handle" : ""}${record2.button.classList.contains("planr-pin-highlight") ? " planr-pin-highlight" : ""}`;
354
+ if (record2.button.className !== buttonClass) record2.button.className = buttonClass;
355
+ if (record2.button.textContent !== String(ordinal)) record2.button.textContent = String(ordinal);
356
+ for (const [name, value] of Object.entries({
357
+ "data-planr-intent": pin.intent,
358
+ "data-planr-status": pin.status,
359
+ "aria-label": `${pin.intent} comment ${ordinal}: ${pin.comment}`
360
+ })) {
361
+ if (record2.button.getAttribute(name) !== value) record2.button.setAttribute(name, value);
362
+ }
363
+ if (record2.region) {
364
+ const regionClass = `planr-pin-region planr-pin-region-${pin.intent} planr-pin-region-${pin.status}`;
365
+ if (record2.region.className !== regionClass) record2.region.className = regionClass;
366
+ }
367
+ const key = pinGeometryKey(pin);
368
+ if (record2.geometryKey !== key) {
369
+ record2.geometryKey = key;
370
+ record2.pending = null;
371
+ record2.requestedAt = -Infinity;
372
+ if (pin.anchor?.planrId) hidePin(record2);
373
+ else {
374
+ delete record2.button.dataset.planrAnchorStatus;
375
+ setPinPosition(record2, pin.region);
376
+ }
377
+ }
378
+ }
379
+ for (const [id, record2] of records) {
380
+ if (!current.has(id)) {
381
+ removePin(record2);
382
+ records.delete(id);
383
+ }
384
+ }
385
+ }
386
+ refreshAnchors();
387
+ }
388
+ function closeComposer({ restoreFocus = false, preserveDraft = false } = {}) {
389
+ const snapshot = preserveDraft ? snapshotDraft() : null;
390
+ draftFieldCleanup?.();
391
+ draftFieldCleanup = null;
392
+ composerLayoutCleanup?.();
393
+ composerLayoutCleanup = null;
394
+ const activeLayer = draft ? layerFor(draft.artifactId) : null;
395
+ const composer = root.querySelector("[data-planr-annotation-composer]");
396
+ try {
397
+ if (composer?.matches(":popover-open")) composer.hidePopover();
398
+ } catch {
399
+ }
400
+ composer?.remove();
401
+ draft = null;
402
+ suspendedDraft = snapshot;
403
+ draftToken += 1;
404
+ if (activeLayer && stageController.getState().reviewMode !== "comment") {
405
+ activeLayer.setAttribute("aria-disabled", "true");
406
+ }
407
+ if (restoreFocus) {
408
+ const target = composerReturnFocus?.isConnected && composerReturnFocus !== document2.body ? composerReturnFocus : activeLayer;
409
+ target?.focus?.({ preventScroll: true });
410
+ }
411
+ composerReturnFocus = null;
412
+ }
413
+ async function resolveAnchor(token, candidate) {
414
+ const frame = frameFor(candidate.artifactId);
415
+ const point = artifactAnchorPoint(candidate.region, candidate.viewport);
416
+ let result = null;
417
+ try {
418
+ const anchor = frame?.__openPlanrBridge?.hitTest?.(point.x, point.y);
419
+ if (anchor) {
420
+ result = await Promise.race([
421
+ anchor,
422
+ new Promise((resolve) => window.setTimeout(() => resolve(null), 800))
423
+ ]);
424
+ }
425
+ } catch {
426
+ result = null;
427
+ }
428
+ if (token !== draftToken || !draft || draft.artifactId !== candidate.artifactId) return;
429
+ if (result?.planrId) {
430
+ draft.anchor = Object.freeze({
431
+ planrId: String(result.planrId).slice(0, 512),
432
+ ...result.screen ? { screen: String(result.screen).slice(0, 128) } : {}
433
+ });
434
+ draft.region = viewportRegionToAnchorRegion(draft.region, draft.viewport, result.rect);
435
+ }
436
+ }
437
+ function positionComposer() {
438
+ const composer = root.querySelector("[data-planr-annotation-composer]");
439
+ const layer = draft && layerFor(draft.artifactId);
440
+ if (!composer || !layer) return;
441
+ const visual = window.visualViewport;
442
+ const viewport = { x: finite(visual?.offsetLeft), y: finite(visual?.offsetTop), width: finite(visual?.width, window.innerWidth), height: finite(visual?.height, window.innerHeight) };
443
+ const margin = Math.min(12, viewport.width / 8, viewport.height / 8);
444
+ const availableWidth = Math.max(1, viewport.width - margin * 2), availableHeight = Math.max(1, viewport.height - margin * 2);
445
+ composer.style.width = `${Math.min(360, availableWidth)}px`;
446
+ composer.style.maxHeight = `${Math.min(620, availableHeight)}px`;
447
+ const bounds = layer.getBoundingClientRect();
448
+ const point = {
449
+ x: bounds.left + clamp(draft.displayRegion.x + draft.displayRegion.w / 2) * bounds.width,
450
+ y: bounds.top + clamp(draft.displayRegion.y + draft.displayRegion.h / 2) * bounds.height
451
+ };
452
+ const size = composer.getBoundingClientRect();
453
+ const width = Math.min(size.width || 360, availableWidth), height = Math.min(size.height || 360, availableHeight);
454
+ const left = point.x + 16 + width <= viewport.x + viewport.width - margin ? point.x + 16 : point.x - width - 16;
455
+ composer.style.left = `${clamp(left, viewport.x + margin, viewport.x + viewport.width - width - margin)}px`;
456
+ composer.style.top = `${clamp(point.y + 16, viewport.y + margin, viewport.y + viewport.height - height - margin)}px`;
457
+ }
458
+ function openComposer(detail, { restoredDraft = null } = {}) {
459
+ const opener = document2.activeElement;
460
+ closeComposer();
461
+ composerReturnFocus = opener;
462
+ const layer = layerFor(detail.artifactId);
463
+ if (!layer) return;
464
+ draftToken += 1;
465
+ const token = draftToken;
466
+ draft = {
467
+ artifactId: detail.artifactId,
468
+ region: Object.freeze({ ...detail.region }),
469
+ viewport: Object.freeze({ ...detail.viewport }),
470
+ variant: typeof detail.variant === "string" && detail.variant.length > 0 ? detail.variant : detail.artifactId,
471
+ anchor: restoredDraft?.anchor ?? null,
472
+ displayRegion: Object.freeze({ ...restoredDraft?.displayRegion ?? detail.region })
473
+ };
474
+ const composer = make(document2, "form", {
475
+ className: "planr-annotation-composer",
476
+ attributes: {
477
+ "data-planr-annotation-composer": "",
478
+ role: "dialog",
479
+ popover: "manual",
480
+ "aria-label": "Add artifact comment"
481
+ }
482
+ });
483
+ const header = make(document2, "header", { className: "planr-composer-header" });
484
+ const heading = make(document2, "strong", { textContent: "New comment" });
485
+ const close = make(document2, "button", { textContent: "×", attributes: { type: "button", "data-planr-composer-close": "", "aria-label": "Close new comment", title: "Close new comment (Escape)" } });
486
+ header.append(heading, close);
487
+ const identityLabel = make(document2, "label", { textContent: "Your name" });
488
+ const identity = make(document2, "input", {
489
+ attributes: {
490
+ type: "text",
491
+ maxlength: ARTIFACT_ANNOTATION_LIMITS.maxIdentityLength,
492
+ autocomplete: "name",
493
+ value: identityName(reviewController),
494
+ "data-planr-composer-identity": "",
495
+ "aria-describedby": "planr-composer-error"
496
+ }
497
+ });
498
+ identityLabel.append(identity);
499
+ const intentPicker = createIntentPicker(document2);
500
+ const commentLabel = make(document2, "label", { textContent: "Comment" });
501
+ const comment = make(document2, "textarea", {
502
+ attributes: {
503
+ maxlength: ARTIFACT_ANNOTATION_LIMITS.maxCommentLength,
504
+ required: "",
505
+ placeholder: "Describe what the coding agent should change or consider…",
506
+ "data-planr-composer-comment": "",
507
+ "aria-describedby": "planr-composer-error"
508
+ }
509
+ });
510
+ commentLabel.append(comment);
511
+ const error = make(document2, "p", {
512
+ className: "planr-field-error",
513
+ attributes: { id: "planr-composer-error", role: "alert", "data-planr-composer-error": "" }
514
+ });
515
+ const actions = make(document2, "div", { className: "planr-composer-actions" });
516
+ actions.append(
517
+ make(document2, "button", {
518
+ textContent: "Cancel",
519
+ attributes: { type: "button", "data-planr-composer-cancel": "" }
520
+ }),
521
+ make(document2, "button", {
522
+ textContent: "Add comment",
523
+ attributes: { type: "submit", "data-planr-composer-submit": "" }
524
+ })
525
+ );
526
+ composer.append(header, identityLabel, intentPicker, commentLabel, error, actions);
527
+ root.append(composer);
528
+ try {
529
+ if (typeof composer.showPopover === "function") composer.showPopover();
530
+ else composer.removeAttribute("popover");
531
+ } catch {
532
+ composer.removeAttribute("popover");
533
+ }
534
+ positionComposer();
535
+ const observer = typeof window.ResizeObserver === "function" ? new window.ResizeObserver(positionComposer) : null;
536
+ observer?.observe(composer);
537
+ composerLayoutCleanup = () => observer?.disconnect();
538
+ let selectedIntent = "fix";
539
+ listen(intentPicker, "click", (event) => {
540
+ const button = event.target.closest?.("[data-planr-intent]");
541
+ if (!button || !INTENTS.includes(button.dataset.planrIntent)) return;
542
+ selectedIntent = button.dataset.planrIntent;
543
+ for (const option of intentPicker.querySelectorAll("[data-planr-intent]")) {
544
+ option.setAttribute("aria-checked", String(option === button));
545
+ option.tabIndex = option === button ? 0 : -1;
546
+ }
547
+ });
548
+ listen(intentPicker, "keydown", (event) => {
549
+ if (!["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) return;
550
+ const options = [...intentPicker.querySelectorAll("[data-planr-intent]")];
551
+ const current = options.findIndex((option) => option.getAttribute("aria-checked") === "true");
552
+ const delta = ["ArrowRight", "ArrowDown"].includes(event.key) ? 1 : -1;
553
+ const nextIndex = event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : (Math.max(0, current) + delta + options.length) % options.length;
554
+ event.preventDefault();
555
+ options[nextIndex].click();
556
+ options[nextIndex].focus();
557
+ });
558
+ listen(close, "click", () => closeComposer({ restoreFocus: true }));
559
+ listen(composer.querySelector("[data-planr-composer-cancel]"), "click", () => {
560
+ closeComposer({ restoreFocus: true });
561
+ }, { once: true });
562
+ listen(composer, "keydown", (event) => {
563
+ if (event.key === "Escape") {
564
+ event.preventDefault();
565
+ event.stopPropagation();
566
+ closeComposer({ restoreFocus: true });
567
+ } else if (event.key === "Enter" && !event.isComposing && (event.metaKey || event.ctrlKey)) {
568
+ event.preventDefault();
569
+ composer.requestSubmit();
570
+ }
571
+ });
572
+ listen(composer, "submit", (event) => {
573
+ event.preventDefault();
574
+ if (!draft) return;
575
+ const author = text(identity.value, ARTIFACT_ANNOTATION_LIMITS.maxIdentityLength);
576
+ const body = text(comment.value);
577
+ identity.setAttribute("aria-invalid", String(!author));
578
+ comment.setAttribute("aria-invalid", String(!body));
579
+ if (!author || !body) {
580
+ error.textContent = !author ? "Enter your name before adding a comment." : "Enter a comment before submitting.";
581
+ (!author ? identity : comment).focus();
582
+ return;
583
+ }
584
+ reviewController.setIdentity?.({ name: author });
585
+ const existingIds = new Set(review()?.pins?.map(({ id }) => id) ?? []);
586
+ const action = {
587
+ type: "add-pin",
588
+ pin: {
589
+ artifactId: draft.artifactId,
590
+ region: draft.region,
591
+ viewport: draft.viewport,
592
+ variant: draft.variant,
593
+ ...draft.anchor ? { anchor: draft.anchor } : {},
594
+ intent: selectedIntent,
595
+ comment: body
596
+ }
597
+ };
598
+ const next = reviewController.dispatch(action);
599
+ const nextReview = next?.review ?? next;
600
+ const created = nextReview?.pins?.find?.(({ id }) => !existingIds.has(id));
601
+ closeComposer();
602
+ renderPins();
603
+ announce(document2, `${selectedIntent} comment added.`);
604
+ if (created?.id) queueMicrotask(() => focusThread(created.id));
605
+ });
606
+ comment.focus();
607
+ root.dispatchEvent(new window.CustomEvent(ARTIFACT_ANNOTATION_EVENTS.draft, {
608
+ bubbles: true,
609
+ detail: Object.freeze({ ...draft })
610
+ }));
611
+ if (restoredDraft) {
612
+ identity.value = restoredDraft.identity;
613
+ comment.value = restoredDraft.comment;
614
+ selectedIntent = restoredDraft.intent;
615
+ for (const option of intentPicker.querySelectorAll("[data-planr-intent]")) {
616
+ const selected = option.dataset.planrIntent === selectedIntent;
617
+ option.setAttribute("aria-checked", String(selected));
618
+ option.tabIndex = selected ? 0 : -1;
619
+ }
620
+ if (Number.isInteger(restoredDraft.selectionStart)) comment.setSelectionRange(restoredDraft.selectionStart, restoredDraft.selectionEnd, restoredDraft.selectionDirection);
621
+ const fields = new Map(Object.entries(restoredDraft.fields ?? {}).slice(0, 32).filter(([key, value]) => key.length <= 128 && typeof value === "string" && value.length <= ARTIFACT_ANNOTATION_LIMITS.maxCommentLength));
622
+ if (fields.size) {
623
+ let restoreFields = function() {
624
+ if (token !== draftToken || !composer.isConnected) {
625
+ finish();
626
+ return;
627
+ }
628
+ for (const field of composer.querySelectorAll("[data-planr-draft-key]")) {
629
+ const key = field.dataset.planrDraftKey;
630
+ if (!fields.has(key) || typeof field.value !== "string") continue;
631
+ field.value = fields.get(key);
632
+ fields.delete(key);
633
+ field.dispatchEvent(new window.Event("change", { bubbles: true }));
634
+ }
635
+ if (!fields.size) finish();
636
+ };
637
+ let timer;
638
+ const observer2 = new window.MutationObserver(restoreFields);
639
+ const finish = () => {
640
+ observer2.disconnect();
641
+ window.clearTimeout(timer);
642
+ };
643
+ observer2.observe(composer, { childList: true, subtree: true });
644
+ timer = window.setTimeout(finish, 1500);
645
+ draftFieldCleanup = finish;
646
+ restoreFields();
647
+ }
648
+ } else void resolveAnchor(token, draft);
649
+ }
650
+ function snapshotDraft() {
651
+ const composer = document2.querySelector("[data-planr-annotation-composer]");
652
+ if (!draft || !composer) return suspendedDraft;
653
+ const comment = composer.querySelector("[data-planr-composer-comment]");
654
+ return Object.freeze({
655
+ ...draft,
656
+ reviewOf: reviewController.getReviewOf?.() ?? review()?.reviewOf ?? null,
657
+ identity: composer.querySelector("[data-planr-composer-identity]").value,
658
+ fields: Object.fromEntries([...composer.querySelectorAll("[data-planr-draft-key]")].slice(0, 32).filter((field) => field.dataset.planrDraftKey.length <= 128 && typeof field.value === "string").map((field) => [field.dataset.planrDraftKey, field.value.slice(0, ARTIFACT_ANNOTATION_LIMITS.maxCommentLength)])),
659
+ comment: comment.value,
660
+ intent: composer.querySelector('[data-planr-intent][aria-checked="true"]')?.dataset.planrIntent ?? "fix",
661
+ selectionStart: comment.selectionStart,
662
+ selectionEnd: comment.selectionEnd,
663
+ selectionDirection: comment.selectionDirection
664
+ });
665
+ }
666
+ function restoreDraft(snapshot) {
667
+ if (!snapshot || snapshot.reviewOf !== (reviewController.getReviewOf?.() ?? review()?.reviewOf ?? null)) return false;
668
+ const artifact = stageController.getState().artifacts.find((entry) => entry.id === snapshot.artifactId);
669
+ if (!artifact || artifact.viewport.width !== snapshot.viewport?.width || artifact.viewport.height !== snapshot.viewport?.height || !["x", "y", "w", "h"].every((key) => Number.isFinite(snapshot.region?.[key]) && snapshot.region[key] >= 0 && snapshot.region[key] <= 1) || !["x", "y", "w", "h"].every((key) => Number.isFinite(snapshot.displayRegion?.[key]) && snapshot.displayRegion[key] >= 0 && snapshot.displayRegion[key] <= 1) || typeof snapshot.comment !== "string" || snapshot.comment.length > ARTIFACT_ANNOTATION_LIMITS.maxCommentLength || typeof snapshot.identity !== "string" || snapshot.identity.length > ARTIFACT_ANNOTATION_LIMITS.maxIdentityLength || !INTENTS.includes(snapshot.intent) || snapshot.anchor && (typeof snapshot.anchor.planrId !== "string" || snapshot.anchor.planrId.length > 512)) return false;
670
+ openComposer(snapshot, { restoredDraft: snapshot });
671
+ return Boolean(draft);
672
+ }
673
+ listen(window, "resize", positionComposer);
674
+ if (window.visualViewport) {
675
+ listen(window.visualViewport, "resize", positionComposer);
676
+ listen(window.visualViewport, "scroll", positionComposer);
677
+ }
678
+ listen(root, "planr:artifact-region", (event) => openComposer(event.detail));
679
+ listen(root, "planr:stage-change", () => {
680
+ const state = stageController.getState();
681
+ const visible = state.viewMode === "split" ? [state.activeArtifactId, state.comparisonArtifactId] : [state.activeArtifactId];
682
+ if (!draft) {
683
+ if (suspendedDraft && state.status === "ready" && state.reviewMode === "comment" && visible.includes(suspendedDraft.artifactId)) restoreDraft(suspendedDraft);
684
+ return;
685
+ }
686
+ if (state.status !== "ready" || state.presentation !== "document" && state.reviewMode !== "comment") {
687
+ closeComposer({ preserveDraft: true });
688
+ return;
689
+ }
690
+ if (!visible.includes(draft.artifactId)) closeComposer({ preserveDraft: true });
691
+ else {
692
+ draftToken += 1;
693
+ positionComposer();
694
+ }
695
+ });
696
+ listen(root, "planr:artifact-review-change", renderPins);
697
+ const anchorRefresh = window.setInterval(refreshAnchors, 250);
698
+ cleanup.push(() => window.clearInterval(anchorRefresh));
699
+ listen(root, ARTIFACT_ANNOTATION_EVENTS.focus, (event) => {
700
+ if (event.detail?.target === "pin") focusPin(event.detail.pinId);
701
+ if (event.detail?.target === "thread") focusThread(event.detail.pinId);
702
+ });
703
+ listen(root, "planr:artifact-review-select", (event) => {
704
+ if (event.detail?.source === "thread" && typeof event.detail?.pinId === "string") {
705
+ focusPin(event.detail.pinId);
706
+ }
707
+ });
708
+ renderPins();
709
+ const controller = Object.freeze({
710
+ render: renderPins,
711
+ openComposer,
712
+ closeComposer,
713
+ snapshotDraft,
714
+ restoreDraft,
715
+ focusPin,
716
+ focusThread,
717
+ destroy() {
718
+ destroyed = true;
719
+ closeComposer();
720
+ for (const remove of cleanup.splice(0)) remove();
721
+ for (const records of pinRecords.values()) for (const record2 of records.values()) removePin(record2);
722
+ pinRecords.clear();
723
+ anchorRequests.clear();
724
+ }
725
+ });
726
+ window.__openPlanrArtifactAnnotations = controller;
727
+ return controller;
728
+ }
729
+
730
+ // lib/artifact/ui/feedback-rail.mjs
731
+ var ARTIFACT_REVIEW_CHANGE_EVENT = "planr:artifact-review-change";
732
+ var ARTIFACT_REVIEW_SELECT_EVENT = "planr:artifact-review-select";
733
+ var ARTIFACT_REVIEW_DRAFT_CHANGE_EVENT = "planr:artifact-review-draft-change";
734
+ var ARTIFACT_REVIEW_LIMITS = Object.freeze({
735
+ id: 128,
736
+ authorName: 256,
737
+ artifactId: 128,
738
+ variant: 128,
739
+ anchor: 512,
740
+ screen: 128,
741
+ text: 65536,
742
+ pins: 1e4,
743
+ replies: 1e4,
744
+ viewport: 16384
745
+ });
746
+ var ARTIFACT_REVIEW_DECISIONS = Object.freeze([
747
+ "pending",
748
+ "approved",
749
+ "changes_requested"
750
+ ]);
751
+ var ARTIFACT_REVIEW_INTENTS = Object.freeze(["fix", "improve", "question"]);
752
+ var ARTIFACT_REVIEW_STATUSES = Object.freeze(["open", "addressed", "resolved"]);
753
+ var REVIEW_OF_RE = /^[a-f0-9]{64}$/;
754
+ var ArtifactReviewStateError = class extends Error {
755
+ constructor(code, message) {
756
+ super(message);
757
+ this.name = "ArtifactReviewStateError";
758
+ this.code = code;
759
+ }
760
+ };
761
+ function invalid(message) {
762
+ throw new ArtifactReviewStateError("E_ARTIFACT_REVIEW_INVALID", message);
763
+ }
764
+ function identityRequired() {
765
+ throw new ArtifactReviewStateError(
766
+ "E_ARTIFACT_REVIEW_IDENTITY_REQUIRED",
767
+ "Enter your name before adding a comment."
768
+ );
769
+ }
770
+ function clonePlain(value) {
771
+ if (Array.isArray(value)) return value.map(clonePlain);
772
+ if (!value || typeof value !== "object") return value;
773
+ const clone = {};
774
+ for (const [key, entry] of Object.entries(value)) clone[key] = clonePlain(entry);
775
+ return clone;
776
+ }
777
+ function deepFreezeArtifactReview(value) {
778
+ if (!value || typeof value !== "object" || Object.isFrozen(value)) return value;
779
+ for (const entry of Object.values(value)) deepFreezeArtifactReview(entry);
780
+ return Object.freeze(value);
781
+ }
782
+ function cloneFrozenArtifactReview(review) {
783
+ return deepFreezeArtifactReview(clonePlain(review));
784
+ }
785
+ function boundedString(value, label, { min = 0, max, trim = false, pattern } = {}) {
786
+ if (typeof value !== "string") invalid(`${label} must be a string.`);
787
+ const normalized3 = trim ? value.trim() : value;
788
+ if (normalized3.length < min || max !== void 0 && normalized3.length > max) {
789
+ invalid(`${label} must contain ${min} through ${max ?? "unlimited"} characters.`);
790
+ }
791
+ if (pattern && !pattern.test(normalized3)) invalid(`${label} has an invalid format.`);
792
+ return normalized3;
793
+ }
794
+ function optionalString(value, label, options) {
795
+ if (value === void 0) return void 0;
796
+ return boundedString(value, label, options);
797
+ }
798
+ function enumValue(value, values, label) {
799
+ if (!values.includes(value)) invalid(`${label} must be one of: ${values.join(", ")}.`);
800
+ return value;
801
+ }
802
+ function isoTimestamp(value, label) {
803
+ const timestamp = value instanceof Date ? value.toISOString() : value;
804
+ if (typeof timestamp !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(timestamp) || !Number.isFinite(Date.parse(timestamp))) {
805
+ invalid(`${label} must be an ISO-8601 date-time.`);
806
+ }
807
+ return timestamp;
808
+ }
809
+ function dependencyTimestamp(now) {
810
+ return isoTimestamp(now(), "now()");
811
+ }
812
+ function defaultNow() {
813
+ return (/* @__PURE__ */ new Date()).toISOString();
814
+ }
815
+ function createSecureArtifactReviewId(cryptoProvider = globalThis.crypto) {
816
+ const randomUuid = cryptoProvider?.randomUUID?.();
817
+ if (randomUuid) return randomUuid;
818
+ const bytes = new Uint8Array(16);
819
+ if (typeof cryptoProvider?.getRandomValues !== "function") {
820
+ throw new ArtifactReviewStateError(
821
+ "E_ARTIFACT_REVIEW_UUID_UNAVAILABLE",
822
+ "Secure UUID generation is unavailable in this browser."
823
+ );
824
+ }
825
+ cryptoProvider.getRandomValues(bytes);
826
+ bytes[6] = bytes[6] & 15 | 64;
827
+ bytes[8] = bytes[8] & 63 | 128;
828
+ const hex = [...bytes].map((value) => value.toString(16).padStart(2, "0")).join("");
829
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
830
+ }
831
+ function defaultCreateId() {
832
+ return createSecureArtifactReviewId();
833
+ }
834
+ function dependencyId(createId, kind) {
835
+ return boundedString(createId(kind), `${kind} id`, {
836
+ min: 1,
837
+ max: ARTIFACT_REVIEW_LIMITS.id,
838
+ trim: true
839
+ });
840
+ }
841
+ function uniqueDependencyId(createId, kind, existingIds) {
842
+ for (let attempt = 0; attempt < 100; attempt += 1) {
843
+ const candidate = dependencyId(createId, kind);
844
+ if (!existingIds.has(candidate)) return candidate;
845
+ }
846
+ throw new ArtifactReviewStateError(
847
+ "E_ARTIFACT_REVIEW_ID_COLLISION",
848
+ `Could not create a unique ${kind} id.`
849
+ );
850
+ }
851
+ function normalizeArtifactReviewIdentity(value, { allowEmpty = false } = {}) {
852
+ if (value === null || value === void 0 || value === "") {
853
+ if (allowEmpty) return null;
854
+ identityRequired();
855
+ }
856
+ const source = typeof value === "string" ? { name: value } : value;
857
+ if (!source || typeof source !== "object" || Array.isArray(source)) identityRequired();
858
+ const name = boundedString(source.name, "author.name", {
859
+ min: 1,
860
+ max: ARTIFACT_REVIEW_LIMITS.authorName,
861
+ trim: true
862
+ });
863
+ const id = optionalString(source.id, "author.id", {
864
+ min: 1,
865
+ max: ARTIFACT_REVIEW_LIMITS.id,
866
+ trim: true
867
+ });
868
+ return deepFreezeArtifactReview(id === void 0 ? { name } : { id, name });
869
+ }
870
+ function normalizeRegion(region) {
871
+ if (!region || typeof region !== "object" || Array.isArray(region)) {
872
+ invalid("pin.region must be an object.");
873
+ }
874
+ const unit = (value, label) => {
875
+ if (typeof value !== "number" || !Number.isFinite(value)) invalid(`${label} must be finite.`);
876
+ return Math.round(Math.min(1, Math.max(0, value)) * 1e6) / 1e6;
877
+ };
878
+ const x = unit(region.x, "pin.region.x");
879
+ const y = unit(region.y, "pin.region.y");
880
+ const w = Math.round(Math.min(unit(region.w, "pin.region.w"), 1 - x) * 1e6) / 1e6;
881
+ const h = Math.round(Math.min(unit(region.h, "pin.region.h"), 1 - y) * 1e6) / 1e6;
882
+ return { x, y, w, h };
883
+ }
884
+ function normalizeViewport(viewport) {
885
+ if (!viewport || typeof viewport !== "object" || Array.isArray(viewport)) {
886
+ invalid("pin.viewport must be an object.");
887
+ }
888
+ const dimension = (value, label) => {
889
+ if (!Number.isInteger(value) || value < 1 || value > ARTIFACT_REVIEW_LIMITS.viewport) {
890
+ invalid(`${label} must be an integer from 1 through ${ARTIFACT_REVIEW_LIMITS.viewport}.`);
891
+ }
892
+ return value;
893
+ };
894
+ return {
895
+ width: dimension(viewport.width, "pin.viewport.width"),
896
+ height: dimension(viewport.height, "pin.viewport.height")
897
+ };
898
+ }
899
+ function normalizeAnchor(anchor) {
900
+ if (anchor === void 0 || anchor === null) return void 0;
901
+ if (typeof anchor !== "object" || Array.isArray(anchor)) invalid("pin.anchor must be an object.");
902
+ const planrId = boundedString(anchor.planrId, "pin.anchor.planrId", {
903
+ min: 1,
904
+ max: ARTIFACT_REVIEW_LIMITS.anchor,
905
+ trim: true
906
+ });
907
+ const screen = optionalString(anchor.screen, "pin.anchor.screen", {
908
+ min: 1,
909
+ max: ARTIFACT_REVIEW_LIMITS.screen,
910
+ trim: true
911
+ });
912
+ return screen === void 0 ? { planrId } : { planrId, screen };
913
+ }
914
+ function normalizeReply(reply, label = "reply") {
915
+ if (!reply || typeof reply !== "object" || Array.isArray(reply)) invalid(`${label} must be an object.`);
916
+ return {
917
+ id: boundedString(reply.id, `${label}.id`, {
918
+ min: 1,
919
+ max: ARTIFACT_REVIEW_LIMITS.id,
920
+ trim: true
921
+ }),
922
+ author: normalizeArtifactReviewIdentity(reply.author),
923
+ comment: boundedString(reply.comment, `${label}.comment`, {
924
+ min: 1,
925
+ max: ARTIFACT_REVIEW_LIMITS.text,
926
+ trim: true
927
+ }),
928
+ createdAt: isoTimestamp(reply.createdAt, `${label}.createdAt`)
929
+ };
930
+ }
931
+ function compareTimestampThenId(left, right) {
932
+ const byTime = left.createdAt.localeCompare(right.createdAt);
933
+ return byTime === 0 ? left.id.localeCompare(right.id) : byTime;
934
+ }
935
+ function normalizePin(pin, label = "pin") {
936
+ if (!pin || typeof pin !== "object" || Array.isArray(pin)) invalid(`${label} must be an object.`);
937
+ if (!Array.isArray(pin.replies) || pin.replies.length > ARTIFACT_REVIEW_LIMITS.replies) {
938
+ invalid(`${label}.replies must contain no more than ${ARTIFACT_REVIEW_LIMITS.replies} items.`);
939
+ }
940
+ const replies = pin.replies.map((reply, index) => normalizeReply(reply, `${label}.replies[${index}]`));
941
+ const replyIds = new Set(replies.map(({ id }) => id));
942
+ if (replyIds.size !== replies.length) invalid(`${label}.replies must have unique ids.`);
943
+ const normalized3 = {
944
+ id: boundedString(pin.id, `${label}.id`, {
945
+ min: 1,
946
+ max: ARTIFACT_REVIEW_LIMITS.id,
947
+ trim: true
948
+ }),
949
+ author: normalizeArtifactReviewIdentity(pin.author),
950
+ artifactId: boundedString(pin.artifactId, `${label}.artifactId`, {
951
+ min: 1,
952
+ max: ARTIFACT_REVIEW_LIMITS.artifactId,
953
+ trim: true
954
+ }),
955
+ region: normalizeRegion(pin.region),
956
+ viewport: normalizeViewport(pin.viewport),
957
+ intent: enumValue(pin.intent, ARTIFACT_REVIEW_INTENTS, `${label}.intent`),
958
+ status: enumValue(pin.status, ARTIFACT_REVIEW_STATUSES, `${label}.status`),
959
+ comment: boundedString(pin.comment, `${label}.comment`, {
960
+ min: 1,
961
+ max: ARTIFACT_REVIEW_LIMITS.text,
962
+ trim: true
963
+ }),
964
+ replies: replies.sort(compareTimestampThenId),
965
+ createdAt: isoTimestamp(pin.createdAt, `${label}.createdAt`),
966
+ updatedAt: isoTimestamp(pin.updatedAt, `${label}.updatedAt`)
967
+ };
968
+ const variant = optionalString(pin.variant, `${label}.variant`, {
969
+ min: 1,
970
+ max: ARTIFACT_REVIEW_LIMITS.variant,
971
+ trim: true
972
+ });
973
+ const anchor = normalizeAnchor(pin.anchor);
974
+ if (variant !== void 0) normalized3.variant = variant;
975
+ if (anchor !== void 0) normalized3.anchor = anchor;
976
+ return normalized3;
977
+ }
978
+ function normalizeArtifactReview(review) {
979
+ if (!review || typeof review !== "object" || Array.isArray(review)) {
980
+ invalid("Artifact review must be an object.");
981
+ }
982
+ if (!Array.isArray(review.pins) || review.pins.length > ARTIFACT_REVIEW_LIMITS.pins) {
983
+ invalid(`review.pins must contain no more than ${ARTIFACT_REVIEW_LIMITS.pins} items.`);
984
+ }
985
+ const pins = review.pins.map((pin, index) => normalizePin(pin, `review.pins[${index}]`));
986
+ const pinIds = new Set(pins.map(({ id }) => id));
987
+ if (pinIds.size !== pins.length) invalid("review.pins must have unique ids.");
988
+ const normalized3 = {
989
+ schemaVersion: enumValue(review.schemaVersion, ["1.0.0"], "review.schemaVersion"),
990
+ reviewId: boundedString(review.reviewId, "review.reviewId", {
991
+ min: 1,
992
+ max: ARTIFACT_REVIEW_LIMITS.id,
993
+ trim: true
994
+ }),
995
+ reviewOf: boundedString(review.reviewOf, "review.reviewOf", {
996
+ min: 64,
997
+ max: 64,
998
+ pattern: REVIEW_OF_RE
999
+ }),
1000
+ decision: enumValue(review.decision, ARTIFACT_REVIEW_DECISIONS, "review.decision"),
1001
+ overall: boundedString(review.overall, "review.overall", {
1002
+ max: ARTIFACT_REVIEW_LIMITS.text
1003
+ }),
1004
+ pins: pins.sort(compareTimestampThenId)
1005
+ };
1006
+ if (review.createdAt !== void 0) normalized3.createdAt = isoTimestamp(review.createdAt, "review.createdAt");
1007
+ if (review.updatedAt !== void 0) normalized3.updatedAt = isoTimestamp(review.updatedAt, "review.updatedAt");
1008
+ return deepFreezeArtifactReview(normalized3);
1009
+ }
1010
+ function createArtifactReview({ reviewId, reviewOf, createId = defaultCreateId } = {}) {
1011
+ const normalizedReviewId = reviewId === void 0 ? dependencyId(createId, "review") : boundedString(reviewId, "reviewId", {
1012
+ min: 1,
1013
+ max: ARTIFACT_REVIEW_LIMITS.id,
1014
+ trim: true
1015
+ });
1016
+ return normalizeArtifactReview({
1017
+ schemaVersion: "1.0.0",
1018
+ reviewId: normalizedReviewId,
1019
+ reviewOf: boundedString(reviewOf, "reviewOf", {
1020
+ min: 64,
1021
+ max: 64,
1022
+ pattern: REVIEW_OF_RE
1023
+ }),
1024
+ decision: "pending",
1025
+ overall: "",
1026
+ pins: []
1027
+ });
1028
+ }
1029
+ function replacePin(review, pin) {
1030
+ return review.pins.map((candidate) => candidate.id === pin.id ? pin : candidate);
1031
+ }
1032
+ function findPin(review, pinId) {
1033
+ const normalizedId = boundedString(pinId, "pinId", {
1034
+ min: 1,
1035
+ max: ARTIFACT_REVIEW_LIMITS.id,
1036
+ trim: true
1037
+ });
1038
+ const pin = review.pins.find(({ id }) => id === normalizedId);
1039
+ if (!pin) {
1040
+ throw new ArtifactReviewStateError("E_ARTIFACT_REVIEW_PIN_NOT_FOUND", `Unknown feedback pin: ${normalizedId}`);
1041
+ }
1042
+ return pin;
1043
+ }
1044
+ function preserveOptionalReviewTimestamps(review, next, timestamp) {
1045
+ if (review.createdAt !== void 0) next.createdAt = review.createdAt;
1046
+ if (review.updatedAt !== void 0) next.updatedAt = timestamp;
1047
+ return next;
1048
+ }
1049
+ function reduceArtifactReview(review, action, {
1050
+ createId = defaultCreateId,
1051
+ now = defaultNow
1052
+ } = {}) {
1053
+ const current = normalizeArtifactReview(review);
1054
+ if (!action || typeof action !== "object" || Array.isArray(action)) invalid("Review action must be an object.");
1055
+ const timestamp = dependencyTimestamp(now);
1056
+ let next;
1057
+ switch (action.type) {
1058
+ case "add-pin": {
1059
+ if (current.pins.length >= ARTIFACT_REVIEW_LIMITS.pins) {
1060
+ invalid(`A review can contain at most ${ARTIFACT_REVIEW_LIMITS.pins} pins.`);
1061
+ }
1062
+ const author = normalizeArtifactReviewIdentity(action.author);
1063
+ const pinInput = action.pin && typeof action.pin === "object" ? action.pin : {};
1064
+ const pinId = pinInput.id === void 0 ? uniqueDependencyId(createId, "pin", new Set(current.pins.map(({ id }) => id))) : boundedString(pinInput.id, "pin.id", {
1065
+ min: 1,
1066
+ max: ARTIFACT_REVIEW_LIMITS.id,
1067
+ trim: true
1068
+ });
1069
+ if (current.pins.some(({ id }) => id === pinId)) {
1070
+ throw new ArtifactReviewStateError("E_ARTIFACT_REVIEW_ID_COLLISION", `Duplicate pin id: ${pinId}`);
1071
+ }
1072
+ const pin = normalizePin({
1073
+ ...pinInput,
1074
+ id: pinId,
1075
+ author,
1076
+ status: pinInput.status ?? "open",
1077
+ replies: [],
1078
+ createdAt: pinInput.createdAt ?? timestamp,
1079
+ updatedAt: pinInput.updatedAt ?? timestamp
1080
+ });
1081
+ next = preserveOptionalReviewTimestamps(current, {
1082
+ ...current,
1083
+ pins: [...current.pins, pin]
1084
+ }, timestamp);
1085
+ break;
1086
+ }
1087
+ case "add-reply": {
1088
+ const pin = findPin(current, action.pinId);
1089
+ if (pin.replies.length >= ARTIFACT_REVIEW_LIMITS.replies) {
1090
+ invalid(`A feedback thread can contain at most ${ARTIFACT_REVIEW_LIMITS.replies} replies.`);
1091
+ }
1092
+ const replyId = action.id === void 0 ? uniqueDependencyId(createId, "reply", new Set(pin.replies.map(({ id }) => id))) : boundedString(action.id, "reply.id", {
1093
+ min: 1,
1094
+ max: ARTIFACT_REVIEW_LIMITS.id,
1095
+ trim: true
1096
+ });
1097
+ if (pin.replies.some(({ id }) => id === replyId)) {
1098
+ throw new ArtifactReviewStateError("E_ARTIFACT_REVIEW_ID_COLLISION", `Duplicate reply id: ${replyId}`);
1099
+ }
1100
+ const reply = normalizeReply({
1101
+ id: replyId,
1102
+ author: normalizeArtifactReviewIdentity(action.author),
1103
+ comment: action.comment,
1104
+ createdAt: action.createdAt ?? timestamp
1105
+ });
1106
+ const updatedPin = normalizePin({
1107
+ ...pin,
1108
+ replies: [...pin.replies, reply],
1109
+ updatedAt: timestamp
1110
+ });
1111
+ next = preserveOptionalReviewTimestamps(current, {
1112
+ ...current,
1113
+ pins: replacePin(current, updatedPin)
1114
+ }, timestamp);
1115
+ break;
1116
+ }
1117
+ case "set-status": {
1118
+ const pin = findPin(current, action.pinId);
1119
+ const updatedPin = normalizePin({
1120
+ ...pin,
1121
+ status: enumValue(action.status, ARTIFACT_REVIEW_STATUSES, "status"),
1122
+ updatedAt: timestamp
1123
+ });
1124
+ next = preserveOptionalReviewTimestamps(current, {
1125
+ ...current,
1126
+ pins: replacePin(current, updatedPin)
1127
+ }, timestamp);
1128
+ break;
1129
+ }
1130
+ case "set-overall":
1131
+ next = preserveOptionalReviewTimestamps(current, {
1132
+ ...current,
1133
+ overall: boundedString(action.overall, "overall", { max: ARTIFACT_REVIEW_LIMITS.text })
1134
+ }, timestamp);
1135
+ break;
1136
+ case "set-decision":
1137
+ next = preserveOptionalReviewTimestamps(current, {
1138
+ ...current,
1139
+ decision: enumValue(action.decision, ARTIFACT_REVIEW_DECISIONS, "decision")
1140
+ }, timestamp);
1141
+ break;
1142
+ default:
1143
+ throw new ArtifactReviewStateError(
1144
+ "E_ARTIFACT_REVIEW_ACTION_UNKNOWN",
1145
+ `Unknown artifact review action: ${String(action.type)}`
1146
+ );
1147
+ }
1148
+ return normalizeArtifactReview(next);
1149
+ }
1150
+ function createArtifactReviewController({
1151
+ initialReview = null,
1152
+ reviewOf,
1153
+ reviewId,
1154
+ identity = null,
1155
+ createId = defaultCreateId,
1156
+ now = defaultNow
1157
+ } = {}) {
1158
+ let review = initialReview === null || initialReview === void 0 ? null : normalizeArtifactReview(initialReview);
1159
+ if (review && reviewOf !== void 0 && review.reviewOf !== reviewOf) {
1160
+ throw new ArtifactReviewStateError(
1161
+ "E_ARTIFACT_REVIEW_DIGEST_MISMATCH",
1162
+ "The initial review does not match the artifact envelope digest."
1163
+ );
1164
+ }
1165
+ let localIdentity = normalizeArtifactReviewIdentity(identity, { allowEmpty: true });
1166
+ let activePinId = null;
1167
+ let destroyed = false;
1168
+ const listeners = /* @__PURE__ */ new Set();
1169
+ const assertAlive = () => {
1170
+ if (destroyed) {
1171
+ throw new ArtifactReviewStateError("E_ARTIFACT_REVIEW_DESTROYED", "Artifact review controller is destroyed.");
1172
+ }
1173
+ };
1174
+ const ensureReview = () => {
1175
+ review ??= createArtifactReview({ reviewId, reviewOf, createId });
1176
+ return review;
1177
+ };
1178
+ const getState = () => deepFreezeArtifactReview({
1179
+ review,
1180
+ identity: localIdentity,
1181
+ activePinId
1182
+ });
1183
+ const notify = (change) => {
1184
+ const state = getState();
1185
+ for (const listener of [...listeners]) listener(state, deepFreezeArtifactReview({ ...change }));
1186
+ };
1187
+ const controller = {
1188
+ getReview() {
1189
+ return review;
1190
+ },
1191
+ getState,
1192
+ getIdentity() {
1193
+ return localIdentity;
1194
+ },
1195
+ setIdentity(value) {
1196
+ assertAlive();
1197
+ localIdentity = normalizeArtifactReviewIdentity(value, { allowEmpty: true });
1198
+ notify({ type: "identity" });
1199
+ return localIdentity;
1200
+ },
1201
+ dispatch(action) {
1202
+ assertAlive();
1203
+ const authored = action?.type === "add-pin" || action?.type === "add-reply";
1204
+ const nextAction = authored && action.author === void 0 ? { ...action, author: localIdentity ?? identityRequired() } : action;
1205
+ const previousPinIds = nextAction?.type === "add-pin" ? new Set(review?.pins.map(({ id }) => id) ?? []) : null;
1206
+ review = reduceArtifactReview(ensureReview(), nextAction, { createId, now });
1207
+ if (previousPinIds) {
1208
+ activePinId = review.pins.find(({ id }) => !previousPinIds.has(id))?.id ?? activePinId;
1209
+ }
1210
+ notify({ type: "review", action: nextAction.type });
1211
+ return review;
1212
+ },
1213
+ replaceReview(value) {
1214
+ assertAlive();
1215
+ const next = value === null || value === void 0 ? null : normalizeArtifactReview(value);
1216
+ if (next && reviewOf !== void 0 && next.reviewOf !== reviewOf) {
1217
+ throw new ArtifactReviewStateError(
1218
+ "E_ARTIFACT_REVIEW_DIGEST_MISMATCH",
1219
+ "The replacement review does not match the artifact envelope digest."
1220
+ );
1221
+ }
1222
+ review = next;
1223
+ if (activePinId && !review?.pins.some(({ id }) => id === activePinId)) activePinId = null;
1224
+ notify({ type: "review-replaced" });
1225
+ return review;
1226
+ },
1227
+ selectPin(pinId) {
1228
+ assertAlive();
1229
+ if (pinId === null || pinId === void 0) {
1230
+ activePinId = null;
1231
+ } else {
1232
+ activePinId = findPin(ensureReview(), pinId).id;
1233
+ }
1234
+ notify({ type: "selection" });
1235
+ return activePinId;
1236
+ },
1237
+ subscribe(listener) {
1238
+ assertAlive();
1239
+ if (typeof listener !== "function") invalid("Review subscriber must be a function.");
1240
+ listeners.add(listener);
1241
+ return () => listeners.delete(listener);
1242
+ },
1243
+ destroy() {
1244
+ if (destroyed) return;
1245
+ destroyed = true;
1246
+ listeners.clear();
1247
+ review = null;
1248
+ localIdentity = null;
1249
+ activePinId = null;
1250
+ }
1251
+ };
1252
+ return Object.freeze(controller);
1253
+ }
1254
+ function createElement(document2, tagName, { className, text: text3, attributes = {} } = {}) {
1255
+ const element = document2.createElement(tagName);
1256
+ if (className) element.className = className;
1257
+ if (text3 !== void 0) element.textContent = text3;
1258
+ for (const [name, value] of Object.entries(attributes)) {
1259
+ if (value !== void 0 && value !== null) element.setAttribute(name, String(value));
1260
+ }
1261
+ return element;
1262
+ }
1263
+ function artifactReviewThreadDomId(pinId) {
1264
+ return annotationDomIds(pinId).thread;
1265
+ }
1266
+ function displayTimestamp(timestamp) {
1267
+ const canonical = new Date(timestamp).toISOString();
1268
+ return `${canonical.slice(0, 10)} ${canonical.slice(11, 16)} UTC`;
1269
+ }
1270
+ function renderReply(document2, reply) {
1271
+ const item = createElement(document2, "li", { className: "planr-reply", attributes: { "data-planr-reply-id": reply.id } });
1272
+ const heading = createElement(document2, "header");
1273
+ heading.append(createElement(document2, "strong", { text: reply.author.name }));
1274
+ const time = createElement(document2, "time", {
1275
+ text: displayTimestamp(reply.createdAt),
1276
+ attributes: { datetime: reply.createdAt }
1277
+ });
1278
+ heading.append(time);
1279
+ item.append(heading, createElement(document2, "p", { text: reply.comment }));
1280
+ return item;
1281
+ }
1282
+ function renderReplyForm(document2, pin, expanded = false) {
1283
+ const fieldId = `${annotationDomIds(pin.id).thread}-reply`;
1284
+ const wrapper = createElement(document2, "div", { className: "planr-reply-editor" });
1285
+ const toggle = createElement(document2, "button", {
1286
+ className: "planr-reply-toggle",
1287
+ text: expanded ? "− Reply" : "+ Reply",
1288
+ attributes: {
1289
+ type: "button",
1290
+ id: `${fieldId}-toggle`,
1291
+ "data-planr-reply-toggle": pin.id,
1292
+ "aria-expanded": String(expanded),
1293
+ "aria-controls": `${fieldId}-form`,
1294
+ title: expanded ? "Collapse reply" : "Reply to this comment"
1295
+ }
1296
+ });
1297
+ const form = createElement(document2, "form", {
1298
+ className: "planr-reply-form",
1299
+ attributes: { "data-planr-reply-form": pin.id, id: `${fieldId}-form`, ...expanded ? {} : { hidden: "" } }
1300
+ });
1301
+ const label = createElement(document2, "label", {
1302
+ className: "planr-reply-label",
1303
+ text: "Reply to thread",
1304
+ attributes: { for: fieldId }
1305
+ });
1306
+ const textarea = createElement(document2, "textarea", {
1307
+ attributes: {
1308
+ id: fieldId,
1309
+ name: "reply",
1310
+ maxlength: ARTIFACT_REVIEW_LIMITS.text,
1311
+ rows: 2,
1312
+ placeholder: "Write a reply…",
1313
+ required: "",
1314
+ "aria-describedby": "planr-review-error"
1315
+ }
1316
+ });
1317
+ const controls = createElement(document2, "div", { className: "planr-reply-controls" });
1318
+ const hint = createElement(document2, "span", { className: "planr-reply-hint", text: "Ctrl/⌘ + Enter to send" });
1319
+ const submit = createElement(document2, "button", {
1320
+ className: "planr-reply-send",
1321
+ attributes: { type: "submit", disabled: "", "aria-label": "Send reply", title: "Send reply (Ctrl/⌘ + Enter)" }
1322
+ });
1323
+ const svg = document2.createElementNS("http://www.w3.org/2000/svg", "svg");
1324
+ for (const [name, value] of Object.entries({ viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "currentColor", "stroke-width": "1.8", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", focusable: "false" })) svg.setAttribute(name, value);
1325
+ const path = document2.createElementNS("http://www.w3.org/2000/svg", "path");
1326
+ path.setAttribute("d", "M12 19V5m-6 6 6-6 6 6");
1327
+ svg.append(path);
1328
+ submit.append(svg);
1329
+ controls.append(hint, submit);
1330
+ form.append(label, textarea, controls);
1331
+ wrapper.append(toggle, form);
1332
+ return wrapper;
1333
+ }
1334
+ function renderThread(document2, pin, active, description = {}) {
1335
+ const intentLabel = typeof description.intentLabel === "string" ? description.intentLabel.slice(0, 128) : pin.intent;
1336
+ const article = createElement(document2, "article", {
1337
+ className: `planr-thread${active ? " is-active" : ""}`,
1338
+ attributes: {
1339
+ id: artifactReviewThreadDomId(pin.id),
1340
+ tabindex: "-1",
1341
+ "data-planr-pin-id": pin.id,
1342
+ "data-planr-intent": pin.intent,
1343
+ "data-planr-status": pin.status,
1344
+ "aria-controls": annotationDomIds(pin.id).pin,
1345
+ "aria-label": `${intentLabel} comment by ${pin.author.name}`,
1346
+ "data-planr-unread": description.unread === true ? "true" : "false",
1347
+ ...description.compact ? { "data-planr-compact": "true" } : {}
1348
+ }
1349
+ });
1350
+ const header = createElement(document2, "header");
1351
+ const byline = createElement(document2, "div", { className: "planr-review-byline" });
1352
+ byline.append(
1353
+ createElement(document2, "strong", { text: pin.author.name }),
1354
+ createElement(document2, "span", { className: "planr-intent", text: intentLabel })
1355
+ );
1356
+ const time = createElement(document2, "time", {
1357
+ text: description.compact ? `${new Date(pin.createdAt).toISOString().slice(11, 16)} UTC` : displayTimestamp(pin.createdAt),
1358
+ attributes: { datetime: pin.createdAt, title: displayTimestamp(pin.createdAt) }
1359
+ });
1360
+ header.append(byline, time);
1361
+ const comment = createElement(document2, "p", {
1362
+ className: "planr-thread-comment",
1363
+ text: pin.comment
1364
+ });
1365
+ const lifecycle = createElement(document2, "div", { className: "planr-thread-actions" });
1366
+ lifecycle.append(
1367
+ createElement(document2, "span", { className: "planr-thread-status", text: pin.status, attributes: { title: `Status: ${pin.status}` } }),
1368
+ createElement(document2, "button", {
1369
+ text: pin.status === "resolved" ? "Reopen" : "Resolve",
1370
+ attributes: {
1371
+ type: "button",
1372
+ "data-planr-thread-action": pin.status === "resolved" ? "reopen" : "resolve",
1373
+ "data-planr-pin-id": pin.id
1374
+ }
1375
+ }),
1376
+ createElement(document2, "button", {
1377
+ text: "Show pin",
1378
+ attributes: {
1379
+ type: "button",
1380
+ "data-planr-thread-focus": pin.id,
1381
+ "aria-controls": annotationDomIds(pin.id).pin
1382
+ }
1383
+ })
1384
+ );
1385
+ const replies = createElement(document2, "ol", {
1386
+ className: "planr-replies",
1387
+ attributes: { "aria-label": "Replies" }
1388
+ });
1389
+ const earlierReplies = description.compact ? Math.max(0, pin.replies.length - (description.replyLimit || 2)) : 0;
1390
+ for (const reply of pin.replies.slice(earlierReplies)) replies.append(renderReply(document2, reply));
1391
+ const editor = renderReplyForm(document2, pin, description.replyExpanded);
1392
+ article.append(header, comment);
1393
+ if (description.compact && pin.comment.length > 240) {
1394
+ comment.dataset.planrCommentCollapsed = String(!description.commentExpanded);
1395
+ article.append(createElement(document2, "button", { className: "planr-comment-expand", text: description.commentExpanded ? "Show less" : "Read full comment", attributes: { type: "button", id: `${annotationDomIds(pin.id).thread}-expand`, "data-planr-comment-expand": pin.id, "aria-expanded": String(Boolean(description.commentExpanded)) } }));
1396
+ }
1397
+ if (earlierReplies) article.append(createElement(document2, "button", { className: "planr-history-expand", text: `Show ${earlierReplies} earlier ${earlierReplies === 1 ? "reply" : "replies"}`, attributes: { type: "button", id: `${annotationDomIds(pin.id).thread}-history`, "data-planr-history-expand": pin.id, "aria-expanded": "false" } }));
1398
+ if (pin.replies.length) article.append(replies);
1399
+ if (description.compact) {
1400
+ lifecycle.append(editor.querySelector("[data-planr-reply-toggle]"));
1401
+ article.append(lifecycle, editor);
1402
+ } else article.append(lifecycle, editor);
1403
+ return article;
1404
+ }
1405
+ function decisionCopy(decision) {
1406
+ if (decision === "approved") return "Review approved";
1407
+ if (decision === "changes_requested") return "Changes requested";
1408
+ return "Decision pending";
1409
+ }
1410
+ function mountArtifactFeedbackRail({
1411
+ root,
1412
+ document: document2 = root?.ownerDocument,
1413
+ window = document2?.defaultView,
1414
+ controller: providedController,
1415
+ initialReview = null,
1416
+ reviewOf,
1417
+ reviewId,
1418
+ identity = null,
1419
+ createId = defaultCreateId,
1420
+ now = defaultNow,
1421
+ onSelectPin,
1422
+ presentation: initialPresentation = {}
1423
+ } = {}) {
1424
+ if (!root || !document2 || !window) invalid("A browser root, document, and window are required.");
1425
+ const slot = root.querySelector('[data-planr-slot="feedback-rail"]');
1426
+ const identityInput = root.querySelector("[data-planr-reviewer-name]");
1427
+ const identityStatus = root.querySelector("[data-planr-identity-status]");
1428
+ const overall = root.querySelector("#planr-overall-note");
1429
+ const decisionStatus = root.querySelector('[data-planr-slot="decision-status"]');
1430
+ const decisionButtons = [...root.querySelectorAll("[data-planr-decision]")];
1431
+ if (!slot || !identityInput || !overall || !decisionStatus || decisionButtons.length === 0) {
1432
+ invalid("Artifact feedback renderer slots are missing.");
1433
+ }
1434
+ const ownsController = !providedController;
1435
+ const controller = providedController ?? createArtifactReviewController({
1436
+ initialReview,
1437
+ reviewOf,
1438
+ reviewId,
1439
+ identity,
1440
+ createId,
1441
+ now
1442
+ });
1443
+ let destroyed = false;
1444
+ let presentation = { ...initialPresentation };
1445
+ const replyDrafts = /* @__PURE__ */ new Map();
1446
+ const expandedReplies = /* @__PURE__ */ new Set();
1447
+ const expandedHistory = /* @__PURE__ */ new Map(), expandedComments = /* @__PURE__ */ new Set();
1448
+ let visibleLimit = Number.isInteger(initialPresentation.pageSize) ? initialPresentation.pageSize : Infinity;
1449
+ const extraDrafts = /* @__PURE__ */ new Map();
1450
+ let overallDirty = false;
1451
+ let composing = false;
1452
+ let renderQueued = false;
1453
+ const captureDrafts = () => {
1454
+ for (const form of slot.querySelectorAll("[data-planr-reply-form]")) {
1455
+ const field = form.elements.namedItem("reply");
1456
+ if (field) replyDrafts.set(form.dataset.planrReplyForm, field.value);
1457
+ }
1458
+ for (const field of slot.querySelectorAll("[data-planr-draft-key]")) {
1459
+ if (typeof field.value === "string") extraDrafts.set(field.dataset.planrDraftKey, field.value);
1460
+ }
1461
+ };
1462
+ const snapshotDrafts = () => {
1463
+ captureDrafts();
1464
+ return cloneFrozenArtifactReview({
1465
+ reviewOf: controller.getReview()?.reviewOf ?? reviewOf,
1466
+ replies: Object.fromEntries(replyDrafts),
1467
+ expandedReplies: [...expandedReplies],
1468
+ fields: Object.fromEntries(extraDrafts),
1469
+ overall: { value: overall.value, dirty: overallDirty },
1470
+ identity: identityInput.value
1471
+ });
1472
+ };
1473
+ const emitDraftChange = () => root.dispatchEvent(new window.CustomEvent(ARTIFACT_REVIEW_DRAFT_CHANGE_EVENT, { bubbles: true, detail: snapshotDrafts() }));
1474
+ const focusDescriptor = () => {
1475
+ const element = document2.activeElement;
1476
+ if (!element || !slot.contains(element)) return null;
1477
+ const thread = element.closest("[data-planr-pin-id]");
1478
+ return {
1479
+ id: element.id,
1480
+ pinId: thread?.dataset.planrPinId,
1481
+ draftKey: element.dataset.planrDraftKey,
1482
+ action: element.dataset.planrThreadAction,
1483
+ showPin: element.dataset.planrThreadFocus,
1484
+ tag: element.tagName,
1485
+ name: element.name,
1486
+ start: element.selectionStart,
1487
+ end: element.selectionEnd,
1488
+ direction: element.selectionDirection
1489
+ };
1490
+ };
1491
+ const restoreFocus = (descriptor) => {
1492
+ if (!descriptor) return;
1493
+ const thread = descriptor.pinId && document2.getElementById(artifactReviewThreadDomId(descriptor.pinId));
1494
+ const target = descriptor.id && document2.getElementById(descriptor.id) || descriptor.draftKey && [...slot.querySelectorAll("[data-planr-draft-key]")].find((field) => field.dataset.planrDraftKey === descriptor.draftKey) || descriptor.action && [...thread?.querySelectorAll("[data-planr-thread-action]") ?? []].find((button) => button.dataset.planrThreadAction === descriptor.action) || descriptor.showPin && thread?.querySelector("[data-planr-thread-focus]") || [...thread?.querySelectorAll("button,input,select,textarea") ?? []].find((field) => field.tagName === descriptor.tag && field.name === descriptor.name);
1495
+ target?.focus?.({ preventScroll: true });
1496
+ if (Number.isInteger(descriptor.start)) target?.setSelectionRange?.(descriptor.start, descriptor.end, descriptor.direction);
1497
+ };
1498
+ const showError = (error) => {
1499
+ const target = root.querySelector("#planr-review-error");
1500
+ if (!target) return;
1501
+ target.textContent = error?.message ?? String(error);
1502
+ target.hidden = false;
1503
+ };
1504
+ const clearError = () => {
1505
+ const target = root.querySelector("#planr-review-error");
1506
+ if (!target) return;
1507
+ target.textContent = "";
1508
+ target.hidden = true;
1509
+ };
1510
+ const announce2 = (message) => {
1511
+ decisionStatus.textContent = message;
1512
+ const live = root.parentElement?.querySelector('[data-planr-slot="review-announcer"]') ?? document2.querySelector('[data-planr-slot="review-announcer"]');
1513
+ if (live) live.textContent = message;
1514
+ };
1515
+ const updateCounts = (pins) => {
1516
+ const label = `${pins.length} ${pins.length === 1 ? "comment" : "comments"}`;
1517
+ for (const count2 of root.querySelectorAll('[data-planr-action="feedback"] .planr-count, .planr-review-rail > header .planr-count')) {
1518
+ count2.textContent = String(pins.length);
1519
+ count2.setAttribute("aria-label", label);
1520
+ }
1521
+ const commentsButton = root.querySelector('[data-planr-action="feedback"]');
1522
+ commentsButton?.setAttribute("aria-label", commentsButton.dataset.planrReviewLabel || label);
1523
+ if (commentsButton?.dataset.planrReviewLabel) commentsButton.setAttribute("aria-description", label);
1524
+ };
1525
+ const render = ({ capture = true } = {}) => {
1526
+ if (composing) {
1527
+ renderQueued = true;
1528
+ return;
1529
+ }
1530
+ if (capture) captureDrafts();
1531
+ const focus = focusDescriptor();
1532
+ const scroll = [];
1533
+ for (let node = slot; node && root.contains(node); node = node.parentElement) scroll.push([node, node.scrollTop, node.scrollLeft]);
1534
+ const state = controller.getState();
1535
+ const { review, activePinId } = state;
1536
+ const allPins = review?.pins ?? [];
1537
+ const pins = typeof presentation.filterPin === "function" ? allPins.filter((pin) => presentation.filterPin(pin, state)) : allPins;
1538
+ const activeIndex = pins.findIndex((pin) => pin.id === activePinId);
1539
+ const visiblePins = pins.slice(0, visibleLimit);
1540
+ if (activeIndex >= visibleLimit) visiblePins.push(pins[activeIndex]);
1541
+ const fragment = document2.createDocumentFragment();
1542
+ const list = createElement(document2, "div", {
1543
+ className: "planr-thread-list",
1544
+ attributes: { "aria-label": "Comment threads" }
1545
+ });
1546
+ if (pins.length === 0) {
1547
+ list.append(createElement(document2, "p", {
1548
+ className: "planr-review-empty",
1549
+ text: typeof presentation.emptyMessage === "string" ? presentation.emptyMessage : allPins.length ? "No comments match these filters." : "No comments yet. Choose Add comment, then select a point or region in the artifact."
1550
+ }));
1551
+ } else {
1552
+ for (const pin of visiblePins) {
1553
+ const thread = renderThread(document2, pin, pin.id === activePinId, { ...presentation.describePin?.(pin, state), compact: presentation.compact === true, replyLimit: expandedHistory.get(pin.id) || 2, commentExpanded: expandedComments.has(pin.id), replyExpanded: expandedReplies.has(pin.id) });
1554
+ presentation.decorateThread?.({ element: thread, pin, state, document: document2 });
1555
+ const reply = thread.querySelector('[name="reply"]');
1556
+ if (replyDrafts.has(pin.id)) reply.value = replyDrafts.get(pin.id);
1557
+ thread.querySelector(".planr-reply-send").disabled = !reply.value.trim();
1558
+ for (const field of thread.querySelectorAll("[data-planr-draft-key]")) {
1559
+ if (extraDrafts.has(field.dataset.planrDraftKey)) field.value = extraDrafts.get(field.dataset.planrDraftKey);
1560
+ }
1561
+ list.append(thread);
1562
+ }
1563
+ }
1564
+ if (pins.length > visibleLimit) list.append(createElement(document2, "button", { className: "planr-threads-more", text: `Show more comments · ${Math.min(visibleLimit, pins.length)} of ${pins.length}`, attributes: { type: "button", "data-planr-threads-more": "" } }));
1565
+ fragment.append(list);
1566
+ slot.replaceChildren(fragment);
1567
+ const identityName2 = controller.getIdentity()?.name ?? "";
1568
+ if (document2.activeElement !== identityInput) identityInput.value = identityName2;
1569
+ if (identityStatus) {
1570
+ identityStatus.dataset.planrIdentityReady = String(Boolean(identityName2));
1571
+ identityStatus.textContent = identityName2 ? `Comments will appear as ${identityName2}.` : "Used to sign your comments.";
1572
+ }
1573
+ overall.maxLength = ARTIFACT_REVIEW_LIMITS.text;
1574
+ if (!overallDirty && document2.activeElement !== overall) overall.value = review?.overall ?? "";
1575
+ for (const button of decisionButtons) {
1576
+ button.setAttribute("aria-pressed", String(button.dataset.planrDecision === (review?.decision ?? "pending")));
1577
+ }
1578
+ decisionStatus.textContent = decisionCopy(review?.decision ?? "pending");
1579
+ updateCounts(allPins);
1580
+ restoreFocus(focus);
1581
+ for (const [node, top, left] of scroll) {
1582
+ node.scrollTop = top;
1583
+ node.scrollLeft = left;
1584
+ }
1585
+ const openMetric = root.querySelector('[data-planr-metric="open"]');
1586
+ if (openMetric) openMetric.textContent = `${allPins.filter(({ status }) => status !== "resolved").length} open`;
1587
+ };
1588
+ const focusThread = (pinId) => {
1589
+ const thread = document2.getElementById(artifactReviewThreadDomId(pinId));
1590
+ thread?.focus({ preventScroll: true });
1591
+ thread?.scrollIntoView?.({ block: "nearest" });
1592
+ };
1593
+ const emitReview = (review) => {
1594
+ const detail = cloneFrozenArtifactReview(review);
1595
+ root.dispatchEvent(new window.CustomEvent(ARTIFACT_REVIEW_CHANGE_EVENT, {
1596
+ detail,
1597
+ bubbles: true
1598
+ }));
1599
+ };
1600
+ const unsubscribe = controller.subscribe((state, change) => {
1601
+ if (destroyed) return;
1602
+ if (["review", "review-replaced", "selection"].includes(change.type)) render();
1603
+ if (["review", "review-replaced"].includes(change.type) && state.review) emitReview(state.review);
1604
+ });
1605
+ const onInput = (event) => {
1606
+ if (event.target !== identityInput) return;
1607
+ try {
1608
+ controller.setIdentity(event.target.value ? { name: event.target.value } : null);
1609
+ const name = controller.getIdentity()?.name ?? "";
1610
+ if (identityStatus) {
1611
+ identityStatus.dataset.planrIdentityReady = String(Boolean(name));
1612
+ identityStatus.textContent = name ? `Comments will appear as ${name}.` : "Used to sign your comments.";
1613
+ }
1614
+ clearError();
1615
+ } catch (error) {
1616
+ showError(error);
1617
+ }
1618
+ };
1619
+ const setReplyExpanded = (pinId, expanded, { focus = false } = {}) => {
1620
+ const thread = document2.getElementById(artifactReviewThreadDomId(pinId));
1621
+ const form = thread?.querySelector("[data-planr-reply-form]");
1622
+ const toggle = thread?.querySelector("[data-planr-reply-toggle]");
1623
+ if (!form || !toggle) return;
1624
+ if (expanded) expandedReplies.add(pinId);
1625
+ else expandedReplies.delete(pinId);
1626
+ form.hidden = !expanded;
1627
+ toggle.setAttribute("aria-expanded", String(expanded));
1628
+ toggle.textContent = expanded ? "− Reply" : "+ Reply";
1629
+ toggle.title = expanded ? "Collapse reply" : "Reply to this comment";
1630
+ if (focus) (expanded ? form.elements.namedItem("reply") : toggle).focus({ preventScroll: true });
1631
+ emitDraftChange();
1632
+ };
1633
+ const onKeyDown = (event) => {
1634
+ const form = event.target?.closest?.("[data-planr-reply-form]");
1635
+ if (!form || event.isComposing) return;
1636
+ if (event.key === "Escape") {
1637
+ event.preventDefault();
1638
+ event.stopPropagation();
1639
+ setReplyExpanded(form.dataset.planrReplyForm, false, { focus: true });
1640
+ } else if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
1641
+ event.preventDefault();
1642
+ if (form.elements.namedItem("reply").value.trim()) form.requestSubmit();
1643
+ }
1644
+ };
1645
+ const emitSelection = (pinId) => {
1646
+ controller.selectPin(pinId);
1647
+ root.dispatchEvent(new window.CustomEvent(ARTIFACT_REVIEW_SELECT_EVENT, {
1648
+ detail: deepFreezeArtifactReview({ pinId, source: "thread" }),
1649
+ bubbles: true
1650
+ }));
1651
+ onSelectPin?.(pinId);
1652
+ };
1653
+ const onClick = (event) => {
1654
+ if (event.target.closest?.("[data-planr-threads-more]")) {
1655
+ visibleLimit += presentation.pageSize || 40;
1656
+ render();
1657
+ return;
1658
+ }
1659
+ const historyToggle = event.target.closest?.("[data-planr-history-expand]");
1660
+ if (historyToggle) {
1661
+ const id = historyToggle.dataset.planrHistoryExpand;
1662
+ expandedHistory.set(id, (expandedHistory.get(id) || 2) + 20);
1663
+ render();
1664
+ return;
1665
+ }
1666
+ const commentToggle = event.target.closest?.("[data-planr-comment-expand]");
1667
+ if (commentToggle) {
1668
+ const id = commentToggle.dataset.planrCommentExpand;
1669
+ if (expandedComments.has(id)) expandedComments.delete(id);
1670
+ else expandedComments.add(id);
1671
+ render();
1672
+ return;
1673
+ }
1674
+ const replyToggle = event.target?.closest?.("[data-planr-reply-toggle]");
1675
+ if (replyToggle) {
1676
+ setReplyExpanded(replyToggle.dataset.planrReplyToggle, replyToggle.getAttribute("aria-expanded") !== "true", { focus: true });
1677
+ return;
1678
+ }
1679
+ const action = event.target?.closest?.("[data-planr-thread-action]");
1680
+ const focus = event.target?.closest?.("[data-planr-thread-focus]");
1681
+ if (action) {
1682
+ try {
1683
+ const pinId = action.dataset.planrPinId;
1684
+ controller.dispatch({
1685
+ type: "set-status",
1686
+ pinId,
1687
+ status: action.dataset.planrThreadAction === "resolve" ? "resolved" : "open"
1688
+ });
1689
+ announce2(action.dataset.planrThreadAction === "resolve" ? "Comment resolved" : "Comment reopened");
1690
+ focusThread(pinId);
1691
+ clearError();
1692
+ } catch (error) {
1693
+ showError(error);
1694
+ }
1695
+ return;
1696
+ }
1697
+ if (focus) emitSelection(focus.dataset.planrThreadFocus);
1698
+ };
1699
+ const onSubmit = (event) => {
1700
+ const form = event.target?.closest?.("[data-planr-reply-form]");
1701
+ if (!form) return;
1702
+ event.preventDefault();
1703
+ const textarea = form.elements.namedItem("reply");
1704
+ const comment = textarea.value;
1705
+ if (!comment.trim()) return;
1706
+ const wasExpanded = expandedReplies.has(form.dataset.planrReplyForm);
1707
+ try {
1708
+ textarea.setAttribute("aria-invalid", "false");
1709
+ textarea.value = "";
1710
+ replyDrafts.delete(form.dataset.planrReplyForm);
1711
+ expandedReplies.delete(form.dataset.planrReplyForm);
1712
+ controller.dispatch({
1713
+ type: "add-reply",
1714
+ pinId: form.dataset.planrReplyForm,
1715
+ comment
1716
+ });
1717
+ emitDraftChange();
1718
+ announce2("Reply added");
1719
+ focusThread(form.dataset.planrReplyForm);
1720
+ clearError();
1721
+ } catch (error) {
1722
+ textarea.value = comment;
1723
+ replyDrafts.set(form.dataset.planrReplyForm, comment);
1724
+ if (wasExpanded) expandedReplies.add(form.dataset.planrReplyForm);
1725
+ textarea?.setAttribute("aria-invalid", "true");
1726
+ showError(error);
1727
+ textarea?.focus();
1728
+ }
1729
+ };
1730
+ const onOverallChange = () => {
1731
+ try {
1732
+ const value = overall.value;
1733
+ controller.dispatch({ type: "set-overall", overall: value });
1734
+ overallDirty = false;
1735
+ announce2("Overall note updated");
1736
+ clearError();
1737
+ } catch (error) {
1738
+ showError(error);
1739
+ }
1740
+ };
1741
+ const onDecision = (event) => {
1742
+ try {
1743
+ const selected = event.currentTarget.dataset.planrDecision;
1744
+ const decision = controller.getReview()?.decision === selected ? "pending" : selected;
1745
+ controller.dispatch({ type: "set-decision", decision });
1746
+ announce2(decisionCopy(decision));
1747
+ clearError();
1748
+ } catch (error) {
1749
+ showError(error);
1750
+ }
1751
+ };
1752
+ const onSelect = (event) => {
1753
+ if (event.detail?.source === "thread" || typeof event.detail?.pinId !== "string") return;
1754
+ try {
1755
+ controller.selectPin(event.detail.pinId);
1756
+ focusThread(event.detail.pinId);
1757
+ } catch (error) {
1758
+ showError(error);
1759
+ }
1760
+ };
1761
+ let lastOpened = null;
1762
+ const onThreadOpen = (event) => {
1763
+ const thread = event.target.closest?.(".planr-thread[data-planr-pin-id]");
1764
+ if (!thread || !slot.contains(thread)) return;
1765
+ const pin = controller.getReview()?.pins.find((entry) => entry.id === thread.dataset.planrPinId);
1766
+ const key = pin && `${pin.id}:${pin.replies.map((reply) => reply.id).join(",")}`;
1767
+ if (!key || lastOpened === key) return;
1768
+ lastOpened = key;
1769
+ presentation.onThreadOpen?.(pin.id, controller.getState());
1770
+ root.dispatchEvent(new window.CustomEvent("planr:artifact-thread-open", { bubbles: true, detail: Object.freeze({ pinId: pin.id }) }));
1771
+ };
1772
+ const onDraftInput = (event) => {
1773
+ const form = event.target.closest?.("[data-planr-reply-form]");
1774
+ if (form) form.querySelector(".planr-reply-send").disabled = !form.elements.namedItem("reply").value.trim();
1775
+ emitDraftChange();
1776
+ };
1777
+ const onOverallInput = () => {
1778
+ overallDirty = true;
1779
+ emitDraftChange();
1780
+ };
1781
+ const onCompositionStart = () => {
1782
+ composing = true;
1783
+ };
1784
+ const onCompositionEnd = () => {
1785
+ composing = false;
1786
+ if (renderQueued) {
1787
+ renderQueued = false;
1788
+ render();
1789
+ }
1790
+ };
1791
+ slot.addEventListener("input", onDraftInput);
1792
+ slot.addEventListener("focusin", onThreadOpen);
1793
+ slot.addEventListener("click", onThreadOpen);
1794
+ slot.addEventListener("compositionstart", onCompositionStart);
1795
+ slot.addEventListener("compositionend", onCompositionEnd);
1796
+ overall.addEventListener("input", onOverallInput);
1797
+ identityInput.addEventListener("input", onInput);
1798
+ slot.addEventListener("click", onClick);
1799
+ slot.addEventListener("submit", onSubmit);
1800
+ slot.addEventListener("keydown", onKeyDown);
1801
+ overall.addEventListener("change", onOverallChange);
1802
+ for (const button of decisionButtons) button.addEventListener("click", onDecision);
1803
+ root.addEventListener(ARTIFACT_REVIEW_SELECT_EVENT, onSelect);
1804
+ render();
1805
+ return Object.freeze({
1806
+ controller,
1807
+ getReview: () => controller.getReview(),
1808
+ getState: () => controller.getState(),
1809
+ getIdentity: () => controller.getIdentity(),
1810
+ setIdentity: (value) => controller.setIdentity(value),
1811
+ dispatch: (action) => controller.dispatch(action),
1812
+ replaceReview: (review) => controller.replaceReview(review),
1813
+ selectPin: (pinId) => controller.selectPin(pinId),
1814
+ render,
1815
+ setPresentation(options = {}) {
1816
+ if (options.filterKey !== presentation.filterKey || options.pageSize !== void 0 && options.pageSize !== presentation.pageSize) visibleLimit = options.pageSize || presentation.pageSize || Infinity;
1817
+ presentation = { ...presentation, ...options };
1818
+ render();
1819
+ },
1820
+ snapshotDrafts,
1821
+ getReviewOf: () => controller.getReview()?.reviewOf ?? reviewOf,
1822
+ restoreDrafts(snapshot) {
1823
+ const digest = controller.getReview()?.reviewOf ?? reviewOf;
1824
+ if (!snapshot || snapshot.reviewOf !== digest) return false;
1825
+ if (typeof snapshot.identity === "string") {
1826
+ const name = snapshot.identity.slice(0, ARTIFACT_REVIEW_LIMITS.authorName);
1827
+ controller.setIdentity(name.trim() ? { ...controller.getIdentity(), name } : null);
1828
+ }
1829
+ for (const [id, value] of Object.entries(snapshot.replies ?? {}).slice(0, ARTIFACT_REVIEW_LIMITS.pins)) {
1830
+ if (id.length <= ARTIFACT_REVIEW_LIMITS.id && typeof value === "string") replyDrafts.set(id, value.slice(0, ARTIFACT_REVIEW_LIMITS.text));
1831
+ }
1832
+ expandedReplies.clear();
1833
+ const expanded = Array.isArray(snapshot.expandedReplies) ? snapshot.expandedReplies : [...replyDrafts.keys()];
1834
+ for (const id of expanded.slice(0, ARTIFACT_REVIEW_LIMITS.pins)) if (typeof id === "string" && id.length <= ARTIFACT_REVIEW_LIMITS.id) expandedReplies.add(id);
1835
+ for (const [key, value] of Object.entries(snapshot.fields ?? {}).slice(0, ARTIFACT_REVIEW_LIMITS.pins)) {
1836
+ if (key.length <= 512 && typeof value === "string") extraDrafts.set(key, value.slice(0, ARTIFACT_REVIEW_LIMITS.text));
1837
+ }
1838
+ overallDirty = snapshot.overall?.dirty === true;
1839
+ if (overallDirty && typeof snapshot.overall?.value === "string") overall.value = snapshot.overall.value.slice(0, ARTIFACT_REVIEW_LIMITS.text);
1840
+ render({ capture: false });
1841
+ return true;
1842
+ },
1843
+ focusThread,
1844
+ destroy() {
1845
+ if (destroyed) return;
1846
+ destroyed = true;
1847
+ unsubscribe();
1848
+ slot.removeEventListener("input", onDraftInput);
1849
+ slot.removeEventListener("focusin", onThreadOpen);
1850
+ slot.removeEventListener("click", onThreadOpen);
1851
+ slot.removeEventListener("compositionstart", onCompositionStart);
1852
+ slot.removeEventListener("compositionend", onCompositionEnd);
1853
+ overall.removeEventListener("input", onOverallInput);
1854
+ identityInput.removeEventListener("input", onInput);
1855
+ slot.removeEventListener("click", onClick);
1856
+ slot.removeEventListener("submit", onSubmit);
1857
+ slot.removeEventListener("keydown", onKeyDown);
1858
+ overall.removeEventListener("change", onOverallChange);
1859
+ for (const button of decisionButtons) button.removeEventListener("click", onDecision);
1860
+ root.removeEventListener(ARTIFACT_REVIEW_SELECT_EVENT, onSelect);
1861
+ if (ownsController) controller.destroy();
1862
+ }
1863
+ });
1864
+ }
1865
+
1866
+ // lib/artifact/ui/share-dialog.mjs
1867
+ var ARTIFACT_SHARE_FRAGMENT_LIMIT = 8e3;
1868
+ var ARTIFACT_SHARE_TTLS = Object.freeze({
1869
+ "1d": Object.freeze({ label: "1 day", milliseconds: 864e5 }),
1870
+ "7d": Object.freeze({ label: "7 days", milliseconds: 6048e5 }),
1871
+ "30d": Object.freeze({ label: "30 days", milliseconds: 2592e6 })
1872
+ });
1873
+ var ARTIFACT_SHARE_TRANSPORTS = Object.freeze(["live", "fragment", "short"]);
1874
+ var PHASES = Object.freeze([
1875
+ "idle",
1876
+ "previewing",
1877
+ "ready",
1878
+ "custody-preparing",
1879
+ "custody-ready",
1880
+ "creating",
1881
+ "ambiguous",
1882
+ "created",
1883
+ "error"
1884
+ ]);
1885
+ var LIVE_ROOM_ID_RE = /^[A-Za-z0-9_-]{16,128}$/;
1886
+ var LIVE_ROOM_SECRET_RE = /^[A-Za-z0-9_-]{43}$/;
1887
+ var LIVE_ROOM_KEY_ID_RE = /^sha256:[a-f0-9]{64}$/;
1888
+ var LIVE_ROOM_REVIEW_RE = /^[a-f0-9]{64}$/;
1889
+ var BASE64URL_RE = /^[A-Za-z0-9_-]+$/;
1890
+ var OWNER_SECRET_MAX_BYTES = 64 * 1024;
1891
+ var ArtifactShareUiError = class extends Error {
1892
+ constructor(code, message, details = {}) {
1893
+ super(message);
1894
+ this.name = "ArtifactShareUiError";
1895
+ this.code = code;
1896
+ this.details = Object.freeze({ ...details });
1897
+ }
1898
+ };
1899
+ function member(value, allowed, fallback) {
1900
+ return allowed.includes(value) ? value : fallback;
1901
+ }
1902
+ function count(value, name) {
1903
+ if (!Number.isInteger(value) || value < 0) {
1904
+ throw new ArtifactShareUiError(
1905
+ "E_ARTIFACT_SHARE_PREVIEW_INVALID",
1906
+ `${name} must be a non-negative integer.`,
1907
+ { field: name }
1908
+ );
1909
+ }
1910
+ return value;
1911
+ }
1912
+ function text2(value, fallback = "") {
1913
+ return typeof value === "string" ? value : fallback;
1914
+ }
1915
+ function record(value) {
1916
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1917
+ }
1918
+ function exactKeys(value, expected) {
1919
+ return record(value) && JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...expected].sort());
1920
+ }
1921
+ function exactLoopback(hostname) {
1922
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
1923
+ }
1924
+ function parseLiveResultUrl(value, capability) {
1925
+ let url;
1926
+ try {
1927
+ url = new URL(value);
1928
+ } catch {
1929
+ throw new ArtifactShareUiError(
1930
+ "E_ARTIFACT_SHARE_RESULT_INVALID",
1931
+ "Live room creation returned a malformed capability URL."
1932
+ );
1933
+ }
1934
+ const fields = new URLSearchParams(url.hash.slice(1));
1935
+ const keys = [...fields.keys()];
1936
+ const roomId = /^\/r\/([A-Za-z0-9_-]{16,128})\/?$/.exec(url.pathname)?.[1];
1937
+ if (url.username || url.password || url.search || url.protocol !== "https:" && !(url.protocol === "http:" && exactLoopback(url.hostname)) || !roomId || !LIVE_ROOM_ID_RE.test(roomId) || keys.length !== 2 || !keys.includes("k") || !keys.includes(capability) || keys.some((key) => !["k", capability].includes(key) || fields.getAll(key).length !== 1) || !LIVE_ROOM_SECRET_RE.test(fields.get("k") ?? "") || !LIVE_ROOM_SECRET_RE.test(fields.get(capability) ?? "")) {
1938
+ throw new ArtifactShareUiError(
1939
+ "E_ARTIFACT_SHARE_RESULT_INVALID",
1940
+ "Live room creation returned an invalid or mixed capability URL."
1941
+ );
1942
+ }
1943
+ return Object.freeze({
1944
+ origin: url.origin,
1945
+ pathname: url.pathname.replace(/\/$/, ""),
1946
+ key: fields.get("k"),
1947
+ capability: fields.get(capability)
1948
+ });
1949
+ }
1950
+ function validateLiveResultUrls({ url, ownerUrl, manageUrl }) {
1951
+ const reviewer = parseLiveResultUrl(url, "w");
1952
+ const owner = parseLiveResultUrl(ownerUrl, "o");
1953
+ const management = parseLiveResultUrl(manageUrl, "m");
1954
+ if (reviewer.origin !== owner.origin || reviewer.origin !== management.origin || reviewer.pathname !== owner.pathname || reviewer.pathname !== management.pathname || reviewer.key !== owner.key || reviewer.key !== management.key || (/* @__PURE__ */ new Set([reviewer.capability, owner.capability, management.capability])).size !== 3) {
1955
+ throw new ArtifactShareUiError(
1956
+ "E_ARTIFACT_SHARE_RESULT_INVALID",
1957
+ "Live room creation must return separate reviewer, owner-verdict, and management capabilities for one room."
1958
+ );
1959
+ }
1960
+ }
1961
+ function normalizeOwnerCustody(value) {
1962
+ if (record(value?.prepared) && record(value?.recovery)) {
1963
+ const { prepared, recovery } = value;
1964
+ if (!exactKeys(prepared, [
1965
+ "schemaVersion",
1966
+ "kind",
1967
+ "protocolVersion",
1968
+ "id",
1969
+ "roomId",
1970
+ "reviewOf",
1971
+ "ttl",
1972
+ "ownerKey"
1973
+ ]) || prepared.schemaVersion !== "1.0.0" || prepared.kind !== "openplanr-live-room-preparation" || prepared.protocolVersion !== "2.0.0" || prepared.id !== prepared.roomId || !LIVE_ROOM_ID_RE.test(prepared.roomId ?? "") || !LIVE_ROOM_REVIEW_RE.test(prepared.reviewOf ?? "") || !Object.hasOwn(ARTIFACT_SHARE_TTLS, prepared.ttl) || !record(prepared.ownerKey) || !exactKeys(prepared.ownerKey, ["algorithm", "encoding", "keyId", "value"]) || !record(prepared.ownerSigner) || !exactKeys(recovery, [
1974
+ "schemaVersion",
1975
+ "kind",
1976
+ "protocolVersion",
1977
+ "id",
1978
+ "roomId",
1979
+ "reviewOf",
1980
+ "ttl",
1981
+ "ownerKey",
1982
+ "url",
1983
+ "ownerUrl",
1984
+ "manageUrl",
1985
+ "ownerSigner"
1986
+ ]) || recovery.schemaVersion !== "1.0.0" || recovery.kind !== "openplanr-live-room-recovery" || recovery.protocolVersion !== "2.0.0" || recovery.id !== prepared.id || recovery.roomId !== prepared.roomId || recovery.reviewOf !== prepared.reviewOf || recovery.ttl !== prepared.ttl || JSON.stringify(recovery.ownerKey) !== JSON.stringify(prepared.ownerKey) || recovery.url !== prepared.url || recovery.ownerUrl !== prepared.ownerUrl || recovery.manageUrl !== prepared.manageUrl) {
1987
+ throw new ArtifactShareUiError(
1988
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_INVALID",
1989
+ "Live room recovery custody does not match its prepared creation."
1990
+ );
1991
+ }
1992
+ validateLiveResultUrls(recovery);
1993
+ const signerCustody = normalizeOwnerCustody({
1994
+ signer: prepared.ownerSigner,
1995
+ secret: recovery.ownerSigner
1996
+ });
1997
+ if (prepared.ownerKey.algorithm !== signerCustody.signer.algorithm || prepared.ownerKey.encoding !== signerCustody.signer.encoding || prepared.ownerKey.keyId !== signerCustody.signer.keyId || prepared.ownerKey.value !== (signerCustody.signer.value ?? signerCustody.signer.publicKey)) {
1998
+ throw new ArtifactShareUiError(
1999
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_INVALID",
2000
+ "Live room recovery owner key does not match its prepared signer."
2001
+ );
2002
+ }
2003
+ const serialized2 = `${JSON.stringify(recovery, null, 2)}
2004
+ `;
2005
+ const byteLength2 = new TextEncoder().encode(serialized2).byteLength;
2006
+ if (byteLength2 < 2 || byteLength2 > OWNER_SECRET_MAX_BYTES) {
2007
+ throw new ArtifactShareUiError(
2008
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_INVALID",
2009
+ "Live room recovery bundle exceeds its bounded export size."
2010
+ );
2011
+ }
2012
+ return Object.freeze({
2013
+ credential: prepared,
2014
+ signer: signerCustody.signer,
2015
+ serialized: serialized2,
2016
+ filename: `openplanr-live-room-recovery-${prepared.roomId.slice(0, 12)}.json`
2017
+ });
2018
+ }
2019
+ if (!record(value) || !record(value.signer) || !record(value.secret)) {
2020
+ throw new ArtifactShareUiError(
2021
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_INVALID",
2022
+ "Live room owner custody could not be prepared safely."
2023
+ );
2024
+ }
2025
+ const { signer, secret } = value;
2026
+ if (signer.role !== "owner" || typeof signer.sign !== "function" || signer.algorithm !== "ECDSA-P256-SHA256" || signer.encoding !== "spki-base64url" || !LIVE_ROOM_KEY_ID_RE.test(signer.keyId ?? "") || !BASE64URL_RE.test(signer.value ?? signer.publicKey ?? "") || (signer.value ?? signer.publicKey).length < 64 || (signer.value ?? signer.publicKey).length > 512) {
2027
+ throw new ArtifactShareUiError(
2028
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_INVALID",
2029
+ "Live room owner signer is invalid."
2030
+ );
2031
+ }
2032
+ if (!exactKeys(secret, [
2033
+ "schemaVersion",
2034
+ "kind",
2035
+ "role",
2036
+ "algorithm",
2037
+ "keyId",
2038
+ "publicKey",
2039
+ "privateKey"
2040
+ ]) || secret.schemaVersion !== "1.0.0" || secret.kind !== "openplanr-live-room-signer" || secret.role !== "owner" || secret.algorithm !== "ECDSA-P256-SHA256" || secret.keyId !== signer.keyId || secret.publicKey !== (signer.value ?? signer.publicKey) || !BASE64URL_RE.test(secret.publicKey ?? "") || !BASE64URL_RE.test(secret.privateKey ?? "") || secret.publicKey.length < 64 || secret.publicKey.length > 512 || secret.privateKey.length < 64 || secret.privateKey.length > 1024) {
2041
+ throw new ArtifactShareUiError(
2042
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_INVALID",
2043
+ "Live room owner secret does not match its signer."
2044
+ );
2045
+ }
2046
+ const serialized = `${JSON.stringify(secret, null, 2)}
2047
+ `;
2048
+ const byteLength = new TextEncoder().encode(serialized).byteLength;
2049
+ if (byteLength < 2 || byteLength > OWNER_SECRET_MAX_BYTES) {
2050
+ throw new ArtifactShareUiError(
2051
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_INVALID",
2052
+ "Live room owner secret exceeds its bounded export size."
2053
+ );
2054
+ }
2055
+ return Object.freeze({
2056
+ credential: signer,
2057
+ signer,
2058
+ serialized,
2059
+ filename: `openplanr-live-room-owner-${signer.keyId.slice(7, 19)}.json`
2060
+ });
2061
+ }
2062
+ function defaultSaveOwnerCustody(document2, window, { filename, serialized }) {
2063
+ if (typeof window?.Blob !== "function" || typeof window?.URL?.createObjectURL !== "function" || typeof window?.URL?.revokeObjectURL !== "function" || typeof document2?.createElement !== "function" || !document2.body) {
2064
+ throw new ArtifactShareUiError(
2065
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_UNAVAILABLE",
2066
+ "This browser cannot save the private owner key. No room was created."
2067
+ );
2068
+ }
2069
+ const blobUrl = window.URL.createObjectURL(new window.Blob(
2070
+ [serialized],
2071
+ { type: "application/json;charset=utf-8" }
2072
+ ));
2073
+ try {
2074
+ const anchor = document2.createElement("a");
2075
+ anchor.hidden = true;
2076
+ anchor.href = blobUrl;
2077
+ anchor.download = filename;
2078
+ anchor.rel = "noreferrer";
2079
+ document2.body.append(anchor);
2080
+ anchor.click();
2081
+ anchor.remove();
2082
+ } catch (error) {
2083
+ throw new ArtifactShareUiError(
2084
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_UNAVAILABLE",
2085
+ "The private owner key could not be handed to the browser download manager. No room was created.",
2086
+ { cause: error?.name }
2087
+ );
2088
+ } finally {
2089
+ window.setTimeout(() => window.URL.revokeObjectURL(blobUrl), 0);
2090
+ }
2091
+ return true;
2092
+ }
2093
+ async function establishArtifactOwnerCustody({ prepareOwnerCustody, saveOwnerCustody } = {}) {
2094
+ if (typeof prepareOwnerCustody !== "function" || typeof saveOwnerCustody !== "function") {
2095
+ throw new ArtifactShareUiError(
2096
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_REQUIRED",
2097
+ "Live room creation requires explicit private owner-key custody. No room was created."
2098
+ );
2099
+ }
2100
+ const custody = normalizeOwnerCustody(await prepareOwnerCustody());
2101
+ const saved = await saveOwnerCustody(Object.freeze({
2102
+ filename: custody.filename,
2103
+ serialized: custody.serialized
2104
+ }));
2105
+ if (saved !== true && saved?.saved !== true) {
2106
+ throw new ArtifactShareUiError(
2107
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_UNAVAILABLE",
2108
+ "Private owner-key custody was not confirmed. No room was created."
2109
+ );
2110
+ }
2111
+ return custody.credential;
2112
+ }
2113
+ function frozenResult(value) {
2114
+ if (!value || typeof value !== "object" || typeof value.url !== "string" || value.url.length === 0) {
2115
+ throw new ArtifactShareUiError(
2116
+ "E_ARTIFACT_SHARE_RESULT_INVALID",
2117
+ "Share creation must return a non-empty review URL."
2118
+ );
2119
+ }
2120
+ if (!ARTIFACT_SHARE_TRANSPORTS.includes(value.transport)) {
2121
+ throw new ArtifactShareUiError(
2122
+ "E_ARTIFACT_SHARE_RESULT_INVALID",
2123
+ "Share creation must return a known transport.",
2124
+ { field: "transport" }
2125
+ );
2126
+ }
2127
+ const deletionToken = text2(value.deletionToken);
2128
+ const ownerUrl = text2(value.ownerUrl);
2129
+ const manageUrl = text2(value.manageUrl);
2130
+ if (deletionToken && value.url.includes(deletionToken)) {
2131
+ throw new ArtifactShareUiError(
2132
+ "E_ARTIFACT_SHARE_DELETION_TOKEN_LEAK",
2133
+ "The deletion token must never be included in the review URL."
2134
+ );
2135
+ }
2136
+ if (value.transport === "live") {
2137
+ validateLiveResultUrls({ url: value.url, ownerUrl, manageUrl });
2138
+ } else if (ownerUrl || manageUrl) {
2139
+ throw new ArtifactShareUiError(
2140
+ "E_ARTIFACT_SHARE_RESULT_INVALID",
2141
+ "Snapshot creation cannot return live room capabilities."
2142
+ );
2143
+ }
2144
+ return Object.freeze({
2145
+ transport: value.transport,
2146
+ url: value.url,
2147
+ ownerUrl,
2148
+ manageUrl,
2149
+ deletionToken,
2150
+ expiresAt: text2(value.expiresAt)
2151
+ });
2152
+ }
2153
+ function normalizeArtifactSharePreview(value = {}) {
2154
+ const preview = value && typeof value === "object" ? value : {};
2155
+ const fragmentLength = count(preview.fragmentLength, "fragmentLength");
2156
+ return Object.freeze({
2157
+ fragmentLength,
2158
+ compressedBytes: count(preview.compressedBytes, "compressedBytes"),
2159
+ ciphertextBytes: count(preview.ciphertextBytes, "ciphertextBytes"),
2160
+ fragmentEligible: fragmentLength <= ARTIFACT_SHARE_FRAGMENT_LIMIT
2161
+ });
2162
+ }
2163
+ function freezeState(value) {
2164
+ return Object.freeze({
2165
+ open: Boolean(value.open),
2166
+ phase: member(value.phase, PHASES, "idle"),
2167
+ transport: member(value.transport, ARTIFACT_SHARE_TRANSPORTS, "live"),
2168
+ ttl: Object.hasOwn(ARTIFACT_SHARE_TTLS, value.ttl) ? value.ttl : "7d",
2169
+ preview: value.preview ? normalizeArtifactSharePreview(value.preview) : null,
2170
+ ownerCustodyEstablished: Boolean(value.ownerCustodyEstablished),
2171
+ result: value.result ? frozenResult(value.result) : null,
2172
+ error: text2(value.error)
2173
+ });
2174
+ }
2175
+ function createArtifactShareDialogState({ preview, ttl = "7d" } = {}) {
2176
+ const normalizedPreview = preview ? normalizeArtifactSharePreview(preview) : null;
2177
+ return freezeState({
2178
+ open: false,
2179
+ phase: normalizedPreview ? "ready" : "idle",
2180
+ transport: "live",
2181
+ ttl,
2182
+ preview: normalizedPreview,
2183
+ ownerCustodyEstablished: false,
2184
+ result: null,
2185
+ error: ""
2186
+ });
2187
+ }
2188
+ function reduceArtifactShareDialog(state, action = {}) {
2189
+ const current = state ?? createArtifactShareDialogState();
2190
+ if (current.phase === "created" && action.type !== "close") return current;
2191
+ if (current.phase === "ambiguous" && !["create-start", "create-success", "failure"].includes(action.type)) return current;
2192
+ if (current.phase === "custody-ready" && ["select-transport", "set-ttl"].includes(action.type)) return current;
2193
+ switch (action.type) {
2194
+ case "open":
2195
+ return freezeState({ ...current, open: true, ownerCustodyEstablished: false, result: null, error: "" });
2196
+ case "close":
2197
+ return freezeState({ ...current, open: false, phase: current.preview ? "ready" : "idle", ownerCustodyEstablished: false, error: "" });
2198
+ case "preview-start":
2199
+ return freezeState({ ...current, open: true, phase: "previewing", preview: null, ownerCustodyEstablished: false, result: null, error: "" });
2200
+ case "preview-ready": {
2201
+ const preview = normalizeArtifactSharePreview(action.preview);
2202
+ return freezeState({
2203
+ ...current,
2204
+ phase: "ready",
2205
+ preview,
2206
+ ownerCustodyEstablished: false,
2207
+ transport: current.transport === "fragment" && !preview.fragmentEligible ? "short" : current.transport,
2208
+ result: null,
2209
+ error: ""
2210
+ });
2211
+ }
2212
+ case "select-transport": {
2213
+ const transport = member(action.transport, ARTIFACT_SHARE_TRANSPORTS, current.transport);
2214
+ if (transport === "fragment" && current.preview?.fragmentEligible === false) return current;
2215
+ return transport === current.transport ? current : freezeState({
2216
+ ...current,
2217
+ phase: current.preview ? "ready" : "idle",
2218
+ transport,
2219
+ ownerCustodyEstablished: false,
2220
+ result: null,
2221
+ error: ""
2222
+ });
2223
+ }
2224
+ case "set-ttl": {
2225
+ const ttl = Object.hasOwn(ARTIFACT_SHARE_TTLS, action.ttl) ? action.ttl : current.ttl;
2226
+ return ttl === current.ttl ? current : freezeState({ ...current, ttl, result: null, error: "" });
2227
+ }
2228
+ case "custody-start":
2229
+ return freezeState({ ...current, phase: "custody-preparing", ownerCustodyEstablished: false, result: null, error: "" });
2230
+ case "custody-ready":
2231
+ return freezeState({ ...current, phase: "custody-ready", ownerCustodyEstablished: true, result: null, error: "" });
2232
+ case "create-start":
2233
+ return freezeState({ ...current, phase: "creating", result: null, error: "" });
2234
+ case "create-success":
2235
+ return freezeState({ ...current, phase: "created", result: action.result, error: "" });
2236
+ case "failure":
2237
+ return freezeState({
2238
+ ...current,
2239
+ phase: action.ambiguous ? "ambiguous" : "error",
2240
+ ownerCustodyEstablished: Boolean(action.ownerCustodyEstablished),
2241
+ result: null,
2242
+ error: text2(action.error, "Share creation failed.")
2243
+ });
2244
+ default:
2245
+ return current;
2246
+ }
2247
+ }
2248
+ function artifactShareExpiry(ttl, now = /* @__PURE__ */ new Date()) {
2249
+ const choice = ARTIFACT_SHARE_TTLS[ttl] ?? ARTIFACT_SHARE_TTLS["7d"];
2250
+ const base = now instanceof Date ? now.getTime() : new Date(now).getTime();
2251
+ if (!Number.isFinite(base)) throw new TypeError("Share expiry requires a valid date.");
2252
+ return new Date(base + choice.milliseconds).toISOString();
2253
+ }
2254
+ function formatArtifactShareBytes(value) {
2255
+ const bytes = count(value, "bytes");
2256
+ if (bytes < 1e3) return `${bytes} B`;
2257
+ if (bytes < 1e6) return `${(bytes / 1e3).toFixed(bytes >= 1e4 ? 0 : 1)} KB`;
2258
+ return `${(bytes / 1e6).toFixed(1)} MB`;
2259
+ }
2260
+ function focusableElements(dialog) {
2261
+ return [...dialog.querySelectorAll(
2262
+ 'button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [href], [tabindex]:not([tabindex="-1"])'
2263
+ )].filter((element) => !element.hidden && !element.closest("[hidden]"));
2264
+ }
2265
+ function defaultCopy(window, value) {
2266
+ if (typeof window?.navigator?.clipboard?.writeText !== "function") {
2267
+ throw new ArtifactShareUiError(
2268
+ "E_ARTIFACT_SHARE_CLIPBOARD_UNAVAILABLE",
2269
+ "Clipboard access is unavailable. Copy the value manually."
2270
+ );
2271
+ }
2272
+ return window.navigator.clipboard.writeText(value);
2273
+ }
2274
+ function reviewForShare(stageController) {
2275
+ return stageController?.review?.getReview?.() ?? null;
2276
+ }
2277
+ function artifactShareCapabilities({ prepareShare, prepareOwnerCustody, createShare, supportedTransports } = {}) {
2278
+ const canCreate = typeof prepareShare === "function" && typeof createShare === "function";
2279
+ return Object.freeze(ARTIFACT_SHARE_TRANSPORTS.filter((transport) => canCreate && (transport !== "live" || typeof prepareOwnerCustody === "function") && (supportedTransports === void 0 || Array.isArray(supportedTransports) && supportedTransports.includes(transport))));
2280
+ }
2281
+ function mountArtifactShareDialog({
2282
+ document: document2 = globalThis.document,
2283
+ window = document2?.defaultView,
2284
+ root = document2?.querySelector?.(".planr-shell"),
2285
+ stageController,
2286
+ prepareShare,
2287
+ prepareOwnerCustody,
2288
+ saveOwnerCustody,
2289
+ createShare,
2290
+ supportedTransports,
2291
+ unavailableReason,
2292
+ copyText,
2293
+ existingRoom = false,
2294
+ existingShareUrl = null,
2295
+ now = () => /* @__PURE__ */ new Date()
2296
+ } = {}) {
2297
+ if (!document2 || !window || !root) return null;
2298
+ const backdrop = document2.querySelector("[data-planr-share-dialog]");
2299
+ const dialog = backdrop?.querySelector('[role="dialog"]');
2300
+ const trigger = root.querySelector('[data-planr-action="share"]');
2301
+ if (!backdrop || !dialog || !trigger) return null;
2302
+ let state = createArtifactShareDialogState();
2303
+ const capabilities = artifactShareCapabilities({ prepareShare, prepareOwnerCustody, createShare, supportedTransports });
2304
+ const unavailable = text2(unavailableReason) || "Sharing is not configured in this viewer. Open the review with an updated OpenPlanr installation that supports sharing.";
2305
+ let returnFocus = null;
2306
+ let generation = 0;
2307
+ let pendingOwnerCustody = null;
2308
+ const copyResetTimers = /* @__PURE__ */ new Map();
2309
+ const cleanup = [];
2310
+ const handlers = {
2311
+ prepareShare: typeof prepareShare === "function" ? prepareShare : null,
2312
+ prepareOwnerCustody: typeof prepareOwnerCustody === "function" ? prepareOwnerCustody : null,
2313
+ saveOwnerCustody: typeof saveOwnerCustody === "function" ? saveOwnerCustody : (value) => defaultSaveOwnerCustody(document2, window, value),
2314
+ createShare: typeof createShare === "function" ? createShare : null,
2315
+ copyText: typeof copyText === "function" ? copyText : (value) => defaultCopy(window, value)
2316
+ };
2317
+ const stableShareUrl = typeof existingShareUrl === "function" ? existingShareUrl : () => existingShareUrl;
2318
+ function supports(transport) {
2319
+ return capabilities.includes(transport) && (transport !== "fragment" || state.preview?.fragmentEligible !== false);
2320
+ }
2321
+ function selectSupportedTransport() {
2322
+ if (!supports(state.transport)) {
2323
+ const transport = capabilities.find(supports);
2324
+ if (transport) state = reduceArtifactShareDialog(state, { type: "select-transport", transport });
2325
+ }
2326
+ }
2327
+ function listen(target, type, handler, options) {
2328
+ target.addEventListener(type, handler, options);
2329
+ cleanup.push(() => target.removeEventListener(type, handler, options));
2330
+ }
2331
+ function announce2(message) {
2332
+ const live = dialog.querySelector("[data-planr-share-status]");
2333
+ if (live) live.textContent = message;
2334
+ }
2335
+ function resetCopyButton(button) {
2336
+ const timer = copyResetTimers.get(button);
2337
+ if (timer) window.clearTimeout(timer);
2338
+ copyResetTimers.delete(button);
2339
+ button.removeAttribute("data-planr-copy-state");
2340
+ const label = button.querySelector?.(".planr-action-label");
2341
+ if (label) label.textContent = button.dataset.planrCopyLabel ?? label.textContent;
2342
+ else button.textContent = button.dataset.planrCopyLabel ?? button.textContent;
2343
+ }
2344
+ function showCopyState(button, stateValue) {
2345
+ if (!button) return;
2346
+ const label = button.querySelector?.(".planr-action-label");
2347
+ if (!button.dataset.planrCopyLabel) {
2348
+ button.dataset.planrCopyLabel = (label?.textContent ?? button.textContent).trim();
2349
+ }
2350
+ const prior = copyResetTimers.get(button);
2351
+ if (prior) window.clearTimeout(prior);
2352
+ button.dataset.planrCopyState = stateValue;
2353
+ if (label) label.textContent = stateValue === "copied" ? "Copied" : "Try again";
2354
+ else button.textContent = stateValue === "copied" ? "Copied" : "Try again";
2355
+ copyResetTimers.set(button, window.setTimeout(() => resetCopyButton(button), 1800));
2356
+ }
2357
+ function resetCopyButtons() {
2358
+ for (const button of dialog.querySelectorAll("[data-planr-copy-state]")) resetCopyButton(button);
2359
+ }
2360
+ function clearPendingOwnerSigner() {
2361
+ pendingOwnerCustody = null;
2362
+ }
2363
+ function pendingOwnerSigner() {
2364
+ return pendingOwnerCustody?.ownerSigner ?? pendingOwnerCustody;
2365
+ }
2366
+ async function copyExistingRoom() {
2367
+ const value = stableShareUrl();
2368
+ if (!value) return;
2369
+ try {
2370
+ await handlers.copyText(value);
2371
+ showCopyState(trigger, "copied");
2372
+ announce2("Live review URL copied. This remains the same collaboration room.");
2373
+ } catch (error) {
2374
+ showCopyState(trigger, "error");
2375
+ announce2(error?.message ?? "Review URL could not be copied.");
2376
+ }
2377
+ }
2378
+ function render() {
2379
+ const preview = state.preview;
2380
+ backdrop.hidden = !state.open;
2381
+ backdrop.style.pointerEvents = state.open ? "auto" : "";
2382
+ root.toggleAttribute("inert", state.open);
2383
+ root.setAttribute("aria-hidden", String(state.open));
2384
+ if (!state.open) root.removeAttribute("aria-hidden");
2385
+ dialog.dataset.planrSharePhase = state.phase;
2386
+ dialog.dataset.planrShareSelected = state.transport;
2387
+ for (const button of dialog.querySelectorAll("[data-planr-share-transport]")) {
2388
+ const transport = button.dataset.planrShareTransport;
2389
+ const selected = transport === state.transport;
2390
+ button.hidden = state.phase === "created";
2391
+ button.setAttribute("aria-pressed", String(selected));
2392
+ button.classList.toggle("is-selected", selected);
2393
+ button.disabled = ["previewing", "custody-preparing", "custody-ready", "creating", "ambiguous", "created"].includes(state.phase) || !supports(transport);
2394
+ button.setAttribute("aria-disabled", String(button.disabled));
2395
+ button.title = capabilities.includes(transport) ? "" : transport === "live" && capabilities.length ? "Live review requires this host to provide private owner-key custody. Choose an available snapshot option." : unavailable;
2396
+ if (transport === "live") button.querySelector(".planr-share-receipt-size").textContent = capabilities.includes("live") ? "Default" : "Unavailable";
2397
+ }
2398
+ const fragmentSize = dialog.querySelector("[data-planr-share-fragment-size]");
2399
+ if (fragmentSize) fragmentSize.textContent = !capabilities.includes("fragment") ? "Unavailable" : preview ? `${preview.fragmentLength.toLocaleString("en-US")} chars · ${formatArtifactShareBytes(preview.compressedBytes)}` : state.phase === "previewing" ? "Calculating…" : "Size unavailable";
2400
+ const shortSize = dialog.querySelector("[data-planr-share-short-size]");
2401
+ if (shortSize) shortSize.textContent = !capabilities.includes("short") ? "Unavailable" : preview ? formatArtifactShareBytes(preview.ciphertextBytes) : state.phase === "previewing" ? "Calculating…" : "Size unavailable";
2402
+ const threshold = dialog.querySelector("[data-planr-share-threshold]");
2403
+ if (threshold) {
2404
+ threshold.hidden = !capabilities.includes("fragment");
2405
+ threshold.textContent = preview?.fragmentEligible === false ? `Private fragment snapshot unavailable (${preview.fragmentLength.toLocaleString("en-US")} characters; 8,000 limit). Choose an available sharing option.` : preview ? "Private fragment snapshot available for links up to 8,000 characters." : "Preparing the snapshot size before sharing.";
2406
+ }
2407
+ const ttlRow = dialog.querySelector("[data-planr-share-ttl-row]");
2408
+ if (ttlRow) ttlRow.hidden = state.phase === "created" || !supports(state.transport) || !["live", "short"].includes(state.transport);
2409
+ const ttlSelect2 = dialog.querySelector("[data-planr-share-ttl]");
2410
+ if (ttlSelect2) {
2411
+ ttlSelect2.value = state.ttl;
2412
+ ttlSelect2.disabled = ["custody-preparing", "custody-ready", "creating", "ambiguous", "created"].includes(state.phase);
2413
+ }
2414
+ const expiry = artifactShareExpiry(state.ttl, now());
2415
+ const expiryNode = dialog.querySelector("[data-planr-share-expiry]");
2416
+ if (expiryNode) {
2417
+ expiryNode.dateTime = expiry;
2418
+ expiryNode.textContent = new Intl.DateTimeFormat("en", {
2419
+ year: "numeric",
2420
+ month: "short",
2421
+ day: "numeric",
2422
+ timeZone: "UTC"
2423
+ }).format(new Date(expiry));
2424
+ }
2425
+ const primary = dialog.querySelector("[data-planr-share-confirm]");
2426
+ if (primary) {
2427
+ primary.hidden = state.phase === "created";
2428
+ primary.disabled = !supports(state.transport) || !preview && state.phase !== "error" || state.phase === "previewing" || state.phase === "custody-preparing" || state.phase === "creating" || state.phase === "created";
2429
+ primary.textContent = !supports(state.transport) ? "Sharing unavailable" : state.phase === "error" && !preview ? "Retry preparation" : state.phase === "custody-preparing" ? "Preparing owner key…" : state.phase === "creating" ? "Creating…" : state.phase === "ambiguous" ? "Retry exact room creation" : state.transport === "live" ? state.ownerCustodyEstablished ? state.phase === "error" ? "Retry live review room" : "I saved it — create live room" : "Download recovery bundle" : state.transport === "short" ? "Create encrypted link" : "Copy private link";
2430
+ }
2431
+ for (const closeControl of dialog.querySelectorAll("[data-planr-share-close], [data-planr-share-cancel]")) {
2432
+ const closeBlocked = state.phase === "creating" || state.phase === "ambiguous";
2433
+ closeControl.disabled = closeBlocked;
2434
+ closeControl.setAttribute("aria-disabled", String(closeBlocked));
2435
+ }
2436
+ const custody = dialog.querySelector("[data-planr-share-owner-custody]");
2437
+ if (custody) custody.hidden = state.transport !== "live" || !supports("live") || state.phase === "created";
2438
+ const custodyStatus = dialog.querySelector("[data-planr-share-owner-custody-status]");
2439
+ if (custodyStatus) custodyStatus.textContent = state.ownerCustodyEstablished ? "Full recovery bundle handed to the browser. It contains the three scoped URLs and owner key; no room exists until you confirm creation." : "No room will be created until the full private recovery bundle is downloaded successfully.";
2440
+ const receipt = dialog.querySelector("[data-planr-share-result]");
2441
+ if (receipt) receipt.hidden = state.phase !== "created" || !state.result;
2442
+ const resultUrl = dialog.querySelector("[data-planr-share-url]");
2443
+ if (resultUrl) resultUrl.value = state.result?.url ?? "";
2444
+ const owner = dialog.querySelector("[data-planr-share-owner]");
2445
+ if (owner) owner.hidden = !state.result?.ownerUrl;
2446
+ const ownerUrl = dialog.querySelector("[data-planr-share-owner-url]");
2447
+ if (ownerUrl) ownerUrl.value = state.result?.ownerUrl ?? "";
2448
+ const manage = dialog.querySelector("[data-planr-share-manage]");
2449
+ if (manage) manage.hidden = !state.result?.manageUrl;
2450
+ const manageUrl = dialog.querySelector("[data-planr-share-manage-url]");
2451
+ if (manageUrl) manageUrl.value = state.result?.manageUrl ?? "";
2452
+ const deletion = dialog.querySelector("[data-planr-share-deletion]");
2453
+ if (deletion) deletion.hidden = !state.result?.deletionToken;
2454
+ const deletionToken = dialog.querySelector("[data-planr-share-deletion-token]");
2455
+ if (deletionToken) deletionToken.textContent = state.result?.deletionToken ?? "";
2456
+ const error = dialog.querySelector("[data-planr-share-error]");
2457
+ if (error) {
2458
+ error.hidden = !state.error;
2459
+ error.textContent = state.error;
2460
+ }
2461
+ }
2462
+ async function open() {
2463
+ clearPendingOwnerSigner();
2464
+ resetCopyButtons();
2465
+ if (!state.open) returnFocus = document2.activeElement instanceof window.HTMLElement ? document2.activeElement : trigger;
2466
+ state = reduceArtifactShareDialog(state, { type: "open" });
2467
+ state = reduceArtifactShareDialog(state, { type: "preview-start" });
2468
+ selectSupportedTransport();
2469
+ state = reduceArtifactShareDialog(state, { type: "preview-start" });
2470
+ render();
2471
+ dialog.querySelector("[data-planr-share-close]")?.focus();
2472
+ const request = ++generation;
2473
+ try {
2474
+ if (!capabilities.length) throw new ArtifactShareUiError("E_ARTIFACT_SHARE_HANDLER_REQUIRED", unavailable);
2475
+ const preview = await handlers.prepareShare(Object.freeze({
2476
+ review: reviewForShare(stageController),
2477
+ fragmentLimit: ARTIFACT_SHARE_FRAGMENT_LIMIT
2478
+ }));
2479
+ if (request !== generation || !state.open) return state;
2480
+ state = reduceArtifactShareDialog(state, { type: "preview-ready", preview });
2481
+ selectSupportedTransport();
2482
+ if (!supports(state.transport)) throw new ArtifactShareUiError("E_ARTIFACT_SHARE_TRANSPORT_UNAVAILABLE", "This review is too large for the sharing options supported by this viewer. Open it with an updated OpenPlanr installation or export the review.");
2483
+ render();
2484
+ announce2(capabilities.includes("fragment") && state.preview.fragmentEligible ? "Private fragment is available. Nothing will be uploaded." : "Review prepared. Choose an available sharing option.");
2485
+ } catch (error) {
2486
+ if (request !== generation || !state.open) return state;
2487
+ state = reduceArtifactShareDialog(state, { type: "failure", error: error?.message });
2488
+ render();
2489
+ announce2(state.error);
2490
+ }
2491
+ return state;
2492
+ }
2493
+ function close() {
2494
+ if (state.phase === "creating" || state.phase === "ambiguous") {
2495
+ announce2(state.phase === "ambiguous" ? "Room creation may have completed. Retry the exact attempt until its receipt is shown." : "Room creation is in progress. Keep this dialog open until its receipt is shown.");
2496
+ return state;
2497
+ }
2498
+ generation += 1;
2499
+ clearPendingOwnerSigner();
2500
+ state = reduceArtifactShareDialog(state, { type: "close" });
2501
+ resetCopyButtons();
2502
+ render();
2503
+ returnFocus?.focus?.();
2504
+ returnFocus = null;
2505
+ return state;
2506
+ }
2507
+ async function confirm() {
2508
+ if (!state.open || !supports(state.transport)) return state;
2509
+ if (!state.preview && state.phase === "error") return open();
2510
+ if (!state.preview || ["custody-preparing", "creating", "created"].includes(state.phase)) return state;
2511
+ const transport = state.transport;
2512
+ const request = generation;
2513
+ if (transport === "live" && !state.ownerCustodyEstablished) {
2514
+ state = reduceArtifactShareDialog(state, { type: "custody-start" });
2515
+ render();
2516
+ try {
2517
+ const custody = await establishArtifactOwnerCustody({
2518
+ prepareOwnerCustody: () => handlers.prepareOwnerCustody(Object.freeze({
2519
+ review: reviewForShare(stageController),
2520
+ ttl: state.ttl
2521
+ })),
2522
+ saveOwnerCustody: handlers.saveOwnerCustody
2523
+ });
2524
+ if (request !== generation || !state.open) return state;
2525
+ pendingOwnerCustody = custody;
2526
+ state = reduceArtifactShareDialog(state, { type: "custody-ready" });
2527
+ render();
2528
+ announce2("Private recovery-bundle download started. Verify the file is saved, then confirm room creation.");
2529
+ } catch (error) {
2530
+ if (request !== generation || !state.open) return state;
2531
+ clearPendingOwnerSigner();
2532
+ state = reduceArtifactShareDialog(state, {
2533
+ type: "failure",
2534
+ ownerCustodyEstablished: false,
2535
+ error: error?.message
2536
+ });
2537
+ render();
2538
+ announce2(state.error);
2539
+ }
2540
+ return state;
2541
+ }
2542
+ if (transport === "live" && !pendingOwnerCustody) {
2543
+ state = reduceArtifactShareDialog(state, {
2544
+ type: "failure",
2545
+ ownerCustodyEstablished: false,
2546
+ error: "The prepared recovery attempt is no longer available. Download a new bundle before creating a room."
2547
+ });
2548
+ render();
2549
+ announce2(state.error);
2550
+ return state;
2551
+ }
2552
+ state = reduceArtifactShareDialog(state, { type: "create-start" });
2553
+ render();
2554
+ try {
2555
+ const input = {
2556
+ review: reviewForShare(stageController),
2557
+ preview: state.preview,
2558
+ transport,
2559
+ ttl: ["live", "short"].includes(transport) ? state.ttl : void 0,
2560
+ confirmed: ["live", "short"].includes(transport)
2561
+ };
2562
+ if (transport === "live") {
2563
+ if (pendingOwnerCustody?.kind === "openplanr-live-room-preparation") {
2564
+ Object.defineProperty(input, "prepared", { enumerable: false, value: pendingOwnerCustody });
2565
+ } else {
2566
+ Object.defineProperty(input, "ownerSigner", { enumerable: false, value: pendingOwnerCustody });
2567
+ }
2568
+ }
2569
+ const result = await handlers.createShare(Object.freeze(input));
2570
+ if (request !== generation || !state.open) return state;
2571
+ if (transport === "live" && result?.ownerSigner !== pendingOwnerSigner()) {
2572
+ throw new ArtifactShareUiError(
2573
+ "E_ARTIFACT_SHARE_OWNER_CUSTODY_MISMATCH",
2574
+ "The created room did not bind the prepared owner key. Retry the exact prepared attempt.",
2575
+ { effect: "ambiguous" }
2576
+ );
2577
+ }
2578
+ state = reduceArtifactShareDialog(state, {
2579
+ type: "create-success",
2580
+ result: { ...result, transport }
2581
+ });
2582
+ clearPendingOwnerSigner();
2583
+ render();
2584
+ announce2(transport === "live" ? "Live room created. Keep the downloaded owner key with the separate owner-verdict URL; management cannot set a verdict." : transport === "short" ? "Encrypted short link copied. Store the one-time deletion token now." : "Private fragment copied. Nothing was uploaded.");
2585
+ try {
2586
+ await handlers.copyText(state.result.url);
2587
+ announce2(transport === "live" ? "Live review URL copied. Keep the downloaded owner key with the separate owner-verdict URL." : transport === "short" ? "Encrypted short link copied. Store the one-time deletion token now." : "Private fragment copied. Nothing was uploaded.");
2588
+ } catch {
2589
+ announce2(transport === "live" ? "Live room created. Copy the review and owner-verdict URLs manually; the room receipt remains visible." : "Share created. Copy the URL manually; the receipt remains visible.");
2590
+ }
2591
+ } catch (error) {
2592
+ if (request !== generation || !state.open) return state;
2593
+ const ambiguous = transport === "live" && error?.details?.effect === "ambiguous";
2594
+ if (transport === "live" && !ambiguous) clearPendingOwnerSigner();
2595
+ state = reduceArtifactShareDialog(state, {
2596
+ type: "failure",
2597
+ ambiguous,
2598
+ ownerCustodyEstablished: transport === "live" && Boolean(pendingOwnerCustody),
2599
+ error: error?.message
2600
+ });
2601
+ render();
2602
+ announce2(state.error);
2603
+ }
2604
+ return state;
2605
+ }
2606
+ async function copy(value, successMessage, button) {
2607
+ if (!value) return;
2608
+ try {
2609
+ await handlers.copyText(value);
2610
+ showCopyState(button, "copied");
2611
+ announce2(successMessage);
2612
+ } catch (error) {
2613
+ showCopyState(button, "error");
2614
+ announce2(error?.message ?? "The value could not be copied. The share receipt remains visible.");
2615
+ }
2616
+ }
2617
+ if (existingRoom) {
2618
+ const value = stableShareUrl();
2619
+ if (value) {
2620
+ const label = trigger.querySelector(".planr-action-label");
2621
+ if (label) label.textContent = "Copy link";
2622
+ else trigger.textContent = "Copy link";
2623
+ trigger.dataset.planrCopyLabel = "Copy link";
2624
+ trigger.dataset.planrTooltip = "Copy link";
2625
+ trigger.removeAttribute("aria-haspopup");
2626
+ trigger.setAttribute("aria-label", "Copy this live review room link");
2627
+ listen(trigger, "click", () => {
2628
+ void copyExistingRoom();
2629
+ });
2630
+ } else {
2631
+ trigger.hidden = true;
2632
+ }
2633
+ } else {
2634
+ listen(trigger, "click", open);
2635
+ }
2636
+ listen(backdrop, "click", (event) => {
2637
+ const button = event.target.closest?.("button");
2638
+ if (!button) return;
2639
+ if (button.dataset.planrShareClose !== void 0 || button.dataset.planrShareCancel !== void 0) {
2640
+ close();
2641
+ return;
2642
+ }
2643
+ if (button.dataset.planrShareTransport) {
2644
+ if (!supports(button.dataset.planrShareTransport)) return;
2645
+ if (["custody-ready", "creating", "ambiguous", "created"].includes(state.phase)) return;
2646
+ if (button.dataset.planrShareTransport !== state.transport) clearPendingOwnerSigner();
2647
+ state = reduceArtifactShareDialog(state, {
2648
+ type: "select-transport",
2649
+ transport: button.dataset.planrShareTransport
2650
+ });
2651
+ render();
2652
+ announce2(state.transport === "live" ? "Live encrypted review selected. Anyone with this link can comment." : state.transport === "short" ? "Encrypted short link selected. Creation requires confirmation." : "Private fragment selected. Nothing will be uploaded.");
2653
+ return;
2654
+ }
2655
+ if (button.dataset.planrShareConfirm !== void 0) {
2656
+ void confirm();
2657
+ return;
2658
+ }
2659
+ if (button.dataset.planrShareCopyUrl !== void 0) {
2660
+ void copy(state.result?.url, "Review URL copied.", button);
2661
+ return;
2662
+ }
2663
+ if (button.dataset.planrShareCopyOwner !== void 0) {
2664
+ void copy(
2665
+ state.result?.ownerUrl,
2666
+ "Private owner-verdict URL copied. It requires the matching downloaded owner key.",
2667
+ button
2668
+ );
2669
+ return;
2670
+ }
2671
+ if (button.dataset.planrShareCopyManage !== void 0) {
2672
+ void copy(
2673
+ state.result?.manageUrl,
2674
+ "Private management URL copied. It can pause, reopen, or delete the room, but cannot set a verdict.",
2675
+ button
2676
+ );
2677
+ return;
2678
+ }
2679
+ if (button.dataset.planrShareCopyDeletion !== void 0) {
2680
+ void copy(state.result?.deletionToken, "One-time deletion token copied.", button);
2681
+ }
2682
+ });
2683
+ const ttlSelect = dialog.querySelector("[data-planr-share-ttl]");
2684
+ if (ttlSelect) listen(ttlSelect, "change", () => {
2685
+ if (["custody-ready", "creating", "ambiguous", "created"].includes(state.phase)) {
2686
+ ttlSelect.value = state.ttl;
2687
+ return;
2688
+ }
2689
+ state = reduceArtifactShareDialog(state, { type: "set-ttl", ttl: ttlSelect.value });
2690
+ render();
2691
+ announce2(`Expiry set to ${ARTIFACT_SHARE_TTLS[state.ttl].label}.`);
2692
+ });
2693
+ listen(document2, "keydown", (event) => {
2694
+ if (!state.open) return;
2695
+ if (event.key === "Escape") {
2696
+ event.preventDefault();
2697
+ close();
2698
+ return;
2699
+ }
2700
+ if (event.key !== "Tab") return;
2701
+ const focusable = focusableElements(dialog);
2702
+ if (focusable.length === 0) return;
2703
+ const first = focusable[0];
2704
+ const last = focusable.at(-1);
2705
+ if (event.shiftKey && document2.activeElement === first) {
2706
+ event.preventDefault();
2707
+ last.focus();
2708
+ } else if (!event.shiftKey && document2.activeElement === last) {
2709
+ event.preventDefault();
2710
+ first.focus();
2711
+ }
2712
+ }, true);
2713
+ render();
2714
+ const controller = Object.freeze({
2715
+ getState: () => state,
2716
+ open,
2717
+ close,
2718
+ confirm,
2719
+ dispatch(action) {
2720
+ if (action.type === "select-transport" && !supports(action.transport)) return state;
2721
+ state = reduceArtifactShareDialog(state, action);
2722
+ render();
2723
+ return state;
2724
+ },
2725
+ destroy() {
2726
+ if (state.phase === "creating" || state.phase === "ambiguous") {
2727
+ announce2(state.phase === "ambiguous" ? "Room creation may have completed. Retry the exact attempt until its receipt is shown." : "Room creation is in progress. Keep this review open until its receipt is shown.");
2728
+ return false;
2729
+ }
2730
+ generation += 1;
2731
+ clearPendingOwnerSigner();
2732
+ for (const timer of copyResetTimers.values()) window.clearTimeout(timer);
2733
+ copyResetTimers.clear();
2734
+ for (const remove of cleanup.splice(0)) remove();
2735
+ if (state.open) {
2736
+ state = reduceArtifactShareDialog(state, { type: "close" });
2737
+ render();
2738
+ }
2739
+ return true;
2740
+ }
2741
+ });
2742
+ window.__openPlanrArtifactShare = controller;
2743
+ return controller;
2744
+ }
2745
+
2746
+ // lib/artifact/ui/hosted-viewer.mjs
2747
+ var HOSTED_ARTIFACT_VIEWER_STATES = Object.freeze([
2748
+ "idle",
2749
+ "empty-hash",
2750
+ "loading",
2751
+ "ready",
2752
+ "invalid-version",
2753
+ "malformed-payload",
2754
+ "too-large",
2755
+ "paste-missing",
2756
+ "expired",
2757
+ "decryption-failed",
2758
+ "unsupported-browser",
2759
+ "network-error",
2760
+ "room-closed"
2761
+ ]);
2762
+ var HOSTED_ARTIFACT_STATE_COPY = Object.freeze({
2763
+ "empty-hash": Object.freeze({
2764
+ title: "Open a private review link",
2765
+ detail: "This page needs a complete OpenPlanr fragment or encrypted short-link URL.",
2766
+ action: ""
2767
+ }),
2768
+ loading: Object.freeze({
2769
+ title: "Loading private review",
2770
+ detail: "Validating the immutable payload before opening the artifact.",
2771
+ action: ""
2772
+ }),
2773
+ "invalid-version": Object.freeze({
2774
+ title: "This review version is not supported",
2775
+ detail: "Ask the sender to create a new link with a compatible OpenPlanr release.",
2776
+ action: ""
2777
+ }),
2778
+ "malformed-payload": Object.freeze({
2779
+ title: "This review link is incomplete",
2780
+ detail: "Copy the complete URL again, including everything after the # character.",
2781
+ action: ""
2782
+ }),
2783
+ "too-large": Object.freeze({
2784
+ title: "This private fragment is too large",
2785
+ detail: "Ask the sender to create an encrypted expiring short link instead.",
2786
+ action: ""
2787
+ }),
2788
+ "paste-missing": Object.freeze({
2789
+ title: "This encrypted review is unavailable",
2790
+ detail: "It may have been deleted. Ask the sender for a new immutable review link.",
2791
+ action: ""
2792
+ }),
2793
+ expired: Object.freeze({
2794
+ title: "This encrypted review expired",
2795
+ detail: "Ask the sender for a new immutable review link.",
2796
+ action: ""
2797
+ }),
2798
+ "decryption-failed": Object.freeze({
2799
+ title: "This key cannot decrypt the review",
2800
+ detail: "Use the complete link, including its private fragment key. The payload may also have been changed.",
2801
+ action: ""
2802
+ }),
2803
+ "unsupported-browser": Object.freeze({
2804
+ title: "Browser support is required",
2805
+ detail: "Use a current browser with raw DEFLATE and Web Crypto support.",
2806
+ action: ""
2807
+ }),
2808
+ "network-error": Object.freeze({
2809
+ title: "The encrypted review could not be loaded",
2810
+ detail: "Your link remains unchanged. Check the connection and try again safely.",
2811
+ action: "Try again"
2812
+ }),
2813
+ "room-closed": Object.freeze({
2814
+ title: "Comments are paused",
2815
+ detail: "This review remains available to read, but the owner has paused new feedback.",
2816
+ action: ""
2817
+ })
2818
+ });
2819
+ var HostedArtifactViewerError = class extends Error {
2820
+ constructor(code, message, details = {}) {
2821
+ super(message);
2822
+ this.name = "HostedArtifactViewerError";
2823
+ this.code = code;
2824
+ this.details = Object.freeze({ ...details });
2825
+ }
2826
+ };
2827
+ function freezeState2(value) {
2828
+ const status = HOSTED_ARTIFACT_VIEWER_STATES.includes(value.status) ? value.status : "idle";
2829
+ return Object.freeze({
2830
+ status,
2831
+ transport: ["fragment", "short", "room"].includes(value.transport) ? value.transport : null,
2832
+ request: value.request ? Object.freeze({ ...value.request }) : null,
2833
+ envelope: value.envelope ?? null,
2834
+ retryable: status === "network-error"
2835
+ });
2836
+ }
2837
+ function locationParts(location) {
2838
+ if (typeof location === "string") {
2839
+ const parsed = new URL(location, "https://share.openplanr.dev/");
2840
+ return { pathname: parsed.pathname, hash: parsed.hash };
2841
+ }
2842
+ return {
2843
+ pathname: typeof location?.pathname === "string" ? location.pathname : "/",
2844
+ hash: typeof location?.hash === "string" ? location.hash : ""
2845
+ };
2846
+ }
2847
+ function malformed(status, details = {}) {
2848
+ return Object.freeze({ ok: false, status, details: Object.freeze(details) });
2849
+ }
2850
+ function parseHostedArtifactLocation(location, {
2851
+ fragmentLimit = ARTIFACT_SHARE_FRAGMENT_LIMIT
2852
+ } = {}) {
2853
+ const { pathname, hash } = locationParts(location);
2854
+ const shortMatch = pathname.match(/^\/p\/([A-Za-z0-9_-]{1,128})\/?$/);
2855
+ if (shortMatch) {
2856
+ if (!hash.startsWith("#k=")) return malformed("malformed-payload", { transport: "short" });
2857
+ const key = hash.slice(3);
2858
+ if (!/^[A-Za-z0-9_-]{43}$/.test(key)) {
2859
+ return malformed("malformed-payload", { transport: "short" });
2860
+ }
2861
+ return Object.freeze({
2862
+ ok: true,
2863
+ transport: "short",
2864
+ id: shortMatch[1],
2865
+ key
2866
+ });
2867
+ }
2868
+ const roomMatch = pathname.match(/^\/r\/([A-Za-z0-9_-]{16,128})\/?$/);
2869
+ if (roomMatch) {
2870
+ const params = new URLSearchParams(hash.slice(1));
2871
+ const key = params.get("k");
2872
+ const write = params.get("w");
2873
+ const owner = params.get("o");
2874
+ const manage = params.get("m");
2875
+ const authority = [write, owner, manage].filter(Boolean);
2876
+ if (!key || !/^[A-Za-z0-9_-]{43}$/.test(key) || authority.length > 1 || write && !/^[A-Za-z0-9_-]{43}$/.test(write) || owner && !/^[A-Za-z0-9_-]{43}$/.test(owner) || manage && !/^[A-Za-z0-9_-]{43}$/.test(manage)) {
2877
+ return malformed("malformed-payload", { transport: "room" });
2878
+ }
2879
+ return Object.freeze({ ok: true, transport: "room", id: roomMatch[1], key, ...write ? { write } : {}, ...owner ? { owner } : {}, ...manage ? { manage } : {} });
2880
+ }
2881
+ if (!hash || hash === "#") return malformed("empty-hash");
2882
+ const fragment = hash.slice(1);
2883
+ if (fragment.length > fragmentLimit) {
2884
+ return malformed("too-large", { fragmentLength: fragment.length, fragmentLimit });
2885
+ }
2886
+ if (!fragment.startsWith("v1.")) {
2887
+ return malformed(/^v\d+\./.test(fragment) ? "invalid-version" : "malformed-payload");
2888
+ }
2889
+ const payload = fragment.slice(3);
2890
+ if (!payload || !/^[A-Za-z0-9_-]+$/.test(payload)) return malformed("malformed-payload");
2891
+ return Object.freeze({ ok: true, transport: "fragment", version: "v1", payload });
2892
+ }
2893
+ function hostedArtifactStateForError(error) {
2894
+ const code = typeof error?.code === "string" ? error.code : "";
2895
+ if (["E_ARTIFACT_BROWSER_UNSUPPORTED", "E_ARTIFACT_CODEC_UNSUPPORTED"].includes(code)) {
2896
+ return "unsupported-browser";
2897
+ }
2898
+ if (["E_ARTIFACT_FRAGMENT_TOO_LARGE", "E_ARTIFACT_PAYLOAD_TOO_LARGE", "E_ARTIFACT_DECOMPRESSION_LIMIT"].includes(code)) {
2899
+ return "too-large";
2900
+ }
2901
+ if (["E_ARTIFACT_PASTE_NOT_FOUND", "E_ARTIFACT_SHARE_NOT_FOUND", "E_ARTIFACT_PASTE_UNAVAILABLE"].includes(code)) {
2902
+ return "paste-missing";
2903
+ }
2904
+ if (["E_ARTIFACT_PASTE_EXPIRED", "E_ARTIFACT_SHARE_EXPIRED"].includes(code)) {
2905
+ return "expired";
2906
+ }
2907
+ if (["E_ARTIFACT_DECRYPTION_FAILED", "E_ARTIFACT_AUTH_FAILED", "E_ARTIFACT_PAYLOAD_TAMPERED", "OperationError"].includes(code)) {
2908
+ return "decryption-failed";
2909
+ }
2910
+ if (["E_ARTIFACT_SHARE_NETWORK", "E_ARTIFACT_NETWORK", "E_ARTIFACT_FETCH_FAILED"].includes(code) || error?.name === "TypeError") {
2911
+ return "network-error";
2912
+ }
2913
+ if (["E_ARTIFACT_VERSION_UNSUPPORTED", "E_ARTIFACT_FRAGMENT_VERSION", "E_ARTIFACT_FRAGMENT_VERSION_UNSUPPORTED"].includes(code)) {
2914
+ return "invalid-version";
2915
+ }
2916
+ if (code === "E_ARTIFACT_PASTE_INVALID") return "malformed-payload";
2917
+ return "malformed-payload";
2918
+ }
2919
+ function setCopy(document2, status) {
2920
+ const copy = HOSTED_ARTIFACT_STATE_COPY[status] ?? { title: "", detail: "", action: "" };
2921
+ const title = document2.querySelector("[data-planr-hosted-title]");
2922
+ const detail = document2.querySelector("[data-planr-hosted-detail]");
2923
+ const action = document2.querySelector("[data-planr-hosted-retry]");
2924
+ if (title) title.textContent = copy.title;
2925
+ if (detail) detail.textContent = copy.detail;
2926
+ if (action) {
2927
+ action.textContent = copy.action;
2928
+ action.hidden = !copy.action;
2929
+ }
2930
+ }
2931
+ function mountHostedArtifactViewer({
2932
+ document: document2 = globalThis.document,
2933
+ window = document2?.defaultView,
2934
+ enabled = false,
2935
+ location = window?.location,
2936
+ decodeFragment,
2937
+ loadShort,
2938
+ loadRoom,
2939
+ onEnvelope,
2940
+ supportsTransport = () => true,
2941
+ fragmentLimit = ARTIFACT_SHARE_FRAGMENT_LIMIT
2942
+ } = {}) {
2943
+ if (!enabled || !document2 || !window) return null;
2944
+ const slot = document2.querySelector("[data-planr-hosted-viewer]");
2945
+ if (!slot) return null;
2946
+ let state = freezeState2({ status: "idle" });
2947
+ let generation = 0;
2948
+ const cleanup = [];
2949
+ function render() {
2950
+ const visible = !["idle", "ready"].includes(state.status);
2951
+ slot.hidden = !visible;
2952
+ slot.dataset.planrHostedState = state.status;
2953
+ slot.setAttribute("aria-busy", String(state.status === "loading"));
2954
+ setCopy(document2, state.status);
2955
+ }
2956
+ function setState(next) {
2957
+ state = freezeState2(next);
2958
+ render();
2959
+ return state;
2960
+ }
2961
+ async function load() {
2962
+ const parsed = parseHostedArtifactLocation(location, { fragmentLimit });
2963
+ if (!parsed.ok) return setState({ status: parsed.status });
2964
+ const request = parsed.transport === "fragment" ? { transport: "fragment", version: parsed.version, payload: parsed.payload } : { transport: parsed.transport, id: parsed.id, key: parsed.key, ...parsed.write ? { write: parsed.write } : {}, ...parsed.owner ? { owner: parsed.owner } : {}, ...parsed.manage ? { manage: parsed.manage } : {} };
2965
+ if (!supportsTransport(parsed.transport)) {
2966
+ return setState({ status: "unsupported-browser", transport: parsed.transport, request });
2967
+ }
2968
+ const sequence = ++generation;
2969
+ setState({ status: "loading", transport: parsed.transport, request });
2970
+ try {
2971
+ const envelope = parsed.transport === "fragment" ? await (typeof decodeFragment === "function" ? decodeFragment(Object.freeze({ version: parsed.version, payload: parsed.payload })) : Promise.reject(new HostedArtifactViewerError(
2972
+ "E_ARTIFACT_CODEC_UNSUPPORTED",
2973
+ "No private-fragment decoder is installed."
2974
+ ))) : parsed.transport === "short" ? await (typeof loadShort === "function" ? loadShort(Object.freeze({ id: parsed.id, key: parsed.key })) : Promise.reject(new HostedArtifactViewerError(
2975
+ "E_ARTIFACT_BROWSER_UNSUPPORTED",
2976
+ "No encrypted short-link loader is installed."
2977
+ ))) : await (typeof loadRoom === "function" ? loadRoom(Object.freeze({ id: parsed.id, key: parsed.key, ...parsed.write ? { write: parsed.write } : {}, ...parsed.owner ? { owner: parsed.owner } : {}, ...parsed.manage ? { manage: parsed.manage } : {} })) : Promise.reject(new HostedArtifactViewerError("E_ARTIFACT_BROWSER_UNSUPPORTED", "No live review room loader is installed.")));
2978
+ if (sequence !== generation) return state;
2979
+ setState({ status: "ready", transport: parsed.transport, request, envelope });
2980
+ if (typeof onEnvelope === "function") await onEnvelope(envelope, Object.freeze({ transport: parsed.transport }));
2981
+ } catch (error) {
2982
+ if (sequence !== generation) return state;
2983
+ setState({ status: hostedArtifactStateForError(error), transport: parsed.transport, request });
2984
+ }
2985
+ return state;
2986
+ }
2987
+ function onClick(event) {
2988
+ if (!event.target.closest?.("[data-planr-hosted-retry]") || !state.retryable) return;
2989
+ void load();
2990
+ }
2991
+ slot.addEventListener("click", onClick);
2992
+ cleanup.push(() => slot.removeEventListener("click", onClick));
2993
+ render();
2994
+ const ready = load();
2995
+ const controller = Object.freeze({
2996
+ getState: () => state,
2997
+ ready,
2998
+ retry() {
2999
+ return state.retryable ? load() : Promise.resolve(state);
3000
+ },
3001
+ load,
3002
+ destroy() {
3003
+ generation += 1;
3004
+ for (const remove of cleanup.splice(0)) remove();
3005
+ }
3006
+ });
3007
+ window.__openPlanrHostedArtifactViewer = controller;
3008
+ return controller;
3009
+ }
3010
+
3011
+ // lib/artifact/ui/stage-payload.mjs
3012
+ var PRESENTATIONS = Object.freeze(["document", "canvas"]);
3013
+ function positiveInteger(value, fallback) {
3014
+ return Number.isInteger(value) && value > 0 ? value : fallback;
3015
+ }
3016
+ function freezeArtifactMetadata(artifact, index) {
3017
+ if (!artifact || typeof artifact !== "object") {
3018
+ throw new TypeError(`Artifact ${index + 1} must be an object.`);
3019
+ }
3020
+ if (typeof artifact.id !== "string" || artifact.id.length === 0) {
3021
+ throw new TypeError(`Artifact ${index + 1} requires an id.`);
3022
+ }
3023
+ return Object.freeze({
3024
+ id: artifact.id,
3025
+ title: typeof artifact.title === "string" && artifact.title.length > 0 ? artifact.title : `Artifact ${index + 1}`,
3026
+ sha256: typeof artifact.sha256 === "string" ? artifact.sha256 : "",
3027
+ viewport: Object.freeze({
3028
+ width: positiveInteger(artifact.viewport?.width, 1440),
3029
+ height: positiveInteger(artifact.viewport?.height, 900)
3030
+ }),
3031
+ colorScheme: ["light", "dark"].includes(artifact.colorScheme) ? artifact.colorScheme : "light"
3032
+ });
3033
+ }
3034
+ function requestedArtifactId(value) {
3035
+ if (typeof value === "string") return value;
3036
+ return typeof value?.id === "string" ? value.id : "";
3037
+ }
3038
+ function availableId(artifacts, requested, fallback = "") {
3039
+ return artifacts.some(({ id }) => id === requested) ? requested : fallback;
3040
+ }
3041
+ function normalizeViewMode(value, artifactCount) {
3042
+ if (artifactCount < 2) return "single";
3043
+ return ["single", "variants", "split"].includes(value) ? value : "variants";
3044
+ }
3045
+ function createArtifactStagePayload(envelope = {}, { viewer } = {}) {
3046
+ const artifacts = Object.freeze(
3047
+ (Array.isArray(envelope?.artifacts) ? envelope.artifacts : []).map(freezeArtifactMetadata)
3048
+ );
3049
+ const sourceViewer = viewer && typeof viewer === "object" ? viewer : envelope?.viewer && typeof envelope.viewer === "object" ? envelope.viewer : {};
3050
+ const firstId = artifacts[0]?.id ?? "";
3051
+ const activeArtifactId = availableId(
3052
+ artifacts,
3053
+ requestedArtifactId(sourceViewer.activeArtifactId),
3054
+ firstId
3055
+ );
3056
+ const mode = normalizeViewMode(sourceViewer.mode, artifacts.length);
3057
+ return Object.freeze({
3058
+ schemaVersion: "1.0.0",
3059
+ artifacts,
3060
+ viewer: Object.freeze({
3061
+ mode,
3062
+ activeArtifactId,
3063
+ ...PRESENTATIONS.includes(sourceViewer.presentation) ? { presentation: sourceViewer.presentation } : {}
3064
+ })
3065
+ });
3066
+ }
3067
+
3068
+ // lib/artifact/ui/stage.mjs
3069
+ var ARTIFACT_STAGE_EVENTS = Object.freeze({
3070
+ change: "planr:stage-change",
3071
+ point: "planr:artifact-point",
3072
+ region: "planr:artifact-region",
3073
+ layout: "planr:artifact-layout"
3074
+ });
3075
+ var ARTIFACT_STAGE_LIMITS = Object.freeze({
3076
+ defaultZoom: 72,
3077
+ minZoom: 25,
3078
+ maxZoom: 200,
3079
+ zoomStep: 10,
3080
+ maxDocumentWidth: 16384,
3081
+ maxDocumentHeight: 262144
3082
+ });
3083
+ var VIEW_MODES = Object.freeze(["single", "variants", "split"]);
3084
+ var REVIEW_MODES = Object.freeze(["interact", "comment"]);
3085
+ var THEMES = Object.freeze(["auto", "light", "dark"]);
3086
+ var PRESENTATIONS2 = Object.freeze(["document", "canvas"]);
3087
+ var STATUSES = Object.freeze([
3088
+ "ready",
3089
+ "empty",
3090
+ "bundling",
3091
+ "loading",
3092
+ "invalid",
3093
+ "expired",
3094
+ "decryption-failed",
3095
+ "unsupported-browser"
3096
+ ]);
3097
+ var STATUS_COPY = Object.freeze({
3098
+ empty: Object.freeze({
3099
+ title: "No artifact content",
3100
+ detail: "Choose a bundled HTML artifact to begin this review."
3101
+ }),
3102
+ bundling: Object.freeze({
3103
+ title: "Bundling artifact",
3104
+ detail: "Packaging local scripts, styles, fonts, and images without network access."
3105
+ }),
3106
+ loading: Object.freeze({
3107
+ title: "Loading private review",
3108
+ detail: "Validating the envelope and frozen artifact viewport."
3109
+ }),
3110
+ invalid: Object.freeze({
3111
+ title: "This review is invalid",
3112
+ detail: "The artifact envelope could not be decoded or validated."
3113
+ }),
3114
+ expired: Object.freeze({
3115
+ title: "This encrypted review expired",
3116
+ detail: "Ask the sender for a new immutable review link."
3117
+ }),
3118
+ "decryption-failed": Object.freeze({
3119
+ title: "This key cannot decrypt the review",
3120
+ detail: "Use the complete link, including its private fragment key."
3121
+ }),
3122
+ "unsupported-browser": Object.freeze({
3123
+ title: "Browser support is required",
3124
+ detail: "Use a current browser with Blob URL support to review this artifact."
3125
+ })
3126
+ });
3127
+ function member2(value, allowed, fallback) {
3128
+ return allowed.includes(value) ? value : fallback;
3129
+ }
3130
+ function finite2(value, fallback = 0) {
3131
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
3132
+ }
3133
+ function clamp2(value, min, max) {
3134
+ return Math.min(max, Math.max(min, value));
3135
+ }
3136
+ function normalized2(value) {
3137
+ return Math.round(clamp2(finite2(value), 0, 1) * 1e6) / 1e6;
3138
+ }
3139
+ function artifactMetadata(artifact) {
3140
+ return Object.freeze({
3141
+ id: artifact.id,
3142
+ title: artifact.title,
3143
+ sha256: artifact.sha256,
3144
+ viewport: artifact.viewport,
3145
+ colorScheme: artifact.colorScheme
3146
+ });
3147
+ }
3148
+ function requestedArtifactId2(value) {
3149
+ if (typeof value === "string") return value;
3150
+ return typeof value?.id === "string" ? value.id : "";
3151
+ }
3152
+ function availableId2(artifacts, requested, fallback = "") {
3153
+ return artifacts.some(({ id }) => id === requested) ? requested : fallback;
3154
+ }
3155
+ function comparisonIdFor(artifacts, activeArtifactId, requested = "") {
3156
+ if (requested !== activeArtifactId && artifacts.some(({ id }) => id === requested)) return requested;
3157
+ return artifacts.find(({ id }) => id !== activeArtifactId)?.id ?? "";
3158
+ }
3159
+ function normalizeViewMode2(value, artifactCount) {
3160
+ if (artifactCount < 2) return "single";
3161
+ return member2(value, VIEW_MODES, "variants");
3162
+ }
3163
+ function resolveArtifactPresentation(value, { viewMode = "single", artifactCount = 1 } = {}) {
3164
+ if (PRESENTATIONS2.includes(value)) return value;
3165
+ return artifactCount > 1 || viewMode === "variants" || viewMode === "split" ? "canvas" : "document";
3166
+ }
3167
+ function createArtifactStageState(payload = {}, shellModel = {}) {
3168
+ const artifacts = Object.freeze(
3169
+ (Array.isArray(payload?.artifacts) ? payload.artifacts : []).map(artifactMetadata)
3170
+ );
3171
+ const firstId = artifacts[0]?.id ?? "";
3172
+ const activeArtifactId = availableId2(
3173
+ artifacts,
3174
+ requestedArtifactId2(shellModel.activeArtifact ?? shellModel.activeArtifactId) || requestedArtifactId2(payload?.viewer?.activeArtifactId),
3175
+ firstId
3176
+ );
3177
+ const comparisonArtifactId = comparisonIdFor(
3178
+ artifacts,
3179
+ activeArtifactId,
3180
+ requestedArtifactId2(shellModel.comparisonArtifact ?? shellModel.comparisonArtifactId)
3181
+ );
3182
+ const statusFallback = artifacts.length === 0 ? "empty" : "ready";
3183
+ let status = member2(shellModel.status, STATUSES, statusFallback);
3184
+ if (artifacts.length === 0 && status === "ready") status = "empty";
3185
+ const viewMode = normalizeViewMode2(
3186
+ shellModel.viewMode ?? payload?.viewer?.mode,
3187
+ artifacts.length
3188
+ );
3189
+ const presentation = resolveArtifactPresentation(
3190
+ shellModel.presentation ?? payload?.viewer?.presentation,
3191
+ { viewMode, artifactCount: artifacts.length }
3192
+ );
3193
+ return Object.freeze({
3194
+ schemaVersion: "1.0.0",
3195
+ artifacts,
3196
+ activeArtifactId,
3197
+ comparisonArtifactId,
3198
+ viewMode,
3199
+ presentation,
3200
+ reviewMode: member2(shellModel.reviewMode, REVIEW_MODES, "interact"),
3201
+ zoom: clamp2(
3202
+ Number.isInteger(shellModel.zoom) ? shellModel.zoom : ARTIFACT_STAGE_LIMITS.defaultZoom,
3203
+ ARTIFACT_STAGE_LIMITS.minZoom,
3204
+ ARTIFACT_STAGE_LIMITS.maxZoom
3205
+ ),
3206
+ railOpen: shellModel.railOpen === void 0 ? presentation === "canvas" : Boolean(shellModel.railOpen),
3207
+ theme: member2(shellModel.theme, THEMES, "auto"),
3208
+ status
3209
+ });
3210
+ }
3211
+ function nextState(state, changes) {
3212
+ return Object.freeze({ ...state, ...changes });
3213
+ }
3214
+ function reduceArtifactStageState(state, action = {}) {
3215
+ switch (action.type) {
3216
+ case "set-active": {
3217
+ const id = availableId2(state.artifacts, action.artifactId);
3218
+ if (!id || id === state.activeArtifactId) return state;
3219
+ const comparisonArtifactId = id === state.comparisonArtifactId ? state.activeArtifactId : comparisonIdFor(state.artifacts, id, state.comparisonArtifactId);
3220
+ return nextState(state, { activeArtifactId: id, comparisonArtifactId });
3221
+ }
3222
+ case "set-comparison": {
3223
+ const id = comparisonIdFor(state.artifacts, state.activeArtifactId, action.artifactId);
3224
+ return id === state.comparisonArtifactId ? state : nextState(state, { comparisonArtifactId: id });
3225
+ }
3226
+ case "set-view-mode": {
3227
+ const viewMode = normalizeViewMode2(action.viewMode, state.artifacts.length);
3228
+ return viewMode === state.viewMode ? state : nextState(state, { viewMode });
3229
+ }
3230
+ case "set-review-mode": {
3231
+ const reviewMode = member2(action.reviewMode, REVIEW_MODES, state.reviewMode);
3232
+ return reviewMode === state.reviewMode ? state : nextState(state, { reviewMode });
3233
+ }
3234
+ case "set-zoom": {
3235
+ const zoom = clamp2(
3236
+ Math.round(finite2(action.zoom, state.zoom)),
3237
+ ARTIFACT_STAGE_LIMITS.minZoom,
3238
+ ARTIFACT_STAGE_LIMITS.maxZoom
3239
+ );
3240
+ return zoom === state.zoom ? state : nextState(state, { zoom });
3241
+ }
3242
+ case "zoom-by":
3243
+ return reduceArtifactStageState(state, {
3244
+ type: "set-zoom",
3245
+ zoom: state.zoom + finite2(action.delta)
3246
+ });
3247
+ case "set-rail-open": {
3248
+ const railOpen = Boolean(action.railOpen);
3249
+ return railOpen === state.railOpen ? state : nextState(state, { railOpen });
3250
+ }
3251
+ case "toggle-rail":
3252
+ return nextState(state, { railOpen: !state.railOpen });
3253
+ case "set-theme": {
3254
+ const theme = member2(action.theme, THEMES, state.theme);
3255
+ return theme === state.theme ? state : nextState(state, { theme });
3256
+ }
3257
+ case "cycle-theme": {
3258
+ const index = THEMES.indexOf(state.theme);
3259
+ return nextState(state, { theme: THEMES[(index + 1) % THEMES.length] });
3260
+ }
3261
+ case "set-status": {
3262
+ const status = member2(action.status, STATUSES, state.status);
3263
+ return status === state.status ? state : nextState(state, { status });
3264
+ }
3265
+ default:
3266
+ return state;
3267
+ }
3268
+ }
3269
+ function visibleArtifactIds(state) {
3270
+ if (!state.activeArtifactId) return Object.freeze([]);
3271
+ if (state.viewMode === "split" && state.comparisonArtifactId) {
3272
+ return Object.freeze([state.activeArtifactId, state.comparisonArtifactId]);
3273
+ }
3274
+ return Object.freeze([state.activeArtifactId]);
3275
+ }
3276
+ function assertRect2(rect) {
3277
+ if (!rect || !Number.isFinite(rect.left) || !Number.isFinite(rect.top) || !Number.isFinite(rect.width) || !Number.isFinite(rect.height) || rect.width <= 0 || rect.height <= 0) {
3278
+ throw new RangeError("Artifact bounds must have positive finite dimensions.");
3279
+ }
3280
+ }
3281
+ function clientPointToNormalized(rect, point) {
3282
+ assertRect2(rect);
3283
+ return Object.freeze({
3284
+ x: normalized2((finite2(point?.x ?? point?.clientX) - rect.left) / rect.width),
3285
+ y: normalized2((finite2(point?.y ?? point?.clientY) - rect.top) / rect.height)
3286
+ });
3287
+ }
3288
+ function normalizedPointToClient(rect, point) {
3289
+ assertRect2(rect);
3290
+ return Object.freeze({
3291
+ x: rect.left + normalized2(point?.x) * rect.width,
3292
+ y: rect.top + normalized2(point?.y) * rect.height
3293
+ });
3294
+ }
3295
+ function parseDataScript(document2, id) {
3296
+ const node = document2.getElementById(id);
3297
+ if (!node) throw new Error(`Missing artifact shell data: ${id}`);
3298
+ return JSON.parse(node.textContent ?? "null");
3299
+ }
3300
+ function isEditableTarget(target) {
3301
+ const HTMLElement = target?.ownerDocument?.defaultView?.HTMLElement;
3302
+ return Boolean(HTMLElement && target instanceof HTMLElement && (target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName)));
3303
+ }
3304
+ function stageArtifactById(state, id) {
3305
+ return state.artifacts.find((artifact) => artifact.id === id) ?? null;
3306
+ }
3307
+ function updateStatus(document2, state) {
3308
+ const statusPanel = document2.querySelector(".planr-stage-status");
3309
+ const surface = document2.querySelector(".planr-stage-surface");
3310
+ if (!statusPanel || !surface) return;
3311
+ const ready = state.status === "ready";
3312
+ statusPanel.hidden = ready;
3313
+ surface.toggleAttribute("inert", !ready);
3314
+ surface.setAttribute("aria-hidden", String(!ready));
3315
+ if (ready) surface.removeAttribute("aria-hidden");
3316
+ const copy = STATUS_COPY[state.status];
3317
+ if (copy) {
3318
+ const title = statusPanel.querySelector("strong");
3319
+ const detail = statusPanel.querySelector("p");
3320
+ if (title) title.textContent = copy.title;
3321
+ if (detail) detail.textContent = copy.detail;
3322
+ }
3323
+ }
3324
+ function emit(root, window, type, detail) {
3325
+ root.dispatchEvent(new window.CustomEvent(type, { detail, bubbles: true }));
3326
+ }
3327
+ async function htmlForSource(window, source) {
3328
+ if (typeof source === "string" && source.trimStart().startsWith("<")) return source;
3329
+ if (source && typeof source === "object" && typeof source.html === "string") return source.html;
3330
+ if (source instanceof window.Blob) return source.text();
3331
+ if (source instanceof window.ArrayBuffer) return new window.TextDecoder().decode(source);
3332
+ if (window.ArrayBuffer.isView(source)) {
3333
+ return new window.TextDecoder().decode(
3334
+ new window.Uint8Array(source.buffer, source.byteOffset, source.byteLength)
3335
+ );
3336
+ }
3337
+ return null;
3338
+ }
3339
+ function mountArtifactStage({
3340
+ document: document2 = globalThis.document,
3341
+ window = document2?.defaultView,
3342
+ resolveArtifactSource,
3343
+ sourceTransport = "blob",
3344
+ bridgeClient,
3345
+ onState,
3346
+ review: reviewOptions = {},
3347
+ share: shareOptions = {},
3348
+ hosted: hostedOptions = {}
3349
+ } = {}) {
3350
+ if (!document2 || !window) return null;
3351
+ const root = document2.querySelector(".planr-shell");
3352
+ if (!root) return null;
3353
+ if (!["blob", "srcdoc"].includes(sourceTransport)) {
3354
+ throw new TypeError("Artifact source transport must be blob or srcdoc.");
3355
+ }
3356
+ let payload;
3357
+ let shellModel;
3358
+ let reviewConfig;
3359
+ try {
3360
+ payload = parseDataScript(document2, "planr-artifact-stage-payload");
3361
+ shellModel = parseDataScript(document2, "planr-artifact-shell-model");
3362
+ reviewConfig = parseDataScript(document2, "planr-artifact-review-state");
3363
+ } catch {
3364
+ payload = { artifacts: [], viewer: { mode: "single", activeArtifactId: "" } };
3365
+ shellModel = { status: "invalid" };
3366
+ reviewConfig = { reviewOf: "0".repeat(64), review: null };
3367
+ }
3368
+ let state;
3369
+ try {
3370
+ state = createArtifactStageState(payload, shellModel);
3371
+ } catch {
3372
+ state = createArtifactStageState({}, { status: "invalid" });
3373
+ }
3374
+ const frames = new Map(
3375
+ [...document2.querySelectorAll("[data-planr-artifact-frame]")].map((frame) => [frame.dataset.planrArtifactFrame, frame])
3376
+ );
3377
+ const panels = new Map(
3378
+ [...document2.querySelectorAll(".planr-artifact-panel[data-artifact-id]")].map((panel) => [panel.dataset.artifactId, panel])
3379
+ );
3380
+ const documentLayouts = /* @__PURE__ */ new Map();
3381
+ const cleanup = [];
3382
+ const frameBudget = root.dataset.planrFrameBudget === "3" ? 3 : null;
3383
+ const frameLoads = /* @__PURE__ */ new Map();
3384
+ let frameUse = 0;
3385
+ let frameQueue = Promise.resolve();
3386
+ let disposed = false;
3387
+ for (const frame of frames.values()) frame.dataset.planrFrameState = "unloaded";
3388
+ function listen(target, type, handler, options) {
3389
+ target.addEventListener(type, handler, options);
3390
+ cleanup.push(() => target.removeEventListener(type, handler, options));
3391
+ }
3392
+ function render({ announce: announce2 = false } = {}) {
3393
+ const visible = new Set(visibleArtifactIds(state));
3394
+ root.dataset.planrView = state.viewMode;
3395
+ root.dataset.planrReviewMode = state.reviewMode;
3396
+ root.dataset.planrState = state.status;
3397
+ root.dataset.planrRailOpen = String(state.railOpen);
3398
+ root.dataset.planrPresentation = state.presentation;
3399
+ document2.documentElement.dataset.planrPresentation = state.presentation;
3400
+ document2.documentElement.dataset.planrTheme = state.theme;
3401
+ const grid = document2.querySelector(".planr-frame-grid");
3402
+ const surface = document2.querySelector(".planr-stage-surface");
3403
+ const tablist = document2.querySelector(".planr-variants");
3404
+ const rail = document2.getElementById("planr-review-rail");
3405
+ const feedbackButton = document2.querySelector('[data-planr-action="feedback"]');
3406
+ const addCommentButton = document2.querySelector('[data-planr-action="add-comment"]');
3407
+ const themeButton = document2.querySelector('[data-planr-action="theme"]');
3408
+ const statusSlot = document2.querySelector('[data-planr-slot="status"]');
3409
+ const metadata = document2.querySelector(".planr-title-block > span");
3410
+ const breadcrumb = document2.querySelector(".planr-stage-heading > span:first-child");
3411
+ const activeArtifact = stageArtifactById(state, state.activeArtifactId);
3412
+ if (grid) grid.dataset.planrLayout = state.viewMode;
3413
+ const visualOrder = state.viewMode === "split" ? [...visible, ...state.artifacts.map(({ id }) => id).filter((id) => !visible.has(id))] : state.artifacts.map(({ id }) => id);
3414
+ if (surface) surface.style.setProperty("--planr-shell-zoom", String(state.zoom / 100));
3415
+ if (tablist) tablist.hidden = state.viewMode === "single" || state.artifacts.length < 2;
3416
+ if (rail) {
3417
+ rail.toggleAttribute("inert", !state.railOpen);
3418
+ rail.setAttribute("aria-hidden", String(!state.railOpen));
3419
+ if (state.railOpen) rail.removeAttribute("aria-hidden");
3420
+ }
3421
+ if (feedbackButton) feedbackButton.setAttribute("aria-expanded", String(state.railOpen));
3422
+ if (addCommentButton) {
3423
+ const paused = root.hasAttribute("data-planr-room-comments-paused");
3424
+ addCommentButton.disabled = paused;
3425
+ addCommentButton.setAttribute("aria-pressed", String(state.reviewMode === "comment"));
3426
+ addCommentButton.setAttribute(
3427
+ "aria-label",
3428
+ paused ? "Add comment unavailable: comments are paused" : "Add comment"
3429
+ );
3430
+ addCommentButton.dataset.planrTooltip = paused ? "Comments are paused" : "Add comment (C)";
3431
+ }
3432
+ if (themeButton) {
3433
+ themeButton.textContent = state.theme;
3434
+ themeButton.setAttribute("aria-label", `Shell theme ${state.theme}`);
3435
+ }
3436
+ if (statusSlot) statusSlot.textContent = state.reviewMode === "comment" ? "Comment mode" : "Interactions enabled";
3437
+ if (metadata && activeArtifact) {
3438
+ metadata.textContent = `HTML · ${activeArtifact.viewport.width}×${activeArtifact.viewport.height}`;
3439
+ }
3440
+ if (breadcrumb) breadcrumb.textContent = `ARTIFACT / ${(activeArtifact?.title ?? "Artifact").toUpperCase()}`;
3441
+ for (const button of document2.querySelectorAll("[data-planr-view]")) {
3442
+ const mode = button.dataset.planrView;
3443
+ button.setAttribute("aria-pressed", String(mode === state.viewMode));
3444
+ button.disabled = state.artifacts.length < 2 && mode !== "single";
3445
+ }
3446
+ for (const button of document2.querySelectorAll("[data-planr-mode]")) {
3447
+ button.setAttribute("aria-pressed", String(button.dataset.planrMode === state.reviewMode));
3448
+ }
3449
+ for (const button of document2.querySelectorAll('[data-planr-action="zoom-reset"]')) {
3450
+ button.textContent = `${state.zoom}%`;
3451
+ }
3452
+ for (const tab of document2.querySelectorAll('[role="tab"][data-artifact-id]')) {
3453
+ const selected = tab.dataset.artifactId === state.activeArtifactId;
3454
+ tab.setAttribute("aria-selected", String(selected));
3455
+ tab.tabIndex = selected ? 0 : -1;
3456
+ }
3457
+ for (const [id, panel] of panels) {
3458
+ const isVisible = visible.has(id);
3459
+ const isPrimary = id === state.activeArtifactId;
3460
+ panel.hidden = !isVisible;
3461
+ panel.style.order = String(visualOrder.indexOf(id));
3462
+ const artifact = stageArtifactById(state, id);
3463
+ panel.setAttribute("aria-label", `${isPrimary ? "Primary" : "Comparison"} artifact: ${artifact?.title ?? id}`);
3464
+ const frame = frames.get(id);
3465
+ const frameReady = frameBudget === null || frame?.dataset.planrFrameState === "ready";
3466
+ const annotationLayer = panel.querySelector("[data-planr-annotation-layer]");
3467
+ if (frame) {
3468
+ frame.tabIndex = isVisible && frameReady && state.status === "ready" && state.reviewMode === "interact" ? 0 : -1;
3469
+ if (state.presentation === "document") {
3470
+ frame.setAttribute("scrolling", "no");
3471
+ frame.style.overflow = "hidden";
3472
+ } else {
3473
+ frame.removeAttribute("scrolling");
3474
+ frame.style.removeProperty("overflow");
3475
+ }
3476
+ }
3477
+ if (annotationLayer) {
3478
+ const enabled = isVisible && frameReady && state.status === "ready" && state.reviewMode === "comment";
3479
+ const hasComposer = Boolean(annotationLayer.querySelector("[data-planr-annotation-composer]"));
3480
+ annotationLayer.tabIndex = enabled ? 0 : -1;
3481
+ annotationLayer.setAttribute("aria-disabled", String(!enabled && !hasComposer));
3482
+ }
3483
+ }
3484
+ updateStatus(document2, state);
3485
+ if (typeof onState === "function") {
3486
+ try {
3487
+ onState(state);
3488
+ } catch {
3489
+ }
3490
+ }
3491
+ if (announce2) emit(root, window, ARTIFACT_STAGE_EVENTS.change, state);
3492
+ }
3493
+ function dispatch(action, { announce: announce2 = true } = {}) {
3494
+ const previous = state;
3495
+ state = reduceArtifactStageState(state, action);
3496
+ if (state !== previous) render({ announce: announce2 });
3497
+ return state;
3498
+ }
3499
+ function setActiveFromTab(tab, { focus = false } = {}) {
3500
+ dispatch({ type: "set-active", artifactId: tab.dataset.artifactId });
3501
+ if (focus) tab.focus();
3502
+ }
3503
+ function onClick(event) {
3504
+ const target = event.target.closest?.("button");
3505
+ if (!target) return;
3506
+ if (target.hasAttribute("data-planr-close-feedback")) {
3507
+ dispatch({ type: "set-rail-open", railOpen: false });
3508
+ document2.querySelector('[data-planr-action="feedback"]')?.focus();
3509
+ return;
3510
+ }
3511
+ if (target.dataset.planrView) {
3512
+ dispatch({ type: "set-view-mode", viewMode: target.dataset.planrView });
3513
+ return;
3514
+ }
3515
+ if (target.dataset.artifactId && target.getAttribute("role") === "tab") {
3516
+ setActiveFromTab(target);
3517
+ return;
3518
+ }
3519
+ if (target.dataset.planrMode) {
3520
+ dispatch({ type: "set-review-mode", reviewMode: target.dataset.planrMode });
3521
+ return;
3522
+ }
3523
+ switch (target.dataset.planrAction) {
3524
+ case "add-comment":
3525
+ if (!root.hasAttribute("data-planr-room-comments-paused")) {
3526
+ dispatch({ type: "set-review-mode", reviewMode: "comment" });
3527
+ }
3528
+ break;
3529
+ case "zoom-out":
3530
+ dispatch({ type: "zoom-by", delta: -ARTIFACT_STAGE_LIMITS.zoomStep });
3531
+ break;
3532
+ case "zoom-reset":
3533
+ dispatch({ type: "set-zoom", zoom: ARTIFACT_STAGE_LIMITS.defaultZoom });
3534
+ break;
3535
+ case "zoom-in":
3536
+ dispatch({ type: "zoom-by", delta: ARTIFACT_STAGE_LIMITS.zoomStep });
3537
+ break;
3538
+ case "feedback": {
3539
+ const rail = document2.getElementById("planr-review-rail");
3540
+ if (state.railOpen && rail?.contains(document2.activeElement)) target.focus();
3541
+ dispatch({ type: "toggle-rail" });
3542
+ break;
3543
+ }
3544
+ case "more": {
3545
+ const menu = target.closest(".planr-more")?.querySelector(".planr-more-menu");
3546
+ if (!menu) break;
3547
+ const open = menu.hidden;
3548
+ menu.hidden = !open;
3549
+ target.setAttribute("aria-expanded", String(open));
3550
+ if (open) menu.querySelector('[role="menuitem"]')?.focus();
3551
+ break;
3552
+ }
3553
+ case "sharing-options":
3554
+ target.closest(".planr-more-menu").hidden = true;
3555
+ document2.querySelector('[data-planr-action="more"]')?.setAttribute("aria-expanded", "false");
3556
+ shareController?.open?.();
3557
+ break;
3558
+ case "theme":
3559
+ dispatch({ type: "cycle-theme" });
3560
+ break;
3561
+ default:
3562
+ break;
3563
+ }
3564
+ }
3565
+ function onKeyDown(event) {
3566
+ if (event.defaultPrevented) return;
3567
+ if (!event.altKey && !event.ctrlKey && !event.metaKey && !isEditableTarget(event.target)) {
3568
+ if (event.key.toLowerCase() === "i") {
3569
+ dispatch({ type: "set-review-mode", reviewMode: "interact" });
3570
+ return;
3571
+ }
3572
+ if (event.key.toLowerCase() === "c") {
3573
+ if (!root.hasAttribute("data-planr-room-comments-paused")) {
3574
+ dispatch({ type: "set-review-mode", reviewMode: "comment" });
3575
+ document2.querySelector('[data-planr-action="add-comment"]')?.focus();
3576
+ }
3577
+ return;
3578
+ }
3579
+ if (event.key === "Escape") {
3580
+ const more = document2.querySelector(".planr-more-menu:not([hidden])");
3581
+ if (more) {
3582
+ more.hidden = true;
3583
+ const trigger = document2.querySelector('[data-planr-action="more"]');
3584
+ trigger?.setAttribute("aria-expanded", "false");
3585
+ trigger?.focus();
3586
+ return;
3587
+ }
3588
+ if (state.presentation === "document" && state.reviewMode === "comment") {
3589
+ dispatch({ type: "set-review-mode", reviewMode: "interact" });
3590
+ document2.querySelector('[data-planr-action="add-comment"]')?.focus();
3591
+ return;
3592
+ }
3593
+ if (state.railOpen) {
3594
+ dispatch({ type: "set-rail-open", railOpen: false });
3595
+ document2.querySelector('[data-planr-action="feedback"]')?.focus();
3596
+ return;
3597
+ }
3598
+ }
3599
+ }
3600
+ const tab = event.target.closest?.('[role="tab"][data-artifact-id]');
3601
+ if (!tab || !["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) return;
3602
+ const tabs = [...document2.querySelectorAll('[role="tab"][data-artifact-id]')];
3603
+ const index = tabs.indexOf(tab);
3604
+ if (index < 0) return;
3605
+ event.preventDefault();
3606
+ const nextIndex = event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : (index + (event.key === "ArrowRight" ? 1 : -1) + tabs.length) % tabs.length;
3607
+ setActiveFromTab(tabs[nextIndex], { focus: true });
3608
+ }
3609
+ function emitSelection(layer, start, end = start) {
3610
+ if (state.reviewMode !== "comment" || state.status !== "ready") return;
3611
+ const artifactId = layer.dataset.planrAnnotationLayer;
3612
+ if (!visibleArtifactIds(state).includes(artifactId)) return;
3613
+ const artifact = stageArtifactById(state, artifactId);
3614
+ if (!artifact) return;
3615
+ const region = clientSelectionToNormalized(layer.getBoundingClientRect(), start, end);
3616
+ const measured = state.presentation === "document" ? documentLayouts.get(artifactId) : null;
3617
+ const detail = Object.freeze({
3618
+ schemaVersion: "1.0.0",
3619
+ artifactId,
3620
+ region,
3621
+ viewport: measured ?? artifact.viewport
3622
+ });
3623
+ emit(root, window, ARTIFACT_STAGE_EVENTS.region, detail);
3624
+ emit(root, window, ARTIFACT_STAGE_EVENTS.point, detail);
3625
+ if (state.presentation === "document") {
3626
+ dispatch({ type: "set-review-mode", reviewMode: "interact" });
3627
+ }
3628
+ }
3629
+ for (const layer of document2.querySelectorAll("[data-planr-annotation-layer]")) {
3630
+ let selection = null;
3631
+ let selectionPreview = null;
3632
+ listen(layer, "pointerdown", (event) => {
3633
+ if (event.button !== 0 || state.reviewMode !== "comment" || state.status !== "ready") return;
3634
+ if (event.target !== layer) return;
3635
+ event.preventDefault();
3636
+ selection = { pointerId: event.pointerId, start: { x: event.clientX, y: event.clientY } };
3637
+ layer.setPointerCapture?.(event.pointerId);
3638
+ selectionPreview = document2.createElement("span");
3639
+ selectionPreview.className = "planr-region-selection";
3640
+ selectionPreview.setAttribute("aria-hidden", "true");
3641
+ layer.append(selectionPreview);
3642
+ });
3643
+ listen(layer, "pointermove", (event) => {
3644
+ if (!selection || selection.pointerId !== event.pointerId || !selectionPreview) return;
3645
+ const region = clientSelectionToNormalized(
3646
+ layer.getBoundingClientRect(),
3647
+ selection.start,
3648
+ { x: event.clientX, y: event.clientY }
3649
+ );
3650
+ selectionPreview.style.left = `${region.x * 100}%`;
3651
+ selectionPreview.style.top = `${region.y * 100}%`;
3652
+ selectionPreview.style.width = `${region.w * 100}%`;
3653
+ selectionPreview.style.height = `${region.h * 100}%`;
3654
+ });
3655
+ listen(layer, "pointercancel", (event) => {
3656
+ if (!selection || selection.pointerId !== event.pointerId) return;
3657
+ layer.releasePointerCapture?.(event.pointerId);
3658
+ selection = null;
3659
+ selectionPreview?.remove();
3660
+ selectionPreview = null;
3661
+ });
3662
+ listen(layer, "pointerup", (event) => {
3663
+ if (!selection || selection.pointerId !== event.pointerId) return;
3664
+ const start = selection.start;
3665
+ layer.releasePointerCapture?.(event.pointerId);
3666
+ selection = null;
3667
+ selectionPreview?.remove();
3668
+ selectionPreview = null;
3669
+ emitSelection(layer, start, { x: event.clientX, y: event.clientY });
3670
+ });
3671
+ listen(layer, "keydown", (event) => {
3672
+ if (!["Enter", " "].includes(event.key)) return;
3673
+ if (event.target !== layer) return;
3674
+ event.preventDefault();
3675
+ const bounds = layer.getBoundingClientRect();
3676
+ emitSelection(layer, { x: bounds.left + bounds.width / 2, y: bounds.top + bounds.height / 2 });
3677
+ });
3678
+ }
3679
+ for (const [artifactId, frame] of frames) {
3680
+ listen(frame, ARTIFACT_STAGE_EVENTS.layout, (event) => {
3681
+ if (state.presentation !== "document") return;
3682
+ const width = event.detail?.width;
3683
+ const height = event.detail?.height;
3684
+ if (!Number.isInteger(width) || !Number.isInteger(height) || width < 1 || width > ARTIFACT_STAGE_LIMITS.maxDocumentWidth || height < 1 || height > ARTIFACT_STAGE_LIMITS.maxDocumentHeight) return;
3685
+ const layout = Object.freeze({ width, height });
3686
+ documentLayouts.set(artifactId, layout);
3687
+ const panel = panels.get(artifactId);
3688
+ if (!panel) return;
3689
+ panel.dataset.planrLayoutMeasured = "true";
3690
+ panel.style.setProperty("--planr-document-width", `${width}px`);
3691
+ panel.style.setProperty("--planr-document-height", `${height}px`);
3692
+ });
3693
+ }
3694
+ listen(root, "click", onClick);
3695
+ listen(document2, "keydown", onKeyDown);
3696
+ listen(document2, "click", (event) => {
3697
+ const more = document2.querySelector(".planr-more-menu:not([hidden])");
3698
+ if (!more || event.target.closest?.(".planr-more")) return;
3699
+ more.hidden = true;
3700
+ document2.querySelector('[data-planr-action="more"]')?.setAttribute("aria-expanded", "false");
3701
+ });
3702
+ const roomStateObserver = typeof window.MutationObserver === "function" ? new window.MutationObserver(() => {
3703
+ if (root.hasAttribute("data-planr-room-comments-paused") && state.reviewMode === "comment") {
3704
+ dispatch({ type: "set-review-mode", reviewMode: "interact" });
3705
+ } else {
3706
+ render();
3707
+ }
3708
+ }) : null;
3709
+ roomStateObserver?.observe(root, {
3710
+ attributes: true,
3711
+ attributeFilter: ["data-planr-room-comments-paused"]
3712
+ });
3713
+ if (roomStateObserver) cleanup.push(() => roomStateObserver.disconnect());
3714
+ render();
3715
+ let readyPromise = Promise.resolve(state);
3716
+ let feedbackController = null;
3717
+ let annotationController = null;
3718
+ let shareController = null;
3719
+ let hostedController = null;
3720
+ const controller = Object.freeze({
3721
+ frameBudget,
3722
+ ensureFrames,
3723
+ getLoadedArtifactIds: () => [...frameLoads].filter(([, record2]) => record2.status === "ready").map(([id]) => id),
3724
+ getState: () => state,
3725
+ getFrame: (artifactId) => frames.get(artifactId) ?? null,
3726
+ getPanel: (artifactId) => panels.get(artifactId) ?? null,
3727
+ get review() {
3728
+ return feedbackController;
3729
+ },
3730
+ get annotations() {
3731
+ return annotationController;
3732
+ },
3733
+ get share() {
3734
+ return shareController;
3735
+ },
3736
+ get hosted() {
3737
+ return hostedController;
3738
+ },
3739
+ get ready() {
3740
+ return readyPromise;
3741
+ },
3742
+ dispatch,
3743
+ destroy() {
3744
+ if (["creating", "ambiguous"].includes(shareController?.getState?.().phase)) {
3745
+ shareController.destroy?.();
3746
+ return false;
3747
+ }
3748
+ disposed = true;
3749
+ for (const id of [...frameLoads.keys()]) releaseFrame(id);
3750
+ for (const remove of cleanup.splice(0)) remove();
3751
+ return true;
3752
+ }
3753
+ });
3754
+ window.__openPlanrArtifactStage = controller;
3755
+ feedbackController = mountArtifactFeedbackRail({
3756
+ document: document2,
3757
+ window,
3758
+ root,
3759
+ stageController: controller,
3760
+ reviewOf: reviewConfig?.reviewOf,
3761
+ initialReview: reviewConfig?.review ?? null,
3762
+ artifacts: state.artifacts,
3763
+ ...reviewOptions
3764
+ });
3765
+ annotationController = mountArtifactAnnotations({
3766
+ document: document2,
3767
+ window,
3768
+ root,
3769
+ stageController: controller,
3770
+ reviewController: feedbackController
3771
+ });
3772
+ shareController = mountArtifactShareDialog({
3773
+ document: document2,
3774
+ window,
3775
+ root,
3776
+ stageController: controller,
3777
+ ...shareOptions
3778
+ });
3779
+ hostedController = mountHostedArtifactViewer({
3780
+ document: document2,
3781
+ window,
3782
+ ...hostedOptions
3783
+ });
3784
+ if (feedbackController?.destroy) cleanup.push(() => feedbackController.destroy());
3785
+ if (annotationController?.destroy) cleanup.push(() => annotationController.destroy());
3786
+ if (shareController?.destroy) cleanup.push(() => shareController.destroy());
3787
+ if (hostedController?.destroy) cleanup.push(() => hostedController.destroy());
3788
+ function cancelledFrame() {
3789
+ const error = new Error("Artifact frame loading was cancelled.");
3790
+ error.name = "AbortError";
3791
+ return error;
3792
+ }
3793
+ function frameStatus(artifactId, status) {
3794
+ const frame = frames.get(artifactId);
3795
+ if (frame) frame.dataset.planrFrameState = status;
3796
+ if (!disposed) emit(root, window, "planr:artifact-frame-state", { artifactId, status });
3797
+ }
3798
+ function releaseFrame(artifactId, { status = "unloaded", error = cancelledFrame() } = {}) {
3799
+ const record2 = frameLoads.get(artifactId);
3800
+ if (!record2) return;
3801
+ frameLoads.delete(artifactId);
3802
+ record2.cancelled = true;
3803
+ record2.abort.abort();
3804
+ record2.unlisten?.();
3805
+ record2.detach?.();
3806
+ record2.reject(error);
3807
+ const frame = frames.get(artifactId);
3808
+ frame.removeAttribute("srcdoc");
3809
+ frame.removeAttribute("src");
3810
+ delete frame.dataset.planrArtifactDigest;
3811
+ delete frame.dataset.planrBridgeTrusted;
3812
+ try {
3813
+ delete frame.__openPlanrBridge;
3814
+ } catch {
3815
+ }
3816
+ if (record2.sourceUrl) window.URL.revokeObjectURL(record2.sourceUrl);
3817
+ documentLayouts.delete(artifactId);
3818
+ const panel = panels.get(artifactId);
3819
+ if (panel) {
3820
+ delete panel.dataset.planrLayoutMeasured;
3821
+ panel.style.removeProperty("--planr-document-width");
3822
+ panel.style.removeProperty("--planr-document-height");
3823
+ }
3824
+ frameStatus(artifactId, status);
3825
+ }
3826
+ function assignArtifactSource(artifact) {
3827
+ if (disposed) return Promise.reject(cancelledFrame());
3828
+ const existing = frameLoads.get(artifact.id);
3829
+ if (existing) {
3830
+ if (existing.status === "ready" && existing.requireTrust && frames.get(artifact.id)?.dataset.planrBridgeTrusted !== "true") {
3831
+ releaseFrame(artifact.id);
3832
+ } else {
3833
+ existing.used = ++frameUse;
3834
+ return existing.promise;
3835
+ }
3836
+ }
3837
+ const frame = frames.get(artifact.id);
3838
+ if (!frame) return Promise.reject(new Error(`Missing artifact frame: ${artifact.id}`));
3839
+ const record2 = {
3840
+ status: "loading",
3841
+ used: ++frameUse,
3842
+ cancelled: false,
3843
+ abort: typeof window.AbortController === "function" ? new window.AbortController() : { signal: void 0, abort() {
3844
+ } }
3845
+ };
3846
+ record2.promise = new Promise((resolve, reject) => {
3847
+ record2.resolve = resolve;
3848
+ record2.reject = reject;
3849
+ });
3850
+ frameLoads.set(artifact.id, record2);
3851
+ const current = () => !disposed && !record2.cancelled && frameLoads.get(artifact.id) === record2;
3852
+ const fail = (error) => {
3853
+ if (current()) releaseFrame(artifact.id, { status: "error", error });
3854
+ };
3855
+ const timer = frameBudget === null ? null : window.setTimeout(() => fail(new Error(`Artifact frame did not finish loading: ${artifact.id}`)), 15e3);
3856
+ let loaded = false;
3857
+ const ready = () => {
3858
+ if (!current() || !loaded || record2.requireTrust && frame.dataset.planrBridgeTrusted !== "true") return;
3859
+ record2.status = "ready";
3860
+ record2.unlisten();
3861
+ frameStatus(artifact.id, "ready");
3862
+ record2.resolve(artifact.id);
3863
+ };
3864
+ const onLoad = () => {
3865
+ loaded = true;
3866
+ ready();
3867
+ };
3868
+ const onError = () => fail(new Error(`Artifact frame failed: ${artifact.id}`));
3869
+ record2.unlisten = () => {
3870
+ window.clearTimeout(timer);
3871
+ frame.removeEventListener("load", onLoad);
3872
+ frame.removeEventListener("error", onError);
3873
+ frame.removeEventListener("planr:artifact-bridge-ready", ready);
3874
+ };
3875
+ frameStatus(artifact.id, "loading");
3876
+ if (!current()) return record2.promise;
3877
+ void (async () => {
3878
+ const source = await resolveArtifactSource(artifact, {
3879
+ frame,
3880
+ getState: () => state,
3881
+ signal: record2.abort.signal
3882
+ });
3883
+ if (!current()) return;
3884
+ if (typeof window.TextDecoder !== "function") {
3885
+ const error = new Error("UTF-8 decoding support is required for artifact sources.");
3886
+ error.code = "E_ARTIFACT_BROWSER_UNSUPPORTED";
3887
+ throw error;
3888
+ }
3889
+ const html = await htmlForSource(window, source);
3890
+ if (!current()) return;
3891
+ if (!html) {
3892
+ throw new TypeError(
3893
+ `Artifact source resolver must return HTML bytes or a Blob for ${artifact.id}.`
3894
+ );
3895
+ }
3896
+ if (typeof bridgeClient?.attach === "function") {
3897
+ const detach = bridgeClient.attach({
3898
+ artifact,
3899
+ frame,
3900
+ getState: () => state
3901
+ });
3902
+ if (typeof detach === "function") record2.detach = detach;
3903
+ record2.requireTrust = frameBudget !== null;
3904
+ }
3905
+ frame.addEventListener("load", onLoad);
3906
+ frame.addEventListener("error", onError);
3907
+ frame.addEventListener("planr:artifact-bridge-ready", ready);
3908
+ frame.dataset.planrArtifactDigest = artifact.sha256;
3909
+ if (sourceTransport === "srcdoc") {
3910
+ frame.removeAttribute("src");
3911
+ frame.srcdoc = html;
3912
+ } else {
3913
+ if (typeof window.URL?.createObjectURL !== "function" || typeof window.Blob !== "function") {
3914
+ const error = new Error("Blob URL support is required for artifact sources.");
3915
+ error.code = "E_ARTIFACT_BROWSER_UNSUPPORTED";
3916
+ throw error;
3917
+ }
3918
+ const sourceUrl = window.URL.createObjectURL(new window.Blob([html], {
3919
+ type: "text/html;charset=utf-8"
3920
+ }));
3921
+ record2.sourceUrl = sourceUrl;
3922
+ frame.removeAttribute("srcdoc");
3923
+ frame.src = sourceUrl;
3924
+ }
3925
+ })().catch(fail);
3926
+ return record2.promise;
3927
+ }
3928
+ function ensureFrames(artifactIds) {
3929
+ if (disposed) return Promise.reject(cancelledFrame());
3930
+ if (!Array.isArray(artifactIds) || artifactIds.some((id) => typeof id !== "string" || !frames.has(id))) {
3931
+ return Promise.reject(new TypeError("Requested artifact frames must be known artifact IDs."));
3932
+ }
3933
+ const requested = [...new Set(artifactIds)];
3934
+ if (frameBudget !== null && requested.length > frameBudget) {
3935
+ return Promise.reject(new RangeError(`At most ${frameBudget} artifact frames may be requested together.`));
3936
+ }
3937
+ if (frameBudget === null) return Promise.all(requested.map((id) => assignArtifactSource(stageArtifactById(state, id))));
3938
+ const run = async () => {
3939
+ if (disposed) throw cancelledFrame();
3940
+ for (const id of requested) {
3941
+ if (disposed) throw cancelledFrame();
3942
+ if (!frameLoads.has(id)) {
3943
+ while (frameLoads.size >= frameBudget) {
3944
+ const candidates = [...frameLoads].filter(([loadedId]) => !requested.includes(loadedId)).sort((a, b) => a[1].used - b[1].used);
3945
+ if (!candidates.length) throw new Error("The artifact frame budget is exhausted.");
3946
+ releaseFrame(candidates[0][0]);
3947
+ }
3948
+ }
3949
+ await assignArtifactSource(stageArtifactById(state, id));
3950
+ }
3951
+ return requested;
3952
+ };
3953
+ const result = frameQueue.then(run);
3954
+ frameQueue = result.catch(() => {
3955
+ });
3956
+ return result;
3957
+ }
3958
+ if (state.status === "ready" && state.artifacts.length > 0) {
3959
+ if (typeof resolveArtifactSource !== "function") {
3960
+ state = reduceArtifactStageState(state, { type: "set-status", status: "loading" });
3961
+ render();
3962
+ readyPromise = Promise.resolve(state);
3963
+ } else {
3964
+ state = reduceArtifactStageState(state, { type: "set-status", status: "loading" });
3965
+ render();
3966
+ readyPromise = (frameBudget === null ? Promise.all(state.artifacts.map(assignArtifactSource)) : ensureFrames([state.activeArtifactId])).then(() => {
3967
+ if (disposed) return state;
3968
+ state = reduceArtifactStageState(state, { type: "set-status", status: "ready" });
3969
+ render({ announce: true });
3970
+ return state;
3971
+ }).catch((error) => {
3972
+ if (disposed) return state;
3973
+ const status = error?.code === "E_ARTIFACT_BROWSER_UNSUPPORTED" ? "unsupported-browser" : "invalid";
3974
+ state = reduceArtifactStageState(state, { type: "set-status", status });
3975
+ render({ announce: true });
3976
+ return state;
3977
+ });
3978
+ }
3979
+ }
3980
+ return controller;
3981
+ }
3982
+ function bootstrapArtifactStage(document2 = globalThis.document, options = {}) {
3983
+ return mountArtifactStage({ ...options, document: document2, window: document2?.defaultView });
3984
+ }
3985
+ if (typeof document !== "undefined") {
3986
+ const options = globalThis.__OPENPLANR_ARTIFACT_STAGE_OPTIONS__ ?? {};
3987
+ if (document.readyState === "loading") {
3988
+ document.addEventListener("DOMContentLoaded", () => bootstrapArtifactStage(document, options), { once: true });
3989
+ } else {
3990
+ queueMicrotask(() => bootstrapArtifactStage(document, options));
3991
+ }
3992
+ }
3993
+ return __toCommonJS(stage_exports);
3994
+ })();