@co0ontty/wand 1.39.0 → 1.40.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.
- package/dist/cli.js +0 -0
- package/dist/git-quick-commit.js +27 -0
- package/dist/process-manager.d.ts +1 -0
- package/dist/process-manager.js +134 -11
- package/dist/resume-policy.d.ts +1 -0
- package/dist/resume-policy.js +7 -1
- package/dist/server-session-routes.js +30 -10
- package/dist/types.d.ts +4 -0
- package/dist/web-ui/content/scripts.js +563 -263
- package/dist/web-ui/content/styles.css +372 -356
- package/package.json +1 -1
- package/dist/acp-protocol.d.ts +0 -67
- package/dist/acp-protocol.js +0 -291
- package/dist/claude-stream-adapter.d.ts +0 -35
- package/dist/claude-stream-adapter.js +0 -153
- package/dist/claude-structured-runner.d.ts +0 -27
- package/dist/claude-structured-runner.js +0 -106
- package/dist/message-parser.d.ts +0 -2
- package/dist/message-parser.js +0 -329
- package/dist/message-queue.d.ts +0 -57
- package/dist/message-queue.js +0 -127
- package/dist/session-lifecycle.d.ts +0 -81
- package/dist/session-lifecycle.js +0 -176
package/package.json
CHANGED
package/dist/acp-protocol.d.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ACP (Agent Communication Protocol) implementation
|
|
3
|
-
* Inspired by Happy's unified agent communication format
|
|
4
|
-
*/
|
|
5
|
-
import type { ACPMessage, ACPTextMessage, ACPReasoningMessage, ACPToolCallMessage, ACPToolResultMessage, ACPFileEditMessage, ACPTerminalOutputMessage, ACPPermissionRequestMessage, ACPSessionStartMessage, ACPSessionEndMessage, ACPErrorMessage, ConversationTurn } from "./types.js";
|
|
6
|
-
/**
|
|
7
|
-
* Create a text message
|
|
8
|
-
*/
|
|
9
|
-
export declare function createTextMessage(sessionId: string, role: "user" | "assistant" | "system", content: string): ACPTextMessage;
|
|
10
|
-
/**
|
|
11
|
-
* Create a reasoning message
|
|
12
|
-
*/
|
|
13
|
-
export declare function createReasoningMessage(sessionId: string, content: string, isStreaming?: boolean): ACPReasoningMessage;
|
|
14
|
-
/**
|
|
15
|
-
* Create a tool call message
|
|
16
|
-
*/
|
|
17
|
-
export declare function createToolCallMessage(sessionId: string, toolCallId: string, name: string, input: Record<string, unknown>, description?: string): ACPToolCallMessage;
|
|
18
|
-
/**
|
|
19
|
-
* Create a tool result message
|
|
20
|
-
*/
|
|
21
|
-
export declare function createToolResultMessage(sessionId: string, toolCallId: string, output: string | Array<{
|
|
22
|
-
type: string;
|
|
23
|
-
[key: string]: unknown;
|
|
24
|
-
}>, isError?: boolean): ACPToolResultMessage;
|
|
25
|
-
/**
|
|
26
|
-
* Create a file edit message
|
|
27
|
-
*/
|
|
28
|
-
export declare function createFileEditMessage(sessionId: string, filePath: string, description: string, options?: {
|
|
29
|
-
oldContent?: string;
|
|
30
|
-
newContent?: string;
|
|
31
|
-
diff?: string;
|
|
32
|
-
}): ACPFileEditMessage;
|
|
33
|
-
/**
|
|
34
|
-
* Create a terminal output message
|
|
35
|
-
*/
|
|
36
|
-
export declare function createTerminalOutputMessage(sessionId: string, data: string, toolCallId?: string): ACPTerminalOutputMessage;
|
|
37
|
-
/**
|
|
38
|
-
* Create a permission request message
|
|
39
|
-
*/
|
|
40
|
-
export declare function createPermissionRequestMessage(sessionId: string, permissionId: string, toolName: string, description: string): ACPPermissionRequestMessage;
|
|
41
|
-
/**
|
|
42
|
-
* Create a session start message
|
|
43
|
-
*/
|
|
44
|
-
export declare function createSessionStartMessage(sessionId: string, workingDirectory: string, agent?: string): ACPSessionStartMessage;
|
|
45
|
-
/**
|
|
46
|
-
* Create a session end message
|
|
47
|
-
*/
|
|
48
|
-
export declare function createSessionEndMessage(sessionId: string, exitCode: number | null): ACPSessionEndMessage;
|
|
49
|
-
/**
|
|
50
|
-
* Create an error message
|
|
51
|
-
*/
|
|
52
|
-
export declare function createErrorMessage(sessionId: string, error: string, details?: string): ACPErrorMessage;
|
|
53
|
-
/**
|
|
54
|
-
* Convert ConversationTurn to ACP messages
|
|
55
|
-
*/
|
|
56
|
-
export declare function conversationTurnToACP(sessionId: string, turn: ConversationTurn): ACPMessage[];
|
|
57
|
-
/**
|
|
58
|
-
* Convert ACP messages to ConversationTurn
|
|
59
|
-
*/
|
|
60
|
-
export declare function acpToConversationTurns(messages: ACPMessage[]): ConversationTurn[];
|
|
61
|
-
/**
|
|
62
|
-
* Parse Claude stream-json event to ACP message
|
|
63
|
-
*/
|
|
64
|
-
export declare function parseClaudeStreamEvent(sessionId: string, event: {
|
|
65
|
-
type?: string;
|
|
66
|
-
[key: string]: unknown;
|
|
67
|
-
}): ACPMessage | null;
|
package/dist/acp-protocol.js
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ACP (Agent Communication Protocol) implementation
|
|
3
|
-
* Inspired by Happy's unified agent communication format
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Generate a unique message ID
|
|
7
|
-
*/
|
|
8
|
-
function generateId() {
|
|
9
|
-
return `acp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Create a text message
|
|
13
|
-
*/
|
|
14
|
-
export function createTextMessage(sessionId, role, content) {
|
|
15
|
-
return {
|
|
16
|
-
id: generateId(),
|
|
17
|
-
type: "message",
|
|
18
|
-
timestamp: Date.now(),
|
|
19
|
-
sessionId,
|
|
20
|
-
role,
|
|
21
|
-
content,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Create a reasoning message
|
|
26
|
-
*/
|
|
27
|
-
export function createReasoningMessage(sessionId, content, isStreaming = false) {
|
|
28
|
-
return {
|
|
29
|
-
id: generateId(),
|
|
30
|
-
type: "reasoning",
|
|
31
|
-
timestamp: Date.now(),
|
|
32
|
-
sessionId,
|
|
33
|
-
content,
|
|
34
|
-
isStreaming,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Create a tool call message
|
|
39
|
-
*/
|
|
40
|
-
export function createToolCallMessage(sessionId, toolCallId, name, input, description) {
|
|
41
|
-
return {
|
|
42
|
-
id: generateId(),
|
|
43
|
-
type: "tool-call",
|
|
44
|
-
timestamp: Date.now(),
|
|
45
|
-
sessionId,
|
|
46
|
-
toolCallId,
|
|
47
|
-
name,
|
|
48
|
-
input,
|
|
49
|
-
description,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Create a tool result message
|
|
54
|
-
*/
|
|
55
|
-
export function createToolResultMessage(sessionId, toolCallId, output, isError = false) {
|
|
56
|
-
return {
|
|
57
|
-
id: generateId(),
|
|
58
|
-
type: "tool-result",
|
|
59
|
-
timestamp: Date.now(),
|
|
60
|
-
sessionId,
|
|
61
|
-
toolCallId,
|
|
62
|
-
output,
|
|
63
|
-
isError,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Create a file edit message
|
|
68
|
-
*/
|
|
69
|
-
export function createFileEditMessage(sessionId, filePath, description, options = {}) {
|
|
70
|
-
return {
|
|
71
|
-
id: generateId(),
|
|
72
|
-
type: "file-edit",
|
|
73
|
-
timestamp: Date.now(),
|
|
74
|
-
sessionId,
|
|
75
|
-
filePath,
|
|
76
|
-
description,
|
|
77
|
-
...options,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Create a terminal output message
|
|
82
|
-
*/
|
|
83
|
-
export function createTerminalOutputMessage(sessionId, data, toolCallId) {
|
|
84
|
-
return {
|
|
85
|
-
id: generateId(),
|
|
86
|
-
type: "terminal-output",
|
|
87
|
-
timestamp: Date.now(),
|
|
88
|
-
sessionId,
|
|
89
|
-
data,
|
|
90
|
-
toolCallId,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Create a permission request message
|
|
95
|
-
*/
|
|
96
|
-
export function createPermissionRequestMessage(sessionId, permissionId, toolName, description) {
|
|
97
|
-
return {
|
|
98
|
-
id: generateId(),
|
|
99
|
-
type: "permission-request",
|
|
100
|
-
timestamp: Date.now(),
|
|
101
|
-
sessionId,
|
|
102
|
-
permissionId,
|
|
103
|
-
toolName,
|
|
104
|
-
description,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Create a session start message
|
|
109
|
-
*/
|
|
110
|
-
export function createSessionStartMessage(sessionId, workingDirectory, agent) {
|
|
111
|
-
return {
|
|
112
|
-
id: generateId(),
|
|
113
|
-
type: "session-start",
|
|
114
|
-
timestamp: Date.now(),
|
|
115
|
-
sessionId,
|
|
116
|
-
workingDirectory,
|
|
117
|
-
agent,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Create a session end message
|
|
122
|
-
*/
|
|
123
|
-
export function createSessionEndMessage(sessionId, exitCode) {
|
|
124
|
-
return {
|
|
125
|
-
id: generateId(),
|
|
126
|
-
type: "session-end",
|
|
127
|
-
timestamp: Date.now(),
|
|
128
|
-
sessionId,
|
|
129
|
-
exitCode,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Create an error message
|
|
134
|
-
*/
|
|
135
|
-
export function createErrorMessage(sessionId, error, details) {
|
|
136
|
-
return {
|
|
137
|
-
id: generateId(),
|
|
138
|
-
type: "error",
|
|
139
|
-
timestamp: Date.now(),
|
|
140
|
-
sessionId,
|
|
141
|
-
error,
|
|
142
|
-
details,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Convert ConversationTurn to ACP messages
|
|
147
|
-
*/
|
|
148
|
-
export function conversationTurnToACP(sessionId, turn) {
|
|
149
|
-
const messages = [];
|
|
150
|
-
for (const block of turn.content) {
|
|
151
|
-
switch (block.type) {
|
|
152
|
-
case "text":
|
|
153
|
-
messages.push(createTextMessage(sessionId, turn.role, block.text));
|
|
154
|
-
break;
|
|
155
|
-
case "thinking":
|
|
156
|
-
messages.push(createReasoningMessage(sessionId, block.thinking));
|
|
157
|
-
break;
|
|
158
|
-
case "tool_use":
|
|
159
|
-
messages.push(createToolCallMessage(sessionId, block.id, block.name, block.input, block.description));
|
|
160
|
-
break;
|
|
161
|
-
case "tool_result":
|
|
162
|
-
messages.push(createToolResultMessage(sessionId, block.tool_use_id, block.content, block.is_error ?? false));
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return messages;
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Convert ACP messages to ConversationTurn
|
|
170
|
-
*/
|
|
171
|
-
export function acpToConversationTurns(messages) {
|
|
172
|
-
const turns = [];
|
|
173
|
-
let currentTurn = null;
|
|
174
|
-
for (const msg of messages) {
|
|
175
|
-
switch (msg.type) {
|
|
176
|
-
case "message":
|
|
177
|
-
if (msg.role === "user") {
|
|
178
|
-
// Start a new user turn
|
|
179
|
-
if (currentTurn) {
|
|
180
|
-
turns.push(currentTurn);
|
|
181
|
-
}
|
|
182
|
-
currentTurn = {
|
|
183
|
-
role: "user",
|
|
184
|
-
content: [{ type: "text", text: msg.content }],
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
else if (msg.role === "assistant") {
|
|
188
|
-
if (currentTurn?.role === "assistant") {
|
|
189
|
-
// Add to existing assistant turn
|
|
190
|
-
currentTurn.content.push({ type: "text", text: msg.content });
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
// Start new assistant turn
|
|
194
|
-
if (currentTurn) {
|
|
195
|
-
turns.push(currentTurn);
|
|
196
|
-
}
|
|
197
|
-
currentTurn = {
|
|
198
|
-
role: "assistant",
|
|
199
|
-
content: [{ type: "text", text: msg.content }],
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
break;
|
|
204
|
-
case "reasoning":
|
|
205
|
-
if (currentTurn?.role === "assistant") {
|
|
206
|
-
currentTurn.content.push({ type: "thinking", thinking: msg.content });
|
|
207
|
-
}
|
|
208
|
-
break;
|
|
209
|
-
case "tool-call":
|
|
210
|
-
if (currentTurn?.role === "assistant") {
|
|
211
|
-
currentTurn.content.push({
|
|
212
|
-
type: "tool_use",
|
|
213
|
-
id: msg.toolCallId,
|
|
214
|
-
name: msg.name,
|
|
215
|
-
input: msg.input,
|
|
216
|
-
description: msg.description,
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
break;
|
|
220
|
-
case "tool-result":
|
|
221
|
-
if (currentTurn?.role === "assistant") {
|
|
222
|
-
currentTurn.content.push({
|
|
223
|
-
type: "tool_result",
|
|
224
|
-
tool_use_id: msg.toolCallId,
|
|
225
|
-
content: msg.output,
|
|
226
|
-
is_error: msg.isError,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
if (currentTurn) {
|
|
233
|
-
turns.push(currentTurn);
|
|
234
|
-
}
|
|
235
|
-
return turns;
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Parse Claude stream-json event to ACP message
|
|
239
|
-
*/
|
|
240
|
-
export function parseClaudeStreamEvent(sessionId, event) {
|
|
241
|
-
switch (event.type) {
|
|
242
|
-
case "content_block_start": {
|
|
243
|
-
const block = event.content_block;
|
|
244
|
-
if (!block)
|
|
245
|
-
return null;
|
|
246
|
-
if (block.type === "text") {
|
|
247
|
-
return createTextMessage(sessionId, "assistant", "");
|
|
248
|
-
}
|
|
249
|
-
if (block.type === "thinking") {
|
|
250
|
-
return createReasoningMessage(sessionId, "", true);
|
|
251
|
-
}
|
|
252
|
-
if (block.type === "tool_use") {
|
|
253
|
-
return createToolCallMessage(sessionId, block.id ?? "", block.name ?? "", block.input ?? {});
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
case "content_block_delta": {
|
|
258
|
-
const delta = event.delta;
|
|
259
|
-
if (!delta)
|
|
260
|
-
return null;
|
|
261
|
-
if (delta.type === "text_delta" && delta.text) {
|
|
262
|
-
return createTextMessage(sessionId, "assistant", delta.text);
|
|
263
|
-
}
|
|
264
|
-
if (delta.type === "thinking_delta" && delta.thinking) {
|
|
265
|
-
return createReasoningMessage(sessionId, delta.thinking, true);
|
|
266
|
-
}
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
case "content_block_stop": {
|
|
270
|
-
// Block completed - could emit a completion event
|
|
271
|
-
return null;
|
|
272
|
-
}
|
|
273
|
-
case "message_start": {
|
|
274
|
-
const message = event.message;
|
|
275
|
-
if (message?.role === "assistant") {
|
|
276
|
-
return createTextMessage(sessionId, "assistant", "");
|
|
277
|
-
}
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
case "message_stop": {
|
|
281
|
-
// Message completed
|
|
282
|
-
return null;
|
|
283
|
-
}
|
|
284
|
-
case "error": {
|
|
285
|
-
const error = event.error;
|
|
286
|
-
return createErrorMessage(sessionId, error?.message ?? "Unknown error");
|
|
287
|
-
}
|
|
288
|
-
default:
|
|
289
|
-
return null;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { ContentBlock } from "./types.js";
|
|
2
|
-
export interface ClaudeStreamAdapterState {
|
|
3
|
-
blocks: ContentBlock[];
|
|
4
|
-
usage?: {
|
|
5
|
-
inputTokens?: number;
|
|
6
|
-
outputTokens?: number;
|
|
7
|
-
cacheReadInputTokens?: number;
|
|
8
|
-
cacheCreationInputTokens?: number;
|
|
9
|
-
totalCostUsd?: number;
|
|
10
|
-
};
|
|
11
|
-
sessionId: string | null;
|
|
12
|
-
}
|
|
13
|
-
type ClaudeStreamEvent = {
|
|
14
|
-
type?: string;
|
|
15
|
-
session_id?: string;
|
|
16
|
-
message?: {
|
|
17
|
-
role?: string;
|
|
18
|
-
content?: unknown[];
|
|
19
|
-
};
|
|
20
|
-
content_block?: {
|
|
21
|
-
type?: string;
|
|
22
|
-
[key: string]: unknown;
|
|
23
|
-
};
|
|
24
|
-
delta?: {
|
|
25
|
-
type?: string;
|
|
26
|
-
text?: string;
|
|
27
|
-
thinking?: string;
|
|
28
|
-
partial_json?: string;
|
|
29
|
-
};
|
|
30
|
-
result?: unknown;
|
|
31
|
-
usage?: Record<string, unknown>;
|
|
32
|
-
total_cost_usd?: number;
|
|
33
|
-
};
|
|
34
|
-
export declare function updateClaudeStreamState(state: ClaudeStreamAdapterState, event: ClaudeStreamEvent): ClaudeStreamAdapterState;
|
|
35
|
-
export {};
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
function normalizeToolInput(block) {
|
|
2
|
-
if (typeof block._partialJson === "string" && block._partialJson.length > 0) {
|
|
3
|
-
try {
|
|
4
|
-
const parsed = JSON.parse(block._partialJson);
|
|
5
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
6
|
-
return parsed;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
catch {
|
|
10
|
-
// Keep original input if partial JSON is incomplete.
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
if (block.input && typeof block.input === "object" && !Array.isArray(block.input)) {
|
|
14
|
-
return block.input;
|
|
15
|
-
}
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
18
|
-
function appendAssistantBlock(target, block) {
|
|
19
|
-
if (!block.type) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
if (block.type === "text") {
|
|
23
|
-
target.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (block.type === "thinking") {
|
|
27
|
-
target.push({ type: "thinking", thinking: typeof block.thinking === "string" ? block.thinking : "" });
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (block.type === "tool_use") {
|
|
31
|
-
target.push({
|
|
32
|
-
type: "tool_use",
|
|
33
|
-
id: typeof block.id === "string" ? block.id : "",
|
|
34
|
-
name: typeof block.name === "string" ? block.name : "",
|
|
35
|
-
description: typeof block.description === "string" ? block.description : undefined,
|
|
36
|
-
input: normalizeToolInput({ input: block.input, _partialJson: block._partialJson }),
|
|
37
|
-
});
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (block.type === "tool_result") {
|
|
41
|
-
const content = typeof block.content === "string"
|
|
42
|
-
? block.content
|
|
43
|
-
: Array.isArray(block.content)
|
|
44
|
-
? block.content
|
|
45
|
-
: "";
|
|
46
|
-
target.push({
|
|
47
|
-
type: "tool_result",
|
|
48
|
-
tool_use_id: typeof block.tool_use_id === "string" ? block.tool_use_id : "",
|
|
49
|
-
content,
|
|
50
|
-
is_error: block.is_error === true,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function buildUsage(event) {
|
|
55
|
-
if (!event.usage && event.total_cost_usd === undefined) {
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
inputTokens: typeof event.usage?.input_tokens === "number" ? event.usage.input_tokens : undefined,
|
|
60
|
-
outputTokens: typeof event.usage?.output_tokens === "number" ? event.usage.output_tokens : undefined,
|
|
61
|
-
cacheReadInputTokens: typeof event.usage?.cache_read_input_tokens === "number"
|
|
62
|
-
? event.usage.cache_read_input_tokens
|
|
63
|
-
: undefined,
|
|
64
|
-
cacheCreationInputTokens: typeof event.usage?.cache_creation_input_tokens === "number"
|
|
65
|
-
? event.usage.cache_creation_input_tokens
|
|
66
|
-
: undefined,
|
|
67
|
-
totalCostUsd: typeof event.total_cost_usd === "number" ? event.total_cost_usd : undefined,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
export function updateClaudeStreamState(state, event) {
|
|
71
|
-
if (typeof event.session_id === "string" && event.session_id.length > 0) {
|
|
72
|
-
state.sessionId = event.session_id;
|
|
73
|
-
}
|
|
74
|
-
switch (event.type) {
|
|
75
|
-
case "assistant": {
|
|
76
|
-
const content = Array.isArray(event.message?.content) ? event.message?.content : [];
|
|
77
|
-
for (const block of content) {
|
|
78
|
-
if (block && typeof block === "object" && "type" in block) {
|
|
79
|
-
appendAssistantBlock(state.blocks, block);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
case "content_block_start": {
|
|
85
|
-
if (event.content_block && typeof event.content_block === "object") {
|
|
86
|
-
appendAssistantBlock(state.blocks, event.content_block);
|
|
87
|
-
}
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
case "content_block_delta": {
|
|
91
|
-
const lastBlock = state.blocks[state.blocks.length - 1];
|
|
92
|
-
if (!lastBlock || !event.delta) {
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
if (lastBlock.type === "text" && event.delta.type === "text_delta" && typeof event.delta.text === "string") {
|
|
96
|
-
lastBlock.text += event.delta.text;
|
|
97
|
-
}
|
|
98
|
-
else if (lastBlock.type === "thinking" &&
|
|
99
|
-
event.delta.type === "thinking_delta" &&
|
|
100
|
-
typeof event.delta.thinking === "string") {
|
|
101
|
-
lastBlock.thinking += event.delta.thinking;
|
|
102
|
-
}
|
|
103
|
-
else if (lastBlock.type === "tool_use" &&
|
|
104
|
-
typeof event.delta.partial_json === "string") {
|
|
105
|
-
const nextPartial = (lastBlock._partialJson ?? "") + event.delta.partial_json;
|
|
106
|
-
lastBlock._partialJson = nextPartial;
|
|
107
|
-
lastBlock.input = normalizeToolInput({
|
|
108
|
-
input: lastBlock.input,
|
|
109
|
-
_partialJson: nextPartial,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
case "user": {
|
|
115
|
-
const content = Array.isArray(event.message?.content) ? event.message?.content : [];
|
|
116
|
-
for (const block of content) {
|
|
117
|
-
if (block &&
|
|
118
|
-
typeof block === "object" &&
|
|
119
|
-
"type" in block &&
|
|
120
|
-
block.type === "tool_result") {
|
|
121
|
-
appendAssistantBlock(state.blocks, block);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
case "result": {
|
|
127
|
-
const usage = buildUsage(event);
|
|
128
|
-
if (usage) {
|
|
129
|
-
state.usage = usage;
|
|
130
|
-
}
|
|
131
|
-
if (typeof event.result === "string") {
|
|
132
|
-
const hasAssistantText = state.blocks.some((block) => block.type === "text");
|
|
133
|
-
if (!hasAssistantText && event.result.trim().length > 0) {
|
|
134
|
-
state.blocks.push({ type: "text", text: event.result });
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else if (event.result && typeof event.result === "object") {
|
|
138
|
-
const resultContent = event.result.content;
|
|
139
|
-
if (Array.isArray(resultContent)) {
|
|
140
|
-
for (const block of resultContent) {
|
|
141
|
-
if (block && typeof block === "object" && "type" in block) {
|
|
142
|
-
appendAssistantBlock(state.blocks, block);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
default:
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
return state;
|
|
153
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { ChildProcess } from "node:child_process";
|
|
2
|
-
import type { ContentBlock, ConversationTurn } from "./types.js";
|
|
3
|
-
export interface ClaudeStructuredRunnerCallbacks {
|
|
4
|
-
onOutput: (text: string) => void;
|
|
5
|
-
onBlocks: (blocks: ContentBlock[], usage?: ConversationTurn["usage"]) => void;
|
|
6
|
-
onSessionId: (sessionId: string) => void;
|
|
7
|
-
onClose: (exitCode: number | null, state: ClaudeStructuredRunnerState) => void;
|
|
8
|
-
onError: (error: Error) => void;
|
|
9
|
-
}
|
|
10
|
-
export interface ClaudeStructuredRunnerState {
|
|
11
|
-
stdoutBuffer: string;
|
|
12
|
-
assistantBlocks: ContentBlock[];
|
|
13
|
-
usage?: ConversationTurn["usage"];
|
|
14
|
-
sessionId: string | null;
|
|
15
|
-
}
|
|
16
|
-
export interface StartClaudeStructuredRunnerOptions {
|
|
17
|
-
command: string;
|
|
18
|
-
cwd: string;
|
|
19
|
-
env?: NodeJS.ProcessEnv;
|
|
20
|
-
callbacks: ClaudeStructuredRunnerCallbacks;
|
|
21
|
-
}
|
|
22
|
-
export interface ClaudeStructuredRunnerHandle {
|
|
23
|
-
child: ChildProcess;
|
|
24
|
-
getState: () => ClaudeStructuredRunnerState;
|
|
25
|
-
kill: () => void;
|
|
26
|
-
}
|
|
27
|
-
export declare function startClaudeStructuredRunner(options: StartClaudeStructuredRunnerOptions): ClaudeStructuredRunnerHandle;
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { updateClaudeStreamState } from "./claude-stream-adapter.js";
|
|
3
|
-
function toContentBlocks(blocks) {
|
|
4
|
-
return blocks.map((block) => {
|
|
5
|
-
switch (block.type) {
|
|
6
|
-
case "text":
|
|
7
|
-
return { type: "text", text: typeof block.text === "string" ? block.text : "" };
|
|
8
|
-
case "thinking":
|
|
9
|
-
return { type: "thinking", thinking: typeof block.thinking === "string" ? block.thinking : "" };
|
|
10
|
-
case "tool_use":
|
|
11
|
-
return {
|
|
12
|
-
type: "tool_use",
|
|
13
|
-
id: typeof block.id === "string" ? block.id : "",
|
|
14
|
-
name: typeof block.name === "string" ? block.name : "",
|
|
15
|
-
description: typeof block.description === "string" ? block.description : undefined,
|
|
16
|
-
input: block.input && typeof block.input === "object" && !Array.isArray(block.input)
|
|
17
|
-
? block.input
|
|
18
|
-
: {},
|
|
19
|
-
};
|
|
20
|
-
case "tool_result":
|
|
21
|
-
return {
|
|
22
|
-
type: "tool_result",
|
|
23
|
-
tool_use_id: typeof block.tool_use_id === "string" ? block.tool_use_id : "",
|
|
24
|
-
content: typeof block.content === "string"
|
|
25
|
-
? block.content
|
|
26
|
-
: Array.isArray(block.content)
|
|
27
|
-
? block.content
|
|
28
|
-
: "",
|
|
29
|
-
is_error: block.is_error === true,
|
|
30
|
-
};
|
|
31
|
-
default:
|
|
32
|
-
return { type: "text", text: JSON.stringify(block) };
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
export function startClaudeStructuredRunner(options) {
|
|
37
|
-
const state = {
|
|
38
|
-
stdoutBuffer: "",
|
|
39
|
-
assistantBlocks: [],
|
|
40
|
-
usage: undefined,
|
|
41
|
-
sessionId: null,
|
|
42
|
-
};
|
|
43
|
-
const child = spawn(options.command, [], {
|
|
44
|
-
cwd: options.cwd,
|
|
45
|
-
env: options.env,
|
|
46
|
-
shell: true,
|
|
47
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
48
|
-
});
|
|
49
|
-
child.stdout?.on("data", (chunk) => {
|
|
50
|
-
state.stdoutBuffer += chunk.toString();
|
|
51
|
-
const lines = state.stdoutBuffer.split("\n");
|
|
52
|
-
state.stdoutBuffer = lines.pop() || "";
|
|
53
|
-
for (const line of lines) {
|
|
54
|
-
const trimmed = line.trim();
|
|
55
|
-
if (!trimmed) {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
try {
|
|
59
|
-
const event = JSON.parse(trimmed);
|
|
60
|
-
const nextState = updateClaudeStreamState({
|
|
61
|
-
blocks: state.assistantBlocks,
|
|
62
|
-
usage: state.usage,
|
|
63
|
-
sessionId: state.sessionId,
|
|
64
|
-
}, event);
|
|
65
|
-
state.assistantBlocks = nextState.blocks.map((block) => ({ ...block }));
|
|
66
|
-
state.usage = nextState.usage;
|
|
67
|
-
if (nextState.sessionId && nextState.sessionId !== state.sessionId) {
|
|
68
|
-
state.sessionId = nextState.sessionId;
|
|
69
|
-
options.callbacks.onSessionId(nextState.sessionId);
|
|
70
|
-
}
|
|
71
|
-
options.callbacks.onBlocks(state.assistantBlocks, state.usage);
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
options.callbacks.onOutput(trimmed + "\n");
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
child.stderr?.on("data", (chunk) => {
|
|
79
|
-
options.callbacks.onOutput(chunk.toString());
|
|
80
|
-
});
|
|
81
|
-
child.on("close", (code) => {
|
|
82
|
-
options.callbacks.onClose(code, {
|
|
83
|
-
stdoutBuffer: state.stdoutBuffer,
|
|
84
|
-
assistantBlocks: [...state.assistantBlocks],
|
|
85
|
-
usage: state.usage,
|
|
86
|
-
sessionId: state.sessionId,
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
child.on("error", (error) => {
|
|
90
|
-
options.callbacks.onError(error);
|
|
91
|
-
});
|
|
92
|
-
return {
|
|
93
|
-
child,
|
|
94
|
-
getState: () => ({
|
|
95
|
-
stdoutBuffer: state.stdoutBuffer,
|
|
96
|
-
assistantBlocks: [...state.assistantBlocks],
|
|
97
|
-
usage: state.usage,
|
|
98
|
-
sessionId: state.sessionId,
|
|
99
|
-
}),
|
|
100
|
-
kill: () => {
|
|
101
|
-
if (!child.killed) {
|
|
102
|
-
child.kill();
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
}
|
package/dist/message-parser.d.ts
DELETED