dev3000 0.0.112 → 0.0.113
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.
- package/dist/cdp-monitor.d.ts +2 -1
- package/dist/cdp-monitor.d.ts.map +1 -1
- package/dist/cdp-monitor.js +23 -6
- package/dist/cdp-monitor.js.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/dev-environment.d.ts +1 -0
- package/dist/dev-environment.d.ts.map +1 -1
- package/dist/dev-environment.js +2 -1
- package/dist/dev-environment.js.map +1 -1
- package/mcp-server/.next/BUILD_ID +1 -1
- package/mcp-server/.next/build-manifest.json +2 -2
- package/mcp-server/.next/fallback-build-manifest.json +2 -2
- package/mcp-server/.next/prerender-manifest.json +3 -3
- package/mcp-server/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/_global-error.html +2 -2
- package/mcp-server/.next/server/app/_global-error.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/_not-found.html +1 -1
- package/mcp-server/.next/server/app/_not-found.rsc +2 -2
- package/mcp-server/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/mcp-server/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/mcp-server/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/auth/error/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/auth/error.html +1 -1
- package/mcp-server/.next/server/app/auth/error.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/_full.segment.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/auth/error.segments/_index.segment.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/_tree.segment.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/auth/error/__PAGE__.segment.rsc +1 -1
- package/mcp-server/.next/server/app/auth/error.segments/auth/error.segment.rsc +1 -1
- package/mcp-server/.next/server/app/auth/error.segments/auth.segment.rsc +1 -1
- package/mcp-server/.next/server/app/index.html +1 -1
- package/mcp-server/.next/server/app/index.rsc +2 -2
- package/mcp-server/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/mcp-server/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/mcp-server/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/mcp-server/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/mcp-server/.next/server/app/logs/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/signin/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/signin/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/video/[session]/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/video/[session]/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/workflows/[id]/report/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/workflows/[id]/report/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/workflows/new/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/workflows/new/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/workflows/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/workflows/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__157de66b._.js +38 -32
- package/mcp-server/.next/server/chunks/[root-of-the-server]__157de66b._.js.map +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__446f0436._.js.map +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__730a8fd0._.js.map +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__c508da18._.js +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__c508da18._.js.map +1 -1
- package/mcp-server/.next/server/chunks/bee4f_next_dist_esm_build_templates_app-route_1ece9366.js +6 -5
- package/mcp-server/.next/server/chunks/bee4f_next_dist_esm_build_templates_app-route_1ece9366.js.map +1 -1
- package/mcp-server/.next/server/chunks/mcp-server_app_api_cloud_fix-workflow_steps_ts_b65f3271._.js +29 -23
- package/mcp-server/.next/server/chunks/mcp-server_app_api_cloud_fix-workflow_steps_ts_b65f3271._.js.map +1 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__0ff05d72._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__0ff05d72._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__9a29b768._.js → [root-of-the-server]__27cc5956._.js} +2 -2
- package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__9a29b768._.js.map → [root-of-the-server]__27cc5956._.js.map} +1 -1
- package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__8ce53954._.js → [root-of-the-server]__34731fcf._.js} +2 -2
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__34731fcf._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__97dbdf3d._.js → [root-of-the-server]__570677dc._.js} +2 -2
- package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__97dbdf3d._.js.map → [root-of-the-server]__570677dc._.js.map} +1 -1
- package/mcp-server/.next/server/chunks/ssr/_cd4dc25e._.js.map +1 -1
- package/mcp-server/.next/server/server-reference-manifest.js +1 -1
- package/mcp-server/.next/server/server-reference-manifest.json +1 -1
- package/mcp-server/.next/static/chunks/{8d5a57e1de949e9f.js → 07848f6bd2a7e5f6.js} +2 -2
- package/mcp-server/.next/static/chunks/aed4fb5252a4bc95.js +3 -0
- package/mcp-server/.next/static/chunks/e8d521464b0c96ca.css +1 -0
- package/mcp-server/app/api/cloud/fix-workflow/steps.ts +236 -63
- package/mcp-server/app/api/cloud/fix-workflow/workflow.ts +19 -6
- package/mcp-server/app/api/cloud/start-fix/route.ts +2 -1
- package/mcp-server/app/workflows/workflows-client.tsx +35 -0
- package/package.json +1 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__3a2dacc6._.js +0 -3
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__3a2dacc6._.js.map +0 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__8ce53954._.js.map +0 -1
- package/mcp-server/.next/static/chunks/2bcc973e2858aaba.js +0 -1
- package/mcp-server/.next/static/chunks/a0e4d9b8d2f627cf.css +0 -1
- /package/mcp-server/.next/static/{aFliqsQDgiIm8sdHtWiID → UcmWUkU-l9iLeWRnSUybj}/_buildManifest.js +0 -0
- /package/mcp-server/.next/static/{aFliqsQDgiIm8sdHtWiID → UcmWUkU-l9iLeWRnSUybj}/_clientMiddlewareManifest.json +0 -0
- /package/mcp-server/.next/static/{aFliqsQDgiIm8sdHtWiID → UcmWUkU-l9iLeWRnSUybj}/_ssgManifest.js +0 -0
|
@@ -55,36 +55,56 @@ export async function createD3kSandbox(
|
|
|
55
55
|
let clsData: unknown = null
|
|
56
56
|
let mcpError: string | null = null
|
|
57
57
|
|
|
58
|
+
// Helper function to properly consume sandbox command output
|
|
59
|
+
// The Vercel Sandbox SDK returns a result object with an async logs() iterator
|
|
60
|
+
async function runSandboxCommand(
|
|
61
|
+
sandbox: typeof sandboxResult.sandbox,
|
|
62
|
+
cmd: string,
|
|
63
|
+
args: string[]
|
|
64
|
+
): Promise<{ exitCode: number; stdout: string; stderr: string }> {
|
|
65
|
+
const result = await sandbox.runCommand({ cmd, args })
|
|
66
|
+
let stdout = ""
|
|
67
|
+
let stderr = ""
|
|
68
|
+
for await (const log of result.logs()) {
|
|
69
|
+
if (log.stream === "stdout") {
|
|
70
|
+
stdout += log.data
|
|
71
|
+
} else {
|
|
72
|
+
stderr += log.data
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
await result.wait()
|
|
76
|
+
return { exitCode: result.exitCode, stdout, stderr }
|
|
77
|
+
}
|
|
78
|
+
|
|
58
79
|
try {
|
|
59
80
|
// Call fix_my_app MCP tool via curl from inside the sandbox
|
|
60
81
|
// This avoids network isolation issues - we're calling localhost:3684 from within the sandbox
|
|
61
|
-
const mcpCommand = `curl -s -X POST http://localhost:3684/mcp
|
|
62
|
-
-H "Content-Type: application/json" \\
|
|
63
|
-
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"fix_my_app","arguments":{"mode":"snapshot","focusArea":"performance","returnRawData":true}}}'`
|
|
82
|
+
const mcpCommand = `curl -s -X POST http://localhost:3684/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"fix_my_app","arguments":{"mode":"snapshot","focusArea":"performance","returnRawData":true}}}'`
|
|
64
83
|
|
|
65
84
|
console.log(`[Step 0] Executing MCP command inside sandbox...`)
|
|
66
|
-
|
|
67
|
-
cmd: "bash",
|
|
68
|
-
args: ["-c", mcpCommand]
|
|
69
|
-
})
|
|
85
|
+
console.log(`[Step 0] MCP command: ${mcpCommand.substring(0, 200)}...`)
|
|
70
86
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// The Vercel Sandbox SDK types stdout as a union of string | function
|
|
75
|
-
let stdout: string
|
|
76
|
-
const rawStdout = mcpResult.stdout
|
|
77
|
-
if (typeof rawStdout === "string") {
|
|
78
|
-
stdout = rawStdout as string
|
|
79
|
-
} else if (typeof rawStdout === "function") {
|
|
80
|
-
stdout = await (rawStdout as () => Promise<string>)()
|
|
81
|
-
} else {
|
|
82
|
-
stdout = String(rawStdout || "")
|
|
83
|
-
}
|
|
87
|
+
let stdout = ""
|
|
88
|
+
let stderr = ""
|
|
89
|
+
let exitCode = -1
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
try {
|
|
92
|
+
const result = await runSandboxCommand(sandboxResult.sandbox, "bash", ["-c", mcpCommand])
|
|
93
|
+
stdout = result.stdout
|
|
94
|
+
stderr = result.stderr
|
|
95
|
+
exitCode = result.exitCode
|
|
96
|
+
console.log(`[Step 0] MCP command exit code: ${exitCode}`)
|
|
97
|
+
console.log(`[Step 0] MCP stdout length: ${stdout.length} bytes`)
|
|
98
|
+
if (stderr) {
|
|
99
|
+
console.log(`[Step 0] MCP stderr: ${stderr.substring(0, 500)}`)
|
|
100
|
+
}
|
|
101
|
+
} catch (runCommandError) {
|
|
102
|
+
const errorMsg = runCommandError instanceof Error ? runCommandError.message : String(runCommandError)
|
|
103
|
+
console.log(`[Step 0] sandbox.runCommand threw: ${errorMsg}`)
|
|
104
|
+
mcpError = `sandbox.runCommand failed: ${errorMsg}`
|
|
105
|
+
}
|
|
86
106
|
|
|
87
|
-
if (
|
|
107
|
+
if (exitCode === 0 && stdout) {
|
|
88
108
|
try {
|
|
89
109
|
const mcpResponse = JSON.parse(stdout)
|
|
90
110
|
if (mcpResponse.result?.content) {
|
|
@@ -111,11 +131,11 @@ export async function createD3kSandbox(
|
|
|
111
131
|
console.log(`[Step 0] ${mcpError}`)
|
|
112
132
|
console.log(`[Step 0] Raw stdout: ${stdout.substring(0, 1000)}`)
|
|
113
133
|
}
|
|
114
|
-
} else {
|
|
115
|
-
mcpError = `MCP command failed with exit code ${
|
|
134
|
+
} else if (exitCode !== 0 && !mcpError) {
|
|
135
|
+
mcpError = `MCP command failed with exit code ${exitCode}`
|
|
116
136
|
console.log(`[Step 0] ${mcpError}`)
|
|
117
|
-
if (
|
|
118
|
-
console.log(`[Step 0] stderr: ${
|
|
137
|
+
if (stderr) {
|
|
138
|
+
console.log(`[Step 0] stderr: ${stderr}`)
|
|
119
139
|
}
|
|
120
140
|
}
|
|
121
141
|
} catch (error) {
|
|
@@ -123,6 +143,19 @@ export async function createD3kSandbox(
|
|
|
123
143
|
console.log(`[Step 0] ${mcpError}`)
|
|
124
144
|
}
|
|
125
145
|
|
|
146
|
+
// Dump all sandbox logs before returning for debugging
|
|
147
|
+
console.log(`[Step 0] === Dumping sandbox logs before returning ===`)
|
|
148
|
+
try {
|
|
149
|
+
const logsResult = await runSandboxCommand(sandboxResult.sandbox, "sh", [
|
|
150
|
+
"-c",
|
|
151
|
+
'for log in /home/vercel-sandbox/.d3k/logs/*.log; do [ -f "$log" ] && echo "=== $log ===" && tail -100 "$log" || true; done 2>/dev/null || echo "No log files found"'
|
|
152
|
+
])
|
|
153
|
+
console.log(logsResult.stdout)
|
|
154
|
+
} catch (logsError) {
|
|
155
|
+
console.log(`[Step 0] Failed to dump logs: ${logsError instanceof Error ? logsError.message : String(logsError)}`)
|
|
156
|
+
}
|
|
157
|
+
console.log(`[Step 0] === End sandbox log dump ===`)
|
|
158
|
+
|
|
126
159
|
// Note: We cannot return the cleanup function or sandbox object as they're not serializable
|
|
127
160
|
// Sandbox cleanup will happen automatically when the sandbox times out
|
|
128
161
|
return {
|
|
@@ -150,7 +183,7 @@ export async function fetchRealLogs(
|
|
|
150
183
|
// If we already have CLS data from Step 0, use it
|
|
151
184
|
if (clsData) {
|
|
152
185
|
console.log("[Step 1] Using CLS data captured in Step 0")
|
|
153
|
-
return JSON.stringify(clsData, null, 2)
|
|
186
|
+
return { logAnalysis: JSON.stringify(clsData, null, 2), beforeScreenshotUrl: null }
|
|
154
187
|
}
|
|
155
188
|
|
|
156
189
|
// If there was an MCP error in Step 0, log it
|
|
@@ -181,7 +214,10 @@ export async function fetchRealLogs(
|
|
|
181
214
|
console.log("[Step 1] Using d3k MCP server to capture CLS metrics and errors...")
|
|
182
215
|
|
|
183
216
|
// First, validate MCP server access and list available tools
|
|
217
|
+
// Use a 30-second timeout to avoid hanging the entire workflow
|
|
184
218
|
console.log("[Step 1] Validating d3k MCP server access...")
|
|
219
|
+
const validationController = new AbortController()
|
|
220
|
+
const validationTimeout = setTimeout(() => validationController.abort(), 30000)
|
|
185
221
|
try {
|
|
186
222
|
const toolsResponse = await fetch(`${mcpUrl}/mcp`, {
|
|
187
223
|
method: "POST",
|
|
@@ -193,13 +229,32 @@ export async function fetchRealLogs(
|
|
|
193
229
|
jsonrpc: "2.0",
|
|
194
230
|
id: 0,
|
|
195
231
|
method: "tools/list"
|
|
196
|
-
})
|
|
232
|
+
}),
|
|
233
|
+
signal: validationController.signal
|
|
197
234
|
})
|
|
235
|
+
clearTimeout(validationTimeout)
|
|
198
236
|
|
|
199
237
|
if (toolsResponse.ok) {
|
|
200
238
|
const toolsText = await toolsResponse.text()
|
|
201
239
|
try {
|
|
202
|
-
|
|
240
|
+
// Parse SSE response format: "event: message\ndata: {...}\n\n"
|
|
241
|
+
let toolsData = null
|
|
242
|
+
const lines = toolsText.split("\n")
|
|
243
|
+
for (const line of lines) {
|
|
244
|
+
if (line.startsWith("data: ")) {
|
|
245
|
+
try {
|
|
246
|
+
toolsData = JSON.parse(line.substring(6))
|
|
247
|
+
break
|
|
248
|
+
} catch {
|
|
249
|
+
// Continue to next line
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Fallback: try parsing the whole response as JSON (non-SSE format)
|
|
254
|
+
if (!toolsData) {
|
|
255
|
+
toolsData = JSON.parse(toolsText)
|
|
256
|
+
}
|
|
257
|
+
|
|
203
258
|
const toolNames = toolsData.result?.tools?.map((t: { name: string }) => t.name) || []
|
|
204
259
|
console.log(`[Step 1] ✅ d3k MCP server accessible`)
|
|
205
260
|
console.log(`[Step 1] Available tools (${toolNames.length}): ${toolNames.join(", ")}`)
|
|
@@ -219,47 +274,132 @@ export async function fetchRealLogs(
|
|
|
219
274
|
console.log(`[Step 1] ⚠️ MCP server not accessible: ${toolsResponse.status}`)
|
|
220
275
|
}
|
|
221
276
|
} catch (error) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
277
|
+
clearTimeout(validationTimeout)
|
|
278
|
+
const errorMsg = error instanceof Error ? error.message : String(error)
|
|
279
|
+
const isTimeout = error instanceof Error && error.name === "AbortError"
|
|
280
|
+
console.log(`[Step 1] ⚠️ Failed to validate MCP server: ${isTimeout ? "Timed out after 30s" : errorMsg}`)
|
|
225
281
|
}
|
|
226
282
|
|
|
227
|
-
// Navigate to the app to generate logs
|
|
283
|
+
// Navigate to the app to generate logs (with 30s timeout)
|
|
228
284
|
console.log("[Step 1] Navigating browser to app URL...")
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
285
|
+
const navController = new AbortController()
|
|
286
|
+
const navTimeout = setTimeout(() => navController.abort(), 30000)
|
|
287
|
+
try {
|
|
288
|
+
const navResponse = await fetch(`${mcpUrl}/mcp`, {
|
|
289
|
+
method: "POST",
|
|
290
|
+
headers: {
|
|
291
|
+
"Content-Type": "application/json",
|
|
292
|
+
Accept: "application/json, text/event-stream"
|
|
293
|
+
},
|
|
294
|
+
body: JSON.stringify({
|
|
295
|
+
jsonrpc: "2.0",
|
|
296
|
+
id: 0,
|
|
297
|
+
method: "tools/call",
|
|
298
|
+
params: {
|
|
299
|
+
name: "execute_browser_action",
|
|
300
|
+
arguments: {
|
|
301
|
+
action: "navigate",
|
|
302
|
+
params: { url: urlWithBypass }
|
|
303
|
+
}
|
|
244
304
|
}
|
|
245
|
-
}
|
|
305
|
+
}),
|
|
306
|
+
signal: navController.signal
|
|
246
307
|
})
|
|
247
|
-
|
|
308
|
+
clearTimeout(navTimeout)
|
|
248
309
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
310
|
+
if (navResponse.ok) {
|
|
311
|
+
console.log("[Step 1] Browser navigation completed")
|
|
312
|
+
} else {
|
|
313
|
+
console.log(`[Step 1] Browser navigation failed: ${navResponse.status}`)
|
|
314
|
+
}
|
|
315
|
+
} catch (navError) {
|
|
316
|
+
clearTimeout(navTimeout)
|
|
317
|
+
const isTimeout = navError instanceof Error && navError.name === "AbortError"
|
|
318
|
+
console.log(
|
|
319
|
+
`[Step 1] Browser navigation error: ${isTimeout ? "Timed out after 30s" : navError instanceof Error ? navError.message : String(navError)}`
|
|
320
|
+
)
|
|
253
321
|
}
|
|
254
322
|
|
|
255
323
|
// Wait for page to fully load
|
|
256
324
|
console.log("[Step 1] Waiting 5s for page load...")
|
|
257
325
|
await new Promise((resolve) => setTimeout(resolve, 5000))
|
|
258
326
|
|
|
259
|
-
//
|
|
327
|
+
// Capture "before" screenshot to prove the page loaded and for later comparison
|
|
328
|
+
let beforeScreenshotUrl: string | null = null
|
|
329
|
+
console.log("[Step 1] Capturing 'before' screenshot...")
|
|
330
|
+
const screenshotController = new AbortController()
|
|
331
|
+
const screenshotTimeout = setTimeout(() => screenshotController.abort(), 30000)
|
|
332
|
+
try {
|
|
333
|
+
const screenshotResponse = await fetch(`${mcpUrl}/mcp`, {
|
|
334
|
+
method: "POST",
|
|
335
|
+
headers: {
|
|
336
|
+
"Content-Type": "application/json",
|
|
337
|
+
Accept: "application/json, text/event-stream"
|
|
338
|
+
},
|
|
339
|
+
body: JSON.stringify({
|
|
340
|
+
jsonrpc: "2.0",
|
|
341
|
+
id: 0,
|
|
342
|
+
method: "tools/call",
|
|
343
|
+
params: {
|
|
344
|
+
name: "chrome-devtools_take_snapshot",
|
|
345
|
+
arguments: {}
|
|
346
|
+
}
|
|
347
|
+
}),
|
|
348
|
+
signal: screenshotController.signal
|
|
349
|
+
})
|
|
350
|
+
clearTimeout(screenshotTimeout)
|
|
351
|
+
|
|
352
|
+
if (screenshotResponse.ok) {
|
|
353
|
+
const screenshotText = await screenshotResponse.text()
|
|
354
|
+
// Parse SSE response to get screenshot data
|
|
355
|
+
const lines = screenshotText.split("\n")
|
|
356
|
+
for (const line of lines) {
|
|
357
|
+
if (line.startsWith("data: ")) {
|
|
358
|
+
try {
|
|
359
|
+
const json = JSON.parse(line.substring(6))
|
|
360
|
+
if (json.result?.content) {
|
|
361
|
+
for (const content of json.result.content) {
|
|
362
|
+
if (content.type === "image" && content.data) {
|
|
363
|
+
// Upload base64 image to Vercel Blob
|
|
364
|
+
const imageBuffer = Buffer.from(content.data, "base64")
|
|
365
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-")
|
|
366
|
+
const filename = `screenshot-before-${timestamp}.png`
|
|
367
|
+
const blob = await put(filename, imageBuffer, {
|
|
368
|
+
access: "public",
|
|
369
|
+
contentType: "image/png"
|
|
370
|
+
})
|
|
371
|
+
beforeScreenshotUrl = blob.url
|
|
372
|
+
console.log(`[Step 1] ✅ Before screenshot uploaded: ${beforeScreenshotUrl}`)
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
} catch {
|
|
377
|
+
// Continue parsing other lines
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (!beforeScreenshotUrl) {
|
|
382
|
+
console.log(`[Step 1] Screenshot response received but no image data found`)
|
|
383
|
+
console.log(`[Step 1] Response preview: ${screenshotText.substring(0, 500)}`)
|
|
384
|
+
}
|
|
385
|
+
} else {
|
|
386
|
+
console.log(`[Step 1] Screenshot request failed: ${screenshotResponse.status}`)
|
|
387
|
+
}
|
|
388
|
+
} catch (error) {
|
|
389
|
+
clearTimeout(screenshotTimeout)
|
|
390
|
+
const isTimeout = error instanceof Error && error.name === "AbortError"
|
|
391
|
+
console.log(
|
|
392
|
+
`[Step 1] Screenshot capture error: ${isTimeout ? "Timed out after 30s" : error instanceof Error ? error.message : String(error)}`
|
|
393
|
+
)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Check d3k logs to see if it's capturing data (with 15s timeout)
|
|
260
397
|
console.log("[Step 1] Fetching d3k logs from sandbox to verify it's working...")
|
|
398
|
+
const logsController = new AbortController()
|
|
399
|
+
const logsTimeout = setTimeout(() => logsController.abort(), 15000)
|
|
261
400
|
try {
|
|
262
|
-
const logsResponse = await fetch(`${mcpUrl}/api/logs
|
|
401
|
+
const logsResponse = await fetch(`${mcpUrl}/api/logs`, { signal: logsController.signal })
|
|
402
|
+
clearTimeout(logsTimeout)
|
|
263
403
|
if (logsResponse.ok) {
|
|
264
404
|
const logsText = await logsResponse.text()
|
|
265
405
|
console.log(`[Step 1] d3k logs (last 1000 chars):\n${logsText.slice(-1000)}`)
|
|
@@ -267,7 +407,11 @@ export async function fetchRealLogs(
|
|
|
267
407
|
console.log(`[Step 1] Could not fetch d3k logs: ${logsResponse.status}`)
|
|
268
408
|
}
|
|
269
409
|
} catch (error) {
|
|
270
|
-
|
|
410
|
+
clearTimeout(logsTimeout)
|
|
411
|
+
const isTimeout = error instanceof Error && error.name === "AbortError"
|
|
412
|
+
console.log(
|
|
413
|
+
`[Step 1] Failed to fetch d3k logs: ${isTimeout ? "Timed out after 15s" : error instanceof Error ? error.message : String(error)}`
|
|
414
|
+
)
|
|
271
415
|
}
|
|
272
416
|
|
|
273
417
|
// Call fix_my_app with focusArea='performance' to capture CLS and jank
|
|
@@ -353,7 +497,10 @@ export async function fetchRealLogs(
|
|
|
353
497
|
console.log(`[Step 1] WARNING: fix_my_app returned NO data. Full response:\n${text}`)
|
|
354
498
|
}
|
|
355
499
|
|
|
356
|
-
return
|
|
500
|
+
return {
|
|
501
|
+
logAnalysis: `d3k Performance Analysis for ${devUrl}\n\n${logAnalysis}`,
|
|
502
|
+
beforeScreenshotUrl
|
|
503
|
+
}
|
|
357
504
|
} catch (error) {
|
|
358
505
|
clearTimeout(timeoutId)
|
|
359
506
|
|
|
@@ -407,7 +554,7 @@ Format your response as a clear, structured report that helps identify what's br
|
|
|
407
554
|
})
|
|
408
555
|
|
|
409
556
|
console.log(`[Step 1] Browser automation response (first 500 chars): ${text.substring(0, 500)}...`)
|
|
410
|
-
return `Browser Automation Analysis for ${devUrl}\n\n${text}
|
|
557
|
+
return { logAnalysis: `Browser Automation Analysis for ${devUrl}\n\n${text}`, beforeScreenshotUrl: null }
|
|
411
558
|
} catch (error) {
|
|
412
559
|
console.error("[Step 1] Error with browser automation:", error)
|
|
413
560
|
|
|
@@ -442,10 +589,13 @@ Format your response as a clear, structured report that helps identify what's br
|
|
|
442
589
|
logAnalysis += "No errors detected in response.\n"
|
|
443
590
|
}
|
|
444
591
|
|
|
445
|
-
return logAnalysis
|
|
592
|
+
return { logAnalysis, beforeScreenshotUrl: null }
|
|
446
593
|
} catch (fallbackError) {
|
|
447
594
|
const errorMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError)
|
|
448
|
-
return
|
|
595
|
+
return {
|
|
596
|
+
logAnalysis: `Failed to fetch logs from ${devUrl}\n\nError: ${errorMessage}\n\nThis may indicate the dev server is not accessible or has crashed.`,
|
|
597
|
+
beforeScreenshotUrl: null
|
|
598
|
+
}
|
|
449
599
|
}
|
|
450
600
|
}
|
|
451
601
|
}
|
|
@@ -530,10 +680,32 @@ IMPORTANT:
|
|
|
530
680
|
/**
|
|
531
681
|
* Step 3: Upload fix proposal to blob storage and return URL
|
|
532
682
|
*/
|
|
533
|
-
export async function uploadToBlob(
|
|
683
|
+
export async function uploadToBlob(
|
|
684
|
+
fixProposal: string,
|
|
685
|
+
projectName: string,
|
|
686
|
+
logAnalysis: string,
|
|
687
|
+
devUrl: string,
|
|
688
|
+
beforeScreenshotUrl?: string | null
|
|
689
|
+
) {
|
|
534
690
|
"use step"
|
|
535
691
|
|
|
536
692
|
console.log("[Step 3] Uploading fix proposal to blob storage...")
|
|
693
|
+
if (beforeScreenshotUrl) {
|
|
694
|
+
console.log(`[Step 3] Including before screenshot: ${beforeScreenshotUrl}`)
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Create screenshot section if we have a screenshot
|
|
698
|
+
const screenshotSection = beforeScreenshotUrl
|
|
699
|
+
? `## Before Screenshot
|
|
700
|
+
|
|
701
|
+
This screenshot was captured when the sandbox dev server first loaded, proving the page rendered successfully.
|
|
702
|
+
|
|
703
|
+

|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
`
|
|
708
|
+
: ""
|
|
537
709
|
|
|
538
710
|
// Create enhanced markdown with full context and attribution
|
|
539
711
|
const timestamp = new Date().toISOString()
|
|
@@ -545,7 +717,7 @@ export async function uploadToBlob(fixProposal: string, projectName: string, log
|
|
|
545
717
|
|
|
546
718
|
---
|
|
547
719
|
|
|
548
|
-
## Original Log Analysis
|
|
720
|
+
${screenshotSection}## Original Log Analysis
|
|
549
721
|
|
|
550
722
|
\`\`\`
|
|
551
723
|
${logAnalysis}
|
|
@@ -591,6 +763,7 @@ Learn more at https://github.com/vercel-labs/dev3000
|
|
|
591
763
|
projectName,
|
|
592
764
|
fixProposal,
|
|
593
765
|
blobUrl: blob.url,
|
|
766
|
+
beforeScreenshotUrl: beforeScreenshotUrl || null,
|
|
594
767
|
message: "Fix analysis completed and uploaded to blob storage"
|
|
595
768
|
}
|
|
596
769
|
}
|
|
@@ -73,19 +73,26 @@ export async function cloudFixWorkflow(params: {
|
|
|
73
73
|
// If we got CLS data from Step 0, pass it to Step 1 to avoid re-fetching
|
|
74
74
|
// Use bypass token from sandbox if available, otherwise use provided one
|
|
75
75
|
const effectiveBypassToken = sandboxInfo?.bypassToken || bypassToken
|
|
76
|
-
const
|
|
76
|
+
const step1Result = await fetchRealLogs(
|
|
77
77
|
sandboxInfo?.mcpUrl || devUrl,
|
|
78
78
|
effectiveBypassToken,
|
|
79
79
|
sandboxInfo?.devUrl,
|
|
80
80
|
sandboxInfo?.clsData,
|
|
81
81
|
sandboxInfo?.mcpError
|
|
82
82
|
)
|
|
83
|
+
const { logAnalysis, beforeScreenshotUrl } = step1Result
|
|
83
84
|
|
|
84
85
|
// Step 2: Invoke AI agent to analyze logs and create fix
|
|
85
86
|
const fixProposal = await analyzeLogsWithAgent(logAnalysis, sandboxInfo?.devUrl || devUrl)
|
|
86
87
|
|
|
87
|
-
// Step 3: Upload to blob storage with full context
|
|
88
|
-
const blobResult = await uploadToBlob(
|
|
88
|
+
// Step 3: Upload to blob storage with full context and screenshot
|
|
89
|
+
const blobResult = await uploadToBlob(
|
|
90
|
+
fixProposal,
|
|
91
|
+
projectName,
|
|
92
|
+
logAnalysis,
|
|
93
|
+
sandboxInfo?.devUrl || devUrl,
|
|
94
|
+
beforeScreenshotUrl
|
|
95
|
+
)
|
|
89
96
|
|
|
90
97
|
// Step 4: Create GitHub PR if repo info provided AND there are actual fixes to apply
|
|
91
98
|
let prResult = null
|
|
@@ -124,7 +131,7 @@ async function fetchRealLogs(
|
|
|
124
131
|
sandboxDevUrl?: string,
|
|
125
132
|
clsData?: unknown,
|
|
126
133
|
mcpError?: string | null
|
|
127
|
-
) {
|
|
134
|
+
): Promise<{ logAnalysis: string; beforeScreenshotUrl: string | null }> {
|
|
128
135
|
"use step"
|
|
129
136
|
const { fetchRealLogs } = await import("./steps")
|
|
130
137
|
return fetchRealLogs(mcpUrlOrDevUrl, bypassToken, sandboxDevUrl, clsData, mcpError)
|
|
@@ -136,10 +143,16 @@ async function analyzeLogsWithAgent(logAnalysis: string, devUrl: string) {
|
|
|
136
143
|
return analyzeLogsWithAgent(logAnalysis, devUrl)
|
|
137
144
|
}
|
|
138
145
|
|
|
139
|
-
async function uploadToBlob(
|
|
146
|
+
async function uploadToBlob(
|
|
147
|
+
fixProposal: string,
|
|
148
|
+
projectName: string,
|
|
149
|
+
logAnalysis: string,
|
|
150
|
+
devUrl: string,
|
|
151
|
+
beforeScreenshotUrl?: string | null
|
|
152
|
+
) {
|
|
140
153
|
"use step"
|
|
141
154
|
const { uploadToBlob } = await import("./steps")
|
|
142
|
-
return uploadToBlob(fixProposal, projectName, logAnalysis, devUrl)
|
|
155
|
+
return uploadToBlob(fixProposal, projectName, logAnalysis, devUrl, beforeScreenshotUrl)
|
|
143
156
|
}
|
|
144
157
|
|
|
145
158
|
async function createGitHubPR(
|
|
@@ -134,7 +134,8 @@ export async function POST(request: Request) {
|
|
|
134
134
|
timestamp: new Date().toISOString(),
|
|
135
135
|
status: "success",
|
|
136
136
|
reportBlobUrl: result.blobUrl,
|
|
137
|
-
prUrl: result.pr?.prUrl
|
|
137
|
+
prUrl: result.pr?.prUrl,
|
|
138
|
+
beforeScreenshotUrl: result.beforeScreenshotUrl || undefined
|
|
138
139
|
})
|
|
139
140
|
console.log(`[Start Fix] Updated workflow run metadata to success: ${runId}`)
|
|
140
141
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import Image from "next/image"
|
|
3
4
|
import Link from "next/link"
|
|
4
5
|
import { useState } from "react"
|
|
5
6
|
import { Badge } from "@/components/ui/badge"
|
|
@@ -68,6 +69,8 @@ export default function WorkflowsClient({ user, initialRuns }: WorkflowsClientPr
|
|
|
68
69
|
<TableHead>Project</TableHead>
|
|
69
70
|
<TableHead>Status</TableHead>
|
|
70
71
|
<TableHead>Timestamp</TableHead>
|
|
72
|
+
<TableHead>Before</TableHead>
|
|
73
|
+
<TableHead>After</TableHead>
|
|
71
74
|
<TableHead>Report</TableHead>
|
|
72
75
|
<TableHead>PR</TableHead>
|
|
73
76
|
</TableRow>
|
|
@@ -96,6 +99,38 @@ export default function WorkflowsClient({ user, initialRuns }: WorkflowsClientPr
|
|
|
96
99
|
</Badge>
|
|
97
100
|
</TableCell>
|
|
98
101
|
<TableCell className="text-muted-foreground">{new Date(run.timestamp).toLocaleString()}</TableCell>
|
|
102
|
+
<TableCell>
|
|
103
|
+
{run.beforeScreenshotUrl ? (
|
|
104
|
+
<a href={run.beforeScreenshotUrl} target="_blank" rel="noopener noreferrer">
|
|
105
|
+
<Image
|
|
106
|
+
src={run.beforeScreenshotUrl}
|
|
107
|
+
alt="Before"
|
|
108
|
+
width={64}
|
|
109
|
+
height={40}
|
|
110
|
+
className="object-cover rounded border hover:opacity-80 transition-opacity"
|
|
111
|
+
unoptimized
|
|
112
|
+
/>
|
|
113
|
+
</a>
|
|
114
|
+
) : (
|
|
115
|
+
<span className="text-muted-foreground text-xs">-</span>
|
|
116
|
+
)}
|
|
117
|
+
</TableCell>
|
|
118
|
+
<TableCell>
|
|
119
|
+
{run.afterScreenshotUrl ? (
|
|
120
|
+
<a href={run.afterScreenshotUrl} target="_blank" rel="noopener noreferrer">
|
|
121
|
+
<Image
|
|
122
|
+
src={run.afterScreenshotUrl}
|
|
123
|
+
alt="After"
|
|
124
|
+
width={64}
|
|
125
|
+
height={40}
|
|
126
|
+
className="object-cover rounded border hover:opacity-80 transition-opacity"
|
|
127
|
+
unoptimized
|
|
128
|
+
/>
|
|
129
|
+
</a>
|
|
130
|
+
) : (
|
|
131
|
+
<span className="text-muted-foreground text-xs">-</span>
|
|
132
|
+
)}
|
|
133
|
+
</TableCell>
|
|
99
134
|
<TableCell>
|
|
100
135
|
{run.reportBlobUrl ? (
|
|
101
136
|
<Link href={`/workflows/${run.id}/report`} className="text-primary hover:underline">
|
package/package.json
CHANGED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},65071,(a,b,c)=>{"use strict";b.exports=a.r(18622)},55205,(a,b,c)=>{"use strict";b.exports=a.r(65071).vendored["react-ssr"].ReactJsxRuntime},33857,(a,b,c)=>{"use strict";b.exports=a.r(65071).vendored["react-ssr"].React},27125,(a,b,c)=>{"use strict";b.exports=a.r(65071).vendored.contexts.AppRouterContext},77279,(a,b,c)=>{"use strict";b.exports=a.r(65071).vendored["react-ssr"].ReactServerDOMTurbopackClient},3988,(a,b,c)=>{"use strict";function d(a){if("function"!=typeof WeakMap)return null;var b=new WeakMap,c=new WeakMap;return(d=function(a){return a?c:b})(a)}c._=function(a,b){if(!b&&a&&a.__esModule)return a;if(null===a||"object"!=typeof a&&"function"!=typeof a)return{default:a};var c=d(b);if(c&&c.has(a))return c.get(a);var e={__proto__:null},f=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var g in a)if("default"!==g&&Object.prototype.hasOwnProperty.call(a,g)){var h=f?Object.getOwnPropertyDescriptor(a,g):null;h&&(h.get||h.set)?Object.defineProperty(e,g,h):e[g]=a[g]}return e.default=a,c&&c.set(a,e),e}},71075,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"useMergedRef",{enumerable:!0,get:function(){return e}});let d=a.r(33857);function e(a,b){let c=(0,d.useRef)(null),e=(0,d.useRef)(null);return(0,d.useCallback)(d=>{if(null===d){let a=c.current;a&&(c.current=null,a());let b=e.current;b&&(e.current=null,b())}else a&&(c.current=f(a,d)),b&&(e.current=f(b,d))},[a,b])}function f(a,b){if("function"!=typeof a)return a.current=b,()=>{a.current=null};{let c=a(b);return"function"==typeof c?c:()=>a(null)}}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},32570,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"warnOnce",{enumerable:!0,get:function(){return d}});let d=a=>{}},16274,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={DEFAULT_SEGMENT_KEY:function(){return l},PAGE_SEGMENT_KEY:function(){return k},addSearchParamsIfPageSegment:function(){return i},computeSelectedLayoutSegment:function(){return j},getSegmentValue:function(){return f},getSelectedLayoutSegmentPath:function(){return function a(b,c,d=!0,e=[]){let g;if(d)g=b[1][c];else{let a=b[1];g=a.children??Object.values(a)[0]}if(!g)return e;let h=f(g[0]);return!h||h.startsWith(k)?e:(e.push(h),a(g,c,!1,e))}},isGroupSegment:function(){return g},isParallelRouteSegment:function(){return h}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});function f(a){return Array.isArray(a)?a[1]:a}function g(a){return"("===a[0]&&a.endsWith(")")}function h(a){return a.startsWith("@")&&"@children"!==a}function i(a,b){if(a.includes(k)){let a=JSON.stringify(b);return"{}"!==a?k+"?"+a:k}return a}function j(a,b){if(!a||0===a.length)return null;let c="children"===b?a[0]:a[a.length-1];return c===l?null:c}let k="__PAGE__",l="__DEFAULT__"},60019,a=>{"use strict";var b=a.i(55205),c=a.i(77696),d=a.i(42261),e=a.i(18749);let f=(0,d.cva)("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",{variants:{variant:{default:"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",destructive:"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",secondary:"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2 has-[>svg]:px-3",sm:"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",lg:"h-10 rounded-md px-6 has-[>svg]:px-4",icon:"size-9"}},defaultVariants:{variant:"default",size:"default"}});function g({className:a,variant:d,size:g,asChild:h=!1,...i}){let j=h?c.Slot:"button";return(0,b.jsx)(j,{"data-slot":"button",className:(0,e.cn)(f({variant:d,size:g,className:a})),...i})}a.s(["Button",()=>g])},25988,a=>{"use strict";var b=a.i(55205),c=a.i(18749);function d({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card",className:(0,c.cn)("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",a),...d})}function e({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-header",className:(0,c.cn)("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",a),...d})}function f({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-title",className:(0,c.cn)("leading-none font-semibold",a),...d})}function g({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-content",className:(0,c.cn)("px-6",a),...d})}a.s(["Card",()=>d,"CardContent",()=>g,"CardHeader",()=>e,"CardTitle",()=>f])},24501,a=>{"use strict";var b=a.i(55205),c=a.i(7287),d=a.i(33857),e=a.i(77696),f=a.i(42261),g=a.i(18749);let h=(0,f.cva)("inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",secondary:"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",destructive:"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"}},defaultVariants:{variant:"default"}});function i({className:a,variant:c,asChild:d=!1,...f}){let i=d?e.Slot:"span";return(0,b.jsx)(i,{"data-slot":"badge",className:(0,g.cn)(h({variant:c}),a),...f})}var j=a.i(60019),k=a.i(25988);function l({className:a,...c}){return(0,b.jsx)("div",{"data-slot":"table-container",className:"relative w-full overflow-x-auto",children:(0,b.jsx)("table",{"data-slot":"table",className:(0,g.cn)("w-full caption-bottom text-sm",a),...c})})}function m({className:a,...c}){return(0,b.jsx)("thead",{"data-slot":"table-header",className:(0,g.cn)("[&_tr]:border-b",a),...c})}function n({className:a,...c}){return(0,b.jsx)("tbody",{"data-slot":"table-body",className:(0,g.cn)("[&_tr:last-child]:border-0",a),...c})}function o({className:a,...c}){return(0,b.jsx)("tr",{"data-slot":"table-row",className:(0,g.cn)("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",a),...c})}function p({className:a,...c}){return(0,b.jsx)("th",{"data-slot":"table-head",className:(0,g.cn)("text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",a),...c})}function q({className:a,...c}){return(0,b.jsx)("td",{"data-slot":"table-cell",className:(0,g.cn)("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",a),...c})}function r({user:a,initialRuns:e}){let[f,g]=(0,d.useState)(!1);async function h(){g(!0);try{await fetch("/api/auth/signout",{method:"POST"}),window.location.href="/"}catch(a){console.error("Failed to sign out:",a),g(!1)}}return(0,b.jsx)("div",{className:"min-h-screen bg-gray-50 py-8",children:(0,b.jsxs)("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:[(0,b.jsxs)("div",{className:"mb-8 flex justify-between items-start",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-3xl font-bold text-gray-900",children:"d3k Workflow Runs"}),(0,b.jsx)("p",{className:"mt-2 text-gray-600",children:"View all your d3k workflow fix proposals and PRs"}),(0,b.jsxs)("p",{className:"mt-1 text-sm text-gray-500",children:["Signed in as ",a.email]})]}),(0,b.jsxs)("div",{className:"flex gap-3",children:[(0,b.jsx)(j.Button,{asChild:!0,children:(0,b.jsx)(c.default,{href:"/workflows/new",children:"New Workflow"})}),(0,b.jsx)(j.Button,{variant:"outline",onClick:h,disabled:f,children:f?"Signing out...":"Sign out"})]})]}),0===e.length?(0,b.jsx)(k.Card,{className:"p-12 text-center",children:(0,b.jsxs)(k.CardContent,{children:[(0,b.jsx)("p",{className:"text-muted-foreground",children:"No workflow runs yet"}),(0,b.jsx)("p",{className:"text-sm text-muted-foreground/70 mt-2",children:"Run a workflow from the CLI to see it appear here"})]})}):(0,b.jsx)(k.Card,{children:(0,b.jsxs)(l,{children:[(0,b.jsx)(m,{children:(0,b.jsxs)(o,{children:[(0,b.jsx)(p,{children:"Project"}),(0,b.jsx)(p,{children:"Status"}),(0,b.jsx)(p,{children:"Timestamp"}),(0,b.jsx)(p,{children:"Report"}),(0,b.jsx)(p,{children:"PR"})]})}),(0,b.jsx)(n,{children:e.map(a=>(0,b.jsxs)(o,{children:[(0,b.jsxs)(q,{children:[(0,b.jsx)("div",{className:"font-medium",children:a.projectName}),(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:a.id})]}),(0,b.jsx)(q,{children:(0,b.jsx)(i,{variant:"success"===a.status?"secondary":"running"===a.status?"default":"destructive",className:"success"===a.status?"bg-green-100 text-green-800 hover:bg-green-100":"running"===a.status?"bg-blue-100 text-blue-800 hover:bg-blue-100":"",children:a.status})}),(0,b.jsx)(q,{className:"text-muted-foreground",children:new Date(a.timestamp).toLocaleString()}),(0,b.jsx)(q,{children:a.reportBlobUrl?(0,b.jsx)(c.default,{href:`/workflows/${a.id}/report`,className:"text-primary hover:underline",children:"View Report"}):(0,b.jsx)("span",{className:"text-muted-foreground",children:"No report"})}),(0,b.jsx)(q,{children:a.prUrl?(0,b.jsx)("a",{href:a.prUrl,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:"View PR"}):(0,b.jsx)("span",{className:"text-muted-foreground",children:"No PR"})})]},`${a.id}-${a.timestamp}`))})]})})]})})}a.s(["default",()=>r],24501)}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__3a2dacc6._.js.map
|