@sideboard-ai/core 0.1.258 → 0.1.261

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 (66) hide show
  1. package/dist/{abletime-IDQJI2KW.js → abletime-CDGINDXG.js} +6 -5
  2. package/dist/{abletime-OGQR4LIL.js → abletime-OQ4PC52L.js} +7 -6
  3. package/dist/{abletime-oauth-ZQUIY4EM.js → abletime-oauth-5A5EOH2A.js} +5 -4
  4. package/dist/{abletime-oauth-MBAG5MYU.js → abletime-oauth-KX2TDFTE.js} +6 -5
  5. package/dist/{abletime-rest-WEJERY4O.js → abletime-rest-PUGKYTRR.js} +6 -5
  6. package/dist/{abletime-rest-JZIIT5W3.js → abletime-rest-UEHOBLXD.js} +5 -4
  7. package/dist/agents/cursor-runner.cjs +274 -12
  8. package/dist/agents/cursor-runner.js +156 -13
  9. package/dist/{agents-HZP7YEKC.js → agents-IKVUGW5H.js} +12 -9
  10. package/dist/{agents-FSUI5MET.js → agents-J2P4KNEY.js} +21 -18
  11. package/dist/{app-settings-CLARFJUX.js → app-settings-OM7H64YM.js} +12 -3
  12. package/dist/{app-settings-ONYJ36XH.js → app-settings-VQEUCONM.js} +11 -2
  13. package/dist/chunk-3HO2OY5T.js +159 -0
  14. package/dist/{chunk-F7ANS66U.js → chunk-4F7J6UWD.js} +75 -33
  15. package/dist/{chunk-WDDUIGFK.js → chunk-4GK32AYX.js} +1 -1
  16. package/dist/{chunk-ZC3TVLY6.js → chunk-5OKJDCBK.js} +5 -5
  17. package/dist/{chunk-KJM3E3NF.js → chunk-6PFZ6XO7.js} +65 -6
  18. package/dist/{title-4A2ATYNY.js → chunk-7H655NEW.js} +1 -0
  19. package/dist/{chunk-R4DWUBOL.js → chunk-ABPNIYRS.js} +78 -37
  20. package/dist/{chunk-XIEDFRBP.js → chunk-B6XFBNYM.js} +2 -2
  21. package/dist/chunk-CEMNIGQH.js +161 -0
  22. package/dist/{chunk-66LAOKLK.js → chunk-D554YCHG.js} +2 -2
  23. package/dist/{chunk-HCNCZPDL.js → chunk-FSZ7YYFQ.js} +119 -63
  24. package/dist/{chunk-4723RAO3.js → chunk-FWNL62VA.js} +3 -1
  25. package/dist/{chunk-Y7CS2WGJ.js → chunk-GIZQAOHZ.js} +247 -109
  26. package/dist/chunk-HHEKVR6C.js +72 -0
  27. package/dist/{chunk-IFHHPPSL.js → chunk-J6ONZP74.js} +5 -5
  28. package/dist/{chunk-PJK24CN3.js → chunk-JTNY5CK4.js} +10 -10
  29. package/dist/{chunk-CPEIHTG7.js → chunk-KVQX62XI.js} +3 -3
  30. package/dist/{chunk-5F4YFGHL.js → chunk-LDXSAVWO.js} +7 -7
  31. package/dist/{title-4WAKWZRF.js → chunk-LX5R5JOR.js} +1 -0
  32. package/dist/{chunk-D6JWYJ4P.js → chunk-N2WW62LF.js} +1 -0
  33. package/dist/{chunk-RTQOCFIV.js → chunk-S7VDDJ34.js} +3 -3
  34. package/dist/{chunk-RJC2MKXN.js → chunk-TJ673EZT.js} +3 -1
  35. package/dist/{chunk-63YSFXLT.js → chunk-U3AOJLH3.js} +126 -70
  36. package/dist/{chunk-452Y24PW.js → chunk-VIC6TDYT.js} +68 -9
  37. package/dist/{chunk-553IEH7O.js → chunk-W5PWGEKS.js} +241 -104
  38. package/dist/{chunk-VVHHBOIA.js → chunk-WV7KJH2E.js} +5 -3
  39. package/dist/{chunk-BYRZS2S2.js → chunk-X2OTZ36G.js} +4 -4
  40. package/dist/{chunk-FGWUZOZN.js → chunk-YFTO7U2A.js} +3 -3
  41. package/dist/connected-teams-7CENZDWU.js +1 -1
  42. package/dist/{connected-teams-Z5GOIC5I.js → connected-teams-RU6VATCM.js} +2 -2
  43. package/dist/{coordinator-prompt-HZUWK3NP.js → coordinator-prompt-TU6656OK.js} +9 -8
  44. package/dist/{coordinator-prompt-Y6S6USNS.js → coordinator-prompt-VQHQ3RIX.js} +8 -7
  45. package/dist/{global-workspace-4JCITHB6.js → global-workspace-47NZVA44.js} +8 -7
  46. package/dist/{global-workspace-YA7U4M2N.js → global-workspace-PHF2MOGW.js} +9 -8
  47. package/dist/index.cjs +1443 -856
  48. package/dist/index.d.cts +118 -37
  49. package/dist/index.d.ts +118 -37
  50. package/dist/index.js +148 -64
  51. package/dist/managed-accounts-2AK5RIAF.js +39 -0
  52. package/dist/managed-accounts-4BLTJKAN.js +41 -0
  53. package/dist/mcp/run-stdio.cjs +2722 -2248
  54. package/dist/mcp/run-stdio.js +136 -50
  55. package/dist/{orchestrator-LWADJQTN.js → orchestrator-OCG4QVA5.js} +13 -11
  56. package/dist/{orchestrator-VHJZEVGA.js → orchestrator-VLTO5JBR.js} +13 -11
  57. package/dist/{plan-file-CKXUFTQ2.js → plan-file-VAHV5WBB.js} +2 -2
  58. package/dist/{thread-store-HDQ4CH54.js → thread-store-FJ5CDX2M.js} +1 -1
  59. package/dist/{thread-store-ZDR3Z5UG.js → thread-store-SHCUBWB3.js} +1 -1
  60. package/dist/title-ERD6D3C3.js +8 -0
  61. package/dist/title-Z7WAJN57.js +6 -0
  62. package/dist/{workspaces-IXZD7EC4.js → workspaces-2XTDS7N2.js} +9 -8
  63. package/dist/{workspaces-4KHEUPEX.js → workspaces-I7TWFTJM.js} +8 -7
  64. package/dist/{worktree-DAAF64UU.js → worktree-DDDF3WHV.js} +8 -7
  65. package/dist/{worktree-S3FOMEQ2.js → worktree-YASFE65H.js} +7 -6
  66. package/package.json +1 -1
@@ -0,0 +1,72 @@
1
+ import {
2
+ clipToolResultForStore,
3
+ looksLikeHugeToolResultDump
4
+ } from "./chunk-WV7KJH2E.js";
5
+ import {
6
+ CLI_DIR
7
+ } from "./chunk-6K64FJDD.js";
8
+
9
+ // src/agents/tool-result-clip.ts
10
+ import { mkdirSync, writeFileSync } from "fs";
11
+ import { join } from "path";
12
+ function spillPath(cwd, prefix) {
13
+ const stamp = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
14
+ const safe = prefix.replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "tool";
15
+ return join(cwd, CLI_DIR, `${safe}-${stamp}.txt`);
16
+ }
17
+ function spillToolResultToCli(content, opts) {
18
+ const cwd = opts?.cwd?.trim();
19
+ if (!cwd || !content) return null;
20
+ const file = spillPath(cwd, opts?.prefix ?? "tool-result");
21
+ try {
22
+ mkdirSync(join(cwd, CLI_DIR), { recursive: true });
23
+ writeFileSync(file, content, "utf8");
24
+ return file;
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+ function spillAndClipToolResult(content, opts) {
30
+ const clipped = clipToolResultForStore(content);
31
+ if (clipped == null) return content;
32
+ if (clipped === content) return content;
33
+ if (looksLikeHugeToolResultDump(content)) return clipped;
34
+ const spilled = spillToolResultToCli(content, opts);
35
+ if (!spilled) return clipped;
36
+ return `${clipped}
37
+
38
+ Full output: ${spilled} (${content.length} chars). Read that file with offset/limit \u2014 do not dump it whole.`;
39
+ }
40
+ function clipMcpToolResult(result, cwd) {
41
+ if (result == null) return { content: [] };
42
+ if (!Array.isArray(result.content)) return result;
43
+ return {
44
+ ...result,
45
+ content: result.content.map((block) => {
46
+ if (block?.type !== "text" || typeof block.text !== "string") return block;
47
+ return {
48
+ ...block,
49
+ text: spillAndClipToolResult(block.text, { cwd, prefix: "mcp" })
50
+ };
51
+ })
52
+ };
53
+ }
54
+ function clipAgentEventForEmit(event, cwd) {
55
+ if (!event || typeof event !== "object") return event;
56
+ const rec = event;
57
+ if (rec.type === "tool_result" && typeof rec.content === "string") {
58
+ return {
59
+ ...rec,
60
+ content: spillAndClipToolResult(rec.content, { cwd, prefix: "cursor-tool" })
61
+ };
62
+ }
63
+ if ((rec.type === "stderr" || rec.type === "stdout") && typeof rec.data === "string" && looksLikeHugeToolResultDump(rec.data)) {
64
+ return { ...rec, data: clipToolResultForStore(rec.data) };
65
+ }
66
+ return event;
67
+ }
68
+
69
+ export {
70
+ clipMcpToolResult,
71
+ clipAgentEventForEmit
72
+ };
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  getAbleTimeHost,
6
6
  isAbleTimeConnected
7
- } from "./chunk-KJM3E3NF.js";
7
+ } from "./chunk-6PFZ6XO7.js";
8
8
 
9
9
  // src/integrations/abletime-mcp.ts
10
10
  var DEFAULT_ABLETIME_HOST = "https://track.abletime.com";
@@ -153,7 +153,7 @@ function textsFromUnknown(value) {
153
153
  return "";
154
154
  }
155
155
  async function abletimeMcpRequest(method, params, opts) {
156
- const rawToken = opts?.token ?? await import("./abletime-oauth-ZQUIY4EM.js").then((m) => m.ensureAbleTimeAccessToken());
156
+ const rawToken = opts?.token ?? await import("./abletime-oauth-5A5EOH2A.js").then((m) => m.ensureAbleTimeAccessToken());
157
157
  if (!rawToken?.trim()) {
158
158
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
159
159
  }
@@ -224,9 +224,9 @@ async function callAbleTimeTool(name, args = {}, opts) {
224
224
  if (!opts?.token && !isAbleTimeConnected()) {
225
225
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
226
226
  }
227
- const rawToken = opts?.token ?? await import("./abletime-oauth-ZQUIY4EM.js").then((m) => m.ensureAbleTimeAccessToken());
227
+ const rawToken = opts?.token ?? await import("./abletime-oauth-5A5EOH2A.js").then((m) => m.ensureAbleTimeAccessToken());
228
228
  if (rawToken && ableTimeUsesRest(rawToken)) {
229
- const { callAbleTimeRestTool } = await import("./abletime-rest-JZIIT5W3.js");
229
+ const { callAbleTimeRestTool } = await import("./abletime-rest-UEHOBLXD.js");
230
230
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
231
231
  }
232
232
  const requestOpts = { ...opts, pm: opts?.pm ?? abletimeToolUsesPm(name) };
@@ -242,7 +242,7 @@ async function callAbleTimeTool(name, args = {}, opts) {
242
242
  return await call();
243
243
  }
244
244
  if (rawToken && ableTimeUsesRest(rawToken) && isAbleTimeRejectedCredential(message)) {
245
- const { callAbleTimeRestTool } = await import("./abletime-rest-JZIIT5W3.js");
245
+ const { callAbleTimeRestTool } = await import("./abletime-rest-UEHOBLXD.js");
246
246
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
247
247
  }
248
248
  throw err instanceof Error ? new Error(rewriteAbleTimeError(err.message)) : err;
@@ -8,17 +8,11 @@ import {
8
8
  resolveRepoRoot,
9
9
  takenSlugsFromThread,
10
10
  teamSlugFromName
11
- } from "./chunk-HCNCZPDL.js";
11
+ } from "./chunk-FSZ7YYFQ.js";
12
12
  import {
13
13
  ATTACHMENTS_DIR,
14
14
  attachmentsGitignoreBody
15
- } from "./chunk-D6JWYJ4P.js";
16
- import {
17
- createEmptyThread,
18
- listThreads,
19
- updateThread,
20
- writeThread
21
- } from "./chunk-RJC2MKXN.js";
15
+ } from "./chunk-N2WW62LF.js";
22
16
  import {
23
17
  assertOrchestratorCapableAgent,
24
18
  formatAccountProfilePlaybookLine,
@@ -31,7 +25,13 @@ import {
31
25
  resolveThreadDefaults,
32
26
  resolveViewerProfile,
33
27
  resolveViewerProfileForRepo
34
- } from "./chunk-452Y24PW.js";
28
+ } from "./chunk-VIC6TDYT.js";
29
+ import {
30
+ createEmptyThread,
31
+ listThreads,
32
+ updateThread,
33
+ writeThread
34
+ } from "./chunk-TJ673EZT.js";
35
35
  import {
36
36
  appDataDir,
37
37
  globalAgentCwd,
@@ -372,7 +372,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
372
372
  "Inspect / review / PRs:",
373
373
  "- get_diff \u2014 compact diff summary",
374
374
  "- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
375
- '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
375
+ '- request_review \u2014 run a Review on a worktree thread. Reuses the only unused idle agent when the checkout has a single chat with no messages; otherwise opens a Review tab (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
376
376
  "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge \u2014 same prompts as the desktop git buttons (Resolve, Create PR, \u2026). Always steers the worktree agent; then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
377
377
  '- 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.',
378
378
  '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft --assignee @me -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.',
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  textFromAbleTimeDoc
3
- } from "./chunk-66LAOKLK.js";
3
+ } from "./chunk-D554YCHG.js";
4
4
  import {
5
5
  assertAbleTimeCredential,
6
6
  callAbleTimeTool,
7
7
  normalizeAbleTimeHost,
8
8
  rewriteAbleTimeError
9
- } from "./chunk-IFHHPPSL.js";
9
+ } from "./chunk-J6ONZP74.js";
10
10
  import {
11
11
  isAbleTimeConnected,
12
12
  saveAbleTimeConnection
13
- } from "./chunk-KJM3E3NF.js";
13
+ } from "./chunk-6PFZ6XO7.js";
14
14
 
15
15
  // src/integrations/abletime.ts
16
16
  var CLOSED_STATES = /* @__PURE__ */ new Set([
@@ -6,12 +6,12 @@ import {
6
6
  refreshBrightsyAccessToken,
7
7
  saveBrightsyConfig
8
8
  } from "./chunk-ROPGQRPU.js";
9
- import {
10
- appDataDir
11
- } from "./chunk-EHT2DRT4.js";
12
9
  import {
13
10
  run
14
11
  } from "./chunk-QVN2WOKJ.js";
12
+ import {
13
+ appDataDir
14
+ } from "./chunk-EHT2DRT4.js";
15
15
 
16
16
  // src/brightsy/connected-teams.ts
17
17
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -19,7 +19,7 @@ import { join } from "path";
19
19
 
20
20
  // src/brightsy/accounts.ts
21
21
  async function loadConnectedTeams() {
22
- const { listConnectedBrightsyTeams: listConnectedBrightsyTeams2 } = await import("./connected-teams-Z5GOIC5I.js");
22
+ const { listConnectedBrightsyTeams: listConnectedBrightsyTeams2 } = await import("./connected-teams-RU6VATCM.js");
23
23
  return listConnectedBrightsyTeams2();
24
24
  }
25
25
  async function runBrightsyTeamsJson(args) {
@@ -48,14 +48,14 @@ async function listBrightsyAccounts() {
48
48
  async function getBrightsySession() {
49
49
  try {
50
50
  const { ensureBrightsyLocalConfigFresh: ensureBrightsyLocalConfigFresh2 } = await import("./oauth-S3M7B475.js");
51
- const { ensureConnectedBrightsyTeamTokens: ensureConnectedBrightsyTeamTokens2 } = await import("./connected-teams-Z5GOIC5I.js");
51
+ const { ensureConnectedBrightsyTeamTokens: ensureConnectedBrightsyTeamTokens2 } = await import("./connected-teams-RU6VATCM.js");
52
52
  await ensureBrightsyLocalConfigFresh2();
53
53
  await ensureConnectedBrightsyTeamTokens2();
54
54
  loadBrightsyConfig();
55
55
  const data = await runBrightsyTeamsJson([]);
56
56
  const accounts = Array.isArray(data.teams) ? data.teams : [];
57
57
  const active = data.active ?? accounts.find((a) => a.active) ?? null;
58
- const { ensureCliTeamTracked: ensureCliTeamTracked2 } = await import("./connected-teams-Z5GOIC5I.js");
58
+ const { ensureCliTeamTracked: ensureCliTeamTracked2 } = await import("./connected-teams-RU6VATCM.js");
59
59
  const connectedTeams = ensureCliTeamTracked2(
60
60
  active ? { id: active.id, slug: active.slug, name: active.name } : void 0
61
61
  );
@@ -95,7 +95,7 @@ async function performBrightsyAccountSwitch(accountIdOrSlug) {
95
95
  return { cfg, target: data.active };
96
96
  }
97
97
  async function switchBrightsyAccount(accountIdOrSlug) {
98
- const { connectBrightsyTeam: connectBrightsyTeam2 } = await import("./connected-teams-Z5GOIC5I.js");
98
+ const { connectBrightsyTeam: connectBrightsyTeam2 } = await import("./connected-teams-RU6VATCM.js");
99
99
  await connectBrightsyTeam2(accountIdOrSlug);
100
100
  return getBrightsySession();
101
101
  }
@@ -22,6 +22,7 @@ function titleFromPrompt(prompt, max = 60) {
22
22
  const base = lastSpace > Math.floor(max * 0.4) ? sliced.slice(0, lastSpace) : sliced;
23
23
  return `${base.trimEnd()}\u2026`;
24
24
  }
25
+
25
26
  export {
26
27
  titleFromPrompt
27
28
  };
@@ -21,6 +21,7 @@ function isWorkspaceScratchPath(relativePath) {
21
21
 
22
22
  export {
23
23
  ATTACHMENTS_DIR,
24
+ CLI_DIR,
24
25
  DETACHED_JOBS_DIR,
25
26
  LEGACY_ATTACHMENTS_DIR,
26
27
  LEGACY_DETACHED_JOBS_DIR,
@@ -2,17 +2,17 @@
2
2
 
3
3
  import {
4
4
  textFromAbleTimeDoc
5
- } from "./chunk-XIEDFRBP.js";
5
+ } from "./chunk-B6XFBNYM.js";
6
6
  import {
7
7
  assertAbleTimeCredential,
8
8
  callAbleTimeTool,
9
9
  normalizeAbleTimeHost,
10
10
  rewriteAbleTimeError
11
- } from "./chunk-ZC3TVLY6.js";
11
+ } from "./chunk-5OKJDCBK.js";
12
12
  import {
13
13
  isAbleTimeConnected,
14
14
  saveAbleTimeConnection
15
- } from "./chunk-452Y24PW.js";
15
+ } from "./chunk-VIC6TDYT.js";
16
16
 
17
17
  // src/integrations/abletime.ts
18
18
  var CLOSED_STATES = /* @__PURE__ */ new Set([
@@ -83,6 +83,7 @@ function normalizeThread(raw) {
83
83
  runScriptRequest: normalizeRunScriptRequest(raw.runScriptRequest),
84
84
  quotaResumeAt: raw.quotaResumeAt ?? null,
85
85
  quotaContinuedFromId: raw.quotaContinuedFromId ?? null,
86
+ accountId: raw.accountId === null ? null : typeof raw.accountId === "string" && raw.accountId.trim() ? raw.accountId.trim() : void 0,
86
87
  archivedAt: typeof raw.archivedAt === "string" && raw.archivedAt.trim() ? raw.archivedAt.trim() : void 0,
87
88
  compactedMessages: Array.isArray(raw.compactedMessages) ? raw.compactedMessages : void 0
88
89
  };
@@ -135,7 +136,8 @@ function createEmptyThread(partial) {
135
136
  repoPath: partial.repoPath,
136
137
  agent: partial.agent,
137
138
  lastError: null,
138
- agentPid: null
139
+ agentPid: null,
140
+ ...partial.accountId !== void 0 ? { accountId: partial.accountId } : {}
139
141
  };
140
142
  }
141
143
  async function withThreadLock(id, fn) {
@@ -1,19 +1,9 @@
1
- import {
2
- isWorkspaceScratchPath
3
- } from "./chunk-6K64FJDD.js";
4
1
  import {
5
2
  ensureWorktreeSideboardIgnored
6
3
  } from "./chunk-2P4XKWV2.js";
7
4
  import {
8
- getGithubGitAuthMode,
9
- getGithubPat
10
- } from "./chunk-KJM3E3NF.js";
11
- import {
12
- listThreads
13
- } from "./chunk-4723RAO3.js";
14
- import {
15
- worktreesRoot
16
- } from "./chunk-EHT2DRT4.js";
5
+ isWorkspaceScratchPath
6
+ } from "./chunk-6K64FJDD.js";
17
7
  import {
18
8
  gh,
19
9
  git,
@@ -24,12 +14,22 @@ import {
24
14
  materializeGithubAgentAuth,
25
15
  resolveGhAuthToken
26
16
  } from "./chunk-QVN2WOKJ.js";
17
+ import {
18
+ getGithubGitAuthMode,
19
+ getGithubPat
20
+ } from "./chunk-6PFZ6XO7.js";
21
+ import {
22
+ listThreads
23
+ } from "./chunk-FWNL62VA.js";
24
+ import {
25
+ worktreesRoot
26
+ } from "./chunk-EHT2DRT4.js";
27
27
 
28
28
  // src/git/worktree.ts
29
29
  import { randomBytes } from "crypto";
30
- import { existsSync, readdirSync, realpathSync, unlinkSync, writeFileSync } from "fs";
30
+ import { existsSync as existsSync2, realpathSync, unlinkSync, writeFileSync } from "fs";
31
31
  import { tmpdir } from "os";
32
- import { join } from "path";
32
+ import { join as join2 } from "path";
33
33
 
34
34
  // src/git/team-meta.ts
35
35
  var SOCCER_TEAM_META = {
@@ -879,6 +879,42 @@ function worktreeDisplayLabelForGroup(threads) {
879
879
  const canonical = [...threads].sort((a, b) => a.createdAt.localeCompare(b.createdAt))[0];
880
880
  return threadDisplayLabel(canonical);
881
881
  }
882
+ function agentNicknameFromWorktreePath(worktreePath) {
883
+ const dir = worktreeNameFromPath(worktreePath);
884
+ if (!soccerTokenFromTakenSlug(dir)) return null;
885
+ return teamNameFromSlug(dir);
886
+ }
887
+ function worktreeIdentityTitles(thread, parentTitle) {
888
+ const out = [];
889
+ const push = (value) => {
890
+ const trimmed = value?.trim();
891
+ if (trimmed) out.push(trimmed);
892
+ };
893
+ push(parentTitle);
894
+ push(thread.prTitle);
895
+ const branch = thread.branchName?.trim() ?? "";
896
+ const path = thread.worktreePath?.trim() ?? "";
897
+ if (branch && path && branch !== "HEAD" && !isPlaceholderBranch(branch, path)) {
898
+ push(branch);
899
+ }
900
+ return out;
901
+ }
902
+ function foldLabel(value) {
903
+ return value.trim().replace(/[.…]+$/g, "").replace(/\s+/g, " ").toLowerCase();
904
+ }
905
+ function isWorktreeIdentityTitle(title, identities) {
906
+ const a = foldLabel(title);
907
+ if (!a || a === "untitled" || a === "new agent") return true;
908
+ for (const identity of identities) {
909
+ const b = foldLabel(identity);
910
+ if (!b) continue;
911
+ if (a === b) return true;
912
+ const shorter = a.length <= b.length ? a : b;
913
+ const longer = a.length <= b.length ? b : a;
914
+ if (shorter.length >= 20 && longer.startsWith(shorter)) return true;
915
+ }
916
+ return false;
917
+ }
882
918
 
883
919
  // src/git/gh-errors.ts
884
920
  var GITHUB_PR_BODY_MAX_CHARS = 65536;
@@ -1900,6 +1936,70 @@ async function checkoutPrStackLayer(cwd, target) {
1900
1936
  }
1901
1937
  }
1902
1938
 
1939
+ // src/git/team-slugs.ts
1940
+ import { existsSync, readdirSync } from "fs";
1941
+ import { join } from "path";
1942
+ function sameRepoPath(a, b) {
1943
+ return normalizeWorktreePath(a) === normalizeWorktreePath(b);
1944
+ }
1945
+ function listLocalPlaceholderBranchSlugs(repoPath) {
1946
+ const slugs = [];
1947
+ const headsDir = join(repoPath, ".git", "refs", "heads");
1948
+ const threadDir = join(headsDir, "thread");
1949
+ try {
1950
+ if (existsSync(threadDir)) {
1951
+ for (const name of readdirSync(threadDir)) {
1952
+ if (!name.startsWith(".")) slugs.push(normalizeTakenSlug(name));
1953
+ }
1954
+ }
1955
+ if (existsSync(headsDir)) {
1956
+ for (const entry of readdirSync(headsDir, { withFileTypes: true })) {
1957
+ if (entry.isFile() && !entry.name.startsWith(".")) {
1958
+ slugs.push(normalizeTakenSlug(entry.name));
1959
+ }
1960
+ }
1961
+ }
1962
+ } catch {
1963
+ return slugs;
1964
+ }
1965
+ return slugs;
1966
+ }
1967
+ function collectTakenTeamSlugs(repoPath) {
1968
+ const taken = /* @__PURE__ */ new Set();
1969
+ const root = worktreesRoot(repoPath);
1970
+ if (existsSync(root)) {
1971
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
1972
+ if (entry.isDirectory() && entry.name !== ".DS_Store") {
1973
+ for (const slug of takenSlugsFromThread({ worktreePath: entry.name })) {
1974
+ taken.add(slug);
1975
+ }
1976
+ }
1977
+ }
1978
+ }
1979
+ for (const slug of listLocalPlaceholderBranchSlugs(repoPath)) {
1980
+ for (const token of takenSlugsFromThread({ branchName: slug })) {
1981
+ taken.add(token);
1982
+ }
1983
+ }
1984
+ for (const thread of listThreads({ includeArchived: true })) {
1985
+ if (!sameRepoPath(thread.repoPath, repoPath)) continue;
1986
+ for (const slug of takenSlugsFromThread(thread)) {
1987
+ taken.add(slug);
1988
+ }
1989
+ }
1990
+ return taken;
1991
+ }
1992
+ function allocateTeamSlug(repoPath) {
1993
+ const taken = collectTakenTeamSlugs(repoPath);
1994
+ for (let attempt = 0; attempt < 32; attempt++) {
1995
+ const team = allocateTeamName(taken);
1996
+ const path = join(worktreesRoot(repoPath), team.slug);
1997
+ if (!existsSync(path)) return team;
1998
+ taken.add(team.slug);
1999
+ }
2000
+ throw new Error("No available soccer team worktree directories left");
2001
+ }
2002
+
1903
2003
  // src/git/worktree.ts
1904
2004
  async function lookupGithubGraphqlReset(cwd) {
1905
2005
  const result = await gh(["api", "rate_limit"], cwd, { reject: false });
@@ -2858,9 +2958,9 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
2858
2958
  await fastForwardMainCheckoutIfSafe(repoPath, { branch: def });
2859
2959
  }
2860
2960
  async function createThreadWorktree(opts) {
2861
- let branchName = `thread/${opts.slug}`;
2862
- const worktreePath = join(worktreesRoot(opts.repoPath), opts.slug);
2863
- if (existsSync(worktreePath)) {
2961
+ let branchName = opts.slug;
2962
+ const worktreePath = join2(worktreesRoot(opts.repoPath), opts.slug);
2963
+ if (existsSync2(worktreePath)) {
2864
2964
  throw new Error(`Worktree already exists at ${worktreePath}`);
2865
2965
  }
2866
2966
  await ensureGhPreferOrigin(opts.repoPath);
@@ -2901,8 +3001,8 @@ ${add.stdout}`;
2901
3001
  async function createExistingBranchWorktree(opts) {
2902
3002
  const branchName = opts.branchName.trim();
2903
3003
  if (!branchName) throw new Error("branch name required");
2904
- const worktreePath = join(worktreesRoot(opts.repoPath), opts.slug);
2905
- if (existsSync(worktreePath)) {
3004
+ const worktreePath = join2(worktreesRoot(opts.repoPath), opts.slug);
3005
+ if (existsSync2(worktreePath)) {
2906
3006
  throw new Error(`Worktree already exists at ${worktreePath}`);
2907
3007
  }
2908
3008
  await ensureGhPreferOrigin(opts.repoPath);
@@ -3241,7 +3341,7 @@ async function createOrUpdatePr(worktreePath, opts) {
3241
3341
  const headRef = ghHeadRef(slug, opts.head);
3242
3342
  const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
3243
3343
  const bodyText = clampGithubPrBody(opts.body ?? opts.title);
3244
- const bodyFile = join(
3344
+ const bodyFile = join2(
3245
3345
  tmpdir(),
3246
3346
  `sideboard-pr-body-${process.pid}-${randomBytes(6).toString("hex")}.md`
3247
3347
  );
@@ -3339,53 +3439,6 @@ function suggestSlug(source) {
3339
3439
  const stamp = Date.now().toString(36).slice(-4);
3340
3440
  return `${base || "thread"}-${stamp}`;
3341
3441
  }
3342
- function sameRepoPath(a, b) {
3343
- return normalizeWorktreePath(a) === normalizeWorktreePath(b);
3344
- }
3345
- function listLocalThreadBranchSlugs(repoPath) {
3346
- const refsDir = join(repoPath, ".git", "refs", "heads", "thread");
3347
- if (!existsSync(refsDir)) return [];
3348
- try {
3349
- return readdirSync(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
3350
- } catch {
3351
- return [];
3352
- }
3353
- }
3354
- function collectTakenTeamSlugs(repoPath) {
3355
- const taken = /* @__PURE__ */ new Set();
3356
- const root = worktreesRoot(repoPath);
3357
- if (existsSync(root)) {
3358
- for (const entry of readdirSync(root, { withFileTypes: true })) {
3359
- if (entry.isDirectory() && entry.name !== ".DS_Store") {
3360
- for (const slug of takenSlugsFromThread({ worktreePath: entry.name })) {
3361
- taken.add(slug);
3362
- }
3363
- }
3364
- }
3365
- }
3366
- for (const slug of listLocalThreadBranchSlugs(repoPath)) {
3367
- for (const token of takenSlugsFromThread({ branchName: slug })) {
3368
- taken.add(token);
3369
- }
3370
- }
3371
- for (const thread of listThreads({ includeArchived: true })) {
3372
- if (!sameRepoPath(thread.repoPath, repoPath)) continue;
3373
- for (const slug of takenSlugsFromThread(thread)) {
3374
- taken.add(slug);
3375
- }
3376
- }
3377
- return taken;
3378
- }
3379
- function allocateTeamSlug(repoPath) {
3380
- const taken = collectTakenTeamSlugs(repoPath);
3381
- for (let attempt = 0; attempt < 32; attempt++) {
3382
- const team = allocateTeamName(taken);
3383
- const path = join(worktreesRoot(repoPath), team.slug);
3384
- if (!existsSync(path)) return team;
3385
- taken.add(team.slug);
3386
- }
3387
- throw new Error("No available soccer team worktree directories left");
3388
- }
3389
3442
 
3390
3443
  export {
3391
3444
  FAMOUS_SOCCER_TEAMS,
@@ -3402,6 +3455,9 @@ export {
3402
3455
  threadDisplayLabel,
3403
3456
  worktreeDisplayLabel,
3404
3457
  worktreeDisplayLabelForGroup,
3458
+ agentNicknameFromWorktreePath,
3459
+ worktreeIdentityTitles,
3460
+ isWorktreeIdentityTitle,
3405
3461
  GITHUB_PR_BODY_MAX_CHARS,
3406
3462
  GITHUB_PR_BODY_SAFE_CHARS,
3407
3463
  isGhRateLimitError,
@@ -3443,6 +3499,8 @@ export {
3443
3499
  addPrStackLayer,
3444
3500
  submitPrStack,
3445
3501
  checkoutPrStackLayer,
3502
+ collectTakenTeamSlugs,
3503
+ allocateTeamSlug,
3446
3504
  slugify,
3447
3505
  resolveRepoRoot,
3448
3506
  canonicalizeRepoPath,
@@ -3488,7 +3546,5 @@ export {
3488
3546
  mergePr,
3489
3547
  ghPrCreateAssigneeArgs,
3490
3548
  createOrUpdatePr,
3491
- suggestSlug,
3492
- collectTakenTeamSlugs,
3493
- allocateTeamSlug
3549
+ suggestSlug
3494
3550
  };