import type { BranchSnapshot } from "./integrations/git/index.js"; import type { PullRequestSnapshot } from "./integrations/github/index.js"; import type { SandboxSession, SandboxAgentClientOptions, SandboxSessionCreateRequest } from "./integrations/sandbox-agent/client.js"; import type { ListEventsRequest, ListPage, ListPageRequest, ProcessCreateRequest, ProcessInfo, ProcessLogFollowQuery, ProcessLogsResponse, ProcessSignalQuery, SessionEvent, SessionRecord, } from "sandbox-agent"; import type { DaytonaClientOptions, DaytonaCreateSandboxOptions, DaytonaPreviewEndpoint, DaytonaSandbox, } from "./integrations/daytona/client.js"; import { validateRemote, ensureCloned, fetch, listRemoteBranches, remoteDefaultBaseRef, revParse, ensureRemoteBranch, diffStatForBranch, conflictsWithMain, } from "./integrations/git/index.js"; import { gitSpiceAvailable, gitSpiceListStack, gitSpiceRebaseBranch, gitSpiceReparentBranch, gitSpiceRestackRepo, gitSpiceRestackSubtree, gitSpiceSyncRepo, gitSpiceTrackBranch, } from "./integrations/git-spice/index.js"; import { listPullRequests, createPr, starRepository } from "./integrations/github/index.js"; import { SandboxAgentClient } from "./integrations/sandbox-agent/client.js"; import { DaytonaClient } from "./integrations/daytona/client.js"; export interface GitDriver { validateRemote(remoteUrl: string): Promise; ensureCloned(remoteUrl: string, targetPath: string): Promise; fetch(repoPath: string): Promise; listRemoteBranches(repoPath: string): Promise; remoteDefaultBaseRef(repoPath: string): Promise; revParse(repoPath: string, ref: string): Promise; ensureRemoteBranch(repoPath: string, branchName: string): Promise; diffStatForBranch(repoPath: string, branchName: string): Promise; conflictsWithMain(repoPath: string, branchName: string): Promise; } export interface StackBranchSnapshot { branchName: string; parentBranch: string | null; } export interface StackDriver { available(repoPath: string): Promise; listStack(repoPath: string): Promise; syncRepo(repoPath: string): Promise; restackRepo(repoPath: string): Promise; restackSubtree(repoPath: string, branchName: string): Promise; rebaseBranch(repoPath: string, branchName: string): Promise; reparentBranch(repoPath: string, branchName: string, parentBranch: string): Promise; trackBranch(repoPath: string, branchName: string, parentBranch: string): Promise; } export interface GithubDriver { listPullRequests(repoPath: string): Promise; createPr(repoPath: string, headBranch: string, title: string, body?: string): Promise<{ number: number; url: string }>; starRepository(repoFullName: string): Promise; } export interface SandboxAgentClientLike { createSession(request: string | SandboxSessionCreateRequest): Promise; sessionStatus(sessionId: string): Promise; listSessions(request?: ListPageRequest): Promise>; listEvents(request: ListEventsRequest): Promise>; createProcess(request: ProcessCreateRequest): Promise; listProcesses(): Promise<{ processes: ProcessInfo[] }>; getProcessLogs(processId: string, query?: ProcessLogFollowQuery): Promise; stopProcess(processId: string, query?: ProcessSignalQuery): Promise; killProcess(processId: string, query?: ProcessSignalQuery): Promise; deleteProcess(processId: string): Promise; sendPrompt(request: { sessionId: string; prompt: string; notification?: boolean }): Promise; cancelSession(sessionId: string): Promise; destroySession(sessionId: string): Promise; } export interface SandboxAgentDriver { createClient(options: SandboxAgentClientOptions): SandboxAgentClientLike; } export interface DaytonaClientLike { createSandbox(options: DaytonaCreateSandboxOptions): Promise; getSandbox(sandboxId: string): Promise; startSandbox(sandboxId: string, timeoutSeconds?: number): Promise; stopSandbox(sandboxId: string, timeoutSeconds?: number): Promise; deleteSandbox(sandboxId: string): Promise; executeCommand(sandboxId: string, command: string): Promise<{ exitCode: number; result: string }>; getPreviewEndpoint(sandboxId: string, port: number): Promise; } export interface DaytonaDriver { createClient(options: DaytonaClientOptions): DaytonaClientLike; } export interface TmuxDriver { setWindowStatus(branchName: string, status: string): number; } export interface BackendDriver { git: GitDriver; stack: StackDriver; github: GithubDriver; sandboxAgent: SandboxAgentDriver; daytona: DaytonaDriver; tmux: TmuxDriver; } export function createDefaultDriver(): BackendDriver { const sandboxAgentClients = new Map(); const daytonaClients = new Map(); return { git: { validateRemote, ensureCloned, fetch, listRemoteBranches, remoteDefaultBaseRef, revParse, ensureRemoteBranch, diffStatForBranch, conflictsWithMain, }, stack: { available: gitSpiceAvailable, listStack: gitSpiceListStack, syncRepo: gitSpiceSyncRepo, restackRepo: gitSpiceRestackRepo, restackSubtree: gitSpiceRestackSubtree, rebaseBranch: gitSpiceRebaseBranch, reparentBranch: gitSpiceReparentBranch, trackBranch: gitSpiceTrackBranch, }, github: { listPullRequests, createPr, starRepository, }, sandboxAgent: { createClient: (opts) => { if (opts.persist) { return new SandboxAgentClient(opts); } const key = `${opts.endpoint}|${opts.token ?? ""}|${opts.agent ?? ""}`; const cached = sandboxAgentClients.get(key); if (cached) { return cached; } const created = new SandboxAgentClient(opts); sandboxAgentClients.set(key, created); return created; }, }, daytona: { createClient: (opts) => { const key = `${opts.apiUrl ?? ""}|${opts.apiKey ?? ""}|${opts.target ?? ""}`; const cached = daytonaClients.get(key); if (cached) { return cached; } const created = new DaytonaClient(opts); daytonaClients.set(key, created); return created; }, }, tmux: { setWindowStatus: () => 0, }, }; }