@sideboard-ai/core 0.1.130 → 0.1.133
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/abletime-DDTV7WO3.js +36 -0
- package/dist/abletime-VTP4JR63.js +37 -0
- package/dist/agents/cursor-runner.js +1 -1
- package/dist/{agents-7BUQY2WX.js → agents-NHS6P25H.js} +8 -6
- package/dist/{agents-X2I3RNCY.js → agents-SOU5GPWI.js} +9 -7
- package/dist/{app-settings-6RPALX4J.js → app-settings-U5RZKUXG.js} +11 -1
- package/dist/{app-settings-E7NEQY7D.js → app-settings-YQ7YX2CC.js} +11 -1
- package/dist/chunk-2XXAAIN3.js +463 -0
- package/dist/{chunk-VE22NWBD.js → chunk-3UVVWNHF.js} +2 -2
- package/dist/{chunk-NV73AO7Q.js → chunk-4YAVXWFR.js} +21 -9
- package/dist/{chunk-RSFCB23A.js → chunk-6CRKPD4C.js} +4 -3
- package/dist/chunk-6GN5WPYZ.js +31 -0
- package/dist/{chunk-ZMUOPTKZ.js → chunk-AK7SWE2U.js} +55 -12
- package/dist/chunk-AT346U23.js +468 -0
- package/dist/{chunk-YMRT2DU6.js → chunk-ED4UPEJX.js} +25 -50
- package/dist/chunk-ELBYOGVA.js +32 -0
- package/dist/{chunk-IUJOI7KK.js → chunk-FSCQXMGI.js} +35 -4
- package/dist/{chunk-HUYEU4GS.js → chunk-GJBHOJCZ.js} +83 -2
- package/dist/{chunk-ZND6XV6J.js → chunk-GKKHXZCT.js} +83 -2
- package/dist/{chunk-HZPO3SSZ.js → chunk-IM36S4HZ.js} +4 -3
- package/dist/{chunk-EKIDHL2T.js → chunk-KBWND62T.js} +32 -55
- package/dist/{chunk-HULESWLI.js → chunk-LTP7GHIF.js} +3 -3
- package/dist/chunk-M267JPEA.js +103 -0
- package/dist/{chunk-HRSBZIXS.js → chunk-Q6XQXCOM.js} +1 -1
- package/dist/chunk-S42XV45P.js +104 -0
- package/dist/{chunk-YALVX3UE.js → chunk-TG7YU2KG.js} +157 -40
- package/dist/{chunk-FMBLOOAO.js → chunk-VSON7EJ6.js} +155 -39
- package/dist/{chunk-UDQI3N47.js → chunk-WEU5M7BW.js} +1 -1
- package/dist/{chunk-SYLTXDRF.js → chunk-Y645NFYN.js} +2 -2
- package/dist/{chunk-MNL4FSKY.js → chunk-YEIH7P7D.js} +3 -3
- package/dist/{connected-teams-ZCOU6KCD.js → connected-teams-4A2AXDNN.js} +3 -1
- package/dist/{connected-teams-O6D4PM7A.js → connected-teams-IJUJQ7R6.js} +3 -1
- package/dist/{coordinator-prompt-SPJSGAQS.js → coordinator-prompt-DXHEDRRN.js} +3 -3
- package/dist/{coordinator-prompt-MEEUOEF2.js → coordinator-prompt-XF7LVOUN.js} +3 -3
- package/dist/{global-workspace-KNESLWKG.js → global-workspace-2LO5ATOH.js} +4 -4
- package/dist/{global-workspace-BMWP7YZC.js → global-workspace-MLQNULOU.js} +4 -4
- package/dist/index.cjs +1410 -425
- package/dist/index.d.cts +224 -16
- package/dist/index.d.ts +224 -16
- package/dist/index.js +461 -292
- package/dist/mcp/run-stdio.cjs +1261 -342
- package/dist/mcp/run-stdio.js +340 -209
- package/dist/oauth-A7XXI2TM.js +11 -0
- package/dist/oauth-YJBAURIJ.js +13 -0
- package/dist/{orchestrator-3ZSFTG72.js → orchestrator-KR5RA5B7.js} +10 -8
- package/dist/{orchestrator-G6DU3AF3.js → orchestrator-P2SYHVLS.js} +11 -9
- package/dist/{workspaces-O4QZOASB.js → workspaces-ARWPZG6F.js} +5 -5
- package/dist/{workspaces-HSYRYJYV.js → workspaces-MINB764G.js} +5 -5
- package/dist/{worktree-ERHC7Q4F.js → worktree-EBZMUUAL.js} +2 -2
- package/dist/{worktree-JVGSLSLJ.js → worktree-S7MKMYAT.js} +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CONTEXT_KEEP_RECENT_CHARS,
|
|
6
6
|
CONTEXT_KEEP_RECENT_MESSAGES,
|
|
7
7
|
CONTEXT_MIN_MESSAGES,
|
|
8
|
+
DEFAULT_WORKTREE_SORT,
|
|
8
9
|
HOME_BOARD_AGENT_HINT,
|
|
9
10
|
HOME_BOARD_CACHE_TTL_MS,
|
|
10
11
|
LEGACY_REVIEW_REQUEST_PATH,
|
|
@@ -106,6 +107,7 @@ import {
|
|
|
106
107
|
initStackFromThread,
|
|
107
108
|
initializeGitRepository,
|
|
108
109
|
inspectGitWorktree,
|
|
110
|
+
isAccountWideIssueSource,
|
|
109
111
|
isCowboyThread,
|
|
110
112
|
isDesktopHostAlive,
|
|
111
113
|
isHomeBoardThread,
|
|
@@ -185,7 +187,7 @@ import {
|
|
|
185
187
|
worktreeCleanupSettings,
|
|
186
188
|
wrapReviewSkillMarkdown,
|
|
187
189
|
writeWorktreeFile
|
|
188
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-TG7YU2KG.js";
|
|
189
191
|
import {
|
|
190
192
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
191
193
|
CLAUDE_MODEL_CATALOG,
|
|
@@ -264,26 +266,32 @@ import {
|
|
|
264
266
|
withEventParentId,
|
|
265
267
|
withEventsParentId,
|
|
266
268
|
writeInjectedMcpConfig
|
|
267
|
-
} from "./chunk-
|
|
269
|
+
} from "./chunk-4YAVXWFR.js";
|
|
268
270
|
import {
|
|
269
|
-
brightsyConfigPath,
|
|
270
271
|
brightsyMcpServerName,
|
|
271
272
|
connectBrightsyTeam,
|
|
272
273
|
disconnectBrightsyTeam,
|
|
274
|
+
ensureConnectedBrightsyTeamTokens,
|
|
273
275
|
getBrightsySession,
|
|
274
276
|
listBrightsyAccounts,
|
|
275
277
|
listConnectedBrightsyTeams,
|
|
276
|
-
loadBrightsyConfig,
|
|
277
|
-
saveBrightsyConfig,
|
|
278
278
|
switchBrightsyAccount
|
|
279
|
-
} from "./chunk-
|
|
279
|
+
} from "./chunk-KBWND62T.js";
|
|
280
|
+
import {
|
|
281
|
+
brightsyAccessTokenNeedsRefresh,
|
|
282
|
+
brightsyConfigPath,
|
|
283
|
+
ensureBrightsyLocalConfigFresh,
|
|
284
|
+
loadBrightsyConfig,
|
|
285
|
+
refreshBrightsyAccessToken,
|
|
286
|
+
saveBrightsyConfig
|
|
287
|
+
} from "./chunk-M267JPEA.js";
|
|
280
288
|
import {
|
|
281
289
|
addWorkspace,
|
|
282
290
|
ensureWorkspace,
|
|
283
291
|
listWorkspaces,
|
|
284
292
|
removeWorkspace,
|
|
285
293
|
syncWorkspacesFromThreads
|
|
286
|
-
} from "./chunk-
|
|
294
|
+
} from "./chunk-3UVVWNHF.js";
|
|
287
295
|
import {
|
|
288
296
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
289
297
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -311,7 +319,7 @@ import {
|
|
|
311
319
|
parseForceStopMessage,
|
|
312
320
|
slackCoordinatorSourceRef,
|
|
313
321
|
takenTeamSlugsForOrchestration
|
|
314
|
-
} from "./chunk-
|
|
322
|
+
} from "./chunk-LTP7GHIF.js";
|
|
315
323
|
import {
|
|
316
324
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
317
325
|
SLACK_REPLY_FORMATTING,
|
|
@@ -320,7 +328,34 @@ import {
|
|
|
320
328
|
enrichWorkspacesWithGithub,
|
|
321
329
|
ensureGlobalCoordinatorCwd,
|
|
322
330
|
formatWorkspaceInventory
|
|
323
|
-
} from "./chunk-
|
|
331
|
+
} from "./chunk-IM36S4HZ.js";
|
|
332
|
+
import {
|
|
333
|
+
ABLETIME_MCP_PATH,
|
|
334
|
+
DEFAULT_ABLETIME_HOST,
|
|
335
|
+
abletimeMcpRequest,
|
|
336
|
+
abletimeMcpUrl,
|
|
337
|
+
callAbleTimeTool,
|
|
338
|
+
createAbleTimeTask,
|
|
339
|
+
ensureAbleTimeTask,
|
|
340
|
+
getAbleTimeOrientation,
|
|
341
|
+
getAbleTimeTask,
|
|
342
|
+
issueAttachmentForAbleTimeTask,
|
|
343
|
+
listAbleTimeAssignedIssues,
|
|
344
|
+
listAbleTimeProjects,
|
|
345
|
+
listAbleTimeTasks,
|
|
346
|
+
mapAbleTimeTask,
|
|
347
|
+
normalizeAbleTimeHost,
|
|
348
|
+
rewriteAbleTimeError,
|
|
349
|
+
searchAbleTimeTasks,
|
|
350
|
+
taskUrl,
|
|
351
|
+
toAbleTimeIssueInfo,
|
|
352
|
+
verifyAbleTimeConnection
|
|
353
|
+
} from "./chunk-AT346U23.js";
|
|
354
|
+
import {
|
|
355
|
+
formatFetchError,
|
|
356
|
+
httpFetch,
|
|
357
|
+
setHttpFetchImpl
|
|
358
|
+
} from "./chunk-ELBYOGVA.js";
|
|
324
359
|
import {
|
|
325
360
|
LEGACY_PLAN_FILE_REL,
|
|
326
361
|
PLAN_FILE_NAME,
|
|
@@ -341,7 +376,7 @@ import {
|
|
|
341
376
|
preferredCursorCostCents,
|
|
342
377
|
turnCostUsdFromCursorUsage,
|
|
343
378
|
withMaxOldSpaceSize
|
|
344
|
-
} from "./chunk-
|
|
379
|
+
} from "./chunk-FSCQXMGI.js";
|
|
345
380
|
import {
|
|
346
381
|
caffeinateHoldPath,
|
|
347
382
|
getCaffeinateHold,
|
|
@@ -430,7 +465,7 @@ import {
|
|
|
430
465
|
worktreeDisplayLabel,
|
|
431
466
|
worktreeDisplayLabelForGroup,
|
|
432
467
|
worktreeNameFromPath
|
|
433
|
-
} from "./chunk-
|
|
468
|
+
} from "./chunk-WEU5M7BW.js";
|
|
434
469
|
import {
|
|
435
470
|
ATTACHMENTS_DIR,
|
|
436
471
|
LEGACY_ATTACHMENTS_DIR,
|
|
@@ -459,8 +494,11 @@ import {
|
|
|
459
494
|
claudeUserSettingsPath,
|
|
460
495
|
cowboyModeEnabled,
|
|
461
496
|
deleteBranchOnPurgeEnabled,
|
|
497
|
+
disconnectAbleTimeConnection,
|
|
462
498
|
disconnectLinearConnection,
|
|
463
499
|
ensureSlackDeviceIdentity,
|
|
500
|
+
getAbleTimeAccessToken,
|
|
501
|
+
getAbleTimeHost,
|
|
464
502
|
getDefaultAgent,
|
|
465
503
|
getDefaultEffort,
|
|
466
504
|
getDefaultFast,
|
|
@@ -470,6 +508,7 @@ import {
|
|
|
470
508
|
getIssueSource,
|
|
471
509
|
getLinearApiKey,
|
|
472
510
|
harnessEnvKey,
|
|
511
|
+
isAbleTimeConnected,
|
|
473
512
|
isIssueSourceConnected,
|
|
474
513
|
isLinearConnected,
|
|
475
514
|
issueSourceLabel,
|
|
@@ -485,6 +524,7 @@ import {
|
|
|
485
524
|
resolveNewThreadOptions,
|
|
486
525
|
resolveThreadDefaults,
|
|
487
526
|
resolveVaultKey,
|
|
527
|
+
saveAbleTimeConnection,
|
|
488
528
|
saveAppSettings,
|
|
489
529
|
saveLinearOAuth,
|
|
490
530
|
secureFileUnlocksWith,
|
|
@@ -502,7 +542,7 @@ import {
|
|
|
502
542
|
updateDefaultsSettings,
|
|
503
543
|
updateIntegrationsSettings,
|
|
504
544
|
updateOpencodeSettings
|
|
505
|
-
} from "./chunk-
|
|
545
|
+
} from "./chunk-GJBHOJCZ.js";
|
|
506
546
|
import {
|
|
507
547
|
stripNestedElectronEnv
|
|
508
548
|
} from "./chunk-4TR3HZFT.js";
|
|
@@ -598,9 +638,9 @@ async function getGitHubStatus() {
|
|
|
598
638
|
};
|
|
599
639
|
}
|
|
600
640
|
const status = await run("gh", ["auth", "status"], { reject: false });
|
|
601
|
-
const
|
|
641
|
+
const text5 = `${status.stdout}
|
|
602
642
|
${status.stderr}`;
|
|
603
|
-
const loginMatch =
|
|
643
|
+
const loginMatch = text5.match(/Logged in to ([^\s]+) account (\S+)/i) ?? text5.match(/Logged in to ([^\s]+) as (\S+)/i);
|
|
604
644
|
if (loginMatch) {
|
|
605
645
|
return {
|
|
606
646
|
connected: true,
|
|
@@ -620,33 +660,6 @@ async function refreshGitHubAuth() {
|
|
|
620
660
|
return getGitHubStatus();
|
|
621
661
|
}
|
|
622
662
|
|
|
623
|
-
// src/http/fetch.ts
|
|
624
|
-
var injected = null;
|
|
625
|
-
function setHttpFetchImpl(fetchImpl) {
|
|
626
|
-
injected = fetchImpl;
|
|
627
|
-
}
|
|
628
|
-
function formatFetchError(err, url) {
|
|
629
|
-
if (!(err instanceof Error)) return `${String(err)} (${url})`;
|
|
630
|
-
const cause = err.cause;
|
|
631
|
-
let detail = "";
|
|
632
|
-
if (cause instanceof Error) {
|
|
633
|
-
const code = typeof cause.code === "string" ? cause.code : void 0;
|
|
634
|
-
detail = code ? ` [${code}: ${cause.message}]` : ` [${cause.message}]`;
|
|
635
|
-
} else if (cause != null) {
|
|
636
|
-
detail = ` [${String(cause)}]`;
|
|
637
|
-
}
|
|
638
|
-
return `${err.message}${detail} (${url})`;
|
|
639
|
-
}
|
|
640
|
-
async function httpFetch(input, init) {
|
|
641
|
-
const url = typeof input === "string" ? input : input.href;
|
|
642
|
-
const fn = injected ?? globalThis.fetch.bind(globalThis);
|
|
643
|
-
try {
|
|
644
|
-
return await fn(url, init);
|
|
645
|
-
} catch (err) {
|
|
646
|
-
throw new Error(formatFetchError(err, url));
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
663
|
// src/integrations/linear-oauth.ts
|
|
651
664
|
import { createHash, randomBytes } from "crypto";
|
|
652
665
|
import { createServer } from "http";
|
|
@@ -1328,6 +1341,7 @@ async function listIssues(repoPath) {
|
|
|
1328
1341
|
const settings = loadAppSettings();
|
|
1329
1342
|
const preferredSource = settings.integrations.issueSource ?? "github";
|
|
1330
1343
|
const linearConnected = isLinearConnected(settings);
|
|
1344
|
+
const abletimeConnected = isAbleTimeConnected(settings);
|
|
1331
1345
|
const source = resolveEffectiveIssueSource(settings);
|
|
1332
1346
|
if (source === "linear") {
|
|
1333
1347
|
const listed = await listLinearAssignedIssues();
|
|
@@ -1335,6 +1349,21 @@ async function listIssues(repoPath) {
|
|
|
1335
1349
|
source,
|
|
1336
1350
|
preferredSource,
|
|
1337
1351
|
linearConnected,
|
|
1352
|
+
abletimeConnected,
|
|
1353
|
+
issues: listed.issues,
|
|
1354
|
+
viewer: {
|
|
1355
|
+
login: listed.viewer.name,
|
|
1356
|
+
name: listed.viewer.name
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
if (source === "abletime") {
|
|
1361
|
+
const listed = await listAbleTimeAssignedIssues();
|
|
1362
|
+
return {
|
|
1363
|
+
source,
|
|
1364
|
+
preferredSource,
|
|
1365
|
+
linearConnected,
|
|
1366
|
+
abletimeConnected,
|
|
1338
1367
|
issues: listed.issues,
|
|
1339
1368
|
viewer: {
|
|
1340
1369
|
login: listed.viewer.name,
|
|
@@ -1350,6 +1379,7 @@ async function listIssues(repoPath) {
|
|
|
1350
1379
|
source,
|
|
1351
1380
|
preferredSource,
|
|
1352
1381
|
linearConnected,
|
|
1382
|
+
abletimeConnected,
|
|
1353
1383
|
issues,
|
|
1354
1384
|
viewer: login ? { login } : void 0
|
|
1355
1385
|
};
|
|
@@ -1409,16 +1439,16 @@ var PASTE_ATTACH_MIN_CHARS = 1200;
|
|
|
1409
1439
|
var PASTE_ATTACH_MIN_LINES = 15;
|
|
1410
1440
|
var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
|
|
1411
1441
|
var PASTED_NAME_ALT_RE = /^pasted-(\d+)\.txt$/i;
|
|
1412
|
-
function pastedTextStats(
|
|
1413
|
-
const chars =
|
|
1442
|
+
function pastedTextStats(text5) {
|
|
1443
|
+
const chars = text5.length;
|
|
1414
1444
|
if (chars === 0) return { chars: 0, lines: 0 };
|
|
1415
|
-
const lines =
|
|
1445
|
+
const lines = text5.split(/\r\n|\r|\n/).length;
|
|
1416
1446
|
return { chars, lines };
|
|
1417
1447
|
}
|
|
1418
|
-
function shouldAttachPastedText(
|
|
1419
|
-
const trimmed =
|
|
1448
|
+
function shouldAttachPastedText(text5) {
|
|
1449
|
+
const trimmed = text5.trim();
|
|
1420
1450
|
if (!trimmed) return false;
|
|
1421
|
-
const { chars, lines } = pastedTextStats(
|
|
1451
|
+
const { chars, lines } = pastedTextStats(text5);
|
|
1422
1452
|
return chars >= PASTE_ATTACH_MIN_CHARS || lines >= PASTE_ATTACH_MIN_LINES;
|
|
1423
1453
|
}
|
|
1424
1454
|
function nextPastedTextName(existing) {
|
|
@@ -1429,13 +1459,13 @@ function nextPastedTextName(existing) {
|
|
|
1429
1459
|
}
|
|
1430
1460
|
return `Pasted text #${max + 1}.txt`;
|
|
1431
1461
|
}
|
|
1432
|
-
function buildPastedTextAttachment(
|
|
1462
|
+
function buildPastedTextAttachment(text5, opts) {
|
|
1433
1463
|
return {
|
|
1434
1464
|
id: opts?.id ?? randomUUID(),
|
|
1435
1465
|
name: opts?.name ?? "Pasted text #1.txt",
|
|
1436
1466
|
kind: "file",
|
|
1437
1467
|
path: opts?.path,
|
|
1438
|
-
content:
|
|
1468
|
+
content: text5
|
|
1439
1469
|
};
|
|
1440
1470
|
}
|
|
1441
1471
|
|
|
@@ -1556,7 +1586,7 @@ function formatPlanQuestionsForChat(questions) {
|
|
|
1556
1586
|
// src/mcp/server.ts
|
|
1557
1587
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1558
1588
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1559
|
-
import { z as
|
|
1589
|
+
import { z as z5 } from "zod";
|
|
1560
1590
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1561
1591
|
import { basename } from "path";
|
|
1562
1592
|
|
|
@@ -1798,8 +1828,8 @@ function labelGithubUrl(url) {
|
|
|
1798
1828
|
}
|
|
1799
1829
|
return { kind: "other", label: "GitHub", url: raw };
|
|
1800
1830
|
}
|
|
1801
|
-
function appendGithubLink(
|
|
1802
|
-
const body =
|
|
1831
|
+
function appendGithubLink(text5, githubUrl) {
|
|
1832
|
+
const body = text5.trimEnd();
|
|
1803
1833
|
if (!githubUrl?.trim()) return body;
|
|
1804
1834
|
const labeled = labelGithubUrl(githubUrl);
|
|
1805
1835
|
if (!labeled) {
|
|
@@ -2082,7 +2112,7 @@ function registerSlackTools(server) {
|
|
|
2082
2112
|
);
|
|
2083
2113
|
}
|
|
2084
2114
|
|
|
2085
|
-
// src/mcp/
|
|
2115
|
+
// src/mcp/abletime-tools.ts
|
|
2086
2116
|
import { z as z2 } from "zod";
|
|
2087
2117
|
function text2(payload, isError = false) {
|
|
2088
2118
|
return {
|
|
@@ -2096,7 +2126,127 @@ function fail2(err) {
|
|
|
2096
2126
|
true
|
|
2097
2127
|
);
|
|
2098
2128
|
}
|
|
2099
|
-
|
|
2129
|
+
function registerAbleTimeTools(server) {
|
|
2130
|
+
server.tool(
|
|
2131
|
+
"abletime_orientation",
|
|
2132
|
+
"Call first when using AbleTime. Returns who the Account token is, open drafts, active tasks, and current projects. Requires Agent access (MCP) enabled in AbleTime.",
|
|
2133
|
+
{},
|
|
2134
|
+
async () => {
|
|
2135
|
+
try {
|
|
2136
|
+
const orientation = await getAbleTimeOrientation();
|
|
2137
|
+
return text2({
|
|
2138
|
+
viewer: orientation.viewer,
|
|
2139
|
+
projects: orientation.projects,
|
|
2140
|
+
tasks: orientation.tasks.map(toAbleTimeIssueInfo)
|
|
2141
|
+
});
|
|
2142
|
+
} catch (err) {
|
|
2143
|
+
return fail2(err);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
);
|
|
2147
|
+
server.tool(
|
|
2148
|
+
"abletime_list_projects",
|
|
2149
|
+
"List AbleTime projects (and categories) the Account token can see. Use a project id on abletime_create_task / abletime_ensure_task.",
|
|
2150
|
+
{},
|
|
2151
|
+
async () => {
|
|
2152
|
+
try {
|
|
2153
|
+
return text2({ projects: await listAbleTimeProjects() });
|
|
2154
|
+
} catch (err) {
|
|
2155
|
+
return fail2(err);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
);
|
|
2159
|
+
server.tool(
|
|
2160
|
+
"abletime_list_tasks",
|
|
2161
|
+
"List open AbleTime tasks (excludes done/archived). Optional projectId filter.",
|
|
2162
|
+
{ projectId: z2.string().optional() },
|
|
2163
|
+
async ({ projectId }) => {
|
|
2164
|
+
try {
|
|
2165
|
+
const tasks = await listAbleTimeTasks({ projectId });
|
|
2166
|
+
return text2({ issues: tasks.map(toAbleTimeIssueInfo) });
|
|
2167
|
+
} catch (err) {
|
|
2168
|
+
return fail2(err);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
);
|
|
2172
|
+
server.tool(
|
|
2173
|
+
"abletime_search_tasks",
|
|
2174
|
+
"Search AbleTime tasks by text, reference, or tag.",
|
|
2175
|
+
{ query: z2.string() },
|
|
2176
|
+
async ({ query }) => {
|
|
2177
|
+
try {
|
|
2178
|
+
const tasks = await searchAbleTimeTasks(query);
|
|
2179
|
+
return text2({ issues: tasks.map(toAbleTimeIssueInfo) });
|
|
2180
|
+
} catch (err) {
|
|
2181
|
+
return fail2(err);
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
);
|
|
2185
|
+
server.tool(
|
|
2186
|
+
"abletime_get_task",
|
|
2187
|
+
"Get one AbleTime task by id or reference (e.g. CRM-232).",
|
|
2188
|
+
{ id: z2.string() },
|
|
2189
|
+
async ({ id }) => {
|
|
2190
|
+
try {
|
|
2191
|
+
return text2(toAbleTimeIssueInfo(await getAbleTimeTask(id)));
|
|
2192
|
+
} catch (err) {
|
|
2193
|
+
return fail2(err);
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
);
|
|
2197
|
+
server.tool(
|
|
2198
|
+
"abletime_create_task",
|
|
2199
|
+
"Create an AbleTime task in a project. Call abletime_list_projects if you do not have a project id. New tasks start in todo (or backlog).",
|
|
2200
|
+
{
|
|
2201
|
+
title: z2.string(),
|
|
2202
|
+
description: z2.string().optional(),
|
|
2203
|
+
projectId: z2.string().optional(),
|
|
2204
|
+
categoryId: z2.string().optional(),
|
|
2205
|
+
state: z2.enum(["backlog", "todo"]).optional()
|
|
2206
|
+
},
|
|
2207
|
+
async (args) => {
|
|
2208
|
+
try {
|
|
2209
|
+
return text2(toAbleTimeIssueInfo(await createAbleTimeTask(args)));
|
|
2210
|
+
} catch (err) {
|
|
2211
|
+
return fail2(err);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
);
|
|
2215
|
+
server.tool(
|
|
2216
|
+
"abletime_ensure_task",
|
|
2217
|
+
"Find an open AbleTime task for this work, or create one to track against. Matches identifier or exact title before creating. Prefer this when starting work that has no ticket yet, then create_thread with sourceType=ticket and the returned identifier.",
|
|
2218
|
+
{
|
|
2219
|
+
title: z2.string(),
|
|
2220
|
+
description: z2.string().optional(),
|
|
2221
|
+
projectId: z2.string().optional(),
|
|
2222
|
+
categoryId: z2.string().optional()
|
|
2223
|
+
},
|
|
2224
|
+
async (args) => {
|
|
2225
|
+
try {
|
|
2226
|
+
const task = await ensureAbleTimeTask(args);
|
|
2227
|
+
return text2({ ...toAbleTimeIssueInfo(task), created: task.created });
|
|
2228
|
+
} catch (err) {
|
|
2229
|
+
return fail2(err);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
);
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
// src/mcp/linear-tools.ts
|
|
2236
|
+
import { z as z3 } from "zod";
|
|
2237
|
+
function text3(payload, isError = false) {
|
|
2238
|
+
return {
|
|
2239
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
2240
|
+
...isError ? { isError: true } : {}
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
function fail3(err) {
|
|
2244
|
+
return text3(
|
|
2245
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
2246
|
+
true
|
|
2247
|
+
);
|
|
2248
|
+
}
|
|
2249
|
+
var prioritySchema = z3.number().int().min(0).max(4).optional().describe("0 none, 1 urgent, 2 high, 3 medium, 4 low");
|
|
2100
2250
|
function registerLinearTools(server) {
|
|
2101
2251
|
server.tool(
|
|
2102
2252
|
"linear_list_teams",
|
|
@@ -2104,21 +2254,21 @@ function registerLinearTools(server) {
|
|
|
2104
2254
|
{},
|
|
2105
2255
|
async () => {
|
|
2106
2256
|
try {
|
|
2107
|
-
return
|
|
2257
|
+
return text3(await listLinearTeams());
|
|
2108
2258
|
} catch (err) {
|
|
2109
|
-
return
|
|
2259
|
+
return fail3(err);
|
|
2110
2260
|
}
|
|
2111
2261
|
}
|
|
2112
2262
|
);
|
|
2113
2263
|
server.tool(
|
|
2114
2264
|
"linear_get_issue",
|
|
2115
2265
|
"Get a Linear issue by uuid or identifier (ENG-123).",
|
|
2116
|
-
{ id:
|
|
2266
|
+
{ id: z3.string() },
|
|
2117
2267
|
async ({ id }) => {
|
|
2118
2268
|
try {
|
|
2119
|
-
return
|
|
2269
|
+
return text3(await getLinearIssue(id));
|
|
2120
2270
|
} catch (err) {
|
|
2121
|
-
return
|
|
2271
|
+
return fail3(err);
|
|
2122
2272
|
}
|
|
2123
2273
|
}
|
|
2124
2274
|
);
|
|
@@ -2126,18 +2276,18 @@ function registerLinearTools(server) {
|
|
|
2126
2276
|
"linear_create_issue",
|
|
2127
2277
|
'Create a Linear issue. Call linear_list_teams first. team is id, key, or name. state is name, type (unstarted/started/completed/canceled/backlog), or id. assignee is "me" or a user id.',
|
|
2128
2278
|
{
|
|
2129
|
-
team:
|
|
2130
|
-
title:
|
|
2131
|
-
description:
|
|
2132
|
-
state:
|
|
2133
|
-
assignee:
|
|
2279
|
+
team: z3.string(),
|
|
2280
|
+
title: z3.string(),
|
|
2281
|
+
description: z3.string().optional(),
|
|
2282
|
+
state: z3.string().optional(),
|
|
2283
|
+
assignee: z3.string().nullable().optional(),
|
|
2134
2284
|
priority: prioritySchema
|
|
2135
2285
|
},
|
|
2136
2286
|
async (args) => {
|
|
2137
2287
|
try {
|
|
2138
|
-
return
|
|
2288
|
+
return text3(await createLinearIssue(args));
|
|
2139
2289
|
} catch (err) {
|
|
2140
|
-
return
|
|
2290
|
+
return fail3(err);
|
|
2141
2291
|
}
|
|
2142
2292
|
}
|
|
2143
2293
|
);
|
|
@@ -2145,18 +2295,18 @@ function registerLinearTools(server) {
|
|
|
2145
2295
|
"linear_update_issue",
|
|
2146
2296
|
'Update a Linear issue (uuid or ENG-123). Pass at least one of title, description, state, assignee, priority. state is name, type, or id. assignee is "me", a user id, or null to unassign.',
|
|
2147
2297
|
{
|
|
2148
|
-
id:
|
|
2149
|
-
title:
|
|
2150
|
-
description:
|
|
2151
|
-
state:
|
|
2152
|
-
assignee:
|
|
2298
|
+
id: z3.string(),
|
|
2299
|
+
title: z3.string().optional(),
|
|
2300
|
+
description: z3.string().optional(),
|
|
2301
|
+
state: z3.string().optional(),
|
|
2302
|
+
assignee: z3.string().nullable().optional(),
|
|
2153
2303
|
priority: prioritySchema
|
|
2154
2304
|
},
|
|
2155
2305
|
async (args) => {
|
|
2156
2306
|
try {
|
|
2157
|
-
return
|
|
2307
|
+
return text3(await updateLinearIssue(args));
|
|
2158
2308
|
} catch (err) {
|
|
2159
|
-
return
|
|
2309
|
+
return fail3(err);
|
|
2160
2310
|
}
|
|
2161
2311
|
}
|
|
2162
2312
|
);
|
|
@@ -2164,29 +2314,29 @@ function registerLinearTools(server) {
|
|
|
2164
2314
|
"linear_comment",
|
|
2165
2315
|
"Add a markdown comment on a Linear issue (uuid or ENG-123).",
|
|
2166
2316
|
{
|
|
2167
|
-
id:
|
|
2168
|
-
body:
|
|
2317
|
+
id: z3.string(),
|
|
2318
|
+
body: z3.string()
|
|
2169
2319
|
},
|
|
2170
2320
|
async (args) => {
|
|
2171
2321
|
try {
|
|
2172
|
-
return
|
|
2322
|
+
return text3(await commentLinearIssue(args));
|
|
2173
2323
|
} catch (err) {
|
|
2174
|
-
return
|
|
2324
|
+
return fail3(err);
|
|
2175
2325
|
}
|
|
2176
2326
|
}
|
|
2177
2327
|
);
|
|
2178
2328
|
}
|
|
2179
2329
|
|
|
2180
2330
|
// src/mcp/schedule-tools.ts
|
|
2181
|
-
import { z as
|
|
2182
|
-
function
|
|
2331
|
+
import { z as z4 } from "zod";
|
|
2332
|
+
function text4(payload, isError = false) {
|
|
2183
2333
|
return {
|
|
2184
2334
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
2185
2335
|
...isError ? { isError: true } : {}
|
|
2186
2336
|
};
|
|
2187
2337
|
}
|
|
2188
|
-
function
|
|
2189
|
-
return
|
|
2338
|
+
function fail4(err) {
|
|
2339
|
+
return text4(
|
|
2190
2340
|
{ error: err instanceof Error ? err.message : String(err) },
|
|
2191
2341
|
true
|
|
2192
2342
|
);
|
|
@@ -2211,9 +2361,9 @@ function registerScheduleTools(server) {
|
|
|
2211
2361
|
{},
|
|
2212
2362
|
async () => {
|
|
2213
2363
|
try {
|
|
2214
|
-
return
|
|
2364
|
+
return text4({ schedules: listSchedules() });
|
|
2215
2365
|
} catch (err) {
|
|
2216
|
-
return
|
|
2366
|
+
return fail4(err);
|
|
2217
2367
|
}
|
|
2218
2368
|
}
|
|
2219
2369
|
);
|
|
@@ -2221,24 +2371,24 @@ function registerScheduleTools(server) {
|
|
|
2221
2371
|
"create_schedule",
|
|
2222
2372
|
"Create a local schedule that, when due, sends a prompt to an orchestration chat (threadId) or starts a new Global orchestration chat (omit threadId). Pass threadId=self to continue this coordinator. Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without threadId open a new chat each run. Overnight/unattended runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate. Sideboard.app must be running for the job to fire.",
|
|
2223
2373
|
{
|
|
2224
|
-
prompt:
|
|
2225
|
-
name:
|
|
2226
|
-
at:
|
|
2227
|
-
every:
|
|
2228
|
-
cron:
|
|
2229
|
-
tz:
|
|
2230
|
-
threadId:
|
|
2374
|
+
prompt: z4.string().describe("User message / goal queued when the schedule fires"),
|
|
2375
|
+
name: z4.string().optional(),
|
|
2376
|
+
at: z4.string().optional().describe("ISO datetime for a one-shot"),
|
|
2377
|
+
every: z4.string().optional().describe("Interval such as 15m, 1h, 6h, 1d"),
|
|
2378
|
+
cron: z4.string().optional().describe("5-field cron expression"),
|
|
2379
|
+
tz: z4.string().optional().describe("IANA timezone for cron (default: system)"),
|
|
2380
|
+
threadId: z4.string().optional().describe(
|
|
2231
2381
|
'Existing orchestration chat id, or "self" for this coordinator. Omit to create a new Global chat on fire.'
|
|
2232
2382
|
),
|
|
2233
|
-
agent:
|
|
2234
|
-
model:
|
|
2383
|
+
agent: z4.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
|
|
2384
|
+
model: z4.string().optional()
|
|
2235
2385
|
},
|
|
2236
2386
|
async (args) => {
|
|
2237
2387
|
try {
|
|
2238
2388
|
const when = parseWhen(args);
|
|
2239
2389
|
const threadId = resolveScheduleThreadId(args.threadId);
|
|
2240
2390
|
if (args.threadId?.trim().toLowerCase() === "self" && !threadId) {
|
|
2241
|
-
return
|
|
2391
|
+
return fail4(
|
|
2242
2392
|
new Error("threadId=self requires this turn to be an orchestration chat")
|
|
2243
2393
|
);
|
|
2244
2394
|
}
|
|
@@ -2251,12 +2401,12 @@ function registerScheduleTools(server) {
|
|
|
2251
2401
|
model: args.model,
|
|
2252
2402
|
createdBy: "mcp"
|
|
2253
2403
|
});
|
|
2254
|
-
return
|
|
2404
|
+
return text4({
|
|
2255
2405
|
schedule,
|
|
2256
2406
|
hint: "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run. Overnight runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate."
|
|
2257
2407
|
});
|
|
2258
2408
|
} catch (err) {
|
|
2259
|
-
return
|
|
2409
|
+
return fail4(err);
|
|
2260
2410
|
}
|
|
2261
2411
|
}
|
|
2262
2412
|
);
|
|
@@ -2264,17 +2414,17 @@ function registerScheduleTools(server) {
|
|
|
2264
2414
|
"update_schedule",
|
|
2265
2415
|
"Update a local schedule (prompt, cadence, target thread, enabled). Pass id from list_schedules.",
|
|
2266
2416
|
{
|
|
2267
|
-
id:
|
|
2268
|
-
prompt:
|
|
2269
|
-
name:
|
|
2270
|
-
at:
|
|
2271
|
-
every:
|
|
2272
|
-
cron:
|
|
2273
|
-
tz:
|
|
2274
|
-
threadId:
|
|
2275
|
-
agent:
|
|
2276
|
-
model:
|
|
2277
|
-
enabled:
|
|
2417
|
+
id: z4.string(),
|
|
2418
|
+
prompt: z4.string().optional(),
|
|
2419
|
+
name: z4.string().optional(),
|
|
2420
|
+
at: z4.string().optional(),
|
|
2421
|
+
every: z4.string().optional(),
|
|
2422
|
+
cron: z4.string().optional(),
|
|
2423
|
+
tz: z4.string().optional(),
|
|
2424
|
+
threadId: z4.string().optional().describe('Existing orchestration chat, "self", or empty string to create a new chat each run'),
|
|
2425
|
+
agent: z4.enum(["claude", "cursor", "codex", "opencode"]).optional(),
|
|
2426
|
+
model: z4.string().optional(),
|
|
2427
|
+
enabled: z4.boolean().optional()
|
|
2278
2428
|
},
|
|
2279
2429
|
async (args) => {
|
|
2280
2430
|
try {
|
|
@@ -2289,7 +2439,7 @@ function registerScheduleTools(server) {
|
|
|
2289
2439
|
if (args.threadId !== void 0) {
|
|
2290
2440
|
threadId = resolveScheduleThreadId(args.threadId);
|
|
2291
2441
|
if (args.threadId.trim().toLowerCase() === "self" && !threadId) {
|
|
2292
|
-
return
|
|
2442
|
+
return fail4(
|
|
2293
2443
|
new Error("threadId=self requires this turn to be an orchestration chat")
|
|
2294
2444
|
);
|
|
2295
2445
|
}
|
|
@@ -2303,38 +2453,38 @@ function registerScheduleTools(server) {
|
|
|
2303
2453
|
enabled: args.enabled,
|
|
2304
2454
|
model: args.model
|
|
2305
2455
|
});
|
|
2306
|
-
return
|
|
2456
|
+
return text4({ schedule });
|
|
2307
2457
|
} catch (err) {
|
|
2308
|
-
return
|
|
2458
|
+
return fail4(err);
|
|
2309
2459
|
}
|
|
2310
2460
|
}
|
|
2311
2461
|
);
|
|
2312
2462
|
server.tool(
|
|
2313
2463
|
"delete_schedule",
|
|
2314
2464
|
"Delete a local schedule. Pass id from list_schedules.",
|
|
2315
|
-
{ id:
|
|
2465
|
+
{ id: z4.string() },
|
|
2316
2466
|
async ({ id }) => {
|
|
2317
2467
|
try {
|
|
2318
2468
|
deleteSchedule(id);
|
|
2319
|
-
return
|
|
2469
|
+
return text4({ ok: true, id });
|
|
2320
2470
|
} catch (err) {
|
|
2321
|
-
return
|
|
2471
|
+
return fail4(err);
|
|
2322
2472
|
}
|
|
2323
2473
|
}
|
|
2324
2474
|
);
|
|
2325
2475
|
server.tool(
|
|
2326
2476
|
"run_schedule",
|
|
2327
2477
|
"Fire a schedule now (does not wait for nextRunAt). Queues the prompt or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
|
|
2328
|
-
{ id:
|
|
2478
|
+
{ id: z4.string() },
|
|
2329
2479
|
async ({ id }) => {
|
|
2330
2480
|
try {
|
|
2331
2481
|
if (!getSchedule(id)) {
|
|
2332
|
-
return
|
|
2482
|
+
return fail4(new Error(`Schedule not found: ${id}`));
|
|
2333
2483
|
}
|
|
2334
2484
|
const schedule = await fireSchedule(id);
|
|
2335
|
-
return
|
|
2485
|
+
return text4({ schedule });
|
|
2336
2486
|
} catch (err) {
|
|
2337
|
-
return
|
|
2487
|
+
return fail4(err);
|
|
2338
2488
|
}
|
|
2339
2489
|
}
|
|
2340
2490
|
);
|
|
@@ -2507,7 +2657,7 @@ async function loadHomeBoardInputs(workspaces) {
|
|
|
2507
2657
|
const first = await listIssues(paths[0]);
|
|
2508
2658
|
issueSource = first.source;
|
|
2509
2659
|
viewerLogin = first.viewer?.login || first.viewer?.name || void 0;
|
|
2510
|
-
if (first.source
|
|
2660
|
+
if (isAccountWideIssueSource(first.source)) {
|
|
2511
2661
|
const repoPath = paths[0] ?? "";
|
|
2512
2662
|
issues = first.issues.map((issue) => ({
|
|
2513
2663
|
...issue,
|
|
@@ -2735,7 +2885,7 @@ async function startMcpServer() {
|
|
|
2735
2885
|
);
|
|
2736
2886
|
}
|
|
2737
2887
|
try {
|
|
2738
|
-
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-
|
|
2888
|
+
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-U5RZKUXG.js");
|
|
2739
2889
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
2740
2890
|
} catch {
|
|
2741
2891
|
}
|
|
@@ -2793,13 +2943,13 @@ async function startMcpServer() {
|
|
|
2793
2943
|
"list_board",
|
|
2794
2944
|
"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
2945
|
{
|
|
2796
|
-
query:
|
|
2797
|
-
repoPath:
|
|
2798
|
-
kind:
|
|
2799
|
-
column:
|
|
2946
|
+
query: z5.string().optional().describe("Case-insensitive token search across title, id, labels, repo"),
|
|
2947
|
+
repoPath: z5.string().optional().describe("Limit to one workspace path from list_workspaces"),
|
|
2948
|
+
kind: z5.enum(["all", "tickets", "prs", "branches", "threads"]).optional().describe("Filter by worktree source (default all)"),
|
|
2949
|
+
column: z5.enum(["new", "draft", "review", "done", "needs_you"]).optional().describe(
|
|
2800
2950
|
"Return cards for this column only (totals still include the rest). needs_you is a legacy alias for new."
|
|
2801
2951
|
),
|
|
2802
|
-
limit:
|
|
2952
|
+
limit: z5.number().int().positive().optional().describe("Max cards per column (default 40). hidden counts the remainder.")
|
|
2803
2953
|
},
|
|
2804
2954
|
async ({ query, repoPath, kind, column, limit }) => {
|
|
2805
2955
|
const workspaces = orch.listWorkspaces();
|
|
@@ -2837,7 +2987,7 @@ async function startMcpServer() {
|
|
|
2837
2987
|
server.tool(
|
|
2838
2988
|
"get_thread",
|
|
2839
2989
|
"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.",
|
|
2840
|
-
{ ref:
|
|
2990
|
+
{ ref: z5.string() },
|
|
2841
2991
|
async ({ ref }) => {
|
|
2842
2992
|
const t = orch.getThread(ref);
|
|
2843
2993
|
if (!t) {
|
|
@@ -2874,17 +3024,17 @@ async function startMcpServer() {
|
|
|
2874
3024
|
"present_artifact",
|
|
2875
3025
|
"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.",
|
|
2876
3026
|
{
|
|
2877
|
-
title:
|
|
2878
|
-
type:
|
|
3027
|
+
title: z5.string().describe("Short title shown in the artifact pane header"),
|
|
3028
|
+
type: z5.enum(["html", "svg", "markdown", "react", "log"]).describe(
|
|
2879
3029
|
"html/svg/markdown/react replace the pane. log appends content to the same artifact_id (new lines only)."
|
|
2880
3030
|
),
|
|
2881
|
-
content:
|
|
3031
|
+
content: z5.string().describe(
|
|
2882
3032
|
"html/svg/markdown/react: full document. log: only the new lines since the last call (empty is ok for a status-only update)."
|
|
2883
3033
|
),
|
|
2884
|
-
artifact_id:
|
|
2885
|
-
status:
|
|
2886
|
-
phase:
|
|
2887
|
-
mode:
|
|
3034
|
+
artifact_id: z5.string().optional().describe("Stable id. Required for type=log so later calls append to the same pane."),
|
|
3035
|
+
status: z5.enum(["running", "ok", "failed", "idle"]).optional().describe("Log header pill: running (working), ok (done), failed, idle"),
|
|
3036
|
+
phase: z5.string().optional().describe("Log subtitle (Signing, Notarizing, \u2026)"),
|
|
3037
|
+
mode: z5.enum(["append", "replace"]).optional().describe("log only: append (default) or replace the buffer")
|
|
2888
3038
|
},
|
|
2889
3039
|
async ({ title, type, artifact_id, status, phase, mode }) => {
|
|
2890
3040
|
const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -2905,15 +3055,15 @@ async function startMcpServer() {
|
|
|
2905
3055
|
"ask_user",
|
|
2906
3056
|
"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.",
|
|
2907
3057
|
{
|
|
2908
|
-
questions:
|
|
2909
|
-
|
|
2910
|
-
question:
|
|
2911
|
-
header:
|
|
2912
|
-
multiSelect:
|
|
2913
|
-
options:
|
|
2914
|
-
|
|
2915
|
-
label:
|
|
2916
|
-
description:
|
|
3058
|
+
questions: z5.array(
|
|
3059
|
+
z5.object({
|
|
3060
|
+
question: z5.string().describe("Full question text ending with ?"),
|
|
3061
|
+
header: z5.string().max(24).optional().describe("Short label shown above the question"),
|
|
3062
|
+
multiSelect: z5.boolean().optional().describe("Allow selecting multiple options"),
|
|
3063
|
+
options: z5.array(
|
|
3064
|
+
z5.object({
|
|
3065
|
+
label: z5.string(),
|
|
3066
|
+
description: z5.string().optional().describe("What this option means / when to choose it (strongly preferred)")
|
|
2917
3067
|
})
|
|
2918
3068
|
).min(2).max(6).describe("2\u20136 choices (Sideboard also offers Other)")
|
|
2919
3069
|
})
|
|
@@ -2932,9 +3082,9 @@ async function startMcpServer() {
|
|
|
2932
3082
|
"present_plan",
|
|
2933
3083
|
"Save the implementation plan as markdown to .context/attachments/plan.md and show it in Sideboard chat for user approval (Copy / Hand off / Approve). Call this when the plan is ready \u2014 required in plan mode. Pass the full plan body in content. Then Claude should call ExitPlanMode.",
|
|
2934
3084
|
{
|
|
2935
|
-
title:
|
|
2936
|
-
content:
|
|
2937
|
-
thread_id:
|
|
3085
|
+
title: z5.string().optional().describe("Short plan title (defaults to Plan)"),
|
|
3086
|
+
content: z5.string().min(1).describe("Full plan markdown (headings, steps, risks, open questions)"),
|
|
3087
|
+
thread_id: z5.string().optional().describe("Sideboard thread id when cwd is not the worktree")
|
|
2938
3088
|
},
|
|
2939
3089
|
async ({ title, content, thread_id }) => {
|
|
2940
3090
|
const { writePlanFile: writePlanFile2 } = await import("./plan-file-6O7G4VPQ.js");
|
|
@@ -2957,15 +3107,15 @@ async function startMcpServer() {
|
|
|
2957
3107
|
"present_schema",
|
|
2958
3108
|
"Open Sideboard\u2019s schema-driven side column (filterable table and/or form) when the user needs to filter, edit, publish, or persist records. Do not call this just to re-display rows you already wrote as a markdown table. If the user asks for an editable / interactive table, call this even if chat already showed those rows. Pass JSON Schema + optional schemaUi. Prefer datasource=inline with embedded resource/records. Use datasource=brightsy with resource_id only when the user is logged into Brightsy.",
|
|
2959
3109
|
{
|
|
2960
|
-
title:
|
|
2961
|
-
mode:
|
|
2962
|
-
datasource:
|
|
2963
|
-
resource_id:
|
|
2964
|
-
record_id:
|
|
2965
|
-
resource:
|
|
2966
|
-
record:
|
|
2967
|
-
records:
|
|
2968
|
-
pane_id:
|
|
3110
|
+
title: z5.string().describe("Pane title"),
|
|
3111
|
+
mode: z5.enum(["table", "form"]).optional().describe("table = list/filter records; form = edit one record"),
|
|
3112
|
+
datasource: z5.enum(["brightsy", "inline"]).optional().describe("brightsy resolves via login; inline uses embedded resource/records"),
|
|
3113
|
+
resource_id: z5.string().optional().describe("Brightsy record type UUID (or generic resource id)"),
|
|
3114
|
+
record_id: z5.string().optional().describe("Record id when opening form mode"),
|
|
3115
|
+
resource: z5.record(z5.unknown()).optional().describe("Inline { id, title, schema, schemaUi?, slug? }"),
|
|
3116
|
+
record: z5.record(z5.unknown()).optional().describe("Inline record { id, data, published_at? }"),
|
|
3117
|
+
records: z5.array(z5.record(z5.unknown())).optional().describe("Inline records for table mode"),
|
|
3118
|
+
pane_id: z5.string().optional().describe("Stable pane id across updates")
|
|
2969
3119
|
},
|
|
2970
3120
|
async (args) => {
|
|
2971
3121
|
const id = args.pane_id?.trim() || `schema_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -2986,10 +3136,10 @@ async function startMcpServer() {
|
|
|
2986
3136
|
"present_files",
|
|
2987
3137
|
"Open Sideboard\u2019s Files column (CMS-style file manager: browse, upload, pick). Use datasource=brightsy when the user is logged into Brightsy account storage; datasource=memory for a session-local demo store. Prefer this over claiming a file manager UI is unavailable. Pair with present_schema when editing records that need media.",
|
|
2988
3138
|
{
|
|
2989
|
-
title:
|
|
2990
|
-
datasource:
|
|
2991
|
-
path:
|
|
2992
|
-
pane_id:
|
|
3139
|
+
title: z5.string().optional().describe("Pane title (default: Files)"),
|
|
3140
|
+
datasource: z5.enum(["brightsy", "memory"]).optional().describe("brightsy = account storage via login; memory = session demo store"),
|
|
3141
|
+
path: z5.string().optional().describe("Initial folder path (e.g. public)"),
|
|
3142
|
+
pane_id: z5.string().optional().describe("Stable pane id across updates")
|
|
2993
3143
|
},
|
|
2994
3144
|
async (args) => {
|
|
2995
3145
|
const id = args.pane_id?.trim() || `files_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -3007,16 +3157,17 @@ async function startMcpServer() {
|
|
|
3007
3157
|
if (!worktreeProfile) {
|
|
3008
3158
|
registerSlackTools(server);
|
|
3009
3159
|
registerLinearTools(server);
|
|
3160
|
+
registerAbleTimeTools(server);
|
|
3010
3161
|
registerScheduleTools(server);
|
|
3011
3162
|
const { getCaffeinateHold: getCaffeinateHold2, setCaffeinateHold: setCaffeinateHold2 } = await import("./caffeinate-hold-X3JNPR42.js");
|
|
3012
|
-
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-
|
|
3163
|
+
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-U5RZKUXG.js");
|
|
3013
3164
|
const accountDefaults = resolveThreadDefaults2();
|
|
3014
3165
|
const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
|
|
3015
3166
|
server.tool(
|
|
3016
3167
|
"set_caffeinate",
|
|
3017
3168
|
"Keep this Mac awake with caffeinate (like Claude Code) across turns \u2014 independent of Settings toggles. Turn ON when the user will be away from the keyboard, is driving work from Slack, or asks you to keep the machine awake. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the Mac awake. Closing or archiving this orchestration chat also releases the hold. macOS only.",
|
|
3018
3169
|
{
|
|
3019
|
-
enabled:
|
|
3170
|
+
enabled: z5.boolean().describe("true = hold caffeinate on; false = release and let the Mac sleep")
|
|
3020
3171
|
},
|
|
3021
3172
|
async ({ enabled }) => {
|
|
3022
3173
|
const threadId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
|
|
@@ -3054,18 +3205,18 @@ async function startMcpServer() {
|
|
|
3054
3205
|
"create_thread",
|
|
3055
3206
|
`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.`,
|
|
3056
3207
|
{
|
|
3057
|
-
sourceType:
|
|
3058
|
-
sourceRef:
|
|
3059
|
-
agent:
|
|
3060
|
-
model:
|
|
3208
|
+
sourceType: z5.enum(["branch", "pr", "ticket"]),
|
|
3209
|
+
sourceRef: z5.string(),
|
|
3210
|
+
agent: z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"]).optional().describe(`Omit to use Account default agent (${accountDefaults.agent})`),
|
|
3211
|
+
model: z5.string().nullable().optional().describe(
|
|
3061
3212
|
`Usually omit to use Account default model (${accountDefaults.model?.trim() || "Auto"}). Pass null only to force Auto / agent-default.`
|
|
3062
3213
|
),
|
|
3063
|
-
repoPath:
|
|
3064
|
-
title:
|
|
3065
|
-
cowboy:
|
|
3214
|
+
repoPath: z5.string(),
|
|
3215
|
+
title: z5.string().optional(),
|
|
3216
|
+
cowboy: z5.boolean().optional().describe(
|
|
3066
3217
|
"If true, work in the project folder on the default branch (no thread/* worktree). Requires Settings \u2192 Advanced \u2192 Cowboy mode. Land is commit+push to that branch. Archive does not delete the folder."
|
|
3067
3218
|
),
|
|
3068
|
-
parentThreadId:
|
|
3219
|
+
parentThreadId: z5.string().optional().describe(
|
|
3069
3220
|
"Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
|
|
3070
3221
|
)
|
|
3071
3222
|
},
|
|
@@ -3081,10 +3232,10 @@ async function startMcpServer() {
|
|
|
3081
3232
|
"start_board_card",
|
|
3082
3233
|
"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
3234
|
{
|
|
3084
|
-
kind:
|
|
3085
|
-
ref:
|
|
3086
|
-
repoPath:
|
|
3087
|
-
title:
|
|
3235
|
+
kind: z5.enum(["ticket", "pr", "branch"]),
|
|
3236
|
+
ref: z5.string().describe("Ticket identifier (ENG-12), PR number (44), or branch name from list_board"),
|
|
3237
|
+
repoPath: z5.string().describe("Workspace path from list_workspaces / list_board"),
|
|
3238
|
+
title: z5.string().optional()
|
|
3088
3239
|
},
|
|
3089
3240
|
async ({ kind, ref, repoPath, title }) => {
|
|
3090
3241
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -3188,9 +3339,9 @@ async function startMcpServer() {
|
|
|
3188
3339
|
"send_to_thread",
|
|
3189
3340
|
'Queue a prompt on a worktree thread chat (runs under concurrency cap). Use after create_thread to start or continue a conversation. For commit/push/PR, prefer ask_git (canonical desktop-button phrases). Send "Merge PR." / ask_git merge only when the user explicitly asked to merge. Set force_stop=true to interrupt an in-flight/queued turn (kill + clear queue) before queueing this prompt \u2014 use when the thread is mid-turn or has stale queued prompts you need to replace.',
|
|
3190
3341
|
{
|
|
3191
|
-
ref:
|
|
3192
|
-
prompt:
|
|
3193
|
-
force_stop:
|
|
3342
|
+
ref: z5.string(),
|
|
3343
|
+
prompt: z5.string(),
|
|
3344
|
+
force_stop: z5.boolean().optional()
|
|
3194
3345
|
},
|
|
3195
3346
|
async ({ ref, prompt, force_stop }) => {
|
|
3196
3347
|
if (force_stop) {
|
|
@@ -3219,8 +3370,8 @@ async function startMcpServer() {
|
|
|
3219
3370
|
"wait_for_turn",
|
|
3220
3371
|
"Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
|
|
3221
3372
|
{
|
|
3222
|
-
ref:
|
|
3223
|
-
timeoutMs:
|
|
3373
|
+
ref: z5.string(),
|
|
3374
|
+
timeoutMs: z5.number().optional()
|
|
3224
3375
|
},
|
|
3225
3376
|
async ({ ref, timeoutMs }) => {
|
|
3226
3377
|
const thread = await orch.waitForTurn(ref, mcpWaitForTurnTimeoutMs(timeoutMs), {
|
|
@@ -3249,7 +3400,7 @@ async function startMcpServer() {
|
|
|
3249
3400
|
server.tool(
|
|
3250
3401
|
"get_turn_result",
|
|
3251
3402
|
"Assistant message when the turn finished, or live progress while stillRunning. Not the full transcript. Includes usage for the last agent turn (tokens + costUsd when reported).",
|
|
3252
|
-
{ ref:
|
|
3403
|
+
{ ref: z5.string() },
|
|
3253
3404
|
async ({ ref }) => {
|
|
3254
3405
|
const result = orch.getTurnResult(ref);
|
|
3255
3406
|
return {
|
|
@@ -3269,8 +3420,8 @@ async function startMcpServer() {
|
|
|
3269
3420
|
"stop_thread",
|
|
3270
3421
|
"Force-stop a thread: kill any in-flight agent turn AND clear queued prompts so drainQueue cannot continue. Does not archive the worktree. Optional force defaults to true.",
|
|
3271
3422
|
{
|
|
3272
|
-
ref:
|
|
3273
|
-
force:
|
|
3423
|
+
ref: z5.string(),
|
|
3424
|
+
force: z5.boolean().optional()
|
|
3274
3425
|
},
|
|
3275
3426
|
async ({ ref, force }) => {
|
|
3276
3427
|
const t = orch.getThread(ref);
|
|
@@ -3300,7 +3451,7 @@ async function startMcpServer() {
|
|
|
3300
3451
|
server.tool(
|
|
3301
3452
|
"archive_thread",
|
|
3302
3453
|
"Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Coordinators commit, push, and open PRs by asking the worktree agent (ask_git). Merge only when the user explicitly asked.",
|
|
3303
|
-
{ ref:
|
|
3454
|
+
{ ref: z5.string() },
|
|
3304
3455
|
async ({ ref }) => {
|
|
3305
3456
|
const t = orch.getThread(ref);
|
|
3306
3457
|
if (!t) {
|
|
@@ -3333,7 +3484,7 @@ async function startMcpServer() {
|
|
|
3333
3484
|
server.tool(
|
|
3334
3485
|
"restore_thread",
|
|
3335
3486
|
"Restore an archived thread (recreates worktree from branch when needed)",
|
|
3336
|
-
{ ref:
|
|
3487
|
+
{ ref: z5.string() },
|
|
3337
3488
|
async ({ ref }) => {
|
|
3338
3489
|
try {
|
|
3339
3490
|
const restored = await orch.restore(ref);
|
|
@@ -3359,8 +3510,8 @@ async function startMcpServer() {
|
|
|
3359
3510
|
"get_diff",
|
|
3360
3511
|
"Compact diff summary (capped hunks, paginated)",
|
|
3361
3512
|
{
|
|
3362
|
-
ref:
|
|
3363
|
-
maxFiles:
|
|
3513
|
+
ref: z5.string(),
|
|
3514
|
+
maxFiles: z5.number().optional()
|
|
3364
3515
|
},
|
|
3365
3516
|
async ({ ref, maxFiles }) => {
|
|
3366
3517
|
const summary = await orch.diffSummary(ref);
|
|
@@ -3380,7 +3531,7 @@ async function startMcpServer() {
|
|
|
3380
3531
|
server.tool(
|
|
3381
3532
|
"request_review",
|
|
3382
3533
|
'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .claude/skills/review/SKILL.md when present (else seeds that skill from .sideboard/review.md or the stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn (loop while stillRunning) / get_turn_result on the returned review tab id.',
|
|
3383
|
-
{ ref:
|
|
3534
|
+
{ ref: z5.string().describe("Worktree thread id/ref to review") },
|
|
3384
3535
|
async ({ ref }) => {
|
|
3385
3536
|
try {
|
|
3386
3537
|
const tab = await orch.requestReview(ref);
|
|
@@ -3409,8 +3560,8 @@ async function startMcpServer() {
|
|
|
3409
3560
|
"ask_git",
|
|
3410
3561
|
"Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` if SSH is missing). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd.",
|
|
3411
3562
|
{
|
|
3412
|
-
ref:
|
|
3413
|
-
action:
|
|
3563
|
+
ref: z5.string().describe("Worktree thread id/ref"),
|
|
3564
|
+
action: z5.enum(AGENT_GIT_ACTIONS).describe(
|
|
3414
3565
|
"commit-push | create-draft | create-web | resolve-conflicts | merge"
|
|
3415
3566
|
)
|
|
3416
3567
|
},
|
|
@@ -3437,7 +3588,7 @@ async function startMcpServer() {
|
|
|
3437
3588
|
}
|
|
3438
3589
|
}
|
|
3439
3590
|
);
|
|
3440
|
-
const agentEnum =
|
|
3591
|
+
const agentEnum = z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"]);
|
|
3441
3592
|
server.tool(
|
|
3442
3593
|
"list_models",
|
|
3443
3594
|
"List models for an agent. Prefer Auto: do not call this unless you have a reason to pin a specific model (user request, cost/latency, capability). Omit agent to list all.",
|
|
@@ -3460,11 +3611,11 @@ async function startMcpServer() {
|
|
|
3460
3611
|
"fork_worktree",
|
|
3461
3612
|
"Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then send_to_thread / wait_for_turn (loop while stillRunning) on the returned id.",
|
|
3462
3613
|
{
|
|
3463
|
-
ref:
|
|
3464
|
-
through_index:
|
|
3614
|
+
ref: z5.string().describe("Worktree thread id/ref to fork"),
|
|
3615
|
+
through_index: z5.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
3465
3616
|
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
3466
|
-
model:
|
|
3467
|
-
title:
|
|
3617
|
+
model: z5.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
3618
|
+
title: z5.string().optional()
|
|
3468
3619
|
},
|
|
3469
3620
|
async ({ ref, through_index, agent, model, title }) => {
|
|
3470
3621
|
try {
|
|
@@ -3505,11 +3656,11 @@ async function startMcpServer() {
|
|
|
3505
3656
|
"fork_chat",
|
|
3506
3657
|
"Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Slack / Global orchestrators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn (loop while stillRunning) on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
|
|
3507
3658
|
{
|
|
3508
|
-
ref:
|
|
3509
|
-
through_index:
|
|
3659
|
+
ref: z5.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
|
|
3660
|
+
through_index: z5.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
3510
3661
|
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
3511
|
-
model:
|
|
3512
|
-
title:
|
|
3662
|
+
model: z5.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
3663
|
+
title: z5.string().optional()
|
|
3513
3664
|
},
|
|
3514
3665
|
async ({ ref, through_index, agent, model, title }) => {
|
|
3515
3666
|
try {
|
|
@@ -3555,8 +3706,8 @@ async function startMcpServer() {
|
|
|
3555
3706
|
"run_dev_script",
|
|
3556
3707
|
"Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
|
|
3557
3708
|
{
|
|
3558
|
-
ref:
|
|
3559
|
-
name:
|
|
3709
|
+
ref: z5.string(),
|
|
3710
|
+
name: z5.string().optional()
|
|
3560
3711
|
},
|
|
3561
3712
|
async ({ ref, name }) => {
|
|
3562
3713
|
const result = await orch.startDev(ref, name);
|
|
@@ -3578,7 +3729,7 @@ async function startMcpServer() {
|
|
|
3578
3729
|
server.tool(
|
|
3579
3730
|
"list_run_scripts",
|
|
3580
3731
|
"List named run scripts available for a thread",
|
|
3581
|
-
{ ref:
|
|
3732
|
+
{ ref: z5.string() },
|
|
3582
3733
|
async ({ ref }) => {
|
|
3583
3734
|
const scripts = orch.listThreadRunScripts(ref);
|
|
3584
3735
|
const active = orch.getActiveRuns(ref);
|
|
@@ -3596,8 +3747,8 @@ async function startMcpServer() {
|
|
|
3596
3747
|
"stop_dev_script",
|
|
3597
3748
|
"Stop a running script for a thread (all scripts if name omitted)",
|
|
3598
3749
|
{
|
|
3599
|
-
ref:
|
|
3600
|
-
name:
|
|
3750
|
+
ref: z5.string(),
|
|
3751
|
+
name: z5.string().optional()
|
|
3601
3752
|
},
|
|
3602
3753
|
async ({ ref, name }) => {
|
|
3603
3754
|
orch.stopDev(ref, name);
|
|
@@ -3607,7 +3758,7 @@ async function startMcpServer() {
|
|
|
3607
3758
|
server.tool(
|
|
3608
3759
|
"run_setup",
|
|
3609
3760
|
"Re-run workspace setup (Sideboard/Conductor settings, .cursor/worktrees.json, or script/setup). New worktrees already run this automatically.",
|
|
3610
|
-
{ ref:
|
|
3761
|
+
{ ref: z5.string() },
|
|
3611
3762
|
async ({ ref }) => {
|
|
3612
3763
|
const result = await orch.runSetup(ref);
|
|
3613
3764
|
return {
|
|
@@ -3618,7 +3769,7 @@ async function startMcpServer() {
|
|
|
3618
3769
|
server.tool(
|
|
3619
3770
|
"add_workspace",
|
|
3620
3771
|
"Register a git repo as a Sideboard workspace",
|
|
3621
|
-
{ repoPath:
|
|
3772
|
+
{ repoPath: z5.string() },
|
|
3622
3773
|
async ({ repoPath }) => {
|
|
3623
3774
|
const ws = await orch.addWorkspace(repoPath);
|
|
3624
3775
|
return { content: [{ type: "text", text: JSON.stringify(ws) }] };
|
|
@@ -3627,7 +3778,7 @@ async function startMcpServer() {
|
|
|
3627
3778
|
server.tool(
|
|
3628
3779
|
"remove_workspace",
|
|
3629
3780
|
"Unregister a Sideboard workspace (does not archive threads)",
|
|
3630
|
-
{ repoPath:
|
|
3781
|
+
{ repoPath: z5.string() },
|
|
3631
3782
|
async ({ repoPath }) => {
|
|
3632
3783
|
orch.removeWorkspace(repoPath);
|
|
3633
3784
|
return { content: [{ type: "text", text: "ok" }] };
|
|
@@ -3637,12 +3788,12 @@ async function startMcpServer() {
|
|
|
3637
3788
|
"fanout",
|
|
3638
3789
|
"Best-of-n: create one thread per agent with the same prompt (parallel attempts)",
|
|
3639
3790
|
{
|
|
3640
|
-
prompt:
|
|
3641
|
-
agents:
|
|
3642
|
-
repoPath:
|
|
3643
|
-
sourceType:
|
|
3644
|
-
sourceRef:
|
|
3645
|
-
title:
|
|
3791
|
+
prompt: z5.string(),
|
|
3792
|
+
agents: z5.array(z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"])),
|
|
3793
|
+
repoPath: z5.string(),
|
|
3794
|
+
sourceType: z5.enum(["branch", "pr", "ticket"]).optional(),
|
|
3795
|
+
sourceRef: z5.string().optional(),
|
|
3796
|
+
title: z5.string().optional()
|
|
3646
3797
|
},
|
|
3647
3798
|
async (args) => {
|
|
3648
3799
|
const threads = await orch.bestOfN(args);
|
|
@@ -3669,8 +3820,8 @@ async function startMcpServer() {
|
|
|
3669
3820
|
"list_branches",
|
|
3670
3821
|
"List git branches in a registered workspace. Pass repoPath from list_workspaces (unmerged into the default branch by default \u2014 for create_thread sourceType=branch).",
|
|
3671
3822
|
{
|
|
3672
|
-
repoPath:
|
|
3673
|
-
unmergedOnly:
|
|
3823
|
+
repoPath: z5.string(),
|
|
3824
|
+
unmergedOnly: z5.boolean().optional()
|
|
3674
3825
|
},
|
|
3675
3826
|
async ({ repoPath, unmergedOnly }) => {
|
|
3676
3827
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -3690,7 +3841,7 @@ async function startMcpServer() {
|
|
|
3690
3841
|
server.tool(
|
|
3691
3842
|
"list_prs",
|
|
3692
3843
|
"List open GitHub PRs for a registered workspace. Pass repoPath from list_workspaces (uses gh against that repo remote). Then create_thread with sourceType=pr.",
|
|
3693
|
-
{ repoPath:
|
|
3844
|
+
{ repoPath: z5.string() },
|
|
3694
3845
|
async ({ repoPath }) => {
|
|
3695
3846
|
const root = await resolveRepoRoot(repoPath);
|
|
3696
3847
|
const prs = await listPrs(root);
|
|
@@ -3709,7 +3860,7 @@ async function startMcpServer() {
|
|
|
3709
3860
|
server.tool(
|
|
3710
3861
|
"get_pr_stack",
|
|
3711
3862
|
"Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before ask_git merge on stacked PRs (and only merge when the user explicitly asked).",
|
|
3712
|
-
{ ref:
|
|
3863
|
+
{ ref: z5.string() },
|
|
3713
3864
|
async ({ ref }) => {
|
|
3714
3865
|
const stack = await orch.getPrStack(ref);
|
|
3715
3866
|
return {
|
|
@@ -3721,8 +3872,8 @@ async function startMcpServer() {
|
|
|
3721
3872
|
"open_pr_stack_layers",
|
|
3722
3873
|
"Materialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.",
|
|
3723
3874
|
{
|
|
3724
|
-
ref:
|
|
3725
|
-
layer:
|
|
3875
|
+
ref: z5.string(),
|
|
3876
|
+
layer: z5.number().int().positive().optional()
|
|
3726
3877
|
},
|
|
3727
3878
|
async ({ ref, layer }) => {
|
|
3728
3879
|
const result = await orch.openPrStackLayers(ref, { layer });
|
|
@@ -3756,9 +3907,9 @@ async function startMcpServer() {
|
|
|
3756
3907
|
"add_stack_layer",
|
|
3757
3908
|
"Add a branch on top of the current stack (`gh stack add`) and open a worktree+thread for it.",
|
|
3758
3909
|
{
|
|
3759
|
-
ref:
|
|
3760
|
-
branchName:
|
|
3761
|
-
title:
|
|
3910
|
+
ref: z5.string(),
|
|
3911
|
+
branchName: z5.string(),
|
|
3912
|
+
title: z5.string().optional()
|
|
3762
3913
|
},
|
|
3763
3914
|
async ({ ref, branchName, title }) => {
|
|
3764
3915
|
const result = await orch.addStackLayer(ref, branchName, { title });
|
|
@@ -3787,11 +3938,11 @@ async function startMcpServer() {
|
|
|
3787
3938
|
"create_pr_stack",
|
|
3788
3939
|
"Create a new GitHub PR stack with one Sideboard worktree per layer (bottom\u2192top branch names). Requires `gh extension install github/gh-stack`.",
|
|
3789
3940
|
{
|
|
3790
|
-
repoPath:
|
|
3791
|
-
branches:
|
|
3792
|
-
agent:
|
|
3793
|
-
base:
|
|
3794
|
-
title:
|
|
3941
|
+
repoPath: z5.string(),
|
|
3942
|
+
branches: z5.array(z5.string()).min(1),
|
|
3943
|
+
agent: z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
|
|
3944
|
+
base: z5.string().optional(),
|
|
3945
|
+
title: z5.string().optional()
|
|
3795
3946
|
},
|
|
3796
3947
|
async (args) => {
|
|
3797
3948
|
const result = await orch.createPrStack({
|
|
@@ -3828,8 +3979,8 @@ async function startMcpServer() {
|
|
|
3828
3979
|
);
|
|
3829
3980
|
server.tool(
|
|
3830
3981
|
"list_issues",
|
|
3831
|
-
"List issues from Sideboard Account connections (Linear
|
|
3832
|
-
{ repoPath:
|
|
3982
|
+
"List issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
|
|
3983
|
+
{ repoPath: z5.string() },
|
|
3833
3984
|
async ({ repoPath }) => {
|
|
3834
3985
|
const root = await resolveRepoRoot(repoPath);
|
|
3835
3986
|
const result = await listIssues(root);
|
|
@@ -3840,8 +3991,8 @@ async function startMcpServer() {
|
|
|
3840
3991
|
"list_linear_issues",
|
|
3841
3992
|
"Deprecated: prefer list_issues. Lists assigned Linear issues via the chosen agent MCP connector",
|
|
3842
3993
|
{
|
|
3843
|
-
agent:
|
|
3844
|
-
repoPath:
|
|
3994
|
+
agent: z5.enum(["claude", "codex", "opencode"]),
|
|
3995
|
+
repoPath: z5.string()
|
|
3845
3996
|
},
|
|
3846
3997
|
async ({ agent, repoPath }) => {
|
|
3847
3998
|
const issues = await listLinearIssues(agent, repoPath);
|
|
@@ -3876,7 +4027,7 @@ var BrightsySideboardApi = class {
|
|
|
3876
4027
|
return (this.cfg.endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
3877
4028
|
}
|
|
3878
4029
|
async request(path2, init = {}) {
|
|
3879
|
-
await this.
|
|
4030
|
+
await this.ensureFreshAccessToken();
|
|
3880
4031
|
const url = `${this.endpoint}${path2}`;
|
|
3881
4032
|
const headers = {
|
|
3882
4033
|
Authorization: `Bearer ${this.cfg.access_token}`,
|
|
@@ -3899,33 +4050,21 @@ var BrightsySideboardApi = class {
|
|
|
3899
4050
|
}
|
|
3900
4051
|
return await res.json();
|
|
3901
4052
|
}
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
if (!this.cfg.refresh_token ||
|
|
3905
|
-
|
|
3906
|
-
const url = `${this.endpoint}/oauth/token`;
|
|
3907
|
-
let res;
|
|
3908
|
-
try {
|
|
3909
|
-
res = await this.fetchImpl(url, {
|
|
3910
|
-
method: "POST",
|
|
3911
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
3912
|
-
body: new URLSearchParams({
|
|
3913
|
-
grant_type: "refresh_token",
|
|
3914
|
-
refresh_token: this.cfg.refresh_token,
|
|
3915
|
-
client_id: clientId
|
|
3916
|
-
})
|
|
3917
|
-
});
|
|
3918
|
-
} catch (err) {
|
|
3919
|
-
throw new Error(formatBrightsyFetchError(err, url));
|
|
3920
|
-
}
|
|
3921
|
-
if (!res.ok) return;
|
|
3922
|
-
const data = await res.json();
|
|
3923
|
-
if (!data.access_token) return;
|
|
3924
|
-
this.cfg.access_token = data.access_token;
|
|
3925
|
-
if (data.refresh_token) this.cfg.refresh_token = data.refresh_token;
|
|
3926
|
-
if (data.expires_in) {
|
|
3927
|
-
this.cfg.expires_at = Date.now() + data.expires_in * 1e3;
|
|
4053
|
+
/** Refresh ~/.brightsy when the access token is stale or has no expiry. */
|
|
4054
|
+
async ensureFreshAccessToken() {
|
|
4055
|
+
if (!this.cfg.refresh_token || !brightsyAccessTokenNeedsRefresh(this.cfg.expires_at)) {
|
|
4056
|
+
return;
|
|
3928
4057
|
}
|
|
4058
|
+
const grant = await refreshBrightsyAccessToken({
|
|
4059
|
+
endpoint: this.endpoint,
|
|
4060
|
+
refreshToken: this.cfg.refresh_token,
|
|
4061
|
+
clientId: this.cfg.oauth_client_id,
|
|
4062
|
+
fetchImpl: this.fetchImpl
|
|
4063
|
+
});
|
|
4064
|
+
if (!grant) return;
|
|
4065
|
+
this.cfg.access_token = grant.access_token;
|
|
4066
|
+
if (grant.refresh_token) this.cfg.refresh_token = grant.refresh_token;
|
|
4067
|
+
if (grant.expires_at) this.cfg.expires_at = grant.expires_at;
|
|
3929
4068
|
saveBrightsyConfig(this.cfg);
|
|
3930
4069
|
}
|
|
3931
4070
|
async getAccess() {
|
|
@@ -3974,8 +4113,8 @@ var BrightsySideboardApi = class {
|
|
|
3974
4113
|
};
|
|
3975
4114
|
function taskMessageText(task) {
|
|
3976
4115
|
const parts = task.message?.parts ?? [];
|
|
3977
|
-
const
|
|
3978
|
-
return
|
|
4116
|
+
const text5 = parts.find((p) => p.kind === "text")?.text ?? "";
|
|
4117
|
+
return text5.trim();
|
|
3979
4118
|
}
|
|
3980
4119
|
|
|
3981
4120
|
// src/brightsy/cloud-connect.ts
|
|
@@ -4517,11 +4656,11 @@ async function startSlackOAuth(opts) {
|
|
|
4517
4656
|
import { WebSocket as WsWebSocket } from "ws";
|
|
4518
4657
|
var BACKOFF_START_MS = 1e3;
|
|
4519
4658
|
var BACKOFF_MAX_MS = 3e4;
|
|
4520
|
-
function stripSlackMentions(
|
|
4521
|
-
return
|
|
4659
|
+
function stripSlackMentions(text5) {
|
|
4660
|
+
return text5.replace(/<@[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
4522
4661
|
}
|
|
4523
|
-
function isSlackStopCommand(
|
|
4524
|
-
const t = stripSlackMentions(
|
|
4662
|
+
function isSlackStopCommand(text5) {
|
|
4663
|
+
const t = stripSlackMentions(text5).toLowerCase();
|
|
4525
4664
|
return t === "stop" || t === "sideboard_force_stop";
|
|
4526
4665
|
}
|
|
4527
4666
|
function parseSlackSocketFrame(raw) {
|
|
@@ -4543,8 +4682,8 @@ function inboundFromSocketFrame(frame) {
|
|
|
4543
4682
|
const ts = event.ts?.trim();
|
|
4544
4683
|
if (!channelId || !ts) return null;
|
|
4545
4684
|
const rawText = event.text?.trim() ?? "";
|
|
4546
|
-
const
|
|
4547
|
-
if (!
|
|
4685
|
+
const text5 = stripSlackMentions(rawText);
|
|
4686
|
+
if (!text5) return null;
|
|
4548
4687
|
const teamId = (frame.payload?.team_id || event.team || "").trim();
|
|
4549
4688
|
if (!teamId) return null;
|
|
4550
4689
|
const isDm = event.type === "message" && (event.channel_type === "im" || event.channel_type === "mpim" || !event.channel_type && channelId.startsWith("D"));
|
|
@@ -4556,7 +4695,7 @@ function inboundFromSocketFrame(frame) {
|
|
|
4556
4695
|
ts,
|
|
4557
4696
|
threadTs: event.thread_ts?.trim() || void 0,
|
|
4558
4697
|
userId: event.user?.trim(),
|
|
4559
|
-
text:
|
|
4698
|
+
text: text5,
|
|
4560
4699
|
kind: isMention ? "mention" : "dm"
|
|
4561
4700
|
};
|
|
4562
4701
|
}
|
|
@@ -5096,12 +5235,12 @@ function formatSlackInboundPrompt(msg) {
|
|
|
5096
5235
|
|
|
5097
5236
|
${msg.text}`;
|
|
5098
5237
|
}
|
|
5099
|
-
function isSlackInboundUserPrompt(
|
|
5100
|
-
return
|
|
5238
|
+
function isSlackInboundUserPrompt(text5) {
|
|
5239
|
+
return text5.startsWith("Slack DM\n") || text5.startsWith("Slack @mention\n");
|
|
5101
5240
|
}
|
|
5102
|
-
function formatSlackSignedReply(deviceLabel,
|
|
5241
|
+
function formatSlackSignedReply(deviceLabel, text5) {
|
|
5103
5242
|
const label = deviceLabel.trim();
|
|
5104
|
-
const body =
|
|
5243
|
+
const body = text5.trim();
|
|
5105
5244
|
if (!body) return body;
|
|
5106
5245
|
if (!label) return body;
|
|
5107
5246
|
const head = `${label}:`;
|
|
@@ -5110,8 +5249,8 @@ function formatSlackSignedReply(deviceLabel, text4) {
|
|
|
5110
5249
|
}
|
|
5111
5250
|
return `${label}: ${body}`;
|
|
5112
5251
|
}
|
|
5113
|
-
function signForThisMac(
|
|
5114
|
-
return formatSlackSignedReply(ensureSlackDeviceIdentity().deviceLabel,
|
|
5252
|
+
function signForThisMac(text5) {
|
|
5253
|
+
return formatSlackSignedReply(ensureSlackDeviceIdentity().deviceLabel, text5);
|
|
5115
5254
|
}
|
|
5116
5255
|
function slackReplyThreadTs(msg) {
|
|
5117
5256
|
if (msg.threadTs && msg.threadTs !== msg.ts) return msg.threadTs;
|
|
@@ -5172,9 +5311,9 @@ function replyStub(target) {
|
|
|
5172
5311
|
kind: "dm"
|
|
5173
5312
|
};
|
|
5174
5313
|
}
|
|
5175
|
-
async function postSlackText(target,
|
|
5314
|
+
async function postSlackText(target, text5, opts) {
|
|
5176
5315
|
if (opts.postReply) {
|
|
5177
|
-
const result = await opts.postReply(replyStub(target),
|
|
5316
|
+
const result = await opts.postReply(replyStub(target), text5);
|
|
5178
5317
|
const ts2 = result && typeof result === "object" && typeof result.ts === "string" ? result.ts.trim() : "";
|
|
5179
5318
|
return ts2 ? { ts: ts2 } : null;
|
|
5180
5319
|
}
|
|
@@ -5184,7 +5323,7 @@ async function postSlackText(target, text4, opts) {
|
|
|
5184
5323
|
"chat.postMessage",
|
|
5185
5324
|
{
|
|
5186
5325
|
channel: target.channelId,
|
|
5187
|
-
text:
|
|
5326
|
+
text: text5,
|
|
5188
5327
|
thread_ts: target.threadTs
|
|
5189
5328
|
},
|
|
5190
5329
|
opts.fetchImpl
|
|
@@ -5192,9 +5331,9 @@ async function postSlackText(target, text4, opts) {
|
|
|
5192
5331
|
const ts = json.ts?.trim();
|
|
5193
5332
|
return ts ? { ts } : null;
|
|
5194
5333
|
}
|
|
5195
|
-
async function updateSlackText(target, ts,
|
|
5334
|
+
async function updateSlackText(target, ts, text5, opts) {
|
|
5196
5335
|
if (opts.updateReply) {
|
|
5197
|
-
await opts.updateReply(replyStub(target), ts,
|
|
5336
|
+
await opts.updateReply(replyStub(target), ts, text5);
|
|
5198
5337
|
return;
|
|
5199
5338
|
}
|
|
5200
5339
|
const token = writeTokenForTeam(target.teamId);
|
|
@@ -5204,7 +5343,7 @@ async function updateSlackText(target, ts, text4, opts) {
|
|
|
5204
5343
|
{
|
|
5205
5344
|
channel: target.channelId,
|
|
5206
5345
|
ts,
|
|
5207
|
-
text:
|
|
5346
|
+
text: text5
|
|
5208
5347
|
},
|
|
5209
5348
|
opts.fetchImpl
|
|
5210
5349
|
);
|
|
@@ -5232,8 +5371,8 @@ function replyTargetOf(msg) {
|
|
|
5232
5371
|
threadTs: slackReplyThreadTs(msg)
|
|
5233
5372
|
};
|
|
5234
5373
|
}
|
|
5235
|
-
async function postSlackReply(msg,
|
|
5236
|
-
await postSlackText(replyTargetOf(msg), signForThisMac(
|
|
5374
|
+
async function postSlackReply(msg, text5, opts) {
|
|
5375
|
+
await postSlackText(replyTargetOf(msg), signForThisMac(text5), opts);
|
|
5237
5376
|
}
|
|
5238
5377
|
function startSlackTurnProgress(msg, threadId, opts) {
|
|
5239
5378
|
const log = opts.onLog ?? (() => void 0);
|
|
@@ -5316,10 +5455,10 @@ function startSlackTurnProgress(msg, threadId, opts) {
|
|
|
5316
5455
|
}
|
|
5317
5456
|
});
|
|
5318
5457
|
},
|
|
5319
|
-
finishWith: (
|
|
5458
|
+
finishWith: (text5) => {
|
|
5320
5459
|
stop();
|
|
5321
5460
|
return run2(async () => {
|
|
5322
|
-
const signed = signForThisMac(
|
|
5461
|
+
const signed = signForThisMac(text5.trim());
|
|
5323
5462
|
if (!signed) {
|
|
5324
5463
|
if (!postedTs) return;
|
|
5325
5464
|
const ts = postedTs;
|
|
@@ -5347,11 +5486,11 @@ function startSlackTurnProgress(msg, threadId, opts) {
|
|
|
5347
5486
|
};
|
|
5348
5487
|
}
|
|
5349
5488
|
var lastRelayed = /* @__PURE__ */ new Map();
|
|
5350
|
-
function markRelayed(threadId,
|
|
5351
|
-
lastRelayed.set(threadId, `${threadId}:${
|
|
5489
|
+
function markRelayed(threadId, text5) {
|
|
5490
|
+
lastRelayed.set(threadId, `${threadId}:${text5}`);
|
|
5352
5491
|
}
|
|
5353
|
-
function alreadyRelayed(threadId,
|
|
5354
|
-
return lastRelayed.get(threadId) === `${threadId}:${
|
|
5492
|
+
function alreadyRelayed(threadId, text5) {
|
|
5493
|
+
return lastRelayed.get(threadId) === `${threadId}:${text5}`;
|
|
5355
5494
|
}
|
|
5356
5495
|
async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
5357
5496
|
const target = getSlackReplyTarget(threadId);
|
|
@@ -5360,14 +5499,14 @@ async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
|
5360
5499
|
const lastUser = thread ? [...thread.messages].reverse().find((m) => m.role === "user") : void 0;
|
|
5361
5500
|
if (lastUser && isSlackInboundUserPrompt(lastUser.text)) return;
|
|
5362
5501
|
const result = getOrchestrator().getTurnResult(threadId);
|
|
5363
|
-
const
|
|
5364
|
-
if (!
|
|
5365
|
-
if (alreadyRelayed(threadId,
|
|
5366
|
-
markRelayed(threadId,
|
|
5502
|
+
const text5 = result.text.trim();
|
|
5503
|
+
if (!text5) return;
|
|
5504
|
+
if (alreadyRelayed(threadId, text5)) return;
|
|
5505
|
+
markRelayed(threadId, text5);
|
|
5367
5506
|
const log = opts.onLog ?? (() => void 0);
|
|
5368
5507
|
try {
|
|
5369
|
-
await postSlackText(target, signForThisMac(
|
|
5370
|
-
log(`replied ${target.threadTs ?? target.channelId} (${
|
|
5508
|
+
await postSlackText(target, signForThisMac(text5), opts);
|
|
5509
|
+
log(`replied ${target.threadTs ?? target.channelId} (${text5.length} chars)`);
|
|
5371
5510
|
} catch (err) {
|
|
5372
5511
|
lastRelayed.delete(threadId);
|
|
5373
5512
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -5615,10 +5754,10 @@ function resolveSlackListenMode(opts) {
|
|
|
5615
5754
|
}
|
|
5616
5755
|
|
|
5617
5756
|
// src/slack/relay-hub.ts
|
|
5618
|
-
function parseSlackDeviceDestination(
|
|
5619
|
-
const m =
|
|
5620
|
-
if (!m) return { label: null, rest:
|
|
5621
|
-
return { label: m[1], rest:
|
|
5757
|
+
function parseSlackDeviceDestination(text5) {
|
|
5758
|
+
const m = text5.match(/^\s*(?:to\s+)?(?:@|#)?([A-Za-z][\w-]{0,63})\s*[::]\s*/);
|
|
5759
|
+
if (!m) return { label: null, rest: text5 };
|
|
5760
|
+
return { label: m[1], rest: text5.slice(m[0].length) };
|
|
5622
5761
|
}
|
|
5623
5762
|
var SlackRelayHub = class {
|
|
5624
5763
|
sessions = /* @__PURE__ */ new Map();
|
|
@@ -6139,6 +6278,7 @@ async function startSlackRelayServer(opts) {
|
|
|
6139
6278
|
};
|
|
6140
6279
|
}
|
|
6141
6280
|
export {
|
|
6281
|
+
ABLETIME_MCP_PATH,
|
|
6142
6282
|
AGENT_GIT_ACTIONS,
|
|
6143
6283
|
AGENT_RUNNER_MAX_OLD_SPACE_MB,
|
|
6144
6284
|
ATTACHMENTS_DIR,
|
|
@@ -6156,6 +6296,8 @@ export {
|
|
|
6156
6296
|
CONTEXT_MIN_MESSAGES,
|
|
6157
6297
|
CONVENTION_SETUP_RELPATHS,
|
|
6158
6298
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
6299
|
+
DEFAULT_ABLETIME_HOST,
|
|
6300
|
+
DEFAULT_WORKTREE_SORT,
|
|
6159
6301
|
FAMOUS_SOCCER_TEAMS,
|
|
6160
6302
|
GITHUB_GIT_AUTH_MODES,
|
|
6161
6303
|
GLOBAL_WORKSPACE_ID,
|
|
@@ -6202,6 +6344,8 @@ export {
|
|
|
6202
6344
|
SlackRelayHub,
|
|
6203
6345
|
THINKING_EFFORTS,
|
|
6204
6346
|
WORKTREE_MCP_TOOLS,
|
|
6347
|
+
abletimeMcpRequest,
|
|
6348
|
+
abletimeMcpUrl,
|
|
6205
6349
|
ackSlackInboundSeen,
|
|
6206
6350
|
addBoardPin,
|
|
6207
6351
|
addPrStackLayer,
|
|
@@ -6237,6 +6381,7 @@ export {
|
|
|
6237
6381
|
autoRenameBranchEnabled,
|
|
6238
6382
|
autoRunAfterSetupEnabled,
|
|
6239
6383
|
branchDisplayLabel,
|
|
6384
|
+
brightsyAccessTokenNeedsRefresh,
|
|
6240
6385
|
brightsyAdapter,
|
|
6241
6386
|
brightsyCloudConnectAgent,
|
|
6242
6387
|
brightsyCloudConnectEnabled,
|
|
@@ -6257,6 +6402,7 @@ export {
|
|
|
6257
6402
|
caffeinateWhileRunningEnabled,
|
|
6258
6403
|
caffeinateWhileSchedulesEnabled,
|
|
6259
6404
|
caffeinateWhileSlackListenEnabled,
|
|
6405
|
+
callAbleTimeTool,
|
|
6260
6406
|
canonicalizeRepoPath,
|
|
6261
6407
|
captureLoginEnv,
|
|
6262
6408
|
captureTurnBaseline,
|
|
@@ -6290,6 +6436,7 @@ export {
|
|
|
6290
6436
|
copyConfiguredFiles,
|
|
6291
6437
|
countCacheControlBlocks,
|
|
6292
6438
|
cowboyModeEnabled,
|
|
6439
|
+
createAbleTimeTask,
|
|
6293
6440
|
createChatTab,
|
|
6294
6441
|
createEmptyThread,
|
|
6295
6442
|
createExistingBranchWorktree,
|
|
@@ -6313,6 +6460,7 @@ export {
|
|
|
6313
6460
|
detectAgents,
|
|
6314
6461
|
detectGhStack,
|
|
6315
6462
|
detectLocalMergeConflicts,
|
|
6463
|
+
disconnectAbleTimeConnection,
|
|
6316
6464
|
disconnectBrightsyTeam,
|
|
6317
6465
|
disconnectLinear,
|
|
6318
6466
|
disconnectLinearConnection,
|
|
@@ -6322,8 +6470,11 @@ export {
|
|
|
6322
6470
|
encodeBrightsyTarget,
|
|
6323
6471
|
enrichPathWithNpmGlobalBin,
|
|
6324
6472
|
enrichWorkspacesWithGithub,
|
|
6473
|
+
ensureAbleTimeTask,
|
|
6325
6474
|
ensureAgentPath,
|
|
6475
|
+
ensureBrightsyLocalConfigFresh,
|
|
6326
6476
|
ensureCloudCoordinator,
|
|
6477
|
+
ensureConnectedBrightsyTeamTokens,
|
|
6327
6478
|
ensureGhPreferOrigin,
|
|
6328
6479
|
ensureGlobalCoordinatorCwd,
|
|
6329
6480
|
ensureReviewRequestFile,
|
|
@@ -6380,6 +6531,10 @@ export {
|
|
|
6380
6531
|
formatWorktreeDirective,
|
|
6381
6532
|
formatWorktreeReminder,
|
|
6382
6533
|
fromInclusiveInputUsage,
|
|
6534
|
+
getAbleTimeAccessToken,
|
|
6535
|
+
getAbleTimeHost,
|
|
6536
|
+
getAbleTimeOrientation,
|
|
6537
|
+
getAbleTimeTask,
|
|
6383
6538
|
getAdapter,
|
|
6384
6539
|
getAgentSetupInfo,
|
|
6385
6540
|
getBrightsySession,
|
|
@@ -6438,6 +6593,7 @@ export {
|
|
|
6438
6593
|
inspectGitWorktree,
|
|
6439
6594
|
installAgent,
|
|
6440
6595
|
interruptSlackCoordinatorForInbound,
|
|
6596
|
+
isAbleTimeConnected,
|
|
6441
6597
|
isAskUserToolName,
|
|
6442
6598
|
isBrightsyConnected,
|
|
6443
6599
|
isBrightsyNdjsonLine,
|
|
@@ -6478,6 +6634,7 @@ export {
|
|
|
6478
6634
|
isThreadCaffeinated,
|
|
6479
6635
|
isThreadRecordFile,
|
|
6480
6636
|
isWorkspaceScratchPath,
|
|
6637
|
+
issueAttachmentForAbleTimeTask,
|
|
6481
6638
|
issueSourceLabel,
|
|
6482
6639
|
lastRequestOccupancy,
|
|
6483
6640
|
latestPendingPlanQuestions,
|
|
@@ -6486,6 +6643,9 @@ export {
|
|
|
6486
6643
|
linearGraphql,
|
|
6487
6644
|
linearOAuthAuthorizeUrl,
|
|
6488
6645
|
linearOAuthCredentials,
|
|
6646
|
+
listAbleTimeAssignedIssues,
|
|
6647
|
+
listAbleTimeProjects,
|
|
6648
|
+
listAbleTimeTasks,
|
|
6489
6649
|
listAgentSetupInfo,
|
|
6490
6650
|
listBoardPins,
|
|
6491
6651
|
listBranchCommits,
|
|
@@ -6525,6 +6685,7 @@ export {
|
|
|
6525
6685
|
locksDir,
|
|
6526
6686
|
loginAgent,
|
|
6527
6687
|
lookupSoccerTeam,
|
|
6688
|
+
mapAbleTimeTask,
|
|
6528
6689
|
maxConcurrentAgents,
|
|
6529
6690
|
maybeCompactContext,
|
|
6530
6691
|
mcpAllowTools,
|
|
@@ -6538,6 +6699,7 @@ export {
|
|
|
6538
6699
|
nextPastedTextName,
|
|
6539
6700
|
nextThinkingEffort,
|
|
6540
6701
|
nonInteractiveGitProcessEnv,
|
|
6702
|
+
normalizeAbleTimeHost,
|
|
6541
6703
|
normalizeParseResult,
|
|
6542
6704
|
normalizeThinkingEffort,
|
|
6543
6705
|
normalizeThread,
|
|
@@ -6586,6 +6748,7 @@ export {
|
|
|
6586
6748
|
readWorktreeInclude,
|
|
6587
6749
|
recordScheduleRun,
|
|
6588
6750
|
recordSlackOutboundWatch,
|
|
6751
|
+
refreshBrightsyAccessToken,
|
|
6589
6752
|
refreshGitHubAuth,
|
|
6590
6753
|
registerPackagedUserMcpClients,
|
|
6591
6754
|
releaseCaffeinateHoldForThread,
|
|
@@ -6630,6 +6793,7 @@ export {
|
|
|
6630
6793
|
resolveThreadEffort,
|
|
6631
6794
|
resolveVaultKey,
|
|
6632
6795
|
resolveWorktreeStartPoint,
|
|
6796
|
+
rewriteAbleTimeError,
|
|
6633
6797
|
rewriteLinearError,
|
|
6634
6798
|
run,
|
|
6635
6799
|
runArchiveScript,
|
|
@@ -6642,10 +6806,12 @@ export {
|
|
|
6642
6806
|
runWorkspaceSetup,
|
|
6643
6807
|
sameWorktreePath,
|
|
6644
6808
|
sanitizeMcpServerName,
|
|
6809
|
+
saveAbleTimeConnection,
|
|
6645
6810
|
saveAppSettings,
|
|
6646
6811
|
saveLinearOAuth,
|
|
6647
6812
|
schedulesPath,
|
|
6648
6813
|
scrubGithubTokensFromChildEnv,
|
|
6814
|
+
searchAbleTimeTasks,
|
|
6649
6815
|
secureFileUnlocksWith,
|
|
6650
6816
|
setCaffeinateHold,
|
|
6651
6817
|
setHttpFetchImpl,
|
|
@@ -6696,6 +6862,7 @@ export {
|
|
|
6696
6862
|
takenTeamSlugsForChatTab,
|
|
6697
6863
|
takenTeamSlugsForOrchestration,
|
|
6698
6864
|
taskMessageText,
|
|
6865
|
+
taskUrl,
|
|
6699
6866
|
thinkingEffortBars,
|
|
6700
6867
|
thinkingEffortLabel,
|
|
6701
6868
|
thisProcessShouldDrainAgentQueues,
|
|
@@ -6706,6 +6873,7 @@ export {
|
|
|
6706
6873
|
threadRequestsBrightsyMcp,
|
|
6707
6874
|
threadsDir,
|
|
6708
6875
|
threadsSharingWorktree,
|
|
6876
|
+
toAbleTimeIssueInfo,
|
|
6709
6877
|
toPublicAppSettings,
|
|
6710
6878
|
toolActivityLine,
|
|
6711
6879
|
toolDescription,
|
|
@@ -6728,6 +6896,7 @@ export {
|
|
|
6728
6896
|
userClaudeMcpConfigPath,
|
|
6729
6897
|
userCursorMcpConfigPath,
|
|
6730
6898
|
validateLinearApiKey,
|
|
6899
|
+
verifyAbleTimeConnection,
|
|
6731
6900
|
waitForPidExit,
|
|
6732
6901
|
warmGithubAgentAuth,
|
|
6733
6902
|
withAgentInstructions,
|