cursor-opencode-provider 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +200 -0
  3. package/dist/auth.d.ts +48 -0
  4. package/dist/auth.js +200 -0
  5. package/dist/context/agents.d.ts +8 -0
  6. package/dist/context/agents.js +76 -0
  7. package/dist/context/build.d.ts +12 -0
  8. package/dist/context/build.js +83 -0
  9. package/dist/context/env.d.ts +1 -0
  10. package/dist/context/env.js +29 -0
  11. package/dist/context/git.d.ts +20 -0
  12. package/dist/context/git.js +59 -0
  13. package/dist/context/index.d.ts +2 -0
  14. package/dist/context/index.js +2 -0
  15. package/dist/context/layout.d.ts +17 -0
  16. package/dist/context/layout.js +58 -0
  17. package/dist/context/paths.d.ts +3 -0
  18. package/dist/context/paths.js +11 -0
  19. package/dist/context/plugins.d.ts +8 -0
  20. package/dist/context/plugins.js +50 -0
  21. package/dist/context/rules.d.ts +19 -0
  22. package/dist/context/rules.js +198 -0
  23. package/dist/context/skills.d.ts +11 -0
  24. package/dist/context/skills.js +104 -0
  25. package/dist/index.d.ts +15 -0
  26. package/dist/index.js +18 -0
  27. package/dist/language-model.d.ts +45 -0
  28. package/dist/language-model.js +834 -0
  29. package/dist/models.d.ts +49 -0
  30. package/dist/models.js +136 -0
  31. package/dist/plugin-v2.d.ts +2 -0
  32. package/dist/plugin-v2.js +48 -0
  33. package/dist/plugin.d.ts +2 -0
  34. package/dist/plugin.js +201 -0
  35. package/dist/protocol/blob-store.d.ts +15 -0
  36. package/dist/protocol/blob-store.js +52 -0
  37. package/dist/protocol/checkpoint.d.ts +17 -0
  38. package/dist/protocol/checkpoint.js +29 -0
  39. package/dist/protocol/checksum.d.ts +2 -0
  40. package/dist/protocol/checksum.js +23 -0
  41. package/dist/protocol/client-version.d.ts +5 -0
  42. package/dist/protocol/client-version.js +150 -0
  43. package/dist/protocol/device-id.d.ts +8 -0
  44. package/dist/protocol/device-id.js +121 -0
  45. package/dist/protocol/framing.d.ts +10 -0
  46. package/dist/protocol/framing.js +90 -0
  47. package/dist/protocol/kv.d.ts +24 -0
  48. package/dist/protocol/kv.js +81 -0
  49. package/dist/protocol/messages.d.ts +11 -0
  50. package/dist/protocol/messages.js +676 -0
  51. package/dist/protocol/request.d.ts +36 -0
  52. package/dist/protocol/request.js +90 -0
  53. package/dist/protocol/stream.d.ts +38 -0
  54. package/dist/protocol/stream.js +64 -0
  55. package/dist/protocol/struct.d.ts +19 -0
  56. package/dist/protocol/struct.js +186 -0
  57. package/dist/protocol/thinking.d.ts +15 -0
  58. package/dist/protocol/thinking.js +17 -0
  59. package/dist/protocol/tools.d.ts +94 -0
  60. package/dist/protocol/tools.js +631 -0
  61. package/dist/session.d.ts +81 -0
  62. package/dist/session.js +96 -0
  63. package/dist/shared.d.ts +15 -0
  64. package/dist/shared.js +13 -0
  65. package/dist/transport/connect.d.ts +23 -0
  66. package/dist/transport/connect.js +275 -0
  67. package/package.json +65 -0
@@ -0,0 +1,36 @@
1
+ import { type OpencodeToolDef } from "./tools.js";
2
+ import type { ModelInfo } from "../models.js";
3
+ export type RunRequestInput = {
4
+ text: string;
5
+ modelId: string;
6
+ conversationId: string;
7
+ systemPrompt?: string;
8
+ /**
9
+ * Opaque ConversationStateStructure bytes from the last
10
+ * conversation_checkpoint_update for this conversation_id. When set, echoed
11
+ * as AgentRunRequest.conversation_state (CLI parity). When absent, a seed
12
+ * state with the system prompt (or empty) is built for turn 1.
13
+ */
14
+ conversationState?: Uint8Array;
15
+ parameterValues?: Array<{
16
+ id: string;
17
+ value: string;
18
+ }>;
19
+ maxMode?: boolean;
20
+ messageId?: string;
21
+ availableModels?: ModelInfo[];
22
+ tools?: OpencodeToolDef[];
23
+ /** Prebuilt RequestContext (OpenCode-sourced). */
24
+ requestContext?: Record<string, unknown>;
25
+ };
26
+ /**
27
+ * Build an AgentClientMessage{run_request} for a conversation turn.
28
+ *
29
+ * Live `user_message.text` is the current prompt only — same as Cursor CLI.
30
+ * Cross-turn history is the last server checkpoint re-sent as conversation_state.
31
+ */
32
+ export declare function buildRunRequest(input: RunRequestInput): Uint8Array;
33
+ /**
34
+ * Build a heartbeat message.
35
+ */
36
+ export declare function buildHeartbeat(): Uint8Array;
@@ -0,0 +1,90 @@
1
+ import { encodeMessage, getMessageTypes } from "./messages.js";
2
+ import { toolsToDescriptors } from "./tools.js";
3
+ /**
4
+ * Seed ConversationStateStructure for the first turn (no checkpoint yet).
5
+ *
6
+ * OpenCode needs a system prompt channel; we put it in root_prompt_messages_json
7
+ * as a JSON chat message. After the first checkpoint arrives we stop inventing
8
+ * state and echo the server's opaque structure instead (CLI behavior).
9
+ *
10
+ * We deliberately do NOT use `AgentRunRequest.custom_system_prompt` (#8): that
11
+ * field is the internal `--system-prompt` CLI override and the server rejects
12
+ * it for normal accounts.
13
+ */
14
+ function buildSeedConversationState(systemPrompt) {
15
+ const root = getMessageTypes();
16
+ const type = root.lookupType("ConversationStateStructure");
17
+ const obj = {};
18
+ if (systemPrompt && systemPrompt.length > 0) {
19
+ obj.root_prompt_messages_json = [
20
+ JSON.stringify({ role: "system", content: systemPrompt }),
21
+ ];
22
+ }
23
+ return type.encode(type.fromObject(obj)).finish();
24
+ }
25
+ function buildAvailableModels(models) {
26
+ return models.map((m) => ({
27
+ model_id: m.id,
28
+ parameters: (m.variants ?? []).flatMap((v) => (v.parameterValues ?? []).map((p) => p)),
29
+ }));
30
+ }
31
+ /**
32
+ * Build an AgentClientMessage{run_request} for a conversation turn.
33
+ *
34
+ * Live `user_message.text` is the current prompt only — same as Cursor CLI.
35
+ * Cross-turn history is the last server checkpoint re-sent as conversation_state.
36
+ */
37
+ export function buildRunRequest(input) {
38
+ const msgId = input.messageId ?? crypto.randomUUID();
39
+ // Advertise opencode's tools on the LIVE path: UserMessageAction.request_context
40
+ // (#2). AgentRunRequest.mcp_tools (#4) is prewarm-only / empty on real turns —
41
+ // putting tools only there is why the model fell back to native Grep/Read.
42
+ const tools = input.tools ?? [];
43
+ const mcpTools = tools.length > 0 ? toolsToDescriptors(tools) : [];
44
+ const requestContext = input.requestContext;
45
+ const userMessageAction = {
46
+ user_message: {
47
+ text: input.text,
48
+ message_id: msgId,
49
+ },
50
+ };
51
+ if (requestContext) {
52
+ userMessageAction.request_context = requestContext;
53
+ }
54
+ const conversationState = input.conversationState && input.conversationState.length > 0
55
+ ? input.conversationState
56
+ : buildSeedConversationState(input.systemPrompt);
57
+ const runRequest = {
58
+ conversation_id: input.conversationId,
59
+ action: {
60
+ user_message_action: userMessageAction,
61
+ },
62
+ requested_model: {
63
+ // The provider always selects a concrete model. Cursor's "default"
64
+ // pseudo-model (Auto) is never used here — we send the real id plus the
65
+ // chosen variant's parameter values.
66
+ model_id: input.modelId,
67
+ max_mode: input.maxMode ?? false,
68
+ parameters: input.parameterValues ?? [],
69
+ },
70
+ conversation_state: conversationState,
71
+ // Keep #4 populated too (harmless on real turns; useful for prewarm /
72
+ // older server builds that still read it).
73
+ mcp_tools: { mcp_tools: mcpTools },
74
+ unknown_flag: 0,
75
+ field_12: 0,
76
+ available_models: input.availableModels ? buildAvailableModels(input.availableModels) : [],
77
+ conversation_id_dup: input.conversationId,
78
+ };
79
+ return encodeMessage("AgentClientMessage", {
80
+ run_request: runRequest,
81
+ });
82
+ }
83
+ /**
84
+ * Build a heartbeat message.
85
+ */
86
+ export function buildHeartbeat() {
87
+ return encodeMessage("AgentClientMessage", {
88
+ client_heartbeat: {},
89
+ });
90
+ }
@@ -0,0 +1,38 @@
1
+ export type StreamEvent = {
2
+ type: "text-delta";
3
+ text: string;
4
+ } | {
5
+ type: "reasoning-delta";
6
+ text: string;
7
+ } | {
8
+ type: "finish";
9
+ usage: {
10
+ input: number;
11
+ output: number;
12
+ cacheRead: number;
13
+ cacheWrite: number;
14
+ };
15
+ finishReason: string;
16
+ } | {
17
+ type: "tool-call-started";
18
+ callId: string;
19
+ toolName: string;
20
+ args: string;
21
+ } | {
22
+ type: "tool-call-completed";
23
+ callId: string;
24
+ result: string;
25
+ } | {
26
+ type: "tool-input-delta";
27
+ callId: string;
28
+ delta: string;
29
+ } | {
30
+ type: "heartbeat";
31
+ } | {
32
+ type: "step";
33
+ };
34
+ /**
35
+ * Parse an AgentServerMessage frame payload into a stream event.
36
+ * Returns null for frames that should be skipped.
37
+ */
38
+ export declare function parseInteractionUpdate(payload: Uint8Array): StreamEvent | null;
@@ -0,0 +1,64 @@
1
+ import { decodeMessage } from "./messages.js";
2
+ /**
3
+ * Parse an AgentServerMessage frame payload into a stream event.
4
+ * Returns null for frames that should be skipped.
5
+ */
6
+ export function parseInteractionUpdate(payload) {
7
+ const asm = decodeMessage("AgentServerMessage", payload);
8
+ const iu = asm.interaction_update;
9
+ if (!iu)
10
+ return null;
11
+ if (iu.heartbeat)
12
+ return { type: "heartbeat" };
13
+ if (iu.text_delta) {
14
+ const td = iu.text_delta;
15
+ return { type: "text-delta", text: td.text ?? "" };
16
+ }
17
+ if (iu.thinking_delta) {
18
+ const td = iu.thinking_delta;
19
+ return { type: "reasoning-delta", text: td.text ?? "" };
20
+ }
21
+ if (iu.turn_ended) {
22
+ const te = iu.turn_ended;
23
+ return {
24
+ type: "finish",
25
+ usage: {
26
+ input: te.input_tokens ?? 0,
27
+ output: te.output_tokens ?? 0,
28
+ cacheRead: te.cache_read ?? 0,
29
+ cacheWrite: te.cache_write ?? 0,
30
+ },
31
+ finishReason: "stop",
32
+ };
33
+ }
34
+ if (iu.tool_call_started) {
35
+ const tc = iu.tool_call_started;
36
+ const toolCall = tc.tool_call;
37
+ return {
38
+ type: "tool-call-started",
39
+ callId: tc.call_id ?? "",
40
+ toolName: toolCall?.tool_name ?? "",
41
+ args: toolCall?.args ?? "{}",
42
+ };
43
+ }
44
+ if (iu.tool_call_completed) {
45
+ const tc = iu.tool_call_completed;
46
+ return {
47
+ type: "tool-call-completed",
48
+ callId: tc.call_id ?? "",
49
+ result: tc.result ?? "{}",
50
+ };
51
+ }
52
+ if (iu.partial_tool_call) {
53
+ const ptc = iu.partial_tool_call;
54
+ return {
55
+ type: "tool-input-delta",
56
+ callId: ptc.call_id ?? "",
57
+ delta: ptc.args_text_delta ?? "",
58
+ };
59
+ }
60
+ if (iu.step_started || iu.step_completed) {
61
+ return { type: "step" };
62
+ }
63
+ return null;
64
+ }
@@ -0,0 +1,19 @@
1
+ export type RawField = {
2
+ fn: number;
3
+ wt: number;
4
+ varint: number;
5
+ bytes?: Uint8Array;
6
+ i64?: Uint8Array;
7
+ };
8
+ /** Walk a protobuf message's top-level fields off the raw wire bytes. */
9
+ export declare function readAllFields(b: Uint8Array): RawField[];
10
+ /** Decode a google.protobuf.Value message (bytes) back into a JSON value. */
11
+ export declare function decodeValueToJson(bytes: Uint8Array): unknown;
12
+ /**
13
+ * Decode a `map<string, Value>` field that was captured as repeated map-entry
14
+ * messages (each `{1 key, 2 value}`) into a plain JSON object. Used for
15
+ * `McpArgs.args`, which arrives as repeated field #2 on the wire.
16
+ */
17
+ export declare function decodeStructEntriesToJson(entries: Uint8Array[]): Record<string, unknown>;
18
+ /** Encode an arbitrary JSON value as google.protobuf.Value bytes. */
19
+ export declare function encodeJsonAsValue(v: unknown): Uint8Array;
@@ -0,0 +1,186 @@
1
+ // Minimal encoder for google.protobuf.Value / Struct / ListValue.
2
+ //
3
+ // Cursor's per-turn tool descriptors carry the tool `input_schema` (a JSON
4
+ // Schema object) as a `google.protobuf.Value` whose `struct_value` holds the
5
+ // schema — NOT a JSON string. Verified against a live capture
6
+ // (request_context #7 → McpToolDescriptor #3):
7
+ // 2a 9a07 0a10 0a04 74797065 1208 1a06 6f626a656374 ...
8
+ // = Value{#5 struct_value: Struct{#1 fields: {"type": Value{#3 string "object"}}}}
9
+ //
10
+ // Field numbers (well-known types):
11
+ // Value: 1 null_value, 2 number_value(double), 3 string_value,
12
+ // 4 bool_value, 5 struct_value(Struct), 6 list_value(ListValue)
13
+ // Struct: 1 fields (map<string, Value>) — each entry msg{1 key, 2 value}
14
+ // ListValue: 1 values (repeated Value)
15
+ function writeVarint(out, n) {
16
+ let v = n >>> 0;
17
+ while (v > 0x7f) {
18
+ out.push((v & 0x7f) | 0x80);
19
+ v >>>= 7;
20
+ }
21
+ out.push(v);
22
+ }
23
+ function writeTag(out, field, wire) {
24
+ writeVarint(out, (field << 3) | wire);
25
+ }
26
+ function writeLengthDelimited(out, field, bytes) {
27
+ writeTag(out, field, 2);
28
+ writeVarint(out, bytes.length);
29
+ for (let i = 0; i < bytes.length; i++)
30
+ out.push(bytes[i]);
31
+ }
32
+ function writeString(out, field, str) {
33
+ writeLengthDelimited(out, field, new TextEncoder().encode(str));
34
+ }
35
+ function writeDouble(out, field, num) {
36
+ writeTag(out, field, 1); // 64-bit
37
+ const buf = new ArrayBuffer(8);
38
+ new DataView(buf).setFloat64(0, num, true); // little-endian
39
+ const view = new Uint8Array(buf);
40
+ for (let i = 0; i < 8; i++)
41
+ out.push(view[i]);
42
+ }
43
+ function readVarintAt(b, i) {
44
+ let r = 0, s = 0;
45
+ while (i < b.length) {
46
+ const x = b[i++];
47
+ r |= (x & 0x7f) << s;
48
+ if (!(x & 0x80))
49
+ break;
50
+ s += 7;
51
+ }
52
+ return [r >>> 0, i];
53
+ }
54
+ /** Walk a protobuf message's top-level fields off the raw wire bytes. */
55
+ export function readAllFields(b) {
56
+ let i = 0;
57
+ const out = [];
58
+ while (i < b.length) {
59
+ let key;
60
+ [key, i] = readVarintAt(b, i);
61
+ const fn = key >>> 3, wt = key & 7;
62
+ if (wt === 0) {
63
+ let v;
64
+ [v, i] = readVarintAt(b, i);
65
+ out.push({ fn, wt, varint: v });
66
+ }
67
+ else if (wt === 2) {
68
+ let len;
69
+ [len, i] = readVarintAt(b, i);
70
+ out.push({ fn, wt, varint: 0, bytes: b.subarray(i, i + len) });
71
+ i += len;
72
+ }
73
+ else if (wt === 1) {
74
+ out.push({ fn, wt, varint: 0, i64: b.subarray(i, i + 8) });
75
+ i += 8;
76
+ }
77
+ else if (wt === 5) {
78
+ i += 4; // i32 — not used by Value
79
+ }
80
+ else
81
+ break;
82
+ }
83
+ return out;
84
+ }
85
+ function decodeStructBytes(b) {
86
+ const obj = {};
87
+ for (const f of readAllFields(b)) {
88
+ if (f.fn !== 1 || !f.bytes)
89
+ continue; // Struct.fields (map) entries
90
+ const { key, valBytes } = readMapEntry(f.bytes);
91
+ if (key !== undefined)
92
+ obj[key] = valBytes ? decodeValueToJson(valBytes) : null;
93
+ }
94
+ return obj;
95
+ }
96
+ function decodeListBytes(b) {
97
+ const arr = [];
98
+ for (const f of readAllFields(b)) {
99
+ if (f.fn === 1 && f.bytes)
100
+ arr.push(decodeValueToJson(f.bytes));
101
+ }
102
+ return arr;
103
+ }
104
+ function readMapEntry(b) {
105
+ let key;
106
+ let valBytes;
107
+ for (const e of readAllFields(b)) {
108
+ if (e.fn === 1 && e.bytes)
109
+ key = new TextDecoder().decode(e.bytes);
110
+ else if (e.fn === 2 && e.bytes)
111
+ valBytes = e.bytes;
112
+ }
113
+ return { key, valBytes };
114
+ }
115
+ /** Decode a google.protobuf.Value message (bytes) back into a JSON value. */
116
+ export function decodeValueToJson(bytes) {
117
+ const fs = readAllFields(bytes);
118
+ if (fs.length === 0)
119
+ return null;
120
+ const f = fs[0];
121
+ switch (f.fn) {
122
+ case 1: return null; // null_value
123
+ case 2: return f.i64 ? new DataView(f.i64.buffer, f.i64.byteOffset, 8).getFloat64(0, true) : 0;
124
+ case 3: return f.bytes ? new TextDecoder().decode(f.bytes) : "";
125
+ case 4: return f.varint !== 0;
126
+ case 5: return f.bytes ? decodeStructBytes(f.bytes) : {};
127
+ case 6: return f.bytes ? decodeListBytes(f.bytes) : [];
128
+ default: return null;
129
+ }
130
+ }
131
+ /**
132
+ * Decode a `map<string, Value>` field that was captured as repeated map-entry
133
+ * messages (each `{1 key, 2 value}`) into a plain JSON object. Used for
134
+ * `McpArgs.args`, which arrives as repeated field #2 on the wire.
135
+ */
136
+ export function decodeStructEntriesToJson(entries) {
137
+ const obj = {};
138
+ for (const entry of entries) {
139
+ const { key, valBytes } = readMapEntry(entry);
140
+ if (key !== undefined)
141
+ obj[key] = valBytes ? decodeValueToJson(valBytes) : null;
142
+ }
143
+ return obj;
144
+ }
145
+ /** Encode an arbitrary JSON value as google.protobuf.Value bytes. */
146
+ export function encodeJsonAsValue(v) {
147
+ const out = [];
148
+ if (v === null || v === undefined) {
149
+ writeTag(out, 1, 0); // null_value = 0
150
+ writeVarint(out, 0);
151
+ }
152
+ else if (typeof v === "number") {
153
+ writeDouble(out, 2, v);
154
+ }
155
+ else if (typeof v === "boolean") {
156
+ writeTag(out, 4, 0);
157
+ writeVarint(out, v ? 1 : 0);
158
+ }
159
+ else if (typeof v === "string") {
160
+ writeString(out, 3, v);
161
+ }
162
+ else if (Array.isArray(v)) {
163
+ const lv = [];
164
+ for (const item of v)
165
+ writeLengthDelimited(lv, 1, encodeJsonAsValue(item));
166
+ writeLengthDelimited(out, 6, new Uint8Array(lv));
167
+ }
168
+ else if (typeof v === "object") {
169
+ const st = [];
170
+ for (const [key, val] of Object.entries(v)) {
171
+ if (val === undefined)
172
+ continue;
173
+ const entry = [];
174
+ writeString(entry, 1, key);
175
+ writeLengthDelimited(entry, 2, encodeJsonAsValue(val));
176
+ writeLengthDelimited(st, 1, new Uint8Array(entry));
177
+ }
178
+ writeLengthDelimited(out, 5, new Uint8Array(st));
179
+ }
180
+ else {
181
+ // Fallback: treat as null.
182
+ writeTag(out, 1, 0);
183
+ writeVarint(out, 0);
184
+ }
185
+ return new Uint8Array(out);
186
+ }
@@ -0,0 +1,15 @@
1
+ export type EffortConfig = {
2
+ reasoningEffort?: string;
3
+ maxMode?: boolean;
4
+ };
5
+ /**
6
+ * Build RequestedModel parameter list from a model's variant parameters
7
+ * and optional overrides from providerOptions.
8
+ */
9
+ export declare function buildRequestedModelParams(variantParameters: Array<{
10
+ id: string;
11
+ value: string;
12
+ }>, options?: EffortConfig): Array<{
13
+ id: string;
14
+ value: string;
15
+ }>;
@@ -0,0 +1,17 @@
1
+ // Reasoning effort / max mode → RequestedModel parameters
2
+ /**
3
+ * Build RequestedModel parameter list from a model's variant parameters
4
+ * and optional overrides from providerOptions.
5
+ */
6
+ export function buildRequestedModelParams(variantParameters, options) {
7
+ // Start with variant's parameters as base
8
+ const params = variantParameters.map((p) => ({ ...p }));
9
+ // Override effort if specified
10
+ if (options?.reasoningEffort) {
11
+ const effortIdx = params.findIndex((p) => p.id === "effort" || p.id === "reasoning");
12
+ if (effortIdx >= 0) {
13
+ params[effortIdx] = { ...params[effortIdx], value: options.reasoningEffort };
14
+ }
15
+ }
16
+ return params;
17
+ }
@@ -0,0 +1,94 @@
1
+ export declare const REQUEST_CONTEXT_RESULT_FIELD = 10;
2
+ export type OpencodeToolDef = {
3
+ name: string;
4
+ description?: string;
5
+ inputSchema?: unknown;
6
+ };
7
+ /**
8
+ * Convert opencode's per-turn tool list into Cursor `McpToolDefinition`
9
+ * entries for `request_context.tools` (#7) and `AgentRunRequest.mcp_tools`.
10
+ *
11
+ * opencode tools are already namespaced (e.g. `read`, `grep`, or
12
+ * `<server>_<tool>` for MCP). We advertise them all under a synthetic
13
+ * `opencode` provider so Cursor routes their calls back to us as
14
+ * `mcp_args` on the exec channel. The composite `name` is what the model
15
+ * calls and what comes back as `McpArgs.name`.
16
+ */
17
+ export declare function toolsToDescriptors(tools: OpencodeToolDef[], providerIdentifier?: string): Array<Record<string, unknown>>;
18
+ /**
19
+ * Build the nested McpFileSystemOptions / McpMetaToolOptions shape used by
20
+ * requestContext.#23 / #34. Groups every tool under one synthetic server so
21
+ * Cursor's IDE-style decoder also sees the list.
22
+ */
23
+ export declare function toolsToMcpDescriptors(tools: OpencodeToolDef[], providerIdentifier?: string): Array<Record<string, unknown>>;
24
+ /**
25
+ * @deprecated Prefer `buildRequestContext` from `../context/build.js`.
26
+ * Kept as a sync tools-only fallback for unit tests that don't need collectors.
27
+ */
28
+ export declare function buildLiveRequestContext(tools: OpencodeToolDef[], providerIdentifier?: string): Record<string, unknown>;
29
+ export declare function mapExecServerToToolName(execField: string): string | undefined;
30
+ export declare function mapToolNameToExecField(toolName: string): string | undefined;
31
+ export type ParsedExecRequest = {
32
+ id: number;
33
+ execId: string;
34
+ toolName: string;
35
+ args: Record<string, unknown>;
36
+ /** ExecClientMessage result field to reply with (matches the request variant). */
37
+ resultField: string;
38
+ };
39
+ export declare function parseExecServerMessage(msg: Record<string, unknown>): ParsedExecRequest | undefined;
40
+ /**
41
+ * Remap Cursor exec / MCP arg shapes onto OpenCode's Effect Schema keys.
42
+ * Without this, OpenCode rejects calls with InvalidArgumentsError
43
+ * (e.g. `path` instead of `filePath`, `file_text` instead of `content`).
44
+ */
45
+ export declare function mapCursorArgsToOpencode(toolName: string, raw: Record<string, unknown>, execVariant?: string): {
46
+ toolName: string;
47
+ args: Record<string, unknown>;
48
+ };
49
+ export type ToolResultInput = {
50
+ execId: number;
51
+ /** ExecClientMessage result field (from ParsedExecRequest.resultField). */
52
+ resultField: string;
53
+ output: string;
54
+ error?: string;
55
+ executionTimeMs?: number;
56
+ };
57
+ /**
58
+ * Build one or more ExecClientMessage frames for a tool result.
59
+ * Shell replies are a sequence of ShellStream oneofs under the same id —
60
+ * Start → stdout/stderr → exit — then an ACM #5 stream_close so the server
61
+ * knows the client finished streaming (CLI always sends this; without it
62
+ * shell execs hang on heartbeats forever).
63
+ */
64
+ export declare function buildExecClientMessages(input: ToolResultInput): Uint8Array[];
65
+ /** ACM #5 exec_client_control_message { stream_close { id } }. */
66
+ export declare function buildExecStreamClose(execId: number): Uint8Array;
67
+ /**
68
+ * Map OpenCode tool text into the agent.v1 result oneof for each exec variant.
69
+ * OpenCode returns free-form text; we wrap it in the minimal success shape the
70
+ * server accepts (verified against agent.v1 wire captures).
71
+ */
72
+ export declare function buildTypedExecResult(resultField: string, output: string, error?: string): Record<string, unknown>;
73
+ export declare function buildToolCallPart(execMsg: ParsedExecRequest, sessionId: string): {
74
+ toolCallId: string;
75
+ toolName: string;
76
+ input: string;
77
+ };
78
+ export declare function parseExecIdFromToolCallId(toolCallId: string): {
79
+ sessionId: string;
80
+ execId: number;
81
+ } | undefined;
82
+ /**
83
+ * Find the exec variant field number from the raw (gunzipped) AgentServerMessage
84
+ * payload: peel field #2 (exec_server_message), then return the first
85
+ * message-typed field that isn't id(#1)/exec_id(#15)/span_context(#19).
86
+ * Returns undefined if there is no exec_server_message or no variant set.
87
+ */
88
+ export declare function detectExecVariantField(agentServerPayload: Uint8Array): number | undefined;
89
+ /** Build ExecClientMessage{1:id, <resultField>: empty} as raw bytes. */
90
+ export declare function buildRawEmptyExecReply(execId: number, resultField: number): Uint8Array;
91
+ /**
92
+ * Encode exec #10 request_context_result from a prebuilt RequestContext payload.
93
+ */
94
+ export declare function buildRequestContextResult(execId: number, requestContext: Record<string, unknown>): Uint8Array;