@codewithdan/zingit 0.17.5 → 0.17.7
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/AGENTS.md +16 -6
- package/CHANGELOG.md +2 -0
- package/client/dist/zingit-client.js +29 -29
- package/package.json +2 -2
- package/server/dist/handlers/messageHandlers.js +1 -1
- package/server/dist/index.js +2 -1
- package/server/dist/services/git-manager.d.ts +8 -0
- package/server/dist/types.d.ts +8 -0
- package/server/dist/utils/agent-detection.js +12 -2
- package/server/dist/agents/claude.d.ts +0 -17
- package/server/dist/agents/claude.js +0 -175
- package/server/dist/agents/codex.d.ts +0 -11
- package/server/dist/agents/codex.js +0 -202
- package/server/dist/agents/copilot.d.ts +0 -11
- package/server/dist/agents/copilot.js +0 -182
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
// server/src/agents/copilot.ts
|
|
2
|
-
// Agent that uses GitHub Copilot SDK
|
|
3
|
-
import { CopilotClient } from '@github/copilot-sdk';
|
|
4
|
-
import { BaseAgent } from './base.js';
|
|
5
|
-
import { promises as fs } from 'fs';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import * as os from 'os';
|
|
8
|
-
import { randomUUID } from 'crypto';
|
|
9
|
-
export class CopilotAgent extends BaseAgent {
|
|
10
|
-
name = 'copilot';
|
|
11
|
-
model;
|
|
12
|
-
client = null;
|
|
13
|
-
constructor() {
|
|
14
|
-
super();
|
|
15
|
-
this.model = process.env.COPILOT_MODEL || 'claude-sonnet-4-20250514';
|
|
16
|
-
}
|
|
17
|
-
async start() {
|
|
18
|
-
// Initialize the Copilot client
|
|
19
|
-
this.client = new CopilotClient({
|
|
20
|
-
logLevel: 'info',
|
|
21
|
-
autoRestart: true,
|
|
22
|
-
});
|
|
23
|
-
await this.client.start();
|
|
24
|
-
console.log(`✓ Copilot SDK initialized (model: ${this.model})`);
|
|
25
|
-
}
|
|
26
|
-
async stop() {
|
|
27
|
-
if (this.client) {
|
|
28
|
-
await this.client.stop();
|
|
29
|
-
this.client = null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async createSession(wsRef, projectDir, resumeSessionId) {
|
|
33
|
-
if (!this.client) {
|
|
34
|
-
throw new Error('Copilot client not initialized');
|
|
35
|
-
}
|
|
36
|
-
const send = (data) => {
|
|
37
|
-
const ws = wsRef.current;
|
|
38
|
-
if (ws && ws.readyState === ws.OPEN) {
|
|
39
|
-
ws.send(JSON.stringify(data));
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
// System message and permission config for both new and resumed sessions
|
|
43
|
-
const sessionConfig = {
|
|
44
|
-
model: this.model,
|
|
45
|
-
streaming: true,
|
|
46
|
-
systemMessage: {
|
|
47
|
-
mode: 'append',
|
|
48
|
-
content: `
|
|
49
|
-
<context>
|
|
50
|
-
You are a UI debugging assistant working in the project directory: ${projectDir}
|
|
51
|
-
|
|
52
|
-
When given markers about UI elements:
|
|
53
|
-
1. Search for the corresponding code using the selectors and HTML context provided
|
|
54
|
-
2. Make the requested changes in the project at ${projectDir}
|
|
55
|
-
3. Be thorough in finding the right files and making precise edits
|
|
56
|
-
|
|
57
|
-
When screenshots are provided, use them to:
|
|
58
|
-
- Better understand the visual context and styling of the elements
|
|
59
|
-
- Identify the exact appearance that needs to be changed
|
|
60
|
-
- Verify you're targeting the correct element based on its visual representation
|
|
61
|
-
|
|
62
|
-
IMPORTANT: Format all responses using markdown:
|
|
63
|
-
- Use **bold** for emphasis on important points
|
|
64
|
-
- Use numbered lists for sequential steps (1. 2. 3.)
|
|
65
|
-
- Use bullet points for non-sequential items
|
|
66
|
-
- Use code blocks with \`\`\`language syntax for code examples
|
|
67
|
-
- Use inline \`code\` for file paths, selectors, and technical terms
|
|
68
|
-
</context>
|
|
69
|
-
`
|
|
70
|
-
},
|
|
71
|
-
onPermissionRequest: async (request) => {
|
|
72
|
-
// Auto-approve read/write operations for file edits
|
|
73
|
-
if (request.kind === 'read' || request.kind === 'write') {
|
|
74
|
-
return { kind: 'approved' };
|
|
75
|
-
}
|
|
76
|
-
return { kind: 'approved' };
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
// Resume existing session if we have a sessionId, otherwise create new session
|
|
80
|
-
const session = resumeSessionId
|
|
81
|
-
? await this.client.resumeSession(resumeSessionId, sessionConfig)
|
|
82
|
-
: await this.client.createSession(sessionConfig);
|
|
83
|
-
// Track temp files for cleanup on session destroy (prevents race condition)
|
|
84
|
-
const sessionTempFiles = [];
|
|
85
|
-
// Subscribe to streaming events and capture unsubscribe function
|
|
86
|
-
const unsubscribe = session.on((event) => {
|
|
87
|
-
switch (event.type) {
|
|
88
|
-
case 'assistant.message_delta':
|
|
89
|
-
// Streaming chunk
|
|
90
|
-
send({ type: 'delta', content: event.data.deltaContent });
|
|
91
|
-
break;
|
|
92
|
-
case 'assistant.message':
|
|
93
|
-
// Final message (we already sent deltas, so just log)
|
|
94
|
-
console.log('[Copilot Agent] Assistant message complete');
|
|
95
|
-
break;
|
|
96
|
-
case 'tool.execution_start':
|
|
97
|
-
console.log('[Copilot Agent] Tool executing:', event.data.toolName);
|
|
98
|
-
send({ type: 'tool_start', tool: event.data.toolName });
|
|
99
|
-
break;
|
|
100
|
-
case 'tool.execution_complete':
|
|
101
|
-
console.log('[Copilot Agent] Tool complete:', event.data.toolCallId);
|
|
102
|
-
send({ type: 'tool_end', tool: event.data.toolCallId });
|
|
103
|
-
break;
|
|
104
|
-
case 'session.idle':
|
|
105
|
-
console.log('[Copilot Agent] Session idle, sending idle message');
|
|
106
|
-
send({ type: 'idle' });
|
|
107
|
-
break;
|
|
108
|
-
case 'session.error':
|
|
109
|
-
console.error('[Copilot Agent] Session error:', event.data.message);
|
|
110
|
-
send({ type: 'error', message: event.data.message });
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
return {
|
|
115
|
-
send: async (msg) => {
|
|
116
|
-
try {
|
|
117
|
-
console.log('[Copilot Agent] send() called, processing request...');
|
|
118
|
-
// If images are provided, save them as temp files and attach them
|
|
119
|
-
// Copilot SDK supports file attachments for images
|
|
120
|
-
const attachments = [];
|
|
121
|
-
if (msg.images && msg.images.length > 0) {
|
|
122
|
-
const tempDir = os.tmpdir();
|
|
123
|
-
for (let i = 0; i < msg.images.length; i++) {
|
|
124
|
-
const img = msg.images[i];
|
|
125
|
-
// Use UUID to avoid filename collisions
|
|
126
|
-
const ext = img.mediaType.split('/')[1] || 'png';
|
|
127
|
-
const tempPath = path.join(tempDir, `zingit-screenshot-${randomUUID()}.${ext}`);
|
|
128
|
-
// Decode base64 to buffer with error handling
|
|
129
|
-
let buffer;
|
|
130
|
-
try {
|
|
131
|
-
buffer = Buffer.from(img.base64, 'base64');
|
|
132
|
-
}
|
|
133
|
-
catch (decodeErr) {
|
|
134
|
-
console.warn(`ZingIt: Failed to decode base64 for image ${i + 1}:`, decodeErr);
|
|
135
|
-
continue; // Skip this image
|
|
136
|
-
}
|
|
137
|
-
// Save with restrictive permissions (owner read/write only)
|
|
138
|
-
await fs.writeFile(tempPath, buffer, { mode: 0o600 });
|
|
139
|
-
sessionTempFiles.push(tempPath);
|
|
140
|
-
attachments.push({
|
|
141
|
-
type: 'file',
|
|
142
|
-
path: tempPath,
|
|
143
|
-
displayName: img.label || `Screenshot ${i + 1}`
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
console.log('[Copilot Agent] Calling session.sendAndWait...');
|
|
148
|
-
await session.sendAndWait({
|
|
149
|
-
prompt: msg.prompt,
|
|
150
|
-
attachments: attachments.length > 0 ? attachments : undefined
|
|
151
|
-
});
|
|
152
|
-
console.log('[Copilot Agent] session.sendAndWait completed');
|
|
153
|
-
}
|
|
154
|
-
catch (err) {
|
|
155
|
-
console.error('[Copilot Agent] Error in send():', err.message);
|
|
156
|
-
send({ type: 'error', message: err.message });
|
|
157
|
-
}
|
|
158
|
-
// Note: Temp files cleaned up on session destroy to avoid race condition
|
|
159
|
-
},
|
|
160
|
-
destroy: async () => {
|
|
161
|
-
try {
|
|
162
|
-
unsubscribe();
|
|
163
|
-
await session.destroy();
|
|
164
|
-
}
|
|
165
|
-
finally {
|
|
166
|
-
// Clean up all temp files even if destroy() fails
|
|
167
|
-
for (const tempPath of sessionTempFiles) {
|
|
168
|
-
try {
|
|
169
|
-
await fs.unlink(tempPath);
|
|
170
|
-
}
|
|
171
|
-
catch (cleanupErr) {
|
|
172
|
-
// Ignore errors (file may already be deleted)
|
|
173
|
-
console.warn(`ZingIt: Failed to clean up temp file ${tempPath}:`, cleanupErr.message);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
sessionTempFiles.length = 0; // Clear the array
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
getSessionId: () => session.sessionId
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
}
|