@sideboard-ai/core 0.1.149 → 0.1.151

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 +40 -35
  4. package/dist/agents/cursor-runner.js +2 -2
  5. package/dist/{agents-V4MTDWXS.js → agents-JAOMXDXN.js} +10 -9
  6. package/dist/{agents-HSVQ2Z6Y.js → agents-U2JCFXW4.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-N5PM7HGQ.js → chunk-2SDMENAL.js} +1 -1
  10. package/dist/{chunk-JTPDWTWJ.js → chunk-3JBMACYX.js} +137 -114
  11. package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
  12. package/dist/{chunk-JDYKQ6OI.js → chunk-6H4TJ5TA.js} +136 -75
  13. package/dist/{chunk-EGDRPA4B.js → chunk-77MP647F.js} +6 -6
  14. package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
  15. package/dist/{chunk-R4JP32P5.js → chunk-ADCEGG4A.js} +4 -4
  16. package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
  17. package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
  18. package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
  19. package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
  20. package/dist/{chunk-TZWO7J4W.js → chunk-GCWAAPJ5.js} +115 -54
  21. package/dist/{chunk-YP3CSOZ6.js → chunk-GE7M3QTE.js} +142 -114
  22. package/dist/{chunk-LAFA56WD.js → chunk-HEII7W3Q.js} +1 -1
  23. package/dist/{chunk-3QRGCKYL.js → chunk-HWZWBJWL.js} +2 -2
  24. package/dist/{chunk-FKOIHGKV.js → chunk-JRH62XC4.js} +5 -1
  25. package/dist/{chunk-Q5DHVMXB.js → chunk-LZAOX76N.js} +18 -7
  26. package/dist/{chunk-B3SJXYIJ.js → chunk-NVXVEGGM.js} +1 -1
  27. package/dist/{chunk-ZVYLEF72.js → chunk-OXOU2FRS.js} +6 -6
  28. package/dist/chunk-QQKDGPUI.js +63 -0
  29. package/dist/{chunk-QTUESPAW.js → chunk-RFMQY56R.js} +1 -1
  30. package/dist/chunk-SYFVUF2C.js +65 -0
  31. package/dist/{chunk-Q62SDB53.js → chunk-TSCWSAQL.js} +2 -2
  32. package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
  33. package/dist/{chunk-PTI5H3RK.js → chunk-UIS7BVCX.js} +24 -13
  34. package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
  35. package/dist/{chunk-N3VNOFXQ.js → chunk-Y2FNDKHF.js} +4 -4
  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-LWYUZAXR.js} +6 -5
  39. package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-ZK5MII7W.js} +6 -5
  40. package/dist/{global-workspace-OJRXWXEA.js → global-workspace-IB2CCEJF.js} +7 -6
  41. package/dist/{global-workspace-2SIPM4PW.js → global-workspace-T7RL3XEC.js} +7 -6
  42. package/dist/index.cjs +1010 -577
  43. package/dist/index.d.cts +96 -11
  44. package/dist/index.d.ts +96 -11
  45. package/dist/index.js +272 -93
  46. package/dist/mcp/run-stdio.cjs +981 -581
  47. package/dist/mcp/run-stdio.js +196 -43
  48. package/dist/{orchestrator-Z2O5OVJA.js → orchestrator-DPTRBKEH.js} +16 -13
  49. package/dist/{orchestrator-6TXQWBXN.js → orchestrator-Y5MWUU7C.js} +14 -11
  50. package/dist/{plan-file-6O7G4VPQ.js → plan-file-LSSSQGTQ.js} +2 -2
  51. package/dist/{plan-file-PHVKUAEE.js → plan-file-OZEBFSGQ.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-VICQYI2N.js} +8 -7
  55. package/dist/{workspaces-3NUUZTQK.js → workspaces-ZXCUVCZC.js} +8 -7
  56. package/dist/{worktree-RZRJNHYL.js → worktree-DPIREDFR.js} +5 -4
  57. package/dist/{worktree-UCWWTVLS.js → worktree-HTUM35NT.js} +5 -4
  58. package/dist/worktree-exclude-N5X5I422.js +13 -0
  59. package/dist/worktree-exclude-X54WSOXM.js +11 -0
  60. package/package.json +1 -1
@@ -1764,16 +1764,98 @@ var init_path = __esm({
1764
1764
  }
1765
1765
  });
1766
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
+
1767
1849
  // src/git/stale-lock.ts
1768
1850
  function isIndexLockError(text5) {
1769
1851
  return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
1770
1852
  }
1771
1853
  function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
1772
- const lockPath = (0, import_node_path12.join)(gitDir, "index.lock");
1854
+ const lockPath = (0, import_node_path13.join)(gitDir, "index.lock");
1773
1855
  try {
1774
- if (!(0, import_node_fs11.existsSync)(lockPath)) return null;
1775
- if (now - (0, import_node_fs11.statSync)(lockPath).mtimeMs < maxAgeMs) return null;
1776
- (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);
1777
1859
  return lockPath;
1778
1860
  } catch {
1779
1861
  return null;
@@ -1788,12 +1870,12 @@ function clearStaleIndexLocks(gitDirs, maxAgeMs = STALE_INDEX_LOCK_MS) {
1788
1870
  }
1789
1871
  return removed;
1790
1872
  }
1791
- var import_node_fs11, import_node_path12, STALE_INDEX_LOCK_MS;
1873
+ var import_node_fs12, import_node_path13, STALE_INDEX_LOCK_MS;
1792
1874
  var init_stale_lock = __esm({
1793
1875
  "src/git/stale-lock.ts"() {
1794
1876
  "use strict";
1795
- import_node_fs11 = require("fs");
1796
- import_node_path12 = require("path");
1877
+ import_node_fs12 = require("fs");
1878
+ import_node_path13 = require("path");
1797
1879
  STALE_INDEX_LOCK_MS = 2e4;
1798
1880
  }
1799
1881
  });
@@ -1890,7 +1972,10 @@ async function gh(args, cwd, opts) {
1890
1972
  timeoutMs: opts?.timeoutMs,
1891
1973
  env: {
1892
1974
  GH_PROMPT_DISABLED: "1",
1893
- 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() : {}
1894
1979
  }
1895
1980
  });
1896
1981
  }
@@ -1906,6 +1991,7 @@ var init_run = __esm({
1906
1991
  "use strict";
1907
1992
  import_execa2 = require("execa");
1908
1993
  init_path();
1994
+ init_github_agent_auth();
1909
1995
  init_stale_lock();
1910
1996
  }
1911
1997
  });
@@ -2744,6 +2830,18 @@ var init_worktree_labels = __esm({
2744
2830
  function isGhRateLimitError(text5) {
2745
2831
  return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
2746
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
+ }
2747
2845
  function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
2748
2846
  const ms = resetEpochSec * 1e3 - nowMs;
2749
2847
  if (ms <= 0) return "soon";
@@ -2754,18 +2852,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
2754
2852
  const hours = Math.ceil(mins / 60);
2755
2853
  return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
2756
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
+ }
2757
2866
  function extractGhErrorDetail(text5) {
2758
- const trimmed = text5.trim();
2867
+ const trimmed = omitGhBodyArg(text5.trim());
2759
2868
  if (!trimmed) return "";
2869
+ if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
2870
+ return "GraphQL: body is too long (GitHub PR body / request size limit).";
2871
+ }
2760
2872
  const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
2761
- if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}`;
2873
+ if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
2762
2874
  const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
2763
- if (http?.[1]) return `HTTP: ${http[1].trim()}`;
2875
+ if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
2764
2876
  const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
2765
2877
  if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
2766
- return lines.slice(1).join(" ").trim() || lines[0];
2878
+ return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
2767
2879
  }
2768
- return trimmed;
2880
+ return capGhErrorText(trimmed);
2769
2881
  }
2770
2882
  function formatGhLandError(raw, opts) {
2771
2883
  const trimmed = raw.trim();
@@ -2783,6 +2895,10 @@ function formatGhLandError(raw, opts) {
2783
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>.";
2784
2896
  return `Could not create the pull request.${hint}`;
2785
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
+ }
2786
2902
  if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
2787
2903
  const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
2788
2904
  const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
@@ -2803,15 +2919,85 @@ function formatMergePrError(raw) {
2803
2919
  }
2804
2920
  return extractGhErrorDetail(trimmed) || trimmed;
2805
2921
  }
2922
+ var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
2806
2923
  var init_gh_errors = __esm({
2807
2924
  "src/git/gh-errors.ts"() {
2808
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_CONTEXT_EXCLUDE: () => WORKTREE_CONTEXT_EXCLUDE,
2935
+ WORKTREE_SIDEBOARD_EXCLUDE: () => WORKTREE_SIDEBOARD_EXCLUDE,
2936
+ ensureWorktreeSideboardIgnored: () => ensureWorktreeSideboardIgnored
2937
+ });
2938
+ function excludeHasLine(body, ...needles) {
2939
+ return body.split(/\r?\n/).some((line) => needles.includes(line.trim()));
2940
+ }
2941
+ async function ensureWorktreeSideboardIgnored(worktreePath) {
2942
+ if (!worktreePath.trim()) return;
2943
+ const gitDir = await git(["rev-parse", "--absolute-git-dir"], worktreePath, {
2944
+ reject: false,
2945
+ timeoutMs: 5e3
2946
+ });
2947
+ if (gitDir.exitCode !== 0) return;
2948
+ const dir = gitDir.stdout.trim();
2949
+ if (!dir) return;
2950
+ const excludePath = (0, import_node_path14.join)(dir, "info", "exclude");
2951
+ (0, import_node_fs13.mkdirSync)((0, import_node_path14.dirname)(excludePath), { recursive: true });
2952
+ let body = "";
2953
+ try {
2954
+ body = (0, import_node_fs13.readFileSync)(excludePath, "utf8");
2955
+ } catch {
2956
+ body = "";
2957
+ }
2958
+ const missing = [];
2959
+ if (!excludeHasLine(body, ".sideboard/", ".sideboard", "/.sideboard/")) {
2960
+ missing.push(WORKTREE_SIDEBOARD_EXCLUDE);
2961
+ }
2962
+ if (!excludeHasLine(body, ".context/", ".context", "/.context/")) {
2963
+ missing.push(WORKTREE_CONTEXT_EXCLUDE);
2964
+ }
2965
+ if (missing.length > 0) {
2966
+ const prefix = body && !body.endsWith("\n") ? `${body}
2967
+ ` : body;
2968
+ const header = body.includes(EXCLUDE_COMMENT) ? "" : `${EXCLUDE_COMMENT}
2969
+ `;
2970
+ (0, import_node_fs13.writeFileSync)(excludePath, `${prefix}${header}${missing.join("\n")}
2971
+ `, "utf8");
2972
+ }
2973
+ const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
2974
+ reject: false,
2975
+ timeoutMs: 5e3
2976
+ });
2977
+ if (listed.exitCode !== 0 || !listed.stdout) return;
2978
+ const files = listed.stdout.split("\0").filter(Boolean);
2979
+ if (files.length === 0) return;
2980
+ await git(["update-index", "--skip-worktree", "--", ...files], worktreePath, {
2981
+ reject: false,
2982
+ timeoutMs: 8e3
2983
+ });
2984
+ }
2985
+ var import_node_fs13, import_node_path14, WORKTREE_SIDEBOARD_EXCLUDE, WORKTREE_CONTEXT_EXCLUDE, EXCLUDE_COMMENT;
2986
+ var init_worktree_exclude = __esm({
2987
+ "src/git/worktree-exclude.ts"() {
2988
+ "use strict";
2989
+ import_node_fs13 = require("fs");
2990
+ import_node_path14 = require("path");
2991
+ init_run();
2992
+ WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
2993
+ WORKTREE_CONTEXT_EXCLUDE = ".context/";
2994
+ EXCLUDE_COMMENT = "# Sideboard worktree scratch \u2014 do not commit";
2809
2995
  }
2810
2996
  });
2811
2997
 
2812
2998
  // src/store/secret-vault.ts
2813
2999
  function secretVaultPath() {
2814
- return (0, import_node_path13.join)(appDataDir(), "secrets.json");
3000
+ return (0, import_node_path15.join)(appDataDir(), "secrets.json");
2815
3001
  }
2816
3002
  function loadSecretVault() {
2817
3003
  const parsed = readSecureJson(secretVaultPath());
@@ -2870,11 +3056,11 @@ function normalizeVault(raw) {
2870
3056
  }
2871
3057
  return out;
2872
3058
  }
2873
- var import_node_path13;
3059
+ var import_node_path15;
2874
3060
  var init_secret_vault = __esm({
2875
3061
  "src/store/secret-vault.ts"() {
2876
3062
  "use strict";
2877
- import_node_path13 = require("path");
3063
+ import_node_path15 = require("path");
2878
3064
  init_paths();
2879
3065
  init_secure_file();
2880
3066
  }
@@ -2903,6 +3089,7 @@ var init_issue_source_labels = __esm({
2903
3089
  // src/store/app-settings.ts
2904
3090
  var app_settings_exports = {};
2905
3091
  __export(app_settings_exports, {
3092
+ FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
2906
3093
  GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
2907
3094
  HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
2908
3095
  ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
@@ -2928,6 +3115,7 @@ __export(app_settings_exports, {
2928
3115
  disconnectLinearConnection: () => disconnectLinearConnection,
2929
3116
  emptyPublicIntegrations: () => emptyPublicIntegrations,
2930
3117
  ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
3118
+ followUpBehavior: () => followUpBehavior,
2931
3119
  getAbleTimeAccessToken: () => getAbleTimeAccessToken,
2932
3120
  getAbleTimeHost: () => getAbleTimeHost,
2933
3121
  getDefaultAgent: () => getDefaultAgent,
@@ -3036,10 +3224,10 @@ function toPublicAppSettings(settings) {
3036
3224
  };
3037
3225
  }
3038
3226
  function appSettingsPath() {
3039
- return (0, import_node_path14.join)(appDataDir(), "settings.json");
3227
+ return (0, import_node_path16.join)(appDataDir(), "settings.json");
3040
3228
  }
3041
3229
  function claudeUserSettingsPath() {
3042
- return (0, import_node_path14.join)((0, import_node_os4.homedir)(), ".claude", "settings.json");
3230
+ return (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".claude", "settings.json");
3043
3231
  }
3044
3232
  function normalizeClaude(raw) {
3045
3233
  if (!raw || typeof raw !== "object") return {};
@@ -3284,6 +3472,9 @@ function normalizeAdvanced(raw) {
3284
3472
  if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
3285
3473
  out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
3286
3474
  }
3475
+ if (source.followUpBehavior === "queue" || source.followUpBehavior === "steer") {
3476
+ out.followUpBehavior = source.followUpBehavior;
3477
+ }
3287
3478
  return out;
3288
3479
  }
3289
3480
  function normalizeSettings(raw) {
@@ -3343,10 +3534,10 @@ function normalizeSettings(raw) {
3343
3534
  }
3344
3535
  function readSettingsFile() {
3345
3536
  const path = appSettingsPath();
3346
- if (!(0, import_node_fs12.existsSync)(path)) return { ...EMPTY_SETTINGS };
3537
+ if (!(0, import_node_fs14.existsSync)(path)) return { ...EMPTY_SETTINGS };
3347
3538
  try {
3348
3539
  chmodOwnerOnly(path);
3349
- const parsed = JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
3540
+ const parsed = JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8"));
3350
3541
  return normalizeSettings(parsed);
3351
3542
  } catch {
3352
3543
  return { ...EMPTY_SETTINGS };
@@ -3892,7 +4083,7 @@ function ensureSlackDeviceIdentity(settings = loadAppSettings()) {
3892
4083
  }
3893
4084
  if (!deviceLabel) {
3894
4085
  try {
3895
- deviceLabel = (0, import_node_os4.hostname)().split(".")[0]?.trim() || "This Mac";
4086
+ deviceLabel = (0, import_node_os5.hostname)().split(".")[0]?.trim() || "This Mac";
3896
4087
  } catch {
3897
4088
  deviceLabel = "This Mac";
3898
4089
  }
@@ -3975,6 +4166,9 @@ function updateAdvancedSettings(patch) {
3975
4166
  if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
3976
4167
  advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
3977
4168
  }
4169
+ if (patch.followUpBehavior === "queue" || patch.followUpBehavior === "steer") {
4170
+ advanced.followUpBehavior = patch.followUpBehavior;
4171
+ }
3978
4172
  return saveAppSettings({ ...current, advanced });
3979
4173
  }
3980
4174
  function autoRenameBranchEnabled(settings = loadAppSettings()) {
@@ -4020,6 +4214,9 @@ function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
4020
4214
  }
4021
4215
  return "cursor";
4022
4216
  }
4217
+ function followUpBehavior(settings = loadAppSettings()) {
4218
+ return settings.advanced.followUpBehavior === "queue" ? "queue" : "steer";
4219
+ }
4023
4220
  function maxConcurrentAgents(settings = loadAppSettings()) {
4024
4221
  const n = settings.advanced.maxConcurrent;
4025
4222
  if (typeof n === "number" && Number.isFinite(n)) {
@@ -4107,14 +4304,14 @@ function childEnvWithAppSettings(extra) {
4107
4304
  function harnessEnvKey(harness) {
4108
4305
  return HARNESS_ENV_KEYS[harness];
4109
4306
  }
4110
- 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;
4307
+ 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;
4111
4308
  var init_app_settings = __esm({
4112
4309
  "src/store/app-settings.ts"() {
4113
4310
  "use strict";
4114
4311
  import_node_crypto3 = require("crypto");
4115
- import_node_fs12 = require("fs");
4116
- import_node_os4 = require("os");
4117
- import_node_path14 = require("path");
4312
+ import_node_fs14 = require("fs");
4313
+ import_node_os5 = require("os");
4314
+ import_node_path16 = require("path");
4118
4315
  init_thinking_effort();
4119
4316
  init_nested_electron_env();
4120
4317
  init_paths();
@@ -4136,6 +4333,7 @@ var init_app_settings = __esm({
4136
4333
  "cursor"
4137
4334
  ]);
4138
4335
  GITHUB_GIT_AUTH_MODES = ["auto", "gh", "ssh", "token"];
4336
+ FOLLOW_UP_BEHAVIORS = ["steer", "queue"];
4139
4337
  CLOUD_CONNECT_AGENTS = /* @__PURE__ */ new Set([
4140
4338
  "claude",
4141
4339
  "codex",
@@ -4163,89 +4361,26 @@ var init_app_settings = __esm({
4163
4361
  }
4164
4362
  });
4165
4363
 
4166
- // src/git/github-agent-auth.ts
4167
- function githubAgentAuthDir() {
4168
- const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
4169
- if (override) return override;
4170
- return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".sideboard-git-auth");
4171
- }
4172
- function githubCredentialStorePath() {
4173
- return (0, import_node_path15.join)(githubAgentAuthDir(), "git-credentials");
4174
- }
4175
- function githubGhConfigDir() {
4176
- return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
4177
- }
4178
- function writePrivateFile2(file, body) {
4179
- (0, import_node_fs13.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
4180
- try {
4181
- (0, import_node_fs13.chmodSync)((0, import_node_path15.dirname)(file), 448);
4182
- } catch {
4183
- }
4184
- (0, import_node_fs13.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
4185
- try {
4186
- (0, import_node_fs13.chmodSync)(file, 384);
4187
- } catch {
4364
+ // src/git/git-auth-mode.ts
4365
+ function githubHttpsInsteadOfEntries(remoteUrl) {
4366
+ const entries = [...HTTPS_REWRITE];
4367
+ const url = remoteUrl?.trim() ?? "";
4368
+ const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
4369
+ if (scpAlias?.[1]) {
4370
+ entries.push({
4371
+ key: "url.https://github.com/.insteadOf",
4372
+ value: `${scpAlias[1]}:`
4373
+ });
4188
4374
  }
4189
- }
4190
- function gitCredentialStoreContents(token) {
4191
- return `https://x-access-token:${encodeURIComponent(token)}@github.com
4192
- `;
4193
- }
4194
- function ghHostsYml(token, user = "x-access-token") {
4195
- const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
4196
- return [
4197
- "github.com:",
4198
- " git_protocol: https",
4199
- ` user: ${u}`,
4200
- ` oauth_token: ${token}`,
4201
- " users:",
4202
- ` ${u}:`,
4203
- ` oauth_token: ${token}`,
4204
- ""
4205
- ].join("\n");
4206
- }
4207
- function materializeGithubAgentAuth(token, user) {
4208
- const trimmed = token.trim();
4209
- if (!trimmed) return;
4210
- const root = githubAgentAuthDir();
4211
- (0, import_node_fs13.mkdirSync)(root, { recursive: true, mode: 448 });
4212
- try {
4213
- (0, import_node_fs13.chmodSync)(root, 448);
4214
- } catch {
4375
+ const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
4376
+ if (sshAlias?.[1]) {
4377
+ entries.push({
4378
+ key: "url.https://github.com/.insteadOf",
4379
+ value: `ssh://git@${sshAlias[1]}/`
4380
+ });
4215
4381
  }
4216
- writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
4217
- const ghDir = githubGhConfigDir();
4218
- (0, import_node_fs13.mkdirSync)(ghDir, { recursive: true, mode: 448 });
4219
- writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
4220
- writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
4221
- }
4222
- function githubAgentAuthReady() {
4223
- return (0, import_node_fs13.existsSync)(githubCredentialStorePath()) && (0, import_node_fs13.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
4224
- }
4225
- function githubCredentialHelperGitConfig() {
4226
- const file = githubCredentialStorePath();
4227
- return [
4228
- { key: "credential.helper", value: "" },
4229
- { key: "credential.helper", value: `store --file=${file}` }
4230
- ];
4231
- }
4232
- function githubGhConfigEnv() {
4233
- return {
4234
- GH_CONFIG_DIR: githubGhConfigDir(),
4235
- GH_PROMPT_DISABLED: "1"
4236
- };
4382
+ return entries;
4237
4383
  }
4238
- var import_node_fs13, import_node_os5, import_node_path15;
4239
- var init_github_agent_auth = __esm({
4240
- "src/git/github-agent-auth.ts"() {
4241
- "use strict";
4242
- import_node_fs13 = require("fs");
4243
- import_node_os5 = require("os");
4244
- import_node_path15 = require("path");
4245
- }
4246
- });
4247
-
4248
- // src/git/git-auth-mode.ts
4249
4384
  function nonInteractiveGitProcessEnv() {
4250
4385
  return {
4251
4386
  GIT_TERMINAL_PROMPT: "0",
@@ -4268,16 +4403,19 @@ function appendIndexedGitConfig(existing, entries) {
4268
4403
  out.GIT_CONFIG_COUNT = String(count + entries.length);
4269
4404
  return out;
4270
4405
  }
4271
- function githubAgentGitEnv(existing) {
4406
+ function githubAgentGitEnv(existing, opts) {
4272
4407
  const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
4273
- return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
4408
+ return appendIndexedGitConfig(existing, [
4409
+ ...githubHttpsInsteadOfEntries(opts?.remoteUrl),
4410
+ ...helpers
4411
+ ]);
4274
4412
  }
4275
4413
  function applyGithubGitAuthEnv(existing, opts) {
4276
4414
  const out = { ...nonInteractiveGitProcessEnv() };
4277
4415
  const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
4278
4416
  if (token) materializeGithubAgentAuth(token);
4279
4417
  Object.assign(out, githubGhConfigEnv());
4280
- if (opts.mode === "ssh") return out;
4418
+ if (opts.mode === "ssh" && !token) return out;
4281
4419
  Object.assign(out, githubAgentGitEnv(existing));
4282
4420
  return out;
4283
4421
  }
@@ -4333,7 +4471,7 @@ async function warmGithubAgentAuth(opts) {
4333
4471
  }
4334
4472
  function normalizeWritableRoot(raw) {
4335
4473
  const trimmed = raw.trim().replace(/\/+$/, "");
4336
- return trimmed && (0, import_node_path16.isAbsolute)(trimmed) ? trimmed : null;
4474
+ return trimmed && (0, import_node_path17.isAbsolute)(trimmed) ? trimmed : null;
4337
4475
  }
4338
4476
  async function resolveCodexGitWritableRoots(cwd) {
4339
4477
  const roots = /* @__PURE__ */ new Set();
@@ -4390,8 +4528,9 @@ function formatGitAuthModeDirective(mode) {
4390
4528
  case "ssh":
4391
4529
  return [
4392
4530
  "Git authentication (Settings \u2192 Git mode: SSH):",
4393
- "- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
4394
- "- 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.",
4531
+ "- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
4532
+ "- 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.",
4533
+ "- 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).",
4395
4534
  "- `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.",
4396
4535
  "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
4397
4536
  ].join("\n");
@@ -4410,11 +4549,11 @@ function formatGitAuthModeDirective(mode) {
4410
4549
  ].join("\n");
4411
4550
  }
4412
4551
  }
4413
- var import_node_path16, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4552
+ var import_node_path17, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4414
4553
  var init_git_auth_mode = __esm({
4415
4554
  "src/git/git-auth-mode.ts"() {
4416
4555
  "use strict";
4417
- import_node_path16 = require("path");
4556
+ import_node_path17 = require("path");
4418
4557
  init_app_settings();
4419
4558
  init_github_agent_auth();
4420
4559
  init_run();
@@ -4762,7 +4901,7 @@ function attachmentsGitignoreBody() {
4762
4901
  }
4763
4902
  function isWorkspaceScratchPath(relativePath) {
4764
4903
  const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
4765
- return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
4904
+ 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/");
4766
4905
  }
4767
4906
  var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
4768
4907
  var init_workspace_scratch = __esm({
@@ -4869,7 +5008,7 @@ async function resolveRepoRoot(cwd) {
4869
5008
  }
4870
5009
  function canonicalizeRepoPath(path) {
4871
5010
  try {
4872
- return (0, import_node_fs14.realpathSync)(path);
5011
+ return (0, import_node_fs15.realpathSync)(path);
4873
5012
  } catch {
4874
5013
  return path.replace(/\/+$/, "");
4875
5014
  }
@@ -5608,6 +5747,16 @@ function originFetchBranch(sourceRef) {
5608
5747
  if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
5609
5748
  return ref;
5610
5749
  }
5750
+ async function originRemoteUrl(cwd) {
5751
+ const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
5752
+ return result.exitCode === 0 ? result.stdout.trim() : "";
5753
+ }
5754
+ function githubHttpsRetryEnv(remoteUrl) {
5755
+ return {
5756
+ GIT_TERMINAL_PROMPT: "0",
5757
+ ...githubAgentGitEnv(void 0, { remoteUrl })
5758
+ };
5759
+ }
5611
5760
  async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5612
5761
  const first = await git(args, repoPath, { reject: false, timeoutMs });
5613
5762
  if (first.exitCode === 0) return true;
@@ -5617,15 +5766,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5617
5766
  } catch {
5618
5767
  return false;
5619
5768
  }
5620
- if (mode === "ssh") return false;
5621
5769
  const token = await resolveGithubAgentToken(mode, repoPath);
5622
5770
  if (!token) return false;
5771
+ const remoteUrl = await originRemoteUrl(repoPath);
5623
5772
  const tryHttps = async (header) => git(args, repoPath, {
5624
5773
  reject: false,
5625
5774
  timeoutMs,
5626
- env: { GIT_TERMINAL_PROMPT: "0" },
5775
+ env: githubHttpsRetryEnv(remoteUrl),
5627
5776
  config: {
5628
- "url.https://github.com/.insteadOf": "git@github.com:",
5629
5777
  "http.extraHeader": header
5630
5778
  }
5631
5779
  });
@@ -5707,8 +5855,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
5707
5855
  }
5708
5856
  async function createThreadWorktree(opts) {
5709
5857
  let branchName = `thread/${opts.slug}`;
5710
- const worktreePath = (0, import_node_path17.join)(worktreesRoot(opts.repoPath), opts.slug);
5711
- if ((0, import_node_fs14.existsSync)(worktreePath)) {
5858
+ const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
5859
+ if ((0, import_node_fs15.existsSync)(worktreePath)) {
5712
5860
  throw new Error(`Worktree already exists at ${worktreePath}`);
5713
5861
  }
5714
5862
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5743,13 +5891,14 @@ ${add.stdout}`;
5743
5891
  });
5744
5892
  branchName = added;
5745
5893
  await ensureGhPreferOrigin(worktreePath);
5894
+ await ensureWorktreeSideboardIgnored(worktreePath);
5746
5895
  return { branchName, worktreePath };
5747
5896
  }
5748
5897
  async function createExistingBranchWorktree(opts) {
5749
5898
  const branchName = opts.branchName.trim();
5750
5899
  if (!branchName) throw new Error("branch name required");
5751
- const worktreePath = (0, import_node_path17.join)(worktreesRoot(opts.repoPath), opts.slug);
5752
- if ((0, import_node_fs14.existsSync)(worktreePath)) {
5900
+ const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
5901
+ if ((0, import_node_fs15.existsSync)(worktreePath)) {
5753
5902
  throw new Error(`Worktree already exists at ${worktreePath}`);
5754
5903
  }
5755
5904
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5787,6 +5936,7 @@ async function createExistingBranchWorktree(opts) {
5787
5936
  await git(["checkout", "-B", branchName], worktreePath, { reject: false });
5788
5937
  }
5789
5938
  await ensureGhPreferOrigin(worktreePath);
5939
+ await ensureWorktreeSideboardIgnored(worktreePath);
5790
5940
  return { branchName, worktreePath };
5791
5941
  }
5792
5942
  async function removeWorktree(repoPath, worktreePath, opts) {
@@ -5875,7 +6025,9 @@ async function currentBranch(worktreePath) {
5875
6025
  async function commitAll(worktreePath, message) {
5876
6026
  const dirty = await isDirty(worktreePath);
5877
6027
  if (!dirty) return false;
6028
+ await ensureWorktreeSideboardIgnored(worktreePath);
5878
6029
  await git(["add", "-A"], worktreePath);
6030
+ await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
5879
6031
  await git(["commit", "-m", message], worktreePath);
5880
6032
  return true;
5881
6033
  }
@@ -5889,14 +6041,14 @@ async function pushBranch(worktreePath, branchName) {
5889
6041
  const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
5890
6042
  if (!slug || !token) {
5891
6043
  throw new Error(
5892
- sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
6044
+ sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
5893
6045
  );
5894
6046
  }
6047
+ const remoteUrl = await originRemoteUrl(worktreePath);
5895
6048
  const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
5896
6049
  reject: false,
5897
- env: { GIT_TERMINAL_PROMPT: "0" },
6050
+ env: githubHttpsRetryEnv(remoteUrl),
5898
6051
  config: {
5899
- "url.https://github.com/.insteadOf": "git@github.com:",
5900
6052
  "http.extraHeader": header
5901
6053
  }
5902
6054
  });
@@ -6026,6 +6178,32 @@ async function createOrUpdatePr(worktreePath, opts) {
6026
6178
  const repoArgs = ghRepoSelectArgs(slug);
6027
6179
  const headRef = ghHeadRef(slug, opts.head);
6028
6180
  const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
6181
+ const bodyText = clampGithubPrBody(opts.body ?? opts.title);
6182
+ const bodyFile = (0, import_node_path18.join)(
6183
+ (0, import_node_os6.tmpdir)(),
6184
+ `sideboard-pr-body-${process.pid}-${(0, import_node_crypto4.randomBytes)(6).toString("hex")}.md`
6185
+ );
6186
+ (0, import_node_fs15.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
6187
+ `, "utf8");
6188
+ const bodyArgs = ["--body-file", bodyFile];
6189
+ try {
6190
+ return await createOrUpdatePrWithBodyFile(worktreePath, {
6191
+ ...opts,
6192
+ slug,
6193
+ repoArgs,
6194
+ headRef,
6195
+ branchOnly,
6196
+ bodyArgs
6197
+ });
6198
+ } finally {
6199
+ try {
6200
+ (0, import_node_fs15.unlinkSync)(bodyFile);
6201
+ } catch {
6202
+ }
6203
+ }
6204
+ }
6205
+ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
6206
+ const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
6029
6207
  const existing = await gh(
6030
6208
  [...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
6031
6209
  worktreePath,
@@ -6041,8 +6219,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6041
6219
  branchOnly,
6042
6220
  "--title",
6043
6221
  opts.title,
6044
- "--body",
6045
- opts.body ?? opts.title
6222
+ ...bodyArgs
6046
6223
  ],
6047
6224
  worktreePath,
6048
6225
  { reject: false }
@@ -6057,8 +6234,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6057
6234
  "--web",
6058
6235
  "--title",
6059
6236
  opts.title,
6060
- "--body",
6061
- opts.body ?? opts.title,
6237
+ ...bodyArgs,
6062
6238
  "--base",
6063
6239
  opts.base,
6064
6240
  "--head",
@@ -6079,8 +6255,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6079
6255
  "create",
6080
6256
  "--title",
6081
6257
  opts.title,
6082
- "--body",
6083
- opts.body ?? opts.title,
6258
+ ...bodyArgs,
6084
6259
  "--base",
6085
6260
  opts.base,
6086
6261
  "--head",
@@ -6104,10 +6279,10 @@ function sameRepoPath(a, b) {
6104
6279
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
6105
6280
  }
6106
6281
  function listLocalThreadBranchSlugs(repoPath) {
6107
- const refsDir = (0, import_node_path17.join)(repoPath, ".git", "refs", "heads", "thread");
6108
- if (!(0, import_node_fs14.existsSync)(refsDir)) return [];
6282
+ const refsDir = (0, import_node_path18.join)(repoPath, ".git", "refs", "heads", "thread");
6283
+ if (!(0, import_node_fs15.existsSync)(refsDir)) return [];
6109
6284
  try {
6110
- return (0, import_node_fs14.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6285
+ return (0, import_node_fs15.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6111
6286
  } catch {
6112
6287
  return [];
6113
6288
  }
@@ -6115,8 +6290,8 @@ function listLocalThreadBranchSlugs(repoPath) {
6115
6290
  function collectTakenTeamSlugs(repoPath) {
6116
6291
  const taken = /* @__PURE__ */ new Set();
6117
6292
  const root = worktreesRoot(repoPath);
6118
- if ((0, import_node_fs14.existsSync)(root)) {
6119
- for (const entry of (0, import_node_fs14.readdirSync)(root, { withFileTypes: true })) {
6293
+ if ((0, import_node_fs15.existsSync)(root)) {
6294
+ for (const entry of (0, import_node_fs15.readdirSync)(root, { withFileTypes: true })) {
6120
6295
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
6121
6296
  taken.add(normalizeTakenSlug(entry.name));
6122
6297
  }
@@ -6137,23 +6312,26 @@ function allocateTeamSlug(repoPath) {
6137
6312
  const taken = collectTakenTeamSlugs(repoPath);
6138
6313
  for (let attempt = 0; attempt < 32; attempt++) {
6139
6314
  const team = allocateTeamName(taken);
6140
- const path = (0, import_node_path17.join)(worktreesRoot(repoPath), team.slug);
6141
- if (!(0, import_node_fs14.existsSync)(path)) return team;
6315
+ const path = (0, import_node_path18.join)(worktreesRoot(repoPath), team.slug);
6316
+ if (!(0, import_node_fs15.existsSync)(path)) return team;
6142
6317
  taken.add(team.slug);
6143
6318
  }
6144
6319
  throw new Error("No available soccer team worktree directories left");
6145
6320
  }
6146
- var import_node_fs14, import_node_path17;
6321
+ var import_node_crypto4, import_node_fs15, import_node_os6, import_node_path18;
6147
6322
  var init_worktree = __esm({
6148
6323
  "src/git/worktree.ts"() {
6149
6324
  "use strict";
6150
- import_node_fs14 = require("fs");
6151
- import_node_path17 = require("path");
6325
+ import_node_crypto4 = require("crypto");
6326
+ import_node_fs15 = require("fs");
6327
+ import_node_os6 = require("os");
6328
+ import_node_path18 = require("path");
6152
6329
  init_paths();
6153
6330
  init_thread_store();
6154
6331
  init_teams();
6155
6332
  init_worktree_labels();
6156
6333
  init_gh_errors();
6334
+ init_worktree_exclude();
6157
6335
  init_git_auth_mode();
6158
6336
  init_run();
6159
6337
  init_repo_git_lock();
@@ -6197,7 +6375,7 @@ var init_cloud_connect_constants = __esm({
6197
6375
 
6198
6376
  // src/composer/stage-files.ts
6199
6377
  function fileExtension(filePath) {
6200
- const base = (0, import_node_path18.basename)(filePath).toLowerCase();
6378
+ const base = (0, import_node_path19.basename)(filePath).toLowerCase();
6201
6379
  return base.includes(".") ? base.split(".").pop() || "" : "";
6202
6380
  }
6203
6381
  function isImageFilePath(filePath) {
@@ -6207,24 +6385,24 @@ function imageMimeType(filePath) {
6207
6385
  return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
6208
6386
  }
6209
6387
  function ensureAttachmentsDir(worktreePath) {
6210
- const dir = (0, import_node_path18.join)(worktreePath, ATTACHMENTS_DIR);
6211
- (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
6212
- const gi = (0, import_node_path18.join)(dir, ".gitignore");
6213
- if (!(0, import_node_fs15.existsSync)(gi)) {
6214
- (0, import_node_fs15.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
6388
+ const dir = (0, import_node_path19.join)(worktreePath, ATTACHMENTS_DIR);
6389
+ (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
6390
+ const gi = (0, import_node_path19.join)(dir, ".gitignore");
6391
+ if (!(0, import_node_fs16.existsSync)(gi)) {
6392
+ (0, import_node_fs16.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
6215
6393
  }
6216
6394
  return dir;
6217
6395
  }
6218
6396
  function uniqueAttachmentName(dir, originalName) {
6219
6397
  const safe = originalName.replace(/[/\\]/g, "_") || "file";
6220
- if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, safe))) return safe;
6221
- const ext = (0, import_node_path18.extname)(safe);
6398
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path19.join)(dir, safe))) return safe;
6399
+ const ext = (0, import_node_path19.extname)(safe);
6222
6400
  const stem = ext ? safe.slice(0, -ext.length) : safe;
6223
6401
  for (let i = 1; i < 1e4; i++) {
6224
6402
  const candidate = `${stem}-${i}${ext}`;
6225
- if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, candidate))) return candidate;
6403
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path19.join)(dir, candidate))) return candidate;
6226
6404
  }
6227
- return `${stem}-${(0, import_node_crypto4.randomUUID)()}${ext}`;
6405
+ return `${stem}-${(0, import_node_crypto5.randomUUID)()}${ext}`;
6228
6406
  }
6229
6407
  function previewDataUrlFromBuf(filePath, buf) {
6230
6408
  if (!isImageFilePath(filePath)) return void 0;
@@ -6236,7 +6414,7 @@ function attachmentFromBuffer(name, buf, opts) {
6236
6414
  if (isImageFilePath(name)) {
6237
6415
  const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
6238
6416
  return {
6239
- id: (0, import_node_crypto4.randomUUID)(),
6417
+ id: (0, import_node_crypto5.randomUUID)(),
6240
6418
  name,
6241
6419
  kind: "file",
6242
6420
  path: opts.path,
@@ -6249,7 +6427,7 @@ function attachmentFromBuffer(name, buf, opts) {
6249
6427
  }
6250
6428
  if (buf.length > MAX_INLINE_BYTES) {
6251
6429
  return {
6252
- id: (0, import_node_crypto4.randomUUID)(),
6430
+ id: (0, import_node_crypto5.randomUUID)(),
6253
6431
  name,
6254
6432
  kind: "file",
6255
6433
  path: opts.path,
@@ -6258,7 +6436,7 @@ function attachmentFromBuffer(name, buf, opts) {
6258
6436
  }
6259
6437
  if (buf.includes(0)) {
6260
6438
  return {
6261
- id: (0, import_node_crypto4.randomUUID)(),
6439
+ id: (0, import_node_crypto5.randomUUID)(),
6262
6440
  name,
6263
6441
  kind: "file",
6264
6442
  path: opts.path,
@@ -6266,7 +6444,7 @@ function attachmentFromBuffer(name, buf, opts) {
6266
6444
  };
6267
6445
  }
6268
6446
  return {
6269
- id: (0, import_node_crypto4.randomUUID)(),
6447
+ id: (0, import_node_crypto5.randomUUID)(),
6270
6448
  name,
6271
6449
  kind: "file",
6272
6450
  path: opts.path,
@@ -6278,19 +6456,19 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
6278
6456
  const dir = ensureAttachmentsDir(worktreePath);
6279
6457
  const out = [];
6280
6458
  for (const abs of absolutePaths) {
6281
- const originalName = (0, import_node_path18.basename)(abs);
6459
+ const originalName = (0, import_node_path19.basename)(abs);
6282
6460
  try {
6283
- const st = (0, import_node_fs15.statSync)(abs);
6461
+ const st = (0, import_node_fs16.statSync)(abs);
6284
6462
  if (!st.isFile()) continue;
6285
6463
  const name = uniqueAttachmentName(dir, originalName);
6286
- const destAbs = (0, import_node_path18.join)(dir, name);
6287
- (0, import_node_fs15.copyFileSync)(abs, destAbs);
6464
+ const destAbs = (0, import_node_path19.join)(dir, name);
6465
+ (0, import_node_fs16.copyFileSync)(abs, destAbs);
6288
6466
  const rel = `${ATTACHMENTS_DIR}/${name}`;
6289
- const buf = (0, import_node_fs15.readFileSync)(destAbs);
6467
+ const buf = (0, import_node_fs16.readFileSync)(destAbs);
6290
6468
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
6291
6469
  } catch (err) {
6292
6470
  out.push({
6293
- id: (0, import_node_crypto4.randomUUID)(),
6471
+ id: (0, import_node_crypto5.randomUUID)(),
6294
6472
  name: originalName,
6295
6473
  kind: "file",
6296
6474
  content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
@@ -6308,13 +6486,13 @@ function stageBuffersAsAttachments(worktreePath, buffers2) {
6308
6486
  try {
6309
6487
  const buf = Buffer.from(item.dataBase64, "base64");
6310
6488
  const name = uniqueAttachmentName(dir, originalName);
6311
- const destAbs = (0, import_node_path18.join)(dir, name);
6312
- (0, import_node_fs15.writeFileSync)(destAbs, buf);
6489
+ const destAbs = (0, import_node_path19.join)(dir, name);
6490
+ (0, import_node_fs16.writeFileSync)(destAbs, buf);
6313
6491
  const rel = `${ATTACHMENTS_DIR}/${name}`;
6314
6492
  out.push(attachmentFromBuffer(name, buf, { path: rel }));
6315
6493
  } catch (err) {
6316
6494
  out.push({
6317
- id: (0, import_node_crypto4.randomUUID)(),
6495
+ id: (0, import_node_crypto5.randomUUID)(),
6318
6496
  name: originalName,
6319
6497
  kind: "file",
6320
6498
  content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
@@ -6369,23 +6547,23 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
6369
6547
  for (const rel of relativePaths) {
6370
6548
  if (!rel || rel.includes("..") || rel.startsWith("/")) {
6371
6549
  out.push({
6372
- id: (0, import_node_crypto4.randomUUID)(),
6373
- name: (0, import_node_path18.basename)(rel) || "file",
6550
+ id: (0, import_node_crypto5.randomUUID)(),
6551
+ name: (0, import_node_path19.basename)(rel) || "file",
6374
6552
  kind: "file",
6375
6553
  content: `(invalid path: ${rel})`
6376
6554
  });
6377
6555
  continue;
6378
6556
  }
6379
- const name = (0, import_node_path18.basename)(rel);
6557
+ const name = (0, import_node_path19.basename)(rel);
6380
6558
  try {
6381
- const abs = (0, import_node_path18.join)(worktreePath, rel);
6382
- const st = (0, import_node_fs15.statSync)(abs);
6559
+ const abs = (0, import_node_path19.join)(worktreePath, rel);
6560
+ const st = (0, import_node_fs16.statSync)(abs);
6383
6561
  if (!st.isFile()) continue;
6384
- const buf = (0, import_node_fs15.readFileSync)(abs);
6562
+ const buf = (0, import_node_fs16.readFileSync)(abs);
6385
6563
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
6386
6564
  } catch (err) {
6387
6565
  out.push({
6388
- id: (0, import_node_crypto4.randomUUID)(),
6566
+ id: (0, import_node_crypto5.randomUUID)(),
6389
6567
  name,
6390
6568
  kind: "file",
6391
6569
  content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
@@ -6394,13 +6572,13 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
6394
6572
  }
6395
6573
  return out;
6396
6574
  }
6397
- 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;
6575
+ 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;
6398
6576
  var init_stage_files = __esm({
6399
6577
  "src/composer/stage-files.ts"() {
6400
6578
  "use strict";
6401
- import_node_fs15 = require("fs");
6402
- import_node_path18 = require("path");
6403
- import_node_crypto4 = require("crypto");
6579
+ import_node_fs16 = require("fs");
6580
+ import_node_path19 = require("path");
6581
+ import_node_crypto5 = require("crypto");
6404
6582
  init_workspace_scratch();
6405
6583
  IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
6406
6584
  "png",
@@ -6517,7 +6695,7 @@ function coordinatorTurnReminder(opts) {
6517
6695
  function ensureGlobalCoordinatorCwd(opts) {
6518
6696
  const dir = globalAgentCwd();
6519
6697
  try {
6520
- (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
6698
+ (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
6521
6699
  } catch {
6522
6700
  return dir;
6523
6701
  }
@@ -6525,7 +6703,7 @@ function ensureGlobalCoordinatorCwd(opts) {
6525
6703
  let orchId = opts?.orchestratorThreadId?.trim() || "";
6526
6704
  if (!orchId) {
6527
6705
  try {
6528
- const existing = (0, import_node_fs16.readFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), "utf8");
6706
+ const existing = (0, import_node_fs17.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
6529
6707
  const m = existing.match(
6530
6708
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
6531
6709
  );
@@ -6568,9 +6746,9 @@ function ensureGlobalCoordinatorCwd(opts) {
6568
6746
  "Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
6569
6747
  ].join("\n");
6570
6748
  try {
6571
- (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "CLAUDE.md"), `${body}
6749
+ (0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
6572
6750
  `, "utf8");
6573
- (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), `${body}
6751
+ (0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
6574
6752
  `, "utf8");
6575
6753
  } catch {
6576
6754
  }
@@ -6602,12 +6780,12 @@ function coordinatorSystemPrompt(opts) {
6602
6780
  formatWorkspaceInventory(opts.workspaces)
6603
6781
  ].join("\n");
6604
6782
  }
6605
- var import_node_fs16, import_node_path19, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6783
+ var import_node_fs17, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6606
6784
  var init_coordinator_prompt = __esm({
6607
6785
  "src/orchestrator/coordinator-prompt.ts"() {
6608
6786
  "use strict";
6609
- import_node_fs16 = require("fs");
6610
- import_node_path19 = require("path");
6787
+ import_node_fs17 = require("fs");
6788
+ import_node_path20 = require("path");
6611
6789
  init_worktree();
6612
6790
  init_app_settings();
6613
6791
  init_paths();
@@ -6617,8 +6795,8 @@ var init_coordinator_prompt = __esm({
6617
6795
  "Discover:",
6618
6796
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
6619
6797
  "- 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.",
6620
- "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues)",
6621
- "- 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.",
6798
+ "- 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.",
6799
+ "- 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.",
6622
6800
  "- 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).",
6623
6801
  "- 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",
6624
6802
  "- 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).",
@@ -6637,7 +6815,7 @@ var init_coordinator_prompt = __esm({
6637
6815
  "- 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.",
6638
6816
  "- 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.",
6639
6817
  "- 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)",
6640
- "- 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.",
6818
+ "- 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.",
6641
6819
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
6642
6820
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
6643
6821
  "Setup / run:",
@@ -6646,7 +6824,7 @@ var init_coordinator_prompt = __esm({
6646
6824
  "Inspect / review / PRs:",
6647
6825
  "- get_diff \u2014 compact diff summary",
6648
6826
  '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else seeds that skill / local guidelines; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
6649
- "- 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.",
6827
+ "- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error.",
6650
6828
  '- 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.',
6651
6829
  '- 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.',
6652
6830
  "Process guides:",
@@ -6917,32 +7095,32 @@ var init_global_workspace = __esm({
6917
7095
  function brightsyConfigPath() {
6918
7096
  const override = process.env.BRIGHTSY_CONFIG?.trim();
6919
7097
  if (override) return override;
6920
- return (0, import_node_path20.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
7098
+ return (0, import_node_path21.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
6921
7099
  }
6922
7100
  function loadBrightsyConfig() {
6923
7101
  const path = brightsyConfigPath();
6924
- if (!(0, import_node_fs17.existsSync)(path)) {
7102
+ if (!(0, import_node_fs18.existsSync)(path)) {
6925
7103
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
6926
7104
  }
6927
- const raw = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
7105
+ const raw = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
6928
7106
  if (!raw.access_token || !raw.account_id) {
6929
7107
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
6930
7108
  }
6931
7109
  return raw;
6932
7110
  }
6933
7111
  function saveBrightsyConfig(cfg) {
6934
- (0, import_node_fs17.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7112
+ (0, import_node_fs18.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6935
7113
  `, {
6936
7114
  mode: 384
6937
7115
  });
6938
7116
  }
6939
- var import_node_fs17, import_node_os6, import_node_path20;
7117
+ var import_node_fs18, import_node_os7, import_node_path21;
6940
7118
  var init_config = __esm({
6941
7119
  "src/brightsy/config.ts"() {
6942
7120
  "use strict";
6943
- import_node_fs17 = require("fs");
6944
- import_node_os6 = require("os");
6945
- import_node_path20 = require("path");
7121
+ import_node_fs18 = require("fs");
7122
+ import_node_os7 = require("os");
7123
+ import_node_path21 = require("path");
6946
7124
  }
6947
7125
  });
6948
7126
 
@@ -7059,22 +7237,22 @@ var init_oauth = __esm({
7059
7237
 
7060
7238
  // src/brightsy/connected-teams.ts
7061
7239
  function storePath4() {
7062
- return (0, import_node_path21.join)(appDataDir(), "brightsy-teams.json");
7240
+ return (0, import_node_path22.join)(appDataDir(), "brightsy-teams.json");
7063
7241
  }
7064
7242
  function readStore4() {
7065
7243
  const path = storePath4();
7066
- if (!(0, import_node_fs18.existsSync)(path)) return [];
7244
+ if (!(0, import_node_fs19.existsSync)(path)) return [];
7067
7245
  try {
7068
- const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
7246
+ const parsed = JSON.parse((0, import_node_fs19.readFileSync)(path, "utf8"));
7069
7247
  return Array.isArray(parsed.teams) ? parsed.teams : [];
7070
7248
  } catch {
7071
7249
  return [];
7072
7250
  }
7073
7251
  }
7074
7252
  function writeStore2(teams) {
7075
- (0, import_node_fs18.mkdirSync)(appDataDir(), { recursive: true });
7253
+ (0, import_node_fs19.mkdirSync)(appDataDir(), { recursive: true });
7076
7254
  const path = storePath4();
7077
- (0, import_node_fs18.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
7255
+ (0, import_node_fs19.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
7078
7256
  `, {
7079
7257
  mode: 384
7080
7258
  });
@@ -7180,12 +7358,12 @@ function brightsyMcpServerName(slug) {
7180
7358
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
7181
7359
  return `brightsy_${cleaned || "team"}`;
7182
7360
  }
7183
- var import_node_fs18, import_node_path21;
7361
+ var import_node_fs19, import_node_path22;
7184
7362
  var init_connected_teams = __esm({
7185
7363
  "src/brightsy/connected-teams.ts"() {
7186
7364
  "use strict";
7187
- import_node_fs18 = require("fs");
7188
- import_node_path21 = require("path");
7365
+ import_node_fs19 = require("fs");
7366
+ import_node_path22 = require("path");
7189
7367
  init_paths();
7190
7368
  init_accounts();
7191
7369
  init_config();
@@ -7557,11 +7735,11 @@ async function syncCliForTarget(accountId) {
7557
7735
  }
7558
7736
  applyConnectedTeamToCli(team);
7559
7737
  }
7560
- var import_node_fs19, brightsyAdapter;
7738
+ var import_node_fs20, brightsyAdapter;
7561
7739
  var init_brightsy = __esm({
7562
7740
  "src/agents/brightsy.ts"() {
7563
7741
  "use strict";
7564
- import_node_fs19 = require("fs");
7742
+ import_node_fs20 = require("fs");
7565
7743
  init_run();
7566
7744
  init_connected_teams();
7567
7745
  init_config();
@@ -7576,7 +7754,7 @@ var init_brightsy = __esm({
7576
7754
  async detect() {
7577
7755
  const brightsy = resolveAgentExecutable("brightsy");
7578
7756
  if (brightsy !== "brightsy") {
7579
- if (!(0, import_node_fs19.existsSync)(brightsy)) {
7757
+ if (!(0, import_node_fs20.existsSync)(brightsy)) {
7580
7758
  return {
7581
7759
  agent: "brightsy",
7582
7760
  installed: false,
@@ -7807,6 +7985,13 @@ function isSubagentToolName(name) {
7807
7985
  if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
7808
7986
  return /connectedAgentRequest/i.test(n);
7809
7987
  }
7988
+ function isInternalAgentStatusText(text5) {
7989
+ const t = text5.trim();
7990
+ if (!t) return false;
7991
+ if (/waiting for gate to pass/i.test(t)) return true;
7992
+ if (/^agent is running\b/i.test(t) && t.length < 160) return true;
7993
+ return false;
7994
+ }
7810
7995
  function isPollWrapperToolName(name) {
7811
7996
  const n = (name ?? "").replace(/[_-]/g, "");
7812
7997
  return /^(taskoutput|taskstop|sleep)$/i.test(n);
@@ -7814,7 +7999,10 @@ function isPollWrapperToolName(name) {
7814
7999
  function lastTextPart(parts, type) {
7815
8000
  for (let i = parts.length - 1; i >= 0; i--) {
7816
8001
  const p = parts[i];
7817
- if (p.type === type && p.text.trim()) return p.text.trim();
8002
+ if (p.type !== type) continue;
8003
+ const text5 = p.text.trim();
8004
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
8005
+ return text5;
7818
8006
  }
7819
8007
  return "";
7820
8008
  }
@@ -8151,43 +8339,43 @@ function electronResourcesPath() {
8151
8339
  function packagedCursorRuntimeDir() {
8152
8340
  const resources = electronResourcesPath();
8153
8341
  if (!resources) return null;
8154
- const dir = (0, import_node_path22.join)(resources, "cursor-runtime");
8155
- if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
8342
+ const dir = (0, import_node_path23.join)(resources, "cursor-runtime");
8343
+ if (!(0, import_node_fs21.existsSync)((0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
8156
8344
  return dir;
8157
8345
  }
8158
8346
  function packagedCursorRunnerPath() {
8159
8347
  const dir = packagedCursorRuntimeDir();
8160
- return dir ? (0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
8348
+ return dir ? (0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
8161
8349
  }
8162
8350
  function packagedMcpDir() {
8163
8351
  const resources = electronResourcesPath();
8164
8352
  if (!resources) return null;
8165
- const dir = (0, import_node_path22.join)(resources, "sideboard-mcp");
8166
- if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
8353
+ const dir = (0, import_node_path23.join)(resources, "sideboard-mcp");
8354
+ if (!(0, import_node_fs21.existsSync)((0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
8167
8355
  return dir;
8168
8356
  }
8169
8357
  function packagedMcpStdioPath() {
8170
8358
  const dir = packagedMcpDir();
8171
- return dir ? (0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
8359
+ return dir ? (0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
8172
8360
  }
8173
8361
  function packagedBundledNodePath() {
8174
8362
  const resources = electronResourcesPath();
8175
8363
  if (!resources) return null;
8176
- const bin = (0, import_node_path22.join)(resources, "node", "bin", "node");
8177
- if (!(0, import_node_fs20.existsSync)(bin)) return null;
8364
+ const bin = (0, import_node_path23.join)(resources, "node", "bin", "node");
8365
+ if (!(0, import_node_fs21.existsSync)(bin)) return null;
8178
8366
  return bin;
8179
8367
  }
8180
8368
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
8181
8369
  const dir = packagedCursorRuntimeDir();
8182
8370
  if (!dir) return null;
8183
- return (0, import_node_path22.join)(dir, "node_modules", platformPkg, "bin", binName);
8371
+ return (0, import_node_path23.join)(dir, "node_modules", platformPkg, "bin", binName);
8184
8372
  }
8185
- var import_node_fs20, import_node_path22;
8373
+ var import_node_fs21, import_node_path23;
8186
8374
  var init_packaged_runtime = __esm({
8187
8375
  "src/agents/packaged-runtime.ts"() {
8188
8376
  "use strict";
8189
- import_node_fs20 = require("fs");
8190
- import_node_path22 = require("path");
8377
+ import_node_fs21 = require("fs");
8378
+ import_node_path23 = require("path");
8191
8379
  }
8192
8380
  });
8193
8381
 
@@ -8221,7 +8409,7 @@ function unpackedAsarPath(filePath) {
8221
8409
  if (!isAsarPath(filePath)) return null;
8222
8410
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
8223
8411
  if (unpacked === filePath) return null;
8224
- return (0, import_node_fs21.existsSync)(unpacked) ? unpacked : null;
8412
+ return (0, import_node_fs22.existsSync)(unpacked) ? unpacked : null;
8225
8413
  }
8226
8414
  function nodeReadableScriptPath(scriptPath) {
8227
8415
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -8261,37 +8449,37 @@ function pickPreferredNode(candidates) {
8261
8449
  return best;
8262
8450
  }
8263
8451
  function versionDirNodeBins(root, toBin) {
8264
- if (!(0, import_node_fs21.existsSync)(root)) return [];
8452
+ if (!(0, import_node_fs22.existsSync)(root)) return [];
8265
8453
  try {
8266
- return (0, import_node_fs21.readdirSync)(root).map(toBin);
8454
+ return (0, import_node_fs22.readdirSync)(root).map(toBin);
8267
8455
  } catch {
8268
8456
  return [];
8269
8457
  }
8270
8458
  }
8271
- function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
8459
+ function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
8272
8460
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
8273
- (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path23.join)(prefix, "opt", `node@${major}`, "bin", "node"))
8461
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path24.join)(prefix, "opt", `node@${major}`, "bin", "node"))
8274
8462
  );
8275
8463
  return [
8276
8464
  ...kegs,
8277
8465
  "/opt/homebrew/bin/node",
8278
8466
  "/usr/local/bin/node",
8279
- (0, import_node_path23.join)(home, ".local/share/fnm/aliases/default/bin/node"),
8280
- (0, import_node_path23.join)(home, ".nvm/current/bin/node"),
8281
- (0, import_node_path23.join)(home, ".volta/bin/node"),
8282
- (0, import_node_path23.join)(home, ".asdf/shims/node"),
8283
- (0, import_node_path23.join)(home, ".local/share/mise/shims/node"),
8467
+ (0, import_node_path24.join)(home, ".local/share/fnm/aliases/default/bin/node"),
8468
+ (0, import_node_path24.join)(home, ".nvm/current/bin/node"),
8469
+ (0, import_node_path24.join)(home, ".volta/bin/node"),
8470
+ (0, import_node_path24.join)(home, ".asdf/shims/node"),
8471
+ (0, import_node_path24.join)(home, ".local/share/mise/shims/node"),
8284
8472
  ...versionDirNodeBins(
8285
- (0, import_node_path23.join)(home, ".nvm", "versions", "node"),
8286
- (name) => (0, import_node_path23.join)(home, ".nvm", "versions", "node", name, "bin", "node")
8473
+ (0, import_node_path24.join)(home, ".nvm", "versions", "node"),
8474
+ (name) => (0, import_node_path24.join)(home, ".nvm", "versions", "node", name, "bin", "node")
8287
8475
  ),
8288
8476
  ...versionDirNodeBins(
8289
- (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions"),
8290
- (name) => (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
8477
+ (0, import_node_path24.join)(home, ".local/share/fnm", "node-versions"),
8478
+ (name) => (0, import_node_path24.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
8291
8479
  ),
8292
8480
  ...versionDirNodeBins(
8293
- (0, import_node_path23.join)(home, ".volta", "tools", "image", "node"),
8294
- (name) => (0, import_node_path23.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
8481
+ (0, import_node_path24.join)(home, ".volta", "tools", "image", "node"),
8482
+ (name) => (0, import_node_path24.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
8295
8483
  )
8296
8484
  ];
8297
8485
  }
@@ -8300,10 +8488,10 @@ function uniqueExistingNodeBins(paths) {
8300
8488
  const out = [];
8301
8489
  for (const raw of paths) {
8302
8490
  const p = raw.trim();
8303
- if (!p || !(0, import_node_fs21.existsSync)(p) || isElectronLikeCommand(p)) continue;
8491
+ if (!p || !(0, import_node_fs22.existsSync)(p) || isElectronLikeCommand(p)) continue;
8304
8492
  let key = p;
8305
8493
  try {
8306
- key = (0, import_node_fs21.realpathSync)(p);
8494
+ key = (0, import_node_fs22.realpathSync)(p);
8307
8495
  } catch {
8308
8496
  continue;
8309
8497
  }
@@ -8383,13 +8571,13 @@ async function resolveNodeLaunch(scriptPath) {
8383
8571
  env: { ELECTRON_RUN_AS_NODE: "1" }
8384
8572
  };
8385
8573
  }
8386
- var import_node_fs21, import_node_os7, import_node_path23, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
8574
+ var import_node_fs22, import_node_os8, import_node_path24, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
8387
8575
  var init_node_launch = __esm({
8388
8576
  "src/agents/node-launch.ts"() {
8389
8577
  "use strict";
8390
- import_node_fs21 = require("fs");
8391
- import_node_os7 = require("os");
8392
- import_node_path23 = require("path");
8578
+ import_node_fs22 = require("fs");
8579
+ import_node_os8 = require("os");
8580
+ import_node_path24 = require("path");
8393
8581
  init_nested_electron_env();
8394
8582
  init_run();
8395
8583
  init_packaged_runtime();
@@ -8483,37 +8671,37 @@ function corePackageDir() {
8483
8671
  try {
8484
8672
  const url = import_meta.url;
8485
8673
  if (typeof url === "string" && url.length > 0) {
8486
- return (0, import_node_path24.dirname)((0, import_node_url.fileURLToPath)(url));
8674
+ return (0, import_node_path25.dirname)((0, import_node_url.fileURLToPath)(url));
8487
8675
  }
8488
8676
  } catch {
8489
8677
  }
8490
8678
  try {
8491
- const req = (0, import_node_module.createRequire)((0, import_node_path24.join)(process.cwd(), "package.json"));
8492
- return (0, import_node_path24.dirname)(req.resolve("@sideboard-ai/core"));
8679
+ const req = (0, import_node_module.createRequire)((0, import_node_path25.join)(process.cwd(), "package.json"));
8680
+ return (0, import_node_path25.dirname)(req.resolve("@sideboard-ai/core"));
8493
8681
  } catch {
8494
8682
  return process.cwd();
8495
8683
  }
8496
8684
  }
8497
8685
  function findSideboardMcpJsEntry() {
8498
8686
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
8499
- if (override && (0, import_node_fs22.existsSync)(override)) return override;
8687
+ if (override && (0, import_node_fs23.existsSync)(override)) return override;
8500
8688
  const packaged = packagedMcpStdioPath();
8501
8689
  if (packaged) return packaged;
8502
8690
  let dir = corePackageDir();
8503
8691
  for (let i = 0; i < 10; i++) {
8504
8692
  const candidates = [
8505
- (0, import_node_path24.join)(dir, "mcp/run-stdio.js"),
8506
- (0, import_node_path24.join)(dir, "mcp/run-stdio.cjs"),
8507
- (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.js"),
8508
- (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.cjs"),
8509
- (0, import_node_path24.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
8510
- (0, import_node_path24.join)(dir, "packages/cli/dist/index.js"),
8511
- (0, import_node_path24.join)(dir, "cli/dist/index.js")
8693
+ (0, import_node_path25.join)(dir, "mcp/run-stdio.js"),
8694
+ (0, import_node_path25.join)(dir, "mcp/run-stdio.cjs"),
8695
+ (0, import_node_path25.join)(dir, "dist/mcp/run-stdio.js"),
8696
+ (0, import_node_path25.join)(dir, "dist/mcp/run-stdio.cjs"),
8697
+ (0, import_node_path25.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
8698
+ (0, import_node_path25.join)(dir, "packages/cli/dist/index.js"),
8699
+ (0, import_node_path25.join)(dir, "cli/dist/index.js")
8512
8700
  ];
8513
8701
  for (const p of candidates) {
8514
- if ((0, import_node_fs22.existsSync)(p) && !isAsarPath(p)) return p;
8702
+ if ((0, import_node_fs23.existsSync)(p) && !isAsarPath(p)) return p;
8515
8703
  }
8516
- const parent = (0, import_node_path24.dirname)(dir);
8704
+ const parent = (0, import_node_path25.dirname)(dir);
8517
8705
  if (parent === dir) break;
8518
8706
  dir = parent;
8519
8707
  }
@@ -8655,19 +8843,19 @@ function writeMcpServersConfig(servers) {
8655
8843
  ...env ? { env } : {}
8656
8844
  };
8657
8845
  }
8658
- const dir = (0, import_node_fs22.mkdtempSync)((0, import_node_path24.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
8659
- const cfgPath = (0, import_node_path24.join)(dir, "mcp.json");
8660
- (0, import_node_fs22.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8846
+ const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path25.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
8847
+ const cfgPath = (0, import_node_path25.join)(dir, "mcp.json");
8848
+ (0, import_node_fs23.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8661
8849
  return cfgPath;
8662
8850
  }
8663
- 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;
8851
+ 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;
8664
8852
  var init_injected_mcp = __esm({
8665
8853
  "src/agents/injected-mcp.ts"() {
8666
8854
  "use strict";
8667
- import_node_fs22 = require("fs");
8855
+ import_node_fs23 = require("fs");
8668
8856
  import_node_module = require("module");
8669
- import_node_os8 = require("os");
8670
- import_node_path24 = require("path");
8857
+ import_node_os9 = require("os");
8858
+ import_node_path25 = require("path");
8671
8859
  import_node_url = require("url");
8672
8860
  init_run();
8673
8861
  init_config();
@@ -9006,11 +9194,11 @@ function parseIssuesJson(raw) {
9006
9194
  }
9007
9195
  return [];
9008
9196
  }
9009
- var import_node_fs23, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
9197
+ var import_node_fs24, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
9010
9198
  var init_claude = __esm({
9011
9199
  "src/agents/claude.ts"() {
9012
9200
  "use strict";
9013
- import_node_fs23 = require("fs");
9201
+ import_node_fs24 = require("fs");
9014
9202
  init_run();
9015
9203
  init_app_settings();
9016
9204
  init_claude_mcp();
@@ -9050,7 +9238,7 @@ var init_claude = __esm({
9050
9238
  async detect() {
9051
9239
  const claude = resolveClaudeExecutable();
9052
9240
  if (claude !== "claude") {
9053
- if (!(0, import_node_fs23.existsSync)(claude)) {
9241
+ if (!(0, import_node_fs24.existsSync)(claude)) {
9054
9242
  return {
9055
9243
  agent: "claude",
9056
9244
  installed: false,
@@ -9305,7 +9493,7 @@ async function listCodexModels() {
9305
9493
  if (codex === "codex") {
9306
9494
  const which = await run("which", ["codex"], { reject: false });
9307
9495
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
9308
- } else if (!(0, import_node_fs24.existsSync)(codex)) {
9496
+ } else if (!(0, import_node_fs25.existsSync)(codex)) {
9309
9497
  return FALLBACK_CODEX_MODELS;
9310
9498
  }
9311
9499
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -9340,12 +9528,12 @@ function usageFromCodex(usage) {
9340
9528
  }
9341
9529
  function codexConfigHasNetworkAccess() {
9342
9530
  const candidates = [
9343
- (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
9344
- (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
9531
+ (0, import_node_path26.join)((0, import_node_os10.homedir)(), ".codex", "config.toml"),
9532
+ (0, import_node_path26.join)((0, import_node_os10.homedir)(), ".config", "codex", "config.toml")
9345
9533
  ];
9346
9534
  for (const path of candidates) {
9347
- if (!(0, import_node_fs24.existsSync)(path)) continue;
9348
- const text5 = (0, import_node_fs24.readFileSync)(path, "utf8");
9535
+ if (!(0, import_node_fs25.existsSync)(path)) continue;
9536
+ const text5 = (0, import_node_fs25.readFileSync)(path, "utf8");
9349
9537
  if (/network_access\s*=\s*true/.test(text5)) return true;
9350
9538
  }
9351
9539
  return false;
@@ -9377,21 +9565,21 @@ function asRecord2(value) {
9377
9565
  return void 0;
9378
9566
  }
9379
9567
  function codexLooksAuthenticated() {
9380
- const authPath = (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
9381
- if (!(0, import_node_fs24.existsSync)(authPath)) return false;
9568
+ const authPath = (0, import_node_path26.join)((0, import_node_os10.homedir)(), ".codex", "auth.json");
9569
+ if (!(0, import_node_fs25.existsSync)(authPath)) return false;
9382
9570
  try {
9383
- return (0, import_node_fs24.statSync)(authPath).size > 2;
9571
+ return (0, import_node_fs25.statSync)(authPath).size > 2;
9384
9572
  } catch {
9385
9573
  return false;
9386
9574
  }
9387
9575
  }
9388
- var import_node_fs24, import_node_os9, import_node_path25, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
9576
+ var import_node_fs25, import_node_os10, import_node_path26, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
9389
9577
  var init_codex = __esm({
9390
9578
  "src/agents/codex.ts"() {
9391
9579
  "use strict";
9392
- import_node_fs24 = require("fs");
9393
- import_node_os9 = require("os");
9394
- import_node_path25 = require("path");
9580
+ import_node_fs25 = require("fs");
9581
+ import_node_os10 = require("os");
9582
+ import_node_path26 = require("path");
9395
9583
  init_run();
9396
9584
  init_app_settings();
9397
9585
  init_global_workspace();
@@ -9416,7 +9604,7 @@ var init_codex = __esm({
9416
9604
  async detect() {
9417
9605
  const codex = resolveAgentExecutable("codex");
9418
9606
  if (codex !== "codex") {
9419
- if (!(0, import_node_fs24.existsSync)(codex)) {
9607
+ if (!(0, import_node_fs25.existsSync)(codex)) {
9420
9608
  return {
9421
9609
  agent: "codex",
9422
9610
  installed: false,
@@ -9903,21 +10091,21 @@ function platformRipgrepPackage() {
9903
10091
  }
9904
10092
  function usableRipgrepPath(candidate) {
9905
10093
  const raw = candidate?.trim();
9906
- if (!raw || !(0, import_node_path26.isAbsolute)(raw)) return null;
10094
+ if (!raw || !(0, import_node_path27.isAbsolute)(raw)) return null;
9907
10095
  const readable = nodeReadableScriptPath(raw);
9908
- if (!(0, import_node_fs25.existsSync)(readable) || isAsarPath(readable)) return null;
10096
+ if (!(0, import_node_fs26.existsSync)(readable) || isAsarPath(readable)) return null;
9909
10097
  return readable;
9910
10098
  }
9911
10099
  function walkForBundledRipgrep(startFile) {
9912
10100
  if (!startFile) return null;
9913
10101
  const pkg = platformRipgrepPackage();
9914
10102
  const name = rgBinaryName();
9915
- let dir = (0, import_node_path26.dirname)((0, import_node_path26.resolve)(startFile));
9916
- const root = (0, import_node_path26.parse)(dir).root;
10103
+ let dir = (0, import_node_path27.dirname)((0, import_node_path27.resolve)(startFile));
10104
+ const root = (0, import_node_path27.parse)(dir).root;
9917
10105
  while (dir !== root) {
9918
- const hit = usableRipgrepPath((0, import_node_path26.join)(dir, "node_modules", pkg, "bin", name));
10106
+ const hit = usableRipgrepPath((0, import_node_path27.join)(dir, "node_modules", pkg, "bin", name));
9919
10107
  if (hit) return hit;
9920
- const next = (0, import_node_path26.dirname)(dir);
10108
+ const next = (0, import_node_path27.dirname)(dir);
9921
10109
  if (next === dir) break;
9922
10110
  dir = next;
9923
10111
  }
@@ -9927,7 +10115,7 @@ function requireResolveBundledRipgrep(fromFile) {
9927
10115
  try {
9928
10116
  const req = (0, import_node_module2.createRequire)(fromFile);
9929
10117
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
9930
- return usableRipgrepPath((0, import_node_path26.join)((0, import_node_path26.dirname)(pkgJson), "bin", rgBinaryName()));
10118
+ return usableRipgrepPath((0, import_node_path27.join)((0, import_node_path27.dirname)(pkgJson), "bin", rgBinaryName()));
9931
10119
  } catch {
9932
10120
  return null;
9933
10121
  }
@@ -9949,13 +10137,13 @@ function cursorRipgrepEnv(opts) {
9949
10137
  const path = resolveCursorRipgrepPath(opts);
9950
10138
  return path ? { [RIPGREP_ENV]: path } : {};
9951
10139
  }
9952
- var import_node_fs25, import_node_module2, import_node_path26, RIPGREP_ENV;
10140
+ var import_node_fs26, import_node_module2, import_node_path27, RIPGREP_ENV;
9953
10141
  var init_cursor_ripgrep = __esm({
9954
10142
  "src/agents/cursor-ripgrep.ts"() {
9955
10143
  "use strict";
9956
- import_node_fs25 = require("fs");
10144
+ import_node_fs26 = require("fs");
9957
10145
  import_node_module2 = require("module");
9958
- import_node_path26 = require("path");
10146
+ import_node_path27 = require("path");
9959
10147
  init_node_launch();
9960
10148
  init_packaged_runtime();
9961
10149
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -10001,11 +10189,11 @@ function entryDir() {
10001
10189
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
10002
10190
  if (cjsDir) return cjsDir;
10003
10191
  try {
10004
- return (0, import_node_path27.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
10192
+ return (0, import_node_path28.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
10005
10193
  } catch {
10006
10194
  try {
10007
10195
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
10008
- return (0, import_node_path27.dirname)(req.resolve("@sideboard-ai/core"));
10196
+ return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
10009
10197
  } catch {
10010
10198
  return process.cwd();
10011
10199
  }
@@ -10016,27 +10204,27 @@ function cursorRunnerPath() {
10016
10204
  if (packaged) return packaged;
10017
10205
  const root = entryDir();
10018
10206
  const candidates = [
10019
- (0, import_node_path27.join)(root, "agents", "cursor-runner.js"),
10020
- (0, import_node_path27.join)(root, "agents", "cursor-runner.cjs"),
10207
+ (0, import_node_path28.join)(root, "agents", "cursor-runner.js"),
10208
+ (0, import_node_path28.join)(root, "agents", "cursor-runner.cjs"),
10021
10209
  // If somehow resolved from package root instead of dist/
10022
- (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.js"),
10023
- (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.cjs"),
10210
+ (0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.js"),
10211
+ (0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.cjs"),
10024
10212
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
10025
- (0, import_node_path27.join)(root, "cursor-runner.ts"),
10026
- (0, import_node_path27.join)(root, "src", "agents", "cursor-runner.ts")
10213
+ (0, import_node_path28.join)(root, "cursor-runner.ts"),
10214
+ (0, import_node_path28.join)(root, "src", "agents", "cursor-runner.ts")
10027
10215
  ];
10028
10216
  for (const candidate of candidates) {
10029
- if ((0, import_node_fs26.existsSync)(candidate)) return candidate;
10217
+ if ((0, import_node_fs27.existsSync)(candidate)) return candidate;
10030
10218
  }
10031
10219
  return candidates[0];
10032
10220
  }
10033
- 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;
10221
+ 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;
10034
10222
  var init_cursor = __esm({
10035
10223
  "src/agents/cursor.ts"() {
10036
10224
  "use strict";
10037
- import_node_fs26 = require("fs");
10225
+ import_node_fs27 = require("fs");
10038
10226
  import_node_module3 = require("module");
10039
- import_node_path27 = require("path");
10227
+ import_node_path28 = require("path");
10040
10228
  import_node_url2 = require("url");
10041
10229
  import_sdk = require("@cursor/sdk");
10042
10230
  init_run();
@@ -10187,7 +10375,7 @@ async function listOpencodeModels() {
10187
10375
  if (opencode === "opencode") {
10188
10376
  const which = await run("which", ["opencode"], { reject: false });
10189
10377
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
10190
- } else if (!(0, import_node_fs27.existsSync)(opencode)) {
10378
+ } else if (!(0, import_node_fs28.existsSync)(opencode)) {
10191
10379
  return FALLBACK_OPENCODE_MODELS;
10192
10380
  }
10193
10381
  const listed = await run(opencode, ["models"], { reject: false });
@@ -10217,11 +10405,11 @@ function usageFromOpencode(tokens) {
10217
10405
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
10218
10406
  };
10219
10407
  }
10220
- var import_node_fs27, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
10408
+ var import_node_fs28, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
10221
10409
  var init_opencode = __esm({
10222
10410
  "src/agents/opencode.ts"() {
10223
10411
  "use strict";
10224
- import_node_fs27 = require("fs");
10412
+ import_node_fs28 = require("fs");
10225
10413
  init_run();
10226
10414
  init_app_settings();
10227
10415
  init_global_workspace();
@@ -10248,7 +10436,7 @@ var init_opencode = __esm({
10248
10436
  async detect() {
10249
10437
  const opencode = resolveAgentExecutable("opencode");
10250
10438
  if (opencode !== "opencode") {
10251
- if (!(0, import_node_fs27.existsSync)(opencode)) {
10439
+ if (!(0, import_node_fs28.existsSync)(opencode)) {
10252
10440
  return {
10253
10441
  agent: "opencode",
10254
10442
  installed: false,
@@ -11849,7 +12037,7 @@ function forkMessageSlice(from, throughIndex) {
11849
12037
  function buildForkTranscriptAttachment(baseTitle, messages) {
11850
12038
  const title = baseTitle || "Chat";
11851
12039
  return {
11852
- id: (0, import_node_crypto5.randomUUID)(),
12040
+ id: (0, import_node_crypto6.randomUUID)(),
11853
12041
  name: `Transcript of ${title}.md`,
11854
12042
  kind: "transcript",
11855
12043
  content: formatTranscriptMarkdown(title, messages)
@@ -11906,11 +12094,11 @@ function forkChatTab(input) {
11906
12094
  }
11907
12095
  return tab;
11908
12096
  }
11909
- var import_node_crypto5;
12097
+ var import_node_crypto6;
11910
12098
  var init_chat_tabs = __esm({
11911
12099
  "src/threads/chat-tabs.ts"() {
11912
12100
  "use strict";
11913
- import_node_crypto5 = require("crypto");
12101
+ import_node_crypto6 = require("crypto");
11914
12102
  init_context_compact();
11915
12103
  init_teams();
11916
12104
  init_worktree_labels();
@@ -12080,21 +12268,21 @@ function shouldRefreshReviewRequestTemplate(content) {
12080
12268
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
12081
12269
  }
12082
12270
  function readTextIfPresent(abs) {
12083
- if (!(0, import_node_fs28.existsSync)(abs)) return null;
12271
+ if (!(0, import_node_fs29.existsSync)(abs)) return null;
12084
12272
  try {
12085
- const content = (0, import_node_fs28.readFileSync)(abs, "utf8");
12273
+ const content = (0, import_node_fs29.readFileSync)(abs, "utf8");
12086
12274
  return content.trim() ? content : null;
12087
12275
  } catch {
12088
12276
  return null;
12089
12277
  }
12090
12278
  }
12091
12279
  function readLocalGuidelines(worktreePath) {
12092
- const localAbs = (0, import_node_path28.join)(worktreePath, REVIEW_REQUEST_PATH);
12280
+ const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
12093
12281
  const localContent = readTextIfPresent(localAbs);
12094
12282
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
12095
12283
  return { path: REVIEW_REQUEST_PATH, content: localContent };
12096
12284
  }
12097
- const legacyAbs = (0, import_node_path28.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
12285
+ const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
12098
12286
  const legacyContent = readTextIfPresent(legacyAbs);
12099
12287
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
12100
12288
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -12110,20 +12298,20 @@ function skillGuidelines(content, source) {
12110
12298
  };
12111
12299
  }
12112
12300
  function ensureReviewSkillFile(worktreePath) {
12113
- const abs = (0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH);
12301
+ const abs = (0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH);
12114
12302
  const existing = readTextIfPresent(abs);
12115
12303
  if (existing) {
12116
12304
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
12117
12305
  }
12118
- const fromRepo = readTextIfPresent((0, import_node_path28.join)(worktreePath, REPO_REVIEW_PATH));
12306
+ const fromRepo = readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH));
12119
12307
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
12120
12308
  const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
12121
- (0, import_node_fs28.mkdirSync)((0, import_node_path28.dirname)(abs), { recursive: true });
12122
- (0, import_node_fs28.writeFileSync)(abs, content, "utf8");
12309
+ (0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(abs), { recursive: true });
12310
+ (0, import_node_fs29.writeFileSync)(abs, content, "utf8");
12123
12311
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
12124
12312
  }
12125
12313
  function resolveReviewGuidelines(worktreePath) {
12126
- const skillContent = readTextIfPresent((0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH));
12314
+ const skillContent = readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH));
12127
12315
  if (skillContent) return skillGuidelines(skillContent, "skill");
12128
12316
  const local = readLocalGuidelines(worktreePath);
12129
12317
  if (local) {
@@ -12141,7 +12329,7 @@ function buildReviewRequestAttachment(content, opts) {
12141
12329
  const path = opts?.path ?? REVIEW_SKILL_PATH;
12142
12330
  const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
12143
12331
  return {
12144
- id: (0, import_node_crypto6.randomUUID)(),
12332
+ id: (0, import_node_crypto7.randomUUID)(),
12145
12333
  name,
12146
12334
  kind: "file",
12147
12335
  path,
@@ -12173,13 +12361,13 @@ async function requestReview(threadRef, send) {
12173
12361
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
12174
12362
  return { tab: started, from };
12175
12363
  }
12176
- 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;
12364
+ var import_node_crypto7, import_node_fs29, import_node_path29, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
12177
12365
  var init_request_review = __esm({
12178
12366
  "src/review/request-review.ts"() {
12179
12367
  "use strict";
12180
- import_node_crypto6 = require("crypto");
12181
- import_node_fs28 = require("fs");
12182
- import_node_path28 = require("path");
12368
+ import_node_crypto7 = require("crypto");
12369
+ import_node_fs29 = require("fs");
12370
+ import_node_path29 = require("path");
12183
12371
  init_global_workspace();
12184
12372
  init_chat_tabs();
12185
12373
  init_thread_store();
@@ -12204,9 +12392,9 @@ function matchSimpleGlob(pattern, name) {
12204
12392
  return new RegExp(`^${escaped}$`).test(name);
12205
12393
  }
12206
12394
  function readWorktreeInclude(repoPath) {
12207
- const path = (0, import_node_path29.join)(repoPath, ".worktreeinclude");
12208
- if (!(0, import_node_fs29.existsSync)(path)) return [];
12209
- return (0, import_node_fs29.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
12395
+ const path = (0, import_node_path30.join)(repoPath, ".worktreeinclude");
12396
+ if (!(0, import_node_fs30.existsSync)(path)) return [];
12397
+ return (0, import_node_fs30.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
12210
12398
  }
12211
12399
  function resolveFilesToCopy(repoPath) {
12212
12400
  const fromInclude = readWorktreeInclude(repoPath);
@@ -12216,10 +12404,10 @@ function resolveFilesToCopy(repoPath) {
12216
12404
  if (settings?.fileIncludeGlobs?.length) {
12217
12405
  const matched = [];
12218
12406
  try {
12219
- for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
12407
+ for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
12220
12408
  if (!entry.isFile()) continue;
12221
12409
  for (const glob of settings.fileIncludeGlobs) {
12222
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path29.basename)(glob), entry.name)) {
12410
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path30.basename)(glob), entry.name)) {
12223
12411
  matched.push(entry.name);
12224
12412
  break;
12225
12413
  }
@@ -12231,7 +12419,7 @@ function resolveFilesToCopy(repoPath) {
12231
12419
  }
12232
12420
  const defaults = [];
12233
12421
  try {
12234
- for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
12422
+ for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
12235
12423
  if (entry.isFile() && entry.name.startsWith(".env")) {
12236
12424
  defaults.push(entry.name);
12237
12425
  }
@@ -12245,11 +12433,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
12245
12433
  const patterns = resolveFilesToCopy(repoPath);
12246
12434
  const copied = [];
12247
12435
  for (const rel of patterns) {
12248
- const src = (0, import_node_path29.join)(repoPath, rel);
12249
- if (!(0, import_node_fs29.existsSync)(src)) continue;
12250
- const dest = (0, import_node_path29.join)(worktreePath, rel);
12251
- (0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(dest), { recursive: true });
12252
- (0, import_node_fs29.copyFileSync)(src, dest);
12436
+ const src = (0, import_node_path30.join)(repoPath, rel);
12437
+ if (!(0, import_node_fs30.existsSync)(src)) continue;
12438
+ const dest = (0, import_node_path30.join)(worktreePath, rel);
12439
+ (0, import_node_fs30.mkdirSync)((0, import_node_path30.dirname)(dest), { recursive: true });
12440
+ (0, import_node_fs30.copyFileSync)(src, dest);
12253
12441
  copied.push(rel);
12254
12442
  }
12255
12443
  return copied;
@@ -12284,7 +12472,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
12284
12472
  const env = stripNestedElectronEnv({
12285
12473
  ...baseEnv ?? process.env
12286
12474
  });
12287
- const name = opts.workspaceName ?? (0, import_node_path29.basename)(opts.worktreePath);
12475
+ const name = opts.workspaceName ?? (0, import_node_path30.basename)(opts.worktreePath);
12288
12476
  const ports = opts.ports ?? [];
12289
12477
  const primary = ports[0];
12290
12478
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -12439,6 +12627,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
12439
12627
  };
12440
12628
  }
12441
12629
  async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
12630
+ await ensureWorktreeSideboardIgnored(worktreePath);
12442
12631
  const reviewSkill = ensureReviewSkillFile(worktreePath);
12443
12632
  if (reviewSkill.wrote) {
12444
12633
  onLine?.(
@@ -12545,13 +12734,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
12545
12734
  done: handle.done
12546
12735
  };
12547
12736
  }
12548
- var import_node_fs29, import_node_net, import_node_path29, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
12737
+ var import_node_fs30, import_node_net, import_node_path30, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
12549
12738
  var init_conductor = __esm({
12550
12739
  "src/hook/conductor.ts"() {
12551
12740
  "use strict";
12552
- import_node_fs29 = require("fs");
12741
+ import_node_fs30 = require("fs");
12553
12742
  import_node_net = require("net");
12554
- import_node_path29 = require("path");
12743
+ import_node_path30 = require("path");
12555
12744
  import_execa4 = require("execa");
12556
12745
  import_node_readline3 = require("readline");
12557
12746
  init_settings();
@@ -12560,6 +12749,7 @@ var init_conductor = __esm({
12560
12749
  init_cursor_worktrees();
12561
12750
  init_git_auth_mode();
12562
12751
  init_request_review();
12752
+ init_worktree_exclude();
12563
12753
  init_nested_electron_env();
12564
12754
  PORT_RANGE_SIZE = 10;
12565
12755
  cachedLoginEnv = null;
@@ -12577,9 +12767,9 @@ async function findOrphanWorktrees(repoPaths) {
12577
12767
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
12578
12768
  );
12579
12769
  const homeRoot = sideboardWorkspacesDir();
12580
- if ((0, import_node_fs30.existsSync)(homeRoot)) {
12770
+ if ((0, import_node_fs31.existsSync)(homeRoot)) {
12581
12771
  try {
12582
- for (const entry of (0, import_node_fs30.readdirSync)(homeRoot, { withFileTypes: true })) {
12772
+ for (const entry of (0, import_node_fs31.readdirSync)(homeRoot, { withFileTypes: true })) {
12583
12773
  if (!entry.isDirectory()) continue;
12584
12774
  void entry;
12585
12775
  }
@@ -12589,7 +12779,7 @@ async function findOrphanWorktrees(repoPaths) {
12589
12779
  const orphans = [];
12590
12780
  const seen = /* @__PURE__ */ new Set();
12591
12781
  for (const repoPath of repos) {
12592
- if (!repoPath || !(0, import_node_fs30.existsSync)(repoPath)) continue;
12782
+ if (!repoPath || !(0, import_node_fs31.existsSync)(repoPath)) continue;
12593
12783
  try {
12594
12784
  const wts = await listWorktrees(repoPath);
12595
12785
  for (const wt of wts) {
@@ -12600,7 +12790,7 @@ async function findOrphanWorktrees(repoPaths) {
12600
12790
  seen.add(path);
12601
12791
  let mtimeMs = 0;
12602
12792
  try {
12603
- mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
12793
+ mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
12604
12794
  } catch {
12605
12795
  mtimeMs = 0;
12606
12796
  }
@@ -12610,16 +12800,16 @@ async function findOrphanWorktrees(repoPaths) {
12610
12800
  }
12611
12801
  try {
12612
12802
  const root = worktreesRoot(repoPath);
12613
- if ((0, import_node_fs30.existsSync)(root)) {
12614
- for (const entry of (0, import_node_fs30.readdirSync)(root, { withFileTypes: true })) {
12803
+ if ((0, import_node_fs31.existsSync)(root)) {
12804
+ for (const entry of (0, import_node_fs31.readdirSync)(root, { withFileTypes: true })) {
12615
12805
  if (!entry.isDirectory()) continue;
12616
- const path = (0, import_node_path30.join)(root, entry.name).replace(/\/$/, "");
12806
+ const path = (0, import_node_path31.join)(root, entry.name).replace(/\/$/, "");
12617
12807
  if (known.has(path) || seen.has(path)) continue;
12618
- if (!(0, import_node_fs30.existsSync)((0, import_node_path30.join)(path, ".git"))) continue;
12808
+ if (!(0, import_node_fs31.existsSync)((0, import_node_path31.join)(path, ".git"))) continue;
12619
12809
  seen.add(path);
12620
12810
  let mtimeMs = 0;
12621
12811
  try {
12622
- mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
12812
+ mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
12623
12813
  } catch {
12624
12814
  mtimeMs = Date.now();
12625
12815
  }
@@ -12671,12 +12861,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
12671
12861
  const elapsed = Date.now() - Date.parse(last);
12672
12862
  return elapsed >= intervalHours * 36e5;
12673
12863
  }
12674
- var import_node_fs30, import_node_path30;
12864
+ var import_node_fs31, import_node_path31;
12675
12865
  var init_orphan_cleanup = __esm({
12676
12866
  "src/git/orphan-cleanup.ts"() {
12677
12867
  "use strict";
12678
- import_node_fs30 = require("fs");
12679
- import_node_path30 = require("path");
12868
+ import_node_fs31 = require("fs");
12869
+ import_node_path31 = require("path");
12680
12870
  init_worktree();
12681
12871
  init_thread_store();
12682
12872
  init_paths();
@@ -12783,38 +12973,38 @@ __export(workspaces_exports, {
12783
12973
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
12784
12974
  });
12785
12975
  function workspacesFile() {
12786
- return (0, import_node_path31.join)(appDataDir(), "workspaces.json");
12976
+ return (0, import_node_path32.join)(appDataDir(), "workspaces.json");
12787
12977
  }
12788
12978
  function removedWorkspacesFile() {
12789
- return (0, import_node_path31.join)(appDataDir(), "removed-workspaces.json");
12979
+ return (0, import_node_path32.join)(appDataDir(), "removed-workspaces.json");
12790
12980
  }
12791
12981
  function readAll() {
12792
12982
  const path = workspacesFile();
12793
- if (!(0, import_node_fs31.existsSync)(path)) return [];
12983
+ if (!(0, import_node_fs32.existsSync)(path)) return [];
12794
12984
  try {
12795
- const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12985
+ const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
12796
12986
  return Array.isArray(raw) ? raw : [];
12797
12987
  } catch {
12798
12988
  return [];
12799
12989
  }
12800
12990
  }
12801
12991
  function writeAll(list) {
12802
- (0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
12803
- (0, import_node_fs31.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12992
+ (0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
12993
+ (0, import_node_fs32.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12804
12994
  }
12805
12995
  function readRemoved() {
12806
12996
  const path = removedWorkspacesFile();
12807
- if (!(0, import_node_fs31.existsSync)(path)) return /* @__PURE__ */ new Set();
12997
+ if (!(0, import_node_fs32.existsSync)(path)) return /* @__PURE__ */ new Set();
12808
12998
  try {
12809
- const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12999
+ const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
12810
13000
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
12811
13001
  } catch {
12812
13002
  return /* @__PURE__ */ new Set();
12813
13003
  }
12814
13004
  }
12815
13005
  function writeRemoved(paths) {
12816
- (0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
12817
- (0, import_node_fs31.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
13006
+ (0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
13007
+ (0, import_node_fs32.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
12818
13008
  }
12819
13009
  function rememberRemoved(repoPath) {
12820
13010
  const next = readRemoved();
@@ -12837,7 +13027,7 @@ function listWorkspaces() {
12837
13027
  async function addWorkspace(repoPath) {
12838
13028
  const root = await resolveRepoRoot(repoPath);
12839
13029
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
12840
- if (!(0, import_node_fs31.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
13030
+ if (!(0, import_node_fs32.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
12841
13031
  forgetRemoved(root);
12842
13032
  await ensureGhPreferOrigin(root);
12843
13033
  const current = readAll();
@@ -12845,7 +13035,7 @@ async function addWorkspace(repoPath) {
12845
13035
  if (existing) return existing;
12846
13036
  const next = {
12847
13037
  path: root,
12848
- name: (0, import_node_path31.basename)(root),
13038
+ name: (0, import_node_path32.basename)(root),
12849
13039
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12850
13040
  };
12851
13041
  writeAll([...current, next]);
@@ -12867,10 +13057,10 @@ function syncWorkspacesFromThreads(repoPaths) {
12867
13057
  if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
12868
13058
  continue;
12869
13059
  }
12870
- if (!(0, import_node_fs31.existsSync)(path)) continue;
13060
+ if (!(0, import_node_fs32.existsSync)(path)) continue;
12871
13061
  const ws = {
12872
13062
  path,
12873
- name: (0, import_node_path31.basename)(path),
13063
+ name: (0, import_node_path32.basename)(path),
12874
13064
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12875
13065
  };
12876
13066
  byPath.set(path, ws);
@@ -12880,12 +13070,12 @@ function syncWorkspacesFromThreads(repoPaths) {
12880
13070
  if (dirty) writeAll(next);
12881
13071
  return next.sort((a, b) => a.name.localeCompare(b.name));
12882
13072
  }
12883
- var import_node_fs31, import_node_path31;
13073
+ var import_node_fs32, import_node_path32;
12884
13074
  var init_workspaces2 = __esm({
12885
13075
  "src/store/workspaces.ts"() {
12886
13076
  "use strict";
12887
- import_node_fs31 = require("fs");
12888
- import_node_path31 = require("path");
13077
+ import_node_fs32 = require("fs");
13078
+ import_node_path32 = require("path");
12889
13079
  init_paths();
12890
13080
  init_global_workspace();
12891
13081
  init_worktree();
@@ -12898,12 +13088,12 @@ async function cloneRepoIntoSideboard(opts) {
12898
13088
  if (!url) throw new Error("Clone URL is required");
12899
13089
  let name = opts.name?.trim();
12900
13090
  if (!name) {
12901
- const leaf = (0, import_node_path32.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
13091
+ const leaf = (0, import_node_path33.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12902
13092
  name = leaf || "repo";
12903
13093
  }
12904
13094
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
12905
- const dest = (0, import_node_path32.join)(sideboardReposDir(), name);
12906
- if ((0, import_node_fs32.existsSync)(dest)) {
13095
+ const dest = (0, import_node_path33.join)(sideboardReposDir(), name);
13096
+ if ((0, import_node_fs33.existsSync)(dest)) {
12907
13097
  const repoPath2 = await resolveRepoRoot(dest);
12908
13098
  const workspace2 = await ensureWorkspace(repoPath2);
12909
13099
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -12918,12 +13108,12 @@ async function cloneRepoIntoSideboard(opts) {
12918
13108
  const workspace = await ensureWorkspace(repoPath);
12919
13109
  return { repoPath, workspace };
12920
13110
  }
12921
- var import_node_fs32, import_node_path32, import_execa6;
13111
+ var import_node_fs33, import_node_path33, import_execa6;
12922
13112
  var init_clone_repo = __esm({
12923
13113
  "src/git/clone-repo.ts"() {
12924
13114
  "use strict";
12925
- import_node_fs32 = require("fs");
12926
- import_node_path32 = require("path");
13115
+ import_node_fs33 = require("fs");
13116
+ import_node_path33 = require("path");
12927
13117
  import_execa6 = require("execa");
12928
13118
  init_paths();
12929
13119
  init_workspaces2();
@@ -12933,11 +13123,11 @@ var init_clone_repo = __esm({
12933
13123
 
12934
13124
  // src/store/desktop-host.ts
12935
13125
  function desktopHostPidPath() {
12936
- return (0, import_node_path33.join)(appDataDir(), "desktop-host.pid");
13126
+ return (0, import_node_path34.join)(appDataDir(), "desktop-host.pid");
12937
13127
  }
12938
13128
  function readDesktopHostPid() {
12939
13129
  try {
12940
- const pid = Number.parseInt((0, import_node_fs33.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
13130
+ const pid = Number.parseInt((0, import_node_fs34.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
12941
13131
  if (!Number.isFinite(pid) || pid <= 0) return null;
12942
13132
  return pid;
12943
13133
  } catch {
@@ -12963,12 +13153,12 @@ function thisProcessShouldDrainAgentQueues() {
12963
13153
  if (isThisProcessDesktopHost()) return true;
12964
13154
  return !isDesktopHostAlive();
12965
13155
  }
12966
- var import_node_fs33, import_node_path33;
13156
+ var import_node_fs34, import_node_path34;
12967
13157
  var init_desktop_host = __esm({
12968
13158
  "src/store/desktop-host.ts"() {
12969
13159
  "use strict";
12970
- import_node_fs33 = require("fs");
12971
- import_node_path33 = require("path");
13160
+ import_node_fs34 = require("fs");
13161
+ import_node_path34 = require("path");
12972
13162
  init_paths();
12973
13163
  }
12974
13164
  });
@@ -13970,7 +14160,7 @@ function persistCreateAttachments(worktreePath, attachments) {
13970
14160
  }
13971
14161
  async function createThread(input, _onSetupLine) {
13972
14162
  const repoPath = await resolveRepoRoot(input.repoPath);
13973
- if (!(0, import_node_fs34.existsSync)(repoPath)) {
14163
+ if (!(0, import_node_fs35.existsSync)(repoPath)) {
13974
14164
  throw new Error(`Repo not found: ${repoPath}`);
13975
14165
  }
13976
14166
  if (input.reuseExisting !== false) {
@@ -14145,11 +14335,11 @@ async function listLinearIssues(agent, repoPath) {
14145
14335
  }
14146
14336
  return adapter.listLinearIssues(repoPath);
14147
14337
  }
14148
- var import_node_fs34;
14338
+ var import_node_fs35;
14149
14339
  var init_create = __esm({
14150
14340
  "src/threads/create.ts"() {
14151
14341
  "use strict";
14152
- import_node_fs34 = require("fs");
14342
+ import_node_fs35 = require("fs");
14153
14343
  init_detect();
14154
14344
  init_worktree();
14155
14345
  init_home_board();
@@ -14252,20 +14442,20 @@ function writeTurnLive(threadId, progress) {
14252
14442
  const path = threadLivePath(threadId);
14253
14443
  const tmp = `${path}.${process.pid}.tmp`;
14254
14444
  try {
14255
- (0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
14256
- (0, import_node_fs35.renameSync)(tmp, path);
14445
+ (0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
14446
+ (0, import_node_fs36.renameSync)(tmp, path);
14257
14447
  } catch {
14258
14448
  try {
14259
- (0, import_node_fs35.unlinkSync)(tmp);
14449
+ (0, import_node_fs36.unlinkSync)(tmp);
14260
14450
  } catch {
14261
14451
  }
14262
14452
  }
14263
14453
  }
14264
14454
  function readTurnLive(threadId) {
14265
14455
  const path = threadLivePath(threadId);
14266
- if (!(0, import_node_fs35.existsSync)(path)) return null;
14456
+ if (!(0, import_node_fs36.existsSync)(path)) return null;
14267
14457
  try {
14268
- const raw = JSON.parse((0, import_node_fs35.readFileSync)(path, "utf8"));
14458
+ const raw = JSON.parse((0, import_node_fs36.readFileSync)(path, "utf8"));
14269
14459
  if (!raw || typeof raw.summary !== "string") return null;
14270
14460
  return raw;
14271
14461
  } catch {
@@ -14277,17 +14467,17 @@ function clearTurnLive(threadId) {
14277
14467
  if (buf?.timer) clearTimeout(buf.timer);
14278
14468
  buffers.delete(threadId);
14279
14469
  const path = threadLivePath(threadId);
14280
- if (!(0, import_node_fs35.existsSync)(path)) return;
14470
+ if (!(0, import_node_fs36.existsSync)(path)) return;
14281
14471
  try {
14282
- (0, import_node_fs35.unlinkSync)(path);
14472
+ (0, import_node_fs36.unlinkSync)(path);
14283
14473
  } catch {
14284
14474
  }
14285
14475
  }
14286
- var import_node_fs35, buffers, FLUSH_MS, MAX_PARTS;
14476
+ var import_node_fs36, buffers, FLUSH_MS, MAX_PARTS;
14287
14477
  var init_turn_live = __esm({
14288
14478
  "src/store/turn-live.ts"() {
14289
14479
  "use strict";
14290
- import_node_fs35 = require("fs");
14480
+ import_node_fs36 = require("fs");
14291
14481
  init_message_parts();
14292
14482
  init_paths();
14293
14483
  buffers = /* @__PURE__ */ new Map();
@@ -14461,7 +14651,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
14461
14651
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
14462
14652
  ].join("\n");
14463
14653
  return {
14464
- id: (0, import_node_crypto7.randomUUID)(),
14654
+ id: (0, import_node_crypto8.randomUUID)(),
14465
14655
  name: "Orchestration quota handoff.md",
14466
14656
  kind: "transcript",
14467
14657
  content: body
@@ -14482,11 +14672,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
14482
14672
  sourceType: "orchestration"
14483
14673
  });
14484
14674
  }
14485
- var import_node_crypto7, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
14675
+ var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
14486
14676
  var init_quota_failover = __esm({
14487
14677
  "src/orchestrator/quota-failover.ts"() {
14488
14678
  "use strict";
14489
- import_node_crypto7 = require("crypto");
14679
+ import_node_crypto8 = require("crypto");
14490
14680
  init_session_quota();
14491
14681
  init_app_settings();
14492
14682
  init_global_workspace();
@@ -14503,7 +14693,7 @@ var init_quota_failover = __esm({
14503
14693
  // src/threads/adopt.ts
14504
14694
  function thisModuleFile() {
14505
14695
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
14506
- return cjsFile || process.argv[1] || (0, import_node_path34.join)(process.cwd(), "package.json");
14696
+ return cjsFile || process.argv[1] || (0, import_node_path35.join)(process.cwd(), "package.json");
14507
14697
  }
14508
14698
  function openReadonlySqlite(file) {
14509
14699
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -14521,21 +14711,21 @@ function mapAgentType(raw) {
14521
14711
  return null;
14522
14712
  }
14523
14713
  function resolveConductorCursorAgentId(workspacePath) {
14524
- if (!workspacePath || !(0, import_node_fs36.existsSync)(CURSOR_SDK_STORE)) return null;
14714
+ if (!workspacePath || !(0, import_node_fs37.existsSync)(CURSOR_SDK_STORE)) return null;
14525
14715
  const normalized = workspacePath.replace(/\/$/, "");
14526
14716
  let best = null;
14527
14717
  let hashes;
14528
14718
  try {
14529
- hashes = (0, import_node_fs36.readdirSync)(CURSOR_SDK_STORE);
14719
+ hashes = (0, import_node_fs37.readdirSync)(CURSOR_SDK_STORE);
14530
14720
  } catch {
14531
14721
  return null;
14532
14722
  }
14533
14723
  for (const hash of hashes) {
14534
- const agentsFile = (0, import_node_path34.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
14535
- if (!(0, import_node_fs36.existsSync)(agentsFile)) continue;
14724
+ const agentsFile = (0, import_node_path35.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
14725
+ if (!(0, import_node_fs37.existsSync)(agentsFile)) continue;
14536
14726
  let text5;
14537
14727
  try {
14538
- text5 = (0, import_node_fs36.readFileSync)(agentsFile, "utf8");
14728
+ text5 = (0, import_node_fs37.readFileSync)(agentsFile, "utf8");
14539
14729
  } catch {
14540
14730
  continue;
14541
14731
  }
@@ -14559,7 +14749,7 @@ function resolveConductorCursorAgentId(workspacePath) {
14559
14749
  return best?.agentId ?? null;
14560
14750
  }
14561
14751
  async function adoptThread(input) {
14562
- if (!(0, import_node_fs36.existsSync)(input.worktreePath)) {
14752
+ if (!(0, import_node_fs37.existsSync)(input.worktreePath)) {
14563
14753
  throw new Error(`Worktree not found: ${input.worktreePath}`);
14564
14754
  }
14565
14755
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -14580,21 +14770,23 @@ async function adoptThread(input) {
14580
14770
  writeThread(thread);
14581
14771
  const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
14582
14772
  await ensureWorkspace2(repoPath);
14773
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
14774
+ await ensureWorktreeSideboardIgnored2(input.worktreePath);
14583
14775
  return thread;
14584
14776
  }
14585
14777
  function listConductorWorkspaces() {
14586
- if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
14778
+ if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
14587
14779
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
14588
14780
  }
14589
- const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
14590
- const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
14781
+ const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
14782
+ const snapshot = (0, import_node_path35.join)(tmp, "conductor.db");
14591
14783
  try {
14592
- (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
14784
+ (0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
14593
14785
  for (const suffix of ["-wal", "-shm"]) {
14594
14786
  const src = `${CONDUCTOR_DB}${suffix}`;
14595
- if ((0, import_node_fs36.existsSync)(src)) {
14787
+ if ((0, import_node_fs37.existsSync)(src)) {
14596
14788
  try {
14597
- (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
14789
+ (0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
14598
14790
  } catch {
14599
14791
  }
14600
14792
  }
@@ -14670,22 +14862,22 @@ function listConductorWorkspaces() {
14670
14862
  db.close();
14671
14863
  }
14672
14864
  } finally {
14673
- (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
14865
+ (0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
14674
14866
  }
14675
14867
  }
14676
14868
  function importConductorWorkspace(workspaceId) {
14677
- if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
14869
+ if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
14678
14870
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
14679
14871
  }
14680
- const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
14681
- const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
14872
+ const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
14873
+ const snapshot = (0, import_node_path35.join)(tmp, "conductor.db");
14682
14874
  try {
14683
- (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
14875
+ (0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
14684
14876
  for (const suffix of ["-wal", "-shm"]) {
14685
14877
  const src = `${CONDUCTOR_DB}${suffix}`;
14686
- if ((0, import_node_fs36.existsSync)(src)) {
14878
+ if ((0, import_node_fs37.existsSync)(src)) {
14687
14879
  try {
14688
- (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
14880
+ (0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
14689
14881
  } catch {
14690
14882
  }
14691
14883
  }
@@ -14703,7 +14895,7 @@ function importConductorWorkspace(workspaceId) {
14703
14895
  ).get(workspaceId);
14704
14896
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
14705
14897
  const worktreePath = String(row.workspacePath);
14706
- if (!(0, import_node_fs36.existsSync)(worktreePath)) {
14898
+ if (!(0, import_node_fs37.existsSync)(worktreePath)) {
14707
14899
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
14708
14900
  }
14709
14901
  let sessionId = null;
@@ -14766,31 +14958,31 @@ function importConductorWorkspace(workspaceId) {
14766
14958
  db.close();
14767
14959
  }
14768
14960
  } finally {
14769
- (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
14961
+ (0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
14770
14962
  }
14771
14963
  }
14772
14964
  async function importConductorWorkspaceAsync(workspaceId) {
14773
14965
  return importConductorWorkspace(workspaceId);
14774
14966
  }
14775
- 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;
14967
+ 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;
14776
14968
  var init_adopt = __esm({
14777
14969
  "src/threads/adopt.ts"() {
14778
14970
  "use strict";
14779
14971
  import_node_child_process3 = require("child_process");
14780
- import_node_fs36 = require("fs");
14781
- import_node_os10 = require("os");
14782
- import_node_path34 = require("path");
14972
+ import_node_fs37 = require("fs");
14973
+ import_node_os11 = require("os");
14974
+ import_node_path35 = require("path");
14783
14975
  import_node_module4 = require("module");
14784
14976
  init_worktree();
14785
14977
  init_thread_store();
14786
- CONDUCTOR_APP_SUPPORT = (0, import_node_path34.join)(
14978
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path35.join)(
14787
14979
  process.env.HOME ?? "",
14788
14980
  "Library",
14789
14981
  "Application Support",
14790
14982
  "com.conductor.app"
14791
14983
  );
14792
- CONDUCTOR_DB = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
14793
- CURSOR_SDK_STORE = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
14984
+ CONDUCTOR_DB = (0, import_node_path35.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
14985
+ CURSOR_SDK_STORE = (0, import_node_path35.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
14794
14986
  }
14795
14987
  });
14796
14988
 
@@ -14857,7 +15049,7 @@ async function openStackLayer(input, _onSetupLine) {
14857
15049
  let createdWorktree = false;
14858
15050
  const trees = await listWorktrees(repoPath);
14859
15051
  const checkedOut = trees.find((w) => w.branch === branchName);
14860
- if (checkedOut?.path && (0, import_node_fs37.existsSync)(checkedOut.path)) {
15052
+ if (checkedOut?.path && (0, import_node_fs38.existsSync)(checkedOut.path)) {
14861
15053
  if (input.reuseExistingWorktree !== false) {
14862
15054
  worktreePath = checkedOut.path;
14863
15055
  } else {
@@ -14999,7 +15191,7 @@ async function initStackFromThread(input, onSetupLine) {
14999
15191
  async function createPrStack(input, onSetupLine) {
15000
15192
  await requireAgent(input.agent);
15001
15193
  const repoPath = await resolveRepoRoot(input.repoPath);
15002
- if (!(0, import_node_fs37.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
15194
+ if (!(0, import_node_fs38.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
15003
15195
  if (!input.branches.length) throw new Error("At least one branch name required");
15004
15196
  const status = await detectGhStack(repoPath);
15005
15197
  if (!status.available) throw new Error(status.reason);
@@ -15066,7 +15258,7 @@ async function createPrStack(input, onSetupLine) {
15066
15258
  }
15067
15259
  }
15068
15260
  const claimed = new Set(threads.map((t) => t.worktreePath));
15069
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs37.existsSync)(bootstrap.worktreePath)) {
15261
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs38.existsSync)(bootstrap.worktreePath)) {
15070
15262
  try {
15071
15263
  await removeWorktree(repoPath, bootstrap.worktreePath, {
15072
15264
  deleteBranch: bootstrap.branchName
@@ -15076,11 +15268,11 @@ async function createPrStack(input, onSetupLine) {
15076
15268
  }
15077
15269
  return { stack, threads, createdThreadIds };
15078
15270
  }
15079
- var import_node_fs37;
15271
+ var import_node_fs38;
15080
15272
  var init_stack_layers = __esm({
15081
15273
  "src/threads/stack-layers.ts"() {
15082
15274
  "use strict";
15083
- import_node_fs37 = require("fs");
15275
+ import_node_fs38 = require("fs");
15084
15276
  init_detect();
15085
15277
  init_run();
15086
15278
  init_stack();
@@ -15093,7 +15285,7 @@ var init_stack_layers = __esm({
15093
15285
 
15094
15286
  // src/diff/diff.ts
15095
15287
  async function inspectGitWorktree(worktreePath) {
15096
- if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) return "missing_worktree";
15288
+ if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) return "missing_worktree";
15097
15289
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
15098
15290
  reject: false
15099
15291
  });
@@ -15101,7 +15293,7 @@ async function inspectGitWorktree(worktreePath) {
15101
15293
  return "ok";
15102
15294
  }
15103
15295
  async function initializeGitRepository(worktreePath) {
15104
- if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) {
15296
+ if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) {
15105
15297
  throw new Error("Worktree not found");
15106
15298
  }
15107
15299
  const status = await inspectGitWorktree(worktreePath);
@@ -15235,11 +15427,11 @@ new file mode 100644
15235
15427
  };
15236
15428
  }
15237
15429
  async function untrackedPatch(worktreePath, path, maxHunk) {
15238
- const abs = (0, import_node_path35.join)(worktreePath, path);
15430
+ const abs = (0, import_node_path36.join)(worktreePath, path);
15239
15431
  try {
15240
- const st = (0, import_node_fs38.statSync)(abs);
15432
+ const st = (0, import_node_fs39.statSync)(abs);
15241
15433
  if (st.isFile() && st.size > maxHunk) {
15242
- const buf = (0, import_node_fs38.readFileSync)(abs).subarray(0, maxHunk);
15434
+ const buf = (0, import_node_fs39.readFileSync)(abs).subarray(0, maxHunk);
15243
15435
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
15244
15436
  }
15245
15437
  } catch {
@@ -15728,8 +15920,8 @@ function isImageRelativePath(relativePath) {
15728
15920
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
15729
15921
  assertSafeRelativePath(relativePath);
15730
15922
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
15731
- const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15732
- const st = (0, import_node_fs38.statSync)(abs);
15923
+ const abs = (0, import_node_path36.join)(worktreePath, relativePath);
15924
+ const st = (0, import_node_fs39.statSync)(abs);
15733
15925
  if (!st.isFile()) {
15734
15926
  throw new Error(`Not a file: ${relativePath}`);
15735
15927
  }
@@ -15738,7 +15930,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
15738
15930
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
15739
15931
  );
15740
15932
  }
15741
- const buf = (0, import_node_fs38.readFileSync)(abs);
15933
+ const buf = (0, import_node_fs39.readFileSync)(abs);
15742
15934
  return {
15743
15935
  path: relativePath,
15744
15936
  contentBase64: buf.toString("base64"),
@@ -15748,12 +15940,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
15748
15940
  function readWorktreeFile(worktreePath, relativePath, opts) {
15749
15941
  assertSafeRelativePath(relativePath);
15750
15942
  const maxBytes = opts?.maxBytes ?? 2e5;
15751
- const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15752
- const st = (0, import_node_fs38.statSync)(abs);
15943
+ const abs = (0, import_node_path36.join)(worktreePath, relativePath);
15944
+ const st = (0, import_node_fs39.statSync)(abs);
15753
15945
  if (!st.isFile()) {
15754
15946
  throw new Error(`Not a file: ${relativePath}`);
15755
15947
  }
15756
- const buf = (0, import_node_fs38.readFileSync)(abs);
15948
+ const buf = (0, import_node_fs39.readFileSync)(abs);
15757
15949
  if (isImageRelativePath(relativePath)) {
15758
15950
  const maxImageBytes = Math.max(maxBytes, 15e6);
15759
15951
  const truncated2 = buf.length > maxImageBytes;
@@ -15796,9 +15988,9 @@ function assertSafeRelativePath(relativePath) {
15796
15988
  }
15797
15989
  function writeWorktreeFile(worktreePath, relativePath, content) {
15798
15990
  assertSafeRelativePath(relativePath);
15799
- const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15800
- (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
15801
- (0, import_node_fs38.writeFileSync)(abs, content, "utf8");
15991
+ const abs = (0, import_node_path36.join)(worktreePath, relativePath);
15992
+ (0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(abs), { recursive: true });
15993
+ (0, import_node_fs39.writeFileSync)(abs, content, "utf8");
15802
15994
  return { path: relativePath };
15803
15995
  }
15804
15996
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -15815,12 +16007,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
15815
16007
  truncated: full.files.length > maxFiles
15816
16008
  };
15817
16009
  }
15818
- var import_node_fs38, import_node_path35, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
16010
+ var import_node_fs39, import_node_path36, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
15819
16011
  var init_diff = __esm({
15820
16012
  "src/diff/diff.ts"() {
15821
16013
  "use strict";
15822
- import_node_fs38 = require("fs");
15823
- import_node_path35 = require("path");
16014
+ import_node_fs39 = require("fs");
16015
+ import_node_path36 = require("path");
15824
16016
  init_run();
15825
16017
  init_worktree();
15826
16018
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -15988,7 +16180,7 @@ node <detached-job.js> wait <id> --until-done
15988
16180
  node <detached-job.js> status <id>
15989
16181
  \`\`\`
15990
16182
 
15991
- \`<id>\` is kebab-case (\`mac-release\`, \`core-test\`, \`fly-deploy\`). State is \`.sideboard/detached-jobs/<id>/\` (local scratch).
16183
+ \`<id>\` is kebab-case (\`mac-release\`, \`core-test\`, \`fly-deploy\`). State is \`.context/.sideboard/detached-jobs/<id>/\` (local scratch).
15992
16184
 
15993
16185
  Wait JSON:
15994
16186
 
@@ -16078,7 +16270,7 @@ function parseFrontmatter(content) {
16078
16270
  }
16079
16271
  function readSkill(skillMd, source) {
16080
16272
  try {
16081
- const content = (0, import_node_fs39.readFileSync)(skillMd, "utf8");
16273
+ const content = (0, import_node_fs40.readFileSync)(skillMd, "utf8");
16082
16274
  const { name: fmName, description } = parseFrontmatter(content);
16083
16275
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
16084
16276
  const name = fmName || dirName;
@@ -16097,19 +16289,19 @@ function readSkill(skillMd, source) {
16097
16289
  }
16098
16290
  }
16099
16291
  function scanSkillsDir(dir, source, out) {
16100
- if (!(0, import_node_fs39.existsSync)(dir)) return;
16292
+ if (!(0, import_node_fs40.existsSync)(dir)) return;
16101
16293
  let entries;
16102
16294
  try {
16103
- entries = (0, import_node_fs39.readdirSync)(dir);
16295
+ entries = (0, import_node_fs40.readdirSync)(dir);
16104
16296
  } catch {
16105
16297
  return;
16106
16298
  }
16107
16299
  for (const entry of entries) {
16108
16300
  if (entry.startsWith(".")) continue;
16109
- const skillMd = (0, import_node_path36.join)(dir, entry, "SKILL.md");
16110
- if (!(0, import_node_fs39.existsSync)(skillMd)) continue;
16301
+ const skillMd = (0, import_node_path37.join)(dir, entry, "SKILL.md");
16302
+ if (!(0, import_node_fs40.existsSync)(skillMd)) continue;
16111
16303
  try {
16112
- if (!(0, import_node_fs39.statSync)(skillMd).isFile()) continue;
16304
+ if (!(0, import_node_fs40.statSync)(skillMd).isFile()) continue;
16113
16305
  } catch {
16114
16306
  continue;
16115
16307
  }
@@ -16118,24 +16310,24 @@ function scanSkillsDir(dir, source, out) {
16118
16310
  }
16119
16311
  }
16120
16312
  function scanClaudePluginSkills(pluginsRoot, out) {
16121
- if (!(0, import_node_fs39.existsSync)(pluginsRoot)) return;
16313
+ if (!(0, import_node_fs40.existsSync)(pluginsRoot)) return;
16122
16314
  const walk = (dir, depth, lookingForSkillsDir) => {
16123
16315
  if (depth > 7) return;
16124
16316
  let entries;
16125
16317
  try {
16126
- entries = (0, import_node_fs39.readdirSync)(dir);
16318
+ entries = (0, import_node_fs40.readdirSync)(dir);
16127
16319
  } catch {
16128
16320
  return;
16129
16321
  }
16130
16322
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
16131
- const skill = readSkill((0, import_node_path36.join)(dir, "SKILL.md"), "cli");
16323
+ const skill = readSkill((0, import_node_path37.join)(dir, "SKILL.md"), "cli");
16132
16324
  if (skill) out.push(skill);
16133
16325
  }
16134
16326
  for (const entry of entries) {
16135
16327
  if (entry === "node_modules" || entry === ".git") continue;
16136
- const full = (0, import_node_path36.join)(dir, entry);
16328
+ const full = (0, import_node_path37.join)(dir, entry);
16137
16329
  try {
16138
- if (!(0, import_node_fs39.statSync)(full).isDirectory()) continue;
16330
+ if (!(0, import_node_fs40.statSync)(full).isDirectory()) continue;
16139
16331
  } catch {
16140
16332
  continue;
16141
16333
  }
@@ -16150,20 +16342,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
16150
16342
  walk(pluginsRoot, 0, false);
16151
16343
  }
16152
16344
  function discoverSkills(worktreePath) {
16153
- const home = (0, import_node_os11.homedir)();
16345
+ const home = (0, import_node_os12.homedir)();
16154
16346
  const collected = [];
16155
16347
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
16156
- scanSkillsDir((0, import_node_path36.join)(worktreePath, rel), "workspace", collected);
16348
+ scanSkillsDir((0, import_node_path37.join)(worktreePath, rel), "workspace", collected);
16157
16349
  }
16158
16350
  for (const abs of [
16159
- (0, import_node_path36.join)(home, ".claude/skills"),
16160
- (0, import_node_path36.join)(home, ".cursor/skills"),
16161
- (0, import_node_path36.join)(home, ".sideboard/skills"),
16162
- (0, import_node_path36.join)(home, ".brightsy/skills")
16351
+ (0, import_node_path37.join)(home, ".claude/skills"),
16352
+ (0, import_node_path37.join)(home, ".cursor/skills"),
16353
+ (0, import_node_path37.join)(home, ".sideboard/skills"),
16354
+ (0, import_node_path37.join)(home, ".brightsy/skills")
16163
16355
  ]) {
16164
16356
  scanSkillsDir(abs, "user", collected);
16165
16357
  }
16166
- scanClaudePluginSkills((0, import_node_path36.join)(home, ".claude/plugins"), collected);
16358
+ scanClaudePluginSkills((0, import_node_path37.join)(home, ".claude/plugins"), collected);
16167
16359
  collected.push(...bundledSkills());
16168
16360
  const rank = {
16169
16361
  workspace: 0,
@@ -16189,7 +16381,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
16189
16381
  \u2026(truncated)` : body;
16190
16382
  }
16191
16383
  }
16192
- const raw = (0, import_node_fs39.readFileSync)(skillPath, "utf8");
16384
+ const raw = (0, import_node_fs40.readFileSync)(skillPath, "utf8");
16193
16385
  if (raw.startsWith("---")) {
16194
16386
  const end = raw.indexOf("\n---", 3);
16195
16387
  if (end >= 0) {
@@ -16203,13 +16395,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
16203
16395
 
16204
16396
  \u2026(truncated)` : raw;
16205
16397
  }
16206
- var import_node_fs39, import_node_os11, import_node_path36, BUNDLED_SKILL_PREFIX;
16398
+ var import_node_fs40, import_node_os12, import_node_path37, BUNDLED_SKILL_PREFIX;
16207
16399
  var init_discover = __esm({
16208
16400
  "src/skills/discover.ts"() {
16209
16401
  "use strict";
16210
- import_node_fs39 = require("fs");
16211
- import_node_os11 = require("os");
16212
- import_node_path36 = require("path");
16402
+ import_node_fs40 = require("fs");
16403
+ import_node_os12 = require("os");
16404
+ import_node_path37 = require("path");
16213
16405
  init_long_running();
16214
16406
  BUNDLED_SKILL_PREFIX = "bundled:";
16215
16407
  }
@@ -16304,17 +16496,17 @@ var init_expand = __esm({
16304
16496
  function packagedDetachedJobPath() {
16305
16497
  const dir = packagedMcpDir();
16306
16498
  if (!dir) return null;
16307
- const script = (0, import_node_path37.join)(dir, "scripts", "detached-job.js");
16308
- return (0, import_node_fs40.existsSync)(script) ? script : null;
16499
+ const script = (0, import_node_path38.join)(dir, "scripts", "detached-job.js");
16500
+ return (0, import_node_fs41.existsSync)(script) ? script : null;
16309
16501
  }
16310
16502
  function resolveDetachedJobScript() {
16311
16503
  const packaged = packagedDetachedJobPath();
16312
16504
  if (packaged) return packaged;
16313
- let dir = (0, import_node_path37.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
16505
+ let dir = (0, import_node_path38.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
16314
16506
  for (let i = 0; i < 8; i++) {
16315
- const candidate = (0, import_node_path37.join)(dir, "scripts", "detached-job.js");
16316
- if ((0, import_node_fs40.existsSync)(candidate)) return candidate;
16317
- const parent = (0, import_node_path37.dirname)(dir);
16507
+ const candidate = (0, import_node_path38.join)(dir, "scripts", "detached-job.js");
16508
+ if ((0, import_node_fs41.existsSync)(candidate)) return candidate;
16509
+ const parent = (0, import_node_path38.dirname)(dir);
16318
16510
  if (parent === dir) break;
16319
16511
  dir = parent;
16320
16512
  }
@@ -16325,12 +16517,12 @@ function formatDetachedJobInvoke(scriptPath) {
16325
16517
  if (resolved) return `node ${JSON.stringify(resolved)}`;
16326
16518
  return "node scripts/detached-job.js";
16327
16519
  }
16328
- var import_node_fs40, import_node_path37, import_node_url3, import_meta3;
16520
+ var import_node_fs41, import_node_path38, import_node_url3, import_meta3;
16329
16521
  var init_detached_job_path = __esm({
16330
16522
  "src/skills/detached-job-path.ts"() {
16331
16523
  "use strict";
16332
- import_node_fs40 = require("fs");
16333
- import_node_path37 = require("path");
16524
+ import_node_fs41 = require("fs");
16525
+ import_node_path38 = require("path");
16334
16526
  import_node_url3 = require("url");
16335
16527
  init_packaged_runtime();
16336
16528
  import_meta3 = {};
@@ -16403,11 +16595,11 @@ function formatWorktreeDirective(thread, opts) {
16403
16595
  );
16404
16596
  } else if (opts?.githubSlug) {
16405
16597
  lines.push(
16406
- `- 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.`
16598
+ `- 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\`.`
16407
16599
  );
16408
16600
  } else {
16409
16601
  lines.push(
16410
- "- 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."
16602
+ "- 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`."
16411
16603
  );
16412
16604
  }
16413
16605
  lines.push("");
@@ -16463,7 +16655,7 @@ function formatLongRunningDirective(opts) {
16463
16655
  "- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
16464
16656
  `- Loop \`${invoke} wait <id>\` (returns in ~45s). stillRunning \u2192 present the same id with \`content=delta\` only \u2192 wait again. Do not resend the full log or HTML.`,
16465
16657
  "- ok \u2192 finish the task. failed \u2192 read the log, fix, start once.",
16466
- "State: `.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
16658
+ "State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
16467
16659
  ].join("\n");
16468
16660
  }
16469
16661
  function formatLongRunningReminder(opts) {
@@ -16498,12 +16690,12 @@ function formatArtifactDirective() {
16498
16690
  function formatUiReminder() {
16499
16691
  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.";
16500
16692
  }
16501
- var import_node_fs41, import_node_path38;
16693
+ var import_node_fs42, import_node_path39;
16502
16694
  var init_instructions = __esm({
16503
16695
  "src/agents/instructions.ts"() {
16504
16696
  "use strict";
16505
- import_node_fs41 = require("fs");
16506
- import_node_path38 = require("path");
16697
+ import_node_fs42 = require("fs");
16698
+ import_node_path39 = require("path");
16507
16699
  init_git_auth_mode();
16508
16700
  init_worktree_labels();
16509
16701
  init_detached_job_path();
@@ -16673,40 +16865,40 @@ __export(plan_file_exports, {
16673
16865
  writePlanFile: () => writePlanFile
16674
16866
  });
16675
16867
  function ensureAttachmentsGitignore(worktreePath) {
16676
- const gitignoreAbs = (0, import_node_path39.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
16677
- if ((0, import_node_fs42.existsSync)(gitignoreAbs)) return;
16678
- (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(gitignoreAbs), { recursive: true });
16679
- (0, import_node_fs42.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
16868
+ const gitignoreAbs = (0, import_node_path40.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
16869
+ if ((0, import_node_fs43.existsSync)(gitignoreAbs)) return;
16870
+ (0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(gitignoreAbs), { recursive: true });
16871
+ (0, import_node_fs43.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
16680
16872
  }
16681
16873
  function planFileAbs(worktreePath) {
16682
- return (0, import_node_path39.join)(worktreePath, PLAN_FILE_REL);
16874
+ return (0, import_node_path40.join)(worktreePath, PLAN_FILE_REL);
16683
16875
  }
16684
16876
  function readTextIfPresent2(abs) {
16685
- if (!(0, import_node_fs42.existsSync)(abs)) return null;
16877
+ if (!(0, import_node_fs43.existsSync)(abs)) return null;
16686
16878
  try {
16687
- const content = (0, import_node_fs42.readFileSync)(abs, "utf8");
16879
+ const content = (0, import_node_fs43.readFileSync)(abs, "utf8");
16688
16880
  return content.trim() ? content : null;
16689
16881
  } catch {
16690
16882
  return null;
16691
16883
  }
16692
16884
  }
16693
16885
  function readPlanFile(worktreePath) {
16694
- 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));
16886
+ 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));
16695
16887
  }
16696
16888
  function writePlanFile(worktreePath, content) {
16697
16889
  ensureAttachmentsGitignore(worktreePath);
16698
16890
  const abs = planFileAbs(worktreePath);
16699
- (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(abs), { recursive: true });
16891
+ (0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(abs), { recursive: true });
16700
16892
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
16701
- (0, import_node_fs42.writeFileSync)(abs, body, "utf8");
16893
+ (0, import_node_fs43.writeFileSync)(abs, body, "utf8");
16702
16894
  return PLAN_FILE_REL;
16703
16895
  }
16704
- var import_node_fs42, import_node_path39;
16896
+ var import_node_fs43, import_node_path40;
16705
16897
  var init_plan_file = __esm({
16706
16898
  "src/plan/plan-file.ts"() {
16707
16899
  "use strict";
16708
- import_node_fs42 = require("fs");
16709
- import_node_path39 = require("path");
16900
+ import_node_fs43 = require("fs");
16901
+ import_node_path40 = require("path");
16710
16902
  init_workspace_scratch();
16711
16903
  init_plan_present();
16712
16904
  init_plan_present();
@@ -16766,7 +16958,7 @@ function setCaffeinateHoldHooks(next) {
16766
16958
  hooks = next;
16767
16959
  }
16768
16960
  function caffeinateHoldPath() {
16769
- return (0, import_node_path40.join)(appDataDir(), "caffeinate-hold.json");
16961
+ return (0, import_node_path41.join)(appDataDir(), "caffeinate-hold.json");
16770
16962
  }
16771
16963
  function processAlive(pid) {
16772
16964
  if (hooks.processAlive) return hooks.processAlive(pid);
@@ -16800,9 +16992,9 @@ function uniqueIds(ids) {
16800
16992
  }
16801
16993
  function readHold() {
16802
16994
  const path = caffeinateHoldPath();
16803
- if (!(0, import_node_fs43.existsSync)(path)) return null;
16995
+ if (!(0, import_node_fs44.existsSync)(path)) return null;
16804
16996
  try {
16805
- const parsed = JSON.parse((0, import_node_fs43.readFileSync)(path, "utf8"));
16997
+ const parsed = JSON.parse((0, import_node_fs44.readFileSync)(path, "utf8"));
16806
16998
  if (typeof parsed?.pid === "number" && parsed.pid > 0) {
16807
16999
  return {
16808
17000
  pid: parsed.pid,
@@ -16824,7 +17016,7 @@ function writeHold(pid, threadIds) {
16824
17016
  }
16825
17017
  function clearHold() {
16826
17018
  try {
16827
- (0, import_node_fs43.unlinkSync)(caffeinateHoldPath());
17019
+ (0, import_node_fs44.unlinkSync)(caffeinateHoldPath());
16828
17020
  } catch {
16829
17021
  }
16830
17022
  }
@@ -16909,13 +17101,13 @@ function releaseCaffeinateHoldForThread(threadId) {
16909
17101
  }
16910
17102
  return setCaffeinateHold(false, { threadId: id });
16911
17103
  }
16912
- var import_node_child_process4, import_node_fs43, import_node_path40, hooks;
17104
+ var import_node_child_process4, import_node_fs44, import_node_path41, hooks;
16913
17105
  var init_caffeinate_hold = __esm({
16914
17106
  "src/store/caffeinate-hold.ts"() {
16915
17107
  "use strict";
16916
17108
  import_node_child_process4 = require("child_process");
16917
- import_node_fs43 = require("fs");
16918
- import_node_path40 = require("path");
17109
+ import_node_fs44 = require("fs");
17110
+ import_node_path41 = require("path");
16919
17111
  init_paths();
16920
17112
  init_private_file();
16921
17113
  hooks = {};
@@ -16924,7 +17116,7 @@ var init_caffeinate_hold = __esm({
16924
17116
 
16925
17117
  // src/store/schedules.ts
16926
17118
  function schedulesPath() {
16927
- return (0, import_node_path41.join)(appDataDir(), "schedules.json");
17119
+ return (0, import_node_path42.join)(appDataDir(), "schedules.json");
16928
17120
  }
16929
17121
  function parseDurationMs(every) {
16930
17122
  const m = every.trim().match(DURATION_RE);
@@ -17024,9 +17216,9 @@ function normalizeTask(raw) {
17024
17216
  }
17025
17217
  function readAll2() {
17026
17218
  const path = schedulesPath();
17027
- if (!(0, import_node_fs44.existsSync)(path)) return [];
17219
+ if (!(0, import_node_fs45.existsSync)(path)) return [];
17028
17220
  try {
17029
- const parsed = JSON.parse((0, import_node_fs44.readFileSync)(path, "utf8"));
17221
+ const parsed = JSON.parse((0, import_node_fs45.readFileSync)(path, "utf8"));
17030
17222
  if (!Array.isArray(parsed)) return [];
17031
17223
  return parsed.map((row) => {
17032
17224
  try {
@@ -17051,7 +17243,7 @@ function buildTask(input, now) {
17051
17243
  const ts = nowIso2(now);
17052
17244
  const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
17053
17245
  return {
17054
- id: (0, import_node_crypto8.randomUUID)(),
17246
+ id: (0, import_node_crypto9.randomUUID)(),
17055
17247
  name: input.name?.trim() || defaultScheduleName(prompt),
17056
17248
  prompt,
17057
17249
  enabled: input.enabled !== false,
@@ -17138,13 +17330,13 @@ function recordScheduleRun(id, result) {
17138
17330
  writeAll2(rows);
17139
17331
  return next;
17140
17332
  }
17141
- var import_node_crypto8, import_node_fs44, import_node_path41, import_croner, DURATION_RE, UNIT_MS;
17333
+ var import_node_crypto9, import_node_fs45, import_node_path42, import_croner, DURATION_RE, UNIT_MS;
17142
17334
  var init_schedules = __esm({
17143
17335
  "src/store/schedules.ts"() {
17144
17336
  "use strict";
17145
- import_node_crypto8 = require("crypto");
17146
- import_node_fs44 = require("fs");
17147
- import_node_path41 = require("path");
17337
+ import_node_crypto9 = require("crypto");
17338
+ import_node_fs45 = require("fs");
17339
+ import_node_path42 = require("path");
17148
17340
  import_croner = require("croner");
17149
17341
  init_orchestrator_capable();
17150
17342
  init_paths();
@@ -17286,13 +17478,13 @@ var init_schedule_runner = __esm({
17286
17478
 
17287
17479
  // src/agents/cursor-store.ts
17288
17480
  function cursorSdkStoreDir(threadId) {
17289
- const root = (0, import_node_path42.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
17481
+ const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
17290
17482
  const id = sanitizeCursorStoreSegment(threadId);
17291
17483
  if (!id) return root;
17292
- return (0, import_node_path42.join)(root, "threads", id);
17484
+ return (0, import_node_path43.join)(root, "threads", id);
17293
17485
  }
17294
17486
  function cursorSdkRunsNdjsonPath(threadId) {
17295
- return (0, import_node_path42.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
17487
+ return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
17296
17488
  }
17297
17489
  function cursorSdkRunsNdjsonSearchPaths(threadId) {
17298
17490
  const scoped = cursorSdkRunsNdjsonPath(threadId);
@@ -17305,11 +17497,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
17305
17497
  function sanitizeCursorStoreSegment(threadId) {
17306
17498
  return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
17307
17499
  }
17308
- var import_node_path42, CURSOR_SDK_STORE_DIR;
17500
+ var import_node_path43, CURSOR_SDK_STORE_DIR;
17309
17501
  var init_cursor_store = __esm({
17310
17502
  "src/agents/cursor-store.ts"() {
17311
17503
  "use strict";
17312
- import_node_path42 = require("path");
17504
+ import_node_path43 = require("path");
17313
17505
  init_paths();
17314
17506
  CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
17315
17507
  }
@@ -17331,9 +17523,9 @@ function recoverFinishedCursorRun(opts) {
17331
17523
  return best;
17332
17524
  }
17333
17525
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
17334
- if (!(0, import_node_fs45.existsSync)(runsPath)) return null;
17526
+ if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
17335
17527
  try {
17336
- const lines = (0, import_node_fs45.readFileSync)(runsPath, "utf8").split("\n");
17528
+ const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
17337
17529
  let best = null;
17338
17530
  for (const line of lines) {
17339
17531
  const trimmed = line.trim();
@@ -17359,11 +17551,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
17359
17551
  return null;
17360
17552
  }
17361
17553
  }
17362
- var import_node_fs45;
17554
+ var import_node_fs46;
17363
17555
  var init_cursor_recover = __esm({
17364
17556
  "src/agents/cursor-recover.ts"() {
17365
17557
  "use strict";
17366
- import_node_fs45 = require("fs");
17558
+ import_node_fs46 = require("fs");
17367
17559
  init_cursor_store();
17368
17560
  }
17369
17561
  });
@@ -17402,6 +17594,7 @@ var init_title = __esm({
17402
17594
  // src/orchestrator/orchestrator.ts
17403
17595
  var orchestrator_exports = {};
17404
17596
  __export(orchestrator_exports, {
17597
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
17405
17598
  Orchestrator: () => Orchestrator,
17406
17599
  getOrchestrator: () => getOrchestrator,
17407
17600
  isPidAlive: () => isPidAlive,
@@ -17494,13 +17687,13 @@ async function startOrchestration(opts) {
17494
17687
  }
17495
17688
  return updated;
17496
17689
  }
17497
- var import_node_events, import_node_fs46, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
17690
+ var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
17498
17691
  var init_orchestrator = __esm({
17499
17692
  "src/orchestrator/orchestrator.ts"() {
17500
17693
  "use strict";
17501
17694
  import_node_events = require("events");
17502
17695
  init_outbound_watch();
17503
- import_node_fs46 = require("fs");
17696
+ import_node_fs47 = require("fs");
17504
17697
  init_error_detail();
17505
17698
  init_run();
17506
17699
  init_stale_lock();
@@ -17515,6 +17708,7 @@ var init_orchestrator = __esm({
17515
17708
  init_orphan_cleanup();
17516
17709
  init_apply_into_main();
17517
17710
  init_clone_repo();
17711
+ init_message_parts();
17518
17712
  init_usage();
17519
17713
  init_thread_store();
17520
17714
  init_desktop_host();
@@ -17552,6 +17746,7 @@ var init_orchestrator = __esm({
17552
17746
  init_caffeinate_hold();
17553
17747
  init_schedule_runner();
17554
17748
  init_coordinator_prompt();
17749
+ LIVE_TURN_SPAWN_GRACE_MS = 15e3;
17555
17750
  STALE_AGENT_PID_WAIT_MS = 2500;
17556
17751
  Orchestrator = class {
17557
17752
  events = new import_node_events.EventEmitter();
@@ -17608,6 +17803,39 @@ var init_orchestrator = __esm({
17608
17803
  if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
17609
17804
  return true;
17610
17805
  }
17806
+ /**
17807
+ * Whether a child is actually turning — not leftover disk `running` after
17808
+ * the process died. Coordinators were telling users “Agent is running.
17809
+ * Waiting for gate to pass” from stale stillRunning.
17810
+ */
17811
+ threadLooksLive(thread) {
17812
+ if (thread.status === "queued") {
17813
+ if (this.draining.has(thread.id) || this.startingTurns.has(thread.id)) return true;
17814
+ return thread.queue.length > 0;
17815
+ }
17816
+ if (thread.status !== "running") return false;
17817
+ if (this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id)) return true;
17818
+ const pid = thread.agentPid;
17819
+ if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return true;
17820
+ const updated = Date.parse(thread.updatedAt ?? "");
17821
+ if (Number.isFinite(updated) && Date.now() - updated < LIVE_TURN_SPAWN_GRACE_MS) return true;
17822
+ return false;
17823
+ }
17824
+ /** Desktop-only: persist idle/stopped when MCP would otherwise keep reporting live. */
17825
+ healStaleReportedActivity(thread) {
17826
+ if (!thisProcessShouldDrainAgentQueues()) return thread;
17827
+ if (this.threadLooksLive(thread)) return thread;
17828
+ if (thread.status === "running") {
17829
+ this.healStaleRunningTurns();
17830
+ return readThread(thread.id) ?? thread;
17831
+ }
17832
+ if (thread.status === "queued" && thread.queue.length === 0 && !this.activeTurns.has(thread.id) && !this.startingTurns.has(thread.id) && !this.draining.has(thread.id)) {
17833
+ setStatus(thread.id, "idle");
17834
+ this.emit({ type: "status_changed", threadId: thread.id, status: "idle" });
17835
+ return readThread(thread.id) ?? thread;
17836
+ }
17837
+ return thread;
17838
+ }
17611
17839
  async reconcile(repoPath, opts) {
17612
17840
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
17613
17841
  const drainQueues = opts?.drainQueues !== false;
@@ -17632,7 +17860,7 @@ var init_orchestrator = __esm({
17632
17860
  }
17633
17861
  continue;
17634
17862
  }
17635
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
17863
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
17636
17864
  setStatus(thread.id, "broken", "Worktree missing on disk");
17637
17865
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
17638
17866
  continue;
@@ -17942,12 +18170,14 @@ var init_orchestrator = __esm({
17942
18170
  this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
17943
18171
  return thread;
17944
18172
  }
17945
- async send(threadRef, prompt) {
18173
+ async send(threadRef, prompt, opts) {
17946
18174
  const thread = this.requireThread(threadRef);
17947
18175
  if (thread.status === "archived") {
17948
18176
  throw new Error(`Thread is archived: ${thread.id}`);
17949
18177
  }
17950
- return withThreadLock(thread.id, async () => {
18178
+ const followUp = opts?.followUp === "steer" ? "steer" : "queue";
18179
+ let shouldSteer = false;
18180
+ const sent = await withThreadLock(thread.id, async () => {
17951
18181
  const current = this.requireThread(thread.id);
17952
18182
  if (current.status === "archived") {
17953
18183
  throw new Error(`Thread is archived: ${thread.id}`);
@@ -17956,6 +18186,7 @@ var init_orchestrator = __esm({
17956
18186
  this.crashContinued.delete(thread.id);
17957
18187
  this.haltDrain.delete(thread.id);
17958
18188
  const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
18189
+ shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
17959
18190
  const patch = { queue };
17960
18191
  if (!inFlight) patch.status = "queued";
17961
18192
  const pid = current.agentPid;
@@ -17967,16 +18198,20 @@ var init_orchestrator = __esm({
17967
18198
  if (!inFlight) {
17968
18199
  this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
17969
18200
  }
17970
- if (thisProcessShouldDrainAgentQueues()) {
18201
+ if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
17971
18202
  void this.drainQueue(thread.id);
17972
18203
  }
17973
18204
  return this.requireThread(thread.id);
17974
18205
  });
18206
+ if (shouldSteer && sent.queue.length > 0) {
18207
+ return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
18208
+ }
18209
+ return sent;
17975
18210
  }
17976
- async fanOut(threadRefs, prompt) {
18211
+ async fanOut(threadRefs, prompt, opts) {
17977
18212
  const results = [];
17978
18213
  for (const ref of threadRefs) {
17979
- results.push(await this.send(ref, prompt));
18214
+ results.push(await this.send(ref, prompt, opts));
17980
18215
  }
17981
18216
  return results;
17982
18217
  }
@@ -18780,8 +19015,8 @@ var init_orchestrator = __esm({
18780
19015
  return created;
18781
19016
  }
18782
19017
  async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
18783
- const thread = this.requireThread(threadRef);
18784
- if (!["running", "queued"].includes(thread.status)) {
19018
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19019
+ if (!this.threadLooksLive(thread)) {
18785
19020
  return thread;
18786
19021
  }
18787
19022
  const start = Date.now();
@@ -18818,12 +19053,13 @@ var init_orchestrator = __esm({
18818
19053
  }
18819
19054
  });
18820
19055
  timer = setInterval(() => {
18821
- const current = readThread(thread.id);
18822
- if (!current) {
19056
+ const raw = readThread(thread.id);
19057
+ if (!raw) {
18823
19058
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
18824
19059
  return;
18825
19060
  }
18826
- if (!["running", "queued"].includes(current.status)) {
19061
+ const current = this.healStaleReportedActivity(raw);
19062
+ if (!this.threadLooksLive(current)) {
18827
19063
  finish(() => resolve(current));
18828
19064
  return;
18829
19065
  }
@@ -18846,20 +19082,22 @@ var init_orchestrator = __esm({
18846
19082
  };
18847
19083
  }
18848
19084
  getTurnResult(threadRef) {
18849
- const thread = this.requireThread(threadRef);
19085
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
18850
19086
  const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
18851
19087
  const lastError = thread.lastError ?? null;
18852
- const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
18853
- const stillRunning = thread.status === "running" || thread.status === "queued";
19088
+ const rawText = (lastAgent?.text ?? "").trim();
19089
+ const text5 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
19090
+ const stillRunning = this.threadLooksLive(thread);
18854
19091
  const live = stillRunning ? readTurnLive(thread.id) : null;
18855
- const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
19092
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
19093
+ const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
18856
19094
  return {
18857
19095
  text: text5,
18858
19096
  status: thread.status,
18859
19097
  sessionId: thread.sessionId,
18860
19098
  lastError,
18861
19099
  stillRunning,
18862
- progress: live?.summary ?? queuedHint,
19100
+ progress: liveSummary ?? queuedHint,
18863
19101
  lastActivityAt: live?.updatedAt ?? null,
18864
19102
  usage: lastAgent?.usage ?? null
18865
19103
  };
@@ -19207,7 +19445,14 @@ var init_orchestrator = __esm({
19207
19445
  );
19208
19446
  }
19209
19447
  if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
19210
- await this.pushAndMaybeOpenPr(thread, action);
19448
+ try {
19449
+ await this.pushAndMaybeOpenPr(thread, action);
19450
+ } catch (err) {
19451
+ const message = err instanceof Error ? err.message : String(err);
19452
+ updateThread(thread.id, { lastError: message });
19453
+ this.emit({ type: "error", threadId: thread.id, message });
19454
+ throw err;
19455
+ }
19211
19456
  return this.requireThread(threadRef);
19212
19457
  }
19213
19458
  let prBase;
@@ -19410,7 +19655,7 @@ var init_orchestrator = __esm({
19410
19655
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
19411
19656
  return restored2;
19412
19657
  }
19413
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
19658
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
19414
19659
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
19415
19660
  throw new Error(
19416
19661
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -19422,6 +19667,8 @@ var init_orchestrator = __esm({
19422
19667
  await withRepoGitLock(thread.repoPath, async () => {
19423
19668
  await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
19424
19669
  });
19670
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
19671
+ await ensureWorktreeSideboardIgnored2(dest);
19425
19672
  void createThreadWorktree2;
19426
19673
  void slug;
19427
19674
  }
@@ -19490,8 +19737,8 @@ init_nested_electron_env();
19490
19737
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
19491
19738
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
19492
19739
  var import_zod5 = require("zod");
19493
- var import_node_crypto11 = require("crypto");
19494
- var import_node_path45 = require("path");
19740
+ var import_node_crypto12 = require("crypto");
19741
+ var import_node_path46 = require("path");
19495
19742
  init_orchestrator();
19496
19743
  init_worktree();
19497
19744
 
@@ -19505,7 +19752,7 @@ init_abletime();
19505
19752
  init_fetch();
19506
19753
 
19507
19754
  // src/integrations/linear-oauth.ts
19508
- var import_node_crypto9 = require("crypto");
19755
+ var import_node_crypto10 = require("crypto");
19509
19756
  var import_node_http = require("http");
19510
19757
  init_app_settings();
19511
19758
  init_fetch();
@@ -19683,6 +19930,22 @@ query SideboardAssignedIssues($first: Int!) {
19683
19930
  }
19684
19931
  }
19685
19932
  `;
19933
+ var ISSUES_QUERY = `
19934
+ query SideboardIssues($first: Int!, $filter: IssueFilter) {
19935
+ viewer { id name }
19936
+ issues(first: $first, orderBy: updatedAt, filter: $filter) {
19937
+ nodes { ${LIST_ISSUE_FIELDS} }
19938
+ }
19939
+ }
19940
+ `;
19941
+ var SEARCH_ISSUES_QUERY = `
19942
+ query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
19943
+ viewer { id name }
19944
+ searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
19945
+ nodes { ${LIST_ISSUE_FIELDS} }
19946
+ }
19947
+ }
19948
+ `;
19686
19949
  var TEAMS_QUERY = `
19687
19950
  query SideboardTeams {
19688
19951
  viewer { id name }
@@ -19966,19 +20229,73 @@ function normalizePriority(priority) {
19966
20229
  }
19967
20230
  return priority;
19968
20231
  }
19969
- async function listLinearAssignedIssues(opts) {
19970
- const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
19971
- const json = await linearGraphql(ASSIGNED_ISSUES_QUERY, { first }, opts);
20232
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20233
+ function assigneeFilterKey(assignee) {
20234
+ return (assignee ?? "").trim();
20235
+ }
20236
+ function buildLinearIssueFilter(input) {
20237
+ const filter = {
20238
+ state: { type: { nin: ["completed", "canceled"] } }
20239
+ };
20240
+ const raw = assigneeFilterKey(input?.assignee) || "me";
20241
+ const key = raw.toLowerCase();
20242
+ if (key === "all" || key === "*") return filter;
20243
+ if (key === "unassigned" || key === "none" || key === "null") {
20244
+ filter.assignee = { null: true };
20245
+ return filter;
20246
+ }
20247
+ if (key === "me" || key === "@me") {
20248
+ filter.assignee = { isMe: true };
20249
+ return filter;
20250
+ }
20251
+ if (UUID_RE.test(raw)) {
20252
+ filter.assignee = { id: { eq: raw } };
20253
+ return filter;
20254
+ }
20255
+ filter.assignee = { name: { eqIgnoreCase: raw } };
20256
+ return filter;
20257
+ }
20258
+ function isAssignedToMe(assignee) {
20259
+ const key = assignee.toLowerCase();
20260
+ return key === "me" || key === "@me";
20261
+ }
20262
+ function listedLinearIssues(json, nodes) {
19972
20263
  return {
19973
20264
  viewer: {
19974
20265
  id: String(json.viewer?.id ?? ""),
19975
20266
  name: String(json.viewer?.name ?? "")
19976
20267
  },
19977
- issues: (json.viewer?.assignedIssues?.nodes ?? []).map(
19978
- (node) => toIssueInfo(mapIssue(node))
19979
- )
20268
+ issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
19980
20269
  };
19981
20270
  }
20271
+ async function listLinearIssuesFiltered(opts) {
20272
+ const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
20273
+ const query = opts?.query?.trim() ?? "";
20274
+ const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
20275
+ const filter = buildLinearIssueFilter({ assignee });
20276
+ if (query) {
20277
+ const json2 = await linearGraphql(
20278
+ SEARCH_ISSUES_QUERY,
20279
+ { term: query, first, filter },
20280
+ opts
20281
+ );
20282
+ return listedLinearIssues(json2, json2.searchIssues?.nodes);
20283
+ }
20284
+ if (isAssignedToMe(assignee)) {
20285
+ const json2 = await linearGraphql(
20286
+ ASSIGNED_ISSUES_QUERY,
20287
+ { first },
20288
+ opts
20289
+ );
20290
+ return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
20291
+ }
20292
+ const json = await linearGraphql(
20293
+ ISSUES_QUERY,
20294
+ { first, filter },
20295
+ opts
20296
+ );
20297
+ return listedLinearIssues(json, json.issues?.nodes);
20298
+ }
19982
20299
  async function listLinearTeams(opts) {
19983
20300
  const json = await linearGraphql(TEAMS_QUERY, void 0, opts);
19984
20301
  return {
@@ -20085,6 +20402,22 @@ async function commentLinearIssue(input, opts) {
20085
20402
  }
20086
20403
 
20087
20404
  // src/integrations/issues.ts
20405
+ function assigneeKey(assignee) {
20406
+ return (assignee ?? "").trim().toLowerCase();
20407
+ }
20408
+ function issueMatchesAssignee(issue, assignee, viewerName = "") {
20409
+ const key = assigneeKey(assignee);
20410
+ if (!key || key === "all" || key === "*") return true;
20411
+ const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
20412
+ if (key === "unassigned" || key === "none" || key === "null") {
20413
+ return names.length === 0;
20414
+ }
20415
+ if (key === "me" || key === "@me") {
20416
+ const me = viewerName.trim().toLowerCase();
20417
+ return Boolean(me && names.includes(me));
20418
+ }
20419
+ return names.includes(key);
20420
+ }
20088
20421
  async function listGitHubIssues(repoPath, opts) {
20089
20422
  const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
20090
20423
  const slug = await resolveGithubRepoSlug(repoPath);
@@ -20098,6 +20431,17 @@ async function listGitHubIssues(repoPath, opts) {
20098
20431
  "--state",
20099
20432
  "open"
20100
20433
  ];
20434
+ const query = opts?.query?.trim() ?? "";
20435
+ const assignee = opts?.assignee?.trim() ?? "";
20436
+ const key = assignee.toLowerCase();
20437
+ const searchParts = [];
20438
+ if (query) searchParts.push(query);
20439
+ if (key === "unassigned" || key === "none" || key === "null") {
20440
+ searchParts.push("no:assignee");
20441
+ } else if (key && key !== "all" && key !== "*") {
20442
+ args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
20443
+ }
20444
+ if (searchParts.length) args.push("--search", searchParts.join(" "));
20101
20445
  if (slug) args.push("--repo", slug);
20102
20446
  const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
20103
20447
  if (exitCode !== 0 || !stdout.trim()) return [];
@@ -20135,14 +20479,20 @@ async function githubViewerLogin(repoPath) {
20135
20479
  if (exitCode !== 0) return "";
20136
20480
  return stdout.trim();
20137
20481
  }
20138
- async function listIssues(repoPath) {
20482
+ async function listIssues(repoPath, opts) {
20139
20483
  const settings = loadAppSettings();
20140
20484
  const preferredSource = settings.integrations.issueSource ?? "github";
20141
20485
  const linearConnected = isLinearConnected(settings);
20142
20486
  const abletimeConnected = isAbleTimeConnected(settings);
20143
20487
  const source = resolveEffectiveIssueSource(settings);
20488
+ const query = opts?.query?.trim() || void 0;
20489
+ const assignee = opts?.assignee?.trim() || void 0;
20144
20490
  if (source === "linear") {
20145
- const listed = await listLinearAssignedIssues();
20491
+ const listed = await listLinearIssuesFiltered({
20492
+ assignee,
20493
+ query,
20494
+ limit: opts?.limit
20495
+ });
20146
20496
  return {
20147
20497
  source,
20148
20498
  preferredSource,
@@ -20156,13 +20506,20 @@ async function listIssues(repoPath) {
20156
20506
  };
20157
20507
  }
20158
20508
  if (source === "abletime") {
20159
- const listed = await listAbleTimeAssignedIssues();
20509
+ const [listed, searched] = await Promise.all([
20510
+ listAbleTimeAssignedIssues(),
20511
+ query ? searchAbleTimeTasks(query) : Promise.resolve(null)
20512
+ ]);
20513
+ const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
20514
+ const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
20515
+ (issue) => issueMatchesAssignee(issue, assignee, viewerName)
20516
+ );
20160
20517
  return {
20161
20518
  source,
20162
20519
  preferredSource,
20163
20520
  linearConnected,
20164
20521
  abletimeConnected,
20165
- issues: listed.issues,
20522
+ issues: issues2,
20166
20523
  viewer: {
20167
20524
  login: listed.viewer.name,
20168
20525
  name: listed.viewer.name
@@ -20170,7 +20527,7 @@ async function listIssues(repoPath) {
20170
20527
  };
20171
20528
  }
20172
20529
  const [issues, login] = await Promise.all([
20173
- listGitHubIssues(repoPath),
20530
+ listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
20174
20531
  githubViewerLogin(repoPath)
20175
20532
  ]);
20176
20533
  return {
@@ -20223,14 +20580,16 @@ function mcpWaitFinishedHint(status) {
20223
20580
  }
20224
20581
 
20225
20582
  // src/mcp/server.ts
20583
+ init_message_parts();
20226
20584
  init_turn_live();
20227
20585
 
20228
20586
  // src/mcp/thread-visibility.ts
20587
+ init_message_parts();
20229
20588
  function lastMessagePreview(messages, max = 160) {
20230
20589
  if (!messages?.length) return null;
20231
20590
  for (let i = messages.length - 1; i >= 0; i--) {
20232
20591
  const text5 = messages[i]?.text?.trim();
20233
- if (!text5) continue;
20592
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
20234
20593
  const flat = text5.replace(/\s+/g, " ");
20235
20594
  return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
20236
20595
  }
@@ -20900,6 +21259,22 @@ function registerLinearTools(server) {
20900
21259
  }
20901
21260
  }
20902
21261
  );
21262
+ server.tool(
21263
+ "linear_search_issues",
21264
+ "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).",
21265
+ {
21266
+ query: import_zod3.z.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
21267
+ 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."),
21268
+ limit: import_zod3.z.number().int().positive().max(250).optional()
21269
+ },
21270
+ async ({ query, assignee, limit }) => {
21271
+ try {
21272
+ return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
21273
+ } catch (err) {
21274
+ return fail3(err);
21275
+ }
21276
+ }
21277
+ );
20903
21278
  server.tool(
20904
21279
  "linear_get_issue",
20905
21280
  "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.",
@@ -21134,30 +21509,31 @@ function registerScheduleTools(server) {
21134
21509
 
21135
21510
  // src/mcp/server.ts
21136
21511
  init_agent_git_actions();
21512
+ init_gh_errors();
21137
21513
  init_git_auth_mode();
21138
21514
 
21139
21515
  // src/board/load-home-board.ts
21140
- var import_node_fs48 = require("fs");
21141
- var import_node_path44 = require("path");
21516
+ var import_node_fs49 = require("fs");
21517
+ var import_node_path45 = require("path");
21142
21518
  init_worktree();
21143
21519
  init_paths();
21144
21520
 
21145
21521
  // src/board/board-pins.ts
21146
- var import_node_crypto10 = require("crypto");
21147
- var import_node_fs47 = require("fs");
21148
- var import_node_path43 = require("path");
21522
+ var import_node_crypto11 = require("crypto");
21523
+ var import_node_fs48 = require("fs");
21524
+ var import_node_path44 = require("path");
21149
21525
  init_paths();
21150
21526
  init_home_board();
21151
21527
  var FILE = "home-board-pins.json";
21152
21528
  var VERSION = 1;
21153
21529
  function pinsFile() {
21154
- return (0, import_node_path43.join)(appDataDir(), FILE);
21530
+ return (0, import_node_path44.join)(appDataDir(), FILE);
21155
21531
  }
21156
21532
  function readDisk() {
21157
21533
  const path = pinsFile();
21158
- if (!(0, import_node_fs47.existsSync)(path)) return [];
21534
+ if (!(0, import_node_fs48.existsSync)(path)) return [];
21159
21535
  try {
21160
- const raw = JSON.parse((0, import_node_fs47.readFileSync)(path, "utf8"));
21536
+ const raw = JSON.parse((0, import_node_fs48.readFileSync)(path, "utf8"));
21161
21537
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
21162
21538
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
21163
21539
  } catch {
@@ -21165,8 +21541,8 @@ function readDisk() {
21165
21541
  }
21166
21542
  }
21167
21543
  function writeDisk(items) {
21168
- (0, import_node_fs47.mkdirSync)(appDataDir(), { recursive: true });
21169
- (0, import_node_fs47.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
21544
+ (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
21545
+ (0, import_node_fs48.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
21170
21546
  }
21171
21547
  function listBoardPins() {
21172
21548
  return readDisk();
@@ -21187,7 +21563,7 @@ function homeBoardWorkspaceKey(workspaces) {
21187
21563
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
21188
21564
  }
21189
21565
  function cacheFile() {
21190
- return (0, import_node_path44.join)(appDataDir(), "home-board-cache.json");
21566
+ return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
21191
21567
  }
21192
21568
  function emptyInputs() {
21193
21569
  return {
@@ -21213,9 +21589,9 @@ function shouldCacheHomeBoardInputs(inputs) {
21213
21589
  }
21214
21590
  function readDiskCache() {
21215
21591
  const path = cacheFile();
21216
- if (!(0, import_node_fs48.existsSync)(path)) return null;
21592
+ if (!(0, import_node_fs49.existsSync)(path)) return null;
21217
21593
  try {
21218
- const raw = JSON.parse((0, import_node_fs48.readFileSync)(path, "utf8"));
21594
+ const raw = JSON.parse((0, import_node_fs49.readFileSync)(path, "utf8"));
21219
21595
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
21220
21596
  return null;
21221
21597
  }
@@ -21229,8 +21605,8 @@ function readDiskCache() {
21229
21605
  }
21230
21606
  function writeDiskCache(entry) {
21231
21607
  try {
21232
- (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
21233
- (0, import_node_fs48.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
21608
+ (0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
21609
+ (0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
21234
21610
  } catch {
21235
21611
  }
21236
21612
  }
@@ -21519,13 +21895,13 @@ async function startMcpServer() {
21519
21895
  async () => {
21520
21896
  const threads = orch.getThreads(true);
21521
21897
  const lines = threads.map((t) => {
21522
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path45.basename)(t.repoPath) || t.repoPath;
21523
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
21898
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path46.basename)(t.repoPath) || t.repoPath;
21899
+ const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
21524
21900
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
21525
21901
  const preview = lastMessagePreview(t.messages, 80);
21526
21902
  const previewBit = preview ? ` ${preview}` : "";
21527
21903
  const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
21528
- const progress = live?.summary ? ` ${live.summary}` : "";
21904
+ const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
21529
21905
  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}`;
21530
21906
  });
21531
21907
  return {
@@ -21587,7 +21963,9 @@ async function startMcpServer() {
21587
21963
  if (!t) {
21588
21964
  return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
21589
21965
  }
21590
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
21966
+ const stillRunning = orch.threadLooksLive(t);
21967
+ const live = stillRunning ? readTurnLive(t.id) : null;
21968
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
21591
21969
  const spend = orch.getThreadUsage(t.id);
21592
21970
  const summary = {
21593
21971
  id: t.id,
@@ -21607,8 +21985,8 @@ async function startMcpServer() {
21607
21985
  devPort: t.devPort,
21608
21986
  prUrl: t.prUrl,
21609
21987
  lastError: t.lastError ?? null,
21610
- stillRunning: t.status === "running" || t.status === "queued",
21611
- progress: live?.summary ?? (t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
21988
+ stillRunning,
21989
+ progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
21612
21990
  lastActivityAt: live?.updatedAt ?? null,
21613
21991
  usage: spend.usage,
21614
21992
  lastTurnUsage: spend.lastTurnUsage
@@ -21889,7 +22267,7 @@ async function startMcpServer() {
21889
22267
  const ident = issue?.identifier ?? ref.trim();
21890
22268
  const attachments = issue ? [
21891
22269
  {
21892
- id: (0, import_node_crypto11.randomUUID)(),
22270
+ id: (0, import_node_crypto12.randomUUID)(),
21893
22271
  name: issue.identifier,
21894
22272
  kind: "issue",
21895
22273
  content: [
@@ -21965,7 +22343,7 @@ async function startMcpServer() {
21965
22343
  );
21966
22344
  server.tool(
21967
22345
  "wait_for_turn",
21968
- "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).",
22346
+ "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).",
21969
22347
  {
21970
22348
  ref: import_zod5.z.string(),
21971
22349
  timeoutMs: import_zod5.z.number().optional()
@@ -22157,7 +22535,7 @@ async function startMcpServer() {
22157
22535
  );
22158
22536
  server.tool(
22159
22537
  "ask_git",
22160
- "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.",
22538
+ "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
22161
22539
  {
22162
22540
  ref: import_zod5.z.string().describe("Worktree thread id/ref"),
22163
22541
  action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
@@ -22182,8 +22560,26 @@ async function startMcpServer() {
22182
22560
  ]
22183
22561
  };
22184
22562
  } catch (err) {
22185
- const message = err instanceof Error ? err.message : String(err);
22186
- return { content: [{ type: "text", text: message }], isError: true };
22563
+ const raw = err instanceof Error ? err.message : String(err);
22564
+ const message = formatGhLandError(raw);
22565
+ return {
22566
+ content: [
22567
+ {
22568
+ type: "text",
22569
+ text: JSON.stringify(
22570
+ {
22571
+ error: true,
22572
+ action,
22573
+ lastError: message,
22574
+ 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
22575
+ },
22576
+ null,
22577
+ 2
22578
+ )
22579
+ }
22580
+ ],
22581
+ isError: true
22582
+ };
22187
22583
  }
22188
22584
  }
22189
22585
  );
@@ -22578,11 +22974,15 @@ async function startMcpServer() {
22578
22974
  );
22579
22975
  server.tool(
22580
22976
  "list_issues",
22581
- "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.",
22582
- { repoPath: import_zod5.z.string() },
22583
- async ({ repoPath }) => {
22977
+ "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.",
22978
+ {
22979
+ repoPath: import_zod5.z.string(),
22980
+ query: import_zod5.z.string().optional().describe("Search title, identifier, or description"),
22981
+ assignee: import_zod5.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
22982
+ },
22983
+ async ({ repoPath, query, assignee }) => {
22584
22984
  const root = await resolveRepoRoot(repoPath);
22585
- const result = await listIssues(root);
22985
+ const result = await listIssues(root, { query, assignee });
22586
22986
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22587
22987
  }
22588
22988
  );