@evanovation/open-cursor 2.4.15
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/LICENSE +28 -0
- package/README.md +270 -0
- package/dist/cli/discover.js +527 -0
- package/dist/cli/mcptool.js +10339 -0
- package/dist/cli/opencode-cursor.js +2989 -0
- package/dist/index.js +20588 -0
- package/dist/plugin-entry.js +19848 -0
- package/package.json +82 -0
- package/scripts/cursor-agent-runner.mjs +272 -0
- package/scripts/sdk-runner.mjs +412 -0
- package/src/acp/metrics.ts +83 -0
- package/src/acp/sessions.ts +107 -0
- package/src/acp/tools.ts +209 -0
- package/src/auth.ts +175 -0
- package/src/cli/discover.ts +53 -0
- package/src/cli/mcptool.ts +133 -0
- package/src/cli/model-discovery.ts +71 -0
- package/src/cli/opencode-cursor.ts +1195 -0
- package/src/client/cursor-agent-child.ts +459 -0
- package/src/client/sdk-child.ts +550 -0
- package/src/client/simple.ts +293 -0
- package/src/commands/status.ts +39 -0
- package/src/index.ts +39 -0
- package/src/mcp/client-manager.ts +166 -0
- package/src/mcp/config.ts +169 -0
- package/src/mcp/tool-bridge.ts +133 -0
- package/src/models/config.ts +64 -0
- package/src/models/discovery.ts +105 -0
- package/src/models/index.ts +3 -0
- package/src/models/pricing.ts +196 -0
- package/src/models/sync.ts +247 -0
- package/src/models/types.ts +11 -0
- package/src/models/variants.ts +446 -0
- package/src/plugin-entry.ts +28 -0
- package/src/plugin-toggle.ts +81 -0
- package/src/plugin.ts +2802 -0
- package/src/provider/backend.ts +71 -0
- package/src/provider/boundary.ts +168 -0
- package/src/provider/passthrough-tracker.ts +38 -0
- package/src/provider/runtime-interception.ts +818 -0
- package/src/provider/tool-loop-guard.ts +644 -0
- package/src/provider/tool-schema-compat.ts +800 -0
- package/src/provider.ts +268 -0
- package/src/proxy/formatter.ts +60 -0
- package/src/proxy/handler.ts +29 -0
- package/src/proxy/incremental-prompt.ts +74 -0
- package/src/proxy/prompt-builder.ts +204 -0
- package/src/proxy/server.ts +207 -0
- package/src/proxy/session-resume.ts +312 -0
- package/src/proxy/tool-loop.ts +359 -0
- package/src/proxy/types.ts +13 -0
- package/src/services/toast-service.ts +81 -0
- package/src/streaming/ai-sdk-parts.ts +109 -0
- package/src/streaming/delta-tracker.ts +89 -0
- package/src/streaming/line-buffer.ts +44 -0
- package/src/streaming/openai-sse.ts +118 -0
- package/src/streaming/parser.ts +22 -0
- package/src/streaming/types.ts +158 -0
- package/src/tools/core/executor.ts +25 -0
- package/src/tools/core/registry.ts +27 -0
- package/src/tools/core/types.ts +31 -0
- package/src/tools/defaults.ts +954 -0
- package/src/tools/discovery.ts +140 -0
- package/src/tools/executors/cli.ts +59 -0
- package/src/tools/executors/local.ts +25 -0
- package/src/tools/executors/mcp.ts +39 -0
- package/src/tools/executors/sdk.ts +39 -0
- package/src/tools/index.ts +8 -0
- package/src/tools/registry.ts +34 -0
- package/src/tools/router.ts +123 -0
- package/src/tools/schema.ts +58 -0
- package/src/tools/skills/loader.ts +61 -0
- package/src/tools/skills/resolver.ts +21 -0
- package/src/tools/types.ts +29 -0
- package/src/types.ts +8 -0
- package/src/usage.ts +112 -0
- package/src/utils/binary.ts +71 -0
- package/src/utils/errors.ts +224 -0
- package/src/utils/logger.ts +191 -0
- package/src/utils/perf.ts +76 -0
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evanovation/open-cursor",
|
|
3
|
+
"version": "2.4.15",
|
|
4
|
+
"description": "No prompt limits. No broken streams. Full thinking + tool support. Your Cursor subscription, properly integrated.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/plugin-entry.js",
|
|
7
|
+
"module": "src/plugin-entry.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "bun build ./src/index.ts ./src/plugin-entry.ts ./src/cli/discover.ts ./src/cli/opencode-cursor.ts ./src/cli/mcptool.ts --outdir ./dist --target node --external @opencode-ai/plugin --external zod",
|
|
10
|
+
"dev": "bun build ./src/index.ts ./src/plugin-entry.ts ./src/cli/discover.ts ./src/cli/opencode-cursor.ts ./src/cli/mcptool.ts --outdir ./dist --target node --watch --external @opencode-ai/plugin --external zod",
|
|
11
|
+
"test": "bun test",
|
|
12
|
+
"test:unit": "bun test tests/unit",
|
|
13
|
+
"test:integration": "bun test tests/integration",
|
|
14
|
+
"test:perf": "bun test tests/unit/perf.test.ts tests/unit/utils/logger.test.ts tests/unit/proxy/prompt-builder.test.ts tests/unit/proxy/session-resume.test.ts tests/unit/proxy/incremental-prompt.test.ts tests/unit/proxy/plugin-resume.test.ts tests/unit/cursor-agent-child.test.ts tests/unit/cursor-agent-runner.test.ts tests/unit/streaming/line-buffer.test.ts tests/unit/streaming/parser.test.ts tests/unit/streaming/delta-tracker.test.ts tests/unit/streaming/openai-sse.test.ts tests/integration/sdk-demux-roundtrip.test.ts",
|
|
15
|
+
"test:ci:unit": "bun test tests/tools/defaults.test.ts tests/tools/executor-chain.test.ts tests/tools/sdk-executor.test.ts tests/tools/mcp-executor.test.ts tests/tools/skills.test.ts tests/tools/registry.test.ts tests/unit/cli/opencode-cursor.test.ts tests/unit/cli/model-discovery.test.ts tests/unit/cursor-agent-child.test.ts tests/unit/cursor-agent-pool.test.ts tests/unit/cursor-agent-runner.test.ts tests/unit/errors.test.ts tests/unit/models/discovery.test.ts tests/unit/proxy/prompt-builder.test.ts tests/unit/proxy/tool-loop.test.ts tests/unit/proxy/session-resume.test.ts tests/unit/proxy/incremental-prompt.test.ts tests/unit/proxy/plugin-resume.test.ts tests/unit/provider-backend.test.ts tests/unit/provider-boundary.test.ts tests/unit/provider-runtime-interception.test.ts tests/unit/provider-tool-schema-compat.test.ts tests/unit/provider-tool-loop-guard.test.ts tests/unit/mcp/tool-bridge.test.ts tests/unit/sdk-child.test.ts tests/unit/sdk-runner.test.ts tests/unit/plugin.test.ts tests/unit/plugin-tools-hook.test.ts tests/unit/plugin-tool-resolution.test.ts tests/unit/plugin-config.test.ts tests/unit/plugin-stream-extraction.test.ts tests/unit/auth.test.ts tests/unit/streaming/line-buffer.test.ts tests/unit/streaming/parser.test.ts tests/unit/streaming/types.test.ts tests/unit/streaming/delta-tracker.test.ts tests/unit/streaming/openai-sse.test.ts tests/unit/streaming/ai-sdk-parts.test.ts tests/competitive/edge.test.ts",
|
|
16
|
+
"test:ci:integration": "bun test tests/integration/comprehensive.test.ts tests/integration/tools-router.integration.test.ts tests/integration/stream-router.integration.test.ts tests/integration/opencode-loop.integration.test.ts",
|
|
17
|
+
"verify:issue-92": "bash scripts/verify-issue-92.sh",
|
|
18
|
+
"check:pricing": "bun run scripts/check-cursor-pricing-coverage.ts",
|
|
19
|
+
"check:pricing:fixture": "bun run scripts/check-cursor-pricing-coverage.ts --models-file tests/fixtures/cursor-pricing-models.txt --skip-doc-fetch",
|
|
20
|
+
"discover": "bun run src/cli/discover.ts",
|
|
21
|
+
"prepublishOnly": "bun run build"
|
|
22
|
+
},
|
|
23
|
+
"bin": {
|
|
24
|
+
"open-cursor": "dist/cli/opencode-cursor.js",
|
|
25
|
+
"cursor-discover": "dist/cli/discover.js",
|
|
26
|
+
"mcptool": "dist/cli/mcptool.js"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"bun": "./src/plugin-entry.ts",
|
|
31
|
+
"import": "./dist/plugin-entry.js",
|
|
32
|
+
"default": "./dist/plugin-entry.js"
|
|
33
|
+
},
|
|
34
|
+
"./lib": {
|
|
35
|
+
"bun": "./src/index.ts",
|
|
36
|
+
"import": "./dist/index.js",
|
|
37
|
+
"default": "./dist/index.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"src",
|
|
43
|
+
"scripts/sdk-runner.mjs",
|
|
44
|
+
"scripts/cursor-agent-runner.mjs"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
48
|
+
"@opencode-ai/plugin": "1.1.53",
|
|
49
|
+
"@opencode-ai/sdk": "1.1.53",
|
|
50
|
+
"ai": "^6.0.55",
|
|
51
|
+
"strip-ansi": "^7.1.0"
|
|
52
|
+
},
|
|
53
|
+
"optionalDependencies": {
|
|
54
|
+
"@cursor/sdk": "^1.0.18"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^22.0.0",
|
|
58
|
+
"typescript": "^5.8.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@opencode-ai/sdk": "^1.0.0",
|
|
62
|
+
"bun-types": "^1.1.0"
|
|
63
|
+
},
|
|
64
|
+
"license": "ISC",
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/EvanNotFound/opencode-cursor.git"
|
|
68
|
+
},
|
|
69
|
+
"homepage": "https://github.com/EvanNotFound/opencode-cursor#readme",
|
|
70
|
+
"bugs": {
|
|
71
|
+
"url": "https://github.com/EvanNotFound/opencode-cursor/issues"
|
|
72
|
+
},
|
|
73
|
+
"keywords": [
|
|
74
|
+
"opencode",
|
|
75
|
+
"cursor",
|
|
76
|
+
"ai",
|
|
77
|
+
"streaming",
|
|
78
|
+
"plugin",
|
|
79
|
+
"cursor-agent"
|
|
80
|
+
],
|
|
81
|
+
"author": "EvanNotFound"
|
|
82
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* cursor-agent-runner.mjs
|
|
4
|
+
*
|
|
5
|
+
* Persistent Node runner for cursor-agent --print invocations.
|
|
6
|
+
* Reads NDJSON from stdin:
|
|
7
|
+
* {"id":"<string>","model":"...","cwd":"...","prompt":"...","resumeChatId?":"...","force?":bool,"cursorAgent?":"..."}
|
|
8
|
+
* Emits wrapped NDJSON to stdout:
|
|
9
|
+
* {"id":"<id>","event":{...StreamJsonEvent...}}
|
|
10
|
+
* {"id":"<id>","done":true,"exitCode":0|1}
|
|
11
|
+
*
|
|
12
|
+
* Requests are processed serially (one cursor-agent child at a time).
|
|
13
|
+
* Diagnostics go to stderr only.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { spawn } from "node:child_process";
|
|
17
|
+
import { pathToFileURL } from "node:url";
|
|
18
|
+
|
|
19
|
+
const RESUME_CHAT_ID_SAFE_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
20
|
+
|
|
21
|
+
const RUNNING_AS_MAIN = process.argv[1]
|
|
22
|
+
? import.meta.url === pathToFileURL(process.argv[1]).href
|
|
23
|
+
: false;
|
|
24
|
+
|
|
25
|
+
const protocolWrite = process.stdout.write.bind(process.stdout);
|
|
26
|
+
if (RUNNING_AS_MAIN) {
|
|
27
|
+
process.stdout.write = (chunk, ...args) => process.stderr.write(chunk, ...args);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function writeProtocolLine(line) {
|
|
31
|
+
return protocolWrite(line);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function emitEvent(id, event) {
|
|
35
|
+
writeProtocolLine(JSON.stringify({ id, event }) + "\n");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function emitDone(id, exitCode) {
|
|
39
|
+
writeProtocolLine(JSON.stringify({ id, done: true, exitCode }) + "\n");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function emitErrorEvent(id, message) {
|
|
43
|
+
emitEvent(id, { type: "error", message });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function emitStderr(id, text) {
|
|
47
|
+
writeProtocolLine(JSON.stringify({ id, stderr: text }) + "\n");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// In-flight request tracking for cancellation. Requests are processed
|
|
51
|
+
// serially (one cursor-agent child at a time), so at most one child is
|
|
52
|
+
// active at any moment. Set in handleRequest on spawn, cleared on child
|
|
53
|
+
// close/error, and read by cancelRequest to kill the active child.
|
|
54
|
+
let currentRequest = null;
|
|
55
|
+
let currentChild = null;
|
|
56
|
+
|
|
57
|
+
async function handleRequest(request) {
|
|
58
|
+
const { id, model, cwd, prompt, resumeChatId, force, cursorAgent } = request;
|
|
59
|
+
|
|
60
|
+
if (!id || !model || !cwd || prompt == null) {
|
|
61
|
+
// Log only field presence and the request id; the request body includes
|
|
62
|
+
// the prompt, which must not be written to logs.
|
|
63
|
+
console.error(
|
|
64
|
+
`[cursor-agent-runner] Invalid request ${id || "<missing>"}: missing fields (model=${!!model} cwd=${!!cwd} prompt=${prompt != null})`,
|
|
65
|
+
);
|
|
66
|
+
emitErrorEvent(id || "unknown", "Missing required fields: id, model, cwd, prompt");
|
|
67
|
+
emitDone(id || "unknown", 1);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const binary = typeof cursorAgent === "string" && cursorAgent.trim() ? cursorAgent.trim() : "cursor-agent";
|
|
72
|
+
const args = [
|
|
73
|
+
"--print",
|
|
74
|
+
"--output-format",
|
|
75
|
+
"stream-json",
|
|
76
|
+
"--stream-partial-output",
|
|
77
|
+
"--workspace",
|
|
78
|
+
cwd,
|
|
79
|
+
"--model",
|
|
80
|
+
model,
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
if (typeof resumeChatId === "string" && resumeChatId.trim() && RESUME_CHAT_ID_SAFE_RE.test(resumeChatId.trim())) {
|
|
84
|
+
args.push("--resume", resumeChatId.trim());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (force) {
|
|
88
|
+
args.push("--force");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.error(`[cursor-agent-runner] Request ${id}: model=${model}, cwd=${cwd}, resume=${!!resumeChatId}`);
|
|
92
|
+
|
|
93
|
+
await new Promise((resolve) => {
|
|
94
|
+
const shell = process.platform === "win32";
|
|
95
|
+
const cmd = shell && binary.includes(" ") ? `"${binary}"` : binary;
|
|
96
|
+
const child = spawn(cmd, args, {
|
|
97
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
98
|
+
shell,
|
|
99
|
+
});
|
|
100
|
+
currentRequest = id;
|
|
101
|
+
currentChild = child;
|
|
102
|
+
|
|
103
|
+
let stderrText = "";
|
|
104
|
+
child.stderr?.on("data", (chunk) => {
|
|
105
|
+
const text = chunk.toString("utf8");
|
|
106
|
+
stderrText += text;
|
|
107
|
+
emitStderr(id, text);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
child.stdin.write(typeof prompt === "string" ? prompt : String(prompt));
|
|
111
|
+
child.stdin.end();
|
|
112
|
+
|
|
113
|
+
let buffer = "";
|
|
114
|
+
child.stdout?.setEncoding("utf8");
|
|
115
|
+
child.stdout?.on("data", (chunk) => {
|
|
116
|
+
buffer += chunk;
|
|
117
|
+
const parts = buffer.split("\n");
|
|
118
|
+
buffer = parts.pop() ?? "";
|
|
119
|
+
for (const line of parts) {
|
|
120
|
+
if (!line.trim()) continue;
|
|
121
|
+
try {
|
|
122
|
+
const event = JSON.parse(line);
|
|
123
|
+
emitEvent(id, event);
|
|
124
|
+
} catch {
|
|
125
|
+
emitEvent(id, { type: "assistant", message: { role: "assistant", content: [{ type: "text", text: line }] } });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
child.on("close", (code) => {
|
|
131
|
+
currentRequest = null;
|
|
132
|
+
currentChild = null;
|
|
133
|
+
if (buffer.trim()) {
|
|
134
|
+
try {
|
|
135
|
+
emitEvent(id, JSON.parse(buffer));
|
|
136
|
+
} catch {
|
|
137
|
+
// ignore trailing garbage
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
console.error(`[cursor-agent-runner] Request ${id} complete exitCode=${code ?? 1}`);
|
|
141
|
+
emitDone(id, code ?? 1);
|
|
142
|
+
resolve();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
child.on("error", (err) => {
|
|
146
|
+
currentRequest = null;
|
|
147
|
+
currentChild = null;
|
|
148
|
+
console.error(`[cursor-agent-runner] Request ${id} spawn error: ${err.message}`);
|
|
149
|
+
emitErrorEvent(id, err.message);
|
|
150
|
+
if (stderrText.trim()) {
|
|
151
|
+
emitStderr(id, stderrText.trim());
|
|
152
|
+
}
|
|
153
|
+
emitDone(id, 1);
|
|
154
|
+
resolve();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function main() {
|
|
160
|
+
console.error("[cursor-agent-runner] Waiting for requests on stdin...");
|
|
161
|
+
|
|
162
|
+
const queue = [];
|
|
163
|
+
let processing = false;
|
|
164
|
+
|
|
165
|
+
const pump = async () => {
|
|
166
|
+
if (processing) return;
|
|
167
|
+
processing = true;
|
|
168
|
+
try {
|
|
169
|
+
while (queue.length > 0) {
|
|
170
|
+
const request = queue.shift();
|
|
171
|
+
try {
|
|
172
|
+
await handleRequest(request);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
const id = request?.id || "unknown";
|
|
175
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
176
|
+
console.error(`[cursor-agent-runner] Unhandled error in request ${id}: ${message}`);
|
|
177
|
+
emitErrorEvent(id, message);
|
|
178
|
+
emitDone(id, 1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} finally {
|
|
182
|
+
processing = false;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const enqueue = (request) => {
|
|
187
|
+
queue.push(request);
|
|
188
|
+
void pump();
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Cancel an in-flight or queued request. The pool child's kill() sends a
|
|
192
|
+
// {cancel: id} control line; without this, an aborted/intercepted
|
|
193
|
+
// cursor-agent request would run to completion and block the serial queue
|
|
194
|
+
// behind it. Killing the active child lets its close handler emit done
|
|
195
|
+
// promptly; a still-queued request is dropped with a synthetic done so the
|
|
196
|
+
// waiting caller resolves instead of hanging.
|
|
197
|
+
const cancelRequest = (id) => {
|
|
198
|
+
if (id && id === currentRequest && currentChild) {
|
|
199
|
+
try {
|
|
200
|
+
currentChild.kill("SIGKILL");
|
|
201
|
+
} catch (err) {
|
|
202
|
+
console.error(`[cursor-agent-runner] cancel kill failed for ${id}: ${err.message}`);
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const idx = queue.findIndex((r) => r && r.id === id);
|
|
207
|
+
if (idx >= 0) {
|
|
208
|
+
queue.splice(idx, 1);
|
|
209
|
+
console.error(`[cursor-agent-runner] Cancelled queued request ${id}`);
|
|
210
|
+
emitDone(id, 1);
|
|
211
|
+
}
|
|
212
|
+
// else: unknown or already completed — nothing to cancel.
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// Parse one stdin line and route it: a {cancel: "<id>"} control message
|
|
216
|
+
// cancels a request; anything else is enqueued as a request.
|
|
217
|
+
const dispatchLine = (text) => {
|
|
218
|
+
let parsed;
|
|
219
|
+
try {
|
|
220
|
+
parsed = JSON.parse(text);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
console.error(`[cursor-agent-runner] Failed to parse NDJSON line: ${err.message}`);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (parsed && typeof parsed.cancel === "string") {
|
|
226
|
+
cancelRequest(parsed.cancel);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
enqueue(parsed);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
let buffer = "";
|
|
233
|
+
await new Promise((resolveEnd, rejectEnd) => {
|
|
234
|
+
process.stdin.setEncoding("utf8");
|
|
235
|
+
process.stdin.on("data", (chunk) => {
|
|
236
|
+
buffer += chunk;
|
|
237
|
+
const parts = buffer.split("\n");
|
|
238
|
+
buffer = parts.pop() ?? "";
|
|
239
|
+
for (const part of parts) {
|
|
240
|
+
if (!part.trim()) continue;
|
|
241
|
+
dispatchLine(part);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
process.stdin.on("end", () => {
|
|
245
|
+
if (buffer.trim()) {
|
|
246
|
+
dispatchLine(buffer);
|
|
247
|
+
}
|
|
248
|
+
resolveEnd();
|
|
249
|
+
});
|
|
250
|
+
process.stdin.on("error", rejectEnd);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
while (queue.length > 0 || processing) {
|
|
254
|
+
await pump();
|
|
255
|
+
if (queue.length > 0 || processing) {
|
|
256
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.error("[cursor-agent-runner] Shutting down");
|
|
261
|
+
await new Promise((resolve) => protocolWrite("", resolve));
|
|
262
|
+
process.exit(0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (RUNNING_AS_MAIN) {
|
|
266
|
+
main().catch((err) => {
|
|
267
|
+
console.error(`[cursor-agent-runner] Fatal: ${err.message}`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export { RESUME_CHAT_ID_SAFE_RE, emitDone, emitEvent, emitErrorEvent };
|