@sideboard-ai/core 0.1.152 → 0.1.153

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.
Files changed (61) hide show
  1. package/dist/{abletime-223A3LY6.js → abletime-H7LPGIP2.js} +3 -3
  2. package/dist/{abletime-CLC5UJC2.js → abletime-JSTJLXAW.js} +3 -3
  3. package/dist/agents/cursor-runner.js +2 -2
  4. package/dist/{agents-CUKWIM34.js → agents-V24DYZI4.js} +8 -9
  5. package/dist/{agents-VHXCBBBD.js → agents-YVW75KBO.js} +8 -9
  6. package/dist/{app-settings-3CHCNIMD.js → app-settings-H3INSR67.js} +38 -4
  7. package/dist/{app-settings-J3JBCUOT.js → app-settings-VRQI3FIE.js} +38 -4
  8. package/dist/{caffeinate-hold-NBRUWYXO.js → caffeinate-hold-DBKMRZZO.js} +2 -2
  9. package/dist/{caffeinate-hold-X3JNPR42.js → caffeinate-hold-SK2QISPE.js} +2 -2
  10. package/dist/chunk-2F63IMCL.js +959 -0
  11. package/dist/{chunk-7BQNSUR2.js → chunk-2NRNP7QP.js} +357 -185
  12. package/dist/{chunk-4XNSGDXE.js → chunk-3BWVOUQG.js} +244 -1
  13. package/dist/{chunk-EY6QXPPO.js → chunk-4THE3EY7.js} +6 -6
  14. package/dist/{chunk-TUGKX5BD.js → chunk-7UURXPKD.js} +1 -1
  15. package/dist/{chunk-DCOZABNT.js → chunk-AO35MGOE.js} +1 -1
  16. package/dist/{chunk-3JBMACYX.js → chunk-CJQLPPEJ.js} +387 -15
  17. package/dist/{chunk-CZD4NRDZ.js → chunk-D7EGJ3EI.js} +244 -1
  18. package/dist/{chunk-QZQEXME2.js → chunk-EFVFB2AH.js} +1 -1
  19. package/dist/{chunk-B7XK37WZ.js → chunk-FDCFXMDG.js} +1 -1
  20. package/dist/{chunk-WLV7TRMR.js → chunk-JOK4XWBG.js} +1 -1
  21. package/dist/{chunk-BD2ICC4D.js → chunk-JTJHOYCU.js} +1 -1
  22. package/dist/{chunk-6X7Z34XE.js → chunk-KMNODRWF.js} +397 -173
  23. package/dist/{chunk-GE7M3QTE.js → chunk-LQMFCS54.js} +387 -15
  24. package/dist/{chunk-G7SIQFBQ.js → chunk-LZ6QMEQC.js} +1 -1
  25. package/dist/{chunk-EUXOHTUK.js → chunk-LZQULFIT.js} +1 -1
  26. package/dist/{chunk-KLBOWJ74.js → chunk-OCQPTUR7.js} +1 -1
  27. package/dist/{chunk-GFQ57XAX.js → chunk-QZEZXYVV.js} +13 -13
  28. package/dist/chunk-RNC3GR6L.js +905 -0
  29. package/dist/{chunk-VHX673DI.js → chunk-WLPXZFRE.js} +1 -1
  30. package/dist/{chunk-7F4XE6UG.js → chunk-XD2BAANL.js} +5 -5
  31. package/dist/{connected-teams-XO766HB4.js → connected-teams-DBWAMP7G.js} +2 -2
  32. package/dist/{connected-teams-I2WZZZFA.js → connected-teams-WGONUQOF.js} +2 -2
  33. package/dist/{coordinator-prompt-WGFRYCHE.js → coordinator-prompt-7FHKCWXB.js} +5 -5
  34. package/dist/{coordinator-prompt-TBX4MOFM.js → coordinator-prompt-KX2FVVYT.js} +5 -5
  35. package/dist/{cursor-recover-NOQYOFRF.js → cursor-recover-L5MD6MBO.js} +1 -1
  36. package/dist/{cursor-recover-QSLWEZNA.js → cursor-recover-NDMLLNYX.js} +2 -2
  37. package/dist/{global-workspace-IY5QAV5C.js → global-workspace-2BRRKSDN.js} +5 -6
  38. package/dist/{global-workspace-BHLUJ46D.js → global-workspace-4LHCZ2DC.js} +5 -6
  39. package/dist/index.cjs +1875 -765
  40. package/dist/index.d.cts +195 -11
  41. package/dist/index.d.ts +195 -11
  42. package/dist/index.js +298 -108
  43. package/dist/mcp/run-stdio.cjs +1743 -1228
  44. package/dist/mcp/run-stdio.js +232 -80
  45. package/dist/{orchestrator-NUA6SEV7.js → orchestrator-5PSHBLP6.js} +10 -12
  46. package/dist/{orchestrator-256DFPSX.js → orchestrator-ZSSU3FKW.js} +9 -11
  47. package/dist/{paths-UMEDHOS5.js → paths-53TLA7VQ.js} +1 -1
  48. package/dist/{paths-QCI3MTO5.js → paths-RRCLNSJB.js} +1 -1
  49. package/dist/{thread-store-WGASXXXR.js → thread-store-KBFBHT5G.js} +2 -2
  50. package/dist/{thread-store-57ZLHR3A.js → thread-store-MVQU6HPJ.js} +2 -2
  51. package/dist/{workspaces-4FSXVIZM.js → workspaces-5UNDTN4G.js} +5 -7
  52. package/dist/{workspaces-NECIQTAO.js → workspaces-MQYNZXUK.js} +5 -7
  53. package/dist/{worktree-HTUM35NT.js → worktree-PEWDAX5O.js} +4 -4
  54. package/dist/{worktree-DPIREDFR.js → worktree-T4SWFSTT.js} +4 -4
  55. package/package.json +1 -1
  56. package/dist/chunk-2U6QF3PT.js +0 -211
  57. package/dist/chunk-67TIJ7S5.js +0 -122
  58. package/dist/chunk-7TIUOYBK.js +0 -213
  59. package/dist/chunk-G4MTYUWS.js +0 -592
  60. package/dist/chunk-K2ANSHUO.js +0 -120
  61. package/dist/chunk-SN6CMKF6.js +0 -538
@@ -19,7 +19,6 @@ import {
19
19
  getSchedule,
20
20
  isAccountWideIssueSource,
21
21
  issueNeedsWorkspacePick,
22
- listLinearIssues,
23
22
  listSchedules,
24
23
  listSlackOutboundWatches,
25
24
  listSlackWorkspaces,
@@ -32,19 +31,14 @@ import {
32
31
  slackTokenFor,
33
32
  syncBoardPins,
34
33
  updateSchedule
35
- } from "../chunk-7BQNSUR2.js";
34
+ } from "../chunk-2NRNP7QP.js";
36
35
  import {
37
36
  isInternalAgentStatusText,
38
37
  listModelsForAgent,
39
38
  sideboardMcpProfile
40
- } from "../chunk-EY6QXPPO.js";
41
- import "../chunk-G7SIQFBQ.js";
39
+ } from "../chunk-4THE3EY7.js";
40
+ import "../chunk-LZ6QMEQC.js";
42
41
  import "../chunk-S42XV45P.js";
43
- import "../chunk-67TIJ7S5.js";
44
- import {
45
- GLOBAL_WORKSPACE_ID,
46
- isCloudCoordinatorThread
47
- } from "../chunk-SN6CMKF6.js";
48
42
  import {
49
43
  createAbleTimeTask,
50
44
  ensureAbleTimeTask,
@@ -55,24 +49,28 @@ import {
55
49
  listAbleTimeTasks,
56
50
  searchAbleTimeTasks,
57
51
  toAbleTimeIssueInfo
58
- } from "../chunk-B7XK37WZ.js";
52
+ } from "../chunk-FDCFXMDG.js";
59
53
  import {
60
54
  httpFetch
61
55
  } from "../chunk-6GN5WPYZ.js";
62
56
  import "../chunk-2SDMENAL.js";
63
- import "../chunk-KLBOWJ74.js";
64
- import "../chunk-7TIUOYBK.js";
57
+ import "../chunk-OCQPTUR7.js";
58
+ import {
59
+ GLOBAL_WORKSPACE_ID,
60
+ isCloudCoordinatorThread
61
+ } from "../chunk-RNC3GR6L.js";
65
62
  import {
66
63
  canonicalizeRepoPath,
67
64
  formatGhLandError,
68
65
  listBranches,
69
66
  listPrs,
70
67
  resolveGithubRepoSlug,
68
+ resolveListPrsOptions,
71
69
  resolveRepoRoot,
72
70
  warmGithubAgentAuth
73
- } from "../chunk-3JBMACYX.js";
71
+ } from "../chunk-CJQLPPEJ.js";
74
72
  import "../chunk-NVXVEGGM.js";
75
- import "../chunk-EUXOHTUK.js";
73
+ import "../chunk-LZQULFIT.js";
76
74
  import "../chunk-SYFVUF2C.js";
77
75
  import {
78
76
  gh
@@ -80,17 +78,20 @@ import {
80
78
  import {
81
79
  disconnectLinearConnection,
82
80
  dropNestedElectronEnvFromProcess,
81
+ formatWorkspaceProfileSuffix,
83
82
  isAbleTimeConnected,
84
83
  isLinearConnected,
85
84
  loadAppSettings,
86
85
  resolveEffectiveIssueSource,
86
+ resolveViewerProfile,
87
+ resolveViewerProfileForRepo,
87
88
  saveLinearOAuth
88
- } from "../chunk-CZD4NRDZ.js";
89
+ } from "../chunk-D7EGJ3EI.js";
89
90
  import "../chunk-NSTQ6QKD.js";
90
91
  import "../chunk-KGZBYWZ3.js";
91
92
  import {
92
93
  appDataDir
93
- } from "../chunk-BD2ICC4D.js";
94
+ } from "../chunk-JTJHOYCU.js";
94
95
 
95
96
  // src/mcp/server.ts
96
97
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -229,7 +230,7 @@ var ISSUE_FIELDS = `
229
230
  state { id name type }
230
231
  assignee { id name }
231
232
  creator { id name }
232
- team { id key name states(first: 50) { nodes { id name type } } }
233
+ team { id key name }
233
234
  labels(first: 50) { nodes { name } }
234
235
  cycle { name number startsAt endsAt completedAt }
235
236
  project { id name }
@@ -704,7 +705,9 @@ async function updateLinearIssue(input, opts) {
704
705
  }
705
706
  if (input.state?.trim()) {
706
707
  const existing = await getLinearIssue(issueId, opts);
707
- const team = existing.team;
708
+ const { teams } = await listLinearTeams(opts);
709
+ const teamRef = existing.team?.key || existing.team?.id;
710
+ const team = teamRef ? resolveLinearTeam(teams, teamRef) : void 0;
708
711
  if (!team?.states.length) {
709
712
  throw new Error(`Linear issue ${existing.identifier} has no workflow states to resolve "${input.state}"`);
710
713
  }
@@ -751,6 +754,11 @@ async function commentLinearIssue(input, opts) {
751
754
  function assigneeKey(assignee) {
752
755
  return (assignee ?? "").trim().toLowerCase();
753
756
  }
757
+ function takeIssuePage(issues, limit) {
758
+ if (limit == null) return issues;
759
+ const n = Math.max(1, Math.min(1e3, Math.floor(limit)));
760
+ return issues.slice(0, n);
761
+ }
754
762
  function issueMatchesAssignee(issue, assignee, viewerName = "") {
755
763
  const key = assigneeKey(assignee);
756
764
  if (!key || key === "all" || key === "*") return true;
@@ -852,13 +860,33 @@ async function listIssues(repoPath, opts) {
852
860
  };
853
861
  }
854
862
  if (source === "abletime") {
855
- const [listed, searched] = await Promise.all([
856
- listAbleTimeAssignedIssues(),
857
- query ? searchAbleTimeTasks(query) : Promise.resolve(null)
858
- ]);
863
+ if (query) {
864
+ const [searched, orientation] = await Promise.all([
865
+ searchAbleTimeTasks(query),
866
+ getAbleTimeOrientation().catch(() => null)
867
+ ]);
868
+ const viewerName2 = orientation?.viewer.name ?? orientation?.viewer.id ?? "";
869
+ const issues3 = takeIssuePage(
870
+ searched.map(toAbleTimeIssueInfo).filter((issue) => issueMatchesAssignee(issue, assignee, viewerName2)),
871
+ opts?.limit
872
+ );
873
+ return {
874
+ source,
875
+ preferredSource,
876
+ linearConnected,
877
+ abletimeConnected,
878
+ issues: issues3,
879
+ viewer: {
880
+ login: orientation?.viewer.name,
881
+ name: orientation?.viewer.name
882
+ }
883
+ };
884
+ }
885
+ const listed = await listAbleTimeAssignedIssues();
859
886
  const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
860
- const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
861
- (issue) => issueMatchesAssignee(issue, assignee, viewerName)
887
+ const issues2 = takeIssuePage(
888
+ listed.issues.filter((issue) => issueMatchesAssignee(issue, assignee, viewerName)),
889
+ opts?.limit
862
890
  );
863
891
  return {
864
892
  source,
@@ -1440,12 +1468,53 @@ function registerSlackTools(server) {
1440
1468
 
1441
1469
  // src/mcp/abletime-tools.ts
1442
1470
  import { z as z2 } from "zod";
1443
- function text2(payload, isError = false) {
1471
+
1472
+ // src/mcp/issue-list.ts
1473
+ var MCP_ISSUE_LIST_DEFAULT_LIMIT = 40;
1474
+ var MCP_ISSUE_LIST_MAX_LIMIT = 250;
1475
+ function clampMcpIssueLimit(limit) {
1476
+ if (limit == null || !Number.isFinite(limit)) return MCP_ISSUE_LIST_DEFAULT_LIMIT;
1477
+ return Math.max(1, Math.min(MCP_ISSUE_LIST_MAX_LIMIT, Math.floor(limit)));
1478
+ }
1479
+ function applyIssueListWindow(items, limit) {
1480
+ const truncated = items.length > limit;
1444
1481
  return {
1445
- content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
1482
+ items: truncated ? items.slice(0, limit) : items,
1483
+ truncated
1484
+ };
1485
+ }
1486
+ function compactIssueRow(issue) {
1487
+ return {
1488
+ identifier: issue.identifier,
1489
+ title: issue.title,
1490
+ ...issue.assignee ? { assignee: issue.assignee } : {},
1491
+ ...issue.labels.length > 0 ? { labels: issue.labels } : {},
1492
+ ...issue.teamKey ? { team: issue.teamKey } : {},
1493
+ ...issue.cycle?.name ? { cycle: issue.cycle.name } : {}
1494
+ };
1495
+ }
1496
+ function formatMcpIssueList(input) {
1497
+ return {
1498
+ ...input.source ? { source: input.source } : {},
1499
+ ...input.viewer ? { viewer: input.viewer } : {},
1500
+ limit: input.limit,
1501
+ returned: input.issues.length,
1502
+ truncated: input.truncated,
1503
+ ...input.truncated ? { hint: "More issues match. Pass a higher limit (max 250) or a tighter query." } : {},
1504
+ issues: input.issues.map(compactIssueRow)
1505
+ };
1506
+ }
1507
+ function mcpJson(payload, isError = false) {
1508
+ return {
1509
+ content: [{ type: "text", text: JSON.stringify(payload) }],
1446
1510
  ...isError ? { isError: true } : {}
1447
1511
  };
1448
1512
  }
1513
+
1514
+ // src/mcp/abletime-tools.ts
1515
+ function text2(payload, isError = false) {
1516
+ return mcpJson(payload, isError);
1517
+ }
1449
1518
  function fail2(err) {
1450
1519
  return text2(
1451
1520
  { error: err instanceof Error ? err.message : String(err) },
@@ -1455,7 +1524,7 @@ function fail2(err) {
1455
1524
  function registerAbleTimeTools(server) {
1456
1525
  server.tool(
1457
1526
  "abletime_orientation",
1458
- "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.",
1527
+ "Call first when using AbleTime. Returns viewer, active tasks, and projects.",
1459
1528
  {},
1460
1529
  async () => {
1461
1530
  try {
@@ -1472,7 +1541,7 @@ function registerAbleTimeTools(server) {
1472
1541
  );
1473
1542
  server.tool(
1474
1543
  "abletime_list_projects",
1475
- "List AbleTime projects (and categories) the Account token can see. Use a project id on abletime_create_task / abletime_ensure_task.",
1544
+ "List AbleTime projects (and categories). Use a project id on create/ensure.",
1476
1545
  {},
1477
1546
  async () => {
1478
1547
  try {
@@ -1540,7 +1609,7 @@ function registerAbleTimeTools(server) {
1540
1609
  );
1541
1610
  server.tool(
1542
1611
  "abletime_ensure_task",
1543
- "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.",
1612
+ "Find or create an AbleTime task for this work, then create_thread with sourceType=ticket.",
1544
1613
  {
1545
1614
  title: z2.string(),
1546
1615
  description: z2.string().optional(),
@@ -1561,10 +1630,7 @@ function registerAbleTimeTools(server) {
1561
1630
  // src/mcp/linear-tools.ts
1562
1631
  import { z as z3 } from "zod";
1563
1632
  function text3(payload, isError = false) {
1564
- return {
1565
- content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
1566
- ...isError ? { isError: true } : {}
1567
- };
1633
+ return mcpJson(payload, isError);
1568
1634
  }
1569
1635
  function fail3(err) {
1570
1636
  return text3(
@@ -1576,7 +1642,7 @@ var prioritySchema = z3.number().int().min(0).max(4).optional().describe("0 none
1576
1642
  function registerLinearTools(server) {
1577
1643
  server.tool(
1578
1644
  "linear_list_teams",
1579
- "List Linear teams (id, key, name) and workflow states for the connected Account. Use team key (e.g. ENG) on linear_create_issue; use state name or type (started, completed) on create/update. Viewer id is for assignee=me.",
1645
+ "List Linear teams (id, key, name) and workflow states. Use team key on create; state name or type on create/update.",
1580
1646
  {},
1581
1647
  async () => {
1582
1648
  try {
@@ -1588,15 +1654,30 @@ function registerLinearTools(server) {
1588
1654
  );
1589
1655
  server.tool(
1590
1656
  "linear_search_issues",
1591
- "Search or list open Linear issues. Not limited to the current user \u2014 pass assignee=unassigned for issues with no owner, assignee=all (default when query is set) for anyone including unassigned, assignee=me for yours, or a user id / name. Optional query uses Linear search (title, identifier, description).",
1657
+ "Search or list open Linear issues. Default 40; pass query and/or limit (max 250) when truncated. assignee: me, unassigned, all (default with query), or a user id/name.",
1592
1658
  {
1593
1659
  query: z3.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
1594
1660
  assignee: z3.string().optional().describe("me, unassigned, all, a Linear user id, or a display name. Default: all when query is set, otherwise me."),
1595
- limit: z3.number().int().positive().max(250).optional()
1661
+ limit: z3.number().int().positive().max(250).optional().describe("Page size (default 40, max 250). Raise when truncated is true.")
1596
1662
  },
1597
1663
  async ({ query, assignee, limit }) => {
1598
1664
  try {
1599
- return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
1665
+ const page = clampMcpIssueLimit(limit);
1666
+ const listed = await listLinearIssuesFiltered({
1667
+ query,
1668
+ assignee,
1669
+ limit: page + 1
1670
+ });
1671
+ const windowed = applyIssueListWindow(listed.issues, page);
1672
+ return mcpJson(
1673
+ formatMcpIssueList({
1674
+ source: "linear",
1675
+ viewer: listed.viewer.name,
1676
+ limit: page,
1677
+ issues: windowed.items,
1678
+ truncated: windowed.truncated
1679
+ })
1680
+ );
1600
1681
  } catch (err) {
1601
1682
  return fail3(err);
1602
1683
  }
@@ -1604,7 +1685,7 @@ function registerLinearTools(server) {
1604
1685
  );
1605
1686
  server.tool(
1606
1687
  "linear_get_issue",
1607
- "Get a Linear issue by uuid or identifier (ENG-123). Returns description, comments, relations (blocks/blockedBy/related/duplicate), parent/children, project, cycle, labels, and other metadata.",
1688
+ "Get a Linear issue by uuid or identifier (ENG-123): description, comments, relations, parent/children.",
1608
1689
  { id: z3.string() },
1609
1690
  async ({ id }) => {
1610
1691
  try {
@@ -1616,7 +1697,7 @@ function registerLinearTools(server) {
1616
1697
  );
1617
1698
  server.tool(
1618
1699
  "linear_create_issue",
1619
- '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.',
1700
+ 'Create a Linear issue. Call linear_list_teams first. team is id/key/name; state is name/type/id; assignee is "me" or a user id.',
1620
1701
  {
1621
1702
  team: z3.string(),
1622
1703
  title: z3.string(),
@@ -1635,7 +1716,7 @@ function registerLinearTools(server) {
1635
1716
  );
1636
1717
  server.tool(
1637
1718
  "linear_update_issue",
1638
- '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.',
1719
+ "Update a Linear issue (uuid or ENG-123). Pass title, description, state, assignee, and/or priority.",
1639
1720
  {
1640
1721
  id: z3.string(),
1641
1722
  title: z3.string().optional(),
@@ -1669,6 +1750,46 @@ function registerLinearTools(server) {
1669
1750
  );
1670
1751
  }
1671
1752
 
1753
+ // src/mcp/issue-vendor-tools.ts
1754
+ function registerConnectedIssueVendorTools(server, settings = loadAppSettings()) {
1755
+ if (isLinearConnected(settings)) registerLinearTools(server);
1756
+ if (isAbleTimeConnected(settings)) registerAbleTimeTools(server);
1757
+ }
1758
+
1759
+ // src/mcp/pr-list.ts
1760
+ function compactPrRow(pr) {
1761
+ return {
1762
+ number: pr.number,
1763
+ title: pr.title,
1764
+ ...pr.headRefName ? { head: pr.headRefName } : {},
1765
+ ...pr.author?.login ? { author: pr.author.login } : {},
1766
+ ...pr.state ? { state: pr.state } : {},
1767
+ ...pr.isDraft ? { draft: true } : {},
1768
+ ...pr.labels?.length ? { labels: pr.labels } : {},
1769
+ ...pr.reviewers?.length ? { reviewers: pr.reviewers } : {},
1770
+ ...pr.teams?.length ? { teams: pr.teams } : {},
1771
+ ...pr.reviewDecision ? { reviewDecision: pr.reviewDecision } : {},
1772
+ ...pr.tickets?.length ? { tickets: pr.tickets } : {}
1773
+ };
1774
+ }
1775
+ function formatMcpPrList(input) {
1776
+ return {
1777
+ ...input.viewer ? { viewer: input.viewer } : {},
1778
+ ...input.queue ? { queue: input.queue } : {},
1779
+ state: input.state,
1780
+ ...input.labels?.length ? { labels: input.labels } : {},
1781
+ ...input.reviewer ? { reviewer: input.reviewer } : {},
1782
+ ...input.query ? { query: input.query } : {},
1783
+ limit: input.limit,
1784
+ returned: input.prs.length,
1785
+ truncated: input.truncated,
1786
+ ...input.truncated ? {
1787
+ hint: "More PRs match. Pass a higher limit (max 250) or tighten label / reviewer / query."
1788
+ } : {},
1789
+ prs: input.prs.map(compactPrRow)
1790
+ };
1791
+ }
1792
+
1672
1793
  // src/mcp/schedule-tools.ts
1673
1794
  import { z as z4 } from "zod";
1674
1795
  function text4(payload, isError = false) {
@@ -2165,7 +2286,7 @@ async function startMcpServer() {
2165
2286
  );
2166
2287
  }
2167
2288
  try {
2168
- const { maxConcurrentAgents } = await import("../app-settings-J3JBCUOT.js");
2289
+ const { maxConcurrentAgents } = await import("../app-settings-VRQI3FIE.js");
2169
2290
  orch.setMaxConcurrent(maxConcurrentAgents());
2170
2291
  } catch {
2171
2292
  }
@@ -2185,14 +2306,21 @@ async function startMcpServer() {
2185
2306
  if (!worktreeProfile) {
2186
2307
  server.tool(
2187
2308
  "list_workspaces",
2188
- "List registered Sideboard workspaces (repos). Each line is name, path, and github:owner/repo when resolvable \u2014 use path as repoPath for list_board/list_branches/list_prs/list_issues/create_thread.",
2309
+ "List registered Sideboard workspaces (repos). Each line is name, path, github:owner/repo when resolvable, and viewer roles/notes when set \u2014 use path as repoPath for list_board/list_branches/list_prs/list_issues/create_thread. Roles and notes (Settings \u2192 Agents / Projects) say which tickets and review PRs belong to the user.",
2189
2310
  {},
2190
2311
  async () => {
2191
2312
  const workspaces = orch.listWorkspaces();
2192
2313
  const lines = await Promise.all(
2193
2314
  workspaces.map(async (w) => {
2194
2315
  const slug = await resolveGithubRepoSlug(w.path).catch(() => null);
2195
- return slug ? `${w.name} ${w.path} github:${slug}` : `${w.name} ${w.path}`;
2316
+ let profile;
2317
+ try {
2318
+ profile = resolveViewerProfileForRepo(w.path);
2319
+ } catch {
2320
+ profile = resolveViewerProfile();
2321
+ }
2322
+ const suffix = formatWorkspaceProfileSuffix(profile);
2323
+ return slug ? `${w.name} ${w.path} github:${slug}${suffix}` : `${w.name} ${w.path}${suffix}`;
2196
2324
  })
2197
2325
  );
2198
2326
  return {
@@ -2445,11 +2573,10 @@ async function startMcpServer() {
2445
2573
  );
2446
2574
  if (!worktreeProfile) {
2447
2575
  registerSlackTools(server);
2448
- registerLinearTools(server);
2449
- registerAbleTimeTools(server);
2576
+ registerConnectedIssueVendorTools(server);
2450
2577
  registerScheduleTools(server);
2451
- const { getCaffeinateHold, setCaffeinateHold } = await import("../caffeinate-hold-NBRUWYXO.js");
2452
- const { resolveNewThreadOptions, resolveThreadDefaults } = await import("../app-settings-J3JBCUOT.js");
2578
+ const { getCaffeinateHold, setCaffeinateHold } = await import("../caffeinate-hold-DBKMRZZO.js");
2579
+ const { resolveNewThreadOptions, resolveThreadDefaults } = await import("../app-settings-VRQI3FIE.js");
2453
2580
  const accountDefaults = resolveThreadDefaults();
2454
2581
  const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
2455
2582
  server.tool(
@@ -2492,7 +2619,7 @@ async function startMcpServer() {
2492
2619
  );
2493
2620
  server.tool(
2494
2621
  "create_thread",
2495
- `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.`,
2622
+ `Create a worktree thread (chat) from branch, pr, or ticket. A ticket, PR, or named branch may have only one live worktree \u2014 if one already matches, 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.`,
2496
2623
  {
2497
2624
  sourceType: z5.enum(["branch", "pr", "ticket"]),
2498
2625
  sourceRef: z5.string(),
@@ -2519,7 +2646,7 @@ async function startMcpServer() {
2519
2646
  );
2520
2647
  server.tool(
2521
2648
  "start_board_card",
2522
- "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.",
2649
+ "Same as create_thread for a ticket, PR, or named branch (attaches issue text when Sideboard can resolve it). Does not create a second worktree when one already matches \u2014 returns that thread (alreadyStarted). Then send_to_thread.",
2523
2650
  {
2524
2651
  kind: z5.enum(["ticket", "pr", "branch"]),
2525
2652
  ref: z5.string().describe("Ticket identifier (ENG-12), PR number (44), or branch name from list_board"),
@@ -3165,21 +3292,47 @@ async function startMcpServer() {
3165
3292
  );
3166
3293
  server.tool(
3167
3294
  "list_prs",
3168
- "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.",
3169
- { repoPath: z5.string() },
3170
- async ({ repoPath }) => {
3295
+ 'List GitHub PRs for a registered workspace (the review surface for assigned ticket work \u2014 not the tickets). Pass repoPath from list_workspaces. "Get me N tickets to review" \u2192 queue=review and limit=N: open non-draft PRs labeled eng-review with no individual user reviewer. Prefer teams that match Settings \u2192 Agents / Projects roles for this repo. A team like engineering-team is not a claim (you are on that team). Also: state (open|closed|merged|all|review), label, reviewer (me|unassigned|login), query, limit (default 40, max 250). Then create_thread with sourceType=pr.',
3296
+ {
3297
+ repoPath: z5.string(),
3298
+ query: z5.string().optional().describe("GitHub search tokens (title, draft:true, \u2026)"),
3299
+ queue: z5.enum(["review", "mine", "approved", "changes"]).optional().describe(
3300
+ 'review = unclaimed eng-review inbox (use for "get me N tickets to review"). mine = review-requested:@me. approved / changes = eng-approved / eng-requested-changes.'
3301
+ ),
3302
+ state: z5.enum(["open", "closed", "merged", "all", "review"]).optional().describe("GitHub PR state (default open). review is an alias for queue=review."),
3303
+ label: z5.string().optional().describe(
3304
+ "GitHub label / workflow tag. Comma-separated AND. Examples: eng-review, eng-approved, eng-requested-changes"
3305
+ ),
3306
+ reviewer: z5.string().optional().describe(
3307
+ "me (review requested of you), unassigned (no individual reviewer; team queues like engineering-team still count), all, or a GitHub login"
3308
+ ),
3309
+ limit: z5.number().int().positive().max(250).optional().describe("Page size (default 40, max 250). Raise when truncated is true.")
3310
+ },
3311
+ async ({ repoPath, query, queue, state, label, reviewer, limit }) => {
3171
3312
  const root = await resolveRepoRoot(repoPath);
3172
- const prs = await listPrs(root);
3173
- return {
3174
- content: [
3175
- {
3176
- type: "text",
3177
- text: prs.map(
3178
- (p) => `#${p.number} ${p.title} (${p.headRefName})${p.isCrossRepository ? " [fork]" : ""}`
3179
- ).join("\n")
3180
- }
3181
- ]
3182
- };
3313
+ const page = clampMcpIssueLimit(limit);
3314
+ const resolved = resolveListPrsOptions({
3315
+ query,
3316
+ queue,
3317
+ state,
3318
+ labels: label,
3319
+ reviewer,
3320
+ limit: page + 1
3321
+ });
3322
+ const prs = await listPrs(root, resolved);
3323
+ const windowed = applyIssueListWindow(prs, page);
3324
+ return mcpJson(
3325
+ formatMcpPrList({
3326
+ queue: resolved.queue,
3327
+ state: resolved.state,
3328
+ labels: resolved.labels,
3329
+ reviewer: resolved.reviewer,
3330
+ query: resolved.query,
3331
+ limit: page,
3332
+ prs: windowed.items,
3333
+ truncated: windowed.truncated
3334
+ })
3335
+ );
3183
3336
  }
3184
3337
  );
3185
3338
  server.tool(
@@ -3304,28 +3457,27 @@ async function startMcpServer() {
3304
3457
  );
3305
3458
  server.tool(
3306
3459
  "list_issues",
3307
- "List or search issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear defaults to issues assigned to you; pass assignee=unassigned for no owner, assignee=all for everyone (including unassigned), or a user id / GitHub login. Optional query searches title/identifier. Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. Prefer linear_search_issues when Linear is connected and you need unassigned or other people's tickets. 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.",
3460
+ "List or search issues (Linear, AbleTime, or GitHub; falls back to GitHub). Use Settings \u2192 Agents / Projects notes and roles to pick tickets relevant to the viewer (query + assignee=me or unassigned as the notes say). Default 40; pass query and/or limit (max 250) when truncated. assignee: me (Linear default), unassigned, all, or a user id. Then create_thread with sourceType=ticket.",
3308
3461
  {
3309
3462
  repoPath: z5.string(),
3310
3463
  query: z5.string().optional().describe("Search title, identifier, or description"),
3311
- assignee: z5.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
3464
+ assignee: z5.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login"),
3465
+ limit: z5.number().int().positive().max(250).optional().describe("Page size (default 40, max 250). Raise when truncated is true.")
3312
3466
  },
3313
- async ({ repoPath, query, assignee }) => {
3467
+ async ({ repoPath, query, assignee, limit }) => {
3314
3468
  const root = await resolveRepoRoot(repoPath);
3315
- const result = await listIssues(root, { query, assignee });
3316
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
3317
- }
3318
- );
3319
- server.tool(
3320
- "list_linear_issues",
3321
- "Deprecated: prefer list_issues. Lists assigned Linear issues via the chosen agent MCP connector",
3322
- {
3323
- agent: z5.enum(["claude", "codex", "opencode"]),
3324
- repoPath: z5.string()
3325
- },
3326
- async ({ agent, repoPath }) => {
3327
- const issues = await listLinearIssues(agent, repoPath);
3328
- return { content: [{ type: "text", text: JSON.stringify(issues, null, 2) }] };
3469
+ const page = clampMcpIssueLimit(limit);
3470
+ const result = await listIssues(root, { query, assignee, limit: page + 1 });
3471
+ const windowed = applyIssueListWindow(result.issues, page);
3472
+ return mcpJson(
3473
+ formatMcpIssueList({
3474
+ source: result.source,
3475
+ viewer: result.viewer?.name || result.viewer?.login,
3476
+ limit: page,
3477
+ issues: windowed.items,
3478
+ truncated: windowed.truncated
3479
+ })
3480
+ );
3329
3481
  }
3330
3482
  );
3331
3483
  }
@@ -5,26 +5,24 @@ import {
5
5
  isPidAlive,
6
6
  startOrchestration,
7
7
  waitForPidExit
8
- } from "./chunk-6X7Z34XE.js";
8
+ } from "./chunk-KMNODRWF.js";
9
9
  import "./chunk-RFMQY56R.js";
10
- import "./chunk-GFQ57XAX.js";
11
- import "./chunk-7F4XE6UG.js";
12
- import "./chunk-M267JPEA.js";
13
- import "./chunk-K2ANSHUO.js";
14
- import "./chunk-G4MTYUWS.js";
15
- import "./chunk-2U6QF3PT.js";
16
- import "./chunk-GE7M3QTE.js";
10
+ import "./chunk-QZEZXYVV.js";
11
+ import "./chunk-2F63IMCL.js";
12
+ import "./chunk-LQMFCS54.js";
17
13
  import "./chunk-JRH62XC4.js";
14
+ import "./chunk-XD2BAANL.js";
15
+ import "./chunk-M267JPEA.js";
18
16
  import "./chunk-ELBYOGVA.js";
19
17
  import "./chunk-AXQ4ZWHK.js";
20
18
  import "./chunk-HEII7W3Q.js";
21
- import "./chunk-4XNSGDXE.js";
19
+ import "./chunk-3BWVOUQG.js";
22
20
  import "./chunk-4TR3HZFT.js";
23
- import "./chunk-DCOZABNT.js";
21
+ import "./chunk-AO35MGOE.js";
24
22
  import "./chunk-JT7R45JB.js";
25
- import "./chunk-TUGKX5BD.js";
23
+ import "./chunk-7UURXPKD.js";
26
24
  import "./chunk-77WWLBCI.js";
27
- import "./chunk-QZQEXME2.js";
25
+ import "./chunk-EFVFB2AH.js";
28
26
  import "./chunk-QQKDGPUI.js";
29
27
  import "./chunk-UFHNSFAS.js";
30
28
  export {
@@ -7,25 +7,23 @@ import {
7
7
  isPidAlive,
8
8
  startOrchestration,
9
9
  waitForPidExit
10
- } from "./chunk-7BQNSUR2.js";
11
- import "./chunk-EY6QXPPO.js";
12
- import "./chunk-G7SIQFBQ.js";
10
+ } from "./chunk-2NRNP7QP.js";
11
+ import "./chunk-4THE3EY7.js";
12
+ import "./chunk-LZ6QMEQC.js";
13
13
  import "./chunk-S42XV45P.js";
14
- import "./chunk-67TIJ7S5.js";
15
- import "./chunk-SN6CMKF6.js";
16
14
  import "./chunk-6GN5WPYZ.js";
17
15
  import "./chunk-2SDMENAL.js";
18
- import "./chunk-KLBOWJ74.js";
19
- import "./chunk-7TIUOYBK.js";
20
- import "./chunk-3JBMACYX.js";
16
+ import "./chunk-OCQPTUR7.js";
17
+ import "./chunk-RNC3GR6L.js";
18
+ import "./chunk-CJQLPPEJ.js";
21
19
  import "./chunk-NVXVEGGM.js";
22
- import "./chunk-EUXOHTUK.js";
20
+ import "./chunk-LZQULFIT.js";
23
21
  import "./chunk-SYFVUF2C.js";
24
22
  import "./chunk-FNQNJOHY.js";
25
- import "./chunk-CZD4NRDZ.js";
23
+ import "./chunk-D7EGJ3EI.js";
26
24
  import "./chunk-NSTQ6QKD.js";
27
25
  import "./chunk-KGZBYWZ3.js";
28
- import "./chunk-BD2ICC4D.js";
26
+ import "./chunk-JTJHOYCU.js";
29
27
  export {
30
28
  LIVE_TURN_SPAWN_GRACE_MS,
31
29
  Orchestrator,
@@ -11,7 +11,7 @@ import {
11
11
  threadLockPath,
12
12
  threadsDir,
13
13
  worktreesRoot
14
- } from "./chunk-QZQEXME2.js";
14
+ } from "./chunk-EFVFB2AH.js";
15
15
  export {
16
16
  appDataDir,
17
17
  globalAgentCwd,
@@ -13,7 +13,7 @@ import {
13
13
  threadLockPath,
14
14
  threadsDir,
15
15
  worktreesRoot
16
- } from "./chunk-BD2ICC4D.js";
16
+ } from "./chunk-JTJHOYCU.js";
17
17
  export {
18
18
  appDataDir,
19
19
  globalAgentCwd,
@@ -13,9 +13,9 @@ import {
13
13
  updateThread,
14
14
  withThreadLock,
15
15
  writeThread
16
- } from "./chunk-TUGKX5BD.js";
16
+ } from "./chunk-7UURXPKD.js";
17
17
  import "./chunk-77WWLBCI.js";
18
- import "./chunk-QZQEXME2.js";
18
+ import "./chunk-EFVFB2AH.js";
19
19
  export {
20
20
  appendMessage,
21
21
  createEmptyThread,
@@ -15,9 +15,9 @@ import {
15
15
  updateThread,
16
16
  withThreadLock,
17
17
  writeThread
18
- } from "./chunk-EUXOHTUK.js";
18
+ } from "./chunk-LZQULFIT.js";
19
19
  import "./chunk-KGZBYWZ3.js";
20
- import "./chunk-BD2ICC4D.js";
20
+ import "./chunk-JTJHOYCU.js";
21
21
  export {
22
22
  appendMessage,
23
23
  createEmptyThread,