@jasonews/agent-squad-gateway 1.0.0
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 +22 -0
- package/README.md +200 -0
- package/SECURITY.md +44 -0
- package/dist/bin/agent-squad-gateway.js +55 -0
- package/dist/bin/agent-squad-gateway.js.map +1 -0
- package/dist/config/config.js +124 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/paths.js +16 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/control-plane/clients.js +77 -0
- package/dist/control-plane/clients.js.map +1 -0
- package/dist/control-plane/core-connection.js +54 -0
- package/dist/control-plane/core-connection.js.map +1 -0
- package/dist/control-plane/credentials.js +134 -0
- package/dist/control-plane/credentials.js.map +1 -0
- package/dist/control-plane/db.js +33 -0
- package/dist/control-plane/db.js.map +1 -0
- package/dist/control-plane/extensions.js +59 -0
- package/dist/control-plane/extensions.js.map +1 -0
- package/dist/control-plane/grants.js +107 -0
- package/dist/control-plane/grants.js.map +1 -0
- package/dist/control-plane/idempotency.js +132 -0
- package/dist/control-plane/idempotency.js.map +1 -0
- package/dist/control-plane/migrations.js +133 -0
- package/dist/control-plane/migrations.js.map +1 -0
- package/dist/control-plane/response-sessions.js +359 -0
- package/dist/control-plane/response-sessions.js.map +1 -0
- package/dist/control-plane/retention.js +138 -0
- package/dist/control-plane/retention.js.map +1 -0
- package/dist/control-plane/runs.js +156 -0
- package/dist/control-plane/runs.js.map +1 -0
- package/dist/control-plane/targets.js +449 -0
- package/dist/control-plane/targets.js.map +1 -0
- package/dist/control-plane/types.js +2 -0
- package/dist/control-plane/types.js.map +1 -0
- package/dist/core-client/client.js +275 -0
- package/dist/core-client/client.js.map +1 -0
- package/dist/core-client/event-proxy.js +105 -0
- package/dist/core-client/event-proxy.js.map +1 -0
- package/dist/core-client/types.js +2 -0
- package/dist/core-client/types.js.map +1 -0
- package/dist/extensions/contract.js +2 -0
- package/dist/extensions/contract.js.map +1 -0
- package/dist/extensions/openai/auth.js +16 -0
- package/dist/extensions/openai/auth.js.map +1 -0
- package/dist/extensions/openai/chat.js +403 -0
- package/dist/extensions/openai/chat.js.map +1 -0
- package/dist/extensions/openai/errors.js +79 -0
- package/dist/extensions/openai/errors.js.map +1 -0
- package/dist/extensions/openai/image-input.js +79 -0
- package/dist/extensions/openai/image-input.js.map +1 -0
- package/dist/extensions/openai/models.js +40 -0
- package/dist/extensions/openai/models.js.map +1 -0
- package/dist/extensions/openai/responses.js +731 -0
- package/dist/extensions/openai/responses.js.map +1 -0
- package/dist/extensions/openai/routes.js +81 -0
- package/dist/extensions/openai/routes.js.map +1 -0
- package/dist/extensions/openai/run-attempt.js +96 -0
- package/dist/extensions/openai/run-attempt.js.map +1 -0
- package/dist/extensions/openai/schemas.js +176 -0
- package/dist/extensions/openai/schemas.js.map +1 -0
- package/dist/extensions/openai/sse.js +421 -0
- package/dist/extensions/openai/sse.js.map +1 -0
- package/dist/extensions/openai/tools.js +727 -0
- package/dist/extensions/openai/tools.js.map +1 -0
- package/dist/extensions/registry.js +30 -0
- package/dist/extensions/registry.js.map +1 -0
- package/dist/lifecycle/daemon.js +437 -0
- package/dist/lifecycle/daemon.js.map +1 -0
- package/dist/lifecycle/pidfile.js +34 -0
- package/dist/lifecycle/pidfile.js.map +1 -0
- package/dist/provider-runtime/antigravity/adapter.js +398 -0
- package/dist/provider-runtime/antigravity/adapter.js.map +1 -0
- package/dist/provider-runtime/antigravity/conversation.js +31 -0
- package/dist/provider-runtime/antigravity/conversation.js.map +1 -0
- package/dist/provider-runtime/capability-service.js +191 -0
- package/dist/provider-runtime/capability-service.js.map +1 -0
- package/dist/provider-runtime/claude/adapter.js +397 -0
- package/dist/provider-runtime/claude/adapter.js.map +1 -0
- package/dist/provider-runtime/claude/protocol.js +143 -0
- package/dist/provider-runtime/claude/protocol.js.map +1 -0
- package/dist/provider-runtime/codex/adapter.js +440 -0
- package/dist/provider-runtime/codex/adapter.js.map +1 -0
- package/dist/provider-runtime/codex/json-rpc-client.js +182 -0
- package/dist/provider-runtime/codex/json-rpc-client.js.map +1 -0
- package/dist/provider-runtime/codex/protocol.js +128 -0
- package/dist/provider-runtime/codex/protocol.js.map +1 -0
- package/dist/provider-runtime/command-discovery.js +106 -0
- package/dist/provider-runtime/command-discovery.js.map +1 -0
- package/dist/provider-runtime/cursor/adapter.js +427 -0
- package/dist/provider-runtime/cursor/adapter.js.map +1 -0
- package/dist/provider-runtime/cursor/protocol.js +81 -0
- package/dist/provider-runtime/cursor/protocol.js.map +1 -0
- package/dist/provider-runtime/fake/adapter.js +138 -0
- package/dist/provider-runtime/fake/adapter.js.map +1 -0
- package/dist/provider-runtime/image-assets.js +409 -0
- package/dist/provider-runtime/image-assets.js.map +1 -0
- package/dist/provider-runtime/image-support.js +5 -0
- package/dist/provider-runtime/image-support.js.map +1 -0
- package/dist/provider-runtime/invocation-service.js +503 -0
- package/dist/provider-runtime/invocation-service.js.map +1 -0
- package/dist/provider-runtime/kimi/adapter.js +657 -0
- package/dist/provider-runtime/kimi/adapter.js.map +1 -0
- package/dist/provider-runtime/opencode/adapter.js +610 -0
- package/dist/provider-runtime/opencode/adapter.js.map +1 -0
- package/dist/provider-runtime/opencode/server.js +46 -0
- package/dist/provider-runtime/opencode/server.js.map +1 -0
- package/dist/provider-runtime/process/line-reader.js +49 -0
- package/dist/provider-runtime/process/line-reader.js.map +1 -0
- package/dist/provider-runtime/process/managed-process.js +151 -0
- package/dist/provider-runtime/process/managed-process.js.map +1 -0
- package/dist/provider-runtime/provider-input.js +77 -0
- package/dist/provider-runtime/provider-input.js.map +1 -0
- package/dist/provider-runtime/register-providers.js +26 -0
- package/dist/provider-runtime/register-providers.js.map +1 -0
- package/dist/provider-runtime/registry.js +35 -0
- package/dist/provider-runtime/registry.js.map +1 -0
- package/dist/provider-runtime/replay-buffer.js +168 -0
- package/dist/provider-runtime/replay-buffer.js.map +1 -0
- package/dist/provider-runtime/scheduler.js +155 -0
- package/dist/provider-runtime/scheduler.js.map +1 -0
- package/dist/provider-runtime/types.js +2 -0
- package/dist/provider-runtime/types.js.map +1 -0
- package/dist/provider-runtime/workspaces.js +814 -0
- package/dist/provider-runtime/workspaces.js.map +1 -0
- package/dist/security/admin-auth.js +109 -0
- package/dist/security/admin-auth.js.map +1 -0
- package/dist/security/crypto.js +52 -0
- package/dist/security/crypto.js.map +1 -0
- package/dist/security/secret-files.js +33 -0
- package/dist/security/secret-files.js.map +1 -0
- package/dist/server/admin-routes.js +610 -0
- package/dist/server/admin-routes.js.map +1 -0
- package/dist/server/app.js +178 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/auth-hooks.js +43 -0
- package/dist/server/auth-hooks.js.map +1 -0
- package/dist/server/core-routes.js +127 -0
- package/dist/server/core-routes.js.map +1 -0
- package/dist/server/errors.js +19 -0
- package/dist/server/errors.js.map +1 -0
- package/dist/server/ui-routes.js +77 -0
- package/dist/server/ui-routes.js.map +1 -0
- package/dist/web/assets/index-BhqNoPpE.js +206 -0
- package/dist/web/assets/index-BhqNoPpE.js.map +1 -0
- package/dist/web/assets/index-C5nnaBfZ.css +1 -0
- package/dist/web/index.html +14 -0
- package/package.json +74 -0
- package/translations/README.zh-CN.md +175 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
export const CODEX_IGNORED_NOTIFICATION_METHODS = [
|
|
2
|
+
'account/rateLimits/updated',
|
|
3
|
+
'hook/completed',
|
|
4
|
+
'hook/started',
|
|
5
|
+
'item/reasoning/summaryPartAdded',
|
|
6
|
+
'item/reasoning/summaryTextDelta',
|
|
7
|
+
'item/reasoning/textDelta',
|
|
8
|
+
'mcpServer/startupStatus/updated',
|
|
9
|
+
'remoteControl/status/changed',
|
|
10
|
+
'thread/goal/cleared',
|
|
11
|
+
'thread/started',
|
|
12
|
+
'thread/status/changed',
|
|
13
|
+
'thread/tokenUsage/updated',
|
|
14
|
+
'turn/started',
|
|
15
|
+
'warning',
|
|
16
|
+
];
|
|
17
|
+
const IGNORED_NOTIFICATION_METHODS = new Set(CODEX_IGNORED_NOTIFICATION_METHODS);
|
|
18
|
+
export class CodexAdapterError extends Error {
|
|
19
|
+
code;
|
|
20
|
+
constructor(code) {
|
|
21
|
+
super(code);
|
|
22
|
+
this.code = code;
|
|
23
|
+
this.name = 'CodexAdapterError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function isRecord(value) {
|
|
27
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
28
|
+
}
|
|
29
|
+
function hasString(record, key) {
|
|
30
|
+
return typeof record[key] === 'string' && record[key].length > 0;
|
|
31
|
+
}
|
|
32
|
+
export function parseCodexNotification(value) {
|
|
33
|
+
const method = value.method;
|
|
34
|
+
const params = value.params;
|
|
35
|
+
if (method === 'item/agentMessage/delta' && isRecord(params)
|
|
36
|
+
&& hasString(params, 'threadId') && hasString(params, 'turnId')
|
|
37
|
+
&& hasString(params, 'itemId') && typeof params.delta === 'string') {
|
|
38
|
+
return {
|
|
39
|
+
method,
|
|
40
|
+
params: {
|
|
41
|
+
threadId: params.threadId,
|
|
42
|
+
turnId: params.turnId,
|
|
43
|
+
itemId: params.itemId,
|
|
44
|
+
delta: params.delta,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if ((method === 'item/started' || method === 'item/completed') && isRecord(params)
|
|
49
|
+
&& hasString(params, 'threadId') && hasString(params, 'turnId')
|
|
50
|
+
&& isRecord(params.item) && hasString(params.item, 'type')) {
|
|
51
|
+
return {
|
|
52
|
+
method,
|
|
53
|
+
params: {
|
|
54
|
+
threadId: params.threadId,
|
|
55
|
+
turnId: params.turnId,
|
|
56
|
+
item: { type: params.item.type },
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (method === 'turn/completed' && isRecord(params)
|
|
61
|
+
&& hasString(params, 'threadId') && isRecord(params.turn)
|
|
62
|
+
&& hasString(params.turn, 'id')
|
|
63
|
+
&& (params.turn.status === 'completed'
|
|
64
|
+
|| params.turn.status === 'interrupted'
|
|
65
|
+
|| params.turn.status === 'failed')) {
|
|
66
|
+
return {
|
|
67
|
+
method,
|
|
68
|
+
params: {
|
|
69
|
+
threadId: params.threadId,
|
|
70
|
+
turn: {
|
|
71
|
+
id: params.turn.id,
|
|
72
|
+
status: params.turn.status,
|
|
73
|
+
error: params.turn.error,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (method === 'error')
|
|
79
|
+
return { method, params };
|
|
80
|
+
if (typeof method === 'string' && IGNORED_NOTIFICATION_METHODS.has(method) && isRecord(params)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
throw new CodexAdapterError('adapter_protocol_error');
|
|
84
|
+
}
|
|
85
|
+
export function parseThreadResult(value) {
|
|
86
|
+
if (!isRecord(value) || !isRecord(value.thread) || !hasString(value.thread, 'id')) {
|
|
87
|
+
throw new CodexAdapterError('adapter_protocol_error');
|
|
88
|
+
}
|
|
89
|
+
return { thread: { id: value.thread.id } };
|
|
90
|
+
}
|
|
91
|
+
export function parseTurnResult(value) {
|
|
92
|
+
if (!isRecord(value) || !isRecord(value.turn) || !hasString(value.turn, 'id')) {
|
|
93
|
+
throw new CodexAdapterError('adapter_protocol_error');
|
|
94
|
+
}
|
|
95
|
+
return { turn: { id: value.turn.id } };
|
|
96
|
+
}
|
|
97
|
+
export function parseModelListResult(value) {
|
|
98
|
+
if (!isRecord(value) || !Array.isArray(value.data)) {
|
|
99
|
+
throw new CodexAdapterError('adapter_protocol_error');
|
|
100
|
+
}
|
|
101
|
+
const data = value.data.map((model) => {
|
|
102
|
+
if (!isRecord(model) || !hasString(model, 'id') || !hasString(model, 'displayName')) {
|
|
103
|
+
throw new CodexAdapterError('adapter_protocol_error');
|
|
104
|
+
}
|
|
105
|
+
const efforts = parseReasoningEfforts(model.supportedReasoningEfforts);
|
|
106
|
+
return {
|
|
107
|
+
id: model.id,
|
|
108
|
+
displayName: model.displayName,
|
|
109
|
+
supportedReasoningEfforts: efforts,
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
return { data };
|
|
113
|
+
}
|
|
114
|
+
function parseReasoningEfforts(value) {
|
|
115
|
+
if (value === null)
|
|
116
|
+
return null;
|
|
117
|
+
if (!Array.isArray(value))
|
|
118
|
+
throw new CodexAdapterError('adapter_protocol_error');
|
|
119
|
+
return value.map((effort) => {
|
|
120
|
+
if (typeof effort === 'string' && effort.length > 0)
|
|
121
|
+
return effort;
|
|
122
|
+
if (isRecord(effort) && hasString(effort, 'reasoningEffort')) {
|
|
123
|
+
return effort.reasoningEffort;
|
|
124
|
+
}
|
|
125
|
+
throw new CodexAdapterError('adapter_protocol_error');
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/provider-runtime/codex/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { accessSync, constants, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, extname, isAbsolute, join, resolve } from 'node:path';
|
|
4
|
+
export function providerBinDirectories(options = {}) {
|
|
5
|
+
const env = options.env ?? process.env;
|
|
6
|
+
const platform = options.platform ?? process.platform;
|
|
7
|
+
const separator = platform === 'win32' ? ';' : ':';
|
|
8
|
+
const home = options.homeDir ?? env.HOME ?? env.USERPROFILE ?? homedir();
|
|
9
|
+
const directories = [];
|
|
10
|
+
const seen = new Set();
|
|
11
|
+
const add = (directory, requireDirectory) => {
|
|
12
|
+
if (!directory)
|
|
13
|
+
return;
|
|
14
|
+
const key = platform === 'win32' ? directory.toLowerCase() : directory;
|
|
15
|
+
if (seen.has(key) || (requireDirectory && !isDirectory(directory)))
|
|
16
|
+
return;
|
|
17
|
+
seen.add(key);
|
|
18
|
+
directories.push(directory);
|
|
19
|
+
};
|
|
20
|
+
for (const directory of (env.PATH ?? '').split(separator))
|
|
21
|
+
add(directory, false);
|
|
22
|
+
add(dirname(options.execPath ?? process.execPath), true);
|
|
23
|
+
add(prefixBin(env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX, platform), true);
|
|
24
|
+
add(env.NVM_BIN, true);
|
|
25
|
+
add(env.PNPM_HOME, true);
|
|
26
|
+
add(env.VOLTA_HOME ? join(env.VOLTA_HOME, 'bin') : undefined, true);
|
|
27
|
+
add(env.BUN_INSTALL ? join(env.BUN_INSTALL, 'bin') : undefined, true);
|
|
28
|
+
const asdfData = env.ASDF_DATA_DIR ?? join(home, '.asdf');
|
|
29
|
+
const commonDirectories = [
|
|
30
|
+
join(home, '.local', 'bin'),
|
|
31
|
+
join(home, '.npm-global', 'bin'),
|
|
32
|
+
join(home, '.npm', 'bin'),
|
|
33
|
+
join(home, '.volta', 'bin'),
|
|
34
|
+
join(home, '.bun', 'bin'),
|
|
35
|
+
join(home, 'Library', 'pnpm'),
|
|
36
|
+
join(asdfData, 'shims'),
|
|
37
|
+
join(home, '.mise', 'shims'),
|
|
38
|
+
join(home, '.local', 'share', 'mise', 'shims'),
|
|
39
|
+
];
|
|
40
|
+
for (const directory of commonDirectories)
|
|
41
|
+
add(directory, true);
|
|
42
|
+
addVersionedBins(join(home, '.nvm', 'versions', 'node'), ['bin'], add);
|
|
43
|
+
addVersionedBins(join(asdfData, 'installs', 'nodejs'), ['bin'], add);
|
|
44
|
+
addVersionedBins(join(home, '.fnm', 'node-versions'), ['installation', 'bin'], add);
|
|
45
|
+
addVersionedBins(join(home, '.local', 'share', 'fnm', 'node-versions'), ['installation', 'bin'], add);
|
|
46
|
+
addVersionedBins(join(home, '.local', 'share', 'mise', 'installs', 'node'), ['bin'], add);
|
|
47
|
+
return directories;
|
|
48
|
+
}
|
|
49
|
+
export function installProviderSearchPath(env = process.env, options = {}) {
|
|
50
|
+
const platform = options.platform ?? process.platform;
|
|
51
|
+
const value = providerBinDirectories({ ...options, env }).join(platform === 'win32' ? ';' : ':');
|
|
52
|
+
env.PATH = value;
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
export function resolveProviderCommand(command, options = {}) {
|
|
56
|
+
const env = options.env ?? process.env;
|
|
57
|
+
const platform = options.platform ?? process.platform;
|
|
58
|
+
const names = commandNames(command, env, platform);
|
|
59
|
+
const candidates = isAbsolute(command)
|
|
60
|
+
? names
|
|
61
|
+
: providerBinDirectories({ ...options, env }).flatMap((directory) => names.map((name) => resolve(directory, name)));
|
|
62
|
+
const accessMode = platform === 'win32' ? constants.F_OK : constants.X_OK;
|
|
63
|
+
for (const candidate of candidates) {
|
|
64
|
+
try {
|
|
65
|
+
accessSync(candidate, accessMode);
|
|
66
|
+
return candidate;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Continue through the deterministic provider search path.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
function prefixBin(prefix, platform) {
|
|
75
|
+
if (!prefix)
|
|
76
|
+
return undefined;
|
|
77
|
+
return platform === 'win32' ? prefix : join(prefix, 'bin');
|
|
78
|
+
}
|
|
79
|
+
function commandNames(command, env, platform) {
|
|
80
|
+
if (platform !== 'win32' || extname(command))
|
|
81
|
+
return [command];
|
|
82
|
+
return (env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM')
|
|
83
|
+
.split(';')
|
|
84
|
+
.filter(Boolean)
|
|
85
|
+
.map((extension) => `${command}${extension.toLowerCase()}`);
|
|
86
|
+
}
|
|
87
|
+
function isDirectory(path) {
|
|
88
|
+
try {
|
|
89
|
+
return statSync(path).isDirectory();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function addVersionedBins(root, suffix, add) {
|
|
96
|
+
let versions;
|
|
97
|
+
try {
|
|
98
|
+
versions = readdirSync(root).sort().reverse();
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
for (const version of versions)
|
|
104
|
+
add(join(root, version, ...suffix), true);
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=command-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-discovery.js","sourceRoot":"","sources":["../../src/provider-runtime/command-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASxE,MAAM,UAAU,sBAAsB,CACpC,UAA2C,EAAE;IAE7C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACtD,MAAM,SAAS,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACnD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,WAAW,IAAI,OAAO,EAAE,CAAC;IACzE,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAG,CAAC,SAA6B,EAAE,gBAAyB,EAAQ,EAAE;QAC7E,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,MAAM,GAAG,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YAAE,OAAO;QAC3E,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;QAAE,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAEjF,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IACzD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/E,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACzB,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACpE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEtE,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,iBAAiB,GAAG;QACxB,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;QACzB,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;QACzB,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC;QAC7B,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;QAC5B,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;KAC/C,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,iBAAiB;QAAE,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEhE,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACvE,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACrE,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC,cAAc,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACpF,gBAAgB,CACd,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,EACrD,CAAC,cAAc,EAAE,KAAK,CAAC,EACvB,GAAG,CACJ,CAAC;IACF,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IAE1F,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAyB,OAAO,CAAC,GAAG,EACpC,UAAwD,EAAE;IAE1D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACtD,MAAM,KAAK,GAAG,sBAAsB,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjG,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC;IACjB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,OAAe,EACf,UAA2C,EAAE;IAE7C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC;QACpC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,sBAAsB,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAClE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC;IAE1E,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;YAClC,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAAC,MAA0B,EAAE,QAAyB;IACtE,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,YAAY,CACnB,OAAe,EACf,GAAsB,EACtB,QAAyB;IAEzB,IAAI,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,qBAAqB,CAAC;SAC1C,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,OAAO,GAAG,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CACvB,IAAY,EACZ,MAAgB,EAChB,GAA2D;IAE3D,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { renderProviderInput } from '../provider-input.js';
|
|
3
|
+
import { readBoundedLines } from '../process/line-reader.js';
|
|
4
|
+
import { spawnManagedProcess, } from '../process/managed-process.js';
|
|
5
|
+
import { CursorAdapterError, cursorAssistantText, parseCursorEvent, } from './protocol.js';
|
|
6
|
+
const COMMAND_OUTPUT_LIMIT_BYTES = 64 * 1024;
|
|
7
|
+
const ANSI_ESCAPE = /\u001b\[[0-?]*[ -/]*[@-~]/g;
|
|
8
|
+
const REQUIRED_HELP_FLAGS = [
|
|
9
|
+
'--print',
|
|
10
|
+
'--output-format',
|
|
11
|
+
'--stream-partial-output',
|
|
12
|
+
'--mode',
|
|
13
|
+
'--resume',
|
|
14
|
+
'--model',
|
|
15
|
+
'--list-models',
|
|
16
|
+
'--sandbox',
|
|
17
|
+
'--trust',
|
|
18
|
+
];
|
|
19
|
+
const CONFORMANCE_SCHEMA = {
|
|
20
|
+
type: 'object',
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
properties: {
|
|
23
|
+
type: { const: 'assistant_text' },
|
|
24
|
+
content: { type: 'string', minLength: 1 },
|
|
25
|
+
},
|
|
26
|
+
required: ['type', 'content'],
|
|
27
|
+
};
|
|
28
|
+
const conformanceOutputSchema = z.object({
|
|
29
|
+
type: z.literal('assistant_text'),
|
|
30
|
+
content: z.string().min(1),
|
|
31
|
+
}).strict();
|
|
32
|
+
export const CURSOR_SANDBOX_WARNING = 'Cursor Agent runs in Ask mode with its sandbox enabled, but the CLI has no no-tools flag; Gateway rejects every native tool event.';
|
|
33
|
+
export const CURSOR_SESSION_WARNING = 'Cursor Agent has no no-session-persistence flag, so provider-native chat state may outlive an ephemeral Gateway request.';
|
|
34
|
+
export const CURSOR_TOOL_BRIDGE_WARNING = 'Cursor client tools use a Gateway JSON protocol because cursor-agent has no native output-schema flag; malformed model output is rejected.';
|
|
35
|
+
function capabilities(metadata, verified, streamingMode = 'native') {
|
|
36
|
+
return {
|
|
37
|
+
available: true,
|
|
38
|
+
version: metadata.version,
|
|
39
|
+
verified,
|
|
40
|
+
...(verified ? { verifiedAt: new Date().toISOString() } : {}),
|
|
41
|
+
modelSelection: true,
|
|
42
|
+
effortSelection: false,
|
|
43
|
+
modelOptions: metadata.models.map((model) => ({ ...model, effortOptions: null })),
|
|
44
|
+
isolationLevel: 'best_effort',
|
|
45
|
+
streamingMode,
|
|
46
|
+
toolBridge: 'structured_output',
|
|
47
|
+
resume: true,
|
|
48
|
+
cancellation: true,
|
|
49
|
+
details: [CURSOR_SANDBOX_WARNING, CURSOR_SESSION_WARNING, CURSOR_TOOL_BRIDGE_WARNING],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function unavailable(error) {
|
|
53
|
+
return {
|
|
54
|
+
available: false,
|
|
55
|
+
verified: false,
|
|
56
|
+
modelSelection: false,
|
|
57
|
+
effortSelection: false,
|
|
58
|
+
isolationLevel: 'best_effort',
|
|
59
|
+
streamingMode: 'none',
|
|
60
|
+
toolBridge: 'none',
|
|
61
|
+
resume: false,
|
|
62
|
+
cancellation: false,
|
|
63
|
+
error,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function errorCode(error) {
|
|
67
|
+
if (error instanceof CursorAdapterError)
|
|
68
|
+
return error.code;
|
|
69
|
+
if (typeof error !== 'object' || error === null || !('code' in error))
|
|
70
|
+
return null;
|
|
71
|
+
return error.code === 'adapter_spawn_failed' || error.code === 'adapter_process_error'
|
|
72
|
+
? String(error.code)
|
|
73
|
+
: null;
|
|
74
|
+
}
|
|
75
|
+
function safeProbeError(error) {
|
|
76
|
+
return errorCode(error) ?? 'capability_probe_failed';
|
|
77
|
+
}
|
|
78
|
+
function failureEvent(error, nativeStateAdvanced) {
|
|
79
|
+
const knownCode = errorCode(error);
|
|
80
|
+
const code = knownCode === 'adapter_spawn_failed' || knownCode === 'adapter_process_error'
|
|
81
|
+
? knownCode
|
|
82
|
+
: 'adapter_protocol_error';
|
|
83
|
+
return {
|
|
84
|
+
type: 'failed',
|
|
85
|
+
code,
|
|
86
|
+
message: code === 'adapter_protocol_error'
|
|
87
|
+
? 'Cursor provider protocol error'
|
|
88
|
+
: 'Cursor provider process error',
|
|
89
|
+
nativeStateAdvanced,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function disposeQuietly(managed) {
|
|
93
|
+
try {
|
|
94
|
+
await managed.dispose();
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// The print process may exit while process-group cleanup is in progress.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function writeInput(managed, input) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const onError = () => reject(Object.assign(new Error('adapter_process_error'), {
|
|
103
|
+
code: 'adapter_process_error',
|
|
104
|
+
}));
|
|
105
|
+
managed.stdin.once('error', onError);
|
|
106
|
+
managed.stdin.end(input, () => {
|
|
107
|
+
managed.stdin.removeListener('error', onError);
|
|
108
|
+
resolve();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
export function parseCursorModels(output) {
|
|
113
|
+
const models = [];
|
|
114
|
+
const seen = new Set();
|
|
115
|
+
for (const rawLine of output.replace(ANSI_ESCAPE, '').split(/\r?\n/)) {
|
|
116
|
+
const line = rawLine.trim();
|
|
117
|
+
if (line.length === 0 || /^available models$/i.test(line) || /^tip:/i.test(line))
|
|
118
|
+
continue;
|
|
119
|
+
const separator = line.indexOf(' - ');
|
|
120
|
+
if (separator <= 0)
|
|
121
|
+
continue;
|
|
122
|
+
const id = line.slice(0, separator).trim();
|
|
123
|
+
const label = line.slice(separator + 3).trim();
|
|
124
|
+
if (!/^\S+$/.test(id) || label.length === 0 || seen.has(id))
|
|
125
|
+
continue;
|
|
126
|
+
seen.add(id);
|
|
127
|
+
models.push({ id, label, effortOptions: null });
|
|
128
|
+
}
|
|
129
|
+
if (models.length === 0)
|
|
130
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
131
|
+
return models;
|
|
132
|
+
}
|
|
133
|
+
export function renderCursorPrompt(request) {
|
|
134
|
+
const transcript = renderProviderInput(request.input);
|
|
135
|
+
const sections = [
|
|
136
|
+
[
|
|
137
|
+
'Complete the API conversation below as a single assistant turn.',
|
|
138
|
+
'Answer only from the supplied conversation and do not use tools, shell commands, files, browsers,',
|
|
139
|
+
'external integrations, skills, plugins, hooks, or agents during this turn.',
|
|
140
|
+
].join(' '),
|
|
141
|
+
`API conversation:\n${transcript}`,
|
|
142
|
+
];
|
|
143
|
+
if (request.outputSchema !== null) {
|
|
144
|
+
sections.push(`Required response schema:\n${JSON.stringify(request.outputSchema)}`, [
|
|
145
|
+
'Client functions are descriptions only; represent a client function call through the response schema',
|
|
146
|
+
'and do not execute it or use native tools.',
|
|
147
|
+
'Return exactly one raw JSON object that validates against the required response schema.',
|
|
148
|
+
'Do not add Markdown fences, commentary, reasoning, or any text before or after that JSON object.',
|
|
149
|
+
].join(' '));
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
sections.push('Return only the assistant response. Do not use native tools or add protocol markup.');
|
|
153
|
+
}
|
|
154
|
+
return sections.join('\n\n');
|
|
155
|
+
}
|
|
156
|
+
export class CursorProviderAdapter {
|
|
157
|
+
spawnProcess;
|
|
158
|
+
command;
|
|
159
|
+
env;
|
|
160
|
+
launchCwd = process.cwd();
|
|
161
|
+
activeRuns = new Map();
|
|
162
|
+
constructor(options = {}) {
|
|
163
|
+
this.spawnProcess = options.spawnProcess ?? spawnManagedProcess;
|
|
164
|
+
this.command = options.command ?? 'cursor-agent';
|
|
165
|
+
this.env = options.env ?? { ...process.env };
|
|
166
|
+
}
|
|
167
|
+
async probeCapabilities(request = { mode: 'static' }) {
|
|
168
|
+
try {
|
|
169
|
+
const metadata = await this.staticMetadata();
|
|
170
|
+
if (request.mode === 'static')
|
|
171
|
+
return capabilities(metadata, false);
|
|
172
|
+
const streaming = await this.verifyConformance(request);
|
|
173
|
+
return capabilities(metadata, true, streaming ? 'native' : 'none');
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
return unavailable(safeProbeError(error));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
start(request) {
|
|
180
|
+
return this.stream(request, null);
|
|
181
|
+
}
|
|
182
|
+
resume(request) {
|
|
183
|
+
return this.stream(request, request.nativeSessionId);
|
|
184
|
+
}
|
|
185
|
+
async cancel(runId) {
|
|
186
|
+
const active = this.activeRuns.get(runId);
|
|
187
|
+
if (!active)
|
|
188
|
+
return;
|
|
189
|
+
active.cancellationRequested = true;
|
|
190
|
+
await active.process.interrupt();
|
|
191
|
+
}
|
|
192
|
+
args(request, nativeSessionId) {
|
|
193
|
+
return [
|
|
194
|
+
'--print',
|
|
195
|
+
'--output-format', 'stream-json',
|
|
196
|
+
'--stream-partial-output',
|
|
197
|
+
'--mode', 'ask',
|
|
198
|
+
'--sandbox', 'enabled',
|
|
199
|
+
'--trust',
|
|
200
|
+
'--model', request.model,
|
|
201
|
+
...(nativeSessionId ? ['--resume', nativeSessionId] : []),
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
async *stream(request, nativeSessionId, observation) {
|
|
205
|
+
if (request.signal.aborted) {
|
|
206
|
+
yield { type: 'cancelled' };
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
let managed = null;
|
|
210
|
+
let active = null;
|
|
211
|
+
let sessionId = null;
|
|
212
|
+
let aggregateText = null;
|
|
213
|
+
let partialText = '';
|
|
214
|
+
let sawPartialOutput = false;
|
|
215
|
+
let nativeStateAdvanced = false;
|
|
216
|
+
let terminal = false;
|
|
217
|
+
let cancellationRequested = false;
|
|
218
|
+
const onAbort = () => {
|
|
219
|
+
cancellationRequested = true;
|
|
220
|
+
void this.cancel(request.runId).catch(() => undefined);
|
|
221
|
+
};
|
|
222
|
+
request.signal.addEventListener('abort', onAbort, { once: true });
|
|
223
|
+
try {
|
|
224
|
+
const input = renderCursorPrompt(request);
|
|
225
|
+
managed = this.spawnProcess({
|
|
226
|
+
command: this.command,
|
|
227
|
+
args: this.args(request, nativeSessionId),
|
|
228
|
+
cwd: request.workspace,
|
|
229
|
+
env: { ...this.env },
|
|
230
|
+
});
|
|
231
|
+
active = { process: managed, cancellationRequested: false };
|
|
232
|
+
this.activeRuns.set(request.runId, active);
|
|
233
|
+
if (request.signal.aborted) {
|
|
234
|
+
cancellationRequested = true;
|
|
235
|
+
active.cancellationRequested = true;
|
|
236
|
+
await managed.interrupt();
|
|
237
|
+
}
|
|
238
|
+
await writeInput(managed, input);
|
|
239
|
+
nativeStateAdvanced = true;
|
|
240
|
+
for await (const line of readBoundedLines(managed.stdout)) {
|
|
241
|
+
const event = parseCursorEvent(line);
|
|
242
|
+
if (event.type === 'system') {
|
|
243
|
+
if (sessionId !== null || (nativeSessionId !== null && event.session_id !== nativeSessionId)) {
|
|
244
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
245
|
+
}
|
|
246
|
+
sessionId = event.session_id;
|
|
247
|
+
yield { type: 'session_started', nativeSessionId: sessionId };
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (sessionId === null || event.session_id !== sessionId) {
|
|
251
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
252
|
+
}
|
|
253
|
+
if (event.type === 'user' || event.type === 'thinking')
|
|
254
|
+
continue;
|
|
255
|
+
if (event.type === 'tool_call')
|
|
256
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
257
|
+
if (event.type === 'assistant') {
|
|
258
|
+
const text = cursorAssistantText(event);
|
|
259
|
+
if (event.timestamp_ms !== undefined) {
|
|
260
|
+
sawPartialOutput = true;
|
|
261
|
+
partialText += text;
|
|
262
|
+
if (observation)
|
|
263
|
+
observation.sawPartialOutput = true;
|
|
264
|
+
yield request.outputSchema === null
|
|
265
|
+
? { type: 'text_delta', delta: text }
|
|
266
|
+
: { type: 'structured_delta', delta: text };
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
if (aggregateText !== null)
|
|
270
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
271
|
+
aggregateText = text;
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
terminal = true;
|
|
276
|
+
if (event.is_error || event.subtype !== 'success') {
|
|
277
|
+
yield {
|
|
278
|
+
type: 'failed',
|
|
279
|
+
code: 'adapter_provider_failed',
|
|
280
|
+
message: 'Cursor provider turn failed',
|
|
281
|
+
nativeStateAdvanced: true,
|
|
282
|
+
};
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const finalText = event.result ?? aggregateText;
|
|
286
|
+
if (finalText === null || finalText.length === 0
|
|
287
|
+
|| (aggregateText !== null && aggregateText !== finalText)
|
|
288
|
+
|| (sawPartialOutput && partialText !== finalText)) {
|
|
289
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
290
|
+
}
|
|
291
|
+
if (!sawPartialOutput) {
|
|
292
|
+
yield request.outputSchema === null
|
|
293
|
+
? { type: 'text_delta', delta: finalText }
|
|
294
|
+
: { type: 'structured_delta', delta: finalText };
|
|
295
|
+
}
|
|
296
|
+
yield { type: 'completed' };
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const exit = await managed.exited;
|
|
300
|
+
if (!terminal) {
|
|
301
|
+
if (cancellationRequested || active?.cancellationRequested) {
|
|
302
|
+
yield { type: 'cancelled' };
|
|
303
|
+
}
|
|
304
|
+
else if (exit.code !== 0) {
|
|
305
|
+
throw Object.assign(new Error('adapter_process_error'), { code: 'adapter_process_error' });
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
if (cancellationRequested || active?.cancellationRequested) {
|
|
314
|
+
yield { type: 'cancelled' };
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
yield failureEvent(error, nativeStateAdvanced);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
finally {
|
|
321
|
+
request.signal.removeEventListener('abort', onAbort);
|
|
322
|
+
if (active && this.activeRuns.get(request.runId) === active) {
|
|
323
|
+
this.activeRuns.delete(request.runId);
|
|
324
|
+
}
|
|
325
|
+
if (managed)
|
|
326
|
+
await disposeQuietly(managed);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
async staticMetadata() {
|
|
330
|
+
const versionOutput = await this.runCommand(['--version']);
|
|
331
|
+
const helpOutput = await this.runCommand(['--help']);
|
|
332
|
+
if (REQUIRED_HELP_FLAGS.some((flag) => !helpOutput.includes(flag))) {
|
|
333
|
+
throw new CursorAdapterError('adapter_capability_unsupported');
|
|
334
|
+
}
|
|
335
|
+
const modelsOutput = await this.runCommand(['--list-models']);
|
|
336
|
+
const version = versionOutput.match(/\b\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?\b/)?.[0];
|
|
337
|
+
if (!version)
|
|
338
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
339
|
+
return { version, models: parseCursorModels(modelsOutput) };
|
|
340
|
+
}
|
|
341
|
+
async runCommand(args) {
|
|
342
|
+
const managed = this.spawnProcess({
|
|
343
|
+
command: this.command,
|
|
344
|
+
args,
|
|
345
|
+
cwd: this.launchCwd,
|
|
346
|
+
env: { ...this.env },
|
|
347
|
+
});
|
|
348
|
+
managed.stdin.end();
|
|
349
|
+
try {
|
|
350
|
+
let output = '';
|
|
351
|
+
const collect = (async () => {
|
|
352
|
+
for await (const line of readBoundedLines(managed.stdout)) {
|
|
353
|
+
output += `${line}\n`;
|
|
354
|
+
if (Buffer.byteLength(output) > COMMAND_OUTPUT_LIMIT_BYTES) {
|
|
355
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
})();
|
|
359
|
+
const [exit] = await Promise.all([managed.exited, collect]);
|
|
360
|
+
if (exit.code !== 0 || output.trim().length === 0) {
|
|
361
|
+
throw Object.assign(new Error('adapter_process_error'), { code: 'adapter_process_error' });
|
|
362
|
+
}
|
|
363
|
+
return output.trim();
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
await disposeQuietly(managed);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
async verifyConformance(request) {
|
|
370
|
+
const baseRequest = {
|
|
371
|
+
runId: `cursor-conformance-start-${Date.now()}`,
|
|
372
|
+
targetId: request.targetId,
|
|
373
|
+
model: request.model,
|
|
374
|
+
effort: null,
|
|
375
|
+
workspace: request.workspace,
|
|
376
|
+
input: [{
|
|
377
|
+
role: 'user',
|
|
378
|
+
content: 'Return an assistant_text JSON object with a short English confirmation.',
|
|
379
|
+
}],
|
|
380
|
+
sessionMode: 'persistent',
|
|
381
|
+
runTimeoutMs: null,
|
|
382
|
+
outputSchema: CONFORMANCE_SCHEMA,
|
|
383
|
+
signal: request.signal,
|
|
384
|
+
};
|
|
385
|
+
const firstObservation = { sawPartialOutput: false };
|
|
386
|
+
const nativeSessionId = await this.requireConformanceEvents(this.stream(baseRequest, null, firstObservation));
|
|
387
|
+
const resumeObservation = { sawPartialOutput: false };
|
|
388
|
+
await this.requireConformanceEvents(this.stream({
|
|
389
|
+
...baseRequest,
|
|
390
|
+
runId: `cursor-conformance-resume-${Date.now()}`,
|
|
391
|
+
input: [{
|
|
392
|
+
role: 'user',
|
|
393
|
+
content: 'Return another assistant_text JSON object with a short English confirmation.',
|
|
394
|
+
}],
|
|
395
|
+
}, nativeSessionId, resumeObservation));
|
|
396
|
+
return firstObservation.sawPartialOutput && resumeObservation.sawPartialOutput;
|
|
397
|
+
}
|
|
398
|
+
async requireConformanceEvents(events) {
|
|
399
|
+
let nativeSessionId = null;
|
|
400
|
+
let structuredOutput = '';
|
|
401
|
+
let completed = false;
|
|
402
|
+
for await (const event of events) {
|
|
403
|
+
if (event.type === 'session_started')
|
|
404
|
+
nativeSessionId = event.nativeSessionId;
|
|
405
|
+
else if (event.type === 'structured_delta')
|
|
406
|
+
structuredOutput += event.delta;
|
|
407
|
+
else if (event.type === 'completed')
|
|
408
|
+
completed = true;
|
|
409
|
+
else
|
|
410
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
411
|
+
}
|
|
412
|
+
if (!nativeSessionId || !completed)
|
|
413
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
414
|
+
let parsed;
|
|
415
|
+
try {
|
|
416
|
+
parsed = JSON.parse(structuredOutput);
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
420
|
+
}
|
|
421
|
+
if (!conformanceOutputSchema.safeParse(parsed).success) {
|
|
422
|
+
throw new CursorAdapterError('adapter_protocol_error');
|
|
423
|
+
}
|
|
424
|
+
return nativeSessionId;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=adapter.js.map
|