@sumicom/quicksave 0.6.0 → 0.6.1
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/ai/asyncQueue.d.ts +7 -6
- package/dist/ai/asyncQueue.d.ts.map +1 -1
- package/dist/ai/asyncQueue.js +31 -21
- package/dist/ai/asyncQueue.js.map +1 -1
- package/dist/ai/asyncQueue.test.js +18 -18
- package/dist/ai/asyncQueue.test.js.map +1 -1
- package/dist/ai/cardBuilder.d.ts +11 -2
- package/dist/ai/cardBuilder.d.ts.map +1 -1
- package/dist/ai/cardBuilder.js +113 -21
- package/dist/ai/cardBuilder.js.map +1 -1
- package/dist/ai/claudeCliProvider.d.ts +19 -0
- package/dist/ai/claudeCliProvider.d.ts.map +1 -0
- package/dist/ai/claudeCliProvider.js +466 -0
- package/dist/ai/claudeCliProvider.js.map +1 -0
- package/dist/ai/claudeSdkProvider.d.ts +18 -0
- package/dist/ai/claudeSdkProvider.d.ts.map +1 -0
- package/dist/ai/claudeSdkProvider.js +418 -0
- package/dist/ai/claudeSdkProvider.js.map +1 -0
- package/dist/ai/commitSummary.d.ts +4 -0
- package/dist/ai/commitSummary.d.ts.map +1 -1
- package/dist/ai/commitSummary.js +80 -40
- package/dist/ai/commitSummary.js.map +1 -1
- package/dist/ai/provider.d.ts +54 -0
- package/dist/ai/provider.d.ts.map +1 -0
- package/dist/ai/provider.js +2 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/ai/sandboxMcp.d.ts +12 -0
- package/dist/ai/sandboxMcp.d.ts.map +1 -0
- package/dist/ai/sandboxMcp.js +12 -0
- package/dist/ai/sandboxMcp.js.map +1 -0
- package/dist/ai/sandboxMcpStdio.d.ts +16 -0
- package/dist/ai/sandboxMcpStdio.d.ts.map +1 -0
- package/dist/ai/sandboxMcpStdio.js +127 -0
- package/dist/ai/sandboxMcpStdio.js.map +1 -0
- package/dist/ai/sessionManager.d.ts +100 -0
- package/dist/ai/sessionManager.d.ts.map +1 -0
- package/dist/ai/sessionManager.js +595 -0
- package/dist/ai/sessionManager.js.map +1 -0
- package/dist/ai/sessionRegistry.d.ts +28 -0
- package/dist/ai/sessionRegistry.d.ts.map +1 -0
- package/dist/ai/sessionRegistry.js +148 -0
- package/dist/ai/sessionRegistry.js.map +1 -0
- package/dist/git/operations.d.ts +6 -1
- package/dist/git/operations.d.ts.map +1 -1
- package/dist/git/operations.js +31 -2
- package/dist/git/operations.js.map +1 -1
- package/dist/handlers/messageHandler.d.ts +8 -3
- package/dist/handlers/messageHandler.d.ts.map +1 -1
- package/dist/handlers/messageHandler.js +96 -12
- package/dist/handlers/messageHandler.js.map +1 -1
- package/dist/handlers/messageHandler.test.js +1 -1
- package/dist/index.js +3 -40
- package/dist/index.js.map +1 -1
- package/dist/service/ensureDaemon.d.ts.map +1 -1
- package/dist/service/ensureDaemon.js +15 -2
- package/dist/service/ensureDaemon.js.map +1 -1
- package/dist/service/ipc.test.js +6 -6
- package/dist/service/ipcClient.js +1 -1
- package/dist/service/run.d.ts.map +1 -1
- package/dist/service/run.js +22 -15
- package/dist/service/run.js.map +1 -1
- package/dist/service/singleton.d.ts +4 -0
- package/dist/service/singleton.d.ts.map +1 -1
- package/dist/service/singleton.js +28 -2
- package/dist/service/singleton.js.map +1 -1
- package/dist/service/singleton.test.js +1 -1
- package/package.json +5 -3
- package/dist/ai/claudeCodeService.d.ts +0 -122
- package/dist/ai/claudeCodeService.d.ts.map +0 -1
- package/dist/ai/claudeCodeService.js +0 -869
- package/dist/ai/claudeCodeService.js.map +0 -1
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { join, dirname } from 'path';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { query as sdkQuery } from '@anthropic-ai/claude-agent-sdk';
|
|
5
|
+
import { SANDBOX_MCP_NAME } from './sandboxMcp.js';
|
|
6
|
+
import { AsyncQueue } from './asyncQueue.js';
|
|
7
|
+
const __ownDir = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
/** Extract readable text from tool_result content (string or array of blocks). */
|
|
9
|
+
function extractToolResultText(content) {
|
|
10
|
+
if (typeof content === 'string')
|
|
11
|
+
return content;
|
|
12
|
+
if (Array.isArray(content)) {
|
|
13
|
+
return content
|
|
14
|
+
.filter((b) => b.type === 'text')
|
|
15
|
+
.map((b) => b.text || '')
|
|
16
|
+
.join('\n');
|
|
17
|
+
}
|
|
18
|
+
return JSON.stringify(content);
|
|
19
|
+
}
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// SdkProviderSession — wraps SDK Query for ProviderSession interface
|
|
22
|
+
// ============================================================================
|
|
23
|
+
class SdkProviderSession {
|
|
24
|
+
queryHandle;
|
|
25
|
+
inputQueue;
|
|
26
|
+
/** StreamIds queued by hot resume — consumeStream pops after each result. */
|
|
27
|
+
pendingStreamIds = [];
|
|
28
|
+
constructor(queryHandle, inputQueue) {
|
|
29
|
+
this.queryHandle = queryHandle;
|
|
30
|
+
this.inputQueue = inputQueue;
|
|
31
|
+
}
|
|
32
|
+
sendUserMessage(prompt) {
|
|
33
|
+
if (!this.queryHandle)
|
|
34
|
+
return;
|
|
35
|
+
const userMsg = {
|
|
36
|
+
type: 'user',
|
|
37
|
+
message: { role: 'user', content: prompt },
|
|
38
|
+
parent_tool_use_id: null,
|
|
39
|
+
};
|
|
40
|
+
this.inputQueue.push(userMsg);
|
|
41
|
+
}
|
|
42
|
+
interrupt() {
|
|
43
|
+
if (!this.queryHandle)
|
|
44
|
+
return;
|
|
45
|
+
this.queryHandle.interrupt().catch((err) => {
|
|
46
|
+
console.error('[sdk] interrupt failed:', err);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
kill() {
|
|
50
|
+
if (this.queryHandle) {
|
|
51
|
+
this.queryHandle.close();
|
|
52
|
+
this.queryHandle = null;
|
|
53
|
+
}
|
|
54
|
+
this.inputQueue.end();
|
|
55
|
+
}
|
|
56
|
+
get alive() {
|
|
57
|
+
return this.queryHandle !== null;
|
|
58
|
+
}
|
|
59
|
+
/** Called when the stream ends naturally (query generator completes). */
|
|
60
|
+
markClosed() {
|
|
61
|
+
this.queryHandle = null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// ClaudeSdkProvider — implements CodingAgentProvider via SDK query() API
|
|
66
|
+
// ============================================================================
|
|
67
|
+
export class ClaudeSdkProvider {
|
|
68
|
+
async startSession(opts, cardBuilder, callbacks) {
|
|
69
|
+
const inputQueue = new AsyncQueue();
|
|
70
|
+
// Push first user message
|
|
71
|
+
const firstMsg = {
|
|
72
|
+
type: 'user',
|
|
73
|
+
message: { role: 'user', content: opts.prompt },
|
|
74
|
+
parent_tool_use_id: null,
|
|
75
|
+
};
|
|
76
|
+
inputQueue.push(firstMsg);
|
|
77
|
+
const sessionIdRef = { current: '' };
|
|
78
|
+
const options = this.buildOptions(opts, callbacks, sessionIdRef);
|
|
79
|
+
const queryHandle = sdkQuery({ prompt: inputQueue, options });
|
|
80
|
+
// Wait for init message to get sessionId
|
|
81
|
+
const sessionId = await this.waitForInit(queryHandle, callbacks);
|
|
82
|
+
sessionIdRef.current = sessionId;
|
|
83
|
+
const sdkSession = new SdkProviderSession(queryHandle, inputQueue);
|
|
84
|
+
// Update cardBuilder with real sessionId
|
|
85
|
+
cardBuilder.updateSessionId(sessionId);
|
|
86
|
+
// Fire and forget the stream consumer
|
|
87
|
+
this.consumeStream(sessionId, opts.streamId, queryHandle, sdkSession, cardBuilder, callbacks, opts.prompt);
|
|
88
|
+
return { sessionId, session: sdkSession };
|
|
89
|
+
}
|
|
90
|
+
async resumeSession(opts, cardBuilder, callbacks) {
|
|
91
|
+
const inputQueue = new AsyncQueue();
|
|
92
|
+
// Push resume prompt
|
|
93
|
+
const resumeMsg = {
|
|
94
|
+
type: 'user',
|
|
95
|
+
message: { role: 'user', content: opts.prompt },
|
|
96
|
+
parent_tool_use_id: null,
|
|
97
|
+
};
|
|
98
|
+
inputQueue.push(resumeMsg);
|
|
99
|
+
const sessionIdRef = { current: opts.sessionId };
|
|
100
|
+
const options = this.buildOptions(opts, callbacks, sessionIdRef, opts.sessionId);
|
|
101
|
+
const queryHandle = sdkQuery({ prompt: inputQueue, options });
|
|
102
|
+
// Wait for init message
|
|
103
|
+
const sessionId = await this.waitForInit(queryHandle, callbacks);
|
|
104
|
+
sessionIdRef.current = sessionId;
|
|
105
|
+
const sdkSession = new SdkProviderSession(queryHandle, inputQueue);
|
|
106
|
+
// Update cardBuilder with confirmed sessionId
|
|
107
|
+
cardBuilder.updateSessionId(sessionId);
|
|
108
|
+
// Fire and forget
|
|
109
|
+
this.consumeStream(sessionId, opts.streamId, queryHandle, sdkSession, cardBuilder, callbacks, opts.prompt);
|
|
110
|
+
return { sessionId, session: sdkSession };
|
|
111
|
+
}
|
|
112
|
+
// ── Private: Build SDK Options ──
|
|
113
|
+
buildOptions(opts, callbacks, sessionIdRef, resumeSessionId) {
|
|
114
|
+
const permissionMode = this.mapPermissionMode(opts.permissionLevel);
|
|
115
|
+
const canUseTool = async (toolName, toolInput, permOpts) => {
|
|
116
|
+
const decision = await callbacks.handlePermissionRequest(sessionIdRef.current, {
|
|
117
|
+
toolName,
|
|
118
|
+
toolInput,
|
|
119
|
+
toolUseId: permOpts.toolUseID,
|
|
120
|
+
});
|
|
121
|
+
if (decision.action === 'deny') {
|
|
122
|
+
return { behavior: 'deny', message: decision.response || 'User denied permission' };
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
behavior: 'allow',
|
|
126
|
+
updatedInput: decision.updatedInput,
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
// Build MCP server config for sandbox — same as CLI provider
|
|
130
|
+
const tsPath = join(__ownDir, 'sandboxMcpStdio.ts');
|
|
131
|
+
const jsPath = join(__ownDir, 'sandboxMcpStdio.js');
|
|
132
|
+
const hasTsPath = existsSync(tsPath);
|
|
133
|
+
const options = {
|
|
134
|
+
cwd: opts.cwd,
|
|
135
|
+
permissionMode,
|
|
136
|
+
canUseTool,
|
|
137
|
+
includePartialMessages: true,
|
|
138
|
+
settingSources: ['project'],
|
|
139
|
+
mcpServers: {
|
|
140
|
+
[SANDBOX_MCP_NAME]: {
|
|
141
|
+
type: 'stdio',
|
|
142
|
+
command: hasTsPath ? 'npx' : 'node',
|
|
143
|
+
args: hasTsPath
|
|
144
|
+
? ['tsx', tsPath, '--cwd', opts.cwd]
|
|
145
|
+
: [jsPath, '--cwd', opts.cwd],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
systemPrompt: opts.systemPrompt
|
|
149
|
+
? { type: 'preset', preset: 'claude_code', append: opts.systemPrompt }
|
|
150
|
+
: { type: 'preset', preset: 'claude_code' },
|
|
151
|
+
};
|
|
152
|
+
if ('model' in opts && opts.model) {
|
|
153
|
+
options.model = opts.model;
|
|
154
|
+
}
|
|
155
|
+
if (permissionMode === 'bypassPermissions') {
|
|
156
|
+
options.allowDangerouslySkipPermissions = true;
|
|
157
|
+
}
|
|
158
|
+
if (resumeSessionId) {
|
|
159
|
+
options.resume = resumeSessionId;
|
|
160
|
+
}
|
|
161
|
+
return options;
|
|
162
|
+
}
|
|
163
|
+
mapPermissionMode(level) {
|
|
164
|
+
switch (level) {
|
|
165
|
+
case 'bypassPermissions': return 'bypassPermissions';
|
|
166
|
+
case 'acceptEdits': return 'acceptEdits';
|
|
167
|
+
case 'plan': return 'plan';
|
|
168
|
+
default: return 'default';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ── Private: Wait for Init ──
|
|
172
|
+
async waitForInit(queryHandle, callbacks) {
|
|
173
|
+
const timeout = setTimeout(() => {
|
|
174
|
+
throw new Error('Timeout waiting for SDK init');
|
|
175
|
+
}, 30_000);
|
|
176
|
+
try {
|
|
177
|
+
for await (const msg of queryHandle) {
|
|
178
|
+
if (msg.type === 'system' && msg.subtype === 'init' && msg.session_id) {
|
|
179
|
+
const initMsg = msg;
|
|
180
|
+
if (initMsg.model) {
|
|
181
|
+
callbacks.onModelDetected(initMsg.model);
|
|
182
|
+
}
|
|
183
|
+
clearTimeout(timeout);
|
|
184
|
+
return initMsg.session_id;
|
|
185
|
+
}
|
|
186
|
+
// Buffer non-init messages — they will be consumed in consumeStream
|
|
187
|
+
// Since we can't "unread" from the async generator, we break after init
|
|
188
|
+
// and let consumeStream handle remaining messages.
|
|
189
|
+
// Actually, for a generator we can't push back. We need to handle
|
|
190
|
+
// the first non-init messages here. But the SDK should emit init first.
|
|
191
|
+
// If we get a non-init message, skip it (unlikely before init).
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
clearTimeout(timeout);
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
198
|
+
clearTimeout(timeout);
|
|
199
|
+
throw new Error('SDK query ended without init message');
|
|
200
|
+
}
|
|
201
|
+
// ── Private: Stream Consumer ──
|
|
202
|
+
async consumeStream(sessionId, initialStreamId, queryHandle, sdkSession, cb, callbacks, prompt) {
|
|
203
|
+
let streamId = initialStreamId;
|
|
204
|
+
let textBuffer = '';
|
|
205
|
+
let bufferTimer = null;
|
|
206
|
+
let resultEmitted = false;
|
|
207
|
+
const emitCard = (event) => { callbacks.emitCardEvent(event); };
|
|
208
|
+
cb.startNewTurn(streamId);
|
|
209
|
+
// Add user prompt to cardBuilder (for getCards on reconnect) but don't emit
|
|
210
|
+
if (prompt) {
|
|
211
|
+
cb.userMessage(prompt);
|
|
212
|
+
}
|
|
213
|
+
const flushText = () => {
|
|
214
|
+
if (textBuffer) {
|
|
215
|
+
emitCard(cb.assistantText(textBuffer));
|
|
216
|
+
textBuffer = '';
|
|
217
|
+
}
|
|
218
|
+
if (bufferTimer) {
|
|
219
|
+
clearTimeout(bufferTimer);
|
|
220
|
+
bufferTimer = null;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const bufferText = (text) => {
|
|
224
|
+
textBuffer += text;
|
|
225
|
+
if (!bufferTimer) {
|
|
226
|
+
bufferTimer = setTimeout(flushText, 150);
|
|
227
|
+
}
|
|
228
|
+
if (textBuffer.length > 2048) {
|
|
229
|
+
flushText();
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
try {
|
|
233
|
+
for await (const msg of queryHandle) {
|
|
234
|
+
const emittedResult = await this.routeMessage(sessionId, streamId, msg, sdkSession, cb, callbacks, emitCard, flushText, bufferText);
|
|
235
|
+
if (emittedResult) {
|
|
236
|
+
resultEmitted = true;
|
|
237
|
+
// Check for hot resume — start new turn with next pending streamId
|
|
238
|
+
const nextStreamId = sdkSession.pendingStreamIds.shift();
|
|
239
|
+
if (nextStreamId) {
|
|
240
|
+
streamId = nextStreamId;
|
|
241
|
+
cb.startNewTurn(streamId);
|
|
242
|
+
resultEmitted = false; // Reset for next turn
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
flushText();
|
|
249
|
+
console.error(`[sdk] stream error session=${sessionId.slice(0, 8)}:`, error);
|
|
250
|
+
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
251
|
+
callbacks.emitStreamEnd({ streamId, sessionId, success: false, error: msg });
|
|
252
|
+
resultEmitted = true;
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
if (bufferTimer)
|
|
256
|
+
clearTimeout(bufferTimer);
|
|
257
|
+
sdkSession.markClosed();
|
|
258
|
+
if (!resultEmitted) {
|
|
259
|
+
callbacks.emitStreamEnd({ streamId, sessionId, success: false, error: 'SDK query ended unexpectedly' });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// ── Private: Route a single SDK message ──
|
|
264
|
+
// Returns true if a result/stream-end was emitted.
|
|
265
|
+
async routeMessage(sessionId, streamId, msg, _sdkSession, cb, callbacks, emitCard, flushText, bufferText) {
|
|
266
|
+
// ── System events ──
|
|
267
|
+
if (msg.type === 'system') {
|
|
268
|
+
const subtype = msg.subtype;
|
|
269
|
+
if (subtype === 'init') {
|
|
270
|
+
// Already handled in waitForInit — skip
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
if (subtype === 'task_started') {
|
|
274
|
+
flushText();
|
|
275
|
+
const m = msg;
|
|
276
|
+
emitCard(cb.subagentStart(m.description ?? '', m.task_id, m.tool_use_id));
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
if (subtype === 'task_progress') {
|
|
280
|
+
const m = msg;
|
|
281
|
+
const cardEvt = cb.subagentProgress(m.task_id, m.tool_use_id, m.usage?.tool_uses, m.last_tool_name);
|
|
282
|
+
if (cardEvt)
|
|
283
|
+
emitCard(cardEvt);
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
if (subtype === 'task_notification') {
|
|
287
|
+
const m = msg;
|
|
288
|
+
const cardEvt = cb.subagentEnd(m.task_id, m.tool_use_id, m.status, m.summary);
|
|
289
|
+
if (cardEvt)
|
|
290
|
+
emitCard(cardEvt);
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
// Other system subtypes (status, session_state_changed, compact_boundary, etc.) — skip
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
// ── Streaming partial events ──
|
|
297
|
+
if (msg.type === 'stream_event') {
|
|
298
|
+
// Filter subagent stream events by parent_tool_use_id
|
|
299
|
+
if (msg.parent_tool_use_id)
|
|
300
|
+
return false;
|
|
301
|
+
const event = msg.event;
|
|
302
|
+
if (event?.type === 'content_block_delta') {
|
|
303
|
+
const delta = event.delta;
|
|
304
|
+
if (delta?.type === 'text_delta' && delta.text) {
|
|
305
|
+
bufferText(delta.text);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
// ── Rate limit events ──
|
|
311
|
+
if (msg.type === 'rate_limit_event')
|
|
312
|
+
return false;
|
|
313
|
+
// ── Complete assistant messages ──
|
|
314
|
+
if (msg.type === 'assistant') {
|
|
315
|
+
// Filter subagent messages by parent_tool_use_id
|
|
316
|
+
if (msg.parent_tool_use_id)
|
|
317
|
+
return false;
|
|
318
|
+
flushText();
|
|
319
|
+
const blocks = msg.message?.content ?? [];
|
|
320
|
+
for (const block of blocks) {
|
|
321
|
+
if (block.type === 'thinking' && block.thinking) {
|
|
322
|
+
emitCard(cb.thinkingBlock(block.thinking));
|
|
323
|
+
}
|
|
324
|
+
else if (block.type === 'redacted_thinking') {
|
|
325
|
+
emitCard(cb.thinkingBlock('[Redacted thinking]'));
|
|
326
|
+
}
|
|
327
|
+
else if (block.type === 'text' && block.text) {
|
|
328
|
+
const finalizeEvt = cb.finalizeAssistantText();
|
|
329
|
+
if (finalizeEvt) {
|
|
330
|
+
emitCard(finalizeEvt);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
emitCard(cb.assistantText(block.text));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else if (block.type === 'tool_use') {
|
|
337
|
+
if (block.name !== 'Agent') {
|
|
338
|
+
emitCard(cb.toolUse(block.name, block.input ?? {}, block.id));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
else if (block.type === 'server_tool_use' || block.type === 'mcp_tool_use') {
|
|
342
|
+
emitCard(cb.toolUse(block.name ?? block.type, block.input ?? {}, block.id ?? ''));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
// ── User messages (tool results) ──
|
|
348
|
+
if (msg.type === 'user') {
|
|
349
|
+
// Filter subagent messages by parent_tool_use_id
|
|
350
|
+
if (msg.parent_tool_use_id)
|
|
351
|
+
return false;
|
|
352
|
+
const content = msg.message?.content;
|
|
353
|
+
// Skip user text echoes — we already have them from the inputQueue
|
|
354
|
+
if (typeof content === 'string')
|
|
355
|
+
return false;
|
|
356
|
+
if (Array.isArray(content)) {
|
|
357
|
+
for (const block of content) {
|
|
358
|
+
if (block.type === 'tool_result') {
|
|
359
|
+
const resultContent = extractToolResultText(block.content);
|
|
360
|
+
const cardEvt = cb.toolResult(block.tool_use_id, resultContent, !!block.is_error);
|
|
361
|
+
if (cardEvt)
|
|
362
|
+
emitCard(cardEvt);
|
|
363
|
+
}
|
|
364
|
+
if (block.type === 'web_search_tool_result' || block.type === 'web_fetch_tool_result' ||
|
|
365
|
+
block.type === 'mcp_tool_result' || block.type === 'code_execution_tool_result' ||
|
|
366
|
+
block.type === 'tool_search_tool_result') {
|
|
367
|
+
const resultContent = extractToolResultText(block.content ?? block.text ?? '');
|
|
368
|
+
const parentId = block.tool_use_id;
|
|
369
|
+
if (parentId) {
|
|
370
|
+
const cardEvt = cb.toolResult(parentId, resultContent, !!block.is_error);
|
|
371
|
+
if (cardEvt)
|
|
372
|
+
emitCard(cardEvt);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
// ── Result ──
|
|
380
|
+
if (msg.type === 'result') {
|
|
381
|
+
if (msg.session_id !== sessionId)
|
|
382
|
+
return false; // subagent result
|
|
383
|
+
flushText();
|
|
384
|
+
const terminalReason = msg.terminal_reason;
|
|
385
|
+
const interrupted = terminalReason === 'aborted_tools' || terminalReason === 'aborted_streaming';
|
|
386
|
+
const totalCost = msg.total_cost_usd;
|
|
387
|
+
console.log(`[sdk] result session=${sessionId.slice(0, 8)} subtype=${msg.subtype} cost=$${totalCost?.toFixed(4) ?? '?'}`);
|
|
388
|
+
if (interrupted) {
|
|
389
|
+
emitCard(cb.systemMessage('User interrupted'));
|
|
390
|
+
}
|
|
391
|
+
const finalizeEvent = cb.finalizeAssistantText();
|
|
392
|
+
if (finalizeEvent)
|
|
393
|
+
emitCard(finalizeEvent);
|
|
394
|
+
const usage = msg.usage;
|
|
395
|
+
const errors = msg.errors;
|
|
396
|
+
const streamEnd = {
|
|
397
|
+
streamId,
|
|
398
|
+
sessionId,
|
|
399
|
+
success: msg.subtype === 'success' && !interrupted,
|
|
400
|
+
error: (msg.subtype !== 'success' && !interrupted)
|
|
401
|
+
? (errors?.join('; ') || `Session ended: ${msg.subtype}`)
|
|
402
|
+
: undefined,
|
|
403
|
+
interrupted,
|
|
404
|
+
totalCostUsd: totalCost,
|
|
405
|
+
tokenUsage: usage
|
|
406
|
+
? { input: usage.input_tokens, output: usage.output_tokens }
|
|
407
|
+
: undefined,
|
|
408
|
+
};
|
|
409
|
+
callbacks.emitStreamEnd(streamEnd);
|
|
410
|
+
// Clear accumulated cards — JSONL now has the full history for this turn
|
|
411
|
+
cb.clearCards();
|
|
412
|
+
await cb.snapshotCutoff();
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=claudeSdkProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeSdkProvider.js","sourceRoot":"","sources":["../../src/ai/claudeSdkProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,10 @@ export interface GenerateSummaryOptions {
|
|
|
3
3
|
diffs: FileDiff[];
|
|
4
4
|
context?: string;
|
|
5
5
|
model?: ClaudeModel;
|
|
6
|
+
recentCommits?: string[];
|
|
7
|
+
branchName?: string;
|
|
8
|
+
conventions?: string;
|
|
9
|
+
attribution?: boolean;
|
|
6
10
|
}
|
|
7
11
|
export interface GenerateSummaryResult {
|
|
8
12
|
summary: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commitSummary.d.ts","sourceRoot":"","sources":["../../src/ai/commitSummary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEnF,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"commitSummary.d.ts","sourceRoot":"","sources":["../../src/ai/commitSummary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEnF,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAkCD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,eAAe,CAAqD;gBAEhE,MAAM,EAAE,MAAM;IAIpB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;YAyCxE,iBAAiB;IAmC/B,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,oBAAoB;IAiC5B,OAAO,CAAC,WAAW;IAwCnB,OAAO,CAAC,aAAa;CAmCtB"}
|
package/dist/ai/commitSummary.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
3
|
const DEFAULT_MODEL = 'claude-haiku-4-5';
|
|
4
|
+
const COMMIT_MESSAGE_TOOL = {
|
|
5
|
+
name: 'commit_message',
|
|
6
|
+
description: 'Generate a structured git commit message',
|
|
7
|
+
input_schema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
summary: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'The commit summary line (under 72 characters, conventional commit format)',
|
|
13
|
+
},
|
|
14
|
+
description: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Optional extended description for complex changes',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
required: ['summary'],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
4
22
|
// Max characters per file diff for AI generation (roughly 1KB)
|
|
5
23
|
const MAX_DIFF_CHARS_PER_FILE = 1000;
|
|
6
24
|
// Max total characters for all diffs combined
|
|
@@ -15,12 +33,12 @@ export class CommitSummaryService {
|
|
|
15
33
|
this.client = new Anthropic({ apiKey });
|
|
16
34
|
}
|
|
17
35
|
async generateSummary(options) {
|
|
18
|
-
const { diffs, context, model = DEFAULT_MODEL } = options;
|
|
36
|
+
const { diffs, context, model = DEFAULT_MODEL, recentCommits, branchName, conventions, attribution = true } = options;
|
|
19
37
|
const diffText = this.formatDiffsForPrompt(diffs);
|
|
20
38
|
if (!diffText.trim()) {
|
|
21
39
|
return { summary: 'Update files' };
|
|
22
40
|
}
|
|
23
|
-
// Generate cache key from diff content and
|
|
41
|
+
// Generate cache key from diff content, model, and context
|
|
24
42
|
const cacheKey = this.getCacheKey(diffText, context, model);
|
|
25
43
|
// Check cache first
|
|
26
44
|
const cached = this.getFromCache(cacheKey);
|
|
@@ -34,7 +52,12 @@ export class CommitSummaryService {
|
|
|
34
52
|
return { ...result, cached: true };
|
|
35
53
|
}
|
|
36
54
|
// Create the request promise and store it
|
|
37
|
-
const requestPromise = this.executeGeneration(diffText, context, model, cacheKey
|
|
55
|
+
const requestPromise = this.executeGeneration(diffText, context, model, cacheKey, {
|
|
56
|
+
recentCommits,
|
|
57
|
+
branchName,
|
|
58
|
+
conventions,
|
|
59
|
+
attribution,
|
|
60
|
+
});
|
|
38
61
|
this.pendingRequests.set(cacheKey, requestPromise);
|
|
39
62
|
try {
|
|
40
63
|
return await requestPromise;
|
|
@@ -43,14 +66,22 @@ export class CommitSummaryService {
|
|
|
43
66
|
this.pendingRequests.delete(cacheKey);
|
|
44
67
|
}
|
|
45
68
|
}
|
|
46
|
-
async executeGeneration(diffText, context, model, cacheKey) {
|
|
47
|
-
const prompt = this.buildPrompt(diffText, context);
|
|
69
|
+
async executeGeneration(diffText, context, model, cacheKey, extra) {
|
|
70
|
+
const prompt = this.buildPrompt(diffText, context, extra);
|
|
48
71
|
const response = await this.client.messages.create({
|
|
49
72
|
model,
|
|
50
73
|
max_tokens: 500,
|
|
51
74
|
messages: [{ role: 'user', content: prompt }],
|
|
75
|
+
tools: [COMMIT_MESSAGE_TOOL],
|
|
76
|
+
tool_choice: { type: 'tool', name: 'commit_message' },
|
|
52
77
|
});
|
|
53
78
|
const result = this.parseResponse(response);
|
|
79
|
+
if (extra.attribution !== false) {
|
|
80
|
+
const aiTrailer = 'Commit-message-by: Quicksave AI <save@quicksave.dev>';
|
|
81
|
+
result.description = result.description
|
|
82
|
+
? `${result.description}\n\n${aiTrailer}`
|
|
83
|
+
: aiTrailer;
|
|
84
|
+
}
|
|
54
85
|
// Store in cache
|
|
55
86
|
this.cache.set(cacheKey, {
|
|
56
87
|
result,
|
|
@@ -98,48 +129,57 @@ export class CommitSummaryService {
|
|
|
98
129
|
}
|
|
99
130
|
return formattedDiffs.join('\n\n---\n\n');
|
|
100
131
|
}
|
|
101
|
-
buildPrompt(diffText, context) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
132
|
+
buildPrompt(diffText, context, extra) {
|
|
133
|
+
const sections = [
|
|
134
|
+
'Generate a concise, descriptive git commit message for the following changes.',
|
|
135
|
+
'',
|
|
136
|
+
'Guidelines:',
|
|
137
|
+
'- Use conventional commit format (feat:, fix:, docs:, refactor:, chore:, test:, style:, perf:, ci:, build:)',
|
|
138
|
+
'- Keep the summary line under 72 characters',
|
|
139
|
+
'- Focus on WHAT changed and WHY, not HOW',
|
|
140
|
+
'- Be specific but concise',
|
|
141
|
+
];
|
|
142
|
+
if (extra?.conventions) {
|
|
143
|
+
sections.push('', 'Project commit conventions:', extra.conventions);
|
|
144
|
+
}
|
|
145
|
+
if (extra?.recentCommits?.length) {
|
|
146
|
+
sections.push('', 'Recent commits (match this style):', ...extra.recentCommits.map((msg) => `- ${msg}`));
|
|
147
|
+
}
|
|
148
|
+
if (extra?.branchName) {
|
|
149
|
+
sections.push('', `Branch: ${extra.branchName}`);
|
|
150
|
+
}
|
|
151
|
+
if (context) {
|
|
152
|
+
sections.push('', `User context: ${context}`);
|
|
153
|
+
}
|
|
154
|
+
sections.push('', 'Git diff:', '```', diffText, '```');
|
|
155
|
+
return sections.join('\n');
|
|
121
156
|
}
|
|
122
157
|
parseResponse(response) {
|
|
123
|
-
const content = response.content[0];
|
|
124
|
-
if (content.type !== 'text') {
|
|
125
|
-
throw new Error('Unexpected response format');
|
|
126
|
-
}
|
|
127
158
|
const tokenUsage = {
|
|
128
159
|
inputTokens: response.usage.input_tokens,
|
|
129
160
|
outputTokens: response.usage.output_tokens,
|
|
130
161
|
};
|
|
131
|
-
//
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
return {
|
|
162
|
+
// Extract from tool_use block (structured output)
|
|
163
|
+
const toolUse = response.content.find((block) => block.type === 'tool_use');
|
|
164
|
+
if (toolUse) {
|
|
165
|
+
const input = toolUse.input;
|
|
166
|
+
return {
|
|
167
|
+
summary: input.summary || 'Update code',
|
|
168
|
+
description: input.description,
|
|
169
|
+
tokenUsage,
|
|
170
|
+
};
|
|
136
171
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
172
|
+
// Fallback: parse from text if tool_use not present
|
|
173
|
+
const textBlock = response.content.find((block) => block.type === 'text');
|
|
174
|
+
if (textBlock) {
|
|
175
|
+
const jsonMatch = textBlock.text.match(/\{[\s\S]*\}/);
|
|
176
|
+
if (jsonMatch) {
|
|
177
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
178
|
+
return { summary: parsed.summary || 'Update code', description: parsed.description, tokenUsage };
|
|
179
|
+
}
|
|
180
|
+
return { summary: textBlock.text.trim().slice(0, 72), tokenUsage };
|
|
181
|
+
}
|
|
182
|
+
return { summary: 'Update code', tokenUsage };
|
|
143
183
|
}
|
|
144
184
|
}
|
|
145
185
|
//# sourceMappingURL=commitSummary.js.map
|