@sideboard-ai/core 0.1.151 → 0.1.152

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/{agents-JAOMXDXN.js → agents-CUKWIM34.js} +3 -3
  2. package/dist/{agents-U2JCFXW4.js → agents-VHXCBBBD.js} +3 -3
  3. package/dist/{chunk-77MP647F.js → chunk-2U6QF3PT.js} +6 -5
  4. package/dist/{chunk-TSCWSAQL.js → chunk-67TIJ7S5.js} +1 -1
  5. package/dist/{chunk-6H4TJ5TA.js → chunk-6X7Z34XE.js} +95 -50
  6. package/dist/{chunk-GCWAAPJ5.js → chunk-7BQNSUR2.js} +86 -65
  7. package/dist/{chunk-OXOU2FRS.js → chunk-7TIUOYBK.js} +6 -5
  8. package/dist/{chunk-LZAOX76N.js → chunk-EY6QXPPO.js} +2 -2
  9. package/dist/{chunk-ADCEGG4A.js → chunk-G4MTYUWS.js} +1 -1
  10. package/dist/{chunk-UIS7BVCX.js → chunk-GFQ57XAX.js} +2 -2
  11. package/dist/{chunk-HWZWBJWL.js → chunk-K2ANSHUO.js} +1 -1
  12. package/dist/{chunk-Y2FNDKHF.js → chunk-SN6CMKF6.js} +1 -1
  13. package/dist/{coordinator-prompt-ZK5MII7W.js → coordinator-prompt-TBX4MOFM.js} +1 -1
  14. package/dist/{coordinator-prompt-LWYUZAXR.js → coordinator-prompt-WGFRYCHE.js} +1 -1
  15. package/dist/{global-workspace-T7RL3XEC.js → global-workspace-BHLUJ46D.js} +2 -2
  16. package/dist/{global-workspace-IB2CCEJF.js → global-workspace-IY5QAV5C.js} +2 -2
  17. package/dist/index.cjs +112 -47
  18. package/dist/index.d.cts +34 -20
  19. package/dist/index.d.ts +34 -20
  20. package/dist/index.js +29 -7
  21. package/dist/mcp/run-stdio.cjs +101 -63
  22. package/dist/mcp/run-stdio.js +23 -7
  23. package/dist/{orchestrator-Y5MWUU7C.js → orchestrator-256DFPSX.js} +5 -5
  24. package/dist/{orchestrator-DPTRBKEH.js → orchestrator-NUA6SEV7.js} +5 -5
  25. package/dist/{workspaces-ZXCUVCZC.js → workspaces-4FSXVIZM.js} +3 -3
  26. package/dist/{workspaces-VICQYI2N.js → workspaces-NECIQTAO.js} +3 -3
  27. package/package.json +1 -1
@@ -6743,7 +6743,7 @@ function ensureGlobalCoordinatorCwd(opts) {
6743
6743
  "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).",
6744
6744
  "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.",
6745
6745
  "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.",
6746
- "Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
6746
+ "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."
6747
6747
  ].join("\n");
6748
6748
  try {
6749
6749
  (0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
@@ -6823,15 +6823,16 @@ var init_coordinator_prompt = __esm({
6823
6823
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
6824
6824
  "Inspect / review / PRs:",
6825
6825
  "- get_diff \u2014 compact diff summary",
6826
- '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else seeds that skill / local guidelines; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
6827
- "- ask_git \u2014 commit & push, open a draft PR, 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.",
6826
+ "- 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.",
6827
+ '- 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',
6828
+ "- ask_git \u2014 commit & push, open a draft PR, 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.",
6828
6829
  '- 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.',
6829
6830
  '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "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.',
6830
6831
  "Process guides:",
6831
6832
  "- Long child jobs (pack, test, deploy, anything that may run more than ~30s): workers always have `/long-running` (Sideboard product skill). Tell them to detach and wait; do not ask the human to poll.",
6832
6833
  "- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
6833
- "- Recurring shapes: have the worktree agent write `.claude/skills/<kebab-name>/SKILL.md` (commit it) so later threads and native Claude Code / attach see it. Merge-review sentences go in `.claude/skills/review/SKILL.md` (create it \u2014 that is allowed). Do not use `.sideboard/skills/` (that folder only). Codex/OpenCode: one line in AGENTS.md pointing at that file.",
6834
- "- One-offs: no guide. Same miss across threads: edit the skill or `.claude/skills/review/SKILL.md`, then rerun the batch \u2014 do not patch three threads.",
6834
+ "- Recurring shapes: have the worktree agent write `.claude/skills/<kebab-name>/SKILL.md` (commit it) so later threads and native Claude Code / attach see it. Merge-review sentences go in `.claude/skills/review/SKILL.md` when that skill already exists; otherwise `.context/review.md` (do not create a review skill). Do not use `.sideboard/skills/` (that folder only). Codex/OpenCode: one line in AGENTS.md pointing at that file.",
6835
+ "- One-offs: no guide. Same miss across threads: edit the existing skill or `.context/review.md`, then rerun the batch \u2014 do not patch three threads.",
6835
6836
  "Human-only (do not attempt): ready-for-review land (confirm_land), purge_thread.",
6836
6837
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
6837
6838
  "Bash / Read / etc: allowed for (1) inspecting target worktrees / registered repo paths from MCP, and (2) greenfield setup under ~/sideboard/repos (git clone, gh repo create, git init+remote). Never git init/clone *inside* this synthetic home cwd \u2014 emptiness here is expected, not a bug."
@@ -12110,17 +12111,7 @@ var init_chat_tabs = __esm({
12110
12111
  });
12111
12112
 
12112
12113
  // src/review/review-request-template.ts
12113
- function wrapReviewSkillMarkdown(body) {
12114
- const trimmed = body.replace(/^\uFEFF/, "").trim();
12115
- const source = trimmed || REVIEW_REQUEST_TEMPLATE.trim();
12116
- if (/^---\s*\n[\s\S]*?\n---\s*\n/.test(source)) {
12117
- return source.endsWith("\n") ? source : `${source}
12118
- `;
12119
- }
12120
- return `${REVIEW_SKILL_FRONTMATTER}${source}
12121
- `;
12122
- }
12123
- var REVIEW_REQUEST_TEMPLATE, REVIEW_SKILL_PATH, REVIEW_SKILL_NAME, REVIEW_SKILL_FRONTMATTER;
12114
+ var REVIEW_REQUEST_TEMPLATE, REVIEW_SKILL_PATH, REVIEW_SKILL_NAME;
12124
12115
  var init_review_request_template = __esm({
12125
12116
  "src/review/review-request-template.ts"() {
12126
12117
  "use strict";
@@ -12243,18 +12234,10 @@ File: src/client/frontends/desktop/core/UserData.ts
12243
12234
 
12244
12235
  ## Growing the rules
12245
12236
 
12246
- If a blocking issue is a missing or ambiguous repo rule that will recur, add one sentence to \`.claude/skills/review/SKILL.md\` (create the skill if it is missing \u2014 that is allowed and should be committed). Do not only patch this diff when the same miss will happen again. Do not write new skills under \`.sideboard/skills/\`. Do not use \`.sideboard/review.md\` for new notes.
12237
+ If 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/\`.
12247
12238
  `;
12248
12239
  REVIEW_SKILL_PATH = ".claude/skills/review/SKILL.md";
12249
12240
  REVIEW_SKILL_NAME = "review";
12250
- REVIEW_SKILL_FRONTMATTER = `---
12251
- name: review
12252
- description: >-
12253
- Merge-readiness review for this repository. Use when reviewing a PR, worktree
12254
- diff, or Sideboard Review (Approve / Approve with nits / Request changes).
12255
- ---
12256
-
12257
- `;
12258
12241
  }
12259
12242
  });
12260
12243
 
@@ -12297,37 +12280,57 @@ function skillGuidelines(content, source) {
12297
12280
  source
12298
12281
  };
12299
12282
  }
12300
- function ensureReviewSkillFile(worktreePath) {
12301
- const abs = (0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH);
12302
- const existing = readTextIfPresent(abs);
12303
- if (existing) {
12304
- return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
12305
- }
12306
- const fromRepo = readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH));
12307
- const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
12308
- const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
12309
- (0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(abs), { recursive: true });
12310
- (0, import_node_fs29.writeFileSync)(abs, content, "utf8");
12311
- return { path: REVIEW_SKILL_PATH, content, wrote: true };
12283
+ function contextGuidelines(content, source) {
12284
+ return {
12285
+ path: CONTEXT_REVIEW_PATH,
12286
+ name: REPO_REVIEW_NAME,
12287
+ content,
12288
+ source
12289
+ };
12312
12290
  }
12313
- function resolveReviewGuidelines(worktreePath) {
12291
+ function writeContextGuidelines(worktreePath, content) {
12292
+ const abs = (0, import_node_path29.join)(worktreePath, CONTEXT_REVIEW_PATH);
12293
+ (0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(abs), { recursive: true });
12294
+ const body = content.endsWith("\n") ? content : `${content}
12295
+ `;
12296
+ (0, import_node_fs29.writeFileSync)(abs, body, "utf8");
12297
+ return body;
12298
+ }
12299
+ function readSideboardReview(worktreePath, repoPath) {
12300
+ const fromWorktree = readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH));
12301
+ if (fromWorktree) return fromWorktree;
12302
+ const repo = repoPath?.replace(/\/+$/, "");
12303
+ const wt = worktreePath.replace(/\/+$/, "");
12304
+ if (!repo || repo === wt) return null;
12305
+ return readTextIfPresent((0, import_node_path29.join)(repo, REPO_REVIEW_PATH));
12306
+ }
12307
+ function ensureReviewGuidelinesFile(worktreePath, repoPath) {
12314
12308
  const skillContent = readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH));
12315
- if (skillContent) return skillGuidelines(skillContent, "skill");
12316
- const local = readLocalGuidelines(worktreePath);
12317
- if (local) {
12318
- return {
12319
- path: local.path,
12320
- name: REVIEW_REQUEST_NAME,
12321
- content: local.content,
12322
- source: "local"
12323
- };
12309
+ if (skillContent) {
12310
+ return { ...skillGuidelines(skillContent, "skill"), wrote: false };
12311
+ }
12312
+ const contextContent = readTextIfPresent((0, import_node_path29.join)(worktreePath, CONTEXT_REVIEW_PATH));
12313
+ if (contextContent && !shouldRefreshReviewRequestTemplate(contextContent)) {
12314
+ return { ...contextGuidelines(contextContent, "local"), wrote: false };
12315
+ }
12316
+ const fromSideboard = readSideboardReview(worktreePath, repoPath);
12317
+ if (fromSideboard && !shouldRefreshReviewRequestTemplate(fromSideboard)) {
12318
+ const body2 = writeContextGuidelines(worktreePath, fromSideboard);
12319
+ return { ...contextGuidelines(body2, "repo"), wrote: true };
12324
12320
  }
12325
- const seeded = ensureReviewSkillFile(worktreePath);
12326
- return skillGuidelines(seeded.content, seeded.wrote ? "stock" : "skill");
12321
+ const local = readLocalGuidelines(worktreePath);
12322
+ const body = writeContextGuidelines(worktreePath, local?.content ?? REVIEW_REQUEST_TEMPLATE);
12323
+ return {
12324
+ ...contextGuidelines(body, local ? "local" : "stock"),
12325
+ wrote: true
12326
+ };
12327
+ }
12328
+ function resolveReviewGuidelines(worktreePath, repoPath) {
12329
+ return ensureReviewGuidelinesFile(worktreePath, repoPath);
12327
12330
  }
12328
12331
  function buildReviewRequestAttachment(content, opts) {
12329
12332
  const path = opts?.path ?? REVIEW_SKILL_PATH;
12330
- const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
12333
+ const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH || path === CONTEXT_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
12331
12334
  return {
12332
12335
  id: (0, import_node_crypto7.randomUUID)(),
12333
12336
  name,
@@ -12347,7 +12350,7 @@ async function requestReview(threadRef, send) {
12347
12350
  if (from.status === "archived") {
12348
12351
  throw new Error(`Thread is archived: ${from.id}`);
12349
12352
  }
12350
- const guidelines = resolveReviewGuidelines(from.worktreePath);
12353
+ const guidelines = resolveReviewGuidelines(from.worktreePath, from.repoPath);
12351
12354
  const tab = createChatTab({
12352
12355
  fromThreadId: from.id,
12353
12356
  title: "Review",
@@ -12361,7 +12364,7 @@ async function requestReview(threadRef, send) {
12361
12364
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
12362
12365
  return { tab: started, from };
12363
12366
  }
12364
- var import_node_crypto7, import_node_fs29, import_node_path29, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
12367
+ var import_node_crypto7, import_node_fs29, import_node_path29, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
12365
12368
  var init_request_review = __esm({
12366
12369
  "src/review/request-review.ts"() {
12367
12370
  "use strict";
@@ -12375,6 +12378,7 @@ var init_request_review = __esm({
12375
12378
  init_workspace_scratch();
12376
12379
  REPO_REVIEW_PATH = ".sideboard/review.md";
12377
12380
  REPO_REVIEW_NAME = "review.md";
12381
+ CONTEXT_REVIEW_PATH = ".context/review.md";
12378
12382
  REVIEW_REQUEST_PATH = `${ATTACHMENTS_DIR}/Review request.md`;
12379
12383
  LEGACY_REVIEW_REQUEST_PATH = `${LEGACY_ATTACHMENTS_DIR}/Review request.md`;
12380
12384
  REVIEW_REQUEST_NAME = "Review request.md";
@@ -12628,11 +12632,9 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
12628
12632
  }
12629
12633
  async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
12630
12634
  await ensureWorktreeSideboardIgnored(worktreePath);
12631
- const reviewSkill = ensureReviewSkillFile(worktreePath);
12632
- if (reviewSkill.wrote) {
12633
- onLine?.(
12634
- `[setup] wrote ${REVIEW_SKILL_PATH} \u2014 commit it so later worktrees inherit Review guidelines`
12635
- );
12635
+ const review = ensureReviewGuidelinesFile(worktreePath, repoPath);
12636
+ if (review.wrote) {
12637
+ onLine?.(`[setup] wrote ${review.path} \u2014 local Review guidelines`);
12636
12638
  }
12637
12639
  let setup = await runSetupScript(repoPath, worktreePath, onLine, opts);
12638
12640
  if (!setup.ran) {
@@ -16218,6 +16220,16 @@ node <detached-job.js> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
16218
16220
  4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
16219
16221
 
16220
16222
  Never tell the user \u201Csay status when it\u2019s done.\u201D You wait.
16223
+
16224
+ ## PR checks (only if a goal is given)
16225
+
16226
+ Do **not** watch after every push. If the user gave a goal (Greptile 5/5, CI green, until checks pass), wait the same way:
16227
+
16228
+ \`\`\`bash
16229
+ node <detached-job.js> start pr-checks -- gh pr checks --watch
16230
+ \`\`\`
16231
+
16232
+ On miss, fix, commit, push, and watch again until the goal is met or you are blocked. Do not ask the human to poll. Do not merge unless asked.
16221
16233
  `;
16222
16234
  }
16223
16235
  });
@@ -16607,7 +16619,7 @@ function formatWorktreeDirective(thread, opts) {
16607
16619
  "Short git requests from the Sideboard UI are complete instructions \u2014 expand them using the rules above without asking for clarification:"
16608
16620
  );
16609
16621
  lines.push(
16610
- '- "Commit and push." \u2192 commit any uncommitted work with a purpose-stating message, then push to origin (updates an existing PR if one is linked).'
16622
+ '- "Commit and push." \u2192 commit any uncommitted work with a purpose-stating message, then push to origin (updates an existing PR if one is linked). Do not start a checks loop unless they gave a goal.'
16611
16623
  );
16612
16624
  lines.push(
16613
16625
  '- "Commit, push, and open a draft PR." \u2192 commit, push, then create a draft PR with `gh pr create --draft -R \u2026` (title/body from the change purpose).'
@@ -16616,7 +16628,7 @@ function formatWorktreeDirective(thread, opts) {
16616
16628
  '- "Commit, push, and open a PR in the browser." \u2192 commit, push, then `gh pr create --web -R \u2026`.'
16617
16629
  );
16618
16630
  lines.push(
16619
- '- "Fix CI: <name>." \u2192 investigate that failing check, fix it, commit, and push.'
16631
+ '- "Fix CI: <name>." \u2192 investigate that failing check, fix it, commit, and push. Loop only if they gave a goal to keep going until it passes.'
16620
16632
  );
16621
16633
  lines.push(
16622
16634
  '- "Merge the remote branch (<base>) into your branch and resolve conflicts. Then, commit and push your changes." \u2192 fetch the PR base, merge it into this branch, resolve conflicts carefully, commit, and push until the PR is mergeable.'
@@ -16628,11 +16640,21 @@ function formatWorktreeDirective(thread, opts) {
16628
16640
  '- "Merge PR." \u2192 merge this thread\'s open pull request on GitHub (this phrase is the explicit ask). If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.'
16629
16641
  );
16630
16642
  lines.push("");
16643
+ lines.push(formatPrGateDirective());
16644
+ lines.push("");
16631
16645
  lines.push(formatProcessGuideDirective());
16632
16646
  return lines.join("\n");
16633
16647
  }
16634
16648
  function formatWorktreeReminder() {
16635
- return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout.";
16649
+ return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push.";
16650
+ }
16651
+ function formatPrGateDirective() {
16652
+ return [
16653
+ "If a goal is given (not after every push):",
16654
+ "- Enter a watch-fix-push loop and stay in it until that goal is met or you are blocked (examples: \u201CGreptile 5/5\u201D, \u201CCI green\u201D, \u201Cuntil checks pass\u201D). Do not stop after one red run or one review cycle.",
16655
+ "- Wait with `/long-running`: `gh pr checks --watch` (add `-R <origin>` when needed). Present the log. Do not ask the human to poll.",
16656
+ "- Greptile 5/5: wait for the greptile check; read the latest `N/5` from the PR body or Greptile\u2019s most recently *updated* issue comment; also fetch unresolved review comments / the \u201CPrompt to fix all with AI\u201D block. Done = **5/5 and zero unresolved Greptile comments**. If Greptile is idle, comment `@greptile review`. Cap about 5 iterations, then report leftovers. Do not merge unless asked."
16657
+ ].join("\n");
16636
16658
  }
16637
16659
  function formatProcessGuideDirective() {
16638
16660
  return [
@@ -16640,7 +16662,7 @@ function formatProcessGuideDirective() {
16640
16662
  "- Long jobs (pack, test, deploy, anything that may run more than ~30s): Sideboard always provides `/long-running`. Detach and wait \u2014 do not ask the human to poll.",
16641
16663
  "- If `.claude/skills/graph-engineering/SKILL.md` exists, follow it (`/graph-engineering`) for migrations, ports, batch fixes, and other fan-out. Judge first; state on disk; grow the rulebook; do not patch around it.",
16642
16664
  "- If this same shape of work will happen again, write `.claude/skills/<kebab-name>/SKILL.md` in this worktree (Claude Code project skill). Sideboard `/name`, Claude Code, and `attach` all load that path. Do not leave the method only in chat.",
16643
- "- Merge-readiness notes: create or edit `.claude/skills/review/SKILL.md` and commit it. That file is allowed. Do not use `.sideboard/review.md` for new notes (legacy; setup copies it into the skill).",
16665
+ "- Merge-readiness notes: if `.claude/skills/review/SKILL.md` already exists, edit it. Otherwise write them to `.context/review.md` (copied from `.sideboard/review.md` when that file exists). Do not create a review skill.",
16644
16666
  "- Do not write new skills under `.sideboard/skills/` (that folder only \u2014 other `.sideboard/` files such as settings.toml are fine). Point Codex/OpenCode at the Claude skill from `AGENTS.md`. Optional: symlink `.cursor/skills/<name>` to the Claude skill.",
16645
16667
  "- Skip a guide for a one-off. If a matching skill exists, follow it. Same miss twice \u2192 edit the skill, do not patch around it."
16646
16668
  ].join("\n");
@@ -22505,9 +22527,25 @@ async function startMcpServer() {
22505
22527
  };
22506
22528
  }
22507
22529
  );
22530
+ server.tool(
22531
+ "get_pr_checks",
22532
+ "Snapshot of GitHub PR checks for a worktree thread (`gh pr checks` plus merge/review gates). null = no PR. If the user gave a goal (Greptile 5/5, CI green), the worktree agent watches with `gh pr checks --watch` via /long-running \u2014 this tool is a snapshot, not a waiter. Coordinators: do not run gh from the orchestration cwd.",
22533
+ { ref: import_zod5.z.string().describe("Worktree thread id/ref") },
22534
+ async ({ ref }) => {
22535
+ try {
22536
+ const checks = await orch.getPrChecks(ref);
22537
+ return {
22538
+ content: [{ type: "text", text: JSON.stringify(checks) }]
22539
+ };
22540
+ } catch (err) {
22541
+ const message = err instanceof Error ? err.message : String(err);
22542
+ return { content: [{ type: "text", text: message }], isError: true };
22543
+ }
22544
+ }
22545
+ );
22508
22546
  server.tool(
22509
22547
  "request_review",
22510
- 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .claude/skills/review/SKILL.md when present (else seeds that skill from .sideboard/review.md or the stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn (loop while stillRunning) / get_turn_result on the returned review tab id.',
22548
+ '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. 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.',
22511
22549
  { ref: import_zod5.z.string().describe("Worktree thread id/ref to review") },
22512
22550
  async ({ ref }) => {
22513
22551
  try {
@@ -22535,7 +22573,7 @@ async function startMcpServer() {
22535
22573
  );
22536
22574
  server.tool(
22537
22575
  "ask_git",
22538
- "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
22576
+ "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Do not start a checks loop on a plain push \u2014 only if the user gave a goal (Greptile 5/5, CI green). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
22539
22577
  {
22540
22578
  ref: import_zod5.z.string().describe("Worktree thread id/ref"),
22541
22579
  action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
@@ -32,19 +32,19 @@ import {
32
32
  slackTokenFor,
33
33
  syncBoardPins,
34
34
  updateSchedule
35
- } from "../chunk-GCWAAPJ5.js";
35
+ } from "../chunk-7BQNSUR2.js";
36
36
  import {
37
37
  isInternalAgentStatusText,
38
38
  listModelsForAgent,
39
39
  sideboardMcpProfile
40
- } from "../chunk-LZAOX76N.js";
40
+ } from "../chunk-EY6QXPPO.js";
41
41
  import "../chunk-G7SIQFBQ.js";
42
42
  import "../chunk-S42XV45P.js";
43
- import "../chunk-TSCWSAQL.js";
43
+ import "../chunk-67TIJ7S5.js";
44
44
  import {
45
45
  GLOBAL_WORKSPACE_ID,
46
46
  isCloudCoordinatorThread
47
- } from "../chunk-Y2FNDKHF.js";
47
+ } from "../chunk-SN6CMKF6.js";
48
48
  import {
49
49
  createAbleTimeTask,
50
50
  ensureAbleTimeTask,
@@ -61,7 +61,7 @@ import {
61
61
  } from "../chunk-6GN5WPYZ.js";
62
62
  import "../chunk-2SDMENAL.js";
63
63
  import "../chunk-KLBOWJ74.js";
64
- import "../chunk-OXOU2FRS.js";
64
+ import "../chunk-7TIUOYBK.js";
65
65
  import {
66
66
  canonicalizeRepoPath,
67
67
  formatGhLandError,
@@ -2819,9 +2819,25 @@ async function startMcpServer() {
2819
2819
  };
2820
2820
  }
2821
2821
  );
2822
+ server.tool(
2823
+ "get_pr_checks",
2824
+ "Snapshot of GitHub PR checks for a worktree thread (`gh pr checks` plus merge/review gates). null = no PR. If the user gave a goal (Greptile 5/5, CI green), the worktree agent watches with `gh pr checks --watch` via /long-running \u2014 this tool is a snapshot, not a waiter. Coordinators: do not run gh from the orchestration cwd.",
2825
+ { ref: z5.string().describe("Worktree thread id/ref") },
2826
+ async ({ ref }) => {
2827
+ try {
2828
+ const checks = await orch.getPrChecks(ref);
2829
+ return {
2830
+ content: [{ type: "text", text: JSON.stringify(checks) }]
2831
+ };
2832
+ } catch (err) {
2833
+ const message = err instanceof Error ? err.message : String(err);
2834
+ return { content: [{ type: "text", text: message }], isError: true };
2835
+ }
2836
+ }
2837
+ );
2822
2838
  server.tool(
2823
2839
  "request_review",
2824
- 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .claude/skills/review/SKILL.md when present (else seeds that skill from .sideboard/review.md or the stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn (loop while stillRunning) / get_turn_result on the returned review tab id.',
2840
+ '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. 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.',
2825
2841
  { ref: z5.string().describe("Worktree thread id/ref to review") },
2826
2842
  async ({ ref }) => {
2827
2843
  try {
@@ -2849,7 +2865,7 @@ async function startMcpServer() {
2849
2865
  );
2850
2866
  server.tool(
2851
2867
  "ask_git",
2852
- "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
2868
+ "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Do not start a checks loop on a plain push \u2014 only if the user gave a goal (Greptile 5/5, CI green). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
2853
2869
  {
2854
2870
  ref: z5.string().describe("Worktree thread id/ref"),
2855
2871
  action: z5.enum(AGENT_GIT_ACTIONS).describe(
@@ -7,16 +7,16 @@ import {
7
7
  isPidAlive,
8
8
  startOrchestration,
9
9
  waitForPidExit
10
- } from "./chunk-GCWAAPJ5.js";
11
- import "./chunk-LZAOX76N.js";
10
+ } from "./chunk-7BQNSUR2.js";
11
+ import "./chunk-EY6QXPPO.js";
12
12
  import "./chunk-G7SIQFBQ.js";
13
13
  import "./chunk-S42XV45P.js";
14
- import "./chunk-TSCWSAQL.js";
15
- import "./chunk-Y2FNDKHF.js";
14
+ import "./chunk-67TIJ7S5.js";
15
+ import "./chunk-SN6CMKF6.js";
16
16
  import "./chunk-6GN5WPYZ.js";
17
17
  import "./chunk-2SDMENAL.js";
18
18
  import "./chunk-KLBOWJ74.js";
19
- import "./chunk-OXOU2FRS.js";
19
+ import "./chunk-7TIUOYBK.js";
20
20
  import "./chunk-3JBMACYX.js";
21
21
  import "./chunk-NVXVEGGM.js";
22
22
  import "./chunk-EUXOHTUK.js";
@@ -5,14 +5,14 @@ import {
5
5
  isPidAlive,
6
6
  startOrchestration,
7
7
  waitForPidExit
8
- } from "./chunk-6H4TJ5TA.js";
8
+ } from "./chunk-6X7Z34XE.js";
9
9
  import "./chunk-RFMQY56R.js";
10
- import "./chunk-UIS7BVCX.js";
10
+ import "./chunk-GFQ57XAX.js";
11
11
  import "./chunk-7F4XE6UG.js";
12
12
  import "./chunk-M267JPEA.js";
13
- import "./chunk-HWZWBJWL.js";
14
- import "./chunk-ADCEGG4A.js";
15
- import "./chunk-77MP647F.js";
13
+ import "./chunk-K2ANSHUO.js";
14
+ import "./chunk-G4MTYUWS.js";
15
+ import "./chunk-2U6QF3PT.js";
16
16
  import "./chunk-GE7M3QTE.js";
17
17
  import "./chunk-JRH62XC4.js";
18
18
  import "./chunk-ELBYOGVA.js";
@@ -4,9 +4,9 @@ import {
4
4
  listWorkspaces,
5
5
  removeWorkspace,
6
6
  syncWorkspacesFromThreads
7
- } from "./chunk-HWZWBJWL.js";
8
- import "./chunk-ADCEGG4A.js";
9
- import "./chunk-77MP647F.js";
7
+ } from "./chunk-K2ANSHUO.js";
8
+ import "./chunk-G4MTYUWS.js";
9
+ import "./chunk-2U6QF3PT.js";
10
10
  import "./chunk-GE7M3QTE.js";
11
11
  import "./chunk-JRH62XC4.js";
12
12
  import "./chunk-4XNSGDXE.js";
@@ -6,9 +6,9 @@ import {
6
6
  listWorkspaces,
7
7
  removeWorkspace,
8
8
  syncWorkspacesFromThreads
9
- } from "./chunk-TSCWSAQL.js";
10
- import "./chunk-Y2FNDKHF.js";
11
- import "./chunk-OXOU2FRS.js";
9
+ } from "./chunk-67TIJ7S5.js";
10
+ import "./chunk-SN6CMKF6.js";
11
+ import "./chunk-7TIUOYBK.js";
12
12
  import "./chunk-3JBMACYX.js";
13
13
  import "./chunk-NVXVEGGM.js";
14
14
  import "./chunk-EUXOHTUK.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideboard-ai/core",
3
- "version": "0.1.151",
3
+ "version": "0.1.152",
4
4
  "description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",