opendevbrowser 0.0.26 → 0.0.28

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 (102) hide show
  1. package/README.md +7 -10
  2. package/dist/browser/canvas-manager.d.ts.map +1 -1
  3. package/dist/canvas/document-store.d.ts.map +1 -1
  4. package/dist/canvas/guidance.d.ts +22 -0
  5. package/dist/canvas/guidance.d.ts.map +1 -0
  6. package/dist/canvas/types.d.ts +3 -0
  7. package/dist/canvas/types.d.ts.map +1 -1
  8. package/dist/{chunk-GTTYIAI7.js → chunk-I5ZCOZZV.js} +316 -94
  9. package/dist/chunk-I5ZCOZZV.js.map +1 -0
  10. package/dist/{chunk-AVQL6WAS.js → chunk-T3VVHJTK.js} +2384 -544
  11. package/dist/chunk-T3VVHJTK.js.map +1 -0
  12. package/dist/cli/args.d.ts.map +1 -1
  13. package/dist/cli/commands/daemon.d.ts +2 -0
  14. package/dist/cli/commands/daemon.d.ts.map +1 -1
  15. package/dist/cli/commands/devtools/console-poll.d.ts.map +1 -1
  16. package/dist/cli/commands/devtools/network-poll.d.ts.map +1 -1
  17. package/dist/cli/commands/inspiredesign.d.ts +2 -0
  18. package/dist/cli/commands/inspiredesign.d.ts.map +1 -1
  19. package/dist/cli/commands/macro-resolve.d.ts +2 -0
  20. package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
  21. package/dist/cli/commands/product-video.d.ts +2 -0
  22. package/dist/cli/commands/product-video.d.ts.map +1 -1
  23. package/dist/cli/commands/research.d.ts +2 -0
  24. package/dist/cli/commands/research.d.ts.map +1 -1
  25. package/dist/cli/commands/update.d.ts.map +1 -1
  26. package/dist/cli/daemon-autostart.d.ts +6 -2
  27. package/dist/cli/daemon-autostart.d.ts.map +1 -1
  28. package/dist/cli/daemon-commands.d.ts.map +1 -1
  29. package/dist/cli/help.d.ts.map +1 -1
  30. package/dist/cli/index.js +516 -86
  31. package/dist/cli/index.js.map +1 -1
  32. package/dist/cli/utils/parse.d.ts.map +1 -1
  33. package/dist/cli/utils/workflow-message.d.ts +3 -0
  34. package/dist/cli/utils/workflow-message.d.ts.map +1 -1
  35. package/dist/daemon-fingerprint.json +1 -1
  36. package/dist/index.js +39 -15
  37. package/dist/index.js.map +1 -1
  38. package/dist/inspiredesign/brief-expansion.d.ts +3 -0
  39. package/dist/inspiredesign/brief-expansion.d.ts.map +1 -1
  40. package/dist/{providers/inspiredesign-capture-mode.d.ts → inspiredesign/capture-mode.d.ts} +2 -2
  41. package/dist/inspiredesign/capture-mode.d.ts.map +1 -0
  42. package/dist/{providers/inspiredesign-capture.d.ts → inspiredesign/capture.d.ts} +3 -3
  43. package/dist/inspiredesign/capture.d.ts.map +1 -0
  44. package/dist/{providers/inspiredesign-contract.d.ts → inspiredesign/contract.d.ts} +70 -6
  45. package/dist/inspiredesign/contract.d.ts.map +1 -0
  46. package/dist/inspiredesign/handoff.d.ts +12 -10
  47. package/dist/inspiredesign/handoff.d.ts.map +1 -1
  48. package/dist/inspiredesign/reference-pattern-board.d.ts +74 -0
  49. package/dist/inspiredesign/reference-pattern-board.d.ts.map +1 -0
  50. package/dist/macros/execute-runtime.d.ts +2 -1
  51. package/dist/macros/execute-runtime.d.ts.map +1 -1
  52. package/dist/macros/execute.d.ts +4 -2
  53. package/dist/macros/execute.d.ts.map +1 -1
  54. package/dist/opendevbrowser.js +39 -15
  55. package/dist/opendevbrowser.js.map +1 -1
  56. package/dist/providers/browser-fallback.d.ts +7 -0
  57. package/dist/providers/browser-fallback.d.ts.map +1 -1
  58. package/dist/providers/community/index.d.ts.map +1 -1
  59. package/dist/providers/index.d.ts.map +1 -1
  60. package/dist/providers/renderer.d.ts +1 -1
  61. package/dist/providers/renderer.d.ts.map +1 -1
  62. package/dist/providers/research-compiler.d.ts.map +1 -1
  63. package/dist/providers/runtime-bundle.d.ts +1 -1
  64. package/dist/providers/runtime-bundle.d.ts.map +1 -1
  65. package/dist/providers/runtime-factory.d.ts.map +1 -1
  66. package/dist/providers/shopping/index.d.ts.map +1 -1
  67. package/dist/providers/social/platform.d.ts.map +1 -1
  68. package/dist/providers/social/search-quality.d.ts.map +1 -1
  69. package/dist/providers/social/youtube.d.ts.map +1 -1
  70. package/dist/providers/workflow-handoff.d.ts +18 -1
  71. package/dist/providers/workflow-handoff.d.ts.map +1 -1
  72. package/dist/providers/workflows.d.ts +10 -5
  73. package/dist/providers/workflows.d.ts.map +1 -1
  74. package/dist/{providers-T2FQJCF6.js → providers-QF2RFB4J.js} +2 -2
  75. package/dist/public-surface/generated-manifest.d.ts +8 -8
  76. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  77. package/dist/public-surface/source.d.ts +13 -12
  78. package/dist/public-surface/source.d.ts.map +1 -1
  79. package/dist/relay/protocol.d.ts +14 -2
  80. package/dist/relay/protocol.d.ts.map +1 -1
  81. package/dist/tools/inspiredesign_run.d.ts.map +1 -1
  82. package/dist/tools/macro_resolve.d.ts.map +1 -1
  83. package/dist/tools/product_video_run.d.ts.map +1 -1
  84. package/dist/tools/research_run.d.ts.map +1 -1
  85. package/dist/tools/shopping_run.d.ts.map +1 -1
  86. package/extension/dist/canvas/canvas-runtime.js +13 -6
  87. package/extension/dist/services/ConnectionManager.js +8 -4
  88. package/extension/manifest.json +1 -1
  89. package/package.json +1 -1
  90. package/skills/opendevbrowser-best-practices/SKILL.md +6 -6
  91. package/skills/opendevbrowser-best-practices/assets/templates/skill-runtime-pack-matrix.json +1 -1
  92. package/skills/opendevbrowser-design-agent/SKILL.md +5 -0
  93. package/skills/opendevbrowser-design-agent/artifacts/design-contract-playbook.md +6 -1
  94. package/skills/opendevbrowser-design-agent/assets/templates/design-contract.v1.json +15 -1
  95. package/skills/opendevbrowser-design-agent/assets/templates/inspiredesign-advanced-brief.v1.json +72 -33
  96. package/skills/opendevbrowser-design-agent/assets/templates/reference-pattern-board.v1.json +2 -0
  97. package/dist/chunk-AVQL6WAS.js.map +0 -1
  98. package/dist/chunk-GTTYIAI7.js.map +0 -1
  99. package/dist/providers/inspiredesign-capture-mode.d.ts.map +0 -1
  100. package/dist/providers/inspiredesign-capture.d.ts.map +0 -1
  101. package/dist/providers/inspiredesign-contract.d.ts.map +0 -1
  102. /package/dist/{providers-T2FQJCF6.js.map → providers-QF2RFB4J.js.map} +0 -0
@@ -3595,7 +3595,7 @@ var readFallbackRecord = (details, key) => {
3595
3595
  };
3596
3596
  var readFallbackString = (output, key) => {
3597
3597
  const value = output?.[key];
3598
- return typeof value === "string" && value.length > 0 ? value : void 0;
3598
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
3599
3599
  };
3600
3600
  var fallbackDispositionMessage = (fallback, url) => {
3601
3601
  if (typeof fallback.details?.message === "string" && fallback.details.message.trim().length > 0) {
@@ -3610,32 +3610,67 @@ var fallbackDispositionMessage = (fallback, url) => {
3610
3610
  return `Browser fallback failed for ${url}`;
3611
3611
  }
3612
3612
  };
3613
+ var fallbackErrorDetails = (args) => ({
3614
+ url: args.url,
3615
+ disposition: args.fallback.disposition,
3616
+ ...args.fallback.mode ? { browserFallbackMode: args.fallback.mode } : {},
3617
+ ...args.fallback.challenge ? { challenge: toJsonRecord(args.fallback.challenge) } : {},
3618
+ ...args.fallback.preservedSessionId ? { preservedSessionId: args.fallback.preservedSessionId } : {},
3619
+ ...args.fallback.preservedTargetId ? { preservedTargetId: args.fallback.preservedTargetId } : {},
3620
+ ...toJsonRecord(args.fallback.details ?? {}),
3621
+ ...args.extra ?? {}
3622
+ });
3623
+ var addProviderIssueGuidance = (args) => {
3624
+ const hint = readProviderIssueHint({
3625
+ reasonCode: args.reasonCode,
3626
+ details: args.details
3627
+ });
3628
+ const guidanceDetails = args.includeCompleted ? { ...args.details, disposition: "failed" } : args.details;
3629
+ const guidance = hint ? buildProviderIssueGuidance({ provider: args.provider, hint, details: guidanceDetails }) : void 0;
3630
+ return guidance ? { ...args.details, guidance } : args.details;
3631
+ };
3613
3632
  var toProviderFallbackError = (args) => {
3614
3633
  const { fallback } = args;
3615
3634
  const reasonCode = fallback.reasonCode;
3616
- const details = {
3635
+ const details = fallbackErrorDetails({ url: args.url, fallback });
3636
+ return new ProviderRuntimeError(
3637
+ providerErrorCodeFromReasonCode(reasonCode),
3638
+ fallbackDispositionMessage(fallback, args.url),
3639
+ {
3640
+ provider: args.provider,
3641
+ source: args.source,
3642
+ retryable: reasonCode === "rate_limited",
3643
+ reasonCode,
3644
+ details: addProviderIssueGuidance({
3645
+ provider: args.provider,
3646
+ reasonCode,
3647
+ details
3648
+ })
3649
+ }
3650
+ );
3651
+ };
3652
+ var toCompletedFallbackOutputError = (args) => {
3653
+ const { fallback } = args;
3654
+ const reasonCode = fallback.reasonCode;
3655
+ const details = fallbackErrorDetails({
3617
3656
  url: args.url,
3618
- disposition: fallback.disposition,
3619
- ...fallback.mode ? { browserFallbackMode: fallback.mode } : {},
3620
- ...fallback.challenge ? { challenge: toJsonRecord(fallback.challenge) } : {},
3621
- ...fallback.preservedSessionId ? { preservedSessionId: fallback.preservedSessionId } : {},
3622
- ...fallback.preservedTargetId ? { preservedTargetId: fallback.preservedTargetId } : {},
3623
- ...toJsonRecord(fallback.details ?? {})
3624
- };
3625
- const hint = readProviderIssueHint({
3626
- reasonCode,
3627
- details
3657
+ fallback,
3658
+ extra: { fallbackOutputReason: args.outputReason }
3628
3659
  });
3629
- const guidance = hint ? buildProviderIssueGuidance({ provider: args.provider, hint, details }) : void 0;
3630
3660
  return new ProviderRuntimeError(
3631
3661
  providerErrorCodeFromReasonCode(reasonCode),
3632
- fallbackDispositionMessage(fallback, args.url),
3662
+ `Browser fallback completed for ${args.url} without usable HTML content.`,
3633
3663
  {
3634
3664
  provider: args.provider,
3635
3665
  source: args.source,
3636
3666
  retryable: reasonCode === "rate_limited",
3637
3667
  reasonCode,
3638
- details: guidance ? { ...details, guidance } : details
3668
+ details: addProviderIssueGuidance({
3669
+ provider: args.provider,
3670
+ reasonCode,
3671
+ details,
3672
+ includeCompleted: true
3673
+ })
3639
3674
  }
3640
3675
  );
3641
3676
  };
@@ -5070,6 +5105,10 @@ var toPositiveInt = (value, fallback) => {
5070
5105
  if (typeof value !== "number" || Number.isNaN(value)) return fallback;
5071
5106
  return Math.max(1, Math.floor(value));
5072
5107
  };
5108
+ var toNonNegativeInt = (value, fallback) => {
5109
+ if (typeof value !== "number" || Number.isNaN(value)) return fallback;
5110
+ return Math.max(0, Math.floor(value));
5111
+ };
5073
5112
  var isHttpUrl2 = (value) => {
5074
5113
  try {
5075
5114
  const protocol = new URL(value).protocol;
@@ -5115,11 +5154,11 @@ var mergedTraversal = (options, input) => {
5115
5154
  asNumber(filters.pageLimit) ?? options.defaultTraversal?.pageLimit,
5116
5155
  DEFAULT_TRAVERSAL.pageLimit
5117
5156
  ),
5118
- hopLimit: toPositiveInt(
5157
+ hopLimit: toNonNegativeInt(
5119
5158
  asNumber(filters.hopLimit) ?? options.defaultTraversal?.hopLimit,
5120
5159
  DEFAULT_TRAVERSAL.hopLimit
5121
5160
  ),
5122
- expansionPerRecord: toPositiveInt(
5161
+ expansionPerRecord: toNonNegativeInt(
5123
5162
  asNumber(filters.expansionPerRecord) ?? options.defaultTraversal?.expansionPerRecord,
5124
5163
  DEFAULT_TRAVERSAL.expansionPerRecord
5125
5164
  ),
@@ -5428,7 +5467,7 @@ var createCommunityProvider = (options = {}) => {
5428
5467
  };
5429
5468
 
5430
5469
  // src/providers/social/search-quality.ts
5431
- var TARGETED_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit", "facebook"]);
5470
+ var TARGETED_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit", "facebook", "threads"]);
5432
5471
  var SOCIAL_JS_REQUIRED_RE = /\b(?:javascript (?:is not available|required|is disabled(?: in this browser)?)|you need to enable javascript|please enable javascript)\b/i;
5433
5472
  var BLUESKY_LOGGED_OUT_SEARCH_RE = /\bsearch is currently unavailable when logged out\b/i;
5434
5473
  var BLUESKY_EMPTY_SEARCH_SHELL_RE = /\b(?:follow 10 people to get started|find people to follow)\b/i;
@@ -5496,6 +5535,10 @@ var isPrimaryFacebookHost = (host) => {
5496
5535
  const normalized = host.toLowerCase();
5497
5536
  return normalized === "www.facebook.com" || normalized === "facebook.com" || normalized === "m.facebook.com";
5498
5537
  };
5538
+ var isPrimaryThreadsHost = (host) => {
5539
+ const normalized = host.toLowerCase();
5540
+ return normalized === "www.threads.net" || normalized === "threads.net";
5541
+ };
5499
5542
  var isFacebookSearchLikePath = (pathname) => pathname === "/watch/search" || pathname === "/watch/search/" || pathname.startsWith("/watch/explore/") || pathname.startsWith("/search/") || pathname.startsWith("/public/") || pathname.startsWith("/hashtag/");
5500
5543
  var isBlockedFacebookNonContentUrl = (parsed, options) => {
5501
5544
  if (!isPrimaryFacebookHost(parsed.hostname)) {
@@ -5522,7 +5565,7 @@ var isBlockedRedditNonContentUrl = (parsed, options) => {
5522
5565
  return false;
5523
5566
  }
5524
5567
  const pathname = parsed.pathname.toLowerCase();
5525
- if (pathname === "/" || pathname === "/login" || options.includeSearchRoute && pathname === "/search") {
5568
+ if (pathname === "/" || pathname === "/login" || pathname === "/login/" || options.includeSearchRoute && (pathname === "/search" || pathname === "/search/")) {
5526
5569
  return true;
5527
5570
  }
5528
5571
  const pathSegment = firstPathSegment(pathname);
@@ -5540,6 +5583,8 @@ var isRootShellUrl = (platform, parsed) => {
5540
5583
  return isBlockedRedditNonContentUrl(parsed, { includeSearchRoute: false });
5541
5584
  case "facebook":
5542
5585
  return isBlockedFacebookNonContentUrl(parsed, { includeSearchRoute: false });
5586
+ case "threads":
5587
+ return isPrimaryThreadsHost(host) && (pathname === "/" || pathname === "/login" || pathname === "/login/");
5543
5588
  default:
5544
5589
  return false;
5545
5590
  }
@@ -5556,6 +5601,8 @@ var isBlockedExpansionPath = (platform, parsed) => {
5556
5601
  return isBlockedRedditNonContentUrl(parsed, { includeSearchRoute: true });
5557
5602
  case "facebook":
5558
5603
  return isBlockedFacebookNonContentUrl(parsed, { includeSearchRoute: true });
5604
+ case "threads":
5605
+ return isPrimaryThreadsHost(host) && (pathname === "/" || pathname === "/login" || pathname === "/search" || pathname === "/search/" || isStaticMetadataPath(pathname));
5559
5606
  default:
5560
5607
  return false;
5561
5608
  }
@@ -5569,9 +5616,11 @@ var isFirstPartySearchRoute = (platform, parsed) => {
5569
5616
  case "bluesky":
5570
5617
  return host === "bsky.app" && pathname === "/search";
5571
5618
  case "reddit":
5572
- return isPrimaryRedditHost(host) && pathname === "/search";
5619
+ return isPrimaryRedditHost(host) && (pathname === "/search" || pathname === "/search/");
5573
5620
  case "facebook":
5574
5621
  return isPrimaryFacebookHost(host) && isFacebookSearchLikePath(pathname);
5622
+ case "threads":
5623
+ return isPrimaryThreadsHost(host) && (pathname === "/search" || pathname === "/search/");
5575
5624
  default:
5576
5625
  return false;
5577
5626
  }
@@ -5648,6 +5697,10 @@ var isUsableFacebookSearchEvidenceUrl = (url) => {
5648
5697
  }
5649
5698
  return /^\/reel\/[^/]+\/?$/.test(pathname) || /^\/groups\/[^/]+\/posts\/[^/]+\/?$/.test(pathname) || /^\/[^/]+\/videos\/[^/]+\/?$/.test(pathname) || /^\/share\/v\/[^/]+\/?$/.test(pathname) || (pathname === "/permalink.php" || pathname === "/story.php") && parsed.searchParams.has("story_fbid") || pathname === "/photo/" && parsed.searchParams.has("fbid");
5650
5699
  };
5700
+ var isUsableThreadsSearchEvidenceUrl = (url) => {
5701
+ const parsed = parseUrl(url);
5702
+ return parsed !== null && isPrimaryThreadsHost(parsed.hostname) && /^\/@[^/]+\/post\/[^/]+\/?$/.test(parsed.pathname.toLowerCase());
5703
+ };
5651
5704
  var isRetainableFacebookSearchSupportUrl = (url) => {
5652
5705
  const parsed = parseUrl(url);
5653
5706
  if (parsed === null || !isPrimaryFacebookHost(parsed.hostname)) {
@@ -5670,17 +5723,18 @@ var hasFacebookSearchResultSignals = (input) => {
5670
5723
  const hasSearchHeading = FACEBOOK_SEARCH_RESULTS_HEADING_RE.test(combined);
5671
5724
  const markerCount = FACEBOOK_SEARCH_RESULT_MARKERS.filter((pattern) => pattern.test(combined)).length;
5672
5725
  const evidence = collectSocialSearchLinkEvidence("facebook", parsed.toString(), Array.isArray(input.links) ? input.links : []);
5726
+ const hasContentEvidence = evidence.usableContentLinks.length > 0;
5673
5727
  const supportLinkCount = evidence.usableLinks.filter(isRetainableFacebookSearchSupportUrl).length;
5674
- if (markerCount >= 2) {
5728
+ if (markerCount >= 2 && hasContentEvidence) {
5675
5729
  return true;
5676
5730
  }
5677
5731
  if (!hasSearchHeading) {
5678
5732
  return false;
5679
5733
  }
5680
- if (markerCount >= 1) {
5734
+ if (markerCount >= 1 && hasContentEvidence) {
5681
5735
  return true;
5682
5736
  }
5683
- return supportLinkCount >= 2;
5737
+ return supportLinkCount >= 2 && hasContentEvidence;
5684
5738
  };
5685
5739
  var isUsableSocialSearchContentUrl = (platform, url) => {
5686
5740
  switch (platform) {
@@ -5692,6 +5746,8 @@ var isUsableSocialSearchContentUrl = (platform, url) => {
5692
5746
  return isUsableRedditSearchEvidenceUrl(url);
5693
5747
  case "facebook":
5694
5748
  return isUsableFacebookSearchEvidenceUrl(url);
5749
+ case "threads":
5750
+ return isUsableThreadsSearchEvidenceUrl(url);
5695
5751
  default:
5696
5752
  return false;
5697
5753
  }
@@ -5865,6 +5921,10 @@ var toPositiveInt2 = (value, fallback) => {
5865
5921
  if (typeof value !== "number" || Number.isNaN(value)) return fallback;
5866
5922
  return Math.max(1, Math.floor(value));
5867
5923
  };
5924
+ var toNonNegativeInt2 = (value, fallback) => {
5925
+ if (typeof value !== "number" || Number.isNaN(value)) return fallback;
5926
+ return Math.max(0, Math.floor(value));
5927
+ };
5868
5928
  var isHttpUrl3 = (value) => {
5869
5929
  try {
5870
5930
  const protocol = new URL(value).protocol;
@@ -5954,11 +6014,11 @@ var mergedTraversal2 = (input, options) => {
5954
6014
  asNumber2(filters.pageLimit) ?? options.defaultTraversal?.pageLimit,
5955
6015
  DEFAULT_TRAVERSAL2.pageLimit
5956
6016
  ),
5957
- hopLimit: toPositiveInt2(
6017
+ hopLimit: toNonNegativeInt2(
5958
6018
  asNumber2(filters.hopLimit) ?? options.defaultTraversal?.hopLimit,
5959
6019
  DEFAULT_TRAVERSAL2.hopLimit
5960
6020
  ),
5961
- expansionPerRecord: toPositiveInt2(
6021
+ expansionPerRecord: toNonNegativeInt2(
5962
6022
  asNumber2(filters.expansionPerRecord) ?? options.defaultTraversal?.expansionPerRecord,
5963
6023
  DEFAULT_TRAVERSAL2.expansionPerRecord
5964
6024
  ),
@@ -7412,6 +7472,47 @@ var normalizeYouTubeVideoLink = (url) => {
7412
7472
  }
7413
7473
  };
7414
7474
  var YOUTUBE_SEARCH_SHELL_RE = /\b(?:about press copyright contact us creators advertise developers terms privacy policy|google for developers skip to main content youtube)\b/i;
7475
+ var YOUTUBE_FALLBACK_MIN_TEXT_CHARS = 40;
7476
+ var YOUTUBE_CONTENT_MARKER_RE = /"videoId"\s*:|"captionTracks"\s*:|itemprop="author"|itemprop="datePublished"|"viewCount"\s*:/i;
7477
+ var hasYouTubeFallbackEvidence = (html, url) => {
7478
+ if (YOUTUBE_CONTENT_MARKER_RE.test(html)) return true;
7479
+ return extractStructuredContent(html, url).links.some((link) => normalizeYouTubeVideoLink(link) !== null);
7480
+ };
7481
+ var reviewedFallback = (fallback, reasonCode) => ({
7482
+ ...fallback,
7483
+ reasonCode: reasonCode ?? fallback.reasonCode
7484
+ });
7485
+ var assertUsableYouTubeFallbackPage = (url, fallback, html) => {
7486
+ const extracted = extractStructuredContent(html, url);
7487
+ const text = extracted.text.trim();
7488
+ const blocker = classifyBlockerSignal({
7489
+ source: "runtime_fetch",
7490
+ url,
7491
+ message: text,
7492
+ status: 200,
7493
+ providerErrorCode: "unavailable",
7494
+ retryable: true
7495
+ });
7496
+ if (blocker && blocker.type !== "unknown") {
7497
+ throw toCompletedFallbackOutputError({
7498
+ provider: "social/youtube",
7499
+ source: "social",
7500
+ url,
7501
+ fallback: reviewedFallback(fallback, blocker.reasonCode),
7502
+ outputReason: blocker.type
7503
+ });
7504
+ }
7505
+ if (hasYouTubeFallbackEvidence(html, url)) return;
7506
+ if (text.length < YOUTUBE_FALLBACK_MIN_TEXT_CHARS || YOUTUBE_SEARCH_SHELL_RE.test(text)) {
7507
+ throw toCompletedFallbackOutputError({
7508
+ provider: "social/youtube",
7509
+ source: "social",
7510
+ url,
7511
+ fallback,
7512
+ outputReason: "youtube_shell_or_metadata"
7513
+ });
7514
+ }
7515
+ };
7415
7516
  var extractSearchResultSegment = (html, videoId) => {
7416
7517
  const marker = new RegExp(`"videoId"\\s*:\\s*"${escapeRegExp(videoId)}"`);
7417
7518
  const match = marker.exec(html);
@@ -7514,7 +7615,7 @@ var summarizeTranscript = (transcript) => {
7514
7615
  const lines = transcript.split(/\n+/).map((line) => line.trim()).filter(Boolean);
7515
7616
  return lines.slice(0, 8).join(" ").slice(0, 800);
7516
7617
  };
7517
- var fetchPage = async (url, context) => {
7618
+ var fetchPageDirect = async (url, context) => {
7518
7619
  let response;
7519
7620
  try {
7520
7621
  response = await fetch(url, {
@@ -7567,6 +7668,108 @@ var fetchPage = async (url, context) => {
7567
7668
  html: await response.text()
7568
7669
  };
7569
7670
  };
7671
+ var forcedFallbackReasonCode = (context) => {
7672
+ const policy = context.runtimePolicy;
7673
+ if (policy?.cookies.policy === "required") return "auth_required";
7674
+ return "env_limited";
7675
+ };
7676
+ var fallbackReasonCodeForPageError = (error, context) => {
7677
+ if (!isProviderRuntimeError(error)) return "env_limited";
7678
+ if (error.code === "auth") {
7679
+ return context.runtimePolicy?.cookies.policy === "required" ? "auth_required" : "token_required";
7680
+ }
7681
+ if (error.code === "rate_limited") return "rate_limited";
7682
+ if (error.code === "network" || error.code === "timeout") return "env_limited";
7683
+ if (error.code === "upstream") return "ip_blocked";
7684
+ if (error.reasonCode === "ip_blocked" || error.reasonCode === "challenge_detected") return error.reasonCode;
7685
+ return null;
7686
+ };
7687
+ var fallbackDetailsForError = (error) => {
7688
+ if (!isProviderRuntimeError(error)) return {};
7689
+ return {
7690
+ errorCode: error.code,
7691
+ message: error.message,
7692
+ ...error.details ?? {}
7693
+ };
7694
+ };
7695
+ var pageFromFallback = (url, fallback) => {
7696
+ const html = readFallbackString(fallback.output, "html");
7697
+ if (!html) {
7698
+ throw toCompletedFallbackOutputError({
7699
+ provider: "social/youtube",
7700
+ source: "social",
7701
+ url,
7702
+ fallback,
7703
+ outputReason: "missing_or_empty_html"
7704
+ });
7705
+ }
7706
+ assertUsableYouTubeFallbackPage(url, fallback, html);
7707
+ return {
7708
+ status: 200,
7709
+ url: readFallbackString(fallback.output, "url") ?? url,
7710
+ html,
7711
+ browserFallback: toBrowserFallbackObservation(fallback)
7712
+ };
7713
+ };
7714
+ var resolveFallbackPage = async (args) => {
7715
+ const fallback = await resolveProviderBrowserFallback({
7716
+ browserFallbackPort: args.context.browserFallbackPort ?? args.options.browserFallbackPort,
7717
+ provider: "social/youtube",
7718
+ source: "social",
7719
+ operation: args.operation,
7720
+ reasonCode: args.reasonCode,
7721
+ url: args.url,
7722
+ context: args.context,
7723
+ details: args.details,
7724
+ recoveryHints: args.options.recoveryHints?.()
7725
+ });
7726
+ if (!fallback) return null;
7727
+ if (fallback.disposition !== "completed") {
7728
+ throw toProviderFallbackError({
7729
+ provider: "social/youtube",
7730
+ source: "social",
7731
+ url: args.url,
7732
+ fallback
7733
+ });
7734
+ }
7735
+ return pageFromFallback(args.url, fallback);
7736
+ };
7737
+ var fetchPage = async (url, context, options, operation) => {
7738
+ if (context.runtimePolicy?.browser.forceTransport) {
7739
+ const page = await resolveFallbackPage({
7740
+ url,
7741
+ context,
7742
+ options,
7743
+ operation,
7744
+ reasonCode: forcedFallbackReasonCode(context),
7745
+ details: { message: "Direct browser transport was selected for this YouTube provider run." }
7746
+ });
7747
+ if (page) return page;
7748
+ throw new ProviderRuntimeError(providerErrorCodeFromReasonCode(forcedFallbackReasonCode(context)), "Direct browser transport is required for this YouTube provider run, but no browser transport is available.", {
7749
+ provider: "social/youtube",
7750
+ source: "social",
7751
+ retryable: false,
7752
+ reasonCode: forcedFallbackReasonCode(context),
7753
+ details: { browserTransportRequired: true }
7754
+ });
7755
+ }
7756
+ try {
7757
+ return await fetchPageDirect(url, context);
7758
+ } catch (error) {
7759
+ const reasonCode = fallbackReasonCodeForPageError(error, context);
7760
+ if (!reasonCode) throw error;
7761
+ const page = await resolveFallbackPage({
7762
+ url,
7763
+ context,
7764
+ options,
7765
+ operation,
7766
+ reasonCode,
7767
+ details: fallbackDetailsForError(error)
7768
+ });
7769
+ if (page) return page;
7770
+ throw error;
7771
+ }
7772
+ };
7570
7773
  var parseBooleanFilter = (value, fallback = false) => {
7571
7774
  if (typeof value === "boolean") return value;
7572
7775
  if (typeof value === "string") {
@@ -7609,7 +7812,7 @@ var resolveTranscriptStrategyDetail = (transcript) => {
7609
7812
  return transcript.attemptChain.at(-1)?.strategy;
7610
7813
  };
7611
7814
  var buildSearch = (options) => {
7612
- if (options) return options;
7815
+ if (options.search) return options.search;
7613
7816
  return async (input, context) => {
7614
7817
  assertYouTubeLegalReviewChecklist();
7615
7818
  const query = input.query.trim();
@@ -7622,7 +7825,7 @@ var buildSearch = (options) => {
7622
7825
  }
7623
7826
  const lookupUrl = isHttpUrl4(query) ? query : `https://www.youtube.com/results?search_query=${encodeURIComponent(query)}`;
7624
7827
  const directUrlQuery = isHttpUrl4(query);
7625
- const page = await fetchPage(lookupUrl, context);
7828
+ const page = await fetchPage(lookupUrl, context, options, "search");
7626
7829
  const extracted = extractStructuredContent(page.html, page.url);
7627
7830
  const extractedVideoLinks = [...new Set(
7628
7831
  extracted.links.map((link) => normalizeYouTubeVideoLink(link)).filter((link) => typeof link === "string" && link.length > 0)
@@ -7668,7 +7871,8 @@ var buildSearch = (options) => {
7668
7871
  retrievalPath: isHttpUrl4(query) ? "social:youtube:search:url" : "social:youtube:search:index",
7669
7872
  video_id: resolvedVideoId,
7670
7873
  ...primaryResult?.channel ? { channel: primaryResult.channel } : {},
7671
- links: extractedVideoLinks.slice(0, 20)
7874
+ links: extractedVideoLinks.slice(0, 20),
7875
+ ...browserFallbackObservationAttributes(page.browserFallback)
7672
7876
  }
7673
7877
  }];
7674
7878
  };
@@ -7677,7 +7881,7 @@ var buildFetch = (options) => {
7677
7881
  if (options.fetch) return options.fetch;
7678
7882
  return async (input, context) => {
7679
7883
  assertYouTubeLegalReviewChecklist();
7680
- const page = await fetchPage(input.url, context);
7884
+ const page = await fetchPage(input.url, context, options, "fetch");
7681
7885
  const extracted = extractStructuredContent(page.html, page.url);
7682
7886
  const includeFullTranscript = parseBooleanFilter(input.filters?.include_full_transcript, false);
7683
7887
  const requireTranscript = parseBooleanFilter(input.filters?.requireTranscript, false);
@@ -7692,7 +7896,7 @@ var buildFetch = (options) => {
7692
7896
  legalChecklist: YOUTUBE_LEGAL_REVIEW_CHECKLIST,
7693
7897
  config: transcriptConfig,
7694
7898
  mode: requestedMode,
7695
- browserFallbackPort: options.browserFallbackPort,
7899
+ browserFallbackPort: context.browserFallbackPort ?? options.browserFallbackPort,
7696
7900
  recoveryHints,
7697
7901
  allowBrowserFallbackEscalation: options.antiBotPolicy?.allowBrowserEscalation ?? true,
7698
7902
  asrTranscribe: options.asrTranscribe
@@ -7747,6 +7951,7 @@ var buildFetch = (options) => {
7747
7951
  transcript_mode: transcript.mode,
7748
7952
  translation_applied: translationApplied,
7749
7953
  transcript_summary: transcriptSummary,
7954
+ ...browserFallbackObservationAttributes(page.browserFallback),
7750
7955
  ...includeFullTranscript ? { transcript_full: transcriptContent } : {},
7751
7956
  ...transcriptStrategyDetail ? { transcript_strategy_detail: transcriptStrategyDetail } : {},
7752
7957
  ...transcript.ok ? {
@@ -7789,7 +7994,7 @@ var withDefaultYouTubeOptions = (options = {}) => {
7789
7994
  };
7790
7995
  return {
7791
7996
  ...resolvedOptions,
7792
- search: buildSearch(resolvedOptions.search),
7997
+ search: buildSearch(resolvedOptions),
7793
7998
  fetch: buildFetch(resolvedOptions)
7794
7999
  };
7795
8000
  };
@@ -7989,6 +8194,73 @@ var getShoppingRegionSupportDiagnostics = (providerIds, region) => {
7989
8194
  });
7990
8195
  };
7991
8196
  var hasValues2 = (values) => values.some((value) => value.trim().length > 0);
8197
+ var FALLBACK_HEAD_RE = /<head\b[^>]*>[\s\S]*?<\/head>/i;
8198
+ var FALLBACK_BODY_RE = /<body\b[^>]*>([\s\S]*?)<\/body>/i;
8199
+ var SHOPPING_FALLBACK_EVIDENCE_LIMIT = 1;
8200
+ var extractShoppingFallbackBodyText = (html) => {
8201
+ const body = FALLBACK_BODY_RE.exec(html)?.[1];
8202
+ return extractText(body ?? html.replace(FALLBACK_HEAD_RE, " "));
8203
+ };
8204
+ var hasShoppingMetadataEvidence = (extracted) => {
8205
+ return extracted.metadata.price !== void 0;
8206
+ };
8207
+ var hasShoppingOfferTextEvidence = (text) => {
8208
+ const price = parsePrice(text);
8209
+ if (price.amount <= 0) return false;
8210
+ return parseRating(text) > 0 || parseReviews(text) > 0 || parseAvailability(text) !== "unknown" || /\b(?:add to cart|buy now|shipping|pickup|deal|save)\b/i.test(text);
8211
+ };
8212
+ var hasShoppingBlockingPageEvidence = (url, extracted) => {
8213
+ const blocker = classifyBlockerSignal({
8214
+ source: "runtime_fetch",
8215
+ url,
8216
+ finalUrl: url,
8217
+ title: typeof extracted.metadata.title === "string" ? extracted.metadata.title : void 0,
8218
+ message: extracted.text,
8219
+ status: 200,
8220
+ providerErrorCode: "unavailable",
8221
+ retryable: true
8222
+ });
8223
+ return blocker?.type === "auth_required" || blocker?.type === "anti_bot_challenge";
8224
+ };
8225
+ var hasShoppingFallbackEvidence = (args) => {
8226
+ return args.extracted.links.some((link) => isLikelyProductUrl(canonicalizeUrl(link), args.profile)) || extractSearchCandidates(args.html, args.url, args.profile, SHOPPING_FALLBACK_EVIDENCE_LIMIT).length > 0 || hasShoppingMetadataEvidence(args.extracted) || hasShoppingOfferTextEvidence(extractShoppingFallbackBodyText(args.html)) || hasShoppingBlockingPageEvidence(args.url, args.extracted);
8227
+ };
8228
+ var toFallbackShellIssueError = (args) => {
8229
+ const issue = classifyProviderIssue({
8230
+ url: args.url,
8231
+ title: args.requirement.title,
8232
+ message: args.requirement.message,
8233
+ providerShell: args.requirement.reason,
8234
+ browserRequired: true,
8235
+ status: 200
8236
+ });
8237
+ const reasonCode = issue?.reasonCode ?? "env_limited";
8238
+ const extracted = extractStructuredContent(args.html, args.url);
8239
+ return new ProviderRuntimeError(
8240
+ providerErrorCodeFromReasonCode(reasonCode),
8241
+ reasonCode === "challenge_detected" ? `Detected anti-bot challenge while retrieving ${args.url}` : `Browser assistance required for ${args.url}`,
8242
+ {
8243
+ provider: args.provider,
8244
+ source: SHOPPING_SOURCE,
8245
+ retryable: reasonCode === "env_limited",
8246
+ reasonCode,
8247
+ details: {
8248
+ ...applyProviderIssueHint({
8249
+ status: 200,
8250
+ url: args.url,
8251
+ ...args.requirement.title ? { title: args.requirement.title } : {},
8252
+ ...args.requirement.message ? { message: args.requirement.message } : {},
8253
+ providerShell: args.requirement.reason,
8254
+ browserRequired: true,
8255
+ extractionFocus: args.profile.extractionFocus,
8256
+ extractedTextLength: extracted.text.length,
8257
+ extractedLinkCount: extracted.links.length
8258
+ }, issue),
8259
+ ...browserFallbackObservationDetails(toBrowserFallbackObservation(args.fallback))
8260
+ }
8261
+ }
8262
+ );
8263
+ };
7992
8264
  var parseIsoDate2 = (value) => {
7993
8265
  const parsed = Date.parse(value);
7994
8266
  return Number.isNaN(parsed) ? NaN : parsed;
@@ -8120,11 +8392,47 @@ var resolveBrowserFallback = async (args) => {
8120
8392
  };
8121
8393
  }
8122
8394
  const resolvedUrl = canonicalizeUrl(readFallbackString(fallback.output, "url") ?? args.url);
8395
+ const html = readFallbackString(fallback.output, "html");
8396
+ if (!html) {
8397
+ throw toCompletedFallbackOutputError({
8398
+ provider: args.provider,
8399
+ source: SHOPPING_SOURCE,
8400
+ url: resolvedUrl,
8401
+ fallback,
8402
+ outputReason: "missing_or_empty_html"
8403
+ });
8404
+ }
8405
+ const extracted = extractStructuredContent(html, resolvedUrl);
8406
+ const browserRequirement = requiresBrowserAssistance(args.profile, resolvedUrl, html);
8407
+ if (browserRequirement) {
8408
+ throw toFallbackShellIssueError({
8409
+ provider: args.provider,
8410
+ url: resolvedUrl,
8411
+ html,
8412
+ fallback,
8413
+ profile: args.profile,
8414
+ requirement: browserRequirement
8415
+ });
8416
+ }
8417
+ if (!hasShoppingFallbackEvidence({
8418
+ html,
8419
+ url: resolvedUrl,
8420
+ extracted,
8421
+ profile: args.profile
8422
+ })) {
8423
+ throw toCompletedFallbackOutputError({
8424
+ provider: args.provider,
8425
+ source: SHOPPING_SOURCE,
8426
+ url: resolvedUrl,
8427
+ fallback,
8428
+ outputReason: "empty_extracted_content"
8429
+ });
8430
+ }
8123
8431
  return {
8124
8432
  record: {
8125
8433
  status: 200,
8126
8434
  url: resolvedUrl,
8127
- html: readFallbackString(fallback.output, "html") ?? "",
8435
+ html,
8128
8436
  browserFallback: toBrowserFallbackObservation(fallback)
8129
8437
  }
8130
8438
  };
@@ -8237,6 +8545,7 @@ var defaultFetcher = async ({ url, signal, provider, operation, context }) => {
8237
8545
  error,
8238
8546
  url,
8239
8547
  provider: providerId,
8548
+ profile,
8240
8549
  operation,
8241
8550
  recoveryHints,
8242
8551
  context
@@ -8644,8 +8953,7 @@ var requiresBrowserAssistance = (profile, responseUrl, html) => {
8644
8953
  }
8645
8954
  return null;
8646
8955
  };
8647
- var classifySearchPageIssue = (profile, fetched, extracted, content) => {
8648
- const providerShell = requiresBrowserAssistance(profile, fetched.url, fetched.html);
8956
+ var classifySearchPageIssue = (profile, fetched, extracted, content, providerShell = requiresBrowserAssistance(profile, fetched.url, fetched.html)) => {
8649
8957
  return classifyProviderIssue({
8650
8958
  url: fetched.url,
8651
8959
  title: providerShell?.title ?? (typeof extracted.metadata.title === "string" ? extracted.metadata.title : void 0),
@@ -8657,6 +8965,51 @@ var classifySearchPageIssue = (profile, fetched, extracted, content) => {
8657
8965
  retryable: true
8658
8966
  });
8659
8967
  };
8968
+ var toExplicitProviderShellIssue = (providerShell, content) => ({
8969
+ reasonCode: "env_limited",
8970
+ blockerType: "env_limited",
8971
+ constraint: {
8972
+ kind: "render_required",
8973
+ evidenceCode: providerShell.reason,
8974
+ providerShell: providerShell.reason,
8975
+ ...content ? { message: content } : {}
8976
+ }
8977
+ });
8978
+ var ensureProviderShellIssue = (issue, providerShell, content) => {
8979
+ if (!issue || issue.reasonCode === "env_limited" && !issue.constraint) {
8980
+ return toExplicitProviderShellIssue(providerShell, content);
8981
+ }
8982
+ return issue;
8983
+ };
8984
+ var toShoppingPageIssueMessage = (reasonCode, url) => {
8985
+ if (reasonCode === "token_required") return `Authentication required for ${url}`;
8986
+ if (reasonCode === "env_limited") return `Browser assistance required for ${url}`;
8987
+ return `Detected anti-bot challenge while retrieving ${url}`;
8988
+ };
8989
+ var throwShoppingPageIssue = (args) => {
8990
+ const reasonCode = args.pageIssue.reasonCode;
8991
+ throw new ProviderRuntimeError(
8992
+ providerErrorCodeFromReasonCode(reasonCode),
8993
+ toShoppingPageIssueMessage(reasonCode, args.fetched.url),
8994
+ {
8995
+ provider: args.providerId,
8996
+ source: SHOPPING_SOURCE,
8997
+ retryable: reasonCode === "env_limited",
8998
+ reasonCode,
8999
+ details: {
9000
+ ...applyProviderIssueHint({
9001
+ status: args.fetched.status,
9002
+ url: args.fetched.url,
9003
+ ...typeof args.extracted.metadata.title === "string" ? { title: args.extracted.metadata.title } : {},
9004
+ ...args.content ? { message: args.content } : {},
9005
+ ...args.providerShell?.reason ? { providerShell: args.providerShell.reason } : {}
9006
+ }, args.pageIssue),
9007
+ ...args.providerShell?.reason ? { browserRequired: true } : {},
9008
+ ...browserFallbackObservationDetails(args.fetched.browserFallback)
9009
+ }
9010
+ }
9011
+ );
9012
+ };
8660
9013
  var unwrapTrackingUrl = (url, profile) => {
8661
9014
  const normalizedUrl = decodeHrefValue(url);
8662
9015
  try {
@@ -9054,6 +9407,7 @@ var createDefaultSearch = (profile, providerId, fetcher) => async (input, contex
9054
9407
  context
9055
9408
  });
9056
9409
  const extracted = extractStructuredContent(fetched.html, fetched.url);
9410
+ const providerShell = requiresBrowserAssistance(profile, fetched.url, fetched.html);
9057
9411
  const limit = Math.max(1, Math.min(input.limit ?? 10, 20));
9058
9412
  const links = dedupeLinks(
9059
9413
  extracted.links.filter((link) => isLikelyProductUrl(canonicalizeUrl(link), profile)),
@@ -9061,7 +9415,17 @@ var createDefaultSearch = (profile, providerId, fetcher) => async (input, contex
9061
9415
  );
9062
9416
  const content = toSnippet(extracted.text, 2e3);
9063
9417
  const candidates = extractSearchCandidates(fetched.html, fetched.url, profile, limit);
9064
- const pageIssue = candidates.length === 0 ? classifySearchPageIssue(profile, fetched, extracted, content) : null;
9418
+ const pageIssue = providerShell ? classifySearchPageIssue(profile, fetched, extracted, content, providerShell) : candidates.length === 0 ? classifySearchPageIssue(profile, fetched, extracted, content, providerShell) : null;
9419
+ if (providerShell) {
9420
+ throwShoppingPageIssue({
9421
+ providerId,
9422
+ fetched,
9423
+ extracted,
9424
+ content,
9425
+ pageIssue: ensureProviderShellIssue(pageIssue, providerShell, content),
9426
+ providerShell
9427
+ });
9428
+ }
9065
9429
  if (candidates.length > 0) {
9066
9430
  return candidates.map((candidate, index) => ({
9067
9431
  url: candidate.url,
@@ -9096,28 +9460,7 @@ var createDefaultSearch = (profile, providerId, fetcher) => async (input, contex
9096
9460
  }));
9097
9461
  }
9098
9462
  if (pageIssue && (pageIssue.reasonCode !== "env_limited" || pageIssue.constraint)) {
9099
- const reasonCode = pageIssue.reasonCode;
9100
- const providerShell = requiresBrowserAssistance(profile, fetched.url, fetched.html);
9101
- throw new ProviderRuntimeError(
9102
- providerErrorCodeFromReasonCode(reasonCode),
9103
- reasonCode === "token_required" ? `Authentication required for ${fetched.url}` : `Detected anti-bot challenge while retrieving ${fetched.url}`,
9104
- {
9105
- provider: providerId,
9106
- source: SHOPPING_SOURCE,
9107
- retryable: reasonCode === "env_limited",
9108
- reasonCode,
9109
- details: {
9110
- ...applyProviderIssueHint({
9111
- status: fetched.status,
9112
- url: fetched.url,
9113
- ...typeof extracted.metadata.title === "string" ? { title: extracted.metadata.title } : {},
9114
- ...content ? { message: content } : {},
9115
- ...providerShell?.reason ? { providerShell: providerShell.reason } : {}
9116
- }, pageIssue),
9117
- ...browserFallbackObservationDetails(fetched.browserFallback)
9118
- }
9119
- }
9120
- );
9463
+ throwShoppingPageIssue({ providerId, fetched, extracted, content, pageIssue, providerShell });
9121
9464
  }
9122
9465
  const rows = [
9123
9466
  {
@@ -9828,7 +10171,7 @@ var enrichResearchRecords = (records, timebox, now = /* @__PURE__ */ new Date())
9828
10171
  return records.map((record) => toResearchRecord(record, timebox, now));
9829
10172
  };
9830
10173
 
9831
- // src/providers/inspiredesign-contract.ts
10174
+ // src/inspiredesign/contract.ts
9832
10175
  import { createHash as createHash3 } from "crypto";
9833
10176
 
9834
10177
  // skills/opendevbrowser-design-agent/assets/templates/canvas-generation-plan.design.v1.json
@@ -10023,7 +10366,13 @@ var design_contract_v1_default = {
10023
10366
  "section reveal",
10024
10367
  "primary CTA feedback"
10025
10368
  ],
10026
- parallaxPolicy: "off unless explicitly justified"
10369
+ parallaxPolicy: "off unless explicitly justified",
10370
+ advancedMotionAdvisory: [
10371
+ "Advisory shader-like gradient depth: describe intent only; implement with approved runtime primitives unless a separate runtime change authorizes more.",
10372
+ "Advisory WebGL-style spatial reveal: document depth and hierarchy without implying WebGL runtime support.",
10373
+ "Advisory Spline-style product orbit: document scene posture and static fallback without approving custom 3D runtime dependencies.",
10374
+ "Runtime boundary: libraryPolicy.motion and libraryPolicy.threeD stay empty unless separately approved."
10375
+ ]
10027
10376
  },
10028
10377
  performanceModel: {
10029
10378
  renderHotspots: [
@@ -10116,6 +10465,14 @@ var design_contract_v1_default = {
10116
10465
  "spinner-stacking",
10117
10466
  "scan-surface-jank"
10118
10467
  ]
10468
+ },
10469
+ designVectors: {
10470
+ advancedMotionAdvisory: [
10471
+ "Advisory shader-like gradient depth",
10472
+ "Advisory WebGL-style spatial reveal",
10473
+ "Advisory Spline-style product orbit",
10474
+ "Runtime support: none. Library policy authorization: none."
10475
+ ]
10119
10476
  }
10120
10477
  }
10121
10478
  };
@@ -10155,10 +10512,176 @@ var INSPIREDESIGN_HANDOFF_RECOMMENDED_SKILLS = [
10155
10512
  formatSkillReference(INSPIREDESIGN_HANDOFF_SKILLS.designAgent)
10156
10513
  ];
10157
10514
  var INSPIREDESIGN_HANDOFF_GUIDANCE = {
10158
- reviewAdvancedBrief: `${INSPIREDESIGN_HANDOFF_FILES.advancedBrief} is the authoritative prompt route for the selected format, profile defaults, layout posture, motion grammar, and anti-patterns. Read it before touching Canvas or implementation files.`,
10515
+ reviewAdvancedBrief: `${INSPIREDESIGN_HANDOFF_FILES.advancedBrief} is the authoritative reference-first brief. When URL references exist, captured evidence leads the creative direction; selected format, profile defaults, layout posture, motion grammar, and anti-patterns are route guardrails only. Read it before touching Canvas or implementation files.`,
10159
10516
  prepareCanvasPlanRequest: `Fill canvasSessionId, leaseId, and documentId in ${INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest} before running ${INSPIREDESIGN_HANDOFF_COMMANDS.continueInCanvas}.`,
10160
10517
  deepCaptureRecommendation: "Any inspiredesign run with reference URLs already uses captureMode=deep. Rerun with the same URLs only when you need refreshed DOM/layout evidence, restored session state, or capture-specific debugging."
10161
10518
  };
10519
+ var INSPIREDESIGN_ARTIFACT_GUIDE = {
10520
+ [INSPIREDESIGN_HANDOFF_FILES.advancedBrief]: {
10521
+ purpose: "Authoritative reference-first brief for the downstream design agent.",
10522
+ expectedContents: ["Selected prompt format", "reference pattern board", "route guardrails"],
10523
+ howToUse: ["Read first", "treat captured evidence as creative priority", "use guardrails to avoid route drift"],
10524
+ mustNot: ["Do not treat defaults as stronger than captured references"]
10525
+ },
10526
+ [INSPIREDESIGN_HANDOFF_FILES.designMarkdown]: {
10527
+ purpose: "Human-readable design specification and implementation narrative.",
10528
+ expectedContents: ["inspiration analysis", "unified direction", "governance summary", "deliverables"],
10529
+ howToUse: ["Use as the readable project brief", "cross-check implementation choices against its sections"],
10530
+ mustNot: ["Do not use prose as a substitute for the JSON contract when patching Canvas"]
10531
+ },
10532
+ [INSPIREDESIGN_HANDOFF_FILES.designContract]: {
10533
+ purpose: "Narrowed Canvas governance contract for design decisions.",
10534
+ expectedContents: ["emitted governance blocks", "motion system", "library policy", "runtime budgets"],
10535
+ howToUse: ["Patch only emitted governance blocks", "compare implementation against this contract before shipping"],
10536
+ mustNot: ["Do not add navigation, async, or performance context as Canvas governance patches"]
10537
+ },
10538
+ [INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest]: {
10539
+ purpose: "Ready-to-fill request payload for `canvas.plan.set`.",
10540
+ expectedContents: ["request ids", "Canvas session ids", "mutation-safe generationPlan"],
10541
+ howToUse: ["Fill canvasSessionId, leaseId, and documentId", "submit with the provided canvas.plan.set command"],
10542
+ mustNot: ["Do not add handoff-only fields or reference-only analysis to generationPlan"]
10543
+ },
10544
+ [INSPIREDESIGN_HANDOFF_FILES.designAgentHandoff]: {
10545
+ purpose: "Downstream index for artifact usage, skills, commands, and omitted implementation context.",
10546
+ expectedContents: ["skills", "commands", "contract scope", "implementation context", "artifact and section guides"],
10547
+ howToUse: ["Use as the navigation map for the bundle", "load recommended skills before implementation"],
10548
+ mustNot: ["Do not treat handoff context as runtime Canvas schema"]
10549
+ },
10550
+ [INSPIREDESIGN_HANDOFF_FILES.generationPlan]: {
10551
+ purpose: "Full generated plan for reasoning about design intent.",
10552
+ expectedContents: ["Canvas plan fields", "design vectors", "reference analysis when available"],
10553
+ howToUse: ["Use for agent reasoning and audit traceability", "compare with canvas-plan.request.json for runtime subset"],
10554
+ mustNot: ["Do not submit this file directly to Canvas when it contains non-request context"]
10555
+ },
10556
+ [INSPIREDESIGN_HANDOFF_FILES.implementationPlanMarkdown]: {
10557
+ purpose: "Human-readable engineering sequence for the first implementation pass.",
10558
+ expectedContents: ["build sequence", "component plan", "token strategy", "QA and risk checks"],
10559
+ howToUse: ["Convert sections into implementation tasks", "keep tests and browser validation aligned to the plan"],
10560
+ mustNot: ["Do not implement sections unsupported by brief or reference evidence"]
10561
+ },
10562
+ [INSPIREDESIGN_HANDOFF_FILES.implementationPlan]: {
10563
+ purpose: "Machine-readable implementation plan matching the Markdown plan.",
10564
+ expectedContents: ["architecture steps", "component inventory", "state and validation tasks"],
10565
+ howToUse: ["Use for structured task extraction", "keep it synchronized with implementation-plan.md"],
10566
+ mustNot: ["Do not treat it as a Canvas document patch payload"]
10567
+ },
10568
+ [INSPIREDESIGN_HANDOFF_FILES.evidence]: {
10569
+ purpose: "Evidence digest for brief, reference, capture, and design-vector provenance.",
10570
+ expectedContents: ["brief expansion", "reference outcomes", "capture attempts", "design vectors"],
10571
+ howToUse: ["Audit why choices were made", "prefer evidence over generic template defaults"],
10572
+ mustNot: ["Do not ignore failed or skipped capture statuses when judging confidence"]
10573
+ },
10574
+ [INSPIREDESIGN_HANDOFF_FILES.prototypeGuidance]: {
10575
+ purpose: "Optional first prototype guidance when the workflow requests prototype output.",
10576
+ expectedContents: ["prototype structure", "design-vector guidance", "browser proof checklist"],
10577
+ howToUse: ["Use only for the first prototype pass", "promote proven ideas back into contract-aligned work"],
10578
+ mustNot: ["Do not treat prototype guidance as final implementation authority"]
10579
+ }
10580
+ };
10581
+ var INSPIREDESIGN_CONTRACT_SECTION_GUIDE = {
10582
+ intent: {
10583
+ purpose: "Define why the design exists and what success means.",
10584
+ expectedContents: ["audience", "task", "success criteria", "trust posture"],
10585
+ howToUse: ["Validate the primary user job before styling", "reject sections that do not serve the task"],
10586
+ mustNot: ["Do not start visual polish before the audience and task are clear"]
10587
+ },
10588
+ generationPlan: {
10589
+ purpose: "Mutation-safe subset accepted by Canvas planning.",
10590
+ expectedContents: ["target outcome", "visual, layout, content, component, motion, responsive, accessibility posture"],
10591
+ howToUse: ["Submit only through canvas-plan.request.json", "repair generationPlanIssues before mutation"],
10592
+ mustNot: ["Do not add handoff-only guide fields to the Canvas generation plan"]
10593
+ },
10594
+ designLanguage: {
10595
+ purpose: "Name the coherent visual direction and token ownership.",
10596
+ expectedContents: ["direction", "style axes", "semantic token source", "approved libraries"],
10597
+ howToUse: ["Keep one design language per task", "align repeated components to semantic tokens"],
10598
+ mustNot: ["Do not mix unrelated visual families inside one surface"]
10599
+ },
10600
+ contentModel: {
10601
+ purpose: "Define real content, message hierarchy, and UI states.",
10602
+ expectedContents: ["primary message", "supporting messages", "states", "loading, empty, and error behavior"],
10603
+ howToUse: ["Use real content first", "plan non-happy-path states before polish"],
10604
+ mustNot: ["Do not ship placeholder copy as product content"]
10605
+ },
10606
+ layoutSystem: {
10607
+ purpose: "Describe page architecture and section rhythm.",
10608
+ expectedContents: ["grid", "containers", "spacing rhythm", "alignment rules"],
10609
+ howToUse: ["Use to place sections and scan units consistently", "verify desktop and mobile structure"],
10610
+ mustNot: ["Do not invent one-off layout rules for repeated sections"]
10611
+ },
10612
+ typographySystem: {
10613
+ purpose: "Define type families, scale, measure, and loading behavior.",
10614
+ expectedContents: ["families", "scale", "measure", "fallback policy", "loading strategy"],
10615
+ howToUse: ["Apply type hierarchy consistently", "avoid layout shift from font loading"],
10616
+ mustNot: ["Do not default to unapproved system stacks for a distinctive design"]
10617
+ },
10618
+ colorSystem: {
10619
+ purpose: "Define semantic color roles and theme behavior.",
10620
+ expectedContents: ["primary roles", "surface roles", "text roles", "state colors"],
10621
+ howToUse: ["Map repeated UI to semantic tokens", "validate contrast in every required theme"],
10622
+ mustNot: ["Do not scatter raw color values across leaf components"]
10623
+ },
10624
+ surfaceSystem: {
10625
+ purpose: "Define material, depth, borders, and background behavior.",
10626
+ expectedContents: ["surface hierarchy", "border rules", "shadow rules", "material effects"],
10627
+ howToUse: ["Use depth only to clarify hierarchy", "align material effects with design vectors"],
10628
+ mustNot: ["Do not turn every content group into a card by default"]
10629
+ },
10630
+ iconSystem: {
10631
+ purpose: "Define icon usage and decorative asset boundaries.",
10632
+ expectedContents: ["icon family", "stroke policy", "labeling rules", "decorative rules"],
10633
+ howToUse: ["Use icons to clarify actions", "keep accessible names on icon-only controls"],
10634
+ mustNot: ["Do not rely on icons as the only explanation for critical actions"]
10635
+ },
10636
+ motionSystem: {
10637
+ purpose: "Define motion that supports comprehension.",
10638
+ expectedContents: ["timing", "interaction moments", "reduced-motion posture", "advanced motion advisory"],
10639
+ howToUse: ["Keep shader, WebGL, and Spline cues advisory", "provide reduced-motion replacements"],
10640
+ mustNot: ["Do not use motion cues to authorize new runtime libraries"]
10641
+ },
10642
+ responsiveSystem: {
10643
+ purpose: "Define authored behavior across desktop, tablet, and mobile.",
10644
+ expectedContents: ["breakpoints", "adaptation rules", "touch policy", "overflow policy"],
10645
+ howToUse: ["Validate the primary action at every viewport", "collapse structure before copy becomes cramped"],
10646
+ mustNot: ["Do not assume desktop layouts naturally scale down"]
10647
+ },
10648
+ accessibilityPolicy: {
10649
+ purpose: "Set accessibility requirements before implementation.",
10650
+ expectedContents: ["WCAG target", "keyboard requirements", "focus policy", "semantic requirements"],
10651
+ howToUse: ["Block release on contrast or keyboard regressions", "validate focus on every interactive state"],
10652
+ mustNot: ["Do not defer accessibility until after visual implementation"]
10653
+ },
10654
+ libraryPolicy: {
10655
+ purpose: "Declare approved implementation libraries and runtime boundaries.",
10656
+ expectedContents: ["components", "icons", "styling", "motion", "threeD"],
10657
+ howToUse: ["Use as the dependency authorization boundary", "keep motion and threeD empty unless separately approved"],
10658
+ mustNot: ["Do not infer WebGL, shader, Spline, or 3D runtime support from advisory motion"]
10659
+ },
10660
+ runtimeBudgets: {
10661
+ purpose: "Set practical limits for sections, actions, interaction latency, and preview cost.",
10662
+ expectedContents: ["section budgets", "action budgets", "latency budgets", "preview notes"],
10663
+ howToUse: ["Use as a constraint during implementation", "validate slow or animation-heavy surfaces against it"],
10664
+ mustNot: ["Do not add decorative weight that violates the budget"]
10665
+ },
10666
+ navigationModel: {
10667
+ purpose: "Implementation-only context for route, tab, overlay, and deep-link ownership.",
10668
+ expectedContents: ["route owner", "deep-link policy", "invalid route fallback", "overlay entry points"],
10669
+ howToUse: ["Use from design-agent-handoff.json when wiring implementation state"],
10670
+ mustNot: ["Do not patch this omitted block into Canvas governance"]
10671
+ },
10672
+ asyncModel: {
10673
+ purpose: "Implementation-only context for loading, restart, cancellation, and URL-owned query state.",
10674
+ expectedContents: ["owner", "load trigger", "restart triggers", "cancellation policy"],
10675
+ howToUse: ["Use when wiring fetch/search state and stale-request handling"],
10676
+ mustNot: ["Do not let components invent independent async ownership"]
10677
+ },
10678
+ performanceModel: {
10679
+ purpose: "Implementation-only context for render hotspots and measurement posture.",
10680
+ expectedContents: ["render hotspots", "stable identity policy", "list strategy", "measurement plan"],
10681
+ howToUse: ["Use before building scan-heavy or motion-heavy surfaces"],
10682
+ mustNot: ["Do not ship heavy interaction surfaces without measurement evidence"]
10683
+ }
10684
+ };
10162
10685
  var buildInspiredesignFollowthroughSummary = () => `Read ${INSPIREDESIGN_HANDOFF_FILES.advancedBrief} first, then continue in OpenDevBrowser Canvas with ${INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest} and ${INSPIREDESIGN_HANDOFF_FILES.designAgentHandoff}, load ${INSPIREDESIGN_HANDOFF_RECOMMENDED_SKILLS[0]} plus ${INSPIREDESIGN_HANDOFF_RECOMMENDED_SKILLS[1]} before implementation, and note that any supplied reference URL already uses captureMode=deep.`;
10163
10686
  var buildInspiredesignNextStep = () => `Read ${INSPIREDESIGN_HANDOFF_FILES.advancedBrief} first. ${INSPIREDESIGN_HANDOFF_GUIDANCE.prepareCanvasPlanRequest} Then run ${INSPIREDESIGN_HANDOFF_COMMANDS.continueInCanvas}, confirm planStatus=accepted, then patch only the governance blocks listed in ${INSPIREDESIGN_HANDOFF_FILES.designAgentHandoff}.`;
10164
10687
 
@@ -10169,11 +10692,14 @@ var inspiredesign_advanced_brief_v1_default = {
10169
10692
  commonRules: [
10170
10693
  "Preserve only the product, brand, audience, platform, and tone cues that are explicitly present in the source brief.",
10171
10694
  "Treat missing details as open constraints instead of inventing brand facts or user needs.",
10172
- "Use inspiration references to extract transferable design logic rather than copying a single layout, visual treatment, or narrative beat literally."
10695
+ "Use inspiration references to extract transferable design logic rather than copying a single layout, visual treatment, or narrative beat literally.",
10696
+ "Treat shader, WebGL, Spline-style, and 3D motion ideas as advisory design cues only, not as runtime support or dependency approval.",
10697
+ "Carry accepted advanced motion cues in designVectors and motionSystem as intent, and keep libraryPolicy authorization separate."
10173
10698
  ],
10174
10699
  outputRequirements: [
10175
10700
  "Return a reusable design contract that can drive design.md, implementation-plan artifacts, and a Canvas-ready prototype path.",
10176
- "Keep the direction premium, specific, and implementable instead of generic or template-driven."
10701
+ "Keep the direction premium, specific, and implementable instead of generic or template-driven.",
10702
+ "Keep libraryPolicy.motion and libraryPolicy.threeD empty in generated samples unless a separate runtime change explicitly approves those libraries."
10177
10703
  ],
10178
10704
  formats: [
10179
10705
  {
@@ -10182,12 +10708,15 @@ var inspiredesign_advanced_brief_v1_default = {
10182
10708
  bestFor: [
10183
10709
  "product homepages",
10184
10710
  "docs homepages",
10711
+ "consulting service homepages",
10185
10712
  "launch pages",
10186
10713
  "rebrands"
10187
10714
  ],
10188
10715
  businessFocus: [
10189
10716
  "premium SaaS marketing",
10190
10717
  "product launches",
10718
+ "AI consulting services",
10719
+ "enterprise advisory landing pages",
10191
10720
  "docs-first brands",
10192
10721
  "brand refresh surfaces"
10193
10722
  ],
@@ -10199,6 +10728,11 @@ var inspiredesign_advanced_brief_v1_default = {
10199
10728
  "editorial",
10200
10729
  "hero",
10201
10730
  "marketing",
10731
+ "consulting",
10732
+ "advisory",
10733
+ "enterprise AI",
10734
+ "services",
10735
+ "case studies",
10202
10736
  "docs"
10203
10737
  ],
10204
10738
  matchSignals: {
@@ -10212,6 +10746,16 @@ var inspiredesign_advanced_brief_v1_default = {
10212
10746
  "editorial",
10213
10747
  "hero",
10214
10748
  "marketing",
10749
+ "consulting",
10750
+ "advisory",
10751
+ "ai consulting",
10752
+ "enterprise ai",
10753
+ "business services",
10754
+ "client services",
10755
+ "case studies",
10756
+ "transformation",
10757
+ "services",
10758
+ "cta",
10215
10759
  "docs"
10216
10760
  ],
10217
10761
  excluded: [
@@ -10219,7 +10763,7 @@ var inspiredesign_advanced_brief_v1_default = {
10219
10763
  "admin",
10220
10764
  "onboarding"
10221
10765
  ],
10222
- tieBreaker: 1
10766
+ tieBreaker: 2
10223
10767
  },
10224
10768
  lead: "Study the inspiration references and synthesize a premium editorial landing page system that translates the source brief into a reusable, brand-specific direction.",
10225
10769
  archetype: "editorial brand campaign",
@@ -10638,17 +11182,22 @@ var inspiredesign_advanced_brief_v1_default = {
10638
11182
  label: "Maison campaign world",
10639
11183
  bestFor: [
10640
11184
  "luxury fashion",
11185
+ "fashion design studios",
10641
11186
  "fragrance launches",
10642
11187
  "jewelry campaigns",
10643
11188
  "premium hospitality brands"
10644
11189
  ],
10645
11190
  businessFocus: [
10646
11191
  "fashion maisons",
11192
+ "fashion design studios",
10647
11193
  "luxury accessories",
10648
11194
  "fragrance campaigns",
10649
11195
  "high-end hospitality identity"
10650
11196
  ],
10651
11197
  keywords: [
11198
+ "fashion",
11199
+ "fashion design",
11200
+ "fashion studio",
10652
11201
  "maison",
10653
11202
  "atelier",
10654
11203
  "collection",
@@ -10660,6 +11209,9 @@ var inspiredesign_advanced_brief_v1_default = {
10660
11209
  ],
10661
11210
  matchSignals: {
10662
11211
  positive: [
11212
+ "fashion",
11213
+ "fashion design",
11214
+ "fashion studio",
10663
11215
  "maison",
10664
11216
  "atelier",
10665
11217
  "collection",
@@ -10904,7 +11456,7 @@ var inspiredesign_advanced_brief_v1_default = {
10904
11456
  },
10905
11457
  {
10906
11458
  id: "luminous-research-atlas",
10907
- label: "Luminous research atlas",
11459
+ label: "Luminous insight landing page",
10908
11460
  bestFor: [
10909
11461
  "AI labs",
10910
11462
  "think tanks",
@@ -10914,15 +11466,14 @@ var inspiredesign_advanced_brief_v1_default = {
10914
11466
  businessFocus: [
10915
11467
  "research organizations",
10916
11468
  "evidence-led storytelling",
10917
- "atlas and observatory products",
10918
- "methodology-rich publications"
11469
+ "insight-led public landing pages",
11470
+ "visual research narratives"
10919
11471
  ],
10920
11472
  keywords: [
10921
11473
  "atlas",
10922
11474
  "observatory",
10923
- "methodology",
11475
+ "insight",
10924
11476
  "evidence",
10925
- "report",
10926
11477
  "research",
10927
11478
  "index",
10928
11479
  "publication"
@@ -10931,9 +11482,8 @@ var inspiredesign_advanced_brief_v1_default = {
10931
11482
  positive: [
10932
11483
  "atlas",
10933
11484
  "observatory",
10934
- "methodology",
11485
+ "insight",
10935
11486
  "evidence",
10936
- "report",
10937
11487
  "research",
10938
11488
  "map",
10939
11489
  "model",
@@ -10943,37 +11493,43 @@ var inspiredesign_advanced_brief_v1_default = {
10943
11493
  excluded: [
10944
11494
  "checkout",
10945
11495
  "festival",
10946
- "villa"
11496
+ "villa",
11497
+ "consulting",
11498
+ "advisory",
11499
+ "bcg",
11500
+ "services",
11501
+ "landing page",
11502
+ "homepage"
10947
11503
  ],
10948
- tieBreaker: 3
11504
+ tieBreaker: 1
10949
11505
  },
10950
- lead: "Study the inspiration references and synthesize a luminous research atlas that turns evidence, methodology, and narrative into a premium, readable system.",
10951
- archetype: "annotated evidence atlas",
10952
- layoutArchetype: "bright scroll atlas with chaptered evidence bands and annotation rails",
11506
+ lead: "Study the inspiration references and synthesize a luminous insight landing page that turns research-backed ideas into a premium, text-light public story.",
11507
+ archetype: "luminous insight landing page",
11508
+ layoutArchetype: "full-bleed insight story with visual proof bands",
10953
11509
  typographySystem: "precise sans for data and narrative paired with restrained serif emphasis",
10954
- surfaceTreatment: "ivory research planes, layered evidence visuals, and quiet annotation rails",
10955
- shapeLanguage: "clean modules, chart frames, citation bars, and highlighted note rails",
10956
- componentGrammar: "evidence chapters, methodology blocks, chart plates, callout annotations, citation modules",
10957
- motionGrammar: "zoom-and-highlight transitions, subtle annotation reveals, and calm data emphasis",
11510
+ surfaceTreatment: "ivory research planes, layered evidence visuals, and generous image-led whitespace",
11511
+ shapeLanguage: "clean modules, visual proof frames, and quiet emphasis bands",
11512
+ componentGrammar: "hero composition, insight proof bands, visual story panels, outcome moments, restrained CTA groups",
11513
+ motionGrammar: "calm reveal transitions, proof-panel emphasis, and restrained visual depth",
10958
11514
  paletteIntent: "bright ivory base with measured accent coding for evidence groups",
10959
11515
  visualDensity: "balanced",
10960
11516
  designVariance: "structured expressiveness",
10961
11517
  focusAreas: [
10962
11518
  "evidence hierarchy",
10963
- "methodology framing",
10964
- "annotation rails",
10965
- "chart grammar",
10966
- "citation treatment",
11519
+ "insight framing",
11520
+ "visual proof bands",
11521
+ "chart restraint",
11522
+ "public story cadence",
10967
11523
  "scroll-story beats",
10968
11524
  "proof sequencing"
10969
11525
  ],
10970
11526
  responsiveCollapseRules: [
10971
- "Collapse annotation rails beneath the primary evidence block before reducing chart legibility.",
10972
- "Keep citations attached to the relevant section on mobile instead of moving them to a distant appendix treatment."
11527
+ "Collapse visual proof bands into a single readable story stack before reducing chart legibility.",
11528
+ "Keep evidence labels visually close to the relevant section without turning mobile into an appendix."
10973
11529
  ],
10974
11530
  guardrails: [
10975
- "Keep the surface bright, exact, and evidence-first rather than dashboard-like or cyber-styled.",
10976
- "Use motion only to clarify how the user should read charts, maps, and methodology layers."
11531
+ "Keep the surface bright, exact, and evidence-led without becoming a documentation hub.",
11532
+ "Use motion to clarify priority, proof, and action rather than to explain long-form methodology."
10977
11533
  ],
10978
11534
  antiPatterns: [
10979
11535
  "No cyber glow.",
@@ -10982,14 +11538,14 @@ var inspiredesign_advanced_brief_v1_default = {
10982
11538
  "No unexplained iconography."
10983
11539
  ],
10984
11540
  deliverables: [
10985
- "Define the evidence hierarchy, chart grammar, annotation system, citation treatment, and scroll-story beats.",
10986
- "Return a premium research contract detailed enough for publication surfaces and Canvas-ready implementation."
11541
+ "Define the evidence hierarchy, visual proof rhythm, insight story cadence, and conversion path.",
11542
+ "Return a premium insight landing contract detailed enough for a visually led Canvas-ready implementation."
10987
11543
  ],
10988
11544
  route: {
10989
- profile: "documentation",
11545
+ profile: "product-story",
10990
11546
  themeStrategy: "single-theme",
10991
- navigationModel: "contextual",
10992
- layoutApproach: "annotated-atlas-scroll"
11547
+ navigationModel: "global-header",
11548
+ layoutApproach: "insight-led-landing-page"
10993
11549
  }
10994
11550
  },
10995
11551
  {
@@ -11304,7 +11860,13 @@ var inspiredesign_advanced_brief_v1_default = {
11304
11860
  excluded: [
11305
11861
  "villa",
11306
11862
  "festival",
11307
- "fragrance"
11863
+ "fragrance",
11864
+ "fashion",
11865
+ "fashion design",
11866
+ "maison",
11867
+ "couture",
11868
+ "collection",
11869
+ "campaign"
11308
11870
  ],
11309
11871
  tieBreaker: 3
11310
11872
  },
@@ -11537,6 +12099,8 @@ var inspiredesign_advanced_brief_v1_default = {
11537
12099
  // src/inspiredesign/brief-expansion.ts
11538
12100
  var BRIEF_TEMPLATE = inspiredesign_advanced_brief_v1_default;
11539
12101
  var INSPIREDESIGN_BRIEF_TEMPLATE_VERSION = BRIEF_TEMPLATE.version;
12102
+ var INSPIREDESIGN_BRIEF_COMMON_RULES = [...BRIEF_TEMPLATE.commonRules];
12103
+ var INSPIREDESIGN_BRIEF_OUTPUT_REQUIREMENTS = [...BRIEF_TEMPLATE.outputRequirements];
11540
12104
  var normalizeInspiredesignBriefText = (value) => value.trim().replace(/\s+/g, " ");
11541
12105
  var formatBulletList = (items) => items.map((item) => `- ${item}`).join("\n");
11542
12106
  var countMatches = (brief, keywords) => {
@@ -11546,6 +12110,20 @@ var countMatches = (brief, keywords) => {
11546
12110
  0
11547
12111
  );
11548
12112
  };
12113
+ var escapeRegExp2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12114
+ var removeNegativeSignal = (brief, keyword) => {
12115
+ const escaped = escapeRegExp2(keyword.toLowerCase());
12116
+ const modifiers = "(?:[a-z0-9-]+\\s+){0,3}";
12117
+ return brief.replace(new RegExp(`\\b(?:not|no|without|avoid|exclude|excluding)\\s+(?:an?\\s+|the\\s+)?${modifiers}${escaped}\\b(?:\\s+[a-z0-9-]+){0,2}`, "g"), " ").replace(new RegExp(`\\b${escaped}\\s+(?:is\\s+)?(?:not|excluded|forbidden)\\b`, "g"), " ");
12118
+ };
12119
+ var positiveSignalText = (brief, formats) => {
12120
+ const keywords = formats.flatMap((format) => [
12121
+ ...format.matchSignals.positive,
12122
+ ...format.matchSignals.required ?? [],
12123
+ ...format.matchSignals.excluded ?? []
12124
+ ]);
12125
+ return [...new Set(keywords)].reduce(removeNegativeSignal, brief.toLowerCase());
12126
+ };
11549
12127
  var cloneStringList = (items) => [...items];
11550
12128
  var cloneRoute = (route) => ({
11551
12129
  profile: route.profile,
@@ -11569,6 +12147,7 @@ var cloneInspiredesignBriefFormat = (format) => ({
11569
12147
  paletteIntent: format.paletteIntent,
11570
12148
  visualDensity: format.visualDensity,
11571
12149
  designVariance: format.designVariance,
12150
+ focusAreas: cloneStringList(format.focusAreas ?? []),
11572
12151
  responsiveCollapseRules: cloneStringList(format.responsiveCollapseRules),
11573
12152
  guardrails: cloneStringList(format.guardrails),
11574
12153
  antiPatterns: cloneStringList(format.antiPatterns),
@@ -11591,6 +12170,7 @@ var summarizeFormat = (format) => ({
11591
12170
  paletteIntent: format.paletteIntent,
11592
12171
  visualDensity: format.visualDensity,
11593
12172
  designVariance: format.designVariance,
12173
+ focusAreas: cloneStringList(format.focusAreas),
11594
12174
  responsiveCollapseRules: cloneStringList(format.responsiveCollapseRules),
11595
12175
  guardrails: cloneStringList(format.guardrails),
11596
12176
  antiPatterns: cloneStringList(format.antiPatterns),
@@ -11611,12 +12191,13 @@ var findFormatById = (formatId) => {
11611
12191
  return BRIEF_TEMPLATE.formats.find((format) => format.id === formatId);
11612
12192
  };
11613
12193
  var scoreFormat = (sourceBrief, format) => {
11614
- const requiredMatches = countMatches(sourceBrief, format.matchSignals.required ?? []);
12194
+ const brief = positiveSignalText(sourceBrief, BRIEF_TEMPLATE.formats);
12195
+ const requiredMatches = countMatches(brief, format.matchSignals.required ?? []);
11615
12196
  if ((format.matchSignals.required?.length ?? 0) > 0 && requiredMatches === 0) {
11616
12197
  return Number.NEGATIVE_INFINITY;
11617
12198
  }
11618
- const excludedMatches = countMatches(sourceBrief, format.matchSignals.excluded ?? []);
11619
- const positiveMatches = countMatches(sourceBrief, format.matchSignals.positive);
12199
+ const excludedMatches = countMatches(brief, format.matchSignals.excluded ?? []);
12200
+ const positiveMatches = countMatches(brief, format.matchSignals.positive);
11620
12201
  return positiveMatches * 4 + requiredMatches * 6 - excludedMatches * 8 + (format.matchSignals.tieBreaker ?? 0);
11621
12202
  };
11622
12203
  var chooseFormat = (sourceBrief) => {
@@ -11706,10 +12287,390 @@ var expandInspiredesignBrief = (brief, preferredFormatId) => {
11706
12287
  };
11707
12288
  };
11708
12289
 
11709
- // src/providers/inspiredesign-contract.ts
11710
- var INSPIREDESIGN_CAPTURE_ATTEMPT_KEYS = ["snapshot", "clone", "dom"];
11711
- var MALFORMED_CAPTURE_ATTEMPT_DETAIL = "Capture attempt metadata missing or malformed.";
11712
- var NORMALIZED_CAPTURE_ATTEMPT_DETAIL = "Captured artifact was empty after normalization.";
12290
+ // src/inspiredesign/reference-pattern-board.ts
12291
+ var SIGNAL_LIMIT = 5;
12292
+ var SIGNAL_CLIP = 180;
12293
+ var PATTERN_LIMIT = 6;
12294
+ var ADVANCED_MOTION_FIELDS = [
12295
+ "Advisory shader-style gradients: specify effect type, uniforms, static fallback, and reduced-motion replacement as design language only.",
12296
+ "Advisory WebGL-style depth cues: describe layered depth, camera-like parallax, and spatial hierarchy without requiring WebGL runtime.",
12297
+ "Advisory Spline-style staging: describe object-like hero composition, scene count, camera posture, depth model, asset source, and spatial sequencing as implementation guidance only.",
12298
+ "Advanced motion performance policy: define frame budget, lazy loading, offscreen pause behavior, and vestibular risk before implementation.",
12299
+ "Runtime boundary: implement with approved CSS and Canvas-safe primitives unless explicit source-owned runtime support is added later."
12300
+ ];
12301
+ var trimText = (value) => value.trim().replace(/\s+/g, " ");
12302
+ var clipText = (value, maxLength) => {
12303
+ if (value.length <= maxLength) return value;
12304
+ return `${value.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;
12305
+ };
12306
+ var textFromHtml = (html) => {
12307
+ return html ? trimText(html.replace(/<[^>]+>/g, " ")) : void 0;
12308
+ };
12309
+ var stripActionRefs = (value) => value.replace(/\[r\d+\]\s+(?:link|button|combobox|textbox|option)\s+/gi, "").replace(/\[r\d+\]\s+/gi, "").replace(/\bvalue=/gi, "");
12310
+ var isCodeOrCssPreview = (value) => {
12311
+ const lower = value.toLowerCase();
12312
+ return lower.includes("dangerouslysetinnerhtml") || lower.includes("opendevbrowser-root") || lower.includes("align-content:") || lower.startsWith("import ") || /^[.#][a-z0-9_-]+\s*\{/.test(lower) || lower.includes("{") && /[a-z-]+:\s*[^;]+;/.test(lower);
12313
+ };
12314
+ var cleanEvidenceText = (value) => {
12315
+ return trimText(stripActionRefs(value).replace(/[{};]/g, " "));
12316
+ };
12317
+ var DIAGNOSTIC_TEXT_MARKERS = [
12318
+ "authentication required",
12319
+ "sign in",
12320
+ "login required",
12321
+ "challenge page",
12322
+ "access denied",
12323
+ "browser capture unavailable",
12324
+ "javascript required",
12325
+ "javascript is required",
12326
+ "captcha",
12327
+ "verification challenge",
12328
+ "enable cookies",
12329
+ "checking if the site connection is secure",
12330
+ "complete the verification",
12331
+ "blocked reference"
12332
+ ];
12333
+ var PUBLIC_LANDING_TEXT_MARKERS = [
12334
+ "church",
12335
+ "landing page",
12336
+ "homepage",
12337
+ "home page",
12338
+ "consulting",
12339
+ "advisory",
12340
+ "bcg",
12341
+ "ai consulting",
12342
+ "enterprise ai",
12343
+ "transformation",
12344
+ "client services",
12345
+ "business services",
12346
+ "case studies",
12347
+ "clients",
12348
+ "industries",
12349
+ "worship",
12350
+ "locations",
12351
+ "gallery",
12352
+ "atelier",
12353
+ "fashion"
12354
+ ];
12355
+ var PUBLIC_LANDING_SUPPORT_MARKERS = [
12356
+ "online",
12357
+ "events",
12358
+ "studio",
12359
+ "website",
12360
+ "full-bleed",
12361
+ "hero",
12362
+ "story",
12363
+ "stories",
12364
+ "services",
12365
+ "service",
12366
+ "cta"
12367
+ ];
12368
+ var isDiagnosticText = (value) => {
12369
+ const lower = value.toLowerCase();
12370
+ return DIAGNOSTIC_TEXT_MARKERS.some((marker) => lower.includes(marker));
12371
+ };
12372
+ var hasPublicLandingSignal = (value) => {
12373
+ const lower = value.toLowerCase();
12374
+ const strongCount = PUBLIC_LANDING_TEXT_MARKERS.filter((marker) => lower.includes(marker)).length;
12375
+ const supportCount = PUBLIC_LANDING_SUPPORT_MARKERS.filter((marker) => lower.includes(marker)).length;
12376
+ const visualLandingCombo = lower.includes("hero") && (lower.includes("full-bleed") || lower.includes("cta") || lower.includes("website"));
12377
+ return visualLandingCombo || strongCount >= 2 || strongCount >= 1 && strongCount + supportCount >= 2;
12378
+ };
12379
+ var pushSignal = (signals, value) => {
12380
+ if (!value || isCodeOrCssPreview(value)) return;
12381
+ const text = cleanEvidenceText(value);
12382
+ if (isCodeOrCssPreview(text) || isDiagnosticText(text)) return;
12383
+ if (text.length > 0 && !signals.includes(text)) {
12384
+ signals.push(text);
12385
+ }
12386
+ };
12387
+ var getInspiredesignReferenceSignals = (reference) => {
12388
+ const signals = [];
12389
+ pushSignal(signals, reference.title);
12390
+ pushSignal(signals, reference.excerpt);
12391
+ pushSignal(signals, reference.capture?.title);
12392
+ pushSignal(signals, reference.capture?.snapshot?.content);
12393
+ pushSignal(signals, textFromHtml(reference.capture?.clone?.componentPreview));
12394
+ pushSignal(signals, reference.capture?.clone?.cssPreview);
12395
+ pushSignal(signals, textFromHtml(reference.capture?.dom?.outerHTML));
12396
+ return signals.map((signal) => clipText(signal, SIGNAL_CLIP)).slice(0, SIGNAL_LIMIT);
12397
+ };
12398
+ var hasCleanSignal = (value) => {
12399
+ if (!value || isCodeOrCssPreview(value)) return false;
12400
+ const text = cleanEvidenceText(value);
12401
+ return text.length > 0 && !isCodeOrCssPreview(text) && !isDiagnosticText(text);
12402
+ };
12403
+ var hasUsableCloneCreativeEvidence = (reference) => hasCleanSignal(reference.capture?.clone?.componentPreview);
12404
+ var hasUsableCaptureEvidence = (reference) => hasCleanSignal(reference.capture?.snapshot?.content) || hasUsableCloneCreativeEvidence(reference) || hasCleanSignal(textFromHtml(reference.capture?.dom?.outerHTML));
12405
+ var hasInspiredesignUsableReferenceEvidence = (reference) => {
12406
+ if (reference.captureStatus === "captured" && hasUsableCaptureEvidence(reference)) return true;
12407
+ return reference.fetchStatus === "captured" && (hasCleanSignal(reference.title) || hasCleanSignal(reference.excerpt));
12408
+ };
12409
+ var firstSignal = (reference) => {
12410
+ const preferred = [
12411
+ reference.capture?.title,
12412
+ reference.capture?.snapshot?.content,
12413
+ textFromHtml(reference.capture?.clone?.componentPreview),
12414
+ textFromHtml(reference.capture?.dom?.outerHTML),
12415
+ reference.excerpt,
12416
+ reference.title
12417
+ ].map((value) => value ? cleanEvidenceText(value) : "").find((value) => value.length > 0 && !isCodeOrCssPreview(value) && !isDiagnosticText(value));
12418
+ return preferred ? clipText(preferred, SIGNAL_CLIP) : reference.url;
12419
+ };
12420
+ var REFERENCE_PATTERN_RULES = [
12421
+ {
12422
+ summary: "location-first church discovery with regional pathways",
12423
+ matches: ["find a church", "church locations", "location", "city or postcode", "current location"]
12424
+ },
12425
+ {
12426
+ summary: "worship and music content as atmosphere and ministry proof",
12427
+ matches: ["music", "worship", "united", "young & free", "chapel", "instrumentals"]
12428
+ },
12429
+ {
12430
+ summary: "global region navigation with online participation path",
12431
+ matches: ["asia pacific", "europe", "north america", "latin america", "africa", "middle east", "online"]
12432
+ },
12433
+ {
12434
+ summary: "story-led editorial pathway after the primary church action",
12435
+ matches: ["stories", "blog", "start reading", "newsroom"]
12436
+ },
12437
+ {
12438
+ summary: "ministry ecosystem pathways for college, conferences, and events",
12439
+ matches: ["college", "conference", "tours", "events"]
12440
+ },
12441
+ {
12442
+ summary: "multilingual/global audience affordance",
12443
+ matches: ["language", '"en"', '"fr"', '"es"', '"pt"', '"de"']
12444
+ },
12445
+ {
12446
+ summary: "full-bleed hero with restrained CTA rail",
12447
+ matches: ["full-bleed", "hero", "cta rail", "primary cta"]
12448
+ },
12449
+ {
12450
+ summary: "premium consulting public landing page with service narrative, client proof, and conversion CTAs",
12451
+ matches: ["consulting", "advisory", "bcg", "enterprise ai", "transformation", "client services", "case studies", "industries"]
12452
+ }
12453
+ ];
12454
+ var ruleMatches = (text, rule) => {
12455
+ const lower = text.toLowerCase();
12456
+ return rule.matches.some((match) => lower.includes(match));
12457
+ };
12458
+ var derivePatternSummaries = (signals, fallback) => {
12459
+ const text = signals.join(" ");
12460
+ const matches = REFERENCE_PATTERN_RULES.filter((rule) => ruleMatches(text, rule)).map((rule) => rule.summary);
12461
+ return matches.length > 0 ? matches.slice(0, PATTERN_LIMIT) : [fallback];
12462
+ };
12463
+ var appendSourceDetail = (patterns, primarySignal) => {
12464
+ if (patterns.some((pattern) => primarySignal.toLowerCase().includes(pattern.toLowerCase()))) {
12465
+ return patterns;
12466
+ }
12467
+ return [...patterns, `source detail: ${primarySignal}`].slice(0, PATTERN_LIMIT);
12468
+ };
12469
+ var deriveCapturedVia = (reference) => {
12470
+ const methods = [];
12471
+ if (reference.fetchStatus === "captured") methods.push("fetch");
12472
+ if (reference.capture?.snapshot?.content.trim()) methods.push("snapshot");
12473
+ if (hasUsableCloneCreativeEvidence(reference)) {
12474
+ methods.push("clone");
12475
+ }
12476
+ if (reference.capture?.dom?.outerHTML.trim()) methods.push("dom");
12477
+ return methods;
12478
+ };
12479
+ var deriveComponentFamilies = (format, patterns, isPublicLanding) => {
12480
+ const base = isPublicLanding ? "hero composition, proof bands, narrative pathways, service or story sections, conversion CTA, and footer" : format.componentGrammar;
12481
+ return [base, ...patterns.slice(0, 3)];
12482
+ };
12483
+ var hasReferencePublicLandingEvidence = (reference) => {
12484
+ const text = [
12485
+ reference.surfaceType,
12486
+ reference.layoutRecipe,
12487
+ ...reference.contentHierarchy,
12488
+ ...reference.patternsToBorrow
12489
+ ].join(" ");
12490
+ return hasPublicLandingSignal(text);
12491
+ };
12492
+ var hasBoardPublicLandingEvidence = (board) => board.references.some(hasReferencePublicLandingEvidence);
12493
+ var boardEvidenceText = (board) => board.references.map((reference) => [
12494
+ reference.layoutRecipe,
12495
+ ...reference.contentHierarchy,
12496
+ ...reference.componentFamilies,
12497
+ ...reference.motionPosture,
12498
+ ...reference.patternsToBorrow
12499
+ ].join(" ")).join(" ").toLowerCase();
12500
+ var hasEvidenceCue = (text, matches) => matches.some((match) => text.includes(match));
12501
+ var deriveReferenceEntry = (reference, format) => {
12502
+ const signals = getInspiredesignReferenceSignals(reference);
12503
+ const primarySignal = firstSignal(reference);
12504
+ const patterns = appendSourceDetail(derivePatternSummaries(signals, primarySignal), primarySignal);
12505
+ const isPublicLanding = signals.some(hasPublicLandingSignal);
12506
+ return {
12507
+ id: reference.id,
12508
+ name: reference.title ?? reference.url,
12509
+ url: reference.url,
12510
+ surfaceType: isPublicLanding ? "public landing page" : format.archetype,
12511
+ capturedVia: deriveCapturedVia(reference),
12512
+ layoutRecipe: patterns.join("; "),
12513
+ contentHierarchy: patterns.slice(0, 4),
12514
+ componentFamilies: deriveComponentFamilies(format, patterns, isPublicLanding),
12515
+ motionPosture: [format.motionGrammar, "Plan hero reveal, scroll reveal, CTA feedback, and reduced-motion behavior."],
12516
+ tokenNotes: [format.paletteIntent, format.typographySystem, format.surfaceTreatment],
12517
+ patternsToBorrow: [...patterns, ...signals.slice(0, 2)].slice(0, PATTERN_LIMIT),
12518
+ patternsToReject: [...format.antiPatterns],
12519
+ whyItWorks: reference.captureStatus === "captured" ? "Captured reference evidence provides reusable hierarchy, rhythm, and component cues." : "Available reference text provides directional content and hierarchy cues."
12520
+ };
12521
+ };
12522
+ var buildInspiredesignReferencePatternBoard = (briefId, format, references) => {
12523
+ const entries = references.filter(hasInspiredesignUsableReferenceEvidence).map((reference) => deriveReferenceEntry(reference, format));
12524
+ const sharedStrengths = entries.flatMap((entry) => entry.patternsToBorrow).slice(0, 6);
12525
+ const targetSurface = entries.some((entry) => entry.surfaceType === "public landing page") ? "reference-led public landing page" : format.layoutArchetype;
12526
+ return {
12527
+ briefId,
12528
+ targetSurface,
12529
+ references: entries,
12530
+ synthesis: {
12531
+ dominantDirection: entries[0]?.layoutRecipe ?? format.archetype,
12532
+ sharedStrengths,
12533
+ sharedFailuresToAvoid: [...format.antiPatterns],
12534
+ contractDeltas: [
12535
+ "Selected prompt format supplies route defaults and guardrails, not the creative source of truth.",
12536
+ "Use captured reference hierarchy before generic profile defaults when URL evidence exists."
12537
+ ]
12538
+ }
12539
+ };
12540
+ };
12541
+ var buildInteractionDensity = (format, board) => {
12542
+ if (hasBoardPublicLandingEvidence(board)) {
12543
+ return "low-to-medium; prioritize confident public-page CTAs over app-shell controls.";
12544
+ }
12545
+ if (format.route.navigationModel === "sidebar") {
12546
+ return "medium-to-high; prioritize command surfaces, state clarity, and durable workspace controls.";
12547
+ }
12548
+ if (format.route.profile === "documentation") {
12549
+ return "low-to-medium; prioritize visual overview, proof scanning, and a small number of clear action paths.";
12550
+ }
12551
+ if (format.route.profile === "auth-focused") {
12552
+ return "low; prioritize one confident first action with clear feedback and trust cues.";
12553
+ }
12554
+ return "low-to-medium; prioritize confident public-page CTAs over app-shell controls.";
12555
+ };
12556
+ var buildImageryPosture = (format, board) => {
12557
+ if (hasBoardPublicLandingEvidence(board)) {
12558
+ return [format.surfaceTreatment, "Use dominant atmospheric imagery as the visual anchor."];
12559
+ }
12560
+ if (format.route.navigationModel === "sidebar") {
12561
+ return [format.surfaceTreatment, "Use product state, data hierarchy, and workspace continuity as the visual anchor."];
12562
+ }
12563
+ return [format.surfaceTreatment, "Use dominant atmospheric imagery as the visual anchor."];
12564
+ };
12565
+ var buildInteractionMoments = (format, board) => {
12566
+ const evidenceText = boardEvidenceText(board);
12567
+ const publicLanding = hasBoardPublicLandingEvidence(board);
12568
+ const referenceBacked = board.references.length > 0;
12569
+ const cursorScope = publicLanding ? "hero CTA, media reveals, and primary navigation moments" : "high-value actions and selected command surfaces";
12570
+ const moments = [
12571
+ "Microinteractions: define hover effects, visible focus rings, pressed states, loading states, and confirmation feedback for every primary action.",
12572
+ `Animation choreography: sequence ${format.motionGrammar}, hover feedback, active feedback, and page transitions through one timing system.`
12573
+ ];
12574
+ const cursorBacked = hasEvidenceCue(evidenceText, ["cursor", "magnetic", "follow-cursor", "pointer"]);
12575
+ const cursorPolicy = cursorBacked ? `Cursor effects: reference evidence supports premium pointer affordances for ${cursorScope}; keep default cursor behavior for reading surfaces.` : `Cursor effects policy: consider magnetic or follow-cursor affordances only when reference evidence supports ${cursorScope}.`;
12576
+ return referenceBacked ? [...moments, cursorPolicy] : moments;
12577
+ };
12578
+ var buildMaterialEffects = (board) => {
12579
+ if (board.references.length === 0) {
12580
+ return [
12581
+ "Material effects: define elevation, shadows, surface contrast, and reduced-motion-safe depth from the brief.",
12582
+ "Reduced-motion material fallback: preserve hierarchy and CTA clarity without transform-based depth."
12583
+ ];
12584
+ }
12585
+ const evidenceText = boardEvidenceText(board);
12586
+ const publicLanding = hasBoardPublicLandingEvidence(board);
12587
+ const glassScope = publicLanding ? "navigation overlays, hero scrims, and atmospheric CTA surfaces" : "focused overlays, inspectors, or state containers";
12588
+ const parallaxBacked = hasEvidenceCue(evidenceText, ["parallax", "depth", "layered", "immersive", "full-bleed"]);
12589
+ const glassBacked = hasEvidenceCue(evidenceText, ["glass", "frosted", "blur", "translucent", "scrim", "overlay"]);
12590
+ const parallax = parallaxBacked ? "Depth language: reference evidence supports restrained parallax, layered shadows, and atmospheric depth where it reinforces hierarchy." : "Depth language policy: use parallax only when reference evidence supports layered depth; otherwise use spacing, scale, and shadow hierarchy.";
12591
+ const glass = glassBacked ? `Glassmorphism/translucency: reference evidence supports frosted or translucent surfaces for ${glassScope}; never use glass as generic decoration.` : `Glassmorphism/translucency policy: use frosted or translucent surfaces only when reference evidence supports ${glassScope}.`;
12592
+ return [
12593
+ parallax,
12594
+ glass,
12595
+ "Reduced-motion material fallback: remove parallax and cursor-follow transforms while preserving hierarchy, depth, and CTA clarity."
12596
+ ];
12597
+ };
12598
+ var buildSectionArchitecture = (format, board) => {
12599
+ if (hasBoardPublicLandingEvidence(board)) {
12600
+ return [
12601
+ "Use 8 to 12 primary landing-page sections unless the user explicitly asks for a microsite.",
12602
+ "Build a clear sequence from hero, proof, story, service pathways, impact, conversion CTA, and footer."
12603
+ ];
12604
+ }
12605
+ if (format.route.profile === "documentation") {
12606
+ return [
12607
+ "Use a text-light overview sequence for purpose, proof, examples, action paths, and footer.",
12608
+ "Keep long-form reference depth, citation modules, annotation rails, and methodology blocks out of the primary visual route."
12609
+ ];
12610
+ }
12611
+ if (format.route.profile === "auth-focused") {
12612
+ return [
12613
+ "Use a screen sequence for value, trust, input, confirmation, and first-action transition.",
12614
+ "Keep the flow compact instead of expanding into marketing section sprawl."
12615
+ ];
12616
+ }
12617
+ if (format.route.navigationModel === "immersive") {
12618
+ return [
12619
+ "Use cinematic scene beats for hero, product reveal, proof, detail, and decisive CTA.",
12620
+ "Keep each scroll beat focused on one visual idea."
12621
+ ];
12622
+ }
12623
+ if (format.route.navigationModel === "sidebar") {
12624
+ return [
12625
+ "Use workspace shell zones for navigation, command surfaces, primary work area, detail panels, and state feedback.",
12626
+ "Prioritize task continuity over marketing-section cadence."
12627
+ ];
12628
+ }
12629
+ return [
12630
+ "Use 8 to 12 primary landing-page sections unless the user explicitly asks for a microsite.",
12631
+ "Build a clear sequence from hero, proof, story, service pathways, impact, conversion CTA, and footer."
12632
+ ];
12633
+ };
12634
+ var buildInspiredesignDesignVectors = (format, board) => {
12635
+ const influence = board.synthesis.sharedStrengths.length > 0 ? board.synthesis.sharedStrengths : [format.archetype];
12636
+ const publicLandingEvidence = hasBoardPublicLandingEvidence(board);
12637
+ const surfaceIntent = publicLandingEvidence ? "reference-led public landing page" : format.archetype;
12638
+ const compositionModel = publicLandingEvidence ? ["full-bleed hero with narrative section cadence", ...board.references.map((entry) => entry.layoutRecipe)] : [format.layoutArchetype, ...board.references.map((entry) => entry.layoutRecipe)];
12639
+ return {
12640
+ sourcePriority: board.references.length > 0 ? "reference-evidence-first" : "brief-only",
12641
+ directionLabel: board.synthesis.dominantDirection,
12642
+ surfaceIntent,
12643
+ compositionModel: compositionModel.slice(0, 5),
12644
+ premiumPosture: [
12645
+ "premium visual hierarchy, refined spacing, and editorial image treatment.",
12646
+ "Premium typography, spacing, visual hierarchy, palette, and image treatment must lead the page.",
12647
+ format.surfaceTreatment,
12648
+ format.paletteIntent
12649
+ ],
12650
+ motionPosture: [
12651
+ "Use a hero entrance reveal, section scroll reveal, and CTA/focus feedback.",
12652
+ "Respect reduced-motion preference with static hierarchy preserved.",
12653
+ format.motionGrammar
12654
+ ],
12655
+ sectionArchitecture: buildSectionArchitecture(format, board),
12656
+ typographyPosture: [format.typographySystem],
12657
+ imageryPosture: buildImageryPosture(format, board),
12658
+ interactionDensity: buildInteractionDensity(format, board),
12659
+ interactionMoments: buildInteractionMoments(format, board),
12660
+ materialEffects: buildMaterialEffects(board),
12661
+ advancedMotionAdvisory: [...ADVANCED_MOTION_FIELDS],
12662
+ referenceInfluence: influence,
12663
+ patternsToBorrow: board.references.flatMap((entry) => entry.patternsToBorrow).slice(0, 8),
12664
+ patternsToReject: board.references.flatMap((entry) => entry.patternsToReject).slice(0, 8),
12665
+ guardrails: [...format.guardrails],
12666
+ antiPatterns: [...format.antiPatterns]
12667
+ };
12668
+ };
12669
+
12670
+ // src/inspiredesign/contract.ts
12671
+ var INSPIREDESIGN_CAPTURE_ATTEMPT_KEYS = ["snapshot", "clone", "dom"];
12672
+ var MALFORMED_CAPTURE_ATTEMPT_DETAIL = "Capture attempt metadata missing or malformed.";
12673
+ var NORMALIZED_CAPTURE_ATTEMPT_DETAIL = "Captured artifact was empty after normalization.";
11713
12674
  var isJsonRecord2 = (value) => {
11714
12675
  return typeof value === "object" && value !== null && !Array.isArray(value);
11715
12676
  };
@@ -12012,15 +12973,15 @@ var PROFILE_CONFIG = {
12012
12973
  }
12013
12974
  },
12014
12975
  "documentation": {
12015
- direction: "reference-first documentation",
12016
- visualPersonality: "legible, calm, highly structured",
12017
- brandTone: "expert and accessible",
12018
- hierarchyPrinciples: ["Make scanning effortless.", "Keep code, steps, and warnings visually distinct."],
12019
- interactionPhilosophy: "Light motion, sticky wayfinding, strong anchor visibility.",
12976
+ direction: "text-light knowledge story",
12977
+ visualPersonality: "legible, calm, visually led",
12978
+ brandTone: "expert, concise, and accessible",
12979
+ hierarchyPrinciples: ["Make scanning effortless.", "Use visual proof before long explanatory text."],
12980
+ interactionPhilosophy: "Light motion, clear wayfinding, strong anchor visibility.",
12020
12981
  navigationModel: "sidebar",
12021
- layoutApproach: "docs-shell",
12022
- pagePatterns: ["Docs shell", "Procedure section", "Reference table block"],
12023
- componentSequence: ["Sidebar", "Search", "Anchored headings", "Code blocks", "Callouts"],
12982
+ layoutApproach: "knowledge-story-shell",
12983
+ pagePatterns: ["Insight overview", "Visual proof band", "Action path"],
12984
+ componentSequence: ["Navigation", "Search", "Anchored headings", "Proof bands", "Callouts"],
12024
12985
  colors: {
12025
12986
  primary: "#1D4ED8",
12026
12987
  accent: "#0F766E",
@@ -12036,37 +12997,425 @@ var PROFILE_CONFIG = {
12036
12997
  }
12037
12998
  }
12038
12999
  };
12039
- var trimText = (value) => {
13000
+ var trimText2 = (value) => {
12040
13001
  return value.trim().replace(/\s+/g, " ");
12041
13002
  };
12042
- var clipText = (value, maxLength) => {
13003
+ var clipText2 = (value, maxLength) => {
12043
13004
  if (value.length <= maxLength) return value;
12044
13005
  return `${value.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;
12045
13006
  };
13007
+ var REFERENCE_SUMMARY_CLIP_LENGTH = 220;
13008
+ var GENERATION_PLAN_REFERENCE_CLIP_LENGTH = 600;
13009
+ var buildReferenceSynthesis = (references) => {
13010
+ const lines = references.filter(hasInspiredesignUsableReferenceEvidence).map((reference, index) => {
13011
+ const signals = getInspiredesignReferenceSignals(reference);
13012
+ if (signals.length === 0) return "";
13013
+ return `Source ${index + 1} ${reference.title ?? reference.url}: ${signals.join(" | ")}`;
13014
+ }).filter((line) => line.length > 0);
13015
+ return {
13016
+ lines,
13017
+ summary: lines.length > 0 ? lines.map((line) => clipText2(line, REFERENCE_SUMMARY_CLIP_LENGTH)).join(" ") : "No live reference cues were captured."
13018
+ };
13019
+ };
13020
+ var renderReferenceFirstAdvancedBrief = (briefExpansion, board, vectors, references) => {
13021
+ if (board.references.length === 0) {
13022
+ if (references.length > 0) {
13023
+ return [
13024
+ "Reference evidence unavailable:",
13025
+ "URL references were attempted, but no usable creative evidence was captured. Treat this as a capture gap, not a design direction.",
13026
+ "",
13027
+ formatBulletList2(references.map((reference) => renderUnavailableReference(reference))),
13028
+ "",
13029
+ briefExpansion.advancedBrief
13030
+ ].join("\n");
13031
+ }
13032
+ return briefExpansion.advancedBrief;
13033
+ }
13034
+ return [
13035
+ "Reference pattern board:",
13036
+ "URL reference evidence is the creative source of truth when references are supplied.",
13037
+ "",
13038
+ "Reference evidence analysis:",
13039
+ formatBulletList2(board.references.map((reference) => `${reference.name}: ${reference.layoutRecipe}`)),
13040
+ "",
13041
+ "Design vectors:",
13042
+ formatBulletList2([
13043
+ `directionLabel: ${vectors.directionLabel}`,
13044
+ `surfaceIntent: ${vectors.surfaceIntent}`,
13045
+ `premiumPosture: ${vectors.premiumPosture.join(" ")}`,
13046
+ `motionPosture: ${vectors.motionPosture.join(" ")}`,
13047
+ `sectionArchitecture: ${vectors.sectionArchitecture.join(" ")}`,
13048
+ `interactionMoments: ${vectors.interactionMoments.join(" ")}`,
13049
+ `materialEffects: ${vectors.materialEffects.join(" ")}`,
13050
+ `advancedMotionAdvisory: ${vectors.advancedMotionAdvisory.join(" ")}`
13051
+ ]),
13052
+ "",
13053
+ "Fixed format guardrails:",
13054
+ "Selected prompt format supplies route defaults and guardrails, not the creative source of truth.",
13055
+ "",
13056
+ briefExpansion.advancedBrief
13057
+ ].join("\n");
13058
+ };
13059
+ var renderEvidenceDerivedAdvancedBrief = (briefExpansion, format) => [
13060
+ `Selected prompt format: ${format.label}`,
13061
+ "",
13062
+ "Source brief:",
13063
+ briefExpansion.sourceBrief,
13064
+ "",
13065
+ "Prompt objective:",
13066
+ `Use the reference evidence and source brief to define a ${format.archetype}.`,
13067
+ "",
13068
+ "Business focus:",
13069
+ formatBulletList2(format.businessFocus),
13070
+ "",
13071
+ "Keywords:",
13072
+ formatBulletList2(format.keywords),
13073
+ "",
13074
+ "Route defaults:",
13075
+ formatBulletList2([
13076
+ `profile: ${format.route.profile}`,
13077
+ `theme strategy: ${format.route.themeStrategy}`,
13078
+ `navigation model: ${format.route.navigationModel}`,
13079
+ `layout approach: ${format.route.layoutApproach}`
13080
+ ]),
13081
+ "",
13082
+ "Design direction:",
13083
+ formatBulletList2([
13084
+ `archetype: ${format.archetype}`,
13085
+ `layout archetype: ${format.layoutArchetype}`,
13086
+ `typography system: ${format.typographySystem}`,
13087
+ `surface treatment: ${format.surfaceTreatment}`,
13088
+ `shape language: ${format.shapeLanguage}`,
13089
+ `component grammar: ${format.componentGrammar}`,
13090
+ `motion grammar: ${format.motionGrammar}`,
13091
+ `palette intent: ${format.paletteIntent}`,
13092
+ `visual density: ${format.visualDensity}`,
13093
+ `design variance: ${format.designVariance}`
13094
+ ]),
13095
+ "",
13096
+ "Responsive collapse rules:",
13097
+ formatBulletList2(format.responsiveCollapseRules),
13098
+ "",
13099
+ "Focus areas:",
13100
+ formatBulletList2(format.focusAreas ?? []),
13101
+ "",
13102
+ "Execution rules:",
13103
+ formatBulletList2([...INSPIREDESIGN_BRIEF_COMMON_RULES, ...format.guardrails]),
13104
+ "",
13105
+ "Anti-patterns:",
13106
+ formatBulletList2(format.antiPatterns),
13107
+ "",
13108
+ "Return:",
13109
+ formatBulletList2([...INSPIREDESIGN_BRIEF_OUTPUT_REQUIREMENTS, ...format.deliverables]),
13110
+ "",
13111
+ "Best fit use cases:",
13112
+ formatBulletList2(format.bestFor)
13113
+ ].join("\n");
13114
+ var renderUnavailableReference = (reference) => {
13115
+ const reason = reference.fetchFailure ?? reference.captureFailure ?? "no usable creative evidence captured";
13116
+ return `${reference.url}: fetch=${reference.fetchStatus}, capture=${reference.captureStatus}, reason=${clipText2(reason, 160)}`;
13117
+ };
12046
13118
  var cloneTemplate = (value) => structuredClone(value);
12047
13119
  var referenceFingerprint = (value) => {
12048
13120
  return createHash3("sha256").update(value).digest("hex").slice(0, 12);
12049
13121
  };
12050
13122
  var summarizeBrief = (brief) => {
12051
- const normalized = trimText(brief);
13123
+ const normalized = trimText2(brief);
12052
13124
  const sentence = normalized.split(/[.!?]/).map((part) => part.trim()).find(Boolean);
12053
- return clipText(sentence ?? normalized, 140);
13125
+ return clipText2(sentence ?? normalized, 140);
12054
13126
  };
12055
13127
  var buildSupportingMessages = (references) => {
12056
- const messages = references.map((reference) => reference.title ?? reference.excerpt ?? "").map((value) => clipText(trimText(value), 72)).filter((value) => value.length > 0);
13128
+ const messages = references.map((reference) => reference.title ?? reference.excerpt ?? "").map((value) => clipText2(trimText2(value), 72)).filter((value) => value.length > 0);
12057
13129
  return messages.slice(0, 3);
12058
13130
  };
12059
- var buildGenerationPlan = (brief, format) => {
13131
+ var summarizeDesignVectors = (designVectors) => [
13132
+ `direction: ${designVectors.directionLabel}`,
13133
+ `sections: ${designVectors.sectionArchitecture.join(" ")}`,
13134
+ `motion: ${designVectors.motionPosture.slice(0, 1).join(" ")}`,
13135
+ `interactions: ${designVectors.interactionMoments.slice(0, 1).join(" ")}`,
13136
+ `materials: ${designVectors.materialEffects.slice(0, 1).join(" ")}`,
13137
+ `advancedMotion: ${designVectors.advancedMotionAdvisory.slice(0, 1).join(" ")}`
13138
+ ].join(" ");
13139
+ var isReferenceFirstPublicLanding = (designVectors) => {
13140
+ return designVectors.sourcePriority === "reference-evidence-first" && designVectors.surfaceIntent.toLowerCase().includes("public landing page");
13141
+ };
13142
+ var buildEvidenceDerivedFormat = (format, designVectors) => {
13143
+ const clone = cloneInspiredesignBriefFormat(format);
13144
+ if (!isReferenceFirstPublicLanding(designVectors)) return clone;
13145
+ return {
13146
+ ...clone,
13147
+ label: "Reference-led public landing page",
13148
+ archetype: "reference-led public landing page",
13149
+ layoutArchetype: "full-bleed hero with narrative section cadence",
13150
+ componentGrammar: "hero composition, proof bands, narrative pathways, service or story sections, conversion CTA, and footer",
13151
+ route: {
13152
+ ...clone.route,
13153
+ profile: "product-story",
13154
+ navigationModel: "global-header",
13155
+ layoutApproach: "reference-led-landing-page"
13156
+ }
13157
+ };
13158
+ };
13159
+ var TARGET_KIND_ORDER = ["page", "component", "asset"];
13160
+ var TARGET_CONFIDENCE = {
13161
+ defaultPage: 0.55,
13162
+ pageIntentStep: 0.05,
13163
+ nonPageBase: 0.55,
13164
+ intentStep: 0.08,
13165
+ supportingStep: 0.05,
13166
+ maxPage: 0.7,
13167
+ maxNonPage: 0.95
13168
+ };
13169
+ var TARGET_SIGNAL_PROFILES = {
13170
+ page: {
13171
+ intent: ["page", "landing page", "website", "homepage", "dashboard", "workspace", "screen", "flow", "surface", "microsite"],
13172
+ supporting: ["section", "sections", "navigation", "footer", "hero section", "conversion flow"],
13173
+ incidental: ["card", "cards", "button", "buttons", "image", "images", "media", "hero", "cta", "background"]
13174
+ },
13175
+ component: {
13176
+ intent: ["component", "component family", "reusable component", "component prototype", "hero component", "card component", "storybook"],
13177
+ supporting: ["prop", "props", "slot", "slots", "variant", "variants", "state matrix", "hover", "focus", "disabled", "loading", "error", "fixture", "fixtures", "arg", "args"],
13178
+ incidental: ["card", "cards", "button", "buttons", "form", "modal", "drawer", "navbar", "hero", "input", "tabs", "cta"]
13179
+ },
13180
+ asset: {
13181
+ intent: ["asset", "asset pack", "visual asset", "icon pack", "logo pack", "illustration set", "artwork set"],
13182
+ supporting: ["responsive variant", "responsive variants", "responsive artwork", "provenance", "usage rules", "alt text", "replacement rules", "tokenized usage", "source asset", "source assets"],
13183
+ incidental: ["icon", "icons", "illustration", "illustrations", "logo", "logos", "media", "image", "images", "background", "texture", "sprite", "artwork"]
13184
+ }
13185
+ };
13186
+ var buildTargetCorpus = (brief, references, synthesis) => [
13187
+ brief,
13188
+ synthesis.lines.join(" "),
13189
+ ...references.filter(hasInspiredesignUsableReferenceEvidence).flatMap((reference) => getInspiredesignReferenceSignals(reference))
13190
+ ].join(" ").toLowerCase();
13191
+ var escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13192
+ var matchesTargetSignal = (corpus, signal) => {
13193
+ const pattern = escapeRegex(signal.toLowerCase()).replace(/\s+/g, "\\s+");
13194
+ return new RegExp(`(^|[^a-z0-9])${pattern}([^a-z0-9]|$)`).test(corpus);
13195
+ };
13196
+ var findTargetSignalIndex = (corpus, signal) => {
13197
+ const pattern = escapeRegex(signal.toLowerCase()).replace(/\s+/g, "\\s+");
13198
+ return new RegExp(`(^|[^a-z0-9])${pattern}([^a-z0-9]|$)`).exec(corpus)?.index ?? null;
13199
+ };
13200
+ var findFirstBriefTargetKind = (brief) => {
13201
+ const corpus = brief.toLowerCase();
13202
+ const hits = TARGET_KIND_ORDER.flatMap((kind) => TARGET_SIGNAL_PROFILES[kind].intent.map((signal) => findTargetSignalIndex(corpus, signal)).filter((index) => index !== null).map((index) => ({ kind, index })));
13203
+ return hits.sort((left, right) => left.index - right.index)[0]?.kind ?? null;
13204
+ };
13205
+ var collectTargetSignals = (corpus) => {
13206
+ const collect = (kind) => {
13207
+ const profile = TARGET_SIGNAL_PROFILES[kind];
13208
+ return {
13209
+ intent: profile.intent.filter((signal) => matchesTargetSignal(corpus, signal)),
13210
+ supporting: profile.supporting.filter((signal) => matchesTargetSignal(corpus, signal)),
13211
+ incidental: profile.incidental.filter((signal) => matchesTargetSignal(corpus, signal))
13212
+ };
13213
+ };
13214
+ return {
13215
+ page: collect("page"),
13216
+ component: collect("component"),
13217
+ asset: collect("asset")
13218
+ };
13219
+ };
13220
+ var clampTargetConfidence = (value, max) => Math.min(max, Number(value.toFixed(2)));
13221
+ var buildPageConfidence = (signals) => {
13222
+ return clampTargetConfidence(
13223
+ TARGET_CONFIDENCE.defaultPage + signals.intent.length * TARGET_CONFIDENCE.pageIntentStep,
13224
+ TARGET_CONFIDENCE.maxPage
13225
+ );
13226
+ };
13227
+ var buildTargetEligibility = (kind, briefSignals, supportSignals) => {
13228
+ const eligible = briefSignals.intent.length > 0 && supportSignals.supporting.length > 0;
13229
+ const confidence = eligible ? clampTargetConfidence(
13230
+ TARGET_CONFIDENCE.nonPageBase + briefSignals.intent.length * TARGET_CONFIDENCE.intentStep + supportSignals.supporting.length * TARGET_CONFIDENCE.supportingStep,
13231
+ TARGET_CONFIDENCE.maxNonPage
13232
+ ) : 0;
13233
+ return {
13234
+ kind,
13235
+ eligible,
13236
+ confidence,
13237
+ triggeringSignals: [
13238
+ ...briefSignals.intent.map((signal) => `${kind} intent: ${signal}`),
13239
+ ...supportSignals.supporting.map((signal) => `${kind} support: ${signal}`)
13240
+ ]
13241
+ };
13242
+ };
13243
+ var choosePrimaryTargetKind = (pageConfidence, pageSignals, firstBriefTargetKind, component, asset) => {
13244
+ const eligibleTargets = [component, asset].filter((target) => target.eligible);
13245
+ if (eligibleTargets.length === 0) return { primaryKind: "page", reason: "no_non_page_gate" };
13246
+ if (firstBriefTargetKind === "page" && pageSignals.intent.length > 0) {
13247
+ return { primaryKind: "page", reason: "page_first_brief_target" };
13248
+ }
13249
+ const [first, second] = eligibleTargets.sort((left, right) => right.confidence - left.confidence);
13250
+ if (!first || first.confidence <= pageConfidence) {
13251
+ return { primaryKind: "page", reason: "non_page_did_not_beat_page" };
13252
+ }
13253
+ if (second && first.confidence === second.confidence && pageSignals.intent.length > 0) {
13254
+ return { primaryKind: "page", reason: "page_tie_break" };
13255
+ }
13256
+ return { primaryKind: first.kind, reason: "non_page_selected" };
13257
+ };
13258
+ var chooseTargetKinds = (primaryKind, component, asset) => {
13259
+ if (primaryKind === "page") return ["page"];
13260
+ const eligible = new Set([component, asset].filter((target) => target.eligible).map((target) => target.kind));
13261
+ const secondaryKinds = TARGET_KIND_ORDER.filter((kind) => kind !== primaryKind && eligible.has(kind));
13262
+ return [primaryKind, ...secondaryKinds];
13263
+ };
13264
+ var buildTriggeringSignals = (decision, signals, component, asset) => {
13265
+ const pageSignals = signals.page.intent.map((signal) => `page intent: ${signal}`);
13266
+ const eligibleTargets = [component, asset].filter((target) => target.eligible);
13267
+ const targetIntents = eligibleTargets.flatMap((target) => target.triggeringSignals.filter((signal) => signal.includes(" intent: ")));
13268
+ const targetSupport = eligibleTargets.flatMap((target) => target.triggeringSignals.filter((signal) => signal.includes(" support: ")));
13269
+ const defaultSignal = decision.primaryKind === "page" ? [buildPageDecisionSignal(decision.reason)] : [];
13270
+ return [...pageSignals, ...targetIntents, ...targetSupport, ...defaultSignal].slice(0, 12);
13271
+ };
13272
+ var buildPageDecisionSignal = (reason) => {
13273
+ if (reason === "no_non_page_gate") return "page default: non-page targets did not clear brief intent plus support gates";
13274
+ if (reason === "non_page_did_not_beat_page") return "page default: non-page targets did not beat page confidence";
13275
+ if (reason === "page_first_brief_target") return "page default: page was the first explicit target in the brief";
13276
+ if (reason === "page_tie_break") return "page default: page intent won a tied non-page confidence score";
13277
+ return "page default: page selected";
13278
+ };
13279
+ var getTargetConfidence = (primaryKind, pageConfidence, component, asset) => {
13280
+ if (primaryKind === "component") return component.confidence;
13281
+ if (primaryKind === "asset") return asset.confidence;
13282
+ return pageConfidence;
13283
+ };
13284
+ var buildTargetEvidenceBuckets = (primaryKind, format, designVectors) => ({
13285
+ anatomy: [`Map ${primaryKind} anatomy before styling: root, content hierarchy, interaction zones, and supporting regions.`],
13286
+ propsSlots: [`Define props/slots from ${format.componentGrammar}; separate data props, content slots, and visual variant controls.`],
13287
+ stateMatrix: ["Cover default, hover, focus, active, disabled, loading, empty, error, success, and selected where relevant."],
13288
+ tokens: [`Resolve typography, color, spacing, radius, shadow, motion, and z-index through semantic tokens for ${format.paletteIntent}.`],
13289
+ assets: [`Inventory source assets, derived assets, usage rights, responsive variants, and replacement notes for ${primaryKind} prototypes.`],
13290
+ accessibility: ["Validate keyboard order, visible focus, accessible names, ARIA pattern fit, contrast, and WCAG 2.2 states."],
13291
+ motion: [`Use ${format.motionGrammar}; include reduced-motion alternatives for ${designVectors.motionPosture.join(" ") || "all transitions"}.`],
13292
+ previewFixtures: [`Build isolated preview fixtures for ${primaryKind} default, responsive, reduced-motion, and failure states.`]
13293
+ });
13294
+ var buildComponentTargetAnalysis = (briefHash, format) => ({
13295
+ canvasType: "CanvasComponentInventoryItem",
13296
+ inventoryItems: [{
13297
+ id: `component_${briefHash}`,
13298
+ name: `${format.label} Component`,
13299
+ componentName: `${format.route.profile.replace(/-/g, "")}PrototypeComponent`,
13300
+ description: `Reusable component prototype derived from ${format.componentGrammar}.`,
13301
+ sourceFamily: "framework_component",
13302
+ origin: "code_sync",
13303
+ variants: [{
13304
+ id: "default",
13305
+ name: "Default",
13306
+ selector: { interaction: "default" },
13307
+ description: "Default preview fixture.",
13308
+ metadata: {}
13309
+ }],
13310
+ props: [
13311
+ { name: "variant", type: "string", required: false, description: "Visual variant key.", metadata: {} },
13312
+ { name: "state", type: "string", required: false, description: "Interaction state fixture.", metadata: {} }
13313
+ ],
13314
+ slots: [
13315
+ { name: "media", description: "Optional visual or icon slot.", allowedKinds: ["asset", "image", "icon"], metadata: {} },
13316
+ { name: "content", description: "Primary text or rich content slot.", allowedKinds: ["text", "rich-text"], metadata: {} }
13317
+ ],
13318
+ events: [{ name: "onPrimaryAction", description: "Primary interaction callback.", payloadShape: {}, metadata: {} }],
13319
+ content: { acceptsText: true, acceptsRichText: true, slotNames: ["media", "content"], metadata: {} },
13320
+ metadata: { targetKind: "component" }
13321
+ }],
13322
+ prototypeGuidance: [
13323
+ "Component prototype target: document anatomy, props/slots, variant rules, and interaction state fixtures before page composition.",
13324
+ "Use Storybook-style args and interaction checks when converting this guidance into executable component previews."
13325
+ ]
13326
+ });
13327
+ var buildAssetTargetAnalysis = (briefHash) => ({
13328
+ canvasType: "CanvasAsset",
13329
+ assets: [{
13330
+ id: `asset_${briefHash}`,
13331
+ sourceType: "page-derived",
13332
+ kind: "visual-asset",
13333
+ url: null,
13334
+ status: "needs-production-source",
13335
+ provenanceNotes: ["Derived from brief/reference evidence; recreate rather than copy proprietary source assets."],
13336
+ usageNotes: ["Define responsive variants, token usage, alt text, and replacement rules before implementation."],
13337
+ metadata: { targetKind: "asset" }
13338
+ }],
13339
+ prototypeGuidance: [
13340
+ "Asset prototype target: catalog provenance, variants, token usage, responsive behavior, and replacement rules.",
13341
+ "Pair each visual asset with preview fixtures for default, high contrast, and reduced-motion contexts when relevant."
13342
+ ]
13343
+ });
13344
+ var buildPageTargetAnalysis = (format, designVectors) => ({
13345
+ canvasType: "CanvasPage",
13346
+ assemblyFocus: [
13347
+ format.layoutArchetype,
13348
+ ...designVectors.sectionArchitecture
13349
+ ],
13350
+ implementationNotes: [
13351
+ "Page prototype target: validate section order, navigation model, CTA visibility, responsive collapse, and reduced-motion behavior.",
13352
+ "Use component primitives before page-specific wrappers."
13353
+ ]
13354
+ });
13355
+ var buildTargetAnalysis = (brief, format, references, synthesis, designVectors) => {
13356
+ const briefSignals = collectTargetSignals(brief.toLowerCase());
13357
+ const supportSignals = collectTargetSignals(buildTargetCorpus(brief, references, synthesis));
13358
+ const pageConfidence = buildPageConfidence(briefSignals.page);
13359
+ const component = buildTargetEligibility("component", briefSignals.component, supportSignals.component);
13360
+ const asset = buildTargetEligibility("asset", briefSignals.asset, supportSignals.asset);
13361
+ const decision = choosePrimaryTargetKind(
13362
+ pageConfidence,
13363
+ briefSignals.page,
13364
+ findFirstBriefTargetKind(brief),
13365
+ component,
13366
+ asset
13367
+ );
13368
+ const primaryKind = decision.primaryKind;
13369
+ const kinds = chooseTargetKinds(primaryKind, component, asset);
13370
+ const briefHash = referenceFingerprint(brief);
13371
+ return {
13372
+ primaryKind,
13373
+ kinds,
13374
+ confidence: getTargetConfidence(primaryKind, pageConfidence, component, asset),
13375
+ triggeringSignals: buildTriggeringSignals(decision, briefSignals, component, asset),
13376
+ evidenceBuckets: buildTargetEvidenceBuckets(primaryKind, format, designVectors),
13377
+ ...kinds.includes("page") ? { page: buildPageTargetAnalysis(format, designVectors) } : {},
13378
+ ...kinds.includes("component") ? { component: buildComponentTargetAnalysis(briefHash, format) } : {},
13379
+ ...kinds.includes("asset") ? { asset: buildAssetTargetAnalysis(briefHash) } : {}
13380
+ };
13381
+ };
13382
+ var buildGenerationPlan = ({
13383
+ brief,
13384
+ format,
13385
+ synthesis,
13386
+ referencePatternBoard,
13387
+ designVectors,
13388
+ targetAnalysis
13389
+ }) => {
12060
13390
  const plan = cloneTemplate(BASE_GENERATION_PLAN);
12061
13391
  const profile = format.route.profile;
12062
- plan.targetOutcome.summary = summarizeBrief(brief);
13392
+ const vectorSummary = summarizeDesignVectors(designVectors);
13393
+ plan.targetOutcome.summary = clipText2(
13394
+ `${summarizeBrief(brief)} Reference cues: ${synthesis.summary} ${vectorSummary}`,
13395
+ GENERATION_PLAN_REFERENCE_CLIP_LENGTH
13396
+ );
12063
13397
  plan.visualDirection.profile = profile;
12064
13398
  plan.visualDirection.themeStrategy = format.route.themeStrategy;
12065
13399
  plan.layoutStrategy.approach = format.route.layoutApproach;
12066
13400
  plan.layoutStrategy.navigationModel = format.route.navigationModel;
13401
+ plan.contentStrategy.source = clipText2(
13402
+ `${INSPIREDESIGN_HANDOFF_FILES.evidence}, ${INSPIREDESIGN_HANDOFF_FILES.advancedBrief}, ${INSPIREDESIGN_HANDOFF_FILES.designMarkdown}. Use reference pattern board and design vectors from evidence/handoff artifacts. ${synthesis.summary} ${vectorSummary}`,
13403
+ GENERATION_PLAN_REFERENCE_CLIP_LENGTH
13404
+ );
13405
+ plan.componentStrategy.mode = clipText2(
13406
+ `reuse-first, adapted from captured references: ${synthesis.summary}. Include hero entrance reveal, section scroll reveal, CTA/focus feedback, microinteractions, hover effects, evidence-gated cursor effects, material depth, parallax constraints, glass/translucency policy, and prefers-reduced-motion behavior. Capture desktop and mobile browser proof for responsive layout, reduced-motion behavior, focus states, and primary CTA visibility.`,
13407
+ GENERATION_PLAN_REFERENCE_CLIP_LENGTH
13408
+ );
12067
13409
  plan.componentStrategy.interactionStates = ["default", "hover", "focus", "disabled", "loading"];
12068
13410
  plan.validationTargets.requiredThemes = plan.visualDirection.themeStrategy === "single-theme" ? ["light"] : ["light", "dark"];
12069
- return plan;
13411
+ return {
13412
+ ...plan,
13413
+ referencePatternBoard,
13414
+ designVectors,
13415
+ targetAnalysis,
13416
+ interactionMoments: [...designVectors.interactionMoments],
13417
+ materialEffects: [...designVectors.materialEffects]
13418
+ };
12070
13419
  };
12071
13420
  var buildIntentBlock = (brief, urls, references, format) => {
12072
13421
  const intent = cloneTemplate(BASE_CONTRACT_TEMPLATE.intent);
@@ -12174,11 +13523,19 @@ var buildIconSystemBlock = () => ({
12174
13523
  "Decorative icons should remain visually lighter than primary copy."
12175
13524
  ]
12176
13525
  });
12177
- var buildMotionSystemBlock = (format) => {
13526
+ var buildMotionSystemBlock = (format, designVectors) => {
12178
13527
  const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.motionSystem);
12179
13528
  return {
12180
13529
  ...block,
12181
13530
  grammar: format.motionGrammar,
13531
+ posture: [...designVectors.motionPosture],
13532
+ interactionMoments: [...designVectors.interactionMoments],
13533
+ materialEffects: [...designVectors.materialEffects],
13534
+ advancedMotionAdvisory: [...designVectors.advancedMotionAdvisory],
13535
+ advancedMotionRuntimePolicy: "Advanced motion fields are advisory contract metadata only and do not authorize shader, WebGL, Spline, R3F, Pixi, Babylon, or GLSL runtime support.",
13536
+ parallaxPolicy: "Use parallax only as a restrained hierarchy cue and remove transform-based depth for reduced-motion users.",
13537
+ hoverPolicy: "Hover effects must clarify clickability without becoming the only visible affordance.",
13538
+ cursorPolicy: "Cursor effects are allowed only on premium hero or CTA moments and must not interfere with reading or form controls.",
12182
13539
  durations: {
12183
13540
  quick: "120ms",
12184
13541
  standard: "180ms",
@@ -12209,12 +13566,12 @@ var buildLibraryPolicyBlock = () => ({
12209
13566
  components: ["shadcn"],
12210
13567
  icons: ["tabler"],
12211
13568
  styling: ["tailwindcss"],
12212
- motion: ["css"],
13569
+ motion: [],
12213
13570
  threeD: []
12214
13571
  });
12215
13572
  var buildRuntimeBudgetsBlock = (plan) => ({
12216
13573
  maxHeroActions: 2,
12217
- maxPrimarySections: 8,
13574
+ maxPrimarySections: plan.layoutStrategy.navigationModel === "global-header" ? 12 : 8,
12218
13575
  maxInteractionLatencyMs: plan.validationTargets.maxInteractionLatencyMs,
12219
13576
  previewBudgetMs: 1500,
12220
13577
  notes: [
@@ -12254,7 +13611,21 @@ var buildPerformanceModelBlock = () => {
12254
13611
  var buildCanvasPlanRequest = (brief, generationPlan) => ({
12255
13612
  ...cloneTemplate(BASE_PLAN_REQUEST_TEMPLATE),
12256
13613
  requestId: `req_plan_${referenceFingerprint(brief).slice(0, 12)}`,
12257
- generationPlan
13614
+ generationPlan: toCanvasGenerationPlan(generationPlan)
13615
+ });
13616
+ var toCanvasGenerationPlan = (plan) => cloneTemplate({
13617
+ targetOutcome: plan.targetOutcome,
13618
+ visualDirection: plan.visualDirection,
13619
+ layoutStrategy: plan.layoutStrategy,
13620
+ contentStrategy: plan.contentStrategy,
13621
+ componentStrategy: plan.componentStrategy,
13622
+ motionPosture: plan.motionPosture,
13623
+ responsivePosture: plan.responsivePosture,
13624
+ accessibilityPosture: plan.accessibilityPosture,
13625
+ validationTargets: plan.validationTargets,
13626
+ interactionMoments: [...plan.interactionMoments],
13627
+ materialEffects: [...plan.materialEffects],
13628
+ designVectors: plan.designVectors
12258
13629
  });
12259
13630
  var buildContractScope = () => ({
12260
13631
  emittedContract: "CanvasDesignGovernance",
@@ -12267,9 +13638,31 @@ var buildBriefExpansionMetadata = (briefExpansion) => ({
12267
13638
  file: INSPIREDESIGN_HANDOFF_FILES.advancedBrief,
12268
13639
  format: cloneInspiredesignBriefFormat(briefExpansion.format)
12269
13640
  });
12270
- var buildFollowthrough = (generationPlan, briefExpansion) => ({
13641
+ var buildRequiredReferenceArtifacts = (includePrototypeGuidance) => {
13642
+ const files = [
13643
+ INSPIREDESIGN_HANDOFF_FILES.evidence,
13644
+ INSPIREDESIGN_HANDOFF_FILES.advancedBrief,
13645
+ INSPIREDESIGN_HANDOFF_FILES.designMarkdown,
13646
+ INSPIREDESIGN_HANDOFF_FILES.generationPlan,
13647
+ INSPIREDESIGN_HANDOFF_FILES.canvasPlanRequest,
13648
+ INSPIREDESIGN_HANDOFF_FILES.designContract,
13649
+ INSPIREDESIGN_HANDOFF_FILES.implementationPlanMarkdown
13650
+ ];
13651
+ return includePrototypeGuidance ? [...files, INSPIREDESIGN_HANDOFF_FILES.prototypeGuidance] : files;
13652
+ };
13653
+ var buildFollowthrough = ({
13654
+ generationPlan,
13655
+ briefExpansion,
13656
+ synthesis,
13657
+ includePrototypeGuidance,
13658
+ referencePatternBoard,
13659
+ designVectors,
13660
+ targetAnalysis
13661
+ }) => ({
12271
13662
  summary: buildInspiredesignFollowthroughSummary(),
12272
13663
  nextStep: buildInspiredesignNextStep(),
13664
+ artifactGuide: INSPIREDESIGN_ARTIFACT_GUIDE,
13665
+ contractSectionGuide: INSPIREDESIGN_CONTRACT_SECTION_GUIDE,
12273
13666
  briefExpansion: buildBriefExpansionMetadata(briefExpansion),
12274
13667
  recommendedSkills: [...INSPIREDESIGN_HANDOFF_RECOMMENDED_SKILLS],
12275
13668
  commandExamples: { ...INSPIREDESIGN_HANDOFF_COMMANDS },
@@ -12278,20 +13671,33 @@ var buildFollowthrough = (generationPlan, briefExpansion) => ({
12278
13671
  implementationContext: {
12279
13672
  navigationModel: buildNavigationModelBlock(generationPlan.layoutStrategy.navigationModel),
12280
13673
  asyncModel: buildAsyncModelBlock(),
12281
- performanceModel: buildPerformanceModelBlock()
13674
+ performanceModel: buildPerformanceModelBlock(),
13675
+ referenceSynthesis: {
13676
+ requiredArtifacts: buildRequiredReferenceArtifacts(includePrototypeGuidance),
13677
+ cues: synthesis.lines
13678
+ },
13679
+ referencePatternBoard,
13680
+ designVectors,
13681
+ targetAnalysis
12282
13682
  }
12283
13683
  });
12284
- var buildDesignContract = (brief, urls, references, plan, format) => ({
13684
+ var buildDesignContract = ({
13685
+ brief,
13686
+ urls,
13687
+ references,
13688
+ plan,
13689
+ format
13690
+ }) => ({
12285
13691
  intent: buildIntentBlock(brief, urls, references, format),
12286
- generationPlan: plan,
13692
+ generationPlan: toCanvasGenerationPlan(plan),
12287
13693
  designLanguage: buildDesignLanguageBlock(plan.visualDirection.profile, format),
12288
- contentModel: buildContentModelBlock(brief, references),
13694
+ contentModel: buildContentModelBlock(brief, references.filter(hasInspiredesignUsableReferenceEvidence)),
12289
13695
  layoutSystem: buildLayoutSystemBlock(plan, format),
12290
13696
  typographySystem: buildTypographySystemBlock(format),
12291
13697
  colorSystem: buildColorSystemBlock(plan.visualDirection.profile, format),
12292
13698
  surfaceSystem: buildSurfaceSystemBlock(format),
12293
13699
  iconSystem: buildIconSystemBlock(),
12294
- motionSystem: buildMotionSystemBlock(format),
13700
+ motionSystem: buildMotionSystemBlock(format, plan.designVectors),
12295
13701
  responsiveSystem: buildResponsiveSystemBlock(format),
12296
13702
  accessibilityPolicy: buildAccessibilityBlock(),
12297
13703
  libraryPolicy: buildLibraryPolicyBlock(),
@@ -12353,17 +13759,32 @@ var buildComponentBuildPlan = (profile) => {
12353
13759
  implementationNote: "Use semantic tokens first and keep copy/state logic outside the visual component."
12354
13760
  }));
12355
13761
  };
12356
- var buildImplementationPlan = (profile, format, references) => ({
13762
+ var buildImplementationPlan = ({
13763
+ profile,
13764
+ format,
13765
+ references,
13766
+ synthesis,
13767
+ designVectors
13768
+ }) => ({
12357
13769
  architectureRecommendation: `Implement the surface as a ${format.archetype} using token-first components and shared semantic CSS variables, then compose page sections from those primitives before adding any page-specific polish.`,
12358
13770
  tokenStrategy: buildTokenStrategy(profile),
13771
+ referenceImplementationNotes: synthesis.lines.length > 0 ? synthesis.lines : ["No live reference cues were captured; keep implementation anchored to the source brief and selected prompt format."],
12359
13772
  componentBuildPlan: buildComponentBuildPlan(profile),
12360
13773
  pageAssemblyPlan: [
12361
13774
  `Start with the ${format.layoutArchetype} and the primary navigation pattern.`,
13775
+ ...designVectors.sectionArchitecture,
13776
+ "Make each major section content-rich with a concrete headline, supporting copy, proof detail, and a clear role in the journey.",
12362
13777
  "Compose the hero or primary decision section before supporting sections.",
12363
13778
  "Add proof, utility, and footer sections only after the top-level hierarchy is stable."
12364
13779
  ],
12365
13780
  stateAndInteractionPlan: [
12366
13781
  `Use ${format.motionGrammar} while keeping hover, focus, loading, success, and error states visually distinct.`,
13782
+ ...designVectors.motionPosture,
13783
+ ...designVectors.interactionMoments,
13784
+ ...designVectors.materialEffects,
13785
+ ...designVectors.advancedMotionAdvisory,
13786
+ "Implement hero entrance reveal, section scroll reveal, and CTA/focus feedback as the minimum motion system for landing pages.",
13787
+ "Use @media (prefers-reduced-motion: reduce) to preserve hierarchy without motion.",
12367
13788
  "Preserve layout during loading and keep transient confirmations out of the main flow.",
12368
13789
  "Use reduced-motion-safe transitions for reveals and CTA feedback."
12369
13790
  ],
@@ -12379,25 +13800,33 @@ var buildImplementationPlan = (profile, format, references) => ({
12379
13800
  "Avoid horizontal scrolling for primary content."
12380
13801
  ],
12381
13802
  risksAndAmbiguities: [
12382
- references.length === 0 ? "No live references were supplied, so visual cues are derived entirely from the written brief." : "Live references were reduced into reusable patterns; unique brand assets should still be recreated, not copied.",
12383
- "Any missing interaction states must be validated during visual QA."
13803
+ 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.",
13804
+ "Any missing interaction states must be validated during visual QA.",
13805
+ "Capture desktop and mobile browser proof before handoff, including reduced-motion behavior and primary CTA visibility."
12384
13806
  ],
12385
13807
  buildSequence: [
12386
13808
  "Define semantic tokens and typography.",
12387
13809
  "Build the shell, navigation, and primary CTA components.",
12388
13810
  "Implement section-level patterns and proof blocks.",
12389
13811
  "Add loading, empty, and error states.",
12390
- "Run accessibility, responsive, and browser QA before final polish."
13812
+ "Capture desktop and mobile browser proof for responsive layout, reduced-motion behavior, focus states, and primary CTA visibility before final polish."
12391
13813
  ]
12392
13814
  });
12393
13815
  var formatBulletList2 = (items) => items.map((item) => `- ${item}`).join("\n");
13816
+ var renderAntiPatternRule = (rule) => {
13817
+ const cleanRule = rule.replace(/\.$/, "").trim();
13818
+ const withoutNo = cleanRule.replace(/^no\s+/i, "");
13819
+ if (withoutNo !== cleanRule) return `Don't use ${withoutNo.charAt(0).toLowerCase()}${withoutNo.slice(1)}.`;
13820
+ const withoutDoNot = cleanRule.replace(/^do not\s+/i, "");
13821
+ if (withoutDoNot !== cleanRule) return `Don't ${withoutDoNot.charAt(0).toLowerCase()}${withoutDoNot.slice(1)}.`;
13822
+ return `Don't ${cleanRule.charAt(0).toLowerCase()}${cleanRule.slice(1)}.`;
13823
+ };
12394
13824
  var formatRecordList = (record) => {
12395
13825
  return Object.entries(record).map(([key, value]) => `- \`${key}\`: ${value}`).join("\n");
12396
13826
  };
12397
13827
  var referenceContribution = (reference) => {
12398
13828
  if (reference.captureStatus === "captured") return "Live hierarchy and component evidence captured from the page.";
12399
- if (reference.fetchStatus === "captured") return "Content and structural cues inferred from fetched page data.";
12400
- return "Only operator brief context was available for this reference.";
13829
+ return "Content and structural cues inferred from fetched page data.";
12401
13830
  };
12402
13831
  var referenceMotionNote = (reference) => {
12403
13832
  if (reference.capture?.snapshot?.warnings?.length) {
@@ -12406,8 +13835,13 @@ var referenceMotionNote = (reference) => {
12406
13835
  if (reference.captureStatus === "captured") return "Motion should remain subtle until validated against the live capture.";
12407
13836
  return "Motion is inferred from the brief rather than directly observed.";
12408
13837
  };
13838
+ var referenceLayoutObservation = (reference, excerpt) => {
13839
+ if (!reference.capture?.snapshot && !reference.capture?.clone && !reference.capture?.dom) return excerpt;
13840
+ const signals = getInspiredesignReferenceSignals(reference);
13841
+ return signals.find((signal) => signal !== reference.title) ?? signals[0] ?? excerpt;
13842
+ };
12409
13843
  var renderReferenceMarkdown = (reference, index) => {
12410
- const excerpt = reference.excerpt ? clipText(reference.excerpt, 220) : "No fetched excerpt captured.";
13844
+ const excerpt = reference.excerpt ? clipText2(reference.excerpt, 220) : "No fetched excerpt captured.";
12411
13845
  const title = reference.title ?? reference.url;
12412
13846
  return [
12413
13847
  `### Source ${index + 1}: ${title}`,
@@ -12415,13 +13849,20 @@ var renderReferenceMarkdown = (reference, index) => {
12415
13849
  `- notable UI patterns: ${reference.capture?.snapshot ? "Primary hierarchy and actionables were captured from the live page." : "Patterns inferred from brief and fetched content."}`,
12416
13850
  `- typography observations: ${reference.title ? "Headline density and copy hierarchy were inferred from the fetched title and excerpt." : "Typography is inferred."}`,
12417
13851
  `- color and theme observations: ${reference.captureStatus === "captured" ? "Color posture should be validated against the captured page before cloning brand treatment." : "Color posture remains a synthesis decision."}`,
12418
- `- layout and hierarchy observations: ${reference.capture?.snapshot ? clipText(reference.capture.snapshot.content, 180) : excerpt}`,
13852
+ `- layout and hierarchy observations: ${referenceLayoutObservation(reference, excerpt)}`,
12419
13853
  `- component patterns: ${reference.capture?.clone ? "Buttons, cards, or layout wrappers can be inferred from the captured clone preview." : "Component families were inferred from available reference text."}`,
12420
13854
  `- motion/interaction observations: ${referenceMotionNote(reference)}`,
12421
13855
  `- accessibility/responsiveness notes: ${reference.captureStatus === "captured" ? "Validate focus order, CTA prominence, and stacked layouts during build QA." : "Accessibility and responsiveness are inferred from system defaults."}`,
12422
13856
  `- what should be adopted, adapted, or avoided: adopt layout hierarchy, adapt it to the new brand tokens, avoid copying proprietary copy or visual assets directly.`
12423
13857
  ].join("\n");
12424
13858
  };
13859
+ var renderInspirationAnalysis = (references, usableReferences) => {
13860
+ if (usableReferences.length > 0) return usableReferences.map(renderReferenceMarkdown).join("\n\n");
13861
+ if (references.length > 0) {
13862
+ return "- Reference URLs were attempted, but no usable creative evidence was captured. See evidence.json for fetch/capture status.";
13863
+ }
13864
+ return "- No live inspiration source was provided. The system is derived entirely from the brief.";
13865
+ };
12425
13866
  var renderGovernanceMarkdown = (designContract, implementationPlan, format) => {
12426
13867
  const generationPlan = designContract.generationPlan;
12427
13868
  const profileConfig = PROFILE_CONFIG[generationPlan.visualDirection.profile];
@@ -12516,7 +13957,7 @@ var renderGovernanceMarkdown = (designContract, implementationPlan, format) => {
12516
13957
  "Do encode repeated visual rules into semantic tokens.",
12517
13958
  "Don't copy proprietary logos, screenshots, or brand-only illustrations.",
12518
13959
  "Don't hide important actions inside ambiguous hover-only affordances.",
12519
- ...format.antiPatterns.map((rule) => `Don't ${rule.replace(/\.$/, "").toLowerCase()}.`)
13960
+ ...format.antiPatterns.map(renderAntiPatternRule)
12520
13961
  ]),
12521
13962
  "",
12522
13963
  "## 4.15 Acceptance Criteria",
@@ -12539,39 +13980,79 @@ var renderImplementationMarkdown = (implementationPlan) => {
12539
13980
  "",
12540
13981
  formatRecordList(implementationPlan.tokenStrategy.typography),
12541
13982
  "",
12542
- "## 5.3 Component Build Plan",
13983
+ "## 5.3 Reference Implementation Notes",
13984
+ formatBulletList2(implementationPlan.referenceImplementationNotes),
13985
+ "",
13986
+ "## 5.4 Component Build Plan",
12543
13987
  implementationPlan.componentBuildPlan.map((component, index) => `${index + 1}. ${component.name}: ${component.purpose}`).join("\n"),
12544
13988
  "",
12545
- "## 5.4 Page Assembly Plan",
13989
+ "## 5.5 Page Assembly Plan",
12546
13990
  formatBulletList2(implementationPlan.pageAssemblyPlan),
12547
13991
  "",
12548
- "## 5.5 State and Interaction Plan",
13992
+ "## 5.6 State and Interaction Plan",
12549
13993
  formatBulletList2(implementationPlan.stateAndInteractionPlan),
12550
13994
  "",
12551
- "## 5.6 Accessibility Implementation Checklist",
13995
+ "## 5.7 Accessibility Implementation Checklist",
12552
13996
  formatBulletList2(implementationPlan.accessibilityChecklist),
12553
13997
  "",
12554
- "## 5.7 Responsive Implementation Checklist",
13998
+ "## 5.8 Responsive Implementation Checklist",
12555
13999
  formatBulletList2(implementationPlan.responsiveChecklist),
12556
14000
  "",
12557
- "## 5.8 Risks and Ambiguities",
14001
+ "## 5.9 Risks and Ambiguities",
12558
14002
  formatBulletList2(implementationPlan.risksAndAmbiguities),
12559
14003
  "",
12560
- "## 5.9 Recommended Build Sequence",
14004
+ "## 5.10 Recommended Build Sequence",
12561
14005
  implementationPlan.buildSequence.map((step, index) => `${index + 1}. ${step}`).join("\n")
12562
14006
  ].join("\n");
12563
14007
  };
12564
- var renderPrototypeGuidance = (profile) => {
14008
+ var renderTargetAnalysisGuidance = (targetAnalysis) => {
14009
+ const targetGuidance = [
14010
+ ...targetAnalysis.page?.implementationNotes ?? [],
14011
+ ...targetAnalysis.component?.prototypeGuidance ?? [],
14012
+ ...targetAnalysis.asset?.prototypeGuidance ?? []
14013
+ ];
14014
+ return [
14015
+ "## 6.3 Target Analysis",
14016
+ formatBulletList2([
14017
+ `primary target: ${targetAnalysis.primaryKind}`,
14018
+ `target kinds: ${targetAnalysis.kinds.join(", ")}`,
14019
+ `confidence: ${targetAnalysis.confidence.toFixed(2)}`,
14020
+ `triggering signals: ${targetAnalysis.triggeringSignals.join("; ")}`,
14021
+ ...targetGuidance,
14022
+ `anatomy: ${targetAnalysis.evidenceBuckets.anatomy.join(" ")}`,
14023
+ `props/slots: ${targetAnalysis.evidenceBuckets.propsSlots.join(" ")}`,
14024
+ `state matrix: ${targetAnalysis.evidenceBuckets.stateMatrix.join(" ")}`,
14025
+ `tokens: ${targetAnalysis.evidenceBuckets.tokens.join(" ")}`,
14026
+ `assets: ${targetAnalysis.evidenceBuckets.assets.join(" ")}`,
14027
+ `accessibility: ${targetAnalysis.evidenceBuckets.accessibility.join(" ")}`,
14028
+ `motion: ${targetAnalysis.evidenceBuckets.motion.join(" ")}`,
14029
+ `preview fixtures: ${targetAnalysis.evidenceBuckets.previewFixtures.join(" ")}`
14030
+ ])
14031
+ ].join("\n");
14032
+ };
14033
+ var renderPrototypeGuidance = (profile, synthesis, designVectors, targetAnalysis) => {
12565
14034
  return [
12566
14035
  "# 6. Optional Prototype Plan",
12567
14036
  "",
12568
- "- page structure: establish the shell, hero or primary action zone, proof sections, and footer in that order.",
14037
+ "## 6.1 Reference Anchors",
14038
+ formatBulletList2(synthesis.lines.length > 0 ? synthesis.lines : ["No live reference cues were captured."]),
14039
+ "",
14040
+ "## 6.2 Prototype Structure",
14041
+ "- page structure: for public landing pages, build 8 to 12 content-rich sections unless the brief explicitly asks for a microsite.",
14042
+ `- section architecture: ${designVectors.sectionArchitecture.join(" ")}`,
12569
14043
  `- section order: ${PROFILE_CONFIG[profile].pagePatterns.join(" -> ")}`,
12570
14044
  "- component composition: reuse button, card, input, and navigation primitives before page-specific wrappers.",
12571
- "- interaction expectations: provide visible focus, compact hover feedback, and reduced-motion-safe entry transitions.",
12572
- "- HTML skeleton guidance: start with one main landmark, one primary CTA group, and semantic sections for proof or detail bands.",
12573
- "- styling approach: define CSS variables first, then map components to semantic tokens rather than raw values.",
12574
- "- first prototype should include vs omit: include shell, hero, CTA, one proof section, and one form or action cluster; omit analytics, heavy animation, and tertiary content until hierarchy is proven."
14045
+ `- interaction expectations: ${designVectors.interactionMoments.join(" ")}`,
14046
+ `- motion expectations: ${designVectors.motionPosture.join(" ")}`,
14047
+ `- material and depth expectations: ${designVectors.materialEffects.join(" ")}`,
14048
+ `- advisory advanced motion: ${designVectors.advancedMotionAdvisory.join(" ")}`,
14049
+ "",
14050
+ renderTargetAnalysisGuidance(targetAnalysis),
14051
+ "",
14052
+ "- browser proof: capture desktop and mobile browser screenshots, verify reduced-motion behavior, inspect focus states, and confirm the primary CTA remains visible without overlap.",
14053
+ "- HTML skeleton guidance: start with one main landmark, one primary CTA group, and semantic sections that follow the design vector section architecture instead of fixed industry-specific defaults.",
14054
+ "- styling approach: define CSS variables for timing, easing, elevation, translucency, backdrop blur, cursor effects, hover effects, and parallax distance before mapping components to semantic tokens.",
14055
+ "- 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."
12575
14056
  ].join("\n");
12576
14057
  };
12577
14058
  var renderDeliverablesSummary = (includePrototypeGuidance) => {
@@ -12589,27 +14070,38 @@ var renderDeliverablesSummary = (includePrototypeGuidance) => {
12589
14070
  deliverables.push("Evidence digest describing brief, references, fetch outcomes, and capture outcomes");
12590
14071
  return formatBulletList2(deliverables);
12591
14072
  };
12592
- var buildEvidencePayload = (brief, briefExpansion, urls, references) => ({
14073
+ var buildEvidencePayload = ({
14074
+ brief,
14075
+ briefExpansion,
14076
+ advancedBriefMarkdown,
14077
+ urls,
14078
+ references,
14079
+ referencePatternBoard,
14080
+ designVectors,
14081
+ targetAnalysis
14082
+ }) => ({
12593
14083
  brief,
12594
14084
  briefHash: referenceFingerprint(brief),
12595
- advancedBrief: briefExpansion.advancedBrief,
12596
- advancedBriefHash: referenceFingerprint(briefExpansion.advancedBrief),
14085
+ advancedBrief: advancedBriefMarkdown,
14086
+ advancedBriefHash: referenceFingerprint(advancedBriefMarkdown),
12597
14087
  briefExpansion: {
12598
14088
  templateVersion: briefExpansion.templateVersion,
12599
14089
  format: cloneInspiredesignBriefFormat(briefExpansion.format)
12600
14090
  },
12601
14091
  urls,
12602
14092
  referenceCount: references.length,
12603
- references: references.map((reference) => toReferenceEvidenceJson(reference))
14093
+ references: references.map((reference) => toReferenceEvidenceJson(reference)),
14094
+ referencePatternBoard,
14095
+ designVectors,
14096
+ targetAnalysis
12604
14097
  });
12605
- var toCaptureEvidenceJson = (capture) => {
12606
- const normalized = normalizeInspiredesignCaptureEvidence(capture);
14098
+ var toCaptureEvidenceJson = (reference) => {
14099
+ const normalized = normalizeInspiredesignCaptureEvidence(reference.capture);
12607
14100
  if (!normalized) return null;
14101
+ const signals = getInspiredesignReferenceSignals(reference);
12608
14102
  return {
12609
14103
  ...normalized.title ? { title: normalized.title } : {},
12610
- ...normalized.snapshot ? { snapshot: normalized.snapshot } : {},
12611
- ...normalized.dom ? { dom: normalized.dom } : {},
12612
- ...normalized.clone ? { clone: normalized.clone } : {},
14104
+ ...signals.length > 0 ? { signals } : {},
12613
14105
  ...normalized.attempts ? { attempts: normalized.attempts } : {}
12614
14106
  };
12615
14107
  };
@@ -12622,33 +14114,87 @@ var toReferenceEvidenceJson = (reference) => ({
12622
14114
  captureStatus: reference.captureStatus,
12623
14115
  ...reference.fetchFailure ? { fetchFailure: reference.fetchFailure } : {},
12624
14116
  ...reference.captureFailure ? { captureFailure: reference.captureFailure } : {},
12625
- capture: toCaptureEvidenceJson(reference.capture)
14117
+ capture: toCaptureEvidenceJson(reference)
12626
14118
  });
12627
14119
  var buildInspiredesignPacket = (input) => {
12628
- const brief = trimText(input.brief);
14120
+ const brief = trimText2(input.brief);
12629
14121
  const selectedFormat = cloneInspiredesignBriefFormat(input.briefExpansion.format);
12630
- const advancedBriefMarkdown = input.briefExpansion.advancedBrief;
12631
- const urls = [...new Set(input.urls.map((url) => trimText(url)).filter(Boolean))];
14122
+ const includePrototypeGuidance = input.includePrototypeGuidance ?? false;
14123
+ const urls = [...new Set(input.urls.map((url) => trimText2(url)).filter(Boolean))];
12632
14124
  const references = input.references.map((reference) => ({
12633
14125
  ...reference,
12634
- title: reference.title ? trimText(reference.title) : void 0,
12635
- excerpt: reference.excerpt ? trimText(reference.excerpt) : void 0
14126
+ title: reference.title ? trimText2(reference.title) : void 0,
14127
+ excerpt: reference.excerpt ? trimText2(reference.excerpt) : void 0
12636
14128
  }));
12637
- const generationPlan = buildGenerationPlan(brief, selectedFormat);
14129
+ const usableReferences = references.filter(hasInspiredesignUsableReferenceEvidence);
14130
+ const synthesis = buildReferenceSynthesis(usableReferences);
14131
+ const referencePatternBoard = buildInspiredesignReferencePatternBoard(
14132
+ referenceFingerprint(brief),
14133
+ selectedFormat,
14134
+ references
14135
+ );
14136
+ const designVectors = buildInspiredesignDesignVectors(selectedFormat, referencePatternBoard);
14137
+ const effectiveFormat = buildEvidenceDerivedFormat(selectedFormat, designVectors);
14138
+ const targetAnalysis = buildTargetAnalysis(
14139
+ brief,
14140
+ effectiveFormat,
14141
+ references,
14142
+ synthesis,
14143
+ designVectors
14144
+ );
14145
+ const effectiveBriefExpansion = {
14146
+ ...input.briefExpansion,
14147
+ advancedBrief: isReferenceFirstPublicLanding(designVectors) ? renderEvidenceDerivedAdvancedBrief(input.briefExpansion, effectiveFormat) : input.briefExpansion.advancedBrief,
14148
+ format: effectiveFormat
14149
+ };
14150
+ const advancedBriefMarkdown = renderReferenceFirstAdvancedBrief(
14151
+ effectiveBriefExpansion,
14152
+ referencePatternBoard,
14153
+ designVectors,
14154
+ references
14155
+ );
14156
+ const generationPlan = buildGenerationPlan({
14157
+ brief,
14158
+ format: effectiveFormat,
14159
+ synthesis,
14160
+ referencePatternBoard,
14161
+ designVectors,
14162
+ targetAnalysis
14163
+ });
12638
14164
  const profile = generationPlan.visualDirection.profile;
12639
14165
  const canvasPlanRequest = buildCanvasPlanRequest(brief, generationPlan);
12640
- const designContract = buildDesignContract(brief, urls, references, generationPlan, selectedFormat);
12641
- const followthrough = buildFollowthrough(generationPlan, input.briefExpansion);
12642
- const implementationPlan = buildImplementationPlan(profile, selectedFormat, references);
12643
- const governanceMarkdown = renderGovernanceMarkdown(designContract, implementationPlan, selectedFormat);
14166
+ const designContract = buildDesignContract({
14167
+ brief,
14168
+ urls,
14169
+ references,
14170
+ plan: generationPlan,
14171
+ format: effectiveFormat
14172
+ });
14173
+ const followthrough = buildFollowthrough({
14174
+ generationPlan,
14175
+ briefExpansion: effectiveBriefExpansion,
14176
+ synthesis,
14177
+ includePrototypeGuidance,
14178
+ referencePatternBoard,
14179
+ designVectors,
14180
+ targetAnalysis
14181
+ });
14182
+ const implementationPlan = buildImplementationPlan({
14183
+ profile,
14184
+ format: effectiveFormat,
14185
+ references,
14186
+ synthesis,
14187
+ designVectors
14188
+ });
14189
+ const governanceMarkdown = renderGovernanceMarkdown(designContract, implementationPlan, effectiveFormat);
12644
14190
  const implementationPlanMarkdown = renderImplementationMarkdown(implementationPlan);
12645
- const prototypeGuidanceMarkdown = input.includePrototypeGuidance ? renderPrototypeGuidance(profile) : null;
14191
+ const prototypeGuidanceMarkdown = includePrototypeGuidance ? renderPrototypeGuidance(profile, synthesis, designVectors, targetAnalysis) : null;
12646
14192
  const designMarkdown = [
12647
14193
  "# 1. Executive Summary",
12648
14194
  "",
12649
14195
  formatBulletList2([
12650
14196
  `Analyzed brief plus ${references.length || 0} inspiration reference(s).`,
12651
- `Chosen design direction: ${selectedFormat.archetype}.`,
14197
+ `Chosen design direction: ${designVectors.surfaceIntent}.`,
12652
14198
  `Route profile: ${PROFILE_CONFIG[profile].direction}.`,
12653
14199
  `Prompt format: ${selectedFormat.label} (${input.briefExpansion.templateVersion}).`,
12654
14200
  "Final outcome: a reusable design contract, engineering plan, and optional prototype guidance.",
@@ -12657,16 +14203,39 @@ var buildInspiredesignPacket = (input) => {
12657
14203
  "",
12658
14204
  "# 2. Inspiration Analysis",
12659
14205
  "",
12660
- references.length > 0 ? references.map(renderReferenceMarkdown).join("\n\n") : "- No live inspiration source was provided. The system is derived entirely from the brief.",
14206
+ renderInspirationAnalysis(references, usableReferences),
12661
14207
  "",
12662
14208
  "# 3. Unified Design Direction",
12663
14209
  "",
14210
+ "## 3.1 Reference-Specific Build Rules",
14211
+ "",
14212
+ formatBulletList2(synthesis.lines.length > 0 ? synthesis.lines : ["No live reference cues were captured."]),
14213
+ "",
14214
+ "## 3.2 Reference Pattern Board",
14215
+ "",
14216
+ formatBulletList2(referencePatternBoard.synthesis.sharedStrengths.length > 0 ? referencePatternBoard.synthesis.sharedStrengths : ["No live reference cues were captured."]),
14217
+ "",
14218
+ "## 3.3 Design Vectors",
14219
+ "",
14220
+ formatBulletList2([
14221
+ `source priority: ${designVectors.sourcePriority}`,
14222
+ `direction: ${designVectors.directionLabel}`,
14223
+ `premium posture: ${designVectors.premiumPosture.join(" ")}`,
14224
+ `motion posture: ${designVectors.motionPosture.join(" ")}`,
14225
+ `section architecture: ${designVectors.sectionArchitecture.join(" ")}`,
14226
+ `interaction moments: ${designVectors.interactionMoments.join(" ")}`,
14227
+ `material effects: ${designVectors.materialEffects.join(" ")}`,
14228
+ `advanced motion advisory: ${designVectors.advancedMotionAdvisory.join(" ")}`
14229
+ ]),
14230
+ "",
14231
+ "## 3.4 System Direction",
14232
+ "",
12664
14233
  formatBulletList2([
12665
14234
  `visual personality: ${PROFILE_CONFIG[profile].visualPersonality}`,
12666
14235
  `tone: ${PROFILE_CONFIG[profile].brandTone}`,
12667
- `layout archetype: ${selectedFormat.layoutArchetype}`,
12668
- `typography system: ${selectedFormat.typographySystem}`,
12669
- `motion grammar: ${selectedFormat.motionGrammar}`,
14236
+ `layout archetype: ${effectiveFormat.layoutArchetype}`,
14237
+ `typography system: ${effectiveFormat.typographySystem}`,
14238
+ `motion grammar: ${effectiveFormat.motionGrammar}`,
12670
14239
  `UX principles: ${PROFILE_CONFIG[profile].hierarchyPrinciples.join(" ")}`,
12671
14240
  `interaction philosophy: ${PROFILE_CONFIG[profile].interactionPhilosophy}`,
12672
14241
  "branding posture: preserve the intent of the references without cloning brand-only assets.",
@@ -12695,33 +14264,197 @@ var buildInspiredesignPacket = (input) => {
12695
14264
  implementationPlan,
12696
14265
  implementationPlanMarkdown,
12697
14266
  prototypeGuidanceMarkdown,
12698
- evidence: buildEvidencePayload(brief, input.briefExpansion, urls, references)
14267
+ evidence: buildEvidencePayload({
14268
+ brief,
14269
+ briefExpansion: effectiveBriefExpansion,
14270
+ advancedBriefMarkdown,
14271
+ urls,
14272
+ references,
14273
+ referencePatternBoard,
14274
+ designVectors,
14275
+ targetAnalysis
14276
+ })
12699
14277
  };
12700
14278
  };
12701
14279
 
12702
- // src/providers/renderer.ts
12703
- var toCurrency = (value) => `$${value.toFixed(2)}`;
12704
- var primaryConstraintSummaryFromMeta = (meta) => {
12705
- const summary = meta.primaryConstraintSummary;
12706
- return typeof summary === "string" && summary.trim().length > 0 ? summary.trim() : null;
12707
- };
12708
- var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
12709
- var inspiredesignCaptureAttemptReportFromMeta = (meta) => {
12710
- const report = meta.captureAttemptReport;
12711
- if (typeof report !== "object" || report === null || Array.isArray(report)) {
12712
- return null;
12713
- }
12714
- const candidate = report;
12715
- if (!isStringArray(candidate.worked) || !isStringArray(candidate.didNotWork)) {
12716
- return null;
12717
- }
12718
- return {
12719
- worked: candidate.worked,
12720
- didNotWork: candidate.didNotWork
12721
- };
14280
+ // src/providers/workflow-handoff.ts
14281
+ var PRODUCT_VIDEO_BRIEF_HELPER_PATH = "./skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh";
14282
+ var PRODUCT_VIDEO_BRIEF_HELPER_COMMAND = `${PRODUCT_VIDEO_BRIEF_HELPER_PATH} <pack>/manifest.json`;
14283
+ var createSuccessHandoff = (followthroughSummary, suggestedNextAction, suggestedSteps) => ({
14284
+ followthroughSummary,
14285
+ suggestedNextAction,
14286
+ suggestedSteps
14287
+ });
14288
+ var cliExample = (command, args = "") => `npx opendevbrowser ${command}${args ? ` ${args}` : ""}`;
14289
+ var quoteCliValue = (value) => JSON.stringify(value);
14290
+ var buildResearchRerunCommand = (input) => cliExample(
14291
+ "research run",
14292
+ `--topic ${quoteCliValue(input.topic)} --days 14 --source-selection auto --sources web,community --browser-mode ${input.browserMode ?? "managed"} --mode json --output-format json`
14293
+ );
14294
+ var buildShoppingRerunCommand = (input) => {
14295
+ const providers = input.providers?.length ? ` --providers ${input.providers.join(",")}` : " --providers shopping/bestbuy,shopping/ebay";
14296
+ const budget = typeof input.budget === "number" ? ` --budget ${input.budget}` : "";
14297
+ const region = input.region ? ` --region ${quoteCliValue(input.region)}` : "";
14298
+ const browserMode = ` --browser-mode ${input.browserMode ?? "managed"}`;
14299
+ const sort = input.sort ? ` --sort ${input.sort}` : "";
14300
+ return cliExample(
14301
+ "shopping run",
14302
+ `--query ${quoteCliValue(input.query)}${providers}${budget}${region}${browserMode}${sort} --use-cookies --challenge-automation-mode browser_with_helper --mode json --output-format json`
14303
+ );
12722
14304
  };
12723
- var inspiredesignCaptureAttemptSummaryFromMeta = (meta) => {
12724
- const summary = meta.captureAttemptSummary;
14305
+ var buildProductVideoRerunCommand = (input = {}) => {
14306
+ const target = input.productUrl ? `--product-url ${quoteCliValue(input.productUrl)}` : `--product-name ${quoteCliValue(input.productName ?? "<product-name>")}`;
14307
+ const providerHint = input.providerHint ? ` --provider-hint ${input.providerHint}` : "";
14308
+ const screenshots = input.includeScreenshots ? " --include-screenshots" : "";
14309
+ const allImages = input.includeAllImages ? " --include-all-images" : "";
14310
+ const includeCopy = input.includeCopy ? " --include-copy" : "";
14311
+ const browserMode = ` --browser-mode ${input.browserMode ?? "managed"}`;
14312
+ return cliExample(
14313
+ "product-video run",
14314
+ `${target}${providerHint}${screenshots}${allImages}${includeCopy}${browserMode} --use-cookies --challenge-automation-mode browser_with_helper --output-format json`
14315
+ );
14316
+ };
14317
+ var buildMacroResolveArgs = (input, options) => {
14318
+ const defaultProvider = input.defaultProvider ? ` --default-provider ${input.defaultProvider}` : "";
14319
+ const execute = options?.execute ? " --execute" : "";
14320
+ const browserMode = options?.browserMode ? ` --browser-mode ${options.browserMode}` : "";
14321
+ const challenge = options?.challengeAutomationMode ? ` --challenge-automation-mode ${options.challengeAutomationMode}` : "";
14322
+ const outputFormat = options?.includeOutputFormat === false ? "" : " --output-format json";
14323
+ return `--expression ${quoteCliValue(input.expression)}${defaultProvider}${execute}${browserMode}${challenge}${outputFormat}`;
14324
+ };
14325
+ var buildMacroPreviewCommand = (input) => cliExample("macro-resolve", buildMacroResolveArgs(input));
14326
+ var buildMacroExecuteCommand = (input, challengeAutomationMode, browserMode) => cliExample("macro-resolve", buildMacroResolveArgs(input, {
14327
+ execute: true,
14328
+ browserMode,
14329
+ challengeAutomationMode
14330
+ }));
14331
+ var buildResearchSuccessHandoff = (input) => {
14332
+ const rerunCommand = buildResearchRerunCommand(input);
14333
+ return createSuccessHandoff(
14334
+ "Review the ranked records and artifact bundle before turning the result into a publishable claim.",
14335
+ `Open the returned artifact path, inspect the supporting records, and rerun ${rerunCommand} if you need a tighter evidence set.`,
14336
+ [
14337
+ { reason: "Check which records actually support the final claim." },
14338
+ {
14339
+ reason: "Rerun with explicit sources and a narrower timebox if the evidence set is still too broad.",
14340
+ command: rerunCommand
14341
+ }
14342
+ ]
14343
+ );
14344
+ };
14345
+ var buildShoppingSuccessHandoff = (input) => {
14346
+ const rerunCommand = buildShoppingRerunCommand(input);
14347
+ return createSuccessHandoff(
14348
+ "Review the offer set and diagnostics before calling any result a strong deal.",
14349
+ `Inspect the offers and meta.offerFilterDiagnostics, then rerun ${rerunCommand} if you need a tighter comparison.`,
14350
+ [
14351
+ { reason: "Check which offers survived the workflow filters and why." },
14352
+ {
14353
+ reason: "Rerun with explicit providers or updated budget and region inputs if the comparison is still noisy.",
14354
+ command: rerunCommand
14355
+ }
14356
+ ]
14357
+ );
14358
+ };
14359
+ var buildProductVideoSuccessHandoff = (input = {}) => {
14360
+ const rerunCommand = buildProductVideoRerunCommand(input);
14361
+ return createSuccessHandoff(
14362
+ "Review the generated asset pack to confirm whether it is visual-ready or metadata-first before briefing production.",
14363
+ "Open the returned pack path, inspect manifest.json plus copy and features, then run the product-video brief helper with that manifest path to generate production briefs and sourcing notes.",
14364
+ [
14365
+ { reason: "Confirm whether the pack already includes enough images or screenshots for production." },
14366
+ {
14367
+ reason: "Run the product-presentation-asset brief helper on manifest.json to generate the production brief files.",
14368
+ command: PRODUCT_VIDEO_BRIEF_HELPER_COMMAND
14369
+ },
14370
+ {
14371
+ reason: "Rerun the asset workflow with adjusted provider or media flags when the current pack is too thin.",
14372
+ command: rerunCommand
14373
+ },
14374
+ { reason: "Source or capture visuals before final handoff if the pack is metadata-first." }
14375
+ ]
14376
+ );
14377
+ };
14378
+ var buildMacroResolveSuccessHandoff = (input) => {
14379
+ const previewCommand = buildMacroPreviewCommand(input);
14380
+ const executeCommand = buildMacroExecuteCommand(input);
14381
+ const browserRetryCommand = buildMacroExecuteCommand(input, "browser_with_helper", "extension");
14382
+ if (!input.execute) {
14383
+ return createSuccessHandoff(
14384
+ "Review the resolved provider action and provenance before executing the macro.",
14385
+ `Run ${executeCommand} when the resolved action looks correct.`,
14386
+ [
14387
+ { reason: "Inspect resolution.action and resolution.provenance to confirm provider and query shaping." },
14388
+ { reason: "Execute the resolved macro once the plan looks correct.", command: executeCommand },
14389
+ { reason: "Add --default-provider only when you need to force a different provider lane.", command: previewCommand }
14390
+ ]
14391
+ );
14392
+ }
14393
+ if (input.blocked) {
14394
+ return createSuccessHandoff(
14395
+ "Review execution.meta.blocker and failures before retrying the macro.",
14396
+ `Run ${browserRetryCommand} after checking execution.meta.blocker and the current recovery path.`,
14397
+ [
14398
+ { reason: "Inspect execution.meta.blocker and execution.failures before retrying." },
14399
+ { reason: "Retry with browser-scoped challenge automation when the blocker requires live follow-up.", command: browserRetryCommand },
14400
+ { reason: "Preview the resolved action again if you need to switch providers before another execute attempt.", command: previewCommand }
14401
+ ]
14402
+ );
14403
+ }
14404
+ return createSuccessHandoff(
14405
+ "Review execution.records and trace metadata before widening the macro or changing providers.",
14406
+ `Inspect execution.records and execution.meta, then rerun ${previewCommand} if you need a narrower plan.`,
14407
+ [
14408
+ { reason: "Inspect execution.records and execution.meta to confirm the resolved action hit the expected lane." },
14409
+ { reason: "Preview the macro again before changing providers or expression scope.", command: previewCommand },
14410
+ { reason: "Re-execute with browser-scoped challenge automation when the target requires live browser recovery.", command: browserRetryCommand }
14411
+ ]
14412
+ );
14413
+ };
14414
+ var buildInspiredesignSuccessHandoff = (input) => createSuccessHandoff(
14415
+ input.summary,
14416
+ input.nextStep,
14417
+ [
14418
+ { reason: INSPIREDESIGN_HANDOFF_GUIDANCE.reviewAdvancedBrief },
14419
+ {
14420
+ reason: "Load the baseline workflow runbook before implementation.",
14421
+ command: input.commandExamples.loadBestPractices
14422
+ },
14423
+ {
14424
+ reason: "Load the Canvas contract lane before patching.",
14425
+ command: input.commandExamples.loadDesignAgent
14426
+ },
14427
+ {
14428
+ reason: INSPIREDESIGN_HANDOFF_GUIDANCE.prepareCanvasPlanRequest,
14429
+ command: input.commandExamples.continueInCanvas
14430
+ },
14431
+ { reason: input.deepCaptureRecommendation }
14432
+ ]
14433
+ );
14434
+
14435
+ // src/providers/renderer.ts
14436
+ var toCurrency = (value) => `$${value.toFixed(2)}`;
14437
+ var primaryConstraintSummaryFromMeta = (meta) => {
14438
+ const summary = meta.primaryConstraintSummary;
14439
+ return typeof summary === "string" && summary.trim().length > 0 ? summary.trim() : null;
14440
+ };
14441
+ var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
14442
+ var inspiredesignCaptureAttemptReportFromMeta = (meta) => {
14443
+ const report = meta.captureAttemptReport;
14444
+ if (typeof report !== "object" || report === null || Array.isArray(report)) {
14445
+ return null;
14446
+ }
14447
+ const candidate = report;
14448
+ if (!isStringArray(candidate.worked) || !isStringArray(candidate.didNotWork)) {
14449
+ return null;
14450
+ }
14451
+ return {
14452
+ worked: candidate.worked,
14453
+ didNotWork: candidate.didNotWork
14454
+ };
14455
+ };
14456
+ var inspiredesignCaptureAttemptSummaryFromMeta = (meta) => {
14457
+ const summary = meta.captureAttemptSummary;
12725
14458
  if (typeof summary === "string" && summary.trim().length > 0) {
12726
14459
  return summary.trim();
12727
14460
  }
@@ -12962,26 +14695,12 @@ var renderInspiredesign = (args) => {
12962
14695
  evidence: args.evidence,
12963
14696
  meta: args.meta
12964
14697
  };
12965
- const suggestedSteps = [
12966
- {
12967
- reason: INSPIREDESIGN_HANDOFF_GUIDANCE.reviewAdvancedBrief
12968
- },
12969
- {
12970
- reason: "Load the baseline workflow runbook before implementation.",
12971
- command: args.designAgentHandoff.commandExamples.loadBestPractices
12972
- },
12973
- {
12974
- reason: "Load the Canvas contract lane before patching.",
12975
- command: args.designAgentHandoff.commandExamples.loadDesignAgent
12976
- },
12977
- {
12978
- reason: INSPIREDESIGN_HANDOFF_GUIDANCE.prepareCanvasPlanRequest,
12979
- command: args.designAgentHandoff.commandExamples.continueInCanvas
12980
- },
12981
- {
12982
- reason: args.designAgentHandoff.deepCaptureRecommendation
12983
- }
12984
- ];
14698
+ const handoff = buildInspiredesignSuccessHandoff({
14699
+ summary: followthroughSummary,
14700
+ nextStep: args.designAgentHandoff.nextStep,
14701
+ commandExamples: args.designAgentHandoff.commandExamples,
14702
+ deepCaptureRecommendation: args.designAgentHandoff.deepCaptureRecommendation
14703
+ });
12985
14704
  const files = [
12986
14705
  { path: INSPIREDESIGN_HANDOFF_FILES.designMarkdown, content: args.designMarkdown },
12987
14706
  { path: INSPIREDESIGN_HANDOFF_FILES.advancedBrief, content: args.advancedBriefMarkdown },
@@ -13005,9 +14724,7 @@ var renderInspiredesign = (args) => {
13005
14724
  response: {
13006
14725
  mode: args.mode,
13007
14726
  summary,
13008
- followthroughSummary,
13009
- suggestedNextAction: args.designAgentHandoff.nextStep,
13010
- suggestedSteps,
14727
+ ...handoff,
13011
14728
  ...captureAttemptFields,
13012
14729
  meta: args.meta
13013
14730
  },
@@ -13028,9 +14745,7 @@ var renderInspiredesign = (args) => {
13028
14745
  implementationPlan: args.implementationPlan,
13029
14746
  prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
13030
14747
  evidence: args.evidence,
13031
- followthroughSummary,
13032
- suggestedNextAction: args.designAgentHandoff.nextStep,
13033
- suggestedSteps,
14748
+ ...handoff,
13034
14749
  ...captureAttemptFields,
13035
14750
  meta: args.meta
13036
14751
  },
@@ -13044,9 +14759,7 @@ var renderInspiredesign = (args) => {
13044
14759
  markdown: args.designMarkdown,
13045
14760
  implementationPlanMarkdown: args.implementationPlanMarkdown,
13046
14761
  prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
13047
- followthroughSummary,
13048
- suggestedNextAction: args.designAgentHandoff.nextStep,
13049
- suggestedSteps,
14762
+ ...handoff,
13050
14763
  ...captureAttemptFields,
13051
14764
  meta: args.meta
13052
14765
  },
@@ -13058,9 +14771,7 @@ var renderInspiredesign = (args) => {
13058
14771
  response: {
13059
14772
  mode: args.mode,
13060
14773
  context: contextPayload,
13061
- followthroughSummary,
13062
- suggestedNextAction: args.designAgentHandoff.nextStep,
13063
- suggestedSteps,
14774
+ ...handoff,
13064
14775
  ...captureAttemptFields,
13065
14776
  meta: args.meta
13066
14777
  },
@@ -13070,9 +14781,7 @@ var renderInspiredesign = (args) => {
13070
14781
  return {
13071
14782
  response: {
13072
14783
  mode: "path",
13073
- followthroughSummary,
13074
- suggestedNextAction: args.designAgentHandoff.nextStep,
13075
- suggestedSteps,
14784
+ ...handoff,
13076
14785
  ...captureAttemptFields,
13077
14786
  meta: args.meta
13078
14787
  },
@@ -13093,251 +14802,119 @@ var CANVAS_GOVERNANCE_BLOCK_KEYS = [
13093
14802
  "colorSystem",
13094
14803
  "surfaceSystem",
13095
14804
  "iconSystem",
13096
- "motionSystem",
13097
- "responsiveSystem",
13098
- "accessibilityPolicy",
13099
- "libraryPolicy",
13100
- "runtimeBudgets"
13101
- ];
13102
- var CANVAS_REQUIRED_MUTATION_GOVERNANCE_KEYS = [
13103
- "intent",
13104
- "generationPlan",
13105
- "designLanguage",
13106
- "contentModel",
13107
- "layoutSystem",
13108
- "typographySystem",
13109
- "motionSystem",
13110
- "responsiveSystem",
13111
- "accessibilityPolicy"
13112
- ];
13113
- var CANVAS_REQUIRED_SAVE_GOVERNANCE_KEYS = [
13114
- "intent",
13115
- "generationPlan",
13116
- "designLanguage",
13117
- "contentModel",
13118
- "layoutSystem",
13119
- "typographySystem",
13120
- "colorSystem",
13121
- "surfaceSystem",
13122
- "iconSystem",
13123
- "motionSystem",
13124
- "responsiveSystem",
13125
- "accessibilityPolicy",
13126
- "libraryPolicy",
13127
- "runtimeBudgets"
13128
- ];
13129
- var CANVAS_OPTIONAL_INHERITED_GOVERNANCE_KEYS = [
13130
- "colorSystem",
13131
- "surfaceSystem",
13132
- "iconSystem",
13133
- "libraryPolicy",
13134
- "runtimeBudgets"
13135
- ];
13136
- var CANVAS_GENERATION_PLAN_REQUIRED_FIELDS = [
13137
- "targetOutcome",
13138
- "visualDirection",
13139
- "layoutStrategy",
13140
- "contentStrategy",
13141
- "componentStrategy",
13142
- "motionPosture",
13143
- "responsivePosture",
13144
- "accessibilityPosture",
13145
- "validationTargets"
13146
- ];
13147
- var CANVAS_VISUAL_DIRECTION_PROFILES = [
13148
- "clean-room",
13149
- "cinematic-minimal",
13150
- "product-story",
13151
- "commerce-system",
13152
- "control-room",
13153
- "ops-control",
13154
- "auth-focused",
13155
- "settings-system",
13156
- "documentation"
13157
- ];
13158
- var CANVAS_THEME_STRATEGIES = ["single-theme", "light-dark-parity", "multi-theme-system"];
13159
- var CANVAS_NAVIGATION_MODELS = ["global-header", "sidebar", "tabbed", "contextual", "immersive"];
13160
- var CANVAS_INTERACTION_STATES = [
13161
- "default",
13162
- "hover",
13163
- "focus",
13164
- "active",
13165
- "disabled",
13166
- "loading",
13167
- "empty",
13168
- "error",
13169
- "success",
13170
- "selected"
13171
- ];
13172
- var CANVAS_PLAN_VIEWPORTS = ["desktop", "tablet", "mobile"];
13173
- var CANVAS_PLAN_THEMES = ["light", "dark"];
13174
- var CANVAS_MOTION_LEVELS = ["none", "minimal", "subtle", "expressive"];
13175
- var CANVAS_REDUCED_MOTION_POLICIES = ["respect-user-preference", "static-alternative"];
13176
- var CANVAS_KEYBOARD_NAVIGATION_MODES = ["full", "core-flows"];
13177
- var CANVAS_BROWSER_VALIDATION_MODES = ["required", "optional"];
13178
- var CANVAS_VALIDATION_TARGET_BLOCK_ON_CODES = [
13179
- "missing-generation-plan",
13180
- "invalid-generation-plan",
13181
- "missing-governance-block",
13182
- "missing-intent",
13183
- "missing-design-language",
13184
- "missing-content-model",
13185
- "missing-typography-system",
13186
- "missing-color-role",
13187
- "missing-surface-policy",
13188
- "missing-state-coverage",
13189
- "missing-reduced-motion-policy",
13190
- "missing-responsive-policy",
13191
- "overflow",
13192
- "token-missing",
13193
- "broken-asset-reference",
13194
- "contrast-failure",
13195
- "hierarchy-weak",
13196
- "asset-provenance-missing",
13197
- "font-policy-missing",
13198
- "font-load-failure",
13199
- "reduced-motion-violation",
13200
- "unresolved-component-binding",
13201
- "icon-policy-violation",
13202
- "library-policy-violation",
13203
- "responsive-mismatch",
13204
- "runtime-budget-exceeded",
13205
- "unsupported-target",
13206
- "export-warning"
13207
- ];
13208
- var CANVAS_PUBLIC_WARNING_CLASSES = CANVAS_VALIDATION_TARGET_BLOCK_ON_CODES;
13209
-
13210
- // src/providers/workflow-handoff.ts
13211
- var PRODUCT_VIDEO_BRIEF_HELPER_PATH = "./skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh";
13212
- var PRODUCT_VIDEO_BRIEF_HELPER_COMMAND = `${PRODUCT_VIDEO_BRIEF_HELPER_PATH} <pack>/manifest.json`;
13213
- var createSuccessHandoff = (followthroughSummary, suggestedNextAction, suggestedSteps) => ({
13214
- followthroughSummary,
13215
- suggestedNextAction,
13216
- suggestedSteps
13217
- });
13218
- var cliExample = (command, args = "") => `npx opendevbrowser ${command}${args ? ` ${args}` : ""}`;
13219
- var quoteCliValue = (value) => JSON.stringify(value);
13220
- var buildResearchRerunCommand = (topic) => cliExample(
13221
- "research run",
13222
- `--topic ${quoteCliValue(topic)} --days 14 --source-selection auto --sources web,community --mode json --output-format json`
13223
- );
13224
- var buildShoppingRerunCommand = (input) => {
13225
- const providers = input.providers?.length ? ` --providers ${input.providers.join(",")}` : " --providers shopping/bestbuy,shopping/ebay";
13226
- const budget = typeof input.budget === "number" ? ` --budget ${input.budget}` : "";
13227
- const region = input.region ? ` --region ${quoteCliValue(input.region)}` : "";
13228
- const browserMode = ` --browser-mode ${input.browserMode ?? "managed"}`;
13229
- const sort = input.sort ? ` --sort ${input.sort}` : "";
13230
- return cliExample(
13231
- "shopping run",
13232
- `--query ${quoteCliValue(input.query)}${providers}${budget}${region}${browserMode}${sort} --mode json --output-format json`
13233
- );
13234
- };
13235
- var buildProductVideoRerunCommand = (input = {}) => {
13236
- const target = input.productUrl ? `--product-url ${quoteCliValue(input.productUrl)}` : `--product-name ${quoteCliValue(input.productName ?? "<product-name>")}`;
13237
- const providerHint = input.providerHint ? ` --provider-hint ${input.providerHint}` : "";
13238
- const screenshots = input.includeScreenshots ? " --include-screenshots" : "";
13239
- const allImages = input.includeAllImages ? " --include-all-images" : "";
13240
- const includeCopy = input.includeCopy ? " --include-copy" : "";
13241
- return cliExample(
13242
- "product-video run",
13243
- `${target}${providerHint}${screenshots}${allImages}${includeCopy} --output-format json`
13244
- );
13245
- };
13246
- var buildMacroResolveArgs = (input, options) => {
13247
- const defaultProvider = input.defaultProvider ? ` --default-provider ${input.defaultProvider}` : "";
13248
- const execute = options?.execute ? " --execute" : "";
13249
- const challenge = options?.challengeAutomationMode ? ` --challenge-automation-mode ${options.challengeAutomationMode}` : "";
13250
- const outputFormat = options?.includeOutputFormat === false ? "" : " --output-format json";
13251
- return `--expression ${quoteCliValue(input.expression)}${defaultProvider}${execute}${challenge}${outputFormat}`;
13252
- };
13253
- var buildMacroPreviewCommand = (input) => cliExample("macro-resolve", buildMacroResolveArgs(input));
13254
- var buildMacroExecuteCommand = (input, challengeAutomationMode) => cliExample("macro-resolve", buildMacroResolveArgs(input, {
13255
- execute: true,
13256
- challengeAutomationMode
13257
- }));
13258
- var buildResearchSuccessHandoff = (topic) => {
13259
- const rerunCommand = buildResearchRerunCommand(topic);
13260
- return createSuccessHandoff(
13261
- "Review the ranked records and artifact bundle before turning the result into a publishable claim.",
13262
- `Open the returned artifact path, inspect the supporting records, and rerun ${rerunCommand} if you need a tighter evidence set.`,
13263
- [
13264
- { reason: "Check which records actually support the final claim." },
13265
- {
13266
- reason: "Rerun with explicit sources and a narrower timebox if the evidence set is still too broad.",
13267
- command: rerunCommand
13268
- }
13269
- ]
13270
- );
13271
- };
13272
- var buildShoppingSuccessHandoff = (input) => {
13273
- const rerunCommand = buildShoppingRerunCommand(input);
13274
- return createSuccessHandoff(
13275
- "Review the offer set and diagnostics before calling any result a strong deal.",
13276
- `Inspect the offers and meta.offerFilterDiagnostics, then rerun ${rerunCommand} if you need a tighter comparison.`,
13277
- [
13278
- { reason: "Check which offers survived the workflow filters and why." },
13279
- {
13280
- reason: "Rerun with explicit providers or updated budget and region inputs if the comparison is still noisy.",
13281
- command: rerunCommand
13282
- }
13283
- ]
13284
- );
13285
- };
13286
- var buildProductVideoSuccessHandoff = (input = {}) => {
13287
- const rerunCommand = buildProductVideoRerunCommand(input);
13288
- return createSuccessHandoff(
13289
- "Review the generated asset pack to confirm whether it is visual-ready or metadata-first before briefing production.",
13290
- `Open the returned pack path, inspect manifest.json plus copy and features, then run ${PRODUCT_VIDEO_BRIEF_HELPER_COMMAND} to generate production briefs and sourcing notes.`,
13291
- [
13292
- { reason: "Confirm whether the pack already includes enough images or screenshots for production." },
13293
- {
13294
- reason: "Run the product-presentation-asset brief helper on manifest.json to generate the production brief files.",
13295
- command: PRODUCT_VIDEO_BRIEF_HELPER_COMMAND
13296
- },
13297
- {
13298
- reason: "Rerun the asset workflow with adjusted provider or media flags when the current pack is too thin.",
13299
- command: rerunCommand
13300
- },
13301
- { reason: "Source or capture visuals before final handoff if the pack is metadata-first." }
13302
- ]
13303
- );
13304
- };
13305
- var buildMacroResolveSuccessHandoff = (input) => {
13306
- const previewCommand = buildMacroPreviewCommand(input);
13307
- const executeCommand = buildMacroExecuteCommand(input);
13308
- const browserRetryCommand = buildMacroExecuteCommand(input, "browser");
13309
- if (!input.execute) {
13310
- return createSuccessHandoff(
13311
- "Review the resolved provider action and provenance before executing the macro.",
13312
- `Run ${executeCommand} when the resolved action looks correct.`,
13313
- [
13314
- { reason: "Inspect resolution.action and resolution.provenance to confirm provider and query shaping." },
13315
- { reason: "Execute the resolved macro once the plan looks correct.", command: executeCommand },
13316
- { reason: "Add --default-provider only when you need to force a different provider lane.", command: previewCommand }
13317
- ]
13318
- );
13319
- }
13320
- if (input.blocked) {
13321
- return createSuccessHandoff(
13322
- "Review execution.meta.blocker and failures before retrying the macro.",
13323
- `Run ${browserRetryCommand} after checking execution.meta.blocker and the current recovery path.`,
13324
- [
13325
- { reason: "Inspect execution.meta.blocker and execution.failures before retrying." },
13326
- { reason: "Retry with browser-scoped challenge automation when the blocker requires live follow-up.", command: browserRetryCommand },
13327
- { reason: "Preview the resolved action again if you need to switch providers before another execute attempt.", command: previewCommand }
13328
- ]
13329
- );
13330
- }
13331
- return createSuccessHandoff(
13332
- "Review execution.records and trace metadata before widening the macro or changing providers.",
13333
- `Inspect execution.records and execution.meta, then rerun ${previewCommand} if you need a narrower plan.`,
13334
- [
13335
- { reason: "Inspect execution.records and execution.meta to confirm the resolved action hit the expected lane." },
13336
- { reason: "Preview the macro again before changing providers or expression scope.", command: previewCommand },
13337
- { reason: "Re-execute with browser-scoped challenge automation when the target requires live browser recovery.", command: browserRetryCommand }
13338
- ]
13339
- );
13340
- };
14805
+ "motionSystem",
14806
+ "responsiveSystem",
14807
+ "accessibilityPolicy",
14808
+ "libraryPolicy",
14809
+ "runtimeBudgets"
14810
+ ];
14811
+ var CANVAS_REQUIRED_MUTATION_GOVERNANCE_KEYS = [
14812
+ "intent",
14813
+ "generationPlan",
14814
+ "designLanguage",
14815
+ "contentModel",
14816
+ "layoutSystem",
14817
+ "typographySystem",
14818
+ "motionSystem",
14819
+ "responsiveSystem",
14820
+ "accessibilityPolicy"
14821
+ ];
14822
+ var CANVAS_REQUIRED_SAVE_GOVERNANCE_KEYS = [
14823
+ "intent",
14824
+ "generationPlan",
14825
+ "designLanguage",
14826
+ "contentModel",
14827
+ "layoutSystem",
14828
+ "typographySystem",
14829
+ "colorSystem",
14830
+ "surfaceSystem",
14831
+ "iconSystem",
14832
+ "motionSystem",
14833
+ "responsiveSystem",
14834
+ "accessibilityPolicy",
14835
+ "libraryPolicy",
14836
+ "runtimeBudgets"
14837
+ ];
14838
+ var CANVAS_OPTIONAL_INHERITED_GOVERNANCE_KEYS = [
14839
+ "colorSystem",
14840
+ "surfaceSystem",
14841
+ "iconSystem",
14842
+ "libraryPolicy",
14843
+ "runtimeBudgets"
14844
+ ];
14845
+ var CANVAS_GENERATION_PLAN_REQUIRED_FIELDS = [
14846
+ "targetOutcome",
14847
+ "visualDirection",
14848
+ "layoutStrategy",
14849
+ "contentStrategy",
14850
+ "componentStrategy",
14851
+ "motionPosture",
14852
+ "responsivePosture",
14853
+ "accessibilityPosture",
14854
+ "validationTargets"
14855
+ ];
14856
+ var CANVAS_VISUAL_DIRECTION_PROFILES = [
14857
+ "clean-room",
14858
+ "cinematic-minimal",
14859
+ "product-story",
14860
+ "commerce-system",
14861
+ "control-room",
14862
+ "ops-control",
14863
+ "auth-focused",
14864
+ "settings-system",
14865
+ "documentation"
14866
+ ];
14867
+ var CANVAS_THEME_STRATEGIES = ["single-theme", "light-dark-parity", "multi-theme-system"];
14868
+ var CANVAS_NAVIGATION_MODELS = ["global-header", "sidebar", "tabbed", "contextual", "immersive"];
14869
+ var CANVAS_INTERACTION_STATES = [
14870
+ "default",
14871
+ "hover",
14872
+ "focus",
14873
+ "active",
14874
+ "disabled",
14875
+ "loading",
14876
+ "empty",
14877
+ "error",
14878
+ "success",
14879
+ "selected"
14880
+ ];
14881
+ var CANVAS_PLAN_VIEWPORTS = ["desktop", "tablet", "mobile"];
14882
+ var CANVAS_PLAN_THEMES = ["light", "dark"];
14883
+ var CANVAS_MOTION_LEVELS = ["none", "minimal", "subtle", "expressive"];
14884
+ var CANVAS_REDUCED_MOTION_POLICIES = ["respect-user-preference", "static-alternative"];
14885
+ var CANVAS_KEYBOARD_NAVIGATION_MODES = ["full", "core-flows"];
14886
+ var CANVAS_BROWSER_VALIDATION_MODES = ["required", "optional"];
14887
+ var CANVAS_VALIDATION_TARGET_BLOCK_ON_CODES = [
14888
+ "missing-generation-plan",
14889
+ "invalid-generation-plan",
14890
+ "missing-governance-block",
14891
+ "missing-intent",
14892
+ "missing-design-language",
14893
+ "missing-content-model",
14894
+ "missing-typography-system",
14895
+ "missing-color-role",
14896
+ "missing-surface-policy",
14897
+ "missing-state-coverage",
14898
+ "missing-reduced-motion-policy",
14899
+ "missing-responsive-policy",
14900
+ "overflow",
14901
+ "token-missing",
14902
+ "broken-asset-reference",
14903
+ "contrast-failure",
14904
+ "hierarchy-weak",
14905
+ "asset-provenance-missing",
14906
+ "font-policy-missing",
14907
+ "font-load-failure",
14908
+ "reduced-motion-violation",
14909
+ "unresolved-component-binding",
14910
+ "icon-policy-violation",
14911
+ "library-policy-violation",
14912
+ "responsive-mismatch",
14913
+ "runtime-budget-exceeded",
14914
+ "unsupported-target",
14915
+ "export-warning"
14916
+ ];
14917
+ var CANVAS_PUBLIC_WARNING_CLASSES = CANVAS_VALIDATION_TARGET_BLOCK_ON_CODES;
13341
14918
 
13342
14919
  // src/providers/shopping-postprocess.ts
13343
14920
  import { createHash as createHash4 } from "crypto";
@@ -14645,6 +16222,16 @@ var resolveResearchAutoExcludedProviders = (sourceSelection, resolvedSources, de
14645
16222
  return source !== null && sourceSet.has(source);
14646
16223
  }).sort((left, right) => left.localeCompare(right));
14647
16224
  };
16225
+ var buildResearchSearchFilters = (source, args) => ({
16226
+ include_engagement: args.includeEngagement ?? false,
16227
+ timebox_from: args.timebox.from,
16228
+ timebox_to: args.timebox.to,
16229
+ ...source === "community" || source === "social" ? {
16230
+ pageLimit: 1,
16231
+ hopLimit: 0,
16232
+ expansionPerRecord: 0
16233
+ } : {}
16234
+ });
14648
16235
  var compileResearchExecutionPlan = (args) => {
14649
16236
  const topic = args.input.topic?.trim();
14650
16237
  if (!topic) {
@@ -14681,11 +16268,10 @@ var compileResearchExecutionPlan = (args) => {
14681
16268
  source,
14682
16269
  query: topic,
14683
16270
  limit: searchLimit,
14684
- filters: {
14685
- include_engagement: args.input.includeEngagement ?? false,
14686
- timebox_from: timebox.from,
14687
- timebox_to: timebox.to
14688
- }
16271
+ filters: buildResearchSearchFilters(source, {
16272
+ includeEngagement: args.input.includeEngagement,
16273
+ timebox
16274
+ })
14689
16275
  }
14690
16276
  }));
14691
16277
  return {
@@ -14921,7 +16507,7 @@ var executeResearchWorkflowPlan = async (runtime, plan, options) => {
14921
16507
  };
14922
16508
  };
14923
16509
 
14924
- // src/providers/inspiredesign-capture-mode.ts
16510
+ // src/inspiredesign/capture-mode.ts
14925
16511
  var hasInspiredesignUrls = (urls) => {
14926
16512
  return Array.isArray(urls) && urls.some((url) => url.trim().length > 0);
14927
16513
  };
@@ -15493,6 +17079,7 @@ var workflowTestUtils = {
15493
17079
  buildWorkflowResumePayload: (kind, input) => buildWorkflowResumePayload(kind, input)
15494
17080
  };
15495
17081
  var PRODUCT_ASSET_FETCH_TIMEOUT_MS = 15e3;
17082
+ var RESEARCH_PROVIDER_STEP_TIMEOUT_MS = 3e4;
15496
17083
  var resolveAuxiliaryFetchTimeoutMs = (timeoutMs) => {
15497
17084
  if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
15498
17085
  return PRODUCT_ASSET_FETCH_TIMEOUT_MS;
@@ -15676,9 +17263,16 @@ var createRemainingTimeoutResolver = (timeoutMs) => {
15676
17263
  return Math.max(1, timeoutMs - Math.max(0, Date.now() - startedAtMs));
15677
17264
  };
15678
17265
  };
17266
+ var resolveResearchProviderStepTimeoutMs = (timeoutMs) => {
17267
+ if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
17268
+ return void 0;
17269
+ }
17270
+ return Math.max(1, Math.min(timeoutMs, RESEARCH_PROVIDER_STEP_TIMEOUT_MS));
17271
+ };
15679
17272
  var INSPIREDESIGN_RENDER_MODES = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
15680
17273
  var INSPIREDESIGN_CAPTURE_MODES = /* @__PURE__ */ new Set(["off", "deep"]);
15681
17274
  var INSPIREDESIGN_COOKIE_POLICIES = /* @__PURE__ */ new Set(["off", "auto", "required"]);
17275
+ var WORKFLOW_BROWSER_MODES = /* @__PURE__ */ new Set(["auto", "extension", "managed"]);
15682
17276
  var isJsonRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
15683
17277
  var INSPIREDESIGN_CAPTURE_UNAVAILABLE_FAILURE = "Deep capture requested, but browser capture is unavailable in this execution lane.";
15684
17278
  var isCanvasVisualDirectionProfile = (value) => {
@@ -15701,6 +17295,7 @@ var serializeInspiredesignRunInput = (input) => ({
15701
17295
  ...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
15702
17296
  ...input.outputDir ? { outputDir: input.outputDir } : {},
15703
17297
  ...typeof input.ttlHours === "number" ? { ttlHours: input.ttlHours } : {},
17298
+ ...input.browserMode ? { browserMode: input.browserMode } : {},
15704
17299
  ...typeof input.useCookies === "boolean" ? { useCookies: input.useCookies } : {},
15705
17300
  ...input.challengeAutomationMode ? { challengeAutomationMode: input.challengeAutomationMode } : {},
15706
17301
  ...input.cookiePolicyOverride ? { cookiePolicyOverride: input.cookiePolicyOverride } : {}
@@ -15775,6 +17370,7 @@ var parseInspiredesignEnvelopeInput = (input) => {
15775
17370
  ...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
15776
17371
  ...typeof input.outputDir === "string" && input.outputDir.length > 0 ? { outputDir: input.outputDir } : {},
15777
17372
  ...typeof input.ttlHours === "number" ? { ttlHours: input.ttlHours } : {},
17373
+ ...typeof input.browserMode === "string" && WORKFLOW_BROWSER_MODES.has(input.browserMode) ? { browserMode: input.browserMode } : {},
15778
17374
  ...typeof input.useCookies === "boolean" ? { useCookies: input.useCookies } : {},
15779
17375
  ...isChallengeAutomationMode(input.challengeAutomationMode) ? { challengeAutomationMode: input.challengeAutomationMode } : {},
15780
17376
  ...typeof input.cookiePolicyOverride === "string" && INSPIREDESIGN_COOKIE_POLICIES.has(input.cookiePolicyOverride) ? { cookiePolicyOverride: input.cookiePolicyOverride } : {}
@@ -15868,10 +17464,13 @@ var buildInspiredesignStepEnvelope = (workflowInput, trace, stepIndex, url) => b
15868
17464
  }
15869
17465
  );
15870
17466
  var buildInspiredesignFetchOptions = (workflowInput, envelope, timeoutMs) => withWorkflowResumeEnvelopeIntent(
15871
- withChallengeAutomationOverride(
15872
- withCookieOverrides({
15873
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
15874
- }, workflowInput),
17467
+ withBrowserModeOverride(
17468
+ withChallengeAutomationOverride(
17469
+ withCookieOverrides({
17470
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
17471
+ }, workflowInput),
17472
+ workflowInput
17473
+ ),
15875
17474
  workflowInput
15876
17475
  ),
15877
17476
  "workflow.inspiredesign",
@@ -16054,8 +17653,12 @@ var excerptFromInspiredesignCapture = (capture) => {
16054
17653
  return captureSnippet(capture?.snapshot?.content, 240) ?? captureSnippet(capture?.dom?.outerHTML, 240) ?? captureSnippet(capture?.clone?.componentPreview, 240) ?? captureSnippet(capture?.clone?.cssPreview, 240);
16055
17654
  };
16056
17655
  var isInspiredesignFetchRecovered = (reference) => {
16057
- return reference.fetchStatus === "failed" && reference.captureStatus === "captured" && (Boolean(reference.title) || Boolean(reference.excerpt));
17656
+ return reference.fetchStatus === "failed" && reference.captureStatus === "captured" && hasInspiredesignUsableReferenceEvidence(reference);
16058
17657
  };
17658
+ var summarizeInspiredesignRecoveredFetches = (references) => references.filter(isInspiredesignFetchRecovered).map((reference) => ({
17659
+ url: reference.url,
17660
+ ...reference.fetchFailure ? { fetchFailure: reference.fetchFailure } : {}
17661
+ }));
16059
17662
  var buildInspiredesignReference = (url, result, capture) => {
16060
17663
  const primary = getInspiredesignPrimaryRecord(result, url);
16061
17664
  const normalizedCapture = normalizeInspiredesignCaptureEvidence(capture.capture);
@@ -16102,11 +17705,13 @@ var summarizeInspiredesignFetchConstraint = (references) => {
16102
17705
  var buildInspiredesignMeta = (runtime, workflowInput, references, failures, followthrough) => {
16103
17706
  const failedCaptures = references.filter((reference) => reference.captureStatus === "failed");
16104
17707
  const captureAttemptReport = summarizeInspiredesignCaptureAttempts(references);
17708
+ const recoveredFetches = summarizeInspiredesignRecoveredFetches(references);
16105
17709
  let reasonCodeDistribution = summarizeReasonCodeDistribution(failures);
16106
17710
  let meta = withCamelCasePrimaryConstraintMeta(withReasonCodeDistributionMeta({
16107
17711
  selection: {
16108
17712
  urls: workflowInput.urls,
16109
17713
  capture_mode: workflowInput.captureMode,
17714
+ ...workflowInput.browserMode ? { requested_browser_mode: workflowInput.browserMode } : {},
16110
17715
  include_prototype_guidance: Boolean(workflowInput.includePrototypeGuidance)
16111
17716
  },
16112
17717
  metrics: {
@@ -16115,6 +17720,10 @@ var buildInspiredesignMeta = (runtime, workflowInput, references, failures, foll
16115
17720
  captured_references: references.filter((reference) => reference.captureStatus === "captured").length,
16116
17721
  failed_fetches: references.filter((reference) => reference.fetchStatus === "failed" && !isInspiredesignFetchRecovered(reference)).length,
16117
17722
  failed_captures: failedCaptures.length,
17723
+ ...recoveredFetches.length > 0 ? {
17724
+ recovered_fetches: recoveredFetches.length,
17725
+ recovered_fetch_details: recoveredFetches
17726
+ } : {},
16118
17727
  ...captureAttemptReport ? { capture_attempts: captureAttemptReport.counts } : {}
16119
17728
  },
16120
17729
  alerts: buildWorkflowAlerts(runtime, failures)
@@ -16657,10 +18266,17 @@ var runResearchWorkflow = async (runtime, input) => {
16657
18266
  }
16658
18267
  ];
16659
18268
  const buildResearchStepOptions = (step, stepEnvelope) => {
16660
- const stepOptions = withChallengeAutomationOverride(withCookieOverrides({
16661
- source: step.input.source,
16662
- ...typeof workflowInput.timeoutMs === "number" ? { timeoutMs: workflowInput.timeoutMs } : {}
16663
- }, workflowInput), workflowInput);
18269
+ const timeoutMs = resolveResearchProviderStepTimeoutMs(workflowInput.timeoutMs);
18270
+ const stepOptions = withBrowserModeOverride(
18271
+ withChallengeAutomationOverride(
18272
+ withCookieOverrides({
18273
+ source: step.input.source,
18274
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
18275
+ }, workflowInput),
18276
+ workflowInput
18277
+ ),
18278
+ workflowInput
18279
+ );
16664
18280
  return withWorkflowResumeEnvelopeIntent(
16665
18281
  stepOptions,
16666
18282
  "workflow.research",
@@ -16723,7 +18339,8 @@ var runResearchWorkflow = async (runtime, input) => {
16723
18339
  timebox: resolvedTimebox,
16724
18340
  selection: withExcludedProviders({
16725
18341
  source_selection: plan.compiled.sourceSelection,
16726
- resolved_sources: plan.compiled.resolvedSources
18342
+ resolved_sources: plan.compiled.resolvedSources,
18343
+ ...workflowInput.browserMode ? { requested_browser_mode: workflowInput.browserMode } : {}
16727
18344
  }, plan.compiled.autoExcludedProviders),
16728
18345
  metrics: {
16729
18346
  total_records: mergedRecords.length,
@@ -16750,7 +18367,10 @@ var runResearchWorkflow = async (runtime, input) => {
16750
18367
  failures: mergedFailures,
16751
18368
  alerts: buildWorkflowAlerts(runtime, mergedFailures)
16752
18369
  }, primaryConstraintFailures);
16753
- const handoff = buildResearchSuccessHandoff(plan.compiled.topic);
18370
+ const handoff = buildResearchSuccessHandoff({
18371
+ topic: plan.compiled.topic,
18372
+ browserMode: workflowInput.browserMode
18373
+ });
16754
18374
  const responseMeta = withFollowthroughMeta(meta, handoff);
16755
18375
  const rendered = renderResearch({
16756
18376
  mode: workflowInput.mode,
@@ -17185,6 +18805,7 @@ var runProductVideoWorkflow = async (runtime, input, options = {}) => {
17185
18805
  providers: providerHint ? [providerHint] : void 0,
17186
18806
  mode: "json",
17187
18807
  ...timeoutOptions,
18808
+ browserMode: workflowInput.browserMode,
17188
18809
  useCookies: workflowInput.useCookies,
17189
18810
  challengeAutomationMode: workflowInput.challengeAutomationMode,
17190
18811
  cookiePolicyOverride: workflowInput.cookiePolicyOverride
@@ -17263,12 +18884,15 @@ var runProductVideoWorkflow = async (runtime, input, options = {}) => {
17263
18884
  details = await runtime.fetch(
17264
18885
  { url: productUrl },
17265
18886
  withWorkflowResumeEnvelopeIntent(
17266
- withChallengeAutomationOverride(
17267
- withCookieOverrides({
17268
- source,
17269
- providerIds: shoppingProviderId ? [shoppingProviderId] : void 0,
17270
- ...timeoutOptions
17271
- }, workflowInput),
18887
+ withBrowserModeOverride(
18888
+ withChallengeAutomationOverride(
18889
+ withCookieOverrides({
18890
+ source,
18891
+ providerIds: shoppingProviderId ? [shoppingProviderId] : void 0,
18892
+ ...timeoutOptions
18893
+ }, workflowInput),
18894
+ workflowInput
18895
+ ),
17272
18896
  workflowInput
17273
18897
  ),
17274
18898
  "workflow.product_video",
@@ -17418,14 +19042,16 @@ var runProductVideoWorkflow = async (runtime, input, options = {}) => {
17418
19042
  productUrl,
17419
19043
  productName: workflowInput.product_name,
17420
19044
  providerHint,
19045
+ browserMode: workflowInput.browserMode,
17421
19046
  includeScreenshots: workflowInput.include_screenshots,
17422
19047
  includeAllImages: workflowInput.include_all_images,
17423
19048
  includeCopy: workflowInput.include_copy
17424
19049
  });
17425
19050
  const meta = withFollowthroughMeta({
19051
+ ...workflowInput.browserMode ? { selection: { requested_browser_mode: workflowInput.browserMode } } : {},
17426
19052
  alerts: buildWorkflowAlerts(runtime, details.failures),
17427
19053
  failures: details.failures,
17428
- ...primaryIssue ? { primaryConstraintSummary: primaryIssue.summary } : {},
19054
+ ...primaryIssue ? { primaryConstraint: primaryIssue, primaryConstraintSummary: primaryIssue.summary } : {},
17429
19055
  reasonCodeDistribution,
17430
19056
  transcript_strategy_failures: transcriptStrategyFailures,
17431
19057
  transcriptStrategyFailures,
@@ -17466,11 +19092,11 @@ var WORKFLOW_KIND_BY_SUSPENDED_INTENT_KIND2 = {
17466
19092
  "workflow.inspiredesign": "inspiredesign",
17467
19093
  "workflow.product_video": "product_video"
17468
19094
  };
17469
- var EXTENSION_FIRST_SOCIAL_FALLBACK_PLATFORMS = /* @__PURE__ */ new Set(["x", "reddit", "bluesky", "facebook", "linkedin"]);
19095
+ var EXTENSION_FIRST_SOCIAL_FALLBACK_PLATFORMS = /* @__PURE__ */ new Set(["x", "reddit", "bluesky", "facebook", "linkedin", "threads"]);
17470
19096
  var EXTENSION_MINIMAL_TRAVERSAL_SOCIAL_PLATFORMS = /* @__PURE__ */ new Set(["linkedin"]);
17471
19097
  var EXTENSION_FIRST_FALLBACK_MODES = ["extension", "managed_headed"];
17472
19098
  var SOCIAL_BROWSER_RECOVERY_REASON_CODES = /* @__PURE__ */ new Set(["challenge_detected"]);
17473
- var SEARCH_RENDER_RECOVERY_SOCIAL_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit", "facebook"]);
19099
+ var SEARCH_RENDER_RECOVERY_SOCIAL_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit", "facebook", "threads"]);
17474
19100
  var withPrioritizedFallbackModes = (prioritized, existing) => [.../* @__PURE__ */ new Set([...prioritized, ...existing ?? []])];
17475
19101
  var buildSocialRecoveryHints = (platform, options) => {
17476
19102
  const existing = options?.recoveryHints?.();
@@ -17629,6 +19255,154 @@ var SOCIAL_SEARCH_ENDPOINTS = {
17629
19255
  threads: (query, page) => `https://www.threads.net/search?q=${encodeURIComponent(query)}&page=${page}`,
17630
19256
  youtube: (query, page) => `https://www.youtube.com/results?search_query=${encodeURIComponent(query)}&page=${page}`
17631
19257
  };
19258
+ var FALLBACK_SHELL_LINK_SEGMENTS = /* @__PURE__ */ new Set([
19259
+ "account",
19260
+ "auth",
19261
+ "about",
19262
+ "cart",
19263
+ "categories",
19264
+ "category",
19265
+ "collections",
19266
+ "contact",
19267
+ "explore",
19268
+ "help",
19269
+ "home",
19270
+ "legal",
19271
+ "login",
19272
+ "policies",
19273
+ "product",
19274
+ "products",
19275
+ "privacy",
19276
+ "search",
19277
+ "settings",
19278
+ "shop",
19279
+ "signin",
19280
+ "sign-in",
19281
+ "sitemap",
19282
+ "store",
19283
+ "submit",
19284
+ "support",
19285
+ "terms"
19286
+ ]);
19287
+ var FALLBACK_SHELL_TEXT_TOKENS = /* @__PURE__ */ new Set([
19288
+ "account",
19289
+ "ad",
19290
+ "ads",
19291
+ "about",
19292
+ "cart",
19293
+ "contact",
19294
+ "explore",
19295
+ "help",
19296
+ "home",
19297
+ "in",
19298
+ "legal",
19299
+ "log",
19300
+ "login",
19301
+ "policies",
19302
+ "product",
19303
+ "products",
19304
+ "privacy",
19305
+ "search",
19306
+ "settings",
19307
+ "sign",
19308
+ "signin",
19309
+ "submit",
19310
+ "support",
19311
+ "terms"
19312
+ ]);
19313
+ var FALLBACK_HEAD_RE2 = /<head\b[^>]*>[\s\S]*?<\/head>/i;
19314
+ var FALLBACK_BODY_RE2 = /<body\b[^>]*>([\s\S]*?)<\/body>/i;
19315
+ var FALLBACK_MIN_MEANINGFUL_TEXT_CHARS = 20;
19316
+ var FALLBACK_MIN_MEANINGFUL_TOKENS = 3;
19317
+ var FALLBACK_SHELL_PHRASES_RE = /\b(?:search results?|please enable javascript|enable javascript|continue|welcome|accept cookies?|privacy policy|terms of service)\b/i;
19318
+ var extractFallbackBodyHtml = (html) => {
19319
+ const body = FALLBACK_BODY_RE2.exec(html)?.[1];
19320
+ return body ?? html.replace(FALLBACK_HEAD_RE2, " ");
19321
+ };
19322
+ var extractFallbackBodyText = (html) => {
19323
+ return extractText(extractFallbackBodyHtml(html));
19324
+ };
19325
+ var hasUsableFallbackText = (html) => {
19326
+ const text = extractFallbackBodyText(html);
19327
+ const blocker = classifyBlockerSignal({
19328
+ source: "runtime_fetch",
19329
+ message: text,
19330
+ status: 200,
19331
+ providerErrorCode: "unavailable",
19332
+ retryable: true
19333
+ });
19334
+ if (blocker && blocker.type !== "unknown") return false;
19335
+ if (text.length < FALLBACK_MIN_MEANINGFUL_TEXT_CHARS || FALLBACK_SHELL_PHRASES_RE.test(text)) {
19336
+ return false;
19337
+ }
19338
+ const tokens = text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
19339
+ const meaningfulTokens = tokens.filter((token) => !FALLBACK_SHELL_TEXT_TOKENS.has(token));
19340
+ return meaningfulTokens.length >= FALLBACK_MIN_MEANINGFUL_TOKENS;
19341
+ };
19342
+ var isUsableFallbackLink = (link, documentUrl) => {
19343
+ try {
19344
+ const parsed = new URL(link);
19345
+ const source = new URL(documentUrl);
19346
+ const segments = parsed.pathname.toLowerCase().split("/").filter(Boolean);
19347
+ const firstSegment = segments[0];
19348
+ if (parsed.origin === source.origin && parsed.pathname === source.pathname) {
19349
+ return false;
19350
+ }
19351
+ if (segments.length === 0 && parsed.search.length === 0) {
19352
+ return false;
19353
+ }
19354
+ return firstSegment === void 0 || !FALLBACK_SHELL_LINK_SEGMENTS.has(firstSegment);
19355
+ } catch {
19356
+ return false;
19357
+ }
19358
+ };
19359
+ var hasUsableFallbackBodyLink = (documentUrl, html) => extractStructuredContent(extractFallbackBodyHtml(html), documentUrl).links.some((link) => isUsableFallbackLink(link, documentUrl));
19360
+ var hasUsableFallbackContent = (documentUrl, html) => hasUsableFallbackText(html) || hasUsableFallbackBodyLink(documentUrl, html);
19361
+ var isBlockedRedditFallbackLink = (link) => {
19362
+ try {
19363
+ const hostname = new URL(link).hostname.toLowerCase();
19364
+ const isReddit = hostname === "reddit.com" || hostname.endsWith(".reddit.com");
19365
+ return isReddit && !isAllowedSocialSearchExpansionUrl("reddit", link);
19366
+ } catch {
19367
+ return false;
19368
+ }
19369
+ };
19370
+ var shouldOwnerReviewCommunityRedditSearchFallback = (input) => input.providerId === "community/default" && input.source === "community" && input.operation === "search" && isFirstPartySocialSearchRoute("reddit", input.url) && input.extracted.links.length > 0 && input.extracted.links.every(isBlockedRedditFallbackLink);
19371
+ var shouldReturnCompletedFallbackForOwnerReview = (args) => args.document.browserFallback !== void 0 && args.ownerReview?.({
19372
+ providerId: args.providerId,
19373
+ source: args.source,
19374
+ operation: args.operation,
19375
+ url: args.document.url,
19376
+ html: args.document.html,
19377
+ extracted: extractStructuredContent(args.document.html, args.document.url)
19378
+ }) === true;
19379
+ var toCompletedFallbackDocument = (args) => {
19380
+ const resolvedUrl = canonicalizeUrl(readFallbackString(args.fallback.output, "url") ?? args.url);
19381
+ const html = readFallbackString(args.fallback.output, "html");
19382
+ if (!html) {
19383
+ throw toCompletedFallbackOutputError({ ...args, provider: args.providerId, url: resolvedUrl, outputReason: "missing_or_empty_html" });
19384
+ }
19385
+ const extracted = extractStructuredContent(html, resolvedUrl);
19386
+ const reviewInput = {
19387
+ providerId: args.providerId,
19388
+ source: args.source,
19389
+ operation: args.operation,
19390
+ url: resolvedUrl,
19391
+ html,
19392
+ extracted
19393
+ };
19394
+ if (!hasUsableFallbackContent(resolvedUrl, html) && !args.ownerReview?.(reviewInput)) {
19395
+ throw toCompletedFallbackOutputError({ ...args, provider: args.providerId, url: resolvedUrl, outputReason: "empty_extracted_content" });
19396
+ }
19397
+ return {
19398
+ url: resolvedUrl,
19399
+ status: 200,
19400
+ html,
19401
+ text: extracted.text,
19402
+ links: extracted.links,
19403
+ browserFallback: toBrowserFallbackObservation(args.fallback)
19404
+ };
19405
+ };
17632
19406
  var describeDefaultFetchedIssue = (document) => {
17633
19407
  const extracted = extractStructuredContent(document.html, document.url);
17634
19408
  const title = typeof extracted.metadata.title === "string" ? extracted.metadata.title : void 0;
@@ -17690,6 +19464,9 @@ var resolveDefaultFallbackDocumentIfNeeded = async (args) => {
17690
19464
  if (!initialIssue) {
17691
19465
  return { document: currentDocument, ...described };
17692
19466
  }
19467
+ if (shouldReturnCompletedFallbackForOwnerReview({ ...args, document: currentDocument })) {
19468
+ return { document: currentDocument, ...described };
19469
+ }
17693
19470
  if (initialIssue.reasonCode === "env_limited" && !initialIssue.constraint) {
17694
19471
  return { document: currentDocument, ...described };
17695
19472
  }
@@ -17720,18 +19497,18 @@ var resolveDefaultFallbackDocumentIfNeeded = async (args) => {
17720
19497
  fallback
17721
19498
  });
17722
19499
  }
17723
- const resolvedUrl = canonicalizeUrl(readFallbackString(fallback.output, "url") ?? currentDocument.url);
17724
- const html = readFallbackString(fallback.output, "html") ?? "";
17725
- const extracted = extractStructuredContent(html, resolvedUrl);
17726
- currentDocument = {
17727
- url: resolvedUrl,
17728
- status: 200,
17729
- html,
17730
- text: extracted.text,
17731
- links: extracted.links,
17732
- browserFallback: toBrowserFallbackObservation(fallback)
17733
- };
19500
+ currentDocument = toCompletedFallbackDocument({
19501
+ providerId: args.providerId,
19502
+ source: args.source,
19503
+ operation: args.operation,
19504
+ url: currentDocument.url,
19505
+ fallback,
19506
+ ownerReview: args.ownerReview
19507
+ });
17734
19508
  described = describeDefaultFetchedIssue(currentDocument);
19509
+ if (shouldReturnCompletedFallbackForOwnerReview({ ...args, document: currentDocument })) {
19510
+ return { document: currentDocument, ...described };
19511
+ }
17735
19512
  if (!described.issue || described.issue.reasonCode === "env_limited" && !described.issue.constraint) {
17736
19513
  return { document: currentDocument, ...described };
17737
19514
  }
@@ -18008,6 +19785,57 @@ var readResponseTextWithAbort = async (response, args) => {
18008
19785
  }
18009
19786
  };
18010
19787
  var fetchRuntimeDocumentWithFallback = async (args) => {
19788
+ const fallbackPort = args.context?.browserFallbackPort ?? args.browserFallbackPort;
19789
+ const runtimePolicy = args.context?.runtimePolicy;
19790
+ const forcedBrowserTransport = runtimePolicy?.browser.forceTransport === true;
19791
+ const forcedReasonCode = runtimePolicy?.cookies.policy === "required" ? "auth_required" : "env_limited";
19792
+ if (forcedBrowserTransport) {
19793
+ const fallback = await resolveProviderBrowserFallback({
19794
+ browserFallbackPort: fallbackPort,
19795
+ provider: args.provider,
19796
+ source: args.source,
19797
+ operation: args.operation,
19798
+ reasonCode: forcedReasonCode,
19799
+ url: args.url,
19800
+ context: args.context,
19801
+ details: {
19802
+ message: "Direct browser transport was selected for this provider run."
19803
+ },
19804
+ recoveryHints: args.recoveryHints
19805
+ });
19806
+ if (!fallback) {
19807
+ throw new ProviderRuntimeError(
19808
+ providerErrorCodeFromReasonCode(forcedReasonCode),
19809
+ "Direct browser transport is required for this provider run, but no browser transport is available.",
19810
+ {
19811
+ provider: args.provider,
19812
+ source: args.source,
19813
+ retryable: false,
19814
+ reasonCode: forcedReasonCode,
19815
+ details: {
19816
+ reasonCode: forcedReasonCode,
19817
+ browserTransportRequired: true
19818
+ }
19819
+ }
19820
+ );
19821
+ }
19822
+ if (fallback.disposition !== "completed") {
19823
+ throw toProviderFallbackError({
19824
+ provider: args.provider,
19825
+ source: args.source,
19826
+ url: args.url,
19827
+ fallback
19828
+ });
19829
+ }
19830
+ return toCompletedFallbackDocument({
19831
+ providerId: args.provider,
19832
+ source: args.source,
19833
+ operation: args.operation,
19834
+ url: args.url,
19835
+ fallback,
19836
+ ownerReview: args.ownerReview
19837
+ });
19838
+ }
18011
19839
  try {
18012
19840
  return await fetchRuntimeDocument({
18013
19841
  url: args.url,
@@ -18020,7 +19848,9 @@ var fetchRuntimeDocumentWithFallback = async (args) => {
18020
19848
  provider: args.provider,
18021
19849
  source: args.source
18022
19850
  });
18023
- const fallbackPort = args.context?.browserFallbackPort ?? args.browserFallbackPort;
19851
+ if (args.recoverRuntimeErrors === false) {
19852
+ throw error;
19853
+ }
18024
19854
  if (!fallbackPort) {
18025
19855
  throw error;
18026
19856
  }
@@ -18054,17 +19884,14 @@ var fetchRuntimeDocumentWithFallback = async (args) => {
18054
19884
  fallback
18055
19885
  });
18056
19886
  }
18057
- const resolvedUrl = canonicalizeUrl(readFallbackString(fallback.output, "url") ?? args.url);
18058
- const html = readFallbackString(fallback.output, "html") ?? "";
18059
- const extracted = extractStructuredContent(html, resolvedUrl);
18060
- return {
18061
- url: resolvedUrl,
18062
- status: 200,
18063
- html,
18064
- text: extracted.text,
18065
- links: extracted.links,
18066
- browserFallback: toBrowserFallbackObservation(fallback)
18067
- };
19887
+ return toCompletedFallbackDocument({
19888
+ providerId: args.provider,
19889
+ source: args.source,
19890
+ operation: args.operation,
19891
+ url: args.url,
19892
+ fallback,
19893
+ ownerReview: args.ownerReview
19894
+ });
18068
19895
  }
18069
19896
  };
18070
19897
  var ProviderRuntime = class {
@@ -19220,7 +21047,8 @@ var withDefaultCommunityOptions = (options, browserFallbackPort) => {
19220
21047
  operation: "search",
19221
21048
  signal: context.signal,
19222
21049
  context,
19223
- browserFallbackPort
21050
+ browserFallbackPort,
21051
+ ownerReview: shouldOwnerReviewCommunityRedditSearchFallback
19224
21052
  });
19225
21053
  const { document: resolvedDocument, pageMessage } = await resolveDefaultFallbackDocumentIfNeeded({
19226
21054
  providerId,
@@ -19228,7 +21056,8 @@ var withDefaultCommunityOptions = (options, browserFallbackPort) => {
19228
21056
  operation: "search",
19229
21057
  document,
19230
21058
  context,
19231
- browserFallbackPort
21059
+ browserFallbackPort,
21060
+ ownerReview: shouldOwnerReviewCommunityRedditSearchFallback
19232
21061
  });
19233
21062
  const links = resolveCommunitySearchLinks(resolvedDocument, limit);
19234
21063
  if (shouldRejectBlockedCommunityFallback(resolvedDocument, links)) {
@@ -19340,6 +21169,12 @@ var withDefaultSocialPlatformOptions = (platform, options, browserFallbackPort)
19340
21169
  }
19341
21170
  );
19342
21171
  };
21172
+ const shouldOwnerReviewSocialFallback = (input) => input.source === "social" && input.operation === "search" && detectSocialSearchShell(platform, {
21173
+ url: input.url,
21174
+ title: typeof input.extracted.metadata.title === "string" ? input.extracted.metadata.title : void 0,
21175
+ content: toSnippet(stripUrls(input.extracted.text), 1600),
21176
+ links: input.extracted.links
21177
+ })?.browserRequired === true;
19343
21178
  const resolveFallbackDocumentIfNeeded = async (operation, document, context) => {
19344
21179
  let currentDocument = document;
19345
21180
  let described = describeDocumentIssue(operation, currentDocument);
@@ -19374,23 +21209,24 @@ var withDefaultSocialPlatformOptions = (platform, options, browserFallbackPort)
19374
21209
  });
19375
21210
  }
19376
21211
  const requestedUrl = currentDocument.url;
19377
- const resolvedUrl = canonicalizeUrl(readFallbackString(fallback.output, "url") ?? currentDocument.url);
19378
- const html = readFallbackString(fallback.output, "html") ?? "";
19379
- const extracted = extractStructuredContent(html, resolvedUrl);
21212
+ const fallbackDocument = toCompletedFallbackDocument({
21213
+ providerId,
21214
+ source: "social",
21215
+ operation,
21216
+ url: currentDocument.url,
21217
+ fallback,
21218
+ ownerReview: shouldOwnerReviewSocialFallback
21219
+ });
19380
21220
  const effectiveUrl = resolveRecoveredSocialSearchDocumentUrl({
19381
21221
  platform,
19382
21222
  operation,
19383
21223
  requestedUrl,
19384
- recoveredUrl: resolvedUrl,
19385
- recoveredLinks: extracted.links
21224
+ recoveredUrl: fallbackDocument.url,
21225
+ recoveredLinks: fallbackDocument.links
19386
21226
  });
19387
21227
  currentDocument = {
19388
- url: effectiveUrl,
19389
- status: 200,
19390
- html,
19391
- text: extracted.text,
19392
- links: extracted.links,
19393
- browserFallback: toBrowserFallbackObservation(fallback)
21228
+ ...fallbackDocument,
21229
+ url: effectiveUrl
19394
21230
  };
19395
21231
  described = describeDocumentIssue(operation, currentDocument);
19396
21232
  if (!described.issue || described.issue.reasonCode === "env_limited" && !described.issue.constraint) {
@@ -19414,7 +21250,9 @@ var withDefaultSocialPlatformOptions = (platform, options, browserFallbackPort)
19414
21250
  signal: context.signal,
19415
21251
  context,
19416
21252
  browserFallbackPort,
19417
- recoveryHints: extensionFirstRecoveryHints
21253
+ recoveryHints: extensionFirstRecoveryHints,
21254
+ recoverRuntimeErrors: EXTENSION_FIRST_SOCIAL_FALLBACK_PLATFORMS.has(platform),
21255
+ ownerReview: shouldOwnerReviewSocialFallback
19418
21256
  });
19419
21257
  const { document: resolvedDocument, extracted, pageMessage } = await resolveFallbackDocumentIfNeeded("search", document, context);
19420
21258
  const links = dedupeLinks2(
@@ -19447,7 +21285,9 @@ var withDefaultSocialPlatformOptions = (platform, options, browserFallbackPort)
19447
21285
  signal: context.signal,
19448
21286
  context,
19449
21287
  browserFallbackPort,
19450
- recoveryHints: extensionFirstRecoveryHints
21288
+ recoveryHints: extensionFirstRecoveryHints,
21289
+ recoverRuntimeErrors: EXTENSION_FIRST_SOCIAL_FALLBACK_PLATFORMS.has(platform),
21290
+ ownerReview: shouldOwnerReviewSocialFallback
19451
21291
  });
19452
21292
  const { document: resolvedDocument, extracted } = await resolveFallbackDocumentIfNeeded("fetch", document, context);
19453
21293
  const links = dedupeLinks2(resolvedDocument.links, resolvedDocument.url, 20);
@@ -19610,10 +21450,10 @@ export {
19610
21450
  enrichResearchRecords,
19611
21451
  INSPIREDESIGN_HANDOFF_COMMANDS,
19612
21452
  INSPIREDESIGN_HANDOFF_GUIDANCE,
21453
+ buildMacroResolveSuccessHandoff,
19613
21454
  renderResearch,
19614
21455
  renderShopping,
19615
21456
  renderInspiredesign,
19616
- buildMacroResolveSuccessHandoff,
19617
21457
  resolveInspiredesignCaptureMode,
19618
21458
  workflowTestUtils,
19619
21459
  runResearchWorkflow,
@@ -19625,4 +21465,4 @@ export {
19625
21465
  createProviderRuntime,
19626
21466
  createDefaultRuntime
19627
21467
  };
19628
- //# sourceMappingURL=chunk-AVQL6WAS.js.map
21468
+ //# sourceMappingURL=chunk-T3VVHJTK.js.map