@sideboard-ai/core 0.1.30 → 0.1.31
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/dist/agents/cursor-runner.cjs +33 -3
- package/dist/agents/cursor-runner.js +17 -4
- package/dist/{agents-LJJRPW4Y.js → agents-HWIPJLC3.js} +23 -3
- package/dist/{chunk-WK6AK7NK.js → chunk-4YLTMPEO.js} +319 -2
- package/dist/{chunk-RPSHBKLW.js → chunk-OY47OEY2.js} +24 -8
- package/dist/index.cjs +374 -12
- package/dist/index.d.cts +80 -1
- package/dist/index.d.ts +80 -1
- package/dist/index.js +22 -2
- package/dist/mcp/run-stdio.cjs +354 -12
- package/dist/mcp/run-stdio.js +2 -2
- package/package.json +1 -1
|
@@ -3,8 +3,30 @@
|
|
|
3
3
|
|
|
4
4
|
// src/agents/cursor-runner.ts
|
|
5
5
|
var import_sdk = require("@cursor/sdk");
|
|
6
|
+
var import_node_fs3 = require("fs");
|
|
7
|
+
var import_node_path4 = require("path");
|
|
6
8
|
var import_node_readline = require("readline");
|
|
7
9
|
|
|
10
|
+
// src/store/paths.ts
|
|
11
|
+
var import_node_path2 = require("path");
|
|
12
|
+
var import_node_os2 = require("os");
|
|
13
|
+
var import_node_path3 = require("path");
|
|
14
|
+
var import_node_fs2 = require("fs");
|
|
15
|
+
|
|
16
|
+
// src/hook/settings.ts
|
|
17
|
+
var import_node_fs = require("fs");
|
|
18
|
+
var import_node_os = require("os");
|
|
19
|
+
var import_node_path = require("path");
|
|
20
|
+
var import_smol_toml = require("smol-toml");
|
|
21
|
+
|
|
22
|
+
// src/store/paths.ts
|
|
23
|
+
function appDataDir() {
|
|
24
|
+
const override = process.env.SIDEBOARD_APP_DATA?.trim();
|
|
25
|
+
const base = override ? override : process.platform === "darwin" ? (0, import_node_path3.join)((0, import_node_os2.homedir)(), "Library", "Application Support", "sideboard") : process.platform === "win32" ? (0, import_node_path3.join)(process.env.APPDATA ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(), "AppData", "Roaming"), "sideboard") : (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".local", "share", "sideboard");
|
|
26
|
+
(0, import_node_fs2.mkdirSync)(base, { recursive: true });
|
|
27
|
+
return base;
|
|
28
|
+
}
|
|
29
|
+
|
|
8
30
|
// src/agents/cursor-events.ts
|
|
9
31
|
function usageFromCursor(usage) {
|
|
10
32
|
if (!usage) return null;
|
|
@@ -82,12 +104,18 @@ function emit(event) {
|
|
|
82
104
|
`);
|
|
83
105
|
}
|
|
84
106
|
function modelSelection(model, fast) {
|
|
85
|
-
const
|
|
107
|
+
const raw = model && model.trim() || "";
|
|
108
|
+
const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
|
|
86
109
|
if (fast) {
|
|
87
110
|
return { id, params: [{ id: "fast", value: "true" }] };
|
|
88
111
|
}
|
|
89
112
|
return { id };
|
|
90
113
|
}
|
|
114
|
+
function localAgentStore() {
|
|
115
|
+
const root = (0, import_node_path4.join)(appDataDir(), "cursor-sdk-store");
|
|
116
|
+
(0, import_node_fs3.mkdirSync)(root, { recursive: true });
|
|
117
|
+
return new import_sdk.JsonlLocalAgentStore(root);
|
|
118
|
+
}
|
|
91
119
|
async function readStdinJson() {
|
|
92
120
|
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, crlfDelay: Infinity });
|
|
93
121
|
const chunks = [];
|
|
@@ -118,17 +146,19 @@ async function main() {
|
|
|
118
146
|
const apiKey = (req.apiKey || process.env.CURSOR_API_KEY || "").trim() || void 0;
|
|
119
147
|
const model = modelSelection(req.model, Boolean(req.fast));
|
|
120
148
|
const mode = req.planMode ? "plan" : "agent";
|
|
149
|
+
const store = localAgentStore();
|
|
150
|
+
const local = { cwd: req.cwd, store };
|
|
121
151
|
try {
|
|
122
152
|
const agent = req.agentId ? await import_sdk.Agent.resume(req.agentId, {
|
|
123
153
|
apiKey,
|
|
124
154
|
model,
|
|
125
155
|
mode,
|
|
126
|
-
local
|
|
156
|
+
local
|
|
127
157
|
}) : await import_sdk.Agent.create({
|
|
128
158
|
apiKey,
|
|
129
159
|
model,
|
|
130
160
|
mode,
|
|
131
|
-
local
|
|
161
|
+
local,
|
|
132
162
|
name: "Sideboard"
|
|
133
163
|
});
|
|
134
164
|
try {
|
|
@@ -2,21 +2,32 @@
|
|
|
2
2
|
import {
|
|
3
3
|
cursorSdkMessageToEvents
|
|
4
4
|
} from "../chunk-3DKGI32Q.js";
|
|
5
|
+
import {
|
|
6
|
+
appDataDir
|
|
7
|
+
} from "../chunk-M37RITA6.js";
|
|
5
8
|
|
|
6
9
|
// src/agents/cursor-runner.ts
|
|
7
|
-
import { Agent, CursorAgentError } from "@cursor/sdk";
|
|
10
|
+
import { Agent, CursorAgentError, JsonlLocalAgentStore } from "@cursor/sdk";
|
|
11
|
+
import { mkdirSync } from "fs";
|
|
12
|
+
import { join } from "path";
|
|
8
13
|
import { createInterface } from "readline";
|
|
9
14
|
function emit(event) {
|
|
10
15
|
process.stdout.write(`${JSON.stringify(event)}
|
|
11
16
|
`);
|
|
12
17
|
}
|
|
13
18
|
function modelSelection(model, fast) {
|
|
14
|
-
const
|
|
19
|
+
const raw = model && model.trim() || "";
|
|
20
|
+
const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
|
|
15
21
|
if (fast) {
|
|
16
22
|
return { id, params: [{ id: "fast", value: "true" }] };
|
|
17
23
|
}
|
|
18
24
|
return { id };
|
|
19
25
|
}
|
|
26
|
+
function localAgentStore() {
|
|
27
|
+
const root = join(appDataDir(), "cursor-sdk-store");
|
|
28
|
+
mkdirSync(root, { recursive: true });
|
|
29
|
+
return new JsonlLocalAgentStore(root);
|
|
30
|
+
}
|
|
20
31
|
async function readStdinJson() {
|
|
21
32
|
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
22
33
|
const chunks = [];
|
|
@@ -47,17 +58,19 @@ async function main() {
|
|
|
47
58
|
const apiKey = (req.apiKey || process.env.CURSOR_API_KEY || "").trim() || void 0;
|
|
48
59
|
const model = modelSelection(req.model, Boolean(req.fast));
|
|
49
60
|
const mode = req.planMode ? "plan" : "agent";
|
|
61
|
+
const store = localAgentStore();
|
|
62
|
+
const local = { cwd: req.cwd, store };
|
|
50
63
|
try {
|
|
51
64
|
const agent = req.agentId ? await Agent.resume(req.agentId, {
|
|
52
65
|
apiKey,
|
|
53
66
|
model,
|
|
54
67
|
mode,
|
|
55
|
-
local
|
|
68
|
+
local
|
|
56
69
|
}) : await Agent.create({
|
|
57
70
|
apiKey,
|
|
58
71
|
model,
|
|
59
72
|
mode,
|
|
60
|
-
local
|
|
73
|
+
local,
|
|
61
74
|
name: "Sideboard"
|
|
62
75
|
});
|
|
63
76
|
try {
|
|
@@ -8,10 +8,20 @@ import {
|
|
|
8
8
|
decodeBrightsyTarget,
|
|
9
9
|
encodeBrightsyTarget,
|
|
10
10
|
getAdapter,
|
|
11
|
+
getAgentSetupInfo,
|
|
12
|
+
installAgent,
|
|
13
|
+
isCursorAutoModel,
|
|
14
|
+
listAgentSetupInfo,
|
|
11
15
|
listBrightsyChatTargets,
|
|
16
|
+
listCodexModels,
|
|
17
|
+
listCursorModels,
|
|
18
|
+
listOpencodeModels,
|
|
19
|
+
loginAgent,
|
|
20
|
+
openInSystemTerminal,
|
|
12
21
|
opencodeAdapter,
|
|
13
|
-
permissionMode
|
|
14
|
-
|
|
22
|
+
permissionMode,
|
|
23
|
+
resolveCursorModelId
|
|
24
|
+
} from "./chunk-4YLTMPEO.js";
|
|
15
25
|
import "./chunk-ILQK4P5R.js";
|
|
16
26
|
import {
|
|
17
27
|
cursorSdkMessageToEvents,
|
|
@@ -34,8 +44,18 @@ export {
|
|
|
34
44
|
encodeBrightsyTarget,
|
|
35
45
|
ensureAgentPath,
|
|
36
46
|
getAdapter,
|
|
47
|
+
getAgentSetupInfo,
|
|
48
|
+
installAgent,
|
|
49
|
+
isCursorAutoModel,
|
|
50
|
+
listAgentSetupInfo,
|
|
37
51
|
listBrightsyChatTargets,
|
|
52
|
+
listCodexModels,
|
|
53
|
+
listCursorModels,
|
|
54
|
+
listOpencodeModels,
|
|
55
|
+
loginAgent,
|
|
56
|
+
openInSystemTerminal,
|
|
38
57
|
opencodeAdapter,
|
|
39
58
|
parseCursorRunnerLine,
|
|
40
|
-
permissionMode
|
|
59
|
+
permissionMode,
|
|
60
|
+
resolveCursorModelId
|
|
41
61
|
};
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
resolveClaudeExecutable
|
|
15
15
|
} from "./chunk-3WF3X46L.js";
|
|
16
16
|
import {
|
|
17
|
+
ensureAgentPath,
|
|
17
18
|
run
|
|
18
19
|
} from "./chunk-AJ6ROGD7.js";
|
|
19
20
|
|
|
@@ -933,6 +934,44 @@ import { existsSync as existsSync3, readFileSync } from "fs";
|
|
|
933
934
|
import { homedir } from "os";
|
|
934
935
|
import { join as join2 } from "path";
|
|
935
936
|
var CODEX_PROMPT_ARG_MAX = 2e5;
|
|
937
|
+
var FALLBACK_CODEX_MODELS = [
|
|
938
|
+
{ id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
|
|
939
|
+
{ id: "gpt-5.6-terra", displayName: "GPT-5.6 Terra" },
|
|
940
|
+
{ id: "gpt-5.6-luna", displayName: "GPT-5.6 Luna" },
|
|
941
|
+
{ id: "gpt-5.5", displayName: "GPT-5.5" },
|
|
942
|
+
{ id: "gpt-5.2", displayName: "GPT-5.2" }
|
|
943
|
+
];
|
|
944
|
+
var cachedCodexModels = null;
|
|
945
|
+
var CODEX_MODEL_CACHE_MS = 5 * 60 * 1e3;
|
|
946
|
+
async function listCodexModels() {
|
|
947
|
+
const now = Date.now();
|
|
948
|
+
if (cachedCodexModels && now - cachedCodexModels.at < CODEX_MODEL_CACHE_MS) {
|
|
949
|
+
return cachedCodexModels.models;
|
|
950
|
+
}
|
|
951
|
+
const which = await run("which", ["codex"], { reject: false });
|
|
952
|
+
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
953
|
+
const listed = await run("codex", ["debug", "models"], { reject: false });
|
|
954
|
+
if (listed.exitCode !== 0 || !listed.stdout.trim()) {
|
|
955
|
+
return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
|
|
956
|
+
}
|
|
957
|
+
try {
|
|
958
|
+
const parsed = JSON.parse(listed.stdout);
|
|
959
|
+
const rows = Array.isArray(parsed.models) ? parsed.models : [];
|
|
960
|
+
const preferred = rows.filter((m) => (m.visibility ?? "list") === "list");
|
|
961
|
+
const source = preferred.length > 0 ? preferred : rows;
|
|
962
|
+
const models = source.map((m) => ({
|
|
963
|
+
id: (m.slug || "").trim(),
|
|
964
|
+
displayName: (m.display_name || m.slug || "").trim(),
|
|
965
|
+
description: m.description,
|
|
966
|
+
priority: typeof m.priority === "number" ? m.priority : 999
|
|
967
|
+
})).filter((m) => m.id).sort((a, b) => a.priority - b.priority).map(({ id, displayName, description }) => ({ id, displayName, description }));
|
|
968
|
+
if (models.length === 0) return FALLBACK_CODEX_MODELS;
|
|
969
|
+
cachedCodexModels = { at: now, models };
|
|
970
|
+
return models;
|
|
971
|
+
} catch {
|
|
972
|
+
return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
936
975
|
function usageFromCodex(usage) {
|
|
937
976
|
if (!usage) return null;
|
|
938
977
|
const inputTokens = Number(usage.input_tokens ?? 0);
|
|
@@ -1001,6 +1040,7 @@ var codexAdapter = {
|
|
|
1001
1040
|
);
|
|
1002
1041
|
}
|
|
1003
1042
|
const mode = permissionMode(thread);
|
|
1043
|
+
const model = thread.model?.trim();
|
|
1004
1044
|
const args = [
|
|
1005
1045
|
"exec",
|
|
1006
1046
|
...sessionId ? ["resume", sessionId] : [],
|
|
@@ -1011,7 +1051,8 @@ var codexAdapter = {
|
|
|
1011
1051
|
"--sandbox",
|
|
1012
1052
|
mode.codexSandbox,
|
|
1013
1053
|
"--ask-for-approval",
|
|
1014
|
-
"never"
|
|
1054
|
+
"never",
|
|
1055
|
+
...model ? ["--model", model] : []
|
|
1015
1056
|
];
|
|
1016
1057
|
return {
|
|
1017
1058
|
file: "codex",
|
|
@@ -1097,11 +1138,47 @@ import { createRequire as createRequire2 } from "module";
|
|
|
1097
1138
|
import { dirname as dirname2, join as join3 } from "path";
|
|
1098
1139
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1099
1140
|
import { Cursor } from "@cursor/sdk";
|
|
1141
|
+
var FALLBACK_CURSOR_MODELS = [
|
|
1142
|
+
{ id: "default", displayName: "Auto" },
|
|
1143
|
+
{ id: "composer-2.5", displayName: "Composer 2.5" },
|
|
1144
|
+
{ id: "composer-2", displayName: "Composer 2" }
|
|
1145
|
+
];
|
|
1146
|
+
var cachedModels = null;
|
|
1147
|
+
var MODEL_CACHE_MS = 5 * 60 * 1e3;
|
|
1100
1148
|
function resolveCursorApiKey() {
|
|
1101
1149
|
const fromEnv = (process.env.CURSOR_API_KEY || "").trim();
|
|
1102
1150
|
if (fromEnv) return fromEnv;
|
|
1103
1151
|
return (loadAppSettings().environment.CURSOR_API_KEY || "").trim();
|
|
1104
1152
|
}
|
|
1153
|
+
function isCursorAutoModel(model) {
|
|
1154
|
+
const id = (model ?? "").trim().toLowerCase();
|
|
1155
|
+
return !id || id === "default" || id === "auto";
|
|
1156
|
+
}
|
|
1157
|
+
function resolveCursorModelId(model) {
|
|
1158
|
+
if (isCursorAutoModel(model)) return "default";
|
|
1159
|
+
return model.trim();
|
|
1160
|
+
}
|
|
1161
|
+
async function listCursorModels() {
|
|
1162
|
+
const now = Date.now();
|
|
1163
|
+
if (cachedModels && now - cachedModels.at < MODEL_CACHE_MS) {
|
|
1164
|
+
return cachedModels.models;
|
|
1165
|
+
}
|
|
1166
|
+
const apiKey = resolveCursorApiKey();
|
|
1167
|
+
if (!apiKey) return FALLBACK_CURSOR_MODELS;
|
|
1168
|
+
try {
|
|
1169
|
+
const listed = await Cursor.models.list({ apiKey });
|
|
1170
|
+
const models = listed.map((m) => ({
|
|
1171
|
+
id: m.id,
|
|
1172
|
+
displayName: m.displayName || m.id,
|
|
1173
|
+
description: m.description
|
|
1174
|
+
})).filter((m) => Boolean(m.id));
|
|
1175
|
+
if (models.length === 0) return FALLBACK_CURSOR_MODELS;
|
|
1176
|
+
cachedModels = { at: now, models };
|
|
1177
|
+
return models;
|
|
1178
|
+
} catch {
|
|
1179
|
+
return cachedModels?.models ?? FALLBACK_CURSOR_MODELS;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1105
1182
|
function entryDir() {
|
|
1106
1183
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
1107
1184
|
if (cjsDir) return cjsDir;
|
|
@@ -1183,12 +1260,16 @@ var cursorAdapter = {
|
|
|
1183
1260
|
};
|
|
1184
1261
|
const runner = cursorRunnerPath();
|
|
1185
1262
|
const isTs = runner.endsWith(".ts");
|
|
1263
|
+
const whichNode = await run("which", ["node"], { reject: false });
|
|
1264
|
+
const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
|
|
1265
|
+
const file = nodeBin || process.execPath;
|
|
1186
1266
|
return {
|
|
1187
|
-
file
|
|
1267
|
+
file,
|
|
1188
1268
|
args: isTs ? ["--import", "tsx", runner] : [runner],
|
|
1189
1269
|
cwd: thread.worktreePath,
|
|
1190
1270
|
stdin: JSON.stringify(req),
|
|
1191
1271
|
env: {
|
|
1272
|
+
...nodeBin ? {} : { ELECTRON_RUN_AS_NODE: "1" },
|
|
1192
1273
|
...apiKey ? { CURSOR_API_KEY: apiKey } : {}
|
|
1193
1274
|
}
|
|
1194
1275
|
};
|
|
@@ -1211,6 +1292,59 @@ var cursorAdapter = {
|
|
|
1211
1292
|
};
|
|
1212
1293
|
|
|
1213
1294
|
// src/agents/opencode.ts
|
|
1295
|
+
var FALLBACK_OPENCODE_MODELS = [
|
|
1296
|
+
{ id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
|
|
1297
|
+
{
|
|
1298
|
+
id: "openrouter/~anthropic/claude-sonnet-latest",
|
|
1299
|
+
displayName: "openrouter \xB7 claude-sonnet-latest"
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
id: "openrouter/~openai/gpt-latest",
|
|
1303
|
+
displayName: "openrouter \xB7 gpt-latest"
|
|
1304
|
+
}
|
|
1305
|
+
];
|
|
1306
|
+
var cachedOpencodeModels = null;
|
|
1307
|
+
var OPENCODE_MODEL_CACHE_MS = 5 * 60 * 1e3;
|
|
1308
|
+
function displayNameFromOpencodeId(id) {
|
|
1309
|
+
const slash = id.indexOf("/");
|
|
1310
|
+
if (slash <= 0) return id;
|
|
1311
|
+
const provider = id.slice(0, slash);
|
|
1312
|
+
const name = id.slice(slash + 1);
|
|
1313
|
+
return `${provider} \xB7 ${name}`;
|
|
1314
|
+
}
|
|
1315
|
+
function sortOpencodeModelIds(ids) {
|
|
1316
|
+
return [...ids].sort((a, b) => {
|
|
1317
|
+
const aLatest = /latest|~/.test(a) ? 0 : 1;
|
|
1318
|
+
const bLatest = /latest|~/.test(b) ? 0 : 1;
|
|
1319
|
+
if (aLatest !== bLatest) return aLatest - bLatest;
|
|
1320
|
+
const aOc = a.startsWith("opencode/") ? 0 : 1;
|
|
1321
|
+
const bOc = b.startsWith("opencode/") ? 0 : 1;
|
|
1322
|
+
if (aOc !== bOc) return aOc - bOc;
|
|
1323
|
+
return a.localeCompare(b);
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
async function listOpencodeModels() {
|
|
1327
|
+
const now = Date.now();
|
|
1328
|
+
if (cachedOpencodeModels && now - cachedOpencodeModels.at < OPENCODE_MODEL_CACHE_MS) {
|
|
1329
|
+
return cachedOpencodeModels.models;
|
|
1330
|
+
}
|
|
1331
|
+
const which = await run("which", ["opencode"], { reject: false });
|
|
1332
|
+
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
1333
|
+
const listed = await run("opencode", ["models"], { reject: false });
|
|
1334
|
+
if (listed.exitCode !== 0 || !listed.stdout.trim()) {
|
|
1335
|
+
return cachedOpencodeModels?.models ?? FALLBACK_OPENCODE_MODELS;
|
|
1336
|
+
}
|
|
1337
|
+
const ids = listed.stdout.split("\n").map((l) => l.trim()).filter((l) => /^[\w.~@+-]+\/[\w.~@+/-]+$/.test(l));
|
|
1338
|
+
const unique = [...new Set(ids)];
|
|
1339
|
+
if (unique.length === 0) return FALLBACK_OPENCODE_MODELS;
|
|
1340
|
+
const OPENCODE_PICKER_LIMIT = 60;
|
|
1341
|
+
const models = sortOpencodeModelIds(unique).slice(0, OPENCODE_PICKER_LIMIT).map((id) => ({
|
|
1342
|
+
id,
|
|
1343
|
+
displayName: displayNameFromOpencodeId(id)
|
|
1344
|
+
}));
|
|
1345
|
+
cachedOpencodeModels = { at: now, models };
|
|
1346
|
+
return models;
|
|
1347
|
+
}
|
|
1214
1348
|
function usageFromOpencode(tokens) {
|
|
1215
1349
|
if (!tokens) return null;
|
|
1216
1350
|
const inputTokens = Number(tokens.input ?? 0);
|
|
@@ -1254,6 +1388,7 @@ var opencodeAdapter = {
|
|
|
1254
1388
|
const prompt = flattenTurnInput(input);
|
|
1255
1389
|
const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
1256
1390
|
const mode = permissionMode(thread);
|
|
1391
|
+
const model = thread.model?.trim();
|
|
1257
1392
|
const args = [
|
|
1258
1393
|
"run",
|
|
1259
1394
|
"--dir",
|
|
@@ -1264,6 +1399,9 @@ var opencodeAdapter = {
|
|
|
1264
1399
|
if (sessionId) {
|
|
1265
1400
|
args.push("--session", sessionId);
|
|
1266
1401
|
}
|
|
1402
|
+
if (model) {
|
|
1403
|
+
args.push("--model", model);
|
|
1404
|
+
}
|
|
1267
1405
|
return {
|
|
1268
1406
|
file: "opencode",
|
|
1269
1407
|
args,
|
|
@@ -1389,6 +1527,175 @@ var opencodeAdapter = {
|
|
|
1389
1527
|
}
|
|
1390
1528
|
};
|
|
1391
1529
|
|
|
1530
|
+
// src/agents/install.ts
|
|
1531
|
+
var SETUP = {
|
|
1532
|
+
claude: {
|
|
1533
|
+
agent: "claude",
|
|
1534
|
+
kind: "cli",
|
|
1535
|
+
summary: "Install the Claude Code CLI, then complete login in a terminal.",
|
|
1536
|
+
docsUrl: "https://code.claude.com/docs/en/install",
|
|
1537
|
+
installCommand: "npm install -g @anthropic-ai/claude-code",
|
|
1538
|
+
loginCommand: "claude auth login",
|
|
1539
|
+
npmPackage: "@anthropic-ai/claude-code"
|
|
1540
|
+
},
|
|
1541
|
+
codex: {
|
|
1542
|
+
agent: "codex",
|
|
1543
|
+
kind: "cli",
|
|
1544
|
+
summary: "Install the Codex CLI, then run login in a terminal.",
|
|
1545
|
+
docsUrl: "https://github.com/openai/codex",
|
|
1546
|
+
installCommand: "npm install -g @openai/codex",
|
|
1547
|
+
loginCommand: "codex login",
|
|
1548
|
+
npmPackage: "@openai/codex"
|
|
1549
|
+
},
|
|
1550
|
+
opencode: {
|
|
1551
|
+
agent: "opencode",
|
|
1552
|
+
kind: "cli",
|
|
1553
|
+
summary: "Install OpenCode (curl installer or npm), then authenticate providers.",
|
|
1554
|
+
docsUrl: "https://opencode.ai/docs",
|
|
1555
|
+
// Prefer the official installer; npm package name is opencode-ai.
|
|
1556
|
+
installCommand: "curl -fsSL https://opencode.ai/install | bash",
|
|
1557
|
+
loginCommand: "opencode auth login",
|
|
1558
|
+
npmPackage: "opencode-ai@latest"
|
|
1559
|
+
},
|
|
1560
|
+
cursor: {
|
|
1561
|
+
agent: "cursor",
|
|
1562
|
+
kind: "bundled-sdk",
|
|
1563
|
+
summary: "No CLI install \u2014 Sideboard ships the Cursor SDK. Add a CURSOR_API_KEY from the Cursor dashboard.",
|
|
1564
|
+
docsUrl: "https://cursor.com/dashboard/integrations",
|
|
1565
|
+
installCommand: null,
|
|
1566
|
+
loginCommand: null
|
|
1567
|
+
},
|
|
1568
|
+
brightsy: {
|
|
1569
|
+
agent: "brightsy",
|
|
1570
|
+
kind: "cli",
|
|
1571
|
+
summary: "Install the Brightsy CLI, then run `brightsy login`.",
|
|
1572
|
+
docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
|
|
1573
|
+
installCommand: "npm install -g @brightsy/cli",
|
|
1574
|
+
loginCommand: "brightsy login",
|
|
1575
|
+
npmPackage: "@brightsy/cli"
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
function getAgentSetupInfo(agent) {
|
|
1579
|
+
return SETUP[agent];
|
|
1580
|
+
}
|
|
1581
|
+
function listAgentSetupInfo() {
|
|
1582
|
+
return Object.values(SETUP);
|
|
1583
|
+
}
|
|
1584
|
+
async function openInSystemTerminal(command) {
|
|
1585
|
+
ensureAgentPath();
|
|
1586
|
+
const trimmed = command.trim();
|
|
1587
|
+
if (!trimmed) throw new Error("Command is empty");
|
|
1588
|
+
if (process.platform === "darwin") {
|
|
1589
|
+
const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
1590
|
+
const script = `tell application "Terminal" to do script "${escaped}"`;
|
|
1591
|
+
const result = await run("osascript", ["-e", script], { reject: false });
|
|
1592
|
+
if (result.exitCode !== 0) {
|
|
1593
|
+
throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open Terminal");
|
|
1594
|
+
}
|
|
1595
|
+
await run("osascript", ["-e", 'tell application "Terminal" to activate'], {
|
|
1596
|
+
reject: false
|
|
1597
|
+
});
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
if (process.platform === "win32") {
|
|
1601
|
+
const result = await run(
|
|
1602
|
+
"cmd.exe",
|
|
1603
|
+
["/c", "start", "cmd.exe", "/k", trimmed],
|
|
1604
|
+
{ reject: false }
|
|
1605
|
+
);
|
|
1606
|
+
if (result.exitCode !== 0) {
|
|
1607
|
+
throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open cmd");
|
|
1608
|
+
}
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
const candidates = [
|
|
1612
|
+
{ file: "gnome-terminal", args: ["--", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
1613
|
+
{ file: "x-terminal-emulator", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
1614
|
+
{ file: "konsole", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
1615
|
+
{ file: "xterm", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] }
|
|
1616
|
+
];
|
|
1617
|
+
for (const c of candidates) {
|
|
1618
|
+
const which = await run("which", [c.file], { reject: false });
|
|
1619
|
+
if (which.exitCode !== 0 || !which.stdout.trim()) continue;
|
|
1620
|
+
const result = await run(c.file, c.args, { reject: false });
|
|
1621
|
+
if (result.exitCode === 0) return;
|
|
1622
|
+
}
|
|
1623
|
+
throw new Error(
|
|
1624
|
+
`No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
|
|
1625
|
+
);
|
|
1626
|
+
}
|
|
1627
|
+
async function installAgent(agent) {
|
|
1628
|
+
const info = getAgentSetupInfo(agent);
|
|
1629
|
+
if (info.kind === "bundled-sdk" || info.kind === "api-key") {
|
|
1630
|
+
return {
|
|
1631
|
+
ok: true,
|
|
1632
|
+
message: info.summary
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
if (!info.installCommand) {
|
|
1636
|
+
return { ok: false, message: `No install command for ${agent}` };
|
|
1637
|
+
}
|
|
1638
|
+
if (/curl\s| \|\s*bash/.test(info.installCommand) || !info.npmPackage) {
|
|
1639
|
+
await openInSystemTerminal(info.installCommand);
|
|
1640
|
+
return {
|
|
1641
|
+
ok: true,
|
|
1642
|
+
openedTerminal: true,
|
|
1643
|
+
command: info.installCommand,
|
|
1644
|
+
message: `Opened Terminal to run: ${info.installCommand}`
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
ensureAgentPath();
|
|
1648
|
+
const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
|
|
1649
|
+
const ok = result.exitCode === 0;
|
|
1650
|
+
if (!ok) {
|
|
1651
|
+
try {
|
|
1652
|
+
await openInSystemTerminal(info.installCommand);
|
|
1653
|
+
return {
|
|
1654
|
+
ok: false,
|
|
1655
|
+
openedTerminal: true,
|
|
1656
|
+
command: info.installCommand,
|
|
1657
|
+
exitCode: result.exitCode,
|
|
1658
|
+
stdout: result.stdout,
|
|
1659
|
+
stderr: result.stderr,
|
|
1660
|
+
message: `npm install failed (exit ${result.exitCode}). Opened Terminal with: ${info.installCommand}`
|
|
1661
|
+
};
|
|
1662
|
+
} catch {
|
|
1663
|
+
return {
|
|
1664
|
+
ok: false,
|
|
1665
|
+
command: info.installCommand,
|
|
1666
|
+
exitCode: result.exitCode,
|
|
1667
|
+
stdout: result.stdout,
|
|
1668
|
+
stderr: result.stderr,
|
|
1669
|
+
message: result.stderr.trim() || result.stdout.trim() || `npm install failed (exit ${result.exitCode})`
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
return {
|
|
1674
|
+
ok: true,
|
|
1675
|
+
command: info.installCommand,
|
|
1676
|
+
exitCode: 0,
|
|
1677
|
+
stdout: result.stdout,
|
|
1678
|
+
stderr: result.stderr,
|
|
1679
|
+
message: `Installed ${info.npmPackage}`
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
async function loginAgent(agent) {
|
|
1683
|
+
const info = getAgentSetupInfo(agent);
|
|
1684
|
+
if (!info.loginCommand) {
|
|
1685
|
+
return {
|
|
1686
|
+
ok: true,
|
|
1687
|
+
message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
await openInSystemTerminal(info.loginCommand);
|
|
1691
|
+
return {
|
|
1692
|
+
ok: true,
|
|
1693
|
+
openedTerminal: true,
|
|
1694
|
+
command: info.loginCommand,
|
|
1695
|
+
message: `Opened Terminal to run: ${info.loginCommand}`
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1392
1699
|
// src/agents/index.ts
|
|
1393
1700
|
var adapters = {
|
|
1394
1701
|
claude: claudeAdapter,
|
|
@@ -1429,9 +1736,19 @@ export {
|
|
|
1429
1736
|
PLAN_MODE_INSTRUCTION,
|
|
1430
1737
|
permissionMode,
|
|
1431
1738
|
claudeAdapter,
|
|
1739
|
+
listCodexModels,
|
|
1432
1740
|
codexAdapter,
|
|
1741
|
+
isCursorAutoModel,
|
|
1742
|
+
resolveCursorModelId,
|
|
1743
|
+
listCursorModels,
|
|
1433
1744
|
cursorAdapter,
|
|
1745
|
+
listOpencodeModels,
|
|
1434
1746
|
opencodeAdapter,
|
|
1747
|
+
getAgentSetupInfo,
|
|
1748
|
+
listAgentSetupInfo,
|
|
1749
|
+
openInSystemTerminal,
|
|
1750
|
+
installAgent,
|
|
1751
|
+
loginAgent,
|
|
1435
1752
|
getAdapter,
|
|
1436
1753
|
allAdapters
|
|
1437
1754
|
};
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
allAdapters,
|
|
26
26
|
getAdapter,
|
|
27
27
|
parseBrightsyCliLine
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-4YLTMPEO.js";
|
|
29
29
|
import {
|
|
30
30
|
childEnvWithAppSettings,
|
|
31
31
|
getLinearApiKey,
|
|
@@ -2557,7 +2557,7 @@ async function createThread(input, onSetupLine) {
|
|
|
2557
2557
|
return readThread(thread.id) ?? thread;
|
|
2558
2558
|
}
|
|
2559
2559
|
async function listLinearIssues(agent, repoPath) {
|
|
2560
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
2560
|
+
const { getAdapter: getAdapter2 } = await import("./agents-HWIPJLC3.js");
|
|
2561
2561
|
await requireAgent(agent, { requireLinear: true });
|
|
2562
2562
|
const adapter = getAdapter2(agent);
|
|
2563
2563
|
if (!adapter.listLinearIssues) {
|
|
@@ -2637,10 +2637,10 @@ function createChatTab(input) {
|
|
|
2637
2637
|
userSetTitle: true,
|
|
2638
2638
|
...binding,
|
|
2639
2639
|
agent: input.agent ?? from.agent,
|
|
2640
|
-
model: input.agent && input.agent !== from.agent ? null : from.model,
|
|
2640
|
+
model: input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model,
|
|
2641
2641
|
fast: from.fast,
|
|
2642
2642
|
planMode: from.planMode,
|
|
2643
|
-
autonomy: from.autonomy,
|
|
2643
|
+
autonomy: input.autonomy ?? from.autonomy,
|
|
2644
2644
|
attachments: input.attachments ?? [],
|
|
2645
2645
|
status: "idle"
|
|
2646
2646
|
});
|
|
@@ -3546,6 +3546,7 @@ var Orchestrator = class {
|
|
|
3546
3546
|
...fresh.agent === "claude" && fresh.sessionId ? [] : [instructions, seed]
|
|
3547
3547
|
].filter(Boolean).join("\n\n---\n\n");
|
|
3548
3548
|
try {
|
|
3549
|
+
let lastStderr = "";
|
|
3549
3550
|
const handle = await spawnAgentTurn(
|
|
3550
3551
|
fresh,
|
|
3551
3552
|
{ cachedPrefix, prompt: agentPrompt },
|
|
@@ -3554,6 +3555,9 @@ var Orchestrator = class {
|
|
|
3554
3555
|
if (event.type === "session_id") {
|
|
3555
3556
|
updateThread(threadId, { sessionId: event.data });
|
|
3556
3557
|
}
|
|
3558
|
+
if (event.type === "stderr" && typeof event.data === "string" && event.data.trim()) {
|
|
3559
|
+
lastStderr = event.data.trim();
|
|
3560
|
+
}
|
|
3557
3561
|
}
|
|
3558
3562
|
);
|
|
3559
3563
|
this.activeTurns.set(threadId, handle);
|
|
@@ -3599,7 +3603,12 @@ var Orchestrator = class {
|
|
|
3599
3603
|
this.emit({ type: "status_changed", threadId, status: "stopped" });
|
|
3600
3604
|
this.emit({ type: "turn_finished", threadId, exitCode: result.exitCode });
|
|
3601
3605
|
} else {
|
|
3602
|
-
|
|
3606
|
+
const failDetail = lastStderr ? `exit ${result.exitCode}: ${lastStderr.slice(0, 500)}` : `exit ${result.exitCode}`;
|
|
3607
|
+
setStatus(
|
|
3608
|
+
threadId,
|
|
3609
|
+
result.exitCode === 0 ? "idle" : "error",
|
|
3610
|
+
result.exitCode === 0 ? null : failDetail
|
|
3611
|
+
);
|
|
3603
3612
|
this.emit({
|
|
3604
3613
|
type: "status_changed",
|
|
3605
3614
|
threadId,
|
|
@@ -4073,9 +4082,16 @@ var Orchestrator = class {
|
|
|
4073
4082
|
if (patch.planMode !== void 0) next.planMode = patch.planMode;
|
|
4074
4083
|
if (patch.model !== void 0) next.model = patch.model;
|
|
4075
4084
|
if (patch.agent !== void 0) {
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4085
|
+
if (patch.agent !== thread.agent) {
|
|
4086
|
+
if (thread.messages.length > 0) {
|
|
4087
|
+
throw new Error(
|
|
4088
|
+
`Cannot switch agent provider mid-chat (${thread.agent} \u2192 ${patch.agent}). Start a new chat tab instead.`
|
|
4089
|
+
);
|
|
4090
|
+
}
|
|
4091
|
+
next.agent = patch.agent;
|
|
4092
|
+
if (patch.agent !== "claude" && patch.model === void 0) next.model = null;
|
|
4093
|
+
next.sessionId = null;
|
|
4094
|
+
}
|
|
4079
4095
|
}
|
|
4080
4096
|
return updateThread(thread.id, next);
|
|
4081
4097
|
}
|