/** * Proto builders for the modern Cursor CLI exec frames (`ExecServerMessage` * 27-31, 36-38, 40-55). * * Split out of `cursor.ts` because these are pure `create(...)` shapes with no * transport, stream, or block-state coupling: the dispatcher decides *which* * answer a frame gets, this module knows *what* that answer looks like on the * wire. Every builder returns a result whose oneof case is set — an * `ExecClientMessage` carrying a result with an unset oneof is a fake success * the server reads as "the tool ran and produced nothing". */ import type { ToolResultMessage } from "../../types"; import { type ExecuteHookRequest, type ExecuteHookResult, type McpStateExecResult, type McpToolDefinition, type PiBashExecResult, type PiEditExecResult, type PiFindExecResult, type PiGrepExecResult, type PiLsExecResult, type PiReadExecResult, type PiTruncation, type PiWriteExecResult } from "./gen/agent_pb"; /** * The pure arg translation lives in `../cursor-pi-args` so the legacy pi shim * can share it without pulling this module's protobuf graph into the bundled * virtual registry. Re-exported here because this is where the frame builders * and their translation are consumed together. */ export { omitUndefinedArgs, piEscapeRegexLiteral, piGrepSkip, piJoinPath, piLimit, piLsPath, piReadDisplayPath, piReadPath, piReadPathHasRange, piTimeout, } from "../cursor-pi-args"; /** Flatten a tool result's content into the single `output` string the Pi frames carry. */ export declare function piOutputText(toolResult: ToolResultMessage): string; /** * Translate a local tool's truncation summary into `PiTruncation`. * * Two shapes reach here. `read`/`grep` set `details.truncation` * (`TruncationResult`), which carries an explicit `truncated` boolean. `bash` * sets `details.meta.truncation` (`TruncationMeta`), which has **no** such * flag — its presence *is* the signal, and requiring the boolean silently * dropped every Bash truncation, handing Cursor clipped output with no notice * that it was clipped. * * Returns `undefined` when nothing was truncated: the field is `optional` on * every Pi success message, and emitting a zeroed `PiTruncation` would tell the * server the output was trimmed to nothing. */ export declare function piTruncation(toolResult: ToolResultMessage): PiTruncation | undefined; export declare function buildPiReadResult(toolResult: ToolResultMessage): PiReadExecResult; export declare function buildPiReadError(error: string): PiReadExecResult; export declare function buildPiBashResult(toolResult: ToolResultMessage): PiBashExecResult; export declare function buildPiBashError(error: string): PiBashExecResult; /** * `PiEditExecSuccess` requires `diff` and `patch` alongside `output`. The local * `edit` tool reports them under `details`; when it does not, the strings stay * empty rather than being faked from the output text. */ export declare function buildPiEditResult(toolResult: ToolResultMessage): PiEditExecResult; export declare function buildPiEditError(error: string): PiEditExecResult; /** * A refusal is not an execution failure: `PiEditExecResult` models them as * separate variants, and answering a denied call with `error` reads as "the * edit ran and broke", which invites a retry of an operation that was never * permitted. */ export declare function buildPiEditRejected(reason: string): PiEditExecResult; export declare function buildPiWriteResult(toolResult: ToolResultMessage): PiWriteExecResult; export declare function buildPiWriteError(error: string): PiWriteExecResult; /** Same variant split as {@link buildPiEditRejected}. */ export declare function buildPiWriteRejected(reason: string): PiWriteExecResult; export declare function buildPiGrepResult(toolResult: ToolResultMessage): PiGrepExecResult; export declare function buildPiGrepError(error: string): PiGrepExecResult; export declare function buildPiFindResult(toolResult: ToolResultMessage): PiFindExecResult; export declare function buildPiFindError(error: string): PiFindExecResult; export declare function buildPiLsResult(toolResult: ToolResultMessage): PiLsExecResult; export declare function buildPiLsError(error: string): PiLsExecResult; /** * Answer `mcpStateExecArgs` (frame 36) from the catalog already advertised in * `RequestContext.tools`. * * This client hosts no MCP servers of its own: every forwarded tool is a local * pi-agent tool published under a synthetic `providerIdentifier`. Regrouping * the same list keeps the server's view of "which servers exist and what do * they expose" consistent with what it was told at context time, instead of * claiming zero servers while tool calls for them keep arriving. * * `serverIdentifiers` filters the answer when the server asks about specific * servers. `kickOnly` is a restart request — there is nothing to restart, so it * is answered with the same state rather than an error. */ export declare function buildMcpStateResult(tools: McpToolDefinition[], serverIdentifiers: readonly string[]): McpStateExecResult; /** * Build the neutral response for a hook query: the matching response case with * every field unset. * * This client runs no Cursor hooks, and every field of every response variant * is `optional` — so an empty response of the right case means "no hook had * anything to say", which is exactly true. It is NOT the unset-oneof fake * success: the case itself is set, only the payload is empty. * * `ExecuteHookRequest` and `ExecuteHookResponse` are parallel oneofs whose case * names line up, but the two unions are unrelated to the compiler: a `switch` * is what makes each pairing individually type-checked, and it forces a * deliberate branch when a future regen adds a request case. * * Returns `null` for a request case this build does not model, which the * dispatcher answers with `ExecClientThrow` rather than guessing a case. */ export declare function buildNeutralHookResult(request: ExecuteHookRequest | undefined): ExecuteHookResult | null;