cursor-opencode-provider 0.6.0 → 0.6.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.
- package/README.md +4 -0
- package/dist/context/plugins.js +1 -0
- package/dist/context/rules.js +1 -0
- package/dist/context/skills.js +1 -0
- package/dist/language-model.js +20 -10
- package/dist/protocol/conversation-bind.d.ts +1 -0
- package/dist/protocol/conversation-bind.js +3 -0
- package/dist/protocol/struct.js +1 -1
- package/dist/protocol/tools.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -368,8 +368,12 @@ bun run typecheck # type-check without emit
|
|
|
368
368
|
bun test # run unit tests
|
|
369
369
|
bun run test:node-http2 # Node-specific HTTP/2 detach regression
|
|
370
370
|
bun run test:watch # watch mode
|
|
371
|
+
bun run generate:pricing # refresh src/pricing-data.ts from Cursor docs
|
|
372
|
+
bun run check:pricing # fixture coverage for known model ids
|
|
371
373
|
```
|
|
372
374
|
|
|
375
|
+
Before any version bump or `v*` tag, run `generate:pricing` and `check:pricing` and commit mapping/`pricing-data.ts` updates. Publish CI regenerates rates from the live docs; an unmapped Cursor display name fails the job.
|
|
376
|
+
|
|
373
377
|
## Architecture
|
|
374
378
|
|
|
375
379
|
```
|
package/dist/context/plugins.js
CHANGED
package/dist/context/rules.js
CHANGED
package/dist/context/skills.js
CHANGED
package/dist/language-model.js
CHANGED
|
@@ -625,12 +625,18 @@ async function startSession(modelId, token, callOptions, options, startOptions)
|
|
|
625
625
|
// Compaction must not reuse the prior conversation; its first normal turn
|
|
626
626
|
// must also rebase so the summary-agent checkpoint cannot replace the normal
|
|
627
627
|
// system prompt and OpenCode's newly compacted history.
|
|
628
|
+
const lifecycle = !allowTools && !isCompaction && !recovery;
|
|
628
629
|
let bound = resuming
|
|
629
630
|
? { conversationId: resumeRecovery.conversationId, reset: false, previousId: undefined }
|
|
630
|
-
: bindConversationId(sessionKey, {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
631
|
+
: bindConversationId(sessionKey, {
|
|
632
|
+
reset: resetState.reset || recovery?.kind === "rebase",
|
|
633
|
+
ephemeral: lifecycle,
|
|
634
|
+
});
|
|
635
|
+
let conversationState = lifecycle
|
|
636
|
+
? undefined
|
|
637
|
+
: resuming
|
|
638
|
+
? resumeRecovery.checkpoint
|
|
639
|
+
: (bound.reset ? undefined : getCheckpoint(bound.conversationId));
|
|
634
640
|
let checkpointGraph = conversationState
|
|
635
641
|
? inspectConversationBlobGraph(bound.conversationId, conversationState)
|
|
636
642
|
: { count: 0, bytes: 0, complete: true };
|
|
@@ -685,12 +691,13 @@ async function startSession(modelId, token, callOptions, options, startOptions)
|
|
|
685
691
|
const interactionGuidance = buildOpenCodeInteractionGuidance(cursorTools, isCompaction, workspaceRoot);
|
|
686
692
|
// After an approved SwitchMode, inject the Cursor CLI-shaped mode reminder
|
|
687
693
|
// (same <system_reminder> contract the CLI uses after flipping unifiedMode).
|
|
688
|
-
const
|
|
694
|
+
const startedWithCheckpoint = !!conversationState;
|
|
695
|
+
const modeReminder = isCompaction || startedWithCheckpoint || lifecycle
|
|
689
696
|
? undefined
|
|
690
697
|
: takeActiveCursorModeReminder(sessionKey, {
|
|
691
698
|
advertisedTools: cursorTools.map((tool) => tool.name),
|
|
692
699
|
});
|
|
693
|
-
const kickoffWarning = isCompaction
|
|
700
|
+
const kickoffWarning = isCompaction || startedWithCheckpoint || lifecycle
|
|
694
701
|
? undefined
|
|
695
702
|
: takePlanExecutionKickoffWarning(sessionKey);
|
|
696
703
|
const systemPrompt = [
|
|
@@ -898,7 +905,7 @@ async function startSession(modelId, token, callOptions, options, startOptions)
|
|
|
898
905
|
displayToolCalls: 0,
|
|
899
906
|
execRequests: 0,
|
|
900
907
|
},
|
|
901
|
-
openCodeSessionId: sessionKey,
|
|
908
|
+
openCodeSessionId: lifecycle ? undefined : sessionKey,
|
|
902
909
|
postCompactionRebase: isCompaction,
|
|
903
910
|
toolCatalog: snapshotToolCatalog(sessionKey),
|
|
904
911
|
stream,
|
|
@@ -2790,6 +2797,9 @@ export function spanEndParts(opts) {
|
|
|
2790
2797
|
out.push({ type: "text-end", id: opts.textId });
|
|
2791
2798
|
return out;
|
|
2792
2799
|
}
|
|
2800
|
+
function toolsInFixedOrder(tools) {
|
|
2801
|
+
return tools.map((tool) => ({ ...tool })).sort((left, right) => (left.name ?? "").localeCompare(right.name ?? ""));
|
|
2802
|
+
}
|
|
2793
2803
|
/** Exported for tests — false for compaction/summary (no tools) and toolChoice none. */
|
|
2794
2804
|
export function computeAllowTools(toolCount, toolChoice) {
|
|
2795
2805
|
return toolCount > 0 && toolChoice?.type !== "none";
|
|
@@ -2797,7 +2807,7 @@ export function computeAllowTools(toolCount, toolChoice) {
|
|
|
2797
2807
|
export async function resolveTurnToolState(input) {
|
|
2798
2808
|
const { sessionKey, incomingTools, isCompaction } = input;
|
|
2799
2809
|
if (sessionKey && incomingTools.length > 0) {
|
|
2800
|
-
rememberToolCatalog(sessionKey, incomingTools
|
|
2810
|
+
rememberToolCatalog(sessionKey, toolsInFixedOrder(incomingTools));
|
|
2801
2811
|
}
|
|
2802
2812
|
// Advertisement and permission are deliberately independent.
|
|
2803
2813
|
//
|
|
@@ -2818,12 +2828,12 @@ export async function resolveTurnToolState(input) {
|
|
|
2818
2828
|
// still refuse execution and cannot duplicate the real turn's side effects.
|
|
2819
2829
|
let advertisedTools;
|
|
2820
2830
|
if (incomingTools.length > 0) {
|
|
2821
|
-
advertisedTools = incomingTools;
|
|
2831
|
+
advertisedTools = toolsInFixedOrder(incomingTools);
|
|
2822
2832
|
}
|
|
2823
2833
|
else if (sessionKey) {
|
|
2824
2834
|
const cached = toolCatalogBySession.get(sessionKey)
|
|
2825
2835
|
?? await waitForSiblingToolCatalog(sessionKey, input.abortSignal);
|
|
2826
|
-
advertisedTools = cached
|
|
2836
|
+
advertisedTools = toolsInFixedOrder(cached);
|
|
2827
2837
|
}
|
|
2828
2838
|
else {
|
|
2829
2839
|
// Without a session key there is no safe sibling-correlation key. Preserve
|
|
@@ -24,6 +24,7 @@ export declare function peekConversationId(sessionKey: string): string;
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function bindConversationId(sessionKey: string | undefined, opts?: {
|
|
26
26
|
reset?: boolean;
|
|
27
|
+
ephemeral?: boolean;
|
|
27
28
|
}): {
|
|
28
29
|
conversationId: string;
|
|
29
30
|
reset: boolean;
|
|
@@ -76,6 +76,9 @@ export function peekConversationId(sessionKey) {
|
|
|
76
76
|
* mint a new id so TurnEnded cache_read cannot keep overflowing OpenCode.
|
|
77
77
|
*/
|
|
78
78
|
export function bindConversationId(sessionKey, opts) {
|
|
79
|
+
if (opts?.ephemeral) {
|
|
80
|
+
return { conversationId: crypto.randomUUID(), reset: false };
|
|
81
|
+
}
|
|
79
82
|
if (!sessionKey) {
|
|
80
83
|
return { conversationId: crypto.randomUUID(), reset: !!opts?.reset };
|
|
81
84
|
}
|
package/dist/protocol/struct.js
CHANGED
|
@@ -249,7 +249,7 @@ export function encodeJsonAsValue(v) {
|
|
|
249
249
|
}
|
|
250
250
|
else if (typeof v === "object") {
|
|
251
251
|
const st = [];
|
|
252
|
-
for (const [key, val] of Object.entries(v)) {
|
|
252
|
+
for (const [key, val] of Object.entries(v).sort(([left], [right]) => left.localeCompare(right))) {
|
|
253
253
|
if (val === undefined)
|
|
254
254
|
continue;
|
|
255
255
|
const entry = [];
|
package/dist/protocol/tools.js
CHANGED
|
@@ -57,7 +57,9 @@ export function resolveToolServerIdentity(opencodeName, defaultServer = "opencod
|
|
|
57
57
|
* reconstructed in `mcpRealToolName`.
|
|
58
58
|
*/
|
|
59
59
|
export function toolsToDescriptors(tools, providerIdentifier = "opencode", knownMcpServers = []) {
|
|
60
|
-
return tools
|
|
60
|
+
return [...tools]
|
|
61
|
+
.sort((left, right) => left.name.localeCompare(right.name))
|
|
62
|
+
.map((t) => {
|
|
61
63
|
const id = resolveToolServerIdentity(t.sourceName ?? t.name, providerIdentifier, knownMcpServers);
|
|
62
64
|
const collisionSafeAlias = COLLISION_SAFE_ALIASES.has(t.name);
|
|
63
65
|
return {
|