Make sure updating commands happens at the end of loading (#302)

This commit is contained in:
Ben Brandt
2026-02-10 14:18:04 +01:00
committed by GitHub
parent ea00a4014a
commit 673b0507d7
2 changed files with 76 additions and 14 deletions

View File

@@ -259,14 +259,19 @@ export class ClaudeAcpAgent implements Agent {
throw RequestError.authRequired();
}
return await this.createSession(params, {
const response = await this.createSession(params, {
// Revisit these meta values once we support resume
resume: (params._meta as NewSessionMeta | undefined)?.claudeCode?.options?.resume,
});
// Needs to happen after we return the session
setTimeout(() => {
this.sendAvailableCommandsUpdate(response.sessionId);
}, 0);
return response;
}
async unstable_forkSession(params: ForkSessionRequest): Promise<ForkSessionResponse> {
return await this.createSession(
const response = await this.createSession(
{
cwd: params.cwd,
mcpServers: params.mcpServers ?? [],
@@ -277,6 +282,11 @@ export class ClaudeAcpAgent implements Agent {
forkSession: true,
},
);
// Needs to happen after we return the session
setTimeout(() => {
this.sendAvailableCommandsUpdate(response.sessionId);
}, 0);
return response;
}
async unstable_resumeSession(params: ResumeSessionRequest): Promise<ResumeSessionResponse> {
@@ -290,7 +300,10 @@ export class ClaudeAcpAgent implements Agent {
resume: params.sessionId,
},
);
// Needs to happen after we return the session
setTimeout(() => {
this.sendAvailableCommandsUpdate(response.sessionId);
}, 0);
return response;
}
@@ -353,6 +366,11 @@ export class ClaudeAcpAgent implements Agent {
await this.replaySessionHistory(params.sessionId, filePath);
// Send available commands after replay so it doesn't interleave with history
setTimeout(() => {
this.sendAvailableCommandsUpdate(params.sessionId);
}, 0);
return {
modes: response.modes,
models: response.models,
@@ -951,6 +969,19 @@ export class ClaudeAcpAgent implements Agent {
};
}
private async sendAvailableCommandsUpdate(sessionId: string): Promise<void> {
const session = this.sessions[sessionId];
if (!session) return;
const commands = await session.query.supportedCommands();
await this.client.sessionUpdate({
sessionId,
update: {
sessionUpdate: "available_commands_update",
availableCommands: getAvailableSlashCommands(commands),
},
});
}
private async createSession(
params: NewSessionRequest,
creationOpts: { resume?: string; forkSession?: boolean } = {},
@@ -1170,17 +1201,6 @@ export class ClaudeAcpAgent implements Agent {
const models = await getAvailableModels(q, initializationResult.models, settingsManager);
// Needs to happen after we return the session
setTimeout(() => {
this.client.sessionUpdate({
sessionId,
update: {
sessionUpdate: "available_commands_update",
availableCommands: getAvailableSlashCommands(initializationResult.commands),
},
});
}, 0);
const availableModes = [
{
id: "default",

View File

@@ -258,6 +258,48 @@ describe("loadSession", () => {
});
});
it("sends available_commands_update after history replay, not during", async () => {
const cwd = "/Users/test/project";
const sessionId = "session-commands";
// Mock createSession to populate the sessions map with a mock query
createSessionSpy.mockImplementationOnce(async () => {
(agent as unknown as { sessions: Record<string, unknown> }).sessions[sessionId] = {
query: {
supportedCommands: async () => [{ name: "help", description: "Get help" }],
},
};
return { modes: null, models: null };
});
writeSessionFile(cwd, sessionId, [
{
type: "user",
sessionId,
message: { role: "user", content: "Hello" },
},
{
type: "assistant",
sessionId,
message: { role: "assistant", content: [{ type: "text", text: "Hi" }] },
},
]);
await agent.loadSession({ cwd, sessionId, mcpServers: [] });
// Flush the setTimeout + async work inside sendAvailableCommandsUpdate
await new Promise((resolve) => setTimeout(resolve, 10));
const updateTypes = sessionUpdates.map((n) => n.update.sessionUpdate);
// available_commands_update should come AFTER all replay notifications
expect(updateTypes).toEqual([
"user_message_chunk",
"agent_message_chunk",
"available_commands_update",
]);
});
it("handles Windows-style paths", async () => {
const cwd = "C:\\Users\\test\\project";
const sessionId = "win-session";