ultra-dex 3.1.0 → 3.3.0

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 (52) hide show
  1. package/README.md +79 -74
  2. package/assets/code-patterns/clerk-middleware.ts +138 -0
  3. package/assets/code-patterns/prisma-schema.prisma +224 -0
  4. package/assets/code-patterns/rls-policies.sql +246 -0
  5. package/assets/code-patterns/server-actions.ts +191 -0
  6. package/assets/code-patterns/trpc-router.ts +258 -0
  7. package/assets/cursor-rules/13-ai-integration.mdc +155 -0
  8. package/assets/cursor-rules/14-server-components.mdc +81 -0
  9. package/assets/cursor-rules/15-server-actions.mdc +102 -0
  10. package/assets/cursor-rules/16-edge-middleware.mdc +105 -0
  11. package/assets/cursor-rules/17-streaming-ssr.mdc +138 -0
  12. package/bin/ultra-dex.js +50 -1
  13. package/lib/commands/agents.js +16 -13
  14. package/lib/commands/banner.js +43 -21
  15. package/lib/commands/build.js +26 -17
  16. package/lib/commands/cloud.js +780 -0
  17. package/lib/commands/doctor.js +98 -79
  18. package/lib/commands/exec.js +434 -0
  19. package/lib/commands/generate.js +19 -16
  20. package/lib/commands/github.js +475 -0
  21. package/lib/commands/init.js +52 -56
  22. package/lib/commands/scaffold.js +151 -0
  23. package/lib/commands/search.js +477 -0
  24. package/lib/commands/serve.js +15 -13
  25. package/lib/commands/state.js +43 -70
  26. package/lib/commands/swarm.js +31 -9
  27. package/lib/config/theme.js +47 -0
  28. package/lib/mcp/client.js +502 -0
  29. package/lib/providers/agent-sdk.js +630 -0
  30. package/lib/providers/anthropic-agents.js +580 -0
  31. package/lib/templates/code/clerk-middleware.ts +138 -0
  32. package/lib/templates/code/prisma-schema.prisma +224 -0
  33. package/lib/templates/code/rls-policies.sql +246 -0
  34. package/lib/templates/code/server-actions.ts +191 -0
  35. package/lib/templates/code/trpc-router.ts +258 -0
  36. package/lib/themes/doomsday.js +229 -0
  37. package/lib/ui/index.js +5 -0
  38. package/lib/ui/interface.js +241 -0
  39. package/lib/ui/spinners.js +116 -0
  40. package/lib/ui/theme.js +183 -0
  41. package/lib/utils/agents.js +32 -0
  42. package/lib/utils/browser.js +373 -0
  43. package/lib/utils/help.js +64 -0
  44. package/lib/utils/messages.js +35 -0
  45. package/lib/utils/progress.js +24 -0
  46. package/lib/utils/prompts.js +47 -0
  47. package/lib/utils/spinners.js +46 -0
  48. package/lib/utils/status.js +31 -0
  49. package/lib/utils/tables.js +41 -0
  50. package/lib/utils/theme-state.js +9 -0
  51. package/lib/utils/version-display.js +32 -0
  52. package/package.json +19 -4
@@ -0,0 +1,580 @@
1
+ /**
2
+ * Anthropic Agent SDK Integration for Ultra-Dex
3
+ * Enables TRUE autonomous agents using Claude's Agent SDK
4
+ * This is the future of AI-powered development
5
+ */
6
+
7
+ import chalk from 'chalk';
8
+ import fs from 'fs/promises';
9
+ import path from 'path';
10
+
11
+ // ============================================================================
12
+ // AGENT SDK CONFIGURATION
13
+ // ============================================================================
14
+
15
+ const AGENT_SDK_CONFIG = {
16
+ // Default model for agents
17
+ defaultModel: 'claude-sonnet-4-20250514',
18
+
19
+ // Tool definitions for agents
20
+ tools: {
21
+ read_file: {
22
+ name: 'read_file',
23
+ description: 'Read the contents of a file from the codebase',
24
+ input_schema: {
25
+ type: 'object',
26
+ properties: {
27
+ path: {
28
+ type: 'string',
29
+ description: 'The file path to read',
30
+ },
31
+ },
32
+ required: ['path'],
33
+ },
34
+ },
35
+
36
+ write_file: {
37
+ name: 'write_file',
38
+ description: 'Write content to a file, creating directories if needed',
39
+ input_schema: {
40
+ type: 'object',
41
+ properties: {
42
+ path: {
43
+ type: 'string',
44
+ description: 'The file path to write to',
45
+ },
46
+ content: {
47
+ type: 'string',
48
+ description: 'The content to write',
49
+ },
50
+ },
51
+ required: ['path', 'content'],
52
+ },
53
+ },
54
+
55
+ search_code: {
56
+ name: 'search_code',
57
+ description: 'Search for patterns in the codebase using grep',
58
+ input_schema: {
59
+ type: 'object',
60
+ properties: {
61
+ pattern: {
62
+ type: 'string',
63
+ description: 'The pattern to search for',
64
+ },
65
+ file_pattern: {
66
+ type: 'string',
67
+ description: 'Optional file glob pattern (e.g., "*.ts")',
68
+ },
69
+ },
70
+ required: ['pattern'],
71
+ },
72
+ },
73
+
74
+ run_command: {
75
+ name: 'run_command',
76
+ description: 'Execute a shell command in the project directory',
77
+ input_schema: {
78
+ type: 'object',
79
+ properties: {
80
+ command: {
81
+ type: 'string',
82
+ description: 'The command to execute',
83
+ },
84
+ timeout: {
85
+ type: 'number',
86
+ description: 'Timeout in milliseconds (default: 30000)',
87
+ },
88
+ },
89
+ required: ['command'],
90
+ },
91
+ },
92
+
93
+ delegate_to_agent: {
94
+ name: 'delegate_to_agent',
95
+ description: 'Delegate a task to another specialized agent',
96
+ input_schema: {
97
+ type: 'object',
98
+ properties: {
99
+ agent: {
100
+ type: 'string',
101
+ enum: ['backend', 'frontend', 'database', 'testing', 'security', 'devops'],
102
+ description: 'The agent to delegate to',
103
+ },
104
+ task: {
105
+ type: 'string',
106
+ description: 'The task to delegate',
107
+ },
108
+ },
109
+ required: ['agent', 'task'],
110
+ },
111
+ },
112
+
113
+ create_checkpoint: {
114
+ name: 'create_checkpoint',
115
+ description: 'Create a git checkpoint before making changes',
116
+ input_schema: {
117
+ type: 'object',
118
+ properties: {
119
+ message: {
120
+ type: 'string',
121
+ description: 'Checkpoint description',
122
+ },
123
+ },
124
+ required: ['message'],
125
+ },
126
+ },
127
+ },
128
+
129
+ // Agent system prompts
130
+ agentPrompts: {
131
+ orchestrator: `You are the Ultra-Dex Orchestrator Agent - the "Hive Mind" that coordinates complex software development tasks.
132
+
133
+ Your role:
134
+ 1. Break down complex tasks into atomic subtasks
135
+ 2. Delegate to specialized agents (@Backend, @Frontend, @Database, etc.)
136
+ 3. Track progress and handle failures
137
+ 4. Ensure code quality and consistency
138
+
139
+ You have access to tools to read/write files, search code, run commands, and delegate to other agents.
140
+
141
+ IMPORTANT: Always create a checkpoint before making significant changes. Always verify changes work before completing.`,
142
+
143
+ backend: `You are the @Backend Agent - an expert in API development, server-side logic, and system architecture.
144
+
145
+ Expertise:
146
+ - Node.js, Python, Go, Rust backends
147
+ - REST APIs, GraphQL, tRPC
148
+ - Database interactions (Prisma, Drizzle, raw SQL)
149
+ - Authentication and authorization
150
+ - Server Actions (Next.js 15)
151
+
152
+ When implementing:
153
+ 1. Follow existing code patterns in the project
154
+ 2. Add proper error handling
155
+ 3. Include TypeScript types
156
+ 4. Write tests for critical paths`,
157
+
158
+ frontend: `You are the @Frontend Agent - an expert in modern UI development and user experience.
159
+
160
+ Expertise:
161
+ - React, Next.js, Vue, Svelte
162
+ - Server Components vs Client Components
163
+ - State management (Zustand, Jotai, Redux)
164
+ - CSS-in-JS, Tailwind CSS
165
+ - Accessibility (WCAG 2.1)
166
+
167
+ When implementing:
168
+ 1. Prefer Server Components when possible
169
+ 2. Use proper semantic HTML
170
+ 3. Ensure responsive design
171
+ 4. Follow the project's component patterns`,
172
+
173
+ database: `You are the @Database Agent - an expert in data modeling, queries, and database optimization.
174
+
175
+ Expertise:
176
+ - PostgreSQL, MySQL, MongoDB, SQLite
177
+ - Prisma, Drizzle, TypeORM
178
+ - Schema design and migrations
179
+ - Query optimization
180
+ - Row-Level Security (RLS)
181
+
182
+ When implementing:
183
+ 1. Design normalized schemas
184
+ 2. Add proper indexes
185
+ 3. Consider query performance
186
+ 4. Implement soft deletes when appropriate`,
187
+
188
+ testing: `You are the @Testing Agent - an expert in test automation and quality assurance.
189
+
190
+ Expertise:
191
+ - Jest, Vitest, Mocha
192
+ - Playwright, Cypress for E2E
193
+ - Testing Library for component tests
194
+ - Mock Service Worker (MSW)
195
+ - Coverage analysis
196
+
197
+ When implementing:
198
+ 1. Write unit tests for business logic
199
+ 2. Write integration tests for APIs
200
+ 3. Write E2E tests for critical flows
201
+ 4. Aim for 80%+ coverage on critical code`,
202
+
203
+ security: `You are the @Security Agent - an expert in application security and vulnerability prevention.
204
+
205
+ Expertise:
206
+ - OWASP Top 10
207
+ - Authentication/Authorization
208
+ - Input validation and sanitization
209
+ - SQL injection, XSS, CSRF prevention
210
+ - Secure coding practices
211
+
212
+ When reviewing:
213
+ 1. Check for injection vulnerabilities
214
+ 2. Verify authentication flows
215
+ 3. Ensure proper authorization checks
216
+ 4. Review data exposure risks`,
217
+
218
+ devops: `You are the @DevOps Agent - an expert in CI/CD, deployment, and infrastructure.
219
+
220
+ Expertise:
221
+ - GitHub Actions, GitLab CI
222
+ - Docker, Kubernetes
223
+ - Vercel, Railway, AWS
224
+ - Monitoring (Sentry, DataDog)
225
+ - Infrastructure as Code
226
+
227
+ When implementing:
228
+ 1. Create reliable CI/CD pipelines
229
+ 2. Configure proper environments
230
+ 3. Set up monitoring and alerts
231
+ 4. Document deployment procedures`,
232
+ },
233
+ };
234
+
235
+ // ============================================================================
236
+ // TOOL EXECUTORS
237
+ // ============================================================================
238
+
239
+ import { exec as execCallback } from 'child_process';
240
+ import { promisify } from 'util';
241
+ import { glob } from 'glob';
242
+
243
+ const execAsync = promisify(execCallback);
244
+
245
+ /**
246
+ * Execute a tool call
247
+ */
248
+ async function executeTool(toolName, input, context = {}) {
249
+ const { workdir = process.cwd() } = context;
250
+
251
+ switch (toolName) {
252
+ case 'read_file': {
253
+ const filepath = path.resolve(workdir, input.path);
254
+ try {
255
+ const content = await fs.readFile(filepath, 'utf8');
256
+ return { success: true, content };
257
+ } catch (err) {
258
+ return { success: false, error: `Failed to read file: ${err.message}` };
259
+ }
260
+ }
261
+
262
+ case 'write_file': {
263
+ const filepath = path.resolve(workdir, input.path);
264
+ try {
265
+ await fs.mkdir(path.dirname(filepath), { recursive: true });
266
+ await fs.writeFile(filepath, input.content, 'utf8');
267
+ return { success: true, message: `Wrote ${input.path}` };
268
+ } catch (err) {
269
+ return { success: false, error: `Failed to write file: ${err.message}` };
270
+ }
271
+ }
272
+
273
+ case 'search_code': {
274
+ try {
275
+ const pattern = input.pattern;
276
+ const filePattern = input.file_pattern || '**/*';
277
+
278
+ const files = await glob(filePattern, {
279
+ cwd: workdir,
280
+ ignore: ['node_modules/**', '.git/**', 'dist/**'],
281
+ nodir: true,
282
+ });
283
+
284
+ const results = [];
285
+ for (const file of files.slice(0, 50)) { // Limit search
286
+ try {
287
+ const content = await fs.readFile(path.join(workdir, file), 'utf8');
288
+ const lines = content.split('\n');
289
+
290
+ lines.forEach((line, idx) => {
291
+ if (line.includes(pattern)) {
292
+ results.push({
293
+ file,
294
+ line: idx + 1,
295
+ content: line.trim().slice(0, 200),
296
+ });
297
+ }
298
+ });
299
+ } catch {
300
+ // Skip unreadable files
301
+ }
302
+ }
303
+
304
+ return { success: true, results: results.slice(0, 20) };
305
+ } catch (err) {
306
+ return { success: false, error: `Search failed: ${err.message}` };
307
+ }
308
+ }
309
+
310
+ case 'run_command': {
311
+ try {
312
+ const timeout = input.timeout || 30000;
313
+ const { stdout, stderr } = await execAsync(input.command, {
314
+ cwd: workdir,
315
+ timeout,
316
+ });
317
+ return { success: true, stdout, stderr };
318
+ } catch (err) {
319
+ return { success: false, error: err.message, stderr: err.stderr };
320
+ }
321
+ }
322
+
323
+ case 'create_checkpoint': {
324
+ try {
325
+ await execAsync('git add -A', { cwd: workdir });
326
+ await execAsync(`git commit -m "checkpoint: ${input.message}" --allow-empty`, { cwd: workdir });
327
+ return { success: true, message: `Checkpoint created: ${input.message}` };
328
+ } catch (err) {
329
+ return { success: false, error: `Checkpoint failed: ${err.message}` };
330
+ }
331
+ }
332
+
333
+ case 'delegate_to_agent': {
334
+ // This will be handled by the agent loop
335
+ return {
336
+ success: true,
337
+ delegation: {
338
+ agent: input.agent,
339
+ task: input.task,
340
+ },
341
+ };
342
+ }
343
+
344
+ default:
345
+ return { success: false, error: `Unknown tool: ${toolName}` };
346
+ }
347
+ }
348
+
349
+ // ============================================================================
350
+ // AUTONOMOUS AGENT CLASS
351
+ // ============================================================================
352
+
353
+ /**
354
+ * Autonomous Agent powered by Anthropic Agent SDK
355
+ */
356
+ export class AutonomousAgent {
357
+ constructor(agentType, options = {}) {
358
+ this.type = agentType;
359
+ this.options = options;
360
+ this.history = [];
361
+ this.toolResults = [];
362
+ this.maxTurns = options.maxTurns || 10;
363
+ this.verbose = options.verbose || false;
364
+
365
+ // System prompt for this agent type
366
+ this.systemPrompt = AGENT_SDK_CONFIG.agentPrompts[agentType] ||
367
+ AGENT_SDK_CONFIG.agentPrompts.orchestrator;
368
+
369
+ // Available tools
370
+ this.tools = Object.values(AGENT_SDK_CONFIG.tools);
371
+ }
372
+
373
+ /**
374
+ * Run the agent on a task
375
+ */
376
+ async run(task, context = {}) {
377
+ const { provider, workdir = process.cwd() } = context;
378
+
379
+ if (!provider) {
380
+ throw new Error('Provider required for autonomous agent');
381
+ }
382
+
383
+ if (this.verbose) {
384
+ console.log(chalk.cyan(`\n🤖 ${this.type.toUpperCase()} Agent starting...`));
385
+ console.log(chalk.gray(`Task: ${task}\n`));
386
+ }
387
+
388
+ const messages = [
389
+ { role: 'user', content: task },
390
+ ];
391
+
392
+ let turn = 0;
393
+ let finalResult = null;
394
+
395
+ while (turn < this.maxTurns) {
396
+ turn++;
397
+
398
+ if (this.verbose) {
399
+ console.log(chalk.gray(`--- Turn ${turn}/${this.maxTurns} ---`));
400
+ }
401
+
402
+ // Call the model
403
+ const response = await provider.generateWithTools(
404
+ this.systemPrompt,
405
+ messages,
406
+ this.tools
407
+ );
408
+
409
+ // Check for tool calls
410
+ if (response.toolCalls && response.toolCalls.length > 0) {
411
+ // Execute tools
412
+ const toolMessages = [];
413
+
414
+ for (const toolCall of response.toolCalls) {
415
+ if (this.verbose) {
416
+ console.log(chalk.yellow(` 🔧 ${toolCall.name}(${JSON.stringify(toolCall.input).slice(0, 50)}...)`));
417
+ }
418
+
419
+ const result = await executeTool(toolCall.name, toolCall.input, { workdir });
420
+ this.toolResults.push({ tool: toolCall.name, input: toolCall.input, result });
421
+
422
+ // Handle delegation
423
+ if (result.delegation) {
424
+ const subAgent = new AutonomousAgent(result.delegation.agent, this.options);
425
+ const subResult = await subAgent.run(result.delegation.task, context);
426
+ toolMessages.push({
427
+ role: 'tool_result',
428
+ tool_use_id: toolCall.id,
429
+ content: JSON.stringify({
430
+ delegated: true,
431
+ agent: result.delegation.agent,
432
+ result: subResult,
433
+ }),
434
+ });
435
+ } else {
436
+ toolMessages.push({
437
+ role: 'tool_result',
438
+ tool_use_id: toolCall.id,
439
+ content: JSON.stringify(result),
440
+ });
441
+ }
442
+ }
443
+
444
+ // Add assistant message and tool results to history
445
+ messages.push({ role: 'assistant', content: response.content, tool_calls: response.toolCalls });
446
+ messages.push(...toolMessages);
447
+
448
+ } else {
449
+ // No tool calls - agent is done
450
+ finalResult = response.content;
451
+
452
+ if (this.verbose) {
453
+ console.log(chalk.green(`\n✅ Agent completed`));
454
+ }
455
+
456
+ break;
457
+ }
458
+ }
459
+
460
+ if (!finalResult) {
461
+ finalResult = 'Max turns reached without completion';
462
+ }
463
+
464
+ this.history = messages;
465
+
466
+ return {
467
+ success: true,
468
+ result: finalResult,
469
+ turns: turn,
470
+ toolsUsed: this.toolResults.length,
471
+ history: this.history,
472
+ };
473
+ }
474
+
475
+ /**
476
+ * Get execution summary
477
+ */
478
+ getSummary() {
479
+ return {
480
+ agent: this.type,
481
+ toolsUsed: this.toolResults.map(t => t.tool),
482
+ historyLength: this.history.length,
483
+ };
484
+ }
485
+ }
486
+
487
+ // ============================================================================
488
+ // MULTI-AGENT SWARM
489
+ // ============================================================================
490
+
491
+ /**
492
+ * Run a multi-agent swarm for complex tasks
493
+ */
494
+ export async function runAutonomousSwarm(task, options = {}) {
495
+ const { provider, workdir = process.cwd(), verbose = false } = options;
496
+
497
+ console.log(chalk.cyan('\n🐝 Ultra-Dex Autonomous Swarm\n'));
498
+ console.log(chalk.bold(`Task: ${task}\n`));
499
+
500
+ // Start with orchestrator
501
+ const orchestrator = new AutonomousAgent('orchestrator', {
502
+ maxTurns: 15,
503
+ verbose,
504
+ });
505
+
506
+ const result = await orchestrator.run(task, { provider, workdir });
507
+
508
+ console.log(chalk.cyan('\n📊 Swarm Summary:'));
509
+ console.log(` Turns: ${result.turns}`);
510
+ console.log(` Tools used: ${result.toolsUsed}`);
511
+ console.log(chalk.green(`\n✅ Swarm completed`));
512
+
513
+ return result;
514
+ }
515
+
516
+ // ============================================================================
517
+ // PROVIDER EXTENSION
518
+ // ============================================================================
519
+
520
+ /**
521
+ * Extend a provider with tool-use capability
522
+ */
523
+ export function extendProviderWithTools(provider) {
524
+ if (provider.generateWithTools) {
525
+ return provider; // Already extended
526
+ }
527
+
528
+ provider.generateWithTools = async function (systemPrompt, messages, tools) {
529
+ // For providers that don't natively support tools,
530
+ // we simulate tool use through the prompt
531
+ const toolDescriptions = tools.map(t =>
532
+ `- ${t.name}: ${t.description}`
533
+ ).join('\n');
534
+
535
+ const enhancedSystem = `${systemPrompt}
536
+
537
+ Available tools:
538
+ ${toolDescriptions}
539
+
540
+ To use a tool, output JSON in this format:
541
+ {"tool": "tool_name", "input": {...}}
542
+
543
+ After receiving tool results, continue your work or provide your final answer.`;
544
+
545
+ const result = await this.generate(enhancedSystem, messages[messages.length - 1].content);
546
+
547
+ // Parse tool calls from response
548
+ const toolCallMatch = result.content.match(/\{"tool":\s*"(\w+)",\s*"input":\s*(\{[^}]+\})\}/);
549
+
550
+ if (toolCallMatch) {
551
+ return {
552
+ content: result.content,
553
+ toolCalls: [{
554
+ id: `tool_${Date.now()}`,
555
+ name: toolCallMatch[1],
556
+ input: JSON.parse(toolCallMatch[2]),
557
+ }],
558
+ };
559
+ }
560
+
561
+ return {
562
+ content: result.content,
563
+ toolCalls: null,
564
+ };
565
+ };
566
+
567
+ return provider;
568
+ }
569
+
570
+ // ============================================================================
571
+ // EXPORTS
572
+ // ============================================================================
573
+
574
+ export default {
575
+ AutonomousAgent,
576
+ runAutonomousSwarm,
577
+ extendProviderWithTools,
578
+ executeTool,
579
+ AGENT_SDK_CONFIG,
580
+ };
@@ -0,0 +1,138 @@
1
+ // Ultra-Dex Production Pattern: Clerk Middleware
2
+ // Copy to middleware.ts in your Next.js root
3
+
4
+ import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
5
+ import { NextResponse } from 'next/server';
6
+
7
+ // =============================================================================
8
+ // ROUTE MATCHERS
9
+ // =============================================================================
10
+
11
+ // Public routes - accessible without authentication
12
+ const isPublicRoute = createRouteMatcher([
13
+ '/',
14
+ '/sign-in(.*)',
15
+ '/sign-up(.*)',
16
+ '/api/webhooks(.*)',
17
+ '/pricing',
18
+ '/about',
19
+ '/blog(.*)',
20
+ ]);
21
+
22
+ // Admin routes - require admin role
23
+ const isAdminRoute = createRouteMatcher([
24
+ '/admin(.*)',
25
+ '/api/admin(.*)',
26
+ ]);
27
+
28
+ // API routes that need special handling
29
+ const isApiRoute = createRouteMatcher(['/api(.*)']);
30
+
31
+ // =============================================================================
32
+ // MIDDLEWARE
33
+ // =============================================================================
34
+
35
+ export default clerkMiddleware(async (auth, req) => {
36
+ const { userId, sessionClaims } = await auth();
37
+
38
+ // Allow public routes
39
+ if (isPublicRoute(req)) {
40
+ return NextResponse.next();
41
+ }
42
+
43
+ // Protect all non-public routes
44
+ if (!userId) {
45
+ const signInUrl = new URL('/sign-in', req.url);
46
+ signInUrl.searchParams.set('redirect_url', req.url);
47
+ return NextResponse.redirect(signInUrl);
48
+ }
49
+
50
+ // Check admin routes
51
+ if (isAdminRoute(req)) {
52
+ const role = sessionClaims?.metadata?.role as string | undefined;
53
+
54
+ if (role !== 'admin' && role !== 'super_admin') {
55
+ return NextResponse.redirect(new URL('/unauthorized', req.url));
56
+ }
57
+ }
58
+
59
+ // Add user info to headers for API routes
60
+ if (isApiRoute(req)) {
61
+ const requestHeaders = new Headers(req.headers);
62
+ requestHeaders.set('x-user-id', userId);
63
+
64
+ return NextResponse.next({
65
+ request: {
66
+ headers: requestHeaders,
67
+ },
68
+ });
69
+ }
70
+
71
+ return NextResponse.next();
72
+ });
73
+
74
+ export const config = {
75
+ matcher: [
76
+ // Skip Next.js internals and static files
77
+ '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
78
+ // Always run for API routes
79
+ '/(api|trpc)(.*)',
80
+ ],
81
+ };
82
+
83
+ // =============================================================================
84
+ // USAGE EXAMPLES
85
+ // =============================================================================
86
+
87
+ /*
88
+ // In a Server Component - get current user:
89
+
90
+ import { auth, currentUser } from '@clerk/nextjs/server';
91
+
92
+ export default async function DashboardPage() {
93
+ const { userId } = await auth();
94
+ const user = await currentUser();
95
+
96
+ if (!userId) {
97
+ redirect('/sign-in');
98
+ }
99
+
100
+ return <div>Welcome, {user?.firstName}!</div>;
101
+ }
102
+
103
+ // In a Client Component - use hooks:
104
+
105
+ 'use client';
106
+
107
+ import { useUser, useAuth } from '@clerk/nextjs';
108
+
109
+ export function UserProfile() {
110
+ const { user, isLoaded } = useUser();
111
+ const { signOut } = useAuth();
112
+
113
+ if (!isLoaded) return <div>Loading...</div>;
114
+
115
+ return (
116
+ <div>
117
+ <p>Hello, {user?.firstName}</p>
118
+ <button onClick={() => signOut()}>Sign Out</button>
119
+ </div>
120
+ );
121
+ }
122
+
123
+ // In an API Route:
124
+
125
+ import { auth } from '@clerk/nextjs/server';
126
+ import { NextResponse } from 'next/server';
127
+
128
+ export async function GET() {
129
+ const { userId } = await auth();
130
+
131
+ if (!userId) {
132
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
133
+ }
134
+
135
+ // Your logic here
136
+ return NextResponse.json({ userId });
137
+ }
138
+ */