@sideboard-ai/core 0.1.188 → 0.1.190
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/cursor-runner.js +1 -1
- package/dist/{agents-WH3TW5OP.js → agents-5OBZETUV.js} +1 -1
- package/dist/{agents-XPWKGOVT.js → agents-DTPVTDB5.js} +2 -2
- package/dist/{chunk-ZSFQLR7Y.js → chunk-FY64F2ZQ.js} +14 -6
- package/dist/{chunk-QU663NPO.js → chunk-GBWKMWUQ.js} +14 -6
- package/dist/{chunk-72FO6OLT.js → chunk-IAOXW6RI.js} +4 -4
- package/dist/{chunk-ISOCLQEX.js → chunk-OLDZXO53.js} +1 -1
- package/dist/{chunk-TBG2Z3ZV.js → chunk-Z6TW3A5P.js} +6 -6
- package/dist/index.cjs +125 -20
- package/dist/index.d.cts +19 -3
- package/dist/index.d.ts +19 -3
- package/dist/index.js +111 -16
- package/dist/mcp/run-stdio.cjs +121 -20
- package/dist/mcp/run-stdio.js +108 -15
- package/dist/{orchestrator-7A66YINC.js → orchestrator-BHJELEFM.js} +2 -2
- package/dist/{orchestrator-ZMXSPFSF.js → orchestrator-HWNGCDGW.js} +3 -3
- package/package.json +1 -1
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -1610,13 +1610,21 @@ function looksLikeHugeToolResultDump(text7) {
|
|
|
1610
1610
|
if (t.length < 4e3) return false;
|
|
1611
1611
|
return looksLikeMinifiedJsDump(t);
|
|
1612
1612
|
}
|
|
1613
|
+
function looksLikeJobWaitResult(rec) {
|
|
1614
|
+
if (typeof rec.delta === "string") {
|
|
1615
|
+
return typeof rec.status === "string" || typeof rec.id === "string" || typeof rec.stillRunning === "boolean";
|
|
1616
|
+
}
|
|
1617
|
+
if (typeof rec.stopped === "boolean") {
|
|
1618
|
+
return typeof rec.id === "string" || typeof rec.status === "string";
|
|
1619
|
+
}
|
|
1620
|
+
return rec.started === true || rec.reason === "already-running";
|
|
1621
|
+
}
|
|
1613
1622
|
function clipJobWaitResultJson(content) {
|
|
1614
1623
|
const trimmed = content.trim();
|
|
1615
1624
|
if (!trimmed.startsWith("{")) return void 0;
|
|
1616
1625
|
try {
|
|
1617
1626
|
const rec = JSON.parse(trimmed);
|
|
1618
|
-
|
|
1619
|
-
if (!isJob) return void 0;
|
|
1627
|
+
if (!looksLikeJobWaitResult(rec)) return void 0;
|
|
1620
1628
|
if (typeof rec.delta === "string" && rec.delta.length > 3500) {
|
|
1621
1629
|
rec.delta = `\u2026(truncated ${rec.delta.length} chars)
|
|
1622
1630
|
${rec.delta.slice(-3500)}`;
|
|
@@ -1782,7 +1790,7 @@ function humanizeAgentFailDetail(detail) {
|
|
|
1782
1790
|
return /ran out of memory/i.test(raw) ? raw : V8_OOM_SUMMARY;
|
|
1783
1791
|
}
|
|
1784
1792
|
if (/homebrew node \+ shared libuv|Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(raw)) {
|
|
1785
|
-
return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node
|
|
1793
|
+
return /brew install node@(?:22|24)/i.test(raw) ? raw : `${raw} \u2014 install Node 24 LTS (\`brew install node@24\`) and retry.`;
|
|
1786
1794
|
}
|
|
1787
1795
|
if (/uv_run|spineventloopinternal|uv__io_poll|cursor runner crashed in node/i.test(lower)) {
|
|
1788
1796
|
return /retry the turn/i.test(raw) ? raw : BUNDLED_NODE_CRASH_SUMMARY;
|
|
@@ -1860,7 +1868,7 @@ var init_error_detail = __esm({
|
|
|
1860
1868
|
"use strict";
|
|
1861
1869
|
NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
|
|
1862
1870
|
NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
|
|
1863
|
-
HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node
|
|
1871
|
+
HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 24 LTS (`brew install node@24`) and retry.";
|
|
1864
1872
|
BUNDLED_NODE_CRASH_SUMMARY = "Cursor runner crashed in Node. Retry the turn.";
|
|
1865
1873
|
V8_OOM_SUMMARY = "Agent ran out of memory (JavaScript heap). If it keeps happening, exclude large files from the project folder.";
|
|
1866
1874
|
MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
|
|
@@ -9615,7 +9623,7 @@ function parseNodeMajor(version) {
|
|
|
9615
9623
|
function scoreNodeForAgentRuntime(candidate) {
|
|
9616
9624
|
const major = parseNodeMajor(candidate.version);
|
|
9617
9625
|
if (major == null) return Number.NEGATIVE_INFINITY;
|
|
9618
|
-
if (major <
|
|
9626
|
+
if (major < 22) return major - 100;
|
|
9619
9627
|
const posix = candidate.path.replace(/\\/g, "/");
|
|
9620
9628
|
let score = 0;
|
|
9621
9629
|
if (major % 2 === 0) {
|
|
@@ -9776,7 +9784,7 @@ var init_node_launch = __esm({
|
|
|
9776
9784
|
init_packaged_runtime();
|
|
9777
9785
|
AGENT_RUNNER_MAX_OLD_SPACE_MB = 8192;
|
|
9778
9786
|
MAX_OLD_SPACE_FLAG = /(?:^|\s)(--max[-_]old[-_]space[-_]size)(?:[= ](\d+))?(?=\s|$)/;
|
|
9779
|
-
PREFERRED_LTS_MAJORS = [24, 22
|
|
9787
|
+
PREFERRED_LTS_MAJORS = [24, 22];
|
|
9780
9788
|
}
|
|
9781
9789
|
});
|
|
9782
9790
|
|
|
@@ -18299,7 +18307,7 @@ function formatIssueToolsDirective(opts) {
|
|
|
18299
18307
|
];
|
|
18300
18308
|
if (opts.linear) {
|
|
18301
18309
|
lines.push(
|
|
18302
|
-
"- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
|
|
18310
|
+
"- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state, cycle), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
|
|
18303
18311
|
);
|
|
18304
18312
|
}
|
|
18305
18313
|
if (github) {
|
|
@@ -21827,7 +21835,7 @@ async function listGitHubIssueCommentsSince(opts) {
|
|
|
21827
21835
|
}).filter((n) => n != null)
|
|
21828
21836
|
);
|
|
21829
21837
|
if (restrictToIssues && allowed.size === 0) return [];
|
|
21830
|
-
const pageSize =
|
|
21838
|
+
const pageSize = GITHUB_ISSUE_COMMENTS_PAGE_SIZE;
|
|
21831
21839
|
const out = [];
|
|
21832
21840
|
for (let page = 1; page <= GITHUB_ISSUE_COMMENTS_MAX_PAGES; page++) {
|
|
21833
21841
|
const path = `repos/${slug}/issues/comments?since=${encodeURIComponent(opts.since)}&sort=created&direction=desc&per_page=${pageSize}&page=${page}`;
|
|
@@ -22065,7 +22073,7 @@ var LIST_ISSUE_FIELDS = `
|
|
|
22065
22073
|
assignee { id name }
|
|
22066
22074
|
team { id key }
|
|
22067
22075
|
labels(first: 10) { nodes { name } }
|
|
22068
|
-
cycle { name number startsAt endsAt completedAt }
|
|
22076
|
+
cycle { id name number startsAt endsAt completedAt }
|
|
22069
22077
|
`;
|
|
22070
22078
|
var ISSUE_REF_FIELDS = `
|
|
22071
22079
|
id
|
|
@@ -22091,7 +22099,7 @@ var ISSUE_FIELDS = `
|
|
|
22091
22099
|
creator { id name }
|
|
22092
22100
|
team { id key name }
|
|
22093
22101
|
labels(first: 50) { nodes { name } }
|
|
22094
|
-
cycle { name number startsAt endsAt completedAt }
|
|
22102
|
+
cycle { id name number startsAt endsAt completedAt }
|
|
22095
22103
|
project { id name }
|
|
22096
22104
|
parent { ${ISSUE_REF_FIELDS} }
|
|
22097
22105
|
children(first: 25) { nodes { ${ISSUE_REF_FIELDS} } }
|
|
@@ -22176,6 +22184,19 @@ query SideboardTeams {
|
|
|
22176
22184
|
key
|
|
22177
22185
|
name
|
|
22178
22186
|
states(first: 50) { nodes { id name type } }
|
|
22187
|
+
activeCycle { id name number startsAt endsAt completedAt }
|
|
22188
|
+
}
|
|
22189
|
+
}
|
|
22190
|
+
}
|
|
22191
|
+
`;
|
|
22192
|
+
var TEAM_CYCLES_QUERY = `
|
|
22193
|
+
query SideboardTeamCycles($id: String!) {
|
|
22194
|
+
team(id: $id) {
|
|
22195
|
+
id
|
|
22196
|
+
key
|
|
22197
|
+
activeCycle { id name number startsAt endsAt completedAt }
|
|
22198
|
+
cycles(first: 40) {
|
|
22199
|
+
nodes { id name number startsAt endsAt completedAt }
|
|
22179
22200
|
}
|
|
22180
22201
|
}
|
|
22181
22202
|
}
|
|
@@ -22268,11 +22289,26 @@ function linearCycleIsActive(cycle, now = Date.now()) {
|
|
|
22268
22289
|
if (Number.isFinite(end) && now > end) return false;
|
|
22269
22290
|
return true;
|
|
22270
22291
|
}
|
|
22292
|
+
function cycleDisplayName(node) {
|
|
22293
|
+
return String(node?.name ?? (node?.number != null ? `Cycle ${node.number}` : "")).trim();
|
|
22294
|
+
}
|
|
22295
|
+
function mapNamedCycle(node) {
|
|
22296
|
+
if (!node?.id) return null;
|
|
22297
|
+
const name = cycleDisplayName(node);
|
|
22298
|
+
if (!name) return null;
|
|
22299
|
+
return {
|
|
22300
|
+
id: String(node.id),
|
|
22301
|
+
name,
|
|
22302
|
+
number: typeof node.number === "number" ? node.number : void 0,
|
|
22303
|
+
isActive: linearCycleIsActive(node)
|
|
22304
|
+
};
|
|
22305
|
+
}
|
|
22271
22306
|
function mapCycle(node) {
|
|
22272
22307
|
if (!node?.name && node?.number == null) return null;
|
|
22273
|
-
const name =
|
|
22308
|
+
const name = cycleDisplayName(node);
|
|
22274
22309
|
if (!name) return null;
|
|
22275
22310
|
return {
|
|
22311
|
+
...node.id ? { id: String(node.id) } : {},
|
|
22276
22312
|
name,
|
|
22277
22313
|
number: typeof node.number === "number" ? node.number : void 0,
|
|
22278
22314
|
isActive: linearCycleIsActive(node)
|
|
@@ -22411,6 +22447,10 @@ function toIssueInfo(issue) {
|
|
|
22411
22447
|
};
|
|
22412
22448
|
}
|
|
22413
22449
|
function mapTeam(node) {
|
|
22450
|
+
const cycles = (node.cycles?.nodes ?? []).flatMap((c) => {
|
|
22451
|
+
const cycle = mapNamedCycle(c);
|
|
22452
|
+
return cycle ? [cycle] : [];
|
|
22453
|
+
});
|
|
22414
22454
|
return {
|
|
22415
22455
|
id: String(node.id ?? ""),
|
|
22416
22456
|
key: String(node.key ?? ""),
|
|
@@ -22418,7 +22458,9 @@ function mapTeam(node) {
|
|
|
22418
22458
|
states: (node.states?.nodes ?? []).flatMap((s) => {
|
|
22419
22459
|
const state = mapState(s);
|
|
22420
22460
|
return state ? [state] : [];
|
|
22421
|
-
})
|
|
22461
|
+
}),
|
|
22462
|
+
activeCycle: mapNamedCycle(node.activeCycle),
|
|
22463
|
+
...cycles.length ? { cycles } : {}
|
|
22422
22464
|
};
|
|
22423
22465
|
}
|
|
22424
22466
|
function resolveLinearTeam(teams, team) {
|
|
@@ -22445,6 +22487,34 @@ function resolveLinearState(team, state) {
|
|
|
22445
22487
|
}
|
|
22446
22488
|
return found;
|
|
22447
22489
|
}
|
|
22490
|
+
function resolveLinearCycle(team, cycle) {
|
|
22491
|
+
if (cycle == null) return null;
|
|
22492
|
+
const s = cycle.trim();
|
|
22493
|
+
if (!s || /^(none|clear|unschedule|null)$/i.test(s)) return null;
|
|
22494
|
+
if (/^(current|active|this)$/i.test(s)) {
|
|
22495
|
+
const active = team.activeCycle ?? team.cycles?.find((c) => c.isActive);
|
|
22496
|
+
if (!active?.id) {
|
|
22497
|
+
throw new Error(`Linear team ${team.key} has no active cycle`);
|
|
22498
|
+
}
|
|
22499
|
+
return active.id;
|
|
22500
|
+
}
|
|
22501
|
+
const lower = s.toLowerCase();
|
|
22502
|
+
const asNumber = Number.parseInt(s, 10);
|
|
22503
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22504
|
+
const cycles = [team.activeCycle, ...team.cycles ?? []].filter(
|
|
22505
|
+
(c) => {
|
|
22506
|
+
if (!c?.id || seen.has(c.id)) return false;
|
|
22507
|
+
seen.add(c.id);
|
|
22508
|
+
return true;
|
|
22509
|
+
}
|
|
22510
|
+
);
|
|
22511
|
+
const found = cycles.find((c) => c.id === s) || cycles.find((c) => c.name.toLowerCase() === lower) || (Number.isInteger(asNumber) ? cycles.find((c) => c.number === asNumber) : void 0);
|
|
22512
|
+
if (!found) {
|
|
22513
|
+
const available = cycles.map((c) => c.number != null ? `${c.name} (${c.number})` : c.name).join(", ") || "(none)";
|
|
22514
|
+
throw new Error(`Linear cycle not found on ${team.key}: ${cycle}. Available: ${available}`);
|
|
22515
|
+
}
|
|
22516
|
+
return found.id;
|
|
22517
|
+
}
|
|
22448
22518
|
function normalizePriority(priority) {
|
|
22449
22519
|
if (priority == null) return void 0;
|
|
22450
22520
|
if (!Number.isInteger(priority) || priority < 0 || priority > 4) {
|
|
@@ -22554,7 +22624,12 @@ async function listLinearCommentsSince(opts) {
|
|
|
22554
22624
|
first,
|
|
22555
22625
|
filter: {
|
|
22556
22626
|
createdAt: { gte: opts.since },
|
|
22557
|
-
issue: buildLinearIssueFilter({
|
|
22627
|
+
issue: buildLinearIssueFilter({
|
|
22628
|
+
assignee,
|
|
22629
|
+
// Search hits may match identifier/comments — do not also require
|
|
22630
|
+
// title/description contains when an allowlist is already applied.
|
|
22631
|
+
query: restrictToIssues ? void 0 : query || void 0
|
|
22632
|
+
})
|
|
22558
22633
|
}
|
|
22559
22634
|
},
|
|
22560
22635
|
opts
|
|
@@ -22586,6 +22661,19 @@ async function listLinearTeams(opts) {
|
|
|
22586
22661
|
teams: (json.teams?.nodes ?? []).map(mapTeam)
|
|
22587
22662
|
};
|
|
22588
22663
|
}
|
|
22664
|
+
async function listLinearTeamCycles(teamId, opts) {
|
|
22665
|
+
const json = await linearGraphql(TEAM_CYCLES_QUERY, { id: teamId }, opts);
|
|
22666
|
+
if (!json.team?.id) {
|
|
22667
|
+
throw new Error(`Linear team not found: ${teamId}`);
|
|
22668
|
+
}
|
|
22669
|
+
const mapped = mapTeam(json.team);
|
|
22670
|
+
return {
|
|
22671
|
+
id: mapped.id,
|
|
22672
|
+
key: mapped.key,
|
|
22673
|
+
activeCycle: mapped.activeCycle,
|
|
22674
|
+
cycles: mapped.cycles ?? []
|
|
22675
|
+
};
|
|
22676
|
+
}
|
|
22589
22677
|
async function getLinearIssue(id, opts) {
|
|
22590
22678
|
const issueId = id.trim();
|
|
22591
22679
|
if (!issueId) throw new Error("Linear issue id is required (uuid or ENG-123)");
|
|
@@ -22641,16 +22729,28 @@ async function updateLinearIssue(input, opts) {
|
|
|
22641
22729
|
if (input.description !== void 0) {
|
|
22642
22730
|
mutationInput.description = input.description;
|
|
22643
22731
|
}
|
|
22732
|
+
const needsTeam = Boolean(input.state?.trim()) || input.cycle !== void 0;
|
|
22733
|
+
const existing = needsTeam ? await getLinearIssue(issueId, opts) : void 0;
|
|
22644
22734
|
if (input.state?.trim()) {
|
|
22645
|
-
const existing = await getLinearIssue(issueId, opts);
|
|
22646
22735
|
const { teams } = await listLinearTeams(opts);
|
|
22647
|
-
const teamRef = existing
|
|
22736
|
+
const teamRef = existing?.team?.key || existing?.team?.id;
|
|
22648
22737
|
const team = teamRef ? resolveLinearTeam(teams, teamRef) : void 0;
|
|
22649
22738
|
if (!team?.states.length) {
|
|
22650
|
-
throw new Error(`Linear issue ${existing
|
|
22739
|
+
throw new Error(`Linear issue ${existing?.identifier ?? issueId} has no workflow states to resolve "${input.state}"`);
|
|
22651
22740
|
}
|
|
22652
22741
|
mutationInput.stateId = resolveLinearState(team, input.state).id;
|
|
22653
22742
|
}
|
|
22743
|
+
if (input.cycle !== void 0) {
|
|
22744
|
+
const teamId = existing?.team?.id;
|
|
22745
|
+
if (!teamId) {
|
|
22746
|
+
throw new Error(`Linear issue ${existing?.identifier ?? issueId} has no team to resolve a cycle`);
|
|
22747
|
+
}
|
|
22748
|
+
const cycles = await listLinearTeamCycles(teamId, opts);
|
|
22749
|
+
mutationInput.cycleId = resolveLinearCycle(
|
|
22750
|
+
{ ...cycles, key: cycles.key || existing?.team?.key || teamId },
|
|
22751
|
+
input.cycle
|
|
22752
|
+
);
|
|
22753
|
+
}
|
|
22654
22754
|
if (input.assignee !== void 0) {
|
|
22655
22755
|
const assignee = input.assignee?.trim() || null;
|
|
22656
22756
|
if (assignee === "me") {
|
|
@@ -22664,7 +22764,7 @@ async function updateLinearIssue(input, opts) {
|
|
|
22664
22764
|
mutationInput.priority = normalizePriority(input.priority);
|
|
22665
22765
|
}
|
|
22666
22766
|
if (Object.keys(mutationInput).length === 0) {
|
|
22667
|
-
throw new Error("linear_update_issue needs at least one of title, description, state, assignee, priority");
|
|
22767
|
+
throw new Error("linear_update_issue needs at least one of title, description, state, assignee, priority, cycle");
|
|
22668
22768
|
}
|
|
22669
22769
|
const json = await linearGraphql(ISSUE_UPDATE, { id: issueId, input: mutationInput }, opts);
|
|
22670
22770
|
if (!json.issueUpdate?.success || !json.issueUpdate.issue) {
|
|
@@ -24132,7 +24232,7 @@ var prioritySchema = import_zod6.z.number().int().min(0).max(4).optional().descr
|
|
|
24132
24232
|
function registerLinearTools(server) {
|
|
24133
24233
|
server.tool(
|
|
24134
24234
|
"linear_list_teams",
|
|
24135
|
-
|
|
24235
|
+
'List Linear teams (id, key, name), workflow states, and the active cycle. Use team key on create; state name or type on create/update; cycle name/"current"/"none" on update.',
|
|
24136
24236
|
{},
|
|
24137
24237
|
async () => {
|
|
24138
24238
|
try {
|
|
@@ -24219,14 +24319,15 @@ function registerLinearTools(server) {
|
|
|
24219
24319
|
);
|
|
24220
24320
|
server.tool(
|
|
24221
24321
|
"linear_update_issue",
|
|
24222
|
-
|
|
24322
|
+
'Update a Linear issue (uuid or ENG-123). Pass title, description, state, assignee, priority, and/or cycle. Cycle is name, number, "current"/"active", or "none" to unschedule. When reviewing a PR or ticket, wait until they type a next step before changing the ticket \u2014 do not ask_user after the review. The author is notified.',
|
|
24223
24323
|
{
|
|
24224
24324
|
id: import_zod6.z.string(),
|
|
24225
24325
|
title: import_zod6.z.string().optional(),
|
|
24226
24326
|
description: import_zod6.z.string().optional(),
|
|
24227
24327
|
state: import_zod6.z.string().optional(),
|
|
24228
24328
|
assignee: import_zod6.z.string().nullable().optional(),
|
|
24229
|
-
priority: prioritySchema
|
|
24329
|
+
priority: prioritySchema,
|
|
24330
|
+
cycle: import_zod6.z.string().nullable().optional().describe('Cycle name, number, "current"/"active", or "none" to unschedule.')
|
|
24230
24331
|
},
|
|
24231
24332
|
async (args) => {
|
|
24232
24333
|
try {
|
package/dist/mcp/run-stdio.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
syncBoardPins,
|
|
38
38
|
updateSchedule,
|
|
39
39
|
waitForDetachedJob
|
|
40
|
-
} from "../chunk-
|
|
40
|
+
} from "../chunk-IAOXW6RI.js";
|
|
41
41
|
import {
|
|
42
42
|
applySystemCaEnv,
|
|
43
43
|
isCursorApiKeyConfigured,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
materializeSystemCaBundle,
|
|
47
47
|
sideboardMcpProfile,
|
|
48
48
|
trustSystemCertificates
|
|
49
|
-
} from "../chunk-
|
|
49
|
+
} from "../chunk-GBWKMWUQ.js";
|
|
50
50
|
import "../chunk-HVIEYTUK.js";
|
|
51
51
|
import "../chunk-Y4MIXGPA.js";
|
|
52
52
|
import {
|
|
@@ -298,7 +298,7 @@ async function listGitHubIssueCommentsSince(opts) {
|
|
|
298
298
|
}).filter((n) => n != null)
|
|
299
299
|
);
|
|
300
300
|
if (restrictToIssues && allowed.size === 0) return [];
|
|
301
|
-
const pageSize =
|
|
301
|
+
const pageSize = GITHUB_ISSUE_COMMENTS_PAGE_SIZE;
|
|
302
302
|
const out = [];
|
|
303
303
|
for (let page = 1; page <= GITHUB_ISSUE_COMMENTS_MAX_PAGES; page++) {
|
|
304
304
|
const path = `repos/${slug}/issues/comments?since=${encodeURIComponent(opts.since)}&sort=created&direction=desc&per_page=${pageSize}&page=${page}`;
|
|
@@ -531,7 +531,7 @@ var LIST_ISSUE_FIELDS = `
|
|
|
531
531
|
assignee { id name }
|
|
532
532
|
team { id key }
|
|
533
533
|
labels(first: 10) { nodes { name } }
|
|
534
|
-
cycle { name number startsAt endsAt completedAt }
|
|
534
|
+
cycle { id name number startsAt endsAt completedAt }
|
|
535
535
|
`;
|
|
536
536
|
var ISSUE_REF_FIELDS = `
|
|
537
537
|
id
|
|
@@ -557,7 +557,7 @@ var ISSUE_FIELDS = `
|
|
|
557
557
|
creator { id name }
|
|
558
558
|
team { id key name }
|
|
559
559
|
labels(first: 50) { nodes { name } }
|
|
560
|
-
cycle { name number startsAt endsAt completedAt }
|
|
560
|
+
cycle { id name number startsAt endsAt completedAt }
|
|
561
561
|
project { id name }
|
|
562
562
|
parent { ${ISSUE_REF_FIELDS} }
|
|
563
563
|
children(first: 25) { nodes { ${ISSUE_REF_FIELDS} } }
|
|
@@ -642,6 +642,19 @@ query SideboardTeams {
|
|
|
642
642
|
key
|
|
643
643
|
name
|
|
644
644
|
states(first: 50) { nodes { id name type } }
|
|
645
|
+
activeCycle { id name number startsAt endsAt completedAt }
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
`;
|
|
650
|
+
var TEAM_CYCLES_QUERY = `
|
|
651
|
+
query SideboardTeamCycles($id: String!) {
|
|
652
|
+
team(id: $id) {
|
|
653
|
+
id
|
|
654
|
+
key
|
|
655
|
+
activeCycle { id name number startsAt endsAt completedAt }
|
|
656
|
+
cycles(first: 40) {
|
|
657
|
+
nodes { id name number startsAt endsAt completedAt }
|
|
645
658
|
}
|
|
646
659
|
}
|
|
647
660
|
}
|
|
@@ -734,11 +747,26 @@ function linearCycleIsActive(cycle, now = Date.now()) {
|
|
|
734
747
|
if (Number.isFinite(end) && now > end) return false;
|
|
735
748
|
return true;
|
|
736
749
|
}
|
|
750
|
+
function cycleDisplayName(node) {
|
|
751
|
+
return String(node?.name ?? (node?.number != null ? `Cycle ${node.number}` : "")).trim();
|
|
752
|
+
}
|
|
753
|
+
function mapNamedCycle(node) {
|
|
754
|
+
if (!node?.id) return null;
|
|
755
|
+
const name = cycleDisplayName(node);
|
|
756
|
+
if (!name) return null;
|
|
757
|
+
return {
|
|
758
|
+
id: String(node.id),
|
|
759
|
+
name,
|
|
760
|
+
number: typeof node.number === "number" ? node.number : void 0,
|
|
761
|
+
isActive: linearCycleIsActive(node)
|
|
762
|
+
};
|
|
763
|
+
}
|
|
737
764
|
function mapCycle(node) {
|
|
738
765
|
if (!node?.name && node?.number == null) return null;
|
|
739
|
-
const name =
|
|
766
|
+
const name = cycleDisplayName(node);
|
|
740
767
|
if (!name) return null;
|
|
741
768
|
return {
|
|
769
|
+
...node.id ? { id: String(node.id) } : {},
|
|
742
770
|
name,
|
|
743
771
|
number: typeof node.number === "number" ? node.number : void 0,
|
|
744
772
|
isActive: linearCycleIsActive(node)
|
|
@@ -877,6 +905,10 @@ function toIssueInfo(issue) {
|
|
|
877
905
|
};
|
|
878
906
|
}
|
|
879
907
|
function mapTeam(node) {
|
|
908
|
+
const cycles = (node.cycles?.nodes ?? []).flatMap((c) => {
|
|
909
|
+
const cycle = mapNamedCycle(c);
|
|
910
|
+
return cycle ? [cycle] : [];
|
|
911
|
+
});
|
|
880
912
|
return {
|
|
881
913
|
id: String(node.id ?? ""),
|
|
882
914
|
key: String(node.key ?? ""),
|
|
@@ -884,7 +916,9 @@ function mapTeam(node) {
|
|
|
884
916
|
states: (node.states?.nodes ?? []).flatMap((s) => {
|
|
885
917
|
const state = mapState(s);
|
|
886
918
|
return state ? [state] : [];
|
|
887
|
-
})
|
|
919
|
+
}),
|
|
920
|
+
activeCycle: mapNamedCycle(node.activeCycle),
|
|
921
|
+
...cycles.length ? { cycles } : {}
|
|
888
922
|
};
|
|
889
923
|
}
|
|
890
924
|
function resolveLinearTeam(teams, team) {
|
|
@@ -911,6 +945,34 @@ function resolveLinearState(team, state) {
|
|
|
911
945
|
}
|
|
912
946
|
return found;
|
|
913
947
|
}
|
|
948
|
+
function resolveLinearCycle(team, cycle) {
|
|
949
|
+
if (cycle == null) return null;
|
|
950
|
+
const s = cycle.trim();
|
|
951
|
+
if (!s || /^(none|clear|unschedule|null)$/i.test(s)) return null;
|
|
952
|
+
if (/^(current|active|this)$/i.test(s)) {
|
|
953
|
+
const active = team.activeCycle ?? team.cycles?.find((c) => c.isActive);
|
|
954
|
+
if (!active?.id) {
|
|
955
|
+
throw new Error(`Linear team ${team.key} has no active cycle`);
|
|
956
|
+
}
|
|
957
|
+
return active.id;
|
|
958
|
+
}
|
|
959
|
+
const lower = s.toLowerCase();
|
|
960
|
+
const asNumber = Number.parseInt(s, 10);
|
|
961
|
+
const seen = /* @__PURE__ */ new Set();
|
|
962
|
+
const cycles = [team.activeCycle, ...team.cycles ?? []].filter(
|
|
963
|
+
(c) => {
|
|
964
|
+
if (!c?.id || seen.has(c.id)) return false;
|
|
965
|
+
seen.add(c.id);
|
|
966
|
+
return true;
|
|
967
|
+
}
|
|
968
|
+
);
|
|
969
|
+
const found = cycles.find((c) => c.id === s) || cycles.find((c) => c.name.toLowerCase() === lower) || (Number.isInteger(asNumber) ? cycles.find((c) => c.number === asNumber) : void 0);
|
|
970
|
+
if (!found) {
|
|
971
|
+
const available = cycles.map((c) => c.number != null ? `${c.name} (${c.number})` : c.name).join(", ") || "(none)";
|
|
972
|
+
throw new Error(`Linear cycle not found on ${team.key}: ${cycle}. Available: ${available}`);
|
|
973
|
+
}
|
|
974
|
+
return found.id;
|
|
975
|
+
}
|
|
914
976
|
function normalizePriority(priority) {
|
|
915
977
|
if (priority == null) return void 0;
|
|
916
978
|
if (!Number.isInteger(priority) || priority < 0 || priority > 4) {
|
|
@@ -1020,7 +1082,12 @@ async function listLinearCommentsSince(opts) {
|
|
|
1020
1082
|
first,
|
|
1021
1083
|
filter: {
|
|
1022
1084
|
createdAt: { gte: opts.since },
|
|
1023
|
-
issue: buildLinearIssueFilter({
|
|
1085
|
+
issue: buildLinearIssueFilter({
|
|
1086
|
+
assignee,
|
|
1087
|
+
// Search hits may match identifier/comments — do not also require
|
|
1088
|
+
// title/description contains when an allowlist is already applied.
|
|
1089
|
+
query: restrictToIssues ? void 0 : query || void 0
|
|
1090
|
+
})
|
|
1024
1091
|
}
|
|
1025
1092
|
},
|
|
1026
1093
|
opts
|
|
@@ -1052,6 +1119,19 @@ async function listLinearTeams(opts) {
|
|
|
1052
1119
|
teams: (json.teams?.nodes ?? []).map(mapTeam)
|
|
1053
1120
|
};
|
|
1054
1121
|
}
|
|
1122
|
+
async function listLinearTeamCycles(teamId, opts) {
|
|
1123
|
+
const json = await linearGraphql(TEAM_CYCLES_QUERY, { id: teamId }, opts);
|
|
1124
|
+
if (!json.team?.id) {
|
|
1125
|
+
throw new Error(`Linear team not found: ${teamId}`);
|
|
1126
|
+
}
|
|
1127
|
+
const mapped = mapTeam(json.team);
|
|
1128
|
+
return {
|
|
1129
|
+
id: mapped.id,
|
|
1130
|
+
key: mapped.key,
|
|
1131
|
+
activeCycle: mapped.activeCycle,
|
|
1132
|
+
cycles: mapped.cycles ?? []
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1055
1135
|
async function getLinearIssue(id, opts) {
|
|
1056
1136
|
const issueId = id.trim();
|
|
1057
1137
|
if (!issueId) throw new Error("Linear issue id is required (uuid or ENG-123)");
|
|
@@ -1107,16 +1187,28 @@ async function updateLinearIssue(input, opts) {
|
|
|
1107
1187
|
if (input.description !== void 0) {
|
|
1108
1188
|
mutationInput.description = input.description;
|
|
1109
1189
|
}
|
|
1190
|
+
const needsTeam = Boolean(input.state?.trim()) || input.cycle !== void 0;
|
|
1191
|
+
const existing = needsTeam ? await getLinearIssue(issueId, opts) : void 0;
|
|
1110
1192
|
if (input.state?.trim()) {
|
|
1111
|
-
const existing = await getLinearIssue(issueId, opts);
|
|
1112
1193
|
const { teams } = await listLinearTeams(opts);
|
|
1113
|
-
const teamRef = existing
|
|
1194
|
+
const teamRef = existing?.team?.key || existing?.team?.id;
|
|
1114
1195
|
const team = teamRef ? resolveLinearTeam(teams, teamRef) : void 0;
|
|
1115
1196
|
if (!team?.states.length) {
|
|
1116
|
-
throw new Error(`Linear issue ${existing
|
|
1197
|
+
throw new Error(`Linear issue ${existing?.identifier ?? issueId} has no workflow states to resolve "${input.state}"`);
|
|
1117
1198
|
}
|
|
1118
1199
|
mutationInput.stateId = resolveLinearState(team, input.state).id;
|
|
1119
1200
|
}
|
|
1201
|
+
if (input.cycle !== void 0) {
|
|
1202
|
+
const teamId = existing?.team?.id;
|
|
1203
|
+
if (!teamId) {
|
|
1204
|
+
throw new Error(`Linear issue ${existing?.identifier ?? issueId} has no team to resolve a cycle`);
|
|
1205
|
+
}
|
|
1206
|
+
const cycles = await listLinearTeamCycles(teamId, opts);
|
|
1207
|
+
mutationInput.cycleId = resolveLinearCycle(
|
|
1208
|
+
{ ...cycles, key: cycles.key || existing?.team?.key || teamId },
|
|
1209
|
+
input.cycle
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1120
1212
|
if (input.assignee !== void 0) {
|
|
1121
1213
|
const assignee = input.assignee?.trim() || null;
|
|
1122
1214
|
if (assignee === "me") {
|
|
@@ -1130,7 +1222,7 @@ async function updateLinearIssue(input, opts) {
|
|
|
1130
1222
|
mutationInput.priority = normalizePriority(input.priority);
|
|
1131
1223
|
}
|
|
1132
1224
|
if (Object.keys(mutationInput).length === 0) {
|
|
1133
|
-
throw new Error("linear_update_issue needs at least one of title, description, state, assignee, priority");
|
|
1225
|
+
throw new Error("linear_update_issue needs at least one of title, description, state, assignee, priority, cycle");
|
|
1134
1226
|
}
|
|
1135
1227
|
const json = await linearGraphql(ISSUE_UPDATE, { id: issueId, input: mutationInput }, opts);
|
|
1136
1228
|
if (!json.issueUpdate?.success || !json.issueUpdate.issue) {
|
|
@@ -2573,7 +2665,7 @@ var prioritySchema = z6.number().int().min(0).max(4).optional().describe("0 none
|
|
|
2573
2665
|
function registerLinearTools(server) {
|
|
2574
2666
|
server.tool(
|
|
2575
2667
|
"linear_list_teams",
|
|
2576
|
-
|
|
2668
|
+
'List Linear teams (id, key, name), workflow states, and the active cycle. Use team key on create; state name or type on create/update; cycle name/"current"/"none" on update.',
|
|
2577
2669
|
{},
|
|
2578
2670
|
async () => {
|
|
2579
2671
|
try {
|
|
@@ -2660,14 +2752,15 @@ function registerLinearTools(server) {
|
|
|
2660
2752
|
);
|
|
2661
2753
|
server.tool(
|
|
2662
2754
|
"linear_update_issue",
|
|
2663
|
-
|
|
2755
|
+
'Update a Linear issue (uuid or ENG-123). Pass title, description, state, assignee, priority, and/or cycle. Cycle is name, number, "current"/"active", or "none" to unschedule. When reviewing a PR or ticket, wait until they type a next step before changing the ticket \u2014 do not ask_user after the review. The author is notified.',
|
|
2664
2756
|
{
|
|
2665
2757
|
id: z6.string(),
|
|
2666
2758
|
title: z6.string().optional(),
|
|
2667
2759
|
description: z6.string().optional(),
|
|
2668
2760
|
state: z6.string().optional(),
|
|
2669
2761
|
assignee: z6.string().nullable().optional(),
|
|
2670
|
-
priority: prioritySchema
|
|
2762
|
+
priority: prioritySchema,
|
|
2763
|
+
cycle: z6.string().nullable().optional().describe('Cycle name, number, "current"/"active", or "none" to unschedule.')
|
|
2671
2764
|
},
|
|
2672
2765
|
async (args) => {
|
|
2673
2766
|
try {
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
resolveSendFollowUp,
|
|
9
9
|
startOrchestration,
|
|
10
10
|
waitForPidExit
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-IAOXW6RI.js";
|
|
12
|
+
import "./chunk-GBWKMWUQ.js";
|
|
13
13
|
import "./chunk-HVIEYTUK.js";
|
|
14
14
|
import "./chunk-Y4MIXGPA.js";
|
|
15
15
|
import "./chunk-VKQGAWHY.js";
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
resolveSendFollowUp,
|
|
7
7
|
startOrchestration,
|
|
8
8
|
waitForPidExit
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-Z6TW3A5P.js";
|
|
10
10
|
import "./chunk-DJU54RYW.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-OLDZXO53.js";
|
|
12
12
|
import "./chunk-VIODP5PT.js";
|
|
13
13
|
import "./chunk-WXKXSZN4.js";
|
|
14
14
|
import "./chunk-6K64FJDD.js";
|
|
@@ -16,7 +16,7 @@ import "./chunk-IEEAVWAP.js";
|
|
|
16
16
|
import "./chunk-AN3THU7F.js";
|
|
17
17
|
import "./chunk-N7WZ6NIN.js";
|
|
18
18
|
import "./chunk-AXQ4ZWHK.js";
|
|
19
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-FY64F2ZQ.js";
|
|
20
20
|
import "./chunk-J7LQVLFQ.js";
|
|
21
21
|
import "./chunk-4TR3HZFT.js";
|
|
22
22
|
import "./chunk-AO35MGOE.js";
|