@sideboard-ai/core 0.1.148 → 0.1.150

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 (60) hide show
  1. package/dist/{abletime-QEVAE67D.js → abletime-223A3LY6.js} +2 -2
  2. package/dist/{abletime-DI55AJX3.js → abletime-CLC5UJC2.js} +2 -2
  3. package/dist/agents/cursor-runner.cjs +85 -45
  4. package/dist/agents/cursor-runner.js +47 -12
  5. package/dist/{agents-DUF4Q2ZI.js → agents-KKXGTEV6.js} +10 -9
  6. package/dist/{agents-INCTFWKA.js → agents-YWBQXOA2.js} +10 -9
  7. package/dist/{app-settings-WJDCJFSY.js → app-settings-3CHCNIMD.js} +5 -1
  8. package/dist/{app-settings-ZCN632OJ.js → app-settings-J3JBCUOT.js} +5 -1
  9. package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
  10. package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
  11. package/dist/{chunk-R4JP32P5.js → chunk-AF6O55PJ.js} +4 -4
  12. package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
  13. package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
  14. package/dist/{chunk-ZVYLEF72.js → chunk-DMRIZR6M.js} +6 -6
  15. package/dist/{chunk-5MS2XTNV.js → chunk-DXCNW2JF.js} +113 -52
  16. package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
  17. package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
  18. package/dist/{chunk-3QRGCKYL.js → chunk-HAS5EPBS.js} +2 -2
  19. package/dist/{chunk-WT5HSFOU.js → chunk-HEII7W3Q.js} +5 -2
  20. package/dist/{chunk-EGDRPA4B.js → chunk-NOTANBYC.js} +6 -6
  21. package/dist/{chunk-CTXQHSTY.js → chunk-NUPITVRF.js} +134 -73
  22. package/dist/{chunk-QTUESPAW.js → chunk-PTOSP4AH.js} +1 -1
  23. package/dist/{chunk-Q62SDB53.js → chunk-QGJHIJHV.js} +2 -2
  24. package/dist/{chunk-YQRBNOIW.js → chunk-SDN4ZYQH.js} +24 -13
  25. package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
  26. package/dist/{chunk-N3VNOFXQ.js → chunk-VO4SPEBS.js} +4 -4
  27. package/dist/chunk-VSFGPWCQ.js +62 -0
  28. package/dist/{chunk-N5PM7HGQ.js → chunk-W6N6GQME.js} +1 -1
  29. package/dist/{chunk-FKOIHGKV.js → chunk-WHU7YGWP.js} +1 -1
  30. package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
  31. package/dist/chunk-Y4NAPW5I.js +60 -0
  32. package/dist/{chunk-B3SJXYIJ.js → chunk-Y7YBWWIG.js} +1 -1
  33. package/dist/{chunk-XOKHXFFX.js → chunk-YGGBJY5A.js} +22 -8
  34. package/dist/{chunk-JTPDWTWJ.js → chunk-Z2PVJKMN.js} +137 -114
  35. package/dist/{chunk-YP3CSOZ6.js → chunk-ZGFYFVJF.js} +142 -114
  36. package/dist/{connected-teams-IJUJQ7R6.js → connected-teams-I2WZZZFA.js} +2 -2
  37. package/dist/{connected-teams-4A2AXDNN.js → connected-teams-XO766HB4.js} +2 -2
  38. package/dist/{coordinator-prompt-ZWBMAIWA.js → coordinator-prompt-NYR5TPBD.js} +6 -5
  39. package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-UCQJTFA7.js} +6 -5
  40. package/dist/{global-workspace-2SIPM4PW.js → global-workspace-4QHDAD2D.js} +7 -6
  41. package/dist/{global-workspace-OJRXWXEA.js → global-workspace-4SENNWBU.js} +7 -6
  42. package/dist/index.cjs +1002 -575
  43. package/dist/index.d.cts +91 -10
  44. package/dist/index.d.ts +91 -10
  45. package/dist/index.js +268 -93
  46. package/dist/mcp/run-stdio.cjs +980 -580
  47. package/dist/mcp/run-stdio.js +196 -43
  48. package/dist/{orchestrator-OVYITCO6.js → orchestrator-GZE4X3XV.js} +14 -11
  49. package/dist/{orchestrator-NWIU5TJP.js → orchestrator-QSBRWME5.js} +16 -13
  50. package/dist/{plan-file-6O7G4VPQ.js → plan-file-5S5TUNAW.js} +2 -2
  51. package/dist/{plan-file-PHVKUAEE.js → plan-file-IBSU2PVW.js} +2 -2
  52. package/dist/{run-XQKGHQZ2.js → run-CAGKZLHA.js} +1 -1
  53. package/dist/{run-USF6FRKV.js → run-EBWL2Q4N.js} +1 -1
  54. package/dist/{workspaces-UUJNOO4T.js → workspaces-7S7QKCUE.js} +8 -7
  55. package/dist/{workspaces-3NUUZTQK.js → workspaces-RDUSB6FD.js} +8 -7
  56. package/dist/{worktree-RZRJNHYL.js → worktree-63AGPPLO.js} +5 -4
  57. package/dist/{worktree-UCWWTVLS.js → worktree-JIZ3QMZX.js} +5 -4
  58. package/dist/worktree-exclude-6MQWGWV5.js +11 -0
  59. package/dist/worktree-exclude-TV6EV6BS.js +9 -0
  60. package/package.json +1 -1
@@ -1527,7 +1527,7 @@ function looksLikeRetryableRunnerCrash(text5) {
1527
1527
  const lower = text5.trim().toLowerCase();
1528
1528
  if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
1529
1529
  if (!lower) return true;
1530
- return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
1530
+ return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|network request failed|cursor startup failed:.+\(retryable\)|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
1531
1531
  lower
1532
1532
  );
1533
1533
  }
@@ -1595,6 +1595,9 @@ function humanizeAgentFailDetail(detail) {
1595
1595
  if (/connection stalled/.test(lower)) {
1596
1596
  return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
1597
1597
  }
1598
+ if (/network request failed|cursor startup failed:.+\(retryable\)/.test(lower)) {
1599
+ return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (a transient Cursor SDK network error).`;
1600
+ }
1598
1601
  return raw;
1599
1602
  }
1600
1603
  function turnFailChatText(opts) {
@@ -1761,16 +1764,98 @@ var init_path = __esm({
1761
1764
  }
1762
1765
  });
1763
1766
 
1767
+ // src/git/github-agent-auth.ts
1768
+ function githubAgentAuthDir() {
1769
+ const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
1770
+ if (override) return override;
1771
+ return (0, import_node_path12.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
1772
+ }
1773
+ function githubCredentialStorePath() {
1774
+ return (0, import_node_path12.join)(githubAgentAuthDir(), "git-credentials");
1775
+ }
1776
+ function githubGhConfigDir() {
1777
+ return (0, import_node_path12.join)(githubAgentAuthDir(), "gh");
1778
+ }
1779
+ function writePrivateFile2(file, body) {
1780
+ (0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(file), { recursive: true, mode: 448 });
1781
+ try {
1782
+ (0, import_node_fs11.chmodSync)((0, import_node_path12.dirname)(file), 448);
1783
+ } catch {
1784
+ }
1785
+ (0, import_node_fs11.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
1786
+ try {
1787
+ (0, import_node_fs11.chmodSync)(file, 384);
1788
+ } catch {
1789
+ }
1790
+ }
1791
+ function gitCredentialStoreContents(token) {
1792
+ return `https://x-access-token:${encodeURIComponent(token)}@github.com
1793
+ `;
1794
+ }
1795
+ function ghHostsYml(token, user = "x-access-token") {
1796
+ const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
1797
+ return [
1798
+ "github.com:",
1799
+ " git_protocol: https",
1800
+ ` user: ${u}`,
1801
+ ` oauth_token: ${token}`,
1802
+ " users:",
1803
+ ` ${u}:`,
1804
+ ` oauth_token: ${token}`,
1805
+ ""
1806
+ ].join("\n");
1807
+ }
1808
+ function materializeGithubAgentAuth(token, user) {
1809
+ const trimmed = token.trim();
1810
+ if (!trimmed) return;
1811
+ const root = githubAgentAuthDir();
1812
+ (0, import_node_fs11.mkdirSync)(root, { recursive: true, mode: 448 });
1813
+ try {
1814
+ (0, import_node_fs11.chmodSync)(root, 448);
1815
+ } catch {
1816
+ }
1817
+ writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
1818
+ const ghDir = githubGhConfigDir();
1819
+ (0, import_node_fs11.mkdirSync)(ghDir, { recursive: true, mode: 448 });
1820
+ writePrivateFile2((0, import_node_path12.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
1821
+ writePrivateFile2((0, import_node_path12.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
1822
+ }
1823
+ function githubAgentAuthReady() {
1824
+ return (0, import_node_fs11.existsSync)(githubCredentialStorePath()) && (0, import_node_fs11.existsSync)((0, import_node_path12.join)(githubGhConfigDir(), "hosts.yml"));
1825
+ }
1826
+ function githubCredentialHelperGitConfig() {
1827
+ const file = githubCredentialStorePath();
1828
+ return [
1829
+ { key: "credential.helper", value: "" },
1830
+ { key: "credential.helper", value: `store --file=${file}` }
1831
+ ];
1832
+ }
1833
+ function githubGhConfigEnv() {
1834
+ return {
1835
+ GH_CONFIG_DIR: githubGhConfigDir(),
1836
+ GH_PROMPT_DISABLED: "1"
1837
+ };
1838
+ }
1839
+ var import_node_fs11, import_node_os4, import_node_path12;
1840
+ var init_github_agent_auth = __esm({
1841
+ "src/git/github-agent-auth.ts"() {
1842
+ "use strict";
1843
+ import_node_fs11 = require("fs");
1844
+ import_node_os4 = require("os");
1845
+ import_node_path12 = require("path");
1846
+ }
1847
+ });
1848
+
1764
1849
  // src/git/stale-lock.ts
1765
1850
  function isIndexLockError(text5) {
1766
1851
  return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
1767
1852
  }
1768
1853
  function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
1769
- const lockPath = (0, import_node_path12.join)(gitDir, "index.lock");
1854
+ const lockPath = (0, import_node_path13.join)(gitDir, "index.lock");
1770
1855
  try {
1771
- if (!(0, import_node_fs11.existsSync)(lockPath)) return null;
1772
- if (now - (0, import_node_fs11.statSync)(lockPath).mtimeMs < maxAgeMs) return null;
1773
- (0, import_node_fs11.unlinkSync)(lockPath);
1856
+ if (!(0, import_node_fs12.existsSync)(lockPath)) return null;
1857
+ if (now - (0, import_node_fs12.statSync)(lockPath).mtimeMs < maxAgeMs) return null;
1858
+ (0, import_node_fs12.unlinkSync)(lockPath);
1774
1859
  return lockPath;
1775
1860
  } catch {
1776
1861
  return null;
@@ -1785,12 +1870,12 @@ function clearStaleIndexLocks(gitDirs, maxAgeMs = STALE_INDEX_LOCK_MS) {
1785
1870
  }
1786
1871
  return removed;
1787
1872
  }
1788
- var import_node_fs11, import_node_path12, STALE_INDEX_LOCK_MS;
1873
+ var import_node_fs12, import_node_path13, STALE_INDEX_LOCK_MS;
1789
1874
  var init_stale_lock = __esm({
1790
1875
  "src/git/stale-lock.ts"() {
1791
1876
  "use strict";
1792
- import_node_fs11 = require("fs");
1793
- import_node_path12 = require("path");
1877
+ import_node_fs12 = require("fs");
1878
+ import_node_path13 = require("path");
1794
1879
  STALE_INDEX_LOCK_MS = 2e4;
1795
1880
  }
1796
1881
  });
@@ -1887,7 +1972,10 @@ async function gh(args, cwd, opts) {
1887
1972
  timeoutMs: opts?.timeoutMs,
1888
1973
  env: {
1889
1974
  GH_PROMPT_DISABLED: "1",
1890
- GIT_TERMINAL_PROMPT: "0"
1975
+ GIT_TERMINAL_PROMPT: "0",
1976
+ // Isolated hosts.yml uses git_protocol: https so `gh pr create` does not
1977
+ // shell out over SSH when Settings → Git is SSH (ask_git in Electron).
1978
+ ...githubAgentAuthReady() ? githubGhConfigEnv() : {}
1891
1979
  }
1892
1980
  });
1893
1981
  }
@@ -1903,6 +1991,7 @@ var init_run = __esm({
1903
1991
  "use strict";
1904
1992
  import_execa2 = require("execa");
1905
1993
  init_path();
1994
+ init_github_agent_auth();
1906
1995
  init_stale_lock();
1907
1996
  }
1908
1997
  });
@@ -2741,6 +2830,18 @@ var init_worktree_labels = __esm({
2741
2830
  function isGhRateLimitError(text5) {
2742
2831
  return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
2743
2832
  }
2833
+ function isGhPrBodyTooLongError(text5) {
2834
+ return /body is too long|body.{0,20}too long|maximum is 65536|exceeds the maximum allowed size|request (entity |is )?too large|payload too large|413 Request Entity Too Large/i.test(
2835
+ text5
2836
+ );
2837
+ }
2838
+ function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
2839
+ const t = body.replace(/\s+$/u, "");
2840
+ if (t.length <= max) return t;
2841
+ const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
2842
+ const keep = Math.max(0, max - note.length);
2843
+ return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
2844
+ }
2744
2845
  function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
2745
2846
  const ms = resetEpochSec * 1e3 - nowMs;
2746
2847
  if (ms <= 0) return "soon";
@@ -2751,18 +2852,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
2751
2852
  const hours = Math.ceil(mins / 60);
2752
2853
  return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
2753
2854
  }
2855
+ function omitGhBodyArg(text5) {
2856
+ return text5.replace(
2857
+ /--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
2858
+ "--body <omitted>"
2859
+ );
2860
+ }
2861
+ function capGhErrorText(text5, max = 400) {
2862
+ const t = text5.trim();
2863
+ if (t.length <= max) return t;
2864
+ return `${t.slice(0, max - 1).trimEnd()}\u2026`;
2865
+ }
2754
2866
  function extractGhErrorDetail(text5) {
2755
- const trimmed = text5.trim();
2867
+ const trimmed = omitGhBodyArg(text5.trim());
2756
2868
  if (!trimmed) return "";
2869
+ if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
2870
+ return "GraphQL: body is too long (GitHub PR body / request size limit).";
2871
+ }
2757
2872
  const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
2758
- if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}`;
2873
+ if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
2759
2874
  const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
2760
- if (http?.[1]) return `HTTP: ${http[1].trim()}`;
2875
+ if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
2761
2876
  const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
2762
2877
  if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
2763
- return lines.slice(1).join(" ").trim() || lines[0];
2878
+ return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
2764
2879
  }
2765
- return trimmed;
2880
+ return capGhErrorText(trimmed);
2766
2881
  }
2767
2882
  function formatGhLandError(raw, opts) {
2768
2883
  const trimmed = raw.trim();
@@ -2780,6 +2895,10 @@ function formatGhLandError(raw, opts) {
2780
2895
  const hint = opts?.targetedRepo ? ` Branch was pushed to origin \u2014 confirm it exists on GitHub and differs from the base branch.${target}${head}.` : " Often `gh` targeted upstream instead of origin. Branch was pushed \u2014 retry in the latest Sideboard, or run: gh pr create -R <owner/name> --base main --head <branch>.";
2781
2896
  return `Could not create the pull request.${hint}`;
2782
2897
  }
2898
+ if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
2899
+ const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
2900
+ return `GitHub rejected the pull request: the GraphQL body is too long (PR description / request size, limit ${GITHUB_PR_BODY_MAX_CHARS} characters).${pushNote} Retry with a short title and body via \`gh pr create --body-file\` (or send_to_thread so the worktree agent writes a brief description). Do not paste a changelog or diff into --body.`;
2901
+ }
2783
2902
  if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
2784
2903
  const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
2785
2904
  const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
@@ -2800,15 +2919,82 @@ function formatMergePrError(raw) {
2800
2919
  }
2801
2920
  return extractGhErrorDetail(trimmed) || trimmed;
2802
2921
  }
2922
+ var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
2803
2923
  var init_gh_errors = __esm({
2804
2924
  "src/git/gh-errors.ts"() {
2805
2925
  "use strict";
2926
+ GITHUB_PR_BODY_MAX_CHARS = 65536;
2927
+ GITHUB_PR_BODY_SAFE_CHARS = 6e4;
2928
+ }
2929
+ });
2930
+
2931
+ // src/git/worktree-exclude.ts
2932
+ var worktree_exclude_exports = {};
2933
+ __export(worktree_exclude_exports, {
2934
+ WORKTREE_SIDEBOARD_EXCLUDE: () => WORKTREE_SIDEBOARD_EXCLUDE,
2935
+ ensureWorktreeSideboardIgnored: () => ensureWorktreeSideboardIgnored
2936
+ });
2937
+ function excludeHasSideboard(body) {
2938
+ return body.split(/\r?\n/).some((line) => {
2939
+ const t = line.trim();
2940
+ return t === ".sideboard/" || t === ".sideboard" || t === "/.sideboard/";
2941
+ });
2942
+ }
2943
+ async function ensureWorktreeSideboardIgnored(worktreePath) {
2944
+ if (!worktreePath.trim()) return;
2945
+ const gitDir = await git(["rev-parse", "--absolute-git-dir"], worktreePath, {
2946
+ reject: false,
2947
+ timeoutMs: 5e3
2948
+ });
2949
+ if (gitDir.exitCode !== 0) return;
2950
+ const dir = gitDir.stdout.trim();
2951
+ if (!dir) return;
2952
+ const excludePath = (0, import_node_path14.join)(dir, "info", "exclude");
2953
+ (0, import_node_fs13.mkdirSync)((0, import_node_path14.dirname)(excludePath), { recursive: true });
2954
+ let body = "";
2955
+ try {
2956
+ body = (0, import_node_fs13.readFileSync)(excludePath, "utf8");
2957
+ } catch {
2958
+ body = "";
2959
+ }
2960
+ if (!excludeHasSideboard(body)) {
2961
+ const prefix = body && !body.endsWith("\n") ? `${body}
2962
+ ` : body;
2963
+ (0, import_node_fs13.writeFileSync)(
2964
+ excludePath,
2965
+ `${prefix}${EXCLUDE_COMMENT}
2966
+ ${WORKTREE_SIDEBOARD_EXCLUDE}
2967
+ `,
2968
+ "utf8"
2969
+ );
2970
+ }
2971
+ const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
2972
+ reject: false,
2973
+ timeoutMs: 5e3
2974
+ });
2975
+ if (listed.exitCode !== 0 || !listed.stdout) return;
2976
+ const files = listed.stdout.split("\0").filter(Boolean);
2977
+ if (files.length === 0) return;
2978
+ await git(["update-index", "--skip-worktree", "--", ...files], worktreePath, {
2979
+ reject: false,
2980
+ timeoutMs: 8e3
2981
+ });
2982
+ }
2983
+ var import_node_fs13, import_node_path14, WORKTREE_SIDEBOARD_EXCLUDE, EXCLUDE_COMMENT;
2984
+ var init_worktree_exclude = __esm({
2985
+ "src/git/worktree-exclude.ts"() {
2986
+ "use strict";
2987
+ import_node_fs13 = require("fs");
2988
+ import_node_path14 = require("path");
2989
+ init_run();
2990
+ WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
2991
+ EXCLUDE_COMMENT = "# Sideboard worktree scratch \u2014 do not commit";
2806
2992
  }
2807
2993
  });
2808
2994
 
2809
2995
  // src/store/secret-vault.ts
2810
2996
  function secretVaultPath() {
2811
- return (0, import_node_path13.join)(appDataDir(), "secrets.json");
2997
+ return (0, import_node_path15.join)(appDataDir(), "secrets.json");
2812
2998
  }
2813
2999
  function loadSecretVault() {
2814
3000
  const parsed = readSecureJson(secretVaultPath());
@@ -2867,11 +3053,11 @@ function normalizeVault(raw) {
2867
3053
  }
2868
3054
  return out;
2869
3055
  }
2870
- var import_node_path13;
3056
+ var import_node_path15;
2871
3057
  var init_secret_vault = __esm({
2872
3058
  "src/store/secret-vault.ts"() {
2873
3059
  "use strict";
2874
- import_node_path13 = require("path");
3060
+ import_node_path15 = require("path");
2875
3061
  init_paths();
2876
3062
  init_secure_file();
2877
3063
  }
@@ -2900,6 +3086,7 @@ var init_issue_source_labels = __esm({
2900
3086
  // src/store/app-settings.ts
2901
3087
  var app_settings_exports = {};
2902
3088
  __export(app_settings_exports, {
3089
+ FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
2903
3090
  GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
2904
3091
  HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
2905
3092
  ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
@@ -2925,6 +3112,7 @@ __export(app_settings_exports, {
2925
3112
  disconnectLinearConnection: () => disconnectLinearConnection,
2926
3113
  emptyPublicIntegrations: () => emptyPublicIntegrations,
2927
3114
  ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
3115
+ followUpBehavior: () => followUpBehavior,
2928
3116
  getAbleTimeAccessToken: () => getAbleTimeAccessToken,
2929
3117
  getAbleTimeHost: () => getAbleTimeHost,
2930
3118
  getDefaultAgent: () => getDefaultAgent,
@@ -3033,10 +3221,10 @@ function toPublicAppSettings(settings) {
3033
3221
  };
3034
3222
  }
3035
3223
  function appSettingsPath() {
3036
- return (0, import_node_path14.join)(appDataDir(), "settings.json");
3224
+ return (0, import_node_path16.join)(appDataDir(), "settings.json");
3037
3225
  }
3038
3226
  function claudeUserSettingsPath() {
3039
- return (0, import_node_path14.join)((0, import_node_os4.homedir)(), ".claude", "settings.json");
3227
+ return (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".claude", "settings.json");
3040
3228
  }
3041
3229
  function normalizeClaude(raw) {
3042
3230
  if (!raw || typeof raw !== "object") return {};
@@ -3281,6 +3469,9 @@ function normalizeAdvanced(raw) {
3281
3469
  if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
3282
3470
  out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
3283
3471
  }
3472
+ if (source.followUpBehavior === "queue" || source.followUpBehavior === "steer") {
3473
+ out.followUpBehavior = source.followUpBehavior;
3474
+ }
3284
3475
  return out;
3285
3476
  }
3286
3477
  function normalizeSettings(raw) {
@@ -3340,10 +3531,10 @@ function normalizeSettings(raw) {
3340
3531
  }
3341
3532
  function readSettingsFile() {
3342
3533
  const path = appSettingsPath();
3343
- if (!(0, import_node_fs12.existsSync)(path)) return { ...EMPTY_SETTINGS };
3534
+ if (!(0, import_node_fs14.existsSync)(path)) return { ...EMPTY_SETTINGS };
3344
3535
  try {
3345
3536
  chmodOwnerOnly(path);
3346
- const parsed = JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
3537
+ const parsed = JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8"));
3347
3538
  return normalizeSettings(parsed);
3348
3539
  } catch {
3349
3540
  return { ...EMPTY_SETTINGS };
@@ -3889,7 +4080,7 @@ function ensureSlackDeviceIdentity(settings = loadAppSettings()) {
3889
4080
  }
3890
4081
  if (!deviceLabel) {
3891
4082
  try {
3892
- deviceLabel = (0, import_node_os4.hostname)().split(".")[0]?.trim() || "This Mac";
4083
+ deviceLabel = (0, import_node_os5.hostname)().split(".")[0]?.trim() || "This Mac";
3893
4084
  } catch {
3894
4085
  deviceLabel = "This Mac";
3895
4086
  }
@@ -3972,6 +4163,9 @@ function updateAdvancedSettings(patch) {
3972
4163
  if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
3973
4164
  advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
3974
4165
  }
4166
+ if (patch.followUpBehavior === "queue" || patch.followUpBehavior === "steer") {
4167
+ advanced.followUpBehavior = patch.followUpBehavior;
4168
+ }
3975
4169
  return saveAppSettings({ ...current, advanced });
3976
4170
  }
3977
4171
  function autoRenameBranchEnabled(settings = loadAppSettings()) {
@@ -4017,6 +4211,9 @@ function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
4017
4211
  }
4018
4212
  return "cursor";
4019
4213
  }
4214
+ function followUpBehavior(settings = loadAppSettings()) {
4215
+ return settings.advanced.followUpBehavior === "queue" ? "queue" : "steer";
4216
+ }
4020
4217
  function maxConcurrentAgents(settings = loadAppSettings()) {
4021
4218
  const n = settings.advanced.maxConcurrent;
4022
4219
  if (typeof n === "number" && Number.isFinite(n)) {
@@ -4104,14 +4301,14 @@ function childEnvWithAppSettings(extra) {
4104
4301
  function harnessEnvKey(harness) {
4105
4302
  return HARNESS_ENV_KEYS[harness];
4106
4303
  }
4107
- var import_node_crypto3, import_node_fs12, import_node_os4, import_node_path14, HARNESS_ENV_KEYS, DEFAULT_AGENTS, GITHUB_GIT_AUTH_MODES, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, GIT_AUTH_MODES, EMPTY_SETTINGS, DEFAULT_CLI_BIN;
4304
+ var import_node_crypto3, import_node_fs14, import_node_os5, import_node_path16, HARNESS_ENV_KEYS, DEFAULT_AGENTS, GITHUB_GIT_AUTH_MODES, FOLLOW_UP_BEHAVIORS, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, GIT_AUTH_MODES, EMPTY_SETTINGS, DEFAULT_CLI_BIN;
4108
4305
  var init_app_settings = __esm({
4109
4306
  "src/store/app-settings.ts"() {
4110
4307
  "use strict";
4111
4308
  import_node_crypto3 = require("crypto");
4112
- import_node_fs12 = require("fs");
4113
- import_node_os4 = require("os");
4114
- import_node_path14 = require("path");
4309
+ import_node_fs14 = require("fs");
4310
+ import_node_os5 = require("os");
4311
+ import_node_path16 = require("path");
4115
4312
  init_thinking_effort();
4116
4313
  init_nested_electron_env();
4117
4314
  init_paths();
@@ -4133,6 +4330,7 @@ var init_app_settings = __esm({
4133
4330
  "cursor"
4134
4331
  ]);
4135
4332
  GITHUB_GIT_AUTH_MODES = ["auto", "gh", "ssh", "token"];
4333
+ FOLLOW_UP_BEHAVIORS = ["steer", "queue"];
4136
4334
  CLOUD_CONNECT_AGENTS = /* @__PURE__ */ new Set([
4137
4335
  "claude",
4138
4336
  "codex",
@@ -4160,89 +4358,26 @@ var init_app_settings = __esm({
4160
4358
  }
4161
4359
  });
4162
4360
 
4163
- // src/git/github-agent-auth.ts
4164
- function githubAgentAuthDir() {
4165
- const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
4166
- if (override) return override;
4167
- return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".sideboard-git-auth");
4168
- }
4169
- function githubCredentialStorePath() {
4170
- return (0, import_node_path15.join)(githubAgentAuthDir(), "git-credentials");
4171
- }
4172
- function githubGhConfigDir() {
4173
- return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
4174
- }
4175
- function writePrivateFile2(file, body) {
4176
- (0, import_node_fs13.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
4177
- try {
4178
- (0, import_node_fs13.chmodSync)((0, import_node_path15.dirname)(file), 448);
4179
- } catch {
4180
- }
4181
- (0, import_node_fs13.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
4182
- try {
4183
- (0, import_node_fs13.chmodSync)(file, 384);
4184
- } catch {
4361
+ // src/git/git-auth-mode.ts
4362
+ function githubHttpsInsteadOfEntries(remoteUrl) {
4363
+ const entries = [...HTTPS_REWRITE];
4364
+ const url = remoteUrl?.trim() ?? "";
4365
+ const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
4366
+ if (scpAlias?.[1]) {
4367
+ entries.push({
4368
+ key: "url.https://github.com/.insteadOf",
4369
+ value: `${scpAlias[1]}:`
4370
+ });
4185
4371
  }
4186
- }
4187
- function gitCredentialStoreContents(token) {
4188
- return `https://x-access-token:${encodeURIComponent(token)}@github.com
4189
- `;
4190
- }
4191
- function ghHostsYml(token, user = "x-access-token") {
4192
- const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
4193
- return [
4194
- "github.com:",
4195
- " git_protocol: https",
4196
- ` user: ${u}`,
4197
- ` oauth_token: ${token}`,
4198
- " users:",
4199
- ` ${u}:`,
4200
- ` oauth_token: ${token}`,
4201
- ""
4202
- ].join("\n");
4203
- }
4204
- function materializeGithubAgentAuth(token, user) {
4205
- const trimmed = token.trim();
4206
- if (!trimmed) return;
4207
- const root = githubAgentAuthDir();
4208
- (0, import_node_fs13.mkdirSync)(root, { recursive: true, mode: 448 });
4209
- try {
4210
- (0, import_node_fs13.chmodSync)(root, 448);
4211
- } catch {
4372
+ const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
4373
+ if (sshAlias?.[1]) {
4374
+ entries.push({
4375
+ key: "url.https://github.com/.insteadOf",
4376
+ value: `ssh://git@${sshAlias[1]}/`
4377
+ });
4212
4378
  }
4213
- writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
4214
- const ghDir = githubGhConfigDir();
4215
- (0, import_node_fs13.mkdirSync)(ghDir, { recursive: true, mode: 448 });
4216
- writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
4217
- writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
4218
- }
4219
- function githubAgentAuthReady() {
4220
- return (0, import_node_fs13.existsSync)(githubCredentialStorePath()) && (0, import_node_fs13.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
4221
- }
4222
- function githubCredentialHelperGitConfig() {
4223
- const file = githubCredentialStorePath();
4224
- return [
4225
- { key: "credential.helper", value: "" },
4226
- { key: "credential.helper", value: `store --file=${file}` }
4227
- ];
4228
- }
4229
- function githubGhConfigEnv() {
4230
- return {
4231
- GH_CONFIG_DIR: githubGhConfigDir(),
4232
- GH_PROMPT_DISABLED: "1"
4233
- };
4379
+ return entries;
4234
4380
  }
4235
- var import_node_fs13, import_node_os5, import_node_path15;
4236
- var init_github_agent_auth = __esm({
4237
- "src/git/github-agent-auth.ts"() {
4238
- "use strict";
4239
- import_node_fs13 = require("fs");
4240
- import_node_os5 = require("os");
4241
- import_node_path15 = require("path");
4242
- }
4243
- });
4244
-
4245
- // src/git/git-auth-mode.ts
4246
4381
  function nonInteractiveGitProcessEnv() {
4247
4382
  return {
4248
4383
  GIT_TERMINAL_PROMPT: "0",
@@ -4265,16 +4400,19 @@ function appendIndexedGitConfig(existing, entries) {
4265
4400
  out.GIT_CONFIG_COUNT = String(count + entries.length);
4266
4401
  return out;
4267
4402
  }
4268
- function githubAgentGitEnv(existing) {
4403
+ function githubAgentGitEnv(existing, opts) {
4269
4404
  const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
4270
- return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
4405
+ return appendIndexedGitConfig(existing, [
4406
+ ...githubHttpsInsteadOfEntries(opts?.remoteUrl),
4407
+ ...helpers
4408
+ ]);
4271
4409
  }
4272
4410
  function applyGithubGitAuthEnv(existing, opts) {
4273
4411
  const out = { ...nonInteractiveGitProcessEnv() };
4274
4412
  const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
4275
4413
  if (token) materializeGithubAgentAuth(token);
4276
4414
  Object.assign(out, githubGhConfigEnv());
4277
- if (opts.mode === "ssh") return out;
4415
+ if (opts.mode === "ssh" && !token) return out;
4278
4416
  Object.assign(out, githubAgentGitEnv(existing));
4279
4417
  return out;
4280
4418
  }
@@ -4330,7 +4468,7 @@ async function warmGithubAgentAuth(opts) {
4330
4468
  }
4331
4469
  function normalizeWritableRoot(raw) {
4332
4470
  const trimmed = raw.trim().replace(/\/+$/, "");
4333
- return trimmed && (0, import_node_path16.isAbsolute)(trimmed) ? trimmed : null;
4471
+ return trimmed && (0, import_node_path17.isAbsolute)(trimmed) ? trimmed : null;
4334
4472
  }
4335
4473
  async function resolveCodexGitWritableRoots(cwd) {
4336
4474
  const roots = /* @__PURE__ */ new Set();
@@ -4387,8 +4525,9 @@ function formatGitAuthModeDirective(mode) {
4387
4525
  case "ssh":
4388
4526
  return [
4389
4527
  "Git authentication (Settings \u2192 Git mode: SSH):",
4390
- "- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
4391
- "- SSH is batch-mode: it will not prompt for a Keychain password. If push fails with `Permission denied (publickey)`, tell the user to unlock ssh-agent or switch Settings \u2192 Git to Auto / gh CLI \u2014 do not rewrite remotes yourself.",
4528
+ "- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
4529
+ "- This process may push over HTTPS via `gh` (process-only `insteadOf`) so ask_git / unattended turns work when ssh-agent is missing \u2014 that does not change the stored remote.",
4530
+ "- SSH is batch-mode: it will not prompt for a Keychain password. If both SSH and HTTPS fail, tell the user to unlock ssh-agent or run `gh auth login` (or switch Settings \u2192 Git to Auto).",
4392
4531
  "- `gh` already authenticates for PRs/API (no token in the environment). Do not set GitHub token environment variables or run `gh auth login` from this turn.",
4393
4532
  "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
4394
4533
  ].join("\n");
@@ -4407,11 +4546,11 @@ function formatGitAuthModeDirective(mode) {
4407
4546
  ].join("\n");
4408
4547
  }
4409
4548
  }
4410
- var import_node_path16, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4549
+ var import_node_path17, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4411
4550
  var init_git_auth_mode = __esm({
4412
4551
  "src/git/git-auth-mode.ts"() {
4413
4552
  "use strict";
4414
- import_node_path16 = require("path");
4553
+ import_node_path17 = require("path");
4415
4554
  init_app_settings();
4416
4555
  init_github_agent_auth();
4417
4556
  init_run();
@@ -4759,7 +4898,7 @@ function attachmentsGitignoreBody() {
4759
4898
  }
4760
4899
  function isWorkspaceScratchPath(relativePath) {
4761
4900
  const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
4762
- return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
4901
+ return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
4763
4902
  }
4764
4903
  var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
4765
4904
  var init_workspace_scratch = __esm({
@@ -4866,7 +5005,7 @@ async function resolveRepoRoot(cwd) {
4866
5005
  }
4867
5006
  function canonicalizeRepoPath(path) {
4868
5007
  try {
4869
- return (0, import_node_fs14.realpathSync)(path);
5008
+ return (0, import_node_fs15.realpathSync)(path);
4870
5009
  } catch {
4871
5010
  return path.replace(/\/+$/, "");
4872
5011
  }
@@ -5605,6 +5744,16 @@ function originFetchBranch(sourceRef) {
5605
5744
  if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
5606
5745
  return ref;
5607
5746
  }
5747
+ async function originRemoteUrl(cwd) {
5748
+ const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
5749
+ return result.exitCode === 0 ? result.stdout.trim() : "";
5750
+ }
5751
+ function githubHttpsRetryEnv(remoteUrl) {
5752
+ return {
5753
+ GIT_TERMINAL_PROMPT: "0",
5754
+ ...githubAgentGitEnv(void 0, { remoteUrl })
5755
+ };
5756
+ }
5608
5757
  async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5609
5758
  const first = await git(args, repoPath, { reject: false, timeoutMs });
5610
5759
  if (first.exitCode === 0) return true;
@@ -5614,15 +5763,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5614
5763
  } catch {
5615
5764
  return false;
5616
5765
  }
5617
- if (mode === "ssh") return false;
5618
5766
  const token = await resolveGithubAgentToken(mode, repoPath);
5619
5767
  if (!token) return false;
5768
+ const remoteUrl = await originRemoteUrl(repoPath);
5620
5769
  const tryHttps = async (header) => git(args, repoPath, {
5621
5770
  reject: false,
5622
5771
  timeoutMs,
5623
- env: { GIT_TERMINAL_PROMPT: "0" },
5772
+ env: githubHttpsRetryEnv(remoteUrl),
5624
5773
  config: {
5625
- "url.https://github.com/.insteadOf": "git@github.com:",
5626
5774
  "http.extraHeader": header
5627
5775
  }
5628
5776
  });
@@ -5704,8 +5852,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
5704
5852
  }
5705
5853
  async function createThreadWorktree(opts) {
5706
5854
  let branchName = `thread/${opts.slug}`;
5707
- const worktreePath = (0, import_node_path17.join)(worktreesRoot(opts.repoPath), opts.slug);
5708
- if ((0, import_node_fs14.existsSync)(worktreePath)) {
5855
+ const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
5856
+ if ((0, import_node_fs15.existsSync)(worktreePath)) {
5709
5857
  throw new Error(`Worktree already exists at ${worktreePath}`);
5710
5858
  }
5711
5859
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5740,13 +5888,14 @@ ${add.stdout}`;
5740
5888
  });
5741
5889
  branchName = added;
5742
5890
  await ensureGhPreferOrigin(worktreePath);
5891
+ await ensureWorktreeSideboardIgnored(worktreePath);
5743
5892
  return { branchName, worktreePath };
5744
5893
  }
5745
5894
  async function createExistingBranchWorktree(opts) {
5746
5895
  const branchName = opts.branchName.trim();
5747
5896
  if (!branchName) throw new Error("branch name required");
5748
- const worktreePath = (0, import_node_path17.join)(worktreesRoot(opts.repoPath), opts.slug);
5749
- if ((0, import_node_fs14.existsSync)(worktreePath)) {
5897
+ const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
5898
+ if ((0, import_node_fs15.existsSync)(worktreePath)) {
5750
5899
  throw new Error(`Worktree already exists at ${worktreePath}`);
5751
5900
  }
5752
5901
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5784,6 +5933,7 @@ async function createExistingBranchWorktree(opts) {
5784
5933
  await git(["checkout", "-B", branchName], worktreePath, { reject: false });
5785
5934
  }
5786
5935
  await ensureGhPreferOrigin(worktreePath);
5936
+ await ensureWorktreeSideboardIgnored(worktreePath);
5787
5937
  return { branchName, worktreePath };
5788
5938
  }
5789
5939
  async function removeWorktree(repoPath, worktreePath, opts) {
@@ -5872,7 +6022,9 @@ async function currentBranch(worktreePath) {
5872
6022
  async function commitAll(worktreePath, message) {
5873
6023
  const dirty = await isDirty(worktreePath);
5874
6024
  if (!dirty) return false;
6025
+ await ensureWorktreeSideboardIgnored(worktreePath);
5875
6026
  await git(["add", "-A"], worktreePath);
6027
+ await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
5876
6028
  await git(["commit", "-m", message], worktreePath);
5877
6029
  return true;
5878
6030
  }
@@ -5886,14 +6038,14 @@ async function pushBranch(worktreePath, branchName) {
5886
6038
  const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
5887
6039
  if (!slug || !token) {
5888
6040
  throw new Error(
5889
- sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
6041
+ sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
5890
6042
  );
5891
6043
  }
6044
+ const remoteUrl = await originRemoteUrl(worktreePath);
5892
6045
  const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
5893
6046
  reject: false,
5894
- env: { GIT_TERMINAL_PROMPT: "0" },
6047
+ env: githubHttpsRetryEnv(remoteUrl),
5895
6048
  config: {
5896
- "url.https://github.com/.insteadOf": "git@github.com:",
5897
6049
  "http.extraHeader": header
5898
6050
  }
5899
6051
  });
@@ -6023,6 +6175,32 @@ async function createOrUpdatePr(worktreePath, opts) {
6023
6175
  const repoArgs = ghRepoSelectArgs(slug);
6024
6176
  const headRef = ghHeadRef(slug, opts.head);
6025
6177
  const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
6178
+ const bodyText = clampGithubPrBody(opts.body ?? opts.title);
6179
+ const bodyFile = (0, import_node_path18.join)(
6180
+ (0, import_node_os6.tmpdir)(),
6181
+ `sideboard-pr-body-${process.pid}-${(0, import_node_crypto4.randomBytes)(6).toString("hex")}.md`
6182
+ );
6183
+ (0, import_node_fs15.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
6184
+ `, "utf8");
6185
+ const bodyArgs = ["--body-file", bodyFile];
6186
+ try {
6187
+ return await createOrUpdatePrWithBodyFile(worktreePath, {
6188
+ ...opts,
6189
+ slug,
6190
+ repoArgs,
6191
+ headRef,
6192
+ branchOnly,
6193
+ bodyArgs
6194
+ });
6195
+ } finally {
6196
+ try {
6197
+ (0, import_node_fs15.unlinkSync)(bodyFile);
6198
+ } catch {
6199
+ }
6200
+ }
6201
+ }
6202
+ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
6203
+ const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
6026
6204
  const existing = await gh(
6027
6205
  [...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
6028
6206
  worktreePath,
@@ -6038,8 +6216,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6038
6216
  branchOnly,
6039
6217
  "--title",
6040
6218
  opts.title,
6041
- "--body",
6042
- opts.body ?? opts.title
6219
+ ...bodyArgs
6043
6220
  ],
6044
6221
  worktreePath,
6045
6222
  { reject: false }
@@ -6054,8 +6231,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6054
6231
  "--web",
6055
6232
  "--title",
6056
6233
  opts.title,
6057
- "--body",
6058
- opts.body ?? opts.title,
6234
+ ...bodyArgs,
6059
6235
  "--base",
6060
6236
  opts.base,
6061
6237
  "--head",
@@ -6076,8 +6252,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6076
6252
  "create",
6077
6253
  "--title",
6078
6254
  opts.title,
6079
- "--body",
6080
- opts.body ?? opts.title,
6255
+ ...bodyArgs,
6081
6256
  "--base",
6082
6257
  opts.base,
6083
6258
  "--head",
@@ -6101,10 +6276,10 @@ function sameRepoPath(a, b) {
6101
6276
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
6102
6277
  }
6103
6278
  function listLocalThreadBranchSlugs(repoPath) {
6104
- const refsDir = (0, import_node_path17.join)(repoPath, ".git", "refs", "heads", "thread");
6105
- if (!(0, import_node_fs14.existsSync)(refsDir)) return [];
6279
+ const refsDir = (0, import_node_path18.join)(repoPath, ".git", "refs", "heads", "thread");
6280
+ if (!(0, import_node_fs15.existsSync)(refsDir)) return [];
6106
6281
  try {
6107
- return (0, import_node_fs14.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6282
+ return (0, import_node_fs15.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6108
6283
  } catch {
6109
6284
  return [];
6110
6285
  }
@@ -6112,8 +6287,8 @@ function listLocalThreadBranchSlugs(repoPath) {
6112
6287
  function collectTakenTeamSlugs(repoPath) {
6113
6288
  const taken = /* @__PURE__ */ new Set();
6114
6289
  const root = worktreesRoot(repoPath);
6115
- if ((0, import_node_fs14.existsSync)(root)) {
6116
- for (const entry of (0, import_node_fs14.readdirSync)(root, { withFileTypes: true })) {
6290
+ if ((0, import_node_fs15.existsSync)(root)) {
6291
+ for (const entry of (0, import_node_fs15.readdirSync)(root, { withFileTypes: true })) {
6117
6292
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
6118
6293
  taken.add(normalizeTakenSlug(entry.name));
6119
6294
  }
@@ -6134,23 +6309,26 @@ function allocateTeamSlug(repoPath) {
6134
6309
  const taken = collectTakenTeamSlugs(repoPath);
6135
6310
  for (let attempt = 0; attempt < 32; attempt++) {
6136
6311
  const team = allocateTeamName(taken);
6137
- const path = (0, import_node_path17.join)(worktreesRoot(repoPath), team.slug);
6138
- if (!(0, import_node_fs14.existsSync)(path)) return team;
6312
+ const path = (0, import_node_path18.join)(worktreesRoot(repoPath), team.slug);
6313
+ if (!(0, import_node_fs15.existsSync)(path)) return team;
6139
6314
  taken.add(team.slug);
6140
6315
  }
6141
6316
  throw new Error("No available soccer team worktree directories left");
6142
6317
  }
6143
- var import_node_fs14, import_node_path17;
6318
+ var import_node_crypto4, import_node_fs15, import_node_os6, import_node_path18;
6144
6319
  var init_worktree = __esm({
6145
6320
  "src/git/worktree.ts"() {
6146
6321
  "use strict";
6147
- import_node_fs14 = require("fs");
6148
- import_node_path17 = require("path");
6322
+ import_node_crypto4 = require("crypto");
6323
+ import_node_fs15 = require("fs");
6324
+ import_node_os6 = require("os");
6325
+ import_node_path18 = require("path");
6149
6326
  init_paths();
6150
6327
  init_thread_store();
6151
6328
  init_teams();
6152
6329
  init_worktree_labels();
6153
6330
  init_gh_errors();
6331
+ init_worktree_exclude();
6154
6332
  init_git_auth_mode();
6155
6333
  init_run();
6156
6334
  init_repo_git_lock();
@@ -6194,7 +6372,7 @@ var init_cloud_connect_constants = __esm({
6194
6372
 
6195
6373
  // src/composer/stage-files.ts
6196
6374
  function fileExtension(filePath) {
6197
- const base = (0, import_node_path18.basename)(filePath).toLowerCase();
6375
+ const base = (0, import_node_path19.basename)(filePath).toLowerCase();
6198
6376
  return base.includes(".") ? base.split(".").pop() || "" : "";
6199
6377
  }
6200
6378
  function isImageFilePath(filePath) {
@@ -6204,24 +6382,24 @@ function imageMimeType(filePath) {
6204
6382
  return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
6205
6383
  }
6206
6384
  function ensureAttachmentsDir(worktreePath) {
6207
- const dir = (0, import_node_path18.join)(worktreePath, ATTACHMENTS_DIR);
6208
- (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
6209
- const gi = (0, import_node_path18.join)(dir, ".gitignore");
6210
- if (!(0, import_node_fs15.existsSync)(gi)) {
6211
- (0, import_node_fs15.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
6385
+ const dir = (0, import_node_path19.join)(worktreePath, ATTACHMENTS_DIR);
6386
+ (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
6387
+ const gi = (0, import_node_path19.join)(dir, ".gitignore");
6388
+ if (!(0, import_node_fs16.existsSync)(gi)) {
6389
+ (0, import_node_fs16.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
6212
6390
  }
6213
6391
  return dir;
6214
6392
  }
6215
6393
  function uniqueAttachmentName(dir, originalName) {
6216
6394
  const safe = originalName.replace(/[/\\]/g, "_") || "file";
6217
- if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, safe))) return safe;
6218
- const ext = (0, import_node_path18.extname)(safe);
6395
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path19.join)(dir, safe))) return safe;
6396
+ const ext = (0, import_node_path19.extname)(safe);
6219
6397
  const stem = ext ? safe.slice(0, -ext.length) : safe;
6220
6398
  for (let i = 1; i < 1e4; i++) {
6221
6399
  const candidate = `${stem}-${i}${ext}`;
6222
- if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, candidate))) return candidate;
6400
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path19.join)(dir, candidate))) return candidate;
6223
6401
  }
6224
- return `${stem}-${(0, import_node_crypto4.randomUUID)()}${ext}`;
6402
+ return `${stem}-${(0, import_node_crypto5.randomUUID)()}${ext}`;
6225
6403
  }
6226
6404
  function previewDataUrlFromBuf(filePath, buf) {
6227
6405
  if (!isImageFilePath(filePath)) return void 0;
@@ -6233,7 +6411,7 @@ function attachmentFromBuffer(name, buf, opts) {
6233
6411
  if (isImageFilePath(name)) {
6234
6412
  const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
6235
6413
  return {
6236
- id: (0, import_node_crypto4.randomUUID)(),
6414
+ id: (0, import_node_crypto5.randomUUID)(),
6237
6415
  name,
6238
6416
  kind: "file",
6239
6417
  path: opts.path,
@@ -6246,7 +6424,7 @@ function attachmentFromBuffer(name, buf, opts) {
6246
6424
  }
6247
6425
  if (buf.length > MAX_INLINE_BYTES) {
6248
6426
  return {
6249
- id: (0, import_node_crypto4.randomUUID)(),
6427
+ id: (0, import_node_crypto5.randomUUID)(),
6250
6428
  name,
6251
6429
  kind: "file",
6252
6430
  path: opts.path,
@@ -6255,7 +6433,7 @@ function attachmentFromBuffer(name, buf, opts) {
6255
6433
  }
6256
6434
  if (buf.includes(0)) {
6257
6435
  return {
6258
- id: (0, import_node_crypto4.randomUUID)(),
6436
+ id: (0, import_node_crypto5.randomUUID)(),
6259
6437
  name,
6260
6438
  kind: "file",
6261
6439
  path: opts.path,
@@ -6263,7 +6441,7 @@ function attachmentFromBuffer(name, buf, opts) {
6263
6441
  };
6264
6442
  }
6265
6443
  return {
6266
- id: (0, import_node_crypto4.randomUUID)(),
6444
+ id: (0, import_node_crypto5.randomUUID)(),
6267
6445
  name,
6268
6446
  kind: "file",
6269
6447
  path: opts.path,
@@ -6275,19 +6453,19 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
6275
6453
  const dir = ensureAttachmentsDir(worktreePath);
6276
6454
  const out = [];
6277
6455
  for (const abs of absolutePaths) {
6278
- const originalName = (0, import_node_path18.basename)(abs);
6456
+ const originalName = (0, import_node_path19.basename)(abs);
6279
6457
  try {
6280
- const st = (0, import_node_fs15.statSync)(abs);
6458
+ const st = (0, import_node_fs16.statSync)(abs);
6281
6459
  if (!st.isFile()) continue;
6282
6460
  const name = uniqueAttachmentName(dir, originalName);
6283
- const destAbs = (0, import_node_path18.join)(dir, name);
6284
- (0, import_node_fs15.copyFileSync)(abs, destAbs);
6461
+ const destAbs = (0, import_node_path19.join)(dir, name);
6462
+ (0, import_node_fs16.copyFileSync)(abs, destAbs);
6285
6463
  const rel = `${ATTACHMENTS_DIR}/${name}`;
6286
- const buf = (0, import_node_fs15.readFileSync)(destAbs);
6464
+ const buf = (0, import_node_fs16.readFileSync)(destAbs);
6287
6465
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
6288
6466
  } catch (err) {
6289
6467
  out.push({
6290
- id: (0, import_node_crypto4.randomUUID)(),
6468
+ id: (0, import_node_crypto5.randomUUID)(),
6291
6469
  name: originalName,
6292
6470
  kind: "file",
6293
6471
  content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
@@ -6305,13 +6483,13 @@ function stageBuffersAsAttachments(worktreePath, buffers2) {
6305
6483
  try {
6306
6484
  const buf = Buffer.from(item.dataBase64, "base64");
6307
6485
  const name = uniqueAttachmentName(dir, originalName);
6308
- const destAbs = (0, import_node_path18.join)(dir, name);
6309
- (0, import_node_fs15.writeFileSync)(destAbs, buf);
6486
+ const destAbs = (0, import_node_path19.join)(dir, name);
6487
+ (0, import_node_fs16.writeFileSync)(destAbs, buf);
6310
6488
  const rel = `${ATTACHMENTS_DIR}/${name}`;
6311
6489
  out.push(attachmentFromBuffer(name, buf, { path: rel }));
6312
6490
  } catch (err) {
6313
6491
  out.push({
6314
- id: (0, import_node_crypto4.randomUUID)(),
6492
+ id: (0, import_node_crypto5.randomUUID)(),
6315
6493
  name: originalName,
6316
6494
  kind: "file",
6317
6495
  content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
@@ -6366,23 +6544,23 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
6366
6544
  for (const rel of relativePaths) {
6367
6545
  if (!rel || rel.includes("..") || rel.startsWith("/")) {
6368
6546
  out.push({
6369
- id: (0, import_node_crypto4.randomUUID)(),
6370
- name: (0, import_node_path18.basename)(rel) || "file",
6547
+ id: (0, import_node_crypto5.randomUUID)(),
6548
+ name: (0, import_node_path19.basename)(rel) || "file",
6371
6549
  kind: "file",
6372
6550
  content: `(invalid path: ${rel})`
6373
6551
  });
6374
6552
  continue;
6375
6553
  }
6376
- const name = (0, import_node_path18.basename)(rel);
6554
+ const name = (0, import_node_path19.basename)(rel);
6377
6555
  try {
6378
- const abs = (0, import_node_path18.join)(worktreePath, rel);
6379
- const st = (0, import_node_fs15.statSync)(abs);
6556
+ const abs = (0, import_node_path19.join)(worktreePath, rel);
6557
+ const st = (0, import_node_fs16.statSync)(abs);
6380
6558
  if (!st.isFile()) continue;
6381
- const buf = (0, import_node_fs15.readFileSync)(abs);
6559
+ const buf = (0, import_node_fs16.readFileSync)(abs);
6382
6560
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
6383
6561
  } catch (err) {
6384
6562
  out.push({
6385
- id: (0, import_node_crypto4.randomUUID)(),
6563
+ id: (0, import_node_crypto5.randomUUID)(),
6386
6564
  name,
6387
6565
  kind: "file",
6388
6566
  content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
@@ -6391,13 +6569,13 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
6391
6569
  }
6392
6570
  return out;
6393
6571
  }
6394
- var import_node_fs15, import_node_path18, import_node_crypto4, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
6572
+ var import_node_fs16, import_node_path19, import_node_crypto5, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
6395
6573
  var init_stage_files = __esm({
6396
6574
  "src/composer/stage-files.ts"() {
6397
6575
  "use strict";
6398
- import_node_fs15 = require("fs");
6399
- import_node_path18 = require("path");
6400
- import_node_crypto4 = require("crypto");
6576
+ import_node_fs16 = require("fs");
6577
+ import_node_path19 = require("path");
6578
+ import_node_crypto5 = require("crypto");
6401
6579
  init_workspace_scratch();
6402
6580
  IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
6403
6581
  "png",
@@ -6514,7 +6692,7 @@ function coordinatorTurnReminder(opts) {
6514
6692
  function ensureGlobalCoordinatorCwd(opts) {
6515
6693
  const dir = globalAgentCwd();
6516
6694
  try {
6517
- (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
6695
+ (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
6518
6696
  } catch {
6519
6697
  return dir;
6520
6698
  }
@@ -6522,7 +6700,7 @@ function ensureGlobalCoordinatorCwd(opts) {
6522
6700
  let orchId = opts?.orchestratorThreadId?.trim() || "";
6523
6701
  if (!orchId) {
6524
6702
  try {
6525
- const existing = (0, import_node_fs16.readFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), "utf8");
6703
+ const existing = (0, import_node_fs17.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
6526
6704
  const m = existing.match(
6527
6705
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
6528
6706
  );
@@ -6565,9 +6743,9 @@ function ensureGlobalCoordinatorCwd(opts) {
6565
6743
  "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."
6566
6744
  ].join("\n");
6567
6745
  try {
6568
- (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "CLAUDE.md"), `${body}
6746
+ (0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
6569
6747
  `, "utf8");
6570
- (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), `${body}
6748
+ (0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
6571
6749
  `, "utf8");
6572
6750
  } catch {
6573
6751
  }
@@ -6599,12 +6777,12 @@ function coordinatorSystemPrompt(opts) {
6599
6777
  formatWorkspaceInventory(opts.workspaces)
6600
6778
  ].join("\n");
6601
6779
  }
6602
- var import_node_fs16, import_node_path19, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6780
+ var import_node_fs17, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6603
6781
  var init_coordinator_prompt = __esm({
6604
6782
  "src/orchestrator/coordinator-prompt.ts"() {
6605
6783
  "use strict";
6606
- import_node_fs16 = require("fs");
6607
- import_node_path19 = require("path");
6784
+ import_node_fs17 = require("fs");
6785
+ import_node_path20 = require("path");
6608
6786
  init_worktree();
6609
6787
  init_app_settings();
6610
6788
  init_paths();
@@ -6614,8 +6792,8 @@ var init_coordinator_prompt = __esm({
6614
6792
  "Discover:",
6615
6793
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
6616
6794
  "- list_board \u2014 Home Kanban of worktrees (New / Draft / Review / Merged; one card per checkout). Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind, column, limit.",
6617
- "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues)",
6618
- "- linear_list_teams / linear_get_issue / linear_create_issue / linear_update_issue / linear_comment \u2014 Linear Account connection; call linear_list_teams for team key and workflow states; pass ENG-123 or uuid. linear_get_issue returns comments, relations, parent/children, and the rest of the issue metadata. If mutations fail with a scope error, Disconnect and Connect Linear in Account settings.",
6795
+ "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues). list_issues accepts query and assignee (me / unassigned / all / user id) so Linear is not limited to tickets assigned to you.",
6796
+ "- linear_list_teams / linear_search_issues / linear_get_issue / linear_create_issue / linear_update_issue / linear_comment \u2014 Linear Account connection; call linear_list_teams for team key and workflow states; pass ENG-123 or uuid. linear_search_issues finds unassigned and other people's open issues (assignee=unassigned|all|me|user). linear_get_issue returns comments, relations, parent/children, and the rest of the issue metadata. If mutations fail with a scope error, Disconnect and Connect Linear in Account settings.",
6619
6797
  "- abletime_orientation / abletime_list_projects / abletime_list_tasks / abletime_search_tasks / abletime_get_task / abletime_create_task / abletime_ensure_task \u2014 AbleTime Account personal access token (hosted MCP). Call orientation first. If work has no task yet, abletime_ensure_task creates one to track against (or create_thread from the default branch does that automatically when AbleTime is the preferred issue source).",
6620
6798
  "- 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",
6621
6799
  "- 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`). 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).",
@@ -6634,7 +6812,7 @@ var init_coordinator_prompt = __esm({
6634
6812
  "- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
6635
6813
  "- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
6636
6814
  "- send_to_thread \u2014 queue a prompt (start/continue a chat turn). force_stop: true only to replace a wrong in-flight request \u2014 never to check in, resume after a halt notice, or because wait_for_turn returned stillRunning (that kills the child mid-thought)",
6637
- "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
6815
+ "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). stillRunning is the source of truth \u2014 if it is false, the child is not working; do not tell the user it is running or \u201Cwaiting for a gate,\u201D even if status still says running/queued. If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. If stillRunning stays true across many waits with the same lastActivityAt, the child is stuck \u2014 tell the user; do not invent a gate. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
6638
6816
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
6639
6817
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
6640
6818
  "Setup / run:",
@@ -6643,7 +6821,7 @@ var init_coordinator_prompt = __esm({
6643
6821
  "Inspect / review / PRs:",
6644
6822
  "- get_diff \u2014 compact diff summary",
6645
6823
  '- 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',
6646
- "- 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.",
6824
+ "- 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.",
6647
6825
  '- 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.',
6648
6826
  '- 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.',
6649
6827
  "Process guides:",
@@ -6914,32 +7092,32 @@ var init_global_workspace = __esm({
6914
7092
  function brightsyConfigPath() {
6915
7093
  const override = process.env.BRIGHTSY_CONFIG?.trim();
6916
7094
  if (override) return override;
6917
- return (0, import_node_path20.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
7095
+ return (0, import_node_path21.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
6918
7096
  }
6919
7097
  function loadBrightsyConfig() {
6920
7098
  const path = brightsyConfigPath();
6921
- if (!(0, import_node_fs17.existsSync)(path)) {
7099
+ if (!(0, import_node_fs18.existsSync)(path)) {
6922
7100
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
6923
7101
  }
6924
- const raw = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
7102
+ const raw = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
6925
7103
  if (!raw.access_token || !raw.account_id) {
6926
7104
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
6927
7105
  }
6928
7106
  return raw;
6929
7107
  }
6930
7108
  function saveBrightsyConfig(cfg) {
6931
- (0, import_node_fs17.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7109
+ (0, import_node_fs18.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6932
7110
  `, {
6933
7111
  mode: 384
6934
7112
  });
6935
7113
  }
6936
- var import_node_fs17, import_node_os6, import_node_path20;
7114
+ var import_node_fs18, import_node_os7, import_node_path21;
6937
7115
  var init_config = __esm({
6938
7116
  "src/brightsy/config.ts"() {
6939
7117
  "use strict";
6940
- import_node_fs17 = require("fs");
6941
- import_node_os6 = require("os");
6942
- import_node_path20 = require("path");
7118
+ import_node_fs18 = require("fs");
7119
+ import_node_os7 = require("os");
7120
+ import_node_path21 = require("path");
6943
7121
  }
6944
7122
  });
6945
7123
 
@@ -7056,22 +7234,22 @@ var init_oauth = __esm({
7056
7234
 
7057
7235
  // src/brightsy/connected-teams.ts
7058
7236
  function storePath4() {
7059
- return (0, import_node_path21.join)(appDataDir(), "brightsy-teams.json");
7237
+ return (0, import_node_path22.join)(appDataDir(), "brightsy-teams.json");
7060
7238
  }
7061
7239
  function readStore4() {
7062
7240
  const path = storePath4();
7063
- if (!(0, import_node_fs18.existsSync)(path)) return [];
7241
+ if (!(0, import_node_fs19.existsSync)(path)) return [];
7064
7242
  try {
7065
- const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
7243
+ const parsed = JSON.parse((0, import_node_fs19.readFileSync)(path, "utf8"));
7066
7244
  return Array.isArray(parsed.teams) ? parsed.teams : [];
7067
7245
  } catch {
7068
7246
  return [];
7069
7247
  }
7070
7248
  }
7071
7249
  function writeStore2(teams) {
7072
- (0, import_node_fs18.mkdirSync)(appDataDir(), { recursive: true });
7250
+ (0, import_node_fs19.mkdirSync)(appDataDir(), { recursive: true });
7073
7251
  const path = storePath4();
7074
- (0, import_node_fs18.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
7252
+ (0, import_node_fs19.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
7075
7253
  `, {
7076
7254
  mode: 384
7077
7255
  });
@@ -7177,12 +7355,12 @@ function brightsyMcpServerName(slug) {
7177
7355
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
7178
7356
  return `brightsy_${cleaned || "team"}`;
7179
7357
  }
7180
- var import_node_fs18, import_node_path21;
7358
+ var import_node_fs19, import_node_path22;
7181
7359
  var init_connected_teams = __esm({
7182
7360
  "src/brightsy/connected-teams.ts"() {
7183
7361
  "use strict";
7184
- import_node_fs18 = require("fs");
7185
- import_node_path21 = require("path");
7362
+ import_node_fs19 = require("fs");
7363
+ import_node_path22 = require("path");
7186
7364
  init_paths();
7187
7365
  init_accounts();
7188
7366
  init_config();
@@ -7554,11 +7732,11 @@ async function syncCliForTarget(accountId) {
7554
7732
  }
7555
7733
  applyConnectedTeamToCli(team);
7556
7734
  }
7557
- var import_node_fs19, brightsyAdapter;
7735
+ var import_node_fs20, brightsyAdapter;
7558
7736
  var init_brightsy = __esm({
7559
7737
  "src/agents/brightsy.ts"() {
7560
7738
  "use strict";
7561
- import_node_fs19 = require("fs");
7739
+ import_node_fs20 = require("fs");
7562
7740
  init_run();
7563
7741
  init_connected_teams();
7564
7742
  init_config();
@@ -7573,7 +7751,7 @@ var init_brightsy = __esm({
7573
7751
  async detect() {
7574
7752
  const brightsy = resolveAgentExecutable("brightsy");
7575
7753
  if (brightsy !== "brightsy") {
7576
- if (!(0, import_node_fs19.existsSync)(brightsy)) {
7754
+ if (!(0, import_node_fs20.existsSync)(brightsy)) {
7577
7755
  return {
7578
7756
  agent: "brightsy",
7579
7757
  installed: false,
@@ -7804,6 +7982,13 @@ function isSubagentToolName(name) {
7804
7982
  if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
7805
7983
  return /connectedAgentRequest/i.test(n);
7806
7984
  }
7985
+ function isInternalAgentStatusText(text5) {
7986
+ const t = text5.trim();
7987
+ if (!t) return false;
7988
+ if (/waiting for gate to pass/i.test(t)) return true;
7989
+ if (/^agent is running\b/i.test(t) && t.length < 160) return true;
7990
+ return false;
7991
+ }
7807
7992
  function isPollWrapperToolName(name) {
7808
7993
  const n = (name ?? "").replace(/[_-]/g, "");
7809
7994
  return /^(taskoutput|taskstop|sleep)$/i.test(n);
@@ -7811,7 +7996,10 @@ function isPollWrapperToolName(name) {
7811
7996
  function lastTextPart(parts, type) {
7812
7997
  for (let i = parts.length - 1; i >= 0; i--) {
7813
7998
  const p = parts[i];
7814
- if (p.type === type && p.text.trim()) return p.text.trim();
7999
+ if (p.type !== type) continue;
8000
+ const text5 = p.text.trim();
8001
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
8002
+ return text5;
7815
8003
  }
7816
8004
  return "";
7817
8005
  }
@@ -8148,43 +8336,43 @@ function electronResourcesPath() {
8148
8336
  function packagedCursorRuntimeDir() {
8149
8337
  const resources = electronResourcesPath();
8150
8338
  if (!resources) return null;
8151
- const dir = (0, import_node_path22.join)(resources, "cursor-runtime");
8152
- if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
8339
+ const dir = (0, import_node_path23.join)(resources, "cursor-runtime");
8340
+ if (!(0, import_node_fs21.existsSync)((0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
8153
8341
  return dir;
8154
8342
  }
8155
8343
  function packagedCursorRunnerPath() {
8156
8344
  const dir = packagedCursorRuntimeDir();
8157
- return dir ? (0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
8345
+ return dir ? (0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
8158
8346
  }
8159
8347
  function packagedMcpDir() {
8160
8348
  const resources = electronResourcesPath();
8161
8349
  if (!resources) return null;
8162
- const dir = (0, import_node_path22.join)(resources, "sideboard-mcp");
8163
- if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
8350
+ const dir = (0, import_node_path23.join)(resources, "sideboard-mcp");
8351
+ if (!(0, import_node_fs21.existsSync)((0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
8164
8352
  return dir;
8165
8353
  }
8166
8354
  function packagedMcpStdioPath() {
8167
8355
  const dir = packagedMcpDir();
8168
- return dir ? (0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
8356
+ return dir ? (0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
8169
8357
  }
8170
8358
  function packagedBundledNodePath() {
8171
8359
  const resources = electronResourcesPath();
8172
8360
  if (!resources) return null;
8173
- const bin = (0, import_node_path22.join)(resources, "node", "bin", "node");
8174
- if (!(0, import_node_fs20.existsSync)(bin)) return null;
8361
+ const bin = (0, import_node_path23.join)(resources, "node", "bin", "node");
8362
+ if (!(0, import_node_fs21.existsSync)(bin)) return null;
8175
8363
  return bin;
8176
8364
  }
8177
8365
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
8178
8366
  const dir = packagedCursorRuntimeDir();
8179
8367
  if (!dir) return null;
8180
- return (0, import_node_path22.join)(dir, "node_modules", platformPkg, "bin", binName);
8368
+ return (0, import_node_path23.join)(dir, "node_modules", platformPkg, "bin", binName);
8181
8369
  }
8182
- var import_node_fs20, import_node_path22;
8370
+ var import_node_fs21, import_node_path23;
8183
8371
  var init_packaged_runtime = __esm({
8184
8372
  "src/agents/packaged-runtime.ts"() {
8185
8373
  "use strict";
8186
- import_node_fs20 = require("fs");
8187
- import_node_path22 = require("path");
8374
+ import_node_fs21 = require("fs");
8375
+ import_node_path23 = require("path");
8188
8376
  }
8189
8377
  });
8190
8378
 
@@ -8218,7 +8406,7 @@ function unpackedAsarPath(filePath) {
8218
8406
  if (!isAsarPath(filePath)) return null;
8219
8407
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
8220
8408
  if (unpacked === filePath) return null;
8221
- return (0, import_node_fs21.existsSync)(unpacked) ? unpacked : null;
8409
+ return (0, import_node_fs22.existsSync)(unpacked) ? unpacked : null;
8222
8410
  }
8223
8411
  function nodeReadableScriptPath(scriptPath) {
8224
8412
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -8258,37 +8446,37 @@ function pickPreferredNode(candidates) {
8258
8446
  return best;
8259
8447
  }
8260
8448
  function versionDirNodeBins(root, toBin) {
8261
- if (!(0, import_node_fs21.existsSync)(root)) return [];
8449
+ if (!(0, import_node_fs22.existsSync)(root)) return [];
8262
8450
  try {
8263
- return (0, import_node_fs21.readdirSync)(root).map(toBin);
8451
+ return (0, import_node_fs22.readdirSync)(root).map(toBin);
8264
8452
  } catch {
8265
8453
  return [];
8266
8454
  }
8267
8455
  }
8268
- function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
8456
+ function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
8269
8457
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
8270
- (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path23.join)(prefix, "opt", `node@${major}`, "bin", "node"))
8458
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path24.join)(prefix, "opt", `node@${major}`, "bin", "node"))
8271
8459
  );
8272
8460
  return [
8273
8461
  ...kegs,
8274
8462
  "/opt/homebrew/bin/node",
8275
8463
  "/usr/local/bin/node",
8276
- (0, import_node_path23.join)(home, ".local/share/fnm/aliases/default/bin/node"),
8277
- (0, import_node_path23.join)(home, ".nvm/current/bin/node"),
8278
- (0, import_node_path23.join)(home, ".volta/bin/node"),
8279
- (0, import_node_path23.join)(home, ".asdf/shims/node"),
8280
- (0, import_node_path23.join)(home, ".local/share/mise/shims/node"),
8464
+ (0, import_node_path24.join)(home, ".local/share/fnm/aliases/default/bin/node"),
8465
+ (0, import_node_path24.join)(home, ".nvm/current/bin/node"),
8466
+ (0, import_node_path24.join)(home, ".volta/bin/node"),
8467
+ (0, import_node_path24.join)(home, ".asdf/shims/node"),
8468
+ (0, import_node_path24.join)(home, ".local/share/mise/shims/node"),
8281
8469
  ...versionDirNodeBins(
8282
- (0, import_node_path23.join)(home, ".nvm", "versions", "node"),
8283
- (name) => (0, import_node_path23.join)(home, ".nvm", "versions", "node", name, "bin", "node")
8470
+ (0, import_node_path24.join)(home, ".nvm", "versions", "node"),
8471
+ (name) => (0, import_node_path24.join)(home, ".nvm", "versions", "node", name, "bin", "node")
8284
8472
  ),
8285
8473
  ...versionDirNodeBins(
8286
- (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions"),
8287
- (name) => (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
8474
+ (0, import_node_path24.join)(home, ".local/share/fnm", "node-versions"),
8475
+ (name) => (0, import_node_path24.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
8288
8476
  ),
8289
8477
  ...versionDirNodeBins(
8290
- (0, import_node_path23.join)(home, ".volta", "tools", "image", "node"),
8291
- (name) => (0, import_node_path23.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
8478
+ (0, import_node_path24.join)(home, ".volta", "tools", "image", "node"),
8479
+ (name) => (0, import_node_path24.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
8292
8480
  )
8293
8481
  ];
8294
8482
  }
@@ -8297,10 +8485,10 @@ function uniqueExistingNodeBins(paths) {
8297
8485
  const out = [];
8298
8486
  for (const raw of paths) {
8299
8487
  const p = raw.trim();
8300
- if (!p || !(0, import_node_fs21.existsSync)(p) || isElectronLikeCommand(p)) continue;
8488
+ if (!p || !(0, import_node_fs22.existsSync)(p) || isElectronLikeCommand(p)) continue;
8301
8489
  let key = p;
8302
8490
  try {
8303
- key = (0, import_node_fs21.realpathSync)(p);
8491
+ key = (0, import_node_fs22.realpathSync)(p);
8304
8492
  } catch {
8305
8493
  continue;
8306
8494
  }
@@ -8380,13 +8568,13 @@ async function resolveNodeLaunch(scriptPath) {
8380
8568
  env: { ELECTRON_RUN_AS_NODE: "1" }
8381
8569
  };
8382
8570
  }
8383
- var import_node_fs21, import_node_os7, import_node_path23, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
8571
+ var import_node_fs22, import_node_os8, import_node_path24, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
8384
8572
  var init_node_launch = __esm({
8385
8573
  "src/agents/node-launch.ts"() {
8386
8574
  "use strict";
8387
- import_node_fs21 = require("fs");
8388
- import_node_os7 = require("os");
8389
- import_node_path23 = require("path");
8575
+ import_node_fs22 = require("fs");
8576
+ import_node_os8 = require("os");
8577
+ import_node_path24 = require("path");
8390
8578
  init_nested_electron_env();
8391
8579
  init_run();
8392
8580
  init_packaged_runtime();
@@ -8480,37 +8668,37 @@ function corePackageDir() {
8480
8668
  try {
8481
8669
  const url = import_meta.url;
8482
8670
  if (typeof url === "string" && url.length > 0) {
8483
- return (0, import_node_path24.dirname)((0, import_node_url.fileURLToPath)(url));
8671
+ return (0, import_node_path25.dirname)((0, import_node_url.fileURLToPath)(url));
8484
8672
  }
8485
8673
  } catch {
8486
8674
  }
8487
8675
  try {
8488
- const req = (0, import_node_module.createRequire)((0, import_node_path24.join)(process.cwd(), "package.json"));
8489
- return (0, import_node_path24.dirname)(req.resolve("@sideboard-ai/core"));
8676
+ const req = (0, import_node_module.createRequire)((0, import_node_path25.join)(process.cwd(), "package.json"));
8677
+ return (0, import_node_path25.dirname)(req.resolve("@sideboard-ai/core"));
8490
8678
  } catch {
8491
8679
  return process.cwd();
8492
8680
  }
8493
8681
  }
8494
8682
  function findSideboardMcpJsEntry() {
8495
8683
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
8496
- if (override && (0, import_node_fs22.existsSync)(override)) return override;
8684
+ if (override && (0, import_node_fs23.existsSync)(override)) return override;
8497
8685
  const packaged = packagedMcpStdioPath();
8498
8686
  if (packaged) return packaged;
8499
8687
  let dir = corePackageDir();
8500
8688
  for (let i = 0; i < 10; i++) {
8501
8689
  const candidates = [
8502
- (0, import_node_path24.join)(dir, "mcp/run-stdio.js"),
8503
- (0, import_node_path24.join)(dir, "mcp/run-stdio.cjs"),
8504
- (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.js"),
8505
- (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.cjs"),
8506
- (0, import_node_path24.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
8507
- (0, import_node_path24.join)(dir, "packages/cli/dist/index.js"),
8508
- (0, import_node_path24.join)(dir, "cli/dist/index.js")
8690
+ (0, import_node_path25.join)(dir, "mcp/run-stdio.js"),
8691
+ (0, import_node_path25.join)(dir, "mcp/run-stdio.cjs"),
8692
+ (0, import_node_path25.join)(dir, "dist/mcp/run-stdio.js"),
8693
+ (0, import_node_path25.join)(dir, "dist/mcp/run-stdio.cjs"),
8694
+ (0, import_node_path25.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
8695
+ (0, import_node_path25.join)(dir, "packages/cli/dist/index.js"),
8696
+ (0, import_node_path25.join)(dir, "cli/dist/index.js")
8509
8697
  ];
8510
8698
  for (const p of candidates) {
8511
- if ((0, import_node_fs22.existsSync)(p) && !isAsarPath(p)) return p;
8699
+ if ((0, import_node_fs23.existsSync)(p) && !isAsarPath(p)) return p;
8512
8700
  }
8513
- const parent = (0, import_node_path24.dirname)(dir);
8701
+ const parent = (0, import_node_path25.dirname)(dir);
8514
8702
  if (parent === dir) break;
8515
8703
  dir = parent;
8516
8704
  }
@@ -8652,19 +8840,19 @@ function writeMcpServersConfig(servers) {
8652
8840
  ...env ? { env } : {}
8653
8841
  };
8654
8842
  }
8655
- const dir = (0, import_node_fs22.mkdtempSync)((0, import_node_path24.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
8656
- const cfgPath = (0, import_node_path24.join)(dir, "mcp.json");
8657
- (0, import_node_fs22.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8843
+ const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path25.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
8844
+ const cfgPath = (0, import_node_path25.join)(dir, "mcp.json");
8845
+ (0, import_node_fs23.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8658
8846
  return cfgPath;
8659
8847
  }
8660
- var import_node_fs22, import_node_module, import_node_os8, import_node_path24, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
8848
+ var import_node_fs23, import_node_module, import_node_os9, import_node_path25, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
8661
8849
  var init_injected_mcp = __esm({
8662
8850
  "src/agents/injected-mcp.ts"() {
8663
8851
  "use strict";
8664
- import_node_fs22 = require("fs");
8852
+ import_node_fs23 = require("fs");
8665
8853
  import_node_module = require("module");
8666
- import_node_os8 = require("os");
8667
- import_node_path24 = require("path");
8854
+ import_node_os9 = require("os");
8855
+ import_node_path25 = require("path");
8668
8856
  import_node_url = require("url");
8669
8857
  init_run();
8670
8858
  init_config();
@@ -9003,11 +9191,11 @@ function parseIssuesJson(raw) {
9003
9191
  }
9004
9192
  return [];
9005
9193
  }
9006
- var import_node_fs23, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
9194
+ var import_node_fs24, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
9007
9195
  var init_claude = __esm({
9008
9196
  "src/agents/claude.ts"() {
9009
9197
  "use strict";
9010
- import_node_fs23 = require("fs");
9198
+ import_node_fs24 = require("fs");
9011
9199
  init_run();
9012
9200
  init_app_settings();
9013
9201
  init_claude_mcp();
@@ -9047,7 +9235,7 @@ var init_claude = __esm({
9047
9235
  async detect() {
9048
9236
  const claude = resolveClaudeExecutable();
9049
9237
  if (claude !== "claude") {
9050
- if (!(0, import_node_fs23.existsSync)(claude)) {
9238
+ if (!(0, import_node_fs24.existsSync)(claude)) {
9051
9239
  return {
9052
9240
  agent: "claude",
9053
9241
  installed: false,
@@ -9302,7 +9490,7 @@ async function listCodexModels() {
9302
9490
  if (codex === "codex") {
9303
9491
  const which = await run("which", ["codex"], { reject: false });
9304
9492
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
9305
- } else if (!(0, import_node_fs24.existsSync)(codex)) {
9493
+ } else if (!(0, import_node_fs25.existsSync)(codex)) {
9306
9494
  return FALLBACK_CODEX_MODELS;
9307
9495
  }
9308
9496
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -9337,12 +9525,12 @@ function usageFromCodex(usage) {
9337
9525
  }
9338
9526
  function codexConfigHasNetworkAccess() {
9339
9527
  const candidates = [
9340
- (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
9341
- (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
9528
+ (0, import_node_path26.join)((0, import_node_os10.homedir)(), ".codex", "config.toml"),
9529
+ (0, import_node_path26.join)((0, import_node_os10.homedir)(), ".config", "codex", "config.toml")
9342
9530
  ];
9343
9531
  for (const path of candidates) {
9344
- if (!(0, import_node_fs24.existsSync)(path)) continue;
9345
- const text5 = (0, import_node_fs24.readFileSync)(path, "utf8");
9532
+ if (!(0, import_node_fs25.existsSync)(path)) continue;
9533
+ const text5 = (0, import_node_fs25.readFileSync)(path, "utf8");
9346
9534
  if (/network_access\s*=\s*true/.test(text5)) return true;
9347
9535
  }
9348
9536
  return false;
@@ -9374,21 +9562,21 @@ function asRecord2(value) {
9374
9562
  return void 0;
9375
9563
  }
9376
9564
  function codexLooksAuthenticated() {
9377
- const authPath = (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
9378
- if (!(0, import_node_fs24.existsSync)(authPath)) return false;
9565
+ const authPath = (0, import_node_path26.join)((0, import_node_os10.homedir)(), ".codex", "auth.json");
9566
+ if (!(0, import_node_fs25.existsSync)(authPath)) return false;
9379
9567
  try {
9380
- return (0, import_node_fs24.statSync)(authPath).size > 2;
9568
+ return (0, import_node_fs25.statSync)(authPath).size > 2;
9381
9569
  } catch {
9382
9570
  return false;
9383
9571
  }
9384
9572
  }
9385
- var import_node_fs24, import_node_os9, import_node_path25, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
9573
+ var import_node_fs25, import_node_os10, import_node_path26, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
9386
9574
  var init_codex = __esm({
9387
9575
  "src/agents/codex.ts"() {
9388
9576
  "use strict";
9389
- import_node_fs24 = require("fs");
9390
- import_node_os9 = require("os");
9391
- import_node_path25 = require("path");
9577
+ import_node_fs25 = require("fs");
9578
+ import_node_os10 = require("os");
9579
+ import_node_path26 = require("path");
9392
9580
  init_run();
9393
9581
  init_app_settings();
9394
9582
  init_global_workspace();
@@ -9413,7 +9601,7 @@ var init_codex = __esm({
9413
9601
  async detect() {
9414
9602
  const codex = resolveAgentExecutable("codex");
9415
9603
  if (codex !== "codex") {
9416
- if (!(0, import_node_fs24.existsSync)(codex)) {
9604
+ if (!(0, import_node_fs25.existsSync)(codex)) {
9417
9605
  return {
9418
9606
  agent: "codex",
9419
9607
  installed: false,
@@ -9900,21 +10088,21 @@ function platformRipgrepPackage() {
9900
10088
  }
9901
10089
  function usableRipgrepPath(candidate) {
9902
10090
  const raw = candidate?.trim();
9903
- if (!raw || !(0, import_node_path26.isAbsolute)(raw)) return null;
10091
+ if (!raw || !(0, import_node_path27.isAbsolute)(raw)) return null;
9904
10092
  const readable = nodeReadableScriptPath(raw);
9905
- if (!(0, import_node_fs25.existsSync)(readable) || isAsarPath(readable)) return null;
10093
+ if (!(0, import_node_fs26.existsSync)(readable) || isAsarPath(readable)) return null;
9906
10094
  return readable;
9907
10095
  }
9908
10096
  function walkForBundledRipgrep(startFile) {
9909
10097
  if (!startFile) return null;
9910
10098
  const pkg = platformRipgrepPackage();
9911
10099
  const name = rgBinaryName();
9912
- let dir = (0, import_node_path26.dirname)((0, import_node_path26.resolve)(startFile));
9913
- const root = (0, import_node_path26.parse)(dir).root;
10100
+ let dir = (0, import_node_path27.dirname)((0, import_node_path27.resolve)(startFile));
10101
+ const root = (0, import_node_path27.parse)(dir).root;
9914
10102
  while (dir !== root) {
9915
- const hit = usableRipgrepPath((0, import_node_path26.join)(dir, "node_modules", pkg, "bin", name));
10103
+ const hit = usableRipgrepPath((0, import_node_path27.join)(dir, "node_modules", pkg, "bin", name));
9916
10104
  if (hit) return hit;
9917
- const next = (0, import_node_path26.dirname)(dir);
10105
+ const next = (0, import_node_path27.dirname)(dir);
9918
10106
  if (next === dir) break;
9919
10107
  dir = next;
9920
10108
  }
@@ -9924,7 +10112,7 @@ function requireResolveBundledRipgrep(fromFile) {
9924
10112
  try {
9925
10113
  const req = (0, import_node_module2.createRequire)(fromFile);
9926
10114
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
9927
- return usableRipgrepPath((0, import_node_path26.join)((0, import_node_path26.dirname)(pkgJson), "bin", rgBinaryName()));
10115
+ return usableRipgrepPath((0, import_node_path27.join)((0, import_node_path27.dirname)(pkgJson), "bin", rgBinaryName()));
9928
10116
  } catch {
9929
10117
  return null;
9930
10118
  }
@@ -9946,13 +10134,13 @@ function cursorRipgrepEnv(opts) {
9946
10134
  const path = resolveCursorRipgrepPath(opts);
9947
10135
  return path ? { [RIPGREP_ENV]: path } : {};
9948
10136
  }
9949
- var import_node_fs25, import_node_module2, import_node_path26, RIPGREP_ENV;
10137
+ var import_node_fs26, import_node_module2, import_node_path27, RIPGREP_ENV;
9950
10138
  var init_cursor_ripgrep = __esm({
9951
10139
  "src/agents/cursor-ripgrep.ts"() {
9952
10140
  "use strict";
9953
- import_node_fs25 = require("fs");
10141
+ import_node_fs26 = require("fs");
9954
10142
  import_node_module2 = require("module");
9955
- import_node_path26 = require("path");
10143
+ import_node_path27 = require("path");
9956
10144
  init_node_launch();
9957
10145
  init_packaged_runtime();
9958
10146
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -9998,11 +10186,11 @@ function entryDir() {
9998
10186
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
9999
10187
  if (cjsDir) return cjsDir;
10000
10188
  try {
10001
- return (0, import_node_path27.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
10189
+ return (0, import_node_path28.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
10002
10190
  } catch {
10003
10191
  try {
10004
10192
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
10005
- return (0, import_node_path27.dirname)(req.resolve("@sideboard-ai/core"));
10193
+ return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
10006
10194
  } catch {
10007
10195
  return process.cwd();
10008
10196
  }
@@ -10013,27 +10201,27 @@ function cursorRunnerPath() {
10013
10201
  if (packaged) return packaged;
10014
10202
  const root = entryDir();
10015
10203
  const candidates = [
10016
- (0, import_node_path27.join)(root, "agents", "cursor-runner.js"),
10017
- (0, import_node_path27.join)(root, "agents", "cursor-runner.cjs"),
10204
+ (0, import_node_path28.join)(root, "agents", "cursor-runner.js"),
10205
+ (0, import_node_path28.join)(root, "agents", "cursor-runner.cjs"),
10018
10206
  // If somehow resolved from package root instead of dist/
10019
- (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.js"),
10020
- (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.cjs"),
10207
+ (0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.js"),
10208
+ (0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.cjs"),
10021
10209
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
10022
- (0, import_node_path27.join)(root, "cursor-runner.ts"),
10023
- (0, import_node_path27.join)(root, "src", "agents", "cursor-runner.ts")
10210
+ (0, import_node_path28.join)(root, "cursor-runner.ts"),
10211
+ (0, import_node_path28.join)(root, "src", "agents", "cursor-runner.ts")
10024
10212
  ];
10025
10213
  for (const candidate of candidates) {
10026
- if ((0, import_node_fs26.existsSync)(candidate)) return candidate;
10214
+ if ((0, import_node_fs27.existsSync)(candidate)) return candidate;
10027
10215
  }
10028
10216
  return candidates[0];
10029
10217
  }
10030
- var import_node_fs26, import_node_module3, import_node_path27, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
10218
+ var import_node_fs27, import_node_module3, import_node_path28, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
10031
10219
  var init_cursor = __esm({
10032
10220
  "src/agents/cursor.ts"() {
10033
10221
  "use strict";
10034
- import_node_fs26 = require("fs");
10222
+ import_node_fs27 = require("fs");
10035
10223
  import_node_module3 = require("module");
10036
- import_node_path27 = require("path");
10224
+ import_node_path28 = require("path");
10037
10225
  import_node_url2 = require("url");
10038
10226
  import_sdk = require("@cursor/sdk");
10039
10227
  init_run();
@@ -10184,7 +10372,7 @@ async function listOpencodeModels() {
10184
10372
  if (opencode === "opencode") {
10185
10373
  const which = await run("which", ["opencode"], { reject: false });
10186
10374
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
10187
- } else if (!(0, import_node_fs27.existsSync)(opencode)) {
10375
+ } else if (!(0, import_node_fs28.existsSync)(opencode)) {
10188
10376
  return FALLBACK_OPENCODE_MODELS;
10189
10377
  }
10190
10378
  const listed = await run(opencode, ["models"], { reject: false });
@@ -10214,11 +10402,11 @@ function usageFromOpencode(tokens) {
10214
10402
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
10215
10403
  };
10216
10404
  }
10217
- var import_node_fs27, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
10405
+ var import_node_fs28, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
10218
10406
  var init_opencode = __esm({
10219
10407
  "src/agents/opencode.ts"() {
10220
10408
  "use strict";
10221
- import_node_fs27 = require("fs");
10409
+ import_node_fs28 = require("fs");
10222
10410
  init_run();
10223
10411
  init_app_settings();
10224
10412
  init_global_workspace();
@@ -10245,7 +10433,7 @@ var init_opencode = __esm({
10245
10433
  async detect() {
10246
10434
  const opencode = resolveAgentExecutable("opencode");
10247
10435
  if (opencode !== "opencode") {
10248
- if (!(0, import_node_fs27.existsSync)(opencode)) {
10436
+ if (!(0, import_node_fs28.existsSync)(opencode)) {
10249
10437
  return {
10250
10438
  agent: "opencode",
10251
10439
  installed: false,
@@ -11846,7 +12034,7 @@ function forkMessageSlice(from, throughIndex) {
11846
12034
  function buildForkTranscriptAttachment(baseTitle, messages) {
11847
12035
  const title = baseTitle || "Chat";
11848
12036
  return {
11849
- id: (0, import_node_crypto5.randomUUID)(),
12037
+ id: (0, import_node_crypto6.randomUUID)(),
11850
12038
  name: `Transcript of ${title}.md`,
11851
12039
  kind: "transcript",
11852
12040
  content: formatTranscriptMarkdown(title, messages)
@@ -11903,11 +12091,11 @@ function forkChatTab(input) {
11903
12091
  }
11904
12092
  return tab;
11905
12093
  }
11906
- var import_node_crypto5;
12094
+ var import_node_crypto6;
11907
12095
  var init_chat_tabs = __esm({
11908
12096
  "src/threads/chat-tabs.ts"() {
11909
12097
  "use strict";
11910
- import_node_crypto5 = require("crypto");
12098
+ import_node_crypto6 = require("crypto");
11911
12099
  init_context_compact();
11912
12100
  init_teams();
11913
12101
  init_worktree_labels();
@@ -12077,21 +12265,21 @@ function shouldRefreshReviewRequestTemplate(content) {
12077
12265
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
12078
12266
  }
12079
12267
  function readTextIfPresent(abs) {
12080
- if (!(0, import_node_fs28.existsSync)(abs)) return null;
12268
+ if (!(0, import_node_fs29.existsSync)(abs)) return null;
12081
12269
  try {
12082
- const content = (0, import_node_fs28.readFileSync)(abs, "utf8");
12270
+ const content = (0, import_node_fs29.readFileSync)(abs, "utf8");
12083
12271
  return content.trim() ? content : null;
12084
12272
  } catch {
12085
12273
  return null;
12086
12274
  }
12087
12275
  }
12088
12276
  function readLocalGuidelines(worktreePath) {
12089
- const localAbs = (0, import_node_path28.join)(worktreePath, REVIEW_REQUEST_PATH);
12277
+ const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
12090
12278
  const localContent = readTextIfPresent(localAbs);
12091
12279
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
12092
12280
  return { path: REVIEW_REQUEST_PATH, content: localContent };
12093
12281
  }
12094
- const legacyAbs = (0, import_node_path28.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
12282
+ const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
12095
12283
  const legacyContent = readTextIfPresent(legacyAbs);
12096
12284
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
12097
12285
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -12107,20 +12295,20 @@ function skillGuidelines(content, source) {
12107
12295
  };
12108
12296
  }
12109
12297
  function ensureReviewSkillFile(worktreePath) {
12110
- const abs = (0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH);
12298
+ const abs = (0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH);
12111
12299
  const existing = readTextIfPresent(abs);
12112
12300
  if (existing) {
12113
12301
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
12114
12302
  }
12115
- const fromRepo = readTextIfPresent((0, import_node_path28.join)(worktreePath, REPO_REVIEW_PATH));
12303
+ const fromRepo = readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH));
12116
12304
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
12117
12305
  const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
12118
- (0, import_node_fs28.mkdirSync)((0, import_node_path28.dirname)(abs), { recursive: true });
12119
- (0, import_node_fs28.writeFileSync)(abs, content, "utf8");
12306
+ (0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(abs), { recursive: true });
12307
+ (0, import_node_fs29.writeFileSync)(abs, content, "utf8");
12120
12308
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
12121
12309
  }
12122
12310
  function resolveReviewGuidelines(worktreePath) {
12123
- const skillContent = readTextIfPresent((0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH));
12311
+ const skillContent = readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH));
12124
12312
  if (skillContent) return skillGuidelines(skillContent, "skill");
12125
12313
  const local = readLocalGuidelines(worktreePath);
12126
12314
  if (local) {
@@ -12138,7 +12326,7 @@ function buildReviewRequestAttachment(content, opts) {
12138
12326
  const path = opts?.path ?? REVIEW_SKILL_PATH;
12139
12327
  const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
12140
12328
  return {
12141
- id: (0, import_node_crypto6.randomUUID)(),
12329
+ id: (0, import_node_crypto7.randomUUID)(),
12142
12330
  name,
12143
12331
  kind: "file",
12144
12332
  path,
@@ -12170,13 +12358,13 @@ async function requestReview(threadRef, send) {
12170
12358
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
12171
12359
  return { tab: started, from };
12172
12360
  }
12173
- var import_node_crypto6, import_node_fs28, import_node_path28, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
12361
+ 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;
12174
12362
  var init_request_review = __esm({
12175
12363
  "src/review/request-review.ts"() {
12176
12364
  "use strict";
12177
- import_node_crypto6 = require("crypto");
12178
- import_node_fs28 = require("fs");
12179
- import_node_path28 = require("path");
12365
+ import_node_crypto7 = require("crypto");
12366
+ import_node_fs29 = require("fs");
12367
+ import_node_path29 = require("path");
12180
12368
  init_global_workspace();
12181
12369
  init_chat_tabs();
12182
12370
  init_thread_store();
@@ -12201,9 +12389,9 @@ function matchSimpleGlob(pattern, name) {
12201
12389
  return new RegExp(`^${escaped}$`).test(name);
12202
12390
  }
12203
12391
  function readWorktreeInclude(repoPath) {
12204
- const path = (0, import_node_path29.join)(repoPath, ".worktreeinclude");
12205
- if (!(0, import_node_fs29.existsSync)(path)) return [];
12206
- return (0, import_node_fs29.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
12392
+ const path = (0, import_node_path30.join)(repoPath, ".worktreeinclude");
12393
+ if (!(0, import_node_fs30.existsSync)(path)) return [];
12394
+ return (0, import_node_fs30.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
12207
12395
  }
12208
12396
  function resolveFilesToCopy(repoPath) {
12209
12397
  const fromInclude = readWorktreeInclude(repoPath);
@@ -12213,10 +12401,10 @@ function resolveFilesToCopy(repoPath) {
12213
12401
  if (settings?.fileIncludeGlobs?.length) {
12214
12402
  const matched = [];
12215
12403
  try {
12216
- for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
12404
+ for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
12217
12405
  if (!entry.isFile()) continue;
12218
12406
  for (const glob of settings.fileIncludeGlobs) {
12219
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path29.basename)(glob), entry.name)) {
12407
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path30.basename)(glob), entry.name)) {
12220
12408
  matched.push(entry.name);
12221
12409
  break;
12222
12410
  }
@@ -12228,7 +12416,7 @@ function resolveFilesToCopy(repoPath) {
12228
12416
  }
12229
12417
  const defaults = [];
12230
12418
  try {
12231
- for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
12419
+ for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
12232
12420
  if (entry.isFile() && entry.name.startsWith(".env")) {
12233
12421
  defaults.push(entry.name);
12234
12422
  }
@@ -12242,11 +12430,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
12242
12430
  const patterns = resolveFilesToCopy(repoPath);
12243
12431
  const copied = [];
12244
12432
  for (const rel of patterns) {
12245
- const src = (0, import_node_path29.join)(repoPath, rel);
12246
- if (!(0, import_node_fs29.existsSync)(src)) continue;
12247
- const dest = (0, import_node_path29.join)(worktreePath, rel);
12248
- (0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(dest), { recursive: true });
12249
- (0, import_node_fs29.copyFileSync)(src, dest);
12433
+ const src = (0, import_node_path30.join)(repoPath, rel);
12434
+ if (!(0, import_node_fs30.existsSync)(src)) continue;
12435
+ const dest = (0, import_node_path30.join)(worktreePath, rel);
12436
+ (0, import_node_fs30.mkdirSync)((0, import_node_path30.dirname)(dest), { recursive: true });
12437
+ (0, import_node_fs30.copyFileSync)(src, dest);
12250
12438
  copied.push(rel);
12251
12439
  }
12252
12440
  return copied;
@@ -12281,7 +12469,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
12281
12469
  const env = stripNestedElectronEnv({
12282
12470
  ...baseEnv ?? process.env
12283
12471
  });
12284
- const name = opts.workspaceName ?? (0, import_node_path29.basename)(opts.worktreePath);
12472
+ const name = opts.workspaceName ?? (0, import_node_path30.basename)(opts.worktreePath);
12285
12473
  const ports = opts.ports ?? [];
12286
12474
  const primary = ports[0];
12287
12475
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -12436,6 +12624,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
12436
12624
  };
12437
12625
  }
12438
12626
  async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
12627
+ await ensureWorktreeSideboardIgnored(worktreePath);
12439
12628
  const reviewSkill = ensureReviewSkillFile(worktreePath);
12440
12629
  if (reviewSkill.wrote) {
12441
12630
  onLine?.(
@@ -12542,13 +12731,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
12542
12731
  done: handle.done
12543
12732
  };
12544
12733
  }
12545
- var import_node_fs29, import_node_net, import_node_path29, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
12734
+ var import_node_fs30, import_node_net, import_node_path30, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
12546
12735
  var init_conductor = __esm({
12547
12736
  "src/hook/conductor.ts"() {
12548
12737
  "use strict";
12549
- import_node_fs29 = require("fs");
12738
+ import_node_fs30 = require("fs");
12550
12739
  import_node_net = require("net");
12551
- import_node_path29 = require("path");
12740
+ import_node_path30 = require("path");
12552
12741
  import_execa4 = require("execa");
12553
12742
  import_node_readline3 = require("readline");
12554
12743
  init_settings();
@@ -12557,6 +12746,7 @@ var init_conductor = __esm({
12557
12746
  init_cursor_worktrees();
12558
12747
  init_git_auth_mode();
12559
12748
  init_request_review();
12749
+ init_worktree_exclude();
12560
12750
  init_nested_electron_env();
12561
12751
  PORT_RANGE_SIZE = 10;
12562
12752
  cachedLoginEnv = null;
@@ -12574,9 +12764,9 @@ async function findOrphanWorktrees(repoPaths) {
12574
12764
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
12575
12765
  );
12576
12766
  const homeRoot = sideboardWorkspacesDir();
12577
- if ((0, import_node_fs30.existsSync)(homeRoot)) {
12767
+ if ((0, import_node_fs31.existsSync)(homeRoot)) {
12578
12768
  try {
12579
- for (const entry of (0, import_node_fs30.readdirSync)(homeRoot, { withFileTypes: true })) {
12769
+ for (const entry of (0, import_node_fs31.readdirSync)(homeRoot, { withFileTypes: true })) {
12580
12770
  if (!entry.isDirectory()) continue;
12581
12771
  void entry;
12582
12772
  }
@@ -12586,7 +12776,7 @@ async function findOrphanWorktrees(repoPaths) {
12586
12776
  const orphans = [];
12587
12777
  const seen = /* @__PURE__ */ new Set();
12588
12778
  for (const repoPath of repos) {
12589
- if (!repoPath || !(0, import_node_fs30.existsSync)(repoPath)) continue;
12779
+ if (!repoPath || !(0, import_node_fs31.existsSync)(repoPath)) continue;
12590
12780
  try {
12591
12781
  const wts = await listWorktrees(repoPath);
12592
12782
  for (const wt of wts) {
@@ -12597,7 +12787,7 @@ async function findOrphanWorktrees(repoPaths) {
12597
12787
  seen.add(path);
12598
12788
  let mtimeMs = 0;
12599
12789
  try {
12600
- mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
12790
+ mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
12601
12791
  } catch {
12602
12792
  mtimeMs = 0;
12603
12793
  }
@@ -12607,16 +12797,16 @@ async function findOrphanWorktrees(repoPaths) {
12607
12797
  }
12608
12798
  try {
12609
12799
  const root = worktreesRoot(repoPath);
12610
- if ((0, import_node_fs30.existsSync)(root)) {
12611
- for (const entry of (0, import_node_fs30.readdirSync)(root, { withFileTypes: true })) {
12800
+ if ((0, import_node_fs31.existsSync)(root)) {
12801
+ for (const entry of (0, import_node_fs31.readdirSync)(root, { withFileTypes: true })) {
12612
12802
  if (!entry.isDirectory()) continue;
12613
- const path = (0, import_node_path30.join)(root, entry.name).replace(/\/$/, "");
12803
+ const path = (0, import_node_path31.join)(root, entry.name).replace(/\/$/, "");
12614
12804
  if (known.has(path) || seen.has(path)) continue;
12615
- if (!(0, import_node_fs30.existsSync)((0, import_node_path30.join)(path, ".git"))) continue;
12805
+ if (!(0, import_node_fs31.existsSync)((0, import_node_path31.join)(path, ".git"))) continue;
12616
12806
  seen.add(path);
12617
12807
  let mtimeMs = 0;
12618
12808
  try {
12619
- mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
12809
+ mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
12620
12810
  } catch {
12621
12811
  mtimeMs = Date.now();
12622
12812
  }
@@ -12668,12 +12858,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
12668
12858
  const elapsed = Date.now() - Date.parse(last);
12669
12859
  return elapsed >= intervalHours * 36e5;
12670
12860
  }
12671
- var import_node_fs30, import_node_path30;
12861
+ var import_node_fs31, import_node_path31;
12672
12862
  var init_orphan_cleanup = __esm({
12673
12863
  "src/git/orphan-cleanup.ts"() {
12674
12864
  "use strict";
12675
- import_node_fs30 = require("fs");
12676
- import_node_path30 = require("path");
12865
+ import_node_fs31 = require("fs");
12866
+ import_node_path31 = require("path");
12677
12867
  init_worktree();
12678
12868
  init_thread_store();
12679
12869
  init_paths();
@@ -12780,38 +12970,38 @@ __export(workspaces_exports, {
12780
12970
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
12781
12971
  });
12782
12972
  function workspacesFile() {
12783
- return (0, import_node_path31.join)(appDataDir(), "workspaces.json");
12973
+ return (0, import_node_path32.join)(appDataDir(), "workspaces.json");
12784
12974
  }
12785
12975
  function removedWorkspacesFile() {
12786
- return (0, import_node_path31.join)(appDataDir(), "removed-workspaces.json");
12976
+ return (0, import_node_path32.join)(appDataDir(), "removed-workspaces.json");
12787
12977
  }
12788
12978
  function readAll() {
12789
12979
  const path = workspacesFile();
12790
- if (!(0, import_node_fs31.existsSync)(path)) return [];
12980
+ if (!(0, import_node_fs32.existsSync)(path)) return [];
12791
12981
  try {
12792
- const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12982
+ const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
12793
12983
  return Array.isArray(raw) ? raw : [];
12794
12984
  } catch {
12795
12985
  return [];
12796
12986
  }
12797
12987
  }
12798
12988
  function writeAll(list) {
12799
- (0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
12800
- (0, import_node_fs31.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12989
+ (0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
12990
+ (0, import_node_fs32.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12801
12991
  }
12802
12992
  function readRemoved() {
12803
12993
  const path = removedWorkspacesFile();
12804
- if (!(0, import_node_fs31.existsSync)(path)) return /* @__PURE__ */ new Set();
12994
+ if (!(0, import_node_fs32.existsSync)(path)) return /* @__PURE__ */ new Set();
12805
12995
  try {
12806
- const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12996
+ const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
12807
12997
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
12808
12998
  } catch {
12809
12999
  return /* @__PURE__ */ new Set();
12810
13000
  }
12811
13001
  }
12812
13002
  function writeRemoved(paths) {
12813
- (0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
12814
- (0, import_node_fs31.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
13003
+ (0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
13004
+ (0, import_node_fs32.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
12815
13005
  }
12816
13006
  function rememberRemoved(repoPath) {
12817
13007
  const next = readRemoved();
@@ -12834,7 +13024,7 @@ function listWorkspaces() {
12834
13024
  async function addWorkspace(repoPath) {
12835
13025
  const root = await resolveRepoRoot(repoPath);
12836
13026
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
12837
- if (!(0, import_node_fs31.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
13027
+ if (!(0, import_node_fs32.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
12838
13028
  forgetRemoved(root);
12839
13029
  await ensureGhPreferOrigin(root);
12840
13030
  const current = readAll();
@@ -12842,7 +13032,7 @@ async function addWorkspace(repoPath) {
12842
13032
  if (existing) return existing;
12843
13033
  const next = {
12844
13034
  path: root,
12845
- name: (0, import_node_path31.basename)(root),
13035
+ name: (0, import_node_path32.basename)(root),
12846
13036
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12847
13037
  };
12848
13038
  writeAll([...current, next]);
@@ -12864,10 +13054,10 @@ function syncWorkspacesFromThreads(repoPaths) {
12864
13054
  if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
12865
13055
  continue;
12866
13056
  }
12867
- if (!(0, import_node_fs31.existsSync)(path)) continue;
13057
+ if (!(0, import_node_fs32.existsSync)(path)) continue;
12868
13058
  const ws = {
12869
13059
  path,
12870
- name: (0, import_node_path31.basename)(path),
13060
+ name: (0, import_node_path32.basename)(path),
12871
13061
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12872
13062
  };
12873
13063
  byPath.set(path, ws);
@@ -12877,12 +13067,12 @@ function syncWorkspacesFromThreads(repoPaths) {
12877
13067
  if (dirty) writeAll(next);
12878
13068
  return next.sort((a, b) => a.name.localeCompare(b.name));
12879
13069
  }
12880
- var import_node_fs31, import_node_path31;
13070
+ var import_node_fs32, import_node_path32;
12881
13071
  var init_workspaces2 = __esm({
12882
13072
  "src/store/workspaces.ts"() {
12883
13073
  "use strict";
12884
- import_node_fs31 = require("fs");
12885
- import_node_path31 = require("path");
13074
+ import_node_fs32 = require("fs");
13075
+ import_node_path32 = require("path");
12886
13076
  init_paths();
12887
13077
  init_global_workspace();
12888
13078
  init_worktree();
@@ -12895,12 +13085,12 @@ async function cloneRepoIntoSideboard(opts) {
12895
13085
  if (!url) throw new Error("Clone URL is required");
12896
13086
  let name = opts.name?.trim();
12897
13087
  if (!name) {
12898
- const leaf = (0, import_node_path32.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
13088
+ const leaf = (0, import_node_path33.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12899
13089
  name = leaf || "repo";
12900
13090
  }
12901
13091
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
12902
- const dest = (0, import_node_path32.join)(sideboardReposDir(), name);
12903
- if ((0, import_node_fs32.existsSync)(dest)) {
13092
+ const dest = (0, import_node_path33.join)(sideboardReposDir(), name);
13093
+ if ((0, import_node_fs33.existsSync)(dest)) {
12904
13094
  const repoPath2 = await resolveRepoRoot(dest);
12905
13095
  const workspace2 = await ensureWorkspace(repoPath2);
12906
13096
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -12915,12 +13105,12 @@ async function cloneRepoIntoSideboard(opts) {
12915
13105
  const workspace = await ensureWorkspace(repoPath);
12916
13106
  return { repoPath, workspace };
12917
13107
  }
12918
- var import_node_fs32, import_node_path32, import_execa6;
13108
+ var import_node_fs33, import_node_path33, import_execa6;
12919
13109
  var init_clone_repo = __esm({
12920
13110
  "src/git/clone-repo.ts"() {
12921
13111
  "use strict";
12922
- import_node_fs32 = require("fs");
12923
- import_node_path32 = require("path");
13112
+ import_node_fs33 = require("fs");
13113
+ import_node_path33 = require("path");
12924
13114
  import_execa6 = require("execa");
12925
13115
  init_paths();
12926
13116
  init_workspaces2();
@@ -12930,11 +13120,11 @@ var init_clone_repo = __esm({
12930
13120
 
12931
13121
  // src/store/desktop-host.ts
12932
13122
  function desktopHostPidPath() {
12933
- return (0, import_node_path33.join)(appDataDir(), "desktop-host.pid");
13123
+ return (0, import_node_path34.join)(appDataDir(), "desktop-host.pid");
12934
13124
  }
12935
13125
  function readDesktopHostPid() {
12936
13126
  try {
12937
- const pid = Number.parseInt((0, import_node_fs33.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
13127
+ const pid = Number.parseInt((0, import_node_fs34.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
12938
13128
  if (!Number.isFinite(pid) || pid <= 0) return null;
12939
13129
  return pid;
12940
13130
  } catch {
@@ -12960,12 +13150,12 @@ function thisProcessShouldDrainAgentQueues() {
12960
13150
  if (isThisProcessDesktopHost()) return true;
12961
13151
  return !isDesktopHostAlive();
12962
13152
  }
12963
- var import_node_fs33, import_node_path33;
13153
+ var import_node_fs34, import_node_path34;
12964
13154
  var init_desktop_host = __esm({
12965
13155
  "src/store/desktop-host.ts"() {
12966
13156
  "use strict";
12967
- import_node_fs33 = require("fs");
12968
- import_node_path33 = require("path");
13157
+ import_node_fs34 = require("fs");
13158
+ import_node_path34 = require("path");
12969
13159
  init_paths();
12970
13160
  }
12971
13161
  });
@@ -13967,7 +14157,7 @@ function persistCreateAttachments(worktreePath, attachments) {
13967
14157
  }
13968
14158
  async function createThread(input, _onSetupLine) {
13969
14159
  const repoPath = await resolveRepoRoot(input.repoPath);
13970
- if (!(0, import_node_fs34.existsSync)(repoPath)) {
14160
+ if (!(0, import_node_fs35.existsSync)(repoPath)) {
13971
14161
  throw new Error(`Repo not found: ${repoPath}`);
13972
14162
  }
13973
14163
  if (input.reuseExisting !== false) {
@@ -14142,11 +14332,11 @@ async function listLinearIssues(agent, repoPath) {
14142
14332
  }
14143
14333
  return adapter.listLinearIssues(repoPath);
14144
14334
  }
14145
- var import_node_fs34;
14335
+ var import_node_fs35;
14146
14336
  var init_create = __esm({
14147
14337
  "src/threads/create.ts"() {
14148
14338
  "use strict";
14149
- import_node_fs34 = require("fs");
14339
+ import_node_fs35 = require("fs");
14150
14340
  init_detect();
14151
14341
  init_worktree();
14152
14342
  init_home_board();
@@ -14249,20 +14439,20 @@ function writeTurnLive(threadId, progress) {
14249
14439
  const path = threadLivePath(threadId);
14250
14440
  const tmp = `${path}.${process.pid}.tmp`;
14251
14441
  try {
14252
- (0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
14253
- (0, import_node_fs35.renameSync)(tmp, path);
14442
+ (0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
14443
+ (0, import_node_fs36.renameSync)(tmp, path);
14254
14444
  } catch {
14255
14445
  try {
14256
- (0, import_node_fs35.unlinkSync)(tmp);
14446
+ (0, import_node_fs36.unlinkSync)(tmp);
14257
14447
  } catch {
14258
14448
  }
14259
14449
  }
14260
14450
  }
14261
14451
  function readTurnLive(threadId) {
14262
14452
  const path = threadLivePath(threadId);
14263
- if (!(0, import_node_fs35.existsSync)(path)) return null;
14453
+ if (!(0, import_node_fs36.existsSync)(path)) return null;
14264
14454
  try {
14265
- const raw = JSON.parse((0, import_node_fs35.readFileSync)(path, "utf8"));
14455
+ const raw = JSON.parse((0, import_node_fs36.readFileSync)(path, "utf8"));
14266
14456
  if (!raw || typeof raw.summary !== "string") return null;
14267
14457
  return raw;
14268
14458
  } catch {
@@ -14274,17 +14464,17 @@ function clearTurnLive(threadId) {
14274
14464
  if (buf?.timer) clearTimeout(buf.timer);
14275
14465
  buffers.delete(threadId);
14276
14466
  const path = threadLivePath(threadId);
14277
- if (!(0, import_node_fs35.existsSync)(path)) return;
14467
+ if (!(0, import_node_fs36.existsSync)(path)) return;
14278
14468
  try {
14279
- (0, import_node_fs35.unlinkSync)(path);
14469
+ (0, import_node_fs36.unlinkSync)(path);
14280
14470
  } catch {
14281
14471
  }
14282
14472
  }
14283
- var import_node_fs35, buffers, FLUSH_MS, MAX_PARTS;
14473
+ var import_node_fs36, buffers, FLUSH_MS, MAX_PARTS;
14284
14474
  var init_turn_live = __esm({
14285
14475
  "src/store/turn-live.ts"() {
14286
14476
  "use strict";
14287
- import_node_fs35 = require("fs");
14477
+ import_node_fs36 = require("fs");
14288
14478
  init_message_parts();
14289
14479
  init_paths();
14290
14480
  buffers = /* @__PURE__ */ new Map();
@@ -14458,7 +14648,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
14458
14648
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
14459
14649
  ].join("\n");
14460
14650
  return {
14461
- id: (0, import_node_crypto7.randomUUID)(),
14651
+ id: (0, import_node_crypto8.randomUUID)(),
14462
14652
  name: "Orchestration quota handoff.md",
14463
14653
  kind: "transcript",
14464
14654
  content: body
@@ -14479,11 +14669,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
14479
14669
  sourceType: "orchestration"
14480
14670
  });
14481
14671
  }
14482
- var import_node_crypto7, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
14672
+ var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
14483
14673
  var init_quota_failover = __esm({
14484
14674
  "src/orchestrator/quota-failover.ts"() {
14485
14675
  "use strict";
14486
- import_node_crypto7 = require("crypto");
14676
+ import_node_crypto8 = require("crypto");
14487
14677
  init_session_quota();
14488
14678
  init_app_settings();
14489
14679
  init_global_workspace();
@@ -14500,7 +14690,7 @@ var init_quota_failover = __esm({
14500
14690
  // src/threads/adopt.ts
14501
14691
  function thisModuleFile() {
14502
14692
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
14503
- return cjsFile || process.argv[1] || (0, import_node_path34.join)(process.cwd(), "package.json");
14693
+ return cjsFile || process.argv[1] || (0, import_node_path35.join)(process.cwd(), "package.json");
14504
14694
  }
14505
14695
  function openReadonlySqlite(file) {
14506
14696
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -14518,21 +14708,21 @@ function mapAgentType(raw) {
14518
14708
  return null;
14519
14709
  }
14520
14710
  function resolveConductorCursorAgentId(workspacePath) {
14521
- if (!workspacePath || !(0, import_node_fs36.existsSync)(CURSOR_SDK_STORE)) return null;
14711
+ if (!workspacePath || !(0, import_node_fs37.existsSync)(CURSOR_SDK_STORE)) return null;
14522
14712
  const normalized = workspacePath.replace(/\/$/, "");
14523
14713
  let best = null;
14524
14714
  let hashes;
14525
14715
  try {
14526
- hashes = (0, import_node_fs36.readdirSync)(CURSOR_SDK_STORE);
14716
+ hashes = (0, import_node_fs37.readdirSync)(CURSOR_SDK_STORE);
14527
14717
  } catch {
14528
14718
  return null;
14529
14719
  }
14530
14720
  for (const hash of hashes) {
14531
- const agentsFile = (0, import_node_path34.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
14532
- if (!(0, import_node_fs36.existsSync)(agentsFile)) continue;
14721
+ const agentsFile = (0, import_node_path35.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
14722
+ if (!(0, import_node_fs37.existsSync)(agentsFile)) continue;
14533
14723
  let text5;
14534
14724
  try {
14535
- text5 = (0, import_node_fs36.readFileSync)(agentsFile, "utf8");
14725
+ text5 = (0, import_node_fs37.readFileSync)(agentsFile, "utf8");
14536
14726
  } catch {
14537
14727
  continue;
14538
14728
  }
@@ -14556,7 +14746,7 @@ function resolveConductorCursorAgentId(workspacePath) {
14556
14746
  return best?.agentId ?? null;
14557
14747
  }
14558
14748
  async function adoptThread(input) {
14559
- if (!(0, import_node_fs36.existsSync)(input.worktreePath)) {
14749
+ if (!(0, import_node_fs37.existsSync)(input.worktreePath)) {
14560
14750
  throw new Error(`Worktree not found: ${input.worktreePath}`);
14561
14751
  }
14562
14752
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -14577,21 +14767,23 @@ async function adoptThread(input) {
14577
14767
  writeThread(thread);
14578
14768
  const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
14579
14769
  await ensureWorkspace2(repoPath);
14770
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
14771
+ await ensureWorktreeSideboardIgnored2(input.worktreePath);
14580
14772
  return thread;
14581
14773
  }
14582
14774
  function listConductorWorkspaces() {
14583
- if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
14775
+ if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
14584
14776
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
14585
14777
  }
14586
- const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
14587
- const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
14778
+ const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
14779
+ const snapshot = (0, import_node_path35.join)(tmp, "conductor.db");
14588
14780
  try {
14589
- (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
14781
+ (0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
14590
14782
  for (const suffix of ["-wal", "-shm"]) {
14591
14783
  const src = `${CONDUCTOR_DB}${suffix}`;
14592
- if ((0, import_node_fs36.existsSync)(src)) {
14784
+ if ((0, import_node_fs37.existsSync)(src)) {
14593
14785
  try {
14594
- (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
14786
+ (0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
14595
14787
  } catch {
14596
14788
  }
14597
14789
  }
@@ -14667,22 +14859,22 @@ function listConductorWorkspaces() {
14667
14859
  db.close();
14668
14860
  }
14669
14861
  } finally {
14670
- (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
14862
+ (0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
14671
14863
  }
14672
14864
  }
14673
14865
  function importConductorWorkspace(workspaceId) {
14674
- if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
14866
+ if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
14675
14867
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
14676
14868
  }
14677
- const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
14678
- const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
14869
+ const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
14870
+ const snapshot = (0, import_node_path35.join)(tmp, "conductor.db");
14679
14871
  try {
14680
- (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
14872
+ (0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
14681
14873
  for (const suffix of ["-wal", "-shm"]) {
14682
14874
  const src = `${CONDUCTOR_DB}${suffix}`;
14683
- if ((0, import_node_fs36.existsSync)(src)) {
14875
+ if ((0, import_node_fs37.existsSync)(src)) {
14684
14876
  try {
14685
- (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
14877
+ (0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
14686
14878
  } catch {
14687
14879
  }
14688
14880
  }
@@ -14700,7 +14892,7 @@ function importConductorWorkspace(workspaceId) {
14700
14892
  ).get(workspaceId);
14701
14893
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
14702
14894
  const worktreePath = String(row.workspacePath);
14703
- if (!(0, import_node_fs36.existsSync)(worktreePath)) {
14895
+ if (!(0, import_node_fs37.existsSync)(worktreePath)) {
14704
14896
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
14705
14897
  }
14706
14898
  let sessionId = null;
@@ -14763,31 +14955,31 @@ function importConductorWorkspace(workspaceId) {
14763
14955
  db.close();
14764
14956
  }
14765
14957
  } finally {
14766
- (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
14958
+ (0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
14767
14959
  }
14768
14960
  }
14769
14961
  async function importConductorWorkspaceAsync(workspaceId) {
14770
14962
  return importConductorWorkspace(workspaceId);
14771
14963
  }
14772
- var import_node_child_process3, import_node_fs36, import_node_os10, import_node_path34, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
14964
+ var import_node_child_process3, import_node_fs37, import_node_os11, import_node_path35, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
14773
14965
  var init_adopt = __esm({
14774
14966
  "src/threads/adopt.ts"() {
14775
14967
  "use strict";
14776
14968
  import_node_child_process3 = require("child_process");
14777
- import_node_fs36 = require("fs");
14778
- import_node_os10 = require("os");
14779
- import_node_path34 = require("path");
14969
+ import_node_fs37 = require("fs");
14970
+ import_node_os11 = require("os");
14971
+ import_node_path35 = require("path");
14780
14972
  import_node_module4 = require("module");
14781
14973
  init_worktree();
14782
14974
  init_thread_store();
14783
- CONDUCTOR_APP_SUPPORT = (0, import_node_path34.join)(
14975
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path35.join)(
14784
14976
  process.env.HOME ?? "",
14785
14977
  "Library",
14786
14978
  "Application Support",
14787
14979
  "com.conductor.app"
14788
14980
  );
14789
- CONDUCTOR_DB = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
14790
- CURSOR_SDK_STORE = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
14981
+ CONDUCTOR_DB = (0, import_node_path35.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
14982
+ CURSOR_SDK_STORE = (0, import_node_path35.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
14791
14983
  }
14792
14984
  });
14793
14985
 
@@ -14854,7 +15046,7 @@ async function openStackLayer(input, _onSetupLine) {
14854
15046
  let createdWorktree = false;
14855
15047
  const trees = await listWorktrees(repoPath);
14856
15048
  const checkedOut = trees.find((w) => w.branch === branchName);
14857
- if (checkedOut?.path && (0, import_node_fs37.existsSync)(checkedOut.path)) {
15049
+ if (checkedOut?.path && (0, import_node_fs38.existsSync)(checkedOut.path)) {
14858
15050
  if (input.reuseExistingWorktree !== false) {
14859
15051
  worktreePath = checkedOut.path;
14860
15052
  } else {
@@ -14996,7 +15188,7 @@ async function initStackFromThread(input, onSetupLine) {
14996
15188
  async function createPrStack(input, onSetupLine) {
14997
15189
  await requireAgent(input.agent);
14998
15190
  const repoPath = await resolveRepoRoot(input.repoPath);
14999
- if (!(0, import_node_fs37.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
15191
+ if (!(0, import_node_fs38.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
15000
15192
  if (!input.branches.length) throw new Error("At least one branch name required");
15001
15193
  const status = await detectGhStack(repoPath);
15002
15194
  if (!status.available) throw new Error(status.reason);
@@ -15063,7 +15255,7 @@ async function createPrStack(input, onSetupLine) {
15063
15255
  }
15064
15256
  }
15065
15257
  const claimed = new Set(threads.map((t) => t.worktreePath));
15066
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs37.existsSync)(bootstrap.worktreePath)) {
15258
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs38.existsSync)(bootstrap.worktreePath)) {
15067
15259
  try {
15068
15260
  await removeWorktree(repoPath, bootstrap.worktreePath, {
15069
15261
  deleteBranch: bootstrap.branchName
@@ -15073,11 +15265,11 @@ async function createPrStack(input, onSetupLine) {
15073
15265
  }
15074
15266
  return { stack, threads, createdThreadIds };
15075
15267
  }
15076
- var import_node_fs37;
15268
+ var import_node_fs38;
15077
15269
  var init_stack_layers = __esm({
15078
15270
  "src/threads/stack-layers.ts"() {
15079
15271
  "use strict";
15080
- import_node_fs37 = require("fs");
15272
+ import_node_fs38 = require("fs");
15081
15273
  init_detect();
15082
15274
  init_run();
15083
15275
  init_stack();
@@ -15090,7 +15282,7 @@ var init_stack_layers = __esm({
15090
15282
 
15091
15283
  // src/diff/diff.ts
15092
15284
  async function inspectGitWorktree(worktreePath) {
15093
- if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) return "missing_worktree";
15285
+ if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) return "missing_worktree";
15094
15286
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
15095
15287
  reject: false
15096
15288
  });
@@ -15098,7 +15290,7 @@ async function inspectGitWorktree(worktreePath) {
15098
15290
  return "ok";
15099
15291
  }
15100
15292
  async function initializeGitRepository(worktreePath) {
15101
- if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) {
15293
+ if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) {
15102
15294
  throw new Error("Worktree not found");
15103
15295
  }
15104
15296
  const status = await inspectGitWorktree(worktreePath);
@@ -15232,11 +15424,11 @@ new file mode 100644
15232
15424
  };
15233
15425
  }
15234
15426
  async function untrackedPatch(worktreePath, path, maxHunk) {
15235
- const abs = (0, import_node_path35.join)(worktreePath, path);
15427
+ const abs = (0, import_node_path36.join)(worktreePath, path);
15236
15428
  try {
15237
- const st = (0, import_node_fs38.statSync)(abs);
15429
+ const st = (0, import_node_fs39.statSync)(abs);
15238
15430
  if (st.isFile() && st.size > maxHunk) {
15239
- const buf = (0, import_node_fs38.readFileSync)(abs).subarray(0, maxHunk);
15431
+ const buf = (0, import_node_fs39.readFileSync)(abs).subarray(0, maxHunk);
15240
15432
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
15241
15433
  }
15242
15434
  } catch {
@@ -15725,8 +15917,8 @@ function isImageRelativePath(relativePath) {
15725
15917
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
15726
15918
  assertSafeRelativePath(relativePath);
15727
15919
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
15728
- const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15729
- const st = (0, import_node_fs38.statSync)(abs);
15920
+ const abs = (0, import_node_path36.join)(worktreePath, relativePath);
15921
+ const st = (0, import_node_fs39.statSync)(abs);
15730
15922
  if (!st.isFile()) {
15731
15923
  throw new Error(`Not a file: ${relativePath}`);
15732
15924
  }
@@ -15735,7 +15927,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
15735
15927
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
15736
15928
  );
15737
15929
  }
15738
- const buf = (0, import_node_fs38.readFileSync)(abs);
15930
+ const buf = (0, import_node_fs39.readFileSync)(abs);
15739
15931
  return {
15740
15932
  path: relativePath,
15741
15933
  contentBase64: buf.toString("base64"),
@@ -15745,12 +15937,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
15745
15937
  function readWorktreeFile(worktreePath, relativePath, opts) {
15746
15938
  assertSafeRelativePath(relativePath);
15747
15939
  const maxBytes = opts?.maxBytes ?? 2e5;
15748
- const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15749
- const st = (0, import_node_fs38.statSync)(abs);
15940
+ const abs = (0, import_node_path36.join)(worktreePath, relativePath);
15941
+ const st = (0, import_node_fs39.statSync)(abs);
15750
15942
  if (!st.isFile()) {
15751
15943
  throw new Error(`Not a file: ${relativePath}`);
15752
15944
  }
15753
- const buf = (0, import_node_fs38.readFileSync)(abs);
15945
+ const buf = (0, import_node_fs39.readFileSync)(abs);
15754
15946
  if (isImageRelativePath(relativePath)) {
15755
15947
  const maxImageBytes = Math.max(maxBytes, 15e6);
15756
15948
  const truncated2 = buf.length > maxImageBytes;
@@ -15793,9 +15985,9 @@ function assertSafeRelativePath(relativePath) {
15793
15985
  }
15794
15986
  function writeWorktreeFile(worktreePath, relativePath, content) {
15795
15987
  assertSafeRelativePath(relativePath);
15796
- const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15797
- (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
15798
- (0, import_node_fs38.writeFileSync)(abs, content, "utf8");
15988
+ const abs = (0, import_node_path36.join)(worktreePath, relativePath);
15989
+ (0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(abs), { recursive: true });
15990
+ (0, import_node_fs39.writeFileSync)(abs, content, "utf8");
15799
15991
  return { path: relativePath };
15800
15992
  }
15801
15993
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -15812,12 +16004,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
15812
16004
  truncated: full.files.length > maxFiles
15813
16005
  };
15814
16006
  }
15815
- var import_node_fs38, import_node_path35, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
16007
+ var import_node_fs39, import_node_path36, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
15816
16008
  var init_diff = __esm({
15817
16009
  "src/diff/diff.ts"() {
15818
16010
  "use strict";
15819
- import_node_fs38 = require("fs");
15820
- import_node_path35 = require("path");
16011
+ import_node_fs39 = require("fs");
16012
+ import_node_path36 = require("path");
15821
16013
  init_run();
15822
16014
  init_worktree();
15823
16015
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -16075,7 +16267,7 @@ function parseFrontmatter(content) {
16075
16267
  }
16076
16268
  function readSkill(skillMd, source) {
16077
16269
  try {
16078
- const content = (0, import_node_fs39.readFileSync)(skillMd, "utf8");
16270
+ const content = (0, import_node_fs40.readFileSync)(skillMd, "utf8");
16079
16271
  const { name: fmName, description } = parseFrontmatter(content);
16080
16272
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
16081
16273
  const name = fmName || dirName;
@@ -16094,19 +16286,19 @@ function readSkill(skillMd, source) {
16094
16286
  }
16095
16287
  }
16096
16288
  function scanSkillsDir(dir, source, out) {
16097
- if (!(0, import_node_fs39.existsSync)(dir)) return;
16289
+ if (!(0, import_node_fs40.existsSync)(dir)) return;
16098
16290
  let entries;
16099
16291
  try {
16100
- entries = (0, import_node_fs39.readdirSync)(dir);
16292
+ entries = (0, import_node_fs40.readdirSync)(dir);
16101
16293
  } catch {
16102
16294
  return;
16103
16295
  }
16104
16296
  for (const entry of entries) {
16105
16297
  if (entry.startsWith(".")) continue;
16106
- const skillMd = (0, import_node_path36.join)(dir, entry, "SKILL.md");
16107
- if (!(0, import_node_fs39.existsSync)(skillMd)) continue;
16298
+ const skillMd = (0, import_node_path37.join)(dir, entry, "SKILL.md");
16299
+ if (!(0, import_node_fs40.existsSync)(skillMd)) continue;
16108
16300
  try {
16109
- if (!(0, import_node_fs39.statSync)(skillMd).isFile()) continue;
16301
+ if (!(0, import_node_fs40.statSync)(skillMd).isFile()) continue;
16110
16302
  } catch {
16111
16303
  continue;
16112
16304
  }
@@ -16115,24 +16307,24 @@ function scanSkillsDir(dir, source, out) {
16115
16307
  }
16116
16308
  }
16117
16309
  function scanClaudePluginSkills(pluginsRoot, out) {
16118
- if (!(0, import_node_fs39.existsSync)(pluginsRoot)) return;
16310
+ if (!(0, import_node_fs40.existsSync)(pluginsRoot)) return;
16119
16311
  const walk = (dir, depth, lookingForSkillsDir) => {
16120
16312
  if (depth > 7) return;
16121
16313
  let entries;
16122
16314
  try {
16123
- entries = (0, import_node_fs39.readdirSync)(dir);
16315
+ entries = (0, import_node_fs40.readdirSync)(dir);
16124
16316
  } catch {
16125
16317
  return;
16126
16318
  }
16127
16319
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
16128
- const skill = readSkill((0, import_node_path36.join)(dir, "SKILL.md"), "cli");
16320
+ const skill = readSkill((0, import_node_path37.join)(dir, "SKILL.md"), "cli");
16129
16321
  if (skill) out.push(skill);
16130
16322
  }
16131
16323
  for (const entry of entries) {
16132
16324
  if (entry === "node_modules" || entry === ".git") continue;
16133
- const full = (0, import_node_path36.join)(dir, entry);
16325
+ const full = (0, import_node_path37.join)(dir, entry);
16134
16326
  try {
16135
- if (!(0, import_node_fs39.statSync)(full).isDirectory()) continue;
16327
+ if (!(0, import_node_fs40.statSync)(full).isDirectory()) continue;
16136
16328
  } catch {
16137
16329
  continue;
16138
16330
  }
@@ -16147,20 +16339,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
16147
16339
  walk(pluginsRoot, 0, false);
16148
16340
  }
16149
16341
  function discoverSkills(worktreePath) {
16150
- const home = (0, import_node_os11.homedir)();
16342
+ const home = (0, import_node_os12.homedir)();
16151
16343
  const collected = [];
16152
16344
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
16153
- scanSkillsDir((0, import_node_path36.join)(worktreePath, rel), "workspace", collected);
16345
+ scanSkillsDir((0, import_node_path37.join)(worktreePath, rel), "workspace", collected);
16154
16346
  }
16155
16347
  for (const abs of [
16156
- (0, import_node_path36.join)(home, ".claude/skills"),
16157
- (0, import_node_path36.join)(home, ".cursor/skills"),
16158
- (0, import_node_path36.join)(home, ".sideboard/skills"),
16159
- (0, import_node_path36.join)(home, ".brightsy/skills")
16348
+ (0, import_node_path37.join)(home, ".claude/skills"),
16349
+ (0, import_node_path37.join)(home, ".cursor/skills"),
16350
+ (0, import_node_path37.join)(home, ".sideboard/skills"),
16351
+ (0, import_node_path37.join)(home, ".brightsy/skills")
16160
16352
  ]) {
16161
16353
  scanSkillsDir(abs, "user", collected);
16162
16354
  }
16163
- scanClaudePluginSkills((0, import_node_path36.join)(home, ".claude/plugins"), collected);
16355
+ scanClaudePluginSkills((0, import_node_path37.join)(home, ".claude/plugins"), collected);
16164
16356
  collected.push(...bundledSkills());
16165
16357
  const rank = {
16166
16358
  workspace: 0,
@@ -16186,7 +16378,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
16186
16378
  \u2026(truncated)` : body;
16187
16379
  }
16188
16380
  }
16189
- const raw = (0, import_node_fs39.readFileSync)(skillPath, "utf8");
16381
+ const raw = (0, import_node_fs40.readFileSync)(skillPath, "utf8");
16190
16382
  if (raw.startsWith("---")) {
16191
16383
  const end = raw.indexOf("\n---", 3);
16192
16384
  if (end >= 0) {
@@ -16200,13 +16392,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
16200
16392
 
16201
16393
  \u2026(truncated)` : raw;
16202
16394
  }
16203
- var import_node_fs39, import_node_os11, import_node_path36, BUNDLED_SKILL_PREFIX;
16395
+ var import_node_fs40, import_node_os12, import_node_path37, BUNDLED_SKILL_PREFIX;
16204
16396
  var init_discover = __esm({
16205
16397
  "src/skills/discover.ts"() {
16206
16398
  "use strict";
16207
- import_node_fs39 = require("fs");
16208
- import_node_os11 = require("os");
16209
- import_node_path36 = require("path");
16399
+ import_node_fs40 = require("fs");
16400
+ import_node_os12 = require("os");
16401
+ import_node_path37 = require("path");
16210
16402
  init_long_running();
16211
16403
  BUNDLED_SKILL_PREFIX = "bundled:";
16212
16404
  }
@@ -16301,17 +16493,17 @@ var init_expand = __esm({
16301
16493
  function packagedDetachedJobPath() {
16302
16494
  const dir = packagedMcpDir();
16303
16495
  if (!dir) return null;
16304
- const script = (0, import_node_path37.join)(dir, "scripts", "detached-job.js");
16305
- return (0, import_node_fs40.existsSync)(script) ? script : null;
16496
+ const script = (0, import_node_path38.join)(dir, "scripts", "detached-job.js");
16497
+ return (0, import_node_fs41.existsSync)(script) ? script : null;
16306
16498
  }
16307
16499
  function resolveDetachedJobScript() {
16308
16500
  const packaged = packagedDetachedJobPath();
16309
16501
  if (packaged) return packaged;
16310
- let dir = (0, import_node_path37.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
16502
+ let dir = (0, import_node_path38.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
16311
16503
  for (let i = 0; i < 8; i++) {
16312
- const candidate = (0, import_node_path37.join)(dir, "scripts", "detached-job.js");
16313
- if ((0, import_node_fs40.existsSync)(candidate)) return candidate;
16314
- const parent = (0, import_node_path37.dirname)(dir);
16504
+ const candidate = (0, import_node_path38.join)(dir, "scripts", "detached-job.js");
16505
+ if ((0, import_node_fs41.existsSync)(candidate)) return candidate;
16506
+ const parent = (0, import_node_path38.dirname)(dir);
16315
16507
  if (parent === dir) break;
16316
16508
  dir = parent;
16317
16509
  }
@@ -16322,12 +16514,12 @@ function formatDetachedJobInvoke(scriptPath) {
16322
16514
  if (resolved) return `node ${JSON.stringify(resolved)}`;
16323
16515
  return "node scripts/detached-job.js";
16324
16516
  }
16325
- var import_node_fs40, import_node_path37, import_node_url3, import_meta3;
16517
+ var import_node_fs41, import_node_path38, import_node_url3, import_meta3;
16326
16518
  var init_detached_job_path = __esm({
16327
16519
  "src/skills/detached-job-path.ts"() {
16328
16520
  "use strict";
16329
- import_node_fs40 = require("fs");
16330
- import_node_path37 = require("path");
16521
+ import_node_fs41 = require("fs");
16522
+ import_node_path38 = require("path");
16331
16523
  import_node_url3 = require("url");
16332
16524
  init_packaged_runtime();
16333
16525
  import_meta3 = {};
@@ -16400,11 +16592,11 @@ function formatWorktreeDirective(thread, opts) {
16400
16592
  );
16401
16593
  } else if (opts?.githubSlug) {
16402
16594
  lines.push(
16403
- `- Prefer a draft PR first: \`gh pr create --draft -R ${opts.githubSlug}\` (or update via \`gh pr edit -R ${opts.githubSlug}\`) once the change set is coherent. Always pass \`-R ${opts.githubSlug}\` (this worktree's origin). Bare \`gh pr create\` may target upstream instead of origin on dual-remote checkouts. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name.`
16595
+ `- Prefer a draft PR first: \`gh pr create --draft -R ${opts.githubSlug}\` (or update via \`gh pr edit -R ${opts.githubSlug}\`) once the change set is coherent. Always pass \`-R ${opts.githubSlug}\` (this worktree's origin). Bare \`gh pr create\` may target upstream instead of origin on dual-remote checkouts. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short \`--body-file\` (limit 65,536 characters) \u2014 do not paste a changelog or diff into \`--body\`.`
16404
16596
  );
16405
16597
  } else {
16406
16598
  lines.push(
16407
- "- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name."
16599
+ "- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short `--body-file` (limit 65,536 characters) \u2014 do not paste a changelog or diff into `--body`."
16408
16600
  );
16409
16601
  }
16410
16602
  lines.push("");
@@ -16495,12 +16687,12 @@ function formatArtifactDirective() {
16495
16687
  function formatUiReminder() {
16496
16688
  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 or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
16497
16689
  }
16498
- var import_node_fs41, import_node_path38;
16690
+ var import_node_fs42, import_node_path39;
16499
16691
  var init_instructions = __esm({
16500
16692
  "src/agents/instructions.ts"() {
16501
16693
  "use strict";
16502
- import_node_fs41 = require("fs");
16503
- import_node_path38 = require("path");
16694
+ import_node_fs42 = require("fs");
16695
+ import_node_path39 = require("path");
16504
16696
  init_git_auth_mode();
16505
16697
  init_worktree_labels();
16506
16698
  init_detached_job_path();
@@ -16670,40 +16862,40 @@ __export(plan_file_exports, {
16670
16862
  writePlanFile: () => writePlanFile
16671
16863
  });
16672
16864
  function ensureAttachmentsGitignore(worktreePath) {
16673
- const gitignoreAbs = (0, import_node_path39.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
16674
- if ((0, import_node_fs42.existsSync)(gitignoreAbs)) return;
16675
- (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(gitignoreAbs), { recursive: true });
16676
- (0, import_node_fs42.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
16865
+ const gitignoreAbs = (0, import_node_path40.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
16866
+ if ((0, import_node_fs43.existsSync)(gitignoreAbs)) return;
16867
+ (0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(gitignoreAbs), { recursive: true });
16868
+ (0, import_node_fs43.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
16677
16869
  }
16678
16870
  function planFileAbs(worktreePath) {
16679
- return (0, import_node_path39.join)(worktreePath, PLAN_FILE_REL);
16871
+ return (0, import_node_path40.join)(worktreePath, PLAN_FILE_REL);
16680
16872
  }
16681
16873
  function readTextIfPresent2(abs) {
16682
- if (!(0, import_node_fs42.existsSync)(abs)) return null;
16874
+ if (!(0, import_node_fs43.existsSync)(abs)) return null;
16683
16875
  try {
16684
- const content = (0, import_node_fs42.readFileSync)(abs, "utf8");
16876
+ const content = (0, import_node_fs43.readFileSync)(abs, "utf8");
16685
16877
  return content.trim() ? content : null;
16686
16878
  } catch {
16687
16879
  return null;
16688
16880
  }
16689
16881
  }
16690
16882
  function readPlanFile(worktreePath) {
16691
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path39.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path39.join)(worktreePath, LEGACY_PLAN_FILE_REL));
16883
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path40.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path40.join)(worktreePath, LEGACY_PLAN_FILE_REL));
16692
16884
  }
16693
16885
  function writePlanFile(worktreePath, content) {
16694
16886
  ensureAttachmentsGitignore(worktreePath);
16695
16887
  const abs = planFileAbs(worktreePath);
16696
- (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(abs), { recursive: true });
16888
+ (0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(abs), { recursive: true });
16697
16889
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
16698
- (0, import_node_fs42.writeFileSync)(abs, body, "utf8");
16890
+ (0, import_node_fs43.writeFileSync)(abs, body, "utf8");
16699
16891
  return PLAN_FILE_REL;
16700
16892
  }
16701
- var import_node_fs42, import_node_path39;
16893
+ var import_node_fs43, import_node_path40;
16702
16894
  var init_plan_file = __esm({
16703
16895
  "src/plan/plan-file.ts"() {
16704
16896
  "use strict";
16705
- import_node_fs42 = require("fs");
16706
- import_node_path39 = require("path");
16897
+ import_node_fs43 = require("fs");
16898
+ import_node_path40 = require("path");
16707
16899
  init_workspace_scratch();
16708
16900
  init_plan_present();
16709
16901
  init_plan_present();
@@ -16763,7 +16955,7 @@ function setCaffeinateHoldHooks(next) {
16763
16955
  hooks = next;
16764
16956
  }
16765
16957
  function caffeinateHoldPath() {
16766
- return (0, import_node_path40.join)(appDataDir(), "caffeinate-hold.json");
16958
+ return (0, import_node_path41.join)(appDataDir(), "caffeinate-hold.json");
16767
16959
  }
16768
16960
  function processAlive(pid) {
16769
16961
  if (hooks.processAlive) return hooks.processAlive(pid);
@@ -16797,9 +16989,9 @@ function uniqueIds(ids) {
16797
16989
  }
16798
16990
  function readHold() {
16799
16991
  const path = caffeinateHoldPath();
16800
- if (!(0, import_node_fs43.existsSync)(path)) return null;
16992
+ if (!(0, import_node_fs44.existsSync)(path)) return null;
16801
16993
  try {
16802
- const parsed = JSON.parse((0, import_node_fs43.readFileSync)(path, "utf8"));
16994
+ const parsed = JSON.parse((0, import_node_fs44.readFileSync)(path, "utf8"));
16803
16995
  if (typeof parsed?.pid === "number" && parsed.pid > 0) {
16804
16996
  return {
16805
16997
  pid: parsed.pid,
@@ -16821,7 +17013,7 @@ function writeHold(pid, threadIds) {
16821
17013
  }
16822
17014
  function clearHold() {
16823
17015
  try {
16824
- (0, import_node_fs43.unlinkSync)(caffeinateHoldPath());
17016
+ (0, import_node_fs44.unlinkSync)(caffeinateHoldPath());
16825
17017
  } catch {
16826
17018
  }
16827
17019
  }
@@ -16906,13 +17098,13 @@ function releaseCaffeinateHoldForThread(threadId) {
16906
17098
  }
16907
17099
  return setCaffeinateHold(false, { threadId: id });
16908
17100
  }
16909
- var import_node_child_process4, import_node_fs43, import_node_path40, hooks;
17101
+ var import_node_child_process4, import_node_fs44, import_node_path41, hooks;
16910
17102
  var init_caffeinate_hold = __esm({
16911
17103
  "src/store/caffeinate-hold.ts"() {
16912
17104
  "use strict";
16913
17105
  import_node_child_process4 = require("child_process");
16914
- import_node_fs43 = require("fs");
16915
- import_node_path40 = require("path");
17106
+ import_node_fs44 = require("fs");
17107
+ import_node_path41 = require("path");
16916
17108
  init_paths();
16917
17109
  init_private_file();
16918
17110
  hooks = {};
@@ -16921,7 +17113,7 @@ var init_caffeinate_hold = __esm({
16921
17113
 
16922
17114
  // src/store/schedules.ts
16923
17115
  function schedulesPath() {
16924
- return (0, import_node_path41.join)(appDataDir(), "schedules.json");
17116
+ return (0, import_node_path42.join)(appDataDir(), "schedules.json");
16925
17117
  }
16926
17118
  function parseDurationMs(every) {
16927
17119
  const m = every.trim().match(DURATION_RE);
@@ -17021,9 +17213,9 @@ function normalizeTask(raw) {
17021
17213
  }
17022
17214
  function readAll2() {
17023
17215
  const path = schedulesPath();
17024
- if (!(0, import_node_fs44.existsSync)(path)) return [];
17216
+ if (!(0, import_node_fs45.existsSync)(path)) return [];
17025
17217
  try {
17026
- const parsed = JSON.parse((0, import_node_fs44.readFileSync)(path, "utf8"));
17218
+ const parsed = JSON.parse((0, import_node_fs45.readFileSync)(path, "utf8"));
17027
17219
  if (!Array.isArray(parsed)) return [];
17028
17220
  return parsed.map((row) => {
17029
17221
  try {
@@ -17048,7 +17240,7 @@ function buildTask(input, now) {
17048
17240
  const ts = nowIso2(now);
17049
17241
  const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
17050
17242
  return {
17051
- id: (0, import_node_crypto8.randomUUID)(),
17243
+ id: (0, import_node_crypto9.randomUUID)(),
17052
17244
  name: input.name?.trim() || defaultScheduleName(prompt),
17053
17245
  prompt,
17054
17246
  enabled: input.enabled !== false,
@@ -17135,13 +17327,13 @@ function recordScheduleRun(id, result) {
17135
17327
  writeAll2(rows);
17136
17328
  return next;
17137
17329
  }
17138
- var import_node_crypto8, import_node_fs44, import_node_path41, import_croner, DURATION_RE, UNIT_MS;
17330
+ var import_node_crypto9, import_node_fs45, import_node_path42, import_croner, DURATION_RE, UNIT_MS;
17139
17331
  var init_schedules = __esm({
17140
17332
  "src/store/schedules.ts"() {
17141
17333
  "use strict";
17142
- import_node_crypto8 = require("crypto");
17143
- import_node_fs44 = require("fs");
17144
- import_node_path41 = require("path");
17334
+ import_node_crypto9 = require("crypto");
17335
+ import_node_fs45 = require("fs");
17336
+ import_node_path42 = require("path");
17145
17337
  import_croner = require("croner");
17146
17338
  init_orchestrator_capable();
17147
17339
  init_paths();
@@ -17283,13 +17475,13 @@ var init_schedule_runner = __esm({
17283
17475
 
17284
17476
  // src/agents/cursor-store.ts
17285
17477
  function cursorSdkStoreDir(threadId) {
17286
- const root = (0, import_node_path42.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
17478
+ const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
17287
17479
  const id = sanitizeCursorStoreSegment(threadId);
17288
17480
  if (!id) return root;
17289
- return (0, import_node_path42.join)(root, "threads", id);
17481
+ return (0, import_node_path43.join)(root, "threads", id);
17290
17482
  }
17291
17483
  function cursorSdkRunsNdjsonPath(threadId) {
17292
- return (0, import_node_path42.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
17484
+ return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
17293
17485
  }
17294
17486
  function cursorSdkRunsNdjsonSearchPaths(threadId) {
17295
17487
  const scoped = cursorSdkRunsNdjsonPath(threadId);
@@ -17302,11 +17494,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
17302
17494
  function sanitizeCursorStoreSegment(threadId) {
17303
17495
  return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
17304
17496
  }
17305
- var import_node_path42, CURSOR_SDK_STORE_DIR;
17497
+ var import_node_path43, CURSOR_SDK_STORE_DIR;
17306
17498
  var init_cursor_store = __esm({
17307
17499
  "src/agents/cursor-store.ts"() {
17308
17500
  "use strict";
17309
- import_node_path42 = require("path");
17501
+ import_node_path43 = require("path");
17310
17502
  init_paths();
17311
17503
  CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
17312
17504
  }
@@ -17328,9 +17520,9 @@ function recoverFinishedCursorRun(opts) {
17328
17520
  return best;
17329
17521
  }
17330
17522
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
17331
- if (!(0, import_node_fs45.existsSync)(runsPath)) return null;
17523
+ if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
17332
17524
  try {
17333
- const lines = (0, import_node_fs45.readFileSync)(runsPath, "utf8").split("\n");
17525
+ const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
17334
17526
  let best = null;
17335
17527
  for (const line of lines) {
17336
17528
  const trimmed = line.trim();
@@ -17356,11 +17548,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
17356
17548
  return null;
17357
17549
  }
17358
17550
  }
17359
- var import_node_fs45;
17551
+ var import_node_fs46;
17360
17552
  var init_cursor_recover = __esm({
17361
17553
  "src/agents/cursor-recover.ts"() {
17362
17554
  "use strict";
17363
- import_node_fs45 = require("fs");
17555
+ import_node_fs46 = require("fs");
17364
17556
  init_cursor_store();
17365
17557
  }
17366
17558
  });
@@ -17399,6 +17591,7 @@ var init_title = __esm({
17399
17591
  // src/orchestrator/orchestrator.ts
17400
17592
  var orchestrator_exports = {};
17401
17593
  __export(orchestrator_exports, {
17594
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
17402
17595
  Orchestrator: () => Orchestrator,
17403
17596
  getOrchestrator: () => getOrchestrator,
17404
17597
  isPidAlive: () => isPidAlive,
@@ -17491,13 +17684,13 @@ async function startOrchestration(opts) {
17491
17684
  }
17492
17685
  return updated;
17493
17686
  }
17494
- var import_node_events, import_node_fs46, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
17687
+ var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
17495
17688
  var init_orchestrator = __esm({
17496
17689
  "src/orchestrator/orchestrator.ts"() {
17497
17690
  "use strict";
17498
17691
  import_node_events = require("events");
17499
17692
  init_outbound_watch();
17500
- import_node_fs46 = require("fs");
17693
+ import_node_fs47 = require("fs");
17501
17694
  init_error_detail();
17502
17695
  init_run();
17503
17696
  init_stale_lock();
@@ -17512,6 +17705,7 @@ var init_orchestrator = __esm({
17512
17705
  init_orphan_cleanup();
17513
17706
  init_apply_into_main();
17514
17707
  init_clone_repo();
17708
+ init_message_parts();
17515
17709
  init_usage();
17516
17710
  init_thread_store();
17517
17711
  init_desktop_host();
@@ -17549,6 +17743,7 @@ var init_orchestrator = __esm({
17549
17743
  init_caffeinate_hold();
17550
17744
  init_schedule_runner();
17551
17745
  init_coordinator_prompt();
17746
+ LIVE_TURN_SPAWN_GRACE_MS = 15e3;
17552
17747
  STALE_AGENT_PID_WAIT_MS = 2500;
17553
17748
  Orchestrator = class {
17554
17749
  events = new import_node_events.EventEmitter();
@@ -17605,6 +17800,39 @@ var init_orchestrator = __esm({
17605
17800
  if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
17606
17801
  return true;
17607
17802
  }
17803
+ /**
17804
+ * Whether a child is actually turning — not leftover disk `running` after
17805
+ * the process died. Coordinators were telling users “Agent is running.
17806
+ * Waiting for gate to pass” from stale stillRunning.
17807
+ */
17808
+ threadLooksLive(thread) {
17809
+ if (thread.status === "queued") {
17810
+ if (this.draining.has(thread.id) || this.startingTurns.has(thread.id)) return true;
17811
+ return thread.queue.length > 0;
17812
+ }
17813
+ if (thread.status !== "running") return false;
17814
+ if (this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id)) return true;
17815
+ const pid = thread.agentPid;
17816
+ if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return true;
17817
+ const updated = Date.parse(thread.updatedAt ?? "");
17818
+ if (Number.isFinite(updated) && Date.now() - updated < LIVE_TURN_SPAWN_GRACE_MS) return true;
17819
+ return false;
17820
+ }
17821
+ /** Desktop-only: persist idle/stopped when MCP would otherwise keep reporting live. */
17822
+ healStaleReportedActivity(thread) {
17823
+ if (!thisProcessShouldDrainAgentQueues()) return thread;
17824
+ if (this.threadLooksLive(thread)) return thread;
17825
+ if (thread.status === "running") {
17826
+ this.healStaleRunningTurns();
17827
+ return readThread(thread.id) ?? thread;
17828
+ }
17829
+ if (thread.status === "queued" && thread.queue.length === 0 && !this.activeTurns.has(thread.id) && !this.startingTurns.has(thread.id) && !this.draining.has(thread.id)) {
17830
+ setStatus(thread.id, "idle");
17831
+ this.emit({ type: "status_changed", threadId: thread.id, status: "idle" });
17832
+ return readThread(thread.id) ?? thread;
17833
+ }
17834
+ return thread;
17835
+ }
17608
17836
  async reconcile(repoPath, opts) {
17609
17837
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
17610
17838
  const drainQueues = opts?.drainQueues !== false;
@@ -17629,7 +17857,7 @@ var init_orchestrator = __esm({
17629
17857
  }
17630
17858
  continue;
17631
17859
  }
17632
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
17860
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
17633
17861
  setStatus(thread.id, "broken", "Worktree missing on disk");
17634
17862
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
17635
17863
  continue;
@@ -17939,12 +18167,14 @@ var init_orchestrator = __esm({
17939
18167
  this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
17940
18168
  return thread;
17941
18169
  }
17942
- async send(threadRef, prompt) {
18170
+ async send(threadRef, prompt, opts) {
17943
18171
  const thread = this.requireThread(threadRef);
17944
18172
  if (thread.status === "archived") {
17945
18173
  throw new Error(`Thread is archived: ${thread.id}`);
17946
18174
  }
17947
- return withThreadLock(thread.id, async () => {
18175
+ const followUp = opts?.followUp === "steer" ? "steer" : "queue";
18176
+ let shouldSteer = false;
18177
+ const sent = await withThreadLock(thread.id, async () => {
17948
18178
  const current = this.requireThread(thread.id);
17949
18179
  if (current.status === "archived") {
17950
18180
  throw new Error(`Thread is archived: ${thread.id}`);
@@ -17953,6 +18183,7 @@ var init_orchestrator = __esm({
17953
18183
  this.crashContinued.delete(thread.id);
17954
18184
  this.haltDrain.delete(thread.id);
17955
18185
  const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
18186
+ shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
17956
18187
  const patch = { queue };
17957
18188
  if (!inFlight) patch.status = "queued";
17958
18189
  const pid = current.agentPid;
@@ -17964,16 +18195,20 @@ var init_orchestrator = __esm({
17964
18195
  if (!inFlight) {
17965
18196
  this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
17966
18197
  }
17967
- if (thisProcessShouldDrainAgentQueues()) {
18198
+ if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
17968
18199
  void this.drainQueue(thread.id);
17969
18200
  }
17970
18201
  return this.requireThread(thread.id);
17971
18202
  });
18203
+ if (shouldSteer && sent.queue.length > 0) {
18204
+ return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
18205
+ }
18206
+ return sent;
17972
18207
  }
17973
- async fanOut(threadRefs, prompt) {
18208
+ async fanOut(threadRefs, prompt, opts) {
17974
18209
  const results = [];
17975
18210
  for (const ref of threadRefs) {
17976
- results.push(await this.send(ref, prompt));
18211
+ results.push(await this.send(ref, prompt, opts));
17977
18212
  }
17978
18213
  return results;
17979
18214
  }
@@ -18777,8 +19012,8 @@ var init_orchestrator = __esm({
18777
19012
  return created;
18778
19013
  }
18779
19014
  async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
18780
- const thread = this.requireThread(threadRef);
18781
- if (!["running", "queued"].includes(thread.status)) {
19015
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19016
+ if (!this.threadLooksLive(thread)) {
18782
19017
  return thread;
18783
19018
  }
18784
19019
  const start = Date.now();
@@ -18815,12 +19050,13 @@ var init_orchestrator = __esm({
18815
19050
  }
18816
19051
  });
18817
19052
  timer = setInterval(() => {
18818
- const current = readThread(thread.id);
18819
- if (!current) {
19053
+ const raw = readThread(thread.id);
19054
+ if (!raw) {
18820
19055
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
18821
19056
  return;
18822
19057
  }
18823
- if (!["running", "queued"].includes(current.status)) {
19058
+ const current = this.healStaleReportedActivity(raw);
19059
+ if (!this.threadLooksLive(current)) {
18824
19060
  finish(() => resolve(current));
18825
19061
  return;
18826
19062
  }
@@ -18843,20 +19079,22 @@ var init_orchestrator = __esm({
18843
19079
  };
18844
19080
  }
18845
19081
  getTurnResult(threadRef) {
18846
- const thread = this.requireThread(threadRef);
19082
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
18847
19083
  const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
18848
19084
  const lastError = thread.lastError ?? null;
18849
- const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
18850
- const stillRunning = thread.status === "running" || thread.status === "queued";
19085
+ const rawText = (lastAgent?.text ?? "").trim();
19086
+ const text5 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
19087
+ const stillRunning = this.threadLooksLive(thread);
18851
19088
  const live = stillRunning ? readTurnLive(thread.id) : null;
18852
- const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
19089
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
19090
+ const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
18853
19091
  return {
18854
19092
  text: text5,
18855
19093
  status: thread.status,
18856
19094
  sessionId: thread.sessionId,
18857
19095
  lastError,
18858
19096
  stillRunning,
18859
- progress: live?.summary ?? queuedHint,
19097
+ progress: liveSummary ?? queuedHint,
18860
19098
  lastActivityAt: live?.updatedAt ?? null,
18861
19099
  usage: lastAgent?.usage ?? null
18862
19100
  };
@@ -19204,7 +19442,14 @@ var init_orchestrator = __esm({
19204
19442
  );
19205
19443
  }
19206
19444
  if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
19207
- await this.pushAndMaybeOpenPr(thread, action);
19445
+ try {
19446
+ await this.pushAndMaybeOpenPr(thread, action);
19447
+ } catch (err) {
19448
+ const message = err instanceof Error ? err.message : String(err);
19449
+ updateThread(thread.id, { lastError: message });
19450
+ this.emit({ type: "error", threadId: thread.id, message });
19451
+ throw err;
19452
+ }
19208
19453
  return this.requireThread(threadRef);
19209
19454
  }
19210
19455
  let prBase;
@@ -19407,7 +19652,7 @@ var init_orchestrator = __esm({
19407
19652
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
19408
19653
  return restored2;
19409
19654
  }
19410
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
19655
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
19411
19656
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
19412
19657
  throw new Error(
19413
19658
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -19419,6 +19664,8 @@ var init_orchestrator = __esm({
19419
19664
  await withRepoGitLock(thread.repoPath, async () => {
19420
19665
  await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
19421
19666
  });
19667
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
19668
+ await ensureWorktreeSideboardIgnored2(dest);
19422
19669
  void createThreadWorktree2;
19423
19670
  void slug;
19424
19671
  }
@@ -19487,8 +19734,8 @@ init_nested_electron_env();
19487
19734
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
19488
19735
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
19489
19736
  var import_zod5 = require("zod");
19490
- var import_node_crypto11 = require("crypto");
19491
- var import_node_path45 = require("path");
19737
+ var import_node_crypto12 = require("crypto");
19738
+ var import_node_path46 = require("path");
19492
19739
  init_orchestrator();
19493
19740
  init_worktree();
19494
19741
 
@@ -19502,7 +19749,7 @@ init_abletime();
19502
19749
  init_fetch();
19503
19750
 
19504
19751
  // src/integrations/linear-oauth.ts
19505
- var import_node_crypto9 = require("crypto");
19752
+ var import_node_crypto10 = require("crypto");
19506
19753
  var import_node_http = require("http");
19507
19754
  init_app_settings();
19508
19755
  init_fetch();
@@ -19680,6 +19927,22 @@ query SideboardAssignedIssues($first: Int!) {
19680
19927
  }
19681
19928
  }
19682
19929
  `;
19930
+ var ISSUES_QUERY = `
19931
+ query SideboardIssues($first: Int!, $filter: IssueFilter) {
19932
+ viewer { id name }
19933
+ issues(first: $first, orderBy: updatedAt, filter: $filter) {
19934
+ nodes { ${LIST_ISSUE_FIELDS} }
19935
+ }
19936
+ }
19937
+ `;
19938
+ var SEARCH_ISSUES_QUERY = `
19939
+ query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
19940
+ viewer { id name }
19941
+ searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
19942
+ nodes { ${LIST_ISSUE_FIELDS} }
19943
+ }
19944
+ }
19945
+ `;
19683
19946
  var TEAMS_QUERY = `
19684
19947
  query SideboardTeams {
19685
19948
  viewer { id name }
@@ -19963,19 +20226,73 @@ function normalizePriority(priority) {
19963
20226
  }
19964
20227
  return priority;
19965
20228
  }
19966
- async function listLinearAssignedIssues(opts) {
19967
- const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
19968
- const json = await linearGraphql(ASSIGNED_ISSUES_QUERY, { first }, opts);
20229
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20230
+ function assigneeFilterKey(assignee) {
20231
+ return (assignee ?? "").trim();
20232
+ }
20233
+ function buildLinearIssueFilter(input) {
20234
+ const filter = {
20235
+ state: { type: { nin: ["completed", "canceled"] } }
20236
+ };
20237
+ const raw = assigneeFilterKey(input?.assignee) || "me";
20238
+ const key = raw.toLowerCase();
20239
+ if (key === "all" || key === "*") return filter;
20240
+ if (key === "unassigned" || key === "none" || key === "null") {
20241
+ filter.assignee = { null: true };
20242
+ return filter;
20243
+ }
20244
+ if (key === "me" || key === "@me") {
20245
+ filter.assignee = { isMe: true };
20246
+ return filter;
20247
+ }
20248
+ if (UUID_RE.test(raw)) {
20249
+ filter.assignee = { id: { eq: raw } };
20250
+ return filter;
20251
+ }
20252
+ filter.assignee = { name: { eqIgnoreCase: raw } };
20253
+ return filter;
20254
+ }
20255
+ function isAssignedToMe(assignee) {
20256
+ const key = assignee.toLowerCase();
20257
+ return key === "me" || key === "@me";
20258
+ }
20259
+ function listedLinearIssues(json, nodes) {
19969
20260
  return {
19970
20261
  viewer: {
19971
20262
  id: String(json.viewer?.id ?? ""),
19972
20263
  name: String(json.viewer?.name ?? "")
19973
20264
  },
19974
- issues: (json.viewer?.assignedIssues?.nodes ?? []).map(
19975
- (node) => toIssueInfo(mapIssue(node))
19976
- )
20265
+ issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
19977
20266
  };
19978
20267
  }
20268
+ async function listLinearIssuesFiltered(opts) {
20269
+ const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
20270
+ const query = opts?.query?.trim() ?? "";
20271
+ const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
20272
+ const filter = buildLinearIssueFilter({ assignee });
20273
+ if (query) {
20274
+ const json2 = await linearGraphql(
20275
+ SEARCH_ISSUES_QUERY,
20276
+ { term: query, first, filter },
20277
+ opts
20278
+ );
20279
+ return listedLinearIssues(json2, json2.searchIssues?.nodes);
20280
+ }
20281
+ if (isAssignedToMe(assignee)) {
20282
+ const json2 = await linearGraphql(
20283
+ ASSIGNED_ISSUES_QUERY,
20284
+ { first },
20285
+ opts
20286
+ );
20287
+ return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
20288
+ }
20289
+ const json = await linearGraphql(
20290
+ ISSUES_QUERY,
20291
+ { first, filter },
20292
+ opts
20293
+ );
20294
+ return listedLinearIssues(json, json.issues?.nodes);
20295
+ }
19979
20296
  async function listLinearTeams(opts) {
19980
20297
  const json = await linearGraphql(TEAMS_QUERY, void 0, opts);
19981
20298
  return {
@@ -20082,6 +20399,22 @@ async function commentLinearIssue(input, opts) {
20082
20399
  }
20083
20400
 
20084
20401
  // src/integrations/issues.ts
20402
+ function assigneeKey(assignee) {
20403
+ return (assignee ?? "").trim().toLowerCase();
20404
+ }
20405
+ function issueMatchesAssignee(issue, assignee, viewerName = "") {
20406
+ const key = assigneeKey(assignee);
20407
+ if (!key || key === "all" || key === "*") return true;
20408
+ const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
20409
+ if (key === "unassigned" || key === "none" || key === "null") {
20410
+ return names.length === 0;
20411
+ }
20412
+ if (key === "me" || key === "@me") {
20413
+ const me = viewerName.trim().toLowerCase();
20414
+ return Boolean(me && names.includes(me));
20415
+ }
20416
+ return names.includes(key);
20417
+ }
20085
20418
  async function listGitHubIssues(repoPath, opts) {
20086
20419
  const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
20087
20420
  const slug = await resolveGithubRepoSlug(repoPath);
@@ -20095,6 +20428,17 @@ async function listGitHubIssues(repoPath, opts) {
20095
20428
  "--state",
20096
20429
  "open"
20097
20430
  ];
20431
+ const query = opts?.query?.trim() ?? "";
20432
+ const assignee = opts?.assignee?.trim() ?? "";
20433
+ const key = assignee.toLowerCase();
20434
+ const searchParts = [];
20435
+ if (query) searchParts.push(query);
20436
+ if (key === "unassigned" || key === "none" || key === "null") {
20437
+ searchParts.push("no:assignee");
20438
+ } else if (key && key !== "all" && key !== "*") {
20439
+ args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
20440
+ }
20441
+ if (searchParts.length) args.push("--search", searchParts.join(" "));
20098
20442
  if (slug) args.push("--repo", slug);
20099
20443
  const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
20100
20444
  if (exitCode !== 0 || !stdout.trim()) return [];
@@ -20132,14 +20476,20 @@ async function githubViewerLogin(repoPath) {
20132
20476
  if (exitCode !== 0) return "";
20133
20477
  return stdout.trim();
20134
20478
  }
20135
- async function listIssues(repoPath) {
20479
+ async function listIssues(repoPath, opts) {
20136
20480
  const settings = loadAppSettings();
20137
20481
  const preferredSource = settings.integrations.issueSource ?? "github";
20138
20482
  const linearConnected = isLinearConnected(settings);
20139
20483
  const abletimeConnected = isAbleTimeConnected(settings);
20140
20484
  const source = resolveEffectiveIssueSource(settings);
20485
+ const query = opts?.query?.trim() || void 0;
20486
+ const assignee = opts?.assignee?.trim() || void 0;
20141
20487
  if (source === "linear") {
20142
- const listed = await listLinearAssignedIssues();
20488
+ const listed = await listLinearIssuesFiltered({
20489
+ assignee,
20490
+ query,
20491
+ limit: opts?.limit
20492
+ });
20143
20493
  return {
20144
20494
  source,
20145
20495
  preferredSource,
@@ -20153,13 +20503,20 @@ async function listIssues(repoPath) {
20153
20503
  };
20154
20504
  }
20155
20505
  if (source === "abletime") {
20156
- const listed = await listAbleTimeAssignedIssues();
20506
+ const [listed, searched] = await Promise.all([
20507
+ listAbleTimeAssignedIssues(),
20508
+ query ? searchAbleTimeTasks(query) : Promise.resolve(null)
20509
+ ]);
20510
+ const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
20511
+ const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
20512
+ (issue) => issueMatchesAssignee(issue, assignee, viewerName)
20513
+ );
20157
20514
  return {
20158
20515
  source,
20159
20516
  preferredSource,
20160
20517
  linearConnected,
20161
20518
  abletimeConnected,
20162
- issues: listed.issues,
20519
+ issues: issues2,
20163
20520
  viewer: {
20164
20521
  login: listed.viewer.name,
20165
20522
  name: listed.viewer.name
@@ -20167,7 +20524,7 @@ async function listIssues(repoPath) {
20167
20524
  };
20168
20525
  }
20169
20526
  const [issues, login] = await Promise.all([
20170
- listGitHubIssues(repoPath),
20527
+ listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
20171
20528
  githubViewerLogin(repoPath)
20172
20529
  ]);
20173
20530
  return {
@@ -20220,14 +20577,16 @@ function mcpWaitFinishedHint(status) {
20220
20577
  }
20221
20578
 
20222
20579
  // src/mcp/server.ts
20580
+ init_message_parts();
20223
20581
  init_turn_live();
20224
20582
 
20225
20583
  // src/mcp/thread-visibility.ts
20584
+ init_message_parts();
20226
20585
  function lastMessagePreview(messages, max = 160) {
20227
20586
  if (!messages?.length) return null;
20228
20587
  for (let i = messages.length - 1; i >= 0; i--) {
20229
20588
  const text5 = messages[i]?.text?.trim();
20230
- if (!text5) continue;
20589
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
20231
20590
  const flat = text5.replace(/\s+/g, " ");
20232
20591
  return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
20233
20592
  }
@@ -20897,6 +21256,22 @@ function registerLinearTools(server) {
20897
21256
  }
20898
21257
  }
20899
21258
  );
21259
+ server.tool(
21260
+ "linear_search_issues",
21261
+ "Search or list open Linear issues. Not limited to the current user \u2014 pass assignee=unassigned for issues with no owner, assignee=all (default when query is set) for anyone including unassigned, assignee=me for yours, or a user id / name. Optional query uses Linear search (title, identifier, description).",
21262
+ {
21263
+ query: import_zod3.z.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
21264
+ assignee: import_zod3.z.string().optional().describe("me, unassigned, all, a Linear user id, or a display name. Default: all when query is set, otherwise me."),
21265
+ limit: import_zod3.z.number().int().positive().max(250).optional()
21266
+ },
21267
+ async ({ query, assignee, limit }) => {
21268
+ try {
21269
+ return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
21270
+ } catch (err) {
21271
+ return fail3(err);
21272
+ }
21273
+ }
21274
+ );
20900
21275
  server.tool(
20901
21276
  "linear_get_issue",
20902
21277
  "Get a Linear issue by uuid or identifier (ENG-123). Returns description, comments, relations (blocks/blockedBy/related/duplicate), parent/children, project, cycle, labels, and other metadata.",
@@ -21131,30 +21506,31 @@ function registerScheduleTools(server) {
21131
21506
 
21132
21507
  // src/mcp/server.ts
21133
21508
  init_agent_git_actions();
21509
+ init_gh_errors();
21134
21510
  init_git_auth_mode();
21135
21511
 
21136
21512
  // src/board/load-home-board.ts
21137
- var import_node_fs48 = require("fs");
21138
- var import_node_path44 = require("path");
21513
+ var import_node_fs49 = require("fs");
21514
+ var import_node_path45 = require("path");
21139
21515
  init_worktree();
21140
21516
  init_paths();
21141
21517
 
21142
21518
  // src/board/board-pins.ts
21143
- var import_node_crypto10 = require("crypto");
21144
- var import_node_fs47 = require("fs");
21145
- var import_node_path43 = require("path");
21519
+ var import_node_crypto11 = require("crypto");
21520
+ var import_node_fs48 = require("fs");
21521
+ var import_node_path44 = require("path");
21146
21522
  init_paths();
21147
21523
  init_home_board();
21148
21524
  var FILE = "home-board-pins.json";
21149
21525
  var VERSION = 1;
21150
21526
  function pinsFile() {
21151
- return (0, import_node_path43.join)(appDataDir(), FILE);
21527
+ return (0, import_node_path44.join)(appDataDir(), FILE);
21152
21528
  }
21153
21529
  function readDisk() {
21154
21530
  const path = pinsFile();
21155
- if (!(0, import_node_fs47.existsSync)(path)) return [];
21531
+ if (!(0, import_node_fs48.existsSync)(path)) return [];
21156
21532
  try {
21157
- const raw = JSON.parse((0, import_node_fs47.readFileSync)(path, "utf8"));
21533
+ const raw = JSON.parse((0, import_node_fs48.readFileSync)(path, "utf8"));
21158
21534
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
21159
21535
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
21160
21536
  } catch {
@@ -21162,8 +21538,8 @@ function readDisk() {
21162
21538
  }
21163
21539
  }
21164
21540
  function writeDisk(items) {
21165
- (0, import_node_fs47.mkdirSync)(appDataDir(), { recursive: true });
21166
- (0, import_node_fs47.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
21541
+ (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
21542
+ (0, import_node_fs48.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
21167
21543
  }
21168
21544
  function listBoardPins() {
21169
21545
  return readDisk();
@@ -21184,7 +21560,7 @@ function homeBoardWorkspaceKey(workspaces) {
21184
21560
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
21185
21561
  }
21186
21562
  function cacheFile() {
21187
- return (0, import_node_path44.join)(appDataDir(), "home-board-cache.json");
21563
+ return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
21188
21564
  }
21189
21565
  function emptyInputs() {
21190
21566
  return {
@@ -21210,9 +21586,9 @@ function shouldCacheHomeBoardInputs(inputs) {
21210
21586
  }
21211
21587
  function readDiskCache() {
21212
21588
  const path = cacheFile();
21213
- if (!(0, import_node_fs48.existsSync)(path)) return null;
21589
+ if (!(0, import_node_fs49.existsSync)(path)) return null;
21214
21590
  try {
21215
- const raw = JSON.parse((0, import_node_fs48.readFileSync)(path, "utf8"));
21591
+ const raw = JSON.parse((0, import_node_fs49.readFileSync)(path, "utf8"));
21216
21592
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
21217
21593
  return null;
21218
21594
  }
@@ -21226,8 +21602,8 @@ function readDiskCache() {
21226
21602
  }
21227
21603
  function writeDiskCache(entry) {
21228
21604
  try {
21229
- (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
21230
- (0, import_node_fs48.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
21605
+ (0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
21606
+ (0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
21231
21607
  } catch {
21232
21608
  }
21233
21609
  }
@@ -21516,13 +21892,13 @@ async function startMcpServer() {
21516
21892
  async () => {
21517
21893
  const threads = orch.getThreads(true);
21518
21894
  const lines = threads.map((t) => {
21519
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path45.basename)(t.repoPath) || t.repoPath;
21520
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
21895
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path46.basename)(t.repoPath) || t.repoPath;
21896
+ const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
21521
21897
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
21522
21898
  const preview = lastMessagePreview(t.messages, 80);
21523
21899
  const previewBit = preview ? ` ${preview}` : "";
21524
21900
  const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
21525
- const progress = live?.summary ? ` ${live.summary}` : "";
21901
+ const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
21526
21902
  return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title}${parent}${previewBit}${err} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}${progress}`;
21527
21903
  });
21528
21904
  return {
@@ -21584,7 +21960,9 @@ async function startMcpServer() {
21584
21960
  if (!t) {
21585
21961
  return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
21586
21962
  }
21587
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
21963
+ const stillRunning = orch.threadLooksLive(t);
21964
+ const live = stillRunning ? readTurnLive(t.id) : null;
21965
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
21588
21966
  const spend = orch.getThreadUsage(t.id);
21589
21967
  const summary = {
21590
21968
  id: t.id,
@@ -21604,8 +21982,8 @@ async function startMcpServer() {
21604
21982
  devPort: t.devPort,
21605
21983
  prUrl: t.prUrl,
21606
21984
  lastError: t.lastError ?? null,
21607
- stillRunning: t.status === "running" || t.status === "queued",
21608
- progress: live?.summary ?? (t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
21985
+ stillRunning,
21986
+ progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
21609
21987
  lastActivityAt: live?.updatedAt ?? null,
21610
21988
  usage: spend.usage,
21611
21989
  lastTurnUsage: spend.lastTurnUsage
@@ -21886,7 +22264,7 @@ async function startMcpServer() {
21886
22264
  const ident = issue?.identifier ?? ref.trim();
21887
22265
  const attachments = issue ? [
21888
22266
  {
21889
- id: (0, import_node_crypto11.randomUUID)(),
22267
+ id: (0, import_node_crypto12.randomUUID)(),
21890
22268
  name: issue.identifier,
21891
22269
  kind: "issue",
21892
22270
  content: [
@@ -21962,7 +22340,7 @@ async function startMcpServer() {
21962
22340
  );
21963
22341
  server.tool(
21964
22342
  "wait_for_turn",
21965
- "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
22343
+ "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. stillRunning is the source of truth \u2014 if false, the child is not working (do not say it is waiting for a gate). If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
21966
22344
  {
21967
22345
  ref: import_zod5.z.string(),
21968
22346
  timeoutMs: import_zod5.z.number().optional()
@@ -22154,7 +22532,7 @@ async function startMcpServer() {
22154
22532
  );
22155
22533
  server.tool(
22156
22534
  "ask_git",
22157
- "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` if SSH is missing). 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.",
22535
+ "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.",
22158
22536
  {
22159
22537
  ref: import_zod5.z.string().describe("Worktree thread id/ref"),
22160
22538
  action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
@@ -22179,8 +22557,26 @@ async function startMcpServer() {
22179
22557
  ]
22180
22558
  };
22181
22559
  } catch (err) {
22182
- const message = err instanceof Error ? err.message : String(err);
22183
- return { content: [{ type: "text", text: message }], isError: true };
22560
+ const raw = err instanceof Error ? err.message : String(err);
22561
+ const message = formatGhLandError(raw);
22562
+ return {
22563
+ content: [
22564
+ {
22565
+ type: "text",
22566
+ text: JSON.stringify(
22567
+ {
22568
+ error: true,
22569
+ action,
22570
+ lastError: message,
22571
+ hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_thread so the worktree agent runs gh pr create --draft -R <origin> --body-file <short.md>. Keep the description short." : void 0
22572
+ },
22573
+ null,
22574
+ 2
22575
+ )
22576
+ }
22577
+ ],
22578
+ isError: true
22579
+ };
22184
22580
  }
22185
22581
  }
22186
22582
  );
@@ -22575,11 +22971,15 @@ async function startMcpServer() {
22575
22971
  );
22576
22972
  server.tool(
22577
22973
  "list_issues",
22578
- "List issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
22579
- { repoPath: import_zod5.z.string() },
22580
- async ({ repoPath }) => {
22974
+ "List or search issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear defaults to issues assigned to you; pass assignee=unassigned for no owner, assignee=all for everyone (including unassigned), or a user id / GitHub login. Optional query searches title/identifier. Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. Prefer linear_search_issues when Linear is connected and you need unassigned or other people's tickets. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
22975
+ {
22976
+ repoPath: import_zod5.z.string(),
22977
+ query: import_zod5.z.string().optional().describe("Search title, identifier, or description"),
22978
+ assignee: import_zod5.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
22979
+ },
22980
+ async ({ repoPath, query, assignee }) => {
22581
22981
  const root = await resolveRepoRoot(repoPath);
22582
- const result = await listIssues(root);
22982
+ const result = await listIssues(root, { query, assignee });
22583
22983
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22584
22984
  }
22585
22985
  );