@sideboard-ai/core 0.1.77 → 0.1.79

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 (31) hide show
  1. package/dist/{agents-XJV6J3K2.js → agents-EWPHOM6Y.js} +6 -6
  2. package/dist/{agents-LKUHPPEQ.js → agents-GRAPUXWW.js} +5 -5
  3. package/dist/{app-settings-3TLA2EJ7.js → app-settings-6IOQYGBK.js} +7 -1
  4. package/dist/{app-settings-P42Z3VOB.js → app-settings-NILNWNNQ.js} +7 -1
  5. package/dist/{chunk-VERLUKN2.js → chunk-5LXWTU3J.js} +6 -6
  6. package/dist/{chunk-2ZIPJRJE.js → chunk-5VTWBI3I.js} +2 -2
  7. package/dist/{chunk-GWTLKXXP.js → chunk-6T2SKGCS.js} +3 -3
  8. package/dist/{chunk-OE7YBB5X.js → chunk-FUUVPN4A.js} +108 -3
  9. package/dist/{chunk-EEKSZTMU.js → chunk-HCGEFU3J.js} +5 -5
  10. package/dist/{chunk-XJNCWYFR.js → chunk-HSLQXL6M.js} +3 -3
  11. package/dist/{chunk-W7YOTDVO.js → chunk-IFPN6TER.js} +47 -2
  12. package/dist/{chunk-2FJI5JXX.js → chunk-P33ZQ7ZC.js} +3 -3
  13. package/dist/{chunk-75U65MBE.js → chunk-PW5YHHP3.js} +2 -2
  14. package/dist/{chunk-QD37IILI.js → chunk-SHCR6RPU.js} +3 -3
  15. package/dist/{chunk-PTJJIQK7.js → chunk-XKNBSYA7.js} +47 -2
  16. package/dist/{chunk-MF2YMEGD.js → chunk-YVVXWWCC.js} +110 -3
  17. package/dist/{coordinator-prompt-LLFJUO2R.js → coordinator-prompt-2OVON2LQ.js} +4 -4
  18. package/dist/{coordinator-prompt-MRCMMRSF.js → coordinator-prompt-K2R34A5T.js} +3 -3
  19. package/dist/{global-workspace-TWHMYLTZ.js → global-workspace-RI367AM6.js} +4 -4
  20. package/dist/{global-workspace-YNMNO4CL.js → global-workspace-VG44RZUH.js} +5 -5
  21. package/dist/index.cjs +500 -178
  22. package/dist/index.d.cts +83 -8
  23. package/dist/index.d.ts +83 -8
  24. package/dist/index.js +344 -179
  25. package/dist/mcp/run-stdio.cjs +2439 -2228
  26. package/dist/mcp/run-stdio.js +156 -100
  27. package/dist/{workspaces-GQ4XKBD3.js → workspaces-BQWQEZWE.js} +5 -5
  28. package/dist/{workspaces-O3U5BENH.js → workspaces-TYPJNUSM.js} +6 -6
  29. package/dist/{worktree-VOCH3WS3.js → worktree-5VLLFI5W.js} +5 -1
  30. package/dist/{worktree-KWXHMKRN.js → worktree-UNSOCYZU.js} +5 -1
  31. package/package.json +1 -1
@@ -16,14 +16,14 @@ import {
16
16
  resolveQuotaFallbackAgent,
17
17
  sideboardMcpProfile,
18
18
  summarizeTurnStderr
19
- } from "../chunk-2FJI5JXX.js";
19
+ } from "../chunk-P33ZQ7ZC.js";
20
20
  import "../chunk-VROPG6QF.js";
21
21
  import {
22
22
  addWorkspace,
23
23
  ensureWorkspace,
24
24
  removeWorkspace,
25
25
  syncWorkspacesFromThreads
26
- } from "../chunk-2ZIPJRJE.js";
26
+ } from "../chunk-5VTWBI3I.js";
27
27
  import {
28
28
  extractPresentedPlan,
29
29
  readPlanFile,
@@ -41,14 +41,14 @@ import {
41
41
  isGlobalThread,
42
42
  isOrchestratorThread,
43
43
  orchestratorSessionPoisonedByBuiltins
44
- } from "../chunk-GWTLKXXP.js";
44
+ } from "../chunk-6T2SKGCS.js";
45
45
  import {
46
46
  SLACK_REPLY_FORMATTING,
47
47
  coordinatorSystemPrompt,
48
48
  coordinatorTurnReminder,
49
49
  enrichWorkspacesWithGithub,
50
50
  ensureGlobalCoordinatorCwd
51
- } from "../chunk-XJNCWYFR.js";
51
+ } from "../chunk-HSLQXL6M.js";
52
52
  import {
53
53
  addPrStackLayer,
54
54
  allocateTeamName,
@@ -57,9 +57,11 @@ import {
57
57
  createExistingBranchWorktree,
58
58
  createOrUpdatePr,
59
59
  createThreadWorktree,
60
+ currentBranch,
60
61
  detectGhStack,
61
62
  fetchPrHead,
62
63
  formatGhLandError,
64
+ formatGitAuthModeDirective,
63
65
  getPr,
64
66
  getPrChecks,
65
67
  getPrDetails,
@@ -85,7 +87,7 @@ import {
85
87
  takenSlugsFromThread,
86
88
  threadDisplayLabel,
87
89
  worktreeNameFromPath
88
- } from "../chunk-OE7YBB5X.js";
90
+ } from "../chunk-FUUVPN4A.js";
89
91
  import {
90
92
  ATTACHMENTS_DIR,
91
93
  LEGACY_ATTACHMENTS_DIR,
@@ -125,7 +127,7 @@ import {
125
127
  saveLinearOAuth,
126
128
  updateAdvancedSettings,
127
129
  writeSecureJson
128
- } from "../chunk-PTJJIQK7.js";
130
+ } from "../chunk-XKNBSYA7.js";
129
131
  import {
130
132
  writePrivateFile
131
133
  } from "../chunk-NSTQ6QKD.js";
@@ -916,9 +918,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
916
918
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
917
919
  );
918
920
  }
919
- const { isGlobalThread: isGlobalThread2 } = await import("../global-workspace-TWHMYLTZ.js");
921
+ const { isGlobalThread: isGlobalThread2 } = await import("../global-workspace-RI367AM6.js");
920
922
  if (isGlobalThread2(thread)) {
921
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("../coordinator-prompt-MRCMMRSF.js");
923
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("../coordinator-prompt-K2R34A5T.js");
922
924
  ensureGlobalCoordinatorCwd2(
923
925
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
924
926
  );
@@ -935,8 +937,13 @@ async function spawnAgentTurn(thread, input, onEvent) {
935
937
  }
936
938
  const env = childEnvWithAppSettings(cmd.env);
937
939
  if (!isOrchestratorThread(thread)) {
938
- const originEnv = await originGhRepoEnv(thread.worktreePath).catch(() => ({}));
939
- Object.assign(env, originEnv);
940
+ try {
941
+ const originEnv = await originGhRepoEnv(thread.worktreePath, { env });
942
+ Object.assign(env, originEnv);
943
+ } catch (err) {
944
+ const detail = err instanceof Error ? err.message : String(err);
945
+ console.warn(`[sideboard] originGhRepoEnv failed (${thread.worktreePath}): ${detail}`);
946
+ }
940
947
  }
941
948
  const child = execa(cmd.file, cmd.args, {
942
949
  cwd: cmd.cwd,
@@ -1020,6 +1027,80 @@ async function spawnAgentTurn(thread, input, onEvent) {
1020
1027
  };
1021
1028
  }
1022
1029
 
1030
+ // src/land/pr-metadata.ts
1031
+ var GENERIC_TITLE_RE = /^(sideboard:|thread\/|wip\b|tmp\b|update\b|changes?\b|misc\b|stuff\b)/i;
1032
+ function looksGeneric(title) {
1033
+ const t = title.trim();
1034
+ if (!t) return true;
1035
+ if (t.length < 4) return true;
1036
+ if (GENERIC_TITLE_RE.test(t)) return true;
1037
+ if (!/[\s:/\-_]/.test(t) && t.length <= 24) return true;
1038
+ return false;
1039
+ }
1040
+ function truncateTitle(title, max = 72) {
1041
+ const t = title.trim().replace(/\s+/g, " ");
1042
+ if (t.length <= max) return t;
1043
+ return `${t.slice(0, max - 1).trimEnd()}\u2026`;
1044
+ }
1045
+ function titleFromPaths(paths) {
1046
+ if (paths.length === 0) return null;
1047
+ const top = paths.slice(0, 3).map((p) => p.replace(/\/$/, ""));
1048
+ if (paths.length === 1) return truncateTitle(`Update ${top[0]}`);
1049
+ if (paths.length <= 3) return truncateTitle(`Update ${top.join(", ")}`);
1050
+ return truncateTitle(`Update ${top[0]} and ${paths.length - 1} more files`);
1051
+ }
1052
+ async function suggestPrMetadata(worktreePath, opts) {
1053
+ const [{ stdout: logOut }, { stdout: nameStatus }, { stdout: statOut }] = await Promise.all([
1054
+ git(["log", "--format=%s", `${opts.base}..HEAD`], worktreePath, {
1055
+ reject: false
1056
+ }),
1057
+ git(["diff", "--name-only", `${opts.base}...HEAD`], worktreePath, {
1058
+ reject: false
1059
+ }),
1060
+ git(["diff", "--stat", `${opts.base}...HEAD`], worktreePath, {
1061
+ reject: false
1062
+ })
1063
+ ]);
1064
+ const { stdout: dirtyNames } = await git(["diff", "--name-only", "HEAD"], worktreePath, {
1065
+ reject: false
1066
+ });
1067
+ const { stdout: untracked } = await git(
1068
+ ["ls-files", "--others", "--exclude-standard"],
1069
+ worktreePath,
1070
+ { reject: false }
1071
+ );
1072
+ const subjects = logOut.split("\n").map((s) => s.trim()).filter(Boolean);
1073
+ const paths = [
1074
+ ...new Set(
1075
+ [...nameStatus.split("\n"), ...dirtyNames.split("\n"), ...untracked.split("\n")].map((p) => p.trim()).filter(Boolean)
1076
+ )
1077
+ ].sort((a, b) => a.localeCompare(b));
1078
+ const meaningfulSubjects = subjects.filter((s) => !looksGeneric(s));
1079
+ const fallback = opts.fallbackTitle?.trim() || null;
1080
+ const fallbackOk = fallback && !looksGeneric(fallback) ? fallback : null;
1081
+ const title = truncateTitle(
1082
+ meaningfulSubjects[0] ?? fallbackOk ?? titleFromPaths(paths) ?? "Sideboard changes"
1083
+ );
1084
+ const commitMessage = meaningfulSubjects[0] ?? fallbackOk ?? titleFromPaths(paths) ?? `sideboard: ${title}`;
1085
+ const summaryLines = meaningfulSubjects.length > 0 ? meaningfulSubjects.slice(0, 12).map((s) => `- ${s}`) : paths.slice(0, 20).map((p) => `- \`${p}\``);
1086
+ const bodyParts = [
1087
+ "## Summary",
1088
+ summaryLines.length > 0 ? summaryLines.join("\n") : "- Changes landed via Sideboard.",
1089
+ ""
1090
+ ];
1091
+ if (statOut.trim()) {
1092
+ bodyParts.push("## Diff", "```", statOut.trim(), "```", "");
1093
+ }
1094
+ if (opts.sourceLabel) {
1095
+ bodyParts.push(`_Landed via Sideboard from ${opts.sourceLabel}_`);
1096
+ }
1097
+ return {
1098
+ title,
1099
+ body: bodyParts.join("\n").trim() + "\n",
1100
+ commitMessage: truncateTitle(commitMessage, 72)
1101
+ };
1102
+ }
1103
+
1023
1104
  // src/git/agent-git-actions.ts
1024
1105
  var AGENT_GIT_ACTIONS = [
1025
1106
  "commit-push",
@@ -1154,8 +1235,20 @@ async function captureLoginEnv() {
1154
1235
  cachedLoginEnv = { ...process.env };
1155
1236
  return { ...cachedLoginEnv };
1156
1237
  }
1238
+ var NESTED_ELECTRON_ENV_PREFIXES = ["ELECTRON_", "CHROME_"];
1239
+ function stripNestedElectronEnv(env) {
1240
+ const out = { ...env };
1241
+ for (const key of Object.keys(out)) {
1242
+ if (NESTED_ELECTRON_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))) {
1243
+ delete out[key];
1244
+ }
1245
+ }
1246
+ return out;
1247
+ }
1157
1248
  function buildWorkspaceScriptEnv(opts, baseEnv) {
1158
- const env = { ...baseEnv ?? process.env };
1249
+ const env = stripNestedElectronEnv({
1250
+ ...baseEnv ?? process.env
1251
+ });
1159
1252
  const name = opts.workspaceName ?? basename(opts.worktreePath);
1160
1253
  const ports = opts.ports ?? [];
1161
1254
  const primary = ports[0];
@@ -1759,7 +1852,7 @@ async function createThread(input, _onSetupLine) {
1759
1852
  return readThread(thread.id) ?? thread;
1760
1853
  }
1761
1854
  async function listLinearIssues(agent, repoPath) {
1762
- const { getAdapter: getAdapter2 } = await import("../agents-LKUHPPEQ.js");
1855
+ const { getAdapter: getAdapter2 } = await import("../agents-GRAPUXWW.js");
1763
1856
  await requireAgent(agent, { requireLinear: true });
1764
1857
  const adapter = getAdapter2(agent);
1765
1858
  if (!adapter.listLinearIssues) {
@@ -2623,7 +2716,7 @@ async function adoptThread(input) {
2623
2716
  messages: input.messages ?? []
2624
2717
  });
2625
2718
  writeThread(thread);
2626
- const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-GQ4XKBD3.js");
2719
+ const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-BQWQEZWE.js");
2627
2720
  await ensureWorkspace2(repoPath);
2628
2721
  return thread;
2629
2722
  }
@@ -3842,80 +3935,6 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
3842
3935
  };
3843
3936
  }
3844
3937
 
3845
- // src/land/pr-metadata.ts
3846
- var GENERIC_TITLE_RE = /^(sideboard:|thread\/|wip\b|tmp\b|update\b|changes?\b|misc\b|stuff\b)/i;
3847
- function looksGeneric(title) {
3848
- const t = title.trim();
3849
- if (!t) return true;
3850
- if (t.length < 4) return true;
3851
- if (GENERIC_TITLE_RE.test(t)) return true;
3852
- if (!/[\s:/\-_]/.test(t) && t.length <= 24) return true;
3853
- return false;
3854
- }
3855
- function truncateTitle(title, max = 72) {
3856
- const t = title.trim().replace(/\s+/g, " ");
3857
- if (t.length <= max) return t;
3858
- return `${t.slice(0, max - 1).trimEnd()}\u2026`;
3859
- }
3860
- function titleFromPaths(paths) {
3861
- if (paths.length === 0) return null;
3862
- const top = paths.slice(0, 3).map((p) => p.replace(/\/$/, ""));
3863
- if (paths.length === 1) return truncateTitle(`Update ${top[0]}`);
3864
- if (paths.length <= 3) return truncateTitle(`Update ${top.join(", ")}`);
3865
- return truncateTitle(`Update ${top[0]} and ${paths.length - 1} more files`);
3866
- }
3867
- async function suggestPrMetadata(worktreePath, opts) {
3868
- const [{ stdout: logOut }, { stdout: nameStatus }, { stdout: statOut }] = await Promise.all([
3869
- git(["log", "--format=%s", `${opts.base}..HEAD`], worktreePath, {
3870
- reject: false
3871
- }),
3872
- git(["diff", "--name-only", `${opts.base}...HEAD`], worktreePath, {
3873
- reject: false
3874
- }),
3875
- git(["diff", "--stat", `${opts.base}...HEAD`], worktreePath, {
3876
- reject: false
3877
- })
3878
- ]);
3879
- const { stdout: dirtyNames } = await git(["diff", "--name-only", "HEAD"], worktreePath, {
3880
- reject: false
3881
- });
3882
- const { stdout: untracked } = await git(
3883
- ["ls-files", "--others", "--exclude-standard"],
3884
- worktreePath,
3885
- { reject: false }
3886
- );
3887
- const subjects = logOut.split("\n").map((s) => s.trim()).filter(Boolean);
3888
- const paths = [
3889
- ...new Set(
3890
- [...nameStatus.split("\n"), ...dirtyNames.split("\n"), ...untracked.split("\n")].map((p) => p.trim()).filter(Boolean)
3891
- )
3892
- ].sort((a, b) => a.localeCompare(b));
3893
- const meaningfulSubjects = subjects.filter((s) => !looksGeneric(s));
3894
- const fallback = opts.fallbackTitle?.trim() || null;
3895
- const fallbackOk = fallback && !looksGeneric(fallback) ? fallback : null;
3896
- const title = truncateTitle(
3897
- meaningfulSubjects[0] ?? fallbackOk ?? titleFromPaths(paths) ?? "Sideboard changes"
3898
- );
3899
- const commitMessage = meaningfulSubjects[0] ?? fallbackOk ?? titleFromPaths(paths) ?? `sideboard: ${title}`;
3900
- const summaryLines = meaningfulSubjects.length > 0 ? meaningfulSubjects.slice(0, 12).map((s) => `- ${s}`) : paths.slice(0, 20).map((p) => `- \`${p}\``);
3901
- const bodyParts = [
3902
- "## Summary",
3903
- summaryLines.length > 0 ? summaryLines.join("\n") : "- Changes landed via Sideboard.",
3904
- ""
3905
- ];
3906
- if (statOut.trim()) {
3907
- bodyParts.push("## Diff", "```", statOut.trim(), "```", "");
3908
- }
3909
- if (opts.sourceLabel) {
3910
- bodyParts.push(`_Landed via Sideboard from ${opts.sourceLabel}_`);
3911
- }
3912
- return {
3913
- title,
3914
- body: bodyParts.join("\n").trim() + "\n",
3915
- commitMessage: truncateTitle(commitMessage, 72)
3916
- };
3917
- }
3918
-
3919
3938
  // src/land/land.ts
3920
3939
  async function previewLand(thread) {
3921
3940
  if (thread.sourceIsFork) {
@@ -4459,6 +4478,8 @@ function formatWorktreeDirective(thread, opts) {
4459
4478
  lines.push(
4460
4479
  "- Push with `git push -u origin HEAD` (or the current branch name). Do not `git push upstream`."
4461
4480
  );
4481
+ lines.push("");
4482
+ lines.push(formatGitAuthModeDirective(opts?.gitAuthMode ?? "auto"));
4462
4483
  lines.push(
4463
4484
  "- Derive the PR title and body from what the changes actually do and why \u2014 inspect the diff/commits and the user request. Do not use the soccer-team worktree nickname or placeholder branch as the PR title."
4464
4485
  );
@@ -4663,7 +4684,7 @@ var Orchestrator = class {
4663
4684
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
4664
4685
  });
4665
4686
  }
4666
- const { autoCleanupOrphansEnabled } = await import("../app-settings-P42Z3VOB.js");
4687
+ const { autoCleanupOrphansEnabled } = await import("../app-settings-NILNWNNQ.js");
4667
4688
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
4668
4689
  await cleanupOrphanWorktrees({ repoPaths });
4669
4690
  }
@@ -4820,7 +4841,7 @@ var Orchestrator = class {
4820
4841
  }
4821
4842
  async finishCreateThread(threadId, prompt) {
4822
4843
  await this.runSetupAfterCreate(threadId);
4823
- const { autoRunAfterSetupEnabled } = await import("../app-settings-P42Z3VOB.js");
4844
+ const { autoRunAfterSetupEnabled } = await import("../app-settings-NILNWNNQ.js");
4824
4845
  if (autoRunAfterSetupEnabled()) {
4825
4846
  try {
4826
4847
  await this.startDev(threadId);
@@ -5098,14 +5119,16 @@ var Orchestrator = class {
5098
5119
  }
5099
5120
  const isBrightsy = fresh.agent === "brightsy";
5100
5121
  const isOrchestration = isOrchestratorThread(fresh);
5122
+ const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("../app-settings-NILNWNNQ.js");
5123
+ const gitAuthMode = getGithubGitAuthMode();
5101
5124
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
5102
5125
  githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
5103
5126
  () => null
5104
- )
5127
+ ),
5128
+ gitAuthMode
5105
5129
  });
5106
5130
  const artifactDirective = isBrightsy ? null : formatArtifactDirective();
5107
5131
  const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
5108
- const { autoRenameBranchEnabled } = await import("../app-settings-P42Z3VOB.js");
5109
5132
  const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled() ? formatRenameBranchDirective(fresh, {
5110
5133
  customPrompt: settings?.prompts?.renameBranch
5111
5134
  }) : null;
@@ -5811,7 +5834,7 @@ var Orchestrator = class {
5811
5834
  updateThread(thread.id, { title: meta.title });
5812
5835
  }
5813
5836
  }
5814
- const { autoArchiveOnMergeEnabled } = await import("../app-settings-P42Z3VOB.js");
5837
+ const { autoArchiveOnMergeEnabled } = await import("../app-settings-NILNWNNQ.js");
5815
5838
  const latest = this.requireThread(thread.id);
5816
5839
  if (!shouldAutoArchiveOnPrMerge({
5817
5840
  previousPrState: prevState || null,
@@ -5942,8 +5965,9 @@ var Orchestrator = class {
5942
5965
  return tab;
5943
5966
  }
5944
5967
  /**
5945
- * Queue a desktop-git-button prompt on a worktree agent (commit/push/PR/merge).
5946
- * Orchestrators use this instead of running git/gh from the synthetic home.
5968
+ * Desktop git buttons + MCP `ask_git`.
5969
+ * When the worktree is clean, push / open the PR here (HTTPS via `gh` if SSH
5970
+ * is missing). When dirty, queue the worktree agent to commit first.
5947
5971
  */
5948
5972
  async askGit(threadRef, action) {
5949
5973
  if (!AGENT_GIT_ACTIONS.includes(action)) {
@@ -5961,6 +5985,10 @@ var Orchestrator = class {
5961
5985
  "No pull request linked. Ask the worktree agent to open a draft PR first (ask_git create-draft)."
5962
5986
  );
5963
5987
  }
5988
+ if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
5989
+ await this.pushAndMaybeOpenPr(thread, action);
5990
+ return this.requireThread(threadRef);
5991
+ }
5964
5992
  let prBase;
5965
5993
  if (action === "resolve-conflicts") {
5966
5994
  try {
@@ -5971,6 +5999,34 @@ var Orchestrator = class {
5971
5999
  }
5972
6000
  return this.send(threadRef, agentGitPrompt(action, { prBase }));
5973
6001
  }
6002
+ /** Push origin (gh HTTPS fallback) and create/update the PR when requested. */
6003
+ async pushAndMaybeOpenPr(thread, action) {
6004
+ const cwd = thread.worktreePath;
6005
+ const branch = await currentBranch(cwd);
6006
+ await pushBranch(cwd, branch);
6007
+ if (action === "commit-push") return;
6008
+ const base = await resolveDefaultBranch(thread.repoPath);
6009
+ const meta = await suggestPrMetadata(cwd, {
6010
+ base,
6011
+ fallbackTitle: thread.prTitle ?? thread.title
6012
+ });
6013
+ const url = await createOrUpdatePr(cwd, {
6014
+ title: meta.title,
6015
+ body: meta.body,
6016
+ base,
6017
+ head: branch,
6018
+ draft: action === "create-draft",
6019
+ web: action === "create-web"
6020
+ });
6021
+ if (!url) return;
6022
+ const patch = { prUrl: url, prTitle: meta.title };
6023
+ try {
6024
+ const fetched = await getPrMeta(cwd, url);
6025
+ if (fetched?.title) patch.prTitle = fetched.title;
6026
+ } catch {
6027
+ }
6028
+ updateThread(thread.id, patch);
6029
+ }
5974
6030
  setThreadOptions(threadRef, patch) {
5975
6031
  const thread = this.requireThread(threadRef);
5976
6032
  const next = {};
@@ -6066,7 +6122,7 @@ var Orchestrator = class {
6066
6122
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
6067
6123
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
6068
6124
  try {
6069
- const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-GQ4XKBD3.js");
6125
+ const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-BQWQEZWE.js");
6070
6126
  await ensureWorkspace2(thread.repoPath);
6071
6127
  } catch {
6072
6128
  }
@@ -6088,7 +6144,7 @@ var Orchestrator = class {
6088
6144
  await runArchiveScript(thread.repoPath, thread.worktreePath);
6089
6145
  } catch {
6090
6146
  }
6091
- const { deleteBranchOnPurgeEnabled } = await import("../app-settings-P42Z3VOB.js");
6147
+ const { deleteBranchOnPurgeEnabled } = await import("../app-settings-NILNWNNQ.js");
6092
6148
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
6093
6149
  await removeWorktree(thread.repoPath, thread.worktreePath, {
6094
6150
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -6109,7 +6165,7 @@ var Orchestrator = class {
6109
6165
  return restored2;
6110
6166
  }
6111
6167
  if (!existsSync15(thread.worktreePath)) {
6112
- const { createThreadWorktree: createThreadWorktree2 } = await import("../worktree-KWXHMKRN.js");
6168
+ const { createThreadWorktree: createThreadWorktree2 } = await import("../worktree-UNSOCYZU.js");
6113
6169
  const { execa: execa6 } = await import("execa");
6114
6170
  const slug = thread.worktreePath.split("/").pop();
6115
6171
  const dest = thread.worktreePath;
@@ -7280,7 +7336,7 @@ function withTimeout(promise, ms, label) {
7280
7336
  async function startMcpServer() {
7281
7337
  const orch = getOrchestrator();
7282
7338
  try {
7283
- const { maxConcurrentAgents } = await import("../app-settings-P42Z3VOB.js");
7339
+ const { maxConcurrentAgents } = await import("../app-settings-NILNWNNQ.js");
7284
7340
  orch.setMaxConcurrent(maxConcurrentAgents());
7285
7341
  } catch {
7286
7342
  }
@@ -7490,7 +7546,7 @@ async function startMcpServer() {
7490
7546
  registerLinearTools(server);
7491
7547
  if (sideboardMcpProfile() !== "worktree") {
7492
7548
  const { getCaffeinateHold, setCaffeinateHold } = await import("../caffeinate-hold-OHAUWOA6.js");
7493
- const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults } = await import("../app-settings-P42Z3VOB.js");
7549
+ const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults } = await import("../app-settings-NILNWNNQ.js");
7494
7550
  const accountDefaults = resolveThreadDefaults();
7495
7551
  const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
7496
7552
  server.tool(
@@ -7852,7 +7908,7 @@ async function startMcpServer() {
7852
7908
  );
7853
7909
  server.tool(
7854
7910
  "ask_git",
7855
- "Tell a worktree agent to commit & push, open a draft PR, resolve conflicts, or merge the linked PR \u2014 same short prompts as the desktop git buttons. The worktree agent runs git/gh (`gh pr merge`); this only queues the prompt. Pass a worktree thread ref (not the orchestrator). Then wait_for_turn / get_turn_result. Do not run git or gh from the orchestration cwd.",
7911
+ "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` if SSH is missing). When dirty, queues the worktree agent to commit; then wait_for_turn. Pass a worktree thread ref (not the orchestrator). Do not run git or gh from the orchestration cwd.",
7856
7912
  {
7857
7913
  ref: z3.string().describe("Worktree thread id/ref"),
7858
7914
  action: z3.enum(AGENT_GIT_ACTIONS).describe(
@@ -6,14 +6,14 @@ import {
6
6
  listWorkspaces,
7
7
  removeWorkspace,
8
8
  syncWorkspacesFromThreads
9
- } from "./chunk-2ZIPJRJE.js";
10
- import "./chunk-GWTLKXXP.js";
11
- import "./chunk-XJNCWYFR.js";
12
- import "./chunk-OE7YBB5X.js";
9
+ } from "./chunk-5VTWBI3I.js";
10
+ import "./chunk-6T2SKGCS.js";
11
+ import "./chunk-HSLQXL6M.js";
12
+ import "./chunk-FUUVPN4A.js";
13
13
  import "./chunk-B3SJXYIJ.js";
14
14
  import "./chunk-7FD7COKE.js";
15
15
  import "./chunk-AE5VBOFE.js";
16
- import "./chunk-PTJJIQK7.js";
16
+ import "./chunk-XKNBSYA7.js";
17
17
  import "./chunk-NSTQ6QKD.js";
18
18
  import "./chunk-KGZBYWZ3.js";
19
19
  import "./chunk-7MV3RXSC.js";
@@ -4,13 +4,13 @@ import {
4
4
  listWorkspaces,
5
5
  removeWorkspace,
6
6
  syncWorkspacesFromThreads
7
- } from "./chunk-75U65MBE.js";
8
- import "./chunk-VERLUKN2.js";
9
- import "./chunk-EEKSZTMU.js";
10
- import "./chunk-W7YOTDVO.js";
11
- import "./chunk-JT7R45JB.js";
12
- import "./chunk-MF2YMEGD.js";
7
+ } from "./chunk-PW5YHHP3.js";
8
+ import "./chunk-5LXWTU3J.js";
9
+ import "./chunk-HCGEFU3J.js";
10
+ import "./chunk-YVVXWWCC.js";
13
11
  import "./chunk-FKOIHGKV.js";
12
+ import "./chunk-IFPN6TER.js";
13
+ import "./chunk-JT7R45JB.js";
14
14
  import "./chunk-FWJYLBO6.js";
15
15
  import "./chunk-77WWLBCI.js";
16
16
  import "./chunk-M37RITA6.js";
@@ -18,6 +18,7 @@ import {
18
18
  getPrMeta,
19
19
  ghHeadRef,
20
20
  ghRepoSelectArgs,
21
+ githubAgentGitEnv,
21
22
  isDirty,
22
23
  isPlaceholderBranch,
23
24
  isSideboardScratchPath,
@@ -43,8 +44,10 @@ import {
43
44
  worktreeDisplayLabel,
44
45
  worktreeDisplayLabelForGroup,
45
46
  worktreeNameFromPath
46
- } from "./chunk-MF2YMEGD.js";
47
+ } from "./chunk-YVVXWWCC.js";
47
48
  import "./chunk-FKOIHGKV.js";
49
+ import "./chunk-IFPN6TER.js";
50
+ import "./chunk-JT7R45JB.js";
48
51
  import "./chunk-FWJYLBO6.js";
49
52
  import "./chunk-77WWLBCI.js";
50
53
  import "./chunk-M37RITA6.js";
@@ -69,6 +72,7 @@ export {
69
72
  getPrMeta,
70
73
  ghHeadRef,
71
74
  ghRepoSelectArgs,
75
+ githubAgentGitEnv,
72
76
  isDirty,
73
77
  isPlaceholderBranch,
74
78
  isSideboardScratchPath,
@@ -20,6 +20,7 @@ import {
20
20
  getPrMeta,
21
21
  ghHeadRef,
22
22
  ghRepoSelectArgs,
23
+ githubAgentGitEnv,
23
24
  isDirty,
24
25
  isPlaceholderBranch,
25
26
  isSideboardScratchPath,
@@ -45,10 +46,12 @@ import {
45
46
  worktreeDisplayLabel,
46
47
  worktreeDisplayLabelForGroup,
47
48
  worktreeNameFromPath
48
- } from "./chunk-OE7YBB5X.js";
49
+ } from "./chunk-FUUVPN4A.js";
49
50
  import "./chunk-B3SJXYIJ.js";
50
51
  import "./chunk-7FD7COKE.js";
51
52
  import "./chunk-AE5VBOFE.js";
53
+ import "./chunk-XKNBSYA7.js";
54
+ import "./chunk-NSTQ6QKD.js";
52
55
  import "./chunk-KGZBYWZ3.js";
53
56
  import "./chunk-7MV3RXSC.js";
54
57
  export {
@@ -71,6 +74,7 @@ export {
71
74
  getPrMeta,
72
75
  ghHeadRef,
73
76
  ghRepoSelectArgs,
77
+ githubAgentGitEnv,
74
78
  isDirty,
75
79
  isPlaceholderBranch,
76
80
  isSideboardScratchPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideboard-ai/core",
3
- "version": "0.1.77",
3
+ "version": "0.1.79",
4
4
  "description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",