@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/index.cjs
CHANGED
|
@@ -7694,7 +7694,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
7694
7694
|
"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).",
|
|
7695
7695
|
"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.",
|
|
7696
7696
|
"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.",
|
|
7697
|
-
'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
|
|
7697
|
+
'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.',
|
|
7698
7698
|
"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.",
|
|
7699
7699
|
"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."
|
|
7700
7700
|
].join("\n");
|
|
@@ -7752,8 +7752,8 @@ var init_coordinator_prompt = __esm({
|
|
|
7752
7752
|
'- 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).',
|
|
7753
7753
|
"- 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.",
|
|
7754
7754
|
"- 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.",
|
|
7755
|
-
"- 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
|
|
7756
|
-
"- 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
|
|
7755
|
+
"- 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.",
|
|
7756
|
+
"- 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.",
|
|
7757
7757
|
"- 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.",
|
|
7758
7758
|
"- 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",
|
|
7759
7759
|
"- 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).",
|
|
@@ -7761,7 +7761,7 @@ var init_coordinator_prompt = __esm({
|
|
|
7761
7761
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
7762
7762
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
7763
7763
|
"- 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.",
|
|
7764
|
-
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API, Save this context / Do not save
|
|
7764
|
+
"- 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.",
|
|
7765
7765
|
"- 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.",
|
|
7766
7766
|
"- 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.",
|
|
7767
7767
|
"- 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.",
|
|
@@ -7782,7 +7782,7 @@ var init_coordinator_prompt = __esm({
|
|
|
7782
7782
|
"Inspect / review / PRs:",
|
|
7783
7783
|
"- get_diff \u2014 compact diff summary",
|
|
7784
7784
|
"- 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.",
|
|
7785
|
-
'- 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
|
|
7785
|
+
'- 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.',
|
|
7786
7786
|
"- 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.",
|
|
7787
7787
|
'- 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.',
|
|
7788
7788
|
'- 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.',
|
|
@@ -14928,11 +14928,11 @@ People running this review are asking \u201Ccan we ship this?\u201D Treat that a
|
|
|
14928
14928
|
|
|
14929
14929
|
## Confirm before posting
|
|
14930
14930
|
|
|
14931
|
-
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
|
|
14931
|
+
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.
|
|
14932
14932
|
|
|
14933
|
-
After the Recommendation is in chat, ask_user
|
|
14933
|
+
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.
|
|
14934
14934
|
|
|
14935
|
-
The
|
|
14935
|
+
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.
|
|
14936
14936
|
|
|
14937
14937
|
## Findings
|
|
14938
14938
|
|
|
@@ -16349,7 +16349,7 @@ function classifyWorktreeOwnership(group, viewerLogin = "") {
|
|
|
16349
16349
|
const reviewing = group.some((t) => {
|
|
16350
16350
|
const author = normalizeViewerLogin(t.prAuthorLogin);
|
|
16351
16351
|
if (author && me && author !== me) return true;
|
|
16352
|
-
if (t.sourceType === "pr" && (!author ||
|
|
16352
|
+
if (t.sourceType === "pr" && me && (!author || author !== me)) return true;
|
|
16353
16353
|
if (me && loginsInclude(t.prReviewerLogins, me)) return true;
|
|
16354
16354
|
return false;
|
|
16355
16355
|
});
|
|
@@ -19955,13 +19955,13 @@ function formatIssueToolsDirective(opts) {
|
|
|
19955
19955
|
}
|
|
19956
19956
|
lines.push(
|
|
19957
19957
|
"- Do not ask the user to `claude mcp login` for tickets. Reconnect the Account source in Settings \u2192 Issues (or Git for `gh`).",
|
|
19958
|
-
"- When reviewing a PR or ticket (review inbox or a Review tab): write the review in chat
|
|
19958
|
+
"- 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."
|
|
19959
19959
|
);
|
|
19960
19960
|
const ticket = opts.ticketId?.trim();
|
|
19961
19961
|
if (ticket) {
|
|
19962
19962
|
const provider = opts.ticketProvider ?? "linear";
|
|
19963
19963
|
lines.push(
|
|
19964
|
-
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get. Do not comment or update it with review findings until they
|
|
19964
|
+
`- 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.`
|
|
19965
19965
|
);
|
|
19966
19966
|
}
|
|
19967
19967
|
return lines.join("\n");
|
|
@@ -19984,8 +19984,8 @@ function formatIssueToolsReminder(opts) {
|
|
|
19984
19984
|
opts.abletime ? "abletime_*" : null
|
|
19985
19985
|
].filter(Boolean);
|
|
19986
19986
|
const ticket = opts.ticketId?.trim();
|
|
19987
|
-
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get; comment/update review findings only after
|
|
19988
|
-
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit} Review
|
|
19987
|
+
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).";
|
|
19988
|
+
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.`;
|
|
19989
19989
|
}
|
|
19990
19990
|
function formatLinearReminder(opts) {
|
|
19991
19991
|
return formatIssueToolsReminder({
|
|
@@ -20040,11 +20040,11 @@ function formatArtifactDirective() {
|
|
|
20040
20040
|
"- 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.",
|
|
20041
20041
|
"- 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.",
|
|
20042
20042
|
"- 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.",
|
|
20043
|
-
"- 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,
|
|
20043
|
+
"- 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."
|
|
20044
20044
|
].join("\n");
|
|
20045
20045
|
}
|
|
20046
20046
|
function formatUiReminder() {
|
|
20047
|
-
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
|
|
20047
|
+
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.";
|
|
20048
20048
|
}
|
|
20049
20049
|
var import_node_fs50, import_node_path47, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
|
|
20050
20050
|
var init_instructions = __esm({
|
|
@@ -20077,13 +20077,13 @@ function isReviewWriteGatedThread(thread, siblings) {
|
|
|
20077
20077
|
function formatReviewWriteGateDirective() {
|
|
20078
20078
|
return [
|
|
20079
20079
|
"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.",
|
|
20080
|
-
"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
|
|
20081
|
-
"After the review is in chat, ask_user
|
|
20080
|
+
"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.",
|
|
20081
|
+
"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.",
|
|
20082
20082
|
"Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
|
|
20083
20083
|
].join("\n");
|
|
20084
20084
|
}
|
|
20085
20085
|
function formatReviewWriteGateReminder() {
|
|
20086
|
-
return "Review writes: keep the review in chat
|
|
20086
|
+
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.";
|
|
20087
20087
|
}
|
|
20088
20088
|
var REVIEW_TAB_TITLE;
|
|
20089
20089
|
var init_review_write_gate = __esm({
|
|
@@ -24622,12 +24622,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;
|
|
|
24622
24622
|
function assigneeFilterKey(assignee) {
|
|
24623
24623
|
return (assignee ?? "").trim();
|
|
24624
24624
|
}
|
|
24625
|
+
function applyLinearIssueQueryFilter(filter, query) {
|
|
24626
|
+
const term = query?.trim();
|
|
24627
|
+
if (!term) return;
|
|
24628
|
+
const or = [
|
|
24629
|
+
{ title: { containsIgnoreCase: term } },
|
|
24630
|
+
{ description: { containsIgnoreCase: term } }
|
|
24631
|
+
];
|
|
24632
|
+
const identifierMatch = term.match(/^[A-Za-z][\w]*-(\d+)$/);
|
|
24633
|
+
const asNumber = identifierMatch ? Number(identifierMatch[1]) : /^\d+$/.test(term) ? Number(term) : NaN;
|
|
24634
|
+
if (Number.isFinite(asNumber) && asNumber > 0) {
|
|
24635
|
+
or.push({ number: { eq: asNumber } });
|
|
24636
|
+
}
|
|
24637
|
+
filter.or = or;
|
|
24638
|
+
}
|
|
24625
24639
|
function buildLinearIssueFilter(input) {
|
|
24626
24640
|
const filter = {
|
|
24627
24641
|
state: { type: { nin: ["completed", "canceled"] } }
|
|
24628
24642
|
};
|
|
24629
24643
|
const since = input?.updatedSince?.trim();
|
|
24630
24644
|
if (since) filter.updatedAt = { gte: since };
|
|
24645
|
+
applyLinearIssueQueryFilter(filter, input?.query);
|
|
24631
24646
|
const raw = assigneeFilterKey(input?.assignee) || "me";
|
|
24632
24647
|
const key = raw.toLowerCase();
|
|
24633
24648
|
if (key === "all" || key === "*") return filter;
|
|
@@ -24693,6 +24708,11 @@ async function listLinearIssuesFiltered(opts) {
|
|
|
24693
24708
|
async function listLinearCommentsSince(opts) {
|
|
24694
24709
|
const first = Math.max(1, Math.min(250, opts.limit ?? 200));
|
|
24695
24710
|
const query = opts.query?.trim() ?? "";
|
|
24711
|
+
const restrictToIssues = opts.issueIdentifiers != null;
|
|
24712
|
+
const allowed = new Set(
|
|
24713
|
+
(opts.issueIdentifiers ?? []).map((id) => id.trim()).filter(Boolean)
|
|
24714
|
+
);
|
|
24715
|
+
if (restrictToIssues && allowed.size === 0) return [];
|
|
24696
24716
|
const assignee = assigneeFilterKey(opts.assignee) || (query ? "all" : "me");
|
|
24697
24717
|
const json = await linearGraphql(
|
|
24698
24718
|
COMMENTS_SINCE_QUERY,
|
|
@@ -24700,7 +24720,7 @@ async function listLinearCommentsSince(opts) {
|
|
|
24700
24720
|
first,
|
|
24701
24721
|
filter: {
|
|
24702
24722
|
createdAt: { gte: opts.since },
|
|
24703
|
-
issue: buildLinearIssueFilter({ assignee })
|
|
24723
|
+
issue: buildLinearIssueFilter({ assignee, query: query || void 0 })
|
|
24704
24724
|
}
|
|
24705
24725
|
},
|
|
24706
24726
|
opts
|
|
@@ -24708,6 +24728,7 @@ async function listLinearCommentsSince(opts) {
|
|
|
24708
24728
|
const out = [];
|
|
24709
24729
|
for (const node of json.comments?.nodes ?? []) {
|
|
24710
24730
|
const identifier = String(node.issue?.identifier ?? "").trim();
|
|
24731
|
+
if (restrictToIssues && !allowed.has(identifier)) continue;
|
|
24711
24732
|
const body = previewIssueCommentBody(String(node.body ?? ""));
|
|
24712
24733
|
if (!identifier && !body) continue;
|
|
24713
24734
|
out.push({
|
|
@@ -24939,10 +24960,32 @@ function issueNumberFromApiUrl(url) {
|
|
|
24939
24960
|
const number = Number(match[1]);
|
|
24940
24961
|
return Number.isFinite(number) && number > 0 ? number : null;
|
|
24941
24962
|
}
|
|
24963
|
+
var GITHUB_ISSUE_COMMENTS_PAGE_SIZE = 100;
|
|
24964
|
+
var GITHUB_ISSUE_COMMENTS_MAX_PAGES = 5;
|
|
24965
|
+
function parseGitHubIssueCommentNode(item, allowed) {
|
|
24966
|
+
const rec = item && typeof item === "object" ? item : null;
|
|
24967
|
+
if (!rec) return null;
|
|
24968
|
+
const issueUrl = typeof rec.issue_url === "string" ? rec.issue_url : "";
|
|
24969
|
+
const number = issueNumberFromApiUrl(issueUrl);
|
|
24970
|
+
if (number == null) return null;
|
|
24971
|
+
if (allowed && !allowed.has(number)) return null;
|
|
24972
|
+
const body = previewIssueCommentBody(typeof rec.body === "string" ? rec.body : "");
|
|
24973
|
+
const user = rec.user && typeof rec.user === "object" ? String(rec.user.login ?? "").trim() : "";
|
|
24974
|
+
const createdAt = typeof rec.created_at === "string" ? rec.created_at : typeof rec.createdAt === "string" ? rec.createdAt : void 0;
|
|
24975
|
+
const url = typeof rec.html_url === "string" ? rec.html_url : void 0;
|
|
24976
|
+
return {
|
|
24977
|
+
identifier: `#${number}`,
|
|
24978
|
+
...user ? { author: user } : {},
|
|
24979
|
+
...createdAt ? { createdAt } : {},
|
|
24980
|
+
body,
|
|
24981
|
+
...url ? { url } : {}
|
|
24982
|
+
};
|
|
24983
|
+
}
|
|
24942
24984
|
async function listGitHubIssueCommentsSince(opts) {
|
|
24943
24985
|
const limit = Math.max(1, Math.min(250, opts.limit ?? 200));
|
|
24944
24986
|
const { cwd, slug } = await resolveGitHubIssueRepo(opts.repoPath);
|
|
24945
24987
|
if (!slug) return [];
|
|
24988
|
+
const restrictToIssues = opts.issueIdentifiers != null;
|
|
24946
24989
|
const allowed = new Set(
|
|
24947
24990
|
(opts.issueIdentifiers ?? []).map((id) => {
|
|
24948
24991
|
try {
|
|
@@ -24952,36 +24995,27 @@ async function listGitHubIssueCommentsSince(opts) {
|
|
|
24952
24995
|
}
|
|
24953
24996
|
}).filter((n) => n != null)
|
|
24954
24997
|
);
|
|
24955
|
-
|
|
24956
|
-
const
|
|
24957
|
-
if (result.exitCode !== 0 || !result.stdout.trim()) return [];
|
|
24958
|
-
let parsed;
|
|
24959
|
-
try {
|
|
24960
|
-
parsed = JSON.parse(result.stdout);
|
|
24961
|
-
} catch {
|
|
24962
|
-
return [];
|
|
24963
|
-
}
|
|
24964
|
-
if (!Array.isArray(parsed)) return [];
|
|
24998
|
+
if (restrictToIssues && allowed.size === 0) return [];
|
|
24999
|
+
const pageSize = Math.min(GITHUB_ISSUE_COMMENTS_PAGE_SIZE, Math.max(1, limit));
|
|
24965
25000
|
const out = [];
|
|
24966
|
-
for (
|
|
24967
|
-
const
|
|
24968
|
-
|
|
24969
|
-
|
|
24970
|
-
|
|
24971
|
-
|
|
24972
|
-
|
|
24973
|
-
|
|
24974
|
-
|
|
24975
|
-
|
|
24976
|
-
|
|
24977
|
-
|
|
24978
|
-
|
|
24979
|
-
|
|
24980
|
-
|
|
24981
|
-
|
|
24982
|
-
|
|
24983
|
-
|
|
24984
|
-
if (out.length >= limit) break;
|
|
25001
|
+
for (let page = 1; page <= GITHUB_ISSUE_COMMENTS_MAX_PAGES; page++) {
|
|
25002
|
+
const path2 = `repos/${slug}/issues/comments?since=${encodeURIComponent(opts.since)}&sort=created&direction=desc&per_page=${pageSize}&page=${page}`;
|
|
25003
|
+
const result = await gh(["api", path2], cwd, { reject: false });
|
|
25004
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) break;
|
|
25005
|
+
let parsed;
|
|
25006
|
+
try {
|
|
25007
|
+
parsed = JSON.parse(result.stdout);
|
|
25008
|
+
} catch {
|
|
25009
|
+
break;
|
|
25010
|
+
}
|
|
25011
|
+
if (!Array.isArray(parsed) || parsed.length === 0) break;
|
|
25012
|
+
for (const item of parsed) {
|
|
25013
|
+
const comment = parseGitHubIssueCommentNode(item, restrictToIssues ? allowed : null);
|
|
25014
|
+
if (!comment) continue;
|
|
25015
|
+
out.push(comment);
|
|
25016
|
+
if (out.length >= limit) return out;
|
|
25017
|
+
}
|
|
25018
|
+
if (parsed.length < pageSize) break;
|
|
24985
25019
|
}
|
|
24986
25020
|
return out;
|
|
24987
25021
|
}
|
|
@@ -25195,20 +25229,19 @@ async function listIssues(repoPath, opts) {
|
|
|
25195
25229
|
const assignee = opts?.assignee?.trim() || void 0;
|
|
25196
25230
|
const since = opts?.updatedSince ? parseIssueSince(opts.updatedSince) : void 0;
|
|
25197
25231
|
if (source === "linear") {
|
|
25198
|
-
const
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25202
|
-
|
|
25203
|
-
|
|
25204
|
-
|
|
25205
|
-
since
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
|
|
25209
|
-
|
|
25210
|
-
|
|
25211
|
-
]);
|
|
25232
|
+
const listed = await listLinearIssuesFiltered({
|
|
25233
|
+
assignee,
|
|
25234
|
+
query,
|
|
25235
|
+
limit: opts?.limit,
|
|
25236
|
+
updatedSince: since
|
|
25237
|
+
});
|
|
25238
|
+
const comments2 = since ? await listLinearCommentsSince({
|
|
25239
|
+
since,
|
|
25240
|
+
assignee,
|
|
25241
|
+
query,
|
|
25242
|
+
issueIdentifiers: query ? listed.issues.map((issue) => issue.identifier) : void 0,
|
|
25243
|
+
limit: opts?.limit
|
|
25244
|
+
}) : void 0;
|
|
25212
25245
|
return {
|
|
25213
25246
|
source,
|
|
25214
25247
|
preferredSource,
|
|
@@ -26728,7 +26761,7 @@ function registerAbleTimeTools(server) {
|
|
|
26728
26761
|
);
|
|
26729
26762
|
server.tool(
|
|
26730
26763
|
"abletime_comment",
|
|
26731
|
-
"Add a markdown comment on an AbleTime task (id or CRM-232). When reviewing a PR or ticket, show the draft in chat and
|
|
26764
|
+
"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.",
|
|
26732
26765
|
{ id: import_zod4.z.string(), body: import_zod4.z.string() },
|
|
26733
26766
|
async (args) => {
|
|
26734
26767
|
try {
|
|
@@ -26740,7 +26773,7 @@ function registerAbleTimeTools(server) {
|
|
|
26740
26773
|
);
|
|
26741
26774
|
server.tool(
|
|
26742
26775
|
"abletime_update_task",
|
|
26743
|
-
"Update an AbleTime task (id or CRM-232). Pass title, description, and/or state. When reviewing a PR or ticket,
|
|
26776
|
+
"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.",
|
|
26744
26777
|
{
|
|
26745
26778
|
id: import_zod4.z.string(),
|
|
26746
26779
|
title: import_zod4.z.string().optional(),
|
|
@@ -26870,7 +26903,7 @@ function registerGithubIssueTools(server) {
|
|
|
26870
26903
|
);
|
|
26871
26904
|
server.tool(
|
|
26872
26905
|
"github_comment",
|
|
26873
|
-
"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
|
|
26906
|
+
"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.",
|
|
26874
26907
|
{ id: import_zod5.z.string(), body: import_zod5.z.string(), repoPath: repoPathSchema },
|
|
26875
26908
|
async ({ id, body, repoPath }) => {
|
|
26876
26909
|
try {
|
|
@@ -26882,7 +26915,7 @@ function registerGithubIssueTools(server) {
|
|
|
26882
26915
|
);
|
|
26883
26916
|
server.tool(
|
|
26884
26917
|
"github_update_issue",
|
|
26885
|
-
"Update a GitHub issue (#123). Pass title, body, and/or state (open|closed). When reviewing a PR or ticket,
|
|
26918
|
+
"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.",
|
|
26886
26919
|
{
|
|
26887
26920
|
id: import_zod5.z.string(),
|
|
26888
26921
|
title: import_zod5.z.string().optional(),
|
|
@@ -26955,20 +26988,19 @@ function registerLinearTools(server) {
|
|
|
26955
26988
|
try {
|
|
26956
26989
|
const page = clampMcpIssueLimit(limit);
|
|
26957
26990
|
const since = updatedSince ? parseIssueSince(updatedSince) : void 0;
|
|
26958
|
-
const
|
|
26959
|
-
|
|
26960
|
-
|
|
26961
|
-
|
|
26962
|
-
|
|
26963
|
-
|
|
26964
|
-
|
|
26965
|
-
since
|
|
26966
|
-
|
|
26967
|
-
|
|
26968
|
-
|
|
26969
|
-
|
|
26970
|
-
|
|
26971
|
-
]);
|
|
26991
|
+
const listed = await listLinearIssuesFiltered({
|
|
26992
|
+
query,
|
|
26993
|
+
assignee,
|
|
26994
|
+
limit: page + 1,
|
|
26995
|
+
updatedSince: since
|
|
26996
|
+
});
|
|
26997
|
+
const comments = since ? await listLinearCommentsSince({
|
|
26998
|
+
since,
|
|
26999
|
+
assignee,
|
|
27000
|
+
query,
|
|
27001
|
+
issueIdentifiers: query ? listed.issues.map((issue) => issue.identifier) : void 0,
|
|
27002
|
+
limit: page + 1
|
|
27003
|
+
}) : void 0;
|
|
26972
27004
|
return mcpJson(
|
|
26973
27005
|
formatListedIssuesForMcp(
|
|
26974
27006
|
{
|
|
@@ -27020,7 +27052,7 @@ function registerLinearTools(server) {
|
|
|
27020
27052
|
);
|
|
27021
27053
|
server.tool(
|
|
27022
27054
|
"linear_update_issue",
|
|
27023
|
-
"Update a Linear issue (uuid or ENG-123). Pass title, description, state, assignee, and/or priority. When reviewing a PR or ticket,
|
|
27055
|
+
"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.",
|
|
27024
27056
|
{
|
|
27025
27057
|
id: import_zod6.z.string(),
|
|
27026
27058
|
title: import_zod6.z.string().optional(),
|
|
@@ -27039,7 +27071,7 @@ function registerLinearTools(server) {
|
|
|
27039
27071
|
);
|
|
27040
27072
|
server.tool(
|
|
27041
27073
|
"linear_comment",
|
|
27042
|
-
"Add a markdown comment on a Linear issue (uuid or ENG-123). When reviewing a PR or ticket, show the draft in chat and
|
|
27074
|
+
"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.",
|
|
27043
27075
|
{
|
|
27044
27076
|
id: import_zod6.z.string(),
|
|
27045
27077
|
body: import_zod6.z.string()
|
|
@@ -28445,7 +28477,7 @@ async function startMcpServer() {
|
|
|
28445
28477
|
);
|
|
28446
28478
|
server.tool(
|
|
28447
28479
|
"request_review",
|
|
28448
|
-
'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.
|
|
28480
|
+
'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.',
|
|
28449
28481
|
{ ref: import_zod9.z.string().describe("Worktree thread id/ref to review") },
|
|
28450
28482
|
async ({ ref }) => {
|
|
28451
28483
|
try {
|
package/dist/index.d.cts
CHANGED
|
@@ -2213,13 +2213,10 @@ type LinearAssignedIssuesResult = {
|
|
|
2213
2213
|
};
|
|
2214
2214
|
/** `me`, `unassigned`, `all`, a Linear user id, or a display name. */
|
|
2215
2215
|
type LinearAssigneeFilter = string;
|
|
2216
|
-
/**
|
|
2217
|
-
* Linear `IssueFilter` for open issues. Default assignee is `me` so existing
|
|
2218
|
-
* Home / Create-from callers stay assigned-to-you unless they ask otherwise.
|
|
2219
|
-
*/
|
|
2220
2216
|
declare function buildLinearIssueFilter(input?: {
|
|
2221
2217
|
assignee?: string | null;
|
|
2222
2218
|
updatedSince?: string | null;
|
|
2219
|
+
query?: string | null;
|
|
2223
2220
|
}): Record<string, unknown>;
|
|
2224
2221
|
/**
|
|
2225
2222
|
* List or search open Linear issues. `assignee` is `me` (default when there is
|
|
@@ -2234,13 +2231,16 @@ declare function listLinearIssuesFiltered(opts?: {
|
|
|
2234
2231
|
updatedSince?: string | null;
|
|
2235
2232
|
}): Promise<LinearAssignedIssuesResult>;
|
|
2236
2233
|
/**
|
|
2237
|
-
* Comments created at/after `since` on issues matching the same assignee
|
|
2238
|
-
* One GraphQL query — do not get_issue each ticket to check for new comments.
|
|
2234
|
+
* Comments created at/after `since` on issues matching the same assignee / search
|
|
2235
|
+
* filter. One GraphQL query — do not get_issue each ticket to check for new comments.
|
|
2236
|
+
* Pass `issueIdentifiers` (search hits) to keep only those tickets; an empty
|
|
2237
|
+
* allowlist means no comments.
|
|
2239
2238
|
*/
|
|
2240
2239
|
declare function listLinearCommentsSince(opts: {
|
|
2241
2240
|
since: string;
|
|
2242
2241
|
assignee?: string | null;
|
|
2243
2242
|
query?: string;
|
|
2243
|
+
issueIdentifiers?: string[];
|
|
2244
2244
|
limit?: number;
|
|
2245
2245
|
apiKey?: string | null;
|
|
2246
2246
|
}): Promise<IssueActivityComment[]>;
|
|
@@ -2364,7 +2364,8 @@ declare function resolveGitHubIssueRepo(repoPath?: string | null): Promise<{
|
|
|
2364
2364
|
declare function toGitHubIssueInfo(issue: GitHubIssue): IssueInfo;
|
|
2365
2365
|
/**
|
|
2366
2366
|
* Repo issue comments created at/after `since`. Pass `issueIdentifiers` (#12)
|
|
2367
|
-
* to keep only comments on that inbox page —
|
|
2367
|
+
* to keep only comments on that inbox page — paginated REST, not N issue views.
|
|
2368
|
+
* An empty allowlist means no comments (do not fall through to the whole repo).
|
|
2368
2369
|
*/
|
|
2369
2370
|
declare function listGitHubIssueCommentsSince(opts: {
|
|
2370
2371
|
since: string;
|
|
@@ -4611,7 +4612,7 @@ declare function isSetupLastError(err: string | null | undefined): boolean;
|
|
|
4611
4612
|
declare function isStaleLastErrorDuringTurn(err: string | null | undefined): boolean;
|
|
4612
4613
|
|
|
4613
4614
|
/** Default Review request.md body (Conductor-style). Kept in sync with desktop review-request.ts. */
|
|
4614
|
-
declare const REVIEW_REQUEST_TEMPLATE = "# Review guidelines:\n\nYou are reviewing a proposed code change so a human can decide whether it is **ready to merge / land**. Findings matter, but the primary deliverable is a clear readiness recommendation \u2014 not a laundry list of style notes.\n\n## Required outcome\n\nStart your reply with a **Recommendation** section using exactly one of:\n\n- **Approve** \u2014 ready to merge as-is (or with only trivial nits the author can ignore).\n- **Approve with nits** \u2014 ready to merge; list only optional polish that should not block.\n- **Request changes** \u2014 not ready; blocking issues must be fixed first.\n- **Needs more information** \u2014 cannot judge readiness yet (missing context, incomplete diff, unclear intent).\n\nIn 1\u20133 sentences, say **why** \u2014 grounded in correctness, risk, test coverage, and scope \u2014 not vibes. If you request changes, name the blockers explicitly.\n\nPeople running this review are asking \u201Ccan we ship this?\u201D Treat that as the question you answer first.\n\n## Confirm before posting\n\nThe 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
|
|
4615
|
+
declare const REVIEW_REQUEST_TEMPLATE = "# Review guidelines:\n\nYou are reviewing a proposed code change so a human can decide whether it is **ready to merge / land**. Findings matter, but the primary deliverable is a clear readiness recommendation \u2014 not a laundry list of style notes.\n\n## Required outcome\n\nStart your reply with a **Recommendation** section using exactly one of:\n\n- **Approve** \u2014 ready to merge as-is (or with only trivial nits the author can ignore).\n- **Approve with nits** \u2014 ready to merge; list only optional polish that should not block.\n- **Request changes** \u2014 not ready; blocking issues must be fixed first.\n- **Needs more information** \u2014 cannot judge readiness yet (missing context, incomplete diff, unclear intent).\n\nIn 1\u20133 sentences, say **why** \u2014 grounded in correctness, risk, test coverage, and scope \u2014 not vibes. If you request changes, name the blockers explicitly.\n\nPeople running this review are asking \u201Ccan we ship this?\u201D Treat that as the question you answer first.\n\n## Confirm before posting\n\nThe 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.\n\nAfter 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.\n\nThe 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.\n\n## Findings\n\nBelow are guidelines for determining whether an issue is worth flagging to the original author.\n\nThese are not the final word. More specific guidelines elsewhere (developer message, user message, a file, etc.) override these.\n\nFlag something as a bug / blocking finding only when:\n\n1. It meaningfully impacts the accuracy, performance, security, or maintainability of the code.\n2. The bug is discrete and actionable (not a vague codebase-wide complaint or a bundle of unrelated issues).\n3. Fixing it does not demand rigor absent from the rest of the codebase.\n4. The issue was introduced by this change (do not flag pre-existing bugs unless they are newly exposed by this PR).\n5. The author would likely fix it if made aware.\n6. It does not rely on unstated assumptions about the codebase or author intent.\n7. Speculative breakage is not enough \u2014 identify the other code that is provably affected.\n8. It is clearly not just an intentional change by the author.\n\nWhen flagging an issue, include a short accompanying comment:\n\n1. Clear about why it is a problem.\n2. Severity must match reality \u2014 do not inflate.\n3. Brief: at most one paragraph; avoid unnecessary line breaks in prose.\n4. No code chunks longer than 3 lines; wrap code in inline ticks or a fenced block.\n5. Call out scenarios / environments / inputs needed to hit the bug when severity depends on them.\n6. Matter-of-fact tone \u2014 helpful assistant, not accusatory or effusive.\n7. Skimmable on first read.\n8. No empty flattery (\u201CGreat job\u2026\u201D, \u201CThanks for\u2026\u201D).\n\nHOW MANY FINDINGS TO RETURN:\n\nList every finding the author would fix if they knew about it. If nothing qualifies, say so and still give the Recommendation. Do not stop at the first finding.\n\nGUIDELINES:\n\n- Ignore trivial style unless it obscures meaning or violates documented standards.\n- One comment per distinct issue (or a short multi-line range if needed).\n- Use ```suggestion blocks ONLY for concrete replacement code (minimal lines; no commentary inside the block).\n- In every ```suggestion block, preserve the exact leading whitespace of the replaced lines (spaces vs tabs, number of spaces).\n- Do NOT introduce or remove outer indentation levels unless that is the actual fix.\n- Separate **blocking** findings from **nits**. Only blocking findings should drive Request changes.\n\nThe report appears in chat (and can become Sideboard diff comments). Avoid unnecessary location chatter in the body; keep line ranges as short as possible (prefer \u22645\u201310 lines).\n\n## Getting the diff\n\nUse Sideboard's diff for this thread's worktree. Prefer the `get_diff` MCP tool (pass this thread's ref) for a compact summary, then read specific files with Read/Glob as needed. In the Sideboard desktop app, the Changes panel shows the same worktree diff.\n\nIf the user asks you to address or read line comments they added in the Changes / file diff UI, those arrive as `diff-comment` attachments on the next turn \u2014 follow them precisely.\n\n## Fallback: if you don't have access to the Sideboard diff tool\n\nIf you don't have access to `get_diff`, use the following git commands to get the diff:\n\n```bash\n# Get the merge base between this branch and the target\nMERGE_BASE=$(git merge-base origin/main HEAD)\n\n# Get the committed diff against the merge base\ngit diff $MERGE_BASE HEAD\n\n# Get any uncommitted changes (staged and unstaged)\ngit diff HEAD\n```\n\nReview the combination of both outputs: the first shows all committed changes on this branch relative to the target, and the second shows any uncommitted work in progress.\n\nNo need to mention in your report whether or not you used one of the fallback strategies; it's usually irrelevant.\n\n## Output format\n\n**1. Recommendation first** (required), then **2. Findings** (may be empty).\n\nOnly report ONE finding per unique issue.\n\n<example>\n## Recommendation\n\n**Request changes** \u2014 The empty-input crash on load will break first-run users; fix that before merge. The unused helper is a nit and can wait.\n\n## Findings\n\n### **#1 Empty input causes crash** (blocking)\n\nIf the input field is empty when the page loads, the app will crash.\n\nFile: src/client/frontends/desktop/ui/Input.tsx\n\n### **#2 Dead code** (nit)\n\nThe getUserData function is now unused. It should be deleted.\n\nFile: src/client/frontends/desktop/core/UserData.ts\n</example>\n\n<example>\n## Recommendation\n\n**Approve** \u2014 Diff is scoped, behavior looks correct, and there are no blocking issues. Safe to merge.\n</example>\n\n## Growing the rules\n\nIf a blocking issue is a missing or ambiguous repo rule that will recur, add one sentence to `.claude/skills/review/SKILL.md` when that skill already exists. Otherwise write it to `.context/review.md` (do not create a review skill). Do not only patch this diff when the same miss will happen again. Do not write new skills under `.sideboard/skills/`.\n";
|
|
4615
4616
|
/** Committed Claude Code project skill — Review attaches this when present. */
|
|
4616
4617
|
declare const REVIEW_SKILL_PATH = ".claude/skills/review/SKILL.md";
|
|
4617
4618
|
declare const REVIEW_SKILL_NAME = "review";
|
package/dist/index.d.ts
CHANGED
|
@@ -2213,13 +2213,10 @@ type LinearAssignedIssuesResult = {
|
|
|
2213
2213
|
};
|
|
2214
2214
|
/** `me`, `unassigned`, `all`, a Linear user id, or a display name. */
|
|
2215
2215
|
type LinearAssigneeFilter = string;
|
|
2216
|
-
/**
|
|
2217
|
-
* Linear `IssueFilter` for open issues. Default assignee is `me` so existing
|
|
2218
|
-
* Home / Create-from callers stay assigned-to-you unless they ask otherwise.
|
|
2219
|
-
*/
|
|
2220
2216
|
declare function buildLinearIssueFilter(input?: {
|
|
2221
2217
|
assignee?: string | null;
|
|
2222
2218
|
updatedSince?: string | null;
|
|
2219
|
+
query?: string | null;
|
|
2223
2220
|
}): Record<string, unknown>;
|
|
2224
2221
|
/**
|
|
2225
2222
|
* List or search open Linear issues. `assignee` is `me` (default when there is
|
|
@@ -2234,13 +2231,16 @@ declare function listLinearIssuesFiltered(opts?: {
|
|
|
2234
2231
|
updatedSince?: string | null;
|
|
2235
2232
|
}): Promise<LinearAssignedIssuesResult>;
|
|
2236
2233
|
/**
|
|
2237
|
-
* Comments created at/after `since` on issues matching the same assignee
|
|
2238
|
-
* One GraphQL query — do not get_issue each ticket to check for new comments.
|
|
2234
|
+
* Comments created at/after `since` on issues matching the same assignee / search
|
|
2235
|
+
* filter. One GraphQL query — do not get_issue each ticket to check for new comments.
|
|
2236
|
+
* Pass `issueIdentifiers` (search hits) to keep only those tickets; an empty
|
|
2237
|
+
* allowlist means no comments.
|
|
2239
2238
|
*/
|
|
2240
2239
|
declare function listLinearCommentsSince(opts: {
|
|
2241
2240
|
since: string;
|
|
2242
2241
|
assignee?: string | null;
|
|
2243
2242
|
query?: string;
|
|
2243
|
+
issueIdentifiers?: string[];
|
|
2244
2244
|
limit?: number;
|
|
2245
2245
|
apiKey?: string | null;
|
|
2246
2246
|
}): Promise<IssueActivityComment[]>;
|
|
@@ -2364,7 +2364,8 @@ declare function resolveGitHubIssueRepo(repoPath?: string | null): Promise<{
|
|
|
2364
2364
|
declare function toGitHubIssueInfo(issue: GitHubIssue): IssueInfo;
|
|
2365
2365
|
/**
|
|
2366
2366
|
* Repo issue comments created at/after `since`. Pass `issueIdentifiers` (#12)
|
|
2367
|
-
* to keep only comments on that inbox page —
|
|
2367
|
+
* to keep only comments on that inbox page — paginated REST, not N issue views.
|
|
2368
|
+
* An empty allowlist means no comments (do not fall through to the whole repo).
|
|
2368
2369
|
*/
|
|
2369
2370
|
declare function listGitHubIssueCommentsSince(opts: {
|
|
2370
2371
|
since: string;
|
|
@@ -4611,7 +4612,7 @@ declare function isSetupLastError(err: string | null | undefined): boolean;
|
|
|
4611
4612
|
declare function isStaleLastErrorDuringTurn(err: string | null | undefined): boolean;
|
|
4612
4613
|
|
|
4613
4614
|
/** Default Review request.md body (Conductor-style). Kept in sync with desktop review-request.ts. */
|
|
4614
|
-
declare const REVIEW_REQUEST_TEMPLATE = "# Review guidelines:\n\nYou are reviewing a proposed code change so a human can decide whether it is **ready to merge / land**. Findings matter, but the primary deliverable is a clear readiness recommendation \u2014 not a laundry list of style notes.\n\n## Required outcome\n\nStart your reply with a **Recommendation** section using exactly one of:\n\n- **Approve** \u2014 ready to merge as-is (or with only trivial nits the author can ignore).\n- **Approve with nits** \u2014 ready to merge; list only optional polish that should not block.\n- **Request changes** \u2014 not ready; blocking issues must be fixed first.\n- **Needs more information** \u2014 cannot judge readiness yet (missing context, incomplete diff, unclear intent).\n\nIn 1\u20133 sentences, say **why** \u2014 grounded in correctness, risk, test coverage, and scope \u2014 not vibes. If you request changes, name the blockers explicitly.\n\nPeople running this review are asking \u201Ccan we ship this?\u201D Treat that as the question you answer first.\n\n## Confirm before posting\n\nThe 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
|
|
4615
|
+
declare const REVIEW_REQUEST_TEMPLATE = "# Review guidelines:\n\nYou are reviewing a proposed code change so a human can decide whether it is **ready to merge / land**. Findings matter, but the primary deliverable is a clear readiness recommendation \u2014 not a laundry list of style notes.\n\n## Required outcome\n\nStart your reply with a **Recommendation** section using exactly one of:\n\n- **Approve** \u2014 ready to merge as-is (or with only trivial nits the author can ignore).\n- **Approve with nits** \u2014 ready to merge; list only optional polish that should not block.\n- **Request changes** \u2014 not ready; blocking issues must be fixed first.\n- **Needs more information** \u2014 cannot judge readiness yet (missing context, incomplete diff, unclear intent).\n\nIn 1\u20133 sentences, say **why** \u2014 grounded in correctness, risk, test coverage, and scope \u2014 not vibes. If you request changes, name the blockers explicitly.\n\nPeople running this review are asking \u201Ccan we ship this?\u201D Treat that as the question you answer first.\n\n## Confirm before posting\n\nThe 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.\n\nAfter 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.\n\nThe 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.\n\n## Findings\n\nBelow are guidelines for determining whether an issue is worth flagging to the original author.\n\nThese are not the final word. More specific guidelines elsewhere (developer message, user message, a file, etc.) override these.\n\nFlag something as a bug / blocking finding only when:\n\n1. It meaningfully impacts the accuracy, performance, security, or maintainability of the code.\n2. The bug is discrete and actionable (not a vague codebase-wide complaint or a bundle of unrelated issues).\n3. Fixing it does not demand rigor absent from the rest of the codebase.\n4. The issue was introduced by this change (do not flag pre-existing bugs unless they are newly exposed by this PR).\n5. The author would likely fix it if made aware.\n6. It does not rely on unstated assumptions about the codebase or author intent.\n7. Speculative breakage is not enough \u2014 identify the other code that is provably affected.\n8. It is clearly not just an intentional change by the author.\n\nWhen flagging an issue, include a short accompanying comment:\n\n1. Clear about why it is a problem.\n2. Severity must match reality \u2014 do not inflate.\n3. Brief: at most one paragraph; avoid unnecessary line breaks in prose.\n4. No code chunks longer than 3 lines; wrap code in inline ticks or a fenced block.\n5. Call out scenarios / environments / inputs needed to hit the bug when severity depends on them.\n6. Matter-of-fact tone \u2014 helpful assistant, not accusatory or effusive.\n7. Skimmable on first read.\n8. No empty flattery (\u201CGreat job\u2026\u201D, \u201CThanks for\u2026\u201D).\n\nHOW MANY FINDINGS TO RETURN:\n\nList every finding the author would fix if they knew about it. If nothing qualifies, say so and still give the Recommendation. Do not stop at the first finding.\n\nGUIDELINES:\n\n- Ignore trivial style unless it obscures meaning or violates documented standards.\n- One comment per distinct issue (or a short multi-line range if needed).\n- Use ```suggestion blocks ONLY for concrete replacement code (minimal lines; no commentary inside the block).\n- In every ```suggestion block, preserve the exact leading whitespace of the replaced lines (spaces vs tabs, number of spaces).\n- Do NOT introduce or remove outer indentation levels unless that is the actual fix.\n- Separate **blocking** findings from **nits**. Only blocking findings should drive Request changes.\n\nThe report appears in chat (and can become Sideboard diff comments). Avoid unnecessary location chatter in the body; keep line ranges as short as possible (prefer \u22645\u201310 lines).\n\n## Getting the diff\n\nUse Sideboard's diff for this thread's worktree. Prefer the `get_diff` MCP tool (pass this thread's ref) for a compact summary, then read specific files with Read/Glob as needed. In the Sideboard desktop app, the Changes panel shows the same worktree diff.\n\nIf the user asks you to address or read line comments they added in the Changes / file diff UI, those arrive as `diff-comment` attachments on the next turn \u2014 follow them precisely.\n\n## Fallback: if you don't have access to the Sideboard diff tool\n\nIf you don't have access to `get_diff`, use the following git commands to get the diff:\n\n```bash\n# Get the merge base between this branch and the target\nMERGE_BASE=$(git merge-base origin/main HEAD)\n\n# Get the committed diff against the merge base\ngit diff $MERGE_BASE HEAD\n\n# Get any uncommitted changes (staged and unstaged)\ngit diff HEAD\n```\n\nReview the combination of both outputs: the first shows all committed changes on this branch relative to the target, and the second shows any uncommitted work in progress.\n\nNo need to mention in your report whether or not you used one of the fallback strategies; it's usually irrelevant.\n\n## Output format\n\n**1. Recommendation first** (required), then **2. Findings** (may be empty).\n\nOnly report ONE finding per unique issue.\n\n<example>\n## Recommendation\n\n**Request changes** \u2014 The empty-input crash on load will break first-run users; fix that before merge. The unused helper is a nit and can wait.\n\n## Findings\n\n### **#1 Empty input causes crash** (blocking)\n\nIf the input field is empty when the page loads, the app will crash.\n\nFile: src/client/frontends/desktop/ui/Input.tsx\n\n### **#2 Dead code** (nit)\n\nThe getUserData function is now unused. It should be deleted.\n\nFile: src/client/frontends/desktop/core/UserData.ts\n</example>\n\n<example>\n## Recommendation\n\n**Approve** \u2014 Diff is scoped, behavior looks correct, and there are no blocking issues. Safe to merge.\n</example>\n\n## Growing the rules\n\nIf a blocking issue is a missing or ambiguous repo rule that will recur, add one sentence to `.claude/skills/review/SKILL.md` when that skill already exists. Otherwise write it to `.context/review.md` (do not create a review skill). Do not only patch this diff when the same miss will happen again. Do not write new skills under `.sideboard/skills/`.\n";
|
|
4615
4616
|
/** Committed Claude Code project skill — Review attaches this when present. */
|
|
4616
4617
|
declare const REVIEW_SKILL_PATH = ".claude/skills/review/SKILL.md";
|
|
4617
4618
|
declare const REVIEW_SKILL_NAME = "review";
|