@sideboard-ai/core 0.1.67 → 0.1.71

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 (44) hide show
  1. package/dist/{agents-OTBZVTZO.js → agents-GB7XL2LI.js} +8 -7
  2. package/dist/{agents-TS3EI2YI.js → agents-TCAK3MXN.js} +8 -7
  3. package/dist/{app-settings-ONKMFSEJ.js → app-settings-3TLA2EJ7.js} +16 -1
  4. package/dist/{app-settings-GJVZGU3M.js → app-settings-P42Z3VOB.js} +16 -1
  5. package/dist/caffeinate-hold-BEJIYPJ7.js +107 -0
  6. package/dist/caffeinate-hold-KLC6SABD.js +14 -0
  7. package/dist/{chunk-WAFIF22N.js → chunk-3CY6WJ7O.js} +2 -2
  8. package/dist/{chunk-7ZOQY4A7.js → chunk-57ROTAFD.js} +62 -3
  9. package/dist/{chunk-57WWNMFP.js → chunk-7NCIHRAU.js} +22 -4
  10. package/dist/{chunk-FGDJOJ2L.js → chunk-AE5VBOFE.js} +1 -1
  11. package/dist/{chunk-DB3I75FI.js → chunk-BTL7EMGT.js} +4 -4
  12. package/dist/{chunk-4UIYN56C.js → chunk-D4DPQ552.js} +1 -1
  13. package/dist/{chunk-JWZNK3CQ.js → chunk-DGPUAZA4.js} +62 -3
  14. package/dist/{chunk-ZRFAZVGL.js → chunk-H2IXNFQ2.js} +22 -4
  15. package/dist/chunk-JAWEDVVA.js +106 -0
  16. package/dist/chunk-JT7R45JB.js +20 -0
  17. package/dist/{chunk-4BUCGNZS.js → chunk-MF2YMEGD.js} +83 -29
  18. package/dist/{chunk-K7LM4CLD.js → chunk-NG7S3OPX.js} +12 -6
  19. package/dist/chunk-NSTQ6QKD.js +23 -0
  20. package/dist/{chunk-LW5CMQGZ.js → chunk-OE7YBB5X.js} +83 -29
  21. package/dist/{chunk-BPOTVI5J.js → chunk-PTJJIQK7.js} +472 -18
  22. package/dist/{chunk-B4PRRKMA.js → chunk-S25IHL5H.js} +12 -6
  23. package/dist/{chunk-5HTTCYWA.js → chunk-UH57WVFP.js} +2 -2
  24. package/dist/{chunk-M5V4QIWF.js → chunk-VROPG6QF.js} +1 -1
  25. package/dist/{chunk-MHR4OGZ4.js → chunk-W7YOTDVO.js} +493 -18
  26. package/dist/{connected-teams-RUNMOCG5.js → connected-teams-35EIRJCP.js} +2 -2
  27. package/dist/{connected-teams-OMDHTL6A.js → connected-teams-ZRS53OAT.js} +2 -2
  28. package/dist/{coordinator-prompt-6HMTOX4G.js → coordinator-prompt-2J4PIMUF.js} +7 -4
  29. package/dist/{coordinator-prompt-3BSMKZL4.js → coordinator-prompt-QYYG2IBB.js} +7 -4
  30. package/dist/{global-workspace-YZ2NJVLL.js → global-workspace-KHIFQUUM.js} +12 -5
  31. package/dist/{global-workspace-QS7A23CB.js → global-workspace-SVRYNJZA.js} +12 -5
  32. package/dist/index.cjs +4805 -1262
  33. package/dist/index.d.cts +570 -22
  34. package/dist/index.d.ts +570 -22
  35. package/dist/index.js +3084 -340
  36. package/dist/mcp/run-stdio.cjs +2339 -617
  37. package/dist/mcp/run-stdio.js +1289 -290
  38. package/dist/{run-Y2MI3EVV.js → run-A4RHY7HH.js} +1 -1
  39. package/dist/{run-JLD2Y52J.js → run-V2WZUMJA.js} +1 -1
  40. package/dist/{workspaces-EBFW7I7S.js → workspaces-AHFTHVBT.js} +7 -6
  41. package/dist/{workspaces-AIUYUXB7.js → workspaces-SVQIEVIZ.js} +7 -6
  42. package/dist/{worktree-WMDJW2BL.js → worktree-KWXHMKRN.js} +2 -2
  43. package/dist/{worktree-7NBPIVFZ.js → worktree-VOCH3WS3.js} +2 -2
  44. package/package.json +3 -1
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  resolveThreadDefaults
3
- } from "./chunk-MHR4OGZ4.js";
3
+ } from "./chunk-W7YOTDVO.js";
4
4
  import {
5
5
  resolveGithubRepoSlug
6
- } from "./chunk-4BUCGNZS.js";
6
+ } from "./chunk-MF2YMEGD.js";
7
7
  import {
8
8
  globalAgentCwd,
9
9
  sideboardReposDir
@@ -45,9 +45,12 @@ var COORDINATOR_TOOL_PLAYBOOK = [
45
45
  "Discover:",
46
46
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
47
47
  "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear API or GitHub Issues)",
48
+ "- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post \u2014 Slack workspaces from Account settings; pass team_id from list_teams",
49
+ "- Slack notify (only when the user asks): list_teams \u2192 slack_list_users or slack_list_channels \u2192 slack_post with to=@user or #channel and optional github_url (PR, blob permalink, or review/issue comment). Do not notify proactively.",
48
50
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
49
51
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
50
52
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
53
+ "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake.",
51
54
  "Workspaces:",
52
55
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
53
56
  "Worktree threads (chats):",
@@ -69,6 +72,13 @@ var COORDINATOR_TOOL_PLAYBOOK = [
69
72
  "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.",
70
73
  "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."
71
74
  ].join("\n");
75
+ var SLACK_REPLY_FORMATTING = [
76
+ "Slack formatting (mandatory \u2014 your reply is posted verbatim to Slack):",
77
+ "- Use Slack mrkdwn, NOT GitHub/CommonMark markdown. Slack does not render `**bold**`, `# headings`, or `[label](url)`.",
78
+ "- Bold: *text* (single asterisks). Italic: _text_. Strikethrough: ~text~. Inline code: `code`.",
79
+ "- Links: <https://example.com|label> or bare URLs. Thread ids: plain `sideboard://thread/<id>` (no markdown link syntax).",
80
+ "- Prefer short paragraphs and *bold* section labels over markdown headings or bullet trees with `**`."
81
+ ].join("\n");
72
82
  function accountDefaultsPlaybookLine() {
73
83
  const d = resolveThreadDefaults();
74
84
  const model = d.model?.trim() || "Auto";
@@ -89,7 +99,8 @@ function coordinatorTurnReminder(opts) {
89
99
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
90
100
  "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn.",
91
101
  "- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR.",
92
- "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`."
102
+ "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
103
+ "- If they will wait on Slack or leave the Mac, call set_caffeinate enabled=true. When they say they are done / wrapping up / going to sleep, call set_caffeinate enabled=false."
93
104
  ].filter(Boolean).join("\n");
94
105
  }
95
106
  function ensureGlobalCoordinatorCwd(opts) {
@@ -157,8 +168,14 @@ function coordinatorSystemPrompt(opts) {
157
168
  const audience = opts.audience ?? "cloud";
158
169
  const reposDir = sideboardReposDir();
159
170
  const intro = audience === "cloud" ? [
160
- "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Slack, Discord, Teams, or other chat).",
171
+ "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Discord, Teams, or other chat).",
161
172
  "Your reply will be sent back to that cloud agent \u2014 be concise and actionable."
173
+ ] : audience === "slack" ? [
174
+ "You are a Sideboard coordinator responding to a Slack DM or @mention via the Sideboard Slack app.",
175
+ "Your reply will be posted back in Slack \u2014 be concise and actionable.",
176
+ "Sideboard signs the Slack reply with this Mac's destination name (Personal / Work). Do not prefix that name yourself.",
177
+ "Call set_caffeinate enabled=true when they start a stretch of remote work so the Mac stays awake. Call set_caffeinate enabled=false when they say they are done, wrapping up, or going to sleep.",
178
+ SLACK_REPLY_FORMATTING
162
179
  ] : [
163
180
  "You are a Sideboard orchestration agent: you oversee worktree agents across registered workspaces in the Sideboard app.",
164
181
  "Stay concise and actionable; prefer Sideboard MCP for fleet status; use Bash for greenfield repo setup and inspecting target worktree paths."
@@ -186,6 +203,7 @@ export {
186
203
  enrichWorkspacesWithGithub,
187
204
  coordinatorGreenfieldPlaybook,
188
205
  COORDINATOR_TOOL_PLAYBOOK,
206
+ SLACK_REPLY_FORMATTING,
189
207
  coordinatorTurnReminder,
190
208
  ensureGlobalCoordinatorCwd,
191
209
  coordinatorSystemPrompt
@@ -0,0 +1,106 @@
1
+ import {
2
+ writePrivateFile
3
+ } from "./chunk-JT7R45JB.js";
4
+ import {
5
+ appDataDir
6
+ } from "./chunk-M37RITA6.js";
7
+
8
+ // src/store/caffeinate-hold.ts
9
+ import { spawn } from "child_process";
10
+ import { existsSync, readFileSync, unlinkSync } from "fs";
11
+ import { join } from "path";
12
+ var hooks = {};
13
+ function setCaffeinateHoldHooks(next) {
14
+ hooks = next;
15
+ }
16
+ function caffeinateHoldPath() {
17
+ return join(appDataDir(), "caffeinate-hold.json");
18
+ }
19
+ function processAlive(pid) {
20
+ if (hooks.processAlive) return hooks.processAlive(pid);
21
+ try {
22
+ process.kill(pid, 0);
23
+ return true;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+ function killPid(pid) {
29
+ if (hooks.kill) {
30
+ hooks.kill(pid);
31
+ return;
32
+ }
33
+ try {
34
+ process.kill(pid, "SIGTERM");
35
+ } catch {
36
+ }
37
+ }
38
+ function readHold() {
39
+ const path = caffeinateHoldPath();
40
+ if (!existsSync(path)) return null;
41
+ try {
42
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
43
+ if (typeof parsed?.pid === "number" && parsed.pid > 0) return parsed;
44
+ } catch {
45
+ }
46
+ return null;
47
+ }
48
+ function writeHold(pid) {
49
+ writePrivateFile(caffeinateHoldPath(), `${JSON.stringify({ pid })}
50
+ `);
51
+ }
52
+ function clearHold() {
53
+ try {
54
+ unlinkSync(caffeinateHoldPath());
55
+ } catch {
56
+ }
57
+ }
58
+ function getCaffeinateHold() {
59
+ const platform = hooks.platform ?? process.platform;
60
+ const hold = readHold();
61
+ if (!hold) {
62
+ return { held: false, pid: null, running: false, platform };
63
+ }
64
+ const running = processAlive(hold.pid);
65
+ if (!running) {
66
+ clearHold();
67
+ return { held: false, pid: null, running: false, platform };
68
+ }
69
+ return { held: true, pid: hold.pid, running: true, platform };
70
+ }
71
+ function setCaffeinateHold(enabled) {
72
+ const platform = hooks.platform ?? process.platform;
73
+ const current = getCaffeinateHold();
74
+ if (!enabled) {
75
+ if (current.pid) killPid(current.pid);
76
+ clearHold();
77
+ return { held: false, pid: null, running: false, platform };
78
+ }
79
+ if (current.running && current.pid) return current;
80
+ if (platform !== "darwin") {
81
+ return { held: false, pid: null, running: false, platform };
82
+ }
83
+ const spawnImpl = hooks.spawn ?? spawn;
84
+ const child = spawnImpl("caffeinate", ["-dimsu"], {
85
+ detached: true,
86
+ stdio: "ignore"
87
+ });
88
+ const pid = child.pid;
89
+ if (!pid) {
90
+ try {
91
+ child.kill();
92
+ } catch {
93
+ }
94
+ return { held: false, pid: null, running: false, platform };
95
+ }
96
+ child.unref();
97
+ writeHold(pid);
98
+ return { held: true, pid, running: true, platform };
99
+ }
100
+
101
+ export {
102
+ setCaffeinateHoldHooks,
103
+ caffeinateHoldPath,
104
+ getCaffeinateHold,
105
+ setCaffeinateHold
106
+ };
@@ -0,0 +1,20 @@
1
+ // src/store/private-file.ts
2
+ import { chmodSync, mkdirSync, writeFileSync } from "fs";
3
+ import { dirname } from "path";
4
+ var PRIVATE_FILE_MODE = 384;
5
+ function writePrivateFile(path, contents) {
6
+ mkdirSync(dirname(path), { recursive: true });
7
+ writeFileSync(path, contents, { encoding: "utf8", mode: PRIVATE_FILE_MODE });
8
+ chmodOwnerOnly(path);
9
+ }
10
+ function chmodOwnerOnly(path) {
11
+ try {
12
+ chmodSync(path, PRIVATE_FILE_MODE);
13
+ } catch {
14
+ }
15
+ }
16
+
17
+ export {
18
+ writePrivateFile,
19
+ chmodOwnerOnly
20
+ };
@@ -11,7 +11,7 @@ import {
11
11
  gh,
12
12
  git,
13
13
  resolveGhAuthToken
14
- } from "./chunk-4UIYN56C.js";
14
+ } from "./chunk-D4DPQ552.js";
15
15
 
16
16
  // src/git/worktree.ts
17
17
  import { existsSync, readdirSync } from "fs";
@@ -887,6 +887,10 @@ function formatIpcInvokeError(err) {
887
887
  }
888
888
 
889
889
  // src/git/pr-gates.ts
890
+ function prIsInMergeQueue(gate) {
891
+ if (gate.isInMergeQueue) return true;
892
+ return (gate.mergeStateStatus ?? "").toUpperCase() === "QUEUED";
893
+ }
890
894
  function buildMergeGateChecks(gate, opts = {}) {
891
895
  const rows = [];
892
896
  const base = gate.baseRefName?.trim() || "the base branch";
@@ -896,7 +900,8 @@ function buildMergeGateChecks(gate, opts = {}) {
896
900
  const review = (gate.reviewDecision ?? "").toUpperCase();
897
901
  const suppressBlocked = opts.suppressGenericBlocked !== false;
898
902
  const conflicting = mergeable === "CONFLICTING" || mergeState === "DIRTY";
899
- if (conflicting) {
903
+ const inQueue = prIsInMergeQueue(gate);
904
+ if (conflicting && !inQueue) {
900
905
  rows.push({
901
906
  name: "Merge conflicts",
902
907
  state: mergeable === "CONFLICTING" ? "CONFLICTING" : mergeState || "DIRTY",
@@ -908,6 +913,18 @@ function buildMergeGateChecks(gate, opts = {}) {
908
913
  workflow: "mergeability",
909
914
  kind: "mergeability"
910
915
  });
916
+ } else if (inQueue) {
917
+ rows.push({
918
+ name: "Merge queue",
919
+ state: "QUEUED",
920
+ bucket: "pending",
921
+ startedAt: null,
922
+ completedAt: null,
923
+ link,
924
+ description: `This pull request is in the GitHub merge queue for ${base}.`,
925
+ workflow: "mergeability",
926
+ kind: "mergeability"
927
+ });
911
928
  } else if (mergeState === "BEHIND") {
912
929
  rows.push({
913
930
  name: "Branch behind",
@@ -1274,7 +1291,7 @@ async function originGhRepoEnv(cwd) {
1274
1291
  const slug = await resolveGithubRepoSlug(cwd);
1275
1292
  return slug ? { GH_REPO: slug } : {};
1276
1293
  }
1277
- async function resolveDefaultBranch(repoPath) {
1294
+ async function resolveDefaultBranch(repoPath, opts) {
1278
1295
  const viaOrigin = await git(
1279
1296
  ["symbolic-ref", "refs/remotes/origin/HEAD"],
1280
1297
  repoPath,
@@ -1283,22 +1300,24 @@ async function resolveDefaultBranch(repoPath) {
1283
1300
  if (viaOrigin.exitCode === 0 && viaOrigin.stdout.trim()) {
1284
1301
  return viaOrigin.stdout.trim().replace(/^refs\/remotes\/origin\//, "");
1285
1302
  }
1286
- const slug = await resolveGithubRepoSlug(repoPath);
1287
- const viaGh = await gh(
1288
- [
1289
- "repo",
1290
- "view",
1291
- ...slug ? ["--repo", slug] : [],
1292
- "--json",
1293
- "defaultBranchRef",
1294
- "--jq",
1295
- ".defaultBranchRef.name"
1296
- ],
1297
- repoPath,
1298
- { reject: false }
1299
- );
1300
- if (viaGh.exitCode === 0 && viaGh.stdout.trim()) {
1301
- return viaGh.stdout.trim();
1303
+ if (opts?.network !== false) {
1304
+ const slug = await resolveGithubRepoSlug(repoPath);
1305
+ const viaGh = await gh(
1306
+ [
1307
+ "repo",
1308
+ "view",
1309
+ ...slug ? ["--repo", slug] : [],
1310
+ "--json",
1311
+ "defaultBranchRef",
1312
+ "--jq",
1313
+ ".defaultBranchRef.name"
1314
+ ],
1315
+ repoPath,
1316
+ { reject: false, timeoutMs: 8e3 }
1317
+ );
1318
+ if (viaGh.exitCode === 0 && viaGh.stdout.trim()) {
1319
+ return viaGh.stdout.trim();
1320
+ }
1302
1321
  }
1303
1322
  for (const candidate of ["main", "master"]) {
1304
1323
  const check = await git(
@@ -1439,10 +1458,21 @@ async function fetchPrMergeGate(cwd, selector, slug) {
1439
1458
  "view",
1440
1459
  selector,
1441
1460
  "--json",
1442
- "mergeable,mergeStateStatus,reviewDecision,baseRefName,url"
1461
+ "mergeable,mergeStateStatus,reviewDecision,baseRefName,url,isInMergeQueue"
1443
1462
  ];
1444
1463
  if (slug) args.push("--repo", slug);
1445
- const { stdout, exitCode, stderr } = await gh(args, cwd, { reject: false });
1464
+ let { stdout, exitCode, stderr } = await gh(args, cwd, { reject: false });
1465
+ if (exitCode !== 0 && isUnknownJsonField(stderr, "isInMergeQueue")) {
1466
+ const retry = [
1467
+ "pr",
1468
+ "view",
1469
+ selector,
1470
+ "--json",
1471
+ "mergeable,mergeStateStatus,reviewDecision,baseRefName,url"
1472
+ ];
1473
+ if (slug) retry.push("--repo", slug);
1474
+ ({ stdout, exitCode, stderr } = await gh(retry, cwd, { reject: false }));
1475
+ }
1446
1476
  if (exitCode !== 0 || !stdout.trim()) {
1447
1477
  if (/no pull requests found/i.test(stderr)) return null;
1448
1478
  return null;
@@ -1454,12 +1484,22 @@ async function fetchPrMergeGate(cwd, selector, slug) {
1454
1484
  mergeStateStatus: typeof view.mergeStateStatus === "string" && view.mergeStateStatus ? view.mergeStateStatus : null,
1455
1485
  reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
1456
1486
  baseRefName: typeof view.baseRefName === "string" && view.baseRefName ? view.baseRefName : null,
1457
- url: typeof view.url === "string" && view.url ? view.url : null
1487
+ url: typeof view.url === "string" && view.url ? view.url : null,
1488
+ isInMergeQueue: parseInMergeQueue(view)
1458
1489
  };
1459
1490
  } catch {
1460
1491
  return null;
1461
1492
  }
1462
1493
  }
1494
+ function isUnknownJsonField(stderr, field) {
1495
+ return new RegExp(`unknown json field[^\\n]*${field}`, "i").test(stderr);
1496
+ }
1497
+ function parseInMergeQueue(view) {
1498
+ return prIsInMergeQueue({
1499
+ isInMergeQueue: view.isInMergeQueue === true,
1500
+ mergeStateStatus: typeof view.mergeStateStatus === "string" ? view.mergeStateStatus : null
1501
+ });
1502
+ }
1463
1503
  async function detectLocalMergeConflicts(cwd, baseRefName) {
1464
1504
  const baseName = (baseRefName?.trim() || await resolveDefaultBranch(cwd)).replace(
1465
1505
  /^origin\//,
@@ -1520,7 +1560,8 @@ async function getPrChecks(cwd, selector) {
1520
1560
  const mergeable = (gate?.mergeable ?? "").toUpperCase();
1521
1561
  const mergeState = (gate?.mergeStateStatus ?? "").toUpperCase();
1522
1562
  const alreadyConflicting = mergeable === "CONFLICTING" || mergeState === "DIRTY";
1523
- const needsLocalProbe = !alreadyConflicting;
1563
+ const inQueue = gate ? prIsInMergeQueue(gate) : false;
1564
+ const needsLocalProbe = !alreadyConflicting && !inQueue;
1524
1565
  if (needsLocalProbe) {
1525
1566
  try {
1526
1567
  const local = await detectLocalMergeConflicts(cwd, gate?.baseRefName ?? null);
@@ -1531,7 +1572,8 @@ async function getPrChecks(cwd, selector) {
1531
1572
  mergeStateStatus: "DIRTY",
1532
1573
  reviewDecision: gate?.reviewDecision ?? null,
1533
1574
  baseRefName: local.base,
1534
- url: gate?.url ?? null
1575
+ url: gate?.url ?? null,
1576
+ isInMergeQueue: false
1535
1577
  };
1536
1578
  const ciFailed2 = ciChecks.some((c) => c.bucket === "fail");
1537
1579
  const review2 = (gate.reviewDecision ?? "").toUpperCase();
@@ -1575,10 +1617,21 @@ async function getPrMeta(cwd, selector) {
1575
1617
  "view",
1576
1618
  selector,
1577
1619
  "--json",
1578
- "number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName"
1620
+ "number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,isInMergeQueue,mergeStateStatus"
1579
1621
  ];
1580
1622
  if (slug) viewArgs.push("--repo", slug);
1581
- const { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
1623
+ let { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
1624
+ if (exitCode !== 0 && isUnknownJsonField(stderr, "isInMergeQueue")) {
1625
+ const retry = [
1626
+ "pr",
1627
+ "view",
1628
+ selector,
1629
+ "--json",
1630
+ "number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,mergeStateStatus"
1631
+ ];
1632
+ if (slug) retry.push("--repo", slug);
1633
+ ({ stdout, exitCode, stderr } = await gh(retry, cwd, { reject: false }));
1634
+ }
1582
1635
  if (exitCode !== 0 || !stdout.trim()) {
1583
1636
  if (/no pull requests found/i.test(stderr)) return null;
1584
1637
  return null;
@@ -1593,7 +1646,8 @@ async function getPrMeta(cwd, selector) {
1593
1646
  isDraft: Boolean(view.isDraft),
1594
1647
  reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
1595
1648
  baseRefName: String(view.baseRefName ?? ""),
1596
- headRefName: String(view.headRefName ?? "")
1649
+ headRefName: String(view.headRefName ?? ""),
1650
+ isInMergeQueue: parseInMergeQueue(view)
1597
1651
  };
1598
1652
  } catch {
1599
1653
  return null;
@@ -1950,11 +2004,11 @@ async function listWorktrees(repoPath) {
1950
2004
  return entries;
1951
2005
  }
1952
2006
  async function isDirty(worktreePath) {
1953
- const { stdout } = await git(["status", "--porcelain", "-uall"], worktreePath);
2007
+ const { stdout } = await git(["status", "--porcelain"], worktreePath);
1954
2008
  for (const line of stdout.split("\n")) {
1955
2009
  if (!line.trim()) continue;
1956
2010
  const rel = porcelainStatusPath(line);
1957
- if (!rel || isSideboardScratchPath(rel)) continue;
2011
+ if (!rel || isSideboardScratchPath(rel) || rel === ".sideboard") continue;
1958
2012
  return true;
1959
2013
  }
1960
2014
  return false;
@@ -6,23 +6,23 @@ import {
6
6
  ensureCliTeamTracked,
7
7
  ensureConnectedBrightsyTeamTokens,
8
8
  loadBrightsyConfig
9
- } from "./chunk-M5V4QIWF.js";
9
+ } from "./chunk-VROPG6QF.js";
10
10
  import {
11
11
  isOrchestratorThread
12
- } from "./chunk-JWZNK3CQ.js";
12
+ } from "./chunk-DGPUAZA4.js";
13
13
  import {
14
14
  enrichPathWithNpmGlobalBin,
15
15
  isConductorBundledCli,
16
16
  resolveCommandBinarySync,
17
17
  run,
18
18
  withExportedPath
19
- } from "./chunk-FGDJOJ2L.js";
19
+ } from "./chunk-AE5VBOFE.js";
20
20
  import {
21
21
  claudeChromeEnabled,
22
22
  loadAppSettings,
23
23
  resolveAgentExecutable,
24
24
  resolveClaudeExecutable
25
- } from "./chunk-BPOTVI5J.js";
25
+ } from "./chunk-PTJJIQK7.js";
26
26
  import {
27
27
  appDataDir
28
28
  } from "./chunk-7MV3RXSC.js";
@@ -580,7 +580,13 @@ var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
580
580
  "mcp__sideboard__present_schema",
581
581
  "mcp__sideboard__present_files",
582
582
  "mcp__sideboard__ask_user",
583
- "mcp__sideboard__present_plan"
583
+ "mcp__sideboard__present_plan",
584
+ "mcp__sideboard__list_teams",
585
+ "mcp__sideboard__slack_list_channels",
586
+ "mcp__sideboard__slack_list_users",
587
+ "mcp__sideboard__slack_search",
588
+ "mcp__sideboard__slack_read",
589
+ "mcp__sideboard__slack_post"
584
590
  ];
585
591
  var brightsyMcpCommandCache = null;
586
592
  async function resolveBrightsyMcpCommand() {
@@ -1000,7 +1006,7 @@ var claudeAdapter = {
1000
1006
  );
1001
1007
  }
1002
1008
  const mode = permissionMode(thread);
1003
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-YZ2NJVLL.js");
1009
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-KHIFQUUM.js");
1004
1010
  const isOrchestrator = isOrchestratorThread2(thread);
1005
1011
  const injectedServers = await buildInjectedMcpServers({
1006
1012
  includeSideboard: true,
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ // src/store/private-file.ts
5
+ import { chmodSync, mkdirSync, writeFileSync } from "fs";
6
+ import { dirname } from "path";
7
+ var PRIVATE_FILE_MODE = 384;
8
+ function writePrivateFile(path, contents) {
9
+ mkdirSync(dirname(path), { recursive: true });
10
+ writeFileSync(path, contents, { encoding: "utf8", mode: PRIVATE_FILE_MODE });
11
+ chmodOwnerOnly(path);
12
+ }
13
+ function chmodOwnerOnly(path) {
14
+ try {
15
+ chmodSync(path, PRIVATE_FILE_MODE);
16
+ } catch {
17
+ }
18
+ }
19
+
20
+ export {
21
+ writePrivateFile,
22
+ chmodOwnerOnly
23
+ };