claude-code-rust 0.9.0 → 0.10.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/README.md +9 -3
- package/agent-sdk/dist/bridge/events.js +116 -8
- package/agent-sdk/dist/bridge/logger.js +245 -0
- package/agent-sdk/dist/bridge/mcp.js +81 -5
- package/agent-sdk/dist/bridge/message_handlers.js +87 -48
- package/agent-sdk/dist/bridge/session_lifecycle.js +385 -51
- package/agent-sdk/dist/bridge/shared.js +0 -7
- package/agent-sdk/dist/bridge/tool_calls.js +174 -59
- package/agent-sdk/dist/bridge/user_interaction.js +34 -23
- package/agent-sdk/dist/bridge.js +203 -21
- package/package.json +1 -1
package/agent-sdk/dist/bridge.js
CHANGED
|
@@ -6,12 +6,13 @@ import { pathToFileURL } from "node:url";
|
|
|
6
6
|
import { getSessionMessages, listSessions, renameSession, } from "@anthropic-ai/claude-agent-sdk";
|
|
7
7
|
import { parseCommandEnvelope, toPermissionMode } from "./bridge/commands.js";
|
|
8
8
|
import { writeEvent, failConnection, slashError, emitSessionUpdate, emitSessionsList, currentSessionListOptions, setSessionListingDir, } from "./bridge/events.js";
|
|
9
|
-
import {
|
|
9
|
+
import { contentFromPrompt } from "./bridge/message_handlers.js";
|
|
10
10
|
import { sessions, sessionById, createSession, closeAllSessions, handleElicitationResponse, handlePermissionResponse, handleQuestionResponse, } from "./bridge/session_lifecycle.js";
|
|
11
11
|
import { mapSessionMessagesToUpdates } from "./bridge/history.js";
|
|
12
12
|
import { MCP_STALE_STATUS_REVALIDATION_COOLDOWN_MS, handleMcpAuthenticateCommand, handleMcpClearAuthCommand, handleMcpOauthCallbackUrlCommand, handleMcpReconnectCommand, handleMcpSetServersCommand, handleMcpStatusCommand, handleMcpToggleCommand, staleMcpAuthCandidates, } from "./bridge/mcp.js";
|
|
13
|
+
import { bridgeLogger, LOG_TARGETS, logBridgeCommandReceived } from "./bridge/logger.js";
|
|
13
14
|
// Re-exports: all symbols that tests and external consumers import from bridge.js.
|
|
14
|
-
export { AsyncQueue
|
|
15
|
+
export { AsyncQueue } from "./bridge/shared.js";
|
|
15
16
|
export { asRecordOrNull } from "./bridge/shared.js";
|
|
16
17
|
export { CACHE_SPLIT_POLICY, previewKilobyteLabel } from "./bridge/cache_policy.js";
|
|
17
18
|
export { buildToolResultFields, createToolCall, normalizeToolKind, normalizeToolResultText, unwrapToolUseResult, } from "./bridge/tooling.js";
|
|
@@ -67,14 +68,34 @@ export function agentSdkVersionCompatibilityError() {
|
|
|
67
68
|
`found ${installed}.`);
|
|
68
69
|
}
|
|
69
70
|
async function handleCommand(command, requestId) {
|
|
71
|
+
logBridgeCommandReceived(command, requestId);
|
|
70
72
|
const sdkVersionError = agentSdkVersionCompatibilityError();
|
|
71
73
|
if (sdkVersionError && command.command !== "initialize" && command.command !== "shutdown") {
|
|
74
|
+
bridgeLogger.error({
|
|
75
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
76
|
+
eventName: "bridge_command_rejected",
|
|
77
|
+
message: "bridge command rejected due to unsupported SDK version",
|
|
78
|
+
outcome: "failure",
|
|
79
|
+
...(requestId ? { requestId } : {}),
|
|
80
|
+
fields: {
|
|
81
|
+
bridge_command: command.command,
|
|
82
|
+
error_message: sdkVersionError,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
72
85
|
failConnection(sdkVersionError, requestId);
|
|
73
86
|
return;
|
|
74
87
|
}
|
|
75
88
|
switch (command.command) {
|
|
76
89
|
case "initialize":
|
|
77
90
|
if (sdkVersionError) {
|
|
91
|
+
bridgeLogger.error({
|
|
92
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
93
|
+
eventName: "bridge_initialize_failed",
|
|
94
|
+
message: "bridge initialization failed due to unsupported SDK version",
|
|
95
|
+
outcome: "failure",
|
|
96
|
+
...(requestId ? { requestId } : {}),
|
|
97
|
+
fields: { error_message: sdkVersionError },
|
|
98
|
+
});
|
|
78
99
|
failConnection(sdkVersionError, requestId);
|
|
79
100
|
return;
|
|
80
101
|
}
|
|
@@ -92,7 +113,7 @@ async function handleCommand(command, requestId) {
|
|
|
92
113
|
},
|
|
93
114
|
],
|
|
94
115
|
capabilities: {
|
|
95
|
-
prompt_image:
|
|
116
|
+
prompt_image: true,
|
|
96
117
|
prompt_embedded_context: true,
|
|
97
118
|
supports_session_listing: true,
|
|
98
119
|
supports_resume_session: true,
|
|
@@ -102,6 +123,17 @@ async function handleCommand(command, requestId) {
|
|
|
102
123
|
await emitSessionsList(requestId);
|
|
103
124
|
return;
|
|
104
125
|
case "create_session":
|
|
126
|
+
bridgeLogger.info({
|
|
127
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
128
|
+
eventName: "session_create_requested",
|
|
129
|
+
message: "session creation requested",
|
|
130
|
+
outcome: "start",
|
|
131
|
+
...(requestId ? { requestId } : {}),
|
|
132
|
+
fields: {
|
|
133
|
+
cwd: command.cwd,
|
|
134
|
+
resume_requested: command.resume !== undefined,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
105
137
|
setSessionListingDir(command.cwd);
|
|
106
138
|
await createSession({
|
|
107
139
|
cwd: command.cwd,
|
|
@@ -112,10 +144,27 @@ async function handleCommand(command, requestId) {
|
|
|
112
144
|
});
|
|
113
145
|
return;
|
|
114
146
|
case "resume_session": {
|
|
147
|
+
bridgeLogger.info({
|
|
148
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
149
|
+
eventName: "session_resume_requested",
|
|
150
|
+
message: "session resume requested",
|
|
151
|
+
outcome: "start",
|
|
152
|
+
...(requestId ? { requestId } : {}),
|
|
153
|
+
sessionId: command.session_id,
|
|
154
|
+
});
|
|
115
155
|
try {
|
|
116
156
|
const sdkSessions = await listSessions(currentSessionListOptions());
|
|
117
157
|
const matched = sdkSessions.find((entry) => entry.sessionId === command.session_id);
|
|
118
158
|
if (!matched) {
|
|
159
|
+
bridgeLogger.warn({
|
|
160
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
161
|
+
eventName: "session_resume_lookup_failed",
|
|
162
|
+
message: "session resume requested for an unknown session",
|
|
163
|
+
outcome: "failure",
|
|
164
|
+
...(requestId ? { requestId } : {}),
|
|
165
|
+
sessionId: command.session_id,
|
|
166
|
+
fields: { reason: "unknown_session" },
|
|
167
|
+
});
|
|
119
168
|
slashError(command.session_id, `unknown session: ${command.session_id}`, requestId);
|
|
120
169
|
return;
|
|
121
170
|
}
|
|
@@ -124,6 +173,18 @@ async function handleCommand(command, requestId) {
|
|
|
124
173
|
const resumeUpdates = mapSessionMessagesToUpdates(historyMessages);
|
|
125
174
|
const staleSessions = Array.from(sessions.values());
|
|
126
175
|
const hadActiveSession = staleSessions.length > 0;
|
|
176
|
+
bridgeLogger.info({
|
|
177
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
178
|
+
eventName: "session_resume_history_loaded",
|
|
179
|
+
message: "session resume history loaded",
|
|
180
|
+
outcome: "success",
|
|
181
|
+
...(requestId ? { requestId } : {}),
|
|
182
|
+
sessionId: command.session_id,
|
|
183
|
+
fields: {
|
|
184
|
+
history_update_count: resumeUpdates.length,
|
|
185
|
+
stale_session_count: staleSessions.length,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
127
188
|
await createSession({
|
|
128
189
|
cwd: matched.cwd ?? process.cwd(),
|
|
129
190
|
resume: command.session_id,
|
|
@@ -136,12 +197,29 @@ async function handleCommand(command, requestId) {
|
|
|
136
197
|
}
|
|
137
198
|
catch (error) {
|
|
138
199
|
const message = error instanceof Error ? error.message : String(error);
|
|
200
|
+
bridgeLogger.error({
|
|
201
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
202
|
+
eventName: "session_resume_failed",
|
|
203
|
+
message: "session resume failed",
|
|
204
|
+
outcome: "failure",
|
|
205
|
+
...(requestId ? { requestId } : {}),
|
|
206
|
+
sessionId: command.session_id,
|
|
207
|
+
fields: { error_message: message },
|
|
208
|
+
});
|
|
139
209
|
slashError(command.session_id, `failed to resume session: ${message}`, requestId);
|
|
140
210
|
}
|
|
141
211
|
return;
|
|
142
212
|
}
|
|
143
213
|
case "new_session":
|
|
144
|
-
|
|
214
|
+
bridgeLogger.info({
|
|
215
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
216
|
+
eventName: "session_new_requested",
|
|
217
|
+
message: "replacement session requested",
|
|
218
|
+
outcome: "start",
|
|
219
|
+
...(requestId ? { requestId } : {}),
|
|
220
|
+
fields: { cwd: command.cwd },
|
|
221
|
+
});
|
|
222
|
+
await closeAllSessions({ reason: "new_session_requested", requestId });
|
|
145
223
|
setSessionListingDir(command.cwd);
|
|
146
224
|
await createSession({
|
|
147
225
|
cwd: command.cwd,
|
|
@@ -156,8 +234,8 @@ async function handleCommand(command, requestId) {
|
|
|
156
234
|
slashError(command.session_id, `unknown session: ${command.session_id}`, requestId);
|
|
157
235
|
return;
|
|
158
236
|
}
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
237
|
+
const content = contentFromPrompt(command);
|
|
238
|
+
if (content.length === 0) {
|
|
161
239
|
return;
|
|
162
240
|
}
|
|
163
241
|
session.input.enqueue({
|
|
@@ -166,7 +244,7 @@ async function handleCommand(command, requestId) {
|
|
|
166
244
|
parent_tool_use_id: null,
|
|
167
245
|
message: {
|
|
168
246
|
role: "user",
|
|
169
|
-
content
|
|
247
|
+
content,
|
|
170
248
|
},
|
|
171
249
|
});
|
|
172
250
|
return;
|
|
@@ -254,18 +332,48 @@ async function handleCommand(command, requestId) {
|
|
|
254
332
|
slashError(command.session_id, `unknown session: ${command.session_id}`, requestId);
|
|
255
333
|
return;
|
|
256
334
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
335
|
+
try {
|
|
336
|
+
const account = await session.query.accountInfo();
|
|
337
|
+
bridgeLogger.info({
|
|
338
|
+
target: LOG_TARGETS.APP_AUTH,
|
|
339
|
+
eventName: "status_snapshot_emitted",
|
|
340
|
+
message: "status snapshot emitted",
|
|
341
|
+
outcome: "success",
|
|
342
|
+
...(requestId ? { requestId } : {}),
|
|
343
|
+
sessionId: session.sessionId,
|
|
344
|
+
fields: {
|
|
345
|
+
has_email: typeof account.email === "string" && account.email.trim().length > 0,
|
|
346
|
+
has_organization: account.organization !== undefined,
|
|
347
|
+
subscription_type: account.subscriptionType,
|
|
348
|
+
token_source: account.tokenSource,
|
|
349
|
+
api_key_source: account.apiKeySource,
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
writeEvent({
|
|
353
|
+
event: "status_snapshot",
|
|
354
|
+
session_id: session.sessionId,
|
|
355
|
+
account: {
|
|
356
|
+
email: account.email,
|
|
357
|
+
organization: account.organization,
|
|
358
|
+
subscription_type: account.subscriptionType,
|
|
359
|
+
token_source: account.tokenSource,
|
|
360
|
+
api_key_source: account.apiKeySource,
|
|
361
|
+
},
|
|
362
|
+
}, requestId);
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
366
|
+
bridgeLogger.warn({
|
|
367
|
+
target: LOG_TARGETS.APP_AUTH,
|
|
368
|
+
eventName: "status_snapshot_failed",
|
|
369
|
+
message: "failed to build status snapshot",
|
|
370
|
+
outcome: "failure",
|
|
371
|
+
...(requestId ? { requestId } : {}),
|
|
372
|
+
sessionId: session.sessionId,
|
|
373
|
+
fields: { error_message: message },
|
|
374
|
+
});
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
269
377
|
return;
|
|
270
378
|
}
|
|
271
379
|
case "mcp_status": {
|
|
@@ -341,13 +449,45 @@ async function handleCommand(command, requestId) {
|
|
|
341
449
|
handleElicitationResponse(command);
|
|
342
450
|
return;
|
|
343
451
|
case "shutdown":
|
|
344
|
-
|
|
452
|
+
bridgeLogger.info({
|
|
453
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
454
|
+
eventName: "bridge_shutdown_requested",
|
|
455
|
+
message: "bridge shutdown requested",
|
|
456
|
+
outcome: "start",
|
|
457
|
+
...(requestId ? { requestId } : {}),
|
|
458
|
+
});
|
|
459
|
+
await closeAllSessions({ reason: "bridge_shutdown_requested", requestId });
|
|
460
|
+
bridgeLogger.info({
|
|
461
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
462
|
+
eventName: "bridge_shutdown_completed",
|
|
463
|
+
message: "bridge shutdown completed",
|
|
464
|
+
outcome: "success",
|
|
465
|
+
...(requestId ? { requestId } : {}),
|
|
466
|
+
});
|
|
345
467
|
process.exit(0);
|
|
346
468
|
default:
|
|
469
|
+
bridgeLogger.error({
|
|
470
|
+
target: LOG_TARGETS.BRIDGE_PROTOCOL,
|
|
471
|
+
eventName: "bridge_command_rejected",
|
|
472
|
+
message: "received unsupported bridge command",
|
|
473
|
+
outcome: "failure",
|
|
474
|
+
...(requestId ? { requestId } : {}),
|
|
475
|
+
fields: {
|
|
476
|
+
bridge_command: command.command ?? "unknown",
|
|
477
|
+
reason: "unsupported_command",
|
|
478
|
+
},
|
|
479
|
+
});
|
|
347
480
|
failConnection(`unhandled command: ${command.command ?? "unknown"}`, requestId);
|
|
348
481
|
}
|
|
349
482
|
}
|
|
350
483
|
function main() {
|
|
484
|
+
bridgeLogger.info({
|
|
485
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
486
|
+
eventName: "bridge_process_started",
|
|
487
|
+
message: "bridge process started",
|
|
488
|
+
outcome: "start",
|
|
489
|
+
fields: { pid: process.pid },
|
|
490
|
+
});
|
|
351
491
|
const rl = readline.createInterface({
|
|
352
492
|
input: process.stdin,
|
|
353
493
|
crlfDelay: Number.POSITIVE_INFINITY,
|
|
@@ -363,6 +503,18 @@ function main() {
|
|
|
363
503
|
}
|
|
364
504
|
catch (error) {
|
|
365
505
|
const message = error instanceof Error ? error.message : String(error);
|
|
506
|
+
bridgeLogger.error({
|
|
507
|
+
target: LOG_TARGETS.BRIDGE_PROTOCOL,
|
|
508
|
+
eventName: "bridge_command_decode_failed",
|
|
509
|
+
message: "failed to decode bridge command envelope",
|
|
510
|
+
outcome: "failure",
|
|
511
|
+
sizeBytes: Buffer.byteLength(line),
|
|
512
|
+
fields: {
|
|
513
|
+
preview: line.slice(0, 240),
|
|
514
|
+
preview_chars: Math.min(line.length, 240),
|
|
515
|
+
error_message: message,
|
|
516
|
+
},
|
|
517
|
+
});
|
|
366
518
|
failConnection(`invalid command envelope: ${message}`);
|
|
367
519
|
return;
|
|
368
520
|
}
|
|
@@ -371,12 +523,42 @@ function main() {
|
|
|
371
523
|
}
|
|
372
524
|
catch (error) {
|
|
373
525
|
const message = error instanceof Error ? error.message : String(error);
|
|
526
|
+
bridgeLogger.error({
|
|
527
|
+
target: LOG_TARGETS.BRIDGE_PROTOCOL,
|
|
528
|
+
eventName: "bridge_command_failed",
|
|
529
|
+
message: "bridge command handler failed",
|
|
530
|
+
outcome: "failure",
|
|
531
|
+
...(parsed.requestId ? { requestId: parsed.requestId } : {}),
|
|
532
|
+
...(parsed.command.command === "create_session" || parsed.command.command === "new_session"
|
|
533
|
+
? {}
|
|
534
|
+
: "session_id" in parsed.command
|
|
535
|
+
? { sessionId: parsed.command.session_id }
|
|
536
|
+
: {}),
|
|
537
|
+
fields: {
|
|
538
|
+
bridge_command: parsed.command.command,
|
|
539
|
+
error_message: message,
|
|
540
|
+
},
|
|
541
|
+
});
|
|
374
542
|
failConnection(`bridge command failed (${parsed.command.command}): ${message}`, parsed.requestId);
|
|
375
543
|
}
|
|
376
544
|
})();
|
|
377
545
|
});
|
|
378
546
|
rl.on("close", () => {
|
|
379
|
-
|
|
547
|
+
bridgeLogger.info({
|
|
548
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
549
|
+
eventName: "bridge_input_closed",
|
|
550
|
+
message: "bridge stdin closed",
|
|
551
|
+
outcome: "success",
|
|
552
|
+
});
|
|
553
|
+
void closeAllSessions({ reason: "bridge_stdin_closed" }).finally(() => {
|
|
554
|
+
bridgeLogger.info({
|
|
555
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
556
|
+
eventName: "bridge_shutdown_completed",
|
|
557
|
+
message: "bridge shutdown completed after stdin close",
|
|
558
|
+
outcome: "success",
|
|
559
|
+
});
|
|
560
|
+
process.exit(0);
|
|
561
|
+
});
|
|
380
562
|
});
|
|
381
563
|
}
|
|
382
564
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|