cursor-opencode-provider 0.2.4 → 0.2.6
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 +15 -11
- package/SECURITY.md +42 -0
- package/dist/auth.d.ts +2 -1
- package/dist/auth.js +19 -13
- package/dist/context/rules.d.ts +4 -0
- package/dist/context/rules.js +53 -17
- package/dist/debug.d.ts +9 -0
- package/dist/debug.js +44 -4
- package/dist/language-model.d.ts +18 -4
- package/dist/language-model.js +149 -30
- package/dist/plugin.js +28 -12
- package/dist/protocol/interactions.d.ts +8 -1
- package/dist/protocol/interactions.js +15 -2
- package/dist/protocol/messages.js +7 -2
- package/dist/protocol/request.d.ts +4 -2
- package/dist/protocol/request.js +5 -5
- package/dist/protocol/tool-call-bridge.js +11 -1
- package/dist/protocol/tools.d.ts +2 -2
- package/dist/protocol/tools.js +145 -28
- package/dist/session.d.ts +2 -0
- package/dist/shell-timeout.d.ts +52 -3
- package/dist/shell-timeout.js +277 -23
- package/package.json +3 -2
package/dist/protocol/tools.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import { encodeMessage } from "./messages.js";
|
|
2
3
|
import { encodeJsonAsValue, decodeStructEntriesToJson, readAllFields } from "./struct.js";
|
|
3
4
|
import { trace } from "../debug.js";
|
|
4
5
|
import { cursorExecVariantByRequestName } from "./exec-variants.js";
|
|
6
|
+
import { BACKGROUND_SHELL_MARKER } from "../shell-timeout.js";
|
|
5
7
|
// Exec variant field number whose reply is the server-initiated request_context
|
|
6
8
|
// probe (ExecServerMessage #10 → ExecClientMessage #10). request/result share a
|
|
7
9
|
// field number for every exec variant, so this is also the result field.
|
|
@@ -133,8 +135,13 @@ export function buildLiveRequestContext(tools, providerIdentifier = "opencode",
|
|
|
133
135
|
// glob_args on the exec channel — Cursor's EditToolCall is display-only, and
|
|
134
136
|
// glob/edit from opencode are advertised as MCP tools and arrive as mcp_args.
|
|
135
137
|
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
+
// Design note (F11): Cursor has native delete / background-shell tools; OpenCode
|
|
139
|
+
// does not. This provider intentionally remaps:
|
|
140
|
+
// - delete_args → bash `rm -f -- <quoted-path>`
|
|
141
|
+
// - background_shell_spawn_args → bash (original command; plugin wraps nohup)
|
|
142
|
+
// Permissions still flow through OpenCode's advertised `bash` tool. Soft-
|
|
143
|
+
// background / detached children can outlive the OpenCode tool call; leftover
|
|
144
|
+
// process cleanup is left to the user / OS. Arg key remapping happens below.
|
|
138
145
|
const cursorToolToOpencode = {
|
|
139
146
|
read_args: "read",
|
|
140
147
|
write_args: "write",
|
|
@@ -207,7 +214,6 @@ export function mapExecServerToToolName(execField) {
|
|
|
207
214
|
export function mapToolNameToExecField(toolName) {
|
|
208
215
|
return opencodeToolToCursor[toolName];
|
|
209
216
|
}
|
|
210
|
-
const BACKGROUND_SHELL_MARKER = "__CURSOR_BACKGROUND_SHELL__";
|
|
211
217
|
export function parseExecServerMessage(msg) {
|
|
212
218
|
const id = msg.id;
|
|
213
219
|
if (id === undefined)
|
|
@@ -229,13 +235,16 @@ export function parseExecServerMessage(msg) {
|
|
|
229
235
|
if (!resultField)
|
|
230
236
|
return undefined;
|
|
231
237
|
const execId = msg.exec_id ?? "";
|
|
238
|
+
// F11: Cursor native background shell → OpenCode bash. Emit the original
|
|
239
|
+
// command for UI/storage; the classic plugin before-hook wraps with nohup.
|
|
240
|
+
// Residual: the child can keep running after this tool call completes.
|
|
232
241
|
if (execVariant === "background_shell_spawn_args") {
|
|
233
242
|
const raw = msg.background_shell_spawn_args ?? {};
|
|
234
243
|
const command = str(raw.command);
|
|
235
244
|
const workingDirectory = str(raw.working_directory) ?? "";
|
|
236
245
|
const args = {};
|
|
237
246
|
if (command)
|
|
238
|
-
args.command =
|
|
247
|
+
args.command = command;
|
|
239
248
|
if (workingDirectory)
|
|
240
249
|
args.workdir = workingDirectory;
|
|
241
250
|
return {
|
|
@@ -244,7 +253,11 @@ export function parseExecServerMessage(msg) {
|
|
|
244
253
|
toolName: "bash",
|
|
245
254
|
args,
|
|
246
255
|
resultField,
|
|
247
|
-
resultMetadata: {
|
|
256
|
+
resultMetadata: {
|
|
257
|
+
background_shell_spawn: true,
|
|
258
|
+
command: command ?? "",
|
|
259
|
+
working_directory: workingDirectory,
|
|
260
|
+
},
|
|
248
261
|
localError: raw.enable_write_shell_stdin_tool === true
|
|
249
262
|
? "Interactive background shells are not available through OpenCode's bash tool."
|
|
250
263
|
: command
|
|
@@ -328,9 +341,16 @@ export function parseExecServerMessage(msg) {
|
|
|
328
341
|
if (!toolName)
|
|
329
342
|
return undefined;
|
|
330
343
|
const mapped = mapCursorArgsToOpencode(toolName, msg[execVariant] ?? {}, execVariant);
|
|
344
|
+
const rawArgs = msg[execVariant] ?? {};
|
|
331
345
|
const resultMetadata = execVariant === "shell_stream_args"
|
|
332
|
-
? shellStreamResultMetadata(
|
|
333
|
-
:
|
|
346
|
+
? shellStreamResultMetadata(rawArgs)
|
|
347
|
+
: execVariant === "read_args"
|
|
348
|
+
? {
|
|
349
|
+
path: str(rawArgs.path) ?? str(rawArgs.file_path) ?? "",
|
|
350
|
+
...(typeof mapped.args.offset === "number" ? { offset: mapped.args.offset } : {}),
|
|
351
|
+
...(typeof mapped.args.limit === "number" ? { limit: mapped.args.limit } : {}),
|
|
352
|
+
}
|
|
353
|
+
: undefined;
|
|
334
354
|
if (resultMetadata
|
|
335
355
|
&& resultMetadata.timeout_behavior !== 2
|
|
336
356
|
&& typeof resultMetadata.timeout_ms === "number") {
|
|
@@ -390,7 +410,9 @@ export function mapCursorArgsToOpencode(toolName, raw, execVariant) {
|
|
|
390
410
|
const filePath = str(cleaned.path) ?? str(cleaned.filePath);
|
|
391
411
|
return { toolName: "read", args: filePath ? { filePath } : {} };
|
|
392
412
|
}
|
|
393
|
-
//
|
|
413
|
+
// F11: Cursor native delete_args → OpenCode bash. No delete builtin exists, so
|
|
414
|
+
// we emulate with `rm -f -- <path>` (shell-quoted). Same permission boundary
|
|
415
|
+
// as any other bash tool call.
|
|
394
416
|
if (execVariant === "delete_args") {
|
|
395
417
|
const target = str(cleaned.path) ?? str(cleaned.filePath);
|
|
396
418
|
return {
|
|
@@ -522,20 +544,6 @@ function mapCursorSubagentTypeToOpenCode(subagentType) {
|
|
|
522
544
|
function shellQuote(s) {
|
|
523
545
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
524
546
|
}
|
|
525
|
-
/**
|
|
526
|
-
* OpenCode's bash tool is foreground-only. Detach the requested command inside
|
|
527
|
-
* that one foreground call and print a private marker containing the spawned
|
|
528
|
-
* PID and log path. With stdin and all output redirected, the host shell can
|
|
529
|
-
* return immediately instead of retaining OpenCode's tool pipe.
|
|
530
|
-
*/
|
|
531
|
-
function buildBackgroundShellCommand(command) {
|
|
532
|
-
return [
|
|
533
|
-
'bg_log="$(mktemp "${TMPDIR:-/tmp}/cursor-opencode-bg.XXXXXX")" || exit 1',
|
|
534
|
-
`nohup sh -c ${shellQuote(command)} >"$bg_log" 2>&1 </dev/null &`,
|
|
535
|
-
"bg_pid=$!",
|
|
536
|
-
`printf '${BACKGROUND_SHELL_MARKER}%s:%s\\n' "$bg_pid" "$bg_log"`,
|
|
537
|
-
].join("\n");
|
|
538
|
-
}
|
|
539
547
|
/**
|
|
540
548
|
* Map Cursor McpArgs back to the OpenCode tool id.
|
|
541
549
|
* Prefers provider_identifier + bare tool_name (github + create_pull_request
|
|
@@ -646,7 +654,7 @@ export function buildExecClientMessages(input) {
|
|
|
646
654
|
id: input.execId,
|
|
647
655
|
local_execution_time_ms: input.executionTimeMs ?? 0,
|
|
648
656
|
};
|
|
649
|
-
clientMsg[resultField] = buildTypedExecResult(resultField, input.output, input.error, input.toolName, input.resultMetadata);
|
|
657
|
+
clientMsg[resultField] = buildTypedExecResult(resultField, input.output, input.error, input.toolName, input.resultMetadata, input.shellOutcome);
|
|
650
658
|
frames.push(encodeMessage("AgentClientMessage", {
|
|
651
659
|
exec_client_message: clientMsg,
|
|
652
660
|
}));
|
|
@@ -733,22 +741,31 @@ export function unwrapReadOutput(output) {
|
|
|
733
741
|
* OpenCode returns free-form text; we wrap it in the minimal success shape the
|
|
734
742
|
* server accepts (verified against agent.v1 wire captures).
|
|
735
743
|
*/
|
|
736
|
-
export function buildTypedExecResult(resultField, output, error, toolName, resultMetadata) {
|
|
744
|
+
export function buildTypedExecResult(resultField, output, error, toolName, resultMetadata, shellOutcome) {
|
|
737
745
|
switch (resultField) {
|
|
738
|
-
case "read_result":
|
|
746
|
+
case "read_result": {
|
|
747
|
+
const readPath = str(resultMetadata?.path) ?? extractPathTag(output) ?? "";
|
|
739
748
|
if (error)
|
|
740
|
-
return { error: { path:
|
|
749
|
+
return { error: { path: readPath, error } };
|
|
741
750
|
// Strip opencode's <path>/<content> envelope so Cursor's model receives
|
|
742
751
|
// raw file content and can't echo the wrapper into subsequent writes.
|
|
743
752
|
// reads route here only for native read_args; most arrive via mcp_result.
|
|
744
753
|
const content = unwrapReadOutput(output);
|
|
754
|
+
const statPath = extractPathTag(output) ?? readPath;
|
|
755
|
+
const outputMetadata = parseOpenCodeReadMetadata(output);
|
|
756
|
+
const totalLines = outputMetadata.totalLines ?? readFileLineCount(statPath) ?? countLines(content);
|
|
757
|
+
const rangeApplied = readRangeApplied(resultMetadata, totalLines);
|
|
745
758
|
return {
|
|
746
759
|
success: {
|
|
747
|
-
path:
|
|
760
|
+
path: readPath,
|
|
748
761
|
content,
|
|
749
|
-
total_lines:
|
|
762
|
+
total_lines: totalLines,
|
|
763
|
+
file_size: readFileSize(statPath),
|
|
764
|
+
truncated: readOutputTruncated(resultMetadata, outputMetadata, totalLines),
|
|
765
|
+
range_applied: rangeApplied,
|
|
750
766
|
},
|
|
751
767
|
};
|
|
768
|
+
}
|
|
752
769
|
case "grep_result": {
|
|
753
770
|
if (error)
|
|
754
771
|
return { error: { error } };
|
|
@@ -809,6 +826,19 @@ export function buildTypedExecResult(resultField, output, error, toolName, resul
|
|
|
809
826
|
const workingDirectory = str(resultMetadata?.working_directory) ?? "";
|
|
810
827
|
if (error)
|
|
811
828
|
return { error: { command, working_directory: workingDirectory, error } };
|
|
829
|
+
// Prefer the structured outcome captured by the plugin after-hook; markers
|
|
830
|
+
// are already stripped from the stored/rendered OpenCode output by then.
|
|
831
|
+
if (shellOutcome?.kind === "backgrounded") {
|
|
832
|
+
return {
|
|
833
|
+
success: {
|
|
834
|
+
shell_id: shellOutcome.shellId,
|
|
835
|
+
command: shellOutcome.command || command,
|
|
836
|
+
working_directory: shellOutcome.workingDirectory || workingDirectory,
|
|
837
|
+
pid: shellOutcome.pid,
|
|
838
|
+
},
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
// Fallback when no plugin hook ran: parse the private spawn marker inline.
|
|
812
842
|
const match = new RegExp(`${BACKGROUND_SHELL_MARKER}(\\d+):([^\\r\\n]+)`).exec(output);
|
|
813
843
|
const pid = match ? Number(match[1]) : 0;
|
|
814
844
|
if (!Number.isSafeInteger(pid) || pid <= 0 || pid > 0xffff_ffff) {
|
|
@@ -913,6 +943,93 @@ function extractPathTag(output) {
|
|
|
913
943
|
const m = output.match(/<path>([^<]+)<\/path>/);
|
|
914
944
|
return m?.[1];
|
|
915
945
|
}
|
|
946
|
+
/** Recover full-file metadata before unwrapReadOutput removes OpenCode's footer. */
|
|
947
|
+
function parseOpenCodeReadMetadata(output) {
|
|
948
|
+
const showing = /Showing lines (\d+)-(\d+)(?: of (\d+))?\./.exec(output);
|
|
949
|
+
if (showing) {
|
|
950
|
+
return {
|
|
951
|
+
startLine: Number(showing[1]),
|
|
952
|
+
endLine: Number(showing[2]),
|
|
953
|
+
...(showing[3] ? { totalLines: Number(showing[3]) } : {}),
|
|
954
|
+
outputCapped: output.includes("(Output capped at "),
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
const complete = /\(End of file - total (\d+) lines?\)/.exec(output);
|
|
958
|
+
if (complete)
|
|
959
|
+
return { totalLines: Number(complete[1]) };
|
|
960
|
+
return {};
|
|
961
|
+
}
|
|
962
|
+
function readRangeApplied(resultMetadata, totalLines) {
|
|
963
|
+
const offset = num(resultMetadata?.offset);
|
|
964
|
+
const limit = num(resultMetadata?.limit);
|
|
965
|
+
if (offset === undefined && limit === undefined)
|
|
966
|
+
return false;
|
|
967
|
+
if (totalLines === 0)
|
|
968
|
+
return false;
|
|
969
|
+
const startLine = offset ?? 1;
|
|
970
|
+
return startLine < 0 || startLine <= totalLines;
|
|
971
|
+
}
|
|
972
|
+
function readOutputTruncated(resultMetadata, outputMetadata, totalLines) {
|
|
973
|
+
if (outputMetadata.outputCapped)
|
|
974
|
+
return true;
|
|
975
|
+
const returnedEnd = outputMetadata.endLine;
|
|
976
|
+
if (returnedEnd === undefined || totalLines === 0)
|
|
977
|
+
return false;
|
|
978
|
+
const offset = num(resultMetadata?.offset);
|
|
979
|
+
const limit = num(resultMetadata?.limit);
|
|
980
|
+
const startLine = offset ?? 1;
|
|
981
|
+
if (startLine < 0)
|
|
982
|
+
return false;
|
|
983
|
+
const expectedEnd = limit === undefined
|
|
984
|
+
? totalLines
|
|
985
|
+
: Math.min(totalLines, Math.max(1, startLine) + limit - 1);
|
|
986
|
+
return returnedEnd < expectedEnd;
|
|
987
|
+
}
|
|
988
|
+
function readFileSize(filePath) {
|
|
989
|
+
if (!filePath)
|
|
990
|
+
return 0;
|
|
991
|
+
try {
|
|
992
|
+
return fs.statSync(filePath).size;
|
|
993
|
+
}
|
|
994
|
+
catch {
|
|
995
|
+
return 0;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
function readFileLineCount(filePath) {
|
|
999
|
+
if (!filePath)
|
|
1000
|
+
return undefined;
|
|
1001
|
+
let fd;
|
|
1002
|
+
try {
|
|
1003
|
+
fd = fs.openSync(filePath, "r");
|
|
1004
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
1005
|
+
let totalBytes = 0;
|
|
1006
|
+
let lines = 1;
|
|
1007
|
+
while (true) {
|
|
1008
|
+
const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, null);
|
|
1009
|
+
if (bytesRead === 0)
|
|
1010
|
+
break;
|
|
1011
|
+
totalBytes += bytesRead;
|
|
1012
|
+
for (let index = 0; index < bytesRead; index++) {
|
|
1013
|
+
if (buffer[index] === 0x0a)
|
|
1014
|
+
lines++;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
return totalBytes === 0 ? 0 : lines;
|
|
1018
|
+
}
|
|
1019
|
+
catch {
|
|
1020
|
+
return undefined;
|
|
1021
|
+
}
|
|
1022
|
+
finally {
|
|
1023
|
+
if (fd !== undefined) {
|
|
1024
|
+
try {
|
|
1025
|
+
fs.closeSync(fd);
|
|
1026
|
+
}
|
|
1027
|
+
catch {
|
|
1028
|
+
/* best effort */
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
916
1033
|
function extractPathLines(output) {
|
|
917
1034
|
const lines = output.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
918
1035
|
// Prefer absolute / relative path-looking lines; fall back to all non-empty.
|
package/dist/session.d.ts
CHANGED
|
@@ -98,6 +98,8 @@ export type CursorSession = {
|
|
|
98
98
|
* conversation_checkpoint_update (CLI parity).
|
|
99
99
|
*/
|
|
100
100
|
conversationId: string;
|
|
101
|
+
/** Latest eligible checkpoint emitted by this Run attempt. */
|
|
102
|
+
resumeCheckpoint?: Uint8Array;
|
|
101
103
|
/** OpenCode session whose own or descendant activity renews tool leases. */
|
|
102
104
|
openCodeSessionId?: string;
|
|
103
105
|
stream: BidiStream;
|
package/dist/shell-timeout.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/** Cursor agent.v1 TimeoutBehavior enum values. */
|
|
2
2
|
export declare const CURSOR_TIMEOUT_CANCEL = 1;
|
|
3
3
|
export declare const CURSOR_TIMEOUT_BACKGROUND = 2;
|
|
4
|
+
/** Private marker for Cursor `background_shell_spawn_args` detach wrappers. */
|
|
5
|
+
export declare const BACKGROUND_SHELL_MARKER = "__CURSOR_BACKGROUND_SHELL__";
|
|
4
6
|
export type CursorShellPolicy = {
|
|
5
7
|
command: string;
|
|
6
8
|
workingDirectory: string;
|
|
7
9
|
timeoutMs: number;
|
|
8
10
|
timeoutBehavior: number;
|
|
9
11
|
hardTimeoutMs?: number;
|
|
12
|
+
/** Immediate nohup detach for Cursor `background_shell_spawn_args`. */
|
|
13
|
+
backgroundSpawn?: boolean;
|
|
10
14
|
};
|
|
11
15
|
export type CursorShellOutcome = {
|
|
12
16
|
kind: "exit";
|
|
@@ -27,15 +31,60 @@ export declare function shellPolicyFromMetadata(metadata: Record<string, unknown
|
|
|
27
31
|
/** Register a Cursor shell request before OpenCode executes its emitted tool call. */
|
|
28
32
|
export declare function registerCursorShellCall(toolCallId: string, metadata: Record<string, unknown> | undefined): void;
|
|
29
33
|
/**
|
|
34
|
+
* F11 / soft-background helper.
|
|
35
|
+
*
|
|
30
36
|
* Run a Cursor soft-background command for its foreground window, then leave
|
|
31
|
-
* it detached if still alive. The sentinel is removed by the after
|
|
32
|
-
* OpenCode stores/renders the result.
|
|
37
|
+
* it detached (`nohup`) if still alive. The sentinel is removed by the after
|
|
38
|
+
* hook before OpenCode stores/renders the result.
|
|
39
|
+
*
|
|
40
|
+
* This approximates Cursor's TIMEOUT_BACKGROUND semantics through OpenCode's
|
|
41
|
+
* foreground-only bash tool. Residual: after OpenCode returns, the child (and
|
|
42
|
+
* optional hard-timeout watchdog) may still be running; this provider does not
|
|
43
|
+
* reap leftover processes — cleanup is left to the user / OS.
|
|
33
44
|
*/
|
|
34
45
|
export declare function buildSoftBackgroundCommand(policy: CursorShellPolicy): string;
|
|
35
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* F11 / background_shell_spawn_args helper.
|
|
48
|
+
*
|
|
49
|
+
* OpenCode's bash tool is foreground-only. Detach the requested command inside
|
|
50
|
+
* that one foreground call (`nohup … &`) and print a private marker containing
|
|
51
|
+
* the spawned PID and log path. With stdin and all output redirected, the host
|
|
52
|
+
* shell can return immediately instead of retaining OpenCode's tool pipe.
|
|
53
|
+
*
|
|
54
|
+
* Residual: the detached child is not reaped by this provider after OpenCode
|
|
55
|
+
* completes the tool call; cleanup is left to the user / OS.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildBackgroundShellCommand(command: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Prepare OpenCode Bash args before execution when Cursor requested wrapping.
|
|
60
|
+
*
|
|
61
|
+
* Important: do **not** replace `args.command` with the wrapper script.
|
|
62
|
+
* OpenCode's bash UI renders `state.input.command`, and `ctx.metadata()`
|
|
63
|
+
* persists the execute-time `args` object into that field. Mutating
|
|
64
|
+
* `args.command` therefore leaks the private wrapper into the TUI/GUI.
|
|
65
|
+
*
|
|
66
|
+
* Wrapping is applied later via {@link cursorShellEnvForCall} (`shell.env`),
|
|
67
|
+
* which uses BASH_ENV / ZDOTDIR injectors so bash/zsh `-c <original>` is
|
|
68
|
+
* replaced with the wrapper while the stored/displayed command stays original.
|
|
69
|
+
* Permissions also keep analyzing the real user command.
|
|
70
|
+
*/
|
|
36
71
|
export declare function prepareCursorShellArgs(toolCallId: string, args: Record<string, unknown>): void;
|
|
37
72
|
/** Restore the model-facing command in OpenCode's completed tool title. */
|
|
38
73
|
export declare function cursorShellOriginalCommand(toolCallId: string): string | undefined;
|
|
74
|
+
/** Drop injector temp files for a finished/abandoned Cursor shell call. */
|
|
75
|
+
export declare function releaseCursorShellEnv(toolCallId: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Env vars for OpenCode's `shell.env` hook so bash/zsh execute the Cursor
|
|
78
|
+
* wrapper while `args.command` (and therefore the bash UI) stay original.
|
|
79
|
+
*/
|
|
80
|
+
export declare function cursorShellEnvForCall(toolCallId: string | undefined): Record<string, string> | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Strip private wrapper sentinels / OpenCode timeout envelopes for display.
|
|
83
|
+
* Does not record outcomes — use {@link captureCursorShellResult} for that.
|
|
84
|
+
*/
|
|
85
|
+
export declare function sanitizeCursorShellDisplayOutput(output: string, policy?: CursorShellPolicy): string;
|
|
86
|
+
/** Sanitize a secondary display string (e.g. Bash `metadata.output`) for a registered call. */
|
|
87
|
+
export declare function sanitizeRegisteredCursorShellOutput(toolCallId: string, output: string): string;
|
|
39
88
|
/**
|
|
40
89
|
* Capture Bash completion in the classic plugin's after hook. Returns the
|
|
41
90
|
* sanitized output that OpenCode should store and render.
|