@sideboard-ai/core 0.1.252 → 0.1.254

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-B66CNEPB.js → agents-FSUI5MET.js} +3 -3
  2. package/dist/{agents-C7T4US6D.js → agents-HZP7YEKC.js} +3 -3
  3. package/dist/{chunk-AQQWP2TL.js → chunk-553IEH7O.js} +52 -25
  4. package/dist/{chunk-NYXDZCMP.js → chunk-63YSFXLT.js} +72 -2
  5. package/dist/{chunk-SJ3IUYG2.js → chunk-BYRZS2S2.js} +2 -2
  6. package/dist/{chunk-4DGYMF7H.js → chunk-F7ANS66U.js} +16 -4
  7. package/dist/{chunk-PV4KCI2S.js → chunk-HCNCZPDL.js} +72 -2
  8. package/dist/{chunk-6IP4FWMK.js → chunk-PJK24CN3.js} +2 -2
  9. package/dist/{chunk-BHPGORIY.js → chunk-R4DWUBOL.js} +22 -5
  10. package/dist/{chunk-FKGVQKRX.js → chunk-Y7CS2WGJ.js} +53 -26
  11. package/dist/{coordinator-prompt-A2JJ5X7B.js → coordinator-prompt-HZUWK3NP.js} +2 -2
  12. package/dist/{coordinator-prompt-BX2R5EMW.js → coordinator-prompt-Y6S6USNS.js} +2 -2
  13. package/dist/{global-workspace-PUJEGSOB.js → global-workspace-4JCITHB6.js} +2 -2
  14. package/dist/{global-workspace-JJRPZNTY.js → global-workspace-YA7U4M2N.js} +2 -2
  15. package/dist/index.cjs +727 -606
  16. package/dist/index.d.cts +26 -9
  17. package/dist/index.d.ts +26 -9
  18. package/dist/index.js +24 -14
  19. package/dist/mcp/run-stdio.cjs +141 -29
  20. package/dist/mcp/run-stdio.js +21 -14
  21. package/dist/{orchestrator-O3V4UH73.js → orchestrator-LWADJQTN.js} +4 -4
  22. package/dist/{orchestrator-O3TVI7SN.js → orchestrator-VHJZEVGA.js} +4 -4
  23. package/dist/{workspaces-FUOZIR3V.js → workspaces-4KHEUPEX.js} +2 -2
  24. package/dist/{workspaces-V3PZRTY5.js → workspaces-IXZD7EC4.js} +2 -2
  25. package/dist/{worktree-UK62JCYF.js → worktree-DAAF64UU.js} +3 -1
  26. package/dist/{worktree-4DNK2CK6.js → worktree-S3FOMEQ2.js} +3 -1
  27. package/package.json +1 -1
@@ -6275,6 +6275,7 @@ __export(worktree_exports, {
6275
6275
  resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
6276
6276
  slugify: () => slugify,
6277
6277
  suggestSlug: () => suggestSlug,
6278
+ switchWorktreeBranch: () => switchWorktreeBranch,
6278
6279
  threadDisplayLabel: () => threadDisplayLabel,
6279
6280
  ticketSlugForBranch: () => ticketSlugForBranch,
6280
6281
  worktreeDisplayLabel: () => worktreeDisplayLabel,
@@ -6886,6 +6887,7 @@ function parsePrDetailsView(view) {
6886
6887
  const author = view.author ?? {};
6887
6888
  const comments = Array.isArray(view.comments) ? view.comments : [];
6888
6889
  const reviews = Array.isArray(view.reviews) ? view.reviews : [];
6890
+ const commits = Array.isArray(view.commits) ? view.commits : [];
6889
6891
  const requested = {
6890
6892
  ids: reviewerIdentities(view.reviewRequests),
6891
6893
  users: humanReviewerLogins(view.reviewRequests),
@@ -6906,8 +6908,22 @@ function parsePrDetailsView(view) {
6906
6908
  additions: Number(view.additions ?? 0),
6907
6909
  deletions: Number(view.deletions ?? 0),
6908
6910
  changedFiles: Number(view.changedFiles ?? 0),
6909
- // Commits live in Changes; omit from GraphQL to save rate-limit points.
6910
- commits: [],
6911
+ commits: commits.map((c) => {
6912
+ const row = c;
6913
+ const authors = Array.isArray(row.authors) ? row.authors.map((a) => {
6914
+ const actor = a;
6915
+ return {
6916
+ login: actor.login?.trim() || actor.name?.trim() || "unknown",
6917
+ name: actor.name ?? null
6918
+ };
6919
+ }) : [];
6920
+ return {
6921
+ oid: String(row.oid ?? ""),
6922
+ messageHeadline: String(row.messageHeadline ?? ""),
6923
+ committedDate: String(row.committedDate ?? ""),
6924
+ authors
6925
+ };
6926
+ }),
6911
6927
  comments: comments.map((c) => {
6912
6928
  const row = c;
6913
6929
  const a = row.author ?? {};
@@ -7286,6 +7302,59 @@ async function createExistingBranchWorktree(opts) {
7286
7302
  await ensureWorktreeSideboardIgnored(worktreePath);
7287
7303
  return { branchName, worktreePath };
7288
7304
  }
7305
+ async function switchWorktreeBranch(opts) {
7306
+ const branch = opts.branchName.trim().replace(/^origin\//, "");
7307
+ if (!branch) throw new Error("branch name required");
7308
+ const head = await git(["rev-parse", "--abbrev-ref", "HEAD"], opts.worktreePath, {
7309
+ reject: false
7310
+ });
7311
+ if (head.stdout.trim() === branch) return branch;
7312
+ const here = normalizeWorktreePath(opts.worktreePath);
7313
+ const trees = await listWorktrees(opts.repoPath);
7314
+ const taken = trees.find(
7315
+ (w) => w.branch === branch && normalizeWorktreePath(w.path) !== here
7316
+ );
7317
+ if (taken?.path) {
7318
+ throw new Error(`Branch ${branch} is already checked out at ${taken.path}`);
7319
+ }
7320
+ await withRepoGitLock(opts.repoPath, async () => {
7321
+ const local = await git(
7322
+ ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
7323
+ opts.worktreePath,
7324
+ { reject: false }
7325
+ );
7326
+ if (local.exitCode === 0) {
7327
+ const sw = await git(["switch", branch], opts.worktreePath, {
7328
+ reject: false
7329
+ });
7330
+ if (sw.exitCode !== 0) {
7331
+ throw new Error(
7332
+ sw.stderr.trim() || sw.stdout.trim() || `Failed to switch to ${branch}`
7333
+ );
7334
+ }
7335
+ return;
7336
+ }
7337
+ const remote = `origin/${branch}`;
7338
+ const remoteOk = await git(["rev-parse", "--verify", "--quiet", remote], opts.repoPath, {
7339
+ reject: false
7340
+ });
7341
+ if (remoteOk.exitCode === 0) {
7342
+ const sw = await git(
7343
+ ["switch", "-c", branch, "--track", remote],
7344
+ opts.worktreePath,
7345
+ { reject: false }
7346
+ );
7347
+ if (sw.exitCode !== 0) {
7348
+ throw new Error(
7349
+ sw.stderr.trim() || sw.stdout.trim() || `Failed to switch to ${branch}`
7350
+ );
7351
+ }
7352
+ return;
7353
+ }
7354
+ throw new Error(`Unknown branch ${branch}`);
7355
+ });
7356
+ return branch;
7357
+ }
7289
7358
  async function removeWorktree(repoPath, worktreePath, opts) {
7290
7359
  await withRepoGitLock(repoPath, async () => {
7291
7360
  await git(["worktree", "remove", "--force", worktreePath], repoPath, {
@@ -7718,6 +7787,7 @@ var init_worktree = __esm({
7718
7787
  "additions",
7719
7788
  "deletions",
7720
7789
  "changedFiles",
7790
+ "commits",
7721
7791
  "comments",
7722
7792
  "reviews",
7723
7793
  "assignees",
@@ -8399,7 +8469,7 @@ var init_coordinator_prompt = __esm({
8399
8469
  "- 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.",
8400
8470
  "- 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.",
8401
8471
  "- 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.",
8402
- "- 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.",
8472
+ "- 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).",
8403
8473
  "Workspaces:",
8404
8474
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
8405
8475
  "Worktree threads (chats):",
@@ -10152,7 +10222,12 @@ var init_injected_mcp = __esm({
10152
10222
  "mcp__sideboard__get_run_log",
10153
10223
  "mcp__sideboard__notify_orchestrator",
10154
10224
  "mcp__sideboard__get_viewer_context",
10155
- "mcp__sideboard__update_viewer_context"
10225
+ "mcp__sideboard__update_viewer_context",
10226
+ "mcp__sideboard__list_schedules",
10227
+ "mcp__sideboard__create_schedule",
10228
+ "mcp__sideboard__update_schedule",
10229
+ "mcp__sideboard__delete_schedule",
10230
+ "mcp__sideboard__run_schedule"
10156
10231
  ];
10157
10232
  SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS = ["mcp__sideboard__github_*"];
10158
10233
  SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS = ["mcp__sideboard__linear_*"];
@@ -10467,6 +10542,13 @@ function toolDescription(name, input) {
10467
10542
  return str2(input?.name) ? `Read ${str2(input?.name)} log` : "Read Dev log";
10468
10543
  }
10469
10544
  if (/notify_orchestrator$/i.test(name)) return "Notify orchestrator";
10545
+ if (/list_schedules$/i.test(name)) return "List schedules";
10546
+ if (/create_schedule$/i.test(name)) {
10547
+ return str2(input?.name) ? `Schedule ${str2(input?.name)}` : "Create schedule";
10548
+ }
10549
+ if (/update_schedule$/i.test(name)) return "Update schedule";
10550
+ if (/delete_schedule$/i.test(name)) return "Delete schedule";
10551
+ if (/run_schedule$/i.test(name)) return "Run schedule";
10470
10552
  if (isSkillToolName(name)) {
10471
10553
  const cmd = skillCommandFromInput(input);
10472
10554
  return cmd ? `Using /${cmd}` : "Using skill";
@@ -21405,11 +21487,15 @@ function formatWorktreeDirective(thread, opts) {
21405
21487
  lines.push("");
21406
21488
  lines.push(formatDevAccessHint(opts?.activeRuns));
21407
21489
  lines.push("");
21490
+ lines.push(
21491
+ "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."
21492
+ );
21493
+ lines.push("");
21408
21494
  lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
21409
21495
  return lines.join("\n");
21410
21496
  }
21411
21497
  function formatWorktreeReminder() {
21412
- 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.";
21498
+ 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).";
21413
21499
  }
21414
21500
  function mentionsPrGoal(prompt) {
21415
21501
  return PR_GOAL_RE.test(prompt);
@@ -22036,7 +22122,7 @@ function resolveScheduleThreadId(raw, env = process.env) {
22036
22122
  const value = raw?.trim() || "";
22037
22123
  if (!value) return null;
22038
22124
  if (value.toLowerCase() === "self") {
22039
- return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
22125
+ return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || env.SIDEBOARD_THREAD_ID?.trim() || null;
22040
22126
  }
22041
22127
  return value;
22042
22128
  }
@@ -22164,6 +22250,17 @@ function buildTask(input, now) {
22164
22250
  function listSchedules() {
22165
22251
  return readAll2().sort((a, b) => a.nextRunAt.localeCompare(b.nextRunAt));
22166
22252
  }
22253
+ function scheduleNeedsCaffeinate(task, now = /* @__PURE__ */ new Date()) {
22254
+ if (!task.enabled) return false;
22255
+ const at = new Date(task.nextRunAt);
22256
+ if (Number.isNaN(at.getTime())) return false;
22257
+ return at.getTime() > now.getTime();
22258
+ }
22259
+ function ensureCaffeinateForFutureSchedule(task) {
22260
+ if (!scheduleNeedsCaffeinate(task)) return;
22261
+ if (caffeinateWhileSchedulesEnabled()) return;
22262
+ updateAdvancedSettings({ caffeinateWhileSchedules: true });
22263
+ }
22167
22264
  function getSchedule(id) {
22168
22265
  const key = id.trim();
22169
22266
  if (!key) return null;
@@ -22176,6 +22273,7 @@ function createSchedule(input) {
22176
22273
  const rows = readAll2();
22177
22274
  rows.push(task);
22178
22275
  writeAll2(rows);
22276
+ ensureCaffeinateForFutureSchedule(task);
22179
22277
  return task;
22180
22278
  }
22181
22279
  function updateSchedule(id, patch) {
@@ -22202,6 +22300,7 @@ function updateSchedule(id, patch) {
22202
22300
  };
22203
22301
  rows[idx] = next;
22204
22302
  writeAll2(rows);
22303
+ ensureCaffeinateForFutureSchedule(next);
22205
22304
  return next;
22206
22305
  }
22207
22306
  function deleteSchedule(id) {
@@ -22242,6 +22341,7 @@ var init_schedules = __esm({
22242
22341
  init_orchestrator_capable();
22243
22342
  init_paths();
22244
22343
  init_private_file();
22344
+ init_app_settings();
22245
22345
  DURATION_RE = /^(\d+)(s|m|h|d)$/i;
22246
22346
  UNIT_MS = {
22247
22347
  s: 1e3,
@@ -22278,19 +22378,9 @@ async function fireSchedule(id) {
22278
22378
  try {
22279
22379
  const deps = fireHooks ?? await defaultDeps();
22280
22380
  const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
22281
- if (schedule.threadId) {
22282
- const thread = deps.findThread(schedule.threadId);
22283
- if (!thread || thread.status === "archived") {
22284
- return recordScheduleRun(schedule.id, {
22285
- lastError: thread ? `Orchestration chat ${schedule.threadId} is archived` : `Orchestration chat not found: ${schedule.threadId}`
22286
- });
22287
- }
22288
- if (!isOrchestratorThread(thread)) {
22289
- return recordScheduleRun(schedule.id, {
22290
- lastError: `Thread ${schedule.threadId} is not an orchestration chat`
22291
- });
22292
- }
22293
- const sent = await deps.send(thread.id, prompt);
22381
+ const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
22382
+ if (target && target.status !== "archived") {
22383
+ const sent = await deps.send(target.id, prompt);
22294
22384
  return recordScheduleRun(schedule.id, {
22295
22385
  lastThreadId: sent.id,
22296
22386
  lastError: null
@@ -22301,6 +22391,9 @@ async function fireSchedule(id) {
22301
22391
  agent: pickAgent(schedule),
22302
22392
  model: schedule.model
22303
22393
  });
22394
+ if (schedule.threadId && schedule.when.kind !== "once") {
22395
+ updateSchedule(schedule.id, { threadId: created.id });
22396
+ }
22304
22397
  return recordScheduleRun(schedule.id, {
22305
22398
  lastThreadId: created.id,
22306
22399
  lastError: null
@@ -22369,7 +22462,6 @@ var init_schedule_runner = __esm({
22369
22462
  init_app_settings();
22370
22463
  init_schedules();
22371
22464
  init_thread_store();
22372
- init_global_workspace();
22373
22465
  SET_TIMEOUT_MAX = 2147483647;
22374
22466
  fireHooks = null;
22375
22467
  timers = /* @__PURE__ */ new Map();
@@ -25073,6 +25165,20 @@ var init_orchestrator = __esm({
25073
25165
  if (!next) throw new Error("Title cannot be empty");
25074
25166
  return updateThread(thread.id, { title: next, userSetTitle: true });
25075
25167
  }
25168
+ async switchThreadBranch(threadRef, branchName) {
25169
+ const thread = this.requireThread(threadRef);
25170
+ this.assertNotGlobal(thread, "Switch branch");
25171
+ if (thread.status === "running") {
25172
+ throw new Error("Stop the agent before switching branches");
25173
+ }
25174
+ await switchWorktreeBranch({
25175
+ repoPath: thread.repoPath,
25176
+ worktreePath: thread.worktreePath,
25177
+ branchName
25178
+ });
25179
+ await syncThreadBranchFromGit(thread.id);
25180
+ return this.requireThread(thread.id);
25181
+ }
25076
25182
  setAttachments(threadRef, attachments) {
25077
25183
  return updateThread(this.requireThread(threadRef).id, { attachments });
25078
25184
  }
@@ -29113,7 +29219,7 @@ function parseWhen(args) {
29113
29219
  function registerScheduleTools(server) {
29114
29220
  server.tool(
29115
29221
  "list_schedules",
29116
- "List local Sideboard schedules that trigger orchestration agents. Jobs fire only while Sideboard.app is running on this Mac (sleep skips until wake).",
29222
+ "List local Sideboard schedules that trigger a chat when due. Jobs fire only while Sideboard.app is running on this Mac (sleep skips until wake).",
29117
29223
  {},
29118
29224
  async () => {
29119
29225
  try {
@@ -29125,7 +29231,7 @@ function registerScheduleTools(server) {
29125
29231
  );
29126
29232
  server.tool(
29127
29233
  "create_schedule",
29128
- "Create a local schedule that, when due, sends a prompt to an orchestration chat (threadId) or starts a new Global orchestration chat (omit threadId). Pass threadId=self to continue this coordinator. Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without threadId open a new chat each run. Overnight/unattended runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate. Sideboard.app must be running for the job to fire.",
29234
+ "Create a local schedule that, when due, sends a prompt to an existing chat (threadId) or starts a new Global orchestration chat (omit threadId). Pass threadId=self to continue this chat. If that chat is missing or archived when the job fires, Sideboard starts a new Global chat (recurring jobs then continue that chat). Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without threadId open a new Global chat each run. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled so the Mac stays awake until due. Sideboard.app must be running for the job to fire.",
29129
29235
  {
29130
29236
  prompt: import_zod8.z.string().describe("User message / goal queued when the schedule fires"),
29131
29237
  name: import_zod8.z.string().optional(),
@@ -29134,7 +29240,7 @@ function registerScheduleTools(server) {
29134
29240
  cron: import_zod8.z.string().optional().describe("5-field cron expression"),
29135
29241
  tz: import_zod8.z.string().optional().describe("IANA timezone for cron (default: system)"),
29136
29242
  threadId: import_zod8.z.string().optional().describe(
29137
- 'Existing orchestration chat id, or "self" for this coordinator. Omit to create a new Global chat on fire.'
29243
+ 'Existing chat id (orchestration or worktree), or "self" for this chat. Omit to create a new Global chat on fire.'
29138
29244
  ),
29139
29245
  agent: import_zod8.z.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
29140
29246
  model: import_zod8.z.string().optional()
@@ -29145,7 +29251,9 @@ function registerScheduleTools(server) {
29145
29251
  const threadId = resolveScheduleThreadId(args.threadId);
29146
29252
  if (args.threadId?.trim().toLowerCase() === "self" && !threadId) {
29147
29253
  return fail5(
29148
- new Error("threadId=self requires this turn to be an orchestration chat")
29254
+ new Error(
29255
+ "threadId=self needs this chat id (SIDEBOARD_THREAD_ID or SIDEBOARD_ORCHESTRATOR_THREAD_ID)"
29256
+ )
29149
29257
  );
29150
29258
  }
29151
29259
  const schedule = createSchedule({
@@ -29159,7 +29267,7 @@ function registerScheduleTools(server) {
29159
29267
  });
29160
29268
  return text6({
29161
29269
  schedule,
29162
- hint: "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run. Overnight runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate."
29270
+ hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run. Caffeinate while schedules are enabled is now on so the Mac can stay awake until this job is due." : "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run."
29163
29271
  });
29164
29272
  } catch (err) {
29165
29273
  return fail5(err);
@@ -29177,7 +29285,9 @@ function registerScheduleTools(server) {
29177
29285
  every: import_zod8.z.string().optional(),
29178
29286
  cron: import_zod8.z.string().optional(),
29179
29287
  tz: import_zod8.z.string().optional(),
29180
- threadId: import_zod8.z.string().optional().describe('Existing orchestration chat, "self", or empty string to create a new chat each run'),
29288
+ threadId: import_zod8.z.string().optional().describe(
29289
+ 'Existing chat (orchestration or worktree), "self", or empty string to create a new Global chat each run'
29290
+ ),
29181
29291
  agent: import_zod8.z.enum(["claude", "cursor", "codex", "opencode"]).optional(),
29182
29292
  model: import_zod8.z.string().optional(),
29183
29293
  enabled: import_zod8.z.boolean().optional()
@@ -29196,7 +29306,9 @@ function registerScheduleTools(server) {
29196
29306
  threadId = resolveScheduleThreadId(args.threadId);
29197
29307
  if (args.threadId.trim().toLowerCase() === "self" && !threadId) {
29198
29308
  return fail5(
29199
- new Error("threadId=self requires this turn to be an orchestration chat")
29309
+ new Error(
29310
+ "threadId=self needs this chat id (SIDEBOARD_THREAD_ID or SIDEBOARD_ORCHESTRATOR_THREAD_ID)"
29311
+ )
29200
29312
  );
29201
29313
  }
29202
29314
  }
@@ -29230,7 +29342,7 @@ function registerScheduleTools(server) {
29230
29342
  );
29231
29343
  server.tool(
29232
29344
  "run_schedule",
29233
- "Fire a schedule now (does not wait for nextRunAt). Queues the prompt or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
29345
+ "Fire a schedule now (does not wait for nextRunAt). Queues the prompt on the target chat or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
29234
29346
  { id: import_zod8.z.string() },
29235
29347
  async ({ id }) => {
29236
29348
  try {
@@ -30170,10 +30282,10 @@ async function startMcpServer() {
30170
30282
  }
30171
30283
  );
30172
30284
  }
30285
+ registerScheduleTools(server);
30173
30286
  if (!worktreeProfile) {
30174
30287
  registerSlackTools(server);
30175
30288
  registerConnectedIssueVendorTools(server);
30176
- registerScheduleTools(server);
30177
30289
  const { getCaffeinateHold: getCaffeinateHold2, setCaffeinateHold: setCaffeinateHold2 } = await Promise.resolve().then(() => (init_caffeinate_hold(), caffeinate_hold_exports));
30178
30290
  const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
30179
30291
  const accountDefaults = resolveThreadDefaults2();
@@ -43,13 +43,14 @@ import {
43
43
  readTurnLive,
44
44
  resolveOrchChildFollowUp,
45
45
  resolveScheduleThreadId,
46
+ scheduleNeedsCaffeinate,
46
47
  sliceRunLogOutput,
47
48
  stopDetachedJob,
48
49
  syncBoardPins,
49
50
  threadsSharingWorktree,
50
51
  updateSchedule,
51
52
  waitForDetachedJob
52
- } from "../chunk-AQQWP2TL.js";
53
+ } from "../chunk-553IEH7O.js";
53
54
  import {
54
55
  PRESENT_PLAN_REQUIRES_PLAN_MODE,
55
56
  PRESENT_PLAN_TOOL_DESCRIPTION,
@@ -66,13 +67,13 @@ import {
66
67
  materializeSystemCaBundle,
67
68
  sideboardMcpProfile,
68
69
  trustSystemCertificates
69
- } from "../chunk-4DGYMF7H.js";
70
+ } from "../chunk-F7ANS66U.js";
70
71
  import {
71
72
  GLOBAL_WORKSPACE_ID,
72
73
  isCloudCoordinatorThread,
73
74
  isOrchestratorThread,
74
75
  listWorkspaces
75
- } from "../chunk-6IP4FWMK.js";
76
+ } from "../chunk-PJK24CN3.js";
76
77
  import "../chunk-XAISOBBG.js";
77
78
  import "../chunk-P2BSMNHB.js";
78
79
  import "../chunk-XIEDFRBP.js";
@@ -90,7 +91,7 @@ import {
90
91
  resolveListPrsOptions,
91
92
  resolveRepoRoot,
92
93
  warmGithubAgentAuth
93
- } from "../chunk-PV4KCI2S.js";
94
+ } from "../chunk-HCNCZPDL.js";
94
95
  import "../chunk-D6JWYJ4P.js";
95
96
  import {
96
97
  appendMessage,
@@ -2367,7 +2368,7 @@ async function continueSourceThread(threadId, prompt) {
2367
2368
  await continueOnReply(threadId, prompt);
2368
2369
  return;
2369
2370
  }
2370
- const { getOrchestrator: getOrchestrator2 } = await import("../orchestrator-O3TVI7SN.js");
2371
+ const { getOrchestrator: getOrchestrator2 } = await import("../orchestrator-VHJZEVGA.js");
2371
2372
  await getOrchestrator2().send(threadId, prompt);
2372
2373
  } catch {
2373
2374
  }
@@ -3912,7 +3913,7 @@ function parseWhen(args) {
3912
3913
  function registerScheduleTools(server) {
3913
3914
  server.tool(
3914
3915
  "list_schedules",
3915
- "List local Sideboard schedules that trigger orchestration agents. Jobs fire only while Sideboard.app is running on this Mac (sleep skips until wake).",
3916
+ "List local Sideboard schedules that trigger a chat when due. Jobs fire only while Sideboard.app is running on this Mac (sleep skips until wake).",
3916
3917
  {},
3917
3918
  async () => {
3918
3919
  try {
@@ -3924,7 +3925,7 @@ function registerScheduleTools(server) {
3924
3925
  );
3925
3926
  server.tool(
3926
3927
  "create_schedule",
3927
- "Create a local schedule that, when due, sends a prompt to an orchestration chat (threadId) or starts a new Global orchestration chat (omit threadId). Pass threadId=self to continue this coordinator. Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without threadId open a new chat each run. Overnight/unattended runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate. Sideboard.app must be running for the job to fire.",
3928
+ "Create a local schedule that, when due, sends a prompt to an existing chat (threadId) or starts a new Global orchestration chat (omit threadId). Pass threadId=self to continue this chat. If that chat is missing or archived when the job fires, Sideboard starts a new Global chat (recurring jobs then continue that chat). Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without threadId open a new Global chat each run. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled so the Mac stays awake until due. Sideboard.app must be running for the job to fire.",
3928
3929
  {
3929
3930
  prompt: z8.string().describe("User message / goal queued when the schedule fires"),
3930
3931
  name: z8.string().optional(),
@@ -3933,7 +3934,7 @@ function registerScheduleTools(server) {
3933
3934
  cron: z8.string().optional().describe("5-field cron expression"),
3934
3935
  tz: z8.string().optional().describe("IANA timezone for cron (default: system)"),
3935
3936
  threadId: z8.string().optional().describe(
3936
- 'Existing orchestration chat id, or "self" for this coordinator. Omit to create a new Global chat on fire.'
3937
+ 'Existing chat id (orchestration or worktree), or "self" for this chat. Omit to create a new Global chat on fire.'
3937
3938
  ),
3938
3939
  agent: z8.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
3939
3940
  model: z8.string().optional()
@@ -3944,7 +3945,9 @@ function registerScheduleTools(server) {
3944
3945
  const threadId = resolveScheduleThreadId(args.threadId);
3945
3946
  if (args.threadId?.trim().toLowerCase() === "self" && !threadId) {
3946
3947
  return fail5(
3947
- new Error("threadId=self requires this turn to be an orchestration chat")
3948
+ new Error(
3949
+ "threadId=self needs this chat id (SIDEBOARD_THREAD_ID or SIDEBOARD_ORCHESTRATOR_THREAD_ID)"
3950
+ )
3948
3951
  );
3949
3952
  }
3950
3953
  const schedule = createSchedule({
@@ -3958,7 +3961,7 @@ function registerScheduleTools(server) {
3958
3961
  });
3959
3962
  return text6({
3960
3963
  schedule,
3961
- hint: "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run. Overnight runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate."
3964
+ hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run. Caffeinate while schedules are enabled is now on so the Mac can stay awake until this job is due." : "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run."
3962
3965
  });
3963
3966
  } catch (err) {
3964
3967
  return fail5(err);
@@ -3976,7 +3979,9 @@ function registerScheduleTools(server) {
3976
3979
  every: z8.string().optional(),
3977
3980
  cron: z8.string().optional(),
3978
3981
  tz: z8.string().optional(),
3979
- threadId: z8.string().optional().describe('Existing orchestration chat, "self", or empty string to create a new chat each run'),
3982
+ threadId: z8.string().optional().describe(
3983
+ 'Existing chat (orchestration or worktree), "self", or empty string to create a new Global chat each run'
3984
+ ),
3980
3985
  agent: z8.enum(["claude", "cursor", "codex", "opencode"]).optional(),
3981
3986
  model: z8.string().optional(),
3982
3987
  enabled: z8.boolean().optional()
@@ -3995,7 +4000,9 @@ function registerScheduleTools(server) {
3995
4000
  threadId = resolveScheduleThreadId(args.threadId);
3996
4001
  if (args.threadId.trim().toLowerCase() === "self" && !threadId) {
3997
4002
  return fail5(
3998
- new Error("threadId=self requires this turn to be an orchestration chat")
4003
+ new Error(
4004
+ "threadId=self needs this chat id (SIDEBOARD_THREAD_ID or SIDEBOARD_ORCHESTRATOR_THREAD_ID)"
4005
+ )
3999
4006
  );
4000
4007
  }
4001
4008
  }
@@ -4029,7 +4036,7 @@ function registerScheduleTools(server) {
4029
4036
  );
4030
4037
  server.tool(
4031
4038
  "run_schedule",
4032
- "Fire a schedule now (does not wait for nextRunAt). Queues the prompt or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
4039
+ "Fire a schedule now (does not wait for nextRunAt). Queues the prompt on the target chat or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
4033
4040
  { id: z8.string() },
4034
4041
  async ({ id }) => {
4035
4042
  try {
@@ -4954,10 +4961,10 @@ async function startMcpServer() {
4954
4961
  }
4955
4962
  );
4956
4963
  }
4964
+ registerScheduleTools(server);
4957
4965
  if (!worktreeProfile) {
4958
4966
  registerSlackTools(server);
4959
4967
  registerConnectedIssueVendorTools(server);
4960
- registerScheduleTools(server);
4961
4968
  const { getCaffeinateHold, setCaffeinateHold } = await import("../caffeinate-hold-UAGLSGMM.js");
4962
4969
  const { resolveNewThreadOptions, resolveThreadDefaults } = await import("../app-settings-CLARFJUX.js");
4963
4970
  const accountDefaults = resolveThreadDefaults();
@@ -9,11 +9,11 @@ import {
9
9
  resolveSendFollowUp,
10
10
  startOrchestration,
11
11
  waitForPidExit
12
- } from "./chunk-FKGVQKRX.js";
12
+ } from "./chunk-Y7CS2WGJ.js";
13
13
  import "./chunk-PGPSIEMW.js";
14
- import "./chunk-BHPGORIY.js";
15
- import "./chunk-SJ3IUYG2.js";
16
- import "./chunk-NYXDZCMP.js";
14
+ import "./chunk-R4DWUBOL.js";
15
+ import "./chunk-BYRZS2S2.js";
16
+ import "./chunk-63YSFXLT.js";
17
17
  import "./chunk-6K64FJDD.js";
18
18
  import "./chunk-2P4XKWV2.js";
19
19
  import "./chunk-5F4YFGHL.js";
@@ -11,15 +11,15 @@ import {
11
11
  resolveSendFollowUp,
12
12
  startOrchestration,
13
13
  waitForPidExit
14
- } from "./chunk-AQQWP2TL.js";
14
+ } from "./chunk-553IEH7O.js";
15
15
  import "./chunk-WDDUIGFK.js";
16
16
  import "./chunk-QN5DL2QO.js";
17
- import "./chunk-4DGYMF7H.js";
18
- import "./chunk-6IP4FWMK.js";
17
+ import "./chunk-F7ANS66U.js";
18
+ import "./chunk-PJK24CN3.js";
19
19
  import "./chunk-XAISOBBG.js";
20
20
  import "./chunk-P2BSMNHB.js";
21
21
  import "./chunk-VKQGAWHY.js";
22
- import "./chunk-PV4KCI2S.js";
22
+ import "./chunk-HCNCZPDL.js";
23
23
  import "./chunk-D6JWYJ4P.js";
24
24
  import "./chunk-RJC2MKXN.js";
25
25
  import "./chunk-H547WSSZ.js";
@@ -5,8 +5,8 @@ import {
5
5
  primaryCheckoutFromLinkedWorktree,
6
6
  removeWorkspace,
7
7
  syncWorkspacesFromThreads
8
- } from "./chunk-SJ3IUYG2.js";
9
- import "./chunk-NYXDZCMP.js";
8
+ } from "./chunk-BYRZS2S2.js";
9
+ import "./chunk-63YSFXLT.js";
10
10
  import "./chunk-6K64FJDD.js";
11
11
  import "./chunk-2P4XKWV2.js";
12
12
  import "./chunk-KJM3E3NF.js";
@@ -7,8 +7,8 @@ import {
7
7
  primaryCheckoutFromLinkedWorktree,
8
8
  removeWorkspace,
9
9
  syncWorkspacesFromThreads
10
- } from "./chunk-6IP4FWMK.js";
11
- import "./chunk-PV4KCI2S.js";
10
+ } from "./chunk-PJK24CN3.js";
11
+ import "./chunk-HCNCZPDL.js";
12
12
  import "./chunk-D6JWYJ4P.js";
13
13
  import "./chunk-RJC2MKXN.js";
14
14
  import "./chunk-H547WSSZ.js";
@@ -55,13 +55,14 @@ import {
55
55
  resolveWorktreeStartPoint,
56
56
  slugify,
57
57
  suggestSlug,
58
+ switchWorktreeBranch,
58
59
  threadDisplayLabel,
59
60
  ticketSlugForBranch,
60
61
  worktreeDisplayLabel,
61
62
  worktreeDisplayLabelForGroup,
62
63
  worktreeNameFromPath,
63
64
  worktreeSlugForTicket
64
- } from "./chunk-PV4KCI2S.js";
65
+ } from "./chunk-HCNCZPDL.js";
65
66
  import "./chunk-D6JWYJ4P.js";
66
67
  import "./chunk-RJC2MKXN.js";
67
68
  import "./chunk-H547WSSZ.js";
@@ -128,6 +129,7 @@ export {
128
129
  resolveWorktreeStartPoint,
129
130
  slugify,
130
131
  suggestSlug,
132
+ switchWorktreeBranch,
131
133
  threadDisplayLabel,
132
134
  ticketSlugForBranch,
133
135
  worktreeDisplayLabel,
@@ -53,13 +53,14 @@ import {
53
53
  resolveWorktreeStartPoint,
54
54
  slugify,
55
55
  suggestSlug,
56
+ switchWorktreeBranch,
56
57
  threadDisplayLabel,
57
58
  ticketSlugForBranch,
58
59
  worktreeDisplayLabel,
59
60
  worktreeDisplayLabelForGroup,
60
61
  worktreeNameFromPath,
61
62
  worktreeSlugForTicket
62
- } from "./chunk-NYXDZCMP.js";
63
+ } from "./chunk-63YSFXLT.js";
63
64
  import "./chunk-6K64FJDD.js";
64
65
  import "./chunk-2P4XKWV2.js";
65
66
  import "./chunk-KJM3E3NF.js";
@@ -126,6 +127,7 @@ export {
126
127
  resolveWorktreeStartPoint,
127
128
  slugify,
128
129
  suggestSlug,
130
+ switchWorktreeBranch,
129
131
  threadDisplayLabel,
130
132
  ticketSlugForBranch,
131
133
  worktreeDisplayLabel,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideboard-ai/core",
3
- "version": "0.1.252",
3
+ "version": "0.1.254",
4
4
  "description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",