@sideboard-ai/core 0.1.132 → 0.1.135
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-LGJLZMM3.js → agents-O3AJMI2Y.js} +9 -8
- package/dist/{agents-CI6NGKRO.js → agents-RTQFF7PY.js} +9 -8
- 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-MNL4FSKY.js → chunk-2ESCEK2Q.js} +4 -4
- package/dist/chunk-2XXAAIN3.js +463 -0
- package/dist/{chunk-HZPO3SSZ.js → chunk-57GIFU3X.js} +4 -3
- package/dist/chunk-6GN5WPYZ.js +31 -0
- package/dist/chunk-AT346U23.js +468 -0
- package/dist/{chunk-LLX3OMHU.js → chunk-ED4UPEJX.js} +1 -1
- package/dist/chunk-ELBYOGVA.js +32 -0
- package/dist/{chunk-HUYEU4GS.js → chunk-GJBHOJCZ.js} +83 -2
- package/dist/{chunk-ZND6XV6J.js → chunk-GKKHXZCT.js} +83 -2
- package/dist/{chunk-UDQI3N47.js → chunk-HQQNLDVC.js} +2 -2
- package/dist/{chunk-G6X6UFJO.js → chunk-J5IBSVB3.js} +42 -12
- package/dist/{chunk-RSFCB23A.js → chunk-K7EX47QG.js} +4 -3
- package/dist/{chunk-PK4PQUPU.js → chunk-KBBXNS2V.js} +6 -6
- package/dist/{chunk-SIPDL62B.js → chunk-KBWND62T.js} +6 -6
- package/dist/{chunk-VE22NWBD.js → chunk-LOKXPQ4U.js} +2 -2
- package/dist/{chunk-AQESMTCZ.js → chunk-M267JPEA.js} +3 -29
- package/dist/{chunk-MGYCQAZ6.js → chunk-N62K3KXX.js} +6 -6
- package/dist/{chunk-HLJUNJBF.js → chunk-PM3C2J6K.js} +42 -12
- package/dist/{chunk-HRSBZIXS.js → chunk-QAV3HGVS.js} +2 -2
- package/dist/{chunk-SYLTXDRF.js → chunk-RDULVW3E.js} +2 -2
- package/dist/{chunk-R7FGPBKL.js → chunk-S42XV45P.js} +3 -25
- package/dist/{chunk-VFXZTSAD.js → chunk-XIKEUCNC.js} +55 -31
- package/dist/{chunk-HULESWLI.js → chunk-XUEI4GCF.js} +4 -4
- package/dist/{chunk-SMWJAE74.js → chunk-Z5LYMW7M.js} +55 -31
- package/dist/{connected-teams-S6E3D5C7.js → connected-teams-4A2AXDNN.js} +3 -2
- package/dist/{connected-teams-3BWNJIRY.js → connected-teams-IJUJQ7R6.js} +3 -2
- package/dist/{coordinator-prompt-MEEUOEF2.js → coordinator-prompt-FYMWE33S.js} +4 -4
- package/dist/{coordinator-prompt-SPJSGAQS.js → coordinator-prompt-Y737IIFR.js} +4 -4
- package/dist/{global-workspace-KNESLWKG.js → global-workspace-6KH6BSKL.js} +5 -5
- package/dist/{global-workspace-BMWP7YZC.js → global-workspace-ZFKNLBZA.js} +5 -5
- package/dist/index.cjs +1150 -353
- package/dist/index.d.cts +173 -13
- package/dist/index.d.ts +173 -13
- package/dist/index.js +435 -240
- package/dist/mcp/run-stdio.cjs +1041 -300
- package/dist/mcp/run-stdio.js +339 -187
- package/dist/{oauth-FT7EL2PY.js → oauth-A7XXI2TM.js} +2 -1
- package/dist/{oauth-43NNH6C6.js → oauth-YJBAURIJ.js} +2 -1
- package/dist/{orchestrator-JA65XKB6.js → orchestrator-2BRAPJ47.js} +11 -10
- package/dist/{orchestrator-5TN2DJWO.js → orchestrator-3YDPPZHZ.js} +11 -10
- package/dist/{thread-store-5MLYY35S.js → thread-store-CRLQJ2HM.js} +3 -1
- package/dist/{thread-store-F6BCARQG.js → thread-store-FADXSMEJ.js} +3 -1
- package/dist/{workspaces-HSYRYJYV.js → workspaces-3RRF3LVF.js} +6 -6
- package/dist/{workspaces-O4QZOASB.js → workspaces-AYI5DHK4.js} +6 -6
- package/dist/{worktree-ERHC7Q4F.js → worktree-BC6XDMQK.js} +3 -3
- package/dist/{worktree-JVGSLSLJ.js → worktree-MX7XBX6Z.js} +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -107,6 +107,7 @@ import {
|
|
|
107
107
|
initStackFromThread,
|
|
108
108
|
initializeGitRepository,
|
|
109
109
|
inspectGitWorktree,
|
|
110
|
+
isAccountWideIssueSource,
|
|
110
111
|
isCowboyThread,
|
|
111
112
|
isDesktopHostAlive,
|
|
112
113
|
isHomeBoardThread,
|
|
@@ -186,7 +187,7 @@ import {
|
|
|
186
187
|
worktreeCleanupSettings,
|
|
187
188
|
wrapReviewSkillMarkdown,
|
|
188
189
|
writeWorktreeFile
|
|
189
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-XIKEUCNC.js";
|
|
190
191
|
import {
|
|
191
192
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
192
193
|
CLAUDE_MODEL_CATALOG,
|
|
@@ -265,7 +266,7 @@ import {
|
|
|
265
266
|
withEventParentId,
|
|
266
267
|
withEventsParentId,
|
|
267
268
|
writeInjectedMcpConfig
|
|
268
|
-
} from "./chunk-
|
|
269
|
+
} from "./chunk-N62K3KXX.js";
|
|
269
270
|
import {
|
|
270
271
|
brightsyMcpServerName,
|
|
271
272
|
connectBrightsyTeam,
|
|
@@ -275,25 +276,22 @@ import {
|
|
|
275
276
|
listBrightsyAccounts,
|
|
276
277
|
listConnectedBrightsyTeams,
|
|
277
278
|
switchBrightsyAccount
|
|
278
|
-
} from "./chunk-
|
|
279
|
+
} from "./chunk-KBWND62T.js";
|
|
279
280
|
import {
|
|
280
281
|
brightsyAccessTokenNeedsRefresh,
|
|
281
282
|
brightsyConfigPath,
|
|
282
283
|
ensureBrightsyLocalConfigFresh,
|
|
283
|
-
formatFetchError,
|
|
284
|
-
httpFetch,
|
|
285
284
|
loadBrightsyConfig,
|
|
286
285
|
refreshBrightsyAccessToken,
|
|
287
|
-
saveBrightsyConfig
|
|
288
|
-
|
|
289
|
-
} from "./chunk-AQESMTCZ.js";
|
|
286
|
+
saveBrightsyConfig
|
|
287
|
+
} from "./chunk-M267JPEA.js";
|
|
290
288
|
import {
|
|
291
289
|
addWorkspace,
|
|
292
290
|
ensureWorkspace,
|
|
293
291
|
listWorkspaces,
|
|
294
292
|
removeWorkspace,
|
|
295
293
|
syncWorkspacesFromThreads
|
|
296
|
-
} from "./chunk-
|
|
294
|
+
} from "./chunk-LOKXPQ4U.js";
|
|
297
295
|
import {
|
|
298
296
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
299
297
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -321,7 +319,7 @@ import {
|
|
|
321
319
|
parseForceStopMessage,
|
|
322
320
|
slackCoordinatorSourceRef,
|
|
323
321
|
takenTeamSlugsForOrchestration
|
|
324
|
-
} from "./chunk-
|
|
322
|
+
} from "./chunk-XUEI4GCF.js";
|
|
325
323
|
import {
|
|
326
324
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
327
325
|
SLACK_REPLY_FORMATTING,
|
|
@@ -330,7 +328,34 @@ import {
|
|
|
330
328
|
enrichWorkspacesWithGithub,
|
|
331
329
|
ensureGlobalCoordinatorCwd,
|
|
332
330
|
formatWorkspaceInventory
|
|
333
|
-
} from "./chunk-
|
|
331
|
+
} from "./chunk-57GIFU3X.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";
|
|
334
359
|
import {
|
|
335
360
|
LEGACY_PLAN_FILE_REL,
|
|
336
361
|
PLAN_FILE_NAME,
|
|
@@ -440,7 +465,7 @@ import {
|
|
|
440
465
|
worktreeDisplayLabel,
|
|
441
466
|
worktreeDisplayLabelForGroup,
|
|
442
467
|
worktreeNameFromPath
|
|
443
|
-
} from "./chunk-
|
|
468
|
+
} from "./chunk-HQQNLDVC.js";
|
|
444
469
|
import {
|
|
445
470
|
ATTACHMENTS_DIR,
|
|
446
471
|
LEGACY_ATTACHMENTS_DIR,
|
|
@@ -469,8 +494,11 @@ import {
|
|
|
469
494
|
claudeUserSettingsPath,
|
|
470
495
|
cowboyModeEnabled,
|
|
471
496
|
deleteBranchOnPurgeEnabled,
|
|
497
|
+
disconnectAbleTimeConnection,
|
|
472
498
|
disconnectLinearConnection,
|
|
473
499
|
ensureSlackDeviceIdentity,
|
|
500
|
+
getAbleTimeAccessToken,
|
|
501
|
+
getAbleTimeHost,
|
|
474
502
|
getDefaultAgent,
|
|
475
503
|
getDefaultEffort,
|
|
476
504
|
getDefaultFast,
|
|
@@ -480,6 +508,7 @@ import {
|
|
|
480
508
|
getIssueSource,
|
|
481
509
|
getLinearApiKey,
|
|
482
510
|
harnessEnvKey,
|
|
511
|
+
isAbleTimeConnected,
|
|
483
512
|
isIssueSourceConnected,
|
|
484
513
|
isLinearConnected,
|
|
485
514
|
issueSourceLabel,
|
|
@@ -495,6 +524,7 @@ import {
|
|
|
495
524
|
resolveNewThreadOptions,
|
|
496
525
|
resolveThreadDefaults,
|
|
497
526
|
resolveVaultKey,
|
|
527
|
+
saveAbleTimeConnection,
|
|
498
528
|
saveAppSettings,
|
|
499
529
|
saveLinearOAuth,
|
|
500
530
|
secureFileUnlocksWith,
|
|
@@ -512,7 +542,7 @@ import {
|
|
|
512
542
|
updateDefaultsSettings,
|
|
513
543
|
updateIntegrationsSettings,
|
|
514
544
|
updateOpencodeSettings
|
|
515
|
-
} from "./chunk-
|
|
545
|
+
} from "./chunk-GJBHOJCZ.js";
|
|
516
546
|
import {
|
|
517
547
|
stripNestedElectronEnv
|
|
518
548
|
} from "./chunk-4TR3HZFT.js";
|
|
@@ -522,6 +552,7 @@ import {
|
|
|
522
552
|
createEmptyThread,
|
|
523
553
|
deleteThreadRecord,
|
|
524
554
|
findThreadByRef,
|
|
555
|
+
invalidateThreadListCache,
|
|
525
556
|
isThreadRecordFile,
|
|
526
557
|
listThreads,
|
|
527
558
|
normalizeThread,
|
|
@@ -531,7 +562,7 @@ import {
|
|
|
531
562
|
updateThread,
|
|
532
563
|
withThreadLock,
|
|
533
564
|
writeThread
|
|
534
|
-
} from "./chunk-
|
|
565
|
+
} from "./chunk-PM3C2J6K.js";
|
|
535
566
|
import {
|
|
536
567
|
THINKING_EFFORTS,
|
|
537
568
|
isThinkingEffort,
|
|
@@ -608,9 +639,9 @@ async function getGitHubStatus() {
|
|
|
608
639
|
};
|
|
609
640
|
}
|
|
610
641
|
const status = await run("gh", ["auth", "status"], { reject: false });
|
|
611
|
-
const
|
|
642
|
+
const text5 = `${status.stdout}
|
|
612
643
|
${status.stderr}`;
|
|
613
|
-
const loginMatch =
|
|
644
|
+
const loginMatch = text5.match(/Logged in to ([^\s]+) account (\S+)/i) ?? text5.match(/Logged in to ([^\s]+) as (\S+)/i);
|
|
614
645
|
if (loginMatch) {
|
|
615
646
|
return {
|
|
616
647
|
connected: true,
|
|
@@ -1311,6 +1342,7 @@ async function listIssues(repoPath) {
|
|
|
1311
1342
|
const settings = loadAppSettings();
|
|
1312
1343
|
const preferredSource = settings.integrations.issueSource ?? "github";
|
|
1313
1344
|
const linearConnected = isLinearConnected(settings);
|
|
1345
|
+
const abletimeConnected = isAbleTimeConnected(settings);
|
|
1314
1346
|
const source = resolveEffectiveIssueSource(settings);
|
|
1315
1347
|
if (source === "linear") {
|
|
1316
1348
|
const listed = await listLinearAssignedIssues();
|
|
@@ -1318,6 +1350,21 @@ async function listIssues(repoPath) {
|
|
|
1318
1350
|
source,
|
|
1319
1351
|
preferredSource,
|
|
1320
1352
|
linearConnected,
|
|
1353
|
+
abletimeConnected,
|
|
1354
|
+
issues: listed.issues,
|
|
1355
|
+
viewer: {
|
|
1356
|
+
login: listed.viewer.name,
|
|
1357
|
+
name: listed.viewer.name
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1361
|
+
if (source === "abletime") {
|
|
1362
|
+
const listed = await listAbleTimeAssignedIssues();
|
|
1363
|
+
return {
|
|
1364
|
+
source,
|
|
1365
|
+
preferredSource,
|
|
1366
|
+
linearConnected,
|
|
1367
|
+
abletimeConnected,
|
|
1321
1368
|
issues: listed.issues,
|
|
1322
1369
|
viewer: {
|
|
1323
1370
|
login: listed.viewer.name,
|
|
@@ -1333,6 +1380,7 @@ async function listIssues(repoPath) {
|
|
|
1333
1380
|
source,
|
|
1334
1381
|
preferredSource,
|
|
1335
1382
|
linearConnected,
|
|
1383
|
+
abletimeConnected,
|
|
1336
1384
|
issues,
|
|
1337
1385
|
viewer: login ? { login } : void 0
|
|
1338
1386
|
};
|
|
@@ -1392,16 +1440,16 @@ var PASTE_ATTACH_MIN_CHARS = 1200;
|
|
|
1392
1440
|
var PASTE_ATTACH_MIN_LINES = 15;
|
|
1393
1441
|
var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
|
|
1394
1442
|
var PASTED_NAME_ALT_RE = /^pasted-(\d+)\.txt$/i;
|
|
1395
|
-
function pastedTextStats(
|
|
1396
|
-
const chars =
|
|
1443
|
+
function pastedTextStats(text5) {
|
|
1444
|
+
const chars = text5.length;
|
|
1397
1445
|
if (chars === 0) return { chars: 0, lines: 0 };
|
|
1398
|
-
const lines =
|
|
1446
|
+
const lines = text5.split(/\r\n|\r|\n/).length;
|
|
1399
1447
|
return { chars, lines };
|
|
1400
1448
|
}
|
|
1401
|
-
function shouldAttachPastedText(
|
|
1402
|
-
const trimmed =
|
|
1449
|
+
function shouldAttachPastedText(text5) {
|
|
1450
|
+
const trimmed = text5.trim();
|
|
1403
1451
|
if (!trimmed) return false;
|
|
1404
|
-
const { chars, lines } = pastedTextStats(
|
|
1452
|
+
const { chars, lines } = pastedTextStats(text5);
|
|
1405
1453
|
return chars >= PASTE_ATTACH_MIN_CHARS || lines >= PASTE_ATTACH_MIN_LINES;
|
|
1406
1454
|
}
|
|
1407
1455
|
function nextPastedTextName(existing) {
|
|
@@ -1412,13 +1460,13 @@ function nextPastedTextName(existing) {
|
|
|
1412
1460
|
}
|
|
1413
1461
|
return `Pasted text #${max + 1}.txt`;
|
|
1414
1462
|
}
|
|
1415
|
-
function buildPastedTextAttachment(
|
|
1463
|
+
function buildPastedTextAttachment(text5, opts) {
|
|
1416
1464
|
return {
|
|
1417
1465
|
id: opts?.id ?? randomUUID(),
|
|
1418
1466
|
name: opts?.name ?? "Pasted text #1.txt",
|
|
1419
1467
|
kind: "file",
|
|
1420
1468
|
path: opts?.path,
|
|
1421
|
-
content:
|
|
1469
|
+
content: text5
|
|
1422
1470
|
};
|
|
1423
1471
|
}
|
|
1424
1472
|
|
|
@@ -1539,7 +1587,7 @@ function formatPlanQuestionsForChat(questions) {
|
|
|
1539
1587
|
// src/mcp/server.ts
|
|
1540
1588
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1541
1589
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1542
|
-
import { z as
|
|
1590
|
+
import { z as z5 } from "zod";
|
|
1543
1591
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1544
1592
|
import { basename } from "path";
|
|
1545
1593
|
|
|
@@ -1781,8 +1829,8 @@ function labelGithubUrl(url) {
|
|
|
1781
1829
|
}
|
|
1782
1830
|
return { kind: "other", label: "GitHub", url: raw };
|
|
1783
1831
|
}
|
|
1784
|
-
function appendGithubLink(
|
|
1785
|
-
const body =
|
|
1832
|
+
function appendGithubLink(text5, githubUrl) {
|
|
1833
|
+
const body = text5.trimEnd();
|
|
1786
1834
|
if (!githubUrl?.trim()) return body;
|
|
1787
1835
|
const labeled = labelGithubUrl(githubUrl);
|
|
1788
1836
|
if (!labeled) {
|
|
@@ -2065,7 +2113,7 @@ function registerSlackTools(server) {
|
|
|
2065
2113
|
);
|
|
2066
2114
|
}
|
|
2067
2115
|
|
|
2068
|
-
// src/mcp/
|
|
2116
|
+
// src/mcp/abletime-tools.ts
|
|
2069
2117
|
import { z as z2 } from "zod";
|
|
2070
2118
|
function text2(payload, isError = false) {
|
|
2071
2119
|
return {
|
|
@@ -2079,7 +2127,127 @@ function fail2(err) {
|
|
|
2079
2127
|
true
|
|
2080
2128
|
);
|
|
2081
2129
|
}
|
|
2082
|
-
|
|
2130
|
+
function registerAbleTimeTools(server) {
|
|
2131
|
+
server.tool(
|
|
2132
|
+
"abletime_orientation",
|
|
2133
|
+
"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.",
|
|
2134
|
+
{},
|
|
2135
|
+
async () => {
|
|
2136
|
+
try {
|
|
2137
|
+
const orientation = await getAbleTimeOrientation();
|
|
2138
|
+
return text2({
|
|
2139
|
+
viewer: orientation.viewer,
|
|
2140
|
+
projects: orientation.projects,
|
|
2141
|
+
tasks: orientation.tasks.map(toAbleTimeIssueInfo)
|
|
2142
|
+
});
|
|
2143
|
+
} catch (err) {
|
|
2144
|
+
return fail2(err);
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
);
|
|
2148
|
+
server.tool(
|
|
2149
|
+
"abletime_list_projects",
|
|
2150
|
+
"List AbleTime projects (and categories) the Account token can see. Use a project id on abletime_create_task / abletime_ensure_task.",
|
|
2151
|
+
{},
|
|
2152
|
+
async () => {
|
|
2153
|
+
try {
|
|
2154
|
+
return text2({ projects: await listAbleTimeProjects() });
|
|
2155
|
+
} catch (err) {
|
|
2156
|
+
return fail2(err);
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
);
|
|
2160
|
+
server.tool(
|
|
2161
|
+
"abletime_list_tasks",
|
|
2162
|
+
"List open AbleTime tasks (excludes done/archived). Optional projectId filter.",
|
|
2163
|
+
{ projectId: z2.string().optional() },
|
|
2164
|
+
async ({ projectId }) => {
|
|
2165
|
+
try {
|
|
2166
|
+
const tasks = await listAbleTimeTasks({ projectId });
|
|
2167
|
+
return text2({ issues: tasks.map(toAbleTimeIssueInfo) });
|
|
2168
|
+
} catch (err) {
|
|
2169
|
+
return fail2(err);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
);
|
|
2173
|
+
server.tool(
|
|
2174
|
+
"abletime_search_tasks",
|
|
2175
|
+
"Search AbleTime tasks by text, reference, or tag.",
|
|
2176
|
+
{ query: z2.string() },
|
|
2177
|
+
async ({ query }) => {
|
|
2178
|
+
try {
|
|
2179
|
+
const tasks = await searchAbleTimeTasks(query);
|
|
2180
|
+
return text2({ issues: tasks.map(toAbleTimeIssueInfo) });
|
|
2181
|
+
} catch (err) {
|
|
2182
|
+
return fail2(err);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
);
|
|
2186
|
+
server.tool(
|
|
2187
|
+
"abletime_get_task",
|
|
2188
|
+
"Get one AbleTime task by id or reference (e.g. CRM-232).",
|
|
2189
|
+
{ id: z2.string() },
|
|
2190
|
+
async ({ id }) => {
|
|
2191
|
+
try {
|
|
2192
|
+
return text2(toAbleTimeIssueInfo(await getAbleTimeTask(id)));
|
|
2193
|
+
} catch (err) {
|
|
2194
|
+
return fail2(err);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
);
|
|
2198
|
+
server.tool(
|
|
2199
|
+
"abletime_create_task",
|
|
2200
|
+
"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).",
|
|
2201
|
+
{
|
|
2202
|
+
title: z2.string(),
|
|
2203
|
+
description: z2.string().optional(),
|
|
2204
|
+
projectId: z2.string().optional(),
|
|
2205
|
+
categoryId: z2.string().optional(),
|
|
2206
|
+
state: z2.enum(["backlog", "todo"]).optional()
|
|
2207
|
+
},
|
|
2208
|
+
async (args) => {
|
|
2209
|
+
try {
|
|
2210
|
+
return text2(toAbleTimeIssueInfo(await createAbleTimeTask(args)));
|
|
2211
|
+
} catch (err) {
|
|
2212
|
+
return fail2(err);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
);
|
|
2216
|
+
server.tool(
|
|
2217
|
+
"abletime_ensure_task",
|
|
2218
|
+
"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.",
|
|
2219
|
+
{
|
|
2220
|
+
title: z2.string(),
|
|
2221
|
+
description: z2.string().optional(),
|
|
2222
|
+
projectId: z2.string().optional(),
|
|
2223
|
+
categoryId: z2.string().optional()
|
|
2224
|
+
},
|
|
2225
|
+
async (args) => {
|
|
2226
|
+
try {
|
|
2227
|
+
const task = await ensureAbleTimeTask(args);
|
|
2228
|
+
return text2({ ...toAbleTimeIssueInfo(task), created: task.created });
|
|
2229
|
+
} catch (err) {
|
|
2230
|
+
return fail2(err);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
);
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
// src/mcp/linear-tools.ts
|
|
2237
|
+
import { z as z3 } from "zod";
|
|
2238
|
+
function text3(payload, isError = false) {
|
|
2239
|
+
return {
|
|
2240
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
2241
|
+
...isError ? { isError: true } : {}
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
function fail3(err) {
|
|
2245
|
+
return text3(
|
|
2246
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
2247
|
+
true
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
var prioritySchema = z3.number().int().min(0).max(4).optional().describe("0 none, 1 urgent, 2 high, 3 medium, 4 low");
|
|
2083
2251
|
function registerLinearTools(server) {
|
|
2084
2252
|
server.tool(
|
|
2085
2253
|
"linear_list_teams",
|
|
@@ -2087,21 +2255,21 @@ function registerLinearTools(server) {
|
|
|
2087
2255
|
{},
|
|
2088
2256
|
async () => {
|
|
2089
2257
|
try {
|
|
2090
|
-
return
|
|
2258
|
+
return text3(await listLinearTeams());
|
|
2091
2259
|
} catch (err) {
|
|
2092
|
-
return
|
|
2260
|
+
return fail3(err);
|
|
2093
2261
|
}
|
|
2094
2262
|
}
|
|
2095
2263
|
);
|
|
2096
2264
|
server.tool(
|
|
2097
2265
|
"linear_get_issue",
|
|
2098
2266
|
"Get a Linear issue by uuid or identifier (ENG-123).",
|
|
2099
|
-
{ id:
|
|
2267
|
+
{ id: z3.string() },
|
|
2100
2268
|
async ({ id }) => {
|
|
2101
2269
|
try {
|
|
2102
|
-
return
|
|
2270
|
+
return text3(await getLinearIssue(id));
|
|
2103
2271
|
} catch (err) {
|
|
2104
|
-
return
|
|
2272
|
+
return fail3(err);
|
|
2105
2273
|
}
|
|
2106
2274
|
}
|
|
2107
2275
|
);
|
|
@@ -2109,18 +2277,18 @@ function registerLinearTools(server) {
|
|
|
2109
2277
|
"linear_create_issue",
|
|
2110
2278
|
'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.',
|
|
2111
2279
|
{
|
|
2112
|
-
team:
|
|
2113
|
-
title:
|
|
2114
|
-
description:
|
|
2115
|
-
state:
|
|
2116
|
-
assignee:
|
|
2280
|
+
team: z3.string(),
|
|
2281
|
+
title: z3.string(),
|
|
2282
|
+
description: z3.string().optional(),
|
|
2283
|
+
state: z3.string().optional(),
|
|
2284
|
+
assignee: z3.string().nullable().optional(),
|
|
2117
2285
|
priority: prioritySchema
|
|
2118
2286
|
},
|
|
2119
2287
|
async (args) => {
|
|
2120
2288
|
try {
|
|
2121
|
-
return
|
|
2289
|
+
return text3(await createLinearIssue(args));
|
|
2122
2290
|
} catch (err) {
|
|
2123
|
-
return
|
|
2291
|
+
return fail3(err);
|
|
2124
2292
|
}
|
|
2125
2293
|
}
|
|
2126
2294
|
);
|
|
@@ -2128,18 +2296,18 @@ function registerLinearTools(server) {
|
|
|
2128
2296
|
"linear_update_issue",
|
|
2129
2297
|
'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.',
|
|
2130
2298
|
{
|
|
2131
|
-
id:
|
|
2132
|
-
title:
|
|
2133
|
-
description:
|
|
2134
|
-
state:
|
|
2135
|
-
assignee:
|
|
2299
|
+
id: z3.string(),
|
|
2300
|
+
title: z3.string().optional(),
|
|
2301
|
+
description: z3.string().optional(),
|
|
2302
|
+
state: z3.string().optional(),
|
|
2303
|
+
assignee: z3.string().nullable().optional(),
|
|
2136
2304
|
priority: prioritySchema
|
|
2137
2305
|
},
|
|
2138
2306
|
async (args) => {
|
|
2139
2307
|
try {
|
|
2140
|
-
return
|
|
2308
|
+
return text3(await updateLinearIssue(args));
|
|
2141
2309
|
} catch (err) {
|
|
2142
|
-
return
|
|
2310
|
+
return fail3(err);
|
|
2143
2311
|
}
|
|
2144
2312
|
}
|
|
2145
2313
|
);
|
|
@@ -2147,29 +2315,29 @@ function registerLinearTools(server) {
|
|
|
2147
2315
|
"linear_comment",
|
|
2148
2316
|
"Add a markdown comment on a Linear issue (uuid or ENG-123).",
|
|
2149
2317
|
{
|
|
2150
|
-
id:
|
|
2151
|
-
body:
|
|
2318
|
+
id: z3.string(),
|
|
2319
|
+
body: z3.string()
|
|
2152
2320
|
},
|
|
2153
2321
|
async (args) => {
|
|
2154
2322
|
try {
|
|
2155
|
-
return
|
|
2323
|
+
return text3(await commentLinearIssue(args));
|
|
2156
2324
|
} catch (err) {
|
|
2157
|
-
return
|
|
2325
|
+
return fail3(err);
|
|
2158
2326
|
}
|
|
2159
2327
|
}
|
|
2160
2328
|
);
|
|
2161
2329
|
}
|
|
2162
2330
|
|
|
2163
2331
|
// src/mcp/schedule-tools.ts
|
|
2164
|
-
import { z as
|
|
2165
|
-
function
|
|
2332
|
+
import { z as z4 } from "zod";
|
|
2333
|
+
function text4(payload, isError = false) {
|
|
2166
2334
|
return {
|
|
2167
2335
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
2168
2336
|
...isError ? { isError: true } : {}
|
|
2169
2337
|
};
|
|
2170
2338
|
}
|
|
2171
|
-
function
|
|
2172
|
-
return
|
|
2339
|
+
function fail4(err) {
|
|
2340
|
+
return text4(
|
|
2173
2341
|
{ error: err instanceof Error ? err.message : String(err) },
|
|
2174
2342
|
true
|
|
2175
2343
|
);
|
|
@@ -2194,9 +2362,9 @@ function registerScheduleTools(server) {
|
|
|
2194
2362
|
{},
|
|
2195
2363
|
async () => {
|
|
2196
2364
|
try {
|
|
2197
|
-
return
|
|
2365
|
+
return text4({ schedules: listSchedules() });
|
|
2198
2366
|
} catch (err) {
|
|
2199
|
-
return
|
|
2367
|
+
return fail4(err);
|
|
2200
2368
|
}
|
|
2201
2369
|
}
|
|
2202
2370
|
);
|
|
@@ -2204,24 +2372,24 @@ function registerScheduleTools(server) {
|
|
|
2204
2372
|
"create_schedule",
|
|
2205
2373
|
"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.",
|
|
2206
2374
|
{
|
|
2207
|
-
prompt:
|
|
2208
|
-
name:
|
|
2209
|
-
at:
|
|
2210
|
-
every:
|
|
2211
|
-
cron:
|
|
2212
|
-
tz:
|
|
2213
|
-
threadId:
|
|
2375
|
+
prompt: z4.string().describe("User message / goal queued when the schedule fires"),
|
|
2376
|
+
name: z4.string().optional(),
|
|
2377
|
+
at: z4.string().optional().describe("ISO datetime for a one-shot"),
|
|
2378
|
+
every: z4.string().optional().describe("Interval such as 15m, 1h, 6h, 1d"),
|
|
2379
|
+
cron: z4.string().optional().describe("5-field cron expression"),
|
|
2380
|
+
tz: z4.string().optional().describe("IANA timezone for cron (default: system)"),
|
|
2381
|
+
threadId: z4.string().optional().describe(
|
|
2214
2382
|
'Existing orchestration chat id, or "self" for this coordinator. Omit to create a new Global chat on fire.'
|
|
2215
2383
|
),
|
|
2216
|
-
agent:
|
|
2217
|
-
model:
|
|
2384
|
+
agent: z4.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
|
|
2385
|
+
model: z4.string().optional()
|
|
2218
2386
|
},
|
|
2219
2387
|
async (args) => {
|
|
2220
2388
|
try {
|
|
2221
2389
|
const when = parseWhen(args);
|
|
2222
2390
|
const threadId = resolveScheduleThreadId(args.threadId);
|
|
2223
2391
|
if (args.threadId?.trim().toLowerCase() === "self" && !threadId) {
|
|
2224
|
-
return
|
|
2392
|
+
return fail4(
|
|
2225
2393
|
new Error("threadId=self requires this turn to be an orchestration chat")
|
|
2226
2394
|
);
|
|
2227
2395
|
}
|
|
@@ -2234,12 +2402,12 @@ function registerScheduleTools(server) {
|
|
|
2234
2402
|
model: args.model,
|
|
2235
2403
|
createdBy: "mcp"
|
|
2236
2404
|
});
|
|
2237
|
-
return
|
|
2405
|
+
return text4({
|
|
2238
2406
|
schedule,
|
|
2239
2407
|
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."
|
|
2240
2408
|
});
|
|
2241
2409
|
} catch (err) {
|
|
2242
|
-
return
|
|
2410
|
+
return fail4(err);
|
|
2243
2411
|
}
|
|
2244
2412
|
}
|
|
2245
2413
|
);
|
|
@@ -2247,17 +2415,17 @@ function registerScheduleTools(server) {
|
|
|
2247
2415
|
"update_schedule",
|
|
2248
2416
|
"Update a local schedule (prompt, cadence, target thread, enabled). Pass id from list_schedules.",
|
|
2249
2417
|
{
|
|
2250
|
-
id:
|
|
2251
|
-
prompt:
|
|
2252
|
-
name:
|
|
2253
|
-
at:
|
|
2254
|
-
every:
|
|
2255
|
-
cron:
|
|
2256
|
-
tz:
|
|
2257
|
-
threadId:
|
|
2258
|
-
agent:
|
|
2259
|
-
model:
|
|
2260
|
-
enabled:
|
|
2418
|
+
id: z4.string(),
|
|
2419
|
+
prompt: z4.string().optional(),
|
|
2420
|
+
name: z4.string().optional(),
|
|
2421
|
+
at: z4.string().optional(),
|
|
2422
|
+
every: z4.string().optional(),
|
|
2423
|
+
cron: z4.string().optional(),
|
|
2424
|
+
tz: z4.string().optional(),
|
|
2425
|
+
threadId: z4.string().optional().describe('Existing orchestration chat, "self", or empty string to create a new chat each run'),
|
|
2426
|
+
agent: z4.enum(["claude", "cursor", "codex", "opencode"]).optional(),
|
|
2427
|
+
model: z4.string().optional(),
|
|
2428
|
+
enabled: z4.boolean().optional()
|
|
2261
2429
|
},
|
|
2262
2430
|
async (args) => {
|
|
2263
2431
|
try {
|
|
@@ -2272,7 +2440,7 @@ function registerScheduleTools(server) {
|
|
|
2272
2440
|
if (args.threadId !== void 0) {
|
|
2273
2441
|
threadId = resolveScheduleThreadId(args.threadId);
|
|
2274
2442
|
if (args.threadId.trim().toLowerCase() === "self" && !threadId) {
|
|
2275
|
-
return
|
|
2443
|
+
return fail4(
|
|
2276
2444
|
new Error("threadId=self requires this turn to be an orchestration chat")
|
|
2277
2445
|
);
|
|
2278
2446
|
}
|
|
@@ -2286,38 +2454,38 @@ function registerScheduleTools(server) {
|
|
|
2286
2454
|
enabled: args.enabled,
|
|
2287
2455
|
model: args.model
|
|
2288
2456
|
});
|
|
2289
|
-
return
|
|
2457
|
+
return text4({ schedule });
|
|
2290
2458
|
} catch (err) {
|
|
2291
|
-
return
|
|
2459
|
+
return fail4(err);
|
|
2292
2460
|
}
|
|
2293
2461
|
}
|
|
2294
2462
|
);
|
|
2295
2463
|
server.tool(
|
|
2296
2464
|
"delete_schedule",
|
|
2297
2465
|
"Delete a local schedule. Pass id from list_schedules.",
|
|
2298
|
-
{ id:
|
|
2466
|
+
{ id: z4.string() },
|
|
2299
2467
|
async ({ id }) => {
|
|
2300
2468
|
try {
|
|
2301
2469
|
deleteSchedule(id);
|
|
2302
|
-
return
|
|
2470
|
+
return text4({ ok: true, id });
|
|
2303
2471
|
} catch (err) {
|
|
2304
|
-
return
|
|
2472
|
+
return fail4(err);
|
|
2305
2473
|
}
|
|
2306
2474
|
}
|
|
2307
2475
|
);
|
|
2308
2476
|
server.tool(
|
|
2309
2477
|
"run_schedule",
|
|
2310
2478
|
"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.",
|
|
2311
|
-
{ id:
|
|
2479
|
+
{ id: z4.string() },
|
|
2312
2480
|
async ({ id }) => {
|
|
2313
2481
|
try {
|
|
2314
2482
|
if (!getSchedule(id)) {
|
|
2315
|
-
return
|
|
2483
|
+
return fail4(new Error(`Schedule not found: ${id}`));
|
|
2316
2484
|
}
|
|
2317
2485
|
const schedule = await fireSchedule(id);
|
|
2318
|
-
return
|
|
2486
|
+
return text4({ schedule });
|
|
2319
2487
|
} catch (err) {
|
|
2320
|
-
return
|
|
2488
|
+
return fail4(err);
|
|
2321
2489
|
}
|
|
2322
2490
|
}
|
|
2323
2491
|
);
|
|
@@ -2490,7 +2658,7 @@ async function loadHomeBoardInputs(workspaces) {
|
|
|
2490
2658
|
const first = await listIssues(paths[0]);
|
|
2491
2659
|
issueSource = first.source;
|
|
2492
2660
|
viewerLogin = first.viewer?.login || first.viewer?.name || void 0;
|
|
2493
|
-
if (first.source
|
|
2661
|
+
if (isAccountWideIssueSource(first.source)) {
|
|
2494
2662
|
const repoPath = paths[0] ?? "";
|
|
2495
2663
|
issues = first.issues.map((issue) => ({
|
|
2496
2664
|
...issue,
|
|
@@ -2718,7 +2886,7 @@ async function startMcpServer() {
|
|
|
2718
2886
|
);
|
|
2719
2887
|
}
|
|
2720
2888
|
try {
|
|
2721
|
-
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-
|
|
2889
|
+
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-U5RZKUXG.js");
|
|
2722
2890
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
2723
2891
|
} catch {
|
|
2724
2892
|
}
|
|
@@ -2776,13 +2944,13 @@ async function startMcpServer() {
|
|
|
2776
2944
|
"list_board",
|
|
2777
2945
|
"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.",
|
|
2778
2946
|
{
|
|
2779
|
-
query:
|
|
2780
|
-
repoPath:
|
|
2781
|
-
kind:
|
|
2782
|
-
column:
|
|
2947
|
+
query: z5.string().optional().describe("Case-insensitive token search across title, id, labels, repo"),
|
|
2948
|
+
repoPath: z5.string().optional().describe("Limit to one workspace path from list_workspaces"),
|
|
2949
|
+
kind: z5.enum(["all", "tickets", "prs", "branches", "threads"]).optional().describe("Filter by worktree source (default all)"),
|
|
2950
|
+
column: z5.enum(["new", "draft", "review", "done", "needs_you"]).optional().describe(
|
|
2783
2951
|
"Return cards for this column only (totals still include the rest). needs_you is a legacy alias for new."
|
|
2784
2952
|
),
|
|
2785
|
-
limit:
|
|
2953
|
+
limit: z5.number().int().positive().optional().describe("Max cards per column (default 40). hidden counts the remainder.")
|
|
2786
2954
|
},
|
|
2787
2955
|
async ({ query, repoPath, kind, column, limit }) => {
|
|
2788
2956
|
const workspaces = orch.listWorkspaces();
|
|
@@ -2820,7 +2988,7 @@ async function startMcpServer() {
|
|
|
2820
2988
|
server.tool(
|
|
2821
2989
|
"get_thread",
|
|
2822
2990
|
"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.",
|
|
2823
|
-
{ ref:
|
|
2991
|
+
{ ref: z5.string() },
|
|
2824
2992
|
async ({ ref }) => {
|
|
2825
2993
|
const t = orch.getThread(ref);
|
|
2826
2994
|
if (!t) {
|
|
@@ -2857,17 +3025,17 @@ async function startMcpServer() {
|
|
|
2857
3025
|
"present_artifact",
|
|
2858
3026
|
"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.",
|
|
2859
3027
|
{
|
|
2860
|
-
title:
|
|
2861
|
-
type:
|
|
3028
|
+
title: z5.string().describe("Short title shown in the artifact pane header"),
|
|
3029
|
+
type: z5.enum(["html", "svg", "markdown", "react", "log"]).describe(
|
|
2862
3030
|
"html/svg/markdown/react replace the pane. log appends content to the same artifact_id (new lines only)."
|
|
2863
3031
|
),
|
|
2864
|
-
content:
|
|
3032
|
+
content: z5.string().describe(
|
|
2865
3033
|
"html/svg/markdown/react: full document. log: only the new lines since the last call (empty is ok for a status-only update)."
|
|
2866
3034
|
),
|
|
2867
|
-
artifact_id:
|
|
2868
|
-
status:
|
|
2869
|
-
phase:
|
|
2870
|
-
mode:
|
|
3035
|
+
artifact_id: z5.string().optional().describe("Stable id. Required for type=log so later calls append to the same pane."),
|
|
3036
|
+
status: z5.enum(["running", "ok", "failed", "idle"]).optional().describe("Log header pill: running (working), ok (done), failed, idle"),
|
|
3037
|
+
phase: z5.string().optional().describe("Log subtitle (Signing, Notarizing, \u2026)"),
|
|
3038
|
+
mode: z5.enum(["append", "replace"]).optional().describe("log only: append (default) or replace the buffer")
|
|
2871
3039
|
},
|
|
2872
3040
|
async ({ title, type, artifact_id, status, phase, mode }) => {
|
|
2873
3041
|
const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -2888,15 +3056,15 @@ async function startMcpServer() {
|
|
|
2888
3056
|
"ask_user",
|
|
2889
3057
|
"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.",
|
|
2890
3058
|
{
|
|
2891
|
-
questions:
|
|
2892
|
-
|
|
2893
|
-
question:
|
|
2894
|
-
header:
|
|
2895
|
-
multiSelect:
|
|
2896
|
-
options:
|
|
2897
|
-
|
|
2898
|
-
label:
|
|
2899
|
-
description:
|
|
3059
|
+
questions: z5.array(
|
|
3060
|
+
z5.object({
|
|
3061
|
+
question: z5.string().describe("Full question text ending with ?"),
|
|
3062
|
+
header: z5.string().max(24).optional().describe("Short label shown above the question"),
|
|
3063
|
+
multiSelect: z5.boolean().optional().describe("Allow selecting multiple options"),
|
|
3064
|
+
options: z5.array(
|
|
3065
|
+
z5.object({
|
|
3066
|
+
label: z5.string(),
|
|
3067
|
+
description: z5.string().optional().describe("What this option means / when to choose it (strongly preferred)")
|
|
2900
3068
|
})
|
|
2901
3069
|
).min(2).max(6).describe("2\u20136 choices (Sideboard also offers Other)")
|
|
2902
3070
|
})
|
|
@@ -2915,9 +3083,9 @@ async function startMcpServer() {
|
|
|
2915
3083
|
"present_plan",
|
|
2916
3084
|
"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.",
|
|
2917
3085
|
{
|
|
2918
|
-
title:
|
|
2919
|
-
content:
|
|
2920
|
-
thread_id:
|
|
3086
|
+
title: z5.string().optional().describe("Short plan title (defaults to Plan)"),
|
|
3087
|
+
content: z5.string().min(1).describe("Full plan markdown (headings, steps, risks, open questions)"),
|
|
3088
|
+
thread_id: z5.string().optional().describe("Sideboard thread id when cwd is not the worktree")
|
|
2921
3089
|
},
|
|
2922
3090
|
async ({ title, content, thread_id }) => {
|
|
2923
3091
|
const { writePlanFile: writePlanFile2 } = await import("./plan-file-6O7G4VPQ.js");
|
|
@@ -2940,15 +3108,15 @@ async function startMcpServer() {
|
|
|
2940
3108
|
"present_schema",
|
|
2941
3109
|
"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.",
|
|
2942
3110
|
{
|
|
2943
|
-
title:
|
|
2944
|
-
mode:
|
|
2945
|
-
datasource:
|
|
2946
|
-
resource_id:
|
|
2947
|
-
record_id:
|
|
2948
|
-
resource:
|
|
2949
|
-
record:
|
|
2950
|
-
records:
|
|
2951
|
-
pane_id:
|
|
3111
|
+
title: z5.string().describe("Pane title"),
|
|
3112
|
+
mode: z5.enum(["table", "form"]).optional().describe("table = list/filter records; form = edit one record"),
|
|
3113
|
+
datasource: z5.enum(["brightsy", "inline"]).optional().describe("brightsy resolves via login; inline uses embedded resource/records"),
|
|
3114
|
+
resource_id: z5.string().optional().describe("Brightsy record type UUID (or generic resource id)"),
|
|
3115
|
+
record_id: z5.string().optional().describe("Record id when opening form mode"),
|
|
3116
|
+
resource: z5.record(z5.unknown()).optional().describe("Inline { id, title, schema, schemaUi?, slug? }"),
|
|
3117
|
+
record: z5.record(z5.unknown()).optional().describe("Inline record { id, data, published_at? }"),
|
|
3118
|
+
records: z5.array(z5.record(z5.unknown())).optional().describe("Inline records for table mode"),
|
|
3119
|
+
pane_id: z5.string().optional().describe("Stable pane id across updates")
|
|
2952
3120
|
},
|
|
2953
3121
|
async (args) => {
|
|
2954
3122
|
const id = args.pane_id?.trim() || `schema_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -2969,10 +3137,10 @@ async function startMcpServer() {
|
|
|
2969
3137
|
"present_files",
|
|
2970
3138
|
"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.",
|
|
2971
3139
|
{
|
|
2972
|
-
title:
|
|
2973
|
-
datasource:
|
|
2974
|
-
path:
|
|
2975
|
-
pane_id:
|
|
3140
|
+
title: z5.string().optional().describe("Pane title (default: Files)"),
|
|
3141
|
+
datasource: z5.enum(["brightsy", "memory"]).optional().describe("brightsy = account storage via login; memory = session demo store"),
|
|
3142
|
+
path: z5.string().optional().describe("Initial folder path (e.g. public)"),
|
|
3143
|
+
pane_id: z5.string().optional().describe("Stable pane id across updates")
|
|
2976
3144
|
},
|
|
2977
3145
|
async (args) => {
|
|
2978
3146
|
const id = args.pane_id?.trim() || `files_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -2990,16 +3158,17 @@ async function startMcpServer() {
|
|
|
2990
3158
|
if (!worktreeProfile) {
|
|
2991
3159
|
registerSlackTools(server);
|
|
2992
3160
|
registerLinearTools(server);
|
|
3161
|
+
registerAbleTimeTools(server);
|
|
2993
3162
|
registerScheduleTools(server);
|
|
2994
3163
|
const { getCaffeinateHold: getCaffeinateHold2, setCaffeinateHold: setCaffeinateHold2 } = await import("./caffeinate-hold-X3JNPR42.js");
|
|
2995
|
-
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-
|
|
3164
|
+
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-U5RZKUXG.js");
|
|
2996
3165
|
const accountDefaults = resolveThreadDefaults2();
|
|
2997
3166
|
const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
|
|
2998
3167
|
server.tool(
|
|
2999
3168
|
"set_caffeinate",
|
|
3000
3169
|
"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.",
|
|
3001
3170
|
{
|
|
3002
|
-
enabled:
|
|
3171
|
+
enabled: z5.boolean().describe("true = hold caffeinate on; false = release and let the Mac sleep")
|
|
3003
3172
|
},
|
|
3004
3173
|
async ({ enabled }) => {
|
|
3005
3174
|
const threadId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
|
|
@@ -3037,18 +3206,18 @@ async function startMcpServer() {
|
|
|
3037
3206
|
"create_thread",
|
|
3038
3207
|
`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.`,
|
|
3039
3208
|
{
|
|
3040
|
-
sourceType:
|
|
3041
|
-
sourceRef:
|
|
3042
|
-
agent:
|
|
3043
|
-
model:
|
|
3209
|
+
sourceType: z5.enum(["branch", "pr", "ticket"]),
|
|
3210
|
+
sourceRef: z5.string(),
|
|
3211
|
+
agent: z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"]).optional().describe(`Omit to use Account default agent (${accountDefaults.agent})`),
|
|
3212
|
+
model: z5.string().nullable().optional().describe(
|
|
3044
3213
|
`Usually omit to use Account default model (${accountDefaults.model?.trim() || "Auto"}). Pass null only to force Auto / agent-default.`
|
|
3045
3214
|
),
|
|
3046
|
-
repoPath:
|
|
3047
|
-
title:
|
|
3048
|
-
cowboy:
|
|
3215
|
+
repoPath: z5.string(),
|
|
3216
|
+
title: z5.string().optional(),
|
|
3217
|
+
cowboy: z5.boolean().optional().describe(
|
|
3049
3218
|
"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."
|
|
3050
3219
|
),
|
|
3051
|
-
parentThreadId:
|
|
3220
|
+
parentThreadId: z5.string().optional().describe(
|
|
3052
3221
|
"Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
|
|
3053
3222
|
)
|
|
3054
3223
|
},
|
|
@@ -3064,10 +3233,10 @@ async function startMcpServer() {
|
|
|
3064
3233
|
"start_board_card",
|
|
3065
3234
|
"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.",
|
|
3066
3235
|
{
|
|
3067
|
-
kind:
|
|
3068
|
-
ref:
|
|
3069
|
-
repoPath:
|
|
3070
|
-
title:
|
|
3236
|
+
kind: z5.enum(["ticket", "pr", "branch"]),
|
|
3237
|
+
ref: z5.string().describe("Ticket identifier (ENG-12), PR number (44), or branch name from list_board"),
|
|
3238
|
+
repoPath: z5.string().describe("Workspace path from list_workspaces / list_board"),
|
|
3239
|
+
title: z5.string().optional()
|
|
3071
3240
|
},
|
|
3072
3241
|
async ({ kind, ref, repoPath, title }) => {
|
|
3073
3242
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -3171,9 +3340,9 @@ async function startMcpServer() {
|
|
|
3171
3340
|
"send_to_thread",
|
|
3172
3341
|
'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.',
|
|
3173
3342
|
{
|
|
3174
|
-
ref:
|
|
3175
|
-
prompt:
|
|
3176
|
-
force_stop:
|
|
3343
|
+
ref: z5.string(),
|
|
3344
|
+
prompt: z5.string(),
|
|
3345
|
+
force_stop: z5.boolean().optional()
|
|
3177
3346
|
},
|
|
3178
3347
|
async ({ ref, prompt, force_stop }) => {
|
|
3179
3348
|
if (force_stop) {
|
|
@@ -3202,8 +3371,8 @@ async function startMcpServer() {
|
|
|
3202
3371
|
"wait_for_turn",
|
|
3203
3372
|
"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).",
|
|
3204
3373
|
{
|
|
3205
|
-
ref:
|
|
3206
|
-
timeoutMs:
|
|
3374
|
+
ref: z5.string(),
|
|
3375
|
+
timeoutMs: z5.number().optional()
|
|
3207
3376
|
},
|
|
3208
3377
|
async ({ ref, timeoutMs }) => {
|
|
3209
3378
|
const thread = await orch.waitForTurn(ref, mcpWaitForTurnTimeoutMs(timeoutMs), {
|
|
@@ -3232,7 +3401,7 @@ async function startMcpServer() {
|
|
|
3232
3401
|
server.tool(
|
|
3233
3402
|
"get_turn_result",
|
|
3234
3403
|
"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).",
|
|
3235
|
-
{ ref:
|
|
3404
|
+
{ ref: z5.string() },
|
|
3236
3405
|
async ({ ref }) => {
|
|
3237
3406
|
const result = orch.getTurnResult(ref);
|
|
3238
3407
|
return {
|
|
@@ -3252,8 +3421,8 @@ async function startMcpServer() {
|
|
|
3252
3421
|
"stop_thread",
|
|
3253
3422
|
"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.",
|
|
3254
3423
|
{
|
|
3255
|
-
ref:
|
|
3256
|
-
force:
|
|
3424
|
+
ref: z5.string(),
|
|
3425
|
+
force: z5.boolean().optional()
|
|
3257
3426
|
},
|
|
3258
3427
|
async ({ ref, force }) => {
|
|
3259
3428
|
const t = orch.getThread(ref);
|
|
@@ -3283,7 +3452,7 @@ async function startMcpServer() {
|
|
|
3283
3452
|
server.tool(
|
|
3284
3453
|
"archive_thread",
|
|
3285
3454
|
"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.",
|
|
3286
|
-
{ ref:
|
|
3455
|
+
{ ref: z5.string() },
|
|
3287
3456
|
async ({ ref }) => {
|
|
3288
3457
|
const t = orch.getThread(ref);
|
|
3289
3458
|
if (!t) {
|
|
@@ -3316,7 +3485,7 @@ async function startMcpServer() {
|
|
|
3316
3485
|
server.tool(
|
|
3317
3486
|
"restore_thread",
|
|
3318
3487
|
"Restore an archived thread (recreates worktree from branch when needed)",
|
|
3319
|
-
{ ref:
|
|
3488
|
+
{ ref: z5.string() },
|
|
3320
3489
|
async ({ ref }) => {
|
|
3321
3490
|
try {
|
|
3322
3491
|
const restored = await orch.restore(ref);
|
|
@@ -3342,8 +3511,8 @@ async function startMcpServer() {
|
|
|
3342
3511
|
"get_diff",
|
|
3343
3512
|
"Compact diff summary (capped hunks, paginated)",
|
|
3344
3513
|
{
|
|
3345
|
-
ref:
|
|
3346
|
-
maxFiles:
|
|
3514
|
+
ref: z5.string(),
|
|
3515
|
+
maxFiles: z5.number().optional()
|
|
3347
3516
|
},
|
|
3348
3517
|
async ({ ref, maxFiles }) => {
|
|
3349
3518
|
const summary = await orch.diffSummary(ref);
|
|
@@ -3363,7 +3532,7 @@ async function startMcpServer() {
|
|
|
3363
3532
|
server.tool(
|
|
3364
3533
|
"request_review",
|
|
3365
3534
|
'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.',
|
|
3366
|
-
{ ref:
|
|
3535
|
+
{ ref: z5.string().describe("Worktree thread id/ref to review") },
|
|
3367
3536
|
async ({ ref }) => {
|
|
3368
3537
|
try {
|
|
3369
3538
|
const tab = await orch.requestReview(ref);
|
|
@@ -3392,8 +3561,8 @@ async function startMcpServer() {
|
|
|
3392
3561
|
"ask_git",
|
|
3393
3562
|
"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.",
|
|
3394
3563
|
{
|
|
3395
|
-
ref:
|
|
3396
|
-
action:
|
|
3564
|
+
ref: z5.string().describe("Worktree thread id/ref"),
|
|
3565
|
+
action: z5.enum(AGENT_GIT_ACTIONS).describe(
|
|
3397
3566
|
"commit-push | create-draft | create-web | resolve-conflicts | merge"
|
|
3398
3567
|
)
|
|
3399
3568
|
},
|
|
@@ -3420,7 +3589,7 @@ async function startMcpServer() {
|
|
|
3420
3589
|
}
|
|
3421
3590
|
}
|
|
3422
3591
|
);
|
|
3423
|
-
const agentEnum =
|
|
3592
|
+
const agentEnum = z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"]);
|
|
3424
3593
|
server.tool(
|
|
3425
3594
|
"list_models",
|
|
3426
3595
|
"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.",
|
|
@@ -3443,11 +3612,11 @@ async function startMcpServer() {
|
|
|
3443
3612
|
"fork_worktree",
|
|
3444
3613
|
"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.",
|
|
3445
3614
|
{
|
|
3446
|
-
ref:
|
|
3447
|
-
through_index:
|
|
3615
|
+
ref: z5.string().describe("Worktree thread id/ref to fork"),
|
|
3616
|
+
through_index: z5.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
3448
3617
|
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
3449
|
-
model:
|
|
3450
|
-
title:
|
|
3618
|
+
model: z5.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
3619
|
+
title: z5.string().optional()
|
|
3451
3620
|
},
|
|
3452
3621
|
async ({ ref, through_index, agent, model, title }) => {
|
|
3453
3622
|
try {
|
|
@@ -3488,11 +3657,11 @@ async function startMcpServer() {
|
|
|
3488
3657
|
"fork_chat",
|
|
3489
3658
|
"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.",
|
|
3490
3659
|
{
|
|
3491
|
-
ref:
|
|
3492
|
-
through_index:
|
|
3660
|
+
ref: z5.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
|
|
3661
|
+
through_index: z5.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
3493
3662
|
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
3494
|
-
model:
|
|
3495
|
-
title:
|
|
3663
|
+
model: z5.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
3664
|
+
title: z5.string().optional()
|
|
3496
3665
|
},
|
|
3497
3666
|
async ({ ref, through_index, agent, model, title }) => {
|
|
3498
3667
|
try {
|
|
@@ -3538,8 +3707,8 @@ async function startMcpServer() {
|
|
|
3538
3707
|
"run_dev_script",
|
|
3539
3708
|
"Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
|
|
3540
3709
|
{
|
|
3541
|
-
ref:
|
|
3542
|
-
name:
|
|
3710
|
+
ref: z5.string(),
|
|
3711
|
+
name: z5.string().optional()
|
|
3543
3712
|
},
|
|
3544
3713
|
async ({ ref, name }) => {
|
|
3545
3714
|
const result = await orch.startDev(ref, name);
|
|
@@ -3561,7 +3730,7 @@ async function startMcpServer() {
|
|
|
3561
3730
|
server.tool(
|
|
3562
3731
|
"list_run_scripts",
|
|
3563
3732
|
"List named run scripts available for a thread",
|
|
3564
|
-
{ ref:
|
|
3733
|
+
{ ref: z5.string() },
|
|
3565
3734
|
async ({ ref }) => {
|
|
3566
3735
|
const scripts = orch.listThreadRunScripts(ref);
|
|
3567
3736
|
const active = orch.getActiveRuns(ref);
|
|
@@ -3579,8 +3748,8 @@ async function startMcpServer() {
|
|
|
3579
3748
|
"stop_dev_script",
|
|
3580
3749
|
"Stop a running script for a thread (all scripts if name omitted)",
|
|
3581
3750
|
{
|
|
3582
|
-
ref:
|
|
3583
|
-
name:
|
|
3751
|
+
ref: z5.string(),
|
|
3752
|
+
name: z5.string().optional()
|
|
3584
3753
|
},
|
|
3585
3754
|
async ({ ref, name }) => {
|
|
3586
3755
|
orch.stopDev(ref, name);
|
|
@@ -3590,7 +3759,7 @@ async function startMcpServer() {
|
|
|
3590
3759
|
server.tool(
|
|
3591
3760
|
"run_setup",
|
|
3592
3761
|
"Re-run workspace setup (Sideboard/Conductor settings, .cursor/worktrees.json, or script/setup). New worktrees already run this automatically.",
|
|
3593
|
-
{ ref:
|
|
3762
|
+
{ ref: z5.string() },
|
|
3594
3763
|
async ({ ref }) => {
|
|
3595
3764
|
const result = await orch.runSetup(ref);
|
|
3596
3765
|
return {
|
|
@@ -3601,7 +3770,7 @@ async function startMcpServer() {
|
|
|
3601
3770
|
server.tool(
|
|
3602
3771
|
"add_workspace",
|
|
3603
3772
|
"Register a git repo as a Sideboard workspace",
|
|
3604
|
-
{ repoPath:
|
|
3773
|
+
{ repoPath: z5.string() },
|
|
3605
3774
|
async ({ repoPath }) => {
|
|
3606
3775
|
const ws = await orch.addWorkspace(repoPath);
|
|
3607
3776
|
return { content: [{ type: "text", text: JSON.stringify(ws) }] };
|
|
@@ -3610,7 +3779,7 @@ async function startMcpServer() {
|
|
|
3610
3779
|
server.tool(
|
|
3611
3780
|
"remove_workspace",
|
|
3612
3781
|
"Unregister a Sideboard workspace (does not archive threads)",
|
|
3613
|
-
{ repoPath:
|
|
3782
|
+
{ repoPath: z5.string() },
|
|
3614
3783
|
async ({ repoPath }) => {
|
|
3615
3784
|
orch.removeWorkspace(repoPath);
|
|
3616
3785
|
return { content: [{ type: "text", text: "ok" }] };
|
|
@@ -3620,12 +3789,12 @@ async function startMcpServer() {
|
|
|
3620
3789
|
"fanout",
|
|
3621
3790
|
"Best-of-n: create one thread per agent with the same prompt (parallel attempts)",
|
|
3622
3791
|
{
|
|
3623
|
-
prompt:
|
|
3624
|
-
agents:
|
|
3625
|
-
repoPath:
|
|
3626
|
-
sourceType:
|
|
3627
|
-
sourceRef:
|
|
3628
|
-
title:
|
|
3792
|
+
prompt: z5.string(),
|
|
3793
|
+
agents: z5.array(z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"])),
|
|
3794
|
+
repoPath: z5.string(),
|
|
3795
|
+
sourceType: z5.enum(["branch", "pr", "ticket"]).optional(),
|
|
3796
|
+
sourceRef: z5.string().optional(),
|
|
3797
|
+
title: z5.string().optional()
|
|
3629
3798
|
},
|
|
3630
3799
|
async (args) => {
|
|
3631
3800
|
const threads = await orch.bestOfN(args);
|
|
@@ -3652,8 +3821,8 @@ async function startMcpServer() {
|
|
|
3652
3821
|
"list_branches",
|
|
3653
3822
|
"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).",
|
|
3654
3823
|
{
|
|
3655
|
-
repoPath:
|
|
3656
|
-
unmergedOnly:
|
|
3824
|
+
repoPath: z5.string(),
|
|
3825
|
+
unmergedOnly: z5.boolean().optional()
|
|
3657
3826
|
},
|
|
3658
3827
|
async ({ repoPath, unmergedOnly }) => {
|
|
3659
3828
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -3673,7 +3842,7 @@ async function startMcpServer() {
|
|
|
3673
3842
|
server.tool(
|
|
3674
3843
|
"list_prs",
|
|
3675
3844
|
"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.",
|
|
3676
|
-
{ repoPath:
|
|
3845
|
+
{ repoPath: z5.string() },
|
|
3677
3846
|
async ({ repoPath }) => {
|
|
3678
3847
|
const root = await resolveRepoRoot(repoPath);
|
|
3679
3848
|
const prs = await listPrs(root);
|
|
@@ -3692,7 +3861,7 @@ async function startMcpServer() {
|
|
|
3692
3861
|
server.tool(
|
|
3693
3862
|
"get_pr_stack",
|
|
3694
3863
|
"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).",
|
|
3695
|
-
{ ref:
|
|
3864
|
+
{ ref: z5.string() },
|
|
3696
3865
|
async ({ ref }) => {
|
|
3697
3866
|
const stack = await orch.getPrStack(ref);
|
|
3698
3867
|
return {
|
|
@@ -3704,8 +3873,8 @@ async function startMcpServer() {
|
|
|
3704
3873
|
"open_pr_stack_layers",
|
|
3705
3874
|
"Materialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.",
|
|
3706
3875
|
{
|
|
3707
|
-
ref:
|
|
3708
|
-
layer:
|
|
3876
|
+
ref: z5.string(),
|
|
3877
|
+
layer: z5.number().int().positive().optional()
|
|
3709
3878
|
},
|
|
3710
3879
|
async ({ ref, layer }) => {
|
|
3711
3880
|
const result = await orch.openPrStackLayers(ref, { layer });
|
|
@@ -3739,9 +3908,9 @@ async function startMcpServer() {
|
|
|
3739
3908
|
"add_stack_layer",
|
|
3740
3909
|
"Add a branch on top of the current stack (`gh stack add`) and open a worktree+thread for it.",
|
|
3741
3910
|
{
|
|
3742
|
-
ref:
|
|
3743
|
-
branchName:
|
|
3744
|
-
title:
|
|
3911
|
+
ref: z5.string(),
|
|
3912
|
+
branchName: z5.string(),
|
|
3913
|
+
title: z5.string().optional()
|
|
3745
3914
|
},
|
|
3746
3915
|
async ({ ref, branchName, title }) => {
|
|
3747
3916
|
const result = await orch.addStackLayer(ref, branchName, { title });
|
|
@@ -3770,11 +3939,11 @@ async function startMcpServer() {
|
|
|
3770
3939
|
"create_pr_stack",
|
|
3771
3940
|
"Create a new GitHub PR stack with one Sideboard worktree per layer (bottom\u2192top branch names). Requires `gh extension install github/gh-stack`.",
|
|
3772
3941
|
{
|
|
3773
|
-
repoPath:
|
|
3774
|
-
branches:
|
|
3775
|
-
agent:
|
|
3776
|
-
base:
|
|
3777
|
-
title:
|
|
3942
|
+
repoPath: z5.string(),
|
|
3943
|
+
branches: z5.array(z5.string()).min(1),
|
|
3944
|
+
agent: z5.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
|
|
3945
|
+
base: z5.string().optional(),
|
|
3946
|
+
title: z5.string().optional()
|
|
3778
3947
|
},
|
|
3779
3948
|
async (args) => {
|
|
3780
3949
|
const result = await orch.createPrStack({
|
|
@@ -3811,8 +3980,8 @@ async function startMcpServer() {
|
|
|
3811
3980
|
);
|
|
3812
3981
|
server.tool(
|
|
3813
3982
|
"list_issues",
|
|
3814
|
-
"List issues from Sideboard Account connections (Linear
|
|
3815
|
-
{ repoPath:
|
|
3983
|
+
"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.",
|
|
3984
|
+
{ repoPath: z5.string() },
|
|
3816
3985
|
async ({ repoPath }) => {
|
|
3817
3986
|
const root = await resolveRepoRoot(repoPath);
|
|
3818
3987
|
const result = await listIssues(root);
|
|
@@ -3823,8 +3992,8 @@ async function startMcpServer() {
|
|
|
3823
3992
|
"list_linear_issues",
|
|
3824
3993
|
"Deprecated: prefer list_issues. Lists assigned Linear issues via the chosen agent MCP connector",
|
|
3825
3994
|
{
|
|
3826
|
-
agent:
|
|
3827
|
-
repoPath:
|
|
3995
|
+
agent: z5.enum(["claude", "codex", "opencode"]),
|
|
3996
|
+
repoPath: z5.string()
|
|
3828
3997
|
},
|
|
3829
3998
|
async ({ agent, repoPath }) => {
|
|
3830
3999
|
const issues = await listLinearIssues(agent, repoPath);
|
|
@@ -3945,8 +4114,8 @@ var BrightsySideboardApi = class {
|
|
|
3945
4114
|
};
|
|
3946
4115
|
function taskMessageText(task) {
|
|
3947
4116
|
const parts = task.message?.parts ?? [];
|
|
3948
|
-
const
|
|
3949
|
-
return
|
|
4117
|
+
const text5 = parts.find((p) => p.kind === "text")?.text ?? "";
|
|
4118
|
+
return text5.trim();
|
|
3950
4119
|
}
|
|
3951
4120
|
|
|
3952
4121
|
// src/brightsy/cloud-connect.ts
|
|
@@ -4488,11 +4657,11 @@ async function startSlackOAuth(opts) {
|
|
|
4488
4657
|
import { WebSocket as WsWebSocket } from "ws";
|
|
4489
4658
|
var BACKOFF_START_MS = 1e3;
|
|
4490
4659
|
var BACKOFF_MAX_MS = 3e4;
|
|
4491
|
-
function stripSlackMentions(
|
|
4492
|
-
return
|
|
4660
|
+
function stripSlackMentions(text5) {
|
|
4661
|
+
return text5.replace(/<@[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
4493
4662
|
}
|
|
4494
|
-
function isSlackStopCommand(
|
|
4495
|
-
const t = stripSlackMentions(
|
|
4663
|
+
function isSlackStopCommand(text5) {
|
|
4664
|
+
const t = stripSlackMentions(text5).toLowerCase();
|
|
4496
4665
|
return t === "stop" || t === "sideboard_force_stop";
|
|
4497
4666
|
}
|
|
4498
4667
|
function parseSlackSocketFrame(raw) {
|
|
@@ -4514,8 +4683,8 @@ function inboundFromSocketFrame(frame) {
|
|
|
4514
4683
|
const ts = event.ts?.trim();
|
|
4515
4684
|
if (!channelId || !ts) return null;
|
|
4516
4685
|
const rawText = event.text?.trim() ?? "";
|
|
4517
|
-
const
|
|
4518
|
-
if (!
|
|
4686
|
+
const text5 = stripSlackMentions(rawText);
|
|
4687
|
+
if (!text5) return null;
|
|
4519
4688
|
const teamId = (frame.payload?.team_id || event.team || "").trim();
|
|
4520
4689
|
if (!teamId) return null;
|
|
4521
4690
|
const isDm = event.type === "message" && (event.channel_type === "im" || event.channel_type === "mpim" || !event.channel_type && channelId.startsWith("D"));
|
|
@@ -4527,7 +4696,7 @@ function inboundFromSocketFrame(frame) {
|
|
|
4527
4696
|
ts,
|
|
4528
4697
|
threadTs: event.thread_ts?.trim() || void 0,
|
|
4529
4698
|
userId: event.user?.trim(),
|
|
4530
|
-
text:
|
|
4699
|
+
text: text5,
|
|
4531
4700
|
kind: isMention ? "mention" : "dm"
|
|
4532
4701
|
};
|
|
4533
4702
|
}
|
|
@@ -5067,12 +5236,12 @@ function formatSlackInboundPrompt(msg) {
|
|
|
5067
5236
|
|
|
5068
5237
|
${msg.text}`;
|
|
5069
5238
|
}
|
|
5070
|
-
function isSlackInboundUserPrompt(
|
|
5071
|
-
return
|
|
5239
|
+
function isSlackInboundUserPrompt(text5) {
|
|
5240
|
+
return text5.startsWith("Slack DM\n") || text5.startsWith("Slack @mention\n");
|
|
5072
5241
|
}
|
|
5073
|
-
function formatSlackSignedReply(deviceLabel,
|
|
5242
|
+
function formatSlackSignedReply(deviceLabel, text5) {
|
|
5074
5243
|
const label = deviceLabel.trim();
|
|
5075
|
-
const body =
|
|
5244
|
+
const body = text5.trim();
|
|
5076
5245
|
if (!body) return body;
|
|
5077
5246
|
if (!label) return body;
|
|
5078
5247
|
const head = `${label}:`;
|
|
@@ -5081,8 +5250,8 @@ function formatSlackSignedReply(deviceLabel, text4) {
|
|
|
5081
5250
|
}
|
|
5082
5251
|
return `${label}: ${body}`;
|
|
5083
5252
|
}
|
|
5084
|
-
function signForThisMac(
|
|
5085
|
-
return formatSlackSignedReply(ensureSlackDeviceIdentity().deviceLabel,
|
|
5253
|
+
function signForThisMac(text5) {
|
|
5254
|
+
return formatSlackSignedReply(ensureSlackDeviceIdentity().deviceLabel, text5);
|
|
5086
5255
|
}
|
|
5087
5256
|
function slackReplyThreadTs(msg) {
|
|
5088
5257
|
if (msg.threadTs && msg.threadTs !== msg.ts) return msg.threadTs;
|
|
@@ -5143,9 +5312,9 @@ function replyStub(target) {
|
|
|
5143
5312
|
kind: "dm"
|
|
5144
5313
|
};
|
|
5145
5314
|
}
|
|
5146
|
-
async function postSlackText(target,
|
|
5315
|
+
async function postSlackText(target, text5, opts) {
|
|
5147
5316
|
if (opts.postReply) {
|
|
5148
|
-
const result = await opts.postReply(replyStub(target),
|
|
5317
|
+
const result = await opts.postReply(replyStub(target), text5);
|
|
5149
5318
|
const ts2 = result && typeof result === "object" && typeof result.ts === "string" ? result.ts.trim() : "";
|
|
5150
5319
|
return ts2 ? { ts: ts2 } : null;
|
|
5151
5320
|
}
|
|
@@ -5155,7 +5324,7 @@ async function postSlackText(target, text4, opts) {
|
|
|
5155
5324
|
"chat.postMessage",
|
|
5156
5325
|
{
|
|
5157
5326
|
channel: target.channelId,
|
|
5158
|
-
text:
|
|
5327
|
+
text: text5,
|
|
5159
5328
|
thread_ts: target.threadTs
|
|
5160
5329
|
},
|
|
5161
5330
|
opts.fetchImpl
|
|
@@ -5163,9 +5332,9 @@ async function postSlackText(target, text4, opts) {
|
|
|
5163
5332
|
const ts = json.ts?.trim();
|
|
5164
5333
|
return ts ? { ts } : null;
|
|
5165
5334
|
}
|
|
5166
|
-
async function updateSlackText(target, ts,
|
|
5335
|
+
async function updateSlackText(target, ts, text5, opts) {
|
|
5167
5336
|
if (opts.updateReply) {
|
|
5168
|
-
await opts.updateReply(replyStub(target), ts,
|
|
5337
|
+
await opts.updateReply(replyStub(target), ts, text5);
|
|
5169
5338
|
return;
|
|
5170
5339
|
}
|
|
5171
5340
|
const token = writeTokenForTeam(target.teamId);
|
|
@@ -5175,7 +5344,7 @@ async function updateSlackText(target, ts, text4, opts) {
|
|
|
5175
5344
|
{
|
|
5176
5345
|
channel: target.channelId,
|
|
5177
5346
|
ts,
|
|
5178
|
-
text:
|
|
5347
|
+
text: text5
|
|
5179
5348
|
},
|
|
5180
5349
|
opts.fetchImpl
|
|
5181
5350
|
);
|
|
@@ -5203,8 +5372,8 @@ function replyTargetOf(msg) {
|
|
|
5203
5372
|
threadTs: slackReplyThreadTs(msg)
|
|
5204
5373
|
};
|
|
5205
5374
|
}
|
|
5206
|
-
async function postSlackReply(msg,
|
|
5207
|
-
await postSlackText(replyTargetOf(msg), signForThisMac(
|
|
5375
|
+
async function postSlackReply(msg, text5, opts) {
|
|
5376
|
+
await postSlackText(replyTargetOf(msg), signForThisMac(text5), opts);
|
|
5208
5377
|
}
|
|
5209
5378
|
function startSlackTurnProgress(msg, threadId, opts) {
|
|
5210
5379
|
const log = opts.onLog ?? (() => void 0);
|
|
@@ -5287,10 +5456,10 @@ function startSlackTurnProgress(msg, threadId, opts) {
|
|
|
5287
5456
|
}
|
|
5288
5457
|
});
|
|
5289
5458
|
},
|
|
5290
|
-
finishWith: (
|
|
5459
|
+
finishWith: (text5) => {
|
|
5291
5460
|
stop();
|
|
5292
5461
|
return run2(async () => {
|
|
5293
|
-
const signed = signForThisMac(
|
|
5462
|
+
const signed = signForThisMac(text5.trim());
|
|
5294
5463
|
if (!signed) {
|
|
5295
5464
|
if (!postedTs) return;
|
|
5296
5465
|
const ts = postedTs;
|
|
@@ -5318,11 +5487,11 @@ function startSlackTurnProgress(msg, threadId, opts) {
|
|
|
5318
5487
|
};
|
|
5319
5488
|
}
|
|
5320
5489
|
var lastRelayed = /* @__PURE__ */ new Map();
|
|
5321
|
-
function markRelayed(threadId,
|
|
5322
|
-
lastRelayed.set(threadId, `${threadId}:${
|
|
5490
|
+
function markRelayed(threadId, text5) {
|
|
5491
|
+
lastRelayed.set(threadId, `${threadId}:${text5}`);
|
|
5323
5492
|
}
|
|
5324
|
-
function alreadyRelayed(threadId,
|
|
5325
|
-
return lastRelayed.get(threadId) === `${threadId}:${
|
|
5493
|
+
function alreadyRelayed(threadId, text5) {
|
|
5494
|
+
return lastRelayed.get(threadId) === `${threadId}:${text5}`;
|
|
5326
5495
|
}
|
|
5327
5496
|
async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
5328
5497
|
const target = getSlackReplyTarget(threadId);
|
|
@@ -5331,14 +5500,14 @@ async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
|
5331
5500
|
const lastUser = thread ? [...thread.messages].reverse().find((m) => m.role === "user") : void 0;
|
|
5332
5501
|
if (lastUser && isSlackInboundUserPrompt(lastUser.text)) return;
|
|
5333
5502
|
const result = getOrchestrator().getTurnResult(threadId);
|
|
5334
|
-
const
|
|
5335
|
-
if (!
|
|
5336
|
-
if (alreadyRelayed(threadId,
|
|
5337
|
-
markRelayed(threadId,
|
|
5503
|
+
const text5 = result.text.trim();
|
|
5504
|
+
if (!text5) return;
|
|
5505
|
+
if (alreadyRelayed(threadId, text5)) return;
|
|
5506
|
+
markRelayed(threadId, text5);
|
|
5338
5507
|
const log = opts.onLog ?? (() => void 0);
|
|
5339
5508
|
try {
|
|
5340
|
-
await postSlackText(target, signForThisMac(
|
|
5341
|
-
log(`replied ${target.threadTs ?? target.channelId} (${
|
|
5509
|
+
await postSlackText(target, signForThisMac(text5), opts);
|
|
5510
|
+
log(`replied ${target.threadTs ?? target.channelId} (${text5.length} chars)`);
|
|
5342
5511
|
} catch (err) {
|
|
5343
5512
|
lastRelayed.delete(threadId);
|
|
5344
5513
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -5586,10 +5755,10 @@ function resolveSlackListenMode(opts) {
|
|
|
5586
5755
|
}
|
|
5587
5756
|
|
|
5588
5757
|
// src/slack/relay-hub.ts
|
|
5589
|
-
function parseSlackDeviceDestination(
|
|
5590
|
-
const m =
|
|
5591
|
-
if (!m) return { label: null, rest:
|
|
5592
|
-
return { label: m[1], rest:
|
|
5758
|
+
function parseSlackDeviceDestination(text5) {
|
|
5759
|
+
const m = text5.match(/^\s*(?:to\s+)?(?:@|#)?([A-Za-z][\w-]{0,63})\s*[::]\s*/);
|
|
5760
|
+
if (!m) return { label: null, rest: text5 };
|
|
5761
|
+
return { label: m[1], rest: text5.slice(m[0].length) };
|
|
5593
5762
|
}
|
|
5594
5763
|
var SlackRelayHub = class {
|
|
5595
5764
|
sessions = /* @__PURE__ */ new Map();
|
|
@@ -6110,6 +6279,7 @@ async function startSlackRelayServer(opts) {
|
|
|
6110
6279
|
};
|
|
6111
6280
|
}
|
|
6112
6281
|
export {
|
|
6282
|
+
ABLETIME_MCP_PATH,
|
|
6113
6283
|
AGENT_GIT_ACTIONS,
|
|
6114
6284
|
AGENT_RUNNER_MAX_OLD_SPACE_MB,
|
|
6115
6285
|
ATTACHMENTS_DIR,
|
|
@@ -6127,6 +6297,7 @@ export {
|
|
|
6127
6297
|
CONTEXT_MIN_MESSAGES,
|
|
6128
6298
|
CONVENTION_SETUP_RELPATHS,
|
|
6129
6299
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
6300
|
+
DEFAULT_ABLETIME_HOST,
|
|
6130
6301
|
DEFAULT_WORKTREE_SORT,
|
|
6131
6302
|
FAMOUS_SOCCER_TEAMS,
|
|
6132
6303
|
GITHUB_GIT_AUTH_MODES,
|
|
@@ -6174,6 +6345,8 @@ export {
|
|
|
6174
6345
|
SlackRelayHub,
|
|
6175
6346
|
THINKING_EFFORTS,
|
|
6176
6347
|
WORKTREE_MCP_TOOLS,
|
|
6348
|
+
abletimeMcpRequest,
|
|
6349
|
+
abletimeMcpUrl,
|
|
6177
6350
|
ackSlackInboundSeen,
|
|
6178
6351
|
addBoardPin,
|
|
6179
6352
|
addPrStackLayer,
|
|
@@ -6230,6 +6403,7 @@ export {
|
|
|
6230
6403
|
caffeinateWhileRunningEnabled,
|
|
6231
6404
|
caffeinateWhileSchedulesEnabled,
|
|
6232
6405
|
caffeinateWhileSlackListenEnabled,
|
|
6406
|
+
callAbleTimeTool,
|
|
6233
6407
|
canonicalizeRepoPath,
|
|
6234
6408
|
captureLoginEnv,
|
|
6235
6409
|
captureTurnBaseline,
|
|
@@ -6263,6 +6437,7 @@ export {
|
|
|
6263
6437
|
copyConfiguredFiles,
|
|
6264
6438
|
countCacheControlBlocks,
|
|
6265
6439
|
cowboyModeEnabled,
|
|
6440
|
+
createAbleTimeTask,
|
|
6266
6441
|
createChatTab,
|
|
6267
6442
|
createEmptyThread,
|
|
6268
6443
|
createExistingBranchWorktree,
|
|
@@ -6286,6 +6461,7 @@ export {
|
|
|
6286
6461
|
detectAgents,
|
|
6287
6462
|
detectGhStack,
|
|
6288
6463
|
detectLocalMergeConflicts,
|
|
6464
|
+
disconnectAbleTimeConnection,
|
|
6289
6465
|
disconnectBrightsyTeam,
|
|
6290
6466
|
disconnectLinear,
|
|
6291
6467
|
disconnectLinearConnection,
|
|
@@ -6295,6 +6471,7 @@ export {
|
|
|
6295
6471
|
encodeBrightsyTarget,
|
|
6296
6472
|
enrichPathWithNpmGlobalBin,
|
|
6297
6473
|
enrichWorkspacesWithGithub,
|
|
6474
|
+
ensureAbleTimeTask,
|
|
6298
6475
|
ensureAgentPath,
|
|
6299
6476
|
ensureBrightsyLocalConfigFresh,
|
|
6300
6477
|
ensureCloudCoordinator,
|
|
@@ -6355,6 +6532,10 @@ export {
|
|
|
6355
6532
|
formatWorktreeDirective,
|
|
6356
6533
|
formatWorktreeReminder,
|
|
6357
6534
|
fromInclusiveInputUsage,
|
|
6535
|
+
getAbleTimeAccessToken,
|
|
6536
|
+
getAbleTimeHost,
|
|
6537
|
+
getAbleTimeOrientation,
|
|
6538
|
+
getAbleTimeTask,
|
|
6358
6539
|
getAdapter,
|
|
6359
6540
|
getAgentSetupInfo,
|
|
6360
6541
|
getBrightsySession,
|
|
@@ -6413,6 +6594,8 @@ export {
|
|
|
6413
6594
|
inspectGitWorktree,
|
|
6414
6595
|
installAgent,
|
|
6415
6596
|
interruptSlackCoordinatorForInbound,
|
|
6597
|
+
invalidateThreadListCache,
|
|
6598
|
+
isAbleTimeConnected,
|
|
6416
6599
|
isAskUserToolName,
|
|
6417
6600
|
isBrightsyConnected,
|
|
6418
6601
|
isBrightsyNdjsonLine,
|
|
@@ -6453,6 +6636,7 @@ export {
|
|
|
6453
6636
|
isThreadCaffeinated,
|
|
6454
6637
|
isThreadRecordFile,
|
|
6455
6638
|
isWorkspaceScratchPath,
|
|
6639
|
+
issueAttachmentForAbleTimeTask,
|
|
6456
6640
|
issueSourceLabel,
|
|
6457
6641
|
lastRequestOccupancy,
|
|
6458
6642
|
latestPendingPlanQuestions,
|
|
@@ -6461,6 +6645,9 @@ export {
|
|
|
6461
6645
|
linearGraphql,
|
|
6462
6646
|
linearOAuthAuthorizeUrl,
|
|
6463
6647
|
linearOAuthCredentials,
|
|
6648
|
+
listAbleTimeAssignedIssues,
|
|
6649
|
+
listAbleTimeProjects,
|
|
6650
|
+
listAbleTimeTasks,
|
|
6464
6651
|
listAgentSetupInfo,
|
|
6465
6652
|
listBoardPins,
|
|
6466
6653
|
listBranchCommits,
|
|
@@ -6500,6 +6687,7 @@ export {
|
|
|
6500
6687
|
locksDir,
|
|
6501
6688
|
loginAgent,
|
|
6502
6689
|
lookupSoccerTeam,
|
|
6690
|
+
mapAbleTimeTask,
|
|
6503
6691
|
maxConcurrentAgents,
|
|
6504
6692
|
maybeCompactContext,
|
|
6505
6693
|
mcpAllowTools,
|
|
@@ -6513,6 +6701,7 @@ export {
|
|
|
6513
6701
|
nextPastedTextName,
|
|
6514
6702
|
nextThinkingEffort,
|
|
6515
6703
|
nonInteractiveGitProcessEnv,
|
|
6704
|
+
normalizeAbleTimeHost,
|
|
6516
6705
|
normalizeParseResult,
|
|
6517
6706
|
normalizeThinkingEffort,
|
|
6518
6707
|
normalizeThread,
|
|
@@ -6606,6 +6795,7 @@ export {
|
|
|
6606
6795
|
resolveThreadEffort,
|
|
6607
6796
|
resolveVaultKey,
|
|
6608
6797
|
resolveWorktreeStartPoint,
|
|
6798
|
+
rewriteAbleTimeError,
|
|
6609
6799
|
rewriteLinearError,
|
|
6610
6800
|
run,
|
|
6611
6801
|
runArchiveScript,
|
|
@@ -6618,10 +6808,12 @@ export {
|
|
|
6618
6808
|
runWorkspaceSetup,
|
|
6619
6809
|
sameWorktreePath,
|
|
6620
6810
|
sanitizeMcpServerName,
|
|
6811
|
+
saveAbleTimeConnection,
|
|
6621
6812
|
saveAppSettings,
|
|
6622
6813
|
saveLinearOAuth,
|
|
6623
6814
|
schedulesPath,
|
|
6624
6815
|
scrubGithubTokensFromChildEnv,
|
|
6816
|
+
searchAbleTimeTasks,
|
|
6625
6817
|
secureFileUnlocksWith,
|
|
6626
6818
|
setCaffeinateHold,
|
|
6627
6819
|
setHttpFetchImpl,
|
|
@@ -6672,6 +6864,7 @@ export {
|
|
|
6672
6864
|
takenTeamSlugsForChatTab,
|
|
6673
6865
|
takenTeamSlugsForOrchestration,
|
|
6674
6866
|
taskMessageText,
|
|
6867
|
+
taskUrl,
|
|
6675
6868
|
thinkingEffortBars,
|
|
6676
6869
|
thinkingEffortLabel,
|
|
6677
6870
|
thisProcessShouldDrainAgentQueues,
|
|
@@ -6682,6 +6875,7 @@ export {
|
|
|
6682
6875
|
threadRequestsBrightsyMcp,
|
|
6683
6876
|
threadsDir,
|
|
6684
6877
|
threadsSharingWorktree,
|
|
6878
|
+
toAbleTimeIssueInfo,
|
|
6685
6879
|
toPublicAppSettings,
|
|
6686
6880
|
toolActivityLine,
|
|
6687
6881
|
toolDescription,
|
|
@@ -6704,6 +6898,7 @@ export {
|
|
|
6704
6898
|
userClaudeMcpConfigPath,
|
|
6705
6899
|
userCursorMcpConfigPath,
|
|
6706
6900
|
validateLinearApiKey,
|
|
6901
|
+
verifyAbleTimeConnection,
|
|
6707
6902
|
waitForPidExit,
|
|
6708
6903
|
warmGithubAgentAuth,
|
|
6709
6904
|
withAgentInstructions,
|