@sideboard-ai/core 0.1.245 → 0.1.247

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 (48) hide show
  1. package/dist/{abletime-OI6FNSXX.js → abletime-GAPUN2LL.js} +4 -4
  2. package/dist/{abletime-CWIJ7INC.js → abletime-HTRIHTL5.js} +4 -4
  3. package/dist/{abletime-oauth-CHVTUZBR.js → abletime-oauth-G6ZPGVAE.js} +3 -3
  4. package/dist/{abletime-oauth-PUIPZTA4.js → abletime-oauth-ME7ZY2RS.js} +3 -3
  5. package/dist/{abletime-rest-32NIVXAY.js → abletime-rest-73EKIAZU.js} +3 -3
  6. package/dist/{abletime-rest-APJUKFKL.js → abletime-rest-M2D2NELV.js} +3 -3
  7. package/dist/{agents-FTQZFMDS.js → agents-3PQ2BWGB.js} +5 -5
  8. package/dist/{agents-BOIIFMNG.js → agents-7SCJTTZN.js} +5 -5
  9. package/dist/{app-settings-VOPXJMGV.js → app-settings-2BHGANQH.js} +7 -1
  10. package/dist/{app-settings-652J57CX.js → app-settings-NKXH4PKM.js} +7 -1
  11. package/dist/{chunk-576S3HJ7.js → chunk-64NUGRZ3.js} +4 -4
  12. package/dist/{chunk-IMO7AZI4.js → chunk-6HIAYIXT.js} +2 -2
  13. package/dist/{chunk-WURF67ID.js → chunk-BEQE7VOE.js} +5 -5
  14. package/dist/{chunk-6I5YQTNK.js → chunk-CXTIOJRX.js} +12 -0
  15. package/dist/{chunk-QRWVKBGP.js → chunk-D3DYMGZS.js} +18 -5
  16. package/dist/{chunk-J5IZXFLD.js → chunk-ERQYYL4I.js} +74 -23
  17. package/dist/{chunk-C64YQAA6.js → chunk-GFGSC4Z7.js} +3 -3
  18. package/dist/{chunk-43F44EKX.js → chunk-GVAR6R6R.js} +2 -2
  19. package/dist/{chunk-NT6MCFSB.js → chunk-KFXP4KSP.js} +143 -24
  20. package/dist/{chunk-G45QP2ZD.js → chunk-LPS6D346.js} +3 -3
  21. package/dist/{chunk-7HOKP4GR.js → chunk-PELMZRDB.js} +12 -0
  22. package/dist/{chunk-PPJ5JTWA.js → chunk-QVQPIFBV.js} +28 -2
  23. package/dist/{chunk-QNJXJIWJ.js → chunk-RF46WMSI.js} +5 -5
  24. package/dist/{chunk-GFRC6JQN.js → chunk-U2ZZMGPV.js} +4 -4
  25. package/dist/{chunk-3ZEBUVUI.js → chunk-UVWIYSAA.js} +18 -5
  26. package/dist/{chunk-E6C5NR46.js → chunk-W4F7JKXF.js} +20 -6
  27. package/dist/{chunk-YLGBQVRK.js → chunk-XEBQRCDW.js} +28 -2
  28. package/dist/{chunk-5ZFULOTC.js → chunk-XM4UIFQU.js} +20 -6
  29. package/dist/{chunk-BL2UGKWU.js → chunk-Z7QWXE4W.js} +3 -3
  30. package/dist/{coordinator-prompt-ZBYRREHD.js → coordinator-prompt-BFO2TAVR.js} +4 -4
  31. package/dist/{coordinator-prompt-WQIICPT6.js → coordinator-prompt-IG676OSP.js} +4 -4
  32. package/dist/{global-workspace-3SQU4GL4.js → global-workspace-J6H7X5SM.js} +4 -4
  33. package/dist/{global-workspace-2N6KISDO.js → global-workspace-RLCICVQE.js} +4 -4
  34. package/dist/index.cjs +207 -15
  35. package/dist/index.d.cts +66 -2
  36. package/dist/index.d.ts +66 -2
  37. package/dist/index.js +27 -16
  38. package/dist/mcp/run-stdio.cjs +131 -15
  39. package/dist/mcp/run-stdio.js +17 -15
  40. package/dist/{orchestrator-5ROSTGGH.js → orchestrator-2NZUV4LI.js} +6 -6
  41. package/dist/{orchestrator-7YCQ7V5S.js → orchestrator-JCETTHVV.js} +6 -6
  42. package/dist/{thread-store-JQB7KZJR.js → thread-store-BEBZMOS7.js} +1 -1
  43. package/dist/{thread-store-SCV2IZYS.js → thread-store-S6PJADDM.js} +1 -1
  44. package/dist/{workspaces-QLKWW3O2.js → workspaces-NJF3GG5F.js} +4 -4
  45. package/dist/{workspaces-CFI7XVAE.js → workspaces-OLBW42V3.js} +4 -4
  46. package/dist/{worktree-PK3QETXO.js → worktree-2FYRYJTB.js} +3 -3
  47. package/dist/{worktree-4UAOZUJ4.js → worktree-UKLK7VHH.js} +3 -3
  48. package/package.json +1 -1
@@ -25,7 +25,7 @@ import {
25
25
  resolveQuotaFallbackAgent,
26
26
  stripBrightsyNdjsonNoise,
27
27
  toolDescription
28
- } from "./chunk-QRWVKBGP.js";
28
+ } from "./chunk-D3DYMGZS.js";
29
29
  import {
30
30
  SLACK_REPLY_FORMATTING,
31
31
  addWorkspace,
@@ -48,12 +48,13 @@ import {
48
48
  stageAbsolutePathsAsAttachments,
49
49
  stageBuffersAsAttachments,
50
50
  syncWorkspacesFromThreads
51
- } from "./chunk-GFRC6JQN.js";
51
+ } from "./chunk-U2ZZMGPV.js";
52
52
  import {
53
53
  addPrStackLayer,
54
54
  allocateTeamName,
55
55
  allocateTeamSlug,
56
56
  canonicalizeRepoPath,
57
+ ciChecksFailed,
57
58
  commitAll,
58
59
  connectedPrSelectors,
59
60
  createExistingBranchWorktree,
@@ -97,7 +98,7 @@ import {
97
98
  worktreeDisplayLabelForGroup,
98
99
  worktreeNameFromPath,
99
100
  worktreeSlugForTicket
100
- } from "./chunk-E6C5NR46.js";
101
+ } from "./chunk-W4F7JKXF.js";
101
102
  import {
102
103
  ATTACHMENTS_DIR,
103
104
  DETACHED_JOBS_DIR,
@@ -160,7 +161,7 @@ import {
160
161
  sumUsageList,
161
162
  updateAdvancedSettings,
162
163
  usageOnLimit
163
- } from "./chunk-PPJ5JTWA.js";
164
+ } from "./chunk-QVQPIFBV.js";
164
165
  import {
165
166
  examplePrefixedBranch,
166
167
  sanitizeGitBranchPrefix
@@ -182,7 +183,7 @@ import {
182
183
  updateThread,
183
184
  withThreadLock,
184
185
  writeThread
185
- } from "./chunk-6I5YQTNK.js";
186
+ } from "./chunk-CXTIOJRX.js";
186
187
  import {
187
188
  annotateDevAccessRuns,
188
189
  appDataDir,
@@ -442,9 +443,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
442
443
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
443
444
  );
444
445
  }
445
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-2N6KISDO.js");
446
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-RLCICVQE.js");
446
447
  if (isGlobalThread2(thread)) {
447
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-WQIICPT6.js");
448
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-IG676OSP.js");
448
449
  ensureGlobalCoordinatorCwd2(
449
450
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
450
451
  );
@@ -729,11 +730,41 @@ function threadPrMetaPatch(thread, meta) {
729
730
  if (!sameLoginList(nextReviewers, thread.prReviewerLogins)) {
730
731
  patch.prReviewerLogins = nextReviewers;
731
732
  }
733
+ const nextDecision = meta.reviewDecision ?? null;
734
+ if ((thread.prReviewDecision ?? null) !== nextDecision) {
735
+ patch.prReviewDecision = nextDecision;
736
+ }
737
+ const nextMergeable = meta.mergeable ?? null;
738
+ if ((thread.prMergeable ?? null) !== nextMergeable) {
739
+ patch.prMergeable = nextMergeable;
740
+ }
741
+ const nextMergeState = meta.mergeStateStatus ?? null;
742
+ if ((thread.prMergeStateStatus ?? null) !== nextMergeState) {
743
+ patch.prMergeStateStatus = nextMergeState;
744
+ }
745
+ const nextQueued = Boolean(meta.isInMergeQueue);
746
+ if (Boolean(thread.prIsInMergeQueue) !== nextQueued) {
747
+ patch.prIsInMergeQueue = nextQueued;
748
+ }
749
+ const nextLabels = meta.labels ?? [];
750
+ if (!sameLoginList(nextLabels, thread.prLabels)) {
751
+ patch.prLabels = nextLabels;
752
+ }
753
+ const mergeState = (nextMergeState ?? "").toUpperCase();
754
+ if (mergeState === "CLEAN" && thread.prChecksFailed) {
755
+ patch.prChecksFailed = false;
756
+ } else if ((mergeState === "UNSTABLE" || mergeState === "BLOCKED" && (nextDecision ?? "").toUpperCase() === "APPROVED") && !thread.prChecksFailed) {
757
+ patch.prChecksFailed = true;
758
+ }
732
759
  if (thread.skipAutoArchiveOnMerge && nextState && nextState !== "MERGED" && nextState !== "CLOSED") {
733
760
  patch.skipAutoArchiveOnMerge = false;
734
761
  }
735
762
  return patch;
736
763
  }
764
+ function threadPrChecksFailedPatch(thread, failed) {
765
+ if (thread.prChecksFailed === failed) return {};
766
+ return { prChecksFailed: failed };
767
+ }
737
768
  function shouldAutoArchiveOnPrMerge(opts) {
738
769
  if (!opts.autoArchiveEnabled) return false;
739
770
  if (opts.isGlobal) return false;
@@ -1322,6 +1353,12 @@ function worktreeBindingFrom(from) {
1322
1353
  prIsDraft: from.prIsDraft,
1323
1354
  prAuthorLogin: from.prAuthorLogin,
1324
1355
  prReviewerLogins: from.prReviewerLogins,
1356
+ prReviewDecision: from.prReviewDecision,
1357
+ prMergeable: from.prMergeable,
1358
+ prMergeStateStatus: from.prMergeStateStatus,
1359
+ prIsInMergeQueue: from.prIsInMergeQueue,
1360
+ prLabels: from.prLabels,
1361
+ prChecksFailed: from.prChecksFailed,
1325
1362
  skipAutoArchiveOnMerge: from.skipAutoArchiveOnMerge,
1326
1363
  stackId: from.stackId,
1327
1364
  stackLayer: from.stackLayer,
@@ -3572,6 +3609,72 @@ function classifyWorktreeColumn(group) {
3572
3609
  }
3573
3610
  return "new";
3574
3611
  }
3612
+ function labelsInclude(labels, name) {
3613
+ const want = name.trim().toLowerCase();
3614
+ if (!want) return false;
3615
+ return (labels ?? []).some((label) => label.trim().toLowerCase() === want);
3616
+ }
3617
+ function reviewLabelForRepo(labelsByRepo, repoPath) {
3618
+ const want = repoPath.trim().replace(/\/+$/, "");
3619
+ if (!want || !labelsByRepo) return "";
3620
+ const direct = labelsByRepo[want]?.trim();
3621
+ if (direct) return direct;
3622
+ let best = "";
3623
+ let bestLen = 0;
3624
+ for (const [key, label] of Object.entries(labelsByRepo)) {
3625
+ const stored = key.trim().replace(/\/+$/, "");
3626
+ const value = label.trim();
3627
+ if (!stored || !value) continue;
3628
+ if (stored === want || want.startsWith(`${stored}/`)) {
3629
+ if (stored.length > bestLen) {
3630
+ best = value;
3631
+ bestLen = stored.length;
3632
+ }
3633
+ }
3634
+ }
3635
+ return best;
3636
+ }
3637
+ function groupPrLabels(group) {
3638
+ const out = [];
3639
+ const seen = /* @__PURE__ */ new Set();
3640
+ for (const thread of group) {
3641
+ for (const label of thread.prLabels ?? []) {
3642
+ const key = label.trim().toLowerCase();
3643
+ if (!key || seen.has(key)) continue;
3644
+ seen.add(key);
3645
+ out.push(label.trim());
3646
+ }
3647
+ }
3648
+ return out;
3649
+ }
3650
+ function classifyWorktreeListBadges(group, viewerLogin = "", reviewLabel = "") {
3651
+ if (group.length === 0 || group.some((t) => t.cowboy)) return [];
3652
+ const open = group.filter((t) => isOpenPrState(t.prUrl, t.prState));
3653
+ if (open.length === 0) return [];
3654
+ const ownership = classifyWorktreeOwnership(group, viewerLogin);
3655
+ if (ownership === "reviewing") {
3656
+ return [
3657
+ {
3658
+ id: "review",
3659
+ label: "review",
3660
+ title: "Someone else's PR",
3661
+ mod: "is-review"
3662
+ }
3663
+ ];
3664
+ }
3665
+ const draft = open.some((t) => t.prIsDraft);
3666
+ const readyLabel = reviewLabel.trim();
3667
+ const inReview = readyLabel ? labelsInclude(groupPrLabels(group), readyLabel) : !draft;
3668
+ if (!inReview) return [];
3669
+ return [
3670
+ {
3671
+ id: "pending",
3672
+ label: "pending",
3673
+ title: "Waiting for review",
3674
+ mod: "is-pending"
3675
+ }
3676
+ ];
3677
+ }
3575
3678
  function worktreeBoardStatus(group) {
3576
3679
  const order = ["running", "queued", "error", "broken"];
3577
3680
  for (const status of order) {
@@ -4063,7 +4166,7 @@ async function createThread(input, _onSetupLine) {
4063
4166
  });
4064
4167
  await requireAgent(resolved.agent);
4065
4168
  if (input.cowboy) {
4066
- const { cowboyModeEnabled } = await import("./app-settings-VOPXJMGV.js");
4169
+ const { cowboyModeEnabled } = await import("./app-settings-2BHGANQH.js");
4067
4170
  if (!cowboyModeEnabled()) {
4068
4171
  throw new Error(
4069
4172
  "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
@@ -4121,7 +4224,7 @@ async function createThread(input, _onSetupLine) {
4121
4224
  let sourceIsFork = false;
4122
4225
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
4123
4226
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
4124
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-CWIJ7INC.js");
4227
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-HTRIHTL5.js");
4125
4228
  const task = await ensureAbleTimeTask({
4126
4229
  title: title?.trim() || "Untitled work",
4127
4230
  description: input.prompt?.trim() || void 0
@@ -4142,6 +4245,7 @@ async function createThread(input, _onSetupLine) {
4142
4245
  let prUrl = null;
4143
4246
  let prTitle = null;
4144
4247
  let prAuthorLogin2 = null;
4248
+ let prLabels = [];
4145
4249
  if (sourceType === "pr") {
4146
4250
  const num = Number(input.sourceRef.replace(/^#/, ""));
4147
4251
  if (!Number.isFinite(num)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
@@ -4158,6 +4262,7 @@ async function createThread(input, _onSetupLine) {
4158
4262
  sourceIsFork = pr.isCrossRepository;
4159
4263
  prUrl = pr.url;
4160
4264
  prAuthorLogin2 = pr.author?.login?.trim() || null;
4265
+ prLabels = pr.labels ?? [];
4161
4266
  const localFetchBranch = `sideboard-pr-${pr.number}`;
4162
4267
  await fetchPrHead(repoPath, pr.number, localFetchBranch);
4163
4268
  sourceRef = localFetchBranch;
@@ -4181,6 +4286,7 @@ async function createThread(input, _onSetupLine) {
4181
4286
  prUrl = existing.url;
4182
4287
  prTitle = existing.title;
4183
4288
  prAuthorLogin2 = existing.author?.login?.trim() || null;
4289
+ prLabels = existing.labels ?? [];
4184
4290
  }
4185
4291
  }
4186
4292
  }
@@ -4216,14 +4322,15 @@ async function createThread(input, _onSetupLine) {
4216
4322
  status: "idle",
4217
4323
  prUrl,
4218
4324
  prTitle,
4219
- prAuthorLogin: prAuthorLogin2
4325
+ prAuthorLogin: prAuthorLogin2,
4326
+ prLabels
4220
4327
  });
4221
4328
  writeThread(thread);
4222
4329
  await ensureWorkspace(repoPath);
4223
4330
  return readThread(thread.id) ?? thread;
4224
4331
  }
4225
4332
  async function listLinearIssues(agent, repoPath) {
4226
- const { getAdapter: getAdapter2 } = await import("./agents-BOIIFMNG.js");
4333
+ const { getAdapter: getAdapter2 } = await import("./agents-7SCJTTZN.js");
4227
4334
  await requireAgent(agent, { requireLinear: true });
4228
4335
  const adapter = getAdapter2(agent);
4229
4336
  if (!adapter.listLinearIssues) {
@@ -4696,7 +4803,7 @@ async function adoptThread(input) {
4696
4803
  messages: input.messages ?? []
4697
4804
  });
4698
4805
  writeThread(thread);
4699
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-CFI7XVAE.js");
4806
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OLBW42V3.js");
4700
4807
  await ensureWorkspace2(repoPath);
4701
4808
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-RXZPTCNH.js");
4702
4809
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -7408,7 +7515,7 @@ function formatScheduledPrompt(name, prompt) {
7408
7515
  ${prompt}`;
7409
7516
  }
7410
7517
  async function defaultDeps() {
7411
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-7YCQ7V5S.js");
7518
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-JCETTHVV.js");
7412
7519
  const orch = getOrchestrator2();
7413
7520
  return {
7414
7521
  findThread: (id) => findThreadByRef(id),
@@ -7733,7 +7840,7 @@ var Orchestrator = class {
7733
7840
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
7734
7841
  });
7735
7842
  }
7736
- const { autoCleanupOrphansEnabled } = await import("./app-settings-VOPXJMGV.js");
7843
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-2BHGANQH.js");
7737
7844
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
7738
7845
  await cleanupOrphanWorktrees({ repoPaths });
7739
7846
  }
@@ -8080,7 +8187,7 @@ var Orchestrator = class {
8080
8187
  }
8081
8188
  await setup;
8082
8189
  if (skipSetup) return;
8083
- const { autoRunAfterSetupEnabled } = await import("./app-settings-VOPXJMGV.js");
8190
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-2BHGANQH.js");
8084
8191
  if (autoRunAfterSetupEnabled()) {
8085
8192
  try {
8086
8193
  await this.startDev(threadId);
@@ -8450,7 +8557,7 @@ var Orchestrator = class {
8450
8557
  }
8451
8558
  const isBrightsy = fresh.agent === "brightsy";
8452
8559
  const isOrchestration = isOrchestratorThread(fresh);
8453
- const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-VOPXJMGV.js");
8560
+ const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-2BHGANQH.js");
8454
8561
  const gitAuthMode = getGithubGitAuthMode();
8455
8562
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
8456
8563
  githubSlug: await withTimeout(
@@ -9695,10 +9802,20 @@ var Orchestrator = class {
9695
9802
  return { thread, selectors: connectedPrSelectors(thread, headUrl), cwd, headUrl };
9696
9803
  }
9697
9804
  async getPrChecks(threadRef) {
9698
- const { selectors, cwd } = await this.withPrSelector(threadRef);
9805
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
9699
9806
  for (const selector of selectors) {
9700
9807
  const checks = await getPrChecks(cwd, selector);
9701
- if (checks) return checks;
9808
+ if (!checks) continue;
9809
+ const live = this.requireThread(thread.id);
9810
+ const failed = ciChecksFailed(checks);
9811
+ const siblings = threadsSharingWorktree(live.worktreePath);
9812
+ const targets = siblings.length > 0 ? siblings : [live];
9813
+ for (const t of targets) {
9814
+ const patch = threadPrChecksFailedPatch(t, failed);
9815
+ if (Object.keys(patch).length === 0) continue;
9816
+ updateThread(t.id, patch);
9817
+ }
9818
+ return checks;
9702
9819
  }
9703
9820
  return null;
9704
9821
  }
@@ -9741,7 +9858,7 @@ var Orchestrator = class {
9741
9858
  if (!titled.userSetTitle && meta.title && titled.title !== meta.title) {
9742
9859
  updateThread(thread.id, { title: meta.title });
9743
9860
  }
9744
- const { autoArchiveOnMergeEnabled } = await import("./app-settings-VOPXJMGV.js");
9861
+ const { autoArchiveOnMergeEnabled } = await import("./app-settings-2BHGANQH.js");
9745
9862
  const latest = this.requireThread(thread.id);
9746
9863
  if (!shouldAutoArchiveOnPrMerge({
9747
9864
  previousPrState: prevState || null,
@@ -10023,7 +10140,7 @@ var Orchestrator = class {
10023
10140
  this.enforceHistoryRetention();
10024
10141
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
10025
10142
  try {
10026
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-CFI7XVAE.js");
10143
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OLBW42V3.js");
10027
10144
  await ensureWorkspace2(thread.repoPath);
10028
10145
  } catch {
10029
10146
  }
@@ -10050,7 +10167,7 @@ var Orchestrator = class {
10050
10167
  await runArchiveScript(thread.repoPath, thread.worktreePath);
10051
10168
  } catch {
10052
10169
  }
10053
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-VOPXJMGV.js");
10170
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-2BHGANQH.js");
10054
10171
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
10055
10172
  await removeWorktree(thread.repoPath, thread.worktreePath, {
10056
10173
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -10077,7 +10194,7 @@ var Orchestrator = class {
10077
10194
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
10078
10195
  );
10079
10196
  }
10080
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-4UAOZUJ4.js");
10197
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-UKLK7VHH.js");
10081
10198
  const slug = thread.worktreePath.split("/").pop();
10082
10199
  const dest = thread.worktreePath;
10083
10200
  await withRepoGitLock(thread.repoPath, async () => {
@@ -10187,7 +10304,7 @@ async function startOrchestration(opts) {
10187
10304
  sourceRef: "default",
10188
10305
  ...createOpts
10189
10306
  }).catch(async () => {
10190
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-4UAOZUJ4.js");
10307
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-UKLK7VHH.js");
10191
10308
  const repo = await resolveRepoRoot2(repoPath);
10192
10309
  const def = await resolveDefaultBranch2(repo);
10193
10310
  return orch.createThread({
@@ -10197,7 +10314,7 @@ async function startOrchestration(opts) {
10197
10314
  repoPath: repo
10198
10315
  });
10199
10316
  });
10200
- const { updateThread: upd } = await import("./thread-store-SCV2IZYS.js");
10317
+ const { updateThread: upd } = await import("./thread-store-S6PJADDM.js");
10201
10318
  const updated = upd(thread.id, {
10202
10319
  sourceType: "orchestration",
10203
10320
  sourceRef: goal
@@ -10217,6 +10334,8 @@ export {
10217
10334
  DEFAULT_WORKTREE_SORT,
10218
10335
  groupHomeBoardWorktrees,
10219
10336
  classifyWorktreeColumn,
10337
+ reviewLabelForRepo,
10338
+ classifyWorktreeListBadges,
10220
10339
  worktreeBoardStatus,
10221
10340
  dedupeBoardIssues,
10222
10341
  issueNeedsWorkspacePick,
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  textFromAbleTimeDoc
3
- } from "./chunk-43F44EKX.js";
3
+ } from "./chunk-GVAR6R6R.js";
4
4
  import {
5
5
  assertAbleTimeCredential,
6
6
  callAbleTimeTool,
7
7
  normalizeAbleTimeHost,
8
8
  rewriteAbleTimeError
9
- } from "./chunk-QNJXJIWJ.js";
9
+ } from "./chunk-RF46WMSI.js";
10
10
  import {
11
11
  isAbleTimeConnected,
12
12
  saveAbleTimeConnection
13
- } from "./chunk-PPJ5JTWA.js";
13
+ } from "./chunk-QVQPIFBV.js";
14
14
 
15
15
  // src/integrations/abletime.ts
16
16
  var CLOSED_STATES = /* @__PURE__ */ new Set([
@@ -68,6 +68,12 @@ function normalizeThread(raw) {
68
68
  prTitle: raw.prTitle ?? null,
69
69
  prState: raw.prState ?? null,
70
70
  prIsDraft: Boolean(raw.prIsDraft),
71
+ prReviewDecision: raw.prReviewDecision ?? null,
72
+ prMergeable: raw.prMergeable ?? null,
73
+ prMergeStateStatus: raw.prMergeStateStatus ?? null,
74
+ prIsInMergeQueue: Boolean(raw.prIsInMergeQueue),
75
+ prLabels: Array.isArray(raw.prLabels) ? raw.prLabels : [],
76
+ prChecksFailed: typeof raw.prChecksFailed === "boolean" ? raw.prChecksFailed : void 0,
71
77
  skipAutoArchiveOnMerge: Boolean(raw.skipAutoArchiveOnMerge),
72
78
  cowboy: Boolean(raw.cowboy),
73
79
  stackId: raw.stackId ?? null,
@@ -103,6 +109,12 @@ function createEmptyThread(partial) {
103
109
  prIsDraft: Boolean(partial.prIsDraft),
104
110
  prAuthorLogin: partial.prAuthorLogin?.trim() || null,
105
111
  prReviewerLogins: partial.prReviewerLogins ?? [],
112
+ prReviewDecision: partial.prReviewDecision ?? null,
113
+ prMergeable: partial.prMergeable ?? null,
114
+ prMergeStateStatus: partial.prMergeStateStatus ?? null,
115
+ prIsInMergeQueue: Boolean(partial.prIsInMergeQueue),
116
+ prLabels: partial.prLabels ?? [],
117
+ prChecksFailed: partial.prChecksFailed,
106
118
  skipAutoArchiveOnMerge: partial.skipAutoArchiveOnMerge ?? false,
107
119
  cowboy: Boolean(partial.cowboy),
108
120
  stackId: partial.stackId ?? null,
@@ -897,13 +897,26 @@ function normalizeDefaults(raw) {
897
897
  function profileRepoKey(path) {
898
898
  return path.trim().replace(/\/+$/, "");
899
899
  }
900
+ var REVIEW_LABEL_MAX = 50;
901
+ function normalizeReviewLabel(value) {
902
+ const label = (value ?? "").trim().replace(/^:+/, "").slice(0, REVIEW_LABEL_MAX);
903
+ if (!label || /[,|]/.test(label)) return "";
904
+ return label;
905
+ }
906
+ function projectProfileHasFields(profile) {
907
+ return Boolean(profile.notes || profile.reviewLabel);
908
+ }
900
909
  function normalizeProjectProfile(raw) {
901
910
  if (!raw || typeof raw !== "object") return void 0;
902
911
  const source = raw;
903
912
  const out = {};
904
913
  const notes = foldLegacyRolesIntoNotes(source.roles, source.role, source.notes);
905
914
  if (notes) out.notes = notes;
906
- return out.notes ? out : void 0;
915
+ const reviewLabel = normalizeReviewLabel(
916
+ typeof source.reviewLabel === "string" ? source.reviewLabel : null
917
+ );
918
+ if (reviewLabel) out.reviewLabel = reviewLabel;
919
+ return projectProfileHasFields(out) ? out : void 0;
907
920
  }
908
921
  function normalizeProjects(raw) {
909
922
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
@@ -1587,12 +1600,22 @@ function updateProjectProfileSettings(repoPath, patch) {
1587
1600
  if (!notes) delete next.notes;
1588
1601
  else next.notes = notes;
1589
1602
  }
1603
+ if ("reviewLabel" in patch) {
1604
+ const reviewLabel = normalizeReviewLabel(patch.reviewLabel);
1605
+ if (!reviewLabel) delete next.reviewLabel;
1606
+ else next.reviewLabel = reviewLabel;
1607
+ }
1590
1608
  delete next.roles;
1591
1609
  delete next.role;
1592
- if (!next.notes) delete projects[key];
1610
+ if (!projectProfileHasFields(next)) delete projects[key];
1593
1611
  else projects[key] = next;
1594
1612
  return saveAppSettings({ ...current, projects });
1595
1613
  }
1614
+ function resolveProjectReviewLabel(settings, repoPath) {
1615
+ const key = findProjectProfileKey(settings.projects, repoPath);
1616
+ if (!key) return "";
1617
+ return settings.projects[key]?.reviewLabel?.trim() || "";
1618
+ }
1596
1619
  function getDefaultAgent(settings = loadAppSettings()) {
1597
1620
  return settings.defaults.agent ?? "claude";
1598
1621
  }
@@ -2182,6 +2205,8 @@ export {
2182
2205
  toPublicAppSettings,
2183
2206
  appSettingsPath,
2184
2207
  claudeUserSettingsPath,
2208
+ REVIEW_LABEL_MAX,
2209
+ normalizeReviewLabel,
2185
2210
  findProjectProfileKey,
2186
2211
  loadAppSettings,
2187
2212
  saveAppSettings,
@@ -2193,6 +2218,7 @@ export {
2193
2218
  updateIntegrationsSettings,
2194
2219
  updateDefaultsSettings,
2195
2220
  updateProjectProfileSettings,
2221
+ resolveProjectReviewLabel,
2196
2222
  getDefaultAgent,
2197
2223
  getDefaultModel,
2198
2224
  getDefaultEffort,
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  getAbleTimeHost,
6
6
  isAbleTimeConnected
7
- } from "./chunk-PPJ5JTWA.js";
7
+ } from "./chunk-QVQPIFBV.js";
8
8
 
9
9
  // src/integrations/abletime-mcp.ts
10
10
  var DEFAULT_ABLETIME_HOST = "https://track.abletime.com";
@@ -153,7 +153,7 @@ function textsFromUnknown(value) {
153
153
  return "";
154
154
  }
155
155
  async function abletimeMcpRequest(method, params, opts) {
156
- const rawToken = opts?.token ?? await import("./abletime-oauth-PUIPZTA4.js").then((m) => m.ensureAbleTimeAccessToken());
156
+ const rawToken = opts?.token ?? await import("./abletime-oauth-ME7ZY2RS.js").then((m) => m.ensureAbleTimeAccessToken());
157
157
  if (!rawToken?.trim()) {
158
158
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
159
159
  }
@@ -224,9 +224,9 @@ async function callAbleTimeTool(name, args = {}, opts) {
224
224
  if (!opts?.token && !isAbleTimeConnected()) {
225
225
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
226
226
  }
227
- const rawToken = opts?.token ?? await import("./abletime-oauth-PUIPZTA4.js").then((m) => m.ensureAbleTimeAccessToken());
227
+ const rawToken = opts?.token ?? await import("./abletime-oauth-ME7ZY2RS.js").then((m) => m.ensureAbleTimeAccessToken());
228
228
  if (rawToken && ableTimeUsesRest(rawToken)) {
229
- const { callAbleTimeRestTool } = await import("./abletime-rest-32NIVXAY.js");
229
+ const { callAbleTimeRestTool } = await import("./abletime-rest-73EKIAZU.js");
230
230
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
231
231
  }
232
232
  const requestOpts = { ...opts, pm: opts?.pm ?? abletimeToolUsesPm(name) };
@@ -242,7 +242,7 @@ async function callAbleTimeTool(name, args = {}, opts) {
242
242
  return await call();
243
243
  }
244
244
  if (rawToken && ableTimeUsesRest(rawToken) && isAbleTimeRejectedCredential(message)) {
245
- const { callAbleTimeRestTool } = await import("./abletime-rest-32NIVXAY.js");
245
+ const { callAbleTimeRestTool } = await import("./abletime-rest-73EKIAZU.js");
246
246
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
247
247
  }
248
248
  throw err instanceof Error ? new Error(rewriteAbleTimeError(err.message)) : err;
@@ -6,7 +6,7 @@ import {
6
6
  resolveRepoRoot,
7
7
  takenSlugsFromThread,
8
8
  teamSlugFromName
9
- } from "./chunk-E6C5NR46.js";
9
+ } from "./chunk-W4F7JKXF.js";
10
10
  import {
11
11
  ATTACHMENTS_DIR,
12
12
  attachmentsGitignoreBody
@@ -23,13 +23,13 @@ import {
23
23
  resolveThreadDefaults,
24
24
  resolveViewerProfile,
25
25
  resolveViewerProfileForRepo
26
- } from "./chunk-PPJ5JTWA.js";
26
+ } from "./chunk-QVQPIFBV.js";
27
27
  import {
28
28
  createEmptyThread,
29
29
  listThreads,
30
30
  updateThread,
31
31
  writeThread
32
- } from "./chunk-6I5YQTNK.js";
32
+ } from "./chunk-CXTIOJRX.js";
33
33
  import {
34
34
  appDataDir,
35
35
  globalAgentCwd,
@@ -383,7 +383,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
383
383
  "Discover:",
384
384
  "- list_workspaces \u2014 registered repos (path + github slug + project context when set). Use account / project context to pick the right repo for tickets or reviews.",
385
385
  "- list_board \u2014 Home Kanban of worktrees (New / Draft / Review / Merged; one card per checkout). Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind, column, limit.",
386
- '- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_thread sourceType=pr. That is open non-draft PRs labeled eng-review with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets \u2014 do not use it for that review-inbox ask. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).',
386
+ `- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_thread sourceType=pr. That is open non-draft PRs labeled with this project's ready-for-review GitHub label (Settings \u2192 Projects; default eng-review) with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets \u2014 do not use it for that review-inbox ask. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).`,
387
387
  "- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. Show the options \u2014 do not create_thread or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
388
388
  "- Ticket updates: list_issues / linear_search_issues / github_search_issues with updatedSince (yesterday, 2d, or ISO). One call returns new assignments, ticket edits, and new comments \u2014 do not get_issue every ticket just to check for comments. kind=created vs updated distinguishes new tickets from existing ones.",
389
389
  "- linear_* (when Linear is connected) \u2014 list_teams for team key/states; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user types a next step \u2014 they should work through the feedback in chat first. Do not tell the child to ask_user after the review. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list.",
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  isOrchestratorThread
5
- } from "./chunk-576S3HJ7.js";
5
+ } from "./chunk-64NUGRZ3.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-5ZFULOTC.js";
23
+ } from "./chunk-XM4UIFQU.js";
24
24
  import {
25
25
  enrichPathWithNpmGlobalBin,
26
26
  isConductorBundledCli,
@@ -37,7 +37,7 @@ import {
37
37
  loadAppSettings,
38
38
  resolveAgentExecutable,
39
39
  resolveClaudeExecutable
40
- } from "./chunk-YLGBQVRK.js";
40
+ } from "./chunk-XEBQRCDW.js";
41
41
  import {
42
42
  appDataDir
43
43
  } from "./chunk-KK63BFYN.js";
@@ -2081,6 +2081,14 @@ function lastRunningSkillIndex(parts, parentId) {
2081
2081
  }
2082
2082
  return -1;
2083
2083
  }
2084
+ function markRunningSkillsDone(parts, parentId) {
2085
+ return parts.map((p) => {
2086
+ if (p.type === "tool" && isSkillToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
2087
+ return withPartTimes({ ...p, status: "done" }, p);
2088
+ }
2089
+ return p;
2090
+ });
2091
+ }
2084
2092
  function promoteOrFoldSkillText(parts, textIdx) {
2085
2093
  const acc = parts[textIdx];
2086
2094
  if (acc?.type !== "text") return parts;
@@ -2208,7 +2216,10 @@ function applyAgentEvent(parts, event) {
2208
2216
  {
2209
2217
  ...prev,
2210
2218
  result: clipToolResultForStore(result),
2211
- status: looksLikeSkillBody(result) ? "done" : prev.status
2219
+ // Stay running after the YAML `name:` fence so later content_block_delta
2220
+ // tokens of SKILL.md stay on this row. thinking / tool_use / finalizeParts
2221
+ // mark the row done so the real reply can be chat.
2222
+ status: "running"
2212
2223
  },
2213
2224
  prev
2214
2225
  );
@@ -2250,6 +2261,7 @@ function applyAgentEvent(parts, event) {
2250
2261
  if (event.type === "thinking") {
2251
2262
  const data = event.data;
2252
2263
  if (!data) return parts;
2264
+ parts = markRunningSkillsDone(parts, event.parentId);
2253
2265
  const next = [...parts];
2254
2266
  if (event.replace) {
2255
2267
  for (let i = next.length - 1; i >= 0; i--) {
@@ -2297,6 +2309,7 @@ function applyAgentEvent(parts, event) {
2297
2309
  return withCompactFinish(next, data, event.parentId);
2298
2310
  }
2299
2311
  if (event.type === "tool_use") {
2312
+ parts = markRunningSkillsDone(parts, event.parentId);
2300
2313
  const input = asRecord(event.input);
2301
2314
  const diff = diffFromInput(input);
2302
2315
  const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
@@ -2934,7 +2947,7 @@ var claudeAdapter = {
2934
2947
  );
2935
2948
  }
2936
2949
  const mode = permissionMode(thread);
2937
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3SQU4GL4.js");
2950
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-J6H7X5SM.js");
2938
2951
  const isOrchestrator = isOrchestratorThread2(thread);
2939
2952
  const injectedServers = await buildInjectedMcpServers({
2940
2953
  includeSideboard: true,