@posthog/agent 2.3.727 → 2.3.736
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/adapters/claude/conversion/tool-use-to-acp.d.ts +2 -10
- package/dist/adapters/claude/conversion/tool-use-to-acp.js +24 -10
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/adapters/claude/permissions/permission-options.js +6 -4
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
- package/dist/adapters/claude/session/jsonl-hydration.js +1 -0
- package/dist/adapters/claude/session/jsonl-hydration.js.map +1 -1
- package/dist/adapters/claude/session/models.js +20 -1
- package/dist/adapters/claude/session/models.js.map +1 -1
- package/dist/adapters/claude/tools.js +4 -2
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/adapters/reasoning-effort.js +3 -1
- package/dist/adapters/reasoning-effort.js.map +1 -1
- package/dist/agent.js +544 -74
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +4 -4
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +544 -74
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +544 -74
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +4 -4
- package/src/adapters/claude/UPSTREAM.md +81 -3
- package/src/adapters/claude/claude-agent.slash-command.test.ts +22 -2
- package/src/adapters/claude/claude-agent.ts +232 -19
- package/src/adapters/claude/conversion/sdk-to-acp.ts +182 -16
- package/src/adapters/claude/conversion/task-state.test.ts +338 -0
- package/src/adapters/claude/conversion/task-state.ts +178 -0
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +29 -19
- package/src/adapters/claude/hooks.test.ts +162 -0
- package/src/adapters/claude/hooks.ts +44 -3
- package/src/adapters/claude/permissions/permission-options.ts +7 -2
- package/src/adapters/claude/session/commands.ts +1 -0
- package/src/adapters/claude/session/mcp-config.ts +23 -7
- package/src/adapters/claude/session/model-config.test.ts +60 -0
- package/src/adapters/claude/session/model-config.ts +56 -0
- package/src/adapters/claude/session/models.test.ts +119 -0
- package/src/adapters/claude/session/models.ts +31 -0
- package/src/adapters/claude/session/options.test.ts +1 -0
- package/src/adapters/claude/session/options.ts +29 -1
- package/src/adapters/claude/session/settings.test.ts +102 -1
- package/src/adapters/claude/session/settings.ts +33 -6
- package/src/adapters/claude/tools.ts +4 -2
- package/src/adapters/claude/types.ts +15 -0
- package/src/adapters/codex/codex-agent.ts +2 -2
- package/src/server/agent-server.test.ts +173 -0
- package/src/test/mocks/claude-sdk.ts +4 -0
- package/src/test/native-binary.test.ts +27 -0
- package/dist/claude-cli/cli.js +0 -18412
- package/dist/claude-cli/vendor/audio-capture/arm64-darwin/audio-capture.node +0 -0
- package/dist/claude-cli/vendor/audio-capture/arm64-linux/audio-capture.node +0 -0
- package/dist/claude-cli/vendor/audio-capture/arm64-win32/audio-capture.node +0 -0
- package/dist/claude-cli/vendor/audio-capture/x64-darwin/audio-capture.node +0 -0
- package/dist/claude-cli/vendor/audio-capture/x64-linux/audio-capture.node +0 -0
- package/dist/claude-cli/vendor/audio-capture/x64-win32/audio-capture.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/COPYING +0 -3
- package/dist/claude-cli/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-linux/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-win32/rg.exe +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-darwin/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-linux/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-win32/rg.exe +0 -0
- package/dist/claude-cli/yoga.wasm +0 -0
package/dist/agent.js
CHANGED
|
@@ -4674,7 +4674,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
4674
4674
|
// package.json
|
|
4675
4675
|
var package_default = {
|
|
4676
4676
|
name: "@posthog/agent",
|
|
4677
|
-
version: "2.3.
|
|
4677
|
+
version: "2.3.736",
|
|
4678
4678
|
repository: "https://github.com/PostHog/code",
|
|
4679
4679
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
4680
4680
|
exports: {
|
|
@@ -4794,9 +4794,9 @@ var package_default = {
|
|
|
4794
4794
|
vitest: "^2.1.8"
|
|
4795
4795
|
},
|
|
4796
4796
|
dependencies: {
|
|
4797
|
-
"@agentclientprotocol/sdk": "0.
|
|
4798
|
-
"@anthropic-ai/claude-agent-sdk": "0.
|
|
4799
|
-
"@anthropic-ai/sdk": "0.
|
|
4797
|
+
"@agentclientprotocol/sdk": "0.22.1",
|
|
4798
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.154",
|
|
4799
|
+
"@anthropic-ai/sdk": "0.100.0",
|
|
4800
4800
|
"@hono/node-server": "^1.19.9",
|
|
4801
4801
|
"@opentelemetry/api-logs": "^0.208.0",
|
|
4802
4802
|
"@opentelemetry/exporter-logs-otlp-http": "^0.208.0",
|
|
@@ -10183,6 +10183,30 @@ var registerHookCallback = (toolUseID, {
|
|
|
10183
10183
|
onPostToolUseHook
|
|
10184
10184
|
};
|
|
10185
10185
|
};
|
|
10186
|
+
var createTaskHook = (taskState, onChange) => async (input) => {
|
|
10187
|
+
const taskId = "task_id" in input && typeof input.task_id === "string" ? input.task_id : void 0;
|
|
10188
|
+
if (!taskId) return { continue: true };
|
|
10189
|
+
let mutated = false;
|
|
10190
|
+
if (input.hook_event_name === "TaskCreated") {
|
|
10191
|
+
if (!input.task_subject) return { continue: true };
|
|
10192
|
+
if (taskState.has(taskId)) return { continue: true };
|
|
10193
|
+
taskState.set(taskId, {
|
|
10194
|
+
subject: input.task_subject,
|
|
10195
|
+
status: "pending",
|
|
10196
|
+
description: input.task_description
|
|
10197
|
+
});
|
|
10198
|
+
mutated = true;
|
|
10199
|
+
} else if (input.hook_event_name === "TaskCompleted") {
|
|
10200
|
+
const existing = taskState.get(taskId);
|
|
10201
|
+
if (!existing || existing.status === "completed") {
|
|
10202
|
+
return { continue: true };
|
|
10203
|
+
}
|
|
10204
|
+
taskState.set(taskId, { ...existing, status: "completed" });
|
|
10205
|
+
mutated = true;
|
|
10206
|
+
}
|
|
10207
|
+
if (mutated && onChange) await onChange();
|
|
10208
|
+
return { continue: true };
|
|
10209
|
+
};
|
|
10186
10210
|
var createPostToolUseHook = ({ onModeChange }) => async (input, toolUseID) => {
|
|
10187
10211
|
if (input.hook_event_name === "PostToolUse") {
|
|
10188
10212
|
const toolName = input.tool_name;
|
|
@@ -10197,10 +10221,8 @@ var createPostToolUseHook = ({ onModeChange }) => async (input, toolUseID) => {
|
|
|
10197
10221
|
input.tool_input,
|
|
10198
10222
|
input.tool_response
|
|
10199
10223
|
);
|
|
10200
|
-
delete toolUseCallbacks[toolUseID];
|
|
10201
|
-
} else {
|
|
10202
|
-
delete toolUseCallbacks[toolUseID];
|
|
10203
10224
|
}
|
|
10225
|
+
delete toolUseCallbacks[toolUseID];
|
|
10204
10226
|
}
|
|
10205
10227
|
}
|
|
10206
10228
|
return { continue: true };
|
|
@@ -10347,6 +10369,104 @@ var createPreToolUseHook = (settingsManager, logger) => async (input, _toolUseID
|
|
|
10347
10369
|
}
|
|
10348
10370
|
};
|
|
10349
10371
|
|
|
10372
|
+
// src/adapters/claude/conversion/task-state.ts
|
|
10373
|
+
function parseTaskCreateOutput(content) {
|
|
10374
|
+
const tryParse = (text2) => {
|
|
10375
|
+
try {
|
|
10376
|
+
const parsed = JSON.parse(text2);
|
|
10377
|
+
if (parsed && typeof parsed === "object" && parsed.task && typeof parsed.task.id === "string") {
|
|
10378
|
+
return parsed;
|
|
10379
|
+
}
|
|
10380
|
+
} catch {
|
|
10381
|
+
}
|
|
10382
|
+
return void 0;
|
|
10383
|
+
};
|
|
10384
|
+
if (typeof content === "string") {
|
|
10385
|
+
return tryParse(content);
|
|
10386
|
+
}
|
|
10387
|
+
if (Array.isArray(content)) {
|
|
10388
|
+
for (const block of content) {
|
|
10389
|
+
if (block && typeof block === "object" && "type" in block && block.type === "text") {
|
|
10390
|
+
const text2 = block.text;
|
|
10391
|
+
if (typeof text2 === "string") {
|
|
10392
|
+
const parsed = tryParse(text2);
|
|
10393
|
+
if (parsed) return parsed;
|
|
10394
|
+
}
|
|
10395
|
+
}
|
|
10396
|
+
}
|
|
10397
|
+
}
|
|
10398
|
+
return void 0;
|
|
10399
|
+
}
|
|
10400
|
+
function applyTaskCreate(state, input, output) {
|
|
10401
|
+
const taskId = output?.task?.id;
|
|
10402
|
+
if (!taskId || !input) return;
|
|
10403
|
+
state.set(taskId, {
|
|
10404
|
+
subject: input.subject,
|
|
10405
|
+
status: "pending",
|
|
10406
|
+
activeForm: input.activeForm,
|
|
10407
|
+
description: input.description
|
|
10408
|
+
});
|
|
10409
|
+
}
|
|
10410
|
+
function applyTaskUpdate(state, input) {
|
|
10411
|
+
if (!input?.taskId) return;
|
|
10412
|
+
if (input.status === "deleted") {
|
|
10413
|
+
state.delete(input.taskId);
|
|
10414
|
+
return;
|
|
10415
|
+
}
|
|
10416
|
+
const existing = state.get(input.taskId);
|
|
10417
|
+
const subject = input.subject ?? existing?.subject;
|
|
10418
|
+
if (!subject) return;
|
|
10419
|
+
state.set(input.taskId, {
|
|
10420
|
+
subject,
|
|
10421
|
+
status: input.status ?? existing?.status ?? "pending",
|
|
10422
|
+
activeForm: input.activeForm ?? existing?.activeForm,
|
|
10423
|
+
description: input.description ?? existing?.description
|
|
10424
|
+
});
|
|
10425
|
+
}
|
|
10426
|
+
function taskStateToPlanEntries(state) {
|
|
10427
|
+
return Array.from(state.values()).map((task) => ({
|
|
10428
|
+
content: task.subject,
|
|
10429
|
+
status: task.status,
|
|
10430
|
+
priority: "medium"
|
|
10431
|
+
}));
|
|
10432
|
+
}
|
|
10433
|
+
function isToolUseBlock(block) {
|
|
10434
|
+
return !!block && typeof block === "object" && block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string";
|
|
10435
|
+
}
|
|
10436
|
+
function isToolResultBlock(block) {
|
|
10437
|
+
return !!block && typeof block === "object" && block.type === "tool_result" && typeof block.tool_use_id === "string";
|
|
10438
|
+
}
|
|
10439
|
+
function rehydrateTaskState(messages, state) {
|
|
10440
|
+
const pendingInputs = /* @__PURE__ */ new Map();
|
|
10441
|
+
for (const msg of messages) {
|
|
10442
|
+
const content = msg.message?.content;
|
|
10443
|
+
if (!Array.isArray(content)) continue;
|
|
10444
|
+
if (msg.type === "assistant") {
|
|
10445
|
+
for (const block of content) {
|
|
10446
|
+
if (isToolUseBlock(block) && (block.name === "TaskCreate" || block.name === "TaskUpdate")) {
|
|
10447
|
+
pendingInputs.set(block.id, { name: block.name, input: block.input });
|
|
10448
|
+
}
|
|
10449
|
+
}
|
|
10450
|
+
} else if (msg.type === "user") {
|
|
10451
|
+
for (const block of content) {
|
|
10452
|
+
if (!isToolResultBlock(block) || block.is_error) continue;
|
|
10453
|
+
const cached = pendingInputs.get(block.tool_use_id);
|
|
10454
|
+
if (!cached) continue;
|
|
10455
|
+
if (cached.name === "TaskCreate") {
|
|
10456
|
+
applyTaskCreate(
|
|
10457
|
+
state,
|
|
10458
|
+
cached.input,
|
|
10459
|
+
parseTaskCreateOutput(block.content)
|
|
10460
|
+
);
|
|
10461
|
+
} else if (cached.name === "TaskUpdate") {
|
|
10462
|
+
applyTaskUpdate(state, cached.input);
|
|
10463
|
+
}
|
|
10464
|
+
pendingInputs.delete(block.tool_use_id);
|
|
10465
|
+
}
|
|
10466
|
+
}
|
|
10467
|
+
}
|
|
10468
|
+
}
|
|
10469
|
+
|
|
10350
10470
|
// src/adapters/claude/conversion/tool-use-to-acp.ts
|
|
10351
10471
|
import fs4 from "fs";
|
|
10352
10472
|
import path7 from "path";
|
|
@@ -10698,9 +10818,31 @@ function toolInfoFromToolUse(toolUse, options) {
|
|
|
10698
10818
|
content: []
|
|
10699
10819
|
};
|
|
10700
10820
|
}
|
|
10701
|
-
case "
|
|
10821
|
+
case "TaskCreate": {
|
|
10822
|
+
const subject = typeof input?.subject === "string" ? input.subject : void 0;
|
|
10823
|
+
return {
|
|
10824
|
+
title: subject ? `Create task: ${subject}` : "Create task",
|
|
10825
|
+
kind: "think",
|
|
10826
|
+
content: []
|
|
10827
|
+
};
|
|
10828
|
+
}
|
|
10829
|
+
case "TaskUpdate": {
|
|
10830
|
+
const subject = typeof input?.subject === "string" ? input.subject : void 0;
|
|
10702
10831
|
return {
|
|
10703
|
-
title:
|
|
10832
|
+
title: subject ? `Update task: ${subject}` : "Update task",
|
|
10833
|
+
kind: "think",
|
|
10834
|
+
content: []
|
|
10835
|
+
};
|
|
10836
|
+
}
|
|
10837
|
+
case "TaskList":
|
|
10838
|
+
return {
|
|
10839
|
+
title: "List tasks",
|
|
10840
|
+
kind: "think",
|
|
10841
|
+
content: []
|
|
10842
|
+
};
|
|
10843
|
+
case "TaskGet":
|
|
10844
|
+
return {
|
|
10845
|
+
title: "Get task",
|
|
10704
10846
|
kind: "think",
|
|
10705
10847
|
content: []
|
|
10706
10848
|
};
|
|
@@ -10984,13 +11126,6 @@ ${content}
|
|
|
10984
11126
|
}
|
|
10985
11127
|
return {};
|
|
10986
11128
|
}
|
|
10987
|
-
function planEntries(input) {
|
|
10988
|
-
return input.todos.map((input2) => ({
|
|
10989
|
-
content: input2.content,
|
|
10990
|
-
status: input2.status,
|
|
10991
|
-
priority: "medium"
|
|
10992
|
-
}));
|
|
10993
|
-
}
|
|
10994
11129
|
function resolveFileContent(filePath, oldText, cachedFileContent) {
|
|
10995
11130
|
if (cachedFileContent && filePath in cachedFileContent) {
|
|
10996
11131
|
const cached = cachedFileContent[filePath];
|
|
@@ -11076,14 +11211,7 @@ function handleThinkingChunk(chunk, parentToolCallId) {
|
|
|
11076
11211
|
function handleToolUseChunk(chunk, ctx) {
|
|
11077
11212
|
const alreadyCached = chunk.id in ctx.toolUseCache;
|
|
11078
11213
|
ctx.toolUseCache[chunk.id] = chunk;
|
|
11079
|
-
if (chunk.name === "
|
|
11080
|
-
const input = chunk.input;
|
|
11081
|
-
if (Array.isArray(input.todos)) {
|
|
11082
|
-
return {
|
|
11083
|
-
sessionUpdate: "plan",
|
|
11084
|
-
entries: planEntries(chunk.input)
|
|
11085
|
-
};
|
|
11086
|
-
}
|
|
11214
|
+
if (chunk.name === "TaskCreate" || chunk.name === "TaskUpdate" || chunk.name === "TaskList" || chunk.name === "TaskGet") {
|
|
11087
11215
|
return null;
|
|
11088
11216
|
}
|
|
11089
11217
|
if (!alreadyCached && ctx.registerHooks !== false) {
|
|
@@ -11091,7 +11219,7 @@ function handleToolUseChunk(chunk, ctx) {
|
|
|
11091
11219
|
onPostToolUseHook: async (toolUseId, _toolInput, toolResponse) => {
|
|
11092
11220
|
const toolUse = ctx.toolUseCache[toolUseId];
|
|
11093
11221
|
if (toolUse) {
|
|
11094
|
-
const editUpdate = toolUse.name === "Edit" ? toolUpdateFromEditToolResponse(toolResponse) : null;
|
|
11222
|
+
const editUpdate = toolUse.name === "Edit" || toolUse.name === "Write" ? toolUpdateFromEditToolResponse(toolResponse) : null;
|
|
11095
11223
|
await ctx.client.sessionUpdate({
|
|
11096
11224
|
sessionId: ctx.sessionId,
|
|
11097
11225
|
update: {
|
|
@@ -11203,7 +11331,28 @@ function handleToolResultChunk(chunk, ctx) {
|
|
|
11203
11331
|
);
|
|
11204
11332
|
return [];
|
|
11205
11333
|
}
|
|
11206
|
-
if (toolUse.name === "
|
|
11334
|
+
if (toolUse.name === "TaskCreate" || toolUse.name === "TaskUpdate" || toolUse.name === "TaskList" || toolUse.name === "TaskGet") {
|
|
11335
|
+
if (chunk.is_error || !ctx.taskState) return [];
|
|
11336
|
+
if (toolUse.name === "TaskCreate") {
|
|
11337
|
+
applyTaskCreate(
|
|
11338
|
+
ctx.taskState,
|
|
11339
|
+
toolUse.input,
|
|
11340
|
+
parseTaskCreateOutput(chunk.content)
|
|
11341
|
+
);
|
|
11342
|
+
} else if (toolUse.name === "TaskUpdate") {
|
|
11343
|
+
applyTaskUpdate(
|
|
11344
|
+
ctx.taskState,
|
|
11345
|
+
toolUse.input
|
|
11346
|
+
);
|
|
11347
|
+
}
|
|
11348
|
+
if (toolUse.name === "TaskCreate" || toolUse.name === "TaskUpdate") {
|
|
11349
|
+
return [
|
|
11350
|
+
{
|
|
11351
|
+
sessionUpdate: "plan",
|
|
11352
|
+
entries: taskStateToPlanEntries(ctx.taskState)
|
|
11353
|
+
}
|
|
11354
|
+
];
|
|
11355
|
+
}
|
|
11207
11356
|
return [];
|
|
11208
11357
|
}
|
|
11209
11358
|
if (!chunk.is_error) {
|
|
@@ -11300,13 +11449,15 @@ function processContentChunk(chunk, role, ctx) {
|
|
|
11300
11449
|
case "container_upload":
|
|
11301
11450
|
case "compaction":
|
|
11302
11451
|
case "compaction_delta":
|
|
11452
|
+
case "advisor_tool_result":
|
|
11453
|
+
case "mid_conv_system":
|
|
11303
11454
|
return [];
|
|
11304
11455
|
default:
|
|
11305
11456
|
unreachable(chunk, ctx.logger);
|
|
11306
11457
|
return [];
|
|
11307
11458
|
}
|
|
11308
11459
|
}
|
|
11309
|
-
function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd, mcpToolUseResult, enrichedReadCache) {
|
|
11460
|
+
function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd, mcpToolUseResult, enrichedReadCache, taskState) {
|
|
11310
11461
|
if (typeof content === "string") {
|
|
11311
11462
|
const update = {
|
|
11312
11463
|
sessionUpdate: messageUpdateType(role),
|
|
@@ -11332,7 +11483,8 @@ function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentC
|
|
|
11332
11483
|
registerHooks,
|
|
11333
11484
|
supportsTerminalOutput,
|
|
11334
11485
|
cwd,
|
|
11335
|
-
mcpToolUseResult
|
|
11486
|
+
mcpToolUseResult,
|
|
11487
|
+
taskState
|
|
11336
11488
|
};
|
|
11337
11489
|
const output = [];
|
|
11338
11490
|
for (const chunk of content) {
|
|
@@ -11342,7 +11494,7 @@ function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentC
|
|
|
11342
11494
|
}
|
|
11343
11495
|
return output;
|
|
11344
11496
|
}
|
|
11345
|
-
function streamEventToAcpNotifications(message, sessionId, toolUseCache, toolUseStreamCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd, enrichedReadCache) {
|
|
11497
|
+
function streamEventToAcpNotifications(message, sessionId, toolUseCache, toolUseStreamCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd, enrichedReadCache, taskState) {
|
|
11346
11498
|
const event = message.event;
|
|
11347
11499
|
switch (event.type) {
|
|
11348
11500
|
case "content_block_start": {
|
|
@@ -11366,7 +11518,8 @@ function streamEventToAcpNotifications(message, sessionId, toolUseCache, toolUse
|
|
|
11366
11518
|
supportsTerminalOutput,
|
|
11367
11519
|
cwd,
|
|
11368
11520
|
void 0,
|
|
11369
|
-
enrichedReadCache
|
|
11521
|
+
enrichedReadCache,
|
|
11522
|
+
taskState
|
|
11370
11523
|
);
|
|
11371
11524
|
}
|
|
11372
11525
|
case "content_block_delta": {
|
|
@@ -11391,12 +11544,18 @@ function streamEventToAcpNotifications(message, sessionId, toolUseCache, toolUse
|
|
|
11391
11544
|
supportsTerminalOutput,
|
|
11392
11545
|
cwd,
|
|
11393
11546
|
void 0,
|
|
11394
|
-
enrichedReadCache
|
|
11547
|
+
enrichedReadCache,
|
|
11548
|
+
taskState
|
|
11395
11549
|
);
|
|
11396
11550
|
}
|
|
11397
11551
|
case "content_block_stop":
|
|
11398
11552
|
toolUseStreamCache.delete(event.index);
|
|
11399
11553
|
return [];
|
|
11554
|
+
// `ping` is a Messages-API keep-alive event that the SDK's
|
|
11555
|
+
// `BetaRawMessageStreamEvent` union doesn't include even though the
|
|
11556
|
+
// wire format emits it; the `as never` cast lets us no-op it here
|
|
11557
|
+
// instead of falling through to `unreachable`.
|
|
11558
|
+
case "ping":
|
|
11400
11559
|
case "message_start":
|
|
11401
11560
|
case "message_delta":
|
|
11402
11561
|
case "message_stop":
|
|
@@ -11467,6 +11626,38 @@ async function handleSystemMessage(message, context) {
|
|
|
11467
11626
|
});
|
|
11468
11627
|
break;
|
|
11469
11628
|
}
|
|
11629
|
+
case "memory_recall": {
|
|
11630
|
+
const isSynthesis = message.mode === "synthesize";
|
|
11631
|
+
if (!isSynthesis && message.memories.length === 0) break;
|
|
11632
|
+
const locations = isSynthesis ? [] : message.memories.map((m) => ({ path: m.path }));
|
|
11633
|
+
const content = isSynthesis ? message.memories.filter(
|
|
11634
|
+
(m) => typeof m.content === "string"
|
|
11635
|
+
).map((m) => ({
|
|
11636
|
+
type: "content",
|
|
11637
|
+
content: { type: "text", text: m.content }
|
|
11638
|
+
})) : [];
|
|
11639
|
+
const count = message.memories.length;
|
|
11640
|
+
const title = isSynthesis ? "Recalled synthesized memory" : `Recalled ${count} ${count === 1 ? "memory" : "memories"}`;
|
|
11641
|
+
await client.sessionUpdate({
|
|
11642
|
+
sessionId: message.session_id,
|
|
11643
|
+
update: {
|
|
11644
|
+
sessionUpdate: "tool_call",
|
|
11645
|
+
toolCallId: message.uuid,
|
|
11646
|
+
title,
|
|
11647
|
+
kind: "read",
|
|
11648
|
+
status: "completed",
|
|
11649
|
+
...locations.length > 0 && { locations },
|
|
11650
|
+
...content.length > 0 && { content },
|
|
11651
|
+
_meta: {
|
|
11652
|
+
claudeCode: {
|
|
11653
|
+
toolName: "memory_recall",
|
|
11654
|
+
toolResponse: { mode: message.mode }
|
|
11655
|
+
}
|
|
11656
|
+
}
|
|
11657
|
+
}
|
|
11658
|
+
});
|
|
11659
|
+
break;
|
|
11660
|
+
}
|
|
11470
11661
|
default:
|
|
11471
11662
|
break;
|
|
11472
11663
|
}
|
|
@@ -11576,7 +11767,8 @@ async function handleStreamEvent(message, context) {
|
|
|
11576
11767
|
context.registerHooks,
|
|
11577
11768
|
context.supportsTerminalOutput,
|
|
11578
11769
|
context.session.cwd,
|
|
11579
|
-
context.enrichedReadCache
|
|
11770
|
+
context.enrichedReadCache,
|
|
11771
|
+
context.session.taskState
|
|
11580
11772
|
)) {
|
|
11581
11773
|
await client.sessionUpdate(notification);
|
|
11582
11774
|
context.session.notificationHistory.push(notification);
|
|
@@ -11588,6 +11780,17 @@ function hasLocalCommandStdout(content) {
|
|
|
11588
11780
|
function hasLocalCommandStderr(content) {
|
|
11589
11781
|
return typeof content === "string" && content.includes("<local-command-stderr>");
|
|
11590
11782
|
}
|
|
11783
|
+
function isSdkLocalCommandMessage(content) {
|
|
11784
|
+
return typeof content === "string" && content.includes("<command-name>") && (content.includes("<local-command-stdout>") || content.includes("<local-command-stderr>"));
|
|
11785
|
+
}
|
|
11786
|
+
var LOCAL_COMMAND_TAG_PATTERN = /<(command-name|command-message|command-args|local-command-stdout|local-command-stderr)>[\s\S]*?<\/\1>/g;
|
|
11787
|
+
function stripMarkerTags(text2) {
|
|
11788
|
+
return text2.replace(LOCAL_COMMAND_TAG_PATTERN, "");
|
|
11789
|
+
}
|
|
11790
|
+
function stripLocalCommandMetadata(content) {
|
|
11791
|
+
const stripped = stripMarkerTags(content);
|
|
11792
|
+
return stripped.trim() === "" ? null : stripped;
|
|
11793
|
+
}
|
|
11591
11794
|
function isLoginRequiredMessage(message) {
|
|
11592
11795
|
return message.type === "assistant" && message.message.model === "<synthetic>" && Array.isArray(message.message.content) && message.message.content.length === 1 && message.message.content[0].type === "text" && message.message.content[0].text?.includes("Please run /login") === true;
|
|
11593
11796
|
}
|
|
@@ -11596,7 +11799,7 @@ function isPlainTextUserMessage(message) {
|
|
|
11596
11799
|
return message.type === "user" && (typeof content === "string" || Array.isArray(content) && content.length === 1 && content[0].type === "text");
|
|
11597
11800
|
}
|
|
11598
11801
|
function shouldSkipUserAssistantMessage(message) {
|
|
11599
|
-
return
|
|
11802
|
+
return isSdkLocalCommandMessage(message.message.content) || isLoginRequiredMessage(message);
|
|
11600
11803
|
}
|
|
11601
11804
|
function logSpecialMessages(message, logger) {
|
|
11602
11805
|
const content = message.message.content;
|
|
@@ -11617,11 +11820,39 @@ function filterMessageContent(content) {
|
|
|
11617
11820
|
}
|
|
11618
11821
|
async function handleUserAssistantMessage(message, context) {
|
|
11619
11822
|
const { session, sessionId, client, toolUseCache, fileContentCache, logger } = context;
|
|
11823
|
+
if (message.message.role === "system") {
|
|
11824
|
+
return {};
|
|
11825
|
+
}
|
|
11620
11826
|
if (shouldSkipUserAssistantMessage(message)) {
|
|
11621
11827
|
logSpecialMessages(message, logger);
|
|
11622
11828
|
if (isLoginRequiredMessage(message)) {
|
|
11623
11829
|
return { shouldStop: true, error: RequestError.authRequired() };
|
|
11624
11830
|
}
|
|
11831
|
+
const rawContent = message.message.content;
|
|
11832
|
+
if (typeof rawContent === "string") {
|
|
11833
|
+
const stripped = stripLocalCommandMetadata(rawContent);
|
|
11834
|
+
if (stripped !== null) {
|
|
11835
|
+
for (const notification of toAcpNotifications(
|
|
11836
|
+
stripped,
|
|
11837
|
+
message.message.role,
|
|
11838
|
+
sessionId,
|
|
11839
|
+
toolUseCache,
|
|
11840
|
+
fileContentCache,
|
|
11841
|
+
client,
|
|
11842
|
+
logger,
|
|
11843
|
+
void 0,
|
|
11844
|
+
context.registerHooks,
|
|
11845
|
+
context.supportsTerminalOutput,
|
|
11846
|
+
session.cwd,
|
|
11847
|
+
void 0,
|
|
11848
|
+
context.enrichedReadCache,
|
|
11849
|
+
session.taskState
|
|
11850
|
+
)) {
|
|
11851
|
+
await client.sessionUpdate(notification);
|
|
11852
|
+
session.notificationHistory.push(notification);
|
|
11853
|
+
}
|
|
11854
|
+
}
|
|
11855
|
+
}
|
|
11625
11856
|
return {};
|
|
11626
11857
|
}
|
|
11627
11858
|
if (isPlainTextUserMessage(message)) {
|
|
@@ -11644,7 +11875,8 @@ async function handleUserAssistantMessage(message, context) {
|
|
|
11644
11875
|
context.supportsTerminalOutput,
|
|
11645
11876
|
session.cwd,
|
|
11646
11877
|
mcpToolUseResult,
|
|
11647
|
-
context.enrichedReadCache
|
|
11878
|
+
context.enrichedReadCache,
|
|
11879
|
+
session.taskState
|
|
11648
11880
|
)) {
|
|
11649
11881
|
await client.sessionUpdate(notification);
|
|
11650
11882
|
session.notificationHistory.push(notification);
|
|
@@ -11840,8 +12072,10 @@ var WEB_TOOLS = /* @__PURE__ */ new Set(["WebSearch", "WebFetch"]);
|
|
|
11840
12072
|
var AGENT_TOOLS = /* @__PURE__ */ new Set([
|
|
11841
12073
|
"Task",
|
|
11842
12074
|
"Agent",
|
|
11843
|
-
"
|
|
11844
|
-
"
|
|
12075
|
+
"TaskCreate",
|
|
12076
|
+
"TaskUpdate",
|
|
12077
|
+
"TaskGet",
|
|
12078
|
+
"TaskList"
|
|
11845
12079
|
]);
|
|
11846
12080
|
var BASE_ALLOWED_TOOLS = [
|
|
11847
12081
|
...READ_TOOLS,
|
|
@@ -11925,8 +12159,8 @@ function buildPermissionOptions(toolName, toolInput, repoRoot, suggestions) {
|
|
|
11925
12159
|
if (toolName === "Task") {
|
|
11926
12160
|
return permissionOptions("Yes, allow all sub-tasks");
|
|
11927
12161
|
}
|
|
11928
|
-
if (toolName === "
|
|
11929
|
-
return permissionOptions("Yes, allow all
|
|
12162
|
+
if (toolName === "TaskCreate" || toolName === "TaskUpdate" || toolName === "TaskGet" || toolName === "TaskList") {
|
|
12163
|
+
return permissionOptions("Yes, allow all task updates");
|
|
11930
12164
|
}
|
|
11931
12165
|
return permissionOptions("Yes, always allow");
|
|
11932
12166
|
}
|
|
@@ -12478,6 +12712,7 @@ async function canUseTool(context) {
|
|
|
12478
12712
|
|
|
12479
12713
|
// src/adapters/claude/session/commands.ts
|
|
12480
12714
|
var UNSUPPORTED_COMMANDS = [
|
|
12715
|
+
"clear",
|
|
12481
12716
|
"context",
|
|
12482
12717
|
"cost",
|
|
12483
12718
|
"keybindings-help",
|
|
@@ -12532,18 +12767,30 @@ function loadUserClaudeJsonMcpServers(cwd, logger, homeDir = os3.homedir()) {
|
|
|
12532
12767
|
const projectScoped = project?.mcpServers && typeof project.mcpServers === "object" ? project.mcpServers : {};
|
|
12533
12768
|
return { ...topLevel, ...projectScoped };
|
|
12534
12769
|
}
|
|
12535
|
-
function parseMcpServers(params) {
|
|
12770
|
+
function parseMcpServers(params, logger) {
|
|
12536
12771
|
const mcpServers = {};
|
|
12537
12772
|
if (!Array.isArray(params.mcpServers)) {
|
|
12538
12773
|
return mcpServers;
|
|
12539
12774
|
}
|
|
12540
12775
|
for (const server of params.mcpServers) {
|
|
12541
12776
|
if ("type" in server) {
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12777
|
+
if (server.type === "http" || server.type === "sse") {
|
|
12778
|
+
mcpServers[server.name] = {
|
|
12779
|
+
type: server.type,
|
|
12780
|
+
url: server.url,
|
|
12781
|
+
headers: server.headers ? Object.fromEntries(
|
|
12782
|
+
server.headers.map((e) => [
|
|
12783
|
+
e.name,
|
|
12784
|
+
e.value
|
|
12785
|
+
])
|
|
12786
|
+
) : void 0
|
|
12787
|
+
};
|
|
12788
|
+
} else {
|
|
12789
|
+
logger?.warn("parseMcpServers: dropping unsupported MCP server type", {
|
|
12790
|
+
name: server.name,
|
|
12791
|
+
type: server.type
|
|
12792
|
+
});
|
|
12793
|
+
}
|
|
12547
12794
|
} else {
|
|
12548
12795
|
mcpServers[server.name] = {
|
|
12549
12796
|
type: "stdio",
|
|
@@ -12556,12 +12803,43 @@ function parseMcpServers(params) {
|
|
|
12556
12803
|
return mcpServers;
|
|
12557
12804
|
}
|
|
12558
12805
|
|
|
12806
|
+
// src/adapters/claude/session/model-config.ts
|
|
12807
|
+
function applyAvailableModelsAllowlist(modelOptions, allowlist) {
|
|
12808
|
+
const filtered = [];
|
|
12809
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12810
|
+
for (const entry of allowlist) {
|
|
12811
|
+
const trimmed2 = entry.trim();
|
|
12812
|
+
if (!trimmed2 || seen.has(trimmed2)) continue;
|
|
12813
|
+
const match = modelOptions.options.find((o) => o.value === trimmed2);
|
|
12814
|
+
if (match) {
|
|
12815
|
+
filtered.push(match);
|
|
12816
|
+
seen.add(trimmed2);
|
|
12817
|
+
}
|
|
12818
|
+
}
|
|
12819
|
+
if (filtered.length === 0) return modelOptions;
|
|
12820
|
+
const currentModelId = filtered.some(
|
|
12821
|
+
(o) => o.value === modelOptions.currentModelId
|
|
12822
|
+
) ? modelOptions.currentModelId : filtered[0].value;
|
|
12823
|
+
return { currentModelId, options: filtered };
|
|
12824
|
+
}
|
|
12825
|
+
function resolveInitialModelId(modelOptions, preferredModelIds) {
|
|
12826
|
+
const allowedModelIds = new Set(modelOptions.options.map((opt) => opt.value));
|
|
12827
|
+
for (const candidate of preferredModelIds) {
|
|
12828
|
+
const trimmed2 = candidate?.trim();
|
|
12829
|
+
if (trimmed2 && allowedModelIds.has(trimmed2)) {
|
|
12830
|
+
return trimmed2;
|
|
12831
|
+
}
|
|
12832
|
+
}
|
|
12833
|
+
return modelOptions.currentModelId;
|
|
12834
|
+
}
|
|
12835
|
+
|
|
12559
12836
|
// src/adapters/claude/session/models.ts
|
|
12560
12837
|
var DEFAULT_MODEL = "opus";
|
|
12561
12838
|
var GATEWAY_TO_SDK_MODEL = {
|
|
12562
12839
|
"claude-opus-4-5": "opus",
|
|
12563
12840
|
"claude-opus-4-6": "opus",
|
|
12564
12841
|
"claude-opus-4-7": "opus",
|
|
12842
|
+
"claude-opus-4-8": "opus",
|
|
12565
12843
|
"claude-sonnet-4-5": "sonnet",
|
|
12566
12844
|
"claude-sonnet-4-6": "sonnet",
|
|
12567
12845
|
"claude-haiku-4-5": "haiku"
|
|
@@ -12572,6 +12850,7 @@ function toSdkModelId(modelId) {
|
|
|
12572
12850
|
var MODELS_WITH_1M_CONTEXT = /* @__PURE__ */ new Set([
|
|
12573
12851
|
"claude-opus-4-6",
|
|
12574
12852
|
"claude-opus-4-7",
|
|
12853
|
+
"claude-opus-4-8",
|
|
12575
12854
|
"claude-sonnet-4-6"
|
|
12576
12855
|
]);
|
|
12577
12856
|
function supports1MContext(modelId) {
|
|
@@ -12581,11 +12860,13 @@ var MODELS_WITH_EFFORT = /* @__PURE__ */ new Set([
|
|
|
12581
12860
|
"claude-opus-4-5",
|
|
12582
12861
|
"claude-opus-4-6",
|
|
12583
12862
|
"claude-opus-4-7",
|
|
12863
|
+
"claude-opus-4-8",
|
|
12584
12864
|
"claude-sonnet-4-6"
|
|
12585
12865
|
]);
|
|
12586
12866
|
var MODELS_WITH_XHIGH_EFFORT = /* @__PURE__ */ new Set([
|
|
12587
12867
|
"claude-opus-4-6",
|
|
12588
|
-
"claude-opus-4-7"
|
|
12868
|
+
"claude-opus-4-7",
|
|
12869
|
+
"claude-opus-4-8"
|
|
12589
12870
|
]);
|
|
12590
12871
|
function supportsEffort(modelId) {
|
|
12591
12872
|
return MODELS_WITH_EFFORT.has(modelId);
|
|
@@ -12625,6 +12906,19 @@ function tokenizeModelPreference(model) {
|
|
|
12625
12906
|
}).filter((token) => token && token !== "claude").filter((token) => /[a-z]/.test(token) || token.endsWith("m"));
|
|
12626
12907
|
return { tokens, contextHint };
|
|
12627
12908
|
}
|
|
12909
|
+
var MODEL_FAMILY_VERSION_PATTERN = /\b(\d+)[-.](\d+)\b/;
|
|
12910
|
+
function extractModelFamilyVersion(s) {
|
|
12911
|
+
if (!s) return null;
|
|
12912
|
+
const match = s.match(MODEL_FAMILY_VERSION_PATTERN);
|
|
12913
|
+
return match ? `${match[1]}.${match[2]}` : null;
|
|
12914
|
+
}
|
|
12915
|
+
function modelVersionsCompatible(preference, candidate) {
|
|
12916
|
+
const preferred = extractModelFamilyVersion(preference);
|
|
12917
|
+
if (!preferred) return true;
|
|
12918
|
+
const candidateVersion = extractModelFamilyVersion(candidate.value) ?? extractModelFamilyVersion(candidate.name) ?? extractModelFamilyVersion(candidate.description);
|
|
12919
|
+
if (!candidateVersion) return true;
|
|
12920
|
+
return preferred === candidateVersion;
|
|
12921
|
+
}
|
|
12628
12922
|
function scoreModelMatch(model, tokens, contextHint) {
|
|
12629
12923
|
const haystack = `${model.value} ${model.name ?? ""}`.toLowerCase();
|
|
12630
12924
|
let score = 0;
|
|
@@ -12644,6 +12938,7 @@ function resolveModelPreference(preference, options) {
|
|
|
12644
12938
|
);
|
|
12645
12939
|
if (directMatch) return directMatch.value;
|
|
12646
12940
|
const includesMatch = options.find((o) => {
|
|
12941
|
+
if (!modelVersionsCompatible(trimmed2, o)) return false;
|
|
12647
12942
|
const value = o.value.toLowerCase();
|
|
12648
12943
|
const display = (o.name ?? "").toLowerCase();
|
|
12649
12944
|
return value.includes(lower) || display.includes(lower) || lower.includes(value);
|
|
@@ -12654,6 +12949,7 @@ function resolveModelPreference(preference, options) {
|
|
|
12654
12949
|
let bestMatch = null;
|
|
12655
12950
|
let bestScore = 0;
|
|
12656
12951
|
for (const model of options) {
|
|
12952
|
+
if (!modelVersionsCompatible(trimmed2, model)) continue;
|
|
12657
12953
|
const score = scoreModelMatch(model, tokens, contextHint);
|
|
12658
12954
|
if (0 < score && (!bestMatch || bestScore < score)) {
|
|
12659
12955
|
bestMatch = model;
|
|
@@ -12730,6 +13026,7 @@ function buildEnvironment() {
|
|
|
12730
13026
|
const existingCustomHeaders = process.env.ANTHROPIC_CUSTOM_HEADERS;
|
|
12731
13027
|
const customHeaders = existingCustomHeaders ? `${existingCustomHeaders}
|
|
12732
13028
|
${bedrockFallbackHeader}` : bedrockFallbackHeader;
|
|
13029
|
+
const mcpNonblocking = process.env.MCP_CONNECTION_NONBLOCKING;
|
|
12733
13030
|
return {
|
|
12734
13031
|
...process.env,
|
|
12735
13032
|
ELECTRON_RUN_AS_NODE: "1",
|
|
@@ -12738,11 +13035,14 @@ ${bedrockFallbackHeader}` : bedrockFallbackHeader;
|
|
|
12738
13035
|
ENABLE_TOOL_SEARCH: "auto:0",
|
|
12739
13036
|
// Enable idle state as end-of-turn signal (required for SDK 0.2.114+)
|
|
12740
13037
|
CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS: "1",
|
|
13038
|
+
...mcpNonblocking !== void 0 && {
|
|
13039
|
+
MCP_CONNECTION_NONBLOCKING: mcpNonblocking
|
|
13040
|
+
},
|
|
12741
13041
|
// Route to AWS Bedrock as a fallback when Anthropic returns 5xx
|
|
12742
13042
|
ANTHROPIC_CUSTOM_HEADERS: customHeaders
|
|
12743
13043
|
};
|
|
12744
13044
|
}
|
|
12745
|
-
function buildHooks(userHooks, onModeChange, settingsManager, logger, enrichmentDeps, enrichedReadCache, registeredAgents, cloudMode) {
|
|
13045
|
+
function buildHooks(userHooks, onModeChange, settingsManager, logger, enrichmentDeps, enrichedReadCache, registeredAgents, cloudMode, taskState, onTaskStateChange) {
|
|
12746
13046
|
const postToolUseHooks = [createPostToolUseHook({ onModeChange })];
|
|
12747
13047
|
if (enrichmentDeps && enrichedReadCache) {
|
|
12748
13048
|
postToolUseHooks.push(
|
|
@@ -12756,13 +13056,16 @@ function buildHooks(userHooks, onModeChange, settingsManager, logger, enrichment
|
|
|
12756
13056
|
if (cloudMode) {
|
|
12757
13057
|
preToolUseHooks.push(createSignedCommitGuardHook(logger));
|
|
12758
13058
|
}
|
|
13059
|
+
const taskHook = createTaskHook(taskState, onTaskStateChange);
|
|
12759
13060
|
return {
|
|
12760
13061
|
...userHooks,
|
|
12761
13062
|
PostToolUse: [
|
|
12762
13063
|
...userHooks?.PostToolUse || [],
|
|
12763
13064
|
{ hooks: postToolUseHooks }
|
|
12764
13065
|
],
|
|
12765
|
-
PreToolUse: [...userHooks?.PreToolUse || [], { hooks: preToolUseHooks }]
|
|
13066
|
+
PreToolUse: [...userHooks?.PreToolUse || [], { hooks: preToolUseHooks }],
|
|
13067
|
+
TaskCreated: [...userHooks?.TaskCreated || [], { hooks: [taskHook] }],
|
|
13068
|
+
TaskCompleted: [...userHooks?.TaskCompleted || [], { hooks: [taskHook] }]
|
|
12766
13069
|
};
|
|
12767
13070
|
}
|
|
12768
13071
|
var PH_EXPLORE_AGENT = {
|
|
@@ -12793,7 +13096,10 @@ Rules:
|
|
|
12793
13096
|
"WebFetch",
|
|
12794
13097
|
"WebSearch",
|
|
12795
13098
|
"NotebookRead",
|
|
12796
|
-
"
|
|
13099
|
+
"TaskCreate",
|
|
13100
|
+
"TaskUpdate",
|
|
13101
|
+
"TaskGet",
|
|
13102
|
+
"TaskList"
|
|
12797
13103
|
]
|
|
12798
13104
|
};
|
|
12799
13105
|
function buildAgents(userAgents) {
|
|
@@ -12921,7 +13227,9 @@ function buildSessionOptions(params) {
|
|
|
12921
13227
|
params.enrichmentDeps,
|
|
12922
13228
|
params.enrichedReadCache,
|
|
12923
13229
|
registeredAgentNames,
|
|
12924
|
-
params.cloudMode ?? false
|
|
13230
|
+
params.cloudMode ?? false,
|
|
13231
|
+
params.taskState,
|
|
13232
|
+
params.onTaskStateChange
|
|
12925
13233
|
),
|
|
12926
13234
|
outputFormat: params.outputFormat,
|
|
12927
13235
|
abortController: getAbortController(
|
|
@@ -17957,6 +18265,15 @@ function getManagedSettingsPath() {
|
|
|
17957
18265
|
return "/etc/claude-code/managed-settings.json";
|
|
17958
18266
|
}
|
|
17959
18267
|
}
|
|
18268
|
+
function mergeAvailableModels(existing, incoming, layer) {
|
|
18269
|
+
if (incoming === void 0) {
|
|
18270
|
+
return existing;
|
|
18271
|
+
}
|
|
18272
|
+
if (layer === "enterprise") {
|
|
18273
|
+
return Array.from(new Set(incoming));
|
|
18274
|
+
}
|
|
18275
|
+
return Array.from(/* @__PURE__ */ new Set([...existing ?? [], ...incoming]));
|
|
18276
|
+
}
|
|
17960
18277
|
var SettingsManager = class {
|
|
17961
18278
|
cwd;
|
|
17962
18279
|
repoRoot;
|
|
@@ -18012,10 +18329,10 @@ var SettingsManager = class {
|
|
|
18012
18329
|
}
|
|
18013
18330
|
mergeAllSettings() {
|
|
18014
18331
|
const allSettings = [
|
|
18015
|
-
this.userSettings,
|
|
18016
|
-
this.projectSettings,
|
|
18017
|
-
this.localSettings,
|
|
18018
|
-
this.enterpriseSettings
|
|
18332
|
+
{ layer: "user", settings: this.userSettings },
|
|
18333
|
+
{ layer: "project", settings: this.projectSettings },
|
|
18334
|
+
{ layer: "local", settings: this.localSettings },
|
|
18335
|
+
{ layer: "enterprise", settings: this.enterpriseSettings }
|
|
18019
18336
|
];
|
|
18020
18337
|
const permissions = {
|
|
18021
18338
|
allow: [],
|
|
@@ -18024,7 +18341,7 @@ var SettingsManager = class {
|
|
|
18024
18341
|
};
|
|
18025
18342
|
const merged = { permissions };
|
|
18026
18343
|
const posthogApprovedExecTools = /* @__PURE__ */ new Set();
|
|
18027
|
-
for (const settings of allSettings) {
|
|
18344
|
+
for (const { layer, settings } of allSettings) {
|
|
18028
18345
|
if (settings.permissions) {
|
|
18029
18346
|
if (settings.permissions.allow) {
|
|
18030
18347
|
permissions.allow?.push(...settings.permissions.allow);
|
|
@@ -18051,6 +18368,11 @@ var SettingsManager = class {
|
|
|
18051
18368
|
if (settings.model) {
|
|
18052
18369
|
merged.model = settings.model;
|
|
18053
18370
|
}
|
|
18371
|
+
merged.availableModels = mergeAvailableModels(
|
|
18372
|
+
merged.availableModels,
|
|
18373
|
+
settings.availableModels,
|
|
18374
|
+
layer
|
|
18375
|
+
);
|
|
18054
18376
|
if (settings.posthogApprovedExecTools) {
|
|
18055
18377
|
for (const tool2 of settings.posthogApprovedExecTools) {
|
|
18056
18378
|
posthogApprovedExecTools.add(tool2);
|
|
@@ -18193,6 +18515,14 @@ function readClaudeMdQuietly(cwd, logger) {
|
|
|
18193
18515
|
return void 0;
|
|
18194
18516
|
}
|
|
18195
18517
|
}
|
|
18518
|
+
function collectKnownSlashCommands(commands) {
|
|
18519
|
+
const names = /* @__PURE__ */ new Set();
|
|
18520
|
+
if (!commands) return names;
|
|
18521
|
+
for (const cmd of commands) {
|
|
18522
|
+
if (cmd.name) names.add(cmd.name);
|
|
18523
|
+
}
|
|
18524
|
+
return names;
|
|
18525
|
+
}
|
|
18196
18526
|
function sanitizeTitle(text2) {
|
|
18197
18527
|
const sanitized = text2.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
18198
18528
|
if (sanitized.length <= MAX_TITLE_LENGTH) {
|
|
@@ -18251,6 +18581,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18251
18581
|
},
|
|
18252
18582
|
loadSession: true,
|
|
18253
18583
|
sessionCapabilities: {
|
|
18584
|
+
additionalDirectories: {},
|
|
18254
18585
|
list: {},
|
|
18255
18586
|
fork: {},
|
|
18256
18587
|
resume: {}
|
|
@@ -18276,10 +18607,18 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18276
18607
|
if (fs10.existsSync(path14.resolve(os6.homedir(), ".claude.json.backup")) && !fs10.existsSync(path14.resolve(os6.homedir(), ".claude.json"))) {
|
|
18277
18608
|
throw RequestError2.authRequired();
|
|
18278
18609
|
}
|
|
18279
|
-
const response = await this.createSession(
|
|
18280
|
-
|
|
18281
|
-
|
|
18282
|
-
|
|
18610
|
+
const response = await this.createSession(
|
|
18611
|
+
{
|
|
18612
|
+
cwd: params.cwd,
|
|
18613
|
+
mcpServers: params.mcpServers ?? [],
|
|
18614
|
+
additionalDirectories: params.additionalDirectories,
|
|
18615
|
+
_meta: params._meta
|
|
18616
|
+
},
|
|
18617
|
+
{
|
|
18618
|
+
// Revisit these meta values once we support resume
|
|
18619
|
+
resume: params._meta?.claudeCode?.options?.resume
|
|
18620
|
+
}
|
|
18621
|
+
);
|
|
18283
18622
|
return response;
|
|
18284
18623
|
}
|
|
18285
18624
|
async unstable_forkSession(params) {
|
|
@@ -18287,24 +18626,27 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18287
18626
|
{
|
|
18288
18627
|
cwd: params.cwd,
|
|
18289
18628
|
mcpServers: params.mcpServers ?? [],
|
|
18629
|
+
additionalDirectories: params.additionalDirectories,
|
|
18290
18630
|
_meta: params._meta
|
|
18291
18631
|
},
|
|
18292
18632
|
{ resume: params.sessionId, forkSession: true }
|
|
18293
18633
|
);
|
|
18294
18634
|
}
|
|
18295
|
-
async
|
|
18635
|
+
async resumeSession(params) {
|
|
18296
18636
|
const existing = this.getExistingSessionState(params.sessionId);
|
|
18297
18637
|
if (existing) return existing;
|
|
18298
18638
|
const response = await this.createSession(
|
|
18299
18639
|
{
|
|
18300
18640
|
cwd: params.cwd,
|
|
18301
18641
|
mcpServers: params.mcpServers ?? [],
|
|
18642
|
+
additionalDirectories: params.additionalDirectories,
|
|
18302
18643
|
_meta: params._meta
|
|
18303
18644
|
},
|
|
18304
18645
|
{
|
|
18305
18646
|
resume: params.sessionId
|
|
18306
18647
|
}
|
|
18307
18648
|
);
|
|
18649
|
+
await this.rehydrateTaskStateFromJsonl(params.sessionId);
|
|
18308
18650
|
return response;
|
|
18309
18651
|
}
|
|
18310
18652
|
async loadSession(params) {
|
|
@@ -18314,6 +18656,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18314
18656
|
{
|
|
18315
18657
|
cwd: params.cwd,
|
|
18316
18658
|
mcpServers: params.mcpServers ?? [],
|
|
18659
|
+
additionalDirectories: params.additionalDirectories,
|
|
18317
18660
|
_meta: params._meta
|
|
18318
18661
|
},
|
|
18319
18662
|
{ resume: params.sessionId, skipBackgroundFetches: true }
|
|
@@ -18392,6 +18735,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18392
18735
|
await this.broadcastUserMessage(params);
|
|
18393
18736
|
this.session.promptRunning = true;
|
|
18394
18737
|
let handedOff = false;
|
|
18738
|
+
let errored = false;
|
|
18395
18739
|
let lastAssistantTotalUsage = null;
|
|
18396
18740
|
let lastStreamUsage = {
|
|
18397
18741
|
input_tokens: 0,
|
|
@@ -18399,6 +18743,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18399
18743
|
cache_read_input_tokens: 0,
|
|
18400
18744
|
cache_creation_input_tokens: 0
|
|
18401
18745
|
};
|
|
18746
|
+
let compactionInProgress = false;
|
|
18402
18747
|
if (this.session.lastContextWindowSize == null) {
|
|
18403
18748
|
this.session.lastContextWindowSize = this.getContextWindowForModel(
|
|
18404
18749
|
this.session.modelId ?? ""
|
|
@@ -18456,9 +18801,45 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18456
18801
|
if (message.subtype === "local_command_output") {
|
|
18457
18802
|
promptReplayed = true;
|
|
18458
18803
|
}
|
|
18804
|
+
if (message.subtype === "status") {
|
|
18805
|
+
if (message.status === "compacting") {
|
|
18806
|
+
compactionInProgress = true;
|
|
18807
|
+
} else if (message.compact_result === "success" && compactionInProgress) {
|
|
18808
|
+
compactionInProgress = false;
|
|
18809
|
+
await this.client.sessionUpdate({
|
|
18810
|
+
sessionId: params.sessionId,
|
|
18811
|
+
update: {
|
|
18812
|
+
sessionUpdate: "agent_message_chunk",
|
|
18813
|
+
content: {
|
|
18814
|
+
type: "text",
|
|
18815
|
+
text: "\n\nCompacting completed."
|
|
18816
|
+
}
|
|
18817
|
+
}
|
|
18818
|
+
});
|
|
18819
|
+
break;
|
|
18820
|
+
} else if (message.compact_result === "failed" && compactionInProgress) {
|
|
18821
|
+
compactionInProgress = false;
|
|
18822
|
+
const reason = message.compact_error ? `: ${message.compact_error}` : ".";
|
|
18823
|
+
await this.client.sessionUpdate({
|
|
18824
|
+
sessionId: params.sessionId,
|
|
18825
|
+
update: {
|
|
18826
|
+
sessionUpdate: "agent_message_chunk",
|
|
18827
|
+
content: {
|
|
18828
|
+
type: "text",
|
|
18829
|
+
text: `
|
|
18830
|
+
|
|
18831
|
+
Compacting failed${reason}`
|
|
18832
|
+
}
|
|
18833
|
+
}
|
|
18834
|
+
});
|
|
18835
|
+
break;
|
|
18836
|
+
}
|
|
18837
|
+
}
|
|
18459
18838
|
if (message.subtype === "session_state_changed" && message.state === "idle") {
|
|
18460
18839
|
if (!promptReplayed) {
|
|
18461
|
-
|
|
18840
|
+
const cmdName = commandMatch?.[1].slice(1);
|
|
18841
|
+
const known = cmdName !== void 0 && this.session.knownSlashCommands?.has(cmdName) === true;
|
|
18842
|
+
if (commandMatch && !known) {
|
|
18462
18843
|
const cmd = commandMatch[1];
|
|
18463
18844
|
this.logger.warn(
|
|
18464
18845
|
"Slash command produced no output; treating as unsupported",
|
|
@@ -18477,7 +18858,9 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18477
18858
|
return { stopReason: "end_turn" };
|
|
18478
18859
|
}
|
|
18479
18860
|
this.logger.debug("Skipping idle state before prompt replay", {
|
|
18480
|
-
sessionId: params.sessionId
|
|
18861
|
+
sessionId: params.sessionId,
|
|
18862
|
+
command: commandMatch?.[1],
|
|
18863
|
+
known
|
|
18481
18864
|
});
|
|
18482
18865
|
break;
|
|
18483
18866
|
}
|
|
@@ -18491,7 +18874,9 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18491
18874
|
size: lastContextWindowSize
|
|
18492
18875
|
}
|
|
18493
18876
|
});
|
|
18494
|
-
return {
|
|
18877
|
+
return {
|
|
18878
|
+
stopReason: this.session.cancelled ? "cancelled" : "end_turn"
|
|
18879
|
+
};
|
|
18495
18880
|
}
|
|
18496
18881
|
await handleSystemMessage(message, context);
|
|
18497
18882
|
break;
|
|
@@ -18674,6 +19059,28 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18674
19059
|
}
|
|
18675
19060
|
throw new Error("Session did not end in result");
|
|
18676
19061
|
} catch (error) {
|
|
19062
|
+
errored = true;
|
|
19063
|
+
try {
|
|
19064
|
+
await this.session.query.interrupt();
|
|
19065
|
+
const MAX_DRAIN = 100;
|
|
19066
|
+
for (let i2 = 0; i2 < MAX_DRAIN; i2++) {
|
|
19067
|
+
const { value: m, done } = await this.session.query.next();
|
|
19068
|
+
if (done || !m) break;
|
|
19069
|
+
if (m.type === "system" && m.subtype === "session_state_changed" && m.state === "idle") {
|
|
19070
|
+
break;
|
|
19071
|
+
}
|
|
19072
|
+
if (i2 === MAX_DRAIN - 1) {
|
|
19073
|
+
this.logger.error(
|
|
19074
|
+
`Session ${params.sessionId}: drained ${MAX_DRAIN} messages after error without observing idle`
|
|
19075
|
+
);
|
|
19076
|
+
}
|
|
19077
|
+
}
|
|
19078
|
+
} catch (drainErr) {
|
|
19079
|
+
this.logger.error(
|
|
19080
|
+
`Session ${params.sessionId}: failed to drain query after prompt error`,
|
|
19081
|
+
{ error: drainErr }
|
|
19082
|
+
);
|
|
19083
|
+
}
|
|
18677
19084
|
if (error instanceof RequestError2 || !(error instanceof Error)) {
|
|
18678
19085
|
throw error;
|
|
18679
19086
|
}
|
|
@@ -18694,9 +19101,19 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18694
19101
|
this.toolUseStreamCache.clear();
|
|
18695
19102
|
if (!handedOff) {
|
|
18696
19103
|
this.session.promptRunning = false;
|
|
18697
|
-
|
|
18698
|
-
pending.
|
|
18699
|
-
|
|
19104
|
+
if (errored) {
|
|
19105
|
+
for (const pending of this.session.pendingMessages.values()) {
|
|
19106
|
+
pending.resolve(true);
|
|
19107
|
+
}
|
|
19108
|
+
this.session.pendingMessages.clear();
|
|
19109
|
+
} else if (this.session.pendingMessages.size > 0) {
|
|
19110
|
+
const next = [...this.session.pendingMessages.entries()].sort(
|
|
19111
|
+
(a, b) => a[1].order - b[1].order
|
|
19112
|
+
)[0];
|
|
19113
|
+
if (next) {
|
|
19114
|
+
next[1].resolve(false);
|
|
19115
|
+
this.session.pendingMessages.delete(next[0]);
|
|
19116
|
+
}
|
|
18700
19117
|
}
|
|
18701
19118
|
}
|
|
18702
19119
|
}
|
|
@@ -18747,7 +19164,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18747
19164
|
);
|
|
18748
19165
|
}
|
|
18749
19166
|
const mcpServers = parseMcpServers(
|
|
18750
|
-
params
|
|
19167
|
+
params,
|
|
19168
|
+
this.logger
|
|
18751
19169
|
);
|
|
18752
19170
|
await this.refreshSession(mcpServers);
|
|
18753
19171
|
return { refreshed: true };
|
|
@@ -18932,7 +19350,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18932
19350
|
const settingsManager = new SettingsManager(cwd);
|
|
18933
19351
|
await settingsManager.initialize();
|
|
18934
19352
|
const earlyModelId = settingsManager.getSettings().model || meta?.model || "";
|
|
18935
|
-
const mcpServers = supportsMcpInjection(earlyModelId) ? parseMcpServers(params) : {};
|
|
19353
|
+
const mcpServers = supportsMcpInjection(earlyModelId) ? parseMcpServers(params, this.logger) : {};
|
|
18936
19354
|
const localToolsServer = createLocalToolsMcpServer(
|
|
18937
19355
|
{ cwd, token: resolveGithubToken(), taskId },
|
|
18938
19356
|
meta
|
|
@@ -18956,6 +19374,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18956
19374
|
cwd
|
|
18957
19375
|
});
|
|
18958
19376
|
const permissionMode = meta?.permissionMode && CODE_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
19377
|
+
const taskState = /* @__PURE__ */ new Map();
|
|
18959
19378
|
const options = buildSessionOptions({
|
|
18960
19379
|
cwd,
|
|
18961
19380
|
mcpServers,
|
|
@@ -18969,7 +19388,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18969
19388
|
forkSession,
|
|
18970
19389
|
additionalDirectories: [
|
|
18971
19390
|
...meta?.claudeCode?.options?.additionalDirectories ?? [],
|
|
18972
|
-
|
|
19391
|
+
// Prefer the official ACP `additionalDirectories` field. Fall back
|
|
19392
|
+
// to the legacy `_meta.additionalRoots` extension for clients that
|
|
19393
|
+
// haven't been updated yet.
|
|
19394
|
+
...params.additionalDirectories ?? meta?.additionalRoots ?? []
|
|
18973
19395
|
],
|
|
18974
19396
|
disableBuiltInTools: meta?.disableBuiltInTools,
|
|
18975
19397
|
outputFormat,
|
|
@@ -18980,7 +19402,17 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18980
19402
|
effort,
|
|
18981
19403
|
enrichmentDeps: this.enrichment?.deps,
|
|
18982
19404
|
enrichedReadCache: this.enrichedReadCache,
|
|
18983
|
-
cloudMode: cloudRun
|
|
19405
|
+
cloudMode: cloudRun,
|
|
19406
|
+
taskState,
|
|
19407
|
+
onTaskStateChange: async () => {
|
|
19408
|
+
await this.client.sessionUpdate({
|
|
19409
|
+
sessionId,
|
|
19410
|
+
update: {
|
|
19411
|
+
sessionUpdate: "plan",
|
|
19412
|
+
entries: taskStateToPlanEntries(taskState)
|
|
19413
|
+
}
|
|
19414
|
+
});
|
|
19415
|
+
}
|
|
18984
19416
|
});
|
|
18985
19417
|
const abortController = options.abortController;
|
|
18986
19418
|
const q = query({ prompt: input, options });
|
|
@@ -19009,6 +19441,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19009
19441
|
systemPrompt: estimateSystemPrompt(systemPrompt),
|
|
19010
19442
|
rules: estimateRulesTokens(readClaudeMdQuietly(cwd, this.logger))
|
|
19011
19443
|
},
|
|
19444
|
+
taskState,
|
|
19012
19445
|
// Custom properties
|
|
19013
19446
|
cwd,
|
|
19014
19447
|
notificationHistory: [],
|
|
@@ -19027,6 +19460,9 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19027
19460
|
`Session ${forkSession ? "fork" : "resumption"} timed out for sessionId=${sessionId}`
|
|
19028
19461
|
);
|
|
19029
19462
|
}
|
|
19463
|
+
session.knownSlashCommands = collectKnownSlashCommands(
|
|
19464
|
+
result.value.commands
|
|
19465
|
+
);
|
|
19030
19466
|
} catch (err2) {
|
|
19031
19467
|
settingsManager.dispose();
|
|
19032
19468
|
if (err2 instanceof Error && err2.message === "Query closed before response received") {
|
|
@@ -19045,7 +19481,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19045
19481
|
}
|
|
19046
19482
|
}
|
|
19047
19483
|
const initPromise2 = !isResume ? withTimeout(q.initializationResult(), SESSION_VALIDATION_TIMEOUT_MS) : void 0;
|
|
19048
|
-
const [
|
|
19484
|
+
const [rawModelOptions] = await Promise.all([
|
|
19049
19485
|
this.getModelConfigOptions(
|
|
19050
19486
|
settingsManager.getSettings().model || meta?.model || void 0
|
|
19051
19487
|
),
|
|
@@ -19057,6 +19493,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19057
19493
|
})
|
|
19058
19494
|
] : []
|
|
19059
19495
|
]);
|
|
19496
|
+
const settingsAvailableModels = settingsManager.getSettings().availableModels;
|
|
19497
|
+
const modelOptions = Array.isArray(settingsAvailableModels) ? applyAvailableModelsAllowlist(rawModelOptions, settingsAvailableModels) : rawModelOptions;
|
|
19060
19498
|
if (initPromise2) {
|
|
19061
19499
|
try {
|
|
19062
19500
|
const initResult = await initPromise2;
|
|
@@ -19066,6 +19504,9 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19066
19504
|
`Session initialization timed out for sessionId=${sessionId}`
|
|
19067
19505
|
);
|
|
19068
19506
|
}
|
|
19507
|
+
session.knownSlashCommands = collectKnownSlashCommands(
|
|
19508
|
+
initResult.value.commands
|
|
19509
|
+
);
|
|
19069
19510
|
} catch (err2) {
|
|
19070
19511
|
settingsManager.dispose();
|
|
19071
19512
|
this.logger.error("Session initialization failed", {
|
|
@@ -19077,9 +19518,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19077
19518
|
throw err2;
|
|
19078
19519
|
}
|
|
19079
19520
|
}
|
|
19080
|
-
const
|
|
19081
|
-
|
|
19082
|
-
|
|
19521
|
+
const resolvedModelId = resolveInitialModelId(modelOptions, [
|
|
19522
|
+
settingsManager.getSettings().model,
|
|
19523
|
+
meta?.model
|
|
19524
|
+
]);
|
|
19083
19525
|
session.modelId = resolvedModelId;
|
|
19084
19526
|
session.lastContextWindowSize = this.getContextWindowForModel(resolvedModelId);
|
|
19085
19527
|
const resolvedSdkModel = toSdkModelId(resolvedModelId);
|
|
@@ -19287,6 +19729,34 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19287
19729
|
[key]: tokens
|
|
19288
19730
|
};
|
|
19289
19731
|
}
|
|
19732
|
+
/**
|
|
19733
|
+
* Rebuild the in-memory taskState from JSONL and push a plan update so the
|
|
19734
|
+
* client's plan panel reflects pre-resume tasks. `loadSession` already covers
|
|
19735
|
+
* this via the full `replaySessionHistory` notification stream; resume
|
|
19736
|
+
* deliberately stays quiet (the client keeps its own message history) so we
|
|
19737
|
+
* walk the transcript here for state only.
|
|
19738
|
+
*/
|
|
19739
|
+
async rehydrateTaskStateFromJsonl(sessionId) {
|
|
19740
|
+
try {
|
|
19741
|
+
const messages = await getSessionMessages(sessionId, {
|
|
19742
|
+
dir: this.session.cwd
|
|
19743
|
+
});
|
|
19744
|
+
rehydrateTaskState(messages, this.session.taskState);
|
|
19745
|
+
if (this.session.taskState.size === 0) return;
|
|
19746
|
+
await this.client.sessionUpdate({
|
|
19747
|
+
sessionId,
|
|
19748
|
+
update: {
|
|
19749
|
+
sessionUpdate: "plan",
|
|
19750
|
+
entries: taskStateToPlanEntries(this.session.taskState)
|
|
19751
|
+
}
|
|
19752
|
+
});
|
|
19753
|
+
} catch (err2) {
|
|
19754
|
+
this.logger.warn("Failed to rehydrate task state", {
|
|
19755
|
+
sessionId,
|
|
19756
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
19757
|
+
});
|
|
19758
|
+
}
|
|
19759
|
+
}
|
|
19290
19760
|
async replaySessionHistory(sessionId) {
|
|
19291
19761
|
try {
|
|
19292
19762
|
const messages = await getSessionMessages(sessionId, {
|
|
@@ -20077,7 +20547,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
20077
20547
|
}
|
|
20078
20548
|
return response;
|
|
20079
20549
|
}
|
|
20080
|
-
async
|
|
20550
|
+
async resumeSession(params) {
|
|
20081
20551
|
const meta = params._meta;
|
|
20082
20552
|
const injectedParams = this.applyLocalTools(
|
|
20083
20553
|
this.applyStructuredOutput(
|