@sideboard-ai/core 0.1.46 → 0.1.49

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 (40) hide show
  1. package/dist/{agents-6L6VENDT.js → agents-3P4N6KHC.js} +1 -1
  2. package/dist/agents-LUB3Q773.js +82 -0
  3. package/dist/app-settings-7XVDQJ7F.js +80 -0
  4. package/dist/{chunk-SZAKJ4TR.js → chunk-3NAS4MWH.js} +1 -1
  5. package/dist/{chunk-SPCU3MFY.js → chunk-5WYEJ3F3.js} +3 -3
  6. package/dist/chunk-7MV3RXSC.js +277 -0
  7. package/dist/chunk-DF5VQQKA.js +191 -0
  8. package/dist/chunk-E35APBHV.js +269 -0
  9. package/dist/chunk-EOYDCKQC.js +172 -0
  10. package/dist/chunk-GZXBYHJC.js +148 -0
  11. package/dist/chunk-HBJSHRY2.js +494 -0
  12. package/dist/chunk-ISY4EGF6.js +77 -0
  13. package/dist/chunk-KGZBYWZ3.js +23 -0
  14. package/dist/chunk-RQI4TOXK.js +2232 -0
  15. package/dist/chunk-S2LL5HA4.js +33 -0
  16. package/dist/{chunk-TQK2OYPU.js → chunk-SS34TVSY.js} +1 -1
  17. package/dist/chunk-V4JRXYYU.js +122 -0
  18. package/dist/{chunk-6NAPN2N5.js → chunk-ZQCQIWIP.js} +1 -1
  19. package/dist/chunk-ZVV5EEQN.js +1892 -0
  20. package/dist/connected-teams-UBXHZGO4.js +24 -0
  21. package/dist/{coordinator-prompt-2XFYG3C5.js → coordinator-prompt-SPGDT7J5.js} +1 -1
  22. package/dist/coordinator-prompt-VG4BZ5JL.js +25 -0
  23. package/dist/cursor-recover-NNK7JPQM.js +44 -0
  24. package/dist/{global-workspace-XFOXEQCP.js → global-workspace-KSR3E63K.js} +2 -2
  25. package/dist/global-workspace-OJF4ENH4.js +40 -0
  26. package/dist/index.cjs +243 -19
  27. package/dist/index.d.cts +49 -10
  28. package/dist/index.d.ts +49 -10
  29. package/dist/index.js +5768 -192
  30. package/dist/mcp/run-stdio.cjs +203 -21
  31. package/dist/mcp/run-stdio.js +5618 -15
  32. package/dist/paths-2OFB7UJG.js +28 -0
  33. package/dist/run-HMRSRG3U.js +12 -0
  34. package/dist/thread-store-XICUWFNM.js +32 -0
  35. package/dist/title-4WAKWZRF.js +27 -0
  36. package/dist/workspaces-OZE7LRDO.js +24 -0
  37. package/dist/{workspaces-SRL2HZTB.js → workspaces-UJX7JIGH.js} +3 -3
  38. package/dist/worktree-XG5PCLZY.js +94 -0
  39. package/package.json +2 -2
  40. package/dist/chunk-7DTJFP4D.js +0 -5680
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  "use strict";
3
4
  var __create = Object.create;
4
5
  var __defProp = Object.defineProperty;
@@ -3300,7 +3301,7 @@ var init_coordinator_prompt = __esm({
3300
3301
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
3301
3302
  "Inspect / review / PRs:",
3302
3303
  "- get_diff \u2014 compact diff summary",
3303
- "- request_review \u2014 open a Review chat tab on a worktree thread (merge-readiness recommendation); then wait_for_turn / get_turn_result on the returned id",
3304
+ '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review."); then wait_for_turn / get_turn_result on the returned id',
3304
3305
  "- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
3305
3306
  "Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
3306
3307
  "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.",
@@ -7540,22 +7541,149 @@ var import_node_fs19 = require("fs");
7540
7541
  var import_node_path18 = require("path");
7541
7542
  init_global_workspace();
7542
7543
  init_thread_store();
7544
+
7545
+ // src/review/review-request-template.ts
7546
+ var REVIEW_REQUEST_TEMPLATE = `# Review guidelines:
7547
+
7548
+ You 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.
7549
+
7550
+ ## Required outcome
7551
+
7552
+ Start your reply with a **Recommendation** section using exactly one of:
7553
+
7554
+ - **Approve** \u2014 ready to merge as-is (or with only trivial nits the author can ignore).
7555
+ - **Approve with nits** \u2014 ready to merge; list only optional polish that should not block.
7556
+ - **Request changes** \u2014 not ready; blocking issues must be fixed first.
7557
+ - **Needs more information** \u2014 cannot judge readiness yet (missing context, incomplete diff, unclear intent).
7558
+
7559
+ In 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.
7560
+
7561
+ People running this review are asking \u201Ccan we ship this?\u201D Treat that as the question you answer first.
7562
+
7563
+ ## Findings
7564
+
7565
+ Below are guidelines for determining whether an issue is worth flagging to the original author.
7566
+
7567
+ These are not the final word. More specific guidelines elsewhere (developer message, user message, a file, etc.) override these.
7568
+
7569
+ Flag something as a bug / blocking finding only when:
7570
+
7571
+ 1. It meaningfully impacts the accuracy, performance, security, or maintainability of the code.
7572
+ 2. The bug is discrete and actionable (not a vague codebase-wide complaint or a bundle of unrelated issues).
7573
+ 3. Fixing it does not demand rigor absent from the rest of the codebase.
7574
+ 4. The issue was introduced by this change (do not flag pre-existing bugs unless they are newly exposed by this PR).
7575
+ 5. The author would likely fix it if made aware.
7576
+ 6. It does not rely on unstated assumptions about the codebase or author intent.
7577
+ 7. Speculative breakage is not enough \u2014 identify the other code that is provably affected.
7578
+ 8. It is clearly not just an intentional change by the author.
7579
+
7580
+ When flagging an issue, include a short accompanying comment:
7581
+
7582
+ 1. Clear about why it is a problem.
7583
+ 2. Severity must match reality \u2014 do not inflate.
7584
+ 3. Brief: at most one paragraph; avoid unnecessary line breaks in prose.
7585
+ 4. No code chunks longer than 3 lines; wrap code in inline ticks or a fenced block.
7586
+ 5. Call out scenarios / environments / inputs needed to hit the bug when severity depends on them.
7587
+ 6. Matter-of-fact tone \u2014 helpful assistant, not accusatory or effusive.
7588
+ 7. Skimmable on first read.
7589
+ 8. No empty flattery (\u201CGreat job\u2026\u201D, \u201CThanks for\u2026\u201D).
7590
+
7591
+ HOW MANY FINDINGS TO RETURN:
7592
+
7593
+ List 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.
7594
+
7595
+ GUIDELINES:
7596
+
7597
+ - Ignore trivial style unless it obscures meaning or violates documented standards.
7598
+ - One comment per distinct issue (or a short multi-line range if needed).
7599
+ - Use \`\`\`suggestion blocks ONLY for concrete replacement code (minimal lines; no commentary inside the block).
7600
+ - In every \`\`\`suggestion block, preserve the exact leading whitespace of the replaced lines (spaces vs tabs, number of spaces).
7601
+ - Do NOT introduce or remove outer indentation levels unless that is the actual fix.
7602
+ - Separate **blocking** findings from **nits**. Only blocking findings should drive Request changes.
7603
+
7604
+ The 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).
7605
+
7606
+ ## Getting the diff
7607
+
7608
+ Use 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.
7609
+
7610
+ If 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.
7611
+
7612
+ ## Fallback: if you don't have access to the Sideboard diff tool
7613
+
7614
+ If you don't have access to \`get_diff\`, use the following git commands to get the diff:
7615
+
7616
+ \`\`\`bash
7617
+ # Get the merge base between this branch and the target
7618
+ MERGE_BASE=$(git merge-base origin/main HEAD)
7619
+
7620
+ # Get the committed diff against the merge base
7621
+ git diff $MERGE_BASE HEAD
7622
+
7623
+ # Get any uncommitted changes (staged and unstaged)
7624
+ git diff HEAD
7625
+ \`\`\`
7626
+
7627
+ Review 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.
7628
+
7629
+ No need to mention in your report whether or not you used one of the fallback strategies; it's usually irrelevant.
7630
+
7631
+ ## Output format
7632
+
7633
+ **1. Recommendation first** (required), then **2. Findings** (may be empty).
7634
+
7635
+ Only report ONE finding per unique issue.
7636
+
7637
+ <example>
7638
+ ## Recommendation
7639
+
7640
+ **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.
7641
+
7642
+ ## Findings
7643
+
7644
+ ### **#1 Empty input causes crash** (blocking)
7645
+
7646
+ If the input field is empty when the page loads, the app will crash.
7647
+
7648
+ File: src/client/frontends/desktop/ui/Input.tsx
7649
+
7650
+ ### **#2 Dead code** (nit)
7651
+
7652
+ The getUserData function is now unused. It should be deleted.
7653
+
7654
+ File: src/client/frontends/desktop/core/UserData.ts
7655
+ </example>
7656
+
7657
+ <example>
7658
+ ## Recommendation
7659
+
7660
+ **Approve** \u2014 Diff is scoped, behavior looks correct, and there are no blocking issues. Safe to merge.
7661
+ </example>
7662
+ `;
7663
+
7664
+ // src/review/request-review.ts
7665
+ var REPO_REVIEW_PATH = ".sideboard/review.md";
7666
+ var REPO_REVIEW_NAME = "review.md";
7543
7667
  var REVIEW_REQUEST_PATH = ".sideboard/attachments/Review request.md";
7544
7668
  var REVIEW_REQUEST_NAME = "Review request.md";
7545
- var REVIEW_REQUEST_PREFILL = `Please review the changes in this workspace and recommend whether they are ready to merge.
7546
-
7547
- Start with a **Recommendation**: Approve, Approve with nits, Request changes, or Needs more information \u2014 and say why in 1\u20133 sentences. Then list blocking findings vs nits (findings may be empty).`;
7548
- function buildReviewRequestAttachment(content) {
7549
- return {
7550
- id: (0, import_node_crypto3.randomUUID)(),
7551
- name: REVIEW_REQUEST_NAME,
7552
- kind: "file",
7553
- path: REVIEW_REQUEST_PATH,
7554
- content
7555
- };
7669
+ var REVIEW_REQUEST_PREFILL = "Review.";
7670
+ var ATTACHMENTS_GITIGNORE = `# Sideboard review / composer attachments (local only)
7671
+ *
7672
+ !.gitignore
7673
+ `;
7674
+ var LEGACY_REVIEW_TEMPLATE_MARKERS = [
7675
+ "You are acting as a reviewer for a proposed code change made by another engineer.",
7676
+ "HOW MANY FINDINGS TO RETURN:"
7677
+ ];
7678
+ function shouldRefreshReviewRequestTemplate(content) {
7679
+ const trimmed = content.trim();
7680
+ if (!trimmed) return true;
7681
+ if (/##\s*Recommendation|ready to merge|Approve with nits|Request changes/i.test(trimmed)) {
7682
+ return false;
7683
+ }
7684
+ return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
7556
7685
  }
7557
- function readExistingReviewRequestFile(worktreePath) {
7558
- const abs = (0, import_node_path18.join)(worktreePath, REVIEW_REQUEST_PATH);
7686
+ function readTextIfPresent(abs) {
7559
7687
  if (!(0, import_node_fs19.existsSync)(abs)) return null;
7560
7688
  try {
7561
7689
  const content = (0, import_node_fs19.readFileSync)(abs, "utf8");
@@ -7564,6 +7692,54 @@ function readExistingReviewRequestFile(worktreePath) {
7564
7692
  return null;
7565
7693
  }
7566
7694
  }
7695
+ function ensureAttachmentsGitignore(worktreePath) {
7696
+ const gitignoreAbs = (0, import_node_path18.join)(worktreePath, ".sideboard", "attachments", ".gitignore");
7697
+ if ((0, import_node_fs19.existsSync)(gitignoreAbs)) return;
7698
+ (0, import_node_fs19.mkdirSync)((0, import_node_path18.dirname)(gitignoreAbs), { recursive: true });
7699
+ (0, import_node_fs19.writeFileSync)(gitignoreAbs, ATTACHMENTS_GITIGNORE, "utf8");
7700
+ }
7701
+ function resolveReviewGuidelines(worktreePath) {
7702
+ const repoAbs = (0, import_node_path18.join)(worktreePath, REPO_REVIEW_PATH);
7703
+ const repoContent = readTextIfPresent(repoAbs);
7704
+ if (repoContent) {
7705
+ return {
7706
+ path: REPO_REVIEW_PATH,
7707
+ name: REPO_REVIEW_NAME,
7708
+ content: repoContent,
7709
+ source: "repo"
7710
+ };
7711
+ }
7712
+ const localAbs = (0, import_node_path18.join)(worktreePath, REVIEW_REQUEST_PATH);
7713
+ const localContent = readTextIfPresent(localAbs);
7714
+ if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
7715
+ return {
7716
+ path: REVIEW_REQUEST_PATH,
7717
+ name: REVIEW_REQUEST_NAME,
7718
+ content: localContent,
7719
+ source: "local"
7720
+ };
7721
+ }
7722
+ ensureAttachmentsGitignore(worktreePath);
7723
+ (0, import_node_fs19.mkdirSync)((0, import_node_path18.dirname)(localAbs), { recursive: true });
7724
+ (0, import_node_fs19.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
7725
+ return {
7726
+ path: REVIEW_REQUEST_PATH,
7727
+ name: REVIEW_REQUEST_NAME,
7728
+ content: REVIEW_REQUEST_TEMPLATE,
7729
+ source: "stock"
7730
+ };
7731
+ }
7732
+ function buildReviewRequestAttachment(content, opts) {
7733
+ const path = opts?.path ?? REVIEW_REQUEST_PATH;
7734
+ const name = opts?.name ?? (path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
7735
+ return {
7736
+ id: (0, import_node_crypto3.randomUUID)(),
7737
+ name,
7738
+ kind: "file",
7739
+ path,
7740
+ content
7741
+ };
7742
+ }
7567
7743
  async function requestReview(threadRef, send) {
7568
7744
  const from = findThreadByRef(threadRef);
7569
7745
  if (!from) throw new Error(`Thread not found: ${threadRef}`);
@@ -7575,12 +7751,16 @@ async function requestReview(threadRef, send) {
7575
7751
  if (from.status === "archived") {
7576
7752
  throw new Error(`Thread is archived: ${from.id}`);
7577
7753
  }
7578
- const existing = readExistingReviewRequestFile(from.worktreePath);
7579
- const attachments = existing ? [buildReviewRequestAttachment(existing)] : [];
7754
+ const guidelines = resolveReviewGuidelines(from.worktreePath);
7580
7755
  const tab = createChatTab({
7581
7756
  fromThreadId: from.id,
7582
7757
  title: "Review",
7583
- attachments
7758
+ attachments: [
7759
+ buildReviewRequestAttachment(guidelines.content, {
7760
+ path: guidelines.path,
7761
+ name: guidelines.name
7762
+ })
7763
+ ]
7584
7764
  });
7585
7765
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
7586
7766
  return { tab: started, from };
@@ -8964,7 +9144,7 @@ var IMAGE_MIME_BY_EXT = {
8964
9144
  ico: "image/x-icon"
8965
9145
  };
8966
9146
  var ATTACHMENTS_DIR = ".sideboard/attachments";
8967
- var ATTACHMENTS_GITIGNORE = `# Sideboard review / composer attachments (local only)
9147
+ var ATTACHMENTS_GITIGNORE2 = `# Sideboard review / composer attachments (local only)
8968
9148
  *
8969
9149
  !.gitignore
8970
9150
  `;
@@ -8985,7 +9165,7 @@ function ensureAttachmentsDir(worktreePath) {
8985
9165
  (0, import_node_fs23.mkdirSync)(dir, { recursive: true });
8986
9166
  const gi = (0, import_node_path22.join)(dir, ".gitignore");
8987
9167
  if (!(0, import_node_fs23.existsSync)(gi)) {
8988
- (0, import_node_fs23.writeFileSync)(gi, ATTACHMENTS_GITIGNORE, "utf8");
9168
+ (0, import_node_fs23.writeFileSync)(gi, ATTACHMENTS_GITIGNORE2, "utf8");
8989
9169
  }
8990
9170
  return dir;
8991
9171
  }
@@ -9769,9 +9949,11 @@ var Orchestrator = class {
9769
9949
  this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
9770
9950
  thread = this.requireThread(threadId);
9771
9951
  }
9952
+ const sentAttachments = thread.attachments.length > 0 ? [...thread.attachments] : void 0;
9772
9953
  appendMessage(threadId, {
9773
9954
  role: "user",
9774
9955
  text: prompt,
9956
+ ...sentAttachments ? { attachments: sentAttachments } : {},
9775
9957
  ts: (/* @__PURE__ */ new Date()).toISOString()
9776
9958
  });
9777
9959
  thread = this.requireThread(threadId);
@@ -9779,7 +9961,7 @@ var Orchestrator = class {
9779
9961
  thread.worktreePath,
9780
9962
  prompt,
9781
9963
  {
9782
- attachments: thread.attachments
9964
+ attachments: sentAttachments ?? thread.attachments
9783
9965
  }
9784
9966
  );
9785
9967
  const orchestrationReminder = isOrchestratorThread(thread) ? coordinatorTurnReminder({
@@ -11139,7 +11321,7 @@ async function startMcpServer() {
11139
11321
  );
11140
11322
  server.tool(
11141
11323
  "request_review",
11142
- "Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, optionally attaches .sideboard/attachments/Review request.md when present, and asks for Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.",
11324
+ 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
11143
11325
  { ref: import_zod.z.string().describe("Worktree thread id/ref to review") },
11144
11326
  async ({ ref }) => {
11145
11327
  try {