cursor-opencode-provider 0.8.0 → 0.8.3
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/CHANGELOG.md +174 -0
- package/README.md +230 -44
- package/SECURITY.md +60 -12
- package/dist/activity.d.ts +73 -1
- package/dist/activity.js +231 -5
- package/dist/agent-url.js +37 -9
- package/dist/auth-renewal.d.ts +1 -1
- package/dist/auth-renewal.js +58 -26
- package/dist/billing.d.ts +105 -0
- package/dist/billing.js +212 -0
- package/dist/classic-tool-results.d.ts +1 -0
- package/dist/classic-tool-results.js +42 -0
- package/dist/context/build.d.ts +23 -4
- package/dist/context/build.js +65 -10
- package/dist/context/dynamic-catalog.js +6 -1
- package/dist/context/env.js +27 -3
- package/dist/context/epoch.js +9 -5
- package/dist/context/frozen.js +6 -2
- package/dist/context/git.d.ts +5 -2
- package/dist/context/git.js +17 -7
- package/dist/context/index.d.ts +2 -0
- package/dist/context/index.js +2 -0
- package/dist/context/paths.d.ts +45 -18
- package/dist/context/paths.js +72 -22
- package/dist/context/skills-bridge.d.ts +22 -0
- package/dist/context/skills-bridge.js +20 -0
- package/dist/context/skills.d.ts +34 -0
- package/dist/context/skills.js +211 -0
- package/dist/debug.js +13 -2
- package/dist/early-tool-rows.d.ts +60 -0
- package/dist/early-tool-rows.js +96 -0
- package/dist/errors.d.ts +49 -7
- package/dist/errors.js +163 -8
- package/dist/host-agent-mode.d.ts +53 -4
- package/dist/host-agent-mode.js +117 -13
- package/dist/host-interrupt.d.ts +12 -0
- package/dist/host-interrupt.js +18 -0
- package/dist/host-plan-file.d.ts +28 -0
- package/dist/host-plan-file.js +76 -0
- package/dist/host-steer.d.ts +71 -0
- package/dist/host-steer.js +232 -0
- package/dist/image-input.d.ts +18 -0
- package/dist/image-input.js +122 -30
- package/dist/image-save.d.ts +10 -2
- package/dist/image-save.js +33 -21
- package/dist/index.d.ts +2 -2
- package/dist/language-model.d.ts +149 -30
- package/dist/language-model.js +3127 -673
- package/dist/lost-request.d.ts +39 -0
- package/dist/lost-request.js +111 -0
- package/dist/model-config.d.ts +12 -1
- package/dist/model-config.js +78 -30
- package/dist/models.d.ts +26 -3
- package/dist/models.js +101 -45
- package/dist/opencode2/catalog.d.ts +1 -0
- package/dist/opencode2/catalog.js +2 -0
- package/dist/opencode2/image-save-tool.d.ts +8 -0
- package/dist/opencode2/image-save-tool.js +84 -0
- package/dist/opencode2/tool-results.d.ts +18 -0
- package/dist/opencode2/tool-results.js +66 -0
- package/dist/opencode2/types.d.ts +15 -0
- package/dist/parallel-step.d.ts +65 -0
- package/dist/parallel-step.js +102 -0
- package/dist/plugin-opencode2.js +233 -65
- package/dist/plugin.js +97 -23
- package/dist/pricing-data.d.ts +40 -3
- package/dist/pricing-data.js +40 -3
- package/dist/pricing.d.ts +1 -1
- package/dist/pricing.js +7 -4
- package/dist/process-shared.d.ts +14 -0
- package/dist/process-shared.js +18 -0
- package/dist/protocol/apply-patch.d.ts +25 -13
- package/dist/protocol/apply-patch.js +79 -30
- package/dist/protocol/ask-question.d.ts +12 -1
- package/dist/protocol/ask-question.js +77 -3
- package/dist/protocol/blob-store.d.ts +5 -1
- package/dist/protocol/blob-store.js +10 -6
- package/dist/protocol/client-version.js +6 -4
- package/dist/protocol/conversation-cache-header.d.ts +23 -0
- package/dist/protocol/conversation-cache-header.js +149 -0
- package/dist/protocol/conversation-persistence.d.ts +27 -1
- package/dist/protocol/conversation-persistence.js +628 -126
- package/dist/protocol/conversation-state.d.ts +8 -1
- package/dist/protocol/conversation-state.js +28 -7
- package/dist/protocol/create-plan.d.ts +47 -25
- package/dist/protocol/create-plan.js +33 -23
- package/dist/protocol/host-notes.d.ts +31 -0
- package/dist/protocol/host-notes.js +85 -0
- package/dist/protocol/interactions.d.ts +26 -17
- package/dist/protocol/interactions.js +80 -31
- package/dist/protocol/messages.js +164 -21
- package/dist/protocol/request.d.ts +40 -19
- package/dist/protocol/request.js +55 -28
- package/dist/protocol/sent-history-images.d.ts +49 -0
- package/dist/protocol/sent-history-images.js +102 -0
- package/dist/protocol/switch-mode.d.ts +66 -27
- package/dist/protocol/switch-mode.js +147 -73
- package/dist/protocol/token-details.d.ts +2 -0
- package/dist/protocol/token-details.js +11 -1
- package/dist/protocol/tool-call-bridge.d.ts +6 -0
- package/dist/protocol/tool-call-bridge.js +24 -0
- package/dist/protocol/tools.d.ts +90 -9
- package/dist/protocol/tools.js +543 -151
- package/dist/protocol/turn-provenance.d.ts +19 -4
- package/dist/protocol/turn-provenance.js +77 -20
- package/dist/replay-safety.d.ts +22 -4
- package/dist/replay-safety.js +86 -27
- package/dist/retry-budget.d.ts +21 -0
- package/dist/retry-budget.js +94 -0
- package/dist/runtime-files.d.ts +23 -0
- package/dist/runtime-files.js +581 -0
- package/dist/session.d.ts +129 -10
- package/dist/session.js +198 -35
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js +1 -1
- package/dist/shell-timeout.d.ts +54 -10
- package/dist/shell-timeout.js +362 -92
- package/dist/stream-write.d.ts +20 -0
- package/dist/stream-write.js +87 -0
- package/dist/terminal-runner.d.ts +15 -0
- package/dist/terminal-runner.js +528 -0
- package/dist/todo-store.d.ts +2 -0
- package/dist/todo-store.js +19 -0
- package/dist/transport/connect.d.ts +10 -1
- package/dist/transport/connect.js +124 -27
- package/dist/usage.d.ts +37 -17
- package/dist/usage.js +85 -34
- package/package.json +5 -3
- package/dist/plan-execution-kickoff.d.ts +0 -57
- package/dist/plan-execution-kickoff.js +0 -186
- package/dist/protocol/thinking.d.ts +0 -15
- package/dist/protocol/thinking.js +0 -17
package/dist/plugin.js
CHANGED
|
@@ -4,16 +4,18 @@ import { pollForTokens, exchangeApiKey, isExpiringSoon, generatePkceParams, gene
|
|
|
4
4
|
import { renewSessionIfDue, resolveApiKeyToken, } from "./auth-renewal.js";
|
|
5
5
|
import { CursorAuthError } from "./errors.js";
|
|
6
6
|
import { errorMessage, trace } from "./debug.js";
|
|
7
|
+
import { normalizeClassicInterruptedResults } from "./classic-tool-results.js";
|
|
7
8
|
import { readCache, discoverModels, isCacheFresh } from "./models.js";
|
|
8
9
|
import { modelsToConfig } from "./model-config.js";
|
|
9
10
|
import { loadClassicTools } from "./classic-tools.js";
|
|
10
11
|
import { opencodeGlobalCacheDir } from "./context/paths.js";
|
|
11
12
|
import { readStoredAuth } from "./context/auth-store.js";
|
|
12
13
|
import { resolveAgentUrl } from "./agent-url.js";
|
|
13
|
-
import { captureCursorShellResult, cursorShellEnvForCall, cursorShellOriginalCommand, prepareCursorShellArgs, releaseCursorShellEnv, sanitizeRegisteredCursorShellOutput, setCursorShellPath, } from "./shell-timeout.js";
|
|
14
|
-
import { sessionActivity } from "./activity.js";
|
|
15
|
-
import { createPlanExecutionKickoffText, setPlanExecutionKickoff, } from "./plan-execution-kickoff.js";
|
|
14
|
+
import { captureCursorShellResult, cursorShellEnvForCall, cursorShellOriginalCommand, cursorShellTimeoutMs, prepareCursorShellArgs, releaseCursorShellEnv, sanitizeRegisteredCursorShellOutput, setCursorShellPath, resolveCursorShellPath, } from "./shell-timeout.js";
|
|
15
|
+
import { applyHostPromptEvent, applyHostToolEvent, sessionActivity } from "./activity.js";
|
|
16
16
|
import { dispatchHostEventBridge } from "./host-event-bridge.js";
|
|
17
|
+
import { createPromptHostAgentModeSwitch, setHostAgentModeSwitch } from "./host-agent-mode.js";
|
|
18
|
+
import { isHostPlanFileResolved, resolveHostPlanFile } from "./host-plan-file.js";
|
|
17
19
|
const MODULE_URL = new URL("./index.js", import.meta.url).href;
|
|
18
20
|
/**
|
|
19
21
|
* Raw `crsr_` key behind an API-key login: under `metadata.apiKey` (saved at
|
|
@@ -41,29 +43,63 @@ function isSameCredential(latest, started) {
|
|
|
41
43
|
}
|
|
42
44
|
return false;
|
|
43
45
|
}
|
|
46
|
+
/** Names of the host's own user-selectable primary agents, from `app.agents()`. */
|
|
47
|
+
function primaryAgentNames(response) {
|
|
48
|
+
const list = Array.isArray(response)
|
|
49
|
+
? response
|
|
50
|
+
: Array.isArray(response?.data)
|
|
51
|
+
? response.data
|
|
52
|
+
: undefined;
|
|
53
|
+
if (!list)
|
|
54
|
+
return undefined;
|
|
55
|
+
const names = new Set();
|
|
56
|
+
for (const item of list) {
|
|
57
|
+
if (typeof item?.name !== "string" || item.mode === "subagent" || item.hidden === true)
|
|
58
|
+
continue;
|
|
59
|
+
names.add(item.name);
|
|
60
|
+
}
|
|
61
|
+
return names;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Install the OpenCode 1.x host-agent switch. Returns the agent-list refresh,
|
|
65
|
+
* which the caller runs once the host serves requests: the list is read from
|
|
66
|
+
* the host's own API, and a failed read leaves SwitchMode provider-owned.
|
|
67
|
+
*/
|
|
68
|
+
function installPromptHostAgentModeSwitch(input, sessionClient, promptAsync) {
|
|
69
|
+
const app = input.client?.app;
|
|
70
|
+
const agents = app?.agents;
|
|
71
|
+
// Nothing to install; a switch another entrypoint installed stays in place.
|
|
72
|
+
if (typeof promptAsync !== "function" || typeof agents !== "function")
|
|
73
|
+
return undefined;
|
|
74
|
+
let primary;
|
|
75
|
+
const refresh = () => agents.call(app)
|
|
76
|
+
.then((response) => { primary = primaryAgentNames(response) ?? primary; })
|
|
77
|
+
.catch((error) => trace(`host-agent-mode: agent list unavailable: ${errorMessage(error)}`));
|
|
78
|
+
const { apply, accepts } = createPromptHostAgentModeSwitch(async ({ sessionID, agent, text }) => {
|
|
79
|
+
await promptAsync.call(sessionClient, {
|
|
80
|
+
path: { id: sessionID },
|
|
81
|
+
body: { agent, parts: [{ type: "text", text, synthetic: true }] },
|
|
82
|
+
});
|
|
83
|
+
void refresh();
|
|
84
|
+
}, () => primary);
|
|
85
|
+
setHostAgentModeSwitch(apply, { resumesTurn: true, accepts });
|
|
86
|
+
return refresh;
|
|
87
|
+
}
|
|
44
88
|
export async function CursorPlugin(input) {
|
|
45
89
|
const cacheDir = opencodeGlobalCacheDir();
|
|
46
90
|
const apiBaseURL = cursorApiBaseURL();
|
|
47
91
|
const classicTools = await loadClassicTools();
|
|
48
|
-
// Install the OpenCode plan-exit-shaped kickoff only when the OpenCode client
|
|
49
|
-
// exposes that structural API. Without it, no synthetic kickoff is registered.
|
|
50
92
|
const sessionClient = input.client?.session;
|
|
51
93
|
const promptAsync = sessionClient?.promptAsync;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
synthetic: true,
|
|
62
|
-
}],
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
: undefined);
|
|
94
|
+
// Cursor SwitchMode without an advertised plan_enter selects the host's
|
|
95
|
+
// primary agent the OpenCode 1.x way once its Run has ended. The OpenCode 2.0
|
|
96
|
+
// entrypoint replaces this with `session.switchAgent` in its own setup().
|
|
97
|
+
const refreshHostAgents = installPromptHostAgentModeSwitch(input, sessionClient, promptAsync);
|
|
98
|
+
let hostAgentsLoaded;
|
|
99
|
+
const sessionGet = sessionClient?.get;
|
|
100
|
+
const getSession = typeof sessionGet === "function"
|
|
101
|
+
? (sessionID) => sessionGet.call(sessionClient, { path: { id: sessionID } })
|
|
102
|
+
: undefined;
|
|
67
103
|
let lastPersistAttempt;
|
|
68
104
|
async function persistAuth(body) {
|
|
69
105
|
await input.client.auth.set({
|
|
@@ -215,6 +251,9 @@ export async function CursorPlugin(input) {
|
|
|
215
251
|
cursor_image_save: classicTools.imageSave,
|
|
216
252
|
},
|
|
217
253
|
async event({ event }) {
|
|
254
|
+
// The SDK's event union predates these prompt events; read them untyped.
|
|
255
|
+
applyHostPromptEvent(sessionActivity, event.type, event.properties);
|
|
256
|
+
applyHostToolEvent(sessionActivity, event.type, event.properties);
|
|
218
257
|
switch (event.type) {
|
|
219
258
|
case "session.created":
|
|
220
259
|
sessionActivity.linkSession(event.properties.info.id, event.properties.info.parentID);
|
|
@@ -231,6 +270,11 @@ export async function CursorPlugin(input) {
|
|
|
231
270
|
break;
|
|
232
271
|
case "message.part.updated":
|
|
233
272
|
sessionActivity.recordActivity(event.properties.part.sessionID);
|
|
273
|
+
// Rejection/abort can stop the classic host before a continuation or
|
|
274
|
+
// execute.after. Its persisted tool state is still authoritative.
|
|
275
|
+
if (event.properties.part.type === "tool" && event.properties.part.state.status === "error") {
|
|
276
|
+
releaseCursorShellEnv(event.properties.part.callID);
|
|
277
|
+
}
|
|
234
278
|
break;
|
|
235
279
|
}
|
|
236
280
|
await dispatchHostEventBridge({
|
|
@@ -240,13 +284,22 @@ export async function CursorPlugin(input) {
|
|
|
240
284
|
serverUrl: input.serverUrl,
|
|
241
285
|
});
|
|
242
286
|
},
|
|
287
|
+
async "experimental.chat.messages.transform"(_hookInput, output) {
|
|
288
|
+
// The classic host retains the original array and discards hook output.
|
|
289
|
+
// Replace entries with request-only clones, preserving array identity.
|
|
290
|
+
const normalized = normalizeClassicInterruptedResults(output.messages);
|
|
291
|
+
for (let index = 0; index < output.messages.length; index++)
|
|
292
|
+
output.messages[index] = normalized[index];
|
|
293
|
+
},
|
|
243
294
|
async "tool.execute.before"(hookInput, output) {
|
|
244
295
|
if (hookInput.tool !== "bash")
|
|
245
296
|
return;
|
|
246
297
|
// bash/zsh retain the original display/permission command and wrap via
|
|
247
|
-
// shell.env. sh/dash
|
|
298
|
+
// shell.env. sh/dash disclose the managed launcher inline because their
|
|
248
299
|
// non-interactive `-c` path ignores BASH_ENV / ZDOTDIR.
|
|
249
|
-
prepareCursorShellArgs(hookInput.callID, output.args
|
|
300
|
+
prepareCursorShellArgs(hookInput.callID, output.args, {
|
|
301
|
+
shellPath: resolveCursorShellPath(undefined, input.directory),
|
|
302
|
+
});
|
|
250
303
|
},
|
|
251
304
|
async "shell.env"(hookInput, output) {
|
|
252
305
|
const env = cursorShellEnvForCall(hookInput.callID);
|
|
@@ -267,6 +320,11 @@ export async function CursorPlugin(input) {
|
|
|
267
320
|
if (typeof metadata.output === "string") {
|
|
268
321
|
metadata.output = sanitizeRegisteredCursorShellOutput(hookInput.callID, metadata.output);
|
|
269
322
|
}
|
|
323
|
+
// The stored output keeps only a display notice, and the saved
|
|
324
|
+
// outcome does not survive consumption or a restart.
|
|
325
|
+
const timeoutMs = cursorShellTimeoutMs(hookInput.callID);
|
|
326
|
+
if (timeoutMs !== undefined)
|
|
327
|
+
metadata.cursorShellTimeoutMs = timeoutMs;
|
|
270
328
|
}
|
|
271
329
|
}
|
|
272
330
|
finally {
|
|
@@ -280,6 +338,22 @@ export async function CursorPlugin(input) {
|
|
|
280
338
|
// Carry the canonical OpenCode id so an incompatible Cursor checkpoint
|
|
281
339
|
// is rotated instead of resuming the prior agent's prompt.
|
|
282
340
|
output.options[CURSOR_HOST_AGENT_OPTION] = hookInput.agent;
|
|
341
|
+
// First Cursor request: the host now serves its API, so read its agents
|
|
342
|
+
// before any Run can raise SwitchMode. Concurrent first requests share
|
|
343
|
+
// the one read; later requests find it settled.
|
|
344
|
+
hostAgentsLoaded ??= refreshHostAgents?.();
|
|
345
|
+
await hostAgentsLoaded;
|
|
346
|
+
// Know the session's own plan file (OpenCode's `Session.plan`) before the
|
|
347
|
+
// Run starts, so CreatePlan records the plan where the plan agent and
|
|
348
|
+
// plan_exit read it. It is fixed per session, so resolve it once.
|
|
349
|
+
if (hookInput.agent !== "compaction" && getSession && !isHostPlanFileResolved(hookInput.sessionID)) {
|
|
350
|
+
await resolveHostPlanFile({
|
|
351
|
+
sessionID: hookInput.sessionID,
|
|
352
|
+
getSession,
|
|
353
|
+
worktree: input.worktree || input.project?.worktree,
|
|
354
|
+
vcs: !!input.project?.vcs,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
283
357
|
// OpenCode's compaction pipeline invokes the LLM with agent="compaction".
|
|
284
358
|
// Carry that stable runtime fact into LanguageModelV3 providerOptions so
|
|
285
359
|
// the provider never has to guess from an empty tool list.
|
|
@@ -288,7 +362,7 @@ export async function CursorPlugin(input) {
|
|
|
288
362
|
}
|
|
289
363
|
},
|
|
290
364
|
async config(cfg) {
|
|
291
|
-
setCursorShellPath(cfg.shell);
|
|
365
|
+
setCursorShellPath(cfg.shell, input.directory);
|
|
292
366
|
cfg.provider ??= {};
|
|
293
367
|
const models = await loadModels();
|
|
294
368
|
const existing = cfg.provider[CURSOR_PROVIDER_ID];
|
package/dist/pricing-data.d.ts
CHANGED
|
@@ -25,6 +25,12 @@ export declare const CURSOR_MODEL_COSTS: {
|
|
|
25
25
|
readonly cache_read: 0.1;
|
|
26
26
|
readonly cache_write: 1.25;
|
|
27
27
|
};
|
|
28
|
+
readonly "claude-haiku-5-5": {
|
|
29
|
+
readonly input: 0.1;
|
|
30
|
+
readonly output: 0.5;
|
|
31
|
+
readonly cache_read: 0.01;
|
|
32
|
+
readonly cache_write: 0.125;
|
|
33
|
+
};
|
|
28
34
|
readonly "claude-opus-4-5": {
|
|
29
35
|
readonly input: 5;
|
|
30
36
|
readonly output: 25;
|
|
@@ -94,7 +100,7 @@ export declare const CURSOR_MODEL_COSTS: {
|
|
|
94
100
|
readonly "claude-sonnet-5-5": {
|
|
95
101
|
readonly input: 2;
|
|
96
102
|
readonly output: 10;
|
|
97
|
-
readonly cache_read: 0.
|
|
103
|
+
readonly cache_read: 0.1;
|
|
98
104
|
readonly cache_write: 2.5;
|
|
99
105
|
};
|
|
100
106
|
readonly "composer-2.5": {
|
|
@@ -134,14 +140,19 @@ export declare const CURSOR_MODEL_COSTS: {
|
|
|
134
140
|
};
|
|
135
141
|
readonly "gemini-3.7-flash": {
|
|
136
142
|
readonly input: 0.75;
|
|
137
|
-
readonly output: 3.
|
|
143
|
+
readonly output: 3.75;
|
|
138
144
|
readonly cache_read: 0.075;
|
|
139
145
|
};
|
|
140
146
|
readonly "gemini-3.8-flash": {
|
|
141
147
|
readonly input: 0.75;
|
|
142
|
-
readonly output: 3.
|
|
148
|
+
readonly output: 3.75;
|
|
143
149
|
readonly cache_read: 0.075;
|
|
144
150
|
};
|
|
151
|
+
readonly "gemini-4-argon": {
|
|
152
|
+
readonly input: 2;
|
|
153
|
+
readonly output: 10;
|
|
154
|
+
readonly cache_read: 0.1;
|
|
155
|
+
};
|
|
145
156
|
readonly "glm-5.2": {
|
|
146
157
|
readonly input: 1.4;
|
|
147
158
|
readonly output: 4.4;
|
|
@@ -298,6 +309,11 @@ export declare const CURSOR_MODEL_COSTS: {
|
|
|
298
309
|
readonly output: 4.25;
|
|
299
310
|
readonly cache_read: 0.15;
|
|
300
311
|
};
|
|
312
|
+
readonly "muse-wonder-1.0": {
|
|
313
|
+
readonly input: 4;
|
|
314
|
+
readonly output: 20;
|
|
315
|
+
readonly cache_read: 0.2;
|
|
316
|
+
};
|
|
301
317
|
};
|
|
302
318
|
export declare const CURSOR_MODEL_CONTEXTS: {
|
|
303
319
|
readonly "claude-fable-5": {
|
|
@@ -311,6 +327,10 @@ export declare const CURSOR_MODEL_CONTEXTS: {
|
|
|
311
327
|
readonly "claude-haiku-4-5": {
|
|
312
328
|
readonly maxContext: 200000;
|
|
313
329
|
};
|
|
330
|
+
readonly "claude-haiku-5-5": {
|
|
331
|
+
readonly maxContext: 300000;
|
|
332
|
+
readonly maxContextForMaxMode: 1000000;
|
|
333
|
+
};
|
|
314
334
|
readonly "claude-opus-4-5": {
|
|
315
335
|
readonly maxContext: 200000;
|
|
316
336
|
readonly maxContextForMaxMode: 200000;
|
|
@@ -386,6 +406,10 @@ export declare const CURSOR_MODEL_CONTEXTS: {
|
|
|
386
406
|
readonly maxContext: 200000;
|
|
387
407
|
readonly maxContextForMaxMode: 1000000;
|
|
388
408
|
};
|
|
409
|
+
readonly "gemini-4-argon": {
|
|
410
|
+
readonly maxContext: 200000;
|
|
411
|
+
readonly maxContextForMaxMode: 1000000;
|
|
412
|
+
};
|
|
389
413
|
readonly "glm-5.2": {
|
|
390
414
|
readonly maxContext: 200000;
|
|
391
415
|
};
|
|
@@ -454,6 +478,10 @@ export declare const CURSOR_MODEL_CONTEXTS: {
|
|
|
454
478
|
readonly maxContext: 300000;
|
|
455
479
|
readonly maxContextForMaxMode: 1000000;
|
|
456
480
|
};
|
|
481
|
+
readonly "muse-wonder-1.0": {
|
|
482
|
+
readonly maxContext: 300000;
|
|
483
|
+
readonly maxContextForMaxMode: 1000000;
|
|
484
|
+
};
|
|
457
485
|
};
|
|
458
486
|
export declare const CURSOR_MODEL_CAPABILITIES: {
|
|
459
487
|
readonly "claude-fable-5": {
|
|
@@ -465,6 +493,9 @@ export declare const CURSOR_MODEL_CAPABILITIES: {
|
|
|
465
493
|
readonly "claude-haiku-4-5": {
|
|
466
494
|
readonly supportsImages: true;
|
|
467
495
|
};
|
|
496
|
+
readonly "claude-haiku-5-5": {
|
|
497
|
+
readonly supportsImages: true;
|
|
498
|
+
};
|
|
468
499
|
readonly "claude-opus-4-5": {
|
|
469
500
|
readonly supportsImages: true;
|
|
470
501
|
};
|
|
@@ -522,6 +553,9 @@ export declare const CURSOR_MODEL_CAPABILITIES: {
|
|
|
522
553
|
readonly "gemini-3.8-flash": {
|
|
523
554
|
readonly supportsImages: true;
|
|
524
555
|
};
|
|
556
|
+
readonly "gemini-4-argon": {
|
|
557
|
+
readonly supportsImages: true;
|
|
558
|
+
};
|
|
525
559
|
readonly "glm-5.2": {
|
|
526
560
|
readonly supportsImages: false;
|
|
527
561
|
};
|
|
@@ -582,4 +616,7 @@ export declare const CURSOR_MODEL_CAPABILITIES: {
|
|
|
582
616
|
readonly "muse-spark-1.3": {
|
|
583
617
|
readonly supportsImages: true;
|
|
584
618
|
};
|
|
619
|
+
readonly "muse-wonder-1.0": {
|
|
620
|
+
readonly supportsImages: true;
|
|
621
|
+
};
|
|
585
622
|
};
|
package/dist/pricing-data.js
CHANGED
|
@@ -25,6 +25,12 @@ export const CURSOR_MODEL_COSTS = {
|
|
|
25
25
|
"cache_read": 0.1,
|
|
26
26
|
"cache_write": 1.25
|
|
27
27
|
},
|
|
28
|
+
"claude-haiku-5-5": {
|
|
29
|
+
"input": 0.1,
|
|
30
|
+
"output": 0.5,
|
|
31
|
+
"cache_read": 0.01,
|
|
32
|
+
"cache_write": 0.125
|
|
33
|
+
},
|
|
28
34
|
"claude-opus-4-5": {
|
|
29
35
|
"input": 5,
|
|
30
36
|
"output": 25,
|
|
@@ -94,7 +100,7 @@ export const CURSOR_MODEL_COSTS = {
|
|
|
94
100
|
"claude-sonnet-5-5": {
|
|
95
101
|
"input": 2,
|
|
96
102
|
"output": 10,
|
|
97
|
-
"cache_read": 0.
|
|
103
|
+
"cache_read": 0.1,
|
|
98
104
|
"cache_write": 2.5
|
|
99
105
|
},
|
|
100
106
|
"composer-2.5": {
|
|
@@ -134,14 +140,19 @@ export const CURSOR_MODEL_COSTS = {
|
|
|
134
140
|
},
|
|
135
141
|
"gemini-3.7-flash": {
|
|
136
142
|
"input": 0.75,
|
|
137
|
-
"output": 3.
|
|
143
|
+
"output": 3.75,
|
|
138
144
|
"cache_read": 0.075
|
|
139
145
|
},
|
|
140
146
|
"gemini-3.8-flash": {
|
|
141
147
|
"input": 0.75,
|
|
142
|
-
"output": 3.
|
|
148
|
+
"output": 3.75,
|
|
143
149
|
"cache_read": 0.075
|
|
144
150
|
},
|
|
151
|
+
"gemini-4-argon": {
|
|
152
|
+
"input": 2,
|
|
153
|
+
"output": 10,
|
|
154
|
+
"cache_read": 0.1
|
|
155
|
+
},
|
|
145
156
|
"glm-5.2": {
|
|
146
157
|
"input": 1.4,
|
|
147
158
|
"output": 4.4,
|
|
@@ -297,6 +308,11 @@ export const CURSOR_MODEL_COSTS = {
|
|
|
297
308
|
"input": 1.25,
|
|
298
309
|
"output": 4.25,
|
|
299
310
|
"cache_read": 0.15
|
|
311
|
+
},
|
|
312
|
+
"muse-wonder-1.0": {
|
|
313
|
+
"input": 4,
|
|
314
|
+
"output": 20,
|
|
315
|
+
"cache_read": 0.2
|
|
300
316
|
}
|
|
301
317
|
};
|
|
302
318
|
export const CURSOR_MODEL_CONTEXTS = {
|
|
@@ -311,6 +327,10 @@ export const CURSOR_MODEL_CONTEXTS = {
|
|
|
311
327
|
"claude-haiku-4-5": {
|
|
312
328
|
"maxContext": 200000
|
|
313
329
|
},
|
|
330
|
+
"claude-haiku-5-5": {
|
|
331
|
+
"maxContext": 300000,
|
|
332
|
+
"maxContextForMaxMode": 1000000
|
|
333
|
+
},
|
|
314
334
|
"claude-opus-4-5": {
|
|
315
335
|
"maxContext": 200000,
|
|
316
336
|
"maxContextForMaxMode": 200000
|
|
@@ -386,6 +406,10 @@ export const CURSOR_MODEL_CONTEXTS = {
|
|
|
386
406
|
"maxContext": 200000,
|
|
387
407
|
"maxContextForMaxMode": 1000000
|
|
388
408
|
},
|
|
409
|
+
"gemini-4-argon": {
|
|
410
|
+
"maxContext": 200000,
|
|
411
|
+
"maxContextForMaxMode": 1000000
|
|
412
|
+
},
|
|
389
413
|
"glm-5.2": {
|
|
390
414
|
"maxContext": 200000
|
|
391
415
|
},
|
|
@@ -453,6 +477,10 @@ export const CURSOR_MODEL_CONTEXTS = {
|
|
|
453
477
|
"muse-spark-1.3": {
|
|
454
478
|
"maxContext": 300000,
|
|
455
479
|
"maxContextForMaxMode": 1000000
|
|
480
|
+
},
|
|
481
|
+
"muse-wonder-1.0": {
|
|
482
|
+
"maxContext": 300000,
|
|
483
|
+
"maxContextForMaxMode": 1000000
|
|
456
484
|
}
|
|
457
485
|
};
|
|
458
486
|
export const CURSOR_MODEL_CAPABILITIES = {
|
|
@@ -465,6 +493,9 @@ export const CURSOR_MODEL_CAPABILITIES = {
|
|
|
465
493
|
"claude-haiku-4-5": {
|
|
466
494
|
"supportsImages": true
|
|
467
495
|
},
|
|
496
|
+
"claude-haiku-5-5": {
|
|
497
|
+
"supportsImages": true
|
|
498
|
+
},
|
|
468
499
|
"claude-opus-4-5": {
|
|
469
500
|
"supportsImages": true
|
|
470
501
|
},
|
|
@@ -522,6 +553,9 @@ export const CURSOR_MODEL_CAPABILITIES = {
|
|
|
522
553
|
"gemini-3.8-flash": {
|
|
523
554
|
"supportsImages": true
|
|
524
555
|
},
|
|
556
|
+
"gemini-4-argon": {
|
|
557
|
+
"supportsImages": true
|
|
558
|
+
},
|
|
525
559
|
"glm-5.2": {
|
|
526
560
|
"supportsImages": false
|
|
527
561
|
},
|
|
@@ -581,5 +615,8 @@ export const CURSOR_MODEL_CAPABILITIES = {
|
|
|
581
615
|
},
|
|
582
616
|
"muse-spark-1.3": {
|
|
583
617
|
"supportsImages": true
|
|
618
|
+
},
|
|
619
|
+
"muse-wonder-1.0": {
|
|
620
|
+
"supportsImages": true
|
|
584
621
|
}
|
|
585
622
|
};
|
package/dist/pricing.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare function validateOpenCodeModelCost(value: unknown, path?: string)
|
|
|
40
40
|
errors: string[];
|
|
41
41
|
};
|
|
42
42
|
export declare function isOpenCodeModelCost(value: unknown): value is OpenCodeModelCost;
|
|
43
|
-
/** Strip synthetic
|
|
43
|
+
/** Strip synthetic context suffixes (`…-1m`, `…-500k`, `…-500k-2-fast`, …). */
|
|
44
44
|
export declare function wireModelIdForPricing(modelId: string): {
|
|
45
45
|
baseId: string;
|
|
46
46
|
longContextEntry: boolean;
|
package/dist/pricing.js
CHANGED
|
@@ -47,9 +47,9 @@ export function validateOpenCodeModelCost(value, path = "cost") {
|
|
|
47
47
|
export function isOpenCodeModelCost(value) {
|
|
48
48
|
return validateOpenCodeModelCost(value).valid;
|
|
49
49
|
}
|
|
50
|
-
/** Strip synthetic
|
|
50
|
+
/** Strip synthetic context suffixes (`…-1m`, `…-500k`, `…-500k-2-fast`, …). */
|
|
51
51
|
export function wireModelIdForPricing(modelId) {
|
|
52
|
-
const match = /^(.*)
|
|
52
|
+
const match = /^(.*)-\d+(?:\.\d+)?[km](?:-\d+)?(-fast)?$/.exec(modelId);
|
|
53
53
|
if (match) {
|
|
54
54
|
return { baseId: `${match[1]}${match[2] ?? ""}`, longContextEntry: true };
|
|
55
55
|
}
|
|
@@ -79,8 +79,11 @@ function asMutableCost(value) {
|
|
|
79
79
|
* Synthetic `-fast` entries are stored as their own keys.
|
|
80
80
|
*/
|
|
81
81
|
export function getCursorModelCost(modelId) {
|
|
82
|
-
const
|
|
83
|
-
|
|
82
|
+
const costs = CURSOR_MODEL_COSTS;
|
|
83
|
+
// A priced wire id wins over suffix stripping (`-<n>k` / `-<n>m` may be real).
|
|
84
|
+
const found = Object.hasOwn(costs, modelId)
|
|
85
|
+
? costs[modelId]
|
|
86
|
+
: costs[wireModelIdForPricing(modelId).baseId];
|
|
84
87
|
if (!found)
|
|
85
88
|
return undefined;
|
|
86
89
|
return asMutableCost(found);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State shared by every copy of this package in one process.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode 2 imports a separate copy of a plugin's module graph for each
|
|
5
|
+
* location (project directory) it serves, all in one realm. Module-level state
|
|
6
|
+
* then exists once per copy, so per-account work such as credential renewal ran
|
|
7
|
+
* once per location. Keep that state here instead.
|
|
8
|
+
*
|
|
9
|
+
* Store plain data only (maps, strings, numbers, promises): every copy has its
|
|
10
|
+
* own classes, so an instance stored by one copy fails `instanceof` in another.
|
|
11
|
+
* Name keys with a version suffix (`….v1`) and bump it when the stored shape
|
|
12
|
+
* changes, so two package versions in one process never read each other's data.
|
|
13
|
+
*/
|
|
14
|
+
export declare function processShared<T>(name: string, create: () => T): T;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State shared by every copy of this package in one process.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode 2 imports a separate copy of a plugin's module graph for each
|
|
5
|
+
* location (project directory) it serves, all in one realm. Module-level state
|
|
6
|
+
* then exists once per copy, so per-account work such as credential renewal ran
|
|
7
|
+
* once per location. Keep that state here instead.
|
|
8
|
+
*
|
|
9
|
+
* Store plain data only (maps, strings, numbers, promises): every copy has its
|
|
10
|
+
* own classes, so an instance stored by one copy fails `instanceof` in another.
|
|
11
|
+
* Name keys with a version suffix (`….v1`) and bump it when the stored shape
|
|
12
|
+
* changes, so two package versions in one process never read each other's data.
|
|
13
|
+
*/
|
|
14
|
+
export function processShared(name, create) {
|
|
15
|
+
const key = Symbol.for(`cursor-opencode-provider.${name}`);
|
|
16
|
+
const registry = globalThis;
|
|
17
|
+
return registry[key] ??= create();
|
|
18
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Synthesis of OpenCode `apply_patch` envelopes from Cursor's
|
|
3
|
-
* exec requests.
|
|
2
|
+
* Synthesis of OpenCode `apply_patch` (2.0: `patch`) envelopes from Cursor's
|
|
3
|
+
* native write/edit exec requests.
|
|
4
4
|
*
|
|
5
5
|
* ## Why this exists
|
|
6
6
|
*
|
|
@@ -36,10 +36,12 @@
|
|
|
36
36
|
* `ctx.session.context(...)` hook exposing a mutable tool roster, and lists
|
|
37
37
|
* "Select `apply_patch` versus `edit` + `write`" as work to move out of the
|
|
38
38
|
* registry. Once that lands, a host-side opt-out replaces this shim.
|
|
39
|
-
* - OpenCode 2.0 (`packages/core`)
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* - OpenCode 2.0 (`packages/core`) keeps the gate under a new name. The tool is
|
|
40
|
+
* `patch` (still `{ patchText }`, same envelope format), and
|
|
41
|
+
* `tool/plugin/patch.ts` applies the same model-id predicate in its session
|
|
42
|
+
* `context`/`compaction`/`generate` hooks, deleting `edit` and `write` for GPT models and
|
|
43
|
+
* `patch` for everyone else. Both names are recognised here; which one the
|
|
44
|
+
* host offers is read from the advertised set rather than a version check.
|
|
43
45
|
*
|
|
44
46
|
* ## Why translation, not advertisement
|
|
45
47
|
*
|
|
@@ -59,7 +61,7 @@
|
|
|
59
61
|
* native requests arrive for every model. Those names are absent from
|
|
60
62
|
* the catalog, so the request is refused before it reaches OpenCode.
|
|
61
63
|
*
|
|
62
|
-
* ## Format notes (verified against `packages/opencode/src/patch/index.ts`)
|
|
64
|
+
* ## Format notes (verified against `packages/opencode/src/patch/index.ts` and 2.0's `packages/util/src/patch.ts`)
|
|
63
65
|
*
|
|
64
66
|
* - `*** Add File:` **overwrites an existing file** — the tool's `add` case uses
|
|
65
67
|
* `oldContent = ""` and never stats the target (upstream test: "adds file
|
|
@@ -71,15 +73,25 @@
|
|
|
71
73
|
* - Every payload line is prefixed with `+`, `-`, or a space, and the parser
|
|
72
74
|
* only breaks on *unprefixed* `***` / `@@`. Content lines that themselves
|
|
73
75
|
* begin with `***` or `@@` therefore survive a round trip unharmed.
|
|
74
|
-
* - `Add File` content is rejoined with `\n
|
|
75
|
-
*
|
|
76
|
+
* - `Add File` content is rejoined with `\n`; the tool appends a final newline
|
|
77
|
+
* only when nonempty content lacks one. Keep the trailing empty payload line
|
|
78
|
+
* so blank lines survive. Nonempty unterminated content cannot round-trip.
|
|
79
|
+
* - OpenCode 2's `patch` parser strips a trailing `\r` from every payload
|
|
80
|
+
* line, unlike 1.x `apply_patch`. Refuse that lossy encoding on `patch`.
|
|
76
81
|
* - Update chunks match **whole lines** via `seekSequence`, unlike OpenCode
|
|
77
82
|
* `edit`, which is substring-based. Substring edits must be expanded to line
|
|
78
83
|
* boundaries before they can be expressed as a patch — see `planSubstringEdit`.
|
|
79
|
-
* -
|
|
80
|
-
*
|
|
84
|
+
* - Cursor's write/edit requests never rename, so `*** Move to:` is never
|
|
85
|
+
* emitted here.
|
|
81
86
|
*/
|
|
87
|
+
/** OpenCode 1.x name for the patch tool. */
|
|
82
88
|
export declare const APPLY_PATCH_TOOL = "apply_patch";
|
|
89
|
+
/** OpenCode 2.0 name for the same tool (renamed from `apply_patch`). */
|
|
90
|
+
export declare const PATCH_TOOL = "patch";
|
|
91
|
+
export type HostPatchTool = typeof APPLY_PATCH_TOOL | typeof PATCH_TOOL;
|
|
92
|
+
/** The patch tool this host advertises in place of `edit`/`write`, if any. */
|
|
93
|
+
export declare function hostPatchTool(advertised: ReadonlySet<string>): HostPatchTool | undefined;
|
|
94
|
+
export declare function isHostPatchTool(name: string): name is HostPatchTool;
|
|
83
95
|
/** One `@@` chunk: replace `oldLines` with `newLines`. */
|
|
84
96
|
export type UpdateChunk = {
|
|
85
97
|
oldLines: string[];
|
|
@@ -89,9 +101,9 @@ export type UpdateChunk = {
|
|
|
89
101
|
* Whole-file write as `*** Add File:`. Valid whether or not the target exists —
|
|
90
102
|
* OpenCode's add case overwrites unconditionally.
|
|
91
103
|
*/
|
|
92
|
-
export declare function buildAddFilePatch(filePath: string, content: string): string;
|
|
104
|
+
export declare function buildAddFilePatch(filePath: string, content: string, tool?: HostPatchTool): string;
|
|
93
105
|
/** Targeted replacement as `*** Update File:` with one `@@` chunk per change. */
|
|
94
|
-
export declare function buildUpdateFilePatch(filePath: string, chunks: UpdateChunk[]): string;
|
|
106
|
+
export declare function buildUpdateFilePatch(filePath: string, chunks: UpdateChunk[], tool?: HostPatchTool): string;
|
|
95
107
|
export type SubstringEditPlan = {
|
|
96
108
|
ok: true;
|
|
97
109
|
chunks: UpdateChunk[];
|