@sideboard-ai/core 0.1.61 → 0.1.66
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-B2723EOF.js → agents-EWFD765A.js} +23 -7
- package/dist/{agents-EADRAAPG.js → agents-MD7SCFYX.js} +23 -7
- package/dist/{app-settings-YBNZ4XSR.js → app-settings-GJVZGU3M.js} +15 -3
- package/dist/{app-settings-TBHTJWLQ.js → app-settings-ONKMFSEJ.js} +15 -3
- package/dist/{chunk-RIWUU7FO.js → chunk-5AG5BUQN.js} +61 -3
- package/dist/{chunk-HLEX5AQ6.js → chunk-7FD7COKE.js} +4 -0
- package/dist/{chunk-XWPKLRB3.js → chunk-AKPEXIKK.js} +2 -2
- package/dist/{chunk-MX7UH5AT.js → chunk-BBEH2CJE.js} +264 -93
- package/dist/{chunk-FGNBTFRD.js → chunk-BPOTVI5J.js} +125 -3
- package/dist/{chunk-CHGOMFTA.js → chunk-DNPP7QMK.js} +32 -7
- package/dist/{chunk-MBAL5FE6.js → chunk-DZYMNW2A.js} +4 -4
- package/dist/{chunk-JB2H7E7V.js → chunk-EVD4KNKR.js} +1 -1
- package/dist/{chunk-TSRXOSVD.js → chunk-FWJYLBO6.js} +4 -0
- package/dist/{chunk-QJBC4BRK.js → chunk-HTOTTJJX.js} +2 -2
- package/dist/{chunk-MFGGIRUA.js → chunk-I2KGRAXC.js} +2 -2
- package/dist/{chunk-ZXDOI6IH.js → chunk-IFAU2DEY.js} +269 -93
- package/dist/{chunk-NTYRBRE7.js → chunk-LRBRQFBU.js} +2 -2
- package/dist/{chunk-75QR74KM.js → chunk-MHR4OGZ4.js} +125 -3
- package/dist/{chunk-2P2UK7E7.js → chunk-PESJDZTB.js} +2 -2
- package/dist/{chunk-P7EQUFB6.js → chunk-R7GUDEPY.js} +2 -2
- package/dist/{chunk-73AT5K4A.js → chunk-TXQ6K2GR.js} +61 -3
- package/dist/{chunk-MLAST5BB.js → chunk-YTNLOJPK.js} +32 -7
- package/dist/{connected-teams-RSL4VB3X.js → connected-teams-CHXO5FFA.js} +2 -2
- package/dist/{connected-teams-MKIYKOYA.js → connected-teams-GJTESSTX.js} +2 -2
- package/dist/{coordinator-prompt-4P23VVFC.js → coordinator-prompt-E5UGSJES.js} +5 -5
- package/dist/{coordinator-prompt-LNWHZ64D.js → coordinator-prompt-ILSULI7C.js} +5 -5
- package/dist/{global-workspace-TMMAVRVW.js → global-workspace-44UG64NA.js} +6 -7
- package/dist/{global-workspace-BHT4XUAA.js → global-workspace-5PM5LA6E.js} +6 -7
- package/dist/index.cjs +1433 -944
- package/dist/index.d.cts +117 -2
- package/dist/index.d.ts +117 -2
- package/dist/index.js +859 -736
- package/dist/mcp/run-stdio.cjs +1388 -993
- package/dist/mcp/run-stdio.js +798 -765
- package/dist/{run-HZTBWGQR.js → run-74S2NZWB.js} +1 -1
- package/dist/{run-GPSVV5OH.js → run-JLN5JK7Q.js} +1 -1
- package/dist/{thread-store-GHOADGL2.js → thread-store-BUBR24YA.js} +1 -1
- package/dist/{thread-store-UJIGMI5J.js → thread-store-XTPFCJAI.js} +1 -1
- package/dist/{workspaces-3GO3EDQG.js → workspaces-OVBCSS5Y.js} +7 -8
- package/dist/{workspaces-GFPGDGCS.js → workspaces-RXFXQRRF.js} +7 -8
- package/dist/{worktree-GBLHEFHR.js → worktree-K2JB53R5.js} +3 -3
- package/dist/{worktree-3L2G6PCM.js → worktree-S2N63FLV.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-GI7E5733.js +0 -30
- package/dist/chunk-S2LL5HA4.js +0 -33
package/dist/index.js
CHANGED
|
@@ -4,33 +4,14 @@ import {
|
|
|
4
4
|
listWorkspaces,
|
|
5
5
|
removeWorkspace,
|
|
6
6
|
syncWorkspacesFromThreads
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import {
|
|
9
|
-
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
10
|
-
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
11
|
-
CLOUD_COORDINATOR_TIMEOUT_REPLY,
|
|
12
|
-
CLOUD_ORCHESTRATOR_GOAL,
|
|
13
|
-
GLOBAL_WORKSPACE_ID,
|
|
14
|
-
SIDEBOARD_FORCE_STOP,
|
|
15
|
-
createGlobalChat,
|
|
16
|
-
ensureCloudCoordinator,
|
|
17
|
-
healOrchestrationSoccerTitles,
|
|
18
|
-
isCloudCoordinatorThread,
|
|
19
|
-
isGlobalRepoPath,
|
|
20
|
-
isGlobalThread,
|
|
21
|
-
isOrchestratorThread,
|
|
22
|
-
listGlobalThreads,
|
|
23
|
-
orchestrationTitleNeedsSoccerNickname,
|
|
24
|
-
orchestratorSessionPoisonedByBuiltins,
|
|
25
|
-
parseForceStopMessage,
|
|
26
|
-
takenTeamSlugsForOrchestration
|
|
27
|
-
} from "./chunk-MLAST5BB.js";
|
|
7
|
+
} from "./chunk-PESJDZTB.js";
|
|
28
8
|
import {
|
|
29
9
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
30
10
|
CLAUDE_MODEL_CATALOG,
|
|
31
11
|
MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
|
|
32
12
|
PLAN_MODE_INSTRUCTION,
|
|
33
13
|
SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
14
|
+
SIDEBOARD_MCP_PROFILE_ENV,
|
|
34
15
|
allAdapters,
|
|
35
16
|
brightsyAdapter,
|
|
36
17
|
brightsyMcpAllowedTools,
|
|
@@ -41,6 +22,7 @@ import {
|
|
|
41
22
|
countCacheControlBlocks,
|
|
42
23
|
cursorAdapter,
|
|
43
24
|
decodeBrightsyTarget,
|
|
25
|
+
dropCachedPrefixOnResume,
|
|
44
26
|
encodeBrightsyTarget,
|
|
45
27
|
findInvalidCacheControlTtlOrder,
|
|
46
28
|
flattenTurnInput,
|
|
@@ -66,17 +48,41 @@ import {
|
|
|
66
48
|
parseMcpList,
|
|
67
49
|
parseSessionQuotaResetAt,
|
|
68
50
|
permissionMode,
|
|
51
|
+
prepareTerminalCommand,
|
|
52
|
+
promptMentionsBrightsy,
|
|
69
53
|
resolveCursorModelId,
|
|
54
|
+
resolveLoginCommand,
|
|
70
55
|
resolveQuotaFallbackAgent,
|
|
71
56
|
sanitizeMcpServerName,
|
|
57
|
+
shouldInjectBrightsyMcp,
|
|
58
|
+
sideboardMcpProfile,
|
|
59
|
+
threadRequestsBrightsyMcp,
|
|
72
60
|
writeInjectedMcpConfig
|
|
73
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-IFAU2DEY.js";
|
|
74
62
|
import {
|
|
63
|
+
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
64
|
+
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
65
|
+
CLOUD_COORDINATOR_TIMEOUT_REPLY,
|
|
66
|
+
CLOUD_ORCHESTRATOR_GOAL,
|
|
67
|
+
GLOBAL_WORKSPACE_ID,
|
|
75
68
|
ORCHESTRATOR_AGENT_KINDS,
|
|
69
|
+
SIDEBOARD_FORCE_STOP,
|
|
76
70
|
assertOrchestratorCapableAgent,
|
|
77
71
|
coerceOrchestratorAgent,
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
createGlobalChat,
|
|
73
|
+
ensureCloudCoordinator,
|
|
74
|
+
healOrchestrationSoccerTitles,
|
|
75
|
+
isCloudCoordinatorThread,
|
|
76
|
+
isGlobalRepoPath,
|
|
77
|
+
isGlobalThread,
|
|
78
|
+
isOrchestratorCapableAgent,
|
|
79
|
+
isOrchestratorThread,
|
|
80
|
+
listGlobalThreads,
|
|
81
|
+
orchestrationTitleNeedsSoccerNickname,
|
|
82
|
+
orchestratorSessionPoisonedByBuiltins,
|
|
83
|
+
parseForceStopMessage,
|
|
84
|
+
takenTeamSlugsForOrchestration
|
|
85
|
+
} from "./chunk-YTNLOJPK.js";
|
|
80
86
|
import {
|
|
81
87
|
brightsyConfigPath,
|
|
82
88
|
brightsyMcpServerName,
|
|
@@ -88,7 +94,7 @@ import {
|
|
|
88
94
|
loadBrightsyConfig,
|
|
89
95
|
saveBrightsyConfig,
|
|
90
96
|
switchBrightsyAccount
|
|
91
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-DZYMNW2A.js";
|
|
92
98
|
import {
|
|
93
99
|
LEGACY_PLAN_FILE_REL,
|
|
94
100
|
PLAN_FILE_NAME,
|
|
@@ -118,16 +124,18 @@ import {
|
|
|
118
124
|
enrichWorkspacesWithGithub,
|
|
119
125
|
ensureGlobalCoordinatorCwd,
|
|
120
126
|
formatWorkspaceInventory
|
|
121
|
-
} from "./chunk-
|
|
127
|
+
} from "./chunk-AKPEXIKK.js";
|
|
122
128
|
import {
|
|
123
129
|
HARNESS_ENV_KEYS,
|
|
124
130
|
appSettingsPath,
|
|
125
131
|
applyAppEnvironment,
|
|
132
|
+
autoArchiveOnMergeEnabled,
|
|
126
133
|
autoCleanupOrphansEnabled,
|
|
127
134
|
autoRenameBranchEnabled,
|
|
128
135
|
autoRunAfterSetupEnabled,
|
|
129
136
|
brightsyCloudConnectAgent,
|
|
130
137
|
brightsyCloudConnectEnabled,
|
|
138
|
+
brightsyInjectWorktreeMcpEnabled,
|
|
131
139
|
caffeinateWhileCloudConnectEnabled,
|
|
132
140
|
caffeinateWhileRunningEnabled,
|
|
133
141
|
childEnvWithAppSettings,
|
|
@@ -146,18 +154,22 @@ import {
|
|
|
146
154
|
maxConcurrentAgents,
|
|
147
155
|
orchestrationQuotaFallbackAgent,
|
|
148
156
|
orchestrationQuotaOnLimit,
|
|
157
|
+
resolveAgentExecutable,
|
|
149
158
|
resolveClaudeExecutable,
|
|
150
159
|
resolveEffectiveIssueSource,
|
|
151
160
|
resolveNewThreadOptions,
|
|
152
161
|
resolveThreadDefaults,
|
|
153
162
|
saveAppSettings,
|
|
154
163
|
updateAdvancedSettings,
|
|
164
|
+
updateAgentExecutable,
|
|
155
165
|
updateAppEnvironment,
|
|
156
166
|
updateBrightsySettings,
|
|
157
167
|
updateClaudeSettings,
|
|
168
|
+
updateCodexSettings,
|
|
158
169
|
updateDefaultsSettings,
|
|
159
|
-
updateIntegrationsSettings
|
|
160
|
-
|
|
170
|
+
updateIntegrationsSettings,
|
|
171
|
+
updateOpencodeSettings
|
|
172
|
+
} from "./chunk-MHR4OGZ4.js";
|
|
161
173
|
import {
|
|
162
174
|
FAMOUS_SOCCER_TEAMS,
|
|
163
175
|
addPrStackLayer,
|
|
@@ -220,7 +232,7 @@ import {
|
|
|
220
232
|
worktreeDisplayLabel,
|
|
221
233
|
worktreeDisplayLabelForGroup,
|
|
222
234
|
worktreeNameFromPath
|
|
223
|
-
} from "./chunk-
|
|
235
|
+
} from "./chunk-R7GUDEPY.js";
|
|
224
236
|
import {
|
|
225
237
|
ATTACHMENTS_DIR,
|
|
226
238
|
LEGACY_ATTACHMENTS_DIR,
|
|
@@ -240,7 +252,7 @@ import {
|
|
|
240
252
|
updateThread,
|
|
241
253
|
withThreadLock,
|
|
242
254
|
writeThread
|
|
243
|
-
} from "./chunk-
|
|
255
|
+
} from "./chunk-FWJYLBO6.js";
|
|
244
256
|
import {
|
|
245
257
|
THINKING_EFFORTS,
|
|
246
258
|
isThinkingEffort,
|
|
@@ -272,12 +284,16 @@ import {
|
|
|
272
284
|
worktreesRoot
|
|
273
285
|
} from "./chunk-M37RITA6.js";
|
|
274
286
|
import {
|
|
287
|
+
enrichPathWithNpmGlobalBin,
|
|
275
288
|
ensureAgentPath,
|
|
276
289
|
gh,
|
|
277
290
|
git,
|
|
291
|
+
posixShellSingleQuote,
|
|
292
|
+
resolveCommandBinarySync,
|
|
278
293
|
resolveGhAuthToken,
|
|
279
|
-
run
|
|
280
|
-
|
|
294
|
+
run,
|
|
295
|
+
withExportedPath
|
|
296
|
+
} from "./chunk-TXQ6K2GR.js";
|
|
281
297
|
|
|
282
298
|
// src/integrations/github.ts
|
|
283
299
|
async function getGitHubStatus() {
|
|
@@ -706,9 +722,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
706
722
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
707
723
|
);
|
|
708
724
|
}
|
|
709
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
725
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-44UG64NA.js");
|
|
710
726
|
if (isGlobalThread2(thread)) {
|
|
711
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
727
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-ILSULI7C.js");
|
|
712
728
|
ensureGlobalCoordinatorCwd2(
|
|
713
729
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
714
730
|
);
|
|
@@ -910,6 +926,9 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
910
926
|
);
|
|
911
927
|
return lines.join("\n");
|
|
912
928
|
}
|
|
929
|
+
function formatWorktreeReminder() {
|
|
930
|
+
return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout.";
|
|
931
|
+
}
|
|
913
932
|
function formatArtifactDirective() {
|
|
914
933
|
return [
|
|
915
934
|
"Sideboard side column (desktop UI):",
|
|
@@ -995,11 +1014,13 @@ ${prompt}`;
|
|
|
995
1014
|
// src/detect/detect.ts
|
|
996
1015
|
async function detectAgents() {
|
|
997
1016
|
ensureAgentPath();
|
|
1017
|
+
enrichPathWithNpmGlobalBin();
|
|
998
1018
|
return Promise.all(allAdapters().map((a) => a.detect()));
|
|
999
1019
|
}
|
|
1000
1020
|
var REQUIRE_AGENT_TIMEOUT_MS = 8e3;
|
|
1001
1021
|
async function requireAgent(agent, opts) {
|
|
1002
1022
|
ensureAgentPath();
|
|
1023
|
+
enrichPathWithNpmGlobalBin();
|
|
1003
1024
|
const status = await Promise.race([
|
|
1004
1025
|
getAdapter(agent).detect(),
|
|
1005
1026
|
new Promise((_, reject) => {
|
|
@@ -2841,7 +2862,7 @@ async function previewLand(thread) {
|
|
|
2841
2862
|
const target = await resolveDefaultBranch(thread.repoPath);
|
|
2842
2863
|
if (thread.branchName === target || thread.branchName === "main" || thread.branchName === "master") {
|
|
2843
2864
|
}
|
|
2844
|
-
const { stdout: head } = await import("./run-
|
|
2865
|
+
const { stdout: head } = await import("./run-JLN5JK7Q.js").then(
|
|
2845
2866
|
({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], thread.worktreePath)
|
|
2846
2867
|
);
|
|
2847
2868
|
const current = head.trim();
|
|
@@ -2880,7 +2901,7 @@ async function confirmLand(thread, opts) {
|
|
|
2880
2901
|
if (preview.dirty) {
|
|
2881
2902
|
committed = await commitAll(thread.worktreePath, meta.commitMessage);
|
|
2882
2903
|
}
|
|
2883
|
-
const { git: git2 } = await import("./run-
|
|
2904
|
+
const { git: git2 } = await import("./run-JLN5JK7Q.js");
|
|
2884
2905
|
const { stdout: headOut } = await git2(
|
|
2885
2906
|
["rev-parse", "--abbrev-ref", "HEAD"],
|
|
2886
2907
|
thread.worktreePath,
|
|
@@ -2978,7 +2999,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2978
2999
|
return readThread(thread.id) ?? thread;
|
|
2979
3000
|
}
|
|
2980
3001
|
async function listLinearIssues(agent, repoPath) {
|
|
2981
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3002
|
+
const { getAdapter: getAdapter2 } = await import("./agents-EWFD765A.js");
|
|
2982
3003
|
await requireAgent(agent, { requireLinear: true });
|
|
2983
3004
|
const adapter = getAdapter2(agent);
|
|
2984
3005
|
if (!adapter.listLinearIssues) {
|
|
@@ -3022,6 +3043,8 @@ function worktreeBindingFrom(from) {
|
|
|
3022
3043
|
parentThreadId: from.parentThreadId,
|
|
3023
3044
|
prUrl: from.prUrl,
|
|
3024
3045
|
prTitle: from.prTitle,
|
|
3046
|
+
prState: from.prState,
|
|
3047
|
+
skipAutoArchiveOnMerge: from.skipAutoArchiveOnMerge,
|
|
3025
3048
|
stackId: from.stackId,
|
|
3026
3049
|
stackLayer: from.stackLayer
|
|
3027
3050
|
};
|
|
@@ -3504,7 +3527,7 @@ async function adoptThread(input) {
|
|
|
3504
3527
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
3505
3528
|
}
|
|
3506
3529
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
3507
|
-
const { stdout: branch } = await import("./run-
|
|
3530
|
+
const { stdout: branch } = await import("./run-JLN5JK7Q.js").then(
|
|
3508
3531
|
({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], input.worktreePath)
|
|
3509
3532
|
);
|
|
3510
3533
|
const thread = createEmptyThread({
|
|
@@ -3519,7 +3542,7 @@ async function adoptThread(input) {
|
|
|
3519
3542
|
messages: input.messages ?? []
|
|
3520
3543
|
});
|
|
3521
3544
|
writeThread(thread);
|
|
3522
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
3545
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OVBCSS5Y.js");
|
|
3523
3546
|
await ensureWorkspace2(repoPath);
|
|
3524
3547
|
return thread;
|
|
3525
3548
|
}
|
|
@@ -3721,6 +3744,20 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
3721
3744
|
import { EventEmitter } from "events";
|
|
3722
3745
|
import { existsSync as existsSync13 } from "fs";
|
|
3723
3746
|
|
|
3747
|
+
// src/git/pr-merge-archive.ts
|
|
3748
|
+
function normalizePrState(state) {
|
|
3749
|
+
return (state ?? "").trim().toUpperCase();
|
|
3750
|
+
}
|
|
3751
|
+
function shouldAutoArchiveOnPrMerge(opts) {
|
|
3752
|
+
if (!opts.autoArchiveEnabled) return false;
|
|
3753
|
+
if (opts.isGlobal) return false;
|
|
3754
|
+
if (opts.skipAutoArchiveOnMerge) return false;
|
|
3755
|
+
if (opts.threadStatus === "archived") return false;
|
|
3756
|
+
const next = normalizePrState(opts.nextPrState);
|
|
3757
|
+
if (next !== "MERGED") return false;
|
|
3758
|
+
return normalizePrState(opts.previousPrState) !== "MERGED";
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3724
3761
|
// src/git/orphan-cleanup.ts
|
|
3725
3762
|
import { existsSync as existsSync10, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
|
|
3726
3763
|
import { join as join8 } from "path";
|
|
@@ -4456,7 +4493,7 @@ var Orchestrator = class {
|
|
|
4456
4493
|
orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
|
|
4457
4494
|
});
|
|
4458
4495
|
}
|
|
4459
|
-
const { autoCleanupOrphansEnabled: autoCleanupOrphansEnabled2 } = await import("./app-settings-
|
|
4496
|
+
const { autoCleanupOrphansEnabled: autoCleanupOrphansEnabled2 } = await import("./app-settings-ONKMFSEJ.js");
|
|
4460
4497
|
if (autoCleanupOrphansEnabled2() && shouldRunWorktreeCleanup() && orphans.length > 0) {
|
|
4461
4498
|
await cleanupOrphanWorktrees({ repoPaths });
|
|
4462
4499
|
}
|
|
@@ -4613,7 +4650,7 @@ var Orchestrator = class {
|
|
|
4613
4650
|
}
|
|
4614
4651
|
async finishCreateThread(threadId, prompt) {
|
|
4615
4652
|
await this.runSetupAfterCreate(threadId);
|
|
4616
|
-
const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await import("./app-settings-
|
|
4653
|
+
const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await import("./app-settings-ONKMFSEJ.js");
|
|
4617
4654
|
if (autoRunAfterSetupEnabled2()) {
|
|
4618
4655
|
try {
|
|
4619
4656
|
await this.startDev(threadId);
|
|
@@ -4854,13 +4891,14 @@ var Orchestrator = class {
|
|
|
4854
4891
|
"Files column: MCP present_files (brightsy account storage or memory).",
|
|
4855
4892
|
"Do not say artifacts/CMS UI are unavailable."
|
|
4856
4893
|
].join(" ") : null;
|
|
4894
|
+
const worktreeReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatWorktreeReminder() : null;
|
|
4857
4895
|
const agentPrompt = [
|
|
4858
4896
|
thread.planMode ? PLAN_MODE_INSTRUCTION : null,
|
|
4859
4897
|
orchestrationReminder,
|
|
4898
|
+
worktreeReminder,
|
|
4860
4899
|
artifactReminder,
|
|
4861
4900
|
expandedPrompt
|
|
4862
4901
|
].filter(Boolean).join("\n\n");
|
|
4863
|
-
const instructionFiles = loadAgentInstructions(thread.worktreePath, thread.agent);
|
|
4864
4902
|
if (thread.attachments.length > 0) {
|
|
4865
4903
|
updateThread(threadId, { attachments: [] });
|
|
4866
4904
|
}
|
|
@@ -4884,11 +4922,10 @@ var Orchestrator = class {
|
|
|
4884
4922
|
});
|
|
4885
4923
|
const artifactDirective = isBrightsy ? null : formatArtifactDirective();
|
|
4886
4924
|
const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
|
|
4887
|
-
const { autoRenameBranchEnabled: autoRenameBranchEnabled2 } = await import("./app-settings-
|
|
4925
|
+
const { autoRenameBranchEnabled: autoRenameBranchEnabled2 } = await import("./app-settings-ONKMFSEJ.js");
|
|
4888
4926
|
const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled2() ? formatRenameBranchDirective(fresh, {
|
|
4889
4927
|
customPrompt: settings?.prompts?.renameBranch
|
|
4890
4928
|
}) : null;
|
|
4891
|
-
const instructions = fresh.agent === "claude" || isBrightsy ? null : formatAgentInstructions(instructionFiles);
|
|
4892
4929
|
let seed = null;
|
|
4893
4930
|
if (!fresh.sessionId) {
|
|
4894
4931
|
const prior = fresh.messages.slice(0, -1);
|
|
@@ -4909,12 +4946,12 @@ var Orchestrator = class {
|
|
|
4909
4946
|
});
|
|
4910
4947
|
}
|
|
4911
4948
|
}
|
|
4912
|
-
const cachedPrefix = [
|
|
4949
|
+
const cachedPrefix = fresh.sessionId ? "" : [
|
|
4913
4950
|
coordinatorDirective,
|
|
4914
4951
|
worktreeDirective,
|
|
4915
4952
|
artifactDirective,
|
|
4916
4953
|
renameBranchDirective,
|
|
4917
|
-
|
|
4954
|
+
seed
|
|
4918
4955
|
].filter(Boolean).join("\n\n---\n\n");
|
|
4919
4956
|
try {
|
|
4920
4957
|
const stderrTail = [];
|
|
@@ -5001,15 +5038,11 @@ var Orchestrator = class {
|
|
|
5001
5038
|
const retryThread = this.requireThread(threadId);
|
|
5002
5039
|
const prior = retryThread.messages.slice(0, -1);
|
|
5003
5040
|
const retrySeed = buildSessionSeed(prior);
|
|
5004
|
-
const retryInstructions = retryThread.agent === "claude" ? null : formatAgentInstructions(
|
|
5005
|
-
loadAgentInstructions(retryThread.worktreePath, retryThread.agent)
|
|
5006
|
-
);
|
|
5007
5041
|
const retryPrefix = [
|
|
5008
5042
|
coordinatorDirective,
|
|
5009
5043
|
worktreeDirective,
|
|
5010
5044
|
artifactDirective,
|
|
5011
5045
|
renameBranchDirective,
|
|
5012
|
-
retryInstructions,
|
|
5013
5046
|
retrySeed
|
|
5014
5047
|
].filter(Boolean).join("\n\n---\n\n");
|
|
5015
5048
|
const retryHandle = await spawnAgentTurn(
|
|
@@ -5520,10 +5553,19 @@ var Orchestrator = class {
|
|
|
5520
5553
|
this.assertNotGlobal(thread, "Merge PR");
|
|
5521
5554
|
if (!selector) throw new Error("No pull request linked to this thread");
|
|
5522
5555
|
const result = await mergePr(cwd, selector);
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5556
|
+
const state = normalizePrState(result.state) || "MERGED";
|
|
5557
|
+
const metaLike = {
|
|
5558
|
+
number: 0,
|
|
5559
|
+
title: thread.prTitle ?? thread.title,
|
|
5560
|
+
url: result.url || thread.prUrl || "",
|
|
5561
|
+
state,
|
|
5562
|
+
isDraft: false,
|
|
5563
|
+
reviewDecision: null,
|
|
5564
|
+
baseRefName: "",
|
|
5565
|
+
headRefName: ""
|
|
5566
|
+
};
|
|
5567
|
+
await this.persistPrMetaAndMaybeArchive(thread, metaLike);
|
|
5568
|
+
return { url: metaLike.url, state };
|
|
5527
5569
|
}
|
|
5528
5570
|
/** Resolve PR selector and optionally persist `prUrl` when found. */
|
|
5529
5571
|
async withPrSelector(threadRef) {
|
|
@@ -5545,19 +5587,55 @@ var Orchestrator = class {
|
|
|
5545
5587
|
if (!selector) return null;
|
|
5546
5588
|
const meta = await getPrMeta(cwd, selector);
|
|
5547
5589
|
if (meta) {
|
|
5548
|
-
|
|
5549
|
-
if (meta.url && meta.url !== thread.prUrl) patch.prUrl = meta.url;
|
|
5550
|
-
if (meta.title && meta.title !== thread.prTitle) patch.prTitle = meta.title;
|
|
5551
|
-
if (Object.keys(patch).length > 0) {
|
|
5552
|
-
updateThread(thread.id, patch);
|
|
5553
|
-
const latest = this.requireThread(thread.id);
|
|
5554
|
-
if (!latest.userSetTitle && meta.title && latest.title !== meta.title) {
|
|
5555
|
-
updateThread(thread.id, { title: meta.title });
|
|
5556
|
-
}
|
|
5557
|
-
}
|
|
5590
|
+
await this.persistPrMetaAndMaybeArchive(thread, meta);
|
|
5558
5591
|
}
|
|
5559
5592
|
return meta;
|
|
5560
5593
|
}
|
|
5594
|
+
/**
|
|
5595
|
+
* Persist PR URL/title/state and Conductor-style auto-archive when the PR
|
|
5596
|
+
* first becomes MERGED.
|
|
5597
|
+
*/
|
|
5598
|
+
async persistPrMetaAndMaybeArchive(thread, meta) {
|
|
5599
|
+
const prevState = normalizePrState(thread.prState);
|
|
5600
|
+
const nextState = normalizePrState(meta.state);
|
|
5601
|
+
const patch = {};
|
|
5602
|
+
if (meta.url && meta.url !== thread.prUrl) patch.prUrl = meta.url;
|
|
5603
|
+
if (meta.title && meta.title !== thread.prTitle) patch.prTitle = meta.title;
|
|
5604
|
+
if (nextState && nextState !== prevState) patch.prState = nextState;
|
|
5605
|
+
if (thread.skipAutoArchiveOnMerge && nextState && nextState !== "MERGED" && nextState !== "CLOSED") {
|
|
5606
|
+
patch.skipAutoArchiveOnMerge = false;
|
|
5607
|
+
}
|
|
5608
|
+
if (Object.keys(patch).length > 0) {
|
|
5609
|
+
updateThread(thread.id, patch);
|
|
5610
|
+
const latest2 = this.requireThread(thread.id);
|
|
5611
|
+
if (!latest2.userSetTitle && meta.title && latest2.title !== meta.title) {
|
|
5612
|
+
updateThread(thread.id, { title: meta.title });
|
|
5613
|
+
}
|
|
5614
|
+
}
|
|
5615
|
+
const { autoArchiveOnMergeEnabled: autoArchiveOnMergeEnabled2 } = await import("./app-settings-ONKMFSEJ.js");
|
|
5616
|
+
const latest = this.requireThread(thread.id);
|
|
5617
|
+
if (!shouldAutoArchiveOnPrMerge({
|
|
5618
|
+
previousPrState: prevState || null,
|
|
5619
|
+
nextPrState: nextState,
|
|
5620
|
+
threadStatus: latest.status,
|
|
5621
|
+
skipAutoArchiveOnMerge: latest.skipAutoArchiveOnMerge,
|
|
5622
|
+
autoArchiveEnabled: autoArchiveOnMergeEnabled2(),
|
|
5623
|
+
isGlobal: isGlobalThread(latest)
|
|
5624
|
+
})) {
|
|
5625
|
+
return;
|
|
5626
|
+
}
|
|
5627
|
+
const siblings = threadsSharingWorktree(latest.worktreePath);
|
|
5628
|
+
for (const t of siblings) {
|
|
5629
|
+
const sibPatch = { prState: "MERGED" };
|
|
5630
|
+
if (meta.url && meta.url !== t.prUrl) sibPatch.prUrl = meta.url;
|
|
5631
|
+
if (meta.title && meta.title !== t.prTitle) sibPatch.prTitle = meta.title;
|
|
5632
|
+
if (Object.keys(sibPatch).length > 0) updateThread(t.id, sibPatch);
|
|
5633
|
+
}
|
|
5634
|
+
for (const t of siblings) {
|
|
5635
|
+
if (this.requireThread(t.id).status === "archived") continue;
|
|
5636
|
+
await this.archive(t.id);
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5561
5639
|
async getPrStack(threadRef) {
|
|
5562
5640
|
const thread = this.requireThread(threadRef);
|
|
5563
5641
|
if (!thread.worktreePath?.trim()) return null;
|
|
@@ -5735,7 +5813,9 @@ var Orchestrator = class {
|
|
|
5735
5813
|
const thread = this.requireThread(threadRef);
|
|
5736
5814
|
this.stop(thread.id);
|
|
5737
5815
|
if (isGlobalThread(thread)) {
|
|
5738
|
-
|
|
5816
|
+
const archived2 = setStatus(thread.id, "archived");
|
|
5817
|
+
this.emit({ type: "status_changed", threadId: archived2.id, status: "archived" });
|
|
5818
|
+
return archived2;
|
|
5739
5819
|
}
|
|
5740
5820
|
const siblings = threadsSharingWorktree(thread.worktreePath).filter((t) => t.id !== thread.id);
|
|
5741
5821
|
if (siblings.length === 0) {
|
|
@@ -5753,9 +5833,10 @@ var Orchestrator = class {
|
|
|
5753
5833
|
await removeWorktree(thread.repoPath, thread.worktreePath);
|
|
5754
5834
|
}
|
|
5755
5835
|
const archived = setStatus(thread.id, "archived");
|
|
5836
|
+
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
5756
5837
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
5757
5838
|
try {
|
|
5758
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
5839
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OVBCSS5Y.js");
|
|
5759
5840
|
await ensureWorkspace2(thread.repoPath);
|
|
5760
5841
|
} catch {
|
|
5761
5842
|
}
|
|
@@ -5776,7 +5857,7 @@ var Orchestrator = class {
|
|
|
5776
5857
|
await runArchiveScript(thread.repoPath, thread.worktreePath);
|
|
5777
5858
|
} catch {
|
|
5778
5859
|
}
|
|
5779
|
-
const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await import("./app-settings-
|
|
5860
|
+
const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await import("./app-settings-ONKMFSEJ.js");
|
|
5780
5861
|
const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled2();
|
|
5781
5862
|
await removeWorktree(thread.repoPath, thread.worktreePath, {
|
|
5782
5863
|
deleteBranch: deleteBranch ? thread.branchName : void 0
|
|
@@ -5792,10 +5873,12 @@ var Orchestrator = class {
|
|
|
5792
5873
|
if (isGlobalThread(thread)) {
|
|
5793
5874
|
const { globalAgentCwd: globalAgentCwd2 } = await import("./paths-VPH3ITBK.js");
|
|
5794
5875
|
updateThread(thread.id, { worktreePath: globalAgentCwd2() });
|
|
5795
|
-
|
|
5876
|
+
const restored2 = setStatus(thread.id, "idle");
|
|
5877
|
+
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
5878
|
+
return restored2;
|
|
5796
5879
|
}
|
|
5797
5880
|
if (!existsSync13(thread.worktreePath)) {
|
|
5798
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
5881
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-K2JB53R5.js");
|
|
5799
5882
|
const { execa: execa6 } = await import("execa");
|
|
5800
5883
|
const slug = thread.worktreePath.split("/").pop();
|
|
5801
5884
|
const dest = thread.worktreePath;
|
|
@@ -5805,7 +5888,31 @@ var Orchestrator = class {
|
|
|
5805
5888
|
void createThreadWorktree2;
|
|
5806
5889
|
void slug;
|
|
5807
5890
|
}
|
|
5808
|
-
|
|
5891
|
+
const restorePatch = {};
|
|
5892
|
+
let alreadyMerged = normalizePrState(thread.prState) === "MERGED";
|
|
5893
|
+
if (!alreadyMerged && thread.prUrl?.trim() && thread.worktreePath?.trim()) {
|
|
5894
|
+
try {
|
|
5895
|
+
const selector = resolvePrSelector(thread);
|
|
5896
|
+
if (selector) {
|
|
5897
|
+
const meta = await getPrMeta(thread.worktreePath, selector);
|
|
5898
|
+
if (meta) {
|
|
5899
|
+
const state = normalizePrState(meta.state);
|
|
5900
|
+
if (meta.url && meta.url !== thread.prUrl) restorePatch.prUrl = meta.url;
|
|
5901
|
+
if (meta.title && meta.title !== thread.prTitle) restorePatch.prTitle = meta.title;
|
|
5902
|
+
if (state) restorePatch.prState = state;
|
|
5903
|
+
if (state === "MERGED") alreadyMerged = true;
|
|
5904
|
+
}
|
|
5905
|
+
}
|
|
5906
|
+
} catch {
|
|
5907
|
+
}
|
|
5908
|
+
}
|
|
5909
|
+
if (alreadyMerged) restorePatch.skipAutoArchiveOnMerge = true;
|
|
5910
|
+
if (Object.keys(restorePatch).length > 0) {
|
|
5911
|
+
updateThread(thread.id, restorePatch);
|
|
5912
|
+
}
|
|
5913
|
+
const restored = setStatus(thread.id, "idle");
|
|
5914
|
+
this.emit({ type: "status_changed", threadId: restored.id, status: restored.status });
|
|
5915
|
+
return restored;
|
|
5809
5916
|
}
|
|
5810
5917
|
async attachCommand(threadRef) {
|
|
5811
5918
|
const thread = this.requireThread(threadRef);
|
|
@@ -5880,7 +5987,7 @@ async function startOrchestration(opts) {
|
|
|
5880
5987
|
sourceRef: "default",
|
|
5881
5988
|
...createOpts
|
|
5882
5989
|
}).catch(async () => {
|
|
5883
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
5990
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-K2JB53R5.js");
|
|
5884
5991
|
const repo = await resolveRepoRoot2(repoPath);
|
|
5885
5992
|
const def = await resolveDefaultBranch2(repo);
|
|
5886
5993
|
return createThread({
|
|
@@ -5890,7 +5997,7 @@ async function startOrchestration(opts) {
|
|
|
5890
5997
|
repoPath: repo
|
|
5891
5998
|
});
|
|
5892
5999
|
});
|
|
5893
|
-
const { updateThread: upd } = await import("./thread-store-
|
|
6000
|
+
const { updateThread: upd } = await import("./thread-store-XTPFCJAI.js");
|
|
5894
6001
|
const updated = upd(thread.id, {
|
|
5895
6002
|
sourceType: "orchestration",
|
|
5896
6003
|
sourceRef: goal
|
|
@@ -6036,7 +6143,7 @@ function withTimeout(promise, ms, label) {
|
|
|
6036
6143
|
async function startMcpServer() {
|
|
6037
6144
|
const orch = getOrchestrator();
|
|
6038
6145
|
try {
|
|
6039
|
-
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-
|
|
6146
|
+
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-ONKMFSEJ.js");
|
|
6040
6147
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
6041
6148
|
} catch {
|
|
6042
6149
|
}
|
|
@@ -6127,14 +6234,13 @@ async function startMcpServer() {
|
|
|
6127
6234
|
),
|
|
6128
6235
|
artifact_id: z.string().optional().describe("Stable id when updating the same artifact across turns")
|
|
6129
6236
|
},
|
|
6130
|
-
async ({ title, type,
|
|
6237
|
+
async ({ title, type, artifact_id }) => {
|
|
6131
6238
|
const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6132
6239
|
const payload = {
|
|
6133
6240
|
ok: true,
|
|
6134
6241
|
artifact_id: id,
|
|
6135
6242
|
title,
|
|
6136
6243
|
type,
|
|
6137
|
-
content,
|
|
6138
6244
|
message: "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
|
|
6139
6245
|
};
|
|
6140
6246
|
return { content: [{ type: "text", text: JSON.stringify(payload) }] };
|
|
@@ -6187,7 +6293,6 @@ async function startMcpServer() {
|
|
|
6187
6293
|
ok: true,
|
|
6188
6294
|
path,
|
|
6189
6295
|
title: title?.trim() || "Plan",
|
|
6190
|
-
content,
|
|
6191
6296
|
message: "Plan saved to .context/attachments/plan.md and shown in Sideboard chat for approval."
|
|
6192
6297
|
};
|
|
6193
6298
|
return { content: [{ type: "text", text: JSON.stringify(payload) }] };
|
|
@@ -6217,9 +6322,6 @@ async function startMcpServer() {
|
|
|
6217
6322
|
datasource: args.datasource ?? (args.resource ? "inline" : "brightsy"),
|
|
6218
6323
|
resource_id: args.resource_id,
|
|
6219
6324
|
record_id: args.record_id,
|
|
6220
|
-
resource: args.resource,
|
|
6221
|
-
record: args.record,
|
|
6222
|
-
records: args.records,
|
|
6223
6325
|
message: "Schema pane accepted. Sideboard desktop opens the CMS column beside chat."
|
|
6224
6326
|
};
|
|
6225
6327
|
return { content: [{ type: "text", text: JSON.stringify(payload) }] };
|
|
@@ -6247,739 +6349,741 @@ async function startMcpServer() {
|
|
|
6247
6349
|
return { content: [{ type: "text", text: JSON.stringify(payload) }] };
|
|
6248
6350
|
}
|
|
6249
6351
|
);
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
if (
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6352
|
+
if (sideboardMcpProfile() !== "worktree") {
|
|
6353
|
+
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-ONKMFSEJ.js");
|
|
6354
|
+
const accountDefaults = resolveThreadDefaults2();
|
|
6355
|
+
const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
|
|
6356
|
+
server.tool(
|
|
6357
|
+
"create_thread",
|
|
6358
|
+
`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.`,
|
|
6359
|
+
{
|
|
6360
|
+
sourceType: z.enum(["branch", "pr", "ticket"]),
|
|
6361
|
+
sourceRef: z.string(),
|
|
6362
|
+
agent: z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]).optional().describe(`Omit to use Account default agent (${accountDefaults.agent})`),
|
|
6363
|
+
model: z.string().nullable().optional().describe(
|
|
6364
|
+
`Usually omit to use Account default model (${accountDefaults.model?.trim() || "Auto"}). Pass null only to force Auto / agent-default.`
|
|
6365
|
+
),
|
|
6366
|
+
repoPath: z.string(),
|
|
6367
|
+
title: z.string().optional(),
|
|
6368
|
+
parentThreadId: z.string().optional().describe(
|
|
6369
|
+
"Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
|
|
6370
|
+
)
|
|
6371
|
+
},
|
|
6372
|
+
async (args) => {
|
|
6373
|
+
const envParentId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || "";
|
|
6374
|
+
let parentId = args.parentThreadId?.trim() || "";
|
|
6375
|
+
let parent = parentId ? orch.getThread(parentId) : null;
|
|
6376
|
+
let parentCorrectedFrom;
|
|
6377
|
+
if (envParentId) {
|
|
6378
|
+
const envParent = orch.getThread(envParentId);
|
|
6379
|
+
if (envParent) {
|
|
6380
|
+
if (parentId && parentId !== envParentId) parentCorrectedFrom = parentId;
|
|
6381
|
+
else if (!parentId) parentCorrectedFrom = void 0;
|
|
6382
|
+
parentId = envParentId;
|
|
6383
|
+
parent = envParent;
|
|
6384
|
+
}
|
|
6281
6385
|
}
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6386
|
+
if (parentId && !parent) {
|
|
6387
|
+
parentCorrectedFrom = parentId;
|
|
6388
|
+
parentId = "";
|
|
6389
|
+
parent = null;
|
|
6390
|
+
}
|
|
6391
|
+
if (parentId) {
|
|
6392
|
+
const children = orch.getThreads(false).filter((t) => t.parentThreadId === parentId);
|
|
6393
|
+
if (children.length >= MAX_ORCH_THREADS) {
|
|
6394
|
+
return {
|
|
6395
|
+
content: [
|
|
6396
|
+
{
|
|
6397
|
+
type: "text",
|
|
6398
|
+
text: `Thread-creation cap (${MAX_ORCH_THREADS}) reached for this orchestration session`
|
|
6399
|
+
}
|
|
6400
|
+
],
|
|
6401
|
+
isError: true
|
|
6402
|
+
};
|
|
6403
|
+
}
|
|
6404
|
+
}
|
|
6405
|
+
let agentArg = args.agent;
|
|
6406
|
+
let agentCoercedFrom;
|
|
6407
|
+
const resolvedProbe = resolveNewThreadOptions2({ agent: agentArg }).agent;
|
|
6408
|
+
if (resolvedProbe === "codex") {
|
|
6409
|
+
agentCoercedFrom = agentArg ?? "codex";
|
|
6410
|
+
const accountAgent = resolveNewThreadOptions2({}).agent;
|
|
6411
|
+
agentArg = accountAgent !== "codex" ? accountAgent : "cursor";
|
|
6412
|
+
}
|
|
6413
|
+
const opts = resolveNewThreadOptions2({
|
|
6414
|
+
agent: agentArg,
|
|
6415
|
+
model: args.model
|
|
6416
|
+
});
|
|
6417
|
+
try {
|
|
6418
|
+
const thread = await withTimeout(
|
|
6419
|
+
orch.createThread({
|
|
6420
|
+
sourceType: args.sourceType,
|
|
6421
|
+
sourceRef: args.sourceRef,
|
|
6422
|
+
agent: opts.agent,
|
|
6423
|
+
model: opts.model,
|
|
6424
|
+
effort: opts.effort,
|
|
6425
|
+
fast: opts.fast,
|
|
6426
|
+
repoPath: args.repoPath,
|
|
6427
|
+
title: args.title,
|
|
6428
|
+
parentThreadId: parentId || null
|
|
6429
|
+
}),
|
|
6430
|
+
CREATE_THREAD_TIMEOUT_MS,
|
|
6431
|
+
"create_thread"
|
|
6432
|
+
);
|
|
6433
|
+
const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
|
|
6434
|
+
return {
|
|
6435
|
+
content: [
|
|
6436
|
+
{
|
|
6437
|
+
type: "text",
|
|
6438
|
+
text: JSON.stringify({
|
|
6439
|
+
id: thread.id,
|
|
6440
|
+
title: thread.title,
|
|
6441
|
+
branchName: thread.branchName,
|
|
6442
|
+
worktreePath: thread.worktreePath,
|
|
6443
|
+
agent: thread.agent,
|
|
6444
|
+
model: thread.model,
|
|
6445
|
+
status: thread.status,
|
|
6446
|
+
link: `sideboard://thread/${thread.id}`,
|
|
6447
|
+
parentThreadId: thread.parentThreadId,
|
|
6448
|
+
...agentCoercedFrom ? {
|
|
6449
|
+
agentCoercedFrom,
|
|
6450
|
+
note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
|
|
6451
|
+
} : {},
|
|
6452
|
+
...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
|
|
6453
|
+
})
|
|
6454
|
+
}
|
|
6455
|
+
]
|
|
6456
|
+
};
|
|
6457
|
+
} catch (err) {
|
|
6458
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6291
6459
|
return {
|
|
6292
6460
|
content: [
|
|
6293
6461
|
{
|
|
6294
6462
|
type: "text",
|
|
6295
|
-
text: `
|
|
6463
|
+
text: `create_thread failed: ${message}`
|
|
6296
6464
|
}
|
|
6297
6465
|
],
|
|
6298
6466
|
isError: true
|
|
6299
6467
|
};
|
|
6300
6468
|
}
|
|
6301
6469
|
}
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
agent: opts.agent,
|
|
6320
|
-
model: opts.model,
|
|
6321
|
-
effort: opts.effort,
|
|
6322
|
-
fast: opts.fast,
|
|
6323
|
-
repoPath: args.repoPath,
|
|
6324
|
-
title: args.title,
|
|
6325
|
-
parentThreadId: parentId || null
|
|
6326
|
-
}),
|
|
6327
|
-
CREATE_THREAD_TIMEOUT_MS,
|
|
6328
|
-
"create_thread"
|
|
6329
|
-
);
|
|
6330
|
-
const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
|
|
6470
|
+
);
|
|
6471
|
+
server.tool(
|
|
6472
|
+
"send_to_thread",
|
|
6473
|
+
"Queue a prompt on a worktree thread chat (runs under concurrency cap). Use after create_thread to start or continue a conversation. Set force_stop=true to interrupt an in-flight/queued turn (kill + clear queue) before queueing this prompt \u2014 use when the thread is mid-turn or has stale queued prompts you need to replace.",
|
|
6474
|
+
{
|
|
6475
|
+
ref: z.string(),
|
|
6476
|
+
prompt: z.string(),
|
|
6477
|
+
force_stop: z.boolean().optional()
|
|
6478
|
+
},
|
|
6479
|
+
async ({ ref, prompt, force_stop }) => {
|
|
6480
|
+
if (force_stop) {
|
|
6481
|
+
const existing = orch.getThread(ref);
|
|
6482
|
+
if (existing) {
|
|
6483
|
+
orch.stop(ref, { clearQueue: true });
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
const thread = await orch.send(ref, prompt);
|
|
6331
6487
|
return {
|
|
6332
6488
|
content: [
|
|
6333
6489
|
{
|
|
6334
6490
|
type: "text",
|
|
6335
6491
|
text: JSON.stringify({
|
|
6336
6492
|
id: thread.id,
|
|
6337
|
-
title: thread.title,
|
|
6338
|
-
branchName: thread.branchName,
|
|
6339
|
-
worktreePath: thread.worktreePath,
|
|
6340
|
-
agent: thread.agent,
|
|
6341
|
-
model: thread.model,
|
|
6342
6493
|
status: thread.status,
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
...agentCoercedFrom ? {
|
|
6346
|
-
agentCoercedFrom,
|
|
6347
|
-
note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
|
|
6348
|
-
} : {},
|
|
6349
|
-
...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
|
|
6494
|
+
queueLength: thread.queue.length,
|
|
6495
|
+
forceStopped: Boolean(force_stop)
|
|
6350
6496
|
})
|
|
6351
6497
|
}
|
|
6352
6498
|
]
|
|
6353
6499
|
};
|
|
6354
|
-
}
|
|
6355
|
-
|
|
6500
|
+
}
|
|
6501
|
+
);
|
|
6502
|
+
server.tool(
|
|
6503
|
+
"wait_for_turn",
|
|
6504
|
+
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread to read the agent reply.",
|
|
6505
|
+
{
|
|
6506
|
+
ref: z.string(),
|
|
6507
|
+
timeoutMs: z.number().optional()
|
|
6508
|
+
},
|
|
6509
|
+
async ({ ref, timeoutMs }) => {
|
|
6510
|
+
const thread = await orch.waitForTurn(ref, timeoutMs ?? 6e5);
|
|
6511
|
+
const result = orch.getTurnResult(thread.id);
|
|
6356
6512
|
return {
|
|
6357
6513
|
content: [
|
|
6358
6514
|
{
|
|
6359
6515
|
type: "text",
|
|
6360
|
-
text:
|
|
6516
|
+
text: JSON.stringify({
|
|
6517
|
+
id: thread.id,
|
|
6518
|
+
status: result.status,
|
|
6519
|
+
text: result.text
|
|
6520
|
+
})
|
|
6361
6521
|
}
|
|
6362
|
-
]
|
|
6363
|
-
isError: true
|
|
6364
|
-
};
|
|
6365
|
-
}
|
|
6366
|
-
}
|
|
6367
|
-
);
|
|
6368
|
-
server.tool(
|
|
6369
|
-
"send_to_thread",
|
|
6370
|
-
"Queue a prompt on a worktree thread chat (runs under concurrency cap). Use after create_thread to start or continue a conversation. Set force_stop=true to interrupt an in-flight/queued turn (kill + clear queue) before queueing this prompt \u2014 use when the thread is mid-turn or has stale queued prompts you need to replace.",
|
|
6371
|
-
{
|
|
6372
|
-
ref: z.string(),
|
|
6373
|
-
prompt: z.string(),
|
|
6374
|
-
force_stop: z.boolean().optional()
|
|
6375
|
-
},
|
|
6376
|
-
async ({ ref, prompt, force_stop }) => {
|
|
6377
|
-
if (force_stop) {
|
|
6378
|
-
const existing = orch.getThread(ref);
|
|
6379
|
-
if (existing) {
|
|
6380
|
-
orch.stop(ref, { clearQueue: true });
|
|
6381
|
-
}
|
|
6382
|
-
}
|
|
6383
|
-
const thread = await orch.send(ref, prompt);
|
|
6384
|
-
return {
|
|
6385
|
-
content: [
|
|
6386
|
-
{
|
|
6387
|
-
type: "text",
|
|
6388
|
-
text: JSON.stringify({
|
|
6389
|
-
id: thread.id,
|
|
6390
|
-
status: thread.status,
|
|
6391
|
-
queueLength: thread.queue.length,
|
|
6392
|
-
forceStopped: Boolean(force_stop)
|
|
6393
|
-
})
|
|
6394
|
-
}
|
|
6395
|
-
]
|
|
6396
|
-
};
|
|
6397
|
-
}
|
|
6398
|
-
);
|
|
6399
|
-
server.tool(
|
|
6400
|
-
"wait_for_turn",
|
|
6401
|
-
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread to read the agent reply.",
|
|
6402
|
-
{
|
|
6403
|
-
ref: z.string(),
|
|
6404
|
-
timeoutMs: z.number().optional()
|
|
6405
|
-
},
|
|
6406
|
-
async ({ ref, timeoutMs }) => {
|
|
6407
|
-
const thread = await orch.waitForTurn(ref, timeoutMs ?? 6e5);
|
|
6408
|
-
const result = orch.getTurnResult(thread.id);
|
|
6409
|
-
return {
|
|
6410
|
-
content: [
|
|
6411
|
-
{
|
|
6412
|
-
type: "text",
|
|
6413
|
-
text: JSON.stringify({
|
|
6414
|
-
id: thread.id,
|
|
6415
|
-
status: result.status,
|
|
6416
|
-
text: result.text
|
|
6417
|
-
})
|
|
6418
|
-
}
|
|
6419
|
-
]
|
|
6420
|
-
};
|
|
6421
|
-
}
|
|
6422
|
-
);
|
|
6423
|
-
server.tool(
|
|
6424
|
-
"get_turn_result",
|
|
6425
|
-
"Final assistant message only (not full transcript)",
|
|
6426
|
-
{ ref: z.string() },
|
|
6427
|
-
async ({ ref }) => {
|
|
6428
|
-
const result = orch.getTurnResult(ref);
|
|
6429
|
-
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
6430
|
-
}
|
|
6431
|
-
);
|
|
6432
|
-
server.tool(
|
|
6433
|
-
"stop_thread",
|
|
6434
|
-
"Force-stop a thread: kill any in-flight agent turn AND clear queued prompts so drainQueue cannot continue. Does not archive the worktree. Optional force defaults to true.",
|
|
6435
|
-
{
|
|
6436
|
-
ref: z.string(),
|
|
6437
|
-
force: z.boolean().optional()
|
|
6438
|
-
},
|
|
6439
|
-
async ({ ref, force }) => {
|
|
6440
|
-
const t = orch.getThread(ref);
|
|
6441
|
-
if (!t) {
|
|
6442
|
-
return {
|
|
6443
|
-
content: [{ type: "text", text: `Thread not found: ${ref}` }],
|
|
6444
|
-
isError: true
|
|
6445
|
-
};
|
|
6446
|
-
}
|
|
6447
|
-
const clearQueue = force !== false;
|
|
6448
|
-
const hadQueued = t.queue.length > 0;
|
|
6449
|
-
const stopped = orch.stop(ref, { clearQueue });
|
|
6450
|
-
return {
|
|
6451
|
-
content: [
|
|
6452
|
-
{
|
|
6453
|
-
type: "text",
|
|
6454
|
-
text: JSON.stringify({
|
|
6455
|
-
id: stopped.id,
|
|
6456
|
-
status: stopped.status,
|
|
6457
|
-
clearedQueue: clearQueue && hadQueued
|
|
6458
|
-
})
|
|
6459
|
-
}
|
|
6460
|
-
]
|
|
6461
|
-
};
|
|
6462
|
-
}
|
|
6463
|
-
);
|
|
6464
|
-
server.tool(
|
|
6465
|
-
"archive_thread",
|
|
6466
|
-
"Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Cannot archive the cloud coordinator \u2014 use the Sideboard UI for that.",
|
|
6467
|
-
{ ref: z.string() },
|
|
6468
|
-
async ({ ref }) => {
|
|
6469
|
-
const t = orch.getThread(ref);
|
|
6470
|
-
if (!t) {
|
|
6471
|
-
return {
|
|
6472
|
-
content: [{ type: "text", text: `Thread not found: ${ref}` }],
|
|
6473
|
-
isError: true
|
|
6522
|
+
]
|
|
6474
6523
|
};
|
|
6475
6524
|
}
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6525
|
+
);
|
|
6526
|
+
server.tool(
|
|
6527
|
+
"get_turn_result",
|
|
6528
|
+
"Final assistant message only (not full transcript)",
|
|
6529
|
+
{ ref: z.string() },
|
|
6530
|
+
async ({ ref }) => {
|
|
6531
|
+
const result = orch.getTurnResult(ref);
|
|
6532
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
6482
6533
|
}
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
try {
|
|
6503
|
-
const restored = await orch.restore(ref);
|
|
6534
|
+
);
|
|
6535
|
+
server.tool(
|
|
6536
|
+
"stop_thread",
|
|
6537
|
+
"Force-stop a thread: kill any in-flight agent turn AND clear queued prompts so drainQueue cannot continue. Does not archive the worktree. Optional force defaults to true.",
|
|
6538
|
+
{
|
|
6539
|
+
ref: z.string(),
|
|
6540
|
+
force: z.boolean().optional()
|
|
6541
|
+
},
|
|
6542
|
+
async ({ ref, force }) => {
|
|
6543
|
+
const t = orch.getThread(ref);
|
|
6544
|
+
if (!t) {
|
|
6545
|
+
return {
|
|
6546
|
+
content: [{ type: "text", text: `Thread not found: ${ref}` }],
|
|
6547
|
+
isError: true
|
|
6548
|
+
};
|
|
6549
|
+
}
|
|
6550
|
+
const clearQueue = force !== false;
|
|
6551
|
+
const hadQueued = t.queue.length > 0;
|
|
6552
|
+
const stopped = orch.stop(ref, { clearQueue });
|
|
6504
6553
|
return {
|
|
6505
6554
|
content: [
|
|
6506
6555
|
{
|
|
6507
6556
|
type: "text",
|
|
6508
6557
|
text: JSON.stringify({
|
|
6509
|
-
id:
|
|
6510
|
-
status:
|
|
6511
|
-
|
|
6558
|
+
id: stopped.id,
|
|
6559
|
+
status: stopped.status,
|
|
6560
|
+
clearedQueue: clearQueue && hadQueued
|
|
6512
6561
|
})
|
|
6513
6562
|
}
|
|
6514
6563
|
]
|
|
6515
6564
|
};
|
|
6516
|
-
} catch (err) {
|
|
6517
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6518
|
-
return { content: [{ type: "text", text: message }], isError: true };
|
|
6519
6565
|
}
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
};
|
|
6542
|
-
}
|
|
6543
|
-
);
|
|
6544
|
-
server.tool(
|
|
6545
|
-
"request_review",
|
|
6546
|
-
'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.',
|
|
6547
|
-
{ ref: z.string().describe("Worktree thread id/ref to review") },
|
|
6548
|
-
async ({ ref }) => {
|
|
6549
|
-
try {
|
|
6550
|
-
const tab = await orch.requestReview(ref);
|
|
6551
|
-
const from = orch.getThread(ref);
|
|
6566
|
+
);
|
|
6567
|
+
server.tool(
|
|
6568
|
+
"archive_thread",
|
|
6569
|
+
"Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Cannot archive the cloud coordinator \u2014 use the Sideboard UI for that.",
|
|
6570
|
+
{ ref: z.string() },
|
|
6571
|
+
async ({ ref }) => {
|
|
6572
|
+
const t = orch.getThread(ref);
|
|
6573
|
+
if (!t) {
|
|
6574
|
+
return {
|
|
6575
|
+
content: [{ type: "text", text: `Thread not found: ${ref}` }],
|
|
6576
|
+
isError: true
|
|
6577
|
+
};
|
|
6578
|
+
}
|
|
6579
|
+
const blocked = mcpArchiveBlockedReason(t);
|
|
6580
|
+
if (blocked) {
|
|
6581
|
+
return {
|
|
6582
|
+
content: [{ type: "text", text: blocked }],
|
|
6583
|
+
isError: true
|
|
6584
|
+
};
|
|
6585
|
+
}
|
|
6586
|
+
const archived = await orch.archive(ref);
|
|
6552
6587
|
return {
|
|
6553
6588
|
content: [
|
|
6554
6589
|
{
|
|
6555
6590
|
type: "text",
|
|
6556
6591
|
text: JSON.stringify({
|
|
6557
|
-
id:
|
|
6558
|
-
|
|
6559
|
-
status: tab.status,
|
|
6560
|
-
fromThreadId: from?.id ?? ref,
|
|
6561
|
-
link: `sideboard://thread/${tab.id}`
|
|
6592
|
+
id: archived.id,
|
|
6593
|
+
status: archived.status
|
|
6562
6594
|
})
|
|
6563
6595
|
}
|
|
6564
6596
|
]
|
|
6565
6597
|
};
|
|
6566
|
-
} catch (err) {
|
|
6567
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6568
|
-
return { content: [{ type: "text", text: message }], isError: true };
|
|
6569
6598
|
}
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6599
|
+
);
|
|
6600
|
+
server.tool(
|
|
6601
|
+
"restore_thread",
|
|
6602
|
+
"Restore an archived thread (recreates worktree from branch when needed)",
|
|
6603
|
+
{ ref: z.string() },
|
|
6604
|
+
async ({ ref }) => {
|
|
6605
|
+
try {
|
|
6606
|
+
const restored = await orch.restore(ref);
|
|
6607
|
+
return {
|
|
6608
|
+
content: [
|
|
6609
|
+
{
|
|
6610
|
+
type: "text",
|
|
6611
|
+
text: JSON.stringify({
|
|
6612
|
+
id: restored.id,
|
|
6613
|
+
status: restored.status,
|
|
6614
|
+
worktreePath: restored.worktreePath
|
|
6615
|
+
})
|
|
6616
|
+
}
|
|
6617
|
+
]
|
|
6618
|
+
};
|
|
6619
|
+
} catch (err) {
|
|
6620
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6621
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
6622
|
+
}
|
|
6588
6623
|
}
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
title: z.string().optional()
|
|
6600
|
-
},
|
|
6601
|
-
async ({ ref, through_index, agent, model, title }) => {
|
|
6602
|
-
try {
|
|
6603
|
-
const source = orch.getThread(ref);
|
|
6604
|
-
if (source) await orch.reconcile(source.repoPath, { drainQueues: false });
|
|
6605
|
-
const thread = await orch.forkThreadWorktree({
|
|
6606
|
-
threadId: ref,
|
|
6607
|
-
throughIndex: through_index,
|
|
6608
|
-
agent,
|
|
6609
|
-
model,
|
|
6610
|
-
title
|
|
6611
|
-
});
|
|
6624
|
+
);
|
|
6625
|
+
server.tool(
|
|
6626
|
+
"get_diff",
|
|
6627
|
+
"Compact diff summary (capped hunks, paginated)",
|
|
6628
|
+
{
|
|
6629
|
+
ref: z.string(),
|
|
6630
|
+
maxFiles: z.number().optional()
|
|
6631
|
+
},
|
|
6632
|
+
async ({ ref, maxFiles }) => {
|
|
6633
|
+
const summary = await orch.diffSummary(ref);
|
|
6612
6634
|
return {
|
|
6613
6635
|
content: [
|
|
6614
6636
|
{
|
|
6615
6637
|
type: "text",
|
|
6616
6638
|
text: JSON.stringify({
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
status: thread.status,
|
|
6620
|
-
agent: thread.agent,
|
|
6621
|
-
model: thread.model,
|
|
6622
|
-
branchName: thread.branchName,
|
|
6623
|
-
worktreePath: thread.worktreePath,
|
|
6624
|
-
fromThreadId: source?.id ?? ref,
|
|
6625
|
-
link: `sideboard://thread/${thread.id}`
|
|
6639
|
+
...summary,
|
|
6640
|
+
files: summary.files.slice(0, maxFiles ?? 10)
|
|
6626
6641
|
})
|
|
6627
6642
|
}
|
|
6628
6643
|
]
|
|
6629
6644
|
};
|
|
6630
|
-
} catch (err) {
|
|
6631
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6632
|
-
return { content: [{ type: "text", text: message }], isError: true };
|
|
6633
6645
|
}
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
model: z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
6644
|
-
title: z.string().optional()
|
|
6645
|
-
},
|
|
6646
|
-
async ({ ref, through_index, agent, model, title }) => {
|
|
6647
|
-
try {
|
|
6648
|
-
const source = orch.getThread(ref);
|
|
6649
|
-
if (!source) {
|
|
6646
|
+
);
|
|
6647
|
+
server.tool(
|
|
6648
|
+
"request_review",
|
|
6649
|
+
'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.',
|
|
6650
|
+
{ ref: z.string().describe("Worktree thread id/ref to review") },
|
|
6651
|
+
async ({ ref }) => {
|
|
6652
|
+
try {
|
|
6653
|
+
const tab = await orch.requestReview(ref);
|
|
6654
|
+
const from = orch.getThread(ref);
|
|
6650
6655
|
return {
|
|
6651
|
-
content: [
|
|
6652
|
-
|
|
6656
|
+
content: [
|
|
6657
|
+
{
|
|
6658
|
+
type: "text",
|
|
6659
|
+
text: JSON.stringify({
|
|
6660
|
+
id: tab.id,
|
|
6661
|
+
title: tab.title,
|
|
6662
|
+
status: tab.status,
|
|
6663
|
+
fromThreadId: from?.id ?? ref,
|
|
6664
|
+
link: `sideboard://thread/${tab.id}`
|
|
6665
|
+
})
|
|
6666
|
+
}
|
|
6667
|
+
]
|
|
6653
6668
|
};
|
|
6669
|
+
} catch (err) {
|
|
6670
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6671
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
6654
6672
|
}
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6673
|
+
}
|
|
6674
|
+
);
|
|
6675
|
+
const agentEnum = z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]);
|
|
6676
|
+
server.tool(
|
|
6677
|
+
"list_models",
|
|
6678
|
+
"List models for an agent. Prefer Auto: do not call this unless you have a reason to pin a specific model (user request, cost/latency, capability). Omit agent to list all.",
|
|
6679
|
+
{
|
|
6680
|
+
agent: agentEnum.optional().describe("Limit to one agent; omit for all")
|
|
6681
|
+
},
|
|
6682
|
+
async ({ agent }) => {
|
|
6683
|
+
try {
|
|
6684
|
+
const catalogs = await listModelsForAgent(agent);
|
|
6685
|
+
return {
|
|
6686
|
+
content: [{ type: "text", text: JSON.stringify(catalogs, null, 2) }]
|
|
6687
|
+
};
|
|
6688
|
+
} catch (err) {
|
|
6689
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6690
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
);
|
|
6694
|
+
server.tool(
|
|
6695
|
+
"fork_worktree",
|
|
6696
|
+
"Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then send_to_thread / wait_for_turn on the returned id.",
|
|
6697
|
+
{
|
|
6698
|
+
ref: z.string().describe("Worktree thread id/ref to fork"),
|
|
6699
|
+
through_index: z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
6700
|
+
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
6701
|
+
model: z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
6702
|
+
title: z.string().optional()
|
|
6703
|
+
},
|
|
6704
|
+
async ({ ref, through_index, agent, model, title }) => {
|
|
6705
|
+
try {
|
|
6706
|
+
const source = orch.getThread(ref);
|
|
6707
|
+
if (source) await orch.reconcile(source.repoPath, { drainQueues: false });
|
|
6708
|
+
const thread = await orch.forkThreadWorktree({
|
|
6709
|
+
threadId: ref,
|
|
6710
|
+
throughIndex: through_index,
|
|
6711
|
+
agent,
|
|
6712
|
+
model,
|
|
6713
|
+
title
|
|
6714
|
+
});
|
|
6715
|
+
return {
|
|
6716
|
+
content: [
|
|
6717
|
+
{
|
|
6718
|
+
type: "text",
|
|
6719
|
+
text: JSON.stringify({
|
|
6720
|
+
id: thread.id,
|
|
6721
|
+
title: thread.title,
|
|
6722
|
+
status: thread.status,
|
|
6723
|
+
agent: thread.agent,
|
|
6724
|
+
model: thread.model,
|
|
6725
|
+
branchName: thread.branchName,
|
|
6726
|
+
worktreePath: thread.worktreePath,
|
|
6727
|
+
fromThreadId: source?.id ?? ref,
|
|
6728
|
+
link: `sideboard://thread/${thread.id}`
|
|
6729
|
+
})
|
|
6730
|
+
}
|
|
6731
|
+
]
|
|
6732
|
+
};
|
|
6733
|
+
} catch (err) {
|
|
6734
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6735
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6738
|
+
);
|
|
6739
|
+
server.tool(
|
|
6740
|
+
"fork_chat",
|
|
6741
|
+
"Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Remote coordinators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
|
|
6742
|
+
{
|
|
6743
|
+
ref: z.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
|
|
6744
|
+
through_index: z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
6745
|
+
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
6746
|
+
model: z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
6747
|
+
title: z.string().optional()
|
|
6748
|
+
},
|
|
6749
|
+
async ({ ref, through_index, agent, model, title }) => {
|
|
6750
|
+
try {
|
|
6751
|
+
const source = orch.getThread(ref);
|
|
6752
|
+
if (!source) {
|
|
6753
|
+
return {
|
|
6754
|
+
content: [{ type: "text", text: `Thread not found: ${ref}` }],
|
|
6755
|
+
isError: true
|
|
6756
|
+
};
|
|
6757
|
+
}
|
|
6758
|
+
const tab = orch.forkChatTab({
|
|
6759
|
+
threadId: source.id,
|
|
6760
|
+
throughIndex: through_index,
|
|
6761
|
+
agent,
|
|
6762
|
+
model,
|
|
6763
|
+
title
|
|
6764
|
+
});
|
|
6765
|
+
return {
|
|
6766
|
+
content: [
|
|
6767
|
+
{
|
|
6768
|
+
type: "text",
|
|
6769
|
+
text: JSON.stringify({
|
|
6770
|
+
id: tab.id,
|
|
6771
|
+
title: tab.title,
|
|
6772
|
+
status: tab.status,
|
|
6773
|
+
agent: tab.agent,
|
|
6774
|
+
model: tab.model,
|
|
6775
|
+
sourceType: tab.sourceType,
|
|
6776
|
+
worktreePath: tab.worktreePath,
|
|
6777
|
+
fromThreadId: source.id,
|
|
6778
|
+
link: `sideboard://thread/${tab.id}`
|
|
6779
|
+
})
|
|
6780
|
+
}
|
|
6781
|
+
]
|
|
6782
|
+
};
|
|
6783
|
+
} catch (err) {
|
|
6784
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6785
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
6786
|
+
}
|
|
6787
|
+
}
|
|
6788
|
+
);
|
|
6789
|
+
server.tool(
|
|
6790
|
+
"run_dev_script",
|
|
6791
|
+
"Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
|
|
6792
|
+
{
|
|
6793
|
+
ref: z.string(),
|
|
6794
|
+
name: z.string().optional()
|
|
6795
|
+
},
|
|
6796
|
+
async ({ ref, name }) => {
|
|
6797
|
+
const result = await orch.startDev(ref, name);
|
|
6662
6798
|
return {
|
|
6663
6799
|
content: [
|
|
6664
6800
|
{
|
|
6665
6801
|
type: "text",
|
|
6666
6802
|
text: JSON.stringify({
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
model: tab.model,
|
|
6672
|
-
sourceType: tab.sourceType,
|
|
6673
|
-
worktreePath: tab.worktreePath,
|
|
6674
|
-
fromThreadId: source.id,
|
|
6675
|
-
link: `sideboard://thread/${tab.id}`
|
|
6803
|
+
port: result.port,
|
|
6804
|
+
scriptName: result.scriptName,
|
|
6805
|
+
ports: result.ports,
|
|
6806
|
+
url: `http://localhost:${result.port}`
|
|
6676
6807
|
})
|
|
6677
6808
|
}
|
|
6678
6809
|
]
|
|
6679
6810
|
};
|
|
6680
|
-
} catch (err) {
|
|
6681
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6682
|
-
return { content: [{ type: "text", text: message }], isError: true };
|
|
6683
6811
|
}
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
{ repoPath: z.string() },
|
|
6763
|
-
async ({ repoPath }) => {
|
|
6764
|
-
orch.removeWorkspace(repoPath);
|
|
6765
|
-
return { content: [{ type: "text", text: "ok" }] };
|
|
6766
|
-
}
|
|
6767
|
-
);
|
|
6768
|
-
server.tool(
|
|
6769
|
-
"fanout",
|
|
6770
|
-
"Best-of-n: create one thread per agent with the same prompt (parallel attempts)",
|
|
6771
|
-
{
|
|
6772
|
-
prompt: z.string(),
|
|
6773
|
-
agents: z.array(z.enum(["claude", "codex", "opencode", "brightsy", "cursor"])),
|
|
6774
|
-
repoPath: z.string(),
|
|
6775
|
-
sourceType: z.enum(["branch", "pr", "ticket"]).optional(),
|
|
6776
|
-
sourceRef: z.string().optional(),
|
|
6777
|
-
title: z.string().optional()
|
|
6778
|
-
},
|
|
6779
|
-
async (args) => {
|
|
6780
|
-
const threads = await orch.bestOfN(args);
|
|
6781
|
-
return {
|
|
6782
|
-
content: [
|
|
6783
|
-
{
|
|
6784
|
-
type: "text",
|
|
6785
|
-
text: JSON.stringify(
|
|
6786
|
-
threads.map((t) => ({
|
|
6787
|
-
id: t.id,
|
|
6788
|
-
agent: t.agent,
|
|
6789
|
-
branchName: t.branchName,
|
|
6790
|
-
worktreePath: t.worktreePath
|
|
6791
|
-
})),
|
|
6792
|
-
null,
|
|
6793
|
-
2
|
|
6794
|
-
)
|
|
6795
|
-
}
|
|
6796
|
-
]
|
|
6797
|
-
};
|
|
6798
|
-
}
|
|
6799
|
-
);
|
|
6800
|
-
server.tool(
|
|
6801
|
-
"list_branches",
|
|
6802
|
-
"List git branches in a registered workspace. Pass repoPath from list_workspaces (unmerged into the default branch by default \u2014 for create_thread sourceType=branch).",
|
|
6803
|
-
{
|
|
6804
|
-
repoPath: z.string(),
|
|
6805
|
-
unmergedOnly: z.boolean().optional()
|
|
6806
|
-
},
|
|
6807
|
-
async ({ repoPath, unmergedOnly }) => {
|
|
6808
|
-
const root = await resolveRepoRoot(repoPath);
|
|
6809
|
-
const branches = await listBranches(root, {
|
|
6810
|
-
unmergedOnly: unmergedOnly !== false
|
|
6811
|
-
});
|
|
6812
|
-
return {
|
|
6813
|
-
content: [
|
|
6814
|
-
{
|
|
6815
|
-
type: "text",
|
|
6816
|
-
text: branches.map((b) => `${b.current ? "*" : " "} ${b.name}`).join("\n")
|
|
6817
|
-
}
|
|
6818
|
-
]
|
|
6819
|
-
};
|
|
6820
|
-
}
|
|
6821
|
-
);
|
|
6822
|
-
server.tool(
|
|
6823
|
-
"list_prs",
|
|
6824
|
-
"List open GitHub PRs for a registered workspace. Pass repoPath from list_workspaces (uses gh against that repo remote). Then create_thread with sourceType=pr.",
|
|
6825
|
-
{ repoPath: z.string() },
|
|
6826
|
-
async ({ repoPath }) => {
|
|
6827
|
-
const root = await resolveRepoRoot(repoPath);
|
|
6828
|
-
const prs = await listPrs(root);
|
|
6829
|
-
return {
|
|
6830
|
-
content: [
|
|
6831
|
-
{
|
|
6832
|
-
type: "text",
|
|
6833
|
-
text: prs.map(
|
|
6834
|
-
(p) => `#${p.number} ${p.title} (${p.headRefName})${p.isCrossRepository ? " [fork]" : ""}`
|
|
6835
|
-
).join("\n")
|
|
6836
|
-
}
|
|
6837
|
-
]
|
|
6838
|
-
};
|
|
6839
|
-
}
|
|
6840
|
-
);
|
|
6841
|
-
server.tool(
|
|
6842
|
-
"get_pr_stack",
|
|
6843
|
-
"Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before mergePr on stacked PRs.",
|
|
6844
|
-
{ ref: z.string() },
|
|
6845
|
-
async ({ ref }) => {
|
|
6846
|
-
const stack = await orch.getPrStack(ref);
|
|
6847
|
-
return {
|
|
6848
|
-
content: [{ type: "text", text: JSON.stringify(stack, null, 2) }]
|
|
6849
|
-
};
|
|
6850
|
-
}
|
|
6851
|
-
);
|
|
6852
|
-
server.tool(
|
|
6853
|
-
"open_pr_stack_layers",
|
|
6854
|
-
"Materialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.",
|
|
6855
|
-
{
|
|
6856
|
-
ref: z.string(),
|
|
6857
|
-
layer: z.number().int().positive().optional()
|
|
6858
|
-
},
|
|
6859
|
-
async ({ ref, layer }) => {
|
|
6860
|
-
const result = await orch.openPrStackLayers(ref, { layer });
|
|
6861
|
-
return {
|
|
6862
|
-
content: [
|
|
6863
|
-
{
|
|
6864
|
-
type: "text",
|
|
6865
|
-
text: JSON.stringify(
|
|
6866
|
-
{
|
|
6867
|
-
stackNumber: result.stack.stackNumber,
|
|
6868
|
-
trunk: result.stack.trunk,
|
|
6869
|
-
threads: result.threads.map((t) => ({
|
|
6870
|
-
id: t.id,
|
|
6871
|
-
title: t.title,
|
|
6872
|
-
branchName: t.branchName,
|
|
6873
|
-
stackLayer: t.stackLayer,
|
|
6874
|
-
worktreePath: t.worktreePath,
|
|
6875
|
-
prUrl: t.prUrl,
|
|
6876
|
-
link: `sideboard://thread/${t.id}`
|
|
6877
|
-
}))
|
|
6878
|
-
},
|
|
6879
|
-
null,
|
|
6880
|
-
2
|
|
6881
|
-
)
|
|
6882
|
-
}
|
|
6883
|
-
]
|
|
6884
|
-
};
|
|
6885
|
-
}
|
|
6886
|
-
);
|
|
6887
|
-
server.tool(
|
|
6888
|
-
"add_stack_layer",
|
|
6889
|
-
"Add a branch on top of the current stack (`gh stack add`) and open a worktree+thread for it.",
|
|
6890
|
-
{
|
|
6891
|
-
ref: z.string(),
|
|
6892
|
-
branchName: z.string(),
|
|
6893
|
-
title: z.string().optional()
|
|
6894
|
-
},
|
|
6895
|
-
async ({ ref, branchName, title }) => {
|
|
6896
|
-
const result = await orch.addStackLayer(ref, branchName, { title });
|
|
6897
|
-
return {
|
|
6898
|
-
content: [
|
|
6899
|
-
{
|
|
6900
|
-
type: "text",
|
|
6901
|
-
text: JSON.stringify(
|
|
6902
|
-
{
|
|
6903
|
-
id: result.thread.id,
|
|
6904
|
-
title: result.thread.title,
|
|
6905
|
-
branchName: result.thread.branchName,
|
|
6906
|
-
stackLayer: result.thread.stackLayer,
|
|
6907
|
-
worktreePath: result.thread.worktreePath,
|
|
6908
|
-
link: `sideboard://thread/${result.thread.id}`
|
|
6909
|
-
},
|
|
6910
|
-
null,
|
|
6911
|
-
2
|
|
6912
|
-
)
|
|
6913
|
-
}
|
|
6914
|
-
]
|
|
6915
|
-
};
|
|
6916
|
-
}
|
|
6917
|
-
);
|
|
6918
|
-
server.tool(
|
|
6919
|
-
"create_pr_stack",
|
|
6920
|
-
"Create a new GitHub PR stack with one Sideboard worktree per layer (bottom\u2192top branch names). Requires `gh extension install github/gh-stack`.",
|
|
6921
|
-
{
|
|
6922
|
-
repoPath: z.string(),
|
|
6923
|
-
branches: z.array(z.string()).min(1),
|
|
6924
|
-
agent: z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
|
|
6925
|
-
base: z.string().optional(),
|
|
6926
|
-
title: z.string().optional()
|
|
6927
|
-
},
|
|
6928
|
-
async (args) => {
|
|
6929
|
-
const result = await orch.createPrStack({
|
|
6930
|
-
repoPath: args.repoPath,
|
|
6931
|
-
branches: args.branches,
|
|
6932
|
-
agent: args.agent,
|
|
6933
|
-
base: args.base,
|
|
6934
|
-
title: args.title
|
|
6935
|
-
});
|
|
6936
|
-
return {
|
|
6937
|
-
content: [
|
|
6938
|
-
{
|
|
6939
|
-
type: "text",
|
|
6940
|
-
text: JSON.stringify(
|
|
6941
|
-
{
|
|
6942
|
-
stackNumber: result.stack.stackNumber,
|
|
6943
|
-
trunk: result.stack.trunk,
|
|
6944
|
-
threads: result.threads.map((t) => ({
|
|
6812
|
+
);
|
|
6813
|
+
server.tool(
|
|
6814
|
+
"list_run_scripts",
|
|
6815
|
+
"List named run scripts available for a thread",
|
|
6816
|
+
{ ref: z.string() },
|
|
6817
|
+
async ({ ref }) => {
|
|
6818
|
+
const scripts = orch.listThreadRunScripts(ref);
|
|
6819
|
+
const active = orch.getActiveRuns(ref);
|
|
6820
|
+
return {
|
|
6821
|
+
content: [
|
|
6822
|
+
{
|
|
6823
|
+
type: "text",
|
|
6824
|
+
text: JSON.stringify({ scripts, active }, null, 2)
|
|
6825
|
+
}
|
|
6826
|
+
]
|
|
6827
|
+
};
|
|
6828
|
+
}
|
|
6829
|
+
);
|
|
6830
|
+
server.tool(
|
|
6831
|
+
"stop_dev_script",
|
|
6832
|
+
"Stop a running script for a thread (all scripts if name omitted)",
|
|
6833
|
+
{
|
|
6834
|
+
ref: z.string(),
|
|
6835
|
+
name: z.string().optional()
|
|
6836
|
+
},
|
|
6837
|
+
async ({ ref, name }) => {
|
|
6838
|
+
orch.stopDev(ref, name);
|
|
6839
|
+
return { content: [{ type: "text", text: "ok" }] };
|
|
6840
|
+
}
|
|
6841
|
+
);
|
|
6842
|
+
server.tool(
|
|
6843
|
+
"run_setup",
|
|
6844
|
+
"Re-run workspace setup (Sideboard/Conductor settings or .cursor/worktrees.json)",
|
|
6845
|
+
{ ref: z.string() },
|
|
6846
|
+
async ({ ref }) => {
|
|
6847
|
+
const result = await orch.runSetup(ref);
|
|
6848
|
+
return {
|
|
6849
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
6850
|
+
};
|
|
6851
|
+
}
|
|
6852
|
+
);
|
|
6853
|
+
server.tool(
|
|
6854
|
+
"add_workspace",
|
|
6855
|
+
"Register a git repo as a Sideboard workspace",
|
|
6856
|
+
{ repoPath: z.string() },
|
|
6857
|
+
async ({ repoPath }) => {
|
|
6858
|
+
const ws = await orch.addWorkspace(repoPath);
|
|
6859
|
+
return { content: [{ type: "text", text: JSON.stringify(ws) }] };
|
|
6860
|
+
}
|
|
6861
|
+
);
|
|
6862
|
+
server.tool(
|
|
6863
|
+
"remove_workspace",
|
|
6864
|
+
"Unregister a Sideboard workspace (does not archive threads)",
|
|
6865
|
+
{ repoPath: z.string() },
|
|
6866
|
+
async ({ repoPath }) => {
|
|
6867
|
+
orch.removeWorkspace(repoPath);
|
|
6868
|
+
return { content: [{ type: "text", text: "ok" }] };
|
|
6869
|
+
}
|
|
6870
|
+
);
|
|
6871
|
+
server.tool(
|
|
6872
|
+
"fanout",
|
|
6873
|
+
"Best-of-n: create one thread per agent with the same prompt (parallel attempts)",
|
|
6874
|
+
{
|
|
6875
|
+
prompt: z.string(),
|
|
6876
|
+
agents: z.array(z.enum(["claude", "codex", "opencode", "brightsy", "cursor"])),
|
|
6877
|
+
repoPath: z.string(),
|
|
6878
|
+
sourceType: z.enum(["branch", "pr", "ticket"]).optional(),
|
|
6879
|
+
sourceRef: z.string().optional(),
|
|
6880
|
+
title: z.string().optional()
|
|
6881
|
+
},
|
|
6882
|
+
async (args) => {
|
|
6883
|
+
const threads = await orch.bestOfN(args);
|
|
6884
|
+
return {
|
|
6885
|
+
content: [
|
|
6886
|
+
{
|
|
6887
|
+
type: "text",
|
|
6888
|
+
text: JSON.stringify(
|
|
6889
|
+
threads.map((t) => ({
|
|
6945
6890
|
id: t.id,
|
|
6946
|
-
|
|
6891
|
+
agent: t.agent,
|
|
6947
6892
|
branchName: t.branchName,
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6893
|
+
worktreePath: t.worktreePath
|
|
6894
|
+
})),
|
|
6895
|
+
null,
|
|
6896
|
+
2
|
|
6897
|
+
)
|
|
6898
|
+
}
|
|
6899
|
+
]
|
|
6900
|
+
};
|
|
6901
|
+
}
|
|
6902
|
+
);
|
|
6903
|
+
server.tool(
|
|
6904
|
+
"list_branches",
|
|
6905
|
+
"List git branches in a registered workspace. Pass repoPath from list_workspaces (unmerged into the default branch by default \u2014 for create_thread sourceType=branch).",
|
|
6906
|
+
{
|
|
6907
|
+
repoPath: z.string(),
|
|
6908
|
+
unmergedOnly: z.boolean().optional()
|
|
6909
|
+
},
|
|
6910
|
+
async ({ repoPath, unmergedOnly }) => {
|
|
6911
|
+
const root = await resolveRepoRoot(repoPath);
|
|
6912
|
+
const branches = await listBranches(root, {
|
|
6913
|
+
unmergedOnly: unmergedOnly !== false
|
|
6914
|
+
});
|
|
6915
|
+
return {
|
|
6916
|
+
content: [
|
|
6917
|
+
{
|
|
6918
|
+
type: "text",
|
|
6919
|
+
text: branches.map((b) => `${b.current ? "*" : " "} ${b.name}`).join("\n")
|
|
6920
|
+
}
|
|
6921
|
+
]
|
|
6922
|
+
};
|
|
6923
|
+
}
|
|
6924
|
+
);
|
|
6925
|
+
server.tool(
|
|
6926
|
+
"list_prs",
|
|
6927
|
+
"List open GitHub PRs for a registered workspace. Pass repoPath from list_workspaces (uses gh against that repo remote). Then create_thread with sourceType=pr.",
|
|
6928
|
+
{ repoPath: z.string() },
|
|
6929
|
+
async ({ repoPath }) => {
|
|
6930
|
+
const root = await resolveRepoRoot(repoPath);
|
|
6931
|
+
const prs = await listPrs(root);
|
|
6932
|
+
return {
|
|
6933
|
+
content: [
|
|
6934
|
+
{
|
|
6935
|
+
type: "text",
|
|
6936
|
+
text: prs.map(
|
|
6937
|
+
(p) => `#${p.number} ${p.title} (${p.headRefName})${p.isCrossRepository ? " [fork]" : ""}`
|
|
6938
|
+
).join("\n")
|
|
6939
|
+
}
|
|
6940
|
+
]
|
|
6941
|
+
};
|
|
6942
|
+
}
|
|
6943
|
+
);
|
|
6944
|
+
server.tool(
|
|
6945
|
+
"get_pr_stack",
|
|
6946
|
+
"Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before mergePr on stacked PRs.",
|
|
6947
|
+
{ ref: z.string() },
|
|
6948
|
+
async ({ ref }) => {
|
|
6949
|
+
const stack = await orch.getPrStack(ref);
|
|
6950
|
+
return {
|
|
6951
|
+
content: [{ type: "text", text: JSON.stringify(stack, null, 2) }]
|
|
6952
|
+
};
|
|
6953
|
+
}
|
|
6954
|
+
);
|
|
6955
|
+
server.tool(
|
|
6956
|
+
"open_pr_stack_layers",
|
|
6957
|
+
"Materialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.",
|
|
6958
|
+
{
|
|
6959
|
+
ref: z.string(),
|
|
6960
|
+
layer: z.number().int().positive().optional()
|
|
6961
|
+
},
|
|
6962
|
+
async ({ ref, layer }) => {
|
|
6963
|
+
const result = await orch.openPrStackLayers(ref, { layer });
|
|
6964
|
+
return {
|
|
6965
|
+
content: [
|
|
6966
|
+
{
|
|
6967
|
+
type: "text",
|
|
6968
|
+
text: JSON.stringify(
|
|
6969
|
+
{
|
|
6970
|
+
stackNumber: result.stack.stackNumber,
|
|
6971
|
+
trunk: result.stack.trunk,
|
|
6972
|
+
threads: result.threads.map((t) => ({
|
|
6973
|
+
id: t.id,
|
|
6974
|
+
title: t.title,
|
|
6975
|
+
branchName: t.branchName,
|
|
6976
|
+
stackLayer: t.stackLayer,
|
|
6977
|
+
worktreePath: t.worktreePath,
|
|
6978
|
+
prUrl: t.prUrl,
|
|
6979
|
+
link: `sideboard://thread/${t.id}`
|
|
6980
|
+
}))
|
|
6981
|
+
},
|
|
6982
|
+
null,
|
|
6983
|
+
2
|
|
6984
|
+
)
|
|
6985
|
+
}
|
|
6986
|
+
]
|
|
6987
|
+
};
|
|
6988
|
+
}
|
|
6989
|
+
);
|
|
6990
|
+
server.tool(
|
|
6991
|
+
"add_stack_layer",
|
|
6992
|
+
"Add a branch on top of the current stack (`gh stack add`) and open a worktree+thread for it.",
|
|
6993
|
+
{
|
|
6994
|
+
ref: z.string(),
|
|
6995
|
+
branchName: z.string(),
|
|
6996
|
+
title: z.string().optional()
|
|
6997
|
+
},
|
|
6998
|
+
async ({ ref, branchName, title }) => {
|
|
6999
|
+
const result = await orch.addStackLayer(ref, branchName, { title });
|
|
7000
|
+
return {
|
|
7001
|
+
content: [
|
|
7002
|
+
{
|
|
7003
|
+
type: "text",
|
|
7004
|
+
text: JSON.stringify(
|
|
7005
|
+
{
|
|
7006
|
+
id: result.thread.id,
|
|
7007
|
+
title: result.thread.title,
|
|
7008
|
+
branchName: result.thread.branchName,
|
|
7009
|
+
stackLayer: result.thread.stackLayer,
|
|
7010
|
+
worktreePath: result.thread.worktreePath,
|
|
7011
|
+
link: `sideboard://thread/${result.thread.id}`
|
|
7012
|
+
},
|
|
7013
|
+
null,
|
|
7014
|
+
2
|
|
7015
|
+
)
|
|
7016
|
+
}
|
|
7017
|
+
]
|
|
7018
|
+
};
|
|
7019
|
+
}
|
|
7020
|
+
);
|
|
7021
|
+
server.tool(
|
|
7022
|
+
"create_pr_stack",
|
|
7023
|
+
"Create a new GitHub PR stack with one Sideboard worktree per layer (bottom\u2192top branch names). Requires `gh extension install github/gh-stack`.",
|
|
7024
|
+
{
|
|
7025
|
+
repoPath: z.string(),
|
|
7026
|
+
branches: z.array(z.string()).min(1),
|
|
7027
|
+
agent: z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
|
|
7028
|
+
base: z.string().optional(),
|
|
7029
|
+
title: z.string().optional()
|
|
7030
|
+
},
|
|
7031
|
+
async (args) => {
|
|
7032
|
+
const result = await orch.createPrStack({
|
|
7033
|
+
repoPath: args.repoPath,
|
|
7034
|
+
branches: args.branches,
|
|
7035
|
+
agent: args.agent,
|
|
7036
|
+
base: args.base,
|
|
7037
|
+
title: args.title
|
|
7038
|
+
});
|
|
7039
|
+
return {
|
|
7040
|
+
content: [
|
|
7041
|
+
{
|
|
7042
|
+
type: "text",
|
|
7043
|
+
text: JSON.stringify(
|
|
7044
|
+
{
|
|
7045
|
+
stackNumber: result.stack.stackNumber,
|
|
7046
|
+
trunk: result.stack.trunk,
|
|
7047
|
+
threads: result.threads.map((t) => ({
|
|
7048
|
+
id: t.id,
|
|
7049
|
+
title: t.title,
|
|
7050
|
+
branchName: t.branchName,
|
|
7051
|
+
stackLayer: t.stackLayer,
|
|
7052
|
+
worktreePath: t.worktreePath,
|
|
7053
|
+
link: `sideboard://thread/${t.id}`
|
|
7054
|
+
}))
|
|
7055
|
+
},
|
|
7056
|
+
null,
|
|
7057
|
+
2
|
|
7058
|
+
)
|
|
7059
|
+
}
|
|
7060
|
+
]
|
|
7061
|
+
};
|
|
7062
|
+
}
|
|
7063
|
+
);
|
|
7064
|
+
server.tool(
|
|
7065
|
+
"list_issues",
|
|
7066
|
+
"List issues from Sideboard Account connections (Linear API or GitHub Issues; Linear\u2192GitHub fallback when Linear is not connected). Pass repoPath from list_workspaces \u2014 GitHub Issues are scoped to that repo. Then create_thread with sourceType=ticket.",
|
|
7067
|
+
{ repoPath: z.string() },
|
|
7068
|
+
async ({ repoPath }) => {
|
|
7069
|
+
const root = await resolveRepoRoot(repoPath);
|
|
7070
|
+
const result = await listIssues(root);
|
|
7071
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
7072
|
+
}
|
|
7073
|
+
);
|
|
7074
|
+
server.tool(
|
|
7075
|
+
"list_linear_issues",
|
|
7076
|
+
"Deprecated: prefer list_issues. Lists assigned Linear issues via the chosen agent MCP connector",
|
|
7077
|
+
{
|
|
7078
|
+
agent: z.enum(["claude", "codex", "opencode"]),
|
|
7079
|
+
repoPath: z.string()
|
|
7080
|
+
},
|
|
7081
|
+
async ({ agent, repoPath }) => {
|
|
7082
|
+
const issues = await listLinearIssues(agent, repoPath);
|
|
7083
|
+
return { content: [{ type: "text", text: JSON.stringify(issues, null, 2) }] };
|
|
7084
|
+
}
|
|
7085
|
+
);
|
|
7086
|
+
}
|
|
6983
7087
|
const transport = new StdioServerTransport();
|
|
6984
7088
|
await server.connect(transport);
|
|
6985
7089
|
}
|
|
@@ -7345,6 +7449,7 @@ export {
|
|
|
7345
7449
|
REVIEW_REQUEST_PREFILL,
|
|
7346
7450
|
SIDEBOARD_FORCE_STOP,
|
|
7347
7451
|
SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
7452
|
+
SIDEBOARD_MCP_PROFILE_ENV,
|
|
7348
7453
|
THINKING_EFFORTS,
|
|
7349
7454
|
addPrStackLayer,
|
|
7350
7455
|
addStackLayerFromThread,
|
|
@@ -7367,6 +7472,7 @@ export {
|
|
|
7367
7472
|
attachmentsFromBuffers,
|
|
7368
7473
|
attachmentsFromWorktreePaths,
|
|
7369
7474
|
attachmentsGitignoreBody,
|
|
7475
|
+
autoArchiveOnMergeEnabled,
|
|
7370
7476
|
autoCleanupOrphansEnabled,
|
|
7371
7477
|
autoRenameBranchEnabled,
|
|
7372
7478
|
autoRunAfterSetupEnabled,
|
|
@@ -7375,6 +7481,7 @@ export {
|
|
|
7375
7481
|
brightsyCloudConnectAgent,
|
|
7376
7482
|
brightsyCloudConnectEnabled,
|
|
7377
7483
|
brightsyConfigPath,
|
|
7484
|
+
brightsyInjectWorktreeMcpEnabled,
|
|
7378
7485
|
brightsyMcpAllowedTools,
|
|
7379
7486
|
brightsyMcpServerName,
|
|
7380
7487
|
buildCachedUserContent,
|
|
@@ -7426,7 +7533,9 @@ export {
|
|
|
7426
7533
|
detectLocalMergeConflicts,
|
|
7427
7534
|
disconnectBrightsyTeam,
|
|
7428
7535
|
discoverSkills,
|
|
7536
|
+
dropCachedPrefixOnResume,
|
|
7429
7537
|
encodeBrightsyTarget,
|
|
7538
|
+
enrichPathWithNpmGlobalBin,
|
|
7430
7539
|
enrichWorkspacesWithGithub,
|
|
7431
7540
|
ensureAgentPath,
|
|
7432
7541
|
ensureCloudCoordinator,
|
|
@@ -7464,6 +7573,7 @@ export {
|
|
|
7464
7573
|
formatTranscriptMarkdown,
|
|
7465
7574
|
formatWorkspaceInventory,
|
|
7466
7575
|
formatWorktreeDirective,
|
|
7576
|
+
formatWorktreeReminder,
|
|
7467
7577
|
getAdapter,
|
|
7468
7578
|
getAgentSetupInfo,
|
|
7469
7579
|
getBrightsySession,
|
|
@@ -7590,7 +7700,10 @@ export {
|
|
|
7590
7700
|
pastedTextStats,
|
|
7591
7701
|
permissionMode,
|
|
7592
7702
|
planFileAbs,
|
|
7703
|
+
posixShellSingleQuote,
|
|
7704
|
+
prepareTerminalCommand,
|
|
7593
7705
|
previewLand,
|
|
7706
|
+
promptMentionsBrightsy,
|
|
7594
7707
|
pushBranch,
|
|
7595
7708
|
readExistingReviewRequestFile,
|
|
7596
7709
|
readPlanFile,
|
|
@@ -7606,7 +7719,9 @@ export {
|
|
|
7606
7719
|
requestReview,
|
|
7607
7720
|
requireAgent,
|
|
7608
7721
|
resetGhStackDetectCache,
|
|
7722
|
+
resolveAgentExecutable,
|
|
7609
7723
|
resolveClaudeExecutable,
|
|
7724
|
+
resolveCommandBinarySync,
|
|
7610
7725
|
resolveConductorCursorAgentId,
|
|
7611
7726
|
resolveCursorModelId,
|
|
7612
7727
|
resolveDefaultBranch,
|
|
@@ -7615,6 +7730,7 @@ export {
|
|
|
7615
7730
|
resolveFilesToCopy,
|
|
7616
7731
|
resolveGhAuthToken,
|
|
7617
7732
|
resolveGithubRepoSlug,
|
|
7733
|
+
resolveLoginCommand,
|
|
7618
7734
|
resolveNewThreadOptions,
|
|
7619
7735
|
resolvePlanMarkdown,
|
|
7620
7736
|
resolvePrSelector,
|
|
@@ -7636,9 +7752,11 @@ export {
|
|
|
7636
7752
|
settingsSourceLabel,
|
|
7637
7753
|
shouldAttachPastedText,
|
|
7638
7754
|
shouldCompactContext,
|
|
7755
|
+
shouldInjectBrightsyMcp,
|
|
7639
7756
|
shouldRefreshReviewRequestTemplate,
|
|
7640
7757
|
shouldRunWorktreeCleanup,
|
|
7641
7758
|
sideboardHomeDir,
|
|
7759
|
+
sideboardMcpProfile,
|
|
7642
7760
|
sideboardReposDir,
|
|
7643
7761
|
sideboardWorkspacesDir,
|
|
7644
7762
|
slugify,
|
|
@@ -7666,6 +7784,7 @@ export {
|
|
|
7666
7784
|
threadDisplayLabel,
|
|
7667
7785
|
threadFilePath,
|
|
7668
7786
|
threadLockPath,
|
|
7787
|
+
threadRequestsBrightsyMcp,
|
|
7669
7788
|
threadsDir,
|
|
7670
7789
|
threadsSharingWorktree,
|
|
7671
7790
|
toolDescription,
|
|
@@ -7673,14 +7792,18 @@ export {
|
|
|
7673
7792
|
toolFilePath,
|
|
7674
7793
|
totalTokens,
|
|
7675
7794
|
updateAdvancedSettings,
|
|
7795
|
+
updateAgentExecutable,
|
|
7676
7796
|
updateAppEnvironment,
|
|
7677
7797
|
updateBrightsySettings,
|
|
7678
7798
|
updateClaudeSettings,
|
|
7799
|
+
updateCodexSettings,
|
|
7679
7800
|
updateDefaultsSettings,
|
|
7680
7801
|
updateIntegrationsSettings,
|
|
7802
|
+
updateOpencodeSettings,
|
|
7681
7803
|
updateThread,
|
|
7682
7804
|
validateLinearApiKey,
|
|
7683
7805
|
withAgentInstructions,
|
|
7806
|
+
withExportedPath,
|
|
7684
7807
|
withThreadLock,
|
|
7685
7808
|
workspaceSettingsSourceLabel,
|
|
7686
7809
|
worktreeCleanupSettings,
|