@sideboard-ai/core 0.1.57 → 0.1.59
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-2YYWW723.js → agents-B2723EOF.js} +4 -4
- package/dist/{agents-AQFEFKBL.js → agents-EADRAAPG.js} +4 -4
- package/dist/{app-settings-2LQNRTBE.js → app-settings-TBHTJWLQ.js} +1 -1
- package/dist/{app-settings-73DI4B6T.js → app-settings-YBNZ4XSR.js} +1 -1
- package/dist/{chunk-5DMYULLC.js → chunk-2P2UK7E7.js} +2 -2
- package/dist/{chunk-7LNGIP3X.js → chunk-73AT5K4A.js} +15 -3
- package/dist/{chunk-DIOF73S2.js → chunk-75QR74KM.js} +7 -2
- package/dist/{chunk-EBWEKG52.js → chunk-CHGOMFTA.js} +3 -3
- package/dist/{chunk-C4BCC5X5.js → chunk-FGNBTFRD.js} +7 -2
- package/dist/{chunk-H6GGDLYS.js → chunk-JB2H7E7V.js} +1 -1
- package/dist/{chunk-BXJ76RHF.js → chunk-MBAL5FE6.js} +4 -4
- package/dist/{chunk-XOU6HNQJ.js → chunk-MFGGIRUA.js} +39 -13
- package/dist/{chunk-S42XDFKF.js → chunk-MLAST5BB.js} +3 -3
- package/dist/{chunk-C3J4GDW4.js → chunk-MX7UH5AT.js} +76 -60
- package/dist/{chunk-DQJ5D42H.js → chunk-NTYRBRE7.js} +44 -13
- package/dist/{chunk-DZFH2KLT.js → chunk-P7EQUFB6.js} +39 -13
- package/dist/{chunk-V2DUTUNC.js → chunk-QJBC4BRK.js} +2 -2
- package/dist/{chunk-ZNM4MAN4.js → chunk-RIWUU7FO.js} +15 -3
- package/dist/{chunk-UA5NDAHL.js → chunk-XWPKLRB3.js} +44 -13
- package/dist/{chunk-7F454EE2.js → chunk-ZXDOI6IH.js} +76 -53
- package/dist/{connected-teams-ONC4666A.js → connected-teams-MKIYKOYA.js} +2 -2
- package/dist/{connected-teams-2ANNZCP5.js → connected-teams-RSL4VB3X.js} +2 -2
- package/dist/{coordinator-prompt-RBKUNRPR.js → coordinator-prompt-4P23VVFC.js} +4 -4
- package/dist/{coordinator-prompt-ICF36NUQ.js → coordinator-prompt-LNWHZ64D.js} +4 -4
- package/dist/{global-workspace-667XLBW6.js → global-workspace-BHT4XUAA.js} +5 -5
- package/dist/{global-workspace-S7VLWPWG.js → global-workspace-TMMAVRVW.js} +5 -5
- package/dist/index.cjs +303 -115
- package/dist/index.d.cts +15 -6
- package/dist/index.d.ts +15 -6
- package/dist/index.js +157 -64
- package/dist/mcp/run-stdio.cjs +303 -126
- package/dist/mcp/run-stdio.js +156 -68
- package/dist/{run-ZJKYHXGN.js → run-GPSVV5OH.js} +1 -1
- package/dist/{run-H3IMNOYN.js → run-HZTBWGQR.js} +1 -1
- package/dist/{workspaces-FPJJXXAE.js → workspaces-3GO3EDQG.js} +6 -6
- package/dist/{workspaces-LYIDE2VR.js → workspaces-GFPGDGCS.js} +6 -6
- package/dist/{worktree-5KEQWSAF.js → worktree-3L2G6PCM.js} +2 -2
- package/dist/{worktree-RWGL7FUV.js → worktree-GBLHEFHR.js} +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -712,9 +712,14 @@ function resolveThreadDefaults(settings = loadAppSettings()) {
|
|
|
712
712
|
function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
|
|
713
713
|
const defaults = resolveThreadDefaults(settings);
|
|
714
714
|
const effort = overrides.effort === void 0 || overrides.effort === null ? defaults.effort : normalizeThinkingEffort(overrides.effort) ?? defaults.effort;
|
|
715
|
+
const agent = overrides.agent ?? defaults.agent;
|
|
716
|
+
let model = overrides.model === void 0 ? defaults.model : overrides.model?.trim() || null;
|
|
717
|
+
if (model && agent !== "cursor" && /^(default|auto)$/i.test(model.trim())) {
|
|
718
|
+
model = null;
|
|
719
|
+
}
|
|
715
720
|
return {
|
|
716
|
-
agent
|
|
717
|
-
model
|
|
721
|
+
agent,
|
|
722
|
+
model,
|
|
718
723
|
effort,
|
|
719
724
|
fast: overrides.fast === void 0 || overrides.fast === null ? defaults.fast : Boolean(overrides.fast)
|
|
720
725
|
};
|
|
@@ -2073,7 +2078,8 @@ async function run(file, args, opts) {
|
|
|
2073
2078
|
const result = await (0, import_execa.execa)(file, args, {
|
|
2074
2079
|
cwd: opts?.cwd,
|
|
2075
2080
|
env: { ...process.env, ...opts?.env },
|
|
2076
|
-
reject: opts?.reject ?? true
|
|
2081
|
+
reject: opts?.reject ?? true,
|
|
2082
|
+
...opts?.timeoutMs != null ? { timeout: opts.timeoutMs } : {}
|
|
2077
2083
|
});
|
|
2078
2084
|
return {
|
|
2079
2085
|
stdout: result.stdout ?? "",
|
|
@@ -2103,11 +2109,22 @@ async function git(args, cwd, opts) {
|
|
|
2103
2109
|
return run("git", [...prefix, ...args], {
|
|
2104
2110
|
cwd,
|
|
2105
2111
|
reject: opts?.reject,
|
|
2106
|
-
|
|
2112
|
+
timeoutMs: opts?.timeoutMs,
|
|
2113
|
+
// Never block forever on a credential/SSH prompt inside MCP / Electron.
|
|
2114
|
+
env: {
|
|
2115
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
2116
|
+
GIT_ASKPASS: process.env.GIT_ASKPASS || "echo",
|
|
2117
|
+
GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND || "ssh -o BatchMode=yes -o ConnectTimeout=15",
|
|
2118
|
+
...opts?.env
|
|
2119
|
+
}
|
|
2107
2120
|
});
|
|
2108
2121
|
}
|
|
2109
2122
|
async function gh(args, cwd, opts) {
|
|
2110
|
-
return run("gh", args, {
|
|
2123
|
+
return run("gh", args, {
|
|
2124
|
+
cwd,
|
|
2125
|
+
reject: opts?.reject,
|
|
2126
|
+
timeoutMs: opts?.timeoutMs
|
|
2127
|
+
});
|
|
2111
2128
|
}
|
|
2112
2129
|
async function resolveGhAuthToken(cwd) {
|
|
2113
2130
|
const result = await gh(["auth", "token"], cwd, { reject: false });
|
|
@@ -2576,12 +2593,16 @@ async function ensureGhPreferOrigin(cwd) {
|
|
|
2576
2593
|
const hasAlt = Boolean(await slugFromGitRemote(cwd, "upstream")) || Boolean(await slugFromGitRemote(cwd, "github"));
|
|
2577
2594
|
if (!hasAlt) return;
|
|
2578
2595
|
const view = await gh(["repo", "set-default", "--view"], cwd, {
|
|
2579
|
-
reject: false
|
|
2596
|
+
reject: false,
|
|
2597
|
+
timeoutMs: 15e3
|
|
2580
2598
|
});
|
|
2581
2599
|
const current = `${view.stdout}
|
|
2582
2600
|
${view.stderr}`;
|
|
2583
2601
|
if (view.exitCode === 0 && current.includes(originSlug)) return;
|
|
2584
|
-
await gh(["repo", "set-default", "origin"], cwd, {
|
|
2602
|
+
await gh(["repo", "set-default", "origin"], cwd, {
|
|
2603
|
+
reject: false,
|
|
2604
|
+
timeoutMs: 15e3
|
|
2605
|
+
});
|
|
2585
2606
|
}
|
|
2586
2607
|
async function originGhRepoEnv(cwd) {
|
|
2587
2608
|
await ensureGhPreferOrigin(cwd);
|
|
@@ -3127,20 +3148,42 @@ async function createThreadWorktree(opts) {
|
|
|
3127
3148
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
3128
3149
|
}
|
|
3129
3150
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
await
|
|
3133
|
-
|
|
3151
|
+
let startPoint = null;
|
|
3152
|
+
try {
|
|
3153
|
+
startPoint = await resolveWorktreeStartPoint(opts.repoPath, opts.sourceRef);
|
|
3154
|
+
} catch {
|
|
3155
|
+
startPoint = null;
|
|
3156
|
+
}
|
|
3157
|
+
if (!isLocalPrFetchBranch(opts.sourceRef)) {
|
|
3158
|
+
const fetchTimeoutMs = startPoint ? 12e3 : 45e3;
|
|
3159
|
+
await git(["fetch", "origin", "--prune"], opts.repoPath, {
|
|
3160
|
+
reject: false,
|
|
3161
|
+
timeoutMs: fetchTimeoutMs
|
|
3134
3162
|
});
|
|
3163
|
+
if (!opts.sourceRef.startsWith("origin/") && !opts.sourceRef.startsWith("refs/")) {
|
|
3164
|
+
await git(["fetch", "origin", opts.sourceRef], opts.repoPath, {
|
|
3165
|
+
reject: false,
|
|
3166
|
+
timeoutMs: fetchTimeoutMs
|
|
3167
|
+
});
|
|
3168
|
+
}
|
|
3169
|
+
try {
|
|
3170
|
+
startPoint = await resolveWorktreeStartPoint(
|
|
3171
|
+
opts.repoPath,
|
|
3172
|
+
opts.sourceRef
|
|
3173
|
+
);
|
|
3174
|
+
} catch (err) {
|
|
3175
|
+
if (!startPoint) throw err;
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
if (!startPoint) {
|
|
3179
|
+
throw new Error(
|
|
3180
|
+
`Invalid git reference: ${opts.sourceRef} (and fetch did not resolve it)`
|
|
3181
|
+
);
|
|
3135
3182
|
}
|
|
3136
|
-
const startPoint = await resolveWorktreeStartPoint(
|
|
3137
|
-
opts.repoPath,
|
|
3138
|
-
opts.sourceRef
|
|
3139
|
-
);
|
|
3140
3183
|
const add = await git(
|
|
3141
3184
|
["worktree", "add", "-b", branchName, worktreePath, startPoint],
|
|
3142
3185
|
opts.repoPath,
|
|
3143
|
-
{ reject: false }
|
|
3186
|
+
{ reject: false, timeoutMs: 6e4 }
|
|
3144
3187
|
);
|
|
3145
3188
|
if (add.exitCode !== 0) {
|
|
3146
3189
|
const err = `${add.stderr}
|
|
@@ -3151,7 +3194,7 @@ ${add.stdout}`;
|
|
|
3151
3194
|
const retry = await git(
|
|
3152
3195
|
["worktree", "add", "-b", alt, worktreePath, startPoint],
|
|
3153
3196
|
opts.repoPath,
|
|
3154
|
-
{ reject: false }
|
|
3197
|
+
{ reject: false, timeoutMs: 6e4 }
|
|
3155
3198
|
);
|
|
3156
3199
|
if (retry.exitCode === 0) {
|
|
3157
3200
|
branchName = alt;
|
|
@@ -3540,7 +3583,9 @@ function coordinatorTurnReminder(opts) {
|
|
|
3540
3583
|
"- You oversee Sideboard worktree agents. You are not yourself checked out in a project worktree.",
|
|
3541
3584
|
"- This cwd is a synthetic empty home (not a git repo). Emptiness here is expected \u2014 it is not a problem to fix.",
|
|
3542
3585
|
"- Registered workspaces / child threads are the fleet you manage via Sideboard MCP.",
|
|
3543
|
-
`-
|
|
3586
|
+
`- YOUR orchestration thread id is ${opts.parentId}`,
|
|
3587
|
+
`- Always pass parentThreadId="${opts.parentId}" on create_thread (never invent or reuse another uuid).`,
|
|
3588
|
+
`- Or omit parentThreadId \u2014 Sideboard MCP already binds children to ${opts.parentId}.`,
|
|
3544
3589
|
goal ? `- Goal / title: ${goal}` : null,
|
|
3545
3590
|
accountDefaultsPlaybookLine(),
|
|
3546
3591
|
`- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
|
|
@@ -3549,10 +3594,33 @@ function coordinatorTurnReminder(opts) {
|
|
|
3549
3594
|
"- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`."
|
|
3550
3595
|
].filter(Boolean).join("\n");
|
|
3551
3596
|
}
|
|
3552
|
-
function ensureGlobalCoordinatorCwd() {
|
|
3597
|
+
function ensureGlobalCoordinatorCwd(opts) {
|
|
3553
3598
|
const dir = globalAgentCwd();
|
|
3554
|
-
|
|
3599
|
+
try {
|
|
3600
|
+
(0, import_node_fs6.mkdirSync)(dir, { recursive: true });
|
|
3601
|
+
} catch {
|
|
3602
|
+
return dir;
|
|
3603
|
+
}
|
|
3555
3604
|
const reposDir = sideboardReposDir();
|
|
3605
|
+
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
3606
|
+
if (!orchId) {
|
|
3607
|
+
try {
|
|
3608
|
+
const existing = (0, import_node_fs6.readFileSync)((0, import_node_path7.join)(dir, "AGENTS.md"), "utf8");
|
|
3609
|
+
const m = existing.match(
|
|
3610
|
+
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
3611
|
+
);
|
|
3612
|
+
if (m?.[1]) orchId = m[1];
|
|
3613
|
+
} catch {
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
const parentBlock = orchId ? [
|
|
3617
|
+
"",
|
|
3618
|
+
`## This chat's id`,
|
|
3619
|
+
"",
|
|
3620
|
+
`YOUR orchestration thread id is \`${orchId}\`.`,
|
|
3621
|
+
`On every create_thread, pass parentThreadId="${orchId}" \u2014 or omit parentThreadId (Sideboard binds it automatically).`,
|
|
3622
|
+
"Never invent a uuid and never reuse an id from an earlier conversation."
|
|
3623
|
+
] : [];
|
|
3556
3624
|
const body = [
|
|
3557
3625
|
"# Sideboard Orchestration",
|
|
3558
3626
|
"",
|
|
@@ -3562,6 +3630,7 @@ function ensureGlobalCoordinatorCwd() {
|
|
|
3562
3630
|
"Repos from `list_workspaces` and threads from `list_threads` are the fleet you orchestrate.",
|
|
3563
3631
|
'For status questions ("what\'s going on?"), use `list_threads` / `list_workspaces` \u2014 never diagnose this synthetic home as a broken worktree.',
|
|
3564
3632
|
"Bash is fine for inspecting **child worktree** / registered-repo paths, and for greenfield repo setup under the Sideboard repos directory \u2014 not for treating this home as the project.",
|
|
3633
|
+
...parentBlock,
|
|
3565
3634
|
"",
|
|
3566
3635
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
3567
3636
|
"",
|
|
@@ -3569,16 +3638,21 @@ function ensureGlobalCoordinatorCwd() {
|
|
|
3569
3638
|
"",
|
|
3570
3639
|
coordinatorGreenfieldPlaybook(reposDir),
|
|
3571
3640
|
"",
|
|
3572
|
-
"When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered)
|
|
3641
|
+
"When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered).",
|
|
3642
|
+
orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
|
|
3573
3643
|
"Omit `agent` / `model` on `create_thread` unless you have a reason to override Account defaults.",
|
|
3644
|
+
"Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent (Account default) or use cursor/claude.",
|
|
3574
3645
|
"Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn.",
|
|
3575
3646
|
"Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
|
|
3576
3647
|
"Always ask worktree agents to open draft PRs (`send_to_thread` + `gh pr create --draft -R <origin>`); never open PRs from the orchestrator."
|
|
3577
3648
|
].join("\n");
|
|
3578
|
-
|
|
3649
|
+
try {
|
|
3650
|
+
(0, import_node_fs6.writeFileSync)((0, import_node_path7.join)(dir, "CLAUDE.md"), `${body}
|
|
3579
3651
|
`, "utf8");
|
|
3580
|
-
|
|
3652
|
+
(0, import_node_fs6.writeFileSync)((0, import_node_path7.join)(dir, "AGENTS.md"), `${body}
|
|
3581
3653
|
`, "utf8");
|
|
3654
|
+
} catch {
|
|
3655
|
+
}
|
|
3582
3656
|
return dir;
|
|
3583
3657
|
}
|
|
3584
3658
|
function coordinatorSystemPrompt(opts) {
|
|
@@ -3598,12 +3672,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
3598
3672
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
3599
3673
|
accountDefaultsPlaybookLine(),
|
|
3600
3674
|
coordinatorGreenfieldPlaybook(reposDir),
|
|
3601
|
-
"When creating threads, pass the correct repoPath for the target workspace
|
|
3675
|
+
"When creating threads, pass the correct repoPath for the target workspace.",
|
|
3676
|
+
`YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit parentThreadId (Sideboard binds it). Never invent a uuid.`,
|
|
3602
3677
|
"Omit agent/model on create_thread unless you need to override Account defaults.",
|
|
3603
3678
|
"Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 send_to_thread (ask for `gh pr create --draft -R <origin-owner/name>` using the workspace github slug) \u2192 wait_for_turn. Never target upstream. Never open PRs from the orchestrator.",
|
|
3604
3679
|
"Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
|
|
3605
3680
|
`Goal: ${opts.goal}`,
|
|
3606
|
-
`Parent thread id (pass as parentThreadId when creating children): ${opts.parentId}`,
|
|
3607
3681
|
"Registered workspaces:",
|
|
3608
3682
|
formatWorkspaceInventory(opts.workspaces)
|
|
3609
3683
|
].join("\n");
|
|
@@ -3629,7 +3703,7 @@ var init_coordinator_prompt = __esm({
|
|
|
3629
3703
|
"Workspaces:",
|
|
3630
3704
|
"- add_workspace / remove_workspace \u2014 register or unregister a git repo",
|
|
3631
3705
|
"Worktree threads (chats):",
|
|
3632
|
-
"- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId; omit agent and model to use Sideboard Account defaults (Settings \u2192 Default agent, model & effort)",
|
|
3706
|
+
"- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId; omit agent and model to use Sideboard Account defaults (Settings \u2192 Default agent, model & effort). If you are Codex, do not set agent=codex (nested Codex deadlocks)",
|
|
3633
3707
|
"- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
|
|
3634
3708
|
"- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
|
|
3635
3709
|
"- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
|
|
@@ -3641,7 +3715,7 @@ var init_coordinator_prompt = __esm({
|
|
|
3641
3715
|
"- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
|
|
3642
3716
|
"Inspect / review / PRs:",
|
|
3643
3717
|
"- get_diff \u2014 compact diff summary",
|
|
3644
|
-
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review."); then wait_for_turn / get_turn_result on the returned id',
|
|
3718
|
+
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review changes in this workspace."); then wait_for_turn / get_turn_result on the returned id',
|
|
3645
3719
|
"- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
|
|
3646
3720
|
"Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
|
|
3647
3721
|
"Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
|
|
@@ -4965,7 +5039,16 @@ async function resolveSideboardMcpServer() {
|
|
|
4965
5039
|
async function buildInjectedMcpServers(opts) {
|
|
4966
5040
|
const servers = [];
|
|
4967
5041
|
if (opts.includeSideboard) {
|
|
4968
|
-
|
|
5042
|
+
const sideboard = await resolveSideboardMcpServer();
|
|
5043
|
+
sideboard.env = {
|
|
5044
|
+
...sideboard.env ?? {},
|
|
5045
|
+
SIDEBOARD_APP_DATA: appDataDir()
|
|
5046
|
+
};
|
|
5047
|
+
const orchId = opts.orchestratorThreadId?.trim();
|
|
5048
|
+
if (orchId) {
|
|
5049
|
+
sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
|
|
5050
|
+
}
|
|
5051
|
+
servers.push(sideboard);
|
|
4969
5052
|
}
|
|
4970
5053
|
if (opts.includeBrightsy && isBrightsyConnected()) {
|
|
4971
5054
|
const cmd = await resolveBrightsyMcpCommand();
|
|
@@ -5009,6 +5092,8 @@ function toCodexMcpConfigArgs(servers) {
|
|
|
5009
5092
|
}
|
|
5010
5093
|
}
|
|
5011
5094
|
args.push("-c", `${prefix}.default_tools_approval_mode=${JSON.stringify("approve")}`);
|
|
5095
|
+
args.push("-c", `${prefix}.tool_timeout_sec=300`);
|
|
5096
|
+
args.push("-c", `${prefix}.startup_timeout_sec=30`);
|
|
5012
5097
|
}
|
|
5013
5098
|
return args;
|
|
5014
5099
|
}
|
|
@@ -5054,6 +5139,7 @@ var init_injected_mcp = __esm({
|
|
|
5054
5139
|
init_run();
|
|
5055
5140
|
init_config();
|
|
5056
5141
|
init_connected_teams();
|
|
5142
|
+
init_paths();
|
|
5057
5143
|
init_node_launch();
|
|
5058
5144
|
import_meta = {};
|
|
5059
5145
|
SIDEBOARD_MCP_ALLOWED_TOOLS = [
|
|
@@ -5077,6 +5163,16 @@ var init_injected_mcp = __esm({
|
|
|
5077
5163
|
|
|
5078
5164
|
// src/agents/types.ts
|
|
5079
5165
|
function permissionMode(thread) {
|
|
5166
|
+
if (thread.sourceType === "orchestration") {
|
|
5167
|
+
return {
|
|
5168
|
+
claude: "acceptEdits",
|
|
5169
|
+
opencodePermission: JSON.stringify({
|
|
5170
|
+
edit: "allow",
|
|
5171
|
+
bash: { "*": "allow", "rm -rf *": "deny" }
|
|
5172
|
+
}),
|
|
5173
|
+
codexSandbox: "danger-full-access"
|
|
5174
|
+
};
|
|
5175
|
+
}
|
|
5080
5176
|
if (thread.planMode) {
|
|
5081
5177
|
return {
|
|
5082
5178
|
claude: "plan",
|
|
@@ -5272,18 +5368,17 @@ var init_claude = __esm({
|
|
|
5272
5368
|
};
|
|
5273
5369
|
}
|
|
5274
5370
|
}
|
|
5275
|
-
const auth = await run(claude, ["auth", "status"], {
|
|
5371
|
+
const auth = await run(claude, ["auth", "status"], {
|
|
5372
|
+
reject: false,
|
|
5373
|
+
timeoutMs: 5e3
|
|
5374
|
+
});
|
|
5276
5375
|
const authenticated = auth.exitCode === 0;
|
|
5277
|
-
const servers = await loadMcpServers();
|
|
5278
|
-
const linearMcp = servers.some(
|
|
5279
|
-
(s) => s.connected && /linear/i.test(s.name)
|
|
5280
|
-
);
|
|
5281
5376
|
return {
|
|
5282
5377
|
agent: "claude",
|
|
5283
5378
|
installed: true,
|
|
5284
5379
|
authenticated,
|
|
5285
|
-
linearMcp,
|
|
5286
|
-
warnings:
|
|
5380
|
+
linearMcp: false,
|
|
5381
|
+
warnings: [],
|
|
5287
5382
|
reason: authenticated ? void 0 : "claude auth status failed \u2014 run `claude auth login`"
|
|
5288
5383
|
};
|
|
5289
5384
|
},
|
|
@@ -5304,7 +5399,8 @@ var init_claude = __esm({
|
|
|
5304
5399
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
5305
5400
|
const injectedServers = await buildInjectedMcpServers({
|
|
5306
5401
|
includeSideboard: true,
|
|
5307
|
-
includeBrightsy: isBrightsyConnected()
|
|
5402
|
+
includeBrightsy: isBrightsyConnected(),
|
|
5403
|
+
orchestratorThreadId: isOrchestrator ? thread.id : null
|
|
5308
5404
|
});
|
|
5309
5405
|
const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
|
|
5310
5406
|
const chromeOn = claudeChromeEnabled();
|
|
@@ -5550,6 +5646,15 @@ function asRecord(value) {
|
|
|
5550
5646
|
}
|
|
5551
5647
|
return void 0;
|
|
5552
5648
|
}
|
|
5649
|
+
function codexLooksAuthenticated() {
|
|
5650
|
+
const authPath = (0, import_node_path12.join)((0, import_node_os7.homedir)(), ".codex", "auth.json");
|
|
5651
|
+
if (!(0, import_node_fs12.existsSync)(authPath)) return false;
|
|
5652
|
+
try {
|
|
5653
|
+
return (0, import_node_fs12.statSync)(authPath).size > 2;
|
|
5654
|
+
} catch {
|
|
5655
|
+
return false;
|
|
5656
|
+
}
|
|
5657
|
+
}
|
|
5553
5658
|
var import_node_fs12, import_node_os7, import_node_path12, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
5554
5659
|
var init_codex = __esm({
|
|
5555
5660
|
"src/agents/codex.ts"() {
|
|
@@ -5575,7 +5680,7 @@ var init_codex = __esm({
|
|
|
5575
5680
|
codexAdapter = {
|
|
5576
5681
|
kind: "codex",
|
|
5577
5682
|
async detect() {
|
|
5578
|
-
const which = await run("which", ["codex"], { reject: false });
|
|
5683
|
+
const which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
|
|
5579
5684
|
if (which.exitCode !== 0) {
|
|
5580
5685
|
return {
|
|
5581
5686
|
agent: "codex",
|
|
@@ -5586,10 +5691,8 @@ var init_codex = __esm({
|
|
|
5586
5691
|
reason: "codex CLI not found on PATH"
|
|
5587
5692
|
};
|
|
5588
5693
|
}
|
|
5589
|
-
const
|
|
5590
|
-
const
|
|
5591
|
-
const mcp = await run("codex", ["mcp", "list", "--json"], { reject: false });
|
|
5592
|
-
const linearMcp = /linear/i.test(mcp.stdout + mcp.stderr);
|
|
5694
|
+
const authenticated = codexLooksAuthenticated();
|
|
5695
|
+
const linearMcp = false;
|
|
5593
5696
|
const warnings = [];
|
|
5594
5697
|
if (!codexConfigHasNetworkAccess()) {
|
|
5595
5698
|
warnings.push(
|
|
@@ -5602,7 +5705,7 @@ var init_codex = __esm({
|
|
|
5602
5705
|
authenticated,
|
|
5603
5706
|
linearMcp,
|
|
5604
5707
|
warnings,
|
|
5605
|
-
reason: authenticated ? void 0 : "
|
|
5708
|
+
reason: authenticated ? void 0 : "Codex auth not found \u2014 run `codex login` (expected ~/.codex/auth.json)"
|
|
5606
5709
|
};
|
|
5607
5710
|
},
|
|
5608
5711
|
async buildTurn(thread, input) {
|
|
@@ -5620,23 +5723,26 @@ var init_codex = __esm({
|
|
|
5620
5723
|
const model = thread.model?.trim();
|
|
5621
5724
|
const injected = await buildInjectedMcpServers({
|
|
5622
5725
|
includeSideboard: true,
|
|
5623
|
-
includeBrightsy: isBrightsyConnected()
|
|
5726
|
+
includeBrightsy: isBrightsyConnected(),
|
|
5727
|
+
orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
|
|
5624
5728
|
});
|
|
5625
5729
|
const mcpOverrides = toCodexMcpConfigArgs(injected);
|
|
5626
|
-
const
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5730
|
+
const execOpts = [
|
|
5731
|
+
// Global orchestration cwd is not a git repo; without this Codex ≥0.147
|
|
5732
|
+
// refuses to start ("Not inside a trusted directory").
|
|
5733
|
+
"--skip-git-repo-check",
|
|
5630
5734
|
"--cd",
|
|
5631
5735
|
thread.worktreePath,
|
|
5632
5736
|
"--json",
|
|
5633
5737
|
"--sandbox",
|
|
5634
5738
|
mode.codexSandbox,
|
|
5635
|
-
|
|
5636
|
-
"
|
|
5739
|
+
// `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
|
|
5740
|
+
"-c",
|
|
5741
|
+
'approval_policy="never"',
|
|
5637
5742
|
...model ? ["--model", model] : [],
|
|
5638
5743
|
...mcpOverrides
|
|
5639
5744
|
];
|
|
5745
|
+
const args = sessionId ? ["exec", ...execOpts, "resume", sessionId, promptArg] : ["exec", ...execOpts, promptArg];
|
|
5640
5746
|
return {
|
|
5641
5747
|
file: "codex",
|
|
5642
5748
|
args,
|
|
@@ -5738,7 +5844,7 @@ var init_codex = __esm({
|
|
|
5738
5844
|
if (sessionId) {
|
|
5739
5845
|
return {
|
|
5740
5846
|
file: "codex",
|
|
5741
|
-
args: ["exec", "
|
|
5847
|
+
args: ["exec", "--cd", thread.worktreePath, "resume", sessionId],
|
|
5742
5848
|
cwd: thread.worktreePath
|
|
5743
5849
|
};
|
|
5744
5850
|
}
|
|
@@ -5754,12 +5860,12 @@ var init_codex = __esm({
|
|
|
5754
5860
|
"codex",
|
|
5755
5861
|
[
|
|
5756
5862
|
"exec",
|
|
5757
|
-
prompt,
|
|
5758
5863
|
"--json",
|
|
5759
5864
|
"--sandbox",
|
|
5760
5865
|
"read-only",
|
|
5761
|
-
"
|
|
5762
|
-
"never"
|
|
5866
|
+
"-c",
|
|
5867
|
+
'approval_policy="never"',
|
|
5868
|
+
prompt
|
|
5763
5869
|
],
|
|
5764
5870
|
{ reject: false }
|
|
5765
5871
|
);
|
|
@@ -6056,26 +6162,13 @@ var init_cursor = __esm({
|
|
|
6056
6162
|
reason: "CURSOR_API_KEY not set \u2014 add it in Settings \u2192 Agents \u2192 Cursor, or Settings \u2192 Environment"
|
|
6057
6163
|
};
|
|
6058
6164
|
}
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
warnings: []
|
|
6067
|
-
};
|
|
6068
|
-
} catch (err) {
|
|
6069
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6070
|
-
return {
|
|
6071
|
-
agent: "cursor",
|
|
6072
|
-
installed: true,
|
|
6073
|
-
authenticated: false,
|
|
6074
|
-
linearMcp: false,
|
|
6075
|
-
warnings: [],
|
|
6076
|
-
reason: `Cursor API auth failed: ${message}`
|
|
6077
|
-
};
|
|
6078
|
-
}
|
|
6165
|
+
return {
|
|
6166
|
+
agent: "cursor",
|
|
6167
|
+
installed: true,
|
|
6168
|
+
authenticated: true,
|
|
6169
|
+
linearMcp: false,
|
|
6170
|
+
warnings: []
|
|
6171
|
+
};
|
|
6079
6172
|
},
|
|
6080
6173
|
async buildTurn(thread, input) {
|
|
6081
6174
|
const prompt = flattenTurnInput(input);
|
|
@@ -6083,7 +6176,8 @@ var init_cursor = __esm({
|
|
|
6083
6176
|
const apiKey = resolveCursorApiKey() || void 0;
|
|
6084
6177
|
const injected = await buildInjectedMcpServers({
|
|
6085
6178
|
includeSideboard: true,
|
|
6086
|
-
includeBrightsy: isBrightsyConnected()
|
|
6179
|
+
includeBrightsy: isBrightsyConnected(),
|
|
6180
|
+
orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
|
|
6087
6181
|
});
|
|
6088
6182
|
const mcpServers = toCursorMcpServers(injected);
|
|
6089
6183
|
const req = {
|
|
@@ -6252,7 +6346,8 @@ var init_opencode = __esm({
|
|
|
6252
6346
|
}
|
|
6253
6347
|
const injected = await buildInjectedMcpServers({
|
|
6254
6348
|
includeSideboard: true,
|
|
6255
|
-
includeBrightsy: isBrightsyConnected()
|
|
6349
|
+
includeBrightsy: isBrightsyConnected(),
|
|
6350
|
+
orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
|
|
6256
6351
|
});
|
|
6257
6352
|
const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
|
|
6258
6353
|
return {
|
|
@@ -7886,7 +7981,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
7886
7981
|
const { isGlobalThread: isGlobalThread2 } = await Promise.resolve().then(() => (init_global_workspace(), global_workspace_exports));
|
|
7887
7982
|
if (isGlobalThread2(thread)) {
|
|
7888
7983
|
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
7889
|
-
ensureGlobalCoordinatorCwd2(
|
|
7984
|
+
ensureGlobalCoordinatorCwd2(
|
|
7985
|
+
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
7986
|
+
);
|
|
7890
7987
|
}
|
|
7891
7988
|
if (isOrchestratorThread(thread)) {
|
|
7892
7989
|
assertOrchestratorCapableAgent(thread.agent);
|
|
@@ -8180,9 +8277,21 @@ async function detectAgents() {
|
|
|
8180
8277
|
ensureAgentPath();
|
|
8181
8278
|
return Promise.all(allAdapters().map((a) => a.detect()));
|
|
8182
8279
|
}
|
|
8280
|
+
var REQUIRE_AGENT_TIMEOUT_MS = 8e3;
|
|
8183
8281
|
async function requireAgent(agent, opts) {
|
|
8184
|
-
|
|
8185
|
-
|
|
8282
|
+
ensureAgentPath();
|
|
8283
|
+
const status = await Promise.race([
|
|
8284
|
+
getAdapter(agent).detect(),
|
|
8285
|
+
new Promise((_, reject) => {
|
|
8286
|
+
setTimeout(() => {
|
|
8287
|
+
reject(
|
|
8288
|
+
new Error(
|
|
8289
|
+
`${agent} detect timed out after ${REQUIRE_AGENT_TIMEOUT_MS / 1e3}s`
|
|
8290
|
+
)
|
|
8291
|
+
);
|
|
8292
|
+
}, REQUIRE_AGENT_TIMEOUT_MS);
|
|
8293
|
+
})
|
|
8294
|
+
]);
|
|
8186
8295
|
if (!status.installed || !status.authenticated) {
|
|
8187
8296
|
throw new Error(status.reason ?? `${agent} is not available`);
|
|
8188
8297
|
}
|
|
@@ -11290,7 +11399,7 @@ var REPO_REVIEW_NAME = "review.md";
|
|
|
11290
11399
|
var REVIEW_REQUEST_PATH = `${ATTACHMENTS_DIR}/Review request.md`;
|
|
11291
11400
|
var LEGACY_REVIEW_REQUEST_PATH = `${LEGACY_ATTACHMENTS_DIR}/Review request.md`;
|
|
11292
11401
|
var REVIEW_REQUEST_NAME = "Review request.md";
|
|
11293
|
-
var REVIEW_REQUEST_PREFILL = "Review.";
|
|
11402
|
+
var REVIEW_REQUEST_PREFILL = "Review changes in this workspace.";
|
|
11294
11403
|
var LEGACY_REVIEW_TEMPLATE_MARKERS = [
|
|
11295
11404
|
"You are acting as a reviewer for a proposed code change made by another engineer.",
|
|
11296
11405
|
"HOW MANY FINDINGS TO RETURN:"
|
|
@@ -12121,7 +12230,9 @@ var Orchestrator = class {
|
|
|
12121
12230
|
}
|
|
12122
12231
|
let coordinatorDirective = null;
|
|
12123
12232
|
if (isOrchestration) {
|
|
12124
|
-
if (isGlobalThread(fresh))
|
|
12233
|
+
if (isGlobalThread(fresh)) {
|
|
12234
|
+
ensureGlobalCoordinatorCwd({ orchestratorThreadId: fresh.id });
|
|
12235
|
+
}
|
|
12125
12236
|
if (!fresh.sessionId) {
|
|
12126
12237
|
const inventory = await enrichWorkspacesWithGithub(this.listWorkspaces());
|
|
12127
12238
|
coordinatorDirective = coordinatorSystemPrompt({
|
|
@@ -13250,6 +13361,24 @@ function mcpArchiveBlockedReason(thread) {
|
|
|
13250
13361
|
|
|
13251
13362
|
// src/mcp/server.ts
|
|
13252
13363
|
var MAX_ORCH_THREADS = 5;
|
|
13364
|
+
var CREATE_THREAD_TIMEOUT_MS = 9e4;
|
|
13365
|
+
function withTimeout(promise, ms, label) {
|
|
13366
|
+
return new Promise((resolve, reject) => {
|
|
13367
|
+
const timer = setTimeout(() => {
|
|
13368
|
+
reject(new Error(`${label} timed out after ${Math.round(ms / 1e3)}s`));
|
|
13369
|
+
}, ms);
|
|
13370
|
+
promise.then(
|
|
13371
|
+
(value) => {
|
|
13372
|
+
clearTimeout(timer);
|
|
13373
|
+
resolve(value);
|
|
13374
|
+
},
|
|
13375
|
+
(err) => {
|
|
13376
|
+
clearTimeout(timer);
|
|
13377
|
+
reject(err);
|
|
13378
|
+
}
|
|
13379
|
+
);
|
|
13380
|
+
});
|
|
13381
|
+
}
|
|
13253
13382
|
async function startMcpServer() {
|
|
13254
13383
|
const orch = getOrchestrator();
|
|
13255
13384
|
try {
|
|
@@ -13257,7 +13386,14 @@ async function startMcpServer() {
|
|
|
13257
13386
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
13258
13387
|
} catch {
|
|
13259
13388
|
}
|
|
13260
|
-
|
|
13389
|
+
try {
|
|
13390
|
+
await orch.reconcile(void 0, { reclaimStaleTurns: false, drainQueues: false });
|
|
13391
|
+
} catch (err) {
|
|
13392
|
+
console.error(
|
|
13393
|
+
"[sideboard-mcp] reconcile on boot failed (continuing):",
|
|
13394
|
+
err instanceof Error ? err.message : err
|
|
13395
|
+
);
|
|
13396
|
+
}
|
|
13261
13397
|
const server = new import_mcp.McpServer({
|
|
13262
13398
|
name: "sideboard",
|
|
13263
13399
|
version: "0.1.0"
|
|
@@ -13462,7 +13598,7 @@ async function startMcpServer() {
|
|
|
13462
13598
|
const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
|
|
13463
13599
|
server.tool(
|
|
13464
13600
|
"create_thread",
|
|
13465
|
-
`Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces
|
|
13601
|
+
`Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces. From an orchestration chat, omit parentThreadId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Then use send_to_thread to chat.`,
|
|
13466
13602
|
{
|
|
13467
13603
|
sourceType: import_zod.z.enum(["branch", "pr", "ticket"]),
|
|
13468
13604
|
sourceRef: import_zod.z.string(),
|
|
@@ -13472,11 +13608,31 @@ async function startMcpServer() {
|
|
|
13472
13608
|
),
|
|
13473
13609
|
repoPath: import_zod.z.string(),
|
|
13474
13610
|
title: import_zod.z.string().optional(),
|
|
13475
|
-
parentThreadId: import_zod.z.string().optional()
|
|
13611
|
+
parentThreadId: import_zod.z.string().optional().describe(
|
|
13612
|
+
"Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
|
|
13613
|
+
)
|
|
13476
13614
|
},
|
|
13477
13615
|
async (args) => {
|
|
13478
|
-
|
|
13479
|
-
|
|
13616
|
+
const envParentId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || "";
|
|
13617
|
+
let parentId = args.parentThreadId?.trim() || "";
|
|
13618
|
+
let parent = parentId ? orch.getThread(parentId) : null;
|
|
13619
|
+
let parentCorrectedFrom;
|
|
13620
|
+
if (envParentId) {
|
|
13621
|
+
const envParent = orch.getThread(envParentId);
|
|
13622
|
+
if (envParent) {
|
|
13623
|
+
if (parentId && parentId !== envParentId) parentCorrectedFrom = parentId;
|
|
13624
|
+
else if (!parentId) parentCorrectedFrom = void 0;
|
|
13625
|
+
parentId = envParentId;
|
|
13626
|
+
parent = envParent;
|
|
13627
|
+
}
|
|
13628
|
+
}
|
|
13629
|
+
if (parentId && !parent) {
|
|
13630
|
+
parentCorrectedFrom = parentId;
|
|
13631
|
+
parentId = "";
|
|
13632
|
+
parent = null;
|
|
13633
|
+
}
|
|
13634
|
+
if (parentId) {
|
|
13635
|
+
const children = orch.getThreads(true).filter((t) => t.parentThreadId === parentId);
|
|
13480
13636
|
if (children.length >= MAX_ORCH_THREADS) {
|
|
13481
13637
|
return {
|
|
13482
13638
|
content: [
|
|
@@ -13489,38 +13645,70 @@ async function startMcpServer() {
|
|
|
13489
13645
|
};
|
|
13490
13646
|
}
|
|
13491
13647
|
}
|
|
13648
|
+
let agentArg = args.agent;
|
|
13649
|
+
let agentCoercedFrom;
|
|
13650
|
+
const resolvedProbe = resolveNewThreadOptions2({ agent: agentArg }).agent;
|
|
13651
|
+
if (resolvedProbe === "codex") {
|
|
13652
|
+
agentCoercedFrom = agentArg ?? "codex";
|
|
13653
|
+
const accountAgent = resolveNewThreadOptions2({}).agent;
|
|
13654
|
+
agentArg = accountAgent !== "codex" ? accountAgent : "cursor";
|
|
13655
|
+
}
|
|
13492
13656
|
const opts = resolveNewThreadOptions2({
|
|
13493
|
-
agent:
|
|
13657
|
+
agent: agentArg,
|
|
13494
13658
|
model: args.model
|
|
13495
13659
|
});
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
|
|
13512
|
-
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13660
|
+
try {
|
|
13661
|
+
const thread = await withTimeout(
|
|
13662
|
+
orch.createThread({
|
|
13663
|
+
sourceType: args.sourceType,
|
|
13664
|
+
sourceRef: args.sourceRef,
|
|
13665
|
+
agent: opts.agent,
|
|
13666
|
+
model: opts.model,
|
|
13667
|
+
effort: opts.effort,
|
|
13668
|
+
fast: opts.fast,
|
|
13669
|
+
repoPath: args.repoPath,
|
|
13670
|
+
title: args.title,
|
|
13671
|
+
parentThreadId: parentId || null
|
|
13672
|
+
}),
|
|
13673
|
+
CREATE_THREAD_TIMEOUT_MS,
|
|
13674
|
+
"create_thread"
|
|
13675
|
+
);
|
|
13676
|
+
const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
|
|
13677
|
+
return {
|
|
13678
|
+
content: [
|
|
13679
|
+
{
|
|
13680
|
+
type: "text",
|
|
13681
|
+
text: JSON.stringify({
|
|
13682
|
+
id: thread.id,
|
|
13683
|
+
title: thread.title,
|
|
13684
|
+
branchName: thread.branchName,
|
|
13685
|
+
worktreePath: thread.worktreePath,
|
|
13686
|
+
agent: thread.agent,
|
|
13687
|
+
model: thread.model,
|
|
13688
|
+
status: thread.status,
|
|
13689
|
+
link: `sideboard://thread/${thread.id}`,
|
|
13690
|
+
parentThreadId: thread.parentThreadId,
|
|
13691
|
+
...agentCoercedFrom ? {
|
|
13692
|
+
agentCoercedFrom,
|
|
13693
|
+
note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
|
|
13694
|
+
} : {},
|
|
13695
|
+
...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
|
|
13696
|
+
})
|
|
13697
|
+
}
|
|
13698
|
+
]
|
|
13699
|
+
};
|
|
13700
|
+
} catch (err) {
|
|
13701
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13702
|
+
return {
|
|
13703
|
+
content: [
|
|
13704
|
+
{
|
|
13705
|
+
type: "text",
|
|
13706
|
+
text: `create_thread failed: ${message}`
|
|
13707
|
+
}
|
|
13708
|
+
],
|
|
13709
|
+
isError: true
|
|
13710
|
+
};
|
|
13711
|
+
}
|
|
13524
13712
|
}
|
|
13525
13713
|
);
|
|
13526
13714
|
server.tool(
|
|
@@ -13701,7 +13889,7 @@ async function startMcpServer() {
|
|
|
13701
13889
|
);
|
|
13702
13890
|
server.tool(
|
|
13703
13891
|
"request_review",
|
|
13704
|
-
'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
|
|
13892
|
+
'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
|
|
13705
13893
|
{ ref: import_zod.z.string().describe("Worktree thread id/ref to review") },
|
|
13706
13894
|
async ({ ref }) => {
|
|
13707
13895
|
try {
|