import { Message } from '../config/index.js'; import type { McpServer } from './protocol.js'; import type { AgentSessionOptions } from './session.js'; export interface AcpSession { sessionId: string; workspaceRoot: string; /** In-memory message history for the ACP conversation */ history: Message[]; /** Codeep session name (maps to .codeep/sessions/.json) */ codeepSessionId: string; /** Files added to context via /add */ addedFiles: Map; /** MCP servers the client passed on session/new, load or resume. */ clientMcpServers?: McpServer[]; /** Bumped whenever the thread moves to another conversation (/session * new, /session load, /rewind), so a turn still running can tell. */ conversation?: number; } /** * How the agent runs for the current prompt: the session mode's permission * prompts and the client's fs and terminal. The server builds it once per * prompt so a slash command that runs the agent gets what a plain prompt * gets. */ export type AcpAgentRunOptions = Pick & { /** Ask the user a yes/no question. Unset: the mode runs without asking. */ confirm?: (message: string) => Promise; /** * Auto mode's answer to the agent's permission gate: yes to everything * except a write to a file that decides what runs later, which is asked * about in every mode. A command that runs the agent passes it in place of * the missing `onRequestPermission`, because the agent refuses those writes * outright when it has nobody to ask — so without this, /go and a skill's * agent step could not touch `.git/config` at all in auto mode, while a * plain prompt could after a confirmation. * * Kept under its own key rather than set on `onRequestPermission`, which * this file reads as "this session asks the user" when it decides whether * to gate a skill's shell lines. Auto mode runs those without asking, as * that mode promises. */ onAutoModePermission?: AgentSessionOptions['onRequestPermission']; }; export interface CommandResult { /** true if the input was a slash command (even if it failed) */ handled: boolean; /** Markdown text to stream back to the client */ response: string; /** If true, server should stream response chunks as they arrive (skills) */ streaming?: boolean; /** If true, server should re-send configOptions to client (provider/model changed) */ configOptionsChanged?: boolean; } /** * Ensure workspace has a .codeep folder, initialise it as a project if needed, * and load the most recent session (or start a new one). * * Returns the welcome message to stream back to the client. */ export declare function initWorkspace(workspaceRoot: string, fresh?: boolean): { codeepSessionId: string; history: Message[]; welcomeText: string; }; /** * Restore a previously saved ACP session by its Zed sessionId. * Falls back to initWorkspace if the session cannot be found on disk. */ export declare function loadWorkspace(workspaceRoot: string, acpSessionId: string): { codeepSessionId: string; history: Message[]; welcomeText: string; }; /** * Try to handle a slash command. Async because skills and diff/review * need to call the AI API or run shell commands. * * onChunk is called for streaming output (skills). For simple commands * the full response is returned in CommandResult.response. * * agentRun carries the options commands that run the agent (/go, custom * commands, skill agent steps) must run it with. */ export declare function handleCommand(input: string, session: AcpSession, onChunk: (text: string) => void, abortSignal?: AbortSignal, agentRun?: AcpAgentRunOptions): Promise; /** * Split a skill's shell line into the simple commands it runs, each as * argv, so every one of them can go through the execute_command policy. * `&&`, `||`, `;`, `|` and newlines separate commands. Redirections stay * with their command as arguments (`2>&1`, `>`, `out.txt`), so the policy * sees where output goes. Returns null for a line it cannot read with * certainty — unbalanced quotes, subshells, background jobs, heredocs, and * anything the shell would expand first (`$`, backticks, globs, braces, a * leading `~`) — which the caller must refuse. So a `$` or backtick in the * result is always plain text. * * Exported for unit testing (see commands.slash.test.ts). */ export declare function splitShellCommands(line: string, windows?: boolean): string[][] | null;