cursor-opencode-provider 0.7.2 → 0.7.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/README.md +8 -5
- package/dist/context/agents.js +1 -1
- package/dist/context/build.d.ts +2 -0
- package/dist/context/build.js +22 -10
- package/dist/context/epoch.d.ts +59 -0
- package/dist/context/epoch.js +224 -0
- package/dist/context/frozen.d.ts +4 -2
- package/dist/context/frozen.js +31 -11
- package/dist/context/index.d.ts +2 -0
- package/dist/context/index.js +2 -0
- package/dist/context/overlay.d.ts +44 -0
- package/dist/context/overlay.js +96 -0
- package/dist/debug.d.ts +9 -1
- package/dist/debug.js +46 -5
- package/dist/host-event-bridge.d.ts +22 -0
- package/dist/host-event-bridge.js +22 -0
- package/dist/image-input.js +36 -11
- package/dist/index.d.ts +3 -0
- package/dist/language-model.d.ts +51 -3
- package/dist/language-model.js +569 -140
- package/dist/model-config.js +5 -1
- package/dist/plugin-opencode2.js +10 -4
- package/dist/plugin.js +26 -15
- package/dist/pricing-data.d.ts +40 -0
- package/dist/pricing-data.js +40 -0
- package/dist/protocol/ask-question.d.ts +8 -9
- package/dist/protocol/ask-question.js +8 -9
- package/dist/protocol/conversation-bind.js +18 -8
- package/dist/protocol/create-plan.d.ts +6 -7
- package/dist/protocol/create-plan.js +4 -5
- package/dist/protocol/messages.js +16 -1
- package/dist/protocol/struct.js +1 -1
- package/dist/protocol/switch-mode.d.ts +3 -4
- package/dist/protocol/switch-mode.js +21 -12
- package/dist/protocol/tool-call-bridge.d.ts +4 -1
- package/dist/protocol/tool-call-bridge.js +27 -5
- package/dist/protocol/tools.d.ts +4 -2
- package/dist/protocol/tools.js +247 -51
- package/dist/session-directory.d.ts +23 -4
- package/dist/session-directory.js +36 -4
- package/dist/session.d.ts +23 -3
- package/dist/session.js +68 -8
- package/dist/shared.d.ts +2 -0
- package/dist/shared.js +2 -0
- package/dist/transport/connect.js +78 -10
- package/dist/transport/https-proxy.d.ts +56 -0
- package/dist/transport/https-proxy.js +348 -0
- package/dist/usage.d.ts +11 -0
- package/dist/usage.js +33 -7
- package/package.json +1 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Epoch-hold live RequestContext overlay lists (skills, subagents, plugins).
|
|
3
|
+
*
|
|
4
|
+
* Same policy as the tool catalog: first nonempty freeze is UTF-16 by id,
|
|
5
|
+
* equal ids keep frozen bytes (including content), new ids append at the
|
|
6
|
+
* tail, shrink keeps the epoch advertisement. Discovery still runs every
|
|
7
|
+
* Run; this only canonicalizes what is advertised.
|
|
8
|
+
*/
|
|
9
|
+
export const MAX_OVERLAY_HOLDS = 256;
|
|
10
|
+
const byConversationId = new Map();
|
|
11
|
+
function utf16(left, right) {
|
|
12
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
13
|
+
}
|
|
14
|
+
function inFixedOrder(items, idOf) {
|
|
15
|
+
return items
|
|
16
|
+
.map((item) => ({ ...item }))
|
|
17
|
+
.sort((left, right) => utf16(idOf(left), idOf(right)));
|
|
18
|
+
}
|
|
19
|
+
function holdList(cached, incoming, idOf) {
|
|
20
|
+
const orderedIncoming = inFixedOrder(incoming, idOf);
|
|
21
|
+
if (!cached || cached.length === 0)
|
|
22
|
+
return orderedIncoming;
|
|
23
|
+
const cachedIds = new Set(cached.map(idOf));
|
|
24
|
+
const hasNew = orderedIncoming.some((item) => !cachedIds.has(idOf(item)));
|
|
25
|
+
if (!hasNew)
|
|
26
|
+
return cached;
|
|
27
|
+
const newcomers = inFixedOrder(orderedIncoming.filter((item) => !cachedIds.has(idOf(item))), idOf);
|
|
28
|
+
return [...cached, ...newcomers];
|
|
29
|
+
}
|
|
30
|
+
function remember(conversationId, hold) {
|
|
31
|
+
const stored = {
|
|
32
|
+
skills: structuredClone(hold.skills),
|
|
33
|
+
subagents: structuredClone(hold.subagents),
|
|
34
|
+
plugins: structuredClone(hold.plugins),
|
|
35
|
+
};
|
|
36
|
+
byConversationId.delete(conversationId);
|
|
37
|
+
byConversationId.set(conversationId, stored);
|
|
38
|
+
while (byConversationId.size > MAX_OVERLAY_HOLDS) {
|
|
39
|
+
const oldest = byConversationId.keys().next().value;
|
|
40
|
+
if (!oldest)
|
|
41
|
+
break;
|
|
42
|
+
byConversationId.delete(oldest);
|
|
43
|
+
}
|
|
44
|
+
return stored;
|
|
45
|
+
}
|
|
46
|
+
function skillId(skill) {
|
|
47
|
+
return skill.id || skill.full_path;
|
|
48
|
+
}
|
|
49
|
+
function toWire(hold) {
|
|
50
|
+
return {
|
|
51
|
+
skills: hold.skills.map(({ full_path, content, description }) => ({
|
|
52
|
+
full_path,
|
|
53
|
+
content,
|
|
54
|
+
description,
|
|
55
|
+
})),
|
|
56
|
+
subagents: hold.subagents,
|
|
57
|
+
plugins: hold.plugins,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Merge live discovery into the conversation overlay epoch. */
|
|
61
|
+
export function holdCapabilityOverlay(conversationId, live) {
|
|
62
|
+
if (!conversationId) {
|
|
63
|
+
return toWire({
|
|
64
|
+
skills: inFixedOrder(live.skills, skillId),
|
|
65
|
+
subagents: inFixedOrder(live.subagents, (agent) => agent.name),
|
|
66
|
+
plugins: inFixedOrder(live.plugins, (plugin) => plugin.id),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const cached = byConversationId.get(conversationId);
|
|
70
|
+
const next = {
|
|
71
|
+
skills: holdList(cached?.skills, live.skills, skillId),
|
|
72
|
+
subagents: holdList(cached?.subagents, live.subagents, (agent) => agent.name),
|
|
73
|
+
plugins: holdList(cached?.plugins, live.plugins, (plugin) => plugin.id),
|
|
74
|
+
};
|
|
75
|
+
if (next.skills.length === 0 && next.subagents.length === 0 && next.plugins.length === 0) {
|
|
76
|
+
byConversationId.delete(conversationId);
|
|
77
|
+
return toWire(next);
|
|
78
|
+
}
|
|
79
|
+
return toWire(remember(conversationId, next));
|
|
80
|
+
}
|
|
81
|
+
export function clearOverlayHold(conversationId) {
|
|
82
|
+
byConversationId.delete(conversationId);
|
|
83
|
+
}
|
|
84
|
+
export function transferOverlayHold(previousConversationId, nextConversationId) {
|
|
85
|
+
if (!previousConversationId || !nextConversationId)
|
|
86
|
+
return;
|
|
87
|
+
const hold = byConversationId.get(previousConversationId);
|
|
88
|
+
byConversationId.delete(previousConversationId);
|
|
89
|
+
byConversationId.delete(nextConversationId);
|
|
90
|
+
if (!hold)
|
|
91
|
+
return;
|
|
92
|
+
remember(nextConversationId, hold);
|
|
93
|
+
}
|
|
94
|
+
export function resetOverlayHoldsForTests() {
|
|
95
|
+
byConversationId.clear();
|
|
96
|
+
}
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
/** Soft cap for the debug log file; exceeded size triggers truncate + new header. */
|
|
2
|
+
export declare const DEBUG_LOG_MAX_BYTES: number;
|
|
1
3
|
/** Whether `CURSOR_PROVIDER_DEBUG` is enabled for this process. */
|
|
2
4
|
export declare function isDebugEnabled(): boolean;
|
|
3
5
|
/** Resolve the debug log path (env override or per-uid tmpdir default). */
|
|
4
6
|
export declare function resolveDebugLogPath(): string;
|
|
5
7
|
/**
|
|
6
|
-
* Ensure the log directory is 0o700 and
|
|
8
|
+
* Ensure the log directory is 0o700 and the log file exists as 0o600.
|
|
9
|
+
* Does **not** truncate an existing file — mid-run re-init must keep prior lines.
|
|
7
10
|
* Exported for tests; callers normally go through `trace`.
|
|
8
11
|
*/
|
|
9
12
|
export declare function ensureSecureDebugLog(filePath: string, options?: {
|
|
10
13
|
secureParent?: boolean;
|
|
11
14
|
}): void;
|
|
15
|
+
/**
|
|
16
|
+
* If `filePath` is at least `maxBytes`, truncate it and write a size-cap header.
|
|
17
|
+
* Returns true when a truncate happened. Exported for tests.
|
|
18
|
+
*/
|
|
19
|
+
export declare function truncateDebugLogIfOversized(filePath: string, maxBytes?: number): boolean;
|
|
12
20
|
export declare function trace(msg: string): void;
|
|
13
21
|
/**
|
|
14
22
|
* Compact path-advertising summary for RequestContext troubleshooting.
|
package/dist/debug.js
CHANGED
|
@@ -4,9 +4,16 @@ import path from "node:path";
|
|
|
4
4
|
// Wire-level diagnostics. Opt in with CURSOR_PROVIDER_DEBUG=1 (or "true").
|
|
5
5
|
// Default path mirrors Cursor CLI: $TMPDIR/cursor-provider-logs-<uid>/debug-<pid>.log
|
|
6
6
|
// with directory mode 0o700 and file mode 0o600. Override with CURSOR_PROVIDER_DEBUG_FILE.
|
|
7
|
-
//
|
|
7
|
+
// First init in a fresh file writes a header; later inits (module reload / second
|
|
8
|
+
// isolate sharing CURSOR_PROVIDER_DEBUG_FILE) append another header instead of
|
|
9
|
+
// wiping earlier EMITTED lines. Operators who want a clean run should truncate
|
|
10
|
+
// the override path before starting the host. Independently, when the file reaches
|
|
11
|
+
// DEBUG_LOG_MAX_BYTES it is size-capped (truncated + new header) so self-verify
|
|
12
|
+
// runs cannot grow without bound. Tokens / checksums: redact in callers.
|
|
8
13
|
const DEBUG_ENABLED = process.env.CURSOR_PROVIDER_DEBUG === "1" ||
|
|
9
14
|
process.env.CURSOR_PROVIDER_DEBUG === "true";
|
|
15
|
+
/** Soft cap for the debug log file; exceeded size triggers truncate + new header. */
|
|
16
|
+
export const DEBUG_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
|
10
17
|
let _traceInitialized = false;
|
|
11
18
|
let _debugFile;
|
|
12
19
|
let _debugFileUsesManagedDirectory = false;
|
|
@@ -24,7 +31,8 @@ export function resolveDebugLogPath() {
|
|
|
24
31
|
return path.join(os.tmpdir(), `cursor-provider-logs-${uid}`, `debug-${process.pid}.log`);
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
|
-
* Ensure the log directory is 0o700 and
|
|
34
|
+
* Ensure the log directory is 0o700 and the log file exists as 0o600.
|
|
35
|
+
* Does **not** truncate an existing file — mid-run re-init must keep prior lines.
|
|
28
36
|
* Exported for tests; callers normally go through `trace`.
|
|
29
37
|
*/
|
|
30
38
|
export function ensureSecureDebugLog(filePath, options = {}) {
|
|
@@ -43,7 +51,9 @@ export function ensureSecureDebugLog(filePath, options = {}) {
|
|
|
43
51
|
}
|
|
44
52
|
fs.chmodSync(dir, 0o700);
|
|
45
53
|
}
|
|
46
|
-
fs.
|
|
54
|
+
if (!fs.existsSync(filePath)) {
|
|
55
|
+
fs.writeFileSync(filePath, "", { mode: 0o600 });
|
|
56
|
+
}
|
|
47
57
|
fs.chmodSync(filePath, 0o600);
|
|
48
58
|
}
|
|
49
59
|
function announceLogPath(filePath) {
|
|
@@ -58,6 +68,25 @@ function announceLogPath(filePath) {
|
|
|
58
68
|
/* ignore */
|
|
59
69
|
}
|
|
60
70
|
}
|
|
71
|
+
function debugBannerLine() {
|
|
72
|
+
return `--- cursor-provider debug (pid ${process.pid}) ${new Date().toISOString()} ---\n`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* If `filePath` is at least `maxBytes`, truncate it and write a size-cap header.
|
|
76
|
+
* Returns true when a truncate happened. Exported for tests.
|
|
77
|
+
*/
|
|
78
|
+
export function truncateDebugLogIfOversized(filePath, maxBytes = DEBUG_LOG_MAX_BYTES) {
|
|
79
|
+
if (!fs.existsSync(filePath))
|
|
80
|
+
return false;
|
|
81
|
+
const size = fs.statSync(filePath).size;
|
|
82
|
+
if (size < maxBytes)
|
|
83
|
+
return false;
|
|
84
|
+
fs.writeFileSync(filePath, debugBannerLine() +
|
|
85
|
+
`[${new Date().toISOString()}] debug: size-cap truncate file=${filePath} ` +
|
|
86
|
+
`wasBytes=${size} maxBytes=${maxBytes}\n`, { mode: 0o600 });
|
|
87
|
+
fs.chmodSync(filePath, 0o600);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
61
90
|
export function trace(msg) {
|
|
62
91
|
if (!DEBUG_ENABLED)
|
|
63
92
|
return;
|
|
@@ -68,13 +97,25 @@ export function trace(msg) {
|
|
|
68
97
|
}
|
|
69
98
|
if (!_traceInitialized) {
|
|
70
99
|
ensureSecureDebugLog(_debugFile, { secureParent: _debugFileUsesManagedDirectory });
|
|
71
|
-
|
|
100
|
+
// Drop oversized leftovers from a prior run before appending a reinit banner.
|
|
101
|
+
truncateDebugLogIfOversized(_debugFile);
|
|
102
|
+
const banner = debugBannerLine();
|
|
103
|
+
const preexisting = fs.existsSync(_debugFile) && fs.statSync(_debugFile).size > 0;
|
|
104
|
+
if (preexisting) {
|
|
105
|
+
fs.appendFileSync(_debugFile, banner);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
fs.writeFileSync(_debugFile, banner, { mode: 0o600 });
|
|
109
|
+
}
|
|
72
110
|
_traceInitialized = true;
|
|
73
111
|
announceLogPath(_debugFile);
|
|
74
112
|
fs.appendFileSync(_debugFile, `[${new Date().toISOString()}] debug: enabled file=${_debugFile} ` +
|
|
75
113
|
`xdg_cache_home=${process.env.XDG_CACHE_HOME ?? "(unset)"} ` +
|
|
76
|
-
`cwd=${process.cwd()}
|
|
114
|
+
`cwd=${process.cwd()}` +
|
|
115
|
+
(preexisting ? " reinit=append" : "") +
|
|
116
|
+
`\n`);
|
|
77
117
|
}
|
|
118
|
+
truncateDebugLogIfOversized(_debugFile);
|
|
78
119
|
fs.appendFileSync(_debugFile, `[${new Date().toISOString()}] ${msg}\n`);
|
|
79
120
|
}
|
|
80
121
|
catch {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional host-neutral event capability installed by a compatibility layer.
|
|
3
|
+
*
|
|
4
|
+
* The provider does not interpret host-specific event payloads here. It only
|
|
5
|
+
* forwards the canonical OpenCode plugin event and the structural host values
|
|
6
|
+
* that were supplied to the plugin at load time.
|
|
7
|
+
*/
|
|
8
|
+
export declare const HOST_EVENT_BRIDGE: unique symbol;
|
|
9
|
+
export type HostEventBridge = {
|
|
10
|
+
handle(input: {
|
|
11
|
+
event: unknown;
|
|
12
|
+
client: unknown;
|
|
13
|
+
directory: string;
|
|
14
|
+
serverUrl: URL;
|
|
15
|
+
}): void | Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
export declare function dispatchHostEventBridge(input: {
|
|
18
|
+
event: unknown;
|
|
19
|
+
client: unknown;
|
|
20
|
+
directory: string;
|
|
21
|
+
serverUrl: URL;
|
|
22
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional host-neutral event capability installed by a compatibility layer.
|
|
3
|
+
*
|
|
4
|
+
* The provider does not interpret host-specific event payloads here. It only
|
|
5
|
+
* forwards the canonical OpenCode plugin event and the structural host values
|
|
6
|
+
* that were supplied to the plugin at load time.
|
|
7
|
+
*/
|
|
8
|
+
export const HOST_EVENT_BRIDGE = Symbol.for("opencode.host.event-bridge");
|
|
9
|
+
export async function dispatchHostEventBridge(input) {
|
|
10
|
+
const bridge = globalThis[HOST_EVENT_BRIDGE];
|
|
11
|
+
if (!bridge || typeof bridge !== "object")
|
|
12
|
+
return;
|
|
13
|
+
const handle = bridge.handle;
|
|
14
|
+
if (typeof handle !== "function")
|
|
15
|
+
return;
|
|
16
|
+
try {
|
|
17
|
+
await handle.call(bridge, input);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// An optional compatibility capability must not break the native plugin.
|
|
21
|
+
}
|
|
22
|
+
}
|
package/dist/image-input.js
CHANGED
|
@@ -189,24 +189,44 @@ export async function extractCursorUserImages(lastUser, signal, maxBytes = MAX_C
|
|
|
189
189
|
}
|
|
190
190
|
return images;
|
|
191
191
|
}
|
|
192
|
+
function pushImageFileParts(parts, content) {
|
|
193
|
+
for (const part of content) {
|
|
194
|
+
if (!part || typeof part !== "object")
|
|
195
|
+
continue;
|
|
196
|
+
const file = part;
|
|
197
|
+
if (file.type === "file" &&
|
|
198
|
+
typeof file.mediaType === "string" &&
|
|
199
|
+
file.mediaType.startsWith("image/"))
|
|
200
|
+
parts.push(file);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
192
203
|
function cursorHistoryImageParts(prompt) {
|
|
193
204
|
const parts = [];
|
|
194
|
-
|
|
205
|
+
// Last user attachments stay owned by extractCursorUserImages so a prompt that
|
|
206
|
+
// still carries images on the trailing user message is not double-attached.
|
|
207
|
+
let lastUserIndex = -1;
|
|
208
|
+
for (let i = 0; i < prompt.length; i++) {
|
|
209
|
+
const message = prompt[i];
|
|
210
|
+
if (!message || typeof message !== "object")
|
|
211
|
+
continue;
|
|
212
|
+
if (message.role === "user")
|
|
213
|
+
lastUserIndex = i;
|
|
214
|
+
}
|
|
215
|
+
for (let i = 0; i < prompt.length; i++) {
|
|
216
|
+
const message = prompt[i];
|
|
195
217
|
if (!message || typeof message !== "object")
|
|
196
218
|
continue;
|
|
197
219
|
const record = message;
|
|
198
220
|
if (!Array.isArray(record.content))
|
|
199
221
|
continue;
|
|
222
|
+
if (record.role === "user") {
|
|
223
|
+
if (i === lastUserIndex)
|
|
224
|
+
continue;
|
|
225
|
+
pushImageFileParts(parts, record.content);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
200
228
|
if (record.role === "assistant") {
|
|
201
|
-
|
|
202
|
-
if (!part || typeof part !== "object")
|
|
203
|
-
continue;
|
|
204
|
-
const file = part;
|
|
205
|
-
if (file.type === "file" &&
|
|
206
|
-
typeof file.mediaType === "string" &&
|
|
207
|
-
file.mediaType.startsWith("image/"))
|
|
208
|
-
parts.push(file);
|
|
209
|
-
}
|
|
229
|
+
pushImageFileParts(parts, record.content);
|
|
210
230
|
continue;
|
|
211
231
|
}
|
|
212
232
|
if (record.role !== "tool")
|
|
@@ -266,9 +286,14 @@ export async function extractCursorPromptImages(prompt, lastUser, options) {
|
|
|
266
286
|
const maxBytes = cursorImageBudget(options.maxBytes ?? MAX_CURSOR_IMAGE_INPUT_BYTES);
|
|
267
287
|
const userImages = await extractCursorUserImages(lastUser, options.signal, maxBytes);
|
|
268
288
|
const userBytes = userImages.reduce((total, image) => total + image.data.length, 0);
|
|
289
|
+
// Seed history dedupe with this-turn last-user hashes so the same bytes on an
|
|
290
|
+
// earlier user/assistant/tool message are not attached twice in one Run.
|
|
291
|
+
const seenHashes = new Set(options.seenHistoryHashes);
|
|
292
|
+
for (const image of userImages)
|
|
293
|
+
seenHashes.add(imageContentHash(image.data));
|
|
269
294
|
const history = await extractCursorHistoryImages(prompt, {
|
|
270
295
|
supportsImages: options.supportsImages,
|
|
271
|
-
seenHashes
|
|
296
|
+
seenHashes,
|
|
272
297
|
signal: options.signal,
|
|
273
298
|
maxBytes: maxBytes - userBytes,
|
|
274
299
|
filenameOffset: userImages.length,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CursorPlugin } from "./plugin.js";
|
|
2
2
|
import type { CursorContinuationOptions } from "./session.js";
|
|
3
|
+
import type { HostToolDialect } from "./protocol/tools.js";
|
|
3
4
|
export type CursorRetryOptions = {
|
|
4
5
|
/** Total attempts including the initial request. Default: 3. */
|
|
5
6
|
maxAttempts?: number;
|
|
@@ -33,6 +34,8 @@ export type CreateCursorOptions = {
|
|
|
33
34
|
continuation?: CursorContinuationOptions;
|
|
34
35
|
/** Fresh-turn retry policy. Defaults: 3 attempts, 500ms base, 8000ms cap. */
|
|
35
36
|
retry?: CursorRetryOptions;
|
|
37
|
+
/** Fallback host dialect when schemas are omitted or ambiguous. Default: OpenCode 1.x. */
|
|
38
|
+
defaultDialect?: HostToolDialect;
|
|
36
39
|
};
|
|
37
40
|
export declare function createCursor(options: CreateCursorOptions): import("./plugin-core.js").CursorSdk;
|
|
38
41
|
export { CursorPlugin };
|
package/dist/language-model.d.ts
CHANGED
|
@@ -11,9 +11,16 @@ type PromptIdentity = {
|
|
|
11
11
|
systemPromptHash?: string;
|
|
12
12
|
};
|
|
13
13
|
export declare const MAX_TURN_STATE_SESSIONS = 256;
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Cursor CLI's conversation **export / transfer-to-cloud** path treats state
|
|
16
|
+
* above 100 MiB as large (`conversation-export.ts` default `104857600`). That
|
|
17
|
+
* budget must not remint a sticky conversation on resume — CLI soft-reuses.
|
|
18
|
+
*/
|
|
15
19
|
export declare const MAX_CHECKPOINT_BLOB_GRAPH_BYTES: number;
|
|
16
|
-
|
|
20
|
+
/** @deprecated Never remints; kept for call-site/tests. Always false. */
|
|
21
|
+
export declare function checkpointBlobGraphRequiresRebase(_stats: ConversationBlobGraphStats, _maxBytes?: number): boolean;
|
|
22
|
+
/** Warn-only concern for incomplete / oversized checkpoint graphs (no remint). */
|
|
23
|
+
export declare function checkpointBlobGraphConcern(stats: ConversationBlobGraphStats, maxBytes?: number): "incomplete-checkpoint-graph" | "oversized-checkpoint-graph" | undefined;
|
|
17
24
|
export type CursorRetryPolicy = {
|
|
18
25
|
maxAttempts: number;
|
|
19
26
|
baseDelayMs: number;
|
|
@@ -27,6 +34,12 @@ export declare function restoreTurnToolCatalog(sessionKey: string, tools: Openco
|
|
|
27
34
|
export declare function rememberMirroredTodos(sessionKey: string | undefined, todos: ReadonlyArray<Record<string, unknown>>): void;
|
|
28
35
|
/** Copy of the last known host todo list for an OpenCode session, if any. */
|
|
29
36
|
export declare function snapshotMirroredTodosBySession(sessionKey: string | undefined): Array<Record<string, unknown>> | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Prompt identity is diagnostics / persistence only and never drives remint.
|
|
39
|
+
* Kept as a named helper so call sites / tests that still mention identity
|
|
40
|
+
* churn have a single no-op definition.
|
|
41
|
+
*/
|
|
42
|
+
export declare function promptIdentityWouldRemint(_previous: PromptIdentity, _current: PromptIdentity): boolean;
|
|
30
43
|
type V3Part = LanguageModelV3StreamPart;
|
|
31
44
|
export declare function createCursorLanguageModel(modelId: string, providerId: string, options: CreateCursorOptions): LanguageModelV3;
|
|
32
45
|
export declare function pumpWithRecovery(input: {
|
|
@@ -55,6 +68,39 @@ export declare function findContinuationSession(toolResults: Array<{
|
|
|
55
68
|
sessionId: string;
|
|
56
69
|
execId: number;
|
|
57
70
|
}>): CursorSession | undefined;
|
|
71
|
+
/** How long a fresh-turn drain may wait for Cursor `turn_ended` after bridged settle. */
|
|
72
|
+
export declare const FRESH_TURN_DRAIN_TIMEOUT_MS = 8000;
|
|
73
|
+
/**
|
|
74
|
+
* Error text written onto Cursor execs that the host abandoned by starting a
|
|
75
|
+
* new user turn before returning the tool result. Completing the held Run with
|
|
76
|
+
* this cancel (then draining to `turn_ended`) keeps the same conversation
|
|
77
|
+
* prefix instead of `superseded-by-new-run` mid-exec.
|
|
78
|
+
*/
|
|
79
|
+
export declare const FRESH_TURN_PENDING_CANCEL_REASON = "Host started a new user turn before this tool result was delivered";
|
|
80
|
+
/**
|
|
81
|
+
* Before opening a new user-turn Run, finish the prior held-open Run cleanly:
|
|
82
|
+
* settle display-only bridged pendings, cancel any real execs still waiting on
|
|
83
|
+
* the host, then drain for `turn_ended`. That preserves the same
|
|
84
|
+
* conversation_id / checkpoint prefix instead of aborting mid-tool.
|
|
85
|
+
*/
|
|
86
|
+
export declare function preparePriorSessionForFreshTurn(openCodeSessionId: string | undefined, opts?: {
|
|
87
|
+
timeoutMs?: number;
|
|
88
|
+
}): Promise<"drained" | "settled-only" | "busy" | "none">;
|
|
89
|
+
/**
|
|
90
|
+
* Write error/reject results for every still-open non-bridged pending on the
|
|
91
|
+
* held Run so Cursor can finish the agent turn instead of being superseded.
|
|
92
|
+
*
|
|
93
|
+
* @returns number of pendings successfully cancelled
|
|
94
|
+
*/
|
|
95
|
+
export declare function cancelPendingExecsForFreshTurn(session: CursorSession): number;
|
|
96
|
+
/**
|
|
97
|
+
* Read remaining frames on an idle held-open Run until `turn_ended`, a
|
|
98
|
+
* response-requiring request we cannot answer without the host, or timeout.
|
|
99
|
+
* Used only on the fresh-turn settle path — not a general pump substitute.
|
|
100
|
+
*/
|
|
101
|
+
export declare function drainSessionUntilTurnEnded(session: CursorSession, opts?: {
|
|
102
|
+
timeoutMs?: number;
|
|
103
|
+
}): Promise<"turn-ended" | "busy" | "timeout" | "interrupted" | "skipped">;
|
|
58
104
|
/**
|
|
59
105
|
* Deliver trailing tool results onto a live continuation session.
|
|
60
106
|
* Returns the same session when writes succeed (or only bridged results were
|
|
@@ -162,9 +208,11 @@ export declare function resolveTurnToolState(input: {
|
|
|
162
208
|
export declare function resolveTurnConversationReset(input: {
|
|
163
209
|
sessionKey?: string;
|
|
164
210
|
isCompaction: boolean;
|
|
211
|
+
historyRewrite?: boolean;
|
|
212
|
+
/** @deprecated Ignored — prompt identity never remints. Kept for call-site compat. */
|
|
165
213
|
promptIdentity?: PromptIdentity;
|
|
166
214
|
}): {
|
|
167
215
|
reset: boolean;
|
|
168
|
-
reason?: "compaction" | "post-compaction-rebase" | "
|
|
216
|
+
reason?: "compaction" | "post-compaction-rebase" | "history-rewrite";
|
|
169
217
|
};
|
|
170
218
|
export declare function resetTurnStateForTests(): void;
|