@sideboard-ai/core 0.1.148 → 0.1.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/{abletime-QEVAE67D.js → abletime-223A3LY6.js} +2 -2
  2. package/dist/{abletime-DI55AJX3.js → abletime-CLC5UJC2.js} +2 -2
  3. package/dist/agents/cursor-runner.cjs +85 -45
  4. package/dist/agents/cursor-runner.js +47 -12
  5. package/dist/{agents-DUF4Q2ZI.js → agents-KKXGTEV6.js} +10 -9
  6. package/dist/{agents-INCTFWKA.js → agents-YWBQXOA2.js} +10 -9
  7. package/dist/{app-settings-WJDCJFSY.js → app-settings-3CHCNIMD.js} +5 -1
  8. package/dist/{app-settings-ZCN632OJ.js → app-settings-J3JBCUOT.js} +5 -1
  9. package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
  10. package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
  11. package/dist/{chunk-R4JP32P5.js → chunk-AF6O55PJ.js} +4 -4
  12. package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
  13. package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
  14. package/dist/{chunk-ZVYLEF72.js → chunk-DMRIZR6M.js} +6 -6
  15. package/dist/{chunk-5MS2XTNV.js → chunk-DXCNW2JF.js} +113 -52
  16. package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
  17. package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
  18. package/dist/{chunk-3QRGCKYL.js → chunk-HAS5EPBS.js} +2 -2
  19. package/dist/{chunk-WT5HSFOU.js → chunk-HEII7W3Q.js} +5 -2
  20. package/dist/{chunk-EGDRPA4B.js → chunk-NOTANBYC.js} +6 -6
  21. package/dist/{chunk-CTXQHSTY.js → chunk-NUPITVRF.js} +134 -73
  22. package/dist/{chunk-QTUESPAW.js → chunk-PTOSP4AH.js} +1 -1
  23. package/dist/{chunk-Q62SDB53.js → chunk-QGJHIJHV.js} +2 -2
  24. package/dist/{chunk-YQRBNOIW.js → chunk-SDN4ZYQH.js} +24 -13
  25. package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
  26. package/dist/{chunk-N3VNOFXQ.js → chunk-VO4SPEBS.js} +4 -4
  27. package/dist/chunk-VSFGPWCQ.js +62 -0
  28. package/dist/{chunk-N5PM7HGQ.js → chunk-W6N6GQME.js} +1 -1
  29. package/dist/{chunk-FKOIHGKV.js → chunk-WHU7YGWP.js} +1 -1
  30. package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
  31. package/dist/chunk-Y4NAPW5I.js +60 -0
  32. package/dist/{chunk-B3SJXYIJ.js → chunk-Y7YBWWIG.js} +1 -1
  33. package/dist/{chunk-XOKHXFFX.js → chunk-YGGBJY5A.js} +22 -8
  34. package/dist/{chunk-JTPDWTWJ.js → chunk-Z2PVJKMN.js} +137 -114
  35. package/dist/{chunk-YP3CSOZ6.js → chunk-ZGFYFVJF.js} +142 -114
  36. package/dist/{connected-teams-IJUJQ7R6.js → connected-teams-I2WZZZFA.js} +2 -2
  37. package/dist/{connected-teams-4A2AXDNN.js → connected-teams-XO766HB4.js} +2 -2
  38. package/dist/{coordinator-prompt-ZWBMAIWA.js → coordinator-prompt-NYR5TPBD.js} +6 -5
  39. package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-UCQJTFA7.js} +6 -5
  40. package/dist/{global-workspace-2SIPM4PW.js → global-workspace-4QHDAD2D.js} +7 -6
  41. package/dist/{global-workspace-OJRXWXEA.js → global-workspace-4SENNWBU.js} +7 -6
  42. package/dist/index.cjs +1002 -575
  43. package/dist/index.d.cts +91 -10
  44. package/dist/index.d.ts +91 -10
  45. package/dist/index.js +268 -93
  46. package/dist/mcp/run-stdio.cjs +980 -580
  47. package/dist/mcp/run-stdio.js +196 -43
  48. package/dist/{orchestrator-OVYITCO6.js → orchestrator-GZE4X3XV.js} +14 -11
  49. package/dist/{orchestrator-NWIU5TJP.js → orchestrator-QSBRWME5.js} +16 -13
  50. package/dist/{plan-file-6O7G4VPQ.js → plan-file-5S5TUNAW.js} +2 -2
  51. package/dist/{plan-file-PHVKUAEE.js → plan-file-IBSU2PVW.js} +2 -2
  52. package/dist/{run-XQKGHQZ2.js → run-CAGKZLHA.js} +1 -1
  53. package/dist/{run-USF6FRKV.js → run-EBWL2Q4N.js} +1 -1
  54. package/dist/{workspaces-UUJNOO4T.js → workspaces-7S7QKCUE.js} +8 -7
  55. package/dist/{workspaces-3NUUZTQK.js → workspaces-RDUSB6FD.js} +8 -7
  56. package/dist/{worktree-RZRJNHYL.js → worktree-63AGPPLO.js} +5 -4
  57. package/dist/{worktree-UCWWTVLS.js → worktree-JIZ3QMZX.js} +5 -4
  58. package/dist/worktree-exclude-6MQWGWV5.js +11 -0
  59. package/dist/worktree-exclude-TV6EV6BS.js +9 -0
  60. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -837,6 +837,7 @@ var init_issue_source_labels = __esm({
837
837
  // src/store/app-settings.ts
838
838
  var app_settings_exports = {};
839
839
  __export(app_settings_exports, {
840
+ FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
840
841
  GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
841
842
  HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
842
843
  ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
@@ -862,6 +863,7 @@ __export(app_settings_exports, {
862
863
  disconnectLinearConnection: () => disconnectLinearConnection,
863
864
  emptyPublicIntegrations: () => emptyPublicIntegrations,
864
865
  ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
866
+ followUpBehavior: () => followUpBehavior,
865
867
  getAbleTimeAccessToken: () => getAbleTimeAccessToken,
866
868
  getAbleTimeHost: () => getAbleTimeHost,
867
869
  getDefaultAgent: () => getDefaultAgent,
@@ -1218,6 +1220,9 @@ function normalizeAdvanced(raw) {
1218
1220
  if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
1219
1221
  out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
1220
1222
  }
1223
+ if (source.followUpBehavior === "queue" || source.followUpBehavior === "steer") {
1224
+ out.followUpBehavior = source.followUpBehavior;
1225
+ }
1221
1226
  return out;
1222
1227
  }
1223
1228
  function normalizeSettings(raw) {
@@ -1909,6 +1914,9 @@ function updateAdvancedSettings(patch) {
1909
1914
  if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
1910
1915
  advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
1911
1916
  }
1917
+ if (patch.followUpBehavior === "queue" || patch.followUpBehavior === "steer") {
1918
+ advanced.followUpBehavior = patch.followUpBehavior;
1919
+ }
1912
1920
  return saveAppSettings({ ...current, advanced });
1913
1921
  }
1914
1922
  function autoRenameBranchEnabled(settings = loadAppSettings()) {
@@ -1954,6 +1962,9 @@ function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
1954
1962
  }
1955
1963
  return "cursor";
1956
1964
  }
1965
+ function followUpBehavior(settings = loadAppSettings()) {
1966
+ return settings.advanced.followUpBehavior === "queue" ? "queue" : "steer";
1967
+ }
1957
1968
  function maxConcurrentAgents(settings = loadAppSettings()) {
1958
1969
  const n = settings.advanced.maxConcurrent;
1959
1970
  if (typeof n === "number" && Number.isFinite(n)) {
@@ -2041,7 +2052,7 @@ function childEnvWithAppSettings(extra) {
2041
2052
  function harnessEnvKey(harness) {
2042
2053
  return HARNESS_ENV_KEYS[harness];
2043
2054
  }
2044
- var import_node_crypto2, import_node_fs7, import_node_os3, import_node_path8, HARNESS_ENV_KEYS, DEFAULT_AGENTS, GITHUB_GIT_AUTH_MODES, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, GIT_AUTH_MODES, EMPTY_SETTINGS, DEFAULT_CLI_BIN;
2055
+ var import_node_crypto2, import_node_fs7, import_node_os3, import_node_path8, 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;
2045
2056
  var init_app_settings = __esm({
2046
2057
  "src/store/app-settings.ts"() {
2047
2058
  "use strict";
@@ -2070,6 +2081,7 @@ var init_app_settings = __esm({
2070
2081
  "cursor"
2071
2082
  ]);
2072
2083
  GITHUB_GIT_AUTH_MODES = ["auto", "gh", "ssh", "token"];
2084
+ FOLLOW_UP_BEHAVIORS = ["steer", "queue"];
2073
2085
  CLOUD_CONNECT_AGENTS = /* @__PURE__ */ new Set([
2074
2086
  "claude",
2075
2087
  "codex",
@@ -2869,7 +2881,7 @@ function attachmentsGitignoreBody() {
2869
2881
  }
2870
2882
  function isWorkspaceScratchPath(relativePath) {
2871
2883
  const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
2872
- return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
2884
+ 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/");
2873
2885
  }
2874
2886
  var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
2875
2887
  var init_workspace_scratch = __esm({
@@ -3991,6 +4003,18 @@ var init_worktree_labels = __esm({
3991
4003
  function isGhRateLimitError(text5) {
3992
4004
  return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
3993
4005
  }
4006
+ function isGhPrBodyTooLongError(text5) {
4007
+ 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(
4008
+ text5
4009
+ );
4010
+ }
4011
+ function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
4012
+ const t = body.replace(/\s+$/u, "");
4013
+ if (t.length <= max) return t;
4014
+ const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
4015
+ const keep = Math.max(0, max - note.length);
4016
+ return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
4017
+ }
3994
4018
  function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
3995
4019
  const ms = resetEpochSec * 1e3 - nowMs;
3996
4020
  if (ms <= 0) return "soon";
@@ -4001,18 +4025,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
4001
4025
  const hours = Math.ceil(mins / 60);
4002
4026
  return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
4003
4027
  }
4028
+ function omitGhBodyArg(text5) {
4029
+ return text5.replace(
4030
+ /--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
4031
+ "--body <omitted>"
4032
+ );
4033
+ }
4034
+ function capGhErrorText(text5, max = 400) {
4035
+ const t = text5.trim();
4036
+ if (t.length <= max) return t;
4037
+ return `${t.slice(0, max - 1).trimEnd()}\u2026`;
4038
+ }
4004
4039
  function extractGhErrorDetail(text5) {
4005
- const trimmed = text5.trim();
4040
+ const trimmed = omitGhBodyArg(text5.trim());
4006
4041
  if (!trimmed) return "";
4042
+ if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
4043
+ return "GraphQL: body is too long (GitHub PR body / request size limit).";
4044
+ }
4007
4045
  const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
4008
- if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}`;
4046
+ if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
4009
4047
  const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
4010
- if (http?.[1]) return `HTTP: ${http[1].trim()}`;
4048
+ if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
4011
4049
  const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
4012
4050
  if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
4013
- return lines.slice(1).join(" ").trim() || lines[0];
4051
+ return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
4014
4052
  }
4015
- return trimmed;
4053
+ return capGhErrorText(trimmed);
4016
4054
  }
4017
4055
  function formatGhLandError(raw, opts) {
4018
4056
  const trimmed = raw.trim();
@@ -4030,6 +4068,10 @@ function formatGhLandError(raw, opts) {
4030
4068
  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>.";
4031
4069
  return `Could not create the pull request.${hint}`;
4032
4070
  }
4071
+ if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
4072
+ const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
4073
+ 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.`;
4074
+ }
4033
4075
  if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
4034
4076
  const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
4035
4077
  const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
@@ -4058,130 +4100,51 @@ function formatIpcInvokeError(err) {
4058
4100
  if (isPrNotMergeableError(msg)) return formatMergePrError(msg);
4059
4101
  return formatGhLandError(msg);
4060
4102
  }
4103
+ var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
4061
4104
  var init_gh_errors = __esm({
4062
4105
  "src/git/gh-errors.ts"() {
4063
4106
  "use strict";
4064
- }
4065
- });
4066
-
4067
- // src/git/github-agent-auth.ts
4068
- function githubAgentAuthDir() {
4069
- const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
4070
- if (override) return override;
4071
- return (0, import_node_path14.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
4072
- }
4073
- function githubCredentialStorePath() {
4074
- return (0, import_node_path14.join)(githubAgentAuthDir(), "git-credentials");
4075
- }
4076
- function githubGhConfigDir() {
4077
- return (0, import_node_path14.join)(githubAgentAuthDir(), "gh");
4078
- }
4079
- function writePrivateFile2(file, body) {
4080
- (0, import_node_fs13.mkdirSync)((0, import_node_path14.dirname)(file), { recursive: true, mode: 448 });
4081
- try {
4082
- (0, import_node_fs13.chmodSync)((0, import_node_path14.dirname)(file), 448);
4083
- } catch {
4084
- }
4085
- (0, import_node_fs13.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
4086
- try {
4087
- (0, import_node_fs13.chmodSync)(file, 384);
4088
- } catch {
4089
- }
4090
- }
4091
- function gitCredentialStoreContents(token) {
4092
- return `https://x-access-token:${encodeURIComponent(token)}@github.com
4093
- `;
4094
- }
4095
- function ghHostsYml(token, user = "x-access-token") {
4096
- const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
4097
- return [
4098
- "github.com:",
4099
- " git_protocol: https",
4100
- ` user: ${u}`,
4101
- ` oauth_token: ${token}`,
4102
- " users:",
4103
- ` ${u}:`,
4104
- ` oauth_token: ${token}`,
4105
- ""
4106
- ].join("\n");
4107
- }
4108
- function materializeGithubAgentAuth(token, user) {
4109
- const trimmed = token.trim();
4110
- if (!trimmed) return;
4111
- const root = githubAgentAuthDir();
4112
- (0, import_node_fs13.mkdirSync)(root, { recursive: true, mode: 448 });
4113
- try {
4114
- (0, import_node_fs13.chmodSync)(root, 448);
4115
- } catch {
4116
- }
4117
- writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
4118
- const ghDir = githubGhConfigDir();
4119
- (0, import_node_fs13.mkdirSync)(ghDir, { recursive: true, mode: 448 });
4120
- writePrivateFile2((0, import_node_path14.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
4121
- writePrivateFile2((0, import_node_path14.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
4122
- }
4123
- function githubAgentAuthReady() {
4124
- return (0, import_node_fs13.existsSync)(githubCredentialStorePath()) && (0, import_node_fs13.existsSync)((0, import_node_path14.join)(githubGhConfigDir(), "hosts.yml"));
4125
- }
4126
- function githubCredentialHelperGitConfig() {
4127
- const file = githubCredentialStorePath();
4128
- return [
4129
- { key: "credential.helper", value: "" },
4130
- { key: "credential.helper", value: `store --file=${file}` }
4131
- ];
4132
- }
4133
- function githubGhConfigEnv() {
4134
- return {
4135
- GH_CONFIG_DIR: githubGhConfigDir(),
4136
- GH_PROMPT_DISABLED: "1"
4137
- };
4138
- }
4139
- var import_node_fs13, import_node_os4, import_node_path14;
4140
- var init_github_agent_auth = __esm({
4141
- "src/git/github-agent-auth.ts"() {
4142
- "use strict";
4143
- import_node_fs13 = require("fs");
4144
- import_node_os4 = require("os");
4145
- import_node_path14 = require("path");
4107
+ GITHUB_PR_BODY_MAX_CHARS = 65536;
4108
+ GITHUB_PR_BODY_SAFE_CHARS = 6e4;
4146
4109
  }
4147
4110
  });
4148
4111
 
4149
4112
  // src/agents/path.ts
4150
4113
  function prependPathDir(env, dir) {
4151
- if (!dir || !(0, import_node_fs14.existsSync)(dir)) return;
4114
+ if (!dir || !(0, import_node_fs13.existsSync)(dir)) return;
4152
4115
  const current = env.PATH ?? "";
4153
- const parts = current.split(import_node_path15.delimiter).filter(Boolean);
4116
+ const parts = current.split(import_node_path14.delimiter).filter(Boolean);
4154
4117
  if (parts.includes(dir)) {
4155
4118
  env.PATH = current;
4156
4119
  return;
4157
4120
  }
4158
- env.PATH = [dir, ...parts].join(import_node_path15.delimiter);
4121
+ env.PATH = [dir, ...parts].join(import_node_path14.delimiter);
4159
4122
  }
4160
- function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os5.homedir)()) {
4161
- return (0, import_node_path15.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
4123
+ function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os4.homedir)()) {
4124
+ return (0, import_node_path14.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
4162
4125
  }
4163
4126
  function isConductorBundledCli(filePath) {
4164
4127
  const p = (filePath ?? "").replace(/\\/g, "/");
4165
4128
  return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
4166
4129
  }
4167
4130
  function ensureAgentPath(env = process.env) {
4168
- const home = env.HOME || env.USERPROFILE || (0, import_node_os5.homedir)();
4131
+ const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
4169
4132
  const current = env.PATH ?? "";
4170
- const parts = current.split(import_node_path15.delimiter).filter(Boolean);
4133
+ const parts = current.split(import_node_path14.delimiter).filter(Boolean);
4171
4134
  const seen = new Set(parts);
4172
4135
  const extras = [
4173
- ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path15.join)(home, rel)),
4136
+ ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path14.join)(home, rel)),
4174
4137
  "/opt/homebrew/bin",
4175
4138
  "/usr/local/bin",
4176
4139
  // Keep after Homebrew/npm so a user-installed CLI still wins.
4177
4140
  conductorBundledBinDir(home)
4178
4141
  ];
4179
4142
  for (const dir of extras.reverse()) {
4180
- if (!dir || seen.has(dir) || !(0, import_node_fs14.existsSync)(dir)) continue;
4143
+ if (!dir || seen.has(dir) || !(0, import_node_fs13.existsSync)(dir)) continue;
4181
4144
  parts.unshift(dir);
4182
4145
  seen.add(dir);
4183
4146
  }
4184
- const next = parts.join(import_node_path15.delimiter);
4147
+ const next = parts.join(import_node_path14.delimiter);
4185
4148
  env.PATH = next;
4186
4149
  return next;
4187
4150
  }
@@ -4195,7 +4158,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
4195
4158
  stdio: ["ignore", "pipe", "ignore"]
4196
4159
  }).trim().split(/\r?\n/).find(Boolean);
4197
4160
  if (prefix) {
4198
- const binDir = process.platform === "win32" ? prefix : (0, import_node_path15.join)(prefix, "bin");
4161
+ const binDir = process.platform === "win32" ? prefix : (0, import_node_path14.join)(prefix, "bin");
4199
4162
  prependPathDir(env, binDir);
4200
4163
  }
4201
4164
  } catch {
@@ -4223,14 +4186,14 @@ function withExportedPath(command, pathValue) {
4223
4186
  if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
4224
4187
  return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
4225
4188
  }
4226
- var import_node_fs14, import_node_child_process3, import_node_os5, import_node_path15, EXTRA_BIN_DIRS;
4189
+ var import_node_fs13, import_node_child_process3, import_node_os4, import_node_path14, EXTRA_BIN_DIRS;
4227
4190
  var init_path = __esm({
4228
4191
  "src/agents/path.ts"() {
4229
4192
  "use strict";
4230
- import_node_fs14 = require("fs");
4193
+ import_node_fs13 = require("fs");
4231
4194
  import_node_child_process3 = require("child_process");
4232
- import_node_os5 = require("os");
4233
- import_node_path15 = require("path");
4195
+ import_node_os4 = require("os");
4196
+ import_node_path14 = require("path");
4234
4197
  EXTRA_BIN_DIRS = [
4235
4198
  ".local/bin",
4236
4199
  ".cargo/bin",
@@ -4247,6 +4210,88 @@ var init_path = __esm({
4247
4210
  }
4248
4211
  });
4249
4212
 
4213
+ // src/git/github-agent-auth.ts
4214
+ function githubAgentAuthDir() {
4215
+ const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
4216
+ if (override) return override;
4217
+ return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".sideboard-git-auth");
4218
+ }
4219
+ function githubCredentialStorePath() {
4220
+ return (0, import_node_path15.join)(githubAgentAuthDir(), "git-credentials");
4221
+ }
4222
+ function githubGhConfigDir() {
4223
+ return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
4224
+ }
4225
+ function writePrivateFile2(file, body) {
4226
+ (0, import_node_fs14.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
4227
+ try {
4228
+ (0, import_node_fs14.chmodSync)((0, import_node_path15.dirname)(file), 448);
4229
+ } catch {
4230
+ }
4231
+ (0, import_node_fs14.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
4232
+ try {
4233
+ (0, import_node_fs14.chmodSync)(file, 384);
4234
+ } catch {
4235
+ }
4236
+ }
4237
+ function gitCredentialStoreContents(token) {
4238
+ return `https://x-access-token:${encodeURIComponent(token)}@github.com
4239
+ `;
4240
+ }
4241
+ function ghHostsYml(token, user = "x-access-token") {
4242
+ const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
4243
+ return [
4244
+ "github.com:",
4245
+ " git_protocol: https",
4246
+ ` user: ${u}`,
4247
+ ` oauth_token: ${token}`,
4248
+ " users:",
4249
+ ` ${u}:`,
4250
+ ` oauth_token: ${token}`,
4251
+ ""
4252
+ ].join("\n");
4253
+ }
4254
+ function materializeGithubAgentAuth(token, user) {
4255
+ const trimmed = token.trim();
4256
+ if (!trimmed) return;
4257
+ const root = githubAgentAuthDir();
4258
+ (0, import_node_fs14.mkdirSync)(root, { recursive: true, mode: 448 });
4259
+ try {
4260
+ (0, import_node_fs14.chmodSync)(root, 448);
4261
+ } catch {
4262
+ }
4263
+ writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
4264
+ const ghDir = githubGhConfigDir();
4265
+ (0, import_node_fs14.mkdirSync)(ghDir, { recursive: true, mode: 448 });
4266
+ writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
4267
+ writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
4268
+ }
4269
+ function githubAgentAuthReady() {
4270
+ return (0, import_node_fs14.existsSync)(githubCredentialStorePath()) && (0, import_node_fs14.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
4271
+ }
4272
+ function githubCredentialHelperGitConfig() {
4273
+ const file = githubCredentialStorePath();
4274
+ return [
4275
+ { key: "credential.helper", value: "" },
4276
+ { key: "credential.helper", value: `store --file=${file}` }
4277
+ ];
4278
+ }
4279
+ function githubGhConfigEnv() {
4280
+ return {
4281
+ GH_CONFIG_DIR: githubGhConfigDir(),
4282
+ GH_PROMPT_DISABLED: "1"
4283
+ };
4284
+ }
4285
+ var import_node_fs14, import_node_os5, import_node_path15;
4286
+ var init_github_agent_auth = __esm({
4287
+ "src/git/github-agent-auth.ts"() {
4288
+ "use strict";
4289
+ import_node_fs14 = require("fs");
4290
+ import_node_os5 = require("os");
4291
+ import_node_path15 = require("path");
4292
+ }
4293
+ });
4294
+
4250
4295
  // src/git/stale-lock.ts
4251
4296
  function isIndexLockError(text5) {
4252
4297
  return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
@@ -4373,7 +4418,10 @@ async function gh(args, cwd, opts) {
4373
4418
  timeoutMs: opts?.timeoutMs,
4374
4419
  env: {
4375
4420
  GH_PROMPT_DISABLED: "1",
4376
- GIT_TERMINAL_PROMPT: "0"
4421
+ GIT_TERMINAL_PROMPT: "0",
4422
+ // Isolated hosts.yml uses git_protocol: https so `gh pr create` does not
4423
+ // shell out over SSH when Settings → Git is SSH (ask_git in Electron).
4424
+ ...githubAgentAuthReady() ? githubGhConfigEnv() : {}
4377
4425
  }
4378
4426
  });
4379
4427
  }
@@ -4389,11 +4437,95 @@ var init_run = __esm({
4389
4437
  "use strict";
4390
4438
  import_execa2 = require("execa");
4391
4439
  init_path();
4440
+ init_github_agent_auth();
4392
4441
  init_stale_lock();
4393
4442
  }
4394
4443
  });
4395
4444
 
4445
+ // src/git/worktree-exclude.ts
4446
+ var worktree_exclude_exports = {};
4447
+ __export(worktree_exclude_exports, {
4448
+ WORKTREE_SIDEBOARD_EXCLUDE: () => WORKTREE_SIDEBOARD_EXCLUDE,
4449
+ ensureWorktreeSideboardIgnored: () => ensureWorktreeSideboardIgnored
4450
+ });
4451
+ function excludeHasSideboard(body) {
4452
+ return body.split(/\r?\n/).some((line) => {
4453
+ const t = line.trim();
4454
+ return t === ".sideboard/" || t === ".sideboard" || t === "/.sideboard/";
4455
+ });
4456
+ }
4457
+ async function ensureWorktreeSideboardIgnored(worktreePath) {
4458
+ if (!worktreePath.trim()) return;
4459
+ const gitDir = await git(["rev-parse", "--absolute-git-dir"], worktreePath, {
4460
+ reject: false,
4461
+ timeoutMs: 5e3
4462
+ });
4463
+ if (gitDir.exitCode !== 0) return;
4464
+ const dir = gitDir.stdout.trim();
4465
+ if (!dir) return;
4466
+ const excludePath = (0, import_node_path17.join)(dir, "info", "exclude");
4467
+ (0, import_node_fs16.mkdirSync)((0, import_node_path17.dirname)(excludePath), { recursive: true });
4468
+ let body = "";
4469
+ try {
4470
+ body = (0, import_node_fs16.readFileSync)(excludePath, "utf8");
4471
+ } catch {
4472
+ body = "";
4473
+ }
4474
+ if (!excludeHasSideboard(body)) {
4475
+ const prefix = body && !body.endsWith("\n") ? `${body}
4476
+ ` : body;
4477
+ (0, import_node_fs16.writeFileSync)(
4478
+ excludePath,
4479
+ `${prefix}${EXCLUDE_COMMENT}
4480
+ ${WORKTREE_SIDEBOARD_EXCLUDE}
4481
+ `,
4482
+ "utf8"
4483
+ );
4484
+ }
4485
+ const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
4486
+ reject: false,
4487
+ timeoutMs: 5e3
4488
+ });
4489
+ if (listed.exitCode !== 0 || !listed.stdout) return;
4490
+ const files = listed.stdout.split("\0").filter(Boolean);
4491
+ if (files.length === 0) return;
4492
+ await git(["update-index", "--skip-worktree", "--", ...files], worktreePath, {
4493
+ reject: false,
4494
+ timeoutMs: 8e3
4495
+ });
4496
+ }
4497
+ var import_node_fs16, import_node_path17, WORKTREE_SIDEBOARD_EXCLUDE, EXCLUDE_COMMENT;
4498
+ var init_worktree_exclude = __esm({
4499
+ "src/git/worktree-exclude.ts"() {
4500
+ "use strict";
4501
+ import_node_fs16 = require("fs");
4502
+ import_node_path17 = require("path");
4503
+ init_run();
4504
+ WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
4505
+ EXCLUDE_COMMENT = "# Sideboard worktree scratch \u2014 do not commit";
4506
+ }
4507
+ });
4508
+
4396
4509
  // src/git/git-auth-mode.ts
4510
+ function githubHttpsInsteadOfEntries(remoteUrl) {
4511
+ const entries = [...HTTPS_REWRITE];
4512
+ const url = remoteUrl?.trim() ?? "";
4513
+ const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
4514
+ if (scpAlias?.[1]) {
4515
+ entries.push({
4516
+ key: "url.https://github.com/.insteadOf",
4517
+ value: `${scpAlias[1]}:`
4518
+ });
4519
+ }
4520
+ const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
4521
+ if (sshAlias?.[1]) {
4522
+ entries.push({
4523
+ key: "url.https://github.com/.insteadOf",
4524
+ value: `ssh://git@${sshAlias[1]}/`
4525
+ });
4526
+ }
4527
+ return entries;
4528
+ }
4397
4529
  function nonInteractiveGitProcessEnv() {
4398
4530
  return {
4399
4531
  GIT_TERMINAL_PROMPT: "0",
@@ -4416,16 +4548,19 @@ function appendIndexedGitConfig(existing, entries) {
4416
4548
  out.GIT_CONFIG_COUNT = String(count + entries.length);
4417
4549
  return out;
4418
4550
  }
4419
- function githubAgentGitEnv(existing) {
4551
+ function githubAgentGitEnv(existing, opts) {
4420
4552
  const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
4421
- return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
4553
+ return appendIndexedGitConfig(existing, [
4554
+ ...githubHttpsInsteadOfEntries(opts?.remoteUrl),
4555
+ ...helpers
4556
+ ]);
4422
4557
  }
4423
4558
  function applyGithubGitAuthEnv(existing, opts) {
4424
4559
  const out = { ...nonInteractiveGitProcessEnv() };
4425
4560
  const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
4426
4561
  if (token) materializeGithubAgentAuth(token);
4427
4562
  Object.assign(out, githubGhConfigEnv());
4428
- if (opts.mode === "ssh") return out;
4563
+ if (opts.mode === "ssh" && !token) return out;
4429
4564
  Object.assign(out, githubAgentGitEnv(existing));
4430
4565
  return out;
4431
4566
  }
@@ -4484,7 +4619,7 @@ async function warmGithubAgentAuth(opts) {
4484
4619
  }
4485
4620
  function normalizeWritableRoot(raw) {
4486
4621
  const trimmed = raw.trim().replace(/\/+$/, "");
4487
- return trimmed && (0, import_node_path17.isAbsolute)(trimmed) ? trimmed : null;
4622
+ return trimmed && (0, import_node_path18.isAbsolute)(trimmed) ? trimmed : null;
4488
4623
  }
4489
4624
  async function resolveCodexGitWritableRoots(cwd) {
4490
4625
  const roots = /* @__PURE__ */ new Set();
@@ -4541,8 +4676,9 @@ function formatGitAuthModeDirective(mode) {
4541
4676
  case "ssh":
4542
4677
  return [
4543
4678
  "Git authentication (Settings \u2192 Git mode: SSH):",
4544
- "- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
4545
- "- 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.",
4679
+ "- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
4680
+ "- 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.",
4681
+ "- 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).",
4546
4682
  "- `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.",
4547
4683
  "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
4548
4684
  ].join("\n");
@@ -4561,11 +4697,11 @@ function formatGitAuthModeDirective(mode) {
4561
4697
  ].join("\n");
4562
4698
  }
4563
4699
  }
4564
- var import_node_path17, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4700
+ var import_node_path18, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4565
4701
  var init_git_auth_mode = __esm({
4566
4702
  "src/git/git-auth-mode.ts"() {
4567
4703
  "use strict";
4568
- import_node_path17 = require("path");
4704
+ import_node_path18 = require("path");
4569
4705
  init_app_settings();
4570
4706
  init_github_agent_auth();
4571
4707
  init_run();
@@ -5027,7 +5163,7 @@ async function resolveRepoRoot(cwd) {
5027
5163
  }
5028
5164
  function canonicalizeRepoPath(path2) {
5029
5165
  try {
5030
- return (0, import_node_fs16.realpathSync)(path2);
5166
+ return (0, import_node_fs17.realpathSync)(path2);
5031
5167
  } catch {
5032
5168
  return path2.replace(/\/+$/, "");
5033
5169
  }
@@ -5766,6 +5902,16 @@ function originFetchBranch(sourceRef) {
5766
5902
  if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
5767
5903
  return ref;
5768
5904
  }
5905
+ async function originRemoteUrl(cwd) {
5906
+ const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
5907
+ return result.exitCode === 0 ? result.stdout.trim() : "";
5908
+ }
5909
+ function githubHttpsRetryEnv(remoteUrl) {
5910
+ return {
5911
+ GIT_TERMINAL_PROMPT: "0",
5912
+ ...githubAgentGitEnv(void 0, { remoteUrl })
5913
+ };
5914
+ }
5769
5915
  async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5770
5916
  const first = await git(args, repoPath, { reject: false, timeoutMs });
5771
5917
  if (first.exitCode === 0) return true;
@@ -5775,15 +5921,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5775
5921
  } catch {
5776
5922
  return false;
5777
5923
  }
5778
- if (mode === "ssh") return false;
5779
5924
  const token = await resolveGithubAgentToken(mode, repoPath);
5780
5925
  if (!token) return false;
5926
+ const remoteUrl = await originRemoteUrl(repoPath);
5781
5927
  const tryHttps = async (header) => git(args, repoPath, {
5782
5928
  reject: false,
5783
5929
  timeoutMs,
5784
- env: { GIT_TERMINAL_PROMPT: "0" },
5930
+ env: githubHttpsRetryEnv(remoteUrl),
5785
5931
  config: {
5786
- "url.https://github.com/.insteadOf": "git@github.com:",
5787
5932
  "http.extraHeader": header
5788
5933
  }
5789
5934
  });
@@ -5865,8 +6010,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
5865
6010
  }
5866
6011
  async function createThreadWorktree(opts) {
5867
6012
  let branchName = `thread/${opts.slug}`;
5868
- const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
5869
- if ((0, import_node_fs16.existsSync)(worktreePath)) {
6013
+ const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
6014
+ if ((0, import_node_fs17.existsSync)(worktreePath)) {
5870
6015
  throw new Error(`Worktree already exists at ${worktreePath}`);
5871
6016
  }
5872
6017
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5901,13 +6046,14 @@ ${add.stdout}`;
5901
6046
  });
5902
6047
  branchName = added;
5903
6048
  await ensureGhPreferOrigin(worktreePath);
6049
+ await ensureWorktreeSideboardIgnored(worktreePath);
5904
6050
  return { branchName, worktreePath };
5905
6051
  }
5906
6052
  async function createExistingBranchWorktree(opts) {
5907
6053
  const branchName = opts.branchName.trim();
5908
6054
  if (!branchName) throw new Error("branch name required");
5909
- const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
5910
- if ((0, import_node_fs16.existsSync)(worktreePath)) {
6055
+ const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
6056
+ if ((0, import_node_fs17.existsSync)(worktreePath)) {
5911
6057
  throw new Error(`Worktree already exists at ${worktreePath}`);
5912
6058
  }
5913
6059
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5945,6 +6091,7 @@ async function createExistingBranchWorktree(opts) {
5945
6091
  await git(["checkout", "-B", branchName], worktreePath, { reject: false });
5946
6092
  }
5947
6093
  await ensureGhPreferOrigin(worktreePath);
6094
+ await ensureWorktreeSideboardIgnored(worktreePath);
5948
6095
  return { branchName, worktreePath };
5949
6096
  }
5950
6097
  async function removeWorktree(repoPath, worktreePath, opts) {
@@ -6033,7 +6180,9 @@ async function currentBranch(worktreePath) {
6033
6180
  async function commitAll(worktreePath, message) {
6034
6181
  const dirty = await isDirty(worktreePath);
6035
6182
  if (!dirty) return false;
6183
+ await ensureWorktreeSideboardIgnored(worktreePath);
6036
6184
  await git(["add", "-A"], worktreePath);
6185
+ await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
6037
6186
  await git(["commit", "-m", message], worktreePath);
6038
6187
  return true;
6039
6188
  }
@@ -6047,14 +6196,14 @@ async function pushBranch(worktreePath, branchName) {
6047
6196
  const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
6048
6197
  if (!slug || !token) {
6049
6198
  throw new Error(
6050
- sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
6199
+ sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
6051
6200
  );
6052
6201
  }
6202
+ const remoteUrl = await originRemoteUrl(worktreePath);
6053
6203
  const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
6054
6204
  reject: false,
6055
- env: { GIT_TERMINAL_PROMPT: "0" },
6205
+ env: githubHttpsRetryEnv(remoteUrl),
6056
6206
  config: {
6057
- "url.https://github.com/.insteadOf": "git@github.com:",
6058
6207
  "http.extraHeader": header
6059
6208
  }
6060
6209
  });
@@ -6184,6 +6333,32 @@ async function createOrUpdatePr(worktreePath, opts) {
6184
6333
  const repoArgs = ghRepoSelectArgs(slug);
6185
6334
  const headRef = ghHeadRef(slug, opts.head);
6186
6335
  const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
6336
+ const bodyText = clampGithubPrBody(opts.body ?? opts.title);
6337
+ const bodyFile = (0, import_node_path19.join)(
6338
+ (0, import_node_os6.tmpdir)(),
6339
+ `sideboard-pr-body-${process.pid}-${(0, import_node_crypto6.randomBytes)(6).toString("hex")}.md`
6340
+ );
6341
+ (0, import_node_fs17.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
6342
+ `, "utf8");
6343
+ const bodyArgs = ["--body-file", bodyFile];
6344
+ try {
6345
+ return await createOrUpdatePrWithBodyFile(worktreePath, {
6346
+ ...opts,
6347
+ slug,
6348
+ repoArgs,
6349
+ headRef,
6350
+ branchOnly,
6351
+ bodyArgs
6352
+ });
6353
+ } finally {
6354
+ try {
6355
+ (0, import_node_fs17.unlinkSync)(bodyFile);
6356
+ } catch {
6357
+ }
6358
+ }
6359
+ }
6360
+ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
6361
+ const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
6187
6362
  const existing = await gh(
6188
6363
  [...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
6189
6364
  worktreePath,
@@ -6199,8 +6374,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6199
6374
  branchOnly,
6200
6375
  "--title",
6201
6376
  opts.title,
6202
- "--body",
6203
- opts.body ?? opts.title
6377
+ ...bodyArgs
6204
6378
  ],
6205
6379
  worktreePath,
6206
6380
  { reject: false }
@@ -6215,8 +6389,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6215
6389
  "--web",
6216
6390
  "--title",
6217
6391
  opts.title,
6218
- "--body",
6219
- opts.body ?? opts.title,
6392
+ ...bodyArgs,
6220
6393
  "--base",
6221
6394
  opts.base,
6222
6395
  "--head",
@@ -6237,8 +6410,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6237
6410
  "create",
6238
6411
  "--title",
6239
6412
  opts.title,
6240
- "--body",
6241
- opts.body ?? opts.title,
6413
+ ...bodyArgs,
6242
6414
  "--base",
6243
6415
  opts.base,
6244
6416
  "--head",
@@ -6262,10 +6434,10 @@ function sameRepoPath(a, b) {
6262
6434
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
6263
6435
  }
6264
6436
  function listLocalThreadBranchSlugs(repoPath) {
6265
- const refsDir = (0, import_node_path18.join)(repoPath, ".git", "refs", "heads", "thread");
6266
- if (!(0, import_node_fs16.existsSync)(refsDir)) return [];
6437
+ const refsDir = (0, import_node_path19.join)(repoPath, ".git", "refs", "heads", "thread");
6438
+ if (!(0, import_node_fs17.existsSync)(refsDir)) return [];
6267
6439
  try {
6268
- return (0, import_node_fs16.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6440
+ return (0, import_node_fs17.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6269
6441
  } catch {
6270
6442
  return [];
6271
6443
  }
@@ -6273,8 +6445,8 @@ function listLocalThreadBranchSlugs(repoPath) {
6273
6445
  function collectTakenTeamSlugs(repoPath) {
6274
6446
  const taken = /* @__PURE__ */ new Set();
6275
6447
  const root = worktreesRoot(repoPath);
6276
- if ((0, import_node_fs16.existsSync)(root)) {
6277
- for (const entry of (0, import_node_fs16.readdirSync)(root, { withFileTypes: true })) {
6448
+ if ((0, import_node_fs17.existsSync)(root)) {
6449
+ for (const entry of (0, import_node_fs17.readdirSync)(root, { withFileTypes: true })) {
6278
6450
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
6279
6451
  taken.add(normalizeTakenSlug(entry.name));
6280
6452
  }
@@ -6295,23 +6467,26 @@ function allocateTeamSlug(repoPath) {
6295
6467
  const taken = collectTakenTeamSlugs(repoPath);
6296
6468
  for (let attempt = 0; attempt < 32; attempt++) {
6297
6469
  const team = allocateTeamName(taken);
6298
- const path2 = (0, import_node_path18.join)(worktreesRoot(repoPath), team.slug);
6299
- if (!(0, import_node_fs16.existsSync)(path2)) return team;
6470
+ const path2 = (0, import_node_path19.join)(worktreesRoot(repoPath), team.slug);
6471
+ if (!(0, import_node_fs17.existsSync)(path2)) return team;
6300
6472
  taken.add(team.slug);
6301
6473
  }
6302
6474
  throw new Error("No available soccer team worktree directories left");
6303
6475
  }
6304
- var import_node_fs16, import_node_path18;
6476
+ var import_node_crypto6, import_node_fs17, import_node_os6, import_node_path19;
6305
6477
  var init_worktree = __esm({
6306
6478
  "src/git/worktree.ts"() {
6307
6479
  "use strict";
6308
- import_node_fs16 = require("fs");
6309
- import_node_path18 = require("path");
6480
+ import_node_crypto6 = require("crypto");
6481
+ import_node_fs17 = require("fs");
6482
+ import_node_os6 = require("os");
6483
+ import_node_path19 = require("path");
6310
6484
  init_paths();
6311
6485
  init_thread_store();
6312
6486
  init_teams();
6313
6487
  init_worktree_labels();
6314
6488
  init_gh_errors();
6489
+ init_worktree_exclude();
6315
6490
  init_git_auth_mode();
6316
6491
  init_run();
6317
6492
  init_repo_git_lock();
@@ -6383,7 +6558,7 @@ function coordinatorTurnReminder(opts) {
6383
6558
  function ensureGlobalCoordinatorCwd(opts) {
6384
6559
  const dir = globalAgentCwd();
6385
6560
  try {
6386
- (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
6561
+ (0, import_node_fs18.mkdirSync)(dir, { recursive: true });
6387
6562
  } catch {
6388
6563
  return dir;
6389
6564
  }
@@ -6391,7 +6566,7 @@ function ensureGlobalCoordinatorCwd(opts) {
6391
6566
  let orchId = opts?.orchestratorThreadId?.trim() || "";
6392
6567
  if (!orchId) {
6393
6568
  try {
6394
- const existing = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), "utf8");
6569
+ const existing = (0, import_node_fs18.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
6395
6570
  const m = existing.match(
6396
6571
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
6397
6572
  );
@@ -6434,9 +6609,9 @@ function ensureGlobalCoordinatorCwd(opts) {
6434
6609
  "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."
6435
6610
  ].join("\n");
6436
6611
  try {
6437
- (0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(dir, "CLAUDE.md"), `${body}
6612
+ (0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
6438
6613
  `, "utf8");
6439
- (0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), `${body}
6614
+ (0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
6440
6615
  `, "utf8");
6441
6616
  } catch {
6442
6617
  }
@@ -6468,12 +6643,12 @@ function coordinatorSystemPrompt(opts) {
6468
6643
  formatWorkspaceInventory(opts.workspaces)
6469
6644
  ].join("\n");
6470
6645
  }
6471
- var import_node_fs17, import_node_path19, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6646
+ var import_node_fs18, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6472
6647
  var init_coordinator_prompt = __esm({
6473
6648
  "src/orchestrator/coordinator-prompt.ts"() {
6474
6649
  "use strict";
6475
- import_node_fs17 = require("fs");
6476
- import_node_path19 = require("path");
6650
+ import_node_fs18 = require("fs");
6651
+ import_node_path20 = require("path");
6477
6652
  init_worktree();
6478
6653
  init_app_settings();
6479
6654
  init_paths();
@@ -6483,8 +6658,8 @@ var init_coordinator_prompt = __esm({
6483
6658
  "Discover:",
6484
6659
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
6485
6660
  "- 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.",
6486
- "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues)",
6487
- "- 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.",
6661
+ "- 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.",
6662
+ "- 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.",
6488
6663
  "- 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).",
6489
6664
  "- 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",
6490
6665
  "- 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).",
@@ -6503,7 +6678,7 @@ var init_coordinator_prompt = __esm({
6503
6678
  "- 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.",
6504
6679
  "- 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.",
6505
6680
  "- 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)",
6506
- "- 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.",
6681
+ "- 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.",
6507
6682
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
6508
6683
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
6509
6684
  "Setup / run:",
@@ -6512,7 +6687,7 @@ var init_coordinator_prompt = __esm({
6512
6687
  "Inspect / review / PRs:",
6513
6688
  "- get_diff \u2014 compact diff summary",
6514
6689
  '- 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',
6515
- "- 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.",
6690
+ "- 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.",
6516
6691
  '- 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.',
6517
6692
  '- 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.',
6518
6693
  "Process guides:",
@@ -6826,13 +7001,13 @@ var init_api = __esm({
6826
7001
 
6827
7002
  // src/slack/reply-target.ts
6828
7003
  function storePath() {
6829
- return (0, import_node_path20.join)(appDataDir(), "slack-reply-to.json");
7004
+ return (0, import_node_path21.join)(appDataDir(), "slack-reply-to.json");
6830
7005
  }
6831
7006
  function readStore() {
6832
7007
  const path2 = storePath();
6833
- if (!(0, import_node_fs18.existsSync)(path2)) return {};
7008
+ if (!(0, import_node_fs19.existsSync)(path2)) return {};
6834
7009
  try {
6835
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
7010
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
6836
7011
  return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
6837
7012
  } catch {
6838
7013
  return {};
@@ -6847,12 +7022,12 @@ function setSlackReplyTarget(target) {
6847
7022
  function getSlackReplyTarget(threadId) {
6848
7023
  return readStore()[threadId] ?? null;
6849
7024
  }
6850
- var import_node_fs18, import_node_path20;
7025
+ var import_node_fs19, import_node_path21;
6851
7026
  var init_reply_target = __esm({
6852
7027
  "src/slack/reply-target.ts"() {
6853
7028
  "use strict";
6854
- import_node_fs18 = require("fs");
6855
- import_node_path20 = require("path");
7029
+ import_node_fs19 = require("fs");
7030
+ import_node_path21 = require("path");
6856
7031
  init_paths();
6857
7032
  init_private_file();
6858
7033
  init_secure_file();
@@ -6861,7 +7036,7 @@ var init_reply_target = __esm({
6861
7036
 
6862
7037
  // src/slack/workspaces.ts
6863
7038
  function storePath2() {
6864
- return (0, import_node_path21.join)(appDataDir(), "slack-workspaces.json");
7039
+ return (0, import_node_path22.join)(appDataDir(), "slack-workspaces.json");
6865
7040
  }
6866
7041
  function readStore2() {
6867
7042
  try {
@@ -6968,11 +7143,11 @@ function requireSlackWorkspace(teamId) {
6968
7143
  }
6969
7144
  return ws;
6970
7145
  }
6971
- var import_node_path21;
7146
+ var import_node_path22;
6972
7147
  var init_workspaces = __esm({
6973
7148
  "src/slack/workspaces.ts"() {
6974
7149
  "use strict";
6975
- import_node_path21 = require("path");
7150
+ import_node_path22 = require("path");
6976
7151
  init_paths();
6977
7152
  init_secure_file();
6978
7153
  init_api();
@@ -6981,7 +7156,7 @@ var init_workspaces = __esm({
6981
7156
 
6982
7157
  // src/slack/outbound-watch.ts
6983
7158
  function storePath3() {
6984
- return (0, import_node_path22.join)(appDataDir(), "slack-outbound-watch.json");
7159
+ return (0, import_node_path23.join)(appDataDir(), "slack-outbound-watch.json");
6985
7160
  }
6986
7161
  function watchId(teamId, channelId, ts) {
6987
7162
  return `${teamId}:${channelId}:${ts}`;
@@ -6994,9 +7169,9 @@ function tsNewer(a, b) {
6994
7169
  }
6995
7170
  function readStore3() {
6996
7171
  const path2 = storePath3();
6997
- if (!(0, import_node_fs19.existsSync)(path2)) return [];
7172
+ if (!(0, import_node_fs20.existsSync)(path2)) return [];
6998
7173
  try {
6999
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
7174
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
7000
7175
  return Array.isArray(parsed?.watches) ? parsed.watches : [];
7001
7176
  } catch {
7002
7177
  return [];
@@ -7318,12 +7493,12 @@ async function pollSlackOutboundWatches(opts) {
7318
7493
  }
7319
7494
  if (changed) writeStore2(watches);
7320
7495
  }
7321
- var import_node_fs19, import_node_path22, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache, continueOnReply;
7496
+ var import_node_fs20, import_node_path23, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache, continueOnReply;
7322
7497
  var init_outbound_watch = __esm({
7323
7498
  "src/slack/outbound-watch.ts"() {
7324
7499
  "use strict";
7325
- import_node_fs19 = require("fs");
7326
- import_node_path22 = require("path");
7500
+ import_node_fs20 = require("fs");
7501
+ import_node_path23 = require("path");
7327
7502
  init_paths();
7328
7503
  init_private_file();
7329
7504
  init_secure_file();
@@ -7467,7 +7642,7 @@ function looksLikeRetryableRunnerCrash(text5) {
7467
7642
  const lower = text5.trim().toLowerCase();
7468
7643
  if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
7469
7644
  if (!lower) return true;
7470
- return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
7645
+ return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|network request failed|cursor startup failed:.+\(retryable\)|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
7471
7646
  lower
7472
7647
  );
7473
7648
  }
@@ -7535,6 +7710,9 @@ function humanizeAgentFailDetail(detail) {
7535
7710
  if (/connection stalled/.test(lower)) {
7536
7711
  return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
7537
7712
  }
7713
+ if (/network request failed|cursor startup failed:.+\(retryable\)/.test(lower)) {
7714
+ return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (a transient Cursor SDK network error).`;
7715
+ }
7538
7716
  return raw;
7539
7717
  }
7540
7718
  function turnFailChatText(opts) {
@@ -7604,32 +7782,32 @@ var init_error_detail = __esm({
7604
7782
  function brightsyConfigPath() {
7605
7783
  const override = process.env.BRIGHTSY_CONFIG?.trim();
7606
7784
  if (override) return override;
7607
- return (0, import_node_path23.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
7785
+ return (0, import_node_path24.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
7608
7786
  }
7609
7787
  function loadBrightsyConfig() {
7610
7788
  const path2 = brightsyConfigPath();
7611
- if (!(0, import_node_fs20.existsSync)(path2)) {
7789
+ if (!(0, import_node_fs21.existsSync)(path2)) {
7612
7790
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
7613
7791
  }
7614
- const raw = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
7792
+ const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
7615
7793
  if (!raw.access_token || !raw.account_id) {
7616
7794
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
7617
7795
  }
7618
7796
  return raw;
7619
7797
  }
7620
7798
  function saveBrightsyConfig(cfg) {
7621
- (0, import_node_fs20.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7799
+ (0, import_node_fs21.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7622
7800
  `, {
7623
7801
  mode: 384
7624
7802
  });
7625
7803
  }
7626
- var import_node_fs20, import_node_os6, import_node_path23;
7804
+ var import_node_fs21, import_node_os7, import_node_path24;
7627
7805
  var init_config = __esm({
7628
7806
  "src/brightsy/config.ts"() {
7629
7807
  "use strict";
7630
- import_node_fs20 = require("fs");
7631
- import_node_os6 = require("os");
7632
- import_node_path23 = require("path");
7808
+ import_node_fs21 = require("fs");
7809
+ import_node_os7 = require("os");
7810
+ import_node_path24 = require("path");
7633
7811
  }
7634
7812
  });
7635
7813
 
@@ -7847,22 +8025,22 @@ __export(connected_teams_exports, {
7847
8025
  listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
7848
8026
  });
7849
8027
  function storePath4() {
7850
- return (0, import_node_path24.join)(appDataDir(), "brightsy-teams.json");
8028
+ return (0, import_node_path25.join)(appDataDir(), "brightsy-teams.json");
7851
8029
  }
7852
8030
  function readStore4() {
7853
8031
  const path2 = storePath4();
7854
- if (!(0, import_node_fs21.existsSync)(path2)) return [];
8032
+ if (!(0, import_node_fs22.existsSync)(path2)) return [];
7855
8033
  try {
7856
- const parsed = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
8034
+ const parsed = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
7857
8035
  return Array.isArray(parsed.teams) ? parsed.teams : [];
7858
8036
  } catch {
7859
8037
  return [];
7860
8038
  }
7861
8039
  }
7862
8040
  function writeStore3(teams) {
7863
- (0, import_node_fs21.mkdirSync)(appDataDir(), { recursive: true });
8041
+ (0, import_node_fs22.mkdirSync)(appDataDir(), { recursive: true });
7864
8042
  const path2 = storePath4();
7865
- (0, import_node_fs21.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
8043
+ (0, import_node_fs22.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
7866
8044
  `, {
7867
8045
  mode: 384
7868
8046
  });
@@ -8018,12 +8196,12 @@ function brightsyMcpServerName(slug) {
8018
8196
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
8019
8197
  return `brightsy_${cleaned || "team"}`;
8020
8198
  }
8021
- var import_node_fs21, import_node_path24;
8199
+ var import_node_fs22, import_node_path25;
8022
8200
  var init_connected_teams = __esm({
8023
8201
  "src/brightsy/connected-teams.ts"() {
8024
8202
  "use strict";
8025
- import_node_fs21 = require("fs");
8026
- import_node_path24 = require("path");
8203
+ import_node_fs22 = require("fs");
8204
+ import_node_path25 = require("path");
8027
8205
  init_paths();
8028
8206
  init_accounts();
8029
8207
  init_config();
@@ -8442,11 +8620,11 @@ async function syncCliForTarget(accountId) {
8442
8620
  }
8443
8621
  applyConnectedTeamToCli(team);
8444
8622
  }
8445
- var import_node_fs22, brightsyAdapter;
8623
+ var import_node_fs23, brightsyAdapter;
8446
8624
  var init_brightsy = __esm({
8447
8625
  "src/agents/brightsy.ts"() {
8448
8626
  "use strict";
8449
- import_node_fs22 = require("fs");
8627
+ import_node_fs23 = require("fs");
8450
8628
  init_run();
8451
8629
  init_connected_teams();
8452
8630
  init_config();
@@ -8461,7 +8639,7 @@ var init_brightsy = __esm({
8461
8639
  async detect() {
8462
8640
  const brightsy = resolveAgentExecutable("brightsy");
8463
8641
  if (brightsy !== "brightsy") {
8464
- if (!(0, import_node_fs22.existsSync)(brightsy)) {
8642
+ if (!(0, import_node_fs23.existsSync)(brightsy)) {
8465
8643
  return {
8466
8644
  agent: "brightsy",
8467
8645
  installed: false,
@@ -8728,6 +8906,13 @@ function isSubagentToolName(name) {
8728
8906
  if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
8729
8907
  return /connectedAgentRequest/i.test(n);
8730
8908
  }
8909
+ function isInternalAgentStatusText(text5) {
8910
+ const t = text5.trim();
8911
+ if (!t) return false;
8912
+ if (/waiting for gate to pass/i.test(t)) return true;
8913
+ if (/^agent is running\b/i.test(t) && t.length < 160) return true;
8914
+ return false;
8915
+ }
8731
8916
  function isPollWrapperToolName(name) {
8732
8917
  const n = (name ?? "").replace(/[_-]/g, "");
8733
8918
  return /^(taskoutput|taskstop|sleep)$/i.test(n);
@@ -8735,7 +8920,10 @@ function isPollWrapperToolName(name) {
8735
8920
  function lastTextPart(parts, type) {
8736
8921
  for (let i = parts.length - 1; i >= 0; i--) {
8737
8922
  const p = parts[i];
8738
- if (p.type === type && p.text.trim()) return p.text.trim();
8923
+ if (p.type !== type) continue;
8924
+ const text5 = p.text.trim();
8925
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
8926
+ return text5;
8739
8927
  }
8740
8928
  return "";
8741
8929
  }
@@ -9151,43 +9339,43 @@ function electronResourcesPath() {
9151
9339
  function packagedCursorRuntimeDir() {
9152
9340
  const resources = electronResourcesPath();
9153
9341
  if (!resources) return null;
9154
- const dir = (0, import_node_path25.join)(resources, "cursor-runtime");
9155
- if (!(0, import_node_fs23.existsSync)((0, import_node_path25.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
9342
+ const dir = (0, import_node_path26.join)(resources, "cursor-runtime");
9343
+ if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
9156
9344
  return dir;
9157
9345
  }
9158
9346
  function packagedCursorRunnerPath() {
9159
9347
  const dir = packagedCursorRuntimeDir();
9160
- return dir ? (0, import_node_path25.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
9348
+ return dir ? (0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
9161
9349
  }
9162
9350
  function packagedMcpDir() {
9163
9351
  const resources = electronResourcesPath();
9164
9352
  if (!resources) return null;
9165
- const dir = (0, import_node_path25.join)(resources, "sideboard-mcp");
9166
- if (!(0, import_node_fs23.existsSync)((0, import_node_path25.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
9353
+ const dir = (0, import_node_path26.join)(resources, "sideboard-mcp");
9354
+ if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
9167
9355
  return dir;
9168
9356
  }
9169
9357
  function packagedMcpStdioPath() {
9170
9358
  const dir = packagedMcpDir();
9171
- return dir ? (0, import_node_path25.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
9359
+ return dir ? (0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
9172
9360
  }
9173
9361
  function packagedBundledNodePath() {
9174
9362
  const resources = electronResourcesPath();
9175
9363
  if (!resources) return null;
9176
- const bin = (0, import_node_path25.join)(resources, "node", "bin", "node");
9177
- if (!(0, import_node_fs23.existsSync)(bin)) return null;
9364
+ const bin = (0, import_node_path26.join)(resources, "node", "bin", "node");
9365
+ if (!(0, import_node_fs24.existsSync)(bin)) return null;
9178
9366
  return bin;
9179
9367
  }
9180
9368
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
9181
9369
  const dir = packagedCursorRuntimeDir();
9182
9370
  if (!dir) return null;
9183
- return (0, import_node_path25.join)(dir, "node_modules", platformPkg, "bin", binName);
9371
+ return (0, import_node_path26.join)(dir, "node_modules", platformPkg, "bin", binName);
9184
9372
  }
9185
- var import_node_fs23, import_node_path25;
9373
+ var import_node_fs24, import_node_path26;
9186
9374
  var init_packaged_runtime = __esm({
9187
9375
  "src/agents/packaged-runtime.ts"() {
9188
9376
  "use strict";
9189
- import_node_fs23 = require("fs");
9190
- import_node_path25 = require("path");
9377
+ import_node_fs24 = require("fs");
9378
+ import_node_path26 = require("path");
9191
9379
  }
9192
9380
  });
9193
9381
 
@@ -9221,7 +9409,7 @@ function unpackedAsarPath(filePath) {
9221
9409
  if (!isAsarPath(filePath)) return null;
9222
9410
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
9223
9411
  if (unpacked === filePath) return null;
9224
- return (0, import_node_fs24.existsSync)(unpacked) ? unpacked : null;
9412
+ return (0, import_node_fs25.existsSync)(unpacked) ? unpacked : null;
9225
9413
  }
9226
9414
  function nodeReadableScriptPath(scriptPath) {
9227
9415
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -9261,37 +9449,37 @@ function pickPreferredNode(candidates) {
9261
9449
  return best;
9262
9450
  }
9263
9451
  function versionDirNodeBins(root, toBin) {
9264
- if (!(0, import_node_fs24.existsSync)(root)) return [];
9452
+ if (!(0, import_node_fs25.existsSync)(root)) return [];
9265
9453
  try {
9266
- return (0, import_node_fs24.readdirSync)(root).map(toBin);
9454
+ return (0, import_node_fs25.readdirSync)(root).map(toBin);
9267
9455
  } catch {
9268
9456
  return [];
9269
9457
  }
9270
9458
  }
9271
- function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
9459
+ function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
9272
9460
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
9273
- (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path26.join)(prefix, "opt", `node@${major}`, "bin", "node"))
9461
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path27.join)(prefix, "opt", `node@${major}`, "bin", "node"))
9274
9462
  );
9275
9463
  return [
9276
9464
  ...kegs,
9277
9465
  "/opt/homebrew/bin/node",
9278
9466
  "/usr/local/bin/node",
9279
- (0, import_node_path26.join)(home, ".local/share/fnm/aliases/default/bin/node"),
9280
- (0, import_node_path26.join)(home, ".nvm/current/bin/node"),
9281
- (0, import_node_path26.join)(home, ".volta/bin/node"),
9282
- (0, import_node_path26.join)(home, ".asdf/shims/node"),
9283
- (0, import_node_path26.join)(home, ".local/share/mise/shims/node"),
9467
+ (0, import_node_path27.join)(home, ".local/share/fnm/aliases/default/bin/node"),
9468
+ (0, import_node_path27.join)(home, ".nvm/current/bin/node"),
9469
+ (0, import_node_path27.join)(home, ".volta/bin/node"),
9470
+ (0, import_node_path27.join)(home, ".asdf/shims/node"),
9471
+ (0, import_node_path27.join)(home, ".local/share/mise/shims/node"),
9284
9472
  ...versionDirNodeBins(
9285
- (0, import_node_path26.join)(home, ".nvm", "versions", "node"),
9286
- (name) => (0, import_node_path26.join)(home, ".nvm", "versions", "node", name, "bin", "node")
9473
+ (0, import_node_path27.join)(home, ".nvm", "versions", "node"),
9474
+ (name) => (0, import_node_path27.join)(home, ".nvm", "versions", "node", name, "bin", "node")
9287
9475
  ),
9288
9476
  ...versionDirNodeBins(
9289
- (0, import_node_path26.join)(home, ".local/share/fnm", "node-versions"),
9290
- (name) => (0, import_node_path26.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
9477
+ (0, import_node_path27.join)(home, ".local/share/fnm", "node-versions"),
9478
+ (name) => (0, import_node_path27.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
9291
9479
  ),
9292
9480
  ...versionDirNodeBins(
9293
- (0, import_node_path26.join)(home, ".volta", "tools", "image", "node"),
9294
- (name) => (0, import_node_path26.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
9481
+ (0, import_node_path27.join)(home, ".volta", "tools", "image", "node"),
9482
+ (name) => (0, import_node_path27.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
9295
9483
  )
9296
9484
  ];
9297
9485
  }
@@ -9300,10 +9488,10 @@ function uniqueExistingNodeBins(paths) {
9300
9488
  const out = [];
9301
9489
  for (const raw of paths) {
9302
9490
  const p = raw.trim();
9303
- if (!p || !(0, import_node_fs24.existsSync)(p) || isElectronLikeCommand(p)) continue;
9491
+ if (!p || !(0, import_node_fs25.existsSync)(p) || isElectronLikeCommand(p)) continue;
9304
9492
  let key = p;
9305
9493
  try {
9306
- key = (0, import_node_fs24.realpathSync)(p);
9494
+ key = (0, import_node_fs25.realpathSync)(p);
9307
9495
  } catch {
9308
9496
  continue;
9309
9497
  }
@@ -9383,13 +9571,13 @@ async function resolveNodeLaunch(scriptPath) {
9383
9571
  env: { ELECTRON_RUN_AS_NODE: "1" }
9384
9572
  };
9385
9573
  }
9386
- var import_node_fs24, import_node_os7, import_node_path26, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
9574
+ var import_node_fs25, import_node_os8, import_node_path27, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
9387
9575
  var init_node_launch = __esm({
9388
9576
  "src/agents/node-launch.ts"() {
9389
9577
  "use strict";
9390
- import_node_fs24 = require("fs");
9391
- import_node_os7 = require("os");
9392
- import_node_path26 = require("path");
9578
+ import_node_fs25 = require("fs");
9579
+ import_node_os8 = require("os");
9580
+ import_node_path27 = require("path");
9393
9581
  init_nested_electron_env();
9394
9582
  init_run();
9395
9583
  init_packaged_runtime();
@@ -9483,37 +9671,37 @@ function corePackageDir() {
9483
9671
  try {
9484
9672
  const url = import_meta.url;
9485
9673
  if (typeof url === "string" && url.length > 0) {
9486
- return (0, import_node_path27.dirname)((0, import_node_url.fileURLToPath)(url));
9674
+ return (0, import_node_path28.dirname)((0, import_node_url.fileURLToPath)(url));
9487
9675
  }
9488
9676
  } catch {
9489
9677
  }
9490
9678
  try {
9491
- const req = (0, import_node_module.createRequire)((0, import_node_path27.join)(process.cwd(), "package.json"));
9492
- return (0, import_node_path27.dirname)(req.resolve("@sideboard-ai/core"));
9679
+ const req = (0, import_node_module.createRequire)((0, import_node_path28.join)(process.cwd(), "package.json"));
9680
+ return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
9493
9681
  } catch {
9494
9682
  return process.cwd();
9495
9683
  }
9496
9684
  }
9497
9685
  function findSideboardMcpJsEntry() {
9498
9686
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
9499
- if (override && (0, import_node_fs25.existsSync)(override)) return override;
9687
+ if (override && (0, import_node_fs26.existsSync)(override)) return override;
9500
9688
  const packaged = packagedMcpStdioPath();
9501
9689
  if (packaged) return packaged;
9502
9690
  let dir = corePackageDir();
9503
9691
  for (let i = 0; i < 10; i++) {
9504
9692
  const candidates = [
9505
- (0, import_node_path27.join)(dir, "mcp/run-stdio.js"),
9506
- (0, import_node_path27.join)(dir, "mcp/run-stdio.cjs"),
9507
- (0, import_node_path27.join)(dir, "dist/mcp/run-stdio.js"),
9508
- (0, import_node_path27.join)(dir, "dist/mcp/run-stdio.cjs"),
9509
- (0, import_node_path27.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
9510
- (0, import_node_path27.join)(dir, "packages/cli/dist/index.js"),
9511
- (0, import_node_path27.join)(dir, "cli/dist/index.js")
9693
+ (0, import_node_path28.join)(dir, "mcp/run-stdio.js"),
9694
+ (0, import_node_path28.join)(dir, "mcp/run-stdio.cjs"),
9695
+ (0, import_node_path28.join)(dir, "dist/mcp/run-stdio.js"),
9696
+ (0, import_node_path28.join)(dir, "dist/mcp/run-stdio.cjs"),
9697
+ (0, import_node_path28.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
9698
+ (0, import_node_path28.join)(dir, "packages/cli/dist/index.js"),
9699
+ (0, import_node_path28.join)(dir, "cli/dist/index.js")
9512
9700
  ];
9513
9701
  for (const p of candidates) {
9514
- if ((0, import_node_fs25.existsSync)(p) && !isAsarPath(p)) return p;
9702
+ if ((0, import_node_fs26.existsSync)(p) && !isAsarPath(p)) return p;
9515
9703
  }
9516
- const parent = (0, import_node_path27.dirname)(dir);
9704
+ const parent = (0, import_node_path28.dirname)(dir);
9517
9705
  if (parent === dir) break;
9518
9706
  dir = parent;
9519
9707
  }
@@ -9655,22 +9843,22 @@ function writeMcpServersConfig(servers) {
9655
9843
  ...env ? { env } : {}
9656
9844
  };
9657
9845
  }
9658
- const dir = (0, import_node_fs25.mkdtempSync)((0, import_node_path27.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
9659
- const cfgPath = (0, import_node_path27.join)(dir, "mcp.json");
9660
- (0, import_node_fs25.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
9846
+ const dir = (0, import_node_fs26.mkdtempSync)((0, import_node_path28.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
9847
+ const cfgPath = (0, import_node_path28.join)(dir, "mcp.json");
9848
+ (0, import_node_fs26.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
9661
9849
  return cfgPath;
9662
9850
  }
9663
9851
  async function writeInjectedMcpConfig(opts) {
9664
9852
  return writeMcpServersConfig(await buildInjectedMcpServers(opts));
9665
9853
  }
9666
- var import_node_fs25, import_node_module, import_node_os8, import_node_path27, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
9854
+ var import_node_fs26, import_node_module, import_node_os9, import_node_path28, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
9667
9855
  var init_injected_mcp = __esm({
9668
9856
  "src/agents/injected-mcp.ts"() {
9669
9857
  "use strict";
9670
- import_node_fs25 = require("fs");
9858
+ import_node_fs26 = require("fs");
9671
9859
  import_node_module = require("module");
9672
- import_node_os8 = require("os");
9673
- import_node_path27 = require("path");
9860
+ import_node_os9 = require("os");
9861
+ import_node_path28 = require("path");
9674
9862
  import_node_url = require("url");
9675
9863
  init_run();
9676
9864
  init_config();
@@ -10013,11 +10201,11 @@ function parseIssuesJson(raw) {
10013
10201
  }
10014
10202
  return [];
10015
10203
  }
10016
- var import_node_fs26, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
10204
+ var import_node_fs27, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
10017
10205
  var init_claude = __esm({
10018
10206
  "src/agents/claude.ts"() {
10019
10207
  "use strict";
10020
- import_node_fs26 = require("fs");
10208
+ import_node_fs27 = require("fs");
10021
10209
  init_run();
10022
10210
  init_app_settings();
10023
10211
  init_claude_mcp();
@@ -10057,7 +10245,7 @@ var init_claude = __esm({
10057
10245
  async detect() {
10058
10246
  const claude = resolveClaudeExecutable();
10059
10247
  if (claude !== "claude") {
10060
- if (!(0, import_node_fs26.existsSync)(claude)) {
10248
+ if (!(0, import_node_fs27.existsSync)(claude)) {
10061
10249
  return {
10062
10250
  agent: "claude",
10063
10251
  installed: false,
@@ -10312,7 +10500,7 @@ async function listCodexModels() {
10312
10500
  if (codex === "codex") {
10313
10501
  const which = await run("which", ["codex"], { reject: false });
10314
10502
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
10315
- } else if (!(0, import_node_fs27.existsSync)(codex)) {
10503
+ } else if (!(0, import_node_fs28.existsSync)(codex)) {
10316
10504
  return FALLBACK_CODEX_MODELS;
10317
10505
  }
10318
10506
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -10347,12 +10535,12 @@ function usageFromCodex(usage) {
10347
10535
  }
10348
10536
  function codexConfigHasNetworkAccess() {
10349
10537
  const candidates = [
10350
- (0, import_node_path28.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
10351
- (0, import_node_path28.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
10538
+ (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "config.toml"),
10539
+ (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".config", "codex", "config.toml")
10352
10540
  ];
10353
10541
  for (const path2 of candidates) {
10354
- if (!(0, import_node_fs27.existsSync)(path2)) continue;
10355
- const text5 = (0, import_node_fs27.readFileSync)(path2, "utf8");
10542
+ if (!(0, import_node_fs28.existsSync)(path2)) continue;
10543
+ const text5 = (0, import_node_fs28.readFileSync)(path2, "utf8");
10356
10544
  if (/network_access\s*=\s*true/.test(text5)) return true;
10357
10545
  }
10358
10546
  return false;
@@ -10384,21 +10572,21 @@ function asRecord2(value) {
10384
10572
  return void 0;
10385
10573
  }
10386
10574
  function codexLooksAuthenticated() {
10387
- const authPath = (0, import_node_path28.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
10388
- if (!(0, import_node_fs27.existsSync)(authPath)) return false;
10575
+ const authPath = (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "auth.json");
10576
+ if (!(0, import_node_fs28.existsSync)(authPath)) return false;
10389
10577
  try {
10390
- return (0, import_node_fs27.statSync)(authPath).size > 2;
10578
+ return (0, import_node_fs28.statSync)(authPath).size > 2;
10391
10579
  } catch {
10392
10580
  return false;
10393
10581
  }
10394
10582
  }
10395
- var import_node_fs27, import_node_os9, import_node_path28, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
10583
+ var import_node_fs28, import_node_os10, import_node_path29, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
10396
10584
  var init_codex = __esm({
10397
10585
  "src/agents/codex.ts"() {
10398
10586
  "use strict";
10399
- import_node_fs27 = require("fs");
10400
- import_node_os9 = require("os");
10401
- import_node_path28 = require("path");
10587
+ import_node_fs28 = require("fs");
10588
+ import_node_os10 = require("os");
10589
+ import_node_path29 = require("path");
10402
10590
  init_run();
10403
10591
  init_app_settings();
10404
10592
  init_global_workspace();
@@ -10423,7 +10611,7 @@ var init_codex = __esm({
10423
10611
  async detect() {
10424
10612
  const codex = resolveAgentExecutable("codex");
10425
10613
  if (codex !== "codex") {
10426
- if (!(0, import_node_fs27.existsSync)(codex)) {
10614
+ if (!(0, import_node_fs28.existsSync)(codex)) {
10427
10615
  return {
10428
10616
  agent: "codex",
10429
10617
  installed: false,
@@ -10910,21 +11098,21 @@ function platformRipgrepPackage() {
10910
11098
  }
10911
11099
  function usableRipgrepPath(candidate) {
10912
11100
  const raw = candidate?.trim();
10913
- if (!raw || !(0, import_node_path29.isAbsolute)(raw)) return null;
11101
+ if (!raw || !(0, import_node_path30.isAbsolute)(raw)) return null;
10914
11102
  const readable = nodeReadableScriptPath(raw);
10915
- if (!(0, import_node_fs28.existsSync)(readable) || isAsarPath(readable)) return null;
11103
+ if (!(0, import_node_fs29.existsSync)(readable) || isAsarPath(readable)) return null;
10916
11104
  return readable;
10917
11105
  }
10918
11106
  function walkForBundledRipgrep(startFile) {
10919
11107
  if (!startFile) return null;
10920
11108
  const pkg = platformRipgrepPackage();
10921
11109
  const name = rgBinaryName();
10922
- let dir = (0, import_node_path29.dirname)((0, import_node_path29.resolve)(startFile));
10923
- const root = (0, import_node_path29.parse)(dir).root;
11110
+ let dir = (0, import_node_path30.dirname)((0, import_node_path30.resolve)(startFile));
11111
+ const root = (0, import_node_path30.parse)(dir).root;
10924
11112
  while (dir !== root) {
10925
- const hit = usableRipgrepPath((0, import_node_path29.join)(dir, "node_modules", pkg, "bin", name));
11113
+ const hit = usableRipgrepPath((0, import_node_path30.join)(dir, "node_modules", pkg, "bin", name));
10926
11114
  if (hit) return hit;
10927
- const next = (0, import_node_path29.dirname)(dir);
11115
+ const next = (0, import_node_path30.dirname)(dir);
10928
11116
  if (next === dir) break;
10929
11117
  dir = next;
10930
11118
  }
@@ -10934,7 +11122,7 @@ function requireResolveBundledRipgrep(fromFile) {
10934
11122
  try {
10935
11123
  const req = (0, import_node_module2.createRequire)(fromFile);
10936
11124
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
10937
- return usableRipgrepPath((0, import_node_path29.join)((0, import_node_path29.dirname)(pkgJson), "bin", rgBinaryName()));
11125
+ return usableRipgrepPath((0, import_node_path30.join)((0, import_node_path30.dirname)(pkgJson), "bin", rgBinaryName()));
10938
11126
  } catch {
10939
11127
  return null;
10940
11128
  }
@@ -10956,13 +11144,13 @@ function cursorRipgrepEnv(opts) {
10956
11144
  const path2 = resolveCursorRipgrepPath(opts);
10957
11145
  return path2 ? { [RIPGREP_ENV]: path2 } : {};
10958
11146
  }
10959
- var import_node_fs28, import_node_module2, import_node_path29, RIPGREP_ENV;
11147
+ var import_node_fs29, import_node_module2, import_node_path30, RIPGREP_ENV;
10960
11148
  var init_cursor_ripgrep = __esm({
10961
11149
  "src/agents/cursor-ripgrep.ts"() {
10962
11150
  "use strict";
10963
- import_node_fs28 = require("fs");
11151
+ import_node_fs29 = require("fs");
10964
11152
  import_node_module2 = require("module");
10965
- import_node_path29 = require("path");
11153
+ import_node_path30 = require("path");
10966
11154
  init_node_launch();
10967
11155
  init_packaged_runtime();
10968
11156
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -11008,11 +11196,11 @@ function entryDir() {
11008
11196
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
11009
11197
  if (cjsDir) return cjsDir;
11010
11198
  try {
11011
- return (0, import_node_path30.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
11199
+ return (0, import_node_path31.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
11012
11200
  } catch {
11013
11201
  try {
11014
11202
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
11015
- return (0, import_node_path30.dirname)(req.resolve("@sideboard-ai/core"));
11203
+ return (0, import_node_path31.dirname)(req.resolve("@sideboard-ai/core"));
11016
11204
  } catch {
11017
11205
  return process.cwd();
11018
11206
  }
@@ -11023,27 +11211,27 @@ function cursorRunnerPath() {
11023
11211
  if (packaged) return packaged;
11024
11212
  const root = entryDir();
11025
11213
  const candidates = [
11026
- (0, import_node_path30.join)(root, "agents", "cursor-runner.js"),
11027
- (0, import_node_path30.join)(root, "agents", "cursor-runner.cjs"),
11214
+ (0, import_node_path31.join)(root, "agents", "cursor-runner.js"),
11215
+ (0, import_node_path31.join)(root, "agents", "cursor-runner.cjs"),
11028
11216
  // If somehow resolved from package root instead of dist/
11029
- (0, import_node_path30.join)(root, "dist", "agents", "cursor-runner.js"),
11030
- (0, import_node_path30.join)(root, "dist", "agents", "cursor-runner.cjs"),
11217
+ (0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.js"),
11218
+ (0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.cjs"),
11031
11219
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
11032
- (0, import_node_path30.join)(root, "cursor-runner.ts"),
11033
- (0, import_node_path30.join)(root, "src", "agents", "cursor-runner.ts")
11220
+ (0, import_node_path31.join)(root, "cursor-runner.ts"),
11221
+ (0, import_node_path31.join)(root, "src", "agents", "cursor-runner.ts")
11034
11222
  ];
11035
11223
  for (const candidate of candidates) {
11036
- if ((0, import_node_fs29.existsSync)(candidate)) return candidate;
11224
+ if ((0, import_node_fs30.existsSync)(candidate)) return candidate;
11037
11225
  }
11038
11226
  return candidates[0];
11039
11227
  }
11040
- var import_node_fs29, import_node_module3, import_node_path30, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
11228
+ var import_node_fs30, import_node_module3, import_node_path31, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
11041
11229
  var init_cursor = __esm({
11042
11230
  "src/agents/cursor.ts"() {
11043
11231
  "use strict";
11044
- import_node_fs29 = require("fs");
11232
+ import_node_fs30 = require("fs");
11045
11233
  import_node_module3 = require("module");
11046
- import_node_path30 = require("path");
11234
+ import_node_path31 = require("path");
11047
11235
  import_node_url2 = require("url");
11048
11236
  import_sdk = require("@cursor/sdk");
11049
11237
  init_run();
@@ -11194,7 +11382,7 @@ async function listOpencodeModels() {
11194
11382
  if (opencode === "opencode") {
11195
11383
  const which = await run("which", ["opencode"], { reject: false });
11196
11384
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
11197
- } else if (!(0, import_node_fs30.existsSync)(opencode)) {
11385
+ } else if (!(0, import_node_fs31.existsSync)(opencode)) {
11198
11386
  return FALLBACK_OPENCODE_MODELS;
11199
11387
  }
11200
11388
  const listed = await run(opencode, ["models"], { reject: false });
@@ -11224,11 +11412,11 @@ function usageFromOpencode(tokens) {
11224
11412
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
11225
11413
  };
11226
11414
  }
11227
- var import_node_fs30, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
11415
+ var import_node_fs31, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
11228
11416
  var init_opencode = __esm({
11229
11417
  "src/agents/opencode.ts"() {
11230
11418
  "use strict";
11231
- import_node_fs30 = require("fs");
11419
+ import_node_fs31 = require("fs");
11232
11420
  init_run();
11233
11421
  init_app_settings();
11234
11422
  init_global_workspace();
@@ -11255,7 +11443,7 @@ var init_opencode = __esm({
11255
11443
  async detect() {
11256
11444
  const opencode = resolveAgentExecutable("opencode");
11257
11445
  if (opencode !== "opencode") {
11258
- if (!(0, import_node_fs30.existsSync)(opencode)) {
11446
+ if (!(0, import_node_fs31.existsSync)(opencode)) {
11259
11447
  return {
11260
11448
  agent: "opencode",
11261
11449
  installed: false,
@@ -12881,7 +13069,7 @@ function forkMessageSlice(from, throughIndex) {
12881
13069
  function buildForkTranscriptAttachment(baseTitle, messages) {
12882
13070
  const title = baseTitle || "Chat";
12883
13071
  return {
12884
- id: (0, import_node_crypto6.randomUUID)(),
13072
+ id: (0, import_node_crypto7.randomUUID)(),
12885
13073
  name: `Transcript of ${title}.md`,
12886
13074
  kind: "transcript",
12887
13075
  content: formatTranscriptMarkdown(title, messages)
@@ -12938,11 +13126,11 @@ function forkChatTab(input) {
12938
13126
  }
12939
13127
  return tab;
12940
13128
  }
12941
- var import_node_crypto6;
13129
+ var import_node_crypto7;
12942
13130
  var init_chat_tabs = __esm({
12943
13131
  "src/threads/chat-tabs.ts"() {
12944
13132
  "use strict";
12945
- import_node_crypto6 = require("crypto");
13133
+ import_node_crypto7 = require("crypto");
12946
13134
  init_context_compact();
12947
13135
  init_teams();
12948
13136
  init_worktree_labels();
@@ -13112,21 +13300,21 @@ function shouldRefreshReviewRequestTemplate(content) {
13112
13300
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
13113
13301
  }
13114
13302
  function readTextIfPresent(abs) {
13115
- if (!(0, import_node_fs31.existsSync)(abs)) return null;
13303
+ if (!(0, import_node_fs32.existsSync)(abs)) return null;
13116
13304
  try {
13117
- const content = (0, import_node_fs31.readFileSync)(abs, "utf8");
13305
+ const content = (0, import_node_fs32.readFileSync)(abs, "utf8");
13118
13306
  return content.trim() ? content : null;
13119
13307
  } catch {
13120
13308
  return null;
13121
13309
  }
13122
13310
  }
13123
13311
  function readLocalGuidelines(worktreePath) {
13124
- const localAbs = (0, import_node_path31.join)(worktreePath, REVIEW_REQUEST_PATH);
13312
+ const localAbs = (0, import_node_path32.join)(worktreePath, REVIEW_REQUEST_PATH);
13125
13313
  const localContent = readTextIfPresent(localAbs);
13126
13314
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
13127
13315
  return { path: REVIEW_REQUEST_PATH, content: localContent };
13128
13316
  }
13129
- const legacyAbs = (0, import_node_path31.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
13317
+ const legacyAbs = (0, import_node_path32.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
13130
13318
  const legacyContent = readTextIfPresent(legacyAbs);
13131
13319
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
13132
13320
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -13142,20 +13330,20 @@ function skillGuidelines(content, source) {
13142
13330
  };
13143
13331
  }
13144
13332
  function ensureReviewSkillFile(worktreePath) {
13145
- const abs = (0, import_node_path31.join)(worktreePath, REVIEW_SKILL_PATH);
13333
+ const abs = (0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH);
13146
13334
  const existing = readTextIfPresent(abs);
13147
13335
  if (existing) {
13148
13336
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
13149
13337
  }
13150
- const fromRepo = readTextIfPresent((0, import_node_path31.join)(worktreePath, REPO_REVIEW_PATH));
13338
+ const fromRepo = readTextIfPresent((0, import_node_path32.join)(worktreePath, REPO_REVIEW_PATH));
13151
13339
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
13152
13340
  const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
13153
- (0, import_node_fs31.mkdirSync)((0, import_node_path31.dirname)(abs), { recursive: true });
13154
- (0, import_node_fs31.writeFileSync)(abs, content, "utf8");
13341
+ (0, import_node_fs32.mkdirSync)((0, import_node_path32.dirname)(abs), { recursive: true });
13342
+ (0, import_node_fs32.writeFileSync)(abs, content, "utf8");
13155
13343
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
13156
13344
  }
13157
13345
  function resolveReviewGuidelines(worktreePath) {
13158
- const skillContent = readTextIfPresent((0, import_node_path31.join)(worktreePath, REVIEW_SKILL_PATH));
13346
+ const skillContent = readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH));
13159
13347
  if (skillContent) return skillGuidelines(skillContent, "skill");
13160
13348
  const local = readLocalGuidelines(worktreePath);
13161
13349
  if (local) {
@@ -13177,7 +13365,7 @@ function buildReviewRequestAttachment(content, opts) {
13177
13365
  const path2 = opts?.path ?? REVIEW_SKILL_PATH;
13178
13366
  const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
13179
13367
  return {
13180
- id: (0, import_node_crypto7.randomUUID)(),
13368
+ id: (0, import_node_crypto8.randomUUID)(),
13181
13369
  name,
13182
13370
  kind: "file",
13183
13371
  path: path2,
@@ -13185,7 +13373,7 @@ function buildReviewRequestAttachment(content, opts) {
13185
13373
  };
13186
13374
  }
13187
13375
  function readExistingReviewRequestFile(worktreePath) {
13188
- return readTextIfPresent((0, import_node_path31.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path31.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path31.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path31.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
13376
+ return readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path32.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path32.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
13189
13377
  }
13190
13378
  async function requestReview(threadRef, send2) {
13191
13379
  const from = findThreadByRef(threadRef);
@@ -13212,13 +13400,13 @@ async function requestReview(threadRef, send2) {
13212
13400
  const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
13213
13401
  return { tab: started, from };
13214
13402
  }
13215
- var import_node_crypto7, import_node_fs31, import_node_path31, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
13403
+ var import_node_crypto8, import_node_fs32, import_node_path32, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
13216
13404
  var init_request_review = __esm({
13217
13405
  "src/review/request-review.ts"() {
13218
13406
  "use strict";
13219
- import_node_crypto7 = require("crypto");
13220
- import_node_fs31 = require("fs");
13221
- import_node_path31 = require("path");
13407
+ import_node_crypto8 = require("crypto");
13408
+ import_node_fs32 = require("fs");
13409
+ import_node_path32 = require("path");
13222
13410
  init_global_workspace();
13223
13411
  init_chat_tabs();
13224
13412
  init_thread_store();
@@ -13243,9 +13431,9 @@ function matchSimpleGlob(pattern, name) {
13243
13431
  return new RegExp(`^${escaped}$`).test(name);
13244
13432
  }
13245
13433
  function readWorktreeInclude(repoPath) {
13246
- const path2 = (0, import_node_path32.join)(repoPath, ".worktreeinclude");
13247
- if (!(0, import_node_fs32.existsSync)(path2)) return [];
13248
- return (0, import_node_fs32.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
13434
+ const path2 = (0, import_node_path33.join)(repoPath, ".worktreeinclude");
13435
+ if (!(0, import_node_fs33.existsSync)(path2)) return [];
13436
+ return (0, import_node_fs33.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
13249
13437
  }
13250
13438
  function resolveFilesToCopy(repoPath) {
13251
13439
  const fromInclude = readWorktreeInclude(repoPath);
@@ -13255,10 +13443,10 @@ function resolveFilesToCopy(repoPath) {
13255
13443
  if (settings?.fileIncludeGlobs?.length) {
13256
13444
  const matched = [];
13257
13445
  try {
13258
- for (const entry of (0, import_node_fs32.readdirSync)(repoPath, { withFileTypes: true })) {
13446
+ for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
13259
13447
  if (!entry.isFile()) continue;
13260
13448
  for (const glob of settings.fileIncludeGlobs) {
13261
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path32.basename)(glob), entry.name)) {
13449
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path33.basename)(glob), entry.name)) {
13262
13450
  matched.push(entry.name);
13263
13451
  break;
13264
13452
  }
@@ -13270,7 +13458,7 @@ function resolveFilesToCopy(repoPath) {
13270
13458
  }
13271
13459
  const defaults = [];
13272
13460
  try {
13273
- for (const entry of (0, import_node_fs32.readdirSync)(repoPath, { withFileTypes: true })) {
13461
+ for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
13274
13462
  if (entry.isFile() && entry.name.startsWith(".env")) {
13275
13463
  defaults.push(entry.name);
13276
13464
  }
@@ -13284,11 +13472,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
13284
13472
  const patterns = resolveFilesToCopy(repoPath);
13285
13473
  const copied = [];
13286
13474
  for (const rel of patterns) {
13287
- const src = (0, import_node_path32.join)(repoPath, rel);
13288
- if (!(0, import_node_fs32.existsSync)(src)) continue;
13289
- const dest = (0, import_node_path32.join)(worktreePath, rel);
13290
- (0, import_node_fs32.mkdirSync)((0, import_node_path32.dirname)(dest), { recursive: true });
13291
- (0, import_node_fs32.copyFileSync)(src, dest);
13475
+ const src = (0, import_node_path33.join)(repoPath, rel);
13476
+ if (!(0, import_node_fs33.existsSync)(src)) continue;
13477
+ const dest = (0, import_node_path33.join)(worktreePath, rel);
13478
+ (0, import_node_fs33.mkdirSync)((0, import_node_path33.dirname)(dest), { recursive: true });
13479
+ (0, import_node_fs33.copyFileSync)(src, dest);
13292
13480
  copied.push(rel);
13293
13481
  }
13294
13482
  return copied;
@@ -13323,7 +13511,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
13323
13511
  const env = stripNestedElectronEnv({
13324
13512
  ...baseEnv ?? process.env
13325
13513
  });
13326
- const name = opts.workspaceName ?? (0, import_node_path32.basename)(opts.worktreePath);
13514
+ const name = opts.workspaceName ?? (0, import_node_path33.basename)(opts.worktreePath);
13327
13515
  const ports = opts.ports ?? [];
13328
13516
  const primary = ports[0];
13329
13517
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -13478,6 +13666,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
13478
13666
  };
13479
13667
  }
13480
13668
  async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
13669
+ await ensureWorktreeSideboardIgnored(worktreePath);
13481
13670
  const reviewSkill = ensureReviewSkillFile(worktreePath);
13482
13671
  if (reviewSkill.wrote) {
13483
13672
  onLine?.(
@@ -13584,13 +13773,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
13584
13773
  done: handle.done
13585
13774
  };
13586
13775
  }
13587
- var import_node_fs32, import_node_net, import_node_path32, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
13776
+ var import_node_fs33, import_node_net, import_node_path33, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
13588
13777
  var init_conductor = __esm({
13589
13778
  "src/hook/conductor.ts"() {
13590
13779
  "use strict";
13591
- import_node_fs32 = require("fs");
13780
+ import_node_fs33 = require("fs");
13592
13781
  import_node_net = require("net");
13593
- import_node_path32 = require("path");
13782
+ import_node_path33 = require("path");
13594
13783
  import_execa4 = require("execa");
13595
13784
  import_node_readline3 = require("readline");
13596
13785
  init_settings();
@@ -13599,6 +13788,7 @@ var init_conductor = __esm({
13599
13788
  init_cursor_worktrees();
13600
13789
  init_git_auth_mode();
13601
13790
  init_request_review();
13791
+ init_worktree_exclude();
13602
13792
  init_nested_electron_env();
13603
13793
  PORT_RANGE_SIZE = 10;
13604
13794
  cachedLoginEnv = null;
@@ -13616,9 +13806,9 @@ async function findOrphanWorktrees(repoPaths) {
13616
13806
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
13617
13807
  );
13618
13808
  const homeRoot = sideboardWorkspacesDir();
13619
- if ((0, import_node_fs33.existsSync)(homeRoot)) {
13809
+ if ((0, import_node_fs34.existsSync)(homeRoot)) {
13620
13810
  try {
13621
- for (const entry of (0, import_node_fs33.readdirSync)(homeRoot, { withFileTypes: true })) {
13811
+ for (const entry of (0, import_node_fs34.readdirSync)(homeRoot, { withFileTypes: true })) {
13622
13812
  if (!entry.isDirectory()) continue;
13623
13813
  void entry;
13624
13814
  }
@@ -13628,7 +13818,7 @@ async function findOrphanWorktrees(repoPaths) {
13628
13818
  const orphans = [];
13629
13819
  const seen = /* @__PURE__ */ new Set();
13630
13820
  for (const repoPath of repos) {
13631
- if (!repoPath || !(0, import_node_fs33.existsSync)(repoPath)) continue;
13821
+ if (!repoPath || !(0, import_node_fs34.existsSync)(repoPath)) continue;
13632
13822
  try {
13633
13823
  const wts = await listWorktrees(repoPath);
13634
13824
  for (const wt of wts) {
@@ -13639,7 +13829,7 @@ async function findOrphanWorktrees(repoPaths) {
13639
13829
  seen.add(path2);
13640
13830
  let mtimeMs = 0;
13641
13831
  try {
13642
- mtimeMs = (0, import_node_fs33.statSync)(path2).mtimeMs;
13832
+ mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
13643
13833
  } catch {
13644
13834
  mtimeMs = 0;
13645
13835
  }
@@ -13649,16 +13839,16 @@ async function findOrphanWorktrees(repoPaths) {
13649
13839
  }
13650
13840
  try {
13651
13841
  const root = worktreesRoot(repoPath);
13652
- if ((0, import_node_fs33.existsSync)(root)) {
13653
- for (const entry of (0, import_node_fs33.readdirSync)(root, { withFileTypes: true })) {
13842
+ if ((0, import_node_fs34.existsSync)(root)) {
13843
+ for (const entry of (0, import_node_fs34.readdirSync)(root, { withFileTypes: true })) {
13654
13844
  if (!entry.isDirectory()) continue;
13655
- const path2 = (0, import_node_path33.join)(root, entry.name).replace(/\/$/, "");
13845
+ const path2 = (0, import_node_path34.join)(root, entry.name).replace(/\/$/, "");
13656
13846
  if (known.has(path2) || seen.has(path2)) continue;
13657
- if (!(0, import_node_fs33.existsSync)((0, import_node_path33.join)(path2, ".git"))) continue;
13847
+ if (!(0, import_node_fs34.existsSync)((0, import_node_path34.join)(path2, ".git"))) continue;
13658
13848
  seen.add(path2);
13659
13849
  let mtimeMs = 0;
13660
13850
  try {
13661
- mtimeMs = (0, import_node_fs33.statSync)(path2).mtimeMs;
13851
+ mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
13662
13852
  } catch {
13663
13853
  mtimeMs = Date.now();
13664
13854
  }
@@ -13719,12 +13909,12 @@ function worktreeCleanupSettings() {
13719
13909
  autoCleanupOrphans: a.autoCleanupOrphans
13720
13910
  };
13721
13911
  }
13722
- var import_node_fs33, import_node_path33;
13912
+ var import_node_fs34, import_node_path34;
13723
13913
  var init_orphan_cleanup = __esm({
13724
13914
  "src/git/orphan-cleanup.ts"() {
13725
13915
  "use strict";
13726
- import_node_fs33 = require("fs");
13727
- import_node_path33 = require("path");
13916
+ import_node_fs34 = require("fs");
13917
+ import_node_path34 = require("path");
13728
13918
  init_worktree();
13729
13919
  init_thread_store();
13730
13920
  init_paths();
@@ -13831,38 +14021,38 @@ __export(workspaces_exports, {
13831
14021
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
13832
14022
  });
13833
14023
  function workspacesFile() {
13834
- return (0, import_node_path34.join)(appDataDir(), "workspaces.json");
14024
+ return (0, import_node_path35.join)(appDataDir(), "workspaces.json");
13835
14025
  }
13836
14026
  function removedWorkspacesFile() {
13837
- return (0, import_node_path34.join)(appDataDir(), "removed-workspaces.json");
14027
+ return (0, import_node_path35.join)(appDataDir(), "removed-workspaces.json");
13838
14028
  }
13839
14029
  function readAll2() {
13840
14030
  const path2 = workspacesFile();
13841
- if (!(0, import_node_fs34.existsSync)(path2)) return [];
14031
+ if (!(0, import_node_fs35.existsSync)(path2)) return [];
13842
14032
  try {
13843
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
14033
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13844
14034
  return Array.isArray(raw) ? raw : [];
13845
14035
  } catch {
13846
14036
  return [];
13847
14037
  }
13848
14038
  }
13849
14039
  function writeAll2(list) {
13850
- (0, import_node_fs34.mkdirSync)(appDataDir(), { recursive: true });
13851
- (0, import_node_fs34.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
14040
+ (0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
14041
+ (0, import_node_fs35.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
13852
14042
  }
13853
14043
  function readRemoved() {
13854
14044
  const path2 = removedWorkspacesFile();
13855
- if (!(0, import_node_fs34.existsSync)(path2)) return /* @__PURE__ */ new Set();
14045
+ if (!(0, import_node_fs35.existsSync)(path2)) return /* @__PURE__ */ new Set();
13856
14046
  try {
13857
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
14047
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13858
14048
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
13859
14049
  } catch {
13860
14050
  return /* @__PURE__ */ new Set();
13861
14051
  }
13862
14052
  }
13863
14053
  function writeRemoved(paths) {
13864
- (0, import_node_fs34.mkdirSync)(appDataDir(), { recursive: true });
13865
- (0, import_node_fs34.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
14054
+ (0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
14055
+ (0, import_node_fs35.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
13866
14056
  }
13867
14057
  function rememberRemoved(repoPath) {
13868
14058
  const next = readRemoved();
@@ -13885,7 +14075,7 @@ function listWorkspaces() {
13885
14075
  async function addWorkspace(repoPath) {
13886
14076
  const root = await resolveRepoRoot(repoPath);
13887
14077
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
13888
- if (!(0, import_node_fs34.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
14078
+ if (!(0, import_node_fs35.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
13889
14079
  forgetRemoved(root);
13890
14080
  await ensureGhPreferOrigin(root);
13891
14081
  const current = readAll2();
@@ -13893,7 +14083,7 @@ async function addWorkspace(repoPath) {
13893
14083
  if (existing) return existing;
13894
14084
  const next = {
13895
14085
  path: root,
13896
- name: (0, import_node_path34.basename)(root),
14086
+ name: (0, import_node_path35.basename)(root),
13897
14087
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
13898
14088
  };
13899
14089
  writeAll2([...current, next]);
@@ -13915,10 +14105,10 @@ function syncWorkspacesFromThreads(repoPaths) {
13915
14105
  if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
13916
14106
  continue;
13917
14107
  }
13918
- if (!(0, import_node_fs34.existsSync)(path2)) continue;
14108
+ if (!(0, import_node_fs35.existsSync)(path2)) continue;
13919
14109
  const ws = {
13920
14110
  path: path2,
13921
- name: (0, import_node_path34.basename)(path2),
14111
+ name: (0, import_node_path35.basename)(path2),
13922
14112
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
13923
14113
  };
13924
14114
  byPath.set(path2, ws);
@@ -13928,12 +14118,12 @@ function syncWorkspacesFromThreads(repoPaths) {
13928
14118
  if (dirty) writeAll2(next);
13929
14119
  return next.sort((a, b) => a.name.localeCompare(b.name));
13930
14120
  }
13931
- var import_node_fs34, import_node_path34;
14121
+ var import_node_fs35, import_node_path35;
13932
14122
  var init_workspaces2 = __esm({
13933
14123
  "src/store/workspaces.ts"() {
13934
14124
  "use strict";
13935
- import_node_fs34 = require("fs");
13936
- import_node_path34 = require("path");
14125
+ import_node_fs35 = require("fs");
14126
+ import_node_path35 = require("path");
13937
14127
  init_paths();
13938
14128
  init_global_workspace();
13939
14129
  init_worktree();
@@ -13946,12 +14136,12 @@ async function cloneRepoIntoSideboard(opts) {
13946
14136
  if (!url) throw new Error("Clone URL is required");
13947
14137
  let name = opts.name?.trim();
13948
14138
  if (!name) {
13949
- const leaf = (0, import_node_path35.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
14139
+ const leaf = (0, import_node_path36.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
13950
14140
  name = leaf || "repo";
13951
14141
  }
13952
14142
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
13953
- const dest = (0, import_node_path35.join)(sideboardReposDir(), name);
13954
- if ((0, import_node_fs35.existsSync)(dest)) {
14143
+ const dest = (0, import_node_path36.join)(sideboardReposDir(), name);
14144
+ if ((0, import_node_fs36.existsSync)(dest)) {
13955
14145
  const repoPath2 = await resolveRepoRoot(dest);
13956
14146
  const workspace2 = await ensureWorkspace(repoPath2);
13957
14147
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -13966,12 +14156,12 @@ async function cloneRepoIntoSideboard(opts) {
13966
14156
  const workspace = await ensureWorkspace(repoPath);
13967
14157
  return { repoPath, workspace };
13968
14158
  }
13969
- var import_node_fs35, import_node_path35, import_execa6;
14159
+ var import_node_fs36, import_node_path36, import_execa6;
13970
14160
  var init_clone_repo = __esm({
13971
14161
  "src/git/clone-repo.ts"() {
13972
14162
  "use strict";
13973
- import_node_fs35 = require("fs");
13974
- import_node_path35 = require("path");
14163
+ import_node_fs36 = require("fs");
14164
+ import_node_path36 = require("path");
13975
14165
  import_execa6 = require("execa");
13976
14166
  init_paths();
13977
14167
  init_workspaces2();
@@ -14988,7 +15178,7 @@ function persistCreateAttachments(worktreePath, attachments) {
14988
15178
  }
14989
15179
  async function createThread(input, _onSetupLine) {
14990
15180
  const repoPath = await resolveRepoRoot(input.repoPath);
14991
- if (!(0, import_node_fs36.existsSync)(repoPath)) {
15181
+ if (!(0, import_node_fs37.existsSync)(repoPath)) {
14992
15182
  throw new Error(`Repo not found: ${repoPath}`);
14993
15183
  }
14994
15184
  if (input.reuseExisting !== false) {
@@ -15163,11 +15353,11 @@ async function listLinearIssues(agent, repoPath) {
15163
15353
  }
15164
15354
  return adapter.listLinearIssues(repoPath);
15165
15355
  }
15166
- var import_node_fs36;
15356
+ var import_node_fs37;
15167
15357
  var init_create = __esm({
15168
15358
  "src/threads/create.ts"() {
15169
15359
  "use strict";
15170
- import_node_fs36 = require("fs");
15360
+ import_node_fs37 = require("fs");
15171
15361
  init_detect();
15172
15362
  init_worktree();
15173
15363
  init_home_board();
@@ -15270,20 +15460,20 @@ function writeTurnLive(threadId, progress) {
15270
15460
  const path2 = threadLivePath(threadId);
15271
15461
  const tmp = `${path2}.${process.pid}.tmp`;
15272
15462
  try {
15273
- (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
15274
- (0, import_node_fs37.renameSync)(tmp, path2);
15463
+ (0, import_node_fs38.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
15464
+ (0, import_node_fs38.renameSync)(tmp, path2);
15275
15465
  } catch {
15276
15466
  try {
15277
- (0, import_node_fs37.unlinkSync)(tmp);
15467
+ (0, import_node_fs38.unlinkSync)(tmp);
15278
15468
  } catch {
15279
15469
  }
15280
15470
  }
15281
15471
  }
15282
15472
  function readTurnLive(threadId) {
15283
15473
  const path2 = threadLivePath(threadId);
15284
- if (!(0, import_node_fs37.existsSync)(path2)) return null;
15474
+ if (!(0, import_node_fs38.existsSync)(path2)) return null;
15285
15475
  try {
15286
- const raw = JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8"));
15476
+ const raw = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
15287
15477
  if (!raw || typeof raw.summary !== "string") return null;
15288
15478
  return raw;
15289
15479
  } catch {
@@ -15295,17 +15485,17 @@ function clearTurnLive(threadId) {
15295
15485
  if (buf?.timer) clearTimeout(buf.timer);
15296
15486
  buffers.delete(threadId);
15297
15487
  const path2 = threadLivePath(threadId);
15298
- if (!(0, import_node_fs37.existsSync)(path2)) return;
15488
+ if (!(0, import_node_fs38.existsSync)(path2)) return;
15299
15489
  try {
15300
- (0, import_node_fs37.unlinkSync)(path2);
15490
+ (0, import_node_fs38.unlinkSync)(path2);
15301
15491
  } catch {
15302
15492
  }
15303
15493
  }
15304
- var import_node_fs37, buffers, FLUSH_MS, MAX_PARTS;
15494
+ var import_node_fs38, buffers, FLUSH_MS, MAX_PARTS;
15305
15495
  var init_turn_live = __esm({
15306
15496
  "src/store/turn-live.ts"() {
15307
15497
  "use strict";
15308
- import_node_fs37 = require("fs");
15498
+ import_node_fs38 = require("fs");
15309
15499
  init_message_parts();
15310
15500
  init_paths();
15311
15501
  buffers = /* @__PURE__ */ new Map();
@@ -15479,7 +15669,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
15479
15669
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
15480
15670
  ].join("\n");
15481
15671
  return {
15482
- id: (0, import_node_crypto8.randomUUID)(),
15672
+ id: (0, import_node_crypto9.randomUUID)(),
15483
15673
  name: "Orchestration quota handoff.md",
15484
15674
  kind: "transcript",
15485
15675
  content: body
@@ -15500,11 +15690,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
15500
15690
  sourceType: "orchestration"
15501
15691
  });
15502
15692
  }
15503
- var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
15693
+ var import_node_crypto9, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
15504
15694
  var init_quota_failover = __esm({
15505
15695
  "src/orchestrator/quota-failover.ts"() {
15506
15696
  "use strict";
15507
- import_node_crypto8 = require("crypto");
15697
+ import_node_crypto9 = require("crypto");
15508
15698
  init_session_quota();
15509
15699
  init_app_settings();
15510
15700
  init_global_workspace();
@@ -15521,7 +15711,7 @@ var init_quota_failover = __esm({
15521
15711
  // src/threads/adopt.ts
15522
15712
  function thisModuleFile() {
15523
15713
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
15524
- return cjsFile || process.argv[1] || (0, import_node_path36.join)(process.cwd(), "package.json");
15714
+ return cjsFile || process.argv[1] || (0, import_node_path37.join)(process.cwd(), "package.json");
15525
15715
  }
15526
15716
  function openReadonlySqlite(file) {
15527
15717
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -15539,21 +15729,21 @@ function mapAgentType(raw) {
15539
15729
  return null;
15540
15730
  }
15541
15731
  function resolveConductorCursorAgentId(workspacePath) {
15542
- if (!workspacePath || !(0, import_node_fs38.existsSync)(CURSOR_SDK_STORE)) return null;
15732
+ if (!workspacePath || !(0, import_node_fs39.existsSync)(CURSOR_SDK_STORE)) return null;
15543
15733
  const normalized = workspacePath.replace(/\/$/, "");
15544
15734
  let best = null;
15545
15735
  let hashes;
15546
15736
  try {
15547
- hashes = (0, import_node_fs38.readdirSync)(CURSOR_SDK_STORE);
15737
+ hashes = (0, import_node_fs39.readdirSync)(CURSOR_SDK_STORE);
15548
15738
  } catch {
15549
15739
  return null;
15550
15740
  }
15551
15741
  for (const hash of hashes) {
15552
- const agentsFile = (0, import_node_path36.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
15553
- if (!(0, import_node_fs38.existsSync)(agentsFile)) continue;
15742
+ const agentsFile = (0, import_node_path37.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
15743
+ if (!(0, import_node_fs39.existsSync)(agentsFile)) continue;
15554
15744
  let text5;
15555
15745
  try {
15556
- text5 = (0, import_node_fs38.readFileSync)(agentsFile, "utf8");
15746
+ text5 = (0, import_node_fs39.readFileSync)(agentsFile, "utf8");
15557
15747
  } catch {
15558
15748
  continue;
15559
15749
  }
@@ -15577,7 +15767,7 @@ function resolveConductorCursorAgentId(workspacePath) {
15577
15767
  return best?.agentId ?? null;
15578
15768
  }
15579
15769
  async function adoptThread(input) {
15580
- if (!(0, import_node_fs38.existsSync)(input.worktreePath)) {
15770
+ if (!(0, import_node_fs39.existsSync)(input.worktreePath)) {
15581
15771
  throw new Error(`Worktree not found: ${input.worktreePath}`);
15582
15772
  }
15583
15773
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -15598,24 +15788,26 @@ async function adoptThread(input) {
15598
15788
  writeThread(thread);
15599
15789
  const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
15600
15790
  await ensureWorkspace2(repoPath);
15791
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
15792
+ await ensureWorktreeSideboardIgnored2(input.worktreePath);
15601
15793
  return thread;
15602
15794
  }
15603
15795
  function conductorDbPath() {
15604
15796
  return CONDUCTOR_DB;
15605
15797
  }
15606
15798
  function listConductorWorkspaces() {
15607
- if (!(0, import_node_fs38.existsSync)(CONDUCTOR_DB)) {
15799
+ if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
15608
15800
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
15609
15801
  }
15610
- const tmp = (0, import_node_fs38.mkdtempSync)((0, import_node_path36.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
15611
- const snapshot = (0, import_node_path36.join)(tmp, "conductor.db");
15802
+ const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
15803
+ const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
15612
15804
  try {
15613
- (0, import_node_fs38.copyFileSync)(CONDUCTOR_DB, snapshot);
15805
+ (0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
15614
15806
  for (const suffix of ["-wal", "-shm"]) {
15615
15807
  const src = `${CONDUCTOR_DB}${suffix}`;
15616
- if ((0, import_node_fs38.existsSync)(src)) {
15808
+ if ((0, import_node_fs39.existsSync)(src)) {
15617
15809
  try {
15618
- (0, import_node_fs38.copyFileSync)(src, `${snapshot}${suffix}`);
15810
+ (0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
15619
15811
  } catch {
15620
15812
  }
15621
15813
  }
@@ -15691,22 +15883,22 @@ function listConductorWorkspaces() {
15691
15883
  db.close();
15692
15884
  }
15693
15885
  } finally {
15694
- (0, import_node_fs38.rmSync)(tmp, { recursive: true, force: true });
15886
+ (0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
15695
15887
  }
15696
15888
  }
15697
15889
  function importConductorWorkspace(workspaceId) {
15698
- if (!(0, import_node_fs38.existsSync)(CONDUCTOR_DB)) {
15890
+ if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
15699
15891
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
15700
15892
  }
15701
- const tmp = (0, import_node_fs38.mkdtempSync)((0, import_node_path36.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
15702
- const snapshot = (0, import_node_path36.join)(tmp, "conductor.db");
15893
+ const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
15894
+ const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
15703
15895
  try {
15704
- (0, import_node_fs38.copyFileSync)(CONDUCTOR_DB, snapshot);
15896
+ (0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
15705
15897
  for (const suffix of ["-wal", "-shm"]) {
15706
15898
  const src = `${CONDUCTOR_DB}${suffix}`;
15707
- if ((0, import_node_fs38.existsSync)(src)) {
15899
+ if ((0, import_node_fs39.existsSync)(src)) {
15708
15900
  try {
15709
- (0, import_node_fs38.copyFileSync)(src, `${snapshot}${suffix}`);
15901
+ (0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
15710
15902
  } catch {
15711
15903
  }
15712
15904
  }
@@ -15724,7 +15916,7 @@ function importConductorWorkspace(workspaceId) {
15724
15916
  ).get(workspaceId);
15725
15917
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
15726
15918
  const worktreePath = String(row.workspacePath);
15727
- if (!(0, import_node_fs38.existsSync)(worktreePath)) {
15919
+ if (!(0, import_node_fs39.existsSync)(worktreePath)) {
15728
15920
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
15729
15921
  }
15730
15922
  let sessionId = null;
@@ -15787,31 +15979,31 @@ function importConductorWorkspace(workspaceId) {
15787
15979
  db.close();
15788
15980
  }
15789
15981
  } finally {
15790
- (0, import_node_fs38.rmSync)(tmp, { recursive: true, force: true });
15982
+ (0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
15791
15983
  }
15792
15984
  }
15793
15985
  async function importConductorWorkspaceAsync(workspaceId) {
15794
15986
  return importConductorWorkspace(workspaceId);
15795
15987
  }
15796
- var import_node_child_process4, import_node_fs38, import_node_os10, import_node_path36, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
15988
+ var import_node_child_process4, import_node_fs39, import_node_os11, import_node_path37, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
15797
15989
  var init_adopt = __esm({
15798
15990
  "src/threads/adopt.ts"() {
15799
15991
  "use strict";
15800
15992
  import_node_child_process4 = require("child_process");
15801
- import_node_fs38 = require("fs");
15802
- import_node_os10 = require("os");
15803
- import_node_path36 = require("path");
15993
+ import_node_fs39 = require("fs");
15994
+ import_node_os11 = require("os");
15995
+ import_node_path37 = require("path");
15804
15996
  import_node_module4 = require("module");
15805
15997
  init_worktree();
15806
15998
  init_thread_store();
15807
- CONDUCTOR_APP_SUPPORT = (0, import_node_path36.join)(
15999
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path37.join)(
15808
16000
  process.env.HOME ?? "",
15809
16001
  "Library",
15810
16002
  "Application Support",
15811
16003
  "com.conductor.app"
15812
16004
  );
15813
- CONDUCTOR_DB = (0, import_node_path36.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
15814
- CURSOR_SDK_STORE = (0, import_node_path36.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
16005
+ CONDUCTOR_DB = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
16006
+ CURSOR_SDK_STORE = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
15815
16007
  }
15816
16008
  });
15817
16009
 
@@ -15878,7 +16070,7 @@ async function openStackLayer(input, _onSetupLine) {
15878
16070
  let createdWorktree = false;
15879
16071
  const trees = await listWorktrees(repoPath);
15880
16072
  const checkedOut = trees.find((w) => w.branch === branchName);
15881
- if (checkedOut?.path && (0, import_node_fs39.existsSync)(checkedOut.path)) {
16073
+ if (checkedOut?.path && (0, import_node_fs40.existsSync)(checkedOut.path)) {
15882
16074
  if (input.reuseExistingWorktree !== false) {
15883
16075
  worktreePath = checkedOut.path;
15884
16076
  } else {
@@ -16020,7 +16212,7 @@ async function initStackFromThread(input, onSetupLine) {
16020
16212
  async function createPrStack(input, onSetupLine) {
16021
16213
  await requireAgent(input.agent);
16022
16214
  const repoPath = await resolveRepoRoot(input.repoPath);
16023
- if (!(0, import_node_fs39.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
16215
+ if (!(0, import_node_fs40.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
16024
16216
  if (!input.branches.length) throw new Error("At least one branch name required");
16025
16217
  const status = await detectGhStack(repoPath);
16026
16218
  if (!status.available) throw new Error(status.reason);
@@ -16087,7 +16279,7 @@ async function createPrStack(input, onSetupLine) {
16087
16279
  }
16088
16280
  }
16089
16281
  const claimed = new Set(threads.map((t) => t.worktreePath));
16090
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs39.existsSync)(bootstrap.worktreePath)) {
16282
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs40.existsSync)(bootstrap.worktreePath)) {
16091
16283
  try {
16092
16284
  await removeWorktree(repoPath, bootstrap.worktreePath, {
16093
16285
  deleteBranch: bootstrap.branchName
@@ -16107,11 +16299,11 @@ function stackAgentDefaultsFrom(input) {
16107
16299
  planMode: input.planMode
16108
16300
  };
16109
16301
  }
16110
- var import_node_fs39;
16302
+ var import_node_fs40;
16111
16303
  var init_stack_layers = __esm({
16112
16304
  "src/threads/stack-layers.ts"() {
16113
16305
  "use strict";
16114
- import_node_fs39 = require("fs");
16306
+ import_node_fs40 = require("fs");
16115
16307
  init_detect();
16116
16308
  init_run();
16117
16309
  init_stack();
@@ -16124,7 +16316,7 @@ var init_stack_layers = __esm({
16124
16316
 
16125
16317
  // src/diff/diff.ts
16126
16318
  async function inspectGitWorktree(worktreePath) {
16127
- if (!worktreePath || !(0, import_node_fs40.existsSync)(worktreePath)) return "missing_worktree";
16319
+ if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) return "missing_worktree";
16128
16320
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
16129
16321
  reject: false
16130
16322
  });
@@ -16132,7 +16324,7 @@ async function inspectGitWorktree(worktreePath) {
16132
16324
  return "ok";
16133
16325
  }
16134
16326
  async function initializeGitRepository(worktreePath) {
16135
- if (!worktreePath || !(0, import_node_fs40.existsSync)(worktreePath)) {
16327
+ if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) {
16136
16328
  throw new Error("Worktree not found");
16137
16329
  }
16138
16330
  const status = await inspectGitWorktree(worktreePath);
@@ -16266,11 +16458,11 @@ new file mode 100644
16266
16458
  };
16267
16459
  }
16268
16460
  async function untrackedPatch(worktreePath, path2, maxHunk) {
16269
- const abs = (0, import_node_path37.join)(worktreePath, path2);
16461
+ const abs = (0, import_node_path38.join)(worktreePath, path2);
16270
16462
  try {
16271
- const st = (0, import_node_fs40.statSync)(abs);
16463
+ const st = (0, import_node_fs41.statSync)(abs);
16272
16464
  if (st.isFile() && st.size > maxHunk) {
16273
- const buf = (0, import_node_fs40.readFileSync)(abs).subarray(0, maxHunk);
16465
+ const buf = (0, import_node_fs41.readFileSync)(abs).subarray(0, maxHunk);
16274
16466
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
16275
16467
  }
16276
16468
  } catch {
@@ -16759,8 +16951,8 @@ function isImageRelativePath(relativePath) {
16759
16951
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16760
16952
  assertSafeRelativePath(relativePath);
16761
16953
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
16762
- const abs = (0, import_node_path37.join)(worktreePath, relativePath);
16763
- const st = (0, import_node_fs40.statSync)(abs);
16954
+ const abs = (0, import_node_path38.join)(worktreePath, relativePath);
16955
+ const st = (0, import_node_fs41.statSync)(abs);
16764
16956
  if (!st.isFile()) {
16765
16957
  throw new Error(`Not a file: ${relativePath}`);
16766
16958
  }
@@ -16769,7 +16961,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16769
16961
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
16770
16962
  );
16771
16963
  }
16772
- const buf = (0, import_node_fs40.readFileSync)(abs);
16964
+ const buf = (0, import_node_fs41.readFileSync)(abs);
16773
16965
  return {
16774
16966
  path: relativePath,
16775
16967
  contentBase64: buf.toString("base64"),
@@ -16779,12 +16971,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16779
16971
  function readWorktreeFile(worktreePath, relativePath, opts) {
16780
16972
  assertSafeRelativePath(relativePath);
16781
16973
  const maxBytes = opts?.maxBytes ?? 2e5;
16782
- const abs = (0, import_node_path37.join)(worktreePath, relativePath);
16783
- const st = (0, import_node_fs40.statSync)(abs);
16974
+ const abs = (0, import_node_path38.join)(worktreePath, relativePath);
16975
+ const st = (0, import_node_fs41.statSync)(abs);
16784
16976
  if (!st.isFile()) {
16785
16977
  throw new Error(`Not a file: ${relativePath}`);
16786
16978
  }
16787
- const buf = (0, import_node_fs40.readFileSync)(abs);
16979
+ const buf = (0, import_node_fs41.readFileSync)(abs);
16788
16980
  if (isImageRelativePath(relativePath)) {
16789
16981
  const maxImageBytes = Math.max(maxBytes, 15e6);
16790
16982
  const truncated2 = buf.length > maxImageBytes;
@@ -16827,9 +17019,9 @@ function assertSafeRelativePath(relativePath) {
16827
17019
  }
16828
17020
  function writeWorktreeFile(worktreePath, relativePath, content) {
16829
17021
  assertSafeRelativePath(relativePath);
16830
- const abs = (0, import_node_path37.join)(worktreePath, relativePath);
16831
- (0, import_node_fs40.mkdirSync)((0, import_node_path37.dirname)(abs), { recursive: true });
16832
- (0, import_node_fs40.writeFileSync)(abs, content, "utf8");
17022
+ const abs = (0, import_node_path38.join)(worktreePath, relativePath);
17023
+ (0, import_node_fs41.mkdirSync)((0, import_node_path38.dirname)(abs), { recursive: true });
17024
+ (0, import_node_fs41.writeFileSync)(abs, content, "utf8");
16833
17025
  return { path: relativePath };
16834
17026
  }
16835
17027
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -16846,12 +17038,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
16846
17038
  truncated: full.files.length > maxFiles
16847
17039
  };
16848
17040
  }
16849
- var import_node_fs40, import_node_path37, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
17041
+ var import_node_fs41, import_node_path38, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
16850
17042
  var init_diff = __esm({
16851
17043
  "src/diff/diff.ts"() {
16852
17044
  "use strict";
16853
- import_node_fs40 = require("fs");
16854
- import_node_path37 = require("path");
17045
+ import_node_fs41 = require("fs");
17046
+ import_node_path38 = require("path");
16855
17047
  init_run();
16856
17048
  init_worktree();
16857
17049
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -17109,7 +17301,7 @@ function parseFrontmatter(content) {
17109
17301
  }
17110
17302
  function readSkill(skillMd, source) {
17111
17303
  try {
17112
- const content = (0, import_node_fs41.readFileSync)(skillMd, "utf8");
17304
+ const content = (0, import_node_fs42.readFileSync)(skillMd, "utf8");
17113
17305
  const { name: fmName, description } = parseFrontmatter(content);
17114
17306
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
17115
17307
  const name = fmName || dirName;
@@ -17128,19 +17320,19 @@ function readSkill(skillMd, source) {
17128
17320
  }
17129
17321
  }
17130
17322
  function scanSkillsDir(dir, source, out) {
17131
- if (!(0, import_node_fs41.existsSync)(dir)) return;
17323
+ if (!(0, import_node_fs42.existsSync)(dir)) return;
17132
17324
  let entries;
17133
17325
  try {
17134
- entries = (0, import_node_fs41.readdirSync)(dir);
17326
+ entries = (0, import_node_fs42.readdirSync)(dir);
17135
17327
  } catch {
17136
17328
  return;
17137
17329
  }
17138
17330
  for (const entry of entries) {
17139
17331
  if (entry.startsWith(".")) continue;
17140
- const skillMd = (0, import_node_path38.join)(dir, entry, "SKILL.md");
17141
- if (!(0, import_node_fs41.existsSync)(skillMd)) continue;
17332
+ const skillMd = (0, import_node_path39.join)(dir, entry, "SKILL.md");
17333
+ if (!(0, import_node_fs42.existsSync)(skillMd)) continue;
17142
17334
  try {
17143
- if (!(0, import_node_fs41.statSync)(skillMd).isFile()) continue;
17335
+ if (!(0, import_node_fs42.statSync)(skillMd).isFile()) continue;
17144
17336
  } catch {
17145
17337
  continue;
17146
17338
  }
@@ -17149,24 +17341,24 @@ function scanSkillsDir(dir, source, out) {
17149
17341
  }
17150
17342
  }
17151
17343
  function scanClaudePluginSkills(pluginsRoot, out) {
17152
- if (!(0, import_node_fs41.existsSync)(pluginsRoot)) return;
17344
+ if (!(0, import_node_fs42.existsSync)(pluginsRoot)) return;
17153
17345
  const walk = (dir, depth, lookingForSkillsDir) => {
17154
17346
  if (depth > 7) return;
17155
17347
  let entries;
17156
17348
  try {
17157
- entries = (0, import_node_fs41.readdirSync)(dir);
17349
+ entries = (0, import_node_fs42.readdirSync)(dir);
17158
17350
  } catch {
17159
17351
  return;
17160
17352
  }
17161
17353
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
17162
- const skill = readSkill((0, import_node_path38.join)(dir, "SKILL.md"), "cli");
17354
+ const skill = readSkill((0, import_node_path39.join)(dir, "SKILL.md"), "cli");
17163
17355
  if (skill) out.push(skill);
17164
17356
  }
17165
17357
  for (const entry of entries) {
17166
17358
  if (entry === "node_modules" || entry === ".git") continue;
17167
- const full = (0, import_node_path38.join)(dir, entry);
17359
+ const full = (0, import_node_path39.join)(dir, entry);
17168
17360
  try {
17169
- if (!(0, import_node_fs41.statSync)(full).isDirectory()) continue;
17361
+ if (!(0, import_node_fs42.statSync)(full).isDirectory()) continue;
17170
17362
  } catch {
17171
17363
  continue;
17172
17364
  }
@@ -17181,20 +17373,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
17181
17373
  walk(pluginsRoot, 0, false);
17182
17374
  }
17183
17375
  function discoverSkills(worktreePath) {
17184
- const home = (0, import_node_os11.homedir)();
17376
+ const home = (0, import_node_os12.homedir)();
17185
17377
  const collected = [];
17186
17378
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
17187
- scanSkillsDir((0, import_node_path38.join)(worktreePath, rel), "workspace", collected);
17379
+ scanSkillsDir((0, import_node_path39.join)(worktreePath, rel), "workspace", collected);
17188
17380
  }
17189
17381
  for (const abs of [
17190
- (0, import_node_path38.join)(home, ".claude/skills"),
17191
- (0, import_node_path38.join)(home, ".cursor/skills"),
17192
- (0, import_node_path38.join)(home, ".sideboard/skills"),
17193
- (0, import_node_path38.join)(home, ".brightsy/skills")
17382
+ (0, import_node_path39.join)(home, ".claude/skills"),
17383
+ (0, import_node_path39.join)(home, ".cursor/skills"),
17384
+ (0, import_node_path39.join)(home, ".sideboard/skills"),
17385
+ (0, import_node_path39.join)(home, ".brightsy/skills")
17194
17386
  ]) {
17195
17387
  scanSkillsDir(abs, "user", collected);
17196
17388
  }
17197
- scanClaudePluginSkills((0, import_node_path38.join)(home, ".claude/plugins"), collected);
17389
+ scanClaudePluginSkills((0, import_node_path39.join)(home, ".claude/plugins"), collected);
17198
17390
  collected.push(...bundledSkills());
17199
17391
  const rank = {
17200
17392
  workspace: 0,
@@ -17220,7 +17412,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
17220
17412
  \u2026(truncated)` : body;
17221
17413
  }
17222
17414
  }
17223
- const raw = (0, import_node_fs41.readFileSync)(skillPath, "utf8");
17415
+ const raw = (0, import_node_fs42.readFileSync)(skillPath, "utf8");
17224
17416
  if (raw.startsWith("---")) {
17225
17417
  const end = raw.indexOf("\n---", 3);
17226
17418
  if (end >= 0) {
@@ -17234,13 +17426,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
17234
17426
 
17235
17427
  \u2026(truncated)` : raw;
17236
17428
  }
17237
- var import_node_fs41, import_node_os11, import_node_path38, BUNDLED_SKILL_PREFIX;
17429
+ var import_node_fs42, import_node_os12, import_node_path39, BUNDLED_SKILL_PREFIX;
17238
17430
  var init_discover = __esm({
17239
17431
  "src/skills/discover.ts"() {
17240
17432
  "use strict";
17241
- import_node_fs41 = require("fs");
17242
- import_node_os11 = require("os");
17243
- import_node_path38 = require("path");
17433
+ import_node_fs42 = require("fs");
17434
+ import_node_os12 = require("os");
17435
+ import_node_path39 = require("path");
17244
17436
  init_long_running();
17245
17437
  BUNDLED_SKILL_PREFIX = "bundled:";
17246
17438
  }
@@ -17335,17 +17527,17 @@ var init_expand = __esm({
17335
17527
  function packagedDetachedJobPath() {
17336
17528
  const dir = packagedMcpDir();
17337
17529
  if (!dir) return null;
17338
- const script = (0, import_node_path39.join)(dir, "scripts", "detached-job.js");
17339
- return (0, import_node_fs42.existsSync)(script) ? script : null;
17530
+ const script = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
17531
+ return (0, import_node_fs43.existsSync)(script) ? script : null;
17340
17532
  }
17341
17533
  function resolveDetachedJobScript() {
17342
17534
  const packaged = packagedDetachedJobPath();
17343
17535
  if (packaged) return packaged;
17344
- let dir = (0, import_node_path39.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
17536
+ let dir = (0, import_node_path40.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
17345
17537
  for (let i = 0; i < 8; i++) {
17346
- const candidate = (0, import_node_path39.join)(dir, "scripts", "detached-job.js");
17347
- if ((0, import_node_fs42.existsSync)(candidate)) return candidate;
17348
- const parent = (0, import_node_path39.dirname)(dir);
17538
+ const candidate = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
17539
+ if ((0, import_node_fs43.existsSync)(candidate)) return candidate;
17540
+ const parent = (0, import_node_path40.dirname)(dir);
17349
17541
  if (parent === dir) break;
17350
17542
  dir = parent;
17351
17543
  }
@@ -17356,12 +17548,12 @@ function formatDetachedJobInvoke(scriptPath) {
17356
17548
  if (resolved) return `node ${JSON.stringify(resolved)}`;
17357
17549
  return "node scripts/detached-job.js";
17358
17550
  }
17359
- var import_node_fs42, import_node_path39, import_node_url3, import_meta3;
17551
+ var import_node_fs43, import_node_path40, import_node_url3, import_meta3;
17360
17552
  var init_detached_job_path = __esm({
17361
17553
  "src/skills/detached-job-path.ts"() {
17362
17554
  "use strict";
17363
- import_node_fs42 = require("fs");
17364
- import_node_path39 = require("path");
17555
+ import_node_fs43 = require("fs");
17556
+ import_node_path40 = require("path");
17365
17557
  import_node_url3 = require("url");
17366
17558
  init_packaged_runtime();
17367
17559
  import_meta3 = {};
@@ -17434,11 +17626,11 @@ function formatWorktreeDirective(thread, opts) {
17434
17626
  );
17435
17627
  } else if (opts?.githubSlug) {
17436
17628
  lines.push(
17437
- `- 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.`
17629
+ `- 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\`.`
17438
17630
  );
17439
17631
  } else {
17440
17632
  lines.push(
17441
- "- 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."
17633
+ "- 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`."
17442
17634
  );
17443
17635
  }
17444
17636
  lines.push("");
@@ -17536,11 +17728,11 @@ function loadAgentInstructions(worktreePath, agent) {
17536
17728
  const out = [];
17537
17729
  for (const rel of candidates) {
17538
17730
  if (seenPaths.has(rel)) continue;
17539
- const abs = (0, import_node_path40.join)(worktreePath, rel);
17540
- if (!(0, import_node_fs43.existsSync)(abs)) continue;
17731
+ const abs = (0, import_node_path41.join)(worktreePath, rel);
17732
+ if (!(0, import_node_fs44.existsSync)(abs)) continue;
17541
17733
  try {
17542
- if (!(0, import_node_fs43.statSync)(abs).isFile()) continue;
17543
- let content = (0, import_node_fs43.readFileSync)(abs, "utf8");
17734
+ if (!(0, import_node_fs44.statSync)(abs).isFile()) continue;
17735
+ let content = (0, import_node_fs44.readFileSync)(abs, "utf8");
17544
17736
  if (!content.trim()) continue;
17545
17737
  if (content.length > MAX_CHARS_PER_FILE) {
17546
17738
  content = `${content.slice(0, MAX_CHARS_PER_FILE)}
@@ -17580,12 +17772,12 @@ function withAgentInstructions(prompt, files) {
17580
17772
 
17581
17773
  ${prompt}`;
17582
17774
  }
17583
- var import_node_fs43, import_node_path40, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
17775
+ var import_node_fs44, import_node_path41, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
17584
17776
  var init_instructions = __esm({
17585
17777
  "src/agents/instructions.ts"() {
17586
17778
  "use strict";
17587
- import_node_fs43 = require("fs");
17588
- import_node_path40 = require("path");
17779
+ import_node_fs44 = require("fs");
17780
+ import_node_path41 = require("path");
17589
17781
  init_git_auth_mode();
17590
17782
  init_worktree_labels();
17591
17783
  init_detached_job_path();
@@ -17931,40 +18123,40 @@ __export(plan_file_exports, {
17931
18123
  writePlanFile: () => writePlanFile
17932
18124
  });
17933
18125
  function ensureAttachmentsGitignore(worktreePath) {
17934
- const gitignoreAbs = (0, import_node_path41.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
17935
- if ((0, import_node_fs44.existsSync)(gitignoreAbs)) return;
17936
- (0, import_node_fs44.mkdirSync)((0, import_node_path41.dirname)(gitignoreAbs), { recursive: true });
17937
- (0, import_node_fs44.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
18126
+ const gitignoreAbs = (0, import_node_path42.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
18127
+ if ((0, import_node_fs45.existsSync)(gitignoreAbs)) return;
18128
+ (0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(gitignoreAbs), { recursive: true });
18129
+ (0, import_node_fs45.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
17938
18130
  }
17939
18131
  function planFileAbs(worktreePath) {
17940
- return (0, import_node_path41.join)(worktreePath, PLAN_FILE_REL);
18132
+ return (0, import_node_path42.join)(worktreePath, PLAN_FILE_REL);
17941
18133
  }
17942
18134
  function readTextIfPresent2(abs) {
17943
- if (!(0, import_node_fs44.existsSync)(abs)) return null;
18135
+ if (!(0, import_node_fs45.existsSync)(abs)) return null;
17944
18136
  try {
17945
- const content = (0, import_node_fs44.readFileSync)(abs, "utf8");
18137
+ const content = (0, import_node_fs45.readFileSync)(abs, "utf8");
17946
18138
  return content.trim() ? content : null;
17947
18139
  } catch {
17948
18140
  return null;
17949
18141
  }
17950
18142
  }
17951
18143
  function readPlanFile(worktreePath) {
17952
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path41.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path41.join)(worktreePath, LEGACY_PLAN_FILE_REL));
18144
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path42.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path42.join)(worktreePath, LEGACY_PLAN_FILE_REL));
17953
18145
  }
17954
18146
  function writePlanFile(worktreePath, content) {
17955
18147
  ensureAttachmentsGitignore(worktreePath);
17956
18148
  const abs = planFileAbs(worktreePath);
17957
- (0, import_node_fs44.mkdirSync)((0, import_node_path41.dirname)(abs), { recursive: true });
18149
+ (0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(abs), { recursive: true });
17958
18150
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
17959
- (0, import_node_fs44.writeFileSync)(abs, body, "utf8");
18151
+ (0, import_node_fs45.writeFileSync)(abs, body, "utf8");
17960
18152
  return PLAN_FILE_REL;
17961
18153
  }
17962
- var import_node_fs44, import_node_path41;
18154
+ var import_node_fs45, import_node_path42;
17963
18155
  var init_plan_file = __esm({
17964
18156
  "src/plan/plan-file.ts"() {
17965
18157
  "use strict";
17966
- import_node_fs44 = require("fs");
17967
- import_node_path41 = require("path");
18158
+ import_node_fs45 = require("fs");
18159
+ import_node_path42 = require("path");
17968
18160
  init_workspace_scratch();
17969
18161
  init_plan_present();
17970
18162
  init_plan_present();
@@ -18012,13 +18204,13 @@ var init_sync_branch = __esm({
18012
18204
 
18013
18205
  // src/agents/cursor-store.ts
18014
18206
  function cursorSdkStoreDir(threadId) {
18015
- const root = (0, import_node_path42.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
18207
+ const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
18016
18208
  const id = sanitizeCursorStoreSegment(threadId);
18017
18209
  if (!id) return root;
18018
- return (0, import_node_path42.join)(root, "threads", id);
18210
+ return (0, import_node_path43.join)(root, "threads", id);
18019
18211
  }
18020
18212
  function cursorSdkRunsNdjsonPath(threadId) {
18021
- return (0, import_node_path42.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
18213
+ return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
18022
18214
  }
18023
18215
  function cursorSdkRunsNdjsonSearchPaths(threadId) {
18024
18216
  const scoped = cursorSdkRunsNdjsonPath(threadId);
@@ -18031,11 +18223,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
18031
18223
  function sanitizeCursorStoreSegment(threadId) {
18032
18224
  return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
18033
18225
  }
18034
- var import_node_path42, CURSOR_SDK_STORE_DIR;
18226
+ var import_node_path43, CURSOR_SDK_STORE_DIR;
18035
18227
  var init_cursor_store = __esm({
18036
18228
  "src/agents/cursor-store.ts"() {
18037
18229
  "use strict";
18038
- import_node_path42 = require("path");
18230
+ import_node_path43 = require("path");
18039
18231
  init_paths();
18040
18232
  CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
18041
18233
  }
@@ -18057,9 +18249,9 @@ function recoverFinishedCursorRun(opts) {
18057
18249
  return best;
18058
18250
  }
18059
18251
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
18060
- if (!(0, import_node_fs45.existsSync)(runsPath)) return null;
18252
+ if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
18061
18253
  try {
18062
- const lines = (0, import_node_fs45.readFileSync)(runsPath, "utf8").split("\n");
18254
+ const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
18063
18255
  let best = null;
18064
18256
  for (const line of lines) {
18065
18257
  const trimmed = line.trim();
@@ -18085,11 +18277,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
18085
18277
  return null;
18086
18278
  }
18087
18279
  }
18088
- var import_node_fs45;
18280
+ var import_node_fs46;
18089
18281
  var init_cursor_recover = __esm({
18090
18282
  "src/agents/cursor-recover.ts"() {
18091
18283
  "use strict";
18092
- import_node_fs45 = require("fs");
18284
+ import_node_fs46 = require("fs");
18093
18285
  init_cursor_store();
18094
18286
  }
18095
18287
  });
@@ -18128,6 +18320,7 @@ var init_title = __esm({
18128
18320
  // src/orchestrator/orchestrator.ts
18129
18321
  var orchestrator_exports = {};
18130
18322
  __export(orchestrator_exports, {
18323
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
18131
18324
  Orchestrator: () => Orchestrator,
18132
18325
  getOrchestrator: () => getOrchestrator,
18133
18326
  isPidAlive: () => isPidAlive,
@@ -18220,13 +18413,13 @@ async function startOrchestration(opts) {
18220
18413
  }
18221
18414
  return updated;
18222
18415
  }
18223
- var import_node_events, import_node_fs46, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
18416
+ var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
18224
18417
  var init_orchestrator = __esm({
18225
18418
  "src/orchestrator/orchestrator.ts"() {
18226
18419
  "use strict";
18227
18420
  import_node_events = require("events");
18228
18421
  init_outbound_watch();
18229
- import_node_fs46 = require("fs");
18422
+ import_node_fs47 = require("fs");
18230
18423
  init_error_detail();
18231
18424
  init_run();
18232
18425
  init_stale_lock();
@@ -18241,6 +18434,7 @@ var init_orchestrator = __esm({
18241
18434
  init_orphan_cleanup();
18242
18435
  init_apply_into_main();
18243
18436
  init_clone_repo();
18437
+ init_message_parts();
18244
18438
  init_usage();
18245
18439
  init_thread_store();
18246
18440
  init_desktop_host();
@@ -18278,6 +18472,7 @@ var init_orchestrator = __esm({
18278
18472
  init_caffeinate_hold();
18279
18473
  init_schedule_runner();
18280
18474
  init_coordinator_prompt();
18475
+ LIVE_TURN_SPAWN_GRACE_MS = 15e3;
18281
18476
  STALE_AGENT_PID_WAIT_MS = 2500;
18282
18477
  Orchestrator = class {
18283
18478
  events = new import_node_events.EventEmitter();
@@ -18334,6 +18529,39 @@ var init_orchestrator = __esm({
18334
18529
  if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
18335
18530
  return true;
18336
18531
  }
18532
+ /**
18533
+ * Whether a child is actually turning — not leftover disk `running` after
18534
+ * the process died. Coordinators were telling users “Agent is running.
18535
+ * Waiting for gate to pass” from stale stillRunning.
18536
+ */
18537
+ threadLooksLive(thread) {
18538
+ if (thread.status === "queued") {
18539
+ if (this.draining.has(thread.id) || this.startingTurns.has(thread.id)) return true;
18540
+ return thread.queue.length > 0;
18541
+ }
18542
+ if (thread.status !== "running") return false;
18543
+ if (this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id)) return true;
18544
+ const pid = thread.agentPid;
18545
+ if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return true;
18546
+ const updated = Date.parse(thread.updatedAt ?? "");
18547
+ if (Number.isFinite(updated) && Date.now() - updated < LIVE_TURN_SPAWN_GRACE_MS) return true;
18548
+ return false;
18549
+ }
18550
+ /** Desktop-only: persist idle/stopped when MCP would otherwise keep reporting live. */
18551
+ healStaleReportedActivity(thread) {
18552
+ if (!thisProcessShouldDrainAgentQueues()) return thread;
18553
+ if (this.threadLooksLive(thread)) return thread;
18554
+ if (thread.status === "running") {
18555
+ this.healStaleRunningTurns();
18556
+ return readThread(thread.id) ?? thread;
18557
+ }
18558
+ if (thread.status === "queued" && thread.queue.length === 0 && !this.activeTurns.has(thread.id) && !this.startingTurns.has(thread.id) && !this.draining.has(thread.id)) {
18559
+ setStatus(thread.id, "idle");
18560
+ this.emit({ type: "status_changed", threadId: thread.id, status: "idle" });
18561
+ return readThread(thread.id) ?? thread;
18562
+ }
18563
+ return thread;
18564
+ }
18337
18565
  async reconcile(repoPath, opts) {
18338
18566
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
18339
18567
  const drainQueues = opts?.drainQueues !== false;
@@ -18358,7 +18586,7 @@ var init_orchestrator = __esm({
18358
18586
  }
18359
18587
  continue;
18360
18588
  }
18361
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
18589
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
18362
18590
  setStatus(thread.id, "broken", "Worktree missing on disk");
18363
18591
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
18364
18592
  continue;
@@ -18668,12 +18896,14 @@ var init_orchestrator = __esm({
18668
18896
  this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
18669
18897
  return thread;
18670
18898
  }
18671
- async send(threadRef, prompt) {
18899
+ async send(threadRef, prompt, opts) {
18672
18900
  const thread = this.requireThread(threadRef);
18673
18901
  if (thread.status === "archived") {
18674
18902
  throw new Error(`Thread is archived: ${thread.id}`);
18675
18903
  }
18676
- return withThreadLock(thread.id, async () => {
18904
+ const followUp = opts?.followUp === "steer" ? "steer" : "queue";
18905
+ let shouldSteer = false;
18906
+ const sent = await withThreadLock(thread.id, async () => {
18677
18907
  const current = this.requireThread(thread.id);
18678
18908
  if (current.status === "archived") {
18679
18909
  throw new Error(`Thread is archived: ${thread.id}`);
@@ -18682,6 +18912,7 @@ var init_orchestrator = __esm({
18682
18912
  this.crashContinued.delete(thread.id);
18683
18913
  this.haltDrain.delete(thread.id);
18684
18914
  const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
18915
+ shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
18685
18916
  const patch = { queue };
18686
18917
  if (!inFlight) patch.status = "queued";
18687
18918
  const pid = current.agentPid;
@@ -18693,16 +18924,20 @@ var init_orchestrator = __esm({
18693
18924
  if (!inFlight) {
18694
18925
  this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
18695
18926
  }
18696
- if (thisProcessShouldDrainAgentQueues()) {
18927
+ if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
18697
18928
  void this.drainQueue(thread.id);
18698
18929
  }
18699
18930
  return this.requireThread(thread.id);
18700
18931
  });
18932
+ if (shouldSteer && sent.queue.length > 0) {
18933
+ return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
18934
+ }
18935
+ return sent;
18701
18936
  }
18702
- async fanOut(threadRefs, prompt) {
18937
+ async fanOut(threadRefs, prompt, opts) {
18703
18938
  const results = [];
18704
18939
  for (const ref of threadRefs) {
18705
- results.push(await this.send(ref, prompt));
18940
+ results.push(await this.send(ref, prompt, opts));
18706
18941
  }
18707
18942
  return results;
18708
18943
  }
@@ -19506,8 +19741,8 @@ var init_orchestrator = __esm({
19506
19741
  return created;
19507
19742
  }
19508
19743
  async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
19509
- const thread = this.requireThread(threadRef);
19510
- if (!["running", "queued"].includes(thread.status)) {
19744
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19745
+ if (!this.threadLooksLive(thread)) {
19511
19746
  return thread;
19512
19747
  }
19513
19748
  const start = Date.now();
@@ -19544,12 +19779,13 @@ var init_orchestrator = __esm({
19544
19779
  }
19545
19780
  });
19546
19781
  timer = setInterval(() => {
19547
- const current = readThread(thread.id);
19548
- if (!current) {
19782
+ const raw = readThread(thread.id);
19783
+ if (!raw) {
19549
19784
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
19550
19785
  return;
19551
19786
  }
19552
- if (!["running", "queued"].includes(current.status)) {
19787
+ const current = this.healStaleReportedActivity(raw);
19788
+ if (!this.threadLooksLive(current)) {
19553
19789
  finish(() => resolve(current));
19554
19790
  return;
19555
19791
  }
@@ -19572,20 +19808,22 @@ var init_orchestrator = __esm({
19572
19808
  };
19573
19809
  }
19574
19810
  getTurnResult(threadRef) {
19575
- const thread = this.requireThread(threadRef);
19811
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19576
19812
  const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
19577
19813
  const lastError = thread.lastError ?? null;
19578
- const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
19579
- const stillRunning = thread.status === "running" || thread.status === "queued";
19814
+ const rawText = (lastAgent?.text ?? "").trim();
19815
+ const text5 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
19816
+ const stillRunning = this.threadLooksLive(thread);
19580
19817
  const live = stillRunning ? readTurnLive(thread.id) : null;
19581
- const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
19818
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
19819
+ const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
19582
19820
  return {
19583
19821
  text: text5,
19584
19822
  status: thread.status,
19585
19823
  sessionId: thread.sessionId,
19586
19824
  lastError,
19587
19825
  stillRunning,
19588
- progress: live?.summary ?? queuedHint,
19826
+ progress: liveSummary ?? queuedHint,
19589
19827
  lastActivityAt: live?.updatedAt ?? null,
19590
19828
  usage: lastAgent?.usage ?? null
19591
19829
  };
@@ -19933,7 +20171,14 @@ var init_orchestrator = __esm({
19933
20171
  );
19934
20172
  }
19935
20173
  if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
19936
- await this.pushAndMaybeOpenPr(thread, action);
20174
+ try {
20175
+ await this.pushAndMaybeOpenPr(thread, action);
20176
+ } catch (err) {
20177
+ const message = err instanceof Error ? err.message : String(err);
20178
+ updateThread(thread.id, { lastError: message });
20179
+ this.emit({ type: "error", threadId: thread.id, message });
20180
+ throw err;
20181
+ }
19937
20182
  return this.requireThread(threadRef);
19938
20183
  }
19939
20184
  let prBase;
@@ -20136,7 +20381,7 @@ var init_orchestrator = __esm({
20136
20381
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
20137
20382
  return restored2;
20138
20383
  }
20139
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
20384
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
20140
20385
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
20141
20386
  throw new Error(
20142
20387
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -20148,6 +20393,8 @@ var init_orchestrator = __esm({
20148
20393
  await withRepoGitLock(thread.repoPath, async () => {
20149
20394
  await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
20150
20395
  });
20396
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
20397
+ await ensureWorktreeSideboardIgnored2(dest);
20151
20398
  void createThreadWorktree2;
20152
20399
  void slug;
20153
20400
  }
@@ -20362,7 +20609,10 @@ __export(index_exports, {
20362
20609
  DEFAULT_ABLETIME_HOST: () => DEFAULT_ABLETIME_HOST,
20363
20610
  DEFAULT_WORKTREE_SORT: () => DEFAULT_WORKTREE_SORT,
20364
20611
  FAMOUS_SOCCER_TEAMS: () => FAMOUS_SOCCER_TEAMS,
20612
+ FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
20365
20613
  GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
20614
+ GITHUB_PR_BODY_MAX_CHARS: () => GITHUB_PR_BODY_MAX_CHARS,
20615
+ GITHUB_PR_BODY_SAFE_CHARS: () => GITHUB_PR_BODY_SAFE_CHARS,
20366
20616
  GLOBAL_WORKSPACE_ID: () => GLOBAL_WORKSPACE_ID,
20367
20617
  HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
20368
20618
  HOME_BOARD_CACHE_TTL_MS: () => HOME_BOARD_CACHE_TTL_MS,
@@ -20374,6 +20624,7 @@ __export(index_exports, {
20374
20624
  LINEAR_OAUTH_PORT: () => LINEAR_OAUTH_PORT,
20375
20625
  LINEAR_OAUTH_REDIRECT: () => LINEAR_OAUTH_REDIRECT,
20376
20626
  LINEAR_OAUTH_SCOPES: () => LINEAR_OAUTH_SCOPES,
20627
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
20377
20628
  LONG_RUNNING_SKILL_COMMAND: () => LONG_RUNNING_SKILL_COMMAND,
20378
20629
  LinearOAuthCancelledError: () => LinearOAuthCancelledError,
20379
20630
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS: () => MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
@@ -20463,6 +20714,7 @@ __export(index_exports, {
20463
20714
  buildCodeRefAttachment: () => buildCodeRefAttachment,
20464
20715
  buildDiffCommentAttachment: () => buildDiffCommentAttachment,
20465
20716
  buildForkTranscriptAttachment: () => buildForkTranscriptAttachment,
20717
+ buildLinearIssueFilter: () => buildLinearIssueFilter,
20466
20718
  buildPastedTextAttachment: () => buildPastedTextAttachment,
20467
20719
  buildPathRefAttachment: () => buildPathRefAttachment,
20468
20720
  buildReviewRequestAttachment: () => buildReviewRequestAttachment,
@@ -20480,6 +20732,7 @@ __export(index_exports, {
20480
20732
  checkoutPrStackLayer: () => checkoutPrStackLayer,
20481
20733
  childEnvWithAppSettings: () => childEnvWithAppSettings,
20482
20734
  claimDesktopHost: () => claimDesktopHost,
20735
+ clampGithubPrBody: () => clampGithubPrBody,
20483
20736
  classifyWorktreeColumn: () => classifyWorktreeColumn,
20484
20737
  claudeAdapter: () => claudeAdapter,
20485
20738
  claudeChromeEnabled: () => claudeChromeEnabled,
@@ -20584,6 +20837,7 @@ __export(index_exports, {
20584
20837
  fireSchedule: () => fireSchedule,
20585
20838
  flattenTurnInput: () => flattenTurnInput,
20586
20839
  flipLinearRelationType: () => flipLinearRelationType,
20840
+ followUpBehavior: () => followUpBehavior,
20587
20841
  forkChatTab: () => forkChatTab,
20588
20842
  forkMessageSlice: () => forkMessageSlice,
20589
20843
  forkThreadWorktree: () => forkThreadWorktree,
@@ -20662,6 +20916,7 @@ __export(index_exports, {
20662
20916
  ghRepoSelectArgs: () => ghRepoSelectArgs,
20663
20917
  git: () => git,
20664
20918
  githubAgentGitEnv: () => githubAgentGitEnv,
20919
+ githubHttpsInsteadOfEntries: () => githubHttpsInsteadOfEntries,
20665
20920
  globalAgentCwd: () => globalAgentCwd,
20666
20921
  groupHomeBoardWorktrees: () => groupHomeBoardWorktrees,
20667
20922
  handleSlackInbound: () => handleSlackInbound,
@@ -20698,6 +20953,7 @@ __export(index_exports, {
20698
20953
  isDefaultishSourceRef: () => isDefaultishSourceRef,
20699
20954
  isDesktopHostAlive: () => isDesktopHostAlive,
20700
20955
  isDirty: () => isDirty,
20956
+ isGhPrBodyTooLongError: () => isGhPrBodyTooLongError,
20701
20957
  isGhRateLimitError: () => isGhRateLimitError,
20702
20958
  isGlobalRepoPath: () => isGlobalRepoPath,
20703
20959
  isGlobalThread: () => isGlobalThread,
@@ -20705,6 +20961,7 @@ __export(index_exports, {
20705
20961
  isImageFilePath: () => isImageFilePath,
20706
20962
  isInPrStack: () => isInPrStack,
20707
20963
  isInboundForThisDesktop: () => isInboundForThisDesktop,
20964
+ isInternalAgentStatusText: () => isInternalAgentStatusText,
20708
20965
  isIssueSourceConnected: () => isIssueSourceConnected,
20709
20966
  isLinearConnected: () => isLinearConnected,
20710
20967
  isLinearOAuthCancelled: () => isLinearOAuthCancelled,
@@ -20731,6 +20988,7 @@ __export(index_exports, {
20731
20988
  isThreadRecordFile: () => isThreadRecordFile,
20732
20989
  isWorkspaceScratchPath: () => isWorkspaceScratchPath,
20733
20990
  issueAttachmentForAbleTimeTask: () => issueAttachmentForAbleTimeTask,
20991
+ issueMatchesAssignee: () => issueMatchesAssignee,
20734
20992
  issueSourceLabel: () => issueSourceLabel,
20735
20993
  lastRequestOccupancy: () => lastRequestOccupancy,
20736
20994
  latestPendingPlanQuestions: () => latestPendingPlanQuestions,
@@ -20758,6 +21016,7 @@ __export(index_exports, {
20758
21016
  listLinearAssignedIssues: () => listLinearAssignedIssues,
20759
21017
  listLinearIssues: () => listLinearIssues,
20760
21018
  listLinearIssuesDirect: () => listLinearIssuesDirect,
21019
+ listLinearIssuesFiltered: () => listLinearIssuesFiltered,
20761
21020
  listLinearTeams: () => listLinearTeams,
20762
21021
  listModelsForAgent: () => listModelsForAgent,
20763
21022
  listOpencodeModels: () => listOpencodeModels,
@@ -21099,7 +21358,7 @@ async function refreshGitHubAuth() {
21099
21358
  init_fetch();
21100
21359
 
21101
21360
  // src/integrations/linear-oauth.ts
21102
- var import_node_crypto9 = require("crypto");
21361
+ var import_node_crypto10 = require("crypto");
21103
21362
  var import_node_http = require("http");
21104
21363
  init_app_settings();
21105
21364
  init_fetch();
@@ -21131,8 +21390,8 @@ function linearOAuthCredentials() {
21131
21390
  return { clientId, clientSecret };
21132
21391
  }
21133
21392
  function createLinearPkce() {
21134
- const verifier = (0, import_node_crypto9.randomBytes)(32).toString("base64url");
21135
- const challenge = (0, import_node_crypto9.createHash)("sha256").update(verifier).digest("base64url");
21393
+ const verifier = (0, import_node_crypto10.randomBytes)(32).toString("base64url");
21394
+ const challenge = (0, import_node_crypto10.createHash)("sha256").update(verifier).digest("base64url");
21136
21395
  return { verifier, challenge };
21137
21396
  }
21138
21397
  function linearOAuthAuthorizeUrl(clientId, state, codeChallenge) {
@@ -21263,7 +21522,7 @@ async function startLinearOAuth(opts) {
21263
21522
  throw new LinearOAuthCancelledError();
21264
21523
  }
21265
21524
  const { clientId, clientSecret } = linearOAuthCredentials();
21266
- const state = (0, import_node_crypto9.randomBytes)(16).toString("hex");
21525
+ const state = (0, import_node_crypto10.randomBytes)(16).toString("hex");
21267
21526
  const pkce = createLinearPkce();
21268
21527
  const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
21269
21528
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
@@ -21451,6 +21710,22 @@ query SideboardAssignedIssues($first: Int!) {
21451
21710
  }
21452
21711
  }
21453
21712
  `;
21713
+ var ISSUES_QUERY = `
21714
+ query SideboardIssues($first: Int!, $filter: IssueFilter) {
21715
+ viewer { id name }
21716
+ issues(first: $first, orderBy: updatedAt, filter: $filter) {
21717
+ nodes { ${LIST_ISSUE_FIELDS} }
21718
+ }
21719
+ }
21720
+ `;
21721
+ var SEARCH_ISSUES_QUERY = `
21722
+ query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
21723
+ viewer { id name }
21724
+ searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
21725
+ nodes { ${LIST_ISSUE_FIELDS} }
21726
+ }
21727
+ }
21728
+ `;
21454
21729
  var TEAMS_QUERY = `
21455
21730
  query SideboardTeams {
21456
21731
  viewer { id name }
@@ -21734,19 +22009,76 @@ function normalizePriority(priority) {
21734
22009
  }
21735
22010
  return priority;
21736
22011
  }
21737
- async function listLinearAssignedIssues(opts) {
21738
- const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
21739
- const json = await linearGraphql(ASSIGNED_ISSUES_QUERY, { first }, opts);
22012
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
22013
+ function assigneeFilterKey(assignee) {
22014
+ return (assignee ?? "").trim();
22015
+ }
22016
+ function buildLinearIssueFilter(input) {
22017
+ const filter = {
22018
+ state: { type: { nin: ["completed", "canceled"] } }
22019
+ };
22020
+ const raw = assigneeFilterKey(input?.assignee) || "me";
22021
+ const key = raw.toLowerCase();
22022
+ if (key === "all" || key === "*") return filter;
22023
+ if (key === "unassigned" || key === "none" || key === "null") {
22024
+ filter.assignee = { null: true };
22025
+ return filter;
22026
+ }
22027
+ if (key === "me" || key === "@me") {
22028
+ filter.assignee = { isMe: true };
22029
+ return filter;
22030
+ }
22031
+ if (UUID_RE.test(raw)) {
22032
+ filter.assignee = { id: { eq: raw } };
22033
+ return filter;
22034
+ }
22035
+ filter.assignee = { name: { eqIgnoreCase: raw } };
22036
+ return filter;
22037
+ }
22038
+ function isAssignedToMe(assignee) {
22039
+ const key = assignee.toLowerCase();
22040
+ return key === "me" || key === "@me";
22041
+ }
22042
+ function listedLinearIssues(json, nodes) {
21740
22043
  return {
21741
22044
  viewer: {
21742
22045
  id: String(json.viewer?.id ?? ""),
21743
22046
  name: String(json.viewer?.name ?? "")
21744
22047
  },
21745
- issues: (json.viewer?.assignedIssues?.nodes ?? []).map(
21746
- (node) => toIssueInfo(mapIssue(node))
21747
- )
22048
+ issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
21748
22049
  };
21749
22050
  }
22051
+ async function listLinearIssuesFiltered(opts) {
22052
+ const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
22053
+ const query = opts?.query?.trim() ?? "";
22054
+ const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
22055
+ const filter = buildLinearIssueFilter({ assignee });
22056
+ if (query) {
22057
+ const json2 = await linearGraphql(
22058
+ SEARCH_ISSUES_QUERY,
22059
+ { term: query, first, filter },
22060
+ opts
22061
+ );
22062
+ return listedLinearIssues(json2, json2.searchIssues?.nodes);
22063
+ }
22064
+ if (isAssignedToMe(assignee)) {
22065
+ const json2 = await linearGraphql(
22066
+ ASSIGNED_ISSUES_QUERY,
22067
+ { first },
22068
+ opts
22069
+ );
22070
+ return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
22071
+ }
22072
+ const json = await linearGraphql(
22073
+ ISSUES_QUERY,
22074
+ { first, filter },
22075
+ opts
22076
+ );
22077
+ return listedLinearIssues(json, json.issues?.nodes);
22078
+ }
22079
+ async function listLinearAssignedIssues(opts) {
22080
+ return listLinearIssuesFiltered({ ...opts, assignee: "me" });
22081
+ }
21750
22082
  async function listLinearIssuesDirect(opts) {
21751
22083
  return (await listLinearAssignedIssues(opts)).issues;
21752
22084
  }
@@ -21874,6 +22206,22 @@ init_worktree();
21874
22206
  init_run();
21875
22207
  init_app_settings();
21876
22208
  init_abletime();
22209
+ function assigneeKey(assignee) {
22210
+ return (assignee ?? "").trim().toLowerCase();
22211
+ }
22212
+ function issueMatchesAssignee(issue, assignee, viewerName = "") {
22213
+ const key = assigneeKey(assignee);
22214
+ if (!key || key === "all" || key === "*") return true;
22215
+ const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
22216
+ if (key === "unassigned" || key === "none" || key === "null") {
22217
+ return names.length === 0;
22218
+ }
22219
+ if (key === "me" || key === "@me") {
22220
+ const me = viewerName.trim().toLowerCase();
22221
+ return Boolean(me && names.includes(me));
22222
+ }
22223
+ return names.includes(key);
22224
+ }
21877
22225
  async function listGitHubIssues(repoPath, opts) {
21878
22226
  const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
21879
22227
  const slug = await resolveGithubRepoSlug(repoPath);
@@ -21887,6 +22235,17 @@ async function listGitHubIssues(repoPath, opts) {
21887
22235
  "--state",
21888
22236
  "open"
21889
22237
  ];
22238
+ const query = opts?.query?.trim() ?? "";
22239
+ const assignee = opts?.assignee?.trim() ?? "";
22240
+ const key = assignee.toLowerCase();
22241
+ const searchParts = [];
22242
+ if (query) searchParts.push(query);
22243
+ if (key === "unassigned" || key === "none" || key === "null") {
22244
+ searchParts.push("no:assignee");
22245
+ } else if (key && key !== "all" && key !== "*") {
22246
+ args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
22247
+ }
22248
+ if (searchParts.length) args.push("--search", searchParts.join(" "));
21890
22249
  if (slug) args.push("--repo", slug);
21891
22250
  const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
21892
22251
  if (exitCode !== 0 || !stdout.trim()) return [];
@@ -21924,14 +22283,20 @@ async function githubViewerLogin(repoPath) {
21924
22283
  if (exitCode !== 0) return "";
21925
22284
  return stdout.trim();
21926
22285
  }
21927
- async function listIssues(repoPath) {
22286
+ async function listIssues(repoPath, opts) {
21928
22287
  const settings = loadAppSettings();
21929
22288
  const preferredSource = settings.integrations.issueSource ?? "github";
21930
22289
  const linearConnected = isLinearConnected(settings);
21931
22290
  const abletimeConnected = isAbleTimeConnected(settings);
21932
22291
  const source = resolveEffectiveIssueSource(settings);
22292
+ const query = opts?.query?.trim() || void 0;
22293
+ const assignee = opts?.assignee?.trim() || void 0;
21933
22294
  if (source === "linear") {
21934
- const listed = await listLinearAssignedIssues();
22295
+ const listed = await listLinearIssuesFiltered({
22296
+ assignee,
22297
+ query,
22298
+ limit: opts?.limit
22299
+ });
21935
22300
  return {
21936
22301
  source,
21937
22302
  preferredSource,
@@ -21945,13 +22310,20 @@ async function listIssues(repoPath) {
21945
22310
  };
21946
22311
  }
21947
22312
  if (source === "abletime") {
21948
- const listed = await listAbleTimeAssignedIssues();
22313
+ const [listed, searched] = await Promise.all([
22314
+ listAbleTimeAssignedIssues(),
22315
+ query ? searchAbleTimeTasks(query) : Promise.resolve(null)
22316
+ ]);
22317
+ const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
22318
+ const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
22319
+ (issue) => issueMatchesAssignee(issue, assignee, viewerName)
22320
+ );
21949
22321
  return {
21950
22322
  source,
21951
22323
  preferredSource,
21952
22324
  linearConnected,
21953
22325
  abletimeConnected,
21954
- issues: listed.issues,
22326
+ issues: issues2,
21955
22327
  viewer: {
21956
22328
  login: listed.viewer.name,
21957
22329
  name: listed.viewer.name
@@ -21959,7 +22331,7 @@ async function listIssues(repoPath) {
21959
22331
  };
21960
22332
  }
21961
22333
  const [issues, login] = await Promise.all([
21962
- listGitHubIssues(repoPath),
22334
+ listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
21963
22335
  githubViewerLogin(repoPath)
21964
22336
  ]);
21965
22337
  return {
@@ -22179,7 +22551,7 @@ function buildPathRefAttachment(input) {
22179
22551
  init_stage_files();
22180
22552
 
22181
22553
  // src/composer/pasted-text.ts
22182
- var import_node_crypto10 = require("crypto");
22554
+ var import_node_crypto11 = require("crypto");
22183
22555
  var PASTE_ATTACH_MIN_CHARS = 1200;
22184
22556
  var PASTE_ATTACH_MIN_LINES = 15;
22185
22557
  var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
@@ -22206,7 +22578,7 @@ function nextPastedTextName(existing) {
22206
22578
  }
22207
22579
  function buildPastedTextAttachment(text5, opts) {
22208
22580
  return {
22209
- id: opts?.id ?? (0, import_node_crypto10.randomUUID)(),
22581
+ id: opts?.id ?? (0, import_node_crypto11.randomUUID)(),
22210
22582
  name: opts?.name ?? "Pasted text #1.txt",
22211
22583
  kind: "file",
22212
22584
  path: opts?.path,
@@ -22358,8 +22730,8 @@ init_orphan_cleanup();
22358
22730
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
22359
22731
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
22360
22732
  var import_zod5 = require("zod");
22361
- var import_node_crypto12 = require("crypto");
22362
- var import_node_path45 = require("path");
22733
+ var import_node_crypto13 = require("crypto");
22734
+ var import_node_path46 = require("path");
22363
22735
  init_orchestrator();
22364
22736
  init_worktree();
22365
22737
  init_create();
@@ -22401,14 +22773,16 @@ function mcpWaitFinishedHint(status) {
22401
22773
  }
22402
22774
 
22403
22775
  // src/mcp/server.ts
22776
+ init_message_parts();
22404
22777
  init_turn_live();
22405
22778
 
22406
22779
  // src/mcp/thread-visibility.ts
22780
+ init_message_parts();
22407
22781
  function lastMessagePreview(messages, max = 160) {
22408
22782
  if (!messages?.length) return null;
22409
22783
  for (let i = messages.length - 1; i >= 0; i--) {
22410
22784
  const text5 = messages[i]?.text?.trim();
22411
- if (!text5) continue;
22785
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
22412
22786
  const flat = text5.replace(/\s+/g, " ");
22413
22787
  return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
22414
22788
  }
@@ -23078,6 +23452,22 @@ function registerLinearTools(server) {
23078
23452
  }
23079
23453
  }
23080
23454
  );
23455
+ server.tool(
23456
+ "linear_search_issues",
23457
+ "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).",
23458
+ {
23459
+ query: import_zod3.z.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
23460
+ 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."),
23461
+ limit: import_zod3.z.number().int().positive().max(250).optional()
23462
+ },
23463
+ async ({ query, assignee, limit }) => {
23464
+ try {
23465
+ return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
23466
+ } catch (err) {
23467
+ return fail3(err);
23468
+ }
23469
+ }
23470
+ );
23081
23471
  server.tool(
23082
23472
  "linear_get_issue",
23083
23473
  "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.",
@@ -23312,30 +23702,31 @@ function registerScheduleTools(server) {
23312
23702
 
23313
23703
  // src/mcp/server.ts
23314
23704
  init_agent_git_actions();
23705
+ init_gh_errors();
23315
23706
  init_git_auth_mode();
23316
23707
 
23317
23708
  // src/board/load-home-board.ts
23318
- var import_node_fs48 = require("fs");
23319
- var import_node_path44 = require("path");
23709
+ var import_node_fs49 = require("fs");
23710
+ var import_node_path45 = require("path");
23320
23711
  init_worktree();
23321
23712
  init_paths();
23322
23713
 
23323
23714
  // src/board/board-pins.ts
23324
- var import_node_crypto11 = require("crypto");
23325
- var import_node_fs47 = require("fs");
23326
- var import_node_path43 = require("path");
23715
+ var import_node_crypto12 = require("crypto");
23716
+ var import_node_fs48 = require("fs");
23717
+ var import_node_path44 = require("path");
23327
23718
  init_paths();
23328
23719
  init_home_board();
23329
23720
  var FILE = "home-board-pins.json";
23330
23721
  var VERSION = 1;
23331
23722
  function pinsFile() {
23332
- return (0, import_node_path43.join)(appDataDir(), FILE);
23723
+ return (0, import_node_path44.join)(appDataDir(), FILE);
23333
23724
  }
23334
23725
  function readDisk() {
23335
23726
  const path2 = pinsFile();
23336
- if (!(0, import_node_fs47.existsSync)(path2)) return [];
23727
+ if (!(0, import_node_fs48.existsSync)(path2)) return [];
23337
23728
  try {
23338
- const raw = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
23729
+ const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
23339
23730
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
23340
23731
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
23341
23732
  } catch {
@@ -23343,8 +23734,8 @@ function readDisk() {
23343
23734
  }
23344
23735
  }
23345
23736
  function writeDisk(items) {
23346
- (0, import_node_fs47.mkdirSync)(appDataDir(), { recursive: true });
23347
- (0, import_node_fs47.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
23737
+ (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
23738
+ (0, import_node_fs48.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
23348
23739
  }
23349
23740
  function listBoardPins() {
23350
23741
  return readDisk();
@@ -23353,7 +23744,7 @@ function addBoardPin(input) {
23353
23744
  const ref = input.ref.trim();
23354
23745
  if (!ref) throw new Error("Board item needs a ref");
23355
23746
  const pin = {
23356
- id: (0, import_node_crypto11.randomUUID)(),
23747
+ id: (0, import_node_crypto12.randomUUID)(),
23357
23748
  kind: input.kind,
23358
23749
  ref,
23359
23750
  repoPath: input.repoPath.trim(),
@@ -23396,7 +23787,7 @@ function replaceBoardPins(items) {
23396
23787
  }
23397
23788
  function clearBoardPins() {
23398
23789
  try {
23399
- (0, import_node_fs47.unlinkSync)(pinsFile());
23790
+ (0, import_node_fs48.unlinkSync)(pinsFile());
23400
23791
  } catch {
23401
23792
  }
23402
23793
  }
@@ -23413,7 +23804,7 @@ function homeBoardWorkspaceKey(workspaces) {
23413
23804
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
23414
23805
  }
23415
23806
  function cacheFile() {
23416
- return (0, import_node_path44.join)(appDataDir(), "home-board-cache.json");
23807
+ return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
23417
23808
  }
23418
23809
  function emptyInputs() {
23419
23810
  return {
@@ -23439,9 +23830,9 @@ function shouldCacheHomeBoardInputs(inputs) {
23439
23830
  }
23440
23831
  function readDiskCache() {
23441
23832
  const path2 = cacheFile();
23442
- if (!(0, import_node_fs48.existsSync)(path2)) return null;
23833
+ if (!(0, import_node_fs49.existsSync)(path2)) return null;
23443
23834
  try {
23444
- const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
23835
+ const raw = JSON.parse((0, import_node_fs49.readFileSync)(path2, "utf8"));
23445
23836
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
23446
23837
  return null;
23447
23838
  }
@@ -23455,14 +23846,14 @@ function readDiskCache() {
23455
23846
  }
23456
23847
  function writeDiskCache(entry) {
23457
23848
  try {
23458
- (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
23459
- (0, import_node_fs48.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
23849
+ (0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
23850
+ (0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
23460
23851
  } catch {
23461
23852
  }
23462
23853
  }
23463
23854
  function deleteDiskCache() {
23464
23855
  try {
23465
- (0, import_node_fs48.unlinkSync)(cacheFile());
23856
+ (0, import_node_fs49.unlinkSync)(cacheFile());
23466
23857
  } catch {
23467
23858
  }
23468
23859
  }
@@ -23759,13 +24150,13 @@ async function startMcpServer() {
23759
24150
  async () => {
23760
24151
  const threads = orch.getThreads(true);
23761
24152
  const lines = threads.map((t) => {
23762
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path45.basename)(t.repoPath) || t.repoPath;
23763
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
24153
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path46.basename)(t.repoPath) || t.repoPath;
24154
+ const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
23764
24155
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
23765
24156
  const preview = lastMessagePreview(t.messages, 80);
23766
24157
  const previewBit = preview ? ` ${preview}` : "";
23767
24158
  const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
23768
- const progress = live?.summary ? ` ${live.summary}` : "";
24159
+ const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
23769
24160
  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}`;
23770
24161
  });
23771
24162
  return {
@@ -23827,7 +24218,9 @@ async function startMcpServer() {
23827
24218
  if (!t) {
23828
24219
  return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
23829
24220
  }
23830
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
24221
+ const stillRunning = orch.threadLooksLive(t);
24222
+ const live = stillRunning ? readTurnLive(t.id) : null;
24223
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
23831
24224
  const spend = orch.getThreadUsage(t.id);
23832
24225
  const summary = {
23833
24226
  id: t.id,
@@ -23847,8 +24240,8 @@ async function startMcpServer() {
23847
24240
  devPort: t.devPort,
23848
24241
  prUrl: t.prUrl,
23849
24242
  lastError: t.lastError ?? null,
23850
- stillRunning: t.status === "running" || t.status === "queued",
23851
- progress: live?.summary ?? (t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
24243
+ stillRunning,
24244
+ progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
23852
24245
  lastActivityAt: live?.updatedAt ?? null,
23853
24246
  usage: spend.usage,
23854
24247
  lastTurnUsage: spend.lastTurnUsage
@@ -24129,7 +24522,7 @@ async function startMcpServer() {
24129
24522
  const ident = issue?.identifier ?? ref.trim();
24130
24523
  const attachments = issue ? [
24131
24524
  {
24132
- id: (0, import_node_crypto12.randomUUID)(),
24525
+ id: (0, import_node_crypto13.randomUUID)(),
24133
24526
  name: issue.identifier,
24134
24527
  kind: "issue",
24135
24528
  content: [
@@ -24205,7 +24598,7 @@ async function startMcpServer() {
24205
24598
  );
24206
24599
  server.tool(
24207
24600
  "wait_for_turn",
24208
- "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).",
24601
+ "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).",
24209
24602
  {
24210
24603
  ref: import_zod5.z.string(),
24211
24604
  timeoutMs: import_zod5.z.number().optional()
@@ -24397,7 +24790,7 @@ async function startMcpServer() {
24397
24790
  );
24398
24791
  server.tool(
24399
24792
  "ask_git",
24400
- "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.",
24793
+ "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.",
24401
24794
  {
24402
24795
  ref: import_zod5.z.string().describe("Worktree thread id/ref"),
24403
24796
  action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
@@ -24422,8 +24815,26 @@ async function startMcpServer() {
24422
24815
  ]
24423
24816
  };
24424
24817
  } catch (err) {
24425
- const message = err instanceof Error ? err.message : String(err);
24426
- return { content: [{ type: "text", text: message }], isError: true };
24818
+ const raw = err instanceof Error ? err.message : String(err);
24819
+ const message = formatGhLandError(raw);
24820
+ return {
24821
+ content: [
24822
+ {
24823
+ type: "text",
24824
+ text: JSON.stringify(
24825
+ {
24826
+ error: true,
24827
+ action,
24828
+ lastError: message,
24829
+ 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
24830
+ },
24831
+ null,
24832
+ 2
24833
+ )
24834
+ }
24835
+ ],
24836
+ isError: true
24837
+ };
24427
24838
  }
24428
24839
  }
24429
24840
  );
@@ -24818,11 +25229,15 @@ async function startMcpServer() {
24818
25229
  );
24819
25230
  server.tool(
24820
25231
  "list_issues",
24821
- "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.",
24822
- { repoPath: import_zod5.z.string() },
24823
- async ({ repoPath }) => {
25232
+ "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.",
25233
+ {
25234
+ repoPath: import_zod5.z.string(),
25235
+ query: import_zod5.z.string().optional().describe("Search title, identifier, or description"),
25236
+ assignee: import_zod5.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
25237
+ },
25238
+ async ({ repoPath, query, assignee }) => {
24824
25239
  const root = await resolveRepoRoot(repoPath);
24825
- const result = await listIssues(root);
25240
+ const result = await listIssues(root, { query, assignee });
24826
25241
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
24827
25242
  }
24828
25243
  );
@@ -25169,16 +25584,16 @@ init_oauth();
25169
25584
  init_injected_mcp();
25170
25585
 
25171
25586
  // src/agents/user-mcp-config.ts
25172
- var import_node_fs49 = require("fs");
25173
- var import_node_os12 = require("os");
25174
- var import_node_path46 = require("path");
25587
+ var import_node_fs50 = require("fs");
25588
+ var import_node_os13 = require("os");
25589
+ var import_node_path47 = require("path");
25175
25590
  init_paths();
25176
25591
  init_injected_mcp();
25177
25592
  function userCursorMcpConfigPath() {
25178
- return (0, import_node_path46.join)((0, import_node_os12.homedir)(), ".cursor", "mcp.json");
25593
+ return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".cursor", "mcp.json");
25179
25594
  }
25180
25595
  function userClaudeMcpConfigPath() {
25181
- return (0, import_node_path46.join)((0, import_node_os12.homedir)(), ".claude.json");
25596
+ return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".claude.json");
25182
25597
  }
25183
25598
  function asObject(value) {
25184
25599
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -25205,16 +25620,16 @@ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
25205
25620
  }
25206
25621
  function writeMergedMcpServersJson(configPath, sideboard) {
25207
25622
  let existing = {};
25208
- if ((0, import_node_fs49.existsSync)(configPath)) {
25623
+ if ((0, import_node_fs50.existsSync)(configPath)) {
25209
25624
  try {
25210
- existing = JSON.parse((0, import_node_fs49.readFileSync)(configPath, "utf8"));
25625
+ existing = JSON.parse((0, import_node_fs50.readFileSync)(configPath, "utf8"));
25211
25626
  } catch {
25212
25627
  existing = {};
25213
25628
  }
25214
25629
  }
25215
25630
  const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
25216
- (0, import_node_fs49.mkdirSync)((0, import_node_path46.dirname)(configPath), { recursive: true });
25217
- (0, import_node_fs49.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
25631
+ (0, import_node_fs50.mkdirSync)((0, import_node_path47.dirname)(configPath), { recursive: true });
25632
+ (0, import_node_fs50.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
25218
25633
  `);
25219
25634
  }
25220
25635
  function launchFromResolved(server) {
@@ -25232,7 +25647,7 @@ async function registerPackagedUserMcpClients() {
25232
25647
  const cursor = userCursorMcpConfigPath();
25233
25648
  writeMergedMcpServersJson(cursor, launch);
25234
25649
  const claude = userClaudeMcpConfigPath();
25235
- if ((0, import_node_fs49.existsSync)(claude)) {
25650
+ if ((0, import_node_fs50.existsSync)(claude)) {
25236
25651
  writeMergedMcpServersJson(claude, launch);
25237
25652
  return { cursor, claude };
25238
25653
  }
@@ -25243,7 +25658,7 @@ async function registerPackagedUserMcpClients() {
25243
25658
  init_workspaces();
25244
25659
 
25245
25660
  // src/slack/oauth.ts
25246
- var import_node_crypto13 = require("crypto");
25661
+ var import_node_crypto14 = require("crypto");
25247
25662
  init_app_settings();
25248
25663
  init_workspaces();
25249
25664
 
@@ -25467,7 +25882,7 @@ async function startSlackOAuth(opts) {
25467
25882
  throw new SlackOAuthCancelledError();
25468
25883
  }
25469
25884
  const { clientId } = slackOAuthCredentials();
25470
- const state = (0, import_node_crypto13.randomBytes)(16).toString("hex");
25885
+ const state = (0, import_node_crypto14.randomBytes)(16).toString("hex");
25471
25886
  const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
25472
25887
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
25473
25888
  const pollIntervalMs = opts?.pollIntervalMs ?? 400;
@@ -25749,7 +26164,7 @@ init_workspaces();
25749
26164
  init_reply_target();
25750
26165
 
25751
26166
  // src/slack/relay-protocol.ts
25752
- var import_node_crypto14 = require("crypto");
26167
+ var import_node_crypto15 = require("crypto");
25753
26168
  var SLACK_RELAY_PING_INTERVAL_MS = 2e4;
25754
26169
  var SLACK_RELAY_PONG_TIMEOUT_MS = 15e3;
25755
26170
  function slackRelaySessionKey(teamId, userId, deviceId) {
@@ -25759,7 +26174,7 @@ function slackRelayUserKey(teamId, userId) {
25759
26174
  return `${teamId.trim()}:${userId.trim()}`;
25760
26175
  }
25761
26176
  function newSlackRelayEventId() {
25762
- return (0, import_node_crypto14.randomBytes)(12).toString("hex");
26177
+ return (0, import_node_crypto15.randomBytes)(12).toString("hex");
25763
26178
  }
25764
26179
  function parseSlackRelayClientMessage(raw) {
25765
26180
  try {
@@ -26862,9 +27277,9 @@ var import_node_http3 = require("http");
26862
27277
  var import_ws3 = require("ws");
26863
27278
 
26864
27279
  // src/slack/relay-static.ts
26865
- var import_node_fs50 = require("fs");
27280
+ var import_node_fs51 = require("fs");
26866
27281
  var import_promises = require("fs/promises");
26867
- var import_node_path47 = __toESM(require("path"), 1);
27282
+ var import_node_path48 = __toESM(require("path"), 1);
26868
27283
  var TYPES = {
26869
27284
  ".css": "text/css; charset=utf-8",
26870
27285
  ".html": "text/html; charset=utf-8",
@@ -26895,9 +27310,9 @@ function resolveStaticPath(root, requestUrl) {
26895
27310
  return null;
26896
27311
  }
26897
27312
  if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
26898
- const rootResolved = import_node_path47.default.resolve(root);
26899
- const candidate = import_node_path47.default.resolve(rootResolved, `.${pathname}`);
26900
- if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path47.default.sep)) {
27313
+ const rootResolved = import_node_path48.default.resolve(root);
27314
+ const candidate = import_node_path48.default.resolve(rootResolved, `.${pathname}`);
27315
+ if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path48.default.sep)) {
26901
27316
  return null;
26902
27317
  }
26903
27318
  return candidate;
@@ -26911,7 +27326,7 @@ async function fileSize(file) {
26911
27326
  }
26912
27327
  }
26913
27328
  function sendFile(req, res, file, size) {
26914
- const ext = import_node_path47.default.extname(file).toLowerCase();
27329
+ const ext = import_node_path48.default.extname(file).toLowerCase();
26915
27330
  res.writeHead(200, {
26916
27331
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
26917
27332
  "Content-Length": size,
@@ -26921,7 +27336,7 @@ function sendFile(req, res, file, size) {
26921
27336
  res.end();
26922
27337
  return true;
26923
27338
  }
26924
- (0, import_node_fs50.createReadStream)(file).pipe(res);
27339
+ (0, import_node_fs51.createReadStream)(file).pipe(res);
26925
27340
  return true;
26926
27341
  }
26927
27342
  async function tryServeStatic(req, res, root) {
@@ -26930,7 +27345,7 @@ async function tryServeStatic(req, res, root) {
26930
27345
  if (!candidate) return false;
26931
27346
  const direct = await fileSize(candidate);
26932
27347
  if (direct != null) return sendFile(req, res, candidate, direct);
26933
- const asIndex = import_node_path47.default.join(candidate, "index.html");
27348
+ const asIndex = import_node_path48.default.join(candidate, "index.html");
26934
27349
  const indexSize = await fileSize(asIndex);
26935
27350
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
26936
27351
  return false;
@@ -27190,7 +27605,10 @@ init_outbound_watch();
27190
27605
  DEFAULT_ABLETIME_HOST,
27191
27606
  DEFAULT_WORKTREE_SORT,
27192
27607
  FAMOUS_SOCCER_TEAMS,
27608
+ FOLLOW_UP_BEHAVIORS,
27193
27609
  GITHUB_GIT_AUTH_MODES,
27610
+ GITHUB_PR_BODY_MAX_CHARS,
27611
+ GITHUB_PR_BODY_SAFE_CHARS,
27194
27612
  GLOBAL_WORKSPACE_ID,
27195
27613
  HARNESS_ENV_KEYS,
27196
27614
  HOME_BOARD_CACHE_TTL_MS,
@@ -27202,6 +27620,7 @@ init_outbound_watch();
27202
27620
  LINEAR_OAUTH_PORT,
27203
27621
  LINEAR_OAUTH_REDIRECT,
27204
27622
  LINEAR_OAUTH_SCOPES,
27623
+ LIVE_TURN_SPAWN_GRACE_MS,
27205
27624
  LONG_RUNNING_SKILL_COMMAND,
27206
27625
  LinearOAuthCancelledError,
27207
27626
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
@@ -27291,6 +27710,7 @@ init_outbound_watch();
27291
27710
  buildCodeRefAttachment,
27292
27711
  buildDiffCommentAttachment,
27293
27712
  buildForkTranscriptAttachment,
27713
+ buildLinearIssueFilter,
27294
27714
  buildPastedTextAttachment,
27295
27715
  buildPathRefAttachment,
27296
27716
  buildReviewRequestAttachment,
@@ -27308,6 +27728,7 @@ init_outbound_watch();
27308
27728
  checkoutPrStackLayer,
27309
27729
  childEnvWithAppSettings,
27310
27730
  claimDesktopHost,
27731
+ clampGithubPrBody,
27311
27732
  classifyWorktreeColumn,
27312
27733
  claudeAdapter,
27313
27734
  claudeChromeEnabled,
@@ -27412,6 +27833,7 @@ init_outbound_watch();
27412
27833
  fireSchedule,
27413
27834
  flattenTurnInput,
27414
27835
  flipLinearRelationType,
27836
+ followUpBehavior,
27415
27837
  forkChatTab,
27416
27838
  forkMessageSlice,
27417
27839
  forkThreadWorktree,
@@ -27490,6 +27912,7 @@ init_outbound_watch();
27490
27912
  ghRepoSelectArgs,
27491
27913
  git,
27492
27914
  githubAgentGitEnv,
27915
+ githubHttpsInsteadOfEntries,
27493
27916
  globalAgentCwd,
27494
27917
  groupHomeBoardWorktrees,
27495
27918
  handleSlackInbound,
@@ -27526,6 +27949,7 @@ init_outbound_watch();
27526
27949
  isDefaultishSourceRef,
27527
27950
  isDesktopHostAlive,
27528
27951
  isDirty,
27952
+ isGhPrBodyTooLongError,
27529
27953
  isGhRateLimitError,
27530
27954
  isGlobalRepoPath,
27531
27955
  isGlobalThread,
@@ -27533,6 +27957,7 @@ init_outbound_watch();
27533
27957
  isImageFilePath,
27534
27958
  isInPrStack,
27535
27959
  isInboundForThisDesktop,
27960
+ isInternalAgentStatusText,
27536
27961
  isIssueSourceConnected,
27537
27962
  isLinearConnected,
27538
27963
  isLinearOAuthCancelled,
@@ -27559,6 +27984,7 @@ init_outbound_watch();
27559
27984
  isThreadRecordFile,
27560
27985
  isWorkspaceScratchPath,
27561
27986
  issueAttachmentForAbleTimeTask,
27987
+ issueMatchesAssignee,
27562
27988
  issueSourceLabel,
27563
27989
  lastRequestOccupancy,
27564
27990
  latestPendingPlanQuestions,
@@ -27586,6 +28012,7 @@ init_outbound_watch();
27586
28012
  listLinearAssignedIssues,
27587
28013
  listLinearIssues,
27588
28014
  listLinearIssuesDirect,
28015
+ listLinearIssuesFiltered,
27589
28016
  listLinearTeams,
27590
28017
  listModelsForAgent,
27591
28018
  listOpencodeModels,