cursor-opencode-provider 0.5.0 → 0.6.0
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.
- package/README.md +18 -13
- package/dist/context/agents.d.ts +1 -1
- package/dist/context/agents.js +1 -1
- package/dist/context/auth-store.js +2 -2
- package/dist/context/build.d.ts +3 -1
- package/dist/context/build.js +4 -2
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/paths.d.ts +34 -53
- package/dist/context/paths.js +54 -118
- package/dist/context/rules.js +1 -1
- package/dist/image-save-tool.d.ts +19 -0
- package/dist/image-save-tool.js +25 -0
- package/dist/image-save.d.ts +58 -0
- package/dist/image-save.js +189 -0
- package/dist/image-staging.d.ts +59 -0
- package/dist/image-staging.js +91 -0
- package/dist/index.d.ts +1 -1
- package/dist/language-model.d.ts +3 -2
- package/dist/language-model.js +572 -34
- package/dist/plan-execution-kickoff.d.ts +55 -0
- package/dist/plan-execution-kickoff.js +162 -0
- package/dist/plugin-opencode2.js +52 -3
- package/dist/plugin-v2.d.ts +11 -9
- package/dist/plugin-v2.js +6 -13
- package/dist/plugin.d.ts +9 -0
- package/dist/plugin.js +61 -5
- package/dist/pricing-data.d.ts +16 -4
- package/dist/pricing-data.js +16 -4
- package/dist/protocol/ask-question.d.ts +133 -0
- package/dist/protocol/ask-question.js +320 -0
- package/dist/protocol/create-plan.d.ts +141 -0
- package/dist/protocol/create-plan.js +373 -0
- package/dist/protocol/generate-image.d.ts +54 -0
- package/dist/protocol/generate-image.js +101 -0
- package/dist/protocol/interactions.d.ts +110 -8
- package/dist/protocol/interactions.js +295 -35
- package/dist/protocol/messages.js +118 -6
- package/dist/protocol/switch-mode.d.ts +178 -0
- package/dist/protocol/switch-mode.js +417 -0
- package/dist/protocol/tool-call-bridge.js +10 -5
- package/dist/protocol/tools.d.ts +27 -11
- package/dist/protocol/tools.js +95 -41
- package/dist/usage.d.ts +2 -2
- package/dist/usage.js +2 -2
- package/dist/web-search-tool.d.ts +22 -26
- package/dist/web-search-tool.js +25 -15
- package/package.json +7 -4
package/dist/protocol/tools.d.ts
CHANGED
|
@@ -71,9 +71,9 @@ export type HostSubagentDefinition = {
|
|
|
71
71
|
description?: string;
|
|
72
72
|
};
|
|
73
73
|
export type HostSubagentCatalog = {
|
|
74
|
-
executor?: "task"
|
|
74
|
+
executor?: "task";
|
|
75
75
|
agents: HostSubagentDefinition[];
|
|
76
|
-
/** True when the
|
|
76
|
+
/** True when the OpenCode task tool supplied its complete, permission-filtered catalog. */
|
|
77
77
|
complete: boolean;
|
|
78
78
|
};
|
|
79
79
|
/** Extract the current host's permission-filtered Task/Actor recipient catalog. */
|
|
@@ -151,7 +151,28 @@ export declare function parseExecServerMessage(msg: Record<string, unknown>): Pa
|
|
|
151
151
|
export declare function mapCursorArgsToOpencode(toolName: string, raw: Record<string, unknown>, execVariant?: string): {
|
|
152
152
|
toolName: string;
|
|
153
153
|
args: Record<string, unknown>;
|
|
154
|
+
binaryBytes?: Uint8Array;
|
|
154
155
|
};
|
|
156
|
+
/**
|
|
157
|
+
* Decode `WriteArgs.file_bytes`. `encoding_hint` names the file's original
|
|
158
|
+
* encoding; OpenCode's `write` takes a string, so an unknown encoding label
|
|
159
|
+
* falls back to UTF-8 rather than dropping the write.
|
|
160
|
+
*
|
|
161
|
+
* Returns undefined when the bytes are not text in that encoding. A non-fatal
|
|
162
|
+
* decode would replace every undecodable sequence with U+FFFD and hand the host
|
|
163
|
+
* a corrupted file that still reports success, so binary content must take the
|
|
164
|
+
* byte-preserving path instead (see `isBinaryWriteRequest`).
|
|
165
|
+
*/
|
|
166
|
+
export declare function decodeWriteBytes(bytes: Uint8Array, encodingHint?: string): string | undefined;
|
|
167
|
+
/**
|
|
168
|
+
* True when a parsed `write` request carries bytes that are not text. Such a
|
|
169
|
+
* request cannot go to OpenCode's `write` tool at all — it takes a string, and
|
|
170
|
+
* additionally BOM-splits, diffs, and runs `Format.file()` on what it writes.
|
|
171
|
+
*/
|
|
172
|
+
export declare function binaryWritePayload(parsed: ParsedExecRequest): {
|
|
173
|
+
path: string;
|
|
174
|
+
data: Uint8Array;
|
|
175
|
+
} | undefined;
|
|
155
176
|
/**
|
|
156
177
|
* Map Cursor McpArgs back to the OpenCode tool id.
|
|
157
178
|
* Prefers provider_identifier + bare tool_name (github + create_pull_request
|
|
@@ -162,15 +183,10 @@ export declare function mcpRealToolName(mcpArgs: Record<string, unknown>, defaul
|
|
|
162
183
|
* A read target addressed by URI scheme rather than by local filesystem path.
|
|
163
184
|
*
|
|
164
185
|
* Cursor's LocalReadExecutor only ever reads local files, so this provider
|
|
165
|
-
* mirrors its pre-execution validation.
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* (`tools.xdev`, on by default). Resolving those against the workspace root
|
|
170
|
-
* mangles `xd://everything_echo` into `<root>/xd:/everything_echo`, which stats
|
|
171
|
-
* as missing and gets refused as `file_not_found` — so the host's read tool is
|
|
172
|
-
* never called and every xd://-mounted MCP tool is unreachable through this
|
|
173
|
-
* provider. Such targets must be forwarded untouched and left to the host.
|
|
186
|
+
* mirrors its pre-execution validation. An advertised host read tool may also
|
|
187
|
+
* accept URLs or internal URI schemes. Resolving those against the workspace
|
|
188
|
+
* root mangles the URI and produces a false `file_not_found`, so URI targets
|
|
189
|
+
* are forwarded untouched and left to the advertised executor.
|
|
174
190
|
*
|
|
175
191
|
* Requires a scheme of two or more characters followed by `://`, so Windows
|
|
176
192
|
* drive letters (`C:\src`, `C:/src`) stay local paths.
|
package/dist/protocol/tools.js
CHANGED
|
@@ -299,6 +299,10 @@ const PRESERVE_EMPTY_STRING_KEYS = new Set([
|
|
|
299
299
|
"file_text",
|
|
300
300
|
"fileText",
|
|
301
301
|
"stream_content",
|
|
302
|
+
// Some advertised edit schemas use a single textual `input` payload. Preserve
|
|
303
|
+
// an empty value so the executor reports the real edit error rather than a
|
|
304
|
+
// misleading missing-property error.
|
|
305
|
+
"input",
|
|
302
306
|
"oldString",
|
|
303
307
|
"old_string",
|
|
304
308
|
"newString",
|
|
@@ -396,18 +400,16 @@ function subagentTypeEnumValues(schema) {
|
|
|
396
400
|
}
|
|
397
401
|
/** Extract the current host's permission-filtered Task/Actor recipient catalog. */
|
|
398
402
|
export function extractHostSubagentCatalog(tools) {
|
|
399
|
-
const executorTool = tools.find((tool) => tool.name === "
|
|
400
|
-
tools.find((tool) => tool.name === "task");
|
|
403
|
+
const executorTool = tools.find((tool) => tool.name === "task");
|
|
401
404
|
if (!executorTool)
|
|
402
405
|
return { agents: [], complete: true };
|
|
403
406
|
const described = parseSubagentDescriptionCatalog(executorTool.description);
|
|
404
407
|
const enumNames = subagentTypeEnumValues(executorTool.inputSchema);
|
|
405
408
|
const descriptions = new Map(described.agents.map((agent) => [agent.name, agent.description]));
|
|
406
|
-
//
|
|
407
|
-
// rather than every non-primary agent), so structured names are authoritative.
|
|
409
|
+
// A structured subagent_type enum is stricter than prose, so it is authoritative.
|
|
408
410
|
const names = new Set(enumNames.length > 0 ? enumNames : described.agents.map((agent) => agent.name));
|
|
409
411
|
return {
|
|
410
|
-
executor:
|
|
412
|
+
executor: "task",
|
|
411
413
|
agents: [...names].map((name) => ({
|
|
412
414
|
name,
|
|
413
415
|
...(descriptions.get(name) ? { description: descriptions.get(name) } : {}),
|
|
@@ -467,9 +469,9 @@ export function remapNativeSubagentForCatalog(parsed, advertisedToolNames, catal
|
|
|
467
469
|
if (parsed.resultField !== "subagent_result" || parsed.toolName !== "task")
|
|
468
470
|
return;
|
|
469
471
|
const advertised = new Set(advertisedToolNames);
|
|
470
|
-
|
|
471
|
-
if (!executor)
|
|
472
|
+
if (!advertised.has("task"))
|
|
472
473
|
return;
|
|
474
|
+
const executor = "task";
|
|
473
475
|
const description = str(parsed.args.description) ?? "";
|
|
474
476
|
const prompt = str(parsed.args.prompt) ?? "";
|
|
475
477
|
const cursorSubagentType = str(parsed.resultMetadata?.cursor_subagent_type) ??
|
|
@@ -484,24 +486,12 @@ export function remapNativeSubagentForCatalog(parsed, advertisedToolNames, catal
|
|
|
484
486
|
}
|
|
485
487
|
const resumeAgentId = str(parsed.args.task_id);
|
|
486
488
|
parsed.toolName = executor;
|
|
487
|
-
if (executor === "task") {
|
|
488
|
-
parsed.args = {
|
|
489
|
-
description,
|
|
490
|
-
prompt,
|
|
491
|
-
subagent_type: subagentType,
|
|
492
|
-
...(resumeAgentId ? { task_id: resumeAgentId } : {}),
|
|
493
|
-
...(parsed.args.background === true ? { background: true } : {}),
|
|
494
|
-
};
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
489
|
parsed.args = {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
...(resumeAgentId ? { actor_id: resumeAgentId } : {}),
|
|
504
|
-
},
|
|
490
|
+
description,
|
|
491
|
+
prompt,
|
|
492
|
+
subagent_type: subagentType,
|
|
493
|
+
...(resumeAgentId ? { task_id: resumeAgentId } : {}),
|
|
494
|
+
...(parsed.args.background === true ? { background: true } : {}),
|
|
505
495
|
};
|
|
506
496
|
}
|
|
507
497
|
/** Matches Cursor's own pre-write read threshold (`local-exec` 52428800). */
|
|
@@ -682,6 +672,12 @@ export function remapCorrelatedEditWriteForCatalog(parsed, advertisedToolNames,
|
|
|
682
672
|
export function remapEditToolsForCatalog(parsed, advertisedToolNames, workspaceRoot) {
|
|
683
673
|
if (parsed.toolName !== "write" && parsed.toolName !== "edit")
|
|
684
674
|
return;
|
|
675
|
+
// `apply_patch` envelopes are text. A binary write has no patch form at all,
|
|
676
|
+
// so it must stay a write and reach the byte-preserving path — converting it
|
|
677
|
+
// here would drop the bytes and report a patch-translation failure instead of
|
|
678
|
+
// the image Cursor asked to save.
|
|
679
|
+
if (binaryWritePayload(parsed))
|
|
680
|
+
return;
|
|
685
681
|
const advertised = new Set(advertisedToolNames);
|
|
686
682
|
if (advertised.has(parsed.toolName) || !advertised.has(APPLY_PATCH_TOOL))
|
|
687
683
|
return;
|
|
@@ -940,7 +936,19 @@ export function parseExecServerMessage(msg) {
|
|
|
940
936
|
toolName: mapped.toolName,
|
|
941
937
|
args: mapped.args,
|
|
942
938
|
resultField,
|
|
943
|
-
...(resultMetadata
|
|
939
|
+
...(resultMetadata || mapped.binaryBytes
|
|
940
|
+
? {
|
|
941
|
+
resultMetadata: {
|
|
942
|
+
...resultMetadata,
|
|
943
|
+
...(mapped.binaryBytes
|
|
944
|
+
? {
|
|
945
|
+
binaryWriteBytes: mapped.binaryBytes,
|
|
946
|
+
path: str(rawArgs.path) ?? str(rawArgs.file_path) ?? "",
|
|
947
|
+
}
|
|
948
|
+
: {}),
|
|
949
|
+
},
|
|
950
|
+
}
|
|
951
|
+
: {}),
|
|
944
952
|
};
|
|
945
953
|
}
|
|
946
954
|
function shellStreamResultMetadata(raw) {
|
|
@@ -1020,14 +1028,31 @@ export function mapCursorArgsToOpencode(toolName, raw, execVariant) {
|
|
|
1020
1028
|
// non-empty and only falls back to `file_text`; mirror that order so a
|
|
1021
1029
|
// byte-encoded write is not silently seen as empty content.
|
|
1022
1030
|
const bytes = bytesValue(cleaned.file_bytes) ?? bytesValue(cleaned.fileBytes);
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1031
|
+
let content;
|
|
1032
|
+
if (bytes !== undefined) {
|
|
1033
|
+
content = decodeWriteBytes(bytes, str(cleaned.encoding_hint) ?? str(cleaned.encodingHint));
|
|
1034
|
+
if (content === undefined) {
|
|
1035
|
+
// Binary. Surface the raw bytes to the caller instead of a lossy
|
|
1036
|
+
// decode; `binaryWritePayload` picks them up after parsing.
|
|
1037
|
+
return { toolName: "write", args, binaryBytes: bytes };
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
else {
|
|
1041
|
+
content = stringValue(cleaned.content)
|
|
1042
|
+
?? stringValue(cleaned.file_text)
|
|
1043
|
+
?? stringValue(cleaned.fileText);
|
|
1044
|
+
}
|
|
1026
1045
|
if (content !== undefined)
|
|
1027
1046
|
args.content = content;
|
|
1028
1047
|
return { toolName: "write", args };
|
|
1029
1048
|
}
|
|
1030
1049
|
case "edit": {
|
|
1050
|
+
// Preserve an opaque textual edit payload when the advertised executor
|
|
1051
|
+
// accepts that generic shape; rebuilding only OpenCode's targeted fields
|
|
1052
|
+
// would silently turn a valid call into `{}`.
|
|
1053
|
+
if (typeof cleaned.input === "string") {
|
|
1054
|
+
return { toolName: "edit", args: { input: cleaned.input } };
|
|
1055
|
+
}
|
|
1031
1056
|
const args = {};
|
|
1032
1057
|
const filePath = str(cleaned.filePath) ?? str(cleaned.path) ?? str(cleaned.file_path);
|
|
1033
1058
|
if (filePath)
|
|
@@ -1105,22 +1130,56 @@ function bytesValue(v) {
|
|
|
1105
1130
|
}
|
|
1106
1131
|
return undefined;
|
|
1107
1132
|
}
|
|
1133
|
+
/** UTF-16/32 embed NUL bytes in ordinary text; 8-bit encodings do not. */
|
|
1134
|
+
const WIDE_TEXT_ENCODING = /^utf-?(16|32)/;
|
|
1108
1135
|
/**
|
|
1109
1136
|
* Decode `WriteArgs.file_bytes`. `encoding_hint` names the file's original
|
|
1110
|
-
* encoding; OpenCode's `write` takes a string, so
|
|
1137
|
+
* encoding; OpenCode's `write` takes a string, so an unknown encoding label
|
|
1111
1138
|
* falls back to UTF-8 rather than dropping the write.
|
|
1139
|
+
*
|
|
1140
|
+
* Returns undefined when the bytes are not text in that encoding. A non-fatal
|
|
1141
|
+
* decode would replace every undecodable sequence with U+FFFD and hand the host
|
|
1142
|
+
* a corrupted file that still reports success, so binary content must take the
|
|
1143
|
+
* byte-preserving path instead (see `isBinaryWriteRequest`).
|
|
1112
1144
|
*/
|
|
1113
|
-
function decodeWriteBytes(bytes, encodingHint) {
|
|
1145
|
+
export function decodeWriteBytes(bytes, encodingHint) {
|
|
1114
1146
|
const encoding = encodingHint?.trim().toLowerCase().replace(/[_ ]/g, "-");
|
|
1147
|
+
let decoder;
|
|
1148
|
+
let label = "utf-8";
|
|
1115
1149
|
if (encoding && encoding !== "utf-8" && encoding !== "utf8") {
|
|
1116
1150
|
try {
|
|
1117
|
-
|
|
1151
|
+
decoder = new TextDecoder(encoding, { fatal: true });
|
|
1152
|
+
label = encoding;
|
|
1118
1153
|
}
|
|
1119
1154
|
catch {
|
|
1120
1155
|
trace(`write: unsupported encoding_hint ${JSON.stringify(encodingHint)} — decoding as utf-8`);
|
|
1121
1156
|
}
|
|
1122
1157
|
}
|
|
1123
|
-
|
|
1158
|
+
if (!decoder)
|
|
1159
|
+
decoder = new TextDecoder("utf-8", { fatal: true });
|
|
1160
|
+
// Single-byte encodings decode any byte sequence without error, so a decode
|
|
1161
|
+
// that cannot fail is not on its own evidence of text.
|
|
1162
|
+
if (!WIDE_TEXT_ENCODING.test(label) && bytes.includes(0))
|
|
1163
|
+
return undefined;
|
|
1164
|
+
try {
|
|
1165
|
+
return decoder.decode(bytes);
|
|
1166
|
+
}
|
|
1167
|
+
catch {
|
|
1168
|
+
return undefined;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* True when a parsed `write` request carries bytes that are not text. Such a
|
|
1173
|
+
* request cannot go to OpenCode's `write` tool at all — it takes a string, and
|
|
1174
|
+
* additionally BOM-splits, diffs, and runs `Format.file()` on what it writes.
|
|
1175
|
+
*/
|
|
1176
|
+
export function binaryWritePayload(parsed) {
|
|
1177
|
+
if (parsed.toolName !== "write")
|
|
1178
|
+
return undefined;
|
|
1179
|
+
const data = parsed.resultMetadata?.binaryWriteBytes;
|
|
1180
|
+
if (!(data instanceof Uint8Array))
|
|
1181
|
+
return undefined;
|
|
1182
|
+
return { path: str(parsed.resultMetadata?.path) ?? "", data };
|
|
1124
1183
|
}
|
|
1125
1184
|
function num(v) {
|
|
1126
1185
|
if (typeof v === "number" && Number.isFinite(v))
|
|
@@ -1203,15 +1262,10 @@ function untildify(input) {
|
|
|
1203
1262
|
* A read target addressed by URI scheme rather than by local filesystem path.
|
|
1204
1263
|
*
|
|
1205
1264
|
* Cursor's LocalReadExecutor only ever reads local files, so this provider
|
|
1206
|
-
* mirrors its pre-execution validation.
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1210
|
-
* (`tools.xdev`, on by default). Resolving those against the workspace root
|
|
1211
|
-
* mangles `xd://everything_echo` into `<root>/xd:/everything_echo`, which stats
|
|
1212
|
-
* as missing and gets refused as `file_not_found` — so the host's read tool is
|
|
1213
|
-
* never called and every xd://-mounted MCP tool is unreachable through this
|
|
1214
|
-
* provider. Such targets must be forwarded untouched and left to the host.
|
|
1265
|
+
* mirrors its pre-execution validation. An advertised host read tool may also
|
|
1266
|
+
* accept URLs or internal URI schemes. Resolving those against the workspace
|
|
1267
|
+
* root mangles the URI and produces a false `file_not_found`, so URI targets
|
|
1268
|
+
* are forwarded untouched and left to the advertised executor.
|
|
1215
1269
|
*
|
|
1216
1270
|
* Requires a scheme of two or more characters followed by `://`, so Windows
|
|
1217
1271
|
* drive letters (`C:\src`, `C:/src`) stay local paths.
|
package/dist/usage.d.ts
CHANGED
|
@@ -49,8 +49,8 @@ export declare function formatCursorCacheDiagnostics(counters: CursorUsageCounte
|
|
|
49
49
|
export declare function formatTurnUsageValidation(counters: CursorUsageCounters, usage: LanguageModelV3Usage, tokenDetails?: CursorConversationTokenDetails, contextSource?: CursorContextUsageSource): string;
|
|
50
50
|
/** OpenCode requires a usage object at every step boundary. */
|
|
51
51
|
export declare function emptyLanguageModelV3Usage(): LanguageModelV3Usage;
|
|
52
|
-
/**
|
|
53
|
-
export declare function
|
|
52
|
+
/** Project nested V3 usage into the common flat AI-SDK counter shape. */
|
|
53
|
+
export declare function flatUsageFromV3(usage: LanguageModelV3Usage): {
|
|
54
54
|
inputTokens: number;
|
|
55
55
|
outputTokens: number;
|
|
56
56
|
reasoningTokens: number;
|
package/dist/usage.js
CHANGED
|
@@ -217,8 +217,8 @@ export function emptyLanguageModelV3Usage() {
|
|
|
217
217
|
reasoningTokens: 0,
|
|
218
218
|
});
|
|
219
219
|
}
|
|
220
|
-
/**
|
|
221
|
-
export function
|
|
220
|
+
/** Project nested V3 usage into the common flat AI-SDK counter shape. */
|
|
221
|
+
export function flatUsageFromV3(usage) {
|
|
222
222
|
const input = usage.inputTokens;
|
|
223
223
|
const output = usage.outputTokens;
|
|
224
224
|
const noCache = input.noCache ?? 0;
|
|
@@ -1,33 +1,29 @@
|
|
|
1
|
+
import { executeOpenCodeWebSearch } from "./web-tools.js";
|
|
2
|
+
type ToolFactory = {
|
|
3
|
+
tool: (input: Record<string, unknown>) => Record<string, unknown>;
|
|
4
|
+
schema: {
|
|
5
|
+
string: () => any;
|
|
6
|
+
number: () => any;
|
|
7
|
+
enum: (values: readonly string[]) => any;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
/** Build the classic OpenCode web-search tool with the host's own Zod helper. */
|
|
11
|
+
export declare function createOpenCodeWebSearchTool(factory: ToolFactory): Record<string, unknown>;
|
|
1
12
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* implementation in that module. 2.0's package root exports no `tool`, so
|
|
7
|
-
* importing it from a module on the 2.0 graph would throw during plugin load.
|
|
8
|
-
* Only `plugin.ts` (classic hooks) may import this file.
|
|
13
|
+
* Host-neutral JSON-schema fallback when the classic helper is unavailable.
|
|
14
|
+
* OpenCode's legacy schema adapter marks every listed property required, so
|
|
15
|
+
* expose only the genuinely required query rather than turning four optional
|
|
16
|
+
* tuning fields into mandatory inputs.
|
|
9
17
|
*/
|
|
10
18
|
export declare const openCodeWebSearchTool: {
|
|
11
19
|
description: string;
|
|
12
20
|
args: {
|
|
13
|
-
query:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
preferred: "preferred";
|
|
18
|
-
}>>;
|
|
19
|
-
type: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
20
|
-
fast: "fast";
|
|
21
|
-
auto: "auto";
|
|
22
|
-
deep: "deep";
|
|
23
|
-
}>>;
|
|
24
|
-
contextMaxCharacters: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
21
|
+
query: {
|
|
22
|
+
type: string;
|
|
23
|
+
description: string;
|
|
24
|
+
};
|
|
25
25
|
};
|
|
26
|
-
execute
|
|
27
|
-
query: string;
|
|
28
|
-
numResults?: number | undefined;
|
|
29
|
-
livecrawl?: "fallback" | "preferred" | undefined;
|
|
30
|
-
type?: "fast" | "auto" | "deep" | undefined;
|
|
31
|
-
contextMaxCharacters?: number | undefined;
|
|
32
|
-
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
26
|
+
execute: typeof executeOpenCodeWebSearch;
|
|
33
27
|
};
|
|
28
|
+
export type { ToolFactory as OpenCodeToolFactory };
|
|
29
|
+
export declare function createOpenCodeWebSearchToolFromPlugin(pluginModule: any): Record<string, unknown>;
|
package/dist/web-search-tool.js
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
|
-
import { tool } from "@opencode-ai/plugin";
|
|
2
1
|
import { executeOpenCodeWebSearch } from "./web-tools.js";
|
|
2
|
+
/** Build the classic OpenCode web-search tool with the host's own Zod helper. */
|
|
3
|
+
export function createOpenCodeWebSearchTool(factory) {
|
|
4
|
+
const schema = factory.schema;
|
|
5
|
+
return factory.tool({
|
|
6
|
+
description: "Search the web for current information using OpenCode's web search backend.",
|
|
7
|
+
args: {
|
|
8
|
+
query: schema.string().describe("Web search query"),
|
|
9
|
+
numResults: schema.number().int().min(1).max(20).optional(),
|
|
10
|
+
livecrawl: schema.enum(["fallback", "preferred"]).optional(),
|
|
11
|
+
type: schema.enum(["auto", "fast", "deep"]).optional(),
|
|
12
|
+
contextMaxCharacters: schema.number().int().positive().optional(),
|
|
13
|
+
},
|
|
14
|
+
execute: executeOpenCodeWebSearch,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
3
17
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* implementation in that module. 2.0's package root exports no `tool`, so
|
|
9
|
-
* importing it from a module on the 2.0 graph would throw during plugin load.
|
|
10
|
-
* Only `plugin.ts` (classic hooks) may import this file.
|
|
18
|
+
* Host-neutral JSON-schema fallback when the classic helper is unavailable.
|
|
19
|
+
* OpenCode's legacy schema adapter marks every listed property required, so
|
|
20
|
+
* expose only the genuinely required query rather than turning four optional
|
|
21
|
+
* tuning fields into mandatory inputs.
|
|
11
22
|
*/
|
|
12
|
-
export const openCodeWebSearchTool =
|
|
23
|
+
export const openCodeWebSearchTool = {
|
|
13
24
|
description: "Search the web for current information using OpenCode's web search backend.",
|
|
14
25
|
args: {
|
|
15
|
-
query:
|
|
16
|
-
numResults: tool.schema.number().int().min(1).max(20).optional(),
|
|
17
|
-
livecrawl: tool.schema.enum(["fallback", "preferred"]).optional(),
|
|
18
|
-
type: tool.schema.enum(["auto", "fast", "deep"]).optional(),
|
|
19
|
-
contextMaxCharacters: tool.schema.number().int().positive().optional(),
|
|
26
|
+
query: { type: "string", description: "Web search query" },
|
|
20
27
|
},
|
|
21
28
|
execute: executeOpenCodeWebSearch,
|
|
22
|
-
}
|
|
29
|
+
};
|
|
30
|
+
export function createOpenCodeWebSearchToolFromPlugin(pluginModule) {
|
|
31
|
+
return createOpenCodeWebSearchTool({ tool: pluginModule.tool, schema: pluginModule.tool.schema });
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursor-opencode-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Use Cursor subscription models from OpenCode via Cursor's Connect-RPC agent protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -55,6 +55,10 @@
|
|
|
55
55
|
"./auth": {
|
|
56
56
|
"types": "./dist/auth.d.ts",
|
|
57
57
|
"import": "./dist/auth.js"
|
|
58
|
+
},
|
|
59
|
+
"./image-save": {
|
|
60
|
+
"types": "./dist/image-save.d.ts",
|
|
61
|
+
"import": "./dist/image-save.js"
|
|
58
62
|
}
|
|
59
63
|
},
|
|
60
64
|
"files": [
|
|
@@ -80,11 +84,10 @@
|
|
|
80
84
|
"protobufjs": "^7.6.5"
|
|
81
85
|
},
|
|
82
86
|
"peerDependencies": {
|
|
83
|
-
"@opencode-ai/plugin": "^1.17.13"
|
|
84
|
-
"@opencode-compat/profile": ">=0.1.0"
|
|
87
|
+
"@opencode-ai/plugin": "^1.17.13"
|
|
85
88
|
},
|
|
86
89
|
"peerDependenciesMeta": {
|
|
87
|
-
"@opencode-
|
|
90
|
+
"@opencode-ai/plugin": {
|
|
88
91
|
"optional": true
|
|
89
92
|
}
|
|
90
93
|
},
|