rivet-design 0.9.2 → 0.9.4

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 (157) hide show
  1. package/dist/mcp/agent-variants/SessionStore.d.ts +78 -2
  2. package/dist/mcp/agent-variants/SessionStore.d.ts.map +1 -1
  3. package/dist/mcp/agent-variants/SessionStore.js +464 -62
  4. package/dist/mcp/agent-variants/SessionStore.js.map +1 -1
  5. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts +331 -9
  6. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts.map +1 -1
  7. package/dist/mcp/agent-variants/WorktreeOrchestrator.js +1985 -61
  8. package/dist/mcp/agent-variants/WorktreeOrchestrator.js.map +1 -1
  9. package/dist/mcp/agent-variants/WorktreeOrchestrator.testHelpers.d.ts +65 -0
  10. package/dist/mcp/agent-variants/WorktreeOrchestrator.testHelpers.d.ts.map +1 -0
  11. package/dist/mcp/agent-variants/WorktreeOrchestrator.testHelpers.js +162 -0
  12. package/dist/mcp/agent-variants/WorktreeOrchestrator.testHelpers.js.map +1 -0
  13. package/dist/mcp/agent-variants/contracts.d.ts +2508 -10
  14. package/dist/mcp/agent-variants/contracts.d.ts.map +1 -1
  15. package/dist/mcp/agent-variants/contracts.js +295 -5
  16. package/dist/mcp/agent-variants/contracts.js.map +1 -1
  17. package/dist/mcp/agent-variants/createProjectArtifacts.d.ts +78 -0
  18. package/dist/mcp/agent-variants/createProjectArtifacts.d.ts.map +1 -0
  19. package/dist/mcp/agent-variants/createProjectArtifacts.js +123 -0
  20. package/dist/mcp/agent-variants/createProjectArtifacts.js.map +1 -0
  21. package/dist/mcp/agent-variants/createZeroToOneTool.d.ts +241 -0
  22. package/dist/mcp/agent-variants/createZeroToOneTool.d.ts.map +1 -0
  23. package/dist/mcp/agent-variants/createZeroToOneTool.js +213 -0
  24. package/dist/mcp/agent-variants/createZeroToOneTool.js.map +1 -0
  25. package/dist/mcp/agent-variants/designContextStore.d.ts +160 -0
  26. package/dist/mcp/agent-variants/designContextStore.d.ts.map +1 -0
  27. package/dist/mcp/agent-variants/designContextStore.js +295 -0
  28. package/dist/mcp/agent-variants/designContextStore.js.map +1 -0
  29. package/dist/mcp/agent-variants/elementRefToTarget.d.ts +21 -0
  30. package/dist/mcp/agent-variants/elementRefToTarget.d.ts.map +1 -0
  31. package/dist/mcp/agent-variants/elementRefToTarget.js +47 -0
  32. package/dist/mcp/agent-variants/elementRefToTarget.js.map +1 -0
  33. package/dist/mcp/agent-variants/errors.d.ts +1 -1
  34. package/dist/mcp/agent-variants/errors.d.ts.map +1 -1
  35. package/dist/mcp/agent-variants/errors.js +7 -0
  36. package/dist/mcp/agent-variants/errors.js.map +1 -1
  37. package/dist/mcp/agent-variants/index.d.ts +4 -2
  38. package/dist/mcp/agent-variants/index.d.ts.map +1 -1
  39. package/dist/mcp/agent-variants/index.js +7 -1
  40. package/dist/mcp/agent-variants/index.js.map +1 -1
  41. package/dist/mcp/agent-variants/inspirationDesignContext.d.ts +440 -0
  42. package/dist/mcp/agent-variants/inspirationDesignContext.d.ts.map +1 -0
  43. package/dist/mcp/agent-variants/inspirationDesignContext.js +2467 -0
  44. package/dist/mcp/agent-variants/inspirationDesignContext.js.map +1 -0
  45. package/dist/mcp/agent-variants/pendingChangesAdapter.d.ts.map +1 -1
  46. package/dist/mcp/agent-variants/pendingChangesAdapter.js +21 -7
  47. package/dist/mcp/agent-variants/pendingChangesAdapter.js.map +1 -1
  48. package/dist/mcp/agent-variants/previewQa.d.ts +61 -0
  49. package/dist/mcp/agent-variants/previewQa.d.ts.map +1 -0
  50. package/dist/mcp/agent-variants/previewQa.js +374 -0
  51. package/dist/mcp/agent-variants/previewQa.js.map +1 -0
  52. package/dist/mcp/agent-variants/sourceContext.d.ts +8 -0
  53. package/dist/mcp/agent-variants/sourceContext.d.ts.map +1 -0
  54. package/dist/mcp/agent-variants/sourceContext.js +183 -0
  55. package/dist/mcp/agent-variants/sourceContext.js.map +1 -0
  56. package/dist/mcp/agent-variants/tools.d.ts +36 -0
  57. package/dist/mcp/agent-variants/tools.d.ts.map +1 -1
  58. package/dist/mcp/agent-variants/tools.js +451 -19
  59. package/dist/mcp/agent-variants/tools.js.map +1 -1
  60. package/dist/mcp/changeBatchClassification.d.ts +30 -0
  61. package/dist/mcp/changeBatchClassification.d.ts.map +1 -0
  62. package/dist/mcp/changeBatchClassification.js +65 -0
  63. package/dist/mcp/changeBatchClassification.js.map +1 -0
  64. package/dist/mcp/server.d.ts.map +1 -1
  65. package/dist/mcp/server.js +258 -41
  66. package/dist/mcp/server.js.map +1 -1
  67. package/dist/prompts/agentModPrompts.js +4 -4
  68. package/dist/prompts/agentModPrompts.js.map +1 -1
  69. package/dist/proxy-middleware/proxy-config.d.ts.map +1 -1
  70. package/dist/proxy-middleware/proxy-config.js +1 -15
  71. package/dist/proxy-middleware/proxy-config.js.map +1 -1
  72. package/dist/routes/agentVariants.d.ts +3 -1
  73. package/dist/routes/agentVariants.d.ts.map +1 -1
  74. package/dist/routes/agentVariants.js +138 -13
  75. package/dist/routes/agentVariants.js.map +1 -1
  76. package/dist/routes/mcp.d.ts +7 -1
  77. package/dist/routes/mcp.d.ts.map +1 -1
  78. package/dist/routes/mcp.js +139 -16
  79. package/dist/routes/mcp.js.map +1 -1
  80. package/dist/server.d.ts.map +1 -1
  81. package/dist/server.js +23 -5
  82. package/dist/server.js.map +1 -1
  83. package/dist/services/ProjectDetectionService.d.ts.map +1 -1
  84. package/dist/services/ProjectDetectionService.js +9 -0
  85. package/dist/services/ProjectDetectionService.js.map +1 -1
  86. package/dist/services/SessionBridgeService.d.ts +22 -0
  87. package/dist/services/SessionBridgeService.d.ts.map +1 -1
  88. package/dist/services/SessionBridgeService.js +61 -0
  89. package/dist/services/SessionBridgeService.js.map +1 -1
  90. package/dist/services/TelemetryService.d.ts +121 -0
  91. package/dist/services/TelemetryService.d.ts.map +1 -1
  92. package/dist/services/TelemetryService.js +155 -0
  93. package/dist/services/TelemetryService.js.map +1 -1
  94. package/dist/services/WorktreeManager.d.ts +116 -6
  95. package/dist/services/WorktreeManager.d.ts.map +1 -1
  96. package/dist/services/WorktreeManager.js +394 -19
  97. package/dist/services/WorktreeManager.js.map +1 -1
  98. package/dist/services/agent/AgentModService.js +6 -6
  99. package/dist/services/agent/AgentModService.js.map +1 -1
  100. package/dist/services/templates/designCatalog.d.ts +27 -0
  101. package/dist/services/templates/designCatalog.d.ts.map +1 -0
  102. package/dist/services/templates/designCatalog.js +141 -0
  103. package/dist/services/templates/designCatalog.js.map +1 -0
  104. package/dist/services/templates/designmd/airbnb.md +545 -0
  105. package/dist/services/templates/designmd/airtable.md +554 -0
  106. package/dist/services/templates/designmd/apple.md +562 -0
  107. package/dist/services/templates/designmd/binance.md +634 -0
  108. package/dist/services/templates/designmd/bmw-m.md +503 -0
  109. package/dist/services/templates/designmd/bmw.md +544 -0
  110. package/dist/services/templates/designmd/bugatti.md +454 -0
  111. package/dist/services/templates/designmd/cal.md +542 -0
  112. package/dist/services/templates/designmd/claude.md +589 -0
  113. package/dist/services/templates/designmd/clay.md +541 -0
  114. package/dist/services/templates/designmd/cohere.md +451 -0
  115. package/dist/services/templates/designmd/cursor.md +537 -0
  116. package/dist/services/templates/designmd/expo.md +526 -0
  117. package/dist/services/templates/designmd/figma.md +578 -0
  118. package/dist/services/templates/designmd/framer.md +544 -0
  119. package/dist/services/templates/designmd/hp.md +670 -0
  120. package/dist/services/templates/designmd/linear.app.md +548 -0
  121. package/dist/services/templates/designmd/mintlify.md +852 -0
  122. package/dist/services/templates/designmd/miro.md +825 -0
  123. package/dist/services/templates/designmd/notion.md +821 -0
  124. package/dist/services/templates/designmd/raycast.md +669 -0
  125. package/dist/services/templates/designmd/resend.md +585 -0
  126. package/dist/services/templates/designmd/sentry.md +262 -0
  127. package/dist/services/templates/designmd/shopify.md +350 -0
  128. package/dist/services/templates/designmd/spotify.md +246 -0
  129. package/dist/services/templates/designmd/stripe.md +322 -0
  130. package/dist/services/templates/designmd/supabase.md +255 -0
  131. package/dist/services/templates/designmd/superhuman.md +252 -0
  132. package/dist/services/templates/designmd/uber.md +295 -0
  133. package/dist/services/templates/designmd/vercel.md +310 -0
  134. package/dist/services/templates/viteReactTs.d.ts +48 -0
  135. package/dist/services/templates/viteReactTs.d.ts.map +1 -0
  136. package/dist/services/templates/viteReactTs.js +274 -0
  137. package/dist/services/templates/viteReactTs.js.map +1 -0
  138. package/dist/types/change-request-types.d.ts +29 -3
  139. package/dist/types/change-request-types.d.ts.map +1 -1
  140. package/dist/utils/skills/claude-skill.d.ts +2 -2
  141. package/dist/utils/skills/claude-skill.d.ts.map +1 -1
  142. package/dist/utils/skills/claude-skill.js +19 -98
  143. package/dist/utils/skills/claude-skill.js.map +1 -1
  144. package/dist/utils/skills/cursor-rules.d.ts +2 -2
  145. package/dist/utils/skills/cursor-rules.d.ts.map +1 -1
  146. package/dist/utils/skills/cursor-rules.js +15 -80
  147. package/dist/utils/skills/cursor-rules.js.map +1 -1
  148. package/dist/utils/skills/shared-variants-protocol.d.ts +23 -0
  149. package/dist/utils/skills/shared-variants-protocol.d.ts.map +1 -0
  150. package/dist/utils/skills/shared-variants-protocol.js +130 -0
  151. package/dist/utils/skills/shared-variants-protocol.js.map +1 -0
  152. package/package.json +6 -6
  153. package/src/ui/dist/assets/main-CpX7fB64.js +382 -0
  154. package/src/ui/dist/assets/main-Qqe2_oMT.css +1 -0
  155. package/src/ui/dist/index.html +2 -2
  156. package/src/ui/dist/assets/main-AsPCtLsx.js +0 -382
  157. package/src/ui/dist/assets/main-BzmseUDd.css +0 -1
@@ -0,0 +1,374 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_ASSET_PROBER = exports.DEFAULT_RUNTIME_QA_RUNNER = void 0;
7
+ exports.runPreviewQa = runPreviewQa;
8
+ exports.extractExternalAssetUrls = extractExternalAssetUrls;
9
+ const dns_1 = __importDefault(require("dns"));
10
+ const http_1 = __importDefault(require("http"));
11
+ const https_1 = __importDefault(require("https"));
12
+ const inspirationDesignContext_1 = require("./inspirationDesignContext");
13
+ /**
14
+ * Preview QA — objective post-generation health checks for static-preview
15
+ * variants. The orchestrator runs this before accepting a `static_preview`
16
+ * succeeded report so a variant cannot enter `ready` while its referenced
17
+ * assets 404 or its runtime throws.
18
+ *
19
+ * The runner has two layers:
20
+ *
21
+ * 1. A pure static check that extracts external asset URLs from the
22
+ * generated HTML and fetches each one with a small timeout. This
23
+ * catches the most common failure mode (broken CDN URLs, missing
24
+ * `.glb` model assets) without needing a browser.
25
+ *
26
+ * 2. An injectable runtime check that can be wired to Playwright later
27
+ * to capture `pageerror` / `console.error` events. Tests stub this
28
+ * layer; production uses `DEFAULT_RUNTIME_QA_RUNNER` which is a
29
+ * no-op so the gate falls back to the static layer when no real
30
+ * runner is available.
31
+ */
32
+ const DEFAULT_ASSET_TIMEOUT_MS = 4_000;
33
+ /**
34
+ * No-op runtime QA runner used when no real (e.g. Playwright-based)
35
+ * runner is injected. Returns an empty issue list so the gate decision
36
+ * is driven entirely by the static asset layer.
37
+ */
38
+ const DEFAULT_RUNTIME_QA_RUNNER = async () => [];
39
+ exports.DEFAULT_RUNTIME_QA_RUNNER = DEFAULT_RUNTIME_QA_RUNNER;
40
+ const MAX_REDIRECTS = 5;
41
+ /**
42
+ * Resolves a hostname to public addresses and returns the address that the
43
+ * subsequent HTTP request must use for its own lookup.
44
+ *
45
+ * @effect Performs a DNS lookup via dns.promises.lookup
46
+ */
47
+ const resolvePinnedAddress = async (hostname) => {
48
+ if ((0, inspirationDesignContext_1.isLocalLiteralHostname)(hostname)) {
49
+ return {
50
+ kind: 'blocked',
51
+ message: `Host '${hostname}' resolves to a protected target.`,
52
+ };
53
+ }
54
+ let addresses;
55
+ try {
56
+ addresses = await dns_1.default.promises.lookup(hostname, { all: true });
57
+ }
58
+ catch {
59
+ return {
60
+ kind: 'blocked',
61
+ message: `Host '${hostname}' could not be resolved safely.`,
62
+ };
63
+ }
64
+ const protectedAddress = addresses.find(({ address }) => (0, inspirationDesignContext_1.isLocalLiteralHostname)(address));
65
+ if (protectedAddress) {
66
+ return {
67
+ kind: 'blocked',
68
+ message: `Host '${hostname}' resolves to a protected target.`,
69
+ };
70
+ }
71
+ const address = addresses[0];
72
+ if (!address) {
73
+ return {
74
+ kind: 'blocked',
75
+ message: `Host '${hostname}' did not resolve to an address.`,
76
+ };
77
+ }
78
+ return {
79
+ kind: 'resolved',
80
+ address: {
81
+ address: address.address,
82
+ family: address.family === 6 ? 6 : 4,
83
+ },
84
+ };
85
+ };
86
+ const locationHeader = (headers) => {
87
+ const value = headers.location;
88
+ return Array.isArray(value) ? value[0] : value;
89
+ };
90
+ /**
91
+ * Issues one HTTP request while pinning Node's lookup callback to the address
92
+ * produced by the SSRF guard.
93
+ *
94
+ * @effect Performs a network request to the validated asset URL
95
+ */
96
+ const requestAsset = async (input) => {
97
+ const parsed = new URL(input.url);
98
+ const pinned = await resolvePinnedAddress(parsed.hostname);
99
+ if (pinned.kind === 'blocked') {
100
+ return { kind: 'blocked', status: 0, message: pinned.message };
101
+ }
102
+ const lookup = (_hostname, _options, callback) => {
103
+ callback(null, pinned.address.address, pinned.address.family);
104
+ };
105
+ const transport = parsed.protocol === 'https:' ? https_1.default : http_1.default;
106
+ return new Promise((resolve, reject) => {
107
+ const request = transport.request({
108
+ protocol: parsed.protocol,
109
+ hostname: parsed.hostname,
110
+ port: parsed.port || undefined,
111
+ path: `${parsed.pathname}${parsed.search}`,
112
+ method: input.method,
113
+ headers: input.headers,
114
+ lookup,
115
+ signal: input.signal,
116
+ }, (response) => {
117
+ response.resume();
118
+ resolve({
119
+ kind: 'response',
120
+ response: {
121
+ status: response.statusCode ?? 0,
122
+ headers: response.headers,
123
+ },
124
+ });
125
+ });
126
+ request.on('error', reject);
127
+ request.end();
128
+ });
129
+ };
130
+ const DEFAULT_ASSET_PROBER = async (url, timeoutMs) => {
131
+ // SSRF guard: agent-supplied HTML can carry URLs pointing at localhost,
132
+ // RFC1918, link-local, or cloud-metadata hosts. Validate scheme +
133
+ // local-literal targets before issuing a network request, pin DNS for the
134
+ // request itself, and re-check after redirects.
135
+ const validation = (0, inspirationDesignContext_1.validateInspirationUrl)(url);
136
+ if (!validation.ok) {
137
+ return { ok: false, status: 0, message: validation.reason };
138
+ }
139
+ const controller = new AbortController();
140
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
141
+ const requestWithGuardedRedirects = async (initialUrl, init) => {
142
+ let currentUrl = initialUrl;
143
+ for (let hop = 0; hop <= MAX_REDIRECTS; hop += 1) {
144
+ const currentValidation = (0, inspirationDesignContext_1.validateInspirationUrl)(currentUrl);
145
+ if (!currentValidation.ok) {
146
+ return {
147
+ kind: 'blocked',
148
+ status: 0,
149
+ message: currentValidation.reason,
150
+ };
151
+ }
152
+ const result = await requestAsset({
153
+ url: currentValidation.normalized,
154
+ method: init.method,
155
+ headers: init.headers,
156
+ signal: controller.signal,
157
+ });
158
+ if (result.kind === 'blocked')
159
+ return result;
160
+ const response = result.response;
161
+ const isRedirect = response.status >= 300 && response.status < 400;
162
+ const location = locationHeader(response.headers);
163
+ if (!isRedirect || !location) {
164
+ return { kind: 'response', response };
165
+ }
166
+ if (hop === MAX_REDIRECTS) {
167
+ return {
168
+ kind: 'blocked',
169
+ status: 0,
170
+ message: `Exceeded ${MAX_REDIRECTS} redirects probing asset.`,
171
+ };
172
+ }
173
+ // Resolve relative redirects against the URL we just hit.
174
+ let nextUrl;
175
+ try {
176
+ nextUrl = new URL(location, currentUrl);
177
+ }
178
+ catch {
179
+ return {
180
+ kind: 'blocked',
181
+ status: 0,
182
+ message: `Malformed redirect Location '${location}'.`,
183
+ };
184
+ }
185
+ currentUrl = nextUrl.toString();
186
+ }
187
+ return {
188
+ kind: 'blocked',
189
+ status: 0,
190
+ message: 'Redirect handling exhausted unexpectedly.',
191
+ };
192
+ };
193
+ try {
194
+ let result = await requestWithGuardedRedirects(validation.normalized, {
195
+ method: 'HEAD',
196
+ });
197
+ if (result.kind === 'blocked') {
198
+ return { ok: false, status: result.status, message: result.message };
199
+ }
200
+ let response = result.response;
201
+ // Some CDNs reject HEAD with 405 — fall back to a ranged GET.
202
+ if (response.status === 405 || response.status === 501) {
203
+ result = await requestWithGuardedRedirects(validation.normalized, {
204
+ method: 'GET',
205
+ headers: { Range: 'bytes=0-0' },
206
+ });
207
+ if (result.kind === 'blocked') {
208
+ return { ok: false, status: result.status, message: result.message };
209
+ }
210
+ response = result.response;
211
+ }
212
+ return {
213
+ ok: response.status >= 200 && response.status < 300,
214
+ status: response.status,
215
+ };
216
+ }
217
+ catch (err) {
218
+ const message = err instanceof Error ? err.message : String(err);
219
+ return { ok: false, status: 0, message };
220
+ }
221
+ finally {
222
+ clearTimeout(timer);
223
+ }
224
+ };
225
+ exports.DEFAULT_ASSET_PROBER = DEFAULT_ASSET_PROBER;
226
+ /**
227
+ * Run preview QA against a generated static-preview HTML document. The
228
+ * static layer extracts external asset URLs and probes each one; the
229
+ * injectable runtime layer adds console/runtime checks. Returns a single
230
+ * `VariantQaResult` with the combined verdict.
231
+ */
232
+ async function runPreviewQa(input) {
233
+ const html = input.html;
234
+ if (typeof html !== 'string' || html.trim().length === 0) {
235
+ return {
236
+ status: 'failed',
237
+ issues: [
238
+ {
239
+ kind: 'preview_unavailable',
240
+ detail: input.options?.source ?? 'inline',
241
+ message: 'Preview HTML was empty',
242
+ },
243
+ ],
244
+ summary: 'Preview unavailable: generated HTML was empty.',
245
+ checkedSource: input.options?.source,
246
+ };
247
+ }
248
+ const assetProber = input.options?.assetProber ?? exports.DEFAULT_ASSET_PROBER;
249
+ const runtimeRunner = input.options?.runtimeQaRunner ?? exports.DEFAULT_RUNTIME_QA_RUNNER;
250
+ const assetTimeoutMs = input.options?.assetTimeoutMs ?? DEFAULT_ASSET_TIMEOUT_MS;
251
+ const source = input.options?.source;
252
+ const issues = [];
253
+ const assetUrls = extractExternalAssetUrls(html);
254
+ await Promise.all(assetUrls.map(async (url) => {
255
+ const result = await assetProber(url, assetTimeoutMs);
256
+ if (!result.ok) {
257
+ issues.push({
258
+ kind: 'asset_load_failed',
259
+ detail: url,
260
+ message: result.status > 0
261
+ ? `HTTP ${result.status}`
262
+ : result.message ?? 'Network error',
263
+ });
264
+ }
265
+ }));
266
+ try {
267
+ const runtimeIssues = await runtimeRunner({ html, source: source ?? 'inline' });
268
+ for (const issue of runtimeIssues) {
269
+ issues.push(issue);
270
+ }
271
+ }
272
+ catch (err) {
273
+ issues.push({
274
+ kind: 'console_error',
275
+ detail: 'runtime_qa_runner',
276
+ message: err instanceof Error ? err.message : String(err),
277
+ });
278
+ }
279
+ // External-asset probe failures don't block — the user's browser fetches
280
+ // these directly when viewing the preview, so a server-side reachability
281
+ // failure (e.g. IPv6/SSRF-guard edge cases on fonts.googleapis.com) doesn't
282
+ // predict whether the iframe will render. Keep them in `issues` for
283
+ // visibility, but only console/runtime errors and missing previews actually
284
+ // fail QA.
285
+ const blockingIssues = issues.filter((issue) => issue.kind !== 'asset_load_failed');
286
+ if (blockingIssues.length === 0) {
287
+ const assetIssueCount = issues.length;
288
+ return {
289
+ status: 'passed',
290
+ issues,
291
+ summary: assetIssueCount === 0
292
+ ? 'Preview QA passed — assets reachable, no runtime errors.'
293
+ : `Preview QA passed — ${assetIssueCount} external asset${assetIssueCount === 1 ? '' : 's'} unreachable from server (browser will fetch independently).`,
294
+ checkedSource: source,
295
+ };
296
+ }
297
+ return {
298
+ status: 'failed',
299
+ issues,
300
+ summary: buildIssueSummary(issues),
301
+ checkedSource: source,
302
+ };
303
+ }
304
+ const buildIssueSummary = (issues) => {
305
+ const counts = {
306
+ asset_load_failed: 0,
307
+ console_error: 0,
308
+ preview_unavailable: 0,
309
+ };
310
+ for (const issue of issues) {
311
+ counts[issue.kind] += 1;
312
+ }
313
+ const fragments = [];
314
+ if (counts.asset_load_failed > 0) {
315
+ const first = issues.find((i) => i.kind === 'asset_load_failed');
316
+ fragments.push(counts.asset_load_failed === 1
317
+ ? `asset failed to load (${first?.detail ?? 'unknown'})`
318
+ : `${counts.asset_load_failed} assets failed to load`);
319
+ }
320
+ if (counts.console_error > 0) {
321
+ fragments.push(counts.console_error === 1
322
+ ? '1 console/runtime error detected'
323
+ : `${counts.console_error} console/runtime errors detected`);
324
+ }
325
+ if (counts.preview_unavailable > 0) {
326
+ fragments.push('preview unavailable');
327
+ }
328
+ return `Preview QA failed: ${fragments.join('; ')}.`;
329
+ };
330
+ /**
331
+ * Extract external asset URLs from a generated HTML document. Pulls from
332
+ * the common attributes (`src`, `href`, `poster`, `data-*` images) and
333
+ * inline CSS `url(...)` references. Keeps only http(s) URLs — relative
334
+ * paths and inline data URIs can't fail the QA gate because they don't
335
+ * touch the network.
336
+ */
337
+ function extractExternalAssetUrls(html) {
338
+ const seen = new Set();
339
+ const push = (raw) => {
340
+ if (!raw)
341
+ return;
342
+ const trimmed = raw.trim();
343
+ if (!trimmed)
344
+ return;
345
+ if (!/^https?:\/\//i.test(trimmed))
346
+ return;
347
+ seen.add(trimmed);
348
+ };
349
+ const attributeRegex = /\b(?:src|href|poster|data-src|data-href|data-image|model-src)\s*=\s*("|')([^"']+)\1/gi;
350
+ let attrMatch;
351
+ while ((attrMatch = attributeRegex.exec(html))) {
352
+ push(attrMatch[2]);
353
+ }
354
+ // <link rel="stylesheet" href="..."> is already covered above; capture
355
+ // <img srcset> entries here. srcset is a comma list of "url descriptor".
356
+ const srcsetRegex = /\bsrcset\s*=\s*("|')([^"']+)\1/gi;
357
+ let srcsetMatch;
358
+ while ((srcsetMatch = srcsetRegex.exec(html))) {
359
+ const list = srcsetMatch[2];
360
+ for (const entry of list.split(',')) {
361
+ const url = entry.trim().split(/\s+/)[0];
362
+ push(url);
363
+ }
364
+ }
365
+ // Inline CSS `url(...)` references (background-image, etc.). Strip
366
+ // surrounding quotes if present.
367
+ const cssUrlRegex = /url\(\s*("|'|)([^"')]+)\1\s*\)/gi;
368
+ let cssMatch;
369
+ while ((cssMatch = cssUrlRegex.exec(html))) {
370
+ push(cssMatch[2]);
371
+ }
372
+ return [...seen];
373
+ }
374
+ //# sourceMappingURL=previewQa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"previewQa.js","sourceRoot":"","sources":["../../../src/mcp/agent-variants/previewQa.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type SourceArtifactInput, type SourceContextArtifact, type SourceContextInput } from './contracts';
2
+ export declare const normalizeUrl: (rawUrl: string) => string | null;
3
+ export declare const extractPromptUrls: (prompt: string) => string[];
4
+ export declare const resolveSourceUrls: (prompt: string, sourceContext?: SourceContextInput) => string[];
5
+ export declare const normalizeSourceArtifacts: (sourceArtifacts: SourceArtifactInput[] | undefined) => SourceArtifactInput[];
6
+ export declare const normalizeSourceContextArtifact: (artifact: SourceContextArtifact) => SourceContextArtifact;
7
+ export declare const buildSourceContextMarkdown: (artifact: SourceContextArtifact) => string;
8
+ //# sourceMappingURL=sourceContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceContext.d.ts","sourceRoot":"","sources":["../../../src/mcp/agent-variants/sourceContext.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAkCrB,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,KAAG,MAAM,GAAG,IA4BtD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,MAAM,EAYxD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,EACd,gBAAgB,kBAAkB,KACjC,MAAM,EAYR,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,iBAAiB,mBAAmB,EAAE,GAAG,SAAS,KACjD,mBAAmB,EAOrB,CAAC;AAEF,eAAO,MAAM,8BAA8B,GACzC,UAAU,qBAAqB,KAC9B,qBAsCF,CAAC;AAaF,eAAO,MAAM,0BAA0B,GACrC,UAAU,qBAAqB,KAC9B,MA0CF,CAAC"}
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildSourceContextMarkdown = exports.normalizeSourceContextArtifact = exports.normalizeSourceArtifacts = exports.resolveSourceUrls = exports.extractPromptUrls = exports.normalizeUrl = void 0;
4
+ const errors_1 = require("./errors");
5
+ // NOTE: This creates an ES module cycle with inspirationDesignContext (which
6
+ // imports `extractPromptUrls` from here). The cycle is safe because
7
+ // `isLocalLiteralHostname` is only invoked from inside `normalizeUrl`'s
8
+ // function body, not at module-eval time. Without this guard,
9
+ // `resolveSourceUrls` would happily pass `http://169.254.169.254/...` or
10
+ // `http://localhost:.../` URLs from prompts / `sourceContext.sourceUrls`
11
+ // straight into the `source_plan` work item, where the agent's browser
12
+ // extraction step would dial them — bypassing the SSRF guard that already
13
+ // covers the server-side inspiration fetcher.
14
+ const inspirationDesignContext_1 = require("./inspirationDesignContext");
15
+ const MAX_PROMPT_URLS = 6;
16
+ const MAX_SOURCE_URLS = 24;
17
+ const MAX_ARTIFACTS = 24;
18
+ const MAX_ARTIFACT_CONTENT_LENGTH = 8_000;
19
+ const MAX_FIELD_LENGTH = 400;
20
+ const MAX_TOTAL_MARKDOWN_LENGTH = 60_000;
21
+ const TRAILING_URL_PUNCTUATION = /[),.;:!?]+$/;
22
+ const EMAIL_PATTERN = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
23
+ const PHONE_PATTERN = /\b(?:\+?\d{1,3}[ -]?)?(?:\(?\d{2,4}\)?[ -]?)?\d{3,4}[ -]?\d{4}\b/g;
24
+ const TOKEN_PATTERN = /\b(?:api[_-]?key|token|secret|password)\s*[:=]\s*[^\s,;]+/gi;
25
+ const sanitizeText = (value, maxLength) => {
26
+ const redacted = value
27
+ .replace(EMAIL_PATTERN, '[redacted-email]')
28
+ .replace(PHONE_PATTERN, '[redacted-phone]')
29
+ .replace(TOKEN_PATTERN, '[redacted-secret]');
30
+ return redacted.replace(/\s+/g, ' ').trim().slice(0, maxLength);
31
+ };
32
+ const normalizeUrl = (rawUrl) => {
33
+ const trimmed = rawUrl.trim().replace(TRAILING_URL_PUNCTUATION, '');
34
+ if (!trimmed)
35
+ return null;
36
+ let parsed;
37
+ try {
38
+ parsed = new URL(trimmed);
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
44
+ return null;
45
+ }
46
+ // SSRF gate: reject literal localhost / loopback / link-local /
47
+ // RFC1918 / cloud-metadata hosts here, before the URL is handed to
48
+ // `source_plan` and the agent's browser extraction step. The
49
+ // server-side inspiration fetcher applies the same check (plus a
50
+ // resolved-DNS check) — without this, prompt-injected URLs like
51
+ // `http://169.254.169.254/...` or `http://localhost:.../` would
52
+ // sneak through `resolveSourceUrls` and drive the agent at internal
53
+ // services. The DNS-resolved layer is intentionally not run here
54
+ // because `normalizeUrl` must stay sync; the literal check covers
55
+ // every cheap-to-stuff target without needing IO.
56
+ const hostname = parsed.hostname.toLowerCase();
57
+ if (!hostname || (0, inspirationDesignContext_1.isLocalLiteralHostname)(hostname)) {
58
+ return null;
59
+ }
60
+ parsed.hash = '';
61
+ return parsed.toString();
62
+ };
63
+ exports.normalizeUrl = normalizeUrl;
64
+ const extractPromptUrls = (prompt) => {
65
+ const matches = prompt.match(/\bhttps?:\/\/[^\s)]+/g) ?? [];
66
+ const deduped = [];
67
+ const seen = new Set();
68
+ for (const raw of matches) {
69
+ const normalized = (0, exports.normalizeUrl)(raw);
70
+ if (!normalized || seen.has(normalized))
71
+ continue;
72
+ seen.add(normalized);
73
+ deduped.push(normalized);
74
+ if (deduped.length >= MAX_PROMPT_URLS)
75
+ break;
76
+ }
77
+ return deduped;
78
+ };
79
+ exports.extractPromptUrls = extractPromptUrls;
80
+ const resolveSourceUrls = (prompt, sourceContext) => {
81
+ const merged = [...(0, exports.extractPromptUrls)(prompt), ...(sourceContext?.sourceUrls ?? [])];
82
+ const deduped = [];
83
+ const seen = new Set();
84
+ for (const candidate of merged) {
85
+ const normalized = (0, exports.normalizeUrl)(candidate);
86
+ if (!normalized || seen.has(normalized))
87
+ continue;
88
+ seen.add(normalized);
89
+ deduped.push(normalized);
90
+ if (deduped.length >= MAX_SOURCE_URLS)
91
+ break;
92
+ }
93
+ return deduped;
94
+ };
95
+ exports.resolveSourceUrls = resolveSourceUrls;
96
+ const normalizeSourceArtifacts = (sourceArtifacts) => {
97
+ if (!sourceArtifacts || sourceArtifacts.length === 0)
98
+ return [];
99
+ return sourceArtifacts.slice(0, MAX_ARTIFACTS).map((artifact) => ({
100
+ kind: artifact.kind,
101
+ label: sanitizeText(artifact.label, 80),
102
+ content: sanitizeText(artifact.content, MAX_ARTIFACT_CONTENT_LENGTH),
103
+ }));
104
+ };
105
+ exports.normalizeSourceArtifacts = normalizeSourceArtifacts;
106
+ const normalizeSourceContextArtifact = (artifact) => {
107
+ const normalizeList = (items) => items.map((item) => sanitizeText(item, MAX_FIELD_LENGTH)).filter(Boolean);
108
+ const normalized = {
109
+ sourceFindings: normalizeList(artifact.sourceFindings),
110
+ sectionInventory: normalizeList(artifact.sectionInventory),
111
+ visualObservations: normalizeList(artifact.visualObservations),
112
+ sourceRoles: artifact.sourceRoles.map((entry) => ({
113
+ url: sanitizeText(entry.url, 2_048),
114
+ role: entry.role,
115
+ ...(entry.rationale
116
+ ? { rationale: sanitizeText(entry.rationale, MAX_FIELD_LENGTH) }
117
+ : {}),
118
+ })),
119
+ qualityBar: normalizeList(artifact.qualityBar),
120
+ ...(artifact.screenshotReferences
121
+ ? {
122
+ screenshotReferences: normalizeList(artifact.screenshotReferences).slice(0, 16),
123
+ }
124
+ : {}),
125
+ ...(artifact.risks
126
+ ? { risks: normalizeList(artifact.risks).slice(0, 24) }
127
+ : {}),
128
+ };
129
+ const estimatedSize = JSON.stringify(normalized).length;
130
+ if (estimatedSize > MAX_TOTAL_MARKDOWN_LENGTH) {
131
+ throw new errors_1.AgentVariantsError('SOURCE_CONTEXT_TOO_LARGE', `Source context exceeds size limit (${estimatedSize} > ${MAX_TOTAL_MARKDOWN_LENGTH})`);
132
+ }
133
+ return normalized;
134
+ };
135
+ exports.normalizeSourceContextArtifact = normalizeSourceContextArtifact;
136
+ const redactUrlForDisplay = (url) => {
137
+ try {
138
+ const parsed = new URL(url);
139
+ parsed.search = '';
140
+ parsed.hash = '';
141
+ return parsed.toString();
142
+ }
143
+ catch {
144
+ return url;
145
+ }
146
+ };
147
+ const buildSourceContextMarkdown = (artifact) => {
148
+ const lines = [
149
+ '# SOURCE_CONTEXT',
150
+ '',
151
+ '## Source Findings',
152
+ ...artifact.sourceFindings.map((item) => `- ${item}`),
153
+ '',
154
+ '## Section Inventory',
155
+ ...artifact.sectionInventory.map((item) => `- ${item}`),
156
+ '',
157
+ '## Visual Observations',
158
+ ...artifact.visualObservations.map((item) => `- ${item}`),
159
+ '',
160
+ '## Source Roles',
161
+ ...artifact.sourceRoles.map((entry) => entry.rationale
162
+ ? `- ${entry.role}: ${redactUrlForDisplay(entry.url)} (${entry.rationale})`
163
+ : `- ${entry.role}: ${redactUrlForDisplay(entry.url)}`),
164
+ '',
165
+ '## Quality Bar',
166
+ ...artifact.qualityBar.map((item) => `- ${item}`),
167
+ ];
168
+ if (artifact.screenshotReferences && artifact.screenshotReferences.length > 0) {
169
+ lines.push('', '## Screenshot References');
170
+ lines.push(...artifact.screenshotReferences.map((item) => `- ${item}`));
171
+ }
172
+ if (artifact.risks && artifact.risks.length > 0) {
173
+ lines.push('', '## Risks');
174
+ lines.push(...artifact.risks.map((item) => `- ${item}`));
175
+ }
176
+ const markdown = lines.join('\n').trim();
177
+ if (markdown.length > MAX_TOTAL_MARKDOWN_LENGTH) {
178
+ throw new errors_1.AgentVariantsError('SOURCE_CONTEXT_TOO_LARGE', `SOURCE_CONTEXT.md exceeds size limit (${markdown.length} > ${MAX_TOTAL_MARKDOWN_LENGTH})`);
179
+ }
180
+ return `${markdown}\n`;
181
+ };
182
+ exports.buildSourceContextMarkdown = buildSourceContextMarkdown;
183
+ //# sourceMappingURL=sourceContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceContext.js","sourceRoot":"","sources":["../../../src/mcp/agent-variants/sourceContext.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,44 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type VariantQaResult, type VisualEditorAttachment } from './contracts';
3
+ import { slugifyPrompt } from './createZeroToOneTool';
4
+ export { slugifyPrompt };
2
5
  import type { AgentVariantsOrchestrator } from './WorktreeOrchestrator';
6
+ /**
7
+ * Coerce `output` to a structured value when an agent (incorrectly) sends a
8
+ * stringified JSON. The MCP schema accepts `z.unknown()` so the call doesn't
9
+ * fail validation, but downstream consumers (e.g. `output.html` in
10
+ * WorktreeOrchestrator) expect an object and silently no-op on strings —
11
+ * leaving the variant stuck at "not ready" until session expiry.
12
+ */
13
+ export declare const normalizeAgentOutput: (output: unknown) => unknown;
3
14
  export interface ToolDeps {
4
15
  orchestrator: AgentVariantsOrchestrator;
5
16
  leaseOwner: () => string;
17
+ /**
18
+ * Zero-to-one only: ensure the Rivet visual editor is up on the future
19
+ * destination path so the iframe is ready when variants render. Wired
20
+ * from server.ts; same hook used by create_zero_to_one_project. When
21
+ * absent (e.g. unit tests), start_variants(mode='zero_to_one') skips
22
+ * the auto-open and the caller can open the editor themselves.
23
+ */
24
+ ensureVisualEditorOpen?: (input: {
25
+ projectPath: string;
26
+ framework: 'vite';
27
+ }) => Promise<VisualEditorAttachment>;
28
+ /** Test seam — defaults to os.homedir. */
29
+ homedir?: () => string;
30
+ telemetry?: unknown;
6
31
  }
7
32
  export declare function registerAgentVariantsTools(mcp: McpServer, deps: ToolDeps): void;
33
+ /**
34
+ * User-facing prompt template for QA failures. Lists each failed variant
35
+ * with its summary + first asset/console issue, then asks the user
36
+ * whether to retry, continue with healthy variants, or cancel. Kept as
37
+ * data (not a log line) so the calling agent can present the choice
38
+ * directly to the human.
39
+ */
40
+ export declare function buildQaFailurePrompt(failures: Array<{
41
+ label: string;
42
+ qa: VariantQaResult;
43
+ }>, healthyCount: number): string;
8
44
  //# sourceMappingURL=tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/agent-variants/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0BzE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAExE,MAAM,WAAW,QAAQ;IACvB,YAAY,EAAE,yBAAyB,CAAC;IACxC,UAAU,EAAE,MAAM,MAAM,CAAC;CAC1B;AAED,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,QAAQ,GACb,IAAI,CAoON"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/agent-variants/tools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAmCL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,CAAC;AAGzB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAGxE;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,OAAO,KAAG,OAOtD,CAAC;AAmBF,MAAM,WAAW,QAAQ;IACvB,YAAY,EAAE,yBAAyB,CAAC;IACxC,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE;QAC/B,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACnB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACtC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAQD,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,QAAQ,GACb,IAAI,CAqYN;AA+GD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,eAAe,CAAA;CAAE,CAAC,EACvD,YAAY,EAAE,MAAM,GACnB,MAAM,CAwBR"}