@sideboard-ai/core 0.1.251 → 0.1.253

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/{agents-FY2DFOMV.js → agents-6HDC7UA7.js} +3 -3
  2. package/dist/{agents-PU2P5VWM.js → agents-RKZ2NBIV.js} +3 -3
  3. package/dist/{chunk-6Z66OYYO.js → chunk-46KDLP6T.js} +50 -26
  4. package/dist/{chunk-GNO7RXNH.js → chunk-6ZYSXLXK.js} +37 -14
  5. package/dist/{chunk-2LZ3CNTN.js → chunk-GZRS5QVL.js} +52 -27
  6. package/dist/{chunk-PL23EQ3S.js → chunk-IAS7Q2YF.js} +2 -2
  7. package/dist/{chunk-TMLS5WYR.js → chunk-JUYD2YUC.js} +2 -2
  8. package/dist/{chunk-7R5I5UWW.js → chunk-MLB5CFUP.js} +44 -15
  9. package/dist/{chunk-WI75LO3T.js → chunk-PLMMPA6A.js} +62 -13
  10. package/dist/{chunk-JLLISK4D.js → chunk-WVNQML4W.js} +62 -13
  11. package/dist/{coordinator-prompt-6CWVH2US.js → coordinator-prompt-JKW7YZOC.js} +2 -2
  12. package/dist/{coordinator-prompt-R7JNOUZ3.js → coordinator-prompt-YSIC6YFC.js} +2 -2
  13. package/dist/{global-workspace-GTEL4UUZ.js → global-workspace-3Q57XYG4.js} +2 -2
  14. package/dist/{global-workspace-DWKW4CFY.js → global-workspace-DMR5JB7T.js} +2 -2
  15. package/dist/index.cjs +738 -628
  16. package/dist/index.d.cts +36 -9
  17. package/dist/index.d.ts +36 -9
  18. package/dist/index.js +24 -14
  19. package/dist/mcp/run-stdio.cjs +152 -52
  20. package/dist/mcp/run-stdio.js +21 -14
  21. package/dist/{orchestrator-7XDC4UOC.js → orchestrator-PJCQSVLY.js} +4 -4
  22. package/dist/{orchestrator-W7A5BA5V.js → orchestrator-W6DUFWVE.js} +4 -4
  23. package/dist/{workspaces-E6IL3MIH.js → workspaces-6A3ASHHI.js} +2 -2
  24. package/dist/{workspaces-PSDDVERD.js → workspaces-PS3IO4VJ.js} +2 -2
  25. package/dist/{worktree-MWX6ZVNS.js → worktree-7WTVHFGF.js} +1 -1
  26. package/dist/{worktree-Q4T7RSSW.js → worktree-DLSVHUF6.js} +1 -1
  27. package/package.json +1 -1
@@ -46,9 +46,9 @@ import {
46
46
  resolveLoginCommand,
47
47
  resolveQuotaFallbackAgent,
48
48
  whichOnPath
49
- } from "./chunk-7R5I5UWW.js";
50
- import "./chunk-TMLS5WYR.js";
51
- import "./chunk-WI75LO3T.js";
49
+ } from "./chunk-MLB5CFUP.js";
50
+ import "./chunk-JUYD2YUC.js";
51
+ import "./chunk-PLMMPA6A.js";
52
52
  import "./chunk-6K64FJDD.js";
53
53
  import "./chunk-2P4XKWV2.js";
54
54
  import "./chunk-5F4YFGHL.js";
@@ -55,12 +55,12 @@ import {
55
55
  resolveQuotaFallbackAgent,
56
56
  turnCostUsdFromCursorUsage,
57
57
  whichOnPath
58
- } from "./chunk-GNO7RXNH.js";
59
- import "./chunk-PL23EQ3S.js";
58
+ } from "./chunk-6ZYSXLXK.js";
59
+ import "./chunk-IAS7Q2YF.js";
60
60
  import "./chunk-XAISOBBG.js";
61
61
  import "./chunk-P2BSMNHB.js";
62
62
  import "./chunk-VKQGAWHY.js";
63
- import "./chunk-JLLISK4D.js";
63
+ import "./chunk-WVNQML4W.js";
64
64
  import "./chunk-D6JWYJ4P.js";
65
65
  import "./chunk-RJC2MKXN.js";
66
66
  import "./chunk-H547WSSZ.js";
@@ -44,7 +44,7 @@ import {
44
44
  summarizeTurnStderr,
45
45
  toolDescription,
46
46
  turnFailChatText
47
- } from "./chunk-GNO7RXNH.js";
47
+ } from "./chunk-6ZYSXLXK.js";
48
48
  import {
49
49
  SLACK_REPLY_FORMATTING,
50
50
  addWorkspace,
@@ -67,7 +67,7 @@ import {
67
67
  stageAbsolutePathsAsAttachments,
68
68
  stageBuffersAsAttachments,
69
69
  syncWorkspacesFromThreads
70
- } from "./chunk-PL23EQ3S.js";
70
+ } from "./chunk-IAS7Q2YF.js";
71
71
  import {
72
72
  addPrStackLayer,
73
73
  allocateTeamName,
@@ -117,7 +117,7 @@ import {
117
117
  worktreeDisplayLabelForGroup,
118
118
  worktreeNameFromPath,
119
119
  worktreeSlugForTicket
120
- } from "./chunk-JLLISK4D.js";
120
+ } from "./chunk-WVNQML4W.js";
121
121
  import {
122
122
  ATTACHMENTS_DIR,
123
123
  DETACHED_JOBS_DIR,
@@ -152,6 +152,7 @@ import {
152
152
  applyTurnUsage,
153
153
  assertOrchestratorCapableAgent,
154
154
  autoCleanupHistoryEnabled,
155
+ caffeinateWhileSchedulesEnabled,
155
156
  childEnvWithAppSettings,
156
157
  coerceOrchestratorAgent,
157
158
  contextTokens,
@@ -491,9 +492,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
491
492
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
492
493
  );
493
494
  }
494
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-DWKW4CFY.js");
495
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-DMR5JB7T.js");
495
496
  if (isGlobalThread2(thread)) {
496
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-6CWVH2US.js");
497
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-JKW7YZOC.js");
497
498
  ensureGlobalCoordinatorCwd2(
498
499
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
499
500
  );
@@ -4050,6 +4051,7 @@ async function createThread(input, _onSetupLine) {
4050
4051
  let prTitle = null;
4051
4052
  let prAuthorLogin2 = null;
4052
4053
  let prLabels = [];
4054
+ let prIsDraft = false;
4053
4055
  if (sourceType === "pr") {
4054
4056
  const num = Number(input.sourceRef.replace(/^#/, ""));
4055
4057
  if (!Number.isFinite(num)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
@@ -4067,6 +4069,7 @@ async function createThread(input, _onSetupLine) {
4067
4069
  prUrl = pr.url;
4068
4070
  prAuthorLogin2 = pr.author?.login?.trim() || null;
4069
4071
  prLabels = pr.labels ?? [];
4072
+ prIsDraft = Boolean(pr.isDraft);
4070
4073
  const localFetchBranch = `sideboard-pr-${pr.number}`;
4071
4074
  await fetchPrHead(repoPath, pr.number, localFetchBranch);
4072
4075
  sourceRef = localFetchBranch;
@@ -4091,6 +4094,7 @@ async function createThread(input, _onSetupLine) {
4091
4094
  prTitle = existing.title;
4092
4095
  prAuthorLogin2 = existing.author?.login?.trim() || null;
4093
4096
  prLabels = existing.labels ?? [];
4097
+ prIsDraft = Boolean(existing.isDraft);
4094
4098
  }
4095
4099
  }
4096
4100
  }
@@ -4127,7 +4131,8 @@ async function createThread(input, _onSetupLine) {
4127
4131
  prUrl,
4128
4132
  prTitle,
4129
4133
  prAuthorLogin: prAuthorLogin2,
4130
- prLabels
4134
+ prLabels,
4135
+ prIsDraft
4131
4136
  });
4132
4137
  writeThread(thread);
4133
4138
  await ensureWorkspace(repoPath);
@@ -4595,7 +4600,7 @@ async function adoptThread(input) {
4595
4600
  messages: input.messages ?? []
4596
4601
  });
4597
4602
  writeThread(thread);
4598
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-E6IL3MIH.js");
4603
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-6A3ASHHI.js");
4599
4604
  await ensureWorkspace2(repoPath);
4600
4605
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-5N2KTYIT.js");
4601
4606
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -6581,11 +6586,15 @@ function formatWorktreeDirective(thread, opts) {
6581
6586
  lines.push("");
6582
6587
  lines.push(formatDevAccessHint(opts?.activeRuns));
6583
6588
  lines.push("");
6589
+ lines.push(
6590
+ "Schedules: `create_schedule` / `list_schedules` (`at` / `every` / `cron`). `threadId=self` continues this chat; omit threadId for a new Global chat. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled."
6591
+ );
6592
+ lines.push("");
6584
6593
  lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
6585
6594
  return lines.join("\n");
6586
6595
  }
6587
6596
  function formatWorktreeReminder() {
6588
- 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.";
6597
+ 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. Schedules: create_schedule (at / every / cron; threadId=self for this chat).";
6589
6598
  }
6590
6599
  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;
6591
6600
  function mentionsPrGoal(prompt) {
@@ -6895,7 +6904,7 @@ function resolveScheduleThreadId(raw, env = process.env) {
6895
6904
  const value = raw?.trim() || "";
6896
6905
  if (!value) return null;
6897
6906
  if (value.toLowerCase() === "self") {
6898
- return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
6907
+ return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || env.SIDEBOARD_THREAD_ID?.trim() || null;
6899
6908
  }
6900
6909
  return value;
6901
6910
  }
@@ -7023,6 +7032,17 @@ function buildTask(input, now) {
7023
7032
  function listSchedules() {
7024
7033
  return readAll().sort((a, b) => a.nextRunAt.localeCompare(b.nextRunAt));
7025
7034
  }
7035
+ function scheduleNeedsCaffeinate(task, now = /* @__PURE__ */ new Date()) {
7036
+ if (!task.enabled) return false;
7037
+ const at = new Date(task.nextRunAt);
7038
+ if (Number.isNaN(at.getTime())) return false;
7039
+ return at.getTime() > now.getTime();
7040
+ }
7041
+ function ensureCaffeinateForFutureSchedule(task) {
7042
+ if (!scheduleNeedsCaffeinate(task)) return;
7043
+ if (caffeinateWhileSchedulesEnabled()) return;
7044
+ updateAdvancedSettings({ caffeinateWhileSchedules: true });
7045
+ }
7026
7046
  function getSchedule(id) {
7027
7047
  const key = id.trim();
7028
7048
  if (!key) return null;
@@ -7035,6 +7055,7 @@ function createSchedule(input) {
7035
7055
  const rows = readAll();
7036
7056
  rows.push(task);
7037
7057
  writeAll(rows);
7058
+ ensureCaffeinateForFutureSchedule(task);
7038
7059
  return task;
7039
7060
  }
7040
7061
  function updateSchedule(id, patch) {
@@ -7061,6 +7082,7 @@ function updateSchedule(id, patch) {
7061
7082
  };
7062
7083
  rows[idx] = next;
7063
7084
  writeAll(rows);
7085
+ ensureCaffeinateForFutureSchedule(next);
7064
7086
  return next;
7065
7087
  }
7066
7088
  function deleteSchedule(id) {
@@ -7101,7 +7123,7 @@ function formatScheduledPrompt(name, prompt) {
7101
7123
  ${prompt}`;
7102
7124
  }
7103
7125
  async function defaultDeps() {
7104
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-W7A5BA5V.js");
7126
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-W6DUFWVE.js");
7105
7127
  const orch = getOrchestrator2();
7106
7128
  return {
7107
7129
  findThread: (id) => findThreadByRef(id),
@@ -7121,19 +7143,9 @@ async function fireSchedule(id) {
7121
7143
  try {
7122
7144
  const deps = fireHooks ?? await defaultDeps();
7123
7145
  const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
7124
- if (schedule.threadId) {
7125
- const thread = deps.findThread(schedule.threadId);
7126
- if (!thread || thread.status === "archived") {
7127
- return recordScheduleRun(schedule.id, {
7128
- lastError: thread ? `Orchestration chat ${schedule.threadId} is archived` : `Orchestration chat not found: ${schedule.threadId}`
7129
- });
7130
- }
7131
- if (!isOrchestratorThread(thread)) {
7132
- return recordScheduleRun(schedule.id, {
7133
- lastError: `Thread ${schedule.threadId} is not an orchestration chat`
7134
- });
7135
- }
7136
- const sent = await deps.send(thread.id, prompt);
7146
+ const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
7147
+ if (target && target.status !== "archived") {
7148
+ const sent = await deps.send(target.id, prompt);
7137
7149
  return recordScheduleRun(schedule.id, {
7138
7150
  lastThreadId: sent.id,
7139
7151
  lastError: null
@@ -7144,6 +7156,9 @@ async function fireSchedule(id) {
7144
7156
  agent: pickAgent(schedule),
7145
7157
  model: schedule.model
7146
7158
  });
7159
+ if (schedule.threadId && schedule.when.kind !== "once") {
7160
+ updateSchedule(schedule.id, { threadId: created.id });
7161
+ }
7147
7162
  return recordScheduleRun(schedule.id, {
7148
7163
  lastThreadId: created.id,
7149
7164
  lastError: null
@@ -9298,6 +9313,14 @@ var Orchestrator = class {
9298
9313
  const thread = this.requireThread(threadRef);
9299
9314
  return discoverSkills(thread.worktreePath);
9300
9315
  }
9316
+ /** Skills for a project folder before a worktree exists (create modal). */
9317
+ listSkillsForRepo(repoPath) {
9318
+ const root = repoPath.trim();
9319
+ if (!root || root === "/" || root === ".") {
9320
+ return discoverSkills("/__sideboard_no_workspace__");
9321
+ }
9322
+ return discoverSkills(root);
9323
+ }
9301
9324
  async previewLand(threadRef) {
9302
9325
  const thread = this.requireThread(threadRef);
9303
9326
  this.assertNotGlobal(thread, "Land");
@@ -9726,7 +9749,7 @@ var Orchestrator = class {
9726
9749
  this.enforceHistoryRetention();
9727
9750
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
9728
9751
  try {
9729
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-E6IL3MIH.js");
9752
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-6A3ASHHI.js");
9730
9753
  await ensureWorkspace2(thread.repoPath);
9731
9754
  } catch {
9732
9755
  }
@@ -9780,7 +9803,7 @@ var Orchestrator = class {
9780
9803
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
9781
9804
  );
9782
9805
  }
9783
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-MWX6ZVNS.js");
9806
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-7WTVHFGF.js");
9784
9807
  const slug = thread.worktreePath.split("/").pop();
9785
9808
  const dest = thread.worktreePath;
9786
9809
  await withRepoGitLock(thread.repoPath, async () => {
@@ -9890,7 +9913,7 @@ async function startOrchestration(opts) {
9890
9913
  sourceRef: "default",
9891
9914
  ...createOpts
9892
9915
  }).catch(async () => {
9893
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-MWX6ZVNS.js");
9916
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-7WTVHFGF.js");
9894
9917
  const repo = await resolveRepoRoot2(repoPath);
9895
9918
  const def = await resolveDefaultBranch2(repo);
9896
9919
  return orch.createThread({
@@ -9941,6 +9964,7 @@ export {
9941
9964
  localhostPreviewUrl,
9942
9965
  resolveScheduleThreadId,
9943
9966
  listSchedules,
9967
+ scheduleNeedsCaffeinate,
9944
9968
  getSchedule,
9945
9969
  createSchedule,
9946
9970
  updateSchedule,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  isOrchestratorThread
5
- } from "./chunk-PL23EQ3S.js";
5
+ } from "./chunk-IAS7Q2YF.js";
6
6
  import {
7
7
  applyConnectedTeamToCli,
8
8
  brightsyMcpServerName,
@@ -20,7 +20,7 @@ import {
20
20
  mergeAgentGitAuthEnv,
21
21
  resolveAgentGitAuthEnv,
22
22
  resolveCodexGitWritableRoots
23
- } from "./chunk-JLLISK4D.js";
23
+ } from "./chunk-WVNQML4W.js";
24
24
  import {
25
25
  enrichPathWithNpmGlobalBin,
26
26
  isConductorBundledCli,
@@ -1240,7 +1240,12 @@ var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
1240
1240
  "mcp__sideboard__get_run_log",
1241
1241
  "mcp__sideboard__notify_orchestrator",
1242
1242
  "mcp__sideboard__get_viewer_context",
1243
- "mcp__sideboard__update_viewer_context"
1243
+ "mcp__sideboard__update_viewer_context",
1244
+ "mcp__sideboard__list_schedules",
1245
+ "mcp__sideboard__create_schedule",
1246
+ "mcp__sideboard__update_schedule",
1247
+ "mcp__sideboard__delete_schedule",
1248
+ "mcp__sideboard__run_schedule"
1244
1249
  ];
1245
1250
  var SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS = ["mcp__sideboard__github_*"];
1246
1251
  var SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS = ["mcp__sideboard__linear_*"];
@@ -1744,6 +1749,15 @@ function isContextCompactInProgress(text) {
1744
1749
  if (isContextCompactDone(t)) return false;
1745
1750
  return /^Compressing context/i.test(t);
1746
1751
  }
1752
+ function isSystemStatusThinking(event) {
1753
+ if (event.replace) return true;
1754
+ const t = (event.data ?? "").trim();
1755
+ if (!t) return true;
1756
+ if (/^API retry\b/i.test(t)) return true;
1757
+ if (/^MCP:/i.test(t)) return true;
1758
+ if (isContextCompactInProgress(t) || isContextCompactDone(t)) return true;
1759
+ return false;
1760
+ }
1747
1761
  function looksLikeConversationSummary(text) {
1748
1762
  const t = text.trim();
1749
1763
  if (t.length < 80) return false;
@@ -1821,6 +1835,13 @@ function toolDescription(name, input) {
1821
1835
  return str(input?.name) ? `Read ${str(input?.name)} log` : "Read Dev log";
1822
1836
  }
1823
1837
  if (/notify_orchestrator$/i.test(name)) return "Notify orchestrator";
1838
+ if (/list_schedules$/i.test(name)) return "List schedules";
1839
+ if (/create_schedule$/i.test(name)) {
1840
+ return str(input?.name) ? `Schedule ${str(input?.name)}` : "Create schedule";
1841
+ }
1842
+ if (/update_schedule$/i.test(name)) return "Update schedule";
1843
+ if (/delete_schedule$/i.test(name)) return "Delete schedule";
1844
+ if (/run_schedule$/i.test(name)) return "Run schedule";
1824
1845
  if (isSkillToolName(name)) {
1825
1846
  const cmd = skillCommandFromInput(input);
1826
1847
  return cmd ? `Using /${cmd}` : "Using skill";
@@ -2198,15 +2219,6 @@ function applyAgentEvent(parts, event) {
2198
2219
  );
2199
2220
  return next2;
2200
2221
  }
2201
- if (contextCompactInProgress(parts, event.parentId)) {
2202
- return [
2203
- ...parts,
2204
- compactToolPart(data, `compact-${parts.length}`, {
2205
- parentId: event.parentId,
2206
- status: "running"
2207
- })
2208
- ];
2209
- }
2210
2222
  const runningSkillIdx = lastRunningSkillIndex(parts, event.parentId);
2211
2223
  if (runningSkillIdx >= 0) {
2212
2224
  const prev = parts[runningSkillIdx];
@@ -2225,6 +2237,15 @@ function applyAgentEvent(parts, event) {
2225
2237
  );
2226
2238
  return next2;
2227
2239
  }
2240
+ if (contextCompactInProgress(parts, event.parentId)) {
2241
+ return [
2242
+ ...parts,
2243
+ compactToolPart(data, `compact-${parts.length}`, {
2244
+ parentId: event.parentId,
2245
+ status: "running"
2246
+ })
2247
+ ];
2248
+ }
2228
2249
  const next = [...parts];
2229
2250
  const last = next[next.length - 1];
2230
2251
  if (last?.type === "text" && sameParentId(last.parentId, event.parentId)) {
@@ -2261,7 +2282,9 @@ function applyAgentEvent(parts, event) {
2261
2282
  if (event.type === "thinking") {
2262
2283
  const data = event.data;
2263
2284
  if (!data) return parts;
2264
- parts = markRunningSkillsDone(parts, event.parentId);
2285
+ if (!isSystemStatusThinking(event)) {
2286
+ parts = markRunningSkillsDone(parts, event.parentId);
2287
+ }
2265
2288
  const next = [...parts];
2266
2289
  if (event.replace) {
2267
2290
  for (let i = next.length - 1; i >= 0; i--) {
@@ -2947,7 +2970,7 @@ var claudeAdapter = {
2947
2970
  );
2948
2971
  }
2949
2972
  const mode = permissionMode(thread);
2950
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-DWKW4CFY.js");
2973
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-DMR5JB7T.js");
2951
2974
  const isOrchestrator = isOrchestratorThread2(thread);
2952
2975
  const injectedServers = await buildInjectedMcpServers({
2953
2976
  includeSideboard: true,
@@ -25,7 +25,7 @@ import {
25
25
  resolveQuotaFallbackAgent,
26
26
  stripBrightsyNdjsonNoise,
27
27
  toolDescription
28
- } from "./chunk-7R5I5UWW.js";
28
+ } from "./chunk-MLB5CFUP.js";
29
29
  import {
30
30
  SLACK_REPLY_FORMATTING,
31
31
  addWorkspace,
@@ -48,7 +48,7 @@ import {
48
48
  stageAbsolutePathsAsAttachments,
49
49
  stageBuffersAsAttachments,
50
50
  syncWorkspacesFromThreads
51
- } from "./chunk-TMLS5WYR.js";
51
+ } from "./chunk-JUYD2YUC.js";
52
52
  import {
53
53
  addPrStackLayer,
54
54
  allocateTeamName,
@@ -98,7 +98,7 @@ import {
98
98
  worktreeDisplayLabelForGroup,
99
99
  worktreeNameFromPath,
100
100
  worktreeSlugForTicket
101
- } from "./chunk-WI75LO3T.js";
101
+ } from "./chunk-PLMMPA6A.js";
102
102
  import {
103
103
  ATTACHMENTS_DIR,
104
104
  DETACHED_JOBS_DIR,
@@ -136,6 +136,7 @@ import {
136
136
  applyTurnUsage,
137
137
  assertOrchestratorCapableAgent,
138
138
  autoCleanupHistoryEnabled,
139
+ caffeinateWhileSchedulesEnabled,
139
140
  childEnvWithAppSettings,
140
141
  coerceOrchestratorAgent,
141
142
  contextTokens,
@@ -443,9 +444,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
443
444
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
444
445
  );
445
446
  }
446
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-GTEL4UUZ.js");
447
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-3Q57XYG4.js");
447
448
  if (isGlobalThread2(thread)) {
448
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-R7JNOUZ3.js");
449
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-YSIC6YFC.js");
449
450
  ensureGlobalCoordinatorCwd2(
450
451
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
451
452
  );
@@ -3662,6 +3663,7 @@ function classifyWorktreeListBadges(group, viewerLogin = "", reviewLabel = "") {
3662
3663
  }
3663
3664
  ];
3664
3665
  }
3666
+ if (!normalizeViewerLogin(viewerLogin)) return [];
3665
3667
  const draft = open.some((t) => t.prIsDraft);
3666
3668
  const readyLabel = reviewLabel.trim();
3667
3669
  const inReview = readyLabel ? labelsInclude(groupPrLabels(group), readyLabel) : !draft;
@@ -4246,6 +4248,7 @@ async function createThread(input, _onSetupLine) {
4246
4248
  let prTitle = null;
4247
4249
  let prAuthorLogin2 = null;
4248
4250
  let prLabels = [];
4251
+ let prIsDraft = false;
4249
4252
  if (sourceType === "pr") {
4250
4253
  const num = Number(input.sourceRef.replace(/^#/, ""));
4251
4254
  if (!Number.isFinite(num)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
@@ -4263,6 +4266,7 @@ async function createThread(input, _onSetupLine) {
4263
4266
  prUrl = pr.url;
4264
4267
  prAuthorLogin2 = pr.author?.login?.trim() || null;
4265
4268
  prLabels = pr.labels ?? [];
4269
+ prIsDraft = Boolean(pr.isDraft);
4266
4270
  const localFetchBranch = `sideboard-pr-${pr.number}`;
4267
4271
  await fetchPrHead(repoPath, pr.number, localFetchBranch);
4268
4272
  sourceRef = localFetchBranch;
@@ -4287,6 +4291,7 @@ async function createThread(input, _onSetupLine) {
4287
4291
  prTitle = existing.title;
4288
4292
  prAuthorLogin2 = existing.author?.login?.trim() || null;
4289
4293
  prLabels = existing.labels ?? [];
4294
+ prIsDraft = Boolean(existing.isDraft);
4290
4295
  }
4291
4296
  }
4292
4297
  }
@@ -4323,14 +4328,15 @@ async function createThread(input, _onSetupLine) {
4323
4328
  prUrl,
4324
4329
  prTitle,
4325
4330
  prAuthorLogin: prAuthorLogin2,
4326
- prLabels
4331
+ prLabels,
4332
+ prIsDraft
4327
4333
  });
4328
4334
  writeThread(thread);
4329
4335
  await ensureWorkspace(repoPath);
4330
4336
  return readThread(thread.id) ?? thread;
4331
4337
  }
4332
4338
  async function listLinearIssues(agent, repoPath) {
4333
- const { getAdapter: getAdapter2 } = await import("./agents-FY2DFOMV.js");
4339
+ const { getAdapter: getAdapter2 } = await import("./agents-6HDC7UA7.js");
4334
4340
  await requireAgent(agent, { requireLinear: true });
4335
4341
  const adapter = getAdapter2(agent);
4336
4342
  if (!adapter.listLinearIssues) {
@@ -4803,7 +4809,7 @@ async function adoptThread(input) {
4803
4809
  messages: input.messages ?? []
4804
4810
  });
4805
4811
  writeThread(thread);
4806
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-PSDDVERD.js");
4812
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-PS3IO4VJ.js");
4807
4813
  await ensureWorkspace2(repoPath);
4808
4814
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-RXZPTCNH.js");
4809
4815
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -6802,11 +6808,15 @@ function formatWorktreeDirective(thread, opts) {
6802
6808
  lines.push("");
6803
6809
  lines.push(formatDevAccessHint(opts?.activeRuns));
6804
6810
  lines.push("");
6811
+ lines.push(
6812
+ "Schedules: `create_schedule` / `list_schedules` (`at` / `every` / `cron`). `threadId=self` continues this chat; omit threadId for a new Global chat. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled."
6813
+ );
6814
+ lines.push("");
6805
6815
  lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
6806
6816
  return lines.join("\n");
6807
6817
  }
6808
6818
  function formatWorktreeReminder() {
6809
- 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.";
6819
+ 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. Schedules: create_schedule (at / every / cron; threadId=self for this chat).";
6810
6820
  }
6811
6821
  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;
6812
6822
  function mentionsPrGoal(prompt) {
@@ -7300,7 +7310,7 @@ function resolveScheduleThreadId(raw, env = process.env) {
7300
7310
  const value = raw?.trim() || "";
7301
7311
  if (!value) return null;
7302
7312
  if (value.toLowerCase() === "self") {
7303
- return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
7313
+ return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || env.SIDEBOARD_THREAD_ID?.trim() || null;
7304
7314
  }
7305
7315
  return value;
7306
7316
  }
@@ -7437,6 +7447,17 @@ function listSchedules() {
7437
7447
  function hasEnabledSchedules() {
7438
7448
  return listSchedules().some((row) => row.enabled);
7439
7449
  }
7450
+ function scheduleNeedsCaffeinate(task, now = /* @__PURE__ */ new Date()) {
7451
+ if (!task.enabled) return false;
7452
+ const at = new Date(task.nextRunAt);
7453
+ if (Number.isNaN(at.getTime())) return false;
7454
+ return at.getTime() > now.getTime();
7455
+ }
7456
+ function ensureCaffeinateForFutureSchedule(task) {
7457
+ if (!scheduleNeedsCaffeinate(task)) return;
7458
+ if (caffeinateWhileSchedulesEnabled()) return;
7459
+ updateAdvancedSettings({ caffeinateWhileSchedules: true });
7460
+ }
7440
7461
  function getSchedule(id) {
7441
7462
  const key = id.trim();
7442
7463
  if (!key) return null;
@@ -7449,6 +7470,7 @@ function createSchedule(input) {
7449
7470
  const rows = readAll();
7450
7471
  rows.push(task);
7451
7472
  writeAll(rows);
7473
+ ensureCaffeinateForFutureSchedule(task);
7452
7474
  return task;
7453
7475
  }
7454
7476
  function updateSchedule(id, patch) {
@@ -7475,6 +7497,7 @@ function updateSchedule(id, patch) {
7475
7497
  };
7476
7498
  rows[idx] = next;
7477
7499
  writeAll(rows);
7500
+ ensureCaffeinateForFutureSchedule(next);
7478
7501
  return next;
7479
7502
  }
7480
7503
  function deleteSchedule(id) {
@@ -7515,7 +7538,7 @@ function formatScheduledPrompt(name, prompt) {
7515
7538
  ${prompt}`;
7516
7539
  }
7517
7540
  async function defaultDeps() {
7518
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-7XDC4UOC.js");
7541
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-PJCQSVLY.js");
7519
7542
  const orch = getOrchestrator2();
7520
7543
  return {
7521
7544
  findThread: (id) => findThreadByRef(id),
@@ -7535,19 +7558,9 @@ async function fireSchedule(id) {
7535
7558
  try {
7536
7559
  const deps = fireHooks ?? await defaultDeps();
7537
7560
  const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
7538
- if (schedule.threadId) {
7539
- const thread = deps.findThread(schedule.threadId);
7540
- if (!thread || thread.status === "archived") {
7541
- return recordScheduleRun(schedule.id, {
7542
- lastError: thread ? `Orchestration chat ${schedule.threadId} is archived` : `Orchestration chat not found: ${schedule.threadId}`
7543
- });
7544
- }
7545
- if (!isOrchestratorThread(thread)) {
7546
- return recordScheduleRun(schedule.id, {
7547
- lastError: `Thread ${schedule.threadId} is not an orchestration chat`
7548
- });
7549
- }
7550
- const sent = await deps.send(thread.id, prompt);
7561
+ const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
7562
+ if (target && target.status !== "archived") {
7563
+ const sent = await deps.send(target.id, prompt);
7551
7564
  return recordScheduleRun(schedule.id, {
7552
7565
  lastThreadId: sent.id,
7553
7566
  lastError: null
@@ -7558,6 +7571,9 @@ async function fireSchedule(id) {
7558
7571
  agent: pickAgent(schedule),
7559
7572
  model: schedule.model
7560
7573
  });
7574
+ if (schedule.threadId && schedule.when.kind !== "once") {
7575
+ updateSchedule(schedule.id, { threadId: created.id });
7576
+ }
7561
7577
  return recordScheduleRun(schedule.id, {
7562
7578
  lastThreadId: created.id,
7563
7579
  lastError: null
@@ -9712,6 +9728,14 @@ var Orchestrator = class {
9712
9728
  const thread = this.requireThread(threadRef);
9713
9729
  return discoverSkills(thread.worktreePath);
9714
9730
  }
9731
+ /** Skills for a project folder before a worktree exists (create modal). */
9732
+ listSkillsForRepo(repoPath) {
9733
+ const root = repoPath.trim();
9734
+ if (!root || root === "/" || root === ".") {
9735
+ return discoverSkills("/__sideboard_no_workspace__");
9736
+ }
9737
+ return discoverSkills(root);
9738
+ }
9715
9739
  async previewLand(threadRef) {
9716
9740
  const thread = this.requireThread(threadRef);
9717
9741
  this.assertNotGlobal(thread, "Land");
@@ -10140,7 +10164,7 @@ var Orchestrator = class {
10140
10164
  this.enforceHistoryRetention();
10141
10165
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
10142
10166
  try {
10143
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-PSDDVERD.js");
10167
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-PS3IO4VJ.js");
10144
10168
  await ensureWorkspace2(thread.repoPath);
10145
10169
  } catch {
10146
10170
  }
@@ -10194,7 +10218,7 @@ var Orchestrator = class {
10194
10218
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
10195
10219
  );
10196
10220
  }
10197
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-Q4T7RSSW.js");
10221
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-DLSVHUF6.js");
10198
10222
  const slug = thread.worktreePath.split("/").pop();
10199
10223
  const dest = thread.worktreePath;
10200
10224
  await withRepoGitLock(thread.repoPath, async () => {
@@ -10304,7 +10328,7 @@ async function startOrchestration(opts) {
10304
10328
  sourceRef: "default",
10305
10329
  ...createOpts
10306
10330
  }).catch(async () => {
10307
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-Q4T7RSSW.js");
10331
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-DLSVHUF6.js");
10308
10332
  const repo = await resolveRepoRoot2(repoPath);
10309
10333
  const def = await resolveDefaultBranch2(repo);
10310
10334
  return orch.createThread({
@@ -10368,6 +10392,7 @@ export {
10368
10392
  formatScheduleWhen,
10369
10393
  listSchedules,
10370
10394
  hasEnabledSchedules,
10395
+ scheduleNeedsCaffeinate,
10371
10396
  getSchedule,
10372
10397
  createSchedule,
10373
10398
  updateSchedule,
@@ -8,7 +8,7 @@ import {
8
8
  resolveRepoRoot,
9
9
  takenSlugsFromThread,
10
10
  teamSlugFromName
11
- } from "./chunk-JLLISK4D.js";
11
+ } from "./chunk-WVNQML4W.js";
12
12
  import {
13
13
  ATTACHMENTS_DIR,
14
14
  attachmentsGitignoreBody
@@ -353,7 +353,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
353
353
  "- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API, Save this context / Do not save). Never for hellos, check-ins, invented \u201Cwhat should we do?\u201D menus, or after a review \u2014 reply in chat. Explain options first, description on every option, then wait.",
354
354
  "- get_viewer_context / update_viewer_context \u2014 read or replace Settings \u2192 Agents (account) and Settings \u2192 Projects (per-repo) context. You can update a project: pass scope=project and repoPath from list_workspaces (this cwd is not a project). update_viewer_context requires confirmed=true after ask_user. Never write context unprompted.",
355
355
  "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work, overnight schedules, or when the user will be away. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
356
- "- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 local jobs that send a prompt to an orchestration chat (threadId or self) or start a new Global chat (omit threadId). One-shot `at`, interval `every` (15m/1h/6h/1d), or 5-field `cron`. Recurring jobs without threadId open a new chat each run. Jobs fire only while Sideboard.app is running; sleep skips until wake. Overnight/unattended runs: ask the user to enable Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or call set_caffeinate.",
356
+ "- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 local jobs that send a prompt to a chat (threadId or self) or start a new Global chat (omit threadId). One-shot `at`, interval `every` (15m/1h/6h/1d), or 5-field `cron`. Recurring jobs without threadId open a new chat each run. Worktree agents have the same tools (`threadId=self` continues that coding chat). Jobs fire only while Sideboard.app is running; sleep skips until wake. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled (or call set_caffeinate).",
357
357
  "Workspaces:",
358
358
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
359
359
  "Worktree threads (chats):",
@@ -6,7 +6,7 @@ import {
6
6
  resolveRepoRoot,
7
7
  takenSlugsFromThread,
8
8
  teamSlugFromName
9
- } from "./chunk-WI75LO3T.js";
9
+ } from "./chunk-PLMMPA6A.js";
10
10
  import {
11
11
  ATTACHMENTS_DIR,
12
12
  attachmentsGitignoreBody
@@ -398,7 +398,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
398
398
  "- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API, Save this context / Do not save). Never for hellos, check-ins, invented \u201Cwhat should we do?\u201D menus, or after a review \u2014 reply in chat. Explain options first, description on every option, then wait.",
399
399
  "- get_viewer_context / update_viewer_context \u2014 read or replace Settings \u2192 Agents (account) and Settings \u2192 Projects (per-repo) context. You can update a project: pass scope=project and repoPath from list_workspaces (this cwd is not a project). update_viewer_context requires confirmed=true after ask_user. Never write context unprompted.",
400
400
  "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work, overnight schedules, or when the user will be away. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
401
- "- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 local jobs that send a prompt to an orchestration chat (threadId or self) or start a new Global chat (omit threadId). One-shot `at`, interval `every` (15m/1h/6h/1d), or 5-field `cron`. Recurring jobs without threadId open a new chat each run. Jobs fire only while Sideboard.app is running; sleep skips until wake. Overnight/unattended runs: ask the user to enable Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or call set_caffeinate.",
401
+ "- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 local jobs that send a prompt to a chat (threadId or self) or start a new Global chat (omit threadId). One-shot `at`, interval `every` (15m/1h/6h/1d), or 5-field `cron`. Recurring jobs without threadId open a new chat each run. Worktree agents have the same tools (`threadId=self` continues that coding chat). Jobs fire only while Sideboard.app is running; sleep skips until wake. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled (or call set_caffeinate).",
402
402
  "Workspaces:",
403
403
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
404
404
  "Worktree threads (chats):",