dev3000 0.0.101 → 0.0.103

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 (48) hide show
  1. package/README.md +2 -0
  2. package/dist/dev-environment.d.ts +1 -0
  3. package/dist/dev-environment.d.ts.map +1 -1
  4. package/dist/dev-environment.js +52 -8
  5. package/dist/dev-environment.js.map +1 -1
  6. package/dist/screencast-manager.d.ts.map +1 -1
  7. package/dist/screencast-manager.js +3 -4
  8. package/dist/screencast-manager.js.map +1 -1
  9. package/dist/src/tui-interface-impl.tsx +7 -1
  10. package/dist/tui-interface-impl.d.ts.map +1 -1
  11. package/dist/tui-interface-impl.js +4 -1
  12. package/dist/tui-interface-impl.js.map +1 -1
  13. package/mcp-server/.next/BUILD_ID +1 -1
  14. package/mcp-server/.next/build-manifest.json +2 -2
  15. package/mcp-server/.next/fallback-build-manifest.json +2 -2
  16. package/mcp-server/.next/prerender-manifest.json +3 -3
  17. package/mcp-server/.next/server/app/_global-error.html +2 -2
  18. package/mcp-server/.next/server/app/_global-error.rsc +1 -1
  19. package/mcp-server/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  20. package/mcp-server/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  21. package/mcp-server/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  22. package/mcp-server/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  23. package/mcp-server/.next/server/app/_not-found.html +1 -1
  24. package/mcp-server/.next/server/app/_not-found.rsc +1 -1
  25. package/mcp-server/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  26. package/mcp-server/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  27. package/mcp-server/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  28. package/mcp-server/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  29. package/mcp-server/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  30. package/mcp-server/.next/server/app/index.html +1 -1
  31. package/mcp-server/.next/server/app/index.rsc +1 -1
  32. package/mcp-server/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  33. package/mcp-server/.next/server/app/index.segments/_full.segment.rsc +1 -1
  34. package/mcp-server/.next/server/app/index.segments/_index.segment.rsc +1 -1
  35. package/mcp-server/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  36. package/mcp-server/.next/server/chunks/[root-of-the-server]__0691849a._.js +1 -1
  37. package/mcp-server/.next/server/chunks/[root-of-the-server]__0691849a._.js.map +1 -1
  38. package/mcp-server/.next/server/chunks/[root-of-the-server]__ae49815f._.js +78 -15
  39. package/mcp-server/.next/server/chunks/[root-of-the-server]__ae49815f._.js.map +1 -1
  40. package/mcp-server/.next/server/server-reference-manifest.js +1 -1
  41. package/mcp-server/.next/server/server-reference-manifest.json +1 -1
  42. package/mcp-server/app/mcp/route.ts +28 -2
  43. package/mcp-server/app/mcp/tools.ts +486 -3
  44. package/package.json +2 -1
  45. package/src/tui-interface-impl.tsx +7 -1
  46. /package/mcp-server/.next/static/{eVcHKbTsqk-_vUXyVOoaO → I_0vbzGzd9Y9Tse-yfGKd}/_buildManifest.js +0 -0
  47. /package/mcp-server/.next/static/{eVcHKbTsqk-_vUXyVOoaO → I_0vbzGzd9Y9Tse-yfGKd}/_clientMiddlewareManifest.json +0 -0
  48. /package/mcp-server/.next/static/{eVcHKbTsqk-_vUXyVOoaO → I_0vbzGzd9Y9Tse-yfGKd}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"/PxvsAvzRaWzXUHwWLug3ZcveweVRuE36Tz0vOuDXP8=\"\n}"
1
+ self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"5LNEsGYjtwWobrqfCSeqJHwMBqVNoQL+Ca6PZ7kLWsc=\"\n}"
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "node": {},
3
3
  "edge": {},
4
- "encryptionKey": "/PxvsAvzRaWzXUHwWLug3ZcveweVRuE36Tz0vOuDXP8="
4
+ "encryptionKey": "5LNEsGYjtwWobrqfCSeqJHwMBqVNoQL+Ca6PZ7kLWsc="
5
5
  }
@@ -5,7 +5,14 @@ import type { Tool } from "@modelcontextprotocol/sdk/types.js"
5
5
  import { createMcpHandler } from "mcp-handler"
6
6
  import { z } from "zod"
7
7
  import { getMCPClientManager } from "./client-manager"
8
- import { executeBrowserAction, findComponentSource, fixMyApp, restartDevServer, TOOL_DESCRIPTIONS } from "./tools"
8
+ import {
9
+ crawlApp,
10
+ executeBrowserAction,
11
+ findComponentSource,
12
+ fixMyApp,
13
+ restartDevServer,
14
+ TOOL_DESCRIPTIONS
15
+ } from "./tools"
9
16
 
10
17
  // Detect available package runner (bunx, npx, pnpm dlx, or fail)
11
18
  const getPackageRunner = (): { command: string; args: string[] } | null => {
@@ -412,7 +419,8 @@ const handler = createMcpHandler(
412
419
  returnRawData: z
413
420
  .boolean()
414
421
  .optional()
415
- .describe("Return structured data for Claude orchestration instead of formatted text")
422
+ .describe("Return structured data for Claude orchestration instead of formatted text"),
423
+ createPR: z.boolean().optional().describe("Create a PR for the highest priority issue (default: false)")
416
424
  },
417
425
  async (params) => {
418
426
  return fixMyApp(params)
@@ -502,6 +510,24 @@ const handler = createMcpHandler(
502
510
  }
503
511
  )
504
512
 
513
+ // App crawler tool
514
+ server.tool(
515
+ "crawl_app",
516
+ TOOL_DESCRIPTIONS.crawl_app,
517
+ {
518
+ depth: z
519
+ .union([z.number().int().min(1), z.literal("all")])
520
+ .optional()
521
+ .describe(
522
+ "Crawl depth: number (1=homepage only, 2=homepage+next level, etc.) or 'all' for exhaustive (default: 1)"
523
+ ),
524
+ projectName: z.string().optional().describe("Project name (if multiple dev3000 instances are running)")
525
+ },
526
+ async (params) => {
527
+ return crawlApp(params)
528
+ }
529
+ )
530
+
505
531
  // Tool that returns monitoring code for Claude to execute
506
532
  // TODO: Commenting out for now - need to figure out the right approach for proactive monitoring
507
533
  /*
@@ -12,7 +12,7 @@ const execAsync = promisify(exec)
12
12
  // Tool descriptions
13
13
  export const TOOL_DESCRIPTIONS = {
14
14
  fix_my_app:
15
- "🔧 **THE ULTIMATE FIND→FIX→VERIFY MACHINE!** This tool doesn't just find bugs - it FIXES them! Pure dev3000 magic that identifies issues, provides exact fixes, and verifies everything works! 🪄\n\n🔥 **INSTANT FIXING SUPERPOWERS:**\n• Detects ALL error types: server crashes, browser errors, build failures, API issues, performance problems\n• Shows EXACT user interactions that triggered each error (clicks, navigation, etc.)\n• Provides EXACT fix code with file locations and line numbers\n• Guides you through implementing fixes step-by-step\n• Verifies fixes by replaying the same interactions that caused the error!\n\n📍 **INTERACTION-BASED VERIFICATION:**\n• Every error includes the user interactions that led to it\n• Use execute_browser_action to replay these exact interactions\n• Verify your fix works by confirming the error doesn't reoccur\n• Example: Error shows '[INTERACTION] Click at (450,300)' → After fix, use execute_browser_action(action='click', params={x:450, y:300}) to verify\n\n⚡ **3 ACTION MODES:**\n• FIX NOW: 'What's broken RIGHT NOW?' → Find and fix immediately\n• FIX REGRESSION: 'What broke during testing?' → Compare before/after and fix\n• FIX CONTINUOUSLY: 'Fix issues as they appear' → Monitor and fix proactively\n\n🎪 **THE FIX-IT WORKFLOW:**\n1️⃣ I FIND all issues with their triggering interactions\n2️⃣ I provide EXACT FIXES with code snippets\n3️⃣ You implement the fixes\n4️⃣ We REPLAY the interactions to VERIFY everything works\n\n💡 **PERFECT FOR:** 'fix my app' or 'debug my app' requests, error resolution, code repairs, making broken apps work again. This tool doesn't just identify problems - it SOLVES them with precise reproduction steps!",
15
+ "🔧 **THE ULTIMATE FIND→FIX→VERIFY MACHINE!** This tool doesn't just find bugs - it FIXES them! Pure dev3000 magic that identifies issues, prioritizes them, and creates focused PRs for the worst issue! 🪄\n\n🔥 **INSTANT FIXING SUPERPOWERS:**\n• Detects ALL error types: server crashes, browser errors, build failures, API issues, performance problems\n• **PRIORITIZES errors** using smart scoring (build > server > browser > network > warnings)\n• **Identifies the SINGLE WORST issue** that needs fixing right now\n• **Creates ONE focused PR** per run - no overwhelming multi-issue PRs!\n• Shows EXACT user interactions that triggered each error (clicks, navigation, etc.)\n• Provides EXACT fix code with file locations and line numbers\n• Verifies fixes by replaying the same interactions that caused the error!\n\n🎯 **SMART PRIORITIZATION:**\n• Build errors: 1000+ priority (blocks development)\n• Server errors: 500+ priority (affects functionality)\n• Browser errors: 300+ priority (user-facing issues)\n• Network errors: 200+ priority (intermittent issues)\n• Warnings: 100+ priority (nice to fix)\n• +Modifiers: Multiple occurrences, recency, reproducibility\n\n🚀 **ONE-PR-PER-RUN WORKFLOW:**\n1️⃣ I FIND all issues and their interactions\n2️⃣ I PRIORITIZE using smart scoring algorithm\n3️⃣ I IDENTIFY the single worst issue\n4️⃣ Set createPR=true to CREATE A FOCUSED PR for just that issue\n5️⃣ Fix that ONE issue, then run again for the next worst issue\n\n📍 **INTERACTION-BASED VERIFICATION:**\n• Every error includes the user interactions that led to it\n• Use execute_browser_action to replay these exact interactions\n• Verify your fix works by confirming the error doesn't reoccur\n• Example: Error shows '[INTERACTION] Click at (450,300)' → After fix, use execute_browser_action(action='click', params={x:450, y:300}) to verify\n\n⚡ **3 ACTION MODES:**\n• FIX NOW: 'What's broken RIGHT NOW?' → Find worst issue and optionally create PR\n• FIX REGRESSION: 'What broke during testing?' → Compare before/after and fix worst issue\n• FIX CONTINUOUSLY: 'Fix issues as they appear' → Monitor and fix proactively\n\n💡 **PERFECT FOR:** 'fix my app' or 'debug my app' or 'create pr for worst issue' requests. This tool identifies problems, ranks them by severity, and creates focused single-issue PRs - not giant multi-fix PRs!",
16
16
 
17
17
  execute_browser_action:
18
18
  "🌐 **INTELLIGENT BROWSER AUTOMATION** - Smart browser action routing that automatically delegates to chrome-devtools MCP when available for superior automation capabilities.\n\n🎯 **INTELLIGENT DELEGATION:**\n• Screenshots → chrome-devtools MCP (better quality, no conflicts)\n• Navigation → chrome-devtools MCP (more reliable page handling)\n• Clicks → chrome-devtools MCP (precise coordinate-based interaction)\n• JavaScript evaluation → chrome-devtools MCP (enhanced debugging)\n• Scrolling & typing → dev3000 fallback (specialized actions)\n\n⚡ **PROGRESSIVE ENHANCEMENT:**\n• Uses chrome-devtools MCP when available for best results\n• Falls back to dev3000's native implementation when chrome-devtools unavailable\n• Shares the same Chrome instance via CDP URL coordination\n• Eliminates browser conflicts between tools\n\n💡 **PERFECT FOR:** Browser automation that automatically chooses the best tool for each action, ensuring optimal results whether chrome-devtools MCP is available or not.",
@@ -24,7 +24,10 @@ export const TOOL_DESCRIPTIONS = {
24
24
  "🔍 **COMPONENT SOURCE FINDER** - Maps DOM elements to their source code by extracting the React component function and finding unique patterns to search for.\n\n🎯 **HOW IT WORKS:**\n• Inspects the element via Chrome DevTools Protocol\n• Extracts the React component function source using .toString()\n• Identifies unique code patterns (specific JSX, classNames, imports)\n• Returns targeted grep patterns to find the exact source file\n\n💡 **PERFECT FOR:** Finding which file contains the code for a specific element, especially useful for CLS debugging when you need to fix layout shifts in specific components.",
25
25
 
26
26
  restart_dev_server:
27
- "🔄 **DEV SERVER RESTART** - Safely restarts the development server while preserving dev3000's monitoring, logs, and browser connection.\n\n🎯 **SMART RESTART LOGIC:**\n• First tries nextjs-dev MCP restart (if available and user has Next.js canary)\n• Falls back to dev3000's own restart mechanism:\n - Kills the old server process on the app port\n - Waits for clean shutdown\n - Spawns a new server with the same command that was originally used\n - Keeps dev3000's MCP server, browser monitoring, and screenshot capture running\n• All logging continues seamlessly - no data loss\n• Browser monitoring stays connected - no need to relaunch Chrome\n\n⚡ **WHEN TO USE:**\n• After modifying next.config.js, middleware, or environment variables\n• When you need a clean restart to clear server state\n• After significant code changes that Next.js HMR can't handle\n• When debugging persistent state or memory issues\n\n⚠️ **CRITICAL - DO NOT:**\n• ❌ NEVER manually run kill commands on the dev server like `pkill -f \"next dev\"` or `lsof -ti :3000 | xargs kill`\n• ❌ NEVER manually start the dev server with `npm run dev`, `pnpm dev`, `next dev`, etc.\n• ✅ ALWAYS use this tool for dev server restarts - it preserves all dev3000 infrastructure\n\n⚠️ **IMPORTANT:**\n• AVOID using this unnecessarily - Next.js HMR handles most changes automatically\n• Only restart when truly needed for config changes or state issues\n• The server will be offline for a few seconds during restart\n• Browser may show connection error briefly while server restarts\n\n💡 **PERFECT FOR:** 'restart the dev server', 'clean restart', 'reload the server' - but only when actually needed, not for regular code changes."
27
+ "🔄 **DEV SERVER RESTART** - Safely restarts the development server while preserving dev3000's monitoring, logs, and browser connection.\n\n🎯 **SMART RESTART LOGIC:**\n• First tries nextjs-dev MCP restart (if available and user has Next.js canary)\n• Falls back to dev3000's own restart mechanism:\n - Kills the old server process on the app port\n - Waits for clean shutdown\n - Spawns a new server with the same command that was originally used\n - Keeps dev3000's MCP server, browser monitoring, and screenshot capture running\n• All logging continues seamlessly - no data loss\n• Browser monitoring stays connected - no need to relaunch Chrome\n\n⚡ **WHEN TO USE:**\n• After modifying next.config.js, middleware, or environment variables\n• When you need a clean restart to clear server state\n• After significant code changes that Next.js HMR can't handle\n• When debugging persistent state or memory issues\n\n⚠️ **CRITICAL - DO NOT:**\n• ❌ NEVER manually run kill commands on the dev server like `pkill -f \"next dev\"` or `lsof -ti :3000 | xargs kill`\n• ❌ NEVER manually start the dev server with `npm run dev`, `pnpm dev`, `next dev`, etc.\n• ✅ ALWAYS use this tool for dev server restarts - it preserves all dev3000 infrastructure\n\n⚠️ **IMPORTANT:**\n• AVOID using this unnecessarily - Next.js HMR handles most changes automatically\n• Only restart when truly needed for config changes or state issues\n• The server will be offline for a few seconds during restart\n• Browser may show connection error briefly while server restarts\n\n💡 **PERFECT FOR:** 'restart the dev server', 'clean restart', 'reload the server' - but only when actually needed, not for regular code changes.",
28
+
29
+ crawl_app:
30
+ "🕷️ **APP CRAWLER** - Discovers all URLs in your app by crawling links starting from the homepage. Perfect for finding every page before running fixes or tests across your entire site.\n\n🎯 **SMART CRAWLING:**\n• Starts at your app's homepage (localhost)\n• Discovers all unique URLs at specified depth\n• Depth 1 = homepage links only\n• Depth 2 = homepage + links from those pages\n• Depth 'all' = exhaustive crawl until no new links found\n• Only follows same-origin links (stays within your app)\n• Deduplicates URLs automatically\n\n📊 **OUTPUT:**\n• List of all discovered URLs\n• Total count of unique pages\n• Depth reached\n• Ready to use with fix_my_app or other tools\n\n💡 **PERFECT FOR:**\n• 'crawl my app' or 'crawl my shit' - discover all pages\n• 'crawl my app and fix my shit' - find all pages then run fixes\n• Site-wide testing and debugging\n• Verifying all routes work before deployment\n\n⚡ **USAGE:**\n• Default: depth 1 (just homepage links)\n• Specify depth: 'crawl at depth 2' or depth=2\n• Full crawl: 'crawl all pages' or depth='all'"
28
31
  }
29
32
 
30
33
  // Types
@@ -46,6 +49,7 @@ export interface FixMyAppParams {
46
49
  integrateNextjs?: boolean
47
50
  integrateChromeDevtools?: boolean
48
51
  returnRawData?: boolean
52
+ createPR?: boolean // Create a PR for the highest priority issue
49
53
  }
50
54
 
51
55
  export interface CreateIntegratedWorkflowParams {
@@ -119,6 +123,259 @@ export interface StructuredAnalysisResult {
119
123
  }
120
124
  }
121
125
 
126
+ export interface PrioritizedError {
127
+ error: string
128
+ category: "build" | "server" | "browser" | "network" | "warning"
129
+ severity: "critical" | "error" | "warning"
130
+ priorityScore: number
131
+ interactions: string[]
132
+ timestamp?: string
133
+ suggestedFix?: string
134
+ }
135
+
136
+ // Helper functions
137
+
138
+ /**
139
+ * Calculate priority score for an error
140
+ * Higher score = higher priority to fix
141
+ *
142
+ * Scoring system:
143
+ * - Build errors: 1000+ (blocks development)
144
+ * - Server errors: 500+ (affects functionality)
145
+ * - Browser errors: 300+ (user-facing issues)
146
+ * - Network errors: 200+ (intermittent issues)
147
+ * - Warnings: 100+ (nice to fix)
148
+ *
149
+ * Additional modifiers:
150
+ * - Multiple occurrences: +50 per occurrence
151
+ * - Recent (last minute): +100
152
+ * - Has user interactions: +50 (reproducible)
153
+ */
154
+ function calculateErrorPriority(
155
+ errorLine: string,
156
+ category: PrioritizedError["category"],
157
+ interactions: string[],
158
+ allErrors: string[]
159
+ ): number {
160
+ let score = 0
161
+
162
+ // Base score by category
163
+ if (category === "build") {
164
+ score = 1000
165
+ } else if (category === "server") {
166
+ score = 500
167
+ } else if (category === "browser") {
168
+ score = 300
169
+ } else if (category === "network") {
170
+ score = 200
171
+ } else if (category === "warning") {
172
+ score = 100
173
+ }
174
+
175
+ // Severity multipliers
176
+ if (/CRITICAL|FATAL|crashed/i.test(errorLine)) {
177
+ score *= 2
178
+ } else if (/ERROR|Exception|FAIL/i.test(errorLine)) {
179
+ score *= 1.5
180
+ }
181
+
182
+ // Count occurrences of similar errors
183
+ const errorPattern = errorLine.replace(/\d+/g, "\\d+").substring(0, 100)
184
+ const occurrences = allErrors.filter((e) => new RegExp(errorPattern).test(e)).length
185
+ if (occurrences > 1) {
186
+ score += (occurrences - 1) * 50
187
+ }
188
+
189
+ // Boost if has interactions (reproducible)
190
+ if (interactions.length > 0) {
191
+ score += 50
192
+ }
193
+
194
+ // Boost if recent (within last minute)
195
+ const timestampMatch = errorLine.match(/\[(\d{2}):(\d{2}):(\d{2})\.\d{3}\]/)
196
+ if (timestampMatch) {
197
+ const now = new Date()
198
+ const errorTime = new Date()
199
+ errorTime.setHours(parseInt(timestampMatch[1], 10))
200
+ errorTime.setMinutes(parseInt(timestampMatch[2], 10))
201
+ errorTime.setSeconds(parseInt(timestampMatch[3], 10))
202
+
203
+ const ageMinutes = (now.getTime() - errorTime.getTime()) / 1000 / 60
204
+ if (ageMinutes < 1) {
205
+ score += 100
206
+ }
207
+ }
208
+
209
+ return score
210
+ }
211
+
212
+ /**
213
+ * Find the single highest priority error from categorized errors
214
+ */
215
+ function findHighestPriorityError(
216
+ categorizedErrors: {
217
+ serverErrors: string[]
218
+ browserErrors: string[]
219
+ buildErrors: string[]
220
+ networkErrors: string[]
221
+ warnings: string[]
222
+ },
223
+ allErrors: string[],
224
+ logLines: string[]
225
+ ): PrioritizedError | null {
226
+ const prioritizedErrors: PrioritizedError[] = []
227
+
228
+ // Helper to find interactions before an error
229
+ const findInteractions = (errorLine: string): string[] => {
230
+ const errorIndex = logLines.indexOf(errorLine)
231
+ if (errorIndex === -1) return []
232
+
233
+ const interactions: string[] = []
234
+ for (let i = errorIndex - 1; i >= Math.max(0, errorIndex - 20) && interactions.length < 5; i--) {
235
+ if (
236
+ logLines[i].includes("[INTERACTION]") ||
237
+ logLines[i].includes("[NAVIGATION]") ||
238
+ logLines[i].includes("[PAGE]")
239
+ ) {
240
+ interactions.unshift(logLines[i])
241
+ }
242
+ }
243
+ return interactions
244
+ }
245
+
246
+ // Process build errors
247
+ for (const error of categorizedErrors.buildErrors) {
248
+ const interactions = findInteractions(error)
249
+ prioritizedErrors.push({
250
+ error,
251
+ category: "build",
252
+ severity: "critical",
253
+ priorityScore: calculateErrorPriority(error, "build", interactions, allErrors),
254
+ interactions
255
+ })
256
+ }
257
+
258
+ // Process server errors
259
+ for (const error of categorizedErrors.serverErrors) {
260
+ const interactions = findInteractions(error)
261
+ const severity: PrioritizedError["severity"] = /CRITICAL|FATAL/i.test(error) ? "critical" : "error"
262
+ prioritizedErrors.push({
263
+ error,
264
+ category: "server",
265
+ severity,
266
+ priorityScore: calculateErrorPriority(error, "server", interactions, allErrors),
267
+ interactions
268
+ })
269
+ }
270
+
271
+ // Process browser errors
272
+ for (const error of categorizedErrors.browserErrors) {
273
+ const interactions = findInteractions(error)
274
+ const severity: PrioritizedError["severity"] = /CRITICAL|FATAL/i.test(error) ? "critical" : "error"
275
+ prioritizedErrors.push({
276
+ error,
277
+ category: "browser",
278
+ severity,
279
+ priorityScore: calculateErrorPriority(error, "browser", interactions, allErrors),
280
+ interactions
281
+ })
282
+ }
283
+
284
+ // Process network errors
285
+ for (const error of categorizedErrors.networkErrors) {
286
+ const interactions = findInteractions(error)
287
+ prioritizedErrors.push({
288
+ error,
289
+ category: "network",
290
+ severity: "error",
291
+ priorityScore: calculateErrorPriority(error, "network", interactions, allErrors),
292
+ interactions
293
+ })
294
+ }
295
+
296
+ // Process warnings (only if no errors found)
297
+ if (prioritizedErrors.length === 0) {
298
+ for (const error of categorizedErrors.warnings) {
299
+ const interactions = findInteractions(error)
300
+ prioritizedErrors.push({
301
+ error,
302
+ category: "warning",
303
+ severity: "warning",
304
+ priorityScore: calculateErrorPriority(error, "warning", interactions, allErrors),
305
+ interactions
306
+ })
307
+ }
308
+ }
309
+
310
+ // Sort by priority score (highest first)
311
+ prioritizedErrors.sort((a, b) => b.priorityScore - a.priorityScore)
312
+
313
+ return prioritizedErrors[0] || null
314
+ }
315
+
316
+ /**
317
+ * Create a PR for the highest priority issue
318
+ */
319
+ async function createPRForIssue(prioritizedError: PrioritizedError, _projectName: string): Promise<string> {
320
+ try {
321
+ // Extract error details for PR title and body
322
+ const errorType = prioritizedError.category.toUpperCase()
323
+ const errorMessage = prioritizedError.error
324
+ .replace(/\[[^\]]+\]/g, "") // Remove timestamps and tags
325
+ .trim()
326
+ .substring(0, 100)
327
+
328
+ const prTitle = `Fix: ${errorType} - ${errorMessage}`
329
+
330
+ // Build PR body
331
+ const prBody = `## 🐛 Bug Fix - ${prioritizedError.category} Error
332
+
333
+ **Priority Score:** ${prioritizedError.priorityScore} (${prioritizedError.severity})
334
+
335
+ ### Error Details
336
+ \`\`\`
337
+ ${prioritizedError.error}
338
+ \`\`\`
339
+
340
+ ${
341
+ prioritizedError.interactions.length > 0
342
+ ? `### Reproduction Steps
343
+ The error occurred after these user interactions:
344
+ ${prioritizedError.interactions.map((i, idx) => `${idx + 1}. ${i}`).join("\n")}
345
+
346
+ ### Verification
347
+ After implementing the fix, verify by:
348
+ 1. Replaying the same interactions using \`execute_browser_action\`
349
+ 2. Confirming the error no longer appears in logs
350
+ 3. Checking that functionality works as expected
351
+ `
352
+ : ""
353
+ }
354
+
355
+ ### Suggested Fix
356
+ This PR addresses the ${prioritizedError.severity}-level ${prioritizedError.category} error detected by dev3000.
357
+
358
+ ${prioritizedError.suggestedFix || "Please analyze the error and implement the appropriate fix."}
359
+
360
+ ---
361
+ 🤖 Generated with [dev3000](https://github.com/vercel-labs/dev3000) - AI-powered debugging
362
+ `
363
+
364
+ // Create a new branch
365
+ const branchName = `fix/${prioritizedError.category}-${Date.now()}`
366
+
367
+ // Use execAsync to run git and gh commands
368
+ await execAsync(`git checkout -b ${branchName}`)
369
+
370
+ // Create the PR using gh
371
+ await execAsync(`gh pr create --title "${prTitle}" --body "${prBody}" --head ${branchName}`)
372
+
373
+ return `✅ Created PR: ${prTitle}\n\nBranch: ${branchName}\n\nNext steps:\n1. Implement the fix in your code\n2. Commit and push changes\n3. PR is ready for review!`
374
+ } catch (error) {
375
+ return `❌ Failed to create PR: ${error instanceof Error ? error.message : String(error)}\n\nYou can manually create a PR with the error details above.`
376
+ }
377
+ }
378
+
122
379
  // Helper functions
123
380
  export function findActiveSessions(): Session[] {
124
381
  const sessionDir = join(homedir(), ".d3k")
@@ -182,7 +439,8 @@ export async function fixMyApp({
182
439
  includeTimestampInstructions = true,
183
440
  integrateNextjs = false,
184
441
  integrateChromeDevtools = false,
185
- returnRawData = false
442
+ returnRawData = false,
443
+ createPR = false
186
444
  }: FixMyAppParams): Promise<{ content: Array<{ type: "text"; text: string }> }> {
187
445
  // 🎯 MCP ORCHESTRATION: Check which downstream MCPs are available
188
446
  const { getMCPClientManager } = await import("./client-manager")
@@ -628,6 +886,47 @@ export async function fixMyApp({
628
886
  results.push("• Combined = 90%+ issue resolution rate!")
629
887
  }
630
888
  }
889
+
890
+ // 🎯 PRIORITIZATION & PR CREATION
891
+ // Find the single highest priority error and optionally create a PR
892
+ const highestPriorityError = findHighestPriorityError(categorizedErrors, actionableErrors, logLines)
893
+
894
+ if (highestPriorityError) {
895
+ results.push("")
896
+ results.push("🎯 **HIGHEST PRIORITY ISSUE:**")
897
+ results.push(`📊 Priority Score: ${highestPriorityError.priorityScore}`)
898
+ results.push(`🏷️ Category: ${highestPriorityError.category.toUpperCase()}`)
899
+ results.push(`⚠️ Severity: ${highestPriorityError.severity.toUpperCase()}`)
900
+ results.push("")
901
+ results.push("❌ **Error:**")
902
+ results.push(` ${highestPriorityError.error}`)
903
+
904
+ if (highestPriorityError.interactions.length > 0) {
905
+ results.push("")
906
+ results.push("📍 **Reproduction Steps:**")
907
+ highestPriorityError.interactions.forEach((interaction, idx) => {
908
+ results.push(` ${idx + 1}. ${interaction}`)
909
+ })
910
+ }
911
+
912
+ // Create PR if requested
913
+ if (createPR) {
914
+ results.push("")
915
+ results.push("🚀 **CREATING PR FOR THIS ISSUE...**")
916
+ const prResult = await createPRForIssue(highestPriorityError, projectName || "")
917
+ results.push(prResult)
918
+ } else {
919
+ results.push("")
920
+ results.push("💡 **To create a PR for this issue:**")
921
+ results.push(" Run: fix_my_app(createPR=true)")
922
+ results.push("")
923
+ results.push(" This will:")
924
+ results.push(" • Create a new branch for the fix")
925
+ results.push(" • Generate a PR with full error context")
926
+ results.push(" • Include reproduction steps")
927
+ results.push(" • Focus on fixing just this ONE issue")
928
+ }
929
+ }
631
930
  }
632
931
 
633
932
  // Extract screenshot information (replaces get_recent_screenshots)
@@ -3606,3 +3905,187 @@ export async function restartDevServer(params: {
3606
3905
  }
3607
3906
  }
3608
3907
  }
3908
+
3909
+ // Crawl app - discover all URLs
3910
+ export interface CrawlAppParams {
3911
+ depth?: number | "all"
3912
+ projectName?: string
3913
+ }
3914
+
3915
+ export async function crawlApp(params: CrawlAppParams) {
3916
+ const { depth = 1, projectName } = params
3917
+
3918
+ try {
3919
+ // Find active session
3920
+ const sessions = findActiveSessions()
3921
+ const session = projectName ? sessions.find((s) => s.projectName === projectName) : sessions[0]
3922
+
3923
+ if (!session) {
3924
+ return {
3925
+ content: [
3926
+ {
3927
+ type: "text" as const,
3928
+ text: projectName
3929
+ ? `❌ No active session found for project "${projectName}". Available projects: ${sessions.map((s) => s.projectName).join(", ") || "none"}`
3930
+ : "❌ No active dev3000 sessions found. Start dev3000 first with `d3k` in your project directory."
3931
+ }
3932
+ ]
3933
+ }
3934
+ }
3935
+
3936
+ // Get CDP URL and app port from session
3937
+ const sessionData = JSON.parse(readFileSync(session.sessionFile, "utf-8"))
3938
+ const cdpUrl = sessionData.cdpUrl?.replace("http://", "ws://")
3939
+ const appPort = sessionData.appPort || "3000"
3940
+ const baseUrl = `http://localhost:${appPort}`
3941
+
3942
+ if (!cdpUrl) {
3943
+ return {
3944
+ content: [
3945
+ {
3946
+ type: "text" as const,
3947
+ text: "❌ No Chrome DevTools connection found. Browser monitoring must be active to crawl."
3948
+ }
3949
+ ]
3950
+ }
3951
+ }
3952
+
3953
+ logToDevFile(`Crawl App: Starting crawl at depth ${depth} for ${baseUrl}`)
3954
+
3955
+ // Connect to CDP
3956
+ const ws = new WebSocket(cdpUrl)
3957
+ await new Promise((resolve, reject) => {
3958
+ ws.on("open", resolve)
3959
+ ws.on("error", reject)
3960
+ setTimeout(() => reject(new Error("CDP connection timeout")), 5000)
3961
+ })
3962
+
3963
+ let messageId = 2000
3964
+ // biome-ignore lint/suspicious/noExplicitAny: CDP protocol responses are dynamic
3965
+ const sendCommand = (method: string, params: Record<string, unknown> = {}): Promise<any> => {
3966
+ return new Promise((resolve, reject) => {
3967
+ const id = messageId++
3968
+ const message = JSON.stringify({ id, method, params })
3969
+
3970
+ const handler = (data: Buffer) => {
3971
+ const response = JSON.parse(data.toString())
3972
+ if (response.id === id) {
3973
+ ws.off("message", handler)
3974
+ if (response.error) {
3975
+ reject(new Error(response.error.message))
3976
+ } else {
3977
+ resolve(response.result)
3978
+ }
3979
+ }
3980
+ }
3981
+
3982
+ ws.on("message", handler)
3983
+ ws.send(message)
3984
+
3985
+ setTimeout(() => {
3986
+ ws.off("message", handler)
3987
+ reject(new Error("Command timeout"))
3988
+ }, 10000)
3989
+ })
3990
+ }
3991
+
3992
+ // Enable necessary domains
3993
+ await sendCommand("Runtime.enable")
3994
+ await sendCommand("Page.enable")
3995
+
3996
+ // Discovered URLs
3997
+ const discovered = new Set<string>([baseUrl])
3998
+ const visited = new Set<string>()
3999
+ const toVisit: string[] = [baseUrl]
4000
+
4001
+ let currentDepth = 0
4002
+ const maxDepth = depth === "all" ? Number.POSITIVE_INFINITY : depth
4003
+
4004
+ while (toVisit.length > 0 && currentDepth <= maxDepth) {
4005
+ const currentLevelUrls = [...toVisit]
4006
+ toVisit.length = 0
4007
+
4008
+ logToDevFile(`Crawl App: Processing depth ${currentDepth} with ${currentLevelUrls.length} URLs`)
4009
+
4010
+ for (const url of currentLevelUrls) {
4011
+ if (visited.has(url)) continue
4012
+ visited.add(url)
4013
+
4014
+ try {
4015
+ // Navigate to URL
4016
+ logToDevFile(`Crawl App: Visiting ${url}`)
4017
+ await sendCommand("Page.navigate", { url })
4018
+
4019
+ // Wait for page load
4020
+ await new Promise((resolve) => setTimeout(resolve, 2000))
4021
+
4022
+ // Extract all links
4023
+ const result = await sendCommand("Runtime.evaluate", {
4024
+ expression: `
4025
+ Array.from(document.querySelectorAll('a[href]')).map(a => {
4026
+ try {
4027
+ const url = new URL(a.href, window.location.href);
4028
+ // Only return same-origin links
4029
+ if (url.origin === window.location.origin) {
4030
+ // Remove hash and query params for deduplication
4031
+ return url.origin + url.pathname;
4032
+ }
4033
+ } catch {}
4034
+ return null;
4035
+ }).filter(Boolean)
4036
+ `,
4037
+ returnByValue: true
4038
+ })
4039
+
4040
+ const links = result.result?.value || []
4041
+
4042
+ for (const link of links) {
4043
+ if (!discovered.has(link)) {
4044
+ discovered.add(link)
4045
+ if (currentDepth < maxDepth) {
4046
+ toVisit.push(link)
4047
+ }
4048
+ }
4049
+ }
4050
+
4051
+ logToDevFile(`Crawl App: Found ${links.length} links on ${url}`)
4052
+ } catch (error) {
4053
+ logToDevFile(`Crawl App: Error visiting ${url} - ${error}`)
4054
+ }
4055
+ }
4056
+
4057
+ currentDepth++
4058
+
4059
+ // For "all" mode, stop when no new URLs are found
4060
+ if (depth === "all" && toVisit.length === 0) {
4061
+ break
4062
+ }
4063
+ }
4064
+
4065
+ ws.close()
4066
+
4067
+ const urls = Array.from(discovered).sort()
4068
+ const depthReached = depth === "all" ? currentDepth - 1 : Math.min(currentDepth - 1, maxDepth)
4069
+
4070
+ logToDevFile(`Crawl App: Complete - discovered ${urls.length} URLs at depth ${depthReached}`)
4071
+
4072
+ return {
4073
+ content: [
4074
+ {
4075
+ type: "text" as const,
4076
+ text: `🕷️ **APP CRAWL COMPLETE**\n\n📊 **SUMMARY:**\n• Base URL: ${baseUrl}\n• Depth: ${depthReached}${depth === "all" ? " (exhaustive)" : ""}\n• Total URLs: ${urls.length}\n\n📍 **DISCOVERED URLs:**\n${urls.map((url) => `• ${url}`).join("\n")}\n\n💡 **NEXT STEPS:**\n• Use fix_my_app to check for errors across all pages\n• Use execute_browser_action to test specific pages\n• Verify all routes are working correctly`
4077
+ }
4078
+ ]
4079
+ }
4080
+ } catch (error) {
4081
+ logToDevFile(`Crawl App: Error - ${error}`)
4082
+ return {
4083
+ content: [
4084
+ {
4085
+ type: "text" as const,
4086
+ text: `❌ **CRAWL FAILED**\n\n${error instanceof Error ? error.message : String(error)}`
4087
+ }
4088
+ ]
4089
+ }
4090
+ }
4091
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dev3000",
3
- "version": "0.0.101",
3
+ "version": "0.0.103",
4
4
  "description": "AI-powered development tools with browser monitoring and MCP server integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -63,6 +63,7 @@
63
63
  "chalk": "^5.3.0",
64
64
  "commander": "^14.0.1",
65
65
  "ink": "^6.3.1",
66
+ "ink-spinner": "^5.0.0",
66
67
  "next": "16.0.0-canary.18",
67
68
  "ora": "^9.0.0",
68
69
  "package-manager-detector": "^1.3.0",
@@ -1,6 +1,7 @@
1
1
  import chalk from "chalk"
2
2
  import { createReadStream, unwatchFile, watchFile } from "fs"
3
3
  import { Box, render, Text, useInput, useStdout } from "ink"
4
+ import Spinner from "ink-spinner"
4
5
  import { useEffect, useRef, useState } from "react"
5
6
  import type { Readable } from "stream"
6
7
  import { LOG_COLORS } from "./constants/log-colors.js"
@@ -46,6 +47,7 @@ const TUIApp = ({
46
47
  const [scrollOffset, setScrollOffset] = useState(0)
47
48
  const [initStatus, setInitStatus] = useState<string | null>("Initializing...")
48
49
  const [appPort, setAppPort] = useState<string>(initialAppPort)
50
+ const [portConfirmed, setPortConfirmed] = useState<boolean>(false)
49
51
  const logIdCounter = useRef(0)
50
52
  const [clearFromLogId, setClearFromLogId] = useState<number>(0) // Track log ID to clear from
51
53
  const { stdout } = useStdout()
@@ -112,6 +114,7 @@ const TUIApp = ({
112
114
  useEffect(() => {
113
115
  onAppPortUpdate((port: string) => {
114
116
  setAppPort(port)
117
+ setPortConfirmed(true)
115
118
  })
116
119
  }, [onAppPortUpdate])
117
120
 
@@ -332,7 +335,10 @@ const TUIApp = ({
332
335
 
333
336
  {/* Info on the right */}
334
337
  <Box flexDirection="column" flexGrow={1}>
335
- <Text color="cyan">🌐 App: http://localhost:{appPort}</Text>
338
+ <Box>
339
+ <Text color="cyan">🌐 App: http://localhost:{appPort} </Text>
340
+ {!portConfirmed && <Spinner type="dots" />}
341
+ </Box>
336
342
  <Text color="cyan">🤖 MCP: http://localhost:{mcpPort}</Text>
337
343
  <Text color="cyan">
338
344
  📸 Logs: http://localhost:{mcpPort}/logs