@sideboard-ai/core 0.1.168 → 0.1.170

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-BMS53RIZ.js → abletime-ESVTHTFH.js} +2 -2
  2. package/dist/{abletime-AGF54TNA.js → abletime-IC2V7CNB.js} +2 -2
  3. package/dist/{agents-TSO4MB3X.js → agents-GOBVOXFG.js} +9 -9
  4. package/dist/{agents-KWJXZAHB.js → agents-ZCIMZHXZ.js} +9 -9
  5. package/dist/{app-settings-BRLZQA7N.js → app-settings-LF3TS7XS.js} +5 -1
  6. package/dist/{app-settings-JJQDWPEK.js → app-settings-VMOTQORT.js} +5 -1
  7. package/dist/{chunk-74TWOSQP.js → chunk-3C4B52TS.js} +78 -42
  8. package/dist/{chunk-CVZ4KXVP.js → chunk-7IUO67CW.js} +122 -2
  9. package/dist/{chunk-HSGSQA42.js → chunk-DHPZW2EA.js} +8 -34
  10. package/dist/{chunk-KJFFQAMA.js → chunk-DKLGWRWC.js} +1 -1
  11. package/dist/{chunk-NYMFNUT5.js → chunk-GQHVICNT.js} +194 -147
  12. package/dist/{chunk-ILXKJ4ZD.js → chunk-NB7TEKCF.js} +1 -1
  13. package/dist/{chunk-RS756MKF.js → chunk-P2VCMIZU.js} +8 -34
  14. package/dist/{chunk-UIR4VDYA.js → chunk-SAZIRJR4.js} +30 -10
  15. package/dist/{chunk-UVLPL2FJ.js → chunk-TEI72FYD.js} +198 -216
  16. package/dist/{chunk-3A54S244.js → chunk-UDEWGTP6.js} +29 -10
  17. package/dist/{chunk-TW5A2HFY.js → chunk-Y7DJA3UW.js} +78 -42
  18. package/dist/{chunk-LTXS26K5.js → chunk-YMF5WCIA.js} +122 -2
  19. package/dist/{coordinator-prompt-75N74HAO.js → coordinator-prompt-JTDCEU74.js} +3 -3
  20. package/dist/{coordinator-prompt-Y372QRFE.js → coordinator-prompt-RRUU2OYO.js} +3 -3
  21. package/dist/{global-workspace-JNNFVSP7.js → global-workspace-4SI3CRRT.js} +3 -3
  22. package/dist/{global-workspace-TPE4LKVM.js → global-workspace-ZF6EJAM3.js} +3 -3
  23. package/dist/index.cjs +421 -278
  24. package/dist/index.d.cts +135 -37
  25. package/dist/index.d.ts +135 -37
  26. package/dist/index.js +33 -19
  27. package/dist/mcp/run-stdio.cjs +401 -207
  28. package/dist/mcp/run-stdio.js +8 -8
  29. package/dist/{orchestrator-XG3QCMOS.js → orchestrator-LE6L6MJC.js} +5 -5
  30. package/dist/{orchestrator-IIME6KXQ.js → orchestrator-UZSFTDKA.js} +5 -5
  31. package/dist/{workspaces-2IGQNFPL.js → workspaces-A7C3WA54.js} +3 -3
  32. package/dist/{workspaces-BWZSDSGG.js → workspaces-NOC2MWQV.js} +3 -3
  33. package/dist/{worktree-7X7XNSYL.js → worktree-GXO2VDQF.js} +12 -4
  34. package/dist/{worktree-5BFEK6PF.js → worktree-PODE23PD.js} +12 -4
  35. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -530,6 +530,36 @@ var init_paths = __esm({
530
530
  }
531
531
  });
532
532
 
533
+ // src/agents/orchestrator-capable.ts
534
+ function isOrchestratorCapableAgent(agent) {
535
+ return Boolean(
536
+ agent && ORCHESTRATOR_AGENT_KINDS.includes(agent)
537
+ );
538
+ }
539
+ function assertOrchestratorCapableAgent(agent, context = "orchestration") {
540
+ if (!isOrchestratorCapableAgent(agent)) {
541
+ throw new Error(
542
+ `${agent} cannot run ${context} \u2014 it does not support Sideboard MCP. Use Claude, Cursor, Codex, or OpenCode.`
543
+ );
544
+ }
545
+ return agent;
546
+ }
547
+ function coerceOrchestratorAgent(agent, fallback = "claude") {
548
+ return isOrchestratorCapableAgent(agent) ? agent : fallback;
549
+ }
550
+ var ORCHESTRATOR_AGENT_KINDS;
551
+ var init_orchestrator_capable = __esm({
552
+ "src/agents/orchestrator-capable.ts"() {
553
+ "use strict";
554
+ ORCHESTRATOR_AGENT_KINDS = [
555
+ "claude",
556
+ "codex",
557
+ "opencode",
558
+ "cursor"
559
+ ];
560
+ }
561
+ });
562
+
533
563
  // src/hook/nested-electron-env.ts
534
564
  function isNestedElectronEnvKey(key) {
535
565
  return NESTED_ELECTRON_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));
@@ -1008,7 +1038,9 @@ __export(app_settings_exports, {
1008
1038
  resolveAgentExecutable: () => resolveAgentExecutable,
1009
1039
  resolveClaudeExecutable: () => resolveClaudeExecutable,
1010
1040
  resolveEffectiveIssueSource: () => resolveEffectiveIssueSource,
1041
+ resolveNewOrchestratorOptions: () => resolveNewOrchestratorOptions,
1011
1042
  resolveNewThreadOptions: () => resolveNewThreadOptions,
1043
+ resolveOrchestratorDefaults: () => resolveOrchestratorDefaults,
1012
1044
  resolveThreadDefaults: () => resolveThreadDefaults,
1013
1045
  resolveViewerProfile: () => resolveViewerProfile,
1014
1046
  resolveViewerProfileForRepo: () => resolveViewerProfileForRepo,
@@ -1270,6 +1302,25 @@ function normalizeIntegrations(raw) {
1270
1302
  }
1271
1303
  return out;
1272
1304
  }
1305
+ function normalizeOrchestratorDefaults(raw) {
1306
+ if (!raw || typeof raw !== "object") return void 0;
1307
+ const source = raw;
1308
+ const out = {};
1309
+ if (typeof source.agent === "string" && isOrchestratorCapableAgent(source.agent)) {
1310
+ out.agent = source.agent;
1311
+ }
1312
+ if (typeof source.model === "string") {
1313
+ const model = source.model.trim();
1314
+ if (model) out.model = model;
1315
+ }
1316
+ if (normalizeThinkingEffort(source.effort)) {
1317
+ out.effort = normalizeThinkingEffort(source.effort);
1318
+ }
1319
+ if (typeof source.fast === "boolean") {
1320
+ out.fast = source.fast;
1321
+ }
1322
+ return Object.keys(out).length > 0 ? out : void 0;
1323
+ }
1273
1324
  function normalizeDefaults(raw) {
1274
1325
  if (!raw || typeof raw !== "object") return {};
1275
1326
  const source = raw;
@@ -1289,6 +1340,8 @@ function normalizeDefaults(raw) {
1289
1340
  }
1290
1341
  const notes = foldLegacyRolesIntoNotes(source.roles, source.role, source.notes);
1291
1342
  if (notes) out.notes = notes;
1343
+ const orchestrator = normalizeOrchestratorDefaults(source.orchestrator);
1344
+ if (orchestrator) out.orchestrator = orchestrator;
1292
1345
  return out;
1293
1346
  }
1294
1347
  function profileRepoKey(path2) {
@@ -1832,6 +1885,39 @@ function updateIntegrationsSettings(patch) {
1832
1885
  }
1833
1886
  return saveAppSettings({ ...current, integrations });
1834
1887
  }
1888
+ function applyOrchestratorDefaultsPatch(current, patch) {
1889
+ const next = { ...current };
1890
+ if ("agent" in patch) {
1891
+ if (patch.agent == null) {
1892
+ delete next.agent;
1893
+ } else if (isOrchestratorCapableAgent(patch.agent)) {
1894
+ next.agent = patch.agent;
1895
+ }
1896
+ }
1897
+ if ("model" in patch) {
1898
+ if (patch.model == null || patch.model.trim() === "") {
1899
+ delete next.model;
1900
+ } else {
1901
+ next.model = patch.model.trim();
1902
+ }
1903
+ }
1904
+ if ("effort" in patch) {
1905
+ if (patch.effort == null) {
1906
+ delete next.effort;
1907
+ } else {
1908
+ const effort = normalizeThinkingEffort(patch.effort);
1909
+ if (effort) next.effort = effort;
1910
+ }
1911
+ }
1912
+ if ("fast" in patch) {
1913
+ if (patch.fast == null) {
1914
+ delete next.fast;
1915
+ } else {
1916
+ next.fast = Boolean(patch.fast);
1917
+ }
1918
+ }
1919
+ return Object.keys(next).length > 0 ? next : void 0;
1920
+ }
1835
1921
  function updateDefaultsSettings(patch) {
1836
1922
  const current = loadAppSettings();
1837
1923
  const defaults = { ...current.defaults };
@@ -1869,6 +1955,18 @@ function updateDefaultsSettings(patch) {
1869
1955
  if (!notes) delete defaults.notes;
1870
1956
  else defaults.notes = notes;
1871
1957
  }
1958
+ if ("orchestrator" in patch) {
1959
+ if (patch.orchestrator == null) {
1960
+ delete defaults.orchestrator;
1961
+ } else {
1962
+ const orchestrator = applyOrchestratorDefaultsPatch(
1963
+ defaults.orchestrator,
1964
+ patch.orchestrator
1965
+ );
1966
+ if (orchestrator) defaults.orchestrator = orchestrator;
1967
+ else delete defaults.orchestrator;
1968
+ }
1969
+ }
1872
1970
  delete defaults.roles;
1873
1971
  delete defaults.role;
1874
1972
  return saveAppSettings({ ...current, defaults });
@@ -1974,8 +2072,22 @@ function resolveThreadDefaults(settings = loadAppSettings()) {
1974
2072
  fast: getDefaultFast(settings)
1975
2073
  };
1976
2074
  }
1977
- function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
1978
- const defaults = resolveThreadDefaults(settings);
2075
+ function resolveOrchestratorDefaults(settings = loadAppSettings()) {
2076
+ const account = resolveThreadDefaults(settings);
2077
+ const orch = settings.defaults.orchestrator;
2078
+ const agent = coerceOrchestratorAgent(orch?.agent ?? account.agent);
2079
+ let model = orch ? orch.model?.trim() || null : account.model;
2080
+ if (model && agent !== "cursor" && /^(default|auto)$/i.test(model.trim())) {
2081
+ model = null;
2082
+ }
2083
+ return {
2084
+ agent,
2085
+ model,
2086
+ effort: orch?.effort ?? account.effort,
2087
+ fast: orch?.fast ?? account.fast
2088
+ };
2089
+ }
2090
+ function mergeThreadOptionOverrides(defaults, overrides) {
1979
2091
  const effort = overrides.effort === void 0 || overrides.effort === null ? defaults.effort : normalizeThinkingEffort(overrides.effort) ?? defaults.effort;
1980
2092
  const agent = overrides.agent ?? defaults.agent;
1981
2093
  let model = overrides.model === void 0 ? defaults.model : overrides.model?.trim() || null;
@@ -1989,6 +2101,12 @@ function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
1989
2101
  fast: overrides.fast === void 0 || overrides.fast === null ? defaults.fast : Boolean(overrides.fast)
1990
2102
  };
1991
2103
  }
2104
+ function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
2105
+ return mergeThreadOptionOverrides(resolveThreadDefaults(settings), overrides);
2106
+ }
2107
+ function resolveNewOrchestratorOptions(overrides = {}, settings = loadAppSettings()) {
2108
+ return mergeThreadOptionOverrides(resolveOrchestratorDefaults(settings), overrides);
2109
+ }
1992
2110
  function isLinearConnected(settings = loadAppSettings()) {
1993
2111
  return hasLinearCredentials(settings.integrations);
1994
2112
  }
@@ -2110,6 +2228,10 @@ function brightsyInjectWorktreeMcpEnabled(settings = loadAppSettings()) {
2110
2228
  }
2111
2229
  function brightsyCloudConnectAgent(settings = loadAppSettings()) {
2112
2230
  const fallback = settings.brightsy.cloudConnectAgent && CLOUD_CONNECT_AGENTS.has(settings.brightsy.cloudConnectAgent) ? settings.brightsy.cloudConnectAgent : "claude";
2231
+ const orchAgent = settings.defaults.orchestrator?.agent;
2232
+ if (orchAgent && CLOUD_CONNECT_AGENTS.has(orchAgent)) {
2233
+ return orchAgent;
2234
+ }
2113
2235
  const preferred = getDefaultAgent(settings);
2114
2236
  if (CLOUD_CONNECT_AGENTS.has(preferred)) {
2115
2237
  return preferred;
@@ -2320,6 +2442,7 @@ var init_app_settings = __esm({
2320
2442
  import_node_fs7 = require("fs");
2321
2443
  import_node_os3 = require("os");
2322
2444
  import_node_path8 = require("path");
2445
+ init_orchestrator_capable();
2323
2446
  init_thinking_effort();
2324
2447
  init_nested_electron_env();
2325
2448
  init_account_profile();
@@ -2895,36 +3018,6 @@ var init_setup_log = __esm({
2895
3018
  }
2896
3019
  });
2897
3020
 
2898
- // src/agents/orchestrator-capable.ts
2899
- function isOrchestratorCapableAgent(agent) {
2900
- return Boolean(
2901
- agent && ORCHESTRATOR_AGENT_KINDS.includes(agent)
2902
- );
2903
- }
2904
- function assertOrchestratorCapableAgent(agent, context = "orchestration") {
2905
- if (!isOrchestratorCapableAgent(agent)) {
2906
- throw new Error(
2907
- `${agent} cannot run ${context} \u2014 it does not support Sideboard MCP. Use Claude, Cursor, Codex, or OpenCode.`
2908
- );
2909
- }
2910
- return agent;
2911
- }
2912
- function coerceOrchestratorAgent(agent, fallback = "claude") {
2913
- return isOrchestratorCapableAgent(agent) ? agent : fallback;
2914
- }
2915
- var ORCHESTRATOR_AGENT_KINDS;
2916
- var init_orchestrator_capable = __esm({
2917
- "src/agents/orchestrator-capable.ts"() {
2918
- "use strict";
2919
- ORCHESTRATOR_AGENT_KINDS = [
2920
- "claude",
2921
- "codex",
2922
- "opencode",
2923
- "cursor"
2924
- ];
2925
- }
2926
- });
2927
-
2928
3021
  // src/store/schedules.ts
2929
3022
  function schedulesPath() {
2930
3023
  return (0, import_node_path12.join)(appDataDir(), "schedules.json");
@@ -3930,8 +4023,10 @@ function lookupSoccerTeam(titleOrSlug) {
3930
4023
  }
3931
4024
  function teamNameFromSlug(slug) {
3932
4025
  const normalized = slug.toLowerCase().replace(/^thread\//, "");
3933
- const suffixMatch = normalized.match(/^(.+)-(\d+)$/);
3934
- const base = suffixMatch?.[1] ?? normalized;
4026
+ const withoutTicket = normalized.replace(/^[a-z]{2,8}-\d{1,6}-/, "").replace(/^\d{1,8}-/, "");
4027
+ const lookup = withoutTicket || normalized;
4028
+ const suffixMatch = lookup.match(/^(.+)-(\d+)$/);
4029
+ const base = suffixMatch?.[1] ?? lookup;
3935
4030
  const suffix = suffixMatch?.[2];
3936
4031
  const team = FAMOUS_SOCCER_TEAM_SEEDS.find((t) => t.slug === base);
3937
4032
  if (team) return suffix ? `${team.name} ${suffix}` : team.name;
@@ -4352,6 +4447,25 @@ function worktreeNameFromPath(worktreePath) {
4352
4447
  const parts = normalized.split("/");
4353
4448
  return parts[parts.length - 1] || worktreePath;
4354
4449
  }
4450
+ function ticketSlugForBranch(sourceRef) {
4451
+ const raw = sourceRef.trim();
4452
+ if (!raw) return null;
4453
+ const linear = raw.match(/\b([A-Za-z]{2,8}-\d{1,6})\b/);
4454
+ if (linear) return linear[1].toLowerCase();
4455
+ const hashed = raw.match(/^#(\d{1,8})$/);
4456
+ if (hashed) return hashed[1];
4457
+ const digits = raw.match(/^(\d{1,8})$/);
4458
+ if (digits) return digits[1];
4459
+ const slug = raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
4460
+ return slug || null;
4461
+ }
4462
+ function worktreeSlugForTicket(ticketRef, teamSlug) {
4463
+ const ticket = ticketSlugForBranch(ticketRef);
4464
+ const team = teamSlug.trim().replace(/^thread\//, "");
4465
+ if (!ticket) return team;
4466
+ if (!team) return ticket;
4467
+ return `${ticket}-${team}`;
4468
+ }
4355
4469
  function isPlaceholderBranch(branchName, worktreePath) {
4356
4470
  const branch = branchName.trim();
4357
4471
  if (!branch || branch === "HEAD") return true;
@@ -5828,6 +5942,7 @@ var init_stack = __esm({
5828
5942
  var worktree_exports = {};
5829
5943
  __export(worktree_exports, {
5830
5944
  FAMOUS_SOCCER_TEAMS: () => FAMOUS_SOCCER_TEAMS,
5945
+ PR_DETAILS_JSON_FIELDS: () => PR_DETAILS_JSON_FIELDS,
5831
5946
  allocateTeamName: () => allocateTeamName,
5832
5947
  allocateTeamSlug: () => allocateTeamSlug,
5833
5948
  branchDisplayLabel: () => branchDisplayLabel,
@@ -5866,6 +5981,7 @@ __export(worktree_exports, {
5866
5981
  originFetchBranch: () => originFetchBranch,
5867
5982
  originGhRepoEnv: () => originGhRepoEnv,
5868
5983
  parseGithubSlugFromRemoteUrl: () => parseGithubSlugFromRemoteUrl,
5984
+ parsePrDetailsView: () => parsePrDetailsView,
5869
5985
  pushBranch: () => pushBranch,
5870
5986
  removeWorktree: () => removeWorktree,
5871
5987
  resolveDefaultBranch: () => resolveDefaultBranch,
@@ -5878,9 +5994,11 @@ __export(worktree_exports, {
5878
5994
  slugify: () => slugify,
5879
5995
  suggestSlug: () => suggestSlug,
5880
5996
  threadDisplayLabel: () => threadDisplayLabel,
5997
+ ticketSlugForBranch: () => ticketSlugForBranch,
5881
5998
  worktreeDisplayLabel: () => worktreeDisplayLabel,
5882
5999
  worktreeDisplayLabelForGroup: () => worktreeDisplayLabelForGroup,
5883
- worktreeNameFromPath: () => worktreeNameFromPath
6000
+ worktreeNameFromPath: () => worktreeNameFromPath,
6001
+ worktreeSlugForTicket: () => worktreeSlugForTicket
5884
6002
  });
5885
6003
  async function lookupGithubGraphqlReset(cwd) {
5886
6004
  const result = await gh(["api", "rate_limit"], cwd, { reject: false });
@@ -6441,48 +6559,15 @@ async function getPrMeta(cwd, selector) {
6441
6559
  return null;
6442
6560
  }
6443
6561
  }
6444
- async function getPrDetails(cwd, selector) {
6445
- const slug = await resolveGithubRepoSlug(cwd);
6446
- const viewArgs = [
6447
- "pr",
6448
- "view",
6449
- selector,
6450
- "--json",
6451
- [
6452
- "number",
6453
- "title",
6454
- "body",
6455
- "url",
6456
- "state",
6457
- "isDraft",
6458
- "reviewDecision",
6459
- "author",
6460
- "baseRefName",
6461
- "headRefName",
6462
- "additions",
6463
- "deletions",
6464
- "changedFiles",
6465
- "comments",
6466
- "reviews"
6467
- ].join(",")
6468
- ];
6469
- if (slug) viewArgs.push("--repo", slug);
6470
- const { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
6471
- if (exitCode !== 0 || !stdout.trim()) {
6472
- if (stderr.trim()) {
6473
- if (/no pull requests found/i.test(stderr)) return null;
6474
- }
6475
- return null;
6476
- }
6477
- let view;
6478
- try {
6479
- view = JSON.parse(stdout);
6480
- } catch {
6481
- throw new Error(stderr.trim() || "gh pr view returned invalid JSON");
6482
- }
6562
+ function parsePrDetailsView(view) {
6483
6563
  const author = view.author ?? {};
6484
6564
  const comments = Array.isArray(view.comments) ? view.comments : [];
6485
6565
  const reviews = Array.isArray(view.reviews) ? view.reviews : [];
6566
+ const requested = {
6567
+ ids: reviewerIdentities(view.reviewRequests),
6568
+ users: humanReviewerLogins(view.reviewRequests),
6569
+ teams: teamReviewerSlugs(view.reviewRequests)
6570
+ };
6486
6571
  return {
6487
6572
  number: Number(view.number),
6488
6573
  title: String(view.title ?? ""),
@@ -6518,10 +6603,34 @@ async function getPrDetails(cwd, selector) {
6518
6603
  submittedAt: normalizeGhTime(row.submittedAt)
6519
6604
  };
6520
6605
  }),
6606
+ assignees: reviewerIdentities(view.assignees),
6607
+ labels: labelNames(view.labels),
6608
+ reviewRequests: requested.ids,
6609
+ reviewers: requested.users,
6610
+ teams: requested.teams,
6521
6611
  // CI lives in Checks tab via getPrChecks — nesting burned GraphQL points.
6522
6612
  checks: []
6523
6613
  };
6524
6614
  }
6615
+ async function getPrDetails(cwd, selector) {
6616
+ const slug = await resolveGithubRepoSlug(cwd);
6617
+ const viewArgs = ["pr", "view", selector, "--json", PR_DETAILS_JSON_FIELDS];
6618
+ if (slug) viewArgs.push("--repo", slug);
6619
+ const { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
6620
+ if (exitCode !== 0 || !stdout.trim()) {
6621
+ if (stderr.trim()) {
6622
+ if (/no pull requests found/i.test(stderr)) return null;
6623
+ }
6624
+ return null;
6625
+ }
6626
+ let view;
6627
+ try {
6628
+ view = JSON.parse(stdout);
6629
+ } catch {
6630
+ throw new Error(stderr.trim() || "gh pr view returned invalid JSON");
6631
+ }
6632
+ return parsePrDetailsView(view);
6633
+ }
6525
6634
  async function fetchPrHead(repoPath, number, localBranch) {
6526
6635
  const slug = await resolveGithubRepoSlug(repoPath);
6527
6636
  const refspec = `+pull/${number}/head:${localBranch}`;
@@ -7232,7 +7341,7 @@ function allocateTeamSlug(repoPath) {
7232
7341
  }
7233
7342
  throw new Error("No available soccer team worktree directories left");
7234
7343
  }
7235
- var import_node_crypto6, import_node_fs18, import_node_os6, import_node_path20;
7344
+ var import_node_crypto6, import_node_fs18, import_node_os6, import_node_path20, PR_DETAILS_JSON_FIELDS;
7236
7345
  var init_worktree = __esm({
7237
7346
  "src/git/worktree.ts"() {
7238
7347
  "use strict";
@@ -7254,9 +7363,30 @@ var init_worktree = __esm({
7254
7363
  init_pr_gates();
7255
7364
  init_stack();
7256
7365
  init_teams();
7366
+ init_worktree_labels();
7257
7367
  init_git_auth_mode();
7258
7368
  init_workspace_scratch();
7259
7369
  init_worktree_labels();
7370
+ PR_DETAILS_JSON_FIELDS = [
7371
+ "number",
7372
+ "title",
7373
+ "body",
7374
+ "url",
7375
+ "state",
7376
+ "isDraft",
7377
+ "reviewDecision",
7378
+ "author",
7379
+ "baseRefName",
7380
+ "headRefName",
7381
+ "additions",
7382
+ "deletions",
7383
+ "changedFiles",
7384
+ "comments",
7385
+ "reviews",
7386
+ "assignees",
7387
+ "labels",
7388
+ "reviewRequests"
7389
+ ].join(",");
7260
7390
  }
7261
7391
  });
7262
7392
 
@@ -7724,7 +7854,7 @@ function createGlobalChat(opts) {
7724
7854
  const explicit = opts.title?.trim();
7725
7855
  const title = explicit && explicit !== CLOUD_ORCHESTRATOR_GOAL ? explicit : allocateTeamName(takenTeamSlugsForOrchestration()).name;
7726
7856
  const sourceRef = opts.sourceRef?.trim() || (isCloud ? CLOUD_ORCHESTRATOR_GOAL : title);
7727
- const resolved = resolveNewThreadOptions({
7857
+ const resolved = resolveNewOrchestratorOptions({
7728
7858
  agent: opts.agent,
7729
7859
  model: opts.model,
7730
7860
  effort: opts.effort,
@@ -7800,7 +7930,7 @@ function findSlackCoordinator(teamId, userId) {
7800
7930
  );
7801
7931
  }
7802
7932
  function ensureSlackCoordinator(teamId, userId, agent, opts) {
7803
- const defaults = resolveThreadDefaults();
7933
+ const defaults = resolveOrchestratorDefaults();
7804
7934
  const desired = assertOrchestratorCapableAgent(agent);
7805
7935
  const ref = slackCoordinatorSourceRef(teamId, userId);
7806
7936
  if (!opts?.forceNew) {
@@ -7835,7 +7965,7 @@ function ensureSlackCoordinator(teamId, userId, agent, opts) {
7835
7965
  });
7836
7966
  }
7837
7967
  function ensureCloudCoordinator(agent) {
7838
- const defaults = resolveThreadDefaults();
7968
+ const defaults = resolveOrchestratorDefaults();
7839
7969
  const desired = assertOrchestratorCapableAgent(agent);
7840
7970
  const existing = findCloudCoordinator();
7841
7971
  if (existing) {
@@ -9304,22 +9434,38 @@ var init_brightsy_targets = __esm({
9304
9434
  // src/agents/turn-input.ts
9305
9435
  function normalizeTurnInput(input) {
9306
9436
  if (typeof input === "string") return { prompt: input };
9307
- return { prompt: input.prompt, cachedPrefix: input.cachedPrefix?.trim() || void 0 };
9437
+ return {
9438
+ prompt: input.prompt,
9439
+ cachedPrefix: input.cachedPrefix?.trim() || void 0,
9440
+ systemPrompt: input.systemPrompt?.trim() || void 0
9441
+ };
9308
9442
  }
9309
9443
  function dropCachedPrefixOnResume(input, sessionId) {
9310
9444
  const turn = normalizeTurnInput(input);
9311
- if (sessionId) return { prompt: turn.prompt };
9445
+ if (sessionId) {
9446
+ return turn.systemPrompt ? { prompt: turn.prompt, systemPrompt: turn.systemPrompt } : { prompt: turn.prompt };
9447
+ }
9312
9448
  return turn;
9313
9449
  }
9314
9450
  function flattenTurnInput(input) {
9315
- const { cachedPrefix, prompt } = normalizeTurnInput(input);
9316
- if (!cachedPrefix) return prompt;
9317
- return `${cachedPrefix}
9451
+ const { cachedPrefix, prompt, systemPrompt } = normalizeTurnInput(input);
9452
+ if (cachedPrefix) return `${cachedPrefix}
9318
9453
 
9319
9454
  ---
9320
9455
 
9321
9456
  Current request:
9322
9457
  ${prompt}`;
9458
+ if (systemPrompt) return `${systemPrompt}
9459
+
9460
+ ${prompt}`;
9461
+ return prompt;
9462
+ }
9463
+ function splitTurnInputForSystemPrompt(input) {
9464
+ const turn = normalizeTurnInput(input);
9465
+ return {
9466
+ promptText: flattenTurnInput({ cachedPrefix: turn.cachedPrefix, prompt: turn.prompt }),
9467
+ systemPrompt: turn.systemPrompt
9468
+ };
9323
9469
  }
9324
9470
  function buildCachedUserContent(input) {
9325
9471
  return [{ type: "text", text: flattenTurnInput(input) }];
@@ -11359,7 +11505,7 @@ var init_claude = __esm({
11359
11505
  const claude = resolveClaudeExecutable();
11360
11506
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
11361
11507
  const effective = dropCachedPrefixOnResume(input, sessionId);
11362
- const promptText = flattenTurnInput(effective);
11508
+ const { promptText, systemPrompt } = splitTurnInputForSystemPrompt(effective);
11363
11509
  const useStdin = promptText.length > CLAUDE_PROMPT_ARG_MAX;
11364
11510
  if (process.env.SIDEBOARD_DEBUG_CLAUDE_TURN === "1") {
11365
11511
  console.error(
@@ -11411,6 +11557,9 @@ var init_claude = __esm({
11411
11557
  "--permission-mode",
11412
11558
  mode.claude
11413
11559
  ];
11560
+ if (systemPrompt) {
11561
+ args.push("--append-system-prompt", systemPrompt);
11562
+ }
11414
11563
  const mcpConfigPath = writeMcpServersConfig(injectedServers);
11415
11564
  if (mcpConfigPath) {
11416
11565
  args.push("--mcp-config", mcpConfigPath);
@@ -13832,7 +13981,50 @@ function agentGitPrompt(action, opts) {
13832
13981
  return "Merge PR.";
13833
13982
  }
13834
13983
  }
13835
- var AGENT_GIT_ACTIONS;
13984
+ function gitActionExpansion(action, base) {
13985
+ switch (action) {
13986
+ case "commit-push":
13987
+ 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.";
13988
+ case "create-draft":
13989
+ 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.";
13990
+ case "create-web":
13991
+ return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
13992
+ case "resolve-conflicts":
13993
+ return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
13994
+ case "merge":
13995
+ 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.";
13996
+ }
13997
+ }
13998
+ function expandCanonicalGitRequest(prompt) {
13999
+ const trimmed = prompt.trim();
14000
+ let action = null;
14001
+ let base = null;
14002
+ for (const candidate of AGENT_GIT_ACTIONS) {
14003
+ if (candidate === "resolve-conflicts") continue;
14004
+ if (agentGitPrompt(candidate) === trimmed) {
14005
+ action = candidate;
14006
+ break;
14007
+ }
14008
+ }
14009
+ if (!action) {
14010
+ const m = RESOLVE_CONFLICTS_RE.exec(trimmed);
14011
+ if (m) {
14012
+ action = "resolve-conflicts";
14013
+ base = m[1] ?? null;
14014
+ }
14015
+ }
14016
+ let expansion = action ? gitActionExpansion(action, base) : null;
14017
+ if (!expansion && trimmed === "Address review comments.") {
14018
+ expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
14019
+ } else if (!expansion && FIX_CI_RE.test(trimmed)) {
14020
+ 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.";
14021
+ }
14022
+ if (!expansion) return prompt;
14023
+ return `${trimmed}
14024
+
14025
+ (Sideboard git request \u2014 do not ask for clarification: ${expansion})`;
14026
+ }
14027
+ var AGENT_GIT_ACTIONS, RESOLVE_CONFLICTS_RE, FIX_CI_RE;
13836
14028
  var init_agent_git_actions = __esm({
13837
14029
  "src/git/agent-git-actions.ts"() {
13838
14030
  "use strict";
@@ -13843,6 +14035,8 @@ var init_agent_git_actions = __esm({
13843
14035
  "resolve-conflicts",
13844
14036
  "merge"
13845
14037
  ];
14038
+ RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
14039
+ FIX_CI_RE = /^Fix CI: .+\.$/;
13846
14040
  }
13847
14041
  });
13848
14042
 
@@ -14100,47 +14294,82 @@ function formatToolPart(t, detail) {
14100
14294
  }
14101
14295
  function formatMessagesAsTranscript(messages, opts) {
14102
14296
  const tools = opts?.tools ?? "full";
14103
- const blocks = [];
14104
- for (const m of messages) {
14105
- if (m.role === "summary") {
14106
- blocks.push(`## Prior summary
14107
- ${m.text}`);
14108
- continue;
14109
- }
14110
- if (m.role === "user") {
14111
- blocks.push(`### User
14112
- ${m.text}`);
14113
- continue;
14114
- }
14115
- const bits = [];
14116
- if (m.text?.trim()) {
14117
- bits.push(`### Agent
14297
+ const thinking = opts?.thinking ?? true;
14298
+ return messages.map((m) => formatMessageBlock(m, { tools, thinking })).join("\n\n");
14299
+ }
14300
+ function formatMessageBlock(m, opts) {
14301
+ if (m.role === "summary") return `## Prior summary
14302
+ ${m.text}`;
14303
+ if (m.role === "user") return `### User
14304
+ ${m.text}`;
14305
+ const bits = [];
14306
+ if (m.text?.trim()) {
14307
+ bits.push(`### Agent
14118
14308
  ${m.text}`);
14119
- } else {
14120
- bits.push("### Agent");
14121
- }
14122
- const thinking = (m.parts ?? []).filter((p) => p.type === "thinking");
14123
- for (const th of thinking) {
14309
+ } else {
14310
+ bits.push("### Agent");
14311
+ }
14312
+ if (opts.thinking) {
14313
+ for (const th of m.parts ?? []) {
14124
14314
  if (th.type !== "thinking" || !th.text.trim()) continue;
14125
14315
  bits.push("Thinking:");
14126
14316
  bits.push(th.text);
14127
14317
  }
14128
- const toolParts = (m.parts ?? []).filter(
14129
- (p) => p.type === "tool"
14130
- );
14131
- if (tools !== "none" && toolParts.length > 0) {
14132
- if (tools === "summary") bits.push("Tools:");
14133
- for (const t of toolParts) {
14134
- bits.push(formatToolPart(t, tools));
14135
- }
14318
+ }
14319
+ const toolParts = (m.parts ?? []).filter(
14320
+ (p) => p.type === "tool"
14321
+ );
14322
+ if (opts.tools !== "none" && toolParts.length > 0) {
14323
+ if (opts.tools === "summary") bits.push("Tools:");
14324
+ for (const t of toolParts) {
14325
+ bits.push(formatToolPart(t, opts.tools));
14136
14326
  }
14137
- blocks.push(bits.join("\n"));
14138
14327
  }
14139
- return blocks.join("\n\n");
14328
+ return bits.join("\n");
14140
14329
  }
14141
14330
  function buildSessionSeed(messages, opts) {
14142
14331
  if (messages.length === 0) return null;
14143
- const body = formatMessagesAsTranscript(messages, { tools: opts?.tools ?? "full" });
14332
+ const tools = opts?.tools ?? "full";
14333
+ const fullCount = opts?.fullToolMessages ?? SEED_FULL_TOOL_MESSAGES;
14334
+ const maxChars = opts?.maxChars ?? SEED_MAX_CHARS;
14335
+ const olderTools = tools === "none" ? "none" : "summary";
14336
+ const fullFrom = Math.max(0, messages.length - fullCount);
14337
+ const blocks = messages.map(
14338
+ (m, i) => formatMessageBlock(m, {
14339
+ tools: i >= fullFrom ? tools : olderTools,
14340
+ thinking: false
14341
+ })
14342
+ );
14343
+ const keep = new Array(blocks.length).fill(false);
14344
+ let used = 0;
14345
+ for (let i = 0; i < blocks.length; i++) {
14346
+ if (messages[i].role === "summary") {
14347
+ keep[i] = true;
14348
+ used += blocks[i].length + 2;
14349
+ }
14350
+ }
14351
+ for (let i = blocks.length - 1; i >= 0; i--) {
14352
+ if (keep[i]) continue;
14353
+ const next = used + blocks[i].length + 2;
14354
+ if (next > maxChars && used > 0) break;
14355
+ keep[i] = true;
14356
+ used = next;
14357
+ }
14358
+ const dropped = keep.filter((k) => !k).length;
14359
+ const kept = [];
14360
+ let markerPlaced = false;
14361
+ for (let i = 0; i < blocks.length; i++) {
14362
+ if (!keep[i]) continue;
14363
+ if (dropped > 0 && !markerPlaced && messages[i].role !== "summary") {
14364
+ kept.push(`_(${dropped} older message${dropped === 1 ? "" : "s"} omitted for length)_`);
14365
+ markerPlaced = true;
14366
+ }
14367
+ kept.push(blocks[i]);
14368
+ }
14369
+ if (dropped > 0 && !markerPlaced) {
14370
+ kept.push(`_(${dropped} older message${dropped === 1 ? "" : "s"} omitted for length)_`);
14371
+ }
14372
+ const body = kept.join("\n\n");
14144
14373
  if (!body.trim()) return null;
14145
14374
  return [
14146
14375
  "Sideboard conversation context (restored after compaction or a new session):",
@@ -14198,7 +14427,7 @@ function messagesSinceLastBrightsyContextSummary(messages) {
14198
14427
  function buildBrightsySessionSeed(messages) {
14199
14428
  const match = findLastBrightsyContextSummary(messages);
14200
14429
  const tail = match ? messages.slice(match.index + 1) : messages;
14201
- const body = formatMessagesAsTranscript(tail, { tools: "none" });
14430
+ const body = formatMessagesAsTranscript(tail, { tools: "none", thinking: false });
14202
14431
  if (!match && !body.trim()) return null;
14203
14432
  const blocks = [
14204
14433
  "Sideboard conversation context (restored after compaction or a new session):",
@@ -14265,7 +14494,7 @@ async function maybeCompactContext(thread, thresholds = {}, summarize = summariz
14265
14494
  olderCount: older.length
14266
14495
  };
14267
14496
  }
14268
- var CONTEXT_COMPACT_CHARS, CONTEXT_KEEP_RECENT_CHARS, CONTEXT_KEEP_RECENT_MESSAGES, CONTEXT_MIN_MESSAGES, SESSION_RESET_OCCUPANCY_TOKENS, BRIGHTSY_SUMMARIZE_CONTEXT_TOOL;
14497
+ var CONTEXT_COMPACT_CHARS, CONTEXT_KEEP_RECENT_CHARS, CONTEXT_KEEP_RECENT_MESSAGES, CONTEXT_MIN_MESSAGES, SESSION_RESET_OCCUPANCY_TOKENS, SEED_MAX_CHARS, SEED_FULL_TOOL_MESSAGES, BRIGHTSY_SUMMARIZE_CONTEXT_TOOL;
14269
14498
  var init_context_compact = __esm({
14270
14499
  "src/composer/context-compact.ts"() {
14271
14500
  "use strict";
@@ -14278,6 +14507,8 @@ var init_context_compact = __esm({
14278
14507
  CONTEXT_KEEP_RECENT_MESSAGES = 12;
14279
14508
  CONTEXT_MIN_MESSAGES = 10;
14280
14509
  SESSION_RESET_OCCUPANCY_TOKENS = 75e4;
14510
+ SEED_MAX_CHARS = 6e4;
14511
+ SEED_FULL_TOOL_MESSAGES = 6;
14281
14512
  BRIGHTSY_SUMMARIZE_CONTEXT_TOOL = "summarize_context";
14282
14513
  }
14283
14514
  });
@@ -17000,10 +17231,11 @@ async function createThread(input, _onSetupLine) {
17000
17231
  throw new Error("Use adoptThread() for adopt sources");
17001
17232
  }
17002
17233
  const team = allocateTeamSlug(repoPath);
17234
+ const slug = sourceType === "ticket" ? worktreeSlugForTicket(persistedSourceRef, team.slug) : team.slug;
17003
17235
  const { branchName, worktreePath } = await createThreadWorktree({
17004
17236
  repoPath,
17005
17237
  sourceRef,
17006
- slug: team.slug
17238
+ slug
17007
17239
  });
17008
17240
  copyConfiguredFiles(repoPath, worktreePath);
17009
17241
  const explicitTitle = title?.trim();
@@ -19301,12 +19533,17 @@ function normPath3(p) {
19301
19533
  function formatRenameBranchDirective(thread, opts) {
19302
19534
  if (!isPlaceholderBranch(thread.branchName, thread.worktreePath)) return null;
19303
19535
  const dir = worktreeNameFromPath(thread.worktreePath);
19536
+ const ticket = thread.sourceType === "ticket" ? ticketSlugForBranch(thread.sourceRef ?? "") : null;
19537
+ const example = ticket ? `\`feat/${ticket}-dark-mode\` or \`fix/${ticket}-panel-width\`` : "`fix/panel-width` or `feat/dark-mode`";
19304
19538
  const lines = [
19305
19539
  "Branch naming (do this early in the turn):",
19306
- `- Current branch \`${thread.branchName}\` is a temporary placeholder. The worktree folder \`${dir}\` is a stable soccer-team nickname \u2014 do not rename or leave that directory.`,
19307
- "- Rename the git branch to a short kebab-case name that describes this task (what you are changing), e.g. `fix/panel-width` or `feat/dark-mode`:",
19540
+ `- Current branch \`${thread.branchName}\` is a temporary placeholder. The worktree folder \`${dir}\` is a stable nickname \u2014 do not rename or leave that directory.`,
19541
+ `- Rename the git branch to a short kebab-case name that describes this task (what you are changing), e.g. ${example}:`,
19308
19542
  " `git branch -m <new-name>`",
19309
19543
  "- Prefer Conventional Commits style prefixes when they fit (`fix/`, `feat/`, `chore/`, `docs/`).",
19544
+ ...ticket ? [
19545
+ `- Keep ticket \`${ticket}\` in the new branch name so the issue stays findable.`
19546
+ ] : [],
19310
19547
  "- Never push this placeholder to main/master."
19311
19548
  ];
19312
19549
  const custom = opts?.customPrompt?.trim();
@@ -19340,67 +19577,37 @@ function formatWorktreeDirective(thread, opts) {
19340
19577
  lines.push(
19341
19578
  "- 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)."
19342
19579
  );
19343
- lines.push(
19344
- "- Push with `git push -u origin HEAD` (or the current branch name). Do not `git push upstream`."
19345
- );
19346
- lines.push("");
19347
19580
  lines.push(formatGitAuthModeDirective(opts?.gitAuthMode ?? "auto"));
19348
19581
  lines.push(
19349
- "- 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."
19350
- );
19351
- lines.push(
19352
- "- Prefer a concise imperative title (Conventional Commits style when it fits: feat:/fix:/chore:/docs:). Body should summarize intent, key changes, and test notes."
19582
+ "- 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."
19353
19583
  );
19354
19584
  lines.push(
19355
- "- 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`)."
19585
+ "- 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`)."
19356
19586
  );
19357
19587
  if (thread.prUrl) {
19358
19588
  lines.push(
19359
19589
  `- A PR already exists (${thread.prUrl}). Update it (push + edit title/body if the purpose drifted) instead of opening a duplicate.`
19360
19590
  );
19361
- } else if (opts?.githubSlug) {
19362
- lines.push(
19363
- `- 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\`.`
19364
- );
19365
19591
  } else {
19592
+ const slug = opts?.githubSlug ?? "<origin-owner/name>";
19593
+ const resolve = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
19366
19594
  lines.push(
19367
- "- 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`."
19595
+ `- 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\`.`
19368
19596
  );
19369
19597
  }
19370
- lines.push("");
19371
- lines.push(
19372
- "Short git requests from the Sideboard UI are complete instructions \u2014 expand them using the rules above without asking for clarification:"
19373
- );
19374
- lines.push(
19375
- '- "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.'
19376
- );
19377
- lines.push(
19378
- '- "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).'
19379
- );
19380
- lines.push(
19381
- '- "Commit, push, and open a PR in the browser." \u2192 commit, push, then `gh pr create --web -R \u2026`.'
19382
- );
19383
19598
  lines.push(
19384
- '- "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.'
19599
+ '- 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.'
19385
19600
  );
19386
- lines.push(
19387
- '- "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.'
19388
- );
19389
- lines.push(
19390
- '- "Address review comments." \u2192 read PR review feedback, make the requested changes, commit, and push.'
19391
- );
19392
- lines.push(
19393
- '- "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.'
19394
- );
19395
- lines.push("");
19396
- lines.push(formatPrGateDirective());
19397
19601
  lines.push("");
19398
- lines.push(formatProcessGuideDirective());
19602
+ lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
19399
19603
  return lines.join("\n");
19400
19604
  }
19401
19605
  function formatWorktreeReminder() {
19402
19606
  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.";
19403
19607
  }
19608
+ function mentionsPrGoal(prompt) {
19609
+ return PR_GOAL_RE.test(prompt);
19610
+ }
19404
19611
  function issueTicketFromThread(thread, preferredSource = "github") {
19405
19612
  if (thread?.sourceType !== "ticket") return null;
19406
19613
  const ref = thread.sourceRef?.trim() ?? "";
@@ -19489,29 +19696,27 @@ function formatPrGateDirective() {
19489
19696
  "- 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."
19490
19697
  ].join("\n");
19491
19698
  }
19492
- function formatProcessGuideDirective() {
19699
+ function formatProcessGuideDirective(opts) {
19700
+ const worktree = opts?.worktreePath?.trim();
19701
+ const hasGraphSkill = !!worktree && (0, import_node_fs48.existsSync)((0, import_node_path45.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
19702
+ const hasReviewSkill = !!worktree && (0, import_node_fs48.existsSync)((0, import_node_path45.join)(worktree, ".claude/skills/review/SKILL.md"));
19493
19703
  return [
19494
19704
  "Process guides (recurring work only):",
19495
- "- 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.",
19496
- "- 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.",
19497
- "- 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.",
19498
- "- 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.",
19499
- "- 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.",
19705
+ 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,
19706
+ "- 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`.",
19707
+ 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.",
19500
19708
  "- 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."
19501
- ].join("\n");
19709
+ ].filter(Boolean).join("\n");
19502
19710
  }
19503
19711
  function formatLongRunningDirective(opts) {
19504
19712
  const invoke = formatDetachedJobInvoke(opts?.scriptPath);
19505
19713
  return [
19506
- "Long-running jobs (mandatory when a command may run more than ~30s):",
19507
- "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.",
19508
- `Helper (same tool as \`scripts/detached-job.cjs\` when that file exists in the worktree): \`${invoke}\``,
19509
- `- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree). If JSON says already-running, do not start again.`,
19510
- "- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
19511
- `- 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.`,
19512
- `- 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.`,
19513
- "- 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).",
19514
- "- ok \u2192 finish the task. failed / stopped \u2192 read the log, fix or narrow the command, start once.",
19714
+ "Long-running jobs (mandatory when a command may run more than ~30s \u2014 pack, test, deploy, `gh pr checks --watch`):",
19715
+ "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.",
19716
+ `- 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.`,
19717
+ "- 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>`.",
19718
+ "- 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.",
19719
+ "- 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.",
19515
19720
  "State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
19516
19721
  ].join("\n");
19517
19722
  }
@@ -19521,84 +19726,17 @@ function formatLongRunningReminder(opts) {
19521
19726
  }
19522
19727
  function formatArtifactDirective() {
19523
19728
  return [
19524
- "Sideboard side column (desktop UI):",
19525
- "claude.ai\u2019s \u201CArtifact\u201D tool does NOT exist in Claude Code. That is expected.",
19526
- "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.",
19527
- "Documents (HTML/SVG/markdown):",
19528
- "1) Emit a fenced code block tagged `html` (preferred), `svg`, or `markdown` with the FULL document \u2014 Sideboard opens a side column. Example:",
19529
- "```html",
19530
- "<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
19531
- "```",
19532
- "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.",
19533
- " 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.",
19534
- "CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
19535
- "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:",
19536
- " - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
19537
- " - datasource=inline + resource: { id, title, schema, schemaUi } and optional records/record.",
19538
- "Files / media browser (CMS file manager column):",
19539
- "4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
19540
- " Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
19541
- "Multiple-choice questions:",
19542
- "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.",
19543
- "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.",
19544
- "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."
19729
+ "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.",
19730
+ "- 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.",
19731
+ "- 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.",
19732
+ "- 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.",
19733
+ "- 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."
19545
19734
  ].join("\n");
19546
19735
  }
19547
19736
  function formatUiReminder() {
19548
19737
  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.";
19549
19738
  }
19550
- function loadAgentInstructions(worktreePath, agent) {
19551
- const candidates = FILES_BY_AGENT[agent] ?? FILES_BY_AGENT.claude;
19552
- const seenPaths = /* @__PURE__ */ new Set();
19553
- const seenBodies = /* @__PURE__ */ new Set();
19554
- const out = [];
19555
- for (const rel of candidates) {
19556
- if (seenPaths.has(rel)) continue;
19557
- const abs = (0, import_node_path45.join)(worktreePath, rel);
19558
- if (!(0, import_node_fs48.existsSync)(abs)) continue;
19559
- try {
19560
- if (!(0, import_node_fs48.statSync)(abs).isFile()) continue;
19561
- let content = (0, import_node_fs48.readFileSync)(abs, "utf8");
19562
- if (!content.trim()) continue;
19563
- if (content.length > MAX_CHARS_PER_FILE) {
19564
- content = `${content.slice(0, MAX_CHARS_PER_FILE)}
19565
-
19566
- \u2026(truncated)`;
19567
- }
19568
- const body = content.trim().replace(/\r\n/g, "\n");
19569
- if (seenBodies.has(body)) continue;
19570
- seenPaths.add(rel);
19571
- seenBodies.add(body);
19572
- out.push({ relativePath: rel, content });
19573
- } catch {
19574
- }
19575
- }
19576
- return out;
19577
- }
19578
- function formatAgentInstructions(files) {
19579
- if (files.length === 0) return null;
19580
- const parts = [
19581
- "Project agent instructions (from the worktree \u2014 follow these):",
19582
- ""
19583
- ];
19584
- for (const f of files) {
19585
- parts.push(`## ${f.relativePath}`);
19586
- parts.push("");
19587
- parts.push(f.content.trim());
19588
- parts.push("");
19589
- parts.push("---");
19590
- parts.push("");
19591
- }
19592
- return parts.join("\n").trimEnd();
19593
- }
19594
- function withAgentInstructions(prompt, files) {
19595
- const prefix = formatAgentInstructions(files);
19596
- if (!prefix) return prompt;
19597
- return `${prefix}
19598
-
19599
- ${prompt}`;
19600
- }
19601
- var import_node_fs48, import_node_path45, GITHUB_TICKET_REF, KEYED_TICKET_REF, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
19739
+ var import_node_fs48, import_node_path45, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
19602
19740
  var init_instructions = __esm({
19603
19741
  "src/agents/instructions.ts"() {
19604
19742
  "use strict";
@@ -19607,22 +19745,9 @@ var init_instructions = __esm({
19607
19745
  init_git_auth_mode();
19608
19746
  init_worktree_labels();
19609
19747
  init_detached_job_path();
19748
+ 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;
19610
19749
  GITHUB_TICKET_REF = /^(?:#?\d+|gh-\d+)$/i;
19611
19750
  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;
19612
- FILES_BY_AGENT = {
19613
- claude: [
19614
- "CLAUDE.md",
19615
- ".claude/CLAUDE.md",
19616
- "CLAUDE.local.md",
19617
- "AGENTS.md",
19618
- "AGENT.md"
19619
- ],
19620
- codex: ["AGENTS.md", "AGENT.md", ".codex/AGENTS.md", "CLAUDE.md"],
19621
- opencode: ["AGENTS.md", "AGENT.md", "OPENCODE.md", "CLAUDE.md"],
19622
- brightsy: ["AGENTS.md", "AGENT.md", "CLAUDE.md"],
19623
- cursor: ["AGENTS.md", "AGENT.md", ".cursor/rules", "CLAUDE.md"]
19624
- };
19625
- MAX_CHARS_PER_FILE = 48e3;
19626
19751
  }
19627
19752
  });
19628
19753
 
@@ -21019,17 +21144,21 @@ var init_orchestrator = __esm({
21019
21144
  const slackReplyContext = formatSlackRepliesForTurn(
21020
21145
  pendingSlackExternalReplies(thread.messages)
21021
21146
  );
21022
- const agentPrompt = [
21023
- thread.planMode ? PLAN_MODE_INSTRUCTION : null,
21024
- orchestrationReminder,
21147
+ const turnReminders = [
21025
21148
  worktreeReminder,
21026
21149
  optionalServicesReminder,
21027
21150
  issueToolsReminder,
21028
21151
  viewerContextReminder,
21029
21152
  artifactReminder,
21030
- longRunningReminder,
21153
+ longRunningReminder
21154
+ ].filter(Boolean).join("\n\n") || void 0;
21155
+ const prGateDirective = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && mentionsPrGoal(expandedPrompt) ? formatPrGateDirective() : null;
21156
+ const agentPrompt = [
21157
+ thread.planMode ? PLAN_MODE_INSTRUCTION : null,
21158
+ orchestrationReminder,
21159
+ prGateDirective,
21031
21160
  slackReplyContext,
21032
- expandedPrompt
21161
+ expandCanonicalGitRequest(expandedPrompt)
21033
21162
  ].filter(Boolean).join("\n\n");
21034
21163
  if (thread.attachments.length > 0) {
21035
21164
  updateThread(threadId, { attachments: [] });
@@ -21119,7 +21248,7 @@ var init_orchestrator = __esm({
21119
21248
  const stderrTail = [];
21120
21249
  const handle = await spawnAgentTurn(
21121
21250
  fresh,
21122
- { cachedPrefix, prompt: agentPrompt },
21251
+ { cachedPrefix, prompt: agentPrompt, systemPrompt: turnReminders },
21123
21252
  (event) => {
21124
21253
  this.emit({ type: "turn_output", threadId, event });
21125
21254
  noteTurnLiveEvent(threadId, event);
@@ -21228,7 +21357,7 @@ var init_orchestrator = __esm({
21228
21357
  ].filter(Boolean).join("\n\n---\n\n");
21229
21358
  const retryHandle = await spawnAgentTurn(
21230
21359
  retryThread,
21231
- { cachedPrefix: retryPrefix, prompt: agentPrompt },
21360
+ { cachedPrefix: retryPrefix, prompt: agentPrompt, systemPrompt: turnReminders },
21232
21361
  (event) => {
21233
21362
  this.emit({ type: "turn_output", threadId, event });
21234
21363
  if (event.type === "session_id") {
@@ -22415,7 +22544,7 @@ async function defaultDeps() {
22415
22544
  }
22416
22545
  function pickAgent(schedule) {
22417
22546
  if (schedule.agent) return schedule.agent;
22418
- return coerceOrchestratorAgent(resolveThreadDefaults().agent);
22547
+ return coerceOrchestratorAgent(resolveOrchestratorDefaults().agent);
22419
22548
  }
22420
22549
  async function fireSchedule(id) {
22421
22550
  const schedule = getSchedule(id);
@@ -22587,6 +22716,7 @@ __export(index_exports, {
22587
22716
  PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
22588
22717
  PLAN_QUESTION_ANSWERS_PREFIX: () => PLAN_QUESTION_ANSWERS_PREFIX,
22589
22718
  PROFILE_NOTES_MAX: () => PROFILE_NOTES_MAX,
22719
+ PR_DETAILS_JSON_FIELDS: () => PR_DETAILS_JSON_FIELDS,
22590
22720
  REPO_REVIEW_NAME: () => REPO_REVIEW_NAME,
22591
22721
  REPO_REVIEW_PATH: () => REPO_REVIEW_PATH,
22592
22722
  REVIEW_REQUEST_NAME: () => REVIEW_REQUEST_NAME,
@@ -22595,6 +22725,8 @@ __export(index_exports, {
22595
22725
  REVIEW_REQUEST_TEMPLATE: () => REVIEW_REQUEST_TEMPLATE,
22596
22726
  REVIEW_SKILL_NAME: () => REVIEW_SKILL_NAME,
22597
22727
  REVIEW_SKILL_PATH: () => REVIEW_SKILL_PATH,
22728
+ SEED_FULL_TOOL_MESSAGES: () => SEED_FULL_TOOL_MESSAGES,
22729
+ SEED_MAX_CHARS: () => SEED_MAX_CHARS,
22598
22730
  SESSION_RESET_OCCUPANCY_TOKENS: () => SESSION_RESET_OCCUPANCY_TOKENS,
22599
22731
  SIDEBOARD_FORCE_STOP: () => SIDEBOARD_FORCE_STOP,
22600
22732
  SIDEBOARD_MCP_ALLOWED_TOOLS: () => SIDEBOARD_MCP_ALLOWED_TOOLS,
@@ -22802,7 +22934,6 @@ __export(index_exports, {
22802
22934
  forkMessageSlice: () => forkMessageSlice,
22803
22935
  forkThreadWorktree: () => forkThreadWorktree,
22804
22936
  formatAccountProfilePlaybookLine: () => formatAccountProfilePlaybookLine,
22805
- formatAgentInstructions: () => formatAgentInstructions,
22806
22937
  formatArtifactDirective: () => formatArtifactDirective,
22807
22938
  formatBrightsyFetchError: () => formatBrightsyFetchError,
22808
22939
  formatDetachedJobInvoke: () => formatDetachedJobInvoke,
@@ -23007,7 +23138,6 @@ __export(index_exports, {
23007
23138
  listWorktreeFiles: () => listWorktreeFiles,
23008
23139
  listWorktrees: () => listWorktrees,
23009
23140
  liveActivitySummary: () => liveActivitySummary,
23010
- loadAgentInstructions: () => loadAgentInstructions,
23011
23141
  loadAppSettings: () => loadAppSettings,
23012
23142
  loadBrightsyConfig: () => loadBrightsyConfig,
23013
23143
  loadConductorSettings: () => loadConductorSettings,
@@ -23024,6 +23154,7 @@ __export(index_exports, {
23024
23154
  mcpAllowTools: () => mcpAllowTools,
23025
23155
  mcpAuthWarnings: () => mcpAuthWarnings,
23026
23156
  mcpStatusThinkingFromClaudeInit: () => mcpStatusThinkingFromClaudeInit,
23157
+ mentionsPrGoal: () => mentionsPrGoal,
23027
23158
  mergeAgentGitAuthEnv: () => mergeAgentGitAuthEnv,
23028
23159
  mergePr: () => mergePr,
23029
23160
  mergePrStack: () => mergePrStack,
@@ -23064,6 +23195,7 @@ __export(index_exports, {
23064
23195
  parseGithubSlugFromRemoteUrl: () => parseGithubSlugFromRemoteUrl,
23065
23196
  parseMcpList: () => parseMcpList,
23066
23197
  parsePlanQuestionsInput: () => parsePlanQuestionsInput,
23198
+ parsePrDetailsView: () => parsePrDetailsView,
23067
23199
  parseSessionQuotaResetAt: () => parseSessionQuotaResetAt,
23068
23200
  parseSlackRelayClientMessage: () => parseSlackRelayClientMessage,
23069
23201
  parseSlackRelayServerMessage: () => parseSlackRelayServerMessage,
@@ -23131,7 +23263,9 @@ __export(index_exports, {
23131
23263
  resolveLinearState: () => resolveLinearState,
23132
23264
  resolveLinearTeam: () => resolveLinearTeam,
23133
23265
  resolveLoginCommand: () => resolveLoginCommand,
23266
+ resolveNewOrchestratorOptions: () => resolveNewOrchestratorOptions,
23134
23267
  resolveNewThreadOptions: () => resolveNewThreadOptions,
23268
+ resolveOrchestratorDefaults: () => resolveOrchestratorDefaults,
23135
23269
  resolvePlanMarkdown: () => resolvePlanMarkdown,
23136
23270
  resolvePrSelector: () => resolvePrSelector,
23137
23271
  resolvePrSelectors: () => resolvePrSelectors,
@@ -23194,6 +23328,7 @@ __export(index_exports, {
23194
23328
  slugify: () => slugify,
23195
23329
  spawnAgentTurn: () => spawnAgentTurn,
23196
23330
  splitForCompaction: () => splitForCompaction,
23331
+ splitTurnInputForSystemPrompt: () => splitTurnInputForSystemPrompt,
23197
23332
  stackAgentDefaultsFrom: () => stackAgentDefaultsFrom,
23198
23333
  stackIdFrom: () => stackIdFrom,
23199
23334
  stackMergeReadiness: () => stackMergeReadiness,
@@ -23228,6 +23363,7 @@ __export(index_exports, {
23228
23363
  threadRequestsBrightsyMcp: () => threadRequestsBrightsyMcp,
23229
23364
  threadsDir: () => threadsDir,
23230
23365
  threadsSharingWorktree: () => threadsSharingWorktree,
23366
+ ticketSlugForBranch: () => ticketSlugForBranch,
23231
23367
  toAbleTimeIssueInfo: () => toAbleTimeIssueInfo,
23232
23368
  toGitHubIssueInfo: () => toGitHubIssueInfo,
23233
23369
  toPublicAppSettings: () => toPublicAppSettings,
@@ -23262,7 +23398,6 @@ __export(index_exports, {
23262
23398
  waitForPidExit: () => waitForPidExit,
23263
23399
  warmGithubAgentAuth: () => warmGithubAgentAuth,
23264
23400
  whichOnPath: () => whichOnPath,
23265
- withAgentInstructions: () => withAgentInstructions,
23266
23401
  withEventParentId: () => withEventParentId,
23267
23402
  withEventsParentId: () => withEventsParentId,
23268
23403
  withExportedPath: () => withExportedPath,
@@ -23274,6 +23409,7 @@ __export(index_exports, {
23274
23409
  worktreeDisplayLabel: () => worktreeDisplayLabel,
23275
23410
  worktreeDisplayLabelForGroup: () => worktreeDisplayLabelForGroup,
23276
23411
  worktreeNameFromPath: () => worktreeNameFromPath,
23412
+ worktreeSlugForTicket: () => worktreeSlugForTicket,
23277
23413
  worktreesRoot: () => worktreesRoot,
23278
23414
  wrapReviewSkillMarkdown: () => wrapReviewSkillMarkdown,
23279
23415
  writeInjectedMcpConfig: () => writeInjectedMcpConfig,
@@ -30309,6 +30445,7 @@ init_outbound_watch();
30309
30445
  PLAN_MODE_INSTRUCTION,
30310
30446
  PLAN_QUESTION_ANSWERS_PREFIX,
30311
30447
  PROFILE_NOTES_MAX,
30448
+ PR_DETAILS_JSON_FIELDS,
30312
30449
  REPO_REVIEW_NAME,
30313
30450
  REPO_REVIEW_PATH,
30314
30451
  REVIEW_REQUEST_NAME,
@@ -30317,6 +30454,8 @@ init_outbound_watch();
30317
30454
  REVIEW_REQUEST_TEMPLATE,
30318
30455
  REVIEW_SKILL_NAME,
30319
30456
  REVIEW_SKILL_PATH,
30457
+ SEED_FULL_TOOL_MESSAGES,
30458
+ SEED_MAX_CHARS,
30320
30459
  SESSION_RESET_OCCUPANCY_TOKENS,
30321
30460
  SIDEBOARD_FORCE_STOP,
30322
30461
  SIDEBOARD_MCP_ALLOWED_TOOLS,
@@ -30524,7 +30663,6 @@ init_outbound_watch();
30524
30663
  forkMessageSlice,
30525
30664
  forkThreadWorktree,
30526
30665
  formatAccountProfilePlaybookLine,
30527
- formatAgentInstructions,
30528
30666
  formatArtifactDirective,
30529
30667
  formatBrightsyFetchError,
30530
30668
  formatDetachedJobInvoke,
@@ -30729,7 +30867,6 @@ init_outbound_watch();
30729
30867
  listWorktreeFiles,
30730
30868
  listWorktrees,
30731
30869
  liveActivitySummary,
30732
- loadAgentInstructions,
30733
30870
  loadAppSettings,
30734
30871
  loadBrightsyConfig,
30735
30872
  loadConductorSettings,
@@ -30746,6 +30883,7 @@ init_outbound_watch();
30746
30883
  mcpAllowTools,
30747
30884
  mcpAuthWarnings,
30748
30885
  mcpStatusThinkingFromClaudeInit,
30886
+ mentionsPrGoal,
30749
30887
  mergeAgentGitAuthEnv,
30750
30888
  mergePr,
30751
30889
  mergePrStack,
@@ -30786,6 +30924,7 @@ init_outbound_watch();
30786
30924
  parseGithubSlugFromRemoteUrl,
30787
30925
  parseMcpList,
30788
30926
  parsePlanQuestionsInput,
30927
+ parsePrDetailsView,
30789
30928
  parseSessionQuotaResetAt,
30790
30929
  parseSlackRelayClientMessage,
30791
30930
  parseSlackRelayServerMessage,
@@ -30853,7 +30992,9 @@ init_outbound_watch();
30853
30992
  resolveLinearState,
30854
30993
  resolveLinearTeam,
30855
30994
  resolveLoginCommand,
30995
+ resolveNewOrchestratorOptions,
30856
30996
  resolveNewThreadOptions,
30997
+ resolveOrchestratorDefaults,
30857
30998
  resolvePlanMarkdown,
30858
30999
  resolvePrSelector,
30859
31000
  resolvePrSelectors,
@@ -30916,6 +31057,7 @@ init_outbound_watch();
30916
31057
  slugify,
30917
31058
  spawnAgentTurn,
30918
31059
  splitForCompaction,
31060
+ splitTurnInputForSystemPrompt,
30919
31061
  stackAgentDefaultsFrom,
30920
31062
  stackIdFrom,
30921
31063
  stackMergeReadiness,
@@ -30950,6 +31092,7 @@ init_outbound_watch();
30950
31092
  threadRequestsBrightsyMcp,
30951
31093
  threadsDir,
30952
31094
  threadsSharingWorktree,
31095
+ ticketSlugForBranch,
30953
31096
  toAbleTimeIssueInfo,
30954
31097
  toGitHubIssueInfo,
30955
31098
  toPublicAppSettings,
@@ -30984,7 +31127,6 @@ init_outbound_watch();
30984
31127
  waitForPidExit,
30985
31128
  warmGithubAgentAuth,
30986
31129
  whichOnPath,
30987
- withAgentInstructions,
30988
31130
  withEventParentId,
30989
31131
  withEventsParentId,
30990
31132
  withExportedPath,
@@ -30996,6 +31138,7 @@ init_outbound_watch();
30996
31138
  worktreeDisplayLabel,
30997
31139
  worktreeDisplayLabelForGroup,
30998
31140
  worktreeNameFromPath,
31141
+ worktreeSlugForTicket,
30999
31142
  worktreesRoot,
31000
31143
  wrapReviewSkillMarkdown,
31001
31144
  writeInjectedMcpConfig,