@sideboard-ai/core 0.1.183 → 0.1.185
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-GBI2YFCE.js → agents-HC6HWBDB.js} +2 -2
- package/dist/{agents-BQQ6BRJO.js → agents-R6RQMMNE.js} +2 -2
- package/dist/{chunk-VA76U3BU.js → chunk-5FTIOINZ.js} +2 -2
- package/dist/{chunk-TPOODE27.js → chunk-AHV36NL3.js} +2 -2
- package/dist/{chunk-26N6LKLE.js → chunk-G4VAMUCL.js} +22 -22
- package/dist/{chunk-B4IENDRW.js → chunk-IQC35TVQ.js} +21 -21
- package/dist/{chunk-JFDCHOU7.js → chunk-VIODP5PT.js} +5 -5
- package/dist/{chunk-JA7TKTQ4.js → chunk-XXEIF2IL.js} +5 -5
- package/dist/{coordinator-prompt-UBCXNR5V.js → coordinator-prompt-LWKOL3AZ.js} +1 -1
- package/dist/{coordinator-prompt-NEF3AEFG.js → coordinator-prompt-MSC44OOM.js} +1 -1
- package/dist/{global-workspace-RNPHVMFM.js → global-workspace-6G5JJH2E.js} +1 -1
- package/dist/{global-workspace-5B6AOK7A.js → global-workspace-XATJTV3N.js} +1 -1
- package/dist/index.cjs +115 -83
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +100 -68
- package/dist/mcp/run-stdio.cjs +115 -83
- package/dist/mcp/run-stdio.js +100 -68
- package/dist/{orchestrator-H4G6SN4O.js → orchestrator-45PPV2LQ.js} +3 -3
- package/dist/{orchestrator-CMNI3MIS.js → orchestrator-SVFF5CLQ.js} +3 -3
- package/dist/{workspaces-NQQ5X6L4.js → workspaces-FWKPWSXV.js} +1 -1
- package/dist/{workspaces-4ZTRQX2J.js → workspaces-LMFCRXTT.js} +1 -1
- package/package.json +1 -1
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -7853,7 +7853,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
7853
7853
|
"Typical flow (Home board): list_board \u2192 create_thread (sourceType=ticket|pr|branch) \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
|
|
7854
7854
|
"Typical flow (branch / explicit source): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
7855
7855
|
"Typical flow (find work): list_workspaces \u2192 pick repo(s) matching account / project context \u2192 Sideboard list_issues / linear_* (tickets) or list_prs(queue=review) (reviews) \u2192 show the options. Never wait on Claude Linear MCP. Only create_thread + send_to_thread when they asked to start (e.g. \u201Cfind me work and start it\u201D) \u2014 then wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
7856
|
-
'Typical flow (review inbox): list_workspaces \u2192 list_prs(queue=review, limit=N) \u2192 show those PRs (ticket ids in the title when present). create_thread sourceType=pr only when they asked to start / do the work. Do not list_issues for "tickets to review". The child writes the review in chat and
|
|
7856
|
+
'Typical flow (review inbox): list_workspaces \u2192 list_prs(queue=review, limit=N) \u2192 show those PRs (ticket ids in the title when present). create_thread sourceType=pr only when they asked to start / do the work. Do not list_issues for "tickets to review". The child writes the review in chat and stops \u2014 do not ask_user after it. Do not github_comment / linear_comment / update the PR or ticket, and do not tell the child to post, until the user types a next step. They should work through the feedback in chat first. The PR or ticket author sees those writes immediately.',
|
|
7857
7857
|
"Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
7858
7858
|
"Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). If the user gave a goal (Greptile 5/5, CI green), pass that goal through so they watch-fix-push until it lands \u2014 do not start that loop on a plain push, and do not tell the human to poll. Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
|
|
7859
7859
|
].join("\n");
|
|
@@ -7911,8 +7911,8 @@ var init_coordinator_prompt = __esm({
|
|
|
7911
7911
|
'- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_thread sourceType=pr. That is open non-draft PRs labeled eng-review with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets \u2014 do not use it for that review-inbox ask. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).',
|
|
7912
7912
|
"- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. Show the options \u2014 do not create_thread or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
|
|
7913
7913
|
"- Ticket updates: list_issues / linear_search_issues / github_search_issues with updatedSince (yesterday, 2d, or ISO). One call returns new assignments, ticket edits, and new comments \u2014 do not get_issue every ticket just to check for comments. kind=created vs updated distinguishes new tickets from existing ones.",
|
|
7914
|
-
"- linear_* (when Linear is connected) \u2014 list_teams for team key/states; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user
|
|
7915
|
-
"- github_* \u2014 get/comment/update/create GitHub issues via Account `gh` (#123). Worktree agents have these too. Prefer over any vendor GitHub MCP. Pass parent= for spin-offs. When reviewing a PR or ticket, do not comment, submit `gh pr review`, or update the PR/ticket until the user
|
|
7914
|
+
"- linear_* (when Linear is connected) \u2014 list_teams for team key/states; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user types a next step \u2014 they should work through the feedback in chat first. Do not tell the child to ask_user after the review. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list.",
|
|
7915
|
+
"- github_* \u2014 get/comment/update/create GitHub issues via Account `gh` (#123). Worktree agents have these too. Prefer over any vendor GitHub MCP. Pass parent= for spin-offs. When reviewing a PR or ticket, do not comment, submit `gh pr review`, or update the PR/ticket until the user types a next step.",
|
|
7916
7916
|
"- abletime_* (when AbleTime is connected) \u2014 orientation first; get/comment/update/create (parent= for spin-offs); ensure_task when work has no ticket (or create_thread from the default branch auto-creates one). Worktree agents have the same Account tools. Same review-write gate as Linear/GitHub.",
|
|
7917
7917
|
"- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post / slack_replies \u2014 Slack workspaces from Settings \u2192 Remote; pass team_id from list_teams",
|
|
7918
7918
|
"- Optional connectors (Vercel, Supabase, PostHog, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`) with those env vars. PostHog has no first-class CLI \u2014 use the HTTP API (`POSTHOG_PERSONAL_API_KEY`). Tell any worktree agent (Claude / Cursor / Codex / OpenCode) to write CLI output to `.context/cli/` (not `.context/attachments/`) and read a slice \u2014 never stream raw `--json` / `--expand` into a tool result (that crashes the turn). They can `stop_job` if a detached fetch hangs. If a CLI is missing, the user can Install CLI on that row (not auto-installed on Connect). Do not add vendor MCPs or ask the user to paste tokens again. Git (`gh`) stays Settings \u2192 Git; issue tracking stays Settings \u2192 Issues; Slack stays Settings \u2192 Remote (Sideboard MCP).",
|
|
@@ -7920,7 +7920,7 @@ var init_coordinator_prompt = __esm({
|
|
|
7920
7920
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
7921
7921
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
7922
7922
|
"- list_threads / get_thread \u2014 live thread list (parent id + last message preview). get_thread on this orchestration chat lists child worktree agents (status + lastText). Also includes usage / lastTurnUsage.",
|
|
7923
|
-
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API, Save this context / Do not save
|
|
7923
|
+
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API, Save this context / Do not save). Never for hellos, check-ins, invented \u201Cwhat should we do?\u201D menus, or after a review \u2014 reply in chat. Explain options first, description on every option, then wait.",
|
|
7924
7924
|
"- get_viewer_context / update_viewer_context \u2014 read or replace Settings \u2192 Agents (account) and Settings \u2192 Projects (per-repo) context. You can update a project: pass scope=project and repoPath from list_workspaces (this cwd is not a project). update_viewer_context requires confirmed=true after ask_user. Never write context unprompted.",
|
|
7925
7925
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work, overnight schedules, or when the user will be away. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
7926
7926
|
"- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 local jobs that send a prompt to an orchestration chat (threadId or self) or start a new Global chat (omit threadId). One-shot `at`, interval `every` (15m/1h/6h/1d), or 5-field `cron`. Recurring jobs without threadId open a new chat each run. Jobs fire only while Sideboard.app is running; sleep skips until wake. Overnight/unattended runs: ask the user to enable Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or call set_caffeinate.",
|
|
@@ -7941,7 +7941,7 @@ var init_coordinator_prompt = __esm({
|
|
|
7941
7941
|
"Inspect / review / PRs:",
|
|
7942
7942
|
"- get_diff \u2014 compact diff summary",
|
|
7943
7943
|
"- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
|
|
7944
|
-
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat
|
|
7944
|
+
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
|
|
7945
7945
|
"- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
|
|
7946
7946
|
'- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
|
|
7947
7947
|
'- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
|
|
@@ -13151,11 +13151,11 @@ People running this review are asking \u201Ccan we ship this?\u201D Treat that a
|
|
|
13151
13151
|
|
|
13152
13152
|
## Confirm before posting
|
|
13153
13153
|
|
|
13154
|
-
The report stays in this chat until the user posts it. Do not call \`github_comment\`, \`linear_comment\`, \`abletime_comment\`, \`github_update_issue\`, \`linear_update_issue\`, \`abletime_update_task\`, or run \`gh pr review\` / \`gh pr comment\`, until they
|
|
13154
|
+
The report stays in this chat until the user posts it. Do not call \`github_comment\`, \`linear_comment\`, \`abletime_comment\`, \`github_update_issue\`, \`linear_update_issue\`, \`abletime_update_task\`, or run \`gh pr review\` / \`gh pr comment\`, until they type a next step that asks you to post.
|
|
13155
13155
|
|
|
13156
|
-
After the Recommendation is in chat, ask_user
|
|
13156
|
+
After the Recommendation is in chat, stop. Do not call ask_user. The user needs time to read the review and will type the next steps. If they already asked you to post a specific comment or update in this turn, that is confirmation.
|
|
13157
13157
|
|
|
13158
|
-
The
|
|
13158
|
+
The PR or ticket author sees those writes immediately \u2014 a draft review will confuse them. Do not request reviewers, change labels, or assign yourself unless they asked.
|
|
13159
13159
|
|
|
13160
13160
|
## Findings
|
|
13161
13161
|
|
|
@@ -14694,7 +14694,7 @@ function classifyWorktreeOwnership(group, viewerLogin = "") {
|
|
|
14694
14694
|
const reviewing = group.some((t) => {
|
|
14695
14695
|
const author = normalizeViewerLogin(t.prAuthorLogin);
|
|
14696
14696
|
if (author && me && author !== me) return true;
|
|
14697
|
-
if (t.sourceType === "pr" && (!author ||
|
|
14697
|
+
if (t.sourceType === "pr" && me && (!author || author !== me)) return true;
|
|
14698
14698
|
if (me && loginsInclude(t.prReviewerLogins, me)) return true;
|
|
14699
14699
|
return false;
|
|
14700
14700
|
});
|
|
@@ -18234,13 +18234,13 @@ function formatIssueToolsDirective(opts) {
|
|
|
18234
18234
|
}
|
|
18235
18235
|
lines.push(
|
|
18236
18236
|
"- Do not ask the user to `claude mcp login` for tickets. Reconnect the Account source in Settings \u2192 Issues (or Git for `gh`).",
|
|
18237
|
-
"- When reviewing a PR or ticket (review inbox or a Review tab): write the review in chat
|
|
18237
|
+
"- When reviewing a PR or ticket (review inbox or a Review tab): write the review in chat and stop. Do not call ask_user. The user needs time to read and will type next steps. Do not `github_comment` / `linear_comment` / `*_update_*` / `gh pr review` until they ask. The PR or ticket author sees those immediately."
|
|
18238
18238
|
);
|
|
18239
18239
|
const ticket = opts.ticketId?.trim();
|
|
18240
18240
|
if (ticket) {
|
|
18241
18241
|
const provider = opts.ticketProvider ?? "linear";
|
|
18242
18242
|
lines.push(
|
|
18243
|
-
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get. Do not comment or update it with review findings until they
|
|
18243
|
+
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get. Do not comment or update it with review findings until they type a next step that asks you to \u2014 they should work through the feedback in chat first. If they asked you to do the work, routine status and spin-offs (\`parent=\`) are OK.`
|
|
18244
18244
|
);
|
|
18245
18245
|
}
|
|
18246
18246
|
return lines.join("\n");
|
|
@@ -18254,8 +18254,8 @@ function formatIssueToolsReminder(opts) {
|
|
|
18254
18254
|
opts.abletime ? "abletime_*" : null
|
|
18255
18255
|
].filter(Boolean);
|
|
18256
18256
|
const ticket = opts.ticketId?.trim();
|
|
18257
|
-
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get; comment/update review findings only after
|
|
18258
|
-
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit} Review
|
|
18257
|
+
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get; comment/update review findings only after they ask. Spin-offs use parent=.` : " get/comment/update/create (parent= for spin-offs).";
|
|
18258
|
+
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit} Review stays in chat \u2014 do not ask_user after it; they type next steps. Authors see comments immediately.`;
|
|
18259
18259
|
}
|
|
18260
18260
|
function formatPrGateDirective() {
|
|
18261
18261
|
return [
|
|
@@ -18301,11 +18301,11 @@ function formatArtifactDirective() {
|
|
|
18301
18301
|
"- Standalone documents: a fenced block tagged `html` (preferred), `svg`, or `markdown` containing the FULL document opens the side column by itself. Use that or present_artifact \u2014 never both for the same body.",
|
|
18302
18302
|
"- present_artifact type=log appends: same artifact_id, content = new lines only (plus status/phase). Do not resend the full log or wrap it in HTML.",
|
|
18303
18303
|
"- Data: a markdown table is enough to read. Call present_schema only when the user needs to filter/edit/publish/persist rows \u2014 including when they ask for an editable table after you already showed markdown. Never re-present rows you already wrote just to display them.",
|
|
18304
|
-
"- ask_user only when work is blocked on a few concrete options (approach fork, which API, auth vs cookies): first a short chat message explaining the decision and each option, then the call (description on every option), then stop and wait. Not for greetings, check-ins,
|
|
18304
|
+
"- ask_user only when work is blocked on a few concrete options (approach fork, which API, auth vs cookies): first a short chat message explaining the decision and each option, then the call (description on every option), then stop and wait. Not for greetings, check-ins, an invented menu of next tasks, or after a review \u2014 reply in chat. If one option is the obvious default, proceed."
|
|
18305
18305
|
].join("\n");
|
|
18306
18306
|
}
|
|
18307
18307
|
function formatUiReminder() {
|
|
18308
|
-
return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos
|
|
18308
|
+
return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
|
|
18309
18309
|
}
|
|
18310
18310
|
var import_node_fs48, import_node_path45, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
|
|
18311
18311
|
var init_instructions = __esm({
|
|
@@ -18338,13 +18338,13 @@ function isReviewWriteGatedThread(thread, siblings) {
|
|
|
18338
18338
|
function formatReviewWriteGateDirective() {
|
|
18339
18339
|
return [
|
|
18340
18340
|
"Review writes are public. The PR or ticket author sees GitHub/Linear/AbleTime comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
|
|
18341
|
-
"Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until
|
|
18342
|
-
"After the review is in chat, ask_user
|
|
18341
|
+
"Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until they type a next step that asks you to post.",
|
|
18342
|
+
"After the review is in chat, stop. Do not call ask_user. The user needs time to read and will type the next steps. If they already asked you to post a specific comment or update in this turn, that is confirmation.",
|
|
18343
18343
|
"Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
|
|
18344
18344
|
].join("\n");
|
|
18345
18345
|
}
|
|
18346
18346
|
function formatReviewWriteGateReminder() {
|
|
18347
|
-
return "Review writes: keep the review in chat
|
|
18347
|
+
return "Review writes: keep the review in chat. Do not ask_user after it \u2014 they read and type next steps. Do not github_comment / linear_comment / *_update_* / `gh pr review` on the PR or ticket until they ask. Authors see those immediately.";
|
|
18348
18348
|
}
|
|
18349
18349
|
var REVIEW_TAB_TITLE;
|
|
18350
18350
|
var init_review_write_gate = __esm({
|
|
@@ -21709,10 +21709,32 @@ function issueNumberFromApiUrl(url) {
|
|
|
21709
21709
|
const number = Number(match[1]);
|
|
21710
21710
|
return Number.isFinite(number) && number > 0 ? number : null;
|
|
21711
21711
|
}
|
|
21712
|
+
var GITHUB_ISSUE_COMMENTS_PAGE_SIZE = 100;
|
|
21713
|
+
var GITHUB_ISSUE_COMMENTS_MAX_PAGES = 5;
|
|
21714
|
+
function parseGitHubIssueCommentNode(item, allowed) {
|
|
21715
|
+
const rec = item && typeof item === "object" ? item : null;
|
|
21716
|
+
if (!rec) return null;
|
|
21717
|
+
const issueUrl = typeof rec.issue_url === "string" ? rec.issue_url : "";
|
|
21718
|
+
const number = issueNumberFromApiUrl(issueUrl);
|
|
21719
|
+
if (number == null) return null;
|
|
21720
|
+
if (allowed && !allowed.has(number)) return null;
|
|
21721
|
+
const body = previewIssueCommentBody(typeof rec.body === "string" ? rec.body : "");
|
|
21722
|
+
const user = rec.user && typeof rec.user === "object" ? String(rec.user.login ?? "").trim() : "";
|
|
21723
|
+
const createdAt = typeof rec.created_at === "string" ? rec.created_at : typeof rec.createdAt === "string" ? rec.createdAt : void 0;
|
|
21724
|
+
const url = typeof rec.html_url === "string" ? rec.html_url : void 0;
|
|
21725
|
+
return {
|
|
21726
|
+
identifier: `#${number}`,
|
|
21727
|
+
...user ? { author: user } : {},
|
|
21728
|
+
...createdAt ? { createdAt } : {},
|
|
21729
|
+
body,
|
|
21730
|
+
...url ? { url } : {}
|
|
21731
|
+
};
|
|
21732
|
+
}
|
|
21712
21733
|
async function listGitHubIssueCommentsSince(opts) {
|
|
21713
21734
|
const limit = Math.max(1, Math.min(250, opts.limit ?? 200));
|
|
21714
21735
|
const { cwd, slug } = await resolveGitHubIssueRepo(opts.repoPath);
|
|
21715
21736
|
if (!slug) return [];
|
|
21737
|
+
const restrictToIssues = opts.issueIdentifiers != null;
|
|
21716
21738
|
const allowed = new Set(
|
|
21717
21739
|
(opts.issueIdentifiers ?? []).map((id) => {
|
|
21718
21740
|
try {
|
|
@@ -21722,36 +21744,27 @@ async function listGitHubIssueCommentsSince(opts) {
|
|
|
21722
21744
|
}
|
|
21723
21745
|
}).filter((n) => n != null)
|
|
21724
21746
|
);
|
|
21725
|
-
|
|
21726
|
-
const
|
|
21727
|
-
if (result.exitCode !== 0 || !result.stdout.trim()) return [];
|
|
21728
|
-
let parsed;
|
|
21729
|
-
try {
|
|
21730
|
-
parsed = JSON.parse(result.stdout);
|
|
21731
|
-
} catch {
|
|
21732
|
-
return [];
|
|
21733
|
-
}
|
|
21734
|
-
if (!Array.isArray(parsed)) return [];
|
|
21747
|
+
if (restrictToIssues && allowed.size === 0) return [];
|
|
21748
|
+
const pageSize = Math.min(GITHUB_ISSUE_COMMENTS_PAGE_SIZE, Math.max(1, limit));
|
|
21735
21749
|
const out = [];
|
|
21736
|
-
for (
|
|
21737
|
-
const
|
|
21738
|
-
|
|
21739
|
-
|
|
21740
|
-
|
|
21741
|
-
|
|
21742
|
-
|
|
21743
|
-
|
|
21744
|
-
|
|
21745
|
-
|
|
21746
|
-
|
|
21747
|
-
|
|
21748
|
-
|
|
21749
|
-
|
|
21750
|
-
|
|
21751
|
-
|
|
21752
|
-
|
|
21753
|
-
|
|
21754
|
-
if (out.length >= limit) break;
|
|
21750
|
+
for (let page = 1; page <= GITHUB_ISSUE_COMMENTS_MAX_PAGES; page++) {
|
|
21751
|
+
const path = `repos/${slug}/issues/comments?since=${encodeURIComponent(opts.since)}&sort=created&direction=desc&per_page=${pageSize}&page=${page}`;
|
|
21752
|
+
const result = await gh(["api", path], cwd, { reject: false });
|
|
21753
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) break;
|
|
21754
|
+
let parsed;
|
|
21755
|
+
try {
|
|
21756
|
+
parsed = JSON.parse(result.stdout);
|
|
21757
|
+
} catch {
|
|
21758
|
+
break;
|
|
21759
|
+
}
|
|
21760
|
+
if (!Array.isArray(parsed) || parsed.length === 0) break;
|
|
21761
|
+
for (const item of parsed) {
|
|
21762
|
+
const comment = parseGitHubIssueCommentNode(item, restrictToIssues ? allowed : null);
|
|
21763
|
+
if (!comment) continue;
|
|
21764
|
+
out.push(comment);
|
|
21765
|
+
if (out.length >= limit) return out;
|
|
21766
|
+
}
|
|
21767
|
+
if (parsed.length < pageSize) break;
|
|
21755
21768
|
}
|
|
21756
21769
|
return out;
|
|
21757
21770
|
}
|
|
@@ -22361,12 +22374,27 @@ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
|
22361
22374
|
function assigneeFilterKey(assignee) {
|
|
22362
22375
|
return (assignee ?? "").trim();
|
|
22363
22376
|
}
|
|
22377
|
+
function applyLinearIssueQueryFilter(filter, query) {
|
|
22378
|
+
const term = query?.trim();
|
|
22379
|
+
if (!term) return;
|
|
22380
|
+
const or = [
|
|
22381
|
+
{ title: { containsIgnoreCase: term } },
|
|
22382
|
+
{ description: { containsIgnoreCase: term } }
|
|
22383
|
+
];
|
|
22384
|
+
const identifierMatch = term.match(/^[A-Za-z][\w]*-(\d+)$/);
|
|
22385
|
+
const asNumber = identifierMatch ? Number(identifierMatch[1]) : /^\d+$/.test(term) ? Number(term) : NaN;
|
|
22386
|
+
if (Number.isFinite(asNumber) && asNumber > 0) {
|
|
22387
|
+
or.push({ number: { eq: asNumber } });
|
|
22388
|
+
}
|
|
22389
|
+
filter.or = or;
|
|
22390
|
+
}
|
|
22364
22391
|
function buildLinearIssueFilter(input) {
|
|
22365
22392
|
const filter = {
|
|
22366
22393
|
state: { type: { nin: ["completed", "canceled"] } }
|
|
22367
22394
|
};
|
|
22368
22395
|
const since = input?.updatedSince?.trim();
|
|
22369
22396
|
if (since) filter.updatedAt = { gte: since };
|
|
22397
|
+
applyLinearIssueQueryFilter(filter, input?.query);
|
|
22370
22398
|
const raw = assigneeFilterKey(input?.assignee) || "me";
|
|
22371
22399
|
const key = raw.toLowerCase();
|
|
22372
22400
|
if (key === "all" || key === "*") return filter;
|
|
@@ -22432,6 +22460,11 @@ async function listLinearIssuesFiltered(opts) {
|
|
|
22432
22460
|
async function listLinearCommentsSince(opts) {
|
|
22433
22461
|
const first = Math.max(1, Math.min(250, opts.limit ?? 200));
|
|
22434
22462
|
const query = opts.query?.trim() ?? "";
|
|
22463
|
+
const restrictToIssues = opts.issueIdentifiers != null;
|
|
22464
|
+
const allowed = new Set(
|
|
22465
|
+
(opts.issueIdentifiers ?? []).map((id) => id.trim()).filter(Boolean)
|
|
22466
|
+
);
|
|
22467
|
+
if (restrictToIssues && allowed.size === 0) return [];
|
|
22435
22468
|
const assignee = assigneeFilterKey(opts.assignee) || (query ? "all" : "me");
|
|
22436
22469
|
const json = await linearGraphql(
|
|
22437
22470
|
COMMENTS_SINCE_QUERY,
|
|
@@ -22439,7 +22472,7 @@ async function listLinearCommentsSince(opts) {
|
|
|
22439
22472
|
first,
|
|
22440
22473
|
filter: {
|
|
22441
22474
|
createdAt: { gte: opts.since },
|
|
22442
|
-
issue: buildLinearIssueFilter({ assignee })
|
|
22475
|
+
issue: buildLinearIssueFilter({ assignee, query: query || void 0 })
|
|
22443
22476
|
}
|
|
22444
22477
|
},
|
|
22445
22478
|
opts
|
|
@@ -22447,6 +22480,7 @@ async function listLinearCommentsSince(opts) {
|
|
|
22447
22480
|
const out = [];
|
|
22448
22481
|
for (const node of json.comments?.nodes ?? []) {
|
|
22449
22482
|
const identifier = String(node.issue?.identifier ?? "").trim();
|
|
22483
|
+
if (restrictToIssues && !allowed.has(identifier)) continue;
|
|
22450
22484
|
const body = previewIssueCommentBody(String(node.body ?? ""));
|
|
22451
22485
|
if (!identifier && !body) continue;
|
|
22452
22486
|
out.push({
|
|
@@ -22672,20 +22706,19 @@ async function listIssues(repoPath, opts) {
|
|
|
22672
22706
|
const assignee = opts?.assignee?.trim() || void 0;
|
|
22673
22707
|
const since = opts?.updatedSince ? parseIssueSince(opts.updatedSince) : void 0;
|
|
22674
22708
|
if (source === "linear") {
|
|
22675
|
-
const
|
|
22676
|
-
|
|
22677
|
-
|
|
22678
|
-
|
|
22679
|
-
|
|
22680
|
-
|
|
22681
|
-
|
|
22682
|
-
since
|
|
22683
|
-
|
|
22684
|
-
|
|
22685
|
-
|
|
22686
|
-
|
|
22687
|
-
|
|
22688
|
-
]);
|
|
22709
|
+
const listed = await listLinearIssuesFiltered({
|
|
22710
|
+
assignee,
|
|
22711
|
+
query,
|
|
22712
|
+
limit: opts?.limit,
|
|
22713
|
+
updatedSince: since
|
|
22714
|
+
});
|
|
22715
|
+
const comments2 = since ? await listLinearCommentsSince({
|
|
22716
|
+
since,
|
|
22717
|
+
assignee,
|
|
22718
|
+
query,
|
|
22719
|
+
issueIdentifiers: query ? listed.issues.map((issue) => issue.identifier) : void 0,
|
|
22720
|
+
limit: opts?.limit
|
|
22721
|
+
}) : void 0;
|
|
22689
22722
|
return {
|
|
22690
22723
|
source,
|
|
22691
22724
|
preferredSource,
|
|
@@ -23813,7 +23846,7 @@ function registerAbleTimeTools(server) {
|
|
|
23813
23846
|
);
|
|
23814
23847
|
server.tool(
|
|
23815
23848
|
"abletime_comment",
|
|
23816
|
-
"Add a markdown comment on an AbleTime task (id or CRM-232). When reviewing a PR or ticket, show the draft in chat and
|
|
23849
|
+
"Add a markdown comment on an AbleTime task (id or CRM-232). When reviewing a PR or ticket, show the draft in chat and wait until they type a next step \u2014 do not ask_user after the review. The author sees this immediately.",
|
|
23817
23850
|
{ id: import_zod4.z.string(), body: import_zod4.z.string() },
|
|
23818
23851
|
async (args) => {
|
|
23819
23852
|
try {
|
|
@@ -23825,7 +23858,7 @@ function registerAbleTimeTools(server) {
|
|
|
23825
23858
|
);
|
|
23826
23859
|
server.tool(
|
|
23827
23860
|
"abletime_update_task",
|
|
23828
|
-
"Update an AbleTime task (id or CRM-232). Pass title, description, and/or state. When reviewing a PR or ticket,
|
|
23861
|
+
"Update an AbleTime task (id or CRM-232). Pass title, description, and/or state. When reviewing a PR or ticket, wait until they type a next step before changing the task \u2014 do not ask_user after the review. The author is notified.",
|
|
23829
23862
|
{
|
|
23830
23863
|
id: import_zod4.z.string(),
|
|
23831
23864
|
title: import_zod4.z.string().optional(),
|
|
@@ -23955,7 +23988,7 @@ function registerGithubIssueTools(server) {
|
|
|
23955
23988
|
);
|
|
23956
23989
|
server.tool(
|
|
23957
23990
|
"github_comment",
|
|
23958
|
-
"Add a markdown comment on a GitHub issue (#123 or URL). Uses Account gh. When reviewing a PR or ticket, show the draft in chat and
|
|
23991
|
+
"Add a markdown comment on a GitHub issue (#123 or URL). Uses Account gh. When reviewing a PR or ticket, show the draft in chat and wait until they type a next step \u2014 do not ask_user after the review. The author sees this immediately.",
|
|
23959
23992
|
{ id: import_zod5.z.string(), body: import_zod5.z.string(), repoPath: repoPathSchema },
|
|
23960
23993
|
async ({ id, body, repoPath }) => {
|
|
23961
23994
|
try {
|
|
@@ -23967,7 +24000,7 @@ function registerGithubIssueTools(server) {
|
|
|
23967
24000
|
);
|
|
23968
24001
|
server.tool(
|
|
23969
24002
|
"github_update_issue",
|
|
23970
|
-
"Update a GitHub issue (#123). Pass title, body, and/or state (open|closed). When reviewing a PR or ticket,
|
|
24003
|
+
"Update a GitHub issue (#123). Pass title, body, and/or state (open|closed). When reviewing a PR or ticket, wait until they type a next step before changing the issue \u2014 do not ask_user after the review. The author is notified.",
|
|
23971
24004
|
{
|
|
23972
24005
|
id: import_zod5.z.string(),
|
|
23973
24006
|
title: import_zod5.z.string().optional(),
|
|
@@ -24040,20 +24073,19 @@ function registerLinearTools(server) {
|
|
|
24040
24073
|
try {
|
|
24041
24074
|
const page = clampMcpIssueLimit(limit);
|
|
24042
24075
|
const since = updatedSince ? parseIssueSince(updatedSince) : void 0;
|
|
24043
|
-
const
|
|
24044
|
-
|
|
24045
|
-
|
|
24046
|
-
|
|
24047
|
-
|
|
24048
|
-
|
|
24049
|
-
|
|
24050
|
-
since
|
|
24051
|
-
|
|
24052
|
-
|
|
24053
|
-
|
|
24054
|
-
|
|
24055
|
-
|
|
24056
|
-
]);
|
|
24076
|
+
const listed = await listLinearIssuesFiltered({
|
|
24077
|
+
query,
|
|
24078
|
+
assignee,
|
|
24079
|
+
limit: page + 1,
|
|
24080
|
+
updatedSince: since
|
|
24081
|
+
});
|
|
24082
|
+
const comments = since ? await listLinearCommentsSince({
|
|
24083
|
+
since,
|
|
24084
|
+
assignee,
|
|
24085
|
+
query,
|
|
24086
|
+
issueIdentifiers: query ? listed.issues.map((issue) => issue.identifier) : void 0,
|
|
24087
|
+
limit: page + 1
|
|
24088
|
+
}) : void 0;
|
|
24057
24089
|
return mcpJson(
|
|
24058
24090
|
formatListedIssuesForMcp(
|
|
24059
24091
|
{
|
|
@@ -24105,7 +24137,7 @@ function registerLinearTools(server) {
|
|
|
24105
24137
|
);
|
|
24106
24138
|
server.tool(
|
|
24107
24139
|
"linear_update_issue",
|
|
24108
|
-
"Update a Linear issue (uuid or ENG-123). Pass title, description, state, assignee, and/or priority. When reviewing a PR or ticket,
|
|
24140
|
+
"Update a Linear issue (uuid or ENG-123). Pass title, description, state, assignee, and/or priority. 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.",
|
|
24109
24141
|
{
|
|
24110
24142
|
id: import_zod6.z.string(),
|
|
24111
24143
|
title: import_zod6.z.string().optional(),
|
|
@@ -24124,7 +24156,7 @@ function registerLinearTools(server) {
|
|
|
24124
24156
|
);
|
|
24125
24157
|
server.tool(
|
|
24126
24158
|
"linear_comment",
|
|
24127
|
-
"Add a markdown comment on a Linear issue (uuid or ENG-123). When reviewing a PR or ticket, show the draft in chat and
|
|
24159
|
+
"Add a markdown comment on a Linear issue (uuid or ENG-123). When reviewing a PR or ticket, show the draft in chat and wait until they type a next step \u2014 do not ask_user after the review. The author sees this immediately.",
|
|
24128
24160
|
{
|
|
24129
24161
|
id: import_zod6.z.string(),
|
|
24130
24162
|
body: import_zod6.z.string()
|
|
@@ -25513,7 +25545,7 @@ async function startMcpServer() {
|
|
|
25513
25545
|
);
|
|
25514
25546
|
server.tool(
|
|
25515
25547
|
"request_review",
|
|
25516
|
-
'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 copies .sideboard/review.md into .context/review.md, or seeds that file from the stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information in that chat.
|
|
25548
|
+
'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 copies .sideboard/review.md into .context/review.md, or seeds that file from the stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information in that chat. The review stays there so the user can read it and type next steps \u2014 do not comment on or update the PR or ticket, and do not ask_user after the review, until they ask. 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.',
|
|
25517
25549
|
{ ref: import_zod9.z.string().describe("Worktree thread id/ref to review") },
|
|
25518
25550
|
async ({ ref }) => {
|
|
25519
25551
|
try {
|