opendevbrowser 0.0.32 → 0.0.34

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 (274) hide show
  1. package/README.md +1 -1
  2. package/dist/{accessibility-snapshot-XOP66CSK.js → accessibility-snapshot-VCBXK47S.js} +9 -9
  3. package/dist/{active-window-E3WFOQGX.js → active-window-7EUN36LZ.js} +9 -9
  4. package/dist/{annotate-MAE7ZJOZ.js → annotate-VLBK7YB6.js} +8 -8
  5. package/dist/{attr-M3PFDJ7Q.js → attr-JNANQKM6.js} +8 -8
  6. package/dist/browser/browser-manager.d.ts.map +1 -1
  7. package/dist/browser/canvas-manager.d.ts.map +1 -1
  8. package/dist/browser/manager-types.d.ts +3 -0
  9. package/dist/browser/manager-types.d.ts.map +1 -1
  10. package/dist/browser/ops-browser-manager.d.ts.map +1 -1
  11. package/dist/browser/screencast-recorder.d.ts +1 -0
  12. package/dist/browser/screencast-recorder.d.ts.map +1 -1
  13. package/dist/canvas/guidance.d.ts +7 -0
  14. package/dist/canvas/guidance.d.ts.map +1 -1
  15. package/dist/canvas/repair-examples.d.ts +45 -0
  16. package/dist/canvas/repair-examples.d.ts.map +1 -0
  17. package/dist/{canvas-3AJVL5I5.js → canvas-V5LO4JVL.js} +23 -8
  18. package/dist/canvas-V5LO4JVL.js.map +1 -0
  19. package/dist/{capture-desktop-VJGEETMJ.js → capture-desktop-FKVDWTVG.js} +9 -9
  20. package/dist/{capture-window-W5UFSFQL.js → capture-window-QVPM2DN2.js} +9 -9
  21. package/dist/{check-4IR3UJVW.js → check-V3CWZ56S.js} +8 -8
  22. package/dist/{checked-PKNY7724.js → checked-Q27Q6YZN.js} +8 -8
  23. package/dist/{chunk-WHQZBUNY.js → chunk-3WLCWHIV.js} +2 -2
  24. package/dist/{chunk-WHQZBUNY.js.map → chunk-3WLCWHIV.js.map} +1 -1
  25. package/dist/{chunk-RO3SMXF3.js → chunk-5FDXH4CS.js} +2870 -191
  26. package/dist/chunk-5FDXH4CS.js.map +1 -0
  27. package/dist/{chunk-J3KYGJRQ.js → chunk-G6NQ7WYD.js} +2 -2
  28. package/dist/{chunk-AKIAGFOE.js → chunk-GC2FWISX.js} +33 -14
  29. package/dist/chunk-GC2FWISX.js.map +1 -0
  30. package/dist/{chunk-2X4JFMKJ.js → chunk-IBIHDGTZ.js} +4 -4
  31. package/dist/chunk-IBIHDGTZ.js.map +1 -0
  32. package/dist/{chunk-XDLJE3RJ.js → chunk-NX2XYJP5.js} +2 -2
  33. package/dist/{chunk-AWQ37HSC.js → chunk-OJAUKABV.js} +2 -2
  34. package/dist/{chunk-ZOVMMQO6.js → chunk-QXJDJDSZ.js} +35 -14
  35. package/dist/chunk-QXJDJDSZ.js.map +1 -0
  36. package/dist/{chunk-SKFB5ICF.js → chunk-TI5I6UWY.js} +8 -3
  37. package/dist/chunk-TI5I6UWY.js.map +1 -0
  38. package/dist/{chunk-W6YPVNDX.js → chunk-VTGG5ZU2.js} +2 -2
  39. package/dist/{chunk-P5K3ZIPI.js → chunk-VX47SJZM.js} +2 -2
  40. package/dist/{chunk-BUXFIY2P.js → chunk-VY47VKXU.js} +3 -3
  41. package/dist/{chunk-NURQB55J.js → chunk-WY72GYAH.js} +2 -2
  42. package/dist/{chunk-HBK56JST.js → chunk-XRDCSHKZ.js} +202 -126
  43. package/dist/chunk-XRDCSHKZ.js.map +1 -0
  44. package/dist/{chunk-PIFHXKV4.js → chunk-Z3HIX2SE.js} +3 -3
  45. package/dist/{chunk-37VSRUW4.js → chunk-ZGCTC5YM.js} +39 -7
  46. package/dist/chunk-ZGCTC5YM.js.map +1 -0
  47. package/dist/cli/commands/canvas.d.ts +12 -0
  48. package/dist/cli/commands/canvas.d.ts.map +1 -1
  49. package/dist/cli/commands/inspiredesign.d.ts.map +1 -1
  50. package/dist/cli/daemon-commands.d.ts.map +1 -1
  51. package/dist/cli/daemon-mismatch.d.ts +6 -0
  52. package/dist/cli/daemon-mismatch.d.ts.map +1 -1
  53. package/dist/cli/help.d.ts.map +1 -1
  54. package/dist/cli/index.js +77 -77
  55. package/dist/cli/index.js.map +1 -1
  56. package/dist/cli/utils/parse.d.ts +1 -0
  57. package/dist/cli/utils/parse.d.ts.map +1 -1
  58. package/dist/cli/utils/workflow-message.d.ts +1 -1
  59. package/dist/cli/utils/workflow-message.d.ts.map +1 -1
  60. package/dist/{click-HLNXU4I5.js → click-EQDRSLR3.js} +8 -8
  61. package/dist/{clone-component-QIKN5PIM.js → clone-component-SISUXTJS.js} +7 -7
  62. package/dist/{clone-page-5C7DTGZT.js → clone-page-MLDPCBOY.js} +7 -7
  63. package/dist/{close-WTXB3EDD.js → close-2LQMJVOA.js} +7 -7
  64. package/dist/{close-PCRZHX7F.js → close-7J7EV237.js} +7 -7
  65. package/dist/{connect-6C2IG55I.js → connect-JFRSIW5M.js} +8 -8
  66. package/dist/{console-poll-VJXCZR3F.js → console-poll-NSVVUNEC.js} +8 -8
  67. package/dist/{cookie-import-5OEDFB6U.js → cookie-import-B7IQTGTN.js} +7 -7
  68. package/dist/{cookie-list-44UNJJ6D.js → cookie-list-YHG7JCZZ.js} +7 -7
  69. package/dist/{daemon-CIKGBWEB.js → daemon-ENU4FOV4.js} +6 -6
  70. package/dist/daemon-fingerprint.json +1 -1
  71. package/dist/{debug-trace-snapshot-RGXAPGWB.js → debug-trace-snapshot-KLGU2AWY.js} +8 -8
  72. package/dist/{dialog-S64MJUM2.js → dialog-MUVQIERS.js} +8 -8
  73. package/dist/{disconnect-MTIELIM7.js → disconnect-KELQJ45J.js} +7 -7
  74. package/dist/{enabled-KF2L7LW4.js → enabled-SF6UU5HG.js} +8 -8
  75. package/dist/{goto-ULWINUAZ.js → goto-AZQWXYPG.js} +8 -8
  76. package/dist/guidance/context.d.ts +44 -0
  77. package/dist/guidance/context.d.ts.map +1 -0
  78. package/dist/guidance/index.d.ts +7 -0
  79. package/dist/guidance/index.d.ts.map +1 -0
  80. package/dist/guidance/readiness.d.ts +7 -0
  81. package/dist/guidance/readiness.d.ts.map +1 -0
  82. package/dist/guidance/recipes/generic.d.ts +3 -0
  83. package/dist/guidance/recipes/generic.d.ts.map +1 -0
  84. package/dist/guidance/recipes/pinterest.d.ts +5 -0
  85. package/dist/guidance/recipes/pinterest.d.ts.map +1 -0
  86. package/dist/guidance/recipes/site-recipe-types.d.ts +2 -0
  87. package/dist/guidance/recipes/site-recipe-types.d.ts.map +1 -0
  88. package/dist/guidance/recipes/site-recipe-validation.d.ts +27 -0
  89. package/dist/guidance/recipes/site-recipe-validation.d.ts.map +1 -0
  90. package/dist/guidance/recipes/site-registry.d.ts +5 -0
  91. package/dist/guidance/recipes/site-registry.d.ts.map +1 -0
  92. package/dist/guidance/renderers.d.ts +22 -0
  93. package/dist/guidance/renderers.d.ts.map +1 -0
  94. package/dist/guidance/router.d.ts +8 -0
  95. package/dist/guidance/router.d.ts.map +1 -0
  96. package/dist/guidance/types.d.ts +140 -0
  97. package/dist/guidance/types.d.ts.map +1 -0
  98. package/dist/{help-IG5S5RJD.js → help-B44IBHXL.js} +6 -5
  99. package/dist/help-B44IBHXL.js.map +1 -0
  100. package/dist/{hover-NOCOTR6N.js → hover-MQRAKKVU.js} +8 -8
  101. package/dist/{html-LXSYP6BT.js → html-PLRTU2WS.js} +8 -8
  102. package/dist/index.js +51 -16
  103. package/dist/index.js.map +1 -1
  104. package/dist/{inspector-62EPCLYB.js → inspector-IY4GBIT6.js} +10 -10
  105. package/dist/{inspector-audit-T2IF67RJ.js → inspector-audit-7MQCRJHD.js} +12 -12
  106. package/dist/{inspector-plan-KQS6LRMW.js → inspector-plan-ZAUDHBET.js} +10 -10
  107. package/dist/inspiredesign/contract.d.ts +3 -0
  108. package/dist/inspiredesign/contract.d.ts.map +1 -1
  109. package/dist/inspiredesign/handoff.d.ts +2 -2
  110. package/dist/inspiredesign/meta-prompt.d.ts +1 -1
  111. package/dist/inspiredesign/meta-prompt.d.ts.map +1 -1
  112. package/dist/inspiredesign/reference-pattern-board.d.ts +22 -1
  113. package/dist/inspiredesign/reference-pattern-board.d.ts.map +1 -1
  114. package/dist/{inspiredesign-DB6CHYN3.js → inspiredesign-VHPEO3UK.js} +83 -30
  115. package/dist/inspiredesign-VHPEO3UK.js.map +1 -0
  116. package/dist/{launch-B5ES6FVS.js → launch-OCTWPTV5.js} +8 -8
  117. package/dist/{list-TIZVR6RO.js → list-HUSYADUS.js} +7 -7
  118. package/dist/{list-XM4BP5GM.js → list-JWKAMAUA.js} +7 -7
  119. package/dist/{macro-resolve-TTQZVFIW.js → macro-resolve-WOXMPZDQ.js} +9 -9
  120. package/dist/{network-poll-NNSY4W63.js → network-poll-WHB62OEF.js} +8 -8
  121. package/dist/{new-E6VNAC2A.js → new-IKZBYBNK.js} +7 -7
  122. package/dist/{open-F55XKMKB.js → open-UA2VI6ZP.js} +7 -7
  123. package/dist/opendevbrowser.js +51 -16
  124. package/dist/opendevbrowser.js.map +1 -1
  125. package/dist/{perf-RE7JE6CP.js → perf-DICS3VKH.js} +8 -8
  126. package/dist/{pointer-down-BCBPC5FJ.js → pointer-down-2XPRZFJC.js} +9 -9
  127. package/dist/{pointer-drag-QK7KGF7W.js → pointer-drag-7NY4BOLH.js} +9 -9
  128. package/dist/{pointer-move-VFAZQAXA.js → pointer-move-FWEXMH37.js} +9 -9
  129. package/dist/{pointer-up-FA5WE6LS.js → pointer-up-VU2OHK5D.js} +9 -9
  130. package/dist/{press-TNRHNDSW.js → press-W7IZ3FCX.js} +8 -8
  131. package/dist/{product-video-UEANMZ2U.js → product-video-XCZ6CHR5.js} +10 -10
  132. package/dist/providers/browser-native-discovery.d.ts +23 -0
  133. package/dist/providers/browser-native-discovery.d.ts.map +1 -0
  134. package/dist/providers/browser-output-artifacts.d.ts +13 -0
  135. package/dist/providers/browser-output-artifacts.d.ts.map +1 -0
  136. package/dist/providers/renderer.d.ts +2 -0
  137. package/dist/providers/renderer.d.ts.map +1 -1
  138. package/dist/providers/workflow-handoff.d.ts +3 -0
  139. package/dist/providers/workflow-handoff.d.ts.map +1 -1
  140. package/dist/providers/workflows.d.ts.map +1 -1
  141. package/dist/{providers-AMCNWZUL.js → providers-XCNSU3T6.js} +4 -4
  142. package/dist/public-surface/generated-manifest.d.ts +5 -5
  143. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  144. package/dist/public-surface/source.d.ts +2 -2
  145. package/dist/public-surface/source.d.ts.map +1 -1
  146. package/dist/{research-YFY7WJSZ.js → research-AYCKHOWK.js} +10 -10
  147. package/dist/{review-NHOPLAT7.js → review-PP2UNSMJ.js} +9 -9
  148. package/dist/{review-desktop-OFWPDYGD.js → review-desktop-3JOJFUEJ.js} +9 -9
  149. package/dist/{rpc-TVVQPUOL.js → rpc-7EPTJQQ6.js} +8 -8
  150. package/dist/{run-OCBEZRDW.js → run-P6UJS3D4.js} +6 -6
  151. package/dist/{screencast-start-GTSDA33J.js → screencast-start-ZZYNH2HT.js} +8 -8
  152. package/dist/{screencast-stop-FYBUIXAA.js → screencast-stop-Y6ADFOFA.js} +8 -8
  153. package/dist/{screenshot-OEYRT3SP.js → screenshot-CJB7PMAF.js} +8 -8
  154. package/dist/{scroll-35OFEFC5.js → scroll-BP5MA4ZT.js} +8 -8
  155. package/dist/{scroll-into-view-UQ5RAWIX.js → scroll-into-view-O3RDWLM2.js} +8 -8
  156. package/dist/{select-K56QELVZ.js → select-QLCNRI36.js} +8 -8
  157. package/dist/{serve-5UJ3VMWC.js → serve-OO2MQWGL.js} +7 -7
  158. package/dist/{shopping-FJG7XB4Q.js → shopping-UYHCYPAH.js} +10 -10
  159. package/dist/{snapshot-W7RKVZEI.js → snapshot-SXYZ3CMC.js} +8 -8
  160. package/dist/{status-KHYCLGUD.js → status-AL2AHVA5.js} +7 -7
  161. package/dist/{status-R4EV4TWO.js → status-QQW7REK4.js} +9 -9
  162. package/dist/{status-capabilities-XD3RGLKF.js → status-capabilities-AVHJYQQQ.js} +9 -9
  163. package/dist/{text-TANLFZ4O.js → text-B6Z47EOA.js} +8 -8
  164. package/dist/tools/inspiredesign_run.d.ts.map +1 -1
  165. package/dist/tools/product_video_run.d.ts.map +1 -1
  166. package/dist/{type-Y2Y7LX7Y.js → type-LR3F3SQY.js} +8 -8
  167. package/dist/{uncheck-6REVUUB2.js → uncheck-5PJEHR7J.js} +8 -8
  168. package/dist/{upload-GGZC5UQP.js → upload-HQ3QN2OW.js} +8 -8
  169. package/dist/{use-B4Q7CFG2.js → use-KFZLMRUH.js} +7 -7
  170. package/dist/{value-DHOHO55D.js → value-TKUFUK5I.js} +8 -8
  171. package/dist/{visible-S5BTWYNH.js → visible-P5Z2N2QR.js} +8 -8
  172. package/dist/{wait-WV6NZUKL.js → wait-BYSHJPSC.js} +8 -8
  173. package/dist/{windows-GKE36DJQ.js → windows-6GTD25EU.js} +9 -9
  174. package/extension/manifest.json +1 -1
  175. package/package.json +1 -1
  176. package/skills/opendevbrowser-best-practices/SKILL.md +8 -2
  177. package/skills/opendevbrowser-best-practices/artifacts/canvas-governance-playbook.md +4 -4
  178. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +7 -0
  179. package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +6 -0
  180. package/skills/opendevbrowser-design-agent/SKILL.md +8 -6
  181. package/skills/opendevbrowser-design-agent/artifacts/design-workflows.md +4 -3
  182. package/skills/opendevbrowser-design-agent/artifacts/research-harvest-workflow.md +28 -4
  183. package/skills/opendevbrowser-design-agent/assets/templates/reference-pattern-board.v1.json +1 -0
  184. package/skills/opendevbrowser-design-agent/scripts/design-workflow.sh +5 -2
  185. package/skills/opendevbrowser-design-agent/scripts/validate-skill-assets.sh +8 -2
  186. package/skills/opendevbrowser-motion-design/SKILL.md +1 -1
  187. package/skills/opendevbrowser-motion-design/scripts/validate-skill-assets.sh +1 -0
  188. package/dist/canvas-3AJVL5I5.js.map +0 -1
  189. package/dist/chunk-2X4JFMKJ.js.map +0 -1
  190. package/dist/chunk-37VSRUW4.js.map +0 -1
  191. package/dist/chunk-AKIAGFOE.js.map +0 -1
  192. package/dist/chunk-HBK56JST.js.map +0 -1
  193. package/dist/chunk-RO3SMXF3.js.map +0 -1
  194. package/dist/chunk-SKFB5ICF.js.map +0 -1
  195. package/dist/chunk-ZOVMMQO6.js.map +0 -1
  196. package/dist/help-IG5S5RJD.js.map +0 -1
  197. package/dist/inspiredesign-DB6CHYN3.js.map +0 -1
  198. /package/dist/{accessibility-snapshot-XOP66CSK.js.map → accessibility-snapshot-VCBXK47S.js.map} +0 -0
  199. /package/dist/{active-window-E3WFOQGX.js.map → active-window-7EUN36LZ.js.map} +0 -0
  200. /package/dist/{annotate-MAE7ZJOZ.js.map → annotate-VLBK7YB6.js.map} +0 -0
  201. /package/dist/{attr-M3PFDJ7Q.js.map → attr-JNANQKM6.js.map} +0 -0
  202. /package/dist/{capture-desktop-VJGEETMJ.js.map → capture-desktop-FKVDWTVG.js.map} +0 -0
  203. /package/dist/{capture-window-W5UFSFQL.js.map → capture-window-QVPM2DN2.js.map} +0 -0
  204. /package/dist/{check-4IR3UJVW.js.map → check-V3CWZ56S.js.map} +0 -0
  205. /package/dist/{checked-PKNY7724.js.map → checked-Q27Q6YZN.js.map} +0 -0
  206. /package/dist/{chunk-J3KYGJRQ.js.map → chunk-G6NQ7WYD.js.map} +0 -0
  207. /package/dist/{chunk-XDLJE3RJ.js.map → chunk-NX2XYJP5.js.map} +0 -0
  208. /package/dist/{chunk-AWQ37HSC.js.map → chunk-OJAUKABV.js.map} +0 -0
  209. /package/dist/{chunk-W6YPVNDX.js.map → chunk-VTGG5ZU2.js.map} +0 -0
  210. /package/dist/{chunk-P5K3ZIPI.js.map → chunk-VX47SJZM.js.map} +0 -0
  211. /package/dist/{chunk-BUXFIY2P.js.map → chunk-VY47VKXU.js.map} +0 -0
  212. /package/dist/{chunk-NURQB55J.js.map → chunk-WY72GYAH.js.map} +0 -0
  213. /package/dist/{chunk-PIFHXKV4.js.map → chunk-Z3HIX2SE.js.map} +0 -0
  214. /package/dist/{click-HLNXU4I5.js.map → click-EQDRSLR3.js.map} +0 -0
  215. /package/dist/{clone-component-QIKN5PIM.js.map → clone-component-SISUXTJS.js.map} +0 -0
  216. /package/dist/{clone-page-5C7DTGZT.js.map → clone-page-MLDPCBOY.js.map} +0 -0
  217. /package/dist/{close-WTXB3EDD.js.map → close-2LQMJVOA.js.map} +0 -0
  218. /package/dist/{close-PCRZHX7F.js.map → close-7J7EV237.js.map} +0 -0
  219. /package/dist/{connect-6C2IG55I.js.map → connect-JFRSIW5M.js.map} +0 -0
  220. /package/dist/{console-poll-VJXCZR3F.js.map → console-poll-NSVVUNEC.js.map} +0 -0
  221. /package/dist/{cookie-import-5OEDFB6U.js.map → cookie-import-B7IQTGTN.js.map} +0 -0
  222. /package/dist/{cookie-list-44UNJJ6D.js.map → cookie-list-YHG7JCZZ.js.map} +0 -0
  223. /package/dist/{daemon-CIKGBWEB.js.map → daemon-ENU4FOV4.js.map} +0 -0
  224. /package/dist/{debug-trace-snapshot-RGXAPGWB.js.map → debug-trace-snapshot-KLGU2AWY.js.map} +0 -0
  225. /package/dist/{dialog-S64MJUM2.js.map → dialog-MUVQIERS.js.map} +0 -0
  226. /package/dist/{disconnect-MTIELIM7.js.map → disconnect-KELQJ45J.js.map} +0 -0
  227. /package/dist/{enabled-KF2L7LW4.js.map → enabled-SF6UU5HG.js.map} +0 -0
  228. /package/dist/{goto-ULWINUAZ.js.map → goto-AZQWXYPG.js.map} +0 -0
  229. /package/dist/{hover-NOCOTR6N.js.map → hover-MQRAKKVU.js.map} +0 -0
  230. /package/dist/{html-LXSYP6BT.js.map → html-PLRTU2WS.js.map} +0 -0
  231. /package/dist/{inspector-62EPCLYB.js.map → inspector-IY4GBIT6.js.map} +0 -0
  232. /package/dist/{inspector-audit-T2IF67RJ.js.map → inspector-audit-7MQCRJHD.js.map} +0 -0
  233. /package/dist/{inspector-plan-KQS6LRMW.js.map → inspector-plan-ZAUDHBET.js.map} +0 -0
  234. /package/dist/{launch-B5ES6FVS.js.map → launch-OCTWPTV5.js.map} +0 -0
  235. /package/dist/{list-TIZVR6RO.js.map → list-HUSYADUS.js.map} +0 -0
  236. /package/dist/{list-XM4BP5GM.js.map → list-JWKAMAUA.js.map} +0 -0
  237. /package/dist/{macro-resolve-TTQZVFIW.js.map → macro-resolve-WOXMPZDQ.js.map} +0 -0
  238. /package/dist/{network-poll-NNSY4W63.js.map → network-poll-WHB62OEF.js.map} +0 -0
  239. /package/dist/{new-E6VNAC2A.js.map → new-IKZBYBNK.js.map} +0 -0
  240. /package/dist/{open-F55XKMKB.js.map → open-UA2VI6ZP.js.map} +0 -0
  241. /package/dist/{perf-RE7JE6CP.js.map → perf-DICS3VKH.js.map} +0 -0
  242. /package/dist/{pointer-down-BCBPC5FJ.js.map → pointer-down-2XPRZFJC.js.map} +0 -0
  243. /package/dist/{pointer-drag-QK7KGF7W.js.map → pointer-drag-7NY4BOLH.js.map} +0 -0
  244. /package/dist/{pointer-move-VFAZQAXA.js.map → pointer-move-FWEXMH37.js.map} +0 -0
  245. /package/dist/{pointer-up-FA5WE6LS.js.map → pointer-up-VU2OHK5D.js.map} +0 -0
  246. /package/dist/{press-TNRHNDSW.js.map → press-W7IZ3FCX.js.map} +0 -0
  247. /package/dist/{product-video-UEANMZ2U.js.map → product-video-XCZ6CHR5.js.map} +0 -0
  248. /package/dist/{providers-AMCNWZUL.js.map → providers-XCNSU3T6.js.map} +0 -0
  249. /package/dist/{research-YFY7WJSZ.js.map → research-AYCKHOWK.js.map} +0 -0
  250. /package/dist/{review-NHOPLAT7.js.map → review-PP2UNSMJ.js.map} +0 -0
  251. /package/dist/{review-desktop-OFWPDYGD.js.map → review-desktop-3JOJFUEJ.js.map} +0 -0
  252. /package/dist/{rpc-TVVQPUOL.js.map → rpc-7EPTJQQ6.js.map} +0 -0
  253. /package/dist/{run-OCBEZRDW.js.map → run-P6UJS3D4.js.map} +0 -0
  254. /package/dist/{screencast-start-GTSDA33J.js.map → screencast-start-ZZYNH2HT.js.map} +0 -0
  255. /package/dist/{screencast-stop-FYBUIXAA.js.map → screencast-stop-Y6ADFOFA.js.map} +0 -0
  256. /package/dist/{screenshot-OEYRT3SP.js.map → screenshot-CJB7PMAF.js.map} +0 -0
  257. /package/dist/{scroll-35OFEFC5.js.map → scroll-BP5MA4ZT.js.map} +0 -0
  258. /package/dist/{scroll-into-view-UQ5RAWIX.js.map → scroll-into-view-O3RDWLM2.js.map} +0 -0
  259. /package/dist/{select-K56QELVZ.js.map → select-QLCNRI36.js.map} +0 -0
  260. /package/dist/{serve-5UJ3VMWC.js.map → serve-OO2MQWGL.js.map} +0 -0
  261. /package/dist/{shopping-FJG7XB4Q.js.map → shopping-UYHCYPAH.js.map} +0 -0
  262. /package/dist/{snapshot-W7RKVZEI.js.map → snapshot-SXYZ3CMC.js.map} +0 -0
  263. /package/dist/{status-KHYCLGUD.js.map → status-AL2AHVA5.js.map} +0 -0
  264. /package/dist/{status-R4EV4TWO.js.map → status-QQW7REK4.js.map} +0 -0
  265. /package/dist/{status-capabilities-XD3RGLKF.js.map → status-capabilities-AVHJYQQQ.js.map} +0 -0
  266. /package/dist/{text-TANLFZ4O.js.map → text-B6Z47EOA.js.map} +0 -0
  267. /package/dist/{type-Y2Y7LX7Y.js.map → type-LR3F3SQY.js.map} +0 -0
  268. /package/dist/{uncheck-6REVUUB2.js.map → uncheck-5PJEHR7J.js.map} +0 -0
  269. /package/dist/{upload-GGZC5UQP.js.map → upload-HQ3QN2OW.js.map} +0 -0
  270. /package/dist/{use-B4Q7CFG2.js.map → use-KFZLMRUH.js.map} +0 -0
  271. /package/dist/{value-DHOHO55D.js.map → value-TKUFUK5I.js.map} +0 -0
  272. /package/dist/{visible-S5BTWYNH.js.map → visible-P5Z2N2QR.js.map} +0 -0
  273. /package/dist/{wait-WV6NZUKL.js.map → wait-BYSHJPSC.js.map} +0 -0
  274. /package/dist/{windows-GKE36DJQ.js.map → windows-6GTD25EU.js.map} +0 -0
@@ -10,7 +10,7 @@ import {
10
10
  INSPIREDESIGN_HANDOFF_RECOMMENDED_SKILLS,
11
11
  buildInspiredesignFollowthroughSummary,
12
12
  buildInspiredesignNextStep
13
- } from "./chunk-2X4JFMKJ.js";
13
+ } from "./chunk-IBIHDGTZ.js";
14
14
  import {
15
15
  applyPromptGuard,
16
16
  applyProviderIssueHint,
@@ -22,7 +22,7 @@ import {
22
22
  readProviderIssueHintFromRecord,
23
23
  redactSensitive,
24
24
  summarizePrimaryProviderIssue
25
- } from "./chunk-WHQZBUNY.js";
25
+ } from "./chunk-3WLCWHIV.js";
26
26
  import {
27
27
  ProviderRuntimeError,
28
28
  createProviderError,
@@ -11192,6 +11192,162 @@ var expandInspiredesignBrief = (brief, preferredFormatId) => {
11192
11192
  };
11193
11193
  };
11194
11194
 
11195
+ // src/guidance/recipes/pinterest.ts
11196
+ var pinterestGuidance = {
11197
+ id: "inspiredesign.harvest.browser_native_site_search.pinterest",
11198
+ recipeType: "site_navigation",
11199
+ workflow: "inspiredesign",
11200
+ severity: "warning",
11201
+ readiness: "needs_recovery",
11202
+ reasonCode: "pinterest_browser_native_recovery",
11203
+ primaryAction: {
11204
+ id: "pinterest_browser_native_discovery",
11205
+ label: "Use Pinterest browser-native discovery",
11206
+ summary: "Use a user-authorized signed-in Pinterest browser session when required, search Pinterest naturally, collect visual pins or boards, and reject full login walls, challenges, empty grids, and search-shell pages."
11207
+ },
11208
+ commands: [{
11209
+ id: "pinterest-authenticated-harvest",
11210
+ label: "Run an authenticated Pinterest harvest",
11211
+ command: 'npx opendevbrowser inspiredesign harvest --brief "Digital photography studio landing page" --query "cinematic photography studio landing page inspiration" --provider social/pinterest --max-references 5 --visual-evidence required --browser-mode extension --use-cookies --cookie-policy required --challenge-automation-mode browser_with_helper --mode json --output-format json'
11212
+ }],
11213
+ paramsExamples: [{
11214
+ id: "pinterest-harvest-input",
11215
+ label: "Pinterest discovery input",
11216
+ params: {
11217
+ provider: "social/pinterest",
11218
+ browserMode: "extension",
11219
+ useCookies: true,
11220
+ cookiePolicy: "required",
11221
+ visualEvidence: "required"
11222
+ }
11223
+ }],
11224
+ fieldExamples: [],
11225
+ artifactInputs: [
11226
+ { path: "ranked-references.json", purpose: "Confirm accepted URLs are pins, boards, or idea pages with actual visual grids.", required: true },
11227
+ { path: "visual-evidence.json", purpose: "Reject login, challenge, empty-grid, and search-shell screenshots.", required: true }
11228
+ ],
11229
+ validationChecks: [
11230
+ { id: "pinterest-hosts", description: "Accepted URLs stay on Pinterest hosts.", assertion: 'acceptedUrls.every(url => { const host = new URL(url).hostname; return host === "pinterest.com" || host.endsWith(".pinterest.com"); })' },
11231
+ { id: "pinterest-visual-grid", description: "Screenshots show usable visual grids, pins, boards, or idea pages, not blocked UI." }
11232
+ ],
11233
+ fallbackPolicy: {
11234
+ allowed: false,
11235
+ requiresUserConfirmation: true,
11236
+ reason: "Do not switch a Pinterest-scoped request to unrelated web providers without user confirmation."
11237
+ },
11238
+ doNotProceedIf: [
11239
+ "Pinterest is logged out when cookies are required or protected by a challenge",
11240
+ "The signed-in Pinterest session was not explicitly authorized by the user",
11241
+ "Captured page is only a search shell, login wall, or empty grid",
11242
+ "No ranked Pinterest references remain after scoring"
11243
+ ]
11244
+ };
11245
+ var PINTEREST_PIN_ID_PATTERN = /^\d+$/;
11246
+ var RESERVED_PINTEREST_BOARD_PATHS = /* @__PURE__ */ new Set([
11247
+ "about",
11248
+ "ads",
11249
+ "board",
11250
+ "business",
11251
+ "careers",
11252
+ "contact",
11253
+ "create",
11254
+ "developers",
11255
+ "explore",
11256
+ "help",
11257
+ "ideas",
11258
+ "login",
11259
+ "messages",
11260
+ "notifications",
11261
+ "pin",
11262
+ "search",
11263
+ "settings",
11264
+ "shopping",
11265
+ "terms",
11266
+ "today"
11267
+ ]);
11268
+ var RESERVED_PINTEREST_IDEA_PATHS = /* @__PURE__ */ new Set(["create", "edit", "search"]);
11269
+ var RESERVED_PINTEREST_PROFILE_TABS = /* @__PURE__ */ new Set([
11270
+ "activity",
11271
+ "boards",
11272
+ "comments",
11273
+ "created",
11274
+ "followers",
11275
+ "following",
11276
+ "likes",
11277
+ "pins",
11278
+ "saved",
11279
+ "tried"
11280
+ ]);
11281
+ var isAllowedPinterestReferenceHost = (hostname) => hostname === "pinterest.com" || hostname === "www.pinterest.com" || /^[a-z]{2}\.pinterest\.com$/.test(hostname);
11282
+ var normalizePinterestReferenceUrl = (value) => {
11283
+ const trimmed = value.trim();
11284
+ const absolute = trimmed.startsWith("/") ? `https://www.pinterest.com${trimmed}` : trimmed;
11285
+ try {
11286
+ const url = new URL(absolute);
11287
+ if (url.protocol !== "https:" && url.protocol !== "http:") return null;
11288
+ url.protocol = "https:";
11289
+ const hostname = url.hostname.toLowerCase();
11290
+ if (!isAllowedPinterestReferenceHost(hostname)) return null;
11291
+ const pathSegments = url.pathname.split("/").filter(Boolean);
11292
+ const isPin = pathSegments[0] === "pin" && pathSegments.length === 2 && PINTEREST_PIN_ID_PATTERN.test(pathSegments[1] ?? "");
11293
+ const isIdea = pathSegments[0] === "ideas" && pathSegments.length >= 3 && !RESERVED_PINTEREST_IDEA_PATHS.has(pathSegments[1] ?? "") && PINTEREST_PIN_ID_PATTERN.test(pathSegments[pathSegments.length - 1] ?? "");
11294
+ const isBoard = pathSegments.length === 2 && !RESERVED_PINTEREST_BOARD_PATHS.has(pathSegments[0] ?? "") && !RESERVED_PINTEREST_PROFILE_TABS.has(pathSegments[1] ?? "") && pathSegments.every((segment) => !segment.startsWith("_"));
11295
+ if (!isPin && !isIdea && !isBoard) return null;
11296
+ url.hash = "";
11297
+ url.search = "";
11298
+ return url.toString();
11299
+ } catch {
11300
+ return null;
11301
+ }
11302
+ };
11303
+ var extractPinterestUrlsFromText = (value) => {
11304
+ const candidates = value.match(/(?:https?:\/\/(?:(?:www|[a-z]{2})\.)?pinterest\.com\/(?:pin\/[a-zA-Z0-9_-]+|ideas\/[a-zA-Z0-9/_-]+|[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+)|(?<![A-Za-z0-9.])\/(?:pin\/[a-zA-Z0-9_-]+|ideas\/[a-zA-Z0-9/_-]+|[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+))\/?/g) ?? [];
11305
+ return candidates.map(normalizePinterestReferenceUrl).filter((url) => url !== null);
11306
+ };
11307
+ var buildPinterestSearchUrl = (query) => {
11308
+ const params = new URLSearchParams({ q: query });
11309
+ return `https://www.pinterest.com/search/pins/?${params.toString()}`;
11310
+ };
11311
+ var extractPinterestReferenceUrls = (candidate) => {
11312
+ return [
11313
+ normalizePinterestReferenceUrl(candidate.url ?? ""),
11314
+ ...(candidate.links ?? []).map(normalizePinterestReferenceUrl),
11315
+ ...extractPinterestUrlsFromText(candidate.content ?? ""),
11316
+ ...extractPinterestUrlsFromText(candidate.html ?? "")
11317
+ ].filter((url) => url !== null);
11318
+ };
11319
+ var pinterestSiteRecipe = {
11320
+ id: "social/pinterest",
11321
+ providerIds: ["social/pinterest", "pinterest"],
11322
+ hostnames: ["pinterest.com", "www.pinterest.com", "uk.pinterest.com"],
11323
+ authMode: "authenticated_preferred",
11324
+ navigationSteps: [
11325
+ { id: "open", instruction: "Open Pinterest in the requested browser mode." },
11326
+ { id: "verify-session", instruction: "Verify the page is logged in before searching when cookies are required." },
11327
+ { id: "search", instruction: "Use the Pinterest search box with the brief-specific visual query." },
11328
+ { id: "scroll", instruction: "Scroll enough to collect varied pins, boards, and idea pages." },
11329
+ { id: "collect", instruction: "Collect candidate URLs only from visual result pages." }
11330
+ ],
11331
+ badStates: [
11332
+ { id: "login", markers: ["log in", "sign up", "continue with"], reasonCode: "auth_required", recoveryAction: "Use extension mode with a user-authorized logged-in Pinterest session." },
11333
+ { id: "challenge", markers: ["captcha", "verification", "challenge"], reasonCode: "challenge_detected", recoveryAction: "Resolve the browser challenge before rerunning harvest." },
11334
+ { id: "search-shell", markers: ["pin card", "your profile", "when autocomplete results are available"], reasonCode: "env_limited", recoveryAction: "Open a concrete pin, board, or idea page before capture." }
11335
+ ],
11336
+ evidenceRequirements: [
11337
+ { id: "visual-grid", description: "Candidate shows visual design material, not only Pinterest chrome.", validation: "Screenshot contains pins, boards, or idea page content." },
11338
+ { id: "on-brief", description: "Candidate matches the design brief surface and style intent.", validation: "Reference signals overlap the brief target and are not generic marketplace chrome." }
11339
+ ],
11340
+ recoverySteps: [
11341
+ { id: "authenticate", instruction: "Use extension mode and cookies only from a user-authorized signed-in Pinterest tab." },
11342
+ { id: "explicit-url", instruction: "If search is blocked, provide explicit Pinterest pin, board, or idea page URLs." }
11343
+ ],
11344
+ browserNativeDiscovery: {
11345
+ buildSearchUrl: buildPinterestSearchUrl,
11346
+ extractReferenceUrls: extractPinterestReferenceUrls
11347
+ },
11348
+ guidance: pinterestGuidance
11349
+ };
11350
+
11195
11351
  // src/inspiredesign/reference-pattern-board.ts
11196
11352
  var SIGNAL_LIMIT = 5;
11197
11353
  var SIGNAL_CLIP = 180;
@@ -11204,7 +11360,11 @@ var SCORE_CLONE = 8;
11204
11360
  var SCORE_DOM = 8;
11205
11361
  var SCORE_PUBLIC_LANDING = 6;
11206
11362
  var SCORE_SIGNAL_CAP = 12;
11363
+ var SCORE_INTENT_MISMATCH_PENALTY = 55;
11364
+ var SCORE_PINTEREST_CHROME_METADATA_PENALTY = 35;
11207
11365
  var MAX_REFERENCE_SCORE = 100;
11366
+ var MIN_READY_REFERENCE_SCORE = 50;
11367
+ var MIN_READY_REFERENCE_CONFIDENCE = 0.5;
11208
11368
  var ADVANCED_MOTION_FIELDS = [
11209
11369
  "Advisory shader-style gradients: specify effect type, uniforms, static fallback, and reduced-motion replacement as design language only.",
11210
11370
  "Advisory WebGL-style depth cues: describe layered depth, camera-like parallax, and spatial hierarchy without requiring WebGL runtime.",
@@ -11235,6 +11395,15 @@ var DIAGNOSTIC_TEXT_MARKERS = [
11235
11395
  "challenge page",
11236
11396
  "access denied",
11237
11397
  "browser capture unavailable",
11398
+ "404",
11399
+ "page not found",
11400
+ "not found",
11401
+ "unavailable page",
11402
+ "accept all cookies",
11403
+ "cookie consent",
11404
+ "cookie preferences",
11405
+ "privacy settings",
11406
+ "consent modal",
11238
11407
  "javascript required",
11239
11408
  "javascript is required",
11240
11409
  "captcha",
@@ -11244,6 +11413,31 @@ var DIAGNOSTIC_TEXT_MARKERS = [
11244
11413
  "complete the verification",
11245
11414
  "blocked reference"
11246
11415
  ];
11416
+ var SEARCH_OR_LISTING_SHELL_MARKERS = [
11417
+ "search results for",
11418
+ "related searches",
11419
+ "sort by",
11420
+ "filter by"
11421
+ ];
11422
+ var MARKETPLACE_CHROME_MARKERS = [
11423
+ "add to cart",
11424
+ "marketplace",
11425
+ "envato",
11426
+ "etsy",
11427
+ "template kits"
11428
+ ];
11429
+ var HARD_DIAGNOSTIC_PAGE_MARKERS = [
11430
+ "404",
11431
+ "page not found",
11432
+ "this page is unavailable",
11433
+ "accept all cookies",
11434
+ "manage cookies",
11435
+ "cookie consent",
11436
+ "sign in to continue",
11437
+ "log in to continue",
11438
+ "captcha",
11439
+ "verification challenge"
11440
+ ];
11247
11441
  var INTERFACE_CHROME_TEXT_MARKERS = [
11248
11442
  "your profile",
11249
11443
  "your boards",
@@ -11300,14 +11494,53 @@ var isDiagnosticText = (value) => {
11300
11494
  const lower = value.toLowerCase();
11301
11495
  return DIAGNOSTIC_TEXT_MARKERS.some((marker) => lower.includes(marker));
11302
11496
  };
11497
+ var diagnosticPageReasons = (value) => {
11498
+ const lower = value.toLowerCase();
11499
+ const reasons = [];
11500
+ if (["404", "page not found", "this page is unavailable"].some((marker) => lower.includes(marker))) {
11501
+ reasons.push("unavailable_page");
11502
+ }
11503
+ if (["accept all cookies", "manage cookies", "cookie consent", "privacy settings", "enable cookies"].some((marker) => lower.includes(marker))) {
11504
+ reasons.push("cookie_or_consent_modal");
11505
+ }
11506
+ if ([
11507
+ "sign in to continue",
11508
+ "log in to continue",
11509
+ "authentication required",
11510
+ "access denied",
11511
+ "captcha",
11512
+ "verification challenge",
11513
+ "complete the verification"
11514
+ ].some((marker) => lower.includes(marker))) {
11515
+ reasons.push("login_or_challenge_state");
11516
+ }
11517
+ const searchShellCount = SEARCH_OR_LISTING_SHELL_MARKERS.filter((marker) => lower.includes(marker)).length;
11518
+ if (searchShellCount >= 2 || lower.includes("search results for") || lower.includes("related searches")) {
11519
+ reasons.push("search_or_listing_shell");
11520
+ }
11521
+ const marketplaceChromeCount = MARKETPLACE_CHROME_MARKERS.filter((marker) => lower.includes(marker)).length;
11522
+ if (marketplaceChromeCount >= 2 || (lower.includes("envato") || lower.includes("etsy")) && (lower.includes("template kits") || searchShellCount > 0)) {
11523
+ reasons.push("marketplace_or_template_chrome");
11524
+ }
11525
+ if (isInterfaceChromeText(value)) {
11526
+ reasons.push("interface_chrome_shell");
11527
+ }
11528
+ return [...new Set(reasons)];
11529
+ };
11530
+ var isDiagnosticPageText = (value) => {
11531
+ const lower = value.toLowerCase();
11532
+ return HARD_DIAGNOSTIC_PAGE_MARKERS.some((marker) => lower.includes(marker)) || diagnosticPageReasons(value).length > 0;
11533
+ };
11303
11534
  var isInterfaceChromeText = (value) => {
11304
11535
  const lower = value.toLowerCase();
11305
- if (lower === "your profile" || lower === "adobe, inc." || lower === "dribbble: the community for graphic design" || /^https?:\/\/\S+$/.test(lower) || lower.includes("when autocomplete results are available") && lower.includes("touch device users") || lower.includes("get 20%") && lower.includes("dribbble: the community for graphic design") || lower.includes("our free wordpress themes are downloaded") && lower.includes("get them now")) {
11536
+ const actionRefCount = countActionRefs(value);
11537
+ const markerCount = INTERFACE_CHROME_TEXT_MARKERS.filter((marker) => lower.includes(marker)).length;
11538
+ if (lower === "your profile" || lower === "adobe, inc." || lower === "dribbble: the community for graphic design" || /^https?:\/\/\S+$/.test(lower) || lower.includes("when autocomplete results are available") && lower.includes("touch device users") || actionRefCount >= 3 && markerCount >= 2 || lower.includes("get 20%") && lower.includes("dribbble: the community for graphic design") || lower.includes("our free wordpress themes are downloaded") && lower.includes("get them now")) {
11306
11539
  return true;
11307
11540
  }
11308
- const markerCount = INTERFACE_CHROME_TEXT_MARKERS.filter((marker) => lower.includes(marker)).length;
11309
11541
  return markerCount >= 3 || lower.includes("pin card") && lower.includes("your profile");
11310
11542
  };
11543
+ var countActionRefs = (value) => (value.match(/\[r\d+\]\s+(?:link|button|combobox|textbox|option)\s+/gi) ?? []).length;
11311
11544
  var hasPublicLandingSignal = (value) => {
11312
11545
  const lower = value.toLowerCase();
11313
11546
  const strongCount = PUBLIC_LANDING_TEXT_MARKERS.filter((marker) => lower.includes(marker)).length;
@@ -11337,13 +11570,56 @@ var getInspiredesignReferenceSignals = (reference) => {
11337
11570
  var hasCleanSignal = (value) => {
11338
11571
  if (!value || isCodeOrCssPreview(value)) return false;
11339
11572
  const text = cleanEvidenceText(value);
11340
- return text.length > 0 && !isCodeOrCssPreview(text) && !isDiagnosticText(text) && !isInterfaceChromeText(text);
11573
+ return text.length > 0 && !isCodeOrCssPreview(text) && !isDiagnosticText(text) && !isDiagnosticPageText(text) && !isInterfaceChromeText(text);
11341
11574
  };
11342
11575
  var hasUsableCloneCreativeEvidence = (reference) => hasCleanSignal(reference.capture?.clone?.componentPreview);
11576
+ var hasUsableRecoveredCreativeEvidence = (reference) => hasUsableCloneCreativeEvidence(reference) || hasCleanSignal(textFromHtml(reference.capture?.dom?.outerHTML));
11577
+ var isPinterestVisualReferenceUrl = (value) => normalizePinterestReferenceUrl(value) !== null;
11578
+ var pinterestHostnameFromUrl = (value) => {
11579
+ try {
11580
+ return new URL(value).hostname.toLowerCase();
11581
+ } catch {
11582
+ return null;
11583
+ }
11584
+ };
11585
+ var isPinterestOwnedReferenceUrl = (value) => {
11586
+ const hostname = pinterestHostnameFromUrl(value);
11587
+ return hostname !== null && (hostname === "pinterest.com" || hostname.endsWith(".pinterest.com"));
11588
+ };
11589
+ var isUnapprovedPinterestReferenceUrl = (value) => {
11590
+ const hostname = pinterestHostnameFromUrl(value);
11591
+ return hostname !== null && isPinterestOwnedReferenceUrl(value) && !isAllowedPinterestReferenceHost(hostname);
11592
+ };
11593
+ var hasCleanMetadataValue = (value) => typeof value === "string" && countActionRefs(value) < 3 && hasCleanSignal(value);
11594
+ var hasCleanMetadataSignal = (reference) => hasCleanMetadataValue(reference.title) || hasCleanMetadataValue(reference.excerpt) || hasCleanMetadataValue(reference.capture?.title);
11595
+ var hasOnlySoftPinterestChromeDiagnostics = (reasons) => reasons.every((reason) => reason === "interface_chrome_shell");
11596
+ var hasPinterestVisualMetadataEvidence = (reference, diagnosticReasons) => isPinterestVisualReferenceUrl(reference.url) && reference.captureStatus === "captured" && reference.capture?.visual?.status === "captured" && hasCleanMetadataSignal(reference) && hasOnlySoftPinterestChromeDiagnostics(diagnosticReasons);
11343
11597
  var hasUsableCaptureEvidence = (reference) => hasCleanSignal(reference.capture?.snapshot?.content) || hasUsableCloneCreativeEvidence(reference) || hasCleanSignal(textFromHtml(reference.capture?.dom?.outerHTML));
11598
+ var referenceDiagnosticReasons = (reference) => {
11599
+ const text = [
11600
+ reference.title,
11601
+ reference.excerpt,
11602
+ reference.capture?.title,
11603
+ reference.capture?.snapshot?.content,
11604
+ textFromHtml(reference.capture?.clone?.componentPreview),
11605
+ reference.capture?.clone?.cssPreview,
11606
+ textFromHtml(reference.capture?.dom?.outerHTML),
11607
+ reference.capture?.visual?.failure,
11608
+ ...reference.capture?.visual?.warnings ?? []
11609
+ ].filter((value) => typeof value === "string" && value.trim().length > 0).join(" ");
11610
+ return diagnosticPageReasons(text);
11611
+ };
11612
+ var hasBlockingDiagnosticReason = (reasons) => reasons.some((reason) => reason !== "login_or_challenge_state");
11344
11613
  var hasInspiredesignUsableReferenceEvidence = (reference) => {
11614
+ if (isUnapprovedPinterestReferenceUrl(reference.url)) return false;
11615
+ const diagnosticReasons = referenceDiagnosticReasons(reference);
11616
+ if (hasPinterestVisualMetadataEvidence(reference, diagnosticReasons)) return true;
11617
+ if (hasBlockingDiagnosticReason(diagnosticReasons)) return false;
11618
+ if (diagnosticReasons.includes("login_or_challenge_state") && !hasUsableRecoveredCreativeEvidence(reference)) {
11619
+ return false;
11620
+ }
11345
11621
  if (reference.captureStatus === "captured" && hasUsableCaptureEvidence(reference)) return true;
11346
- return reference.fetchStatus === "captured" && (hasCleanSignal(reference.title) || hasCleanSignal(reference.excerpt));
11622
+ return reference.fetchStatus === "captured" && diagnosticReasons.length === 0 && (hasCleanSignal(reference.title) || hasCleanSignal(reference.excerpt));
11347
11623
  };
11348
11624
  var firstSignal = (reference) => {
11349
11625
  const preferred = [
@@ -11414,25 +11690,34 @@ var appendSourceDetail = (patterns, primarySignal) => {
11414
11690
  };
11415
11691
  var deriveCapturedVia = (reference) => {
11416
11692
  const methods = [];
11693
+ const diagnosticReasons = referenceDiagnosticReasons(reference);
11694
+ const hasPinterestVisualMetadata = hasPinterestVisualMetadataEvidence(reference, diagnosticReasons);
11417
11695
  if (reference.fetchStatus === "captured") methods.push("fetch");
11418
- if (reference.capture?.snapshot?.content.trim()) methods.push("snapshot");
11696
+ if (hasCleanSignal(reference.capture?.snapshot?.content)) methods.push("snapshot");
11419
11697
  if (hasUsableCloneCreativeEvidence(reference)) {
11420
11698
  methods.push("clone");
11421
11699
  }
11422
- if (reference.capture?.dom?.outerHTML.trim()) methods.push("dom");
11423
- if (reference.capture?.visual?.status === "captured") methods.push("visual");
11700
+ if (hasCleanSignal(textFromHtml(reference.capture?.dom?.outerHTML))) methods.push("dom");
11701
+ if (reference.capture?.visual?.status === "captured" && (hasUsableCaptureEvidence(reference) || hasPinterestVisualMetadata)) methods.push("visual");
11424
11702
  return methods;
11425
11703
  };
11426
11704
  var scoreReference = (reference, signals, isPublicLanding) => {
11427
11705
  let score = 0;
11706
+ const diagnosticReasons = referenceDiagnosticReasons(reference);
11707
+ const hasPinterestVisualMetadata = hasPinterestVisualMetadataEvidence(reference, diagnosticReasons);
11428
11708
  if (reference.fetchStatus === "captured") score += SCORE_FETCH_CAPTURED;
11429
- if (reference.captureStatus === "captured") score += SCORE_CAPTURE_CAPTURED;
11430
- if (reference.capture?.visual?.status === "captured") score += SCORE_VISUAL_CAPTURED;
11431
- if (reference.capture?.snapshot?.content.trim()) score += SCORE_SNAPSHOT;
11709
+ if (reference.captureStatus === "captured" && (hasUsableCaptureEvidence(reference) || hasPinterestVisualMetadata)) {
11710
+ score += SCORE_CAPTURE_CAPTURED;
11711
+ }
11712
+ if (reference.capture?.visual?.status === "captured" && (hasUsableCaptureEvidence(reference) || hasPinterestVisualMetadata)) score += SCORE_VISUAL_CAPTURED;
11713
+ if (hasCleanSignal(reference.capture?.snapshot?.content)) score += SCORE_SNAPSHOT;
11432
11714
  if (hasUsableCloneCreativeEvidence(reference)) score += SCORE_CLONE;
11433
- if (reference.capture?.dom?.outerHTML.trim()) score += SCORE_DOM;
11715
+ if (hasCleanSignal(textFromHtml(reference.capture?.dom?.outerHTML))) score += SCORE_DOM;
11434
11716
  if (isPublicLanding) score += SCORE_PUBLIC_LANDING;
11435
11717
  score += Math.min(SCORE_SIGNAL_CAP, signals.length * 2);
11718
+ if (hasPinterestVisualMetadata && diagnosticReasons.includes("interface_chrome_shell")) {
11719
+ score -= SCORE_PINTEREST_CHROME_METADATA_PENALTY;
11720
+ }
11436
11721
  return Math.min(MAX_REFERENCE_SCORE, score);
11437
11722
  };
11438
11723
  var confidenceFromScore = (score) => Number((score / MAX_REFERENCE_SCORE).toFixed(2));
@@ -11485,13 +11770,68 @@ var boardEvidenceText = (board) => board.references.map((reference) => [
11485
11770
  ...reference.patternsToBorrow
11486
11771
  ].join(" ")).join(" ").toLowerCase();
11487
11772
  var hasEvidenceCue = (text, matches) => matches.some((match) => text.includes(match));
11488
- var deriveReferenceEntry = (reference, format) => {
11773
+ var INTENT_STOP_WORDS = /* @__PURE__ */ new Set([
11774
+ "and",
11775
+ "cinematic",
11776
+ "dark",
11777
+ "digital",
11778
+ "for",
11779
+ "from",
11780
+ "landing",
11781
+ "light",
11782
+ "microinteractions",
11783
+ "motion",
11784
+ "page",
11785
+ "parallax",
11786
+ "premium",
11787
+ "reveal",
11788
+ "site",
11789
+ "scroll",
11790
+ "theme",
11791
+ "with",
11792
+ "design",
11793
+ "website"
11794
+ ]);
11795
+ var tokenizeIntent = (value) => (value.toLowerCase().match(/[a-z0-9][a-z0-9-]{2,}/g) ?? []).filter((token) => !INTENT_STOP_WORDS.has(token));
11796
+ var formatIntentTokens = (format) => [
11797
+ ...format.keywords,
11798
+ ...format.businessFocus,
11799
+ ...format.bestFor,
11800
+ ...format.focusAreas ?? [],
11801
+ format.archetype,
11802
+ format.layoutArchetype,
11803
+ format.surfaceTreatment,
11804
+ format.motionGrammar,
11805
+ format.paletteIntent
11806
+ ].flatMap(tokenizeIntent);
11807
+ var intentTokenVariants = (token) => {
11808
+ if (token === "photo" || token === "photos" || token === "photography" || token === "photographer" || token === "photographic") {
11809
+ return ["photo", "photos", "photography", "photographer", "photographic"];
11810
+ }
11811
+ return [token];
11812
+ };
11813
+ var countMatchedIntentTokens = (signals, intentTokens) => {
11814
+ const evidenceTokens = new Set(signals.flatMap(tokenizeIntent));
11815
+ return intentTokens.filter((token) => intentTokenVariants(token).some((variant) => evidenceTokens.has(variant))).length;
11816
+ };
11817
+ var hasBriefIntentMatch = (signals, format, briefText) => {
11818
+ const briefTokens = tokenizeIntent(briefText);
11819
+ const hasBriefIntentTokens = briefTokens.length > 0;
11820
+ const intentTokens = [...new Set(hasBriefIntentTokens ? briefTokens : formatIntentTokens(format))];
11821
+ if (intentTokens.length === 0) return true;
11822
+ const matchCount = countMatchedIntentTokens(signals, intentTokens);
11823
+ if (!hasBriefIntentTokens) return matchCount > 0;
11824
+ return matchCount >= Math.min(2, intentTokens.length);
11825
+ };
11826
+ var deriveReferenceEntry = (reference, format, briefText) => {
11489
11827
  const signals = getInspiredesignReferenceSignals(reference);
11490
11828
  const primarySignal = firstSignal(reference);
11491
11829
  const patterns = appendSourceDetail(derivePatternSummaries(signals, primarySignal), primarySignal);
11492
11830
  const isPublicLanding = signals.some(hasPublicLandingSignal);
11493
11831
  const capturedVia = deriveCapturedVia(reference);
11494
- const score = scoreReference(reference, signals, isPublicLanding);
11832
+ const intentMatched = hasBriefIntentMatch(signals, format, briefText);
11833
+ const rawScore = scoreReference(reference, signals, isPublicLanding);
11834
+ const score = intentMatched ? rawScore : Math.max(0, rawScore - SCORE_INTENT_MISMATCH_PENALTY);
11495
11835
  return {
11496
11836
  id: reference.id,
11497
11837
  score,
@@ -11500,7 +11840,8 @@ var deriveReferenceEntry = (reference, format) => {
11500
11840
  url: reference.url,
11501
11841
  surfaceType: isPublicLanding ? "public landing page" : format.archetype,
11502
11842
  capturedVia,
11503
- selectionReason: selectionReasonForScore(score, capturedVia),
11843
+ intentMatched,
11844
+ selectionReason: intentMatched ? selectionReasonForScore(score, capturedVia) : `${selectionReasonForScore(score, capturedVia)} Intent overlap with the brief is weak, so the score was downgraded.`,
11504
11845
  visualStrengths: deriveVisualStrengths(reference, patterns),
11505
11846
  visualRisks: deriveVisualRisks(reference),
11506
11847
  layoutRecipe: patterns.join("; "),
@@ -11518,6 +11859,13 @@ var sortReferenceEntries = (entries) => entries.slice().sort((left, right) => ri
11518
11859
  ...entry
11519
11860
  }));
11520
11861
  var rejectionReasonForReference = (reference) => {
11862
+ if (isUnapprovedPinterestReferenceUrl(reference.url)) {
11863
+ return "Pinterest reference host is not approved for creative synthesis.";
11864
+ }
11865
+ const diagnosticReasons = referenceDiagnosticReasons(reference);
11866
+ if (diagnosticReasons.length > 0) {
11867
+ return `Reference evidence is diagnostic-only: ${diagnosticReasons.join(", ")}.`;
11868
+ }
11521
11869
  if (reference.fetchStatus === "failed" && reference.captureStatus === "failed") {
11522
11870
  return "Fetch and capture did not produce usable creative evidence.";
11523
11871
  }
@@ -11529,23 +11877,125 @@ var rejectionReasonForReference = (reference) => {
11529
11877
  }
11530
11878
  return "Reference evidence was diagnostic, empty, or too weak for creative synthesis.";
11531
11879
  };
11532
- var buildRejectedReferences = (references) => references.filter((reference) => !hasInspiredesignUsableReferenceEvidence(reference)).map((reference) => ({
11533
- id: reference.id,
11534
- url: reference.url,
11535
- reason: rejectionReasonForReference(reference),
11536
- fetchStatus: reference.fetchStatus,
11537
- captureStatus: reference.captureStatus
11538
- }));
11539
- var buildInspiredesignReferencePatternBoard = (briefId, format, references) => {
11540
- const entries = references.filter(hasInspiredesignUsableReferenceEvidence).map((reference) => deriveReferenceEntry(reference, format));
11880
+ var hasCapturedEvidence = (reference) => reference.captureStatus === "captured" || reference.capture?.visual?.status === "captured";
11881
+ var capturedButRejectedReason = (diagnosticReasons) => diagnosticReasons.length > 0 ? `Captured browser evidence was rejected because it only exposed diagnostic signals: ${diagnosticReasons.join(", ")}.` : "Captured browser evidence was rejected because it did not contain usable creative reference evidence.";
11882
+ var buildRejectedReferences = (references) => references.filter((reference) => !hasInspiredesignUsableReferenceEvidence(reference)).map((reference) => {
11883
+ const diagnosticReasons = referenceDiagnosticReasons(reference);
11884
+ const captured = hasCapturedEvidence(reference);
11885
+ return {
11886
+ id: reference.id,
11887
+ url: reference.url,
11888
+ reason: rejectionReasonForReference(reference),
11889
+ fetchStatus: reference.fetchStatus,
11890
+ captureStatus: reference.captureStatus,
11891
+ ...captured ? { captured: true } : {},
11892
+ ...diagnosticReasons.length > 0 ? { diagnosticReasons } : {},
11893
+ ...captured ? {
11894
+ capturedButRejectedReason: capturedButRejectedReason(diagnosticReasons),
11895
+ evidenceGap: "Design-facing artifacts require creative layout evidence; diagnostic browser chrome is kept only as rejection metadata."
11896
+ } : {}
11897
+ };
11898
+ });
11899
+ var buildQualitySummary = (references, rankedEntries, rejectedReferences) => {
11900
+ const diagnosticOnlyReasons = [...new Set(references.flatMap(referenceDiagnosticReasons))];
11901
+ const rankedIds = new Set(rankedEntries.map((entry) => entry.id));
11902
+ const rankedReferences = references.filter((reference) => rankedIds.has(reference.id));
11903
+ const failedCaptureCount = rankedReferences.filter((reference) => reference.captureStatus === "failed").length;
11904
+ const missingScreenshotCount = rankedReferences.filter((reference) => reference.capture?.visual?.status !== "captured").length;
11905
+ const topReference = rankedEntries[0];
11906
+ return {
11907
+ rankedReferenceCount: rankedEntries.length,
11908
+ rejectedReferenceCount: rejectedReferences.length,
11909
+ failedCaptureCount,
11910
+ missingScreenshotCount,
11911
+ diagnosticOnlyReasons,
11912
+ ...topReference ? {
11913
+ topReferenceScore: topReference.score,
11914
+ topReferenceConfidence: topReference.confidence,
11915
+ topReferenceIntentMatched: topReference.intentMatched
11916
+ } : {}
11917
+ };
11918
+ };
11919
+ var summarizeInspiredesignReferenceQuality = (board) => ({ ...board.qualitySummary });
11920
+ var isInspiredesignReadyReference = (reference) => reference.intentMatched && reference.score >= MIN_READY_REFERENCE_SCORE && reference.confidence >= MIN_READY_REFERENCE_CONFIDENCE;
11921
+ var isInspiredesignDesignReference = (reference) => !isPinterestOwnedReferenceUrl(reference.url) || isPinterestVisualReferenceUrl(reference.url) && isInspiredesignReadyReference(reference);
11922
+ var buildNotReadyRejectedReference = (reference) => {
11923
+ const captured = reference.capturedVia.length > 0;
11924
+ return {
11925
+ id: reference.id,
11926
+ url: reference.url,
11927
+ reason: reference.intentMatched ? "Reference evidence did not meet the design-ready ranking threshold." : "Reference evidence did not match the requested design intent.",
11928
+ fetchStatus: reference.capturedVia.includes("fetch") ? "captured" : "skipped",
11929
+ captureStatus: reference.capturedVia.some((method) => method !== "fetch") ? "captured" : "off",
11930
+ ...captured ? {
11931
+ captured: true,
11932
+ capturedButRejectedReason: "Captured reference evidence did not satisfy design-ready ranking gates.",
11933
+ evidenceGap: "Design-facing artifacts require design-ready creative evidence; non-ready captures are kept only as rejection metadata."
11934
+ } : {}
11935
+ };
11936
+ };
11937
+ var mergeRejectedReferences = (rejectedReferences) => {
11938
+ const seen = /* @__PURE__ */ new Set();
11939
+ return rejectedReferences.filter((reference) => {
11940
+ if (seen.has(reference.id)) return false;
11941
+ seen.add(reference.id);
11942
+ return true;
11943
+ });
11944
+ };
11945
+ var buildInspiredesignRankedArtifactPatternBoard = (designBoard, sourceBoard) => {
11946
+ const designReferenceIds = new Set(designBoard.references.map((reference) => reference.id));
11947
+ const notReadyReferences = sourceBoard.references.filter((reference) => !designReferenceIds.has(reference.id)).map(buildNotReadyRejectedReference);
11948
+ return {
11949
+ ...designBoard,
11950
+ rejectedReferences: mergeRejectedReferences([
11951
+ ...sourceBoard.rejectedReferences,
11952
+ ...notReadyReferences
11953
+ ])
11954
+ };
11955
+ };
11956
+ var buildInspiredesignDesignReferencePatternBoard = (board, designVectors) => {
11957
+ const references = board.references.filter(isInspiredesignDesignReference);
11958
+ const notReadyCount = board.references.length - references.length;
11959
+ const topReference = references[0];
11960
+ const missingScreenshotCount = references.filter((reference) => !reference.capturedVia.includes("visual")).length;
11961
+ const qualitySummary = {
11962
+ rankedReferenceCount: references.length,
11963
+ rejectedReferenceCount: board.rejectedReferences.length + notReadyCount,
11964
+ failedCaptureCount: 0,
11965
+ missingScreenshotCount,
11966
+ diagnosticOnlyReasons: [...board.qualitySummary.diagnosticOnlyReasons],
11967
+ ...topReference ? {
11968
+ topReferenceScore: topReference.score,
11969
+ topReferenceConfidence: topReference.confidence,
11970
+ topReferenceIntentMatched: topReference.intentMatched
11971
+ } : {}
11972
+ };
11973
+ return {
11974
+ ...board,
11975
+ targetSurface: designVectors.surfaceIntent,
11976
+ qualitySummary,
11977
+ references,
11978
+ rejectedReferences: [],
11979
+ synthesis: {
11980
+ dominantDirection: designVectors.directionLabel,
11981
+ sharedStrengths: [...designVectors.patternsToBorrow],
11982
+ sharedFailuresToAvoid: [...designVectors.patternsToReject],
11983
+ contractDeltas: references.length > 0 ? [...board.synthesis.contractDeltas] : ["No ready reference evidence is available; keep implementation anchored to the source brief."]
11984
+ }
11985
+ };
11986
+ };
11987
+ var buildInspiredesignReferencePatternBoard = (briefId, format, references, briefText = "") => {
11988
+ const entries = references.filter(hasInspiredesignUsableReferenceEvidence).map((reference) => deriveReferenceEntry(reference, format, briefText));
11541
11989
  const rankedEntries = sortReferenceEntries(entries);
11990
+ const rejectedReferences = buildRejectedReferences(references);
11542
11991
  const sharedStrengths = rankedEntries.flatMap((entry) => entry.patternsToBorrow).slice(0, 6);
11543
11992
  const targetSurface = rankedEntries.some((entry) => entry.surfaceType === "public landing page") ? "reference-led public landing page" : format.layoutArchetype;
11544
11993
  return {
11545
11994
  briefId,
11546
11995
  targetSurface,
11996
+ qualitySummary: buildQualitySummary(references, rankedEntries, rejectedReferences),
11547
11997
  references: rankedEntries,
11548
- rejectedReferences: buildRejectedReferences(references),
11998
+ rejectedReferences,
11549
11999
  synthesis: {
11550
12000
  dominantDirection: rankedEntries[0]?.layoutRecipe ?? format.archetype,
11551
12001
  sharedStrengths,
@@ -11651,13 +12101,16 @@ var buildSectionArchitecture = (format, board) => {
11651
12101
  ];
11652
12102
  };
11653
12103
  var buildInspiredesignDesignVectors = (format, board) => {
11654
- const influence = board.synthesis.sharedStrengths.length > 0 ? board.synthesis.sharedStrengths : [format.archetype];
11655
- const publicLandingEvidence = hasBoardPublicLandingEvidence(board);
12104
+ const designReferences = board.references.filter(isInspiredesignDesignReference);
12105
+ const designStrengths = designReferences.flatMap((entry) => entry.patternsToBorrow).slice(0, 6);
12106
+ const influence = designStrengths.length > 0 ? designStrengths : [format.archetype];
12107
+ const designBoard = { ...board, references: designReferences };
12108
+ const publicLandingEvidence = hasBoardPublicLandingEvidence(designBoard);
11656
12109
  const surfaceIntent = publicLandingEvidence ? "reference-led public landing page" : format.archetype;
11657
- const compositionModel = publicLandingEvidence ? ["full-bleed hero with narrative section cadence", ...board.references.map((entry) => entry.layoutRecipe)] : [format.layoutArchetype, ...board.references.map((entry) => entry.layoutRecipe)];
12110
+ const compositionModel = publicLandingEvidence ? ["full-bleed hero with narrative section cadence", ...designReferences.map((entry) => entry.layoutRecipe)] : [format.layoutArchetype, ...designReferences.map((entry) => entry.layoutRecipe)];
11658
12111
  return {
11659
- sourcePriority: board.references.length > 0 ? "reference-evidence-first" : "brief-only",
11660
- directionLabel: board.synthesis.dominantDirection,
12112
+ sourcePriority: designReferences.length > 0 ? "reference-evidence-first" : "brief-only",
12113
+ directionLabel: designReferences[0]?.layoutRecipe ?? format.archetype,
11661
12114
  surfaceIntent,
11662
12115
  compositionModel: compositionModel.slice(0, 5),
11663
12116
  premiumPosture: [
@@ -11671,16 +12124,16 @@ var buildInspiredesignDesignVectors = (format, board) => {
11671
12124
  "Respect reduced-motion preference with static hierarchy preserved.",
11672
12125
  format.motionGrammar
11673
12126
  ],
11674
- sectionArchitecture: buildSectionArchitecture(format, board),
12127
+ sectionArchitecture: buildSectionArchitecture(format, designBoard),
11675
12128
  typographyPosture: [format.typographySystem],
11676
- imageryPosture: buildImageryPosture(format, board),
11677
- interactionDensity: buildInteractionDensity(format, board),
11678
- interactionMoments: buildInteractionMoments(format, board),
11679
- materialEffects: buildMaterialEffects(board),
12129
+ imageryPosture: buildImageryPosture(format, designBoard),
12130
+ interactionDensity: buildInteractionDensity(format, designBoard),
12131
+ interactionMoments: buildInteractionMoments(format, designBoard),
12132
+ materialEffects: buildMaterialEffects(designBoard),
11680
12133
  advancedMotionAdvisory: [...ADVANCED_MOTION_FIELDS],
11681
12134
  referenceInfluence: influence,
11682
- patternsToBorrow: board.references.flatMap((entry) => entry.patternsToBorrow).slice(0, 8),
11683
- patternsToReject: board.references.flatMap((entry) => entry.patternsToReject).slice(0, 8),
12135
+ patternsToBorrow: designReferences.flatMap((entry) => entry.patternsToBorrow).slice(0, 8),
12136
+ patternsToReject: designReferences.flatMap((entry) => entry.patternsToReject).slice(0, 8),
11684
12137
  guardrails: [...format.guardrails],
11685
12138
  antiPatterns: [...format.antiPatterns]
11686
12139
  };
@@ -11688,11 +12141,11 @@ var buildInspiredesignDesignVectors = (format, board) => {
11688
12141
 
11689
12142
  // src/inspiredesign/meta-prompt.ts
11690
12143
  var formatList = (items) => items.length > 0 ? items.map((item) => `- ${item}`).join("\n") : "- No evidence-backed item available.";
11691
- var formatRankedReferences = (board) => {
11692
- if (board.references.length === 0) {
11693
- return "- No usable references were ranked. Work from the brief and note missing evidence.";
12144
+ var formatRankedReferences = (references) => {
12145
+ if (references.length === 0) {
12146
+ return "- No ready references were ranked. Work from the brief and note missing evidence.";
11694
12147
  }
11695
- return board.references.map((reference) => [
12148
+ return references.map((reference) => [
11696
12149
  `### Rank ${reference.rank}: ${reference.name}`,
11697
12150
  `- URL: ${reference.url}`,
11698
12151
  `- Score: ${reference.score}`,
@@ -11704,64 +12157,71 @@ var formatRankedReferences = (board) => {
11704
12157
  `- Visual risks: ${reference.visualRisks.join("; ")}`
11705
12158
  ].join("\n")).join("\n\n");
11706
12159
  };
11707
- var formatRejectedReferences = (board) => {
11708
- if (board.rejectedReferences.length === 0) {
11709
- return "- No references were rejected from the creative synthesis.";
11710
- }
11711
- return board.rejectedReferences.map((reference) => `- ${reference.url}: ${reference.reason} (fetch=${reference.fetchStatus}, capture=${reference.captureStatus})`).join("\n");
12160
+ var formatRejectedReferences = (board, notReadyReferences) => {
12161
+ const lines = [
12162
+ ...board.rejectedReferences.length > 0 ? [`- ${board.rejectedReferences.length} reference(s) were rejected as diagnostic-only or unavailable.`] : [],
12163
+ ...notReadyReferences.length > 0 ? [`- ${notReadyReferences.length} ranked reference(s) were not ready for creative synthesis due to score, confidence, or brief-intent mismatch.`] : []
12164
+ ];
12165
+ return lines.length > 0 ? lines.join("\n") : "- No references were rejected from the creative synthesis.";
12166
+ };
12167
+ var buildInspiredesignMetaPrompt = (input) => {
12168
+ const designReferences = input.referencePatternBoard.references.filter(isInspiredesignDesignReference);
12169
+ const notReadyReferences = input.referencePatternBoard.references.filter(
12170
+ (reference) => !isInspiredesignDesignReference(reference)
12171
+ );
12172
+ return [
12173
+ "# InspireDesign Meta Prompt",
12174
+ "",
12175
+ "Use this prompt to generate a fresh design direction from evidence without copying any reference brand, asset, layout, or proprietary expression.",
12176
+ "",
12177
+ "## Source Brief",
12178
+ input.brief,
12179
+ "",
12180
+ "## Prompt Format",
12181
+ `- Format: ${input.briefExpansion.format.label}`,
12182
+ `- Target surface: ${input.designVectors.surfaceIntent}`,
12183
+ `- Dominant direction: ${input.designVectors.directionLabel}`,
12184
+ "",
12185
+ "## Ranked References",
12186
+ formatRankedReferences(designReferences),
12187
+ "",
12188
+ "## Rejected References",
12189
+ formatRejectedReferences(input.referencePatternBoard, notReadyReferences),
12190
+ "",
12191
+ "## Borrow Guidance",
12192
+ formatList(input.designVectors.patternsToBorrow),
12193
+ "",
12194
+ "## Reject Guidance",
12195
+ formatList([
12196
+ ...input.designVectors.patternsToReject,
12197
+ "Do not copy logos, screenshots, protected brand assets, page structure, copy, or trade dress from references."
12198
+ ]),
12199
+ "",
12200
+ "## Motion Posture",
12201
+ formatList([
12202
+ ...input.designVectors.motionPosture,
12203
+ ...input.designVectors.interactionMoments,
12204
+ ...input.designVectors.advancedMotionAdvisory
12205
+ ]),
12206
+ "",
12207
+ "## Accessibility Constraints",
12208
+ formatList([
12209
+ "Keyboard navigation must reach every interactive element.",
12210
+ "Focus states must be visible in every theme and viewport.",
12211
+ "Respect prefers-reduced-motion with a static hierarchy-preserving alternative.",
12212
+ "Validate contrast for text, controls, overlays, and disabled states."
12213
+ ]),
12214
+ "",
12215
+ "## Validation Gates",
12216
+ formatList([
12217
+ "Read visual-evidence.json, screenshot-index.json, ranked-references.json, and evidence.json before implementation.",
12218
+ "Confirm screenshot paths exist before making visual claims.",
12219
+ "Verify desktop and mobile layouts with real browser screenshots.",
12220
+ "Run reduced-motion, keyboard, focus, and contrast checks before shipping.",
12221
+ "Keep production code generation outside the harvest output."
12222
+ ])
12223
+ ].join("\n");
11712
12224
  };
11713
- var buildInspiredesignMetaPrompt = (input) => [
11714
- "# InspireDesign Meta Prompt",
11715
- "",
11716
- "Use this prompt to generate a fresh design direction from evidence without copying any reference brand, asset, layout, or proprietary expression.",
11717
- "",
11718
- "## Source Brief",
11719
- input.brief,
11720
- "",
11721
- "## Prompt Format",
11722
- `- Format: ${input.briefExpansion.format.label}`,
11723
- `- Target surface: ${input.referencePatternBoard.targetSurface}`,
11724
- `- Dominant direction: ${input.referencePatternBoard.synthesis.dominantDirection}`,
11725
- "",
11726
- "## Ranked References",
11727
- formatRankedReferences(input.referencePatternBoard),
11728
- "",
11729
- "## Rejected References",
11730
- formatRejectedReferences(input.referencePatternBoard),
11731
- "",
11732
- "## Borrow Guidance",
11733
- formatList(input.designVectors.patternsToBorrow),
11734
- "",
11735
- "## Reject Guidance",
11736
- formatList([
11737
- ...input.designVectors.patternsToReject,
11738
- "Do not copy logos, screenshots, protected brand assets, page structure, copy, or trade dress from references."
11739
- ]),
11740
- "",
11741
- "## Motion Posture",
11742
- formatList([
11743
- ...input.designVectors.motionPosture,
11744
- ...input.designVectors.interactionMoments,
11745
- ...input.designVectors.advancedMotionAdvisory
11746
- ]),
11747
- "",
11748
- "## Accessibility Constraints",
11749
- formatList([
11750
- "Keyboard navigation must reach every interactive element.",
11751
- "Focus states must be visible in every theme and viewport.",
11752
- "Respect prefers-reduced-motion with a static hierarchy-preserving alternative.",
11753
- "Validate contrast for text, controls, overlays, and disabled states."
11754
- ]),
11755
- "",
11756
- "## Validation Gates",
11757
- formatList([
11758
- "Read visual-evidence.json, screenshot-index.json, ranked-references.json, and evidence.json before implementation.",
11759
- "Confirm screenshot paths exist before making visual claims.",
11760
- "Verify desktop and mobile layouts with real browser screenshots.",
11761
- "Run reduced-motion, keyboard, focus, and contrast checks before shipping.",
11762
- "Keep production code generation outside the harvest output."
11763
- ])
11764
- ].join("\n");
11765
12225
 
11766
12226
  // src/inspiredesign/visual-evidence.ts
11767
12227
  import { createHash as createHash3 } from "crypto";
@@ -12208,13 +12668,16 @@ var buildReferenceSynthesis = (references) => {
12208
12668
  };
12209
12669
  };
12210
12670
  var renderReferenceFirstAdvancedBrief = (briefExpansion, board, vectors, references) => {
12211
- if (board.references.length === 0) {
12671
+ if (board.references.length === 0 || vectors.sourcePriority !== "reference-evidence-first") {
12212
12672
  if (references.length > 0) {
12213
12673
  return [
12214
12674
  "Reference evidence unavailable:",
12215
- "URL references were attempted, but no usable creative evidence was captured. Treat this as a capture gap, not a design direction.",
12675
+ "URL references were attempted, but no ready-quality creative evidence was captured. Treat this as a capture or intent gap, not a design direction.",
12216
12676
  "",
12217
- formatBulletList2(references.map((reference) => renderUnavailableReference(reference))),
12677
+ formatBulletList2([
12678
+ `${references.length} attempted reference(s) are retained in diagnostic artifacts only.`,
12679
+ "Do not use rejected or not-ready reference URLs, names, screenshots, or metadata as creative direction."
12680
+ ]),
12218
12681
  "",
12219
12682
  briefExpansion.advancedBrief
12220
12683
  ].join("\n");
@@ -12301,10 +12764,6 @@ var renderEvidenceDerivedAdvancedBrief = (briefExpansion, format) => [
12301
12764
  "Best fit use cases:",
12302
12765
  formatBulletList2(format.bestFor)
12303
12766
  ].join("\n");
12304
- var renderUnavailableReference = (reference) => {
12305
- const reason = reference.fetchFailure ?? reference.captureFailure ?? "no usable creative evidence captured";
12306
- return `${reference.url}: fetch=${reference.fetchStatus}, capture=${reference.captureStatus}, reason=${clipText2(reason, 160)}`;
12307
- };
12308
12767
  var cloneTemplate = (value) => structuredClone(value);
12309
12768
  var referenceFingerprint = (value) => {
12310
12769
  return createHash4("sha256").update(value).digest("hex").slice(0, 12);
@@ -12877,15 +13336,14 @@ var buildFollowthrough = ({
12877
13336
  });
12878
13337
  var buildDesignContract = ({
12879
13338
  brief,
12880
- urls,
12881
- references,
13339
+ designReferences,
12882
13340
  plan,
12883
13341
  format
12884
13342
  }) => ({
12885
- intent: buildIntentBlock(brief, urls, references, format),
13343
+ intent: buildIntentBlock(brief, designReferences.map((reference) => reference.url), designReferences, format),
12886
13344
  generationPlan: toCanvasGenerationPlan(plan),
12887
13345
  designLanguage: buildDesignLanguageBlock(plan.visualDirection.profile, format),
12888
- contentModel: buildContentModelBlock(brief, references.filter(hasInspiredesignUsableReferenceEvidence)),
13346
+ contentModel: buildContentModelBlock(brief, designReferences),
12889
13347
  layoutSystem: buildLayoutSystemBlock(plan, format),
12890
13348
  typographySystem: buildTypographySystemBlock(format),
12891
13349
  colorSystem: buildColorSystemBlock(plan.visualDirection.profile, format),
@@ -12957,6 +13415,7 @@ var buildImplementationPlan = ({
12957
13415
  profile,
12958
13416
  format,
12959
13417
  references,
13418
+ attemptedReferenceCount,
12960
13419
  synthesis,
12961
13420
  designVectors
12962
13421
  }) => ({
@@ -12994,7 +13453,7 @@ var buildImplementationPlan = ({
12994
13453
  "Avoid horizontal scrolling for primary content."
12995
13454
  ],
12996
13455
  risksAndAmbiguities: [
12997
- references.length === 0 ? "No live references were supplied, so visual cues are derived entirely from the written brief." : synthesis.lines.length > 0 ? "Live references were reduced into reusable patterns; unique brand assets should still be recreated, not copied." : "Reference URLs were attempted, but no usable creative evidence was captured; keep implementation anchored to the source brief and selected prompt format.",
13456
+ attemptedReferenceCount === 0 ? "No live references were supplied, so visual cues are derived entirely from the written brief." : synthesis.lines.length > 0 ? "Live references were reduced into reusable patterns; unique brand assets should still be recreated, not copied." : "Reference URLs were attempted, but no usable creative evidence was captured; keep implementation anchored to the source brief and selected prompt format.",
12998
13457
  "Any missing interaction states must be validated during visual QA.",
12999
13458
  "Capture desktop and mobile browser proof before handoff, including reduced-motion behavior and primary CTA visibility."
13000
13459
  ],
@@ -13249,11 +13708,11 @@ var renderPrototypeGuidance = (profile, synthesis, designVectors, targetAnalysis
13249
13708
  "- first prototype should include vs omit: include shell, primary hero or decision section, CTA group, proof or detail sections, section patterns named in the design vectors, final CTA, and footer; omit analytics, app-shell widgets, empty card grids, and any section not supported by the brief or reference evidence."
13250
13709
  ].join("\n");
13251
13710
  };
13252
- var renderDeliverablesSummary = (includePrototypeGuidance) => {
13711
+ var renderDeliverablesSummary = (includePrototypeGuidance, canvasContinuationReady) => {
13253
13712
  const deliverables = [
13254
13713
  "Structured `designContract` JSON aligned to canvas governance",
13255
13714
  "Valid `generationPlan` JSON aligned to the canvas generation plan contract",
13256
- "Ready-to-fill `canvasPlanRequest` JSON for `canvas.plan.set`",
13715
+ canvasContinuationReady ? "Ready-to-fill `canvasPlanRequest` JSON for `canvas.plan.set`" : "Diagnostic `canvasPlanRequest` preview; do not submit to Canvas until next-step guidance is ready",
13257
13716
  "Design-agent handoff JSON with contract scope, skill nudges, and richer implementation context",
13258
13717
  "Human-readable `design.md` design specification",
13259
13718
  "Engineering implementation plan in JSON and Markdown"
@@ -13342,19 +13801,25 @@ var buildInspiredesignPacket = (input) => {
13342
13801
  title: reference.title ? trimText2(reference.title) : void 0,
13343
13802
  excerpt: reference.excerpt ? trimText2(reference.excerpt) : void 0
13344
13803
  }));
13345
- const usableReferences = references.filter(hasInspiredesignUsableReferenceEvidence);
13346
- const synthesis = buildReferenceSynthesis(usableReferences);
13804
+ const referenceEvidenceRequired = input.referenceEvidenceRequired ?? (urls.length > 0 || references.length > 0);
13347
13805
  const referencePatternBoard = buildInspiredesignReferencePatternBoard(
13348
13806
  referenceFingerprint(brief),
13349
13807
  selectedFormat,
13350
- references
13808
+ references,
13809
+ brief
13810
+ );
13811
+ const readyReferenceIds = new Set(
13812
+ referencePatternBoard.references.filter(isInspiredesignDesignReference).map((reference) => reference.id)
13351
13813
  );
13814
+ const usableReferences = references.filter(hasInspiredesignUsableReferenceEvidence).filter((reference) => readyReferenceIds.has(reference.id));
13815
+ const synthesis = buildReferenceSynthesis(usableReferences);
13352
13816
  const designVectors = buildInspiredesignDesignVectors(selectedFormat, referencePatternBoard);
13817
+ const designReferencePatternBoard = buildInspiredesignDesignReferencePatternBoard(referencePatternBoard, designVectors);
13353
13818
  const effectiveFormat = buildEvidenceDerivedFormat(selectedFormat, designVectors);
13354
13819
  const targetAnalysis = buildTargetAnalysis(
13355
13820
  brief,
13356
13821
  effectiveFormat,
13357
- references,
13822
+ usableReferences,
13358
13823
  synthesis,
13359
13824
  designVectors
13360
13825
  );
@@ -13371,7 +13836,7 @@ var buildInspiredesignPacket = (input) => {
13371
13836
  });
13372
13837
  const advancedBriefMarkdown = renderReferenceFirstAdvancedBrief(
13373
13838
  effectiveBriefExpansion,
13374
- referencePatternBoard,
13839
+ designReferencePatternBoard,
13375
13840
  designVectors,
13376
13841
  references
13377
13842
  );
@@ -13379,7 +13844,7 @@ var buildInspiredesignPacket = (input) => {
13379
13844
  brief,
13380
13845
  format: effectiveFormat,
13381
13846
  synthesis,
13382
- referencePatternBoard,
13847
+ referencePatternBoard: designReferencePatternBoard,
13383
13848
  designVectors,
13384
13849
  targetAnalysis
13385
13850
  });
@@ -13387,8 +13852,7 @@ var buildInspiredesignPacket = (input) => {
13387
13852
  const canvasPlanRequest = buildCanvasPlanRequest(brief, generationPlan);
13388
13853
  const designContract = buildDesignContract({
13389
13854
  brief,
13390
- urls,
13391
- references,
13855
+ designReferences: usableReferences,
13392
13856
  plan: generationPlan,
13393
13857
  format: effectiveFormat
13394
13858
  });
@@ -13397,14 +13861,15 @@ var buildInspiredesignPacket = (input) => {
13397
13861
  briefExpansion: effectiveBriefExpansion,
13398
13862
  synthesis,
13399
13863
  includePrototypeGuidance,
13400
- referencePatternBoard,
13864
+ referencePatternBoard: designReferencePatternBoard,
13401
13865
  designVectors,
13402
13866
  targetAnalysis
13403
13867
  });
13404
13868
  const implementationPlan = buildImplementationPlan({
13405
13869
  profile,
13406
13870
  format: effectiveFormat,
13407
- references,
13871
+ references: usableReferences,
13872
+ attemptedReferenceCount: references.length,
13408
13873
  synthesis,
13409
13874
  designVectors
13410
13875
  });
@@ -13435,7 +13900,7 @@ var buildInspiredesignPacket = (input) => {
13435
13900
  "",
13436
13901
  "## 3.2 Reference Pattern Board",
13437
13902
  "",
13438
- formatBulletList2(referencePatternBoard.synthesis.sharedStrengths.length > 0 ? referencePatternBoard.synthesis.sharedStrengths : ["No live reference cues were captured."]),
13903
+ formatBulletList2(designVectors.patternsToBorrow.length > 0 ? designVectors.patternsToBorrow : ["No live reference cues were captured."]),
13439
13904
  "",
13440
13905
  "## 3.3 Design Vectors",
13441
13906
  "",
@@ -13474,7 +13939,10 @@ var buildInspiredesignPacket = (input) => {
13474
13939
  "",
13475
13940
  "# 7. Deliverables Summary",
13476
13941
  "",
13477
- renderDeliverablesSummary(Boolean(input.includePrototypeGuidance))
13942
+ renderDeliverablesSummary(
13943
+ Boolean(input.includePrototypeGuidance),
13944
+ !referenceEvidenceRequired || designReferencePatternBoard.references.length > 0
13945
+ )
13478
13946
  ].join("\n");
13479
13947
  const visualEvidence = buildVisualEvidencePayload(references);
13480
13948
  const screenshotIndex = buildScreenshotIndex(references);
@@ -13490,7 +13958,8 @@ var buildInspiredesignPacket = (input) => {
13490
13958
  prototypeGuidanceMarkdown,
13491
13959
  visualEvidence,
13492
13960
  screenshotIndex,
13493
- rankedReferences: referencePatternBoard.references,
13961
+ rankedReferences: designReferencePatternBoard.references,
13962
+ referencePatternBoard,
13494
13963
  metaPromptMarkdown,
13495
13964
  evidence: buildEvidencePayload({
13496
13965
  brief,
@@ -13498,13 +13967,1228 @@ var buildInspiredesignPacket = (input) => {
13498
13967
  advancedBriefMarkdown,
13499
13968
  urls,
13500
13969
  references,
13501
- referencePatternBoard,
13970
+ referencePatternBoard: designReferencePatternBoard,
13502
13971
  designVectors,
13503
13972
  targetAnalysis
13504
13973
  })
13505
13974
  };
13506
13975
  };
13507
13976
 
13977
+ // src/guidance/renderers.ts
13978
+ var toJsonValue2 = (value) => {
13979
+ return structuredClone(value);
13980
+ };
13981
+ var renderWorkflowGuidance = (guidance) => {
13982
+ return toJsonValue2(guidance);
13983
+ };
13984
+ var renderWorkflowCompatibility = (guidance, fallbackSummary) => {
13985
+ const commandSteps = guidance.commands.map((entry) => ({
13986
+ reason: entry.label,
13987
+ command: entry.command
13988
+ }));
13989
+ const artifactSteps = guidance.artifactInputs.map((entry) => ({
13990
+ reason: `${entry.required ? "Required" : "Optional"}: ${entry.path}. ${entry.purpose}`
13991
+ }));
13992
+ const validationSteps = guidance.validationChecks.map((entry) => ({
13993
+ reason: entry.assertion ? `${entry.description} Assertion: ${entry.assertion}` : entry.description,
13994
+ ...entry.command ? { command: entry.command } : {}
13995
+ }));
13996
+ return {
13997
+ followthroughSummary: fallbackSummary ?? guidance.primaryAction.summary,
13998
+ suggestedNextAction: guidance.primaryAction.summary,
13999
+ suggestedSteps: [...commandSteps, ...artifactSteps, ...validationSteps]
14000
+ };
14001
+ };
14002
+
14003
+ // src/guidance/readiness.ts
14004
+ var MIN_READY_REFERENCE_SCORE2 = 50;
14005
+ var MIN_READY_REFERENCE_CONFIDENCE2 = 0.5;
14006
+ var hasProviderBlocker = (context) => {
14007
+ if (context.providerUnavailable === true) return true;
14008
+ return context.reasonCode === "provider_unavailable" || context.reasonCode === "auth_required";
14009
+ };
14010
+ var hasDiagnosticOnlyEvidence = (context) => {
14011
+ const reasons = context.evidence?.diagnosticOnlyReasons ?? [];
14012
+ if (reasons.length === 0) return false;
14013
+ return (context.evidence?.rankedReferenceCount ?? 0) === 0;
14014
+ };
14015
+ var hasNoReferences = (context) => {
14016
+ return context.evidence?.referenceEvidenceRequired !== false && (context.evidence?.referenceCount ?? 0) === 0;
14017
+ };
14018
+ var hasNoRankedReferences = (context) => {
14019
+ const referenceCount = context.evidence?.referenceCount ?? 0;
14020
+ if (referenceCount === 0) return false;
14021
+ return (context.evidence?.rankedReferenceCount ?? 0) === 0;
14022
+ };
14023
+ var hasRequiredCaptureFailure = (context) => {
14024
+ if (context.evidence?.visualEvidenceRequired !== true) return false;
14025
+ return (context.evidence.failedCaptureCount ?? 0) > 0 || (context.evidence.missingScreenshotCount ?? 0) > 0;
14026
+ };
14027
+ var hasWeakTopReference = (context) => {
14028
+ const rankedCount = context.evidence?.rankedReferenceCount ?? 0;
14029
+ if (rankedCount === 0) return false;
14030
+ const score = context.evidence?.topReferenceScore ?? 0;
14031
+ const confidence = context.evidence?.topReferenceConfidence ?? 0;
14032
+ return score < MIN_READY_REFERENCE_SCORE2 || confidence < MIN_READY_REFERENCE_CONFIDENCE2;
14033
+ };
14034
+ var hasOffBriefTopReference = (context) => {
14035
+ const rankedCount = context.evidence?.rankedReferenceCount ?? 0;
14036
+ return rankedCount > 0 && context.evidence?.topReferenceIntentMatched === false;
14037
+ };
14038
+ var classifyGuidanceReadiness = (context) => {
14039
+ if (context.reasonCode === "missing_input" || context.reasonCode === "missing_params") return "needs_input";
14040
+ if (context.reasonCode === "daemon_fingerprint_mismatch") return "blocked";
14041
+ if (hasProviderBlocker(context)) return "blocked";
14042
+ if (hasDiagnosticOnlyEvidence(context)) return "diagnostic_only";
14043
+ if (hasNoReferences(context)) return "needs_recovery";
14044
+ if (hasNoRankedReferences(context)) return "needs_recovery";
14045
+ if (hasRequiredCaptureFailure(context)) return "needs_recovery";
14046
+ if (hasOffBriefTopReference(context)) return "needs_recovery";
14047
+ if (hasWeakTopReference(context)) return "needs_recovery";
14048
+ return "ready";
14049
+ };
14050
+
14051
+ // src/canvas/repair-examples.ts
14052
+ var EXAMPLE_MAX_INTERACTION_LATENCY_MS = 150;
14053
+ var MAX_ISSUE_FIELD_EXAMPLES = 8;
14054
+ var EXAMPLE_CANVAS_GENERATION_PLAN = {
14055
+ targetOutcome: {
14056
+ mode: "high-fi-live-edit",
14057
+ summary: "Produce an evidence-backed, responsive landing page iteration."
14058
+ },
14059
+ visualDirection: {
14060
+ profile: "cinematic-minimal",
14061
+ themeStrategy: "single-theme"
14062
+ },
14063
+ layoutStrategy: {
14064
+ approach: "hero-led composition with clear content sections",
14065
+ navigationModel: "global-header"
14066
+ },
14067
+ contentStrategy: {
14068
+ source: "design brief, harvested references, and current project content"
14069
+ },
14070
+ componentStrategy: {
14071
+ mode: "reuse existing components before creating new primitives",
14072
+ interactionStates: ["default", "hover", "focus", "disabled"]
14073
+ },
14074
+ motionPosture: {
14075
+ level: "subtle",
14076
+ reducedMotion: "respect-user-preference"
14077
+ },
14078
+ responsivePosture: {
14079
+ primaryViewport: "desktop",
14080
+ requiredViewports: ["desktop", "tablet", "mobile"]
14081
+ },
14082
+ accessibilityPosture: {
14083
+ target: "WCAG_2_2_AA",
14084
+ keyboardNavigation: "full"
14085
+ },
14086
+ validationTargets: {
14087
+ blockOn: ["contrast-failure", "missing-intent", "missing-design-language"],
14088
+ requiredThemes: ["light"],
14089
+ browserValidation: "required",
14090
+ maxInteractionLatencyMs: EXAMPLE_MAX_INTERACTION_LATENCY_MS
14091
+ },
14092
+ interactionMoments: ["primary CTA hover", "keyboard focus ring", "mobile navigation open"],
14093
+ materialEffects: ["soft depth on primary surfaces"],
14094
+ designVectors: {
14095
+ density: "editorial",
14096
+ imagery: "dominant first-viewport visual plane"
14097
+ }
14098
+ };
14099
+ var exampleIds = {
14100
+ canvasSessionId: "canvas-session-from-session-open",
14101
+ leaseId: "lease-from-session-open",
14102
+ documentId: "document-from-session-open"
14103
+ };
14104
+ var stringifyReceived = (value) => {
14105
+ if (typeof value === "string") return value;
14106
+ try {
14107
+ return JSON.stringify(value);
14108
+ } catch {
14109
+ return String(value);
14110
+ }
14111
+ };
14112
+ var toExpectedString = (value) => {
14113
+ if (Array.isArray(value)) return value.join(" | ");
14114
+ return value;
14115
+ };
14116
+ var commandForReason = (reasonCode, blockedCommand) => {
14117
+ const retryCommand = blockedCommand && blockedCommand !== "canvas.session.attach" ? blockedCommand : "canvas.plan.set";
14118
+ if (reasonCode === "missing_canvas_session_id") return ["canvas.session.open", retryCommand];
14119
+ if (reasonCode === "missing_lease_id") return ["canvas.session.attach", retryCommand];
14120
+ if (reasonCode === "missing_document_id") return ["canvas.document.load"];
14121
+ if (reasonCode === "governance_missing") return ["canvas.document.patch", "canvas.preview.render", "canvas.document.save"];
14122
+ return ["canvas.plan.set", "canvas.plan.get"];
14123
+ };
14124
+ var titleForReason = (reasonCode) => {
14125
+ if (reasonCode === "missing_canvas_session_id") return "Open a Canvas session before running this command.";
14126
+ if (reasonCode === "missing_lease_id") return "Attach to the Canvas session and include the active leaseId.";
14127
+ if (reasonCode === "missing_document_id") return "Load a Canvas document by documentId or repoPath before continuing.";
14128
+ if (reasonCode === "governance_missing") return "Patch missing governance blocks before mutation, preview, or save.";
14129
+ if (reasonCode === "plan_required") return "Submit a valid generationPlan before mutating the Canvas document.";
14130
+ return "Repair generationPlan and resubmit canvas.plan.set.";
14131
+ };
14132
+ var labelForCommand = (command) => {
14133
+ switch (command) {
14134
+ case "canvas.session.open":
14135
+ return "Open a Canvas session";
14136
+ case "canvas.session.attach":
14137
+ return "Attach or reclaim a Canvas lease";
14138
+ case "canvas.document.load":
14139
+ return "Load the target Canvas document";
14140
+ case "canvas.document.patch":
14141
+ return "Patch missing governance";
14142
+ case "canvas.plan.get":
14143
+ return "Inspect the current plan status";
14144
+ case "canvas.plan.set":
14145
+ return "Submit a valid generationPlan";
14146
+ default:
14147
+ return command.startsWith("canvas.") ? `Retry ${command}` : "Submit a valid generationPlan";
14148
+ }
14149
+ };
14150
+ var shellSingleQuote = (value) => `'${value.replaceAll("'", `'"'"'`)}'`;
14151
+ var inlineParamsFlag = (params) => ` --params ${shellSingleQuote(JSON.stringify(params))}`;
14152
+ var buildCanvasSessionParamsExample = () => ({
14153
+ canvasSessionId: exampleIds.canvasSessionId,
14154
+ leaseId: exampleIds.leaseId
14155
+ });
14156
+ var cliForCommand = (command) => {
14157
+ switch (command) {
14158
+ case "canvas.session.open":
14159
+ return "npx opendevbrowser canvas --command canvas.session.open --output-format json";
14160
+ case "canvas.session.attach":
14161
+ return `npx opendevbrowser canvas --command canvas.session.attach${inlineParamsFlag(buildAttachParamsExample())} --output-format json`;
14162
+ case "canvas.document.load":
14163
+ return `npx opendevbrowser canvas --command canvas.document.load${inlineParamsFlag(buildDocumentLoadParamsExample())} --output-format json`;
14164
+ case "canvas.document.patch":
14165
+ return `npx opendevbrowser canvas --command canvas.document.patch${inlineParamsFlag(buildCanvasGovernancePatchParamsExample())} --output-format json`;
14166
+ case "canvas.plan.get":
14167
+ return `npx opendevbrowser canvas --command canvas.plan.get${inlineParamsFlag(buildCanvasSessionParamsExample())} --output-format json`;
14168
+ case "canvas.plan.set":
14169
+ return `npx opendevbrowser canvas --command canvas.plan.set${inlineParamsFlag(buildCanvasPlanSetParamsExample())} --output-format json`;
14170
+ default:
14171
+ if (command.startsWith("canvas.")) {
14172
+ return `npx opendevbrowser canvas --command ${command}${inlineParamsFlag(buildCanvasSessionParamsExample())} --output-format json`;
14173
+ }
14174
+ return `npx opendevbrowser canvas --command canvas.plan.set${inlineParamsFlag(buildCanvasPlanSetParamsExample())} --output-format json`;
14175
+ }
14176
+ };
14177
+ var commandExamples = (reasonCode, blockedCommand) => {
14178
+ const commands = commandForReason(reasonCode, blockedCommand);
14179
+ return commands.map((command) => ({
14180
+ id: command.replaceAll(".", "-"),
14181
+ label: labelForCommand(command),
14182
+ command: cliForCommand(command)
14183
+ }));
14184
+ };
14185
+ var buildCanvasPlanSetParamsExample = () => ({
14186
+ canvasSessionId: exampleIds.canvasSessionId,
14187
+ leaseId: exampleIds.leaseId,
14188
+ generationPlan: EXAMPLE_CANVAS_GENERATION_PLAN
14189
+ });
14190
+ var buildCanvasGovernancePatchParamsExample = () => ({
14191
+ canvasSessionId: exampleIds.canvasSessionId,
14192
+ leaseId: exampleIds.leaseId,
14193
+ baseRevision: 1,
14194
+ patches: [{
14195
+ op: "governance.update",
14196
+ block: "intent",
14197
+ changes: {
14198
+ summary: "Create an evidence-backed landing page iteration for the current brief.",
14199
+ audience: "Primary product or service buyers",
14200
+ task: "Understand the offer and take the primary conversion action",
14201
+ successCriteria: [
14202
+ "Hero communicates the brand and offer without relying on navigation text",
14203
+ "Primary CTA is visible and keyboard reachable",
14204
+ "Desktop, tablet, and mobile layouts preserve content hierarchy"
14205
+ ]
14206
+ }
14207
+ }]
14208
+ });
14209
+ var buildDocumentLoadParamsExample = () => ({
14210
+ canvasSessionId: exampleIds.canvasSessionId,
14211
+ leaseId: exampleIds.leaseId,
14212
+ documentId: exampleIds.documentId
14213
+ });
14214
+ var buildAttachParamsExample = () => ({
14215
+ canvasSessionId: exampleIds.canvasSessionId,
14216
+ attachMode: "lease_reclaim"
14217
+ });
14218
+ var issuePriority = (issue) => {
14219
+ if (issue.code === "invalid_value") return 0;
14220
+ if (issue.code === "invalid_type") return 1;
14221
+ return 2;
14222
+ };
14223
+ var issueFieldExamples = (issues) => {
14224
+ const prioritizedIssues = [...issues].sort((left, right) => issuePriority(left) - issuePriority(right));
14225
+ return prioritizedIssues.slice(0, MAX_ISSUE_FIELD_EXAMPLES).map((issue) => ({
14226
+ path: `generationPlan.${issue.path}`,
14227
+ description: issue.message,
14228
+ example: readExampleForIssuePath(issue.path),
14229
+ ...issue.expected ? { expected: toExpectedString(issue.expected) } : {},
14230
+ ...typeof issue.received !== "undefined" ? { received: stringifyReceived(issue.received) } : {}
14231
+ }));
14232
+ };
14233
+ var readExampleForIssuePath = (path2) => {
14234
+ const segments = path2.split(".");
14235
+ let current = EXAMPLE_CANVAS_GENERATION_PLAN;
14236
+ for (const segment of segments) {
14237
+ if (!current || typeof current !== "object" || Array.isArray(current)) return "<valid value>";
14238
+ current = current[segment] ?? "<valid value>";
14239
+ }
14240
+ return current;
14241
+ };
14242
+ var normalizeGenerationPlanPath = (path2) => {
14243
+ const trimmed = path2.trim();
14244
+ return trimmed.startsWith("generationPlan.") ? trimmed.slice("generationPlan.".length) : trimmed;
14245
+ };
14246
+ var missingFieldExamples = (missingFields) => missingFields.map(normalizeGenerationPlanPath).filter((path2) => path2.length > 0).slice(0, MAX_ISSUE_FIELD_EXAMPLES).map((path2) => ({
14247
+ path: `generationPlan.${path2}`,
14248
+ description: `Provide generationPlan.${path2} before retrying canvas.plan.set.`,
14249
+ example: readExampleForIssuePath(path2),
14250
+ expected: "valid Canvas generation plan field"
14251
+ }));
14252
+ var baseFieldExamples = (reasonCode) => {
14253
+ if (reasonCode === "missing_canvas_session_id") {
14254
+ return [{
14255
+ path: "canvasSessionId",
14256
+ description: "Use the canvasSessionId returned by canvas.session.open.",
14257
+ example: exampleIds.canvasSessionId,
14258
+ expected: "non-empty string"
14259
+ }];
14260
+ }
14261
+ if (reasonCode === "missing_lease_id") {
14262
+ return [{
14263
+ path: "leaseId",
14264
+ description: "Use the active leaseId returned by canvas.session.open or canvas.session.attach.",
14265
+ example: exampleIds.leaseId,
14266
+ expected: "non-empty string"
14267
+ }];
14268
+ }
14269
+ if (reasonCode === "missing_document_id") {
14270
+ return [{
14271
+ path: "documentId",
14272
+ description: "Use documentId when loading a persisted Canvas document. Use repoPath instead when loading by file path.",
14273
+ example: exampleIds.documentId,
14274
+ expected: "non-empty string"
14275
+ }];
14276
+ }
14277
+ return [{
14278
+ path: "designGovernance.intent",
14279
+ description: "Patch intent before save or downstream handoff when governance warnings report missing intent.",
14280
+ example: {
14281
+ summary: "Create an evidence-backed landing page iteration for the current brief.",
14282
+ audience: "Primary product or service buyers",
14283
+ task: "Understand the offer and take the primary conversion action"
14284
+ }
14285
+ }];
14286
+ };
14287
+ var chooseFieldExamples = (reasonCode, issues, missingFields) => {
14288
+ const issueExamples = issueFieldExamples(issues);
14289
+ if (issueExamples.length > 0) return issueExamples;
14290
+ const missingExamples = missingFieldExamples(missingFields);
14291
+ if (missingExamples.length > 0) return missingExamples;
14292
+ return baseFieldExamples(reasonCode);
14293
+ };
14294
+ var paramsForCommand = (command) => {
14295
+ switch (command) {
14296
+ case "canvas.session.attach":
14297
+ return buildAttachParamsExample();
14298
+ case "canvas.document.load":
14299
+ return buildDocumentLoadParamsExample();
14300
+ case "canvas.document.patch":
14301
+ return buildCanvasGovernancePatchParamsExample();
14302
+ case "canvas.plan.get":
14303
+ return buildCanvasSessionParamsExample();
14304
+ case "canvas.plan.set":
14305
+ return buildCanvasPlanSetParamsExample();
14306
+ default:
14307
+ return command.startsWith("canvas.") ? buildCanvasSessionParamsExample() : null;
14308
+ }
14309
+ };
14310
+ var paramsExamples = (reasonCode, blockedCommand) => {
14311
+ const examples = [];
14312
+ if (reasonCode === "missing_lease_id") {
14313
+ examples.push({
14314
+ id: "canvas-attach-request",
14315
+ label: "Attach or reclaim a session lease",
14316
+ command: "canvas.session.attach",
14317
+ params: buildAttachParamsExample()
14318
+ });
14319
+ const blockedParams = blockedCommand ? paramsForCommand(blockedCommand) : null;
14320
+ if (blockedCommand && blockedCommand !== "canvas.session.attach" && blockedParams) {
14321
+ examples.push({
14322
+ id: `${blockedCommand.replaceAll(".", "-")}-request`,
14323
+ label: `Valid ${blockedCommand} params after lease recovery`,
14324
+ command: blockedCommand,
14325
+ params: blockedParams
14326
+ });
14327
+ return examples;
14328
+ }
14329
+ }
14330
+ if (reasonCode === "missing_document_id") {
14331
+ examples.push({
14332
+ id: "canvas-document-load-request",
14333
+ label: "Load a document by id",
14334
+ command: "canvas.document.load",
14335
+ params: buildDocumentLoadParamsExample()
14336
+ });
14337
+ return examples;
14338
+ }
14339
+ examples.push({
14340
+ id: "canvas-plan-set-request",
14341
+ label: "Valid canvas.plan.set params",
14342
+ command: "canvas.plan.set",
14343
+ params: buildCanvasPlanSetParamsExample()
14344
+ });
14345
+ if (reasonCode === "governance_missing") {
14346
+ examples.push({
14347
+ id: "canvas-governance-intent-patch",
14348
+ label: "Patch missing intent governance",
14349
+ command: "canvas.document.patch",
14350
+ params: buildCanvasGovernancePatchParamsExample()
14351
+ });
14352
+ }
14353
+ return examples;
14354
+ };
14355
+ var validationChecks = (reasonCode) => {
14356
+ const checks = [{
14357
+ id: "session-opened",
14358
+ description: "canvas.session.open or canvas.session.attach returns active ids before command retry.",
14359
+ assertion: 'typeof canvasSessionId === "string" && typeof leaseId === "string"'
14360
+ }];
14361
+ if (reasonCode !== "missing_document_id") {
14362
+ checks.push({
14363
+ id: "plan-valid",
14364
+ description: "generationPlan passes Canvas validation.",
14365
+ assertion: "validateGenerationPlan(generationPlan).ok === true"
14366
+ });
14367
+ } else {
14368
+ checks.push({
14369
+ id: "document-target-selected",
14370
+ description: "documentId or repoPath is present before loading a Canvas document.",
14371
+ assertion: 'typeof documentId === "string" || typeof repoPath === "string"'
14372
+ });
14373
+ }
14374
+ if (reasonCode === "governance_missing") {
14375
+ checks.push({
14376
+ id: "intent-present",
14377
+ description: "intent governance block is present after canvas.document.patch.",
14378
+ assertion: "designGovernance.intent is present"
14379
+ });
14380
+ }
14381
+ return checks;
14382
+ };
14383
+ var doNotProceedIf = (reasonCode) => {
14384
+ const blockers = [
14385
+ "canvasSessionId is missing or stale",
14386
+ "leaseId is missing or no longer active"
14387
+ ];
14388
+ if (reasonCode !== "missing_document_id") {
14389
+ blockers.push("generationPlan validation still reports missing or invalid fields");
14390
+ } else {
14391
+ blockers.push("documentId and repoPath are both missing");
14392
+ }
14393
+ if (reasonCode === "governance_missing") {
14394
+ blockers.push("intent or other required governance blocks are still missing");
14395
+ }
14396
+ return blockers;
14397
+ };
14398
+ var buildCanvasRepairGuidance = (input) => {
14399
+ const fields = chooseFieldExamples(input.reasonCode, input.issues ?? [], input.missingFields ?? []);
14400
+ const readiness = input.reasonCode === "governance_missing" ? "needs_recovery" : "needs_input";
14401
+ const severity = input.reasonCode === "governance_missing" ? "warning" : "blocked";
14402
+ return {
14403
+ id: `canvas.${input.reasonCode}`,
14404
+ recipeType: "schema_repair",
14405
+ workflow: "canvas",
14406
+ severity,
14407
+ readiness,
14408
+ reasonCode: input.reasonCode,
14409
+ primaryAction: {
14410
+ id: "repair_canvas_request",
14411
+ label: "Repair Canvas command params",
14412
+ summary: input.message ?? titleForReason(input.reasonCode)
14413
+ },
14414
+ commands: commandExamples(input.reasonCode, input.blockedCommand),
14415
+ paramsExamples: paramsExamples(input.reasonCode, input.blockedCommand),
14416
+ fieldExamples: fields,
14417
+ artifactInputs: [],
14418
+ validationChecks: validationChecks(input.reasonCode),
14419
+ fallbackPolicy: {
14420
+ allowed: false,
14421
+ requiresUserConfirmation: true,
14422
+ reason: "Do not skip Canvas validation or governance gates. Repair the typed command payload first."
14423
+ },
14424
+ doNotProceedIf: doNotProceedIf(input.reasonCode)
14425
+ };
14426
+ };
14427
+ var buildCanvasRepairEnvelope = (input) => {
14428
+ const guidance = buildCanvasRepairGuidance(input);
14429
+ const recommendedNextCommands = commandForReason(input.reasonCode, input.blockedCommand);
14430
+ const message = input.message ?? guidance.primaryAction.summary;
14431
+ const guidancePayload = {
14432
+ recommendedNextCommands,
14433
+ reason: message,
14434
+ nextStepGuidance: renderWorkflowGuidance(guidance),
14435
+ paramsExamples: guidance.paramsExamples,
14436
+ fieldExamples: guidance.fieldExamples,
14437
+ validationChecks: guidance.validationChecks,
14438
+ doNotProceedIf: guidance.doNotProceedIf
14439
+ };
14440
+ return {
14441
+ code: input.reasonCode,
14442
+ message,
14443
+ recommendedNextCommands,
14444
+ guidance: guidancePayload,
14445
+ nextStepGuidance: guidancePayload.nextStepGuidance,
14446
+ paramsExamples: guidancePayload.paramsExamples,
14447
+ fieldExamples: guidancePayload.fieldExamples,
14448
+ validationChecks: guidancePayload.validationChecks,
14449
+ doNotProceedIf: guidancePayload.doNotProceedIf
14450
+ };
14451
+ };
14452
+ var missingIdentifierReasonCode = (field) => {
14453
+ if (field === "canvasSessionId") return "missing_canvas_session_id";
14454
+ if (field === "leaseId") return "missing_lease_id";
14455
+ return "missing_document_id";
14456
+ };
14457
+ var SESSION_REQUIRED_COMMANDS = /* @__PURE__ */ new Set([
14458
+ "canvas.session.attach",
14459
+ "canvas.session.status",
14460
+ "canvas.session.close",
14461
+ "canvas.capabilities.get",
14462
+ "canvas.plan.set",
14463
+ "canvas.plan.get",
14464
+ "canvas.document.load",
14465
+ "canvas.document.import",
14466
+ "canvas.document.patch",
14467
+ "canvas.history.undo",
14468
+ "canvas.history.redo",
14469
+ "canvas.document.save",
14470
+ "canvas.document.export",
14471
+ "canvas.inventory.list",
14472
+ "canvas.inventory.insert",
14473
+ "canvas.starter.apply",
14474
+ "canvas.tab.open",
14475
+ "canvas.tab.close",
14476
+ "canvas.overlay.mount",
14477
+ "canvas.overlay.unmount",
14478
+ "canvas.overlay.select",
14479
+ "canvas.preview.render",
14480
+ "canvas.preview.refresh",
14481
+ "canvas.feedback.poll",
14482
+ "canvas.feedback.subscribe",
14483
+ "canvas.feedback.next",
14484
+ "canvas.feedback.unsubscribe",
14485
+ "canvas.code.bind",
14486
+ "canvas.code.unbind",
14487
+ "canvas.code.pull",
14488
+ "canvas.code.push",
14489
+ "canvas.code.status",
14490
+ "canvas.code.resolve"
14491
+ ]);
14492
+ var requiresCanvasSessionId = (command) => SESSION_REQUIRED_COMMANDS.has(command);
14493
+ var LEASE_REQUIRED_COMMANDS = /* @__PURE__ */ new Set([
14494
+ "canvas.session.close",
14495
+ "canvas.plan.set",
14496
+ "canvas.plan.get",
14497
+ "canvas.document.load",
14498
+ "canvas.document.import",
14499
+ "canvas.document.patch",
14500
+ "canvas.history.undo",
14501
+ "canvas.history.redo",
14502
+ "canvas.document.save",
14503
+ "canvas.document.export",
14504
+ "canvas.inventory.insert",
14505
+ "canvas.starter.apply",
14506
+ "canvas.tab.open",
14507
+ "canvas.tab.close",
14508
+ "canvas.overlay.mount",
14509
+ "canvas.overlay.unmount",
14510
+ "canvas.overlay.select",
14511
+ "canvas.preview.render",
14512
+ "canvas.preview.refresh",
14513
+ "canvas.code.bind",
14514
+ "canvas.code.unbind",
14515
+ "canvas.code.pull",
14516
+ "canvas.code.push",
14517
+ "canvas.code.resolve"
14518
+ ]);
14519
+ var requiresLeaseId = (command) => LEASE_REQUIRED_COMMANDS.has(command);
14520
+ var missingString = (params, field) => {
14521
+ const value = params[field];
14522
+ return typeof value !== "string" || value.trim().length === 0;
14523
+ };
14524
+ var buildCanvasCommandValidationEnvelope = (command, params) => {
14525
+ if (requiresCanvasSessionId(command) && missingString(params, "canvasSessionId")) {
14526
+ return buildCanvasMissingIdentifierEnvelope("canvasSessionId", command);
14527
+ }
14528
+ if (requiresLeaseId(command) && missingString(params, "leaseId")) {
14529
+ return buildCanvasMissingIdentifierEnvelope("leaseId", command);
14530
+ }
14531
+ const repoPath = params.repoPath;
14532
+ const hasRepoPath = typeof repoPath === "string" && repoPath.trim().length > 0;
14533
+ if (command === "canvas.document.load" && missingString(params, "documentId") && !hasRepoPath) {
14534
+ return buildCanvasMissingIdentifierEnvelope("documentId", command);
14535
+ }
14536
+ return null;
14537
+ };
14538
+ var buildCanvasMissingIdentifierEnvelope = (field, blockedCommand) => {
14539
+ const reasonCode = missingIdentifierReasonCode(field);
14540
+ return buildCanvasRepairEnvelope({
14541
+ reasonCode,
14542
+ ...blockedCommand ? { blockedCommand } : {},
14543
+ message: `Missing ${field}. ${titleForReason(reasonCode)}`
14544
+ });
14545
+ };
14546
+
14547
+ // src/guidance/recipes/generic.ts
14548
+ var quote = (value) => JSON.stringify(value);
14549
+ var DAEMON_STATUS_PREFLIGHT_COMMAND = "opendevbrowser status --daemon --output-format json";
14550
+ var DAEMON_FINGERPRINT_CURRENT_ASSERTION = "data.fingerprintCurrent === true";
14551
+ var DEFAULT_INSPIREDESIGN_BRIEF = "Digital photography studio landing page";
14552
+ var DEFAULT_INSPIREDESIGN_QUERY = "cinematic photography studio landing page inspiration";
14553
+ var DEFAULT_RESEARCH_TOPIC = "browser automation provider recovery";
14554
+ var DEFAULT_PROVIDER = "provider diagnostics";
14555
+ var DEFAULT_PINTEREST_REFERENCE_URL = "https://www.pinterest.com/pin/27654985208435505/";
14556
+ var isCanvasGenerationPlanIssue = (value) => {
14557
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
14558
+ const record = value;
14559
+ return typeof record.path === "string" && typeof record.message === "string" && typeof record.code === "string";
14560
+ };
14561
+ var canvasGenerationPlanIssues = (value) => Array.isArray(value) ? value.filter(isCanvasGenerationPlanIssue) : [];
14562
+ var isPinterestProvider = (provider) => provider === "social/pinterest" || provider === "pinterest";
14563
+ var isPinterestOnlyContext = (context) => {
14564
+ const providers = context.requestedProviders ?? [];
14565
+ return providers.length === 0 || providers.every(isPinterestProvider);
14566
+ };
14567
+ var selectedInspiredesignProvider = (context) => {
14568
+ const providers = context.requestedProviders ?? [];
14569
+ const nonPinterestProvider = providers.find((provider) => !isPinterestProvider(provider));
14570
+ if (!isPinterestOnlyContext(context) && nonPinterestProvider) return nonPinterestProvider;
14571
+ return providers[0] ?? context.siteRecipeId ?? "web/default";
14572
+ };
14573
+ var selectedProviderIsPinterest = (context) => isPinterestProvider(selectedInspiredesignProvider(context));
14574
+ var isPinterestScopedRecovery = (context) => context.siteRecipeId === "social/pinterest" && isPinterestOnlyContext(context);
14575
+ var inspiredesignBrowserMode = (context) => selectedProviderIsPinterest(context) ? "extension" : context.browserMode ?? "managed";
14576
+ var inspiredesignCookieFlags = (context) => {
14577
+ if (selectedProviderIsPinterest(context)) return " --use-cookies --cookie-policy required";
14578
+ return context.useCookies === true ? " --use-cookies" : "";
14579
+ };
14580
+ var pinterestRecoveryUrls = (context) => {
14581
+ if (!isPinterestScopedRecovery(context)) return [];
14582
+ const urls = context.referenceUrls ?? [];
14583
+ const canonicalUrls = urls.map(normalizePinterestReferenceUrl).filter((url) => url !== null);
14584
+ return [...new Set(canonicalUrls)];
14585
+ };
14586
+ var inspiredesignRecoveryExampleUrls = (context) => selectedProviderIsPinterest(context) ? [DEFAULT_PINTEREST_REFERENCE_URL] : ["https://example.com/usable-reference"];
14587
+ var inspiredesignHarvestCommand = (context) => {
14588
+ const brief = typeof context.details?.brief === "string" ? context.details.brief : DEFAULT_INSPIREDESIGN_BRIEF;
14589
+ const query = context.query ?? DEFAULT_INSPIREDESIGN_QUERY;
14590
+ const provider = selectedInspiredesignProvider(context);
14591
+ const browserMode = inspiredesignBrowserMode(context);
14592
+ const cookieFlags = inspiredesignCookieFlags(context);
14593
+ const urls = pinterestRecoveryUrls(context);
14594
+ if (urls.length > 0) {
14595
+ const urlFlags = urls.map((url) => `--url ${quote(url)}`).join(" ");
14596
+ return {
14597
+ id: "inspiredesign-harvest-url-recovery",
14598
+ label: "Recover Inspired Design harvest with explicit Pinterest URLs",
14599
+ command: `npx opendevbrowser inspiredesign harvest --brief ${quote(brief)} --provider social/pinterest ${urlFlags} --max-references 5 --visual-evidence required --browser-mode extension --use-cookies --cookie-policy required --challenge-automation-mode browser_with_helper --mode json --output-format json`
14600
+ };
14601
+ }
14602
+ return {
14603
+ id: "inspiredesign-harvest-rerun",
14604
+ label: "Rerun Inspired Design harvest with explicit evidence settings",
14605
+ command: `npx opendevbrowser inspiredesign harvest --brief ${quote(brief)} --query ${quote(query)} --provider ${provider} --max-references 5 --visual-evidence required --browser-mode ${browserMode}${cookieFlags} --challenge-automation-mode browser_with_helper --mode json --output-format json`
14606
+ };
14607
+ };
14608
+ var canvasSessionOpenCommand = {
14609
+ id: "canvas-session-open",
14610
+ label: "Open a Canvas session before submitting the plan",
14611
+ command: "npx opendevbrowser canvas --command canvas.session.open --output-format json"
14612
+ };
14613
+ var canvasPlanSetCommand = {
14614
+ id: "canvas-plan-set",
14615
+ label: "Submit the generated Canvas plan request after filling ids",
14616
+ command: "npx opendevbrowser canvas --command canvas.plan.set --params-file ./canvas-plan.request.json --output-format json"
14617
+ };
14618
+ var defaultFallbackPolicy = {
14619
+ allowed: false,
14620
+ requiresUserConfirmation: true,
14621
+ reason: "Do not widen provider or source scope without user confirmation."
14622
+ };
14623
+ var inspiredesignArtifacts = [
14624
+ { path: "advanced-brief.md", purpose: "Review the reference-first brief before design or implementation.", required: true },
14625
+ { path: "ranked-references.json", purpose: "Verify ranked evidence quality and rejected diagnostics.", required: true },
14626
+ { path: "visual-evidence.json", purpose: "Confirm screenshot metadata and warnings.", required: true },
14627
+ { path: "screenshot-index.json", purpose: "Confirm screenshot artifact paths exist before visual claims.", required: true }
14628
+ ];
14629
+ var requiresInspiredesignReferenceEvidence = (context) => context.evidence?.referenceEvidenceRequired !== false;
14630
+ var notReadyInspiredesignReasonCode = (context) => context.evidence?.topReferenceIntentMatched === false ? "off_brief_reference" : "weak_reference";
14631
+ var notReadyInspiredesignSummary = (reasonCode) => reasonCode === "off_brief_reference" ? "The workflow requested a design-ready handoff, but the top ranked reference is off brief for Canvas continuation." : "The workflow requested a design-ready handoff, but the evidence does not meet the ready threshold for Canvas continuation.";
14632
+ var buildReadyInspiredesignGuidance = (context, readiness) => {
14633
+ if (readiness !== "ready") {
14634
+ const reasonCode = notReadyInspiredesignReasonCode(context);
14635
+ return buildEvidenceRecoveryGuidance(
14636
+ context,
14637
+ readiness,
14638
+ reasonCode,
14639
+ reasonCode === "off_brief_reference" ? "Replace off-brief reference evidence" : "Strengthen reference evidence before Canvas",
14640
+ notReadyInspiredesignSummary(reasonCode)
14641
+ );
14642
+ }
14643
+ const referenceEvidenceRequired = requiresInspiredesignReferenceEvidence(context);
14644
+ const artifactInputs = referenceEvidenceRequired ? [...inspiredesignArtifacts, { path: "canvas-plan.request.json", purpose: "Runtime request body for canvas.plan.set.", required: true }] : [
14645
+ { path: "advanced-brief.md", purpose: "Review the brief-expanded design direction before Canvas.", required: true },
14646
+ { path: "design-contract.json", purpose: "Use the brief-derived Canvas governance contract.", required: true },
14647
+ { path: "canvas-plan.request.json", purpose: "Runtime request body for canvas.plan.set.", required: true }
14648
+ ];
14649
+ const validationChecks2 = referenceEvidenceRequired ? [{
14650
+ id: "plan-accepted",
14651
+ description: "canvas.plan.set returns planStatus=accepted before document mutation.",
14652
+ assertion: 'planStatus === "accepted"'
14653
+ }] : [{
14654
+ id: "brief-contract-accepted",
14655
+ description: "canvas.plan.set accepts the generated brief-only generationPlan before document mutation.",
14656
+ assertion: 'planStatus === "accepted"'
14657
+ }];
14658
+ const doNotProceedIf2 = referenceEvidenceRequired ? [
14659
+ "rankedReferences is empty",
14660
+ "screenshot paths are missing when visual evidence was required",
14661
+ "planStatus is not accepted"
14662
+ ] : [
14663
+ "advanced-brief.md or design-contract.json is missing",
14664
+ "planStatus is not accepted"
14665
+ ];
14666
+ return {
14667
+ id: "inspiredesign.canvas_ready_handoff",
14668
+ recipeType: "artifact_handoff",
14669
+ workflow: "inspiredesign",
14670
+ severity: "info",
14671
+ readiness,
14672
+ reasonCode: "design_ready",
14673
+ primaryAction: {
14674
+ id: "continue_in_canvas",
14675
+ label: "Continue in Canvas",
14676
+ summary: "Read the generated artifacts, open a Canvas session, fill canvas-plan.request.json ids, then submit canvas.plan.set."
14677
+ },
14678
+ commands: [canvasSessionOpenCommand, canvasPlanSetCommand],
14679
+ paramsExamples: [{
14680
+ id: "canvas-plan-request-ids",
14681
+ label: "Canvas plan request id placeholders to fill",
14682
+ command: "canvas.plan.set",
14683
+ params: {
14684
+ canvasSessionId: "<canvasSessionId from canvas.session.open>",
14685
+ leaseId: "<leaseId from canvas.session.open>",
14686
+ generationPlan: "<keep generated generationPlan object unchanged>"
14687
+ }
14688
+ }],
14689
+ fieldExamples: [{
14690
+ path: "intent",
14691
+ description: "Patch emitted governance blocks from design-contract.json after plan acceptance.",
14692
+ example: { audience: "Primary user", task: "Complete the design goal", successCriteria: ["Evidence-backed design direction is implemented"] }
14693
+ }],
14694
+ artifactInputs,
14695
+ validationChecks: validationChecks2,
14696
+ fallbackPolicy: {
14697
+ allowed: true,
14698
+ requiresUserConfirmation: false,
14699
+ reason: referenceEvidenceRequired ? "Canvas continuation is allowed because ranked reference evidence is ready." : "Canvas continuation is allowed because this brief-only run did not require reference evidence."
14700
+ },
14701
+ doNotProceedIf: doNotProceedIf2
14702
+ };
14703
+ };
14704
+ var buildDaemonFingerprintMismatchGuidance = (readiness) => ({
14705
+ id: "daemon.fingerprint_mismatch",
14706
+ recipeType: "workflow_entry",
14707
+ workflow: "daemon",
14708
+ severity: "blocked",
14709
+ readiness,
14710
+ reasonCode: "daemon_fingerprint_mismatch",
14711
+ primaryAction: {
14712
+ id: "verify_daemon_fingerprint",
14713
+ label: "Verify daemon fingerprint",
14714
+ summary: "Run the daemon status preflight and continue only when the running daemon matches the current opendevbrowser build."
14715
+ },
14716
+ commands: [{
14717
+ id: "daemon-status-preflight",
14718
+ label: "Check daemon fingerprint freshness",
14719
+ command: DAEMON_STATUS_PREFLIGHT_COMMAND
14720
+ }],
14721
+ paramsExamples: [],
14722
+ fieldExamples: [{
14723
+ path: "data.fingerprintCurrent",
14724
+ description: "The daemon status response must report the current build fingerprint.",
14725
+ example: true,
14726
+ expected: "true"
14727
+ }],
14728
+ artifactInputs: [],
14729
+ validationChecks: [{
14730
+ id: "fingerprint-current",
14731
+ description: "Daemon status confirms the binary and daemon fingerprint match.",
14732
+ assertion: DAEMON_FINGERPRINT_CURRENT_ASSERTION,
14733
+ command: DAEMON_STATUS_PREFLIGHT_COMMAND
14734
+ }],
14735
+ fallbackPolicy: {
14736
+ allowed: true,
14737
+ requiresUserConfirmation: false,
14738
+ reason: "Use the matching binary, restart the daemon from the current install, or isolate config, cache, daemon port, and relay port."
14739
+ },
14740
+ doNotProceedIf: [
14741
+ "data.fingerprintCurrent is false or missing",
14742
+ "the daemon is still running a different opendevbrowser build"
14743
+ ]
14744
+ });
14745
+ var buildResearchGatedProviderGuidance = (context, readiness) => {
14746
+ const topic = typeof context.details?.topic === "string" ? context.details.topic : DEFAULT_RESEARCH_TOPIC;
14747
+ const browserMode = context.browserMode ?? "extension";
14748
+ const cookieFlag = context.useCookies === true ? " --use-cookies" : "";
14749
+ const providers = context.requestedProviders?.length ? context.requestedProviders.join(", ") : "gated providers";
14750
+ return {
14751
+ id: "research.gated_provider_recovery",
14752
+ recipeType: "evidence_recovery",
14753
+ workflow: "research",
14754
+ severity: "warning",
14755
+ readiness,
14756
+ reasonCode: "gated_provider",
14757
+ primaryAction: {
14758
+ id: "recover_gated_provider_evidence",
14759
+ label: "Recover gated provider evidence",
14760
+ summary: `Inspect gated-provider diagnostics for ${providers}, then rerun research with a user-authorized signed-in browser session before publishing claims.`
14761
+ },
14762
+ commands: [{
14763
+ id: "research-gated-provider-rerun",
14764
+ label: "Rerun research with browser-scoped provider recovery",
14765
+ command: `npx opendevbrowser research run --topic ${quote(topic)} --days 14 --sources web,community --browser-mode ${browserMode}${cookieFlag} --challenge-automation-mode browser_with_helper --mode json --output-format json`
14766
+ }],
14767
+ paramsExamples: [{
14768
+ id: "research-gated-provider-input",
14769
+ label: "Research gated-provider retry input",
14770
+ params: {
14771
+ topic,
14772
+ browserMode,
14773
+ useCookies: context.useCookies === true,
14774
+ challengeAutomationMode: "browser_with_helper",
14775
+ providers
14776
+ }
14777
+ }],
14778
+ fieldExamples: [{
14779
+ path: "meta.failures[].error.reasonCode",
14780
+ description: "Gated provider failures should identify auth or challenge reason codes before retry.",
14781
+ example: "auth_required"
14782
+ }],
14783
+ artifactInputs: [
14784
+ { path: "records.json", purpose: "Confirm destination records support claims.", required: true },
14785
+ { path: "context.json", purpose: "Inspect source and timebox context.", required: true },
14786
+ { path: "meta.json", purpose: "Review failures, cookie diagnostics, and challenge orchestration metadata.", required: true },
14787
+ { path: "report.md", purpose: "Publish only claims supported by accepted records.", required: true }
14788
+ ],
14789
+ validationChecks: [
14790
+ { id: "signed-in-session", description: "Provider auth or challenge state has been resolved in the browser session." },
14791
+ { id: "records-supported", description: "Final claims are supported by destination records, not SERP snippets." }
14792
+ ],
14793
+ fallbackPolicy: {
14794
+ allowed: false,
14795
+ requiresUserConfirmation: true,
14796
+ reason: "Do not switch sources or publish unsupported claims without user approval."
14797
+ },
14798
+ doNotProceedIf: [
14799
+ "gated provider failures remain unresolved",
14800
+ "records.json lacks destination evidence for the claim",
14801
+ "cookie or challenge recovery has not been user-authorized"
14802
+ ]
14803
+ };
14804
+ };
14805
+ var buildProviderWorkflowGuidance = (context, readiness) => {
14806
+ const providers = context.requestedProviders?.join(", ") || DEFAULT_PROVIDER;
14807
+ const reasonCode = context.reasonCode ?? "provider_recovery";
14808
+ return {
14809
+ id: `provider.${reasonCode}`,
14810
+ recipeType: "evidence_recovery",
14811
+ workflow: "provider",
14812
+ severity: readiness === "blocked" ? "blocked" : "warning",
14813
+ readiness,
14814
+ reasonCode,
14815
+ primaryAction: {
14816
+ id: "inspect_provider_diagnostics",
14817
+ label: "Inspect provider diagnostics",
14818
+ summary: "Use the typed failure details to resolve auth, challenge, availability, or evidence-quality blockers before widening provider scope."
14819
+ },
14820
+ commands: [{
14821
+ id: "provider-diagnostic-rerun",
14822
+ label: "Show executable workflow help before rerunning",
14823
+ command: "npx opendevbrowser help"
14824
+ }],
14825
+ paramsExamples: [{
14826
+ id: "provider-recovery-input",
14827
+ label: "Provider recovery input",
14828
+ params: {
14829
+ providers,
14830
+ reasonCode,
14831
+ browserMode: context.browserMode ?? "extension",
14832
+ useCookies: context.useCookies === true
14833
+ }
14834
+ }],
14835
+ fieldExamples: [{
14836
+ path: "meta.failures[].error.reasonCode",
14837
+ description: "Use the provider reason code to choose auth, challenge, availability, or evidence recovery.",
14838
+ example: reasonCode
14839
+ }],
14840
+ artifactInputs: [
14841
+ { path: "meta.json", purpose: "Inspect provider diagnostics and reason codes.", required: true },
14842
+ { path: "records.json", purpose: "Confirm accepted destination records before using results.", required: true }
14843
+ ],
14844
+ validationChecks: [{
14845
+ id: "provider-evidence-ready",
14846
+ description: "At least one accepted record supports the workflow output before proceeding."
14847
+ }],
14848
+ fallbackPolicy: defaultFallbackPolicy,
14849
+ doNotProceedIf: [
14850
+ "provider failure reason codes remain unresolved",
14851
+ "accepted records are empty",
14852
+ "the requested provider scope would be widened without user confirmation"
14853
+ ]
14854
+ };
14855
+ };
14856
+ var buildCliValidationGuidance = (context, readiness) => {
14857
+ const reasonCode = context.reasonCode ?? "validation_error";
14858
+ return {
14859
+ id: `cli.${reasonCode}`,
14860
+ recipeType: "schema_repair",
14861
+ workflow: "cli",
14862
+ severity: "blocked",
14863
+ readiness,
14864
+ reasonCode,
14865
+ primaryAction: {
14866
+ id: "repair_cli_arguments",
14867
+ label: "Repair CLI arguments",
14868
+ summary: "Use the command help and typed error details to rerun with valid flags, params, and output mode."
14869
+ },
14870
+ commands: [{
14871
+ id: "cli-help",
14872
+ label: "Show command help",
14873
+ command: "npx opendevbrowser help"
14874
+ }],
14875
+ paramsExamples: [{
14876
+ id: "cli-validation-input",
14877
+ label: "CLI validation retry",
14878
+ params: {
14879
+ reasonCode,
14880
+ outputFormat: "json"
14881
+ }
14882
+ }],
14883
+ fieldExamples: [{
14884
+ path: "error.reasonCode",
14885
+ description: "The reason code identifies which CLI argument or params field must be repaired.",
14886
+ example: reasonCode
14887
+ }],
14888
+ artifactInputs: [],
14889
+ validationChecks: [{
14890
+ id: "json-output",
14891
+ description: "Rerun the command with --output-format json and verify the response has no validation errors."
14892
+ }],
14893
+ fallbackPolicy: {
14894
+ allowed: true,
14895
+ requiresUserConfirmation: false,
14896
+ reason: "Help output and typed examples are the supported recovery path for invalid CLI input."
14897
+ },
14898
+ doNotProceedIf: [
14899
+ "the command still returns validation errors",
14900
+ "required params are missing or empty"
14901
+ ]
14902
+ };
14903
+ };
14904
+ var buildEvidenceRecoveryGuidance = (context, readiness, reasonCode, actionLabel, actionSummary) => ({
14905
+ id: `inspiredesign.harvest.${reasonCode}`,
14906
+ recipeType: "evidence_recovery",
14907
+ workflow: "inspiredesign",
14908
+ severity: readiness === "blocked" ? "blocked" : "warning",
14909
+ readiness,
14910
+ reasonCode,
14911
+ primaryAction: {
14912
+ id: "recover_reference_evidence",
14913
+ label: actionLabel,
14914
+ summary: actionSummary
14915
+ },
14916
+ commands: [inspiredesignHarvestCommand(context)],
14917
+ paramsExamples: [{
14918
+ id: "explicit-reference-url-recovery",
14919
+ label: "Use explicit high-quality visual references when provider discovery is blocked",
14920
+ params: {
14921
+ brief: typeof context.details?.brief === "string" ? context.details.brief : DEFAULT_INSPIREDESIGN_BRIEF,
14922
+ urls: inspiredesignRecoveryExampleUrls(context),
14923
+ visualEvidence: "required",
14924
+ browserMode: inspiredesignBrowserMode(context),
14925
+ ...selectedProviderIsPinterest(context) ? { useCookies: true, cookiePolicy: "required" } : {}
14926
+ }
14927
+ }],
14928
+ fieldExamples: [],
14929
+ artifactInputs: inspiredesignArtifacts.map((artifact) => ({ ...artifact, required: false })),
14930
+ validationChecks: [
14931
+ { id: "ranked-reference-count", description: "At least one ranked reference is present.", assertion: "rankedReferences.length > 0" },
14932
+ { id: "reference-score", description: "The top reference score meets the ready threshold.", assertion: "topReferenceScore >= 50" },
14933
+ { id: "reference-intent", description: "The top ranked reference overlaps the requested brief intent.", assertion: "topReferenceIntentMatched === true" },
14934
+ { id: "visual-artifact", description: "Required visual evidence has finalized screenshot paths.", assertion: "missingScreenshotCount === 0" }
14935
+ ],
14936
+ fallbackPolicy: defaultFallbackPolicy,
14937
+ doNotProceedIf: [
14938
+ "reference_count is 0",
14939
+ "rankedReferences is empty",
14940
+ "top ranked reference is diagnostic-only or off brief",
14941
+ "required visual evidence is missing or failed"
14942
+ ]
14943
+ });
14944
+ var genericGuidanceRecipes = [
14945
+ {
14946
+ id: "provider.generic_recovery",
14947
+ recipeType: "evidence_recovery",
14948
+ workflow: "provider",
14949
+ priority: 130,
14950
+ reasonCode: "provider_recovery",
14951
+ matches: (context) => context.workflow === "provider",
14952
+ build: buildProviderWorkflowGuidance
14953
+ },
14954
+ {
14955
+ id: "cli.validation_recovery",
14956
+ recipeType: "schema_repair",
14957
+ workflow: "cli",
14958
+ priority: 125,
14959
+ reasonCode: "validation_error",
14960
+ matches: (context) => context.workflow === "cli",
14961
+ build: buildCliValidationGuidance
14962
+ },
14963
+ {
14964
+ id: "daemon.fingerprint_mismatch",
14965
+ recipeType: "workflow_entry",
14966
+ workflow: "daemon",
14967
+ priority: 120,
14968
+ reasonCode: "daemon_fingerprint_mismatch",
14969
+ matches: (context) => context.workflow === "daemon" && context.reasonCode === "daemon_fingerprint_mismatch",
14970
+ build: (_context, readiness) => buildDaemonFingerprintMismatchGuidance(readiness)
14971
+ },
14972
+ {
14973
+ id: "research.gated_provider",
14974
+ recipeType: "evidence_recovery",
14975
+ workflow: "research",
14976
+ priority: 110,
14977
+ reasonCode: "gated_provider",
14978
+ matches: (context) => context.workflow === "research" && context.reasonCode === "gated_provider",
14979
+ build: buildResearchGatedProviderGuidance
14980
+ },
14981
+ {
14982
+ id: "canvas.generation_plan_invalid",
14983
+ recipeType: "schema_repair",
14984
+ workflow: "canvas",
14985
+ priority: 100,
14986
+ reasonCode: "generation_plan_invalid",
14987
+ matches: (context) => context.workflow === "canvas" && context.reasonCode === "generation_plan_invalid",
14988
+ build: (context) => buildCanvasRepairGuidance({
14989
+ reasonCode: "generation_plan_invalid",
14990
+ missingFields: Array.isArray(context.details?.missingFields) ? context.details.missingFields.filter((field) => typeof field === "string") : [],
14991
+ issues: canvasGenerationPlanIssues(context.details?.issues)
14992
+ })
14993
+ },
14994
+ {
14995
+ id: "canvas.plan_required",
14996
+ recipeType: "schema_repair",
14997
+ workflow: "canvas",
14998
+ priority: 90,
14999
+ reasonCode: "plan_required",
15000
+ matches: (context) => context.workflow === "canvas" && context.reasonCode === "plan_required",
15001
+ build: () => buildCanvasRepairGuidance({ reasonCode: "plan_required" })
15002
+ },
15003
+ {
15004
+ id: "canvas.governance_missing",
15005
+ recipeType: "schema_repair",
15006
+ workflow: "canvas",
15007
+ priority: 80,
15008
+ reasonCode: "governance_missing",
15009
+ matches: (context) => context.workflow === "canvas" && context.reasonCode === "governance_missing",
15010
+ build: () => buildCanvasRepairGuidance({ reasonCode: "governance_missing" })
15011
+ },
15012
+ {
15013
+ id: "canvas.missing_canvas_session_id",
15014
+ recipeType: "schema_repair",
15015
+ workflow: "canvas",
15016
+ priority: 70,
15017
+ reasonCode: "missing_canvas_session_id",
15018
+ matches: (context) => context.workflow === "canvas" && context.reasonCode === "missing_canvas_session_id",
15019
+ build: () => buildCanvasRepairGuidance({ reasonCode: "missing_canvas_session_id" })
15020
+ },
15021
+ {
15022
+ id: "canvas.missing_lease_id",
15023
+ recipeType: "schema_repair",
15024
+ workflow: "canvas",
15025
+ priority: 60,
15026
+ reasonCode: "missing_lease_id",
15027
+ matches: (context) => context.workflow === "canvas" && context.reasonCode === "missing_lease_id",
15028
+ build: () => buildCanvasRepairGuidance({ reasonCode: "missing_lease_id" })
15029
+ },
15030
+ {
15031
+ id: "canvas.missing_document_id",
15032
+ recipeType: "schema_repair",
15033
+ workflow: "canvas",
15034
+ priority: 50,
15035
+ reasonCode: "missing_document_id",
15036
+ matches: (context) => context.workflow === "canvas" && context.reasonCode === "missing_document_id",
15037
+ build: () => buildCanvasRepairGuidance({ reasonCode: "missing_document_id" })
15038
+ },
15039
+ {
15040
+ id: "inspiredesign.pinterest.browser_native_recovery",
15041
+ recipeType: "site_navigation",
15042
+ workflow: "inspiredesign",
15043
+ priority: 100,
15044
+ reasonCode: "pinterest_browser_native_recovery",
15045
+ matches: (context) => context.workflow === "inspiredesign" && isPinterestScopedRecovery(context) && context.reasonCode !== "design_ready",
15046
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15047
+ context,
15048
+ readiness,
15049
+ "pinterest_browser_native_recovery",
15050
+ "Recover Pinterest evidence in an authenticated browser session",
15051
+ "Use the Pinterest browser-native recipe to verify login, search the brief on Pinterest, collect usable pins or boards, and reject login, challenge, empty-grid, and search-shell pages before Canvas."
15052
+ )
15053
+ },
15054
+ {
15055
+ id: "inspiredesign.provider_unavailable",
15056
+ recipeType: "evidence_recovery",
15057
+ workflow: "inspiredesign",
15058
+ priority: 90,
15059
+ reasonCode: "provider_unavailable",
15060
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "provider_unavailable",
15061
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15062
+ context,
15063
+ readiness,
15064
+ "provider_unavailable",
15065
+ "Recover provider evidence",
15066
+ "Resolve the requested provider lane or supply explicit usable reference URLs before continuing to Canvas."
15067
+ )
15068
+ },
15069
+ {
15070
+ id: "inspiredesign.diagnostic_only",
15071
+ recipeType: "quality_gate",
15072
+ workflow: "inspiredesign",
15073
+ priority: 80,
15074
+ reasonCode: "diagnostic_only",
15075
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "diagnostic_only",
15076
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15077
+ context,
15078
+ readiness,
15079
+ "diagnostic_only",
15080
+ "Replace diagnostic references",
15081
+ "The harvest captured diagnostic or blocked pages. Replace them with usable creative references before Canvas."
15082
+ )
15083
+ },
15084
+ {
15085
+ id: "inspiredesign.zero_references",
15086
+ recipeType: "evidence_recovery",
15087
+ workflow: "inspiredesign",
15088
+ priority: 70,
15089
+ reasonCode: "zero_references",
15090
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "zero_references",
15091
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15092
+ context,
15093
+ readiness,
15094
+ "zero_references",
15095
+ "Collect reference evidence",
15096
+ "The harvest produced no references. Run source-specific discovery or provide explicit URLs before Canvas."
15097
+ )
15098
+ },
15099
+ {
15100
+ id: "inspiredesign.failed_capture",
15101
+ recipeType: "evidence_recovery",
15102
+ workflow: "inspiredesign",
15103
+ priority: 60,
15104
+ reasonCode: "failed_capture",
15105
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "failed_capture",
15106
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15107
+ context,
15108
+ readiness,
15109
+ "failed_capture",
15110
+ "Retry capture with a usable browser session",
15111
+ "Deep capture or required visual evidence failed. Restore session state or use explicit references with capturable pages."
15112
+ )
15113
+ },
15114
+ {
15115
+ id: "inspiredesign.zero_ranked_references",
15116
+ recipeType: "evidence_recovery",
15117
+ workflow: "inspiredesign",
15118
+ priority: 55,
15119
+ reasonCode: "zero_ranked_references",
15120
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "zero_ranked_references",
15121
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15122
+ context,
15123
+ readiness,
15124
+ "zero_ranked_references",
15125
+ "Replace rejected reference evidence",
15126
+ "The harvest captured references, but none survived scoring. Replace rejected, off-brief, blocked, or diagnostic pages before Canvas."
15127
+ )
15128
+ },
15129
+ {
15130
+ id: "inspiredesign.off_brief_reference",
15131
+ recipeType: "quality_gate",
15132
+ workflow: "inspiredesign",
15133
+ priority: 52,
15134
+ reasonCode: "off_brief_reference",
15135
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "off_brief_reference",
15136
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15137
+ context,
15138
+ readiness,
15139
+ "off_brief_reference",
15140
+ "Replace off-brief reference evidence",
15141
+ "The top ranked reference is captured, but its signals do not overlap the requested brief. Replace it with on-brief references before Canvas."
15142
+ )
15143
+ },
15144
+ {
15145
+ id: "inspiredesign.weak_reference",
15146
+ recipeType: "quality_gate",
15147
+ workflow: "inspiredesign",
15148
+ priority: 50,
15149
+ reasonCode: "weak_reference",
15150
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "weak_reference",
15151
+ build: (context, readiness) => buildEvidenceRecoveryGuidance(
15152
+ context,
15153
+ readiness,
15154
+ "weak_reference",
15155
+ "Strengthen weak reference evidence",
15156
+ "The harvest has ranked references, but their score or confidence is too weak for Canvas-first design handoff."
15157
+ )
15158
+ },
15159
+ {
15160
+ id: "inspiredesign.ready",
15161
+ recipeType: "artifact_handoff",
15162
+ workflow: "inspiredesign",
15163
+ priority: 1,
15164
+ reasonCode: "design_ready",
15165
+ matches: (context) => context.workflow === "inspiredesign" && context.reasonCode === "design_ready",
15166
+ build: buildReadyInspiredesignGuidance
15167
+ }
15168
+ ];
15169
+
15170
+ // src/guidance/router.ts
15171
+ var byPriority = (left, right) => {
15172
+ return right.priority - left.priority || left.id.localeCompare(right.id);
15173
+ };
15174
+ var GuidanceRouter = class {
15175
+ recipes;
15176
+ constructor(recipes = genericGuidanceRecipes) {
15177
+ this.recipes = recipes.slice().sort(byPriority);
15178
+ }
15179
+ route(context) {
15180
+ const readiness = classifyGuidanceReadiness(context);
15181
+ const recipe = this.recipes.find((candidate) => candidate.matches(context));
15182
+ if (!recipe) {
15183
+ throw new Error(`No guidance recipe matched workflow ${context.workflow}.`);
15184
+ }
15185
+ return recipe.build(context, readiness);
15186
+ }
15187
+ };
15188
+ var routeNextStepGuidance = (context) => {
15189
+ return new GuidanceRouter().route(context);
15190
+ };
15191
+
13508
15192
  // src/providers/workflow-handoff.ts
13509
15193
  var PRODUCT_VIDEO_BRIEF_HELPER_PATH = "./skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh";
13510
15194
  var PRODUCT_VIDEO_BRIEF_HELPER_COMMAND = `${PRODUCT_VIDEO_BRIEF_HELPER_PATH} <pack>/manifest.json`;
@@ -13513,7 +15197,7 @@ var createSuccessHandoff = (followthroughSummary, suggestedNextAction, suggested
13513
15197
  suggestedNextAction,
13514
15198
  suggestedSteps
13515
15199
  });
13516
- var cliExample = (command, args = "") => `npx opendevbrowser ${command}${args ? ` ${args}` : ""}`;
15200
+ var cliExample = (command, args) => `npx opendevbrowser ${command} ${args}`;
13517
15201
  var quoteCliValue = (value) => JSON.stringify(value);
13518
15202
  var GATED_PROVIDER_REASON_CODES = /* @__PURE__ */ new Set([
13519
15203
  "auth_required",
@@ -13643,6 +15327,10 @@ var buildProductVideoRerunCommand = (input = {}) => {
13643
15327
  `${target}${providerHint}${screenshots}${allImages}${includeCopy}${browserMode} --use-cookies --challenge-automation-mode browser_with_helper --output-format json`
13644
15328
  );
13645
15329
  };
15330
+ var extractPrimaryConstraintSentence = (summary) => {
15331
+ const match = /^Primary constraint:\s+(.+?\.)\s/.exec(summary);
15332
+ return match?.[1] ?? null;
15333
+ };
13646
15334
  var buildMacroResolveArgs = (input, options) => {
13647
15335
  const defaultProvider = input.defaultProvider ? ` --default-provider ${input.defaultProvider}` : "";
13648
15336
  const execute = options?.execute ? " --execute" : "";
@@ -13650,7 +15338,7 @@ var buildMacroResolveArgs = (input, options) => {
13650
15338
  const useCookies = options?.useCookies ? " --use-cookies" : "";
13651
15339
  const challenge = options?.challengeAutomationMode ? ` --challenge-automation-mode ${options.challengeAutomationMode}` : "";
13652
15340
  const cookiePolicy = options?.cookiePolicyOverride ? ` --cookie-policy ${options.cookiePolicyOverride}` : "";
13653
- const outputFormat = options?.includeOutputFormat === false ? "" : " --output-format json";
15341
+ const outputFormat = " --output-format json";
13654
15342
  return `--expression ${quoteCliValue(input.expression)}${defaultProvider}${execute}${browserMode}${useCookies}${cookiePolicy}${challenge}${outputFormat}`;
13655
15343
  };
13656
15344
  var buildMacroPreviewCommand = (input) => cliExample("macro-resolve", buildMacroResolveArgs(input));
@@ -13664,7 +15352,7 @@ var buildResearchGatedSuccessHandoff = (input, signal) => {
13664
15352
  const recoveryCommand = buildResearchRecoveryRerunCommand(input, signal);
13665
15353
  const providers = signal.providers.length > 0 ? signal.providers.join(", ") : "gated providers";
13666
15354
  const cookieNote = signal.useCookies ? " The command includes --use-cookies because cookie diagnostics show available cookies." : " Add --use-cookies only when legitimate provider cookies are available.";
13667
- return createSuccessHandoff(
15355
+ const handoff = createSuccessHandoff(
13668
15356
  `Review ranked records, artifact metadata, and gated-provider diagnostics for ${providers} before publishing claims.`,
13669
15357
  `Open the returned artifact path, inspect records.json, context.json, meta.json, and report.md, then rerun ${recoveryCommand} only with a user-authorized signed-in relay session.${cookieNote}`,
13670
15358
  [
@@ -13676,6 +15364,21 @@ var buildResearchGatedSuccessHandoff = (input, signal) => {
13676
15364
  { reason: "Keep SERPs discovery-only and publish only claims supported by destination records that passed review." }
13677
15365
  ]
13678
15366
  );
15367
+ const guidance = routeNextStepGuidance({
15368
+ workflow: "research",
15369
+ reasonCode: "gated_provider",
15370
+ requestedProviders: signal.providers,
15371
+ browserMode: "extension",
15372
+ useCookies: signal.useCookies,
15373
+ details: {
15374
+ topic: input.topic,
15375
+ reasonCodes: signal.reasonCodes
15376
+ }
15377
+ });
15378
+ return {
15379
+ ...handoff,
15380
+ nextStepGuidance: renderWorkflowGuidance(guidance)
15381
+ };
13679
15382
  };
13680
15383
  var buildResearchDefaultSuccessHandoff = (input) => {
13681
15384
  const rerunCommand = buildResearchRerunCommand(input);
@@ -13764,31 +15467,43 @@ var buildMacroResolveSuccessHandoff = (input) => {
13764
15467
  ]
13765
15468
  );
13766
15469
  };
13767
- var buildInspiredesignSuccessHandoff = (input) => createSuccessHandoff(
13768
- input.summary,
13769
- input.nextStep,
13770
- [
13771
- { reason: INSPIREDESIGN_HANDOFF_GUIDANCE.reviewAdvancedBrief },
13772
- {
13773
- reason: "Load the baseline workflow runbook before implementation.",
13774
- command: input.commandExamples.loadBestPractices
13775
- },
13776
- {
13777
- reason: "Load the Canvas contract lane before patching.",
13778
- command: input.commandExamples.loadDesignAgent
13779
- },
13780
- {
13781
- reason: "Load the motion-design lane before translating visual evidence into animation, timing, or reduced-motion behavior.",
13782
- command: input.commandExamples.loadMotionDesign
13783
- },
13784
- { reason: INSPIREDESIGN_HANDOFF_GUIDANCE.visualArtifactRecommendation },
13785
- {
13786
- reason: INSPIREDESIGN_HANDOFF_GUIDANCE.prepareCanvasPlanRequest,
13787
- command: input.commandExamples.continueInCanvas
13788
- },
13789
- { reason: input.deepCaptureRecommendation }
13790
- ]
13791
- );
15470
+ var buildInspiredesignSuccessHandoff = (input) => {
15471
+ if (input.nextStepGuidance && input.nextStepGuidance.readiness !== "ready") {
15472
+ const primaryConstraint = extractPrimaryConstraintSentence(input.summary);
15473
+ const summary = primaryConstraint ? `Primary constraint: ${primaryConstraint} ${input.nextStepGuidance.primaryAction.summary}` : void 0;
15474
+ const compatibility = renderWorkflowCompatibility(input.nextStepGuidance, summary);
15475
+ return {
15476
+ ...compatibility,
15477
+ nextStepGuidance: renderWorkflowGuidance(input.nextStepGuidance)
15478
+ };
15479
+ }
15480
+ const handoff = createSuccessHandoff(
15481
+ input.summary,
15482
+ input.nextStep,
15483
+ [
15484
+ { reason: INSPIREDESIGN_HANDOFF_GUIDANCE.reviewAdvancedBrief },
15485
+ {
15486
+ reason: "Load the baseline workflow runbook before implementation.",
15487
+ command: input.commandExamples.loadBestPractices
15488
+ },
15489
+ {
15490
+ reason: "Load the Canvas contract lane before patching.",
15491
+ command: input.commandExamples.loadDesignAgent
15492
+ },
15493
+ {
15494
+ reason: "Load the motion-design lane before translating visual evidence into animation, timing, or reduced-motion behavior.",
15495
+ command: input.commandExamples.loadMotionDesign
15496
+ },
15497
+ { reason: INSPIREDESIGN_HANDOFF_GUIDANCE.visualArtifactRecommendation },
15498
+ {
15499
+ reason: INSPIREDESIGN_HANDOFF_GUIDANCE.prepareCanvasPlanRequest,
15500
+ command: input.commandExamples.continueInCanvas
15501
+ },
15502
+ { reason: input.deepCaptureRecommendation }
15503
+ ]
15504
+ );
15505
+ return input.nextStepGuidance ? { ...handoff, nextStepGuidance: renderWorkflowGuidance(input.nextStepGuidance) } : handoff;
15506
+ };
13792
15507
 
13793
15508
  // src/providers/renderer.ts
13794
15509
  var toCurrency = (value) => `$${value.toFixed(2)}`;
@@ -13893,6 +15608,86 @@ var researchFailureMessage = (content) => boundedInlineText({
13893
15608
  limit: RESEARCH_REPORT_LIMITS.failureMessageCharacters,
13894
15609
  target: "meta.json"
13895
15610
  });
15611
+ var CANVAS_CONTINUATION_BLOCKED_COMMAND = "Unavailable until nextStepGuidance.readiness is ready.";
15612
+ var CANVAS_PLAN_OMITTED_GUIDANCE = "Canvas plan request omitted until nextStepGuidance.readiness is ready.";
15613
+ var canContinueInspiredesignInCanvas = (guidance) => guidance?.readiness === "ready";
15614
+ var scrubCanvasPlanReference = (value) => value.includes(INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest) ? CANVAS_PLAN_OMITTED_GUIDANCE : value;
15615
+ var scrubGuideEntryCanvasReferences = (entry) => ({
15616
+ ...entry,
15617
+ expectedContents: entry.expectedContents.map(scrubCanvasPlanReference),
15618
+ howToUse: entry.howToUse.map(scrubCanvasPlanReference),
15619
+ mustNot: entry.mustNot.map(scrubCanvasPlanReference)
15620
+ });
15621
+ var scrubArtifactGuideCanvasReferences = (guide) => {
15622
+ const scrubbed = {};
15623
+ for (const [key, entry] of Object.entries(guide)) {
15624
+ if (entry) {
15625
+ scrubbed[key] = scrubGuideEntryCanvasReferences(entry);
15626
+ }
15627
+ }
15628
+ return scrubbed;
15629
+ };
15630
+ var scrubContractSectionGuideCanvasReferences = (guide) => {
15631
+ const scrubbed = {};
15632
+ for (const [key, entry] of Object.entries(guide)) {
15633
+ scrubbed[key] = scrubGuideEntryCanvasReferences(entry);
15634
+ }
15635
+ return scrubbed;
15636
+ };
15637
+ var blockInspiredesignCanvasArtifactGuide = (handoff) => {
15638
+ const artifactGuide = { ...handoff.artifactGuide };
15639
+ delete artifactGuide[INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest];
15640
+ return artifactGuide;
15641
+ };
15642
+ var blockInspiredesignNotReadyArtifacts = (handoff) => {
15643
+ const referenceSynthesis = plainObject(handoff.implementationContext.referenceSynthesis);
15644
+ const blockedArtifacts = /* @__PURE__ */ new Set([
15645
+ INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest,
15646
+ INSPIREDESIGN_HANDOFF_FILES.prototypeGuidance
15647
+ ]);
15648
+ const requiredArtifacts = isStringArray(referenceSynthesis.requiredArtifacts) ? referenceSynthesis.requiredArtifacts.filter((artifact) => !blockedArtifacts.has(artifact)) : [];
15649
+ const artifactGuide = { ...handoff.artifactGuide };
15650
+ delete artifactGuide[INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest];
15651
+ delete artifactGuide[INSPIREDESIGN_HANDOFF_FILES.prototypeGuidance];
15652
+ return {
15653
+ ...handoff,
15654
+ artifactGuide: scrubArtifactGuideCanvasReferences(artifactGuide),
15655
+ contractSectionGuide: scrubContractSectionGuideCanvasReferences(handoff.contractSectionGuide),
15656
+ implementationContext: {
15657
+ ...handoff.implementationContext,
15658
+ referenceSynthesis: {
15659
+ ...referenceSynthesis,
15660
+ requiredArtifacts
15661
+ }
15662
+ }
15663
+ };
15664
+ };
15665
+ var blockPrototypeGuidanceInDesignMarkdown = (markdown, prototypeGuidanceMarkdown) => {
15666
+ const withoutCanvasDeliverable = markdown.replace(
15667
+ /\n- Diagnostic `canvasPlanRequest` preview; do not submit to Canvas until next-step guidance is ready/g,
15668
+ `
15669
+ - ${CANVAS_PLAN_OMITTED_GUIDANCE}`
15670
+ );
15671
+ const withoutPrototypeDeliverable = withoutCanvasDeliverable.replace(
15672
+ /\n- Prototype guidance Markdown for the first HTML pass/g,
15673
+ ""
15674
+ );
15675
+ if (!prototypeGuidanceMarkdown) return withoutPrototypeDeliverable;
15676
+ return withoutPrototypeDeliverable.replace(
15677
+ prototypeGuidanceMarkdown,
15678
+ "# 6. Optional Prototype Plan\n\n- Prototype guidance omitted because next-step guidance is not ready."
15679
+ );
15680
+ };
15681
+ var buildMissingInspiredesignGuidanceHandoff = () => {
15682
+ const summary = "Canvas continuation unavailable until nextStepGuidance.readiness is ready.";
15683
+ return {
15684
+ followthroughSummary: summary,
15685
+ suggestedNextAction: summary,
15686
+ suggestedSteps: [{
15687
+ reason: "Inspect the workflow output for nextStepGuidance before using Canvas artifacts."
15688
+ }]
15689
+ };
15690
+ };
13896
15691
  var limitedCount = (total, limit) => Math.min(total, limit);
13897
15692
  var omissionLine = (args) => {
13898
15693
  const omitted = args.total - limitedCount(args.total, args.limit);
@@ -14321,6 +16116,7 @@ var renderInspiredesign = (args) => {
14321
16116
  const screenshotIndex = args.screenshotIndex ?? [];
14322
16117
  const rankedReferences = args.rankedReferences ?? [];
14323
16118
  const rankedReferencesArtifact = args.referencePatternBoard ? {
16119
+ qualitySummary: args.referencePatternBoard.qualitySummary,
14324
16120
  references: args.referencePatternBoard.references,
14325
16121
  rejectedReferences: args.referencePatternBoard.rejectedReferences,
14326
16122
  synthesis: args.referencePatternBoard.synthesis
@@ -14336,18 +16132,44 @@ var renderInspiredesign = (args) => {
14336
16132
  meta: args.meta
14337
16133
  });
14338
16134
  const followthroughSummary = prependPrimaryConstraint(args.designAgentHandoff.summary, args.meta);
16135
+ const canContinueInCanvas = canContinueInspiredesignInCanvas(args.nextStepGuidance);
16136
+ const prototypeGuidanceMarkdown = canContinueInCanvas ? args.prototypeGuidanceMarkdown : null;
16137
+ const designMarkdown = canContinueInCanvas ? args.designMarkdown : blockPrototypeGuidanceInDesignMarkdown(args.designMarkdown, args.prototypeGuidanceMarkdown);
16138
+ const commandExamples2 = {
16139
+ ...args.designAgentHandoff.commandExamples,
16140
+ continueInCanvas: canContinueInCanvas ? args.designAgentHandoff.commandExamples.continueInCanvas : CANVAS_CONTINUATION_BLOCKED_COMMAND
16141
+ };
16142
+ const renderedWorkflowHandoff = buildInspiredesignSuccessHandoff({
16143
+ summary: followthroughSummary,
16144
+ nextStep: args.designAgentHandoff.nextStep,
16145
+ commandExamples: commandExamples2,
16146
+ deepCaptureRecommendation: args.designAgentHandoff.deepCaptureRecommendation,
16147
+ ...args.nextStepGuidance ? { nextStepGuidance: args.nextStepGuidance } : {}
16148
+ });
16149
+ const handoff = args.nextStepGuidance ? renderedWorkflowHandoff : buildMissingInspiredesignGuidanceHandoff();
16150
+ const blockedCanvasArtifactGuide = canContinueInCanvas ? args.designAgentHandoff.artifactGuide : blockInspiredesignCanvasArtifactGuide(args.designAgentHandoff);
16151
+ const renderedDesignAgentHandoffBase = {
16152
+ ...args.designAgentHandoff,
16153
+ ...handoff,
16154
+ summary: handoff.followthroughSummary,
16155
+ nextStep: handoff.suggestedNextAction,
16156
+ artifactGuide: blockedCanvasArtifactGuide,
16157
+ commandExamples: commandExamples2
16158
+ };
16159
+ const renderedDesignAgentHandoff = canContinueInCanvas ? renderedDesignAgentHandoffBase : blockInspiredesignNotReadyArtifacts(renderedDesignAgentHandoffBase);
14339
16160
  const contextPayload = {
14340
16161
  brief: args.brief,
14341
16162
  advancedBriefMarkdown: args.advancedBriefMarkdown,
14342
16163
  urls: args.urls,
14343
16164
  designContract: args.designContract,
14344
- canvasPlanRequest: args.canvasPlanRequest,
14345
- designAgentHandoff: args.designAgentHandoff,
16165
+ ...canContinueInCanvas ? { canvasPlanRequest: args.canvasPlanRequest } : {},
16166
+ designAgentHandoff: renderedDesignAgentHandoff,
16167
+ ...args.nextStepGuidance ? { nextStepGuidance: args.nextStepGuidance } : {},
14346
16168
  generationPlan: args.generationPlan,
14347
16169
  implementationPlan: args.implementationPlan,
14348
- designMarkdown: args.designMarkdown,
16170
+ designMarkdown,
14349
16171
  implementationPlanMarkdown: args.implementationPlanMarkdown,
14350
- prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
16172
+ prototypeGuidanceMarkdown,
14351
16173
  evidence: args.evidence,
14352
16174
  visualEvidence,
14353
16175
  screenshotIndex,
@@ -14355,18 +16177,14 @@ var renderInspiredesign = (args) => {
14355
16177
  metaPromptMarkdown,
14356
16178
  meta: args.meta
14357
16179
  };
14358
- const handoff = buildInspiredesignSuccessHandoff({
14359
- summary: followthroughSummary,
14360
- nextStep: args.designAgentHandoff.nextStep,
14361
- commandExamples: args.designAgentHandoff.commandExamples,
14362
- deepCaptureRecommendation: args.designAgentHandoff.deepCaptureRecommendation
14363
- });
14364
16180
  const files = [
14365
- { path: INSPIREDESIGN_HANDOFF_FILES.designMarkdown, content: args.designMarkdown },
16181
+ { path: INSPIREDESIGN_HANDOFF_FILES.designMarkdown, content: designMarkdown },
14366
16182
  { path: INSPIREDESIGN_HANDOFF_FILES.advancedBrief, content: args.advancedBriefMarkdown },
14367
16183
  { path: INSPIREDESIGN_HANDOFF_FILES.designContract, content: args.designContract },
14368
- { path: INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest, content: args.canvasPlanRequest },
14369
- { path: INSPIREDESIGN_HANDOFF_FILES.designAgentHandoff, content: args.designAgentHandoff },
16184
+ {
16185
+ path: INSPIREDESIGN_HANDOFF_FILES.designAgentHandoff,
16186
+ content: renderedDesignAgentHandoff
16187
+ },
14370
16188
  { path: INSPIREDESIGN_HANDOFF_FILES.generationPlan, content: args.generationPlan },
14371
16189
  { path: INSPIREDESIGN_HANDOFF_FILES.implementationPlanMarkdown, content: args.implementationPlanMarkdown },
14372
16190
  { path: INSPIREDESIGN_HANDOFF_FILES.implementationPlan, content: args.implementationPlan },
@@ -14376,8 +16194,11 @@ var renderInspiredesign = (args) => {
14376
16194
  { path: INSPIREDESIGN_HANDOFF_FILES.rankedReferences, content: rankedReferencesArtifact },
14377
16195
  { path: INSPIREDESIGN_HANDOFF_FILES.metaPrompt, content: metaPromptMarkdown }
14378
16196
  ];
14379
- if (args.prototypeGuidanceMarkdown) {
14380
- files.push({ path: INSPIREDESIGN_HANDOFF_FILES.prototypeGuidance, content: args.prototypeGuidanceMarkdown });
16197
+ if (prototypeGuidanceMarkdown) {
16198
+ files.push({ path: INSPIREDESIGN_HANDOFF_FILES.prototypeGuidance, content: prototypeGuidanceMarkdown });
16199
+ }
16200
+ if (canContinueInCanvas) {
16201
+ files.push({ path: INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest, content: args.canvasPlanRequest });
14381
16202
  }
14382
16203
  const captureAttemptFields = {
14383
16204
  ...captureAttemptSummary ? { captureAttemptSummary } : {},
@@ -14402,12 +16223,13 @@ var renderInspiredesign = (args) => {
14402
16223
  brief: args.brief,
14403
16224
  advancedBriefMarkdown: args.advancedBriefMarkdown,
14404
16225
  urls: args.urls,
14405
- canvasPlanRequest: args.canvasPlanRequest,
14406
- designAgentHandoff: args.designAgentHandoff,
16226
+ ...canContinueInCanvas ? { canvasPlanRequest: args.canvasPlanRequest } : {},
16227
+ designAgentHandoff: renderedDesignAgentHandoff,
16228
+ ...args.nextStepGuidance ? { nextStepGuidance: args.nextStepGuidance } : {},
14407
16229
  designContract: args.designContract,
14408
16230
  generationPlan: args.generationPlan,
14409
16231
  implementationPlan: args.implementationPlan,
14410
- prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
16232
+ prototypeGuidanceMarkdown,
14411
16233
  evidence: args.evidence,
14412
16234
  visualEvidence,
14413
16235
  screenshotIndex,
@@ -14424,9 +16246,9 @@ var renderInspiredesign = (args) => {
14424
16246
  return {
14425
16247
  response: {
14426
16248
  mode: args.mode,
14427
- markdown: args.designMarkdown,
16249
+ markdown: designMarkdown,
14428
16250
  implementationPlanMarkdown: args.implementationPlanMarkdown,
14429
- prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
16251
+ prototypeGuidanceMarkdown,
14430
16252
  ...handoff,
14431
16253
  ...captureAttemptFields,
14432
16254
  meta: args.meta
@@ -14457,6 +16279,247 @@ var renderInspiredesign = (args) => {
14457
16279
  };
14458
16280
  };
14459
16281
 
16282
+ // src/guidance/recipes/site-registry.ts
16283
+ var freezeRecipeValue = (value) => {
16284
+ if (value === null || typeof value !== "object" || Object.isFrozen(value)) return value;
16285
+ for (const child of Object.values(value)) {
16286
+ freezeRecipeValue(child);
16287
+ }
16288
+ return Object.freeze(value);
16289
+ };
16290
+ var SITE_RECIPES = [freezeRecipeValue(pinterestSiteRecipe)];
16291
+ var normalizeHostname = (hostname) => hostname.toLowerCase().replace(/^www\./, "");
16292
+ var resolveSiteRecipeForProvider = (providerId) => {
16293
+ return SITE_RECIPES.find((recipe) => recipe.providerIds.includes(providerId));
16294
+ };
16295
+ var resolveSiteRecipeForUrl = (url) => {
16296
+ let hostname;
16297
+ try {
16298
+ hostname = new URL(url).hostname.toLowerCase();
16299
+ } catch {
16300
+ return void 0;
16301
+ }
16302
+ return SITE_RECIPES.find((recipe) => {
16303
+ if (recipe.id === "social/pinterest") {
16304
+ return isAllowedPinterestReferenceHost(hostname);
16305
+ }
16306
+ const normalizedHost = normalizeHostname(hostname);
16307
+ return recipe.hostnames.some((candidate) => {
16308
+ const normalized = normalizeHostname(candidate);
16309
+ return normalizedHost === normalized || normalizedHost.endsWith(`.${normalized}`);
16310
+ });
16311
+ });
16312
+ };
16313
+
16314
+ // src/guidance/context.ts
16315
+ var HARD_PROVIDER_FAILURE_REASON_CODES = /* @__PURE__ */ new Set([
16316
+ "auth_required",
16317
+ "challenge_detected",
16318
+ "policy_blocked",
16319
+ "rate_limited",
16320
+ "token_required"
16321
+ ]);
16322
+ var normalizeComparableUrl = (value) => {
16323
+ try {
16324
+ const url = new URL(value);
16325
+ url.protocol = "https:";
16326
+ url.hostname = url.hostname.toLowerCase().replace(/^www\./, "");
16327
+ url.hash = "";
16328
+ url.search = "";
16329
+ return url.toString();
16330
+ } catch {
16331
+ return null;
16332
+ }
16333
+ };
16334
+ var hasAcceptedUserSuppliedSiteRecipeReferenceUrl = (source) => {
16335
+ if (source.metrics.referenceCount === 0 || source.quality.rankedReferenceCount === 0) return false;
16336
+ const rankedReferenceUrls = new Set((source.quality.rankedReferenceUrls ?? []).map(normalizeComparableUrl).filter((url) => typeof url === "string"));
16337
+ if (rankedReferenceUrls.size === 0) return false;
16338
+ const requestedSiteRecipeIds = new Set(source.requestedProviders.map((providerId) => resolveSiteRecipeForProvider(providerId)?.id).filter((recipeId) => typeof recipeId === "string"));
16339
+ return (source.urls ?? []).some((url) => {
16340
+ const recipeId = resolveSiteRecipeForUrl(url)?.id;
16341
+ if (!recipeId) return false;
16342
+ if (requestedSiteRecipeIds.size > 0 && !requestedSiteRecipeIds.has(recipeId)) return false;
16343
+ const normalizedUrl = normalizeComparableUrl(url);
16344
+ return normalizedUrl !== null && rankedReferenceUrls.has(normalizedUrl);
16345
+ });
16346
+ };
16347
+ var hasHardProviderFailureSignal = (source) => !hasAcceptedUserSuppliedSiteRecipeReferenceUrl(source) && (source.discovery.hardFailureReasonCodes ?? []).some((reasonCode) => HARD_PROVIDER_FAILURE_REASON_CODES.has(reasonCode)) || (source.primaryConstraint?.reasonCode ? HARD_PROVIDER_FAILURE_REASON_CODES.has(source.primaryConstraint.reasonCode) : false);
16348
+ var hasProviderUnavailableSignal = (source) => {
16349
+ if (hasHardProviderFailureSignal(source)) return true;
16350
+ if (source.metrics.referenceCount > 0 && source.quality.rankedReferenceCount > 0) return false;
16351
+ if (source.discovery.requested && source.discovery.acceptedUrls.length === 0 && source.discovery.failures > 0) return true;
16352
+ if (source.discovery.failure && source.discovery.acceptedUrls.length === 0) return true;
16353
+ return source.primaryConstraint?.reasonCode === "auth_required";
16354
+ };
16355
+ var hasWeakTopReference2 = (source) => {
16356
+ if (source.quality.rankedReferenceCount === 0) return false;
16357
+ const score = source.quality.topReferenceScore ?? 0;
16358
+ const confidence = source.quality.topReferenceConfidence ?? 0;
16359
+ return score < 50 || confidence < 0.5;
16360
+ };
16361
+ var reasonCodeForInspiredesign = (source) => {
16362
+ if (hasProviderUnavailableSignal(source)) return "provider_unavailable";
16363
+ if (source.quality.diagnosticOnlyReasons.length > 0 && source.quality.rankedReferenceCount === 0) return "diagnostic_only";
16364
+ if (source.metrics.referenceCount === 0 && source.metrics.referenceEvidenceRequired !== false) return "zero_references";
16365
+ if (source.metrics.referenceCount > 0 && source.quality.rankedReferenceCount === 0) return "zero_ranked_references";
16366
+ if (source.metrics.visualEvidenceRequired && (source.metrics.failedCaptureCount > 0 || source.quality.missingScreenshotCount > 0)) {
16367
+ return "failed_capture";
16368
+ }
16369
+ if (source.quality.topReferenceIntentMatched === false) return "off_brief_reference";
16370
+ if (hasWeakTopReference2(source)) return "weak_reference";
16371
+ return "design_ready";
16372
+ };
16373
+ var dedupeInspiredesignReferenceUrls = (source) => {
16374
+ const urls = [...source.urls ?? [], ...source.discovery.acceptedUrls].map((url) => url.trim()).filter((url) => url.length > 0);
16375
+ return [...new Set(urls)];
16376
+ };
16377
+ var resolveInspiredesignSiteRecipe = (source) => {
16378
+ const providerRecipe = source.requestedProviders.map((providerId) => resolveSiteRecipeForProvider(providerId)).find((recipe) => recipe !== void 0);
16379
+ if (providerRecipe) return providerRecipe.id;
16380
+ const urlRecipe = (source.urls ?? []).map((url) => resolveSiteRecipeForUrl(url)).find((recipe) => recipe !== void 0);
16381
+ return urlRecipe?.id;
16382
+ };
16383
+ var createInspiredesignGuidanceContext = (source) => {
16384
+ const siteRecipeId = resolveInspiredesignSiteRecipe(source);
16385
+ const referenceUrls = dedupeInspiredesignReferenceUrls(source);
16386
+ return {
16387
+ workflow: "inspiredesign",
16388
+ reasonCode: reasonCodeForInspiredesign(source),
16389
+ requestedProviders: source.requestedProviders,
16390
+ ...siteRecipeId ? { siteRecipeId } : {},
16391
+ ...source.query ? { query: source.query } : {},
16392
+ ...referenceUrls.length > 0 ? { referenceUrls } : {},
16393
+ ...source.browserMode ? { browserMode: source.browserMode } : {},
16394
+ ...source.cookiePolicy ? { cookiePolicy: source.cookiePolicy } : {},
16395
+ ...typeof source.useCookies === "boolean" ? { useCookies: source.useCookies } : {},
16396
+ providerUnavailable: hasProviderUnavailableSignal(source),
16397
+ evidence: {
16398
+ referenceCount: source.metrics.referenceCount,
16399
+ referenceEvidenceRequired: source.metrics.referenceEvidenceRequired,
16400
+ failedCaptureCount: source.metrics.failedCaptureCount,
16401
+ visualEvidenceRequired: source.metrics.visualEvidenceRequired,
16402
+ rankedReferenceCount: source.quality.rankedReferenceCount,
16403
+ rejectedReferenceCount: source.quality.rejectedReferenceCount,
16404
+ missingScreenshotCount: source.quality.missingScreenshotCount,
16405
+ diagnosticOnlyReasons: source.quality.diagnosticOnlyReasons,
16406
+ ...typeof source.quality.topReferenceScore === "number" ? { topReferenceScore: source.quality.topReferenceScore } : {},
16407
+ ...typeof source.quality.topReferenceConfidence === "number" ? { topReferenceConfidence: source.quality.topReferenceConfidence } : {},
16408
+ ...typeof source.quality.topReferenceIntentMatched === "boolean" ? { topReferenceIntentMatched: source.quality.topReferenceIntentMatched } : {}
16409
+ },
16410
+ details: {
16411
+ brief: source.brief,
16412
+ discoveryFailure: source.discovery.failure ?? "",
16413
+ hardFailureReasonCodes: source.discovery.hardFailureReasonCodes ?? [],
16414
+ primaryConstraintSummary: source.primaryConstraint?.summary ?? ""
16415
+ }
16416
+ };
16417
+ };
16418
+
16419
+ // src/guidance/recipes/site-recipe-validation.ts
16420
+ var normalizeNonBlank = (values) => values.map((value) => value.trim()).filter((value) => value.length > 0);
16421
+ var incompatible = (message) => ({ ok: false, message });
16422
+ var supportsBrowserNativeRecovery = (recipe) => typeof recipe?.browserNativeDiscovery?.buildSearchUrl === "function";
16423
+ var isCanonicalRecipeReferenceUrl = (recipe, url) => {
16424
+ if (recipe.id === "social/pinterest") {
16425
+ return normalizePinterestReferenceUrl(url) !== null;
16426
+ }
16427
+ return true;
16428
+ };
16429
+ var isPinterestLikeHostname = (value) => {
16430
+ const hostname = value.toLowerCase();
16431
+ return [
16432
+ hostname === "pinterest.com",
16433
+ hostname.endsWith(".pinterest.com"),
16434
+ hostname.startsWith("pinterest."),
16435
+ hostname.includes(".pinterest.")
16436
+ ].some(Boolean);
16437
+ };
16438
+ var isPinterestLikeUrl = (value) => {
16439
+ try {
16440
+ return isPinterestLikeHostname(new URL(value).hostname);
16441
+ } catch {
16442
+ return false;
16443
+ }
16444
+ };
16445
+ var isNonCanonicalPinterestLikeUrl = (url) => (resolveSiteRecipeForUrl(url)?.id === "social/pinterest" || isPinterestLikeUrl(url)) && normalizePinterestReferenceUrl(url) === null;
16446
+ var requiresProviderUrlSiteRecipeCompatibility = ({
16447
+ providers,
16448
+ urls,
16449
+ query
16450
+ }) => {
16451
+ const providerIds = normalizeNonBlank(providers);
16452
+ if (providerIds.length === 0) return false;
16453
+ if (!query?.trim()) return true;
16454
+ return false;
16455
+ };
16456
+ var validateProviderScopedUrlCanonicality = ({
16457
+ providers,
16458
+ urls
16459
+ }) => {
16460
+ const providerHasPinterest = normalizeNonBlank(providers).some((providerId) => resolveSiteRecipeForProvider(providerId)?.id === "social/pinterest");
16461
+ if (!providerHasPinterest) return { ok: true };
16462
+ const nonCanonicalPinterestUrl = normalizeNonBlank(urls).find((url) => normalizePinterestReferenceUrl(url) === null);
16463
+ if (!nonCanonicalPinterestUrl) return { ok: true };
16464
+ return incompatible(
16465
+ `URL ${nonCanonicalPinterestUrl} is not a canonical social/pinterest reference URL for provider-scoped recovery.`
16466
+ );
16467
+ };
16468
+ var validateProviderUrlSiteRecipeCompatibility = ({
16469
+ providers,
16470
+ urls
16471
+ }) => {
16472
+ const providerIds = normalizeNonBlank(providers);
16473
+ const referenceUrls = normalizeNonBlank(urls);
16474
+ if (providerIds.length === 0) {
16475
+ return incompatible("Provider-scoped URL recovery requires at least one provider.");
16476
+ }
16477
+ if (referenceUrls.length === 0) {
16478
+ return incompatible("Provider-scoped URL recovery requires at least one URL.");
16479
+ }
16480
+ const providerRecipes = providerIds.map((providerId) => ({
16481
+ providerId,
16482
+ recipe: resolveSiteRecipeForProvider(providerId)
16483
+ }));
16484
+ const missingProviderRecipe = providerRecipes.find((entry) => entry.recipe === void 0);
16485
+ if (missingProviderRecipe) {
16486
+ return incompatible(`Provider ${missingProviderRecipe.providerId} does not support URL-only site recipe recovery.`);
16487
+ }
16488
+ const nonNativeProviderRecipe = providerRecipes.find((entry) => !supportsBrowserNativeRecovery(entry.recipe));
16489
+ if (nonNativeProviderRecipe) {
16490
+ return incompatible(`Provider ${nonNativeProviderRecipe.providerId} does not support browser-native URL-only site recipe recovery.`);
16491
+ }
16492
+ const urlRecipes = referenceUrls.map((url) => ({
16493
+ url,
16494
+ recipe: resolveSiteRecipeForUrl(url)
16495
+ }));
16496
+ const missingUrlRecipe = urlRecipes.find((entry) => entry.recipe === void 0);
16497
+ if (missingUrlRecipe) {
16498
+ return incompatible(`URL ${missingUrlRecipe.url} does not match a browser-native site recipe for provider-scoped recovery.`);
16499
+ }
16500
+ const nonNativeUrlRecipe = urlRecipes.find((entry) => !supportsBrowserNativeRecovery(entry.recipe));
16501
+ if (nonNativeUrlRecipe) {
16502
+ return incompatible(`URL ${nonNativeUrlRecipe.url} does not match a browser-native site recipe for provider-scoped recovery.`);
16503
+ }
16504
+ const recipeIds = /* @__PURE__ */ new Set([
16505
+ ...providerRecipes.map((entry) => entry.recipe?.id),
16506
+ ...urlRecipes.map((entry) => entry.recipe?.id)
16507
+ ]);
16508
+ if (recipeIds.size !== 1) {
16509
+ return incompatible("Provider-scoped URL recovery requires every provider and URL to resolve to the same site recipe.");
16510
+ }
16511
+ const recipeId = providerRecipes[0]?.recipe?.id;
16512
+ if (!recipeId) {
16513
+ return incompatible("Provider-scoped URL recovery could not resolve a site recipe.");
16514
+ }
16515
+ const recipe = providerRecipes[0]?.recipe;
16516
+ const nonReferenceUrl = recipe ? urlRecipes.find((entry) => !isCanonicalRecipeReferenceUrl(recipe, entry.url)) : void 0;
16517
+ if (nonReferenceUrl) {
16518
+ return incompatible(`URL ${nonReferenceUrl.url} is not a canonical ${recipeId} reference URL for provider-scoped recovery.`);
16519
+ }
16520
+ return { ok: true, recipeId };
16521
+ };
16522
+
14460
16523
  // src/inspiredesign/reference-discovery.ts
14461
16524
  var normalizeHttpUrl = (value) => {
14462
16525
  try {
@@ -15170,7 +17233,7 @@ var withOfferFilterDiagnosticDetails = (details, offerFilterDiagnostic) => {
15170
17233
  };
15171
17234
  };
15172
17235
  var inferShoppingNoOfferFailure = (providerId, query, records, offerFilterDiagnostic) => {
15173
- const issuePriority = (issue) => ({
17236
+ const issuePriority2 = (issue) => ({
15174
17237
  token_required: 3,
15175
17238
  auth_required: 3,
15176
17239
  challenge_detected: 2
@@ -15185,7 +17248,7 @@ var inferShoppingNoOfferFailure = (providerId, query, records, offerFilterDiagno
15185
17248
  ...title ? { title } : {},
15186
17249
  ...typeof record.attributes.providerShell === "string" && record.attributes.providerShell.trim().length > 0 ? { providerShell: record.attributes.providerShell.trim() } : {}
15187
17250
  }];
15188
- }).sort((left, right) => issuePriority(right.hint) - issuePriority(left.hint))[0] ?? null;
17251
+ }).sort((left, right) => issuePriority2(right.hint) - issuePriority2(left.hint))[0] ?? null;
15189
17252
  if (primaryRecordIssue) {
15190
17253
  const reasonCode = primaryRecordIssue.hint.reasonCode;
15191
17254
  return {
@@ -16335,6 +18398,307 @@ function resolveInspiredesignCaptureMode(requested, urls) {
16335
18398
  return hasInspiredesignUrls(urls) ? "deep" : requested ?? "off";
16336
18399
  }
16337
18400
 
18401
+ // src/providers/browser-native-discovery.ts
18402
+ var HARD_FAILURE_REASON_CODES = /* @__PURE__ */ new Set([
18403
+ "auth_required",
18404
+ "challenge_detected",
18405
+ "policy_blocked",
18406
+ "rate_limited",
18407
+ "token_required"
18408
+ ]);
18409
+ var sourceForRecipe = (recipe) => {
18410
+ return recipe.id.startsWith("social/") ? "social" : "web";
18411
+ };
18412
+ var needsAuthenticatedBrowser = (input) => {
18413
+ if (input.recipe.authMode === "public") return false;
18414
+ if (input.cookiePolicy === "required") return true;
18415
+ return input.recipe.authMode === "authenticated";
18416
+ };
18417
+ var hasAuthenticatedBrowser = (input) => {
18418
+ return input.browserMode === "extension" && input.useCookies === true;
18419
+ };
18420
+ var htmlFromRecord = (record) => {
18421
+ const html = record.attributes.html;
18422
+ return typeof html === "string" ? html : "";
18423
+ };
18424
+ var linksFromRecord = (record) => {
18425
+ const links = record.attributes.links;
18426
+ return Array.isArray(links) ? links.filter((link) => typeof link === "string") : [];
18427
+ };
18428
+ var badStateTextForRecord = (record) => {
18429
+ return [
18430
+ record.url ?? "",
18431
+ record.title ?? "",
18432
+ record.content ?? "",
18433
+ htmlFromRecord(record)
18434
+ ].join(" ").toLowerCase();
18435
+ };
18436
+ var normalizeBadStateReasonCode = (state) => {
18437
+ return isProviderReasonCode(state.reasonCode) ? state.reasonCode : "env_limited";
18438
+ };
18439
+ var shouldMatchBadState = (state, mode) => {
18440
+ if (mode === "hard_blocker") return state.id === "challenge";
18441
+ return mode === "all" || state.id !== "search-shell";
18442
+ };
18443
+ var findBadState = (recipe, records, mode) => {
18444
+ for (const record of records) {
18445
+ const text = badStateTextForRecord(record);
18446
+ const state = recipe.badStates.find((candidate) => shouldMatchBadState(candidate, mode) && candidate.markers.some((marker) => text.includes(marker.toLowerCase())));
18447
+ if (state) {
18448
+ return {
18449
+ state,
18450
+ reasonCode: normalizeBadStateReasonCode(state)
18451
+ };
18452
+ }
18453
+ }
18454
+ return void 0;
18455
+ };
18456
+ var findHardFailure = (failures) => failures.find((failure) => {
18457
+ const reasonCode = failure.error.reasonCode ?? failure.error.details?.reasonCode;
18458
+ return typeof reasonCode === "string" && isProviderReasonCode(reasonCode) && HARD_FAILURE_REASON_CODES.has(reasonCode);
18459
+ });
18460
+ var reasonCodeForFailure = (failure) => {
18461
+ const reasonCode = failure.error.reasonCode ?? failure.error.details?.reasonCode;
18462
+ return typeof reasonCode === "string" && isProviderReasonCode(reasonCode) ? reasonCode : void 0;
18463
+ };
18464
+ var buildBadStateResult = (input, source, searchUrl, fetchedRecordCount, badState) => ({
18465
+ records: [],
18466
+ failures: [{
18467
+ provider: input.recipe.id,
18468
+ source,
18469
+ error: createProviderError(
18470
+ providerErrorCodeFromReasonCode(badState.reasonCode),
18471
+ badState.state.recoveryAction,
18472
+ {
18473
+ retryable: true,
18474
+ reasonCode: badState.reasonCode,
18475
+ provider: input.recipe.id,
18476
+ source,
18477
+ details: {
18478
+ siteRecipeId: input.recipe.id,
18479
+ query: input.query,
18480
+ searchUrl,
18481
+ badStateId: badState.state.id
18482
+ }
18483
+ }
18484
+ )
18485
+ }],
18486
+ diagnostics: {
18487
+ siteRecipeId: input.recipe.id,
18488
+ attempted: true,
18489
+ reason: badState.reasonCode,
18490
+ searchUrl,
18491
+ fetchedRecordCount,
18492
+ badStateId: badState.state.id,
18493
+ recoveryAction: badState.state.recoveryAction
18494
+ }
18495
+ });
18496
+ var buildHardFailureResult = (input, source, searchUrl, fetchedRecordCount, failure) => ({
18497
+ records: [],
18498
+ failures: [failure],
18499
+ diagnostics: {
18500
+ siteRecipeId: input.recipe.id,
18501
+ attempted: true,
18502
+ reason: reasonCodeForFailure(failure) ?? "challenge_detected",
18503
+ searchUrl,
18504
+ fetchedRecordCount,
18505
+ recoveryAction: failure.error.message
18506
+ }
18507
+ });
18508
+ var extractRecipeReferenceUrls = (input, records, maxReferences) => {
18509
+ const extractor = input.recipe.browserNativeDiscovery?.extractReferenceUrls;
18510
+ if (!extractor) return [];
18511
+ const urls = [];
18512
+ const seen = /* @__PURE__ */ new Set();
18513
+ const pushUrl = (url) => {
18514
+ if (!url || seen.has(url)) return;
18515
+ seen.add(url);
18516
+ urls.push(url);
18517
+ };
18518
+ for (const record of records) {
18519
+ extractor({
18520
+ url: record.url ?? void 0,
18521
+ content: record.content ?? void 0,
18522
+ html: typeof record.attributes.html === "string" ? record.attributes.html : void 0,
18523
+ links: linksFromRecord(record)
18524
+ }).forEach(pushUrl);
18525
+ if (urls.length >= maxReferences) break;
18526
+ }
18527
+ return urls.slice(0, maxReferences);
18528
+ };
18529
+ var buildRecipeReferenceRecord = (input, url, index) => {
18530
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
18531
+ return {
18532
+ id: `${input.recipe.id}:reference:${index + 1}:${timestamp}`,
18533
+ source: sourceForRecipe(input.recipe),
18534
+ provider: input.recipe.id,
18535
+ url,
18536
+ title: `Site visual reference ${index + 1} for ${input.query}`,
18537
+ content: input.recipe.navigationSteps.map((step) => step.instruction).join(" "),
18538
+ timestamp,
18539
+ confidence: 0.72,
18540
+ attributes: {
18541
+ siteRecipeId: input.recipe.id,
18542
+ discoveryMode: "browser_native_extracted_reference",
18543
+ authMode: input.recipe.authMode,
18544
+ maxReferences: input.maxReferences,
18545
+ validationChecks: input.recipe.evidenceRequirements.map((entry) => entry.validation)
18546
+ }
18547
+ };
18548
+ };
18549
+ var runBrowserNativeDiscovery = async (input) => {
18550
+ const source = sourceForRecipe(input.recipe);
18551
+ const searchUrl = input.recipe.browserNativeDiscovery?.buildSearchUrl(input.query);
18552
+ if (!searchUrl) {
18553
+ return {
18554
+ records: [],
18555
+ failures: [{
18556
+ provider: input.recipe.id,
18557
+ source,
18558
+ error: createProviderError(
18559
+ "unavailable",
18560
+ `Site recipe ${input.recipe.id} does not define browser-native discovery.`,
18561
+ {
18562
+ retryable: false,
18563
+ reasonCode: "env_limited",
18564
+ provider: input.recipe.id,
18565
+ source,
18566
+ details: {
18567
+ siteRecipeId: input.recipe.id,
18568
+ query: input.query
18569
+ }
18570
+ }
18571
+ )
18572
+ }],
18573
+ diagnostics: {
18574
+ siteRecipeId: input.recipe.id,
18575
+ attempted: false,
18576
+ reason: "unsupported_site_recipe"
18577
+ }
18578
+ };
18579
+ }
18580
+ if (needsAuthenticatedBrowser(input) && !hasAuthenticatedBrowser(input)) {
18581
+ return {
18582
+ records: [],
18583
+ failures: [{
18584
+ provider: input.recipe.id,
18585
+ source,
18586
+ error: createProviderError(
18587
+ "auth",
18588
+ `${input.recipe.id} requires an authenticated browser session before search results are visible.`,
18589
+ {
18590
+ retryable: true,
18591
+ reasonCode: "auth_required",
18592
+ provider: input.recipe.id,
18593
+ source,
18594
+ details: {
18595
+ siteRecipeId: input.recipe.id,
18596
+ query: input.query,
18597
+ requiredBrowserMode: "extension",
18598
+ requiredCookies: true
18599
+ }
18600
+ }
18601
+ )
18602
+ }],
18603
+ diagnostics: {
18604
+ siteRecipeId: input.recipe.id,
18605
+ attempted: false,
18606
+ reason: "auth_required",
18607
+ recoverySteps: input.recipe.recoverySteps.map((step) => step.instruction)
18608
+ }
18609
+ };
18610
+ }
18611
+ if (!input.fetchSearchPage) {
18612
+ return {
18613
+ records: [],
18614
+ failures: [{
18615
+ provider: input.recipe.id,
18616
+ source,
18617
+ error: createProviderError(
18618
+ "unavailable",
18619
+ `${input.recipe.id} browser-native discovery requires a browser-backed fetch executor for the search page.`,
18620
+ {
18621
+ retryable: true,
18622
+ reasonCode: "env_limited",
18623
+ provider: input.recipe.id,
18624
+ source,
18625
+ details: {
18626
+ siteRecipeId: input.recipe.id,
18627
+ query: input.query,
18628
+ searchUrl
18629
+ }
18630
+ }
18631
+ )
18632
+ }],
18633
+ diagnostics: {
18634
+ siteRecipeId: input.recipe.id,
18635
+ attempted: false,
18636
+ reason: "fetch_executor_missing",
18637
+ searchUrl
18638
+ }
18639
+ };
18640
+ }
18641
+ const fetched = await input.fetchSearchPage(searchUrl);
18642
+ const hardFailure = findHardFailure(fetched.failures);
18643
+ if (hardFailure) {
18644
+ return buildHardFailureResult(input, source, searchUrl, fetched.records.length, hardFailure);
18645
+ }
18646
+ const preExtractionMode = needsAuthenticatedBrowser(input) ? "pre_extraction" : "hard_blocker";
18647
+ const hardBlocker = findBadState(input.recipe, fetched.records, preExtractionMode);
18648
+ if (hardBlocker) {
18649
+ return buildBadStateResult(input, source, searchUrl, fetched.records.length, hardBlocker);
18650
+ }
18651
+ const extractedUrls = extractRecipeReferenceUrls(input, fetched.records, input.maxReferences);
18652
+ if (extractedUrls.length === 0) {
18653
+ const shellState = fetched.failures.length === 0 ? findBadState(input.recipe, fetched.records, "all") : void 0;
18654
+ if (shellState) {
18655
+ return buildBadStateResult(input, source, searchUrl, fetched.records.length, shellState);
18656
+ }
18657
+ return {
18658
+ records: [],
18659
+ failures: fetched.failures.length > 0 ? fetched.failures : [{
18660
+ provider: input.recipe.id,
18661
+ source,
18662
+ error: createProviderError(
18663
+ "unavailable",
18664
+ fetched.errorMessage ?? `${input.recipe.id} search did not expose recipe-approved URLs that can be used as references.`,
18665
+ {
18666
+ retryable: true,
18667
+ reasonCode: "env_limited",
18668
+ provider: input.recipe.id,
18669
+ source,
18670
+ details: {
18671
+ siteRecipeId: input.recipe.id,
18672
+ query: input.query,
18673
+ searchUrl
18674
+ }
18675
+ }
18676
+ )
18677
+ }],
18678
+ diagnostics: {
18679
+ siteRecipeId: input.recipe.id,
18680
+ attempted: true,
18681
+ reason: "no_reference_urls_extracted",
18682
+ searchUrl,
18683
+ fetchedRecordCount: fetched.records.length
18684
+ }
18685
+ };
18686
+ }
18687
+ return {
18688
+ records: extractedUrls.map((url, index) => buildRecipeReferenceRecord(input, url, index)),
18689
+ failures: [],
18690
+ diagnostics: {
18691
+ siteRecipeId: input.recipe.id,
18692
+ attempted: true,
18693
+ reason: "reference_urls_extracted",
18694
+ searchUrl,
18695
+ navigationSteps: input.recipe.navigationSteps.map((step) => step.instruction),
18696
+ badStates: input.recipe.badStates.map((state) => state.id),
18697
+ extractedUrlCount: extractedUrls.length
18698
+ }
18699
+ };
18700
+ };
18701
+
16338
18702
  // src/providers/workflows.ts
16339
18703
  var SIGNAL_WINDOW = 50;
16340
18704
  var RECOVERY_WINDOWS_REQUIRED = 2;
@@ -16594,7 +18958,15 @@ var withPrimaryConstraintMeta = (meta, failures) => {
16594
18958
  var withCamelCasePrimaryConstraintMeta = withPrimaryConstraintMeta;
16595
18959
  var readPrimaryConstraintGuidance = (constraint) => {
16596
18960
  const guidance = constraint.guidance;
16597
- return guidance && typeof guidance === "object" && !Array.isArray(guidance) ? guidance : void 0;
18961
+ if (!guidance || typeof guidance !== "object" || Array.isArray(guidance)) return void 0;
18962
+ const record = guidance;
18963
+ if (typeof record.reason !== "string") return void 0;
18964
+ if (!Array.isArray(record.recommendedNextCommands)) return void 0;
18965
+ if (!record.recommendedNextCommands.every((command) => typeof command === "string")) return void 0;
18966
+ return {
18967
+ reason: record.reason,
18968
+ recommendedNextCommands: record.recommendedNextCommands
18969
+ };
16598
18970
  };
16599
18971
  var withPrimaryConstraintSummaryOverride = (meta, summary, guidance) => {
16600
18972
  const currentPrimaryConstraint = meta.primaryConstraint;
@@ -17331,8 +19703,18 @@ var normalizeInspiredesignInput = (input) => {
17331
19703
  if (query && input.harvest !== true) {
17332
19704
  throw new Error("Inspiredesign workflow query is only supported when harvest is true.");
17333
19705
  }
17334
- if (providers.length > 0 && !query) {
17335
- throw new Error("Inspiredesign workflow providers require query.");
19706
+ const canonicality = validateProviderScopedUrlCanonicality({ providers, urls });
19707
+ if (!canonicality.ok) {
19708
+ throw new Error(`Inspiredesign workflow ${canonicality.message}`);
19709
+ }
19710
+ if (requiresProviderUrlSiteRecipeCompatibility({ providers, urls, query })) {
19711
+ if (input.harvest !== true) {
19712
+ throw new Error("Inspiredesign workflow providers require query unless harvest uses compatible URL recovery.");
19713
+ }
19714
+ const compatibility = validateProviderUrlSiteRecipeCompatibility({ providers, urls });
19715
+ if (!compatibility.ok) {
19716
+ throw new Error(`Inspiredesign workflow ${compatibility.message}`);
19717
+ }
17336
19718
  }
17337
19719
  if (input.harvest === true && !query && urls.length === 0) {
17338
19720
  throw new Error("Inspiredesign harvest requires query or URL references.");
@@ -17404,10 +19786,11 @@ var buildInspiredesignStepEnvelope = (workflowInput, trace, stepIndex, url) => b
17404
19786
  trace
17405
19787
  }
17406
19788
  );
17407
- var buildInspiredesignFetchOptions = (workflowInput, envelope, timeoutMs) => withWorkflowResumeEnvelopeIntent(
19789
+ var buildInspiredesignFetchOptionsWithScope = (workflowInput, envelope, providerScope, timeoutMs) => withWorkflowResumeEnvelopeIntent(
17408
19790
  withBrowserModeOverride(
17409
19791
  withChallengeAutomationOverride(
17410
19792
  withCookieOverrides({
19793
+ ...providerScope,
17411
19794
  ...typeof timeoutMs === "number" ? { timeoutMs } : {}
17412
19795
  }, workflowInput),
17413
19796
  workflowInput
@@ -17417,6 +19800,26 @@ var buildInspiredesignFetchOptions = (workflowInput, envelope, timeoutMs) => wit
17417
19800
  "workflow.inspiredesign",
17418
19801
  envelope
17419
19802
  );
19803
+ var buildInspiredesignFetchOptions = (workflowInput, envelope, timeoutMs) => {
19804
+ const siteRecipeProviderIds = new Set(
19805
+ workflowInput.providers.filter((providerId) => resolveSiteRecipeForProvider(providerId) !== void 0)
19806
+ );
19807
+ const standardProviderIds = workflowInput.providers.filter((providerId) => !siteRecipeProviderIds.has(providerId));
19808
+ let providerScope = {};
19809
+ if (workflowInput.providers.length > 0 && standardProviderIds.length === 0) {
19810
+ providerScope = { source: "web" };
19811
+ } else if (standardProviderIds.length > 0) {
19812
+ providerScope = { providerIds: standardProviderIds };
19813
+ }
19814
+ return buildInspiredesignFetchOptionsWithScope(workflowInput, envelope, providerScope, timeoutMs);
19815
+ };
19816
+ var buildInspiredesignSiteRecipeFetchOptions = (workflowInput, envelope, timeoutMs) => buildInspiredesignFetchOptionsWithScope(
19817
+ workflowInput,
19818
+ envelope,
19819
+ { source: "web" },
19820
+ timeoutMs
19821
+ );
19822
+ var buildInspiredesignReferenceFetchOptions = (workflowInput, envelope, url, timeoutMs) => resolveSiteRecipeForUrl(url) ? buildInspiredesignSiteRecipeFetchOptions(workflowInput, envelope, timeoutMs) : buildInspiredesignFetchOptions(workflowInput, envelope, timeoutMs);
17420
19823
  var emptyInspiredesignDiscoveryDiagnostics = (workflowInput, searchAvailable, failure) => ({
17421
19824
  requested: Boolean(workflowInput.query),
17422
19825
  searchAvailable,
@@ -17457,10 +19860,177 @@ var failureFromInspiredesignFetchError = (result) => {
17457
19860
  error: result.error
17458
19861
  }];
17459
19862
  };
19863
+ var normalizeSiteRecipeFetchFailures = (siteRecipe, failures) => {
19864
+ const source = toProviderSource2(siteRecipe.id) ?? "web";
19865
+ return failures.map((failure) => ({
19866
+ provider: siteRecipe.id,
19867
+ source,
19868
+ error: {
19869
+ ...failure.error,
19870
+ provider: siteRecipe.id,
19871
+ source,
19872
+ details: {
19873
+ ...failure.error.details ?? {},
19874
+ upstreamProvider: failure.provider,
19875
+ upstreamSource: failure.source
19876
+ }
19877
+ }
19878
+ }));
19879
+ };
19880
+ var appendNextUniqueDiscoveryCandidate = (queue, cursor, seen, accepted) => {
19881
+ let nextCursor = cursor;
19882
+ while (nextCursor < queue.length) {
19883
+ const candidate = queue[nextCursor];
19884
+ nextCursor += 1;
19885
+ if (!candidate || seen.has(candidate.url)) continue;
19886
+ seen.add(candidate.url);
19887
+ accepted.push(candidate);
19888
+ return nextCursor;
19889
+ }
19890
+ return nextCursor;
19891
+ };
19892
+ var capMixedInspiredesignDiscovery = (siteDiscovery, standardDiscovery, maxReferences) => {
19893
+ const accepted = [];
19894
+ const seen = /* @__PURE__ */ new Set();
19895
+ let siteCursor = 0;
19896
+ let standardCursor = 0;
19897
+ while (accepted.length < maxReferences && (siteCursor < siteDiscovery.accepted.length || standardCursor < standardDiscovery.accepted.length)) {
19898
+ siteCursor = appendNextUniqueDiscoveryCandidate(siteDiscovery.accepted, siteCursor, seen, accepted);
19899
+ if (accepted.length >= maxReferences) break;
19900
+ standardCursor = appendNextUniqueDiscoveryCandidate(standardDiscovery.accepted, standardCursor, seen, accepted);
19901
+ }
19902
+ return {
19903
+ accepted,
19904
+ rejected: [...siteDiscovery.rejected, ...standardDiscovery.rejected]
19905
+ };
19906
+ };
19907
+ var filterStandardDiscoveryForSiteRecipe = (siteRecipe, discovery) => {
19908
+ if (siteRecipe.id !== "social/pinterest") return discovery;
19909
+ const accepted = [];
19910
+ const rejected = [...discovery.rejected];
19911
+ discovery.accepted.forEach((candidate) => {
19912
+ if (!isNonCanonicalPinterestLikeUrl(candidate.url)) {
19913
+ accepted.push(candidate);
19914
+ return;
19915
+ }
19916
+ rejected.push({
19917
+ status: "rejected",
19918
+ reason: "invalid_url",
19919
+ rawUrl: candidate.url,
19920
+ ...candidate.title ? { title: candidate.title } : {},
19921
+ source: candidate.source,
19922
+ provider: candidate.provider,
19923
+ rank: candidate.rank
19924
+ });
19925
+ });
19926
+ return { accepted, rejected };
19927
+ };
17460
19928
  var discoverInspiredesignReferences = async (runtime, workflowInput, envelope, timeoutMs) => {
17461
19929
  if (!workflowInput.query) {
17462
19930
  return emptyInspiredesignDiscoveryDiagnostics(workflowInput, typeof runtime.search === "function");
17463
19931
  }
19932
+ const query = workflowInput.query;
19933
+ const siteRecipe = workflowInput.providers.map((providerId) => resolveSiteRecipeForProvider(providerId)).find((recipe) => recipe !== void 0);
19934
+ const siteRecipeProviderIds = new Set(
19935
+ workflowInput.providers.filter((providerId) => resolveSiteRecipeForProvider(providerId) !== void 0)
19936
+ );
19937
+ const standardProviderIds = workflowInput.providers.filter((providerId) => !siteRecipeProviderIds.has(providerId));
19938
+ if (siteRecipe) {
19939
+ const runSiteRecipeDiscovery = async () => runBrowserNativeDiscovery({
19940
+ recipe: siteRecipe,
19941
+ query,
19942
+ maxReferences: workflowInput.referenceLimit ?? workflowInput.maxReferences,
19943
+ ...workflowInput.browserMode ? { browserMode: workflowInput.browserMode } : {},
19944
+ ...typeof workflowInput.useCookies === "boolean" ? { useCookies: workflowInput.useCookies } : {},
19945
+ ...workflowInput.cookiePolicyOverride ? { cookiePolicy: workflowInput.cookiePolicyOverride } : {},
19946
+ fetchSearchPage: async (url) => {
19947
+ const result = normalizeInspiredesignFetchResult(await runtime.fetch(
19948
+ { url },
19949
+ buildInspiredesignSiteRecipeFetchOptions(workflowInput, envelope, timeoutMs)
19950
+ ));
19951
+ const failures = result.failures.length > 0 ? result.failures : failureFromInspiredesignFetchError(result);
19952
+ return {
19953
+ records: result.records,
19954
+ failures: normalizeSiteRecipeFetchFailures(siteRecipe, failures),
19955
+ ...result.error?.message ? { errorMessage: result.error.message } : {}
19956
+ };
19957
+ }
19958
+ });
19959
+ if (standardProviderIds.length > 0 && typeof runtime.search === "function") {
19960
+ try {
19961
+ const searchResult2 = await runtime.search(
19962
+ {
19963
+ query,
19964
+ limit: workflowInput.maxReferences
19965
+ },
19966
+ {
19967
+ ...buildInspiredesignFetchOptions(workflowInput, envelope, timeoutMs),
19968
+ providerIds: standardProviderIds
19969
+ }
19970
+ );
19971
+ const searchFailures = searchResult2.failures.length > 0 ? searchResult2.failures : failureFromInspiredesignDiscoveryError({ ...workflowInput, providers: standardProviderIds }, searchResult2.error);
19972
+ const discovery3 = filterStandardDiscoveryForSiteRecipe(
19973
+ siteRecipe,
19974
+ normalizeInspiredesignDiscoveryRecords(searchResult2.records)
19975
+ );
19976
+ const siteResult2 = await runSiteRecipeDiscovery();
19977
+ const siteDiscovery = normalizeInspiredesignDiscoveryRecords(siteResult2.records);
19978
+ const combinedDiscovery = capMixedInspiredesignDiscovery(
19979
+ siteDiscovery,
19980
+ discovery3,
19981
+ workflowInput.referenceLimit ?? workflowInput.maxReferences
19982
+ );
19983
+ const failures = [...searchFailures, ...siteResult2.failures];
19984
+ return {
19985
+ requested: true,
19986
+ searchAvailable: true,
19987
+ query,
19988
+ providers: workflowInput.providers,
19989
+ acceptedUrls: combinedDiscovery.accepted.map((candidate) => candidate.url),
19990
+ rejected: combinedDiscovery.rejected,
19991
+ failures,
19992
+ ...failures[0]?.error.message ? { failure: failures[0].error.message } : {},
19993
+ siteRecipeId: siteRecipe.id,
19994
+ browserNativeDiagnostics: {
19995
+ ...siteResult2.diagnostics,
19996
+ standardAcceptedCount: discovery3.accepted.length,
19997
+ standardRejectedCount: discovery3.rejected.length,
19998
+ siteAcceptedCount: siteDiscovery.accepted.length,
19999
+ cappedAcceptedCount: combinedDiscovery.accepted.length
20000
+ }
20001
+ };
20002
+ } catch (error) {
20003
+ const siteResult2 = await runSiteRecipeDiscovery();
20004
+ const discovery3 = normalizeInspiredesignDiscoveryRecords(siteResult2.records);
20005
+ return {
20006
+ requested: true,
20007
+ searchAvailable: true,
20008
+ query,
20009
+ providers: workflowInput.providers,
20010
+ acceptedUrls: discovery3.accepted.map((candidate) => candidate.url),
20011
+ rejected: discovery3.rejected,
20012
+ failures: siteResult2.failures,
20013
+ failure: error instanceof Error ? error.message : "Reference discovery failed.",
20014
+ siteRecipeId: siteRecipe.id,
20015
+ browserNativeDiagnostics: siteResult2.diagnostics
20016
+ };
20017
+ }
20018
+ }
20019
+ const siteResult = await runSiteRecipeDiscovery();
20020
+ const discovery2 = normalizeInspiredesignDiscoveryRecords(siteResult.records);
20021
+ return {
20022
+ requested: true,
20023
+ searchAvailable: true,
20024
+ query,
20025
+ providers: workflowInput.providers,
20026
+ acceptedUrls: discovery2.accepted.map((candidate) => candidate.url),
20027
+ rejected: discovery2.rejected,
20028
+ failures: siteResult.failures,
20029
+ ...siteResult.failures[0]?.error.message ? { failure: siteResult.failures[0].error.message } : {},
20030
+ siteRecipeId: siteRecipe.id,
20031
+ browserNativeDiagnostics: siteResult.diagnostics
20032
+ };
20033
+ }
17464
20034
  if (typeof runtime.search !== "function") {
17465
20035
  return emptyInspiredesignDiscoveryDiagnostics(
17466
20036
  workflowInput,
@@ -17934,11 +20504,85 @@ var summarizeInspiredesignFetchConstraint = (references) => {
17934
20504
  return references.find((reference) => reference.fetchStatus === "failed" && !isInspiredesignFetchRecovered(reference) && typeof reference.fetchFailure === "string" && reference.fetchFailure.trim().length > 0)?.fetchFailure;
17935
20505
  };
17936
20506
  var hasSurvivingInspiredesignReference = (references) => references.some((reference) => reference.fetchStatus === "captured" || reference.captureStatus === "captured");
20507
+ var INSPIREDESIGN_HARD_DISCOVERY_REASON_CODES = /* @__PURE__ */ new Set([
20508
+ "auth_required",
20509
+ "challenge_detected",
20510
+ "policy_blocked",
20511
+ "rate_limited",
20512
+ "token_required"
20513
+ ]);
20514
+ var readInspiredesignFailureReasonCode = (failure) => {
20515
+ const reasonCode = failure.error.reasonCode ?? failure.error.details?.reasonCode;
20516
+ return typeof reasonCode === "string" && INSPIREDESIGN_HARD_DISCOVERY_REASON_CODES.has(reasonCode) ? reasonCode : void 0;
20517
+ };
20518
+ var hardInspiredesignDiscoveryReasonCodes = (discovery) => {
20519
+ const reasonCodes = discovery.failures.map(readInspiredesignFailureReasonCode).filter((reasonCode) => reasonCode !== void 0);
20520
+ return [...new Set(reasonCodes)];
20521
+ };
20522
+ var hardInspiredesignMetaReasonCodes = (meta) => {
20523
+ const distribution = meta.reasonCodeDistribution;
20524
+ if (!distribution || typeof distribution !== "object" || Array.isArray(distribution)) return [];
20525
+ return Object.keys(distribution).filter((reasonCode) => INSPIREDESIGN_HARD_DISCOVERY_REASON_CODES.has(reasonCode));
20526
+ };
20527
+ var hardInspiredesignGuidanceReasonCodes = (discovery, meta) => [
20528
+ .../* @__PURE__ */ new Set([
20529
+ ...hardInspiredesignDiscoveryReasonCodes(discovery),
20530
+ ...hardInspiredesignMetaReasonCodes(meta)
20531
+ ])
20532
+ ];
17937
20533
  var selectInspiredesignPrimaryConstraintFailures = (failures, references, discovery) => {
17938
20534
  if (!hasSurvivingInspiredesignReference(references)) return failures;
17939
20535
  if (discovery.failures.length === 0) return failures;
17940
20536
  return failures.slice(discovery.failures.length);
17941
20537
  };
20538
+ var readMetaPrimaryConstraint = (meta) => {
20539
+ const value = meta.primaryConstraint;
20540
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
20541
+ const record = value;
20542
+ const primaryConstraint = {
20543
+ ...typeof record.reasonCode === "string" ? { reasonCode: record.reasonCode } : {},
20544
+ ...typeof record.summary === "string" ? { summary: record.summary } : {}
20545
+ };
20546
+ return Object.keys(primaryConstraint).length > 0 ? primaryConstraint : void 0;
20547
+ };
20548
+ var isInspiredesignReferenceEvidenceRequired = (workflowInput) => workflowInput.harvest === true || workflowInput.urls.length > 0 || workflowInput.providers.length > 0 || typeof workflowInput.query === "string" || workflowInput.visualEvidence === "required";
20549
+ var buildInspiredesignGuidanceSource = (workflowInput, discovery, meta, referencePatternBoard) => {
20550
+ const quality = summarizeInspiredesignReferenceQuality(referencePatternBoard);
20551
+ const primaryConstraint = readMetaPrimaryConstraint(meta);
20552
+ return {
20553
+ brief: workflowInput.brief,
20554
+ ...workflowInput.query ? { query: workflowInput.query } : {},
20555
+ urls: workflowInput.urls,
20556
+ requestedProviders: workflowInput.providers,
20557
+ ...workflowInput.browserMode ? { browserMode: workflowInput.browserMode } : {},
20558
+ ...workflowInput.cookiePolicyOverride ? { cookiePolicy: workflowInput.cookiePolicyOverride } : {},
20559
+ ...typeof workflowInput.useCookies === "boolean" ? { useCookies: workflowInput.useCookies } : {},
20560
+ discovery: {
20561
+ requested: discovery.requested,
20562
+ acceptedUrls: discovery.acceptedUrls,
20563
+ failures: discovery.failures.length,
20564
+ ...discovery.failure ? { failure: discovery.failure } : {},
20565
+ hardFailureReasonCodes: hardInspiredesignGuidanceReasonCodes(discovery, meta)
20566
+ },
20567
+ metrics: {
20568
+ referenceCount: quality.rankedReferenceCount + quality.rejectedReferenceCount,
20569
+ referenceEvidenceRequired: isInspiredesignReferenceEvidenceRequired(workflowInput),
20570
+ failedCaptureCount: quality.failedCaptureCount,
20571
+ visualEvidenceRequired: workflowInput.visualEvidence === "required"
20572
+ },
20573
+ quality: {
20574
+ rankedReferenceCount: quality.rankedReferenceCount,
20575
+ rankedReferenceUrls: referencePatternBoard.references.map((reference) => reference.url),
20576
+ rejectedReferenceCount: quality.rejectedReferenceCount,
20577
+ missingScreenshotCount: quality.missingScreenshotCount,
20578
+ diagnosticOnlyReasons: quality.diagnosticOnlyReasons,
20579
+ ...typeof quality.topReferenceScore === "number" ? { topReferenceScore: quality.topReferenceScore } : {},
20580
+ ...typeof quality.topReferenceConfidence === "number" ? { topReferenceConfidence: quality.topReferenceConfidence } : {},
20581
+ ...typeof quality.topReferenceIntentMatched === "boolean" ? { topReferenceIntentMatched: quality.topReferenceIntentMatched } : {}
20582
+ },
20583
+ ...primaryConstraint ? { primaryConstraint } : {}
20584
+ };
20585
+ };
17942
20586
  var buildInspiredesignMeta = (runtime, workflowInput, references, failures, followthrough, discovery) => {
17943
20587
  const failedCaptures = references.filter((reference) => reference.captureStatus === "failed");
17944
20588
  const captureAttemptReport = summarizeInspiredesignCaptureAttempts(references);
@@ -18034,6 +20678,11 @@ var summarizeInspiredesignDiscoveryConstraint = (discovery) => {
18034
20678
  guidance: buildInspiredesignDiscoveryGuidance(discovery)
18035
20679
  };
18036
20680
  };
20681
+ var buildInspiredesignGuidanceFollowthroughSummary = (_followthrough, meta, nextStepGuidance) => {
20682
+ const primaryConstraintSummary = typeof meta.primaryConstraintSummary === "string" ? meta.primaryConstraintSummary.trim() : "";
20683
+ const fallbackSummary = primaryConstraintSummary ? `Primary constraint: ${primaryConstraintSummary} ${nextStepGuidance.primaryAction.summary}` : void 0;
20684
+ return renderWorkflowCompatibility(nextStepGuidance, fallbackSummary).followthroughSummary;
20685
+ };
18037
20686
  var inferBrandFromContent = (content, productUrl) => {
18038
20687
  const normalized = normalizePlainText(content);
18039
20688
  if (!normalized) return void 0;
@@ -19073,9 +21722,10 @@ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
19073
21722
  const fetchTimeoutMs = remainingTimeoutMs();
19074
21723
  const fetchResult = await runtime.fetch(
19075
21724
  { url },
19076
- buildInspiredesignFetchOptions(
21725
+ buildInspiredesignReferenceFetchOptions(
19077
21726
  workflowInput,
19078
21727
  buildInspiredesignStepEnvelope(workflowInput, stepTrace, index, url),
21728
+ url,
19079
21729
  fetchTimeoutMs
19080
21730
  )
19081
21731
  );
@@ -19099,7 +21749,9 @@ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
19099
21749
  const reference = buildInspiredesignReference(url, result, capture);
19100
21750
  references.push(reference);
19101
21751
  if (reference.fetchStatus === "failed" && !isInspiredesignFetchRecovered(reference)) {
19102
- failures.push(...result.failures);
21752
+ const fetchFailures = result.failures.length > 0 ? result.failures : failureFromInspiredesignFetchError(result);
21753
+ const siteRecipe = resolveSiteRecipeForUrl(url);
21754
+ failures.push(...siteRecipe ? normalizeSiteRecipeFetchFailures(siteRecipe, fetchFailures) : fetchFailures);
19103
21755
  }
19104
21756
  trace = appendWorkflowTrace(stepTrace, "execute", "reference_completed", {
19105
21757
  stepIndex: index,
@@ -19114,7 +21766,8 @@ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
19114
21766
  briefExpansion: workflowInput.briefExpansion,
19115
21767
  urls: workflowInput.urls,
19116
21768
  references: visualCollation.references,
19117
- includePrototypeGuidance: workflowInput.includePrototypeGuidance
21769
+ includePrototypeGuidance: workflowInput.includePrototypeGuidance,
21770
+ referenceEvidenceRequired: isInspiredesignReferenceEvidenceRequired(workflowInput)
19118
21771
  });
19119
21772
  const meta = buildInspiredesignMeta(
19120
21773
  runtime,
@@ -19124,6 +21777,23 @@ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
19124
21777
  packet.followthrough,
19125
21778
  discovery
19126
21779
  );
21780
+ const nextStepGuidance = routeNextStepGuidance(createInspiredesignGuidanceContext(
21781
+ buildInspiredesignGuidanceSource(
21782
+ workflowInput,
21783
+ discovery,
21784
+ meta,
21785
+ packet.generationPlan.referencePatternBoard
21786
+ )
21787
+ ));
21788
+ const metaWithGuidance = {
21789
+ ...meta,
21790
+ followthroughSummary: nextStepGuidance.readiness === "ready" ? meta.followthroughSummary : buildInspiredesignGuidanceFollowthroughSummary(
21791
+ packet.followthrough,
21792
+ meta,
21793
+ nextStepGuidance
21794
+ ),
21795
+ nextStepGuidance
21796
+ };
19127
21797
  const rendered = renderInspiredesign({
19128
21798
  mode: workflowInput.mode,
19129
21799
  brief: workflowInput.brief,
@@ -19141,9 +21811,13 @@ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
19141
21811
  visualEvidence: packet.visualEvidence,
19142
21812
  screenshotIndex: packet.screenshotIndex,
19143
21813
  rankedReferences: packet.rankedReferences,
19144
- referencePatternBoard: packet.generationPlan.referencePatternBoard,
21814
+ referencePatternBoard: buildInspiredesignRankedArtifactPatternBoard(
21815
+ packet.generationPlan.referencePatternBoard,
21816
+ packet.referencePatternBoard
21817
+ ),
19145
21818
  metaPromptMarkdown: packet.metaPromptMarkdown,
19146
- meta
21819
+ nextStepGuidance,
21820
+ meta: metaWithGuidance
19147
21821
  });
19148
21822
  const bundle = await createArtifactBundle({
19149
21823
  namespace: "inspiredesign",
@@ -19156,7 +21830,7 @@ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
19156
21830
  ...rendered.response,
19157
21831
  artifact_path: bundle.basePath,
19158
21832
  meta: {
19159
- ...meta,
21833
+ ...metaWithGuidance,
19160
21834
  artifact_manifest: bundle.manifest
19161
21835
  }
19162
21836
  };
@@ -19165,7 +21839,7 @@ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
19165
21839
  ...rendered.response,
19166
21840
  artifact_path: bundle.basePath,
19167
21841
  meta: {
19168
- ...meta,
21842
+ ...metaWithGuidance,
19169
21843
  artifact_manifest: bundle.manifest
19170
21844
  }
19171
21845
  };
@@ -21947,6 +24621,8 @@ var mergeBudgets = (base, partial) => {
21947
24621
  };
21948
24622
 
21949
24623
  export {
24624
+ WORKFLOW_ARTIFACT_DIRECTORY,
24625
+ resolveWorkflowArtifactRoot,
21950
24626
  CHALLENGE_AUTOMATION_MODES,
21951
24627
  isChallengeAutomationMode,
21952
24628
  resolveChallengeAutomationPolicy,
@@ -21971,6 +24647,8 @@ export {
21971
24647
  CANVAS_BROWSER_VALIDATION_MODES,
21972
24648
  CANVAS_VALIDATION_TARGET_BLOCK_ON_CODES,
21973
24649
  CANVAS_PUBLIC_WARNING_CLASSES,
24650
+ buildCanvasRepairEnvelope,
24651
+ buildCanvasCommandValidationEnvelope,
21974
24652
  createTraceContext,
21975
24653
  clampConfidence,
21976
24654
  createStableRecordId,
@@ -21998,8 +24676,6 @@ export {
21998
24676
  createShoppingProviders,
21999
24677
  createShoppingProviderById,
22000
24678
  createWebProvider,
22001
- WORKFLOW_ARTIFACT_DIRECTORY,
22002
- resolveWorkflowArtifactRoot,
22003
24679
  resolveTimebox,
22004
24680
  isWithinTimebox,
22005
24681
  filterByTimebox,
@@ -22009,6 +24685,9 @@ export {
22009
24685
  renderResearch,
22010
24686
  renderShopping,
22011
24687
  renderInspiredesign,
24688
+ requiresProviderUrlSiteRecipeCompatibility,
24689
+ validateProviderScopedUrlCanonicality,
24690
+ validateProviderUrlSiteRecipeCompatibility,
22012
24691
  resolveInspiredesignCaptureMode,
22013
24692
  workflowTestUtils,
22014
24693
  runResearchWorkflow,
@@ -22020,4 +24699,4 @@ export {
22020
24699
  createProviderRuntime,
22021
24700
  createDefaultRuntime
22022
24701
  };
22023
- //# sourceMappingURL=chunk-RO3SMXF3.js.map
24702
+ //# sourceMappingURL=chunk-5FDXH4CS.js.map