cursor-opencode-provider 0.7.3 → 0.7.4
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/dist/language-model.js
CHANGED
|
@@ -3406,7 +3406,7 @@ export function buildOpenCodeInteractionGuidance(tools, isCompaction, workspaceR
|
|
|
3406
3406
|
instructions.push(shell
|
|
3407
3407
|
? `- OpenCode \`execute\` is Code Mode JavaScript (\`code\`); it is not a shell. For OS commands, call OpenCode ${shell}. Do not pass \`command\` to \`execute\`.`
|
|
3408
3408
|
: "- OpenCode `execute` is Code Mode JavaScript (`code`); it is not a shell. Do not pass `command` to `execute`.");
|
|
3409
|
-
instructions.push("-
|
|
3409
|
+
instructions.push("- Call tools named in the direct list by their own names, even when a server instruction says to reach them through `execute`. Use `execute` only for tools that appear in the host Code Mode catalog and are absent from that list. Use the exact paths and signatures from that catalog or its `search` function, and call `execute` with `{ code }`.");
|
|
3410
3410
|
}
|
|
3411
3411
|
if (names.has("task") || names.has("subagent")) {
|
|
3412
3412
|
const target = names.has("task") ? "`task`" : "`subagent`";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ToolDraft } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* OpenCode 2 puts an MCP server's tools in Code Mode unless that server's
|
|
4
|
+
* config sets `codemode: false` (`packages/schema/src/mcp.ts`, applied in
|
|
5
|
+
* `packages/core/src/tool/mcp.ts`). Only `options.codemode === false` joins
|
|
6
|
+
* the AI SDK catalog (`packages/core/src/tool.ts`). Cursor can call a tool
|
|
7
|
+
* only when it is in that catalog.
|
|
8
|
+
*
|
|
9
|
+
* `config.codemode` is also the remote-connection switch: while it is not
|
|
10
|
+
* false, OpenCode appends `?codemode=false` so servers that bundle their own
|
|
11
|
+
* Code Mode return individual tools (`packages/core/src/mcp/client.ts`).
|
|
12
|
+
* This module therefore leaves server config alone and clears the tool option
|
|
13
|
+
* instead. An explicit server `codemode: true` stays in Code Mode. OpenCode's
|
|
14
|
+
* own namespaced tools (the `opencode` namespace) are not MCP servers and are
|
|
15
|
+
* left alone.
|
|
16
|
+
*
|
|
17
|
+
* The tool registry is location-scoped, so this placement is shared by every
|
|
18
|
+
* provider in the process. `"codemode": true` on a server is the per-server
|
|
19
|
+
* way to keep that server inside `execute`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mcpServerNamespace(server: string): string;
|
|
22
|
+
export declare function rememberDirectMcpNamespaces(target: Set<string>, servers: readonly (readonly [string, {
|
|
23
|
+
readonly codemode?: boolean;
|
|
24
|
+
}])[]): void;
|
|
25
|
+
/** Move tools from the recorded MCP namespaces onto the direct catalog. */
|
|
26
|
+
export declare function exposeDirectMcpTools(editor: ToolDraft, namespaces: ReadonlySet<string>): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode 2 puts an MCP server's tools in Code Mode unless that server's
|
|
3
|
+
* config sets `codemode: false` (`packages/schema/src/mcp.ts`, applied in
|
|
4
|
+
* `packages/core/src/tool/mcp.ts`). Only `options.codemode === false` joins
|
|
5
|
+
* the AI SDK catalog (`packages/core/src/tool.ts`). Cursor can call a tool
|
|
6
|
+
* only when it is in that catalog.
|
|
7
|
+
*
|
|
8
|
+
* `config.codemode` is also the remote-connection switch: while it is not
|
|
9
|
+
* false, OpenCode appends `?codemode=false` so servers that bundle their own
|
|
10
|
+
* Code Mode return individual tools (`packages/core/src/mcp/client.ts`).
|
|
11
|
+
* This module therefore leaves server config alone and clears the tool option
|
|
12
|
+
* instead. An explicit server `codemode: true` stays in Code Mode. OpenCode's
|
|
13
|
+
* own namespaced tools (the `opencode` namespace) are not MCP servers and are
|
|
14
|
+
* left alone.
|
|
15
|
+
*
|
|
16
|
+
* The tool registry is location-scoped, so this placement is shared by every
|
|
17
|
+
* provider in the process. `"codemode": true` on a server is the per-server
|
|
18
|
+
* way to keep that server inside `execute`.
|
|
19
|
+
*/
|
|
20
|
+
export function mcpServerNamespace(server) {
|
|
21
|
+
return server.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
22
|
+
}
|
|
23
|
+
export function rememberDirectMcpNamespaces(target, servers) {
|
|
24
|
+
target.clear();
|
|
25
|
+
// The editor exposes normalized namespaces, not server ownership. Keep
|
|
26
|
+
// ambiguous namespaces in their host-selected placement: otherwise a server
|
|
27
|
+
// named `opencode` moves builtins too, or `my.docs` overrides an explicit
|
|
28
|
+
// Code Mode choice on `my_docs`. Exclusions must win regardless of order.
|
|
29
|
+
const excluded = new Set(["opencode"]);
|
|
30
|
+
for (const [name, config] of servers) {
|
|
31
|
+
const namespace = mcpServerNamespace(name);
|
|
32
|
+
if (config.codemode === true)
|
|
33
|
+
excluded.add(namespace);
|
|
34
|
+
else
|
|
35
|
+
target.add(namespace);
|
|
36
|
+
}
|
|
37
|
+
for (const namespace of excluded)
|
|
38
|
+
target.delete(namespace);
|
|
39
|
+
}
|
|
40
|
+
/** Move tools from the recorded MCP namespaces onto the direct catalog. */
|
|
41
|
+
export function exposeDirectMcpTools(editor, namespaces) {
|
|
42
|
+
if (namespaces.size === 0 || !editor.list || !editor.update)
|
|
43
|
+
return;
|
|
44
|
+
for (const tool of editor.list()) {
|
|
45
|
+
const namespace = tool.options?.namespace;
|
|
46
|
+
if (!namespace || !namespaces.has(namespace))
|
|
47
|
+
continue;
|
|
48
|
+
if (tool.options?.codemode === false)
|
|
49
|
+
continue;
|
|
50
|
+
editor.update(tool.id, (draft) => {
|
|
51
|
+
const options = {};
|
|
52
|
+
if (draft.options?.namespace !== undefined)
|
|
53
|
+
options.namespace = draft.options.namespace;
|
|
54
|
+
if (draft.options?.permission !== undefined)
|
|
55
|
+
options.permission = draft.options.permission;
|
|
56
|
+
options.codemode = false;
|
|
57
|
+
draft.options = options;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -223,6 +223,15 @@ export type ToolDraft = {
|
|
|
223
223
|
list?(): readonly (ToolDefinition & {
|
|
224
224
|
readonly id: string;
|
|
225
225
|
})[];
|
|
226
|
+
/** Host ToolEditor.update — missing ids are ignored. */
|
|
227
|
+
update?(id: string, update: (tool: {
|
|
228
|
+
options?: {
|
|
229
|
+
namespace?: string;
|
|
230
|
+
permission?: string;
|
|
231
|
+
codemode?: boolean;
|
|
232
|
+
pinned?: boolean;
|
|
233
|
+
};
|
|
234
|
+
}) => void): void;
|
|
226
235
|
};
|
|
227
236
|
export type ToolHookBaseFields = {
|
|
228
237
|
readonly tool: string;
|
|
@@ -368,6 +377,20 @@ export type WebSearchDomain = {
|
|
|
368
377
|
readonly transform: Transform<WebSearchEditor>;
|
|
369
378
|
readonly reload: () => Promise<void>;
|
|
370
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* MCP config reader this plugin uses. Server `codemode` is observed and not
|
|
382
|
+
* written: writing it also changes the remote raw-tool URL. The host
|
|
383
|
+
* `MCPEditor` is a superset.
|
|
384
|
+
*/
|
|
385
|
+
export type McpServerConfig = {
|
|
386
|
+
readonly codemode?: boolean;
|
|
387
|
+
};
|
|
388
|
+
export type McpEditor = {
|
|
389
|
+
list(): readonly (readonly [string, McpServerConfig])[];
|
|
390
|
+
};
|
|
391
|
+
export type McpDomain = {
|
|
392
|
+
readonly transform: Transform<McpEditor>;
|
|
393
|
+
};
|
|
371
394
|
export type PluginLocation = {
|
|
372
395
|
readonly directory: string;
|
|
373
396
|
};
|
|
@@ -381,6 +404,7 @@ export type PluginContext = {
|
|
|
381
404
|
readonly location?: PluginLocation;
|
|
382
405
|
readonly shell?: ShellDomain;
|
|
383
406
|
readonly websearch?: WebSearchDomain;
|
|
407
|
+
readonly mcp?: McpDomain;
|
|
384
408
|
};
|
|
385
409
|
export type Cleanup = () => Promise<void> | void;
|
|
386
410
|
export type Plugin2 = {
|
package/dist/plugin-opencode2.js
CHANGED
|
@@ -8,6 +8,7 @@ import { fetchOpenCodeWebSearchText, parseExaWebSearchResults, } from "./web-too
|
|
|
8
8
|
import { captureCursorShellResult, cursorShellEnvForCommand, prepareCursorShellArgs, releaseCursorShellEnv, sanitizeRegisteredCursorShellOutput, } from "./shell-timeout.js";
|
|
9
9
|
import { applyCursorProviderInventory, CURSOR_INTEGRATION_ID } from "./opencode2/catalog.js";
|
|
10
10
|
import { applyCursorIntegration, resolveCursorAccessToken } from "./opencode2/integration.js";
|
|
11
|
+
import { exposeDirectMcpTools, rememberDirectMcpNamespaces } from "./opencode2/mcp-direct.js";
|
|
11
12
|
import { registerTodoTools } from "./opencode2/todo-tools.js";
|
|
12
13
|
import { OPENCODE_2_TOOL_DIALECT } from "./protocol/tools.js";
|
|
13
14
|
import { clearSessionTodos } from "./todo-store.js";
|
|
@@ -250,12 +251,25 @@ const plugin = {
|
|
|
250
251
|
});
|
|
251
252
|
}));
|
|
252
253
|
}
|
|
254
|
+
// Namespaces whose tools belong on the direct catalog. Filled by the MCP
|
|
255
|
+
// transform (config is not written) and read when tool transforms replay,
|
|
256
|
+
// including after a later MCP discovery reload.
|
|
257
|
+
const directMcpNamespaces = new Set();
|
|
258
|
+
if (ctx.mcp) {
|
|
259
|
+
await track(ctx.mcp.transform((editor) => {
|
|
260
|
+
rememberDirectMcpNamespaces(directMcpNamespaces, editor.list());
|
|
261
|
+
}));
|
|
262
|
+
}
|
|
253
263
|
await track(ctx.tool.transform((draft) => {
|
|
254
264
|
// OpenCode 2 dropped host todowrite/todoread. Off by default
|
|
255
265
|
// (`CURSOR_OPENCODE2_TODOS=1`/`true` force-enables). When on, register
|
|
256
266
|
// them as direct catalog tools (`codemode: false` + output schema) if
|
|
257
267
|
// the host does not already own those names. When off, register none.
|
|
258
268
|
registerTodoTools(draft);
|
|
269
|
+
// MCP tools default into Code Mode. Move every server that did not
|
|
270
|
+
// explicitly opt in onto the direct catalog so Cursor can call them
|
|
271
|
+
// by name. See `opencode2/mcp-direct.ts`.
|
|
272
|
+
exposeDirectMcpTools(draft, directMcpNamespaces);
|
|
259
273
|
}));
|
|
260
274
|
// ── Shell timeout wrapper ────────────────────────────────
|
|
261
275
|
await track(ctx.tool.hook("execute.before", (event) => {
|