@sideboard-ai/core 0.1.169 → 0.1.171

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 (35) hide show
  1. package/dist/{abletime-IC2V7CNB.js → abletime-7VW4EGPT.js} +2 -2
  2. package/dist/{abletime-ESVTHTFH.js → abletime-PCLL36HW.js} +2 -2
  3. package/dist/{agents-V7CF33IK.js → agents-7UTRNLXQ.js} +4 -4
  4. package/dist/{agents-LNFEVU2F.js → agents-CTWLBPCV.js} +4 -4
  5. package/dist/{app-settings-VMOTQORT.js → app-settings-663VQWUV.js} +1 -1
  6. package/dist/{app-settings-LF3TS7XS.js → app-settings-74HBAAH7.js} +1 -1
  7. package/dist/{chunk-P2VCMIZU.js → chunk-234EKD2F.js} +2 -2
  8. package/dist/{chunk-DHPZW2EA.js → chunk-2RM6BZQ2.js} +2 -2
  9. package/dist/{chunk-QHCSYWEC.js → chunk-3F7AXVIL.js} +30 -10
  10. package/dist/{chunk-BLSTB2AD.js → chunk-6X6KMUI2.js} +29 -10
  11. package/dist/{chunk-DKLGWRWC.js → chunk-AQPVBVJE.js} +1 -1
  12. package/dist/{chunk-NB7TEKCF.js → chunk-CMJ2FBBV.js} +1 -1
  13. package/dist/{chunk-7IUO67CW.js → chunk-J7LQVLFQ.js} +15 -8
  14. package/dist/{chunk-YMF5WCIA.js → chunk-OKZFTOM2.js} +15 -8
  15. package/dist/{chunk-Y7DJA3UW.js → chunk-PXNOT6NV.js} +1 -1
  16. package/dist/{chunk-ISMGVHP4.js → chunk-QYJS7LYE.js} +181 -207
  17. package/dist/{chunk-3C4B52TS.js → chunk-QYZYDO3F.js} +1 -1
  18. package/dist/{chunk-M3OIQZRS.js → chunk-ZTVBIBLB.js} +177 -138
  19. package/dist/{coordinator-prompt-JTDCEU74.js → coordinator-prompt-7CTI6HRH.js} +3 -3
  20. package/dist/{coordinator-prompt-RRUU2OYO.js → coordinator-prompt-PM6MPYYB.js} +3 -3
  21. package/dist/{global-workspace-ZF6EJAM3.js → global-workspace-CMYSFRCM.js} +3 -3
  22. package/dist/{global-workspace-4SI3CRRT.js → global-workspace-CRJ6ZVIY.js} +3 -3
  23. package/dist/index.cjs +205 -203
  24. package/dist/index.d.cts +49 -21
  25. package/dist/index.d.ts +49 -21
  26. package/dist/index.js +16 -14
  27. package/dist/mcp/run-stdio.cjs +197 -132
  28. package/dist/mcp/run-stdio.js +8 -8
  29. package/dist/{orchestrator-67BPEJZL.js → orchestrator-RW4IVITI.js} +5 -5
  30. package/dist/{orchestrator-FCH2PFPX.js → orchestrator-VPT4SXXD.js} +5 -5
  31. package/dist/{workspaces-NOC2MWQV.js → workspaces-L73MCDFA.js} +3 -3
  32. package/dist/{workspaces-A7C3WA54.js → workspaces-UYSD2STS.js} +3 -3
  33. package/dist/{worktree-GXO2VDQF.js → worktree-SQD3DBYC.js} +2 -2
  34. package/dist/{worktree-PODE23PD.js → worktree-WVEDT3FM.js} +2 -2
  35. package/package.json +1 -1
@@ -24,7 +24,7 @@ import {
24
24
  stripBrightsyNdjsonNoise,
25
25
  sumUsageList,
26
26
  toolDescription
27
- } from "./chunk-QHCSYWEC.js";
27
+ } from "./chunk-3F7AXVIL.js";
28
28
  import {
29
29
  SLACK_REPLY_FORMATTING,
30
30
  addWorkspace,
@@ -47,7 +47,7 @@ import {
47
47
  stageAbsolutePathsAsAttachments,
48
48
  stageBuffersAsAttachments,
49
49
  syncWorkspacesFromThreads
50
- } from "./chunk-DHPZW2EA.js";
50
+ } from "./chunk-2RM6BZQ2.js";
51
51
  import {
52
52
  addPrStackLayer,
53
53
  allocateTeamName,
@@ -97,7 +97,7 @@ import {
97
97
  worktreeDisplayLabelForGroup,
98
98
  worktreeNameFromPath,
99
99
  worktreeSlugForTicket
100
- } from "./chunk-3C4B52TS.js";
100
+ } from "./chunk-QYZYDO3F.js";
101
101
  import {
102
102
  ATTACHMENTS_DIR,
103
103
  DETACHED_JOBS_DIR,
@@ -148,7 +148,7 @@ import {
148
148
  saveAppSettings,
149
149
  updateAdvancedSettings,
150
150
  writeSecureJson
151
- } from "./chunk-7IUO67CW.js";
151
+ } from "./chunk-J7LQVLFQ.js";
152
152
  import {
153
153
  stripNestedElectronEnv
154
154
  } from "./chunk-4TR3HZFT.js";
@@ -466,7 +466,7 @@ async function continueSourceThread(threadId, prompt) {
466
466
  await continueOnReply(threadId, prompt);
467
467
  return;
468
468
  }
469
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-FCH2PFPX.js");
469
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-VPT4SXXD.js");
470
470
  await getOrchestrator2().send(threadId, prompt);
471
471
  } catch {
472
472
  }
@@ -748,9 +748,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
748
748
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
749
749
  );
750
750
  }
751
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-ZF6EJAM3.js");
751
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-CMYSFRCM.js");
752
752
  if (isGlobalThread2(thread)) {
753
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-JTDCEU74.js");
753
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-7CTI6HRH.js");
754
754
  ensureGlobalCoordinatorCwd2(
755
755
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
756
756
  );
@@ -961,6 +961,51 @@ function agentGitPrompt(action, opts) {
961
961
  return "Merge PR.";
962
962
  }
963
963
  }
964
+ var RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
965
+ function gitActionExpansion(action, base) {
966
+ switch (action) {
967
+ case "commit-push":
968
+ 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.";
969
+ case "create-draft":
970
+ 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.";
971
+ case "create-web":
972
+ return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
973
+ case "resolve-conflicts":
974
+ return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
975
+ case "merge":
976
+ return "This phrase is the explicit ask to merge this thread's open pull request on GitHub. If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.";
977
+ }
978
+ }
979
+ function expandCanonicalGitRequest(prompt) {
980
+ const trimmed = prompt.trim();
981
+ let action = null;
982
+ let base = null;
983
+ for (const candidate of AGENT_GIT_ACTIONS) {
984
+ if (candidate === "resolve-conflicts") continue;
985
+ if (agentGitPrompt(candidate) === trimmed) {
986
+ action = candidate;
987
+ break;
988
+ }
989
+ }
990
+ if (!action) {
991
+ const m = RESOLVE_CONFLICTS_RE.exec(trimmed);
992
+ if (m) {
993
+ action = "resolve-conflicts";
994
+ base = m[1] ?? null;
995
+ }
996
+ }
997
+ let expansion = action ? gitActionExpansion(action, base) : null;
998
+ if (!expansion && trimmed === "Address review comments.") {
999
+ expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
1000
+ } else if (!expansion && FIX_CI_RE.test(trimmed)) {
1001
+ expansion = "Investigate that failing check (`gh pr checks`, `gh run view --log-failed`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given.";
1002
+ }
1003
+ if (!expansion) return prompt;
1004
+ return `${trimmed}
1005
+
1006
+ (Sideboard git request \u2014 do not ask for clarification: ${expansion})`;
1007
+ }
1008
+ var FIX_CI_RE = /^Fix CI: .+\.$/;
964
1009
 
965
1010
  // src/git/pr-merge-archive.ts
966
1011
  function normalizePrState(state) {
@@ -1222,47 +1267,84 @@ function formatToolPart(t, detail) {
1222
1267
  }
1223
1268
  function formatMessagesAsTranscript(messages, opts) {
1224
1269
  const tools = opts?.tools ?? "full";
1225
- const blocks = [];
1226
- for (const m of messages) {
1227
- if (m.role === "summary") {
1228
- blocks.push(`## Prior summary
1229
- ${m.text}`);
1230
- continue;
1231
- }
1232
- if (m.role === "user") {
1233
- blocks.push(`### User
1270
+ const thinking = opts?.thinking ?? true;
1271
+ return messages.map((m) => formatMessageBlock(m, { tools, thinking })).join("\n\n");
1272
+ }
1273
+ function formatMessageBlock(m, opts) {
1274
+ if (m.role === "summary") return `## Prior summary
1275
+ ${m.text}`;
1276
+ if (m.role === "user") return `### User
1277
+ ${m.text}`;
1278
+ const bits = [];
1279
+ if (m.text?.trim()) {
1280
+ bits.push(`### Agent
1234
1281
  ${m.text}`);
1235
- continue;
1236
- }
1237
- const bits = [];
1238
- if (m.text?.trim()) {
1239
- bits.push(`### Agent
1240
- ${m.text}`);
1241
- } else {
1242
- bits.push("### Agent");
1243
- }
1244
- const thinking = (m.parts ?? []).filter((p) => p.type === "thinking");
1245
- for (const th of thinking) {
1282
+ } else {
1283
+ bits.push("### Agent");
1284
+ }
1285
+ if (opts.thinking) {
1286
+ for (const th of m.parts ?? []) {
1246
1287
  if (th.type !== "thinking" || !th.text.trim()) continue;
1247
1288
  bits.push("Thinking:");
1248
1289
  bits.push(th.text);
1249
1290
  }
1250
- const toolParts = (m.parts ?? []).filter(
1251
- (p) => p.type === "tool"
1252
- );
1253
- if (tools !== "none" && toolParts.length > 0) {
1254
- if (tools === "summary") bits.push("Tools:");
1255
- for (const t of toolParts) {
1256
- bits.push(formatToolPart(t, tools));
1257
- }
1291
+ }
1292
+ const toolParts = (m.parts ?? []).filter(
1293
+ (p) => p.type === "tool"
1294
+ );
1295
+ if (opts.tools !== "none" && toolParts.length > 0) {
1296
+ if (opts.tools === "summary") bits.push("Tools:");
1297
+ for (const t of toolParts) {
1298
+ bits.push(formatToolPart(t, opts.tools));
1258
1299
  }
1259
- blocks.push(bits.join("\n"));
1260
1300
  }
1261
- return blocks.join("\n\n");
1301
+ return bits.join("\n");
1262
1302
  }
1303
+ var SEED_MAX_CHARS = 6e4;
1304
+ var SEED_FULL_TOOL_MESSAGES = 6;
1263
1305
  function buildSessionSeed(messages, opts) {
1264
1306
  if (messages.length === 0) return null;
1265
- const body = formatMessagesAsTranscript(messages, { tools: opts?.tools ?? "full" });
1307
+ const tools = opts?.tools ?? "full";
1308
+ const fullCount = opts?.fullToolMessages ?? SEED_FULL_TOOL_MESSAGES;
1309
+ const maxChars = opts?.maxChars ?? SEED_MAX_CHARS;
1310
+ const olderTools = tools === "none" ? "none" : "summary";
1311
+ const fullFrom = Math.max(0, messages.length - fullCount);
1312
+ const blocks = messages.map(
1313
+ (m, i) => formatMessageBlock(m, {
1314
+ tools: i >= fullFrom ? tools : olderTools,
1315
+ thinking: false
1316
+ })
1317
+ );
1318
+ const keep = new Array(blocks.length).fill(false);
1319
+ let used = 0;
1320
+ for (let i = 0; i < blocks.length; i++) {
1321
+ if (messages[i].role === "summary") {
1322
+ keep[i] = true;
1323
+ used += blocks[i].length + 2;
1324
+ }
1325
+ }
1326
+ for (let i = blocks.length - 1; i >= 0; i--) {
1327
+ if (keep[i]) continue;
1328
+ const next = used + blocks[i].length + 2;
1329
+ if (next > maxChars && used > 0) break;
1330
+ keep[i] = true;
1331
+ used = next;
1332
+ }
1333
+ const dropped = keep.filter((k) => !k).length;
1334
+ const kept = [];
1335
+ let markerPlaced = false;
1336
+ for (let i = 0; i < blocks.length; i++) {
1337
+ if (!keep[i]) continue;
1338
+ if (dropped > 0 && !markerPlaced && messages[i].role !== "summary") {
1339
+ kept.push(`_(${dropped} older message${dropped === 1 ? "" : "s"} omitted for length)_`);
1340
+ markerPlaced = true;
1341
+ }
1342
+ kept.push(blocks[i]);
1343
+ }
1344
+ if (dropped > 0 && !markerPlaced) {
1345
+ kept.push(`_(${dropped} older message${dropped === 1 ? "" : "s"} omitted for length)_`);
1346
+ }
1347
+ const body = kept.join("\n\n");
1266
1348
  if (!body.trim()) return null;
1267
1349
  return [
1268
1350
  "Sideboard conversation context (restored after compaction or a new session):",
@@ -1321,7 +1403,7 @@ function messagesSinceLastBrightsyContextSummary(messages) {
1321
1403
  function buildBrightsySessionSeed(messages) {
1322
1404
  const match = findLastBrightsyContextSummary(messages);
1323
1405
  const tail = match ? messages.slice(match.index + 1) : messages;
1324
- const body = formatMessagesAsTranscript(tail, { tools: "none" });
1406
+ const body = formatMessagesAsTranscript(tail, { tools: "none", thinking: false });
1325
1407
  if (!match && !body.trim()) return null;
1326
1408
  const blocks = [
1327
1409
  "Sideboard conversation context (restored after compaction or a new session):",
@@ -3488,7 +3570,7 @@ async function createThread(input, _onSetupLine) {
3488
3570
  });
3489
3571
  await requireAgent(resolved.agent);
3490
3572
  if (input.cowboy) {
3491
- const { cowboyModeEnabled } = await import("./app-settings-VMOTQORT.js");
3573
+ const { cowboyModeEnabled } = await import("./app-settings-663VQWUV.js");
3492
3574
  if (!cowboyModeEnabled()) {
3493
3575
  throw new Error(
3494
3576
  "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
@@ -3546,7 +3628,7 @@ async function createThread(input, _onSetupLine) {
3546
3628
  let sourceIsFork = false;
3547
3629
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
3548
3630
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
3549
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-IC2V7CNB.js");
3631
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-7VW4EGPT.js");
3550
3632
  const task = await ensureAbleTimeTask({
3551
3633
  title: title?.trim() || "Untitled work",
3552
3634
  description: input.prompt?.trim() || void 0
@@ -3644,7 +3726,7 @@ async function createThread(input, _onSetupLine) {
3644
3726
  return readThread(thread.id) ?? thread;
3645
3727
  }
3646
3728
  async function listLinearIssues(agent, repoPath) {
3647
- const { getAdapter: getAdapter2 } = await import("./agents-V7CF33IK.js");
3729
+ const { getAdapter: getAdapter2 } = await import("./agents-7UTRNLXQ.js");
3648
3730
  await requireAgent(agent, { requireLinear: true });
3649
3731
  const adapter = getAdapter2(agent);
3650
3732
  if (!adapter.listLinearIssues) {
@@ -4066,7 +4148,7 @@ async function adoptThread(input) {
4066
4148
  messages: input.messages ?? []
4067
4149
  });
4068
4150
  writeThread(thread);
4069
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-A7C3WA54.js");
4151
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-UYSD2STS.js");
4070
4152
  await ensureWorkspace2(repoPath);
4071
4153
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
4072
4154
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -5751,7 +5833,7 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
5751
5833
  }
5752
5834
 
5753
5835
  // src/agents/instructions.ts
5754
- import { existsSync as existsSync16, readFileSync as readFileSync12, statSync as statSync4 } from "fs";
5836
+ import { existsSync as existsSync16 } from "fs";
5755
5837
  import { join as join15 } from "path";
5756
5838
 
5757
5839
  // src/skills/detached-job-path.ts
@@ -5841,67 +5923,38 @@ function formatWorktreeDirective(thread, opts) {
5841
5923
  lines.push(
5842
5924
  "- Always use this worktree's `origin` remote (`git remote get-url origin` from this cwd). Never push to or open PRs against `upstream` (template remotes)."
5843
5925
  );
5844
- lines.push(
5845
- "- Push with `git push -u origin HEAD` (or the current branch name). Do not `git push upstream`."
5846
- );
5847
- lines.push("");
5848
5926
  lines.push(formatGitAuthModeDirective(opts?.gitAuthMode ?? "auto"));
5849
5927
  lines.push(
5850
- "- Derive the PR title and body from what the changes actually do and why \u2014 inspect the diff/commits and the user request. Do not use the soccer-team worktree nickname or placeholder branch as the PR title."
5928
+ "- PR title/body and commit messages state what the change does and why (inspect the diff/commits and the user request) \u2014 never the worktree nickname or placeholder branch. Concise imperative title (Conventional Commits when it fits: feat:/fix:/chore:/docs:); body = intent, key changes, test notes."
5851
5929
  );
5852
5930
  lines.push(
5853
- "- Prefer a concise imperative title (Conventional Commits style when it fits: feat:/fix:/chore:/docs:). Body should summarize intent, key changes, and test notes."
5854
- );
5855
- lines.push(
5856
- "- Commit with messages that state the purpose of the change (same standard as the PR). Stay on this thread branch. Never push directly to main/master or merge locally into the main checkout. Do not merge the PR unless this turn is a Merge PR request or the user explicitly asked. When merging, use GitHub from this worktree (`gh pr merge` / `gh stack merge`)."
5931
+ "- Stay on this thread branch. Never push to main/master or merge locally into the main checkout. Merge the PR only when this turn is a Merge PR request or the user explicitly asked \u2014 via GitHub from this worktree (`gh pr merge` / `gh stack merge`)."
5857
5932
  );
5858
5933
  if (thread.prUrl) {
5859
5934
  lines.push(
5860
5935
  `- A PR already exists (${thread.prUrl}). Update it (push + edit title/body if the purpose drifted) instead of opening a duplicate.`
5861
5936
  );
5862
- } else if (opts?.githubSlug) {
5863
- lines.push(
5864
- `- Prefer a draft PR first: \`gh pr create --draft -R ${opts.githubSlug}\` (or update via \`gh pr edit -R ${opts.githubSlug}\`) once the change set is coherent. Always pass \`-R ${opts.githubSlug}\` (this worktree's origin). Bare \`gh pr create\` may target upstream instead of origin on dual-remote checkouts. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short \`--body-file\` (limit 65,536 characters) \u2014 do not paste a changelog or diff into \`--body\`.`
5865
- );
5866
5937
  } else {
5938
+ const slug = opts?.githubSlug ?? "<origin-owner/name>";
5939
+ const resolve = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
5867
5940
  lines.push(
5868
- "- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short `--body-file` (limit 65,536 characters) \u2014 do not paste a changelog or diff into `--body`."
5941
+ `- 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.${resolve} 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\`.`
5869
5942
  );
5870
5943
  }
5871
- lines.push("");
5872
5944
  lines.push(
5873
- "Short git requests from the Sideboard UI are complete instructions \u2014 expand them using the rules above without asking for clarification:"
5874
- );
5875
- lines.push(
5876
- '- "Commit and push." \u2192 commit any uncommitted work with a purpose-stating message, then push to origin (updates an existing PR if one is linked). Do not start a checks loop unless they gave a goal.'
5877
- );
5878
- lines.push(
5879
- '- "Commit, push, and open a draft PR." \u2192 commit, push, then create a draft PR with `gh pr create --draft -R \u2026` (title/body from the change purpose).'
5880
- );
5881
- lines.push(
5882
- '- "Commit, push, and open a PR in the browser." \u2192 commit, push, then `gh pr create --web -R \u2026`.'
5883
- );
5884
- lines.push(
5885
- '- "Fix CI: <name>." \u2192 investigate that failing check, fix it, commit, and push. Loop only if they gave a goal to keep going until it passes.'
5886
- );
5887
- lines.push(
5888
- '- "Merge the remote branch (<base>) into your branch and resolve conflicts. Then, commit and push your changes." \u2192 fetch the PR base, merge it into this branch, resolve conflicts carefully, commit, and push until the PR is mergeable.'
5889
- );
5890
- lines.push(
5891
- '- "Address review comments." \u2192 read PR review feedback, make the requested changes, commit, and push.'
5892
- );
5893
- lines.push(
5894
- '- "Merge PR." \u2192 merge this thread\'s open pull request on GitHub (this phrase is the explicit ask). If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.'
5945
+ '- Sideboard git buttons send short phrases ("Commit and push.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
5895
5946
  );
5896
5947
  lines.push("");
5897
- lines.push(formatPrGateDirective());
5898
- lines.push("");
5899
- lines.push(formatProcessGuideDirective());
5948
+ lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
5900
5949
  return lines.join("\n");
5901
5950
  }
5902
5951
  function formatWorktreeReminder() {
5903
5952
  return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push.";
5904
5953
  }
5954
+ var PR_GOAL_RE = /greptile|\bci\b.*\b(green|pass)|checks?\s+(pass|green)|until\s+.*\b(pass|green|merge|clean)|\bfix ci\b|watch[- ]fix[- ]push/i;
5955
+ function mentionsPrGoal(prompt) {
5956
+ return PR_GOAL_RE.test(prompt);
5957
+ }
5905
5958
  var GITHUB_TICKET_REF = /^(?:#?\d+|gh-\d+)$/i;
5906
5959
  var KEYED_TICKET_REF = /^(?:[A-Z][A-Z0-9]{0,9}-\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
5907
5960
  function issueTicketFromThread(thread, preferredSource = "github") {
@@ -5992,29 +6045,27 @@ function formatPrGateDirective() {
5992
6045
  "- Greptile 5/5: wait for the greptile check; read the latest `N/5` from the PR body or Greptile\u2019s most recently *updated* issue comment; also fetch unresolved review comments / the \u201CPrompt to fix all with AI\u201D block. Done = **5/5 and zero unresolved Greptile comments**. If Greptile is idle, comment `@greptile review`. Cap about 5 iterations, then report leftovers. Do not merge unless asked."
5993
6046
  ].join("\n");
5994
6047
  }
5995
- function formatProcessGuideDirective() {
6048
+ function formatProcessGuideDirective(opts) {
6049
+ const worktree = opts?.worktreePath?.trim();
6050
+ const hasGraphSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/graph-engineering/SKILL.md"));
6051
+ const hasReviewSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/review/SKILL.md"));
5996
6052
  return [
5997
6053
  "Process guides (recurring work only):",
5998
- "- Long jobs (pack, test, deploy, anything that may run more than ~30s): Sideboard always provides `/long-running`. Detach and wait; `stop_job` if hanging or wrong. Do not ask the human to poll.",
5999
- "- If `.claude/skills/graph-engineering/SKILL.md` exists, follow it (`/graph-engineering`) for migrations, ports, batch fixes, and other fan-out. Judge first; state on disk; grow the rulebook; do not patch around it.",
6000
- "- If this same shape of work will happen again, write `.claude/skills/<kebab-name>/SKILL.md` in this worktree (Claude Code project skill). Sideboard `/name`, Claude Code, and `attach` all load that path. Do not leave the method only in chat.",
6001
- "- Merge-readiness notes: if `.claude/skills/review/SKILL.md` already exists, edit it. Otherwise write them to `.context/review.md` (copied from `.sideboard/review.md` when that file exists). Do not create a review skill.",
6002
- "- Do not write new skills under `.sideboard/skills/` (that folder only \u2014 other `.sideboard/` files such as settings.toml are fine). Point Codex/OpenCode at the Claude skill from `AGENTS.md`. Optional: symlink `.cursor/skills/<name>` to the Claude skill.",
6054
+ hasGraphSkill ? "- Migrations, ports, batch fixes, and other fan-out: follow `.claude/skills/graph-engineering/SKILL.md` (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch around it." : null,
6055
+ "- If this same shape of work will happen again, write `.claude/skills/<kebab-name>/SKILL.md` in this worktree (Claude Code project skill; Sideboard `/name`, Claude Code, and `attach` all load it). Not under `.sideboard/skills/`. Point Codex/OpenCode at it from `AGENTS.md`.",
6056
+ hasReviewSkill ? "- Merge-readiness notes go in `.claude/skills/review/SKILL.md` (edit it; do not create another review skill)." : "- Merge-readiness notes go in `.context/review.md` (copied from `.sideboard/review.md` when that file exists). Do not create a review skill.",
6003
6057
  "- Skip a guide for a one-off. If a matching skill exists, follow it. Same miss twice \u2192 edit the skill, do not patch around it."
6004
- ].join("\n");
6058
+ ].filter(Boolean).join("\n");
6005
6059
  }
6006
6060
  function formatLongRunningDirective(opts) {
6007
6061
  const invoke = formatDetachedJobInvoke(opts?.scriptPath);
6008
6062
  return [
6009
- "Long-running jobs (mandatory when a command may run more than ~30s):",
6010
- "A Sideboard worktree turn SIGTERMs the agent shell (and its process group) when the user sends another message or the turn is interrupted. `block_until_ms: 0` is not enough. Do not ask the human to poll.",
6011
- `Helper (same tool as \`scripts/detached-job.cjs\` when that file exists in the worktree): \`${invoke}\``,
6012
- `- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree). If JSON says already-running, do not start again.`,
6013
- "- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
6014
- `- Loop Sideboard MCP \`wait_for_job\` with the same id (returns in ~45s). stillRunning \u2192 present the same id with \`content=delta\` only \u2192 wait_for_job again. Shell fallback: \`${invoke} wait <id>\`. Do not resend the full log or HTML.`,
6015
- `- If it is hanging, producing no useful output, or doing the wrong thing: MCP \`stop_job\` (same id, optional reason) or \`${invoke} stop <id>\`. Do not loop forever. Do not stop a pack/test/deploy that is clearly making progress.`,
6016
- "- Do not end the turn with \u201CI\u2019ll let you know when it\u2019s done.\u201D Stay in the loop until stillRunning is false (or you stopped it).",
6017
- "- ok \u2192 finish the task. failed / stopped \u2192 read the log, fix or narrow the command, start once.",
6063
+ "Long-running jobs (mandatory when a command may run more than ~30s \u2014 pack, test, deploy, `gh pr checks --watch`):",
6064
+ "A Sideboard worktree turn SIGTERMs the agent shell (and its process group) when the user sends another message or the turn is interrupted; `block_until_ms: 0` is not enough. Detach instead, and never ask the human to poll.",
6065
+ `- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree; same tool as \`scripts/detached-job.cjs\` when the worktree has it). If JSON says already-running, do not start again.`,
6066
+ "- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running`, then loop Sideboard MCP `wait_for_job` (returns in ~45s). stillRunning \u2192 present the same id with `content=delta` only \u2192 wait again. Shell fallback: the same helper with `wait <id>`.",
6067
+ "- Hanging, no useful output, or the wrong thing \u2192 `stop_job` (or the helper with `stop <id>`). Do not stop a pack/test/deploy that is clearly making progress.",
6068
+ "- Stay in the loop until stillRunning is false (or you stopped it). ok \u2192 finish the task. failed / stopped \u2192 read the log, fix or narrow the command, start once.",
6018
6069
  "State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
6019
6070
  ].join("\n");
6020
6071
  }
@@ -6024,97 +6075,16 @@ function formatLongRunningReminder(opts) {
6024
6075
  }
6025
6076
  function formatArtifactDirective() {
6026
6077
  return [
6027
- "Sideboard side column (desktop UI):",
6028
- "claude.ai\u2019s \u201CArtifact\u201D tool does NOT exist in Claude Code. That is expected.",
6029
- "Do not unprompted-duplicate a payload. Chat markdown (including tables) already renders in the transcript \u2014 do not also call present_schema with those same rows just to display them. If the user asks for an editable / interactive table, call present_schema even if markdown already showed the data. Do not also call present_artifact for a document you already fenced in chat.",
6030
- "Documents (HTML/SVG/markdown):",
6031
- "1) Emit a fenced code block tagged `html` (preferred), `svg`, or `markdown` with the FULL document \u2014 Sideboard opens a side column. Example:",
6032
- "```html",
6033
- "<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
6034
- "```",
6035
- "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown|react|log), and content \u2014 not both a fence and this tool for the same body.",
6036
- " type=log is append-only: same `artifact_id`, `content` = new lines only (plus optional status/phase). Do not resend the full log or wrap it in HTML.",
6037
- "CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
6038
- "3) Call Sideboard MCP `present_schema` when the user needs to filter, edit, publish, or persist rows \u2014 including after you already showed a markdown table, if they then ask for an editable table. If they only need to read the data, a markdown table is enough. When you do call it, pass title, mode (table|form), and either:",
6039
- " - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
6040
- " - datasource=inline + resource: { id, title, schema, schemaUi } and optional records/record.",
6041
- "Files / media browser (CMS file manager column):",
6042
- "4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
6043
- " Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
6044
- "Multiple-choice questions:",
6045
- "5) Call Sideboard MCP `ask_user` only when work is blocked on choosing among a few concrete options (approach forks, which API, auth vs cookies). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. If you are asking a real multiple-choice, use ask_user rather than chat bullets so Sideboard shows the composer picker.",
6046
- "Do not call ask_user for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat. If one option is the obvious default, proceed without asking.",
6047
- "Never say artifacts, CMS UI, or the Files column are unavailable. present_schema is for interactive list/edit/publish (use it when they ask to edit, even if chat already had a markdown table); present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
6078
+ "Sideboard side column (desktop UI) \u2014 Sideboard MCP tools present_artifact, present_schema, present_files, ask_user (see their descriptions). claude.ai\u2019s \u201CArtifact\u201D tool does not exist here; never say artifacts, the CMS UI, or the Files column are unavailable.",
6079
+ "- Standalone documents: a fenced block tagged `html` (preferred), `svg`, or `markdown` containing the FULL document opens the side column by itself. Use that or present_artifact \u2014 never both for the same body.",
6080
+ "- present_artifact type=log appends: same artifact_id, content = new lines only (plus status/phase). Do not resend the full log or wrap it in HTML.",
6081
+ "- Data: a markdown table is enough to read. Call present_schema only when the user needs to filter/edit/publish/persist rows \u2014 including when they ask for an editable table after you already showed markdown. Never re-present rows you already wrote just to display them.",
6082
+ "- ask_user only when work is blocked on a few concrete options (approach fork, which API, auth vs cookies): first a short chat message explaining the decision and each option, then the call (description on every option), then stop and wait. Not for greetings, check-ins, or an invented menu of next tasks \u2014 reply in chat. If one option is the obvious default, proceed."
6048
6083
  ].join("\n");
6049
6084
  }
6050
6085
  function formatUiReminder() {
6051
6086
  return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
6052
6087
  }
6053
- var FILES_BY_AGENT = {
6054
- claude: [
6055
- "CLAUDE.md",
6056
- ".claude/CLAUDE.md",
6057
- "CLAUDE.local.md",
6058
- "AGENTS.md",
6059
- "AGENT.md"
6060
- ],
6061
- codex: ["AGENTS.md", "AGENT.md", ".codex/AGENTS.md", "CLAUDE.md"],
6062
- opencode: ["AGENTS.md", "AGENT.md", "OPENCODE.md", "CLAUDE.md"],
6063
- brightsy: ["AGENTS.md", "AGENT.md", "CLAUDE.md"],
6064
- cursor: ["AGENTS.md", "AGENT.md", ".cursor/rules", "CLAUDE.md"]
6065
- };
6066
- var MAX_CHARS_PER_FILE = 48e3;
6067
- function loadAgentInstructions(worktreePath, agent) {
6068
- const candidates = FILES_BY_AGENT[agent] ?? FILES_BY_AGENT.claude;
6069
- const seenPaths = /* @__PURE__ */ new Set();
6070
- const seenBodies = /* @__PURE__ */ new Set();
6071
- const out = [];
6072
- for (const rel of candidates) {
6073
- if (seenPaths.has(rel)) continue;
6074
- const abs = join15(worktreePath, rel);
6075
- if (!existsSync16(abs)) continue;
6076
- try {
6077
- if (!statSync4(abs).isFile()) continue;
6078
- let content = readFileSync12(abs, "utf8");
6079
- if (!content.trim()) continue;
6080
- if (content.length > MAX_CHARS_PER_FILE) {
6081
- content = `${content.slice(0, MAX_CHARS_PER_FILE)}
6082
-
6083
- \u2026(truncated)`;
6084
- }
6085
- const body = content.trim().replace(/\r\n/g, "\n");
6086
- if (seenBodies.has(body)) continue;
6087
- seenPaths.add(rel);
6088
- seenBodies.add(body);
6089
- out.push({ relativePath: rel, content });
6090
- } catch {
6091
- }
6092
- }
6093
- return out;
6094
- }
6095
- function formatAgentInstructions(files) {
6096
- if (files.length === 0) return null;
6097
- const parts = [
6098
- "Project agent instructions (from the worktree \u2014 follow these):",
6099
- ""
6100
- ];
6101
- for (const f of files) {
6102
- parts.push(`## ${f.relativePath}`);
6103
- parts.push("");
6104
- parts.push(f.content.trim());
6105
- parts.push("");
6106
- parts.push("---");
6107
- parts.push("");
6108
- }
6109
- return parts.join("\n").trimEnd();
6110
- }
6111
- function withAgentInstructions(prompt, files) {
6112
- const prefix = formatAgentInstructions(files);
6113
- if (!prefix) return prompt;
6114
- return `${prefix}
6115
-
6116
- ${prompt}`;
6117
- }
6118
6088
 
6119
6089
  // src/integrations/optional-services.ts
6120
6090
  var OPTIONAL_SERVICE_IDS = ["vercel", "supabase", "posthog", "sentry"];
@@ -6413,7 +6383,7 @@ async function syncThreadBranchFromGit(threadId) {
6413
6383
 
6414
6384
  // src/store/schedules.ts
6415
6385
  import { randomUUID as randomUUID4 } from "crypto";
6416
- import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
6386
+ import { existsSync as existsSync17, readFileSync as readFileSync12 } from "fs";
6417
6387
  import { join as join16 } from "path";
6418
6388
  import { Cron } from "croner";
6419
6389
  var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
@@ -6532,7 +6502,7 @@ function readAll() {
6532
6502
  const path = schedulesPath();
6533
6503
  if (!existsSync17(path)) return [];
6534
6504
  try {
6535
- const parsed = JSON.parse(readFileSync13(path, "utf8"));
6505
+ const parsed = JSON.parse(readFileSync12(path, "utf8"));
6536
6506
  if (!Array.isArray(parsed)) return [];
6537
6507
  return parsed.map((row) => {
6538
6508
  try {
@@ -6658,7 +6628,7 @@ function formatScheduledPrompt(name, prompt) {
6658
6628
  ${prompt}`;
6659
6629
  }
6660
6630
  async function defaultDeps() {
6661
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-FCH2PFPX.js");
6631
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VPT4SXXD.js");
6662
6632
  const orch = getOrchestrator2();
6663
6633
  return {
6664
6634
  findThread: (id) => findThreadByRef(id),
@@ -6920,7 +6890,7 @@ var Orchestrator = class {
6920
6890
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
6921
6891
  });
6922
6892
  }
6923
- const { autoCleanupOrphansEnabled } = await import("./app-settings-VMOTQORT.js");
6893
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-663VQWUV.js");
6924
6894
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
6925
6895
  await cleanupOrphanWorktrees({ repoPaths });
6926
6896
  }
@@ -7199,7 +7169,7 @@ var Orchestrator = class {
7199
7169
  }
7200
7170
  await setup;
7201
7171
  if (skipSetup) return;
7202
- const { autoRunAfterSetupEnabled } = await import("./app-settings-VMOTQORT.js");
7172
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-663VQWUV.js");
7203
7173
  if (autoRunAfterSetupEnabled()) {
7204
7174
  try {
7205
7175
  await this.startDev(threadId);
@@ -7482,17 +7452,21 @@ var Orchestrator = class {
7482
7452
  const slackReplyContext = formatSlackRepliesForTurn(
7483
7453
  pendingSlackExternalReplies(thread.messages)
7484
7454
  );
7485
- const agentPrompt = [
7486
- thread.planMode ? PLAN_MODE_INSTRUCTION : null,
7487
- orchestrationReminder,
7455
+ const turnReminders = [
7488
7456
  worktreeReminder,
7489
7457
  optionalServicesReminder,
7490
7458
  issueToolsReminder,
7491
7459
  viewerContextReminder,
7492
7460
  artifactReminder,
7493
- longRunningReminder,
7461
+ longRunningReminder
7462
+ ].filter(Boolean).join("\n\n") || void 0;
7463
+ const prGateDirective = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && mentionsPrGoal(expandedPrompt) ? formatPrGateDirective() : null;
7464
+ const agentPrompt = [
7465
+ thread.planMode ? PLAN_MODE_INSTRUCTION : null,
7466
+ orchestrationReminder,
7467
+ prGateDirective,
7494
7468
  slackReplyContext,
7495
- expandedPrompt
7469
+ expandCanonicalGitRequest(expandedPrompt)
7496
7470
  ].filter(Boolean).join("\n\n");
7497
7471
  if (thread.attachments.length > 0) {
7498
7472
  updateThread(threadId, { attachments: [] });
@@ -7510,7 +7484,7 @@ var Orchestrator = class {
7510
7484
  }
7511
7485
  const isBrightsy = fresh.agent === "brightsy";
7512
7486
  const isOrchestration = isOrchestratorThread(fresh);
7513
- const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-VMOTQORT.js");
7487
+ const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-663VQWUV.js");
7514
7488
  const gitAuthMode = getGithubGitAuthMode();
7515
7489
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
7516
7490
  githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
@@ -7582,7 +7556,7 @@ var Orchestrator = class {
7582
7556
  const stderrTail = [];
7583
7557
  const handle = await spawnAgentTurn(
7584
7558
  fresh,
7585
- { cachedPrefix, prompt: agentPrompt },
7559
+ { cachedPrefix, prompt: agentPrompt, systemPrompt: turnReminders },
7586
7560
  (event) => {
7587
7561
  this.emit({ type: "turn_output", threadId, event });
7588
7562
  noteTurnLiveEvent(threadId, event);
@@ -7691,7 +7665,7 @@ var Orchestrator = class {
7691
7665
  ].filter(Boolean).join("\n\n---\n\n");
7692
7666
  const retryHandle = await spawnAgentTurn(
7693
7667
  retryThread,
7694
- { cachedPrefix: retryPrefix, prompt: agentPrompt },
7668
+ { cachedPrefix: retryPrefix, prompt: agentPrompt, systemPrompt: turnReminders },
7695
7669
  (event) => {
7696
7670
  this.emit({ type: "turn_output", threadId, event });
7697
7671
  if (event.type === "session_id") {
@@ -8422,7 +8396,7 @@ var Orchestrator = class {
8422
8396
  updateThread(thread.id, { title: meta.title });
8423
8397
  }
8424
8398
  }
8425
- const { autoArchiveOnMergeEnabled } = await import("./app-settings-VMOTQORT.js");
8399
+ const { autoArchiveOnMergeEnabled } = await import("./app-settings-663VQWUV.js");
8426
8400
  const latest = this.requireThread(thread.id);
8427
8401
  if (!shouldAutoArchiveOnPrMerge({
8428
8402
  previousPrState: prevState || null,
@@ -8739,7 +8713,7 @@ var Orchestrator = class {
8739
8713
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
8740
8714
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
8741
8715
  try {
8742
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-A7C3WA54.js");
8716
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-UYSD2STS.js");
8743
8717
  await ensureWorkspace2(thread.repoPath);
8744
8718
  } catch {
8745
8719
  }
@@ -8766,7 +8740,7 @@ var Orchestrator = class {
8766
8740
  await runArchiveScript(thread.repoPath, thread.worktreePath);
8767
8741
  } catch {
8768
8742
  }
8769
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-VMOTQORT.js");
8743
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-663VQWUV.js");
8770
8744
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
8771
8745
  await removeWorktree(thread.repoPath, thread.worktreePath, {
8772
8746
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -8793,7 +8767,7 @@ var Orchestrator = class {
8793
8767
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
8794
8768
  );
8795
8769
  }
8796
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-PODE23PD.js");
8770
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-WVEDT3FM.js");
8797
8771
  const slug = thread.worktreePath.split("/").pop();
8798
8772
  const dest = thread.worktreePath;
8799
8773
  await withRepoGitLock(thread.repoPath, async () => {
@@ -8903,7 +8877,7 @@ async function startOrchestration(opts) {
8903
8877
  sourceRef: "default",
8904
8878
  ...createOpts
8905
8879
  }).catch(async () => {
8906
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-PODE23PD.js");
8880
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-WVEDT3FM.js");
8907
8881
  const repo = await resolveRepoRoot2(repoPath);
8908
8882
  const def = await resolveDefaultBranch2(repo);
8909
8883
  return orch.createThread({
@@ -8990,6 +8964,8 @@ export {
8990
8964
  shouldCompactContext,
8991
8965
  splitForCompaction,
8992
8966
  formatMessagesAsTranscript,
8967
+ SEED_MAX_CHARS,
8968
+ SEED_FULL_TOOL_MESSAGES,
8993
8969
  buildSessionSeed,
8994
8970
  BRIGHTSY_SUMMARIZE_CONTEXT_TOOL,
8995
8971
  extractBrightsyContextSummary,
@@ -9127,6 +9103,7 @@ export {
9127
9103
  formatRenameBranchDirective,
9128
9104
  formatWorktreeDirective,
9129
9105
  formatWorktreeReminder,
9106
+ mentionsPrGoal,
9130
9107
  issueTicketFromThread,
9131
9108
  linearTicketIdFromThread,
9132
9109
  formatIssueToolsDirective,
@@ -9139,9 +9116,6 @@ export {
9139
9116
  formatLongRunningReminder,
9140
9117
  formatArtifactDirective,
9141
9118
  formatUiReminder,
9142
- loadAgentInstructions,
9143
- formatAgentInstructions,
9144
- withAgentInstructions,
9145
9119
  OPTIONAL_SERVICE_IDS,
9146
9120
  OPTIONAL_SERVICES,
9147
9121
  optionalServiceSpec,