@sideboard-ai/core 0.1.148 → 0.1.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/{abletime-QEVAE67D.js → abletime-223A3LY6.js} +2 -2
  2. package/dist/{abletime-DI55AJX3.js → abletime-CLC5UJC2.js} +2 -2
  3. package/dist/agents/cursor-runner.cjs +85 -45
  4. package/dist/agents/cursor-runner.js +47 -12
  5. package/dist/{agents-DUF4Q2ZI.js → agents-KKXGTEV6.js} +10 -9
  6. package/dist/{agents-INCTFWKA.js → agents-YWBQXOA2.js} +10 -9
  7. package/dist/{app-settings-WJDCJFSY.js → app-settings-3CHCNIMD.js} +5 -1
  8. package/dist/{app-settings-ZCN632OJ.js → app-settings-J3JBCUOT.js} +5 -1
  9. package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
  10. package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
  11. package/dist/{chunk-R4JP32P5.js → chunk-AF6O55PJ.js} +4 -4
  12. package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
  13. package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
  14. package/dist/{chunk-ZVYLEF72.js → chunk-DMRIZR6M.js} +6 -6
  15. package/dist/{chunk-5MS2XTNV.js → chunk-DXCNW2JF.js} +113 -52
  16. package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
  17. package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
  18. package/dist/{chunk-3QRGCKYL.js → chunk-HAS5EPBS.js} +2 -2
  19. package/dist/{chunk-WT5HSFOU.js → chunk-HEII7W3Q.js} +5 -2
  20. package/dist/{chunk-EGDRPA4B.js → chunk-NOTANBYC.js} +6 -6
  21. package/dist/{chunk-CTXQHSTY.js → chunk-NUPITVRF.js} +134 -73
  22. package/dist/{chunk-QTUESPAW.js → chunk-PTOSP4AH.js} +1 -1
  23. package/dist/{chunk-Q62SDB53.js → chunk-QGJHIJHV.js} +2 -2
  24. package/dist/{chunk-YQRBNOIW.js → chunk-SDN4ZYQH.js} +24 -13
  25. package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
  26. package/dist/{chunk-N3VNOFXQ.js → chunk-VO4SPEBS.js} +4 -4
  27. package/dist/chunk-VSFGPWCQ.js +62 -0
  28. package/dist/{chunk-N5PM7HGQ.js → chunk-W6N6GQME.js} +1 -1
  29. package/dist/{chunk-FKOIHGKV.js → chunk-WHU7YGWP.js} +1 -1
  30. package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
  31. package/dist/chunk-Y4NAPW5I.js +60 -0
  32. package/dist/{chunk-B3SJXYIJ.js → chunk-Y7YBWWIG.js} +1 -1
  33. package/dist/{chunk-XOKHXFFX.js → chunk-YGGBJY5A.js} +22 -8
  34. package/dist/{chunk-JTPDWTWJ.js → chunk-Z2PVJKMN.js} +137 -114
  35. package/dist/{chunk-YP3CSOZ6.js → chunk-ZGFYFVJF.js} +142 -114
  36. package/dist/{connected-teams-IJUJQ7R6.js → connected-teams-I2WZZZFA.js} +2 -2
  37. package/dist/{connected-teams-4A2AXDNN.js → connected-teams-XO766HB4.js} +2 -2
  38. package/dist/{coordinator-prompt-ZWBMAIWA.js → coordinator-prompt-NYR5TPBD.js} +6 -5
  39. package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-UCQJTFA7.js} +6 -5
  40. package/dist/{global-workspace-2SIPM4PW.js → global-workspace-4QHDAD2D.js} +7 -6
  41. package/dist/{global-workspace-OJRXWXEA.js → global-workspace-4SENNWBU.js} +7 -6
  42. package/dist/index.cjs +1002 -575
  43. package/dist/index.d.cts +91 -10
  44. package/dist/index.d.ts +91 -10
  45. package/dist/index.js +268 -93
  46. package/dist/mcp/run-stdio.cjs +980 -580
  47. package/dist/mcp/run-stdio.js +196 -43
  48. package/dist/{orchestrator-OVYITCO6.js → orchestrator-GZE4X3XV.js} +14 -11
  49. package/dist/{orchestrator-NWIU5TJP.js → orchestrator-QSBRWME5.js} +16 -13
  50. package/dist/{plan-file-6O7G4VPQ.js → plan-file-5S5TUNAW.js} +2 -2
  51. package/dist/{plan-file-PHVKUAEE.js → plan-file-IBSU2PVW.js} +2 -2
  52. package/dist/{run-XQKGHQZ2.js → run-CAGKZLHA.js} +1 -1
  53. package/dist/{run-USF6FRKV.js → run-EBWL2Q4N.js} +1 -1
  54. package/dist/{workspaces-UUJNOO4T.js → workspaces-7S7QKCUE.js} +8 -7
  55. package/dist/{workspaces-3NUUZTQK.js → workspaces-RDUSB6FD.js} +8 -7
  56. package/dist/{worktree-RZRJNHYL.js → worktree-63AGPPLO.js} +5 -4
  57. package/dist/{worktree-UCWWTVLS.js → worktree-JIZ3QMZX.js} +5 -4
  58. package/dist/worktree-exclude-6MQWGWV5.js +11 -0
  59. package/dist/worktree-exclude-TV6EV6BS.js +9 -0
  60. package/package.json +1 -1
@@ -1,25 +1,35 @@
1
1
  import {
2
2
  isWorkspaceScratchPath
3
- } from "./chunk-FKOIHGKV.js";
3
+ } from "./chunk-WHU7YGWP.js";
4
4
  import {
5
5
  getGithubGitAuthMode,
6
6
  getGithubPat
7
- } from "./chunk-I77RYPOH.js";
7
+ } from "./chunk-4XNSGDXE.js";
8
8
  import {
9
9
  listThreads
10
10
  } from "./chunk-TUGKX5BD.js";
11
11
  import {
12
12
  worktreesRoot
13
13
  } from "./chunk-QZQEXME2.js";
14
+ import {
15
+ ensureWorktreeSideboardIgnored
16
+ } from "./chunk-Y4NAPW5I.js";
14
17
  import {
15
18
  gh,
16
19
  git,
20
+ githubAgentAuthDir,
21
+ githubAgentAuthReady,
22
+ githubCredentialHelperGitConfig,
23
+ githubGhConfigEnv,
24
+ materializeGithubAgentAuth,
17
25
  resolveGhAuthToken
18
- } from "./chunk-DVM4ID64.js";
26
+ } from "./chunk-UFHNSFAS.js";
19
27
 
20
28
  // src/git/worktree.ts
21
- import { existsSync as existsSync2, readdirSync, realpathSync } from "fs";
22
- import { join as join2 } from "path";
29
+ import { randomBytes } from "crypto";
30
+ import { existsSync, readdirSync, realpathSync, unlinkSync, writeFileSync } from "fs";
31
+ import { tmpdir } from "os";
32
+ import { join } from "path";
23
33
 
24
34
  // src/git/team-meta.ts
25
35
  var SOCCER_TEAM_META = {
@@ -833,9 +843,23 @@ function worktreeDisplayLabelForGroup(threads) {
833
843
  }
834
844
 
835
845
  // src/git/gh-errors.ts
846
+ var GITHUB_PR_BODY_MAX_CHARS = 65536;
847
+ var GITHUB_PR_BODY_SAFE_CHARS = 6e4;
836
848
  function isGhRateLimitError(text) {
837
849
  return /API rate limit (already )?exceeded/i.test(text) || /rate limit exceeded/i.test(text);
838
850
  }
851
+ function isGhPrBodyTooLongError(text) {
852
+ return /body is too long|body.{0,20}too long|maximum is 65536|exceeds the maximum allowed size|request (entity |is )?too large|payload too large|413 Request Entity Too Large/i.test(
853
+ text
854
+ );
855
+ }
856
+ function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
857
+ const t = body.replace(/\s+$/u, "");
858
+ if (t.length <= max) return t;
859
+ const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
860
+ const keep = Math.max(0, max - note.length);
861
+ return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
862
+ }
839
863
  function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
840
864
  const ms = resetEpochSec * 1e3 - nowMs;
841
865
  if (ms <= 0) return "soon";
@@ -846,18 +870,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
846
870
  const hours = Math.ceil(mins / 60);
847
871
  return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
848
872
  }
873
+ function omitGhBodyArg(text) {
874
+ return text.replace(
875
+ /--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
876
+ "--body <omitted>"
877
+ );
878
+ }
879
+ function capGhErrorText(text, max = 400) {
880
+ const t = text.trim();
881
+ if (t.length <= max) return t;
882
+ return `${t.slice(0, max - 1).trimEnd()}\u2026`;
883
+ }
849
884
  function extractGhErrorDetail(text) {
850
- const trimmed = text.trim();
885
+ const trimmed = omitGhBodyArg(text.trim());
851
886
  if (!trimmed) return "";
887
+ if (isGhPrBodyTooLongError(text) || isGhPrBodyTooLongError(trimmed)) {
888
+ return "GraphQL: body is too long (GitHub PR body / request size limit).";
889
+ }
852
890
  const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
853
- if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}`;
891
+ if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
854
892
  const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
855
- if (http?.[1]) return `HTTP: ${http[1].trim()}`;
893
+ if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
856
894
  const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
857
895
  if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
858
- return lines.slice(1).join(" ").trim() || lines[0];
896
+ return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
859
897
  }
860
- return trimmed;
898
+ return capGhErrorText(trimmed);
861
899
  }
862
900
  function formatGhLandError(raw, opts) {
863
901
  const trimmed = raw.trim();
@@ -875,6 +913,10 @@ function formatGhLandError(raw, opts) {
875
913
  const hint = opts?.targetedRepo ? ` Branch was pushed to origin \u2014 confirm it exists on GitHub and differs from the base branch.${target}${head}.` : " Often `gh` targeted upstream instead of origin. Branch was pushed \u2014 retry in the latest Sideboard, or run: gh pr create -R <owner/name> --base main --head <branch>.";
876
914
  return `Could not create the pull request.${hint}`;
877
915
  }
916
+ if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
917
+ const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
918
+ return `GitHub rejected the pull request: the GraphQL body is too long (PR description / request size, limit ${GITHUB_PR_BODY_MAX_CHARS} characters).${pushNote} Retry with a short title and body via \`gh pr create --body-file\` (or send_to_thread so the worktree agent writes a brief description). Do not paste a changelog or diff into --body.`;
919
+ }
878
920
  if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
879
921
  const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
880
922
  const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
@@ -906,88 +948,29 @@ function formatIpcInvokeError(err) {
906
948
 
907
949
  // src/git/git-auth-mode.ts
908
950
  import { isAbsolute } from "path";
909
-
910
- // src/git/github-agent-auth.ts
911
- import { chmodSync, existsSync, mkdirSync, writeFileSync } from "fs";
912
- import { homedir } from "os";
913
- import { dirname, join } from "path";
914
- function githubAgentAuthDir() {
915
- const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
916
- if (override) return override;
917
- return join(homedir(), ".sideboard-git-auth");
918
- }
919
- function githubCredentialStorePath() {
920
- return join(githubAgentAuthDir(), "git-credentials");
921
- }
922
- function githubGhConfigDir() {
923
- return join(githubAgentAuthDir(), "gh");
924
- }
925
- function writePrivateFile(file, body) {
926
- mkdirSync(dirname(file), { recursive: true, mode: 448 });
927
- try {
928
- chmodSync(dirname(file), 448);
929
- } catch {
930
- }
931
- writeFileSync(file, body, { encoding: "utf8", mode: 384 });
932
- try {
933
- chmodSync(file, 384);
934
- } catch {
935
- }
936
- }
937
- function gitCredentialStoreContents(token) {
938
- return `https://x-access-token:${encodeURIComponent(token)}@github.com
939
- `;
940
- }
941
- function ghHostsYml(token, user = "x-access-token") {
942
- const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
943
- return [
944
- "github.com:",
945
- " git_protocol: https",
946
- ` user: ${u}`,
947
- ` oauth_token: ${token}`,
948
- " users:",
949
- ` ${u}:`,
950
- ` oauth_token: ${token}`,
951
- ""
952
- ].join("\n");
953
- }
954
- function materializeGithubAgentAuth(token, user) {
955
- const trimmed = token.trim();
956
- if (!trimmed) return;
957
- const root = githubAgentAuthDir();
958
- mkdirSync(root, { recursive: true, mode: 448 });
959
- try {
960
- chmodSync(root, 448);
961
- } catch {
962
- }
963
- writePrivateFile(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
964
- const ghDir = githubGhConfigDir();
965
- mkdirSync(ghDir, { recursive: true, mode: 448 });
966
- writePrivateFile(join(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
967
- writePrivateFile(join(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
968
- }
969
- function githubAgentAuthReady() {
970
- return existsSync(githubCredentialStorePath()) && existsSync(join(githubGhConfigDir(), "hosts.yml"));
971
- }
972
- function githubCredentialHelperGitConfig() {
973
- const file = githubCredentialStorePath();
974
- return [
975
- { key: "credential.helper", value: "" },
976
- { key: "credential.helper", value: `store --file=${file}` }
977
- ];
978
- }
979
- function githubGhConfigEnv() {
980
- return {
981
- GH_CONFIG_DIR: githubGhConfigDir(),
982
- GH_PROMPT_DISABLED: "1"
983
- };
984
- }
985
-
986
- // src/git/git-auth-mode.ts
987
951
  var HTTPS_REWRITE = [
988
952
  { key: "url.https://github.com/.insteadOf", value: "git@github.com:" },
989
953
  { key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
990
954
  ];
955
+ function githubHttpsInsteadOfEntries(remoteUrl) {
956
+ const entries = [...HTTPS_REWRITE];
957
+ const url = remoteUrl?.trim() ?? "";
958
+ const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
959
+ if (scpAlias?.[1]) {
960
+ entries.push({
961
+ key: "url.https://github.com/.insteadOf",
962
+ value: `${scpAlias[1]}:`
963
+ });
964
+ }
965
+ const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
966
+ if (sshAlias?.[1]) {
967
+ entries.push({
968
+ key: "url.https://github.com/.insteadOf",
969
+ value: `ssh://git@${sshAlias[1]}/`
970
+ });
971
+ }
972
+ return entries;
973
+ }
991
974
  var TOKEN_TTL_MS = 12 * 60 * 60 * 1e3;
992
975
  var tokenMemo = null;
993
976
  var GITHUB_CHILD_TOKEN_KEYS = [
@@ -1017,16 +1000,19 @@ function appendIndexedGitConfig(existing, entries) {
1017
1000
  out.GIT_CONFIG_COUNT = String(count + entries.length);
1018
1001
  return out;
1019
1002
  }
1020
- function githubAgentGitEnv(existing) {
1003
+ function githubAgentGitEnv(existing, opts) {
1021
1004
  const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
1022
- return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
1005
+ return appendIndexedGitConfig(existing, [
1006
+ ...githubHttpsInsteadOfEntries(opts?.remoteUrl),
1007
+ ...helpers
1008
+ ]);
1023
1009
  }
1024
1010
  function applyGithubGitAuthEnv(existing, opts) {
1025
1011
  const out = { ...nonInteractiveGitProcessEnv() };
1026
1012
  const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
1027
1013
  if (token) materializeGithubAgentAuth(token);
1028
1014
  Object.assign(out, githubGhConfigEnv());
1029
- if (opts.mode === "ssh") return out;
1015
+ if (opts.mode === "ssh" && !token) return out;
1030
1016
  Object.assign(out, githubAgentGitEnv(existing));
1031
1017
  return out;
1032
1018
  }
@@ -1142,8 +1128,9 @@ function formatGitAuthModeDirective(mode) {
1142
1128
  case "ssh":
1143
1129
  return [
1144
1130
  "Git authentication (Settings \u2192 Git mode: SSH):",
1145
- "- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
1146
- "- SSH is batch-mode: it will not prompt for a Keychain password. If push fails with `Permission denied (publickey)`, tell the user to unlock ssh-agent or switch Settings \u2192 Git to Auto / gh CLI \u2014 do not rewrite remotes yourself.",
1131
+ "- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
1132
+ "- This process may push over HTTPS via `gh` (process-only `insteadOf`) so ask_git / unattended turns work when ssh-agent is missing \u2014 that does not change the stored remote.",
1133
+ "- SSH is batch-mode: it will not prompt for a Keychain password. If both SSH and HTTPS fail, tell the user to unlock ssh-agent or run `gh auth login` (or switch Settings \u2192 Git to Auto).",
1147
1134
  "- `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.",
1148
1135
  "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
1149
1136
  ].join("\n");
@@ -2265,6 +2252,16 @@ function originFetchBranch(sourceRef) {
2265
2252
  if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
2266
2253
  return ref;
2267
2254
  }
2255
+ async function originRemoteUrl(cwd) {
2256
+ const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
2257
+ return result.exitCode === 0 ? result.stdout.trim() : "";
2258
+ }
2259
+ function githubHttpsRetryEnv(remoteUrl) {
2260
+ return {
2261
+ GIT_TERMINAL_PROMPT: "0",
2262
+ ...githubAgentGitEnv(void 0, { remoteUrl })
2263
+ };
2264
+ }
2268
2265
  async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
2269
2266
  const first = await git(args, repoPath, { reject: false, timeoutMs });
2270
2267
  if (first.exitCode === 0) return true;
@@ -2274,15 +2271,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
2274
2271
  } catch {
2275
2272
  return false;
2276
2273
  }
2277
- if (mode === "ssh") return false;
2278
2274
  const token = await resolveGithubAgentToken(mode, repoPath);
2279
2275
  if (!token) return false;
2276
+ const remoteUrl = await originRemoteUrl(repoPath);
2280
2277
  const tryHttps = async (header) => git(args, repoPath, {
2281
2278
  reject: false,
2282
2279
  timeoutMs,
2283
- env: { GIT_TERMINAL_PROMPT: "0" },
2280
+ env: githubHttpsRetryEnv(remoteUrl),
2284
2281
  config: {
2285
- "url.https://github.com/.insteadOf": "git@github.com:",
2286
2282
  "http.extraHeader": header
2287
2283
  }
2288
2284
  });
@@ -2364,8 +2360,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
2364
2360
  }
2365
2361
  async function createThreadWorktree(opts) {
2366
2362
  let branchName = `thread/${opts.slug}`;
2367
- const worktreePath = join2(worktreesRoot(opts.repoPath), opts.slug);
2368
- if (existsSync2(worktreePath)) {
2363
+ const worktreePath = join(worktreesRoot(opts.repoPath), opts.slug);
2364
+ if (existsSync(worktreePath)) {
2369
2365
  throw new Error(`Worktree already exists at ${worktreePath}`);
2370
2366
  }
2371
2367
  await ensureGhPreferOrigin(opts.repoPath);
@@ -2400,13 +2396,14 @@ ${add.stdout}`;
2400
2396
  });
2401
2397
  branchName = added;
2402
2398
  await ensureGhPreferOrigin(worktreePath);
2399
+ await ensureWorktreeSideboardIgnored(worktreePath);
2403
2400
  return { branchName, worktreePath };
2404
2401
  }
2405
2402
  async function createExistingBranchWorktree(opts) {
2406
2403
  const branchName = opts.branchName.trim();
2407
2404
  if (!branchName) throw new Error("branch name required");
2408
- const worktreePath = join2(worktreesRoot(opts.repoPath), opts.slug);
2409
- if (existsSync2(worktreePath)) {
2405
+ const worktreePath = join(worktreesRoot(opts.repoPath), opts.slug);
2406
+ if (existsSync(worktreePath)) {
2410
2407
  throw new Error(`Worktree already exists at ${worktreePath}`);
2411
2408
  }
2412
2409
  await ensureGhPreferOrigin(opts.repoPath);
@@ -2444,6 +2441,7 @@ async function createExistingBranchWorktree(opts) {
2444
2441
  await git(["checkout", "-B", branchName], worktreePath, { reject: false });
2445
2442
  }
2446
2443
  await ensureGhPreferOrigin(worktreePath);
2444
+ await ensureWorktreeSideboardIgnored(worktreePath);
2447
2445
  return { branchName, worktreePath };
2448
2446
  }
2449
2447
  async function removeWorktree(repoPath, worktreePath, opts) {
@@ -2532,7 +2530,9 @@ async function currentBranch(worktreePath) {
2532
2530
  async function commitAll(worktreePath, message) {
2533
2531
  const dirty = await isDirty(worktreePath);
2534
2532
  if (!dirty) return false;
2533
+ await ensureWorktreeSideboardIgnored(worktreePath);
2535
2534
  await git(["add", "-A"], worktreePath);
2535
+ await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
2536
2536
  await git(["commit", "-m", message], worktreePath);
2537
2537
  return true;
2538
2538
  }
@@ -2546,14 +2546,14 @@ async function pushBranch(worktreePath, branchName) {
2546
2546
  const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
2547
2547
  if (!slug || !token) {
2548
2548
  throw new Error(
2549
- sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
2549
+ sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
2550
2550
  );
2551
2551
  }
2552
+ const remoteUrl = await originRemoteUrl(worktreePath);
2552
2553
  const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
2553
2554
  reject: false,
2554
- env: { GIT_TERMINAL_PROMPT: "0" },
2555
+ env: githubHttpsRetryEnv(remoteUrl),
2555
2556
  config: {
2556
- "url.https://github.com/.insteadOf": "git@github.com:",
2557
2557
  "http.extraHeader": header
2558
2558
  }
2559
2559
  });
@@ -2683,6 +2683,32 @@ async function createOrUpdatePr(worktreePath, opts) {
2683
2683
  const repoArgs = ghRepoSelectArgs(slug);
2684
2684
  const headRef = ghHeadRef(slug, opts.head);
2685
2685
  const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
2686
+ const bodyText = clampGithubPrBody(opts.body ?? opts.title);
2687
+ const bodyFile = join(
2688
+ tmpdir(),
2689
+ `sideboard-pr-body-${process.pid}-${randomBytes(6).toString("hex")}.md`
2690
+ );
2691
+ writeFileSync(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
2692
+ `, "utf8");
2693
+ const bodyArgs = ["--body-file", bodyFile];
2694
+ try {
2695
+ return await createOrUpdatePrWithBodyFile(worktreePath, {
2696
+ ...opts,
2697
+ slug,
2698
+ repoArgs,
2699
+ headRef,
2700
+ branchOnly,
2701
+ bodyArgs
2702
+ });
2703
+ } finally {
2704
+ try {
2705
+ unlinkSync(bodyFile);
2706
+ } catch {
2707
+ }
2708
+ }
2709
+ }
2710
+ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
2711
+ const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
2686
2712
  const existing = await gh(
2687
2713
  [...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
2688
2714
  worktreePath,
@@ -2698,8 +2724,7 @@ async function createOrUpdatePr(worktreePath, opts) {
2698
2724
  branchOnly,
2699
2725
  "--title",
2700
2726
  opts.title,
2701
- "--body",
2702
- opts.body ?? opts.title
2727
+ ...bodyArgs
2703
2728
  ],
2704
2729
  worktreePath,
2705
2730
  { reject: false }
@@ -2714,8 +2739,7 @@ async function createOrUpdatePr(worktreePath, opts) {
2714
2739
  "--web",
2715
2740
  "--title",
2716
2741
  opts.title,
2717
- "--body",
2718
- opts.body ?? opts.title,
2742
+ ...bodyArgs,
2719
2743
  "--base",
2720
2744
  opts.base,
2721
2745
  "--head",
@@ -2736,8 +2760,7 @@ async function createOrUpdatePr(worktreePath, opts) {
2736
2760
  "create",
2737
2761
  "--title",
2738
2762
  opts.title,
2739
- "--body",
2740
- opts.body ?? opts.title,
2763
+ ...bodyArgs,
2741
2764
  "--base",
2742
2765
  opts.base,
2743
2766
  "--head",
@@ -2761,8 +2784,8 @@ function sameRepoPath(a, b) {
2761
2784
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
2762
2785
  }
2763
2786
  function listLocalThreadBranchSlugs(repoPath) {
2764
- const refsDir = join2(repoPath, ".git", "refs", "heads", "thread");
2765
- if (!existsSync2(refsDir)) return [];
2787
+ const refsDir = join(repoPath, ".git", "refs", "heads", "thread");
2788
+ if (!existsSync(refsDir)) return [];
2766
2789
  try {
2767
2790
  return readdirSync(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
2768
2791
  } catch {
@@ -2772,7 +2795,7 @@ function listLocalThreadBranchSlugs(repoPath) {
2772
2795
  function collectTakenTeamSlugs(repoPath) {
2773
2796
  const taken = /* @__PURE__ */ new Set();
2774
2797
  const root = worktreesRoot(repoPath);
2775
- if (existsSync2(root)) {
2798
+ if (existsSync(root)) {
2776
2799
  for (const entry of readdirSync(root, { withFileTypes: true })) {
2777
2800
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
2778
2801
  taken.add(normalizeTakenSlug(entry.name));
@@ -2794,8 +2817,8 @@ function allocateTeamSlug(repoPath) {
2794
2817
  const taken = collectTakenTeamSlugs(repoPath);
2795
2818
  for (let attempt = 0; attempt < 32; attempt++) {
2796
2819
  const team = allocateTeamName(taken);
2797
- const path = join2(worktreesRoot(repoPath), team.slug);
2798
- if (!existsSync2(path)) return team;
2820
+ const path = join(worktreesRoot(repoPath), team.slug);
2821
+ if (!existsSync(path)) return team;
2799
2822
  taken.add(team.slug);
2800
2823
  }
2801
2824
  throw new Error("No available soccer team worktree directories left");
@@ -2814,13 +2837,18 @@ export {
2814
2837
  threadDisplayLabel,
2815
2838
  worktreeDisplayLabel,
2816
2839
  worktreeDisplayLabelForGroup,
2840
+ GITHUB_PR_BODY_MAX_CHARS,
2841
+ GITHUB_PR_BODY_SAFE_CHARS,
2817
2842
  isGhRateLimitError,
2843
+ isGhPrBodyTooLongError,
2844
+ clampGithubPrBody,
2818
2845
  formatRateLimitResetHint,
2819
2846
  extractGhErrorDetail,
2820
2847
  formatGhLandError,
2821
2848
  isPrNotMergeableError,
2822
2849
  formatMergePrError,
2823
2850
  formatIpcInvokeError,
2851
+ githubHttpsInsteadOfEntries,
2824
2852
  nonInteractiveGitProcessEnv,
2825
2853
  appendIndexedGitConfig,
2826
2854
  githubAgentGitEnv,
@@ -9,10 +9,10 @@ import {
9
9
  ensureConnectedBrightsyTeamTokens,
10
10
  getConnectedBrightsyTeamsRaw,
11
11
  listConnectedBrightsyTeams
12
- } from "./chunk-ED4UPEJX.js";
12
+ } from "./chunk-G7SIQFBQ.js";
13
13
  import "./chunk-S42XV45P.js";
14
14
  import "./chunk-6GN5WPYZ.js";
15
- import "./chunk-KPIYENTF.js";
15
+ import "./chunk-FNQNJOHY.js";
16
16
  import "./chunk-BD2ICC4D.js";
17
17
  export {
18
18
  applyConnectedTeamToCli,
@@ -7,11 +7,11 @@ import {
7
7
  ensureConnectedBrightsyTeamTokens,
8
8
  getConnectedBrightsyTeamsRaw,
9
9
  listConnectedBrightsyTeams
10
- } from "./chunk-KBWND62T.js";
10
+ } from "./chunk-7F4XE6UG.js";
11
11
  import "./chunk-M267JPEA.js";
12
12
  import "./chunk-ELBYOGVA.js";
13
13
  import "./chunk-QZQEXME2.js";
14
- import "./chunk-DVM4ID64.js";
14
+ import "./chunk-UFHNSFAS.js";
15
15
  export {
16
16
  applyConnectedTeamToCli,
17
17
  brightsyMcpServerName,
@@ -7,16 +7,17 @@ import {
7
7
  enrichWorkspacesWithGithub,
8
8
  ensureGlobalCoordinatorCwd,
9
9
  formatWorkspaceInventory
10
- } from "./chunk-EGDRPA4B.js";
11
- import "./chunk-YP3CSOZ6.js";
12
- import "./chunk-FKOIHGKV.js";
13
- import "./chunk-I77RYPOH.js";
10
+ } from "./chunk-NOTANBYC.js";
11
+ import "./chunk-ZGFYFVJF.js";
12
+ import "./chunk-WHU7YGWP.js";
13
+ import "./chunk-4XNSGDXE.js";
14
14
  import "./chunk-4TR3HZFT.js";
15
15
  import "./chunk-JT7R45JB.js";
16
16
  import "./chunk-TUGKX5BD.js";
17
17
  import "./chunk-77WWLBCI.js";
18
18
  import "./chunk-QZQEXME2.js";
19
- import "./chunk-DVM4ID64.js";
19
+ import "./chunk-Y4NAPW5I.js";
20
+ import "./chunk-UFHNSFAS.js";
20
21
  export {
21
22
  COORDINATOR_TOOL_PLAYBOOK,
22
23
  SLACK_REPLY_FORMATTING,
@@ -9,12 +9,13 @@ import {
9
9
  enrichWorkspacesWithGithub,
10
10
  ensureGlobalCoordinatorCwd,
11
11
  formatWorkspaceInventory
12
- } from "./chunk-ZVYLEF72.js";
13
- import "./chunk-JTPDWTWJ.js";
14
- import "./chunk-B3SJXYIJ.js";
12
+ } from "./chunk-DMRIZR6M.js";
13
+ import "./chunk-Z2PVJKMN.js";
14
+ import "./chunk-Y7YBWWIG.js";
15
15
  import "./chunk-EUXOHTUK.js";
16
- import "./chunk-KPIYENTF.js";
17
- import "./chunk-BGQBELGJ.js";
16
+ import "./chunk-VSFGPWCQ.js";
17
+ import "./chunk-FNQNJOHY.js";
18
+ import "./chunk-CZD4NRDZ.js";
18
19
  import "./chunk-NSTQ6QKD.js";
19
20
  import "./chunk-KGZBYWZ3.js";
20
21
  import "./chunk-BD2ICC4D.js";
@@ -17,13 +17,14 @@ import {
17
17
  orchestratorSessionPoisonedByBuiltins,
18
18
  slackCoordinatorSourceRef,
19
19
  takenTeamSlugsForOrchestration
20
- } from "./chunk-N3VNOFXQ.js";
21
- import "./chunk-ZVYLEF72.js";
22
- import "./chunk-JTPDWTWJ.js";
23
- import "./chunk-B3SJXYIJ.js";
20
+ } from "./chunk-VO4SPEBS.js";
21
+ import "./chunk-DMRIZR6M.js";
22
+ import "./chunk-Z2PVJKMN.js";
23
+ import "./chunk-Y7YBWWIG.js";
24
24
  import "./chunk-EUXOHTUK.js";
25
- import "./chunk-KPIYENTF.js";
26
- import "./chunk-BGQBELGJ.js";
25
+ import "./chunk-VSFGPWCQ.js";
26
+ import "./chunk-FNQNJOHY.js";
27
+ import "./chunk-CZD4NRDZ.js";
27
28
  import "./chunk-NSTQ6QKD.js";
28
29
  import "./chunk-KGZBYWZ3.js";
29
30
  import {
@@ -15,11 +15,11 @@ import {
15
15
  orchestratorSessionPoisonedByBuiltins,
16
16
  slackCoordinatorSourceRef,
17
17
  takenTeamSlugsForOrchestration
18
- } from "./chunk-R4JP32P5.js";
19
- import "./chunk-EGDRPA4B.js";
20
- import "./chunk-YP3CSOZ6.js";
21
- import "./chunk-FKOIHGKV.js";
22
- import "./chunk-I77RYPOH.js";
18
+ } from "./chunk-AF6O55PJ.js";
19
+ import "./chunk-NOTANBYC.js";
20
+ import "./chunk-ZGFYFVJF.js";
21
+ import "./chunk-WHU7YGWP.js";
22
+ import "./chunk-4XNSGDXE.js";
23
23
  import "./chunk-4TR3HZFT.js";
24
24
  import "./chunk-JT7R45JB.js";
25
25
  import "./chunk-TUGKX5BD.js";
@@ -27,7 +27,8 @@ import "./chunk-77WWLBCI.js";
27
27
  import {
28
28
  globalAgentCwd
29
29
  } from "./chunk-QZQEXME2.js";
30
- import "./chunk-DVM4ID64.js";
30
+ import "./chunk-Y4NAPW5I.js";
31
+ import "./chunk-UFHNSFAS.js";
31
32
  export {
32
33
  GLOBAL_WORKSPACE_ID,
33
34
  createGlobalChat,