@sideboard-ai/core 0.1.243 → 0.1.245

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 (27) hide show
  1. package/dist/{agents-CPME6O2H.js → agents-BOIIFMNG.js} +3 -3
  2. package/dist/{agents-VKO5UZO6.js → agents-FTQZFMDS.js} +3 -3
  3. package/dist/{chunk-HR4RNC73.js → chunk-3ZEBUVUI.js} +113 -29
  4. package/dist/{chunk-ECZTXNYR.js → chunk-576S3HJ7.js} +3 -3
  5. package/dist/{chunk-7UCZ4DRF.js → chunk-5ZFULOTC.js} +8 -0
  6. package/dist/{chunk-CCD2QIFK.js → chunk-E6C5NR46.js} +8 -0
  7. package/dist/{chunk-3P5OCI2X.js → chunk-GFRC6JQN.js} +3 -3
  8. package/dist/{chunk-DARSRQUE.js → chunk-J5IZXFLD.js} +16 -14
  9. package/dist/{chunk-NEOAHPMK.js → chunk-NT6MCFSB.js} +17 -15
  10. package/dist/{chunk-ISZERVDT.js → chunk-QRWVKBGP.js} +122 -30
  11. package/dist/{coordinator-prompt-AJ3E6LBX.js → coordinator-prompt-WQIICPT6.js} +2 -2
  12. package/dist/{coordinator-prompt-PYIRQGU7.js → coordinator-prompt-ZBYRREHD.js} +2 -2
  13. package/dist/{global-workspace-GQM653DP.js → global-workspace-2N6KISDO.js} +2 -2
  14. package/dist/{global-workspace-GIQ6F6IJ.js → global-workspace-3SQU4GL4.js} +2 -2
  15. package/dist/index.cjs +140 -34
  16. package/dist/index.d.cts +22 -6
  17. package/dist/index.d.ts +22 -6
  18. package/dist/index.js +12 -6
  19. package/dist/mcp/run-stdio.cjs +128 -34
  20. package/dist/mcp/run-stdio.js +6 -6
  21. package/dist/{orchestrator-3IOISDFS.js → orchestrator-5ROSTGGH.js} +4 -4
  22. package/dist/{orchestrator-YDPDMXUY.js → orchestrator-7YCQ7V5S.js} +4 -4
  23. package/dist/{workspaces-WYC5TLC3.js → workspaces-CFI7XVAE.js} +2 -2
  24. package/dist/{workspaces-OIBSD5B6.js → workspaces-QLKWW3O2.js} +2 -2
  25. package/dist/{worktree-DGDM7LGV.js → worktree-4UAOZUJ4.js} +3 -1
  26. package/dist/{worktree-5VRZVGP3.js → worktree-PK3QETXO.js} +3 -1
  27. package/package.json +1 -1
@@ -46,9 +46,9 @@ import {
46
46
  resolveLoginCommand,
47
47
  resolveQuotaFallbackAgent,
48
48
  whichOnPath
49
- } from "./chunk-ISZERVDT.js";
50
- import "./chunk-3P5OCI2X.js";
51
- import "./chunk-CCD2QIFK.js";
49
+ } from "./chunk-QRWVKBGP.js";
50
+ import "./chunk-GFRC6JQN.js";
51
+ import "./chunk-E6C5NR46.js";
52
52
  import "./chunk-6K64FJDD.js";
53
53
  import "./chunk-2P4XKWV2.js";
54
54
  import "./chunk-CJKL7A4G.js";
@@ -55,12 +55,12 @@ import {
55
55
  resolveQuotaFallbackAgent,
56
56
  turnCostUsdFromCursorUsage,
57
57
  whichOnPath
58
- } from "./chunk-HR4RNC73.js";
59
- import "./chunk-ECZTXNYR.js";
58
+ } from "./chunk-3ZEBUVUI.js";
59
+ import "./chunk-576S3HJ7.js";
60
60
  import "./chunk-J5GON4SU.js";
61
61
  import "./chunk-P2BSMNHB.js";
62
62
  import "./chunk-VKQGAWHY.js";
63
- import "./chunk-7UCZ4DRF.js";
63
+ import "./chunk-5ZFULOTC.js";
64
64
  import "./chunk-D6JWYJ4P.js";
65
65
  import "./chunk-7HOKP4GR.js";
66
66
  import "./chunk-N6XI5KXL.js";
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  isOrchestratorThread
5
- } from "./chunk-ECZTXNYR.js";
5
+ } from "./chunk-576S3HJ7.js";
6
6
  import {
7
7
  applyConnectedTeamToCli,
8
8
  brightsyMcpServerName,
@@ -20,7 +20,7 @@ import {
20
20
  mergeAgentGitAuthEnv,
21
21
  resolveAgentGitAuthEnv,
22
22
  resolveCodexGitWritableRoots
23
- } from "./chunk-7UCZ4DRF.js";
23
+ } from "./chunk-5ZFULOTC.js";
24
24
  import {
25
25
  enrichPathWithNpmGlobalBin,
26
26
  isConductorBundledCli,
@@ -1697,23 +1697,38 @@ function looksLikeComposerSkillExpansion(text) {
1697
1697
  const t = text.trim();
1698
1698
  return /^## Skill: \//m.test(t) && /Follow this skill for the request above:/i.test(t);
1699
1699
  }
1700
+ var SKILL_FRONTMATTER_NAME = /^\s*name\s*:\s*['"]?([A-Za-z0-9][A-Za-z0-9._-]*)['"]?\s*$/m;
1701
+ function skillNameFromFrontmatter(text) {
1702
+ const t = text.trim();
1703
+ if (!t) return void 0;
1704
+ let yaml = t;
1705
+ if (!yaml.startsWith("---")) {
1706
+ const at = t.search(/(?:^|\n)---(?:\r?\n)/);
1707
+ if (at < 0 || at > 800) return void 0;
1708
+ yaml = t.slice(at).replace(/^\n/, "");
1709
+ }
1710
+ if (!yaml.startsWith("---")) return void 0;
1711
+ const close = yaml.indexOf("\n---", 3);
1712
+ if (close < 0) return void 0;
1713
+ return yaml.slice(3, close).match(SKILL_FRONTMATTER_NAME)?.[1];
1714
+ }
1715
+ function skillCommandFromBody(text) {
1716
+ return skillNameFromFrontmatter(text) ?? text.match(/^## Skill: \/([A-Za-z0-9][A-Za-z0-9._-]*)/m)?.[1] ?? text.match(/^Launching skill:\s*\/?([A-Za-z0-9][A-Za-z0-9._-]*)/im)?.[1];
1717
+ }
1700
1718
  function looksLikeSkillBody(text) {
1701
1719
  const t = text.trim();
1702
1720
  if (!t) return false;
1703
1721
  if (looksLikeComposerSkillExpansion(t)) return true;
1704
- return skillNameFromFrontmatter(t) != null;
1722
+ if (skillNameFromFrontmatter(t) != null) return true;
1723
+ return /^Launching skill:/im.test(t) && /Base directory for this skill:/i.test(t);
1705
1724
  }
1706
- function skillNameFromFrontmatter(text) {
1725
+ function looksLikeIncompleteSkillDump(text) {
1707
1726
  const t = text.trim();
1708
- if (!t.startsWith("---")) return void 0;
1709
- const close = t.indexOf("\n---", 3);
1710
- if (close < 0) return void 0;
1711
- const fm = t.slice(3, close);
1712
- const m = fm.match(/^\s*name\s*:\s*['"]?([A-Za-z0-9][A-Za-z0-9._-]*)['"]?\s*$/m);
1713
- return m?.[1];
1714
- }
1715
- function skillCommandFromBody(text) {
1716
- return skillNameFromFrontmatter(text) ?? text.match(/^## Skill: \/([A-Za-z0-9][A-Za-z0-9._-]*)/m)?.[1];
1727
+ if (!t || looksLikeSkillBody(t)) return false;
1728
+ if (/^## Skill: \//m.test(t)) return true;
1729
+ if (/^Launching skill:/im.test(t)) return true;
1730
+ if (/Base directory for this skill:/i.test(t)) return true;
1731
+ return t.startsWith("---") && SKILL_FRONTMATTER_NAME.test(t);
1717
1732
  }
1718
1733
  function isCompactToolName(name) {
1719
1734
  const short = (name ?? "").replace(/^mcp__[^_]+__/, "").trim();
@@ -2032,22 +2047,70 @@ function withPartTimes(next, prev) {
2032
2047
  const startedAt = prev && typeof prev.startedAt === "number" ? prev.startedAt : now;
2033
2048
  return { ...next, startedAt, updatedAt: now };
2034
2049
  }
2035
- function skillToolFromTextPart(part, id) {
2050
+ function skillToolFromTextPart(part, id, status = "done") {
2036
2051
  const command = skillCommandFromBody(part.text);
2037
2052
  const input = command ? { skill: command } : void 0;
2038
2053
  return {
2039
2054
  type: "tool",
2040
- id,
2055
+ id: command ? `skill-${command}` : id,
2041
2056
  name: "Skill",
2042
2057
  input,
2043
2058
  description: toolDescription("Skill", input),
2044
- status: "done",
2059
+ status,
2045
2060
  result: clipToolResultForStore(part.text),
2046
2061
  ...part.parentId ? { parentId: part.parentId } : {},
2047
2062
  startedAt: part.startedAt,
2048
2063
  updatedAt: Date.now()
2049
2064
  };
2050
2065
  }
2066
+ function lastSkillToolIndex(parts, parentId) {
2067
+ for (let i = parts.length - 1; i >= 0; i--) {
2068
+ const p = parts[i];
2069
+ if (p.type === "tool" && isSkillToolName(p.name) && sameParentId(p.parentId, parentId)) {
2070
+ return i;
2071
+ }
2072
+ }
2073
+ return -1;
2074
+ }
2075
+ function lastRunningSkillIndex(parts, parentId) {
2076
+ for (let i = parts.length - 1; i >= 0; i--) {
2077
+ const p = parts[i];
2078
+ if (p.type === "tool" && isSkillToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
2079
+ return i;
2080
+ }
2081
+ }
2082
+ return -1;
2083
+ }
2084
+ function promoteOrFoldSkillText(parts, textIdx) {
2085
+ const acc = parts[textIdx];
2086
+ if (acc?.type !== "text") return parts;
2087
+ const complete = looksLikeSkillBody(acc.text);
2088
+ const incomplete = looksLikeIncompleteSkillDump(acc.text);
2089
+ if (!complete && !incomplete) return parts;
2090
+ const existing = lastSkillToolIndex(parts, acc.parentId);
2091
+ if (existing >= 0 && existing !== textIdx) {
2092
+ const prev = parts[existing];
2093
+ const next2 = parts.filter((_, i) => i !== textIdx);
2094
+ const existingIdx = lastSkillToolIndex(next2, acc.parentId);
2095
+ if (existingIdx < 0) return parts;
2096
+ next2[existingIdx] = withPartTimes(
2097
+ {
2098
+ ...prev,
2099
+ status: complete ? "done" : prev.status,
2100
+ result: clipToolResultForStore(acc.text) ?? prev.result
2101
+ },
2102
+ prev
2103
+ );
2104
+ return next2;
2105
+ }
2106
+ const next = [...parts];
2107
+ next[textIdx] = skillToolFromTextPart(
2108
+ acc,
2109
+ `skill-${next.length}`,
2110
+ complete ? "done" : "running"
2111
+ );
2112
+ return next;
2113
+ }
2051
2114
  function compactSummaryPart(text, id = "compact-summary") {
2052
2115
  return compactToolPart(text, id, { status: "done" });
2053
2116
  }
@@ -2136,6 +2199,21 @@ function applyAgentEvent(parts, event) {
2136
2199
  })
2137
2200
  ];
2138
2201
  }
2202
+ const runningSkillIdx = lastRunningSkillIndex(parts, event.parentId);
2203
+ if (runningSkillIdx >= 0) {
2204
+ const prev = parts[runningSkillIdx];
2205
+ const result = `${prev.result ?? ""}${data}`;
2206
+ const next2 = [...parts];
2207
+ next2[runningSkillIdx] = withPartTimes(
2208
+ {
2209
+ ...prev,
2210
+ result: clipToolResultForStore(result),
2211
+ status: looksLikeSkillBody(result) ? "done" : prev.status
2212
+ },
2213
+ prev
2214
+ );
2215
+ return next2;
2216
+ }
2139
2217
  const next = [...parts];
2140
2218
  const last = next[next.length - 1];
2141
2219
  if (last?.type === "text" && sameParentId(last.parentId, event.parentId)) {
@@ -2157,9 +2235,10 @@ function applyAgentEvent(parts, event) {
2157
2235
  );
2158
2236
  }
2159
2237
  const acc = next[next.length - 1];
2160
- if (acc?.type === "text" && looksLikeComposerSkillExpansion(acc.text)) {
2161
- next[next.length - 1] = skillToolFromTextPart(acc, `skill-${next.length}`);
2162
- } else if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
2238
+ if (acc?.type === "text" && (looksLikeSkillBody(acc.text) || looksLikeIncompleteSkillDump(acc.text))) {
2239
+ return promoteOrFoldSkillText(next, next.length - 1);
2240
+ }
2241
+ if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
2163
2242
  next[next.length - 1] = compactToolPart(acc.text, `compact-${next.length}`, {
2164
2243
  parentId: acc.parentId,
2165
2244
  status: "done",
@@ -2534,13 +2613,17 @@ function eventsFromInjectedUserText(text, parentId) {
2534
2613
  if (looksLikeConversationSummary(text)) return compactToolEventsFromBody(text, parentId);
2535
2614
  return [];
2536
2615
  }
2616
+ function eventsFromAssistantText(text, parentId) {
2617
+ if (looksLikeSkillBody(text)) return skillToolEventsFromBody(text, parentId);
2618
+ return [withEventParentId({ type: "stdout", data: text }, parentId)];
2619
+ }
2537
2620
  function eventsFromUserContent(content, parentId) {
2538
2621
  if (typeof content === "string" && content.trim()) {
2539
2622
  return eventsFromInjectedUserText(content, parentId);
2540
2623
  }
2541
2624
  if (!Array.isArray(content) || content.length === 0) return [];
2542
2625
  const out = [];
2543
- const textBlocks = [];
2626
+ const injected = [];
2544
2627
  for (const block of content) {
2545
2628
  if (!block?.type) continue;
2546
2629
  if (block.type === "tool_use" && block.id && block.name) {
@@ -2571,13 +2654,12 @@ function eventsFromUserContent(content, parentId) {
2571
2654
  );
2572
2655
  continue;
2573
2656
  }
2574
- if (block.type === "text" && block.text) textBlocks.push(block.text);
2575
- }
2576
- if (out.length > 0) return out;
2577
- for (const text of textBlocks) {
2578
- out.push(...eventsFromInjectedUserText(text, parentId));
2657
+ if (block.type === "text" && block.text) {
2658
+ injected.push(...eventsFromInjectedUserText(block.text, parentId));
2659
+ }
2579
2660
  }
2580
- return out;
2661
+ if (out.length === 0 && injected.length === 0) return [];
2662
+ return [...out, ...injected];
2581
2663
  }
2582
2664
  function eventsFromContentBlocks(blocks, parentId) {
2583
2665
  if (!blocks?.length) return [];
@@ -2585,7 +2667,7 @@ function eventsFromContentBlocks(blocks, parentId) {
2585
2667
  for (const block of blocks) {
2586
2668
  if (!block?.type) continue;
2587
2669
  if (block.type === "text" && block.text) {
2588
- out.push(withEventParentId({ type: "stdout", data: block.text }, parentId));
2670
+ out.push(...eventsFromAssistantText(block.text, parentId));
2589
2671
  continue;
2590
2672
  }
2591
2673
  if ((block.type === "thinking" || block.type === "redacted_thinking") && block.thinking) {
@@ -2852,7 +2934,7 @@ var claudeAdapter = {
2852
2934
  );
2853
2935
  }
2854
2936
  const mode = permissionMode(thread);
2855
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-GIQ6F6IJ.js");
2937
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3SQU4GL4.js");
2856
2938
  const isOrchestrator = isOrchestratorThread2(thread);
2857
2939
  const injectedServers = await buildInjectedMcpServers({
2858
2940
  includeSideboard: true,
@@ -3014,7 +3096,9 @@ var claudeAdapter = {
3014
3096
  events.push({ type: "stderr", data: errorDetail });
3015
3097
  } else {
3016
3098
  const text = obj.result;
3017
- if (typeof text === "string" && text) events.push({ type: "stdout", data: text });
3099
+ if (typeof text === "string" && text) {
3100
+ events.push(...eventsFromAssistantText(text));
3101
+ }
3018
3102
  }
3019
3103
  const usage = usageFromClaude(obj.usage);
3020
3104
  if (usage) {
@@ -8,7 +8,7 @@ import {
8
8
  resolveRepoRoot,
9
9
  takenSlugsFromThread,
10
10
  teamSlugFromName
11
- } from "./chunk-7UCZ4DRF.js";
11
+ } from "./chunk-5ZFULOTC.js";
12
12
  import {
13
13
  ATTACHMENTS_DIR,
14
14
  attachmentsGitignoreBody
@@ -327,7 +327,7 @@ function coordinatorGreenfieldPlaybook(reposDir) {
327
327
  "- Examples:",
328
328
  ` - Clone: \`git clone <url> ${reposDir}/<name>\``,
329
329
  ` - New GitHub repo: \`gh repo create <owner>/<name> --private --clone -- ${reposDir}/<name>\` (or mkdir + git init + gh repo create + remote add + push)`,
330
- "- Then: add_workspace with that absolute path \u2192 create_thread (repoPath + parentThreadId) \u2192 send_to_thread (build) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft (or send_to_thread `gh pr create --draft -R <origin-owner/name>`).",
330
+ "- Then: add_workspace with that absolute path \u2192 create_thread (repoPath + parentThreadId) \u2192 send_to_thread (build) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft (or send_to_thread `gh pr create --draft --assignee @me -R <origin-owner/name>`).",
331
331
  "- Always target the child worktree's **origin** (`github:` slug from list_workspaces / `git remote get-url origin` in that worktree). Never open PRs against `upstream`.",
332
332
  "- Do coding work in the child worktree thread, not by editing files in this home cwd."
333
333
  ].join("\n");
@@ -375,7 +375,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
375
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.',
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
- '- 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 -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.',
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.',
379
379
  "Process guides:",
380
380
  "- Long child jobs (pack, test, deploy, anything that may run more than ~30s): workers always have `/long-running` (Sideboard product skill). Tell them to detach and wait; they may `stop_job` if it hangs or is doing the wrong thing; do not ask the human to poll.",
381
381
  "- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
@@ -3069,6 +3069,11 @@ async function mergePr(cwd, selector, opts) {
3069
3069
  }
3070
3070
  return { url, state: "MERGED" };
3071
3071
  }
3072
+ function ghPrCreateAssigneeArgs(assignee) {
3073
+ const raw = assignee?.trim();
3074
+ if (raw && /^(none|unassigned)$/i.test(raw)) return [];
3075
+ return ["--assignee", raw || "@me"];
3076
+ }
3072
3077
  async function createOrUpdatePr(worktreePath, opts) {
3073
3078
  await ensureGhPreferOrigin(worktreePath);
3074
3079
  const slug = await resolveGithubRepoSlug(worktreePath);
@@ -3143,6 +3148,7 @@ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
3143
3148
  headRef
3144
3149
  ];
3145
3150
  if (opts.draft) args2.push("--draft");
3151
+ args2.push(...ghPrCreateAssigneeArgs(opts.assignee));
3146
3152
  await gh(args2, worktreePath, { reject: false });
3147
3153
  const again = await gh(
3148
3154
  [...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
@@ -3164,6 +3170,7 @@ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
3164
3170
  headRef
3165
3171
  ];
3166
3172
  if (opts.draft) args.push("--draft");
3173
+ args.push(...ghPrCreateAssigneeArgs(opts.assignee));
3167
3174
  const created = await gh(args, worktreePath, { reject: false });
3168
3175
  if (created.exitCode !== 0) {
3169
3176
  const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
@@ -3297,6 +3304,7 @@ export {
3297
3304
  pushBranch,
3298
3305
  markPrReady,
3299
3306
  mergePr,
3307
+ ghPrCreateAssigneeArgs,
3300
3308
  createOrUpdatePr,
3301
3309
  suggestSlug,
3302
3310
  collectTakenTeamSlugs,
@@ -3106,6 +3106,11 @@ async function mergePr(cwd, selector, opts) {
3106
3106
  }
3107
3107
  return { url, state: "MERGED" };
3108
3108
  }
3109
+ function ghPrCreateAssigneeArgs(assignee) {
3110
+ const raw = assignee?.trim();
3111
+ if (raw && /^(none|unassigned)$/i.test(raw)) return [];
3112
+ return ["--assignee", raw || "@me"];
3113
+ }
3109
3114
  async function createOrUpdatePr(worktreePath, opts) {
3110
3115
  await ensureGhPreferOrigin(worktreePath);
3111
3116
  const slug = await resolveGithubRepoSlug(worktreePath);
@@ -3180,6 +3185,7 @@ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
3180
3185
  headRef
3181
3186
  ];
3182
3187
  if (opts.draft) args2.push("--draft");
3188
+ args2.push(...ghPrCreateAssigneeArgs(opts.assignee));
3183
3189
  await gh(args2, worktreePath, { reject: false });
3184
3190
  const again = await gh(
3185
3191
  [...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
@@ -3201,6 +3207,7 @@ async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
3201
3207
  headRef
3202
3208
  ];
3203
3209
  if (opts.draft) args.push("--draft");
3210
+ args.push(...ghPrCreateAssigneeArgs(opts.assignee));
3204
3211
  const created = await gh(args, worktreePath, { reject: false });
3205
3212
  if (created.exitCode !== 0) {
3206
3213
  const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
@@ -3359,6 +3366,7 @@ export {
3359
3366
  pushBranch,
3360
3367
  markPrReady,
3361
3368
  mergePr,
3369
+ ghPrCreateAssigneeArgs,
3362
3370
  createOrUpdatePr,
3363
3371
  suggestSlug,
3364
3372
  collectTakenTeamSlugs,
@@ -6,7 +6,7 @@ import {
6
6
  resolveRepoRoot,
7
7
  takenSlugsFromThread,
8
8
  teamSlugFromName
9
- } from "./chunk-CCD2QIFK.js";
9
+ } from "./chunk-E6C5NR46.js";
10
10
  import {
11
11
  ATTACHMENTS_DIR,
12
12
  attachmentsGitignoreBody
@@ -372,7 +372,7 @@ function coordinatorGreenfieldPlaybook(reposDir) {
372
372
  "- Examples:",
373
373
  ` - Clone: \`git clone <url> ${reposDir}/<name>\``,
374
374
  ` - New GitHub repo: \`gh repo create <owner>/<name> --private --clone -- ${reposDir}/<name>\` (or mkdir + git init + gh repo create + remote add + push)`,
375
- "- Then: add_workspace with that absolute path \u2192 create_thread (repoPath + parentThreadId) \u2192 send_to_thread (build) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft (or send_to_thread `gh pr create --draft -R <origin-owner/name>`).",
375
+ "- Then: add_workspace with that absolute path \u2192 create_thread (repoPath + parentThreadId) \u2192 send_to_thread (build) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft (or send_to_thread `gh pr create --draft --assignee @me -R <origin-owner/name>`).",
376
376
  "- Always target the child worktree's **origin** (`github:` slug from list_workspaces / `git remote get-url origin` in that worktree). Never open PRs against `upstream`.",
377
377
  "- Do coding work in the child worktree thread, not by editing files in this home cwd."
378
378
  ].join("\n");
@@ -420,7 +420,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
420
420
  '- 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.',
421
421
  "- 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.",
422
422
  '- 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.',
423
- '- 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 -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.',
423
+ '- 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.',
424
424
  "Process guides:",
425
425
  "- Long child jobs (pack, test, deploy, anything that may run more than ~30s): workers always have `/long-running` (Sideboard product skill). Tell them to detach and wait; they may `stop_job` if it hangs or is doing the wrong thing; do not ask the human to poll.",
426
426
  "- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
@@ -44,7 +44,7 @@ import {
44
44
  summarizeTurnStderr,
45
45
  toolDescription,
46
46
  turnFailChatText
47
- } from "./chunk-HR4RNC73.js";
47
+ } from "./chunk-3ZEBUVUI.js";
48
48
  import {
49
49
  SLACK_REPLY_FORMATTING,
50
50
  addWorkspace,
@@ -67,7 +67,7 @@ import {
67
67
  stageAbsolutePathsAsAttachments,
68
68
  stageBuffersAsAttachments,
69
69
  syncWorkspacesFromThreads
70
- } from "./chunk-ECZTXNYR.js";
70
+ } from "./chunk-576S3HJ7.js";
71
71
  import {
72
72
  addPrStackLayer,
73
73
  allocateTeamName,
@@ -116,7 +116,7 @@ import {
116
116
  worktreeDisplayLabelForGroup,
117
117
  worktreeNameFromPath,
118
118
  worktreeSlugForTicket
119
- } from "./chunk-7UCZ4DRF.js";
119
+ } from "./chunk-5ZFULOTC.js";
120
120
  import {
121
121
  ATTACHMENTS_DIR,
122
122
  DETACHED_JOBS_DIR,
@@ -490,9 +490,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
490
490
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
491
491
  );
492
492
  }
493
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-GIQ6F6IJ.js");
493
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-3SQU4GL4.js");
494
494
  if (isGlobalThread2(thread)) {
495
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-PYIRQGU7.js");
495
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-ZBYRREHD.js");
496
496
  ensureGlobalCoordinatorCwd2(
497
497
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
498
498
  );
@@ -606,9 +606,11 @@ async function spawnAgentTurn(thread, input, onEvent) {
606
606
  if (assistantText && (parsed.data === assistantText || assistantText.endsWith(parsed.data))) {
607
607
  continue;
608
608
  }
609
- assistantText += parsed.data;
610
609
  }
611
610
  parts = applyAgentEvent(parts, parsed);
611
+ if (parsed.type === "stdout") {
612
+ assistantText = partsToAssistantText(parts);
613
+ }
612
614
  outbound.push(parsed);
613
615
  }
614
616
  });
@@ -683,9 +685,9 @@ function gitActionExpansion(action, base) {
683
685
  case "commit-push":
684
686
  return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`; this updates an existing PR when one is linked). Do not start a checks loop unless a goal was given.";
685
687
  case "create-draft":
686
- return "Commit, push, then create a draft PR with `gh pr create --draft -R <origin-owner/name>` (title/body from the change purpose). Update the existing PR instead if one is linked.";
688
+ return "Commit, push, then create a draft PR with `gh pr create --draft --assignee @me -R <origin-owner/name>` (title/body from the change purpose). Update the existing PR instead if one is linked. Use a different `--assignee` only if the user named someone else.";
687
689
  case "create-web":
688
- return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
690
+ return "Commit, push, then `gh pr create --web --assignee @me -R <origin-owner/name>`. Use a different `--assignee` only if the user named someone else.";
689
691
  case "resolve-conflicts":
690
692
  return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
691
693
  case "ready-for-review":
@@ -4552,7 +4554,7 @@ async function adoptThread(input) {
4552
4554
  messages: input.messages ?? []
4553
4555
  });
4554
4556
  writeThread(thread);
4555
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OIBSD5B6.js");
4557
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-QLKWW3O2.js");
4556
4558
  await ensureWorkspace2(repoPath);
4557
4559
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-5N2KTYIT.js");
4558
4560
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -6529,7 +6531,7 @@ function formatWorktreeDirective(thread, opts) {
6529
6531
  const slug = opts?.githubSlug ?? "<origin-owner/name>";
6530
6532
  const resolve2 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
6531
6533
  lines.push(
6532
- `- Prefer a draft PR first: \`gh pr create --draft -R ${slug}\` (update via \`gh pr edit -R ${slug}\`). Always pass \`-R\` \u2014 bare \`gh pr create\` may target upstream on dual-remote checkouts.${resolve2} Mark ready for review only when asked. If GitHub rejects the body as too long, retry with a short \`--body-file\` \u2014 do not paste a changelog or diff into \`--body\`.`
6534
+ `- Prefer a draft PR first: \`gh pr create --draft --assignee @me -R ${slug}\` (update via \`gh pr edit -R ${slug}\`). Always pass \`-R\` \u2014 bare \`gh pr create\` may target upstream on dual-remote checkouts.${resolve2} Assign to the GitHub-connected user (\`--assignee @me\`) unless the user named someone else. Mark ready for review only when asked. If GitHub rejects the body as too long, retry with a short \`--body-file\` \u2014 do not paste a changelog or diff into \`--body\`.`
6533
6535
  );
6534
6536
  }
6535
6537
  lines.push(
@@ -7058,7 +7060,7 @@ function formatScheduledPrompt(name, prompt) {
7058
7060
  ${prompt}`;
7059
7061
  }
7060
7062
  async function defaultDeps() {
7061
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-3IOISDFS.js");
7063
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-5ROSTGGH.js");
7062
7064
  const orch = getOrchestrator2();
7063
7065
  return {
7064
7066
  findThread: (id) => findThreadByRef(id),
@@ -9673,7 +9675,7 @@ var Orchestrator = class {
9673
9675
  this.enforceHistoryRetention();
9674
9676
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
9675
9677
  try {
9676
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OIBSD5B6.js");
9678
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-QLKWW3O2.js");
9677
9679
  await ensureWorkspace2(thread.repoPath);
9678
9680
  } catch {
9679
9681
  }
@@ -9727,7 +9729,7 @@ var Orchestrator = class {
9727
9729
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
9728
9730
  );
9729
9731
  }
9730
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-5VRZVGP3.js");
9732
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-PK3QETXO.js");
9731
9733
  const slug = thread.worktreePath.split("/").pop();
9732
9734
  const dest = thread.worktreePath;
9733
9735
  await withRepoGitLock(thread.repoPath, async () => {
@@ -9837,7 +9839,7 @@ async function startOrchestration(opts) {
9837
9839
  sourceRef: "default",
9838
9840
  ...createOpts
9839
9841
  }).catch(async () => {
9840
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-5VRZVGP3.js");
9842
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-PK3QETXO.js");
9841
9843
  const repo = await resolveRepoRoot2(repoPath);
9842
9844
  const def = await resolveDefaultBranch2(repo);
9843
9845
  return orch.createThread({
@@ -25,7 +25,7 @@ import {
25
25
  resolveQuotaFallbackAgent,
26
26
  stripBrightsyNdjsonNoise,
27
27
  toolDescription
28
- } from "./chunk-ISZERVDT.js";
28
+ } from "./chunk-QRWVKBGP.js";
29
29
  import {
30
30
  SLACK_REPLY_FORMATTING,
31
31
  addWorkspace,
@@ -48,7 +48,7 @@ import {
48
48
  stageAbsolutePathsAsAttachments,
49
49
  stageBuffersAsAttachments,
50
50
  syncWorkspacesFromThreads
51
- } from "./chunk-3P5OCI2X.js";
51
+ } from "./chunk-GFRC6JQN.js";
52
52
  import {
53
53
  addPrStackLayer,
54
54
  allocateTeamName,
@@ -97,7 +97,7 @@ import {
97
97
  worktreeDisplayLabelForGroup,
98
98
  worktreeNameFromPath,
99
99
  worktreeSlugForTicket
100
- } from "./chunk-CCD2QIFK.js";
100
+ } from "./chunk-E6C5NR46.js";
101
101
  import {
102
102
  ATTACHMENTS_DIR,
103
103
  DETACHED_JOBS_DIR,
@@ -442,9 +442,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
442
442
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
443
443
  );
444
444
  }
445
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-GQM653DP.js");
445
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-2N6KISDO.js");
446
446
  if (isGlobalThread2(thread)) {
447
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-AJ3E6LBX.js");
447
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-WQIICPT6.js");
448
448
  ensureGlobalCoordinatorCwd2(
449
449
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
450
450
  );
@@ -558,9 +558,11 @@ async function spawnAgentTurn(thread, input, onEvent) {
558
558
  if (assistantText && (parsed.data === assistantText || assistantText.endsWith(parsed.data))) {
559
559
  continue;
560
560
  }
561
- assistantText += parsed.data;
562
561
  }
563
562
  parts = applyAgentEvent(parts, parsed);
563
+ if (parsed.type === "stdout") {
564
+ assistantText = partsToAssistantText(parts);
565
+ }
564
566
  outbound.push(parsed);
565
567
  }
566
568
  });
@@ -635,9 +637,9 @@ function gitActionExpansion(action, base) {
635
637
  case "commit-push":
636
638
  return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`; this updates an existing PR when one is linked). Do not start a checks loop unless a goal was given.";
637
639
  case "create-draft":
638
- return "Commit, push, then create a draft PR with `gh pr create --draft -R <origin-owner/name>` (title/body from the change purpose). Update the existing PR instead if one is linked.";
640
+ return "Commit, push, then create a draft PR with `gh pr create --draft --assignee @me -R <origin-owner/name>` (title/body from the change purpose). Update the existing PR instead if one is linked. Use a different `--assignee` only if the user named someone else.";
639
641
  case "create-web":
640
- return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
642
+ return "Commit, push, then `gh pr create --web --assignee @me -R <origin-owner/name>`. Use a different `--assignee` only if the user named someone else.";
641
643
  case "resolve-conflicts":
642
644
  return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
643
645
  case "ready-for-review":
@@ -4221,7 +4223,7 @@ async function createThread(input, _onSetupLine) {
4221
4223
  return readThread(thread.id) ?? thread;
4222
4224
  }
4223
4225
  async function listLinearIssues(agent, repoPath) {
4224
- const { getAdapter: getAdapter2 } = await import("./agents-CPME6O2H.js");
4226
+ const { getAdapter: getAdapter2 } = await import("./agents-BOIIFMNG.js");
4225
4227
  await requireAgent(agent, { requireLinear: true });
4226
4228
  const adapter = getAdapter2(agent);
4227
4229
  if (!adapter.listLinearIssues) {
@@ -4694,7 +4696,7 @@ async function adoptThread(input) {
4694
4696
  messages: input.messages ?? []
4695
4697
  });
4696
4698
  writeThread(thread);
4697
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-WYC5TLC3.js");
4699
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-CFI7XVAE.js");
4698
4700
  await ensureWorkspace2(repoPath);
4699
4701
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-RXZPTCNH.js");
4700
4702
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -6684,7 +6686,7 @@ function formatWorktreeDirective(thread, opts) {
6684
6686
  const slug = opts?.githubSlug ?? "<origin-owner/name>";
6685
6687
  const resolve2 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
6686
6688
  lines.push(
6687
- `- Prefer a draft PR first: \`gh pr create --draft -R ${slug}\` (update via \`gh pr edit -R ${slug}\`). Always pass \`-R\` \u2014 bare \`gh pr create\` may target upstream on dual-remote checkouts.${resolve2} Mark ready for review only when asked. If GitHub rejects the body as too long, retry with a short \`--body-file\` \u2014 do not paste a changelog or diff into \`--body\`.`
6689
+ `- Prefer a draft PR first: \`gh pr create --draft --assignee @me -R ${slug}\` (update via \`gh pr edit -R ${slug}\`). Always pass \`-R\` \u2014 bare \`gh pr create\` may target upstream on dual-remote checkouts.${resolve2} Assign to the GitHub-connected user (\`--assignee @me\`) unless the user named someone else. Mark ready for review only when asked. If GitHub rejects the body as too long, retry with a short \`--body-file\` \u2014 do not paste a changelog or diff into \`--body\`.`
6688
6690
  );
6689
6691
  }
6690
6692
  lines.push(
@@ -7406,7 +7408,7 @@ function formatScheduledPrompt(name, prompt) {
7406
7408
  ${prompt}`;
7407
7409
  }
7408
7410
  async function defaultDeps() {
7409
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-YDPDMXUY.js");
7411
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-7YCQ7V5S.js");
7410
7412
  const orch = getOrchestrator2();
7411
7413
  return {
7412
7414
  findThread: (id) => findThreadByRef(id),
@@ -10021,7 +10023,7 @@ var Orchestrator = class {
10021
10023
  this.enforceHistoryRetention();
10022
10024
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
10023
10025
  try {
10024
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-WYC5TLC3.js");
10026
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-CFI7XVAE.js");
10025
10027
  await ensureWorkspace2(thread.repoPath);
10026
10028
  } catch {
10027
10029
  }
@@ -10075,7 +10077,7 @@ var Orchestrator = class {
10075
10077
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
10076
10078
  );
10077
10079
  }
10078
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-DGDM7LGV.js");
10080
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-4UAOZUJ4.js");
10079
10081
  const slug = thread.worktreePath.split("/").pop();
10080
10082
  const dest = thread.worktreePath;
10081
10083
  await withRepoGitLock(thread.repoPath, async () => {
@@ -10185,7 +10187,7 @@ async function startOrchestration(opts) {
10185
10187
  sourceRef: "default",
10186
10188
  ...createOpts
10187
10189
  }).catch(async () => {
10188
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-DGDM7LGV.js");
10190
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-4UAOZUJ4.js");
10189
10191
  const repo = await resolveRepoRoot2(repoPath);
10190
10192
  const def = await resolveDefaultBranch2(repo);
10191
10193
  return orch.createThread({