@sideboard-ai/core 0.1.77 → 0.1.81

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-LKUHPPEQ.js → agents-EBKJ55PN.js} +5 -5
  2. package/dist/{agents-XJV6J3K2.js → agents-UQ7D6U6L.js} +6 -6
  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-2FJI5JXX.js → chunk-4AVU4QXO.js} +54 -20
  6. package/dist/{chunk-XJNCWYFR.js → chunk-4HJK57XU.js} +8 -14
  7. package/dist/{chunk-VERLUKN2.js → chunk-6F2TQFJE.js} +6 -6
  8. package/dist/{chunk-EEKSZTMU.js → chunk-CQBQWX73.js} +10 -16
  9. package/dist/{chunk-OE7YBB5X.js → chunk-FUUVPN4A.js} +108 -3
  10. package/dist/{chunk-W7YOTDVO.js → chunk-IFPN6TER.js} +47 -2
  11. package/dist/{chunk-75U65MBE.js → chunk-K553XK7M.js} +2 -2
  12. package/dist/{chunk-GWTLKXXP.js → chunk-P5VDPGAN.js} +3 -3
  13. package/dist/{chunk-2ZIPJRJE.js → chunk-TDJ43HUD.js} +2 -2
  14. package/dist/{chunk-PTJJIQK7.js → chunk-XKNBSYA7.js} +47 -2
  15. package/dist/{chunk-QD37IILI.js → chunk-XNECBC6T.js} +66 -20
  16. package/dist/{chunk-MF2YMEGD.js → chunk-YVVXWWCC.js} +110 -3
  17. package/dist/{coordinator-prompt-LLFJUO2R.js → coordinator-prompt-JQF72JKX.js} +4 -4
  18. package/dist/{coordinator-prompt-MRCMMRSF.js → coordinator-prompt-NYNEFKIV.js} +3 -3
  19. package/dist/{global-workspace-YNMNO4CL.js → global-workspace-DZM4ZFGU.js} +5 -5
  20. package/dist/{global-workspace-TWHMYLTZ.js → global-workspace-NUMUJRWG.js} +4 -4
  21. package/dist/index.cjs +585 -251
  22. package/dist/index.d.cts +97 -8
  23. package/dist/index.d.ts +97 -8
  24. package/dist/index.js +363 -222
  25. package/dist/mcp/run-stdio.cjs +2502 -2286
  26. package/dist/mcp/run-stdio.js +162 -133
  27. package/dist/{workspaces-O3U5BENH.js → workspaces-QLRCOXAY.js} +6 -6
  28. package/dist/{workspaces-GQ4XKBD3.js → workspaces-SUU2GO3A.js} +5 -5
  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
@@ -32,16 +32,16 @@ import {
32
32
  resolveCursorModelId,
33
33
  resolveLoginCommand,
34
34
  resolveQuotaFallbackAgent
35
- } from "./chunk-2FJI5JXX.js";
35
+ } from "./chunk-4AVU4QXO.js";
36
36
  import "./chunk-VROPG6QF.js";
37
37
  import {
38
38
  ORCHESTRATOR_AGENT_KINDS,
39
39
  assertOrchestratorCapableAgent,
40
40
  coerceOrchestratorAgent,
41
41
  isOrchestratorCapableAgent
42
- } from "./chunk-GWTLKXXP.js";
43
- import "./chunk-XJNCWYFR.js";
44
- import "./chunk-OE7YBB5X.js";
42
+ } from "./chunk-P5VDPGAN.js";
43
+ import "./chunk-4HJK57XU.js";
44
+ import "./chunk-FUUVPN4A.js";
45
45
  import "./chunk-B3SJXYIJ.js";
46
46
  import "./chunk-7FD7COKE.js";
47
47
  import {
@@ -53,7 +53,7 @@ import {
53
53
  resolveCommandBinarySync,
54
54
  withExportedPath
55
55
  } from "./chunk-AE5VBOFE.js";
56
- import "./chunk-PTJJIQK7.js";
56
+ import "./chunk-XKNBSYA7.js";
57
57
  import "./chunk-NSTQ6QKD.js";
58
58
  import "./chunk-KGZBYWZ3.js";
59
59
  import "./chunk-7MV3RXSC.js";
@@ -28,23 +28,23 @@ import {
28
28
  resolveCursorModelId,
29
29
  resolveLoginCommand,
30
30
  resolveQuotaFallbackAgent
31
- } from "./chunk-QD37IILI.js";
31
+ } from "./chunk-XNECBC6T.js";
32
32
  import {
33
33
  ORCHESTRATOR_AGENT_KINDS,
34
34
  assertOrchestratorCapableAgent,
35
35
  coerceOrchestratorAgent,
36
36
  isOrchestratorCapableAgent
37
- } from "./chunk-VERLUKN2.js";
38
- import "./chunk-EEKSZTMU.js";
37
+ } from "./chunk-6F2TQFJE.js";
38
+ import "./chunk-CQBQWX73.js";
39
39
  import "./chunk-BTL7EMGT.js";
40
40
  import {
41
41
  cursorSdkMessageToEvents,
42
42
  parseCursorRunnerLine
43
43
  } from "./chunk-SEOICVGB.js";
44
- import "./chunk-W7YOTDVO.js";
45
- import "./chunk-JT7R45JB.js";
46
- import "./chunk-MF2YMEGD.js";
44
+ import "./chunk-YVVXWWCC.js";
47
45
  import "./chunk-FKOIHGKV.js";
46
+ import "./chunk-IFPN6TER.js";
47
+ import "./chunk-JT7R45JB.js";
48
48
  import "./chunk-FWJYLBO6.js";
49
49
  import "./chunk-77WWLBCI.js";
50
50
  import "./chunk-M37RITA6.js";
@@ -1,4 +1,5 @@
1
1
  import {
2
+ GITHUB_GIT_AUTH_MODES,
2
3
  HARNESS_ENV_KEYS,
3
4
  appSettingsPath,
4
5
  applyAppEnvironment,
@@ -22,6 +23,8 @@ import {
22
23
  getDefaultEffort,
23
24
  getDefaultFast,
24
25
  getDefaultModel,
26
+ getGithubGitAuthMode,
27
+ getGithubPat,
25
28
  getIssueSource,
26
29
  getLinearApiKey,
27
30
  harnessEnvKey,
@@ -49,11 +52,12 @@ import {
49
52
  updateDefaultsSettings,
50
53
  updateIntegrationsSettings,
51
54
  updateOpencodeSettings
52
- } from "./chunk-W7YOTDVO.js";
55
+ } from "./chunk-IFPN6TER.js";
53
56
  import "./chunk-JT7R45JB.js";
54
57
  import "./chunk-77WWLBCI.js";
55
58
  import "./chunk-M37RITA6.js";
56
59
  export {
60
+ GITHUB_GIT_AUTH_MODES,
57
61
  HARNESS_ENV_KEYS,
58
62
  appSettingsPath,
59
63
  applyAppEnvironment,
@@ -77,6 +81,8 @@ export {
77
81
  getDefaultEffort,
78
82
  getDefaultFast,
79
83
  getDefaultModel,
84
+ getGithubGitAuthMode,
85
+ getGithubPat,
80
86
  getIssueSource,
81
87
  getLinearApiKey,
82
88
  harnessEnvKey,
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import {
4
+ GITHUB_GIT_AUTH_MODES,
4
5
  HARNESS_ENV_KEYS,
5
6
  appSettingsPath,
6
7
  applyAppEnvironment,
@@ -24,6 +25,8 @@ import {
24
25
  getDefaultEffort,
25
26
  getDefaultFast,
26
27
  getDefaultModel,
28
+ getGithubGitAuthMode,
29
+ getGithubPat,
27
30
  getIssueSource,
28
31
  getLinearApiKey,
29
32
  harnessEnvKey,
@@ -51,11 +54,12 @@ import {
51
54
  updateDefaultsSettings,
52
55
  updateIntegrationsSettings,
53
56
  updateOpencodeSettings
54
- } from "./chunk-PTJJIQK7.js";
57
+ } from "./chunk-XKNBSYA7.js";
55
58
  import "./chunk-NSTQ6QKD.js";
56
59
  import "./chunk-KGZBYWZ3.js";
57
60
  import "./chunk-7MV3RXSC.js";
58
61
  export {
62
+ GITHUB_GIT_AUTH_MODES,
59
63
  HARNESS_ENV_KEYS,
60
64
  appSettingsPath,
61
65
  applyAppEnvironment,
@@ -79,6 +83,8 @@ export {
79
83
  getDefaultEffort,
80
84
  getDefaultFast,
81
85
  getDefaultModel,
86
+ getGithubGitAuthMode,
87
+ getGithubPat,
82
88
  getIssueSource,
83
89
  getLinearApiKey,
84
90
  harnessEnvKey,
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-VROPG6QF.js";
10
10
  import {
11
11
  isOrchestratorThread
12
- } from "./chunk-GWTLKXXP.js";
12
+ } from "./chunk-P5VDPGAN.js";
13
13
  import {
14
14
  enrichPathWithNpmGlobalBin,
15
15
  isConductorBundledCli,
@@ -22,7 +22,7 @@ import {
22
22
  loadAppSettings,
23
23
  resolveAgentExecutable,
24
24
  resolveClaudeExecutable
25
- } from "./chunk-PTJJIQK7.js";
25
+ } from "./chunk-XKNBSYA7.js";
26
26
  import {
27
27
  appDataDir
28
28
  } from "./chunk-7MV3RXSC.js";
@@ -30,6 +30,46 @@ import {
30
30
  // src/agents/brightsy.ts
31
31
  import { existsSync } from "fs";
32
32
 
33
+ // src/agents/usage.ts
34
+ function sumOptional(a, b) {
35
+ if (a == null && b == null) return void 0;
36
+ return (a ?? 0) + (b ?? 0);
37
+ }
38
+ function fromInclusiveInputUsage(opts) {
39
+ const totalInput = Number(opts.inputTokens) || 0;
40
+ const outputTokens = Number(opts.outputTokens) || 0;
41
+ const cached = Number(opts.cachedInputTokens) || 0;
42
+ if (!totalInput && !outputTokens) return null;
43
+ const cacheReadTokens = cached > 0 ? Math.min(cached, totalInput) : 0;
44
+ return {
45
+ inputTokens: Math.max(0, totalInput - cacheReadTokens),
46
+ outputTokens,
47
+ cacheReadTokens: cacheReadTokens || void 0
48
+ };
49
+ }
50
+ function requestOccupancy(u) {
51
+ return u.inputTokens + (u.cacheReadTokens ?? 0) + (u.cacheWriteTokens ?? 0);
52
+ }
53
+ function mergeUsage(a, b) {
54
+ return {
55
+ inputTokens: (a?.inputTokens ?? 0) + b.inputTokens,
56
+ outputTokens: (a?.outputTokens ?? 0) + b.outputTokens,
57
+ cacheReadTokens: sumOptional(a?.cacheReadTokens, b.cacheReadTokens),
58
+ cacheWriteTokens: sumOptional(a?.cacheWriteTokens, b.cacheWriteTokens),
59
+ lastRequestTokens: b.lastRequestTokens ?? a?.lastRequestTokens
60
+ };
61
+ }
62
+ function applyTurnUsage(current, incoming, scope = "request") {
63
+ if (scope === "turn") {
64
+ return {
65
+ ...incoming,
66
+ lastRequestTokens: current?.lastRequestTokens ?? requestOccupancy(incoming)
67
+ };
68
+ }
69
+ const merged = mergeUsage(current, incoming);
70
+ return { ...merged, lastRequestTokens: requestOccupancy(incoming) };
71
+ }
72
+
33
73
  // src/agents/brightsy-targets.ts
34
74
  function encodeBrightsyTarget(type, id, accountId) {
35
75
  if (accountId) return `team:${accountId}:${type}:${id}`;
@@ -205,15 +245,11 @@ ${prompt}`;
205
245
  // src/agents/brightsy.ts
206
246
  function usageFromBrightsy(usage) {
207
247
  if (!usage) return null;
208
- const inputTokens = Number(usage.prompt_tokens ?? 0);
209
- const outputTokens = Number(usage.completion_tokens ?? 0);
210
- if (!inputTokens && !outputTokens) return null;
211
- const cached = Number(usage.prompt_tokens_details?.cached_tokens ?? 0);
212
- return {
213
- inputTokens,
214
- outputTokens,
215
- cacheReadTokens: cached || void 0
216
- };
248
+ return fromInclusiveInputUsage({
249
+ inputTokens: Number(usage.prompt_tokens ?? 0),
250
+ outputTokens: Number(usage.completion_tokens ?? 0),
251
+ cachedInputTokens: Number(usage.prompt_tokens_details?.cached_tokens ?? 0)
252
+ });
217
253
  }
218
254
  function parseBrightsyCliLine(line) {
219
255
  const trimmed = line.trim();
@@ -1009,7 +1045,7 @@ var claudeAdapter = {
1009
1045
  );
1010
1046
  }
1011
1047
  const mode = permissionMode(thread);
1012
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-TWHMYLTZ.js");
1048
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-NUMUJRWG.js");
1013
1049
  const isOrchestrator = isOrchestratorThread2(thread);
1014
1050
  const injectedServers = await buildInjectedMcpServers({
1015
1051
  includeSideboard: true,
@@ -1260,14 +1296,11 @@ async function listCodexModels() {
1260
1296
  }
1261
1297
  function usageFromCodex(usage) {
1262
1298
  if (!usage) return null;
1263
- const inputTokens = Number(usage.input_tokens ?? 0);
1264
- const outputTokens = Number(usage.output_tokens ?? 0) + Number(usage.reasoning_output_tokens ?? 0);
1265
- if (!inputTokens && !outputTokens) return null;
1266
- return {
1267
- inputTokens,
1268
- outputTokens,
1269
- cacheReadTokens: usage.cached_input_tokens ? Number(usage.cached_input_tokens) : void 0
1270
- };
1299
+ return fromInclusiveInputUsage({
1300
+ inputTokens: Number(usage.input_tokens ?? 0),
1301
+ outputTokens: Number(usage.output_tokens ?? 0),
1302
+ cachedInputTokens: Number(usage.cached_input_tokens ?? 0)
1303
+ });
1271
1304
  }
1272
1305
  function codexConfigHasNetworkAccess() {
1273
1306
  const candidates = [
@@ -2577,6 +2610,7 @@ export {
2577
2610
  fallbackTurnFailDetail,
2578
2611
  humanizeAgentFailDetail,
2579
2612
  formatTurnExitError,
2613
+ applyTurnUsage,
2580
2614
  encodeBrightsyTarget,
2581
2615
  decodeBrightsyTarget,
2582
2616
  parseBrightsyCliLine,
@@ -2,10 +2,10 @@
2
2
 
3
3
  import {
4
4
  resolveGithubRepoSlug
5
- } from "./chunk-OE7YBB5X.js";
5
+ } from "./chunk-FUUVPN4A.js";
6
6
  import {
7
7
  resolveThreadDefaults
8
- } from "./chunk-PTJJIQK7.js";
8
+ } from "./chunk-XKNBSYA7.js";
9
9
  import {
10
10
  globalAgentCwd,
11
11
  sideboardReposDir
@@ -70,7 +70,8 @@ var COORDINATOR_TOOL_PLAYBOOK = [
70
70
  "Inspect / review / PRs:",
71
71
  "- get_diff \u2014 compact diff summary",
72
72
  '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review changes in this workspace."); then wait_for_turn / get_turn_result on the returned id',
73
- "- ask_git \u2014 tell a worktree agent to commit & push, open a draft PR, resolve conflicts, or merge (`Merge PR.`). You only queue that prompt \u2014 the worktree agent runs git/gh (including `gh pr merge`). Then wait_for_turn. Prefer this over paraphrasing.",
73
+ "- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn. Prefer this over paraphrasing.",
74
+ '- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
74
75
  '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Fix merge conflicts.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
75
76
  "Human-only (do not attempt): ready-for-review land (confirm_land), purge_thread.",
76
77
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
@@ -101,7 +102,7 @@ function coordinatorTurnReminder(opts) {
101
102
  goal ? `- Goal / title: ${goal}` : null,
102
103
  accountDefaultsPlaybookLine(),
103
104
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
104
- "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn. Land with ask_git (commit-push / create-draft / merge) on the child, then wait_for_turn \u2014 never git/gh from this cwd.",
105
+ "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn. Commit/push/draft PR with ask_git on the child, then wait_for_turn \u2014 never git/gh from this cwd. Call ask_git merge only if the user explicitly asked to merge.",
105
106
  "- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft.",
106
107
  "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
107
108
  "- If they will wait on Slack or leave the Mac, call set_caffeinate enabled=true. When they say they are done / wrapping up / going to sleep, call set_caffeinate enabled=false. Closing this chat also turns it off."
@@ -155,9 +156,9 @@ function ensureGlobalCoordinatorCwd(opts) {
155
156
  orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
156
157
  "Omit `agent` / `model` on `create_thread` unless you have a reason to override Account defaults.",
157
158
  "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent (Account default) or use cursor/claude.",
158
- "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft \u2192 wait_for_turn \u2192 (when ready) ask_git merge \u2192 wait_for_turn.",
159
+ "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
159
160
  "Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 ask_git create-draft.",
160
- "Always ask worktree agents to commit, push, open draft PRs, and merge (`ask_git` / `send_to_thread`). The worktree agent runs git/gh; never merge from this orchestration cwd."
161
+ "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."
161
162
  ].join("\n");
162
163
  try {
163
164
  writeFileSync(join(dir, "CLAUDE.md"), `${body}
@@ -170,7 +171,6 @@ function ensureGlobalCoordinatorCwd(opts) {
170
171
  }
171
172
  function coordinatorSystemPrompt(opts) {
172
173
  const audience = opts.audience ?? "cloud";
173
- const reposDir = sideboardReposDir();
174
174
  const intro = audience === "cloud" ? [
175
175
  "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Discord, Teams, or other chat).",
176
176
  "Your reply will be sent back to that cloud agent \u2014 be concise and actionable."
@@ -188,14 +188,8 @@ function coordinatorSystemPrompt(opts) {
188
188
  ...intro,
189
189
  "You operate across ALL registered workspaces below.",
190
190
  "You have no project git home \u2014 this process cwd is synthetic and empty on purpose.",
191
- COORDINATOR_TOOL_PLAYBOOK,
192
- accountDefaultsPlaybookLine(),
193
- coordinatorGreenfieldPlaybook(reposDir),
194
- "When creating threads, pass the correct repoPath for the target workspace.",
191
+ "Follow AGENTS.md / CLAUDE.md in this cwd for the fleet playbook (they are the same document).",
195
192
  `YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit parentThreadId (Sideboard binds it). Never invent a uuid.`,
196
- "Omit agent/model on create_thread unless you need to override Account defaults.",
197
- "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 ask_git create-draft \u2192 wait_for_turn \u2192 (when ready) ask_git merge \u2192 wait_for_turn. Never target upstream. Never git/gh from this orchestration cwd.",
198
- "Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft.",
199
193
  `Goal: ${opts.goal}`,
200
194
  "Registered workspaces:",
201
195
  formatWorkspaceInventory(opts.workspaces)
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  ensureGlobalCoordinatorCwd
3
- } from "./chunk-EEKSZTMU.js";
4
- import {
5
- resolveNewThreadOptions,
6
- resolveThreadDefaults
7
- } from "./chunk-W7YOTDVO.js";
3
+ } from "./chunk-CQBQWX73.js";
8
4
  import {
9
5
  allocateTeamName,
10
6
  takenSlugsFromThread,
11
7
  teamSlugFromName
12
- } from "./chunk-MF2YMEGD.js";
8
+ } from "./chunk-YVVXWWCC.js";
9
+ import {
10
+ resolveNewThreadOptions,
11
+ resolveThreadDefaults
12
+ } from "./chunk-IFPN6TER.js";
13
13
  import {
14
14
  createEmptyThread,
15
15
  listThreads,
@@ -1,9 +1,9 @@
1
- import {
2
- resolveThreadDefaults
3
- } from "./chunk-W7YOTDVO.js";
4
1
  import {
5
2
  resolveGithubRepoSlug
6
- } from "./chunk-MF2YMEGD.js";
3
+ } from "./chunk-YVVXWWCC.js";
4
+ import {
5
+ resolveThreadDefaults
6
+ } from "./chunk-IFPN6TER.js";
7
7
  import {
8
8
  globalAgentCwd,
9
9
  sideboardReposDir
@@ -68,7 +68,8 @@ var COORDINATOR_TOOL_PLAYBOOK = [
68
68
  "Inspect / review / PRs:",
69
69
  "- get_diff \u2014 compact diff summary",
70
70
  '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review changes in this workspace."); then wait_for_turn / get_turn_result on the returned id',
71
- "- ask_git \u2014 tell a worktree agent to commit & push, open a draft PR, resolve conflicts, or merge (`Merge PR.`). You only queue that prompt \u2014 the worktree agent runs git/gh (including `gh pr merge`). Then wait_for_turn. Prefer this over paraphrasing.",
71
+ "- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn. Prefer this over paraphrasing.",
72
+ '- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
72
73
  '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Fix merge conflicts.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
73
74
  "Human-only (do not attempt): ready-for-review land (confirm_land), purge_thread.",
74
75
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
@@ -99,7 +100,7 @@ function coordinatorTurnReminder(opts) {
99
100
  goal ? `- Goal / title: ${goal}` : null,
100
101
  accountDefaultsPlaybookLine(),
101
102
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
102
- "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn. Land with ask_git (commit-push / create-draft / merge) on the child, then wait_for_turn \u2014 never git/gh from this cwd.",
103
+ "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn. Commit/push/draft PR with ask_git on the child, then wait_for_turn \u2014 never git/gh from this cwd. Call ask_git merge only if the user explicitly asked to merge.",
103
104
  "- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft.",
104
105
  "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
105
106
  "- If they will wait on Slack or leave the Mac, call set_caffeinate enabled=true. When they say they are done / wrapping up / going to sleep, call set_caffeinate enabled=false. Closing this chat also turns it off."
@@ -153,9 +154,9 @@ function ensureGlobalCoordinatorCwd(opts) {
153
154
  orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
154
155
  "Omit `agent` / `model` on `create_thread` unless you have a reason to override Account defaults.",
155
156
  "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent (Account default) or use cursor/claude.",
156
- "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft \u2192 wait_for_turn \u2192 (when ready) ask_git merge \u2192 wait_for_turn.",
157
+ "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
157
158
  "Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 ask_git create-draft.",
158
- "Always ask worktree agents to commit, push, open draft PRs, and merge (`ask_git` / `send_to_thread`). The worktree agent runs git/gh; never merge from this orchestration cwd."
159
+ "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."
159
160
  ].join("\n");
160
161
  try {
161
162
  writeFileSync(join(dir, "CLAUDE.md"), `${body}
@@ -168,7 +169,6 @@ function ensureGlobalCoordinatorCwd(opts) {
168
169
  }
169
170
  function coordinatorSystemPrompt(opts) {
170
171
  const audience = opts.audience ?? "cloud";
171
- const reposDir = sideboardReposDir();
172
172
  const intro = audience === "cloud" ? [
173
173
  "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Discord, Teams, or other chat).",
174
174
  "Your reply will be sent back to that cloud agent \u2014 be concise and actionable."
@@ -186,14 +186,8 @@ function coordinatorSystemPrompt(opts) {
186
186
  ...intro,
187
187
  "You operate across ALL registered workspaces below.",
188
188
  "You have no project git home \u2014 this process cwd is synthetic and empty on purpose.",
189
- COORDINATOR_TOOL_PLAYBOOK,
190
- accountDefaultsPlaybookLine(),
191
- coordinatorGreenfieldPlaybook(reposDir),
192
- "When creating threads, pass the correct repoPath for the target workspace.",
189
+ "Follow AGENTS.md / CLAUDE.md in this cwd for the fleet playbook (they are the same document).",
193
190
  `YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit parentThreadId (Sideboard binds it). Never invent a uuid.`,
194
- "Omit agent/model on create_thread unless you need to override Account defaults.",
195
- "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 ask_git create-draft \u2192 wait_for_turn \u2192 (when ready) ask_git merge \u2192 wait_for_turn. Never target upstream. Never git/gh from this orchestration cwd.",
196
- "Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft.",
197
191
  `Goal: ${opts.goal}`,
198
192
  "Registered workspaces:",
199
193
  formatWorkspaceInventory(opts.workspaces)
@@ -11,6 +11,10 @@ import {
11
11
  git,
12
12
  resolveGhAuthToken
13
13
  } from "./chunk-AE5VBOFE.js";
14
+ import {
15
+ getGithubGitAuthMode,
16
+ getGithubPat
17
+ } from "./chunk-XKNBSYA7.js";
14
18
  import {
15
19
  worktreesRoot
16
20
  } from "./chunk-7MV3RXSC.js";
@@ -881,6 +885,74 @@ function formatGhLandError(raw, opts) {
881
885
  return detail || "Failed to create or update pull request";
882
886
  }
883
887
 
888
+ // src/git/git-auth-mode.ts
889
+ var HTTPS_REWRITE = [
890
+ { key: "url.https://github.com/.insteadOf", value: "git@github.com:" },
891
+ { key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" },
892
+ { key: "credential.https://github.com.helper", value: "!gh auth git-credential" }
893
+ ];
894
+ function appendIndexedGitConfig(existing, entries) {
895
+ const start = Number.parseInt(String(existing?.GIT_CONFIG_COUNT ?? "0"), 10);
896
+ const count = Number.isFinite(start) && start > 0 ? start : 0;
897
+ const out = {};
898
+ entries.forEach((entry, i) => {
899
+ const n = count + i;
900
+ out[`GIT_CONFIG_KEY_${n}`] = entry.key;
901
+ out[`GIT_CONFIG_VALUE_${n}`] = entry.value;
902
+ });
903
+ out.GIT_CONFIG_COUNT = String(count + entries.length);
904
+ return out;
905
+ }
906
+ function githubAgentGitEnv(existing) {
907
+ return appendIndexedGitConfig(existing, HTTPS_REWRITE);
908
+ }
909
+ function applyGithubGitAuthEnv(existing, opts) {
910
+ const out = {};
911
+ if (opts.mode === "gh" || opts.mode === "token") {
912
+ Object.assign(out, githubAgentGitEnv(existing));
913
+ }
914
+ if (opts.mode === "token") {
915
+ const token = opts.token?.trim();
916
+ if (token && !existing?.GH_TOKEN?.trim()) {
917
+ out.GH_TOKEN = token;
918
+ }
919
+ }
920
+ return out;
921
+ }
922
+ function formatGitAuthModeDirective(mode) {
923
+ switch (mode) {
924
+ case "gh":
925
+ return [
926
+ "Git authentication (Account \u2192 GitHub mode: gh CLI):",
927
+ "- This process rewrites `git@github.com:` and `ssh://git@github.com/` to HTTPS.",
928
+ "- `gh` supplies credentials (`gh auth git-credential`). Do not switch remotes to SSH.",
929
+ "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
930
+ ].join("\n");
931
+ case "ssh":
932
+ return [
933
+ "Git authentication (Account \u2192 GitHub mode: SSH):",
934
+ "- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
935
+ "- Use this Mac\u2019s SSH agent / keys. If push fails with `Permission denied (publickey)`, tell the user to start ssh-agent or switch Account \u2192 GitHub to Auto / gh CLI \u2014 do not rewrite remotes yourself.",
936
+ "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below (API still uses `gh`)."
937
+ ].join("\n");
938
+ case "token":
939
+ return [
940
+ "Git authentication (Account \u2192 GitHub mode: personal access token):",
941
+ "- This process rewrites GitHub SSH remotes to HTTPS.",
942
+ "- `GH_TOKEN` is set in the environment. Use HTTPS git and `gh`; do not paste the token into commands or chat.",
943
+ "- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
944
+ ].join("\n");
945
+ case "auto":
946
+ default:
947
+ return [
948
+ "Git authentication (Account \u2192 GitHub mode: auto):",
949
+ "- Prefer the existing remote URL (SSH or HTTPS). Do not rewrite remotes unless a push/fetch fails.",
950
+ '- If `git push` fails with `Permission denied (publickey)`, this shell has no ssh-agent. Retry over HTTPS (do not stop): `git -c url.https://github.com/.insteadOf=git@github.com: -c http.extraHeader="AUTHORIZATION: bearer $(gh auth token)" push -u origin HEAD`.',
951
+ "- Then create/update the PR with `gh` as below."
952
+ ].join("\n");
953
+ }
954
+ }
955
+
884
956
  // src/git/pr-gates.ts
885
957
  function prIsInMergeQueue(gate) {
886
958
  if (gate.isInMergeQueue) return true;
@@ -1253,10 +1325,15 @@ ${view.stderr}`;
1253
1325
  timeoutMs: 15e3
1254
1326
  });
1255
1327
  }
1256
- async function originGhRepoEnv(cwd) {
1328
+ async function originGhRepoEnv(cwd, opts) {
1257
1329
  await ensureGhPreferOrigin(cwd);
1258
1330
  const slug = await resolveGithubRepoSlug(cwd);
1259
- return slug ? { GH_REPO: slug } : {};
1331
+ const mode = opts?.mode ?? getGithubGitAuthMode();
1332
+ const token = mode === "token" ? getGithubPat() : null;
1333
+ return {
1334
+ ...applyGithubGitAuthEnv(opts?.env, { mode, token }),
1335
+ ...slug ? { GH_REPO: slug } : {}
1336
+ };
1260
1337
  }
1261
1338
  async function resolveDefaultBranch(repoPath, opts) {
1262
1339
  const viaOrigin = await git(
@@ -2005,7 +2082,33 @@ async function commitAll(worktreePath, message) {
2005
2082
  return true;
2006
2083
  }
2007
2084
  async function pushBranch(worktreePath, branchName) {
2008
- await git(["push", "-u", "origin", branchName], worktreePath);
2085
+ const ssh = await git(["push", "-u", "origin", branchName], worktreePath, {
2086
+ reject: false
2087
+ });
2088
+ if (ssh.exitCode === 0) return;
2089
+ const sshErr = (ssh.stderr || ssh.stdout).trim();
2090
+ const slug = await resolveGithubRepoSlug(worktreePath);
2091
+ const token = await resolveGhAuthToken(worktreePath);
2092
+ if (!slug || !token) {
2093
+ throw new Error(
2094
+ sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
2095
+ );
2096
+ }
2097
+ const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
2098
+ reject: false,
2099
+ env: { GIT_TERMINAL_PROMPT: "0" },
2100
+ config: {
2101
+ "url.https://github.com/.insteadOf": "git@github.com:",
2102
+ "http.extraHeader": header
2103
+ }
2104
+ });
2105
+ const bearer = await tryHttps(`AUTHORIZATION: bearer ${token}`);
2106
+ if (bearer.exitCode === 0) return;
2107
+ const basic = Buffer.from(`x-access-token:${token}`, "utf8").toString("base64");
2108
+ const basicPush = await tryHttps(`Authorization: Basic ${basic}`);
2109
+ if (basicPush.exitCode === 0) return;
2110
+ const httpsErr = (basicPush.stderr || bearer.stderr || bearer.stdout).trim();
2111
+ throw new Error(httpsErr || sshErr || `git push origin ${branchName} failed`);
2009
2112
  }
2010
2113
  async function mergePr(cwd, selector, opts) {
2011
2114
  const slug = await resolveGithubRepoSlug(cwd);
@@ -2214,6 +2317,8 @@ export {
2214
2317
  worktreeDisplayLabel,
2215
2318
  worktreeDisplayLabelForGroup,
2216
2319
  formatGhLandError,
2320
+ githubAgentGitEnv,
2321
+ formatGitAuthModeDirective,
2217
2322
  detectGhStack,
2218
2323
  getPrStack,
2219
2324
  initPrStack,