@sideboard-ai/core 0.1.149 → 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 +40 -35
  4. package/dist/agents/cursor-runner.js +2 -2
  5. package/dist/{agents-HSVQ2Z6Y.js → agents-KKXGTEV6.js} +10 -9
  6. package/dist/{agents-V4MTDWXS.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-TZWO7J4W.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-LAFA56WD.js → chunk-HEII7W3Q.js} +1 -1
  20. package/dist/{chunk-EGDRPA4B.js → chunk-NOTANBYC.js} +6 -6
  21. package/dist/{chunk-JDYKQ6OI.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-PTI5H3RK.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-Q5DHVMXB.js → chunk-YGGBJY5A.js} +18 -7
  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 +998 -574
  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 +976 -579
  47. package/dist/mcp/run-stdio.js +196 -43
  48. package/dist/{orchestrator-6TXQWBXN.js → orchestrator-GZE4X3XV.js} +14 -11
  49. package/dist/{orchestrator-Z2O5OVJA.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();
@@ -7607,32 +7782,32 @@ var init_error_detail = __esm({
7607
7782
  function brightsyConfigPath() {
7608
7783
  const override = process.env.BRIGHTSY_CONFIG?.trim();
7609
7784
  if (override) return override;
7610
- 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");
7611
7786
  }
7612
7787
  function loadBrightsyConfig() {
7613
7788
  const path2 = brightsyConfigPath();
7614
- if (!(0, import_node_fs20.existsSync)(path2)) {
7789
+ if (!(0, import_node_fs21.existsSync)(path2)) {
7615
7790
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
7616
7791
  }
7617
- const raw = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
7792
+ const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
7618
7793
  if (!raw.access_token || !raw.account_id) {
7619
7794
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
7620
7795
  }
7621
7796
  return raw;
7622
7797
  }
7623
7798
  function saveBrightsyConfig(cfg) {
7624
- (0, import_node_fs20.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7799
+ (0, import_node_fs21.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7625
7800
  `, {
7626
7801
  mode: 384
7627
7802
  });
7628
7803
  }
7629
- var import_node_fs20, import_node_os6, import_node_path23;
7804
+ var import_node_fs21, import_node_os7, import_node_path24;
7630
7805
  var init_config = __esm({
7631
7806
  "src/brightsy/config.ts"() {
7632
7807
  "use strict";
7633
- import_node_fs20 = require("fs");
7634
- import_node_os6 = require("os");
7635
- import_node_path23 = require("path");
7808
+ import_node_fs21 = require("fs");
7809
+ import_node_os7 = require("os");
7810
+ import_node_path24 = require("path");
7636
7811
  }
7637
7812
  });
7638
7813
 
@@ -7850,22 +8025,22 @@ __export(connected_teams_exports, {
7850
8025
  listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
7851
8026
  });
7852
8027
  function storePath4() {
7853
- return (0, import_node_path24.join)(appDataDir(), "brightsy-teams.json");
8028
+ return (0, import_node_path25.join)(appDataDir(), "brightsy-teams.json");
7854
8029
  }
7855
8030
  function readStore4() {
7856
8031
  const path2 = storePath4();
7857
- if (!(0, import_node_fs21.existsSync)(path2)) return [];
8032
+ if (!(0, import_node_fs22.existsSync)(path2)) return [];
7858
8033
  try {
7859
- const parsed = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
8034
+ const parsed = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
7860
8035
  return Array.isArray(parsed.teams) ? parsed.teams : [];
7861
8036
  } catch {
7862
8037
  return [];
7863
8038
  }
7864
8039
  }
7865
8040
  function writeStore3(teams) {
7866
- (0, import_node_fs21.mkdirSync)(appDataDir(), { recursive: true });
8041
+ (0, import_node_fs22.mkdirSync)(appDataDir(), { recursive: true });
7867
8042
  const path2 = storePath4();
7868
- (0, import_node_fs21.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
8043
+ (0, import_node_fs22.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
7869
8044
  `, {
7870
8045
  mode: 384
7871
8046
  });
@@ -8021,12 +8196,12 @@ function brightsyMcpServerName(slug) {
8021
8196
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
8022
8197
  return `brightsy_${cleaned || "team"}`;
8023
8198
  }
8024
- var import_node_fs21, import_node_path24;
8199
+ var import_node_fs22, import_node_path25;
8025
8200
  var init_connected_teams = __esm({
8026
8201
  "src/brightsy/connected-teams.ts"() {
8027
8202
  "use strict";
8028
- import_node_fs21 = require("fs");
8029
- import_node_path24 = require("path");
8203
+ import_node_fs22 = require("fs");
8204
+ import_node_path25 = require("path");
8030
8205
  init_paths();
8031
8206
  init_accounts();
8032
8207
  init_config();
@@ -8445,11 +8620,11 @@ async function syncCliForTarget(accountId) {
8445
8620
  }
8446
8621
  applyConnectedTeamToCli(team);
8447
8622
  }
8448
- var import_node_fs22, brightsyAdapter;
8623
+ var import_node_fs23, brightsyAdapter;
8449
8624
  var init_brightsy = __esm({
8450
8625
  "src/agents/brightsy.ts"() {
8451
8626
  "use strict";
8452
- import_node_fs22 = require("fs");
8627
+ import_node_fs23 = require("fs");
8453
8628
  init_run();
8454
8629
  init_connected_teams();
8455
8630
  init_config();
@@ -8464,7 +8639,7 @@ var init_brightsy = __esm({
8464
8639
  async detect() {
8465
8640
  const brightsy = resolveAgentExecutable("brightsy");
8466
8641
  if (brightsy !== "brightsy") {
8467
- if (!(0, import_node_fs22.existsSync)(brightsy)) {
8642
+ if (!(0, import_node_fs23.existsSync)(brightsy)) {
8468
8643
  return {
8469
8644
  agent: "brightsy",
8470
8645
  installed: false,
@@ -8731,6 +8906,13 @@ function isSubagentToolName(name) {
8731
8906
  if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
8732
8907
  return /connectedAgentRequest/i.test(n);
8733
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
+ }
8734
8916
  function isPollWrapperToolName(name) {
8735
8917
  const n = (name ?? "").replace(/[_-]/g, "");
8736
8918
  return /^(taskoutput|taskstop|sleep)$/i.test(n);
@@ -8738,7 +8920,10 @@ function isPollWrapperToolName(name) {
8738
8920
  function lastTextPart(parts, type) {
8739
8921
  for (let i = parts.length - 1; i >= 0; i--) {
8740
8922
  const p = parts[i];
8741
- 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;
8742
8927
  }
8743
8928
  return "";
8744
8929
  }
@@ -9154,43 +9339,43 @@ function electronResourcesPath() {
9154
9339
  function packagedCursorRuntimeDir() {
9155
9340
  const resources = electronResourcesPath();
9156
9341
  if (!resources) return null;
9157
- const dir = (0, import_node_path25.join)(resources, "cursor-runtime");
9158
- 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;
9159
9344
  return dir;
9160
9345
  }
9161
9346
  function packagedCursorRunnerPath() {
9162
9347
  const dir = packagedCursorRuntimeDir();
9163
- 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;
9164
9349
  }
9165
9350
  function packagedMcpDir() {
9166
9351
  const resources = electronResourcesPath();
9167
9352
  if (!resources) return null;
9168
- const dir = (0, import_node_path25.join)(resources, "sideboard-mcp");
9169
- 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;
9170
9355
  return dir;
9171
9356
  }
9172
9357
  function packagedMcpStdioPath() {
9173
9358
  const dir = packagedMcpDir();
9174
- 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;
9175
9360
  }
9176
9361
  function packagedBundledNodePath() {
9177
9362
  const resources = electronResourcesPath();
9178
9363
  if (!resources) return null;
9179
- const bin = (0, import_node_path25.join)(resources, "node", "bin", "node");
9180
- 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;
9181
9366
  return bin;
9182
9367
  }
9183
9368
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
9184
9369
  const dir = packagedCursorRuntimeDir();
9185
9370
  if (!dir) return null;
9186
- 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);
9187
9372
  }
9188
- var import_node_fs23, import_node_path25;
9373
+ var import_node_fs24, import_node_path26;
9189
9374
  var init_packaged_runtime = __esm({
9190
9375
  "src/agents/packaged-runtime.ts"() {
9191
9376
  "use strict";
9192
- import_node_fs23 = require("fs");
9193
- import_node_path25 = require("path");
9377
+ import_node_fs24 = require("fs");
9378
+ import_node_path26 = require("path");
9194
9379
  }
9195
9380
  });
9196
9381
 
@@ -9224,7 +9409,7 @@ function unpackedAsarPath(filePath) {
9224
9409
  if (!isAsarPath(filePath)) return null;
9225
9410
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
9226
9411
  if (unpacked === filePath) return null;
9227
- return (0, import_node_fs24.existsSync)(unpacked) ? unpacked : null;
9412
+ return (0, import_node_fs25.existsSync)(unpacked) ? unpacked : null;
9228
9413
  }
9229
9414
  function nodeReadableScriptPath(scriptPath) {
9230
9415
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -9264,37 +9449,37 @@ function pickPreferredNode(candidates) {
9264
9449
  return best;
9265
9450
  }
9266
9451
  function versionDirNodeBins(root, toBin) {
9267
- if (!(0, import_node_fs24.existsSync)(root)) return [];
9452
+ if (!(0, import_node_fs25.existsSync)(root)) return [];
9268
9453
  try {
9269
- return (0, import_node_fs24.readdirSync)(root).map(toBin);
9454
+ return (0, import_node_fs25.readdirSync)(root).map(toBin);
9270
9455
  } catch {
9271
9456
  return [];
9272
9457
  }
9273
9458
  }
9274
- function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
9459
+ function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
9275
9460
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
9276
- (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"))
9277
9462
  );
9278
9463
  return [
9279
9464
  ...kegs,
9280
9465
  "/opt/homebrew/bin/node",
9281
9466
  "/usr/local/bin/node",
9282
- (0, import_node_path26.join)(home, ".local/share/fnm/aliases/default/bin/node"),
9283
- (0, import_node_path26.join)(home, ".nvm/current/bin/node"),
9284
- (0, import_node_path26.join)(home, ".volta/bin/node"),
9285
- (0, import_node_path26.join)(home, ".asdf/shims/node"),
9286
- (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"),
9287
9472
  ...versionDirNodeBins(
9288
- (0, import_node_path26.join)(home, ".nvm", "versions", "node"),
9289
- (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")
9290
9475
  ),
9291
9476
  ...versionDirNodeBins(
9292
- (0, import_node_path26.join)(home, ".local/share/fnm", "node-versions"),
9293
- (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")
9294
9479
  ),
9295
9480
  ...versionDirNodeBins(
9296
- (0, import_node_path26.join)(home, ".volta", "tools", "image", "node"),
9297
- (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")
9298
9483
  )
9299
9484
  ];
9300
9485
  }
@@ -9303,10 +9488,10 @@ function uniqueExistingNodeBins(paths) {
9303
9488
  const out = [];
9304
9489
  for (const raw of paths) {
9305
9490
  const p = raw.trim();
9306
- if (!p || !(0, import_node_fs24.existsSync)(p) || isElectronLikeCommand(p)) continue;
9491
+ if (!p || !(0, import_node_fs25.existsSync)(p) || isElectronLikeCommand(p)) continue;
9307
9492
  let key = p;
9308
9493
  try {
9309
- key = (0, import_node_fs24.realpathSync)(p);
9494
+ key = (0, import_node_fs25.realpathSync)(p);
9310
9495
  } catch {
9311
9496
  continue;
9312
9497
  }
@@ -9386,13 +9571,13 @@ async function resolveNodeLaunch(scriptPath) {
9386
9571
  env: { ELECTRON_RUN_AS_NODE: "1" }
9387
9572
  };
9388
9573
  }
9389
- 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;
9390
9575
  var init_node_launch = __esm({
9391
9576
  "src/agents/node-launch.ts"() {
9392
9577
  "use strict";
9393
- import_node_fs24 = require("fs");
9394
- import_node_os7 = require("os");
9395
- import_node_path26 = require("path");
9578
+ import_node_fs25 = require("fs");
9579
+ import_node_os8 = require("os");
9580
+ import_node_path27 = require("path");
9396
9581
  init_nested_electron_env();
9397
9582
  init_run();
9398
9583
  init_packaged_runtime();
@@ -9486,37 +9671,37 @@ function corePackageDir() {
9486
9671
  try {
9487
9672
  const url = import_meta.url;
9488
9673
  if (typeof url === "string" && url.length > 0) {
9489
- 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));
9490
9675
  }
9491
9676
  } catch {
9492
9677
  }
9493
9678
  try {
9494
- const req = (0, import_node_module.createRequire)((0, import_node_path27.join)(process.cwd(), "package.json"));
9495
- 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"));
9496
9681
  } catch {
9497
9682
  return process.cwd();
9498
9683
  }
9499
9684
  }
9500
9685
  function findSideboardMcpJsEntry() {
9501
9686
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
9502
- if (override && (0, import_node_fs25.existsSync)(override)) return override;
9687
+ if (override && (0, import_node_fs26.existsSync)(override)) return override;
9503
9688
  const packaged = packagedMcpStdioPath();
9504
9689
  if (packaged) return packaged;
9505
9690
  let dir = corePackageDir();
9506
9691
  for (let i = 0; i < 10; i++) {
9507
9692
  const candidates = [
9508
- (0, import_node_path27.join)(dir, "mcp/run-stdio.js"),
9509
- (0, import_node_path27.join)(dir, "mcp/run-stdio.cjs"),
9510
- (0, import_node_path27.join)(dir, "dist/mcp/run-stdio.js"),
9511
- (0, import_node_path27.join)(dir, "dist/mcp/run-stdio.cjs"),
9512
- (0, import_node_path27.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
9513
- (0, import_node_path27.join)(dir, "packages/cli/dist/index.js"),
9514
- (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")
9515
9700
  ];
9516
9701
  for (const p of candidates) {
9517
- if ((0, import_node_fs25.existsSync)(p) && !isAsarPath(p)) return p;
9702
+ if ((0, import_node_fs26.existsSync)(p) && !isAsarPath(p)) return p;
9518
9703
  }
9519
- const parent = (0, import_node_path27.dirname)(dir);
9704
+ const parent = (0, import_node_path28.dirname)(dir);
9520
9705
  if (parent === dir) break;
9521
9706
  dir = parent;
9522
9707
  }
@@ -9658,22 +9843,22 @@ function writeMcpServersConfig(servers) {
9658
9843
  ...env ? { env } : {}
9659
9844
  };
9660
9845
  }
9661
- const dir = (0, import_node_fs25.mkdtempSync)((0, import_node_path27.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
9662
- const cfgPath = (0, import_node_path27.join)(dir, "mcp.json");
9663
- (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));
9664
9849
  return cfgPath;
9665
9850
  }
9666
9851
  async function writeInjectedMcpConfig(opts) {
9667
9852
  return writeMcpServersConfig(await buildInjectedMcpServers(opts));
9668
9853
  }
9669
- 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;
9670
9855
  var init_injected_mcp = __esm({
9671
9856
  "src/agents/injected-mcp.ts"() {
9672
9857
  "use strict";
9673
- import_node_fs25 = require("fs");
9858
+ import_node_fs26 = require("fs");
9674
9859
  import_node_module = require("module");
9675
- import_node_os8 = require("os");
9676
- import_node_path27 = require("path");
9860
+ import_node_os9 = require("os");
9861
+ import_node_path28 = require("path");
9677
9862
  import_node_url = require("url");
9678
9863
  init_run();
9679
9864
  init_config();
@@ -10016,11 +10201,11 @@ function parseIssuesJson(raw) {
10016
10201
  }
10017
10202
  return [];
10018
10203
  }
10019
- 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;
10020
10205
  var init_claude = __esm({
10021
10206
  "src/agents/claude.ts"() {
10022
10207
  "use strict";
10023
- import_node_fs26 = require("fs");
10208
+ import_node_fs27 = require("fs");
10024
10209
  init_run();
10025
10210
  init_app_settings();
10026
10211
  init_claude_mcp();
@@ -10060,7 +10245,7 @@ var init_claude = __esm({
10060
10245
  async detect() {
10061
10246
  const claude = resolveClaudeExecutable();
10062
10247
  if (claude !== "claude") {
10063
- if (!(0, import_node_fs26.existsSync)(claude)) {
10248
+ if (!(0, import_node_fs27.existsSync)(claude)) {
10064
10249
  return {
10065
10250
  agent: "claude",
10066
10251
  installed: false,
@@ -10315,7 +10500,7 @@ async function listCodexModels() {
10315
10500
  if (codex === "codex") {
10316
10501
  const which = await run("which", ["codex"], { reject: false });
10317
10502
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
10318
- } else if (!(0, import_node_fs27.existsSync)(codex)) {
10503
+ } else if (!(0, import_node_fs28.existsSync)(codex)) {
10319
10504
  return FALLBACK_CODEX_MODELS;
10320
10505
  }
10321
10506
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -10350,12 +10535,12 @@ function usageFromCodex(usage) {
10350
10535
  }
10351
10536
  function codexConfigHasNetworkAccess() {
10352
10537
  const candidates = [
10353
- (0, import_node_path28.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
10354
- (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")
10355
10540
  ];
10356
10541
  for (const path2 of candidates) {
10357
- if (!(0, import_node_fs27.existsSync)(path2)) continue;
10358
- 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");
10359
10544
  if (/network_access\s*=\s*true/.test(text5)) return true;
10360
10545
  }
10361
10546
  return false;
@@ -10387,21 +10572,21 @@ function asRecord2(value) {
10387
10572
  return void 0;
10388
10573
  }
10389
10574
  function codexLooksAuthenticated() {
10390
- const authPath = (0, import_node_path28.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
10391
- 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;
10392
10577
  try {
10393
- return (0, import_node_fs27.statSync)(authPath).size > 2;
10578
+ return (0, import_node_fs28.statSync)(authPath).size > 2;
10394
10579
  } catch {
10395
10580
  return false;
10396
10581
  }
10397
10582
  }
10398
- 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;
10399
10584
  var init_codex = __esm({
10400
10585
  "src/agents/codex.ts"() {
10401
10586
  "use strict";
10402
- import_node_fs27 = require("fs");
10403
- import_node_os9 = require("os");
10404
- import_node_path28 = require("path");
10587
+ import_node_fs28 = require("fs");
10588
+ import_node_os10 = require("os");
10589
+ import_node_path29 = require("path");
10405
10590
  init_run();
10406
10591
  init_app_settings();
10407
10592
  init_global_workspace();
@@ -10426,7 +10611,7 @@ var init_codex = __esm({
10426
10611
  async detect() {
10427
10612
  const codex = resolveAgentExecutable("codex");
10428
10613
  if (codex !== "codex") {
10429
- if (!(0, import_node_fs27.existsSync)(codex)) {
10614
+ if (!(0, import_node_fs28.existsSync)(codex)) {
10430
10615
  return {
10431
10616
  agent: "codex",
10432
10617
  installed: false,
@@ -10913,21 +11098,21 @@ function platformRipgrepPackage() {
10913
11098
  }
10914
11099
  function usableRipgrepPath(candidate) {
10915
11100
  const raw = candidate?.trim();
10916
- if (!raw || !(0, import_node_path29.isAbsolute)(raw)) return null;
11101
+ if (!raw || !(0, import_node_path30.isAbsolute)(raw)) return null;
10917
11102
  const readable = nodeReadableScriptPath(raw);
10918
- if (!(0, import_node_fs28.existsSync)(readable) || isAsarPath(readable)) return null;
11103
+ if (!(0, import_node_fs29.existsSync)(readable) || isAsarPath(readable)) return null;
10919
11104
  return readable;
10920
11105
  }
10921
11106
  function walkForBundledRipgrep(startFile) {
10922
11107
  if (!startFile) return null;
10923
11108
  const pkg = platformRipgrepPackage();
10924
11109
  const name = rgBinaryName();
10925
- let dir = (0, import_node_path29.dirname)((0, import_node_path29.resolve)(startFile));
10926
- 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;
10927
11112
  while (dir !== root) {
10928
- 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));
10929
11114
  if (hit) return hit;
10930
- const next = (0, import_node_path29.dirname)(dir);
11115
+ const next = (0, import_node_path30.dirname)(dir);
10931
11116
  if (next === dir) break;
10932
11117
  dir = next;
10933
11118
  }
@@ -10937,7 +11122,7 @@ function requireResolveBundledRipgrep(fromFile) {
10937
11122
  try {
10938
11123
  const req = (0, import_node_module2.createRequire)(fromFile);
10939
11124
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
10940
- 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()));
10941
11126
  } catch {
10942
11127
  return null;
10943
11128
  }
@@ -10959,13 +11144,13 @@ function cursorRipgrepEnv(opts) {
10959
11144
  const path2 = resolveCursorRipgrepPath(opts);
10960
11145
  return path2 ? { [RIPGREP_ENV]: path2 } : {};
10961
11146
  }
10962
- 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;
10963
11148
  var init_cursor_ripgrep = __esm({
10964
11149
  "src/agents/cursor-ripgrep.ts"() {
10965
11150
  "use strict";
10966
- import_node_fs28 = require("fs");
11151
+ import_node_fs29 = require("fs");
10967
11152
  import_node_module2 = require("module");
10968
- import_node_path29 = require("path");
11153
+ import_node_path30 = require("path");
10969
11154
  init_node_launch();
10970
11155
  init_packaged_runtime();
10971
11156
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -11011,11 +11196,11 @@ function entryDir() {
11011
11196
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
11012
11197
  if (cjsDir) return cjsDir;
11013
11198
  try {
11014
- 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));
11015
11200
  } catch {
11016
11201
  try {
11017
11202
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
11018
- return (0, import_node_path30.dirname)(req.resolve("@sideboard-ai/core"));
11203
+ return (0, import_node_path31.dirname)(req.resolve("@sideboard-ai/core"));
11019
11204
  } catch {
11020
11205
  return process.cwd();
11021
11206
  }
@@ -11026,27 +11211,27 @@ function cursorRunnerPath() {
11026
11211
  if (packaged) return packaged;
11027
11212
  const root = entryDir();
11028
11213
  const candidates = [
11029
- (0, import_node_path30.join)(root, "agents", "cursor-runner.js"),
11030
- (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"),
11031
11216
  // If somehow resolved from package root instead of dist/
11032
- (0, import_node_path30.join)(root, "dist", "agents", "cursor-runner.js"),
11033
- (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"),
11034
11219
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
11035
- (0, import_node_path30.join)(root, "cursor-runner.ts"),
11036
- (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")
11037
11222
  ];
11038
11223
  for (const candidate of candidates) {
11039
- if ((0, import_node_fs29.existsSync)(candidate)) return candidate;
11224
+ if ((0, import_node_fs30.existsSync)(candidate)) return candidate;
11040
11225
  }
11041
11226
  return candidates[0];
11042
11227
  }
11043
- 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;
11044
11229
  var init_cursor = __esm({
11045
11230
  "src/agents/cursor.ts"() {
11046
11231
  "use strict";
11047
- import_node_fs29 = require("fs");
11232
+ import_node_fs30 = require("fs");
11048
11233
  import_node_module3 = require("module");
11049
- import_node_path30 = require("path");
11234
+ import_node_path31 = require("path");
11050
11235
  import_node_url2 = require("url");
11051
11236
  import_sdk = require("@cursor/sdk");
11052
11237
  init_run();
@@ -11197,7 +11382,7 @@ async function listOpencodeModels() {
11197
11382
  if (opencode === "opencode") {
11198
11383
  const which = await run("which", ["opencode"], { reject: false });
11199
11384
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
11200
- } else if (!(0, import_node_fs30.existsSync)(opencode)) {
11385
+ } else if (!(0, import_node_fs31.existsSync)(opencode)) {
11201
11386
  return FALLBACK_OPENCODE_MODELS;
11202
11387
  }
11203
11388
  const listed = await run(opencode, ["models"], { reject: false });
@@ -11227,11 +11412,11 @@ function usageFromOpencode(tokens) {
11227
11412
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
11228
11413
  };
11229
11414
  }
11230
- 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;
11231
11416
  var init_opencode = __esm({
11232
11417
  "src/agents/opencode.ts"() {
11233
11418
  "use strict";
11234
- import_node_fs30 = require("fs");
11419
+ import_node_fs31 = require("fs");
11235
11420
  init_run();
11236
11421
  init_app_settings();
11237
11422
  init_global_workspace();
@@ -11258,7 +11443,7 @@ var init_opencode = __esm({
11258
11443
  async detect() {
11259
11444
  const opencode = resolveAgentExecutable("opencode");
11260
11445
  if (opencode !== "opencode") {
11261
- if (!(0, import_node_fs30.existsSync)(opencode)) {
11446
+ if (!(0, import_node_fs31.existsSync)(opencode)) {
11262
11447
  return {
11263
11448
  agent: "opencode",
11264
11449
  installed: false,
@@ -12884,7 +13069,7 @@ function forkMessageSlice(from, throughIndex) {
12884
13069
  function buildForkTranscriptAttachment(baseTitle, messages) {
12885
13070
  const title = baseTitle || "Chat";
12886
13071
  return {
12887
- id: (0, import_node_crypto6.randomUUID)(),
13072
+ id: (0, import_node_crypto7.randomUUID)(),
12888
13073
  name: `Transcript of ${title}.md`,
12889
13074
  kind: "transcript",
12890
13075
  content: formatTranscriptMarkdown(title, messages)
@@ -12941,11 +13126,11 @@ function forkChatTab(input) {
12941
13126
  }
12942
13127
  return tab;
12943
13128
  }
12944
- var import_node_crypto6;
13129
+ var import_node_crypto7;
12945
13130
  var init_chat_tabs = __esm({
12946
13131
  "src/threads/chat-tabs.ts"() {
12947
13132
  "use strict";
12948
- import_node_crypto6 = require("crypto");
13133
+ import_node_crypto7 = require("crypto");
12949
13134
  init_context_compact();
12950
13135
  init_teams();
12951
13136
  init_worktree_labels();
@@ -13115,21 +13300,21 @@ function shouldRefreshReviewRequestTemplate(content) {
13115
13300
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
13116
13301
  }
13117
13302
  function readTextIfPresent(abs) {
13118
- if (!(0, import_node_fs31.existsSync)(abs)) return null;
13303
+ if (!(0, import_node_fs32.existsSync)(abs)) return null;
13119
13304
  try {
13120
- const content = (0, import_node_fs31.readFileSync)(abs, "utf8");
13305
+ const content = (0, import_node_fs32.readFileSync)(abs, "utf8");
13121
13306
  return content.trim() ? content : null;
13122
13307
  } catch {
13123
13308
  return null;
13124
13309
  }
13125
13310
  }
13126
13311
  function readLocalGuidelines(worktreePath) {
13127
- const localAbs = (0, import_node_path31.join)(worktreePath, REVIEW_REQUEST_PATH);
13312
+ const localAbs = (0, import_node_path32.join)(worktreePath, REVIEW_REQUEST_PATH);
13128
13313
  const localContent = readTextIfPresent(localAbs);
13129
13314
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
13130
13315
  return { path: REVIEW_REQUEST_PATH, content: localContent };
13131
13316
  }
13132
- 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);
13133
13318
  const legacyContent = readTextIfPresent(legacyAbs);
13134
13319
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
13135
13320
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -13145,20 +13330,20 @@ function skillGuidelines(content, source) {
13145
13330
  };
13146
13331
  }
13147
13332
  function ensureReviewSkillFile(worktreePath) {
13148
- const abs = (0, import_node_path31.join)(worktreePath, REVIEW_SKILL_PATH);
13333
+ const abs = (0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH);
13149
13334
  const existing = readTextIfPresent(abs);
13150
13335
  if (existing) {
13151
13336
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
13152
13337
  }
13153
- 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));
13154
13339
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
13155
13340
  const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
13156
- (0, import_node_fs31.mkdirSync)((0, import_node_path31.dirname)(abs), { recursive: true });
13157
- (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");
13158
13343
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
13159
13344
  }
13160
13345
  function resolveReviewGuidelines(worktreePath) {
13161
- 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));
13162
13347
  if (skillContent) return skillGuidelines(skillContent, "skill");
13163
13348
  const local = readLocalGuidelines(worktreePath);
13164
13349
  if (local) {
@@ -13180,7 +13365,7 @@ function buildReviewRequestAttachment(content, opts) {
13180
13365
  const path2 = opts?.path ?? REVIEW_SKILL_PATH;
13181
13366
  const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
13182
13367
  return {
13183
- id: (0, import_node_crypto7.randomUUID)(),
13368
+ id: (0, import_node_crypto8.randomUUID)(),
13184
13369
  name,
13185
13370
  kind: "file",
13186
13371
  path: path2,
@@ -13188,7 +13373,7 @@ function buildReviewRequestAttachment(content, opts) {
13188
13373
  };
13189
13374
  }
13190
13375
  function readExistingReviewRequestFile(worktreePath) {
13191
- 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));
13192
13377
  }
13193
13378
  async function requestReview(threadRef, send2) {
13194
13379
  const from = findThreadByRef(threadRef);
@@ -13215,13 +13400,13 @@ async function requestReview(threadRef, send2) {
13215
13400
  const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
13216
13401
  return { tab: started, from };
13217
13402
  }
13218
- 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;
13219
13404
  var init_request_review = __esm({
13220
13405
  "src/review/request-review.ts"() {
13221
13406
  "use strict";
13222
- import_node_crypto7 = require("crypto");
13223
- import_node_fs31 = require("fs");
13224
- import_node_path31 = require("path");
13407
+ import_node_crypto8 = require("crypto");
13408
+ import_node_fs32 = require("fs");
13409
+ import_node_path32 = require("path");
13225
13410
  init_global_workspace();
13226
13411
  init_chat_tabs();
13227
13412
  init_thread_store();
@@ -13246,9 +13431,9 @@ function matchSimpleGlob(pattern, name) {
13246
13431
  return new RegExp(`^${escaped}$`).test(name);
13247
13432
  }
13248
13433
  function readWorktreeInclude(repoPath) {
13249
- const path2 = (0, import_node_path32.join)(repoPath, ".worktreeinclude");
13250
- if (!(0, import_node_fs32.existsSync)(path2)) return [];
13251
- 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("#"));
13252
13437
  }
13253
13438
  function resolveFilesToCopy(repoPath) {
13254
13439
  const fromInclude = readWorktreeInclude(repoPath);
@@ -13258,10 +13443,10 @@ function resolveFilesToCopy(repoPath) {
13258
13443
  if (settings?.fileIncludeGlobs?.length) {
13259
13444
  const matched = [];
13260
13445
  try {
13261
- 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 })) {
13262
13447
  if (!entry.isFile()) continue;
13263
13448
  for (const glob of settings.fileIncludeGlobs) {
13264
- 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)) {
13265
13450
  matched.push(entry.name);
13266
13451
  break;
13267
13452
  }
@@ -13273,7 +13458,7 @@ function resolveFilesToCopy(repoPath) {
13273
13458
  }
13274
13459
  const defaults = [];
13275
13460
  try {
13276
- 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 })) {
13277
13462
  if (entry.isFile() && entry.name.startsWith(".env")) {
13278
13463
  defaults.push(entry.name);
13279
13464
  }
@@ -13287,11 +13472,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
13287
13472
  const patterns = resolveFilesToCopy(repoPath);
13288
13473
  const copied = [];
13289
13474
  for (const rel of patterns) {
13290
- const src = (0, import_node_path32.join)(repoPath, rel);
13291
- if (!(0, import_node_fs32.existsSync)(src)) continue;
13292
- const dest = (0, import_node_path32.join)(worktreePath, rel);
13293
- (0, import_node_fs32.mkdirSync)((0, import_node_path32.dirname)(dest), { recursive: true });
13294
- (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);
13295
13480
  copied.push(rel);
13296
13481
  }
13297
13482
  return copied;
@@ -13326,7 +13511,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
13326
13511
  const env = stripNestedElectronEnv({
13327
13512
  ...baseEnv ?? process.env
13328
13513
  });
13329
- const name = opts.workspaceName ?? (0, import_node_path32.basename)(opts.worktreePath);
13514
+ const name = opts.workspaceName ?? (0, import_node_path33.basename)(opts.worktreePath);
13330
13515
  const ports = opts.ports ?? [];
13331
13516
  const primary = ports[0];
13332
13517
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -13481,6 +13666,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
13481
13666
  };
13482
13667
  }
13483
13668
  async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
13669
+ await ensureWorktreeSideboardIgnored(worktreePath);
13484
13670
  const reviewSkill = ensureReviewSkillFile(worktreePath);
13485
13671
  if (reviewSkill.wrote) {
13486
13672
  onLine?.(
@@ -13587,13 +13773,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
13587
13773
  done: handle.done
13588
13774
  };
13589
13775
  }
13590
- 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;
13591
13777
  var init_conductor = __esm({
13592
13778
  "src/hook/conductor.ts"() {
13593
13779
  "use strict";
13594
- import_node_fs32 = require("fs");
13780
+ import_node_fs33 = require("fs");
13595
13781
  import_node_net = require("net");
13596
- import_node_path32 = require("path");
13782
+ import_node_path33 = require("path");
13597
13783
  import_execa4 = require("execa");
13598
13784
  import_node_readline3 = require("readline");
13599
13785
  init_settings();
@@ -13602,6 +13788,7 @@ var init_conductor = __esm({
13602
13788
  init_cursor_worktrees();
13603
13789
  init_git_auth_mode();
13604
13790
  init_request_review();
13791
+ init_worktree_exclude();
13605
13792
  init_nested_electron_env();
13606
13793
  PORT_RANGE_SIZE = 10;
13607
13794
  cachedLoginEnv = null;
@@ -13619,9 +13806,9 @@ async function findOrphanWorktrees(repoPaths) {
13619
13806
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
13620
13807
  );
13621
13808
  const homeRoot = sideboardWorkspacesDir();
13622
- if ((0, import_node_fs33.existsSync)(homeRoot)) {
13809
+ if ((0, import_node_fs34.existsSync)(homeRoot)) {
13623
13810
  try {
13624
- 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 })) {
13625
13812
  if (!entry.isDirectory()) continue;
13626
13813
  void entry;
13627
13814
  }
@@ -13631,7 +13818,7 @@ async function findOrphanWorktrees(repoPaths) {
13631
13818
  const orphans = [];
13632
13819
  const seen = /* @__PURE__ */ new Set();
13633
13820
  for (const repoPath of repos) {
13634
- if (!repoPath || !(0, import_node_fs33.existsSync)(repoPath)) continue;
13821
+ if (!repoPath || !(0, import_node_fs34.existsSync)(repoPath)) continue;
13635
13822
  try {
13636
13823
  const wts = await listWorktrees(repoPath);
13637
13824
  for (const wt of wts) {
@@ -13642,7 +13829,7 @@ async function findOrphanWorktrees(repoPaths) {
13642
13829
  seen.add(path2);
13643
13830
  let mtimeMs = 0;
13644
13831
  try {
13645
- mtimeMs = (0, import_node_fs33.statSync)(path2).mtimeMs;
13832
+ mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
13646
13833
  } catch {
13647
13834
  mtimeMs = 0;
13648
13835
  }
@@ -13652,16 +13839,16 @@ async function findOrphanWorktrees(repoPaths) {
13652
13839
  }
13653
13840
  try {
13654
13841
  const root = worktreesRoot(repoPath);
13655
- if ((0, import_node_fs33.existsSync)(root)) {
13656
- 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 })) {
13657
13844
  if (!entry.isDirectory()) continue;
13658
- const path2 = (0, import_node_path33.join)(root, entry.name).replace(/\/$/, "");
13845
+ const path2 = (0, import_node_path34.join)(root, entry.name).replace(/\/$/, "");
13659
13846
  if (known.has(path2) || seen.has(path2)) continue;
13660
- 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;
13661
13848
  seen.add(path2);
13662
13849
  let mtimeMs = 0;
13663
13850
  try {
13664
- mtimeMs = (0, import_node_fs33.statSync)(path2).mtimeMs;
13851
+ mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
13665
13852
  } catch {
13666
13853
  mtimeMs = Date.now();
13667
13854
  }
@@ -13722,12 +13909,12 @@ function worktreeCleanupSettings() {
13722
13909
  autoCleanupOrphans: a.autoCleanupOrphans
13723
13910
  };
13724
13911
  }
13725
- var import_node_fs33, import_node_path33;
13912
+ var import_node_fs34, import_node_path34;
13726
13913
  var init_orphan_cleanup = __esm({
13727
13914
  "src/git/orphan-cleanup.ts"() {
13728
13915
  "use strict";
13729
- import_node_fs33 = require("fs");
13730
- import_node_path33 = require("path");
13916
+ import_node_fs34 = require("fs");
13917
+ import_node_path34 = require("path");
13731
13918
  init_worktree();
13732
13919
  init_thread_store();
13733
13920
  init_paths();
@@ -13834,38 +14021,38 @@ __export(workspaces_exports, {
13834
14021
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
13835
14022
  });
13836
14023
  function workspacesFile() {
13837
- return (0, import_node_path34.join)(appDataDir(), "workspaces.json");
14024
+ return (0, import_node_path35.join)(appDataDir(), "workspaces.json");
13838
14025
  }
13839
14026
  function removedWorkspacesFile() {
13840
- return (0, import_node_path34.join)(appDataDir(), "removed-workspaces.json");
14027
+ return (0, import_node_path35.join)(appDataDir(), "removed-workspaces.json");
13841
14028
  }
13842
14029
  function readAll2() {
13843
14030
  const path2 = workspacesFile();
13844
- if (!(0, import_node_fs34.existsSync)(path2)) return [];
14031
+ if (!(0, import_node_fs35.existsSync)(path2)) return [];
13845
14032
  try {
13846
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
14033
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13847
14034
  return Array.isArray(raw) ? raw : [];
13848
14035
  } catch {
13849
14036
  return [];
13850
14037
  }
13851
14038
  }
13852
14039
  function writeAll2(list) {
13853
- (0, import_node_fs34.mkdirSync)(appDataDir(), { recursive: true });
13854
- (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");
13855
14042
  }
13856
14043
  function readRemoved() {
13857
14044
  const path2 = removedWorkspacesFile();
13858
- if (!(0, import_node_fs34.existsSync)(path2)) return /* @__PURE__ */ new Set();
14045
+ if (!(0, import_node_fs35.existsSync)(path2)) return /* @__PURE__ */ new Set();
13859
14046
  try {
13860
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
14047
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13861
14048
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
13862
14049
  } catch {
13863
14050
  return /* @__PURE__ */ new Set();
13864
14051
  }
13865
14052
  }
13866
14053
  function writeRemoved(paths) {
13867
- (0, import_node_fs34.mkdirSync)(appDataDir(), { recursive: true });
13868
- (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");
13869
14056
  }
13870
14057
  function rememberRemoved(repoPath) {
13871
14058
  const next = readRemoved();
@@ -13888,7 +14075,7 @@ function listWorkspaces() {
13888
14075
  async function addWorkspace(repoPath) {
13889
14076
  const root = await resolveRepoRoot(repoPath);
13890
14077
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
13891
- 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}`);
13892
14079
  forgetRemoved(root);
13893
14080
  await ensureGhPreferOrigin(root);
13894
14081
  const current = readAll2();
@@ -13896,7 +14083,7 @@ async function addWorkspace(repoPath) {
13896
14083
  if (existing) return existing;
13897
14084
  const next = {
13898
14085
  path: root,
13899
- name: (0, import_node_path34.basename)(root),
14086
+ name: (0, import_node_path35.basename)(root),
13900
14087
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
13901
14088
  };
13902
14089
  writeAll2([...current, next]);
@@ -13918,10 +14105,10 @@ function syncWorkspacesFromThreads(repoPaths) {
13918
14105
  if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
13919
14106
  continue;
13920
14107
  }
13921
- if (!(0, import_node_fs34.existsSync)(path2)) continue;
14108
+ if (!(0, import_node_fs35.existsSync)(path2)) continue;
13922
14109
  const ws = {
13923
14110
  path: path2,
13924
- name: (0, import_node_path34.basename)(path2),
14111
+ name: (0, import_node_path35.basename)(path2),
13925
14112
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
13926
14113
  };
13927
14114
  byPath.set(path2, ws);
@@ -13931,12 +14118,12 @@ function syncWorkspacesFromThreads(repoPaths) {
13931
14118
  if (dirty) writeAll2(next);
13932
14119
  return next.sort((a, b) => a.name.localeCompare(b.name));
13933
14120
  }
13934
- var import_node_fs34, import_node_path34;
14121
+ var import_node_fs35, import_node_path35;
13935
14122
  var init_workspaces2 = __esm({
13936
14123
  "src/store/workspaces.ts"() {
13937
14124
  "use strict";
13938
- import_node_fs34 = require("fs");
13939
- import_node_path34 = require("path");
14125
+ import_node_fs35 = require("fs");
14126
+ import_node_path35 = require("path");
13940
14127
  init_paths();
13941
14128
  init_global_workspace();
13942
14129
  init_worktree();
@@ -13949,12 +14136,12 @@ async function cloneRepoIntoSideboard(opts) {
13949
14136
  if (!url) throw new Error("Clone URL is required");
13950
14137
  let name = opts.name?.trim();
13951
14138
  if (!name) {
13952
- const leaf = (0, import_node_path35.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
14139
+ const leaf = (0, import_node_path36.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
13953
14140
  name = leaf || "repo";
13954
14141
  }
13955
14142
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
13956
- const dest = (0, import_node_path35.join)(sideboardReposDir(), name);
13957
- 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)) {
13958
14145
  const repoPath2 = await resolveRepoRoot(dest);
13959
14146
  const workspace2 = await ensureWorkspace(repoPath2);
13960
14147
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -13969,12 +14156,12 @@ async function cloneRepoIntoSideboard(opts) {
13969
14156
  const workspace = await ensureWorkspace(repoPath);
13970
14157
  return { repoPath, workspace };
13971
14158
  }
13972
- var import_node_fs35, import_node_path35, import_execa6;
14159
+ var import_node_fs36, import_node_path36, import_execa6;
13973
14160
  var init_clone_repo = __esm({
13974
14161
  "src/git/clone-repo.ts"() {
13975
14162
  "use strict";
13976
- import_node_fs35 = require("fs");
13977
- import_node_path35 = require("path");
14163
+ import_node_fs36 = require("fs");
14164
+ import_node_path36 = require("path");
13978
14165
  import_execa6 = require("execa");
13979
14166
  init_paths();
13980
14167
  init_workspaces2();
@@ -14991,7 +15178,7 @@ function persistCreateAttachments(worktreePath, attachments) {
14991
15178
  }
14992
15179
  async function createThread(input, _onSetupLine) {
14993
15180
  const repoPath = await resolveRepoRoot(input.repoPath);
14994
- if (!(0, import_node_fs36.existsSync)(repoPath)) {
15181
+ if (!(0, import_node_fs37.existsSync)(repoPath)) {
14995
15182
  throw new Error(`Repo not found: ${repoPath}`);
14996
15183
  }
14997
15184
  if (input.reuseExisting !== false) {
@@ -15166,11 +15353,11 @@ async function listLinearIssues(agent, repoPath) {
15166
15353
  }
15167
15354
  return adapter.listLinearIssues(repoPath);
15168
15355
  }
15169
- var import_node_fs36;
15356
+ var import_node_fs37;
15170
15357
  var init_create = __esm({
15171
15358
  "src/threads/create.ts"() {
15172
15359
  "use strict";
15173
- import_node_fs36 = require("fs");
15360
+ import_node_fs37 = require("fs");
15174
15361
  init_detect();
15175
15362
  init_worktree();
15176
15363
  init_home_board();
@@ -15273,20 +15460,20 @@ function writeTurnLive(threadId, progress) {
15273
15460
  const path2 = threadLivePath(threadId);
15274
15461
  const tmp = `${path2}.${process.pid}.tmp`;
15275
15462
  try {
15276
- (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
15277
- (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);
15278
15465
  } catch {
15279
15466
  try {
15280
- (0, import_node_fs37.unlinkSync)(tmp);
15467
+ (0, import_node_fs38.unlinkSync)(tmp);
15281
15468
  } catch {
15282
15469
  }
15283
15470
  }
15284
15471
  }
15285
15472
  function readTurnLive(threadId) {
15286
15473
  const path2 = threadLivePath(threadId);
15287
- if (!(0, import_node_fs37.existsSync)(path2)) return null;
15474
+ if (!(0, import_node_fs38.existsSync)(path2)) return null;
15288
15475
  try {
15289
- const raw = JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8"));
15476
+ const raw = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
15290
15477
  if (!raw || typeof raw.summary !== "string") return null;
15291
15478
  return raw;
15292
15479
  } catch {
@@ -15298,17 +15485,17 @@ function clearTurnLive(threadId) {
15298
15485
  if (buf?.timer) clearTimeout(buf.timer);
15299
15486
  buffers.delete(threadId);
15300
15487
  const path2 = threadLivePath(threadId);
15301
- if (!(0, import_node_fs37.existsSync)(path2)) return;
15488
+ if (!(0, import_node_fs38.existsSync)(path2)) return;
15302
15489
  try {
15303
- (0, import_node_fs37.unlinkSync)(path2);
15490
+ (0, import_node_fs38.unlinkSync)(path2);
15304
15491
  } catch {
15305
15492
  }
15306
15493
  }
15307
- var import_node_fs37, buffers, FLUSH_MS, MAX_PARTS;
15494
+ var import_node_fs38, buffers, FLUSH_MS, MAX_PARTS;
15308
15495
  var init_turn_live = __esm({
15309
15496
  "src/store/turn-live.ts"() {
15310
15497
  "use strict";
15311
- import_node_fs37 = require("fs");
15498
+ import_node_fs38 = require("fs");
15312
15499
  init_message_parts();
15313
15500
  init_paths();
15314
15501
  buffers = /* @__PURE__ */ new Map();
@@ -15482,7 +15669,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
15482
15669
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
15483
15670
  ].join("\n");
15484
15671
  return {
15485
- id: (0, import_node_crypto8.randomUUID)(),
15672
+ id: (0, import_node_crypto9.randomUUID)(),
15486
15673
  name: "Orchestration quota handoff.md",
15487
15674
  kind: "transcript",
15488
15675
  content: body
@@ -15503,11 +15690,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
15503
15690
  sourceType: "orchestration"
15504
15691
  });
15505
15692
  }
15506
- var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
15693
+ var import_node_crypto9, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
15507
15694
  var init_quota_failover = __esm({
15508
15695
  "src/orchestrator/quota-failover.ts"() {
15509
15696
  "use strict";
15510
- import_node_crypto8 = require("crypto");
15697
+ import_node_crypto9 = require("crypto");
15511
15698
  init_session_quota();
15512
15699
  init_app_settings();
15513
15700
  init_global_workspace();
@@ -15524,7 +15711,7 @@ var init_quota_failover = __esm({
15524
15711
  // src/threads/adopt.ts
15525
15712
  function thisModuleFile() {
15526
15713
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
15527
- 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");
15528
15715
  }
15529
15716
  function openReadonlySqlite(file) {
15530
15717
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -15542,21 +15729,21 @@ function mapAgentType(raw) {
15542
15729
  return null;
15543
15730
  }
15544
15731
  function resolveConductorCursorAgentId(workspacePath) {
15545
- 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;
15546
15733
  const normalized = workspacePath.replace(/\/$/, "");
15547
15734
  let best = null;
15548
15735
  let hashes;
15549
15736
  try {
15550
- hashes = (0, import_node_fs38.readdirSync)(CURSOR_SDK_STORE);
15737
+ hashes = (0, import_node_fs39.readdirSync)(CURSOR_SDK_STORE);
15551
15738
  } catch {
15552
15739
  return null;
15553
15740
  }
15554
15741
  for (const hash of hashes) {
15555
- const agentsFile = (0, import_node_path36.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
15556
- 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;
15557
15744
  let text5;
15558
15745
  try {
15559
- text5 = (0, import_node_fs38.readFileSync)(agentsFile, "utf8");
15746
+ text5 = (0, import_node_fs39.readFileSync)(agentsFile, "utf8");
15560
15747
  } catch {
15561
15748
  continue;
15562
15749
  }
@@ -15580,7 +15767,7 @@ function resolveConductorCursorAgentId(workspacePath) {
15580
15767
  return best?.agentId ?? null;
15581
15768
  }
15582
15769
  async function adoptThread(input) {
15583
- if (!(0, import_node_fs38.existsSync)(input.worktreePath)) {
15770
+ if (!(0, import_node_fs39.existsSync)(input.worktreePath)) {
15584
15771
  throw new Error(`Worktree not found: ${input.worktreePath}`);
15585
15772
  }
15586
15773
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -15601,24 +15788,26 @@ async function adoptThread(input) {
15601
15788
  writeThread(thread);
15602
15789
  const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
15603
15790
  await ensureWorkspace2(repoPath);
15791
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
15792
+ await ensureWorktreeSideboardIgnored2(input.worktreePath);
15604
15793
  return thread;
15605
15794
  }
15606
15795
  function conductorDbPath() {
15607
15796
  return CONDUCTOR_DB;
15608
15797
  }
15609
15798
  function listConductorWorkspaces() {
15610
- if (!(0, import_node_fs38.existsSync)(CONDUCTOR_DB)) {
15799
+ if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
15611
15800
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
15612
15801
  }
15613
- const tmp = (0, import_node_fs38.mkdtempSync)((0, import_node_path36.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
15614
- 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");
15615
15804
  try {
15616
- (0, import_node_fs38.copyFileSync)(CONDUCTOR_DB, snapshot);
15805
+ (0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
15617
15806
  for (const suffix of ["-wal", "-shm"]) {
15618
15807
  const src = `${CONDUCTOR_DB}${suffix}`;
15619
- if ((0, import_node_fs38.existsSync)(src)) {
15808
+ if ((0, import_node_fs39.existsSync)(src)) {
15620
15809
  try {
15621
- (0, import_node_fs38.copyFileSync)(src, `${snapshot}${suffix}`);
15810
+ (0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
15622
15811
  } catch {
15623
15812
  }
15624
15813
  }
@@ -15694,22 +15883,22 @@ function listConductorWorkspaces() {
15694
15883
  db.close();
15695
15884
  }
15696
15885
  } finally {
15697
- (0, import_node_fs38.rmSync)(tmp, { recursive: true, force: true });
15886
+ (0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
15698
15887
  }
15699
15888
  }
15700
15889
  function importConductorWorkspace(workspaceId) {
15701
- if (!(0, import_node_fs38.existsSync)(CONDUCTOR_DB)) {
15890
+ if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
15702
15891
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
15703
15892
  }
15704
- const tmp = (0, import_node_fs38.mkdtempSync)((0, import_node_path36.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
15705
- 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");
15706
15895
  try {
15707
- (0, import_node_fs38.copyFileSync)(CONDUCTOR_DB, snapshot);
15896
+ (0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
15708
15897
  for (const suffix of ["-wal", "-shm"]) {
15709
15898
  const src = `${CONDUCTOR_DB}${suffix}`;
15710
- if ((0, import_node_fs38.existsSync)(src)) {
15899
+ if ((0, import_node_fs39.existsSync)(src)) {
15711
15900
  try {
15712
- (0, import_node_fs38.copyFileSync)(src, `${snapshot}${suffix}`);
15901
+ (0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
15713
15902
  } catch {
15714
15903
  }
15715
15904
  }
@@ -15727,7 +15916,7 @@ function importConductorWorkspace(workspaceId) {
15727
15916
  ).get(workspaceId);
15728
15917
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
15729
15918
  const worktreePath = String(row.workspacePath);
15730
- if (!(0, import_node_fs38.existsSync)(worktreePath)) {
15919
+ if (!(0, import_node_fs39.existsSync)(worktreePath)) {
15731
15920
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
15732
15921
  }
15733
15922
  let sessionId = null;
@@ -15790,31 +15979,31 @@ function importConductorWorkspace(workspaceId) {
15790
15979
  db.close();
15791
15980
  }
15792
15981
  } finally {
15793
- (0, import_node_fs38.rmSync)(tmp, { recursive: true, force: true });
15982
+ (0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
15794
15983
  }
15795
15984
  }
15796
15985
  async function importConductorWorkspaceAsync(workspaceId) {
15797
15986
  return importConductorWorkspace(workspaceId);
15798
15987
  }
15799
- 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;
15800
15989
  var init_adopt = __esm({
15801
15990
  "src/threads/adopt.ts"() {
15802
15991
  "use strict";
15803
15992
  import_node_child_process4 = require("child_process");
15804
- import_node_fs38 = require("fs");
15805
- import_node_os10 = require("os");
15806
- import_node_path36 = require("path");
15993
+ import_node_fs39 = require("fs");
15994
+ import_node_os11 = require("os");
15995
+ import_node_path37 = require("path");
15807
15996
  import_node_module4 = require("module");
15808
15997
  init_worktree();
15809
15998
  init_thread_store();
15810
- CONDUCTOR_APP_SUPPORT = (0, import_node_path36.join)(
15999
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path37.join)(
15811
16000
  process.env.HOME ?? "",
15812
16001
  "Library",
15813
16002
  "Application Support",
15814
16003
  "com.conductor.app"
15815
16004
  );
15816
- CONDUCTOR_DB = (0, import_node_path36.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
15817
- 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");
15818
16007
  }
15819
16008
  });
15820
16009
 
@@ -15881,7 +16070,7 @@ async function openStackLayer(input, _onSetupLine) {
15881
16070
  let createdWorktree = false;
15882
16071
  const trees = await listWorktrees(repoPath);
15883
16072
  const checkedOut = trees.find((w) => w.branch === branchName);
15884
- if (checkedOut?.path && (0, import_node_fs39.existsSync)(checkedOut.path)) {
16073
+ if (checkedOut?.path && (0, import_node_fs40.existsSync)(checkedOut.path)) {
15885
16074
  if (input.reuseExistingWorktree !== false) {
15886
16075
  worktreePath = checkedOut.path;
15887
16076
  } else {
@@ -16023,7 +16212,7 @@ async function initStackFromThread(input, onSetupLine) {
16023
16212
  async function createPrStack(input, onSetupLine) {
16024
16213
  await requireAgent(input.agent);
16025
16214
  const repoPath = await resolveRepoRoot(input.repoPath);
16026
- 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}`);
16027
16216
  if (!input.branches.length) throw new Error("At least one branch name required");
16028
16217
  const status = await detectGhStack(repoPath);
16029
16218
  if (!status.available) throw new Error(status.reason);
@@ -16090,7 +16279,7 @@ async function createPrStack(input, onSetupLine) {
16090
16279
  }
16091
16280
  }
16092
16281
  const claimed = new Set(threads.map((t) => t.worktreePath));
16093
- 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)) {
16094
16283
  try {
16095
16284
  await removeWorktree(repoPath, bootstrap.worktreePath, {
16096
16285
  deleteBranch: bootstrap.branchName
@@ -16110,11 +16299,11 @@ function stackAgentDefaultsFrom(input) {
16110
16299
  planMode: input.planMode
16111
16300
  };
16112
16301
  }
16113
- var import_node_fs39;
16302
+ var import_node_fs40;
16114
16303
  var init_stack_layers = __esm({
16115
16304
  "src/threads/stack-layers.ts"() {
16116
16305
  "use strict";
16117
- import_node_fs39 = require("fs");
16306
+ import_node_fs40 = require("fs");
16118
16307
  init_detect();
16119
16308
  init_run();
16120
16309
  init_stack();
@@ -16127,7 +16316,7 @@ var init_stack_layers = __esm({
16127
16316
 
16128
16317
  // src/diff/diff.ts
16129
16318
  async function inspectGitWorktree(worktreePath) {
16130
- if (!worktreePath || !(0, import_node_fs40.existsSync)(worktreePath)) return "missing_worktree";
16319
+ if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) return "missing_worktree";
16131
16320
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
16132
16321
  reject: false
16133
16322
  });
@@ -16135,7 +16324,7 @@ async function inspectGitWorktree(worktreePath) {
16135
16324
  return "ok";
16136
16325
  }
16137
16326
  async function initializeGitRepository(worktreePath) {
16138
- if (!worktreePath || !(0, import_node_fs40.existsSync)(worktreePath)) {
16327
+ if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) {
16139
16328
  throw new Error("Worktree not found");
16140
16329
  }
16141
16330
  const status = await inspectGitWorktree(worktreePath);
@@ -16269,11 +16458,11 @@ new file mode 100644
16269
16458
  };
16270
16459
  }
16271
16460
  async function untrackedPatch(worktreePath, path2, maxHunk) {
16272
- const abs = (0, import_node_path37.join)(worktreePath, path2);
16461
+ const abs = (0, import_node_path38.join)(worktreePath, path2);
16273
16462
  try {
16274
- const st = (0, import_node_fs40.statSync)(abs);
16463
+ const st = (0, import_node_fs41.statSync)(abs);
16275
16464
  if (st.isFile() && st.size > maxHunk) {
16276
- const buf = (0, import_node_fs40.readFileSync)(abs).subarray(0, maxHunk);
16465
+ const buf = (0, import_node_fs41.readFileSync)(abs).subarray(0, maxHunk);
16277
16466
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
16278
16467
  }
16279
16468
  } catch {
@@ -16762,8 +16951,8 @@ function isImageRelativePath(relativePath) {
16762
16951
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16763
16952
  assertSafeRelativePath(relativePath);
16764
16953
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
16765
- const abs = (0, import_node_path37.join)(worktreePath, relativePath);
16766
- 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);
16767
16956
  if (!st.isFile()) {
16768
16957
  throw new Error(`Not a file: ${relativePath}`);
16769
16958
  }
@@ -16772,7 +16961,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16772
16961
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
16773
16962
  );
16774
16963
  }
16775
- const buf = (0, import_node_fs40.readFileSync)(abs);
16964
+ const buf = (0, import_node_fs41.readFileSync)(abs);
16776
16965
  return {
16777
16966
  path: relativePath,
16778
16967
  contentBase64: buf.toString("base64"),
@@ -16782,12 +16971,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16782
16971
  function readWorktreeFile(worktreePath, relativePath, opts) {
16783
16972
  assertSafeRelativePath(relativePath);
16784
16973
  const maxBytes = opts?.maxBytes ?? 2e5;
16785
- const abs = (0, import_node_path37.join)(worktreePath, relativePath);
16786
- 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);
16787
16976
  if (!st.isFile()) {
16788
16977
  throw new Error(`Not a file: ${relativePath}`);
16789
16978
  }
16790
- const buf = (0, import_node_fs40.readFileSync)(abs);
16979
+ const buf = (0, import_node_fs41.readFileSync)(abs);
16791
16980
  if (isImageRelativePath(relativePath)) {
16792
16981
  const maxImageBytes = Math.max(maxBytes, 15e6);
16793
16982
  const truncated2 = buf.length > maxImageBytes;
@@ -16830,9 +17019,9 @@ function assertSafeRelativePath(relativePath) {
16830
17019
  }
16831
17020
  function writeWorktreeFile(worktreePath, relativePath, content) {
16832
17021
  assertSafeRelativePath(relativePath);
16833
- const abs = (0, import_node_path37.join)(worktreePath, relativePath);
16834
- (0, import_node_fs40.mkdirSync)((0, import_node_path37.dirname)(abs), { recursive: true });
16835
- (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");
16836
17025
  return { path: relativePath };
16837
17026
  }
16838
17027
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -16849,12 +17038,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
16849
17038
  truncated: full.files.length > maxFiles
16850
17039
  };
16851
17040
  }
16852
- 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;
16853
17042
  var init_diff = __esm({
16854
17043
  "src/diff/diff.ts"() {
16855
17044
  "use strict";
16856
- import_node_fs40 = require("fs");
16857
- import_node_path37 = require("path");
17045
+ import_node_fs41 = require("fs");
17046
+ import_node_path38 = require("path");
16858
17047
  init_run();
16859
17048
  init_worktree();
16860
17049
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -17112,7 +17301,7 @@ function parseFrontmatter(content) {
17112
17301
  }
17113
17302
  function readSkill(skillMd, source) {
17114
17303
  try {
17115
- const content = (0, import_node_fs41.readFileSync)(skillMd, "utf8");
17304
+ const content = (0, import_node_fs42.readFileSync)(skillMd, "utf8");
17116
17305
  const { name: fmName, description } = parseFrontmatter(content);
17117
17306
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
17118
17307
  const name = fmName || dirName;
@@ -17131,19 +17320,19 @@ function readSkill(skillMd, source) {
17131
17320
  }
17132
17321
  }
17133
17322
  function scanSkillsDir(dir, source, out) {
17134
- if (!(0, import_node_fs41.existsSync)(dir)) return;
17323
+ if (!(0, import_node_fs42.existsSync)(dir)) return;
17135
17324
  let entries;
17136
17325
  try {
17137
- entries = (0, import_node_fs41.readdirSync)(dir);
17326
+ entries = (0, import_node_fs42.readdirSync)(dir);
17138
17327
  } catch {
17139
17328
  return;
17140
17329
  }
17141
17330
  for (const entry of entries) {
17142
17331
  if (entry.startsWith(".")) continue;
17143
- const skillMd = (0, import_node_path38.join)(dir, entry, "SKILL.md");
17144
- 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;
17145
17334
  try {
17146
- if (!(0, import_node_fs41.statSync)(skillMd).isFile()) continue;
17335
+ if (!(0, import_node_fs42.statSync)(skillMd).isFile()) continue;
17147
17336
  } catch {
17148
17337
  continue;
17149
17338
  }
@@ -17152,24 +17341,24 @@ function scanSkillsDir(dir, source, out) {
17152
17341
  }
17153
17342
  }
17154
17343
  function scanClaudePluginSkills(pluginsRoot, out) {
17155
- if (!(0, import_node_fs41.existsSync)(pluginsRoot)) return;
17344
+ if (!(0, import_node_fs42.existsSync)(pluginsRoot)) return;
17156
17345
  const walk = (dir, depth, lookingForSkillsDir) => {
17157
17346
  if (depth > 7) return;
17158
17347
  let entries;
17159
17348
  try {
17160
- entries = (0, import_node_fs41.readdirSync)(dir);
17349
+ entries = (0, import_node_fs42.readdirSync)(dir);
17161
17350
  } catch {
17162
17351
  return;
17163
17352
  }
17164
17353
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
17165
- 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");
17166
17355
  if (skill) out.push(skill);
17167
17356
  }
17168
17357
  for (const entry of entries) {
17169
17358
  if (entry === "node_modules" || entry === ".git") continue;
17170
- const full = (0, import_node_path38.join)(dir, entry);
17359
+ const full = (0, import_node_path39.join)(dir, entry);
17171
17360
  try {
17172
- if (!(0, import_node_fs41.statSync)(full).isDirectory()) continue;
17361
+ if (!(0, import_node_fs42.statSync)(full).isDirectory()) continue;
17173
17362
  } catch {
17174
17363
  continue;
17175
17364
  }
@@ -17184,20 +17373,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
17184
17373
  walk(pluginsRoot, 0, false);
17185
17374
  }
17186
17375
  function discoverSkills(worktreePath) {
17187
- const home = (0, import_node_os11.homedir)();
17376
+ const home = (0, import_node_os12.homedir)();
17188
17377
  const collected = [];
17189
17378
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
17190
- scanSkillsDir((0, import_node_path38.join)(worktreePath, rel), "workspace", collected);
17379
+ scanSkillsDir((0, import_node_path39.join)(worktreePath, rel), "workspace", collected);
17191
17380
  }
17192
17381
  for (const abs of [
17193
- (0, import_node_path38.join)(home, ".claude/skills"),
17194
- (0, import_node_path38.join)(home, ".cursor/skills"),
17195
- (0, import_node_path38.join)(home, ".sideboard/skills"),
17196
- (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")
17197
17386
  ]) {
17198
17387
  scanSkillsDir(abs, "user", collected);
17199
17388
  }
17200
- scanClaudePluginSkills((0, import_node_path38.join)(home, ".claude/plugins"), collected);
17389
+ scanClaudePluginSkills((0, import_node_path39.join)(home, ".claude/plugins"), collected);
17201
17390
  collected.push(...bundledSkills());
17202
17391
  const rank = {
17203
17392
  workspace: 0,
@@ -17223,7 +17412,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
17223
17412
  \u2026(truncated)` : body;
17224
17413
  }
17225
17414
  }
17226
- const raw = (0, import_node_fs41.readFileSync)(skillPath, "utf8");
17415
+ const raw = (0, import_node_fs42.readFileSync)(skillPath, "utf8");
17227
17416
  if (raw.startsWith("---")) {
17228
17417
  const end = raw.indexOf("\n---", 3);
17229
17418
  if (end >= 0) {
@@ -17237,13 +17426,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
17237
17426
 
17238
17427
  \u2026(truncated)` : raw;
17239
17428
  }
17240
- 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;
17241
17430
  var init_discover = __esm({
17242
17431
  "src/skills/discover.ts"() {
17243
17432
  "use strict";
17244
- import_node_fs41 = require("fs");
17245
- import_node_os11 = require("os");
17246
- import_node_path38 = require("path");
17433
+ import_node_fs42 = require("fs");
17434
+ import_node_os12 = require("os");
17435
+ import_node_path39 = require("path");
17247
17436
  init_long_running();
17248
17437
  BUNDLED_SKILL_PREFIX = "bundled:";
17249
17438
  }
@@ -17338,17 +17527,17 @@ var init_expand = __esm({
17338
17527
  function packagedDetachedJobPath() {
17339
17528
  const dir = packagedMcpDir();
17340
17529
  if (!dir) return null;
17341
- const script = (0, import_node_path39.join)(dir, "scripts", "detached-job.js");
17342
- 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;
17343
17532
  }
17344
17533
  function resolveDetachedJobScript() {
17345
17534
  const packaged = packagedDetachedJobPath();
17346
17535
  if (packaged) return packaged;
17347
- 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));
17348
17537
  for (let i = 0; i < 8; i++) {
17349
- const candidate = (0, import_node_path39.join)(dir, "scripts", "detached-job.js");
17350
- if ((0, import_node_fs42.existsSync)(candidate)) return candidate;
17351
- 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);
17352
17541
  if (parent === dir) break;
17353
17542
  dir = parent;
17354
17543
  }
@@ -17359,12 +17548,12 @@ function formatDetachedJobInvoke(scriptPath) {
17359
17548
  if (resolved) return `node ${JSON.stringify(resolved)}`;
17360
17549
  return "node scripts/detached-job.js";
17361
17550
  }
17362
- 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;
17363
17552
  var init_detached_job_path = __esm({
17364
17553
  "src/skills/detached-job-path.ts"() {
17365
17554
  "use strict";
17366
- import_node_fs42 = require("fs");
17367
- import_node_path39 = require("path");
17555
+ import_node_fs43 = require("fs");
17556
+ import_node_path40 = require("path");
17368
17557
  import_node_url3 = require("url");
17369
17558
  init_packaged_runtime();
17370
17559
  import_meta3 = {};
@@ -17437,11 +17626,11 @@ function formatWorktreeDirective(thread, opts) {
17437
17626
  );
17438
17627
  } else if (opts?.githubSlug) {
17439
17628
  lines.push(
17440
- `- 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\`.`
17441
17630
  );
17442
17631
  } else {
17443
17632
  lines.push(
17444
- "- 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`."
17445
17634
  );
17446
17635
  }
17447
17636
  lines.push("");
@@ -17539,11 +17728,11 @@ function loadAgentInstructions(worktreePath, agent) {
17539
17728
  const out = [];
17540
17729
  for (const rel of candidates) {
17541
17730
  if (seenPaths.has(rel)) continue;
17542
- const abs = (0, import_node_path40.join)(worktreePath, rel);
17543
- 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;
17544
17733
  try {
17545
- if (!(0, import_node_fs43.statSync)(abs).isFile()) continue;
17546
- 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");
17547
17736
  if (!content.trim()) continue;
17548
17737
  if (content.length > MAX_CHARS_PER_FILE) {
17549
17738
  content = `${content.slice(0, MAX_CHARS_PER_FILE)}
@@ -17583,12 +17772,12 @@ function withAgentInstructions(prompt, files) {
17583
17772
 
17584
17773
  ${prompt}`;
17585
17774
  }
17586
- 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;
17587
17776
  var init_instructions = __esm({
17588
17777
  "src/agents/instructions.ts"() {
17589
17778
  "use strict";
17590
- import_node_fs43 = require("fs");
17591
- import_node_path40 = require("path");
17779
+ import_node_fs44 = require("fs");
17780
+ import_node_path41 = require("path");
17592
17781
  init_git_auth_mode();
17593
17782
  init_worktree_labels();
17594
17783
  init_detached_job_path();
@@ -17934,40 +18123,40 @@ __export(plan_file_exports, {
17934
18123
  writePlanFile: () => writePlanFile
17935
18124
  });
17936
18125
  function ensureAttachmentsGitignore(worktreePath) {
17937
- const gitignoreAbs = (0, import_node_path41.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
17938
- if ((0, import_node_fs44.existsSync)(gitignoreAbs)) return;
17939
- (0, import_node_fs44.mkdirSync)((0, import_node_path41.dirname)(gitignoreAbs), { recursive: true });
17940
- (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");
17941
18130
  }
17942
18131
  function planFileAbs(worktreePath) {
17943
- return (0, import_node_path41.join)(worktreePath, PLAN_FILE_REL);
18132
+ return (0, import_node_path42.join)(worktreePath, PLAN_FILE_REL);
17944
18133
  }
17945
18134
  function readTextIfPresent2(abs) {
17946
- if (!(0, import_node_fs44.existsSync)(abs)) return null;
18135
+ if (!(0, import_node_fs45.existsSync)(abs)) return null;
17947
18136
  try {
17948
- const content = (0, import_node_fs44.readFileSync)(abs, "utf8");
18137
+ const content = (0, import_node_fs45.readFileSync)(abs, "utf8");
17949
18138
  return content.trim() ? content : null;
17950
18139
  } catch {
17951
18140
  return null;
17952
18141
  }
17953
18142
  }
17954
18143
  function readPlanFile(worktreePath) {
17955
- 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));
17956
18145
  }
17957
18146
  function writePlanFile(worktreePath, content) {
17958
18147
  ensureAttachmentsGitignore(worktreePath);
17959
18148
  const abs = planFileAbs(worktreePath);
17960
- (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 });
17961
18150
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
17962
- (0, import_node_fs44.writeFileSync)(abs, body, "utf8");
18151
+ (0, import_node_fs45.writeFileSync)(abs, body, "utf8");
17963
18152
  return PLAN_FILE_REL;
17964
18153
  }
17965
- var import_node_fs44, import_node_path41;
18154
+ var import_node_fs45, import_node_path42;
17966
18155
  var init_plan_file = __esm({
17967
18156
  "src/plan/plan-file.ts"() {
17968
18157
  "use strict";
17969
- import_node_fs44 = require("fs");
17970
- import_node_path41 = require("path");
18158
+ import_node_fs45 = require("fs");
18159
+ import_node_path42 = require("path");
17971
18160
  init_workspace_scratch();
17972
18161
  init_plan_present();
17973
18162
  init_plan_present();
@@ -18015,13 +18204,13 @@ var init_sync_branch = __esm({
18015
18204
 
18016
18205
  // src/agents/cursor-store.ts
18017
18206
  function cursorSdkStoreDir(threadId) {
18018
- 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);
18019
18208
  const id = sanitizeCursorStoreSegment(threadId);
18020
18209
  if (!id) return root;
18021
- return (0, import_node_path42.join)(root, "threads", id);
18210
+ return (0, import_node_path43.join)(root, "threads", id);
18022
18211
  }
18023
18212
  function cursorSdkRunsNdjsonPath(threadId) {
18024
- return (0, import_node_path42.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
18213
+ return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
18025
18214
  }
18026
18215
  function cursorSdkRunsNdjsonSearchPaths(threadId) {
18027
18216
  const scoped = cursorSdkRunsNdjsonPath(threadId);
@@ -18034,11 +18223,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
18034
18223
  function sanitizeCursorStoreSegment(threadId) {
18035
18224
  return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
18036
18225
  }
18037
- var import_node_path42, CURSOR_SDK_STORE_DIR;
18226
+ var import_node_path43, CURSOR_SDK_STORE_DIR;
18038
18227
  var init_cursor_store = __esm({
18039
18228
  "src/agents/cursor-store.ts"() {
18040
18229
  "use strict";
18041
- import_node_path42 = require("path");
18230
+ import_node_path43 = require("path");
18042
18231
  init_paths();
18043
18232
  CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
18044
18233
  }
@@ -18060,9 +18249,9 @@ function recoverFinishedCursorRun(opts) {
18060
18249
  return best;
18061
18250
  }
18062
18251
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
18063
- if (!(0, import_node_fs45.existsSync)(runsPath)) return null;
18252
+ if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
18064
18253
  try {
18065
- const lines = (0, import_node_fs45.readFileSync)(runsPath, "utf8").split("\n");
18254
+ const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
18066
18255
  let best = null;
18067
18256
  for (const line of lines) {
18068
18257
  const trimmed = line.trim();
@@ -18088,11 +18277,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
18088
18277
  return null;
18089
18278
  }
18090
18279
  }
18091
- var import_node_fs45;
18280
+ var import_node_fs46;
18092
18281
  var init_cursor_recover = __esm({
18093
18282
  "src/agents/cursor-recover.ts"() {
18094
18283
  "use strict";
18095
- import_node_fs45 = require("fs");
18284
+ import_node_fs46 = require("fs");
18096
18285
  init_cursor_store();
18097
18286
  }
18098
18287
  });
@@ -18131,6 +18320,7 @@ var init_title = __esm({
18131
18320
  // src/orchestrator/orchestrator.ts
18132
18321
  var orchestrator_exports = {};
18133
18322
  __export(orchestrator_exports, {
18323
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
18134
18324
  Orchestrator: () => Orchestrator,
18135
18325
  getOrchestrator: () => getOrchestrator,
18136
18326
  isPidAlive: () => isPidAlive,
@@ -18223,13 +18413,13 @@ async function startOrchestration(opts) {
18223
18413
  }
18224
18414
  return updated;
18225
18415
  }
18226
- 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;
18227
18417
  var init_orchestrator = __esm({
18228
18418
  "src/orchestrator/orchestrator.ts"() {
18229
18419
  "use strict";
18230
18420
  import_node_events = require("events");
18231
18421
  init_outbound_watch();
18232
- import_node_fs46 = require("fs");
18422
+ import_node_fs47 = require("fs");
18233
18423
  init_error_detail();
18234
18424
  init_run();
18235
18425
  init_stale_lock();
@@ -18244,6 +18434,7 @@ var init_orchestrator = __esm({
18244
18434
  init_orphan_cleanup();
18245
18435
  init_apply_into_main();
18246
18436
  init_clone_repo();
18437
+ init_message_parts();
18247
18438
  init_usage();
18248
18439
  init_thread_store();
18249
18440
  init_desktop_host();
@@ -18281,6 +18472,7 @@ var init_orchestrator = __esm({
18281
18472
  init_caffeinate_hold();
18282
18473
  init_schedule_runner();
18283
18474
  init_coordinator_prompt();
18475
+ LIVE_TURN_SPAWN_GRACE_MS = 15e3;
18284
18476
  STALE_AGENT_PID_WAIT_MS = 2500;
18285
18477
  Orchestrator = class {
18286
18478
  events = new import_node_events.EventEmitter();
@@ -18337,6 +18529,39 @@ var init_orchestrator = __esm({
18337
18529
  if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
18338
18530
  return true;
18339
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
+ }
18340
18565
  async reconcile(repoPath, opts) {
18341
18566
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
18342
18567
  const drainQueues = opts?.drainQueues !== false;
@@ -18361,7 +18586,7 @@ var init_orchestrator = __esm({
18361
18586
  }
18362
18587
  continue;
18363
18588
  }
18364
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
18589
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
18365
18590
  setStatus(thread.id, "broken", "Worktree missing on disk");
18366
18591
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
18367
18592
  continue;
@@ -18671,12 +18896,14 @@ var init_orchestrator = __esm({
18671
18896
  this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
18672
18897
  return thread;
18673
18898
  }
18674
- async send(threadRef, prompt) {
18899
+ async send(threadRef, prompt, opts) {
18675
18900
  const thread = this.requireThread(threadRef);
18676
18901
  if (thread.status === "archived") {
18677
18902
  throw new Error(`Thread is archived: ${thread.id}`);
18678
18903
  }
18679
- 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 () => {
18680
18907
  const current = this.requireThread(thread.id);
18681
18908
  if (current.status === "archived") {
18682
18909
  throw new Error(`Thread is archived: ${thread.id}`);
@@ -18685,6 +18912,7 @@ var init_orchestrator = __esm({
18685
18912
  this.crashContinued.delete(thread.id);
18686
18913
  this.haltDrain.delete(thread.id);
18687
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);
18688
18916
  const patch = { queue };
18689
18917
  if (!inFlight) patch.status = "queued";
18690
18918
  const pid = current.agentPid;
@@ -18696,16 +18924,20 @@ var init_orchestrator = __esm({
18696
18924
  if (!inFlight) {
18697
18925
  this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
18698
18926
  }
18699
- if (thisProcessShouldDrainAgentQueues()) {
18927
+ if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
18700
18928
  void this.drainQueue(thread.id);
18701
18929
  }
18702
18930
  return this.requireThread(thread.id);
18703
18931
  });
18932
+ if (shouldSteer && sent.queue.length > 0) {
18933
+ return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
18934
+ }
18935
+ return sent;
18704
18936
  }
18705
- async fanOut(threadRefs, prompt) {
18937
+ async fanOut(threadRefs, prompt, opts) {
18706
18938
  const results = [];
18707
18939
  for (const ref of threadRefs) {
18708
- results.push(await this.send(ref, prompt));
18940
+ results.push(await this.send(ref, prompt, opts));
18709
18941
  }
18710
18942
  return results;
18711
18943
  }
@@ -19509,8 +19741,8 @@ var init_orchestrator = __esm({
19509
19741
  return created;
19510
19742
  }
19511
19743
  async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
19512
- const thread = this.requireThread(threadRef);
19513
- if (!["running", "queued"].includes(thread.status)) {
19744
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19745
+ if (!this.threadLooksLive(thread)) {
19514
19746
  return thread;
19515
19747
  }
19516
19748
  const start = Date.now();
@@ -19547,12 +19779,13 @@ var init_orchestrator = __esm({
19547
19779
  }
19548
19780
  });
19549
19781
  timer = setInterval(() => {
19550
- const current = readThread(thread.id);
19551
- if (!current) {
19782
+ const raw = readThread(thread.id);
19783
+ if (!raw) {
19552
19784
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
19553
19785
  return;
19554
19786
  }
19555
- if (!["running", "queued"].includes(current.status)) {
19787
+ const current = this.healStaleReportedActivity(raw);
19788
+ if (!this.threadLooksLive(current)) {
19556
19789
  finish(() => resolve(current));
19557
19790
  return;
19558
19791
  }
@@ -19575,20 +19808,22 @@ var init_orchestrator = __esm({
19575
19808
  };
19576
19809
  }
19577
19810
  getTurnResult(threadRef) {
19578
- const thread = this.requireThread(threadRef);
19811
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19579
19812
  const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
19580
19813
  const lastError = thread.lastError ?? null;
19581
- const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
19582
- 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);
19583
19817
  const live = stillRunning ? readTurnLive(thread.id) : null;
19584
- 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;
19585
19820
  return {
19586
19821
  text: text5,
19587
19822
  status: thread.status,
19588
19823
  sessionId: thread.sessionId,
19589
19824
  lastError,
19590
19825
  stillRunning,
19591
- progress: live?.summary ?? queuedHint,
19826
+ progress: liveSummary ?? queuedHint,
19592
19827
  lastActivityAt: live?.updatedAt ?? null,
19593
19828
  usage: lastAgent?.usage ?? null
19594
19829
  };
@@ -19936,7 +20171,14 @@ var init_orchestrator = __esm({
19936
20171
  );
19937
20172
  }
19938
20173
  if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
19939
- 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
+ }
19940
20182
  return this.requireThread(threadRef);
19941
20183
  }
19942
20184
  let prBase;
@@ -20139,7 +20381,7 @@ var init_orchestrator = __esm({
20139
20381
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
20140
20382
  return restored2;
20141
20383
  }
20142
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
20384
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
20143
20385
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
20144
20386
  throw new Error(
20145
20387
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -20151,6 +20393,8 @@ var init_orchestrator = __esm({
20151
20393
  await withRepoGitLock(thread.repoPath, async () => {
20152
20394
  await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
20153
20395
  });
20396
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
20397
+ await ensureWorktreeSideboardIgnored2(dest);
20154
20398
  void createThreadWorktree2;
20155
20399
  void slug;
20156
20400
  }
@@ -20365,7 +20609,10 @@ __export(index_exports, {
20365
20609
  DEFAULT_ABLETIME_HOST: () => DEFAULT_ABLETIME_HOST,
20366
20610
  DEFAULT_WORKTREE_SORT: () => DEFAULT_WORKTREE_SORT,
20367
20611
  FAMOUS_SOCCER_TEAMS: () => FAMOUS_SOCCER_TEAMS,
20612
+ FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
20368
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,
20369
20616
  GLOBAL_WORKSPACE_ID: () => GLOBAL_WORKSPACE_ID,
20370
20617
  HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
20371
20618
  HOME_BOARD_CACHE_TTL_MS: () => HOME_BOARD_CACHE_TTL_MS,
@@ -20377,6 +20624,7 @@ __export(index_exports, {
20377
20624
  LINEAR_OAUTH_PORT: () => LINEAR_OAUTH_PORT,
20378
20625
  LINEAR_OAUTH_REDIRECT: () => LINEAR_OAUTH_REDIRECT,
20379
20626
  LINEAR_OAUTH_SCOPES: () => LINEAR_OAUTH_SCOPES,
20627
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
20380
20628
  LONG_RUNNING_SKILL_COMMAND: () => LONG_RUNNING_SKILL_COMMAND,
20381
20629
  LinearOAuthCancelledError: () => LinearOAuthCancelledError,
20382
20630
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS: () => MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
@@ -20466,6 +20714,7 @@ __export(index_exports, {
20466
20714
  buildCodeRefAttachment: () => buildCodeRefAttachment,
20467
20715
  buildDiffCommentAttachment: () => buildDiffCommentAttachment,
20468
20716
  buildForkTranscriptAttachment: () => buildForkTranscriptAttachment,
20717
+ buildLinearIssueFilter: () => buildLinearIssueFilter,
20469
20718
  buildPastedTextAttachment: () => buildPastedTextAttachment,
20470
20719
  buildPathRefAttachment: () => buildPathRefAttachment,
20471
20720
  buildReviewRequestAttachment: () => buildReviewRequestAttachment,
@@ -20483,6 +20732,7 @@ __export(index_exports, {
20483
20732
  checkoutPrStackLayer: () => checkoutPrStackLayer,
20484
20733
  childEnvWithAppSettings: () => childEnvWithAppSettings,
20485
20734
  claimDesktopHost: () => claimDesktopHost,
20735
+ clampGithubPrBody: () => clampGithubPrBody,
20486
20736
  classifyWorktreeColumn: () => classifyWorktreeColumn,
20487
20737
  claudeAdapter: () => claudeAdapter,
20488
20738
  claudeChromeEnabled: () => claudeChromeEnabled,
@@ -20587,6 +20837,7 @@ __export(index_exports, {
20587
20837
  fireSchedule: () => fireSchedule,
20588
20838
  flattenTurnInput: () => flattenTurnInput,
20589
20839
  flipLinearRelationType: () => flipLinearRelationType,
20840
+ followUpBehavior: () => followUpBehavior,
20590
20841
  forkChatTab: () => forkChatTab,
20591
20842
  forkMessageSlice: () => forkMessageSlice,
20592
20843
  forkThreadWorktree: () => forkThreadWorktree,
@@ -20665,6 +20916,7 @@ __export(index_exports, {
20665
20916
  ghRepoSelectArgs: () => ghRepoSelectArgs,
20666
20917
  git: () => git,
20667
20918
  githubAgentGitEnv: () => githubAgentGitEnv,
20919
+ githubHttpsInsteadOfEntries: () => githubHttpsInsteadOfEntries,
20668
20920
  globalAgentCwd: () => globalAgentCwd,
20669
20921
  groupHomeBoardWorktrees: () => groupHomeBoardWorktrees,
20670
20922
  handleSlackInbound: () => handleSlackInbound,
@@ -20701,6 +20953,7 @@ __export(index_exports, {
20701
20953
  isDefaultishSourceRef: () => isDefaultishSourceRef,
20702
20954
  isDesktopHostAlive: () => isDesktopHostAlive,
20703
20955
  isDirty: () => isDirty,
20956
+ isGhPrBodyTooLongError: () => isGhPrBodyTooLongError,
20704
20957
  isGhRateLimitError: () => isGhRateLimitError,
20705
20958
  isGlobalRepoPath: () => isGlobalRepoPath,
20706
20959
  isGlobalThread: () => isGlobalThread,
@@ -20708,6 +20961,7 @@ __export(index_exports, {
20708
20961
  isImageFilePath: () => isImageFilePath,
20709
20962
  isInPrStack: () => isInPrStack,
20710
20963
  isInboundForThisDesktop: () => isInboundForThisDesktop,
20964
+ isInternalAgentStatusText: () => isInternalAgentStatusText,
20711
20965
  isIssueSourceConnected: () => isIssueSourceConnected,
20712
20966
  isLinearConnected: () => isLinearConnected,
20713
20967
  isLinearOAuthCancelled: () => isLinearOAuthCancelled,
@@ -20734,6 +20988,7 @@ __export(index_exports, {
20734
20988
  isThreadRecordFile: () => isThreadRecordFile,
20735
20989
  isWorkspaceScratchPath: () => isWorkspaceScratchPath,
20736
20990
  issueAttachmentForAbleTimeTask: () => issueAttachmentForAbleTimeTask,
20991
+ issueMatchesAssignee: () => issueMatchesAssignee,
20737
20992
  issueSourceLabel: () => issueSourceLabel,
20738
20993
  lastRequestOccupancy: () => lastRequestOccupancy,
20739
20994
  latestPendingPlanQuestions: () => latestPendingPlanQuestions,
@@ -20761,6 +21016,7 @@ __export(index_exports, {
20761
21016
  listLinearAssignedIssues: () => listLinearAssignedIssues,
20762
21017
  listLinearIssues: () => listLinearIssues,
20763
21018
  listLinearIssuesDirect: () => listLinearIssuesDirect,
21019
+ listLinearIssuesFiltered: () => listLinearIssuesFiltered,
20764
21020
  listLinearTeams: () => listLinearTeams,
20765
21021
  listModelsForAgent: () => listModelsForAgent,
20766
21022
  listOpencodeModels: () => listOpencodeModels,
@@ -21102,7 +21358,7 @@ async function refreshGitHubAuth() {
21102
21358
  init_fetch();
21103
21359
 
21104
21360
  // src/integrations/linear-oauth.ts
21105
- var import_node_crypto9 = require("crypto");
21361
+ var import_node_crypto10 = require("crypto");
21106
21362
  var import_node_http = require("http");
21107
21363
  init_app_settings();
21108
21364
  init_fetch();
@@ -21134,8 +21390,8 @@ function linearOAuthCredentials() {
21134
21390
  return { clientId, clientSecret };
21135
21391
  }
21136
21392
  function createLinearPkce() {
21137
- const verifier = (0, import_node_crypto9.randomBytes)(32).toString("base64url");
21138
- 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");
21139
21395
  return { verifier, challenge };
21140
21396
  }
21141
21397
  function linearOAuthAuthorizeUrl(clientId, state, codeChallenge) {
@@ -21266,7 +21522,7 @@ async function startLinearOAuth(opts) {
21266
21522
  throw new LinearOAuthCancelledError();
21267
21523
  }
21268
21524
  const { clientId, clientSecret } = linearOAuthCredentials();
21269
- const state = (0, import_node_crypto9.randomBytes)(16).toString("hex");
21525
+ const state = (0, import_node_crypto10.randomBytes)(16).toString("hex");
21270
21526
  const pkce = createLinearPkce();
21271
21527
  const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
21272
21528
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
@@ -21454,6 +21710,22 @@ query SideboardAssignedIssues($first: Int!) {
21454
21710
  }
21455
21711
  }
21456
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
+ `;
21457
21729
  var TEAMS_QUERY = `
21458
21730
  query SideboardTeams {
21459
21731
  viewer { id name }
@@ -21737,19 +22009,76 @@ function normalizePriority(priority) {
21737
22009
  }
21738
22010
  return priority;
21739
22011
  }
21740
- async function listLinearAssignedIssues(opts) {
21741
- const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
21742
- 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) {
21743
22043
  return {
21744
22044
  viewer: {
21745
22045
  id: String(json.viewer?.id ?? ""),
21746
22046
  name: String(json.viewer?.name ?? "")
21747
22047
  },
21748
- issues: (json.viewer?.assignedIssues?.nodes ?? []).map(
21749
- (node) => toIssueInfo(mapIssue(node))
21750
- )
22048
+ issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
21751
22049
  };
21752
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
+ }
21753
22082
  async function listLinearIssuesDirect(opts) {
21754
22083
  return (await listLinearAssignedIssues(opts)).issues;
21755
22084
  }
@@ -21877,6 +22206,22 @@ init_worktree();
21877
22206
  init_run();
21878
22207
  init_app_settings();
21879
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
+ }
21880
22225
  async function listGitHubIssues(repoPath, opts) {
21881
22226
  const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
21882
22227
  const slug = await resolveGithubRepoSlug(repoPath);
@@ -21890,6 +22235,17 @@ async function listGitHubIssues(repoPath, opts) {
21890
22235
  "--state",
21891
22236
  "open"
21892
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(" "));
21893
22249
  if (slug) args.push("--repo", slug);
21894
22250
  const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
21895
22251
  if (exitCode !== 0 || !stdout.trim()) return [];
@@ -21927,14 +22283,20 @@ async function githubViewerLogin(repoPath) {
21927
22283
  if (exitCode !== 0) return "";
21928
22284
  return stdout.trim();
21929
22285
  }
21930
- async function listIssues(repoPath) {
22286
+ async function listIssues(repoPath, opts) {
21931
22287
  const settings = loadAppSettings();
21932
22288
  const preferredSource = settings.integrations.issueSource ?? "github";
21933
22289
  const linearConnected = isLinearConnected(settings);
21934
22290
  const abletimeConnected = isAbleTimeConnected(settings);
21935
22291
  const source = resolveEffectiveIssueSource(settings);
22292
+ const query = opts?.query?.trim() || void 0;
22293
+ const assignee = opts?.assignee?.trim() || void 0;
21936
22294
  if (source === "linear") {
21937
- const listed = await listLinearAssignedIssues();
22295
+ const listed = await listLinearIssuesFiltered({
22296
+ assignee,
22297
+ query,
22298
+ limit: opts?.limit
22299
+ });
21938
22300
  return {
21939
22301
  source,
21940
22302
  preferredSource,
@@ -21948,13 +22310,20 @@ async function listIssues(repoPath) {
21948
22310
  };
21949
22311
  }
21950
22312
  if (source === "abletime") {
21951
- 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
+ );
21952
22321
  return {
21953
22322
  source,
21954
22323
  preferredSource,
21955
22324
  linearConnected,
21956
22325
  abletimeConnected,
21957
- issues: listed.issues,
22326
+ issues: issues2,
21958
22327
  viewer: {
21959
22328
  login: listed.viewer.name,
21960
22329
  name: listed.viewer.name
@@ -21962,7 +22331,7 @@ async function listIssues(repoPath) {
21962
22331
  };
21963
22332
  }
21964
22333
  const [issues, login] = await Promise.all([
21965
- listGitHubIssues(repoPath),
22334
+ listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
21966
22335
  githubViewerLogin(repoPath)
21967
22336
  ]);
21968
22337
  return {
@@ -22182,7 +22551,7 @@ function buildPathRefAttachment(input) {
22182
22551
  init_stage_files();
22183
22552
 
22184
22553
  // src/composer/pasted-text.ts
22185
- var import_node_crypto10 = require("crypto");
22554
+ var import_node_crypto11 = require("crypto");
22186
22555
  var PASTE_ATTACH_MIN_CHARS = 1200;
22187
22556
  var PASTE_ATTACH_MIN_LINES = 15;
22188
22557
  var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
@@ -22209,7 +22578,7 @@ function nextPastedTextName(existing) {
22209
22578
  }
22210
22579
  function buildPastedTextAttachment(text5, opts) {
22211
22580
  return {
22212
- id: opts?.id ?? (0, import_node_crypto10.randomUUID)(),
22581
+ id: opts?.id ?? (0, import_node_crypto11.randomUUID)(),
22213
22582
  name: opts?.name ?? "Pasted text #1.txt",
22214
22583
  kind: "file",
22215
22584
  path: opts?.path,
@@ -22361,8 +22730,8 @@ init_orphan_cleanup();
22361
22730
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
22362
22731
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
22363
22732
  var import_zod5 = require("zod");
22364
- var import_node_crypto12 = require("crypto");
22365
- var import_node_path45 = require("path");
22733
+ var import_node_crypto13 = require("crypto");
22734
+ var import_node_path46 = require("path");
22366
22735
  init_orchestrator();
22367
22736
  init_worktree();
22368
22737
  init_create();
@@ -22404,14 +22773,16 @@ function mcpWaitFinishedHint(status) {
22404
22773
  }
22405
22774
 
22406
22775
  // src/mcp/server.ts
22776
+ init_message_parts();
22407
22777
  init_turn_live();
22408
22778
 
22409
22779
  // src/mcp/thread-visibility.ts
22780
+ init_message_parts();
22410
22781
  function lastMessagePreview(messages, max = 160) {
22411
22782
  if (!messages?.length) return null;
22412
22783
  for (let i = messages.length - 1; i >= 0; i--) {
22413
22784
  const text5 = messages[i]?.text?.trim();
22414
- if (!text5) continue;
22785
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
22415
22786
  const flat = text5.replace(/\s+/g, " ");
22416
22787
  return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
22417
22788
  }
@@ -23081,6 +23452,22 @@ function registerLinearTools(server) {
23081
23452
  }
23082
23453
  }
23083
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
+ );
23084
23471
  server.tool(
23085
23472
  "linear_get_issue",
23086
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.",
@@ -23315,30 +23702,31 @@ function registerScheduleTools(server) {
23315
23702
 
23316
23703
  // src/mcp/server.ts
23317
23704
  init_agent_git_actions();
23705
+ init_gh_errors();
23318
23706
  init_git_auth_mode();
23319
23707
 
23320
23708
  // src/board/load-home-board.ts
23321
- var import_node_fs48 = require("fs");
23322
- var import_node_path44 = require("path");
23709
+ var import_node_fs49 = require("fs");
23710
+ var import_node_path45 = require("path");
23323
23711
  init_worktree();
23324
23712
  init_paths();
23325
23713
 
23326
23714
  // src/board/board-pins.ts
23327
- var import_node_crypto11 = require("crypto");
23328
- var import_node_fs47 = require("fs");
23329
- 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");
23330
23718
  init_paths();
23331
23719
  init_home_board();
23332
23720
  var FILE = "home-board-pins.json";
23333
23721
  var VERSION = 1;
23334
23722
  function pinsFile() {
23335
- return (0, import_node_path43.join)(appDataDir(), FILE);
23723
+ return (0, import_node_path44.join)(appDataDir(), FILE);
23336
23724
  }
23337
23725
  function readDisk() {
23338
23726
  const path2 = pinsFile();
23339
- if (!(0, import_node_fs47.existsSync)(path2)) return [];
23727
+ if (!(0, import_node_fs48.existsSync)(path2)) return [];
23340
23728
  try {
23341
- const raw = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
23729
+ const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
23342
23730
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
23343
23731
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
23344
23732
  } catch {
@@ -23346,8 +23734,8 @@ function readDisk() {
23346
23734
  }
23347
23735
  }
23348
23736
  function writeDisk(items) {
23349
- (0, import_node_fs47.mkdirSync)(appDataDir(), { recursive: true });
23350
- (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");
23351
23739
  }
23352
23740
  function listBoardPins() {
23353
23741
  return readDisk();
@@ -23356,7 +23744,7 @@ function addBoardPin(input) {
23356
23744
  const ref = input.ref.trim();
23357
23745
  if (!ref) throw new Error("Board item needs a ref");
23358
23746
  const pin = {
23359
- id: (0, import_node_crypto11.randomUUID)(),
23747
+ id: (0, import_node_crypto12.randomUUID)(),
23360
23748
  kind: input.kind,
23361
23749
  ref,
23362
23750
  repoPath: input.repoPath.trim(),
@@ -23399,7 +23787,7 @@ function replaceBoardPins(items) {
23399
23787
  }
23400
23788
  function clearBoardPins() {
23401
23789
  try {
23402
- (0, import_node_fs47.unlinkSync)(pinsFile());
23790
+ (0, import_node_fs48.unlinkSync)(pinsFile());
23403
23791
  } catch {
23404
23792
  }
23405
23793
  }
@@ -23416,7 +23804,7 @@ function homeBoardWorkspaceKey(workspaces) {
23416
23804
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
23417
23805
  }
23418
23806
  function cacheFile() {
23419
- return (0, import_node_path44.join)(appDataDir(), "home-board-cache.json");
23807
+ return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
23420
23808
  }
23421
23809
  function emptyInputs() {
23422
23810
  return {
@@ -23442,9 +23830,9 @@ function shouldCacheHomeBoardInputs(inputs) {
23442
23830
  }
23443
23831
  function readDiskCache() {
23444
23832
  const path2 = cacheFile();
23445
- if (!(0, import_node_fs48.existsSync)(path2)) return null;
23833
+ if (!(0, import_node_fs49.existsSync)(path2)) return null;
23446
23834
  try {
23447
- const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
23835
+ const raw = JSON.parse((0, import_node_fs49.readFileSync)(path2, "utf8"));
23448
23836
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
23449
23837
  return null;
23450
23838
  }
@@ -23458,14 +23846,14 @@ function readDiskCache() {
23458
23846
  }
23459
23847
  function writeDiskCache(entry) {
23460
23848
  try {
23461
- (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
23462
- (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");
23463
23851
  } catch {
23464
23852
  }
23465
23853
  }
23466
23854
  function deleteDiskCache() {
23467
23855
  try {
23468
- (0, import_node_fs48.unlinkSync)(cacheFile());
23856
+ (0, import_node_fs49.unlinkSync)(cacheFile());
23469
23857
  } catch {
23470
23858
  }
23471
23859
  }
@@ -23762,13 +24150,13 @@ async function startMcpServer() {
23762
24150
  async () => {
23763
24151
  const threads = orch.getThreads(true);
23764
24152
  const lines = threads.map((t) => {
23765
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path45.basename)(t.repoPath) || t.repoPath;
23766
- 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;
23767
24155
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
23768
24156
  const preview = lastMessagePreview(t.messages, 80);
23769
24157
  const previewBit = preview ? ` ${preview}` : "";
23770
24158
  const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
23771
- const progress = live?.summary ? ` ${live.summary}` : "";
24159
+ const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
23772
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}`;
23773
24161
  });
23774
24162
  return {
@@ -23830,7 +24218,9 @@ async function startMcpServer() {
23830
24218
  if (!t) {
23831
24219
  return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
23832
24220
  }
23833
- 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;
23834
24224
  const spend = orch.getThreadUsage(t.id);
23835
24225
  const summary = {
23836
24226
  id: t.id,
@@ -23850,8 +24240,8 @@ async function startMcpServer() {
23850
24240
  devPort: t.devPort,
23851
24241
  prUrl: t.prUrl,
23852
24242
  lastError: t.lastError ?? null,
23853
- stillRunning: t.status === "running" || t.status === "queued",
23854
- 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),
23855
24245
  lastActivityAt: live?.updatedAt ?? null,
23856
24246
  usage: spend.usage,
23857
24247
  lastTurnUsage: spend.lastTurnUsage
@@ -24132,7 +24522,7 @@ async function startMcpServer() {
24132
24522
  const ident = issue?.identifier ?? ref.trim();
24133
24523
  const attachments = issue ? [
24134
24524
  {
24135
- id: (0, import_node_crypto12.randomUUID)(),
24525
+ id: (0, import_node_crypto13.randomUUID)(),
24136
24526
  name: issue.identifier,
24137
24527
  kind: "issue",
24138
24528
  content: [
@@ -24208,7 +24598,7 @@ async function startMcpServer() {
24208
24598
  );
24209
24599
  server.tool(
24210
24600
  "wait_for_turn",
24211
- "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).",
24212
24602
  {
24213
24603
  ref: import_zod5.z.string(),
24214
24604
  timeoutMs: import_zod5.z.number().optional()
@@ -24400,7 +24790,7 @@ async function startMcpServer() {
24400
24790
  );
24401
24791
  server.tool(
24402
24792
  "ask_git",
24403
- "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.",
24404
24794
  {
24405
24795
  ref: import_zod5.z.string().describe("Worktree thread id/ref"),
24406
24796
  action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
@@ -24425,8 +24815,26 @@ async function startMcpServer() {
24425
24815
  ]
24426
24816
  };
24427
24817
  } catch (err) {
24428
- const message = err instanceof Error ? err.message : String(err);
24429
- 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
+ };
24430
24838
  }
24431
24839
  }
24432
24840
  );
@@ -24821,11 +25229,15 @@ async function startMcpServer() {
24821
25229
  );
24822
25230
  server.tool(
24823
25231
  "list_issues",
24824
- "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.",
24825
- { repoPath: import_zod5.z.string() },
24826
- 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 }) => {
24827
25239
  const root = await resolveRepoRoot(repoPath);
24828
- const result = await listIssues(root);
25240
+ const result = await listIssues(root, { query, assignee });
24829
25241
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
24830
25242
  }
24831
25243
  );
@@ -25172,16 +25584,16 @@ init_oauth();
25172
25584
  init_injected_mcp();
25173
25585
 
25174
25586
  // src/agents/user-mcp-config.ts
25175
- var import_node_fs49 = require("fs");
25176
- var import_node_os12 = require("os");
25177
- 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");
25178
25590
  init_paths();
25179
25591
  init_injected_mcp();
25180
25592
  function userCursorMcpConfigPath() {
25181
- 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");
25182
25594
  }
25183
25595
  function userClaudeMcpConfigPath() {
25184
- 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");
25185
25597
  }
25186
25598
  function asObject(value) {
25187
25599
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -25208,16 +25620,16 @@ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
25208
25620
  }
25209
25621
  function writeMergedMcpServersJson(configPath, sideboard) {
25210
25622
  let existing = {};
25211
- if ((0, import_node_fs49.existsSync)(configPath)) {
25623
+ if ((0, import_node_fs50.existsSync)(configPath)) {
25212
25624
  try {
25213
- existing = JSON.parse((0, import_node_fs49.readFileSync)(configPath, "utf8"));
25625
+ existing = JSON.parse((0, import_node_fs50.readFileSync)(configPath, "utf8"));
25214
25626
  } catch {
25215
25627
  existing = {};
25216
25628
  }
25217
25629
  }
25218
25630
  const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
25219
- (0, import_node_fs49.mkdirSync)((0, import_node_path46.dirname)(configPath), { recursive: true });
25220
- (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)}
25221
25633
  `);
25222
25634
  }
25223
25635
  function launchFromResolved(server) {
@@ -25235,7 +25647,7 @@ async function registerPackagedUserMcpClients() {
25235
25647
  const cursor = userCursorMcpConfigPath();
25236
25648
  writeMergedMcpServersJson(cursor, launch);
25237
25649
  const claude = userClaudeMcpConfigPath();
25238
- if ((0, import_node_fs49.existsSync)(claude)) {
25650
+ if ((0, import_node_fs50.existsSync)(claude)) {
25239
25651
  writeMergedMcpServersJson(claude, launch);
25240
25652
  return { cursor, claude };
25241
25653
  }
@@ -25246,7 +25658,7 @@ async function registerPackagedUserMcpClients() {
25246
25658
  init_workspaces();
25247
25659
 
25248
25660
  // src/slack/oauth.ts
25249
- var import_node_crypto13 = require("crypto");
25661
+ var import_node_crypto14 = require("crypto");
25250
25662
  init_app_settings();
25251
25663
  init_workspaces();
25252
25664
 
@@ -25470,7 +25882,7 @@ async function startSlackOAuth(opts) {
25470
25882
  throw new SlackOAuthCancelledError();
25471
25883
  }
25472
25884
  const { clientId } = slackOAuthCredentials();
25473
- const state = (0, import_node_crypto13.randomBytes)(16).toString("hex");
25885
+ const state = (0, import_node_crypto14.randomBytes)(16).toString("hex");
25474
25886
  const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
25475
25887
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
25476
25888
  const pollIntervalMs = opts?.pollIntervalMs ?? 400;
@@ -25752,7 +26164,7 @@ init_workspaces();
25752
26164
  init_reply_target();
25753
26165
 
25754
26166
  // src/slack/relay-protocol.ts
25755
- var import_node_crypto14 = require("crypto");
26167
+ var import_node_crypto15 = require("crypto");
25756
26168
  var SLACK_RELAY_PING_INTERVAL_MS = 2e4;
25757
26169
  var SLACK_RELAY_PONG_TIMEOUT_MS = 15e3;
25758
26170
  function slackRelaySessionKey(teamId, userId, deviceId) {
@@ -25762,7 +26174,7 @@ function slackRelayUserKey(teamId, userId) {
25762
26174
  return `${teamId.trim()}:${userId.trim()}`;
25763
26175
  }
25764
26176
  function newSlackRelayEventId() {
25765
- return (0, import_node_crypto14.randomBytes)(12).toString("hex");
26177
+ return (0, import_node_crypto15.randomBytes)(12).toString("hex");
25766
26178
  }
25767
26179
  function parseSlackRelayClientMessage(raw) {
25768
26180
  try {
@@ -26865,9 +27277,9 @@ var import_node_http3 = require("http");
26865
27277
  var import_ws3 = require("ws");
26866
27278
 
26867
27279
  // src/slack/relay-static.ts
26868
- var import_node_fs50 = require("fs");
27280
+ var import_node_fs51 = require("fs");
26869
27281
  var import_promises = require("fs/promises");
26870
- var import_node_path47 = __toESM(require("path"), 1);
27282
+ var import_node_path48 = __toESM(require("path"), 1);
26871
27283
  var TYPES = {
26872
27284
  ".css": "text/css; charset=utf-8",
26873
27285
  ".html": "text/html; charset=utf-8",
@@ -26898,9 +27310,9 @@ function resolveStaticPath(root, requestUrl) {
26898
27310
  return null;
26899
27311
  }
26900
27312
  if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
26901
- const rootResolved = import_node_path47.default.resolve(root);
26902
- const candidate = import_node_path47.default.resolve(rootResolved, `.${pathname}`);
26903
- 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)) {
26904
27316
  return null;
26905
27317
  }
26906
27318
  return candidate;
@@ -26914,7 +27326,7 @@ async function fileSize(file) {
26914
27326
  }
26915
27327
  }
26916
27328
  function sendFile(req, res, file, size) {
26917
- const ext = import_node_path47.default.extname(file).toLowerCase();
27329
+ const ext = import_node_path48.default.extname(file).toLowerCase();
26918
27330
  res.writeHead(200, {
26919
27331
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
26920
27332
  "Content-Length": size,
@@ -26924,7 +27336,7 @@ function sendFile(req, res, file, size) {
26924
27336
  res.end();
26925
27337
  return true;
26926
27338
  }
26927
- (0, import_node_fs50.createReadStream)(file).pipe(res);
27339
+ (0, import_node_fs51.createReadStream)(file).pipe(res);
26928
27340
  return true;
26929
27341
  }
26930
27342
  async function tryServeStatic(req, res, root) {
@@ -26933,7 +27345,7 @@ async function tryServeStatic(req, res, root) {
26933
27345
  if (!candidate) return false;
26934
27346
  const direct = await fileSize(candidate);
26935
27347
  if (direct != null) return sendFile(req, res, candidate, direct);
26936
- const asIndex = import_node_path47.default.join(candidate, "index.html");
27348
+ const asIndex = import_node_path48.default.join(candidate, "index.html");
26937
27349
  const indexSize = await fileSize(asIndex);
26938
27350
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
26939
27351
  return false;
@@ -27193,7 +27605,10 @@ init_outbound_watch();
27193
27605
  DEFAULT_ABLETIME_HOST,
27194
27606
  DEFAULT_WORKTREE_SORT,
27195
27607
  FAMOUS_SOCCER_TEAMS,
27608
+ FOLLOW_UP_BEHAVIORS,
27196
27609
  GITHUB_GIT_AUTH_MODES,
27610
+ GITHUB_PR_BODY_MAX_CHARS,
27611
+ GITHUB_PR_BODY_SAFE_CHARS,
27197
27612
  GLOBAL_WORKSPACE_ID,
27198
27613
  HARNESS_ENV_KEYS,
27199
27614
  HOME_BOARD_CACHE_TTL_MS,
@@ -27205,6 +27620,7 @@ init_outbound_watch();
27205
27620
  LINEAR_OAUTH_PORT,
27206
27621
  LINEAR_OAUTH_REDIRECT,
27207
27622
  LINEAR_OAUTH_SCOPES,
27623
+ LIVE_TURN_SPAWN_GRACE_MS,
27208
27624
  LONG_RUNNING_SKILL_COMMAND,
27209
27625
  LinearOAuthCancelledError,
27210
27626
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
@@ -27294,6 +27710,7 @@ init_outbound_watch();
27294
27710
  buildCodeRefAttachment,
27295
27711
  buildDiffCommentAttachment,
27296
27712
  buildForkTranscriptAttachment,
27713
+ buildLinearIssueFilter,
27297
27714
  buildPastedTextAttachment,
27298
27715
  buildPathRefAttachment,
27299
27716
  buildReviewRequestAttachment,
@@ -27311,6 +27728,7 @@ init_outbound_watch();
27311
27728
  checkoutPrStackLayer,
27312
27729
  childEnvWithAppSettings,
27313
27730
  claimDesktopHost,
27731
+ clampGithubPrBody,
27314
27732
  classifyWorktreeColumn,
27315
27733
  claudeAdapter,
27316
27734
  claudeChromeEnabled,
@@ -27415,6 +27833,7 @@ init_outbound_watch();
27415
27833
  fireSchedule,
27416
27834
  flattenTurnInput,
27417
27835
  flipLinearRelationType,
27836
+ followUpBehavior,
27418
27837
  forkChatTab,
27419
27838
  forkMessageSlice,
27420
27839
  forkThreadWorktree,
@@ -27493,6 +27912,7 @@ init_outbound_watch();
27493
27912
  ghRepoSelectArgs,
27494
27913
  git,
27495
27914
  githubAgentGitEnv,
27915
+ githubHttpsInsteadOfEntries,
27496
27916
  globalAgentCwd,
27497
27917
  groupHomeBoardWorktrees,
27498
27918
  handleSlackInbound,
@@ -27529,6 +27949,7 @@ init_outbound_watch();
27529
27949
  isDefaultishSourceRef,
27530
27950
  isDesktopHostAlive,
27531
27951
  isDirty,
27952
+ isGhPrBodyTooLongError,
27532
27953
  isGhRateLimitError,
27533
27954
  isGlobalRepoPath,
27534
27955
  isGlobalThread,
@@ -27536,6 +27957,7 @@ init_outbound_watch();
27536
27957
  isImageFilePath,
27537
27958
  isInPrStack,
27538
27959
  isInboundForThisDesktop,
27960
+ isInternalAgentStatusText,
27539
27961
  isIssueSourceConnected,
27540
27962
  isLinearConnected,
27541
27963
  isLinearOAuthCancelled,
@@ -27562,6 +27984,7 @@ init_outbound_watch();
27562
27984
  isThreadRecordFile,
27563
27985
  isWorkspaceScratchPath,
27564
27986
  issueAttachmentForAbleTimeTask,
27987
+ issueMatchesAssignee,
27565
27988
  issueSourceLabel,
27566
27989
  lastRequestOccupancy,
27567
27990
  latestPendingPlanQuestions,
@@ -27589,6 +28012,7 @@ init_outbound_watch();
27589
28012
  listLinearAssignedIssues,
27590
28013
  listLinearIssues,
27591
28014
  listLinearIssuesDirect,
28015
+ listLinearIssuesFiltered,
27592
28016
  listLinearTeams,
27593
28017
  listModelsForAgent,
27594
28018
  listOpencodeModels,