@sideboard-ai/core 0.1.125 → 0.1.130
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-DPR2TDNF.js → agents-7BUQY2WX.js} +6 -6
- package/dist/{agents-DCXXLTXF.js → agents-X2I3RNCY.js} +6 -6
- package/dist/{app-settings-YFWV7MOG.js → app-settings-6RPALX4J.js} +7 -1
- package/dist/{app-settings-IKFWZDUK.js → app-settings-E7NEQY7D.js} +7 -1
- package/dist/{chunk-GKY2GR2J.js → chunk-FMBLOOAO.js} +484 -37
- package/dist/{chunk-RG737OWT.js → chunk-G6X6UFJO.js} +2 -0
- package/dist/{chunk-HPAWHIZ3.js → chunk-HLJUNJBF.js} +2 -0
- package/dist/{chunk-OHEFHIG3.js → chunk-HRSBZIXS.js} +14 -6
- package/dist/{chunk-KWGP6RZM.js → chunk-HULESWLI.js} +4 -4
- package/dist/{chunk-FXQPY2KU.js → chunk-HUYEU4GS.js} +26 -4
- package/dist/{chunk-2X7I6MDW.js → chunk-HZPO3SSZ.js} +11 -8
- package/dist/{chunk-O43IRQ2Y.js → chunk-MNL4FSKY.js} +4 -4
- package/dist/{chunk-7Y3AYQWT.js → chunk-NV73AO7Q.js} +4 -4
- package/dist/{chunk-TRTWH6C2.js → chunk-RSFCB23A.js} +11 -8
- package/dist/{chunk-RBVVWBVB.js → chunk-SYLTXDRF.js} +2 -2
- package/dist/{chunk-UAVZ2JSO.js → chunk-UDQI3N47.js} +14 -6
- package/dist/{chunk-HZLE6LJJ.js → chunk-VE22NWBD.js} +2 -2
- package/dist/{chunk-ED27HCPV.js → chunk-YALVX3UE.js} +496 -37
- package/dist/{chunk-JNAIKICO.js → chunk-ZMUOPTKZ.js} +4 -4
- package/dist/{chunk-BMIRX64H.js → chunk-ZND6XV6J.js} +26 -4
- package/dist/{coordinator-prompt-AZ3WRDNC.js → coordinator-prompt-MEEUOEF2.js} +4 -4
- package/dist/{coordinator-prompt-LEU62W25.js → coordinator-prompt-SPJSGAQS.js} +4 -4
- package/dist/{global-workspace-U5UOVXKQ.js → global-workspace-BMWP7YZC.js} +5 -5
- package/dist/{global-workspace-4YNYDMLQ.js → global-workspace-KNESLWKG.js} +5 -5
- package/dist/index.cjs +1233 -170
- package/dist/index.d.cts +233 -10
- package/dist/index.d.ts +233 -10
- package/dist/index.js +695 -131
- package/dist/mcp/run-stdio.cjs +1081 -149
- package/dist/mcp/run-stdio.js +579 -123
- package/dist/{orchestrator-FZYM7I42.js → orchestrator-3ZSFTG72.js} +8 -8
- package/dist/{orchestrator-HN3LYHFN.js → orchestrator-G6DU3AF3.js} +8 -8
- package/dist/{thread-store-JR235AWK.js → thread-store-5MLYY35S.js} +1 -1
- package/dist/{thread-store-PMH3BMB6.js → thread-store-F6BCARQG.js} +1 -1
- package/dist/{workspaces-ICK433ZV.js → workspaces-HSYRYJYV.js} +6 -6
- package/dist/{workspaces-POWKTH2D.js → workspaces-O4QZOASB.js} +6 -6
- package/dist/{worktree-CMGBTVN4.js → worktree-ERHC7Q4F.js} +5 -3
- package/dist/{worktree-T57RD7BQ.js → worktree-JVGSLSLJ.js} +5 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AGENT_GIT_ACTIONS,
|
|
3
|
+
BOARD_COLUMN_DEFS,
|
|
3
4
|
CONTEXT_COMPACT_CHARS,
|
|
4
5
|
CONTEXT_KEEP_RECENT_CHARS,
|
|
5
6
|
CONTEXT_KEEP_RECENT_MESSAGES,
|
|
6
7
|
CONTEXT_MIN_MESSAGES,
|
|
8
|
+
HOME_BOARD_AGENT_HINT,
|
|
9
|
+
HOME_BOARD_CACHE_TTL_MS,
|
|
7
10
|
LEGACY_REVIEW_REQUEST_PATH,
|
|
8
11
|
Orchestrator,
|
|
9
12
|
REPO_REVIEW_NAME,
|
|
@@ -25,9 +28,11 @@ import {
|
|
|
25
28
|
applyPromptCacheTtlEnv,
|
|
26
29
|
applyThreadIntoMain,
|
|
27
30
|
armSchedules,
|
|
31
|
+
assembleHomeBoard,
|
|
28
32
|
attachmentFromAbsolutePath,
|
|
29
33
|
attachmentsFromBuffers,
|
|
30
34
|
attachmentsFromWorktreePaths,
|
|
35
|
+
boardPinIdentity,
|
|
31
36
|
buildForkTranscriptAttachment,
|
|
32
37
|
buildReviewRequestAttachment,
|
|
33
38
|
buildSessionSeed,
|
|
@@ -35,6 +40,7 @@ import {
|
|
|
35
40
|
captureLoginEnv,
|
|
36
41
|
captureTurnBaseline,
|
|
37
42
|
claimDesktopHost,
|
|
43
|
+
classifyWorktreeColumn,
|
|
38
44
|
cleanupOrphanWorktrees,
|
|
39
45
|
cloneRepoIntoSideboard,
|
|
40
46
|
computeNextRunAt,
|
|
@@ -46,6 +52,8 @@ import {
|
|
|
46
52
|
createPrStack,
|
|
47
53
|
createSchedule,
|
|
48
54
|
createThread,
|
|
55
|
+
dedupeBoardIssues,
|
|
56
|
+
dedupeBoardPrs,
|
|
49
57
|
defaultScheduleName,
|
|
50
58
|
deleteSchedule,
|
|
51
59
|
desktopHostPidPath,
|
|
@@ -58,6 +66,10 @@ import {
|
|
|
58
66
|
estimateThreadChars,
|
|
59
67
|
expandComposerPrompt,
|
|
60
68
|
extractiveSummary,
|
|
69
|
+
findBoardIssue,
|
|
70
|
+
findBoardPin,
|
|
71
|
+
findBoardPr,
|
|
72
|
+
findLiveThreadForCreate,
|
|
61
73
|
findOrphanWorktrees,
|
|
62
74
|
findThreadForStackLayer,
|
|
63
75
|
fireSchedule,
|
|
@@ -87,6 +99,7 @@ import {
|
|
|
87
99
|
getSchedule,
|
|
88
100
|
getSlackReplyTarget,
|
|
89
101
|
getSlackWorkspace,
|
|
102
|
+
groupHomeBoardWorktrees,
|
|
90
103
|
hasEnabledSchedules,
|
|
91
104
|
importConductorWorkspace,
|
|
92
105
|
importConductorWorkspaceAsync,
|
|
@@ -95,11 +108,13 @@ import {
|
|
|
95
108
|
inspectGitWorktree,
|
|
96
109
|
isCowboyThread,
|
|
97
110
|
isDesktopHostAlive,
|
|
111
|
+
isHomeBoardThread,
|
|
98
112
|
isImageFilePath,
|
|
99
113
|
isPidAlive,
|
|
100
114
|
isPrimaryCheckoutThread,
|
|
101
115
|
isSlackExternalReplyPrompt,
|
|
102
116
|
isThisProcessDesktopHost,
|
|
117
|
+
issueNeedsWorkspacePick,
|
|
103
118
|
lastRequestOccupancy,
|
|
104
119
|
listBranchCommits,
|
|
105
120
|
listConductorWorkspaces,
|
|
@@ -158,6 +173,7 @@ import {
|
|
|
158
173
|
startDevServer,
|
|
159
174
|
startOrchestration,
|
|
160
175
|
summarizeConversation,
|
|
176
|
+
syncBoardPins,
|
|
161
177
|
takenTeamSlugsForChatTab,
|
|
162
178
|
thisProcessShouldDrainAgentQueues,
|
|
163
179
|
threadsSharingWorktree,
|
|
@@ -165,10 +181,11 @@ import {
|
|
|
165
181
|
upsertSlackWorkspace,
|
|
166
182
|
waitForPidExit,
|
|
167
183
|
withAgentInstructions,
|
|
184
|
+
worktreeBoardStatus,
|
|
168
185
|
worktreeCleanupSettings,
|
|
169
186
|
wrapReviewSkillMarkdown,
|
|
170
187
|
writeWorktreeFile
|
|
171
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-YALVX3UE.js";
|
|
172
189
|
import {
|
|
173
190
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
174
191
|
CLAUDE_MODEL_CATALOG,
|
|
@@ -247,7 +264,7 @@ import {
|
|
|
247
264
|
withEventParentId,
|
|
248
265
|
withEventsParentId,
|
|
249
266
|
writeInjectedMcpConfig
|
|
250
|
-
} from "./chunk-
|
|
267
|
+
} from "./chunk-NV73AO7Q.js";
|
|
251
268
|
import {
|
|
252
269
|
brightsyConfigPath,
|
|
253
270
|
brightsyMcpServerName,
|
|
@@ -266,7 +283,7 @@ import {
|
|
|
266
283
|
listWorkspaces,
|
|
267
284
|
removeWorkspace,
|
|
268
285
|
syncWorkspacesFromThreads
|
|
269
|
-
} from "./chunk-
|
|
286
|
+
} from "./chunk-VE22NWBD.js";
|
|
270
287
|
import {
|
|
271
288
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
272
289
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -294,7 +311,7 @@ import {
|
|
|
294
311
|
parseForceStopMessage,
|
|
295
312
|
slackCoordinatorSourceRef,
|
|
296
313
|
takenTeamSlugsForOrchestration
|
|
297
|
-
} from "./chunk-
|
|
314
|
+
} from "./chunk-HULESWLI.js";
|
|
298
315
|
import {
|
|
299
316
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
300
317
|
SLACK_REPLY_FORMATTING,
|
|
@@ -303,7 +320,7 @@ import {
|
|
|
303
320
|
enrichWorkspacesWithGithub,
|
|
304
321
|
ensureGlobalCoordinatorCwd,
|
|
305
322
|
formatWorkspaceInventory
|
|
306
|
-
} from "./chunk-
|
|
323
|
+
} from "./chunk-HZPO3SSZ.js";
|
|
307
324
|
import {
|
|
308
325
|
LEGACY_PLAN_FILE_REL,
|
|
309
326
|
PLAN_FILE_NAME,
|
|
@@ -340,6 +357,7 @@ import {
|
|
|
340
357
|
appendIndexedGitConfig,
|
|
341
358
|
applyGithubGitAuthEnv,
|
|
342
359
|
branchDisplayLabel,
|
|
360
|
+
canonicalizeRepoPath,
|
|
343
361
|
checkoutPrStackLayer,
|
|
344
362
|
codexSandboxWritableRootsArgs,
|
|
345
363
|
codexUnattendedGitConfigArgs,
|
|
@@ -412,7 +430,7 @@ import {
|
|
|
412
430
|
worktreeDisplayLabel,
|
|
413
431
|
worktreeDisplayLabelForGroup,
|
|
414
432
|
worktreeNameFromPath
|
|
415
|
-
} from "./chunk-
|
|
433
|
+
} from "./chunk-UDQI3N47.js";
|
|
416
434
|
import {
|
|
417
435
|
ATTACHMENTS_DIR,
|
|
418
436
|
LEGACY_ATTACHMENTS_DIR,
|
|
@@ -422,6 +440,7 @@ import {
|
|
|
422
440
|
import {
|
|
423
441
|
GITHUB_GIT_AUTH_MODES,
|
|
424
442
|
HARNESS_ENV_KEYS,
|
|
443
|
+
ISSUE_SOURCE_LABELS,
|
|
425
444
|
appSettingsPath,
|
|
426
445
|
applyAppEnvironment,
|
|
427
446
|
autoArchiveOnMergeEnabled,
|
|
@@ -451,7 +470,9 @@ import {
|
|
|
451
470
|
getIssueSource,
|
|
452
471
|
getLinearApiKey,
|
|
453
472
|
harnessEnvKey,
|
|
473
|
+
isIssueSourceConnected,
|
|
454
474
|
isLinearConnected,
|
|
475
|
+
issueSourceLabel,
|
|
455
476
|
loadAppSettings,
|
|
456
477
|
maxConcurrentAgents,
|
|
457
478
|
orchestrationQuotaFallbackAgent,
|
|
@@ -481,7 +502,7 @@ import {
|
|
|
481
502
|
updateDefaultsSettings,
|
|
482
503
|
updateIntegrationsSettings,
|
|
483
504
|
updateOpencodeSettings
|
|
484
|
-
} from "./chunk-
|
|
505
|
+
} from "./chunk-HUYEU4GS.js";
|
|
485
506
|
import {
|
|
486
507
|
stripNestedElectronEnv
|
|
487
508
|
} from "./chunk-4TR3HZFT.js";
|
|
@@ -500,7 +521,7 @@ import {
|
|
|
500
521
|
updateThread,
|
|
501
522
|
withThreadLock,
|
|
502
523
|
writeThread
|
|
503
|
-
} from "./chunk-
|
|
524
|
+
} from "./chunk-HLJUNJBF.js";
|
|
504
525
|
import {
|
|
505
526
|
THINKING_EFFORTS,
|
|
506
527
|
isThinkingEffort,
|
|
@@ -898,6 +919,16 @@ async function disconnectLinear() {
|
|
|
898
919
|
|
|
899
920
|
// src/integrations/linear.ts
|
|
900
921
|
var LINEAR_GRAPHQL2 = "https://api.linear.app/graphql";
|
|
922
|
+
var LIST_ISSUE_FIELDS = `
|
|
923
|
+
id
|
|
924
|
+
identifier
|
|
925
|
+
title
|
|
926
|
+
url
|
|
927
|
+
assignee { id name }
|
|
928
|
+
team { id key }
|
|
929
|
+
labels(first: 10) { nodes { name } }
|
|
930
|
+
cycle { name number startsAt endsAt completedAt }
|
|
931
|
+
`;
|
|
901
932
|
var ISSUE_FIELDS = `
|
|
902
933
|
id
|
|
903
934
|
identifier
|
|
@@ -907,18 +938,21 @@ var ISSUE_FIELDS = `
|
|
|
907
938
|
priority
|
|
908
939
|
state { id name type }
|
|
909
940
|
assignee { id name }
|
|
910
|
-
team { id key name states { nodes { id name type } } }
|
|
911
|
-
labels { nodes { name } }
|
|
941
|
+
team { id key name states(first: 50) { nodes { id name type } } }
|
|
942
|
+
labels(first: 50) { nodes { name } }
|
|
943
|
+
cycle { name number startsAt endsAt completedAt }
|
|
912
944
|
`;
|
|
913
945
|
var ASSIGNED_ISSUES_QUERY = `
|
|
914
946
|
query SideboardAssignedIssues($first: Int!) {
|
|
915
947
|
viewer {
|
|
948
|
+
id
|
|
949
|
+
name
|
|
916
950
|
assignedIssues(
|
|
917
951
|
first: $first
|
|
918
952
|
orderBy: updatedAt
|
|
919
953
|
filter: { state: { type: { nin: ["completed", "canceled"] } } }
|
|
920
954
|
) {
|
|
921
|
-
nodes { ${
|
|
955
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
922
956
|
}
|
|
923
957
|
}
|
|
924
958
|
}
|
|
@@ -931,7 +965,7 @@ query SideboardTeams {
|
|
|
931
965
|
id
|
|
932
966
|
key
|
|
933
967
|
name
|
|
934
|
-
states { nodes { id name type } }
|
|
968
|
+
states(first: 50) { nodes { id name type } }
|
|
935
969
|
}
|
|
936
970
|
}
|
|
937
971
|
}
|
|
@@ -1015,6 +1049,25 @@ function mapState(node) {
|
|
|
1015
1049
|
type: String(node.type ?? "")
|
|
1016
1050
|
};
|
|
1017
1051
|
}
|
|
1052
|
+
function linearCycleIsActive(cycle, now = Date.now()) {
|
|
1053
|
+
if (!cycle) return false;
|
|
1054
|
+
if (cycle.completedAt) return false;
|
|
1055
|
+
const start = cycle.startsAt ? Date.parse(cycle.startsAt) : Number.NaN;
|
|
1056
|
+
const end = cycle.endsAt ? Date.parse(cycle.endsAt) : Number.NaN;
|
|
1057
|
+
if (Number.isFinite(start) && now < start) return false;
|
|
1058
|
+
if (Number.isFinite(end) && now > end) return false;
|
|
1059
|
+
return true;
|
|
1060
|
+
}
|
|
1061
|
+
function mapCycle(node) {
|
|
1062
|
+
if (!node?.name && node?.number == null) return null;
|
|
1063
|
+
const name = String(node.name ?? (node.number != null ? `Cycle ${node.number}` : "")).trim();
|
|
1064
|
+
if (!name) return null;
|
|
1065
|
+
return {
|
|
1066
|
+
name,
|
|
1067
|
+
number: typeof node.number === "number" ? node.number : void 0,
|
|
1068
|
+
isActive: linearCycleIsActive(node)
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1018
1071
|
function mapIssue(node) {
|
|
1019
1072
|
const team = node.team;
|
|
1020
1073
|
return {
|
|
@@ -1032,7 +1085,8 @@ function mapIssue(node) {
|
|
|
1032
1085
|
name: String(team.name ?? ""),
|
|
1033
1086
|
states: (team.states?.nodes ?? []).map((s) => mapState(s)).filter((s) => Boolean(s))
|
|
1034
1087
|
} : void 0,
|
|
1035
|
-
labels: (node.labels?.nodes ?? []).map((l) => l.name).filter((n) => Boolean(n))
|
|
1088
|
+
labels: (node.labels?.nodes ?? []).map((l) => l.name).filter((n) => Boolean(n)),
|
|
1089
|
+
cycle: mapCycle(node.cycle)
|
|
1036
1090
|
};
|
|
1037
1091
|
}
|
|
1038
1092
|
function toIssueInfo(issue) {
|
|
@@ -1042,7 +1096,11 @@ function toIssueInfo(issue) {
|
|
|
1042
1096
|
title: issue.title,
|
|
1043
1097
|
url: issue.url,
|
|
1044
1098
|
labels: issue.labels,
|
|
1045
|
-
provider: "linear"
|
|
1099
|
+
provider: "linear",
|
|
1100
|
+
assignee: issue.assignee?.name,
|
|
1101
|
+
assignees: issue.assignee?.name ? [issue.assignee.name] : void 0,
|
|
1102
|
+
cycle: issue.cycle ?? null,
|
|
1103
|
+
teamKey: issue.team?.key || void 0
|
|
1046
1104
|
};
|
|
1047
1105
|
}
|
|
1048
1106
|
function mapTeam(node) {
|
|
@@ -1084,10 +1142,21 @@ function normalizePriority(priority) {
|
|
|
1084
1142
|
}
|
|
1085
1143
|
return priority;
|
|
1086
1144
|
}
|
|
1087
|
-
async function
|
|
1088
|
-
const first = Math.max(1, Math.min(
|
|
1145
|
+
async function listLinearAssignedIssues(opts) {
|
|
1146
|
+
const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
|
|
1089
1147
|
const json = await linearGraphql(ASSIGNED_ISSUES_QUERY, { first }, opts);
|
|
1090
|
-
return
|
|
1148
|
+
return {
|
|
1149
|
+
viewer: {
|
|
1150
|
+
id: String(json.viewer?.id ?? ""),
|
|
1151
|
+
name: String(json.viewer?.name ?? "")
|
|
1152
|
+
},
|
|
1153
|
+
issues: (json.viewer?.assignedIssues?.nodes ?? []).map(
|
|
1154
|
+
(node) => toIssueInfo(mapIssue(node))
|
|
1155
|
+
)
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
async function listLinearIssuesDirect(opts) {
|
|
1159
|
+
return (await listLinearAssignedIssues(opts)).issues;
|
|
1091
1160
|
}
|
|
1092
1161
|
async function listLinearTeams(opts) {
|
|
1093
1162
|
const json = await linearGraphql(TEAMS_QUERY, void 0, opts);
|
|
@@ -1206,13 +1275,13 @@ async function validateLinearApiKey(apiKey) {
|
|
|
1206
1275
|
|
|
1207
1276
|
// src/integrations/issues.ts
|
|
1208
1277
|
async function listGitHubIssues(repoPath, opts) {
|
|
1209
|
-
const limit = Math.max(1, Math.min(
|
|
1278
|
+
const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
|
|
1210
1279
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
1211
1280
|
const args = [
|
|
1212
1281
|
"issue",
|
|
1213
1282
|
"list",
|
|
1214
1283
|
"--json",
|
|
1215
|
-
"number,title,url,labels",
|
|
1284
|
+
"number,title,url,labels,assignees",
|
|
1216
1285
|
"--limit",
|
|
1217
1286
|
String(limit),
|
|
1218
1287
|
"--state",
|
|
@@ -1235,27 +1304,55 @@ async function listGitHubIssues(repoPath, opts) {
|
|
|
1235
1304
|
const labels = (item.labels ?? []).map(
|
|
1236
1305
|
(l) => typeof l === "string" ? l : String(l?.name ?? "")
|
|
1237
1306
|
).filter(Boolean);
|
|
1307
|
+
const assignees = (item.assignees ?? []).map((a) => typeof a === "string" ? a : String(a?.login ?? "")).map((login) => login.trim()).filter(Boolean);
|
|
1238
1308
|
return {
|
|
1239
1309
|
id: Number.isFinite(number) ? `gh-${number}` : identifier,
|
|
1240
1310
|
identifier,
|
|
1241
1311
|
title: String(item.title ?? ""),
|
|
1242
1312
|
url: String(item.url ?? ""),
|
|
1243
1313
|
labels,
|
|
1244
|
-
provider: "github"
|
|
1314
|
+
provider: "github",
|
|
1315
|
+
assignee: assignees[0],
|
|
1316
|
+
assignees
|
|
1245
1317
|
};
|
|
1246
1318
|
});
|
|
1247
1319
|
}
|
|
1320
|
+
async function githubViewerLogin(repoPath) {
|
|
1321
|
+
const { stdout, exitCode } = await gh(["api", "user", "--jq", ".login"], repoPath, {
|
|
1322
|
+
reject: false
|
|
1323
|
+
});
|
|
1324
|
+
if (exitCode !== 0) return "";
|
|
1325
|
+
return stdout.trim();
|
|
1326
|
+
}
|
|
1248
1327
|
async function listIssues(repoPath) {
|
|
1249
1328
|
const settings = loadAppSettings();
|
|
1250
1329
|
const preferredSource = settings.integrations.issueSource ?? "github";
|
|
1251
1330
|
const linearConnected = isLinearConnected(settings);
|
|
1252
1331
|
const source = resolveEffectiveIssueSource(settings);
|
|
1253
1332
|
if (source === "linear") {
|
|
1254
|
-
const
|
|
1255
|
-
return {
|
|
1333
|
+
const listed = await listLinearAssignedIssues();
|
|
1334
|
+
return {
|
|
1335
|
+
source,
|
|
1336
|
+
preferredSource,
|
|
1337
|
+
linearConnected,
|
|
1338
|
+
issues: listed.issues,
|
|
1339
|
+
viewer: {
|
|
1340
|
+
login: listed.viewer.name,
|
|
1341
|
+
name: listed.viewer.name
|
|
1342
|
+
}
|
|
1343
|
+
};
|
|
1256
1344
|
}
|
|
1257
|
-
const issues = await
|
|
1258
|
-
|
|
1345
|
+
const [issues, login] = await Promise.all([
|
|
1346
|
+
listGitHubIssues(repoPath),
|
|
1347
|
+
githubViewerLogin(repoPath)
|
|
1348
|
+
]);
|
|
1349
|
+
return {
|
|
1350
|
+
source,
|
|
1351
|
+
preferredSource,
|
|
1352
|
+
linearConnected,
|
|
1353
|
+
issues,
|
|
1354
|
+
viewer: login ? { login } : void 0
|
|
1355
|
+
};
|
|
1259
1356
|
}
|
|
1260
1357
|
|
|
1261
1358
|
// src/composer/diff-comment.ts
|
|
@@ -1343,6 +1440,12 @@ function buildPastedTextAttachment(text4, opts) {
|
|
|
1343
1440
|
}
|
|
1344
1441
|
|
|
1345
1442
|
// src/plan/ask-user.ts
|
|
1443
|
+
function planQuestionsSignature(questions) {
|
|
1444
|
+
return questions.map((q) => {
|
|
1445
|
+
const opts = q.options.map((o) => o.label).join("");
|
|
1446
|
+
return `${q.question}${opts}`;
|
|
1447
|
+
}).join("");
|
|
1448
|
+
}
|
|
1346
1449
|
function asRecord(v) {
|
|
1347
1450
|
return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
1348
1451
|
}
|
|
@@ -1400,12 +1503,22 @@ function extractPendingPlanQuestions(parts) {
|
|
|
1400
1503
|
if (!questions.length) continue;
|
|
1401
1504
|
return {
|
|
1402
1505
|
id: p.id || `ask-${i}`,
|
|
1506
|
+
signature: planQuestionsSignature(questions),
|
|
1403
1507
|
questions,
|
|
1404
1508
|
source: p.name || "ask_user"
|
|
1405
1509
|
};
|
|
1406
1510
|
}
|
|
1407
1511
|
return null;
|
|
1408
1512
|
}
|
|
1513
|
+
function latestPendingPlanQuestions(input) {
|
|
1514
|
+
if (input.userReplied) return null;
|
|
1515
|
+
const fromLive = extractPendingPlanQuestions(input.liveParts);
|
|
1516
|
+
if (fromLive) return fromLive;
|
|
1517
|
+
const last = input.messages[input.messages.length - 1];
|
|
1518
|
+
if (last?.role === "user") return null;
|
|
1519
|
+
if (last?.role === "agent") return extractPendingPlanQuestions(last.parts);
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1409
1522
|
function formatPlanQuestionAnswers(questions, answers) {
|
|
1410
1523
|
const lines = ["Answers to your questions:"];
|
|
1411
1524
|
for (let i = 0; i < questions.length; i++) {
|
|
@@ -1444,6 +1557,7 @@ function formatPlanQuestionsForChat(questions) {
|
|
|
1444
1557
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1445
1558
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1446
1559
|
import { z as z4 } from "zod";
|
|
1560
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
1447
1561
|
import { basename } from "path";
|
|
1448
1562
|
|
|
1449
1563
|
// src/mcp/archive-guard.ts
|
|
@@ -2226,6 +2340,283 @@ function registerScheduleTools(server) {
|
|
|
2226
2340
|
);
|
|
2227
2341
|
}
|
|
2228
2342
|
|
|
2343
|
+
// src/board/load-home-board.ts
|
|
2344
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2345
|
+
import { join as join2 } from "path";
|
|
2346
|
+
|
|
2347
|
+
// src/board/board-pins.ts
|
|
2348
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2349
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
2350
|
+
import { join } from "path";
|
|
2351
|
+
var FILE = "home-board-pins.json";
|
|
2352
|
+
var VERSION = 1;
|
|
2353
|
+
function pinsFile() {
|
|
2354
|
+
return join(appDataDir(), FILE);
|
|
2355
|
+
}
|
|
2356
|
+
function readDisk() {
|
|
2357
|
+
const path2 = pinsFile();
|
|
2358
|
+
if (!existsSync(path2)) return [];
|
|
2359
|
+
try {
|
|
2360
|
+
const raw = JSON.parse(readFileSync(path2, "utf8"));
|
|
2361
|
+
if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
|
|
2362
|
+
return raw.items.filter((item) => item?.id && item.kind && item.ref);
|
|
2363
|
+
} catch {
|
|
2364
|
+
return [];
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
function writeDisk(items) {
|
|
2368
|
+
mkdirSync(appDataDir(), { recursive: true });
|
|
2369
|
+
writeFileSync(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
|
|
2370
|
+
}
|
|
2371
|
+
function listBoardPins() {
|
|
2372
|
+
return readDisk();
|
|
2373
|
+
}
|
|
2374
|
+
function addBoardPin(input) {
|
|
2375
|
+
const ref = input.ref.trim();
|
|
2376
|
+
if (!ref) throw new Error("Board item needs a ref");
|
|
2377
|
+
const pin = {
|
|
2378
|
+
id: randomUUID2(),
|
|
2379
|
+
kind: input.kind,
|
|
2380
|
+
ref,
|
|
2381
|
+
repoPath: input.repoPath.trim(),
|
|
2382
|
+
addedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2383
|
+
title: input.title?.trim() || ref,
|
|
2384
|
+
url: input.url,
|
|
2385
|
+
labels: input.labels,
|
|
2386
|
+
provider: input.provider,
|
|
2387
|
+
assignee: input.assignee,
|
|
2388
|
+
cycle: input.cycle,
|
|
2389
|
+
teamKey: input.teamKey,
|
|
2390
|
+
headRefName: input.headRefName,
|
|
2391
|
+
author: input.author,
|
|
2392
|
+
remoteState: "open",
|
|
2393
|
+
needsWorkspacePick: issueNeedsWorkspacePick(
|
|
2394
|
+
input.provider,
|
|
2395
|
+
input.workspaceCount ?? 1
|
|
2396
|
+
)
|
|
2397
|
+
};
|
|
2398
|
+
const items = listBoardPins();
|
|
2399
|
+
const identity = boardPinIdentity(pin);
|
|
2400
|
+
const existing = items.find((item) => boardPinIdentity(item) === identity);
|
|
2401
|
+
if (existing) {
|
|
2402
|
+
const merged = { ...existing, ...pin, id: existing.id, addedAt: existing.addedAt };
|
|
2403
|
+
writeDisk(items.map((item) => item.id === existing.id ? merged : item));
|
|
2404
|
+
return merged;
|
|
2405
|
+
}
|
|
2406
|
+
writeDisk([...items, pin]);
|
|
2407
|
+
return pin;
|
|
2408
|
+
}
|
|
2409
|
+
function removeBoardPin(id) {
|
|
2410
|
+
const items = listBoardPins();
|
|
2411
|
+
const next = items.filter((item) => item.id !== id);
|
|
2412
|
+
if (next.length === items.length) return false;
|
|
2413
|
+
writeDisk(next);
|
|
2414
|
+
return true;
|
|
2415
|
+
}
|
|
2416
|
+
function replaceBoardPins(items) {
|
|
2417
|
+
writeDisk(items);
|
|
2418
|
+
}
|
|
2419
|
+
function clearBoardPins() {
|
|
2420
|
+
try {
|
|
2421
|
+
unlinkSync(pinsFile());
|
|
2422
|
+
} catch {
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// src/board/load-home-board.ts
|
|
2427
|
+
var CACHE_VERSION = 1;
|
|
2428
|
+
var memory = null;
|
|
2429
|
+
var inflight = null;
|
|
2430
|
+
function errText(err) {
|
|
2431
|
+
return err instanceof Error ? err.message : String(err);
|
|
2432
|
+
}
|
|
2433
|
+
function homeBoardWorkspaceKey(workspaces) {
|
|
2434
|
+
return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
|
|
2435
|
+
}
|
|
2436
|
+
function cacheFile() {
|
|
2437
|
+
return join2(appDataDir(), "home-board-cache.json");
|
|
2438
|
+
}
|
|
2439
|
+
function emptyInputs() {
|
|
2440
|
+
return {
|
|
2441
|
+
issues: [],
|
|
2442
|
+
prs: [],
|
|
2443
|
+
issueSource: "github",
|
|
2444
|
+
viewerLogin: void 0,
|
|
2445
|
+
issueErrors: [],
|
|
2446
|
+
prErrors: []
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
function asLoaded(entry, fromCache) {
|
|
2450
|
+
const pins = syncBoardPins(listBoardPins(), entry.inputs.issues, entry.inputs.prs);
|
|
2451
|
+
return { ...entry.inputs, fetchedAt: entry.fetchedAt, fromCache, pins };
|
|
2452
|
+
}
|
|
2453
|
+
function cacheStillFresh(entry, key, now) {
|
|
2454
|
+
return entry.workspaceKey === key && now - entry.fetchedAt < HOME_BOARD_CACHE_TTL_MS;
|
|
2455
|
+
}
|
|
2456
|
+
function shouldCacheHomeBoardInputs(inputs) {
|
|
2457
|
+
const issuesFailed = inputs.issues.length === 0 && inputs.issueErrors.length > 0;
|
|
2458
|
+
const prsFailed = inputs.prs.length === 0 && inputs.prErrors.length > 0;
|
|
2459
|
+
return !(issuesFailed && prsFailed);
|
|
2460
|
+
}
|
|
2461
|
+
function readDiskCache() {
|
|
2462
|
+
const path2 = cacheFile();
|
|
2463
|
+
if (!existsSync2(path2)) return null;
|
|
2464
|
+
try {
|
|
2465
|
+
const raw = JSON.parse(readFileSync2(path2, "utf8"));
|
|
2466
|
+
if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
|
|
2467
|
+
return null;
|
|
2468
|
+
}
|
|
2469
|
+
if (!raw.inputs || !Array.isArray(raw.inputs.issues) || !Array.isArray(raw.inputs.prs)) {
|
|
2470
|
+
return null;
|
|
2471
|
+
}
|
|
2472
|
+
return raw;
|
|
2473
|
+
} catch {
|
|
2474
|
+
return null;
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
function writeDiskCache(entry) {
|
|
2478
|
+
try {
|
|
2479
|
+
mkdirSync2(appDataDir(), { recursive: true });
|
|
2480
|
+
writeFileSync2(cacheFile(), JSON.stringify(entry), "utf8");
|
|
2481
|
+
} catch {
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
function deleteDiskCache() {
|
|
2485
|
+
try {
|
|
2486
|
+
unlinkSync2(cacheFile());
|
|
2487
|
+
} catch {
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
function resetHomeBoardMemory() {
|
|
2491
|
+
memory = null;
|
|
2492
|
+
inflight = null;
|
|
2493
|
+
}
|
|
2494
|
+
function clearHomeBoardCache() {
|
|
2495
|
+
resetHomeBoardMemory();
|
|
2496
|
+
deleteDiskCache();
|
|
2497
|
+
}
|
|
2498
|
+
async function loadHomeBoardInputs(workspaces) {
|
|
2499
|
+
const paths = workspaces.map((w) => w.path).filter(Boolean);
|
|
2500
|
+
if (paths.length === 0) return emptyInputs();
|
|
2501
|
+
const issueErrors = [];
|
|
2502
|
+
const prErrors = [];
|
|
2503
|
+
let issueSource = "github";
|
|
2504
|
+
let viewerLogin;
|
|
2505
|
+
let issues = [];
|
|
2506
|
+
try {
|
|
2507
|
+
const first = await listIssues(paths[0]);
|
|
2508
|
+
issueSource = first.source;
|
|
2509
|
+
viewerLogin = first.viewer?.login || first.viewer?.name || void 0;
|
|
2510
|
+
if (first.source === "linear") {
|
|
2511
|
+
const repoPath = paths[0] ?? "";
|
|
2512
|
+
issues = first.issues.map((issue) => ({
|
|
2513
|
+
...issue,
|
|
2514
|
+
repoPath,
|
|
2515
|
+
needsWorkspacePick: issueNeedsWorkspacePick(
|
|
2516
|
+
issue.provider ?? first.source,
|
|
2517
|
+
paths.length
|
|
2518
|
+
)
|
|
2519
|
+
}));
|
|
2520
|
+
} else {
|
|
2521
|
+
const settled = await Promise.allSettled(
|
|
2522
|
+
paths.map(async (path2) => {
|
|
2523
|
+
const result = path2 === paths[0] ? first : await listIssues(path2);
|
|
2524
|
+
return result.issues.map((issue) => ({
|
|
2525
|
+
...issue,
|
|
2526
|
+
repoPath: path2,
|
|
2527
|
+
needsWorkspacePick: issueNeedsWorkspacePick(
|
|
2528
|
+
issue.provider ?? result.source,
|
|
2529
|
+
1
|
|
2530
|
+
)
|
|
2531
|
+
}));
|
|
2532
|
+
})
|
|
2533
|
+
);
|
|
2534
|
+
const collected = [];
|
|
2535
|
+
for (const item of settled) {
|
|
2536
|
+
if (item.status === "fulfilled") collected.push(...item.value);
|
|
2537
|
+
else issueErrors.push(errText(item.reason));
|
|
2538
|
+
}
|
|
2539
|
+
issues = collected;
|
|
2540
|
+
if (collected.length === 0 && issueErrors[0]) {
|
|
2541
|
+
throw new Error(issueErrors[0]);
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
issues = dedupeBoardIssues(issues);
|
|
2545
|
+
} catch (err) {
|
|
2546
|
+
issueErrors.push(errText(err));
|
|
2547
|
+
issues = [];
|
|
2548
|
+
}
|
|
2549
|
+
let prs = [];
|
|
2550
|
+
try {
|
|
2551
|
+
const settled = await Promise.allSettled(
|
|
2552
|
+
paths.map(async (path2) => {
|
|
2553
|
+
const list = await listPrs(path2);
|
|
2554
|
+
return list.map((pr) => ({ ...pr, repoPath: path2 }));
|
|
2555
|
+
})
|
|
2556
|
+
);
|
|
2557
|
+
const collected = [];
|
|
2558
|
+
for (const item of settled) {
|
|
2559
|
+
if (item.status === "fulfilled") collected.push(...item.value);
|
|
2560
|
+
else prErrors.push(errText(item.reason));
|
|
2561
|
+
}
|
|
2562
|
+
if (collected.length === 0 && prErrors[0]) {
|
|
2563
|
+
throw new Error(prErrors[0]);
|
|
2564
|
+
}
|
|
2565
|
+
prs = dedupeBoardPrs(collected);
|
|
2566
|
+
} catch (err) {
|
|
2567
|
+
prErrors.push(errText(err));
|
|
2568
|
+
prs = [];
|
|
2569
|
+
}
|
|
2570
|
+
return { issues, prs, issueSource, viewerLogin, issueErrors, prErrors };
|
|
2571
|
+
}
|
|
2572
|
+
async function getHomeBoardInputs(workspaces, opts) {
|
|
2573
|
+
const key = homeBoardWorkspaceKey(workspaces);
|
|
2574
|
+
const now = opts?.now ?? Date.now();
|
|
2575
|
+
if (!key) {
|
|
2576
|
+
return {
|
|
2577
|
+
...emptyInputs(),
|
|
2578
|
+
fetchedAt: now,
|
|
2579
|
+
fromCache: false,
|
|
2580
|
+
pins: listBoardPins()
|
|
2581
|
+
};
|
|
2582
|
+
}
|
|
2583
|
+
if (!opts?.refresh) {
|
|
2584
|
+
const disk = readDiskCache();
|
|
2585
|
+
const best = memory && disk ? disk.fetchedAt >= memory.fetchedAt ? disk : memory : memory ?? disk;
|
|
2586
|
+
if (best && cacheStillFresh(best, key, now)) {
|
|
2587
|
+
memory = best;
|
|
2588
|
+
return asLoaded(best, true);
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
if (inflight && inflight.key === key) {
|
|
2592
|
+
return inflight.promise;
|
|
2593
|
+
}
|
|
2594
|
+
const promise = (async () => {
|
|
2595
|
+
const inputs = await loadHomeBoardInputs(workspaces);
|
|
2596
|
+
const fetchedAt = opts?.now ?? Date.now();
|
|
2597
|
+
const pins = syncBoardPins(listBoardPins(), inputs.issues, inputs.prs);
|
|
2598
|
+
replaceBoardPins(pins);
|
|
2599
|
+
const loaded = { ...inputs, fetchedAt, fromCache: false, pins };
|
|
2600
|
+
if (shouldCacheHomeBoardInputs(inputs)) {
|
|
2601
|
+
const entry = {
|
|
2602
|
+
version: CACHE_VERSION,
|
|
2603
|
+
workspaceKey: key,
|
|
2604
|
+
fetchedAt,
|
|
2605
|
+
inputs
|
|
2606
|
+
};
|
|
2607
|
+
memory = entry;
|
|
2608
|
+
writeDiskCache(entry);
|
|
2609
|
+
}
|
|
2610
|
+
return loaded;
|
|
2611
|
+
})();
|
|
2612
|
+
inflight = { key, promise };
|
|
2613
|
+
try {
|
|
2614
|
+
return await promise;
|
|
2615
|
+
} finally {
|
|
2616
|
+
if (inflight?.promise === promise) inflight = null;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2229
2620
|
// src/mcp/server.ts
|
|
2230
2621
|
var MAX_ORCH_THREADS = 5;
|
|
2231
2622
|
var CREATE_THREAD_TIMEOUT_MS = 9e4;
|
|
@@ -2246,6 +2637,93 @@ function withTimeout(promise, ms, label) {
|
|
|
2246
2637
|
);
|
|
2247
2638
|
});
|
|
2248
2639
|
}
|
|
2640
|
+
async function createOrchChildThread(orch, args, resolveNewThreadOptions2) {
|
|
2641
|
+
const envParentId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || "";
|
|
2642
|
+
let parentId = args.parentThreadId?.trim() || "";
|
|
2643
|
+
let parent = parentId ? orch.getThread(parentId) : null;
|
|
2644
|
+
let parentCorrectedFrom;
|
|
2645
|
+
if (envParentId) {
|
|
2646
|
+
const envParent = orch.getThread(envParentId);
|
|
2647
|
+
if (envParent) {
|
|
2648
|
+
if (parentId && parentId !== envParentId) parentCorrectedFrom = parentId;
|
|
2649
|
+
else if (!parentId) parentCorrectedFrom = void 0;
|
|
2650
|
+
parentId = envParentId;
|
|
2651
|
+
parent = envParent;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
if (parentId && !parent) {
|
|
2655
|
+
parentCorrectedFrom = parentId;
|
|
2656
|
+
parentId = "";
|
|
2657
|
+
parent = null;
|
|
2658
|
+
}
|
|
2659
|
+
if (parentId) {
|
|
2660
|
+
const children = orch.getThreads(false).filter((t) => t.parentThreadId === parentId);
|
|
2661
|
+
if (children.length >= MAX_ORCH_THREADS) {
|
|
2662
|
+
return {
|
|
2663
|
+
ok: false,
|
|
2664
|
+
text: `Thread-creation cap (${MAX_ORCH_THREADS}) reached for this orchestration session`
|
|
2665
|
+
};
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
let agentArg = args.agent;
|
|
2669
|
+
let agentCoercedFrom;
|
|
2670
|
+
const resolvedProbe = resolveNewThreadOptions2({ agent: agentArg }).agent;
|
|
2671
|
+
if (resolvedProbe === "codex") {
|
|
2672
|
+
agentCoercedFrom = agentArg ?? "codex";
|
|
2673
|
+
const accountAgent = resolveNewThreadOptions2({}).agent;
|
|
2674
|
+
agentArg = accountAgent !== "codex" ? accountAgent : "cursor";
|
|
2675
|
+
}
|
|
2676
|
+
const opts = resolveNewThreadOptions2({
|
|
2677
|
+
agent: agentArg,
|
|
2678
|
+
model: args.model
|
|
2679
|
+
});
|
|
2680
|
+
try {
|
|
2681
|
+
const priorIds = new Set(orch.getThreads(false).map((t) => t.id));
|
|
2682
|
+
const thread = await withTimeout(
|
|
2683
|
+
orch.createThread({
|
|
2684
|
+
sourceType: args.sourceType,
|
|
2685
|
+
sourceRef: args.sourceRef,
|
|
2686
|
+
agent: opts.agent,
|
|
2687
|
+
model: opts.model,
|
|
2688
|
+
effort: opts.effort,
|
|
2689
|
+
fast: opts.fast,
|
|
2690
|
+
repoPath: args.repoPath,
|
|
2691
|
+
title: args.title,
|
|
2692
|
+
parentThreadId: parentId || null,
|
|
2693
|
+
cowboy: args.cowboy || void 0,
|
|
2694
|
+
attachments: args.attachments
|
|
2695
|
+
}),
|
|
2696
|
+
CREATE_THREAD_TIMEOUT_MS,
|
|
2697
|
+
"create_thread"
|
|
2698
|
+
);
|
|
2699
|
+
const alreadyStarted = priorIds.has(thread.id);
|
|
2700
|
+
const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
|
|
2701
|
+
return {
|
|
2702
|
+
ok: true,
|
|
2703
|
+
text: JSON.stringify({
|
|
2704
|
+
id: thread.id,
|
|
2705
|
+
title: thread.title,
|
|
2706
|
+
branchName: thread.branchName,
|
|
2707
|
+
worktreePath: thread.worktreePath,
|
|
2708
|
+
agent: thread.agent,
|
|
2709
|
+
model: thread.model,
|
|
2710
|
+
status: thread.status,
|
|
2711
|
+
cowboy: Boolean(thread.cowboy),
|
|
2712
|
+
link: `sideboard://thread/${thread.id}`,
|
|
2713
|
+
parentThreadId: thread.parentThreadId,
|
|
2714
|
+
...alreadyStarted ? { alreadyStarted: true } : {},
|
|
2715
|
+
...agentCoercedFrom ? {
|
|
2716
|
+
agentCoercedFrom,
|
|
2717
|
+
note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
|
|
2718
|
+
} : {},
|
|
2719
|
+
...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
|
|
2720
|
+
})
|
|
2721
|
+
};
|
|
2722
|
+
} catch (err) {
|
|
2723
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2724
|
+
return { ok: false, text: `create_thread failed: ${message}` };
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2249
2727
|
async function startMcpServer() {
|
|
2250
2728
|
const orch = getOrchestrator();
|
|
2251
2729
|
try {
|
|
@@ -2257,7 +2735,7 @@ async function startMcpServer() {
|
|
|
2257
2735
|
);
|
|
2258
2736
|
}
|
|
2259
2737
|
try {
|
|
2260
|
-
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-
|
|
2738
|
+
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-6RPALX4J.js");
|
|
2261
2739
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
2262
2740
|
} catch {
|
|
2263
2741
|
}
|
|
@@ -2277,7 +2755,7 @@ async function startMcpServer() {
|
|
|
2277
2755
|
if (!worktreeProfile) {
|
|
2278
2756
|
server.tool(
|
|
2279
2757
|
"list_workspaces",
|
|
2280
|
-
"List registered Sideboard workspaces (repos). Each line is name, path, and github:owner/repo when resolvable \u2014 use path as repoPath for list_branches/list_prs/list_issues/create_thread.",
|
|
2758
|
+
"List registered Sideboard workspaces (repos). Each line is name, path, and github:owner/repo when resolvable \u2014 use path as repoPath for list_board/list_branches/list_prs/list_issues/create_thread.",
|
|
2281
2759
|
{},
|
|
2282
2760
|
async () => {
|
|
2283
2761
|
const workspaces = orch.listWorkspaces();
|
|
@@ -2311,6 +2789,51 @@ async function startMcpServer() {
|
|
|
2311
2789
|
};
|
|
2312
2790
|
}
|
|
2313
2791
|
);
|
|
2792
|
+
server.tool(
|
|
2793
|
+
"list_board",
|
|
2794
|
+
"Home Kanban of worktrees (New, Draft, Review, Merged) \u2014 one card per checkout; sibling chat tabs nest as inner cards. Same cards as desktop Home. Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind (ticket/PR/branch source), column, limit (default 40). create_thread adds a worktree (and a Home card), or returns the live one if that ticket/PR/named branch is already checked out.",
|
|
2795
|
+
{
|
|
2796
|
+
query: z4.string().optional().describe("Case-insensitive token search across title, id, labels, repo"),
|
|
2797
|
+
repoPath: z4.string().optional().describe("Limit to one workspace path from list_workspaces"),
|
|
2798
|
+
kind: z4.enum(["all", "tickets", "prs", "branches", "threads"]).optional().describe("Filter by worktree source (default all)"),
|
|
2799
|
+
column: z4.enum(["new", "draft", "review", "done", "needs_you"]).optional().describe(
|
|
2800
|
+
"Return cards for this column only (totals still include the rest). needs_you is a legacy alias for new."
|
|
2801
|
+
),
|
|
2802
|
+
limit: z4.number().int().positive().optional().describe("Max cards per column (default 40). hidden counts the remainder.")
|
|
2803
|
+
},
|
|
2804
|
+
async ({ query, repoPath, kind, column, limit }) => {
|
|
2805
|
+
const workspaces = orch.listWorkspaces();
|
|
2806
|
+
const all = orch.getThreads(true);
|
|
2807
|
+
const names = new Map(workspaces.map((w) => [w.path, w.name]));
|
|
2808
|
+
const snap = assembleHomeBoard({
|
|
2809
|
+
threads: all.filter((t) => t.status !== "archived"),
|
|
2810
|
+
query,
|
|
2811
|
+
repoPath,
|
|
2812
|
+
kind: kind ?? "all",
|
|
2813
|
+
column: column === "needs_you" ? "new" : column,
|
|
2814
|
+
limit,
|
|
2815
|
+
workspaceName: (path2) => names.get(path2) ?? ""
|
|
2816
|
+
});
|
|
2817
|
+
return {
|
|
2818
|
+
content: [
|
|
2819
|
+
{
|
|
2820
|
+
type: "text",
|
|
2821
|
+
text: JSON.stringify(
|
|
2822
|
+
{
|
|
2823
|
+
columns: snap.columns,
|
|
2824
|
+
hidden: snap.hidden,
|
|
2825
|
+
totals: snap.totals,
|
|
2826
|
+
columnDefs: BOARD_COLUMN_DEFS,
|
|
2827
|
+
hint: HOME_BOARD_AGENT_HINT
|
|
2828
|
+
},
|
|
2829
|
+
null,
|
|
2830
|
+
2
|
|
2831
|
+
)
|
|
2832
|
+
}
|
|
2833
|
+
]
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
);
|
|
2314
2837
|
server.tool(
|
|
2315
2838
|
"get_thread",
|
|
2316
2839
|
"Get a compact thread summary by id/ref. While running, includes progress (last tool/thinking) and lastActivityAt. Includes usage (thread billed token + costUsd totals when providers reported cost) and lastTurnUsage.",
|
|
@@ -2349,25 +2872,31 @@ async function startMcpServer() {
|
|
|
2349
2872
|
}
|
|
2350
2873
|
server.tool(
|
|
2351
2874
|
"present_artifact",
|
|
2352
|
-
"Show
|
|
2875
|
+
"Show a document or live log in Sideboard\u2019s side column. For html/svg/markdown/react, pass the FULL document and do not also fence that same body in chat. For type=log, pass only NEW lines (same artifact_id appends). Prefer type=log for long-running job output \u2014 do not resend HTML. type=react is a single default-export component (JSX/TSX); only react/react-dom imports.",
|
|
2353
2876
|
{
|
|
2354
2877
|
title: z4.string().describe("Short title shown in the artifact pane header"),
|
|
2355
|
-
type: z4.enum(["html", "svg", "markdown", "react"]).describe(
|
|
2356
|
-
"
|
|
2878
|
+
type: z4.enum(["html", "svg", "markdown", "react", "log"]).describe(
|
|
2879
|
+
"html/svg/markdown/react replace the pane. log appends content to the same artifact_id (new lines only)."
|
|
2357
2880
|
),
|
|
2358
2881
|
content: z4.string().describe(
|
|
2359
|
-
"
|
|
2882
|
+
"html/svg/markdown/react: full document. log: only the new lines since the last call (empty is ok for a status-only update)."
|
|
2360
2883
|
),
|
|
2361
|
-
artifact_id: z4.string().optional().describe("Stable id
|
|
2884
|
+
artifact_id: z4.string().optional().describe("Stable id. Required for type=log so later calls append to the same pane."),
|
|
2885
|
+
status: z4.enum(["running", "ok", "failed", "idle"]).optional().describe("Log header pill: running (working), ok (done), failed, idle"),
|
|
2886
|
+
phase: z4.string().optional().describe("Log subtitle (Signing, Notarizing, \u2026)"),
|
|
2887
|
+
mode: z4.enum(["append", "replace"]).optional().describe("log only: append (default) or replace the buffer")
|
|
2362
2888
|
},
|
|
2363
|
-
async ({ title, type, artifact_id }) => {
|
|
2889
|
+
async ({ title, type, artifact_id, status, phase, mode }) => {
|
|
2364
2890
|
const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2365
2891
|
const payload = {
|
|
2366
2892
|
ok: true,
|
|
2367
2893
|
artifact_id: id,
|
|
2368
2894
|
title,
|
|
2369
2895
|
type,
|
|
2370
|
-
|
|
2896
|
+
status,
|
|
2897
|
+
phase,
|
|
2898
|
+
mode: type === "log" ? mode ?? "append" : void 0,
|
|
2899
|
+
message: type === "log" ? "Log accepted. Same artifact_id appends; send only new lines next time." : "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
|
|
2371
2900
|
};
|
|
2372
2901
|
return { content: [{ type: "text", text: JSON.stringify(payload) }] };
|
|
2373
2902
|
}
|
|
@@ -2480,7 +3009,7 @@ async function startMcpServer() {
|
|
|
2480
3009
|
registerLinearTools(server);
|
|
2481
3010
|
registerScheduleTools(server);
|
|
2482
3011
|
const { getCaffeinateHold: getCaffeinateHold2, setCaffeinateHold: setCaffeinateHold2 } = await import("./caffeinate-hold-X3JNPR42.js");
|
|
2483
|
-
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-
|
|
3012
|
+
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-6RPALX4J.js");
|
|
2484
3013
|
const accountDefaults = resolveThreadDefaults2();
|
|
2485
3014
|
const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
|
|
2486
3015
|
server.tool(
|
|
@@ -2523,7 +3052,7 @@ async function startMcpServer() {
|
|
|
2523
3052
|
);
|
|
2524
3053
|
server.tool(
|
|
2525
3054
|
"create_thread",
|
|
2526
|
-
`Create a
|
|
3055
|
+
`Create a worktree thread (chat) from branch, pr, or ticket. If a live worktree already matches that ticket, PR, or named branch, returns it (alreadyStarted=true) instead of a second checkout. Creating from the default branch still opens a new isolated worktree. Pass repoPath from list_workspaces. cowboy=true uses the project folder on the default branch (no isolated worktree; land is commit+push). 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}. Setup (settings.toml, .cursor/worktrees.json, or script/setup) runs in the background in parallel with the first turn (skipped for cowboy). Then use send_to_thread to chat.`,
|
|
2527
3056
|
{
|
|
2528
3057
|
sourceType: z4.enum(["branch", "pr", "ticket"]),
|
|
2529
3058
|
sourceRef: z4.string(),
|
|
@@ -2541,104 +3070,118 @@ async function startMcpServer() {
|
|
|
2541
3070
|
)
|
|
2542
3071
|
},
|
|
2543
3072
|
async (args) => {
|
|
2544
|
-
const
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
}
|
|
2576
|
-
let agentArg = args.agent;
|
|
2577
|
-
let agentCoercedFrom;
|
|
2578
|
-
const resolvedProbe = resolveNewThreadOptions2({ agent: agentArg }).agent;
|
|
2579
|
-
if (resolvedProbe === "codex") {
|
|
2580
|
-
agentCoercedFrom = agentArg ?? "codex";
|
|
2581
|
-
const accountAgent = resolveNewThreadOptions2({}).agent;
|
|
2582
|
-
agentArg = accountAgent !== "codex" ? accountAgent : "cursor";
|
|
2583
|
-
}
|
|
2584
|
-
const opts = resolveNewThreadOptions2({
|
|
2585
|
-
agent: agentArg,
|
|
2586
|
-
model: args.model
|
|
2587
|
-
});
|
|
2588
|
-
try {
|
|
2589
|
-
const thread = await withTimeout(
|
|
2590
|
-
orch.createThread({
|
|
2591
|
-
sourceType: args.sourceType,
|
|
2592
|
-
sourceRef: args.sourceRef,
|
|
2593
|
-
agent: opts.agent,
|
|
2594
|
-
model: opts.model,
|
|
2595
|
-
effort: opts.effort,
|
|
2596
|
-
fast: opts.fast,
|
|
2597
|
-
repoPath: args.repoPath,
|
|
2598
|
-
title: args.title,
|
|
2599
|
-
parentThreadId: parentId || null,
|
|
2600
|
-
cowboy: args.cowboy || void 0
|
|
2601
|
-
}),
|
|
2602
|
-
CREATE_THREAD_TIMEOUT_MS,
|
|
2603
|
-
"create_thread"
|
|
2604
|
-
);
|
|
2605
|
-
const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
|
|
3073
|
+
const result = await createOrchChildThread(orch, args, resolveNewThreadOptions2);
|
|
3074
|
+
return {
|
|
3075
|
+
content: [{ type: "text", text: result.text }],
|
|
3076
|
+
...result.ok ? {} : { isError: true }
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
);
|
|
3080
|
+
server.tool(
|
|
3081
|
+
"start_board_card",
|
|
3082
|
+
"Same as create_thread for a ticket, PR, or named branch (attaches issue text when Sideboard can resolve it). Reuses the live worktree if one already matches. Then send_to_thread.",
|
|
3083
|
+
{
|
|
3084
|
+
kind: z4.enum(["ticket", "pr", "branch"]),
|
|
3085
|
+
ref: z4.string().describe("Ticket identifier (ENG-12), PR number (44), or branch name from list_board"),
|
|
3086
|
+
repoPath: z4.string().describe("Workspace path from list_workspaces / list_board"),
|
|
3087
|
+
title: z4.string().optional()
|
|
3088
|
+
},
|
|
3089
|
+
async ({ kind, ref, repoPath, title }) => {
|
|
3090
|
+
const root = await resolveRepoRoot(repoPath);
|
|
3091
|
+
const existing = findLiveThreadForCreate(
|
|
3092
|
+
{
|
|
3093
|
+
sourceType: kind,
|
|
3094
|
+
sourceRef: ref.trim(),
|
|
3095
|
+
repoPath: canonicalizeRepoPath(root),
|
|
3096
|
+
title: title?.trim()
|
|
3097
|
+
},
|
|
3098
|
+
orch.getThreads(false).map((t) => ({
|
|
3099
|
+
...t,
|
|
3100
|
+
repoPath: canonicalizeRepoPath(t.repoPath)
|
|
3101
|
+
}))
|
|
3102
|
+
);
|
|
3103
|
+
if (existing) {
|
|
2606
3104
|
return {
|
|
2607
3105
|
content: [
|
|
2608
3106
|
{
|
|
2609
3107
|
type: "text",
|
|
2610
3108
|
text: JSON.stringify({
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
model: thread.model,
|
|
2617
|
-
status: thread.status,
|
|
2618
|
-
cowboy: Boolean(thread.cowboy),
|
|
2619
|
-
link: `sideboard://thread/${thread.id}`,
|
|
2620
|
-
parentThreadId: thread.parentThreadId,
|
|
2621
|
-
...agentCoercedFrom ? {
|
|
2622
|
-
agentCoercedFrom,
|
|
2623
|
-
note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
|
|
2624
|
-
} : {},
|
|
2625
|
-
...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
|
|
3109
|
+
alreadyStarted: true,
|
|
3110
|
+
id: existing.id,
|
|
3111
|
+
title: existing.title,
|
|
3112
|
+
status: existing.status,
|
|
3113
|
+
link: `sideboard://thread/${existing.id}`
|
|
2626
3114
|
})
|
|
2627
3115
|
}
|
|
2628
3116
|
]
|
|
2629
3117
|
};
|
|
2630
|
-
}
|
|
2631
|
-
|
|
3118
|
+
}
|
|
3119
|
+
const workspaces = orch.listWorkspaces();
|
|
3120
|
+
const loaded = await getHomeBoardInputs(workspaces);
|
|
3121
|
+
const pin = findBoardPin(loaded.pins, kind, ref, root);
|
|
3122
|
+
if (kind === "branch") {
|
|
3123
|
+
const sourceRef = pin?.ref === "default" ? "default" : pin?.ref ?? ref.trim();
|
|
3124
|
+
const result2 = await createOrchChildThread(
|
|
3125
|
+
orch,
|
|
3126
|
+
{
|
|
3127
|
+
sourceType: "branch",
|
|
3128
|
+
sourceRef,
|
|
3129
|
+
repoPath: root,
|
|
3130
|
+
title: title?.trim() || pin?.title || (sourceRef === "default" ? void 0 : sourceRef)
|
|
3131
|
+
},
|
|
3132
|
+
resolveNewThreadOptions2
|
|
3133
|
+
);
|
|
2632
3134
|
return {
|
|
2633
|
-
content: [
|
|
2634
|
-
|
|
2635
|
-
type: "text",
|
|
2636
|
-
text: `create_thread failed: ${message}`
|
|
2637
|
-
}
|
|
2638
|
-
],
|
|
2639
|
-
isError: true
|
|
3135
|
+
content: [{ type: "text", text: result2.text }],
|
|
3136
|
+
...result2.ok ? {} : { isError: true }
|
|
2640
3137
|
};
|
|
2641
3138
|
}
|
|
3139
|
+
if (kind === "ticket") {
|
|
3140
|
+
const issue = findBoardIssue(loaded.issues, ref, root);
|
|
3141
|
+
const ident = issue?.identifier ?? ref.trim();
|
|
3142
|
+
const attachments = issue ? [
|
|
3143
|
+
{
|
|
3144
|
+
id: randomUUID3(),
|
|
3145
|
+
name: issue.identifier,
|
|
3146
|
+
kind: "issue",
|
|
3147
|
+
content: [
|
|
3148
|
+
`Linked issue: ${issue.identifier} \u2014 ${issue.title}`,
|
|
3149
|
+
issue.url ? `URL: ${issue.url}` : null
|
|
3150
|
+
].filter(Boolean).join("\n")
|
|
3151
|
+
}
|
|
3152
|
+
] : void 0;
|
|
3153
|
+
const result2 = await createOrchChildThread(
|
|
3154
|
+
orch,
|
|
3155
|
+
{
|
|
3156
|
+
sourceType: "ticket",
|
|
3157
|
+
sourceRef: ident,
|
|
3158
|
+
repoPath: root,
|
|
3159
|
+
title: title?.trim() || issue?.title,
|
|
3160
|
+
attachments
|
|
3161
|
+
},
|
|
3162
|
+
resolveNewThreadOptions2
|
|
3163
|
+
);
|
|
3164
|
+
return {
|
|
3165
|
+
content: [{ type: "text", text: result2.text }],
|
|
3166
|
+
...result2.ok ? {} : { isError: true }
|
|
3167
|
+
};
|
|
3168
|
+
}
|
|
3169
|
+
const pr = findBoardPr(loaded.prs, ref, root);
|
|
3170
|
+
const number = pr ? String(pr.number) : ref.trim().replace(/^#/, "");
|
|
3171
|
+
const result = await createOrchChildThread(
|
|
3172
|
+
orch,
|
|
3173
|
+
{
|
|
3174
|
+
sourceType: "pr",
|
|
3175
|
+
sourceRef: number,
|
|
3176
|
+
repoPath: root,
|
|
3177
|
+
title: title?.trim() || pr?.title
|
|
3178
|
+
},
|
|
3179
|
+
resolveNewThreadOptions2
|
|
3180
|
+
);
|
|
3181
|
+
return {
|
|
3182
|
+
content: [{ type: "text", text: result.text }],
|
|
3183
|
+
...result.ok ? {} : { isError: true }
|
|
3184
|
+
};
|
|
2642
3185
|
}
|
|
2643
3186
|
);
|
|
2644
3187
|
server.tool(
|
|
@@ -3285,7 +3828,7 @@ async function startMcpServer() {
|
|
|
3285
3828
|
);
|
|
3286
3829
|
server.tool(
|
|
3287
3830
|
"list_issues",
|
|
3288
|
-
"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.",
|
|
3831
|
+
"List issues from Sideboard Account connections (Linear API or GitHub Issues; Linear\u2192GitHub fallback when Linear is not connected). Linear returns issues assigned to you (includes cycle). Pass repoPath from list_workspaces \u2014 GitHub Issues are scoped to that repo. Prefer list_board for Home columns + current-cycle filter. Then create_thread with sourceType=ticket.",
|
|
3289
3832
|
{ repoPath: z4.string() },
|
|
3290
3833
|
async ({ repoPath }) => {
|
|
3291
3834
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -3627,14 +4170,14 @@ async function runCloudConnect(opts) {
|
|
|
3627
4170
|
}
|
|
3628
4171
|
|
|
3629
4172
|
// src/agents/user-mcp-config.ts
|
|
3630
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4173
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
3631
4174
|
import { homedir } from "os";
|
|
3632
|
-
import { dirname, join } from "path";
|
|
4175
|
+
import { dirname, join as join3 } from "path";
|
|
3633
4176
|
function userCursorMcpConfigPath() {
|
|
3634
|
-
return
|
|
4177
|
+
return join3(homedir(), ".cursor", "mcp.json");
|
|
3635
4178
|
}
|
|
3636
4179
|
function userClaudeMcpConfigPath() {
|
|
3637
|
-
return
|
|
4180
|
+
return join3(homedir(), ".claude.json");
|
|
3638
4181
|
}
|
|
3639
4182
|
function asObject(value) {
|
|
3640
4183
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -3661,16 +4204,16 @@ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
|
|
|
3661
4204
|
}
|
|
3662
4205
|
function writeMergedMcpServersJson(configPath, sideboard) {
|
|
3663
4206
|
let existing = {};
|
|
3664
|
-
if (
|
|
4207
|
+
if (existsSync3(configPath)) {
|
|
3665
4208
|
try {
|
|
3666
|
-
existing = JSON.parse(
|
|
4209
|
+
existing = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
3667
4210
|
} catch {
|
|
3668
4211
|
existing = {};
|
|
3669
4212
|
}
|
|
3670
4213
|
}
|
|
3671
4214
|
const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
|
|
3672
|
-
|
|
3673
|
-
|
|
4215
|
+
mkdirSync3(dirname(configPath), { recursive: true });
|
|
4216
|
+
writeFileSync3(configPath, `${JSON.stringify(next, null, 2)}
|
|
3674
4217
|
`);
|
|
3675
4218
|
}
|
|
3676
4219
|
function launchFromResolved(server) {
|
|
@@ -3688,7 +4231,7 @@ async function registerPackagedUserMcpClients() {
|
|
|
3688
4231
|
const cursor = userCursorMcpConfigPath();
|
|
3689
4232
|
writeMergedMcpServersJson(cursor, launch);
|
|
3690
4233
|
const claude = userClaudeMcpConfigPath();
|
|
3691
|
-
if (
|
|
4234
|
+
if (existsSync3(claude)) {
|
|
3692
4235
|
writeMergedMcpServersJson(claude, launch);
|
|
3693
4236
|
return { cursor, claude };
|
|
3694
4237
|
}
|
|
@@ -5617,6 +6160,8 @@ export {
|
|
|
5617
6160
|
GITHUB_GIT_AUTH_MODES,
|
|
5618
6161
|
GLOBAL_WORKSPACE_ID,
|
|
5619
6162
|
HARNESS_ENV_KEYS,
|
|
6163
|
+
HOME_BOARD_CACHE_TTL_MS,
|
|
6164
|
+
ISSUE_SOURCE_LABELS,
|
|
5620
6165
|
LEGACY_ATTACHMENTS_DIR,
|
|
5621
6166
|
LEGACY_PLAN_FILE_REL,
|
|
5622
6167
|
LEGACY_REVIEW_REQUEST_PATH,
|
|
@@ -5658,6 +6203,7 @@ export {
|
|
|
5658
6203
|
THINKING_EFFORTS,
|
|
5659
6204
|
WORKTREE_MCP_TOOLS,
|
|
5660
6205
|
ackSlackInboundSeen,
|
|
6206
|
+
addBoardPin,
|
|
5661
6207
|
addPrStackLayer,
|
|
5662
6208
|
addStackLayerFromThread,
|
|
5663
6209
|
addWorkspace,
|
|
@@ -5711,15 +6257,19 @@ export {
|
|
|
5711
6257
|
caffeinateWhileRunningEnabled,
|
|
5712
6258
|
caffeinateWhileSchedulesEnabled,
|
|
5713
6259
|
caffeinateWhileSlackListenEnabled,
|
|
6260
|
+
canonicalizeRepoPath,
|
|
5714
6261
|
captureLoginEnv,
|
|
5715
6262
|
captureTurnBaseline,
|
|
5716
6263
|
checkoutPrStackLayer,
|
|
5717
6264
|
childEnvWithAppSettings,
|
|
5718
6265
|
claimDesktopHost,
|
|
6266
|
+
classifyWorktreeColumn,
|
|
5719
6267
|
claudeAdapter,
|
|
5720
6268
|
claudeChromeEnabled,
|
|
5721
6269
|
claudeUserSettingsPath,
|
|
5722
6270
|
cleanupOrphanWorktrees,
|
|
6271
|
+
clearBoardPins,
|
|
6272
|
+
clearHomeBoardCache,
|
|
5723
6273
|
cloneRepoIntoSideboard,
|
|
5724
6274
|
codexAdapter,
|
|
5725
6275
|
codexSandboxWritableRootsArgs,
|
|
@@ -5792,6 +6342,7 @@ export {
|
|
|
5792
6342
|
finalizeParts,
|
|
5793
6343
|
findConventionSetup,
|
|
5794
6344
|
findInvalidCacheControlTtlOrder,
|
|
6345
|
+
findLiveThreadForCreate,
|
|
5795
6346
|
findOrphanWorktrees,
|
|
5796
6347
|
findSlackCoordinator,
|
|
5797
6348
|
findThreadByRef,
|
|
@@ -5843,6 +6394,7 @@ export {
|
|
|
5843
6394
|
getGitHubStatus,
|
|
5844
6395
|
getGithubGitAuthMode,
|
|
5845
6396
|
getGithubPat,
|
|
6397
|
+
getHomeBoardInputs,
|
|
5846
6398
|
getIssueSource,
|
|
5847
6399
|
getLinearApiKey,
|
|
5848
6400
|
getLinearAuthToken,
|
|
@@ -5865,6 +6417,7 @@ export {
|
|
|
5865
6417
|
git,
|
|
5866
6418
|
githubAgentGitEnv,
|
|
5867
6419
|
globalAgentCwd,
|
|
6420
|
+
groupHomeBoardWorktrees,
|
|
5868
6421
|
handleSlackInbound,
|
|
5869
6422
|
harnessEnvKey,
|
|
5870
6423
|
hasBakedLinearOAuth,
|
|
@@ -5898,9 +6451,11 @@ export {
|
|
|
5898
6451
|
isGhRateLimitError,
|
|
5899
6452
|
isGlobalRepoPath,
|
|
5900
6453
|
isGlobalThread,
|
|
6454
|
+
isHomeBoardThread,
|
|
5901
6455
|
isImageFilePath,
|
|
5902
6456
|
isInPrStack,
|
|
5903
6457
|
isInboundForThisDesktop,
|
|
6458
|
+
isIssueSourceConnected,
|
|
5904
6459
|
isLinearConnected,
|
|
5905
6460
|
isLinearOAuthCancelled,
|
|
5906
6461
|
isOrchestratorCapableAgent,
|
|
@@ -5923,12 +6478,16 @@ export {
|
|
|
5923
6478
|
isThreadCaffeinated,
|
|
5924
6479
|
isThreadRecordFile,
|
|
5925
6480
|
isWorkspaceScratchPath,
|
|
6481
|
+
issueSourceLabel,
|
|
5926
6482
|
lastRequestOccupancy,
|
|
6483
|
+
latestPendingPlanQuestions,
|
|
5927
6484
|
linearAuthorizationHeader,
|
|
6485
|
+
linearCycleIsActive,
|
|
5928
6486
|
linearGraphql,
|
|
5929
6487
|
linearOAuthAuthorizeUrl,
|
|
5930
6488
|
linearOAuthCredentials,
|
|
5931
6489
|
listAgentSetupInfo,
|
|
6490
|
+
listBoardPins,
|
|
5932
6491
|
listBranchCommits,
|
|
5933
6492
|
listBranches,
|
|
5934
6493
|
listBrightsyAccounts,
|
|
@@ -5940,6 +6499,7 @@ export {
|
|
|
5940
6499
|
listGitHubIssues,
|
|
5941
6500
|
listGlobalThreads,
|
|
5942
6501
|
listIssues,
|
|
6502
|
+
listLinearAssignedIssues,
|
|
5943
6503
|
listLinearIssues,
|
|
5944
6504
|
listLinearIssuesDirect,
|
|
5945
6505
|
listLinearTeams,
|
|
@@ -5959,6 +6519,7 @@ export {
|
|
|
5959
6519
|
loadAppSettings,
|
|
5960
6520
|
loadBrightsyConfig,
|
|
5961
6521
|
loadConductorSettings,
|
|
6522
|
+
loadHomeBoardInputs,
|
|
5962
6523
|
loadRepoSettings,
|
|
5963
6524
|
loadWorkspaceSettings,
|
|
5964
6525
|
locksDir,
|
|
@@ -6007,6 +6568,7 @@ export {
|
|
|
6007
6568
|
permissionMode,
|
|
6008
6569
|
persistVaultKeyInKeychain,
|
|
6009
6570
|
planFileAbs,
|
|
6571
|
+
planQuestionsSignature,
|
|
6010
6572
|
pollSlackOutboundWatches,
|
|
6011
6573
|
posixShellSingleQuote,
|
|
6012
6574
|
preferredCursorCostCents,
|
|
@@ -6028,6 +6590,7 @@ export {
|
|
|
6028
6590
|
registerPackagedUserMcpClients,
|
|
6029
6591
|
releaseCaffeinateHoldForThread,
|
|
6030
6592
|
releaseDesktopHost,
|
|
6593
|
+
removeBoardPin,
|
|
6031
6594
|
removeWorkspace,
|
|
6032
6595
|
removeWorktree,
|
|
6033
6596
|
repoSlug,
|
|
@@ -6174,6 +6737,7 @@ export {
|
|
|
6174
6737
|
withMaxOldSpaceSize,
|
|
6175
6738
|
withThreadLock,
|
|
6176
6739
|
workspaceSettingsSourceLabel,
|
|
6740
|
+
worktreeBoardStatus,
|
|
6177
6741
|
worktreeCleanupSettings,
|
|
6178
6742
|
worktreeDisplayLabel,
|
|
6179
6743
|
worktreeDisplayLabelForGroup,
|