@sideboard-ai/core 0.1.89 → 0.1.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/cursor-runner.cjs +129 -14
- package/dist/agents/cursor-runner.js +4 -1
- package/dist/{agents-LMUFTGKF.js → agents-HBLA6FEV.js} +4 -4
- package/dist/{agents-ODBP7J6E.js → agents-WS5QV6LE.js} +5 -5
- package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
- package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
- package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
- package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
- package/dist/{chunk-RJLBSYUO.js → chunk-KWNUZ4LR.js} +46 -77
- package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
- package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
- package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
- package/dist/{chunk-JE75QW2I.js → chunk-WBX46OPD.js} +237 -96
- package/dist/{chunk-OB6IRIFV.js → chunk-XH2GS2LO.js} +2 -2
- package/dist/{chunk-VZ2L4AEJ.js → chunk-XUWDLRAE.js} +2 -2
- package/dist/{coordinator-prompt-UK5LYFN5.js → coordinator-prompt-AKEY4WSO.js} +2 -2
- package/dist/{coordinator-prompt-CI5SHONJ.js → coordinator-prompt-OQOOD5ET.js} +2 -2
- package/dist/{global-workspace-2YZ2V4I5.js → global-workspace-3GNPQCLE.js} +3 -3
- package/dist/{global-workspace-JQQLPJM5.js → global-workspace-M3OMVDDH.js} +3 -3
- package/dist/index.cjs +1021 -473
- package/dist/index.d.cts +91 -20
- package/dist/index.d.ts +91 -20
- package/dist/index.js +244 -59
- package/dist/mcp/run-stdio.cjs +816 -428
- package/dist/mcp/run-stdio.js +77 -40
- package/dist/{workspaces-YWCC3WV4.js → workspaces-ERZC7ULY.js} +4 -4
- package/dist/{workspaces-FDO5L4NI.js → workspaces-J4WG6UFR.js} +4 -4
- package/dist/{worktree-7YNSJ224.js → worktree-DA4BOV7G.js} +7 -1
- package/dist/{worktree-4555QBQ7.js → worktree-EO5QAGJU.js} +7 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listWorkspaces,
|
|
5
5
|
removeWorkspace,
|
|
6
6
|
syncWorkspacesFromThreads
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QKYO6BHB.js";
|
|
8
8
|
import {
|
|
9
9
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
10
10
|
CLAUDE_MODEL_CATALOG,
|
|
@@ -58,13 +58,14 @@ import {
|
|
|
58
58
|
resolveCursorModelId,
|
|
59
59
|
resolveLoginCommand,
|
|
60
60
|
resolveQuotaFallbackAgent,
|
|
61
|
+
resolveSideboardMcpServer,
|
|
61
62
|
sanitizeMcpServerName,
|
|
62
63
|
shouldInjectBrightsyMcp,
|
|
63
64
|
sideboardMcpProfile,
|
|
64
65
|
threadRequestsBrightsyMcp,
|
|
65
66
|
totalTokens,
|
|
66
67
|
writeInjectedMcpConfig
|
|
67
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-KWNUZ4LR.js";
|
|
68
69
|
import {
|
|
69
70
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
70
71
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -91,7 +92,7 @@ import {
|
|
|
91
92
|
parseForceStopMessage,
|
|
92
93
|
slackCoordinatorSourceRef,
|
|
93
94
|
takenTeamSlugsForOrchestration
|
|
94
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-CLGO7TLO.js";
|
|
95
96
|
import {
|
|
96
97
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
97
98
|
SLACK_REPLY_FORMATTING,
|
|
@@ -100,7 +101,7 @@ import {
|
|
|
100
101
|
enrichWorkspacesWithGithub,
|
|
101
102
|
ensureGlobalCoordinatorCwd,
|
|
102
103
|
formatWorkspaceInventory
|
|
103
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-XUWDLRAE.js";
|
|
104
105
|
import {
|
|
105
106
|
brightsyConfigPath,
|
|
106
107
|
brightsyMcpServerName,
|
|
@@ -137,7 +138,7 @@ import {
|
|
|
137
138
|
parseCursorRunnerLine,
|
|
138
139
|
pushTurnStderr,
|
|
139
140
|
summarizeTurnStderr
|
|
140
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-GXSYI7FH.js";
|
|
141
142
|
import {
|
|
142
143
|
caffeinateHoldPath,
|
|
143
144
|
getCaffeinateHold,
|
|
@@ -154,6 +155,7 @@ import {
|
|
|
154
155
|
applyGithubGitAuthEnv,
|
|
155
156
|
branchDisplayLabel,
|
|
156
157
|
checkoutPrStackLayer,
|
|
158
|
+
codexSandboxWritableRootsArgs,
|
|
157
159
|
codexUnattendedGitConfigArgs,
|
|
158
160
|
collectTakenTeamSlugs,
|
|
159
161
|
commitAll,
|
|
@@ -174,12 +176,14 @@ import {
|
|
|
174
176
|
getPr,
|
|
175
177
|
getPrChecks,
|
|
176
178
|
getPrDetails,
|
|
179
|
+
getPrForHeadBranch,
|
|
177
180
|
getPrMeta,
|
|
178
181
|
getPrStack,
|
|
179
182
|
ghHeadRef,
|
|
180
183
|
ghRepoSelectArgs,
|
|
181
184
|
githubAgentGitEnv,
|
|
182
185
|
initPrStack,
|
|
186
|
+
isDefaultishSourceRef,
|
|
183
187
|
isDirty,
|
|
184
188
|
isGhRateLimitError,
|
|
185
189
|
isInPrStack,
|
|
@@ -190,6 +194,7 @@ import {
|
|
|
190
194
|
listPrs,
|
|
191
195
|
listWorktrees,
|
|
192
196
|
lookupSoccerTeam,
|
|
197
|
+
mergeAgentGitAuthEnv,
|
|
193
198
|
mergePr,
|
|
194
199
|
mergePrStack,
|
|
195
200
|
nonInteractiveGitProcessEnv,
|
|
@@ -200,24 +205,29 @@ import {
|
|
|
200
205
|
pushBranch,
|
|
201
206
|
removeWorktree,
|
|
202
207
|
resetGhStackDetectCache,
|
|
208
|
+
resetGithubAgentTokenMemo,
|
|
203
209
|
resolveAgentGitAuthEnv,
|
|
210
|
+
resolveCodexGitWritableRoots,
|
|
204
211
|
resolveDefaultBranch,
|
|
205
212
|
resolveDiffBaseRef,
|
|
206
213
|
resolveGithubAgentToken,
|
|
207
214
|
resolveGithubRepoSlug,
|
|
208
215
|
resolvePrSelector,
|
|
216
|
+
resolvePrSelectors,
|
|
209
217
|
resolveRepoRoot,
|
|
210
218
|
resolveWorktreeStartPoint,
|
|
219
|
+
scrubGithubTokensFromChildEnv,
|
|
211
220
|
slugify,
|
|
212
221
|
stackMergeReadiness,
|
|
213
222
|
submitPrStack,
|
|
214
223
|
suggestSlug,
|
|
215
224
|
takenSlugsFromThread,
|
|
216
225
|
threadDisplayLabel,
|
|
226
|
+
warmGithubAgentAuth,
|
|
217
227
|
worktreeDisplayLabel,
|
|
218
228
|
worktreeDisplayLabelForGroup,
|
|
219
229
|
worktreeNameFromPath
|
|
220
|
-
} from "./chunk-
|
|
230
|
+
} from "./chunk-CIRXAYWS.js";
|
|
221
231
|
import {
|
|
222
232
|
ATTACHMENTS_DIR,
|
|
223
233
|
LEGACY_ATTACHMENTS_DIR,
|
|
@@ -1328,9 +1338,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
1328
1338
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
1329
1339
|
);
|
|
1330
1340
|
}
|
|
1331
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
1341
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-M3OMVDDH.js");
|
|
1332
1342
|
if (isGlobalThread2(thread)) {
|
|
1333
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
1343
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-AKEY4WSO.js");
|
|
1334
1344
|
ensureGlobalCoordinatorCwd2(
|
|
1335
1345
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
1336
1346
|
);
|
|
@@ -1348,10 +1358,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
1348
1358
|
const env = childEnvWithAppSettings(cmd.env);
|
|
1349
1359
|
try {
|
|
1350
1360
|
if (isOrchestratorThread(thread)) {
|
|
1351
|
-
|
|
1361
|
+
mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
|
|
1352
1362
|
} else {
|
|
1353
|
-
|
|
1354
|
-
Object.assign(env, originEnv);
|
|
1363
|
+
mergeAgentGitAuthEnv(env, await originGhRepoEnv(thread.worktreePath, { env }));
|
|
1355
1364
|
}
|
|
1356
1365
|
} catch (err) {
|
|
1357
1366
|
const detail = err instanceof Error ? err.message : String(err);
|
|
@@ -1574,9 +1583,10 @@ function formatArtifactDirective() {
|
|
|
1574
1583
|
"Files / media browser (CMS file manager column):",
|
|
1575
1584
|
"4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
|
|
1576
1585
|
" Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
|
|
1577
|
-
"Multiple-choice questions
|
|
1578
|
-
"5) Call Sideboard MCP `ask_user` when
|
|
1579
|
-
"
|
|
1586
|
+
"Multiple-choice questions:",
|
|
1587
|
+
"5) Call Sideboard MCP `ask_user` only when work is blocked on choosing among a few concrete options (approach forks, which API, auth vs cookies). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. If you are asking a real multiple-choice, use ask_user rather than chat bullets so Sideboard shows the composer picker.",
|
|
1588
|
+
"Do not call ask_user for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat. If one option is the obvious default, proceed without asking.",
|
|
1589
|
+
"Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
|
|
1580
1590
|
].join("\n");
|
|
1581
1591
|
}
|
|
1582
1592
|
function formatUiReminder() {
|
|
@@ -1587,7 +1597,7 @@ function formatUiReminder() {
|
|
|
1587
1597
|
"CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
|
|
1588
1598
|
"Files column: MCP present_files (brightsy account storage or memory).",
|
|
1589
1599
|
"Do not say artifacts/CMS UI are unavailable.",
|
|
1590
|
-
"
|
|
1600
|
+
"ask_user: only when blocked on a real multiple-choice (approach fork, which API). Never for hellos, check-ins, or \u201Cwhat next?\u201D menus \u2014 reply in chat."
|
|
1591
1601
|
].join(" ");
|
|
1592
1602
|
}
|
|
1593
1603
|
var FILES_BY_AGENT = {
|
|
@@ -1874,7 +1884,10 @@ async function spawnWorkspaceScript(command, opts) {
|
|
|
1874
1884
|
loginEnv
|
|
1875
1885
|
);
|
|
1876
1886
|
try {
|
|
1877
|
-
|
|
1887
|
+
mergeAgentGitAuthEnv(
|
|
1888
|
+
env,
|
|
1889
|
+
await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath })
|
|
1890
|
+
);
|
|
1878
1891
|
} catch {
|
|
1879
1892
|
}
|
|
1880
1893
|
const shell = process.platform === "darwin" ? "zsh" : "bash";
|
|
@@ -3759,6 +3772,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3759
3772
|
let sourceRef = input.sourceRef;
|
|
3760
3773
|
let sourceIsFork = false;
|
|
3761
3774
|
let prUrl = null;
|
|
3775
|
+
let prTitle = null;
|
|
3762
3776
|
if (input.sourceType === "pr") {
|
|
3763
3777
|
const num = Number(input.sourceRef.replace(/^#/, ""));
|
|
3764
3778
|
if (!Number.isFinite(num)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
|
|
@@ -3774,6 +3788,12 @@ async function createThread(input, _onSetupLine) {
|
|
|
3774
3788
|
} else if (input.sourceType === "branch") {
|
|
3775
3789
|
if (!sourceRef || sourceRef === "HEAD" || sourceRef === "default") {
|
|
3776
3790
|
sourceRef = await resolveDefaultBranch(repoPath);
|
|
3791
|
+
} else {
|
|
3792
|
+
const existing = await getPrForHeadBranch(repoPath, sourceRef);
|
|
3793
|
+
if (existing?.url) {
|
|
3794
|
+
prUrl = existing.url;
|
|
3795
|
+
prTitle = existing.title;
|
|
3796
|
+
}
|
|
3777
3797
|
}
|
|
3778
3798
|
} else if (input.sourceType === "adopt") {
|
|
3779
3799
|
throw new Error("Use adoptThread() for adopt sources");
|
|
@@ -3804,14 +3824,15 @@ async function createThread(input, _onSetupLine) {
|
|
|
3804
3824
|
sourceIsFork,
|
|
3805
3825
|
parentThreadId: input.parentThreadId ?? null,
|
|
3806
3826
|
status: "idle",
|
|
3807
|
-
prUrl
|
|
3827
|
+
prUrl,
|
|
3828
|
+
prTitle
|
|
3808
3829
|
});
|
|
3809
3830
|
writeThread(thread);
|
|
3810
3831
|
await ensureWorkspace(repoPath);
|
|
3811
3832
|
return readThread(thread.id) ?? thread;
|
|
3812
3833
|
}
|
|
3813
3834
|
async function listLinearIssues(agent, repoPath) {
|
|
3814
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3835
|
+
const { getAdapter: getAdapter2 } = await import("./agents-WS5QV6LE.js");
|
|
3815
3836
|
await requireAgent(agent, { requireLinear: true });
|
|
3816
3837
|
const adapter = getAdapter2(agent);
|
|
3817
3838
|
if (!adapter.listLinearIssues) {
|
|
@@ -4277,7 +4298,7 @@ import {
|
|
|
4277
4298
|
} from "fs";
|
|
4278
4299
|
import { tmpdir } from "os";
|
|
4279
4300
|
import { join as join6 } from "path";
|
|
4280
|
-
import
|
|
4301
|
+
import { createRequire } from "module";
|
|
4281
4302
|
var CONDUCTOR_APP_SUPPORT = join6(
|
|
4282
4303
|
process.env.HOME ?? "",
|
|
4283
4304
|
"Library",
|
|
@@ -4286,6 +4307,11 @@ var CONDUCTOR_APP_SUPPORT = join6(
|
|
|
4286
4307
|
);
|
|
4287
4308
|
var CONDUCTOR_DB = join6(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
4288
4309
|
var CURSOR_SDK_STORE = join6(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
4310
|
+
function openReadonlySqlite(file) {
|
|
4311
|
+
const req = createRequire(import.meta.url);
|
|
4312
|
+
const Database = req("better-sqlite3");
|
|
4313
|
+
return new Database(file, { readonly: true, fileMustExist: true });
|
|
4314
|
+
}
|
|
4289
4315
|
function mapAgentType(raw) {
|
|
4290
4316
|
if (!raw) return null;
|
|
4291
4317
|
const v = raw.toLowerCase();
|
|
@@ -4354,7 +4380,7 @@ async function adoptThread(input) {
|
|
|
4354
4380
|
messages: input.messages ?? []
|
|
4355
4381
|
});
|
|
4356
4382
|
writeThread(thread);
|
|
4357
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4383
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-ERZC7ULY.js");
|
|
4358
4384
|
await ensureWorkspace2(repoPath);
|
|
4359
4385
|
return thread;
|
|
4360
4386
|
}
|
|
@@ -4378,7 +4404,7 @@ function listConductorWorkspaces() {
|
|
|
4378
4404
|
}
|
|
4379
4405
|
}
|
|
4380
4406
|
}
|
|
4381
|
-
const db =
|
|
4407
|
+
const db = openReadonlySqlite(snapshot);
|
|
4382
4408
|
try {
|
|
4383
4409
|
const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all();
|
|
4384
4410
|
const names = new Set(tables.map((t) => t.name));
|
|
@@ -4469,7 +4495,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
4469
4495
|
}
|
|
4470
4496
|
}
|
|
4471
4497
|
}
|
|
4472
|
-
const db =
|
|
4498
|
+
const db = openReadonlySqlite(snapshot);
|
|
4473
4499
|
try {
|
|
4474
4500
|
const row = db.prepare(
|
|
4475
4501
|
`SELECT
|
|
@@ -6948,8 +6974,9 @@ var Orchestrator = class {
|
|
|
6948
6974
|
return result;
|
|
6949
6975
|
}
|
|
6950
6976
|
async mergePr(threadRef) {
|
|
6951
|
-
const { thread,
|
|
6977
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
6952
6978
|
this.assertNotGlobal(thread, "Merge PR");
|
|
6979
|
+
const selector = selectors[0];
|
|
6953
6980
|
if (!selector) throw new Error("No pull request linked to this thread");
|
|
6954
6981
|
const result = await mergePr(cwd, selector);
|
|
6955
6982
|
const state = normalizePrState(result.state) || "MERGED";
|
|
@@ -6969,29 +6996,34 @@ var Orchestrator = class {
|
|
|
6969
6996
|
await this.persistPrMetaAndMaybeArchive(thread, metaLike);
|
|
6970
6997
|
return { url: metaLike.url, state };
|
|
6971
6998
|
}
|
|
6972
|
-
/** Resolve PR
|
|
6999
|
+
/** Resolve PR selectors and optionally persist `prUrl` when found. */
|
|
6973
7000
|
async withPrSelector(threadRef) {
|
|
6974
7001
|
const thread = this.requireThread(threadRef);
|
|
6975
|
-
const
|
|
7002
|
+
const selectors = resolvePrSelectors(thread);
|
|
6976
7003
|
const cwd = thread.worktreePath;
|
|
6977
7004
|
if (!cwd?.trim()) {
|
|
6978
7005
|
throw new Error(`Thread ${threadRef} has no worktreePath`);
|
|
6979
7006
|
}
|
|
6980
|
-
return { thread,
|
|
7007
|
+
return { thread, selectors, cwd };
|
|
6981
7008
|
}
|
|
6982
7009
|
async getPrChecks(threadRef) {
|
|
6983
|
-
const {
|
|
6984
|
-
|
|
6985
|
-
|
|
7010
|
+
const { selectors, cwd } = await this.withPrSelector(threadRef);
|
|
7011
|
+
for (const selector of selectors) {
|
|
7012
|
+
const checks = await getPrChecks(cwd, selector);
|
|
7013
|
+
if (checks) return checks;
|
|
7014
|
+
}
|
|
7015
|
+
return null;
|
|
6986
7016
|
}
|
|
6987
7017
|
async getPrMeta(threadRef) {
|
|
6988
|
-
const { thread,
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
7018
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
7019
|
+
for (const selector of selectors) {
|
|
7020
|
+
const meta = await getPrMeta(cwd, selector);
|
|
7021
|
+
if (meta) {
|
|
7022
|
+
await this.persistPrMetaAndMaybeArchive(thread, meta);
|
|
7023
|
+
return meta;
|
|
7024
|
+
}
|
|
6993
7025
|
}
|
|
6994
|
-
return
|
|
7026
|
+
return null;
|
|
6995
7027
|
}
|
|
6996
7028
|
/**
|
|
6997
7029
|
* Persist PR URL/title/state and Conductor-style auto-archive when the PR
|
|
@@ -7115,9 +7147,12 @@ var Orchestrator = class {
|
|
|
7115
7147
|
return { stack: result.stack, threads: result.threads };
|
|
7116
7148
|
}
|
|
7117
7149
|
async getPrDetails(threadRef) {
|
|
7118
|
-
const { thread,
|
|
7119
|
-
|
|
7120
|
-
const
|
|
7150
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
7151
|
+
let details = null;
|
|
7152
|
+
for (const selector of selectors) {
|
|
7153
|
+
details = await getPrDetails(cwd, selector);
|
|
7154
|
+
if (details) break;
|
|
7155
|
+
}
|
|
7121
7156
|
if (details) {
|
|
7122
7157
|
const patch = {};
|
|
7123
7158
|
if (details.url && details.url !== thread.prUrl) patch.prUrl = details.url;
|
|
@@ -7302,7 +7337,7 @@ var Orchestrator = class {
|
|
|
7302
7337
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7303
7338
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7304
7339
|
try {
|
|
7305
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
7340
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-ERZC7ULY.js");
|
|
7306
7341
|
await ensureWorkspace2(thread.repoPath);
|
|
7307
7342
|
} catch {
|
|
7308
7343
|
}
|
|
@@ -7345,7 +7380,7 @@ var Orchestrator = class {
|
|
|
7345
7380
|
return restored2;
|
|
7346
7381
|
}
|
|
7347
7382
|
if (!existsSync14(thread.worktreePath)) {
|
|
7348
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
7383
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-DA4BOV7G.js");
|
|
7349
7384
|
const { execa: execa5 } = await import("execa");
|
|
7350
7385
|
const slug = thread.worktreePath.split("/").pop();
|
|
7351
7386
|
const dest = thread.worktreePath;
|
|
@@ -7454,7 +7489,7 @@ async function startOrchestration(opts) {
|
|
|
7454
7489
|
sourceRef: "default",
|
|
7455
7490
|
...createOpts
|
|
7456
7491
|
}).catch(async () => {
|
|
7457
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
7492
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-DA4BOV7G.js");
|
|
7458
7493
|
const repo = await resolveRepoRoot2(repoPath);
|
|
7459
7494
|
const def = await resolveDefaultBranch2(repo);
|
|
7460
7495
|
return orch.createThread({
|
|
@@ -8205,6 +8240,14 @@ function withTimeout(promise, ms, label) {
|
|
|
8205
8240
|
}
|
|
8206
8241
|
async function startMcpServer() {
|
|
8207
8242
|
const orch = getOrchestrator();
|
|
8243
|
+
try {
|
|
8244
|
+
await warmGithubAgentAuth();
|
|
8245
|
+
} catch (err) {
|
|
8246
|
+
console.error(
|
|
8247
|
+
"[sideboard-mcp] GitHub agent auth warm skipped:",
|
|
8248
|
+
err instanceof Error ? err.message : err
|
|
8249
|
+
);
|
|
8250
|
+
}
|
|
8208
8251
|
try {
|
|
8209
8252
|
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-BRF7VKTQ.js");
|
|
8210
8253
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
@@ -8311,7 +8354,7 @@ async function startMcpServer() {
|
|
|
8311
8354
|
);
|
|
8312
8355
|
server.tool(
|
|
8313
8356
|
"ask_user",
|
|
8314
|
-
"Ask the user clarifying multiple-choice
|
|
8357
|
+
"Ask the user a clarifying multiple-choice question in Sideboard\u2019s composer. Call only when work is blocked on choosing among a few concrete options (approach fork, which API, auth vs cookies). Do not call for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat instead. If one option is the obvious default, proceed without asking. Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. After calling, stop and wait for answers. Not for \u201Cis the plan ready?\u201D.",
|
|
8315
8358
|
{
|
|
8316
8359
|
questions: z3.array(
|
|
8317
8360
|
z3.object({
|
|
@@ -9540,6 +9583,75 @@ async function runCloudConnect(opts) {
|
|
|
9540
9583
|
}
|
|
9541
9584
|
}
|
|
9542
9585
|
|
|
9586
|
+
// src/agents/user-mcp-config.ts
|
|
9587
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "fs";
|
|
9588
|
+
import { homedir as homedir2 } from "os";
|
|
9589
|
+
import { dirname as dirname4, join as join13 } from "path";
|
|
9590
|
+
function userCursorMcpConfigPath() {
|
|
9591
|
+
return join13(homedir2(), ".cursor", "mcp.json");
|
|
9592
|
+
}
|
|
9593
|
+
function userClaudeMcpConfigPath() {
|
|
9594
|
+
return join13(homedir2(), ".claude.json");
|
|
9595
|
+
}
|
|
9596
|
+
function asObject(value) {
|
|
9597
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
9598
|
+
return { ...value };
|
|
9599
|
+
}
|
|
9600
|
+
function stripElectronSpawnEnv(env) {
|
|
9601
|
+
if (!env) return void 0;
|
|
9602
|
+
const next = { ...env };
|
|
9603
|
+
delete next.ELECTRON_RUN_AS_NODE;
|
|
9604
|
+
delete next.ELECTRON_RUN_AS_NODE;
|
|
9605
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
9606
|
+
}
|
|
9607
|
+
function mergeSideboardIntoMcpServersJson(existing, sideboard) {
|
|
9608
|
+
const root = asObject(existing);
|
|
9609
|
+
const servers = asObject(root.mcpServers);
|
|
9610
|
+
const env = stripElectronSpawnEnv(sideboard.env);
|
|
9611
|
+
servers.sideboard = {
|
|
9612
|
+
type: "stdio",
|
|
9613
|
+
command: sideboard.command,
|
|
9614
|
+
...sideboard.args && sideboard.args.length > 0 ? { args: sideboard.args } : {},
|
|
9615
|
+
...env ? { env } : {}
|
|
9616
|
+
};
|
|
9617
|
+
return { ...root, mcpServers: servers };
|
|
9618
|
+
}
|
|
9619
|
+
function writeMergedMcpServersJson(configPath, sideboard) {
|
|
9620
|
+
let existing = {};
|
|
9621
|
+
if (existsSync15(configPath)) {
|
|
9622
|
+
try {
|
|
9623
|
+
existing = JSON.parse(readFileSync10(configPath, "utf8"));
|
|
9624
|
+
} catch {
|
|
9625
|
+
existing = {};
|
|
9626
|
+
}
|
|
9627
|
+
}
|
|
9628
|
+
const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
|
|
9629
|
+
mkdirSync5(dirname4(configPath), { recursive: true });
|
|
9630
|
+
writeFileSync4(configPath, `${JSON.stringify(next, null, 2)}
|
|
9631
|
+
`);
|
|
9632
|
+
}
|
|
9633
|
+
function launchFromResolved(server) {
|
|
9634
|
+
return {
|
|
9635
|
+
command: server.command,
|
|
9636
|
+
args: server.args,
|
|
9637
|
+
env: {
|
|
9638
|
+
...server.env ?? {},
|
|
9639
|
+
SIDEBOARD_APP_DATA: appDataDir()
|
|
9640
|
+
}
|
|
9641
|
+
};
|
|
9642
|
+
}
|
|
9643
|
+
async function registerPackagedUserMcpClients() {
|
|
9644
|
+
const launch = launchFromResolved(await resolveSideboardMcpServer());
|
|
9645
|
+
const cursor = userCursorMcpConfigPath();
|
|
9646
|
+
writeMergedMcpServersJson(cursor, launch);
|
|
9647
|
+
const claude = userClaudeMcpConfigPath();
|
|
9648
|
+
if (existsSync15(claude)) {
|
|
9649
|
+
writeMergedMcpServersJson(claude, launch);
|
|
9650
|
+
return { cursor, claude };
|
|
9651
|
+
}
|
|
9652
|
+
return { cursor };
|
|
9653
|
+
}
|
|
9654
|
+
|
|
9543
9655
|
// src/slack/oauth.ts
|
|
9544
9656
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
9545
9657
|
|
|
@@ -10306,15 +10418,10 @@ function connectSession2(ws, opts, log) {
|
|
|
10306
10418
|
}
|
|
10307
10419
|
|
|
10308
10420
|
// src/slack/listen.ts
|
|
10309
|
-
var SLACK_LISTEN_BUSY_REPLY = [
|
|
10310
|
-
"Sideboard is busy with an in-progress turn.",
|
|
10311
|
-
"I did not start a new request.",
|
|
10312
|
-
'Send "stop" to interrupt, or try again when idle.'
|
|
10313
|
-
].join(" ");
|
|
10314
10421
|
var SLACK_LISTEN_STOPPED_REPLY = "Sideboard stopped the in-progress turn. Send another message when you want to continue.";
|
|
10315
10422
|
var SLACK_LISTEN_TIMEOUT_REPLY = [
|
|
10316
10423
|
"Sideboard timed out waiting for the local agent turn to finish.",
|
|
10317
|
-
'Send
|
|
10424
|
+
'Send another message to interrupt and retry, or send "stop".'
|
|
10318
10425
|
].join(" ");
|
|
10319
10426
|
var handleChain = Promise.resolve();
|
|
10320
10427
|
function enqueueHandle(fn) {
|
|
@@ -10328,6 +10435,30 @@ function enqueueHandle(fn) {
|
|
|
10328
10435
|
function refreshWorkspaces2() {
|
|
10329
10436
|
return getOrchestrator().listWorkspaces();
|
|
10330
10437
|
}
|
|
10438
|
+
function slackInboundSuperseded(opts) {
|
|
10439
|
+
if (opts.inboundGeneration === void 0 || !opts.currentInboundGeneration) {
|
|
10440
|
+
return false;
|
|
10441
|
+
}
|
|
10442
|
+
return opts.currentInboundGeneration() !== opts.inboundGeneration;
|
|
10443
|
+
}
|
|
10444
|
+
function interruptSlackCoordinatorForInbound(msg, agent, log = () => void 0) {
|
|
10445
|
+
const userId = msg.userId?.trim();
|
|
10446
|
+
if (!userId) return false;
|
|
10447
|
+
const coordinator = ensureSlackCoordinator(msg.teamId, userId, agent);
|
|
10448
|
+
const fresh = readThread(coordinator.id) ?? coordinator;
|
|
10449
|
+
if (fresh.status !== "running" && fresh.status !== "queued") return false;
|
|
10450
|
+
try {
|
|
10451
|
+
getOrchestrator().stop(fresh.id, { clearQueue: true });
|
|
10452
|
+
log(
|
|
10453
|
+
`interrupt ${msg.kind} ${msg.ts} \u2192 coordinator ${fresh.id.slice(0, 8)} (${fresh.status})`
|
|
10454
|
+
);
|
|
10455
|
+
return true;
|
|
10456
|
+
} catch (err) {
|
|
10457
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
10458
|
+
log(`interrupt ${msg.ts}: ${errMsg}`);
|
|
10459
|
+
return false;
|
|
10460
|
+
}
|
|
10461
|
+
}
|
|
10331
10462
|
function formatSlackInboundPrompt(msg) {
|
|
10332
10463
|
const kind = msg.kind === "mention" ? "Slack @mention" : "Slack DM";
|
|
10333
10464
|
return `${kind}
|
|
@@ -10458,7 +10589,13 @@ async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
|
10458
10589
|
}
|
|
10459
10590
|
async function handleSlackInbound(msg, opts) {
|
|
10460
10591
|
const log = opts.onLog ?? (() => void 0);
|
|
10461
|
-
|
|
10592
|
+
if (!opts.skipAck) {
|
|
10593
|
+
await ackSlackInboundSeen(msg, opts);
|
|
10594
|
+
}
|
|
10595
|
+
if (slackInboundSuperseded(opts)) {
|
|
10596
|
+
log(`skip superseded ${msg.kind} ${msg.ts}`);
|
|
10597
|
+
return;
|
|
10598
|
+
}
|
|
10462
10599
|
const agent = coerceOrchestratorAgent(opts.agent ?? getDefaultAgent());
|
|
10463
10600
|
const workspaces = refreshWorkspaces2();
|
|
10464
10601
|
for (const ws of workspaces) {
|
|
@@ -10470,25 +10607,31 @@ async function handleSlackInbound(msg, opts) {
|
|
|
10470
10607
|
log(`skip ${msg.kind} ${msg.ts}: missing Slack user id`);
|
|
10471
10608
|
return;
|
|
10472
10609
|
}
|
|
10610
|
+
if (slackInboundSuperseded(opts)) {
|
|
10611
|
+
log(`skip superseded ${msg.kind} ${msg.ts}`);
|
|
10612
|
+
return;
|
|
10613
|
+
}
|
|
10473
10614
|
const coordinator = ensureSlackCoordinator(msg.teamId, userId, agent);
|
|
10474
|
-
|
|
10615
|
+
let fresh = readThread(coordinator.id) ?? coordinator;
|
|
10475
10616
|
if (isSlackStopCommand(msg.text)) {
|
|
10476
10617
|
try {
|
|
10477
|
-
getOrchestrator().stop(fresh.id);
|
|
10618
|
+
getOrchestrator().stop(fresh.id, { clearQueue: true });
|
|
10478
10619
|
log(`stop ${msg.kind} ${msg.ts} \u2192 coordinator ${fresh.id.slice(0, 8)}`);
|
|
10479
10620
|
} catch (err) {
|
|
10480
10621
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
10481
10622
|
log(`stop ${msg.ts}: ${errMsg}`);
|
|
10482
10623
|
}
|
|
10624
|
+
if (slackInboundSuperseded(opts)) {
|
|
10625
|
+
log(`skip superseded stop reply ${msg.ts}`);
|
|
10626
|
+
return;
|
|
10627
|
+
}
|
|
10483
10628
|
await postSlackReply(msg, SLACK_LISTEN_STOPPED_REPLY, opts);
|
|
10484
10629
|
log(`replied stopped ${msg.ts}`);
|
|
10485
10630
|
return;
|
|
10486
10631
|
}
|
|
10487
10632
|
if (fresh.status === "running" || fresh.status === "queued") {
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
log(`replied busy ${msg.ts}`);
|
|
10491
|
-
return;
|
|
10633
|
+
interruptSlackCoordinatorForInbound(msg, agent, log);
|
|
10634
|
+
fresh = readThread(coordinator.id) ?? coordinator;
|
|
10492
10635
|
}
|
|
10493
10636
|
log(
|
|
10494
10637
|
`run ${msg.kind} ${msg.ts} user ${userId} \u2192 coordinator ${fresh.id.slice(0, 8)} (${inventory.length} workspace${inventory.length === 1 ? "" : "s"})`
|
|
@@ -10505,8 +10648,21 @@ async function handleSlackInbound(msg, opts) {
|
|
|
10505
10648
|
try {
|
|
10506
10649
|
await orch.send(fresh.id, prompt);
|
|
10507
10650
|
await orch.waitForTurn(fresh.id, 14 * 60 * 1e3);
|
|
10651
|
+
if (slackInboundSuperseded(opts)) {
|
|
10652
|
+
log(`turn finished ${msg.ts} (superseded)`);
|
|
10653
|
+
return;
|
|
10654
|
+
}
|
|
10655
|
+
const after = readThread(fresh.id);
|
|
10656
|
+
if (after?.status === "stopped") {
|
|
10657
|
+
log(`turn finished ${msg.ts} (interrupted, skip post)`);
|
|
10658
|
+
return;
|
|
10659
|
+
}
|
|
10508
10660
|
reply = orch.getTurnResult(fresh.id).text.trim();
|
|
10509
10661
|
} catch (err) {
|
|
10662
|
+
if (slackInboundSuperseded(opts)) {
|
|
10663
|
+
log(`turn error ${msg.ts} (superseded)`);
|
|
10664
|
+
return;
|
|
10665
|
+
}
|
|
10510
10666
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
10511
10667
|
const timedOut = /timed out|timeout/i.test(errMsg);
|
|
10512
10668
|
const errorReply = timedOut ? SLACK_LISTEN_TIMEOUT_REPLY : `Sideboard coordinator error: ${errMsg}`;
|
|
@@ -10554,19 +10710,35 @@ async function runSlackListen(opts = {}) {
|
|
|
10554
10710
|
const log = opts.onLog ?? console.log;
|
|
10555
10711
|
const connected = listSlackWorkspacesRaw();
|
|
10556
10712
|
const orch = getOrchestrator();
|
|
10713
|
+
const agent = coerceOrchestratorAgent(opts.agent ?? getDefaultAgent());
|
|
10714
|
+
let inboundGeneration = 0;
|
|
10557
10715
|
const off = orch.on((event) => {
|
|
10558
10716
|
if (event.type !== "turn_finished") return;
|
|
10559
10717
|
void relayCoordinatorReplyToSlack(event.threadId, opts);
|
|
10560
10718
|
});
|
|
10561
|
-
const onInbound = (msg) =>
|
|
10719
|
+
const onInbound = (msg) => {
|
|
10562
10720
|
if (!isInboundForThisDesktop(msg)) {
|
|
10563
10721
|
log(
|
|
10564
10722
|
`skip ${msg.kind} ${msg.ts}: Slack user ${msg.userId ?? "?"} is not connected on this Mac`
|
|
10565
10723
|
);
|
|
10566
10724
|
return;
|
|
10567
10725
|
}
|
|
10568
|
-
|
|
10569
|
-
|
|
10726
|
+
const generation = ++inboundGeneration;
|
|
10727
|
+
void ackSlackInboundSeen(msg, opts);
|
|
10728
|
+
interruptSlackCoordinatorForInbound(msg, agent, log);
|
|
10729
|
+
return enqueueHandle(async () => {
|
|
10730
|
+
if (generation !== inboundGeneration) {
|
|
10731
|
+
log(`skip superseded ${msg.kind} ${msg.ts}`);
|
|
10732
|
+
return;
|
|
10733
|
+
}
|
|
10734
|
+
await handleSlackInbound(msg, {
|
|
10735
|
+
...opts,
|
|
10736
|
+
skipAck: true,
|
|
10737
|
+
inboundGeneration: generation,
|
|
10738
|
+
currentInboundGeneration: () => inboundGeneration
|
|
10739
|
+
});
|
|
10740
|
+
});
|
|
10741
|
+
};
|
|
10570
10742
|
try {
|
|
10571
10743
|
const relay = (opts.relayUrl ?? slackRelayUrl()).trim();
|
|
10572
10744
|
if (!relay) {
|
|
@@ -11168,7 +11340,6 @@ export {
|
|
|
11168
11340
|
SIDEBOARD_FORCE_STOP,
|
|
11169
11341
|
SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
11170
11342
|
SIDEBOARD_MCP_PROFILE_ENV,
|
|
11171
|
-
SLACK_LISTEN_BUSY_REPLY,
|
|
11172
11343
|
SLACK_LISTEN_STOPPED_REPLY,
|
|
11173
11344
|
SLACK_LISTEN_TIMEOUT_REPLY,
|
|
11174
11345
|
SLACK_OAUTH_CANCELLED,
|
|
@@ -11238,6 +11409,7 @@ export {
|
|
|
11238
11409
|
cleanupOrphanWorktrees,
|
|
11239
11410
|
cloneRepoIntoSideboard,
|
|
11240
11411
|
codexAdapter,
|
|
11412
|
+
codexSandboxWritableRootsArgs,
|
|
11241
11413
|
codexUnattendedGitConfigArgs,
|
|
11242
11414
|
coerceOrchestratorAgent,
|
|
11243
11415
|
collectTakenTeamSlugs,
|
|
@@ -11354,6 +11526,7 @@ export {
|
|
|
11354
11526
|
getPr,
|
|
11355
11527
|
getPrChecks,
|
|
11356
11528
|
getPrDetails,
|
|
11529
|
+
getPrForHeadBranch,
|
|
11357
11530
|
getPrMeta,
|
|
11358
11531
|
getPrStack,
|
|
11359
11532
|
getRepoSetupInfo,
|
|
@@ -11384,12 +11557,14 @@ export {
|
|
|
11384
11557
|
initializeGitRepository,
|
|
11385
11558
|
inspectGitWorktree,
|
|
11386
11559
|
installAgent,
|
|
11560
|
+
interruptSlackCoordinatorForInbound,
|
|
11387
11561
|
isAskUserToolName,
|
|
11388
11562
|
isBrightsyConnected,
|
|
11389
11563
|
isBrightsyNdjsonLine,
|
|
11390
11564
|
isCloudCoordinatorThread,
|
|
11391
11565
|
isConductorBundledCli,
|
|
11392
11566
|
isCursorAutoModel,
|
|
11567
|
+
isDefaultishSourceRef,
|
|
11393
11568
|
isDirty,
|
|
11394
11569
|
isGhRateLimitError,
|
|
11395
11570
|
isGlobalRepoPath,
|
|
@@ -11456,8 +11631,10 @@ export {
|
|
|
11456
11631
|
maybeCompactContext,
|
|
11457
11632
|
mcpAllowTools,
|
|
11458
11633
|
mcpAuthWarnings,
|
|
11634
|
+
mergeAgentGitAuthEnv,
|
|
11459
11635
|
mergePr,
|
|
11460
11636
|
mergePrStack,
|
|
11637
|
+
mergeSideboardIntoMcpServersJson,
|
|
11461
11638
|
mergeUsage,
|
|
11462
11639
|
nextPastedTextName,
|
|
11463
11640
|
nextThinkingEffort,
|
|
@@ -11508,6 +11685,7 @@ export {
|
|
|
11508
11685
|
recordSlackOutboundWatch,
|
|
11509
11686
|
refreshGitHubAuth,
|
|
11510
11687
|
refreshSlackReplyBadges,
|
|
11688
|
+
registerPackagedUserMcpClients,
|
|
11511
11689
|
releaseCaffeinateHoldForThread,
|
|
11512
11690
|
removeWorkspace,
|
|
11513
11691
|
removeWorktree,
|
|
@@ -11516,9 +11694,11 @@ export {
|
|
|
11516
11694
|
requestReview,
|
|
11517
11695
|
requireAgent,
|
|
11518
11696
|
resetGhStackDetectCache,
|
|
11697
|
+
resetGithubAgentTokenMemo,
|
|
11519
11698
|
resolveAgentExecutable,
|
|
11520
11699
|
resolveAgentGitAuthEnv,
|
|
11521
11700
|
resolveClaudeExecutable,
|
|
11701
|
+
resolveCodexGitWritableRoots,
|
|
11522
11702
|
resolveCommandBinarySync,
|
|
11523
11703
|
resolveConductorCursorAgentId,
|
|
11524
11704
|
resolveCursorModelId,
|
|
@@ -11535,6 +11715,7 @@ export {
|
|
|
11535
11715
|
resolveNewThreadOptions,
|
|
11536
11716
|
resolvePlanMarkdown,
|
|
11537
11717
|
resolvePrSelector,
|
|
11718
|
+
resolvePrSelectors,
|
|
11538
11719
|
resolveQuotaFallbackAgent,
|
|
11539
11720
|
resolveRepoRoot,
|
|
11540
11721
|
resolveReviewGuidelines,
|
|
@@ -11557,6 +11738,7 @@ export {
|
|
|
11557
11738
|
sanitizeMcpServerName,
|
|
11558
11739
|
saveAppSettings,
|
|
11559
11740
|
saveLinearOAuth,
|
|
11741
|
+
scrubGithubTokensFromChildEnv,
|
|
11560
11742
|
secureFileUnlocksWith,
|
|
11561
11743
|
setCaffeinateHold,
|
|
11562
11744
|
setHttpFetchImpl,
|
|
@@ -11627,7 +11809,10 @@ export {
|
|
|
11627
11809
|
updateLinearIssue,
|
|
11628
11810
|
updateOpencodeSettings,
|
|
11629
11811
|
updateThread,
|
|
11812
|
+
userClaudeMcpConfigPath,
|
|
11813
|
+
userCursorMcpConfigPath,
|
|
11630
11814
|
validateLinearApiKey,
|
|
11815
|
+
warmGithubAgentAuth,
|
|
11631
11816
|
withAgentInstructions,
|
|
11632
11817
|
withExportedPath,
|
|
11633
11818
|
withThreadLock,
|