@sideboard-ai/core 0.1.149 → 0.1.151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/{abletime-QEVAE67D.js → abletime-223A3LY6.js} +2 -2
  2. package/dist/{abletime-DI55AJX3.js → abletime-CLC5UJC2.js} +2 -2
  3. package/dist/agents/cursor-runner.cjs +40 -35
  4. package/dist/agents/cursor-runner.js +2 -2
  5. package/dist/{agents-V4MTDWXS.js → agents-JAOMXDXN.js} +10 -9
  6. package/dist/{agents-HSVQ2Z6Y.js → agents-U2JCFXW4.js} +10 -9
  7. package/dist/{app-settings-WJDCJFSY.js → app-settings-3CHCNIMD.js} +5 -1
  8. package/dist/{app-settings-ZCN632OJ.js → app-settings-J3JBCUOT.js} +5 -1
  9. package/dist/{chunk-N5PM7HGQ.js → chunk-2SDMENAL.js} +1 -1
  10. package/dist/{chunk-JTPDWTWJ.js → chunk-3JBMACYX.js} +137 -114
  11. package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
  12. package/dist/{chunk-JDYKQ6OI.js → chunk-6H4TJ5TA.js} +136 -75
  13. package/dist/{chunk-EGDRPA4B.js → chunk-77MP647F.js} +6 -6
  14. package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
  15. package/dist/{chunk-R4JP32P5.js → chunk-ADCEGG4A.js} +4 -4
  16. package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
  17. package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
  18. package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
  19. package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
  20. package/dist/{chunk-TZWO7J4W.js → chunk-GCWAAPJ5.js} +115 -54
  21. package/dist/{chunk-YP3CSOZ6.js → chunk-GE7M3QTE.js} +142 -114
  22. package/dist/{chunk-LAFA56WD.js → chunk-HEII7W3Q.js} +1 -1
  23. package/dist/{chunk-3QRGCKYL.js → chunk-HWZWBJWL.js} +2 -2
  24. package/dist/{chunk-FKOIHGKV.js → chunk-JRH62XC4.js} +5 -1
  25. package/dist/{chunk-Q5DHVMXB.js → chunk-LZAOX76N.js} +18 -7
  26. package/dist/{chunk-B3SJXYIJ.js → chunk-NVXVEGGM.js} +1 -1
  27. package/dist/{chunk-ZVYLEF72.js → chunk-OXOU2FRS.js} +6 -6
  28. package/dist/chunk-QQKDGPUI.js +63 -0
  29. package/dist/{chunk-QTUESPAW.js → chunk-RFMQY56R.js} +1 -1
  30. package/dist/chunk-SYFVUF2C.js +65 -0
  31. package/dist/{chunk-Q62SDB53.js → chunk-TSCWSAQL.js} +2 -2
  32. package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
  33. package/dist/{chunk-PTI5H3RK.js → chunk-UIS7BVCX.js} +24 -13
  34. package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
  35. package/dist/{chunk-N3VNOFXQ.js → chunk-Y2FNDKHF.js} +4 -4
  36. package/dist/{connected-teams-IJUJQ7R6.js → connected-teams-I2WZZZFA.js} +2 -2
  37. package/dist/{connected-teams-4A2AXDNN.js → connected-teams-XO766HB4.js} +2 -2
  38. package/dist/{coordinator-prompt-ZWBMAIWA.js → coordinator-prompt-LWYUZAXR.js} +6 -5
  39. package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-ZK5MII7W.js} +6 -5
  40. package/dist/{global-workspace-OJRXWXEA.js → global-workspace-IB2CCEJF.js} +7 -6
  41. package/dist/{global-workspace-2SIPM4PW.js → global-workspace-T7RL3XEC.js} +7 -6
  42. package/dist/index.cjs +1010 -577
  43. package/dist/index.d.cts +96 -11
  44. package/dist/index.d.ts +96 -11
  45. package/dist/index.js +272 -93
  46. package/dist/mcp/run-stdio.cjs +981 -581
  47. package/dist/mcp/run-stdio.js +196 -43
  48. package/dist/{orchestrator-Z2O5OVJA.js → orchestrator-DPTRBKEH.js} +16 -13
  49. package/dist/{orchestrator-6TXQWBXN.js → orchestrator-Y5MWUU7C.js} +14 -11
  50. package/dist/{plan-file-6O7G4VPQ.js → plan-file-LSSSQGTQ.js} +2 -2
  51. package/dist/{plan-file-PHVKUAEE.js → plan-file-OZEBFSGQ.js} +2 -2
  52. package/dist/{run-XQKGHQZ2.js → run-CAGKZLHA.js} +1 -1
  53. package/dist/{run-USF6FRKV.js → run-EBWL2Q4N.js} +1 -1
  54. package/dist/{workspaces-UUJNOO4T.js → workspaces-VICQYI2N.js} +8 -7
  55. package/dist/{workspaces-3NUUZTQK.js → workspaces-ZXCUVCZC.js} +8 -7
  56. package/dist/{worktree-RZRJNHYL.js → worktree-DPIREDFR.js} +5 -4
  57. package/dist/{worktree-UCWWTVLS.js → worktree-HTUM35NT.js} +5 -4
  58. package/dist/worktree-exclude-N5X5I422.js +13 -0
  59. package/dist/worktree-exclude-X54WSOXM.js +11 -0
  60. package/package.json +1 -1
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,14 +2881,16 @@ 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
- var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
2886
+ var ATTACHMENTS_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
2875
2887
  var init_workspace_scratch = __esm({
2876
2888
  "src/paths/workspace-scratch.ts"() {
2877
2889
  "use strict";
2878
2890
  ATTACHMENTS_DIR = ".context/attachments";
2891
+ DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
2879
2892
  LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
2893
+ LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
2880
2894
  ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
2881
2895
  *
2882
2896
  !.gitignore
@@ -3991,6 +4005,18 @@ var init_worktree_labels = __esm({
3991
4005
  function isGhRateLimitError(text5) {
3992
4006
  return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
3993
4007
  }
4008
+ function isGhPrBodyTooLongError(text5) {
4009
+ 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(
4010
+ text5
4011
+ );
4012
+ }
4013
+ function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
4014
+ const t = body.replace(/\s+$/u, "");
4015
+ if (t.length <= max) return t;
4016
+ const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
4017
+ const keep = Math.max(0, max - note.length);
4018
+ return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
4019
+ }
3994
4020
  function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
3995
4021
  const ms = resetEpochSec * 1e3 - nowMs;
3996
4022
  if (ms <= 0) return "soon";
@@ -4001,18 +4027,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
4001
4027
  const hours = Math.ceil(mins / 60);
4002
4028
  return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
4003
4029
  }
4030
+ function omitGhBodyArg(text5) {
4031
+ return text5.replace(
4032
+ /--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
4033
+ "--body <omitted>"
4034
+ );
4035
+ }
4036
+ function capGhErrorText(text5, max = 400) {
4037
+ const t = text5.trim();
4038
+ if (t.length <= max) return t;
4039
+ return `${t.slice(0, max - 1).trimEnd()}\u2026`;
4040
+ }
4004
4041
  function extractGhErrorDetail(text5) {
4005
- const trimmed = text5.trim();
4042
+ const trimmed = omitGhBodyArg(text5.trim());
4006
4043
  if (!trimmed) return "";
4044
+ if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
4045
+ return "GraphQL: body is too long (GitHub PR body / request size limit).";
4046
+ }
4007
4047
  const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
4008
- if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}`;
4048
+ if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
4009
4049
  const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
4010
- if (http?.[1]) return `HTTP: ${http[1].trim()}`;
4050
+ if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
4011
4051
  const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
4012
4052
  if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
4013
- return lines.slice(1).join(" ").trim() || lines[0];
4053
+ return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
4014
4054
  }
4015
- return trimmed;
4055
+ return capGhErrorText(trimmed);
4016
4056
  }
4017
4057
  function formatGhLandError(raw, opts) {
4018
4058
  const trimmed = raw.trim();
@@ -4030,6 +4070,10 @@ function formatGhLandError(raw, opts) {
4030
4070
  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
4071
  return `Could not create the pull request.${hint}`;
4032
4072
  }
4073
+ if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
4074
+ const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
4075
+ 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.`;
4076
+ }
4033
4077
  if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
4034
4078
  const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
4035
4079
  const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
@@ -4058,130 +4102,51 @@ function formatIpcInvokeError(err) {
4058
4102
  if (isPrNotMergeableError(msg)) return formatMergePrError(msg);
4059
4103
  return formatGhLandError(msg);
4060
4104
  }
4105
+ var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
4061
4106
  var init_gh_errors = __esm({
4062
4107
  "src/git/gh-errors.ts"() {
4063
4108
  "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");
4109
+ GITHUB_PR_BODY_MAX_CHARS = 65536;
4110
+ GITHUB_PR_BODY_SAFE_CHARS = 6e4;
4146
4111
  }
4147
4112
  });
4148
4113
 
4149
4114
  // src/agents/path.ts
4150
4115
  function prependPathDir(env, dir) {
4151
- if (!dir || !(0, import_node_fs14.existsSync)(dir)) return;
4116
+ if (!dir || !(0, import_node_fs13.existsSync)(dir)) return;
4152
4117
  const current = env.PATH ?? "";
4153
- const parts = current.split(import_node_path15.delimiter).filter(Boolean);
4118
+ const parts = current.split(import_node_path14.delimiter).filter(Boolean);
4154
4119
  if (parts.includes(dir)) {
4155
4120
  env.PATH = current;
4156
4121
  return;
4157
4122
  }
4158
- env.PATH = [dir, ...parts].join(import_node_path15.delimiter);
4123
+ env.PATH = [dir, ...parts].join(import_node_path14.delimiter);
4159
4124
  }
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");
4125
+ function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os4.homedir)()) {
4126
+ return (0, import_node_path14.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
4162
4127
  }
4163
4128
  function isConductorBundledCli(filePath) {
4164
4129
  const p = (filePath ?? "").replace(/\\/g, "/");
4165
4130
  return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
4166
4131
  }
4167
4132
  function ensureAgentPath(env = process.env) {
4168
- const home = env.HOME || env.USERPROFILE || (0, import_node_os5.homedir)();
4133
+ const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
4169
4134
  const current = env.PATH ?? "";
4170
- const parts = current.split(import_node_path15.delimiter).filter(Boolean);
4135
+ const parts = current.split(import_node_path14.delimiter).filter(Boolean);
4171
4136
  const seen = new Set(parts);
4172
4137
  const extras = [
4173
- ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path15.join)(home, rel)),
4138
+ ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path14.join)(home, rel)),
4174
4139
  "/opt/homebrew/bin",
4175
4140
  "/usr/local/bin",
4176
4141
  // Keep after Homebrew/npm so a user-installed CLI still wins.
4177
4142
  conductorBundledBinDir(home)
4178
4143
  ];
4179
4144
  for (const dir of extras.reverse()) {
4180
- if (!dir || seen.has(dir) || !(0, import_node_fs14.existsSync)(dir)) continue;
4145
+ if (!dir || seen.has(dir) || !(0, import_node_fs13.existsSync)(dir)) continue;
4181
4146
  parts.unshift(dir);
4182
4147
  seen.add(dir);
4183
4148
  }
4184
- const next = parts.join(import_node_path15.delimiter);
4149
+ const next = parts.join(import_node_path14.delimiter);
4185
4150
  env.PATH = next;
4186
4151
  return next;
4187
4152
  }
@@ -4195,7 +4160,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
4195
4160
  stdio: ["ignore", "pipe", "ignore"]
4196
4161
  }).trim().split(/\r?\n/).find(Boolean);
4197
4162
  if (prefix) {
4198
- const binDir = process.platform === "win32" ? prefix : (0, import_node_path15.join)(prefix, "bin");
4163
+ const binDir = process.platform === "win32" ? prefix : (0, import_node_path14.join)(prefix, "bin");
4199
4164
  prependPathDir(env, binDir);
4200
4165
  }
4201
4166
  } catch {
@@ -4223,14 +4188,14 @@ function withExportedPath(command, pathValue) {
4223
4188
  if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
4224
4189
  return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
4225
4190
  }
4226
- var import_node_fs14, import_node_child_process3, import_node_os5, import_node_path15, EXTRA_BIN_DIRS;
4191
+ var import_node_fs13, import_node_child_process3, import_node_os4, import_node_path14, EXTRA_BIN_DIRS;
4227
4192
  var init_path = __esm({
4228
4193
  "src/agents/path.ts"() {
4229
4194
  "use strict";
4230
- import_node_fs14 = require("fs");
4195
+ import_node_fs13 = require("fs");
4231
4196
  import_node_child_process3 = require("child_process");
4232
- import_node_os5 = require("os");
4233
- import_node_path15 = require("path");
4197
+ import_node_os4 = require("os");
4198
+ import_node_path14 = require("path");
4234
4199
  EXTRA_BIN_DIRS = [
4235
4200
  ".local/bin",
4236
4201
  ".cargo/bin",
@@ -4247,6 +4212,88 @@ var init_path = __esm({
4247
4212
  }
4248
4213
  });
4249
4214
 
4215
+ // src/git/github-agent-auth.ts
4216
+ function githubAgentAuthDir() {
4217
+ const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
4218
+ if (override) return override;
4219
+ return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".sideboard-git-auth");
4220
+ }
4221
+ function githubCredentialStorePath() {
4222
+ return (0, import_node_path15.join)(githubAgentAuthDir(), "git-credentials");
4223
+ }
4224
+ function githubGhConfigDir() {
4225
+ return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
4226
+ }
4227
+ function writePrivateFile2(file, body) {
4228
+ (0, import_node_fs14.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
4229
+ try {
4230
+ (0, import_node_fs14.chmodSync)((0, import_node_path15.dirname)(file), 448);
4231
+ } catch {
4232
+ }
4233
+ (0, import_node_fs14.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
4234
+ try {
4235
+ (0, import_node_fs14.chmodSync)(file, 384);
4236
+ } catch {
4237
+ }
4238
+ }
4239
+ function gitCredentialStoreContents(token) {
4240
+ return `https://x-access-token:${encodeURIComponent(token)}@github.com
4241
+ `;
4242
+ }
4243
+ function ghHostsYml(token, user = "x-access-token") {
4244
+ const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
4245
+ return [
4246
+ "github.com:",
4247
+ " git_protocol: https",
4248
+ ` user: ${u}`,
4249
+ ` oauth_token: ${token}`,
4250
+ " users:",
4251
+ ` ${u}:`,
4252
+ ` oauth_token: ${token}`,
4253
+ ""
4254
+ ].join("\n");
4255
+ }
4256
+ function materializeGithubAgentAuth(token, user) {
4257
+ const trimmed = token.trim();
4258
+ if (!trimmed) return;
4259
+ const root = githubAgentAuthDir();
4260
+ (0, import_node_fs14.mkdirSync)(root, { recursive: true, mode: 448 });
4261
+ try {
4262
+ (0, import_node_fs14.chmodSync)(root, 448);
4263
+ } catch {
4264
+ }
4265
+ writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
4266
+ const ghDir = githubGhConfigDir();
4267
+ (0, import_node_fs14.mkdirSync)(ghDir, { recursive: true, mode: 448 });
4268
+ writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
4269
+ writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
4270
+ }
4271
+ function githubAgentAuthReady() {
4272
+ return (0, import_node_fs14.existsSync)(githubCredentialStorePath()) && (0, import_node_fs14.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
4273
+ }
4274
+ function githubCredentialHelperGitConfig() {
4275
+ const file = githubCredentialStorePath();
4276
+ return [
4277
+ { key: "credential.helper", value: "" },
4278
+ { key: "credential.helper", value: `store --file=${file}` }
4279
+ ];
4280
+ }
4281
+ function githubGhConfigEnv() {
4282
+ return {
4283
+ GH_CONFIG_DIR: githubGhConfigDir(),
4284
+ GH_PROMPT_DISABLED: "1"
4285
+ };
4286
+ }
4287
+ var import_node_fs14, import_node_os5, import_node_path15;
4288
+ var init_github_agent_auth = __esm({
4289
+ "src/git/github-agent-auth.ts"() {
4290
+ "use strict";
4291
+ import_node_fs14 = require("fs");
4292
+ import_node_os5 = require("os");
4293
+ import_node_path15 = require("path");
4294
+ }
4295
+ });
4296
+
4250
4297
  // src/git/stale-lock.ts
4251
4298
  function isIndexLockError(text5) {
4252
4299
  return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
@@ -4373,7 +4420,10 @@ async function gh(args, cwd, opts) {
4373
4420
  timeoutMs: opts?.timeoutMs,
4374
4421
  env: {
4375
4422
  GH_PROMPT_DISABLED: "1",
4376
- GIT_TERMINAL_PROMPT: "0"
4423
+ GIT_TERMINAL_PROMPT: "0",
4424
+ // Isolated hosts.yml uses git_protocol: https so `gh pr create` does not
4425
+ // shell out over SSH when Settings → Git is SSH (ask_git in Electron).
4426
+ ...githubAgentAuthReady() ? githubGhConfigEnv() : {}
4377
4427
  }
4378
4428
  });
4379
4429
  }
@@ -4389,11 +4439,98 @@ var init_run = __esm({
4389
4439
  "use strict";
4390
4440
  import_execa2 = require("execa");
4391
4441
  init_path();
4442
+ init_github_agent_auth();
4392
4443
  init_stale_lock();
4393
4444
  }
4394
4445
  });
4395
4446
 
4447
+ // src/git/worktree-exclude.ts
4448
+ var worktree_exclude_exports = {};
4449
+ __export(worktree_exclude_exports, {
4450
+ WORKTREE_CONTEXT_EXCLUDE: () => WORKTREE_CONTEXT_EXCLUDE,
4451
+ WORKTREE_SIDEBOARD_EXCLUDE: () => WORKTREE_SIDEBOARD_EXCLUDE,
4452
+ ensureWorktreeSideboardIgnored: () => ensureWorktreeSideboardIgnored
4453
+ });
4454
+ function excludeHasLine(body, ...needles) {
4455
+ return body.split(/\r?\n/).some((line) => needles.includes(line.trim()));
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
+ const missing = [];
4475
+ if (!excludeHasLine(body, ".sideboard/", ".sideboard", "/.sideboard/")) {
4476
+ missing.push(WORKTREE_SIDEBOARD_EXCLUDE);
4477
+ }
4478
+ if (!excludeHasLine(body, ".context/", ".context", "/.context/")) {
4479
+ missing.push(WORKTREE_CONTEXT_EXCLUDE);
4480
+ }
4481
+ if (missing.length > 0) {
4482
+ const prefix = body && !body.endsWith("\n") ? `${body}
4483
+ ` : body;
4484
+ const header = body.includes(EXCLUDE_COMMENT) ? "" : `${EXCLUDE_COMMENT}
4485
+ `;
4486
+ (0, import_node_fs16.writeFileSync)(excludePath, `${prefix}${header}${missing.join("\n")}
4487
+ `, "utf8");
4488
+ }
4489
+ const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
4490
+ reject: false,
4491
+ timeoutMs: 5e3
4492
+ });
4493
+ if (listed.exitCode !== 0 || !listed.stdout) return;
4494
+ const files = listed.stdout.split("\0").filter(Boolean);
4495
+ if (files.length === 0) return;
4496
+ await git(["update-index", "--skip-worktree", "--", ...files], worktreePath, {
4497
+ reject: false,
4498
+ timeoutMs: 8e3
4499
+ });
4500
+ }
4501
+ var import_node_fs16, import_node_path17, WORKTREE_SIDEBOARD_EXCLUDE, WORKTREE_CONTEXT_EXCLUDE, EXCLUDE_COMMENT;
4502
+ var init_worktree_exclude = __esm({
4503
+ "src/git/worktree-exclude.ts"() {
4504
+ "use strict";
4505
+ import_node_fs16 = require("fs");
4506
+ import_node_path17 = require("path");
4507
+ init_run();
4508
+ WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
4509
+ WORKTREE_CONTEXT_EXCLUDE = ".context/";
4510
+ EXCLUDE_COMMENT = "# Sideboard worktree scratch \u2014 do not commit";
4511
+ }
4512
+ });
4513
+
4396
4514
  // src/git/git-auth-mode.ts
4515
+ function githubHttpsInsteadOfEntries(remoteUrl) {
4516
+ const entries = [...HTTPS_REWRITE];
4517
+ const url = remoteUrl?.trim() ?? "";
4518
+ const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
4519
+ if (scpAlias?.[1]) {
4520
+ entries.push({
4521
+ key: "url.https://github.com/.insteadOf",
4522
+ value: `${scpAlias[1]}:`
4523
+ });
4524
+ }
4525
+ const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
4526
+ if (sshAlias?.[1]) {
4527
+ entries.push({
4528
+ key: "url.https://github.com/.insteadOf",
4529
+ value: `ssh://git@${sshAlias[1]}/`
4530
+ });
4531
+ }
4532
+ return entries;
4533
+ }
4397
4534
  function nonInteractiveGitProcessEnv() {
4398
4535
  return {
4399
4536
  GIT_TERMINAL_PROMPT: "0",
@@ -4416,16 +4553,19 @@ function appendIndexedGitConfig(existing, entries) {
4416
4553
  out.GIT_CONFIG_COUNT = String(count + entries.length);
4417
4554
  return out;
4418
4555
  }
4419
- function githubAgentGitEnv(existing) {
4556
+ function githubAgentGitEnv(existing, opts) {
4420
4557
  const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
4421
- return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
4558
+ return appendIndexedGitConfig(existing, [
4559
+ ...githubHttpsInsteadOfEntries(opts?.remoteUrl),
4560
+ ...helpers
4561
+ ]);
4422
4562
  }
4423
4563
  function applyGithubGitAuthEnv(existing, opts) {
4424
4564
  const out = { ...nonInteractiveGitProcessEnv() };
4425
4565
  const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
4426
4566
  if (token) materializeGithubAgentAuth(token);
4427
4567
  Object.assign(out, githubGhConfigEnv());
4428
- if (opts.mode === "ssh") return out;
4568
+ if (opts.mode === "ssh" && !token) return out;
4429
4569
  Object.assign(out, githubAgentGitEnv(existing));
4430
4570
  return out;
4431
4571
  }
@@ -4484,7 +4624,7 @@ async function warmGithubAgentAuth(opts) {
4484
4624
  }
4485
4625
  function normalizeWritableRoot(raw) {
4486
4626
  const trimmed = raw.trim().replace(/\/+$/, "");
4487
- return trimmed && (0, import_node_path17.isAbsolute)(trimmed) ? trimmed : null;
4627
+ return trimmed && (0, import_node_path18.isAbsolute)(trimmed) ? trimmed : null;
4488
4628
  }
4489
4629
  async function resolveCodexGitWritableRoots(cwd) {
4490
4630
  const roots = /* @__PURE__ */ new Set();
@@ -4541,8 +4681,9 @@ function formatGitAuthModeDirective(mode) {
4541
4681
  case "ssh":
4542
4682
  return [
4543
4683
  "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.",
4684
+ "- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
4685
+ "- 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.",
4686
+ "- 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
4687
  "- `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
4688
  "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
4548
4689
  ].join("\n");
@@ -4561,11 +4702,11 @@ function formatGitAuthModeDirective(mode) {
4561
4702
  ].join("\n");
4562
4703
  }
4563
4704
  }
4564
- var import_node_path17, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4705
+ var import_node_path18, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
4565
4706
  var init_git_auth_mode = __esm({
4566
4707
  "src/git/git-auth-mode.ts"() {
4567
4708
  "use strict";
4568
- import_node_path17 = require("path");
4709
+ import_node_path18 = require("path");
4569
4710
  init_app_settings();
4570
4711
  init_github_agent_auth();
4571
4712
  init_run();
@@ -5027,7 +5168,7 @@ async function resolveRepoRoot(cwd) {
5027
5168
  }
5028
5169
  function canonicalizeRepoPath(path2) {
5029
5170
  try {
5030
- return (0, import_node_fs16.realpathSync)(path2);
5171
+ return (0, import_node_fs17.realpathSync)(path2);
5031
5172
  } catch {
5032
5173
  return path2.replace(/\/+$/, "");
5033
5174
  }
@@ -5766,6 +5907,16 @@ function originFetchBranch(sourceRef) {
5766
5907
  if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
5767
5908
  return ref;
5768
5909
  }
5910
+ async function originRemoteUrl(cwd) {
5911
+ const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
5912
+ return result.exitCode === 0 ? result.stdout.trim() : "";
5913
+ }
5914
+ function githubHttpsRetryEnv(remoteUrl) {
5915
+ return {
5916
+ GIT_TERMINAL_PROMPT: "0",
5917
+ ...githubAgentGitEnv(void 0, { remoteUrl })
5918
+ };
5919
+ }
5769
5920
  async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5770
5921
  const first = await git(args, repoPath, { reject: false, timeoutMs });
5771
5922
  if (first.exitCode === 0) return true;
@@ -5775,15 +5926,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
5775
5926
  } catch {
5776
5927
  return false;
5777
5928
  }
5778
- if (mode === "ssh") return false;
5779
5929
  const token = await resolveGithubAgentToken(mode, repoPath);
5780
5930
  if (!token) return false;
5931
+ const remoteUrl = await originRemoteUrl(repoPath);
5781
5932
  const tryHttps = async (header) => git(args, repoPath, {
5782
5933
  reject: false,
5783
5934
  timeoutMs,
5784
- env: { GIT_TERMINAL_PROMPT: "0" },
5935
+ env: githubHttpsRetryEnv(remoteUrl),
5785
5936
  config: {
5786
- "url.https://github.com/.insteadOf": "git@github.com:",
5787
5937
  "http.extraHeader": header
5788
5938
  }
5789
5939
  });
@@ -5865,8 +6015,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
5865
6015
  }
5866
6016
  async function createThreadWorktree(opts) {
5867
6017
  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)) {
6018
+ const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
6019
+ if ((0, import_node_fs17.existsSync)(worktreePath)) {
5870
6020
  throw new Error(`Worktree already exists at ${worktreePath}`);
5871
6021
  }
5872
6022
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5901,13 +6051,14 @@ ${add.stdout}`;
5901
6051
  });
5902
6052
  branchName = added;
5903
6053
  await ensureGhPreferOrigin(worktreePath);
6054
+ await ensureWorktreeSideboardIgnored(worktreePath);
5904
6055
  return { branchName, worktreePath };
5905
6056
  }
5906
6057
  async function createExistingBranchWorktree(opts) {
5907
6058
  const branchName = opts.branchName.trim();
5908
6059
  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)) {
6060
+ const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
6061
+ if ((0, import_node_fs17.existsSync)(worktreePath)) {
5911
6062
  throw new Error(`Worktree already exists at ${worktreePath}`);
5912
6063
  }
5913
6064
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5945,6 +6096,7 @@ async function createExistingBranchWorktree(opts) {
5945
6096
  await git(["checkout", "-B", branchName], worktreePath, { reject: false });
5946
6097
  }
5947
6098
  await ensureGhPreferOrigin(worktreePath);
6099
+ await ensureWorktreeSideboardIgnored(worktreePath);
5948
6100
  return { branchName, worktreePath };
5949
6101
  }
5950
6102
  async function removeWorktree(repoPath, worktreePath, opts) {
@@ -6033,7 +6185,9 @@ async function currentBranch(worktreePath) {
6033
6185
  async function commitAll(worktreePath, message) {
6034
6186
  const dirty = await isDirty(worktreePath);
6035
6187
  if (!dirty) return false;
6188
+ await ensureWorktreeSideboardIgnored(worktreePath);
6036
6189
  await git(["add", "-A"], worktreePath);
6190
+ await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
6037
6191
  await git(["commit", "-m", message], worktreePath);
6038
6192
  return true;
6039
6193
  }
@@ -6047,14 +6201,14 @@ async function pushBranch(worktreePath, branchName) {
6047
6201
  const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
6048
6202
  if (!slug || !token) {
6049
6203
  throw new Error(
6050
- sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
6204
+ sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
6051
6205
  );
6052
6206
  }
6207
+ const remoteUrl = await originRemoteUrl(worktreePath);
6053
6208
  const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
6054
6209
  reject: false,
6055
- env: { GIT_TERMINAL_PROMPT: "0" },
6210
+ env: githubHttpsRetryEnv(remoteUrl),
6056
6211
  config: {
6057
- "url.https://github.com/.insteadOf": "git@github.com:",
6058
6212
  "http.extraHeader": header
6059
6213
  }
6060
6214
  });
@@ -6184,6 +6338,32 @@ async function createOrUpdatePr(worktreePath, opts) {
6184
6338
  const repoArgs = ghRepoSelectArgs(slug);
6185
6339
  const headRef = ghHeadRef(slug, opts.head);
6186
6340
  const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
6341
+ const bodyText = clampGithubPrBody(opts.body ?? opts.title);
6342
+ const bodyFile = (0, import_node_path19.join)(
6343
+ (0, import_node_os6.tmpdir)(),
6344
+ `sideboard-pr-body-${process.pid}-${(0, import_node_crypto6.randomBytes)(6).toString("hex")}.md`
6345
+ );
6346
+ (0, import_node_fs17.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
6347
+ `, "utf8");
6348
+ const bodyArgs = ["--body-file", bodyFile];
6349
+ try {
6350
+ return await createOrUpdatePrWithBodyFile(worktreePath, {
6351
+ ...opts,
6352
+ slug,
6353
+ repoArgs,
6354
+ headRef,
6355
+ branchOnly,
6356
+ bodyArgs
6357
+ });
6358
+ } finally {
6359
+ try {
6360
+ (0, import_node_fs17.unlinkSync)(bodyFile);
6361
+ } catch {
6362
+ }
6363
+ }
6364
+ }
6365
+ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
6366
+ const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
6187
6367
  const existing = await gh(
6188
6368
  [...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
6189
6369
  worktreePath,
@@ -6199,8 +6379,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6199
6379
  branchOnly,
6200
6380
  "--title",
6201
6381
  opts.title,
6202
- "--body",
6203
- opts.body ?? opts.title
6382
+ ...bodyArgs
6204
6383
  ],
6205
6384
  worktreePath,
6206
6385
  { reject: false }
@@ -6215,8 +6394,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6215
6394
  "--web",
6216
6395
  "--title",
6217
6396
  opts.title,
6218
- "--body",
6219
- opts.body ?? opts.title,
6397
+ ...bodyArgs,
6220
6398
  "--base",
6221
6399
  opts.base,
6222
6400
  "--head",
@@ -6237,8 +6415,7 @@ async function createOrUpdatePr(worktreePath, opts) {
6237
6415
  "create",
6238
6416
  "--title",
6239
6417
  opts.title,
6240
- "--body",
6241
- opts.body ?? opts.title,
6418
+ ...bodyArgs,
6242
6419
  "--base",
6243
6420
  opts.base,
6244
6421
  "--head",
@@ -6262,10 +6439,10 @@ function sameRepoPath(a, b) {
6262
6439
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
6263
6440
  }
6264
6441
  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 [];
6442
+ const refsDir = (0, import_node_path19.join)(repoPath, ".git", "refs", "heads", "thread");
6443
+ if (!(0, import_node_fs17.existsSync)(refsDir)) return [];
6267
6444
  try {
6268
- return (0, import_node_fs16.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6445
+ return (0, import_node_fs17.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
6269
6446
  } catch {
6270
6447
  return [];
6271
6448
  }
@@ -6273,8 +6450,8 @@ function listLocalThreadBranchSlugs(repoPath) {
6273
6450
  function collectTakenTeamSlugs(repoPath) {
6274
6451
  const taken = /* @__PURE__ */ new Set();
6275
6452
  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 })) {
6453
+ if ((0, import_node_fs17.existsSync)(root)) {
6454
+ for (const entry of (0, import_node_fs17.readdirSync)(root, { withFileTypes: true })) {
6278
6455
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
6279
6456
  taken.add(normalizeTakenSlug(entry.name));
6280
6457
  }
@@ -6295,23 +6472,26 @@ function allocateTeamSlug(repoPath) {
6295
6472
  const taken = collectTakenTeamSlugs(repoPath);
6296
6473
  for (let attempt = 0; attempt < 32; attempt++) {
6297
6474
  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;
6475
+ const path2 = (0, import_node_path19.join)(worktreesRoot(repoPath), team.slug);
6476
+ if (!(0, import_node_fs17.existsSync)(path2)) return team;
6300
6477
  taken.add(team.slug);
6301
6478
  }
6302
6479
  throw new Error("No available soccer team worktree directories left");
6303
6480
  }
6304
- var import_node_fs16, import_node_path18;
6481
+ var import_node_crypto6, import_node_fs17, import_node_os6, import_node_path19;
6305
6482
  var init_worktree = __esm({
6306
6483
  "src/git/worktree.ts"() {
6307
6484
  "use strict";
6308
- import_node_fs16 = require("fs");
6309
- import_node_path18 = require("path");
6485
+ import_node_crypto6 = require("crypto");
6486
+ import_node_fs17 = require("fs");
6487
+ import_node_os6 = require("os");
6488
+ import_node_path19 = require("path");
6310
6489
  init_paths();
6311
6490
  init_thread_store();
6312
6491
  init_teams();
6313
6492
  init_worktree_labels();
6314
6493
  init_gh_errors();
6494
+ init_worktree_exclude();
6315
6495
  init_git_auth_mode();
6316
6496
  init_run();
6317
6497
  init_repo_git_lock();
@@ -6383,7 +6563,7 @@ function coordinatorTurnReminder(opts) {
6383
6563
  function ensureGlobalCoordinatorCwd(opts) {
6384
6564
  const dir = globalAgentCwd();
6385
6565
  try {
6386
- (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
6566
+ (0, import_node_fs18.mkdirSync)(dir, { recursive: true });
6387
6567
  } catch {
6388
6568
  return dir;
6389
6569
  }
@@ -6391,7 +6571,7 @@ function ensureGlobalCoordinatorCwd(opts) {
6391
6571
  let orchId = opts?.orchestratorThreadId?.trim() || "";
6392
6572
  if (!orchId) {
6393
6573
  try {
6394
- const existing = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), "utf8");
6574
+ const existing = (0, import_node_fs18.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
6395
6575
  const m = existing.match(
6396
6576
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
6397
6577
  );
@@ -6434,9 +6614,9 @@ function ensureGlobalCoordinatorCwd(opts) {
6434
6614
  "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
6615
  ].join("\n");
6436
6616
  try {
6437
- (0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(dir, "CLAUDE.md"), `${body}
6617
+ (0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
6438
6618
  `, "utf8");
6439
- (0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), `${body}
6619
+ (0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
6440
6620
  `, "utf8");
6441
6621
  } catch {
6442
6622
  }
@@ -6468,12 +6648,12 @@ function coordinatorSystemPrompt(opts) {
6468
6648
  formatWorkspaceInventory(opts.workspaces)
6469
6649
  ].join("\n");
6470
6650
  }
6471
- var import_node_fs17, import_node_path19, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6651
+ var import_node_fs18, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6472
6652
  var init_coordinator_prompt = __esm({
6473
6653
  "src/orchestrator/coordinator-prompt.ts"() {
6474
6654
  "use strict";
6475
- import_node_fs17 = require("fs");
6476
- import_node_path19 = require("path");
6655
+ import_node_fs18 = require("fs");
6656
+ import_node_path20 = require("path");
6477
6657
  init_worktree();
6478
6658
  init_app_settings();
6479
6659
  init_paths();
@@ -6483,8 +6663,8 @@ var init_coordinator_prompt = __esm({
6483
6663
  "Discover:",
6484
6664
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
6485
6665
  "- 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.",
6666
+ "- 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.",
6667
+ "- 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
6668
  "- 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
6669
  "- 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
6670
  "- 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 +6683,7 @@ var init_coordinator_prompt = __esm({
6503
6683
  "- 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
6684
  "- 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
6685
  "- 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.",
6686
+ "- 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
6687
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
6508
6688
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
6509
6689
  "Setup / run:",
@@ -6512,7 +6692,7 @@ var init_coordinator_prompt = __esm({
6512
6692
  "Inspect / review / PRs:",
6513
6693
  "- get_diff \u2014 compact diff summary",
6514
6694
  '- 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.",
6695
+ "- 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
6696
  '- 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
6697
  '- 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
6698
  "Process guides:",
@@ -6826,13 +7006,13 @@ var init_api = __esm({
6826
7006
 
6827
7007
  // src/slack/reply-target.ts
6828
7008
  function storePath() {
6829
- return (0, import_node_path20.join)(appDataDir(), "slack-reply-to.json");
7009
+ return (0, import_node_path21.join)(appDataDir(), "slack-reply-to.json");
6830
7010
  }
6831
7011
  function readStore() {
6832
7012
  const path2 = storePath();
6833
- if (!(0, import_node_fs18.existsSync)(path2)) return {};
7013
+ if (!(0, import_node_fs19.existsSync)(path2)) return {};
6834
7014
  try {
6835
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
7015
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
6836
7016
  return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
6837
7017
  } catch {
6838
7018
  return {};
@@ -6847,12 +7027,12 @@ function setSlackReplyTarget(target) {
6847
7027
  function getSlackReplyTarget(threadId) {
6848
7028
  return readStore()[threadId] ?? null;
6849
7029
  }
6850
- var import_node_fs18, import_node_path20;
7030
+ var import_node_fs19, import_node_path21;
6851
7031
  var init_reply_target = __esm({
6852
7032
  "src/slack/reply-target.ts"() {
6853
7033
  "use strict";
6854
- import_node_fs18 = require("fs");
6855
- import_node_path20 = require("path");
7034
+ import_node_fs19 = require("fs");
7035
+ import_node_path21 = require("path");
6856
7036
  init_paths();
6857
7037
  init_private_file();
6858
7038
  init_secure_file();
@@ -6861,7 +7041,7 @@ var init_reply_target = __esm({
6861
7041
 
6862
7042
  // src/slack/workspaces.ts
6863
7043
  function storePath2() {
6864
- return (0, import_node_path21.join)(appDataDir(), "slack-workspaces.json");
7044
+ return (0, import_node_path22.join)(appDataDir(), "slack-workspaces.json");
6865
7045
  }
6866
7046
  function readStore2() {
6867
7047
  try {
@@ -6968,11 +7148,11 @@ function requireSlackWorkspace(teamId) {
6968
7148
  }
6969
7149
  return ws;
6970
7150
  }
6971
- var import_node_path21;
7151
+ var import_node_path22;
6972
7152
  var init_workspaces = __esm({
6973
7153
  "src/slack/workspaces.ts"() {
6974
7154
  "use strict";
6975
- import_node_path21 = require("path");
7155
+ import_node_path22 = require("path");
6976
7156
  init_paths();
6977
7157
  init_secure_file();
6978
7158
  init_api();
@@ -6981,7 +7161,7 @@ var init_workspaces = __esm({
6981
7161
 
6982
7162
  // src/slack/outbound-watch.ts
6983
7163
  function storePath3() {
6984
- return (0, import_node_path22.join)(appDataDir(), "slack-outbound-watch.json");
7164
+ return (0, import_node_path23.join)(appDataDir(), "slack-outbound-watch.json");
6985
7165
  }
6986
7166
  function watchId(teamId, channelId, ts) {
6987
7167
  return `${teamId}:${channelId}:${ts}`;
@@ -6994,9 +7174,9 @@ function tsNewer(a, b) {
6994
7174
  }
6995
7175
  function readStore3() {
6996
7176
  const path2 = storePath3();
6997
- if (!(0, import_node_fs19.existsSync)(path2)) return [];
7177
+ if (!(0, import_node_fs20.existsSync)(path2)) return [];
6998
7178
  try {
6999
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
7179
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
7000
7180
  return Array.isArray(parsed?.watches) ? parsed.watches : [];
7001
7181
  } catch {
7002
7182
  return [];
@@ -7318,12 +7498,12 @@ async function pollSlackOutboundWatches(opts) {
7318
7498
  }
7319
7499
  if (changed) writeStore2(watches);
7320
7500
  }
7321
- var import_node_fs19, import_node_path22, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache, continueOnReply;
7501
+ var import_node_fs20, import_node_path23, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache, continueOnReply;
7322
7502
  var init_outbound_watch = __esm({
7323
7503
  "src/slack/outbound-watch.ts"() {
7324
7504
  "use strict";
7325
- import_node_fs19 = require("fs");
7326
- import_node_path22 = require("path");
7505
+ import_node_fs20 = require("fs");
7506
+ import_node_path23 = require("path");
7327
7507
  init_paths();
7328
7508
  init_private_file();
7329
7509
  init_secure_file();
@@ -7607,32 +7787,32 @@ var init_error_detail = __esm({
7607
7787
  function brightsyConfigPath() {
7608
7788
  const override = process.env.BRIGHTSY_CONFIG?.trim();
7609
7789
  if (override) return override;
7610
- return (0, import_node_path23.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
7790
+ return (0, import_node_path24.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
7611
7791
  }
7612
7792
  function loadBrightsyConfig() {
7613
7793
  const path2 = brightsyConfigPath();
7614
- if (!(0, import_node_fs20.existsSync)(path2)) {
7794
+ if (!(0, import_node_fs21.existsSync)(path2)) {
7615
7795
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
7616
7796
  }
7617
- const raw = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
7797
+ const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
7618
7798
  if (!raw.access_token || !raw.account_id) {
7619
7799
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
7620
7800
  }
7621
7801
  return raw;
7622
7802
  }
7623
7803
  function saveBrightsyConfig(cfg) {
7624
- (0, import_node_fs20.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7804
+ (0, import_node_fs21.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
7625
7805
  `, {
7626
7806
  mode: 384
7627
7807
  });
7628
7808
  }
7629
- var import_node_fs20, import_node_os6, import_node_path23;
7809
+ var import_node_fs21, import_node_os7, import_node_path24;
7630
7810
  var init_config = __esm({
7631
7811
  "src/brightsy/config.ts"() {
7632
7812
  "use strict";
7633
- import_node_fs20 = require("fs");
7634
- import_node_os6 = require("os");
7635
- import_node_path23 = require("path");
7813
+ import_node_fs21 = require("fs");
7814
+ import_node_os7 = require("os");
7815
+ import_node_path24 = require("path");
7636
7816
  }
7637
7817
  });
7638
7818
 
@@ -7850,22 +8030,22 @@ __export(connected_teams_exports, {
7850
8030
  listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
7851
8031
  });
7852
8032
  function storePath4() {
7853
- return (0, import_node_path24.join)(appDataDir(), "brightsy-teams.json");
8033
+ return (0, import_node_path25.join)(appDataDir(), "brightsy-teams.json");
7854
8034
  }
7855
8035
  function readStore4() {
7856
8036
  const path2 = storePath4();
7857
- if (!(0, import_node_fs21.existsSync)(path2)) return [];
8037
+ if (!(0, import_node_fs22.existsSync)(path2)) return [];
7858
8038
  try {
7859
- const parsed = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
8039
+ const parsed = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
7860
8040
  return Array.isArray(parsed.teams) ? parsed.teams : [];
7861
8041
  } catch {
7862
8042
  return [];
7863
8043
  }
7864
8044
  }
7865
8045
  function writeStore3(teams) {
7866
- (0, import_node_fs21.mkdirSync)(appDataDir(), { recursive: true });
8046
+ (0, import_node_fs22.mkdirSync)(appDataDir(), { recursive: true });
7867
8047
  const path2 = storePath4();
7868
- (0, import_node_fs21.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
8048
+ (0, import_node_fs22.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
7869
8049
  `, {
7870
8050
  mode: 384
7871
8051
  });
@@ -8021,12 +8201,12 @@ function brightsyMcpServerName(slug) {
8021
8201
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
8022
8202
  return `brightsy_${cleaned || "team"}`;
8023
8203
  }
8024
- var import_node_fs21, import_node_path24;
8204
+ var import_node_fs22, import_node_path25;
8025
8205
  var init_connected_teams = __esm({
8026
8206
  "src/brightsy/connected-teams.ts"() {
8027
8207
  "use strict";
8028
- import_node_fs21 = require("fs");
8029
- import_node_path24 = require("path");
8208
+ import_node_fs22 = require("fs");
8209
+ import_node_path25 = require("path");
8030
8210
  init_paths();
8031
8211
  init_accounts();
8032
8212
  init_config();
@@ -8445,11 +8625,11 @@ async function syncCliForTarget(accountId) {
8445
8625
  }
8446
8626
  applyConnectedTeamToCli(team);
8447
8627
  }
8448
- var import_node_fs22, brightsyAdapter;
8628
+ var import_node_fs23, brightsyAdapter;
8449
8629
  var init_brightsy = __esm({
8450
8630
  "src/agents/brightsy.ts"() {
8451
8631
  "use strict";
8452
- import_node_fs22 = require("fs");
8632
+ import_node_fs23 = require("fs");
8453
8633
  init_run();
8454
8634
  init_connected_teams();
8455
8635
  init_config();
@@ -8464,7 +8644,7 @@ var init_brightsy = __esm({
8464
8644
  async detect() {
8465
8645
  const brightsy = resolveAgentExecutable("brightsy");
8466
8646
  if (brightsy !== "brightsy") {
8467
- if (!(0, import_node_fs22.existsSync)(brightsy)) {
8647
+ if (!(0, import_node_fs23.existsSync)(brightsy)) {
8468
8648
  return {
8469
8649
  agent: "brightsy",
8470
8650
  installed: false,
@@ -8731,6 +8911,13 @@ function isSubagentToolName(name) {
8731
8911
  if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
8732
8912
  return /connectedAgentRequest/i.test(n);
8733
8913
  }
8914
+ function isInternalAgentStatusText(text5) {
8915
+ const t = text5.trim();
8916
+ if (!t) return false;
8917
+ if (/waiting for gate to pass/i.test(t)) return true;
8918
+ if (/^agent is running\b/i.test(t) && t.length < 160) return true;
8919
+ return false;
8920
+ }
8734
8921
  function isPollWrapperToolName(name) {
8735
8922
  const n = (name ?? "").replace(/[_-]/g, "");
8736
8923
  return /^(taskoutput|taskstop|sleep)$/i.test(n);
@@ -8738,7 +8925,10 @@ function isPollWrapperToolName(name) {
8738
8925
  function lastTextPart(parts, type) {
8739
8926
  for (let i = parts.length - 1; i >= 0; i--) {
8740
8927
  const p = parts[i];
8741
- if (p.type === type && p.text.trim()) return p.text.trim();
8928
+ if (p.type !== type) continue;
8929
+ const text5 = p.text.trim();
8930
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
8931
+ return text5;
8742
8932
  }
8743
8933
  return "";
8744
8934
  }
@@ -9154,43 +9344,43 @@ function electronResourcesPath() {
9154
9344
  function packagedCursorRuntimeDir() {
9155
9345
  const resources = electronResourcesPath();
9156
9346
  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;
9347
+ const dir = (0, import_node_path26.join)(resources, "cursor-runtime");
9348
+ if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
9159
9349
  return dir;
9160
9350
  }
9161
9351
  function packagedCursorRunnerPath() {
9162
9352
  const dir = packagedCursorRuntimeDir();
9163
- return dir ? (0, import_node_path25.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
9353
+ return dir ? (0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
9164
9354
  }
9165
9355
  function packagedMcpDir() {
9166
9356
  const resources = electronResourcesPath();
9167
9357
  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;
9358
+ const dir = (0, import_node_path26.join)(resources, "sideboard-mcp");
9359
+ if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
9170
9360
  return dir;
9171
9361
  }
9172
9362
  function packagedMcpStdioPath() {
9173
9363
  const dir = packagedMcpDir();
9174
- return dir ? (0, import_node_path25.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
9364
+ return dir ? (0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
9175
9365
  }
9176
9366
  function packagedBundledNodePath() {
9177
9367
  const resources = electronResourcesPath();
9178
9368
  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;
9369
+ const bin = (0, import_node_path26.join)(resources, "node", "bin", "node");
9370
+ if (!(0, import_node_fs24.existsSync)(bin)) return null;
9181
9371
  return bin;
9182
9372
  }
9183
9373
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
9184
9374
  const dir = packagedCursorRuntimeDir();
9185
9375
  if (!dir) return null;
9186
- return (0, import_node_path25.join)(dir, "node_modules", platformPkg, "bin", binName);
9376
+ return (0, import_node_path26.join)(dir, "node_modules", platformPkg, "bin", binName);
9187
9377
  }
9188
- var import_node_fs23, import_node_path25;
9378
+ var import_node_fs24, import_node_path26;
9189
9379
  var init_packaged_runtime = __esm({
9190
9380
  "src/agents/packaged-runtime.ts"() {
9191
9381
  "use strict";
9192
- import_node_fs23 = require("fs");
9193
- import_node_path25 = require("path");
9382
+ import_node_fs24 = require("fs");
9383
+ import_node_path26 = require("path");
9194
9384
  }
9195
9385
  });
9196
9386
 
@@ -9224,7 +9414,7 @@ function unpackedAsarPath(filePath) {
9224
9414
  if (!isAsarPath(filePath)) return null;
9225
9415
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
9226
9416
  if (unpacked === filePath) return null;
9227
- return (0, import_node_fs24.existsSync)(unpacked) ? unpacked : null;
9417
+ return (0, import_node_fs25.existsSync)(unpacked) ? unpacked : null;
9228
9418
  }
9229
9419
  function nodeReadableScriptPath(scriptPath) {
9230
9420
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -9264,37 +9454,37 @@ function pickPreferredNode(candidates) {
9264
9454
  return best;
9265
9455
  }
9266
9456
  function versionDirNodeBins(root, toBin) {
9267
- if (!(0, import_node_fs24.existsSync)(root)) return [];
9457
+ if (!(0, import_node_fs25.existsSync)(root)) return [];
9268
9458
  try {
9269
- return (0, import_node_fs24.readdirSync)(root).map(toBin);
9459
+ return (0, import_node_fs25.readdirSync)(root).map(toBin);
9270
9460
  } catch {
9271
9461
  return [];
9272
9462
  }
9273
9463
  }
9274
- function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
9464
+ function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
9275
9465
  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"))
9466
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path27.join)(prefix, "opt", `node@${major}`, "bin", "node"))
9277
9467
  );
9278
9468
  return [
9279
9469
  ...kegs,
9280
9470
  "/opt/homebrew/bin/node",
9281
9471
  "/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"),
9472
+ (0, import_node_path27.join)(home, ".local/share/fnm/aliases/default/bin/node"),
9473
+ (0, import_node_path27.join)(home, ".nvm/current/bin/node"),
9474
+ (0, import_node_path27.join)(home, ".volta/bin/node"),
9475
+ (0, import_node_path27.join)(home, ".asdf/shims/node"),
9476
+ (0, import_node_path27.join)(home, ".local/share/mise/shims/node"),
9287
9477
  ...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")
9478
+ (0, import_node_path27.join)(home, ".nvm", "versions", "node"),
9479
+ (name) => (0, import_node_path27.join)(home, ".nvm", "versions", "node", name, "bin", "node")
9290
9480
  ),
9291
9481
  ...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")
9482
+ (0, import_node_path27.join)(home, ".local/share/fnm", "node-versions"),
9483
+ (name) => (0, import_node_path27.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
9294
9484
  ),
9295
9485
  ...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")
9486
+ (0, import_node_path27.join)(home, ".volta", "tools", "image", "node"),
9487
+ (name) => (0, import_node_path27.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
9298
9488
  )
9299
9489
  ];
9300
9490
  }
@@ -9303,10 +9493,10 @@ function uniqueExistingNodeBins(paths) {
9303
9493
  const out = [];
9304
9494
  for (const raw of paths) {
9305
9495
  const p = raw.trim();
9306
- if (!p || !(0, import_node_fs24.existsSync)(p) || isElectronLikeCommand(p)) continue;
9496
+ if (!p || !(0, import_node_fs25.existsSync)(p) || isElectronLikeCommand(p)) continue;
9307
9497
  let key = p;
9308
9498
  try {
9309
- key = (0, import_node_fs24.realpathSync)(p);
9499
+ key = (0, import_node_fs25.realpathSync)(p);
9310
9500
  } catch {
9311
9501
  continue;
9312
9502
  }
@@ -9386,13 +9576,13 @@ async function resolveNodeLaunch(scriptPath) {
9386
9576
  env: { ELECTRON_RUN_AS_NODE: "1" }
9387
9577
  };
9388
9578
  }
9389
- var import_node_fs24, import_node_os7, import_node_path26, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
9579
+ var import_node_fs25, import_node_os8, import_node_path27, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
9390
9580
  var init_node_launch = __esm({
9391
9581
  "src/agents/node-launch.ts"() {
9392
9582
  "use strict";
9393
- import_node_fs24 = require("fs");
9394
- import_node_os7 = require("os");
9395
- import_node_path26 = require("path");
9583
+ import_node_fs25 = require("fs");
9584
+ import_node_os8 = require("os");
9585
+ import_node_path27 = require("path");
9396
9586
  init_nested_electron_env();
9397
9587
  init_run();
9398
9588
  init_packaged_runtime();
@@ -9486,37 +9676,37 @@ function corePackageDir() {
9486
9676
  try {
9487
9677
  const url = import_meta.url;
9488
9678
  if (typeof url === "string" && url.length > 0) {
9489
- return (0, import_node_path27.dirname)((0, import_node_url.fileURLToPath)(url));
9679
+ return (0, import_node_path28.dirname)((0, import_node_url.fileURLToPath)(url));
9490
9680
  }
9491
9681
  } catch {
9492
9682
  }
9493
9683
  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"));
9684
+ const req = (0, import_node_module.createRequire)((0, import_node_path28.join)(process.cwd(), "package.json"));
9685
+ return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
9496
9686
  } catch {
9497
9687
  return process.cwd();
9498
9688
  }
9499
9689
  }
9500
9690
  function findSideboardMcpJsEntry() {
9501
9691
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
9502
- if (override && (0, import_node_fs25.existsSync)(override)) return override;
9692
+ if (override && (0, import_node_fs26.existsSync)(override)) return override;
9503
9693
  const packaged = packagedMcpStdioPath();
9504
9694
  if (packaged) return packaged;
9505
9695
  let dir = corePackageDir();
9506
9696
  for (let i = 0; i < 10; i++) {
9507
9697
  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")
9698
+ (0, import_node_path28.join)(dir, "mcp/run-stdio.js"),
9699
+ (0, import_node_path28.join)(dir, "mcp/run-stdio.cjs"),
9700
+ (0, import_node_path28.join)(dir, "dist/mcp/run-stdio.js"),
9701
+ (0, import_node_path28.join)(dir, "dist/mcp/run-stdio.cjs"),
9702
+ (0, import_node_path28.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
9703
+ (0, import_node_path28.join)(dir, "packages/cli/dist/index.js"),
9704
+ (0, import_node_path28.join)(dir, "cli/dist/index.js")
9515
9705
  ];
9516
9706
  for (const p of candidates) {
9517
- if ((0, import_node_fs25.existsSync)(p) && !isAsarPath(p)) return p;
9707
+ if ((0, import_node_fs26.existsSync)(p) && !isAsarPath(p)) return p;
9518
9708
  }
9519
- const parent = (0, import_node_path27.dirname)(dir);
9709
+ const parent = (0, import_node_path28.dirname)(dir);
9520
9710
  if (parent === dir) break;
9521
9711
  dir = parent;
9522
9712
  }
@@ -9658,22 +9848,22 @@ function writeMcpServersConfig(servers) {
9658
9848
  ...env ? { env } : {}
9659
9849
  };
9660
9850
  }
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));
9851
+ const dir = (0, import_node_fs26.mkdtempSync)((0, import_node_path28.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
9852
+ const cfgPath = (0, import_node_path28.join)(dir, "mcp.json");
9853
+ (0, import_node_fs26.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
9664
9854
  return cfgPath;
9665
9855
  }
9666
9856
  async function writeInjectedMcpConfig(opts) {
9667
9857
  return writeMcpServersConfig(await buildInjectedMcpServers(opts));
9668
9858
  }
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;
9859
+ 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
9860
  var init_injected_mcp = __esm({
9671
9861
  "src/agents/injected-mcp.ts"() {
9672
9862
  "use strict";
9673
- import_node_fs25 = require("fs");
9863
+ import_node_fs26 = require("fs");
9674
9864
  import_node_module = require("module");
9675
- import_node_os8 = require("os");
9676
- import_node_path27 = require("path");
9865
+ import_node_os9 = require("os");
9866
+ import_node_path28 = require("path");
9677
9867
  import_node_url = require("url");
9678
9868
  init_run();
9679
9869
  init_config();
@@ -10016,11 +10206,11 @@ function parseIssuesJson(raw) {
10016
10206
  }
10017
10207
  return [];
10018
10208
  }
10019
- var import_node_fs26, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
10209
+ var import_node_fs27, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
10020
10210
  var init_claude = __esm({
10021
10211
  "src/agents/claude.ts"() {
10022
10212
  "use strict";
10023
- import_node_fs26 = require("fs");
10213
+ import_node_fs27 = require("fs");
10024
10214
  init_run();
10025
10215
  init_app_settings();
10026
10216
  init_claude_mcp();
@@ -10060,7 +10250,7 @@ var init_claude = __esm({
10060
10250
  async detect() {
10061
10251
  const claude = resolveClaudeExecutable();
10062
10252
  if (claude !== "claude") {
10063
- if (!(0, import_node_fs26.existsSync)(claude)) {
10253
+ if (!(0, import_node_fs27.existsSync)(claude)) {
10064
10254
  return {
10065
10255
  agent: "claude",
10066
10256
  installed: false,
@@ -10315,7 +10505,7 @@ async function listCodexModels() {
10315
10505
  if (codex === "codex") {
10316
10506
  const which = await run("which", ["codex"], { reject: false });
10317
10507
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
10318
- } else if (!(0, import_node_fs27.existsSync)(codex)) {
10508
+ } else if (!(0, import_node_fs28.existsSync)(codex)) {
10319
10509
  return FALLBACK_CODEX_MODELS;
10320
10510
  }
10321
10511
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -10350,12 +10540,12 @@ function usageFromCodex(usage) {
10350
10540
  }
10351
10541
  function codexConfigHasNetworkAccess() {
10352
10542
  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")
10543
+ (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "config.toml"),
10544
+ (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".config", "codex", "config.toml")
10355
10545
  ];
10356
10546
  for (const path2 of candidates) {
10357
- if (!(0, import_node_fs27.existsSync)(path2)) continue;
10358
- const text5 = (0, import_node_fs27.readFileSync)(path2, "utf8");
10547
+ if (!(0, import_node_fs28.existsSync)(path2)) continue;
10548
+ const text5 = (0, import_node_fs28.readFileSync)(path2, "utf8");
10359
10549
  if (/network_access\s*=\s*true/.test(text5)) return true;
10360
10550
  }
10361
10551
  return false;
@@ -10387,21 +10577,21 @@ function asRecord2(value) {
10387
10577
  return void 0;
10388
10578
  }
10389
10579
  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;
10580
+ const authPath = (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "auth.json");
10581
+ if (!(0, import_node_fs28.existsSync)(authPath)) return false;
10392
10582
  try {
10393
- return (0, import_node_fs27.statSync)(authPath).size > 2;
10583
+ return (0, import_node_fs28.statSync)(authPath).size > 2;
10394
10584
  } catch {
10395
10585
  return false;
10396
10586
  }
10397
10587
  }
10398
- var import_node_fs27, import_node_os9, import_node_path28, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
10588
+ var import_node_fs28, import_node_os10, import_node_path29, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
10399
10589
  var init_codex = __esm({
10400
10590
  "src/agents/codex.ts"() {
10401
10591
  "use strict";
10402
- import_node_fs27 = require("fs");
10403
- import_node_os9 = require("os");
10404
- import_node_path28 = require("path");
10592
+ import_node_fs28 = require("fs");
10593
+ import_node_os10 = require("os");
10594
+ import_node_path29 = require("path");
10405
10595
  init_run();
10406
10596
  init_app_settings();
10407
10597
  init_global_workspace();
@@ -10426,7 +10616,7 @@ var init_codex = __esm({
10426
10616
  async detect() {
10427
10617
  const codex = resolveAgentExecutable("codex");
10428
10618
  if (codex !== "codex") {
10429
- if (!(0, import_node_fs27.existsSync)(codex)) {
10619
+ if (!(0, import_node_fs28.existsSync)(codex)) {
10430
10620
  return {
10431
10621
  agent: "codex",
10432
10622
  installed: false,
@@ -10913,21 +11103,21 @@ function platformRipgrepPackage() {
10913
11103
  }
10914
11104
  function usableRipgrepPath(candidate) {
10915
11105
  const raw = candidate?.trim();
10916
- if (!raw || !(0, import_node_path29.isAbsolute)(raw)) return null;
11106
+ if (!raw || !(0, import_node_path30.isAbsolute)(raw)) return null;
10917
11107
  const readable = nodeReadableScriptPath(raw);
10918
- if (!(0, import_node_fs28.existsSync)(readable) || isAsarPath(readable)) return null;
11108
+ if (!(0, import_node_fs29.existsSync)(readable) || isAsarPath(readable)) return null;
10919
11109
  return readable;
10920
11110
  }
10921
11111
  function walkForBundledRipgrep(startFile) {
10922
11112
  if (!startFile) return null;
10923
11113
  const pkg = platformRipgrepPackage();
10924
11114
  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;
11115
+ let dir = (0, import_node_path30.dirname)((0, import_node_path30.resolve)(startFile));
11116
+ const root = (0, import_node_path30.parse)(dir).root;
10927
11117
  while (dir !== root) {
10928
- const hit = usableRipgrepPath((0, import_node_path29.join)(dir, "node_modules", pkg, "bin", name));
11118
+ const hit = usableRipgrepPath((0, import_node_path30.join)(dir, "node_modules", pkg, "bin", name));
10929
11119
  if (hit) return hit;
10930
- const next = (0, import_node_path29.dirname)(dir);
11120
+ const next = (0, import_node_path30.dirname)(dir);
10931
11121
  if (next === dir) break;
10932
11122
  dir = next;
10933
11123
  }
@@ -10937,7 +11127,7 @@ function requireResolveBundledRipgrep(fromFile) {
10937
11127
  try {
10938
11128
  const req = (0, import_node_module2.createRequire)(fromFile);
10939
11129
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
10940
- return usableRipgrepPath((0, import_node_path29.join)((0, import_node_path29.dirname)(pkgJson), "bin", rgBinaryName()));
11130
+ return usableRipgrepPath((0, import_node_path30.join)((0, import_node_path30.dirname)(pkgJson), "bin", rgBinaryName()));
10941
11131
  } catch {
10942
11132
  return null;
10943
11133
  }
@@ -10959,13 +11149,13 @@ function cursorRipgrepEnv(opts) {
10959
11149
  const path2 = resolveCursorRipgrepPath(opts);
10960
11150
  return path2 ? { [RIPGREP_ENV]: path2 } : {};
10961
11151
  }
10962
- var import_node_fs28, import_node_module2, import_node_path29, RIPGREP_ENV;
11152
+ var import_node_fs29, import_node_module2, import_node_path30, RIPGREP_ENV;
10963
11153
  var init_cursor_ripgrep = __esm({
10964
11154
  "src/agents/cursor-ripgrep.ts"() {
10965
11155
  "use strict";
10966
- import_node_fs28 = require("fs");
11156
+ import_node_fs29 = require("fs");
10967
11157
  import_node_module2 = require("module");
10968
- import_node_path29 = require("path");
11158
+ import_node_path30 = require("path");
10969
11159
  init_node_launch();
10970
11160
  init_packaged_runtime();
10971
11161
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -11011,11 +11201,11 @@ function entryDir() {
11011
11201
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
11012
11202
  if (cjsDir) return cjsDir;
11013
11203
  try {
11014
- return (0, import_node_path30.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
11204
+ return (0, import_node_path31.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
11015
11205
  } catch {
11016
11206
  try {
11017
11207
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
11018
- return (0, import_node_path30.dirname)(req.resolve("@sideboard-ai/core"));
11208
+ return (0, import_node_path31.dirname)(req.resolve("@sideboard-ai/core"));
11019
11209
  } catch {
11020
11210
  return process.cwd();
11021
11211
  }
@@ -11026,27 +11216,27 @@ function cursorRunnerPath() {
11026
11216
  if (packaged) return packaged;
11027
11217
  const root = entryDir();
11028
11218
  const candidates = [
11029
- (0, import_node_path30.join)(root, "agents", "cursor-runner.js"),
11030
- (0, import_node_path30.join)(root, "agents", "cursor-runner.cjs"),
11219
+ (0, import_node_path31.join)(root, "agents", "cursor-runner.js"),
11220
+ (0, import_node_path31.join)(root, "agents", "cursor-runner.cjs"),
11031
11221
  // 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"),
11222
+ (0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.js"),
11223
+ (0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.cjs"),
11034
11224
  // 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")
11225
+ (0, import_node_path31.join)(root, "cursor-runner.ts"),
11226
+ (0, import_node_path31.join)(root, "src", "agents", "cursor-runner.ts")
11037
11227
  ];
11038
11228
  for (const candidate of candidates) {
11039
- if ((0, import_node_fs29.existsSync)(candidate)) return candidate;
11229
+ if ((0, import_node_fs30.existsSync)(candidate)) return candidate;
11040
11230
  }
11041
11231
  return candidates[0];
11042
11232
  }
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;
11233
+ 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
11234
  var init_cursor = __esm({
11045
11235
  "src/agents/cursor.ts"() {
11046
11236
  "use strict";
11047
- import_node_fs29 = require("fs");
11237
+ import_node_fs30 = require("fs");
11048
11238
  import_node_module3 = require("module");
11049
- import_node_path30 = require("path");
11239
+ import_node_path31 = require("path");
11050
11240
  import_node_url2 = require("url");
11051
11241
  import_sdk = require("@cursor/sdk");
11052
11242
  init_run();
@@ -11197,7 +11387,7 @@ async function listOpencodeModels() {
11197
11387
  if (opencode === "opencode") {
11198
11388
  const which = await run("which", ["opencode"], { reject: false });
11199
11389
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
11200
- } else if (!(0, import_node_fs30.existsSync)(opencode)) {
11390
+ } else if (!(0, import_node_fs31.existsSync)(opencode)) {
11201
11391
  return FALLBACK_OPENCODE_MODELS;
11202
11392
  }
11203
11393
  const listed = await run(opencode, ["models"], { reject: false });
@@ -11227,11 +11417,11 @@ function usageFromOpencode(tokens) {
11227
11417
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
11228
11418
  };
11229
11419
  }
11230
- var import_node_fs30, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
11420
+ var import_node_fs31, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
11231
11421
  var init_opencode = __esm({
11232
11422
  "src/agents/opencode.ts"() {
11233
11423
  "use strict";
11234
- import_node_fs30 = require("fs");
11424
+ import_node_fs31 = require("fs");
11235
11425
  init_run();
11236
11426
  init_app_settings();
11237
11427
  init_global_workspace();
@@ -11258,7 +11448,7 @@ var init_opencode = __esm({
11258
11448
  async detect() {
11259
11449
  const opencode = resolveAgentExecutable("opencode");
11260
11450
  if (opencode !== "opencode") {
11261
- if (!(0, import_node_fs30.existsSync)(opencode)) {
11451
+ if (!(0, import_node_fs31.existsSync)(opencode)) {
11262
11452
  return {
11263
11453
  agent: "opencode",
11264
11454
  installed: false,
@@ -12884,7 +13074,7 @@ function forkMessageSlice(from, throughIndex) {
12884
13074
  function buildForkTranscriptAttachment(baseTitle, messages) {
12885
13075
  const title = baseTitle || "Chat";
12886
13076
  return {
12887
- id: (0, import_node_crypto6.randomUUID)(),
13077
+ id: (0, import_node_crypto7.randomUUID)(),
12888
13078
  name: `Transcript of ${title}.md`,
12889
13079
  kind: "transcript",
12890
13080
  content: formatTranscriptMarkdown(title, messages)
@@ -12941,11 +13131,11 @@ function forkChatTab(input) {
12941
13131
  }
12942
13132
  return tab;
12943
13133
  }
12944
- var import_node_crypto6;
13134
+ var import_node_crypto7;
12945
13135
  var init_chat_tabs = __esm({
12946
13136
  "src/threads/chat-tabs.ts"() {
12947
13137
  "use strict";
12948
- import_node_crypto6 = require("crypto");
13138
+ import_node_crypto7 = require("crypto");
12949
13139
  init_context_compact();
12950
13140
  init_teams();
12951
13141
  init_worktree_labels();
@@ -13115,21 +13305,21 @@ function shouldRefreshReviewRequestTemplate(content) {
13115
13305
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
13116
13306
  }
13117
13307
  function readTextIfPresent(abs) {
13118
- if (!(0, import_node_fs31.existsSync)(abs)) return null;
13308
+ if (!(0, import_node_fs32.existsSync)(abs)) return null;
13119
13309
  try {
13120
- const content = (0, import_node_fs31.readFileSync)(abs, "utf8");
13310
+ const content = (0, import_node_fs32.readFileSync)(abs, "utf8");
13121
13311
  return content.trim() ? content : null;
13122
13312
  } catch {
13123
13313
  return null;
13124
13314
  }
13125
13315
  }
13126
13316
  function readLocalGuidelines(worktreePath) {
13127
- const localAbs = (0, import_node_path31.join)(worktreePath, REVIEW_REQUEST_PATH);
13317
+ const localAbs = (0, import_node_path32.join)(worktreePath, REVIEW_REQUEST_PATH);
13128
13318
  const localContent = readTextIfPresent(localAbs);
13129
13319
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
13130
13320
  return { path: REVIEW_REQUEST_PATH, content: localContent };
13131
13321
  }
13132
- const legacyAbs = (0, import_node_path31.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
13322
+ const legacyAbs = (0, import_node_path32.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
13133
13323
  const legacyContent = readTextIfPresent(legacyAbs);
13134
13324
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
13135
13325
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -13145,20 +13335,20 @@ function skillGuidelines(content, source) {
13145
13335
  };
13146
13336
  }
13147
13337
  function ensureReviewSkillFile(worktreePath) {
13148
- const abs = (0, import_node_path31.join)(worktreePath, REVIEW_SKILL_PATH);
13338
+ const abs = (0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH);
13149
13339
  const existing = readTextIfPresent(abs);
13150
13340
  if (existing) {
13151
13341
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
13152
13342
  }
13153
- const fromRepo = readTextIfPresent((0, import_node_path31.join)(worktreePath, REPO_REVIEW_PATH));
13343
+ const fromRepo = readTextIfPresent((0, import_node_path32.join)(worktreePath, REPO_REVIEW_PATH));
13154
13344
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
13155
13345
  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");
13346
+ (0, import_node_fs32.mkdirSync)((0, import_node_path32.dirname)(abs), { recursive: true });
13347
+ (0, import_node_fs32.writeFileSync)(abs, content, "utf8");
13158
13348
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
13159
13349
  }
13160
13350
  function resolveReviewGuidelines(worktreePath) {
13161
- const skillContent = readTextIfPresent((0, import_node_path31.join)(worktreePath, REVIEW_SKILL_PATH));
13351
+ const skillContent = readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH));
13162
13352
  if (skillContent) return skillGuidelines(skillContent, "skill");
13163
13353
  const local = readLocalGuidelines(worktreePath);
13164
13354
  if (local) {
@@ -13180,7 +13370,7 @@ function buildReviewRequestAttachment(content, opts) {
13180
13370
  const path2 = opts?.path ?? REVIEW_SKILL_PATH;
13181
13371
  const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
13182
13372
  return {
13183
- id: (0, import_node_crypto7.randomUUID)(),
13373
+ id: (0, import_node_crypto8.randomUUID)(),
13184
13374
  name,
13185
13375
  kind: "file",
13186
13376
  path: path2,
@@ -13188,7 +13378,7 @@ function buildReviewRequestAttachment(content, opts) {
13188
13378
  };
13189
13379
  }
13190
13380
  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));
13381
+ 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
13382
  }
13193
13383
  async function requestReview(threadRef, send2) {
13194
13384
  const from = findThreadByRef(threadRef);
@@ -13215,13 +13405,13 @@ async function requestReview(threadRef, send2) {
13215
13405
  const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
13216
13406
  return { tab: started, from };
13217
13407
  }
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;
13408
+ 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
13409
  var init_request_review = __esm({
13220
13410
  "src/review/request-review.ts"() {
13221
13411
  "use strict";
13222
- import_node_crypto7 = require("crypto");
13223
- import_node_fs31 = require("fs");
13224
- import_node_path31 = require("path");
13412
+ import_node_crypto8 = require("crypto");
13413
+ import_node_fs32 = require("fs");
13414
+ import_node_path32 = require("path");
13225
13415
  init_global_workspace();
13226
13416
  init_chat_tabs();
13227
13417
  init_thread_store();
@@ -13246,9 +13436,9 @@ function matchSimpleGlob(pattern, name) {
13246
13436
  return new RegExp(`^${escaped}$`).test(name);
13247
13437
  }
13248
13438
  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("#"));
13439
+ const path2 = (0, import_node_path33.join)(repoPath, ".worktreeinclude");
13440
+ if (!(0, import_node_fs33.existsSync)(path2)) return [];
13441
+ return (0, import_node_fs33.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
13252
13442
  }
13253
13443
  function resolveFilesToCopy(repoPath) {
13254
13444
  const fromInclude = readWorktreeInclude(repoPath);
@@ -13258,10 +13448,10 @@ function resolveFilesToCopy(repoPath) {
13258
13448
  if (settings?.fileIncludeGlobs?.length) {
13259
13449
  const matched = [];
13260
13450
  try {
13261
- for (const entry of (0, import_node_fs32.readdirSync)(repoPath, { withFileTypes: true })) {
13451
+ for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
13262
13452
  if (!entry.isFile()) continue;
13263
13453
  for (const glob of settings.fileIncludeGlobs) {
13264
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path32.basename)(glob), entry.name)) {
13454
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path33.basename)(glob), entry.name)) {
13265
13455
  matched.push(entry.name);
13266
13456
  break;
13267
13457
  }
@@ -13273,7 +13463,7 @@ function resolveFilesToCopy(repoPath) {
13273
13463
  }
13274
13464
  const defaults = [];
13275
13465
  try {
13276
- for (const entry of (0, import_node_fs32.readdirSync)(repoPath, { withFileTypes: true })) {
13466
+ for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
13277
13467
  if (entry.isFile() && entry.name.startsWith(".env")) {
13278
13468
  defaults.push(entry.name);
13279
13469
  }
@@ -13287,11 +13477,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
13287
13477
  const patterns = resolveFilesToCopy(repoPath);
13288
13478
  const copied = [];
13289
13479
  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);
13480
+ const src = (0, import_node_path33.join)(repoPath, rel);
13481
+ if (!(0, import_node_fs33.existsSync)(src)) continue;
13482
+ const dest = (0, import_node_path33.join)(worktreePath, rel);
13483
+ (0, import_node_fs33.mkdirSync)((0, import_node_path33.dirname)(dest), { recursive: true });
13484
+ (0, import_node_fs33.copyFileSync)(src, dest);
13295
13485
  copied.push(rel);
13296
13486
  }
13297
13487
  return copied;
@@ -13326,7 +13516,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
13326
13516
  const env = stripNestedElectronEnv({
13327
13517
  ...baseEnv ?? process.env
13328
13518
  });
13329
- const name = opts.workspaceName ?? (0, import_node_path32.basename)(opts.worktreePath);
13519
+ const name = opts.workspaceName ?? (0, import_node_path33.basename)(opts.worktreePath);
13330
13520
  const ports = opts.ports ?? [];
13331
13521
  const primary = ports[0];
13332
13522
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -13481,6 +13671,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
13481
13671
  };
13482
13672
  }
13483
13673
  async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
13674
+ await ensureWorktreeSideboardIgnored(worktreePath);
13484
13675
  const reviewSkill = ensureReviewSkillFile(worktreePath);
13485
13676
  if (reviewSkill.wrote) {
13486
13677
  onLine?.(
@@ -13587,13 +13778,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
13587
13778
  done: handle.done
13588
13779
  };
13589
13780
  }
13590
- var import_node_fs32, import_node_net, import_node_path32, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
13781
+ var import_node_fs33, import_node_net, import_node_path33, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
13591
13782
  var init_conductor = __esm({
13592
13783
  "src/hook/conductor.ts"() {
13593
13784
  "use strict";
13594
- import_node_fs32 = require("fs");
13785
+ import_node_fs33 = require("fs");
13595
13786
  import_node_net = require("net");
13596
- import_node_path32 = require("path");
13787
+ import_node_path33 = require("path");
13597
13788
  import_execa4 = require("execa");
13598
13789
  import_node_readline3 = require("readline");
13599
13790
  init_settings();
@@ -13602,6 +13793,7 @@ var init_conductor = __esm({
13602
13793
  init_cursor_worktrees();
13603
13794
  init_git_auth_mode();
13604
13795
  init_request_review();
13796
+ init_worktree_exclude();
13605
13797
  init_nested_electron_env();
13606
13798
  PORT_RANGE_SIZE = 10;
13607
13799
  cachedLoginEnv = null;
@@ -13619,9 +13811,9 @@ async function findOrphanWorktrees(repoPaths) {
13619
13811
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
13620
13812
  );
13621
13813
  const homeRoot = sideboardWorkspacesDir();
13622
- if ((0, import_node_fs33.existsSync)(homeRoot)) {
13814
+ if ((0, import_node_fs34.existsSync)(homeRoot)) {
13623
13815
  try {
13624
- for (const entry of (0, import_node_fs33.readdirSync)(homeRoot, { withFileTypes: true })) {
13816
+ for (const entry of (0, import_node_fs34.readdirSync)(homeRoot, { withFileTypes: true })) {
13625
13817
  if (!entry.isDirectory()) continue;
13626
13818
  void entry;
13627
13819
  }
@@ -13631,7 +13823,7 @@ async function findOrphanWorktrees(repoPaths) {
13631
13823
  const orphans = [];
13632
13824
  const seen = /* @__PURE__ */ new Set();
13633
13825
  for (const repoPath of repos) {
13634
- if (!repoPath || !(0, import_node_fs33.existsSync)(repoPath)) continue;
13826
+ if (!repoPath || !(0, import_node_fs34.existsSync)(repoPath)) continue;
13635
13827
  try {
13636
13828
  const wts = await listWorktrees(repoPath);
13637
13829
  for (const wt of wts) {
@@ -13642,7 +13834,7 @@ async function findOrphanWorktrees(repoPaths) {
13642
13834
  seen.add(path2);
13643
13835
  let mtimeMs = 0;
13644
13836
  try {
13645
- mtimeMs = (0, import_node_fs33.statSync)(path2).mtimeMs;
13837
+ mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
13646
13838
  } catch {
13647
13839
  mtimeMs = 0;
13648
13840
  }
@@ -13652,16 +13844,16 @@ async function findOrphanWorktrees(repoPaths) {
13652
13844
  }
13653
13845
  try {
13654
13846
  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 })) {
13847
+ if ((0, import_node_fs34.existsSync)(root)) {
13848
+ for (const entry of (0, import_node_fs34.readdirSync)(root, { withFileTypes: true })) {
13657
13849
  if (!entry.isDirectory()) continue;
13658
- const path2 = (0, import_node_path33.join)(root, entry.name).replace(/\/$/, "");
13850
+ const path2 = (0, import_node_path34.join)(root, entry.name).replace(/\/$/, "");
13659
13851
  if (known.has(path2) || seen.has(path2)) continue;
13660
- if (!(0, import_node_fs33.existsSync)((0, import_node_path33.join)(path2, ".git"))) continue;
13852
+ if (!(0, import_node_fs34.existsSync)((0, import_node_path34.join)(path2, ".git"))) continue;
13661
13853
  seen.add(path2);
13662
13854
  let mtimeMs = 0;
13663
13855
  try {
13664
- mtimeMs = (0, import_node_fs33.statSync)(path2).mtimeMs;
13856
+ mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
13665
13857
  } catch {
13666
13858
  mtimeMs = Date.now();
13667
13859
  }
@@ -13722,12 +13914,12 @@ function worktreeCleanupSettings() {
13722
13914
  autoCleanupOrphans: a.autoCleanupOrphans
13723
13915
  };
13724
13916
  }
13725
- var import_node_fs33, import_node_path33;
13917
+ var import_node_fs34, import_node_path34;
13726
13918
  var init_orphan_cleanup = __esm({
13727
13919
  "src/git/orphan-cleanup.ts"() {
13728
13920
  "use strict";
13729
- import_node_fs33 = require("fs");
13730
- import_node_path33 = require("path");
13921
+ import_node_fs34 = require("fs");
13922
+ import_node_path34 = require("path");
13731
13923
  init_worktree();
13732
13924
  init_thread_store();
13733
13925
  init_paths();
@@ -13834,38 +14026,38 @@ __export(workspaces_exports, {
13834
14026
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
13835
14027
  });
13836
14028
  function workspacesFile() {
13837
- return (0, import_node_path34.join)(appDataDir(), "workspaces.json");
14029
+ return (0, import_node_path35.join)(appDataDir(), "workspaces.json");
13838
14030
  }
13839
14031
  function removedWorkspacesFile() {
13840
- return (0, import_node_path34.join)(appDataDir(), "removed-workspaces.json");
14032
+ return (0, import_node_path35.join)(appDataDir(), "removed-workspaces.json");
13841
14033
  }
13842
14034
  function readAll2() {
13843
14035
  const path2 = workspacesFile();
13844
- if (!(0, import_node_fs34.existsSync)(path2)) return [];
14036
+ if (!(0, import_node_fs35.existsSync)(path2)) return [];
13845
14037
  try {
13846
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
14038
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13847
14039
  return Array.isArray(raw) ? raw : [];
13848
14040
  } catch {
13849
14041
  return [];
13850
14042
  }
13851
14043
  }
13852
14044
  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");
14045
+ (0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
14046
+ (0, import_node_fs35.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
13855
14047
  }
13856
14048
  function readRemoved() {
13857
14049
  const path2 = removedWorkspacesFile();
13858
- if (!(0, import_node_fs34.existsSync)(path2)) return /* @__PURE__ */ new Set();
14050
+ if (!(0, import_node_fs35.existsSync)(path2)) return /* @__PURE__ */ new Set();
13859
14051
  try {
13860
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
14052
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13861
14053
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
13862
14054
  } catch {
13863
14055
  return /* @__PURE__ */ new Set();
13864
14056
  }
13865
14057
  }
13866
14058
  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");
14059
+ (0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
14060
+ (0, import_node_fs35.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
13869
14061
  }
13870
14062
  function rememberRemoved(repoPath) {
13871
14063
  const next = readRemoved();
@@ -13888,7 +14080,7 @@ function listWorkspaces() {
13888
14080
  async function addWorkspace(repoPath) {
13889
14081
  const root = await resolveRepoRoot(repoPath);
13890
14082
  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}`);
14083
+ if (!(0, import_node_fs35.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
13892
14084
  forgetRemoved(root);
13893
14085
  await ensureGhPreferOrigin(root);
13894
14086
  const current = readAll2();
@@ -13896,7 +14088,7 @@ async function addWorkspace(repoPath) {
13896
14088
  if (existing) return existing;
13897
14089
  const next = {
13898
14090
  path: root,
13899
- name: (0, import_node_path34.basename)(root),
14091
+ name: (0, import_node_path35.basename)(root),
13900
14092
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
13901
14093
  };
13902
14094
  writeAll2([...current, next]);
@@ -13918,10 +14110,10 @@ function syncWorkspacesFromThreads(repoPaths) {
13918
14110
  if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
13919
14111
  continue;
13920
14112
  }
13921
- if (!(0, import_node_fs34.existsSync)(path2)) continue;
14113
+ if (!(0, import_node_fs35.existsSync)(path2)) continue;
13922
14114
  const ws = {
13923
14115
  path: path2,
13924
- name: (0, import_node_path34.basename)(path2),
14116
+ name: (0, import_node_path35.basename)(path2),
13925
14117
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
13926
14118
  };
13927
14119
  byPath.set(path2, ws);
@@ -13931,12 +14123,12 @@ function syncWorkspacesFromThreads(repoPaths) {
13931
14123
  if (dirty) writeAll2(next);
13932
14124
  return next.sort((a, b) => a.name.localeCompare(b.name));
13933
14125
  }
13934
- var import_node_fs34, import_node_path34;
14126
+ var import_node_fs35, import_node_path35;
13935
14127
  var init_workspaces2 = __esm({
13936
14128
  "src/store/workspaces.ts"() {
13937
14129
  "use strict";
13938
- import_node_fs34 = require("fs");
13939
- import_node_path34 = require("path");
14130
+ import_node_fs35 = require("fs");
14131
+ import_node_path35 = require("path");
13940
14132
  init_paths();
13941
14133
  init_global_workspace();
13942
14134
  init_worktree();
@@ -13949,12 +14141,12 @@ async function cloneRepoIntoSideboard(opts) {
13949
14141
  if (!url) throw new Error("Clone URL is required");
13950
14142
  let name = opts.name?.trim();
13951
14143
  if (!name) {
13952
- const leaf = (0, import_node_path35.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
14144
+ const leaf = (0, import_node_path36.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
13953
14145
  name = leaf || "repo";
13954
14146
  }
13955
14147
  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)) {
14148
+ const dest = (0, import_node_path36.join)(sideboardReposDir(), name);
14149
+ if ((0, import_node_fs36.existsSync)(dest)) {
13958
14150
  const repoPath2 = await resolveRepoRoot(dest);
13959
14151
  const workspace2 = await ensureWorkspace(repoPath2);
13960
14152
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -13969,12 +14161,12 @@ async function cloneRepoIntoSideboard(opts) {
13969
14161
  const workspace = await ensureWorkspace(repoPath);
13970
14162
  return { repoPath, workspace };
13971
14163
  }
13972
- var import_node_fs35, import_node_path35, import_execa6;
14164
+ var import_node_fs36, import_node_path36, import_execa6;
13973
14165
  var init_clone_repo = __esm({
13974
14166
  "src/git/clone-repo.ts"() {
13975
14167
  "use strict";
13976
- import_node_fs35 = require("fs");
13977
- import_node_path35 = require("path");
14168
+ import_node_fs36 = require("fs");
14169
+ import_node_path36 = require("path");
13978
14170
  import_execa6 = require("execa");
13979
14171
  init_paths();
13980
14172
  init_workspaces2();
@@ -14991,7 +15183,7 @@ function persistCreateAttachments(worktreePath, attachments) {
14991
15183
  }
14992
15184
  async function createThread(input, _onSetupLine) {
14993
15185
  const repoPath = await resolveRepoRoot(input.repoPath);
14994
- if (!(0, import_node_fs36.existsSync)(repoPath)) {
15186
+ if (!(0, import_node_fs37.existsSync)(repoPath)) {
14995
15187
  throw new Error(`Repo not found: ${repoPath}`);
14996
15188
  }
14997
15189
  if (input.reuseExisting !== false) {
@@ -15166,11 +15358,11 @@ async function listLinearIssues(agent, repoPath) {
15166
15358
  }
15167
15359
  return adapter.listLinearIssues(repoPath);
15168
15360
  }
15169
- var import_node_fs36;
15361
+ var import_node_fs37;
15170
15362
  var init_create = __esm({
15171
15363
  "src/threads/create.ts"() {
15172
15364
  "use strict";
15173
- import_node_fs36 = require("fs");
15365
+ import_node_fs37 = require("fs");
15174
15366
  init_detect();
15175
15367
  init_worktree();
15176
15368
  init_home_board();
@@ -15273,20 +15465,20 @@ function writeTurnLive(threadId, progress) {
15273
15465
  const path2 = threadLivePath(threadId);
15274
15466
  const tmp = `${path2}.${process.pid}.tmp`;
15275
15467
  try {
15276
- (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
15277
- (0, import_node_fs37.renameSync)(tmp, path2);
15468
+ (0, import_node_fs38.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
15469
+ (0, import_node_fs38.renameSync)(tmp, path2);
15278
15470
  } catch {
15279
15471
  try {
15280
- (0, import_node_fs37.unlinkSync)(tmp);
15472
+ (0, import_node_fs38.unlinkSync)(tmp);
15281
15473
  } catch {
15282
15474
  }
15283
15475
  }
15284
15476
  }
15285
15477
  function readTurnLive(threadId) {
15286
15478
  const path2 = threadLivePath(threadId);
15287
- if (!(0, import_node_fs37.existsSync)(path2)) return null;
15479
+ if (!(0, import_node_fs38.existsSync)(path2)) return null;
15288
15480
  try {
15289
- const raw = JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8"));
15481
+ const raw = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
15290
15482
  if (!raw || typeof raw.summary !== "string") return null;
15291
15483
  return raw;
15292
15484
  } catch {
@@ -15298,17 +15490,17 @@ function clearTurnLive(threadId) {
15298
15490
  if (buf?.timer) clearTimeout(buf.timer);
15299
15491
  buffers.delete(threadId);
15300
15492
  const path2 = threadLivePath(threadId);
15301
- if (!(0, import_node_fs37.existsSync)(path2)) return;
15493
+ if (!(0, import_node_fs38.existsSync)(path2)) return;
15302
15494
  try {
15303
- (0, import_node_fs37.unlinkSync)(path2);
15495
+ (0, import_node_fs38.unlinkSync)(path2);
15304
15496
  } catch {
15305
15497
  }
15306
15498
  }
15307
- var import_node_fs37, buffers, FLUSH_MS, MAX_PARTS;
15499
+ var import_node_fs38, buffers, FLUSH_MS, MAX_PARTS;
15308
15500
  var init_turn_live = __esm({
15309
15501
  "src/store/turn-live.ts"() {
15310
15502
  "use strict";
15311
- import_node_fs37 = require("fs");
15503
+ import_node_fs38 = require("fs");
15312
15504
  init_message_parts();
15313
15505
  init_paths();
15314
15506
  buffers = /* @__PURE__ */ new Map();
@@ -15482,7 +15674,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
15482
15674
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
15483
15675
  ].join("\n");
15484
15676
  return {
15485
- id: (0, import_node_crypto8.randomUUID)(),
15677
+ id: (0, import_node_crypto9.randomUUID)(),
15486
15678
  name: "Orchestration quota handoff.md",
15487
15679
  kind: "transcript",
15488
15680
  content: body
@@ -15503,11 +15695,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
15503
15695
  sourceType: "orchestration"
15504
15696
  });
15505
15697
  }
15506
- var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
15698
+ var import_node_crypto9, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
15507
15699
  var init_quota_failover = __esm({
15508
15700
  "src/orchestrator/quota-failover.ts"() {
15509
15701
  "use strict";
15510
- import_node_crypto8 = require("crypto");
15702
+ import_node_crypto9 = require("crypto");
15511
15703
  init_session_quota();
15512
15704
  init_app_settings();
15513
15705
  init_global_workspace();
@@ -15524,7 +15716,7 @@ var init_quota_failover = __esm({
15524
15716
  // src/threads/adopt.ts
15525
15717
  function thisModuleFile() {
15526
15718
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
15527
- return cjsFile || process.argv[1] || (0, import_node_path36.join)(process.cwd(), "package.json");
15719
+ return cjsFile || process.argv[1] || (0, import_node_path37.join)(process.cwd(), "package.json");
15528
15720
  }
15529
15721
  function openReadonlySqlite(file) {
15530
15722
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -15542,21 +15734,21 @@ function mapAgentType(raw) {
15542
15734
  return null;
15543
15735
  }
15544
15736
  function resolveConductorCursorAgentId(workspacePath) {
15545
- if (!workspacePath || !(0, import_node_fs38.existsSync)(CURSOR_SDK_STORE)) return null;
15737
+ if (!workspacePath || !(0, import_node_fs39.existsSync)(CURSOR_SDK_STORE)) return null;
15546
15738
  const normalized = workspacePath.replace(/\/$/, "");
15547
15739
  let best = null;
15548
15740
  let hashes;
15549
15741
  try {
15550
- hashes = (0, import_node_fs38.readdirSync)(CURSOR_SDK_STORE);
15742
+ hashes = (0, import_node_fs39.readdirSync)(CURSOR_SDK_STORE);
15551
15743
  } catch {
15552
15744
  return null;
15553
15745
  }
15554
15746
  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;
15747
+ const agentsFile = (0, import_node_path37.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
15748
+ if (!(0, import_node_fs39.existsSync)(agentsFile)) continue;
15557
15749
  let text5;
15558
15750
  try {
15559
- text5 = (0, import_node_fs38.readFileSync)(agentsFile, "utf8");
15751
+ text5 = (0, import_node_fs39.readFileSync)(agentsFile, "utf8");
15560
15752
  } catch {
15561
15753
  continue;
15562
15754
  }
@@ -15580,7 +15772,7 @@ function resolveConductorCursorAgentId(workspacePath) {
15580
15772
  return best?.agentId ?? null;
15581
15773
  }
15582
15774
  async function adoptThread(input) {
15583
- if (!(0, import_node_fs38.existsSync)(input.worktreePath)) {
15775
+ if (!(0, import_node_fs39.existsSync)(input.worktreePath)) {
15584
15776
  throw new Error(`Worktree not found: ${input.worktreePath}`);
15585
15777
  }
15586
15778
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -15601,24 +15793,26 @@ async function adoptThread(input) {
15601
15793
  writeThread(thread);
15602
15794
  const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
15603
15795
  await ensureWorkspace2(repoPath);
15796
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
15797
+ await ensureWorktreeSideboardIgnored2(input.worktreePath);
15604
15798
  return thread;
15605
15799
  }
15606
15800
  function conductorDbPath() {
15607
15801
  return CONDUCTOR_DB;
15608
15802
  }
15609
15803
  function listConductorWorkspaces() {
15610
- if (!(0, import_node_fs38.existsSync)(CONDUCTOR_DB)) {
15804
+ if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
15611
15805
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
15612
15806
  }
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");
15807
+ const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
15808
+ const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
15615
15809
  try {
15616
- (0, import_node_fs38.copyFileSync)(CONDUCTOR_DB, snapshot);
15810
+ (0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
15617
15811
  for (const suffix of ["-wal", "-shm"]) {
15618
15812
  const src = `${CONDUCTOR_DB}${suffix}`;
15619
- if ((0, import_node_fs38.existsSync)(src)) {
15813
+ if ((0, import_node_fs39.existsSync)(src)) {
15620
15814
  try {
15621
- (0, import_node_fs38.copyFileSync)(src, `${snapshot}${suffix}`);
15815
+ (0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
15622
15816
  } catch {
15623
15817
  }
15624
15818
  }
@@ -15694,22 +15888,22 @@ function listConductorWorkspaces() {
15694
15888
  db.close();
15695
15889
  }
15696
15890
  } finally {
15697
- (0, import_node_fs38.rmSync)(tmp, { recursive: true, force: true });
15891
+ (0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
15698
15892
  }
15699
15893
  }
15700
15894
  function importConductorWorkspace(workspaceId) {
15701
- if (!(0, import_node_fs38.existsSync)(CONDUCTOR_DB)) {
15895
+ if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
15702
15896
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
15703
15897
  }
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");
15898
+ const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
15899
+ const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
15706
15900
  try {
15707
- (0, import_node_fs38.copyFileSync)(CONDUCTOR_DB, snapshot);
15901
+ (0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
15708
15902
  for (const suffix of ["-wal", "-shm"]) {
15709
15903
  const src = `${CONDUCTOR_DB}${suffix}`;
15710
- if ((0, import_node_fs38.existsSync)(src)) {
15904
+ if ((0, import_node_fs39.existsSync)(src)) {
15711
15905
  try {
15712
- (0, import_node_fs38.copyFileSync)(src, `${snapshot}${suffix}`);
15906
+ (0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
15713
15907
  } catch {
15714
15908
  }
15715
15909
  }
@@ -15727,7 +15921,7 @@ function importConductorWorkspace(workspaceId) {
15727
15921
  ).get(workspaceId);
15728
15922
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
15729
15923
  const worktreePath = String(row.workspacePath);
15730
- if (!(0, import_node_fs38.existsSync)(worktreePath)) {
15924
+ if (!(0, import_node_fs39.existsSync)(worktreePath)) {
15731
15925
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
15732
15926
  }
15733
15927
  let sessionId = null;
@@ -15790,31 +15984,31 @@ function importConductorWorkspace(workspaceId) {
15790
15984
  db.close();
15791
15985
  }
15792
15986
  } finally {
15793
- (0, import_node_fs38.rmSync)(tmp, { recursive: true, force: true });
15987
+ (0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
15794
15988
  }
15795
15989
  }
15796
15990
  async function importConductorWorkspaceAsync(workspaceId) {
15797
15991
  return importConductorWorkspace(workspaceId);
15798
15992
  }
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;
15993
+ 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
15994
  var init_adopt = __esm({
15801
15995
  "src/threads/adopt.ts"() {
15802
15996
  "use strict";
15803
15997
  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");
15998
+ import_node_fs39 = require("fs");
15999
+ import_node_os11 = require("os");
16000
+ import_node_path37 = require("path");
15807
16001
  import_node_module4 = require("module");
15808
16002
  init_worktree();
15809
16003
  init_thread_store();
15810
- CONDUCTOR_APP_SUPPORT = (0, import_node_path36.join)(
16004
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path37.join)(
15811
16005
  process.env.HOME ?? "",
15812
16006
  "Library",
15813
16007
  "Application Support",
15814
16008
  "com.conductor.app"
15815
16009
  );
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");
16010
+ CONDUCTOR_DB = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
16011
+ CURSOR_SDK_STORE = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
15818
16012
  }
15819
16013
  });
15820
16014
 
@@ -15881,7 +16075,7 @@ async function openStackLayer(input, _onSetupLine) {
15881
16075
  let createdWorktree = false;
15882
16076
  const trees = await listWorktrees(repoPath);
15883
16077
  const checkedOut = trees.find((w) => w.branch === branchName);
15884
- if (checkedOut?.path && (0, import_node_fs39.existsSync)(checkedOut.path)) {
16078
+ if (checkedOut?.path && (0, import_node_fs40.existsSync)(checkedOut.path)) {
15885
16079
  if (input.reuseExistingWorktree !== false) {
15886
16080
  worktreePath = checkedOut.path;
15887
16081
  } else {
@@ -16023,7 +16217,7 @@ async function initStackFromThread(input, onSetupLine) {
16023
16217
  async function createPrStack(input, onSetupLine) {
16024
16218
  await requireAgent(input.agent);
16025
16219
  const repoPath = await resolveRepoRoot(input.repoPath);
16026
- if (!(0, import_node_fs39.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
16220
+ if (!(0, import_node_fs40.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
16027
16221
  if (!input.branches.length) throw new Error("At least one branch name required");
16028
16222
  const status = await detectGhStack(repoPath);
16029
16223
  if (!status.available) throw new Error(status.reason);
@@ -16090,7 +16284,7 @@ async function createPrStack(input, onSetupLine) {
16090
16284
  }
16091
16285
  }
16092
16286
  const claimed = new Set(threads.map((t) => t.worktreePath));
16093
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs39.existsSync)(bootstrap.worktreePath)) {
16287
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs40.existsSync)(bootstrap.worktreePath)) {
16094
16288
  try {
16095
16289
  await removeWorktree(repoPath, bootstrap.worktreePath, {
16096
16290
  deleteBranch: bootstrap.branchName
@@ -16110,11 +16304,11 @@ function stackAgentDefaultsFrom(input) {
16110
16304
  planMode: input.planMode
16111
16305
  };
16112
16306
  }
16113
- var import_node_fs39;
16307
+ var import_node_fs40;
16114
16308
  var init_stack_layers = __esm({
16115
16309
  "src/threads/stack-layers.ts"() {
16116
16310
  "use strict";
16117
- import_node_fs39 = require("fs");
16311
+ import_node_fs40 = require("fs");
16118
16312
  init_detect();
16119
16313
  init_run();
16120
16314
  init_stack();
@@ -16127,7 +16321,7 @@ var init_stack_layers = __esm({
16127
16321
 
16128
16322
  // src/diff/diff.ts
16129
16323
  async function inspectGitWorktree(worktreePath) {
16130
- if (!worktreePath || !(0, import_node_fs40.existsSync)(worktreePath)) return "missing_worktree";
16324
+ if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) return "missing_worktree";
16131
16325
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
16132
16326
  reject: false
16133
16327
  });
@@ -16135,7 +16329,7 @@ async function inspectGitWorktree(worktreePath) {
16135
16329
  return "ok";
16136
16330
  }
16137
16331
  async function initializeGitRepository(worktreePath) {
16138
- if (!worktreePath || !(0, import_node_fs40.existsSync)(worktreePath)) {
16332
+ if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) {
16139
16333
  throw new Error("Worktree not found");
16140
16334
  }
16141
16335
  const status = await inspectGitWorktree(worktreePath);
@@ -16269,11 +16463,11 @@ new file mode 100644
16269
16463
  };
16270
16464
  }
16271
16465
  async function untrackedPatch(worktreePath, path2, maxHunk) {
16272
- const abs = (0, import_node_path37.join)(worktreePath, path2);
16466
+ const abs = (0, import_node_path38.join)(worktreePath, path2);
16273
16467
  try {
16274
- const st = (0, import_node_fs40.statSync)(abs);
16468
+ const st = (0, import_node_fs41.statSync)(abs);
16275
16469
  if (st.isFile() && st.size > maxHunk) {
16276
- const buf = (0, import_node_fs40.readFileSync)(abs).subarray(0, maxHunk);
16470
+ const buf = (0, import_node_fs41.readFileSync)(abs).subarray(0, maxHunk);
16277
16471
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
16278
16472
  }
16279
16473
  } catch {
@@ -16762,8 +16956,8 @@ function isImageRelativePath(relativePath) {
16762
16956
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16763
16957
  assertSafeRelativePath(relativePath);
16764
16958
  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);
16959
+ const abs = (0, import_node_path38.join)(worktreePath, relativePath);
16960
+ const st = (0, import_node_fs41.statSync)(abs);
16767
16961
  if (!st.isFile()) {
16768
16962
  throw new Error(`Not a file: ${relativePath}`);
16769
16963
  }
@@ -16772,7 +16966,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16772
16966
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
16773
16967
  );
16774
16968
  }
16775
- const buf = (0, import_node_fs40.readFileSync)(abs);
16969
+ const buf = (0, import_node_fs41.readFileSync)(abs);
16776
16970
  return {
16777
16971
  path: relativePath,
16778
16972
  contentBase64: buf.toString("base64"),
@@ -16782,12 +16976,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
16782
16976
  function readWorktreeFile(worktreePath, relativePath, opts) {
16783
16977
  assertSafeRelativePath(relativePath);
16784
16978
  const maxBytes = opts?.maxBytes ?? 2e5;
16785
- const abs = (0, import_node_path37.join)(worktreePath, relativePath);
16786
- const st = (0, import_node_fs40.statSync)(abs);
16979
+ const abs = (0, import_node_path38.join)(worktreePath, relativePath);
16980
+ const st = (0, import_node_fs41.statSync)(abs);
16787
16981
  if (!st.isFile()) {
16788
16982
  throw new Error(`Not a file: ${relativePath}`);
16789
16983
  }
16790
- const buf = (0, import_node_fs40.readFileSync)(abs);
16984
+ const buf = (0, import_node_fs41.readFileSync)(abs);
16791
16985
  if (isImageRelativePath(relativePath)) {
16792
16986
  const maxImageBytes = Math.max(maxBytes, 15e6);
16793
16987
  const truncated2 = buf.length > maxImageBytes;
@@ -16830,9 +17024,9 @@ function assertSafeRelativePath(relativePath) {
16830
17024
  }
16831
17025
  function writeWorktreeFile(worktreePath, relativePath, content) {
16832
17026
  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");
17027
+ const abs = (0, import_node_path38.join)(worktreePath, relativePath);
17028
+ (0, import_node_fs41.mkdirSync)((0, import_node_path38.dirname)(abs), { recursive: true });
17029
+ (0, import_node_fs41.writeFileSync)(abs, content, "utf8");
16836
17030
  return { path: relativePath };
16837
17031
  }
16838
17032
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -16849,12 +17043,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
16849
17043
  truncated: full.files.length > maxFiles
16850
17044
  };
16851
17045
  }
16852
- var import_node_fs40, import_node_path37, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
17046
+ var import_node_fs41, import_node_path38, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
16853
17047
  var init_diff = __esm({
16854
17048
  "src/diff/diff.ts"() {
16855
17049
  "use strict";
16856
- import_node_fs40 = require("fs");
16857
- import_node_path37 = require("path");
17050
+ import_node_fs41 = require("fs");
17051
+ import_node_path38 = require("path");
16858
17052
  init_run();
16859
17053
  init_worktree();
16860
17054
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -17022,7 +17216,7 @@ node <detached-job.js> wait <id> --until-done
17022
17216
  node <detached-job.js> status <id>
17023
17217
  \`\`\`
17024
17218
 
17025
- \`<id>\` is kebab-case (\`mac-release\`, \`core-test\`, \`fly-deploy\`). State is \`.sideboard/detached-jobs/<id>/\` (local scratch).
17219
+ \`<id>\` is kebab-case (\`mac-release\`, \`core-test\`, \`fly-deploy\`). State is \`.context/.sideboard/detached-jobs/<id>/\` (local scratch).
17026
17220
 
17027
17221
  Wait JSON:
17028
17222
 
@@ -17112,7 +17306,7 @@ function parseFrontmatter(content) {
17112
17306
  }
17113
17307
  function readSkill(skillMd, source) {
17114
17308
  try {
17115
- const content = (0, import_node_fs41.readFileSync)(skillMd, "utf8");
17309
+ const content = (0, import_node_fs42.readFileSync)(skillMd, "utf8");
17116
17310
  const { name: fmName, description } = parseFrontmatter(content);
17117
17311
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
17118
17312
  const name = fmName || dirName;
@@ -17131,19 +17325,19 @@ function readSkill(skillMd, source) {
17131
17325
  }
17132
17326
  }
17133
17327
  function scanSkillsDir(dir, source, out) {
17134
- if (!(0, import_node_fs41.existsSync)(dir)) return;
17328
+ if (!(0, import_node_fs42.existsSync)(dir)) return;
17135
17329
  let entries;
17136
17330
  try {
17137
- entries = (0, import_node_fs41.readdirSync)(dir);
17331
+ entries = (0, import_node_fs42.readdirSync)(dir);
17138
17332
  } catch {
17139
17333
  return;
17140
17334
  }
17141
17335
  for (const entry of entries) {
17142
17336
  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;
17337
+ const skillMd = (0, import_node_path39.join)(dir, entry, "SKILL.md");
17338
+ if (!(0, import_node_fs42.existsSync)(skillMd)) continue;
17145
17339
  try {
17146
- if (!(0, import_node_fs41.statSync)(skillMd).isFile()) continue;
17340
+ if (!(0, import_node_fs42.statSync)(skillMd).isFile()) continue;
17147
17341
  } catch {
17148
17342
  continue;
17149
17343
  }
@@ -17152,24 +17346,24 @@ function scanSkillsDir(dir, source, out) {
17152
17346
  }
17153
17347
  }
17154
17348
  function scanClaudePluginSkills(pluginsRoot, out) {
17155
- if (!(0, import_node_fs41.existsSync)(pluginsRoot)) return;
17349
+ if (!(0, import_node_fs42.existsSync)(pluginsRoot)) return;
17156
17350
  const walk = (dir, depth, lookingForSkillsDir) => {
17157
17351
  if (depth > 7) return;
17158
17352
  let entries;
17159
17353
  try {
17160
- entries = (0, import_node_fs41.readdirSync)(dir);
17354
+ entries = (0, import_node_fs42.readdirSync)(dir);
17161
17355
  } catch {
17162
17356
  return;
17163
17357
  }
17164
17358
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
17165
- const skill = readSkill((0, import_node_path38.join)(dir, "SKILL.md"), "cli");
17359
+ const skill = readSkill((0, import_node_path39.join)(dir, "SKILL.md"), "cli");
17166
17360
  if (skill) out.push(skill);
17167
17361
  }
17168
17362
  for (const entry of entries) {
17169
17363
  if (entry === "node_modules" || entry === ".git") continue;
17170
- const full = (0, import_node_path38.join)(dir, entry);
17364
+ const full = (0, import_node_path39.join)(dir, entry);
17171
17365
  try {
17172
- if (!(0, import_node_fs41.statSync)(full).isDirectory()) continue;
17366
+ if (!(0, import_node_fs42.statSync)(full).isDirectory()) continue;
17173
17367
  } catch {
17174
17368
  continue;
17175
17369
  }
@@ -17184,20 +17378,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
17184
17378
  walk(pluginsRoot, 0, false);
17185
17379
  }
17186
17380
  function discoverSkills(worktreePath) {
17187
- const home = (0, import_node_os11.homedir)();
17381
+ const home = (0, import_node_os12.homedir)();
17188
17382
  const collected = [];
17189
17383
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
17190
- scanSkillsDir((0, import_node_path38.join)(worktreePath, rel), "workspace", collected);
17384
+ scanSkillsDir((0, import_node_path39.join)(worktreePath, rel), "workspace", collected);
17191
17385
  }
17192
17386
  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")
17387
+ (0, import_node_path39.join)(home, ".claude/skills"),
17388
+ (0, import_node_path39.join)(home, ".cursor/skills"),
17389
+ (0, import_node_path39.join)(home, ".sideboard/skills"),
17390
+ (0, import_node_path39.join)(home, ".brightsy/skills")
17197
17391
  ]) {
17198
17392
  scanSkillsDir(abs, "user", collected);
17199
17393
  }
17200
- scanClaudePluginSkills((0, import_node_path38.join)(home, ".claude/plugins"), collected);
17394
+ scanClaudePluginSkills((0, import_node_path39.join)(home, ".claude/plugins"), collected);
17201
17395
  collected.push(...bundledSkills());
17202
17396
  const rank = {
17203
17397
  workspace: 0,
@@ -17223,7 +17417,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
17223
17417
  \u2026(truncated)` : body;
17224
17418
  }
17225
17419
  }
17226
- const raw = (0, import_node_fs41.readFileSync)(skillPath, "utf8");
17420
+ const raw = (0, import_node_fs42.readFileSync)(skillPath, "utf8");
17227
17421
  if (raw.startsWith("---")) {
17228
17422
  const end = raw.indexOf("\n---", 3);
17229
17423
  if (end >= 0) {
@@ -17237,13 +17431,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
17237
17431
 
17238
17432
  \u2026(truncated)` : raw;
17239
17433
  }
17240
- var import_node_fs41, import_node_os11, import_node_path38, BUNDLED_SKILL_PREFIX;
17434
+ var import_node_fs42, import_node_os12, import_node_path39, BUNDLED_SKILL_PREFIX;
17241
17435
  var init_discover = __esm({
17242
17436
  "src/skills/discover.ts"() {
17243
17437
  "use strict";
17244
- import_node_fs41 = require("fs");
17245
- import_node_os11 = require("os");
17246
- import_node_path38 = require("path");
17438
+ import_node_fs42 = require("fs");
17439
+ import_node_os12 = require("os");
17440
+ import_node_path39 = require("path");
17247
17441
  init_long_running();
17248
17442
  BUNDLED_SKILL_PREFIX = "bundled:";
17249
17443
  }
@@ -17338,17 +17532,17 @@ var init_expand = __esm({
17338
17532
  function packagedDetachedJobPath() {
17339
17533
  const dir = packagedMcpDir();
17340
17534
  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;
17535
+ const script = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
17536
+ return (0, import_node_fs43.existsSync)(script) ? script : null;
17343
17537
  }
17344
17538
  function resolveDetachedJobScript() {
17345
17539
  const packaged = packagedDetachedJobPath();
17346
17540
  if (packaged) return packaged;
17347
- let dir = (0, import_node_path39.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
17541
+ let dir = (0, import_node_path40.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
17348
17542
  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);
17543
+ const candidate = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
17544
+ if ((0, import_node_fs43.existsSync)(candidate)) return candidate;
17545
+ const parent = (0, import_node_path40.dirname)(dir);
17352
17546
  if (parent === dir) break;
17353
17547
  dir = parent;
17354
17548
  }
@@ -17359,12 +17553,12 @@ function formatDetachedJobInvoke(scriptPath) {
17359
17553
  if (resolved) return `node ${JSON.stringify(resolved)}`;
17360
17554
  return "node scripts/detached-job.js";
17361
17555
  }
17362
- var import_node_fs42, import_node_path39, import_node_url3, import_meta3;
17556
+ var import_node_fs43, import_node_path40, import_node_url3, import_meta3;
17363
17557
  var init_detached_job_path = __esm({
17364
17558
  "src/skills/detached-job-path.ts"() {
17365
17559
  "use strict";
17366
- import_node_fs42 = require("fs");
17367
- import_node_path39 = require("path");
17560
+ import_node_fs43 = require("fs");
17561
+ import_node_path40 = require("path");
17368
17562
  import_node_url3 = require("url");
17369
17563
  init_packaged_runtime();
17370
17564
  import_meta3 = {};
@@ -17437,11 +17631,11 @@ function formatWorktreeDirective(thread, opts) {
17437
17631
  );
17438
17632
  } else if (opts?.githubSlug) {
17439
17633
  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.`
17634
+ `- 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
17635
  );
17442
17636
  } else {
17443
17637
  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."
17638
+ "- 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
17639
  );
17446
17640
  }
17447
17641
  lines.push("");
@@ -17497,7 +17691,7 @@ function formatLongRunningDirective(opts) {
17497
17691
  "- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
17498
17692
  `- Loop \`${invoke} wait <id>\` (returns in ~45s). stillRunning \u2192 present the same id with \`content=delta\` only \u2192 wait again. Do not resend the full log or HTML.`,
17499
17693
  "- ok \u2192 finish the task. failed \u2192 read the log, fix, start once.",
17500
- "State: `.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
17694
+ "State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
17501
17695
  ].join("\n");
17502
17696
  }
17503
17697
  function formatLongRunningReminder(opts) {
@@ -17539,11 +17733,11 @@ function loadAgentInstructions(worktreePath, agent) {
17539
17733
  const out = [];
17540
17734
  for (const rel of candidates) {
17541
17735
  if (seenPaths.has(rel)) continue;
17542
- const abs = (0, import_node_path40.join)(worktreePath, rel);
17543
- if (!(0, import_node_fs43.existsSync)(abs)) continue;
17736
+ const abs = (0, import_node_path41.join)(worktreePath, rel);
17737
+ if (!(0, import_node_fs44.existsSync)(abs)) continue;
17544
17738
  try {
17545
- if (!(0, import_node_fs43.statSync)(abs).isFile()) continue;
17546
- let content = (0, import_node_fs43.readFileSync)(abs, "utf8");
17739
+ if (!(0, import_node_fs44.statSync)(abs).isFile()) continue;
17740
+ let content = (0, import_node_fs44.readFileSync)(abs, "utf8");
17547
17741
  if (!content.trim()) continue;
17548
17742
  if (content.length > MAX_CHARS_PER_FILE) {
17549
17743
  content = `${content.slice(0, MAX_CHARS_PER_FILE)}
@@ -17583,12 +17777,12 @@ function withAgentInstructions(prompt, files) {
17583
17777
 
17584
17778
  ${prompt}`;
17585
17779
  }
17586
- var import_node_fs43, import_node_path40, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
17780
+ var import_node_fs44, import_node_path41, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
17587
17781
  var init_instructions = __esm({
17588
17782
  "src/agents/instructions.ts"() {
17589
17783
  "use strict";
17590
- import_node_fs43 = require("fs");
17591
- import_node_path40 = require("path");
17784
+ import_node_fs44 = require("fs");
17785
+ import_node_path41 = require("path");
17592
17786
  init_git_auth_mode();
17593
17787
  init_worktree_labels();
17594
17788
  init_detached_job_path();
@@ -17934,40 +18128,40 @@ __export(plan_file_exports, {
17934
18128
  writePlanFile: () => writePlanFile
17935
18129
  });
17936
18130
  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");
18131
+ const gitignoreAbs = (0, import_node_path42.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
18132
+ if ((0, import_node_fs45.existsSync)(gitignoreAbs)) return;
18133
+ (0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(gitignoreAbs), { recursive: true });
18134
+ (0, import_node_fs45.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
17941
18135
  }
17942
18136
  function planFileAbs(worktreePath) {
17943
- return (0, import_node_path41.join)(worktreePath, PLAN_FILE_REL);
18137
+ return (0, import_node_path42.join)(worktreePath, PLAN_FILE_REL);
17944
18138
  }
17945
18139
  function readTextIfPresent2(abs) {
17946
- if (!(0, import_node_fs44.existsSync)(abs)) return null;
18140
+ if (!(0, import_node_fs45.existsSync)(abs)) return null;
17947
18141
  try {
17948
- const content = (0, import_node_fs44.readFileSync)(abs, "utf8");
18142
+ const content = (0, import_node_fs45.readFileSync)(abs, "utf8");
17949
18143
  return content.trim() ? content : null;
17950
18144
  } catch {
17951
18145
  return null;
17952
18146
  }
17953
18147
  }
17954
18148
  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));
18149
+ 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
18150
  }
17957
18151
  function writePlanFile(worktreePath, content) {
17958
18152
  ensureAttachmentsGitignore(worktreePath);
17959
18153
  const abs = planFileAbs(worktreePath);
17960
- (0, import_node_fs44.mkdirSync)((0, import_node_path41.dirname)(abs), { recursive: true });
18154
+ (0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(abs), { recursive: true });
17961
18155
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
17962
- (0, import_node_fs44.writeFileSync)(abs, body, "utf8");
18156
+ (0, import_node_fs45.writeFileSync)(abs, body, "utf8");
17963
18157
  return PLAN_FILE_REL;
17964
18158
  }
17965
- var import_node_fs44, import_node_path41;
18159
+ var import_node_fs45, import_node_path42;
17966
18160
  var init_plan_file = __esm({
17967
18161
  "src/plan/plan-file.ts"() {
17968
18162
  "use strict";
17969
- import_node_fs44 = require("fs");
17970
- import_node_path41 = require("path");
18163
+ import_node_fs45 = require("fs");
18164
+ import_node_path42 = require("path");
17971
18165
  init_workspace_scratch();
17972
18166
  init_plan_present();
17973
18167
  init_plan_present();
@@ -18015,13 +18209,13 @@ var init_sync_branch = __esm({
18015
18209
 
18016
18210
  // src/agents/cursor-store.ts
18017
18211
  function cursorSdkStoreDir(threadId) {
18018
- const root = (0, import_node_path42.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
18212
+ const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
18019
18213
  const id = sanitizeCursorStoreSegment(threadId);
18020
18214
  if (!id) return root;
18021
- return (0, import_node_path42.join)(root, "threads", id);
18215
+ return (0, import_node_path43.join)(root, "threads", id);
18022
18216
  }
18023
18217
  function cursorSdkRunsNdjsonPath(threadId) {
18024
- return (0, import_node_path42.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
18218
+ return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
18025
18219
  }
18026
18220
  function cursorSdkRunsNdjsonSearchPaths(threadId) {
18027
18221
  const scoped = cursorSdkRunsNdjsonPath(threadId);
@@ -18034,11 +18228,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
18034
18228
  function sanitizeCursorStoreSegment(threadId) {
18035
18229
  return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
18036
18230
  }
18037
- var import_node_path42, CURSOR_SDK_STORE_DIR;
18231
+ var import_node_path43, CURSOR_SDK_STORE_DIR;
18038
18232
  var init_cursor_store = __esm({
18039
18233
  "src/agents/cursor-store.ts"() {
18040
18234
  "use strict";
18041
- import_node_path42 = require("path");
18235
+ import_node_path43 = require("path");
18042
18236
  init_paths();
18043
18237
  CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
18044
18238
  }
@@ -18060,9 +18254,9 @@ function recoverFinishedCursorRun(opts) {
18060
18254
  return best;
18061
18255
  }
18062
18256
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
18063
- if (!(0, import_node_fs45.existsSync)(runsPath)) return null;
18257
+ if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
18064
18258
  try {
18065
- const lines = (0, import_node_fs45.readFileSync)(runsPath, "utf8").split("\n");
18259
+ const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
18066
18260
  let best = null;
18067
18261
  for (const line of lines) {
18068
18262
  const trimmed = line.trim();
@@ -18088,11 +18282,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
18088
18282
  return null;
18089
18283
  }
18090
18284
  }
18091
- var import_node_fs45;
18285
+ var import_node_fs46;
18092
18286
  var init_cursor_recover = __esm({
18093
18287
  "src/agents/cursor-recover.ts"() {
18094
18288
  "use strict";
18095
- import_node_fs45 = require("fs");
18289
+ import_node_fs46 = require("fs");
18096
18290
  init_cursor_store();
18097
18291
  }
18098
18292
  });
@@ -18131,6 +18325,7 @@ var init_title = __esm({
18131
18325
  // src/orchestrator/orchestrator.ts
18132
18326
  var orchestrator_exports = {};
18133
18327
  __export(orchestrator_exports, {
18328
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
18134
18329
  Orchestrator: () => Orchestrator,
18135
18330
  getOrchestrator: () => getOrchestrator,
18136
18331
  isPidAlive: () => isPidAlive,
@@ -18223,13 +18418,13 @@ async function startOrchestration(opts) {
18223
18418
  }
18224
18419
  return updated;
18225
18420
  }
18226
- var import_node_events, import_node_fs46, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
18421
+ var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
18227
18422
  var init_orchestrator = __esm({
18228
18423
  "src/orchestrator/orchestrator.ts"() {
18229
18424
  "use strict";
18230
18425
  import_node_events = require("events");
18231
18426
  init_outbound_watch();
18232
- import_node_fs46 = require("fs");
18427
+ import_node_fs47 = require("fs");
18233
18428
  init_error_detail();
18234
18429
  init_run();
18235
18430
  init_stale_lock();
@@ -18244,6 +18439,7 @@ var init_orchestrator = __esm({
18244
18439
  init_orphan_cleanup();
18245
18440
  init_apply_into_main();
18246
18441
  init_clone_repo();
18442
+ init_message_parts();
18247
18443
  init_usage();
18248
18444
  init_thread_store();
18249
18445
  init_desktop_host();
@@ -18281,6 +18477,7 @@ var init_orchestrator = __esm({
18281
18477
  init_caffeinate_hold();
18282
18478
  init_schedule_runner();
18283
18479
  init_coordinator_prompt();
18480
+ LIVE_TURN_SPAWN_GRACE_MS = 15e3;
18284
18481
  STALE_AGENT_PID_WAIT_MS = 2500;
18285
18482
  Orchestrator = class {
18286
18483
  events = new import_node_events.EventEmitter();
@@ -18337,6 +18534,39 @@ var init_orchestrator = __esm({
18337
18534
  if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
18338
18535
  return true;
18339
18536
  }
18537
+ /**
18538
+ * Whether a child is actually turning — not leftover disk `running` after
18539
+ * the process died. Coordinators were telling users “Agent is running.
18540
+ * Waiting for gate to pass” from stale stillRunning.
18541
+ */
18542
+ threadLooksLive(thread) {
18543
+ if (thread.status === "queued") {
18544
+ if (this.draining.has(thread.id) || this.startingTurns.has(thread.id)) return true;
18545
+ return thread.queue.length > 0;
18546
+ }
18547
+ if (thread.status !== "running") return false;
18548
+ if (this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id)) return true;
18549
+ const pid = thread.agentPid;
18550
+ if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return true;
18551
+ const updated = Date.parse(thread.updatedAt ?? "");
18552
+ if (Number.isFinite(updated) && Date.now() - updated < LIVE_TURN_SPAWN_GRACE_MS) return true;
18553
+ return false;
18554
+ }
18555
+ /** Desktop-only: persist idle/stopped when MCP would otherwise keep reporting live. */
18556
+ healStaleReportedActivity(thread) {
18557
+ if (!thisProcessShouldDrainAgentQueues()) return thread;
18558
+ if (this.threadLooksLive(thread)) return thread;
18559
+ if (thread.status === "running") {
18560
+ this.healStaleRunningTurns();
18561
+ return readThread(thread.id) ?? thread;
18562
+ }
18563
+ if (thread.status === "queued" && thread.queue.length === 0 && !this.activeTurns.has(thread.id) && !this.startingTurns.has(thread.id) && !this.draining.has(thread.id)) {
18564
+ setStatus(thread.id, "idle");
18565
+ this.emit({ type: "status_changed", threadId: thread.id, status: "idle" });
18566
+ return readThread(thread.id) ?? thread;
18567
+ }
18568
+ return thread;
18569
+ }
18340
18570
  async reconcile(repoPath, opts) {
18341
18571
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
18342
18572
  const drainQueues = opts?.drainQueues !== false;
@@ -18361,7 +18591,7 @@ var init_orchestrator = __esm({
18361
18591
  }
18362
18592
  continue;
18363
18593
  }
18364
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
18594
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
18365
18595
  setStatus(thread.id, "broken", "Worktree missing on disk");
18366
18596
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
18367
18597
  continue;
@@ -18671,12 +18901,14 @@ var init_orchestrator = __esm({
18671
18901
  this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
18672
18902
  return thread;
18673
18903
  }
18674
- async send(threadRef, prompt) {
18904
+ async send(threadRef, prompt, opts) {
18675
18905
  const thread = this.requireThread(threadRef);
18676
18906
  if (thread.status === "archived") {
18677
18907
  throw new Error(`Thread is archived: ${thread.id}`);
18678
18908
  }
18679
- return withThreadLock(thread.id, async () => {
18909
+ const followUp = opts?.followUp === "steer" ? "steer" : "queue";
18910
+ let shouldSteer = false;
18911
+ const sent = await withThreadLock(thread.id, async () => {
18680
18912
  const current = this.requireThread(thread.id);
18681
18913
  if (current.status === "archived") {
18682
18914
  throw new Error(`Thread is archived: ${thread.id}`);
@@ -18685,6 +18917,7 @@ var init_orchestrator = __esm({
18685
18917
  this.crashContinued.delete(thread.id);
18686
18918
  this.haltDrain.delete(thread.id);
18687
18919
  const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
18920
+ shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
18688
18921
  const patch = { queue };
18689
18922
  if (!inFlight) patch.status = "queued";
18690
18923
  const pid = current.agentPid;
@@ -18696,16 +18929,20 @@ var init_orchestrator = __esm({
18696
18929
  if (!inFlight) {
18697
18930
  this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
18698
18931
  }
18699
- if (thisProcessShouldDrainAgentQueues()) {
18932
+ if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
18700
18933
  void this.drainQueue(thread.id);
18701
18934
  }
18702
18935
  return this.requireThread(thread.id);
18703
18936
  });
18937
+ if (shouldSteer && sent.queue.length > 0) {
18938
+ return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
18939
+ }
18940
+ return sent;
18704
18941
  }
18705
- async fanOut(threadRefs, prompt) {
18942
+ async fanOut(threadRefs, prompt, opts) {
18706
18943
  const results = [];
18707
18944
  for (const ref of threadRefs) {
18708
- results.push(await this.send(ref, prompt));
18945
+ results.push(await this.send(ref, prompt, opts));
18709
18946
  }
18710
18947
  return results;
18711
18948
  }
@@ -19509,8 +19746,8 @@ var init_orchestrator = __esm({
19509
19746
  return created;
19510
19747
  }
19511
19748
  async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
19512
- const thread = this.requireThread(threadRef);
19513
- if (!["running", "queued"].includes(thread.status)) {
19749
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19750
+ if (!this.threadLooksLive(thread)) {
19514
19751
  return thread;
19515
19752
  }
19516
19753
  const start = Date.now();
@@ -19547,12 +19784,13 @@ var init_orchestrator = __esm({
19547
19784
  }
19548
19785
  });
19549
19786
  timer = setInterval(() => {
19550
- const current = readThread(thread.id);
19551
- if (!current) {
19787
+ const raw = readThread(thread.id);
19788
+ if (!raw) {
19552
19789
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
19553
19790
  return;
19554
19791
  }
19555
- if (!["running", "queued"].includes(current.status)) {
19792
+ const current = this.healStaleReportedActivity(raw);
19793
+ if (!this.threadLooksLive(current)) {
19556
19794
  finish(() => resolve(current));
19557
19795
  return;
19558
19796
  }
@@ -19575,20 +19813,22 @@ var init_orchestrator = __esm({
19575
19813
  };
19576
19814
  }
19577
19815
  getTurnResult(threadRef) {
19578
- const thread = this.requireThread(threadRef);
19816
+ const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
19579
19817
  const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
19580
19818
  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";
19819
+ const rawText = (lastAgent?.text ?? "").trim();
19820
+ const text5 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
19821
+ const stillRunning = this.threadLooksLive(thread);
19583
19822
  const live = stillRunning ? readTurnLive(thread.id) : null;
19584
- const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
19823
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
19824
+ const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
19585
19825
  return {
19586
19826
  text: text5,
19587
19827
  status: thread.status,
19588
19828
  sessionId: thread.sessionId,
19589
19829
  lastError,
19590
19830
  stillRunning,
19591
- progress: live?.summary ?? queuedHint,
19831
+ progress: liveSummary ?? queuedHint,
19592
19832
  lastActivityAt: live?.updatedAt ?? null,
19593
19833
  usage: lastAgent?.usage ?? null
19594
19834
  };
@@ -19936,7 +20176,14 @@ var init_orchestrator = __esm({
19936
20176
  );
19937
20177
  }
19938
20178
  if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
19939
- await this.pushAndMaybeOpenPr(thread, action);
20179
+ try {
20180
+ await this.pushAndMaybeOpenPr(thread, action);
20181
+ } catch (err) {
20182
+ const message = err instanceof Error ? err.message : String(err);
20183
+ updateThread(thread.id, { lastError: message });
20184
+ this.emit({ type: "error", threadId: thread.id, message });
20185
+ throw err;
20186
+ }
19940
20187
  return this.requireThread(threadRef);
19941
20188
  }
19942
20189
  let prBase;
@@ -20139,7 +20386,7 @@ var init_orchestrator = __esm({
20139
20386
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
20140
20387
  return restored2;
20141
20388
  }
20142
- if (!(0, import_node_fs46.existsSync)(thread.worktreePath)) {
20389
+ if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
20143
20390
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
20144
20391
  throw new Error(
20145
20392
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -20151,6 +20398,8 @@ var init_orchestrator = __esm({
20151
20398
  await withRepoGitLock(thread.repoPath, async () => {
20152
20399
  await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
20153
20400
  });
20401
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
20402
+ await ensureWorktreeSideboardIgnored2(dest);
20154
20403
  void createThreadWorktree2;
20155
20404
  void slug;
20156
20405
  }
@@ -20364,19 +20613,25 @@ __export(index_exports, {
20364
20613
  COORDINATOR_TOOL_PLAYBOOK: () => COORDINATOR_TOOL_PLAYBOOK,
20365
20614
  DEFAULT_ABLETIME_HOST: () => DEFAULT_ABLETIME_HOST,
20366
20615
  DEFAULT_WORKTREE_SORT: () => DEFAULT_WORKTREE_SORT,
20616
+ DETACHED_JOBS_DIR: () => DETACHED_JOBS_DIR,
20367
20617
  FAMOUS_SOCCER_TEAMS: () => FAMOUS_SOCCER_TEAMS,
20618
+ FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
20368
20619
  GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
20620
+ GITHUB_PR_BODY_MAX_CHARS: () => GITHUB_PR_BODY_MAX_CHARS,
20621
+ GITHUB_PR_BODY_SAFE_CHARS: () => GITHUB_PR_BODY_SAFE_CHARS,
20369
20622
  GLOBAL_WORKSPACE_ID: () => GLOBAL_WORKSPACE_ID,
20370
20623
  HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
20371
20624
  HOME_BOARD_CACHE_TTL_MS: () => HOME_BOARD_CACHE_TTL_MS,
20372
20625
  ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
20373
20626
  LEGACY_ATTACHMENTS_DIR: () => LEGACY_ATTACHMENTS_DIR,
20627
+ LEGACY_DETACHED_JOBS_DIR: () => LEGACY_DETACHED_JOBS_DIR,
20374
20628
  LEGACY_PLAN_FILE_REL: () => LEGACY_PLAN_FILE_REL,
20375
20629
  LEGACY_REVIEW_REQUEST_PATH: () => LEGACY_REVIEW_REQUEST_PATH,
20376
20630
  LINEAR_OAUTH_CANCELLED: () => LINEAR_OAUTH_CANCELLED,
20377
20631
  LINEAR_OAUTH_PORT: () => LINEAR_OAUTH_PORT,
20378
20632
  LINEAR_OAUTH_REDIRECT: () => LINEAR_OAUTH_REDIRECT,
20379
20633
  LINEAR_OAUTH_SCOPES: () => LINEAR_OAUTH_SCOPES,
20634
+ LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
20380
20635
  LONG_RUNNING_SKILL_COMMAND: () => LONG_RUNNING_SKILL_COMMAND,
20381
20636
  LinearOAuthCancelledError: () => LinearOAuthCancelledError,
20382
20637
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS: () => MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
@@ -20466,6 +20721,7 @@ __export(index_exports, {
20466
20721
  buildCodeRefAttachment: () => buildCodeRefAttachment,
20467
20722
  buildDiffCommentAttachment: () => buildDiffCommentAttachment,
20468
20723
  buildForkTranscriptAttachment: () => buildForkTranscriptAttachment,
20724
+ buildLinearIssueFilter: () => buildLinearIssueFilter,
20469
20725
  buildPastedTextAttachment: () => buildPastedTextAttachment,
20470
20726
  buildPathRefAttachment: () => buildPathRefAttachment,
20471
20727
  buildReviewRequestAttachment: () => buildReviewRequestAttachment,
@@ -20483,6 +20739,7 @@ __export(index_exports, {
20483
20739
  checkoutPrStackLayer: () => checkoutPrStackLayer,
20484
20740
  childEnvWithAppSettings: () => childEnvWithAppSettings,
20485
20741
  claimDesktopHost: () => claimDesktopHost,
20742
+ clampGithubPrBody: () => clampGithubPrBody,
20486
20743
  classifyWorktreeColumn: () => classifyWorktreeColumn,
20487
20744
  claudeAdapter: () => claudeAdapter,
20488
20745
  claudeChromeEnabled: () => claudeChromeEnabled,
@@ -20587,6 +20844,7 @@ __export(index_exports, {
20587
20844
  fireSchedule: () => fireSchedule,
20588
20845
  flattenTurnInput: () => flattenTurnInput,
20589
20846
  flipLinearRelationType: () => flipLinearRelationType,
20847
+ followUpBehavior: () => followUpBehavior,
20590
20848
  forkChatTab: () => forkChatTab,
20591
20849
  forkMessageSlice: () => forkMessageSlice,
20592
20850
  forkThreadWorktree: () => forkThreadWorktree,
@@ -20665,6 +20923,7 @@ __export(index_exports, {
20665
20923
  ghRepoSelectArgs: () => ghRepoSelectArgs,
20666
20924
  git: () => git,
20667
20925
  githubAgentGitEnv: () => githubAgentGitEnv,
20926
+ githubHttpsInsteadOfEntries: () => githubHttpsInsteadOfEntries,
20668
20927
  globalAgentCwd: () => globalAgentCwd,
20669
20928
  groupHomeBoardWorktrees: () => groupHomeBoardWorktrees,
20670
20929
  handleSlackInbound: () => handleSlackInbound,
@@ -20701,6 +20960,7 @@ __export(index_exports, {
20701
20960
  isDefaultishSourceRef: () => isDefaultishSourceRef,
20702
20961
  isDesktopHostAlive: () => isDesktopHostAlive,
20703
20962
  isDirty: () => isDirty,
20963
+ isGhPrBodyTooLongError: () => isGhPrBodyTooLongError,
20704
20964
  isGhRateLimitError: () => isGhRateLimitError,
20705
20965
  isGlobalRepoPath: () => isGlobalRepoPath,
20706
20966
  isGlobalThread: () => isGlobalThread,
@@ -20708,6 +20968,7 @@ __export(index_exports, {
20708
20968
  isImageFilePath: () => isImageFilePath,
20709
20969
  isInPrStack: () => isInPrStack,
20710
20970
  isInboundForThisDesktop: () => isInboundForThisDesktop,
20971
+ isInternalAgentStatusText: () => isInternalAgentStatusText,
20711
20972
  isIssueSourceConnected: () => isIssueSourceConnected,
20712
20973
  isLinearConnected: () => isLinearConnected,
20713
20974
  isLinearOAuthCancelled: () => isLinearOAuthCancelled,
@@ -20734,6 +20995,7 @@ __export(index_exports, {
20734
20995
  isThreadRecordFile: () => isThreadRecordFile,
20735
20996
  isWorkspaceScratchPath: () => isWorkspaceScratchPath,
20736
20997
  issueAttachmentForAbleTimeTask: () => issueAttachmentForAbleTimeTask,
20998
+ issueMatchesAssignee: () => issueMatchesAssignee,
20737
20999
  issueSourceLabel: () => issueSourceLabel,
20738
21000
  lastRequestOccupancy: () => lastRequestOccupancy,
20739
21001
  latestPendingPlanQuestions: () => latestPendingPlanQuestions,
@@ -20761,6 +21023,7 @@ __export(index_exports, {
20761
21023
  listLinearAssignedIssues: () => listLinearAssignedIssues,
20762
21024
  listLinearIssues: () => listLinearIssues,
20763
21025
  listLinearIssuesDirect: () => listLinearIssuesDirect,
21026
+ listLinearIssuesFiltered: () => listLinearIssuesFiltered,
20764
21027
  listLinearTeams: () => listLinearTeams,
20765
21028
  listModelsForAgent: () => listModelsForAgent,
20766
21029
  listOpencodeModels: () => listOpencodeModels,
@@ -21102,7 +21365,7 @@ async function refreshGitHubAuth() {
21102
21365
  init_fetch();
21103
21366
 
21104
21367
  // src/integrations/linear-oauth.ts
21105
- var import_node_crypto9 = require("crypto");
21368
+ var import_node_crypto10 = require("crypto");
21106
21369
  var import_node_http = require("http");
21107
21370
  init_app_settings();
21108
21371
  init_fetch();
@@ -21134,8 +21397,8 @@ function linearOAuthCredentials() {
21134
21397
  return { clientId, clientSecret };
21135
21398
  }
21136
21399
  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");
21400
+ const verifier = (0, import_node_crypto10.randomBytes)(32).toString("base64url");
21401
+ const challenge = (0, import_node_crypto10.createHash)("sha256").update(verifier).digest("base64url");
21139
21402
  return { verifier, challenge };
21140
21403
  }
21141
21404
  function linearOAuthAuthorizeUrl(clientId, state, codeChallenge) {
@@ -21266,7 +21529,7 @@ async function startLinearOAuth(opts) {
21266
21529
  throw new LinearOAuthCancelledError();
21267
21530
  }
21268
21531
  const { clientId, clientSecret } = linearOAuthCredentials();
21269
- const state = (0, import_node_crypto9.randomBytes)(16).toString("hex");
21532
+ const state = (0, import_node_crypto10.randomBytes)(16).toString("hex");
21270
21533
  const pkce = createLinearPkce();
21271
21534
  const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
21272
21535
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
@@ -21454,6 +21717,22 @@ query SideboardAssignedIssues($first: Int!) {
21454
21717
  }
21455
21718
  }
21456
21719
  `;
21720
+ var ISSUES_QUERY = `
21721
+ query SideboardIssues($first: Int!, $filter: IssueFilter) {
21722
+ viewer { id name }
21723
+ issues(first: $first, orderBy: updatedAt, filter: $filter) {
21724
+ nodes { ${LIST_ISSUE_FIELDS} }
21725
+ }
21726
+ }
21727
+ `;
21728
+ var SEARCH_ISSUES_QUERY = `
21729
+ query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
21730
+ viewer { id name }
21731
+ searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
21732
+ nodes { ${LIST_ISSUE_FIELDS} }
21733
+ }
21734
+ }
21735
+ `;
21457
21736
  var TEAMS_QUERY = `
21458
21737
  query SideboardTeams {
21459
21738
  viewer { id name }
@@ -21737,19 +22016,76 @@ function normalizePriority(priority) {
21737
22016
  }
21738
22017
  return priority;
21739
22018
  }
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);
22019
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
22020
+ function assigneeFilterKey(assignee) {
22021
+ return (assignee ?? "").trim();
22022
+ }
22023
+ function buildLinearIssueFilter(input) {
22024
+ const filter = {
22025
+ state: { type: { nin: ["completed", "canceled"] } }
22026
+ };
22027
+ const raw = assigneeFilterKey(input?.assignee) || "me";
22028
+ const key = raw.toLowerCase();
22029
+ if (key === "all" || key === "*") return filter;
22030
+ if (key === "unassigned" || key === "none" || key === "null") {
22031
+ filter.assignee = { null: true };
22032
+ return filter;
22033
+ }
22034
+ if (key === "me" || key === "@me") {
22035
+ filter.assignee = { isMe: true };
22036
+ return filter;
22037
+ }
22038
+ if (UUID_RE.test(raw)) {
22039
+ filter.assignee = { id: { eq: raw } };
22040
+ return filter;
22041
+ }
22042
+ filter.assignee = { name: { eqIgnoreCase: raw } };
22043
+ return filter;
22044
+ }
22045
+ function isAssignedToMe(assignee) {
22046
+ const key = assignee.toLowerCase();
22047
+ return key === "me" || key === "@me";
22048
+ }
22049
+ function listedLinearIssues(json, nodes) {
21743
22050
  return {
21744
22051
  viewer: {
21745
22052
  id: String(json.viewer?.id ?? ""),
21746
22053
  name: String(json.viewer?.name ?? "")
21747
22054
  },
21748
- issues: (json.viewer?.assignedIssues?.nodes ?? []).map(
21749
- (node) => toIssueInfo(mapIssue(node))
21750
- )
22055
+ issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
21751
22056
  };
21752
22057
  }
22058
+ async function listLinearIssuesFiltered(opts) {
22059
+ const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
22060
+ const query = opts?.query?.trim() ?? "";
22061
+ const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
22062
+ const filter = buildLinearIssueFilter({ assignee });
22063
+ if (query) {
22064
+ const json2 = await linearGraphql(
22065
+ SEARCH_ISSUES_QUERY,
22066
+ { term: query, first, filter },
22067
+ opts
22068
+ );
22069
+ return listedLinearIssues(json2, json2.searchIssues?.nodes);
22070
+ }
22071
+ if (isAssignedToMe(assignee)) {
22072
+ const json2 = await linearGraphql(
22073
+ ASSIGNED_ISSUES_QUERY,
22074
+ { first },
22075
+ opts
22076
+ );
22077
+ return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
22078
+ }
22079
+ const json = await linearGraphql(
22080
+ ISSUES_QUERY,
22081
+ { first, filter },
22082
+ opts
22083
+ );
22084
+ return listedLinearIssues(json, json.issues?.nodes);
22085
+ }
22086
+ async function listLinearAssignedIssues(opts) {
22087
+ return listLinearIssuesFiltered({ ...opts, assignee: "me" });
22088
+ }
21753
22089
  async function listLinearIssuesDirect(opts) {
21754
22090
  return (await listLinearAssignedIssues(opts)).issues;
21755
22091
  }
@@ -21877,6 +22213,22 @@ init_worktree();
21877
22213
  init_run();
21878
22214
  init_app_settings();
21879
22215
  init_abletime();
22216
+ function assigneeKey(assignee) {
22217
+ return (assignee ?? "").trim().toLowerCase();
22218
+ }
22219
+ function issueMatchesAssignee(issue, assignee, viewerName = "") {
22220
+ const key = assigneeKey(assignee);
22221
+ if (!key || key === "all" || key === "*") return true;
22222
+ const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
22223
+ if (key === "unassigned" || key === "none" || key === "null") {
22224
+ return names.length === 0;
22225
+ }
22226
+ if (key === "me" || key === "@me") {
22227
+ const me = viewerName.trim().toLowerCase();
22228
+ return Boolean(me && names.includes(me));
22229
+ }
22230
+ return names.includes(key);
22231
+ }
21880
22232
  async function listGitHubIssues(repoPath, opts) {
21881
22233
  const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
21882
22234
  const slug = await resolveGithubRepoSlug(repoPath);
@@ -21890,6 +22242,17 @@ async function listGitHubIssues(repoPath, opts) {
21890
22242
  "--state",
21891
22243
  "open"
21892
22244
  ];
22245
+ const query = opts?.query?.trim() ?? "";
22246
+ const assignee = opts?.assignee?.trim() ?? "";
22247
+ const key = assignee.toLowerCase();
22248
+ const searchParts = [];
22249
+ if (query) searchParts.push(query);
22250
+ if (key === "unassigned" || key === "none" || key === "null") {
22251
+ searchParts.push("no:assignee");
22252
+ } else if (key && key !== "all" && key !== "*") {
22253
+ args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
22254
+ }
22255
+ if (searchParts.length) args.push("--search", searchParts.join(" "));
21893
22256
  if (slug) args.push("--repo", slug);
21894
22257
  const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
21895
22258
  if (exitCode !== 0 || !stdout.trim()) return [];
@@ -21927,14 +22290,20 @@ async function githubViewerLogin(repoPath) {
21927
22290
  if (exitCode !== 0) return "";
21928
22291
  return stdout.trim();
21929
22292
  }
21930
- async function listIssues(repoPath) {
22293
+ async function listIssues(repoPath, opts) {
21931
22294
  const settings = loadAppSettings();
21932
22295
  const preferredSource = settings.integrations.issueSource ?? "github";
21933
22296
  const linearConnected = isLinearConnected(settings);
21934
22297
  const abletimeConnected = isAbleTimeConnected(settings);
21935
22298
  const source = resolveEffectiveIssueSource(settings);
22299
+ const query = opts?.query?.trim() || void 0;
22300
+ const assignee = opts?.assignee?.trim() || void 0;
21936
22301
  if (source === "linear") {
21937
- const listed = await listLinearAssignedIssues();
22302
+ const listed = await listLinearIssuesFiltered({
22303
+ assignee,
22304
+ query,
22305
+ limit: opts?.limit
22306
+ });
21938
22307
  return {
21939
22308
  source,
21940
22309
  preferredSource,
@@ -21948,13 +22317,20 @@ async function listIssues(repoPath) {
21948
22317
  };
21949
22318
  }
21950
22319
  if (source === "abletime") {
21951
- const listed = await listAbleTimeAssignedIssues();
22320
+ const [listed, searched] = await Promise.all([
22321
+ listAbleTimeAssignedIssues(),
22322
+ query ? searchAbleTimeTasks(query) : Promise.resolve(null)
22323
+ ]);
22324
+ const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
22325
+ const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
22326
+ (issue) => issueMatchesAssignee(issue, assignee, viewerName)
22327
+ );
21952
22328
  return {
21953
22329
  source,
21954
22330
  preferredSource,
21955
22331
  linearConnected,
21956
22332
  abletimeConnected,
21957
- issues: listed.issues,
22333
+ issues: issues2,
21958
22334
  viewer: {
21959
22335
  login: listed.viewer.name,
21960
22336
  name: listed.viewer.name
@@ -21962,7 +22338,7 @@ async function listIssues(repoPath) {
21962
22338
  };
21963
22339
  }
21964
22340
  const [issues, login] = await Promise.all([
21965
- listGitHubIssues(repoPath),
22341
+ listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
21966
22342
  githubViewerLogin(repoPath)
21967
22343
  ]);
21968
22344
  return {
@@ -22182,7 +22558,7 @@ function buildPathRefAttachment(input) {
22182
22558
  init_stage_files();
22183
22559
 
22184
22560
  // src/composer/pasted-text.ts
22185
- var import_node_crypto10 = require("crypto");
22561
+ var import_node_crypto11 = require("crypto");
22186
22562
  var PASTE_ATTACH_MIN_CHARS = 1200;
22187
22563
  var PASTE_ATTACH_MIN_LINES = 15;
22188
22564
  var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
@@ -22209,7 +22585,7 @@ function nextPastedTextName(existing) {
22209
22585
  }
22210
22586
  function buildPastedTextAttachment(text5, opts) {
22211
22587
  return {
22212
- id: opts?.id ?? (0, import_node_crypto10.randomUUID)(),
22588
+ id: opts?.id ?? (0, import_node_crypto11.randomUUID)(),
22213
22589
  name: opts?.name ?? "Pasted text #1.txt",
22214
22590
  kind: "file",
22215
22591
  path: opts?.path,
@@ -22361,8 +22737,8 @@ init_orphan_cleanup();
22361
22737
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
22362
22738
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
22363
22739
  var import_zod5 = require("zod");
22364
- var import_node_crypto12 = require("crypto");
22365
- var import_node_path45 = require("path");
22740
+ var import_node_crypto13 = require("crypto");
22741
+ var import_node_path46 = require("path");
22366
22742
  init_orchestrator();
22367
22743
  init_worktree();
22368
22744
  init_create();
@@ -22404,14 +22780,16 @@ function mcpWaitFinishedHint(status) {
22404
22780
  }
22405
22781
 
22406
22782
  // src/mcp/server.ts
22783
+ init_message_parts();
22407
22784
  init_turn_live();
22408
22785
 
22409
22786
  // src/mcp/thread-visibility.ts
22787
+ init_message_parts();
22410
22788
  function lastMessagePreview(messages, max = 160) {
22411
22789
  if (!messages?.length) return null;
22412
22790
  for (let i = messages.length - 1; i >= 0; i--) {
22413
22791
  const text5 = messages[i]?.text?.trim();
22414
- if (!text5) continue;
22792
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
22415
22793
  const flat = text5.replace(/\s+/g, " ");
22416
22794
  return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
22417
22795
  }
@@ -23081,6 +23459,22 @@ function registerLinearTools(server) {
23081
23459
  }
23082
23460
  }
23083
23461
  );
23462
+ server.tool(
23463
+ "linear_search_issues",
23464
+ "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).",
23465
+ {
23466
+ query: import_zod3.z.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
23467
+ 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."),
23468
+ limit: import_zod3.z.number().int().positive().max(250).optional()
23469
+ },
23470
+ async ({ query, assignee, limit }) => {
23471
+ try {
23472
+ return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
23473
+ } catch (err) {
23474
+ return fail3(err);
23475
+ }
23476
+ }
23477
+ );
23084
23478
  server.tool(
23085
23479
  "linear_get_issue",
23086
23480
  "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 +23709,31 @@ function registerScheduleTools(server) {
23315
23709
 
23316
23710
  // src/mcp/server.ts
23317
23711
  init_agent_git_actions();
23712
+ init_gh_errors();
23318
23713
  init_git_auth_mode();
23319
23714
 
23320
23715
  // src/board/load-home-board.ts
23321
- var import_node_fs48 = require("fs");
23322
- var import_node_path44 = require("path");
23716
+ var import_node_fs49 = require("fs");
23717
+ var import_node_path45 = require("path");
23323
23718
  init_worktree();
23324
23719
  init_paths();
23325
23720
 
23326
23721
  // 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");
23722
+ var import_node_crypto12 = require("crypto");
23723
+ var import_node_fs48 = require("fs");
23724
+ var import_node_path44 = require("path");
23330
23725
  init_paths();
23331
23726
  init_home_board();
23332
23727
  var FILE = "home-board-pins.json";
23333
23728
  var VERSION = 1;
23334
23729
  function pinsFile() {
23335
- return (0, import_node_path43.join)(appDataDir(), FILE);
23730
+ return (0, import_node_path44.join)(appDataDir(), FILE);
23336
23731
  }
23337
23732
  function readDisk() {
23338
23733
  const path2 = pinsFile();
23339
- if (!(0, import_node_fs47.existsSync)(path2)) return [];
23734
+ if (!(0, import_node_fs48.existsSync)(path2)) return [];
23340
23735
  try {
23341
- const raw = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
23736
+ const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
23342
23737
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
23343
23738
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
23344
23739
  } catch {
@@ -23346,8 +23741,8 @@ function readDisk() {
23346
23741
  }
23347
23742
  }
23348
23743
  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");
23744
+ (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
23745
+ (0, import_node_fs48.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
23351
23746
  }
23352
23747
  function listBoardPins() {
23353
23748
  return readDisk();
@@ -23356,7 +23751,7 @@ function addBoardPin(input) {
23356
23751
  const ref = input.ref.trim();
23357
23752
  if (!ref) throw new Error("Board item needs a ref");
23358
23753
  const pin = {
23359
- id: (0, import_node_crypto11.randomUUID)(),
23754
+ id: (0, import_node_crypto12.randomUUID)(),
23360
23755
  kind: input.kind,
23361
23756
  ref,
23362
23757
  repoPath: input.repoPath.trim(),
@@ -23399,7 +23794,7 @@ function replaceBoardPins(items) {
23399
23794
  }
23400
23795
  function clearBoardPins() {
23401
23796
  try {
23402
- (0, import_node_fs47.unlinkSync)(pinsFile());
23797
+ (0, import_node_fs48.unlinkSync)(pinsFile());
23403
23798
  } catch {
23404
23799
  }
23405
23800
  }
@@ -23416,7 +23811,7 @@ function homeBoardWorkspaceKey(workspaces) {
23416
23811
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
23417
23812
  }
23418
23813
  function cacheFile() {
23419
- return (0, import_node_path44.join)(appDataDir(), "home-board-cache.json");
23814
+ return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
23420
23815
  }
23421
23816
  function emptyInputs() {
23422
23817
  return {
@@ -23442,9 +23837,9 @@ function shouldCacheHomeBoardInputs(inputs) {
23442
23837
  }
23443
23838
  function readDiskCache() {
23444
23839
  const path2 = cacheFile();
23445
- if (!(0, import_node_fs48.existsSync)(path2)) return null;
23840
+ if (!(0, import_node_fs49.existsSync)(path2)) return null;
23446
23841
  try {
23447
- const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
23842
+ const raw = JSON.parse((0, import_node_fs49.readFileSync)(path2, "utf8"));
23448
23843
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
23449
23844
  return null;
23450
23845
  }
@@ -23458,14 +23853,14 @@ function readDiskCache() {
23458
23853
  }
23459
23854
  function writeDiskCache(entry) {
23460
23855
  try {
23461
- (0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
23462
- (0, import_node_fs48.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
23856
+ (0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
23857
+ (0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
23463
23858
  } catch {
23464
23859
  }
23465
23860
  }
23466
23861
  function deleteDiskCache() {
23467
23862
  try {
23468
- (0, import_node_fs48.unlinkSync)(cacheFile());
23863
+ (0, import_node_fs49.unlinkSync)(cacheFile());
23469
23864
  } catch {
23470
23865
  }
23471
23866
  }
@@ -23762,13 +24157,13 @@ async function startMcpServer() {
23762
24157
  async () => {
23763
24158
  const threads = orch.getThreads(true);
23764
24159
  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;
24160
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path46.basename)(t.repoPath) || t.repoPath;
24161
+ const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
23767
24162
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
23768
24163
  const preview = lastMessagePreview(t.messages, 80);
23769
24164
  const previewBit = preview ? ` ${preview}` : "";
23770
24165
  const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
23771
- const progress = live?.summary ? ` ${live.summary}` : "";
24166
+ const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
23772
24167
  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
24168
  });
23774
24169
  return {
@@ -23830,7 +24225,9 @@ async function startMcpServer() {
23830
24225
  if (!t) {
23831
24226
  return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
23832
24227
  }
23833
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
24228
+ const stillRunning = orch.threadLooksLive(t);
24229
+ const live = stillRunning ? readTurnLive(t.id) : null;
24230
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
23834
24231
  const spend = orch.getThreadUsage(t.id);
23835
24232
  const summary = {
23836
24233
  id: t.id,
@@ -23850,8 +24247,8 @@ async function startMcpServer() {
23850
24247
  devPort: t.devPort,
23851
24248
  prUrl: t.prUrl,
23852
24249
  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),
24250
+ stillRunning,
24251
+ progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
23855
24252
  lastActivityAt: live?.updatedAt ?? null,
23856
24253
  usage: spend.usage,
23857
24254
  lastTurnUsage: spend.lastTurnUsage
@@ -24132,7 +24529,7 @@ async function startMcpServer() {
24132
24529
  const ident = issue?.identifier ?? ref.trim();
24133
24530
  const attachments = issue ? [
24134
24531
  {
24135
- id: (0, import_node_crypto12.randomUUID)(),
24532
+ id: (0, import_node_crypto13.randomUUID)(),
24136
24533
  name: issue.identifier,
24137
24534
  kind: "issue",
24138
24535
  content: [
@@ -24208,7 +24605,7 @@ async function startMcpServer() {
24208
24605
  );
24209
24606
  server.tool(
24210
24607
  "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).",
24608
+ "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
24609
  {
24213
24610
  ref: import_zod5.z.string(),
24214
24611
  timeoutMs: import_zod5.z.number().optional()
@@ -24400,7 +24797,7 @@ async function startMcpServer() {
24400
24797
  );
24401
24798
  server.tool(
24402
24799
  "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.",
24800
+ "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
24801
  {
24405
24802
  ref: import_zod5.z.string().describe("Worktree thread id/ref"),
24406
24803
  action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
@@ -24425,8 +24822,26 @@ async function startMcpServer() {
24425
24822
  ]
24426
24823
  };
24427
24824
  } catch (err) {
24428
- const message = err instanceof Error ? err.message : String(err);
24429
- return { content: [{ type: "text", text: message }], isError: true };
24825
+ const raw = err instanceof Error ? err.message : String(err);
24826
+ const message = formatGhLandError(raw);
24827
+ return {
24828
+ content: [
24829
+ {
24830
+ type: "text",
24831
+ text: JSON.stringify(
24832
+ {
24833
+ error: true,
24834
+ action,
24835
+ lastError: message,
24836
+ 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
24837
+ },
24838
+ null,
24839
+ 2
24840
+ )
24841
+ }
24842
+ ],
24843
+ isError: true
24844
+ };
24430
24845
  }
24431
24846
  }
24432
24847
  );
@@ -24821,11 +25236,15 @@ async function startMcpServer() {
24821
25236
  );
24822
25237
  server.tool(
24823
25238
  "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 }) => {
25239
+ "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.",
25240
+ {
25241
+ repoPath: import_zod5.z.string(),
25242
+ query: import_zod5.z.string().optional().describe("Search title, identifier, or description"),
25243
+ assignee: import_zod5.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
25244
+ },
25245
+ async ({ repoPath, query, assignee }) => {
24827
25246
  const root = await resolveRepoRoot(repoPath);
24828
- const result = await listIssues(root);
25247
+ const result = await listIssues(root, { query, assignee });
24829
25248
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
24830
25249
  }
24831
25250
  );
@@ -25172,16 +25591,16 @@ init_oauth();
25172
25591
  init_injected_mcp();
25173
25592
 
25174
25593
  // 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");
25594
+ var import_node_fs50 = require("fs");
25595
+ var import_node_os13 = require("os");
25596
+ var import_node_path47 = require("path");
25178
25597
  init_paths();
25179
25598
  init_injected_mcp();
25180
25599
  function userCursorMcpConfigPath() {
25181
- return (0, import_node_path46.join)((0, import_node_os12.homedir)(), ".cursor", "mcp.json");
25600
+ return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".cursor", "mcp.json");
25182
25601
  }
25183
25602
  function userClaudeMcpConfigPath() {
25184
- return (0, import_node_path46.join)((0, import_node_os12.homedir)(), ".claude.json");
25603
+ return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".claude.json");
25185
25604
  }
25186
25605
  function asObject(value) {
25187
25606
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -25208,16 +25627,16 @@ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
25208
25627
  }
25209
25628
  function writeMergedMcpServersJson(configPath, sideboard) {
25210
25629
  let existing = {};
25211
- if ((0, import_node_fs49.existsSync)(configPath)) {
25630
+ if ((0, import_node_fs50.existsSync)(configPath)) {
25212
25631
  try {
25213
- existing = JSON.parse((0, import_node_fs49.readFileSync)(configPath, "utf8"));
25632
+ existing = JSON.parse((0, import_node_fs50.readFileSync)(configPath, "utf8"));
25214
25633
  } catch {
25215
25634
  existing = {};
25216
25635
  }
25217
25636
  }
25218
25637
  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)}
25638
+ (0, import_node_fs50.mkdirSync)((0, import_node_path47.dirname)(configPath), { recursive: true });
25639
+ (0, import_node_fs50.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
25221
25640
  `);
25222
25641
  }
25223
25642
  function launchFromResolved(server) {
@@ -25235,7 +25654,7 @@ async function registerPackagedUserMcpClients() {
25235
25654
  const cursor = userCursorMcpConfigPath();
25236
25655
  writeMergedMcpServersJson(cursor, launch);
25237
25656
  const claude = userClaudeMcpConfigPath();
25238
- if ((0, import_node_fs49.existsSync)(claude)) {
25657
+ if ((0, import_node_fs50.existsSync)(claude)) {
25239
25658
  writeMergedMcpServersJson(claude, launch);
25240
25659
  return { cursor, claude };
25241
25660
  }
@@ -25246,7 +25665,7 @@ async function registerPackagedUserMcpClients() {
25246
25665
  init_workspaces();
25247
25666
 
25248
25667
  // src/slack/oauth.ts
25249
- var import_node_crypto13 = require("crypto");
25668
+ var import_node_crypto14 = require("crypto");
25250
25669
  init_app_settings();
25251
25670
  init_workspaces();
25252
25671
 
@@ -25470,7 +25889,7 @@ async function startSlackOAuth(opts) {
25470
25889
  throw new SlackOAuthCancelledError();
25471
25890
  }
25472
25891
  const { clientId } = slackOAuthCredentials();
25473
- const state = (0, import_node_crypto13.randomBytes)(16).toString("hex");
25892
+ const state = (0, import_node_crypto14.randomBytes)(16).toString("hex");
25474
25893
  const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
25475
25894
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
25476
25895
  const pollIntervalMs = opts?.pollIntervalMs ?? 400;
@@ -25752,7 +26171,7 @@ init_workspaces();
25752
26171
  init_reply_target();
25753
26172
 
25754
26173
  // src/slack/relay-protocol.ts
25755
- var import_node_crypto14 = require("crypto");
26174
+ var import_node_crypto15 = require("crypto");
25756
26175
  var SLACK_RELAY_PING_INTERVAL_MS = 2e4;
25757
26176
  var SLACK_RELAY_PONG_TIMEOUT_MS = 15e3;
25758
26177
  function slackRelaySessionKey(teamId, userId, deviceId) {
@@ -25762,7 +26181,7 @@ function slackRelayUserKey(teamId, userId) {
25762
26181
  return `${teamId.trim()}:${userId.trim()}`;
25763
26182
  }
25764
26183
  function newSlackRelayEventId() {
25765
- return (0, import_node_crypto14.randomBytes)(12).toString("hex");
26184
+ return (0, import_node_crypto15.randomBytes)(12).toString("hex");
25766
26185
  }
25767
26186
  function parseSlackRelayClientMessage(raw) {
25768
26187
  try {
@@ -26865,9 +27284,9 @@ var import_node_http3 = require("http");
26865
27284
  var import_ws3 = require("ws");
26866
27285
 
26867
27286
  // src/slack/relay-static.ts
26868
- var import_node_fs50 = require("fs");
27287
+ var import_node_fs51 = require("fs");
26869
27288
  var import_promises = require("fs/promises");
26870
- var import_node_path47 = __toESM(require("path"), 1);
27289
+ var import_node_path48 = __toESM(require("path"), 1);
26871
27290
  var TYPES = {
26872
27291
  ".css": "text/css; charset=utf-8",
26873
27292
  ".html": "text/html; charset=utf-8",
@@ -26898,9 +27317,9 @@ function resolveStaticPath(root, requestUrl) {
26898
27317
  return null;
26899
27318
  }
26900
27319
  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)) {
27320
+ const rootResolved = import_node_path48.default.resolve(root);
27321
+ const candidate = import_node_path48.default.resolve(rootResolved, `.${pathname}`);
27322
+ if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path48.default.sep)) {
26904
27323
  return null;
26905
27324
  }
26906
27325
  return candidate;
@@ -26914,7 +27333,7 @@ async function fileSize(file) {
26914
27333
  }
26915
27334
  }
26916
27335
  function sendFile(req, res, file, size) {
26917
- const ext = import_node_path47.default.extname(file).toLowerCase();
27336
+ const ext = import_node_path48.default.extname(file).toLowerCase();
26918
27337
  res.writeHead(200, {
26919
27338
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
26920
27339
  "Content-Length": size,
@@ -26924,7 +27343,7 @@ function sendFile(req, res, file, size) {
26924
27343
  res.end();
26925
27344
  return true;
26926
27345
  }
26927
- (0, import_node_fs50.createReadStream)(file).pipe(res);
27346
+ (0, import_node_fs51.createReadStream)(file).pipe(res);
26928
27347
  return true;
26929
27348
  }
26930
27349
  async function tryServeStatic(req, res, root) {
@@ -26933,7 +27352,7 @@ async function tryServeStatic(req, res, root) {
26933
27352
  if (!candidate) return false;
26934
27353
  const direct = await fileSize(candidate);
26935
27354
  if (direct != null) return sendFile(req, res, candidate, direct);
26936
- const asIndex = import_node_path47.default.join(candidate, "index.html");
27355
+ const asIndex = import_node_path48.default.join(candidate, "index.html");
26937
27356
  const indexSize = await fileSize(asIndex);
26938
27357
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
26939
27358
  return false;
@@ -27192,19 +27611,25 @@ init_outbound_watch();
27192
27611
  COORDINATOR_TOOL_PLAYBOOK,
27193
27612
  DEFAULT_ABLETIME_HOST,
27194
27613
  DEFAULT_WORKTREE_SORT,
27614
+ DETACHED_JOBS_DIR,
27195
27615
  FAMOUS_SOCCER_TEAMS,
27616
+ FOLLOW_UP_BEHAVIORS,
27196
27617
  GITHUB_GIT_AUTH_MODES,
27618
+ GITHUB_PR_BODY_MAX_CHARS,
27619
+ GITHUB_PR_BODY_SAFE_CHARS,
27197
27620
  GLOBAL_WORKSPACE_ID,
27198
27621
  HARNESS_ENV_KEYS,
27199
27622
  HOME_BOARD_CACHE_TTL_MS,
27200
27623
  ISSUE_SOURCE_LABELS,
27201
27624
  LEGACY_ATTACHMENTS_DIR,
27625
+ LEGACY_DETACHED_JOBS_DIR,
27202
27626
  LEGACY_PLAN_FILE_REL,
27203
27627
  LEGACY_REVIEW_REQUEST_PATH,
27204
27628
  LINEAR_OAUTH_CANCELLED,
27205
27629
  LINEAR_OAUTH_PORT,
27206
27630
  LINEAR_OAUTH_REDIRECT,
27207
27631
  LINEAR_OAUTH_SCOPES,
27632
+ LIVE_TURN_SPAWN_GRACE_MS,
27208
27633
  LONG_RUNNING_SKILL_COMMAND,
27209
27634
  LinearOAuthCancelledError,
27210
27635
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
@@ -27294,6 +27719,7 @@ init_outbound_watch();
27294
27719
  buildCodeRefAttachment,
27295
27720
  buildDiffCommentAttachment,
27296
27721
  buildForkTranscriptAttachment,
27722
+ buildLinearIssueFilter,
27297
27723
  buildPastedTextAttachment,
27298
27724
  buildPathRefAttachment,
27299
27725
  buildReviewRequestAttachment,
@@ -27311,6 +27737,7 @@ init_outbound_watch();
27311
27737
  checkoutPrStackLayer,
27312
27738
  childEnvWithAppSettings,
27313
27739
  claimDesktopHost,
27740
+ clampGithubPrBody,
27314
27741
  classifyWorktreeColumn,
27315
27742
  claudeAdapter,
27316
27743
  claudeChromeEnabled,
@@ -27415,6 +27842,7 @@ init_outbound_watch();
27415
27842
  fireSchedule,
27416
27843
  flattenTurnInput,
27417
27844
  flipLinearRelationType,
27845
+ followUpBehavior,
27418
27846
  forkChatTab,
27419
27847
  forkMessageSlice,
27420
27848
  forkThreadWorktree,
@@ -27493,6 +27921,7 @@ init_outbound_watch();
27493
27921
  ghRepoSelectArgs,
27494
27922
  git,
27495
27923
  githubAgentGitEnv,
27924
+ githubHttpsInsteadOfEntries,
27496
27925
  globalAgentCwd,
27497
27926
  groupHomeBoardWorktrees,
27498
27927
  handleSlackInbound,
@@ -27529,6 +27958,7 @@ init_outbound_watch();
27529
27958
  isDefaultishSourceRef,
27530
27959
  isDesktopHostAlive,
27531
27960
  isDirty,
27961
+ isGhPrBodyTooLongError,
27532
27962
  isGhRateLimitError,
27533
27963
  isGlobalRepoPath,
27534
27964
  isGlobalThread,
@@ -27536,6 +27966,7 @@ init_outbound_watch();
27536
27966
  isImageFilePath,
27537
27967
  isInPrStack,
27538
27968
  isInboundForThisDesktop,
27969
+ isInternalAgentStatusText,
27539
27970
  isIssueSourceConnected,
27540
27971
  isLinearConnected,
27541
27972
  isLinearOAuthCancelled,
@@ -27562,6 +27993,7 @@ init_outbound_watch();
27562
27993
  isThreadRecordFile,
27563
27994
  isWorkspaceScratchPath,
27564
27995
  issueAttachmentForAbleTimeTask,
27996
+ issueMatchesAssignee,
27565
27997
  issueSourceLabel,
27566
27998
  lastRequestOccupancy,
27567
27999
  latestPendingPlanQuestions,
@@ -27589,6 +28021,7 @@ init_outbound_watch();
27589
28021
  listLinearAssignedIssues,
27590
28022
  listLinearIssues,
27591
28023
  listLinearIssuesDirect,
28024
+ listLinearIssuesFiltered,
27592
28025
  listLinearTeams,
27593
28026
  listModelsForAgent,
27594
28027
  listOpencodeModels,