opendevbrowser 0.0.18 → 0.0.20

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 (168) hide show
  1. package/README.md +36 -27
  2. package/dist/automation/coordinator.d.ts +61 -2
  3. package/dist/automation/coordinator.d.ts.map +1 -1
  4. package/dist/browser/browser-manager.d.ts +6 -1
  5. package/dist/browser/browser-manager.d.ts.map +1 -1
  6. package/dist/browser/canvas-manager.d.ts +4 -0
  7. package/dist/browser/canvas-manager.d.ts.map +1 -1
  8. package/dist/browser/manager-types.d.ts +6 -1
  9. package/dist/browser/manager-types.d.ts.map +1 -1
  10. package/dist/browser/ops-browser-manager.d.ts +6 -1
  11. package/dist/browser/ops-browser-manager.d.ts.map +1 -1
  12. package/dist/browser/screencast-recorder.d.ts.map +1 -1
  13. package/dist/browser/session-inspector.d.ts +39 -0
  14. package/dist/browser/session-inspector.d.ts.map +1 -1
  15. package/dist/canvas/document-store.d.ts +14 -5
  16. package/dist/canvas/document-store.d.ts.map +1 -1
  17. package/dist/canvas/starters/catalog.d.ts.map +1 -1
  18. package/dist/canvas/types.d.ts +120 -9
  19. package/dist/canvas/types.d.ts.map +1 -1
  20. package/dist/challenges/action-loop.d.ts +2 -1
  21. package/dist/challenges/action-loop.d.ts.map +1 -1
  22. package/dist/challenges/capture.d.ts +14 -0
  23. package/dist/challenges/capture.d.ts.map +1 -0
  24. package/dist/challenges/index.d.ts +3 -1
  25. package/dist/challenges/index.d.ts.map +1 -1
  26. package/dist/challenges/inspect-plan.d.ts +40 -0
  27. package/dist/challenges/inspect-plan.d.ts.map +1 -0
  28. package/dist/challenges/orchestrator.d.ts.map +1 -1
  29. package/dist/challenges/types.d.ts +34 -0
  30. package/dist/challenges/types.d.ts.map +1 -1
  31. package/dist/{chunk-YBQECXZX.js → chunk-3VA6XR25.js} +3 -3
  32. package/dist/chunk-3VA6XR25.js.map +1 -0
  33. package/dist/{chunk-5FZQJRBQ.js → chunk-C6QUKABT.js} +2789 -992
  34. package/dist/chunk-C6QUKABT.js.map +1 -0
  35. package/dist/{chunk-L57D35TB.js → chunk-LMNFPJRI.js} +4255 -2752
  36. package/dist/chunk-LMNFPJRI.js.map +1 -0
  37. package/dist/cli/commands/challenge-automation-mode.d.ts +3 -0
  38. package/dist/cli/commands/challenge-automation-mode.d.ts.map +1 -0
  39. package/dist/cli/commands/inspiredesign.d.ts +25 -0
  40. package/dist/cli/commands/inspiredesign.d.ts.map +1 -0
  41. package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
  42. package/dist/cli/commands/nav/review-desktop.d.ts +7 -0
  43. package/dist/cli/commands/nav/review-desktop.d.ts.map +1 -0
  44. package/dist/cli/commands/nav/review-shared.d.ts +10 -0
  45. package/dist/cli/commands/nav/review-shared.d.ts.map +1 -0
  46. package/dist/cli/commands/nav/review.d.ts.map +1 -1
  47. package/dist/cli/commands/serve.d.ts.map +1 -1
  48. package/dist/cli/commands/session/inspector-audit.d.ts +7 -0
  49. package/dist/cli/commands/session/inspector-audit.d.ts.map +1 -0
  50. package/dist/cli/commands/session/inspector-plan.d.ts +7 -0
  51. package/dist/cli/commands/session/inspector-plan.d.ts.map +1 -0
  52. package/dist/cli/commands/session/inspector-shared.d.ts +11 -0
  53. package/dist/cli/commands/session/inspector-shared.d.ts.map +1 -0
  54. package/dist/cli/commands/session/inspector.d.ts +1 -11
  55. package/dist/cli/commands/session/inspector.d.ts.map +1 -1
  56. package/dist/cli/commands/status-capabilities.d.ts +7 -0
  57. package/dist/cli/commands/status-capabilities.d.ts.map +1 -0
  58. package/dist/cli/daemon-client.d.ts.map +1 -1
  59. package/dist/cli/daemon-commands.d.ts.map +1 -1
  60. package/dist/cli/daemon-status.d.ts +5 -0
  61. package/dist/cli/daemon-status.d.ts.map +1 -1
  62. package/dist/cli/daemon.d.ts +5 -0
  63. package/dist/cli/daemon.d.ts.map +1 -1
  64. package/dist/cli/help.d.ts +2 -0
  65. package/dist/cli/help.d.ts.map +1 -1
  66. package/dist/cli/index.js +620 -242
  67. package/dist/cli/index.js.map +1 -1
  68. package/dist/cli/remote-manager.d.ts +6 -0
  69. package/dist/cli/remote-manager.d.ts.map +1 -1
  70. package/dist/cli/utils/parse.d.ts +1 -0
  71. package/dist/cli/utils/parse.d.ts.map +1 -1
  72. package/dist/cli/utils/skills.d.ts +1 -1
  73. package/dist/cli/utils/skills.d.ts.map +1 -1
  74. package/dist/cli/utils/workflow-message.d.ts +3 -0
  75. package/dist/cli/utils/workflow-message.d.ts.map +1 -1
  76. package/dist/config.d.ts +1 -0
  77. package/dist/config.d.ts.map +1 -1
  78. package/dist/core/bootstrap.d.ts.map +1 -1
  79. package/dist/core/runtime-assemblies.d.ts +2 -1
  80. package/dist/core/runtime-assemblies.d.ts.map +1 -1
  81. package/dist/core/types.d.ts +1 -1
  82. package/dist/core/types.d.ts.map +1 -1
  83. package/dist/desktop/runtime.d.ts +1 -0
  84. package/dist/desktop/runtime.d.ts.map +1 -1
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +728 -447
  87. package/dist/index.js.map +1 -1
  88. package/dist/opendevbrowser.d.ts.map +1 -1
  89. package/dist/opendevbrowser.js +728 -447
  90. package/dist/opendevbrowser.js.map +1 -1
  91. package/dist/providers/browser-fallback.d.ts.map +1 -1
  92. package/dist/providers/constraint.d.ts +11 -0
  93. package/dist/providers/constraint.d.ts.map +1 -1
  94. package/dist/providers/cookie-source.d.ts +8 -0
  95. package/dist/providers/cookie-source.d.ts.map +1 -0
  96. package/dist/providers/index.d.ts.map +1 -1
  97. package/dist/providers/inspiredesign-capture.d.ts +17 -0
  98. package/dist/providers/inspiredesign-capture.d.ts.map +1 -0
  99. package/dist/providers/inspiredesign-contract.d.ts +77 -0
  100. package/dist/providers/inspiredesign-contract.d.ts.map +1 -0
  101. package/dist/providers/renderer.d.ts +21 -0
  102. package/dist/providers/renderer.d.ts.map +1 -1
  103. package/dist/providers/runtime-bundle.d.ts +2 -1
  104. package/dist/providers/runtime-bundle.d.ts.map +1 -1
  105. package/dist/providers/runtime-factory.d.ts +4 -2
  106. package/dist/providers/runtime-factory.d.ts.map +1 -1
  107. package/dist/providers/shopping/index.d.ts +1 -1
  108. package/dist/providers/types.d.ts +3 -2
  109. package/dist/providers/types.d.ts.map +1 -1
  110. package/dist/providers/workflow-contracts.d.ts +1 -1
  111. package/dist/providers/workflow-contracts.d.ts.map +1 -1
  112. package/dist/providers/workflows.d.ts +21 -2
  113. package/dist/providers/workflows.d.ts.map +1 -1
  114. package/dist/{providers-G36AM3Z2.js → providers-3VBLTNAX.js} +6 -2
  115. package/dist/public-surface/generated-manifest.d.ts +143 -7
  116. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  117. package/dist/public-surface/source.d.ts +102 -3
  118. package/dist/public-surface/source.d.ts.map +1 -1
  119. package/dist/relay/protocol.d.ts +1 -1
  120. package/dist/relay/protocol.d.ts.map +1 -1
  121. package/dist/relay/relay-server.d.ts +1 -0
  122. package/dist/relay/relay-server.d.ts.map +1 -1
  123. package/dist/skills/skill-loader.js +1 -1
  124. package/dist/tools/automation-shared.d.ts +6 -0
  125. package/dist/tools/automation-shared.d.ts.map +1 -0
  126. package/dist/tools/index.d.ts.map +1 -1
  127. package/dist/tools/inspiredesign_run.d.ts +4 -0
  128. package/dist/tools/inspiredesign_run.d.ts.map +1 -0
  129. package/dist/tools/review_desktop.d.ts +4 -0
  130. package/dist/tools/review_desktop.d.ts.map +1 -0
  131. package/dist/tools/session_inspector.d.ts.map +1 -1
  132. package/dist/tools/session_inspector_audit.d.ts +4 -0
  133. package/dist/tools/session_inspector_audit.d.ts.map +1 -0
  134. package/dist/tools/session_inspector_plan.d.ts +4 -0
  135. package/dist/tools/session_inspector_plan.d.ts.map +1 -0
  136. package/dist/tools/status_capabilities.d.ts +4 -0
  137. package/dist/tools/status_capabilities.d.ts.map +1 -0
  138. package/extension/dist/background.js +70 -10
  139. package/extension/dist/canvas/canvas-runtime.js +14 -1
  140. package/extension/dist/ops/ops-runtime.js +18 -1
  141. package/extension/dist/popup.js +29 -16
  142. package/extension/dist/services/ConnectionManager.js +27 -2
  143. package/extension/manifest.json +1 -1
  144. package/extension/popup.html +11 -0
  145. package/package.json +5 -5
  146. package/skills/AGENTS.md +2 -2
  147. package/skills/opendevbrowser-best-practices/SKILL.md +50 -15
  148. package/skills/opendevbrowser-best-practices/artifacts/canvas-governance-playbook.md +31 -12
  149. package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +64 -15
  150. package/skills/opendevbrowser-best-practices/artifacts/provider-workflows.md +4 -0
  151. package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +11 -10
  152. package/skills/opendevbrowser-best-practices/assets/templates/canvas-blocker-checklist.json +28 -22
  153. package/skills/opendevbrowser-best-practices/assets/templates/canvas-generation-plan.v1.json +18 -17
  154. package/skills/opendevbrowser-best-practices/assets/templates/canvas-handshake-example.json +135 -17
  155. package/skills/opendevbrowser-best-practices/assets/templates/skill-runtime-pack-matrix.json +55 -8
  156. package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +18 -4
  157. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +16 -4
  158. package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +3 -1
  159. package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +68 -25
  160. package/skills/opendevbrowser-design-agent/SKILL.md +9 -4
  161. package/skills/opendevbrowser-design-agent/artifacts/design-workflows.md +15 -6
  162. package/skills/opendevbrowser-design-agent/assets/templates/canvas-generation-plan.design.v1.json +18 -17
  163. package/skills/opendevbrowser-design-agent/scripts/design-workflow.sh +11 -0
  164. package/skills/opendevbrowser-design-agent/scripts/validate-skill-assets.sh +57 -0
  165. package/dist/chunk-5FZQJRBQ.js.map +0 -1
  166. package/dist/chunk-L57D35TB.js.map +0 -1
  167. package/dist/chunk-YBQECXZX.js.map +0 -1
  168. /package/dist/{providers-G36AM3Z2.js.map → providers-3VBLTNAX.js.map} +0 -0
@@ -2,6 +2,7 @@ import {
2
2
  ProviderRuntimeError,
3
3
  createProviderError,
4
4
  isProviderReasonCode,
5
+ isProviderRuntimeError,
5
6
  normalizeProviderReasonCode,
6
7
  providerErrorCodeFromReasonCode,
7
8
  toProviderError
@@ -796,6 +797,12 @@ var applyProviderIssueHint = (details, hint) => {
796
797
  if (hint.constraint && !isProviderConstraint(next.constraint)) {
797
798
  next.constraint = hint.constraint;
798
799
  }
800
+ if (typeof next.guidance === "undefined") {
801
+ const guidance = buildProviderIssueGuidance({ hint, details: next });
802
+ if (guidance) {
803
+ next.guidance = guidance;
804
+ }
805
+ }
799
806
  return next;
800
807
  };
801
808
  var providerLabel = (provider) => {
@@ -805,6 +812,77 @@ var providerLabel = (provider) => {
805
812
  const tail = separator >= 0 ? normalized.slice(separator + 1) : normalized;
806
813
  return tail.charAt(0).toUpperCase() + tail.slice(1);
807
814
  };
815
+ var hasPreservedBrowserState = (details) => {
816
+ return typeof details?.preservedSessionId === "string" || typeof details?.preservedTargetId === "string";
817
+ };
818
+ var buildGuidance = (reason, recommendedNextCommands) => ({
819
+ reason,
820
+ recommendedNextCommands
821
+ });
822
+ var buildAuthGuidance = (subject, preservedBrowserState) => {
823
+ return preservedBrowserState ? buildGuidance(
824
+ `${subject} preserved browser state that can finish authentication.`,
825
+ [
826
+ "Complete the login or account checkpoint in the preserved browser session.",
827
+ "Rerun the same provider or workflow after the session is fully authenticated."
828
+ ]
829
+ ) : buildGuidance(
830
+ `${subject} needs an authenticated session before retrying.`,
831
+ [
832
+ "Reuse an authenticated browser session, import logged-in cookies, or use the provider sign-in flow.",
833
+ "Rerun the same provider or workflow once the session is active."
834
+ ]
835
+ );
836
+ };
837
+ var buildChallengeGuidance = (subject, preservedBrowserState) => {
838
+ return preservedBrowserState ? buildGuidance(
839
+ `${subject} preserved browser state that can complete the current challenge.`,
840
+ [
841
+ "Finish the login or anti-bot challenge in the preserved browser session.",
842
+ "Rerun the same provider or workflow after the page unlocks."
843
+ ]
844
+ ) : buildGuidance(
845
+ `${subject} hit a challenge that still needs browser-assisted follow-up.`,
846
+ [
847
+ "Retry with browser assistance so the challenge can be completed interactively.",
848
+ "Only ask for manual credentials if browser-assisted recovery still cannot unlock the page."
849
+ ]
850
+ );
851
+ };
852
+ var buildRenderGuidance = (subject, preservedBrowserState) => {
853
+ return preservedBrowserState ? buildGuidance(
854
+ `${subject} still needs a live browser-rendered page, but browser state is already preserved.`,
855
+ [
856
+ "Inspect the preserved browser session until usable content is visible.",
857
+ "Rerun the same provider or workflow after the rendered page is ready."
858
+ ]
859
+ ) : buildGuidance(
860
+ `${subject} needs a live browser-rendered page before retrying.`,
861
+ [
862
+ "Retry with browser assistance or a headed browser session.",
863
+ "Rerun the same provider or workflow after the rendered page is ready."
864
+ ]
865
+ );
866
+ };
867
+ var buildProviderIssueGuidance = (args) => {
868
+ const subject = providerLabel(args.provider);
869
+ const preservedBrowserState = hasPreservedBrowserState(args.details);
870
+ const disposition = toNonEmptyString(args.details?.disposition);
871
+ if (disposition === "completed") return void 0;
872
+ if (disposition === "challenge_preserved") {
873
+ return buildChallengeGuidance(subject, true);
874
+ }
875
+ if (args.hint.reasonCode === "token_required" || args.hint.reasonCode === "auth_required") {
876
+ return buildAuthGuidance(subject, preservedBrowserState);
877
+ }
878
+ if (args.hint.reasonCode === "challenge_detected") {
879
+ return buildChallengeGuidance(subject, preservedBrowserState);
880
+ }
881
+ if (args.hint.constraint?.kind === "render_required" || args.hint.reasonCode === "env_limited") {
882
+ return buildRenderGuidance(subject, preservedBrowserState);
883
+ }
884
+ return void 0;
885
+ };
808
886
  var summaryPriority = (hint) => {
809
887
  if (hint.reasonCode === "token_required" || hint.reasonCode === "auth_required") return 3;
810
888
  if (hint.reasonCode === "challenge_detected") return 2;
@@ -836,10 +914,16 @@ var summarizePrimaryProviderIssue = (failures) => {
836
914
  });
837
915
  if (!hint) continue;
838
916
  const summary = summarizeProviderIssue({ provider: failure.provider, hint });
917
+ const guidance = buildProviderIssueGuidance({
918
+ provider: failure.provider,
919
+ hint,
920
+ details: failure.error?.details
921
+ });
839
922
  const candidate = {
840
923
  provider: failure.provider,
841
924
  summary,
842
- ...hint
925
+ ...hint,
926
+ ...guidance ? { guidance } : {}
843
927
  };
844
928
  if (!best || summaryPriority(candidate) > summaryPriority(best)) {
845
929
  best = candidate;
@@ -1983,6 +2067,138 @@ var verifyChallengeProgress = async (args) => {
1983
2067
  };
1984
2068
  };
1985
2069
 
2070
+ // src/challenges/capability-matrix.ts
2071
+ var buildCapabilityMatrix = (bundle, interpretation, gate) => {
2072
+ const hasActionables = bundle.actionables.length > 0;
2073
+ const helperActionRefs = [
2074
+ ...bundle.continuity.loginRefs,
2075
+ ...bundle.continuity.sessionReuseRefs,
2076
+ ...bundle.continuity.humanVerificationRefs,
2077
+ ...bundle.continuity.checkpointRefs,
2078
+ ...bundle.interaction?.clickRefs ?? [],
2079
+ ...bundle.interaction?.holdRefs ?? [],
2080
+ ...bundle.interaction?.dragRefs ?? []
2081
+ ];
2082
+ const authLaneRelevant = interpretation.classification === "auth_required" || interpretation.classification === "existing_session_reuse" || bundle.continuity.likelyLoginPage || bundle.continuity.likelySessionPicker;
2083
+ const canNavigateToAuth = gate.allowedActions.includes("auth_navigation") && authLaneRelevant && (bundle.continuity.loginRefs.length > 0 || typeof bundle.url === "string");
2084
+ const canReuseExistingSession = gate.allowedActions.includes("session_reuse") && (bundle.continuity.hasPreservedSession || bundle.continuity.attachedSession || bundle.continuity.sessionReuseRefs.length > 0);
2085
+ const canReuseCookies = gate.allowedActions.includes("cookie_reuse") && authLaneRelevant && (bundle.continuity.canReuseExistingCookies || bundle.continuity.canImportCookies);
2086
+ const canFillNonSecretFields = gate.allowedActions.includes("non_secret_form_fill") && bundle.continuity.hasNonSecretTaskData && bundle.continuity.nonSecretFieldRefs.length > 0;
2087
+ const canExploreClicks = gate.allowedActions.includes("click_path") && (hasActionables || bundle.continuity.loginRefs.length > 0 || bundle.continuity.sessionReuseRefs.length > 0 || bundle.continuity.checkpointRefs.length > 0);
2088
+ const mustYield = interpretation.humanBoundary === "secret_entry" || interpretation.humanBoundary === "mfa" || interpretation.humanBoundary === "explicit_consent" || interpretation.humanBoundary === "exhausted_no_progress";
2089
+ const mustDefer = interpretation.humanBoundary === "policy_blocked" || !bundle.blocker && bundle.blockerState === "clear";
2090
+ let helperEligibility = gate.helperEligibility ?? (gate.optionalComputerUseBridge ? {
2091
+ allowed: true,
2092
+ reason: "Optional helper bridge remains eligible after policy resolution."
2093
+ } : {
2094
+ allowed: false,
2095
+ reason: "Optional computer-use bridge is disabled by policy.",
2096
+ standDownReason: "helper_disabled_by_policy"
2097
+ });
2098
+ if (helperEligibility.allowed && interpretation.humanBoundary !== "none") {
2099
+ helperEligibility = {
2100
+ allowed: false,
2101
+ reason: `Helper bridge is blocked by human boundary: ${interpretation.humanBoundary}.`,
2102
+ standDownReason: "helper_blocked_by_human_boundary"
2103
+ };
2104
+ } else if (helperEligibility.allowed && helperActionRefs.length === 0) {
2105
+ helperEligibility = {
2106
+ allowed: false,
2107
+ reason: "Canonical evidence did not expose any safe browser-scoped helper actions.",
2108
+ standDownReason: "helper_no_safe_actions"
2109
+ };
2110
+ }
2111
+ return {
2112
+ canNavigateToAuth,
2113
+ canReuseExistingSession,
2114
+ canReuseCookies,
2115
+ canFillNonSecretFields,
2116
+ canExploreClicks,
2117
+ canUseOwnedEnvironmentFixture: interpretation.classification === "owned_environment_test_challenge" && gate.governedLanes.includes("owned_environment_fixture"),
2118
+ canUseSanctionedIdentity: gate.governedLanes.includes("sanctioned_identity"),
2119
+ canUseServiceAdapter: gate.governedLanes.includes("service_adapter"),
2120
+ canUseComputerUseBridge: helperEligibility.allowed,
2121
+ helperEligibility,
2122
+ mustYield,
2123
+ mustDefer
2124
+ };
2125
+ };
2126
+
2127
+ // src/challenges/capture.ts
2128
+ async function captureChallengeEvidence(args) {
2129
+ const status = await args.handle.status(args.sessionId);
2130
+ const effectiveTargetId = args.targetId ?? status.activeTargetId ?? null;
2131
+ const snapshot = await args.handle.snapshot(
2132
+ args.sessionId,
2133
+ "actionables",
2134
+ 2400,
2135
+ void 0,
2136
+ effectiveTargetId
2137
+ );
2138
+ const debugTrace = await args.handle.debugTraceSnapshot(args.sessionId, { max: 50 });
2139
+ const cookies = status.url ? await args.handle.cookieList(args.sessionId, [status.url]) : { count: 0 };
2140
+ return buildChallengeEvidenceBundle({
2141
+ status,
2142
+ snapshot: {
2143
+ snapshotId: snapshot.snapshotId,
2144
+ content: snapshot.content,
2145
+ warnings: snapshot.warnings
2146
+ },
2147
+ debugTrace,
2148
+ cookieCount: cookies.count,
2149
+ canImportCookies: args.canImportCookies,
2150
+ fallbackDisposition: args.fallbackDisposition,
2151
+ registryPressure: args.registryPressure,
2152
+ taskData: args.taskData
2153
+ });
2154
+ }
2155
+
2156
+ // src/challenges/human-yield-gate.ts
2157
+ var shouldYieldToHuman = (args) => {
2158
+ if (args.noProgressExhausted) {
2159
+ return {
2160
+ yield: true,
2161
+ reason: "exhausted_no_progress"
2162
+ };
2163
+ }
2164
+ return {
2165
+ yield: args.interpretation.humanBoundary !== "none",
2166
+ reason: args.interpretation.humanBoundary
2167
+ };
2168
+ };
2169
+ var buildHumanYieldPacket = (args) => {
2170
+ const challengeId = args.bundle.challengeId ?? `challenge-${Date.now()}`;
2171
+ const targetHints = [
2172
+ ...args.bundle.continuity.loginRefs,
2173
+ ...args.bundle.continuity.sessionReuseRefs,
2174
+ ...args.bundle.continuity.humanVerificationRefs,
2175
+ ...args.bundle.continuity.checkpointRefs
2176
+ ];
2177
+ return {
2178
+ challengeId,
2179
+ classification: args.interpretation.classification,
2180
+ reason: args.reason,
2181
+ sessionId: args.sessionId,
2182
+ targetId: args.targetId ?? args.bundle.activeTargetId,
2183
+ ownerSurface: args.bundle.challenge?.ownerSurface ?? args.bundle.ownerSurface,
2184
+ url: args.bundle.url,
2185
+ title: args.bundle.title,
2186
+ requiredHumanStep: args.reason === "mfa" ? "Complete MFA or passkey verification, then continue." : args.reason === "secret_entry" ? "Enter the required secret-bearing credentials, then continue." : args.reason === "unsupported_third_party" ? "Complete the unsupported third-party challenge manually, then continue." : "Review the page state and continue when ready.",
2187
+ targetHints,
2188
+ expectedPostAuthCheckpoint: args.interpretation.likelyCheckpoint,
2189
+ preserveUntil: args.bundle.challenge?.preserveUntil,
2190
+ verifyUntil: args.bundle.challenge?.verifyUntil,
2191
+ traceRequestId: args.bundle.diagnostics.traceRequestId,
2192
+ ...args.verification ? {
2193
+ lastVerificationStatus: args.verification.status,
2194
+ lastVerificationReason: args.verification.reason
2195
+ } : {},
2196
+ evidenceSummary: args.interpretation.summary,
2197
+ reclaimHint: "Resume the preserved session and re-run verification after the human step completes.",
2198
+ resumeRule: "Re-run manager-owned verification after the human step completes before resuming automation."
2199
+ };
2200
+ };
2201
+
1986
2202
  // src/challenges/optional-computer-use-bridge.ts
1987
2203
  var OPTIONAL_BRIDGE_SUGGESTION_REASON = "Optional bridge suggested a browser-scoped click follow-up from canonical evidence.";
1988
2204
  var buildComputerUseSuggestions = (bundle, maxSuggestions) => {
@@ -2027,907 +2243,955 @@ var suggestComputerUseActions = (args) => {
2027
2243
  };
2028
2244
  };
2029
2245
 
2030
- // src/challenges/action-loop.ts
2031
- var SENSITIVE_FIELD_RE = /\b(password|passcode|secret|otp|mfa|token|verification code|passkey)\b/i;
2032
- var DEFAULT_HOLD_MS2 = 1500;
2033
- var hasExecuted = (steps, kind, ref, url) => {
2034
- return steps.some((step) => step.kind === kind && step.ref === ref && step.url === url);
2035
- };
2036
- var getActionable = (bundle, ref) => {
2037
- return bundle.actionables.find((entry) => entry.ref === ref);
2038
- };
2039
- var deriveAuthUrls = (url) => {
2040
- if (!url) return [];
2041
- try {
2042
- const current = new URL(url);
2043
- const candidates = ["/login", "/signin", "/sign-in", "/account/login", "/session", "/auth/login"];
2044
- return candidates.map((path2) => new URL(path2, current.origin).toString());
2045
- } catch {
2046
- return [];
2246
+ // src/challenges/policy-gate.ts
2247
+ var ALL_ACTIONS = [
2248
+ "wait",
2249
+ "auth_navigation",
2250
+ "session_reuse",
2251
+ "cookie_reuse",
2252
+ "element_discovery",
2253
+ "click_path",
2254
+ "click_and_hold",
2255
+ "non_secret_form_fill",
2256
+ "dropdown",
2257
+ "scroll",
2258
+ "hover",
2259
+ "press",
2260
+ "pointer",
2261
+ "drag",
2262
+ "verification",
2263
+ "debug_trace"
2264
+ ];
2265
+ var DEFAULT_HANDOFF_TRIGGERS = [
2266
+ "secret_entry",
2267
+ "mfa",
2268
+ "explicit_consent",
2269
+ "policy_blocked",
2270
+ "unsupported_third_party",
2271
+ "exhausted_no_progress"
2272
+ ];
2273
+ var buildResolvedPolicy = (mode, source) => {
2274
+ if (mode === "off") {
2275
+ return {
2276
+ mode,
2277
+ source,
2278
+ standDownReason: "challenge_automation_off"
2279
+ };
2047
2280
  }
2048
- };
2049
- var resolveTaskValue = (bundle, ref) => {
2050
- const actionable = getActionable(bundle, ref);
2051
- const name = actionable?.name?.toLowerCase();
2052
- if (!name || !bundle.taskData) return void 0;
2053
- const entries = Object.entries(bundle.taskData);
2054
- for (const [key, value] of entries) {
2055
- if (SENSITIVE_FIELD_RE.test(key) || SENSITIVE_FIELD_RE.test(name)) {
2056
- continue;
2057
- }
2058
- if (!name.includes(key.toLowerCase())) {
2059
- continue;
2060
- }
2061
- switch (typeof value) {
2062
- case "string":
2063
- case "number":
2064
- case "boolean":
2065
- return String(value);
2066
- default:
2067
- break;
2068
- }
2281
+ if (mode === "browser") {
2282
+ return {
2283
+ mode,
2284
+ source,
2285
+ standDownReason: "helper_disabled_for_browser_mode"
2286
+ };
2069
2287
  }
2070
- return void 0;
2071
- };
2072
- var nextUnusedRef = (refs, steps, kind) => {
2073
- return refs.find((ref) => !hasExecuted(steps, kind, ref));
2288
+ return { mode, source };
2074
2289
  };
2075
- var planInteractionStep = (bundle, decision, executedSteps) => {
2076
- const interaction = bundle.interaction;
2077
- if (!interaction || interaction.preferredAction === "unknown") {
2078
- return void 0;
2079
- }
2080
- if (interaction.preferredAction === "click" && decision.allowedActionFamilies.includes("click_path")) {
2081
- const clickRef = nextUnusedRef(interaction.clickRefs, executedSteps, "click");
2082
- if (clickRef) {
2083
- return {
2084
- kind: "click",
2085
- ref: clickRef,
2086
- reason: "Visible popup or interstitial exposes a bounded click path."
2087
- };
2088
- }
2290
+ var resolveChallengeAutomationPolicy = (args) => {
2291
+ if (args.runMode) {
2292
+ return buildResolvedPolicy(args.runMode, "run");
2089
2293
  }
2090
- if (interaction.preferredAction === "click_and_hold" && decision.allowedActionFamilies.includes("click_and_hold")) {
2091
- const holdRef = nextUnusedRef(interaction.holdRefs, executedSteps, "click_and_hold");
2092
- if (holdRef || !hasExecuted(executedSteps, "click_and_hold")) {
2093
- return {
2094
- kind: "click_and_hold",
2095
- ...holdRef ? { ref: holdRef } : {},
2096
- ...typeof interaction.holdMs === "number" ? { holdMs: interaction.holdMs } : {},
2097
- reason: "Visible challenge requests a bounded click-and-hold gesture."
2098
- };
2099
- }
2294
+ if (args.sessionMode) {
2295
+ return buildResolvedPolicy(args.sessionMode, "session");
2100
2296
  }
2101
- if (interaction.preferredAction === "drag" && decision.allowedActionFamilies.includes("drag") && !hasExecuted(executedSteps, "drag")) {
2102
- return {
2103
- kind: "drag",
2104
- ...interaction.dragRefs[0] ? { ref: interaction.dragRefs[0] } : {},
2105
- coordinates: { x: 640, y: 360 },
2106
- reason: "Visible challenge requests a bounded drag gesture."
2107
- };
2108
- }
2109
- return void 0;
2297
+ return buildResolvedPolicy(args.configMode, "config");
2110
2298
  };
2111
- var planGenericStep = (bundle, decision, executedSteps) => {
2112
- const sessionRef = nextUnusedRef(bundle.continuity.sessionReuseRefs, executedSteps, "click");
2113
- if (sessionRef) {
2299
+ var resolveHelperEligibility = (config, policy) => {
2300
+ if (policy.mode === "off") {
2114
2301
  return {
2115
- kind: "click",
2116
- ref: sessionRef,
2117
- reason: "Try the existing-session or account-selection path first."
2302
+ allowed: false,
2303
+ reason: "Challenge automation mode is off; detection and reporting remain active.",
2304
+ standDownReason: "challenge_automation_off"
2118
2305
  };
2119
2306
  }
2120
- const loginRef = nextUnusedRef(bundle.continuity.loginRefs, executedSteps, "click");
2121
- if (decision.allowedActionFamilies.includes("auth_navigation") && loginRef) {
2307
+ if (policy.mode === "browser") {
2122
2308
  return {
2123
- kind: "click",
2124
- ref: loginRef,
2125
- reason: "Try the visible auth-navigation entrypoint."
2309
+ allowed: false,
2310
+ reason: "Browser mode keeps the optional helper bridge disabled.",
2311
+ standDownReason: "helper_disabled_for_browser_mode"
2126
2312
  };
2127
2313
  }
2128
- if (decision.allowedActionFamilies.includes("auth_navigation")) {
2129
- const loginUrl = deriveAuthUrls(bundle.url).find((candidate) => !hasExecuted(executedSteps, "goto", void 0, candidate));
2130
- if (loginUrl) {
2131
- return {
2132
- kind: "goto",
2133
- url: loginUrl,
2134
- reason: "Try a conventional auth-navigation URL on the current origin."
2135
- };
2136
- }
2137
- }
2138
- const fieldRef = nextUnusedRef(bundle.continuity.nonSecretFieldRefs, executedSteps, "type");
2139
- const fieldValue = fieldRef ? resolveTaskValue(bundle, fieldRef) : void 0;
2140
- if (decision.allowedActionFamilies.includes("non_secret_form_fill") && fieldRef && fieldValue) {
2314
+ if (!config.optionalComputerUseBridge.enabled) {
2141
2315
  return {
2142
- kind: "type",
2143
- ref: fieldRef,
2144
- text: fieldValue,
2145
- reason: "Fill a non-secret field from caller-provided task data."
2316
+ allowed: false,
2317
+ reason: "Optional computer-use bridge is disabled by policy.",
2318
+ standDownReason: "helper_disabled_by_policy"
2146
2319
  };
2147
2320
  }
2148
- const checkpointRef = nextUnusedRef(bundle.continuity.checkpointRefs, executedSteps, "click");
2149
- if (decision.allowedActionFamilies.includes("click_path") && checkpointRef) {
2321
+ return {
2322
+ allowed: true,
2323
+ reason: "Optional helper bridge remains eligible after mode resolution."
2324
+ };
2325
+ };
2326
+ var buildChallengePolicyGate = (config, interpretation, resolvedPolicy = resolveChallengeAutomationPolicy({
2327
+ configMode: config.mode
2328
+ })) => {
2329
+ const helperEligibility = resolveHelperEligibility(config, resolvedPolicy);
2330
+ if (resolvedPolicy.mode === "off") {
2150
2331
  return {
2151
- kind: "click",
2152
- ref: checkpointRef,
2153
- reason: "Try the next visible checkpoint or continue action."
2332
+ resolvedPolicy,
2333
+ allowedActions: [],
2334
+ forbiddenActions: [...ALL_ACTIONS],
2335
+ handoffTriggers: [...DEFAULT_HANDOFF_TRIGGERS],
2336
+ governedLanes: [],
2337
+ optionalComputerUseBridge: false,
2338
+ helperEligibility
2154
2339
  };
2155
2340
  }
2156
- const hoverRef = nextUnusedRef([...bundle.continuity.loginRefs, ...bundle.continuity.checkpointRefs], executedSteps, "hover");
2157
- if (decision.allowedActionFamilies.includes("hover") && hoverRef) {
2158
- return {
2159
- kind: "hover",
2160
- ref: hoverRef,
2161
- reason: "Hover a likely action target to reveal hidden menus or session pickers."
2162
- };
2341
+ const allowed = /* @__PURE__ */ new Set(["wait", "verification", "debug_trace"]);
2342
+ if (config.allowAuthNavigation) {
2343
+ allowed.add("auth_navigation");
2163
2344
  }
2164
- if (decision.allowedActionFamilies.includes("scroll") && !hasExecuted(executedSteps, "scroll")) {
2165
- return {
2166
- kind: "scroll",
2167
- dy: 900,
2168
- reason: "Scroll down to uncover the next actionable region."
2169
- };
2345
+ if (config.allowSessionReuse) {
2346
+ allowed.add("session_reuse");
2170
2347
  }
2171
- if (decision.allowedActionFamilies.includes("scroll") && executedSteps.filter((step) => step.kind === "scroll").length === 1) {
2172
- return {
2173
- kind: "scroll",
2174
- dy: -450,
2175
- reason: "Scroll back up to re-evaluate the visible challenge state."
2176
- };
2348
+ if (config.allowCookieReuse) {
2349
+ allowed.add("cookie_reuse");
2177
2350
  }
2178
- if (decision.allowedActionFamilies.includes("press") && !hasExecuted(executedSteps, "press")) {
2179
- return {
2180
- kind: "press",
2181
- text: "Tab",
2182
- reason: "Advance focus through the challenge surface."
2183
- };
2351
+ if (config.allowNonSecretFormFill) {
2352
+ allowed.add("non_secret_form_fill");
2353
+ allowed.add("dropdown");
2184
2354
  }
2185
- if (decision.allowedActionFamilies.includes("pointer") && !hasExecuted(executedSteps, "pointer")) {
2186
- return {
2187
- kind: "pointer",
2188
- coordinates: { x: 640, y: 360 },
2189
- reason: "Move the pointer through the center of the current browser surface."
2190
- };
2355
+ if (config.allowInteractionExploration) {
2356
+ allowed.add("element_discovery");
2357
+ allowed.add("click_path");
2358
+ allowed.add("click_and_hold");
2359
+ allowed.add("scroll");
2360
+ allowed.add("hover");
2361
+ allowed.add("press");
2362
+ allowed.add("pointer");
2363
+ allowed.add("drag");
2191
2364
  }
2192
- if (decision.allowedActionFamilies.includes("drag") && !hasExecuted(executedSteps, "drag")) {
2193
- return {
2194
- kind: "drag",
2195
- coordinates: { x: 640, y: 360 },
2196
- reason: "Attempt one bounded vertical drag across the visible surface."
2197
- };
2365
+ if (interpretation.humanBoundary === "secret_entry" || interpretation.humanBoundary === "mfa") {
2366
+ allowed.delete("non_secret_form_fill");
2198
2367
  }
2199
- if (!hasExecuted(executedSteps, "wait")) {
2200
- return {
2201
- kind: "wait",
2202
- reason: "Give the page a short bounded settle window before yielding."
2203
- };
2368
+ const governedLanes = [];
2369
+ if (config.governed.allowOwnedEnvironmentFixtures) {
2370
+ governedLanes.push("owned_environment_fixture");
2204
2371
  }
2205
- return void 0;
2206
- };
2207
- var resolveStepPoint = async (args) => {
2208
- if (!args.step.ref) {
2209
- return args.step.coordinates ?? args.fallback;
2372
+ if (config.governed.allowSanctionedIdentity) {
2373
+ governedLanes.push("sanctioned_identity");
2210
2374
  }
2211
- return await args.handle.resolveRefPoint(args.sessionId, args.step.ref, args.targetId);
2212
- };
2213
- var executeStep = async (args) => {
2214
- const timeoutMs = args.config.stepTimeoutMs;
2215
- switch (args.step.kind) {
2216
- case "goto":
2217
- if (args.step.url) {
2218
- await args.handle.goto(args.sessionId, args.step.url, "domcontentloaded", timeoutMs, void 0, args.targetId);
2219
- }
2220
- return;
2221
- case "click":
2222
- if (args.step.ref) {
2223
- await args.handle.click(args.sessionId, args.step.ref, args.targetId);
2224
- }
2225
- return;
2226
- case "click_and_hold": {
2227
- const point = await resolveStepPoint({
2228
- handle: args.handle,
2229
- sessionId: args.sessionId,
2230
- step: args.step,
2231
- targetId: args.targetId,
2232
- fallback: { x: 640, y: 360 }
2233
- });
2234
- await args.handle.pointerMove(args.sessionId, point.x, point.y, args.targetId, 12);
2235
- await args.handle.pointerDown(args.sessionId, point.x, point.y, args.targetId, "left", 1);
2236
- await new Promise((resolve2) => setTimeout(resolve2, Math.max(250, args.step.holdMs ?? DEFAULT_HOLD_MS2)));
2237
- await args.handle.pointerUp(args.sessionId, point.x, point.y, args.targetId, "left", 1);
2238
- return;
2239
- }
2240
- case "hover":
2241
- if (args.step.ref) {
2242
- await args.handle.hover(args.sessionId, args.step.ref, args.targetId);
2243
- }
2244
- return;
2245
- case "press":
2246
- await args.handle.press(args.sessionId, args.step.text ?? "Tab", void 0, args.targetId);
2247
- return;
2248
- case "type":
2249
- if (args.step.ref && typeof args.step.text === "string") {
2250
- await args.handle.type(args.sessionId, args.step.ref, args.step.text, true, false, args.targetId);
2251
- }
2252
- return;
2253
- case "select":
2254
- if (args.step.ref && args.step.values?.length) {
2255
- await args.handle.select(args.sessionId, args.step.ref, args.step.values, args.targetId);
2256
- }
2257
- return;
2258
- case "scroll":
2259
- await args.handle.scroll(args.sessionId, args.step.dy ?? 600, void 0, args.targetId);
2260
- return;
2261
- case "pointer":
2262
- await args.handle.pointerMove(
2263
- args.sessionId,
2264
- args.step.coordinates?.x ?? 640,
2265
- args.step.coordinates?.y ?? 360,
2266
- args.targetId,
2267
- 12
2268
- );
2269
- return;
2270
- case "drag":
2271
- {
2272
- const point = await resolveStepPoint({
2273
- handle: args.handle,
2274
- sessionId: args.sessionId,
2275
- step: args.step,
2276
- targetId: args.targetId,
2277
- fallback: args.step.coordinates ?? { x: 640, y: 360 }
2278
- });
2279
- await args.handle.drag(
2280
- args.sessionId,
2281
- point,
2282
- {
2283
- x: point.x,
2284
- y: point.y + 260
2285
- },
2286
- args.targetId,
2287
- 16
2288
- );
2289
- }
2290
- return;
2291
- case "cookie_list":
2292
- await args.handle.cookieList(args.sessionId, args.step.url ? [args.step.url] : void 0);
2293
- return;
2294
- case "cookie_import":
2295
- await args.handle.cookieImport(args.sessionId, args.step.cookies ?? [], true);
2296
- return;
2297
- case "snapshot":
2298
- await args.handle.snapshot(
2299
- args.sessionId,
2300
- "actionables",
2301
- args.step.snapshotChars ?? 2400,
2302
- void 0,
2303
- args.targetId
2304
- );
2305
- return;
2306
- case "debug_trace":
2307
- await args.handle.debugTraceSnapshot(args.sessionId, { max: args.step.traceMax ?? 50 });
2308
- return;
2309
- case "wait":
2310
- await args.handle.waitForLoad(args.sessionId, "networkidle", Math.min(timeoutMs, 3e3), args.targetId);
2311
- return;
2312
- default:
2313
- return;
2375
+ if (config.governed.allowServiceAdapters) {
2376
+ governedLanes.push("service_adapter");
2314
2377
  }
2378
+ return {
2379
+ resolvedPolicy,
2380
+ allowedActions: ALL_ACTIONS.filter((action) => allowed.has(action)),
2381
+ forbiddenActions: ALL_ACTIONS.filter((action) => !allowed.has(action)),
2382
+ handoffTriggers: [...DEFAULT_HANDOFF_TRIGGERS],
2383
+ governedLanes,
2384
+ optionalComputerUseBridge: helperEligibility.allowed,
2385
+ helperEligibility
2386
+ };
2315
2387
  };
2316
- var runChallengeActionLoop = async (args) => {
2317
- let currentBundle = args.initialBundle;
2318
- let currentTargetId = args.targetId ?? args.initialBundle.activeTargetId ?? null;
2319
- const executedSteps = [];
2320
- let noProgressCount = 0;
2321
- let reusedExistingSession = false;
2322
- let reusedCookies = false;
2323
- for (let attempt = 1; attempt <= args.decision.attemptBudget; attempt += 1) {
2324
- const suggestedStep = args.suggestedSteps?.find((candidate) => !hasExecuted(executedSteps, candidate.kind, candidate.ref, candidate.url));
2325
- const helperSuggestedStep = args.config.optionalComputerUseBridge.enabled ? buildComputerUseSuggestions(
2326
- currentBundle,
2327
- args.config.optionalComputerUseBridge.maxSuggestions
2328
- ).find((candidate) => !hasExecuted(executedSteps, candidate.kind, candidate.ref, candidate.url)) : void 0;
2329
- const interactionStep = planInteractionStep(currentBundle, args.decision, executedSteps);
2330
- const step = args.decision.lane === "optional_computer_use_bridge" ? suggestedStep ?? helperSuggestedStep : suggestedStep ?? interactionStep ?? planGenericStep(currentBundle, args.decision, executedSteps) ?? helperSuggestedStep;
2331
- if (!step) {
2332
- return {
2333
- status: "no_progress",
2334
- attempts: attempt - 1,
2335
- noProgressCount,
2336
- executedSteps,
2337
- verification: {
2338
- status: "still_blocked",
2339
- blockerState: currentBundle.blockerState,
2340
- blocker: currentBundle.blocker,
2341
- challenge: currentBundle.challenge,
2342
- bundle: currentBundle,
2343
- changed: false,
2344
- reason: "No additional safe browser action remained.",
2345
- url: currentBundle.url,
2346
- title: currentBundle.title
2347
- },
2348
- reusedExistingSession,
2349
- reusedCookies
2350
- };
2351
- }
2352
- try {
2353
- await executeStep({
2354
- handle: args.handle,
2355
- sessionId: args.sessionId,
2356
- targetId: currentTargetId,
2357
- step,
2358
- config: args.config
2359
- });
2360
- } catch {
2388
+
2389
+ // src/challenges/strategy-selector.ts
2390
+ var buildDecision = (config, lane, rationale, allowedActionFamilies, verificationLevel, stopConditions, governedLane) => ({
2391
+ lane,
2392
+ ...governedLane ? { governedLane } : {},
2393
+ rationale,
2394
+ attemptBudget: config.attemptBudget,
2395
+ noProgressLimit: config.noProgressLimit,
2396
+ verificationLevel,
2397
+ stopConditions,
2398
+ allowedActionFamilies: [...allowedActionFamilies]
2399
+ });
2400
+ var selectChallengeStrategy = (args) => {
2401
+ const { config, bundle, capabilityMatrix, gate, interpretation } = args;
2402
+ const registryCooldownActive = (bundle.registryPressure?.cooldownUntilMs ?? 0) > Date.now();
2403
+ const registryPressureElevated = (bundle.registryPressure?.activeChallenges ?? 0) > 0 || (bundle.registryPressure?.recentChallengeRatio ?? 0) >= 0.5 || (bundle.registryPressure?.recentRateLimitRatio ?? 0) >= 0.5;
2404
+ const stopConditions = [
2405
+ "manager_verification_clears_blocker",
2406
+ "policy_gate_denies_next_action",
2407
+ "human_boundary_detected",
2408
+ "no_progress_budget_exhausted"
2409
+ ];
2410
+ const { mode, standDownReason } = gate.resolvedPolicy;
2411
+ if (mode === "off") {
2412
+ return buildDecision(
2413
+ config,
2414
+ "defer",
2415
+ "Challenge automation mode is off; challenge handling is detect-and-report only.",
2416
+ [],
2417
+ "light",
2418
+ [standDownReason ?? "challenge_automation_off"]
2419
+ );
2420
+ }
2421
+ if (capabilityMatrix.mustDefer) {
2422
+ return buildDecision(
2423
+ config,
2424
+ "defer",
2425
+ "Current policy or blocker state requires deferral before further automation.",
2426
+ gate.allowedActions,
2427
+ interpretation.requiredVerification,
2428
+ ["policy_blocked_or_clear_state"]
2429
+ );
2430
+ }
2431
+ if (registryCooldownActive && !capabilityMatrix.canReuseExistingSession && !capabilityMatrix.canReuseCookies && !capabilityMatrix.canNavigateToAuth) {
2432
+ return buildDecision(
2433
+ config,
2434
+ "defer",
2435
+ "Registry cooldown is still active and no legitimate continuity or auth-navigation lane is currently available.",
2436
+ gate.allowedActions,
2437
+ interpretation.requiredVerification,
2438
+ ["registry_cooldown_active"]
2439
+ );
2440
+ }
2441
+ if (capabilityMatrix.canUseOwnedEnvironmentFixture) {
2442
+ return buildDecision(
2443
+ config,
2444
+ "owned_environment_fixture",
2445
+ "Owned-environment fixture detected and explicitly allowlisted.",
2446
+ gate.allowedActions,
2447
+ interpretation.requiredVerification,
2448
+ stopConditions,
2449
+ "owned_environment_fixture"
2450
+ );
2451
+ }
2452
+ if (capabilityMatrix.mustYield) {
2453
+ return buildDecision(
2454
+ config,
2455
+ "human_yield",
2456
+ `Human authority boundary reached: ${interpretation.humanBoundary}.`,
2457
+ gate.allowedActions,
2458
+ interpretation.requiredVerification,
2459
+ [...stopConditions, "human_authority_required"]
2460
+ );
2461
+ }
2462
+ if (capabilityMatrix.canNavigateToAuth || capabilityMatrix.canReuseExistingSession || capabilityMatrix.canReuseCookies || capabilityMatrix.canFillNonSecretFields || capabilityMatrix.canExploreClicks) {
2463
+ return buildDecision(
2464
+ config,
2465
+ "generic_browser_autonomy",
2466
+ registryPressureElevated ? "Registry pressure is elevated, but legitimate browser continuity remains available for one bounded generic autonomy pass." : "Existing browser controls can attempt bounded auth navigation, session reuse, non-secret fill, or interaction exploration.",
2467
+ gate.allowedActions,
2468
+ interpretation.requiredVerification,
2469
+ registryPressureElevated ? [...stopConditions, "registry_pressure_elevated"] : stopConditions
2470
+ );
2471
+ }
2472
+ if (capabilityMatrix.canUseComputerUseBridge) {
2473
+ return buildDecision(
2474
+ config,
2475
+ "optional_computer_use_bridge",
2476
+ "DOM-native autonomy is exhausted, but the optional browser-scoped bridge is enabled.",
2477
+ gate.allowedActions,
2478
+ interpretation.requiredVerification,
2479
+ stopConditions
2480
+ );
2481
+ }
2482
+ if (capabilityMatrix.canUseSanctionedIdentity) {
2483
+ return buildDecision(
2484
+ config,
2485
+ "sanctioned_identity",
2486
+ "Sanctioned identity lane is enabled and generic browser autonomy is insufficient.",
2487
+ gate.allowedActions,
2488
+ interpretation.requiredVerification,
2489
+ stopConditions,
2490
+ "sanctioned_identity"
2491
+ );
2492
+ }
2493
+ if (capabilityMatrix.canUseServiceAdapter) {
2494
+ return buildDecision(
2495
+ config,
2496
+ "service_adapter",
2497
+ "Governed service-adapter lane is enabled as the last non-human option.",
2498
+ gate.allowedActions,
2499
+ interpretation.requiredVerification,
2500
+ stopConditions,
2501
+ "service_adapter"
2502
+ );
2503
+ }
2504
+ return buildDecision(
2505
+ config,
2506
+ "human_yield",
2507
+ `No legitimate autonomous lane remains after applying policy and continuity checks. ${capabilityMatrix.helperEligibility.reason}`,
2508
+ gate.allowedActions,
2509
+ interpretation.requiredVerification,
2510
+ [...stopConditions, "no_legitimate_lane_remaining"]
2511
+ );
2512
+ };
2513
+
2514
+ // src/challenges/inspect-plan.ts
2515
+ var SENSITIVE_FIELD_RE = /\b(password|passcode|secret|otp|mfa|token|verification code|passkey)\b/i;
2516
+ var hasExecuted = (steps, kind, ref, url) => {
2517
+ return steps.some((step) => step.kind === kind && step.ref === ref && step.url === url);
2518
+ };
2519
+ var getActionable = (bundle, ref) => {
2520
+ return bundle.actionables.find((entry) => entry.ref === ref);
2521
+ };
2522
+ var deriveAuthUrls = (url) => {
2523
+ if (!url) {
2524
+ return [];
2525
+ }
2526
+ try {
2527
+ const current = new URL(url);
2528
+ const candidates = [
2529
+ "/login",
2530
+ "/signin",
2531
+ "/sign-in",
2532
+ "/account/login",
2533
+ "/session",
2534
+ "/auth/login"
2535
+ ];
2536
+ return candidates.map((path2) => new URL(path2, current.origin).toString());
2537
+ } catch {
2538
+ return [];
2539
+ }
2540
+ };
2541
+ var resolveTaskValue = (bundle, ref) => {
2542
+ const actionable = getActionable(bundle, ref);
2543
+ const name = actionable?.name?.toLowerCase();
2544
+ if (!name || !bundle.taskData) {
2545
+ return void 0;
2546
+ }
2547
+ for (const [key, value] of Object.entries(bundle.taskData)) {
2548
+ if (SENSITIVE_FIELD_RE.test(key) || SENSITIVE_FIELD_RE.test(name)) {
2549
+ continue;
2361
2550
  }
2362
- executedSteps.push(step);
2363
- if (step.ref && currentBundle.continuity.sessionReuseRefs.includes(step.ref)) {
2364
- reusedExistingSession = true;
2551
+ if (!name.includes(key.toLowerCase())) {
2552
+ continue;
2365
2553
  }
2366
- if (step.kind === "goto" && currentBundle.continuity.canReuseExistingCookies) {
2367
- reusedCookies = true;
2554
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
2555
+ return String(value);
2368
2556
  }
2369
- const verification = await verifyChallengeProgress({
2370
- handle: args.handle,
2371
- sessionId: args.sessionId,
2372
- targetId: currentTargetId,
2373
- previous: currentBundle,
2374
- canImportCookies: currentBundle.continuity.canImportCookies,
2375
- fallbackDisposition: currentBundle.fallbackDisposition,
2376
- registryPressure: currentBundle.registryPressure,
2377
- taskData: currentBundle.taskData
2378
- });
2379
- currentBundle = verification.bundle ?? currentBundle;
2380
- currentTargetId = verification.bundle?.activeTargetId ?? currentTargetId;
2381
- if (verification.status === "clear") {
2557
+ }
2558
+ return void 0;
2559
+ };
2560
+ var nextUnusedRef = (refs, steps, kind) => {
2561
+ return refs.find((ref) => !hasExecuted(steps, kind, ref));
2562
+ };
2563
+ var planInteractionStep = (bundle, decision, executedSteps) => {
2564
+ const interaction = bundle.interaction;
2565
+ if (!interaction || interaction.preferredAction === "unknown") {
2566
+ return void 0;
2567
+ }
2568
+ if (interaction.preferredAction === "click" && decision.allowedActionFamilies.includes("click_path")) {
2569
+ const clickRef = nextUnusedRef(interaction.clickRefs, executedSteps, "click");
2570
+ if (clickRef) {
2382
2571
  return {
2383
- status: "resolved",
2384
- attempts: attempt,
2385
- noProgressCount,
2386
- executedSteps,
2387
- verification,
2388
- reusedExistingSession,
2389
- reusedCookies
2572
+ kind: "click",
2573
+ ref: clickRef,
2574
+ reason: "Visible popup or interstitial exposes a bounded click path."
2390
2575
  };
2391
2576
  }
2392
- if (verification.status === "yield_required") {
2577
+ }
2578
+ if (interaction.preferredAction === "click_and_hold" && decision.allowedActionFamilies.includes("click_and_hold")) {
2579
+ const holdRef = nextUnusedRef(interaction.holdRefs, executedSteps, "click_and_hold");
2580
+ if (holdRef || !hasExecuted(executedSteps, "click_and_hold")) {
2393
2581
  return {
2394
- status: "yield_required",
2395
- attempts: attempt,
2396
- noProgressCount,
2397
- executedSteps,
2398
- verification,
2399
- reusedExistingSession,
2400
- reusedCookies
2582
+ kind: "click_and_hold",
2583
+ ...holdRef ? { ref: holdRef } : {},
2584
+ ...typeof interaction.holdMs === "number" ? { holdMs: interaction.holdMs } : {},
2585
+ reason: "Visible challenge requests a bounded click-and-hold gesture."
2401
2586
  };
2402
2587
  }
2403
- if (verification.status === "deferred") {
2404
- return {
2405
- status: "deferred",
2406
- attempts: attempt,
2407
- noProgressCount,
2408
- executedSteps,
2409
- verification,
2410
- reusedExistingSession,
2411
- reusedCookies
2412
- };
2413
- }
2414
- if (verification.changed) {
2415
- noProgressCount = 0;
2416
- continue;
2417
- }
2418
- noProgressCount += 1;
2419
- if (noProgressCount >= args.decision.noProgressLimit) {
2588
+ }
2589
+ if (interaction.preferredAction === "drag" && decision.allowedActionFamilies.includes("drag") && !hasExecuted(executedSteps, "drag")) {
2590
+ return {
2591
+ kind: "drag",
2592
+ ...interaction.dragRefs[0] ? { ref: interaction.dragRefs[0] } : {},
2593
+ coordinates: { x: 640, y: 360 },
2594
+ reason: "Visible challenge requests a bounded drag gesture."
2595
+ };
2596
+ }
2597
+ return void 0;
2598
+ };
2599
+ var planGenericStep = (bundle, decision, executedSteps) => {
2600
+ const sessionRef = nextUnusedRef(
2601
+ bundle.continuity.sessionReuseRefs,
2602
+ executedSteps,
2603
+ "click"
2604
+ );
2605
+ if (sessionRef) {
2606
+ return {
2607
+ kind: "click",
2608
+ ref: sessionRef,
2609
+ reason: "Try the existing-session or account-selection path first."
2610
+ };
2611
+ }
2612
+ const loginRef = nextUnusedRef(bundle.continuity.loginRefs, executedSteps, "click");
2613
+ if (decision.allowedActionFamilies.includes("auth_navigation") && loginRef) {
2614
+ return {
2615
+ kind: "click",
2616
+ ref: loginRef,
2617
+ reason: "Try the visible auth-navigation entrypoint."
2618
+ };
2619
+ }
2620
+ if (decision.allowedActionFamilies.includes("auth_navigation")) {
2621
+ const loginUrl = deriveAuthUrls(bundle.url).find((candidate) => {
2622
+ return !hasExecuted(executedSteps, "goto", void 0, candidate);
2623
+ });
2624
+ if (loginUrl) {
2420
2625
  return {
2421
- status: "no_progress",
2422
- attempts: attempt,
2423
- noProgressCount,
2424
- executedSteps,
2425
- verification,
2426
- reusedExistingSession,
2427
- reusedCookies
2626
+ kind: "goto",
2627
+ url: loginUrl,
2628
+ reason: "Try a conventional auth-navigation URL on the current origin."
2428
2629
  };
2429
2630
  }
2430
2631
  }
2431
- return {
2432
- status: "still_blocked",
2433
- attempts: args.decision.attemptBudget,
2434
- noProgressCount,
2632
+ const fieldRef = nextUnusedRef(
2633
+ bundle.continuity.nonSecretFieldRefs,
2435
2634
  executedSteps,
2436
- verification: {
2437
- status: "still_blocked",
2438
- blockerState: currentBundle.blockerState,
2439
- blocker: currentBundle.blocker,
2440
- challenge: currentBundle.challenge,
2441
- bundle: currentBundle,
2442
- changed: false,
2443
- reason: "Attempt budget exhausted without clearing the blocker.",
2444
- url: currentBundle.url,
2445
- title: currentBundle.title
2446
- },
2447
- reusedExistingSession,
2448
- reusedCookies
2449
- };
2450
- };
2451
-
2452
- // src/challenges/capability-matrix.ts
2453
- var buildCapabilityMatrix = (bundle, interpretation, gate) => {
2454
- const hasActionables = bundle.actionables.length > 0;
2455
- const helperActionRefs = [
2456
- ...bundle.continuity.loginRefs,
2457
- ...bundle.continuity.sessionReuseRefs,
2458
- ...bundle.continuity.humanVerificationRefs,
2459
- ...bundle.continuity.checkpointRefs,
2460
- ...bundle.interaction?.clickRefs ?? [],
2461
- ...bundle.interaction?.holdRefs ?? [],
2462
- ...bundle.interaction?.dragRefs ?? []
2463
- ];
2464
- const authLaneRelevant = interpretation.classification === "auth_required" || interpretation.classification === "existing_session_reuse" || bundle.continuity.likelyLoginPage || bundle.continuity.likelySessionPicker;
2465
- const canNavigateToAuth = gate.allowedActions.includes("auth_navigation") && authLaneRelevant && (bundle.continuity.loginRefs.length > 0 || typeof bundle.url === "string");
2466
- const canReuseExistingSession = gate.allowedActions.includes("session_reuse") && (bundle.continuity.hasPreservedSession || bundle.continuity.attachedSession || bundle.continuity.sessionReuseRefs.length > 0);
2467
- const canReuseCookies = gate.allowedActions.includes("cookie_reuse") && authLaneRelevant && (bundle.continuity.canReuseExistingCookies || bundle.continuity.canImportCookies);
2468
- const canFillNonSecretFields = gate.allowedActions.includes("non_secret_form_fill") && bundle.continuity.hasNonSecretTaskData && bundle.continuity.nonSecretFieldRefs.length > 0;
2469
- const canExploreClicks = gate.allowedActions.includes("click_path") && (hasActionables || bundle.continuity.loginRefs.length > 0 || bundle.continuity.sessionReuseRefs.length > 0 || bundle.continuity.checkpointRefs.length > 0);
2470
- const mustYield = interpretation.humanBoundary === "secret_entry" || interpretation.humanBoundary === "mfa" || interpretation.humanBoundary === "explicit_consent" || interpretation.humanBoundary === "exhausted_no_progress";
2471
- const mustDefer = interpretation.humanBoundary === "policy_blocked" || !bundle.blocker && bundle.blockerState === "clear";
2472
- let helperEligibility = gate.helperEligibility ?? (gate.optionalComputerUseBridge ? {
2473
- allowed: true,
2474
- reason: "Optional helper bridge remains eligible after policy resolution."
2475
- } : {
2476
- allowed: false,
2477
- reason: "Optional computer-use bridge is disabled by policy.",
2478
- standDownReason: "helper_disabled_by_policy"
2479
- });
2480
- if (helperEligibility.allowed && interpretation.humanBoundary !== "none") {
2481
- helperEligibility = {
2482
- allowed: false,
2483
- reason: `Helper bridge is blocked by human boundary: ${interpretation.humanBoundary}.`,
2484
- standDownReason: "helper_blocked_by_human_boundary"
2635
+ "type"
2636
+ );
2637
+ const fieldValue = fieldRef ? resolveTaskValue(bundle, fieldRef) : void 0;
2638
+ if (decision.allowedActionFamilies.includes("non_secret_form_fill") && fieldRef && fieldValue) {
2639
+ return {
2640
+ kind: "type",
2641
+ ref: fieldRef,
2642
+ text: fieldValue,
2643
+ reason: "Fill a non-secret field from caller-provided task data."
2485
2644
  };
2486
- } else if (helperEligibility.allowed && helperActionRefs.length === 0) {
2487
- helperEligibility = {
2488
- allowed: false,
2489
- reason: "Canonical evidence did not expose any safe browser-scoped helper actions.",
2490
- standDownReason: "helper_no_safe_actions"
2645
+ }
2646
+ const checkpointRef = nextUnusedRef(
2647
+ bundle.continuity.checkpointRefs,
2648
+ executedSteps,
2649
+ "click"
2650
+ );
2651
+ if (decision.allowedActionFamilies.includes("click_path") && checkpointRef) {
2652
+ return {
2653
+ kind: "click",
2654
+ ref: checkpointRef,
2655
+ reason: "Try the next visible checkpoint or continue action."
2491
2656
  };
2492
2657
  }
2493
- return {
2494
- canNavigateToAuth,
2495
- canReuseExistingSession,
2496
- canReuseCookies,
2497
- canFillNonSecretFields,
2498
- canExploreClicks,
2499
- canUseOwnedEnvironmentFixture: interpretation.classification === "owned_environment_test_challenge" && gate.governedLanes.includes("owned_environment_fixture"),
2500
- canUseSanctionedIdentity: gate.governedLanes.includes("sanctioned_identity"),
2501
- canUseServiceAdapter: gate.governedLanes.includes("service_adapter"),
2502
- canUseComputerUseBridge: helperEligibility.allowed,
2503
- helperEligibility,
2504
- mustYield,
2505
- mustDefer
2506
- };
2658
+ const hoverRef = nextUnusedRef(
2659
+ [...bundle.continuity.loginRefs, ...bundle.continuity.checkpointRefs],
2660
+ executedSteps,
2661
+ "hover"
2662
+ );
2663
+ if (decision.allowedActionFamilies.includes("hover") && hoverRef) {
2664
+ return {
2665
+ kind: "hover",
2666
+ ref: hoverRef,
2667
+ reason: "Hover a likely action target to reveal hidden menus or session pickers."
2668
+ };
2669
+ }
2670
+ if (decision.allowedActionFamilies.includes("scroll") && !hasExecuted(executedSteps, "scroll")) {
2671
+ return {
2672
+ kind: "scroll",
2673
+ dy: 900,
2674
+ reason: "Scroll down to uncover the next actionable region."
2675
+ };
2676
+ }
2677
+ if (decision.allowedActionFamilies.includes("scroll") && executedSteps.filter((step) => step.kind === "scroll").length === 1) {
2678
+ return {
2679
+ kind: "scroll",
2680
+ dy: -450,
2681
+ reason: "Scroll back up to re-evaluate the visible challenge state."
2682
+ };
2683
+ }
2684
+ if (decision.allowedActionFamilies.includes("press") && !hasExecuted(executedSteps, "press")) {
2685
+ return {
2686
+ kind: "press",
2687
+ text: "Tab",
2688
+ reason: "Advance focus through the challenge surface."
2689
+ };
2690
+ }
2691
+ if (decision.allowedActionFamilies.includes("pointer") && !hasExecuted(executedSteps, "pointer")) {
2692
+ return {
2693
+ kind: "pointer",
2694
+ coordinates: { x: 640, y: 360 },
2695
+ reason: "Move the pointer through the center of the current browser surface."
2696
+ };
2697
+ }
2698
+ if (decision.allowedActionFamilies.includes("drag") && !hasExecuted(executedSteps, "drag")) {
2699
+ return {
2700
+ kind: "drag",
2701
+ coordinates: { x: 640, y: 360 },
2702
+ reason: "Attempt one bounded vertical drag across the visible surface."
2703
+ };
2704
+ }
2705
+ if (!hasExecuted(executedSteps, "wait")) {
2706
+ return {
2707
+ kind: "wait",
2708
+ reason: "Give the page a short bounded settle window before yielding."
2709
+ };
2710
+ }
2711
+ return void 0;
2507
2712
  };
2508
-
2509
- // src/challenges/owned-environment-lane.ts
2510
- var APPROVED_FIXTURE_RE = /\b(turnstile-checkbox|recaptcha-v2-checkbox|1x00000000000000000000AA|6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI)\b/i;
2511
- var runOwnedEnvironmentLane = (request) => {
2512
- const haystack = [request.bundle.url, request.bundle.title, request.bundle.snapshotText].filter((value) => typeof value === "string" && value.length > 0).join(" ");
2513
- const approved = APPROVED_FIXTURE_RE.test(haystack);
2514
- return {
2515
- status: approved ? "executed" : "blocked",
2516
- lane: "owned_environment_fixture",
2517
- reason: approved ? "Approved owned-environment fixture detected." : "Owned-environment lane requires an approved vendor test fixture.",
2518
- auditMetadata: {
2519
- approvedFixture: approved
2713
+ var pendingSteps = (steps, executedSteps) => {
2714
+ return (steps ?? []).filter((step) => {
2715
+ return !hasExecuted(executedSteps, step.kind, step.ref, step.url);
2716
+ });
2717
+ };
2718
+ var dedupeSteps = (steps) => {
2719
+ const seen = /* @__PURE__ */ new Set();
2720
+ return steps.filter((step) => {
2721
+ const key = JSON.stringify([
2722
+ step.kind,
2723
+ step.ref ?? null,
2724
+ step.url ?? null,
2725
+ step.text ?? null,
2726
+ step.reason
2727
+ ]);
2728
+ if (seen.has(key)) {
2729
+ return false;
2520
2730
  }
2521
- };
2731
+ seen.add(key);
2732
+ return true;
2733
+ });
2522
2734
  };
2523
-
2524
- // src/challenges/sanctioned-identity-lane.ts
2525
- var runSanctionedIdentityLane = (request) => {
2526
- const entitlement = request.auditContext?.identityEntitlement;
2527
- const approved = typeof entitlement === "string" && entitlement.trim().length > 0;
2735
+ var buildChallengeActionSuggestions = (args) => {
2736
+ const executedSteps = args.executedSteps ?? [];
2737
+ const helper = suggestComputerUseActions({
2738
+ helperEligibility: args.helperEligibility,
2739
+ bundle: args.bundle,
2740
+ maxSuggestions: args.config.optionalComputerUseBridge.maxSuggestions
2741
+ });
2742
+ const preferredSteps = pendingSteps(args.preferredSteps, executedSteps);
2743
+ const interactionStep = planInteractionStep(args.bundle, args.decision, executedSteps);
2744
+ const genericStep = planGenericStep(args.bundle, args.decision, executedSteps);
2745
+ const helperSteps = pendingSteps(helper.suggestedSteps, executedSteps);
2746
+ const suggestedSteps = args.decision.lane === "optional_computer_use_bridge" ? dedupeSteps([...preferredSteps, ...helperSteps]) : dedupeSteps([
2747
+ ...preferredSteps,
2748
+ ...interactionStep ? [interactionStep] : [],
2749
+ ...genericStep ? [genericStep] : [],
2750
+ ...helperSteps
2751
+ ]);
2528
2752
  return {
2529
- status: approved ? "executed" : "blocked",
2530
- lane: "sanctioned_identity",
2531
- reason: approved ? "Sanctioned identity lane approved by explicit entitlement." : "Sanctioned identity lane requires explicit entitlement metadata.",
2532
- auditMetadata: {
2533
- approved,
2534
- ...approved ? { entitlement } : {}
2535
- }
2753
+ helper,
2754
+ suggestedSteps
2536
2755
  };
2537
2756
  };
2538
-
2539
- // src/challenges/service-adapter-lane.ts
2540
- var runServiceAdapterLane = (request) => {
2541
- const adapter = request.auditContext?.adapterId;
2542
- const approved = typeof adapter === "string" && adapter.trim().length > 0;
2757
+ var selectChallengeActionStep = (args) => {
2758
+ return buildChallengeActionSuggestions(args).suggestedSteps[0];
2759
+ };
2760
+ function buildChallengeInspectPlan(args) {
2761
+ const interpretation = interpretChallengeEvidence(args.bundle);
2762
+ const policy = resolveChallengeAutomationPolicy({
2763
+ runMode: args.runMode,
2764
+ sessionMode: args.sessionMode,
2765
+ configMode: args.config.mode
2766
+ });
2767
+ const gate = buildChallengePolicyGate(args.config, interpretation, policy);
2768
+ const capabilityMatrix = buildCapabilityMatrix(args.bundle, interpretation, gate);
2769
+ const decision = selectChallengeStrategy({
2770
+ config: args.config,
2771
+ bundle: args.bundle,
2772
+ interpretation,
2773
+ capabilityMatrix,
2774
+ gate
2775
+ });
2776
+ const actionSuggestions = buildChallengeActionSuggestions({
2777
+ bundle: args.bundle,
2778
+ decision,
2779
+ helperEligibility: capabilityMatrix.helperEligibility,
2780
+ config: args.config,
2781
+ preferredSteps: args.preferredSteps,
2782
+ executedSteps: args.executedSteps
2783
+ });
2784
+ const yieldDecision = shouldYieldToHuman({
2785
+ interpretation,
2786
+ noProgressExhausted: false
2787
+ });
2788
+ const standDownReason = capabilityMatrix.helperEligibility.standDownReason ?? gate.resolvedPolicy.standDownReason ?? actionSuggestions.helper.standDownReason;
2543
2789
  return {
2544
- status: approved ? "executed" : "blocked",
2545
- lane: "service_adapter",
2546
- reason: approved ? "Governed service adapter approved by explicit adapter metadata." : "Service-adapter lane requires an explicit adapter identifier and entitlement.",
2547
- auditMetadata: {
2548
- approved,
2549
- ...approved ? { adapterId: adapter } : {}
2790
+ challengeId: args.bundle.challengeId,
2791
+ ...args.bundle.mode ? { sessionMode: args.bundle.mode } : {},
2792
+ classification: interpretation.classification,
2793
+ authState: interpretation.authState,
2794
+ summary: interpretation.summary,
2795
+ mode: gate.resolvedPolicy.mode,
2796
+ source: gate.resolvedPolicy.source,
2797
+ helperEligibility: capabilityMatrix.helperEligibility,
2798
+ ...standDownReason ? { standDownReason } : {},
2799
+ yield: {
2800
+ required: yieldDecision.yield,
2801
+ reason: yieldDecision.reason
2802
+ },
2803
+ decision,
2804
+ allowedActionFamilies: gate.allowedActions,
2805
+ forbiddenActionFamilies: gate.forbiddenActions,
2806
+ governedLanes: gate.governedLanes,
2807
+ capabilityMatrix,
2808
+ helper: actionSuggestions.helper,
2809
+ suggestedSteps: actionSuggestions.suggestedSteps,
2810
+ evidence: {
2811
+ blockerState: args.bundle.blockerState,
2812
+ ...args.bundle.blocker?.type ? { blockerType: args.bundle.blocker.type } : {},
2813
+ ...args.bundle.url ? { url: args.bundle.url } : {},
2814
+ ...args.bundle.title ? { title: args.bundle.title } : {},
2815
+ ...typeof args.bundle.activeTargetId !== "undefined" ? { activeTargetId: args.bundle.activeTargetId } : {},
2816
+ ...args.bundle.snapshotId ? { snapshotId: args.bundle.snapshotId } : {},
2817
+ loginRefs: args.bundle.continuity.loginRefs,
2818
+ sessionReuseRefs: args.bundle.continuity.sessionReuseRefs,
2819
+ humanVerificationRefs: args.bundle.continuity.humanVerificationRefs,
2820
+ checkpointRefs: args.bundle.continuity.checkpointRefs
2550
2821
  }
2551
2822
  };
2552
- };
2823
+ }
2824
+ async function inspectChallengePlanFromRuntime(args) {
2825
+ const bundle = await captureChallengeEvidence({
2826
+ handle: args.handle,
2827
+ sessionId: args.sessionId,
2828
+ targetId: args.targetId,
2829
+ canImportCookies: args.canImportCookies ?? true
2830
+ });
2831
+ return buildChallengeInspectPlan({
2832
+ bundle,
2833
+ config: args.config,
2834
+ runMode: args.runMode,
2835
+ sessionMode: args.sessionMode
2836
+ });
2837
+ }
2553
2838
 
2554
- // src/challenges/governed-adapter-gateway.ts
2555
- var evaluateGovernedLane = (config, request) => {
2556
- if (config.mode === "off") {
2557
- return {
2558
- status: "blocked",
2559
- lane: request.lane,
2560
- reason: "Challenge automation mode is off.",
2561
- auditMetadata: {}
2562
- };
2839
+ // src/challenges/action-loop.ts
2840
+ var DEFAULT_HOLD_MS2 = 1500;
2841
+ var resolveStepPoint = async (args) => {
2842
+ if (!args.step.ref) {
2843
+ return args.step.coordinates ?? args.fallback;
2563
2844
  }
2564
- switch (request.lane) {
2565
- case "owned_environment_fixture":
2566
- if (!config.governed.allowOwnedEnvironmentFixtures) {
2567
- return {
2568
- status: "blocked",
2569
- lane: request.lane,
2570
- reason: "Owned-environment fixtures are disabled by policy.",
2571
- auditMetadata: {}
2572
- };
2845
+ return await args.handle.resolveRefPoint(args.sessionId, args.step.ref, args.targetId);
2846
+ };
2847
+ var executeStep = async (args) => {
2848
+ const timeoutMs = args.config.stepTimeoutMs;
2849
+ switch (args.step.kind) {
2850
+ case "goto":
2851
+ if (args.step.url) {
2852
+ await args.handle.goto(args.sessionId, args.step.url, "domcontentloaded", timeoutMs, void 0, args.targetId);
2573
2853
  }
2574
- return runOwnedEnvironmentLane(request);
2575
- case "sanctioned_identity":
2576
- if (!config.governed.allowSanctionedIdentity) {
2577
- return {
2578
- status: "blocked",
2579
- lane: request.lane,
2580
- reason: "Sanctioned identity is disabled by policy.",
2581
- auditMetadata: {}
2582
- };
2854
+ return;
2855
+ case "click":
2856
+ if (args.step.ref) {
2857
+ await args.handle.click(args.sessionId, args.step.ref, args.targetId);
2583
2858
  }
2584
- return runSanctionedIdentityLane(request);
2585
- case "service_adapter":
2586
- if (!config.governed.allowServiceAdapters) {
2587
- return {
2588
- status: "blocked",
2589
- lane: request.lane,
2590
- reason: "Service adapters are disabled by policy.",
2591
- auditMetadata: {}
2592
- };
2859
+ return;
2860
+ case "click_and_hold": {
2861
+ const point = await resolveStepPoint({
2862
+ handle: args.handle,
2863
+ sessionId: args.sessionId,
2864
+ step: args.step,
2865
+ targetId: args.targetId,
2866
+ fallback: { x: 640, y: 360 }
2867
+ });
2868
+ await args.handle.pointerMove(args.sessionId, point.x, point.y, args.targetId, 12);
2869
+ await args.handle.pointerDown(args.sessionId, point.x, point.y, args.targetId, "left", 1);
2870
+ await new Promise((resolve2) => setTimeout(resolve2, Math.max(250, args.step.holdMs ?? DEFAULT_HOLD_MS2)));
2871
+ await args.handle.pointerUp(args.sessionId, point.x, point.y, args.targetId, "left", 1);
2872
+ return;
2873
+ }
2874
+ case "hover":
2875
+ if (args.step.ref) {
2876
+ await args.handle.hover(args.sessionId, args.step.ref, args.targetId);
2593
2877
  }
2594
- return runServiceAdapterLane(request);
2878
+ return;
2879
+ case "press":
2880
+ await args.handle.press(args.sessionId, args.step.text ?? "Tab", void 0, args.targetId);
2881
+ return;
2882
+ case "type":
2883
+ if (args.step.ref && typeof args.step.text === "string") {
2884
+ await args.handle.type(args.sessionId, args.step.ref, args.step.text, true, false, args.targetId);
2885
+ }
2886
+ return;
2887
+ case "select":
2888
+ if (args.step.ref && args.step.values?.length) {
2889
+ await args.handle.select(args.sessionId, args.step.ref, args.step.values, args.targetId);
2890
+ }
2891
+ return;
2892
+ case "scroll":
2893
+ await args.handle.scroll(args.sessionId, args.step.dy ?? 600, void 0, args.targetId);
2894
+ return;
2895
+ case "pointer":
2896
+ await args.handle.pointerMove(
2897
+ args.sessionId,
2898
+ args.step.coordinates?.x ?? 640,
2899
+ args.step.coordinates?.y ?? 360,
2900
+ args.targetId,
2901
+ 12
2902
+ );
2903
+ return;
2904
+ case "drag":
2905
+ {
2906
+ const point = await resolveStepPoint({
2907
+ handle: args.handle,
2908
+ sessionId: args.sessionId,
2909
+ step: args.step,
2910
+ targetId: args.targetId,
2911
+ fallback: args.step.coordinates ?? { x: 640, y: 360 }
2912
+ });
2913
+ await args.handle.drag(
2914
+ args.sessionId,
2915
+ point,
2916
+ {
2917
+ x: point.x,
2918
+ y: point.y + 260
2919
+ },
2920
+ args.targetId,
2921
+ 16
2922
+ );
2923
+ }
2924
+ return;
2925
+ case "cookie_list":
2926
+ await args.handle.cookieList(args.sessionId, args.step.url ? [args.step.url] : void 0);
2927
+ return;
2928
+ case "cookie_import":
2929
+ await args.handle.cookieImport(args.sessionId, args.step.cookies ?? [], true);
2930
+ return;
2931
+ case "snapshot":
2932
+ await args.handle.snapshot(
2933
+ args.sessionId,
2934
+ "actionables",
2935
+ args.step.snapshotChars ?? 2400,
2936
+ void 0,
2937
+ args.targetId
2938
+ );
2939
+ return;
2940
+ case "debug_trace":
2941
+ await args.handle.debugTraceSnapshot(args.sessionId, { max: args.step.traceMax ?? 50 });
2942
+ return;
2943
+ case "wait":
2944
+ await args.handle.waitForLoad(args.sessionId, "networkidle", Math.min(timeoutMs, 3e3), args.targetId);
2945
+ return;
2946
+ default:
2947
+ return;
2595
2948
  }
2596
2949
  };
2597
-
2598
- // src/challenges/human-yield-gate.ts
2599
- var shouldYieldToHuman = (args) => {
2600
- if (args.noProgressExhausted) {
2601
- return {
2602
- yield: true,
2603
- reason: "exhausted_no_progress"
2604
- };
2950
+ var runChallengeActionLoop = async (args) => {
2951
+ let currentBundle = args.initialBundle;
2952
+ let currentTargetId = args.targetId ?? args.initialBundle.activeTargetId ?? null;
2953
+ const executedSteps = [];
2954
+ let noProgressCount = 0;
2955
+ let reusedExistingSession = false;
2956
+ let reusedCookies = false;
2957
+ for (let attempt = 1; attempt <= args.decision.attemptBudget; attempt += 1) {
2958
+ const step = selectChallengeActionStep({
2959
+ bundle: currentBundle,
2960
+ decision: args.decision,
2961
+ helperEligibility: args.helperEligibility,
2962
+ config: args.config,
2963
+ preferredSteps: args.suggestedSteps,
2964
+ executedSteps
2965
+ });
2966
+ if (!step) {
2967
+ return {
2968
+ status: "no_progress",
2969
+ attempts: attempt - 1,
2970
+ noProgressCount,
2971
+ executedSteps,
2972
+ verification: {
2973
+ status: "still_blocked",
2974
+ blockerState: currentBundle.blockerState,
2975
+ blocker: currentBundle.blocker,
2976
+ challenge: currentBundle.challenge,
2977
+ bundle: currentBundle,
2978
+ changed: false,
2979
+ reason: "No additional safe browser action remained.",
2980
+ url: currentBundle.url,
2981
+ title: currentBundle.title
2982
+ },
2983
+ reusedExistingSession,
2984
+ reusedCookies
2985
+ };
2986
+ }
2987
+ try {
2988
+ await executeStep({
2989
+ handle: args.handle,
2990
+ sessionId: args.sessionId,
2991
+ targetId: currentTargetId,
2992
+ step,
2993
+ config: args.config
2994
+ });
2995
+ } catch {
2996
+ }
2997
+ executedSteps.push(step);
2998
+ if (step.ref && currentBundle.continuity.sessionReuseRefs.includes(step.ref)) {
2999
+ reusedExistingSession = true;
3000
+ }
3001
+ if (step.kind === "goto" && currentBundle.continuity.canReuseExistingCookies) {
3002
+ reusedCookies = true;
3003
+ }
3004
+ const verification = await verifyChallengeProgress({
3005
+ handle: args.handle,
3006
+ sessionId: args.sessionId,
3007
+ targetId: currentTargetId,
3008
+ previous: currentBundle,
3009
+ canImportCookies: currentBundle.continuity.canImportCookies,
3010
+ fallbackDisposition: currentBundle.fallbackDisposition,
3011
+ registryPressure: currentBundle.registryPressure,
3012
+ taskData: currentBundle.taskData
3013
+ });
3014
+ currentBundle = verification.bundle ?? currentBundle;
3015
+ currentTargetId = verification.bundle?.activeTargetId ?? currentTargetId;
3016
+ if (verification.status === "clear") {
3017
+ return {
3018
+ status: "resolved",
3019
+ attempts: attempt,
3020
+ noProgressCount,
3021
+ executedSteps,
3022
+ verification,
3023
+ reusedExistingSession,
3024
+ reusedCookies
3025
+ };
3026
+ }
3027
+ if (verification.status === "yield_required") {
3028
+ return {
3029
+ status: "yield_required",
3030
+ attempts: attempt,
3031
+ noProgressCount,
3032
+ executedSteps,
3033
+ verification,
3034
+ reusedExistingSession,
3035
+ reusedCookies
3036
+ };
3037
+ }
3038
+ if (verification.status === "deferred") {
3039
+ return {
3040
+ status: "deferred",
3041
+ attempts: attempt,
3042
+ noProgressCount,
3043
+ executedSteps,
3044
+ verification,
3045
+ reusedExistingSession,
3046
+ reusedCookies
3047
+ };
3048
+ }
3049
+ if (verification.changed) {
3050
+ noProgressCount = 0;
3051
+ continue;
3052
+ }
3053
+ noProgressCount += 1;
3054
+ if (noProgressCount >= args.decision.noProgressLimit) {
3055
+ return {
3056
+ status: "no_progress",
3057
+ attempts: attempt,
3058
+ noProgressCount,
3059
+ executedSteps,
3060
+ verification,
3061
+ reusedExistingSession,
3062
+ reusedCookies
3063
+ };
3064
+ }
2605
3065
  }
2606
3066
  return {
2607
- yield: args.interpretation.humanBoundary !== "none",
2608
- reason: args.interpretation.humanBoundary
2609
- };
2610
- };
2611
- var buildHumanYieldPacket = (args) => {
2612
- const challengeId = args.bundle.challengeId ?? `challenge-${Date.now()}`;
2613
- const targetHints = [
2614
- ...args.bundle.continuity.loginRefs,
2615
- ...args.bundle.continuity.sessionReuseRefs,
2616
- ...args.bundle.continuity.humanVerificationRefs,
2617
- ...args.bundle.continuity.checkpointRefs
2618
- ];
2619
- return {
2620
- challengeId,
2621
- classification: args.interpretation.classification,
2622
- reason: args.reason,
2623
- sessionId: args.sessionId,
2624
- targetId: args.targetId ?? args.bundle.activeTargetId,
2625
- ownerSurface: args.bundle.challenge?.ownerSurface ?? args.bundle.ownerSurface,
2626
- url: args.bundle.url,
2627
- title: args.bundle.title,
2628
- requiredHumanStep: args.reason === "mfa" ? "Complete MFA or passkey verification, then continue." : args.reason === "secret_entry" ? "Enter the required secret-bearing credentials, then continue." : args.reason === "unsupported_third_party" ? "Complete the unsupported third-party challenge manually, then continue." : "Review the page state and continue when ready.",
2629
- targetHints,
2630
- expectedPostAuthCheckpoint: args.interpretation.likelyCheckpoint,
2631
- preserveUntil: args.bundle.challenge?.preserveUntil,
2632
- verifyUntil: args.bundle.challenge?.verifyUntil,
2633
- traceRequestId: args.bundle.diagnostics.traceRequestId,
2634
- ...args.verification ? {
2635
- lastVerificationStatus: args.verification.status,
2636
- lastVerificationReason: args.verification.reason
2637
- } : {},
2638
- evidenceSummary: args.interpretation.summary,
2639
- reclaimHint: "Resume the preserved session and re-run verification after the human step completes.",
2640
- resumeRule: "Re-run manager-owned verification after the human step completes before resuming automation."
3067
+ status: "still_blocked",
3068
+ attempts: args.decision.attemptBudget,
3069
+ noProgressCount,
3070
+ executedSteps,
3071
+ verification: {
3072
+ status: "still_blocked",
3073
+ blockerState: currentBundle.blockerState,
3074
+ blocker: currentBundle.blocker,
3075
+ challenge: currentBundle.challenge,
3076
+ bundle: currentBundle,
3077
+ changed: false,
3078
+ reason: "Attempt budget exhausted without clearing the blocker.",
3079
+ url: currentBundle.url,
3080
+ title: currentBundle.title
3081
+ },
3082
+ reusedExistingSession,
3083
+ reusedCookies
2641
3084
  };
2642
3085
  };
2643
3086
 
2644
- // src/challenges/outcome-recorder.ts
2645
- var MAX_RECORDS_PER_CHALLENGE = 25;
2646
- var OutcomeRecorder = class {
2647
- records = /* @__PURE__ */ new Map();
2648
- record(record) {
2649
- const key = record.challengeId ?? "__untracked__";
2650
- const existing = this.records.get(key) ?? [];
2651
- const next = [...existing, record].slice(-MAX_RECORDS_PER_CHALLENGE);
2652
- this.records.set(key, next);
2653
- }
2654
- latest(challengeId) {
2655
- if (!challengeId) return void 0;
2656
- const entries = this.records.get(challengeId);
2657
- return entries?.[entries.length - 1];
2658
- }
2659
- read(challengeId) {
2660
- if (!challengeId) return [];
2661
- return [...this.records.get(challengeId) ?? []];
2662
- }
2663
- };
2664
-
2665
- // src/challenges/policy-gate.ts
2666
- var ALL_ACTIONS = [
2667
- "wait",
2668
- "auth_navigation",
2669
- "session_reuse",
2670
- "cookie_reuse",
2671
- "element_discovery",
2672
- "click_path",
2673
- "click_and_hold",
2674
- "non_secret_form_fill",
2675
- "dropdown",
2676
- "scroll",
2677
- "hover",
2678
- "press",
2679
- "pointer",
2680
- "drag",
2681
- "verification",
2682
- "debug_trace"
2683
- ];
2684
- var DEFAULT_HANDOFF_TRIGGERS = [
2685
- "secret_entry",
2686
- "mfa",
2687
- "explicit_consent",
2688
- "policy_blocked",
2689
- "unsupported_third_party",
2690
- "exhausted_no_progress"
2691
- ];
2692
- var buildResolvedPolicy = (mode, source) => {
2693
- if (mode === "off") {
2694
- return {
2695
- mode,
2696
- source,
2697
- standDownReason: "challenge_automation_off"
2698
- };
2699
- }
2700
- if (mode === "browser") {
2701
- return {
2702
- mode,
2703
- source,
2704
- standDownReason: "helper_disabled_for_browser_mode"
2705
- };
2706
- }
2707
- return { mode, source };
2708
- };
2709
- var resolveChallengeAutomationPolicy = (args) => {
2710
- if (args.runMode) {
2711
- return buildResolvedPolicy(args.runMode, "run");
2712
- }
2713
- if (args.sessionMode) {
2714
- return buildResolvedPolicy(args.sessionMode, "session");
2715
- }
2716
- return buildResolvedPolicy(args.configMode, "config");
2717
- };
2718
- var resolveHelperEligibility = (config, policy) => {
2719
- if (policy.mode === "off") {
2720
- return {
2721
- allowed: false,
2722
- reason: "Challenge automation mode is off; detection and reporting remain active.",
2723
- standDownReason: "challenge_automation_off"
2724
- };
2725
- }
2726
- if (policy.mode === "browser") {
2727
- return {
2728
- allowed: false,
2729
- reason: "Browser mode keeps the optional helper bridge disabled.",
2730
- standDownReason: "helper_disabled_for_browser_mode"
2731
- };
2732
- }
2733
- if (!config.optionalComputerUseBridge.enabled) {
2734
- return {
2735
- allowed: false,
2736
- reason: "Optional computer-use bridge is disabled by policy.",
2737
- standDownReason: "helper_disabled_by_policy"
2738
- };
2739
- }
2740
- return {
2741
- allowed: true,
2742
- reason: "Optional helper bridge remains eligible after mode resolution."
2743
- };
2744
- };
2745
- var buildChallengePolicyGate = (config, interpretation, resolvedPolicy = resolveChallengeAutomationPolicy({
2746
- configMode: config.mode
2747
- })) => {
2748
- const helperEligibility = resolveHelperEligibility(config, resolvedPolicy);
2749
- if (resolvedPolicy.mode === "off") {
2750
- return {
2751
- resolvedPolicy,
2752
- allowedActions: [],
2753
- forbiddenActions: [...ALL_ACTIONS],
2754
- handoffTriggers: [...DEFAULT_HANDOFF_TRIGGERS],
2755
- governedLanes: [],
2756
- optionalComputerUseBridge: false,
2757
- helperEligibility
2758
- };
2759
- }
2760
- const allowed = /* @__PURE__ */ new Set(["wait", "verification", "debug_trace"]);
2761
- if (config.allowAuthNavigation) {
2762
- allowed.add("auth_navigation");
2763
- }
2764
- if (config.allowSessionReuse) {
2765
- allowed.add("session_reuse");
2766
- }
2767
- if (config.allowCookieReuse) {
2768
- allowed.add("cookie_reuse");
2769
- }
2770
- if (config.allowNonSecretFormFill) {
2771
- allowed.add("non_secret_form_fill");
2772
- allowed.add("dropdown");
2773
- }
2774
- if (config.allowInteractionExploration) {
2775
- allowed.add("element_discovery");
2776
- allowed.add("click_path");
2777
- allowed.add("click_and_hold");
2778
- allowed.add("scroll");
2779
- allowed.add("hover");
2780
- allowed.add("press");
2781
- allowed.add("pointer");
2782
- allowed.add("drag");
2783
- }
2784
- if (interpretation.humanBoundary === "secret_entry" || interpretation.humanBoundary === "mfa") {
2785
- allowed.delete("non_secret_form_fill");
2786
- }
2787
- const governedLanes = [];
2788
- if (config.governed.allowOwnedEnvironmentFixtures) {
2789
- governedLanes.push("owned_environment_fixture");
2790
- }
2791
- if (config.governed.allowSanctionedIdentity) {
2792
- governedLanes.push("sanctioned_identity");
2793
- }
2794
- if (config.governed.allowServiceAdapters) {
2795
- governedLanes.push("service_adapter");
2796
- }
3087
+ // src/challenges/owned-environment-lane.ts
3088
+ var APPROVED_FIXTURE_RE = /\b(turnstile-checkbox|recaptcha-v2-checkbox|1x00000000000000000000AA|6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI)\b/i;
3089
+ var runOwnedEnvironmentLane = (request) => {
3090
+ const haystack = [request.bundle.url, request.bundle.title, request.bundle.snapshotText].filter((value) => typeof value === "string" && value.length > 0).join(" ");
3091
+ const approved = APPROVED_FIXTURE_RE.test(haystack);
2797
3092
  return {
2798
- resolvedPolicy,
2799
- allowedActions: ALL_ACTIONS.filter((action) => allowed.has(action)),
2800
- forbiddenActions: ALL_ACTIONS.filter((action) => !allowed.has(action)),
2801
- handoffTriggers: [...DEFAULT_HANDOFF_TRIGGERS],
2802
- governedLanes,
2803
- optionalComputerUseBridge: helperEligibility.allowed,
2804
- helperEligibility
2805
- };
2806
- };
2807
-
2808
- // src/challenges/strategy-selector.ts
2809
- var buildDecision = (config, lane, rationale, allowedActionFamilies, verificationLevel, stopConditions, governedLane) => ({
2810
- lane,
2811
- ...governedLane ? { governedLane } : {},
2812
- rationale,
2813
- attemptBudget: config.attemptBudget,
2814
- noProgressLimit: config.noProgressLimit,
2815
- verificationLevel,
2816
- stopConditions,
2817
- allowedActionFamilies: [...allowedActionFamilies]
2818
- });
2819
- var selectChallengeStrategy = (args) => {
2820
- const { config, bundle, capabilityMatrix, gate, interpretation } = args;
2821
- const registryCooldownActive = (bundle.registryPressure?.cooldownUntilMs ?? 0) > Date.now();
2822
- const registryPressureElevated = (bundle.registryPressure?.activeChallenges ?? 0) > 0 || (bundle.registryPressure?.recentChallengeRatio ?? 0) >= 0.5 || (bundle.registryPressure?.recentRateLimitRatio ?? 0) >= 0.5;
2823
- const stopConditions = [
2824
- "manager_verification_clears_blocker",
2825
- "policy_gate_denies_next_action",
2826
- "human_boundary_detected",
2827
- "no_progress_budget_exhausted"
2828
- ];
2829
- const { mode, standDownReason } = gate.resolvedPolicy;
2830
- if (mode === "off") {
2831
- return buildDecision(
2832
- config,
2833
- "defer",
2834
- "Challenge automation mode is off; challenge handling is detect-and-report only.",
2835
- [],
2836
- "light",
2837
- [standDownReason ?? "challenge_automation_off"]
2838
- );
2839
- }
2840
- if (capabilityMatrix.mustDefer) {
2841
- return buildDecision(
2842
- config,
2843
- "defer",
2844
- "Current policy or blocker state requires deferral before further automation.",
2845
- gate.allowedActions,
2846
- interpretation.requiredVerification,
2847
- ["policy_blocked_or_clear_state"]
2848
- );
2849
- }
2850
- if (registryCooldownActive && !capabilityMatrix.canReuseExistingSession && !capabilityMatrix.canReuseCookies && !capabilityMatrix.canNavigateToAuth) {
2851
- return buildDecision(
2852
- config,
2853
- "defer",
2854
- "Registry cooldown is still active and no legitimate continuity or auth-navigation lane is currently available.",
2855
- gate.allowedActions,
2856
- interpretation.requiredVerification,
2857
- ["registry_cooldown_active"]
2858
- );
2859
- }
2860
- if (capabilityMatrix.canUseOwnedEnvironmentFixture) {
2861
- return buildDecision(
2862
- config,
2863
- "owned_environment_fixture",
2864
- "Owned-environment fixture detected and explicitly allowlisted.",
2865
- gate.allowedActions,
2866
- interpretation.requiredVerification,
2867
- stopConditions,
2868
- "owned_environment_fixture"
2869
- );
2870
- }
2871
- if (capabilityMatrix.mustYield) {
2872
- return buildDecision(
2873
- config,
2874
- "human_yield",
2875
- `Human authority boundary reached: ${interpretation.humanBoundary}.`,
2876
- gate.allowedActions,
2877
- interpretation.requiredVerification,
2878
- [...stopConditions, "human_authority_required"]
2879
- );
3093
+ status: approved ? "executed" : "blocked",
3094
+ lane: "owned_environment_fixture",
3095
+ reason: approved ? "Approved owned-environment fixture detected." : "Owned-environment lane requires an approved vendor test fixture.",
3096
+ auditMetadata: {
3097
+ approvedFixture: approved
3098
+ }
3099
+ };
3100
+ };
3101
+
3102
+ // src/challenges/sanctioned-identity-lane.ts
3103
+ var runSanctionedIdentityLane = (request) => {
3104
+ const entitlement = request.auditContext?.identityEntitlement;
3105
+ const approved = typeof entitlement === "string" && entitlement.trim().length > 0;
3106
+ return {
3107
+ status: approved ? "executed" : "blocked",
3108
+ lane: "sanctioned_identity",
3109
+ reason: approved ? "Sanctioned identity lane approved by explicit entitlement." : "Sanctioned identity lane requires explicit entitlement metadata.",
3110
+ auditMetadata: {
3111
+ approved,
3112
+ ...approved ? { entitlement } : {}
3113
+ }
3114
+ };
3115
+ };
3116
+
3117
+ // src/challenges/service-adapter-lane.ts
3118
+ var runServiceAdapterLane = (request) => {
3119
+ const adapter = request.auditContext?.adapterId;
3120
+ const approved = typeof adapter === "string" && adapter.trim().length > 0;
3121
+ return {
3122
+ status: approved ? "executed" : "blocked",
3123
+ lane: "service_adapter",
3124
+ reason: approved ? "Governed service adapter approved by explicit adapter metadata." : "Service-adapter lane requires an explicit adapter identifier and entitlement.",
3125
+ auditMetadata: {
3126
+ approved,
3127
+ ...approved ? { adapterId: adapter } : {}
3128
+ }
3129
+ };
3130
+ };
3131
+
3132
+ // src/challenges/governed-adapter-gateway.ts
3133
+ var evaluateGovernedLane = (config, request) => {
3134
+ if (config.mode === "off") {
3135
+ return {
3136
+ status: "blocked",
3137
+ lane: request.lane,
3138
+ reason: "Challenge automation mode is off.",
3139
+ auditMetadata: {}
3140
+ };
2880
3141
  }
2881
- if (capabilityMatrix.canNavigateToAuth || capabilityMatrix.canReuseExistingSession || capabilityMatrix.canReuseCookies || capabilityMatrix.canFillNonSecretFields || capabilityMatrix.canExploreClicks) {
2882
- return buildDecision(
2883
- config,
2884
- "generic_browser_autonomy",
2885
- registryPressureElevated ? "Registry pressure is elevated, but legitimate browser continuity remains available for one bounded generic autonomy pass." : "Existing browser controls can attempt bounded auth navigation, session reuse, non-secret fill, or interaction exploration.",
2886
- gate.allowedActions,
2887
- interpretation.requiredVerification,
2888
- registryPressureElevated ? [...stopConditions, "registry_pressure_elevated"] : stopConditions
2889
- );
3142
+ switch (request.lane) {
3143
+ case "owned_environment_fixture":
3144
+ if (!config.governed.allowOwnedEnvironmentFixtures) {
3145
+ return {
3146
+ status: "blocked",
3147
+ lane: request.lane,
3148
+ reason: "Owned-environment fixtures are disabled by policy.",
3149
+ auditMetadata: {}
3150
+ };
3151
+ }
3152
+ return runOwnedEnvironmentLane(request);
3153
+ case "sanctioned_identity":
3154
+ if (!config.governed.allowSanctionedIdentity) {
3155
+ return {
3156
+ status: "blocked",
3157
+ lane: request.lane,
3158
+ reason: "Sanctioned identity is disabled by policy.",
3159
+ auditMetadata: {}
3160
+ };
3161
+ }
3162
+ return runSanctionedIdentityLane(request);
3163
+ case "service_adapter":
3164
+ if (!config.governed.allowServiceAdapters) {
3165
+ return {
3166
+ status: "blocked",
3167
+ lane: request.lane,
3168
+ reason: "Service adapters are disabled by policy.",
3169
+ auditMetadata: {}
3170
+ };
3171
+ }
3172
+ return runServiceAdapterLane(request);
2890
3173
  }
2891
- if (capabilityMatrix.canUseComputerUseBridge) {
2892
- return buildDecision(
2893
- config,
2894
- "optional_computer_use_bridge",
2895
- "DOM-native autonomy is exhausted, but the optional browser-scoped bridge is enabled.",
2896
- gate.allowedActions,
2897
- interpretation.requiredVerification,
2898
- stopConditions
2899
- );
3174
+ };
3175
+
3176
+ // src/challenges/outcome-recorder.ts
3177
+ var MAX_RECORDS_PER_CHALLENGE = 25;
3178
+ var OutcomeRecorder = class {
3179
+ records = /* @__PURE__ */ new Map();
3180
+ record(record) {
3181
+ const key = record.challengeId ?? "__untracked__";
3182
+ const existing = this.records.get(key) ?? [];
3183
+ const next = [...existing, record].slice(-MAX_RECORDS_PER_CHALLENGE);
3184
+ this.records.set(key, next);
2900
3185
  }
2901
- if (capabilityMatrix.canUseSanctionedIdentity) {
2902
- return buildDecision(
2903
- config,
2904
- "sanctioned_identity",
2905
- "Sanctioned identity lane is enabled and generic browser autonomy is insufficient.",
2906
- gate.allowedActions,
2907
- interpretation.requiredVerification,
2908
- stopConditions,
2909
- "sanctioned_identity"
2910
- );
3186
+ latest(challengeId) {
3187
+ if (!challengeId) return void 0;
3188
+ const entries = this.records.get(challengeId);
3189
+ return entries?.[entries.length - 1];
2911
3190
  }
2912
- if (capabilityMatrix.canUseServiceAdapter) {
2913
- return buildDecision(
2914
- config,
2915
- "service_adapter",
2916
- "Governed service-adapter lane is enabled as the last non-human option.",
2917
- gate.allowedActions,
2918
- interpretation.requiredVerification,
2919
- stopConditions,
2920
- "service_adapter"
2921
- );
3191
+ read(challengeId) {
3192
+ if (!challengeId) return [];
3193
+ return [...this.records.get(challengeId) ?? []];
2922
3194
  }
2923
- return buildDecision(
2924
- config,
2925
- "human_yield",
2926
- `No legitimate autonomous lane remains after applying policy and continuity checks. ${capabilityMatrix.helperEligibility.reason}`,
2927
- gate.allowedActions,
2928
- interpretation.requiredVerification,
2929
- [...stopConditions, "no_legitimate_lane_remaining"]
2930
- );
2931
3195
  };
2932
3196
 
2933
3197
  // src/challenges/orchestrator.ts
@@ -2999,25 +3263,7 @@ var ChallengeOrchestrator = class {
2999
3263
  return this.recorder;
3000
3264
  }
3001
3265
  async captureEvidence(args) {
3002
- const status = await args.handle.status(args.sessionId);
3003
- const effectiveTargetId = status.activeTargetId ?? args.targetId ?? null;
3004
- const snapshot = await args.handle.snapshot(args.sessionId, "actionables", 2400, void 0, effectiveTargetId);
3005
- const debugTrace = await args.handle.debugTraceSnapshot(args.sessionId, { max: 50 });
3006
- const cookies = status.url ? await args.handle.cookieList(args.sessionId, [status.url]) : { count: 0 };
3007
- return buildChallengeEvidenceBundle({
3008
- status,
3009
- snapshot: {
3010
- snapshotId: snapshot.snapshotId,
3011
- content: snapshot.content,
3012
- warnings: snapshot.warnings
3013
- },
3014
- debugTrace,
3015
- cookieCount: cookies.count,
3016
- canImportCookies: args.canImportCookies,
3017
- fallbackDisposition: args.fallbackDisposition,
3018
- registryPressure: args.registryPressure,
3019
- taskData: args.taskData
3020
- });
3266
+ return captureChallengeEvidence(args);
3021
3267
  }
3022
3268
  async orchestrate(args) {
3023
3269
  const bundle = await this.captureEvidence({
@@ -3204,6 +3450,7 @@ var ChallengeOrchestrator = class {
3204
3450
  targetId: args.targetId,
3205
3451
  initialBundle: bundle,
3206
3452
  decision,
3453
+ helperEligibility: capabilityMatrix.helperEligibility,
3207
3454
  config: this.config,
3208
3455
  suggestedSteps
3209
3456
  });
@@ -3366,6 +3613,20 @@ var fallbackDispositionMessage = (fallback, url) => {
3366
3613
  var toProviderFallbackError = (args) => {
3367
3614
  const { fallback } = args;
3368
3615
  const reasonCode = fallback.reasonCode;
3616
+ const details = {
3617
+ 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
3628
+ });
3629
+ const guidance = hint ? buildProviderIssueGuidance({ provider: args.provider, hint, details }) : void 0;
3369
3630
  return new ProviderRuntimeError(
3370
3631
  providerErrorCodeFromReasonCode(reasonCode),
3371
3632
  fallbackDispositionMessage(fallback, args.url),
@@ -3374,15 +3635,7 @@ var toProviderFallbackError = (args) => {
3374
3635
  source: args.source,
3375
3636
  retryable: reasonCode === "rate_limited",
3376
3637
  reasonCode,
3377
- details: {
3378
- url: args.url,
3379
- disposition: fallback.disposition,
3380
- ...fallback.mode ? { browserFallbackMode: fallback.mode } : {},
3381
- ...fallback.challenge ? { challenge: toJsonRecord(fallback.challenge) } : {},
3382
- ...fallback.preservedSessionId ? { preservedSessionId: fallback.preservedSessionId } : {},
3383
- ...fallback.preservedTargetId ? { preservedTargetId: fallback.preservedTargetId } : {},
3384
- ...toJsonRecord(fallback.details ?? {})
3385
- }
3638
+ details: guidance ? { ...details, guidance } : details
3386
3639
  }
3387
3640
  );
3388
3641
  };
@@ -9173,7 +9426,7 @@ var isJsonRecord = (value) => typeof value === "object" && value !== null && !Ar
9173
9426
  var isWorkflowStage = (value) => value === "compile" || value === "execute" || value === "postprocess" || value === "resume";
9174
9427
  var isWorkflowCheckpoint = (value) => isJsonRecord(value) && isWorkflowStage(value.stage) && (value.stepId === void 0 || typeof value.stepId === "string") && (value.stepIndex === void 0 || typeof value.stepIndex === "number") && (value.state === void 0 || isJsonRecord(value.state)) && (value.updatedAt === void 0 || typeof value.updatedAt === "string");
9175
9428
  var isWorkflowTraceEntry = (value) => isJsonRecord(value) && typeof value.at === "string" && isWorkflowStage(value.stage) && typeof value.event === "string" && (value.details === void 0 || isJsonRecord(value.details));
9176
- var isWorkflowKind = (value) => value === "research" || value === "shopping" || value === "product_video";
9429
+ var isWorkflowKind = (value) => value === "research" || value === "shopping" || value === "product_video" || value === "inspiredesign";
9177
9430
  var buildWorkflowResumeEnvelope = (kind, input, options = {}) => ({
9178
9431
  kind,
9179
9432
  input,
@@ -9184,7 +9437,7 @@ var isWorkflowResumeEnvelope = (value) => isJsonRecord(value) && isWorkflowKind(
9184
9437
  var isWorkflowResumePayload = (value) => isJsonRecord(value) && isWorkflowResumeEnvelope(value.workflow);
9185
9438
 
9186
9439
  // src/providers/workflows.ts
9187
- import { createHash as createHash6 } from "crypto";
9440
+ import { createHash as createHash7 } from "crypto";
9188
9441
 
9189
9442
  // src/providers/artifacts.ts
9190
9443
  import { mkdir, readdir as readdir2, readFile, rm as rm2, stat, writeFile } from "fs/promises";
@@ -9503,11 +9756,111 @@ var compactResearchLines = (records, meta) => {
9503
9756
  return `${index + 1}. ${title} (${record.source}/${record.provider}) score=${record.confidence.toFixed(2)} engagement=${engagement}`;
9504
9757
  });
9505
9758
  };
9506
- var renderResearch = (args) => {
9507
- const lines = compactResearchLines(args.records, args.meta);
9508
- const summary = lines.join("\n");
9759
+ var renderResearch = (args) => {
9760
+ const lines = compactResearchLines(args.records, args.meta);
9761
+ const summary = lines.join("\n");
9762
+ const markdown = [
9763
+ `# Research: ${args.topic}`,
9764
+ "",
9765
+ ...lines,
9766
+ "",
9767
+ "## Metadata",
9768
+ "```json",
9769
+ JSON.stringify(args.meta, null, 2),
9770
+ "```"
9771
+ ].join("\n");
9772
+ const contextPayload = {
9773
+ topic: args.topic,
9774
+ highlights: lines,
9775
+ records: args.records,
9776
+ meta: args.meta
9777
+ };
9778
+ const files = [
9779
+ { path: "summary.md", content: markdown },
9780
+ { path: "records.json", content: { records: args.records } },
9781
+ { path: "context.json", content: contextPayload },
9782
+ { path: "meta.json", content: args.meta }
9783
+ ];
9784
+ if (args.mode === "compact") {
9785
+ return {
9786
+ response: {
9787
+ mode: args.mode,
9788
+ summary,
9789
+ meta: args.meta
9790
+ },
9791
+ files
9792
+ };
9793
+ }
9794
+ if (args.mode === "json") {
9795
+ return {
9796
+ response: {
9797
+ mode: args.mode,
9798
+ records: args.records,
9799
+ meta: args.meta
9800
+ },
9801
+ files
9802
+ };
9803
+ }
9804
+ if (args.mode === "md") {
9805
+ return {
9806
+ response: {
9807
+ mode: args.mode,
9808
+ markdown,
9809
+ meta: args.meta
9810
+ },
9811
+ files
9812
+ };
9813
+ }
9814
+ if (args.mode === "context") {
9815
+ return {
9816
+ response: {
9817
+ mode: args.mode,
9818
+ context: contextPayload,
9819
+ meta: args.meta
9820
+ },
9821
+ files
9822
+ };
9823
+ }
9824
+ return {
9825
+ response: {
9826
+ mode: "path",
9827
+ meta: args.meta
9828
+ },
9829
+ files
9830
+ };
9831
+ };
9832
+ var toComparisonCsv = (offers) => {
9833
+ const header = ["provider", "title", "price", "shipping", "deal_score", "availability", "url"].join(",");
9834
+ const rows = offers.map((offer) => {
9835
+ return [
9836
+ offer.provider,
9837
+ JSON.stringify(offer.title),
9838
+ offer.price.amount.toFixed(2),
9839
+ offer.shipping.amount.toFixed(2),
9840
+ offer.deal_score.toFixed(4),
9841
+ offer.availability,
9842
+ canonicalizeUrl(offer.url)
9843
+ ].join(",");
9844
+ });
9845
+ return [header, ...rows].join("\n");
9846
+ };
9847
+ var compactShoppingLines = (offers, meta) => {
9848
+ if (offers.length === 0) {
9849
+ const summary = primaryConstraintSummaryFromMeta(meta);
9850
+ return summary ? [
9851
+ "No offers available from the selected providers.",
9852
+ `Primary constraint: ${summary}`
9853
+ ] : ["No offers available from the selected providers."];
9854
+ }
9855
+ return offers.slice(0, 10).map((offer, index) => {
9856
+ const total = offer.price.amount + offer.shipping.amount;
9857
+ return `${index + 1}. ${offer.title} - ${toCurrency(total)} (${offer.provider}, deal=${offer.deal_score.toFixed(2)})`;
9858
+ });
9859
+ };
9860
+ var renderShopping = (args) => {
9861
+ const lines = compactShoppingLines(args.offers, args.meta);
9509
9862
  const markdown = [
9510
- `# Research: ${args.topic}`,
9863
+ `# Shopping: ${args.query}`,
9511
9864
  "",
9512
9865
  ...lines,
9513
9866
  "",
@@ -9516,23 +9869,25 @@ var renderResearch = (args) => {
9516
9869
  JSON.stringify(args.meta, null, 2),
9517
9870
  "```"
9518
9871
  ].join("\n");
9872
+ const comparisonCsv = toComparisonCsv(args.offers);
9519
9873
  const contextPayload = {
9520
- topic: args.topic,
9874
+ query: args.query,
9521
9875
  highlights: lines,
9522
- records: args.records,
9876
+ offers: args.offers,
9523
9877
  meta: args.meta
9524
9878
  };
9525
9879
  const files = [
9526
- { path: "summary.md", content: markdown },
9527
- { path: "records.json", content: { records: args.records } },
9528
- { path: "context.json", content: contextPayload },
9529
- { path: "meta.json", content: args.meta }
9880
+ { path: "deals.md", content: markdown },
9881
+ { path: "offers.json", content: { offers: args.offers } },
9882
+ { path: "comparison.csv", content: comparisonCsv },
9883
+ { path: "meta.json", content: args.meta },
9884
+ { path: "deals-context.json", content: contextPayload }
9530
9885
  ];
9531
9886
  if (args.mode === "compact") {
9532
9887
  return {
9533
9888
  response: {
9534
9889
  mode: args.mode,
9535
- summary,
9890
+ summary: lines.join("\n"),
9536
9891
  meta: args.meta
9537
9892
  },
9538
9893
  files
@@ -9542,7 +9897,7 @@ var renderResearch = (args) => {
9542
9897
  return {
9543
9898
  response: {
9544
9899
  mode: args.mode,
9545
- records: args.records,
9900
+ offers: args.offers,
9546
9901
  meta: args.meta
9547
9902
  },
9548
9903
  files
@@ -9576,111 +9931,1183 @@ var renderResearch = (args) => {
9576
9931
  files
9577
9932
  };
9578
9933
  };
9579
- var toComparisonCsv = (offers) => {
9580
- const header = ["provider", "title", "price", "shipping", "deal_score", "availability", "url"].join(",");
9581
- const rows = offers.map((offer) => {
9582
- return [
9583
- offer.provider,
9584
- JSON.stringify(offer.title),
9585
- offer.price.amount.toFixed(2),
9586
- offer.shipping.amount.toFixed(2),
9587
- offer.deal_score.toFixed(4),
9588
- offer.availability,
9589
- canonicalizeUrl(offer.url)
9590
- ].join(",");
9591
- });
9592
- return [header, ...rows].join("\n");
9934
+ var renderInspiredesign = (args) => {
9935
+ const summary = [
9936
+ `Brief: ${args.brief}`,
9937
+ `References: ${args.urls.length}`,
9938
+ `Profile: ${args.generationPlan.visualDirection.profile}`
9939
+ ].join("\n");
9940
+ const contextPayload = {
9941
+ brief: args.brief,
9942
+ urls: args.urls,
9943
+ designContract: args.designContract,
9944
+ generationPlan: args.generationPlan,
9945
+ implementationPlan: args.implementationPlan,
9946
+ designMarkdown: args.designMarkdown,
9947
+ implementationPlanMarkdown: args.implementationPlanMarkdown,
9948
+ prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
9949
+ evidence: args.evidence,
9950
+ meta: args.meta
9951
+ };
9952
+ const files = [
9953
+ { path: "design.md", content: args.designMarkdown },
9954
+ { path: "design-contract.json", content: args.designContract },
9955
+ { path: "generation-plan.json", content: args.generationPlan },
9956
+ { path: "implementation-plan.md", content: args.implementationPlanMarkdown },
9957
+ { path: "implementation-plan.json", content: args.implementationPlan },
9958
+ { path: "evidence.json", content: args.evidence }
9959
+ ];
9960
+ if (args.prototypeGuidanceMarkdown) {
9961
+ files.push({ path: "prototype-guidance.md", content: args.prototypeGuidanceMarkdown });
9962
+ }
9963
+ if (args.mode === "compact") {
9964
+ return {
9965
+ response: {
9966
+ mode: args.mode,
9967
+ summary,
9968
+ meta: args.meta
9969
+ },
9970
+ files
9971
+ };
9972
+ }
9973
+ if (args.mode === "json") {
9974
+ return {
9975
+ response: {
9976
+ mode: args.mode,
9977
+ brief: args.brief,
9978
+ urls: args.urls,
9979
+ designContract: args.designContract,
9980
+ generationPlan: args.generationPlan,
9981
+ implementationPlan: args.implementationPlan,
9982
+ prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
9983
+ evidence: args.evidence,
9984
+ meta: args.meta
9985
+ },
9986
+ files
9987
+ };
9988
+ }
9989
+ if (args.mode === "md") {
9990
+ return {
9991
+ response: {
9992
+ mode: args.mode,
9993
+ markdown: args.designMarkdown,
9994
+ implementationPlanMarkdown: args.implementationPlanMarkdown,
9995
+ prototypeGuidanceMarkdown: args.prototypeGuidanceMarkdown,
9996
+ meta: args.meta
9997
+ },
9998
+ files
9999
+ };
10000
+ }
10001
+ if (args.mode === "context") {
10002
+ return {
10003
+ response: {
10004
+ mode: args.mode,
10005
+ context: contextPayload,
10006
+ meta: args.meta
10007
+ },
10008
+ files
10009
+ };
10010
+ }
10011
+ return {
10012
+ response: {
10013
+ mode: "path",
10014
+ meta: args.meta
10015
+ },
10016
+ files
10017
+ };
9593
10018
  };
9594
- var compactShoppingLines = (offers, meta) => {
9595
- if (offers.length === 0) {
9596
- const summary = primaryConstraintSummaryFromMeta(meta);
9597
- return summary ? [
9598
- "No offers available from the selected providers.",
9599
- `Primary constraint: ${summary}`
9600
- ] : ["No offers available from the selected providers."];
10019
+
10020
+ // src/providers/inspiredesign-contract.ts
10021
+ import { createHash as createHash3 } from "crypto";
10022
+
10023
+ // skills/opendevbrowser-design-agent/assets/templates/canvas-generation-plan.design.v1.json
10024
+ var canvas_generation_plan_design_v1_default = {
10025
+ requestId: "req_plan_design_01",
10026
+ canvasSessionId: "<canvas-session-id>",
10027
+ leaseId: "<lease-id>",
10028
+ documentId: "<document-id>",
10029
+ generationPlan: {
10030
+ targetOutcome: {
10031
+ mode: "high-fi-live-edit",
10032
+ summary: "Clarify hierarchy, trust, and action flow"
10033
+ },
10034
+ visualDirection: {
10035
+ profile: "product-story",
10036
+ themeStrategy: "single-theme"
10037
+ },
10038
+ layoutStrategy: {
10039
+ approach: "hero-led-grid",
10040
+ navigationModel: "global-header"
10041
+ },
10042
+ contentStrategy: {
10043
+ source: "real-content-first"
10044
+ },
10045
+ componentStrategy: {
10046
+ mode: "reuse-first",
10047
+ interactionStates: [
10048
+ "default",
10049
+ "hover",
10050
+ "focus",
10051
+ "disabled"
10052
+ ]
10053
+ },
10054
+ motionPosture: {
10055
+ level: "subtle",
10056
+ reducedMotion: "respect-user-preference"
10057
+ },
10058
+ responsivePosture: {
10059
+ primaryViewport: "desktop",
10060
+ requiredViewports: [
10061
+ "desktop",
10062
+ "tablet",
10063
+ "mobile"
10064
+ ]
10065
+ },
10066
+ accessibilityPosture: {
10067
+ target: "WCAG_2_2_AA",
10068
+ keyboardNavigation: "full"
10069
+ },
10070
+ validationTargets: {
10071
+ blockOn: [
10072
+ "contrast-failure",
10073
+ "responsive-mismatch"
10074
+ ],
10075
+ requiredThemes: [
10076
+ "light"
10077
+ ],
10078
+ browserValidation: "required",
10079
+ maxInteractionLatencyMs: 160
10080
+ }
9601
10081
  }
9602
- return offers.slice(0, 10).map((offer, index) => {
9603
- const total = offer.price.amount + offer.shipping.amount;
9604
- return `${index + 1}. ${offer.title} - ${toCurrency(total)} (${offer.provider}, deal=${offer.deal_score.toFixed(2)})`;
9605
- });
9606
10082
  };
9607
- var renderShopping = (args) => {
9608
- const lines = compactShoppingLines(args.offers, args.meta);
9609
- const markdown = [
9610
- `# Shopping: ${args.query}`,
10083
+
10084
+ // skills/opendevbrowser-design-agent/assets/templates/design-contract.v1.json
10085
+ var design_contract_v1_default = {
10086
+ intent: {
10087
+ audience: "Operators evaluating a new OpenDevBrowser design flow",
10088
+ task: "Understand the primary page value and complete the intended action quickly",
10089
+ successCriteria: [
10090
+ "Primary action is obvious within 5 seconds",
10091
+ "Layout remains coherent on desktop, tablet, and mobile"
10092
+ ],
10093
+ trustPosture: "clear and confident"
10094
+ },
10095
+ designLanguage: {
10096
+ direction: "product-led clarity",
10097
+ styleAxes: {
10098
+ contrast: "high",
10099
+ density: "airy",
10100
+ shapeLanguage: "rounded-structured",
10101
+ depth: "subtle",
10102
+ texture: "minimal",
10103
+ motion: "purposeful"
10104
+ },
10105
+ approvedLibraries: {
10106
+ components: [
10107
+ "shadcn"
10108
+ ],
10109
+ icons: [
10110
+ "tabler"
10111
+ ],
10112
+ styling: [
10113
+ "tailwindcss"
10114
+ ]
10115
+ },
10116
+ semanticTokenSource: {
10117
+ owner: "app-shell theme provider",
10118
+ tokens: [
10119
+ "color",
10120
+ "typography",
10121
+ "spacing",
10122
+ "radius",
10123
+ "shadow",
10124
+ "motion"
10125
+ ],
10126
+ rule: "Use semantic tokens in repeated UI; reserve raw values for rare one-off illustration"
10127
+ }
10128
+ },
10129
+ contentModel: {
10130
+ primaryMessage: "Show the core value immediately with real copy",
10131
+ supportingMessages: [
10132
+ "Reinforce trust",
10133
+ "Clarify the primary action",
10134
+ "Reduce ambiguity"
10135
+ ],
10136
+ realContentRequired: true,
10137
+ states: [
10138
+ "default",
10139
+ "hover",
10140
+ "focus",
10141
+ "empty",
10142
+ "loading",
10143
+ "success",
10144
+ "error"
10145
+ ],
10146
+ loadingStrategy: "Preserve the final layout with 3-6 placeholders or one section-level loader when structure cannot be previewed",
10147
+ emptyStateStrategy: "Explain why nothing is shown and provide the next useful action",
10148
+ errorStateStrategy: "Keep retry or recovery actions close to the failed region",
10149
+ transientFeedbackStrategy: "Use short, non-blocking overlays for confirmations instead of reflowing the main layout",
10150
+ avoidPlaceholderCopy: true
10151
+ },
10152
+ navigationModel: {
10153
+ owner: "feature shell route controller",
10154
+ primaryRouteModel: "One canonical route map translates tabs, selected records, and editor modes into URL-backed state",
10155
+ deepLinkPolicy: "Shareable tabs, filters, sort, and selected entities stay in the URL with a safe fallback when params are stale or incomplete",
10156
+ invalidRouteFallback: "Recover to the closest safe baseline view instead of leaving the screen in a partially initialized state",
10157
+ overlayEntryPoints: [
10158
+ "route-owned detail drawer",
10159
+ "feature-owned confirmation modal"
10160
+ ]
10161
+ },
10162
+ asyncModel: {
10163
+ owner: "feature-local controller with URL-owned query state when sharing or refresh matters",
10164
+ loadTrigger: "load-on-enter for the first view; debounced restart on query, scope, or sort change",
10165
+ restartTriggers: [
10166
+ "query",
10167
+ "scope",
10168
+ "sort"
10169
+ ],
10170
+ debounceMs: 250,
10171
+ emptyQueryBehavior: "Reset to the baseline or empty state without a remote fetch unless the product explicitly needs default results",
10172
+ cancellationPolicy: "Treat stale requests as normal and do not surface cancellation as a user-facing error",
10173
+ moveToServiceWhen: [
10174
+ "work must survive dismissal",
10175
+ "caching or retry policy becomes shared",
10176
+ "multiple screens depend on the same in-flight state"
10177
+ ],
10178
+ urlOwnership: "Put query, filter, and sort in the URL when the state should survive refresh, sharing, or handoff"
10179
+ },
10180
+ layoutSystem: {
10181
+ grid: "12-column responsive grid",
10182
+ containers: "max-width sections with asymmetric emphasis",
10183
+ spacingRhythm: "8px base with larger section jumps",
10184
+ alignmentRules: [
10185
+ "Primary content aligns to a consistent reading column",
10186
+ "Actions stay near the message they complete"
10187
+ ]
10188
+ },
10189
+ typographySystem: {
10190
+ families: [
10191
+ "Space Grotesk",
10192
+ "Source Sans 3"
10193
+ ],
10194
+ scale: [
10195
+ "12",
10196
+ "14",
10197
+ "16",
10198
+ "20",
10199
+ "28",
10200
+ "40",
10201
+ "56"
10202
+ ],
10203
+ measure: "60-72 characters for dense reading blocks",
10204
+ fallbackPolicy: "Use repo-native or licensed alternatives when these families are unavailable",
10205
+ loadingStrategy: "Avoid layout shift and keep fallback metrics close"
10206
+ },
10207
+ motionSystem: {
10208
+ timing: "short and decisive",
10209
+ reducedMotionPolicy: "Preserve meaning with reduced movement",
10210
+ interactionMoments: [
10211
+ "page entry",
10212
+ "section reveal",
10213
+ "primary CTA feedback"
10214
+ ],
10215
+ parallaxPolicy: "off unless explicitly justified"
10216
+ },
10217
+ performanceModel: {
10218
+ renderHotspots: [
10219
+ "scan-heavy collection region",
10220
+ "secondary inspector or preview pane"
10221
+ ],
10222
+ stableIdentityPolicy: "Rows, cards, tabs, and overlays use stable domain ids instead of array indexes",
10223
+ listStrategy: "Use the smallest structure that stays fast with realistic data; choose progressive reveal, lazy containers, or virtualization deliberately",
10224
+ secondaryPanelPolicy: "Heavy inspectors, previews, and editors load on demand when they are not required for first paint",
10225
+ measurementPlan: "Validate realistic data volume with browser traces and the framework profiler before claiming the surface is performant"
10226
+ },
10227
+ responsiveSystem: {
10228
+ breakpoints: [
10229
+ "mobile",
10230
+ "tablet",
10231
+ "desktop"
10232
+ ],
10233
+ adaptationRules: [
10234
+ "Collapse multicolumn sections before copy becomes cramped",
10235
+ "Preserve primary CTA prominence on the smallest viewport"
10236
+ ],
10237
+ touchPolicy: "Comfortable targets and low-friction scroll paths",
10238
+ overflowPolicy: "No horizontal scroll for primary content"
10239
+ },
10240
+ accessibilityPolicy: {
10241
+ target: "WCAG 2.2 AA",
10242
+ keyboardRequirements: [
10243
+ "Visible focus",
10244
+ "Logical tab order"
10245
+ ],
10246
+ focusPolicy: "Focus rings must remain visible against every background",
10247
+ semanticRequirements: [
10248
+ "Landmarks are explicit",
10249
+ "Headings remain hierarchical"
10250
+ ]
10251
+ },
10252
+ generationPlan: {
10253
+ targetOutcome: {
10254
+ mode: "high-fi-live-edit",
10255
+ summary: "Improve hierarchy, clarity, and conversion confidence"
10256
+ },
10257
+ visualDirection: {
10258
+ profile: "product-led-clarity",
10259
+ styleAxes: {
10260
+ contrast: "high",
10261
+ density: "airy"
10262
+ }
10263
+ },
10264
+ layoutStrategy: {
10265
+ approach: "hero-led-grid"
10266
+ },
10267
+ contentStrategy: {
10268
+ source: "real-content-first"
10269
+ },
10270
+ componentStrategy: {
10271
+ mode: "reuse-first",
10272
+ approvedLibraries: [
10273
+ "shadcn"
10274
+ ]
10275
+ },
10276
+ motionPosture: {
10277
+ level: "subtle",
10278
+ allow3D: false,
10279
+ allowParallax: false,
10280
+ allowCustomSmoothScroll: false
10281
+ },
10282
+ responsivePosture: {
10283
+ primaryViewport: "desktop",
10284
+ requiredViewports: [
10285
+ "desktop",
10286
+ "tablet",
10287
+ "mobile"
10288
+ ]
10289
+ },
10290
+ accessibilityPosture: {
10291
+ target: "WCAG_2_2_AA",
10292
+ reducedMotion: "required",
10293
+ keyboardParity: true
10294
+ },
10295
+ validationTargets: {
10296
+ blockOn: [
10297
+ "contrast-failure",
10298
+ "keyboard-regression",
10299
+ "stale-search-results",
10300
+ "invalid-route-recovery-failure"
10301
+ ],
10302
+ warnOn: [
10303
+ "responsive-mismatch",
10304
+ "layout-shift",
10305
+ "spinner-stacking",
10306
+ "scan-surface-jank"
10307
+ ]
10308
+ }
10309
+ }
10310
+ };
10311
+
10312
+ // src/providers/inspiredesign-contract.ts
10313
+ var BASE_CONTRACT_TEMPLATE = design_contract_v1_default;
10314
+ var BASE_GENERATION_PLAN = canvas_generation_plan_design_v1_default.generationPlan;
10315
+ var PROFILE_MATCHERS = [
10316
+ { profile: "auth-focused", keywords: ["auth", "login", "signin", "sign-in", "signup", "sign-up", "onboarding"] },
10317
+ { profile: "settings-system", keywords: ["settings", "preferences", "account", "profile", "billing"] },
10318
+ { profile: "ops-control", keywords: ["dashboard", "admin", "control", "analytics", "monitor", "reporting"] },
10319
+ { profile: "documentation", keywords: ["docs", "documentation", "knowledge base", "reference", "guide"] },
10320
+ { profile: "commerce-system", keywords: ["shop", "commerce", "pricing", "checkout", "product page", "catalog"] }
10321
+ ];
10322
+ var PROFILE_CONFIG = {
10323
+ "clean-room": {
10324
+ direction: "clean-room execution",
10325
+ visualPersonality: "disciplined, quiet, system-first",
10326
+ brandTone: "neutral and exacting",
10327
+ hierarchyPrinciples: ["Keep one message per section.", "Use spacing, not ornament, to separate priority."],
10328
+ interactionPhilosophy: "Minimal motion, zero ambiguity, strong focus affordances.",
10329
+ navigationModel: "contextual",
10330
+ layoutApproach: "modular-grid",
10331
+ pagePatterns: ["Single-message hero", "Dense decision panel", "Clean spec sheet"],
10332
+ componentSequence: ["Buttons", "Inputs", "Decision cards", "Structured tables"],
10333
+ colors: {
10334
+ primary: "#0F172A",
10335
+ accent: "#0F766E",
10336
+ accentSurface: "#E6FFFB",
10337
+ background: "#F8FAFC",
10338
+ surface: "#FFFFFF",
10339
+ border: "#CBD5E1",
10340
+ text: "#0F172A",
10341
+ mutedText: "#475569",
10342
+ success: "#15803D",
10343
+ warning: "#B45309",
10344
+ danger: "#B91C1C"
10345
+ }
10346
+ },
10347
+ "cinematic-minimal": {
10348
+ direction: "cinematic restraint",
10349
+ visualPersonality: "dramatic, sparse, image-led",
10350
+ brandTone: "premium and deliberate",
10351
+ hierarchyPrinciples: ["Let the visual plane carry atmosphere.", "Keep copy short and decisive."],
10352
+ interactionPhilosophy: "Use motion for presence, not explanation.",
10353
+ navigationModel: "immersive",
10354
+ layoutApproach: "full-bleed-hero",
10355
+ pagePatterns: ["Full-bleed hero", "Editorial feature strip", "High-contrast CTA block"],
10356
+ componentSequence: ["Hero shell", "CTA buttons", "Image-led sections", "Minimal footer"],
10357
+ colors: {
10358
+ primary: "#111827",
10359
+ accent: "#C2410C",
10360
+ accentSurface: "#FFF7ED",
10361
+ background: "#F8F5F0",
10362
+ surface: "#FFFFFF",
10363
+ border: "#D6D3D1",
10364
+ text: "#111827",
10365
+ mutedText: "#57534E",
10366
+ success: "#15803D",
10367
+ warning: "#B45309",
10368
+ danger: "#B91C1C"
10369
+ }
10370
+ },
10371
+ "product-story": {
10372
+ direction: "product-led clarity",
10373
+ visualPersonality: "confident, editorial, product-first",
10374
+ brandTone: "clear and ambitious",
10375
+ hierarchyPrinciples: ["Lead with value before proof.", "Keep action close to the message it completes."],
10376
+ interactionPhilosophy: "Short, decisive motion with obvious focus states.",
10377
+ navigationModel: "global-header",
10378
+ layoutApproach: "hero-led-grid",
10379
+ pagePatterns: ["Hero with anchored CTA", "Feature narrative strip", "Proof and conversion band"],
10380
+ componentSequence: ["Hero", "Buttons", "Cards", "Feature sections", "Footer"],
10381
+ colors: {
10382
+ primary: "#0B6BFF",
10383
+ accent: "#F97316",
10384
+ accentSurface: "#FFF7ED",
10385
+ background: "#F5F7FB",
10386
+ surface: "#FFFFFF",
10387
+ border: "#D7E3F4",
10388
+ text: "#111827",
10389
+ mutedText: "#475569",
10390
+ success: "#15803D",
10391
+ warning: "#B45309",
10392
+ danger: "#B91C1C"
10393
+ }
10394
+ },
10395
+ "commerce-system": {
10396
+ direction: "trust-driven commerce",
10397
+ visualPersonality: "decisive, reassuring, conversion-aware",
10398
+ brandTone: "credible and practical",
10399
+ hierarchyPrinciples: ["Keep purchasing signals scannable.", "Surface trust proof before commitment moments."],
10400
+ interactionPhilosophy: "Fast feedback, strong affordances, no ambiguous states.",
10401
+ navigationModel: "global-header",
10402
+ layoutApproach: "commerce-grid",
10403
+ pagePatterns: ["Merchandising hero", "Offer comparison band", "Decision-support detail section"],
10404
+ componentSequence: ["Hero", "Offer cards", "Buttons", "Trust badges", "Comparison table"],
10405
+ colors: {
10406
+ primary: "#0F766E",
10407
+ accent: "#D97706",
10408
+ accentSurface: "#FFFBEB",
10409
+ background: "#F8FAFC",
10410
+ surface: "#FFFFFF",
10411
+ border: "#D1D5DB",
10412
+ text: "#111827",
10413
+ mutedText: "#4B5563",
10414
+ success: "#15803D",
10415
+ warning: "#B45309",
10416
+ danger: "#B91C1C"
10417
+ }
10418
+ },
10419
+ "control-room": {
10420
+ direction: "high-signal control room",
10421
+ visualPersonality: "dense, sharp, operational",
10422
+ brandTone: "authoritative and fast",
10423
+ hierarchyPrinciples: ["Use structure to reduce scanning cost.", "Separate primary metrics from diagnostics."],
10424
+ interactionPhilosophy: "Fast updates, explicit states, motion only when it clarifies change.",
10425
+ navigationModel: "sidebar",
10426
+ layoutApproach: "panel-grid",
10427
+ pagePatterns: ["Metric summary rail", "Split-pane workspace", "Diagnostic detail panel"],
10428
+ componentSequence: ["Sidebar", "Stat blocks", "Tables", "Filters", "Panels"],
10429
+ colors: {
10430
+ primary: "#155EEF",
10431
+ accent: "#0F766E",
10432
+ accentSurface: "#ECFDF3",
10433
+ background: "#F8FAFC",
10434
+ surface: "#FFFFFF",
10435
+ border: "#CBD5E1",
10436
+ text: "#0F172A",
10437
+ mutedText: "#475569",
10438
+ success: "#15803D",
10439
+ warning: "#B45309",
10440
+ danger: "#B91C1C"
10441
+ }
10442
+ },
10443
+ "ops-control": {
10444
+ direction: "operational precision",
10445
+ visualPersonality: "structured, dense, high-confidence",
10446
+ brandTone: "decisive and exact",
10447
+ hierarchyPrinciples: ["Pin the primary metric and action path.", "Separate overview from detail panes."],
10448
+ interactionPhilosophy: "Low-latency controls, strong state contrast, keyboard-friendly flows.",
10449
+ navigationModel: "sidebar",
10450
+ layoutApproach: "workspace-shell",
10451
+ pagePatterns: ["KPI overview bar", "Filterable data shell", "Detail drawer or inspector"],
10452
+ componentSequence: ["Sidebar", "Toolbar", "Data table", "Filters", "Detail panel"],
10453
+ colors: {
10454
+ primary: "#155EEF",
10455
+ accent: "#0891B2",
10456
+ accentSurface: "#ECFEFF",
10457
+ background: "#F8FAFC",
10458
+ surface: "#FFFFFF",
10459
+ border: "#CBD5E1",
10460
+ text: "#0F172A",
10461
+ mutedText: "#475569",
10462
+ success: "#15803D",
10463
+ warning: "#B45309",
10464
+ danger: "#B91C1C"
10465
+ }
10466
+ },
10467
+ "auth-focused": {
10468
+ direction: "trust-forward entry flow",
10469
+ visualPersonality: "calm, direct, reassuring",
10470
+ brandTone: "safe and premium",
10471
+ hierarchyPrinciples: ["One job per screen.", "Trust and recovery paths must be visible without clutter."],
10472
+ interactionPhilosophy: "Low-friction focus flow with immediate validation feedback.",
10473
+ navigationModel: "contextual",
10474
+ layoutApproach: "two-panel-auth",
10475
+ pagePatterns: ["Auth split layout", "Trust panel", "Recovery and help strip"],
10476
+ componentSequence: ["Auth form", "Inputs", "Buttons", "Alerts", "Trust panel"],
10477
+ colors: {
10478
+ primary: "#1D4ED8",
10479
+ accent: "#0F766E",
10480
+ accentSurface: "#ECFDF5",
10481
+ background: "#F8FAFC",
10482
+ surface: "#FFFFFF",
10483
+ border: "#D1D5DB",
10484
+ text: "#111827",
10485
+ mutedText: "#4B5563",
10486
+ success: "#15803D",
10487
+ warning: "#B45309",
10488
+ danger: "#B91C1C"
10489
+ }
10490
+ },
10491
+ "settings-system": {
10492
+ direction: "calm settings system",
10493
+ visualPersonality: "ordered, practical, quietly premium",
10494
+ brandTone: "confident and low-friction",
10495
+ hierarchyPrinciples: ["Group related decisions tightly.", "Keep destructive actions isolated and explicit."],
10496
+ interactionPhilosophy: "Prefer clear toggles and inline explanations over hidden complexity.",
10497
+ navigationModel: "tabbed",
10498
+ layoutApproach: "settings-grid",
10499
+ pagePatterns: ["Sectioned settings page", "Inline form groups", "Preference summary rail"],
10500
+ componentSequence: ["Tabs", "Forms", "Inputs", "Alerts", "Confirmation modal"],
10501
+ colors: {
10502
+ primary: "#1D4ED8",
10503
+ accent: "#0F766E",
10504
+ accentSurface: "#ECFDF5",
10505
+ background: "#F8FAFC",
10506
+ surface: "#FFFFFF",
10507
+ border: "#D1D5DB",
10508
+ text: "#111827",
10509
+ mutedText: "#475569",
10510
+ success: "#15803D",
10511
+ warning: "#B45309",
10512
+ danger: "#B91C1C"
10513
+ }
10514
+ },
10515
+ "documentation": {
10516
+ direction: "reference-first documentation",
10517
+ visualPersonality: "legible, calm, highly structured",
10518
+ brandTone: "expert and accessible",
10519
+ hierarchyPrinciples: ["Make scanning effortless.", "Keep code, steps, and warnings visually distinct."],
10520
+ interactionPhilosophy: "Light motion, sticky wayfinding, strong anchor visibility.",
10521
+ navigationModel: "sidebar",
10522
+ layoutApproach: "docs-shell",
10523
+ pagePatterns: ["Docs shell", "Procedure section", "Reference table block"],
10524
+ componentSequence: ["Sidebar", "Search", "Anchored headings", "Code blocks", "Callouts"],
10525
+ colors: {
10526
+ primary: "#1D4ED8",
10527
+ accent: "#0F766E",
10528
+ accentSurface: "#ECFDF5",
10529
+ background: "#F8FAFC",
10530
+ surface: "#FFFFFF",
10531
+ border: "#CBD5E1",
10532
+ text: "#0F172A",
10533
+ mutedText: "#475569",
10534
+ success: "#15803D",
10535
+ warning: "#B45309",
10536
+ danger: "#B91C1C"
10537
+ }
10538
+ }
10539
+ };
10540
+ var trimText = (value) => {
10541
+ return value.trim().replace(/\s+/g, " ");
10542
+ };
10543
+ var clipText = (value, maxLength) => {
10544
+ if (value.length <= maxLength) return value;
10545
+ return `${value.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;
10546
+ };
10547
+ var cloneTemplate = (value) => structuredClone(value);
10548
+ var referenceFingerprint = (value) => {
10549
+ return createHash3("sha256").update(value).digest("hex").slice(0, 12);
10550
+ };
10551
+ var hasKeyword = (value, keywords) => {
10552
+ const haystack = value.toLowerCase();
10553
+ return keywords.some((keyword) => haystack.includes(keyword));
10554
+ };
10555
+ var classifyProfile = (brief, references) => {
10556
+ const combined = [brief, ...references.map((reference) => `${reference.title ?? ""} ${reference.excerpt ?? ""}`)].join(" ").toLowerCase();
10557
+ return PROFILE_MATCHERS.find((matcher) => hasKeyword(combined, matcher.keywords))?.profile ?? "product-story";
10558
+ };
10559
+ var resolveThemeStrategy = (brief, references) => {
10560
+ const combined = `${brief} ${references.map((reference) => reference.excerpt ?? "").join(" ")}`.toLowerCase();
10561
+ return combined.includes("dark") ? "light-dark-parity" : "single-theme";
10562
+ };
10563
+ var summarizeBrief = (brief) => {
10564
+ const normalized = trimText(brief);
10565
+ const sentence = normalized.split(/[.!?]/).map((part) => part.trim()).find(Boolean);
10566
+ return clipText(sentence ?? normalized, 140);
10567
+ };
10568
+ var buildSupportingMessages = (references) => {
10569
+ const messages = references.map((reference) => reference.title ?? reference.excerpt ?? "").map((value) => clipText(trimText(value), 72)).filter((value) => value.length > 0);
10570
+ return messages.slice(0, 3);
10571
+ };
10572
+ var buildGenerationPlan = (brief, profile, references) => {
10573
+ const plan = cloneTemplate(BASE_GENERATION_PLAN);
10574
+ plan.targetOutcome.summary = summarizeBrief(brief);
10575
+ plan.visualDirection.profile = profile;
10576
+ plan.visualDirection.themeStrategy = resolveThemeStrategy(brief, references);
10577
+ plan.layoutStrategy.approach = PROFILE_CONFIG[profile].layoutApproach;
10578
+ plan.layoutStrategy.navigationModel = PROFILE_CONFIG[profile].navigationModel;
10579
+ plan.componentStrategy.interactionStates = ["default", "hover", "focus", "disabled", "loading"];
10580
+ plan.validationTargets.requiredThemes = plan.visualDirection.themeStrategy === "light-dark-parity" ? ["light", "dark"] : ["light"];
10581
+ return plan;
10582
+ };
10583
+ var buildIntentBlock = (brief, urls, references) => {
10584
+ const intent = cloneTemplate(BASE_CONTRACT_TEMPLATE.intent);
10585
+ return {
10586
+ ...intent,
10587
+ task: summarizeBrief(brief),
10588
+ brief,
10589
+ briefHash: referenceFingerprint(brief),
10590
+ referenceCount: references.length,
10591
+ referenceUrls: urls,
10592
+ evidenceStatus: {
10593
+ fetched: references.filter((reference) => reference.fetchStatus === "captured").length,
10594
+ captured: references.filter((reference) => reference.captureStatus === "captured").length
10595
+ }
10596
+ };
10597
+ };
10598
+ var buildDesignLanguageBlock = (profile) => {
10599
+ const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.designLanguage);
10600
+ const config = PROFILE_CONFIG[profile];
10601
+ return {
10602
+ ...block,
10603
+ direction: config.direction,
10604
+ visualPersonality: config.visualPersonality,
10605
+ brandTone: config.brandTone
10606
+ };
10607
+ };
10608
+ var buildContentModelBlock = (brief, references) => {
10609
+ const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.contentModel);
10610
+ return {
10611
+ ...block,
10612
+ primaryMessage: summarizeBrief(brief),
10613
+ supportingMessages: buildSupportingMessages(references)
10614
+ };
10615
+ };
10616
+ var buildLayoutSystemBlock = (profile) => {
10617
+ const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.layoutSystem);
10618
+ return {
10619
+ ...block,
10620
+ pagePatterns: PROFILE_CONFIG[profile].pagePatterns
10621
+ };
10622
+ };
10623
+ var buildTypographySystemBlock = () => {
10624
+ const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.typographySystem);
10625
+ return {
10626
+ ...block,
10627
+ tokens: {
10628
+ display: "56/1.0",
10629
+ h1: "40/1.05",
10630
+ h2: "28/1.1",
10631
+ h3: "20/1.2",
10632
+ body: "16/1.6",
10633
+ label: "14/1.4",
10634
+ caption: "12/1.4"
10635
+ }
10636
+ };
10637
+ };
10638
+ var buildColorSystemBlock = (profile) => {
10639
+ const colors = PROFILE_CONFIG[profile].colors;
10640
+ return {
10641
+ paletteName: `${profile}-default`,
10642
+ tokens: colors,
10643
+ contrastRequirements: {
10644
+ bodyText: "4.5:1",
10645
+ largeText: "3:1",
10646
+ focusRing: "3:1"
10647
+ }
10648
+ };
10649
+ };
10650
+ var buildSurfaceSystemBlock = () => ({
10651
+ radiusScale: {
10652
+ xs: "6px",
10653
+ sm: "10px",
10654
+ md: "16px",
10655
+ lg: "24px"
10656
+ },
10657
+ borderPolicy: "Use 1px neutral strokes before adding elevation.",
10658
+ shadowPolicy: {
10659
+ sm: "0 1px 2px rgba(15, 23, 42, 0.06)",
10660
+ md: "0 10px 30px rgba(15, 23, 42, 0.10)",
10661
+ lg: "0 24px 60px rgba(15, 23, 42, 0.14)"
10662
+ }
10663
+ });
10664
+ var buildIconSystemBlock = () => ({
10665
+ family: "tabler",
10666
+ strokeWidth: 1.5,
10667
+ style: "rounded-linear",
10668
+ usageRules: [
10669
+ "Use icons to reinforce labels, not replace them.",
10670
+ "Decorative icons should remain visually lighter than primary copy."
10671
+ ]
10672
+ });
10673
+ var buildMotionSystemBlock = () => {
10674
+ const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.motionSystem);
10675
+ return {
10676
+ ...block,
10677
+ durations: {
10678
+ quick: "120ms",
10679
+ standard: "180ms",
10680
+ emphasis: "240ms"
10681
+ }
10682
+ };
10683
+ };
10684
+ var buildResponsiveSystemBlock = () => {
10685
+ const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.responsiveSystem);
10686
+ return {
10687
+ ...block,
10688
+ breakpoints: {
10689
+ mobile: "0-639px",
10690
+ tablet: "640-1023px",
10691
+ desktop: "1024px+"
10692
+ }
10693
+ };
10694
+ };
10695
+ var buildAccessibilityBlock = () => {
10696
+ const block = cloneTemplate(BASE_CONTRACT_TEMPLATE.accessibilityPolicy);
10697
+ return {
10698
+ ...block,
10699
+ reducedMotion: "Respect user preference and preserve information without animation."
10700
+ };
10701
+ };
10702
+ var buildLibraryPolicyBlock = () => ({
10703
+ components: ["shadcn"],
10704
+ icons: ["tabler"],
10705
+ styling: ["tailwindcss"],
10706
+ motion: ["css"],
10707
+ threeD: []
10708
+ });
10709
+ var buildRuntimeBudgetsBlock = (plan) => ({
10710
+ maxHeroActions: 2,
10711
+ maxPrimarySections: 8,
10712
+ maxInteractionLatencyMs: plan.validationTargets.maxInteractionLatencyMs,
10713
+ previewBudgetMs: 1500,
10714
+ notes: [
10715
+ "Keep above-the-fold content inside one visual composition.",
10716
+ "Avoid heavyweight decorative animation before interaction clarity is established."
10717
+ ]
10718
+ });
10719
+ var buildDesignContract = (brief, urls, references, plan) => ({
10720
+ intent: buildIntentBlock(brief, urls, references),
10721
+ generationPlan: plan,
10722
+ designLanguage: buildDesignLanguageBlock(plan.visualDirection.profile),
10723
+ contentModel: buildContentModelBlock(brief, references),
10724
+ layoutSystem: buildLayoutSystemBlock(plan.visualDirection.profile),
10725
+ typographySystem: buildTypographySystemBlock(),
10726
+ colorSystem: buildColorSystemBlock(plan.visualDirection.profile),
10727
+ surfaceSystem: buildSurfaceSystemBlock(),
10728
+ iconSystem: buildIconSystemBlock(),
10729
+ motionSystem: buildMotionSystemBlock(),
10730
+ responsiveSystem: buildResponsiveSystemBlock(),
10731
+ accessibilityPolicy: buildAccessibilityBlock(),
10732
+ libraryPolicy: buildLibraryPolicyBlock(),
10733
+ runtimeBudgets: buildRuntimeBudgetsBlock(plan)
10734
+ });
10735
+ var buildTokenStrategy = (profile) => ({
10736
+ colors: PROFILE_CONFIG[profile].colors,
10737
+ typography: {
10738
+ display: "font-display text-[56px] leading-[1.0]",
10739
+ h1: "font-display text-[40px] leading-[1.05]",
10740
+ h2: "font-display text-[28px] leading-[1.1]",
10741
+ h3: "font-display text-[20px] leading-[1.2]",
10742
+ body: "font-body text-[16px] leading-[1.6]",
10743
+ label: "font-body text-[14px] leading-[1.4]",
10744
+ caption: "font-body text-[12px] leading-[1.4]"
10745
+ },
10746
+ spacing: {
10747
+ xs: "4px",
10748
+ sm: "8px",
10749
+ md: "16px",
10750
+ lg: "24px",
10751
+ xl: "40px",
10752
+ section: "96px"
10753
+ },
10754
+ radius: {
10755
+ xs: "6px",
10756
+ sm: "10px",
10757
+ md: "16px",
10758
+ lg: "24px"
10759
+ },
10760
+ shadow: {
10761
+ sm: "0 1px 2px rgba(15, 23, 42, 0.06)",
10762
+ md: "0 10px 30px rgba(15, 23, 42, 0.10)",
10763
+ lg: "0 24px 60px rgba(15, 23, 42, 0.14)"
10764
+ },
10765
+ motion: {
10766
+ quick: "120ms ease-out",
10767
+ standard: "180ms ease-out",
10768
+ emphasis: "240ms cubic-bezier(0.22, 1, 0.36, 1)"
10769
+ },
10770
+ zIndex: {
10771
+ base: 0,
10772
+ sticky: 20,
10773
+ overlay: 40,
10774
+ modal: 60,
10775
+ toast: 70
10776
+ },
10777
+ breakpoints: {
10778
+ mobile: "640px",
10779
+ tablet: "1024px",
10780
+ desktop: "1280px"
10781
+ }
10782
+ });
10783
+ var buildComponentBuildPlan = (profile) => {
10784
+ return PROFILE_CONFIG[profile].componentSequence.map((name) => ({
10785
+ name,
10786
+ purpose: `Establish the ${name.toLowerCase()} pattern as a reusable system primitive.`,
10787
+ states: ["default", "hover", "focus", "disabled"],
10788
+ implementationNote: "Use semantic tokens first and keep copy/state logic outside the visual component."
10789
+ }));
10790
+ };
10791
+ var buildImplementationPlan = (brief, profile, references) => ({
10792
+ architectureRecommendation: "Implement the surface as token-first components using shared semantic CSS variables, then compose page sections from those primitives before adding any page-specific polish.",
10793
+ tokenStrategy: buildTokenStrategy(profile),
10794
+ componentBuildPlan: buildComponentBuildPlan(profile),
10795
+ pageAssemblyPlan: [
10796
+ "Start with the shell and primary navigation pattern.",
10797
+ "Compose the hero or primary decision section before supporting sections.",
10798
+ "Add proof, utility, and footer sections only after the top-level hierarchy is stable."
10799
+ ],
10800
+ stateAndInteractionPlan: [
10801
+ "Keep hover, focus, loading, success, and error states visually distinct.",
10802
+ "Preserve layout during loading and keep transient confirmations out of the main flow.",
10803
+ "Use reduced-motion-safe transitions for reveals and CTA feedback."
10804
+ ],
10805
+ accessibilityChecklist: [
10806
+ "Maintain 4.5:1 body text contrast across all surfaces.",
10807
+ "Preserve visible focus rings on every interactive element.",
10808
+ "Keep landmarks and heading levels explicit and sequential."
10809
+ ],
10810
+ responsiveChecklist: [
10811
+ "Collapse multicolumn layouts before text measure becomes cramped.",
10812
+ "Keep the primary CTA visible without overlap on narrow screens.",
10813
+ "Avoid horizontal scrolling for primary content."
10814
+ ],
10815
+ risksAndAmbiguities: [
10816
+ 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.",
10817
+ "Any missing interaction states must be validated during visual QA."
10818
+ ],
10819
+ buildSequence: [
10820
+ "Define semantic tokens and typography.",
10821
+ "Build the shell, navigation, and primary CTA components.",
10822
+ "Implement section-level patterns and proof blocks.",
10823
+ "Add loading, empty, and error states.",
10824
+ "Run accessibility, responsive, and browser QA before final polish."
10825
+ ]
10826
+ });
10827
+ var formatBulletList = (items) => items.map((item) => `- ${item}`).join("\n");
10828
+ var formatRecordList = (record) => {
10829
+ return Object.entries(record).map(([key, value]) => `- \`${key}\`: ${value}`).join("\n");
10830
+ };
10831
+ var referenceContribution = (reference) => {
10832
+ if (reference.captureStatus === "captured") return "Live hierarchy and component evidence captured from the page.";
10833
+ if (reference.fetchStatus === "captured") return "Content and structural cues inferred from fetched page data.";
10834
+ return "Only operator brief context was available for this reference.";
10835
+ };
10836
+ var referenceMotionNote = (reference) => {
10837
+ if (reference.capture?.snapshot?.warnings?.length) {
10838
+ return `Capture warnings: ${reference.capture.snapshot.warnings.join(", ")}`;
10839
+ }
10840
+ if (reference.captureStatus === "captured") return "Motion should remain subtle until validated against the live capture.";
10841
+ return "Motion is inferred from the brief rather than directly observed.";
10842
+ };
10843
+ var renderReferenceMarkdown = (reference, index) => {
10844
+ const excerpt = reference.excerpt ? clipText(reference.excerpt, 220) : "No fetched excerpt captured.";
10845
+ const title = reference.title ?? reference.url;
10846
+ return [
10847
+ `### Source ${index + 1}: ${title}`,
10848
+ `- what it contributes: ${referenceContribution(reference)}`,
10849
+ `- notable UI patterns: ${reference.capture?.snapshot ? "Primary hierarchy and actionables were captured from the live page." : "Patterns inferred from brief and fetched content."}`,
10850
+ `- typography observations: ${reference.title ? "Headline density and copy hierarchy were inferred from the fetched title and excerpt." : "Typography is inferred."}`,
10851
+ `- 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."}`,
10852
+ `- layout and hierarchy observations: ${reference.capture?.snapshot ? clipText(reference.capture.snapshot.content, 180) : excerpt}`,
10853
+ `- 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."}`,
10854
+ `- motion/interaction observations: ${referenceMotionNote(reference)}`,
10855
+ `- 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."}`,
10856
+ `- 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.`
10857
+ ].join("\n");
10858
+ };
10859
+ var resolveProfileConfigFromGenerationPlan = (generationPlan) => {
10860
+ if (!generationPlan || typeof generationPlan !== "object" || !("visualDirection" in generationPlan)) {
10861
+ throw new Error("Inspiredesign design contract requires a generation plan.");
10862
+ }
10863
+ const visualDirection = generationPlan.visualDirection;
10864
+ if (!visualDirection || typeof visualDirection !== "object" || !("profile" in visualDirection)) {
10865
+ throw new Error("Inspiredesign design contract requires a visual direction profile.");
10866
+ }
10867
+ const profile = visualDirection.profile;
10868
+ if (typeof profile !== "string" || !(profile in PROFILE_CONFIG)) {
10869
+ throw new Error("Inspiredesign design contract profile is invalid.");
10870
+ }
10871
+ return PROFILE_CONFIG[profile];
10872
+ };
10873
+ var renderGovernanceMarkdown = (designContract, implementationPlan) => {
10874
+ const profileConfig = resolveProfileConfigFromGenerationPlan(designContract.generationPlan);
10875
+ return [
10876
+ "## 4.1 Design Intent",
10877
+ formatBulletList([
10878
+ `Purpose: ${designContract.intent.task || ""}`,
10879
+ "Capture the reusable visual logic from the references without cloning proprietary brand assets.",
10880
+ "Keep the resulting system executable for downstream build agents."
10881
+ ]),
10882
+ "",
10883
+ "## 4.2 Core UX Principles",
10884
+ formatBulletList(profileConfig.hierarchyPrinciples),
10885
+ "",
10886
+ "## 4.3 Visual Identity",
10887
+ formatBulletList([
10888
+ `Aesthetic style: ${profileConfig.visualPersonality}`,
10889
+ `Brand tone: ${profileConfig.brandTone}`,
10890
+ `Quality posture: ${profileConfig.direction}`,
10891
+ "Direction: modern, system-led, and implementation-aware."
10892
+ ]),
10893
+ "",
10894
+ "## 4.4 Color System",
10895
+ formatRecordList(implementationPlan.tokenStrategy.colors),
10896
+ "",
10897
+ "## 4.5 Typography System",
10898
+ formatRecordList(implementationPlan.tokenStrategy.typography),
10899
+ "",
10900
+ "## 4.6 Spacing and Layout System",
10901
+ formatRecordList(implementationPlan.tokenStrategy.spacing),
10902
+ "",
10903
+ "## 4.7 Shape, Border, and Elevation Rules",
10904
+ [
10905
+ formatRecordList(implementationPlan.tokenStrategy.radius),
10906
+ formatRecordList(implementationPlan.tokenStrategy.shadow)
10907
+ ].join("\n"),
10908
+ "",
10909
+ "## 4.8 Motion and Interaction Rules",
10910
+ formatRecordList(implementationPlan.tokenStrategy.motion),
10911
+ "",
10912
+ "## 4.9 Component System",
10913
+ implementationPlan.componentBuildPlan.map((component) => [
10914
+ `### ${component.name}`,
10915
+ formatBulletList([
10916
+ `purpose: ${component.purpose}`,
10917
+ `structure: build from semantic tokens and keep state visuals explicit`,
10918
+ `visual style: ${profileConfig.direction}`,
10919
+ `states: ${component.states.join(", ")}`,
10920
+ "spacing: keep internal padding on the 8px rhythm",
10921
+ "accessibility notes: preserve focus visibility and keyboard parity",
10922
+ "responsive behavior: stack content before line length becomes cramped",
10923
+ `implementation notes: ${component.implementationNote}`
10924
+ ])
10925
+ ].join("\n")).join("\n\n"),
10926
+ "",
10927
+ "## 4.10 Page or Section Patterns",
10928
+ formatBulletList(profileConfig.pagePatterns),
10929
+ "",
10930
+ "## 4.11 Accessibility Requirements",
10931
+ formatBulletList(implementationPlan.accessibilityChecklist),
10932
+ "",
10933
+ "## 4.12 Responsiveness Requirements",
10934
+ formatBulletList(implementationPlan.responsiveChecklist),
10935
+ "",
10936
+ "## 4.13 Content and Microcopy Guidance",
10937
+ formatBulletList([
10938
+ "Use direct, confident labels and short CTA copy.",
10939
+ "Keep error and success messages specific to the affected region.",
10940
+ "Prefer descriptive button copy over generic verbs."
10941
+ ]),
10942
+ "",
10943
+ "## 4.14 Do / Don't Rules",
10944
+ formatBulletList([
10945
+ "Do preserve one dominant message per section.",
10946
+ "Do encode repeated visual rules into semantic tokens.",
10947
+ "Don't copy proprietary logos, screenshots, or brand-only illustrations.",
10948
+ "Don't hide important actions inside ambiguous hover-only affordances."
10949
+ ]),
10950
+ "",
10951
+ "## 4.15 Acceptance Criteria",
10952
+ formatBulletList([
10953
+ "Primary action is obvious within one viewport.",
10954
+ "Color, typography, spacing, and elevation all resolve through named tokens.",
10955
+ "Keyboard, focus, and reduced-motion behavior remain intact across breakpoints."
10956
+ ])
10957
+ ].join("\n");
10958
+ };
10959
+ var renderImplementationMarkdown = (implementationPlan) => {
10960
+ return [
10961
+ "# 5. Implementation Plan",
9611
10962
  "",
9612
- ...lines,
10963
+ "## 5.1 Architecture Recommendation",
10964
+ implementationPlan.architectureRecommendation,
9613
10965
  "",
9614
- "## Metadata",
9615
- "```json",
9616
- JSON.stringify(args.meta, null, 2),
9617
- "```"
10966
+ "## 5.2 Design Token Strategy",
10967
+ formatRecordList(implementationPlan.tokenStrategy.colors),
10968
+ "",
10969
+ formatRecordList(implementationPlan.tokenStrategy.typography),
10970
+ "",
10971
+ "## 5.3 Component Build Plan",
10972
+ implementationPlan.componentBuildPlan.map((component, index) => `${index + 1}. ${component.name}: ${component.purpose}`).join("\n"),
10973
+ "",
10974
+ "## 5.4 Page Assembly Plan",
10975
+ formatBulletList(implementationPlan.pageAssemblyPlan),
10976
+ "",
10977
+ "## 5.5 State and Interaction Plan",
10978
+ formatBulletList(implementationPlan.stateAndInteractionPlan),
10979
+ "",
10980
+ "## 5.6 Accessibility Implementation Checklist",
10981
+ formatBulletList(implementationPlan.accessibilityChecklist),
10982
+ "",
10983
+ "## 5.7 Responsive Implementation Checklist",
10984
+ formatBulletList(implementationPlan.responsiveChecklist),
10985
+ "",
10986
+ "## 5.8 Risks and Ambiguities",
10987
+ formatBulletList(implementationPlan.risksAndAmbiguities),
10988
+ "",
10989
+ "## 5.9 Recommended Build Sequence",
10990
+ implementationPlan.buildSequence.map((step, index) => `${index + 1}. ${step}`).join("\n")
9618
10991
  ].join("\n");
9619
- const comparisonCsv = toComparisonCsv(args.offers);
9620
- const contextPayload = {
9621
- query: args.query,
9622
- highlights: lines,
9623
- offers: args.offers,
9624
- meta: args.meta
9625
- };
9626
- const files = [
9627
- { path: "deals.md", content: markdown },
9628
- { path: "offers.json", content: { offers: args.offers } },
9629
- { path: "comparison.csv", content: comparisonCsv },
9630
- { path: "meta.json", content: args.meta },
9631
- { path: "deals-context.json", content: contextPayload }
10992
+ };
10993
+ var renderPrototypeGuidance = (profile) => {
10994
+ return [
10995
+ "# 6. Optional Prototype Plan",
10996
+ "",
10997
+ "- page structure: establish the shell, hero or primary action zone, proof sections, and footer in that order.",
10998
+ `- section order: ${PROFILE_CONFIG[profile].pagePatterns.join(" -> ")}`,
10999
+ "- component composition: reuse button, card, input, and navigation primitives before page-specific wrappers.",
11000
+ "- interaction expectations: provide visible focus, compact hover feedback, and reduced-motion-safe entry transitions.",
11001
+ "- HTML skeleton guidance: start with one main landmark, one primary CTA group, and semantic sections for proof or detail bands.",
11002
+ "- styling approach: define CSS variables first, then map components to semantic tokens rather than raw values.",
11003
+ "- 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."
11004
+ ].join("\n");
11005
+ };
11006
+ var renderDeliverablesSummary = (includePrototypeGuidance) => {
11007
+ const deliverables = [
11008
+ "Structured `designContract` JSON aligned to canvas governance",
11009
+ "Valid `generationPlan` JSON aligned to the canvas generation plan contract",
11010
+ "Human-readable `design.md` design specification",
11011
+ "Engineering implementation plan in JSON and Markdown"
9632
11012
  ];
9633
- if (args.mode === "compact") {
9634
- return {
9635
- response: {
9636
- mode: args.mode,
9637
- summary: lines.join("\n"),
9638
- meta: args.meta
9639
- },
9640
- files
9641
- };
9642
- }
9643
- if (args.mode === "json") {
9644
- return {
9645
- response: {
9646
- mode: args.mode,
9647
- offers: args.offers,
9648
- meta: args.meta
9649
- },
9650
- files
9651
- };
9652
- }
9653
- if (args.mode === "md") {
9654
- return {
9655
- response: {
9656
- mode: args.mode,
9657
- markdown,
9658
- meta: args.meta
9659
- },
9660
- files
9661
- };
9662
- }
9663
- if (args.mode === "context") {
9664
- return {
9665
- response: {
9666
- mode: args.mode,
9667
- context: contextPayload,
9668
- meta: args.meta
9669
- },
9670
- files
9671
- };
9672
- }
11013
+ if (includePrototypeGuidance) {
11014
+ deliverables.push("Prototype guidance Markdown for the first HTML pass");
11015
+ }
11016
+ deliverables.push("Evidence digest describing brief, references, fetch outcomes, and capture outcomes");
11017
+ return formatBulletList(deliverables);
11018
+ };
11019
+ var buildEvidencePayload = (brief, urls, references) => ({
11020
+ brief,
11021
+ briefHash: referenceFingerprint(brief),
11022
+ urls,
11023
+ referenceCount: references.length,
11024
+ references: references.map((reference) => toReferenceEvidenceJson(reference))
11025
+ });
11026
+ var toCaptureEvidenceJson = (capture) => {
11027
+ if (!capture) return null;
9673
11028
  return {
9674
- response: {
9675
- mode: "path",
9676
- meta: args.meta
9677
- },
9678
- files
11029
+ ...capture.title ? { title: capture.title } : {},
11030
+ ...capture.snapshot ? { snapshot: capture.snapshot } : {},
11031
+ ...capture.dom ? { dom: capture.dom } : {},
11032
+ ...capture.clone ? { clone: capture.clone } : {}
11033
+ };
11034
+ };
11035
+ var toReferenceEvidenceJson = (reference) => ({
11036
+ id: reference.id,
11037
+ url: reference.url,
11038
+ ...reference.title ? { title: reference.title } : {},
11039
+ ...reference.excerpt ? { excerpt: reference.excerpt } : {},
11040
+ fetchStatus: reference.fetchStatus,
11041
+ captureStatus: reference.captureStatus,
11042
+ ...reference.fetchFailure ? { fetchFailure: reference.fetchFailure } : {},
11043
+ ...reference.captureFailure ? { captureFailure: reference.captureFailure } : {},
11044
+ capture: toCaptureEvidenceJson(reference.capture)
11045
+ });
11046
+ var buildInspiredesignPacket = (input) => {
11047
+ const brief = trimText(input.brief);
11048
+ const urls = [...new Set(input.urls.map((url) => trimText(url)).filter(Boolean))];
11049
+ const references = input.references.map((reference) => ({
11050
+ ...reference,
11051
+ title: reference.title ? trimText(reference.title) : void 0,
11052
+ excerpt: reference.excerpt ? trimText(reference.excerpt) : void 0
11053
+ }));
11054
+ const profile = classifyProfile(brief, references);
11055
+ const generationPlan = buildGenerationPlan(brief, profile, references);
11056
+ const designContract = buildDesignContract(brief, urls, references, generationPlan);
11057
+ const implementationPlan = buildImplementationPlan(brief, profile, references);
11058
+ const governanceMarkdown = renderGovernanceMarkdown(designContract, implementationPlan);
11059
+ const implementationPlanMarkdown = renderImplementationMarkdown(implementationPlan);
11060
+ const prototypeGuidanceMarkdown = input.includePrototypeGuidance ? renderPrototypeGuidance(profile) : null;
11061
+ const designMarkdown = [
11062
+ "# 1. Executive Summary",
11063
+ "",
11064
+ formatBulletList([
11065
+ `Analyzed brief plus ${references.length || 0} inspiration reference(s).`,
11066
+ `Chosen design direction: ${PROFILE_CONFIG[profile].direction}.`,
11067
+ "Final outcome: a reusable design contract, engineering plan, and optional prototype guidance.",
11068
+ `Scope mode: ${references.length > 1 ? "full-site synthesis" : "single-surface synthesis"}.`
11069
+ ]),
11070
+ "",
11071
+ "# 2. Inspiration Analysis",
11072
+ "",
11073
+ references.length > 0 ? references.map(renderReferenceMarkdown).join("\n\n") : "- No live inspiration source was provided. The system is derived entirely from the brief.",
11074
+ "",
11075
+ "# 3. Unified Design Direction",
11076
+ "",
11077
+ formatBulletList([
11078
+ `visual personality: ${PROFILE_CONFIG[profile].visualPersonality}`,
11079
+ `tone: ${PROFILE_CONFIG[profile].brandTone}`,
11080
+ `UX principles: ${PROFILE_CONFIG[profile].hierarchyPrinciples.join(" ")}`,
11081
+ `interaction philosophy: ${PROFILE_CONFIG[profile].interactionPhilosophy}`,
11082
+ "branding posture: preserve the intent of the references without cloning brand-only assets.",
11083
+ "system coherence rules: encode tokens first, keep one dominant idea per section, and keep states explicit."
11084
+ ]),
11085
+ "",
11086
+ "# 4. Design Governance (`design.md`)",
11087
+ "",
11088
+ renderGovernanceMarkdown(designContract, implementationPlan),
11089
+ "",
11090
+ renderImplementationMarkdown(implementationPlan),
11091
+ "",
11092
+ prototypeGuidanceMarkdown ?? "# 6. Optional Prototype Plan\n\n- Prototype guidance omitted for this run.",
11093
+ "",
11094
+ "# 7. Deliverables Summary",
11095
+ "",
11096
+ renderDeliverablesSummary(Boolean(input.includePrototypeGuidance))
11097
+ ].join("\n");
11098
+ return {
11099
+ designContract,
11100
+ generationPlan,
11101
+ designMarkdown,
11102
+ implementationPlan,
11103
+ implementationPlanMarkdown,
11104
+ prototypeGuidanceMarkdown,
11105
+ evidence: buildEvidencePayload(brief, urls, references)
9679
11106
  };
9680
11107
  };
9681
11108
 
9682
11109
  // src/providers/shopping-postprocess.ts
9683
- import { createHash as createHash3 } from "crypto";
11110
+ import { createHash as createHash4 } from "crypto";
9684
11111
  var LOOKS_LIKE_URL_RE = /^https?:\/\/\S+$/i;
9685
11112
  var PRICE_TOKEN_RE = /((?:US\$|CA\$|C\$|USD|CAD|EUR|GBP|[$€£]))\s*([0-9]{1,4}(?:[.,][0-9]{3})*(?:[.,][0-9]{1,2})?)/gi;
9686
11113
  var CONTEXTUAL_PRICE_TOKEN_RE = /(?:connect to any carrier later|starting at|starts at|starting from|from|buy now for|buy for)\s*((?:US\$|CA\$|C\$|USD|CAD|EUR|GBP|[$€£]))\s*([0-9]{1,4}(?:[.,][0-9]{3})*(?:[.,][0-9]{1,2})?)/gi;
@@ -9766,7 +11193,7 @@ var REGION_CURRENCY_BY_REGION = {
9766
11193
  uk: "GBP",
9767
11194
  eu: "EUR"
9768
11195
  };
9769
- var hash = (value) => createHash3("sha1").update(value).digest("hex").slice(0, 16);
11196
+ var hash = (value) => createHash4("sha1").update(value).digest("hex").slice(0, 16);
9770
11197
  var normalizePlainText = (value) => {
9771
11198
  if (!value) return "";
9772
11199
  return extractText(value).replace(/[\u0000-\u001F\u007F-\u009F]+/g, " ").replace(/\s+/g, " ").trim();
@@ -10395,7 +11822,7 @@ var compileShoppingWorkflow = (input, options = {}) => {
10395
11822
  };
10396
11823
 
10397
11824
  // src/providers/shopping-compiler.ts
10398
- import { createHash as createHash4 } from "crypto";
11825
+ import { createHash as createHash5 } from "crypto";
10399
11826
  var DEFAULT_SHOPPING_SEARCH_LIMIT = 8;
10400
11827
  var SHOPPING_FETCH_RECOVERY_LIMIT = 2;
10401
11828
  var SEARCH_INDEX_RETRIEVAL_PATHS = /* @__PURE__ */ new Set(["shopping:search:index", "shopping:search:link"]);
@@ -10412,7 +11839,7 @@ var emptyCheckpointState = () => ({
10412
11839
  step_results_by_id: {}
10413
11840
  });
10414
11841
  var createShoppingSearchStepId = (providerId) => `search:${providerId}`;
10415
- var createShoppingFetchStepId = (providerId, url) => `fetch:${providerId}:${createHash4("sha1").update(canonicalizeUrl(url)).digest("hex").slice(0, 16)}`;
11842
+ var createShoppingFetchStepId = (providerId, url) => `fetch:${providerId}:${createHash5("sha1").update(canonicalizeUrl(url)).digest("hex").slice(0, 16)}`;
10416
11843
  var serializeShoppingCheckpointState = (state) => ({
10417
11844
  completed_step_ids: [...state.completed_step_ids],
10418
11845
  step_results_by_id: state.step_results_by_id
@@ -10898,7 +12325,7 @@ var compileProductVideoExecutionPlan = (args) => {
10898
12325
  };
10899
12326
 
10900
12327
  // src/providers/research-compiler.ts
10901
- import { createHash as createHash5 } from "crypto";
12328
+ import { createHash as createHash6 } from "crypto";
10902
12329
  var RESEARCH_AUTO_SOURCES = ["web", "community", "social"];
10903
12330
  var RESEARCH_ALL_SOURCES = [...RESEARCH_AUTO_SOURCES];
10904
12331
  var DEFAULT_RESEARCH_SEARCH_LIMIT = 10;
@@ -10923,7 +12350,7 @@ var toProviderSource = (providerId) => {
10923
12350
  return null;
10924
12351
  };
10925
12352
  var createResearchSearchStepId = (source) => `search:${source}`;
10926
- var createResearchFetchStepId = (url) => `fetch:web:${createHash5("sha1").update(canonicalizeUrl(url)).digest("hex").slice(0, 16)}`;
12353
+ var createResearchFetchStepId = (url) => `fetch:web:${createHash6("sha1").update(canonicalizeUrl(url)).digest("hex").slice(0, 16)}`;
10927
12354
  var serializeResearchCheckpointState = (state) => ({
10928
12355
  completed_step_ids: [...state.completed_step_ids],
10929
12356
  step_results_by_id: state.step_results_by_id
@@ -11509,24 +12936,54 @@ var withPrimaryConstraintMeta = (meta, failures) => {
11509
12936
  const primaryIssue = summarizePrimaryProviderIssue(failures);
11510
12937
  return primaryIssue ? {
11511
12938
  ...meta,
11512
- primary_constraint: primaryIssue,
11513
12939
  primaryConstraint: primaryIssue,
11514
12940
  primaryConstraintSummary: primaryIssue.summary
11515
12941
  } : meta;
11516
12942
  };
11517
- var withPrimaryConstraintSummaryOverride = (meta, summary) => {
12943
+ var withCamelCasePrimaryConstraintMeta = withPrimaryConstraintMeta;
12944
+ var readPrimaryConstraintGuidance = (constraint) => {
12945
+ const guidance = constraint.guidance;
12946
+ return guidance && typeof guidance === "object" && !Array.isArray(guidance) ? guidance : void 0;
12947
+ };
12948
+ var withPrimaryConstraintSummaryOverride = (meta, summary, guidance) => {
11518
12949
  const currentPrimaryConstraint = meta.primaryConstraint;
11519
- const nextPrimaryConstraint = currentPrimaryConstraint && typeof currentPrimaryConstraint === "object" && !Array.isArray(currentPrimaryConstraint) ? {
11520
- ...currentPrimaryConstraint,
12950
+ const baseConstraint = currentPrimaryConstraint && typeof currentPrimaryConstraint === "object" && !Array.isArray(currentPrimaryConstraint) ? currentPrimaryConstraint : { reasonCode: "env_limited" };
12951
+ const existingGuidance = readPrimaryConstraintGuidance(baseConstraint);
12952
+ const { guidance: _existingGuidance, ...nextPrimaryConstraintBase } = baseConstraint;
12953
+ const nextGuidance = guidance ?? existingGuidance;
12954
+ const nextPrimaryConstraint = nextGuidance ? {
12955
+ ...nextPrimaryConstraintBase,
12956
+ summary,
12957
+ guidance: nextGuidance
12958
+ } : {
12959
+ ...nextPrimaryConstraintBase,
11521
12960
  summary
11522
- } : { summary, reasonCode: "env_limited" };
12961
+ };
11523
12962
  return {
11524
12963
  ...meta,
11525
- primary_constraint: nextPrimaryConstraint,
11526
12964
  primaryConstraint: nextPrimaryConstraint,
11527
12965
  primaryConstraintSummary: summary
11528
12966
  };
11529
12967
  };
12968
+ var withReasonCodeDistributionMeta = (meta, reasonCodeDistribution) => {
12969
+ const metrics = meta.metrics;
12970
+ const nextMetrics = metrics && typeof metrics === "object" && !Array.isArray(metrics) ? {
12971
+ ...metrics,
12972
+ reasonCodeDistribution
12973
+ } : { reasonCodeDistribution };
12974
+ return {
12975
+ ...meta,
12976
+ metrics: nextMetrics,
12977
+ reasonCodeDistribution
12978
+ };
12979
+ };
12980
+ var incrementReasonCodeDistribution = (reasonCodeDistribution, reasonCode, count) => {
12981
+ if (count <= 0) return reasonCodeDistribution;
12982
+ return Object.fromEntries(Object.entries({
12983
+ ...reasonCodeDistribution,
12984
+ [reasonCode]: (reasonCodeDistribution[reasonCode] ?? 0) + count
12985
+ }).sort(([left], [right]) => left.localeCompare(right)));
12986
+ };
11530
12987
  var summarizeShoppingOfferFilterConstraint = (args) => {
11531
12988
  const primaryIssue = summarizePrimaryProviderIssue(args.failures);
11532
12989
  if (primaryIssue && (primaryIssue.reasonCode !== "env_limited" || primaryIssue.constraint || primaryIssue.blockerType === "anti_bot_challenge")) {
@@ -11586,6 +13043,7 @@ var withBrowserModeOverride = (options, input) => {
11586
13043
  var WORKFLOW_KIND_BY_SUSPENDED_INTENT_KIND = {
11587
13044
  "workflow.research": "research",
11588
13045
  "workflow.shopping": "shopping",
13046
+ "workflow.inspiredesign": "inspiredesign",
11589
13047
  "workflow.product_video": "product_video"
11590
13048
  };
11591
13049
  var buildWorkflowResumePayload = (kind, input) => ({
@@ -11837,7 +13295,7 @@ var rankResearchRecords = (records) => {
11837
13295
  return left.id.localeCompare(right.id);
11838
13296
  });
11839
13297
  };
11840
- var hash2 = (value) => createHash6("sha1").update(value).digest("hex").slice(0, 16);
13298
+ var hash2 = (value) => createHash7("sha1").update(value).digest("hex").slice(0, 16);
11841
13299
  var RESEARCH_ALWAYS_SANITIZED_PATHS = /* @__PURE__ */ new Set([
11842
13300
  "community:search:index",
11843
13301
  "social:search:index"
@@ -11956,6 +13414,229 @@ var createRemainingTimeoutResolver = (timeoutMs) => {
11956
13414
  const startedAtMs = Date.now();
11957
13415
  return () => Math.max(1, timeoutMs - Math.max(0, Date.now() - startedAtMs));
11958
13416
  };
13417
+ var INSPIREDESIGN_RENDER_MODES = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
13418
+ var INSPIREDESIGN_CAPTURE_MODES = /* @__PURE__ */ new Set(["off", "deep"]);
13419
+ var INSPIREDESIGN_COOKIE_POLICIES = /* @__PURE__ */ new Set(["off", "auto", "required"]);
13420
+ var serializeInspiredesignRunInput = (input) => ({
13421
+ brief: input.brief,
13422
+ urls: input.urls,
13423
+ captureMode: input.captureMode,
13424
+ mode: input.mode,
13425
+ ...input.includePrototypeGuidance !== void 0 ? { includePrototypeGuidance: input.includePrototypeGuidance } : {},
13426
+ ...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
13427
+ ...input.outputDir ? { outputDir: input.outputDir } : {},
13428
+ ...typeof input.ttlHours === "number" ? { ttlHours: input.ttlHours } : {},
13429
+ ...typeof input.useCookies === "boolean" ? { useCookies: input.useCookies } : {},
13430
+ ...input.challengeAutomationMode ? { challengeAutomationMode: input.challengeAutomationMode } : {},
13431
+ ...input.cookiePolicyOverride ? { cookiePolicyOverride: input.cookiePolicyOverride } : {}
13432
+ });
13433
+ var parseInspiredesignEnvelopeInput = (input) => ({
13434
+ brief: typeof input.brief === "string" ? input.brief : "",
13435
+ mode: typeof input.mode === "string" && INSPIREDESIGN_RENDER_MODES.has(input.mode) ? input.mode : "compact",
13436
+ ...Array.isArray(input.urls) ? { urls: input.urls.filter((url) => typeof url === "string") } : {},
13437
+ ...typeof input.captureMode === "string" && INSPIREDESIGN_CAPTURE_MODES.has(input.captureMode) ? { captureMode: input.captureMode } : {},
13438
+ ...typeof input.includePrototypeGuidance === "boolean" ? { includePrototypeGuidance: input.includePrototypeGuidance } : {},
13439
+ ...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
13440
+ ...typeof input.outputDir === "string" && input.outputDir.length > 0 ? { outputDir: input.outputDir } : {},
13441
+ ...typeof input.ttlHours === "number" ? { ttlHours: input.ttlHours } : {},
13442
+ ...typeof input.useCookies === "boolean" ? { useCookies: input.useCookies } : {},
13443
+ ...isChallengeAutomationMode(input.challengeAutomationMode) ? { challengeAutomationMode: input.challengeAutomationMode } : {},
13444
+ ...typeof input.cookiePolicyOverride === "string" && INSPIREDESIGN_COOKIE_POLICIES.has(input.cookiePolicyOverride) ? { cookiePolicyOverride: input.cookiePolicyOverride } : {}
13445
+ });
13446
+ var normalizeInspiredesignUrls = (urls) => {
13447
+ if (!urls || urls.length === 0) return [];
13448
+ const normalized = urls.map((url) => url.trim()).filter(Boolean);
13449
+ const invalid = normalized.find((url) => !LOOKS_LIKE_URL_RE.test(url));
13450
+ if (invalid) {
13451
+ throw new Error(`Inspiredesign workflow received an invalid URL: ${invalid}`);
13452
+ }
13453
+ return [...new Set(normalized.map((url) => canonicalizeUrl(url)))];
13454
+ };
13455
+ var normalizeInspiredesignInput = (input) => {
13456
+ const brief = input.brief.trim();
13457
+ if (!brief) {
13458
+ throw new Error("Inspiredesign workflow requires a non-empty brief.");
13459
+ }
13460
+ return {
13461
+ ...input,
13462
+ brief,
13463
+ urls: normalizeInspiredesignUrls(input.urls),
13464
+ captureMode: input.captureMode ?? "off",
13465
+ mode: input.mode ?? "compact"
13466
+ };
13467
+ };
13468
+ var isInspiredesignWorkflowEnvelopeInput = (input) => {
13469
+ return "kind" in input && "input" in input;
13470
+ };
13471
+ var buildInspiredesignEnvelope = (input) => {
13472
+ if (isInspiredesignWorkflowEnvelopeInput(input)) {
13473
+ if (!isWorkflowResumeEnvelope(input)) {
13474
+ throw new Error("Inspiredesign workflow envelope is invalid.");
13475
+ }
13476
+ if (input.kind !== "inspiredesign") {
13477
+ throw new Error(`Inspiredesign workflow envelope kind mismatch. Expected inspiredesign but received ${input.kind}.`);
13478
+ }
13479
+ return {
13480
+ envelope: input,
13481
+ workflowInput: normalizeInspiredesignInput(parseInspiredesignEnvelopeInput(input.input))
13482
+ };
13483
+ }
13484
+ const workflowInput = normalizeInspiredesignInput(input);
13485
+ return {
13486
+ envelope: buildWorkflowResumeEnvelope("inspiredesign", serializeInspiredesignRunInput(workflowInput)),
13487
+ workflowInput
13488
+ };
13489
+ };
13490
+ var appendWorkflowTrace = (trace, stage, event, details) => [
13491
+ ...trace,
13492
+ {
13493
+ at: (/* @__PURE__ */ new Date()).toISOString(),
13494
+ stage,
13495
+ event,
13496
+ details
13497
+ }
13498
+ ];
13499
+ var buildInspiredesignStepEnvelope = (workflowInput, trace, stepIndex, url) => buildWorkflowResumeEnvelope(
13500
+ "inspiredesign",
13501
+ serializeInspiredesignRunInput(workflowInput),
13502
+ {
13503
+ checkpoint: {
13504
+ stage: "execute",
13505
+ stepId: "fetch_reference",
13506
+ stepIndex,
13507
+ state: { url },
13508
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
13509
+ },
13510
+ trace
13511
+ }
13512
+ );
13513
+ var buildInspiredesignFetchOptions = (workflowInput, envelope, timeoutMs) => withWorkflowResumeEnvelopeIntent(
13514
+ withChallengeAutomationOverride(
13515
+ withCookieOverrides({
13516
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
13517
+ }, workflowInput),
13518
+ workflowInput
13519
+ ),
13520
+ "workflow.inspiredesign",
13521
+ envelope
13522
+ );
13523
+ var hasInspiredesignCaptureEvidence = (capture) => {
13524
+ if (!capture) return false;
13525
+ return Boolean(capture.title || capture.snapshot || capture.dom || capture.clone);
13526
+ };
13527
+ var captureInspiredesignReference = async (url, captureMode, workflowInput, captureReference, timeoutMs) => {
13528
+ if (captureMode === "off") {
13529
+ return { captureStatus: "off" };
13530
+ }
13531
+ if (!captureReference) {
13532
+ return {
13533
+ captureStatus: "failed",
13534
+ captureFailure: "Deep capture requested, but no browser capture callback was available."
13535
+ };
13536
+ }
13537
+ try {
13538
+ const capture = await captureReference(url, {
13539
+ timeoutMs,
13540
+ useCookies: workflowInput.useCookies,
13541
+ challengeAutomationMode: workflowInput.challengeAutomationMode,
13542
+ cookiePolicyOverride: workflowInput.cookiePolicyOverride
13543
+ });
13544
+ if (!hasInspiredesignCaptureEvidence(capture)) {
13545
+ return {
13546
+ captureStatus: "failed",
13547
+ captureFailure: "Deep capture did not return usable snapshot, DOM, or clone evidence."
13548
+ };
13549
+ }
13550
+ return {
13551
+ captureStatus: "captured",
13552
+ capture
13553
+ };
13554
+ } catch (error) {
13555
+ return {
13556
+ captureStatus: "failed",
13557
+ captureFailure: error instanceof Error ? error.message : "Deep capture failed."
13558
+ };
13559
+ }
13560
+ };
13561
+ var getInspiredesignPrimaryRecord = (result, url) => {
13562
+ const canonicalUrl = canonicalizeUrl(url);
13563
+ return result.records.find((record) => record.url && canonicalizeUrl(record.url) === canonicalUrl) ?? result.records[0];
13564
+ };
13565
+ var summarizeInspiredesignFetchFailure = (result) => {
13566
+ return summarizePrimaryProviderIssue(result.failures)?.summary ?? result.error?.message;
13567
+ };
13568
+ var excerptFromInspiredesignRecord = (record) => {
13569
+ const content = normalizePlainText(record?.content);
13570
+ if (!content) return void 0;
13571
+ return toSnippet(content, 240);
13572
+ };
13573
+ var buildInspiredesignReference = (url, result, capture) => {
13574
+ const primary = getInspiredesignPrimaryRecord(result, url);
13575
+ const title = primary?.title ?? capture.capture?.title;
13576
+ const excerpt = excerptFromInspiredesignRecord(primary);
13577
+ const fetchStatus = result.records.length > 0 ? "captured" : "failed";
13578
+ return {
13579
+ id: createHash7("sha256").update(url).digest("hex").slice(0, 12),
13580
+ url,
13581
+ ...title ? { title } : {},
13582
+ ...excerpt ? { excerpt } : {},
13583
+ fetchStatus,
13584
+ captureStatus: capture.captureStatus,
13585
+ ...fetchStatus === "failed" && summarizeInspiredesignFetchFailure(result) ? { fetchFailure: summarizeInspiredesignFetchFailure(result) } : {},
13586
+ ...capture.captureFailure ? { captureFailure: capture.captureFailure } : {},
13587
+ ...capture.capture ? { capture: capture.capture } : {}
13588
+ };
13589
+ };
13590
+ var summarizeInspiredesignCaptureConstraint = (references) => {
13591
+ const failedReferences = references.filter((reference) => reference.captureStatus === "failed");
13592
+ if (failedReferences.length === 0) {
13593
+ return void 0;
13594
+ }
13595
+ const summary = `Deep capture failed for ${failedReferences.length} ${failedReferences.length === 1 ? "reference" : "references"}.`;
13596
+ const retryUrls = failedReferences.slice(0, 2).map((reference) => `Retry deep capture for ${reference.url} after restoring the required browser session state.`);
13597
+ return {
13598
+ summary,
13599
+ guidance: {
13600
+ reason: summary,
13601
+ recommendedNextCommands: [
13602
+ "Rerun inspiredesign after configuring providers.cookieSource for the protected references you need to capture.",
13603
+ ...retryUrls
13604
+ ]
13605
+ }
13606
+ };
13607
+ };
13608
+ var buildInspiredesignMeta = (runtime, workflowInput, references, failures) => {
13609
+ const failedCaptures = references.filter((reference) => reference.captureStatus === "failed");
13610
+ let reasonCodeDistribution = summarizeReasonCodeDistribution(failures);
13611
+ let meta = withCamelCasePrimaryConstraintMeta(withReasonCodeDistributionMeta({
13612
+ selection: {
13613
+ urls: workflowInput.urls,
13614
+ capture_mode: workflowInput.captureMode,
13615
+ include_prototype_guidance: Boolean(workflowInput.includePrototypeGuidance)
13616
+ },
13617
+ metrics: {
13618
+ reference_count: references.length,
13619
+ fetched_references: references.filter((reference) => reference.fetchStatus === "captured").length,
13620
+ captured_references: references.filter((reference) => reference.captureStatus === "captured").length,
13621
+ failed_fetches: references.filter((reference) => reference.fetchStatus === "failed").length,
13622
+ failed_captures: failedCaptures.length
13623
+ },
13624
+ alerts: buildWorkflowAlerts(runtime, failures)
13625
+ }, reasonCodeDistribution), failures);
13626
+ if (!meta.primaryConstraint) {
13627
+ const captureConstraint = summarizeInspiredesignCaptureConstraint(references);
13628
+ if (captureConstraint) {
13629
+ reasonCodeDistribution = incrementReasonCodeDistribution(
13630
+ reasonCodeDistribution,
13631
+ "env_limited",
13632
+ failedCaptures.length
13633
+ );
13634
+ meta = withReasonCodeDistributionMeta(meta, reasonCodeDistribution);
13635
+ meta = withPrimaryConstraintSummaryOverride(meta, captureConstraint.summary, captureConstraint.guidance);
13636
+ }
13637
+ }
13638
+ return meta;
13639
+ };
11959
13640
  var inferBrandFromContent = (content) => {
11960
13641
  const normalized = normalizePlainText(content);
11961
13642
  if (!normalized) return void 0;
@@ -12759,6 +14440,96 @@ var runShoppingWorkflow = async (runtime, input) => {
12759
14440
  }
12760
14441
  };
12761
14442
  };
14443
+ var runInspiredesignWorkflow = async (runtime, input, options = {}) => {
14444
+ const { envelope, workflowInput } = buildInspiredesignEnvelope(input);
14445
+ const remainingTimeoutMs = createRemainingTimeoutResolver(workflowInput.timeoutMs);
14446
+ let trace = appendWorkflowTrace(envelope.trace ?? [], "compile", "compile_started", {
14447
+ kind: "inspiredesign"
14448
+ });
14449
+ trace = appendWorkflowTrace(trace, "compile", "compile_completed", {
14450
+ kind: "inspiredesign",
14451
+ urlCount: workflowInput.urls.length,
14452
+ captureMode: workflowInput.captureMode
14453
+ });
14454
+ const references = [];
14455
+ const failures = [];
14456
+ for (const [index, url] of workflowInput.urls.entries()) {
14457
+ const stepTrace = appendWorkflowTrace(trace, "execute", "reference_started", {
14458
+ stepIndex: index,
14459
+ url
14460
+ });
14461
+ const fetchTimeoutMs = remainingTimeoutMs();
14462
+ const result = await runtime.fetch(
14463
+ { url },
14464
+ buildInspiredesignFetchOptions(
14465
+ workflowInput,
14466
+ buildInspiredesignStepEnvelope(workflowInput, stepTrace, index, url),
14467
+ fetchTimeoutMs
14468
+ )
14469
+ );
14470
+ observeWorkflowSignals(runtime, result);
14471
+ failures.push(...result.failures);
14472
+ const captureTimeoutMs = remainingTimeoutMs();
14473
+ const capture = await captureInspiredesignReference(
14474
+ url,
14475
+ workflowInput.captureMode,
14476
+ workflowInput,
14477
+ options.captureReference,
14478
+ captureTimeoutMs
14479
+ );
14480
+ references.push(buildInspiredesignReference(url, result, capture));
14481
+ trace = appendWorkflowTrace(stepTrace, "execute", "reference_completed", {
14482
+ stepIndex: index,
14483
+ url,
14484
+ fetchStatus: result.records.length > 0 ? "captured" : "failed",
14485
+ captureStatus: capture.captureStatus
14486
+ });
14487
+ }
14488
+ const meta = buildInspiredesignMeta(runtime, workflowInput, references, failures);
14489
+ const packet = buildInspiredesignPacket({
14490
+ brief: workflowInput.brief,
14491
+ urls: workflowInput.urls,
14492
+ references,
14493
+ includePrototypeGuidance: workflowInput.includePrototypeGuidance
14494
+ });
14495
+ const rendered = renderInspiredesign({
14496
+ mode: workflowInput.mode,
14497
+ brief: workflowInput.brief,
14498
+ urls: workflowInput.urls,
14499
+ designContract: packet.designContract,
14500
+ generationPlan: packet.generationPlan,
14501
+ implementationPlan: packet.implementationPlan,
14502
+ designMarkdown: packet.designMarkdown,
14503
+ implementationPlanMarkdown: packet.implementationPlanMarkdown,
14504
+ prototypeGuidanceMarkdown: packet.prototypeGuidanceMarkdown,
14505
+ evidence: packet.evidence,
14506
+ meta
14507
+ });
14508
+ const bundle = await createArtifactBundle({
14509
+ namespace: "inspiredesign",
14510
+ outputDir: workflowInput.outputDir,
14511
+ ttlHours: workflowInput.ttlHours,
14512
+ files: rendered.files
14513
+ });
14514
+ if (workflowInput.mode === "path") {
14515
+ return {
14516
+ ...rendered.response,
14517
+ path: bundle.basePath,
14518
+ meta: {
14519
+ ...meta,
14520
+ artifact_manifest: bundle.manifest
14521
+ }
14522
+ };
14523
+ }
14524
+ return {
14525
+ ...rendered.response,
14526
+ artifact_path: bundle.basePath,
14527
+ meta: {
14528
+ ...meta,
14529
+ artifact_manifest: bundle.manifest
14530
+ }
14531
+ };
14532
+ };
12762
14533
  var runProductVideoWorkflow = async (runtime, input, options = {}) => {
12763
14534
  const envelope = isWorkflowResumeEnvelope(input) ? input : buildWorkflowResumeEnvelope("product_video", input);
12764
14535
  if (envelope.kind !== "product_video") {
@@ -13140,6 +14911,7 @@ var DEFAULT_PROVIDER_SUSPENDED_INTENT_KIND = {
13140
14911
  var WORKFLOW_KIND_BY_SUSPENDED_INTENT_KIND2 = {
13141
14912
  "workflow.research": "research",
13142
14913
  "workflow.shopping": "shopping",
14914
+ "workflow.inspiredesign": "inspiredesign",
13143
14915
  "workflow.product_video": "product_video"
13144
14916
  };
13145
14917
  var EXTENSION_FIRST_SOCIAL_FALLBACK_PLATFORMS = /* @__PURE__ */ new Set(["x", "reddit", "bluesky", "linkedin"]);
@@ -14586,6 +16358,14 @@ var ProviderRuntime = class {
14586
16358
  input
14587
16359
  )
14588
16360
  );
16361
+ case "workflow.inspiredesign":
16362
+ return runInspiredesignWorkflow(
16363
+ this,
16364
+ unwrapWorkflowResumeEnvelope(
16365
+ WORKFLOW_KIND_BY_SUSPENDED_INTENT_KIND2[intent.kind],
16366
+ input
16367
+ )
16368
+ );
14589
16369
  case "workflow.product_video":
14590
16370
  return runProductVideoWorkflow(
14591
16371
  this,
@@ -14743,25 +16523,38 @@ var ProviderRuntime = class {
14743
16523
  }
14744
16524
  async withTimeout(timeoutMs, task) {
14745
16525
  const controller = new AbortController();
14746
- const timeoutId = setTimeout(() => {
14747
- controller.abort("timeout");
14748
- }, timeoutMs);
16526
+ const createTimeoutError = (cause) => {
16527
+ return new ProviderRuntimeError("timeout", `Provider request timed out after ${timeoutMs}ms`, {
16528
+ retryable: true,
16529
+ ...cause !== void 0 ? { cause } : {}
16530
+ });
16531
+ };
16532
+ const taskPromise = Promise.resolve().then(() => task(controller.signal));
16533
+ const timeoutPromise = new Promise((_, reject) => {
16534
+ const timeoutId = setTimeout(() => {
16535
+ controller.abort("timeout");
16536
+ reject(createTimeoutError());
16537
+ }, timeoutMs);
16538
+ controller.signal.addEventListener("abort", () => clearTimeout(timeoutId), { once: true });
16539
+ });
14749
16540
  try {
14750
- const result = await task(controller.signal);
14751
- if (controller.signal.aborted) {
14752
- throw new ProviderRuntimeError("timeout", `Provider request timed out after ${timeoutMs}ms`);
14753
- }
14754
- return result;
16541
+ return await Promise.race([
16542
+ taskPromise.catch((error) => {
16543
+ if (controller.signal.aborted) {
16544
+ throw createTimeoutError(error);
16545
+ }
16546
+ throw error;
16547
+ }),
16548
+ timeoutPromise
16549
+ ]);
14755
16550
  } catch (error) {
16551
+ if (isProviderRuntimeError(error) && error.code === "timeout") {
16552
+ throw error;
16553
+ }
14756
16554
  if (controller.signal.aborted) {
14757
- throw new ProviderRuntimeError("timeout", `Provider request timed out after ${timeoutMs}ms`, {
14758
- retryable: true,
14759
- cause: error
14760
- });
16555
+ throw createTimeoutError(error);
14761
16556
  }
14762
16557
  throw error;
14763
- } finally {
14764
- clearTimeout(timeoutId);
14765
16558
  }
14766
16559
  }
14767
16560
  };
@@ -15189,6 +16982,7 @@ var mergeBudgets = (base, partial) => {
15189
16982
  };
15190
16983
 
15191
16984
  export {
16985
+ redactSensitive,
15192
16986
  createRequestId,
15193
16987
  stderrSink,
15194
16988
  setDefaultLogSink,
@@ -15204,6 +16998,7 @@ export {
15204
16998
  CHALLENGE_AUTOMATION_MODES,
15205
16999
  isChallengeAutomationMode,
15206
17000
  resolveChallengeAutomationPolicy,
17001
+ inspectChallengePlanFromRuntime,
15207
17002
  ChallengeOrchestrator,
15208
17003
  summarizePrimaryProviderIssue,
15209
17004
  createTraceContext,
@@ -15244,13 +17039,15 @@ export {
15244
17039
  enrichResearchRecords,
15245
17040
  renderResearch,
15246
17041
  renderShopping,
17042
+ renderInspiredesign,
15247
17043
  workflowTestUtils,
15248
17044
  runResearchWorkflow,
15249
17045
  runShoppingWorkflow,
17046
+ runInspiredesignWorkflow,
15250
17047
  runProductVideoWorkflow,
15251
17048
  DEFAULT_PROVIDER_BUDGETS,
15252
17049
  ProviderRuntime,
15253
17050
  createProviderRuntime,
15254
17051
  createDefaultRuntime
15255
17052
  };
15256
- //# sourceMappingURL=chunk-5FZQJRBQ.js.map
17053
+ //# sourceMappingURL=chunk-C6QUKABT.js.map