feat(acp): add experimental ACP support

Co-authored-by: Jonathan Taylor <visionik@pobox.com>
This commit is contained in:
Peter Steinberger
2026-01-18 08:02:42 +00:00
parent efaa73f543
commit de3b68740a
25 changed files with 1528 additions and 29 deletions

93
src/acp/session.ts Normal file
View File

@@ -0,0 +1,93 @@
import { randomUUID } from "node:crypto";
import type { AcpSession } from "./types.js";
export type AcpSessionStore = {
createSession: (params: {
sessionKey: string;
cwd: string;
sessionId?: string;
}) => AcpSession;
getSession: (sessionId: string) => AcpSession | undefined;
getSessionByRunId: (runId: string) => AcpSession | undefined;
setActiveRun: (sessionId: string, runId: string, abortController: AbortController) => void;
clearActiveRun: (sessionId: string) => void;
cancelActiveRun: (sessionId: string) => boolean;
clearAllSessionsForTest: () => void;
};
export function createInMemorySessionStore(): AcpSessionStore {
const sessions = new Map<string, AcpSession>();
const runIdToSessionId = new Map<string, string>();
const createSession: AcpSessionStore["createSession"] = (params) => {
const sessionId = params.sessionId ?? randomUUID();
const session: AcpSession = {
sessionId,
sessionKey: params.sessionKey,
cwd: params.cwd,
createdAt: Date.now(),
abortController: null,
activeRunId: null,
};
sessions.set(sessionId, session);
return session;
};
const getSession: AcpSessionStore["getSession"] = (sessionId) => sessions.get(sessionId);
const getSessionByRunId: AcpSessionStore["getSessionByRunId"] = (runId) => {
const sessionId = runIdToSessionId.get(runId);
return sessionId ? sessions.get(sessionId) : undefined;
};
const setActiveRun: AcpSessionStore["setActiveRun"] = (
sessionId,
runId,
abortController,
) => {
const session = sessions.get(sessionId);
if (!session) return;
session.activeRunId = runId;
session.abortController = abortController;
runIdToSessionId.set(runId, sessionId);
};
const clearActiveRun: AcpSessionStore["clearActiveRun"] = (sessionId) => {
const session = sessions.get(sessionId);
if (!session) return;
if (session.activeRunId) runIdToSessionId.delete(session.activeRunId);
session.activeRunId = null;
session.abortController = null;
};
const cancelActiveRun: AcpSessionStore["cancelActiveRun"] = (sessionId) => {
const session = sessions.get(sessionId);
if (!session?.abortController) return false;
session.abortController.abort();
if (session.activeRunId) runIdToSessionId.delete(session.activeRunId);
session.abortController = null;
session.activeRunId = null;
return true;
};
const clearAllSessionsForTest: AcpSessionStore["clearAllSessionsForTest"] = () => {
for (const session of sessions.values()) {
session.abortController?.abort();
}
sessions.clear();
runIdToSessionId.clear();
};
return {
createSession,
getSession,
getSessionByRunId,
setActiveRun,
clearActiveRun,
cancelActiveRun,
clearAllSessionsForTest,
};
}
export const defaultAcpSessionStore = createInMemorySessionStore();