Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/CodexAcpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import type {
UserInput,
} from "./app-server/v2";
import packageJson from "../package.json";
import type {AuthenticationLogoutResponse, AuthenticationStatusResponse} from "./AcpExtensions";
import type {AuthenticationStatusResponse} from "./AcpExtensions";

/**
* API for accessing the Codex App Server using ACP requests.
Expand Down Expand Up @@ -176,11 +176,10 @@ export class CodexAcpClient {
return settingsModelProvider.config.model_provider;
}

async logout(): Promise<AuthenticationLogoutResponse> {
async logout(): Promise<void> {
const accountUpdatedPromise = this.awaitNextAccountUpdated();
await this.codexClient.accountLogout();
await accountUpdatedPromise;
return {};
}

async authRequired(): Promise<Boolean> {
Expand Down
15 changes: 13 additions & 2 deletions src/CodexAcpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ export class CodexAcpServer implements acp.Agent {
return {
protocolVersion: acp.PROTOCOL_VERSION,
agentCapabilities: {
auth: {
logout: {},
},
loadSession: true,
promptCapabilities: {
image: true
Expand All @@ -121,8 +124,10 @@ export class CodexAcpServer implements acp.Agent {
switch (methodRequest.method) {
case "authentication/status":
return await this.runWithProcessCheck(() => this.codexAcpClient.getAuthenticationStatus());
case "authentication/logout":
return await this.runWithProcessCheck(() => this.codexAcpClient.logout());
case "authentication/logout": {
await this.unstable_logout({});
return {};
}
}
}

Expand Down Expand Up @@ -270,6 +275,12 @@ export class CodexAcpServer implements acp.Agent {
return { };
}

async unstable_logout(_params: acp.LogoutRequest): Promise<void> {
logger.log("Logout request received");
await this.runWithProcessCheck(() => this.codexAcpClient.logout());
logger.log("Logout request completed");
}

async setSessionMode(
_params: acp.SetSessionModeRequest,
): Promise<acp.SetSessionModeResponse> {
Expand Down
14 changes: 12 additions & 2 deletions src/__tests__/CodexACPAgent/CodexAcpClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ describe('ACP server test', { timeout: 40_000 }, () => {
const authenticatedResponse = await keyFixture.getCodexAcpAgent().extMethod("authentication/status", {});
expect(authenticatedResponse).toEqual({type: "api-key"});

await keyFixture.getCodexAcpAgent().extMethod("authentication/logout", {});
await keyFixture.getCodexAcpAgent().unstable_logout({});
const logoutResponse = await keyFixture.getCodexAcpAgent().extMethod("authentication/status", {});
expect(logoutResponse).toEqual({type: "unauthenticated"});
});
Expand Down Expand Up @@ -146,6 +146,16 @@ describe('ACP server test', { timeout: 40_000 }, () => {
expect(newSessionResponse.sessionId).toBeDefined()
})

it('supports legacy authentication/logout ext method', async () => {
const mockFixture = createCodexMockTestFixture();
const codexAcpAgent = mockFixture.getCodexAcpAgent();

const logoutSpy = vi.spyOn(codexAcpAgent, "unstable_logout").mockResolvedValue();

await expect(codexAcpAgent.extMethod("authentication/logout", {})).resolves.toEqual({});
expect(logoutSpy).toHaveBeenCalledWith({});
});

it('prefetches session additional skill roots before thread start', async () => {
const mockFixture = createCodexMockTestFixture();
const codexAcpClient = mockFixture.getCodexAcpClient();
Expand Down Expand Up @@ -565,7 +575,7 @@ describe('ACP server test', { timeout: 40_000 }, () => {

const sessionState: SessionState = createTestSessionState();

const logoutSpy = vi.spyOn(mockFixture.getCodexAcpClient(), "logout").mockResolvedValue({});
const logoutSpy = vi.spyOn(mockFixture.getCodexAcpClient(), "logout").mockResolvedValue();

// @ts-expect-error - exercising private helper
const handled = await codexAcpAgent.availableCommands.handleCommand({ name: "logout", input: null }, sessionState);
Expand Down
3 changes: 3 additions & 0 deletions src/__tests__/CodexACPAgent/initialize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ describe('CodexACPAgent - initialize', () => {
expect(result).toEqual({
protocolVersion: acp.PROTOCOL_VERSION,
agentCapabilities: {
auth: {
logout: {},
},
loadSession: true,
promptCapabilities: {
image: true
Expand Down
Loading