@sideboard-ai/core 0.1.24 → 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-JNMLRJ3D.js → chunk-OY47OEY2.js} +332 -58
- package/dist/index.cjs +692 -65
- package/dist/index.d.cts +152 -3
- package/dist/index.d.ts +152 -3
- package/dist/index.js +35 -2
- package/dist/mcp/run-stdio.cjs +579 -24
- package/dist/mcp/run-stdio.js +2 -2
- package/package.json +1 -1
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -4177,6 +4177,35 @@ var init_claude = __esm({
|
|
|
4177
4177
|
});
|
|
4178
4178
|
|
|
4179
4179
|
// src/agents/codex.ts
|
|
4180
|
+
async function listCodexModels() {
|
|
4181
|
+
const now = Date.now();
|
|
4182
|
+
if (cachedCodexModels && now - cachedCodexModels.at < CODEX_MODEL_CACHE_MS) {
|
|
4183
|
+
return cachedCodexModels.models;
|
|
4184
|
+
}
|
|
4185
|
+
const which = await run("which", ["codex"], { reject: false });
|
|
4186
|
+
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
4187
|
+
const listed = await run("codex", ["debug", "models"], { reject: false });
|
|
4188
|
+
if (listed.exitCode !== 0 || !listed.stdout.trim()) {
|
|
4189
|
+
return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
|
|
4190
|
+
}
|
|
4191
|
+
try {
|
|
4192
|
+
const parsed = JSON.parse(listed.stdout);
|
|
4193
|
+
const rows = Array.isArray(parsed.models) ? parsed.models : [];
|
|
4194
|
+
const preferred = rows.filter((m) => (m.visibility ?? "list") === "list");
|
|
4195
|
+
const source = preferred.length > 0 ? preferred : rows;
|
|
4196
|
+
const models = source.map((m) => ({
|
|
4197
|
+
id: (m.slug || "").trim(),
|
|
4198
|
+
displayName: (m.display_name || m.slug || "").trim(),
|
|
4199
|
+
description: m.description,
|
|
4200
|
+
priority: typeof m.priority === "number" ? m.priority : 999
|
|
4201
|
+
})).filter((m) => m.id).sort((a, b) => a.priority - b.priority).map(({ id, displayName, description }) => ({ id, displayName, description }));
|
|
4202
|
+
if (models.length === 0) return FALLBACK_CODEX_MODELS;
|
|
4203
|
+
cachedCodexModels = { at: now, models };
|
|
4204
|
+
return models;
|
|
4205
|
+
} catch {
|
|
4206
|
+
return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4180
4209
|
function usageFromCodex(usage) {
|
|
4181
4210
|
if (!usage) return null;
|
|
4182
4211
|
const inputTokens = Number(usage.input_tokens ?? 0);
|
|
@@ -4200,7 +4229,7 @@ function codexConfigHasNetworkAccess() {
|
|
|
4200
4229
|
}
|
|
4201
4230
|
return false;
|
|
4202
4231
|
}
|
|
4203
|
-
var import_node_fs11, import_node_os7, import_node_path11, CODEX_PROMPT_ARG_MAX, codexAdapter;
|
|
4232
|
+
var import_node_fs11, import_node_os7, import_node_path11, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
4204
4233
|
var init_codex = __esm({
|
|
4205
4234
|
"src/agents/codex.ts"() {
|
|
4206
4235
|
"use strict";
|
|
@@ -4211,6 +4240,15 @@ var init_codex = __esm({
|
|
|
4211
4240
|
init_turn_input();
|
|
4212
4241
|
init_types();
|
|
4213
4242
|
CODEX_PROMPT_ARG_MAX = 2e5;
|
|
4243
|
+
FALLBACK_CODEX_MODELS = [
|
|
4244
|
+
{ id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
|
|
4245
|
+
{ id: "gpt-5.6-terra", displayName: "GPT-5.6 Terra" },
|
|
4246
|
+
{ id: "gpt-5.6-luna", displayName: "GPT-5.6 Luna" },
|
|
4247
|
+
{ id: "gpt-5.5", displayName: "GPT-5.5" },
|
|
4248
|
+
{ id: "gpt-5.2", displayName: "GPT-5.2" }
|
|
4249
|
+
];
|
|
4250
|
+
cachedCodexModels = null;
|
|
4251
|
+
CODEX_MODEL_CACHE_MS = 5 * 60 * 1e3;
|
|
4214
4252
|
codexAdapter = {
|
|
4215
4253
|
kind: "codex",
|
|
4216
4254
|
async detect() {
|
|
@@ -4256,6 +4294,7 @@ var init_codex = __esm({
|
|
|
4256
4294
|
);
|
|
4257
4295
|
}
|
|
4258
4296
|
const mode = permissionMode(thread);
|
|
4297
|
+
const model = thread.model?.trim();
|
|
4259
4298
|
const args = [
|
|
4260
4299
|
"exec",
|
|
4261
4300
|
...sessionId ? ["resume", sessionId] : [],
|
|
@@ -4266,7 +4305,8 @@ var init_codex = __esm({
|
|
|
4266
4305
|
"--sandbox",
|
|
4267
4306
|
mode.codexSandbox,
|
|
4268
4307
|
"--ask-for-approval",
|
|
4269
|
-
"never"
|
|
4308
|
+
"never",
|
|
4309
|
+
...model ? ["--model", model] : []
|
|
4270
4310
|
];
|
|
4271
4311
|
return {
|
|
4272
4312
|
file: "codex",
|
|
@@ -4447,6 +4487,35 @@ function resolveCursorApiKey() {
|
|
|
4447
4487
|
if (fromEnv) return fromEnv;
|
|
4448
4488
|
return (loadAppSettings().environment.CURSOR_API_KEY || "").trim();
|
|
4449
4489
|
}
|
|
4490
|
+
function isCursorAutoModel(model) {
|
|
4491
|
+
const id = (model ?? "").trim().toLowerCase();
|
|
4492
|
+
return !id || id === "default" || id === "auto";
|
|
4493
|
+
}
|
|
4494
|
+
function resolveCursorModelId(model) {
|
|
4495
|
+
if (isCursorAutoModel(model)) return "default";
|
|
4496
|
+
return model.trim();
|
|
4497
|
+
}
|
|
4498
|
+
async function listCursorModels() {
|
|
4499
|
+
const now = Date.now();
|
|
4500
|
+
if (cachedModels && now - cachedModels.at < MODEL_CACHE_MS) {
|
|
4501
|
+
return cachedModels.models;
|
|
4502
|
+
}
|
|
4503
|
+
const apiKey = resolveCursorApiKey();
|
|
4504
|
+
if (!apiKey) return FALLBACK_CURSOR_MODELS;
|
|
4505
|
+
try {
|
|
4506
|
+
const listed = await import_sdk.Cursor.models.list({ apiKey });
|
|
4507
|
+
const models = listed.map((m) => ({
|
|
4508
|
+
id: m.id,
|
|
4509
|
+
displayName: m.displayName || m.id,
|
|
4510
|
+
description: m.description
|
|
4511
|
+
})).filter((m) => Boolean(m.id));
|
|
4512
|
+
if (models.length === 0) return FALLBACK_CURSOR_MODELS;
|
|
4513
|
+
cachedModels = { at: now, models };
|
|
4514
|
+
return models;
|
|
4515
|
+
} catch {
|
|
4516
|
+
return cachedModels?.models ?? FALLBACK_CURSOR_MODELS;
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4450
4519
|
function entryDir() {
|
|
4451
4520
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
4452
4521
|
if (cjsDir) return cjsDir;
|
|
@@ -4478,7 +4547,7 @@ function cursorRunnerPath() {
|
|
|
4478
4547
|
}
|
|
4479
4548
|
return candidates[0];
|
|
4480
4549
|
}
|
|
4481
|
-
var import_node_fs12, import_node_module2, import_node_path12, import_node_url2, import_sdk, import_meta2, cursorAdapter;
|
|
4550
|
+
var import_node_fs12, import_node_module2, import_node_path12, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
|
|
4482
4551
|
var init_cursor = __esm({
|
|
4483
4552
|
"src/agents/cursor.ts"() {
|
|
4484
4553
|
"use strict";
|
|
@@ -4493,6 +4562,13 @@ var init_cursor = __esm({
|
|
|
4493
4562
|
init_turn_input();
|
|
4494
4563
|
init_cursor_events();
|
|
4495
4564
|
import_meta2 = {};
|
|
4565
|
+
FALLBACK_CURSOR_MODELS = [
|
|
4566
|
+
{ id: "default", displayName: "Auto" },
|
|
4567
|
+
{ id: "composer-2.5", displayName: "Composer 2.5" },
|
|
4568
|
+
{ id: "composer-2", displayName: "Composer 2" }
|
|
4569
|
+
];
|
|
4570
|
+
cachedModels = null;
|
|
4571
|
+
MODEL_CACHE_MS = 5 * 60 * 1e3;
|
|
4496
4572
|
cursorAdapter = {
|
|
4497
4573
|
kind: "cursor",
|
|
4498
4574
|
async detect() {
|
|
@@ -4543,12 +4619,16 @@ var init_cursor = __esm({
|
|
|
4543
4619
|
};
|
|
4544
4620
|
const runner = cursorRunnerPath();
|
|
4545
4621
|
const isTs = runner.endsWith(".ts");
|
|
4622
|
+
const whichNode = await run("which", ["node"], { reject: false });
|
|
4623
|
+
const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
|
|
4624
|
+
const file = nodeBin || process.execPath;
|
|
4546
4625
|
return {
|
|
4547
|
-
file
|
|
4626
|
+
file,
|
|
4548
4627
|
args: isTs ? ["--import", "tsx", runner] : [runner],
|
|
4549
4628
|
cwd: thread.worktreePath,
|
|
4550
4629
|
stdin: JSON.stringify(req),
|
|
4551
4630
|
env: {
|
|
4631
|
+
...nodeBin ? {} : { ELECTRON_RUN_AS_NODE: "1" },
|
|
4552
4632
|
...apiKey ? { CURSOR_API_KEY: apiKey } : {}
|
|
4553
4633
|
}
|
|
4554
4634
|
};
|
|
@@ -4573,6 +4653,46 @@ var init_cursor = __esm({
|
|
|
4573
4653
|
});
|
|
4574
4654
|
|
|
4575
4655
|
// src/agents/opencode.ts
|
|
4656
|
+
function displayNameFromOpencodeId(id) {
|
|
4657
|
+
const slash = id.indexOf("/");
|
|
4658
|
+
if (slash <= 0) return id;
|
|
4659
|
+
const provider = id.slice(0, slash);
|
|
4660
|
+
const name = id.slice(slash + 1);
|
|
4661
|
+
return `${provider} \xB7 ${name}`;
|
|
4662
|
+
}
|
|
4663
|
+
function sortOpencodeModelIds(ids) {
|
|
4664
|
+
return [...ids].sort((a, b) => {
|
|
4665
|
+
const aLatest = /latest|~/.test(a) ? 0 : 1;
|
|
4666
|
+
const bLatest = /latest|~/.test(b) ? 0 : 1;
|
|
4667
|
+
if (aLatest !== bLatest) return aLatest - bLatest;
|
|
4668
|
+
const aOc = a.startsWith("opencode/") ? 0 : 1;
|
|
4669
|
+
const bOc = b.startsWith("opencode/") ? 0 : 1;
|
|
4670
|
+
if (aOc !== bOc) return aOc - bOc;
|
|
4671
|
+
return a.localeCompare(b);
|
|
4672
|
+
});
|
|
4673
|
+
}
|
|
4674
|
+
async function listOpencodeModels() {
|
|
4675
|
+
const now = Date.now();
|
|
4676
|
+
if (cachedOpencodeModels && now - cachedOpencodeModels.at < OPENCODE_MODEL_CACHE_MS) {
|
|
4677
|
+
return cachedOpencodeModels.models;
|
|
4678
|
+
}
|
|
4679
|
+
const which = await run("which", ["opencode"], { reject: false });
|
|
4680
|
+
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
4681
|
+
const listed = await run("opencode", ["models"], { reject: false });
|
|
4682
|
+
if (listed.exitCode !== 0 || !listed.stdout.trim()) {
|
|
4683
|
+
return cachedOpencodeModels?.models ?? FALLBACK_OPENCODE_MODELS;
|
|
4684
|
+
}
|
|
4685
|
+
const ids = listed.stdout.split("\n").map((l) => l.trim()).filter((l) => /^[\w.~@+-]+\/[\w.~@+/-]+$/.test(l));
|
|
4686
|
+
const unique = [...new Set(ids)];
|
|
4687
|
+
if (unique.length === 0) return FALLBACK_OPENCODE_MODELS;
|
|
4688
|
+
const OPENCODE_PICKER_LIMIT = 60;
|
|
4689
|
+
const models = sortOpencodeModelIds(unique).slice(0, OPENCODE_PICKER_LIMIT).map((id) => ({
|
|
4690
|
+
id,
|
|
4691
|
+
displayName: displayNameFromOpencodeId(id)
|
|
4692
|
+
}));
|
|
4693
|
+
cachedOpencodeModels = { at: now, models };
|
|
4694
|
+
return models;
|
|
4695
|
+
}
|
|
4576
4696
|
function usageFromOpencode(tokens) {
|
|
4577
4697
|
if (!tokens) return null;
|
|
4578
4698
|
const inputTokens = Number(tokens.input ?? 0);
|
|
@@ -4585,13 +4705,26 @@ function usageFromOpencode(tokens) {
|
|
|
4585
4705
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
4586
4706
|
};
|
|
4587
4707
|
}
|
|
4588
|
-
var opencodeAdapter;
|
|
4708
|
+
var FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
4589
4709
|
var init_opencode = __esm({
|
|
4590
4710
|
"src/agents/opencode.ts"() {
|
|
4591
4711
|
"use strict";
|
|
4592
4712
|
init_run();
|
|
4593
4713
|
init_turn_input();
|
|
4594
4714
|
init_types();
|
|
4715
|
+
FALLBACK_OPENCODE_MODELS = [
|
|
4716
|
+
{ id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
|
|
4717
|
+
{
|
|
4718
|
+
id: "openrouter/~anthropic/claude-sonnet-latest",
|
|
4719
|
+
displayName: "openrouter \xB7 claude-sonnet-latest"
|
|
4720
|
+
},
|
|
4721
|
+
{
|
|
4722
|
+
id: "openrouter/~openai/gpt-latest",
|
|
4723
|
+
displayName: "openrouter \xB7 gpt-latest"
|
|
4724
|
+
}
|
|
4725
|
+
];
|
|
4726
|
+
cachedOpencodeModels = null;
|
|
4727
|
+
OPENCODE_MODEL_CACHE_MS = 5 * 60 * 1e3;
|
|
4595
4728
|
opencodeAdapter = {
|
|
4596
4729
|
kind: "opencode",
|
|
4597
4730
|
async detect() {
|
|
@@ -4623,6 +4756,7 @@ var init_opencode = __esm({
|
|
|
4623
4756
|
const prompt = flattenTurnInput(input);
|
|
4624
4757
|
const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
4625
4758
|
const mode = permissionMode(thread);
|
|
4759
|
+
const model = thread.model?.trim();
|
|
4626
4760
|
const args = [
|
|
4627
4761
|
"run",
|
|
4628
4762
|
"--dir",
|
|
@@ -4633,6 +4767,9 @@ var init_opencode = __esm({
|
|
|
4633
4767
|
if (sessionId) {
|
|
4634
4768
|
args.push("--session", sessionId);
|
|
4635
4769
|
}
|
|
4770
|
+
if (model) {
|
|
4771
|
+
args.push("--model", model);
|
|
4772
|
+
}
|
|
4636
4773
|
return {
|
|
4637
4774
|
file: "opencode",
|
|
4638
4775
|
args,
|
|
@@ -4760,6 +4897,183 @@ var init_opencode = __esm({
|
|
|
4760
4897
|
}
|
|
4761
4898
|
});
|
|
4762
4899
|
|
|
4900
|
+
// src/agents/install.ts
|
|
4901
|
+
function getAgentSetupInfo(agent) {
|
|
4902
|
+
return SETUP[agent];
|
|
4903
|
+
}
|
|
4904
|
+
function listAgentSetupInfo() {
|
|
4905
|
+
return Object.values(SETUP);
|
|
4906
|
+
}
|
|
4907
|
+
async function openInSystemTerminal(command) {
|
|
4908
|
+
ensureAgentPath();
|
|
4909
|
+
const trimmed = command.trim();
|
|
4910
|
+
if (!trimmed) throw new Error("Command is empty");
|
|
4911
|
+
if (process.platform === "darwin") {
|
|
4912
|
+
const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
4913
|
+
const script = `tell application "Terminal" to do script "${escaped}"`;
|
|
4914
|
+
const result = await run("osascript", ["-e", script], { reject: false });
|
|
4915
|
+
if (result.exitCode !== 0) {
|
|
4916
|
+
throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open Terminal");
|
|
4917
|
+
}
|
|
4918
|
+
await run("osascript", ["-e", 'tell application "Terminal" to activate'], {
|
|
4919
|
+
reject: false
|
|
4920
|
+
});
|
|
4921
|
+
return;
|
|
4922
|
+
}
|
|
4923
|
+
if (process.platform === "win32") {
|
|
4924
|
+
const result = await run(
|
|
4925
|
+
"cmd.exe",
|
|
4926
|
+
["/c", "start", "cmd.exe", "/k", trimmed],
|
|
4927
|
+
{ reject: false }
|
|
4928
|
+
);
|
|
4929
|
+
if (result.exitCode !== 0) {
|
|
4930
|
+
throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open cmd");
|
|
4931
|
+
}
|
|
4932
|
+
return;
|
|
4933
|
+
}
|
|
4934
|
+
const candidates = [
|
|
4935
|
+
{ file: "gnome-terminal", args: ["--", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
4936
|
+
{ file: "x-terminal-emulator", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
4937
|
+
{ file: "konsole", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
4938
|
+
{ file: "xterm", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] }
|
|
4939
|
+
];
|
|
4940
|
+
for (const c of candidates) {
|
|
4941
|
+
const which = await run("which", [c.file], { reject: false });
|
|
4942
|
+
if (which.exitCode !== 0 || !which.stdout.trim()) continue;
|
|
4943
|
+
const result = await run(c.file, c.args, { reject: false });
|
|
4944
|
+
if (result.exitCode === 0) return;
|
|
4945
|
+
}
|
|
4946
|
+
throw new Error(
|
|
4947
|
+
`No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
|
|
4948
|
+
);
|
|
4949
|
+
}
|
|
4950
|
+
async function installAgent(agent) {
|
|
4951
|
+
const info = getAgentSetupInfo(agent);
|
|
4952
|
+
if (info.kind === "bundled-sdk" || info.kind === "api-key") {
|
|
4953
|
+
return {
|
|
4954
|
+
ok: true,
|
|
4955
|
+
message: info.summary
|
|
4956
|
+
};
|
|
4957
|
+
}
|
|
4958
|
+
if (!info.installCommand) {
|
|
4959
|
+
return { ok: false, message: `No install command for ${agent}` };
|
|
4960
|
+
}
|
|
4961
|
+
if (/curl\s| \|\s*bash/.test(info.installCommand) || !info.npmPackage) {
|
|
4962
|
+
await openInSystemTerminal(info.installCommand);
|
|
4963
|
+
return {
|
|
4964
|
+
ok: true,
|
|
4965
|
+
openedTerminal: true,
|
|
4966
|
+
command: info.installCommand,
|
|
4967
|
+
message: `Opened Terminal to run: ${info.installCommand}`
|
|
4968
|
+
};
|
|
4969
|
+
}
|
|
4970
|
+
ensureAgentPath();
|
|
4971
|
+
const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
|
|
4972
|
+
const ok = result.exitCode === 0;
|
|
4973
|
+
if (!ok) {
|
|
4974
|
+
try {
|
|
4975
|
+
await openInSystemTerminal(info.installCommand);
|
|
4976
|
+
return {
|
|
4977
|
+
ok: false,
|
|
4978
|
+
openedTerminal: true,
|
|
4979
|
+
command: info.installCommand,
|
|
4980
|
+
exitCode: result.exitCode,
|
|
4981
|
+
stdout: result.stdout,
|
|
4982
|
+
stderr: result.stderr,
|
|
4983
|
+
message: `npm install failed (exit ${result.exitCode}). Opened Terminal with: ${info.installCommand}`
|
|
4984
|
+
};
|
|
4985
|
+
} catch {
|
|
4986
|
+
return {
|
|
4987
|
+
ok: false,
|
|
4988
|
+
command: info.installCommand,
|
|
4989
|
+
exitCode: result.exitCode,
|
|
4990
|
+
stdout: result.stdout,
|
|
4991
|
+
stderr: result.stderr,
|
|
4992
|
+
message: result.stderr.trim() || result.stdout.trim() || `npm install failed (exit ${result.exitCode})`
|
|
4993
|
+
};
|
|
4994
|
+
}
|
|
4995
|
+
}
|
|
4996
|
+
return {
|
|
4997
|
+
ok: true,
|
|
4998
|
+
command: info.installCommand,
|
|
4999
|
+
exitCode: 0,
|
|
5000
|
+
stdout: result.stdout,
|
|
5001
|
+
stderr: result.stderr,
|
|
5002
|
+
message: `Installed ${info.npmPackage}`
|
|
5003
|
+
};
|
|
5004
|
+
}
|
|
5005
|
+
async function loginAgent(agent) {
|
|
5006
|
+
const info = getAgentSetupInfo(agent);
|
|
5007
|
+
if (!info.loginCommand) {
|
|
5008
|
+
return {
|
|
5009
|
+
ok: true,
|
|
5010
|
+
message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
|
|
5011
|
+
};
|
|
5012
|
+
}
|
|
5013
|
+
await openInSystemTerminal(info.loginCommand);
|
|
5014
|
+
return {
|
|
5015
|
+
ok: true,
|
|
5016
|
+
openedTerminal: true,
|
|
5017
|
+
command: info.loginCommand,
|
|
5018
|
+
message: `Opened Terminal to run: ${info.loginCommand}`
|
|
5019
|
+
};
|
|
5020
|
+
}
|
|
5021
|
+
var SETUP;
|
|
5022
|
+
var init_install = __esm({
|
|
5023
|
+
"src/agents/install.ts"() {
|
|
5024
|
+
"use strict";
|
|
5025
|
+
init_run();
|
|
5026
|
+
init_path();
|
|
5027
|
+
SETUP = {
|
|
5028
|
+
claude: {
|
|
5029
|
+
agent: "claude",
|
|
5030
|
+
kind: "cli",
|
|
5031
|
+
summary: "Install the Claude Code CLI, then complete login in a terminal.",
|
|
5032
|
+
docsUrl: "https://code.claude.com/docs/en/install",
|
|
5033
|
+
installCommand: "npm install -g @anthropic-ai/claude-code",
|
|
5034
|
+
loginCommand: "claude auth login",
|
|
5035
|
+
npmPackage: "@anthropic-ai/claude-code"
|
|
5036
|
+
},
|
|
5037
|
+
codex: {
|
|
5038
|
+
agent: "codex",
|
|
5039
|
+
kind: "cli",
|
|
5040
|
+
summary: "Install the Codex CLI, then run login in a terminal.",
|
|
5041
|
+
docsUrl: "https://github.com/openai/codex",
|
|
5042
|
+
installCommand: "npm install -g @openai/codex",
|
|
5043
|
+
loginCommand: "codex login",
|
|
5044
|
+
npmPackage: "@openai/codex"
|
|
5045
|
+
},
|
|
5046
|
+
opencode: {
|
|
5047
|
+
agent: "opencode",
|
|
5048
|
+
kind: "cli",
|
|
5049
|
+
summary: "Install OpenCode (curl installer or npm), then authenticate providers.",
|
|
5050
|
+
docsUrl: "https://opencode.ai/docs",
|
|
5051
|
+
// Prefer the official installer; npm package name is opencode-ai.
|
|
5052
|
+
installCommand: "curl -fsSL https://opencode.ai/install | bash",
|
|
5053
|
+
loginCommand: "opencode auth login",
|
|
5054
|
+
npmPackage: "opencode-ai@latest"
|
|
5055
|
+
},
|
|
5056
|
+
cursor: {
|
|
5057
|
+
agent: "cursor",
|
|
5058
|
+
kind: "bundled-sdk",
|
|
5059
|
+
summary: "No CLI install \u2014 Sideboard ships the Cursor SDK. Add a CURSOR_API_KEY from the Cursor dashboard.",
|
|
5060
|
+
docsUrl: "https://cursor.com/dashboard/integrations",
|
|
5061
|
+
installCommand: null,
|
|
5062
|
+
loginCommand: null
|
|
5063
|
+
},
|
|
5064
|
+
brightsy: {
|
|
5065
|
+
agent: "brightsy",
|
|
5066
|
+
kind: "cli",
|
|
5067
|
+
summary: "Install the Brightsy CLI, then run `brightsy login`.",
|
|
5068
|
+
docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
|
|
5069
|
+
installCommand: "npm install -g @brightsy/cli",
|
|
5070
|
+
loginCommand: "brightsy login",
|
|
5071
|
+
npmPackage: "@brightsy/cli"
|
|
5072
|
+
}
|
|
5073
|
+
};
|
|
5074
|
+
}
|
|
5075
|
+
});
|
|
5076
|
+
|
|
4763
5077
|
// src/agents/index.ts
|
|
4764
5078
|
var agents_exports = {};
|
|
4765
5079
|
__export(agents_exports, {
|
|
@@ -4774,10 +5088,20 @@ __export(agents_exports, {
|
|
|
4774
5088
|
encodeBrightsyTarget: () => encodeBrightsyTarget,
|
|
4775
5089
|
ensureAgentPath: () => ensureAgentPath,
|
|
4776
5090
|
getAdapter: () => getAdapter,
|
|
5091
|
+
getAgentSetupInfo: () => getAgentSetupInfo,
|
|
5092
|
+
installAgent: () => installAgent,
|
|
5093
|
+
isCursorAutoModel: () => isCursorAutoModel,
|
|
5094
|
+
listAgentSetupInfo: () => listAgentSetupInfo,
|
|
4777
5095
|
listBrightsyChatTargets: () => listBrightsyChatTargets,
|
|
5096
|
+
listCodexModels: () => listCodexModels,
|
|
5097
|
+
listCursorModels: () => listCursorModels,
|
|
5098
|
+
listOpencodeModels: () => listOpencodeModels,
|
|
5099
|
+
loginAgent: () => loginAgent,
|
|
5100
|
+
openInSystemTerminal: () => openInSystemTerminal,
|
|
4778
5101
|
opencodeAdapter: () => opencodeAdapter,
|
|
4779
5102
|
parseCursorRunnerLine: () => parseCursorRunnerLine,
|
|
4780
|
-
permissionMode: () => permissionMode
|
|
5103
|
+
permissionMode: () => permissionMode,
|
|
5104
|
+
resolveCursorModelId: () => resolveCursorModelId
|
|
4781
5105
|
});
|
|
4782
5106
|
function getAdapter(kind) {
|
|
4783
5107
|
return adapters[kind];
|
|
@@ -4801,8 +5125,10 @@ var init_agents = __esm({
|
|
|
4801
5125
|
init_codex();
|
|
4802
5126
|
init_cursor();
|
|
4803
5127
|
init_cursor_events();
|
|
5128
|
+
init_cursor();
|
|
4804
5129
|
init_opencode();
|
|
4805
5130
|
init_path();
|
|
5131
|
+
init_install();
|
|
4806
5132
|
adapters = {
|
|
4807
5133
|
claude: claudeAdapter,
|
|
4808
5134
|
codex: codexAdapter,
|
|
@@ -4936,11 +5262,11 @@ var init_workspaces = __esm({
|
|
|
4936
5262
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
4937
5263
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
4938
5264
|
var import_zod = require("zod");
|
|
4939
|
-
var
|
|
5265
|
+
var import_node_path23 = require("path");
|
|
4940
5266
|
|
|
4941
5267
|
// src/orchestrator/orchestrator.ts
|
|
4942
5268
|
var import_node_events = require("events");
|
|
4943
|
-
var
|
|
5269
|
+
var import_node_fs24 = require("fs");
|
|
4944
5270
|
|
|
4945
5271
|
// src/agents/spawn.ts
|
|
4946
5272
|
var import_node_readline = require("readline");
|
|
@@ -6310,10 +6636,10 @@ function createChatTab(input) {
|
|
|
6310
6636
|
userSetTitle: true,
|
|
6311
6637
|
...binding,
|
|
6312
6638
|
agent: input.agent ?? from.agent,
|
|
6313
|
-
model: input.agent && input.agent !== from.agent ? null : from.model,
|
|
6639
|
+
model: input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model,
|
|
6314
6640
|
fast: from.fast,
|
|
6315
6641
|
planMode: from.planMode,
|
|
6316
|
-
autonomy: from.autonomy,
|
|
6642
|
+
autonomy: input.autonomy ?? from.autonomy,
|
|
6317
6643
|
attachments: input.attachments ?? [],
|
|
6318
6644
|
status: "idle"
|
|
6319
6645
|
});
|
|
@@ -6350,12 +6676,16 @@ async function forkThreadWorktree(input, onSetupLine) {
|
|
|
6350
6676
|
repoPath: from.repoPath,
|
|
6351
6677
|
agent: input.agent ?? from.agent,
|
|
6352
6678
|
autonomy: from.autonomy,
|
|
6679
|
+
model: from.model,
|
|
6680
|
+
fast: from.fast,
|
|
6681
|
+
planMode: from.planMode,
|
|
6353
6682
|
title: input.title?.trim() || void 0,
|
|
6354
|
-
parentThreadId: from.id
|
|
6683
|
+
parentThreadId: from.id,
|
|
6684
|
+
attachments: [attachment]
|
|
6355
6685
|
},
|
|
6356
6686
|
onSetupLine
|
|
6357
6687
|
);
|
|
6358
|
-
return
|
|
6688
|
+
return thread;
|
|
6359
6689
|
}
|
|
6360
6690
|
|
|
6361
6691
|
// src/threads/adopt.ts
|
|
@@ -7513,6 +7843,9 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
7513
7843
|
parts.push("");
|
|
7514
7844
|
parts.push(`## Attachment: ${att.name}`);
|
|
7515
7845
|
parts.push(`Kind: ${att.kind}`);
|
|
7846
|
+
if (att.path) {
|
|
7847
|
+
parts.push(`Path in worktree: \`${att.path}\``);
|
|
7848
|
+
}
|
|
7516
7849
|
parts.push("");
|
|
7517
7850
|
parts.push(att.content);
|
|
7518
7851
|
}
|
|
@@ -7555,9 +7888,198 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
7555
7888
|
};
|
|
7556
7889
|
}
|
|
7557
7890
|
|
|
7558
|
-
// src/
|
|
7891
|
+
// src/composer/stage-files.ts
|
|
7559
7892
|
var import_node_fs22 = require("fs");
|
|
7560
7893
|
var import_node_path21 = require("path");
|
|
7894
|
+
var import_node_crypto3 = require("crypto");
|
|
7895
|
+
var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
7896
|
+
"png",
|
|
7897
|
+
"jpg",
|
|
7898
|
+
"jpeg",
|
|
7899
|
+
"gif",
|
|
7900
|
+
"webp",
|
|
7901
|
+
"svg",
|
|
7902
|
+
"bmp",
|
|
7903
|
+
"ico"
|
|
7904
|
+
]);
|
|
7905
|
+
var IMAGE_MIME_BY_EXT = {
|
|
7906
|
+
png: "image/png",
|
|
7907
|
+
jpg: "image/jpeg",
|
|
7908
|
+
jpeg: "image/jpeg",
|
|
7909
|
+
gif: "image/gif",
|
|
7910
|
+
webp: "image/webp",
|
|
7911
|
+
svg: "image/svg+xml",
|
|
7912
|
+
bmp: "image/bmp",
|
|
7913
|
+
ico: "image/x-icon"
|
|
7914
|
+
};
|
|
7915
|
+
var ATTACHMENTS_DIR = ".sideboard/attachments";
|
|
7916
|
+
var ATTACHMENTS_GITIGNORE = `# Sideboard review / composer attachments (local only)
|
|
7917
|
+
*
|
|
7918
|
+
!.gitignore
|
|
7919
|
+
`;
|
|
7920
|
+
var MAX_INLINE_BYTES = 4e5;
|
|
7921
|
+
var MAX_PREVIEW_BYTES = 5e6;
|
|
7922
|
+
function fileExtension(filePath) {
|
|
7923
|
+
const base = (0, import_node_path21.basename)(filePath).toLowerCase();
|
|
7924
|
+
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
7925
|
+
}
|
|
7926
|
+
function isImageFilePath(filePath) {
|
|
7927
|
+
return IMAGE_EXTENSIONS2.has(fileExtension(filePath));
|
|
7928
|
+
}
|
|
7929
|
+
function imageMimeType(filePath) {
|
|
7930
|
+
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
7931
|
+
}
|
|
7932
|
+
function ensureAttachmentsDir(worktreePath) {
|
|
7933
|
+
const dir = (0, import_node_path21.join)(worktreePath, ATTACHMENTS_DIR);
|
|
7934
|
+
(0, import_node_fs22.mkdirSync)(dir, { recursive: true });
|
|
7935
|
+
const gi = (0, import_node_path21.join)(dir, ".gitignore");
|
|
7936
|
+
if (!(0, import_node_fs22.existsSync)(gi)) {
|
|
7937
|
+
(0, import_node_fs22.writeFileSync)(gi, ATTACHMENTS_GITIGNORE, "utf8");
|
|
7938
|
+
}
|
|
7939
|
+
return dir;
|
|
7940
|
+
}
|
|
7941
|
+
function uniqueAttachmentName(dir, originalName) {
|
|
7942
|
+
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
7943
|
+
if (!(0, import_node_fs22.existsSync)((0, import_node_path21.join)(dir, safe))) return safe;
|
|
7944
|
+
const ext = (0, import_node_path21.extname)(safe);
|
|
7945
|
+
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
7946
|
+
for (let i = 1; i < 1e4; i++) {
|
|
7947
|
+
const candidate = `${stem}-${i}${ext}`;
|
|
7948
|
+
if (!(0, import_node_fs22.existsSync)((0, import_node_path21.join)(dir, candidate))) return candidate;
|
|
7949
|
+
}
|
|
7950
|
+
return `${stem}-${(0, import_node_crypto3.randomUUID)()}${ext}`;
|
|
7951
|
+
}
|
|
7952
|
+
function previewDataUrlFromBuf(filePath, buf) {
|
|
7953
|
+
if (!isImageFilePath(filePath)) return void 0;
|
|
7954
|
+
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
7955
|
+
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
7956
|
+
}
|
|
7957
|
+
function attachmentFromBuffer(name, buf, opts) {
|
|
7958
|
+
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
7959
|
+
if (isImageFilePath(name)) {
|
|
7960
|
+
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
7961
|
+
return {
|
|
7962
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
7963
|
+
name,
|
|
7964
|
+
kind: "file",
|
|
7965
|
+
path: opts.path,
|
|
7966
|
+
previewDataUrl,
|
|
7967
|
+
content: [
|
|
7968
|
+
`Image attached: ${pathHint}`,
|
|
7969
|
+
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
7970
|
+
].join("\n")
|
|
7971
|
+
};
|
|
7972
|
+
}
|
|
7973
|
+
if (buf.length > MAX_INLINE_BYTES) {
|
|
7974
|
+
return {
|
|
7975
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
7976
|
+
name,
|
|
7977
|
+
kind: "file",
|
|
7978
|
+
path: opts.path,
|
|
7979
|
+
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
7980
|
+
};
|
|
7981
|
+
}
|
|
7982
|
+
if (buf.includes(0)) {
|
|
7983
|
+
return {
|
|
7984
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
7985
|
+
name,
|
|
7986
|
+
kind: "file",
|
|
7987
|
+
path: opts.path,
|
|
7988
|
+
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
7989
|
+
};
|
|
7990
|
+
}
|
|
7991
|
+
return {
|
|
7992
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
7993
|
+
name,
|
|
7994
|
+
kind: "file",
|
|
7995
|
+
path: opts.path,
|
|
7996
|
+
content: buf.toString("utf8")
|
|
7997
|
+
};
|
|
7998
|
+
}
|
|
7999
|
+
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
8000
|
+
if (absolutePaths.length === 0) return [];
|
|
8001
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
8002
|
+
const out = [];
|
|
8003
|
+
for (const abs of absolutePaths) {
|
|
8004
|
+
const originalName = (0, import_node_path21.basename)(abs);
|
|
8005
|
+
try {
|
|
8006
|
+
const st = (0, import_node_fs22.statSync)(abs);
|
|
8007
|
+
if (!st.isFile()) continue;
|
|
8008
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
8009
|
+
const destAbs = (0, import_node_path21.join)(dir, name);
|
|
8010
|
+
(0, import_node_fs22.copyFileSync)(abs, destAbs);
|
|
8011
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
8012
|
+
const buf = (0, import_node_fs22.readFileSync)(destAbs);
|
|
8013
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
8014
|
+
} catch (err) {
|
|
8015
|
+
out.push({
|
|
8016
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
8017
|
+
name: originalName,
|
|
8018
|
+
kind: "file",
|
|
8019
|
+
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
8020
|
+
});
|
|
8021
|
+
}
|
|
8022
|
+
}
|
|
8023
|
+
return out;
|
|
8024
|
+
}
|
|
8025
|
+
function stageBuffersAsAttachments(worktreePath, buffers) {
|
|
8026
|
+
if (buffers.length === 0) return [];
|
|
8027
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
8028
|
+
const out = [];
|
|
8029
|
+
for (const item of buffers) {
|
|
8030
|
+
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
8031
|
+
try {
|
|
8032
|
+
const buf = Buffer.from(item.dataBase64, "base64");
|
|
8033
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
8034
|
+
const destAbs = (0, import_node_path21.join)(dir, name);
|
|
8035
|
+
(0, import_node_fs22.writeFileSync)(destAbs, buf);
|
|
8036
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
8037
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
8038
|
+
} catch (err) {
|
|
8039
|
+
out.push({
|
|
8040
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
8041
|
+
name: originalName,
|
|
8042
|
+
kind: "file",
|
|
8043
|
+
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
8044
|
+
});
|
|
8045
|
+
}
|
|
8046
|
+
}
|
|
8047
|
+
return out;
|
|
8048
|
+
}
|
|
8049
|
+
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
8050
|
+
const out = [];
|
|
8051
|
+
for (const rel of relativePaths) {
|
|
8052
|
+
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
8053
|
+
out.push({
|
|
8054
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
8055
|
+
name: (0, import_node_path21.basename)(rel) || "file",
|
|
8056
|
+
kind: "file",
|
|
8057
|
+
content: `(invalid path: ${rel})`
|
|
8058
|
+
});
|
|
8059
|
+
continue;
|
|
8060
|
+
}
|
|
8061
|
+
const name = (0, import_node_path21.basename)(rel);
|
|
8062
|
+
try {
|
|
8063
|
+
const abs = (0, import_node_path21.join)(worktreePath, rel);
|
|
8064
|
+
const st = (0, import_node_fs22.statSync)(abs);
|
|
8065
|
+
if (!st.isFile()) continue;
|
|
8066
|
+
const buf = (0, import_node_fs22.readFileSync)(abs);
|
|
8067
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
8068
|
+
} catch (err) {
|
|
8069
|
+
out.push({
|
|
8070
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
8071
|
+
name,
|
|
8072
|
+
kind: "file",
|
|
8073
|
+
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
8074
|
+
});
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
return out;
|
|
8078
|
+
}
|
|
8079
|
+
|
|
8080
|
+
// src/agents/instructions.ts
|
|
8081
|
+
var import_node_fs23 = require("fs");
|
|
8082
|
+
var import_node_path22 = require("path");
|
|
7561
8083
|
init_worktree_labels();
|
|
7562
8084
|
function normPath2(p) {
|
|
7563
8085
|
return p.replace(/\/+$/, "");
|
|
@@ -7671,11 +8193,11 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
7671
8193
|
const out = [];
|
|
7672
8194
|
for (const rel of candidates) {
|
|
7673
8195
|
if (seen.has(rel)) continue;
|
|
7674
|
-
const abs = (0,
|
|
7675
|
-
if (!(0,
|
|
8196
|
+
const abs = (0, import_node_path22.join)(worktreePath, rel);
|
|
8197
|
+
if (!(0, import_node_fs23.existsSync)(abs)) continue;
|
|
7676
8198
|
try {
|
|
7677
|
-
if (!(0,
|
|
7678
|
-
let content = (0,
|
|
8199
|
+
if (!(0, import_node_fs23.statSync)(abs).isFile()) continue;
|
|
8200
|
+
let content = (0, import_node_fs23.readFileSync)(abs, "utf8");
|
|
7679
8201
|
if (!content.trim()) continue;
|
|
7680
8202
|
if (content.length > MAX_CHARS_PER_FILE) {
|
|
7681
8203
|
content = `${content.slice(0, MAX_CHARS_PER_FILE)}
|
|
@@ -7801,7 +8323,7 @@ var Orchestrator = class {
|
|
|
7801
8323
|
}
|
|
7802
8324
|
continue;
|
|
7803
8325
|
}
|
|
7804
|
-
if (!(0,
|
|
8326
|
+
if (!(0, import_node_fs24.existsSync)(thread.worktreePath)) {
|
|
7805
8327
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
7806
8328
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
7807
8329
|
continue;
|
|
@@ -8054,6 +8576,7 @@ var Orchestrator = class {
|
|
|
8054
8576
|
...fresh.agent === "claude" && fresh.sessionId ? [] : [instructions, seed]
|
|
8055
8577
|
].filter(Boolean).join("\n\n---\n\n");
|
|
8056
8578
|
try {
|
|
8579
|
+
let lastStderr = "";
|
|
8057
8580
|
const handle = await spawnAgentTurn(
|
|
8058
8581
|
fresh,
|
|
8059
8582
|
{ cachedPrefix, prompt: agentPrompt },
|
|
@@ -8062,6 +8585,9 @@ var Orchestrator = class {
|
|
|
8062
8585
|
if (event.type === "session_id") {
|
|
8063
8586
|
updateThread(threadId, { sessionId: event.data });
|
|
8064
8587
|
}
|
|
8588
|
+
if (event.type === "stderr" && typeof event.data === "string" && event.data.trim()) {
|
|
8589
|
+
lastStderr = event.data.trim();
|
|
8590
|
+
}
|
|
8065
8591
|
}
|
|
8066
8592
|
);
|
|
8067
8593
|
this.activeTurns.set(threadId, handle);
|
|
@@ -8107,7 +8633,12 @@ var Orchestrator = class {
|
|
|
8107
8633
|
this.emit({ type: "status_changed", threadId, status: "stopped" });
|
|
8108
8634
|
this.emit({ type: "turn_finished", threadId, exitCode: result.exitCode });
|
|
8109
8635
|
} else {
|
|
8110
|
-
|
|
8636
|
+
const failDetail = lastStderr ? `exit ${result.exitCode}: ${lastStderr.slice(0, 500)}` : `exit ${result.exitCode}`;
|
|
8637
|
+
setStatus(
|
|
8638
|
+
threadId,
|
|
8639
|
+
result.exitCode === 0 ? "idle" : "error",
|
|
8640
|
+
result.exitCode === 0 ? null : failDetail
|
|
8641
|
+
);
|
|
8111
8642
|
this.emit({
|
|
8112
8643
|
type: "status_changed",
|
|
8113
8644
|
threadId,
|
|
@@ -8581,9 +9112,16 @@ var Orchestrator = class {
|
|
|
8581
9112
|
if (patch.planMode !== void 0) next.planMode = patch.planMode;
|
|
8582
9113
|
if (patch.model !== void 0) next.model = patch.model;
|
|
8583
9114
|
if (patch.agent !== void 0) {
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
9115
|
+
if (patch.agent !== thread.agent) {
|
|
9116
|
+
if (thread.messages.length > 0) {
|
|
9117
|
+
throw new Error(
|
|
9118
|
+
`Cannot switch agent provider mid-chat (${thread.agent} \u2192 ${patch.agent}). Start a new chat tab instead.`
|
|
9119
|
+
);
|
|
9120
|
+
}
|
|
9121
|
+
next.agent = patch.agent;
|
|
9122
|
+
if (patch.agent !== "claude" && patch.model === void 0) next.model = null;
|
|
9123
|
+
next.sessionId = null;
|
|
9124
|
+
}
|
|
8587
9125
|
}
|
|
8588
9126
|
return updateThread(thread.id, next);
|
|
8589
9127
|
}
|
|
@@ -8613,6 +9151,23 @@ var Orchestrator = class {
|
|
|
8613
9151
|
setAttachments(threadRef, attachments) {
|
|
8614
9152
|
return updateThread(this.requireThread(threadRef).id, { attachments });
|
|
8615
9153
|
}
|
|
9154
|
+
/**
|
|
9155
|
+
* Stage OS / worktree files into composer attachments (copies external files
|
|
9156
|
+
* into `.sideboard/attachments/` so agents can Read images and binaries).
|
|
9157
|
+
*/
|
|
9158
|
+
attachComposerFiles(threadRef, opts) {
|
|
9159
|
+
const thread = this.requireThread(threadRef);
|
|
9160
|
+
const fromAbs = stageAbsolutePathsAsAttachments(
|
|
9161
|
+
thread.worktreePath,
|
|
9162
|
+
opts.absolutePaths ?? []
|
|
9163
|
+
);
|
|
9164
|
+
const fromRel = attachmentsFromWorktreePaths(
|
|
9165
|
+
thread.worktreePath,
|
|
9166
|
+
opts.relativePaths ?? []
|
|
9167
|
+
);
|
|
9168
|
+
const fromBuf = stageBuffersAsAttachments(thread.worktreePath, opts.buffers ?? []);
|
|
9169
|
+
return [...fromAbs, ...fromRel, ...fromBuf];
|
|
9170
|
+
}
|
|
8616
9171
|
listWorktreeChats(threadRef) {
|
|
8617
9172
|
const thread = this.requireThread(threadRef);
|
|
8618
9173
|
return threadsSharingWorktree(thread.worktreePath);
|
|
@@ -8672,7 +9227,7 @@ var Orchestrator = class {
|
|
|
8672
9227
|
updateThread(thread.id, { worktreePath: globalAgentCwd2() });
|
|
8673
9228
|
return setStatus(thread.id, "idle");
|
|
8674
9229
|
}
|
|
8675
|
-
if (!(0,
|
|
9230
|
+
if (!(0, import_node_fs24.existsSync)(thread.worktreePath)) {
|
|
8676
9231
|
const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
|
|
8677
9232
|
const { execa: execa7 } = await import("execa");
|
|
8678
9233
|
const slug = thread.worktreePath.split("/").pop();
|
|
@@ -8890,7 +9445,7 @@ async function startMcpServer() {
|
|
|
8890
9445
|
async () => {
|
|
8891
9446
|
const threads = orch.getThreads(true);
|
|
8892
9447
|
const lines = threads.map((t) => {
|
|
8893
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
9448
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path23.basename)(t.repoPath) || t.repoPath;
|
|
8894
9449
|
return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}`;
|
|
8895
9450
|
});
|
|
8896
9451
|
return {
|