@sideboard-ai/core 0.1.89 → 0.1.95

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-HBLA6FEV.js} +4 -4
  4. package/dist/{agents-ODBP7J6E.js → agents-WS5QV6LE.js} +5 -5
  5. package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
  6. package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
  7. package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
  8. package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
  9. package/dist/{chunk-RJLBSYUO.js → chunk-KWNUZ4LR.js} +46 -77
  10. package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
  11. package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
  12. package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
  13. package/dist/{chunk-JE75QW2I.js → chunk-WBX46OPD.js} +237 -96
  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 +1021 -473
  21. package/dist/index.d.cts +91 -20
  22. package/dist/index.d.ts +91 -20
  23. package/dist/index.js +244 -59
  24. package/dist/mcp/run-stdio.cjs +816 -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
package/dist/index.cjs CHANGED
@@ -3068,42 +3068,124 @@ var init_gh_errors = __esm({
3068
3068
  }
3069
3069
  });
3070
3070
 
3071
+ // src/git/github-agent-auth.ts
3072
+ function githubAgentAuthDir() {
3073
+ const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
3074
+ if (override) return override;
3075
+ return (0, import_node_path10.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
3076
+ }
3077
+ function githubCredentialStorePath() {
3078
+ return (0, import_node_path10.join)(githubAgentAuthDir(), "git-credentials");
3079
+ }
3080
+ function githubGhConfigDir() {
3081
+ return (0, import_node_path10.join)(githubAgentAuthDir(), "gh");
3082
+ }
3083
+ function writePrivateFile2(file, body) {
3084
+ (0, import_node_fs10.mkdirSync)((0, import_node_path10.dirname)(file), { recursive: true, mode: 448 });
3085
+ try {
3086
+ (0, import_node_fs10.chmodSync)((0, import_node_path10.dirname)(file), 448);
3087
+ } catch {
3088
+ }
3089
+ (0, import_node_fs10.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
3090
+ try {
3091
+ (0, import_node_fs10.chmodSync)(file, 384);
3092
+ } catch {
3093
+ }
3094
+ }
3095
+ function gitCredentialStoreContents(token) {
3096
+ return `https://x-access-token:${encodeURIComponent(token)}@github.com
3097
+ `;
3098
+ }
3099
+ function ghHostsYml(token, user = "x-access-token") {
3100
+ const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
3101
+ return [
3102
+ "github.com:",
3103
+ " git_protocol: https",
3104
+ ` user: ${u}`,
3105
+ ` oauth_token: ${token}`,
3106
+ " users:",
3107
+ ` ${u}:`,
3108
+ ` oauth_token: ${token}`,
3109
+ ""
3110
+ ].join("\n");
3111
+ }
3112
+ function materializeGithubAgentAuth(token, user) {
3113
+ const trimmed = token.trim();
3114
+ if (!trimmed) return;
3115
+ const root = githubAgentAuthDir();
3116
+ (0, import_node_fs10.mkdirSync)(root, { recursive: true, mode: 448 });
3117
+ try {
3118
+ (0, import_node_fs10.chmodSync)(root, 448);
3119
+ } catch {
3120
+ }
3121
+ writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
3122
+ const ghDir = githubGhConfigDir();
3123
+ (0, import_node_fs10.mkdirSync)(ghDir, { recursive: true, mode: 448 });
3124
+ writePrivateFile2((0, import_node_path10.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
3125
+ writePrivateFile2((0, import_node_path10.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
3126
+ }
3127
+ function githubAgentAuthReady() {
3128
+ return (0, import_node_fs10.existsSync)(githubCredentialStorePath()) && (0, import_node_fs10.existsSync)((0, import_node_path10.join)(githubGhConfigDir(), "hosts.yml"));
3129
+ }
3130
+ function githubCredentialHelperGitConfig() {
3131
+ const file = githubCredentialStorePath();
3132
+ return [
3133
+ { key: "credential.helper", value: "" },
3134
+ { key: "credential.helper", value: `store --file=${file}` }
3135
+ ];
3136
+ }
3137
+ function githubGhConfigEnv() {
3138
+ return {
3139
+ GH_CONFIG_DIR: githubGhConfigDir(),
3140
+ GH_PROMPT_DISABLED: "1"
3141
+ };
3142
+ }
3143
+ var import_node_fs10, import_node_os4, import_node_path10;
3144
+ var init_github_agent_auth = __esm({
3145
+ "src/git/github-agent-auth.ts"() {
3146
+ "use strict";
3147
+ import_node_fs10 = require("fs");
3148
+ import_node_os4 = require("os");
3149
+ import_node_path10 = require("path");
3150
+ }
3151
+ });
3152
+
3071
3153
  // src/agents/path.ts
3072
3154
  function prependPathDir(env, dir) {
3073
- if (!dir || !(0, import_node_fs10.existsSync)(dir)) return;
3155
+ if (!dir || !(0, import_node_fs11.existsSync)(dir)) return;
3074
3156
  const current = env.PATH ?? "";
3075
- const parts = current.split(import_node_path10.delimiter).filter(Boolean);
3157
+ const parts = current.split(import_node_path11.delimiter).filter(Boolean);
3076
3158
  if (parts.includes(dir)) {
3077
3159
  env.PATH = current;
3078
3160
  return;
3079
3161
  }
3080
- env.PATH = [dir, ...parts].join(import_node_path10.delimiter);
3162
+ env.PATH = [dir, ...parts].join(import_node_path11.delimiter);
3081
3163
  }
3082
- function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os4.homedir)()) {
3083
- return (0, import_node_path10.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
3164
+ function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os5.homedir)()) {
3165
+ return (0, import_node_path11.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
3084
3166
  }
3085
3167
  function isConductorBundledCli(filePath) {
3086
3168
  const p = (filePath ?? "").replace(/\\/g, "/");
3087
3169
  return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
3088
3170
  }
3089
3171
  function ensureAgentPath(env = process.env) {
3090
- const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
3172
+ const home = env.HOME || env.USERPROFILE || (0, import_node_os5.homedir)();
3091
3173
  const current = env.PATH ?? "";
3092
- const parts = current.split(import_node_path10.delimiter).filter(Boolean);
3174
+ const parts = current.split(import_node_path11.delimiter).filter(Boolean);
3093
3175
  const seen = new Set(parts);
3094
3176
  const extras = [
3095
- ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path10.join)(home, rel)),
3177
+ ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path11.join)(home, rel)),
3096
3178
  "/opt/homebrew/bin",
3097
3179
  "/usr/local/bin",
3098
3180
  // Keep after Homebrew/npm so a user-installed CLI still wins.
3099
3181
  conductorBundledBinDir(home)
3100
3182
  ];
3101
3183
  for (const dir of extras.reverse()) {
3102
- if (!dir || seen.has(dir) || !(0, import_node_fs10.existsSync)(dir)) continue;
3184
+ if (!dir || seen.has(dir) || !(0, import_node_fs11.existsSync)(dir)) continue;
3103
3185
  parts.unshift(dir);
3104
3186
  seen.add(dir);
3105
3187
  }
3106
- const next = parts.join(import_node_path10.delimiter);
3188
+ const next = parts.join(import_node_path11.delimiter);
3107
3189
  env.PATH = next;
3108
3190
  return next;
3109
3191
  }
@@ -3117,7 +3199,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
3117
3199
  stdio: ["ignore", "pipe", "ignore"]
3118
3200
  }).trim().split(/\r?\n/).find(Boolean);
3119
3201
  if (prefix) {
3120
- const binDir = process.platform === "win32" ? prefix : (0, import_node_path10.join)(prefix, "bin");
3202
+ const binDir = process.platform === "win32" ? prefix : (0, import_node_path11.join)(prefix, "bin");
3121
3203
  prependPathDir(env, binDir);
3122
3204
  }
3123
3205
  } catch {
@@ -3145,14 +3227,14 @@ function withExportedPath(command, pathValue) {
3145
3227
  if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
3146
3228
  return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
3147
3229
  }
3148
- var import_node_fs10, import_node_child_process3, import_node_os4, import_node_path10, EXTRA_BIN_DIRS;
3230
+ var import_node_fs11, import_node_child_process3, import_node_os5, import_node_path11, EXTRA_BIN_DIRS;
3149
3231
  var init_path = __esm({
3150
3232
  "src/agents/path.ts"() {
3151
3233
  "use strict";
3152
- import_node_fs10 = require("fs");
3234
+ import_node_fs11 = require("fs");
3153
3235
  import_node_child_process3 = require("child_process");
3154
- import_node_os4 = require("os");
3155
- import_node_path10 = require("path");
3236
+ import_node_os5 = require("os");
3237
+ import_node_path11 = require("path");
3156
3238
  EXTRA_BIN_DIRS = [
3157
3239
  ".local/bin",
3158
3240
  ".cargo/bin",
@@ -3277,42 +3359,46 @@ function appendIndexedGitConfig(existing, entries) {
3277
3359
  return out;
3278
3360
  }
3279
3361
  function githubAgentGitEnv(existing) {
3280
- return appendIndexedGitConfig(existing, HTTPS_REWRITE);
3281
- }
3282
- function githubHttpsBearerEnv(existing, token) {
3283
- const rewrite = githubAgentGitEnv(existing);
3284
- const header = appendIndexedGitConfig(
3285
- { ...existing, ...rewrite },
3286
- [
3287
- {
3288
- key: "http.https://github.com/.extraHeader",
3289
- value: `AUTHORIZATION: bearer ${token}`
3290
- }
3291
- ]
3292
- );
3293
- return { ...rewrite, ...header };
3362
+ const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
3363
+ return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
3294
3364
  }
3295
3365
  function applyGithubGitAuthEnv(existing, opts) {
3296
3366
  const out = { ...nonInteractiveGitProcessEnv() };
3367
+ const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
3368
+ if (token) materializeGithubAgentAuth(token);
3369
+ Object.assign(out, githubGhConfigEnv());
3297
3370
  if (opts.mode === "ssh") return out;
3298
- const existingToken = existing?.GH_TOKEN?.trim() || "";
3299
- const provided = existingToken ? "" : opts.token?.trim() || "";
3300
- const token = existingToken || provided;
3301
- Object.assign(
3302
- out,
3303
- token ? githubHttpsBearerEnv(existing, token) : githubAgentGitEnv(existing)
3304
- );
3305
- if (provided) out.GH_TOKEN = provided;
3371
+ Object.assign(out, githubAgentGitEnv(existing));
3306
3372
  return out;
3307
3373
  }
3374
+ function scrubGithubTokensFromChildEnv(env) {
3375
+ for (const key of GITHUB_CHILD_TOKEN_KEYS) {
3376
+ delete env[key];
3377
+ }
3378
+ }
3379
+ function mergeAgentGitAuthEnv(env, gitEnv) {
3380
+ Object.assign(env, gitEnv);
3381
+ scrubGithubTokensFromChildEnv(env);
3382
+ }
3308
3383
  async function resolveGithubAgentToken(mode, cwd) {
3309
- if (mode === "ssh") return null;
3310
- if (mode === "token") return getGithubPat();
3311
- try {
3312
- return await resolveGhAuthToken(cwd);
3313
- } catch {
3314
- return null;
3384
+ if (tokenMemo && tokenMemo.mode === mode && Date.now() - tokenMemo.at < TOKEN_TTL_MS) {
3385
+ return tokenMemo.value;
3386
+ }
3387
+ let value = null;
3388
+ if (mode === "token") {
3389
+ value = getGithubPat();
3390
+ } else {
3391
+ try {
3392
+ value = await resolveGhAuthToken(cwd);
3393
+ } catch {
3394
+ value = null;
3395
+ }
3315
3396
  }
3397
+ tokenMemo = { mode, value, at: Date.now() };
3398
+ return value;
3399
+ }
3400
+ function resetGithubAgentTokenMemo() {
3401
+ tokenMemo = null;
3316
3402
  }
3317
3403
  async function resolveAgentGitAuthEnv(existing, opts) {
3318
3404
  let mode = "auto";
@@ -3334,7 +3420,40 @@ async function resolveAgentGitAuthEnv(existing, opts) {
3334
3420
  }
3335
3421
  return applyGithubGitAuthEnv(existing, { mode, token });
3336
3422
  }
3337
- function codexUnattendedGitConfigArgs(sandbox) {
3423
+ async function warmGithubAgentAuth(opts) {
3424
+ if (!opts?.force && githubAgentAuthReady()) return;
3425
+ await resolveAgentGitAuthEnv(void 0, opts);
3426
+ }
3427
+ function normalizeWritableRoot(raw) {
3428
+ const trimmed = raw.trim().replace(/\/+$/, "");
3429
+ return trimmed && (0, import_node_path12.isAbsolute)(trimmed) ? trimmed : null;
3430
+ }
3431
+ async function resolveCodexGitWritableRoots(cwd) {
3432
+ const roots = /* @__PURE__ */ new Set();
3433
+ const authDir = normalizeWritableRoot(githubAgentAuthDir());
3434
+ if (authDir) roots.add(authDir);
3435
+ try {
3436
+ const [gitDir, commonDir] = await Promise.all([
3437
+ git(["rev-parse", "--absolute-git-dir"], cwd, { reject: false, timeoutMs: 5e3 }),
3438
+ git(["rev-parse", "--path-format=absolute", "--git-common-dir"], cwd, {
3439
+ reject: false,
3440
+ timeoutMs: 5e3
3441
+ })
3442
+ ]);
3443
+ const gitDirPath = gitDir.exitCode === 0 ? normalizeWritableRoot(gitDir.stdout) : null;
3444
+ const commonPath = commonDir.exitCode === 0 ? normalizeWritableRoot(commonDir.stdout) : null;
3445
+ if (gitDirPath) roots.add(gitDirPath);
3446
+ if (commonPath) roots.add(commonPath);
3447
+ } catch {
3448
+ }
3449
+ return [...roots];
3450
+ }
3451
+ function codexSandboxWritableRootsArgs(roots) {
3452
+ const abs = [...new Set(roots.map(normalizeWritableRoot).filter(Boolean))];
3453
+ if (abs.length === 0) return [];
3454
+ return ["-c", `sandbox_workspace_write.writable_roots=${JSON.stringify(abs)}`];
3455
+ }
3456
+ function codexUnattendedGitConfigArgs(sandbox, opts) {
3338
3457
  const args = [
3339
3458
  "-c",
3340
3459
  'shell_environment_policy.inherit="all"',
@@ -3343,54 +3462,65 @@ function codexUnattendedGitConfigArgs(sandbox) {
3343
3462
  ];
3344
3463
  if (sandbox === "workspace-write") {
3345
3464
  args.push("-c", "sandbox_workspace_write.network_access=true");
3465
+ args.push(...codexSandboxWritableRootsArgs(opts?.writableRoots ?? []));
3346
3466
  }
3347
3467
  return args;
3348
3468
  }
3349
3469
  function formatGitAuthModeDirective(mode) {
3470
+ const shared = [
3471
+ "- `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.",
3472
+ "- Do not set GitHub token environment variables, pass `--with-token`, or run `gh auth login` from this turn.",
3473
+ "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below.",
3474
+ "- 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."
3475
+ ];
3350
3476
  switch (mode) {
3351
3477
  case "gh":
3352
3478
  return [
3353
3479
  "Git authentication (Account \u2192 GitHub mode: gh CLI):",
3354
3480
  "- This process rewrites `git@github.com:` and `ssh://git@github.com/` to HTTPS.",
3355
- "- `GH_TOKEN` is injected from `gh auth token` (no macOS Keychain prompts). Do not switch remotes to SSH.",
3356
- "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
3481
+ ...shared
3357
3482
  ].join("\n");
3358
3483
  case "ssh":
3359
3484
  return [
3360
3485
  "Git authentication (Account \u2192 GitHub mode: SSH):",
3361
3486
  "- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
3362
3487
  "- 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.",
3363
- "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below (API still uses `gh`)."
3488
+ "- `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.",
3489
+ "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
3364
3490
  ].join("\n");
3365
3491
  case "token":
3366
3492
  return [
3367
3493
  "Git authentication (Account \u2192 GitHub mode: personal access token):",
3368
3494
  "- This process rewrites GitHub SSH remotes to HTTPS.",
3369
- "- `GH_TOKEN` is set in the environment. Use HTTPS git and `gh`; do not paste the token into commands or chat.",
3370
- "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
3495
+ ...shared
3371
3496
  ].join("\n");
3372
3497
  case "auto":
3373
3498
  default:
3374
3499
  return [
3375
3500
  "Git authentication (Account \u2192 GitHub mode: auto):",
3376
- "- 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).",
3377
- "- Do not switch remotes to SSH. Push with `git push -u origin HEAD`.",
3378
- "- 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."
3501
+ "- This process rewrites GitHub SSH remotes to HTTPS so git/ssh never prompt the macOS Keychain (required for unattended orchestrator turns).",
3502
+ ...shared
3379
3503
  ].join("\n");
3380
3504
  }
3381
3505
  }
3382
- var HTTPS_REWRITE;
3506
+ var import_node_path12, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
3383
3507
  var init_git_auth_mode = __esm({
3384
3508
  "src/git/git-auth-mode.ts"() {
3385
3509
  "use strict";
3510
+ import_node_path12 = require("path");
3386
3511
  init_app_settings();
3512
+ init_github_agent_auth();
3387
3513
  init_run();
3388
3514
  HTTPS_REWRITE = [
3389
3515
  { key: "url.https://github.com/.insteadOf", value: "git@github.com:" },
3390
- { key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" },
3391
- // Empty helper disables ~/.gitconfig osxkeychain so GUI agents cannot pop
3392
- // "git-credential-osxkeychain wants to use the keychain".
3393
- { key: "credential.helper", value: "" }
3516
+ { key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
3517
+ ];
3518
+ TOKEN_TTL_MS = 12 * 60 * 60 * 1e3;
3519
+ tokenMemo = null;
3520
+ GITHUB_CHILD_TOKEN_KEYS = [
3521
+ "GH_TOKEN",
3522
+ "GITHUB_TOKEN",
3523
+ "GH_ENTERPRISE_TOKEN"
3394
3524
  ];
3395
3525
  }
3396
3526
  });
@@ -3751,10 +3881,12 @@ __export(worktree_exports, {
3751
3881
  getPr: () => getPr,
3752
3882
  getPrChecks: () => getPrChecks,
3753
3883
  getPrDetails: () => getPrDetails,
3884
+ getPrForHeadBranch: () => getPrForHeadBranch,
3754
3885
  getPrMeta: () => getPrMeta,
3755
3886
  ghHeadRef: () => ghHeadRef,
3756
3887
  ghRepoSelectArgs: () => ghRepoSelectArgs,
3757
3888
  githubAgentGitEnv: () => githubAgentGitEnv,
3889
+ isDefaultishSourceRef: () => isDefaultishSourceRef,
3758
3890
  isDirty: () => isDirty,
3759
3891
  isPlaceholderBranch: () => isPlaceholderBranch,
3760
3892
  isSideboardScratchPath: () => isSideboardScratchPath,
@@ -3772,6 +3904,7 @@ __export(worktree_exports, {
3772
3904
  resolveDiffBaseRef: () => resolveDiffBaseRef,
3773
3905
  resolveGithubRepoSlug: () => resolveGithubRepoSlug,
3774
3906
  resolvePrSelector: () => resolvePrSelector,
3907
+ resolvePrSelectors: () => resolvePrSelectors,
3775
3908
  resolveRepoRoot: () => resolveRepoRoot,
3776
3909
  resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
3777
3910
  slugify: () => slugify,
@@ -3880,7 +4013,7 @@ async function originGhRepoEnv(cwd, opts) {
3880
4013
  await ensureGhPreferOrigin(cwd);
3881
4014
  const slug = await resolveGithubRepoSlug(cwd);
3882
4015
  const mode = opts?.mode ?? getGithubGitAuthMode();
3883
- const token = mode === "token" ? getGithubPat() : mode === "ssh" ? null : await resolveGhAuthToken(cwd);
4016
+ const token = await resolveGithubAgentToken(mode, cwd);
3884
4017
  return {
3885
4018
  ...applyGithubGitAuthEnv(opts?.env, { mode, token }),
3886
4019
  ...slug ? { GH_REPO: slug } : {}
@@ -4020,13 +4153,78 @@ async function getPr(repoPath, number) {
4020
4153
  if (exitCode !== 0 || !stdout.trim()) return null;
4021
4154
  return JSON.parse(stdout);
4022
4155
  }
4023
- function resolvePrSelector(thread) {
4024
- if (thread.prUrl?.trim()) return thread.prUrl.trim();
4156
+ function normalizeGitBranchName(ref) {
4157
+ return ref.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
4158
+ }
4159
+ function isDefaultishSourceRef(ref) {
4160
+ const n = normalizeGitBranchName(ref ?? "").toLowerCase();
4161
+ return !n || n === "head" || n === "default" || n === "main" || n === "master" || n === "develop" || n === "trunk";
4162
+ }
4163
+ function resolvePrSelectors(thread) {
4164
+ const out = [];
4165
+ const push = (value) => {
4166
+ const v = value?.trim();
4167
+ if (!v || out.includes(v)) return;
4168
+ out.push(v);
4169
+ };
4170
+ push(thread.prUrl);
4025
4171
  if (thread.sourceType === "pr" && thread.sourceRef?.trim()) {
4026
- return thread.sourceRef.replace(/^#/, "").trim();
4172
+ push(thread.sourceRef.replace(/^#/, "").trim());
4173
+ }
4174
+ push(thread.branchName);
4175
+ if (thread.sourceType === "branch") {
4176
+ const source = normalizeGitBranchName(thread.sourceRef ?? "");
4177
+ if (source && !isDefaultishSourceRef(source) && source !== thread.branchName?.trim()) {
4178
+ push(source);
4179
+ }
4180
+ }
4181
+ return out;
4182
+ }
4183
+ function resolvePrSelector(thread) {
4184
+ return resolvePrSelectors(thread)[0] ?? null;
4185
+ }
4186
+ async function getPrForHeadBranch(repoPath, branch) {
4187
+ const head = normalizeGitBranchName(branch);
4188
+ if (!head || isDefaultishSourceRef(head)) return null;
4189
+ const slug = await resolveGithubRepoSlug(repoPath);
4190
+ const viewArgs = [
4191
+ "pr",
4192
+ "view",
4193
+ head,
4194
+ "--json",
4195
+ "number,title,headRefName,url,isCrossRepository"
4196
+ ];
4197
+ if (slug) viewArgs.push("--repo", slug);
4198
+ const viewed = await gh(viewArgs, repoPath, { reject: false });
4199
+ if (viewed.exitCode === 0 && viewed.stdout.trim()) {
4200
+ try {
4201
+ return JSON.parse(viewed.stdout);
4202
+ } catch {
4203
+ return null;
4204
+ }
4205
+ }
4206
+ const listHead = slug ? ghHeadRef(slug, head) : head;
4207
+ const listArgs = [
4208
+ "pr",
4209
+ "list",
4210
+ "--head",
4211
+ listHead,
4212
+ "--json",
4213
+ "number,title,headRefName,url,isCrossRepository",
4214
+ "--limit",
4215
+ "1",
4216
+ "--state",
4217
+ "open"
4218
+ ];
4219
+ if (slug) listArgs.push("--repo", slug);
4220
+ const listed = await gh(listArgs, repoPath, { reject: false });
4221
+ if (listed.exitCode !== 0 || !listed.stdout.trim()) return null;
4222
+ try {
4223
+ const rows = JSON.parse(listed.stdout);
4224
+ return rows[0] ?? null;
4225
+ } catch {
4226
+ return null;
4027
4227
  }
4028
- if (thread.branchName?.trim()) return thread.branchName.trim();
4029
- return null;
4030
4228
  }
4031
4229
  function normalizeGhTime(value) {
4032
4230
  if (typeof value !== "string" || !value.trim()) return null;
@@ -4352,7 +4550,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
4352
4550
  const label = opts?.ghAuth ? `${remote} (gh auth)` : remote;
4353
4551
  const gitOpts = { reject: false };
4354
4552
  if (opts?.ghAuth) {
4355
- const token = await resolveGhAuthToken(repoPath);
4553
+ const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
4356
4554
  if (!token) {
4357
4555
  errors.push(`${label}: gh auth token unavailable`);
4358
4556
  return false;
@@ -4403,7 +4601,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
4403
4601
  const ensureOid = async (remote, opts) => {
4404
4602
  const gitOpts = { reject: false };
4405
4603
  if (opts?.ghAuth) {
4406
- const token = await resolveGhAuthToken(repoPath);
4604
+ const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
4407
4605
  if (!token) return false;
4408
4606
  gitOpts.env = { GIT_TERMINAL_PROMPT: "0" };
4409
4607
  gitOpts.config = {
@@ -4471,8 +4669,8 @@ function isLocalPrFetchBranch(ref) {
4471
4669
  }
4472
4670
  async function createThreadWorktree(opts) {
4473
4671
  let branchName = `thread/${opts.slug}`;
4474
- const worktreePath = (0, import_node_path11.join)(worktreesRoot(opts.repoPath), opts.slug);
4475
- if ((0, import_node_fs11.existsSync)(worktreePath)) {
4672
+ const worktreePath = (0, import_node_path13.join)(worktreesRoot(opts.repoPath), opts.slug);
4673
+ if ((0, import_node_fs12.existsSync)(worktreePath)) {
4476
4674
  throw new Error(`Worktree already exists at ${worktreePath}`);
4477
4675
  }
4478
4676
  await ensureGhPreferOrigin(opts.repoPath);
@@ -4541,8 +4739,8 @@ ${add.stdout}`;
4541
4739
  async function createExistingBranchWorktree(opts) {
4542
4740
  const branchName = opts.branchName.trim();
4543
4741
  if (!branchName) throw new Error("branch name required");
4544
- const worktreePath = (0, import_node_path11.join)(worktreesRoot(opts.repoPath), opts.slug);
4545
- if ((0, import_node_fs11.existsSync)(worktreePath)) {
4742
+ const worktreePath = (0, import_node_path13.join)(worktreesRoot(opts.repoPath), opts.slug);
4743
+ if ((0, import_node_fs12.existsSync)(worktreePath)) {
4546
4744
  throw new Error(`Worktree already exists at ${worktreePath}`);
4547
4745
  }
4548
4746
  await ensureGhPreferOrigin(opts.repoPath);
@@ -4653,7 +4851,7 @@ async function pushBranch(worktreePath, branchName) {
4653
4851
  if (ssh.exitCode === 0) return;
4654
4852
  const sshErr = (ssh.stderr || ssh.stdout).trim();
4655
4853
  const slug = await resolveGithubRepoSlug(worktreePath);
4656
- const token = await resolveGhAuthToken(worktreePath);
4854
+ const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
4657
4855
  if (!slug || !token) {
4658
4856
  throw new Error(
4659
4857
  sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
@@ -4830,10 +5028,10 @@ function sameRepoPath(a, b) {
4830
5028
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
4831
5029
  }
4832
5030
  function listLocalThreadBranchSlugs(repoPath) {
4833
- const refsDir = (0, import_node_path11.join)(repoPath, ".git", "refs", "heads", "thread");
4834
- if (!(0, import_node_fs11.existsSync)(refsDir)) return [];
5031
+ const refsDir = (0, import_node_path13.join)(repoPath, ".git", "refs", "heads", "thread");
5032
+ if (!(0, import_node_fs12.existsSync)(refsDir)) return [];
4835
5033
  try {
4836
- return (0, import_node_fs11.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
5034
+ return (0, import_node_fs12.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
4837
5035
  } catch {
4838
5036
  return [];
4839
5037
  }
@@ -4841,8 +5039,8 @@ function listLocalThreadBranchSlugs(repoPath) {
4841
5039
  function collectTakenTeamSlugs(repoPath) {
4842
5040
  const taken = /* @__PURE__ */ new Set();
4843
5041
  const root = worktreesRoot(repoPath);
4844
- if ((0, import_node_fs11.existsSync)(root)) {
4845
- for (const entry of (0, import_node_fs11.readdirSync)(root, { withFileTypes: true })) {
5042
+ if ((0, import_node_fs12.existsSync)(root)) {
5043
+ for (const entry of (0, import_node_fs12.readdirSync)(root, { withFileTypes: true })) {
4846
5044
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
4847
5045
  taken.add(normalizeTakenSlug(entry.name));
4848
5046
  }
@@ -4863,18 +5061,18 @@ function allocateTeamSlug(repoPath) {
4863
5061
  const taken = collectTakenTeamSlugs(repoPath);
4864
5062
  for (let attempt = 0; attempt < 32; attempt++) {
4865
5063
  const team = allocateTeamName(taken);
4866
- const path2 = (0, import_node_path11.join)(worktreesRoot(repoPath), team.slug);
4867
- if (!(0, import_node_fs11.existsSync)(path2)) return team;
5064
+ const path2 = (0, import_node_path13.join)(worktreesRoot(repoPath), team.slug);
5065
+ if (!(0, import_node_fs12.existsSync)(path2)) return team;
4868
5066
  taken.add(team.slug);
4869
5067
  }
4870
5068
  throw new Error("No available soccer team worktree directories left");
4871
5069
  }
4872
- var import_node_fs11, import_node_path11;
5070
+ var import_node_fs12, import_node_path13;
4873
5071
  var init_worktree = __esm({
4874
5072
  "src/git/worktree.ts"() {
4875
5073
  "use strict";
4876
- import_node_fs11 = require("fs");
4877
- import_node_path11 = require("path");
5074
+ import_node_fs12 = require("fs");
5075
+ import_node_path13 = require("path");
4878
5076
  init_paths();
4879
5077
  init_thread_store();
4880
5078
  init_teams();
@@ -4958,7 +5156,7 @@ function coordinatorTurnReminder(opts) {
4958
5156
  function ensureGlobalCoordinatorCwd(opts) {
4959
5157
  const dir = globalAgentCwd();
4960
5158
  try {
4961
- (0, import_node_fs12.mkdirSync)(dir, { recursive: true });
5159
+ (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
4962
5160
  } catch {
4963
5161
  return dir;
4964
5162
  }
@@ -4966,7 +5164,7 @@ function ensureGlobalCoordinatorCwd(opts) {
4966
5164
  let orchId = opts?.orchestratorThreadId?.trim() || "";
4967
5165
  if (!orchId) {
4968
5166
  try {
4969
- const existing = (0, import_node_fs12.readFileSync)((0, import_node_path12.join)(dir, "AGENTS.md"), "utf8");
5167
+ const existing = (0, import_node_fs13.readFileSync)((0, import_node_path14.join)(dir, "AGENTS.md"), "utf8");
4970
5168
  const m = existing.match(
4971
5169
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
4972
5170
  );
@@ -5008,9 +5206,9 @@ function ensureGlobalCoordinatorCwd(opts) {
5008
5206
  "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."
5009
5207
  ].join("\n");
5010
5208
  try {
5011
- (0, import_node_fs12.writeFileSync)((0, import_node_path12.join)(dir, "CLAUDE.md"), `${body}
5209
+ (0, import_node_fs13.writeFileSync)((0, import_node_path14.join)(dir, "CLAUDE.md"), `${body}
5012
5210
  `, "utf8");
5013
- (0, import_node_fs12.writeFileSync)((0, import_node_path12.join)(dir, "AGENTS.md"), `${body}
5211
+ (0, import_node_fs13.writeFileSync)((0, import_node_path14.join)(dir, "AGENTS.md"), `${body}
5014
5212
  `, "utf8");
5015
5213
  } catch {
5016
5214
  }
@@ -5042,12 +5240,12 @@ function coordinatorSystemPrompt(opts) {
5042
5240
  formatWorkspaceInventory(opts.workspaces)
5043
5241
  ].join("\n");
5044
5242
  }
5045
- var import_node_fs12, import_node_path12, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
5243
+ var import_node_fs13, import_node_path14, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
5046
5244
  var init_coordinator_prompt = __esm({
5047
5245
  "src/orchestrator/coordinator-prompt.ts"() {
5048
5246
  "use strict";
5049
- import_node_fs12 = require("fs");
5050
- import_node_path12 = require("path");
5247
+ import_node_fs13 = require("fs");
5248
+ import_node_path14 = require("path");
5051
5249
  init_worktree();
5052
5250
  init_app_settings();
5053
5251
  init_paths();
@@ -5063,7 +5261,7 @@ var init_coordinator_prompt = __esm({
5063
5261
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
5064
5262
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
5065
5263
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
5066
- "- 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.",
5264
+ "- 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.",
5067
5265
  "- 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.",
5068
5266
  "Workspaces:",
5069
5267
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
@@ -5353,38 +5551,38 @@ __export(workspaces_exports, {
5353
5551
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
5354
5552
  });
5355
5553
  function workspacesFile() {
5356
- return (0, import_node_path13.join)(appDataDir(), "workspaces.json");
5554
+ return (0, import_node_path15.join)(appDataDir(), "workspaces.json");
5357
5555
  }
5358
5556
  function removedWorkspacesFile() {
5359
- return (0, import_node_path13.join)(appDataDir(), "removed-workspaces.json");
5557
+ return (0, import_node_path15.join)(appDataDir(), "removed-workspaces.json");
5360
5558
  }
5361
5559
  function readAll() {
5362
5560
  const path2 = workspacesFile();
5363
- if (!(0, import_node_fs13.existsSync)(path2)) return [];
5561
+ if (!(0, import_node_fs14.existsSync)(path2)) return [];
5364
5562
  try {
5365
- const raw = JSON.parse((0, import_node_fs13.readFileSync)(path2, "utf8"));
5563
+ const raw = JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
5366
5564
  return Array.isArray(raw) ? raw : [];
5367
5565
  } catch {
5368
5566
  return [];
5369
5567
  }
5370
5568
  }
5371
5569
  function writeAll(list) {
5372
- (0, import_node_fs13.mkdirSync)(appDataDir(), { recursive: true });
5373
- (0, import_node_fs13.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
5570
+ (0, import_node_fs14.mkdirSync)(appDataDir(), { recursive: true });
5571
+ (0, import_node_fs14.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
5374
5572
  }
5375
5573
  function readRemoved() {
5376
5574
  const path2 = removedWorkspacesFile();
5377
- if (!(0, import_node_fs13.existsSync)(path2)) return /* @__PURE__ */ new Set();
5575
+ if (!(0, import_node_fs14.existsSync)(path2)) return /* @__PURE__ */ new Set();
5378
5576
  try {
5379
- const raw = JSON.parse((0, import_node_fs13.readFileSync)(path2, "utf8"));
5577
+ const raw = JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
5380
5578
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
5381
5579
  } catch {
5382
5580
  return /* @__PURE__ */ new Set();
5383
5581
  }
5384
5582
  }
5385
5583
  function writeRemoved(paths) {
5386
- (0, import_node_fs13.mkdirSync)(appDataDir(), { recursive: true });
5387
- (0, import_node_fs13.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
5584
+ (0, import_node_fs14.mkdirSync)(appDataDir(), { recursive: true });
5585
+ (0, import_node_fs14.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
5388
5586
  }
5389
5587
  function rememberRemoved(repoPath) {
5390
5588
  const next = readRemoved();
@@ -5407,7 +5605,7 @@ function listWorkspaces() {
5407
5605
  async function addWorkspace(repoPath) {
5408
5606
  const root = await resolveRepoRoot(repoPath);
5409
5607
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
5410
- if (!(0, import_node_fs13.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
5608
+ if (!(0, import_node_fs14.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
5411
5609
  forgetRemoved(root);
5412
5610
  await ensureGhPreferOrigin(root);
5413
5611
  const current = readAll();
@@ -5415,7 +5613,7 @@ async function addWorkspace(repoPath) {
5415
5613
  if (existing) return existing;
5416
5614
  const next = {
5417
5615
  path: root,
5418
- name: (0, import_node_path13.basename)(root),
5616
+ name: (0, import_node_path15.basename)(root),
5419
5617
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
5420
5618
  };
5421
5619
  writeAll([...current, next]);
@@ -5437,10 +5635,10 @@ function syncWorkspacesFromThreads(repoPaths) {
5437
5635
  if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
5438
5636
  continue;
5439
5637
  }
5440
- if (!(0, import_node_fs13.existsSync)(path2)) continue;
5638
+ if (!(0, import_node_fs14.existsSync)(path2)) continue;
5441
5639
  const ws = {
5442
5640
  path: path2,
5443
- name: (0, import_node_path13.basename)(path2),
5641
+ name: (0, import_node_path15.basename)(path2),
5444
5642
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
5445
5643
  };
5446
5644
  byPath.set(path2, ws);
@@ -5450,12 +5648,12 @@ function syncWorkspacesFromThreads(repoPaths) {
5450
5648
  if (dirty) writeAll(next);
5451
5649
  return next.sort((a, b) => a.name.localeCompare(b.name));
5452
5650
  }
5453
- var import_node_fs13, import_node_path13;
5651
+ var import_node_fs14, import_node_path15;
5454
5652
  var init_workspaces = __esm({
5455
5653
  "src/store/workspaces.ts"() {
5456
5654
  "use strict";
5457
- import_node_fs13 = require("fs");
5458
- import_node_path13 = require("path");
5655
+ import_node_fs14 = require("fs");
5656
+ import_node_path15 = require("path");
5459
5657
  init_paths();
5460
5658
  init_global_workspace();
5461
5659
  init_worktree();
@@ -5464,32 +5662,32 @@ var init_workspaces = __esm({
5464
5662
 
5465
5663
  // src/brightsy/config.ts
5466
5664
  function brightsyConfigPath() {
5467
- return (0, import_node_path14.join)((0, import_node_os5.homedir)(), ".brightsy", "config.json");
5665
+ return (0, import_node_path16.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
5468
5666
  }
5469
5667
  function loadBrightsyConfig() {
5470
5668
  const path2 = brightsyConfigPath();
5471
- if (!(0, import_node_fs14.existsSync)(path2)) {
5669
+ if (!(0, import_node_fs15.existsSync)(path2)) {
5472
5670
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
5473
5671
  }
5474
- const raw = JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
5672
+ const raw = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
5475
5673
  if (!raw.access_token || !raw.account_id) {
5476
5674
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
5477
5675
  }
5478
5676
  return raw;
5479
5677
  }
5480
5678
  function saveBrightsyConfig(cfg) {
5481
- (0, import_node_fs14.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
5679
+ (0, import_node_fs15.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
5482
5680
  `, {
5483
5681
  mode: 384
5484
5682
  });
5485
5683
  }
5486
- var import_node_fs14, import_node_os5, import_node_path14;
5684
+ var import_node_fs15, import_node_os6, import_node_path16;
5487
5685
  var init_config = __esm({
5488
5686
  "src/brightsy/config.ts"() {
5489
5687
  "use strict";
5490
- import_node_fs14 = require("fs");
5491
- import_node_os5 = require("os");
5492
- import_node_path14 = require("path");
5688
+ import_node_fs15 = require("fs");
5689
+ import_node_os6 = require("os");
5690
+ import_node_path16 = require("path");
5493
5691
  }
5494
5692
  });
5495
5693
 
@@ -5592,22 +5790,22 @@ __export(connected_teams_exports, {
5592
5790
  listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
5593
5791
  });
5594
5792
  function storePath() {
5595
- return (0, import_node_path15.join)(appDataDir(), "brightsy-teams.json");
5793
+ return (0, import_node_path17.join)(appDataDir(), "brightsy-teams.json");
5596
5794
  }
5597
5795
  function readStore() {
5598
5796
  const path2 = storePath();
5599
- if (!(0, import_node_fs15.existsSync)(path2)) return [];
5797
+ if (!(0, import_node_fs16.existsSync)(path2)) return [];
5600
5798
  try {
5601
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
5799
+ const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
5602
5800
  return Array.isArray(parsed.teams) ? parsed.teams : [];
5603
5801
  } catch {
5604
5802
  return [];
5605
5803
  }
5606
5804
  }
5607
5805
  function writeStore(teams) {
5608
- (0, import_node_fs15.mkdirSync)(appDataDir(), { recursive: true });
5806
+ (0, import_node_fs16.mkdirSync)(appDataDir(), { recursive: true });
5609
5807
  const path2 = storePath();
5610
- (0, import_node_fs15.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
5808
+ (0, import_node_fs16.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
5611
5809
  `, {
5612
5810
  mode: 384
5613
5811
  });
@@ -5769,12 +5967,12 @@ function brightsyMcpServerName(slug) {
5769
5967
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
5770
5968
  return `brightsy_${cleaned || "team"}`;
5771
5969
  }
5772
- var import_node_fs15, import_node_path15;
5970
+ var import_node_fs16, import_node_path17;
5773
5971
  var init_connected_teams = __esm({
5774
5972
  "src/brightsy/connected-teams.ts"() {
5775
5973
  "use strict";
5776
- import_node_fs15 = require("fs");
5777
- import_node_path15 = require("path");
5974
+ import_node_fs16 = require("fs");
5975
+ import_node_path17 = require("path");
5778
5976
  init_paths();
5779
5977
  init_accounts();
5780
5978
  init_config();
@@ -5911,17 +6109,27 @@ function extractJsonErrorMessage(obj) {
5911
6109
  }
5912
6110
  return null;
5913
6111
  }
6112
+ function isPinnedStderrLine(line) {
6113
+ if (/^\s*at\s/.test(line)) return false;
6114
+ return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:/i.test(
6115
+ line
6116
+ );
6117
+ }
5914
6118
  function pushTurnStderr(tail, line, maxLines = 12) {
5915
6119
  const trimmed = line.trim();
5916
6120
  if (!trimmed) return;
5917
6121
  if (NODE_VERSION_FOOTER.test(trimmed)) return;
5918
6122
  if (/^reconnecting\.\.\./i.test(trimmed)) return;
5919
6123
  tail.push(trimmed);
5920
- while (tail.length > maxLines) tail.shift();
6124
+ while (tail.length > maxLines) {
6125
+ const dropIdx = tail.findIndex((l) => !isPinnedStderrLine(l));
6126
+ if (dropIdx === -1) tail.shift();
6127
+ else tail.splice(dropIdx, 1);
6128
+ }
5921
6129
  }
5922
6130
  function looksLikeMinifiedJsDump(line) {
5923
6131
  if (line.length < 200) return false;
5924
- return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line);
6132
+ 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);
5925
6133
  }
5926
6134
  function looksLikeNestedElectronCrash(line) {
5927
6135
  return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
@@ -5936,7 +6144,15 @@ function summarizeTurnStderr(tail, maxChars = 500) {
5936
6144
  const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
5937
6145
  if (cursorStartup) return clipStderr(cursorStartup, maxChars);
5938
6146
  if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
5939
- const moduleMissing = [...tail].reverse().find((line) => /cannot find module/i.test(line));
6147
+ if (tail.some(
6148
+ (line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
6149
+ )) {
6150
+ return clipStderr(
6151
+ "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.",
6152
+ maxChars
6153
+ );
6154
+ }
6155
+ const moduleMissing = [...tail].reverse().find((line) => /cannot find (?:package|module)/i.test(line));
5940
6156
  if (moduleMissing) return clipStderr(moduleMissing, maxChars);
5941
6157
  const useful = tail.filter((line) => !looksLikeMinifiedJsDump(line));
5942
6158
  if (useful.length === 0 && tail.some(looksLikeMinifiedJsDump)) {
@@ -5955,7 +6171,7 @@ function looksLikeAgentFailureMessage(text3) {
5955
6171
  if (!lower) return false;
5956
6172
  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(
5957
6173
  lower
5958
- ) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower);
6174
+ ) || /\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);
5959
6175
  }
5960
6176
  function fallbackTurnFailDetail(assistantText) {
5961
6177
  const t = assistantText.trim();
@@ -5977,6 +6193,9 @@ function humanizeAgentFailDetail(detail) {
5977
6193
  if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
5978
6194
  return `${raw} \u2014 wait a moment and retry.`;
5979
6195
  }
6196
+ if (/\[resource_exhausted\]|resource_exhausted|findfileswithripgrep/.test(lower)) {
6197
+ return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
6198
+ }
5980
6199
  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(
5981
6200
  lower
5982
6201
  )) {
@@ -6303,11 +6522,11 @@ async function syncCliForTarget(accountId) {
6303
6522
  }
6304
6523
  applyConnectedTeamToCli(team);
6305
6524
  }
6306
- var import_node_fs16, brightsyAdapter;
6525
+ var import_node_fs17, brightsyAdapter;
6307
6526
  var init_brightsy = __esm({
6308
6527
  "src/agents/brightsy.ts"() {
6309
6528
  "use strict";
6310
- import_node_fs16 = require("fs");
6529
+ import_node_fs17 = require("fs");
6311
6530
  init_run();
6312
6531
  init_connected_teams();
6313
6532
  init_config();
@@ -6322,7 +6541,7 @@ var init_brightsy = __esm({
6322
6541
  async detect() {
6323
6542
  const brightsy = resolveAgentExecutable("brightsy");
6324
6543
  if (brightsy !== "brightsy") {
6325
- if (!(0, import_node_fs16.existsSync)(brightsy)) {
6544
+ if (!(0, import_node_fs17.existsSync)(brightsy)) {
6326
6545
  return {
6327
6546
  agent: "brightsy",
6328
6547
  installed: false,
@@ -6457,13 +6676,38 @@ var init_profile = __esm({
6457
6676
 
6458
6677
  // src/agents/node-launch.ts
6459
6678
  function isAsarPath(filePath) {
6679
+ if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
6460
6680
  return /\.asar([/\\]|$)/.test(filePath);
6461
6681
  }
6682
+ function unpackedAsarPath(filePath) {
6683
+ if (!isAsarPath(filePath)) return null;
6684
+ const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
6685
+ if (unpacked === filePath) return null;
6686
+ return (0, import_node_fs18.existsSync)(unpacked) ? unpacked : null;
6687
+ }
6688
+ function nodeReadableScriptPath(scriptPath) {
6689
+ return unpackedAsarPath(scriptPath) ?? scriptPath;
6690
+ }
6691
+ async function findSystemNode() {
6692
+ const whichNode = await run("which", ["node"], { reject: false });
6693
+ const fromWhich = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : "";
6694
+ if (fromWhich && !isElectronLikeCommand(fromWhich)) return fromWhich;
6695
+ const fallbacks = [
6696
+ ...WELL_KNOWN_NODE_BINS,
6697
+ (0, import_node_path18.join)((0, import_node_os7.homedir)(), ".local/share/fnm/aliases/default/bin/node"),
6698
+ (0, import_node_path18.join)((0, import_node_os7.homedir)(), ".nvm/current/bin/node")
6699
+ ];
6700
+ for (const bin of fallbacks) {
6701
+ if ((0, import_node_fs18.existsSync)(bin) && !isElectronLikeCommand(bin)) return bin;
6702
+ }
6703
+ return null;
6704
+ }
6462
6705
  function applyNodeLaunch(launch, args) {
6706
+ const readableArgs = args.map(nodeReadableScriptPath);
6463
6707
  if (!launch.env.ELECTRON_RUN_AS_NODE) {
6464
- return { file: launch.file, args, env: launch.env };
6708
+ return { file: launch.file, args: readableArgs, env: launch.env };
6465
6709
  }
6466
- const wrapped = wrapElectronAsNodeLaunch(launch.file, args);
6710
+ const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
6467
6711
  if (process.platform === "win32") {
6468
6712
  return { file: wrapped.file, args: wrapped.args, env: launch.env };
6469
6713
  }
@@ -6472,27 +6716,73 @@ function applyNodeLaunch(launch, args) {
6472
6716
  return { file: wrapped.file, args: wrapped.args, env };
6473
6717
  }
6474
6718
  async function resolveNodeLaunch(scriptPath) {
6475
- if (isAsarPath(scriptPath)) {
6476
- return {
6477
- file: process.execPath,
6478
- env: { ELECTRON_RUN_AS_NODE: "1" }
6479
- };
6480
- }
6481
- const whichNode = await run("which", ["node"], { reject: false });
6482
- const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
6483
- if (nodeBin) {
6484
- return { file: nodeBin, env: {} };
6719
+ const script = nodeReadableScriptPath(scriptPath);
6720
+ if (!isAsarPath(script)) {
6721
+ const nodeBin = await findSystemNode();
6722
+ if (nodeBin) {
6723
+ return { file: nodeBin, env: {} };
6724
+ }
6485
6725
  }
6486
6726
  return {
6487
6727
  file: process.execPath,
6488
6728
  env: { ELECTRON_RUN_AS_NODE: "1" }
6489
6729
  };
6490
6730
  }
6731
+ var import_node_fs18, import_node_os7, import_node_path18, WELL_KNOWN_NODE_BINS;
6491
6732
  var init_node_launch = __esm({
6492
6733
  "src/agents/node-launch.ts"() {
6493
6734
  "use strict";
6735
+ import_node_fs18 = require("fs");
6736
+ import_node_os7 = require("os");
6737
+ import_node_path18 = require("path");
6494
6738
  init_nested_electron_env();
6495
6739
  init_run();
6740
+ WELL_KNOWN_NODE_BINS = [
6741
+ "/opt/homebrew/bin/node",
6742
+ "/usr/local/bin/node"
6743
+ ];
6744
+ }
6745
+ });
6746
+
6747
+ // src/agents/packaged-runtime.ts
6748
+ function electronResourcesPath() {
6749
+ const resources = process.resourcesPath;
6750
+ if (typeof resources !== "string" || !resources) return null;
6751
+ return resources;
6752
+ }
6753
+ function packagedCursorRuntimeDir() {
6754
+ const resources = electronResourcesPath();
6755
+ if (!resources) return null;
6756
+ const dir = (0, import_node_path19.join)(resources, "cursor-runtime");
6757
+ if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
6758
+ return dir;
6759
+ }
6760
+ function packagedCursorRunnerPath() {
6761
+ const dir = packagedCursorRuntimeDir();
6762
+ return dir ? (0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
6763
+ }
6764
+ function packagedMcpDir() {
6765
+ const resources = electronResourcesPath();
6766
+ if (!resources) return null;
6767
+ const dir = (0, import_node_path19.join)(resources, "sideboard-mcp");
6768
+ if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
6769
+ return dir;
6770
+ }
6771
+ function packagedMcpStdioPath() {
6772
+ const dir = packagedMcpDir();
6773
+ return dir ? (0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
6774
+ }
6775
+ function packagedCursorRipgrepCandidate(platformPkg, binName) {
6776
+ const dir = packagedCursorRuntimeDir();
6777
+ if (!dir) return null;
6778
+ return (0, import_node_path19.join)(dir, "node_modules", platformPkg, "bin", binName);
6779
+ }
6780
+ var import_node_fs19, import_node_path19;
6781
+ var init_packaged_runtime = __esm({
6782
+ "src/agents/packaged-runtime.ts"() {
6783
+ "use strict";
6784
+ import_node_fs19 = require("fs");
6785
+ import_node_path19 = require("path");
6496
6786
  }
6497
6787
  });
6498
6788
 
@@ -6579,35 +6869,37 @@ function corePackageDir() {
6579
6869
  try {
6580
6870
  const url = import_meta.url;
6581
6871
  if (typeof url === "string" && url.length > 0) {
6582
- return (0, import_node_path16.dirname)((0, import_node_url.fileURLToPath)(url));
6872
+ return (0, import_node_path20.dirname)((0, import_node_url.fileURLToPath)(url));
6583
6873
  }
6584
6874
  } catch {
6585
6875
  }
6586
6876
  try {
6587
- const req = (0, import_node_module.createRequire)((0, import_node_path16.join)(process.cwd(), "package.json"));
6588
- return (0, import_node_path16.dirname)(req.resolve("@sideboard-ai/core"));
6877
+ const req = (0, import_node_module.createRequire)((0, import_node_path20.join)(process.cwd(), "package.json"));
6878
+ return (0, import_node_path20.dirname)(req.resolve("@sideboard-ai/core"));
6589
6879
  } catch {
6590
6880
  return process.cwd();
6591
6881
  }
6592
6882
  }
6593
6883
  function findSideboardMcpJsEntry() {
6594
6884
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
6595
- if (override && (0, import_node_fs17.existsSync)(override)) return override;
6885
+ if (override && (0, import_node_fs20.existsSync)(override)) return override;
6886
+ const packaged = packagedMcpStdioPath();
6887
+ if (packaged) return packaged;
6596
6888
  let dir = corePackageDir();
6597
6889
  for (let i = 0; i < 10; i++) {
6598
6890
  const candidates = [
6599
- (0, import_node_path16.join)(dir, "mcp/run-stdio.js"),
6600
- (0, import_node_path16.join)(dir, "mcp/run-stdio.cjs"),
6601
- (0, import_node_path16.join)(dir, "dist/mcp/run-stdio.js"),
6602
- (0, import_node_path16.join)(dir, "dist/mcp/run-stdio.cjs"),
6603
- (0, import_node_path16.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
6604
- (0, import_node_path16.join)(dir, "packages/cli/dist/index.js"),
6605
- (0, import_node_path16.join)(dir, "cli/dist/index.js")
6891
+ (0, import_node_path20.join)(dir, "mcp/run-stdio.js"),
6892
+ (0, import_node_path20.join)(dir, "mcp/run-stdio.cjs"),
6893
+ (0, import_node_path20.join)(dir, "dist/mcp/run-stdio.js"),
6894
+ (0, import_node_path20.join)(dir, "dist/mcp/run-stdio.cjs"),
6895
+ (0, import_node_path20.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
6896
+ (0, import_node_path20.join)(dir, "packages/cli/dist/index.js"),
6897
+ (0, import_node_path20.join)(dir, "cli/dist/index.js")
6606
6898
  ];
6607
6899
  for (const p of candidates) {
6608
- if ((0, import_node_fs17.existsSync)(p)) return p;
6900
+ if ((0, import_node_fs20.existsSync)(p) && !isAsarPath(p)) return p;
6609
6901
  }
6610
- const parent = (0, import_node_path16.dirname)(dir);
6902
+ const parent = (0, import_node_path20.dirname)(dir);
6611
6903
  if (parent === dir) break;
6612
6904
  dir = parent;
6613
6905
  }
@@ -6619,12 +6911,14 @@ async function resolveSideboardMcpServer() {
6619
6911
  const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
6620
6912
  const scriptArgs = isCli ? [entry, "mcp"] : [entry];
6621
6913
  const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
6622
- return {
6623
- name: "sideboard",
6624
- command: launch.file,
6625
- args: launch.args,
6626
- ...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
6627
- };
6914
+ if (launch.file !== "/bin/sh" && !isElectronLikeCommand(launch.file)) {
6915
+ return {
6916
+ name: "sideboard",
6917
+ command: launch.file,
6918
+ args: launch.args,
6919
+ ...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
6920
+ };
6921
+ }
6628
6922
  }
6629
6923
  const which = await run("which", ["sideboard"], { reject: false });
6630
6924
  if (which.exitCode === 0 && which.stdout.trim()) {
@@ -6647,7 +6941,10 @@ async function buildInjectedMcpServers(opts) {
6647
6941
  sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
6648
6942
  }
6649
6943
  try {
6650
- Object.assign(sideboard.env, await resolveAgentGitAuthEnv(sideboard.env));
6944
+ mergeAgentGitAuthEnv(
6945
+ sideboard.env,
6946
+ await resolveAgentGitAuthEnv(sideboard.env)
6947
+ );
6651
6948
  } catch {
6652
6949
  }
6653
6950
  servers.push(sideboard);
@@ -6669,9 +6966,6 @@ async function buildInjectedMcpServers(opts) {
6669
6966
  }
6670
6967
  return servers;
6671
6968
  }
6672
- function shSingleQuote(value) {
6673
- return `'${value.replace(/'/g, `'\\''`)}'`;
6674
- }
6675
6969
  function cursorSafeMcpLaunch(command, args) {
6676
6970
  if (process.platform === "win32") {
6677
6971
  return args && args.length > 0 ? { command, args } : { command };
@@ -6679,31 +6973,13 @@ function cursorSafeMcpLaunch(command, args) {
6679
6973
  const unwrapped = unwrapStrippedElectronLaunch(command, args);
6680
6974
  const file = unwrapped?.file ?? command;
6681
6975
  const fileArgs = unwrapped?.args ?? args ?? [];
6682
- if (!isElectronLikeCommand(file)) {
6683
- return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
6684
- }
6685
- const dir = (0, import_node_path16.join)(appDataDir(), "mcp-launch");
6686
- (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
6687
- const wrap = (0, import_node_path16.join)(dir, "cursor-electron-as-node.sh");
6688
- const execLine = [file, ...fileArgs].map(shSingleQuote).join(" ");
6689
- (0, import_node_fs17.writeFileSync)(
6690
- wrap,
6691
- [
6692
- "#!/bin/sh",
6693
- "vars=`printenv | awk -F= '/^(ELECTRON_|CHROME_)/{print $1}'`",
6694
- '[ -n "$vars" ] && unset $vars',
6695
- "export ELECTRON_RUN_AS_NODE=1",
6696
- `exec ${execLine} "$@"`,
6697
- ""
6698
- ].join("\n"),
6699
- { mode: 493 }
6700
- );
6701
- return { command: wrap };
6976
+ return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
6702
6977
  }
6703
6978
  function mcpSpawnEnv(env) {
6704
6979
  if (!env) return void 0;
6705
6980
  const out = { ...env };
6706
6981
  delete out.ELECTRON_RUN_AS_NODE;
6982
+ delete out.ELECTRON_RUN_AS_NODE;
6707
6983
  return Object.keys(out).length > 0 ? out : void 0;
6708
6984
  }
6709
6985
  function toCursorMcpServers(servers) {
@@ -6712,6 +6988,7 @@ function toCursorMcpServers(servers) {
6712
6988
  const env = mcpSpawnEnv(s.env);
6713
6989
  const launch = cursorSafeMcpLaunch(s.command, s.args);
6714
6990
  out[s.name] = {
6991
+ type: "stdio",
6715
6992
  command: launch.command,
6716
6993
  ...launch.args && launch.args.length > 0 ? { args: launch.args } : {},
6717
6994
  ...env ? { env } : {}
@@ -6763,22 +7040,22 @@ function writeMcpServersConfig(servers) {
6763
7040
  ...env ? { env } : {}
6764
7041
  };
6765
7042
  }
6766
- const dir = (0, import_node_fs17.mkdtempSync)((0, import_node_path16.join)((0, import_node_os6.tmpdir)(), "sideboard-mcp-"));
6767
- const cfgPath = (0, import_node_path16.join)(dir, "mcp.json");
6768
- (0, import_node_fs17.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
7043
+ const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path20.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
7044
+ const cfgPath = (0, import_node_path20.join)(dir, "mcp.json");
7045
+ (0, import_node_fs20.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
6769
7046
  return cfgPath;
6770
7047
  }
6771
7048
  async function writeInjectedMcpConfig(opts) {
6772
7049
  return writeMcpServersConfig(await buildInjectedMcpServers(opts));
6773
7050
  }
6774
- var import_node_fs17, import_node_module, import_node_os6, import_node_path16, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
7051
+ var import_node_fs20, import_node_module, import_node_os8, import_node_path20, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
6775
7052
  var init_injected_mcp = __esm({
6776
7053
  "src/agents/injected-mcp.ts"() {
6777
7054
  "use strict";
6778
- import_node_fs17 = require("fs");
7055
+ import_node_fs20 = require("fs");
6779
7056
  import_node_module = require("module");
6780
- import_node_os6 = require("os");
6781
- import_node_path16 = require("path");
7057
+ import_node_os8 = require("os");
7058
+ import_node_path20 = require("path");
6782
7059
  import_node_url = require("url");
6783
7060
  init_run();
6784
7061
  init_config();
@@ -6787,6 +7064,7 @@ var init_injected_mcp = __esm({
6787
7064
  init_app_settings();
6788
7065
  init_paths();
6789
7066
  init_node_launch();
7067
+ init_packaged_runtime();
6790
7068
  init_nested_electron_env();
6791
7069
  init_git_auth_mode();
6792
7070
  import_meta = {};
@@ -6860,7 +7138,7 @@ var PLAN_MODE_INSTRUCTION;
6860
7138
  var init_types = __esm({
6861
7139
  "src/agents/types.ts"() {
6862
7140
  "use strict";
6863
- 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.";
7141
+ 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.";
6864
7142
  }
6865
7143
  });
6866
7144
 
@@ -6970,11 +7248,11 @@ function parseIssuesJson(raw) {
6970
7248
  }
6971
7249
  return [];
6972
7250
  }
6973
- var import_node_fs18, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
7251
+ var import_node_fs21, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
6974
7252
  var init_claude = __esm({
6975
7253
  "src/agents/claude.ts"() {
6976
7254
  "use strict";
6977
- import_node_fs18 = require("fs");
7255
+ import_node_fs21 = require("fs");
6978
7256
  init_run();
6979
7257
  init_app_settings();
6980
7258
  init_claude_mcp();
@@ -7003,7 +7281,7 @@ var init_claude = __esm({
7003
7281
  async detect() {
7004
7282
  const claude = resolveClaudeExecutable();
7005
7283
  if (claude !== "claude") {
7006
- if (!(0, import_node_fs18.existsSync)(claude)) {
7284
+ if (!(0, import_node_fs21.existsSync)(claude)) {
7007
7285
  return {
7008
7286
  agent: "claude",
7009
7287
  installed: false,
@@ -7240,7 +7518,7 @@ async function listCodexModels() {
7240
7518
  if (codex === "codex") {
7241
7519
  const which = await run("which", ["codex"], { reject: false });
7242
7520
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
7243
- } else if (!(0, import_node_fs19.existsSync)(codex)) {
7521
+ } else if (!(0, import_node_fs22.existsSync)(codex)) {
7244
7522
  return FALLBACK_CODEX_MODELS;
7245
7523
  }
7246
7524
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -7275,12 +7553,12 @@ function usageFromCodex(usage) {
7275
7553
  }
7276
7554
  function codexConfigHasNetworkAccess() {
7277
7555
  const candidates = [
7278
- (0, import_node_path17.join)((0, import_node_os7.homedir)(), ".codex", "config.toml"),
7279
- (0, import_node_path17.join)((0, import_node_os7.homedir)(), ".config", "codex", "config.toml")
7556
+ (0, import_node_path21.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
7557
+ (0, import_node_path21.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
7280
7558
  ];
7281
7559
  for (const path2 of candidates) {
7282
- if (!(0, import_node_fs19.existsSync)(path2)) continue;
7283
- const text3 = (0, import_node_fs19.readFileSync)(path2, "utf8");
7560
+ if (!(0, import_node_fs22.existsSync)(path2)) continue;
7561
+ const text3 = (0, import_node_fs22.readFileSync)(path2, "utf8");
7284
7562
  if (/network_access\s*=\s*true/.test(text3)) return true;
7285
7563
  }
7286
7564
  return false;
@@ -7312,21 +7590,21 @@ function asRecord(value) {
7312
7590
  return void 0;
7313
7591
  }
7314
7592
  function codexLooksAuthenticated() {
7315
- const authPath = (0, import_node_path17.join)((0, import_node_os7.homedir)(), ".codex", "auth.json");
7316
- if (!(0, import_node_fs19.existsSync)(authPath)) return false;
7593
+ const authPath = (0, import_node_path21.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
7594
+ if (!(0, import_node_fs22.existsSync)(authPath)) return false;
7317
7595
  try {
7318
- return (0, import_node_fs19.statSync)(authPath).size > 2;
7596
+ return (0, import_node_fs22.statSync)(authPath).size > 2;
7319
7597
  } catch {
7320
7598
  return false;
7321
7599
  }
7322
7600
  }
7323
- var import_node_fs19, import_node_os7, import_node_path17, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
7601
+ var import_node_fs22, import_node_os9, import_node_path21, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
7324
7602
  var init_codex = __esm({
7325
7603
  "src/agents/codex.ts"() {
7326
7604
  "use strict";
7327
- import_node_fs19 = require("fs");
7328
- import_node_os7 = require("os");
7329
- import_node_path17 = require("path");
7605
+ import_node_fs22 = require("fs");
7606
+ import_node_os9 = require("os");
7607
+ import_node_path21 = require("path");
7330
7608
  init_run();
7331
7609
  init_app_settings();
7332
7610
  init_global_workspace();
@@ -7351,7 +7629,7 @@ var init_codex = __esm({
7351
7629
  async detect() {
7352
7630
  const codex = resolveAgentExecutable("codex");
7353
7631
  if (codex !== "codex") {
7354
- if (!(0, import_node_fs19.existsSync)(codex)) {
7632
+ if (!(0, import_node_fs22.existsSync)(codex)) {
7355
7633
  return {
7356
7634
  agent: "codex",
7357
7635
  installed: false,
@@ -7424,8 +7702,13 @@ var init_codex = __esm({
7424
7702
  // `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
7425
7703
  "-c",
7426
7704
  'approval_policy="never"',
7427
- // Seatbelt cannot use the login Keychain; default policy also strips GH_TOKEN.
7428
- ...codexUnattendedGitConfigArgs(mode.codexSandbox),
7705
+ // Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
7706
+ // Default policy also strips *TOKEN*. Linked worktrees need the main
7707
+ // repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
7708
+ // can create index.lock.
7709
+ ...codexUnattendedGitConfigArgs(mode.codexSandbox, {
7710
+ writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
7711
+ }),
7429
7712
  ...model ? ["--model", model] : [],
7430
7713
  ...mcpOverrides
7431
7714
  ];
@@ -7746,6 +8029,74 @@ var init_cursor_events = __esm({
7746
8029
  }
7747
8030
  });
7748
8031
 
8032
+ // src/agents/cursor-ripgrep.ts
8033
+ function rgBinaryName() {
8034
+ return process.platform === "win32" ? "rg.exe" : "rg";
8035
+ }
8036
+ function platformRipgrepPackage() {
8037
+ return `@cursor/sdk-${process.platform}-${process.arch}`;
8038
+ }
8039
+ function usableRipgrepPath(candidate) {
8040
+ const raw = candidate?.trim();
8041
+ if (!raw || !(0, import_node_path22.isAbsolute)(raw)) return null;
8042
+ const readable = nodeReadableScriptPath(raw);
8043
+ if (!(0, import_node_fs23.existsSync)(readable) || isAsarPath(readable)) return null;
8044
+ return readable;
8045
+ }
8046
+ function walkForBundledRipgrep(startFile) {
8047
+ if (!startFile) return null;
8048
+ const pkg = platformRipgrepPackage();
8049
+ const name = rgBinaryName();
8050
+ let dir = (0, import_node_path22.dirname)((0, import_node_path22.resolve)(startFile));
8051
+ const root = (0, import_node_path22.parse)(dir).root;
8052
+ while (dir !== root) {
8053
+ const hit = usableRipgrepPath((0, import_node_path22.join)(dir, "node_modules", pkg, "bin", name));
8054
+ if (hit) return hit;
8055
+ const next = (0, import_node_path22.dirname)(dir);
8056
+ if (next === dir) break;
8057
+ dir = next;
8058
+ }
8059
+ return null;
8060
+ }
8061
+ function requireResolveBundledRipgrep(fromFile) {
8062
+ try {
8063
+ const req = (0, import_node_module2.createRequire)(fromFile);
8064
+ const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
8065
+ return usableRipgrepPath((0, import_node_path22.join)((0, import_node_path22.dirname)(pkgJson), "bin", rgBinaryName()));
8066
+ } catch {
8067
+ return null;
8068
+ }
8069
+ }
8070
+ function resolveCursorRipgrepPath(opts) {
8071
+ const env = opts?.env ?? process.env;
8072
+ const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
8073
+ if (fromEnv) return fromEnv;
8074
+ const fromPackaged = usableRipgrepPath(
8075
+ packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
8076
+ );
8077
+ if (fromPackaged) return fromPackaged;
8078
+ const start = opts?.startFile?.trim() || process.argv[1] || (0, import_node_url2.fileURLToPath)(import_meta2.url);
8079
+ return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
8080
+ }
8081
+ function cursorRipgrepEnv(opts) {
8082
+ const path2 = resolveCursorRipgrepPath(opts);
8083
+ return path2 ? { [RIPGREP_ENV]: path2 } : {};
8084
+ }
8085
+ var import_node_fs23, import_node_module2, import_node_path22, import_node_url2, import_meta2, RIPGREP_ENV;
8086
+ var init_cursor_ripgrep = __esm({
8087
+ "src/agents/cursor-ripgrep.ts"() {
8088
+ "use strict";
8089
+ import_node_fs23 = require("fs");
8090
+ import_node_module2 = require("module");
8091
+ import_node_path22 = require("path");
8092
+ import_node_url2 = require("url");
8093
+ init_node_launch();
8094
+ init_packaged_runtime();
8095
+ import_meta2 = {};
8096
+ RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
8097
+ }
8098
+ });
8099
+
7749
8100
  // src/agents/cursor.ts
7750
8101
  function resolveCursorApiKey() {
7751
8102
  const fromEnv = (process.env.CURSOR_API_KEY || "").trim();
@@ -7785,51 +8136,55 @@ function entryDir() {
7785
8136
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
7786
8137
  if (cjsDir) return cjsDir;
7787
8138
  try {
7788
- return (0, import_node_path18.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
8139
+ return (0, import_node_path23.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
7789
8140
  } catch {
7790
8141
  try {
7791
- const req = (0, import_node_module2.createRequire)(process.cwd() + "/");
7792
- return (0, import_node_path18.dirname)(req.resolve("@sideboard-ai/core"));
8142
+ const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
8143
+ return (0, import_node_path23.dirname)(req.resolve("@sideboard-ai/core"));
7793
8144
  } catch {
7794
8145
  return process.cwd();
7795
8146
  }
7796
8147
  }
7797
8148
  }
7798
8149
  function cursorRunnerPath() {
8150
+ const packaged = packagedCursorRunnerPath();
8151
+ if (packaged) return packaged;
7799
8152
  const root = entryDir();
7800
8153
  const candidates = [
7801
- (0, import_node_path18.join)(root, "agents", "cursor-runner.js"),
7802
- (0, import_node_path18.join)(root, "agents", "cursor-runner.cjs"),
8154
+ (0, import_node_path23.join)(root, "agents", "cursor-runner.js"),
8155
+ (0, import_node_path23.join)(root, "agents", "cursor-runner.cjs"),
7803
8156
  // If somehow resolved from package root instead of dist/
7804
- (0, import_node_path18.join)(root, "dist", "agents", "cursor-runner.js"),
7805
- (0, import_node_path18.join)(root, "dist", "agents", "cursor-runner.cjs"),
8157
+ (0, import_node_path23.join)(root, "dist", "agents", "cursor-runner.js"),
8158
+ (0, import_node_path23.join)(root, "dist", "agents", "cursor-runner.cjs"),
7806
8159
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
7807
- (0, import_node_path18.join)(root, "cursor-runner.ts"),
7808
- (0, import_node_path18.join)(root, "src", "agents", "cursor-runner.ts")
8160
+ (0, import_node_path23.join)(root, "cursor-runner.ts"),
8161
+ (0, import_node_path23.join)(root, "src", "agents", "cursor-runner.ts")
7809
8162
  ];
7810
8163
  for (const candidate of candidates) {
7811
- if ((0, import_node_fs20.existsSync)(candidate)) return candidate;
8164
+ if ((0, import_node_fs24.existsSync)(candidate)) return candidate;
7812
8165
  }
7813
8166
  return candidates[0];
7814
8167
  }
7815
- var import_node_fs20, import_node_module2, import_node_path18, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
8168
+ var import_node_fs24, import_node_module3, import_node_path23, import_node_url3, import_sdk, import_meta3, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
7816
8169
  var init_cursor = __esm({
7817
8170
  "src/agents/cursor.ts"() {
7818
8171
  "use strict";
7819
- import_node_fs20 = require("fs");
7820
- import_node_module2 = require("module");
7821
- import_node_path18 = require("path");
7822
- import_node_url2 = require("url");
8172
+ import_node_fs24 = require("fs");
8173
+ import_node_module3 = require("module");
8174
+ import_node_path23 = require("path");
8175
+ import_node_url3 = require("url");
7823
8176
  import_sdk = require("@cursor/sdk");
7824
8177
  init_run();
7825
8178
  init_app_settings();
7826
8179
  init_global_workspace();
7827
8180
  init_cursor_events();
7828
8181
  init_injected_mcp();
8182
+ init_cursor_ripgrep();
7829
8183
  init_node_launch();
8184
+ init_packaged_runtime();
7830
8185
  init_turn_input();
7831
8186
  init_cursor_events();
7832
- import_meta2 = {};
8187
+ import_meta3 = {};
7833
8188
  FALLBACK_CURSOR_MODELS = [
7834
8189
  { id: "default", displayName: "Auto" },
7835
8190
  { id: "composer-2.5", displayName: "Composer 2.5" },
@@ -7896,6 +8251,7 @@ var init_cursor = __esm({
7896
8251
  stdin: JSON.stringify(req),
7897
8252
  env: {
7898
8253
  ...launch.env,
8254
+ ...cursorRipgrepEnv({ startFile: runner }),
7899
8255
  ...apiKey ? { CURSOR_API_KEY: apiKey } : {}
7900
8256
  }
7901
8257
  };
@@ -7947,7 +8303,7 @@ async function listOpencodeModels() {
7947
8303
  if (opencode === "opencode") {
7948
8304
  const which = await run("which", ["opencode"], { reject: false });
7949
8305
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
7950
- } else if (!(0, import_node_fs21.existsSync)(opencode)) {
8306
+ } else if (!(0, import_node_fs25.existsSync)(opencode)) {
7951
8307
  return FALLBACK_OPENCODE_MODELS;
7952
8308
  }
7953
8309
  const listed = await run(opencode, ["models"], { reject: false });
@@ -7977,11 +8333,11 @@ function usageFromOpencode(tokens) {
7977
8333
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
7978
8334
  };
7979
8335
  }
7980
- var import_node_fs21, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
8336
+ var import_node_fs25, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
7981
8337
  var init_opencode = __esm({
7982
8338
  "src/agents/opencode.ts"() {
7983
8339
  "use strict";
7984
- import_node_fs21 = require("fs");
8340
+ import_node_fs25 = require("fs");
7985
8341
  init_run();
7986
8342
  init_app_settings();
7987
8343
  init_global_workspace();
@@ -8007,7 +8363,7 @@ var init_opencode = __esm({
8007
8363
  async detect() {
8008
8364
  const opencode = resolveAgentExecutable("opencode");
8009
8365
  if (opencode !== "opencode") {
8010
- if (!(0, import_node_fs21.existsSync)(opencode)) {
8366
+ if (!(0, import_node_fs25.existsSync)(opencode)) {
8011
8367
  return {
8012
8368
  agent: "opencode",
8013
8369
  installed: false,
@@ -8804,40 +9160,40 @@ __export(plan_file_exports, {
8804
9160
  writePlanFile: () => writePlanFile
8805
9161
  });
8806
9162
  function ensureAttachmentsGitignore2(worktreePath) {
8807
- const gitignoreAbs = (0, import_node_path31.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
8808
- if ((0, import_node_fs35.existsSync)(gitignoreAbs)) return;
8809
- (0, import_node_fs35.mkdirSync)((0, import_node_path31.dirname)(gitignoreAbs), { recursive: true });
8810
- (0, import_node_fs35.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
9163
+ const gitignoreAbs = (0, import_node_path36.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
9164
+ if ((0, import_node_fs39.existsSync)(gitignoreAbs)) return;
9165
+ (0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(gitignoreAbs), { recursive: true });
9166
+ (0, import_node_fs39.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
8811
9167
  }
8812
9168
  function planFileAbs(worktreePath) {
8813
- return (0, import_node_path31.join)(worktreePath, PLAN_FILE_REL);
9169
+ return (0, import_node_path36.join)(worktreePath, PLAN_FILE_REL);
8814
9170
  }
8815
9171
  function readTextIfPresent2(abs) {
8816
- if (!(0, import_node_fs35.existsSync)(abs)) return null;
9172
+ if (!(0, import_node_fs39.existsSync)(abs)) return null;
8817
9173
  try {
8818
- const content = (0, import_node_fs35.readFileSync)(abs, "utf8");
9174
+ const content = (0, import_node_fs39.readFileSync)(abs, "utf8");
8819
9175
  return content.trim() ? content : null;
8820
9176
  } catch {
8821
9177
  return null;
8822
9178
  }
8823
9179
  }
8824
9180
  function readPlanFile(worktreePath) {
8825
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path31.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path31.join)(worktreePath, LEGACY_PLAN_FILE_REL));
9181
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path36.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path36.join)(worktreePath, LEGACY_PLAN_FILE_REL));
8826
9182
  }
8827
9183
  function writePlanFile(worktreePath, content) {
8828
9184
  ensureAttachmentsGitignore2(worktreePath);
8829
9185
  const abs = planFileAbs(worktreePath);
8830
- (0, import_node_fs35.mkdirSync)((0, import_node_path31.dirname)(abs), { recursive: true });
9186
+ (0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(abs), { recursive: true });
8831
9187
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
8832
- (0, import_node_fs35.writeFileSync)(abs, body, "utf8");
9188
+ (0, import_node_fs39.writeFileSync)(abs, body, "utf8");
8833
9189
  return PLAN_FILE_REL;
8834
9190
  }
8835
- var import_node_fs35, import_node_path31;
9191
+ var import_node_fs39, import_node_path36;
8836
9192
  var init_plan_file = __esm({
8837
9193
  "src/plan/plan-file.ts"() {
8838
9194
  "use strict";
8839
- import_node_fs35 = require("fs");
8840
- import_node_path31 = require("path");
9195
+ import_node_fs39 = require("fs");
9196
+ import_node_path36 = require("path");
8841
9197
  init_workspace_scratch();
8842
9198
  init_plan_present();
8843
9199
  init_plan_present();
@@ -8852,10 +9208,10 @@ __export(cursor_recover_exports, {
8852
9208
  function recoverFinishedCursorRun(opts) {
8853
9209
  const agentId = opts.agentId.trim();
8854
9210
  if (!agentId) return null;
8855
- const runsPath = (0, import_node_path32.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
8856
- if (!(0, import_node_fs36.existsSync)(runsPath)) return null;
9211
+ const runsPath = (0, import_node_path37.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
9212
+ if (!(0, import_node_fs40.existsSync)(runsPath)) return null;
8857
9213
  try {
8858
- const lines = (0, import_node_fs36.readFileSync)(runsPath, "utf8").split("\n");
9214
+ const lines = (0, import_node_fs40.readFileSync)(runsPath, "utf8").split("\n");
8859
9215
  let best = null;
8860
9216
  for (const line of lines) {
8861
9217
  const trimmed = line.trim();
@@ -8881,12 +9237,12 @@ function recoverFinishedCursorRun(opts) {
8881
9237
  return null;
8882
9238
  }
8883
9239
  }
8884
- var import_node_fs36, import_node_path32;
9240
+ var import_node_fs40, import_node_path37;
8885
9241
  var init_cursor_recover = __esm({
8886
9242
  "src/agents/cursor-recover.ts"() {
8887
9243
  "use strict";
8888
- import_node_fs36 = require("fs");
8889
- import_node_path32 = require("path");
9244
+ import_node_fs40 = require("fs");
9245
+ import_node_path37 = require("path");
8890
9246
  init_paths();
8891
9247
  }
8892
9248
  });
@@ -8970,7 +9326,6 @@ __export(index_exports, {
8970
9326
  SIDEBOARD_FORCE_STOP: () => SIDEBOARD_FORCE_STOP,
8971
9327
  SIDEBOARD_MCP_ALLOWED_TOOLS: () => SIDEBOARD_MCP_ALLOWED_TOOLS,
8972
9328
  SIDEBOARD_MCP_PROFILE_ENV: () => SIDEBOARD_MCP_PROFILE_ENV,
8973
- SLACK_LISTEN_BUSY_REPLY: () => SLACK_LISTEN_BUSY_REPLY,
8974
9329
  SLACK_LISTEN_STOPPED_REPLY: () => SLACK_LISTEN_STOPPED_REPLY,
8975
9330
  SLACK_LISTEN_TIMEOUT_REPLY: () => SLACK_LISTEN_TIMEOUT_REPLY,
8976
9331
  SLACK_OAUTH_CANCELLED: () => SLACK_OAUTH_CANCELLED,
@@ -9040,6 +9395,7 @@ __export(index_exports, {
9040
9395
  cleanupOrphanWorktrees: () => cleanupOrphanWorktrees,
9041
9396
  cloneRepoIntoSideboard: () => cloneRepoIntoSideboard,
9042
9397
  codexAdapter: () => codexAdapter,
9398
+ codexSandboxWritableRootsArgs: () => codexSandboxWritableRootsArgs,
9043
9399
  codexUnattendedGitConfigArgs: () => codexUnattendedGitConfigArgs,
9044
9400
  coerceOrchestratorAgent: () => coerceOrchestratorAgent,
9045
9401
  collectTakenTeamSlugs: () => collectTakenTeamSlugs,
@@ -9156,6 +9512,7 @@ __export(index_exports, {
9156
9512
  getPr: () => getPr,
9157
9513
  getPrChecks: () => getPrChecks,
9158
9514
  getPrDetails: () => getPrDetails,
9515
+ getPrForHeadBranch: () => getPrForHeadBranch,
9159
9516
  getPrMeta: () => getPrMeta,
9160
9517
  getPrStack: () => getPrStack,
9161
9518
  getRepoSetupInfo: () => getRepoSetupInfo,
@@ -9186,12 +9543,14 @@ __export(index_exports, {
9186
9543
  initializeGitRepository: () => initializeGitRepository,
9187
9544
  inspectGitWorktree: () => inspectGitWorktree,
9188
9545
  installAgent: () => installAgent,
9546
+ interruptSlackCoordinatorForInbound: () => interruptSlackCoordinatorForInbound,
9189
9547
  isAskUserToolName: () => isAskUserToolName,
9190
9548
  isBrightsyConnected: () => isBrightsyConnected,
9191
9549
  isBrightsyNdjsonLine: () => isBrightsyNdjsonLine,
9192
9550
  isCloudCoordinatorThread: () => isCloudCoordinatorThread,
9193
9551
  isConductorBundledCli: () => isConductorBundledCli,
9194
9552
  isCursorAutoModel: () => isCursorAutoModel,
9553
+ isDefaultishSourceRef: () => isDefaultishSourceRef,
9195
9554
  isDirty: () => isDirty,
9196
9555
  isGhRateLimitError: () => isGhRateLimitError,
9197
9556
  isGlobalRepoPath: () => isGlobalRepoPath,
@@ -9258,8 +9617,10 @@ __export(index_exports, {
9258
9617
  maybeCompactContext: () => maybeCompactContext,
9259
9618
  mcpAllowTools: () => mcpAllowTools,
9260
9619
  mcpAuthWarnings: () => mcpAuthWarnings,
9620
+ mergeAgentGitAuthEnv: () => mergeAgentGitAuthEnv,
9261
9621
  mergePr: () => mergePr,
9262
9622
  mergePrStack: () => mergePrStack,
9623
+ mergeSideboardIntoMcpServersJson: () => mergeSideboardIntoMcpServersJson,
9263
9624
  mergeUsage: () => mergeUsage,
9264
9625
  nextPastedTextName: () => nextPastedTextName,
9265
9626
  nextThinkingEffort: () => nextThinkingEffort,
@@ -9310,6 +9671,7 @@ __export(index_exports, {
9310
9671
  recordSlackOutboundWatch: () => recordSlackOutboundWatch,
9311
9672
  refreshGitHubAuth: () => refreshGitHubAuth,
9312
9673
  refreshSlackReplyBadges: () => refreshSlackReplyBadges,
9674
+ registerPackagedUserMcpClients: () => registerPackagedUserMcpClients,
9313
9675
  releaseCaffeinateHoldForThread: () => releaseCaffeinateHoldForThread,
9314
9676
  removeWorkspace: () => removeWorkspace,
9315
9677
  removeWorktree: () => removeWorktree,
@@ -9318,9 +9680,11 @@ __export(index_exports, {
9318
9680
  requestReview: () => requestReview,
9319
9681
  requireAgent: () => requireAgent,
9320
9682
  resetGhStackDetectCache: () => resetGhStackDetectCache,
9683
+ resetGithubAgentTokenMemo: () => resetGithubAgentTokenMemo,
9321
9684
  resolveAgentExecutable: () => resolveAgentExecutable,
9322
9685
  resolveAgentGitAuthEnv: () => resolveAgentGitAuthEnv,
9323
9686
  resolveClaudeExecutable: () => resolveClaudeExecutable,
9687
+ resolveCodexGitWritableRoots: () => resolveCodexGitWritableRoots,
9324
9688
  resolveCommandBinarySync: () => resolveCommandBinarySync,
9325
9689
  resolveConductorCursorAgentId: () => resolveConductorCursorAgentId,
9326
9690
  resolveCursorModelId: () => resolveCursorModelId,
@@ -9337,6 +9701,7 @@ __export(index_exports, {
9337
9701
  resolveNewThreadOptions: () => resolveNewThreadOptions,
9338
9702
  resolvePlanMarkdown: () => resolvePlanMarkdown,
9339
9703
  resolvePrSelector: () => resolvePrSelector,
9704
+ resolvePrSelectors: () => resolvePrSelectors,
9340
9705
  resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
9341
9706
  resolveRepoRoot: () => resolveRepoRoot,
9342
9707
  resolveReviewGuidelines: () => resolveReviewGuidelines,
@@ -9359,6 +9724,7 @@ __export(index_exports, {
9359
9724
  sanitizeMcpServerName: () => sanitizeMcpServerName,
9360
9725
  saveAppSettings: () => saveAppSettings,
9361
9726
  saveLinearOAuth: () => saveLinearOAuth,
9727
+ scrubGithubTokensFromChildEnv: () => scrubGithubTokensFromChildEnv,
9362
9728
  secureFileUnlocksWith: () => secureFileUnlocksWith,
9363
9729
  setCaffeinateHold: () => setCaffeinateHold,
9364
9730
  setHttpFetchImpl: () => setHttpFetchImpl,
@@ -9429,7 +9795,10 @@ __export(index_exports, {
9429
9795
  updateLinearIssue: () => updateLinearIssue,
9430
9796
  updateOpencodeSettings: () => updateOpencodeSettings,
9431
9797
  updateThread: () => updateThread,
9798
+ userClaudeMcpConfigPath: () => userClaudeMcpConfigPath,
9799
+ userCursorMcpConfigPath: () => userCursorMcpConfigPath,
9432
9800
  validateLinearApiKey: () => validateLinearApiKey,
9801
+ warmGithubAgentAuth: () => warmGithubAgentAuth,
9433
9802
  withAgentInstructions: () => withAgentInstructions,
9434
9803
  withExportedPath: () => withExportedPath,
9435
9804
  withThreadLock: () => withThreadLock,
@@ -10513,10 +10882,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
10513
10882
  const env = childEnvWithAppSettings(cmd.env);
10514
10883
  try {
10515
10884
  if (isOrchestratorThread(thread)) {
10516
- Object.assign(env, await resolveAgentGitAuthEnv(env));
10885
+ mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
10517
10886
  } else {
10518
- const originEnv = await originGhRepoEnv(thread.worktreePath, { env });
10519
- Object.assign(env, originEnv);
10887
+ mergeAgentGitAuthEnv(env, await originGhRepoEnv(thread.worktreePath, { env }));
10520
10888
  }
10521
10889
  } catch (err) {
10522
10890
  const detail = err instanceof Error ? err.message : String(err);
@@ -10611,8 +10979,8 @@ init_usage();
10611
10979
  init_claude_mcp();
10612
10980
 
10613
10981
  // src/agents/instructions.ts
10614
- var import_node_fs22 = require("fs");
10615
- var import_node_path19 = require("path");
10982
+ var import_node_fs26 = require("fs");
10983
+ var import_node_path24 = require("path");
10616
10984
  init_git_auth_mode();
10617
10985
  init_worktree_labels();
10618
10986
  function normPath3(p) {
@@ -10745,9 +11113,10 @@ function formatArtifactDirective() {
10745
11113
  "Files / media browser (CMS file manager column):",
10746
11114
  "4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
10747
11115
  " Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
10748
- "Multiple-choice questions (any mode \u2014 not only Plan):",
10749
- "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.",
10750
- "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."
11116
+ "Multiple-choice questions:",
11117
+ "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.",
11118
+ "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.",
11119
+ "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."
10751
11120
  ].join("\n");
10752
11121
  }
10753
11122
  function formatUiReminder() {
@@ -10758,7 +11127,7 @@ function formatUiReminder() {
10758
11127
  "CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
10759
11128
  "Files column: MCP present_files (brightsy account storage or memory).",
10760
11129
  "Do not say artifacts/CMS UI are unavailable.",
10761
- "Multiple-choice questions: MCP ask_user (composer picker, any mode). Explain options in chat first, then wait for answers."
11130
+ "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."
10762
11131
  ].join(" ");
10763
11132
  }
10764
11133
  var FILES_BY_AGENT = {
@@ -10782,11 +11151,11 @@ function loadAgentInstructions(worktreePath, agent) {
10782
11151
  const out = [];
10783
11152
  for (const rel of candidates) {
10784
11153
  if (seenPaths.has(rel)) continue;
10785
- const abs = (0, import_node_path19.join)(worktreePath, rel);
10786
- if (!(0, import_node_fs22.existsSync)(abs)) continue;
11154
+ const abs = (0, import_node_path24.join)(worktreePath, rel);
11155
+ if (!(0, import_node_fs26.existsSync)(abs)) continue;
10787
11156
  try {
10788
- if (!(0, import_node_fs22.statSync)(abs).isFile()) continue;
10789
- let content = (0, import_node_fs22.readFileSync)(abs, "utf8");
11157
+ if (!(0, import_node_fs26.statSync)(abs).isFile()) continue;
11158
+ let content = (0, import_node_fs26.readFileSync)(abs, "utf8");
10790
11159
  if (!content.trim()) continue;
10791
11160
  if (content.length > MAX_CHARS_PER_FILE) {
10792
11161
  content = `${content.slice(0, MAX_CHARS_PER_FILE)}
@@ -10868,9 +11237,9 @@ async function requireAgent(agent, opts) {
10868
11237
  init_settings();
10869
11238
 
10870
11239
  // src/hook/conductor.ts
10871
- var import_node_fs23 = require("fs");
11240
+ var import_node_fs27 = require("fs");
10872
11241
  var import_node_net = require("net");
10873
- var import_node_path20 = require("path");
11242
+ var import_node_path25 = require("path");
10874
11243
  var import_execa4 = require("execa");
10875
11244
  var import_node_readline3 = require("readline");
10876
11245
  init_settings();
@@ -10885,9 +11254,9 @@ function matchSimpleGlob(pattern, name) {
10885
11254
  return new RegExp(`^${escaped}$`).test(name);
10886
11255
  }
10887
11256
  function readWorktreeInclude(repoPath) {
10888
- const path2 = (0, import_node_path20.join)(repoPath, ".worktreeinclude");
10889
- if (!(0, import_node_fs23.existsSync)(path2)) return [];
10890
- return (0, import_node_fs23.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
11257
+ const path2 = (0, import_node_path25.join)(repoPath, ".worktreeinclude");
11258
+ if (!(0, import_node_fs27.existsSync)(path2)) return [];
11259
+ return (0, import_node_fs27.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
10891
11260
  }
10892
11261
  function resolveFilesToCopy(repoPath) {
10893
11262
  const fromInclude = readWorktreeInclude(repoPath);
@@ -10897,10 +11266,10 @@ function resolveFilesToCopy(repoPath) {
10897
11266
  if (settings?.fileIncludeGlobs?.length) {
10898
11267
  const matched = [];
10899
11268
  try {
10900
- for (const entry of (0, import_node_fs23.readdirSync)(repoPath, { withFileTypes: true })) {
11269
+ for (const entry of (0, import_node_fs27.readdirSync)(repoPath, { withFileTypes: true })) {
10901
11270
  if (!entry.isFile()) continue;
10902
11271
  for (const glob of settings.fileIncludeGlobs) {
10903
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path20.basename)(glob), entry.name)) {
11272
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path25.basename)(glob), entry.name)) {
10904
11273
  matched.push(entry.name);
10905
11274
  break;
10906
11275
  }
@@ -10912,7 +11281,7 @@ function resolveFilesToCopy(repoPath) {
10912
11281
  }
10913
11282
  const defaults = [];
10914
11283
  try {
10915
- for (const entry of (0, import_node_fs23.readdirSync)(repoPath, { withFileTypes: true })) {
11284
+ for (const entry of (0, import_node_fs27.readdirSync)(repoPath, { withFileTypes: true })) {
10916
11285
  if (entry.isFile() && entry.name.startsWith(".env")) {
10917
11286
  defaults.push(entry.name);
10918
11287
  }
@@ -10926,11 +11295,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
10926
11295
  const patterns = resolveFilesToCopy(repoPath);
10927
11296
  const copied = [];
10928
11297
  for (const rel of patterns) {
10929
- const src = (0, import_node_path20.join)(repoPath, rel);
10930
- if (!(0, import_node_fs23.existsSync)(src)) continue;
10931
- const dest = (0, import_node_path20.join)(worktreePath, rel);
10932
- (0, import_node_fs23.mkdirSync)((0, import_node_path20.dirname)(dest), { recursive: true });
10933
- (0, import_node_fs23.copyFileSync)(src, dest);
11298
+ const src = (0, import_node_path25.join)(repoPath, rel);
11299
+ if (!(0, import_node_fs27.existsSync)(src)) continue;
11300
+ const dest = (0, import_node_path25.join)(worktreePath, rel);
11301
+ (0, import_node_fs27.mkdirSync)((0, import_node_path25.dirname)(dest), { recursive: true });
11302
+ (0, import_node_fs27.copyFileSync)(src, dest);
10934
11303
  copied.push(rel);
10935
11304
  }
10936
11305
  return copied;
@@ -10966,7 +11335,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
10966
11335
  const env = stripNestedElectronEnv({
10967
11336
  ...baseEnv ?? process.env
10968
11337
  });
10969
- const name = opts.workspaceName ?? (0, import_node_path20.basename)(opts.worktreePath);
11338
+ const name = opts.workspaceName ?? (0, import_node_path25.basename)(opts.worktreePath);
10970
11339
  const ports = opts.ports ?? [];
10971
11340
  const primary = ports[0];
10972
11341
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -11052,7 +11421,10 @@ async function spawnWorkspaceScript(command, opts) {
11052
11421
  loginEnv
11053
11422
  );
11054
11423
  try {
11055
- Object.assign(env, await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath }));
11424
+ mergeAgentGitAuthEnv(
11425
+ env,
11426
+ await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath })
11427
+ );
11056
11428
  } catch {
11057
11429
  }
11058
11430
  const shell = process.platform === "darwin" ? "zsh" : "bash";
@@ -11224,12 +11596,12 @@ init_convention_setup();
11224
11596
  init_cursor_worktrees();
11225
11597
 
11226
11598
  // src/diff/diff.ts
11227
- var import_node_fs24 = require("fs");
11228
- var import_node_path21 = require("path");
11599
+ var import_node_fs28 = require("fs");
11600
+ var import_node_path26 = require("path");
11229
11601
  init_run();
11230
11602
  init_worktree();
11231
11603
  async function inspectGitWorktree(worktreePath) {
11232
- if (!worktreePath || !(0, import_node_fs24.existsSync)(worktreePath)) return "missing_worktree";
11604
+ if (!worktreePath || !(0, import_node_fs28.existsSync)(worktreePath)) return "missing_worktree";
11233
11605
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
11234
11606
  reject: false
11235
11607
  });
@@ -11237,7 +11609,7 @@ async function inspectGitWorktree(worktreePath) {
11237
11609
  return "ok";
11238
11610
  }
11239
11611
  async function initializeGitRepository(worktreePath) {
11240
- if (!worktreePath || !(0, import_node_fs24.existsSync)(worktreePath)) {
11612
+ if (!worktreePath || !(0, import_node_fs28.existsSync)(worktreePath)) {
11241
11613
  throw new Error("Worktree not found");
11242
11614
  }
11243
11615
  const status = await inspectGitWorktree(worktreePath);
@@ -11372,11 +11744,11 @@ new file mode 100644
11372
11744
  };
11373
11745
  }
11374
11746
  async function untrackedPatch(worktreePath, path2, maxHunk) {
11375
- const abs = (0, import_node_path21.join)(worktreePath, path2);
11747
+ const abs = (0, import_node_path26.join)(worktreePath, path2);
11376
11748
  try {
11377
- const st = (0, import_node_fs24.statSync)(abs);
11749
+ const st = (0, import_node_fs28.statSync)(abs);
11378
11750
  if (st.isFile() && st.size > maxHunk) {
11379
- const buf = (0, import_node_fs24.readFileSync)(abs).subarray(0, maxHunk);
11751
+ const buf = (0, import_node_fs28.readFileSync)(abs).subarray(0, maxHunk);
11380
11752
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
11381
11753
  }
11382
11754
  } catch {
@@ -11877,8 +12249,8 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
11877
12249
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
11878
12250
  assertSafeRelativePath(relativePath);
11879
12251
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
11880
- const abs = (0, import_node_path21.join)(worktreePath, relativePath);
11881
- const st = (0, import_node_fs24.statSync)(abs);
12252
+ const abs = (0, import_node_path26.join)(worktreePath, relativePath);
12253
+ const st = (0, import_node_fs28.statSync)(abs);
11882
12254
  if (!st.isFile()) {
11883
12255
  throw new Error(`Not a file: ${relativePath}`);
11884
12256
  }
@@ -11887,7 +12259,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
11887
12259
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
11888
12260
  );
11889
12261
  }
11890
- const buf = (0, import_node_fs24.readFileSync)(abs);
12262
+ const buf = (0, import_node_fs28.readFileSync)(abs);
11891
12263
  return {
11892
12264
  path: relativePath,
11893
12265
  contentBase64: buf.toString("base64"),
@@ -11897,12 +12269,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
11897
12269
  function readWorktreeFile(worktreePath, relativePath, opts) {
11898
12270
  assertSafeRelativePath(relativePath);
11899
12271
  const maxBytes = opts?.maxBytes ?? 2e5;
11900
- const abs = (0, import_node_path21.join)(worktreePath, relativePath);
11901
- const st = (0, import_node_fs24.statSync)(abs);
12272
+ const abs = (0, import_node_path26.join)(worktreePath, relativePath);
12273
+ const st = (0, import_node_fs28.statSync)(abs);
11902
12274
  if (!st.isFile()) {
11903
12275
  throw new Error(`Not a file: ${relativePath}`);
11904
12276
  }
11905
- const buf = (0, import_node_fs24.readFileSync)(abs);
12277
+ const buf = (0, import_node_fs28.readFileSync)(abs);
11906
12278
  if (isImageRelativePath(relativePath)) {
11907
12279
  const maxImageBytes = Math.max(maxBytes, 15e6);
11908
12280
  const truncated2 = buf.length > maxImageBytes;
@@ -11945,9 +12317,9 @@ function assertSafeRelativePath(relativePath) {
11945
12317
  }
11946
12318
  function writeWorktreeFile(worktreePath, relativePath, content) {
11947
12319
  assertSafeRelativePath(relativePath);
11948
- const abs = (0, import_node_path21.join)(worktreePath, relativePath);
11949
- (0, import_node_fs24.mkdirSync)((0, import_node_path21.dirname)(abs), { recursive: true });
11950
- (0, import_node_fs24.writeFileSync)(abs, content, "utf8");
12320
+ const abs = (0, import_node_path26.join)(worktreePath, relativePath);
12321
+ (0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(abs), { recursive: true });
12322
+ (0, import_node_fs28.writeFileSync)(abs, content, "utf8");
11951
12323
  return { path: relativePath };
11952
12324
  }
11953
12325
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -11966,9 +12338,9 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
11966
12338
  }
11967
12339
 
11968
12340
  // src/skills/discover.ts
11969
- var import_node_fs25 = require("fs");
11970
- var import_node_os8 = require("os");
11971
- var import_node_path22 = require("path");
12341
+ var import_node_fs29 = require("fs");
12342
+ var import_node_os10 = require("os");
12343
+ var import_node_path27 = require("path");
11972
12344
  function toCommand(name) {
11973
12345
  return name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
11974
12346
  }
@@ -12000,7 +12372,7 @@ function parseFrontmatter(content) {
12000
12372
  }
12001
12373
  function readSkill(skillMd, source) {
12002
12374
  try {
12003
- const content = (0, import_node_fs25.readFileSync)(skillMd, "utf8");
12375
+ const content = (0, import_node_fs29.readFileSync)(skillMd, "utf8");
12004
12376
  const { name: fmName, description } = parseFrontmatter(content);
12005
12377
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
12006
12378
  const name = fmName || dirName;
@@ -12019,19 +12391,19 @@ function readSkill(skillMd, source) {
12019
12391
  }
12020
12392
  }
12021
12393
  function scanSkillsDir(dir, source, out) {
12022
- if (!(0, import_node_fs25.existsSync)(dir)) return;
12394
+ if (!(0, import_node_fs29.existsSync)(dir)) return;
12023
12395
  let entries;
12024
12396
  try {
12025
- entries = (0, import_node_fs25.readdirSync)(dir);
12397
+ entries = (0, import_node_fs29.readdirSync)(dir);
12026
12398
  } catch {
12027
12399
  return;
12028
12400
  }
12029
12401
  for (const entry of entries) {
12030
12402
  if (entry.startsWith(".")) continue;
12031
- const skillMd = (0, import_node_path22.join)(dir, entry, "SKILL.md");
12032
- if (!(0, import_node_fs25.existsSync)(skillMd)) continue;
12403
+ const skillMd = (0, import_node_path27.join)(dir, entry, "SKILL.md");
12404
+ if (!(0, import_node_fs29.existsSync)(skillMd)) continue;
12033
12405
  try {
12034
- if (!(0, import_node_fs25.statSync)(skillMd).isFile()) continue;
12406
+ if (!(0, import_node_fs29.statSync)(skillMd).isFile()) continue;
12035
12407
  } catch {
12036
12408
  continue;
12037
12409
  }
@@ -12040,24 +12412,24 @@ function scanSkillsDir(dir, source, out) {
12040
12412
  }
12041
12413
  }
12042
12414
  function scanClaudePluginSkills(pluginsRoot, out) {
12043
- if (!(0, import_node_fs25.existsSync)(pluginsRoot)) return;
12415
+ if (!(0, import_node_fs29.existsSync)(pluginsRoot)) return;
12044
12416
  const walk = (dir, depth, lookingForSkillsDir) => {
12045
12417
  if (depth > 7) return;
12046
12418
  let entries;
12047
12419
  try {
12048
- entries = (0, import_node_fs25.readdirSync)(dir);
12420
+ entries = (0, import_node_fs29.readdirSync)(dir);
12049
12421
  } catch {
12050
12422
  return;
12051
12423
  }
12052
12424
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
12053
- const skill = readSkill((0, import_node_path22.join)(dir, "SKILL.md"), "cli");
12425
+ const skill = readSkill((0, import_node_path27.join)(dir, "SKILL.md"), "cli");
12054
12426
  if (skill) out.push(skill);
12055
12427
  }
12056
12428
  for (const entry of entries) {
12057
12429
  if (entry === "node_modules" || entry === ".git") continue;
12058
- const full = (0, import_node_path22.join)(dir, entry);
12430
+ const full = (0, import_node_path27.join)(dir, entry);
12059
12431
  try {
12060
- if (!(0, import_node_fs25.statSync)(full).isDirectory()) continue;
12432
+ if (!(0, import_node_fs29.statSync)(full).isDirectory()) continue;
12061
12433
  } catch {
12062
12434
  continue;
12063
12435
  }
@@ -12072,20 +12444,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
12072
12444
  walk(pluginsRoot, 0, false);
12073
12445
  }
12074
12446
  function discoverSkills(worktreePath) {
12075
- const home = (0, import_node_os8.homedir)();
12447
+ const home = (0, import_node_os10.homedir)();
12076
12448
  const collected = [];
12077
12449
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
12078
- scanSkillsDir((0, import_node_path22.join)(worktreePath, rel), "workspace", collected);
12450
+ scanSkillsDir((0, import_node_path27.join)(worktreePath, rel), "workspace", collected);
12079
12451
  }
12080
12452
  for (const abs of [
12081
- (0, import_node_path22.join)(home, ".claude/skills"),
12082
- (0, import_node_path22.join)(home, ".cursor/skills"),
12083
- (0, import_node_path22.join)(home, ".sideboard/skills"),
12084
- (0, import_node_path22.join)(home, ".brightsy/skills")
12453
+ (0, import_node_path27.join)(home, ".claude/skills"),
12454
+ (0, import_node_path27.join)(home, ".cursor/skills"),
12455
+ (0, import_node_path27.join)(home, ".sideboard/skills"),
12456
+ (0, import_node_path27.join)(home, ".brightsy/skills")
12085
12457
  ]) {
12086
12458
  scanSkillsDir(abs, "user", collected);
12087
12459
  }
12088
- scanClaudePluginSkills((0, import_node_path22.join)(home, ".claude/plugins"), collected);
12460
+ scanClaudePluginSkills((0, import_node_path27.join)(home, ".claude/plugins"), collected);
12089
12461
  const rank = { workspace: 0, user: 1, cli: 2 };
12090
12462
  const byCommand = /* @__PURE__ */ new Map();
12091
12463
  for (const skill of collected) {
@@ -12097,7 +12469,7 @@ function discoverSkills(worktreePath) {
12097
12469
  return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
12098
12470
  }
12099
12471
  function readSkillBody(skillPath, maxChars = 12e3) {
12100
- const raw = (0, import_node_fs25.readFileSync)(skillPath, "utf8");
12472
+ const raw = (0, import_node_fs29.readFileSync)(skillPath, "utf8");
12101
12473
  if (raw.startsWith("---")) {
12102
12474
  const end = raw.indexOf("\n---", 3);
12103
12475
  if (end >= 0) {
@@ -12238,8 +12610,8 @@ function buildDiffCommentAttachment(input) {
12238
12610
  }
12239
12611
 
12240
12612
  // src/composer/stage-files.ts
12241
- var import_node_fs26 = require("fs");
12242
- var import_node_path23 = require("path");
12613
+ var import_node_fs30 = require("fs");
12614
+ var import_node_path28 = require("path");
12243
12615
  var import_node_crypto5 = require("crypto");
12244
12616
  init_workspace_scratch();
12245
12617
  var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
@@ -12265,7 +12637,7 @@ var IMAGE_MIME_BY_EXT = {
12265
12637
  var MAX_INLINE_BYTES = 4e5;
12266
12638
  var MAX_PREVIEW_BYTES = 5e6;
12267
12639
  function fileExtension(filePath) {
12268
- const base = (0, import_node_path23.basename)(filePath).toLowerCase();
12640
+ const base = (0, import_node_path28.basename)(filePath).toLowerCase();
12269
12641
  return base.includes(".") ? base.split(".").pop() || "" : "";
12270
12642
  }
12271
12643
  function isImageFilePath(filePath) {
@@ -12275,22 +12647,22 @@ function imageMimeType(filePath) {
12275
12647
  return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
12276
12648
  }
12277
12649
  function ensureAttachmentsDir(worktreePath) {
12278
- const dir = (0, import_node_path23.join)(worktreePath, ATTACHMENTS_DIR);
12279
- (0, import_node_fs26.mkdirSync)(dir, { recursive: true });
12280
- const gi = (0, import_node_path23.join)(dir, ".gitignore");
12281
- if (!(0, import_node_fs26.existsSync)(gi)) {
12282
- (0, import_node_fs26.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
12650
+ const dir = (0, import_node_path28.join)(worktreePath, ATTACHMENTS_DIR);
12651
+ (0, import_node_fs30.mkdirSync)(dir, { recursive: true });
12652
+ const gi = (0, import_node_path28.join)(dir, ".gitignore");
12653
+ if (!(0, import_node_fs30.existsSync)(gi)) {
12654
+ (0, import_node_fs30.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
12283
12655
  }
12284
12656
  return dir;
12285
12657
  }
12286
12658
  function uniqueAttachmentName(dir, originalName) {
12287
12659
  const safe = originalName.replace(/[/\\]/g, "_") || "file";
12288
- if (!(0, import_node_fs26.existsSync)((0, import_node_path23.join)(dir, safe))) return safe;
12289
- const ext = (0, import_node_path23.extname)(safe);
12660
+ if (!(0, import_node_fs30.existsSync)((0, import_node_path28.join)(dir, safe))) return safe;
12661
+ const ext = (0, import_node_path28.extname)(safe);
12290
12662
  const stem = ext ? safe.slice(0, -ext.length) : safe;
12291
12663
  for (let i = 1; i < 1e4; i++) {
12292
12664
  const candidate = `${stem}-${i}${ext}`;
12293
- if (!(0, import_node_fs26.existsSync)((0, import_node_path23.join)(dir, candidate))) return candidate;
12665
+ if (!(0, import_node_fs30.existsSync)((0, import_node_path28.join)(dir, candidate))) return candidate;
12294
12666
  }
12295
12667
  return `${stem}-${(0, import_node_crypto5.randomUUID)()}${ext}`;
12296
12668
  }
@@ -12342,9 +12714,9 @@ function attachmentFromBuffer(name, buf, opts) {
12342
12714
  };
12343
12715
  }
12344
12716
  function attachmentFromAbsolutePath(absolutePath) {
12345
- const name = (0, import_node_path23.basename)(absolutePath);
12717
+ const name = (0, import_node_path28.basename)(absolutePath);
12346
12718
  try {
12347
- const st = (0, import_node_fs26.statSync)(absolutePath);
12719
+ const st = (0, import_node_fs30.statSync)(absolutePath);
12348
12720
  if (!st.isFile()) {
12349
12721
  return {
12350
12722
  id: (0, import_node_crypto5.randomUUID)(),
@@ -12353,7 +12725,7 @@ function attachmentFromAbsolutePath(absolutePath) {
12353
12725
  content: `(not a file: ${absolutePath})`
12354
12726
  };
12355
12727
  }
12356
- const buf = (0, import_node_fs26.readFileSync)(absolutePath);
12728
+ const buf = (0, import_node_fs30.readFileSync)(absolutePath);
12357
12729
  return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
12358
12730
  } catch (err) {
12359
12731
  return {
@@ -12369,15 +12741,15 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
12369
12741
  const dir = ensureAttachmentsDir(worktreePath);
12370
12742
  const out = [];
12371
12743
  for (const abs of absolutePaths) {
12372
- const originalName = (0, import_node_path23.basename)(abs);
12744
+ const originalName = (0, import_node_path28.basename)(abs);
12373
12745
  try {
12374
- const st = (0, import_node_fs26.statSync)(abs);
12746
+ const st = (0, import_node_fs30.statSync)(abs);
12375
12747
  if (!st.isFile()) continue;
12376
12748
  const name = uniqueAttachmentName(dir, originalName);
12377
- const destAbs = (0, import_node_path23.join)(dir, name);
12378
- (0, import_node_fs26.copyFileSync)(abs, destAbs);
12749
+ const destAbs = (0, import_node_path28.join)(dir, name);
12750
+ (0, import_node_fs30.copyFileSync)(abs, destAbs);
12379
12751
  const rel = `${ATTACHMENTS_DIR}/${name}`;
12380
- const buf = (0, import_node_fs26.readFileSync)(destAbs);
12752
+ const buf = (0, import_node_fs30.readFileSync)(destAbs);
12381
12753
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
12382
12754
  } catch (err) {
12383
12755
  out.push({
@@ -12399,8 +12771,8 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
12399
12771
  try {
12400
12772
  const buf = Buffer.from(item.dataBase64, "base64");
12401
12773
  const name = uniqueAttachmentName(dir, originalName);
12402
- const destAbs = (0, import_node_path23.join)(dir, name);
12403
- (0, import_node_fs26.writeFileSync)(destAbs, buf);
12774
+ const destAbs = (0, import_node_path28.join)(dir, name);
12775
+ (0, import_node_fs30.writeFileSync)(destAbs, buf);
12404
12776
  const rel = `${ATTACHMENTS_DIR}/${name}`;
12405
12777
  out.push(attachmentFromBuffer(name, buf, { path: rel }));
12406
12778
  } catch (err) {
@@ -12436,18 +12808,18 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
12436
12808
  if (!rel || rel.includes("..") || rel.startsWith("/")) {
12437
12809
  out.push({
12438
12810
  id: (0, import_node_crypto5.randomUUID)(),
12439
- name: (0, import_node_path23.basename)(rel) || "file",
12811
+ name: (0, import_node_path28.basename)(rel) || "file",
12440
12812
  kind: "file",
12441
12813
  content: `(invalid path: ${rel})`
12442
12814
  });
12443
12815
  continue;
12444
12816
  }
12445
- const name = (0, import_node_path23.basename)(rel);
12817
+ const name = (0, import_node_path28.basename)(rel);
12446
12818
  try {
12447
- const abs = (0, import_node_path23.join)(worktreePath, rel);
12448
- const st = (0, import_node_fs26.statSync)(abs);
12819
+ const abs = (0, import_node_path28.join)(worktreePath, rel);
12820
+ const st = (0, import_node_fs30.statSync)(abs);
12449
12821
  if (!st.isFile()) continue;
12450
- const buf = (0, import_node_fs26.readFileSync)(abs);
12822
+ const buf = (0, import_node_fs30.readFileSync)(abs);
12451
12823
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
12452
12824
  } catch (err) {
12453
12825
  out.push({
@@ -12935,7 +13307,7 @@ async function confirmLand(thread, opts) {
12935
13307
  }
12936
13308
 
12937
13309
  // src/threads/create.ts
12938
- var import_node_fs27 = require("fs");
13310
+ var import_node_fs31 = require("fs");
12939
13311
  init_worktree();
12940
13312
  init_app_settings();
12941
13313
  init_thread_store();
@@ -12949,12 +13321,13 @@ async function createThread(input, _onSetupLine) {
12949
13321
  });
12950
13322
  await requireAgent(resolved.agent);
12951
13323
  const repoPath = await resolveRepoRoot(input.repoPath);
12952
- if (!(0, import_node_fs27.existsSync)(repoPath)) {
13324
+ if (!(0, import_node_fs31.existsSync)(repoPath)) {
12953
13325
  throw new Error(`Repo not found: ${repoPath}`);
12954
13326
  }
12955
13327
  let sourceRef = input.sourceRef;
12956
13328
  let sourceIsFork = false;
12957
13329
  let prUrl = null;
13330
+ let prTitle = null;
12958
13331
  if (input.sourceType === "pr") {
12959
13332
  const num2 = Number(input.sourceRef.replace(/^#/, ""));
12960
13333
  if (!Number.isFinite(num2)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
@@ -12970,6 +13343,12 @@ async function createThread(input, _onSetupLine) {
12970
13343
  } else if (input.sourceType === "branch") {
12971
13344
  if (!sourceRef || sourceRef === "HEAD" || sourceRef === "default") {
12972
13345
  sourceRef = await resolveDefaultBranch(repoPath);
13346
+ } else {
13347
+ const existing = await getPrForHeadBranch(repoPath, sourceRef);
13348
+ if (existing?.url) {
13349
+ prUrl = existing.url;
13350
+ prTitle = existing.title;
13351
+ }
12973
13352
  }
12974
13353
  } else if (input.sourceType === "adopt") {
12975
13354
  throw new Error("Use adoptThread() for adopt sources");
@@ -13000,7 +13379,8 @@ async function createThread(input, _onSetupLine) {
13000
13379
  sourceIsFork,
13001
13380
  parentThreadId: input.parentThreadId ?? null,
13002
13381
  status: "idle",
13003
- prUrl
13382
+ prUrl,
13383
+ prTitle
13004
13384
  });
13005
13385
  writeThread(thread);
13006
13386
  await ensureWorkspace(repoPath);
@@ -13176,7 +13556,7 @@ async function forkThreadWorktree(input, onSetupLine) {
13176
13556
  }
13177
13557
 
13178
13558
  // src/threads/stack-layers.ts
13179
- var import_node_fs28 = require("fs");
13559
+ var import_node_fs32 = require("fs");
13180
13560
  init_run();
13181
13561
  init_stack();
13182
13562
  init_worktree();
@@ -13244,7 +13624,7 @@ async function openStackLayer(input, _onSetupLine) {
13244
13624
  let createdWorktree = false;
13245
13625
  const trees = await listWorktrees(repoPath);
13246
13626
  const checkedOut = trees.find((w) => w.branch === branchName);
13247
- if (checkedOut?.path && (0, import_node_fs28.existsSync)(checkedOut.path)) {
13627
+ if (checkedOut?.path && (0, import_node_fs32.existsSync)(checkedOut.path)) {
13248
13628
  if (input.reuseExistingWorktree !== false) {
13249
13629
  worktreePath = checkedOut.path;
13250
13630
  } else {
@@ -13386,7 +13766,7 @@ async function initStackFromThread(input, onSetupLine) {
13386
13766
  async function createPrStack(input, onSetupLine) {
13387
13767
  await requireAgent(input.agent);
13388
13768
  const repoPath = await resolveRepoRoot(input.repoPath);
13389
- if (!(0, import_node_fs28.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
13769
+ if (!(0, import_node_fs32.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
13390
13770
  if (!input.branches.length) throw new Error("At least one branch name required");
13391
13771
  const status = await detectGhStack(repoPath);
13392
13772
  if (!status.available) throw new Error(status.reason);
@@ -13453,7 +13833,7 @@ async function createPrStack(input, onSetupLine) {
13453
13833
  }
13454
13834
  }
13455
13835
  const claimed = new Set(threads.map((t) => t.worktreePath));
13456
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs28.existsSync)(bootstrap.worktreePath)) {
13836
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs32.existsSync)(bootstrap.worktreePath)) {
13457
13837
  try {
13458
13838
  await removeWorktree(repoPath, bootstrap.worktreePath, {
13459
13839
  deleteBranch: bootstrap.branchName
@@ -13476,20 +13856,26 @@ function stackAgentDefaultsFrom(input) {
13476
13856
 
13477
13857
  // src/threads/adopt.ts
13478
13858
  var import_node_child_process4 = require("child_process");
13479
- var import_node_fs29 = require("fs");
13480
- var import_node_os9 = require("os");
13481
- var import_node_path24 = require("path");
13482
- var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
13859
+ var import_node_fs33 = require("fs");
13860
+ var import_node_os11 = require("os");
13861
+ var import_node_path29 = require("path");
13862
+ var import_node_module4 = require("module");
13483
13863
  init_worktree();
13484
13864
  init_thread_store();
13485
- var CONDUCTOR_APP_SUPPORT = (0, import_node_path24.join)(
13865
+ var import_meta4 = {};
13866
+ var CONDUCTOR_APP_SUPPORT = (0, import_node_path29.join)(
13486
13867
  process.env.HOME ?? "",
13487
13868
  "Library",
13488
13869
  "Application Support",
13489
13870
  "com.conductor.app"
13490
13871
  );
13491
- var CONDUCTOR_DB = (0, import_node_path24.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
13492
- var CURSOR_SDK_STORE = (0, import_node_path24.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
13872
+ var CONDUCTOR_DB = (0, import_node_path29.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
13873
+ var CURSOR_SDK_STORE = (0, import_node_path29.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
13874
+ function openReadonlySqlite(file) {
13875
+ const req = (0, import_node_module4.createRequire)(import_meta4.url);
13876
+ const Database = req("better-sqlite3");
13877
+ return new Database(file, { readonly: true, fileMustExist: true });
13878
+ }
13493
13879
  function mapAgentType(raw) {
13494
13880
  if (!raw) return null;
13495
13881
  const v = raw.toLowerCase();
@@ -13501,21 +13887,21 @@ function mapAgentType(raw) {
13501
13887
  return null;
13502
13888
  }
13503
13889
  function resolveConductorCursorAgentId(workspacePath) {
13504
- if (!workspacePath || !(0, import_node_fs29.existsSync)(CURSOR_SDK_STORE)) return null;
13890
+ if (!workspacePath || !(0, import_node_fs33.existsSync)(CURSOR_SDK_STORE)) return null;
13505
13891
  const normalized = workspacePath.replace(/\/$/, "");
13506
13892
  let best = null;
13507
13893
  let hashes;
13508
13894
  try {
13509
- hashes = (0, import_node_fs29.readdirSync)(CURSOR_SDK_STORE);
13895
+ hashes = (0, import_node_fs33.readdirSync)(CURSOR_SDK_STORE);
13510
13896
  } catch {
13511
13897
  return null;
13512
13898
  }
13513
13899
  for (const hash of hashes) {
13514
- const agentsFile = (0, import_node_path24.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
13515
- if (!(0, import_node_fs29.existsSync)(agentsFile)) continue;
13900
+ const agentsFile = (0, import_node_path29.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
13901
+ if (!(0, import_node_fs33.existsSync)(agentsFile)) continue;
13516
13902
  let text3;
13517
13903
  try {
13518
- text3 = (0, import_node_fs29.readFileSync)(agentsFile, "utf8");
13904
+ text3 = (0, import_node_fs33.readFileSync)(agentsFile, "utf8");
13519
13905
  } catch {
13520
13906
  continue;
13521
13907
  }
@@ -13539,7 +13925,7 @@ function resolveConductorCursorAgentId(workspacePath) {
13539
13925
  return best?.agentId ?? null;
13540
13926
  }
13541
13927
  async function adoptThread(input) {
13542
- if (!(0, import_node_fs29.existsSync)(input.worktreePath)) {
13928
+ if (!(0, import_node_fs33.existsSync)(input.worktreePath)) {
13543
13929
  throw new Error(`Worktree not found: ${input.worktreePath}`);
13544
13930
  }
13545
13931
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -13566,23 +13952,23 @@ function conductorDbPath() {
13566
13952
  return CONDUCTOR_DB;
13567
13953
  }
13568
13954
  function listConductorWorkspaces() {
13569
- if (!(0, import_node_fs29.existsSync)(CONDUCTOR_DB)) {
13955
+ if (!(0, import_node_fs33.existsSync)(CONDUCTOR_DB)) {
13570
13956
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
13571
13957
  }
13572
- const tmp = (0, import_node_fs29.mkdtempSync)((0, import_node_path24.join)((0, import_node_os9.tmpdir)(), "sideboard-conductor-"));
13573
- const snapshot = (0, import_node_path24.join)(tmp, "conductor.db");
13958
+ const tmp = (0, import_node_fs33.mkdtempSync)((0, import_node_path29.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
13959
+ const snapshot = (0, import_node_path29.join)(tmp, "conductor.db");
13574
13960
  try {
13575
- (0, import_node_fs29.copyFileSync)(CONDUCTOR_DB, snapshot);
13961
+ (0, import_node_fs33.copyFileSync)(CONDUCTOR_DB, snapshot);
13576
13962
  for (const suffix of ["-wal", "-shm"]) {
13577
13963
  const src = `${CONDUCTOR_DB}${suffix}`;
13578
- if ((0, import_node_fs29.existsSync)(src)) {
13964
+ if ((0, import_node_fs33.existsSync)(src)) {
13579
13965
  try {
13580
- (0, import_node_fs29.copyFileSync)(src, `${snapshot}${suffix}`);
13966
+ (0, import_node_fs33.copyFileSync)(src, `${snapshot}${suffix}`);
13581
13967
  } catch {
13582
13968
  }
13583
13969
  }
13584
13970
  }
13585
- const db = new import_better_sqlite3.default(snapshot, { readonly: true, fileMustExist: true });
13971
+ const db = openReadonlySqlite(snapshot);
13586
13972
  try {
13587
13973
  const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all();
13588
13974
  const names = new Set(tables.map((t) => t.name));
@@ -13653,27 +14039,27 @@ function listConductorWorkspaces() {
13653
14039
  db.close();
13654
14040
  }
13655
14041
  } finally {
13656
- (0, import_node_fs29.rmSync)(tmp, { recursive: true, force: true });
14042
+ (0, import_node_fs33.rmSync)(tmp, { recursive: true, force: true });
13657
14043
  }
13658
14044
  }
13659
14045
  function importConductorWorkspace(workspaceId) {
13660
- if (!(0, import_node_fs29.existsSync)(CONDUCTOR_DB)) {
14046
+ if (!(0, import_node_fs33.existsSync)(CONDUCTOR_DB)) {
13661
14047
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
13662
14048
  }
13663
- const tmp = (0, import_node_fs29.mkdtempSync)((0, import_node_path24.join)((0, import_node_os9.tmpdir)(), "sideboard-conductor-"));
13664
- const snapshot = (0, import_node_path24.join)(tmp, "conductor.db");
14049
+ const tmp = (0, import_node_fs33.mkdtempSync)((0, import_node_path29.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
14050
+ const snapshot = (0, import_node_path29.join)(tmp, "conductor.db");
13665
14051
  try {
13666
- (0, import_node_fs29.copyFileSync)(CONDUCTOR_DB, snapshot);
14052
+ (0, import_node_fs33.copyFileSync)(CONDUCTOR_DB, snapshot);
13667
14053
  for (const suffix of ["-wal", "-shm"]) {
13668
14054
  const src = `${CONDUCTOR_DB}${suffix}`;
13669
- if ((0, import_node_fs29.existsSync)(src)) {
14055
+ if ((0, import_node_fs33.existsSync)(src)) {
13670
14056
  try {
13671
- (0, import_node_fs29.copyFileSync)(src, `${snapshot}${suffix}`);
14057
+ (0, import_node_fs33.copyFileSync)(src, `${snapshot}${suffix}`);
13672
14058
  } catch {
13673
14059
  }
13674
14060
  }
13675
14061
  }
13676
- const db = new import_better_sqlite3.default(snapshot, { readonly: true, fileMustExist: true });
14062
+ const db = openReadonlySqlite(snapshot);
13677
14063
  try {
13678
14064
  const row = db.prepare(
13679
14065
  `SELECT
@@ -13686,7 +14072,7 @@ function importConductorWorkspace(workspaceId) {
13686
14072
  ).get(workspaceId);
13687
14073
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
13688
14074
  const worktreePath = String(row.workspacePath);
13689
- if (!(0, import_node_fs29.existsSync)(worktreePath)) {
14075
+ if (!(0, import_node_fs33.existsSync)(worktreePath)) {
13690
14076
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
13691
14077
  }
13692
14078
  let sessionId = null;
@@ -13749,7 +14135,7 @@ function importConductorWorkspace(workspaceId) {
13749
14135
  db.close();
13750
14136
  }
13751
14137
  } finally {
13752
- (0, import_node_fs29.rmSync)(tmp, { recursive: true, force: true });
14138
+ (0, import_node_fs33.rmSync)(tmp, { recursive: true, force: true });
13753
14139
  }
13754
14140
  }
13755
14141
  async function importConductorWorkspaceAsync(workspaceId) {
@@ -13760,8 +14146,8 @@ async function importConductorWorkspaceAsync(workspaceId) {
13760
14146
  var import_node_events = require("events");
13761
14147
 
13762
14148
  // src/slack/outbound-watch.ts
13763
- var import_node_fs31 = require("fs");
13764
- var import_node_path27 = require("path");
14149
+ var import_node_fs35 = require("fs");
14150
+ var import_node_path32 = require("path");
13765
14151
  init_paths();
13766
14152
  init_private_file();
13767
14153
  init_secure_file();
@@ -13807,19 +14193,19 @@ async function slackAuthTest(token) {
13807
14193
  }
13808
14194
 
13809
14195
  // src/slack/reply-target.ts
13810
- var import_node_fs30 = require("fs");
13811
- var import_node_path25 = require("path");
14196
+ var import_node_fs34 = require("fs");
14197
+ var import_node_path30 = require("path");
13812
14198
  init_paths();
13813
14199
  init_private_file();
13814
14200
  init_secure_file();
13815
14201
  function storePath2() {
13816
- return (0, import_node_path25.join)(appDataDir(), "slack-reply-to.json");
14202
+ return (0, import_node_path30.join)(appDataDir(), "slack-reply-to.json");
13817
14203
  }
13818
14204
  function readStore2() {
13819
14205
  const path2 = storePath2();
13820
- if (!(0, import_node_fs30.existsSync)(path2)) return {};
14206
+ if (!(0, import_node_fs34.existsSync)(path2)) return {};
13821
14207
  try {
13822
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
14208
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
13823
14209
  return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
13824
14210
  } catch {
13825
14211
  return {};
@@ -13836,11 +14222,11 @@ function getSlackReplyTarget(threadId) {
13836
14222
  }
13837
14223
 
13838
14224
  // src/slack/workspaces.ts
13839
- var import_node_path26 = require("path");
14225
+ var import_node_path31 = require("path");
13840
14226
  init_paths();
13841
14227
  init_secure_file();
13842
14228
  function storePath3() {
13843
- return (0, import_node_path26.join)(appDataDir(), "slack-workspaces.json");
14229
+ return (0, import_node_path31.join)(appDataDir(), "slack-workspaces.json");
13844
14230
  }
13845
14231
  function readStore3() {
13846
14232
  try {
@@ -13956,7 +14342,7 @@ var POLL_INTERVAL_MS = 12e3;
13956
14342
  var lastPollMs = 0;
13957
14343
  var nameCache = /* @__PURE__ */ new Map();
13958
14344
  function storePath4() {
13959
- return (0, import_node_path27.join)(appDataDir(), "slack-outbound-watch.json");
14345
+ return (0, import_node_path32.join)(appDataDir(), "slack-outbound-watch.json");
13960
14346
  }
13961
14347
  function watchId(teamId, channelId, ts) {
13962
14348
  return `${teamId}:${channelId}:${ts}`;
@@ -13986,9 +14372,9 @@ function tsNewer(a, b) {
13986
14372
  }
13987
14373
  function readStore4() {
13988
14374
  const path2 = storePath4();
13989
- if (!(0, import_node_fs31.existsSync)(path2)) return [];
14375
+ if (!(0, import_node_fs35.existsSync)(path2)) return [];
13990
14376
  try {
13991
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs31.readFileSync)(path2, "utf8"));
14377
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13992
14378
  return Array.isArray(parsed?.watches) ? parsed.watches : [];
13993
14379
  } catch {
13994
14380
  return [];
@@ -14333,7 +14719,7 @@ async function refreshSlackReplyBadges(opts) {
14333
14719
  }
14334
14720
 
14335
14721
  // src/orchestrator/orchestrator.ts
14336
- var import_node_fs37 = require("fs");
14722
+ var import_node_fs41 = require("fs");
14337
14723
  init_error_detail();
14338
14724
  init_agents();
14339
14725
  init_worktree();
@@ -14354,8 +14740,8 @@ function shouldAutoArchiveOnPrMerge(opts) {
14354
14740
  }
14355
14741
 
14356
14742
  // src/git/orphan-cleanup.ts
14357
- var import_node_fs32 = require("fs");
14358
- var import_node_path28 = require("path");
14743
+ var import_node_fs36 = require("fs");
14744
+ var import_node_path33 = require("path");
14359
14745
  init_worktree();
14360
14746
  init_thread_store();
14361
14747
  init_paths();
@@ -14370,9 +14756,9 @@ async function findOrphanWorktrees(repoPaths) {
14370
14756
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
14371
14757
  );
14372
14758
  const homeRoot = sideboardWorkspacesDir();
14373
- if ((0, import_node_fs32.existsSync)(homeRoot)) {
14759
+ if ((0, import_node_fs36.existsSync)(homeRoot)) {
14374
14760
  try {
14375
- for (const entry of (0, import_node_fs32.readdirSync)(homeRoot, { withFileTypes: true })) {
14761
+ for (const entry of (0, import_node_fs36.readdirSync)(homeRoot, { withFileTypes: true })) {
14376
14762
  if (!entry.isDirectory()) continue;
14377
14763
  void entry;
14378
14764
  }
@@ -14382,7 +14768,7 @@ async function findOrphanWorktrees(repoPaths) {
14382
14768
  const orphans = [];
14383
14769
  const seen = /* @__PURE__ */ new Set();
14384
14770
  for (const repoPath of repos) {
14385
- if (!repoPath || !(0, import_node_fs32.existsSync)(repoPath)) continue;
14771
+ if (!repoPath || !(0, import_node_fs36.existsSync)(repoPath)) continue;
14386
14772
  try {
14387
14773
  const wts = await listWorktrees(repoPath);
14388
14774
  for (const wt of wts) {
@@ -14393,7 +14779,7 @@ async function findOrphanWorktrees(repoPaths) {
14393
14779
  seen.add(path2);
14394
14780
  let mtimeMs = 0;
14395
14781
  try {
14396
- mtimeMs = (0, import_node_fs32.statSync)(path2).mtimeMs;
14782
+ mtimeMs = (0, import_node_fs36.statSync)(path2).mtimeMs;
14397
14783
  } catch {
14398
14784
  mtimeMs = 0;
14399
14785
  }
@@ -14403,16 +14789,16 @@ async function findOrphanWorktrees(repoPaths) {
14403
14789
  }
14404
14790
  try {
14405
14791
  const root = worktreesRoot(repoPath);
14406
- if ((0, import_node_fs32.existsSync)(root)) {
14407
- for (const entry of (0, import_node_fs32.readdirSync)(root, { withFileTypes: true })) {
14792
+ if ((0, import_node_fs36.existsSync)(root)) {
14793
+ for (const entry of (0, import_node_fs36.readdirSync)(root, { withFileTypes: true })) {
14408
14794
  if (!entry.isDirectory()) continue;
14409
- const path2 = (0, import_node_path28.join)(root, entry.name).replace(/\/$/, "");
14795
+ const path2 = (0, import_node_path33.join)(root, entry.name).replace(/\/$/, "");
14410
14796
  if (known.has(path2) || seen.has(path2)) continue;
14411
- if (!(0, import_node_fs32.existsSync)((0, import_node_path28.join)(path2, ".git"))) continue;
14797
+ if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(path2, ".git"))) continue;
14412
14798
  seen.add(path2);
14413
14799
  let mtimeMs = 0;
14414
14800
  try {
14415
- mtimeMs = (0, import_node_fs32.statSync)(path2).mtimeMs;
14801
+ mtimeMs = (0, import_node_fs36.statSync)(path2).mtimeMs;
14416
14802
  } catch {
14417
14803
  mtimeMs = Date.now();
14418
14804
  }
@@ -14558,8 +14944,8 @@ async function applyThreadIntoMain(thread, opts) {
14558
14944
  }
14559
14945
 
14560
14946
  // src/git/clone-repo.ts
14561
- var import_node_fs33 = require("fs");
14562
- var import_node_path29 = require("path");
14947
+ var import_node_fs37 = require("fs");
14948
+ var import_node_path34 = require("path");
14563
14949
  var import_execa6 = require("execa");
14564
14950
  init_paths();
14565
14951
  init_workspaces();
@@ -14569,12 +14955,12 @@ async function cloneRepoIntoSideboard(opts) {
14569
14955
  if (!url) throw new Error("Clone URL is required");
14570
14956
  let name = opts.name?.trim();
14571
14957
  if (!name) {
14572
- const leaf = (0, import_node_path29.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
14958
+ const leaf = (0, import_node_path34.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
14573
14959
  name = leaf || "repo";
14574
14960
  }
14575
14961
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
14576
- const dest = (0, import_node_path29.join)(sideboardReposDir(), name);
14577
- if ((0, import_node_fs33.existsSync)(dest)) {
14962
+ const dest = (0, import_node_path34.join)(sideboardReposDir(), name);
14963
+ if ((0, import_node_fs37.existsSync)(dest)) {
14578
14964
  const repoPath2 = await resolveRepoRoot(dest);
14579
14965
  const workspace2 = await ensureWorkspace(repoPath2);
14580
14966
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -14596,8 +14982,8 @@ init_orchestrator_capable();
14596
14982
 
14597
14983
  // src/review/request-review.ts
14598
14984
  var import_node_crypto8 = require("crypto");
14599
- var import_node_fs34 = require("fs");
14600
- var import_node_path30 = require("path");
14985
+ var import_node_fs38 = require("fs");
14986
+ var import_node_path35 = require("path");
14601
14987
  init_global_workspace();
14602
14988
  init_thread_store();
14603
14989
 
@@ -14745,22 +15131,22 @@ function shouldRefreshReviewRequestTemplate(content) {
14745
15131
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
14746
15132
  }
14747
15133
  function readTextIfPresent(abs) {
14748
- if (!(0, import_node_fs34.existsSync)(abs)) return null;
15134
+ if (!(0, import_node_fs38.existsSync)(abs)) return null;
14749
15135
  try {
14750
- const content = (0, import_node_fs34.readFileSync)(abs, "utf8");
15136
+ const content = (0, import_node_fs38.readFileSync)(abs, "utf8");
14751
15137
  return content.trim() ? content : null;
14752
15138
  } catch {
14753
15139
  return null;
14754
15140
  }
14755
15141
  }
14756
15142
  function ensureAttachmentsGitignore(worktreePath) {
14757
- const gitignoreAbs = (0, import_node_path30.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
14758
- if ((0, import_node_fs34.existsSync)(gitignoreAbs)) return;
14759
- (0, import_node_fs34.mkdirSync)((0, import_node_path30.dirname)(gitignoreAbs), { recursive: true });
14760
- (0, import_node_fs34.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
15143
+ const gitignoreAbs = (0, import_node_path35.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
15144
+ if ((0, import_node_fs38.existsSync)(gitignoreAbs)) return;
15145
+ (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(gitignoreAbs), { recursive: true });
15146
+ (0, import_node_fs38.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
14761
15147
  }
14762
15148
  function resolveReviewGuidelines(worktreePath) {
14763
- const repoAbs = (0, import_node_path30.join)(worktreePath, REPO_REVIEW_PATH);
15149
+ const repoAbs = (0, import_node_path35.join)(worktreePath, REPO_REVIEW_PATH);
14764
15150
  const repoContent = readTextIfPresent(repoAbs);
14765
15151
  if (repoContent) {
14766
15152
  return {
@@ -14770,7 +15156,7 @@ function resolveReviewGuidelines(worktreePath) {
14770
15156
  source: "repo"
14771
15157
  };
14772
15158
  }
14773
- const localAbs = (0, import_node_path30.join)(worktreePath, REVIEW_REQUEST_PATH);
15159
+ const localAbs = (0, import_node_path35.join)(worktreePath, REVIEW_REQUEST_PATH);
14774
15160
  const localContent = readTextIfPresent(localAbs);
14775
15161
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
14776
15162
  return {
@@ -14780,7 +15166,7 @@ function resolveReviewGuidelines(worktreePath) {
14780
15166
  source: "local"
14781
15167
  };
14782
15168
  }
14783
- const legacyAbs = (0, import_node_path30.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
15169
+ const legacyAbs = (0, import_node_path35.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
14784
15170
  const legacyContent = readTextIfPresent(legacyAbs);
14785
15171
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
14786
15172
  return {
@@ -14791,8 +15177,8 @@ function resolveReviewGuidelines(worktreePath) {
14791
15177
  };
14792
15178
  }
14793
15179
  ensureAttachmentsGitignore(worktreePath);
14794
- (0, import_node_fs34.mkdirSync)((0, import_node_path30.dirname)(localAbs), { recursive: true });
14795
- (0, import_node_fs34.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
15180
+ (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(localAbs), { recursive: true });
15181
+ (0, import_node_fs38.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
14796
15182
  return {
14797
15183
  path: REVIEW_REQUEST_PATH,
14798
15184
  name: REVIEW_REQUEST_NAME,
@@ -14801,7 +15187,7 @@ function resolveReviewGuidelines(worktreePath) {
14801
15187
  };
14802
15188
  }
14803
15189
  function ensureReviewRequestFile(worktreePath) {
14804
- const repoAbs = (0, import_node_path30.join)(worktreePath, REPO_REVIEW_PATH);
15190
+ const repoAbs = (0, import_node_path35.join)(worktreePath, REPO_REVIEW_PATH);
14805
15191
  const repoContent = readTextIfPresent(repoAbs);
14806
15192
  if (repoContent) {
14807
15193
  return {
@@ -14811,10 +15197,10 @@ function ensureReviewRequestFile(worktreePath) {
14811
15197
  source: "repo"
14812
15198
  };
14813
15199
  }
14814
- const localAbs = (0, import_node_path30.join)(worktreePath, REVIEW_REQUEST_PATH);
14815
- const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent((0, import_node_path30.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
15200
+ const localAbs = (0, import_node_path35.join)(worktreePath, REVIEW_REQUEST_PATH);
15201
+ const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent((0, import_node_path35.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
14816
15202
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
14817
- const path2 = (0, import_node_fs34.existsSync)(localAbs) ? REVIEW_REQUEST_PATH : LEGACY_REVIEW_REQUEST_PATH;
15203
+ const path2 = (0, import_node_fs38.existsSync)(localAbs) ? REVIEW_REQUEST_PATH : LEGACY_REVIEW_REQUEST_PATH;
14818
15204
  return {
14819
15205
  path: path2,
14820
15206
  name: REVIEW_REQUEST_NAME,
@@ -14822,8 +15208,8 @@ function ensureReviewRequestFile(worktreePath) {
14822
15208
  source: "local"
14823
15209
  };
14824
15210
  }
14825
- (0, import_node_fs34.mkdirSync)((0, import_node_path30.dirname)(repoAbs), { recursive: true });
14826
- (0, import_node_fs34.writeFileSync)(repoAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
15211
+ (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(repoAbs), { recursive: true });
15212
+ (0, import_node_fs38.writeFileSync)(repoAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
14827
15213
  return {
14828
15214
  path: REPO_REVIEW_PATH,
14829
15215
  name: REPO_REVIEW_NAME,
@@ -14843,7 +15229,7 @@ function buildReviewRequestAttachment(content, opts) {
14843
15229
  };
14844
15230
  }
14845
15231
  function readExistingReviewRequestFile(worktreePath) {
14846
- return readTextIfPresent((0, import_node_path30.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path30.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path30.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
15232
+ return readTextIfPresent((0, import_node_path35.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path35.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path35.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
14847
15233
  }
14848
15234
  async function requestReview(threadRef, send2) {
14849
15235
  const from = findThreadByRef(threadRef);
@@ -15104,7 +15490,7 @@ var Orchestrator = class {
15104
15490
  }
15105
15491
  continue;
15106
15492
  }
15107
- if (!(0, import_node_fs37.existsSync)(thread.worktreePath)) {
15493
+ if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
15108
15494
  setStatus(thread.id, "broken", "Worktree missing on disk");
15109
15495
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
15110
15496
  continue;
@@ -16196,8 +16582,9 @@ var Orchestrator = class {
16196
16582
  return result;
16197
16583
  }
16198
16584
  async mergePr(threadRef) {
16199
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
16585
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
16200
16586
  this.assertNotGlobal(thread, "Merge PR");
16587
+ const selector = selectors[0];
16201
16588
  if (!selector) throw new Error("No pull request linked to this thread");
16202
16589
  const result = await mergePr(cwd, selector);
16203
16590
  const state = normalizePrState(result.state) || "MERGED";
@@ -16217,29 +16604,34 @@ var Orchestrator = class {
16217
16604
  await this.persistPrMetaAndMaybeArchive(thread, metaLike);
16218
16605
  return { url: metaLike.url, state };
16219
16606
  }
16220
- /** Resolve PR selector and optionally persist `prUrl` when found. */
16607
+ /** Resolve PR selectors and optionally persist `prUrl` when found. */
16221
16608
  async withPrSelector(threadRef) {
16222
16609
  const thread = this.requireThread(threadRef);
16223
- const selector = resolvePrSelector(thread);
16610
+ const selectors = resolvePrSelectors(thread);
16224
16611
  const cwd = thread.worktreePath;
16225
16612
  if (!cwd?.trim()) {
16226
16613
  throw new Error(`Thread ${threadRef} has no worktreePath`);
16227
16614
  }
16228
- return { thread, selector, cwd };
16615
+ return { thread, selectors, cwd };
16229
16616
  }
16230
16617
  async getPrChecks(threadRef) {
16231
- const { selector, cwd } = await this.withPrSelector(threadRef);
16232
- if (!selector) return null;
16233
- return getPrChecks(cwd, selector);
16618
+ const { selectors, cwd } = await this.withPrSelector(threadRef);
16619
+ for (const selector of selectors) {
16620
+ const checks = await getPrChecks(cwd, selector);
16621
+ if (checks) return checks;
16622
+ }
16623
+ return null;
16234
16624
  }
16235
16625
  async getPrMeta(threadRef) {
16236
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
16237
- if (!selector) return null;
16238
- const meta = await getPrMeta(cwd, selector);
16239
- if (meta) {
16240
- await this.persistPrMetaAndMaybeArchive(thread, meta);
16626
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
16627
+ for (const selector of selectors) {
16628
+ const meta = await getPrMeta(cwd, selector);
16629
+ if (meta) {
16630
+ await this.persistPrMetaAndMaybeArchive(thread, meta);
16631
+ return meta;
16632
+ }
16241
16633
  }
16242
- return meta;
16634
+ return null;
16243
16635
  }
16244
16636
  /**
16245
16637
  * Persist PR URL/title/state and Conductor-style auto-archive when the PR
@@ -16363,9 +16755,12 @@ var Orchestrator = class {
16363
16755
  return { stack: result.stack, threads: result.threads };
16364
16756
  }
16365
16757
  async getPrDetails(threadRef) {
16366
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
16367
- if (!selector) return null;
16368
- const details = await getPrDetails(cwd, selector);
16758
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
16759
+ let details = null;
16760
+ for (const selector of selectors) {
16761
+ details = await getPrDetails(cwd, selector);
16762
+ if (details) break;
16763
+ }
16369
16764
  if (details) {
16370
16765
  const patch = {};
16371
16766
  if (details.url && details.url !== thread.prUrl) patch.prUrl = details.url;
@@ -16592,7 +16987,7 @@ var Orchestrator = class {
16592
16987
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
16593
16988
  return restored2;
16594
16989
  }
16595
- if (!(0, import_node_fs37.existsSync)(thread.worktreePath)) {
16990
+ if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
16596
16991
  const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
16597
16992
  const { execa: execa7 } = await import("execa");
16598
16993
  const slug = thread.worktreePath.split("/").pop();
@@ -16833,7 +17228,7 @@ init_coordinator_prompt();
16833
17228
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
16834
17229
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
16835
17230
  var import_zod3 = require("zod");
16836
- var import_node_path33 = require("path");
17231
+ var import_node_path38 = require("path");
16837
17232
  init_worktree();
16838
17233
  init_global_workspace();
16839
17234
  init_list_models();
@@ -17447,6 +17842,7 @@ function registerLinearTools(server) {
17447
17842
  }
17448
17843
 
17449
17844
  // src/mcp/server.ts
17845
+ init_git_auth_mode();
17450
17846
  var MAX_ORCH_THREADS = 5;
17451
17847
  var CREATE_THREAD_TIMEOUT_MS = 9e4;
17452
17848
  function withTimeout(promise, ms, label) {
@@ -17468,6 +17864,14 @@ function withTimeout(promise, ms, label) {
17468
17864
  }
17469
17865
  async function startMcpServer() {
17470
17866
  const orch = getOrchestrator();
17867
+ try {
17868
+ await warmGithubAgentAuth();
17869
+ } catch (err) {
17870
+ console.error(
17871
+ "[sideboard-mcp] GitHub agent auth warm skipped:",
17872
+ err instanceof Error ? err.message : err
17873
+ );
17874
+ }
17471
17875
  try {
17472
17876
  const { maxConcurrentAgents: maxConcurrentAgents2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
17473
17877
  orch.setMaxConcurrent(maxConcurrentAgents2());
@@ -17511,7 +17915,7 @@ async function startMcpServer() {
17511
17915
  async () => {
17512
17916
  const threads = orch.getThreads(true);
17513
17917
  const lines = threads.map((t) => {
17514
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path33.basename)(t.repoPath) || t.repoPath;
17918
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path38.basename)(t.repoPath) || t.repoPath;
17515
17919
  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}` : ""}`;
17516
17920
  });
17517
17921
  return {
@@ -17574,7 +17978,7 @@ async function startMcpServer() {
17574
17978
  );
17575
17979
  server.tool(
17576
17980
  "ask_user",
17577
- "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.",
17981
+ "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.",
17578
17982
  {
17579
17983
  questions: import_zod3.z.array(
17580
17984
  import_zod3.z.object({
@@ -18819,6 +19223,77 @@ init_accounts();
18819
19223
  init_connected_teams();
18820
19224
  init_injected_mcp();
18821
19225
 
19226
+ // src/agents/user-mcp-config.ts
19227
+ var import_node_fs42 = require("fs");
19228
+ var import_node_os12 = require("os");
19229
+ var import_node_path39 = require("path");
19230
+ init_paths();
19231
+ init_injected_mcp();
19232
+ function userCursorMcpConfigPath() {
19233
+ return (0, import_node_path39.join)((0, import_node_os12.homedir)(), ".cursor", "mcp.json");
19234
+ }
19235
+ function userClaudeMcpConfigPath() {
19236
+ return (0, import_node_path39.join)((0, import_node_os12.homedir)(), ".claude.json");
19237
+ }
19238
+ function asObject(value) {
19239
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
19240
+ return { ...value };
19241
+ }
19242
+ function stripElectronSpawnEnv(env) {
19243
+ if (!env) return void 0;
19244
+ const next = { ...env };
19245
+ delete next.ELECTRON_RUN_AS_NODE;
19246
+ delete next.ELECTRON_RUN_AS_NODE;
19247
+ return Object.keys(next).length > 0 ? next : void 0;
19248
+ }
19249
+ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
19250
+ const root = asObject(existing);
19251
+ const servers = asObject(root.mcpServers);
19252
+ const env = stripElectronSpawnEnv(sideboard.env);
19253
+ servers.sideboard = {
19254
+ type: "stdio",
19255
+ command: sideboard.command,
19256
+ ...sideboard.args && sideboard.args.length > 0 ? { args: sideboard.args } : {},
19257
+ ...env ? { env } : {}
19258
+ };
19259
+ return { ...root, mcpServers: servers };
19260
+ }
19261
+ function writeMergedMcpServersJson(configPath, sideboard) {
19262
+ let existing = {};
19263
+ if ((0, import_node_fs42.existsSync)(configPath)) {
19264
+ try {
19265
+ existing = JSON.parse((0, import_node_fs42.readFileSync)(configPath, "utf8"));
19266
+ } catch {
19267
+ existing = {};
19268
+ }
19269
+ }
19270
+ const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
19271
+ (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(configPath), { recursive: true });
19272
+ (0, import_node_fs42.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
19273
+ `);
19274
+ }
19275
+ function launchFromResolved(server) {
19276
+ return {
19277
+ command: server.command,
19278
+ args: server.args,
19279
+ env: {
19280
+ ...server.env ?? {},
19281
+ SIDEBOARD_APP_DATA: appDataDir()
19282
+ }
19283
+ };
19284
+ }
19285
+ async function registerPackagedUserMcpClients() {
19286
+ const launch = launchFromResolved(await resolveSideboardMcpServer());
19287
+ const cursor = userCursorMcpConfigPath();
19288
+ writeMergedMcpServersJson(cursor, launch);
19289
+ const claude = userClaudeMcpConfigPath();
19290
+ if ((0, import_node_fs42.existsSync)(claude)) {
19291
+ writeMergedMcpServersJson(claude, launch);
19292
+ return { cursor, claude };
19293
+ }
19294
+ return { cursor };
19295
+ }
19296
+
18822
19297
  // src/slack/oauth.ts
18823
19298
  var import_node_crypto10 = require("crypto");
18824
19299
  init_app_settings();
@@ -19593,15 +20068,10 @@ function connectSession2(ws, opts, log) {
19593
20068
  }
19594
20069
 
19595
20070
  // src/slack/listen.ts
19596
- var SLACK_LISTEN_BUSY_REPLY = [
19597
- "Sideboard is busy with an in-progress turn.",
19598
- "I did not start a new request.",
19599
- 'Send "stop" to interrupt, or try again when idle.'
19600
- ].join(" ");
19601
20071
  var SLACK_LISTEN_STOPPED_REPLY = "Sideboard stopped the in-progress turn. Send another message when you want to continue.";
19602
20072
  var SLACK_LISTEN_TIMEOUT_REPLY = [
19603
20073
  "Sideboard timed out waiting for the local agent turn to finish.",
19604
- 'Send "stop" to interrupt, or try again.'
20074
+ 'Send another message to interrupt and retry, or send "stop".'
19605
20075
  ].join(" ");
19606
20076
  var handleChain = Promise.resolve();
19607
20077
  function enqueueHandle(fn) {
@@ -19615,6 +20085,30 @@ function enqueueHandle(fn) {
19615
20085
  function refreshWorkspaces2() {
19616
20086
  return getOrchestrator().listWorkspaces();
19617
20087
  }
20088
+ function slackInboundSuperseded(opts) {
20089
+ if (opts.inboundGeneration === void 0 || !opts.currentInboundGeneration) {
20090
+ return false;
20091
+ }
20092
+ return opts.currentInboundGeneration() !== opts.inboundGeneration;
20093
+ }
20094
+ function interruptSlackCoordinatorForInbound(msg, agent, log = () => void 0) {
20095
+ const userId = msg.userId?.trim();
20096
+ if (!userId) return false;
20097
+ const coordinator = ensureSlackCoordinator(msg.teamId, userId, agent);
20098
+ const fresh = readThread(coordinator.id) ?? coordinator;
20099
+ if (fresh.status !== "running" && fresh.status !== "queued") return false;
20100
+ try {
20101
+ getOrchestrator().stop(fresh.id, { clearQueue: true });
20102
+ log(
20103
+ `interrupt ${msg.kind} ${msg.ts} \u2192 coordinator ${fresh.id.slice(0, 8)} (${fresh.status})`
20104
+ );
20105
+ return true;
20106
+ } catch (err) {
20107
+ const errMsg = err instanceof Error ? err.message : String(err);
20108
+ log(`interrupt ${msg.ts}: ${errMsg}`);
20109
+ return false;
20110
+ }
20111
+ }
19618
20112
  function formatSlackInboundPrompt(msg) {
19619
20113
  const kind = msg.kind === "mention" ? "Slack @mention" : "Slack DM";
19620
20114
  return `${kind}
@@ -19745,7 +20239,13 @@ async function relayCoordinatorReplyToSlack(threadId, opts) {
19745
20239
  }
19746
20240
  async function handleSlackInbound(msg, opts) {
19747
20241
  const log = opts.onLog ?? (() => void 0);
19748
- await ackSlackInboundSeen(msg, opts);
20242
+ if (!opts.skipAck) {
20243
+ await ackSlackInboundSeen(msg, opts);
20244
+ }
20245
+ if (slackInboundSuperseded(opts)) {
20246
+ log(`skip superseded ${msg.kind} ${msg.ts}`);
20247
+ return;
20248
+ }
19749
20249
  const agent = coerceOrchestratorAgent(opts.agent ?? getDefaultAgent());
19750
20250
  const workspaces = refreshWorkspaces2();
19751
20251
  for (const ws of workspaces) {
@@ -19757,25 +20257,31 @@ async function handleSlackInbound(msg, opts) {
19757
20257
  log(`skip ${msg.kind} ${msg.ts}: missing Slack user id`);
19758
20258
  return;
19759
20259
  }
20260
+ if (slackInboundSuperseded(opts)) {
20261
+ log(`skip superseded ${msg.kind} ${msg.ts}`);
20262
+ return;
20263
+ }
19760
20264
  const coordinator = ensureSlackCoordinator(msg.teamId, userId, agent);
19761
- const fresh = readThread(coordinator.id) ?? coordinator;
20265
+ let fresh = readThread(coordinator.id) ?? coordinator;
19762
20266
  if (isSlackStopCommand(msg.text)) {
19763
20267
  try {
19764
- getOrchestrator().stop(fresh.id);
20268
+ getOrchestrator().stop(fresh.id, { clearQueue: true });
19765
20269
  log(`stop ${msg.kind} ${msg.ts} \u2192 coordinator ${fresh.id.slice(0, 8)}`);
19766
20270
  } catch (err) {
19767
20271
  const errMsg = err instanceof Error ? err.message : String(err);
19768
20272
  log(`stop ${msg.ts}: ${errMsg}`);
19769
20273
  }
20274
+ if (slackInboundSuperseded(opts)) {
20275
+ log(`skip superseded stop reply ${msg.ts}`);
20276
+ return;
20277
+ }
19770
20278
  await postSlackReply(msg, SLACK_LISTEN_STOPPED_REPLY, opts);
19771
20279
  log(`replied stopped ${msg.ts}`);
19772
20280
  return;
19773
20281
  }
19774
20282
  if (fresh.status === "running" || fresh.status === "queued") {
19775
- log(`busy ${msg.kind} ${msg.ts} \u2192 coordinator ${fresh.id.slice(0, 8)} (${fresh.status})`);
19776
- await postSlackReply(msg, SLACK_LISTEN_BUSY_REPLY, opts);
19777
- log(`replied busy ${msg.ts}`);
19778
- return;
20283
+ interruptSlackCoordinatorForInbound(msg, agent, log);
20284
+ fresh = readThread(coordinator.id) ?? coordinator;
19779
20285
  }
19780
20286
  log(
19781
20287
  `run ${msg.kind} ${msg.ts} user ${userId} \u2192 coordinator ${fresh.id.slice(0, 8)} (${inventory.length} workspace${inventory.length === 1 ? "" : "s"})`
@@ -19792,8 +20298,21 @@ async function handleSlackInbound(msg, opts) {
19792
20298
  try {
19793
20299
  await orch.send(fresh.id, prompt);
19794
20300
  await orch.waitForTurn(fresh.id, 14 * 60 * 1e3);
20301
+ if (slackInboundSuperseded(opts)) {
20302
+ log(`turn finished ${msg.ts} (superseded)`);
20303
+ return;
20304
+ }
20305
+ const after = readThread(fresh.id);
20306
+ if (after?.status === "stopped") {
20307
+ log(`turn finished ${msg.ts} (interrupted, skip post)`);
20308
+ return;
20309
+ }
19795
20310
  reply = orch.getTurnResult(fresh.id).text.trim();
19796
20311
  } catch (err) {
20312
+ if (slackInboundSuperseded(opts)) {
20313
+ log(`turn error ${msg.ts} (superseded)`);
20314
+ return;
20315
+ }
19797
20316
  const errMsg = err instanceof Error ? err.message : String(err);
19798
20317
  const timedOut = /timed out|timeout/i.test(errMsg);
19799
20318
  const errorReply = timedOut ? SLACK_LISTEN_TIMEOUT_REPLY : `Sideboard coordinator error: ${errMsg}`;
@@ -19841,19 +20360,35 @@ async function runSlackListen(opts = {}) {
19841
20360
  const log = opts.onLog ?? console.log;
19842
20361
  const connected = listSlackWorkspacesRaw();
19843
20362
  const orch = getOrchestrator();
20363
+ const agent = coerceOrchestratorAgent(opts.agent ?? getDefaultAgent());
20364
+ let inboundGeneration = 0;
19844
20365
  const off = orch.on((event) => {
19845
20366
  if (event.type !== "turn_finished") return;
19846
20367
  void relayCoordinatorReplyToSlack(event.threadId, opts);
19847
20368
  });
19848
- const onInbound = (msg) => enqueueHandle(async () => {
20369
+ const onInbound = (msg) => {
19849
20370
  if (!isInboundForThisDesktop(msg)) {
19850
20371
  log(
19851
20372
  `skip ${msg.kind} ${msg.ts}: Slack user ${msg.userId ?? "?"} is not connected on this Mac`
19852
20373
  );
19853
20374
  return;
19854
20375
  }
19855
- await handleSlackInbound(msg, opts);
19856
- });
20376
+ const generation = ++inboundGeneration;
20377
+ void ackSlackInboundSeen(msg, opts);
20378
+ interruptSlackCoordinatorForInbound(msg, agent, log);
20379
+ return enqueueHandle(async () => {
20380
+ if (generation !== inboundGeneration) {
20381
+ log(`skip superseded ${msg.kind} ${msg.ts}`);
20382
+ return;
20383
+ }
20384
+ await handleSlackInbound(msg, {
20385
+ ...opts,
20386
+ skipAck: true,
20387
+ inboundGeneration: generation,
20388
+ currentInboundGeneration: () => inboundGeneration
20389
+ });
20390
+ });
20391
+ };
19857
20392
  try {
19858
20393
  const relay = (opts.relayUrl ?? slackRelayUrl()).trim();
19859
20394
  if (!relay) {
@@ -20125,9 +20660,9 @@ var import_node_http3 = require("http");
20125
20660
  var import_ws3 = require("ws");
20126
20661
 
20127
20662
  // src/slack/relay-static.ts
20128
- var import_node_fs38 = require("fs");
20663
+ var import_node_fs43 = require("fs");
20129
20664
  var import_promises = require("fs/promises");
20130
- var import_node_path34 = __toESM(require("path"), 1);
20665
+ var import_node_path40 = __toESM(require("path"), 1);
20131
20666
  var TYPES = {
20132
20667
  ".css": "text/css; charset=utf-8",
20133
20668
  ".html": "text/html; charset=utf-8",
@@ -20158,9 +20693,9 @@ function resolveStaticPath(root, requestUrl) {
20158
20693
  return null;
20159
20694
  }
20160
20695
  if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
20161
- const rootResolved = import_node_path34.default.resolve(root);
20162
- const candidate = import_node_path34.default.resolve(rootResolved, `.${pathname}`);
20163
- if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path34.default.sep)) {
20696
+ const rootResolved = import_node_path40.default.resolve(root);
20697
+ const candidate = import_node_path40.default.resolve(rootResolved, `.${pathname}`);
20698
+ if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path40.default.sep)) {
20164
20699
  return null;
20165
20700
  }
20166
20701
  return candidate;
@@ -20174,7 +20709,7 @@ async function fileSize(file) {
20174
20709
  }
20175
20710
  }
20176
20711
  function sendFile(req, res, file, size) {
20177
- const ext = import_node_path34.default.extname(file).toLowerCase();
20712
+ const ext = import_node_path40.default.extname(file).toLowerCase();
20178
20713
  res.writeHead(200, {
20179
20714
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
20180
20715
  "Content-Length": size,
@@ -20184,7 +20719,7 @@ function sendFile(req, res, file, size) {
20184
20719
  res.end();
20185
20720
  return true;
20186
20721
  }
20187
- (0, import_node_fs38.createReadStream)(file).pipe(res);
20722
+ (0, import_node_fs43.createReadStream)(file).pipe(res);
20188
20723
  return true;
20189
20724
  }
20190
20725
  async function tryServeStatic(req, res, root) {
@@ -20193,7 +20728,7 @@ async function tryServeStatic(req, res, root) {
20193
20728
  if (!candidate) return false;
20194
20729
  const direct = await fileSize(candidate);
20195
20730
  if (direct != null) return sendFile(req, res, candidate, direct);
20196
- const asIndex = import_node_path34.default.join(candidate, "index.html");
20731
+ const asIndex = import_node_path40.default.join(candidate, "index.html");
20197
20732
  const indexSize = await fileSize(asIndex);
20198
20733
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
20199
20734
  return false;
@@ -20456,7 +20991,6 @@ async function startSlackRelayServer(opts) {
20456
20991
  SIDEBOARD_FORCE_STOP,
20457
20992
  SIDEBOARD_MCP_ALLOWED_TOOLS,
20458
20993
  SIDEBOARD_MCP_PROFILE_ENV,
20459
- SLACK_LISTEN_BUSY_REPLY,
20460
20994
  SLACK_LISTEN_STOPPED_REPLY,
20461
20995
  SLACK_LISTEN_TIMEOUT_REPLY,
20462
20996
  SLACK_OAUTH_CANCELLED,
@@ -20526,6 +21060,7 @@ async function startSlackRelayServer(opts) {
20526
21060
  cleanupOrphanWorktrees,
20527
21061
  cloneRepoIntoSideboard,
20528
21062
  codexAdapter,
21063
+ codexSandboxWritableRootsArgs,
20529
21064
  codexUnattendedGitConfigArgs,
20530
21065
  coerceOrchestratorAgent,
20531
21066
  collectTakenTeamSlugs,
@@ -20642,6 +21177,7 @@ async function startSlackRelayServer(opts) {
20642
21177
  getPr,
20643
21178
  getPrChecks,
20644
21179
  getPrDetails,
21180
+ getPrForHeadBranch,
20645
21181
  getPrMeta,
20646
21182
  getPrStack,
20647
21183
  getRepoSetupInfo,
@@ -20672,12 +21208,14 @@ async function startSlackRelayServer(opts) {
20672
21208
  initializeGitRepository,
20673
21209
  inspectGitWorktree,
20674
21210
  installAgent,
21211
+ interruptSlackCoordinatorForInbound,
20675
21212
  isAskUserToolName,
20676
21213
  isBrightsyConnected,
20677
21214
  isBrightsyNdjsonLine,
20678
21215
  isCloudCoordinatorThread,
20679
21216
  isConductorBundledCli,
20680
21217
  isCursorAutoModel,
21218
+ isDefaultishSourceRef,
20681
21219
  isDirty,
20682
21220
  isGhRateLimitError,
20683
21221
  isGlobalRepoPath,
@@ -20744,8 +21282,10 @@ async function startSlackRelayServer(opts) {
20744
21282
  maybeCompactContext,
20745
21283
  mcpAllowTools,
20746
21284
  mcpAuthWarnings,
21285
+ mergeAgentGitAuthEnv,
20747
21286
  mergePr,
20748
21287
  mergePrStack,
21288
+ mergeSideboardIntoMcpServersJson,
20749
21289
  mergeUsage,
20750
21290
  nextPastedTextName,
20751
21291
  nextThinkingEffort,
@@ -20796,6 +21336,7 @@ async function startSlackRelayServer(opts) {
20796
21336
  recordSlackOutboundWatch,
20797
21337
  refreshGitHubAuth,
20798
21338
  refreshSlackReplyBadges,
21339
+ registerPackagedUserMcpClients,
20799
21340
  releaseCaffeinateHoldForThread,
20800
21341
  removeWorkspace,
20801
21342
  removeWorktree,
@@ -20804,9 +21345,11 @@ async function startSlackRelayServer(opts) {
20804
21345
  requestReview,
20805
21346
  requireAgent,
20806
21347
  resetGhStackDetectCache,
21348
+ resetGithubAgentTokenMemo,
20807
21349
  resolveAgentExecutable,
20808
21350
  resolveAgentGitAuthEnv,
20809
21351
  resolveClaudeExecutable,
21352
+ resolveCodexGitWritableRoots,
20810
21353
  resolveCommandBinarySync,
20811
21354
  resolveConductorCursorAgentId,
20812
21355
  resolveCursorModelId,
@@ -20823,6 +21366,7 @@ async function startSlackRelayServer(opts) {
20823
21366
  resolveNewThreadOptions,
20824
21367
  resolvePlanMarkdown,
20825
21368
  resolvePrSelector,
21369
+ resolvePrSelectors,
20826
21370
  resolveQuotaFallbackAgent,
20827
21371
  resolveRepoRoot,
20828
21372
  resolveReviewGuidelines,
@@ -20845,6 +21389,7 @@ async function startSlackRelayServer(opts) {
20845
21389
  sanitizeMcpServerName,
20846
21390
  saveAppSettings,
20847
21391
  saveLinearOAuth,
21392
+ scrubGithubTokensFromChildEnv,
20848
21393
  secureFileUnlocksWith,
20849
21394
  setCaffeinateHold,
20850
21395
  setHttpFetchImpl,
@@ -20915,7 +21460,10 @@ async function startSlackRelayServer(opts) {
20915
21460
  updateLinearIssue,
20916
21461
  updateOpencodeSettings,
20917
21462
  updateThread,
21463
+ userClaudeMcpConfigPath,
21464
+ userCursorMcpConfigPath,
20918
21465
  validateLinearApiKey,
21466
+ warmGithubAgentAuth,
20919
21467
  withAgentInstructions,
20920
21468
  withExportedPath,
20921
21469
  withThreadLock,