Skip to content

Commit e3ad906

Browse files
committed
Started cleanup
1 parent 04a741f commit e3ad906

5 files changed

Lines changed: 196 additions & 136 deletions

File tree

claude-agent-github-wiki/README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ A production-ready Next.js application that enables real-time conversations with
55
## Architecture Overview
66

77
This application uses a hybrid architecture combining:
8+
89
- **Trigger.dev Realtime Streams v2** for streaming AI responses (main data pipeline)
910
- **Supabase Broadcast** for sending questions to the AI (lightweight control plane)
1011
- **Claude Agent SDK** for repository analysis with tool usage
@@ -40,11 +41,13 @@ This application uses a hybrid architecture combining:
4041
### Environment Setup
4142

4243
1. Copy the example environment file:
44+
4345
```bash
4446
cp .env.example .env.local
4547
```
4648

4749
2. Add your API keys to `.env.local`:
50+
4851
```env
4952
# Trigger.dev
5053
TRIGGER_PROJECT_REF=your_project_ref
@@ -83,11 +86,13 @@ Open [http://localhost:3000](http://localhost:3000)
8386
### Deployment
8487

8588
Deploy to Trigger.dev:
89+
8690
```bash
8791
npx trigger.dev@latest deploy
8892
```
8993

9094
Deploy Next.js to Vercel:
95+
9196
```bash
9297
vercel deploy
9398
```
@@ -117,15 +122,18 @@ Responses stream via Trigger.dev Streams v2 → Frontend
117122
### Key Components
118123

119124
1. **Build Extension** (`trigger.config.ts`):
125+
120126
- Installs git via apt-get in container
121127
- Enables shallow cloning without local git dependency
122128

123129
2. **Clone Task** (`trigger/clone-repo.ts`):
130+
124131
- Performs shallow clone (`--depth=1`)
125132
- Generates unique session ID
126133
- Returns temp directory path
127134

128135
3. **Chat Session Task** (`trigger/repo-chat-session.ts`):
136+
129137
- Maintains repo in memory for 60 minutes
130138
- Listens for questions via Supabase Broadcast
131139
- Streams responses via Trigger.dev Streams v2
@@ -177,12 +185,9 @@ components/
177185
## Development Notes
178186

179187
This demo showcases:
188+
180189
- Trigger.dev Realtime Streams v2 for data streaming
181190
- Build extensions for containerized dependencies
182191
- Hybrid architecture pattern (control + data plane separation)
183192
- Long-running task management
184193
- Claude Agent SDK integration
185-
186-
## License
187-
188-
MIT

claude-agent-github-wiki/app/api/analyze-repo/route.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { tasks, runs } from "@trigger.dev/sdk/v3";
1+
import { runs, tasks } from "@trigger.dev/sdk";
22
import { cloneRepo } from "@/trigger/clone-repo";
33
import { repoChatSession } from "@/trigger/repo-chat-session";
44
import { NextRequest, NextResponse } from "next/server";
@@ -11,7 +11,7 @@ export async function POST(request: NextRequest) {
1111
if (!githubUrl || typeof githubUrl !== "string") {
1212
return NextResponse.json(
1313
{ error: "GitHub URL is required" },
14-
{ status: 400 }
14+
{ status: 400 },
1515
);
1616
}
1717

@@ -20,14 +20,14 @@ export async function POST(request: NextRequest) {
2020
if (!githubUrlPattern.test(githubUrl)) {
2121
return NextResponse.json(
2222
{ error: "Invalid GitHub URL format" },
23-
{ status: 400 }
23+
{ status: 400 },
2424
);
2525
}
2626

2727
// Trigger the clone task
2828
const cloneHandle = await tasks.trigger<typeof cloneRepo>(
2929
"clone-repo",
30-
{ githubUrl }
30+
{ githubUrl },
3131
);
3232

3333
// Wait for clone to complete using pollForCompletion
@@ -44,19 +44,19 @@ export async function POST(request: NextRequest) {
4444
} else if (run.status === "FAILED") {
4545
return NextResponse.json(
4646
{ error: "Failed to clone repository" },
47-
{ status: 500 }
47+
{ status: 500 },
4848
);
4949
}
5050

5151
// Wait 1 second before next check
52-
await new Promise(resolve => setTimeout(resolve, 1000));
52+
await new Promise((resolve) => setTimeout(resolve, 1000));
5353
attempts++;
5454
}
5555

5656
if (!cloneResult) {
5757
return NextResponse.json(
5858
{ error: "Clone operation timed out" },
59-
{ status: 500 }
59+
{ status: 500 },
6060
);
6161
}
6262

@@ -67,7 +67,7 @@ export async function POST(request: NextRequest) {
6767
tempDir: cloneResult.output.tempDir,
6868
sessionId: cloneResult.output.sessionId,
6969
repoName: cloneResult.output.repoName,
70-
}
70+
},
7171
);
7272

7373
// Get public access token from handle (auto-generated, expires in 15 min)
@@ -81,12 +81,11 @@ export async function POST(request: NextRequest) {
8181
repoName: cloneResult.output.repoName,
8282
cloneRunId: cloneHandle.id, // Keep for backward compatibility
8383
});
84-
8584
} catch (error: any) {
8685
console.error("Failed to trigger clone-repo task:", error);
8786
return NextResponse.json(
8887
{ error: error.message || "Failed to start cloning" },
89-
{ status: 500 }
88+
{ status: 500 },
9089
);
9190
}
9291
}
Lines changed: 81 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,96 @@
1-
import { createClient } from "@supabase/supabase-js";
2-
import { NextRequest, NextResponse } from "next/server";
3-
import { randomBytes } from "crypto";
1+
// import { createClient } from "@supabase/supabase-js";
2+
// import { NextRequest, NextResponse } from "next/server";
3+
// import { randomBytes } from "crypto";
44

5-
// Generate unique message ID
6-
function generateMessageId(): string {
7-
return `msg_${randomBytes(8).toString("hex")}`;
8-
}
5+
// // Generate unique message ID
6+
// function generateMessageId(): string {
7+
// return `msg_${randomBytes(8).toString("hex")}`;
8+
// }
99

10-
export async function POST(request: NextRequest) {
11-
try {
12-
const { sessionId, question } = await request.json();
10+
// export async function POST(request: NextRequest) {
11+
// try {
12+
// const { sessionId, question } = await request.json();
1313

14-
console.log("📥 API received chat request:", { sessionId, question });
14+
// console.log("📥 API received chat request:", { sessionId, question });
1515

16-
// Validate inputs
17-
if (!sessionId || typeof sessionId !== "string") {
18-
console.error("❌ Missing sessionId");
19-
return NextResponse.json(
20-
{ error: "Session ID is required" },
21-
{ status: 400 }
22-
);
23-
}
16+
// // Validate inputs
17+
// if (!sessionId || typeof sessionId !== "string") {
18+
// console.error("❌ Missing sessionId");
19+
// return NextResponse.json(
20+
// { error: "Session ID is required" },
21+
// { status: 400 }
22+
// );
23+
// }
2424

25-
if (!question || typeof question !== "string") {
26-
console.error("❌ Missing question");
27-
return NextResponse.json(
28-
{ error: "Question is required" },
29-
{ status: 400 }
30-
);
31-
}
25+
// if (!question || typeof question !== "string") {
26+
// console.error("❌ Missing question");
27+
// return NextResponse.json(
28+
// { error: "Question is required" },
29+
// { status: 400 }
30+
// );
31+
// }
3232

33-
// Initialize Supabase client with private key for secure backend communication
34-
const supabase = createClient(
35-
process.env.SUPABASE_URL!,
36-
process.env.SUPABASE_PRIVATE_KEY!,
37-
{
38-
realtime: {
39-
params: {
40-
apikey: process.env.SUPABASE_PRIVATE_KEY!, // Explicitly pass the API key
41-
},
42-
},
43-
auth: {
44-
persistSession: false,
45-
},
46-
}
47-
);
33+
// // Initialize Supabase client with private key for secure backend communication
34+
// const supabase = createClient(
35+
// process.env.SUPABASE_URL!,
36+
// process.env.SUPABASE_PRIVATE_KEY!,
37+
// {
38+
// realtime: {
39+
// params: {
40+
// apikey: process.env.SUPABASE_PRIVATE_KEY!, // Explicitly pass the API key
41+
// },
42+
// },
43+
// auth: {
44+
// persistSession: false,
45+
// },
46+
// }
47+
// );
4848

49-
// Create channel for this session with matching configuration
50-
const channel = supabase.channel(`session:${sessionId}`, {
51-
config: {
52-
broadcast: {
53-
self: false, // Don't receive own broadcasts
54-
ack: true, // Wait for acknowledgment
55-
},
56-
private: false, // Use public channel (must match backend configuration)
57-
},
58-
});
59-
const messageId = generateMessageId();
49+
// // Create channel for this session with matching configuration
50+
// const channel = supabase.channel(`session:${sessionId}`, {
51+
// config: {
52+
// broadcast: {
53+
// self: false, // Don't receive own broadcasts
54+
// ack: true, // Wait for acknowledgment
55+
// },
56+
// private: false, // Use public channel (must match backend configuration)
57+
// },
58+
// });
59+
// const messageId = generateMessageId();
6060

61-
console.log("📡 Subscribing to Supabase channel:", `session:${sessionId}`);
61+
// console.log("📡 Subscribing to Supabase channel:", `session:${sessionId}`);
6262

63-
// Subscribe first
64-
await channel.subscribe();
63+
// // Subscribe first
64+
// await channel.subscribe();
6565

66-
console.log("📤 Broadcasting question to channel with messageId:", messageId);
66+
// console.log("📤 Broadcasting question to channel with messageId:", messageId);
6767

68-
// Send question via Supabase Broadcast (control signal only)
69-
await channel.send({
70-
type: 'broadcast',
71-
event: 'question',
72-
payload: {
73-
question,
74-
messageId
75-
}
76-
});
68+
// // Send question via Supabase Broadcast (control signal only)
69+
// await channel.send({
70+
// type: 'broadcast',
71+
// event: 'question',
72+
// payload: {
73+
// question,
74+
// messageId
75+
// }
76+
// });
7777

78-
console.log("✅ Question broadcast successful");
78+
// console.log("✅ Question broadcast successful");
7979

80-
// Unsubscribe after sending
81-
await channel.unsubscribe();
80+
// // Unsubscribe after sending
81+
// await channel.unsubscribe();
8282

83-
// Return the message ID for tracking
84-
return NextResponse.json({
85-
messageId,
86-
sessionId
87-
});
83+
// // Return the message ID for tracking
84+
// return NextResponse.json({
85+
// messageId,
86+
// sessionId
87+
// });
8888

89-
} catch (error: any) {
90-
console.error("Failed to trigger chat task:", error);
91-
return NextResponse.json(
92-
{ error: error.message || "Failed to start chat" },
93-
{ status: 500 }
94-
);
95-
}
96-
}
89+
// } catch (error: any) {
90+
// console.error("Failed to trigger chat task:", error);
91+
// return NextResponse.json(
92+
// { error: error.message || "Failed to start chat" },
93+
// { status: 500 }
94+
// );
95+
// }
96+
// }

0 commit comments

Comments
 (0)