@sideboard-ai/core 0.1.89 → 0.1.92

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 (30) hide show
  1. package/dist/agents/cursor-runner.cjs +129 -14
  2. package/dist/agents/cursor-runner.js +4 -1
  3. package/dist/{agents-LMUFTGKF.js → agents-JXQ5QHDU.js} +4 -4
  4. package/dist/{agents-ODBP7J6E.js → agents-TUV4NH7S.js} +5 -5
  5. package/dist/{chunk-RJLBSYUO.js → chunk-35LKGGOC.js} +45 -77
  6. package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
  7. package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
  8. package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
  9. package/dist/{chunk-JE75QW2I.js → chunk-GJ2HJQIU.js} +236 -96
  10. package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
  11. package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
  12. package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
  13. package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
  14. package/dist/{chunk-OB6IRIFV.js → chunk-XH2GS2LO.js} +2 -2
  15. package/dist/{chunk-VZ2L4AEJ.js → chunk-XUWDLRAE.js} +2 -2
  16. package/dist/{coordinator-prompt-UK5LYFN5.js → coordinator-prompt-AKEY4WSO.js} +2 -2
  17. package/dist/{coordinator-prompt-CI5SHONJ.js → coordinator-prompt-OQOOD5ET.js} +2 -2
  18. package/dist/{global-workspace-2YZ2V4I5.js → global-workspace-3GNPQCLE.js} +3 -3
  19. package/dist/{global-workspace-JQQLPJM5.js → global-workspace-M3OMVDDH.js} +3 -3
  20. package/dist/index.cjs +941 -455
  21. package/dist/index.d.cts +77 -19
  22. package/dist/index.d.ts +77 -19
  23. package/dist/index.js +166 -42
  24. package/dist/mcp/run-stdio.cjs +815 -428
  25. package/dist/mcp/run-stdio.js +77 -40
  26. package/dist/{workspaces-YWCC3WV4.js → workspaces-ERZC7ULY.js} +4 -4
  27. package/dist/{workspaces-FDO5L4NI.js → workspaces-J4WG6UFR.js} +4 -4
  28. package/dist/{worktree-7YNSJ224.js → worktree-DA4BOV7G.js} +7 -1
  29. package/dist/{worktree-4555QBQ7.js → worktree-EO5QAGJU.js} +7 -1
  30. package/package.json +1 -1
@@ -858,17 +858,27 @@ function extractJsonErrorMessage(obj) {
858
858
  }
859
859
  return null;
860
860
  }
861
+ function isPinnedStderrLine(line) {
862
+ if (/^\s*at\s/.test(line)) return false;
863
+ return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:/i.test(
864
+ line
865
+ );
866
+ }
861
867
  function pushTurnStderr(tail, line, maxLines = 12) {
862
868
  const trimmed = line.trim();
863
869
  if (!trimmed) return;
864
870
  if (NODE_VERSION_FOOTER.test(trimmed)) return;
865
871
  if (/^reconnecting\.\.\./i.test(trimmed)) return;
866
872
  tail.push(trimmed);
867
- while (tail.length > maxLines) tail.shift();
873
+ while (tail.length > maxLines) {
874
+ const dropIdx = tail.findIndex((l) => !isPinnedStderrLine(l));
875
+ if (dropIdx === -1) tail.shift();
876
+ else tail.splice(dropIdx, 1);
877
+ }
868
878
  }
869
879
  function looksLikeMinifiedJsDump(line) {
870
880
  if (line.length < 200) return false;
871
- return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line);
881
+ return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line) || /findFilesWithRipgrep/.test(line) || /@cursor\/sdk\/dist\//.test(line);
872
882
  }
873
883
  function looksLikeNestedElectronCrash(line) {
874
884
  return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
@@ -883,7 +893,15 @@ function summarizeTurnStderr(tail, maxChars = 500) {
883
893
  const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
884
894
  if (cursorStartup) return clipStderr(cursorStartup, maxChars);
885
895
  if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
886
- const moduleMissing = [...tail].reverse().find((line) => /cannot find module/i.test(line));
896
+ if (tail.some(
897
+ (line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
898
+ )) {
899
+ return clipStderr(
900
+ "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.",
901
+ maxChars
902
+ );
903
+ }
904
+ const moduleMissing = [...tail].reverse().find((line) => /cannot find (?:package|module)/i.test(line));
887
905
  if (moduleMissing) return clipStderr(moduleMissing, maxChars);
888
906
  const useful = tail.filter((line) => !looksLikeMinifiedJsDump(line));
889
907
  if (useful.length === 0 && tail.some(looksLikeMinifiedJsDump)) {
@@ -902,7 +920,7 @@ function looksLikeAgentFailureMessage(text3) {
902
920
  if (!lower) return false;
903
921
  return /you've hit your|hit your (session|weekly|opus) limit|usage limit/.test(lower) || /credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded/.test(lower) || /invalid user api key|invalid api key|not logged in|not authenticated|unauthorized/.test(
904
922
  lower
905
- ) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower);
923
+ ) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower) || /\[resource_exhausted\]|resource_exhausted/.test(lower) || /findFilesWithRipgrep/.test(text3);
906
924
  }
907
925
  function fallbackTurnFailDetail(assistantText) {
908
926
  const t = assistantText.trim();
@@ -924,6 +942,9 @@ function humanizeAgentFailDetail(detail) {
924
942
  if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
925
943
  return `${raw} \u2014 wait a moment and retry.`;
926
944
  }
945
+ if (/\[resource_exhausted\]|resource_exhausted|findfileswithripgrep/.test(lower)) {
946
+ return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
947
+ }
927
948
  if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
928
949
  lower
929
950
  )) {
@@ -2880,42 +2901,124 @@ var init_app_settings = __esm({
2880
2901
  }
2881
2902
  });
2882
2903
 
2904
+ // src/git/github-agent-auth.ts
2905
+ function githubAgentAuthDir() {
2906
+ const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
2907
+ if (override) return override;
2908
+ return (0, import_node_path12.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
2909
+ }
2910
+ function githubCredentialStorePath() {
2911
+ return (0, import_node_path12.join)(githubAgentAuthDir(), "git-credentials");
2912
+ }
2913
+ function githubGhConfigDir() {
2914
+ return (0, import_node_path12.join)(githubAgentAuthDir(), "gh");
2915
+ }
2916
+ function writePrivateFile2(file, body) {
2917
+ (0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(file), { recursive: true, mode: 448 });
2918
+ try {
2919
+ (0, import_node_fs11.chmodSync)((0, import_node_path12.dirname)(file), 448);
2920
+ } catch {
2921
+ }
2922
+ (0, import_node_fs11.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
2923
+ try {
2924
+ (0, import_node_fs11.chmodSync)(file, 384);
2925
+ } catch {
2926
+ }
2927
+ }
2928
+ function gitCredentialStoreContents(token) {
2929
+ return `https://x-access-token:${encodeURIComponent(token)}@github.com
2930
+ `;
2931
+ }
2932
+ function ghHostsYml(token, user = "x-access-token") {
2933
+ const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
2934
+ return [
2935
+ "github.com:",
2936
+ " git_protocol: https",
2937
+ ` user: ${u}`,
2938
+ ` oauth_token: ${token}`,
2939
+ " users:",
2940
+ ` ${u}:`,
2941
+ ` oauth_token: ${token}`,
2942
+ ""
2943
+ ].join("\n");
2944
+ }
2945
+ function materializeGithubAgentAuth(token, user) {
2946
+ const trimmed = token.trim();
2947
+ if (!trimmed) return;
2948
+ const root = githubAgentAuthDir();
2949
+ (0, import_node_fs11.mkdirSync)(root, { recursive: true, mode: 448 });
2950
+ try {
2951
+ (0, import_node_fs11.chmodSync)(root, 448);
2952
+ } catch {
2953
+ }
2954
+ writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
2955
+ const ghDir = githubGhConfigDir();
2956
+ (0, import_node_fs11.mkdirSync)(ghDir, { recursive: true, mode: 448 });
2957
+ writePrivateFile2((0, import_node_path12.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
2958
+ writePrivateFile2((0, import_node_path12.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
2959
+ }
2960
+ function githubAgentAuthReady() {
2961
+ return (0, import_node_fs11.existsSync)(githubCredentialStorePath()) && (0, import_node_fs11.existsSync)((0, import_node_path12.join)(githubGhConfigDir(), "hosts.yml"));
2962
+ }
2963
+ function githubCredentialHelperGitConfig() {
2964
+ const file = githubCredentialStorePath();
2965
+ return [
2966
+ { key: "credential.helper", value: "" },
2967
+ { key: "credential.helper", value: `store --file=${file}` }
2968
+ ];
2969
+ }
2970
+ function githubGhConfigEnv() {
2971
+ return {
2972
+ GH_CONFIG_DIR: githubGhConfigDir(),
2973
+ GH_PROMPT_DISABLED: "1"
2974
+ };
2975
+ }
2976
+ var import_node_fs11, import_node_os4, import_node_path12;
2977
+ var init_github_agent_auth = __esm({
2978
+ "src/git/github-agent-auth.ts"() {
2979
+ "use strict";
2980
+ import_node_fs11 = require("fs");
2981
+ import_node_os4 = require("os");
2982
+ import_node_path12 = require("path");
2983
+ }
2984
+ });
2985
+
2883
2986
  // src/agents/path.ts
2884
2987
  function prependPathDir(env, dir) {
2885
- if (!dir || !(0, import_node_fs11.existsSync)(dir)) return;
2988
+ if (!dir || !(0, import_node_fs12.existsSync)(dir)) return;
2886
2989
  const current = env.PATH ?? "";
2887
- const parts = current.split(import_node_path12.delimiter).filter(Boolean);
2990
+ const parts = current.split(import_node_path13.delimiter).filter(Boolean);
2888
2991
  if (parts.includes(dir)) {
2889
2992
  env.PATH = current;
2890
2993
  return;
2891
2994
  }
2892
- env.PATH = [dir, ...parts].join(import_node_path12.delimiter);
2995
+ env.PATH = [dir, ...parts].join(import_node_path13.delimiter);
2893
2996
  }
2894
- function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os4.homedir)()) {
2895
- return (0, import_node_path12.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
2997
+ function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os5.homedir)()) {
2998
+ return (0, import_node_path13.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
2896
2999
  }
2897
3000
  function isConductorBundledCli(filePath) {
2898
3001
  const p = (filePath ?? "").replace(/\\/g, "/");
2899
3002
  return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
2900
3003
  }
2901
3004
  function ensureAgentPath(env = process.env) {
2902
- const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
3005
+ const home = env.HOME || env.USERPROFILE || (0, import_node_os5.homedir)();
2903
3006
  const current = env.PATH ?? "";
2904
- const parts = current.split(import_node_path12.delimiter).filter(Boolean);
3007
+ const parts = current.split(import_node_path13.delimiter).filter(Boolean);
2905
3008
  const seen = new Set(parts);
2906
3009
  const extras = [
2907
- ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path12.join)(home, rel)),
3010
+ ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path13.join)(home, rel)),
2908
3011
  "/opt/homebrew/bin",
2909
3012
  "/usr/local/bin",
2910
3013
  // Keep after Homebrew/npm so a user-installed CLI still wins.
2911
3014
  conductorBundledBinDir(home)
2912
3015
  ];
2913
3016
  for (const dir of extras.reverse()) {
2914
- if (!dir || seen.has(dir) || !(0, import_node_fs11.existsSync)(dir)) continue;
3017
+ if (!dir || seen.has(dir) || !(0, import_node_fs12.existsSync)(dir)) continue;
2915
3018
  parts.unshift(dir);
2916
3019
  seen.add(dir);
2917
3020
  }
2918
- const next = parts.join(import_node_path12.delimiter);
3021
+ const next = parts.join(import_node_path13.delimiter);
2919
3022
  env.PATH = next;
2920
3023
  return next;
2921
3024
  }
@@ -2929,7 +3032,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
2929
3032
  stdio: ["ignore", "pipe", "ignore"]
2930
3033
  }).trim().split(/\r?\n/).find(Boolean);
2931
3034
  if (prefix) {
2932
- const binDir = process.platform === "win32" ? prefix : (0, import_node_path12.join)(prefix, "bin");
3035
+ const binDir = process.platform === "win32" ? prefix : (0, import_node_path13.join)(prefix, "bin");
2933
3036
  prependPathDir(env, binDir);
2934
3037
  }
2935
3038
  } catch {
@@ -2957,14 +3060,14 @@ function withExportedPath(command, pathValue) {
2957
3060
  if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
2958
3061
  return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
2959
3062
  }
2960
- var import_node_fs11, import_node_child_process2, import_node_os4, import_node_path12, EXTRA_BIN_DIRS;
3063
+ var import_node_fs12, import_node_child_process2, import_node_os5, import_node_path13, EXTRA_BIN_DIRS;
2961
3064
  var init_path = __esm({
2962
3065
  "src/agents/path.ts"() {
2963
3066
  "use strict";
2964
- import_node_fs11 = require("fs");
3067
+ import_node_fs12 = require("fs");
2965
3068
  import_node_child_process2 = require("child_process");
2966
- import_node_os4 = require("os");
2967
- import_node_path12 = require("path");
3069
+ import_node_os5 = require("os");
3070
+ import_node_path13 = require("path");
2968
3071
  EXTRA_BIN_DIRS = [
2969
3072
  ".local/bin",
2970
3073
  ".cargo/bin",
@@ -3089,42 +3192,43 @@ function appendIndexedGitConfig(existing, entries) {
3089
3192
  return out;
3090
3193
  }
3091
3194
  function githubAgentGitEnv(existing) {
3092
- return appendIndexedGitConfig(existing, HTTPS_REWRITE);
3093
- }
3094
- function githubHttpsBearerEnv(existing, token) {
3095
- const rewrite = githubAgentGitEnv(existing);
3096
- const header = appendIndexedGitConfig(
3097
- { ...existing, ...rewrite },
3098
- [
3099
- {
3100
- key: "http.https://github.com/.extraHeader",
3101
- value: `AUTHORIZATION: bearer ${token}`
3102
- }
3103
- ]
3104
- );
3105
- return { ...rewrite, ...header };
3195
+ const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
3196
+ return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
3106
3197
  }
3107
3198
  function applyGithubGitAuthEnv(existing, opts) {
3108
3199
  const out = { ...nonInteractiveGitProcessEnv() };
3200
+ const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
3201
+ if (token) materializeGithubAgentAuth(token);
3202
+ Object.assign(out, githubGhConfigEnv());
3109
3203
  if (opts.mode === "ssh") return out;
3110
- const existingToken = existing?.GH_TOKEN?.trim() || "";
3111
- const provided = existingToken ? "" : opts.token?.trim() || "";
3112
- const token = existingToken || provided;
3113
- Object.assign(
3114
- out,
3115
- token ? githubHttpsBearerEnv(existing, token) : githubAgentGitEnv(existing)
3116
- );
3117
- if (provided) out.GH_TOKEN = provided;
3204
+ Object.assign(out, githubAgentGitEnv(existing));
3118
3205
  return out;
3119
3206
  }
3207
+ function scrubGithubTokensFromChildEnv(env) {
3208
+ for (const key of GITHUB_CHILD_TOKEN_KEYS) {
3209
+ delete env[key];
3210
+ }
3211
+ }
3212
+ function mergeAgentGitAuthEnv(env, gitEnv) {
3213
+ Object.assign(env, gitEnv);
3214
+ scrubGithubTokensFromChildEnv(env);
3215
+ }
3120
3216
  async function resolveGithubAgentToken(mode, cwd) {
3121
- if (mode === "ssh") return null;
3122
- if (mode === "token") return getGithubPat();
3123
- try {
3124
- return await resolveGhAuthToken(cwd);
3125
- } catch {
3126
- return null;
3217
+ if (tokenMemo && tokenMemo.mode === mode && Date.now() - tokenMemo.at < TOKEN_TTL_MS) {
3218
+ return tokenMemo.value;
3219
+ }
3220
+ let value = null;
3221
+ if (mode === "token") {
3222
+ value = getGithubPat();
3223
+ } else {
3224
+ try {
3225
+ value = await resolveGhAuthToken(cwd);
3226
+ } catch {
3227
+ value = null;
3228
+ }
3127
3229
  }
3230
+ tokenMemo = { mode, value, at: Date.now() };
3231
+ return value;
3128
3232
  }
3129
3233
  async function resolveAgentGitAuthEnv(existing, opts) {
3130
3234
  let mode = "auto";
@@ -3146,7 +3250,40 @@ async function resolveAgentGitAuthEnv(existing, opts) {
3146
3250
  }
3147
3251
  return applyGithubGitAuthEnv(existing, { mode, token });
3148
3252
  }
3149
- function codexUnattendedGitConfigArgs(sandbox) {
3253
+ async function warmGithubAgentAuth(opts) {
3254
+ if (!opts?.force && githubAgentAuthReady()) return;
3255
+ await resolveAgentGitAuthEnv(void 0, opts);
3256
+ }
3257
+ function normalizeWritableRoot(raw) {
3258
+ const trimmed = raw.trim().replace(/\/+$/, "");
3259
+ return trimmed && (0, import_node_path14.isAbsolute)(trimmed) ? trimmed : null;
3260
+ }
3261
+ async function resolveCodexGitWritableRoots(cwd) {
3262
+ const roots = /* @__PURE__ */ new Set();
3263
+ const authDir = normalizeWritableRoot(githubAgentAuthDir());
3264
+ if (authDir) roots.add(authDir);
3265
+ try {
3266
+ const [gitDir, commonDir] = await Promise.all([
3267
+ git(["rev-parse", "--absolute-git-dir"], cwd, { reject: false, timeoutMs: 5e3 }),
3268
+ git(["rev-parse", "--path-format=absolute", "--git-common-dir"], cwd, {
3269
+ reject: false,
3270
+ timeoutMs: 5e3
3271
+ })
3272
+ ]);
3273
+ const gitDirPath = gitDir.exitCode === 0 ? normalizeWritableRoot(gitDir.stdout) : null;
3274
+ const commonPath = commonDir.exitCode === 0 ? normalizeWritableRoot(commonDir.stdout) : null;
3275
+ if (gitDirPath) roots.add(gitDirPath);
3276
+ if (commonPath) roots.add(commonPath);
3277
+ } catch {
3278
+ }
3279
+ return [...roots];
3280
+ }
3281
+ function codexSandboxWritableRootsArgs(roots) {
3282
+ const abs = [...new Set(roots.map(normalizeWritableRoot).filter(Boolean))];
3283
+ if (abs.length === 0) return [];
3284
+ return ["-c", `sandbox_workspace_write.writable_roots=${JSON.stringify(abs)}`];
3285
+ }
3286
+ function codexUnattendedGitConfigArgs(sandbox, opts) {
3150
3287
  const args = [
3151
3288
  "-c",
3152
3289
  'shell_environment_policy.inherit="all"',
@@ -3155,54 +3292,65 @@ function codexUnattendedGitConfigArgs(sandbox) {
3155
3292
  ];
3156
3293
  if (sandbox === "workspace-write") {
3157
3294
  args.push("-c", "sandbox_workspace_write.network_access=true");
3295
+ args.push(...codexSandboxWritableRootsArgs(opts?.writableRoots ?? []));
3158
3296
  }
3159
3297
  return args;
3160
3298
  }
3161
3299
  function formatGitAuthModeDirective(mode) {
3300
+ const shared = [
3301
+ "- `git` and `gh` already authenticate in this process. Do not look for tokens in the environment, paste credentials into commands, or switch remotes to SSH.",
3302
+ "- Do not set GitHub token environment variables, pass `--with-token`, or run `gh auth login` from this turn.",
3303
+ "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below.",
3304
+ "- If git/gh fail with auth errors, tell the user to run `gh auth login` on this Mac (or set a PAT in Account \u2192 GitHub). Do not wait for a Keychain dialog."
3305
+ ];
3162
3306
  switch (mode) {
3163
3307
  case "gh":
3164
3308
  return [
3165
3309
  "Git authentication (Account \u2192 GitHub mode: gh CLI):",
3166
3310
  "- This process rewrites `git@github.com:` and `ssh://git@github.com/` to HTTPS.",
3167
- "- `GH_TOKEN` is injected from `gh auth token` (no macOS Keychain prompts). Do not switch remotes to SSH.",
3168
- "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
3311
+ ...shared
3169
3312
  ].join("\n");
3170
3313
  case "ssh":
3171
3314
  return [
3172
3315
  "Git authentication (Account \u2192 GitHub mode: SSH):",
3173
3316
  "- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
3174
3317
  "- 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 Account \u2192 GitHub to Auto / gh CLI \u2014 do not rewrite remotes yourself.",
3175
- "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below (API still uses `gh`)."
3318
+ "- `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.",
3319
+ "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
3176
3320
  ].join("\n");
3177
3321
  case "token":
3178
3322
  return [
3179
3323
  "Git authentication (Account \u2192 GitHub mode: personal access token):",
3180
3324
  "- This process rewrites GitHub SSH remotes to HTTPS.",
3181
- "- `GH_TOKEN` is set in the environment. Use HTTPS git and `gh`; do not paste the token into commands or chat.",
3182
- "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
3325
+ ...shared
3183
3326
  ].join("\n");
3184
3327
  case "auto":
3185
3328
  default:
3186
3329
  return [
3187
3330
  "Git authentication (Account \u2192 GitHub mode: auto):",
3188
- "- This process rewrites GitHub SSH remotes to HTTPS and authenticates with `GH_TOKEN` from `gh` so git/ssh never prompt the macOS Keychain (required for unattended orchestrator turns).",
3189
- "- Do not switch remotes to SSH. Push with `git push -u origin HEAD`.",
3190
- "- If HTTPS auth fails, tell the user to run `gh auth login` on this Mac or set Account \u2192 GitHub to a PAT \u2014 do not wait for a Keychain dialog."
3331
+ "- This process rewrites GitHub SSH remotes to HTTPS so git/ssh never prompt the macOS Keychain (required for unattended orchestrator turns).",
3332
+ ...shared
3191
3333
  ].join("\n");
3192
3334
  }
3193
3335
  }
3194
- var HTTPS_REWRITE;
3336
+ var import_node_path14, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
3195
3337
  var init_git_auth_mode = __esm({
3196
3338
  "src/git/git-auth-mode.ts"() {
3197
3339
  "use strict";
3340
+ import_node_path14 = require("path");
3198
3341
  init_app_settings();
3342
+ init_github_agent_auth();
3199
3343
  init_run();
3200
3344
  HTTPS_REWRITE = [
3201
3345
  { key: "url.https://github.com/.insteadOf", value: "git@github.com:" },
3202
- { key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" },
3203
- // Empty helper disables ~/.gitconfig osxkeychain so GUI agents cannot pop
3204
- // "git-credential-osxkeychain wants to use the keychain".
3205
- { key: "credential.helper", value: "" }
3346
+ { key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
3347
+ ];
3348
+ TOKEN_TTL_MS = 12 * 60 * 60 * 1e3;
3349
+ tokenMemo = null;
3350
+ GITHUB_CHILD_TOKEN_KEYS = [
3351
+ "GH_TOKEN",
3352
+ "GITHUB_TOKEN",
3353
+ "GH_ENTERPRISE_TOKEN"
3206
3354
  ];
3207
3355
  }
3208
3356
  });
@@ -3535,10 +3683,12 @@ __export(worktree_exports, {
3535
3683
  getPr: () => getPr,
3536
3684
  getPrChecks: () => getPrChecks,
3537
3685
  getPrDetails: () => getPrDetails,
3686
+ getPrForHeadBranch: () => getPrForHeadBranch,
3538
3687
  getPrMeta: () => getPrMeta,
3539
3688
  ghHeadRef: () => ghHeadRef,
3540
3689
  ghRepoSelectArgs: () => ghRepoSelectArgs,
3541
3690
  githubAgentGitEnv: () => githubAgentGitEnv,
3691
+ isDefaultishSourceRef: () => isDefaultishSourceRef,
3542
3692
  isDirty: () => isDirty,
3543
3693
  isPlaceholderBranch: () => isPlaceholderBranch,
3544
3694
  isSideboardScratchPath: () => isSideboardScratchPath,
@@ -3556,6 +3706,7 @@ __export(worktree_exports, {
3556
3706
  resolveDiffBaseRef: () => resolveDiffBaseRef,
3557
3707
  resolveGithubRepoSlug: () => resolveGithubRepoSlug,
3558
3708
  resolvePrSelector: () => resolvePrSelector,
3709
+ resolvePrSelectors: () => resolvePrSelectors,
3559
3710
  resolveRepoRoot: () => resolveRepoRoot,
3560
3711
  resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
3561
3712
  slugify: () => slugify,
@@ -3664,7 +3815,7 @@ async function originGhRepoEnv(cwd, opts) {
3664
3815
  await ensureGhPreferOrigin(cwd);
3665
3816
  const slug = await resolveGithubRepoSlug(cwd);
3666
3817
  const mode = opts?.mode ?? getGithubGitAuthMode();
3667
- const token = mode === "token" ? getGithubPat() : mode === "ssh" ? null : await resolveGhAuthToken(cwd);
3818
+ const token = await resolveGithubAgentToken(mode, cwd);
3668
3819
  return {
3669
3820
  ...applyGithubGitAuthEnv(opts?.env, { mode, token }),
3670
3821
  ...slug ? { GH_REPO: slug } : {}
@@ -3804,13 +3955,78 @@ async function getPr(repoPath, number) {
3804
3955
  if (exitCode !== 0 || !stdout.trim()) return null;
3805
3956
  return JSON.parse(stdout);
3806
3957
  }
3807
- function resolvePrSelector(thread) {
3808
- if (thread.prUrl?.trim()) return thread.prUrl.trim();
3958
+ function normalizeGitBranchName(ref) {
3959
+ return ref.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
3960
+ }
3961
+ function isDefaultishSourceRef(ref) {
3962
+ const n = normalizeGitBranchName(ref ?? "").toLowerCase();
3963
+ return !n || n === "head" || n === "default" || n === "main" || n === "master" || n === "develop" || n === "trunk";
3964
+ }
3965
+ function resolvePrSelectors(thread) {
3966
+ const out = [];
3967
+ const push = (value) => {
3968
+ const v = value?.trim();
3969
+ if (!v || out.includes(v)) return;
3970
+ out.push(v);
3971
+ };
3972
+ push(thread.prUrl);
3809
3973
  if (thread.sourceType === "pr" && thread.sourceRef?.trim()) {
3810
- return thread.sourceRef.replace(/^#/, "").trim();
3974
+ push(thread.sourceRef.replace(/^#/, "").trim());
3975
+ }
3976
+ push(thread.branchName);
3977
+ if (thread.sourceType === "branch") {
3978
+ const source = normalizeGitBranchName(thread.sourceRef ?? "");
3979
+ if (source && !isDefaultishSourceRef(source) && source !== thread.branchName?.trim()) {
3980
+ push(source);
3981
+ }
3982
+ }
3983
+ return out;
3984
+ }
3985
+ function resolvePrSelector(thread) {
3986
+ return resolvePrSelectors(thread)[0] ?? null;
3987
+ }
3988
+ async function getPrForHeadBranch(repoPath, branch) {
3989
+ const head = normalizeGitBranchName(branch);
3990
+ if (!head || isDefaultishSourceRef(head)) return null;
3991
+ const slug = await resolveGithubRepoSlug(repoPath);
3992
+ const viewArgs = [
3993
+ "pr",
3994
+ "view",
3995
+ head,
3996
+ "--json",
3997
+ "number,title,headRefName,url,isCrossRepository"
3998
+ ];
3999
+ if (slug) viewArgs.push("--repo", slug);
4000
+ const viewed = await gh(viewArgs, repoPath, { reject: false });
4001
+ if (viewed.exitCode === 0 && viewed.stdout.trim()) {
4002
+ try {
4003
+ return JSON.parse(viewed.stdout);
4004
+ } catch {
4005
+ return null;
4006
+ }
4007
+ }
4008
+ const listHead = slug ? ghHeadRef(slug, head) : head;
4009
+ const listArgs = [
4010
+ "pr",
4011
+ "list",
4012
+ "--head",
4013
+ listHead,
4014
+ "--json",
4015
+ "number,title,headRefName,url,isCrossRepository",
4016
+ "--limit",
4017
+ "1",
4018
+ "--state",
4019
+ "open"
4020
+ ];
4021
+ if (slug) listArgs.push("--repo", slug);
4022
+ const listed = await gh(listArgs, repoPath, { reject: false });
4023
+ if (listed.exitCode !== 0 || !listed.stdout.trim()) return null;
4024
+ try {
4025
+ const rows = JSON.parse(listed.stdout);
4026
+ return rows[0] ?? null;
4027
+ } catch {
4028
+ return null;
3811
4029
  }
3812
- if (thread.branchName?.trim()) return thread.branchName.trim();
3813
- return null;
3814
4030
  }
3815
4031
  function normalizeGhTime(value) {
3816
4032
  if (typeof value !== "string" || !value.trim()) return null;
@@ -4136,7 +4352,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
4136
4352
  const label = opts?.ghAuth ? `${remote} (gh auth)` : remote;
4137
4353
  const gitOpts = { reject: false };
4138
4354
  if (opts?.ghAuth) {
4139
- const token = await resolveGhAuthToken(repoPath);
4355
+ const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
4140
4356
  if (!token) {
4141
4357
  errors.push(`${label}: gh auth token unavailable`);
4142
4358
  return false;
@@ -4187,7 +4403,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
4187
4403
  const ensureOid = async (remote, opts) => {
4188
4404
  const gitOpts = { reject: false };
4189
4405
  if (opts?.ghAuth) {
4190
- const token = await resolveGhAuthToken(repoPath);
4406
+ const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
4191
4407
  if (!token) return false;
4192
4408
  gitOpts.env = { GIT_TERMINAL_PROMPT: "0" };
4193
4409
  gitOpts.config = {
@@ -4255,8 +4471,8 @@ function isLocalPrFetchBranch(ref) {
4255
4471
  }
4256
4472
  async function createThreadWorktree(opts) {
4257
4473
  let branchName = `thread/${opts.slug}`;
4258
- const worktreePath = (0, import_node_path13.join)(worktreesRoot(opts.repoPath), opts.slug);
4259
- if ((0, import_node_fs12.existsSync)(worktreePath)) {
4474
+ const worktreePath = (0, import_node_path15.join)(worktreesRoot(opts.repoPath), opts.slug);
4475
+ if ((0, import_node_fs13.existsSync)(worktreePath)) {
4260
4476
  throw new Error(`Worktree already exists at ${worktreePath}`);
4261
4477
  }
4262
4478
  await ensureGhPreferOrigin(opts.repoPath);
@@ -4325,8 +4541,8 @@ ${add.stdout}`;
4325
4541
  async function createExistingBranchWorktree(opts) {
4326
4542
  const branchName = opts.branchName.trim();
4327
4543
  if (!branchName) throw new Error("branch name required");
4328
- const worktreePath = (0, import_node_path13.join)(worktreesRoot(opts.repoPath), opts.slug);
4329
- if ((0, import_node_fs12.existsSync)(worktreePath)) {
4544
+ const worktreePath = (0, import_node_path15.join)(worktreesRoot(opts.repoPath), opts.slug);
4545
+ if ((0, import_node_fs13.existsSync)(worktreePath)) {
4330
4546
  throw new Error(`Worktree already exists at ${worktreePath}`);
4331
4547
  }
4332
4548
  await ensureGhPreferOrigin(opts.repoPath);
@@ -4437,7 +4653,7 @@ async function pushBranch(worktreePath, branchName) {
4437
4653
  if (ssh.exitCode === 0) return;
4438
4654
  const sshErr = (ssh.stderr || ssh.stdout).trim();
4439
4655
  const slug = await resolveGithubRepoSlug(worktreePath);
4440
- const token = await resolveGhAuthToken(worktreePath);
4656
+ const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
4441
4657
  if (!slug || !token) {
4442
4658
  throw new Error(
4443
4659
  sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
@@ -4614,10 +4830,10 @@ function sameRepoPath(a, b) {
4614
4830
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
4615
4831
  }
4616
4832
  function listLocalThreadBranchSlugs(repoPath) {
4617
- const refsDir = (0, import_node_path13.join)(repoPath, ".git", "refs", "heads", "thread");
4618
- if (!(0, import_node_fs12.existsSync)(refsDir)) return [];
4833
+ const refsDir = (0, import_node_path15.join)(repoPath, ".git", "refs", "heads", "thread");
4834
+ if (!(0, import_node_fs13.existsSync)(refsDir)) return [];
4619
4835
  try {
4620
- return (0, import_node_fs12.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
4836
+ return (0, import_node_fs13.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
4621
4837
  } catch {
4622
4838
  return [];
4623
4839
  }
@@ -4625,8 +4841,8 @@ function listLocalThreadBranchSlugs(repoPath) {
4625
4841
  function collectTakenTeamSlugs(repoPath) {
4626
4842
  const taken = /* @__PURE__ */ new Set();
4627
4843
  const root = worktreesRoot(repoPath);
4628
- if ((0, import_node_fs12.existsSync)(root)) {
4629
- for (const entry of (0, import_node_fs12.readdirSync)(root, { withFileTypes: true })) {
4844
+ if ((0, import_node_fs13.existsSync)(root)) {
4845
+ for (const entry of (0, import_node_fs13.readdirSync)(root, { withFileTypes: true })) {
4630
4846
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
4631
4847
  taken.add(normalizeTakenSlug(entry.name));
4632
4848
  }
@@ -4647,18 +4863,18 @@ function allocateTeamSlug(repoPath) {
4647
4863
  const taken = collectTakenTeamSlugs(repoPath);
4648
4864
  for (let attempt = 0; attempt < 32; attempt++) {
4649
4865
  const team = allocateTeamName(taken);
4650
- const path = (0, import_node_path13.join)(worktreesRoot(repoPath), team.slug);
4651
- if (!(0, import_node_fs12.existsSync)(path)) return team;
4866
+ const path = (0, import_node_path15.join)(worktreesRoot(repoPath), team.slug);
4867
+ if (!(0, import_node_fs13.existsSync)(path)) return team;
4652
4868
  taken.add(team.slug);
4653
4869
  }
4654
4870
  throw new Error("No available soccer team worktree directories left");
4655
4871
  }
4656
- var import_node_fs12, import_node_path13;
4872
+ var import_node_fs13, import_node_path15;
4657
4873
  var init_worktree = __esm({
4658
4874
  "src/git/worktree.ts"() {
4659
4875
  "use strict";
4660
- import_node_fs12 = require("fs");
4661
- import_node_path13 = require("path");
4876
+ import_node_fs13 = require("fs");
4877
+ import_node_path15 = require("path");
4662
4878
  init_paths();
4663
4879
  init_thread_store();
4664
4880
  init_teams();
@@ -4800,7 +5016,7 @@ function coordinatorTurnReminder(opts) {
4800
5016
  function ensureGlobalCoordinatorCwd(opts) {
4801
5017
  const dir = globalAgentCwd();
4802
5018
  try {
4803
- (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
5019
+ (0, import_node_fs14.mkdirSync)(dir, { recursive: true });
4804
5020
  } catch {
4805
5021
  return dir;
4806
5022
  }
@@ -4808,7 +5024,7 @@ function ensureGlobalCoordinatorCwd(opts) {
4808
5024
  let orchId = opts?.orchestratorThreadId?.trim() || "";
4809
5025
  if (!orchId) {
4810
5026
  try {
4811
- const existing = (0, import_node_fs13.readFileSync)((0, import_node_path14.join)(dir, "AGENTS.md"), "utf8");
5027
+ const existing = (0, import_node_fs14.readFileSync)((0, import_node_path16.join)(dir, "AGENTS.md"), "utf8");
4812
5028
  const m = existing.match(
4813
5029
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
4814
5030
  );
@@ -4850,9 +5066,9 @@ function ensureGlobalCoordinatorCwd(opts) {
4850
5066
  "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."
4851
5067
  ].join("\n");
4852
5068
  try {
4853
- (0, import_node_fs13.writeFileSync)((0, import_node_path14.join)(dir, "CLAUDE.md"), `${body}
5069
+ (0, import_node_fs14.writeFileSync)((0, import_node_path16.join)(dir, "CLAUDE.md"), `${body}
4854
5070
  `, "utf8");
4855
- (0, import_node_fs13.writeFileSync)((0, import_node_path14.join)(dir, "AGENTS.md"), `${body}
5071
+ (0, import_node_fs14.writeFileSync)((0, import_node_path16.join)(dir, "AGENTS.md"), `${body}
4856
5072
  `, "utf8");
4857
5073
  } catch {
4858
5074
  }
@@ -4884,12 +5100,12 @@ function coordinatorSystemPrompt(opts) {
4884
5100
  formatWorkspaceInventory(opts.workspaces)
4885
5101
  ].join("\n");
4886
5102
  }
4887
- var import_node_fs13, import_node_path14, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
5103
+ var import_node_fs14, import_node_path16, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
4888
5104
  var init_coordinator_prompt = __esm({
4889
5105
  "src/orchestrator/coordinator-prompt.ts"() {
4890
5106
  "use strict";
4891
- import_node_fs13 = require("fs");
4892
- import_node_path14 = require("path");
5107
+ import_node_fs14 = require("fs");
5108
+ import_node_path16 = require("path");
4893
5109
  init_worktree();
4894
5110
  init_app_settings();
4895
5111
  init_paths();
@@ -4905,7 +5121,7 @@ var init_coordinator_prompt = __esm({
4905
5121
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
4906
5122
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
4907
5123
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
4908
- "- ask_user \u2014 multiple-choice questions in the composer (any mode, not only Plan). Explain options in chat first, include a description on every option, then wait for answers.",
5124
+ "- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
4909
5125
  "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
4910
5126
  "Workspaces:",
4911
5127
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
@@ -5187,32 +5403,32 @@ var init_global_workspace = __esm({
5187
5403
 
5188
5404
  // src/brightsy/config.ts
5189
5405
  function brightsyConfigPath() {
5190
- return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".brightsy", "config.json");
5406
+ return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
5191
5407
  }
5192
5408
  function loadBrightsyConfig() {
5193
5409
  const path = brightsyConfigPath();
5194
- if (!(0, import_node_fs14.existsSync)(path)) {
5410
+ if (!(0, import_node_fs15.existsSync)(path)) {
5195
5411
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
5196
5412
  }
5197
- const raw = JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8"));
5413
+ const raw = JSON.parse((0, import_node_fs15.readFileSync)(path, "utf8"));
5198
5414
  if (!raw.access_token || !raw.account_id) {
5199
5415
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
5200
5416
  }
5201
5417
  return raw;
5202
5418
  }
5203
5419
  function saveBrightsyConfig(cfg) {
5204
- (0, import_node_fs14.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
5420
+ (0, import_node_fs15.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
5205
5421
  `, {
5206
5422
  mode: 384
5207
5423
  });
5208
5424
  }
5209
- var import_node_fs14, import_node_os5, import_node_path15;
5425
+ var import_node_fs15, import_node_os6, import_node_path17;
5210
5426
  var init_config = __esm({
5211
5427
  "src/brightsy/config.ts"() {
5212
5428
  "use strict";
5213
- import_node_fs14 = require("fs");
5214
- import_node_os5 = require("os");
5215
- import_node_path15 = require("path");
5429
+ import_node_fs15 = require("fs");
5430
+ import_node_os6 = require("os");
5431
+ import_node_path17 = require("path");
5216
5432
  }
5217
5433
  });
5218
5434
 
@@ -5227,22 +5443,22 @@ var init_accounts = __esm({
5227
5443
 
5228
5444
  // src/brightsy/connected-teams.ts
5229
5445
  function storePath4() {
5230
- return (0, import_node_path16.join)(appDataDir(), "brightsy-teams.json");
5446
+ return (0, import_node_path18.join)(appDataDir(), "brightsy-teams.json");
5231
5447
  }
5232
5448
  function readStore4() {
5233
5449
  const path = storePath4();
5234
- if (!(0, import_node_fs15.existsSync)(path)) return [];
5450
+ if (!(0, import_node_fs16.existsSync)(path)) return [];
5235
5451
  try {
5236
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(path, "utf8"));
5452
+ const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
5237
5453
  return Array.isArray(parsed.teams) ? parsed.teams : [];
5238
5454
  } catch {
5239
5455
  return [];
5240
5456
  }
5241
5457
  }
5242
5458
  function writeStore2(teams) {
5243
- (0, import_node_fs15.mkdirSync)(appDataDir(), { recursive: true });
5459
+ (0, import_node_fs16.mkdirSync)(appDataDir(), { recursive: true });
5244
5460
  const path = storePath4();
5245
- (0, import_node_fs15.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
5461
+ (0, import_node_fs16.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
5246
5462
  `, {
5247
5463
  mode: 384
5248
5464
  });
@@ -5354,12 +5570,12 @@ function brightsyMcpServerName(slug) {
5354
5570
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
5355
5571
  return `brightsy_${cleaned || "team"}`;
5356
5572
  }
5357
- var import_node_fs15, import_node_path16;
5573
+ var import_node_fs16, import_node_path18;
5358
5574
  var init_connected_teams = __esm({
5359
5575
  "src/brightsy/connected-teams.ts"() {
5360
5576
  "use strict";
5361
- import_node_fs15 = require("fs");
5362
- import_node_path16 = require("path");
5577
+ import_node_fs16 = require("fs");
5578
+ import_node_path18 = require("path");
5363
5579
  init_paths();
5364
5580
  init_accounts();
5365
5581
  init_config();
@@ -5686,11 +5902,11 @@ async function syncCliForTarget(accountId) {
5686
5902
  }
5687
5903
  applyConnectedTeamToCli(team);
5688
5904
  }
5689
- var import_node_fs16, brightsyAdapter;
5905
+ var import_node_fs17, brightsyAdapter;
5690
5906
  var init_brightsy = __esm({
5691
5907
  "src/agents/brightsy.ts"() {
5692
5908
  "use strict";
5693
- import_node_fs16 = require("fs");
5909
+ import_node_fs17 = require("fs");
5694
5910
  init_run();
5695
5911
  init_connected_teams();
5696
5912
  init_config();
@@ -5705,7 +5921,7 @@ var init_brightsy = __esm({
5705
5921
  async detect() {
5706
5922
  const brightsy = resolveAgentExecutable("brightsy");
5707
5923
  if (brightsy !== "brightsy") {
5708
- if (!(0, import_node_fs16.existsSync)(brightsy)) {
5924
+ if (!(0, import_node_fs17.existsSync)(brightsy)) {
5709
5925
  return {
5710
5926
  agent: "brightsy",
5711
5927
  installed: false,
@@ -5833,13 +6049,38 @@ var init_profile = __esm({
5833
6049
 
5834
6050
  // src/agents/node-launch.ts
5835
6051
  function isAsarPath(filePath) {
6052
+ if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
5836
6053
  return /\.asar([/\\]|$)/.test(filePath);
5837
6054
  }
6055
+ function unpackedAsarPath(filePath) {
6056
+ if (!isAsarPath(filePath)) return null;
6057
+ const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
6058
+ if (unpacked === filePath) return null;
6059
+ return (0, import_node_fs18.existsSync)(unpacked) ? unpacked : null;
6060
+ }
6061
+ function nodeReadableScriptPath(scriptPath) {
6062
+ return unpackedAsarPath(scriptPath) ?? scriptPath;
6063
+ }
6064
+ async function findSystemNode() {
6065
+ const whichNode = await run("which", ["node"], { reject: false });
6066
+ const fromWhich = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : "";
6067
+ if (fromWhich && !isElectronLikeCommand(fromWhich)) return fromWhich;
6068
+ const fallbacks = [
6069
+ ...WELL_KNOWN_NODE_BINS,
6070
+ (0, import_node_path19.join)((0, import_node_os7.homedir)(), ".local/share/fnm/aliases/default/bin/node"),
6071
+ (0, import_node_path19.join)((0, import_node_os7.homedir)(), ".nvm/current/bin/node")
6072
+ ];
6073
+ for (const bin of fallbacks) {
6074
+ if ((0, import_node_fs18.existsSync)(bin) && !isElectronLikeCommand(bin)) return bin;
6075
+ }
6076
+ return null;
6077
+ }
5838
6078
  function applyNodeLaunch(launch, args) {
6079
+ const readableArgs = args.map(nodeReadableScriptPath);
5839
6080
  if (!launch.env.ELECTRON_RUN_AS_NODE) {
5840
- return { file: launch.file, args, env: launch.env };
6081
+ return { file: launch.file, args: readableArgs, env: launch.env };
5841
6082
  }
5842
- const wrapped = wrapElectronAsNodeLaunch(launch.file, args);
6083
+ const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
5843
6084
  if (process.platform === "win32") {
5844
6085
  return { file: wrapped.file, args: wrapped.args, env: launch.env };
5845
6086
  }
@@ -5848,27 +6089,73 @@ function applyNodeLaunch(launch, args) {
5848
6089
  return { file: wrapped.file, args: wrapped.args, env };
5849
6090
  }
5850
6091
  async function resolveNodeLaunch(scriptPath) {
5851
- if (isAsarPath(scriptPath)) {
5852
- return {
5853
- file: process.execPath,
5854
- env: { ELECTRON_RUN_AS_NODE: "1" }
5855
- };
5856
- }
5857
- const whichNode = await run("which", ["node"], { reject: false });
5858
- const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
5859
- if (nodeBin) {
5860
- return { file: nodeBin, env: {} };
6092
+ const script = nodeReadableScriptPath(scriptPath);
6093
+ if (!isAsarPath(script)) {
6094
+ const nodeBin = await findSystemNode();
6095
+ if (nodeBin) {
6096
+ return { file: nodeBin, env: {} };
6097
+ }
5861
6098
  }
5862
6099
  return {
5863
6100
  file: process.execPath,
5864
6101
  env: { ELECTRON_RUN_AS_NODE: "1" }
5865
6102
  };
5866
6103
  }
6104
+ var import_node_fs18, import_node_os7, import_node_path19, WELL_KNOWN_NODE_BINS;
5867
6105
  var init_node_launch = __esm({
5868
6106
  "src/agents/node-launch.ts"() {
5869
6107
  "use strict";
6108
+ import_node_fs18 = require("fs");
6109
+ import_node_os7 = require("os");
6110
+ import_node_path19 = require("path");
5870
6111
  init_nested_electron_env();
5871
6112
  init_run();
6113
+ WELL_KNOWN_NODE_BINS = [
6114
+ "/opt/homebrew/bin/node",
6115
+ "/usr/local/bin/node"
6116
+ ];
6117
+ }
6118
+ });
6119
+
6120
+ // src/agents/packaged-runtime.ts
6121
+ function electronResourcesPath() {
6122
+ const resources = process.resourcesPath;
6123
+ if (typeof resources !== "string" || !resources) return null;
6124
+ return resources;
6125
+ }
6126
+ function packagedCursorRuntimeDir() {
6127
+ const resources = electronResourcesPath();
6128
+ if (!resources) return null;
6129
+ const dir = (0, import_node_path20.join)(resources, "cursor-runtime");
6130
+ if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
6131
+ return dir;
6132
+ }
6133
+ function packagedCursorRunnerPath() {
6134
+ const dir = packagedCursorRuntimeDir();
6135
+ return dir ? (0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
6136
+ }
6137
+ function packagedMcpDir() {
6138
+ const resources = electronResourcesPath();
6139
+ if (!resources) return null;
6140
+ const dir = (0, import_node_path20.join)(resources, "sideboard-mcp");
6141
+ if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
6142
+ return dir;
6143
+ }
6144
+ function packagedMcpStdioPath() {
6145
+ const dir = packagedMcpDir();
6146
+ return dir ? (0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
6147
+ }
6148
+ function packagedCursorRipgrepCandidate(platformPkg, binName) {
6149
+ const dir = packagedCursorRuntimeDir();
6150
+ if (!dir) return null;
6151
+ return (0, import_node_path20.join)(dir, "node_modules", platformPkg, "bin", binName);
6152
+ }
6153
+ var import_node_fs19, import_node_path20;
6154
+ var init_packaged_runtime = __esm({
6155
+ "src/agents/packaged-runtime.ts"() {
6156
+ "use strict";
6157
+ import_node_fs19 = require("fs");
6158
+ import_node_path20 = require("path");
5872
6159
  }
5873
6160
  });
5874
6161
 
@@ -5955,35 +6242,37 @@ function corePackageDir() {
5955
6242
  try {
5956
6243
  const url = import_meta.url;
5957
6244
  if (typeof url === "string" && url.length > 0) {
5958
- return (0, import_node_path17.dirname)((0, import_node_url.fileURLToPath)(url));
6245
+ return (0, import_node_path21.dirname)((0, import_node_url.fileURLToPath)(url));
5959
6246
  }
5960
6247
  } catch {
5961
6248
  }
5962
6249
  try {
5963
- const req = (0, import_node_module.createRequire)((0, import_node_path17.join)(process.cwd(), "package.json"));
5964
- return (0, import_node_path17.dirname)(req.resolve("@sideboard-ai/core"));
6250
+ const req = (0, import_node_module.createRequire)((0, import_node_path21.join)(process.cwd(), "package.json"));
6251
+ return (0, import_node_path21.dirname)(req.resolve("@sideboard-ai/core"));
5965
6252
  } catch {
5966
6253
  return process.cwd();
5967
6254
  }
5968
6255
  }
5969
6256
  function findSideboardMcpJsEntry() {
5970
6257
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
5971
- if (override && (0, import_node_fs17.existsSync)(override)) return override;
6258
+ if (override && (0, import_node_fs20.existsSync)(override)) return override;
6259
+ const packaged = packagedMcpStdioPath();
6260
+ if (packaged) return packaged;
5972
6261
  let dir = corePackageDir();
5973
6262
  for (let i = 0; i < 10; i++) {
5974
6263
  const candidates = [
5975
- (0, import_node_path17.join)(dir, "mcp/run-stdio.js"),
5976
- (0, import_node_path17.join)(dir, "mcp/run-stdio.cjs"),
5977
- (0, import_node_path17.join)(dir, "dist/mcp/run-stdio.js"),
5978
- (0, import_node_path17.join)(dir, "dist/mcp/run-stdio.cjs"),
5979
- (0, import_node_path17.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
5980
- (0, import_node_path17.join)(dir, "packages/cli/dist/index.js"),
5981
- (0, import_node_path17.join)(dir, "cli/dist/index.js")
6264
+ (0, import_node_path21.join)(dir, "mcp/run-stdio.js"),
6265
+ (0, import_node_path21.join)(dir, "mcp/run-stdio.cjs"),
6266
+ (0, import_node_path21.join)(dir, "dist/mcp/run-stdio.js"),
6267
+ (0, import_node_path21.join)(dir, "dist/mcp/run-stdio.cjs"),
6268
+ (0, import_node_path21.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
6269
+ (0, import_node_path21.join)(dir, "packages/cli/dist/index.js"),
6270
+ (0, import_node_path21.join)(dir, "cli/dist/index.js")
5982
6271
  ];
5983
6272
  for (const p of candidates) {
5984
- if ((0, import_node_fs17.existsSync)(p)) return p;
6273
+ if ((0, import_node_fs20.existsSync)(p) && !isAsarPath(p)) return p;
5985
6274
  }
5986
- const parent = (0, import_node_path17.dirname)(dir);
6275
+ const parent = (0, import_node_path21.dirname)(dir);
5987
6276
  if (parent === dir) break;
5988
6277
  dir = parent;
5989
6278
  }
@@ -5995,12 +6284,14 @@ async function resolveSideboardMcpServer() {
5995
6284
  const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
5996
6285
  const scriptArgs = isCli ? [entry, "mcp"] : [entry];
5997
6286
  const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
5998
- return {
5999
- name: "sideboard",
6000
- command: launch.file,
6001
- args: launch.args,
6002
- ...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
6003
- };
6287
+ if (launch.file !== "/bin/sh" && !isElectronLikeCommand(launch.file)) {
6288
+ return {
6289
+ name: "sideboard",
6290
+ command: launch.file,
6291
+ args: launch.args,
6292
+ ...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
6293
+ };
6294
+ }
6004
6295
  }
6005
6296
  const which = await run("which", ["sideboard"], { reject: false });
6006
6297
  if (which.exitCode === 0 && which.stdout.trim()) {
@@ -6023,7 +6314,10 @@ async function buildInjectedMcpServers(opts) {
6023
6314
  sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
6024
6315
  }
6025
6316
  try {
6026
- Object.assign(sideboard.env, await resolveAgentGitAuthEnv(sideboard.env));
6317
+ mergeAgentGitAuthEnv(
6318
+ sideboard.env,
6319
+ await resolveAgentGitAuthEnv(sideboard.env)
6320
+ );
6027
6321
  } catch {
6028
6322
  }
6029
6323
  servers.push(sideboard);
@@ -6045,9 +6339,6 @@ async function buildInjectedMcpServers(opts) {
6045
6339
  }
6046
6340
  return servers;
6047
6341
  }
6048
- function shSingleQuote(value) {
6049
- return `'${value.replace(/'/g, `'\\''`)}'`;
6050
- }
6051
6342
  function cursorSafeMcpLaunch(command, args) {
6052
6343
  if (process.platform === "win32") {
6053
6344
  return args && args.length > 0 ? { command, args } : { command };
@@ -6055,31 +6346,13 @@ function cursorSafeMcpLaunch(command, args) {
6055
6346
  const unwrapped = unwrapStrippedElectronLaunch(command, args);
6056
6347
  const file = unwrapped?.file ?? command;
6057
6348
  const fileArgs = unwrapped?.args ?? args ?? [];
6058
- if (!isElectronLikeCommand(file)) {
6059
- return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
6060
- }
6061
- const dir = (0, import_node_path17.join)(appDataDir(), "mcp-launch");
6062
- (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
6063
- const wrap = (0, import_node_path17.join)(dir, "cursor-electron-as-node.sh");
6064
- const execLine = [file, ...fileArgs].map(shSingleQuote).join(" ");
6065
- (0, import_node_fs17.writeFileSync)(
6066
- wrap,
6067
- [
6068
- "#!/bin/sh",
6069
- "vars=`printenv | awk -F= '/^(ELECTRON_|CHROME_)/{print $1}'`",
6070
- '[ -n "$vars" ] && unset $vars',
6071
- "export ELECTRON_RUN_AS_NODE=1",
6072
- `exec ${execLine} "$@"`,
6073
- ""
6074
- ].join("\n"),
6075
- { mode: 493 }
6076
- );
6077
- return { command: wrap };
6349
+ return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
6078
6350
  }
6079
6351
  function mcpSpawnEnv(env) {
6080
6352
  if (!env) return void 0;
6081
6353
  const out = { ...env };
6082
6354
  delete out.ELECTRON_RUN_AS_NODE;
6355
+ delete out.ELECTRON_RUN_AS_NODE;
6083
6356
  return Object.keys(out).length > 0 ? out : void 0;
6084
6357
  }
6085
6358
  function toCursorMcpServers(servers) {
@@ -6139,19 +6412,19 @@ function writeMcpServersConfig(servers) {
6139
6412
  ...env ? { env } : {}
6140
6413
  };
6141
6414
  }
6142
- const dir = (0, import_node_fs17.mkdtempSync)((0, import_node_path17.join)((0, import_node_os6.tmpdir)(), "sideboard-mcp-"));
6143
- const cfgPath = (0, import_node_path17.join)(dir, "mcp.json");
6144
- (0, import_node_fs17.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
6415
+ const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path21.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
6416
+ const cfgPath = (0, import_node_path21.join)(dir, "mcp.json");
6417
+ (0, import_node_fs20.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
6145
6418
  return cfgPath;
6146
6419
  }
6147
- var import_node_fs17, import_node_module, import_node_os6, import_node_path17, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
6420
+ var import_node_fs20, import_node_module, import_node_os8, import_node_path21, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
6148
6421
  var init_injected_mcp = __esm({
6149
6422
  "src/agents/injected-mcp.ts"() {
6150
6423
  "use strict";
6151
- import_node_fs17 = require("fs");
6424
+ import_node_fs20 = require("fs");
6152
6425
  import_node_module = require("module");
6153
- import_node_os6 = require("os");
6154
- import_node_path17 = require("path");
6426
+ import_node_os8 = require("os");
6427
+ import_node_path21 = require("path");
6155
6428
  import_node_url = require("url");
6156
6429
  init_run();
6157
6430
  init_config();
@@ -6160,6 +6433,7 @@ var init_injected_mcp = __esm({
6160
6433
  init_app_settings();
6161
6434
  init_paths();
6162
6435
  init_node_launch();
6436
+ init_packaged_runtime();
6163
6437
  init_nested_electron_env();
6164
6438
  init_git_auth_mode();
6165
6439
  import_meta = {};
@@ -6229,7 +6503,7 @@ var PLAN_MODE_INSTRUCTION;
6229
6503
  var init_types = __esm({
6230
6504
  "src/agents/types.ts"() {
6231
6505
  "use strict";
6232
- PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope): (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
6506
+ PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope) \u2014 not greetings, check-ins, or an invented task menu: (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. If one option is the obvious default, proceed without asking. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
6233
6507
  }
6234
6508
  });
6235
6509
 
@@ -6339,11 +6613,11 @@ function parseIssuesJson(raw) {
6339
6613
  }
6340
6614
  return [];
6341
6615
  }
6342
- var import_node_fs18, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
6616
+ var import_node_fs21, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
6343
6617
  var init_claude = __esm({
6344
6618
  "src/agents/claude.ts"() {
6345
6619
  "use strict";
6346
- import_node_fs18 = require("fs");
6620
+ import_node_fs21 = require("fs");
6347
6621
  init_run();
6348
6622
  init_app_settings();
6349
6623
  init_claude_mcp();
@@ -6372,7 +6646,7 @@ var init_claude = __esm({
6372
6646
  async detect() {
6373
6647
  const claude = resolveClaudeExecutable();
6374
6648
  if (claude !== "claude") {
6375
- if (!(0, import_node_fs18.existsSync)(claude)) {
6649
+ if (!(0, import_node_fs21.existsSync)(claude)) {
6376
6650
  return {
6377
6651
  agent: "claude",
6378
6652
  installed: false,
@@ -6609,7 +6883,7 @@ async function listCodexModels() {
6609
6883
  if (codex === "codex") {
6610
6884
  const which = await run("which", ["codex"], { reject: false });
6611
6885
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
6612
- } else if (!(0, import_node_fs19.existsSync)(codex)) {
6886
+ } else if (!(0, import_node_fs22.existsSync)(codex)) {
6613
6887
  return FALLBACK_CODEX_MODELS;
6614
6888
  }
6615
6889
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -6644,12 +6918,12 @@ function usageFromCodex(usage) {
6644
6918
  }
6645
6919
  function codexConfigHasNetworkAccess() {
6646
6920
  const candidates = [
6647
- (0, import_node_path18.join)((0, import_node_os7.homedir)(), ".codex", "config.toml"),
6648
- (0, import_node_path18.join)((0, import_node_os7.homedir)(), ".config", "codex", "config.toml")
6921
+ (0, import_node_path22.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
6922
+ (0, import_node_path22.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
6649
6923
  ];
6650
6924
  for (const path of candidates) {
6651
- if (!(0, import_node_fs19.existsSync)(path)) continue;
6652
- const text3 = (0, import_node_fs19.readFileSync)(path, "utf8");
6925
+ if (!(0, import_node_fs22.existsSync)(path)) continue;
6926
+ const text3 = (0, import_node_fs22.readFileSync)(path, "utf8");
6653
6927
  if (/network_access\s*=\s*true/.test(text3)) return true;
6654
6928
  }
6655
6929
  return false;
@@ -6681,21 +6955,21 @@ function asRecord(value) {
6681
6955
  return void 0;
6682
6956
  }
6683
6957
  function codexLooksAuthenticated() {
6684
- const authPath = (0, import_node_path18.join)((0, import_node_os7.homedir)(), ".codex", "auth.json");
6685
- if (!(0, import_node_fs19.existsSync)(authPath)) return false;
6958
+ const authPath = (0, import_node_path22.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
6959
+ if (!(0, import_node_fs22.existsSync)(authPath)) return false;
6686
6960
  try {
6687
- return (0, import_node_fs19.statSync)(authPath).size > 2;
6961
+ return (0, import_node_fs22.statSync)(authPath).size > 2;
6688
6962
  } catch {
6689
6963
  return false;
6690
6964
  }
6691
6965
  }
6692
- var import_node_fs19, import_node_os7, import_node_path18, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
6966
+ var import_node_fs22, import_node_os9, import_node_path22, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
6693
6967
  var init_codex = __esm({
6694
6968
  "src/agents/codex.ts"() {
6695
6969
  "use strict";
6696
- import_node_fs19 = require("fs");
6697
- import_node_os7 = require("os");
6698
- import_node_path18 = require("path");
6970
+ import_node_fs22 = require("fs");
6971
+ import_node_os9 = require("os");
6972
+ import_node_path22 = require("path");
6699
6973
  init_run();
6700
6974
  init_app_settings();
6701
6975
  init_global_workspace();
@@ -6720,7 +6994,7 @@ var init_codex = __esm({
6720
6994
  async detect() {
6721
6995
  const codex = resolveAgentExecutable("codex");
6722
6996
  if (codex !== "codex") {
6723
- if (!(0, import_node_fs19.existsSync)(codex)) {
6997
+ if (!(0, import_node_fs22.existsSync)(codex)) {
6724
6998
  return {
6725
6999
  agent: "codex",
6726
7000
  installed: false,
@@ -6793,8 +7067,13 @@ var init_codex = __esm({
6793
7067
  // `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
6794
7068
  "-c",
6795
7069
  'approval_policy="never"',
6796
- // Seatbelt cannot use the login Keychain; default policy also strips GH_TOKEN.
6797
- ...codexUnattendedGitConfigArgs(mode.codexSandbox),
7070
+ // Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
7071
+ // Default policy also strips *TOKEN*. Linked worktrees need the main
7072
+ // repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
7073
+ // can create index.lock.
7074
+ ...codexUnattendedGitConfigArgs(mode.codexSandbox, {
7075
+ writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
7076
+ }),
6798
7077
  ...model ? ["--model", model] : [],
6799
7078
  ...mcpOverrides
6800
7079
  ];
@@ -7115,6 +7394,74 @@ var init_cursor_events = __esm({
7115
7394
  }
7116
7395
  });
7117
7396
 
7397
+ // src/agents/cursor-ripgrep.ts
7398
+ function rgBinaryName() {
7399
+ return process.platform === "win32" ? "rg.exe" : "rg";
7400
+ }
7401
+ function platformRipgrepPackage() {
7402
+ return `@cursor/sdk-${process.platform}-${process.arch}`;
7403
+ }
7404
+ function usableRipgrepPath(candidate) {
7405
+ const raw = candidate?.trim();
7406
+ if (!raw || !(0, import_node_path23.isAbsolute)(raw)) return null;
7407
+ const readable = nodeReadableScriptPath(raw);
7408
+ if (!(0, import_node_fs23.existsSync)(readable) || isAsarPath(readable)) return null;
7409
+ return readable;
7410
+ }
7411
+ function walkForBundledRipgrep(startFile) {
7412
+ if (!startFile) return null;
7413
+ const pkg = platformRipgrepPackage();
7414
+ const name = rgBinaryName();
7415
+ let dir = (0, import_node_path23.dirname)((0, import_node_path23.resolve)(startFile));
7416
+ const root = (0, import_node_path23.parse)(dir).root;
7417
+ while (dir !== root) {
7418
+ const hit = usableRipgrepPath((0, import_node_path23.join)(dir, "node_modules", pkg, "bin", name));
7419
+ if (hit) return hit;
7420
+ const next = (0, import_node_path23.dirname)(dir);
7421
+ if (next === dir) break;
7422
+ dir = next;
7423
+ }
7424
+ return null;
7425
+ }
7426
+ function requireResolveBundledRipgrep(fromFile) {
7427
+ try {
7428
+ const req = (0, import_node_module2.createRequire)(fromFile);
7429
+ const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
7430
+ return usableRipgrepPath((0, import_node_path23.join)((0, import_node_path23.dirname)(pkgJson), "bin", rgBinaryName()));
7431
+ } catch {
7432
+ return null;
7433
+ }
7434
+ }
7435
+ function resolveCursorRipgrepPath(opts) {
7436
+ const env = opts?.env ?? process.env;
7437
+ const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
7438
+ if (fromEnv) return fromEnv;
7439
+ const fromPackaged = usableRipgrepPath(
7440
+ packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
7441
+ );
7442
+ if (fromPackaged) return fromPackaged;
7443
+ const start = opts?.startFile?.trim() || process.argv[1] || (0, import_node_url2.fileURLToPath)(import_meta2.url);
7444
+ return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
7445
+ }
7446
+ function cursorRipgrepEnv(opts) {
7447
+ const path = resolveCursorRipgrepPath(opts);
7448
+ return path ? { [RIPGREP_ENV]: path } : {};
7449
+ }
7450
+ var import_node_fs23, import_node_module2, import_node_path23, import_node_url2, import_meta2, RIPGREP_ENV;
7451
+ var init_cursor_ripgrep = __esm({
7452
+ "src/agents/cursor-ripgrep.ts"() {
7453
+ "use strict";
7454
+ import_node_fs23 = require("fs");
7455
+ import_node_module2 = require("module");
7456
+ import_node_path23 = require("path");
7457
+ import_node_url2 = require("url");
7458
+ init_node_launch();
7459
+ init_packaged_runtime();
7460
+ import_meta2 = {};
7461
+ RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
7462
+ }
7463
+ });
7464
+
7118
7465
  // src/agents/cursor.ts
7119
7466
  function resolveCursorApiKey() {
7120
7467
  const fromEnv = (process.env.CURSOR_API_KEY || "").trim();
@@ -7154,51 +7501,55 @@ function entryDir() {
7154
7501
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
7155
7502
  if (cjsDir) return cjsDir;
7156
7503
  try {
7157
- return (0, import_node_path19.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
7504
+ return (0, import_node_path24.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
7158
7505
  } catch {
7159
7506
  try {
7160
- const req = (0, import_node_module2.createRequire)(process.cwd() + "/");
7161
- return (0, import_node_path19.dirname)(req.resolve("@sideboard-ai/core"));
7507
+ const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
7508
+ return (0, import_node_path24.dirname)(req.resolve("@sideboard-ai/core"));
7162
7509
  } catch {
7163
7510
  return process.cwd();
7164
7511
  }
7165
7512
  }
7166
7513
  }
7167
7514
  function cursorRunnerPath() {
7515
+ const packaged = packagedCursorRunnerPath();
7516
+ if (packaged) return packaged;
7168
7517
  const root = entryDir();
7169
7518
  const candidates = [
7170
- (0, import_node_path19.join)(root, "agents", "cursor-runner.js"),
7171
- (0, import_node_path19.join)(root, "agents", "cursor-runner.cjs"),
7519
+ (0, import_node_path24.join)(root, "agents", "cursor-runner.js"),
7520
+ (0, import_node_path24.join)(root, "agents", "cursor-runner.cjs"),
7172
7521
  // If somehow resolved from package root instead of dist/
7173
- (0, import_node_path19.join)(root, "dist", "agents", "cursor-runner.js"),
7174
- (0, import_node_path19.join)(root, "dist", "agents", "cursor-runner.cjs"),
7522
+ (0, import_node_path24.join)(root, "dist", "agents", "cursor-runner.js"),
7523
+ (0, import_node_path24.join)(root, "dist", "agents", "cursor-runner.cjs"),
7175
7524
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
7176
- (0, import_node_path19.join)(root, "cursor-runner.ts"),
7177
- (0, import_node_path19.join)(root, "src", "agents", "cursor-runner.ts")
7525
+ (0, import_node_path24.join)(root, "cursor-runner.ts"),
7526
+ (0, import_node_path24.join)(root, "src", "agents", "cursor-runner.ts")
7178
7527
  ];
7179
7528
  for (const candidate of candidates) {
7180
- if ((0, import_node_fs20.existsSync)(candidate)) return candidate;
7529
+ if ((0, import_node_fs24.existsSync)(candidate)) return candidate;
7181
7530
  }
7182
7531
  return candidates[0];
7183
7532
  }
7184
- var import_node_fs20, import_node_module2, import_node_path19, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
7533
+ var import_node_fs24, import_node_module3, import_node_path24, import_node_url3, import_sdk, import_meta3, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
7185
7534
  var init_cursor = __esm({
7186
7535
  "src/agents/cursor.ts"() {
7187
7536
  "use strict";
7188
- import_node_fs20 = require("fs");
7189
- import_node_module2 = require("module");
7190
- import_node_path19 = require("path");
7191
- import_node_url2 = require("url");
7537
+ import_node_fs24 = require("fs");
7538
+ import_node_module3 = require("module");
7539
+ import_node_path24 = require("path");
7540
+ import_node_url3 = require("url");
7192
7541
  import_sdk = require("@cursor/sdk");
7193
7542
  init_run();
7194
7543
  init_app_settings();
7195
7544
  init_global_workspace();
7196
7545
  init_cursor_events();
7197
7546
  init_injected_mcp();
7547
+ init_cursor_ripgrep();
7198
7548
  init_node_launch();
7549
+ init_packaged_runtime();
7199
7550
  init_turn_input();
7200
7551
  init_cursor_events();
7201
- import_meta2 = {};
7552
+ import_meta3 = {};
7202
7553
  FALLBACK_CURSOR_MODELS = [
7203
7554
  { id: "default", displayName: "Auto" },
7204
7555
  { id: "composer-2.5", displayName: "Composer 2.5" },
@@ -7265,6 +7616,7 @@ var init_cursor = __esm({
7265
7616
  stdin: JSON.stringify(req),
7266
7617
  env: {
7267
7618
  ...launch.env,
7619
+ ...cursorRipgrepEnv({ startFile: runner }),
7268
7620
  ...apiKey ? { CURSOR_API_KEY: apiKey } : {}
7269
7621
  }
7270
7622
  };
@@ -7316,7 +7668,7 @@ async function listOpencodeModels() {
7316
7668
  if (opencode === "opencode") {
7317
7669
  const which = await run("which", ["opencode"], { reject: false });
7318
7670
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
7319
- } else if (!(0, import_node_fs21.existsSync)(opencode)) {
7671
+ } else if (!(0, import_node_fs25.existsSync)(opencode)) {
7320
7672
  return FALLBACK_OPENCODE_MODELS;
7321
7673
  }
7322
7674
  const listed = await run(opencode, ["models"], { reject: false });
@@ -7346,11 +7698,11 @@ function usageFromOpencode(tokens) {
7346
7698
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
7347
7699
  };
7348
7700
  }
7349
- var import_node_fs21, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
7701
+ var import_node_fs25, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
7350
7702
  var init_opencode = __esm({
7351
7703
  "src/agents/opencode.ts"() {
7352
7704
  "use strict";
7353
- import_node_fs21 = require("fs");
7705
+ import_node_fs25 = require("fs");
7354
7706
  init_run();
7355
7707
  init_app_settings();
7356
7708
  init_global_workspace();
@@ -7376,7 +7728,7 @@ var init_opencode = __esm({
7376
7728
  async detect() {
7377
7729
  const opencode = resolveAgentExecutable("opencode");
7378
7730
  if (opencode !== "opencode") {
7379
- if (!(0, import_node_fs21.existsSync)(opencode)) {
7731
+ if (!(0, import_node_fs25.existsSync)(opencode)) {
7380
7732
  return {
7381
7733
  agent: "opencode",
7382
7734
  installed: false,
@@ -8113,38 +8465,38 @@ __export(workspaces_exports, {
8113
8465
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
8114
8466
  });
8115
8467
  function workspacesFile() {
8116
- return (0, import_node_path22.join)(appDataDir(), "workspaces.json");
8468
+ return (0, import_node_path27.join)(appDataDir(), "workspaces.json");
8117
8469
  }
8118
8470
  function removedWorkspacesFile() {
8119
- return (0, import_node_path22.join)(appDataDir(), "removed-workspaces.json");
8471
+ return (0, import_node_path27.join)(appDataDir(), "removed-workspaces.json");
8120
8472
  }
8121
8473
  function readAll() {
8122
8474
  const path = workspacesFile();
8123
- if (!(0, import_node_fs24.existsSync)(path)) return [];
8475
+ if (!(0, import_node_fs28.existsSync)(path)) return [];
8124
8476
  try {
8125
- const raw = JSON.parse((0, import_node_fs24.readFileSync)(path, "utf8"));
8477
+ const raw = JSON.parse((0, import_node_fs28.readFileSync)(path, "utf8"));
8126
8478
  return Array.isArray(raw) ? raw : [];
8127
8479
  } catch {
8128
8480
  return [];
8129
8481
  }
8130
8482
  }
8131
8483
  function writeAll(list) {
8132
- (0, import_node_fs24.mkdirSync)(appDataDir(), { recursive: true });
8133
- (0, import_node_fs24.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
8484
+ (0, import_node_fs28.mkdirSync)(appDataDir(), { recursive: true });
8485
+ (0, import_node_fs28.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
8134
8486
  }
8135
8487
  function readRemoved() {
8136
8488
  const path = removedWorkspacesFile();
8137
- if (!(0, import_node_fs24.existsSync)(path)) return /* @__PURE__ */ new Set();
8489
+ if (!(0, import_node_fs28.existsSync)(path)) return /* @__PURE__ */ new Set();
8138
8490
  try {
8139
- const raw = JSON.parse((0, import_node_fs24.readFileSync)(path, "utf8"));
8491
+ const raw = JSON.parse((0, import_node_fs28.readFileSync)(path, "utf8"));
8140
8492
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
8141
8493
  } catch {
8142
8494
  return /* @__PURE__ */ new Set();
8143
8495
  }
8144
8496
  }
8145
8497
  function writeRemoved(paths) {
8146
- (0, import_node_fs24.mkdirSync)(appDataDir(), { recursive: true });
8147
- (0, import_node_fs24.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
8498
+ (0, import_node_fs28.mkdirSync)(appDataDir(), { recursive: true });
8499
+ (0, import_node_fs28.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
8148
8500
  }
8149
8501
  function rememberRemoved(repoPath) {
8150
8502
  const next = readRemoved();
@@ -8167,7 +8519,7 @@ function listWorkspaces() {
8167
8519
  async function addWorkspace(repoPath) {
8168
8520
  const root = await resolveRepoRoot(repoPath);
8169
8521
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
8170
- if (!(0, import_node_fs24.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
8522
+ if (!(0, import_node_fs28.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
8171
8523
  forgetRemoved(root);
8172
8524
  await ensureGhPreferOrigin(root);
8173
8525
  const current = readAll();
@@ -8175,7 +8527,7 @@ async function addWorkspace(repoPath) {
8175
8527
  if (existing) return existing;
8176
8528
  const next = {
8177
8529
  path: root,
8178
- name: (0, import_node_path22.basename)(root),
8530
+ name: (0, import_node_path27.basename)(root),
8179
8531
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
8180
8532
  };
8181
8533
  writeAll([...current, next]);
@@ -8197,10 +8549,10 @@ function syncWorkspacesFromThreads(repoPaths) {
8197
8549
  if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
8198
8550
  continue;
8199
8551
  }
8200
- if (!(0, import_node_fs24.existsSync)(path)) continue;
8552
+ if (!(0, import_node_fs28.existsSync)(path)) continue;
8201
8553
  const ws = {
8202
8554
  path,
8203
- name: (0, import_node_path22.basename)(path),
8555
+ name: (0, import_node_path27.basename)(path),
8204
8556
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
8205
8557
  };
8206
8558
  byPath.set(path, ws);
@@ -8210,12 +8562,12 @@ function syncWorkspacesFromThreads(repoPaths) {
8210
8562
  if (dirty) writeAll(next);
8211
8563
  return next.sort((a, b) => a.name.localeCompare(b.name));
8212
8564
  }
8213
- var import_node_fs24, import_node_path22;
8565
+ var import_node_fs28, import_node_path27;
8214
8566
  var init_workspaces = __esm({
8215
8567
  "src/store/workspaces.ts"() {
8216
8568
  "use strict";
8217
- import_node_fs24 = require("fs");
8218
- import_node_path22 = require("path");
8569
+ import_node_fs28 = require("fs");
8570
+ import_node_path27 = require("path");
8219
8571
  init_paths();
8220
8572
  init_global_workspace();
8221
8573
  init_worktree();
@@ -8292,40 +8644,40 @@ __export(plan_file_exports, {
8292
8644
  writePlanFile: () => writePlanFile
8293
8645
  });
8294
8646
  function ensureAttachmentsGitignore2(worktreePath) {
8295
- const gitignoreAbs = (0, import_node_path30.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
8296
- if ((0, import_node_fs34.existsSync)(gitignoreAbs)) return;
8297
- (0, import_node_fs34.mkdirSync)((0, import_node_path30.dirname)(gitignoreAbs), { recursive: true });
8298
- (0, import_node_fs34.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
8647
+ const gitignoreAbs = (0, import_node_path35.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
8648
+ if ((0, import_node_fs38.existsSync)(gitignoreAbs)) return;
8649
+ (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(gitignoreAbs), { recursive: true });
8650
+ (0, import_node_fs38.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
8299
8651
  }
8300
8652
  function planFileAbs(worktreePath) {
8301
- return (0, import_node_path30.join)(worktreePath, PLAN_FILE_REL);
8653
+ return (0, import_node_path35.join)(worktreePath, PLAN_FILE_REL);
8302
8654
  }
8303
8655
  function readTextIfPresent2(abs) {
8304
- if (!(0, import_node_fs34.existsSync)(abs)) return null;
8656
+ if (!(0, import_node_fs38.existsSync)(abs)) return null;
8305
8657
  try {
8306
- const content = (0, import_node_fs34.readFileSync)(abs, "utf8");
8658
+ const content = (0, import_node_fs38.readFileSync)(abs, "utf8");
8307
8659
  return content.trim() ? content : null;
8308
8660
  } catch {
8309
8661
  return null;
8310
8662
  }
8311
8663
  }
8312
8664
  function readPlanFile(worktreePath) {
8313
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path30.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path30.join)(worktreePath, LEGACY_PLAN_FILE_REL));
8665
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path35.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path35.join)(worktreePath, LEGACY_PLAN_FILE_REL));
8314
8666
  }
8315
8667
  function writePlanFile(worktreePath, content) {
8316
8668
  ensureAttachmentsGitignore2(worktreePath);
8317
8669
  const abs = planFileAbs(worktreePath);
8318
- (0, import_node_fs34.mkdirSync)((0, import_node_path30.dirname)(abs), { recursive: true });
8670
+ (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
8319
8671
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
8320
- (0, import_node_fs34.writeFileSync)(abs, body, "utf8");
8672
+ (0, import_node_fs38.writeFileSync)(abs, body, "utf8");
8321
8673
  return PLAN_FILE_REL;
8322
8674
  }
8323
- var import_node_fs34, import_node_path30;
8675
+ var import_node_fs38, import_node_path35;
8324
8676
  var init_plan_file = __esm({
8325
8677
  "src/plan/plan-file.ts"() {
8326
8678
  "use strict";
8327
- import_node_fs34 = require("fs");
8328
- import_node_path30 = require("path");
8679
+ import_node_fs38 = require("fs");
8680
+ import_node_path35 = require("path");
8329
8681
  init_workspace_scratch();
8330
8682
  init_plan_present();
8331
8683
  init_plan_present();
@@ -8346,7 +8698,7 @@ function setCaffeinateHoldHooks(next) {
8346
8698
  hooks = next;
8347
8699
  }
8348
8700
  function caffeinateHoldPath() {
8349
- return (0, import_node_path31.join)(appDataDir(), "caffeinate-hold.json");
8701
+ return (0, import_node_path36.join)(appDataDir(), "caffeinate-hold.json");
8350
8702
  }
8351
8703
  function processAlive(pid) {
8352
8704
  if (hooks.processAlive) return hooks.processAlive(pid);
@@ -8380,9 +8732,9 @@ function uniqueIds(ids) {
8380
8732
  }
8381
8733
  function readHold() {
8382
8734
  const path = caffeinateHoldPath();
8383
- if (!(0, import_node_fs35.existsSync)(path)) return null;
8735
+ if (!(0, import_node_fs39.existsSync)(path)) return null;
8384
8736
  try {
8385
- const parsed = JSON.parse((0, import_node_fs35.readFileSync)(path, "utf8"));
8737
+ const parsed = JSON.parse((0, import_node_fs39.readFileSync)(path, "utf8"));
8386
8738
  if (typeof parsed?.pid === "number" && parsed.pid > 0) {
8387
8739
  return {
8388
8740
  pid: parsed.pid,
@@ -8404,7 +8756,7 @@ function writeHold(pid, threadIds) {
8404
8756
  }
8405
8757
  function clearHold() {
8406
8758
  try {
8407
- (0, import_node_fs35.unlinkSync)(caffeinateHoldPath());
8759
+ (0, import_node_fs39.unlinkSync)(caffeinateHoldPath());
8408
8760
  } catch {
8409
8761
  }
8410
8762
  }
@@ -8489,13 +8841,13 @@ function releaseCaffeinateHoldForThread(threadId) {
8489
8841
  }
8490
8842
  return setCaffeinateHold(false, { threadId: id });
8491
8843
  }
8492
- var import_node_child_process4, import_node_fs35, import_node_path31, hooks;
8844
+ var import_node_child_process4, import_node_fs39, import_node_path36, hooks;
8493
8845
  var init_caffeinate_hold = __esm({
8494
8846
  "src/store/caffeinate-hold.ts"() {
8495
8847
  "use strict";
8496
8848
  import_node_child_process4 = require("child_process");
8497
- import_node_fs35 = require("fs");
8498
- import_node_path31 = require("path");
8849
+ import_node_fs39 = require("fs");
8850
+ import_node_path36 = require("path");
8499
8851
  init_paths();
8500
8852
  init_private_file();
8501
8853
  hooks = {};
@@ -8510,10 +8862,10 @@ __export(cursor_recover_exports, {
8510
8862
  function recoverFinishedCursorRun(opts) {
8511
8863
  const agentId = opts.agentId.trim();
8512
8864
  if (!agentId) return null;
8513
- const runsPath = (0, import_node_path32.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
8514
- if (!(0, import_node_fs36.existsSync)(runsPath)) return null;
8865
+ const runsPath = (0, import_node_path37.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
8866
+ if (!(0, import_node_fs40.existsSync)(runsPath)) return null;
8515
8867
  try {
8516
- const lines = (0, import_node_fs36.readFileSync)(runsPath, "utf8").split("\n");
8868
+ const lines = (0, import_node_fs40.readFileSync)(runsPath, "utf8").split("\n");
8517
8869
  let best = null;
8518
8870
  for (const line of lines) {
8519
8871
  const trimmed = line.trim();
@@ -8539,12 +8891,12 @@ function recoverFinishedCursorRun(opts) {
8539
8891
  return null;
8540
8892
  }
8541
8893
  }
8542
- var import_node_fs36, import_node_path32;
8894
+ var import_node_fs40, import_node_path37;
8543
8895
  var init_cursor_recover = __esm({
8544
8896
  "src/agents/cursor-recover.ts"() {
8545
8897
  "use strict";
8546
- import_node_fs36 = require("fs");
8547
- import_node_path32 = require("path");
8898
+ import_node_fs40 = require("fs");
8899
+ import_node_path37 = require("path");
8548
8900
  init_paths();
8549
8901
  }
8550
8902
  });
@@ -8556,7 +8908,7 @@ init_nested_electron_env();
8556
8908
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
8557
8909
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
8558
8910
  var import_zod3 = require("zod");
8559
- var import_node_path33 = require("path");
8911
+ var import_node_path38 = require("path");
8560
8912
 
8561
8913
  // src/orchestrator/orchestrator.ts
8562
8914
  var import_node_events = require("events");
@@ -9067,7 +9419,7 @@ async function refreshSlackReplyBadges(opts) {
9067
9419
  }
9068
9420
 
9069
9421
  // src/orchestrator/orchestrator.ts
9070
- var import_node_fs37 = require("fs");
9422
+ var import_node_fs41 = require("fs");
9071
9423
  init_error_detail();
9072
9424
 
9073
9425
  // src/agents/spawn.ts
@@ -9384,10 +9736,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
9384
9736
  const env = childEnvWithAppSettings(cmd.env);
9385
9737
  try {
9386
9738
  if (isOrchestratorThread(thread)) {
9387
- Object.assign(env, await resolveAgentGitAuthEnv(env));
9739
+ mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
9388
9740
  } else {
9389
- const originEnv = await originGhRepoEnv(thread.worktreePath, { env });
9390
- Object.assign(env, originEnv);
9741
+ mergeAgentGitAuthEnv(env, await originGhRepoEnv(thread.worktreePath, { env }));
9391
9742
  }
9392
9743
  } catch (err) {
9393
9744
  const detail = err instanceof Error ? err.message : String(err);
@@ -9600,9 +9951,9 @@ function shouldAutoArchiveOnPrMerge(opts) {
9600
9951
  }
9601
9952
 
9602
9953
  // src/hook/conductor.ts
9603
- var import_node_fs22 = require("fs");
9954
+ var import_node_fs26 = require("fs");
9604
9955
  var import_node_net = require("net");
9605
- var import_node_path20 = require("path");
9956
+ var import_node_path25 = require("path");
9606
9957
  var import_execa4 = require("execa");
9607
9958
  var import_node_readline3 = require("readline");
9608
9959
  init_settings();
@@ -9617,9 +9968,9 @@ function matchSimpleGlob(pattern, name) {
9617
9968
  return new RegExp(`^${escaped}$`).test(name);
9618
9969
  }
9619
9970
  function readWorktreeInclude(repoPath) {
9620
- const path = (0, import_node_path20.join)(repoPath, ".worktreeinclude");
9621
- if (!(0, import_node_fs22.existsSync)(path)) return [];
9622
- return (0, import_node_fs22.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
9971
+ const path = (0, import_node_path25.join)(repoPath, ".worktreeinclude");
9972
+ if (!(0, import_node_fs26.existsSync)(path)) return [];
9973
+ return (0, import_node_fs26.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
9623
9974
  }
9624
9975
  function resolveFilesToCopy(repoPath) {
9625
9976
  const fromInclude = readWorktreeInclude(repoPath);
@@ -9629,10 +9980,10 @@ function resolveFilesToCopy(repoPath) {
9629
9980
  if (settings?.fileIncludeGlobs?.length) {
9630
9981
  const matched = [];
9631
9982
  try {
9632
- for (const entry of (0, import_node_fs22.readdirSync)(repoPath, { withFileTypes: true })) {
9983
+ for (const entry of (0, import_node_fs26.readdirSync)(repoPath, { withFileTypes: true })) {
9633
9984
  if (!entry.isFile()) continue;
9634
9985
  for (const glob of settings.fileIncludeGlobs) {
9635
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path20.basename)(glob), entry.name)) {
9986
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path25.basename)(glob), entry.name)) {
9636
9987
  matched.push(entry.name);
9637
9988
  break;
9638
9989
  }
@@ -9644,7 +9995,7 @@ function resolveFilesToCopy(repoPath) {
9644
9995
  }
9645
9996
  const defaults = [];
9646
9997
  try {
9647
- for (const entry of (0, import_node_fs22.readdirSync)(repoPath, { withFileTypes: true })) {
9998
+ for (const entry of (0, import_node_fs26.readdirSync)(repoPath, { withFileTypes: true })) {
9648
9999
  if (entry.isFile() && entry.name.startsWith(".env")) {
9649
10000
  defaults.push(entry.name);
9650
10001
  }
@@ -9658,11 +10009,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
9658
10009
  const patterns = resolveFilesToCopy(repoPath);
9659
10010
  const copied = [];
9660
10011
  for (const rel of patterns) {
9661
- const src = (0, import_node_path20.join)(repoPath, rel);
9662
- if (!(0, import_node_fs22.existsSync)(src)) continue;
9663
- const dest = (0, import_node_path20.join)(worktreePath, rel);
9664
- (0, import_node_fs22.mkdirSync)((0, import_node_path20.dirname)(dest), { recursive: true });
9665
- (0, import_node_fs22.copyFileSync)(src, dest);
10012
+ const src = (0, import_node_path25.join)(repoPath, rel);
10013
+ if (!(0, import_node_fs26.existsSync)(src)) continue;
10014
+ const dest = (0, import_node_path25.join)(worktreePath, rel);
10015
+ (0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(dest), { recursive: true });
10016
+ (0, import_node_fs26.copyFileSync)(src, dest);
9666
10017
  copied.push(rel);
9667
10018
  }
9668
10019
  return copied;
@@ -9698,7 +10049,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
9698
10049
  const env = stripNestedElectronEnv({
9699
10050
  ...baseEnv ?? process.env
9700
10051
  });
9701
- const name = opts.workspaceName ?? (0, import_node_path20.basename)(opts.worktreePath);
10052
+ const name = opts.workspaceName ?? (0, import_node_path25.basename)(opts.worktreePath);
9702
10053
  const ports = opts.ports ?? [];
9703
10054
  const primary = ports[0];
9704
10055
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -9784,7 +10135,10 @@ async function spawnWorkspaceScript(command, opts) {
9784
10135
  loginEnv
9785
10136
  );
9786
10137
  try {
9787
- Object.assign(env, await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath }));
10138
+ mergeAgentGitAuthEnv(
10139
+ env,
10140
+ await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath })
10141
+ );
9788
10142
  } catch {
9789
10143
  }
9790
10144
  const shell = process.platform === "darwin" ? "zsh" : "bash";
@@ -9952,8 +10306,8 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
9952
10306
  }
9953
10307
 
9954
10308
  // src/git/orphan-cleanup.ts
9955
- var import_node_fs23 = require("fs");
9956
- var import_node_path21 = require("path");
10309
+ var import_node_fs27 = require("fs");
10310
+ var import_node_path26 = require("path");
9957
10311
  init_worktree();
9958
10312
  init_thread_store();
9959
10313
  init_paths();
@@ -9968,9 +10322,9 @@ async function findOrphanWorktrees(repoPaths) {
9968
10322
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
9969
10323
  );
9970
10324
  const homeRoot = sideboardWorkspacesDir();
9971
- if ((0, import_node_fs23.existsSync)(homeRoot)) {
10325
+ if ((0, import_node_fs27.existsSync)(homeRoot)) {
9972
10326
  try {
9973
- for (const entry of (0, import_node_fs23.readdirSync)(homeRoot, { withFileTypes: true })) {
10327
+ for (const entry of (0, import_node_fs27.readdirSync)(homeRoot, { withFileTypes: true })) {
9974
10328
  if (!entry.isDirectory()) continue;
9975
10329
  void entry;
9976
10330
  }
@@ -9980,7 +10334,7 @@ async function findOrphanWorktrees(repoPaths) {
9980
10334
  const orphans = [];
9981
10335
  const seen = /* @__PURE__ */ new Set();
9982
10336
  for (const repoPath of repos) {
9983
- if (!repoPath || !(0, import_node_fs23.existsSync)(repoPath)) continue;
10337
+ if (!repoPath || !(0, import_node_fs27.existsSync)(repoPath)) continue;
9984
10338
  try {
9985
10339
  const wts = await listWorktrees(repoPath);
9986
10340
  for (const wt of wts) {
@@ -9991,7 +10345,7 @@ async function findOrphanWorktrees(repoPaths) {
9991
10345
  seen.add(path);
9992
10346
  let mtimeMs = 0;
9993
10347
  try {
9994
- mtimeMs = (0, import_node_fs23.statSync)(path).mtimeMs;
10348
+ mtimeMs = (0, import_node_fs27.statSync)(path).mtimeMs;
9995
10349
  } catch {
9996
10350
  mtimeMs = 0;
9997
10351
  }
@@ -10001,16 +10355,16 @@ async function findOrphanWorktrees(repoPaths) {
10001
10355
  }
10002
10356
  try {
10003
10357
  const root = worktreesRoot(repoPath);
10004
- if ((0, import_node_fs23.existsSync)(root)) {
10005
- for (const entry of (0, import_node_fs23.readdirSync)(root, { withFileTypes: true })) {
10358
+ if ((0, import_node_fs27.existsSync)(root)) {
10359
+ for (const entry of (0, import_node_fs27.readdirSync)(root, { withFileTypes: true })) {
10006
10360
  if (!entry.isDirectory()) continue;
10007
- const path = (0, import_node_path21.join)(root, entry.name).replace(/\/$/, "");
10361
+ const path = (0, import_node_path26.join)(root, entry.name).replace(/\/$/, "");
10008
10362
  if (known.has(path) || seen.has(path)) continue;
10009
- if (!(0, import_node_fs23.existsSync)((0, import_node_path21.join)(path, ".git"))) continue;
10363
+ if (!(0, import_node_fs27.existsSync)((0, import_node_path26.join)(path, ".git"))) continue;
10010
10364
  seen.add(path);
10011
10365
  let mtimeMs = 0;
10012
10366
  try {
10013
- mtimeMs = (0, import_node_fs23.statSync)(path).mtimeMs;
10367
+ mtimeMs = (0, import_node_fs27.statSync)(path).mtimeMs;
10014
10368
  } catch {
10015
10369
  mtimeMs = Date.now();
10016
10370
  }
@@ -10147,8 +10501,8 @@ async function applyThreadIntoMain(thread, opts) {
10147
10501
  }
10148
10502
 
10149
10503
  // src/git/clone-repo.ts
10150
- var import_node_fs25 = require("fs");
10151
- var import_node_path23 = require("path");
10504
+ var import_node_fs29 = require("fs");
10505
+ var import_node_path28 = require("path");
10152
10506
  var import_execa6 = require("execa");
10153
10507
  init_paths();
10154
10508
  init_workspaces();
@@ -10158,12 +10512,12 @@ async function cloneRepoIntoSideboard(opts) {
10158
10512
  if (!url) throw new Error("Clone URL is required");
10159
10513
  let name = opts.name?.trim();
10160
10514
  if (!name) {
10161
- const leaf = (0, import_node_path23.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
10515
+ const leaf = (0, import_node_path28.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
10162
10516
  name = leaf || "repo";
10163
10517
  }
10164
10518
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
10165
- const dest = (0, import_node_path23.join)(sideboardReposDir(), name);
10166
- if ((0, import_node_fs25.existsSync)(dest)) {
10519
+ const dest = (0, import_node_path28.join)(sideboardReposDir(), name);
10520
+ if ((0, import_node_fs29.existsSync)(dest)) {
10167
10521
  const repoPath2 = await resolveRepoRoot(dest);
10168
10522
  const workspace2 = await ensureWorkspace(repoPath2);
10169
10523
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -10183,7 +10537,7 @@ async function cloneRepoIntoSideboard(opts) {
10183
10537
  init_thread_store();
10184
10538
 
10185
10539
  // src/threads/create.ts
10186
- var import_node_fs26 = require("fs");
10540
+ var import_node_fs30 = require("fs");
10187
10541
 
10188
10542
  // src/detect/detect.ts
10189
10543
  init_agents();
@@ -10228,12 +10582,13 @@ async function createThread(input, _onSetupLine) {
10228
10582
  });
10229
10583
  await requireAgent(resolved.agent);
10230
10584
  const repoPath = await resolveRepoRoot(input.repoPath);
10231
- if (!(0, import_node_fs26.existsSync)(repoPath)) {
10585
+ if (!(0, import_node_fs30.existsSync)(repoPath)) {
10232
10586
  throw new Error(`Repo not found: ${repoPath}`);
10233
10587
  }
10234
10588
  let sourceRef = input.sourceRef;
10235
10589
  let sourceIsFork = false;
10236
10590
  let prUrl = null;
10591
+ let prTitle = null;
10237
10592
  if (input.sourceType === "pr") {
10238
10593
  const num2 = Number(input.sourceRef.replace(/^#/, ""));
10239
10594
  if (!Number.isFinite(num2)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
@@ -10249,6 +10604,12 @@ async function createThread(input, _onSetupLine) {
10249
10604
  } else if (input.sourceType === "branch") {
10250
10605
  if (!sourceRef || sourceRef === "HEAD" || sourceRef === "default") {
10251
10606
  sourceRef = await resolveDefaultBranch(repoPath);
10607
+ } else {
10608
+ const existing = await getPrForHeadBranch(repoPath, sourceRef);
10609
+ if (existing?.url) {
10610
+ prUrl = existing.url;
10611
+ prTitle = existing.title;
10612
+ }
10252
10613
  }
10253
10614
  } else if (input.sourceType === "adopt") {
10254
10615
  throw new Error("Use adoptThread() for adopt sources");
@@ -10279,7 +10640,8 @@ async function createThread(input, _onSetupLine) {
10279
10640
  sourceIsFork,
10280
10641
  parentThreadId: input.parentThreadId ?? null,
10281
10642
  status: "idle",
10282
- prUrl
10643
+ prUrl,
10644
+ prTitle
10283
10645
  });
10284
10646
  writeThread(thread);
10285
10647
  await ensureWorkspace(repoPath);
@@ -10691,8 +11053,8 @@ function forkChatTab(input) {
10691
11053
 
10692
11054
  // src/review/request-review.ts
10693
11055
  var import_node_crypto5 = require("crypto");
10694
- var import_node_fs27 = require("fs");
10695
- var import_node_path24 = require("path");
11056
+ var import_node_fs31 = require("fs");
11057
+ var import_node_path29 = require("path");
10696
11058
  init_global_workspace();
10697
11059
  init_thread_store();
10698
11060
 
@@ -10840,22 +11202,22 @@ function shouldRefreshReviewRequestTemplate(content) {
10840
11202
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
10841
11203
  }
10842
11204
  function readTextIfPresent(abs) {
10843
- if (!(0, import_node_fs27.existsSync)(abs)) return null;
11205
+ if (!(0, import_node_fs31.existsSync)(abs)) return null;
10844
11206
  try {
10845
- const content = (0, import_node_fs27.readFileSync)(abs, "utf8");
11207
+ const content = (0, import_node_fs31.readFileSync)(abs, "utf8");
10846
11208
  return content.trim() ? content : null;
10847
11209
  } catch {
10848
11210
  return null;
10849
11211
  }
10850
11212
  }
10851
11213
  function ensureAttachmentsGitignore(worktreePath) {
10852
- const gitignoreAbs = (0, import_node_path24.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
10853
- if ((0, import_node_fs27.existsSync)(gitignoreAbs)) return;
10854
- (0, import_node_fs27.mkdirSync)((0, import_node_path24.dirname)(gitignoreAbs), { recursive: true });
10855
- (0, import_node_fs27.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
11214
+ const gitignoreAbs = (0, import_node_path29.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
11215
+ if ((0, import_node_fs31.existsSync)(gitignoreAbs)) return;
11216
+ (0, import_node_fs31.mkdirSync)((0, import_node_path29.dirname)(gitignoreAbs), { recursive: true });
11217
+ (0, import_node_fs31.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
10856
11218
  }
10857
11219
  function resolveReviewGuidelines(worktreePath) {
10858
- const repoAbs = (0, import_node_path24.join)(worktreePath, REPO_REVIEW_PATH);
11220
+ const repoAbs = (0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH);
10859
11221
  const repoContent = readTextIfPresent(repoAbs);
10860
11222
  if (repoContent) {
10861
11223
  return {
@@ -10865,7 +11227,7 @@ function resolveReviewGuidelines(worktreePath) {
10865
11227
  source: "repo"
10866
11228
  };
10867
11229
  }
10868
- const localAbs = (0, import_node_path24.join)(worktreePath, REVIEW_REQUEST_PATH);
11230
+ const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
10869
11231
  const localContent = readTextIfPresent(localAbs);
10870
11232
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
10871
11233
  return {
@@ -10875,7 +11237,7 @@ function resolveReviewGuidelines(worktreePath) {
10875
11237
  source: "local"
10876
11238
  };
10877
11239
  }
10878
- const legacyAbs = (0, import_node_path24.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
11240
+ const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
10879
11241
  const legacyContent = readTextIfPresent(legacyAbs);
10880
11242
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
10881
11243
  return {
@@ -10886,8 +11248,8 @@ function resolveReviewGuidelines(worktreePath) {
10886
11248
  };
10887
11249
  }
10888
11250
  ensureAttachmentsGitignore(worktreePath);
10889
- (0, import_node_fs27.mkdirSync)((0, import_node_path24.dirname)(localAbs), { recursive: true });
10890
- (0, import_node_fs27.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
11251
+ (0, import_node_fs31.mkdirSync)((0, import_node_path29.dirname)(localAbs), { recursive: true });
11252
+ (0, import_node_fs31.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
10891
11253
  return {
10892
11254
  path: REVIEW_REQUEST_PATH,
10893
11255
  name: REVIEW_REQUEST_NAME,
@@ -11087,20 +11449,26 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
11087
11449
 
11088
11450
  // src/threads/adopt.ts
11089
11451
  var import_node_child_process3 = require("child_process");
11090
- var import_node_fs28 = require("fs");
11091
- var import_node_os8 = require("os");
11092
- var import_node_path25 = require("path");
11093
- var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
11452
+ var import_node_fs32 = require("fs");
11453
+ var import_node_os10 = require("os");
11454
+ var import_node_path30 = require("path");
11455
+ var import_node_module4 = require("module");
11094
11456
  init_worktree();
11095
11457
  init_thread_store();
11096
- var CONDUCTOR_APP_SUPPORT = (0, import_node_path25.join)(
11458
+ var import_meta4 = {};
11459
+ var CONDUCTOR_APP_SUPPORT = (0, import_node_path30.join)(
11097
11460
  process.env.HOME ?? "",
11098
11461
  "Library",
11099
11462
  "Application Support",
11100
11463
  "com.conductor.app"
11101
11464
  );
11102
- var CONDUCTOR_DB = (0, import_node_path25.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
11103
- var CURSOR_SDK_STORE = (0, import_node_path25.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
11465
+ var CONDUCTOR_DB = (0, import_node_path30.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
11466
+ var CURSOR_SDK_STORE = (0, import_node_path30.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
11467
+ function openReadonlySqlite(file) {
11468
+ const req = (0, import_node_module4.createRequire)(import_meta4.url);
11469
+ const Database = req("better-sqlite3");
11470
+ return new Database(file, { readonly: true, fileMustExist: true });
11471
+ }
11104
11472
  function mapAgentType(raw) {
11105
11473
  if (!raw) return null;
11106
11474
  const v = raw.toLowerCase();
@@ -11112,21 +11480,21 @@ function mapAgentType(raw) {
11112
11480
  return null;
11113
11481
  }
11114
11482
  function resolveConductorCursorAgentId(workspacePath) {
11115
- if (!workspacePath || !(0, import_node_fs28.existsSync)(CURSOR_SDK_STORE)) return null;
11483
+ if (!workspacePath || !(0, import_node_fs32.existsSync)(CURSOR_SDK_STORE)) return null;
11116
11484
  const normalized = workspacePath.replace(/\/$/, "");
11117
11485
  let best = null;
11118
11486
  let hashes;
11119
11487
  try {
11120
- hashes = (0, import_node_fs28.readdirSync)(CURSOR_SDK_STORE);
11488
+ hashes = (0, import_node_fs32.readdirSync)(CURSOR_SDK_STORE);
11121
11489
  } catch {
11122
11490
  return null;
11123
11491
  }
11124
11492
  for (const hash of hashes) {
11125
- const agentsFile = (0, import_node_path25.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
11126
- if (!(0, import_node_fs28.existsSync)(agentsFile)) continue;
11493
+ const agentsFile = (0, import_node_path30.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
11494
+ if (!(0, import_node_fs32.existsSync)(agentsFile)) continue;
11127
11495
  let text3;
11128
11496
  try {
11129
- text3 = (0, import_node_fs28.readFileSync)(agentsFile, "utf8");
11497
+ text3 = (0, import_node_fs32.readFileSync)(agentsFile, "utf8");
11130
11498
  } catch {
11131
11499
  continue;
11132
11500
  }
@@ -11150,7 +11518,7 @@ function resolveConductorCursorAgentId(workspacePath) {
11150
11518
  return best?.agentId ?? null;
11151
11519
  }
11152
11520
  async function adoptThread(input) {
11153
- if (!(0, import_node_fs28.existsSync)(input.worktreePath)) {
11521
+ if (!(0, import_node_fs32.existsSync)(input.worktreePath)) {
11154
11522
  throw new Error(`Worktree not found: ${input.worktreePath}`);
11155
11523
  }
11156
11524
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -11174,23 +11542,23 @@ async function adoptThread(input) {
11174
11542
  return thread;
11175
11543
  }
11176
11544
  function listConductorWorkspaces() {
11177
- if (!(0, import_node_fs28.existsSync)(CONDUCTOR_DB)) {
11545
+ if (!(0, import_node_fs32.existsSync)(CONDUCTOR_DB)) {
11178
11546
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
11179
11547
  }
11180
- const tmp = (0, import_node_fs28.mkdtempSync)((0, import_node_path25.join)((0, import_node_os8.tmpdir)(), "sideboard-conductor-"));
11181
- const snapshot = (0, import_node_path25.join)(tmp, "conductor.db");
11548
+ const tmp = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
11549
+ const snapshot = (0, import_node_path30.join)(tmp, "conductor.db");
11182
11550
  try {
11183
- (0, import_node_fs28.copyFileSync)(CONDUCTOR_DB, snapshot);
11551
+ (0, import_node_fs32.copyFileSync)(CONDUCTOR_DB, snapshot);
11184
11552
  for (const suffix of ["-wal", "-shm"]) {
11185
11553
  const src = `${CONDUCTOR_DB}${suffix}`;
11186
- if ((0, import_node_fs28.existsSync)(src)) {
11554
+ if ((0, import_node_fs32.existsSync)(src)) {
11187
11555
  try {
11188
- (0, import_node_fs28.copyFileSync)(src, `${snapshot}${suffix}`);
11556
+ (0, import_node_fs32.copyFileSync)(src, `${snapshot}${suffix}`);
11189
11557
  } catch {
11190
11558
  }
11191
11559
  }
11192
11560
  }
11193
- const db = new import_better_sqlite3.default(snapshot, { readonly: true, fileMustExist: true });
11561
+ const db = openReadonlySqlite(snapshot);
11194
11562
  try {
11195
11563
  const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all();
11196
11564
  const names = new Set(tables.map((t) => t.name));
@@ -11261,27 +11629,27 @@ function listConductorWorkspaces() {
11261
11629
  db.close();
11262
11630
  }
11263
11631
  } finally {
11264
- (0, import_node_fs28.rmSync)(tmp, { recursive: true, force: true });
11632
+ (0, import_node_fs32.rmSync)(tmp, { recursive: true, force: true });
11265
11633
  }
11266
11634
  }
11267
11635
  function importConductorWorkspace(workspaceId) {
11268
- if (!(0, import_node_fs28.existsSync)(CONDUCTOR_DB)) {
11636
+ if (!(0, import_node_fs32.existsSync)(CONDUCTOR_DB)) {
11269
11637
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
11270
11638
  }
11271
- const tmp = (0, import_node_fs28.mkdtempSync)((0, import_node_path25.join)((0, import_node_os8.tmpdir)(), "sideboard-conductor-"));
11272
- const snapshot = (0, import_node_path25.join)(tmp, "conductor.db");
11639
+ const tmp = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
11640
+ const snapshot = (0, import_node_path30.join)(tmp, "conductor.db");
11273
11641
  try {
11274
- (0, import_node_fs28.copyFileSync)(CONDUCTOR_DB, snapshot);
11642
+ (0, import_node_fs32.copyFileSync)(CONDUCTOR_DB, snapshot);
11275
11643
  for (const suffix of ["-wal", "-shm"]) {
11276
11644
  const src = `${CONDUCTOR_DB}${suffix}`;
11277
- if ((0, import_node_fs28.existsSync)(src)) {
11645
+ if ((0, import_node_fs32.existsSync)(src)) {
11278
11646
  try {
11279
- (0, import_node_fs28.copyFileSync)(src, `${snapshot}${suffix}`);
11647
+ (0, import_node_fs32.copyFileSync)(src, `${snapshot}${suffix}`);
11280
11648
  } catch {
11281
11649
  }
11282
11650
  }
11283
11651
  }
11284
- const db = new import_better_sqlite3.default(snapshot, { readonly: true, fileMustExist: true });
11652
+ const db = openReadonlySqlite(snapshot);
11285
11653
  try {
11286
11654
  const row = db.prepare(
11287
11655
  `SELECT
@@ -11294,7 +11662,7 @@ function importConductorWorkspace(workspaceId) {
11294
11662
  ).get(workspaceId);
11295
11663
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
11296
11664
  const worktreePath = String(row.workspacePath);
11297
- if (!(0, import_node_fs28.existsSync)(worktreePath)) {
11665
+ if (!(0, import_node_fs32.existsSync)(worktreePath)) {
11298
11666
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
11299
11667
  }
11300
11668
  let sessionId = null;
@@ -11357,7 +11725,7 @@ function importConductorWorkspace(workspaceId) {
11357
11725
  db.close();
11358
11726
  }
11359
11727
  } finally {
11360
- (0, import_node_fs28.rmSync)(tmp, { recursive: true, force: true });
11728
+ (0, import_node_fs32.rmSync)(tmp, { recursive: true, force: true });
11361
11729
  }
11362
11730
  }
11363
11731
  async function importConductorWorkspaceAsync(workspaceId) {
@@ -11365,7 +11733,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
11365
11733
  }
11366
11734
 
11367
11735
  // src/threads/stack-layers.ts
11368
- var import_node_fs29 = require("fs");
11736
+ var import_node_fs33 = require("fs");
11369
11737
  init_run();
11370
11738
  init_stack();
11371
11739
  init_worktree();
@@ -11433,7 +11801,7 @@ async function openStackLayer(input, _onSetupLine) {
11433
11801
  let createdWorktree = false;
11434
11802
  const trees = await listWorktrees(repoPath);
11435
11803
  const checkedOut = trees.find((w) => w.branch === branchName);
11436
- if (checkedOut?.path && (0, import_node_fs29.existsSync)(checkedOut.path)) {
11804
+ if (checkedOut?.path && (0, import_node_fs33.existsSync)(checkedOut.path)) {
11437
11805
  if (input.reuseExistingWorktree !== false) {
11438
11806
  worktreePath = checkedOut.path;
11439
11807
  } else {
@@ -11575,7 +11943,7 @@ async function initStackFromThread(input, onSetupLine) {
11575
11943
  async function createPrStack(input, onSetupLine) {
11576
11944
  await requireAgent(input.agent);
11577
11945
  const repoPath = await resolveRepoRoot(input.repoPath);
11578
- if (!(0, import_node_fs29.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
11946
+ if (!(0, import_node_fs33.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
11579
11947
  if (!input.branches.length) throw new Error("At least one branch name required");
11580
11948
  const status = await detectGhStack(repoPath);
11581
11949
  if (!status.available) throw new Error(status.reason);
@@ -11642,7 +12010,7 @@ async function createPrStack(input, onSetupLine) {
11642
12010
  }
11643
12011
  }
11644
12012
  const claimed = new Set(threads.map((t) => t.worktreePath));
11645
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs29.existsSync)(bootstrap.worktreePath)) {
12013
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs33.existsSync)(bootstrap.worktreePath)) {
11646
12014
  try {
11647
12015
  await removeWorktree(repoPath, bootstrap.worktreePath, {
11648
12016
  deleteBranch: bootstrap.branchName
@@ -11657,12 +12025,12 @@ async function createPrStack(input, onSetupLine) {
11657
12025
  init_worktree();
11658
12026
 
11659
12027
  // src/diff/diff.ts
11660
- var import_node_fs30 = require("fs");
11661
- var import_node_path26 = require("path");
12028
+ var import_node_fs34 = require("fs");
12029
+ var import_node_path31 = require("path");
11662
12030
  init_run();
11663
12031
  init_worktree();
11664
12032
  async function inspectGitWorktree(worktreePath) {
11665
- if (!worktreePath || !(0, import_node_fs30.existsSync)(worktreePath)) return "missing_worktree";
12033
+ if (!worktreePath || !(0, import_node_fs34.existsSync)(worktreePath)) return "missing_worktree";
11666
12034
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
11667
12035
  reject: false
11668
12036
  });
@@ -11670,7 +12038,7 @@ async function inspectGitWorktree(worktreePath) {
11670
12038
  return "ok";
11671
12039
  }
11672
12040
  async function initializeGitRepository(worktreePath) {
11673
- if (!worktreePath || !(0, import_node_fs30.existsSync)(worktreePath)) {
12041
+ if (!worktreePath || !(0, import_node_fs34.existsSync)(worktreePath)) {
11674
12042
  throw new Error("Worktree not found");
11675
12043
  }
11676
12044
  const status = await inspectGitWorktree(worktreePath);
@@ -11805,11 +12173,11 @@ new file mode 100644
11805
12173
  };
11806
12174
  }
11807
12175
  async function untrackedPatch(worktreePath, path, maxHunk) {
11808
- const abs = (0, import_node_path26.join)(worktreePath, path);
12176
+ const abs = (0, import_node_path31.join)(worktreePath, path);
11809
12177
  try {
11810
- const st = (0, import_node_fs30.statSync)(abs);
12178
+ const st = (0, import_node_fs34.statSync)(abs);
11811
12179
  if (st.isFile() && st.size > maxHunk) {
11812
- const buf = (0, import_node_fs30.readFileSync)(abs).subarray(0, maxHunk);
12180
+ const buf = (0, import_node_fs34.readFileSync)(abs).subarray(0, maxHunk);
11813
12181
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
11814
12182
  }
11815
12183
  } catch {
@@ -12310,8 +12678,8 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
12310
12678
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
12311
12679
  assertSafeRelativePath(relativePath);
12312
12680
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
12313
- const abs = (0, import_node_path26.join)(worktreePath, relativePath);
12314
- const st = (0, import_node_fs30.statSync)(abs);
12681
+ const abs = (0, import_node_path31.join)(worktreePath, relativePath);
12682
+ const st = (0, import_node_fs34.statSync)(abs);
12315
12683
  if (!st.isFile()) {
12316
12684
  throw new Error(`Not a file: ${relativePath}`);
12317
12685
  }
@@ -12320,7 +12688,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
12320
12688
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
12321
12689
  );
12322
12690
  }
12323
- const buf = (0, import_node_fs30.readFileSync)(abs);
12691
+ const buf = (0, import_node_fs34.readFileSync)(abs);
12324
12692
  return {
12325
12693
  path: relativePath,
12326
12694
  contentBase64: buf.toString("base64"),
@@ -12330,12 +12698,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
12330
12698
  function readWorktreeFile(worktreePath, relativePath, opts) {
12331
12699
  assertSafeRelativePath(relativePath);
12332
12700
  const maxBytes = opts?.maxBytes ?? 2e5;
12333
- const abs = (0, import_node_path26.join)(worktreePath, relativePath);
12334
- const st = (0, import_node_fs30.statSync)(abs);
12701
+ const abs = (0, import_node_path31.join)(worktreePath, relativePath);
12702
+ const st = (0, import_node_fs34.statSync)(abs);
12335
12703
  if (!st.isFile()) {
12336
12704
  throw new Error(`Not a file: ${relativePath}`);
12337
12705
  }
12338
- const buf = (0, import_node_fs30.readFileSync)(abs);
12706
+ const buf = (0, import_node_fs34.readFileSync)(abs);
12339
12707
  if (isImageRelativePath(relativePath)) {
12340
12708
  const maxImageBytes = Math.max(maxBytes, 15e6);
12341
12709
  const truncated2 = buf.length > maxImageBytes;
@@ -12378,9 +12746,9 @@ function assertSafeRelativePath(relativePath) {
12378
12746
  }
12379
12747
  function writeWorktreeFile(worktreePath, relativePath, content) {
12380
12748
  assertSafeRelativePath(relativePath);
12381
- const abs = (0, import_node_path26.join)(worktreePath, relativePath);
12382
- (0, import_node_fs30.mkdirSync)((0, import_node_path26.dirname)(abs), { recursive: true });
12383
- (0, import_node_fs30.writeFileSync)(abs, content, "utf8");
12749
+ const abs = (0, import_node_path31.join)(worktreePath, relativePath);
12750
+ (0, import_node_fs34.mkdirSync)((0, import_node_path31.dirname)(abs), { recursive: true });
12751
+ (0, import_node_fs34.writeFileSync)(abs, content, "utf8");
12384
12752
  return { path: relativePath };
12385
12753
  }
12386
12754
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -12484,9 +12852,9 @@ async function confirmLand(thread, opts) {
12484
12852
  }
12485
12853
 
12486
12854
  // src/skills/discover.ts
12487
- var import_node_fs31 = require("fs");
12488
- var import_node_os9 = require("os");
12489
- var import_node_path27 = require("path");
12855
+ var import_node_fs35 = require("fs");
12856
+ var import_node_os11 = require("os");
12857
+ var import_node_path32 = require("path");
12490
12858
  function toCommand(name) {
12491
12859
  return name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
12492
12860
  }
@@ -12518,7 +12886,7 @@ function parseFrontmatter(content) {
12518
12886
  }
12519
12887
  function readSkill(skillMd, source) {
12520
12888
  try {
12521
- const content = (0, import_node_fs31.readFileSync)(skillMd, "utf8");
12889
+ const content = (0, import_node_fs35.readFileSync)(skillMd, "utf8");
12522
12890
  const { name: fmName, description } = parseFrontmatter(content);
12523
12891
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
12524
12892
  const name = fmName || dirName;
@@ -12537,19 +12905,19 @@ function readSkill(skillMd, source) {
12537
12905
  }
12538
12906
  }
12539
12907
  function scanSkillsDir(dir, source, out) {
12540
- if (!(0, import_node_fs31.existsSync)(dir)) return;
12908
+ if (!(0, import_node_fs35.existsSync)(dir)) return;
12541
12909
  let entries;
12542
12910
  try {
12543
- entries = (0, import_node_fs31.readdirSync)(dir);
12911
+ entries = (0, import_node_fs35.readdirSync)(dir);
12544
12912
  } catch {
12545
12913
  return;
12546
12914
  }
12547
12915
  for (const entry of entries) {
12548
12916
  if (entry.startsWith(".")) continue;
12549
- const skillMd = (0, import_node_path27.join)(dir, entry, "SKILL.md");
12550
- if (!(0, import_node_fs31.existsSync)(skillMd)) continue;
12917
+ const skillMd = (0, import_node_path32.join)(dir, entry, "SKILL.md");
12918
+ if (!(0, import_node_fs35.existsSync)(skillMd)) continue;
12551
12919
  try {
12552
- if (!(0, import_node_fs31.statSync)(skillMd).isFile()) continue;
12920
+ if (!(0, import_node_fs35.statSync)(skillMd).isFile()) continue;
12553
12921
  } catch {
12554
12922
  continue;
12555
12923
  }
@@ -12558,24 +12926,24 @@ function scanSkillsDir(dir, source, out) {
12558
12926
  }
12559
12927
  }
12560
12928
  function scanClaudePluginSkills(pluginsRoot, out) {
12561
- if (!(0, import_node_fs31.existsSync)(pluginsRoot)) return;
12929
+ if (!(0, import_node_fs35.existsSync)(pluginsRoot)) return;
12562
12930
  const walk = (dir, depth, lookingForSkillsDir) => {
12563
12931
  if (depth > 7) return;
12564
12932
  let entries;
12565
12933
  try {
12566
- entries = (0, import_node_fs31.readdirSync)(dir);
12934
+ entries = (0, import_node_fs35.readdirSync)(dir);
12567
12935
  } catch {
12568
12936
  return;
12569
12937
  }
12570
12938
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
12571
- const skill = readSkill((0, import_node_path27.join)(dir, "SKILL.md"), "cli");
12939
+ const skill = readSkill((0, import_node_path32.join)(dir, "SKILL.md"), "cli");
12572
12940
  if (skill) out.push(skill);
12573
12941
  }
12574
12942
  for (const entry of entries) {
12575
12943
  if (entry === "node_modules" || entry === ".git") continue;
12576
- const full = (0, import_node_path27.join)(dir, entry);
12944
+ const full = (0, import_node_path32.join)(dir, entry);
12577
12945
  try {
12578
- if (!(0, import_node_fs31.statSync)(full).isDirectory()) continue;
12946
+ if (!(0, import_node_fs35.statSync)(full).isDirectory()) continue;
12579
12947
  } catch {
12580
12948
  continue;
12581
12949
  }
@@ -12590,20 +12958,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
12590
12958
  walk(pluginsRoot, 0, false);
12591
12959
  }
12592
12960
  function discoverSkills(worktreePath) {
12593
- const home = (0, import_node_os9.homedir)();
12961
+ const home = (0, import_node_os11.homedir)();
12594
12962
  const collected = [];
12595
12963
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
12596
- scanSkillsDir((0, import_node_path27.join)(worktreePath, rel), "workspace", collected);
12964
+ scanSkillsDir((0, import_node_path32.join)(worktreePath, rel), "workspace", collected);
12597
12965
  }
12598
12966
  for (const abs of [
12599
- (0, import_node_path27.join)(home, ".claude/skills"),
12600
- (0, import_node_path27.join)(home, ".cursor/skills"),
12601
- (0, import_node_path27.join)(home, ".sideboard/skills"),
12602
- (0, import_node_path27.join)(home, ".brightsy/skills")
12967
+ (0, import_node_path32.join)(home, ".claude/skills"),
12968
+ (0, import_node_path32.join)(home, ".cursor/skills"),
12969
+ (0, import_node_path32.join)(home, ".sideboard/skills"),
12970
+ (0, import_node_path32.join)(home, ".brightsy/skills")
12603
12971
  ]) {
12604
12972
  scanSkillsDir(abs, "user", collected);
12605
12973
  }
12606
- scanClaudePluginSkills((0, import_node_path27.join)(home, ".claude/plugins"), collected);
12974
+ scanClaudePluginSkills((0, import_node_path32.join)(home, ".claude/plugins"), collected);
12607
12975
  const rank = { workspace: 0, user: 1, cli: 2 };
12608
12976
  const byCommand = /* @__PURE__ */ new Map();
12609
12977
  for (const skill of collected) {
@@ -12615,7 +12983,7 @@ function discoverSkills(worktreePath) {
12615
12983
  return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
12616
12984
  }
12617
12985
  function readSkillBody(skillPath, maxChars = 12e3) {
12618
- const raw = (0, import_node_fs31.readFileSync)(skillPath, "utf8");
12986
+ const raw = (0, import_node_fs35.readFileSync)(skillPath, "utf8");
12619
12987
  if (raw.startsWith("---")) {
12620
12988
  const end = raw.indexOf("\n---", 3);
12621
12989
  if (end >= 0) {
@@ -12708,8 +13076,8 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
12708
13076
  }
12709
13077
 
12710
13078
  // src/composer/stage-files.ts
12711
- var import_node_fs32 = require("fs");
12712
- var import_node_path28 = require("path");
13079
+ var import_node_fs36 = require("fs");
13080
+ var import_node_path33 = require("path");
12713
13081
  var import_node_crypto7 = require("crypto");
12714
13082
  init_workspace_scratch();
12715
13083
  var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
@@ -12735,7 +13103,7 @@ var IMAGE_MIME_BY_EXT = {
12735
13103
  var MAX_INLINE_BYTES = 4e5;
12736
13104
  var MAX_PREVIEW_BYTES = 5e6;
12737
13105
  function fileExtension(filePath) {
12738
- const base = (0, import_node_path28.basename)(filePath).toLowerCase();
13106
+ const base = (0, import_node_path33.basename)(filePath).toLowerCase();
12739
13107
  return base.includes(".") ? base.split(".").pop() || "" : "";
12740
13108
  }
12741
13109
  function isImageFilePath(filePath) {
@@ -12745,22 +13113,22 @@ function imageMimeType(filePath) {
12745
13113
  return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
12746
13114
  }
12747
13115
  function ensureAttachmentsDir(worktreePath) {
12748
- const dir = (0, import_node_path28.join)(worktreePath, ATTACHMENTS_DIR);
12749
- (0, import_node_fs32.mkdirSync)(dir, { recursive: true });
12750
- const gi = (0, import_node_path28.join)(dir, ".gitignore");
12751
- if (!(0, import_node_fs32.existsSync)(gi)) {
12752
- (0, import_node_fs32.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
13116
+ const dir = (0, import_node_path33.join)(worktreePath, ATTACHMENTS_DIR);
13117
+ (0, import_node_fs36.mkdirSync)(dir, { recursive: true });
13118
+ const gi = (0, import_node_path33.join)(dir, ".gitignore");
13119
+ if (!(0, import_node_fs36.existsSync)(gi)) {
13120
+ (0, import_node_fs36.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
12753
13121
  }
12754
13122
  return dir;
12755
13123
  }
12756
13124
  function uniqueAttachmentName(dir, originalName) {
12757
13125
  const safe = originalName.replace(/[/\\]/g, "_") || "file";
12758
- if (!(0, import_node_fs32.existsSync)((0, import_node_path28.join)(dir, safe))) return safe;
12759
- const ext = (0, import_node_path28.extname)(safe);
13126
+ if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(dir, safe))) return safe;
13127
+ const ext = (0, import_node_path33.extname)(safe);
12760
13128
  const stem = ext ? safe.slice(0, -ext.length) : safe;
12761
13129
  for (let i = 1; i < 1e4; i++) {
12762
13130
  const candidate = `${stem}-${i}${ext}`;
12763
- if (!(0, import_node_fs32.existsSync)((0, import_node_path28.join)(dir, candidate))) return candidate;
13131
+ if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(dir, candidate))) return candidate;
12764
13132
  }
12765
13133
  return `${stem}-${(0, import_node_crypto7.randomUUID)()}${ext}`;
12766
13134
  }
@@ -12816,15 +13184,15 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
12816
13184
  const dir = ensureAttachmentsDir(worktreePath);
12817
13185
  const out = [];
12818
13186
  for (const abs of absolutePaths) {
12819
- const originalName = (0, import_node_path28.basename)(abs);
13187
+ const originalName = (0, import_node_path33.basename)(abs);
12820
13188
  try {
12821
- const st = (0, import_node_fs32.statSync)(abs);
13189
+ const st = (0, import_node_fs36.statSync)(abs);
12822
13190
  if (!st.isFile()) continue;
12823
13191
  const name = uniqueAttachmentName(dir, originalName);
12824
- const destAbs = (0, import_node_path28.join)(dir, name);
12825
- (0, import_node_fs32.copyFileSync)(abs, destAbs);
13192
+ const destAbs = (0, import_node_path33.join)(dir, name);
13193
+ (0, import_node_fs36.copyFileSync)(abs, destAbs);
12826
13194
  const rel = `${ATTACHMENTS_DIR}/${name}`;
12827
- const buf = (0, import_node_fs32.readFileSync)(destAbs);
13195
+ const buf = (0, import_node_fs36.readFileSync)(destAbs);
12828
13196
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
12829
13197
  } catch (err) {
12830
13198
  out.push({
@@ -12846,8 +13214,8 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
12846
13214
  try {
12847
13215
  const buf = Buffer.from(item.dataBase64, "base64");
12848
13216
  const name = uniqueAttachmentName(dir, originalName);
12849
- const destAbs = (0, import_node_path28.join)(dir, name);
12850
- (0, import_node_fs32.writeFileSync)(destAbs, buf);
13217
+ const destAbs = (0, import_node_path33.join)(dir, name);
13218
+ (0, import_node_fs36.writeFileSync)(destAbs, buf);
12851
13219
  const rel = `${ATTACHMENTS_DIR}/${name}`;
12852
13220
  out.push(attachmentFromBuffer(name, buf, { path: rel }));
12853
13221
  } catch (err) {
@@ -12867,18 +13235,18 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
12867
13235
  if (!rel || rel.includes("..") || rel.startsWith("/")) {
12868
13236
  out.push({
12869
13237
  id: (0, import_node_crypto7.randomUUID)(),
12870
- name: (0, import_node_path28.basename)(rel) || "file",
13238
+ name: (0, import_node_path33.basename)(rel) || "file",
12871
13239
  kind: "file",
12872
13240
  content: `(invalid path: ${rel})`
12873
13241
  });
12874
13242
  continue;
12875
13243
  }
12876
- const name = (0, import_node_path28.basename)(rel);
13244
+ const name = (0, import_node_path33.basename)(rel);
12877
13245
  try {
12878
- const abs = (0, import_node_path28.join)(worktreePath, rel);
12879
- const st = (0, import_node_fs32.statSync)(abs);
13246
+ const abs = (0, import_node_path33.join)(worktreePath, rel);
13247
+ const st = (0, import_node_fs36.statSync)(abs);
12880
13248
  if (!st.isFile()) continue;
12881
- const buf = (0, import_node_fs32.readFileSync)(abs);
13249
+ const buf = (0, import_node_fs36.readFileSync)(abs);
12882
13250
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
12883
13251
  } catch (err) {
12884
13252
  out.push({
@@ -12893,8 +13261,8 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
12893
13261
  }
12894
13262
 
12895
13263
  // src/agents/instructions.ts
12896
- var import_node_fs33 = require("fs");
12897
- var import_node_path29 = require("path");
13264
+ var import_node_fs37 = require("fs");
13265
+ var import_node_path34 = require("path");
12898
13266
  init_git_auth_mode();
12899
13267
  init_worktree_labels();
12900
13268
  function normPath3(p) {
@@ -13027,9 +13395,10 @@ function formatArtifactDirective() {
13027
13395
  "Files / media browser (CMS file manager column):",
13028
13396
  "4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
13029
13397
  " Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
13030
- "Multiple-choice questions (any mode \u2014 not only Plan):",
13031
- "5) Call Sideboard MCP `ask_user` when the user should pick from predefined options (approach forks, requirements, which API). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. Do not ask multiple-choice questions as plain chat bullets \u2014 use ask_user so Sideboard shows the composer picker.",
13032
- "Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user for predefined-option questions."
13398
+ "Multiple-choice questions:",
13399
+ "5) Call Sideboard MCP `ask_user` only when work is blocked on choosing among a few concrete options (approach forks, which API, auth vs cookies). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. If you are asking a real multiple-choice, use ask_user rather than chat bullets so Sideboard shows the composer picker.",
13400
+ "Do not call ask_user for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat. If one option is the obvious default, proceed without asking.",
13401
+ "Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
13033
13402
  ].join("\n");
13034
13403
  }
13035
13404
  function formatUiReminder() {
@@ -13040,7 +13409,7 @@ function formatUiReminder() {
13040
13409
  "CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
13041
13410
  "Files column: MCP present_files (brightsy account storage or memory).",
13042
13411
  "Do not say artifacts/CMS UI are unavailable.",
13043
- "Multiple-choice questions: MCP ask_user (composer picker, any mode). Explain options in chat first, then wait for answers."
13412
+ "ask_user: only when blocked on a real multiple-choice (approach fork, which API). Never for hellos, check-ins, or \u201Cwhat next?\u201D menus \u2014 reply in chat."
13044
13413
  ].join(" ");
13045
13414
  }
13046
13415
 
@@ -13168,7 +13537,7 @@ var Orchestrator = class {
13168
13537
  }
13169
13538
  continue;
13170
13539
  }
13171
- if (!(0, import_node_fs37.existsSync)(thread.worktreePath)) {
13540
+ if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
13172
13541
  setStatus(thread.id, "broken", "Worktree missing on disk");
13173
13542
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
13174
13543
  continue;
@@ -14260,8 +14629,9 @@ var Orchestrator = class {
14260
14629
  return result;
14261
14630
  }
14262
14631
  async mergePr(threadRef) {
14263
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
14632
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
14264
14633
  this.assertNotGlobal(thread, "Merge PR");
14634
+ const selector = selectors[0];
14265
14635
  if (!selector) throw new Error("No pull request linked to this thread");
14266
14636
  const result = await mergePr(cwd, selector);
14267
14637
  const state = normalizePrState(result.state) || "MERGED";
@@ -14281,29 +14651,34 @@ var Orchestrator = class {
14281
14651
  await this.persistPrMetaAndMaybeArchive(thread, metaLike);
14282
14652
  return { url: metaLike.url, state };
14283
14653
  }
14284
- /** Resolve PR selector and optionally persist `prUrl` when found. */
14654
+ /** Resolve PR selectors and optionally persist `prUrl` when found. */
14285
14655
  async withPrSelector(threadRef) {
14286
14656
  const thread = this.requireThread(threadRef);
14287
- const selector = resolvePrSelector(thread);
14657
+ const selectors = resolvePrSelectors(thread);
14288
14658
  const cwd = thread.worktreePath;
14289
14659
  if (!cwd?.trim()) {
14290
14660
  throw new Error(`Thread ${threadRef} has no worktreePath`);
14291
14661
  }
14292
- return { thread, selector, cwd };
14662
+ return { thread, selectors, cwd };
14293
14663
  }
14294
14664
  async getPrChecks(threadRef) {
14295
- const { selector, cwd } = await this.withPrSelector(threadRef);
14296
- if (!selector) return null;
14297
- return getPrChecks(cwd, selector);
14665
+ const { selectors, cwd } = await this.withPrSelector(threadRef);
14666
+ for (const selector of selectors) {
14667
+ const checks = await getPrChecks(cwd, selector);
14668
+ if (checks) return checks;
14669
+ }
14670
+ return null;
14298
14671
  }
14299
14672
  async getPrMeta(threadRef) {
14300
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
14301
- if (!selector) return null;
14302
- const meta = await getPrMeta(cwd, selector);
14303
- if (meta) {
14304
- await this.persistPrMetaAndMaybeArchive(thread, meta);
14673
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
14674
+ for (const selector of selectors) {
14675
+ const meta = await getPrMeta(cwd, selector);
14676
+ if (meta) {
14677
+ await this.persistPrMetaAndMaybeArchive(thread, meta);
14678
+ return meta;
14679
+ }
14305
14680
  }
14306
- return meta;
14681
+ return null;
14307
14682
  }
14308
14683
  /**
14309
14684
  * Persist PR URL/title/state and Conductor-style auto-archive when the PR
@@ -14427,9 +14802,12 @@ var Orchestrator = class {
14427
14802
  return { stack: result.stack, threads: result.threads };
14428
14803
  }
14429
14804
  async getPrDetails(threadRef) {
14430
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
14431
- if (!selector) return null;
14432
- const details = await getPrDetails(cwd, selector);
14805
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
14806
+ let details = null;
14807
+ for (const selector of selectors) {
14808
+ details = await getPrDetails(cwd, selector);
14809
+ if (details) break;
14810
+ }
14433
14811
  if (details) {
14434
14812
  const patch = {};
14435
14813
  if (details.url && details.url !== thread.prUrl) patch.prUrl = details.url;
@@ -14656,7 +15034,7 @@ var Orchestrator = class {
14656
15034
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
14657
15035
  return restored2;
14658
15036
  }
14659
- if (!(0, import_node_fs37.existsSync)(thread.worktreePath)) {
15037
+ if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
14660
15038
  const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
14661
15039
  const { execa: execa7 } = await import("execa");
14662
15040
  const slug = thread.worktreePath.split("/").pop();
@@ -15823,6 +16201,7 @@ function registerLinearTools(server) {
15823
16201
  }
15824
16202
 
15825
16203
  // src/mcp/server.ts
16204
+ init_git_auth_mode();
15826
16205
  var MAX_ORCH_THREADS = 5;
15827
16206
  var CREATE_THREAD_TIMEOUT_MS = 9e4;
15828
16207
  function withTimeout(promise, ms, label) {
@@ -15844,6 +16223,14 @@ function withTimeout(promise, ms, label) {
15844
16223
  }
15845
16224
  async function startMcpServer() {
15846
16225
  const orch = getOrchestrator();
16226
+ try {
16227
+ await warmGithubAgentAuth();
16228
+ } catch (err) {
16229
+ console.error(
16230
+ "[sideboard-mcp] GitHub agent auth warm skipped:",
16231
+ err instanceof Error ? err.message : err
16232
+ );
16233
+ }
15847
16234
  try {
15848
16235
  const { maxConcurrentAgents: maxConcurrentAgents2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
15849
16236
  orch.setMaxConcurrent(maxConcurrentAgents2());
@@ -15887,7 +16274,7 @@ async function startMcpServer() {
15887
16274
  async () => {
15888
16275
  const threads = orch.getThreads(true);
15889
16276
  const lines = threads.map((t) => {
15890
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path33.basename)(t.repoPath) || t.repoPath;
16277
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path38.basename)(t.repoPath) || t.repoPath;
15891
16278
  return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}`;
15892
16279
  });
15893
16280
  return {
@@ -15950,7 +16337,7 @@ async function startMcpServer() {
15950
16337
  );
15951
16338
  server.tool(
15952
16339
  "ask_user",
15953
- "Ask the user clarifying multiple-choice questions in Sideboard\u2019s composer (any mode \u2014 not only Plan). Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. Use when the user should pick from predefined options (approach forks, requirements, which API) \u2014 not for \u201Cis the plan ready?\u201D. After calling, stop and wait for their next message with answers.",
16340
+ "Ask the user a clarifying multiple-choice question in Sideboard\u2019s composer. Call only when work is blocked on choosing among a few concrete options (approach fork, which API, auth vs cookies). Do not call for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat instead. If one option is the obvious default, proceed without asking. Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. After calling, stop and wait for answers. Not for \u201Cis the plan ready?\u201D.",
15954
16341
  {
15955
16342
  questions: import_zod3.z.array(
15956
16343
  import_zod3.z.object({